nixio:
[project/luci.git] / libs / nixio / lua / nixio / util.lua
1 --[[
2 nixio - Linux I/O library for lua
3
4 Copyright 2009 Steven Barth <steven@midlink.org>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 $Id$
13 ]]--
14
15 local table = require "table"
16 local nixio = require "nixio"
17 local getmetatable, assert, pairs = getmetatable, assert, pairs
18
19 module "nixio.util"
20
21 local BUFFERSIZE = 8096
22 local socket = nixio.meta_socket
23 local tls_socket = nixio.meta_tls_socket
24 local file = nixio.meta_file
25
26 local meta = {}
27
28 function meta.is_socket(self)
29         return (getmetatable(self) == socket)
30 end
31
32 function meta.is_tls_socket(self)
33         return (getmetatable(self) == tls_socket)
34 end
35
36 function meta.is_file(self)
37         return (getmetatable(self) == file)
38 end
39
40 function meta.readall(self, len)
41         local block, code, msg = self:read(len)
42
43         if not block then
44                 return "", code, msg, len
45         elseif #block == 0 then
46                 return "", nil, nil, len
47         end
48
49         local data, total = {block}, #block
50
51         while len > total do
52                 block, code, msg = self:read(len - total)
53
54                 if not block then
55                         return data, code, msg, len - #data
56                 elseif #block == 0 then
57                         return data, nil, nil, len - #data
58                 end
59
60                 data[#data+1], total = block, total + #block
61         end
62
63         return (#data > 1 and table.concat(data) or data[1]), nil, nil, 0
64 end
65 meta.recvall = meta.readall
66
67 function meta.writeall(self, data)
68         local total, block = 0
69         local sent, code, msg = self:write(data)
70
71         if not sent then
72                 return total, code, msg, data
73         end
74
75         while sent < #data do
76                 block, total = data:sub(sent + 1), total + sent
77                 sent, code, msg = self:write(block)
78                 
79                 if not sent then
80                         return total, code, msg, block
81                 end
82         end
83         
84         return total + sent, nil, nil, ""
85 end
86 meta.sendall = meta.writeall
87
88 function meta.linesource(self, limit)
89         limit = limit or BUFFERSIZE
90         local buffer = ""
91         local bpos = 0
92         return function(flush)
93                 local line, endp, _
94                 
95                 if flush then
96                         line = buffer:sub(bpos + 1)
97                         buffer = ""
98                         bpos = 0
99                         return line
100                 end
101
102                 while not line do
103                         _, endp, line = buffer:find("(.-)\r?\n", bpos + 1)
104                         if line then
105                                 bpos = endp
106                                 return line
107                         elseif #buffer < limit + bpos then
108                                 local newblock, code = self:read(limit + bpos - #buffer)
109                                 if not newblock then
110                                         return nil, code
111                                 elseif #newblock == 0 then
112                                         return nil
113                                 end
114                                 buffer = buffer:sub(bpos + 1) .. newblock
115                                 bpos = 0
116                         else
117                                 return nil, 0
118                         end
119                 end
120         end
121 end
122
123 function meta.blocksource(self, bs, limit)
124         bs = bs or BUFFERSIZE
125         return function()
126                 local toread = bs
127                 if limit then
128                         if limit < 1 then
129                                 return nil
130                         elseif limit < toread then
131                                 toread = limit
132                         end
133                 end
134
135                 local block, code, msg = self:read(toread)
136
137                 if not block then
138                         return nil, code
139                 elseif #block == 0 then
140                         return nil
141                 else
142                         if limit then
143                                 limit = limit - #block
144                         end
145
146                         return block
147                 end
148         end
149 end
150
151 function meta.sink(self, close)
152         return function(chunk, src_err)
153                 if not chunk and not src_err and close then
154                         self:close()
155                 elseif chunk and #chunk > 0 then
156                         return self:writeall(chunk)
157                 end
158                 return true
159         end
160 end
161
162 function tls_socket.close(self)
163         self:shutdown()
164         return self.socket:close()
165 end
166
167 for k, v in pairs(meta) do
168         file[k] = v
169         socket[k] = v
170         tls_socket[k] = v
171 end