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