- initial import of revision 374 from cnc
[apt.git] / lua / lib / liolib.c
1 /*
2 ** $Id: liolib.c,v 2.39a 2003/03/19 21:16:12 roberto Exp $
3 ** Standard I/O (and system) library
4 ** See Copyright Notice in lua.h
5 */
6
7
8 #include <errno.h>
9 #include <locale.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <time.h>
14
15 #define liolib_c
16
17 #include "lua.h"
18
19 #include "lauxlib.h"
20 #include "lualib.h"
21
22
23
24 /*
25 ** by default, gcc does not get `tmpname'
26 */
27 #ifndef USE_TMPNAME
28 #ifdef __GNUC__
29 #define USE_TMPNAME     0
30 #else
31 #define USE_TMPNAME     1
32 #endif
33 #endif
34
35
36 /*
37 ** by default, posix systems get `popen'
38 */
39 #ifndef USE_POPEN
40 #ifdef _POSIX_C_SOURCE
41 #if _POSIX_C_SOURCE >= 2
42 #define USE_POPEN       1
43 #endif
44 #endif
45 #endif
46
47 #ifndef USE_POPEN
48 #define USE_POPEN       0
49 #endif
50
51
52
53
54 /*
55 ** {======================================================
56 ** FILE Operations
57 ** =======================================================
58 */
59
60
61 #if !USE_POPEN
62 #define pclose(f)    (-1)
63 #endif
64
65
66 #define FILEHANDLE              "FILE*"
67
68 #define IO_INPUT                "_input"
69 #define IO_OUTPUT               "_output"
70
71
72 static int pushresult (lua_State *L, int i, const char *filename) {
73   if (i) {
74     lua_pushboolean(L, 1);
75     return 1;
76   }
77   else {
78     lua_pushnil(L);
79     if (filename)
80       lua_pushfstring(L, "%s: %s", filename, strerror(errno));
81     else
82       lua_pushfstring(L, "%s", strerror(errno));
83     lua_pushnumber(L, errno);
84     return 3;
85   }
86 }
87
88
89 static FILE **topfile (lua_State *L, int findex) {
90   FILE **f = (FILE **)luaL_checkudata(L, findex, FILEHANDLE);
91   if (f == NULL) luaL_argerror(L, findex, "bad file");
92   return f;
93 }
94
95
96 static int io_type (lua_State *L) {
97   FILE **f = (FILE **)luaL_checkudata(L, 1, FILEHANDLE);
98   if (f == NULL) lua_pushnil(L);
99   else if (*f == NULL)
100     lua_pushliteral(L, "closed file");
101   else
102     lua_pushliteral(L, "file");
103   return 1;
104 }
105
106
107 static FILE *tofile (lua_State *L, int findex) {
108   FILE **f = topfile(L, findex);
109   if (*f == NULL)
110     luaL_error(L, "attempt to use a closed file");
111   return *f;
112 }
113
114
115
116 /*
117 ** When creating file handles, always creates a `closed' file handle
118 ** before opening the actual file; so, if there is a memory error, the
119 ** file is not left opened.
120 */
121 static FILE **newfile (lua_State *L) {
122   FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *));
123   *pf = NULL;  /* file handle is currently `closed' */
124   luaL_getmetatable(L, FILEHANDLE);
125   lua_setmetatable(L, -2);
126   return pf;
127 }
128
129
130 /*
131 ** assumes that top of the stack is the `io' library, and next is
132 ** the `io' metatable
133 */
134 static void registerfile (lua_State *L, FILE *f, const char *name,
135                                                  const char *impname) {
136   lua_pushstring(L, name);
137   *newfile(L) = f;
138   if (impname) {
139     lua_pushstring(L, impname);
140     lua_pushvalue(L, -2);
141     lua_settable(L, -6);  /* metatable[impname] = file */
142   }
143   lua_settable(L, -3);  /* io[name] = file */
144 }
145
146
147 static int aux_close (lua_State *L) {
148   FILE *f = tofile(L, 1);
149   if (f == stdin || f == stdout || f == stderr)
150     return 0;  /* file cannot be closed */
151   else {
152     int ok = (pclose(f) != -1) || (fclose(f) == 0);
153     if (ok)
154       *(FILE **)lua_touserdata(L, 1) = NULL;  /* mark file as closed */
155     return ok;
156   }
157 }
158
159
160 static int io_close (lua_State *L) {
161   if (lua_isnone(L, 1) && lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE) {
162     lua_pushstring(L, IO_OUTPUT);
163     lua_rawget(L, lua_upvalueindex(1));
164   }
165   return pushresult(L, aux_close(L), NULL);
166 }
167
168
169 static int io_gc (lua_State *L) {
170   FILE **f = topfile(L, 1);
171   if (*f != NULL)  /* ignore closed files */
172     aux_close(L);
173   return 0;
174 }
175
176
177 static int io_tostring (lua_State *L) {
178   char buff[128];
179   FILE **f = topfile(L, 1);
180   if (*f == NULL)
181     strcpy(buff, "closed");
182   else
183     sprintf(buff, "%p", lua_touserdata(L, 1));
184   lua_pushfstring(L, "file (%s)", buff);
185   return 1;
186 }
187
188
189 static int io_open (lua_State *L) {
190   const char *filename = luaL_checkstring(L, 1);
191   const char *mode = luaL_optstring(L, 2, "r");
192   FILE **pf = newfile(L);
193   *pf = fopen(filename, mode);
194   return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
195 }
196
197
198 static int io_popen (lua_State *L) {
199 #if !USE_POPEN
200   luaL_error(L, "`popen' not supported");
201   return 0;
202 #else
203   const char *filename = luaL_checkstring(L, 1);
204   const char *mode = luaL_optstring(L, 2, "r");
205   FILE **pf = newfile(L);
206   *pf = popen(filename, mode);
207   return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
208 #endif
209 }
210
211
212 static int io_tmpfile (lua_State *L) {
213   FILE **pf = newfile(L);
214   *pf = tmpfile();
215   return (*pf == NULL) ? pushresult(L, 0, NULL) : 1;
216 }
217
218
219 static FILE *getiofile (lua_State *L, const char *name) {
220   lua_pushstring(L, name);
221   lua_rawget(L, lua_upvalueindex(1));
222   return tofile(L, -1);
223 }
224
225
226 static int g_iofile (lua_State *L, const char *name, const char *mode) {
227   if (!lua_isnoneornil(L, 1)) {
228     const char *filename = lua_tostring(L, 1);
229     lua_pushstring(L, name);
230     if (filename) {
231       FILE **pf = newfile(L);
232       *pf = fopen(filename, mode);
233       if (*pf == NULL) {
234         lua_pushfstring(L, "%s: %s", filename, strerror(errno));
235         luaL_argerror(L, 1, lua_tostring(L, -1));
236       }
237     }
238     else {
239       tofile(L, 1);  /* check that it's a valid file handle */
240       lua_pushvalue(L, 1);
241     }
242     lua_rawset(L, lua_upvalueindex(1));
243   }
244   /* return current value */
245   lua_pushstring(L, name);
246   lua_rawget(L, lua_upvalueindex(1));
247   return 1;
248 }
249
250
251 static int io_input (lua_State *L) {
252   return g_iofile(L, IO_INPUT, "r");
253 }
254
255
256 static int io_output (lua_State *L) {
257   return g_iofile(L, IO_OUTPUT, "w");
258 }
259
260
261 static int io_readline (lua_State *L);
262
263
264 static void aux_lines (lua_State *L, int idx, int close) {
265   lua_pushliteral(L, FILEHANDLE);
266   lua_rawget(L, LUA_REGISTRYINDEX);
267   lua_pushvalue(L, idx);
268   lua_pushboolean(L, close);  /* close/not close file when finished */
269   lua_pushcclosure(L, io_readline, 3);
270 }
271
272
273 static int f_lines (lua_State *L) {
274   tofile(L, 1);  /* check that it's a valid file handle */
275   aux_lines(L, 1, 0);
276   return 1;
277 }
278
279
280 static int io_lines (lua_State *L) {
281   if (lua_isnoneornil(L, 1)) {  /* no arguments? */
282     lua_pushstring(L, IO_INPUT);
283     lua_rawget(L, lua_upvalueindex(1));  /* will iterate over default input */
284     return f_lines(L);
285   }
286   else {
287     const char *filename = luaL_checkstring(L, 1);
288     FILE **pf = newfile(L);
289     *pf = fopen(filename, "r");
290     luaL_argcheck(L, *pf, 1,  strerror(errno));
291     aux_lines(L, lua_gettop(L), 1);
292     return 1;
293   }
294 }
295
296
297 /*
298 ** {======================================================
299 ** READ
300 ** =======================================================
301 */
302
303
304 static int read_number (lua_State *L, FILE *f) {
305   lua_Number d;
306   if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) {
307     lua_pushnumber(L, d);
308     return 1;
309   }
310   else return 0;  /* read fails */
311 }
312
313
314 static int test_eof (lua_State *L, FILE *f) {
315   int c = getc(f);
316   ungetc(c, f);
317   lua_pushlstring(L, NULL, 0);
318   return (c != EOF);
319 }
320
321
322 static int read_line (lua_State *L, FILE *f) {
323   luaL_Buffer b;
324   luaL_buffinit(L, &b);
325   for (;;) {
326     size_t l;
327     char *p = luaL_prepbuffer(&b);
328     if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) {  /* eof? */
329       luaL_pushresult(&b);  /* close buffer */
330       return (lua_strlen(L, -1) > 0);  /* check whether read something */
331     }
332     l = strlen(p);
333     if (p[l-1] != '\n')
334       luaL_addsize(&b, l);
335     else {
336       luaL_addsize(&b, l - 1);  /* do not include `eol' */
337       luaL_pushresult(&b);  /* close buffer */
338       return 1;  /* read at least an `eol' */
339     }
340   }
341 }
342
343
344 static int read_chars (lua_State *L, FILE *f, size_t n) {
345   size_t rlen;  /* how much to read */
346   size_t nr;  /* number of chars actually read */
347   luaL_Buffer b;
348   luaL_buffinit(L, &b);
349   rlen = LUAL_BUFFERSIZE;  /* try to read that much each time */
350   do {
351     char *p = luaL_prepbuffer(&b);
352     if (rlen > n) rlen = n;  /* cannot read more than asked */
353     nr = fread(p, sizeof(char), rlen, f);
354     luaL_addsize(&b, nr);
355     n -= nr;  /* still have to read `n' chars */
356   } while (n > 0 && nr == rlen);  /* until end of count or eof */
357   luaL_pushresult(&b);  /* close buffer */
358   return (n == 0 || lua_strlen(L, -1) > 0);
359 }
360
361
362 static int g_read (lua_State *L, FILE *f, int first) {
363   int nargs = lua_gettop(L) - 1;
364   int success;
365   int n;
366   if (nargs == 0) {  /* no arguments? */
367     success = read_line(L, f);
368     n = first+1;  /* to return 1 result */
369   }
370   else {  /* ensure stack space for all results and for auxlib's buffer */
371     luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
372     success = 1;
373     for (n = first; nargs-- && success; n++) {
374       if (lua_type(L, n) == LUA_TNUMBER) {
375         size_t l = (size_t)lua_tonumber(L, n);
376         success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
377       }
378       else {
379         const char *p = lua_tostring(L, n);
380         luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
381         switch (p[1]) {
382           case 'n':  /* number */
383             success = read_number(L, f);
384             break;
385           case 'l':  /* line */
386             success = read_line(L, f);
387             break;
388           case 'a':  /* file */
389             read_chars(L, f, ~((size_t)0));  /* read MAX_SIZE_T chars */
390             success = 1; /* always success */
391             break;
392           case 'w':  /* word */
393             return luaL_error(L, "obsolete option `*w' to `read'");
394           default:
395             return luaL_argerror(L, n, "invalid format");
396         }
397       }
398     }
399   }
400   if (!success) {
401     lua_pop(L, 1);  /* remove last result */
402     lua_pushnil(L);  /* push nil instead */
403   }
404   return n - first;
405 }
406
407
408 static int io_read (lua_State *L) {
409   return g_read(L, getiofile(L, IO_INPUT), 1);
410 }
411
412
413 static int f_read (lua_State *L) {
414   return g_read(L, tofile(L, 1), 2);
415 }
416
417
418 static int io_readline (lua_State *L) {
419   FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(2));
420   if (f == NULL)  /* file is already closed? */
421     luaL_error(L, "file is already closed");
422   if (read_line(L, f)) return 1;
423   else {  /* EOF */
424     if (lua_toboolean(L, lua_upvalueindex(3))) {  /* generator created file? */
425       lua_settop(L, 0);
426       lua_pushvalue(L, lua_upvalueindex(2));
427       aux_close(L);  /* close it */
428     }
429     return 0;
430   }
431 }
432
433 /* }====================================================== */
434
435
436 static int g_write (lua_State *L, FILE *f, int arg) {
437   int nargs = lua_gettop(L) - 1;
438   int status = 1;
439   for (; nargs--; arg++) {
440     if (lua_type(L, arg) == LUA_TNUMBER) {
441       /* optimization: could be done exactly as for strings */
442       status = status &&
443           fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
444     }
445     else {
446       size_t l;
447       const char *s = luaL_checklstring(L, arg, &l);
448       status = status && (fwrite(s, sizeof(char), l, f) == l);
449     }
450   }
451   return pushresult(L, status, NULL);
452 }
453
454
455 static int io_write (lua_State *L) {
456   return g_write(L, getiofile(L, IO_OUTPUT), 1);
457 }
458
459
460 static int f_write (lua_State *L) {
461   return g_write(L, tofile(L, 1), 2);
462 }
463
464
465 static int f_seek (lua_State *L) {
466   static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
467   static const char *const modenames[] = {"set", "cur", "end", NULL};
468   FILE *f = tofile(L, 1);
469   int op = luaL_findstring(luaL_optstring(L, 2, "cur"), modenames);
470   long offset = luaL_optlong(L, 3, 0);
471   luaL_argcheck(L, op != -1, 2, "invalid mode");
472   op = fseek(f, offset, mode[op]);
473   if (op)
474     return pushresult(L, 0, NULL);  /* error */
475   else {
476     lua_pushnumber(L, ftell(f));
477     return 1;
478   }
479 }
480
481
482 static int io_flush (lua_State *L) {
483   return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
484 }
485
486
487 static int f_flush (lua_State *L) {
488   return pushresult(L, fflush(tofile(L, 1)) == 0, NULL);
489 }
490
491
492 static const luaL_reg iolib[] = {
493   {"input", io_input},
494   {"output", io_output},
495   {"lines", io_lines},
496   {"close", io_close},
497   {"flush", io_flush},
498   {"open", io_open},
499   {"popen", io_popen},
500   {"read", io_read},
501   {"tmpfile", io_tmpfile},
502   {"type", io_type},
503   {"write", io_write},
504   {NULL, NULL}
505 };
506
507
508 static const luaL_reg flib[] = {
509   {"flush", f_flush},
510   {"read", f_read},
511   {"lines", f_lines},
512   {"seek", f_seek},
513   {"write", f_write},
514   {"close", io_close},
515   {"__gc", io_gc},
516   {"__tostring", io_tostring},
517   {NULL, NULL}
518 };
519
520
521 static void createmeta (lua_State *L) {
522   luaL_newmetatable(L, FILEHANDLE);  /* create new metatable for file handles */
523   /* file methods */
524   lua_pushliteral(L, "__index");
525   lua_pushvalue(L, -2);  /* push metatable */
526   lua_rawset(L, -3);  /* metatable.__index = metatable */
527   luaL_openlib(L, NULL, flib, 0);
528 }
529
530 /* }====================================================== */
531
532
533 /*
534 ** {======================================================
535 ** Other O.S. Operations
536 ** =======================================================
537 */
538
539 static int io_execute (lua_State *L) {
540   lua_pushnumber(L, system(luaL_checkstring(L, 1)));
541   return 1;
542 }
543
544
545 static int io_remove (lua_State *L) {
546   const char *filename = luaL_checkstring(L, 1);
547   return pushresult(L, remove(filename) == 0, filename);
548 }
549
550
551 static int io_rename (lua_State *L) {
552   const char *fromname = luaL_checkstring(L, 1);
553   const char *toname = luaL_checkstring(L, 2);
554   return pushresult(L, rename(fromname, toname) == 0, fromname);
555 }
556
557
558 static int io_tmpname (lua_State *L) {
559 #if !USE_TMPNAME
560   luaL_error(L, "`tmpname' not supported");
561   return 0;
562 #else
563   char buff[L_tmpnam];
564   if (tmpnam(buff) != buff)
565     return luaL_error(L, "unable to generate a unique filename in `tmpname'");
566   lua_pushstring(L, buff);
567   return 1;
568 #endif
569 }
570
571
572 static int io_getenv (lua_State *L) {
573   lua_pushstring(L, getenv(luaL_checkstring(L, 1)));  /* if NULL push nil */
574   return 1;
575 }
576
577
578 static int io_clock (lua_State *L) {
579   lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC);
580   return 1;
581 }
582
583
584 /*
585 ** {======================================================
586 ** Time/Date operations
587 ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S,
588 **   wday=%w+1, yday=%j, isdst=? }
589 ** =======================================================
590 */
591
592 static void setfield (lua_State *L, const char *key, int value) {
593   lua_pushstring(L, key);
594   lua_pushnumber(L, value);
595   lua_rawset(L, -3);
596 }
597
598 static void setboolfield (lua_State *L, const char *key, int value) {
599   lua_pushstring(L, key);
600   lua_pushboolean(L, value);
601   lua_rawset(L, -3);
602 }
603
604 static int getboolfield (lua_State *L, const char *key) {
605   int res;
606   lua_pushstring(L, key);
607   lua_gettable(L, -2);
608   res = lua_toboolean(L, -1);
609   lua_pop(L, 1);
610   return res;
611 }
612
613
614 static int getfield (lua_State *L, const char *key, int d) {
615   int res;
616   lua_pushstring(L, key);
617   lua_gettable(L, -2);
618   if (lua_isnumber(L, -1))
619     res = (int)(lua_tonumber(L, -1));
620   else {
621     if (d == -2)
622       return luaL_error(L, "field `%s' missing in date table", key);
623     res = d;
624   }
625   lua_pop(L, 1);
626   return res;
627 }
628
629
630 static int io_date (lua_State *L) {
631   const char *s = luaL_optstring(L, 1, "%c");
632   time_t t = (time_t)(luaL_optnumber(L, 2, -1));
633   struct tm *stm;
634   if (t == (time_t)(-1))  /* no time given? */
635     t = time(NULL);  /* use current time */
636   if (*s == '!') {  /* UTC? */
637     stm = gmtime(&t);
638     s++;  /* skip `!' */
639   }
640   else
641     stm = localtime(&t);
642   if (stm == NULL)  /* invalid date? */
643     lua_pushnil(L);
644   else if (strcmp(s, "*t") == 0) {
645     lua_newtable(L);
646     setfield(L, "sec", stm->tm_sec);
647     setfield(L, "min", stm->tm_min);
648     setfield(L, "hour", stm->tm_hour);
649     setfield(L, "day", stm->tm_mday);
650     setfield(L, "month", stm->tm_mon+1);
651     setfield(L, "year", stm->tm_year+1900);
652     setfield(L, "wday", stm->tm_wday+1);
653     setfield(L, "yday", stm->tm_yday+1);
654     setboolfield(L, "isdst", stm->tm_isdst);
655   }
656   else {
657     char b[256];
658     if (strftime(b, sizeof(b), s, stm))
659       lua_pushstring(L, b);
660     else
661       return luaL_error(L, "`date' format too long");
662   }
663   return 1;
664 }
665
666
667 static int io_time (lua_State *L) {
668   if (lua_isnoneornil(L, 1))  /* called without args? */
669     lua_pushnumber(L, time(NULL));  /* return current time */
670   else {
671     time_t t;
672     struct tm ts;
673     luaL_checktype(L, 1, LUA_TTABLE);
674     lua_settop(L, 1);  /* make sure table is at the top */
675     ts.tm_sec = getfield(L, "sec", 0);
676     ts.tm_min = getfield(L, "min", 0);
677     ts.tm_hour = getfield(L, "hour", 12);
678     ts.tm_mday = getfield(L, "day", -2);
679     ts.tm_mon = getfield(L, "month", -2) - 1;
680     ts.tm_year = getfield(L, "year", -2) - 1900;
681     ts.tm_isdst = getboolfield(L, "isdst");
682     t = mktime(&ts);
683     if (t == (time_t)(-1))
684       lua_pushnil(L);
685     else
686       lua_pushnumber(L, t);
687   }
688   return 1;
689 }
690
691
692 static int io_difftime (lua_State *L) {
693   lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)),
694                              (time_t)(luaL_optnumber(L, 2, 0))));
695   return 1;
696 }
697
698 /* }====================================================== */
699
700
701 static int io_setloc (lua_State *L) {
702   static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY,
703                       LC_NUMERIC, LC_TIME};
704   static const char *const catnames[] = {"all", "collate", "ctype", "monetary",
705      "numeric", "time", NULL};
706   const char *l = lua_tostring(L, 1);
707   int op = luaL_findstring(luaL_optstring(L, 2, "all"), catnames);
708   luaL_argcheck(L, l || lua_isnoneornil(L, 1), 1, "string expected");
709   luaL_argcheck(L, op != -1, 2, "invalid option");
710   lua_pushstring(L, setlocale(cat[op], l));
711   return 1;
712 }
713
714
715 static int io_exit (lua_State *L) {
716   exit(luaL_optint(L, 1, EXIT_SUCCESS));
717   return 0;  /* to avoid warnings */
718 }
719
720 static const luaL_reg syslib[] = {
721   {"clock",     io_clock},
722   {"date",      io_date},
723   {"difftime",  io_difftime},
724   {"execute",   io_execute},
725   {"exit",      io_exit},
726   {"getenv",    io_getenv},
727   {"remove",    io_remove},
728   {"rename",    io_rename},
729   {"setlocale", io_setloc},
730   {"time",      io_time},
731   {"tmpname",   io_tmpname},
732   {NULL, NULL}
733 };
734
735 /* }====================================================== */
736
737
738
739 LUALIB_API int luaopen_io (lua_State *L) {
740   luaL_openlib(L, LUA_OSLIBNAME, syslib, 0);
741   createmeta(L);
742   lua_pushvalue(L, -1);
743   luaL_openlib(L, LUA_IOLIBNAME, iolib, 1);
744   /* put predefined file handles into `io' table */
745   registerfile(L, stdin, "stdin", IO_INPUT);
746   registerfile(L, stdout, "stdout", IO_OUTPUT);
747   registerfile(L, stderr, "stderr", NULL);
748   return 1;
749 }
750