diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/Makefile | 6 | ||||
-rw-r--r-- | src/lib/README | 6 | ||||
-rw-r--r-- | src/lib/lauxlib.c | 216 | ||||
-rw-r--r-- | src/lib/lbaselib.c | 651 | ||||
-rw-r--r-- | src/lib/ldblib.c | 277 | ||||
-rw-r--r-- | src/lib/linit.c | 17 | ||||
-rw-r--r-- | src/lib/liolib.c | 729 | ||||
-rw-r--r-- | src/lib/lmathlib.c | 193 | ||||
-rw-r--r-- | src/lib/lstrlib.c | 503 |
9 files changed, 1809 insertions, 789 deletions
diff --git a/src/lib/Makefile b/src/lib/Makefile index 5d8664c9..081b8867 100644 --- a/src/lib/Makefile +++ b/src/lib/Makefile @@ -1,4 +1,4 @@ -# makefile for lua standard library +# makefile for Lua standard library LUA= ../.. @@ -7,8 +7,8 @@ include $(LUA)/config # actually only used in liolib.c EXTRA_DEFS= $(POPEN) -OBJS= linit.o ldblib.o liolib.o lmathlib.o lstrlib.o -SRCS= linit.c ldblib.c liolib.c lmathlib.c lstrlib.c +OBJS= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o lstrlib.o +SRCS= lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c lstrlib.c T= $(LIB)/liblualib.a diff --git a/src/lib/README b/src/lib/README index e8e599c8..c04a12e2 100644 --- a/src/lib/README +++ b/src/lib/README @@ -1,4 +1,6 @@ This is the standard Lua library. It is implemented entirely on top of the official Lua API as declared in lua.h, -using src/lauxlib.c, which contains several useful functions. -The code can be read as an example of how to export C functions to Lua. +using lauxlib.c, which contains several useful functions for writing libraries. +We encourage developers to use lauxlib.c in their own libraries. +The code of the standard library can be read as an example of how to export +C functions to Lua. diff --git a/src/lib/lauxlib.c b/src/lib/lauxlib.c new file mode 100644 index 00000000..4bdaeeff --- /dev/null +++ b/src/lib/lauxlib.c @@ -0,0 +1,216 @@ +/* +** $Id: lauxlib.c,v 1.43 2000/10/30 13:07:48 roberto Exp $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +/* This file uses only the official API of Lua. +** Any function declared here could be written as an application function. +** With care, these functions can be used by other libraries. +*/ + +#include "lua.h" + +#include "lauxlib.h" +#include "luadebug.h" + + + +LUALIB_API int luaL_findstring (const char *name, const char *const list[]) { + int i; + for (i=0; list[i]; i++) + if (strcmp(list[i], name) == 0) + return i; + return -1; /* name not found */ +} + +LUALIB_API void luaL_argerror (lua_State *L, int narg, const char *extramsg) { + lua_Debug ar; + lua_getstack(L, 0, &ar); + lua_getinfo(L, "n", &ar); + if (ar.name == NULL) + ar.name = "?"; + luaL_verror(L, "bad argument #%d to `%.50s' (%.100s)", + narg, ar.name, extramsg); +} + + +static void type_error (lua_State *L, int narg, int t) { + char buff[50]; + sprintf(buff, "%.8s expected, got %.8s", lua_typename(L, t), + lua_typename(L, lua_type(L, narg))); + luaL_argerror(L, narg, buff); +} + + +LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) { + if (space > lua_stackspace(L)) + luaL_verror(L, "stack overflow (%.30s)", mes); +} + + +LUALIB_API void luaL_checktype(lua_State *L, int narg, int t) { + if (lua_type(L, narg) != t) + type_error(L, narg, t); +} + + +LUALIB_API void luaL_checkany (lua_State *L, int narg) { + if (lua_type(L, narg) == LUA_TNONE) + luaL_argerror(L, narg, "value expected"); +} + + +LUALIB_API const char *luaL_check_lstr (lua_State *L, int narg, size_t *len) { + const char *s = lua_tostring(L, narg); + if (!s) type_error(L, narg, LUA_TSTRING); + if (len) *len = lua_strlen(L, narg); + return s; +} + + +LUALIB_API const char *luaL_opt_lstr (lua_State *L, int narg, const char *def, size_t *len) { + if (lua_isnull(L, narg)) { + if (len) + *len = (def ? strlen(def) : 0); + return def; + } + else return luaL_check_lstr(L, narg, len); +} + + +LUALIB_API double luaL_check_number (lua_State *L, int narg) { + double d = lua_tonumber(L, narg); + if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ + type_error(L, narg, LUA_TNUMBER); + return d; +} + + +LUALIB_API double luaL_opt_number (lua_State *L, int narg, double def) { + if (lua_isnull(L, narg)) return def; + else return luaL_check_number(L, narg); +} + + +LUALIB_API void luaL_openlib (lua_State *L, const struct luaL_reg *l, int n) { + int i; + for (i=0; i<n; i++) + lua_register(L, l[i].name, l[i].func); +} + + +LUALIB_API void luaL_verror (lua_State *L, const char *fmt, ...) { + char buff[500]; + va_list argp; + va_start(argp, fmt); + vsprintf(buff, fmt, argp); + va_end(argp); + lua_error(L, buff); +} + + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + + +#define buffempty(B) ((B)->p == (B)->buffer) +#define bufflen(B) ((B)->p - (B)->buffer) +#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B))) + +#define LIMIT (LUA_MINSTACK/2) + + +static int emptybuffer (luaL_Buffer *B) { + size_t l = bufflen(B); + if (l == 0) return 0; /* put nothing on stack */ + else { + lua_pushlstring(B->L, B->buffer, l); + B->p = B->buffer; + B->level++; + return 1; + } +} + + +static void adjuststack (luaL_Buffer *B) { + if (B->level > 1) { + lua_State *L = B->L; + int toget = 1; /* number of levels to concat */ + size_t toplen = lua_strlen(L, -1); + do { + size_t l = lua_strlen(L, -(toget+1)); + if (B->level - toget + 1 >= LIMIT || toplen > l) { + toplen += l; + toget++; + } + else break; + } while (toget < B->level); + if (toget >= 2) { + lua_concat(L, toget); + B->level = B->level - toget + 1; + } + } +} + + +LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) { + if (emptybuffer(B)) + adjuststack(B); + return B->buffer; +} + + +LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { + while (l--) + luaL_putchar(B, *s++); +} + + +LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { + luaL_addlstring(B, s, strlen(s)); +} + + +LUALIB_API void luaL_pushresult (luaL_Buffer *B) { + emptybuffer(B); + if (B->level == 0) + lua_pushlstring(B->L, NULL, 0); + else if (B->level > 1) + lua_concat(B->L, B->level); + B->level = 1; +} + + +LUALIB_API void luaL_addvalue (luaL_Buffer *B) { + lua_State *L = B->L; + size_t vl = lua_strlen(L, -1); + if (vl <= bufffree(B)) { /* fit into buffer? */ + memcpy(B->p, lua_tostring(L, -1), vl); /* put it there */ + B->p += vl; + lua_pop(L, 1); /* remove from stack */ + } + else { + if (emptybuffer(B)) + lua_insert(L, -2); /* put buffer before new value */ + B->level++; /* add new value into B stack */ + adjuststack(B); + } +} + + +LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { + B->L = L; + B->p = B->buffer; + B->level = 0; +} + +/* }====================================================== */ diff --git a/src/lib/lbaselib.c b/src/lib/lbaselib.c new file mode 100644 index 00000000..1ff475f9 --- /dev/null +++ b/src/lib/lbaselib.c @@ -0,0 +1,651 @@ +/* +** $Id: lbaselib.c,v 1.17 2000/11/06 13:45:18 roberto Exp $ +** Basic library +** See Copyright Notice in lua.h +*/ + + + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "lua.h" + +#include "lauxlib.h" +#include "luadebug.h" +#include "lualib.h" + + + +/* +** If your system does not support `stderr', redefine this function, or +** redefine _ERRORMESSAGE so that it won't need _ALERT. +*/ +static int luaB__ALERT (lua_State *L) { + fputs(luaL_check_string(L, 1), stderr); + return 0; +} + + +/* +** Basic implementation of _ERRORMESSAGE. +** The library `liolib' redefines _ERRORMESSAGE for better error information. +*/ +static int luaB__ERRORMESSAGE (lua_State *L) { + luaL_checktype(L, 1, LUA_TSTRING); + lua_getglobal(L, LUA_ALERT); + if (lua_isfunction(L, -1)) { /* avoid error loop if _ALERT is not defined */ + lua_Debug ar; + lua_pushstring(L, "error: "); + lua_pushvalue(L, 1); + if (lua_getstack(L, 1, &ar)) { + lua_getinfo(L, "Sl", &ar); + if (ar.source && ar.currentline > 0) { + char buff[100]; + sprintf(buff, "\n <%.70s: line %d>", ar.short_src, ar.currentline); + lua_pushstring(L, buff); + lua_concat(L, 2); + } + } + lua_pushstring(L, "\n"); + lua_concat(L, 3); + lua_rawcall(L, 1, 0); + } + return 0; +} + + +/* +** If your system does not support `stdout', you can just remove this function. +** If you need, you can define your own `print' function, following this +** model but changing `fputs' to put the strings at a proper place +** (a console window or a log file, for instance). +*/ +static int luaB_print (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int i; + lua_getglobal(L, "tostring"); + for (i=1; i<=n; i++) { + const char *s; + lua_pushvalue(L, -1); /* function to be called */ + lua_pushvalue(L, i); /* value to print */ + lua_rawcall(L, 1, 1); + s = lua_tostring(L, -1); /* get result */ + if (s == NULL) + lua_error(L, "`tostring' must return a string to `print'"); + if (i>1) fputs("\t", stdout); + fputs(s, stdout); + lua_pop(L, 1); /* pop result */ + } + fputs("\n", stdout); + return 0; +} + + +static int luaB_tonumber (lua_State *L) { + int base = luaL_opt_int(L, 2, 10); + if (base == 10) { /* standard conversion */ + luaL_checkany(L, 1); + if (lua_isnumber(L, 1)) { + lua_pushnumber(L, lua_tonumber(L, 1)); + return 1; + } + } + else { + const char *s1 = luaL_check_string(L, 1); + char *s2; + unsigned long n; + luaL_arg_check(L, 2 <= base && base <= 36, 2, "base out of range"); + n = strtoul(s1, &s2, base); + if (s1 != s2) { /* at least one valid digit? */ + while (isspace((unsigned char)*s2)) s2++; /* skip trailing spaces */ + if (*s2 == '\0') { /* no invalid trailing characters? */ + lua_pushnumber(L, n); + return 1; + } + } + } + lua_pushnil(L); /* else not a number */ + return 1; +} + + +static int luaB_error (lua_State *L) { + lua_error(L, luaL_opt_string(L, 1, NULL)); + return 0; /* to avoid warnings */ +} + +static int luaB_setglobal (lua_State *L) { + luaL_checkany(L, 2); + lua_setglobal(L, luaL_check_string(L, 1)); + return 0; +} + +static int luaB_getglobal (lua_State *L) { + lua_getglobal(L, luaL_check_string(L, 1)); + return 1; +} + +static int luaB_tag (lua_State *L) { + luaL_checkany(L, 1); + lua_pushnumber(L, lua_tag(L, 1)); + return 1; +} + +static int luaB_settag (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushvalue(L, 1); /* push table */ + lua_settag(L, luaL_check_int(L, 2)); + return 1; /* return table */ +} + +static int luaB_newtag (lua_State *L) { + lua_pushnumber(L, lua_newtag(L)); + return 1; +} + +static int luaB_copytagmethods (lua_State *L) { + lua_pushnumber(L, lua_copytagmethods(L, luaL_check_int(L, 1), + luaL_check_int(L, 2))); + return 1; +} + +static int luaB_globals (lua_State *L) { + lua_getglobals(L); /* value to be returned */ + if (!lua_isnull(L, 1)) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushvalue(L, 1); /* new table of globals */ + lua_setglobals(L); + } + return 1; +} + +static int luaB_rawget (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + lua_rawget(L, -2); + return 1; +} + +static int luaB_rawset (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + luaL_checkany(L, 3); + lua_rawset(L, -3); + return 1; +} + +static int luaB_settagmethod (lua_State *L) { + int tag = luaL_check_int(L, 1); + const char *event = luaL_check_string(L, 2); + luaL_arg_check(L, lua_isfunction(L, 3) || lua_isnil(L, 3), 3, + "function or nil expected"); + if (strcmp(event, "gc") == 0) + lua_error(L, "deprecated use: cannot set the `gc' tag method from Lua"); + lua_gettagmethod(L, tag, event); + lua_pushvalue(L, 3); + lua_settagmethod(L, tag, event); + return 1; +} + + +static int luaB_gettagmethod (lua_State *L) { + int tag = luaL_check_int(L, 1); + const char *event = luaL_check_string(L, 2); + if (strcmp(event, "gc") == 0) + lua_error(L, "deprecated use: cannot get the `gc' tag method from Lua"); + lua_gettagmethod(L, tag, event); + return 1; +} + + +static int luaB_gcinfo (lua_State *L) { + lua_pushnumber(L, lua_getgccount(L)); + lua_pushnumber(L, lua_getgcthreshold(L)); + return 2; +} + + +static int luaB_collectgarbage (lua_State *L) { + lua_setgcthreshold(L, luaL_opt_int(L, 1, 0)); + return 0; +} + + +static int luaB_type (lua_State *L) { + luaL_checkany(L, 1); + lua_pushstring(L, lua_typename(L, lua_type(L, 1))); + return 1; +} + + +static int luaB_next (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 2); /* create a 2nd argument if there isn't one */ + if (lua_next(L, 1)) + return 2; + else { + lua_pushnil(L); + return 1; + } +} + + +static int passresults (lua_State *L, int status, int oldtop) { + static const char *const errornames[] = + {"ok", "run-time error", "file error", "syntax error", + "memory error", "error in error handling"}; + if (status == 0) { + int nresults = lua_gettop(L) - oldtop; + if (nresults > 0) + return nresults; /* results are already on the stack */ + else { + lua_pushuserdata(L, NULL); /* at least one result to signal no errors */ + return 1; + } + } + else { /* error */ + lua_pushnil(L); + lua_pushstring(L, errornames[status]); /* error code */ + return 2; + } +} + +static int luaB_dostring (lua_State *L) { + int oldtop = lua_gettop(L); + size_t l; + const char *s = luaL_check_lstr(L, 1, &l); + if (*s == '\27') /* binary files start with ESC... */ + lua_error(L, "`dostring' cannot run pre-compiled code"); + return passresults(L, lua_dobuffer(L, s, l, luaL_opt_string(L, 2, s)), oldtop); +} + + +static int luaB_dofile (lua_State *L) { + int oldtop = lua_gettop(L); + const char *fname = luaL_opt_string(L, 1, NULL); + return passresults(L, lua_dofile(L, fname), oldtop); +} + + +static int luaB_call (lua_State *L) { + int oldtop; + const char *options = luaL_opt_string(L, 3, ""); + int err = 0; /* index of old error method */ + int i, status; + int n; + luaL_checktype(L, 2, LUA_TTABLE); + n = lua_getn(L, 2); + if (!lua_isnull(L, 4)) { /* set new error method */ + lua_getglobal(L, LUA_ERRORMESSAGE); + err = lua_gettop(L); /* get index */ + lua_pushvalue(L, 4); + lua_setglobal(L, LUA_ERRORMESSAGE); + } + oldtop = lua_gettop(L); /* top before function-call preparation */ + /* push function */ + lua_pushvalue(L, 1); + luaL_checkstack(L, n, "too many arguments"); + for (i=0; i<n; i++) /* push arg[1...n] */ + lua_rawgeti(L, 2, i+1); + status = lua_call(L, n, LUA_MULTRET); + if (err != 0) { /* restore old error method */ + lua_pushvalue(L, err); + lua_setglobal(L, LUA_ERRORMESSAGE); + } + if (status != 0) { /* error in call? */ + if (strchr(options, 'x')) + lua_pushnil(L); /* return nil to signal the error */ + else + lua_error(L, NULL); /* propagate error without additional messages */ + return 1; + } + if (strchr(options, 'p')) /* pack results? */ + lua_error(L, "deprecated option `p' in `call'"); + return lua_gettop(L) - oldtop; /* results are already on the stack */ +} + + +static int luaB_tostring (lua_State *L) { + char buff[64]; + switch (lua_type(L, 1)) { + case LUA_TNUMBER: + lua_pushstring(L, lua_tostring(L, 1)); + return 1; + case LUA_TSTRING: + lua_pushvalue(L, 1); + return 1; + case LUA_TTABLE: + sprintf(buff, "table: %p", lua_topointer(L, 1)); + break; + case LUA_TFUNCTION: + sprintf(buff, "function: %p", lua_topointer(L, 1)); + break; + case LUA_TUSERDATA: + sprintf(buff, "userdata(%d): %p", lua_tag(L, 1), lua_touserdata(L, 1)); + break; + case LUA_TNIL: + lua_pushstring(L, "nil"); + return 1; + default: + luaL_argerror(L, 1, "value expected"); + } + lua_pushstring(L, buff); + return 1; +} + + +static int luaB_foreachi (lua_State *L) { + int n, i; + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checktype(L, 2, LUA_TFUNCTION); + n = lua_getn(L, 1); + for (i=1; i<=n; i++) { + lua_pushvalue(L, 2); /* function */ + lua_pushnumber(L, i); /* 1st argument */ + lua_rawgeti(L, 1, i); /* 2nd argument */ + lua_rawcall(L, 2, 1); + if (!lua_isnil(L, -1)) + return 1; + lua_pop(L, 1); /* remove nil result */ + } + return 0; +} + + +static int luaB_foreach (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checktype(L, 2, LUA_TFUNCTION); + lua_pushnil(L); /* first index */ + for (;;) { + if (lua_next(L, 1) == 0) + return 0; + lua_pushvalue(L, 2); /* function */ + lua_pushvalue(L, -3); /* key */ + lua_pushvalue(L, -3); /* value */ + lua_rawcall(L, 2, 1); + if (!lua_isnil(L, -1)) + return 1; + lua_pop(L, 2); /* remove value and result */ + } +} + + +static int luaB_assert (lua_State *L) { + luaL_checkany(L, 1); + if (lua_isnil(L, 1)) + luaL_verror(L, "assertion failed! %.90s", luaL_opt_string(L, 2, "")); + return 0; +} + + +static int luaB_getn (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushnumber(L, lua_getn(L, 1)); + return 1; +} + + +static int luaB_tinsert (lua_State *L) { + int v = lua_gettop(L); /* last argument: to be inserted */ + int n, pos; + luaL_checktype(L, 1, LUA_TTABLE); + n = lua_getn(L, 1); + if (v == 2) /* called with only 2 arguments */ + pos = n+1; + else + pos = luaL_check_int(L, 2); /* 2nd argument is the position */ + lua_pushstring(L, "n"); + lua_pushnumber(L, n+1); + lua_rawset(L, 1); /* t.n = n+1 */ + for (; n>=pos; n--) { + lua_rawgeti(L, 1, n); + lua_rawseti(L, 1, n+1); /* t[n+1] = t[n] */ + } + lua_pushvalue(L, v); + lua_rawseti(L, 1, pos); /* t[pos] = v */ + return 0; +} + + +static int luaB_tremove (lua_State *L) { + int pos, n; + luaL_checktype(L, 1, LUA_TTABLE); + n = lua_getn(L, 1); + pos = luaL_opt_int(L, 2, n); + if (n <= 0) return 0; /* table is "empty" */ + lua_rawgeti(L, 1, pos); /* result = t[pos] */ + for ( ;pos<n; pos++) { + lua_rawgeti(L, 1, pos+1); + lua_rawseti(L, 1, pos); /* a[pos] = a[pos+1] */ + } + lua_pushstring(L, "n"); + lua_pushnumber(L, n-1); + lua_rawset(L, 1); /* t.n = n-1 */ + lua_pushnil(L); + lua_rawseti(L, 1, n); /* t[n] = nil */ + return 1; +} + + + + +/* +** {====================================================== +** Quicksort +** (based on `Algorithms in MODULA-3', Robert Sedgewick; +** Addison-Wesley, 1993.) +*/ + + +static void set2 (lua_State *L, int i, int j) { + lua_rawseti(L, 1, i); + lua_rawseti(L, 1, j); +} + +static int sort_comp (lua_State *L, int a, int b) { + /* WARNING: the caller (auxsort) must ensure stack space */ + if (!lua_isnil(L, 2)) { /* function? */ + int res; + lua_pushvalue(L, 2); + lua_pushvalue(L, a-1); /* -1 to compensate function */ + lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */ + lua_rawcall(L, 2, 1); + res = !lua_isnil(L, -1); + lua_pop(L, 1); + return res; + } + else /* a < b? */ + return lua_lessthan(L, a, b); +} + +static void auxsort (lua_State *L, int l, int u) { + while (l < u) { /* for tail recursion */ + int i, j; + /* sort elements a[l], a[(l+u)/2] and a[u] */ + lua_rawgeti(L, 1, l); + lua_rawgeti(L, 1, u); + if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */ + set2(L, l, u); /* swap a[l] - a[u] */ + else + lua_pop(L, 2); + if (u-l == 1) break; /* only 2 elements */ + i = (l+u)/2; + lua_rawgeti(L, 1, i); + lua_rawgeti(L, 1, l); + if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */ + set2(L, i, l); + else { + lua_pop(L, 1); /* remove a[l] */ + lua_rawgeti(L, 1, u); + if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */ + set2(L, i, u); + else + lua_pop(L, 2); + } + if (u-l == 2) break; /* only 3 elements */ + lua_rawgeti(L, 1, i); /* Pivot */ + lua_pushvalue(L, -1); + lua_rawgeti(L, 1, u-1); + set2(L, i, u-1); + /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */ + i = l; j = u-1; + for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */ + /* repeat ++i until a[i] >= P */ + while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { + if (i>u) lua_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[i] */ + } + /* repeat --j until a[j] <= P */ + while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { + if (j<l) lua_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[j] */ + } + if (j<i) { + lua_pop(L, 3); /* pop pivot, a[i], a[j] */ + break; + } + set2(L, i, j); + } + lua_rawgeti(L, 1, u-1); + lua_rawgeti(L, 1, i); + set2(L, u-1, i); /* swap pivot (a[u-1]) with a[i] */ + /* a[l..i-1] <= a[i] == P <= a[i+1..u] */ + /* adjust so that smaller "half" is in [j..i] and larger one in [l..u] */ + if (i-l < u-i) { + j=l; i=i-1; l=i+2; + } + else { + j=i+1; i=u; u=j-2; + } + auxsort(L, j, i); /* call recursively the smaller one */ + } /* repeat the routine for the larger one */ +} + +static int luaB_sort (lua_State *L) { + int n; + luaL_checktype(L, 1, LUA_TTABLE); + n = lua_getn(L, 1); + if (!lua_isnull(L, 2)) /* is there a 2nd argument? */ + luaL_checktype(L, 2, LUA_TFUNCTION); + lua_settop(L, 2); /* make sure there is two arguments */ + auxsort(L, 1, n); + return 0; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** Deprecated functions to manipulate global environment. +** ======================================================= +*/ + + +#define num_deprecated 4 + +static const struct luaL_reg deprecated_names [num_deprecated] = { + {"foreachvar", luaB_foreach}, + {"nextvar", luaB_next}, + {"rawgetglobal", luaB_rawget}, + {"rawsetglobal", luaB_rawset} +}; + + +#ifdef LUA_DEPRECATEDFUNCS + +/* +** call corresponding function inserting `globals' as first argument +*/ +static int deprecated_func (lua_State *L) { + lua_insert(L, 1); /* upvalue is the function to be called */ + lua_getglobals(L); + lua_insert(L, 2); /* table of globals is 1o argument */ + lua_rawcall(L, lua_gettop(L)-1, LUA_MULTRET); + return lua_gettop(L); /* return all results */ +} + + +static void deprecated_funcs (lua_State *L) { + int i; + for (i=0; i<num_deprecated; i++) { + lua_pushcfunction(L, deprecated_names[i].func); + lua_pushcclosure(L, deprecated_func, 1); + lua_setglobal(L, deprecated_names[i].name); + } +} + + +#else + +/* +** gives an explicit error in any attempt to call a deprecated function +*/ +static int deprecated_func (lua_State *L) { + luaL_verror(L, "function `%.20s' is deprecated", lua_tostring(L, -1)); + return 0; /* to avoid warnings */ +} + + +static void deprecated_funcs (lua_State *L) { + int i; + for (i=0; i<num_deprecated; i++) { + lua_pushstring(L, deprecated_names[i].name); + lua_pushcclosure(L, deprecated_func, 1); + lua_setglobal(L, deprecated_names[i].name); + } +} + +#endif + +/* }====================================================== */ + +static const struct luaL_reg base_funcs[] = { + {LUA_ALERT, luaB__ALERT}, + {LUA_ERRORMESSAGE, luaB__ERRORMESSAGE}, + {"call", luaB_call}, + {"collectgarbage", luaB_collectgarbage}, + {"copytagmethods", luaB_copytagmethods}, + {"dofile", luaB_dofile}, + {"dostring", luaB_dostring}, + {"error", luaB_error}, + {"foreach", luaB_foreach}, + {"foreachi", luaB_foreachi}, + {"gcinfo", luaB_gcinfo}, + {"getglobal", luaB_getglobal}, + {"gettagmethod", luaB_gettagmethod}, + {"globals", luaB_globals}, + {"newtag", luaB_newtag}, + {"next", luaB_next}, + {"print", luaB_print}, + {"rawget", luaB_rawget}, + {"rawset", luaB_rawset}, + {"rawgettable", luaB_rawget}, /* for compatibility */ + {"rawsettable", luaB_rawset}, /* for compatibility */ + {"setglobal", luaB_setglobal}, + {"settag", luaB_settag}, + {"settagmethod", luaB_settagmethod}, + {"tag", luaB_tag}, + {"tonumber", luaB_tonumber}, + {"tostring", luaB_tostring}, + {"type", luaB_type}, + {"assert", luaB_assert}, + {"getn", luaB_getn}, + {"sort", luaB_sort}, + {"tinsert", luaB_tinsert}, + {"tremove", luaB_tremove} +}; + + + +LUALIB_API void lua_baselibopen (lua_State *L) { + luaL_openl(L, base_funcs); + lua_pushstring(L, LUA_VERSION); + lua_setglobal(L, "_VERSION"); + deprecated_funcs(L); +} + diff --git a/src/lib/ldblib.c b/src/lib/ldblib.c index 388a2f2d..636dbe05 100644 --- a/src/lib/ldblib.c +++ b/src/lib/ldblib.c @@ -1,217 +1,188 @@ /* -** $Id: ldblib.c,v 1.5 1999/03/04 21:17:26 roberto Exp $ +** $Id: ldblib.c,v 1.29 2000/11/06 17:58:38 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ +#include <stdio.h> #include <stdlib.h> #include <string.h> -#include "lauxlib.h" #include "lua.h" + +#include "lauxlib.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 settabss (lua_State *L, const char *i, const char *v) { + lua_pushstring(L, i); + lua_pushstring(L, v); + lua_settable(L, -3); } -static void settabsi (lua_Object t, char *i, int v) { - lua_pushobject(t); - lua_pushstring(i); - lua_pushnumber(v); - lua_settable(); +static void settabsi (lua_State *L, const char *i, int v) { + lua_pushstring(L, i); + lua_pushnumber(L, v); + lua_settable(L, -3); } -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); +static int getinfo (lua_State *L) { + lua_Debug ar; + const char *options = luaL_opt_string(L, 2, "flnSu"); + char buff[20]; + if (lua_isnumber(L, 1)) { + if (!lua_getstack(L, (int)lua_tonumber(L, 1), &ar)) { + lua_pushnil(L); /* level out of range */ + return 1; } - 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); + else if (lua_isfunction(L, 1)) { + lua_pushvalue(L, 1); + sprintf(buff, ">%.10s", options); + options = buff; + } + else + luaL_argerror(L, 1, "function or level expected"); + if (!lua_getinfo(L, options, &ar)) + luaL_argerror(L, 2, "invalid option"); + lua_newtable(L); + for (; *options; options++) { + switch (*options) { + case 'S': + settabss(L, "source", ar.source); + if (ar.source) + settabss(L, "short_src", ar.short_src); + settabsi(L, "linedefined", ar.linedefined); + settabss(L, "what", ar.what); + break; + case 'l': + settabsi(L, "currentline", ar.currentline); + break; + case 'u': + settabsi(L, "nups", ar.nups); + break; + case 'n': + settabss(L, "name", ar.name); + settabss(L, "namewhat", ar.namewhat); + break; + case 'f': + lua_pushstring(L, "func"); + lua_pushvalue(L, -3); + lua_settable(L, -3); + break; } } - return result; + return 1; /* return table */ } - - -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 int getlocal (lua_State *L) { + lua_Debug ar; + const char *name; + if (!lua_getstack(L, luaL_check_int(L, 1), &ar)) /* level out of range? */ + luaL_argerror(L, 1, "level out of range"); + name = lua_getlocal(L, &ar, luaL_check_int(L, 2)); + if (name) { + lua_pushstring(L, name); + lua_pushvalue(L, -2); + return 2; } -} - - -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; + lua_pushnil(L); + return 1; } } -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 int setlocal (lua_State *L) { + lua_Debug ar; + if (!lua_getstack(L, luaL_check_int(L, 1), &ar)) /* level out of range? */ + luaL_argerror(L, 1, "level out of range"); + luaL_checkany(L, 3); + lua_pushstring(L, lua_setlocal(L, &ar, luaL_check_int(L, 2))); + return 1; } -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"); -} +/* dummy variables (to define unique addresses) */ +static char key1, key2; +#define KEY_CALLHOOK (&key1) +#define KEY_LINEHOOK (&key2) -static int linehook = -1; /* Lua reference to line hook function */ -static int callhook = -1; /* Lua reference to call hook function */ +static void hookf (lua_State *L, void *key) { + lua_getregistry(L); + lua_pushuserdata(L, key); + lua_gettable(L, -2); + if (lua_isfunction(L, -1)) { + lua_pushvalue(L, 1); + lua_rawcall(L, 1, 0); + } + else + lua_pop(L, 1); /* pop result from gettable */ + lua_pop(L, 1); /* pop table */ +} -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 callf (lua_State *L, lua_Debug *ar) { + lua_pushstring(L, ar->event); + hookf(L, KEY_CALLHOOK); } -static void linef (int line) { - lua_pushnumber(line); - dohook(linehook); +static void linef (lua_State *L, lua_Debug *ar) { + lua_pushnumber(L, ar->currentline); + hookf(L, KEY_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 sethook (lua_State *L, void *key, lua_Hook hook, + lua_Hook (*sethookf)(lua_State * L, lua_Hook h)) { + lua_settop(L, 1); + if (lua_isnil(L, 1)) + (*sethookf)(L, NULL); + else if (lua_isfunction(L, 1)) + (*sethookf)(L, hook); + else + luaL_argerror(L, 1, "function expected"); + lua_getregistry(L); + lua_pushuserdata(L, key); + lua_pushvalue(L, -1); /* dup key */ + lua_gettable(L, -3); /* get old value */ + lua_pushvalue(L, -2); /* key (again) */ + lua_pushvalue(L, 1); + lua_settable(L, -5); /* set new value */ } -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 int setcallhook (lua_State *L) { + sethook(L, KEY_CALLHOOK, callf, lua_setcallhook); + return 1; } -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 int setlinehook (lua_State *L) { + sethook(L, KEY_LINEHOOK, linef, lua_setlinehook); + return 1; } -static struct luaL_reg dblib[] = { - {"funcinfo", funcinfo}, +static const struct luaL_reg dblib[] = { {"getlocal", getlocal}, - {"getstack", getstack}, + {"getinfo", getinfo}, {"setcallhook", setcallhook}, {"setlinehook", setlinehook}, {"setlocal", setlocal} }; -void lua_dblibopen (void) { - luaL_openlib(dblib, (sizeof(dblib)/sizeof(dblib[0]))); +LUALIB_API void lua_dblibopen (lua_State *L) { + luaL_openl(L, dblib); } diff --git a/src/lib/linit.c b/src/lib/linit.c deleted file mode 100644 index be57aae7..00000000 --- a/src/lib/linit.c +++ /dev/null @@ -1,17 +0,0 @@ -/* -** $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 d833cec5..70f8057a 100644 --- a/src/lib/liolib.c +++ b/src/lib/liolib.c @@ -1,67 +1,78 @@ /* -** $Id: liolib.c,v 1.41 1999/06/23 13:48:39 roberto Exp $ +** $Id: liolib.c,v 1.91 2000/10/31 13:10:24 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ -#include <errno.h> +#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> -#include "lauxlib.h" #include "lua.h" + +#include "lauxlib.h" #include "luadebug.h" #include "lualib.h" #ifndef OLD_ANSI +#include <errno.h> #include <locale.h> +#define realloc(b,s) ((b) == NULL ? malloc(s) : (realloc)(b, s)) +#define free(b) if (b) (free)(b) #else /* no support for locale and for strerror: fake them */ -#define setlocale(a,b) 0 +#define setlocale(a,b) ((void)a, strcmp((b),"C")==0?"C":NULL) #define LC_ALL 0 #define LC_COLLATE 0 #define LC_CTYPE 0 #define LC_MONETARY 0 #define LC_NUMERIC 0 #define LC_TIME 0 -#define strerror(e) "(no error message provided by operating system)" +#define strerror(e) "generic I/O error" +#define errno (-1) #endif -#define IOTAG 1 - -#define FIRSTARG 2 /* 1st is upvalue */ - -#define CLOSEDTAG(tag) ((tag)-1) /* assume that CLOSEDTAG = iotag-1 */ - - -#define FINPUT "_INPUT" -#define FOUTPUT "_OUTPUT" - #ifdef POPEN -FILE *popen(); -int pclose(); -#define CLOSEFILE(f) {if (pclose(f) == -1) fclose(f);} +/* FILE *popen(); +int pclose(); */ +#define CLOSEFILE(L, f) ((pclose(f) == -1) ? fclose(f) : 0) #else /* no support for popen */ #define popen(x,y) NULL /* that is, popen always fails */ -#define CLOSEFILE(f) {fclose(f);} +#define CLOSEFILE(L, f) (fclose(f)) #endif +#define INFILE 0 +#define OUTFILE 1 + +typedef struct IOCtrl { + int ref[2]; /* ref for strings _INPUT/_OUTPUT */ + int iotag; /* tag for file handles */ + int closedtag; /* tag for closed handles */ +} IOCtrl; + + + +static const char *const filenames[] = {"_INPUT", "_OUTPUT"}; -static void pushresult (int i) { - if (i) - lua_pushuserdata(NULL); + +static int pushresult (lua_State *L, int i) { + if (i) { + lua_pushuserdata(L, NULL); + return 1; + } else { - lua_pushnil(); - lua_pushstring(strerror(errno)); - lua_pushnumber(errno); + lua_pushnil(L); + lua_pushstring(L, strerror(errno)); + lua_pushnumber(L, errno); + return 3;; } } @@ -72,138 +83,138 @@ static void pushresult (int i) { ** ======================================================= */ -static int gettag (void) { - return (int)lua_getnumber(lua_getparam(IOTAG)); -} - -static int ishandle (lua_Object f) { - if (lua_isuserdata(f)) { - int tag = gettag(); - if (lua_tag(f) == CLOSEDTAG(tag)) - lua_error("cannot access a closed file"); - return lua_tag(f) == tag; +static FILE *gethandle (lua_State *L, IOCtrl *ctrl, int f) { + void *p = lua_touserdata(L, f); + if (p != NULL) { /* is `f' a userdata ? */ + int ftag = lua_tag(L, f); + if (ftag == ctrl->iotag) /* does it have the correct tag? */ + return (FILE *)p; + else if (ftag == ctrl->closedtag) + lua_error(L, "cannot access a closed file"); + /* else go through */ } - else return 0; + return NULL; } -static FILE *getfilebyname (char *name) { - lua_Object f = lua_getglobal(name); - if (!ishandle(f)) - luaL_verror("global variable `%.50s' is not a file handle", name); - return lua_getuserdata(f); -} - - -static FILE *getfile (int arg) { - lua_Object f = lua_getparam(arg); - return (ishandle(f)) ? lua_getuserdata(f) : NULL; +static FILE *getnonullfile (lua_State *L, IOCtrl *ctrl, int arg) { + FILE *f = gethandle(L, ctrl, arg); + luaL_arg_check(L, f, arg, "invalid file handle"); + return f; } -static FILE *getnonullfile (int arg) { - FILE *f = getfile(arg); - luaL_arg_check(f, arg, "invalid file handle"); +static FILE *getfilebyref (lua_State *L, IOCtrl *ctrl, int inout) { + FILE *f; + lua_getglobals(L); + lua_getref(L, ctrl->ref[inout]); + lua_rawget(L, -2); + f = gethandle(L, ctrl, -1); + if (f == NULL) + luaL_verror(L, "global variable `%.10s' is not a file handle", + filenames[inout]); return f; } -static FILE *getfileparam (char *name, int *arg) { - FILE *f = getfile(*arg); - if (f) { - (*arg)++; - return f; - } - else - return getfilebyname(name); +static void setfilebyname (lua_State *L, IOCtrl *ctrl, FILE *f, + const char *name) { + lua_pushusertag(L, f, ctrl->iotag); + lua_setglobal(L, name); } -static void closefile (FILE *f) { - if (f != stdin && f != stdout) { - int tag = gettag(); - CLOSEFILE(f); - lua_pushusertag(f, tag); - lua_settag(CLOSEDTAG(tag)); - } -} +#define setfile(L,ctrl,f,inout) (setfilebyname(L,ctrl,f,filenames[inout])) -static void io_close (void) { - closefile(getnonullfile(FIRSTARG)); +static int setreturn (lua_State *L, IOCtrl *ctrl, FILE *f, int inout) { + if (f == NULL) + return pushresult(L, 0); + else { + setfile(L, ctrl, f, inout); + lua_pushusertag(L, f, ctrl->iotag); + return 1; + } } -static void gc_close (void) { - FILE *f = getnonullfile(FIRSTARG); - if (f != stdin && f != stdout && f != stderr) { - CLOSEFILE(f); +static int closefile (lua_State *L, IOCtrl *ctrl, FILE *f) { + if (f == stdin || f == stdout || f == stderr) + return 1; + else { + lua_pushusertag(L, f, ctrl->iotag); + lua_settag(L, ctrl->closedtag); + return (CLOSEFILE(L, f) == 0); } } -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 int io_close (lua_State *L) { + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); + lua_pop(L, 1); /* remove upvalue */ + return pushresult(L, closefile(L, ctrl, getnonullfile(L, ctrl, 1))); } -static void setfile (FILE *f, char *name, int tag) { - lua_pushusertag(f, tag); - lua_setglobal(name); +static int file_collect (lua_State *L) { + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); + FILE *f = getnonullfile(L, ctrl, 1); + if (f != stdin && f != stdout && f != stderr) + CLOSEFILE(L, f); + return 0; } -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 int io_open (lua_State *L) { + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); + FILE *f; + lua_pop(L, 1); /* remove upvalue */ + f = fopen(luaL_check_string(L, 1), luaL_check_string(L, 2)); + if (f) { + lua_pushusertag(L, f, ctrl->iotag); + return 1; } + else + return pushresult(L, 0); } -static void io_readfrom (void) { + +static int io_fromto (lua_State *L, int inout, const char *mode) { + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); FILE *current; - lua_Object f = lua_getparam(FIRSTARG); - if (f == LUA_NOOBJECT) { - closefile(getfilebyname(FINPUT)); - current = stdin; + lua_pop(L, 1); /* remove upvalue */ + if (lua_isnull(L, 1)) { + closefile(L, ctrl, getfilebyref(L, ctrl, inout)); + current = (inout == 0) ? stdin : stdout; } - else if (lua_tag(f) == gettag()) /* deprecated option */ - current = lua_getuserdata(f); + else if (lua_tag(L, 1) == ctrl->iotag) /* deprecated option */ + current = (FILE *)lua_touserdata(L, 1); else { - char *s = luaL_check_string(FIRSTARG); - current = (*s == '|') ? popen(s+1, "r") : fopen(s, "r"); + const char *s = luaL_check_string(L, 1); + current = (*s == '|') ? popen(s+1, mode) : fopen(s, mode); } - setreturn(current, FINPUT); + return setreturn(L, ctrl, current, inout); } -static void io_writeto (void) { - FILE *current; - lua_Object f = lua_getparam(FIRSTARG); - if (f == LUA_NOOBJECT) { - closefile(getfilebyname(FOUTPUT)); - current = stdout; - } - 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"); - } - setreturn(current, FOUTPUT); +static int io_readfrom (lua_State *L) { + return io_fromto(L, INFILE, "r"); } -static void io_appendto (void) { - FILE *current = fopen(luaL_check_string(FIRSTARG), "a"); - setreturn(current, FOUTPUT); +static int io_writeto (lua_State *L) { + return io_fromto(L, OUTFILE, "w"); +} + + +static int io_appendto (lua_State *L) { + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); + FILE *current; + lua_pop(L, 1); /* remove upvalue */ + current = fopen(luaL_check_string(L, 1), "a"); + return setreturn(L, ctrl, current, OUTFILE); } @@ -215,6 +226,9 @@ static void io_appendto (void) { */ + +#ifdef LUA_COMPAT_READPATTERN + /* ** We cannot lookahead without need, because this can lock stdin. ** This flag signals when we need to read a next char. @@ -222,9 +236,11 @@ static void io_appendto (void) { #define NEED_OTHER (EOF-1) /* just some flag different from EOF */ -static int read_pattern (FILE *f, char *p) { +static int read_pattern (lua_State *L, FILE *f, const char *p) { int inskip = 0; /* {skip} level */ int c = NEED_OTHER; + luaL_Buffer b; + luaL_buffinit(L, &b); while (*p != '\0') { switch (*p) { case '{': @@ -232,17 +248,17 @@ static int read_pattern (FILE *f, char *p) { p++; continue; case '}': - if (!inskip) lua_error("unbalanced braces in read pattern"); + if (!inskip) lua_error(L, "unbalanced braces in read pattern"); inskip--; p++; continue; default: { - char *ep = luaI_classend(p); /* get what is next */ + const char *ep = luaI_classend(L, 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); + if (!inskip) luaL_putchar(&b, c); c = NEED_OTHER; } switch (*ep) { @@ -253,7 +269,7 @@ static int read_pattern (FILE *f, char *p) { 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); + if (m && !inskip) luaL_putchar(&b, c); } /* go through to continue reading the pattern */ case '?': /* optional */ @@ -267,116 +283,210 @@ static int read_pattern (FILE *f, char *p) { } } break_while: if (c != NEED_OTHER) ungetc(c, f); + luaL_pushresult(&b); /* close buffer */ return (*p == '\0'); } +#else + +#define read_pattern(L, f, p) (lua_error(L, "read patterns are deprecated"), 0) -static int read_number (FILE *f) { +#endif + + +static int read_number (lua_State *L, FILE *f) { double d; if (fscanf(f, "%lf", &d) == 1) { - lua_pushnumber(d); + lua_pushnumber(L, d); return 1; } else return 0; /* read fails */ } -#define HUNK_LINE 1024 -#define HUNK_FILE BUFSIZ +static int read_word (lua_State *L, FILE *f) { + int c; + luaL_Buffer 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); + } + ungetc(c, f); + luaL_pushresult(&b); /* close buffer */ + return (lua_strlen(L, -1) > 0); +} -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 int read_line (lua_State *L, FILE *f) { + int n = 0; + luaL_Buffer b; + luaL_buffinit(L, &b); + for (;;) { + char *p = luaL_prepbuffer(&b); + if (!fgets(p, LUAL_BUFFERSIZE, f)) /* read fails? */ + break; + n = strlen(p); + if (p[n-1] != '\n') + luaL_addsize(&b, n); + else { + luaL_addsize(&b, n-1); /* do not add the `\n' */ + break; + } + } + luaL_pushresult(&b); /* close buffer */ + return (n > 0); /* read something? */ } -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 read_file (lua_State *L, FILE *f) { + size_t len = 0; + size_t size = BUFSIZ; + char *buffer = NULL; + for (;;) { + char *newbuffer = (char *)realloc(buffer, size); + if (newbuffer == NULL) { + free(buffer); + lua_error(L, "not enough memory to read a file"); + } + buffer = newbuffer; + len += fread(buffer+len, sizeof(char), size-len, f); + if (len < size) break; /* did not read all it could */ + size *= 2; + } + lua_pushlstring(L, buffer, len); + free(buffer); } -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++, "*l"); - do { /* repeat for each part */ - long l; +static int read_chars (lua_State *L, FILE *f, size_t n) { + char *buffer; + size_t n1; + char statbuff[BUFSIZ]; + if (n <= BUFSIZ) + buffer = statbuff; + else { + buffer = (char *)malloc(n); + if (buffer == NULL) + lua_error(L, "not enough memory to read a file"); + } + n1 = fread(buffer, sizeof(char), n, f); + lua_pushlstring(L, buffer, n1); + if (buffer != statbuff) free(buffer); + return (n1 > 0 || n == 0); +} + + +static int io_read (lua_State *L) { + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); + int lastarg = lua_gettop(L) - 1; + int firstarg = 1; + FILE *f = gethandle(L, ctrl, firstarg); + int n; + if (f) firstarg++; + else f = getfilebyref(L, ctrl, INFILE); /* get _INPUT */ + lua_pop(L, 1); + if (firstarg > lastarg) { /* no arguments? */ + lua_settop(L, 0); /* erase upvalue and other eventual garbage */ + firstarg = lastarg = 1; /* correct indices */ + lua_pushstring(L, "*l"); /* push default argument */ + } + else /* ensure stack space for all results and for auxlib's buffer */ + luaL_checkstack(L, lastarg-firstarg+1+LUA_MINSTACK, "too many arguments"); + for (n = firstarg; n<=lastarg; n++) { 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); + if (lua_isnumber(L, n)) + success = read_chars(L, f, (size_t)lua_tonumber(L, n)); + else { + const char *p = luaL_check_string(L, n); + if (p[0] != '*') + success = read_pattern(L, f, p); /* deprecated! */ + else { + switch (p[1]) { + case 'n': /* number */ + if (!read_number(L, f)) goto endloop; /* read fails */ + continue; /* number is already pushed; avoid the "pushstring" */ + case 'l': /* line */ + success = read_line(L, f); + break; + case 'a': /* file */ + read_file(L, f); + success = 1; /* always success */ + break; + case 'w': /* word */ + success = read_word(L, f); + break; + default: + luaL_argerror(L, n, "invalid format"); + success = 0; /* to avoid warnings */ + } + } } - l = luaL_getsize(); - if (!success && l==0) return; /* read fails */ - lua_pushlstring(luaL_buffer(), l); - } while ((p = luaL_opt_string(arg++, NULL)) != NULL); + if (!success) { + lua_pop(L, 1); /* remove last result */ + break; /* read fails */ + } + } endloop: + return n - firstarg; } /* }====================================================== */ -static void io_write (void) { - int arg = FIRSTARG; - FILE *f = getfileparam(FOUTPUT, &arg); +static int io_write (lua_State *L) { + int lastarg = lua_gettop(L) - 1; + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); + int arg = 1; int status = 1; - char *s; - long l; - while ((s = luaL_opt_lstr(arg++, NULL, &l)) != NULL) - status = status && ((long)fwrite(s, 1, l, f) == l); - pushresult(status); + FILE *f = gethandle(L, ctrl, arg); + if (f) arg++; + else f = getfilebyref(L, ctrl, OUTFILE); /* get _OUTPUT */ + for (; arg <= lastarg; arg++) { + if (lua_type(L, arg) == LUA_TNUMBER) { /* LUA_NUMBER */ + /* optimization: could be done exactly as for strings */ + status = status && fprintf(f, "%.16g", lua_tonumber(L, arg)) > 0; + } + else { + size_t l; + const char *s = luaL_check_lstr(L, arg, &l); + status = status && (fwrite(s, sizeof(char), l, f) == l); + } + } + pushresult(L, status); + return 1; } -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"); +static int io_seek (lua_State *L) { + static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; + static const char *const modenames[] = {"set", "cur", "end", NULL}; + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); + FILE *f; + int op; + long offset; + lua_pop(L, 1); /* remove upvalue */ + f = getnonullfile(L, ctrl, 1); + op = luaL_findstring(luaL_opt_string(L, 2, "cur"), modenames); + offset = luaL_opt_long(L, 3, 0); + luaL_arg_check(L, op != -1, 2, "invalid mode"); op = fseek(f, offset, mode[op]); if (op) - pushresult(0); /* error */ - else - lua_pushnumber(ftell(f)); + return pushresult(L, 0); /* error */ + else { + lua_pushnumber(L, ftell(f)); + return 1; + } } -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); +static int io_flush (lua_State *L) { + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); + FILE *f; + lua_pop(L, 1); /* remove upvalue */ + f = gethandle(L, ctrl, 1); + luaL_arg_check(L, f || lua_isnull(L, 1), 1, "invalid file handle"); + return pushresult(L, fflush(f) == 0); } /* }====================================================== */ @@ -388,145 +498,165 @@ static void io_flush (void) { ** ======================================================= */ -static void io_execute (void) { - lua_pushnumber(system(luaL_check_string(1))); +static int io_execute (lua_State *L) { + lua_pushnumber(L, system(luaL_check_string(L, 1))); + return 1; } -static void io_remove (void) { - pushresult(remove(luaL_check_string(1)) == 0); +static int io_remove (lua_State *L) { + return pushresult(L, remove(luaL_check_string(L, 1)) == 0); } -static void io_rename (void) { - pushresult(rename(luaL_check_string(1), - luaL_check_string(2)) == 0); +static int io_rename (lua_State *L) { + return pushresult(L, rename(luaL_check_string(L, 1), + luaL_check_string(L, 2)) == 0); } -static void io_tmpname (void) { - lua_pushstring(tmpnam(NULL)); +static int io_tmpname (lua_State *L) { + lua_pushstring(L, tmpnam(NULL)); + return 1; } -static void io_getenv (void) { - lua_pushstring(getenv(luaL_check_string(1))); /* if NULL push nil */ +static int io_getenv (lua_State *L) { + lua_pushstring(L, getenv(luaL_check_string(L, 1))); /* if NULL push nil */ + return 1; } -static void io_clock (void) { - lua_pushnumber(((double)clock())/CLOCKS_PER_SEC); +static int io_clock (lua_State *L) { + lua_pushnumber(L, ((double)clock())/CLOCKS_PER_SEC); + return 1; } -static void io_date (void) { +static int io_date (lua_State *L) { char b[256]; - char *s = luaL_opt_string(1, "%c"); - struct tm *tm; + const char *s = luaL_opt_string(L, 1, "%c"); + struct tm *stm; time_t t; - time(&t); tm = localtime(&t); - if (strftime(b,sizeof(b),s,tm)) - lua_pushstring(b); + time(&t); stm = localtime(&t); + if (strftime(b, sizeof(b), s, stm)) + lua_pushstring(L, b); else - lua_error("invalid `date' format"); + lua_error(L, "invalid `date' format"); + return 1; } -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", +static int setloc (lua_State *L) { + static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, + LC_NUMERIC, LC_TIME}; + static const char *const catnames[] = {"all", "collate", "ctype", "monetary", "numeric", "time", NULL}; - int op = luaL_findstring(luaL_opt_string(2, "all"), catnames); - luaL_arg_check(op != -1, 2, "invalid option"); - lua_pushstring(setlocale(cat[op], luaL_check_string(1))); + int op = luaL_findstring(luaL_opt_string(L, 2, "all"), catnames); + luaL_arg_check(L, op != -1, 2, "invalid option"); + lua_pushstring(L, setlocale(cat[op], luaL_check_string(L, 1))); + return 1; } -static void io_exit (void) { - lua_Object o = lua_getparam(1); - exit(lua_isnumber(o) ? (int)lua_getnumber(o) : 1); +static int io_exit (lua_State *L) { + exit(luaL_opt_int(L, 1, EXIT_SUCCESS)); + return 0; /* to avoid warnings */ } /* }====================================================== */ -static void io_debug (void) { +static int io_debug (lua_State *L) { for (;;) { char buffer[250]; fprintf(stderr, "lua_debug> "); if (fgets(buffer, sizeof(buffer), stdin) == 0 || strcmp(buffer, "cont\n") == 0) - return; - lua_dostring(buffer); + return 0; + lua_dostring(L, buffer); + lua_settop(L, 0); /* remove eventual returns */ } } +#define LEVELS1 12 /* size of the first part of the stack */ +#define LEVELS2 10 /* size of the second part of the stack */ -#define MESSAGESIZE 150 -#define MAXMESSAGE (MESSAGESIZE*10) - - -#define MAXSRC 60 - - -static void errorfb (void) { - char buff[MAXMESSAGE]; +static int errorfb (lua_State *L) { 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 *chunkname; - char buffchunk[MAXSRC]; - int linedefined; - 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 */ + int firstpart = 1; /* still before eventual `...' */ + lua_Debug ar; + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addstring(&b, "error: "); + luaL_addstring(&b, luaL_check_string(L, 1)); + luaL_addstring(&b, "\n"); + while (lua_getstack(L, level++, &ar)) { + char buff[120]; /* enough to fit following `sprintf's */ + if (level == 2) + luaL_addstring(&b, "stack traceback:\n"); + else if (level > LEVELS1 && firstpart) { + /* no more than `LEVELS2' more levels? */ + if (!lua_getstack(L, level+LEVELS2, &ar)) + level--; /* keep going */ + else { + luaL_addstring(&b, " ...\n"); /* too many levels */ + while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */ + level++; + } + firstpart = 0; + continue; } - switch (*lua_getobjname(func, &name)) { - case 'g': - sprintf(buff+strlen(buff), "function `%.50s'", name); + sprintf(buff, "%4d: ", level-1); + luaL_addstring(&b, buff); + lua_getinfo(L, "Snl", &ar); + switch (*ar.namewhat) { + case 'g': case 'l': /* global, local */ + sprintf(buff, "function `%.50s'", ar.name); break; - case 't': - sprintf(buff+strlen(buff), "`%.50s' tag method", name); + case 'f': /* field */ + sprintf(buff, "method `%.50s'", ar.name); + break; + case 't': /* tag method */ + sprintf(buff, "`%.50s' tag method", ar.name); break; default: { - if (linedefined == 0) - sprintf(buff+strlen(buff), "main of %.70s", buffchunk); - else if (linedefined < 0) - sprintf(buff+strlen(buff), "%.70s", buffchunk); + if (*ar.what == 'm') /* main? */ + sprintf(buff, "main of %.70s", ar.short_src); + else if (*ar.what == 'C') /* C function? */ + sprintf(buff, "%.70s", ar.short_src); else - sprintf(buff+strlen(buff), "function <%d:%.70s>", - linedefined, buffchunk); - chunkname = NULL; + sprintf(buff, "function <%d:%.70s>", ar.linedefined, ar.short_src); + ar.source = NULL; /* do not print source again */ } } - if ((currentline = lua_currentline(func)) > 0) - sprintf(buff+strlen(buff), " at line %d", currentline); - if (chunkname) - sprintf(buff+strlen(buff), " [%.70s]", buffchunk); - strcat(buff, "\n"); + luaL_addstring(&b, buff); + if (ar.currentline > 0) { + sprintf(buff, " at line %d", ar.currentline); + luaL_addstring(&b, buff); + } + if (ar.source) { + sprintf(buff, " [%.70s]", ar.short_src); + luaL_addstring(&b, buff); + } + luaL_addstring(&b, "\n"); } - func = lua_rawgetglobal("_ALERT"); - if (lua_isfunction(func)) { /* avoid error loop if _ALERT is not defined */ - lua_pushstring(buff); - lua_callfunction(func); + luaL_pushresult(&b); + lua_getglobal(L, LUA_ALERT); + if (lua_isfunction(L, -1)) { /* avoid loop if _ALERT is not defined */ + lua_pushvalue(L, -2); /* error message */ + lua_rawcall(L, 1, 0); } + return 0; } -static struct luaL_reg iolib[] = { - {"_ERRORMESSAGE", errorfb}, +static const struct luaL_reg iolib[] = { + {LUA_ERRORMESSAGE, errorfb}, {"clock", io_clock}, {"date", io_date}, {"debug", io_debug}, @@ -540,7 +670,7 @@ static struct luaL_reg iolib[] = { }; -static struct luaL_reg iolibtag[] = { +static const struct luaL_reg iolibtag[] = { {"appendto", io_appendto}, {"closefile", io_close}, {"flush", io_flush}, @@ -553,31 +683,36 @@ static struct luaL_reg iolibtag[] = { }; -static void openwithtags (void) { - int i; - int iotag = lua_newtag(); - lua_newtag(); /* alloc CLOSEDTAG: assume that CLOSEDTAG = iotag-1 */ +static void openwithcontrol (lua_State *L) { + IOCtrl *ctrl = (IOCtrl *)lua_newuserdata(L, sizeof(IOCtrl)); + unsigned int i; + ctrl->iotag = lua_newtag(L); + ctrl->closedtag = lua_newtag(L); for (i=0; i<sizeof(iolibtag)/sizeof(iolibtag[0]); i++) { - /* put iotag as upvalue for these functions */ - lua_pushnumber(iotag); - lua_pushcclosure(iolibtag[i].func, 1); - lua_setglobal(iolibtag[i].name); + /* put `ctrl' as upvalue for these functions */ + lua_pushvalue(L, -1); + lua_pushcclosure(L, iolibtag[i].func, 1); + lua_setglobal(L, iolibtag[i].name); } + /* create references to variable names */ + lua_pushstring(L, filenames[INFILE]); + ctrl->ref[INFILE] = lua_ref(L, 1); + lua_pushstring(L, filenames[OUTFILE]); + ctrl->ref[OUTFILE] = lua_ref(L, 1); /* 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) { - /* register lib functions */ - luaL_openlib(iolib, (sizeof(iolib)/sizeof(iolib[0]))); - openwithtags(); + setfile(L, ctrl, stdin, INFILE); + setfile(L, ctrl, stdout, OUTFILE); + setfilebyname(L, ctrl, stdin, "_STDIN"); + setfilebyname(L, ctrl, stdout, "_STDOUT"); + setfilebyname(L, ctrl, stderr, "_STDERR"); + /* close files when collected */ + lua_pushcclosure(L, file_collect, 1); /* pops `ctrl' from stack */ + lua_settagmethod(L, ctrl->iotag, "gc"); +} + + +LUALIB_API void lua_iolibopen (lua_State *L) { + luaL_openl(L, iolib); + openwithcontrol(L); } diff --git a/src/lib/lmathlib.c b/src/lib/lmathlib.c index 19cb11c2..c062cf49 100644 --- a/src/lib/lmathlib.c +++ b/src/lib/lmathlib.c @@ -1,6 +1,6 @@ /* -** $Id: lmathlib.c,v 1.17 1999/07/07 17:54:08 roberto Exp $ -** Lua standard mathematical library +** $Id: lmathlib.c,v 1.32 2000/10/31 13:10:24 roberto Exp $ +** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -8,14 +8,15 @@ #include <stdlib.h> #include <math.h> -#include "lauxlib.h" #include "lua.h" + +#include "lauxlib.h" #include "lualib.h" #undef PI -#define PI (3.14159265358979323846) -#define RADIANS_PER_DEGREE (PI/180.0) +#define PI (3.14159265358979323846) +#define RADIANS_PER_DEGREE (PI/180.0) @@ -32,139 +33,173 @@ #endif -static void math_abs (void) { - lua_pushnumber(fabs(luaL_check_number(1))); +static int math_abs (lua_State *L) { + lua_pushnumber(L, fabs(luaL_check_number(L, 1))); + return 1; } -static void math_sin (void) { - lua_pushnumber(sin(TORAD(luaL_check_number(1)))); +static int math_sin (lua_State *L) { + lua_pushnumber(L, sin(TORAD(luaL_check_number(L, 1)))); + return 1; } -static void math_cos (void) { - lua_pushnumber(cos(TORAD(luaL_check_number(1)))); +static int math_cos (lua_State *L) { + lua_pushnumber(L, cos(TORAD(luaL_check_number(L, 1)))); + return 1; } -static void math_tan (void) { - lua_pushnumber(tan(TORAD(luaL_check_number(1)))); +static int math_tan (lua_State *L) { + lua_pushnumber(L, tan(TORAD(luaL_check_number(L, 1)))); + return 1; } -static void math_asin (void) { - lua_pushnumber(FROMRAD(asin(luaL_check_number(1)))); +static int math_asin (lua_State *L) { + lua_pushnumber(L, FROMRAD(asin(luaL_check_number(L, 1)))); + return 1; } -static void math_acos (void) { - lua_pushnumber(FROMRAD(acos(luaL_check_number(1)))); +static int math_acos (lua_State *L) { + lua_pushnumber(L, FROMRAD(acos(luaL_check_number(L, 1)))); + return 1; } -static void math_atan (void) { - lua_pushnumber(FROMRAD(atan(luaL_check_number(1)))); +static int math_atan (lua_State *L) { + lua_pushnumber(L, FROMRAD(atan(luaL_check_number(L, 1)))); + return 1; } -static void math_atan2 (void) { - lua_pushnumber(FROMRAD(atan2(luaL_check_number(1), luaL_check_number(2)))); +static int math_atan2 (lua_State *L) { + lua_pushnumber(L, FROMRAD(atan2(luaL_check_number(L, 1), luaL_check_number(L, 2)))); + return 1; } -static void math_ceil (void) { - lua_pushnumber(ceil(luaL_check_number(1))); +static int math_ceil (lua_State *L) { + lua_pushnumber(L, ceil(luaL_check_number(L, 1))); + return 1; } -static void math_floor (void) { - lua_pushnumber(floor(luaL_check_number(1))); +static int math_floor (lua_State *L) { + lua_pushnumber(L, floor(luaL_check_number(L, 1))); + return 1; } -static void math_mod (void) { - lua_pushnumber(fmod(luaL_check_number(1), luaL_check_number(2))); +static int math_mod (lua_State *L) { + lua_pushnumber(L, fmod(luaL_check_number(L, 1), luaL_check_number(L, 2))); + return 1; } -static void math_sqrt (void) { - lua_pushnumber(sqrt(luaL_check_number(1))); +static int math_sqrt (lua_State *L) { + lua_pushnumber(L, sqrt(luaL_check_number(L, 1))); + return 1; } -static void math_pow (void) { - lua_pushnumber(pow(luaL_check_number(1), luaL_check_number(2))); +static int math_pow (lua_State *L) { + lua_pushnumber(L, pow(luaL_check_number(L, 1), luaL_check_number(L, 2))); + return 1; } -static void math_log (void) { - lua_pushnumber(log(luaL_check_number(1))); +static int math_log (lua_State *L) { + lua_pushnumber(L, log(luaL_check_number(L, 1))); + return 1; } -static void math_log10 (void) { - lua_pushnumber(log10(luaL_check_number(1))); +static int math_log10 (lua_State *L) { + lua_pushnumber(L, log10(luaL_check_number(L, 1))); + return 1; } -static void math_exp (void) { - lua_pushnumber(exp(luaL_check_number(1))); +static int math_exp (lua_State *L) { + lua_pushnumber(L, exp(luaL_check_number(L, 1))); + return 1; } -static void math_deg (void) { - lua_pushnumber(luaL_check_number(1)/RADIANS_PER_DEGREE); +static int math_deg (lua_State *L) { + lua_pushnumber(L, luaL_check_number(L, 1)/RADIANS_PER_DEGREE); + return 1; } -static void math_rad (void) { - lua_pushnumber(luaL_check_number(1)*RADIANS_PER_DEGREE); +static int math_rad (lua_State *L) { + lua_pushnumber(L, luaL_check_number(L, 1)*RADIANS_PER_DEGREE); + return 1; } -static void math_frexp (void) { +static int math_frexp (lua_State *L) { int e; - lua_pushnumber(frexp(luaL_check_number(1), &e)); - lua_pushnumber(e); + lua_pushnumber(L, frexp(luaL_check_number(L, 1), &e)); + lua_pushnumber(L, e); + return 2; } -static void math_ldexp (void) { - lua_pushnumber(ldexp(luaL_check_number(1), luaL_check_int(2))); +static int math_ldexp (lua_State *L) { + lua_pushnumber(L, ldexp(luaL_check_number(L, 1), luaL_check_int(L, 2))); + return 1; } -static void math_min (void) { - int i = 1; - double dmin = luaL_check_number(i); - while (lua_getparam(++i) != LUA_NOOBJECT) { - double d = luaL_check_number(i); +static int math_min (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + double dmin = luaL_check_number(L, 1); + int i; + for (i=2; i<=n; i++) { + double d = luaL_check_number(L, i); if (d < dmin) dmin = d; } - lua_pushnumber(dmin); + lua_pushnumber(L, dmin); + return 1; } -static void math_max (void) { - int i = 1; - double dmax = luaL_check_number(i); - while (lua_getparam(++i) != LUA_NOOBJECT) { - double d = luaL_check_number(i); +static int math_max (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + double dmax = luaL_check_number(L, 1); + int i; + for (i=2; i<=n; i++) { + double d = luaL_check_number(L, i); if (d > dmax) dmax = d; } - lua_pushnumber(dmax); + lua_pushnumber(L, dmax); + return 1; } -static void math_random (void) { +static int math_random (lua_State *L) { /* 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 */ + some systems (SunOS!) "rand()" may return a value larger than RAND_MAX */ double r = (double)(rand()%RAND_MAX) / (double)RAND_MAX; - int l = luaL_opt_int(1, 0); - if (l == 0) - lua_pushnumber(r); - else { - int u = luaL_opt_int(2, 0); - if (u == 0) { - u = l; - l = 1; + switch (lua_gettop(L)) { /* check number of arguments */ + case 0: { /* no arguments */ + lua_pushnumber(L, r); /* Number between 0 and 1 */ + break; + } + case 1: { /* only upper limit */ + int u = luaL_check_int(L, 1); + luaL_arg_check(L, 1<=u, 1, "interval is empty"); + lua_pushnumber(L, (int)(r*u)+1); /* integer between 1 and `u' */ + break; + } + case 2: { /* lower and upper limits */ + int l = luaL_check_int(L, 1); + int u = luaL_check_int(L, 2); + luaL_arg_check(L, l<=u, 2, "interval is empty"); + lua_pushnumber(L, (int)(r*(u-l+1))+l); /* integer between `l' and `u' */ + break; } - luaL_arg_check(l<=u, 1, "interval is empty"); - lua_pushnumber((int)(r*(u-l+1))+l); + default: lua_error(L, "wrong number of arguments"); } + return 1; } -static void math_randomseed (void) { - srand(luaL_check_int(1)); +static int math_randomseed (lua_State *L) { + srand(luaL_check_int(L, 1)); + return 0; } -static struct luaL_reg mathlib[] = { +static const struct luaL_reg mathlib[] = { {"abs", math_abs}, {"sin", math_sin}, {"cos", math_cos}, @@ -193,11 +228,11 @@ static struct luaL_reg mathlib[] = { /* ** Open math library */ -void lua_mathlibopen (void) { - luaL_openlib(mathlib, (sizeof(mathlib)/sizeof(mathlib[0]))); - lua_pushcfunction(math_pow); - lua_pushnumber(0); /* to get its tag */ - lua_settagmethod(lua_tag(lua_pop()), "pow"); - lua_pushnumber(PI); lua_setglobal("PI"); +LUALIB_API void lua_mathlibopen (lua_State *L) { + luaL_openl(L, mathlib); + lua_pushcfunction(L, math_pow); + lua_settagmethod(L, LUA_TNUMBER, "pow"); + lua_pushnumber(L, PI); + lua_setglobal(L, "PI"); } diff --git a/src/lib/lstrlib.c b/src/lib/lstrlib.c index b47e21d3..8f286982 100644 --- a/src/lib/lstrlib.c +++ b/src/lib/lstrlib.c @@ -1,112 +1,111 @@ /* -** $Id: lstrlib.c,v 1.32 1999/06/17 17:04:03 roberto Exp $ -** Standard library for strings and pattern-matching +** $Id: lstrlib.c,v 1.56 2000/10/27 16:15:53 roberto Exp $ +** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ #include <ctype.h> +#include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include "lauxlib.h" #include "lua.h" -#include "lualib.h" - - - -static void addnchar (char *s, int n) -{ - char *b = luaL_openspace(n); - memcpy(b, s, n); - luaL_addsize(n); -} +#include "lauxlib.h" +#include "lualib.h" -static void str_len (void) -{ - long l; - luaL_check_lstr(1, &l); - lua_pushnumber(l); -} -static void closeandpush (void) { - lua_pushlstring(luaL_buffer(), luaL_getsize()); +static int str_len (lua_State *L) { + size_t l; + luaL_check_lstr(L, 1, &l); + lua_pushnumber(L, l); + return 1; } -static long posrelat (long pos, long len) { +static long posrelat (long pos, size_t len) { /* relative string position: negative means back from end */ - return (pos>=0) ? pos : len+pos+1; + return (pos>=0) ? pos : (long)len+pos+1; } -static void str_sub (void) { - long l; - char *s = luaL_check_lstr(1, &l); - long start = posrelat(luaL_check_long(2), l); - long end = posrelat(luaL_opt_long(3, -1), l); +static int str_sub (lua_State *L) { + size_t l; + const char *s = luaL_check_lstr(L, 1, &l); + long start = posrelat(luaL_check_long(L, 2), l); + long end = posrelat(luaL_opt_long(L, 3, -1), l); if (start < 1) start = 1; - if (end > l) end = l; + if (end > (long)l) end = l; if (start <= end) - lua_pushlstring(s+start-1, end-start+1); - else lua_pushstring(""); + lua_pushlstring(L, s+start-1, end-start+1); + else lua_pushstring(L, ""); + return 1; } -static void str_lower (void) { - long l; - int i; - char *s = luaL_check_lstr(1, &l); - luaL_resetbuffer(); +static int str_lower (lua_State *L) { + size_t l; + size_t i; + luaL_Buffer b; + const char *s = luaL_check_lstr(L, 1, &l); + luaL_buffinit(L, &b); for (i=0; i<l; i++) - luaL_addchar(tolower((unsigned char)(s[i]))); - closeandpush(); + luaL_putchar(&b, tolower((unsigned char)(s[i]))); + luaL_pushresult(&b); + return 1; } -static void str_upper (void) { - long l; - int i; - char *s = luaL_check_lstr(1, &l); - luaL_resetbuffer(); +static int str_upper (lua_State *L) { + size_t l; + size_t i; + luaL_Buffer b; + const char *s = luaL_check_lstr(L, 1, &l); + luaL_buffinit(L, &b); for (i=0; i<l; i++) - luaL_addchar(toupper((unsigned char)(s[i]))); - closeandpush(); + luaL_putchar(&b, toupper((unsigned char)(s[i]))); + luaL_pushresult(&b); + return 1; } -static void str_rep (void) -{ - long l; - char *s = luaL_check_lstr(1, &l); - int n = luaL_check_int(2); - luaL_resetbuffer(); +static int str_rep (lua_State *L) { + size_t l; + luaL_Buffer b; + const char *s = luaL_check_lstr(L, 1, &l); + int n = luaL_check_int(L, 2); + luaL_buffinit(L, &b); while (n-- > 0) - addnchar(s, l); - closeandpush(); + luaL_addlstring(&b, s, l); + luaL_pushresult(&b); + return 1; } -static void str_byte (void) { - long l; - char *s = luaL_check_lstr(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 int str_byte (lua_State *L) { + size_t l; + const char *s = luaL_check_lstr(L, 1, &l); + long pos = posrelat(luaL_opt_long(L, 2, 1), l); + luaL_arg_check(L, 0<pos && (size_t)pos<=l, 2, "out of range"); + lua_pushnumber(L, (unsigned char)s[pos-1]); + return 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((unsigned char)c); +static int str_char (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int i; + luaL_Buffer b; + luaL_buffinit(L, &b); + for (i=1; i<=n; i++) { + int c = luaL_check_int(L, i); + luaL_arg_check(L, (unsigned char)c == c, i, "invalid value"); + luaL_putchar(&b, (unsigned char)c); } - closeandpush(); + luaL_pushresult(&b); + return 1; } @@ -117,63 +116,53 @@ static void str_char (void) { ** ======================================================= */ -#ifndef MAX_CAPT -#define MAX_CAPT 32 /* arbitrary limit */ +#ifndef MAX_CAPTURES +#define MAX_CAPTURES 32 /* arbitrary limit */ #endif struct Capture { - char *src_end; /* end ('\0') of source string */ + const 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 */ - } capture[MAX_CAPT]; + const char *init; + long len; /* -1 signals unfinished capture */ + } capture[MAX_CAPTURES]; }; -#define ESC '%' -#define SPECIALS "^$*+?.([%-" +#define ESC '%' +#define SPECIALS "^$*+?.([%-" -static void push_captures (struct Capture *cap) { - int i; - 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_capture (lua_State *L, int l, struct Capture *cap) { l -= '1'; if (!(0 <= l && l < cap->level && cap->capture[l].len != -1)) - lua_error("invalid capture index"); + lua_error(L, "invalid capture index"); return l; } -static int capture_to_close (struct Capture *cap) { +static int capture_to_close (lua_State *L, struct Capture *cap) { int level = cap->level; for (level--; level>=0; level--) if (cap->capture[level].len == -1) return level; - lua_error("invalid pattern capture"); + lua_error(L, "invalid pattern capture"); return 0; /* to avoid warnings */ } -char *luaI_classend (char *p) { +const char *luaI_classend (lua_State *L, const char *p) { switch (*p++) { case ESC: - if (*p == '\0') - luaL_verror("incorrect pattern (ends with `%c')", ESC); + if (*p == '\0') lua_error(L, "malformed pattern (ends with `%')"); return p+1; case '[': if (*p == '^') p++; - if (*p == ']') p++; - p = strchr(p, ']'); - if (!p) lua_error("incorrect pattern (missing `]')"); + do { /* look for a ']' */ + if (*p == '\0') lua_error(L, "malformed pattern (missing `]')"); + if (*(p++) == ESC && *p != '\0') p++; /* skip escapes (e.g. '%]') */ + } while (*p != ']'); return p+1; default: return p; @@ -181,7 +170,7 @@ char *luaI_classend (char *p) { } -static int matchclass (int c, int cl) { +static int match_class (int c, int cl) { int res; switch (tolower(cl)) { case 'a' : res = isalpha(c); break; @@ -201,36 +190,36 @@ static int matchclass (int c, int cl) { -static int matchbracketclass (int c, char *p, char *end) { +static int matchbracketclass (int c, const char *p, const char *endclass) { int sig = 1; if (*(p+1) == '^') { sig = 0; p++; /* skip the '^' */ } - while (++p < end) { + while (++p < endclass) { if (*p == ESC) { p++; - if ((p < end) && matchclass(c, (unsigned char)*p)) + if (match_class(c, (unsigned char)*p)) return sig; } - else if ((*(p+1) == '-') && (p+2 < end)) { + else if ((*(p+1) == '-') && (p+2 < endclass)) { p+=2; if ((int)(unsigned char)*(p-2) <= c && c <= (int)(unsigned char)*p) return sig; } - else if ((unsigned char)*p == c) return sig; + else if ((int)(unsigned char)*p == c) return sig; } return !sig; } -int luaI_singlematch (int c, char *p, char *ep) { +int luaI_singlematch (int c, const char *p, const char *ep) { switch (*p) { case '.': /* matches any char */ return 1; case ESC: - return matchclass(c, (unsigned char)*(p+1)); + return match_class(c, (unsigned char)*(p+1)); case '[': return matchbracketclass(c, p, ep-1); default: @@ -239,12 +228,14 @@ int luaI_singlematch (int c, char *p, char *ep) { } -static char *match (char *s, char *p, struct Capture *cap); +static const char *match (lua_State *L, const char *s, const char *p, + struct Capture *cap); -static char *matchbalance (char *s, char *p, struct Capture *cap) { +static const char *matchbalance (lua_State *L, const char *s, const char *p, + struct Capture *cap) { if (*p == 0 || *(p+1) == 0) - lua_error("unbalanced pattern"); + lua_error(L, "unbalanced pattern"); if (*s != *p) return NULL; else { int b = *p; @@ -261,13 +252,14 @@ static char *matchbalance (char *s, char *p, struct Capture *cap) { } -static char *max_expand (char *s, char *p, char *ep, struct Capture *cap) { - int i = 0; /* counts maximum expand for item */ +static const char *max_expand (lua_State *L, const char *s, const char *p, + const char *ep, struct Capture *cap) { + long 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 */ + /* keeps trying to match with the maximum repetitions */ while (i>=0) { - char *res = match((s+i), ep+1, cap); + const char *res = match(L, (s+i), ep+1, cap); if (res) return res; i--; /* else didn't match; reduce 1 repetition to try again */ } @@ -275,9 +267,10 @@ static char *max_expand (char *s, char *p, char *ep, struct Capture *cap) { } -static char *min_expand (char *s, char *p, char *ep, struct Capture *cap) { +static const char *min_expand (lua_State *L, const char *s, const char *p, + const char *ep, struct Capture *cap) { for (;;) { - char *res = match(s, ep+1, cap); + const char *res = match(L, s, ep+1, cap); if (res != NULL) return res; else if (s<cap->src_end && luaI_singlematch((unsigned char)*s, p, ep)) @@ -287,56 +280,60 @@ static char *min_expand (char *s, char *p, char *ep, struct Capture *cap) { } -static char *start_capt (char *s, char *p, struct Capture *cap) { - char *res; +static const char *start_capture (lua_State *L, const char *s, const char *p, + struct Capture *cap) { + const char *res; int level = cap->level; - if (level >= MAX_CAPT) lua_error("too many captures"); + if (level >= MAX_CAPTURES) lua_error(L, "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? */ + if ((res=match(L, 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; +static const char *end_capture (lua_State *L, const char *s, const char *p, + struct Capture *cap) { + int l = capture_to_close(L, cap); + const char *res; cap->capture[l].len = s - cap->capture[l].init; /* close capture */ - if ((res = match(s, p+1, cap)) == NULL) /* match failed? */ + if ((res = match(L, 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 && +static const char *match_capture (lua_State *L, const char *s, int level, + struct Capture *cap) { + int l = check_capture(L, level, cap); + size_t len = cap->capture[l].len; + if ((size_t)(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) { +static const char *match (lua_State *L, const char *s, const char *p, + struct Capture *cap) { init: /* using goto's to optimize tail recursion */ switch (*p) { case '(': /* start capture */ - return start_capt(s, p, cap); + return start_capture(L, s, p, cap); case ')': /* end capture */ - return end_capt(s, p, cap); + return end_capture(L, 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); + s = match_capture(L, s, *(p+1), cap); if (s == NULL) return NULL; - p+=2; goto init; /* else return match(p+2, s, cap) */ + p+=2; goto init; /* else return match(L, s, p+2, cap) */ } else if (*(p+1) == 'b') { /* balanced string? */ - s = matchbalance(s, p+2, cap); + s = matchbalance(L, s, p+2, cap); if (s == NULL) return NULL; - p+=4; goto init; /* else return match(p+4, s, cap); */ + p+=4; goto init; /* else return match(L, s, p+4, cap); */ } else goto dflt; /* case default */ case '\0': /* end of pattern */ @@ -346,178 +343,208 @@ static char *match (char *s, char *p, struct Capture *cap) { 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 */ + const char *ep = luaI_classend(L, p); /* points to what is next */ int m = s<cap->src_end && luaI_singlematch((unsigned char)*s, p, ep); switch (*ep) { case '?': { /* optional */ - char *res; - if (m && ((res=match(s+1, ep+1, cap)) != NULL)) + const char *res; + if (m && ((res=match(L, s+1, ep+1, cap)) != NULL)) return res; - p=ep+1; goto init; /* else return match(s, ep+1, cap); */ + p=ep+1; goto init; /* else return match(L, s, ep+1, cap); */ } case '*': /* 0 or more repetitions */ - return max_expand(s, p, ep, cap); + return max_expand(L, s, p, ep, cap); case '+': /* 1 or more repetitions */ - return (m ? max_expand(s+1, p, ep, cap) : NULL); + return (m ? max_expand(L, s+1, p, ep, cap) : NULL); case '-': /* 0 or more repetitions (minimum) */ - return min_expand(s, p, ep, cap); + return min_expand(L, s, p, ep, cap); default: if (!m) return NULL; - s++; p=ep; goto init; /* else return match(s+1, ep, cap); */ + s++; p=ep; goto init; /* else return match(L, s+1, ep, cap); */ + } + } + } +} + + + +static const char *lmemfind (const char *s1, size_t l1, + const char *s2, size_t l2) { + if (l2 == 0) return s1; /* empty strings are everywhere */ + else if (l2 > l1) return NULL; /* avoids a negative `l1' */ + else { + const char *init; /* to search for a `*s2' inside `s1' */ + l2--; /* 1st char will be checked by `memchr' */ + l1 = l1-l2; /* `s2' cannot be found after that */ + while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { + init++; /* 1st char is already checked */ + if (memcmp(init, s2+1, l2) == 0) + return init-1; + else { /* correct `l1' and `s1' to try again */ + l1 -= init-s1; + s1 = init; } } + return NULL; /* not found */ } } -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_long(3, 1), l) - 1; +static int push_captures (lua_State *L, struct Capture *cap) { + int i; + luaL_checkstack(L, cap->level, "too many captures"); + for (i=0; i<cap->level; i++) { + int l = cap->capture[i].len; + if (l == -1) lua_error(L, "unfinished capture"); + lua_pushlstring(L, cap->capture[i].init, l); + } + return cap->level; /* number of strings pushed */ +} + + +static int str_find (lua_State *L) { + size_t l1, l2; + const char *s = luaL_check_lstr(L, 1, &l1); + const char *p = luaL_check_lstr(L, 2, &l2); + long init = posrelat(luaL_opt_long(L, 3, 1), l1) - 1; struct Capture cap; - luaL_arg_check(0 <= init && init <= l, 3, "out of range"); - if (lua_getparam(4) != LUA_NOOBJECT || - strpbrk(p, SPECIALS) == NULL) { /* no special characters? */ - char *s2 = strstr(s+init, p); + luaL_arg_check(L, 0 <= init && (size_t)init <= l1, 3, "out of range"); + if (lua_gettop(L) > 3 || /* extra argument? */ + strpbrk(p, SPECIALS) == NULL) { /* or no special characters? */ + const char *s2 = lmemfind(s+init, l1-init, p, l2); if (s2) { - lua_pushnumber(s2-s+1); - lua_pushnumber(s2-s+strlen(p)); - return; + lua_pushnumber(L, s2-s+1); + lua_pushnumber(L, s2-s+l2); + return 2; } } else { int anchor = (*p == '^') ? (p++, 1) : 0; - char *s1=s+init; - cap.src_end = s+l; + const char *s1=s+init; + cap.src_end = s+l1; do { - char *res; + const char *res; cap.level = 0; - if ((res=match(s1, p, &cap)) != NULL) { - lua_pushnumber(s1-s+1); /* start */ - lua_pushnumber(res-s); /* end */ - push_captures(&cap); - return; + if ((res=match(L, s1, p, &cap)) != NULL) { + lua_pushnumber(L, s1-s+1); /* start */ + lua_pushnumber(L, res-s); /* end */ + return push_captures(L, &cap) + 2; } } while (s1++<cap.src_end && !anchor); } - lua_pushnil(); /* if arrives here, it didn't find */ + lua_pushnil(L); /* not found */ + return 1; } -static void add_s (lua_Object newp, struct Capture *cap) { - if (lua_isstring(newp)) { - char *news = lua_getstring(newp); - int l = lua_strlen(newp); - int i; +static void add_s (lua_State *L, luaL_Buffer *b, struct Capture *cap) { + if (lua_isstring(L, 3)) { + const char *news = lua_tostring(L, 3); + size_t l = lua_strlen(L, 3); + size_t i; for (i=0; i<l; i++) { if (news[i] != ESC) - luaL_addchar(news[i]); + luaL_putchar(b, news[i]); else { i++; /* skip ESC */ if (!isdigit((unsigned char)news[i])) - luaL_addchar(news[i]); + luaL_putchar(b, news[i]); else { - int level = check_cap(news[i], cap); - addnchar(cap->capture[level].init, cap->capture[level].len); + int level = check_capture(L, news[i], cap); + luaL_addlstring(b, cap->capture[level].init, cap->capture[level].len); } } } } else { /* is a function */ - lua_Object res; - int status; - int oldbuff; - lua_beginblock(); - push_captures(cap); - /* function may use buffer, so save it and create a new one */ - oldbuff = luaL_newbuffer(0); - status = lua_callfunction(newp); - /* restore old buffer */ - luaL_oldbuffer(oldbuff); - if (status != 0) { - lua_endblock(); - lua_error(NULL); - } - res = lua_getresult(1); - if (lua_isstring(res)) - addnchar(lua_getstring(res), lua_strlen(res)); - lua_endblock(); + int n; + lua_pushvalue(L, 3); + n = push_captures(L, cap); + lua_rawcall(L, n, 1); + if (lua_isstring(L, -1)) + luaL_addvalue(b); /* add return to accumulated result */ + else + lua_pop(L, 1); /* function result is not a string: pop it */ } } -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 = luaL_opt_int(4, srcl+1); +static int str_gsub (lua_State *L) { + size_t srcl; + const char *src = luaL_check_lstr(L, 1, &srcl); + const char *p = luaL_check_string(L, 2); + int max_s = luaL_opt_int(L, 4, srcl+1); int anchor = (*p == '^') ? (p++, 1) : 0; int n = 0; struct Capture cap; - luaL_arg_check(lua_isstring(newp) || lua_isfunction(newp), 3, - "string or function expected"); - luaL_resetbuffer(); + luaL_Buffer b; + luaL_arg_check(L, + lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)), + 3, "string or function expected"); + luaL_buffinit(L, &b); cap.src_end = src+srcl; while (n < max_s) { - char *e; + const char *e; cap.level = 0; - e = match(src, p, &cap); + e = match(L, src, p, &cap); if (e) { n++; - add_s(newp, &cap); + add_s(L, &b, &cap); } if (e && e>src) /* non empty match? */ src = e; /* skip it */ else if (src < cap.src_end) - luaL_addchar(*src++); + luaL_putchar(&b, *src++); else break; if (anchor) break; } - addnchar(src, cap.src_end-src); - closeandpush(); - lua_pushnumber(n); /* number of substitutions */ + luaL_addlstring(&b, src, cap.src_end-src); + luaL_pushresult(&b); + lua_pushnumber(L, n); /* number of substitutions */ + return 2; } /* }====================================================== */ -static void luaI_addquoted (int arg) { - long l; - char *s = luaL_check_lstr(arg, &l); - luaL_addchar('"'); +static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) { + size_t l; + const char *s = luaL_check_lstr(L, arg, &l); + luaL_putchar(b, '"'); while (l--) { switch (*s) { case '"': case '\\': case '\n': - luaL_addchar('\\'); - luaL_addchar(*s); + luaL_putchar(b, '\\'); + luaL_putchar(b, *s); break; - case '\0': addnchar("\\000", 4); break; - default: luaL_addchar(*s); + case '\0': luaL_addlstring(b, "\\000", 4); break; + default: luaL_putchar(b, *s); } s++; } - luaL_addchar('"'); + luaL_putchar(b, '"'); } +/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ +#define MAX_ITEM 512 /* maximum size of each format specification (such as '%-099.99d') */ -#define MAX_FORMAT 20 /* arbitrary limit */ +#define MAX_FORMAT 20 -static void str_format (void) { +static int str_format (lua_State *L) { int arg = 1; - char *strfrmt = luaL_check_string(arg); - luaL_resetbuffer(); + const char *strfrmt = luaL_check_string(L, arg); + luaL_Buffer b; + luaL_buffinit(L, &b); while (*strfrmt) { if (*strfrmt != '%') - luaL_addchar(*strfrmt++); + luaL_putchar(&b, *strfrmt++); else if (*++strfrmt == '%') - luaL_addchar(*strfrmt++); /* %% */ + luaL_putchar(&b, *strfrmt++); /* %% */ else { /* format item */ struct Capture cap; char form[MAX_FORMAT]; /* to store the format ('%...') */ - char *buff; /* to store the formatted item */ - char *initf = strfrmt; + char buff[MAX_ITEM]; /* to store the formatted item */ + const char *initf = strfrmt; form[0] = '%'; if (isdigit((unsigned char)*initf) && *(initf+1) == '$') { arg = *initf - '0'; @@ -526,33 +553,33 @@ static void str_format (void) { arg++; cap.src_end = strfrmt+strlen(strfrmt)+1; cap.level = 0; - strfrmt = match(initf, "[-+ #0]*(%d*)%.?(%d*)", &cap); + strfrmt = match(L, initf, "[-+ #0]*(%d*)%.?(%d*)", &cap); 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)"); + lua_error(L, "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(512); /* 512 > size of format('%99.99f', -1e308) */ switch (*strfrmt++) { case 'c': case 'd': case 'i': - sprintf(buff, form, luaL_check_int(arg)); + sprintf(buff, form, luaL_check_int(L, arg)); break; case 'o': case 'u': case 'x': case 'X': - sprintf(buff, form, (unsigned int)luaL_check_number(arg)); + sprintf(buff, form, (unsigned int)luaL_check_number(L, arg)); break; case 'e': case 'E': case 'f': case 'g': case 'G': - sprintf(buff, form, luaL_check_number(arg)); + sprintf(buff, form, luaL_check_number(L, arg)); break; case 'q': - luaI_addquoted(arg); + luaI_addquoted(L, &b, arg); continue; /* skip the "addsize" at the end */ case 's': { - long l; - char *s = luaL_check_lstr(arg, &l); + size_t l; + const char *s = luaL_check_lstr(L, arg, &l); if (cap.capture[1].len == 0 && l >= 100) { - /* no precision and string is too big to be formatted; + /* no precision and string is too long to be formatted; keep original string */ - addnchar(s, l); + lua_pushvalue(L, arg); + luaL_addvalue(&b); continue; /* skip the "addsize" at the end */ } else { @@ -561,16 +588,17 @@ static void str_format (void) { } } default: /* also treat cases 'pnLlh' */ - lua_error("invalid option in `format'"); + lua_error(L, "invalid option in `format'"); } - luaL_addsize(strlen(buff)); + luaL_addlstring(&b, buff, strlen(buff)); } } - closeandpush(); /* push the result */ + luaL_pushresult(&b); + return 1; } -static struct luaL_reg strlib[] = { +static const struct luaL_reg strlib[] = { {"strlen", str_len}, {"strsub", str_sub}, {"strlower", str_lower}, @@ -588,7 +616,6 @@ static struct luaL_reg strlib[] = { /* ** Open string library */ -void strlib_open (void) -{ - luaL_openlib(strlib, (sizeof(strlib)/sizeof(strlib[0]))); +LUALIB_API void lua_strlibopen (lua_State *L) { + luaL_openl(L, strlib); } |