diff options
author | Lua Team <team@lua.org> | 1999-07-08 12:00:00 +0000 |
---|---|---|
committer | repogen <> | 1999-07-08 12:00:00 +0000 |
commit | afb67002d94ef22c14741910ba83da262a6e9338 (patch) | |
tree | b51ab3502813f590a4b115997f6fe41da43b6586 /src/lib | |
parent | 377347776f1f3d820f92151f70bec667f96d5e6b (diff) | |
download | lua-github-3.2.tar.gz |
Lua 3.23.2
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/Makefile | 4 | ||||
-rw-r--r-- | src/lib/ldblib.c | 217 | ||||
-rw-r--r-- | src/lib/linit.c | 17 | ||||
-rw-r--r-- | src/lib/liolib.c | 553 | ||||
-rw-r--r-- | src/lib/lmathlib.c | 124 | ||||
-rw-r--r-- | src/lib/lstrlib.c | 407 |
6 files changed, 867 insertions, 455 deletions
diff --git a/src/lib/Makefile b/src/lib/Makefile index 70db660f..5d8664c9 100644 --- a/src/lib/Makefile +++ b/src/lib/Makefile @@ -7,8 +7,8 @@ include $(LUA)/config # actually only used in liolib.c EXTRA_DEFS= $(POPEN) -OBJS= liolib.o lmathlib.o lstrlib.o -SRCS= liolib.c lmathlib.c lstrlib.c +OBJS= linit.o ldblib.o liolib.o lmathlib.o lstrlib.o +SRCS= linit.c ldblib.c liolib.c lmathlib.c lstrlib.c T= $(LIB)/liblualib.a diff --git a/src/lib/ldblib.c b/src/lib/ldblib.c new file mode 100644 index 00000000..388a2f2d --- /dev/null +++ b/src/lib/ldblib.c @@ -0,0 +1,217 @@ +/* +** $Id: ldblib.c,v 1.5 1999/03/04 21:17:26 roberto Exp $ +** Interface from Lua to its debug API +** See Copyright Notice in lua.h +*/ + + +#include <stdlib.h> +#include <string.h> + +#include "lauxlib.h" +#include "lua.h" +#include "luadebug.h" +#include "lualib.h" + + + +static void settabss (lua_Object t, char *i, char *v) { + lua_pushobject(t); + lua_pushstring(i); + lua_pushstring(v); + lua_settable(); +} + + +static void settabsi (lua_Object t, char *i, int v) { + lua_pushobject(t); + lua_pushstring(i); + lua_pushnumber(v); + lua_settable(); +} + + +static lua_Object getfuncinfo (lua_Object func) { + lua_Object result = lua_createtable(); + char *str; + int line; + lua_funcinfo(func, &str, &line); + if (line == -1) /* C function? */ + settabss(result, "kind", "C"); + else if (line == 0) { /* "main"? */ + settabss(result, "kind", "chunk"); + settabss(result, "source", str); + } + else { /* Lua function */ + settabss(result, "kind", "Lua"); + settabsi(result, "def_line", line); + settabss(result, "source", str); + } + if (line != 0) { /* is it not a "main"? */ + char *kind = lua_getobjname(func, &str); + if (*kind) { + settabss(result, "name", str); + settabss(result, "where", kind); + } + } + return result; +} + + +static void getstack (void) { + lua_Object func = lua_stackedfunction(luaL_check_int(1)); + if (func == LUA_NOOBJECT) /* level out of range? */ + return; + else { + lua_Object result = getfuncinfo(func); + int currline = lua_currentline(func); + if (currline > 0) + settabsi(result, "current", currline); + lua_pushobject(result); + lua_pushstring("func"); + lua_pushobject(func); + lua_settable(); /* result.func = func */ + lua_pushobject(result); + } +} + + +static void funcinfo (void) { + lua_pushobject(getfuncinfo(luaL_functionarg(1))); +} + + +static int findlocal (lua_Object func, int arg) { + lua_Object v = lua_getparam(arg); + if (lua_isnumber(v)) + return (int)lua_getnumber(v); + else { + char *name = luaL_check_string(arg); + int i = 0; + int result = -1; + char *vname; + while (lua_getlocal(func, ++i, &vname) != LUA_NOOBJECT) { + if (strcmp(name, vname) == 0) + result = i; /* keep looping to get the last var with this name */ + } + if (result == -1) + luaL_verror("no local variable `%.50s' at given level", name); + return result; + } +} + + +static void getlocal (void) { + lua_Object func = lua_stackedfunction(luaL_check_int(1)); + lua_Object val; + char *name; + if (func == LUA_NOOBJECT) /* level out of range? */ + return; /* return nil */ + else if (lua_getparam(2) != LUA_NOOBJECT) { /* 2nd argument? */ + if ((val = lua_getlocal(func, findlocal(func, 2), &name)) != LUA_NOOBJECT) { + lua_pushobject(val); + lua_pushstring(name); + } + /* else return nil */ + } + else { /* collect all locals in a table */ + lua_Object result = lua_createtable(); + int i; + for (i=1; ;i++) { + if ((val = lua_getlocal(func, i, &name)) == LUA_NOOBJECT) + break; + lua_pushobject(result); + lua_pushstring(name); + lua_pushobject(val); + lua_settable(); /* result[name] = value */ + } + lua_pushobject(result); + } +} + + +static void setlocal (void) { + lua_Object func = lua_stackedfunction(luaL_check_int(1)); + int numvar; + luaL_arg_check(func != LUA_NOOBJECT, 1, "level out of range"); + numvar = findlocal(func, 2); + lua_pushobject(luaL_nonnullarg(3)); + if (!lua_setlocal(func, numvar)) + lua_error("no such local variable"); +} + + + +static int linehook = -1; /* Lua reference to line hook function */ +static int callhook = -1; /* Lua reference to call hook function */ + + +static void dohook (int ref) { + lua_LHFunction oldlinehook = lua_setlinehook(NULL); + lua_CHFunction oldcallhook = lua_setcallhook(NULL); + lua_callfunction(lua_getref(ref)); + lua_setlinehook(oldlinehook); + lua_setcallhook(oldcallhook); +} + + +static void linef (int line) { + lua_pushnumber(line); + dohook(linehook); +} + + +static void callf (lua_Function func, char *file, int line) { + if (func != LUA_NOOBJECT) { + lua_pushobject(func); + lua_pushstring(file); + lua_pushnumber(line); + } + dohook(callhook); +} + + +static void setcallhook (void) { + lua_Object f = lua_getparam(1); + lua_unref(callhook); + if (f == LUA_NOOBJECT) { + callhook = -1; + lua_setcallhook(NULL); + } + else { + lua_pushobject(f); + callhook = lua_ref(1); + lua_setcallhook(callf); + } +} + + +static void setlinehook (void) { + lua_Object f = lua_getparam(1); + lua_unref(linehook); + if (f == LUA_NOOBJECT) { + linehook = -1; + lua_setlinehook(NULL); + } + else { + lua_pushobject(f); + linehook = lua_ref(1); + lua_setlinehook(linef); + } +} + + +static struct luaL_reg dblib[] = { + {"funcinfo", funcinfo}, + {"getlocal", getlocal}, + {"getstack", getstack}, + {"setcallhook", setcallhook}, + {"setlinehook", setlinehook}, + {"setlocal", setlocal} +}; + + +void lua_dblibopen (void) { + luaL_openlib(dblib, (sizeof(dblib)/sizeof(dblib[0]))); +} + diff --git a/src/lib/linit.c b/src/lib/linit.c new file mode 100644 index 00000000..be57aae7 --- /dev/null +++ b/src/lib/linit.c @@ -0,0 +1,17 @@ +/* +** $Id: linit.c,v 1.1 1999/01/08 16:49:32 roberto Exp $ +** Initialization of libraries for lua.c +** See Copyright Notice in lua.h +*/ + +#include "lua.h" +#include "lualib.h" + + +void lua_userinit (void) { + lua_iolibopen(); + lua_strlibopen(); + lua_mathlibopen(); + lua_dblibopen(); +} + diff --git a/src/lib/liolib.c b/src/lib/liolib.c index 15ea6587..d833cec5 100644 --- a/src/lib/liolib.c +++ b/src/lib/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 1.21 1998/06/18 17:04:28 roberto Exp $ +** $Id: liolib.c,v 1.41 1999/06/23 13:48:39 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -20,6 +20,7 @@ #ifndef OLD_ANSI #include <locale.h> #else +/* no support for locale and for strerror: fake them */ #define setlocale(a,b) 0 #define LC_ALL 0 #define LC_COLLATE 0 @@ -31,10 +32,12 @@ #endif -#define CLOSEDTAG 2 -#define IOTAG 1 +#define IOTAG 1 + +#define FIRSTARG 2 /* 1st is upvalue */ + +#define CLOSEDTAG(tag) ((tag)-1) /* assume that CLOSEDTAG = iotag-1 */ -#define FIRSTARG 3 /* 1st and 2nd are upvalues */ #define FINPUT "_INPUT" #define FOUTPUT "_OUTPUT" @@ -43,262 +46,371 @@ #ifdef POPEN FILE *popen(); int pclose(); +#define CLOSEFILE(f) {if (pclose(f) == -1) fclose(f);} #else +/* no support for popen */ #define popen(x,y) NULL /* that is, popen always fails */ -#define pclose(x) (-1) +#define CLOSEFILE(f) {fclose(f);} #endif -static int gettag (int i) -{ - return lua_getnumber(lua_getparam(i)); -} - -static void pushresult (int i) -{ +static void pushresult (int i) { if (i) lua_pushuserdata(NULL); else { lua_pushnil(); lua_pushstring(strerror(errno)); + lua_pushnumber(errno); } } -static int ishandler (lua_Object f) -{ +/* +** {====================================================== +** FILE Operations +** ======================================================= +*/ + +static int gettag (void) { + return (int)lua_getnumber(lua_getparam(IOTAG)); +} + + +static int ishandle (lua_Object f) { if (lua_isuserdata(f)) { - if (lua_tag(f) == gettag(CLOSEDTAG)) + int tag = gettag(); + if (lua_tag(f) == CLOSEDTAG(tag)) lua_error("cannot access a closed file"); - return lua_tag(f) == gettag(IOTAG); + return lua_tag(f) == tag; } else return 0; } -static FILE *getfile (char *name) -{ + +static FILE *getfilebyname (char *name) { lua_Object f = lua_getglobal(name); - if (!ishandler(f)) + if (!ishandle(f)) luaL_verror("global variable `%.50s' is not a file handle", name); return lua_getuserdata(f); } -static FILE *getfileparam (char *name, int *arg) -{ - lua_Object f = lua_getparam(*arg); - if (ishandler(f)) { +static FILE *getfile (int arg) { + lua_Object f = lua_getparam(arg); + return (ishandle(f)) ? lua_getuserdata(f) : NULL; +} + + +static FILE *getnonullfile (int arg) { + FILE *f = getfile(arg); + luaL_arg_check(f, arg, "invalid file handle"); + return f; +} + + +static FILE *getfileparam (char *name, int *arg) { + FILE *f = getfile(*arg); + if (f) { (*arg)++; - return lua_getuserdata(f); + return f; } else - return getfile(name); + return getfilebyname(name); +} + + +static void closefile (FILE *f) { + if (f != stdin && f != stdout) { + int tag = gettag(); + CLOSEFILE(f); + lua_pushusertag(f, tag); + lua_settag(CLOSEDTAG(tag)); + } +} + + +static void io_close (void) { + closefile(getnonullfile(FIRSTARG)); +} + + +static void gc_close (void) { + FILE *f = getnonullfile(FIRSTARG); + if (f != stdin && f != stdout && f != stderr) { + CLOSEFILE(f); + } } -static void closefile (char *name) -{ - FILE *f = getfile(name); - if (f == stdin || f == stdout) return; - if (pclose(f) == -1) - fclose(f); - lua_pushobject(lua_getglobal(name)); - lua_settag(gettag(CLOSEDTAG)); +static void io_open (void) { + FILE *f = fopen(luaL_check_string(FIRSTARG), luaL_check_string(FIRSTARG+1)); + if (f) lua_pushusertag(f, gettag()); + else pushresult(0); } -static void setfile (FILE *f, char *name, int tag) -{ +static void setfile (FILE *f, char *name, int tag) { lua_pushusertag(f, tag); lua_setglobal(name); } -static void setreturn (FILE *f, char *name) -{ - int tag = gettag(IOTAG); - setfile(f, name, tag); - lua_pushusertag(f, tag); +static void setreturn (FILE *f, char *name) { + if (f == NULL) + pushresult(0); + else { + int tag = gettag(); + setfile(f, name, tag); + lua_pushusertag(f, tag); + } } -static void io_readfrom (void) -{ +static void io_readfrom (void) { FILE *current; lua_Object f = lua_getparam(FIRSTARG); if (f == LUA_NOOBJECT) { - closefile(FINPUT); + closefile(getfilebyname(FINPUT)); current = stdin; } - else if (lua_tag(f) == gettag(IOTAG)) + else if (lua_tag(f) == gettag()) /* deprecated option */ current = lua_getuserdata(f); else { char *s = luaL_check_string(FIRSTARG); current = (*s == '|') ? popen(s+1, "r") : fopen(s, "r"); - if (current == NULL) { - pushresult(0); - return; - } } setreturn(current, FINPUT); } -static void io_writeto (void) -{ +static void io_writeto (void) { FILE *current; lua_Object f = lua_getparam(FIRSTARG); if (f == LUA_NOOBJECT) { - closefile(FOUTPUT); + closefile(getfilebyname(FOUTPUT)); current = stdout; } - else if (lua_tag(f) == gettag(IOTAG)) + else if (lua_tag(f) == gettag()) /* deprecated option */ current = lua_getuserdata(f); else { char *s = luaL_check_string(FIRSTARG); - current = (*s == '|') ? popen(s+1,"w") : fopen(s,"w"); - if (current == NULL) { - pushresult(0); - return; - } + current = (*s == '|') ? popen(s+1,"w") : fopen(s, "w"); } setreturn(current, FOUTPUT); } -static void io_appendto (void) -{ - char *s = luaL_check_string(FIRSTARG); - FILE *fp = fopen (s, "a"); - if (fp != NULL) - setreturn(fp, FOUTPUT); - else - pushresult(0); +static void io_appendto (void) { + FILE *current = fopen(luaL_check_string(FIRSTARG), "a"); + setreturn(current, FOUTPUT); } + +/* +** {====================================================== +** READ +** ======================================================= +*/ + + +/* +** We cannot lookahead without need, because this can lock stdin. +** This flag signals when we need to read a next char. +*/ #define NEED_OTHER (EOF-1) /* just some flag different from EOF */ -static void read_until (FILE *f, int lim) { - int l = 0; - int c; - for (c = getc(f); c != EOF && c != lim; c = getc(f)) { - luaL_addchar(c); - l++; +static int read_pattern (FILE *f, char *p) { + int inskip = 0; /* {skip} level */ + int c = NEED_OTHER; + while (*p != '\0') { + switch (*p) { + case '{': + inskip++; + p++; + continue; + case '}': + if (!inskip) lua_error("unbalanced braces in read pattern"); + inskip--; + p++; + continue; + default: { + char *ep = luaI_classend(p); /* get what is next */ + int m; /* match result */ + if (c == NEED_OTHER) c = getc(f); + m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep); + if (m) { + if (!inskip) luaL_addchar(c); + c = NEED_OTHER; + } + switch (*ep) { + case '+': /* repetition (1 or more) */ + if (!m) goto break_while; /* pattern fails? */ + /* else go through */ + case '*': /* repetition (0 or more) */ + while (m) { /* reads the same item until it fails */ + c = getc(f); + m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep); + if (m && !inskip) luaL_addchar(c); + } + /* go through to continue reading the pattern */ + case '?': /* optional */ + p = ep+1; /* continues reading the pattern */ + continue; + default: + if (!m) goto break_while; /* pattern fails? */ + p = ep; /* else continues reading the pattern */ + } + } + } + } break_while: + if (c != NEED_OTHER) ungetc(c, f); + return (*p == '\0'); +} + + +static int read_number (FILE *f) { + double d; + if (fscanf(f, "%lf", &d) == 1) { + lua_pushnumber(d); + return 1; } - if (l > 0 || c == lim) /* read anything? */ - lua_pushlstring(luaL_buffer(), l); + else return 0; /* read fails */ +} + + +#define HUNK_LINE 1024 +#define HUNK_FILE BUFSIZ + +static int read_line (FILE *f) { + /* equivalent to: return read_pattern(f, "[^\n]*{\n}"); */ + int n; + char *b; + do { + b = luaL_openspace(HUNK_LINE); + if (!fgets(b, HUNK_LINE, f)) return 0; /* read fails */ + n = strlen(b); + luaL_addsize(n); + } while (b[n-1] != '\n'); + luaL_addsize(-1); /* remove '\n' */ + return 1; +} + + +static void read_file (FILE *f) { + /* equivalent to: return read_pattern(f, ".*"); */ + int n; + do { + char *b = luaL_openspace(HUNK_FILE); + n = fread(b, sizeof(char), HUNK_FILE, f); + luaL_addsize(n); + } while (n==HUNK_FILE); } + static void io_read (void) { + static char *options[] = {"*n", "*l", "*a", ".*", "*w", NULL}; int arg = FIRSTARG; FILE *f = getfileparam(FINPUT, &arg); - char *p = luaL_opt_string(arg, NULL); - luaL_resetbuffer(); - if (p == NULL) /* default: read a line */ - read_until(f, '\n'); - else if (p[0] == '.' && p[1] == '*' && p[2] == 0) /* p = ".*" */ - read_until(f, EOF); - else { - int l = 0; /* number of chars read in buffer */ - int inskip = 0; /* to control {skips} */ - int c = NEED_OTHER; - while (*p) { - switch (*p) { - case '{': - inskip++; - p++; - continue; - case '}': - if (inskip == 0) - lua_error("unbalanced braces in read pattern"); - inskip--; - p++; - continue; - default: { - char *ep; /* get what is next */ - int m; /* match result */ - if (c == NEED_OTHER) c = getc(f); - if (c == EOF) { - luaI_singlematch(0, p, &ep); /* to set "ep" */ - m = 0; - } - else { - m = luaI_singlematch(c, p, &ep); - if (m) { - if (inskip == 0) { - luaL_addchar(c); - l++; - } - c = NEED_OTHER; - } - } - switch (*ep) { - case '*': /* repetition */ - if (!m) p = ep+1; /* else stay in (repeat) the same item */ - continue; - case '?': /* optional */ - p = ep+1; /* continues reading the pattern */ - continue; - default: - if (m) p = ep; /* continues reading the pattern */ - else - goto break_while; /* pattern fails */ - } - } - } - } break_while: - if (c >= 0) /* not EOF nor NEED_OTHER? */ - ungetc(c, f); - if (l > 0 || *p == 0) /* read something or did not fail? */ - lua_pushlstring(luaL_buffer(), l); - } + char *p = luaL_opt_string(arg++, "*l"); + do { /* repeat for each part */ + long l; + int success; + luaL_resetbuffer(); + switch (luaL_findstring(p, options)) { + case 0: /* number */ + if (!read_number(f)) return; /* read fails */ + continue; /* number is already pushed; avoid the "pushstring" */ + case 1: /* line */ + success = read_line(f); + break; + case 2: case 3: /* file */ + read_file(f); + success = 1; /* always success */ + break; + case 4: /* word */ + success = read_pattern(f, "{%s*}%S+"); + break; + default: + success = read_pattern(f, p); + } + l = luaL_getsize(); + if (!success && l==0) return; /* read fails */ + lua_pushlstring(luaL_buffer(), l); + } while ((p = luaL_opt_string(arg++, NULL)) != NULL); } +/* }====================================================== */ + -static void io_write (void) -{ +static void io_write (void) { int arg = FIRSTARG; FILE *f = getfileparam(FOUTPUT, &arg); int status = 1; char *s; long l; while ((s = luaL_opt_lstr(arg++, NULL, &l)) != NULL) - status = status && (fwrite(s, 1, l, f) == l); + status = status && ((long)fwrite(s, 1, l, f) == l); pushresult(status); } -static void io_execute (void) -{ +static void io_seek (void) { + static int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; + static char *modenames[] = {"set", "cur", "end", NULL}; + FILE *f = getnonullfile(FIRSTARG); + int op = luaL_findstring(luaL_opt_string(FIRSTARG+1, "cur"), modenames); + long offset = luaL_opt_long(FIRSTARG+2, 0); + luaL_arg_check(op != -1, FIRSTARG+1, "invalid mode"); + op = fseek(f, offset, mode[op]); + if (op) + pushresult(0); /* error */ + else + lua_pushnumber(ftell(f)); +} + + +static void io_flush (void) { + FILE *f = getfile(FIRSTARG); + luaL_arg_check(f || lua_getparam(FIRSTARG) == LUA_NOOBJECT, FIRSTARG, + "invalid file handle"); + pushresult(fflush(f) == 0); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Other O.S. Operations +** ======================================================= +*/ + +static void io_execute (void) { lua_pushnumber(system(luaL_check_string(1))); } -static void io_remove (void) -{ +static void io_remove (void) { pushresult(remove(luaL_check_string(1)) == 0); } -static void io_rename (void) -{ +static void io_rename (void) { pushresult(rename(luaL_check_string(1), luaL_check_string(2)) == 0); } -static void io_tmpname (void) -{ +static void io_tmpname (void) { lua_pushstring(tmpnam(NULL)); } -static void io_getenv (void) -{ +static void io_getenv (void) { lua_pushstring(getenv(luaL_check_string(1))); /* if NULL push nil */ } @@ -308,12 +420,11 @@ static void io_clock (void) { } -static void io_date (void) -{ - time_t t; - struct tm *tm; +static void io_date (void) { + char b[256]; char *s = luaL_opt_string(1, "%c"); - char b[BUFSIZ]; + struct tm *tm; + time_t t; time(&t); tm = localtime(&t); if (strftime(b,sizeof(b),s,tm)) lua_pushstring(b); @@ -322,8 +433,7 @@ static void io_date (void) } -static void setloc (void) -{ +static void setloc (void) { static int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME}; static char *catnames[] = {"all", "collate", "ctype", "monetary", @@ -334,115 +444,140 @@ static void setloc (void) } -static void io_exit (void) -{ +static void io_exit (void) { lua_Object o = lua_getparam(1); exit(lua_isnumber(o) ? (int)lua_getnumber(o) : 1); } +/* }====================================================== */ + + -static void io_debug (void) -{ - while (1) { +static void io_debug (void) { + for (;;) { char buffer[250]; fprintf(stderr, "lua_debug> "); - if (fgets(buffer, sizeof(buffer), stdin) == 0) return; - if (strcmp(buffer, "cont\n") == 0) return; + if (fgets(buffer, sizeof(buffer), stdin) == 0 || + strcmp(buffer, "cont\n") == 0) + return; lua_dostring(buffer); } } -static void lua_printstack (FILE *f) -{ + +#define MESSAGESIZE 150 +#define MAXMESSAGE (MESSAGESIZE*10) + + +#define MAXSRC 60 + + +static void errorfb (void) { + char buff[MAXMESSAGE]; int level = 1; /* skip level 0 (it's this function) */ lua_Object func; + sprintf(buff, "lua error: %.200s\n", lua_getstring(lua_getparam(1))); while ((func = lua_stackedfunction(level++)) != LUA_NOOBJECT) { char *name; int currentline; - char *filename; + char *chunkname; + char buffchunk[MAXSRC]; int linedefined; - lua_funcinfo(func, &filename, &linedefined); - fprintf(f, (level==2) ? "Active Stack:\n\t" : "\t"); + lua_funcinfo(func, &chunkname, &linedefined); + luaL_chunkid(buffchunk, chunkname, sizeof(buffchunk)); + if (level == 2) strcat(buff, "Active Stack:\n"); + strcat(buff, " "); + if (strlen(buff) > MAXMESSAGE-MESSAGESIZE) { + strcat(buff, "...\n"); + break; /* buffer is full */ + } switch (*lua_getobjname(func, &name)) { case 'g': - fprintf(f, "function %s", name); + sprintf(buff+strlen(buff), "function `%.50s'", name); break; case 't': - fprintf(f, "`%s' tag method", name); + sprintf(buff+strlen(buff), "`%.50s' tag method", name); break; default: { if (linedefined == 0) - fprintf(f, "main of %s", filename); + sprintf(buff+strlen(buff), "main of %.70s", buffchunk); else if (linedefined < 0) - fprintf(f, "%s", filename); + sprintf(buff+strlen(buff), "%.70s", buffchunk); else - fprintf(f, "function (%s:%d)", filename, linedefined); - filename = NULL; + sprintf(buff+strlen(buff), "function <%d:%.70s>", + linedefined, buffchunk); + chunkname = NULL; } } if ((currentline = lua_currentline(func)) > 0) - fprintf(f, " at line %d", currentline); - if (filename) - fprintf(f, " [in file %s]", filename); - fprintf(f, "\n"); + sprintf(buff+strlen(buff), " at line %d", currentline); + if (chunkname) + sprintf(buff+strlen(buff), " [%.70s]", buffchunk); + strcat(buff, "\n"); + } + func = lua_rawgetglobal("_ALERT"); + if (lua_isfunction(func)) { /* avoid error loop if _ALERT is not defined */ + lua_pushstring(buff); + lua_callfunction(func); } -} - - -static void errorfb (void) -{ - fprintf(stderr, "lua: %s\n", lua_getstring(lua_getparam(1))); - lua_printstack(stderr); } static struct luaL_reg iolib[] = { -{"setlocale", setloc}, -{"execute", io_execute}, -{"remove", io_remove}, -{"rename", io_rename}, -{"tmpname", io_tmpname}, -{"getenv", io_getenv}, -{"date", io_date}, -{"clock", io_clock}, -{"exit", io_exit}, -{"debug", io_debug}, -{"print_stack", errorfb} + {"_ERRORMESSAGE", errorfb}, + {"clock", io_clock}, + {"date", io_date}, + {"debug", io_debug}, + {"execute", io_execute}, + {"exit", io_exit}, + {"getenv", io_getenv}, + {"remove", io_remove}, + {"rename", io_rename}, + {"setlocale", setloc}, + {"tmpname", io_tmpname} }; + static struct luaL_reg iolibtag[] = { -{"readfrom", io_readfrom}, -{"writeto", io_writeto}, -{"appendto", io_appendto}, -{"read", io_read}, -{"write", io_write} + {"appendto", io_appendto}, + {"closefile", io_close}, + {"flush", io_flush}, + {"openfile", io_open}, + {"read", io_read}, + {"readfrom", io_readfrom}, + {"seek", io_seek}, + {"write", io_write}, + {"writeto", io_writeto} }; -static void openwithtags (void) -{ - int iotag = lua_newtag(); - int closedtag = lua_newtag(); + +static void openwithtags (void) { int i; + int iotag = lua_newtag(); + lua_newtag(); /* alloc CLOSEDTAG: assume that CLOSEDTAG = iotag-1 */ for (i=0; i<sizeof(iolibtag)/sizeof(iolibtag[0]); i++) { - /* put both tags as upvalues for these functions */ + /* put iotag as upvalue for these functions */ lua_pushnumber(iotag); - lua_pushnumber(closedtag); - lua_pushcclosure(iolibtag[i].func, 2); + lua_pushcclosure(iolibtag[i].func, 1); lua_setglobal(iolibtag[i].name); } + /* predefined file handles */ setfile(stdin, FINPUT, iotag); setfile(stdout, FOUTPUT, iotag); setfile(stdin, "_STDIN", iotag); setfile(stdout, "_STDOUT", iotag); setfile(stderr, "_STDERR", iotag); + /* close file when collected */ + lua_pushnumber(iotag); + lua_pushcclosure(gc_close, 1); + lua_settagmethod(iotag, "gc"); } -void lua_iolibopen (void) -{ +void lua_iolibopen (void) { + /* register lib functions */ luaL_openlib(iolib, (sizeof(iolib)/sizeof(iolib[0]))); openwithtags(); - lua_pushcfunction(errorfb); - lua_seterrormethod(); } + diff --git a/src/lib/lmathlib.c b/src/lib/lmathlib.c index bdc534f5..19cb11c2 100644 --- a/src/lib/lmathlib.c +++ b/src/lib/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.10 1998/06/19 16:14:09 roberto Exp $ +** $Id: lmathlib.c,v 1.17 1999/07/07 17:54:08 roberto Exp $ ** Lua standard mathematical library ** See Copyright Notice in lua.h */ @@ -12,107 +12,96 @@ #include "lua.h" #include "lualib.h" -#ifdef M_PI -#define PI M_PI -#else -#define PI ((double)3.14159265358979323846) -#endif +#undef PI +#define PI (3.14159265358979323846) +#define RADIANS_PER_DEGREE (PI/180.0) -#define FROMRAD(a) ((a)*(180.0/PI)) -#define TORAD(a) ((a)*(PI/180.0)) -static void math_abs (void) -{ - double d = luaL_check_number(1); - if (d < 0) d = -d; - lua_pushnumber(d); +/* +** If you want Lua to operate in radians (instead of degrees), +** define RADIANS +*/ +#ifdef RADIANS +#define FROMRAD(a) (a) +#define TORAD(a) (a) +#else +#define FROMRAD(a) ((a)/RADIANS_PER_DEGREE) +#define TORAD(a) ((a)*RADIANS_PER_DEGREE) +#endif + + +static void math_abs (void) { + lua_pushnumber(fabs(luaL_check_number(1))); } -static void math_sin (void) -{ +static void math_sin (void) { lua_pushnumber(sin(TORAD(luaL_check_number(1)))); } -static void math_cos (void) -{ +static void math_cos (void) { lua_pushnumber(cos(TORAD(luaL_check_number(1)))); } -static void math_tan (void) -{ +static void math_tan (void) { lua_pushnumber(tan(TORAD(luaL_check_number(1)))); } -static void math_asin (void) -{ +static void math_asin (void) { lua_pushnumber(FROMRAD(asin(luaL_check_number(1)))); } -static void math_acos (void) -{ +static void math_acos (void) { lua_pushnumber(FROMRAD(acos(luaL_check_number(1)))); } -static void math_atan (void) -{ +static void math_atan (void) { lua_pushnumber(FROMRAD(atan(luaL_check_number(1)))); } -static void math_atan2 (void) -{ +static void math_atan2 (void) { lua_pushnumber(FROMRAD(atan2(luaL_check_number(1), luaL_check_number(2)))); } -static void math_ceil (void) -{ +static void math_ceil (void) { lua_pushnumber(ceil(luaL_check_number(1))); } -static void math_floor (void) -{ +static void math_floor (void) { lua_pushnumber(floor(luaL_check_number(1))); } -static void math_mod (void) -{ +static void math_mod (void) { lua_pushnumber(fmod(luaL_check_number(1), luaL_check_number(2))); } -static void math_sqrt (void) -{ +static void math_sqrt (void) { lua_pushnumber(sqrt(luaL_check_number(1))); } -static void math_pow (void) -{ +static void math_pow (void) { lua_pushnumber(pow(luaL_check_number(1), luaL_check_number(2))); } -static void math_log (void) -{ +static void math_log (void) { lua_pushnumber(log(luaL_check_number(1))); } -static void math_log10 (void) -{ +static void math_log10 (void) { lua_pushnumber(log10(luaL_check_number(1))); } -static void math_exp (void) -{ +static void math_exp (void) { lua_pushnumber(exp(luaL_check_number(1))); } -static void math_deg (void) -{ - lua_pushnumber(luaL_check_number(1)*(180.0/PI)); +static void math_deg (void) { + lua_pushnumber(luaL_check_number(1)/RADIANS_PER_DEGREE); } -static void math_rad (void) -{ - lua_pushnumber(luaL_check_number(1)*(PI/180.0)); +static void math_rad (void) { + lua_pushnumber(luaL_check_number(1)*RADIANS_PER_DEGREE); } static void math_frexp (void) { @@ -122,13 +111,12 @@ static void math_frexp (void) { } static void math_ldexp (void) { - lua_pushnumber(ldexp(luaL_check_number(1), luaL_check_number(2))); + lua_pushnumber(ldexp(luaL_check_number(1), luaL_check_int(2))); } -static void math_min (void) -{ +static void math_min (void) { int i = 1; double dmin = luaL_check_number(i); while (lua_getparam(++i) != LUA_NOOBJECT) { @@ -140,8 +128,7 @@ static void math_min (void) } -static void math_max (void) -{ +static void math_max (void) { int i = 1; double dmax = luaL_check_number(i); while (lua_getparam(++i) != LUA_NOOBJECT) { @@ -153,22 +140,27 @@ static void math_max (void) } -static void math_random (void) -{ - /* the '%' is needed because on some systems (SunOS!) "rand()" may */ - /* return a value bigger than RAND_MAX... */ +static void math_random (void) { + /* the '%' avoids the (rare) case of r==1, and is needed also because on + some systems (SunOS!) "rand()" may return a value bigger than RAND_MAX */ double r = (double)(rand()%RAND_MAX) / (double)RAND_MAX; - double l = luaL_opt_number(1, 0); + int l = luaL_opt_int(1, 0); if (l == 0) lua_pushnumber(r); - else - lua_pushnumber((int)(r*l)+1); + else { + int u = luaL_opt_int(2, 0); + if (u == 0) { + u = l; + l = 1; + } + luaL_arg_check(l<=u, 1, "interval is empty"); + lua_pushnumber((int)(r*(u-l+1))+l); + } } -static void math_randomseed (void) -{ - srand(luaL_check_number(1)); +static void math_randomseed (void) { + srand(luaL_check_int(1)); } @@ -201,10 +193,8 @@ static struct luaL_reg mathlib[] = { /* ** Open math library */ -void lua_mathlibopen (void) -{ +void lua_mathlibopen (void) { luaL_openlib(mathlib, (sizeof(mathlib)/sizeof(mathlib[0]))); - lua_pushstring("deg"); lua_setglobal("_TRIGMODE"); lua_pushcfunction(math_pow); lua_pushnumber(0); /* to get its tag */ lua_settagmethod(lua_tag(lua_pop()), "pow"); diff --git a/src/lib/lstrlib.c b/src/lib/lstrlib.c index dc79cc7e..b47e21d3 100644 --- a/src/lib/lstrlib.c +++ b/src/lib/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.18 1998/07/01 14:21:57 roberto Exp $ +** $Id: lstrlib.c,v 1.32 1999/06/17 17:04:03 roberto Exp $ ** Standard library for strings and pattern-matching ** See Copyright Notice in lua.h */ @@ -32,33 +32,31 @@ static void str_len (void) } -static void closeandpush (void) -{ +static void closeandpush (void) { lua_pushlstring(luaL_buffer(), luaL_getsize()); } -static long posrelat (long pos, long len) -{ +static long posrelat (long pos, long len) { /* relative string position: negative means back from end */ return (pos>=0) ? pos : len+pos+1; } -static void str_sub (void) -{ +static void str_sub (void) { long l; char *s = luaL_check_lstr(1, &l); - long start = posrelat(luaL_check_number(2), l); - long end = posrelat(luaL_opt_number(3, -1), l); - if (1 <= start && start <= end && end <= l) + long start = posrelat(luaL_check_long(2), l); + long end = posrelat(luaL_opt_long(3, -1), l); + if (start < 1) start = 1; + if (end > l) end = l; + if (start <= end) lua_pushlstring(s+start-1, end-start+1); else lua_pushstring(""); } -static void str_lower (void) -{ +static void str_lower (void) { long l; int i; char *s = luaL_check_lstr(1, &l); @@ -69,8 +67,7 @@ static void str_lower (void) } -static void str_upper (void) -{ +static void str_upper (void) { long l; int i; char *s = luaL_check_lstr(1, &l); @@ -84,7 +81,7 @@ static void str_rep (void) { long l; char *s = luaL_check_lstr(1, &l); - int n = (int)luaL_check_number(2); + int n = luaL_check_int(2); luaL_resetbuffer(); while (n-- > 0) addnchar(s, l); @@ -92,38 +89,42 @@ static void str_rep (void) } -static void str_byte (void) -{ +static void str_byte (void) { long l; char *s = luaL_check_lstr(1, &l); - long pos = posrelat(luaL_opt_number(2, 1), l); + long pos = posrelat(luaL_opt_long(2, 1), l); luaL_arg_check(0<pos && pos<=l, 2, "out of range"); lua_pushnumber((unsigned char)s[pos-1]); } + static void str_char (void) { int i = 0; luaL_resetbuffer(); while (lua_getparam(++i) != LUA_NOOBJECT) { double c = luaL_check_number(i); luaL_arg_check((unsigned char)c == c, i, "invalid value"); - luaL_addchar((int)c); + luaL_addchar((unsigned char)c); } closeandpush(); } + /* -** ======================================================= +** {====================================================== ** PATTERN MATCHING ** ======================================================= */ -#define MAX_CAPT 9 +#ifndef MAX_CAPT +#define MAX_CAPT 32 /* arbitrary limit */ +#endif + struct Capture { - int level; /* total number of captures (finished or unfinished) */ char *src_end; /* end ('\0') of source string */ + int level; /* total number of captures (finished or unfinished) */ struct { char *init; int len; /* -1 signals unfinished capture */ @@ -132,19 +133,20 @@ struct Capture { #define ESC '%' -#define SPECIALS "^$*?.([%-" +#define SPECIALS "^$*+?.([%-" -static void push_captures (struct Capture *cap) -{ +static void push_captures (struct Capture *cap) { int i; - for (i=0; i<cap->level; i++) - lua_pushlstring(cap->capture[i].init, cap->capture[i].len); + for (i=0; i<cap->level; i++) { + int l = cap->capture[i].len; + if (l == -1) lua_error("unfinished capture"); + lua_pushlstring(cap->capture[i].init, l); + } } -static int check_cap (int l, struct Capture *cap) -{ +static int check_cap (int l, struct Capture *cap) { l -= '1'; if (!(0 <= l && l < cap->level && cap->capture[l].len != -1)) lua_error("invalid capture index"); @@ -152,8 +154,7 @@ static int check_cap (int l, struct Capture *cap) } -static int capture_to_close (struct Capture *cap) -{ +static int capture_to_close (struct Capture *cap) { int level = cap->level; for (level--; level>=0; level--) if (cap->capture[level].len == -1) return level; @@ -162,14 +163,25 @@ static int capture_to_close (struct Capture *cap) } -static char *bracket_end (char *p) -{ - return (*p == 0) ? NULL : strchr((*p=='^') ? p+2 : p+1, ']'); +char *luaI_classend (char *p) { + switch (*p++) { + case ESC: + if (*p == '\0') + luaL_verror("incorrect pattern (ends with `%c')", ESC); + return p+1; + case '[': + if (*p == '^') p++; + if (*p == ']') p++; + p = strchr(p, ']'); + if (!p) lua_error("incorrect pattern (missing `]')"); + return p+1; + default: + return p; + } } -static int matchclass (int c, int cl) -{ +static int matchclass (int c, int cl) { int res; switch (tolower(cl)) { case 'a' : res = isalpha(c); break; @@ -180,57 +192,63 @@ static int matchclass (int c, int cl) case 's' : res = isspace(c); break; case 'u' : res = isupper(c); break; case 'w' : res = isalnum(c); break; + case 'x' : res = isxdigit(c); break; case 'z' : res = (c == '\0'); break; default: return (cl == c); } - return (islower((unsigned char)cl) ? res : !res); + return (islower(cl) ? res : !res); } -int luaI_singlematch (int c, char *p, char **ep) -{ + +static int matchbracketclass (int c, char *p, char *end) { + int sig = 1; + if (*(p+1) == '^') { + sig = 0; + p++; /* skip the '^' */ + } + while (++p < end) { + if (*p == ESC) { + p++; + if ((p < end) && matchclass(c, (unsigned char)*p)) + return sig; + } + else if ((*(p+1) == '-') && (p+2 < end)) { + p+=2; + if ((int)(unsigned char)*(p-2) <= c && c <= (int)(unsigned char)*p) + return sig; + } + else if ((unsigned char)*p == c) return sig; + } + return !sig; +} + + + +int luaI_singlematch (int c, char *p, char *ep) { switch (*p) { case '.': /* matches any char */ - *ep = p+1; return 1; - case '\0': /* end of pattern; matches nothing */ - *ep = p; - return 0; case ESC: - if (*(++p) == '\0') - luaL_verror("incorrect pattern (ends with `%c')", ESC); - *ep = p+1; - return matchclass(c, (unsigned char)*p); - case '[': { - char *end = bracket_end(p+1); - int sig = *(p+1) == '^' ? (p++, 0) : 1; - if (end == NULL) lua_error("incorrect pattern (missing `]')"); - *ep = end+1; - while (++p < end) { - if (*p == ESC) { - if (((p+1) < end) && matchclass(c, (unsigned char)*++p)) - return sig; - } - else if ((*(p+1) == '-') && (p+2 < end)) { - p+=2; - if ((unsigned char)*(p-2) <= c && c <= (unsigned char)*p) - return sig; - } - else if ((unsigned char)*p == c) return sig; - } - return !sig; - } + return matchclass(c, (unsigned char)*(p+1)); + case '[': + return matchbracketclass(c, p, ep-1); default: - *ep = p+1; return ((unsigned char)*p == c); } } -static char *matchbalance (char *s, int b, int e, struct Capture *cap) -{ - if (*s != b) return NULL; +static char *match (char *s, char *p, struct Capture *cap); + + +static char *matchbalance (char *s, char *p, struct Capture *cap) { + if (*p == 0 || *(p+1) == 0) + lua_error("unbalanced pattern"); + if (*s != *p) return NULL; else { + int b = *p; + int e = *(p+1); int cont = 1; while (++s < cap->src_end) { if (*s == e) { @@ -243,101 +261,120 @@ static char *matchbalance (char *s, int b, int e, struct Capture *cap) } -static char *matchitem (char *s, char *p, struct Capture *cap, char **ep) -{ - if (*p == ESC) { - p++; - if (isdigit((unsigned char)*p)) { /* capture */ - int l = check_cap(*p, cap); - int len = cap->capture[l].len; - *ep = p+1; - if (cap->src_end-s >= len && memcmp(cap->capture[l].init, s, len) == 0) - return s+len; - else return NULL; - } - else if (*p == 'b') { /* balanced string */ - p++; - if (*p == 0 || *(p+1) == 0) - lua_error("unbalanced pattern"); - *ep = p+2; - return matchbalance(s, *p, *(p+1), cap); - } - else p--; /* and go through */ +static char *max_expand (char *s, char *p, char *ep, struct Capture *cap) { + int i = 0; /* counts maximum expand for item */ + while ((s+i)<cap->src_end && luaI_singlematch((unsigned char)*(s+i), p, ep)) + i++; + /* keeps trying to match mith the maximum repetitions */ + while (i>=0) { + char *res = match((s+i), ep+1, cap); + if (res) return res; + i--; /* else didn't match; reduce 1 repetition to try again */ } - /* "luaI_singlematch" sets "ep" (so must be called even when *s == 0) */ - return (luaI_singlematch((unsigned char)*s, p, ep) && s<cap->src_end) ? - s+1 : NULL; + return NULL; } -static char *match (char *s, char *p, struct Capture *cap) -{ +static char *min_expand (char *s, char *p, char *ep, struct Capture *cap) { + for (;;) { + char *res = match(s, ep+1, cap); + if (res != NULL) + return res; + else if (s<cap->src_end && luaI_singlematch((unsigned char)*s, p, ep)) + s++; /* try with one more repetition */ + else return NULL; + } +} + + +static char *start_capt (char *s, char *p, struct Capture *cap) { + char *res; + int level = cap->level; + if (level >= MAX_CAPT) lua_error("too many captures"); + cap->capture[level].init = s; + cap->capture[level].len = -1; + cap->level = level+1; + if ((res=match(s, p+1, cap)) == NULL) /* match failed? */ + cap->level--; /* undo capture */ + return res; +} + + +static char *end_capt (char *s, char *p, struct Capture *cap) { + int l = capture_to_close(cap); + char *res; + cap->capture[l].len = s - cap->capture[l].init; /* close capture */ + if ((res = match(s, p+1, cap)) == NULL) /* match failed? */ + cap->capture[l].len = -1; /* undo capture */ + return res; +} + + +static char *match_capture (char *s, int level, struct Capture *cap) { + int l = check_cap(level, cap); + int len = cap->capture[l].len; + if (cap->src_end-s >= len && + memcmp(cap->capture[l].init, s, len) == 0) + return s+len; + else return NULL; +} + + +static char *match (char *s, char *p, struct Capture *cap) { init: /* using goto's to optimize tail recursion */ switch (*p) { - case '(': { /* start capture */ - char *res; - if (cap->level >= MAX_CAPT) lua_error("too many captures"); - cap->capture[cap->level].init = s; - cap->capture[cap->level].len = -1; - cap->level++; - if ((res=match(s, p+1, cap)) == NULL) /* match failed? */ - cap->level--; /* undo capture */ - return res; - } - case ')': { /* end capture */ - int l = capture_to_close(cap); - char *res; - cap->capture[l].len = s - cap->capture[l].init; /* close capture */ - if ((res = match(s, p+1, cap)) == NULL) /* match failed? */ - cap->capture[l].len = -1; /* undo capture */ - return res; - } - case '\0': case '$': /* (possibly) end of pattern */ - if (*p == 0 || (*(p+1) == 0 && s == cap->src_end)) - return s; - /* else go through */ - default: { /* it is a pattern item */ - char *ep; /* get what is next */ - char *s1 = matchitem(s, p, cap, &ep); + case '(': /* start capture */ + return start_capt(s, p, cap); + case ')': /* end capture */ + return end_capt(s, p, cap); + case ESC: /* may be %[0-9] or %b */ + if (isdigit((unsigned char)(*(p+1)))) { /* capture? */ + s = match_capture(s, *(p+1), cap); + if (s == NULL) return NULL; + p+=2; goto init; /* else return match(p+2, s, cap) */ + } + else if (*(p+1) == 'b') { /* balanced string? */ + s = matchbalance(s, p+2, cap); + if (s == NULL) return NULL; + p+=4; goto init; /* else return match(p+4, s, cap); */ + } + else goto dflt; /* case default */ + case '\0': /* end of pattern */ + return s; /* match succeeded */ + case '$': + if (*(p+1) == '\0') /* is the '$' the last char in pattern? */ + return (s == cap->src_end) ? s : NULL; /* check end of string */ + else goto dflt; + default: dflt: { /* it is a pattern item */ + char *ep = luaI_classend(p); /* points to what is next */ + int m = s<cap->src_end && luaI_singlematch((unsigned char)*s, p, ep); switch (*ep) { - case '*': { /* repetition */ - char *res; - if (s1 && s1>s && ((res=match(s1, p, cap)) != NULL)) - return res; - p=ep+1; goto init; /* else return match(s, ep+1, cap); */ - } case '?': { /* optional */ char *res; - if (s1 && ((res=match(s1, ep+1, cap)) != NULL)) + if (m && ((res=match(s+1, ep+1, cap)) != NULL)) return res; p=ep+1; goto init; /* else return match(s, ep+1, cap); */ } - case '-': { /* repetition */ - char *res; - if ((res = match(s, ep+1, cap)) != NULL) - return res; - else if (s1 && s1>s) { - s = s1; - goto init; /* return match(s1, p, cap); */ - } - else - return NULL; - } + case '*': /* 0 or more repetitions */ + return max_expand(s, p, ep, cap); + case '+': /* 1 or more repetitions */ + return (m ? max_expand(s+1, p, ep, cap) : NULL); + case '-': /* 0 or more repetitions (minimum) */ + return min_expand(s, p, ep, cap); default: - if (s1) { s=s1; p=ep; goto init; } /* return match(s1, ep, cap); */ - else return NULL; + if (!m) return NULL; + s++; p=ep; goto init; /* else return match(s+1, ep, cap); */ } } } } -static void str_find (void) -{ +static void str_find (void) { long l; char *s = luaL_check_lstr(1, &l); char *p = luaL_check_string(2); - long init = posrelat(luaL_opt_number(3, 1), l) - 1; + long init = posrelat(luaL_opt_long(3, 1), l) - 1; struct Capture cap; luaL_arg_check(0 <= init && init <= l, 3, "out of range"); if (lua_getparam(4) != LUA_NOOBJECT || @@ -368,8 +405,7 @@ static void str_find (void) } -static void add_s (lua_Object newp, struct Capture *cap) -{ +static void add_s (lua_Object newp, struct Capture *cap) { if (lua_isstring(newp)) { char *news = lua_getstring(newp); int l = lua_strlen(newp); @@ -411,13 +447,12 @@ static void add_s (lua_Object newp, struct Capture *cap) } -static void str_gsub (void) -{ +static void str_gsub (void) { long srcl; char *src = luaL_check_lstr(1, &srcl); char *p = luaL_check_string(2); lua_Object newp = lua_getparam(3); - int max_s = (int)luaL_opt_number(4, srcl+1); + int max_s = luaL_opt_int(4, srcl+1); int anchor = (*p == '^') ? (p++, 1) : 0; int n = 0; struct Capture cap; @@ -445,26 +480,33 @@ static void str_gsub (void) lua_pushnumber(n); /* number of substitutions */ } +/* }====================================================== */ -static void luaI_addquoted (char *s) -{ + +static void luaI_addquoted (int arg) { + long l; + char *s = luaL_check_lstr(arg, &l); luaL_addchar('"'); - for (; *s; s++) { - if (strchr("\"\\\n", *s)) - luaL_addchar('\\'); - luaL_addchar(*s); + while (l--) { + switch (*s) { + case '"': case '\\': case '\n': + luaL_addchar('\\'); + luaL_addchar(*s); + break; + case '\0': addnchar("\\000", 4); break; + default: luaL_addchar(*s); + } + s++; } luaL_addchar('"'); } -#define MAX_FORMAT 200 +/* maximum size of each format specification (such as '%-099.99d') */ +#define MAX_FORMAT 20 /* arbitrary limit */ -static void str_format (void) -{ +static void str_format (void) { int arg = 1; char *strfrmt = luaL_check_string(arg); - struct Capture cap; - cap.src_end = strfrmt+strlen(strfrmt)+1; luaL_resetbuffer(); while (*strfrmt) { if (*strfrmt != '%') @@ -472,34 +514,28 @@ static void str_format (void) else if (*++strfrmt == '%') luaL_addchar(*strfrmt++); /* %% */ else { /* format item */ - char form[MAX_FORMAT]; /* store the format ('%...') */ - char *buff; + struct Capture cap; + char form[MAX_FORMAT]; /* to store the format ('%...') */ + char *buff; /* to store the formatted item */ char *initf = strfrmt; form[0] = '%'; - cap.level = 0; - if (isdigit((unsigned char)initf[0]) && initf[1] == '$') { - arg = initf[0] - '0'; + if (isdigit((unsigned char)*initf) && *(initf+1) == '$') { + arg = *initf - '0'; initf += 2; /* skip the 'n$' */ } arg++; + cap.src_end = strfrmt+strlen(strfrmt)+1; + cap.level = 0; strfrmt = match(initf, "[-+ #0]*(%d*)%.?(%d*)", &cap); - if (cap.capture[0].len > 2 || cap.capture[1].len > 2) /* < 100? */ + if (cap.capture[0].len > 2 || cap.capture[1].len > 2 || /* < 100? */ + strfrmt-initf > MAX_FORMAT-2) lua_error("invalid format (width or precision too long)"); strncpy(form+1, initf, strfrmt-initf+1); /* +1 to include conversion */ form[strfrmt-initf+2] = 0; - buff = luaL_openspace(1000); /* to store the formatted value */ + buff = luaL_openspace(512); /* 512 > size of format('%99.99f', -1e308) */ switch (*strfrmt++) { - case 'q': - luaI_addquoted(luaL_check_string(arg)); - continue; - case 's': { - char *s = luaL_check_string(arg); - buff = luaL_openspace(strlen(s)); - sprintf(buff, form, s); - break; - } case 'c': case 'd': case 'i': - sprintf(buff, form, (int)luaL_check_number(arg)); + sprintf(buff, form, luaL_check_int(arg)); break; case 'o': case 'u': case 'x': case 'X': sprintf(buff, form, (unsigned int)luaL_check_number(arg)); @@ -507,6 +543,23 @@ static void str_format (void) case 'e': case 'E': case 'f': case 'g': case 'G': sprintf(buff, form, luaL_check_number(arg)); break; + case 'q': + luaI_addquoted(arg); + continue; /* skip the "addsize" at the end */ + case 's': { + long l; + char *s = luaL_check_lstr(arg, &l); + if (cap.capture[1].len == 0 && l >= 100) { + /* no precision and string is too big to be formatted; + keep original string */ + addnchar(s, l); + continue; /* skip the "addsize" at the end */ + } + else { + sprintf(buff, form, s); + break; + } + } default: /* also treat cases 'pnLlh' */ lua_error("invalid option in `format'"); } @@ -524,7 +577,7 @@ static struct luaL_reg strlib[] = { {"strupper", str_upper}, {"strchar", str_char}, {"strrep", str_rep}, -{"ascii", str_byte}, /* for compatibility */ +{"ascii", str_byte}, /* for compatibility with 3.0 and earlier */ {"strbyte", str_byte}, {"format", str_format}, {"strfind", str_find}, |