Imported from ../lua-3.2.tar.gz.
[lua.git] / src / lib / liolib.c
blobd833cec54cac2fb35834e852e61890618fefdf57
1 /*
2 ** $Id: liolib.c,v 1.41 1999/06/23 13:48:39 roberto Exp $
3 ** Standard I/O (and system) library
4 ** See Copyright Notice in lua.h
5 */
8 #include <errno.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <time.h>
14 #include "lauxlib.h"
15 #include "lua.h"
16 #include "luadebug.h"
17 #include "lualib.h"
20 #ifndef OLD_ANSI
21 #include <locale.h>
22 #else
23 /* no support for locale and for strerror: fake them */
24 #define setlocale(a,b) 0
25 #define LC_ALL 0
26 #define LC_COLLATE 0
27 #define LC_CTYPE 0
28 #define LC_MONETARY 0
29 #define LC_NUMERIC 0
30 #define LC_TIME 0
31 #define strerror(e) "(no error message provided by operating system)"
32 #endif
35 #define IOTAG 1
37 #define FIRSTARG 2 /* 1st is upvalue */
39 #define CLOSEDTAG(tag) ((tag)-1) /* assume that CLOSEDTAG = iotag-1 */
42 #define FINPUT "_INPUT"
43 #define FOUTPUT "_OUTPUT"
46 #ifdef POPEN
47 FILE *popen();
48 int pclose();
49 #define CLOSEFILE(f) {if (pclose(f) == -1) fclose(f);}
50 #else
51 /* no support for popen */
52 #define popen(x,y) NULL /* that is, popen always fails */
53 #define CLOSEFILE(f) {fclose(f);}
54 #endif
58 static void pushresult (int i) {
59 if (i)
60 lua_pushuserdata(NULL);
61 else {
62 lua_pushnil();
63 lua_pushstring(strerror(errno));
64 lua_pushnumber(errno);
70 ** {======================================================
71 ** FILE Operations
72 ** =======================================================
75 static int gettag (void) {
76 return (int)lua_getnumber(lua_getparam(IOTAG));
80 static int ishandle (lua_Object f) {
81 if (lua_isuserdata(f)) {
82 int tag = gettag();
83 if (lua_tag(f) == CLOSEDTAG(tag))
84 lua_error("cannot access a closed file");
85 return lua_tag(f) == tag;
87 else return 0;
91 static FILE *getfilebyname (char *name) {
92 lua_Object f = lua_getglobal(name);
93 if (!ishandle(f))
94 luaL_verror("global variable `%.50s' is not a file handle", name);
95 return lua_getuserdata(f);
99 static FILE *getfile (int arg) {
100 lua_Object f = lua_getparam(arg);
101 return (ishandle(f)) ? lua_getuserdata(f) : NULL;
105 static FILE *getnonullfile (int arg) {
106 FILE *f = getfile(arg);
107 luaL_arg_check(f, arg, "invalid file handle");
108 return f;
112 static FILE *getfileparam (char *name, int *arg) {
113 FILE *f = getfile(*arg);
114 if (f) {
115 (*arg)++;
116 return f;
118 else
119 return getfilebyname(name);
123 static void closefile (FILE *f) {
124 if (f != stdin && f != stdout) {
125 int tag = gettag();
126 CLOSEFILE(f);
127 lua_pushusertag(f, tag);
128 lua_settag(CLOSEDTAG(tag));
133 static void io_close (void) {
134 closefile(getnonullfile(FIRSTARG));
138 static void gc_close (void) {
139 FILE *f = getnonullfile(FIRSTARG);
140 if (f != stdin && f != stdout && f != stderr) {
141 CLOSEFILE(f);
146 static void io_open (void) {
147 FILE *f = fopen(luaL_check_string(FIRSTARG), luaL_check_string(FIRSTARG+1));
148 if (f) lua_pushusertag(f, gettag());
149 else pushresult(0);
153 static void setfile (FILE *f, char *name, int tag) {
154 lua_pushusertag(f, tag);
155 lua_setglobal(name);
159 static void setreturn (FILE *f, char *name) {
160 if (f == NULL)
161 pushresult(0);
162 else {
163 int tag = gettag();
164 setfile(f, name, tag);
165 lua_pushusertag(f, tag);
170 static void io_readfrom (void) {
171 FILE *current;
172 lua_Object f = lua_getparam(FIRSTARG);
173 if (f == LUA_NOOBJECT) {
174 closefile(getfilebyname(FINPUT));
175 current = stdin;
177 else if (lua_tag(f) == gettag()) /* deprecated option */
178 current = lua_getuserdata(f);
179 else {
180 char *s = luaL_check_string(FIRSTARG);
181 current = (*s == '|') ? popen(s+1, "r") : fopen(s, "r");
183 setreturn(current, FINPUT);
187 static void io_writeto (void) {
188 FILE *current;
189 lua_Object f = lua_getparam(FIRSTARG);
190 if (f == LUA_NOOBJECT) {
191 closefile(getfilebyname(FOUTPUT));
192 current = stdout;
194 else if (lua_tag(f) == gettag()) /* deprecated option */
195 current = lua_getuserdata(f);
196 else {
197 char *s = luaL_check_string(FIRSTARG);
198 current = (*s == '|') ? popen(s+1,"w") : fopen(s, "w");
200 setreturn(current, FOUTPUT);
204 static void io_appendto (void) {
205 FILE *current = fopen(luaL_check_string(FIRSTARG), "a");
206 setreturn(current, FOUTPUT);
212 ** {======================================================
213 ** READ
214 ** =======================================================
219 ** We cannot lookahead without need, because this can lock stdin.
220 ** This flag signals when we need to read a next char.
222 #define NEED_OTHER (EOF-1) /* just some flag different from EOF */
225 static int read_pattern (FILE *f, char *p) {
226 int inskip = 0; /* {skip} level */
227 int c = NEED_OTHER;
228 while (*p != '\0') {
229 switch (*p) {
230 case '{':
231 inskip++;
232 p++;
233 continue;
234 case '}':
235 if (!inskip) lua_error("unbalanced braces in read pattern");
236 inskip--;
237 p++;
238 continue;
239 default: {
240 char *ep = luaI_classend(p); /* get what is next */
241 int m; /* match result */
242 if (c == NEED_OTHER) c = getc(f);
243 m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep);
244 if (m) {
245 if (!inskip) luaL_addchar(c);
246 c = NEED_OTHER;
248 switch (*ep) {
249 case '+': /* repetition (1 or more) */
250 if (!m) goto break_while; /* pattern fails? */
251 /* else go through */
252 case '*': /* repetition (0 or more) */
253 while (m) { /* reads the same item until it fails */
254 c = getc(f);
255 m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep);
256 if (m && !inskip) luaL_addchar(c);
258 /* go through to continue reading the pattern */
259 case '?': /* optional */
260 p = ep+1; /* continues reading the pattern */
261 continue;
262 default:
263 if (!m) goto break_while; /* pattern fails? */
264 p = ep; /* else continues reading the pattern */
268 } break_while:
269 if (c != NEED_OTHER) ungetc(c, f);
270 return (*p == '\0');
274 static int read_number (FILE *f) {
275 double d;
276 if (fscanf(f, "%lf", &d) == 1) {
277 lua_pushnumber(d);
278 return 1;
280 else return 0; /* read fails */
284 #define HUNK_LINE 1024
285 #define HUNK_FILE BUFSIZ
287 static int read_line (FILE *f) {
288 /* equivalent to: return read_pattern(f, "[^\n]*{\n}"); */
289 int n;
290 char *b;
291 do {
292 b = luaL_openspace(HUNK_LINE);
293 if (!fgets(b, HUNK_LINE, f)) return 0; /* read fails */
294 n = strlen(b);
295 luaL_addsize(n);
296 } while (b[n-1] != '\n');
297 luaL_addsize(-1); /* remove '\n' */
298 return 1;
302 static void read_file (FILE *f) {
303 /* equivalent to: return read_pattern(f, ".*"); */
304 int n;
305 do {
306 char *b = luaL_openspace(HUNK_FILE);
307 n = fread(b, sizeof(char), HUNK_FILE, f);
308 luaL_addsize(n);
309 } while (n==HUNK_FILE);
313 static void io_read (void) {
314 static char *options[] = {"*n", "*l", "*a", ".*", "*w", NULL};
315 int arg = FIRSTARG;
316 FILE *f = getfileparam(FINPUT, &arg);
317 char *p = luaL_opt_string(arg++, "*l");
318 do { /* repeat for each part */
319 long l;
320 int success;
321 luaL_resetbuffer();
322 switch (luaL_findstring(p, options)) {
323 case 0: /* number */
324 if (!read_number(f)) return; /* read fails */
325 continue; /* number is already pushed; avoid the "pushstring" */
326 case 1: /* line */
327 success = read_line(f);
328 break;
329 case 2: case 3: /* file */
330 read_file(f);
331 success = 1; /* always success */
332 break;
333 case 4: /* word */
334 success = read_pattern(f, "{%s*}%S+");
335 break;
336 default:
337 success = read_pattern(f, p);
339 l = luaL_getsize();
340 if (!success && l==0) return; /* read fails */
341 lua_pushlstring(luaL_buffer(), l);
342 } while ((p = luaL_opt_string(arg++, NULL)) != NULL);
345 /* }====================================================== */
348 static void io_write (void) {
349 int arg = FIRSTARG;
350 FILE *f = getfileparam(FOUTPUT, &arg);
351 int status = 1;
352 char *s;
353 long l;
354 while ((s = luaL_opt_lstr(arg++, NULL, &l)) != NULL)
355 status = status && ((long)fwrite(s, 1, l, f) == l);
356 pushresult(status);
360 static void io_seek (void) {
361 static int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
362 static char *modenames[] = {"set", "cur", "end", NULL};
363 FILE *f = getnonullfile(FIRSTARG);
364 int op = luaL_findstring(luaL_opt_string(FIRSTARG+1, "cur"), modenames);
365 long offset = luaL_opt_long(FIRSTARG+2, 0);
366 luaL_arg_check(op != -1, FIRSTARG+1, "invalid mode");
367 op = fseek(f, offset, mode[op]);
368 if (op)
369 pushresult(0); /* error */
370 else
371 lua_pushnumber(ftell(f));
375 static void io_flush (void) {
376 FILE *f = getfile(FIRSTARG);
377 luaL_arg_check(f || lua_getparam(FIRSTARG) == LUA_NOOBJECT, FIRSTARG,
378 "invalid file handle");
379 pushresult(fflush(f) == 0);
382 /* }====================================================== */
386 ** {======================================================
387 ** Other O.S. Operations
388 ** =======================================================
391 static void io_execute (void) {
392 lua_pushnumber(system(luaL_check_string(1)));
396 static void io_remove (void) {
397 pushresult(remove(luaL_check_string(1)) == 0);
401 static void io_rename (void) {
402 pushresult(rename(luaL_check_string(1),
403 luaL_check_string(2)) == 0);
407 static void io_tmpname (void) {
408 lua_pushstring(tmpnam(NULL));
413 static void io_getenv (void) {
414 lua_pushstring(getenv(luaL_check_string(1))); /* if NULL push nil */
418 static void io_clock (void) {
419 lua_pushnumber(((double)clock())/CLOCKS_PER_SEC);
423 static void io_date (void) {
424 char b[256];
425 char *s = luaL_opt_string(1, "%c");
426 struct tm *tm;
427 time_t t;
428 time(&t); tm = localtime(&t);
429 if (strftime(b,sizeof(b),s,tm))
430 lua_pushstring(b);
431 else
432 lua_error("invalid `date' format");
436 static void setloc (void) {
437 static int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC,
438 LC_TIME};
439 static char *catnames[] = {"all", "collate", "ctype", "monetary",
440 "numeric", "time", NULL};
441 int op = luaL_findstring(luaL_opt_string(2, "all"), catnames);
442 luaL_arg_check(op != -1, 2, "invalid option");
443 lua_pushstring(setlocale(cat[op], luaL_check_string(1)));
447 static void io_exit (void) {
448 lua_Object o = lua_getparam(1);
449 exit(lua_isnumber(o) ? (int)lua_getnumber(o) : 1);
452 /* }====================================================== */
456 static void io_debug (void) {
457 for (;;) {
458 char buffer[250];
459 fprintf(stderr, "lua_debug> ");
460 if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
461 strcmp(buffer, "cont\n") == 0)
462 return;
463 lua_dostring(buffer);
469 #define MESSAGESIZE 150
470 #define MAXMESSAGE (MESSAGESIZE*10)
473 #define MAXSRC 60
476 static void errorfb (void) {
477 char buff[MAXMESSAGE];
478 int level = 1; /* skip level 0 (it's this function) */
479 lua_Object func;
480 sprintf(buff, "lua error: %.200s\n", lua_getstring(lua_getparam(1)));
481 while ((func = lua_stackedfunction(level++)) != LUA_NOOBJECT) {
482 char *name;
483 int currentline;
484 char *chunkname;
485 char buffchunk[MAXSRC];
486 int linedefined;
487 lua_funcinfo(func, &chunkname, &linedefined);
488 luaL_chunkid(buffchunk, chunkname, sizeof(buffchunk));
489 if (level == 2) strcat(buff, "Active Stack:\n");
490 strcat(buff, " ");
491 if (strlen(buff) > MAXMESSAGE-MESSAGESIZE) {
492 strcat(buff, "...\n");
493 break; /* buffer is full */
495 switch (*lua_getobjname(func, &name)) {
496 case 'g':
497 sprintf(buff+strlen(buff), "function `%.50s'", name);
498 break;
499 case 't':
500 sprintf(buff+strlen(buff), "`%.50s' tag method", name);
501 break;
502 default: {
503 if (linedefined == 0)
504 sprintf(buff+strlen(buff), "main of %.70s", buffchunk);
505 else if (linedefined < 0)
506 sprintf(buff+strlen(buff), "%.70s", buffchunk);
507 else
508 sprintf(buff+strlen(buff), "function <%d:%.70s>",
509 linedefined, buffchunk);
510 chunkname = NULL;
513 if ((currentline = lua_currentline(func)) > 0)
514 sprintf(buff+strlen(buff), " at line %d", currentline);
515 if (chunkname)
516 sprintf(buff+strlen(buff), " [%.70s]", buffchunk);
517 strcat(buff, "\n");
519 func = lua_rawgetglobal("_ALERT");
520 if (lua_isfunction(func)) { /* avoid error loop if _ALERT is not defined */
521 lua_pushstring(buff);
522 lua_callfunction(func);
528 static struct luaL_reg iolib[] = {
529 {"_ERRORMESSAGE", errorfb},
530 {"clock", io_clock},
531 {"date", io_date},
532 {"debug", io_debug},
533 {"execute", io_execute},
534 {"exit", io_exit},
535 {"getenv", io_getenv},
536 {"remove", io_remove},
537 {"rename", io_rename},
538 {"setlocale", setloc},
539 {"tmpname", io_tmpname}
543 static struct luaL_reg iolibtag[] = {
544 {"appendto", io_appendto},
545 {"closefile", io_close},
546 {"flush", io_flush},
547 {"openfile", io_open},
548 {"read", io_read},
549 {"readfrom", io_readfrom},
550 {"seek", io_seek},
551 {"write", io_write},
552 {"writeto", io_writeto}
556 static void openwithtags (void) {
557 int i;
558 int iotag = lua_newtag();
559 lua_newtag(); /* alloc CLOSEDTAG: assume that CLOSEDTAG = iotag-1 */
560 for (i=0; i<sizeof(iolibtag)/sizeof(iolibtag[0]); i++) {
561 /* put iotag as upvalue for these functions */
562 lua_pushnumber(iotag);
563 lua_pushcclosure(iolibtag[i].func, 1);
564 lua_setglobal(iolibtag[i].name);
566 /* predefined file handles */
567 setfile(stdin, FINPUT, iotag);
568 setfile(stdout, FOUTPUT, iotag);
569 setfile(stdin, "_STDIN", iotag);
570 setfile(stdout, "_STDOUT", iotag);
571 setfile(stderr, "_STDERR", iotag);
572 /* close file when collected */
573 lua_pushnumber(iotag);
574 lua_pushcclosure(gc_close, 1);
575 lua_settagmethod(iotag, "gc");
578 void lua_iolibopen (void) {
579 /* register lib functions */
580 luaL_openlib(iolib, (sizeof(iolib)/sizeof(iolib[0])));
581 openwithtags();