Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ceguilua/src/lua-5.0.3/lua/liolib.c @ 1808

Last change on this file since 1808 was 1803, checked in by rgrieder, 16 years ago

added files for lua 5.1.3, lua 5.0.3, CEGUILua-0.6.1 and CEGUILua-0.5.0b

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