diff --git a/lua/src/llex.c b/lua/src/llex.c index b39930498..20716f2a8 100644 --- a/lua/src/llex.c +++ b/lua/src/llex.c @@ -36,7 +36,7 @@ const char *const luaX_tokens [] = { "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", - "return", "then", "true", "until", "while", + "return", "then", "true", "until", "include", "while", "..", "...", "==", ">=", "<=", "~=", "<<", ">>", "//", "", "", "", "", @@ -144,6 +144,10 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { ls->linenumber = 1; ls->lastline = 1; ls->source = source; + + lua_pushnil(L); + lua_setglobal(L, MACRO); + luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ next(ls); /* read first char */ } @@ -332,6 +336,32 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) { luaZ_bufflen(ls->buff) - 2); } +static int insert_string(LexState *ls, const char* s) { + luaZ_resetbuffer(ls->buff); + if (ls->mpos < ls->mlen) { + int len = strlen(s) + ls->mlen - ls->mpos + 1; + char *res = (char*) malloc(len); + strcpy(res, s); + strcat(res, &ls->mstr[ls->mpos-1]); + strcat(res, " "); + free(ls->mstr); + ls->mstr = res; + ls->z->n--; ls->z->p++; + } + else { + if (ls->mlen > 0) free(ls->mstr); + char *res = (char*) malloc(strlen(s)+1); + strcpy(res, s); + ls->mstr = res; + } + ls->mpos = 1; + ls->mlen = strlen(ls->mstr); + if (ls->mlen > 0) { + ls->current = ls->mstr[0]; + ls->z->n++; ls->z->p--; + } + return 0; +} static int llex (LexState *ls, SemInfo *seminfo) { luaZ_resetbuffer(ls->buff); @@ -466,12 +496,14 @@ static int llex (LexState *ls, SemInfo *seminfo) { else luaX_lexerror(ls, "cannot allocate enough memory",0); lua_pushstring(L, key); lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { if (ls->current != '@') luaX_lexerror(ls, "definition of existent macro", 0); } else if (ls->current == '@') luaX_lexerror(ls, "redefinition of nonexistent macro", 0); + if (ls->current == '@') next(ls); lua_pop(L, 1); lua_pushstring(L, key); @@ -618,8 +650,40 @@ static int llex (LexState *ls, SemInfo *seminfo) { free(val); continue; } - if (ts->tsv.reserved > 0) /* reserved word? */ + if (ts->tsv.reserved > 0) { /* reserved word? */ + if (ts->tsv.reserved == TK_INCLUDE - FIRST_RESERVED + 1) { + int t = llex(ls, seminfo); + if (t == TK_STRING) { + const char *filename = getstr(seminfo->ts); + char * buffer = 0; + long length; + FILE * f = fopen (filename, "rb"); + + if (f) + { + fseek (f, 0, SEEK_END); + length = ftell (f); + fseek (f, 0, SEEK_SET); + buffer = malloc (length + 1); + if (buffer) + { + fread (buffer, 1, length, f); + buffer[length] = '\0'; + } + fclose (f); + } + + if (buffer) + { + ++ls->mpos; + insert_string(ls, buffer); + continue; + } + luaX_lexerror(ls, "file not found", TK_INCLUDE); + } else luaX_lexerror(ls, "string expected", TK_INCLUDE); + } return ts->tsv.reserved - 1 + FIRST_RESERVED; + } lua_State *L = ls->L; lua_getglobal(L, MACRO); if (lua_istable(L, -1)) { @@ -717,39 +781,18 @@ static int llex (LexState *ls, SemInfo *seminfo) { } if (lua_isstring(L, -1)) { - luaZ_resetbuffer(ls->buff); const char *s = lua_tostring(L, -1); - if (ls->mpos < ls->mlen) { - int len = strlen(s) + ls->mlen - ls->mpos + 1; - char *res = (char*) malloc(len); - strcpy(res, s); - strcat(res, &ls->mstr[ls->mpos-1]); - strcat(res, " "); - free(ls->mstr); - ls->mstr = res; - ls->z->n--; ls->z->p++; - } - else { - if (ls->mlen > 0) free(ls->mstr); - char *res = (char*) malloc(strlen(s)+1); - strcpy(res, s); - ls->mstr = res; - } - ls->mpos = 1; - ls->mlen = strlen(ls->mstr); - if (ls->mlen > 0) { - ls->current = ls->mstr[0]; - ls->z->n++; ls->z->p--; - } + insert_string(ls, s); lua_pop(L, 1); lua_pop(L, 1); if (ls->mswt++ > 1e6) luaX_lexerror(ls, "possible mutual macro recursion", 0); continue; } + lua_pop(L, 1); } - lua_pop(L, 1); + lua_pop(L, 1); seminfo->ts = ts; return TK_NAME; } diff --git a/lua/src/llex.h b/lua/src/llex.h index 58d9c48cc..1213f66fa 100644 --- a/lua/src/llex.h +++ b/lua/src/llex.h @@ -26,7 +26,7 @@ enum RESERVED { TK_AND = FIRST_RESERVED, TK_BREAK, TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, - TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, + TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_INCLUDE, TK_WHILE, /* other terminal symbols */ TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_LSHFT, TK_RSHFT, TK_INTDIV, diff --git a/lua/src/luac.c b/lua/src/luac.c index e7e1d5bbb..159d01449 100644 --- a/lua/src/luac.c +++ b/lua/src/luac.c @@ -25,6 +25,17 @@ #include "lzio.c" #include "lauxlib.c" +#include "lbaselib.c" +#include "ldblib.c" +#include "liolib.c" +#include "lmathlib.c" +#include "loadlib.c" +#include "luacoslib.c" +#include "lstrlib.c" +#include "ltablib.c" +#include "lutf8lib.c" +#include "lint64.c" +#include "linit.c" #include "print.c" #include @@ -167,7 +178,7 @@ static const Proto* combine(lua_State* L, int n) } } -static int writer(lua_State* L, const void* p, size_t size, void* u) +static int luac_writer(lua_State* L, const void* p, size_t size, void* u) { UNUSED(L); return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); @@ -198,7 +209,7 @@ static int pmain(lua_State* L) FILE* D= (output==NULL) ? stdout : fopen(output,"wb"); if (D==NULL) cannot("open"); lua_lock(L); - luaU_dump(L,f,writer,D,stripping); + luaU_dump(L,f,luac_writer,D,stripping); lua_unlock(L); if (ferror(D)) cannot("write"); if (fclose(D)) cannot("close"); diff --git a/lua/src/luacoslib.c b/lua/src/luacoslib.c new file mode 100644 index 000000000..42b1ed5fa --- /dev/null +++ b/lua/src/luacoslib.c @@ -0,0 +1,246 @@ +/* +** $Id: loslib.c,v 1.19.1.3 2008/01/18 16:38:18 roberto Exp $ +** Standard Operating System library +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include +#include + +#define loslib_c +#define LUA_LIB + +#define LUA_TMPNAMBUFSIZE L_tmpnam +#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +static int os_pushresult (lua_State *L, int i, const char *filename) { + int en = errno; /* calls to Lua API may change this value */ + if (i) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushnil(L); + lua_pushfstring(L, "%s: %s", filename, strerror(en)); + lua_pushinteger(L, en); + return 3; + } +} + + +static int os_execute (lua_State *L) { + lua_pushinteger(L, system(luaL_optstring(L, 1, NULL))); + return 1; +} + + +static int os_remove (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + return os_pushresult(L, remove(filename) == 0, filename); +} + + +static int os_rename (lua_State *L) { + const char *fromname = luaL_checkstring(L, 1); + const char *toname = luaL_checkstring(L, 2); + return os_pushresult(L, rename(fromname, toname) == 0, fromname); +} + + +static int os_tmpname (lua_State *L) { + char buff[LUA_TMPNAMBUFSIZE]; + int err; + lua_tmpnam(buff, err); + if (err) + return luaL_error(L, "unable to generate a unique filename"); + lua_pushstring(L, buff); + return 1; +} + + +static int os_getenv (lua_State *L) { + lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ + return 1; +} + + +static int os_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_pushinteger(L, value); + lua_setfield(L, -2, key); +} + +static void setboolfield (lua_State *L, const char *key, int value) { + if (value < 0) /* undefined? */ + return; /* does not set field */ + lua_pushboolean(L, value); + lua_setfield(L, -2, key); +} + +static int getboolfield (lua_State *L, const char *key) { + int res; + lua_getfield(L, -1, key); + res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); + lua_pop(L, 1); + return res; +} + + +static int getfield (lua_State *L, const char *key, int d) { + int res; + lua_getfield(L, -1, key); + if (lua_isnumber(L, -1)) + res = (int)lua_tointeger(L, -1); + else { + if (d < 0) + return luaL_error(L, "field " LUA_QS " missing in date table", key); + res = d; + } + lua_pop(L, 1); + return res; +} + + +static int os_date (lua_State *L) { + const char *s = luaL_optstring(L, 1, "%c"); + time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); + struct tm *stm; + 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_createtable(L, 0, 9); /* 9 = number of fields */ + 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 cc[3]; + luaL_Buffer b; + cc[0] = '%'; cc[2] = '\0'; + luaL_buffinit(L, &b); + for (; *s; s++) { + if (*s != '%' || *(s + 1) == '\0') /* no conversion specifier? */ + luaL_addchar(&b, *s); + else { + size_t reslen; + char buff[200]; /* should be big enough for any conversion result */ + cc[1] = *(++s); + reslen = strftime(buff, sizeof(buff), cc, stm); + luaL_addlstring(&b, buff, reslen); + } + } + luaL_pushresult(&b); + } + return 1; +} + + +static int os_time (lua_State *L) { + time_t t; + if (lua_isnoneornil(L, 1)) /* called without args? */ + t = time(NULL); /* get current time */ + else { + 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", -1); + ts.tm_mon = getfield(L, "month", -1) - 1; + ts.tm_year = getfield(L, "year", -1) - 1900; + ts.tm_isdst = getboolfield(L, "isdst"); + t = mktime(&ts); + } + if (t == (time_t)(-1)) + lua_pushnil(L); + else + lua_pushnumber(L, (lua_Number)t); + return 1; +} + + +static int os_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 os_setlocale (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 = luaL_optstring(L, 1, NULL); + int op = luaL_checkoption(L, 2, "all", catnames); + lua_pushstring(L, setlocale(cat[op], l)); + return 1; +} + + +static int os_exit (lua_State *L) { + exit(luaL_optint(L, 1, EXIT_SUCCESS)); +} + +static const luaL_Reg syslib[] = { + {"clock", os_clock}, + {"date", os_date}, + {"difftime", os_difftime}, + {"execute", os_execute}, + {"exit", os_exit}, + {"getenv", os_getenv}, + {"remove", os_remove}, + {"rename", os_rename}, + {"setlocale", os_setlocale}, + {"time", os_time}, + {"tmpname", os_tmpname}, + {NULL, NULL} +}; + +/* }====================================================== */ + + + +LUALIB_API int luaopen_os (lua_State *L) { + luaL_register(L, LUA_OSLIBNAME, syslib); + return 1; +} +