src/buffer.c

changeset 0
f7d2d78eb424
equal deleted inserted replaced
-1:000000000000 0:f7d2d78eb424
1 /*=========================================================================*\
2 * LuaSocket 2.0.2
3 * Copyright (C) 2004-2007 Diego Nehab
4 *
5 * Input/Output interface for Lua programs
6 *
7 * RCS ID: $Id: buffer.c,v 1.28 2007/06/11 23:44:54 diego Exp $
8 \*=========================================================================*/
9 #include "lua.h"
10 #include "lauxlib.h"
11
12 #include "buffer.h"
13
14 /*=========================================================================*\
15 * Internal function prototypes
16 \*=========================================================================*/
17 static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b);
18 static int recvline(p_buffer buf, luaL_Buffer *b);
19 static int recvall(p_buffer buf, luaL_Buffer *b);
20 static int buffer_get(p_buffer buf, const char **data, size_t *count);
21 static void buffer_skip(p_buffer buf, size_t count);
22 static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent);
23
24 /* min and max macros */
25 #ifndef MIN
26 #define MIN(x, y) ((x) < (y) ? x : y)
27 #endif
28 #ifndef MAX
29 #define MAX(x, y) ((x) > (y) ? x : y)
30 #endif
31
32 /*=========================================================================*\
33 * Exported functions
34 \*=========================================================================*/
35 /*-------------------------------------------------------------------------*\
36 * Initializes C structure
37 \*-------------------------------------------------------------------------*/
38 void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
39 buf->first = buf->last = 0;
40 buf->io = io;
41 buf->tm = tm;
42 }
43
44 /*-------------------------------------------------------------------------*\
45 * object:send() interface
46 \*-------------------------------------------------------------------------*/
47 int buffer_meth_send(lua_State *L, p_buffer buf) {
48 int top = lua_gettop(L);
49 int err = IO_DONE;
50 size_t size = 0, sent = 0;
51 const char *data = luaL_checklstring(L, 2, &size);
52 long start = (long) luaL_optnumber(L, 3, 1);
53 long end = (long) luaL_optnumber(L, 4, -1);
54 p_timeout tm = timeout_markstart(buf->tm);
55 if (start < 0) start = (long) (size+start+1);
56 if (end < 0) end = (long) (size+end+1);
57 if (start < 1) start = (long) 1;
58 if (end > (long) size) end = (long) size;
59 if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent);
60 /* check if there was an error */
61 if (err != IO_DONE) {
62 lua_pushnil(L);
63 lua_pushstring(L, buf->io->error(buf->io->ctx, err));
64 lua_pushnumber(L, sent+start-1);
65 } else {
66 lua_pushnumber(L, sent+start-1);
67 lua_pushnil(L);
68 lua_pushnil(L);
69 }
70 #ifdef BUFFER_DEBUG
71 /* push time elapsed during operation as the last return value */
72 lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm));
73 #endif
74 return lua_gettop(L) - top;
75 }
76
77 /*-------------------------------------------------------------------------*\
78 * object:receive() interface
79 \*-------------------------------------------------------------------------*/
80 int buffer_meth_receive(lua_State *L, p_buffer buf) {
81 int err = IO_DONE, top = lua_gettop(L);
82 luaL_Buffer b;
83 size_t size;
84 const char *part = luaL_optlstring(L, 3, "", &size);
85 p_timeout tm = timeout_markstart(buf->tm);
86 /* initialize buffer with optional extra prefix
87 * (useful for concatenating previous partial results) */
88 luaL_buffinit(L, &b);
89 luaL_addlstring(&b, part, size);
90 /* receive new patterns */
91 if (!lua_isnumber(L, 2)) {
92 const char *p= luaL_optstring(L, 2, "*l");
93 if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b);
94 else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b);
95 else luaL_argcheck(L, 0, 2, "invalid receive pattern");
96 /* get a fixed number of bytes (minus what was already partially
97 * received) */
98 } else err = recvraw(buf, (size_t) lua_tonumber(L, 2)-size, &b);
99 /* check if there was an error */
100 if (err != IO_DONE) {
101 /* we can't push anyting in the stack before pushing the
102 * contents of the buffer. this is the reason for the complication */
103 luaL_pushresult(&b);
104 lua_pushstring(L, buf->io->error(buf->io->ctx, err));
105 lua_pushvalue(L, -2);
106 lua_pushnil(L);
107 lua_replace(L, -4);
108 } else {
109 luaL_pushresult(&b);
110 lua_pushnil(L);
111 lua_pushnil(L);
112 }
113 #ifdef BUFFER_DEBUG
114 /* push time elapsed during operation as the last return value */
115 lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm));
116 #endif
117 return lua_gettop(L) - top;
118 }
119
120 /*-------------------------------------------------------------------------*\
121 * Determines if there is any data in the read buffer
122 \*-------------------------------------------------------------------------*/
123 int buffer_isempty(p_buffer buf) {
124 return buf->first >= buf->last;
125 }
126
127 /*=========================================================================*\
128 * Internal functions
129 \*=========================================================================*/
130 /*-------------------------------------------------------------------------*\
131 * Sends a block of data (unbuffered)
132 \*-------------------------------------------------------------------------*/
133 #define STEPSIZE 8192
134 static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) {
135 p_io io = buf->io;
136 p_timeout tm = buf->tm;
137 size_t total = 0;
138 int err = IO_DONE;
139 while (total < count && err == IO_DONE) {
140 size_t done;
141 size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE;
142 err = io->send(io->ctx, data+total, step, &done, tm);
143 total += done;
144 }
145 *sent = total;
146 return err;
147 }
148
149 /*-------------------------------------------------------------------------*\
150 * Reads a fixed number of bytes (buffered)
151 \*-------------------------------------------------------------------------*/
152 static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b) {
153 int err = IO_DONE;
154 size_t total = 0;
155 while (err == IO_DONE) {
156 size_t count; const char *data;
157 err = buffer_get(buf, &data, &count);
158 count = MIN(count, wanted - total);
159 luaL_addlstring(b, data, count);
160 buffer_skip(buf, count);
161 total += count;
162 if (total >= wanted) break;
163 }
164 return err;
165 }
166
167 /*-------------------------------------------------------------------------*\
168 * Reads everything until the connection is closed (buffered)
169 \*-------------------------------------------------------------------------*/
170 static int recvall(p_buffer buf, luaL_Buffer *b) {
171 int err = IO_DONE;
172 size_t total = 0;
173 while (err == IO_DONE) {
174 const char *data; size_t count;
175 err = buffer_get(buf, &data, &count);
176 total += count;
177 luaL_addlstring(b, data, count);
178 buffer_skip(buf, count);
179 }
180 if (err == IO_CLOSED) {
181 if (total > 0) return IO_DONE;
182 else return IO_CLOSED;
183 } else return err;
184 }
185
186 /*-------------------------------------------------------------------------*\
187 * Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
188 * are not returned by the function and are discarded from the buffer
189 \*-------------------------------------------------------------------------*/
190 static int recvline(p_buffer buf, luaL_Buffer *b) {
191 int err = IO_DONE;
192 while (err == IO_DONE) {
193 size_t count, pos; const char *data;
194 err = buffer_get(buf, &data, &count);
195 pos = 0;
196 while (pos < count && data[pos] != '\n') {
197 /* we ignore all \r's */
198 if (data[pos] != '\r') luaL_putchar(b, data[pos]);
199 pos++;
200 }
201 if (pos < count) { /* found '\n' */
202 buffer_skip(buf, pos+1); /* skip '\n' too */
203 break; /* we are done */
204 } else /* reached the end of the buffer */
205 buffer_skip(buf, pos);
206 }
207 return err;
208 }
209
210 /*-------------------------------------------------------------------------*\
211 * Skips a given number of bytes from read buffer. No data is read from the
212 * transport layer
213 \*-------------------------------------------------------------------------*/
214 static void buffer_skip(p_buffer buf, size_t count) {
215 buf->first += count;
216 if (buffer_isempty(buf))
217 buf->first = buf->last = 0;
218 }
219
220 /*-------------------------------------------------------------------------*\
221 * Return any data available in buffer, or get more data from transport layer
222 * if buffer is empty
223 \*-------------------------------------------------------------------------*/
224 static int buffer_get(p_buffer buf, const char **data, size_t *count) {
225 int err = IO_DONE;
226 p_io io = buf->io;
227 p_timeout tm = buf->tm;
228 if (buffer_isempty(buf)) {
229 size_t got;
230 err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm);
231 buf->first = 0;
232 buf->last = got;
233 }
234 *count = buf->last - buf->first;
235 *data = buf->data + buf->first;
236 return err;
237 }

mercurial