Branch data Line data Source code
1 : : /*
2 : : ** $Id: liolib.c $
3 : : ** Standard I/O (and system) library
4 : : ** See Copyright Notice in lua.h
5 : : */
6 : :
7 : : #define liolib_c
8 : : #define LUA_LIB
9 : :
10 : : #include "lprefix.h"
11 : :
12 : :
13 : : #include <ctype.h>
14 : : #include <errno.h>
15 : : #include <locale.h>
16 : : #include <stdio.h>
17 : : #include <stdlib.h>
18 : : #include <string.h>
19 : :
20 : : #include "lua.h"
21 : :
22 : : #include "lauxlib.h"
23 : : #include "lualib.h"
24 : :
25 : :
26 : :
27 : :
28 : : /*
29 : : ** Change this macro to accept other modes for 'fopen' besides
30 : : ** the standard ones.
31 : : */
32 : : #if !defined(l_checkmode)
33 : :
34 : : /* accepted extensions to 'mode' in 'fopen' */
35 : : #if !defined(L_MODEEXT)
36 : : #define L_MODEEXT "b"
37 : : #endif
38 : :
39 : : /* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */
40 : 0 : static int l_checkmode (const char *mode) {
41 [ # # # # ]: 0 : return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL &&
42 [ # # # # ]: 0 : (*mode != '+' || ((void)(++mode), 1)) && /* skip if char is '+' */
43 : 0 : (strspn(mode, L_MODEEXT) == strlen(mode))); /* check extensions */
44 : : }
45 : :
46 : : #endif
47 : :
48 : : /*
49 : : ** {======================================================
50 : : ** l_popen spawns a new process connected to the current
51 : : ** one through the file streams.
52 : : ** =======================================================
53 : : */
54 : :
55 : : #if !defined(l_checkmodep)
56 : : /* By default, Lua accepts only "r" or "w" as mode */
57 : : #define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && m[1] == '\0')
58 : : #endif
59 : :
60 : :
61 : : #if !defined(l_popen) /* { */
62 : :
63 : : #if defined(LUA_USE_POSIX) /* { */
64 : :
65 : : #define l_popen(L,c,m) (fflush(NULL), popen(c,m))
66 : : #define l_pclose(L,file) (pclose(file))
67 : :
68 : : #elif defined(LUA_USE_WINDOWS) /* }{ */
69 : :
70 : : #define l_popen(L,c,m) (_popen(c,m))
71 : : #define l_pclose(L,file) (_pclose(file))
72 : :
73 : : #else /* }{ */
74 : :
75 : : /* ISO C definitions */
76 : : #define l_popen(L,c,m) \
77 : : ((void)c, (void)m, \
78 : : luaL_error(L, "'popen' not supported"), \
79 : : (FILE*)0)
80 : : #define l_pclose(L,file) ((void)L, (void)file, -1)
81 : :
82 : : #endif /* } */
83 : :
84 : : #endif /* } */
85 : :
86 : : /* }====================================================== */
87 : :
88 : :
89 : : #if !defined(l_getc) /* { */
90 : :
91 : : #if defined(LUA_USE_POSIX)
92 : : #define l_getc(f) getc_unlocked(f)
93 : : #define l_lockfile(f) flockfile(f)
94 : : #define l_unlockfile(f) funlockfile(f)
95 : : #else
96 : : #define l_getc(f) getc(f)
97 : : #define l_lockfile(f) ((void)0)
98 : : #define l_unlockfile(f) ((void)0)
99 : : #endif
100 : :
101 : : #endif /* } */
102 : :
103 : :
104 : : /*
105 : : ** {======================================================
106 : : ** l_fseek: configuration for longer offsets
107 : : ** =======================================================
108 : : */
109 : :
110 : : #if !defined(l_fseek) /* { */
111 : :
112 : : #if defined(LUA_USE_POSIX) /* { */
113 : :
114 : : #include <sys/types.h>
115 : :
116 : : #define l_fseek(f,o,w) fseeko(f,o,w)
117 : : #define l_ftell(f) ftello(f)
118 : : #define l_seeknum off_t
119 : :
120 : : #elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \
121 : : && defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */
122 : :
123 : : /* Windows (but not DDK) and Visual C++ 2005 or higher */
124 : : #define l_fseek(f,o,w) _fseeki64(f,o,w)
125 : : #define l_ftell(f) _ftelli64(f)
126 : : #define l_seeknum __int64
127 : :
128 : : #else /* }{ */
129 : :
130 : : /* ISO C definitions */
131 : : #define l_fseek(f,o,w) fseek(f,o,w)
132 : : #define l_ftell(f) ftell(f)
133 : : #define l_seeknum long
134 : :
135 : : #endif /* } */
136 : :
137 : : #endif /* } */
138 : :
139 : : /* }====================================================== */
140 : :
141 : :
142 : :
143 : : #define IO_PREFIX "_IO_"
144 : : #define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1)
145 : : #define IO_INPUT (IO_PREFIX "input")
146 : : #define IO_OUTPUT (IO_PREFIX "output")
147 : :
148 : :
149 : : typedef luaL_Stream LStream;
150 : :
151 : :
152 : : #define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE))
153 : :
154 : : #define isclosed(p) ((p)->closef == NULL)
155 : :
156 : :
157 : 0 : static int io_type (lua_State *L) {
158 : : LStream *p;
159 : 0 : luaL_checkany(L, 1);
160 : 0 : p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE);
161 [ # # ]: 0 : if (p == NULL)
162 : 0 : luaL_pushfail(L); /* not a file */
163 [ # # ]: 0 : else if (isclosed(p))
164 : 0 : lua_pushliteral(L, "closed file");
165 : : else
166 : 0 : lua_pushliteral(L, "file");
167 : 0 : return 1;
168 : : }
169 : :
170 : :
171 : 0 : static int f_tostring (lua_State *L) {
172 : 0 : LStream *p = tolstream(L);
173 [ # # ]: 0 : if (isclosed(p))
174 : 0 : lua_pushliteral(L, "file (closed)");
175 : : else
176 : 0 : lua_pushfstring(L, "file (%p)", p->f);
177 : 0 : return 1;
178 : : }
179 : :
180 : :
181 : 36 : static FILE *tofile (lua_State *L) {
182 : 36 : LStream *p = tolstream(L);
183 [ - + ]: 36 : if (isclosed(p))
184 : 0 : luaL_error(L, "attempt to use a closed file");
185 : : lua_assert(p->f);
186 : 36 : return p->f;
187 : : }
188 : :
189 : :
190 : : /*
191 : : ** When creating file handles, always creates a 'closed' file handle
192 : : ** before opening the actual file; so, if there is a memory error, the
193 : : ** handle is in a consistent state.
194 : : */
195 : 2430 : static LStream *newprefile (lua_State *L) {
196 : 2430 : LStream *p = (LStream *)lua_newuserdatauv(L, sizeof(LStream), 0);
197 : 2430 : p->closef = NULL; /* mark file handle as 'closed' */
198 : 2430 : luaL_setmetatable(L, LUA_FILEHANDLE);
199 : 2430 : return p;
200 : : }
201 : :
202 : :
203 : : /*
204 : : ** Calls the 'close' function from a file handle. The 'volatile' avoids
205 : : ** a bug in some versions of the Clang compiler (e.g., clang 3.0 for
206 : : ** 32 bits).
207 : : */
208 : 129 : static int aux_close (lua_State *L) {
209 : 129 : LStream *p = tolstream(L);
210 : 129 : volatile lua_CFunction cf = p->closef;
211 : 129 : p->closef = NULL; /* mark stream as closed */
212 : 129 : return (*cf)(L); /* close it */
213 : : }
214 : :
215 : :
216 : 12 : static int f_close (lua_State *L) {
217 : 12 : tofile(L); /* make sure argument is an open stream */
218 : 12 : return aux_close(L);
219 : : }
220 : :
221 : :
222 : 12 : static int io_close (lua_State *L) {
223 [ - + ]: 12 : if (lua_isnone(L, 1)) /* no argument? */
224 : 0 : lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use default output */
225 : 12 : return f_close(L);
226 : : }
227 : :
228 : :
229 : 129 : static int f_gc (lua_State *L) {
230 : 129 : LStream *p = tolstream(L);
231 [ + - + + ]: 129 : if (!isclosed(p) && p->f != NULL)
232 : 120 : aux_close(L); /* ignore closed and incompletely open files */
233 : 129 : return 0;
234 : : }
235 : :
236 : :
237 : : /*
238 : : ** function to close regular files
239 : : */
240 : 0 : static int io_fclose (lua_State *L) {
241 : 0 : LStream *p = tolstream(L);
242 : 0 : int res = fclose(p->f);
243 : 0 : return luaL_fileresult(L, (res == 0), NULL);
244 : : }
245 : :
246 : :
247 : 0 : static LStream *newfile (lua_State *L) {
248 : 0 : LStream *p = newprefile(L);
249 : 0 : p->f = NULL;
250 : 0 : p->closef = &io_fclose;
251 : 0 : return p;
252 : : }
253 : :
254 : :
255 : 0 : static void opencheck (lua_State *L, const char *fname, const char *mode) {
256 : 0 : LStream *p = newfile(L);
257 : 0 : p->f = fopen(fname, mode);
258 [ # # ]: 0 : if (p->f == NULL)
259 : 0 : luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno));
260 : 0 : }
261 : :
262 : :
263 : 0 : static int io_open (lua_State *L) {
264 : 0 : const char *filename = luaL_checkstring(L, 1);
265 : 0 : const char *mode = luaL_optstring(L, 2, "r");
266 : 0 : LStream *p = newfile(L);
267 : 0 : const char *md = mode; /* to traverse/check mode */
268 [ # # ]: 0 : luaL_argcheck(L, l_checkmode(md), 2, "invalid mode");
269 : 0 : p->f = fopen(filename, mode);
270 [ # # ]: 0 : return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
271 : : }
272 : :
273 : :
274 : : /*
275 : : ** function to close 'popen' files
276 : : */
277 : 0 : static int io_pclose (lua_State *L) {
278 : 0 : LStream *p = tolstream(L);
279 : 0 : errno = 0;
280 : 0 : return luaL_execresult(L, l_pclose(L, p->f));
281 : : }
282 : :
283 : :
284 : 0 : static int io_popen (lua_State *L) {
285 : 0 : const char *filename = luaL_checkstring(L, 1);
286 : 0 : const char *mode = luaL_optstring(L, 2, "r");
287 : 0 : LStream *p = newprefile(L);
288 [ # # # # ]: 0 : luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode");
289 : 0 : p->f = l_popen(L, filename, mode);
290 : 0 : p->closef = &io_pclose;
291 [ # # ]: 0 : return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
292 : : }
293 : :
294 : :
295 : 0 : static int io_tmpfile (lua_State *L) {
296 : 0 : LStream *p = newfile(L);
297 : 0 : p->f = tmpfile();
298 [ # # ]: 0 : return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
299 : : }
300 : :
301 : :
302 : 0 : static FILE *getiofile (lua_State *L, const char *findex) {
303 : : LStream *p;
304 : 0 : lua_getfield(L, LUA_REGISTRYINDEX, findex);
305 : 0 : p = (LStream *)lua_touserdata(L, -1);
306 [ # # ]: 0 : if (isclosed(p))
307 : 0 : luaL_error(L, "default %s file is closed", findex + IOPREF_LEN);
308 : 0 : return p->f;
309 : : }
310 : :
311 : :
312 : 0 : static int g_iofile (lua_State *L, const char *f, const char *mode) {
313 [ # # ]: 0 : if (!lua_isnoneornil(L, 1)) {
314 : 0 : const char *filename = lua_tostring(L, 1);
315 [ # # ]: 0 : if (filename)
316 : 0 : opencheck(L, filename, mode);
317 : : else {
318 : 0 : tofile(L); /* check that it's a valid file handle */
319 : 0 : lua_pushvalue(L, 1);
320 : : }
321 : 0 : lua_setfield(L, LUA_REGISTRYINDEX, f);
322 : 0 : }
323 : : /* return current value */
324 : 0 : lua_getfield(L, LUA_REGISTRYINDEX, f);
325 : 0 : return 1;
326 : : }
327 : :
328 : :
329 : 0 : static int io_input (lua_State *L) {
330 : 0 : return g_iofile(L, IO_INPUT, "r");
331 : : }
332 : :
333 : :
334 : 0 : static int io_output (lua_State *L) {
335 : 0 : return g_iofile(L, IO_OUTPUT, "w");
336 : : }
337 : :
338 : :
339 : : static int io_readline (lua_State *L);
340 : :
341 : :
342 : : /*
343 : : ** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit
344 : : ** in the limit for upvalues of a closure)
345 : : */
346 : : #define MAXARGLINE 250
347 : :
348 : : /*
349 : : ** Auxiliary function to create the iteration function for 'lines'.
350 : : ** The iteration function is a closure over 'io_readline', with
351 : : ** the following upvalues:
352 : : ** 1) The file being read (first value in the stack)
353 : : ** 2) the number of arguments to read
354 : : ** 3) a boolean, true iff file has to be closed when finished ('toclose')
355 : : ** *) a variable number of format arguments (rest of the stack)
356 : : */
357 : 0 : static void aux_lines (lua_State *L, int toclose) {
358 : 0 : int n = lua_gettop(L) - 1; /* number of arguments to read */
359 [ # # ]: 0 : luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments");
360 : 0 : lua_pushvalue(L, 1); /* file */
361 : 0 : lua_pushinteger(L, n); /* number of arguments to read */
362 : 0 : lua_pushboolean(L, toclose); /* close/not close file when finished */
363 : 0 : lua_rotate(L, 2, 3); /* move the three values to their positions */
364 : 0 : lua_pushcclosure(L, io_readline, 3 + n);
365 : 0 : }
366 : :
367 : :
368 : 0 : static int f_lines (lua_State *L) {
369 : 0 : tofile(L); /* check that it's a valid file handle */
370 : 0 : aux_lines(L, 0);
371 : 0 : return 1;
372 : : }
373 : :
374 : :
375 : : /*
376 : : ** Return an iteration function for 'io.lines'. If file has to be
377 : : ** closed, also returns the file itself as a second result (to be
378 : : ** closed as the state at the exit of a generic for).
379 : : */
380 : 0 : static int io_lines (lua_State *L) {
381 : : int toclose;
382 [ # # ]: 0 : if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */
383 [ # # ]: 0 : if (lua_isnil(L, 1)) { /* no file name? */
384 : 0 : lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */
385 : 0 : lua_replace(L, 1); /* put it at index 1 */
386 : 0 : tofile(L); /* check that it's a valid file handle */
387 : 0 : toclose = 0; /* do not close it after iteration */
388 : 0 : }
389 : : else { /* open a new file */
390 : 0 : const char *filename = luaL_checkstring(L, 1);
391 : 0 : opencheck(L, filename, "r");
392 : 0 : lua_replace(L, 1); /* put file at index 1 */
393 : 0 : toclose = 1; /* close it after iteration */
394 : : }
395 : 0 : aux_lines(L, toclose); /* push iteration function */
396 [ # # ]: 0 : if (toclose) {
397 : 0 : lua_pushnil(L); /* state */
398 : 0 : lua_pushnil(L); /* control */
399 : 0 : lua_pushvalue(L, 1); /* file is the to-be-closed variable (4th result) */
400 : 0 : return 4;
401 : : }
402 : : else
403 : 0 : return 1;
404 : 0 : }
405 : :
406 : :
407 : : /*
408 : : ** {======================================================
409 : : ** READ
410 : : ** =======================================================
411 : : */
412 : :
413 : :
414 : : /* maximum length of a numeral */
415 : : #if !defined (L_MAXLENNUM)
416 : : #define L_MAXLENNUM 200
417 : : #endif
418 : :
419 : :
420 : : /* auxiliary structure used by 'read_number' */
421 : : typedef struct {
422 : : FILE *f; /* file being read */
423 : : int c; /* current character (look ahead) */
424 : : int n; /* number of elements in buffer 'buff' */
425 : : char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */
426 : : } RN;
427 : :
428 : :
429 : : /*
430 : : ** Add current char to buffer (if not out of space) and read next one
431 : : */
432 : 0 : static int nextc (RN *rn) {
433 [ # # ]: 0 : if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */
434 : 0 : rn->buff[0] = '\0'; /* invalidate result */
435 : 0 : return 0; /* fail */
436 : : }
437 : : else {
438 : 0 : rn->buff[rn->n++] = rn->c; /* save current char */
439 [ # # # # ]: 0 : rn->c = l_getc(rn->f); /* read next one */
440 : 0 : return 1;
441 : : }
442 : 0 : }
443 : :
444 : :
445 : : /*
446 : : ** Accept current char if it is in 'set' (of size 2)
447 : : */
448 : 0 : static int test2 (RN *rn, const char *set) {
449 [ # # # # ]: 0 : if (rn->c == set[0] || rn->c == set[1])
450 : 0 : return nextc(rn);
451 : 0 : else return 0;
452 : 0 : }
453 : :
454 : :
455 : : /*
456 : : ** Read a sequence of (hex)digits
457 : : */
458 : 0 : static int readdigits (RN *rn, int hex) {
459 : 0 : int count = 0;
460 [ # # # # : 0 : while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn))
# # ]
461 : 0 : count++;
462 : 0 : return count;
463 : : }
464 : :
465 : :
466 : : /*
467 : : ** Read a number: first reads a valid prefix of a numeral into a buffer.
468 : : ** Then it calls 'lua_stringtonumber' to check whether the format is
469 : : ** correct and to convert it to a Lua number.
470 : : */
471 : 0 : static int read_number (lua_State *L, FILE *f) {
472 : : RN rn;
473 : 0 : int count = 0;
474 : 0 : int hex = 0;
475 : : char decp[2];
476 : 0 : rn.f = f; rn.n = 0;
477 : 0 : decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */
478 : 0 : decp[1] = '.'; /* always accept a dot */
479 : : l_lockfile(rn.f);
480 [ # # # # : 0 : do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */
# # ]
481 : 0 : test2(&rn, "-+"); /* optional sign */
482 [ # # ]: 0 : if (test2(&rn, "00")) {
483 [ # # ]: 0 : if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */
484 : 0 : else count = 1; /* count initial '0' as a valid digit */
485 : 0 : }
486 : 0 : count += readdigits(&rn, hex); /* integral part */
487 [ # # ]: 0 : if (test2(&rn, decp)) /* decimal point? */
488 : 0 : count += readdigits(&rn, hex); /* fractional part */
489 [ # # # # ]: 0 : if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) { /* exponent mark? */
490 : 0 : test2(&rn, "-+"); /* exponent sign */
491 : 0 : readdigits(&rn, 0); /* exponent digits */
492 : 0 : }
493 : 0 : ungetc(rn.c, rn.f); /* unread look-ahead char */
494 : : l_unlockfile(rn.f);
495 : 0 : rn.buff[rn.n] = '\0'; /* finish string */
496 [ # # ]: 0 : if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */
497 : 0 : return 1; /* ok */
498 : : else { /* invalid format */
499 : 0 : lua_pushnil(L); /* "result" to be removed */
500 : 0 : return 0; /* read fails */
501 : : }
502 : 0 : }
503 : :
504 : :
505 : 0 : static int test_eof (lua_State *L, FILE *f) {
506 [ # # # # ]: 0 : int c = getc(f);
507 : 0 : ungetc(c, f); /* no-op when c == EOF */
508 : 0 : lua_pushliteral(L, "");
509 : 0 : return (c != EOF);
510 : : }
511 : :
512 : :
513 : 0 : static int read_line (lua_State *L, FILE *f, int chop) {
514 : : luaL_Buffer b;
515 : : int c;
516 : 0 : luaL_buffinit(L, &b);
517 : 0 : do { /* may need to read several chunks to get whole line */
518 : 0 : char *buff = luaL_prepbuffer(&b); /* preallocate buffer space */
519 : 0 : int i = 0;
520 : : l_lockfile(f); /* no memory errors can happen inside the lock */
521 [ # # # # : 0 : while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n')
# # # # #
# ]
522 : 0 : buff[i++] = c; /* read up to end of line or buffer limit */
523 : : l_unlockfile(f);
524 : 0 : luaL_addsize(&b, i);
525 [ # # # # ]: 0 : } while (c != EOF && c != '\n'); /* repeat until end of line */
526 [ # # # # ]: 0 : if (!chop && c == '\n') /* want a newline and have one? */
527 [ # # ]: 0 : luaL_addchar(&b, c); /* add ending newline to result */
528 : 0 : luaL_pushresult(&b); /* close buffer */
529 : : /* return ok if read something (either a newline or something else) */
530 [ # # ]: 0 : return (c == '\n' || lua_rawlen(L, -1) > 0);
531 : : }
532 : :
533 : :
534 : 0 : static void read_all (lua_State *L, FILE *f) {
535 : : size_t nr;
536 : : luaL_Buffer b;
537 : 0 : luaL_buffinit(L, &b);
538 : 0 : do { /* read file in chunks of LUAL_BUFFERSIZE bytes */
539 : 0 : char *p = luaL_prepbuffer(&b);
540 : 0 : nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f);
541 : 0 : luaL_addsize(&b, nr);
542 [ # # ]: 0 : } while (nr == LUAL_BUFFERSIZE);
543 : 0 : luaL_pushresult(&b); /* close buffer */
544 : 0 : }
545 : :
546 : :
547 : 0 : static int read_chars (lua_State *L, FILE *f, size_t n) {
548 : : size_t nr; /* number of chars actually read */
549 : : char *p;
550 : : luaL_Buffer b;
551 : 0 : luaL_buffinit(L, &b);
552 : 0 : p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */
553 : 0 : nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */
554 : 0 : luaL_addsize(&b, nr);
555 : 0 : luaL_pushresult(&b); /* close buffer */
556 : 0 : return (nr > 0); /* true iff read something */
557 : : }
558 : :
559 : :
560 : 0 : static int g_read (lua_State *L, FILE *f, int first) {
561 : 0 : int nargs = lua_gettop(L) - 1;
562 : : int n, success;
563 [ # # ]: 0 : clearerr(f);
564 [ # # ]: 0 : if (nargs == 0) { /* no arguments? */
565 : 0 : success = read_line(L, f, 1);
566 : 0 : n = first + 1; /* to return 1 result */
567 : 0 : }
568 : : else {
569 : : /* ensure stack space for all results and for auxlib's buffer */
570 : 0 : luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
571 : 0 : success = 1;
572 [ # # # # ]: 0 : for (n = first; nargs-- && success; n++) {
573 [ # # ]: 0 : if (lua_type(L, n) == LUA_TNUMBER) {
574 : 0 : size_t l = (size_t)luaL_checkinteger(L, n);
575 [ # # ]: 0 : success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
576 : 0 : }
577 : : else {
578 : 0 : const char *p = luaL_checkstring(L, n);
579 [ # # ]: 0 : if (*p == '*') p++; /* skip optional '*' (for compatibility) */
580 [ # # # # : 0 : switch (*p) {
# ]
581 : : case 'n': /* number */
582 : 0 : success = read_number(L, f);
583 : 0 : break;
584 : : case 'l': /* line */
585 : 0 : success = read_line(L, f, 1);
586 : 0 : break;
587 : : case 'L': /* line with end-of-line */
588 : 0 : success = read_line(L, f, 0);
589 : 0 : break;
590 : : case 'a': /* file */
591 : 0 : read_all(L, f); /* read entire file */
592 : 0 : success = 1; /* always success */
593 : 0 : break;
594 : : default:
595 : 0 : return luaL_argerror(L, n, "invalid format");
596 : : }
597 : : }
598 : 0 : }
599 : : }
600 [ # # # # ]: 0 : if (ferror(f))
601 : 0 : return luaL_fileresult(L, 0, NULL);
602 [ # # ]: 0 : if (!success) {
603 : 0 : lua_pop(L, 1); /* remove last result */
604 : 0 : luaL_pushfail(L); /* push nil instead */
605 : 0 : }
606 : 0 : return n - first;
607 : 0 : }
608 : :
609 : :
610 : 0 : static int io_read (lua_State *L) {
611 : 0 : return g_read(L, getiofile(L, IO_INPUT), 1);
612 : : }
613 : :
614 : :
615 : 0 : static int f_read (lua_State *L) {
616 : 0 : return g_read(L, tofile(L), 2);
617 : : }
618 : :
619 : :
620 : : /*
621 : : ** Iteration function for 'lines'.
622 : : */
623 : 0 : static int io_readline (lua_State *L) {
624 : 0 : LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1));
625 : : int i;
626 : 0 : int n = (int)lua_tointeger(L, lua_upvalueindex(2));
627 [ # # ]: 0 : if (isclosed(p)) /* file is already closed? */
628 : 0 : return luaL_error(L, "file is already closed");
629 : 0 : lua_settop(L , 1);
630 : 0 : luaL_checkstack(L, n, "too many arguments");
631 [ # # ]: 0 : for (i = 1; i <= n; i++) /* push arguments to 'g_read' */
632 : 0 : lua_pushvalue(L, lua_upvalueindex(3 + i));
633 : 0 : n = g_read(L, p->f, 2); /* 'n' is number of results */
634 : : lua_assert(n > 0); /* should return at least a nil */
635 [ # # ]: 0 : if (lua_toboolean(L, -n)) /* read at least one value? */
636 : 0 : return n; /* return them */
637 : : else { /* first result is false: EOF or error */
638 [ # # ]: 0 : if (n > 1) { /* is there error information? */
639 : : /* 2nd result is error message */
640 : 0 : return luaL_error(L, "%s", lua_tostring(L, -n + 1));
641 : : }
642 [ # # ]: 0 : if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */
643 : 0 : lua_settop(L, 0); /* clear stack */
644 : 0 : lua_pushvalue(L, lua_upvalueindex(1)); /* push file at index 1 */
645 : 0 : aux_close(L); /* close it */
646 : 0 : }
647 : 0 : return 0;
648 : : }
649 : 0 : }
650 : :
651 : : /* }====================================================== */
652 : :
653 : :
654 : 24 : static int g_write (lua_State *L, FILE *f, int arg) {
655 : 24 : int nargs = lua_gettop(L) - arg;
656 : 24 : int status = 1;
657 [ + + ]: 48 : for (; nargs--; arg++) {
658 [ - + ]: 24 : if (lua_type(L, arg) == LUA_TNUMBER) {
659 : : /* optimization: could be done exactly as for strings */
660 [ # # ]: 0 : int len = lua_isinteger(L, arg)
661 : 0 : ? fprintf(f, LUA_INTEGER_FMT,
662 : 0 : (LUAI_UACINT)lua_tointeger(L, arg))
663 : 0 : : fprintf(f, LUA_NUMBER_FMT,
664 : 0 : (LUAI_UACNUMBER)lua_tonumber(L, arg));
665 [ # # ]: 0 : status = status && (len > 0);
666 : 0 : }
667 : : else {
668 : : size_t l;
669 : 24 : const char *s = luaL_checklstring(L, arg, &l);
670 [ - + ]: 24 : status = status && (fwrite(s, sizeof(char), l, f) == l);
671 : : }
672 : 24 : }
673 [ - + ]: 24 : if (status) return 1; /* file handle already on stack top */
674 : 0 : else return luaL_fileresult(L, status, NULL);
675 : 24 : }
676 : :
677 : :
678 : 0 : static int io_write (lua_State *L) {
679 : 0 : return g_write(L, getiofile(L, IO_OUTPUT), 1);
680 : : }
681 : :
682 : :
683 : 24 : static int f_write (lua_State *L) {
684 : 24 : FILE *f = tofile(L);
685 : 24 : lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */
686 : 24 : return g_write(L, f, 2);
687 : : }
688 : :
689 : :
690 : 0 : static int f_seek (lua_State *L) {
691 : : static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
692 : : static const char *const modenames[] = {"set", "cur", "end", NULL};
693 : 0 : FILE *f = tofile(L);
694 : 0 : int op = luaL_checkoption(L, 2, "cur", modenames);
695 : 0 : lua_Integer p3 = luaL_optinteger(L, 3, 0);
696 : 0 : l_seeknum offset = (l_seeknum)p3;
697 [ # # ]: 0 : luaL_argcheck(L, (lua_Integer)offset == p3, 3,
698 : : "not an integer in proper range");
699 : 0 : op = l_fseek(f, offset, mode[op]);
700 [ # # ]: 0 : if (op)
701 : 0 : return luaL_fileresult(L, 0, NULL); /* error */
702 : : else {
703 : 0 : lua_pushinteger(L, (lua_Integer)l_ftell(f));
704 : 0 : return 1;
705 : : }
706 : 0 : }
707 : :
708 : :
709 : 0 : static int f_setvbuf (lua_State *L) {
710 : : static const int mode[] = {_IONBF, _IOFBF, _IOLBF};
711 : : static const char *const modenames[] = {"no", "full", "line", NULL};
712 : 0 : FILE *f = tofile(L);
713 : 0 : int op = luaL_checkoption(L, 2, NULL, modenames);
714 : 0 : lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
715 : 0 : int res = setvbuf(f, NULL, mode[op], (size_t)sz);
716 : 0 : return luaL_fileresult(L, res == 0, NULL);
717 : : }
718 : :
719 : :
720 : :
721 : 0 : static int io_flush (lua_State *L) {
722 : 0 : return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
723 : : }
724 : :
725 : :
726 : 0 : static int f_flush (lua_State *L) {
727 : 0 : return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL);
728 : : }
729 : :
730 : :
731 : : /*
732 : : ** functions for 'io' library
733 : : */
734 : : static const luaL_Reg iolib[] = {
735 : : {"close", io_close},
736 : : {"flush", io_flush},
737 : : {"input", io_input},
738 : : {"lines", io_lines},
739 : : {"open", io_open},
740 : : {"output", io_output},
741 : : {"popen", io_popen},
742 : : {"read", io_read},
743 : : {"tmpfile", io_tmpfile},
744 : : {"type", io_type},
745 : : {"write", io_write},
746 : : {NULL, NULL}
747 : : };
748 : :
749 : :
750 : : /*
751 : : ** methods for file handles
752 : : */
753 : : static const luaL_Reg meth[] = {
754 : : {"read", f_read},
755 : : {"write", f_write},
756 : : {"lines", f_lines},
757 : : {"flush", f_flush},
758 : : {"seek", f_seek},
759 : : {"close", f_close},
760 : : {"setvbuf", f_setvbuf},
761 : : {NULL, NULL}
762 : : };
763 : :
764 : :
765 : : /*
766 : : ** metamethods for file handles
767 : : */
768 : : static const luaL_Reg metameth[] = {
769 : : {"__index", NULL}, /* place holder */
770 : : {"__gc", f_gc},
771 : : {"__close", f_gc},
772 : : {"__tostring", f_tostring},
773 : : {NULL, NULL}
774 : : };
775 : :
776 : :
777 : 810 : static void createmeta (lua_State *L) {
778 : 810 : luaL_newmetatable(L, LUA_FILEHANDLE); /* metatable for file handles */
779 : 810 : luaL_setfuncs(L, metameth, 0); /* add metamethods to new metatable */
780 : 810 : luaL_newlibtable(L, meth); /* create method table */
781 : 810 : luaL_setfuncs(L, meth, 0); /* add file methods to method table */
782 : 810 : lua_setfield(L, -2, "__index"); /* metatable.__index = method table */
783 : 810 : lua_pop(L, 1); /* pop metatable */
784 : 810 : }
785 : :
786 : :
787 : : /*
788 : : ** function to (not) close the standard files stdin, stdout, and stderr
789 : : */
790 : 120 : static int io_noclose (lua_State *L) {
791 : 120 : LStream *p = tolstream(L);
792 : 120 : p->closef = &io_noclose; /* keep file opened */
793 : 120 : luaL_pushfail(L);
794 : 120 : lua_pushliteral(L, "cannot close standard file");
795 : 120 : return 2;
796 : : }
797 : :
798 : :
799 : 2430 : static void createstdfile (lua_State *L, FILE *f, const char *k,
800 : : const char *fname) {
801 : 2430 : LStream *p = newprefile(L);
802 : 2430 : p->f = f;
803 : 2430 : p->closef = &io_noclose;
804 [ + + ]: 2430 : if (k != NULL) {
805 : 1620 : lua_pushvalue(L, -1);
806 : 1620 : lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */
807 : 1620 : }
808 : 2430 : lua_setfield(L, -2, fname); /* add file to module */
809 : 2430 : }
810 : :
811 : :
812 : 810 : LUAMOD_API int luaopen_io (lua_State *L) {
813 : 810 : luaL_newlib(L, iolib); /* new module */
814 : 810 : createmeta(L);
815 : : /* create (and set) default files */
816 : 810 : createstdfile(L, stdin, IO_INPUT, "stdin");
817 : 810 : createstdfile(L, stdout, IO_OUTPUT, "stdout");
818 : 810 : createstdfile(L, stderr, NULL, "stderr");
819 : 810 : return 1;
820 : : }
821 : :
|