diff options
Diffstat (limited to 'apps/plugins/lua/liolib.c')
-rw-r--r-- | apps/plugins/lua/liolib.c | 536 |
1 files changed, 380 insertions, 156 deletions
diff --git a/apps/plugins/lua/liolib.c b/apps/plugins/lua/liolib.c index 7a43915f20..a282dd1ac0 100644 --- a/apps/plugins/lua/liolib.c +++ b/apps/plugins/lua/liolib.c | |||
@@ -1,10 +1,21 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: liolib.c,v 2.73.1.3 2008/01/18 17:47:43 roberto Exp $ | 2 | ** $Id: liolib.c,v 2.112.1.1 2013/04/12 18:48:47 roberto Exp $ |
3 | ** Standard I/O (and system) library | 3 | ** Standard I/O (and system) library |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
6 | 6 | ||
7 | 7 | ||
8 | /* | ||
9 | ** This definition must come before the inclusion of 'stdio.h'; it | ||
10 | ** should not affect non-POSIX systems | ||
11 | */ | ||
12 | #if !defined(_FILE_OFFSET_BITS) | ||
13 | #define _LARGEFILE_SOURCE 1 | ||
14 | #define _FILE_OFFSET_BITS 64 | ||
15 | #endif | ||
16 | |||
17 | |||
18 | #include <errno.h> | ||
8 | #include <stdio.h> | 19 | #include <stdio.h> |
9 | #include <stdlib.h> | 20 | #include <stdlib.h> |
10 | #include <string.h> | 21 | #include <string.h> |
@@ -19,46 +30,111 @@ | |||
19 | #include "rocklibc.h" | 30 | #include "rocklibc.h" |
20 | 31 | ||
21 | 32 | ||
33 | #if !defined(lua_checkmode) | ||
22 | 34 | ||
23 | #define IO_INPUT 1 | 35 | /* |
24 | #define IO_OUTPUT 2 | 36 | ** Check whether 'mode' matches '[rwa]%+?b?'. |
37 | ** Change this macro to accept other modes for 'fopen' besides | ||
38 | ** the standard ones. | ||
39 | */ | ||
40 | #define lua_checkmode(mode) \ | ||
41 | (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \ | ||
42 | (*mode != '+' || ++mode) && /* skip if char is '+' */ \ | ||
43 | (*mode != 'b' || ++mode) && /* skip if char is 'b' */ \ | ||
44 | (*mode == '\0')) | ||
25 | 45 | ||
46 | #endif | ||
26 | 47 | ||
27 | static const char *const fnames[] = {"input", "output"}; | 48 | /* |
49 | ** {====================================================== | ||
50 | ** lua_popen spawns a new process connected to the current | ||
51 | ** one through the file streams. | ||
52 | ** ======================================================= | ||
53 | */ | ||
28 | 54 | ||
55 | #if !defined(lua_popen) /* { */ | ||
29 | 56 | ||
30 | static int pushresult (lua_State *L, int i, const char *filename) { | 57 | #if defined(LUA_USE_POPEN) /* { */ |
31 | int en = errno; | ||
32 | if (i) { | ||
33 | lua_pushboolean(L, 1); | ||
34 | return 1; | ||
35 | } | ||
36 | else { | ||
37 | lua_pushnil(L); | ||
38 | if (filename) | ||
39 | lua_pushfstring(L, "%s: %s", filename, strerror(en)); | ||
40 | else | ||
41 | lua_pushfstring(L, "%s", strerror(en)); | ||
42 | lua_pushinteger(L, 0); | ||
43 | return 3; | ||
44 | } | ||
45 | } | ||
46 | 58 | ||
59 | #define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m)) | ||
60 | #define lua_pclose(L,file) ((void)L, pclose(file)) | ||
47 | 61 | ||
48 | static void fileerror (lua_State *L, int arg, const char *filename) { | 62 | #elif defined(LUA_WIN) /* }{ */ |
49 | lua_pushfstring(L, "%s: %s", filename, strerror(errno)); | 63 | |
50 | luaL_argerror(L, arg, lua_tostring(L, -1)); | 64 | #define lua_popen(L,c,m) ((void)L, _popen(c,m)) |
51 | } | 65 | #define lua_pclose(L,file) ((void)L, _pclose(file)) |
66 | |||
67 | |||
68 | #else /* }{ */ | ||
69 | |||
70 | #define lua_popen(L,c,m) ((void)((void)c, m), \ | ||
71 | luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) | ||
72 | #define lua_pclose(L,file) ((void)((void)L, file), -1) | ||
73 | |||
74 | |||
75 | #endif /* } */ | ||
76 | |||
77 | #endif /* } */ | ||
78 | |||
79 | /* }====================================================== */ | ||
80 | |||
81 | |||
82 | /* | ||
83 | ** {====================================================== | ||
84 | ** lua_fseek: configuration for longer offsets | ||
85 | ** ======================================================= | ||
86 | */ | ||
87 | |||
88 | #if !defined(lua_fseek) && !defined(LUA_ANSI) /* { */ | ||
89 | |||
90 | #if defined(LUA_USE_POSIX) /* { */ | ||
91 | |||
92 | #define l_fseek(f,o,w) fseeko(f,o,w) | ||
93 | #define l_ftell(f) ftello(f) | ||
94 | #define l_seeknum off_t | ||
95 | |||
96 | #elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) \ | ||
97 | && defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */ | ||
98 | /* Windows (but not DDK) and Visual C++ 2005 or higher */ | ||
99 | |||
100 | #define l_fseek(f,o,w) _fseeki64(f,o,w) | ||
101 | #define l_ftell(f) _ftelli64(f) | ||
102 | #define l_seeknum __int64 | ||
103 | |||
104 | #endif /* } */ | ||
105 | |||
106 | #endif /* } */ | ||
107 | |||
108 | |||
109 | #if !defined(l_fseek) /* default definitions */ | ||
110 | #define l_fseek(f,o,w) fseek(f,o,w) | ||
111 | #define l_ftell(f) ftell(f) | ||
112 | #define l_seeknum long | ||
113 | #endif | ||
114 | |||
115 | /* }====================================================== */ | ||
116 | |||
117 | |||
118 | #define IO_PREFIX "_IO_" | ||
119 | #define IO_INPUT (IO_PREFIX "input") | ||
120 | #define IO_OUTPUT (IO_PREFIX "output") | ||
121 | |||
122 | |||
123 | typedef luaL_Stream LStream; | ||
124 | |||
125 | |||
126 | #define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) | ||
127 | |||
128 | #define isclosed(p) ((p)->closef == NULL) | ||
52 | 129 | ||
53 | 130 | ||
54 | static int io_type (lua_State *L) { | 131 | static int io_type (lua_State *L) { |
55 | void *ud; | 132 | LStream *p; |
56 | luaL_checkany(L, 1); | 133 | luaL_checkany(L, 1); |
57 | ud = lua_touserdata(L, 1); | 134 | p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE); |
58 | lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); | 135 | if (p == NULL) |
59 | if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) | ||
60 | lua_pushnil(L); /* not a file */ | 136 | lua_pushnil(L); /* not a file */ |
61 | else if (*((int *)ud) < 0) | 137 | else if (isclosed(p)) |
62 | lua_pushliteral(L, "closed file"); | 138 | lua_pushliteral(L, "closed file"); |
63 | else | 139 | else |
64 | lua_pushliteral(L, "file"); | 140 | lua_pushliteral(L, "file"); |
@@ -66,76 +142,97 @@ static int io_type (lua_State *L) { | |||
66 | } | 142 | } |
67 | 143 | ||
68 | 144 | ||
69 | static int* tofile (lua_State *L) { | 145 | static int f_tostring (lua_State *L) { |
70 | int *f = (int*) luaL_checkudata(L, 1, LUA_FILEHANDLE); | 146 | LStream *p = tolstream(L); |
71 | if (*f < 0) | 147 | if (isclosed(p)) |
72 | luaL_error(L, "attempt to use a closed file"); | 148 | lua_pushliteral(L, "file (closed)"); |
73 | return f; | 149 | else |
150 | lua_pushfstring(L, "file (%p)", p->f); | ||
151 | return 1; | ||
74 | } | 152 | } |
75 | 153 | ||
76 | 154 | ||
155 | static FILE *tofile (lua_State *L) { | ||
156 | LStream *p = tolstream(L); | ||
157 | if (isclosed(p)) | ||
158 | luaL_error(L, "attempt to use a closed file"); | ||
159 | lua_assert(p->f); | ||
160 | return p->f; | ||
161 | } | ||
162 | |||
77 | 163 | ||
78 | /* | 164 | /* |
79 | ** When creating file handles, always creates a `closed' file handle | 165 | ** When creating file handles, always creates a `closed' file handle |
80 | ** before opening the actual file; so, if there is a memory error, the | 166 | ** before opening the actual file; so, if there is a memory error, the |
81 | ** file is not left opened. | 167 | ** file is not left opened. |
82 | */ | 168 | */ |
83 | static int* newfile (lua_State *L) { | 169 | static LStream *newprefile (lua_State *L) { |
84 | int *pf = (int *)lua_newuserdata(L, sizeof(int)); | 170 | LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream)); |
85 | *pf = -1; /* file handle is currently `closed' */ | 171 | p->closef = NULL; /* mark file handle as 'closed' */ |
86 | luaL_getmetatable(L, LUA_FILEHANDLE); | 172 | luaL_setmetatable(L, LUA_FILEHANDLE); |
87 | lua_setmetatable(L, -2); | 173 | return p; |
88 | return pf; | ||
89 | } | ||
90 | |||
91 | |||
92 | /* | ||
93 | ** function to close regular files | ||
94 | */ | ||
95 | static int io_fclose (lua_State *L) { | ||
96 | int *p = tofile(L); | ||
97 | int ok = (rb->close(*p) == 0); | ||
98 | *p = -1; | ||
99 | return pushresult(L, ok, NULL); | ||
100 | } | 174 | } |
101 | 175 | ||
102 | 176 | ||
103 | static inline int aux_close (lua_State *L) { | 177 | static int aux_close (lua_State *L) { |
104 | return io_fclose(L); | 178 | LStream *p = tolstream(L); |
179 | lua_CFunction cf = p->closef; | ||
180 | p->closef = NULL; /* mark stream as closed */ | ||
181 | return (*cf)(L); /* close it */ | ||
105 | } | 182 | } |
106 | 183 | ||
107 | 184 | ||
108 | static int io_close (lua_State *L) { | 185 | static int io_close (lua_State *L) { |
109 | if (lua_isnone(L, 1)) | 186 | if (lua_isnone(L, 1)) /* no argument? */ |
110 | lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); | 187 | lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ |
111 | tofile(L); /* make sure argument is a file */ | 188 | tofile(L); /* make sure argument is an open stream */ |
112 | return aux_close(L); | 189 | return aux_close(L); |
113 | } | 190 | } |
114 | 191 | ||
115 | 192 | ||
116 | static int io_gc (lua_State *L) { | 193 | static int f_gc (lua_State *L) { |
117 | int f = *(int*) luaL_checkudata(L, 1, LUA_FILEHANDLE); | 194 | LStream *p = tolstream(L); |
118 | /* ignore closed files */ | 195 | if (!isclosed(p) && p->f != NULL) |
119 | if (f >= 0) | 196 | aux_close(L); /* ignore closed and incompletely open files */ |
120 | aux_close(L); | ||
121 | return 0; | 197 | return 0; |
122 | } | 198 | } |
123 | 199 | ||
124 | 200 | ||
125 | static int io_tostring (lua_State *L) { | 201 | /* |
126 | int f = *(int*) luaL_checkudata(L, 1, LUA_FILEHANDLE); | 202 | ** function to close regular files |
127 | if (f < 0) | 203 | */ |
128 | lua_pushliteral(L, "file (closed)"); | 204 | static int io_fclose (lua_State *L) { |
129 | else | 205 | LStream *p = tolstream(L); |
130 | lua_pushfstring(L, "file (%d)", f); | 206 | int res = rb->close((int)p->f); |
131 | return 1; | 207 | return luaL_fileresult(L, (res == 0), NULL); |
208 | } | ||
209 | |||
210 | |||
211 | static LStream *newfile (lua_State *L) { | ||
212 | LStream *p = newprefile(L); | ||
213 | p->f = NULL; | ||
214 | p->closef = &io_fclose; | ||
215 | return p; | ||
216 | } | ||
217 | |||
218 | |||
219 | static void opencheck (lua_State *L, const char *fname, const char *mode) { | ||
220 | LStream *p = newfile(L); | ||
221 | int flags = O_RDONLY; | ||
222 | if (strcmp(mode, "w") == 0) | ||
223 | flags = O_WRONLY; | ||
224 | p->f = (FILE*)rb->open(fname, flags); | ||
225 | if (p->f == NULL) | ||
226 | luaL_error(L, "cannot open file " LUA_QS " (%s)", fname, strerror(errno)); | ||
132 | } | 227 | } |
133 | 228 | ||
134 | 229 | ||
135 | static int io_open (lua_State *L) { | 230 | static int io_open (lua_State *L) { |
136 | const char *filename = luaL_checkstring(L, 1); | 231 | const char *filename = luaL_checkstring(L, 1); |
137 | const char *mode = luaL_optstring(L, 2, "r"); | 232 | const char *mode = luaL_optstring(L, 2, "r"); |
138 | int *pf = newfile(L); | 233 | LStream *p = newfile(L); |
234 | const char *md = mode; /* to traverse/check mode */ | ||
235 | luaL_argcheck(L, lua_checkmode(md), 2, "invalid mode"); | ||
139 | int flags = 0; | 236 | int flags = 0; |
140 | if(*(mode+1) == '+') { | 237 | if(*(mode+1) == '+') { |
141 | flags = O_RDWR; | 238 | flags = O_RDWR; |
@@ -158,84 +255,117 @@ static int io_open (lua_State *L) { | |||
158 | } | 255 | } |
159 | if((*mode == 'w' || *mode == 'a') && !rb->file_exists(filename)) | 256 | if((*mode == 'w' || *mode == 'a') && !rb->file_exists(filename)) |
160 | flags |= O_CREAT; | 257 | flags |= O_CREAT; |
161 | *pf = rb->open(filename, flags, 0666); | 258 | int pf = rb->open(filename, flags, 0666); |
162 | return (*pf < 0) ? pushresult(L, 0, filename) : 1; | 259 | p->f = (FILE*)pf; |
260 | return (pf < 0) ? luaL_fileresult(L, 0, filename) : 1; | ||
163 | } | 261 | } |
164 | 262 | ||
165 | 263 | ||
166 | static int* getiofile (lua_State *L, int findex) { | 264 | #if 0 |
167 | int *f; | 265 | /* |
168 | lua_rawgeti(L, LUA_ENVIRONINDEX, findex); | 266 | ** function to close 'popen' files |
169 | f = (int *)lua_touserdata(L, -1); | 267 | */ |
170 | if (f == NULL || *f < 0) | 268 | static int io_pclose (lua_State *L) { |
171 | luaL_error(L, "standard %s file is closed", fnames[findex - 1]); | 269 | LStream *p = tolstream(L); |
172 | return f; | 270 | return luaL_execresult(L, lua_pclose(L, p->f)); |
173 | } | 271 | } |
174 | 272 | ||
175 | 273 | ||
176 | static int g_iofile (lua_State *L, int f, int flags) { | 274 | static int io_popen (lua_State *L) { |
275 | const char *filename = luaL_checkstring(L, 1); | ||
276 | const char *mode = luaL_optstring(L, 2, "r"); | ||
277 | LStream *p = newprefile(L); | ||
278 | p->f = lua_popen(L, filename, mode); | ||
279 | p->closef = &io_pclose; | ||
280 | return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; | ||
281 | } | ||
282 | |||
283 | |||
284 | static int io_tmpfile (lua_State *L) { | ||
285 | LStream *p = newfile(L); | ||
286 | p->f = tmpfile(); | ||
287 | return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; | ||
288 | } | ||
289 | #endif | ||
290 | |||
291 | |||
292 | static FILE *getiofile (lua_State *L, const char *findex) { | ||
293 | LStream *p; | ||
294 | lua_getfield(L, LUA_REGISTRYINDEX, findex); | ||
295 | p = (LStream *)lua_touserdata(L, -1); | ||
296 | if (isclosed(p)) | ||
297 | luaL_error(L, "standard %s file is closed", findex + strlen(IO_PREFIX)); | ||
298 | return p->f; | ||
299 | } | ||
300 | |||
301 | |||
302 | static int g_iofile (lua_State *L, const char *f, const char *mode) { | ||
177 | if (!lua_isnoneornil(L, 1)) { | 303 | if (!lua_isnoneornil(L, 1)) { |
178 | const char *filename = lua_tostring(L, 1); | 304 | const char *filename = lua_tostring(L, 1); |
179 | if (filename) { | 305 | if (filename) |
180 | int *pf = newfile(L); | 306 | opencheck(L, filename, mode); |
181 | *pf = rb->open(filename, flags); | ||
182 | if (*pf < 0) | ||
183 | fileerror(L, 1, filename); | ||
184 | } | ||
185 | else { | 307 | else { |
186 | tofile(L); /* check that it's a valid file handle */ | 308 | tofile(L); /* check that it's a valid file handle */ |
187 | lua_pushvalue(L, 1); | 309 | lua_pushvalue(L, 1); |
188 | } | 310 | } |
189 | lua_rawseti(L, LUA_ENVIRONINDEX, f); | 311 | lua_setfield(L, LUA_REGISTRYINDEX, f); |
190 | } | 312 | } |
191 | /* return current value */ | 313 | /* return current value */ |
192 | lua_rawgeti(L, LUA_ENVIRONINDEX, f); | 314 | lua_getfield(L, LUA_REGISTRYINDEX, f); |
193 | return 1; | 315 | return 1; |
194 | } | 316 | } |
195 | 317 | ||
196 | 318 | ||
197 | static int io_input (lua_State *L) { | 319 | static int io_input (lua_State *L) { |
198 | return g_iofile(L, IO_INPUT, O_RDONLY); | 320 | return g_iofile(L, IO_INPUT, "r"); |
199 | } | 321 | } |
200 | 322 | ||
201 | 323 | ||
202 | static int io_output (lua_State *L) { | 324 | static int io_output (lua_State *L) { |
203 | return g_iofile(L, IO_OUTPUT, O_WRONLY); | 325 | return g_iofile(L, IO_OUTPUT, "w"); |
204 | } | 326 | } |
205 | 327 | ||
206 | 328 | ||
207 | static int io_readline (lua_State *L); | 329 | static int io_readline (lua_State *L); |
208 | 330 | ||
209 | 331 | ||
210 | static void aux_lines (lua_State *L, int idx, int toclose) { | 332 | static void aux_lines (lua_State *L, int toclose) { |
211 | lua_pushvalue(L, idx); | 333 | int i; |
334 | int n = lua_gettop(L) - 1; /* number of arguments to read */ | ||
335 | /* ensure that arguments will fit here and into 'io_readline' stack */ | ||
336 | luaL_argcheck(L, n <= LUA_MINSTACK - 3, LUA_MINSTACK - 3, "too many options"); | ||
337 | lua_pushvalue(L, 1); /* file handle */ | ||
338 | lua_pushinteger(L, n); /* number of arguments to read */ | ||
212 | lua_pushboolean(L, toclose); /* close/not close file when finished */ | 339 | lua_pushboolean(L, toclose); /* close/not close file when finished */ |
213 | lua_pushcclosure(L, io_readline, 2); | 340 | for (i = 1; i <= n; i++) lua_pushvalue(L, i + 1); /* copy arguments */ |
341 | lua_pushcclosure(L, io_readline, 3 + n); | ||
214 | } | 342 | } |
215 | 343 | ||
216 | 344 | ||
217 | static int f_lines (lua_State *L) { | 345 | static int f_lines (lua_State *L) { |
218 | tofile(L); /* check that it's a valid file handle */ | 346 | tofile(L); /* check that it's a valid file handle */ |
219 | aux_lines(L, 1, 0); | 347 | aux_lines(L, 0); |
220 | return 1; | 348 | return 1; |
221 | } | 349 | } |
222 | 350 | ||
223 | 351 | ||
224 | static int io_lines (lua_State *L) { | 352 | static int io_lines (lua_State *L) { |
225 | if (lua_isnoneornil(L, 1)) { /* no arguments? */ | 353 | int toclose; |
226 | /* will iterate over default input */ | 354 | if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ |
227 | lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT); | 355 | if (lua_isnil(L, 1)) { /* no file name? */ |
228 | return f_lines(L); | 356 | lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */ |
357 | lua_replace(L, 1); /* put it at index 1 */ | ||
358 | tofile(L); /* check that it's a valid file handle */ | ||
359 | toclose = 0; /* do not close it after iteration */ | ||
229 | } | 360 | } |
230 | else { | 361 | else { /* open a new file */ |
231 | const char *filename = luaL_checkstring(L, 1); | 362 | const char *filename = luaL_checkstring(L, 1); |
232 | int *pf = newfile(L); | 363 | opencheck(L, filename, "r"); |
233 | *pf = rb->open(filename, O_RDONLY); | 364 | lua_replace(L, 1); /* put file at index 1 */ |
234 | if (*pf < 0) | 365 | toclose = 1; /* close it after iteration */ |
235 | fileerror(L, 1, filename); | ||
236 | aux_lines(L, lua_gettop(L), 1); | ||
237 | return 1; | ||
238 | } | 366 | } |
367 | aux_lines(L, toclose); | ||
368 | return 1; | ||
239 | } | 369 | } |
240 | 370 | ||
241 | 371 | ||
@@ -245,72 +375,89 @@ static int io_lines (lua_State *L) { | |||
245 | ** ======================================================= | 375 | ** ======================================================= |
246 | */ | 376 | */ |
247 | 377 | ||
248 | static int read_number (lua_State *L, int *f) { | 378 | |
379 | static int read_number (lua_State *L, FILE *f) { | ||
249 | lua_Number d; | 380 | lua_Number d; |
250 | if (PREFIX(fscanf)(*f, LUA_NUMBER_SCAN, &d) == 1) { | 381 | if (PREFIX(fscanf)(f, LUA_NUMBER_SCAN, &d) == 1) { |
251 | lua_pushnumber(L, d); | 382 | lua_pushnumber(L, d); |
252 | return 1; | 383 | return 1; |
253 | } | 384 | } |
254 | else return 0; /* read fails */ | 385 | else { |
386 | lua_pushnil(L); /* "result" to be removed */ | ||
387 | return 0; /* read fails */ | ||
388 | } | ||
255 | } | 389 | } |
256 | 390 | ||
257 | 391 | ||
258 | static int test_eof (lua_State *L, int *f) { | 392 | static int test_eof (lua_State *L, FILE *f) { |
259 | ssize_t s = rb->lseek(*f, 0, SEEK_CUR); | 393 | ssize_t s = rb->lseek((int)f, 0, SEEK_CUR); |
260 | lua_pushlstring(L, NULL, 0); | 394 | lua_pushlstring(L, NULL, 0); |
261 | return s != rb->filesize(*f); | 395 | return s != rb->filesize((int)f); |
262 | } | 396 | } |
263 | 397 | ||
264 | 398 | ||
265 | /* Rockbox already defines read_line() */ | 399 | /* Rockbox already defines read_line() */ |
266 | static int _read_line (lua_State *L, int *f) { | 400 | static int _read_line (lua_State *L, FILE *f, int chop) { |
267 | luaL_Buffer b; | 401 | luaL_Buffer b; |
268 | luaL_buffinit(L, &b); | 402 | luaL_buffinit(L, &b); |
269 | for (;;) { | 403 | for (;;) { |
270 | size_t l; | 404 | size_t l; |
271 | size_t r; | 405 | size_t r; |
272 | char *p = luaL_prepbuffer(&b); | 406 | char *p = luaL_prepbuffer(&b); |
273 | r = rb->read_line(*f, p, LUAL_BUFFERSIZE); | 407 | r = rb->read_line((int)f, p, LUAL_BUFFERSIZE); |
274 | l = strlen(p); | 408 | l = strlen(p); |
275 | if (l == 0 || p[l-1] != '\n') | 409 | if (l == 0 || p[l-1] != '\n') |
276 | luaL_addsize(&b, l); | 410 | luaL_addsize(&b, l); |
277 | else { | 411 | else { |
278 | luaL_addsize(&b, l - 1); /* do not include `eol' */ | 412 | luaL_addsize(&b, l - chop); /* chop 'eol' if needed */ |
279 | luaL_pushresult(&b); /* close buffer */ | 413 | luaL_pushresult(&b); /* close buffer */ |
280 | return 1; /* read at least an `eol' */ | 414 | return 1; /* read at least an `eol' */ |
281 | } | 415 | } |
282 | if (r < LUAL_BUFFERSIZE) { /* eof? */ | 416 | if (r < LUAL_BUFFERSIZE) { /* eof? */ |
283 | luaL_pushresult(&b); /* close buffer */ | 417 | luaL_pushresult(&b); /* close buffer */ |
284 | return (lua_objlen(L, -1) > 0); /* check whether read something */ | 418 | return (lua_rawlen(L, -1) > 0); /* check whether read something */ |
285 | } | 419 | } |
286 | } | 420 | } |
287 | } | 421 | } |
288 | 422 | ||
289 | 423 | ||
290 | static int read_chars (lua_State *L, int *f, size_t n) { | 424 | #define MAX_SIZE_T (~(size_t)0) |
291 | size_t rlen; /* how much to read */ | 425 | |
292 | size_t nr; /* number of chars actually read */ | 426 | static void read_all (lua_State *L, FILE *f) { |
427 | size_t rlen = LUAL_BUFFERSIZE; /* how much to read in each cycle */ | ||
293 | luaL_Buffer b; | 428 | luaL_Buffer b; |
294 | luaL_buffinit(L, &b); | 429 | luaL_buffinit(L, &b); |
295 | rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ | 430 | for (;;) { |
296 | do { | 431 | char *p = luaL_prepbuffsize(&b, rlen); |
297 | char *p = luaL_prepbuffer(&b); | 432 | size_t nr = rb->read((int)f, p, rlen); |
298 | if (rlen > n) rlen = n; /* cannot read more than asked */ | ||
299 | nr = rb->read(*f, p, rlen); | ||
300 | luaL_addsize(&b, nr); | 433 | luaL_addsize(&b, nr); |
301 | n -= nr; /* still have to read `n' chars */ | 434 | if (nr < rlen) break; /* eof? */ |
302 | } while (n > 0 && nr == rlen); /* until end of count or eof */ | 435 | else if (rlen <= (MAX_SIZE_T / 4)) /* avoid buffers too large */ |
436 | rlen *= 2; /* double buffer size at each iteration */ | ||
437 | } | ||
438 | luaL_pushresult(&b); /* close buffer */ | ||
439 | } | ||
440 | |||
441 | |||
442 | static int read_chars (lua_State *L, FILE *f, size_t n) { | ||
443 | size_t nr; /* number of chars actually read */ | ||
444 | char *p; | ||
445 | luaL_Buffer b; | ||
446 | luaL_buffinit(L, &b); | ||
447 | p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */ | ||
448 | nr = rb->read((int)f, p, n); /* try to read 'n' chars */ | ||
449 | luaL_addsize(&b, nr); | ||
303 | luaL_pushresult(&b); /* close buffer */ | 450 | luaL_pushresult(&b); /* close buffer */ |
304 | return (n == 0 || lua_objlen(L, -1) > 0); | 451 | return (nr > 0); /* true iff read something */ |
305 | } | 452 | } |
306 | 453 | ||
307 | 454 | ||
308 | static int g_read (lua_State *L, int *f, int first) { | 455 | static int g_read (lua_State *L, FILE *f, int first) { |
309 | int nargs = lua_gettop(L) - 1; | 456 | int nargs = lua_gettop(L) - 1; |
310 | int success; | 457 | int success; |
311 | int n; | 458 | int n; |
312 | if (nargs == 0) { /* no arguments? */ | 459 | if (nargs == 0) { /* no arguments? */ |
313 | success = _read_line(L, f); | 460 | success = _read_line(L, f, 1); |
314 | n = first+1; /* to return 1 result */ | 461 | n = first+1; /* to return 1 result */ |
315 | } | 462 | } |
316 | else { /* ensure stack space for all results and for auxlib's buffer */ | 463 | else { /* ensure stack space for all results and for auxlib's buffer */ |
@@ -329,10 +476,13 @@ static int g_read (lua_State *L, int *f, int first) { | |||
329 | success = read_number(L, f); | 476 | success = read_number(L, f); |
330 | break; | 477 | break; |
331 | case 'l': /* line */ | 478 | case 'l': /* line */ |
332 | success = _read_line(L, f); | 479 | success = _read_line(L, f, 1); |
480 | break; | ||
481 | case 'L': /* line with end-of-line */ | ||
482 | success = _read_line(L, f, 0); | ||
333 | break; | 483 | break; |
334 | case 'a': /* file */ | 484 | case 'a': /* file */ |
335 | read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ | 485 | read_all(L, f); /* read entire file */ |
336 | success = 1; /* always success */ | 486 | success = 1; /* always success */ |
337 | break; | 487 | break; |
338 | default: | 488 | default: |
@@ -360,14 +510,24 @@ static int f_read (lua_State *L) { | |||
360 | 510 | ||
361 | 511 | ||
362 | static int io_readline (lua_State *L) { | 512 | static int io_readline (lua_State *L) { |
363 | int *f = (int *) lua_touserdata(L, lua_upvalueindex(1)); | 513 | LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); |
364 | int sucess; | 514 | int i; |
365 | if (*f < 0) /* file is already closed? */ | 515 | int n = (int)lua_tointeger(L, lua_upvalueindex(2)); |
366 | luaL_error(L, "file is already closed"); | 516 | if (isclosed(p)) /* file is already closed? */ |
367 | sucess = _read_line(L, f); | 517 | return luaL_error(L, "file is already closed"); |
368 | if (sucess) return 1; | 518 | lua_settop(L , 1); |
369 | else { /* EOF */ | 519 | for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ |
370 | if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ | 520 | lua_pushvalue(L, lua_upvalueindex(3 + i)); |
521 | n = g_read(L, p->f, 2); /* 'n' is number of results */ | ||
522 | lua_assert(n > 0); /* should return at least a nil */ | ||
523 | if (!lua_isnil(L, -n)) /* read at least one value? */ | ||
524 | return n; /* return them */ | ||
525 | else { /* first result is nil: EOF or error */ | ||
526 | if (n > 1) { /* is there error information? */ | ||
527 | /* 2nd result is error message */ | ||
528 | return luaL_error(L, "%s", lua_tostring(L, -n + 1)); | ||
529 | } | ||
530 | if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ | ||
371 | lua_settop(L, 0); | 531 | lua_settop(L, 0); |
372 | lua_pushvalue(L, lua_upvalueindex(1)); | 532 | lua_pushvalue(L, lua_upvalueindex(1)); |
373 | aux_close(L); /* close it */ | 533 | aux_close(L); /* close it */ |
@@ -379,22 +539,23 @@ static int io_readline (lua_State *L) { | |||
379 | /* }====================================================== */ | 539 | /* }====================================================== */ |
380 | 540 | ||
381 | 541 | ||
382 | static int g_write (lua_State *L, int *f, int arg) { | 542 | static int g_write (lua_State *L, FILE *f, int arg) { |
383 | int nargs = lua_gettop(L) - 1; | 543 | int nargs = lua_gettop(L) - arg; |
384 | int status = 1; | 544 | int status = 1; |
385 | for (; nargs--; arg++) { | 545 | for (; nargs--; arg++) { |
386 | if (lua_type(L, arg) == LUA_TNUMBER) { | 546 | if (lua_type(L, arg) == LUA_TNUMBER) { |
387 | /* optimization: could be done exactly as for strings */ | 547 | /* optimization: could be done exactly as for strings */ |
388 | status = status && | 548 | status = status && |
389 | rb->fdprintf(*f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; | 549 | rb->fdprintf((int)f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; |
390 | } | 550 | } |
391 | else { | 551 | else { |
392 | size_t l; | 552 | size_t l; |
393 | const char *s = luaL_checklstring(L, arg, &l); | 553 | const char *s = luaL_checklstring(L, arg, &l); |
394 | status = status && (rb->write(*f, s, l) == (ssize_t)l); | 554 | status = status && (rb->write((int)f, s, l) == (ssize_t)l); |
395 | } | 555 | } |
396 | } | 556 | } |
397 | return pushresult(L, status, NULL); | 557 | if (status) return 1; /* file handle already on stack top */ |
558 | else return luaL_fileresult(L, status, NULL); | ||
398 | } | 559 | } |
399 | 560 | ||
400 | 561 | ||
@@ -404,47 +565,86 @@ static int io_write (lua_State *L) { | |||
404 | 565 | ||
405 | 566 | ||
406 | static int f_write (lua_State *L) { | 567 | static int f_write (lua_State *L) { |
407 | return g_write(L, tofile(L), 2); | 568 | FILE *f = tofile(L); |
569 | lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ | ||
570 | return g_write(L, f, 2); | ||
408 | } | 571 | } |
409 | 572 | ||
410 | 573 | ||
411 | static int f_seek (lua_State *L) { | 574 | static int f_seek (lua_State *L) { |
412 | static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; | 575 | static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; |
413 | static const char *const modenames[] = {"set", "cur", "end", NULL}; | 576 | static const char *const modenames[] = {"set", "cur", "end", NULL}; |
414 | int f = *tofile(L); | 577 | FILE *f = tofile(L); |
415 | int op = luaL_checkoption(L, 2, "cur", modenames); | 578 | int op = luaL_checkoption(L, 2, "cur", modenames); |
416 | long offset = luaL_optlong(L, 3, 0); | 579 | lua_Number p3 = luaL_optnumber(L, 3, 0); |
417 | op = rb->lseek(f, offset, mode[op]); | 580 | l_seeknum offset = (l_seeknum)p3; |
581 | luaL_argcheck(L, (lua_Number)offset == p3, 3, | ||
582 | "not an integer in proper range"); | ||
583 | op = rb->lseek((int)f, offset, mode[op]); | ||
418 | if (op) | 584 | if (op) |
419 | return pushresult(L, 0, NULL); /* error */ | 585 | return luaL_fileresult(L, 0, NULL); /* error */ |
420 | else { | 586 | else { |
421 | lua_pushinteger(L, rb->lseek(f, 0, SEEK_CUR)); | 587 | lua_pushnumber(L, (lua_Number)rb->lseek((int)f, 0, SEEK_CUR)); |
422 | return 1; | 588 | return 1; |
423 | } | 589 | } |
424 | } | 590 | } |
425 | 591 | ||
592 | #if 0 | ||
593 | static int f_setvbuf (lua_State *L) { | ||
594 | static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; | ||
595 | static const char *const modenames[] = {"no", "full", "line", NULL}; | ||
596 | FILE *f = tofile(L); | ||
597 | int op = luaL_checkoption(L, 2, NULL, modenames); | ||
598 | lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); | ||
599 | int res = setvbuf(f, NULL, mode[op], sz); | ||
600 | return luaL_fileresult(L, res == 0, NULL); | ||
601 | } | ||
602 | |||
426 | 603 | ||
604 | |||
605 | static int io_flush (lua_State *L) { | ||
606 | return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); | ||
607 | } | ||
608 | |||
609 | |||
610 | static int f_flush (lua_State *L) { | ||
611 | return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); | ||
612 | } | ||
613 | #endif | ||
614 | |||
615 | |||
616 | /* | ||
617 | ** functions for 'io' library | ||
618 | */ | ||
427 | static const luaL_Reg iolib[] = { | 619 | static const luaL_Reg iolib[] = { |
428 | {"close", io_close}, | 620 | {"close", io_close}, |
621 | /*{"flush", io_flush},*/ | ||
429 | {"input", io_input}, | 622 | {"input", io_input}, |
430 | {"lines", io_lines}, | 623 | {"lines", io_lines}, |
431 | {"open", io_open}, | 624 | {"open", io_open}, |
432 | {"output", io_output}, | 625 | {"output", io_output}, |
626 | /*{"popen", io_popen},*/ | ||
433 | {"read", io_read}, | 627 | {"read", io_read}, |
628 | /*{"tmpfile", io_tmpfile},*/ | ||
434 | {"type", io_type}, | 629 | {"type", io_type}, |
435 | {"write", io_write}, | 630 | {"write", io_write}, |
436 | {NULL, NULL} | 631 | {NULL, NULL} |
437 | }; | 632 | }; |
438 | 633 | ||
439 | 634 | ||
635 | /* | ||
636 | ** methods for file handles | ||
637 | */ | ||
440 | static const luaL_Reg flib[] = { | 638 | static const luaL_Reg flib[] = { |
441 | {"close", io_close}, | 639 | {"close", io_close}, |
640 | /*{"flush", f_flush},*/ | ||
442 | {"lines", f_lines}, | 641 | {"lines", f_lines}, |
443 | {"read", f_read}, | 642 | {"read", f_read}, |
444 | {"seek", f_seek}, | 643 | {"seek", f_seek}, |
644 | /*{"setvbuf", f_setvbuf},*/ | ||
445 | {"write", f_write}, | 645 | {"write", f_write}, |
446 | {"__gc", io_gc}, | 646 | {"__gc", f_gc}, |
447 | {"__tostring", io_tostring}, | 647 | {"__tostring", f_tostring}, |
448 | {NULL, NULL} | 648 | {NULL, NULL} |
449 | }; | 649 | }; |
450 | 650 | ||
@@ -453,16 +653,40 @@ static void createmeta (lua_State *L) { | |||
453 | luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ | 653 | luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ |
454 | lua_pushvalue(L, -1); /* push metatable */ | 654 | lua_pushvalue(L, -1); /* push metatable */ |
455 | lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ | 655 | lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ |
456 | luaL_register(L, NULL, flib); /* file methods */ | 656 | luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */ |
657 | lua_pop(L, 1); /* pop new metatable */ | ||
457 | } | 658 | } |
458 | 659 | ||
459 | 660 | ||
460 | LUALIB_API int luaopen_io (lua_State *L) { | 661 | /* |
662 | ** function to (not) close the standard files stdin, stdout, and stderr | ||
663 | */ | ||
664 | #if 0 | ||
665 | static int io_noclose (lua_State *L) { | ||
666 | LStream *p = tolstream(L); | ||
667 | p->closef = &io_noclose; /* keep file opened */ | ||
668 | lua_pushnil(L); | ||
669 | lua_pushliteral(L, "cannot close standard file"); | ||
670 | return 2; | ||
671 | } | ||
672 | |||
673 | |||
674 | static void createstdfile (lua_State *L, FILE *f, const char *k, | ||
675 | const char *fname) { | ||
676 | LStream *p = newprefile(L); | ||
677 | p->f = f; | ||
678 | p->closef = &io_noclose; | ||
679 | if (k != NULL) { | ||
680 | lua_pushvalue(L, -1); | ||
681 | lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ | ||
682 | } | ||
683 | lua_setfield(L, -2, fname); /* add file to module */ | ||
684 | } | ||
685 | #endif | ||
686 | |||
687 | LUAMOD_API int luaopen_io (lua_State *L) { | ||
688 | luaL_newlib(L, iolib); /* new module */ | ||
461 | createmeta(L); | 689 | createmeta(L); |
462 | lua_replace(L, LUA_ENVIRONINDEX); | ||
463 | /* open library */ | ||
464 | luaL_register(L, LUA_IOLIBNAME, iolib); | ||
465 | /* create (and set) default files */ | 690 | /* create (and set) default files */ |
466 | lua_pop(L, 1); /* pop environment for default files */ | ||
467 | return 1; | 691 | return 1; |
468 | } | 692 | } |