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