Subversion Repositories WoWGM

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 tristanc 1
/*
2
** $Id: liolib.c,v 2.73 2006/05/08 20:14:16 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 <stdio.h>
10
#include <stdlib.h>
11
#include <string.h>
12
 
13
#define liolib_c
14
#define LUA_LIB
15
 
16
#include "lua.h"
17
 
18
#include "lauxlib.h"
19
#include "lualib.h"
20
 
21
 
22
 
23
#define IO_INPUT	1
24
#define IO_OUTPUT	2
25
 
26
 
27
static const char *const fnames[] = {"input", "output"};
28
 
29
 
30
static int pushresult (lua_State *L, int i, const char *filename) {
31
  int en = errno;  /* calls to Lua API may change this value */
32
  if (i) {
33
    lua_pushboolean(L, 1);
34
    return 1;
35
  }
36
  else {
37
    lua_pushnil(L);
38
    if (filename)
39
      lua_pushfstring(L, "%s: %s", filename, strerror(en));
40
    else
41
      lua_pushfstring(L, "%s", strerror(en));
42
    lua_pushinteger(L, en);
43
    return 3;
44
  }
45
}
46
 
47
 
48
static void fileerror (lua_State *L, int arg, const char *filename) {
49
  lua_pushfstring(L, "%s: %s", filename, strerror(errno));
50
  luaL_argerror(L, arg, lua_tostring(L, -1));
51
}
52
 
53
 
54
#define topfile(L)	((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE))
55
 
56
 
57
static int io_type (lua_State *L) {
58
  void *ud;
59
  luaL_checkany(L, 1);
60
  ud = lua_touserdata(L, 1);
61
  lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
62
  if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1))
63
    lua_pushnil(L);  /* not a file */
64
  else if (*((FILE **)ud) == NULL)
65
    lua_pushliteral(L, "closed file");
66
  else
67
    lua_pushliteral(L, "file");
68
  return 1;
69
}
70
 
71
 
72
static FILE *tofile (lua_State *L) {
73
  FILE **f = topfile(L);
74
  if (*f == NULL)
75
    luaL_error(L, "attempt to use a closed file");
76
  return *f;
77
}
78
 
79
 
80
 
81
/*
82
** When creating file handles, always creates a `closed' file handle
83
** before opening the actual file; so, if there is a memory error, the
84
** file is not left opened.
85
*/
86
static FILE **newfile (lua_State *L) {
87
  FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *));
88
  *pf = NULL;  /* file handle is currently `closed' */
89
  luaL_getmetatable(L, LUA_FILEHANDLE);
90
  lua_setmetatable(L, -2);
91
  return pf;
92
}
93
 
94
 
95
/*
96
** this function has a separated environment, which defines the
97
** correct __close for 'popen' files
98
*/
99
static int io_pclose (lua_State *L) {
100
  FILE **p = topfile(L);
101
  int ok = lua_pclose(L, *p);
102
  *p = NULL;
103
  return pushresult(L, ok, NULL);
104
}
105
 
106
 
107
static int io_fclose (lua_State *L) {
108
  FILE **p = topfile(L);
109
  int ok = (fclose(*p) == 0);
110
  *p = NULL;
111
  return pushresult(L, ok, NULL);
112
}
113
 
114
 
115
static int aux_close (lua_State *L) {
116
  lua_getfenv(L, 1);
117
  lua_getfield(L, -1, "__close");
118
  return (lua_tocfunction(L, -1))(L);
119
}
120
 
121
 
122
static int io_close (lua_State *L) {
123
  if (lua_isnone(L, 1))
124
    lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT);
125
  tofile(L);  /* make sure argument is a file */
126
  return aux_close(L);
127
}
128
 
129
 
130
static int io_gc (lua_State *L) {
131
  FILE *f = *topfile(L);
132
  /* ignore closed files and standard files */
133
  if (f != NULL && f != stdin && f != stdout && f != stderr)
134
    aux_close(L);
135
  return 0;
136
}
137
 
138
 
139
static int io_tostring (lua_State *L) {
140
  FILE *f = *topfile(L);
141
  if (f == NULL)
142
    lua_pushstring(L, "file (closed)");
143
  else
144
    lua_pushfstring(L, "file (%p)", f);
145
  return 1;
146
}
147
 
148
 
149
static int io_open (lua_State *L) {
150
  const char *filename = luaL_checkstring(L, 1);
151
  const char *mode = luaL_optstring(L, 2, "r");
152
  FILE **pf = newfile(L);
153
  *pf = fopen(filename, mode);
154
  return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
155
}
156
 
157
 
158
static int io_popen (lua_State *L) {
159
  const char *filename = luaL_checkstring(L, 1);
160
  const char *mode = luaL_optstring(L, 2, "r");
161
  FILE **pf = newfile(L);
162
  *pf = lua_popen(L, filename, mode);
163
  return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
164
}
165
 
166
 
167
static int io_tmpfile (lua_State *L) {
168
  FILE **pf = newfile(L);
169
  *pf = tmpfile();
170
  return (*pf == NULL) ? pushresult(L, 0, NULL) : 1;
171
}
172
 
173
 
174
static FILE *getiofile (lua_State *L, int findex) {
175
  FILE *f;
176
  lua_rawgeti(L, LUA_ENVIRONINDEX, findex);
177
  f = *(FILE **)lua_touserdata(L, -1);
178
  if (f == NULL)
179
    luaL_error(L, "standard %s file is closed", fnames[findex - 1]);
180
  return f;
181
}
182
 
183
 
184
static int g_iofile (lua_State *L, int f, const char *mode) {
185
  if (!lua_isnoneornil(L, 1)) {
186
    const char *filename = lua_tostring(L, 1);
187
    if (filename) {
188
      FILE **pf = newfile(L);
189
      *pf = fopen(filename, mode);
190
      if (*pf == NULL)
191
        fileerror(L, 1, filename);
192
    }
193
    else {
194
      tofile(L);  /* check that it's a valid file handle */
195
      lua_pushvalue(L, 1);
196
    }
197
    lua_rawseti(L, LUA_ENVIRONINDEX, f);
198
  }
199
  /* return current value */
200
  lua_rawgeti(L, LUA_ENVIRONINDEX, f);
201
  return 1;
202
}
203
 
204
 
205
static int io_input (lua_State *L) {
206
  return g_iofile(L, IO_INPUT, "r");
207
}
208
 
209
 
210
static int io_output (lua_State *L) {
211
  return g_iofile(L, IO_OUTPUT, "w");
212
}
213
 
214
 
215
static int io_readline (lua_State *L);
216
 
217
 
218
static void aux_lines (lua_State *L, int idx, int toclose) {
219
  lua_pushvalue(L, idx);
220
  lua_pushboolean(L, toclose);  /* close/not close file when finished */
221
  lua_pushcclosure(L, io_readline, 2);
222
}
223
 
224
 
225
static int f_lines (lua_State *L) {
226
  tofile(L);  /* check that it's a valid file handle */
227
  aux_lines(L, 1, 0);
228
  return 1;
229
}
230
 
231
 
232
static int io_lines (lua_State *L) {
233
  if (lua_isnoneornil(L, 1)) {  /* no arguments? */
234
    /* will iterate over default input */
235
    lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT);
236
    return f_lines(L);
237
  }
238
  else {
239
    const char *filename = luaL_checkstring(L, 1);
240
    FILE **pf = newfile(L);
241
    *pf = fopen(filename, "r");
242
    if (*pf == NULL)
243
      fileerror(L, 1, filename);
244
    aux_lines(L, lua_gettop(L), 1);
245
    return 1;
246
  }
247
}
248
 
249
 
250
/*
251
** {======================================================
252
** READ
253
** =======================================================
254
*/
255
 
256
 
257
static int read_number (lua_State *L, FILE *f) {
258
  lua_Number d;
259
  if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) {
260
    lua_pushnumber(L, d);
261
    return 1;
262
  }
263
  else return 0;  /* read fails */
264
}
265
 
266
 
267
static int test_eof (lua_State *L, FILE *f) {
268
  int c = getc(f);
269
  ungetc(c, f);
270
  lua_pushlstring(L, NULL, 0);
271
  return (c != EOF);
272
}
273
 
274
 
275
static int read_line (lua_State *L, FILE *f) {
276
  luaL_Buffer b;
277
  luaL_buffinit(L, &b);
278
  for (;;) {
279
    size_t l;
280
    char *p = luaL_prepbuffer(&b);
281
    if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) {  /* eof? */
282
      luaL_pushresult(&b);  /* close buffer */
283
      return (lua_strlen(L, -1) > 0);  /* check whether read something */
284
    }
285
    l = strlen(p);
286
    if (l == 0 || p[l-1] != '\n')
287
      luaL_addsize(&b, l);
288
    else {
289
      luaL_addsize(&b, l - 1);  /* do not include `eol' */
290
      luaL_pushresult(&b);  /* close buffer */
291
      return 1;  /* read at least an `eol' */
292
    }
293
  }
294
}
295
 
296
 
297
static int read_chars (lua_State *L, FILE *f, size_t n) {
298
  size_t rlen;  /* how much to read */
299
  size_t nr;  /* number of chars actually read */
300
  luaL_Buffer b;
301
  luaL_buffinit(L, &b);
302
  rlen = LUAL_BUFFERSIZE;  /* try to read that much each time */
303
  do {
304
    char *p = luaL_prepbuffer(&b);
305
    if (rlen > n) rlen = n;  /* cannot read more than asked */
306
    nr = fread(p, sizeof(char), rlen, f);
307
    luaL_addsize(&b, nr);
308
    n -= nr;  /* still have to read `n' chars */
309
  } while (n > 0 && nr == rlen);  /* until end of count or eof */
310
  luaL_pushresult(&b);  /* close buffer */
311
  return (n == 0 || lua_strlen(L, -1) > 0);
312
}
313
 
314
 
315
static int g_read (lua_State *L, FILE *f, int first) {
316
  int nargs = lua_gettop(L) - 1;
317
  int success;
318
  int n;
319
  clearerr(f);
320
  if (nargs == 0) {  /* no arguments? */
321
    success = read_line(L, f);
322
    n = first+1;  /* to return 1 result */
323
  }
324
  else {  /* ensure stack space for all results and for auxlib's buffer */
325
    luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
326
    success = 1;
327
    for (n = first; nargs-- && success; n++) {
328
      if (lua_type(L, n) == LUA_TNUMBER) {
329
        size_t l = (size_t)lua_tointeger(L, n);
330
        success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
331
      }
332
      else {
333
        const char *p = lua_tostring(L, n);
334
        luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
335
        switch (p[1]) {
336
          case 'n':  /* number */
337
            success = read_number(L, f);
338
            break;
339
          case 'l':  /* line */
340
            success = read_line(L, f);
341
            break;
342
          case 'a':  /* file */
343
            read_chars(L, f, ~((size_t)0));  /* read MAX_SIZE_T chars */
344
            success = 1; /* always success */
345
            break;
346
          default:
347
            return luaL_argerror(L, n, "invalid format");
348
        }
349
      }
350
    }
351
  }
352
  if (ferror(f))
353
    return pushresult(L, 0, NULL);
354
  if (!success) {
355
    lua_pop(L, 1);  /* remove last result */
356
    lua_pushnil(L);  /* push nil instead */
357
  }
358
  return n - first;
359
}
360
 
361
 
362
static int io_read (lua_State *L) {
363
  return g_read(L, getiofile(L, IO_INPUT), 1);
364
}
365
 
366
 
367
static int f_read (lua_State *L) {
368
  return g_read(L, tofile(L), 2);
369
}
370
 
371
 
372
static int io_readline (lua_State *L) {
373
  FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1));
374
  int sucess;
375
  if (f == NULL)  /* file is already closed? */
376
    luaL_error(L, "file is already closed");
377
  sucess = read_line(L, f);
378
  if (ferror(f))
379
    return luaL_error(L, "%s", strerror(errno));
380
  if (sucess) return 1;
381
  else {  /* EOF */
382
    if (lua_toboolean(L, lua_upvalueindex(2))) {  /* generator created file? */
383
      lua_settop(L, 0);
384
      lua_pushvalue(L, lua_upvalueindex(1));
385
      aux_close(L);  /* close it */
386
    }
387
    return 0;
388
  }
389
}
390
 
391
/* }====================================================== */
392
 
393
 
394
static int g_write (lua_State *L, FILE *f, int arg) {
395
  int nargs = lua_gettop(L) - 1;
396
  int status = 1;
397
  for (; nargs--; arg++) {
398
    if (lua_type(L, arg) == LUA_TNUMBER) {
399
      /* optimization: could be done exactly as for strings */
400
      status = status &&
401
          fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
402
    }
403
    else {
404
      size_t l;
405
      const char *s = luaL_checklstring(L, arg, &l);
406
      status = status && (fwrite(s, sizeof(char), l, f) == l);
407
    }
408
  }
409
  return pushresult(L, status, NULL);
410
}
411
 
412
 
413
static int io_write (lua_State *L) {
414
  return g_write(L, getiofile(L, IO_OUTPUT), 1);
415
}
416
 
417
 
418
static int f_write (lua_State *L) {
419
  return g_write(L, tofile(L), 2);
420
}
421
 
422
 
423
static int f_seek (lua_State *L) {
424
  static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
425
  static const char *const modenames[] = {"set", "cur", "end", NULL};
426
  FILE *f = tofile(L);
427
  int op = luaL_checkoption(L, 2, "cur", modenames);
428
  long offset = luaL_optlong(L, 3, 0);
429
  op = fseek(f, offset, mode[op]);
430
  if (op)
431
    return pushresult(L, 0, NULL);  /* error */
432
  else {
433
    lua_pushinteger(L, ftell(f));
434
    return 1;
435
  }
436
}
437
 
438
 
439
static int f_setvbuf (lua_State *L) {
440
  static const int mode[] = {_IONBF, _IOFBF, _IOLBF};
441
  static const char *const modenames[] = {"no", "full", "line", NULL};
442
  FILE *f = tofile(L);
443
  int op = luaL_checkoption(L, 2, NULL, modenames);
444
  lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
445
  int res = setvbuf(f, NULL, mode[op], sz);
446
  return pushresult(L, res == 0, NULL);
447
}
448
 
449
 
450
 
451
static int io_flush (lua_State *L) {
452
  return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
453
}
454
 
455
 
456
static int f_flush (lua_State *L) {
457
  return pushresult(L, fflush(tofile(L)) == 0, NULL);
458
}
459
 
460
 
461
static const luaL_Reg iolib[] = {
462
  {"close", io_close},
463
  {"flush", io_flush},
464
  {"input", io_input},
465
  {"lines", io_lines},
466
  {"open", io_open},
467
  {"output", io_output},
468
  {"popen", io_popen},
469
  {"read", io_read},
470
  {"tmpfile", io_tmpfile},
471
  {"type", io_type},
472
  {"write", io_write},
473
  {NULL, NULL}
474
};
475
 
476
 
477
static const luaL_Reg flib[] = {
478
  {"close", io_close},
479
  {"flush", f_flush},
480
  {"lines", f_lines},
481
  {"read", f_read},
482
  {"seek", f_seek},
483
  {"setvbuf", f_setvbuf},
484
  {"write", f_write},
485
  {"__gc", io_gc},
486
  {"__tostring", io_tostring},
487
  {NULL, NULL}
488
};
489
 
490
 
491
static void createmeta (lua_State *L) {
492
  luaL_newmetatable(L, LUA_FILEHANDLE);  /* create metatable for file handles */
493
  lua_pushvalue(L, -1);  /* push metatable */
494
  lua_setfield(L, -2, "__index");  /* metatable.__index = metatable */
495
  luaL_register(L, NULL, flib);  /* file methods */
496
}
497
 
498
 
499
static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) {
500
  *newfile(L) = f;
501
  if (k > 0) {
502
    lua_pushvalue(L, -1);
503
    lua_rawseti(L, LUA_ENVIRONINDEX, k);
504
  }
505
  lua_setfield(L, -2, fname);
506
}
507
 
508
 
509
LUALIB_API int luaopen_io (lua_State *L) {
510
  createmeta(L);
511
  /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */
512
  lua_createtable(L, 2, 1);
513
  lua_replace(L, LUA_ENVIRONINDEX);
514
  /* open library */
515
  luaL_register(L, LUA_IOLIBNAME, iolib);
516
  /* create (and set) default files */
517
  createstdfile(L, stdin, IO_INPUT, "stdin");
518
  createstdfile(L, stdout, IO_OUTPUT, "stdout");
519
  createstdfile(L, stderr, 0, "stderr");
520
  /* create environment for 'popen' */
521
  lua_getfield(L, -1, "popen");
522
  lua_createtable(L, 0, 1);
523
  lua_pushcfunction(L, io_pclose);
524
  lua_setfield(L, -2, "__close");
525
  lua_setfenv(L, -2);
526
  lua_pop(L, 1);  /* pop 'popen' */
527
  /* set default close function */
528
  lua_pushcfunction(L, io_fclose);
529
  lua_setfield(L, LUA_ENVIRONINDEX, "__close");
530
  return 1;
531
}
532