|
@@ -1,5 +1,5 @@
|
|
/*
|
|
/*
|
|
-** $Id: liolib.c,v 1.114 2001/06/07 13:46:29 roberto Exp roberto $
|
|
|
|
|
|
+** $Id: liolib.c,v 1.115 2001/06/08 16:48:32 roberto Exp roberto $
|
|
** Standard I/O (and system) library
|
|
** Standard I/O (and system) library
|
|
** See Copyright Notice in lua.h
|
|
** See Copyright Notice in lua.h
|
|
*/
|
|
*/
|
|
@@ -205,115 +205,114 @@ static int io_appendto (lua_State *L) {
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
|
|
-static int read_number (lua_State *L, FILE *f) {
|
|
|
|
- double d;
|
|
|
|
- if (fscanf(f, l_s("%lf"), &d) == 1) {
|
|
|
|
- lua_pushnumber(L, d);
|
|
|
|
- return 1;
|
|
|
|
|
|
+#ifndef LUA_MAXUNTIL
|
|
|
|
+#define LUA_MAXUNTIL 100
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+** Knuth-Morris-Pratt algorithm for string searching
|
|
|
|
+** (based on `Algorithms in MODULA-3', Robert Sedgewick;
|
|
|
|
+** Addison-Wesley, 1993.)
|
|
|
|
+*/
|
|
|
|
+
|
|
|
|
+static void prep_read_until (int next[], const l_char *p, int pl) {
|
|
|
|
+ int i = 0;
|
|
|
|
+ int j = -1;
|
|
|
|
+ next[0] = -1;
|
|
|
|
+ while (i < pl) {
|
|
|
|
+ if (j == -1 || p[i] == p[j]) {
|
|
|
|
+ i++; j++; next[i] = j;
|
|
|
|
+ }
|
|
|
|
+ else j = next[j];
|
|
}
|
|
}
|
|
- else return 0; /* read fails */
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-static int read_word (lua_State *L, FILE *f) {
|
|
|
|
|
|
+static int read_until (lua_State *L, FILE *f, const l_char *p, int pl) {
|
|
l_charint c;
|
|
l_charint c;
|
|
|
|
+ int j;
|
|
|
|
+ int next[LUA_MAXUNTIL+1];
|
|
luaL_Buffer b;
|
|
luaL_Buffer b;
|
|
luaL_buffinit(L, &b);
|
|
luaL_buffinit(L, &b);
|
|
- do { c = fgetc(f); } while (isspace(c)); /* skip spaces */
|
|
|
|
- while (c != EOF && !isspace(c)) {
|
|
|
|
- luaL_putchar(&b, c);
|
|
|
|
- c = fgetc(f);
|
|
|
|
|
|
+ prep_read_until(next, p, pl);
|
|
|
|
+ j = 0;
|
|
|
|
+ while ((c = fgetc(f)) != EOF) {
|
|
|
|
+ NoRead:
|
|
|
|
+ if (c == p[j]) {
|
|
|
|
+ j++; /* go to next char in pattern */
|
|
|
|
+ if (j == pl) { /* complete match? */
|
|
|
|
+ luaL_pushresult(&b); /* close buffer */
|
|
|
|
+ return 1; /* always success */
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else if (j == 0)
|
|
|
|
+ luaL_putchar(&b, c);
|
|
|
|
+ else { /* match fail */
|
|
|
|
+ luaL_addlstring(&b, p, j - next[j]); /* put failed part on result */
|
|
|
|
+ j = next[j]; /* backtrack pattern index */
|
|
|
|
+ goto NoRead; /* repeat without reading next char */
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- ungetc(c, f);
|
|
|
|
|
|
+ /* end of file without a match */
|
|
|
|
+ luaL_addlstring(&b, p, j); /* put failed part on result */
|
|
luaL_pushresult(&b); /* close buffer */
|
|
luaL_pushresult(&b); /* close buffer */
|
|
return (lua_strlen(L, -1) > 0);
|
|
return (lua_strlen(L, -1) > 0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-static int read_line (lua_State *L, FILE *f) {
|
|
|
|
- int n = 0;
|
|
|
|
- luaL_Buffer b;
|
|
|
|
- luaL_buffinit(L, &b);
|
|
|
|
- for (;;) {
|
|
|
|
- l_char *p = luaL_prepbuffer(&b);
|
|
|
|
- if (!fgets(p, LUAL_BUFFERSIZE, f)) /* read fails? */
|
|
|
|
- break;
|
|
|
|
- n = strlen(p);
|
|
|
|
- if (p[n-1] != l_c('\n'))
|
|
|
|
- luaL_addsize(&b, n);
|
|
|
|
- else {
|
|
|
|
- luaL_addsize(&b, n-1); /* do not add the `\n' */
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
|
|
+static int read_number (lua_State *L, FILE *f) {
|
|
|
|
+ double d;
|
|
|
|
+ if (fscanf(f, l_s("%lf"), &d) == 1) {
|
|
|
|
+ lua_pushnumber(L, d);
|
|
|
|
+ return 1;
|
|
}
|
|
}
|
|
- luaL_pushresult(&b); /* close buffer */
|
|
|
|
- return (n > 0); /* read something? */
|
|
|
|
|
|
+ else return 0; /* read fails */
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-static void read_file (lua_State *L, FILE *f) {
|
|
|
|
- size_t len = 0;
|
|
|
|
- size_t size = LUAL_BUFFERSIZE;
|
|
|
|
- size_t oldsize = 0;
|
|
|
|
- l_char *buffer = NULL;
|
|
|
|
- for (;;) {
|
|
|
|
- l_char *newbuffer = (l_char *)l_realloc(buffer, oldsize, size);
|
|
|
|
- if (newbuffer == NULL) {
|
|
|
|
- l_free(buffer, oldsize);
|
|
|
|
- lua_error(L, l_s("not enough memory to read a file"));
|
|
|
|
- }
|
|
|
|
- buffer = newbuffer;
|
|
|
|
- len += fread(buffer+len, sizeof(l_char), size-len, f);
|
|
|
|
- if (len < size) break; /* did not read all it could */
|
|
|
|
- oldsize = size;
|
|
|
|
- size *= 2;
|
|
|
|
- }
|
|
|
|
- lua_pushlstring(L, buffer, len);
|
|
|
|
- l_free(buffer, size);
|
|
|
|
|
|
+static int test_eof (lua_State *L, FILE *f) {
|
|
|
|
+ l_charint c = fgetc(f);
|
|
|
|
+ ungetc(c, f);
|
|
|
|
+ lua_pushlstring(L, NULL, 0);
|
|
|
|
+ return (c != EOF);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
static int read_chars (lua_State *L, FILE *f, size_t n) {
|
|
static int read_chars (lua_State *L, FILE *f, size_t n) {
|
|
- if (n == 0) { /* test eof? */
|
|
|
|
- l_charint c = fgetc(f);
|
|
|
|
- ungetc(c, f);
|
|
|
|
- lua_pushlstring(L, NULL, 0);
|
|
|
|
- return (c != EOF);
|
|
|
|
- }
|
|
|
|
- else {
|
|
|
|
- l_char *buffer;
|
|
|
|
- size_t n1;
|
|
|
|
- l_char statbuff[LUAL_BUFFERSIZE];
|
|
|
|
- if (n <= LUAL_BUFFERSIZE)
|
|
|
|
- buffer = statbuff;
|
|
|
|
- else {
|
|
|
|
- buffer = (l_char *)l_malloc(n);
|
|
|
|
- if (buffer == NULL)
|
|
|
|
- lua_error(L, l_s("not enough memory to read a file"));
|
|
|
|
- }
|
|
|
|
- n1 = fread(buffer, sizeof(l_char), n, f);
|
|
|
|
- lua_pushlstring(L, buffer, n1);
|
|
|
|
- if (buffer != statbuff) l_free(buffer, n);
|
|
|
|
- return (n1 > 0 || n == 0);
|
|
|
|
- }
|
|
|
|
|
|
+ size_t rlen;
|
|
|
|
+ luaL_Buffer b;
|
|
|
|
+ luaL_buffinit(L, &b);
|
|
|
|
+ rlen = LUAL_BUFFERSIZE;
|
|
|
|
+ do {
|
|
|
|
+ l_char *p = luaL_prepbuffer(&b);
|
|
|
|
+ if (rlen > n) rlen = n;
|
|
|
|
+ rlen = fread(p, sizeof(l_char), rlen, f);
|
|
|
|
+ luaL_addsize(&b, rlen);
|
|
|
|
+ n -= rlen;
|
|
|
|
+ } while (n > 0 && rlen > 0); /* until end of count or eof */
|
|
|
|
+ luaL_pushresult(&b); /* close buffer */
|
|
|
|
+ return (n == 0 || lua_strlen(L, -1) > 0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
static int io_read (lua_State *L) {
|
|
static int io_read (lua_State *L) {
|
|
FILE *f = getopthandle(L, INFILE);
|
|
FILE *f = getopthandle(L, INFILE);
|
|
- int nargs = lua_gettop(L)-1;
|
|
|
|
|
|
+ int nargs = lua_gettop(L) - 1;
|
|
int success;
|
|
int success;
|
|
int n;
|
|
int n;
|
|
if (nargs == 0) { /* no arguments? */
|
|
if (nargs == 0) { /* no arguments? */
|
|
- success = read_line(L, f);
|
|
|
|
|
|
+ success = read_until(L, f, l_s("\n"), 1); /* read until \n (a line) */
|
|
n = 2; /* will return n-1 results */
|
|
n = 2; /* will return n-1 results */
|
|
}
|
|
}
|
|
else { /* ensure stack space for all results and for auxlib's buffer */
|
|
else { /* ensure stack space for all results and for auxlib's buffer */
|
|
luaL_checkstack(L, nargs+LUA_MINSTACK, l_s("too many arguments"));
|
|
luaL_checkstack(L, nargs+LUA_MINSTACK, l_s("too many arguments"));
|
|
success = 1;
|
|
success = 1;
|
|
for (n = 1; n<=nargs && success; n++) {
|
|
for (n = 1; n<=nargs && success; n++) {
|
|
- if (lua_type(L, n) == LUA_TNUMBER)
|
|
|
|
- success = read_chars(L, f, (size_t)lua_tonumber(L, n));
|
|
|
|
|
|
+ if (lua_type(L, n) == LUA_TNUMBER) {
|
|
|
|
+ size_t l = (size_t)lua_tonumber(L, n);
|
|
|
|
+ success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
|
|
|
|
+ }
|
|
else {
|
|
else {
|
|
const l_char *p = lua_tostring(L, n);
|
|
const l_char *p = lua_tostring(L, n);
|
|
if (!p || p[0] != l_c('*'))
|
|
if (!p || p[0] != l_c('*'))
|
|
@@ -323,15 +322,22 @@ static int io_read (lua_State *L) {
|
|
success = read_number(L, f);
|
|
success = read_number(L, f);
|
|
break;
|
|
break;
|
|
case l_c('l'): /* line */
|
|
case l_c('l'): /* line */
|
|
- success = read_line(L, f);
|
|
|
|
|
|
+ success = read_until(L, f, l_s("\n"), 1); /* read until \n */
|
|
break;
|
|
break;
|
|
case l_c('a'): /* file */
|
|
case l_c('a'): /* file */
|
|
- read_file(L, f);
|
|
|
|
|
|
+ read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */
|
|
success = 1; /* always success */
|
|
success = 1; /* always success */
|
|
break;
|
|
break;
|
|
case l_c('w'): /* word */
|
|
case l_c('w'): /* word */
|
|
- success = read_word(L, f);
|
|
|
|
|
|
+ lua_error(L, "option `*w' is deprecated");
|
|
|
|
+ break;
|
|
|
|
+ case l_c('u'): { /* read until */
|
|
|
|
+ size_t pl = lua_strlen(L, n) - 2;
|
|
|
|
+ luaL_arg_check(L, 0 < pl && pl <= LUA_MAXUNTIL, n,
|
|
|
|
+ l_s("invalid read-until length"));
|
|
|
|
+ success = read_until(L, f, p+2, (int)pl);
|
|
break;
|
|
break;
|
|
|
|
+ }
|
|
default:
|
|
default:
|
|
luaL_argerror(L, n, l_s("invalid format"));
|
|
luaL_argerror(L, n, l_s("invalid format"));
|
|
success = 0; /* to avoid warnings */
|
|
success = 0; /* to avoid warnings */
|