Update of /cvsroot/wxlua/wxLua/modules/lua/src/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14733/wxLua/modules/lua/src/lib Added Files: Makefile README lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loadlib.c lstrlib.c ltablib.c Log Message: moved files to the modules directory structure --- NEW FILE: liolib.c --- /* ** $Id: liolib.c,v 1.1 2005/06/06 23:06:16 jrl1 Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ #include <errno.h> #include <locale.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #define liolib_c #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* ** by default, gcc does not get `tmpname' */ #ifndef USE_TMPNAME #ifdef __GNUC__ #define USE_TMPNAME 0 #else #define USE_TMPNAME 1 #endif #endif /* ** by default, posix systems get `popen' */ #ifndef USE_POPEN #ifdef _POSIX_C_SOURCE #if _POSIX_C_SOURCE >= 2 #define USE_POPEN 1 #endif #endif #endif #ifndef USE_POPEN #define USE_POPEN 0 #endif /* ** {====================================================== ** FILE Operations ** ======================================================= */ #if !USE_POPEN #define pclose(f) (-1) #endif #define FILEHANDLE "FILE*" #define IO_INPUT "_input" #define IO_OUTPUT "_output" static int pushresult (lua_State *L, int i, const char *filename) { if (i) { lua_pushboolean(L, 1); return 1; } else { lua_pushnil(L); if (filename) lua_pushfstring(L, "%s: %s", filename, strerror(errno)); else lua_pushfstring(L, "%s", strerror(errno)); lua_pushnumber(L, errno); return 3; } } static FILE **topfile (lua_State *L, int findex) { FILE **f = (FILE **)luaL_checkudata(L, findex, FILEHANDLE); if (f == NULL) luaL_argerror(L, findex, "bad file"); return f; } static int io_type (lua_State *L) { FILE **f = (FILE **)luaL_checkudata(L, 1, FILEHANDLE); if (f == NULL) lua_pushnil(L); else if (*f == NULL) lua_pushliteral(L, "closed file"); else lua_pushliteral(L, "file"); return 1; } static FILE *tofile (lua_State *L, int findex) { FILE **f = topfile(L, findex); if (*f == NULL) luaL_error(L, "attempt to use a closed file"); return *f; } /* ** When creating file handles, always creates a `closed' file handle ** before opening the actual file; so, if there is a memory error, the ** file is not left opened. */ static FILE **newfile (lua_State *L) { FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); *pf = NULL; /* file handle is currently `closed' */ luaL_getmetatable(L, FILEHANDLE); lua_setmetatable(L, -2); return pf; } /* ** assumes that top of the stack is the `io' library, and next is ** the `io' metatable */ static void registerfile (lua_State *L, FILE *f, const char *name, const char *impname) { lua_pushstring(L, name); *newfile(L) = f; if (impname) { lua_pushstring(L, impname); lua_pushvalue(L, -2); lua_settable(L, -6); /* metatable[impname] = file */ } lua_settable(L, -3); /* io[name] = file */ } static int aux_close (lua_State *L) { FILE *f = tofile(L, 1); if (f == stdin || f == stdout || f == stderr) return 0; /* file cannot be closed */ else { int ok = (pclose(f) != -1) || (fclose(f) == 0); if (ok) *(FILE **)lua_touserdata(L, 1) = NULL; /* mark file as closed */ return ok; } } static int io_close (lua_State *L) { if (lua_isnone(L, 1) && lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE) { lua_pushstring(L, IO_OUTPUT); lua_rawget(L, lua_upvalueindex(1)); } return pushresult(L, aux_close(L), NULL); } static int io_gc (lua_State *L) { FILE **f = topfile(L, 1); if (*f != NULL) /* ignore closed files */ aux_close(L); return 0; } static int io_tostring (lua_State *L) { char buff[128]; FILE **f = topfile(L, 1); if (*f == NULL) strcpy(buff, "closed"); else sprintf(buff, "%p", lua_touserdata(L, 1)); lua_pushfstring(L, "file (%s)", buff); return 1; } static int io_open (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); FILE **pf = newfile(L); *pf = fopen(filename, mode); return (*pf == NULL) ? pushresult(L, 0, filename) : 1; } static int io_popen (lua_State *L) { #if !USE_POPEN luaL_error(L, "`popen' not supported"); return 0; #else const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); FILE **pf = newfile(L); *pf = popen(filename, mode); return (*pf == NULL) ? pushresult(L, 0, filename) : 1; #endif } static int io_tmpfile (lua_State *L) { FILE **pf = newfile(L); *pf = tmpfile(); return (*pf == NULL) ? pushresult(L, 0, NULL) : 1; } static FILE *getiofile (lua_State *L, const char *name) { lua_pushstring(L, name); lua_rawget(L, lua_upvalueindex(1)); return tofile(L, -1); } static int g_iofile (lua_State *L, const char *name, const char *mode) { if (!lua_isnoneornil(L, 1)) { const char *filename = lua_tostring(L, 1); lua_pushstring(L, name); if (filename) { FILE **pf = newfile(L); *pf = fopen(filename, mode); if (*pf == NULL) { lua_pushfstring(L, "%s: %s", filename, strerror(errno)); luaL_argerror(L, 1, lua_tostring(L, -1)); } } else { tofile(L, 1); /* check that it's a valid file handle */ lua_pushvalue(L, 1); } lua_rawset(L, lua_upvalueindex(1)); } /* return current value */ lua_pushstring(L, name); lua_rawget(L, lua_upvalueindex(1)); return 1; } static int io_input (lua_State *L) { return g_iofile(L, IO_INPUT, "r"); } static int io_output (lua_State *L) { return g_iofile(L, IO_OUTPUT, "w"); } static int io_readline (lua_State *L); static void aux_lines (lua_State *L, int idx, int close) { lua_pushliteral(L, FILEHANDLE); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, idx); lua_pushboolean(L, close); /* close/not close file when finished */ lua_pushcclosure(L, io_readline, 3); } static int f_lines (lua_State *L) { tofile(L, 1); /* check that it's a valid file handle */ aux_lines(L, 1, 0); return 1; } static int io_lines (lua_State *L) { if (lua_isnoneornil(L, 1)) { /* no arguments? */ lua_pushstring(L, IO_INPUT); lua_rawget(L, lua_upvalueindex(1)); /* will iterate over default input */ return f_lines(L); } else { const char *filename = luaL_checkstring(L, 1); FILE **pf = newfile(L); *pf = fopen(filename, "r"); luaL_argcheck(L, *pf, 1, strerror(errno)); aux_lines(L, lua_gettop(L), 1); return 1; } } /* ** {====================================================== ** READ ** ======================================================= */ static int read_number (lua_State *L, FILE *f) { lua_Number d; if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { lua_pushnumber(L, d); return 1; } else return 0; /* read fails */ } static int test_eof (lua_State *L, FILE *f) { int c = getc(f); ungetc(c, f); lua_pushlstring(L, NULL, 0); return (c != EOF); } static int read_line (lua_State *L, FILE *f) { luaL_Buffer b; luaL_buffinit(L, &b); for (;;) { size_t l; char *p = luaL_prepbuffer(&b); if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ luaL_pushresult(&b); /* close buffer */ return (lua_strlen(L, -1) > 0); /* check whether read something */ } l = strlen(p); if (p[l-1] != '\n') luaL_addsize(&b, l); else { luaL_addsize(&b, l - 1); /* do not include `eol' */ luaL_pushresult(&b); /* close buffer */ return 1; /* read at least an `eol' */ } } } static int read_chars (lua_State *L, FILE *f, size_t n) { size_t rlen; /* how much to read */ size_t nr; /* number of chars actually read */ luaL_Buffer b; luaL_buffinit(L, &b); rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ do { char *p = luaL_prepbuffer(&b); if (rlen > n) rlen = n; /* cannot read more than asked */ nr = fread(p, sizeof(char), rlen, f); luaL_addsize(&b, nr); n -= nr; /* still have to read `n' chars */ } while (n > 0 && nr == rlen); /* until end of count or eof */ luaL_pushresult(&b); /* close buffer */ return (n == 0 || lua_strlen(L, -1) > 0); } static int g_read (lua_State *L, FILE *f, int first) { int nargs = lua_gettop(L) - 1; int success; int n; if (nargs == 0) { /* no arguments? */ success = read_line(L, f); n = first+1; /* to return 1 result */ } else { /* ensure stack space for all results and for auxlib's buffer */ luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); success = 1; for (n = first; nargs-- && success; n++) { if (lua_type(L, n) == LUA_TNUMBER) { size_t l = (size_t)lua_tonumber(L, n); success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); } else { const char *p = lua_tostring(L, n); luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); switch (p[1]) { case 'n': /* number */ success = read_number(L, f); break; case 'l': /* line */ success = read_line(L, f); break; case 'a': /* file */ read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ success = 1; /* always success */ break; case 'w': /* word */ return luaL_error(L, "obsolete option `*w' to `read'"); default: return luaL_argerror(L, n, "invalid format"); } } } } if (!success) { lua_pop(L, 1); /* remove last result */ lua_pushnil(L); /* push nil instead */ } return n - first; } static int io_read (lua_State *L) { return g_read(L, getiofile(L, IO_INPUT), 1); } static int f_read (lua_State *L) { return g_read(L, tofile(L, 1), 2); } static int io_readline (lua_State *L) { FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(2)); if (f == NULL) /* file is already closed? */ luaL_error(L, "file is already closed"); if (read_line(L, f)) return 1; else { /* EOF */ if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ lua_settop(L, 0); lua_pushvalue(L, lua_upvalueindex(2)); aux_close(L); /* close it */ } return 0; } } /* }====================================================== */ static int g_write (lua_State *L, FILE *f, int arg) { int nargs = lua_gettop(L) - 1; int status = 1; for (; nargs--; arg++) { if (lua_type(L, arg) == LUA_TNUMBER) { /* optimization: could be done exactly as for strings */ status = status && fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; } else { size_t l; const char *s = luaL_checklstring(L, arg, &l); status = status && (fwrite(s, sizeof(char), l, f) == l); } } return pushresult(L, status, NULL); } static int io_write (lua_State *L) { return g_write(L, getiofile(L, IO_OUTPUT), 1); } static int f_write (lua_State *L) { return g_write(L, tofile(L, 1), 2); } static int f_seek (lua_State *L) { static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; static const char *const modenames[] = {"set", "cur", "end", NULL}; FILE *f = tofile(L, 1); int op = luaL_findstring(luaL_optstring(L, 2, "cur"), modenames); long offset = luaL_optlong(L, 3, 0); luaL_argcheck(L, op != -1, 2, "invalid mode"); op = fseek(f, offset, mode[op]); if (op) return pushresult(L, 0, NULL); /* error */ else { lua_pushnumber(L, ftell(f)); return 1; } } static int io_flush (lua_State *L) { return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); } static int f_flush (lua_State *L) { return pushresult(L, fflush(tofile(L, 1)) == 0, NULL); } static const luaL_reg iolib[] = { {"input", io_input}, {"output", io_output}, {"lines", io_lines}, {"close", io_close}, {"flush", io_flush}, {"open", io_open}, {"popen", io_popen}, {"read", io_read}, {"tmpfile", io_tmpfile}, {"type", io_type}, {"write", io_write}, {NULL, NULL} }; static const luaL_reg flib[] = { {"flush", f_flush}, {"read", f_read}, {"lines", f_lines}, {"seek", f_seek}, {"write", f_write}, {"close", io_close}, {"__gc", io_gc}, {"__tostring", io_tostring}, {NULL, NULL} }; static void createmeta (lua_State *L) { luaL_newmetatable(L, FILEHANDLE); /* create new metatable for file handles */ /* file methods */ lua_pushliteral(L, "__index"); lua_pushvalue(L, -2); /* push metatable */ lua_rawset(L, -3); /* metatable.__index = metatable */ luaL_openlib(L, NULL, flib, 0); } /* }====================================================== */ /* ** {====================================================== ** Other O.S. Operations ** ======================================================= */ static int io_execute (lua_State *L) { lua_pushnumber(L, system(luaL_checkstring(L, 1))); return 1; } static int io_remove (lua_State *L) { const char *filename = luaL_checkstring(L, 1); return pushresult(L, remove(filename) == 0, filename); } static int io_rename (lua_State *L) { const char *fromname = luaL_checkstring(L, 1); const char *toname = luaL_checkstring(L, 2); return pushresult(L, rename(fromname, toname) == 0, fromname); } static int io_tmpname (lua_State *L) { #if !USE_TMPNAME luaL_error(L, "`tmpname' not supported"); return 0; #else char buff[L_tmpnam]; if (tmpnam(buff) != buff) return luaL_error(L, "unable to generate a unique filename in `tmpname'"); lua_pushstring(L, buff); return 1; #endif } static int io_getenv (lua_State *L) { lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ return 1; } static int io_clock (lua_State *L) { lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); return 1; } /* ** {====================================================== ** Time/Date operations ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, ** wday=%w+1, yday=%j, isdst=? } ** ======================================================= */ static void setfield (lua_State *L, const char *key, int value) { lua_pushstring(L, key); lua_pushnumber(L, value); lua_rawset(L, -3); } static void setboolfield (lua_State *L, const char *key, int value) { lua_pushstring(L, key); lua_pushboolean(L, value); lua_rawset(L, -3); } static int getboolfield (lua_State *L, const char *key) { int res; lua_pushstring(L, key); lua_gettable(L, -2); res = lua_toboolean(L, -1); lua_pop(L, 1); return res; } static int getfield (lua_State *L, const char *key, int d) { int res; lua_pushstring(L, key); lua_gettable(L, -2); if (lua_isnumber(L, -1)) res = (int)(lua_tonumber(L, -1)); else { if (d == -2) return luaL_error(L, "field `%s' missing in date table", key); res = d; } lua_pop(L, 1); return res; } static int io_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); time_t t = (time_t)(luaL_optnumber(L, 2, -1)); struct tm *stm; if (t == (time_t)(-1)) /* no time given? */ t = time(NULL); /* use current time */ if (*s == '!') { /* UTC? */ stm = gmtime(&t); s++; /* skip `!' */ } else stm = localtime(&t); if (stm == NULL) /* invalid date? */ lua_pushnil(L); else if (strcmp(s, "*t") == 0) { lua_newtable(L); setfield(L, "sec", stm->tm_sec); setfield(L, "min", stm->tm_min); setfield(L, "hour", stm->tm_hour); setfield(L, "day", stm->tm_mday); setfield(L, "month", stm->tm_mon+1); setfield(L, "year", stm->tm_year+1900); setfield(L, "wday", stm->tm_wday+1); setfield(L, "yday", stm->tm_yday+1); setboolfield(L, "isdst", stm->tm_isdst); } else { char b[256]; if (strftime(b, sizeof(b), s, stm)) lua_pushstring(L, b); else return luaL_error(L, "`date' format too long"); } return 1; } static int io_time (lua_State *L) { if (lua_isnoneornil(L, 1)) /* called without args? */ lua_pushnumber(L, time(NULL)); /* return current time */ else { time_t t; struct tm ts; luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 1); /* make sure table is at the top */ ts.tm_sec = getfield(L, "sec", 0); ts.tm_min = getfield(L, "min", 0); ts.tm_hour = getfield(L, "hour", 12); ts.tm_mday = getfield(L, "day", -2); ts.tm_mon = getfield(L, "month", -2) - 1; ts.tm_year = getfield(L, "year", -2) - 1900; ts.tm_isdst = getboolfield(L, "isdst"); t = mktime(&ts); if (t == (time_t)(-1)) lua_pushnil(L); else lua_pushnumber(L, t); } return 1; } static int io_difftime (lua_State *L) { lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), (time_t)(luaL_optnumber(L, 2, 0)))); return 1; } /* }====================================================== */ static int io_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}; const char *l = lua_tostring(L, 1); int op = luaL_findstring(luaL_optstring(L, 2, "all"), catnames); luaL_argcheck(L, l || lua_isnoneornil(L, 1), 1, "string expected"); luaL_argcheck(L, op != -1, 2, "invalid option"); lua_pushstring(L, setlocale(cat[op], l)); return 1; } static int io_exit (lua_State *L) { exit(luaL_optint(L, 1, EXIT_SUCCESS)); return 0; /* to avoid warnings */ } static const luaL_reg syslib[] = { {"clock", io_clock}, {"date", io_date}, {"difftime", io_difftime}, {"execute", io_execute}, {"exit", io_exit}, {"getenv", io_getenv}, {"remove", io_remove}, {"rename", io_rename}, {"setlocale", io_setloc}, {"time", io_time}, {"tmpname", io_tmpname}, {NULL, NULL} }; /* }====================================================== */ LUALIB_API int luaopen_io (lua_State *L) { luaL_openlib(L, LUA_OSLIBNAME, syslib, 0); createmeta(L); lua_pushvalue(L, -1); luaL_openlib(L, LUA_IOLIBNAME, iolib, 1); /* put predefined file handles into `io' table */ registerfile(L, stdin, "stdin", IO_INPUT); registerfile(L, stdout, "stdout", IO_OUTPUT); registerfile(L, stderr, "stderr", NULL); return 1; } --- NEW FILE: lmathlib.c --- /* ** $Id: lmathlib.c,v 1.1 2005/06/06 23:06:16 jrl1 Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ #include <stdlib.h> #include <math.h> #define lmathlib_c #include "lua.h" #include "lauxlib.h" #include "lualib.h" #undef PI #define PI (3.14159265358979323846) #define RADIANS_PER_DEGREE (PI/180.0) /* ** If you want Lua to operate in degrees (instead of radians), ** define USE_DEGREES */ #ifdef USE_DEGREES #define FROMRAD(a) ((a)/RADIANS_PER_DEGREE) #define TORAD(a) ((a)*RADIANS_PER_DEGREE) #else #define FROMRAD(a) (a) #define TORAD(a) (a) #endif static int math_abs (lua_State *L) { lua_pushnumber(L, fabs(luaL_checknumber(L, 1))); return 1; } static int math_sin (lua_State *L) { lua_pushnumber(L, sin(TORAD(luaL_checknumber(L, 1)))); return 1; } static int math_cos (lua_State *L) { lua_pushnumber(L, cos(TORAD(luaL_checknumber(L, 1)))); return 1; } static int math_tan (lua_State *L) { lua_pushnumber(L, tan(TORAD(luaL_checknumber(L, 1)))); return 1; } static int math_asin (lua_State *L) { lua_pushnumber(L, FROMRAD(asin(luaL_checknumber(L, 1)))); return 1; } static int math_acos (lua_State *L) { lua_pushnumber(L, FROMRAD(acos(luaL_checknumber(L, 1)))); return 1; } static int math_atan (lua_State *L) { lua_pushnumber(L, FROMRAD(atan(luaL_checknumber(L, 1)))); return 1; } static int math_atan2 (lua_State *L) { lua_pushnumber(L, FROMRAD(atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2)))); return 1; } static int math_ceil (lua_State *L) { lua_pushnumber(L, ceil(luaL_checknumber(L, 1))); return 1; } static int math_floor (lua_State *L) { lua_pushnumber(L, floor(luaL_checknumber(L, 1))); return 1; } static int math_mod (lua_State *L) { lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int math_sqrt (lua_State *L) { lua_pushnumber(L, sqrt(luaL_checknumber(L, 1))); return 1; } static int math_pow (lua_State *L) { lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int math_log (lua_State *L) { lua_pushnumber(L, log(luaL_checknumber(L, 1))); return 1; } static int math_log10 (lua_State *L) { lua_pushnumber(L, log10(luaL_checknumber(L, 1))); return 1; } static int math_exp (lua_State *L) { lua_pushnumber(L, exp(luaL_checknumber(L, 1))); return 1; } static int math_deg (lua_State *L) { lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE); return 1; } static int math_rad (lua_State *L) { lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE); return 1; } static int math_frexp (lua_State *L) { int e; lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e)); lua_pushnumber(L, e); return 2; } static int math_ldexp (lua_State *L) { lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2))); return 1; } static int math_min (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ lua_Number dmin = luaL_checknumber(L, 1); int i; for (i=2; i<=n; i++) { lua_Number d = luaL_checknumber(L, i); if (d < dmin) dmin = d; } lua_pushnumber(L, dmin); return 1; } static int math_max (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ lua_Number dmax = luaL_checknumber(L, 1); int i; for (i=2; i<=n; i++) { lua_Number d = luaL_checknumber(L, i); if (d > dmax) dmax = d; } lua_pushnumber(L, dmax); return 1; } 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 larger than RAND_MAX */ lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX; 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_checkint(L, 1); luaL_argcheck(L, 1<=u, 1, "interval is empty"); lua_pushnumber(L, (int)floor(r*u)+1); /* int between 1 and `u' */ break; } case 2: { /* lower and upper limits */ int l = luaL_checkint(L, 1); int u = luaL_checkint(L, 2); luaL_argcheck(L, l<=u, 2, "interval is empty"); lua_pushnumber(L, (int)floor(r*(u-l+1))+l); /* int between `l' and `u' */ break; } default: return luaL_error(L, "wrong number of arguments"); } return 1; } static int math_randomseed (lua_State *L) { srand(luaL_checkint(L, 1)); return 0; } static const luaL_reg mathlib[] = { {"abs", math_abs}, {"sin", math_sin}, {"cos", math_cos}, {"tan", math_tan}, {"asin", math_asin}, {"acos", math_acos}, {"atan", math_atan}, {"atan2", math_atan2}, {"ceil", math_ceil}, {"floor", math_floor}, {"mod", math_mod}, {"frexp", math_frexp}, {"ldexp", math_ldexp}, {"sqrt", math_sqrt}, {"min", math_min}, {"max", math_max}, {"log", math_log}, {"log10", math_log10}, {"exp", math_exp}, {"deg", math_deg}, {"pow", math_pow}, {"rad", math_rad}, {"random", math_random}, {"randomseed", math_randomseed}, {NULL, NULL} }; /* ** Open math library */ LUALIB_API int luaopen_math (lua_State *L) { luaL_openlib(L, LUA_MATHLIBNAME, mathlib, 0); lua_pushliteral(L, "pi"); lua_pushnumber(L, PI); lua_settable(L, -3); lua_pushliteral(L, "__pow"); lua_pushcfunction(L, math_pow); lua_settable(L, LUA_GLOBALSINDEX); return 1; } --- NEW FILE: ltablib.c --- /* ** $Id: ltablib.c,v 1.1 2005/06/06 23:06:16 jrl1 Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ #include <stddef.h> #define ltablib_c #include "lua.h" #include "lauxlib.h" #include "lualib.h" #define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n)) static int luaB_foreachi (lua_State *L) { int i; int n = aux_getn(L, 1); luaL_checktype(L, 2, LUA_TFUNCTION); for (i=1; i<=n; i++) { lua_pushvalue(L, 2); /* function */ lua_pushnumber(L, (lua_Number)i); /* 1st argument */ lua_rawgeti(L, 1, i); /* 2nd argument */ lua_call(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 key */ 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_call(L, 2, 1); if (!lua_isnil(L, -1)) return 1; lua_pop(L, 2); /* remove value and result */ } } static int luaB_getn (lua_State *L) { lua_pushnumber(L, (lua_Number)aux_getn(L, 1)); return 1; } static int luaB_setn (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_setn(L, 1, luaL_checkint(L, 2)); return 0; } static int luaB_tinsert (lua_State *L) { int v = lua_gettop(L); /* number of arguments */ int n = aux_getn(L, 1) + 1; int pos; /* where to insert new element */ if (v == 2) /* called with only 2 arguments */ pos = n; /* insert new element at the end */ else { pos = luaL_checkint(L, 2); /* 2nd argument is the position */ if (pos > n) n = pos; /* `grow' array if necessary */ v = 3; /* function may be called with more than 3 args */ } luaL_setn(L, 1, n); /* new size */ while (--n >= pos) { /* move up elements */ 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 n = aux_getn(L, 1); int pos = luaL_optint(L, 2, n); if (n <= 0) return 0; /* table is `empty' */ luaL_setn(L, 1, n-1); /* t.n = n-1 */ lua_rawgeti(L, 1, pos); /* result = t[pos] */ for ( ;pos<n; pos++) { lua_rawgeti(L, 1, pos+1); lua_rawseti(L, 1, pos); /* t[pos] = t[pos+1] */ } lua_pushnil(L); lua_rawseti(L, 1, n); /* t[n] = nil */ return 1; } static int str_concat (lua_State *L) { luaL_Buffer b; size_t lsep; const char *sep = luaL_optlstring(L, 2, "", &lsep); int i = luaL_optint(L, 3, 1); int n = luaL_optint(L, 4, 0); luaL_checktype(L, 1, LUA_TTABLE); if (n == 0) n = luaL_getn(L, 1); luaL_buffinit(L, &b); for (; i <= n; i++) { lua_rawgeti(L, 1, i); luaL_argcheck(L, lua_isstring(L, -1), 1, "table contains non-strings"); luaL_addvalue(&b); if (i != n) luaL_addlstring(&b, sep, lsep); } luaL_pushresult(&b); 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) { 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_call(L, 2, 1); res = lua_toboolean(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) luaL_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) luaL_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 = aux_getn(L, 1); luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */ if (!lua_isnoneornil(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; } /* }====================================================== */ static const luaL_reg tab_funcs[] = { {"concat", str_concat}, {"foreach", luaB_foreach}, {"foreachi", luaB_foreachi}, {"getn", luaB_getn}, {"setn", luaB_setn}, {"sort", luaB_sort}, {"insert", luaB_tinsert}, {"remove", luaB_tremove}, {NULL, NULL} }; LUALIB_API int luaopen_table (lua_State *L) { luaL_openlib(L, LUA_TABLIBNAME, tab_funcs, 0); return 1; } --- NEW FILE: lstrlib.c --- /* ** $Id: lstrlib.c,v 1.1 2005/06/06 23:06:16 jrl1 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> #define lstrlib_c #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* macro to `unsign' a character */ #ifndef uchar #define uchar(c) ((unsigned char)(c)) #endif typedef long sint32; /* a signed version for size_t */ static int str_len (lua_State *L) { size_t l; luaL_checklstring(L, 1, &l); lua_pushnumber(L, (lua_Number)l); return 1; } static sint32 posrelat (sint32 pos, size_t len) { /* relative string position: negative means back from end */ return (pos>=0) ? pos : (sint32)len+pos+1; } static int str_sub (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); sint32 start = posrelat(luaL_checklong(L, 2), l); sint32 end = posrelat(luaL_optlong(L, 3, -1), l); if (start < 1) start = 1; if (end > (sint32)l) end = (sint32)l; if (start <= end) lua_pushlstring(L, s+start-1, end-start+1); else lua_pushliteral(L, ""); return 1; } static int str_lower (lua_State *L) { size_t l; size_t i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); luaL_buffinit(L, &b); for (i=0; i<l; i++) luaL_putchar(&b, tolower(uchar(s[i]))); luaL_pushresult(&b); return 1; } static int str_upper (lua_State *L) { size_t l; size_t i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); luaL_buffinit(L, &b); for (i=0; i<l; i++) luaL_putchar(&b, toupper(uchar(s[i]))); luaL_pushresult(&b); return 1; } static int str_rep (lua_State *L) { size_t l; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); int n = luaL_checkint(L, 2); luaL_buffinit(L, &b); while (n-- > 0) luaL_addlstring(&b, s, l); luaL_pushresult(&b); return 1; } static int str_byte (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); sint32 pos = posrelat(luaL_optlong(L, 2, 1), l); if (pos <= 0 || (size_t)(pos) > l) /* index out of range? */ return 0; /* no answer */ lua_pushnumber(L, uchar(s[pos-1])); return 1; } 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_checkint(L, i); luaL_argcheck(L, uchar(c) == c, i, "invalid value"); luaL_putchar(&b, uchar(c)); } luaL_pushresult(&b); return 1; } static int writer (lua_State *L, const void* b, size_t size, void* B) { (void)L; luaL_addlstring((luaL_Buffer*) B, (const char *)b, size); return 1; } static int str_dump (lua_State *L) { luaL_Buffer b; luaL_checktype(L, 1, LUA_TFUNCTION); luaL_buffinit(L,&b); if (!lua_dump(L, writer, &b)) luaL_error(L, "unable to dump given function"); luaL_pushresult(&b); return 1; } /* ** {====================================================== ** PATTERN MATCHING ** ======================================================= */ #ifndef MAX_CAPTURES #define MAX_CAPTURES 32 /* arbitrary limit */ #endif #define CAP_UNFINISHED (-1) #define CAP_POSITION (-2) typedef struct MatchState { const char *src_init; /* init of source string */ const char *src_end; /* end (`\0') of source string */ lua_State *L; int level; /* total number of captures (finished or unfinished) */ struct { const char *init; sint32 len; } capture[MAX_CAPTURES]; } MatchState; #define ESC '%' #define SPECIALS "^$*+?.([%-" static int check_capture (MatchState *ms, int l) { l -= '1'; if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) return luaL_error(ms->L, "invalid capture index"); return l; } static int capture_to_close (MatchState *ms) { int level = ms->level; for (level--; level>=0; level--) if (ms->capture[level].len == CAP_UNFINISHED) return level; return luaL_error(ms->L, "invalid pattern capture"); } static const char *luaI_classend (MatchState *ms, const char *p) { switch (*p++) { case ESC: { if (*p == '\0') luaL_error(ms->L, "malformed pattern (ends with `%')"); return p+1; } case '[': { if (*p == '^') p++; do { /* look for a `]' */ if (*p == '\0') luaL_error(ms->L, "malformed pattern (missing `]')"); if (*(p++) == ESC && *p != '\0') p++; /* skip escapes (e.g. `%]') */ } while (*p != ']'); return p+1; } default: { return p; } } } static int match_class (int c, int cl) { int res; switch (tolower(cl)) { case 'a' : res = isalpha(c); break; case 'c' : res = iscntrl(c); break; case 'd' : res = isdigit(c); break; case 'l' : res = islower(c); break; case 'p' : res = ispunct(c); break; 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(cl) ? res : !res); } static int matchbracketclass (int c, const char *p, const char *ec) { int sig = 1; if (*(p+1) == '^') { sig = 0; p++; /* skip the `^' */ } while (++p < ec) { if (*p == ESC) { p++; if (match_class(c, *p)) return sig; } else if ((*(p+1) == '-') && (p+2 < ec)) { p+=2; if (uchar(*(p-2)) <= c && c <= uchar(*p)) return sig; } else if (uchar(*p) == c) return sig; } return !sig; } static int luaI_singlematch (int c, const char *p, const char *ep) { switch (*p) { case '.': return 1; /* matches any char */ case ESC: return match_class(c, *(p+1)); case '[': return matchbracketclass(c, p, ep-1); default: return (uchar(*p) == c); } } static const char *match (MatchState *ms, const char *s, const char *p); static const char *matchbalance (MatchState *ms, const char *s, const char *p) { if (*p == 0 || *(p+1) == 0) luaL_error(ms->L, "unbalanced pattern"); if (*s != *p) return NULL; else { int b = *p; int e = *(p+1); int cont = 1; while (++s < ms->src_end) { if (*s == e) { if (--cont == 0) return s+1; } else if (*s == b) cont++; } } return NULL; /* string ends out of balance */ } static const char *max_expand (MatchState *ms, const char *s, const char *p, const char *ep) { sint32 i = 0; /* counts maximum expand for item */ while ((s+i)<ms->src_end && luaI_singlematch(uchar(*(s+i)), p, ep)) i++; /* keeps trying to match with the maximum repetitions */ while (i>=0) { const char *res = match(ms, (s+i), ep+1); if (res) return res; i--; /* else didn't match; reduce 1 repetition to try again */ } return NULL; } static const char *min_expand (MatchState *ms, const char *s, const char *p, const char *ep) { for (;;) { const char *res = match(ms, s, ep+1); if (res != NULL) return res; else if (s<ms->src_end && luaI_singlematch(uchar(*s), p, ep)) s++; /* try with one more repetition */ else return NULL; } } static const char *start_capture (MatchState *ms, const char *s, const char *p, int what) { const char *res; int level = ms->level; if (level >= MAX_CAPTURES) luaL_error(ms->L, "too many captures"); ms->capture[level].init = s; ms->capture[level].len = what; ms->level = level+1; if ((res=match(ms, s, p)) == NULL) /* match failed? */ ms->level--; /* undo capture */ return res; } static const char *end_capture (MatchState *ms, const char *s, const char *p) { int l = capture_to_close(ms); const char *res; ms->capture[l].len = s - ms->capture[l].init; /* close capture */ if ((res = match(ms, s, p)) == NULL) /* match failed? */ ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ return res; } static const char *match_capture (MatchState *ms, const char *s, int l) { size_t len; l = check_capture(ms, l); len = ms->capture[l].len; if ((size_t)(ms->src_end-s) >= len && memcmp(ms->capture[l].init, s, len) == 0) return s+len; else return NULL; } static const char *match (MatchState *ms, const char *s, const char *p) { init: /* using goto's to optimize tail recursion */ switch (*p) { case '(': { /* start capture */ if (*(p+1) == ')') /* position capture? */ return start_capture(ms, s, p+2, CAP_POSITION); else return start_capture(ms, s, p+1, CAP_UNFINISHED); } case ')': { /* end capture */ return end_capture(ms, s, p+1); } case ESC: { switch (*(p+1)) { case 'b': { /* balanced string? */ s = matchbalance(ms, s, p+2); if (s == NULL) return NULL; p+=4; goto init; /* else return match(ms, s, p+4); */ } case 'f': { /* frontier? */ const char *ep; char previous; p += 2; if (*p != '[') luaL_error(ms->L, "missing `[' after `%%f' in pattern"); ep = luaI_classend(ms, p); /* points to what is next */ previous = (char)((s == ms->src_init) ? '\0' : *(s-1)); if (matchbracketclass(uchar(previous), p, ep-1) || !matchbracketclass(uchar(*s), p, ep-1)) return NULL; p=ep; goto init; /* else return match(ms, s, ep); */ } default: { if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ s = match_capture(ms, s, *(p+1)); if (s == NULL) return NULL; p+=2; goto init; /* else return match(ms, s, p+2) */ } 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 == ms->src_end) ? s : NULL; /* check end of string */ else goto dflt; } default: dflt: { /* it is a pattern item */ const char *ep = luaI_classend(ms, p); /* points to what is next */ int m = s<ms->src_end && luaI_singlematch(uchar(*s), p, ep); switch (*ep) { case '?': { /* optional */ const char *res; if (m && ((res=match(ms, s+1, ep+1)) != NULL)) return res; p=ep+1; goto init; /* else return match(ms, s, ep+1); */ } case '*': { /* 0 or more repetitions */ return max_expand(ms, s, p, ep); } case '+': { /* 1 or more repetitions */ return (m ? max_expand(ms, s+1, p, ep) : NULL); } case '-': { /* 0 or more repetitions (minimum) */ return min_expand(ms, s, p, ep); } default: { if (!m) return NULL; s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ } } } } } 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 push_onecapture (MatchState *ms, int i) { int l = ms->capture[i].len; if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); if (l == CAP_POSITION) lua_pushnumber(ms->L, (lua_Number)(ms->capture[i].init - ms->src_init + 1)); else lua_pushlstring(ms->L, ms->capture[i].init, l); } static int push_captures (MatchState *ms, const char *s, const char *e) { int i; luaL_checkstack(ms->L, ms->level, "too many captures"); if (ms->level == 0 && s) { /* no explicit captures? */ lua_pushlstring(ms->L, s, e-s); /* return whole match */ return 1; } else { /* return all captures */ for (i=0; i<ms->level; i++) push_onecapture(ms, i); return ms->level; /* number of strings pushed */ } } static int str_find (lua_State *L) { size_t l1, l2; const char *s = luaL_checklstring(L, 1, &l1); const char *p = luaL_checklstring(L, 2, &l2); sint32 init = posrelat(luaL_optlong(L, 3, 1), l1) - 1; if (init < 0) init = 0; else if ((size_t)(init) > l1) init = (sint32)l1; if (lua_toboolean(L, 4) || /* explicit request? */ strpbrk(p, SPECIALS) == NULL) { /* or no special characters? */ /* do a plain search */ const char *s2 = lmemfind(s+init, l1-init, p, l2); if (s2) { lua_pushnumber(L, (lua_Number)(s2-s+1)); lua_pushnumber(L, (lua_Number)(s2-s+l2)); return 2; } } else { MatchState ms; int anchor = (*p == '^') ? (p++, 1) : 0; const char *s1=s+init; ms.L = L; ms.src_init = s; ms.src_end = s+l1; do { const char *res; ms.level = 0; if ((res=match(&ms, s1, p)) != NULL) { lua_pushnumber(L, (lua_Number)(s1-s+1)); /* start */ lua_pushnumber(L, (lua_Number)(res-s)); /* end */ return push_captures(&ms, NULL, 0) + 2; } } while (s1++<ms.src_end && !anchor); } lua_pushnil(L); /* not found */ return 1; } static int gfind_aux (lua_State *L) { MatchState ms; const char *s = lua_tostring(L, lua_upvalueindex(1)); size_t ls = lua_strlen(L, lua_upvalueindex(1)); const char *p = lua_tostring(L, lua_upvalueindex(2)); const char *src; ms.L = L; ms.src_init = s; ms.src_end = s+ls; for (src = s + (size_t)lua_tonumber(L, lua_upvalueindex(3)); src <= ms.src_end; src++) { const char *e; ms.level = 0; if ((e = match(&ms, src, p)) != NULL) { int newstart = e-s; if (e == src) newstart++; /* empty match? go at least one position */ lua_pushnumber(L, (lua_Number)newstart); lua_replace(L, lua_upvalueindex(3)); return push_captures(&ms, src, e); } } return 0; /* not found */ } static int gfind (lua_State *L) { luaL_checkstring(L, 1); luaL_checkstring(L, 2); lua_settop(L, 2); lua_pushnumber(L, 0); lua_pushcclosure(L, gfind_aux, 3); return 1; } static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, const char *e) { lua_State *L = ms->L; 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_putchar(b, news[i]); else { i++; /* skip ESC */ if (!isdigit(uchar(news[i]))) luaL_putchar(b, news[i]); else { int level = check_capture(ms, news[i]); push_onecapture(ms, level); luaL_addvalue(b); /* add capture to accumulated result */ } } } } else { /* is a function */ int n; lua_pushvalue(L, 3); n = push_captures(ms, s, e); lua_call(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 int str_gsub (lua_State *L) { size_t srcl; const char *src = luaL_checklstring(L, 1, &srcl); const char *p = luaL_checkstring(L, 2); int max_s = luaL_optint(L, 4, srcl+1); int anchor = (*p == '^') ? (p++, 1) : 0; int n = 0; MatchState ms; luaL_Buffer b; luaL_argcheck(L, lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)), 3, "string or function expected"); luaL_buffinit(L, &b); ms.L = L; ms.src_init = src; ms.src_end = src+srcl; while (n < max_s) { const char *e; ms.level = 0; e = match(&ms, src, p); if (e) { n++; add_s(&ms, &b, src, e); } if (e && e>src) /* non empty match? */ src = e; /* skip it */ else if (src < ms.src_end) luaL_putchar(&b, *src++); else break; if (anchor) break; } luaL_addlstring(&b, src, ms.src_end-src); luaL_pushresult(&b); lua_pushnumber(L, (lua_Number)n); /* number of substitutions */ return 2; } /* }====================================================== */ /* 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 static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) { size_t l; const char *s = luaL_checklstring(L, arg, &l); luaL_putchar(b, '"'); while (l--) { switch (*s) { case '"': case '\\': case '\n': { luaL_putchar(b, '\\'); luaL_putchar(b, *s); break; } case '\0': { luaL_addlstring(b, "\\000", 4); break; } default: { luaL_putchar(b, *s); break; } } s++; } luaL_putchar(b, '"'); } static const char *scanformat (lua_State *L, const char *strfrmt, char *form, int *hasprecision) { const char *p = strfrmt; while (strchr("-+ #0", *p)) p++; /* skip flags */ if (isdigit(uchar(*p))) p++; /* skip width */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ if (*p == '.') { p++; *hasprecision = 1; if (isdigit(uchar(*p))) p++; /* skip precision */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ } if (isdigit(uchar(*p))) luaL_error(L, "invalid format (width or precision too long)"); if (p-strfrmt+2 > MAX_FORMAT) /* +2 to include `%' and the specifier */ luaL_error(L, "invalid format (too long)"); form[0] = '%'; strncpy(form+1, strfrmt, p-strfrmt+1); form[p-strfrmt+2] = 0; return p; } static int str_format (lua_State *L) { int arg = 1; size_t sfl; const char *strfrmt = luaL_checklstring(L, arg, &sfl); const char *strfrmt_end = strfrmt+sfl; luaL_Buffer b; luaL_buffinit(L, &b); while (strfrmt < strfrmt_end) { if (*strfrmt != '%') luaL_putchar(&b, *strfrmt++); else if (*++strfrmt == '%') luaL_putchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format (`%...') */ char buff[MAX_ITEM]; /* to store the formatted item */ int hasprecision = 0; if (isdigit(uchar(*strfrmt)) && *(strfrmt+1) == '$') return luaL_error(L, "obsolete option (d$) to `format'"); arg++; strfrmt = scanformat(L, strfrmt, form, &hasprecision); switch (*strfrmt++) { case 'c': case 'd': case 'i': { sprintf(buff, form, luaL_checkint(L, arg)); break; } case 'o': case 'u': case 'x': case 'X': { sprintf(buff, form, (unsigned int)(luaL_checknumber(L, arg))); break; } case 'e': case 'E': case 'f': case 'g': case 'G': { sprintf(buff, form, luaL_checknumber(L, arg)); break; } case 'q': { luaI_addquoted(L, &b, arg); continue; /* skip the `addsize' at the end */ } case 's': { size_t l; const char *s = luaL_checklstring(L, arg, &l); if (!hasprecision && l >= 100) { /* no precision and string is too long to be formatted; keep original string */ lua_pushvalue(L, arg); luaL_addvalue(&b); continue; /* skip the `addsize' at the end */ } else { sprintf(buff, form, s); break; } } default: { /* also treat cases `pnLlh' */ return luaL_error(L, "invalid option to `format'"); } } luaL_addlstring(&b, buff, strlen(buff)); } } luaL_pushresult(&b); return 1; } static const luaL_reg strlib[] = { {"len", str_len}, {"sub", str_sub}, {"lower", str_lower}, {"upper", str_upper}, {"char", str_char}, {"rep", str_rep}, {"byte", str_byte}, {"format", str_format}, {"dump", str_dump}, {"find", str_find}, {"gfind", gfind}, {"gsub", str_gsub}, {NULL, NULL} }; /* ** Open string library */ LUALIB_API int luaopen_string (lua_State *L) { luaL_openlib(L, LUA_STRLIBNAME, strlib, 0); return 1; } --- NEW FILE: lauxlib.c --- /* ** $Id: lauxlib.c,v 1.1 2005/06/06 23:06:16 jrl1 Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ #include <ctype.h> #include <errno.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. */ #define lauxlib_c #include "lua.h" #include "lauxlib.h" /* number of prereserved references (for internal use) */ #define RESERVED_REFS 2 /* reserved references */ #define FREELIST_REF 1 /* free list of references */ #define ARRAYSIZE_REF 2 /* array sizes */ /* convert a stack index to positive */ #define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ lua_gettop(L) + (i) + 1) /* ** {====================================================== ** Error-report functions ** ======================================================= */ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { lua_Debug ar; lua_getstack(L, 0, &ar); lua_getinfo(L, "n", &ar); if (strcmp(ar.namewhat, "method") == 0) { narg--; /* do not count `self' */ if (narg == 0) /* error is in the self argument itself? */ return luaL_error(L, "calling `%s' on bad self (%s)", ar.name, extramsg); } if (ar.name == NULL) ar.name = "?"; return luaL_error(L, "bad argument #%d to `%s' (%s)", narg, ar.name, extramsg); } LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, lua_typename(L, lua_type(L,narg))); return luaL_argerror(L, narg, msg); } static void tag_error (lua_State *L, int narg, int tag) { luaL_typerror(L, narg, lua_typename(L, tag)); } LUALIB_API void luaL_where (lua_State *L, int level) { lua_Debug ar; if (lua_getstack(L, level, &ar)) { /* check function at level */ lua_getinfo(L, "Snl", &ar); /* get info about it */ if (ar.currentline > 0) { /* is there info? */ lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); return; } } lua_pushliteral(L, ""); /* else, no information available... */ } LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { va_list argp; va_start(argp, fmt); luaL_where(L, 1); lua_pushvfstring(L, fmt, argp); va_end(argp); lua_concat(L, 2); return lua_error(L); } /* }====================================================== */ 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 int luaL_newmetatable (lua_State *L, const char *tname) { lua_pushstring(L, tname); lua_rawget(L, LUA_REGISTRYINDEX); /* get registry.name */ if (!lua_isnil(L, -1)) /* name already in use? */ return 0; /* leave previous value on top, but return 0 */ lua_pop(L, 1); lua_newtable(L); /* create metatable */ lua_pushstring(L, tname); lua_pushvalue(L, -2); lua_rawset(L, LUA_REGISTRYINDEX); /* registry.name = metatable */ lua_pushvalue(L, -1); lua_pushstring(L, tname); lua_rawset(L, LUA_REGISTRYINDEX); /* registry[metatable] = name */ return 1; } LUALIB_API void luaL_getmetatable (lua_State *L, const char *tname) { lua_pushstring(L, tname); lua_rawget(L, LUA_REGISTRYINDEX); } LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { const char *tn; if (!lua_getmetatable(L, ud)) return NULL; /* no metatable? */ lua_rawget(L, LUA_REGISTRYINDEX); /* get registry[metatable] */ tn = lua_tostring(L, -1); if (tn && (strcmp(tn, tname) == 0)) { lua_pop(L, 1); return lua_touserdata(L, ud); } else { lua_pop(L, 1); return NULL; } } LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) { if (!lua_checkstack(L, space)) luaL_error(L, "stack overflow (%s)", mes); } LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) { if (lua_type(L, narg) != t) tag_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_checklstring (lua_State *L, int narg, size_t *len) { const char *s = lua_tostring(L, narg); if (!s) tag_error(L, narg, LUA_TSTRING); if (len) *len = lua_strlen(L, narg); return s; } LUALIB_API const char *luaL_optlstring (lua_State *L, int narg, const char *def, size_t *len) { if (lua_isnoneornil(L, narg)) { if (len) *len = (def ? strlen(def) : 0); return def; } else return luaL_checklstring(L, narg, len); } LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { lua_Number d = lua_tonumber(L, narg); if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ tag_error(L, narg, LUA_TNUMBER); return d; } LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { if (lua_isnoneornil(L, narg)) return def; else return luaL_checknumber(L, narg); } LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { if (!lua_getmetatable(L, obj)) /* no metatable? */ return 0; lua_pushstring(L, event); lua_rawget(L, -2); if (lua_isnil(L, -1)) { lua_pop(L, 2); /* remove metatable and metafield */ return 0; } else { lua_remove(L, -2); /* remove only metatable */ return 1; } } LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { obj = abs_index(L, obj); if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ return 0; lua_pushvalue(L, obj); lua_call(L, 1, 1); return 1; } LUALIB_API void luaL_openlib (lua_State *L, const char *libname, const luaL_reg *l, int nup) { if (libname) { lua_pushstring(L, libname); lua_gettable(L, LUA_GLOBALSINDEX); /* check whether lib already exists */ if (lua_isnil(L, -1)) { /* no? */ lua_pop(L, 1); lua_newtable(L); /* create it */ lua_pushstring(L, libname); lua_pushvalue(L, -2); lua_settable(L, LUA_GLOBALSINDEX); /* register it with given name */ } lua_insert(L, -(nup+1)); /* move library table to below upvalues */ } for (; l->name; l++) { int i; lua_pushstring(L, l->name); for (i=0; i<nup; i++) /* copy upvalues to the top */ lua_pushvalue(L, -(nup+1)); lua_pushcclosure(L, l->func, nup); lua_settable(L, -(nup+3)); } lua_pop(L, nup); /* remove upvalues */ } /* ** {====================================================== ** getn-setn: size for arrays ** ======================================================= */ static int checkint (lua_State *L, int topop) { int n = (int)lua_tonumber(L, -1); if (n == 0 && !lua_isnumber(L, -1)) n = -1; lua_pop(L, topop); return n; } static void getsizes (lua_State *L) { lua_rawgeti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); if (lua_isnil(L, -1)) { /* no `size' table? */ lua_pop(L, 1); /* remove nil */ lua_newtable(L); /* create it */ lua_pushvalue(L, -1); /* `size' will be its own metatable */ lua_setmetatable(L, -2); lua_pushliteral(L, "__mode"); lua_pushliteral(L, "k"); lua_rawset(L, -3); /* metatable(N).__mode = "k" */ lua_pushvalue(L, -1); lua_rawseti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); /* store in register */ } } void luaL_setn (lua_State *L, int t, int n) { t = abs_index(L, t); lua_pushliteral(L, "n"); lua_rawget(L, t); if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */ lua_pushliteral(L, "n"); /* use it */ lua_pushnumber(L, (lua_Number)n); lua_rawset(L, t); } else { /* use `sizes' */ getsizes(L); lua_pushvalue(L, t); lua_pushnumber(L, (lua_Number)n); lua_rawset(L, -3); /* sizes[t] = n */ lua_pop(L, 1); /* remove `sizes' */ } } int luaL_getn (lua_State *L, int t) { int n; t = abs_index(L, t); lua_pushliteral(L, "n"); /* try t.n */ lua_rawget(L, t); if ((n = checkint(L, 1)) >= 0) return n; getsizes(L); /* else try sizes[t] */ lua_pushvalue(L, t); lua_rawget(L, -2); if ((n = checkint(L, 2)) >= 0) return n; for (n = 1; ; n++) { /* else must count elements */ lua_rawgeti(L, t, n); if (lua_isnil(L, -1)) break; lua_pop(L, 1); } lua_pop(L, 1); return n - 1; } /* }====================================================== */ /* ** {====================================================== ** Generic Buffer manipulation ** ======================================================= */ #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->lvl++; return 1; } } static void adjuststack (luaL_Buffer *B) { if (B->lvl > 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->lvl... [truncated message content] |