1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
|
-- initialization {{{
local base = _G
local irc_debug = require 'irc.debug'
local socket = require 'socket'
local math = require 'math'
local os = require 'os'
local string = require 'string'
local table = require 'table'
-- }}}
module 'irc.misc'
-- defaults {{{
DELIM = ' '
PATH_SEP = '/'
ENDIANNESS = "big"
INT_BYTES = 4
-- }}}
-- private functions {{{
local function exists(filename)
local _, err = os.rename(filename, filename)
if not err then return true end
return not err:find("No such file or directory")
end
-- }}}
-- public functions {{{
-- split() - splits str into substrings based on several options {{{
function split(str, delim, end_delim, lquotes, rquotes)
-- handle arguments {{{
delim = "["..(delim or DELIM).."]"
if end_delim then end_delim = "["..end_delim.."]" end
if lquotes then lquotes = "["..lquotes.."]" end
if rquotes then rquotes = "["..rquotes.."]" end
local optdelim = delim .. "?"
-- }}}
local ret = {}
local instring = false
while str:len() > 0 do
-- handle case for not currently in a string {{{
if not instring then
local end_delim_ind, lquote_ind, delim_ind
if end_delim then end_delim_ind = str:find(optdelim..end_delim) end
if lquotes then lquote_ind = str:find(optdelim..lquotes) end
local delim_ind = str:find(delim)
if not end_delim_ind then end_delim_ind = str:len() + 1 end
if not lquote_ind then lquote_ind = str:len() + 1 end
if not delim_ind then delim_ind = str:len() + 1 end
local next_ind = math.min(end_delim_ind, lquote_ind, delim_ind)
if next_ind == str:len() + 1 then
table.insert(ret, str)
break
elseif next_ind == end_delim_ind then
-- TODO: hackish here
if str:sub(next_ind, next_ind) == end_delim:gsub('[%[%]]', '') then
table.insert(ret, str:sub(next_ind + 1))
else
table.insert(ret, str:sub(1, next_ind - 1))
table.insert(ret, str:sub(next_ind + 2))
end
break
elseif next_ind == lquote_ind then
table.insert(ret, str:sub(1, next_ind - 1))
str = str:sub(next_ind + 2)
instring = true
else -- last because the top two contain it
table.insert(ret, str:sub(1, next_ind - 1))
str = str:sub(next_ind + 1)
end
-- }}}
-- handle case for currently in a string {{{
else
local endstr = str:find(rquotes..optdelim)
table.insert(ret, str:sub(1, endstr - 1))
str = str:sub(endstr + 2)
instring = false
end
-- }}}
end
return ret
end
-- }}}
-- basename() - returns the basename of a file {{{
function basename(path, sep)
sep = sep or PATH_SEP
if not path:find(sep) then return path end
return socket.skip(2, path:find(".*" .. sep .. "(.*)"))
end
-- }}}
-- dirname() - returns the dirname of a file {{{
function dirname(path, sep)
sep = sep or PATH_SEP
if not path:find(sep) then return "." end
return socket.skip(2, path:find("(.*)" .. sep .. ".*"))
end
-- }}}
-- str_to_int() - converts a number to a low-level int {{{
function str_to_int(str, bytes, endian)
bytes = bytes or INT_BYTES
endian = endian or ENDIANNESS
local ret = ""
for i = 0, bytes - 1 do
local new_byte = string.char(math.fmod(str / (2^(8 * i)), 256))
if endian == "big" or endian == "network" then ret = new_byte .. ret
else ret = ret .. new_byte
end
end
return ret
end
-- }}}
-- int_to_str() - converts a low-level int to a number {{{
function int_to_str(int, endian)
endian = endian or ENDIANNESS
local ret = 0
for i = 1, int:len() do
if endian == "big" or endian == "network" then ind = int:len() - i + 1
else ind = i
end
ret = ret + string.byte(int:sub(ind, ind)) * 2^(8 * (i - 1))
end
return ret
end
-- }}}
-- ip_str_to_int() - converts a string ip address to an int {{{
function ip_str_to_int(ip_str)
local i = 3
local ret = 0
for num in ip_str:gmatch("%d+") do
ret = ret + num * 2^(i * 8)
i = i - 1
end
return ret
end
-- }}}
-- ip_int_to_str() - converts an int to a string ip address {{{
function ip_int_to_str(ip_int)
local ip = {}
for i = 3, 0, -1 do
local new_num = math.floor(ip_int / 2^(i * 8))
table.insert(ip, new_num)
ip_int = ip_int - new_num * 2^(i * 8)
end
return table.concat(ip, ".")
end
-- }}}
-- get_unique_filename() - returns a unique filename {{{
function get_unique_filename(filename)
if not exists(filename) then return filename end
local count = 1
while true do
if not exists(filename .. "." .. count) then
return filename .. "." .. count
end
count = count + 1
end
end
-- }}}
-- try_call() - call a function, if it exists {{{
function try_call(fn, ...)
if base.type(fn) == "function" then
return fn(...)
end
end
-- }}}
-- try_call_warn() - same as try_call, but complain if not {{{
function try_call_warn(msg, fn, ...)
if base.type(fn) == "function" then
return fn(...)
else
irc_debug.warn(msg)
end
end
-- }}}
-- parse_user() - gets the various parts of a full username {{{
-- args: user - usermask (i.e. returned in the from field of a callback)
-- return: nick, username, hostname (these can be nil if nonexistant)
function parse_user(user)
local found, bang, nick = user:find("^([^!]*)!")
if found then
user = user:sub(bang + 1)
else
return user
end
local found, equals = user:find("^.=")
if found then
user = user:sub(3)
end
local found, at, username = user:find("^([^@]*)@")
if found then
return nick, username, user:sub(at + 1)
else
return nick, user
end
end
-- }}}
-- value_iter() - iterate just over values of a table {{{
function value_iter(state, arg, pred)
for k, v in base.pairs(state) do
if arg == v then arg = k end
end
local key, val = base.next(state, arg)
if not key then return end
if base.type(pred) == "function" then
while not pred(val) do
key, val = base.next(state, key)
if not key then return end
end
end
return val
end
-- }}}
-- }}}
|