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