Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5205 clevermous 1
/*
2
** $Id: liolib.c,v 2.108 2011/11/25 12:50:03 roberto Exp $
3
** Standard I/O (and system) library
4
** See Copyright Notice in lua.h
5
*/
6
 
7
 
8
/*
9
** POSIX idiosyncrasy!
10
** This definition must come before the inclusion of 'stdio.h'; it
11
** should not affect non-POSIX systems
12
*/
13
#if !defined(_FILE_OFFSET_BITS)
14
#define _FILE_OFFSET_BITS 64
15
#endif
16
 
17
 
18
#include 
19
#include 
20
#include 
21
#include 
22
 
23
#define liolib_c
24
#define LUA_LIB
25
 
26
#include "lua.h"
27
 
28
#include "lauxlib.h"
29
#include "lualib.h"
30
 
31
 
32
 
33
/*
34
** {======================================================
35
** lua_popen spawns a new process connected to the current
36
** one through the file streams.
37
** =======================================================
38
*/
39
 
40
#if !defined(lua_popen)	/* { */
41
 
42
#if defined(LUA_USE_POPEN)	/* { */
43
 
44
#define lua_popen(L,c,m)	((void)L, fflush(NULL), popen(c,m))
45
#define lua_pclose(L,file)	((void)L, pclose(file))
46
 
47
#elif defined(LUA_WIN)		/* }{ */
48
 
49
#define lua_popen(L,c,m)		((void)L, _popen(c,m))
50
#define lua_pclose(L,file)		((void)L, _pclose(file))
51
 
52
 
53
#else				/* }{ */
54
 
55
#define lua_popen(L,c,m)		((void)((void)c, m),  \
56
		luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0)
57
#define lua_pclose(L,file)		((void)((void)L, file), -1)
58
 
59
 
60
#endif				/* } */
61
 
62
#endif			/* } */
63
 
64
/* }====================================================== */
65
 
66
 
67
/*
68
** {======================================================
69
** lua_fseek/lua_ftell: configuration for longer offsets
70
** =======================================================
71
*/
72
 
73
#if !defined(lua_fseek)	/* { */
74
 
75
#if defined(LUA_USE_POSIX)
76
 
77
#define l_fseek(f,o,w)		fseeko(f,o,w)
78
#define l_ftell(f)		ftello(f)
79
#define l_seeknum		off_t
80
 
81
#elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) \
82
   && defined(_MSC_VER) && (_MSC_VER >= 1400)
83
/* Windows (but not DDK) and Visual C++ 2005 or higher */
84
 
85
#define l_fseek(f,o,w)		_fseeki64(f,o,w)
86
#define l_ftell(f)		_ftelli64(f)
87
#define l_seeknum		__int64
88
 
89
#else
90
 
91
#define l_fseek(f,o,w)		fseek(f,o,w)
92
#define l_ftell(f)		ftell(f)
93
#define l_seeknum		long
94
 
95
#endif
96
 
97
#endif			/* } */
98
 
99
/* }====================================================== */
100
 
101
 
102
#define IO_PREFIX	"_IO_"
103
#define IO_INPUT	(IO_PREFIX "input")
104
#define IO_OUTPUT	(IO_PREFIX "output")
105
 
106
 
107
typedef luaL_Stream LStream;
108
 
109
 
110
#define tolstream(L)	((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE))
111
 
112
#define isclosed(p)	((p)->closef == NULL)
113
 
114
 
115
static int io_type (lua_State *L) {
116
  LStream *p;
117
  luaL_checkany(L, 1);
118
  p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE);
119
  if (p == NULL)
120
    lua_pushnil(L);  /* not a file */
121
  else if (isclosed(p))
122
    lua_pushliteral(L, "closed file");
123
  else
124
    lua_pushliteral(L, "file");
125
  return 1;
126
}
127
 
128
 
129
static int f_tostring (lua_State *L) {
130
  LStream *p = tolstream(L);
131
  if (isclosed(p))
132
    lua_pushliteral(L, "file (closed)");
133
  else
134
    lua_pushfstring(L, "file (%p)", p->f);
135
  return 1;
136
}
137
 
138
 
139
static FILE *tofile (lua_State *L) {
140
  LStream *p = tolstream(L);
141
  if (isclosed(p))
142
    luaL_error(L, "attempt to use a closed file");
143
  lua_assert(p->f);
144
  return p->f;
145
}
146
 
147
 
148
/*
149
** When creating file handles, always creates a `closed' file handle
150
** before opening the actual file; so, if there is a memory error, the
151
** file is not left opened.
152
*/
153
static LStream *newprefile (lua_State *L) {
154
  LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream));
155
  p->closef = NULL;  /* mark file handle as 'closed' */
156
  luaL_setmetatable(L, LUA_FILEHANDLE);
157
  return p;
158
}
159
 
160
 
161
static int aux_close (lua_State *L) {
162
  LStream *p = tolstream(L);
163
  lua_CFunction cf = p->closef;
164
  p->closef = NULL;  /* mark stream as closed */
165
  return (*cf)(L);  /* close it */
166
}
167
 
168
 
169
static int io_close (lua_State *L) {
170
  if (lua_isnone(L, 1))  /* no argument? */
171
    lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT);  /* use standard output */
172
  tofile(L);  /* make sure argument is an open stream */
173
  return aux_close(L);
174
}
175
 
176
 
177
static int f_gc (lua_State *L) {
178
  LStream *p = tolstream(L);
179
  if (!isclosed(p) && p->f != NULL)
180
    aux_close(L);  /* ignore closed and incompletely open files */
181
  return 0;
182
}
183
 
184
 
185
/*
186
** function to close regular files
187
*/
188
static int io_fclose (lua_State *L) {
189
  LStream *p = tolstream(L);
190
  int res = fclose(p->f);
191
  return luaL_fileresult(L, (res == 0), NULL);
192
}
193
 
194
 
195
static LStream *newfile (lua_State *L) {
196
  LStream *p = newprefile(L);
197
  p->f = NULL;
198
  p->closef = &io_fclose;
199
  return p;
200
}
201
 
202
 
203
static void opencheck (lua_State *L, const char *fname, const char *mode) {
204
  LStream *p = newfile(L);
205
  p->f = fopen(fname, mode);
206
  if (p->f == NULL)
207
    luaL_error(L, "cannot open file " LUA_QS " (%s)", fname, strerror(errno));
208
}
209
 
210
 
211
static int io_open (lua_State *L) {
212
  const char *filename = luaL_checkstring(L, 1);
213
  const char *mode = luaL_optstring(L, 2, "r");
214
  LStream *p = newfile(L);
215
  int i = 0;
216
  /* check whether 'mode' matches '[rwa]%+?b?' */
217
  if (!(mode[i] != '\0' && strchr("rwa", mode[i++]) != NULL &&
218
       (mode[i] != '+' || ++i) &&  /* skip if char is '+' */
219
       (mode[i] != 'b' || ++i) &&  /* skip if char is 'b' */
220
       (mode[i] == '\0')))
221
    return luaL_error(L, "invalid mode " LUA_QS
222
                         " (should match " LUA_QL("[rwa]%%+?b?") ")", mode);
223
  p->f = fopen(filename, mode);
224
  return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
225
}
226
 
227
 
228
/*
229
** function to close 'popen' files
230
*/
231
static int io_pclose (lua_State *L) {
232
  LStream *p = tolstream(L);
233
  return luaL_execresult(L, lua_pclose(L, p->f));
234
}
235
 
236
 
237
static int io_popen (lua_State *L) {
238
  const char *filename = luaL_checkstring(L, 1);
239
  const char *mode = luaL_optstring(L, 2, "r");
240
  LStream *p = newprefile(L);
241
  p->f = lua_popen(L, filename, mode);
242
  p->closef = &io_pclose;
243
  return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
244
}
245
 
246
 
247
static int io_tmpfile (lua_State *L) {
248
  LStream *p = newfile(L);
249
  p->f = tmpfile();
250
  return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
251
}
252
 
253
 
254
static FILE *getiofile (lua_State *L, const char *findex) {
255
  LStream *p;
256
  lua_getfield(L, LUA_REGISTRYINDEX, findex);
257
  p = (LStream *)lua_touserdata(L, -1);
258
  if (isclosed(p))
259
    luaL_error(L, "standard %s file is closed", findex + strlen(IO_PREFIX));
260
  return p->f;
261
}
262
 
263
 
264
static int g_iofile (lua_State *L, const char *f, const char *mode) {
265
  if (!lua_isnoneornil(L, 1)) {
266
    const char *filename = lua_tostring(L, 1);
267
    if (filename)
268
      opencheck(L, filename, mode);
269
    else {
270
      tofile(L);  /* check that it's a valid file handle */
271
      lua_pushvalue(L, 1);
272
    }
273
    lua_setfield(L, LUA_REGISTRYINDEX, f);
274
  }
275
  /* return current value */
276
  lua_getfield(L, LUA_REGISTRYINDEX, f);
277
  return 1;
278
}
279
 
280
 
281
static int io_input (lua_State *L) {
282
  return g_iofile(L, IO_INPUT, "r");
283
}
284
 
285
 
286
static int io_output (lua_State *L) {
287
  return g_iofile(L, IO_OUTPUT, "w");
288
}
289
 
290
 
291
static int io_readline (lua_State *L);
292
 
293
 
294
static void aux_lines (lua_State *L, int toclose) {
295
  int i;
296
  int n = lua_gettop(L) - 1;  /* number of arguments to read */
297
  /* ensure that arguments will fit here and into 'io_readline' stack */
298
  luaL_argcheck(L, n <= LUA_MINSTACK - 3, LUA_MINSTACK - 3, "too many options");
299
  lua_pushvalue(L, 1);  /* file handle */
300
  lua_pushinteger(L, n);  /* number of arguments to read */
301
  lua_pushboolean(L, toclose);  /* close/not close file when finished */
302
  for (i = 1; i <= n; i++) lua_pushvalue(L, i + 1);  /* copy arguments */
303
  lua_pushcclosure(L, io_readline, 3 + n);
304
}
305
 
306
 
307
static int f_lines (lua_State *L) {
308
  tofile(L);  /* check that it's a valid file handle */
309
  aux_lines(L, 0);
310
  return 1;
311
}
312
 
313
 
314
static int io_lines (lua_State *L) {
315
  int toclose;
316
  if (lua_isnone(L, 1)) lua_pushnil(L);  /* at least one argument */
317
  if (lua_isnil(L, 1)) {  /* no file name? */
318
    lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT);  /* get default input */
319
    lua_replace(L, 1);  /* put it at index 1 */
320
    tofile(L);  /* check that it's a valid file handle */
321
    toclose = 0;  /* do not close it after iteration */
322
  }
323
  else {  /* open a new file */
324
    const char *filename = luaL_checkstring(L, 1);
325
    opencheck(L, filename, "r");
326
    lua_replace(L, 1);  /* put file at index 1 */
327
    toclose = 1;  /* close it after iteration */
328
  }
329
  aux_lines(L, toclose);
330
  return 1;
331
}
332
 
333
 
334
/*
335
** {======================================================
336
** READ
337
** =======================================================
338
*/
339
 
340
 
341
static int read_number (lua_State *L, FILE *f) {
342
  lua_Number d;
343
  if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) {
344
    lua_pushnumber(L, d);
345
    return 1;
346
  }
347
  else {
348
   lua_pushnil(L);  /* "result" to be removed */
349
   return 0;  /* read fails */
350
  }
351
}
352
 
353
 
354
static int test_eof (lua_State *L, FILE *f) {
355
  int c = getc(f);
356
  ungetc(c, f);
357
  lua_pushlstring(L, NULL, 0);
358
  return (c != EOF);
359
}
360
 
361
 
362
static int read_line (lua_State *L, FILE *f, int chop) {
363
  luaL_Buffer b;
364
  luaL_buffinit(L, &b);
365
  for (;;) {
366
    size_t l;
367
    char *p = luaL_prepbuffer(&b);
368
    if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) {  /* eof? */
369
      luaL_pushresult(&b);  /* close buffer */
370
      return (lua_rawlen(L, -1) > 0);  /* check whether read something */
371
    }
372
    l = strlen(p);
373
    if (l == 0 || p[l-1] != '\n')
374
      luaL_addsize(&b, l);
375
    else {
376
      luaL_addsize(&b, l - chop);  /* chop 'eol' if needed */
377
      luaL_pushresult(&b);  /* close buffer */
378
      return 1;  /* read at least an `eol' */
379
    }
380
  }
381
}
382
 
383
 
384
#define MAX_SIZE_T	(~(size_t)0)
385
 
386
static void read_all (lua_State *L, FILE *f) {
387
  size_t rlen = LUAL_BUFFERSIZE;  /* how much to read in each cycle */
388
  luaL_Buffer b;
389
  luaL_buffinit(L, &b);
390
  for (;;) {
391
    char *p = luaL_prepbuffsize(&b, rlen);
392
    size_t nr = fread(p, sizeof(char), rlen, f);
393
    luaL_addsize(&b, nr);
394
    if (nr < rlen) break;  /* eof? */
395
    else if (rlen <= (MAX_SIZE_T / 4))  /* avoid buffers too large */
396
      rlen *= 2;  /* double buffer size at each iteration */
397
  }
398
  luaL_pushresult(&b);  /* close buffer */
399
}
400
 
401
 
402
static int read_chars (lua_State *L, FILE *f, size_t n) {
403
  size_t nr;  /* number of chars actually read */
404
  char *p;
405
  luaL_Buffer b;
406
  luaL_buffinit(L, &b);
407
  p = luaL_prepbuffsize(&b, n);  /* prepare buffer to read whole block */
408
  nr = fread(p, sizeof(char), n, f);  /* try to read 'n' chars */
409
  luaL_addsize(&b, nr);
410
  luaL_pushresult(&b);  /* close buffer */
411
  return (nr > 0);  /* true iff read something */
412
}
413
 
414
 
415
static int g_read (lua_State *L, FILE *f, int first) {
416
  int nargs = lua_gettop(L) - 1;
417
  int success;
418
  int n;
419
  clearerr(f);
420
  if (nargs == 0) {  /* no arguments? */
421
    success = read_line(L, f, 1);
422
    n = first+1;  /* to return 1 result */
423
  }
424
  else {  /* ensure stack space for all results and for auxlib's buffer */
425
    luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
426
    success = 1;
427
    for (n = first; nargs-- && success; n++) {
428
      if (lua_type(L, n) == LUA_TNUMBER) {
429
        size_t l = (size_t)lua_tointeger(L, n);
430
        success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
431
      }
432
      else {
433
        const char *p = lua_tostring(L, n);
434
        luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
435
        switch (p[1]) {
436
          case 'n':  /* number */
437
            success = read_number(L, f);
438
            break;
439
          case 'l':  /* line */
440
            success = read_line(L, f, 1);
441
            break;
442
          case 'L':  /* line with end-of-line */
443
            success = read_line(L, f, 0);
444
            break;
445
          case 'a':  /* file */
446
            read_all(L, f);  /* read entire file */
447
            success = 1; /* always success */
448
            break;
449
          default:
450
            return luaL_argerror(L, n, "invalid format");
451
        }
452
      }
453
    }
454
  }
455
  if (ferror(f))
456
    return luaL_fileresult(L, 0, NULL);
457
  if (!success) {
458
    lua_pop(L, 1);  /* remove last result */
459
    lua_pushnil(L);  /* push nil instead */
460
  }
461
  return n - first;
462
}
463
 
464
 
465
static int io_read (lua_State *L) {
466
  return g_read(L, getiofile(L, IO_INPUT), 1);
467
}
468
 
469
 
470
static int f_read (lua_State *L) {
471
  return g_read(L, tofile(L), 2);
472
}
473
 
474
 
475
static int io_readline (lua_State *L) {
476
  LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1));
477
  int i;
478
  int n = (int)lua_tointeger(L, lua_upvalueindex(2));
479
  if (isclosed(p))  /* file is already closed? */
480
    return luaL_error(L, "file is already closed");
481
  lua_settop(L , 1);
482
  for (i = 1; i <= n; i++)  /* push arguments to 'g_read' */
483
    lua_pushvalue(L, lua_upvalueindex(3 + i));
484
  n = g_read(L, p->f, 2);  /* 'n' is number of results */
485
  lua_assert(n > 0);  /* should return at least a nil */
486
  if (!lua_isnil(L, -n))  /* read at least one value? */
487
    return n;  /* return them */
488
  else {  /* first result is nil: EOF or error */
489
    if (n > 1) {  /* is there error information? */
490
      /* 2nd result is error message */
491
      return luaL_error(L, "%s", lua_tostring(L, -n + 1));
492
    }
493
    if (lua_toboolean(L, lua_upvalueindex(3))) {  /* generator created file? */
494
      lua_settop(L, 0);
495
      lua_pushvalue(L, lua_upvalueindex(1));
496
      aux_close(L);  /* close it */
497
    }
498
    return 0;
499
  }
500
}
501
 
502
/* }====================================================== */
503
 
504
 
505
static int g_write (lua_State *L, FILE *f, int arg) {
506
  int nargs = lua_gettop(L) - arg;
507
  int status = 1;
508
  for (; nargs--; arg++) {
509
    if (lua_type(L, arg) == LUA_TNUMBER) {
510
      /* optimization: could be done exactly as for strings */
511
      status = status &&
512
          fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
513
    }
514
    else {
515
      size_t l;
516
      const char *s = luaL_checklstring(L, arg, &l);
517
      status = status && (fwrite(s, sizeof(char), l, f) == l);
518
    }
519
  }
520
  if (status) return 1;  /* file handle already on stack top */
521
  else return luaL_fileresult(L, status, NULL);
522
}
523
 
524
 
525
static int io_write (lua_State *L) {
526
  return g_write(L, getiofile(L, IO_OUTPUT), 1);
527
}
528
 
529
 
530
static int f_write (lua_State *L) {
531
  FILE *f = tofile(L);
532
  lua_pushvalue(L, 1);  /* push file at the stack top (to be returned) */
533
  return g_write(L, f, 2);
534
}
535
 
536
 
537
static int f_seek (lua_State *L) {
538
  static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
539
  static const char *const modenames[] = {"set", "cur", "end", NULL};
540
  FILE *f = tofile(L);
541
  int op = luaL_checkoption(L, 2, "cur", modenames);
542
  lua_Number p3 = luaL_optnumber(L, 3, 0);
543
  l_seeknum offset = (l_seeknum)p3;
544
  luaL_argcheck(L, (lua_Number)offset == p3, 3,
545
                  "not an integer in proper range");
546
  op = l_fseek(f, offset, mode[op]);
547
  if (op)
548
    return luaL_fileresult(L, 0, NULL);  /* error */
549
  else {
550
    lua_pushnumber(L, (lua_Number)l_ftell(f));
551
    return 1;
552
  }
553
}
554
 
555
 
556
static int f_setvbuf (lua_State *L) {
557
  static const int mode[] = {_IONBF, _IOFBF, _IOLBF};
558
  static const char *const modenames[] = {"no", "full", "line", NULL};
559
  FILE *f = tofile(L);
560
  int op = luaL_checkoption(L, 2, NULL, modenames);
561
  lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
562
  int res = setvbuf(f, NULL, mode[op], sz);
563
  return luaL_fileresult(L, res == 0, NULL);
564
}
565
 
566
 
567
 
568
static int io_flush (lua_State *L) {
569
  return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
570
}
571
 
572
 
573
static int f_flush (lua_State *L) {
574
  return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL);
575
}
576
 
577
 
578
/*
579
** functions for 'io' library
580
*/
581
static const luaL_Reg iolib[] = {
582
  {"close", io_close},
583
  {"flush", io_flush},
584
  {"input", io_input},
585
  {"lines", io_lines},
586
  {"open", io_open},
587
  {"output", io_output},
588
  {"popen", io_popen},
589
  {"read", io_read},
590
  {"tmpfile", io_tmpfile},
591
  {"type", io_type},
592
  {"write", io_write},
593
  {NULL, NULL}
594
};
595
 
596
 
597
/*
598
** methods for file handles
599
*/
600
static const luaL_Reg flib[] = {
601
  {"close", io_close},
602
  {"flush", f_flush},
603
  {"lines", f_lines},
604
  {"read", f_read},
605
  {"seek", f_seek},
606
  {"setvbuf", f_setvbuf},
607
  {"write", f_write},
608
  {"__gc", f_gc},
609
  {"__tostring", f_tostring},
610
  {NULL, NULL}
611
};
612
 
613
 
614
static void createmeta (lua_State *L) {
615
  luaL_newmetatable(L, LUA_FILEHANDLE);  /* create metatable for file handles */
616
  lua_pushvalue(L, -1);  /* push metatable */
617
  lua_setfield(L, -2, "__index");  /* metatable.__index = metatable */
618
  luaL_setfuncs(L, flib, 0);  /* add file methods to new metatable */
619
  lua_pop(L, 1);  /* pop new metatable */
620
}
621
 
622
 
623
/*
624
** function to (not) close the standard files stdin, stdout, and stderr
625
*/
626
static int io_noclose (lua_State *L) {
627
  LStream *p = tolstream(L);
628
  p->closef = &io_noclose;  /* keep file opened */
629
  lua_pushnil(L);
630
  lua_pushliteral(L, "cannot close standard file");
631
  return 2;
632
}
633
 
634
 
635
static void createstdfile (lua_State *L, FILE *f, const char *k,
636
                           const char *fname) {
637
  LStream *p = newprefile(L);
638
  p->f = f;
639
  p->closef = &io_noclose;
640
  if (k != NULL) {
641
    lua_pushvalue(L, -1);
642
    lua_setfield(L, LUA_REGISTRYINDEX, k);  /* add file to registry */
643
  }
644
  lua_setfield(L, -2, fname);  /* add file to module */
645
}
646
 
647
 
648
LUAMOD_API int luaopen_io (lua_State *L) {
649
  luaL_newlib(L, iolib);  /* new module */
650
  createmeta(L);
651
  /* create (and set) default files */
652
  createstdfile(L, stdin, IO_INPUT, "stdin");
653
  createstdfile(L, stdout, IO_OUTPUT, "stdout");
654
  createstdfile(L, stderr, NULL, "stderr");
655
  return 1;
656
}
657