diff --git a/CLAUDE.md b/CLAUDE.md index 3b201ed..8710471 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -33,15 +33,15 @@ These decisions are final: - **UFSD-only docroot** — Remove DD-based file serving (`/DD:HTML(...)` paths), static files only from UFS - **Remove embedded FTPD** — FTP functionality available separately - **Remove MQTT telemetry** — HTTPT struct, telemetry_thread, mqtt370 dependency -- **CGIs disabled by default** — No CGIs are registered unless explicitly configured in Parmlib. All existing CGI modules remain in the codebase but are only active when configured. +- **Extract HTTPLUA/HTTPREXX** — Lua and REXX CGI handlers moved to separate projects (mvslovers/httplua, mvslovers/httprexx), lua370 dependency removed +- **CGIs disabled by default** — No CGIs are registered unless explicitly configured in Parmlib. ## HTTPD 4.0.0 — Open Items 1. **TSK-112 CGI Chunked Bug** (M, High) — CGI responses with chunked transfer encoding 2. **TSK-110 Fehlende Status-Codes** (XS, High) — Missing HTTP status codes 3. **TSK-108 HTTP Parsing härten** (L, High) — Harden HTTP request parsing -4. **TSK-104 HTTPLUA auslagern** (L, Medium) — Extract HTTPLUA into separate module -5. **TSK-10 Doku + Version Bump** (M, Medium) — Documentation and version bump to 4.0.0 +4. **TSK-10 Doku + Version Bump** (M, Medium) — Documentation and version bump to 4.0.0 ## Dependencies (from project.toml) @@ -49,7 +49,6 @@ These decisions are final: [dependencies] "mvslovers/crent370" = ">=1.0.6" "mvslovers/ufs370" = ">=1.0.0" -"mvslovers/lua370" = "..." # stays while Lua CGI code remains in codebase ``` **Note:** mqtt370 dependency will be removed (MQTT telemetry confirmed for removal). @@ -222,14 +221,14 @@ Missing `DD:HTTPDPRM` → server starts with defaults (port 8080, no CGIs). - **httpdsrv.c**: Server status display (2,675 LOC) - **httpjes2.c**: JES2 spool browser (975 LOC) - **httpdsl.c + helpers**: Dataset list/download (1,540 LOC total) -- **httplua.c**: Lua CGI handler (1,115 LOC) -- **httprexx.c**: REXX CGI handler (587 LOC) +- **httplua.c**: Extracted → mvslovers/httplua +- **httprexx.c**: Extracted → mvslovers/httprexx - **httpdm.c / httpdmtt.c**: Device manager display (440 LOC) - **hello.c, abend0c1.c, test.c**: Demo/test CGIs **Subsystems:** - **httprepo.c**: SMF Type 243 recording + simple counters (~90 LOC) -- **Lua runtime**: lauxlib.c, liolib.c, loadlib.c, httpluax.c (3,297 LOC) — stays for Lua CGI +- **Lua runtime**: Extracted → mvslovers/httplua - **FTP daemon**: ftp*.c (3,290 LOC) — confirmed for removal - **MQTT telemetry**: HTTPT struct, telemetry_thread — confirmed for removal diff --git a/config.mk b/config.mk index 3d17838..c44b5e4 100644 --- a/config.mk +++ b/config.mk @@ -18,14 +18,13 @@ CFLAGS := -fverbose-asm -S -O1 HTTPD_VERSION ?= 4.0.0-dev # Defines and include paths -DEFS := -DLUA_USE_C89 -DLUA_USE_JUMPTABLE=0 -DHTTPD_VERSION=\"$(HTTPD_VERSION)\" +DEFS := -DHTTPD_VERSION=\"$(HTTPD_VERSION)\" INC_DIR := $(ROOT_DIR)include INC1 := $(ROOT_DIR)credentials/include INC2 := $(ROOT_DIR)contrib/crent370_sdk/inc INC3 := $(ROOT_DIR)contrib/ufs370_sdk/inc -INC4 := $(ROOT_DIR)contrib/lua370_sdk/inc -INC5 := $(ROOT_DIR)contrib/mqtt370_sdk/inc -INCS := -I$(INC_DIR) -I$(INC1) -I$(INC2) -I$(INC3) -I$(INC4) -I$(INC5) +INC4 := $(ROOT_DIR)contrib/mqtt370_sdk/inc +INCS := -I$(INC_DIR) -I$(INC1) -I$(INC2) -I$(INC3) -I$(INC4) CFLAGS += $(DEFS) $(INCS) diff --git a/include/httpd.h b/include/httpd.h index 80acf9b..4dc3d3b 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -45,8 +45,7 @@ #include "cred.h" /* Credentials */ #include "httpxlat.h" /* ASCII/EBCDIC translation */ -#define HTTPLUAX (httpd->luax) /* use this pointer */ -#include "httpluax.h" /* Lua function vector struct */ +/* httpluax.h removed — HTTPLUA is now a separate project (mvslovers/httplua) */ typedef struct httpd HTTPD; /* HTTP Daemon (server) */ typedef struct httpc HTTPC; /* HTTP Client */ @@ -112,7 +111,7 @@ struct httpd { time64_t uptime; /* 48 Server startup time */ void *unused_50; /* 50 (was: FTPD *ftpd) */ UFSSYS *ufssys; /* 54 Unix like file system */ - LUAX *luax; /* 58 Lua function vector */ + void *unused_58; /* 58 (was: LUAX *luax) */ const char *version; /* 5C HTTPD Version */ void *unused_60; /* 60 (was: lua_State *config) */ UCHAR cfg_maxtask; /* 64 config max task */ @@ -135,9 +134,9 @@ struct httpd { unsigned total_bytes_sent; /* 78 total bytes sent */ unsigned active_connections; /* 7C active client connections */ void *unused_80; /* 80 (was: st_dataset) */ - UCHAR *cgilua_dataset; /* 84 CGI Lua dataset */ - UCHAR *cgilua_path; /* 88 CGI Lua package.path */ - UCHAR *cgilua_cpath; /* 8C CGI Lua package.cpath */ + void *unused_84; /* 84 (was: cgilua_dataset) */ + void *unused_88; /* 88 (was: cgilua_path) */ + void *unused_8C; /* 8C (was: cgilua_cpath) */ UFS *ufs; /* 90 Unix "like" File System */ void *unused_94; /* 94 (was: HTTPT *httpt) */ CTHDTASK *self; /* 98 HTTPD main thread */ diff --git a/include/httpluax.h b/include/httpluax.h deleted file mode 100644 index 1a43c62..0000000 --- a/include/httpluax.h +++ /dev/null @@ -1,723 +0,0 @@ -#ifndef HTTPLUAX_H -#define HTTPLUAX_H -#include "stdio.h" -#include "string.h" -#include "stdarg.h" -#include "clib.h" -#include "clibio.h" -#include "clibos.h" -#include "lua.h" -#include "lualib.h" -#include "lauxlib.h" - -/* To load the HTTPLUAX module, use the following: - * - * #define HTTPLUAX luax - * #include "httpluax.h" - * LUAX *luax = (LUAX *) __load(0, "HTTPLUAX", 0, 0); - * - * - - - O R - - - - * - * #define HTTPLUAX httpd->luax - * #include "httpluax.h" - * httpd->luax = (LUAX *) __load(0, "HTTPLUAX", 0, 0); - * - * - - - O R - - - - * - * When httpluax is LKED with main program: - * #define HTTPLUAX luax - * #include "httpluax.h" - * LAUX *luax = (LUAX*) &httpluax; - * - * If you don't want the macro names for the LUAX functions - * you can use #define HTTPLUAX_PRIVATE before the - * #include "httpluax.h" to hide the lua... macro names (defines) - */ - -typedef struct luax LUAX; - -struct luax { - const char *lua_ident; - lua_State *(*lua_newstate) (lua_Alloc f, void *ud); - void (*lua_close) (lua_State *L); - lua_State *(*lua_newthread) (lua_State *L); - int (*lua_closethread) (lua_State *L, lua_State *from); - int (*lua_resetthread) (lua_State *L); - lua_CFunction (*lua_atpanic) (lua_State *L, lua_CFunction panicf); - lua_Number (*lua_version) (lua_State *L); - int (*lua_absindex) (lua_State *L, int idx); - int (*lua_gettop) (lua_State *L); - void (*lua_settop) (lua_State *L, int idx); - void (*lua_pushvalue) (lua_State *L, int idx); - void (*lua_rotate) (lua_State *L, int idx, int n); - void (*lua_copy) (lua_State *L, int fromidx, int toidx); - int (*lua_checkstack) (lua_State *L, int n); - void (*lua_xmove) (lua_State *from, lua_State *to, int n); - int (*lua_isnumber) (lua_State *L, int idx); - int (*lua_isstring) (lua_State *L, int idx); - int (*lua_iscfunction) (lua_State *L, int idx); - int (*lua_isinteger) (lua_State *L, int idx); - int (*lua_isuserdata) (lua_State *L, int idx); - int (*lua_type) (lua_State *L, int idx); - const char *(*lua_typename) (lua_State *L, int tp); - lua_Number (*lua_tonumberx) (lua_State *L, int idx, int *isnum); - lua_Integer (*lua_tointegerx) (lua_State *L, int idx, int *isnum); - int (*lua_toboolean) (lua_State *L, int idx); - const char *(*lua_tolstring) (lua_State *L, int idx, size_t *len); - lua_Unsigned (*lua_rawlen) (lua_State *L, int idx); - lua_CFunction (*lua_tocfunction) (lua_State *L, int idx); - void *(*lua_touserdata) (lua_State *L, int idx); - lua_State *(*lua_tothread) (lua_State *L, int idx); - const void *(*lua_topointer) (lua_State *L, int idx); - int (*lua_rawequal) (lua_State *L, int idx1, int idx2); - int (*lua_compare) (lua_State *L, int idx1, int idx2, int op); - void (*lua_pushnil) (lua_State *L); - void (*lua_pushnumber) (lua_State *L, lua_Number n); - void (*lua_pushinteger) (lua_State *L, lua_Integer n); - const char *(*lua_pushlstring) (lua_State *L, const char *s, size_t len); - const char *(*lua_pushstring) (lua_State *L, const char *s); - const char *(*lua_pushvfstring) (lua_State *L, const char *fmt, va_list argp); - const char *(*lua_pushfstring) (lua_State *L, const char *fmt, ...); - void (*lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); - void (*lua_pushboolean) (lua_State *L, int b); - void (*lua_pushlightuserdata) (lua_State *L, void *p); - int (*lua_pushthread) (lua_State *L); - int (*lua_getglobal) (lua_State *L, const char *name); - int (*lua_gettable) (lua_State *L, int idx); - int (*lua_getfield) (lua_State *L, int idx, const char *k); - int (*lua_geti) (lua_State *L, int idx, lua_Integer n); - int (*lua_rawget) (lua_State *L, int idx); - int (*lua_rawgeti) (lua_State *L, int idx, lua_Integer n); - int (*lua_rawgetp) (lua_State *L, int idx, const void *p); - void (*lua_createtable) (lua_State *L, int narr, int nrec); - void *(*lua_newuserdatauv) (lua_State *L, size_t sz, int nuvalue); - int (*lua_getmetatable) (lua_State *L, int objindex); - int (*lua_getiuservalue) (lua_State *L, int idx, int n); - void (*lua_setglobal) (lua_State *L, const char *name); - void (*lua_settable) (lua_State *L, int idx); - void (*lua_setfield) (lua_State *L, int idx, const char *k); - void (*lua_seti) (lua_State *L, int idx, lua_Integer n); - void (*lua_rawset) (lua_State *L, int idx); - void (*lua_rawseti) (lua_State *L, int idx, lua_Integer n); - void (*lua_rawsetp) (lua_State *L, int idx, const void *p); - int (*lua_setmetatable) (lua_State *L, int objindex); - int (*lua_setiuservalue) (lua_State *L, int idx, int n); - void (*lua_callk) (lua_State *L, int nargs, int nresults, lua_KContext ctx, lua_KFunction k); - int (*lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, lua_KContext ctx, lua_KFunction k); - int (*lua_load) (lua_State *L, lua_Reader reader, void *dt, const char *chunkname, const char *mode); - int (*lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); - int (*lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, lua_KFunction k); - int (*lua_resume) (lua_State *L, lua_State *from, int narg, int *nres); - int (*lua_status) (lua_State *L); - int (*lua_isyieldable) (lua_State *L); - void (*lua_setwarnf) (lua_State *L, lua_WarnFunction f, void *ud); - void (*lua_warning) (lua_State *L, const char *msg, int tocont); - int (*lua_gc) (lua_State *L, int what, ...); - int (*lua_error) (lua_State *L); - int (*lua_next) (lua_State *L, int idx); - void (*lua_concat) (lua_State *L, int n); - void (*lua_len) (lua_State *L, int idx); - size_t (*lua_stringtonumber) (lua_State *L, const char *s); - lua_Alloc (*lua_getallocf) (lua_State *L, void **ud); - void (*lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); - void (*lua_toclose) (lua_State *L, int idx); - void (*lua_closeslot) (lua_State *L, int idx); - int (*lua_getstack) (lua_State *L, int level, lua_Debug *ar); - int (*lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); - const char *(*lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); - const char *(*lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); - const char *(*lua_getupvalue) (lua_State *L, int funcindex, int n); - const char *(*lua_setupvalue) (lua_State *L, int funcindex, int n); - void *(*lua_upvalueid) (lua_State *L, int fidx, int n); - void (*lua_upvaluejoin) (lua_State *L, int fidx1, int n1, int fidx2, int n2); - void (*lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); - lua_Hook (*lua_gethook) (lua_State *L); - int (*lua_gethookmask) (lua_State *L); - int (*lua_gethookcount) (lua_State *L); - int (*lua_setcstacklimit) (lua_State *L, unsigned int limit); - void (*lua_arith) (lua_State *L, int op); - void *unused1; - void *unused2; - void *unused3; - /* 0x198 (408 bytes) */ - /* LAUXLIB */ - void (*luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); - int (*luaL_getmetafield) (lua_State *L, int obj, const char *e); - int (*luaL_callmeta) (lua_State *L, int obj, const char *e); - const char *(*luaL_tolstring) (lua_State *L, int idx, size_t *len); - int (*luaL_argerror) (lua_State *L, int arg, const char *extramsg); - int (*luaL_typeerror) (lua_State *L, int arg, const char *tname); - const char *(*luaL_checklstring) (lua_State *L, int arg, size_t *l); - const char *(*luaL_optlstring) (lua_State *L, int arg, const char *def, size_t *l); - lua_Number (*luaL_checknumber) (lua_State *L, int arg); - lua_Number (*luaL_optnumber) (lua_State *L, int arg, lua_Number def); - lua_Integer (*luaL_checkinteger) (lua_State *L, int arg); - lua_Integer (*luaL_optinteger) (lua_State *L, int arg, lua_Integer def); - void (*luaL_checkstack) (lua_State *L, int sz, const char *msg); - void (*luaL_checktype) (lua_State *L, int arg, int t); - void (*luaL_checkany) (lua_State *L, int arg); - int (*luaL_newmetatable) (lua_State *L, const char *tname); - void (*luaL_setmetatable) (lua_State *L, const char *tname); - void *(*luaL_testudata) (lua_State *L, int ud, const char *tname); - void *(*luaL_checkudata) (lua_State *L, int ud, const char *tname); - void (*luaL_where) (lua_State *L, int lvl); - int (*luaL_error) (lua_State *L, const char *fmt, ...); - int (*luaL_checkoption) (lua_State *L, int arg, const char *def, const char *const lst[]); - int (*luaL_fileresult) (lua_State *L, int stat, const char *fname); - int (*luaL_execresult) (lua_State *L, int stat); - int (*luaL_ref) (lua_State *L, int t); - void (*luaL_unref) (lua_State *L, int t, int ref); - int (*luaL_loadfilex) (lua_State *L, const char *filename, const char *mode); - int (*luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode); - int (*luaL_loadstring) (lua_State *L, const char *s); - lua_State *(*luaL_newstate) (void); - lua_Integer (*luaL_len) (lua_State *L, int idx); - void (*luaL_addgsub) (luaL_Buffer *b, const char *s, const char *p, const char *r); - const char *(*luaL_gsub) (lua_State *L, const char *s, const char *p, const char *r); - void (*luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); - int (*luaL_getsubtable) (lua_State *L, int idx, const char *fname); - void (*luaL_traceback) (lua_State *L, lua_State *L1, const char *msg, int level); - void (*luaL_requiref) (lua_State *L, const char *modname, lua_CFunction openf, int glb); - void (*luaL_buffinit) (lua_State *L, luaL_Buffer *B); - char *(*luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); - void (*luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); - void (*luaL_addstring) (luaL_Buffer *B, const char *s); - void (*luaL_addvalue) (luaL_Buffer *B); - void (*luaL_pushresult) (luaL_Buffer *B); - void (*luaL_pushresultsize) (luaL_Buffer *B, size_t sz); - char *(*luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); - void (*luaL_openlibs) (lua_State *L); - - void *lunused1; - void *lunused2; - -}; - -extern LUAX httpluax; - -#ifndef HTTPLUAX_PRIVATE - -#ifndef HTTPLUAX -#error "You must define HTTPLUAX with your LUAX * pointer name" -#endif - -#define lua_ident \ - (HTTPLUAX)->lua_ident -#define lua_newstate(f,ud) \ - (HTTPLUAX)->lua_newstate(f,ud) -#define lua_close(L) \ - (HTTPLUAX)->lua_close(L) -#define lua_newthread(L) \ - (HTTPLUAX)->lua_newthread(L) -#define lua_closethread(L,from) \ - (HTTPLUAX)->lua_closethread(L,from) -#define lua_resetthread(L) \ - (HTTPLUAX)->lua_resetthread(L) -#define lua_atpanic(L,panicf) \ - (HTTPLUAX)->lua_atpanic(L,panicf) -#define lua_version(L) \ - (HTTPLUAX)->lua_version(L) -#define lua_absindex(L,idx) \ - (HTTPLUAX)->lua_absindex(L,idx) -#define lua_gettop(L) \ - (HTTPLUAX)->lua_gettop(L) -#define lua_settop(L,idx) \ - (HTTPLUAX)->lua_settop(L,idx) -#define lua_pushvalue(L,idx) \ - (HTTPLUAX)->lua_pushvalue(L,idx) -#define lua_rotate(L,idx,n) \ - (HTTPLUAX)->lua_rotate(L,idx,n) -#define lua_copy(L,fromidx,toidx) \ - (HTTPLUAX)->lua_copy(L,fromidx,toidx) -#define lua_checkstack(L,n) \ - (HTTPLUAX)->lua_checkstack(L,n) -#define lua_xmove(from,to,n) \ - (HTTPLUAX)->lua_xmove(from,to,n) -#define lua_isnumber(L,idx) \ - (HTTPLUAX)->lua_isnumber(L,idx) -#define lua_isstring(L,idx) \ - (HTTPLUAX)->lua_isstring(L,idx) -#define lua_iscfunction(L,idx) \ - (HTTPLUAX)->lua_iscfunction(L,idx) -#define lua_isinteger(L,idx) \ - (HTTPLUAX)->lua_isinteger(L,idx) -#define lua_isuserdata(L,idx) \ - (HTTPLUAX)->lua_isuserdata(L,idx) -#define lua_type(L,idx) \ - (HTTPLUAX)->lua_type(L,idx) -#define lua_typename(L,tp) \ - (HTTPLUAX)->lua_typename(L,tp) -#define lua_tonumberx(L,idx,isnum) \ - (HTTPLUAX)->lua_tonumberx(L,idx,isnum) -#define lua_tointegerx(L,idx,isnum) \ - (HTTPLUAX)->lua_tointegerx(L,idx,isnum) -#define lua_toboolean(L,idx) \ - (HTTPLUAX)->lua_toboolean(L,idx) -#define lua_tolstring(L,idx,len) \ - (HTTPLUAX)->lua_tolstring(L,idx,len) -#define lua_rawlen(L,idx) \ - (HTTPLUAX)->lua_rawlen(L,idx) -#define lua_tocfunction(L,idx) \ - (HTTPLUAX)->lua_tocfunction(L,idx) -#define lua_touserdata(L,idx) \ - (HTTPLUAX)->lua_touserdata(L,idx) -#define lua_tothread(L,idx) \ - (HTTPLUAX)->lua_tothread(L,idx) -#define lua_topointer(L,idx) \ - (HTTPLUAX)->lua_topointer(L,idx) -#define lua_rawequal(L,idx1,idx2) \ - (HTTPLUAX)->lua_rawequal(L,idx1,idx2) -#define lua_compare(L,idx1,idx2,op) \ - (HTTPLUAX)->lua_compare(L,idx1,idx2,op) -#define lua_pushnil(L) \ - (HTTPLUAX)->lua_pushnil(L) -#define lua_pushnumber(L,n) \ - (HTTPLUAX)->lua_pushnumber(L,n) -#define lua_pushinteger(L,n) \ - (HTTPLUAX)->lua_pushinteger(L,n) -#define lua_pushlstring(L,s,len) \ - (HTTPLUAX)->lua_pushlstring(L,s,len) -#define lua_pushstring(L,s) \ - (HTTPLUAX)->lua_pushstring(L,s) -#define lua_pushvfstring(L,fmt,argp) \ - (HTTPLUAX)->lua_pushvfstring(L,fmt,argp) -#define lua_pushfstring(L,fmt,...) \ - (HTTPLUAX)->lua_pushfstring(L,fmt,## __VA_ARGS__) -#define lua_pushcclosure(L,fn,n) \ - (HTTPLUAX)->lua_pushcclosure(L,fn,n) -#define lua_pushboolean(L,b) \ - (HTTPLUAX)->lua_pushboolean(L,b) -#define lua_pushlightuserdata(L,p) \ - (HTTPLUAX)->lua_pushlightuserdata(L,p) -#define lua_pushthread(L) \ - (HTTPLUAX)->lua_pushthread(L) -#define lua_getglobal(L,name) \ - (HTTPLUAX)->lua_getglobal(L,name) -#define lua_gettable(L,idx) \ - (HTTPLUAX)->lua_gettable(L,idx) -#define lua_getfield(L,idx,k) \ - (HTTPLUAX)->lua_getfield(L,idx,k) -#define lua_geti(L,idx,n) \ - (HTTPLUAX)->lua_geti(L,idx,n) -#define lua_rawget(L,idx) \ - (HTTPLUAX)->lua_rawget(L,idx) -#define lua_rawgeti(L,idx,n) \ - (HTTPLUAX)->lua_rawgeti(L,idx,n) -#define lua_rawgetp(L,idx,p) \ - (HTTPLUAX)->lua_rawgetp(L,idx,p) -#define lua_createtable(L,narr,nrec) \ - (HTTPLUAX)->lua_createtable(L,narr,nrec) -#define lua_newuserdatauv(L,sz,nuvalue) \ - (HTTPLUAX)->lua_newuserdatauv(L,sz,nuvalue) -#define lua_getmetatable(L,objindex) \ - (HTTPLUAX)->lua_getmetatable(L,objindex) -#define lua_getiuservalue(L,idx,n) \ - (HTTPLUAX)->lua_getiuservalue(L,idx,n) -#define lua_setglobal(L,name) \ - (HTTPLUAX)->lua_setglobal(L,name) -#define lua_settable(L,idx) \ - (HTTPLUAX)->lua_settable(L,idx) -#define lua_setfield(L,idx,k) \ - (HTTPLUAX)->lua_setfield(L,idx,k) -#define lua_seti(L,idx,n) \ - (HTTPLUAX)->lua_seti(L,idx,n) -#define lua_rawset(L,idx) \ - (HTTPLUAX)->lua_rawset(L,idx) -#define lua_rawseti(L,idx,n) \ - (HTTPLUAX)->lua_rawseti(L,idx,n) -#define lua_rawsetp(L,idx,p) \ - (HTTPLUAX)->lua_rawsetp(L,idx,p) -#define lua_setmetatable(L,objindex) \ - (HTTPLUAX)->lua_setmetatable(L,objindex) -#define lua_setiuservalue(L,idx,n) \ - (HTTPLUAX)->lua_setiuservalue(L,idx,n) -#define lua_callk(L,nargs,nresults,ctx,k) \ - (HTTPLUAX)->lua_callk(L,nargs,nresults,ctx,k) -#undef lua_call -#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) -#define lua_pcallk(L,nargs,nresults,errfunc,ctx,k) \ - (HTTPLUAX)->lua_pcallk(L,nargs,nresults,errfunc,ctx,k) -#undef lua_pcall -#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) -#define lua_load(L,reader,dt,chunkname,mode) \ - (HTTPLUAX)->lua_load(L,reader,dt,chunkname,mode) -#define lua_dump(L,writer,data,strip) \ - (HTTPLUAX)->lua_dump(L,writer,data,strip) -#define lua_yieldk(L,nresults,ctx,k) \ - (HTTPLUAX)->lua_yieldk(L,nresults,ctx,k) -#define lua_resume(L,from,narg,nres) \ - (HTTPLUAX)->lua_resume(L,from,narg,nres) -#define lua_status(L) \ - (HTTPLUAX)->lua_status(L) -#define lua_isyieldable(L) \ - (HTTPLUAX)->lua_isyieldable(L) -#define lua_setwarnf(L,f,ud) \ - (HTTPLUAX)->lua_setwarnf(L,f,ud) -#define lua_warning(L,msg,tocont) \ - (HTTPLUAX)->lua_warning(L,msg,tocont) -#define lua_gc(L,what,...) \ - (HTTPLUAX)->lua_gc(L,what,## __VA_ARGS__) -#define lua_error(L) \ - (HTTPLUAX)->lua_error(L) -#define lua_next(L,idx) \ - (HTTPLUAX)->lua_next(L,idx) -#define lua_concat(L,n) \ - (HTTPLUAX)->lua_concat(L,n) -#define lua_len(L,idx) \ - (HTTPLUAX)->lua_len(L,idx) -#define lua_stringtonumber(L,s) \ - (HTTPLUAX)->lua_stringtonumber(L,s) -#define lua_getallocf(L,ud) \ - (HTTPLUAX)->lua_getallocf(L,ud) -#define lua_setallocf(L,f,ud) \ - (HTTPLUAX)->lua_setallocf(L,f,ud) -#define lua_toclose(L,idx) \ - (HTTPLUAX)->lua_toclose(L,idx) -#define lua_closeslot(L,idx) \ - (HTTPLUAX)->lua_closeslot(L,idx) -#define lua_getstack(L,level,ar) \ - (HTTPLUAX)->lua_getstack(L,level,ar) -#define lua_getinfo(L,what,ar) \ - (HTTPLUAX)->lua_getinfo(L,what,ar) -#define lua_getlocal(L,ar,n) \ - (HTTPLUAX)->lua_getlocal(L,ar,n) -#define lua_setlocal(L,ar,n) \ - (HTTPLUAX)->lua_setlocal(L,ar,n) -#define lua_getupvalue(L,funcindex,n) \ - (HTTPLUAX)->lua_getupvalue(L,funcindex,n) -#define lua_setupvalue(L,funcindex,n) \ - (HTTPLUAX)->lua_setupvalue(L,funcindex,n) -#define lua_upvalueid(L,fidx,n) \ - (HTTPLUAX)->lua_upvalueid(L,fidx,n) -#define lua_upvaluejoin(L,fidx1,n1,fidx2,n2) \ - (HTTPLUAX)->lua_upvaluejoin(L,fidx1,n1,fidx2,n2) -#define lua_sethook(L,func,mask,count) \ - (HTTPLUAX)->lua_sethook(L,func,mask,count) -#define lua_gethook(L) \ - (HTTPLUAX)->lua_gethook(L) -#define lua_gethookmask(L) \ - (HTTPLUAX)->lua_gethookmask(L) -#define lua_gethookcount(L) \ - (HTTPLUAX)->lua_gethookcount(L) -#define lua_setcstacklimit(L,limit) \ - (HTTPLUAX)->lua_setcstacklimit(L,limit) -#define lua_arith(L,op) \ - (HTTPLUAX)->lua_arith(L,op) -/* LAUXLIB */ -#define luaL_checkversion_(L,ver,sz) \ - (HTTPLUAX)->luaL_checkversion_(L,ver,sz) -#define luaL_getmetafield(L,obj,e) \ - (HTTPLUAX)->luaL_getmetafield(L,obj,e) -#define luaL_callmeta(L,obj,e) \ - (HTTPLUAX)->luaL_callmeta(L,obj,e) -#define luaL_tolstring(L,idx,len) \ - (HTTPLUAX)->luaL_tolstring(L,idx,len) -#define luaL_argerror(L,arg,extramsg) \ - (HTTPLUAX)->luaL_argerror(L,arg,extramsg) -#define luaL_typeerror(L,arg,tname) \ - (HTTPLUAX)->luaL_typeerror(L,arg,tname) -#define luaL_checklstring(L,arg,len) \ - (HTTPLUAX)->luaL_checklstring(L,arg,len) -#define luaL_optlstring(L,arg,def,len) \ - (HTTPLUAX)->luaL_optlstring(L,arg,def,len) -#define luaL_checknumber(L,arg) \ - (HTTPLUAX)->luaL_checknumber(L,arg) -#define luaL_optnumber(L,arg,def) \ - (HTTPLUAX)->luaL_optnumber(L,arg,def) -#define luaL_checkinteger(L,arg) \ - (HTTPLUAX)->luaL_checkinteger(L,arg) -#define luaL_optinteger(L,arg,def) \ - (HTTPLUAX)->luaL_optinteger(L,arg,def) -#define luaL_checkstack(L,sz,msg) \ - (HTTPLUAX)->luaL_checkstack(L,sz,msg) -#define luaL_checktype(L,arg,t) \ - (HTTPLUAX)->luaL_checktype(L,arg,t) -#define luaL_checkany(L,arg) \ - (HTTPLUAX)->luaL_checkany(L,arg) -#define luaL_newmetatable(L,tname) \ - (HTTPLUAX)->luaL_newmetatable(L,tname) -#define luaL_setmetatable(L,tname) \ - (HTTPLUAX)->luaL_setmetatable(L,tname) -#define luaL_testudata(L,ud,tname) \ - (HTTPLUAX)->luaL_testudata(L,ud,tname) -#define luaL_checkudata(L,ud,tname) \ - (HTTPLUAX)->luaL_checkudata(L,ud,tname) -#define luaL_where(L,level) \ - (HTTPLUAX)->luaL_where(L,level) -#define luaL_error(L,fmt,...) \ - (HTTPLUAX)->luaL_error(L,fmt,## __VA_ARGS__) -#define luaL_checkoption(L,arg,def,lst) \ - (HTTPLUAX)->luaL_checkoption(L,arg,def,lst) -#define luaL_fileresult(L,stat,fname) \ - (HTTPLUAX)->luaL_fileresult(L,stat,fname) -#define luaL_execresult(L,stat) \ - (HTTPLUAX)->luaL_execresult(L,stat) -#define luaL_ref(L,t) \ - (HTTPLUAX)->luaL_ref(L,t) -#define luaL_unref(L,t,ref) \ - (HTTPLUAX)->luaL_unref(L,t,ref) -#define luaL_loadfilex(L,filename,mode) \ - (HTTPLUAX)->luaL_loadfilex(L,filename,mode) -#define luaL_loadbufferx(L,buff,sz,name,mode) \ - (HTTPLUAX)->luaL_loadbufferx(L,buff,sz,name,mode) -#define luaL_loadstring(L,s) \ - (HTTPLUAX)->luaL_loadstring(L,s) -#define luaL_newstate() \ - (HTTPLUAX)->luaL_newstate() -#define luaL_len(L,idx) \ - (HTTPLUAX)->luaL_len(L,idx) -#define luaL_addgsub(b,s,p,r) \ - (HTTPLUAX)->luaL_addgsub(b,s,p,r) -#define luaL_gsub(L,s,p,r) \ - (HTTPLUAX)->luaL_gsub(L,s,p,r) -#define luaL_setfuncs(L,l,nup) \ - (HTTPLUAX)->luaL_setfuncs(L,l,nup) -#define luaL_getsubtable(L,idx,fname) \ - (HTTPLUAX)->luaL_getsubtable(L,idx,fname) -#define luaL_traceback(L,L1,msg,level) \ - (HTTPLUAX)->luaL_traceback(L,L1,msg,level) -#define luaL_requiref(L,modname,openf,glb) \ - (HTTPLUAX)->luaL_requiref(L,modname,openf,glb) -#define luaL_buffinit(L,B) \ - (HTTPLUAX)->luaL_buffinit(L,B) -#define luaL_prepbuffsize(B,sz) \ - (HTTPLUAX)->luaL_prepbuffsize(B,sz) -#define luaL_addlstring(B,s,l) \ - (HTTPLUAX)->luaL_addlstring(B,s,l) -#define luaL_addstring(B,s) \ - (HTTPLUAX)->luaL_addstring(B,s) -#define luaL_addvalue(B) \ - (HTTPLUAX)->luaL_addvalue(B) -#define luaL_pushresult(B) \ - (HTTPLUAX)->luaL_pushresult(B) -#define luaL_pushresultsize(B,sz) \ - (HTTPLUAX)->luaL_pushresultsize(B,sz) -#define luaL_buffinitsize(L,B,sz) \ - (HTTPLUAX)->luaL_buffinitsize(L,B,sz) -#define luaL_openlibs(L) \ - (HTTPLUAX)->luaL_openlibs(L) - - - -#undef lua_tonumber -#define lua_tonumber(L,i) \ - lua_tonumberx(L,(i),NULL) - -#undef lua_tointeger -#define lua_tointeger(L,i) \ - lua_tointegerx(L,(i),NULL) - -#undef lua_pop -#define lua_pop(L,n) \ - lua_settop(L, -(n)-1) - -#undef lua_newtable -#define lua_newtable(L) \ - lua_createtable(L, 0, 0) - -#undef lua_pushcfunction -#define lua_pushcfunction(L,f) \ - lua_pushcclosure(L, (f), 0) - -#undef lua_register -#define lua_register(L,n,f) \ - (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) - -#undef lua_isfunction -#define lua_isfunction(L,n) \ - (lua_type(L, (n)) == LUA_TFUNCTION) - -#undef lua_istable -#define lua_istable(L,n) \ - (lua_type(L, (n)) == LUA_TTABLE) - -#undef lua_islightuserdata -#define lua_islightuserdata(L,n) \ - (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) - -#undef lua_isnil -#define lua_isnil(L,n) \ - (lua_type(L, (n)) == LUA_TNIL) - -#undef lua_isboolean -#define lua_isboolean(L,n) \ - (lua_type(L, (n)) == LUA_TBOOLEAN) - -#undef lua_isthread -#define lua_isthread(L,n) \ - (lua_type(L, (n)) == LUA_TTHREAD) - -#undef lua_isnone -#define lua_isnone(L,n) \ - (lua_type(L, (n)) == LUA_TNONE) - -#undef lua_isnoneornil -#define lua_isnoneornil(L, n) \ - (lua_type(L, (n)) <= 0) - -#undef lua_pushliteral -#define lua_pushliteral(L, s) \ - lua_pushstring(L, "" s) - -#undef lua_pushglobaltable -#define lua_pushglobaltable(L) \ - ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)) - -#undef lua_tostring -#define lua_tostring(L,i) \ - lua_tolstring(L, (i), NULL) - -#undef lua_insert -#define lua_insert(L,idx) \ - lua_rotate(L, (idx), 1) - -#undef lua_remove -#define lua_remove(L,idx) \ - (lua_rotate(L, (idx), -1), lua_pop(L, 1)) - -#undef lua_replace -#define lua_replace(L,idx) \ - (lua_copy(L, -1, (idx)), lua_pop(L, 1)) - -#undef lua_call -#define lua_call(L,n,r) \ - lua_callk(L, (n), (r), 0, NULL) - -#undef lua_pcall -#define lua_pcall(L,n,r,f) \ - lua_pcallk(L, (n), (r), (f), 0, NULL) - -#undef lua_yield -#define lua_yield(L,n) \ - lua_yieldk(L, (n), 0, NULL) - - -/* -** {============================================================== -** compatibility macros -** =============================================================== -*/ -#if defined(LUA_COMPAT_APIINTCASTS) -#undef lua_pushunsigned -#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) -#undef lua_tounsignedx -#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is)) -#undef lua_tounsigned -#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL) -#endif - -#undef lua_newuserdata -#define lua_newuserdata(L,s) lua_newuserdatauv(L,s,1) -#undef lua_getuservalue -#define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1) -#undef lua_setuservalue -#define lua_setuservalue(L,idx) lua_setiuservalue(L,idx,1) - -#undef luaL_newlibtable -#define luaL_newlibtable(L,l) \ - lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) - -#undef luaL_argcheck -#define luaL_argcheck(L, cond,arg,extramsg) \ - ((void)(luai_likely(cond) || luaL_argerror(L, (arg), (extramsg)))) - -#undef luaL_argexpected -#define luaL_argexpected(L,cond,arg,tname) \ - ((void)(luai_likely(cond) || luaL_typeerror(L, (arg), (tname)))) - -#undef luaL_checkstring -#define luaL_checkstring(L,n) \ - (luaL_checklstring(L, (n), NULL)) - -#undef luaL_optstring -#define luaL_optstring(L,n,d) \ - (luaL_optlstring(L, (n), (d), NULL)) - -#undef luaL_typename -#define luaL_typename(L,i) \ - lua_typename(L, lua_type(L,(i))) - -#undef luaL_dostring -#define luaL_dostring(L, s) \ - (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) - -#undef luaL_getmetatable -#define luaL_getmetatable(L,n) \ - (lua_getfield(L, LUA_REGISTRYINDEX, (n))) - -#undef luaL_opt -#define luaL_opt(L,f,n,d) \ - (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) - -#undef luaL_loadbuffer -#define luaL_loadbuffer(L,s,sz,n) \ - luaL_loadbufferx(L,s,sz,n,NULL) - -/* push the value used to represent failure/error */ -#undef luaL_pushfail -#define luaL_pushfail(L) \ - lua_pushnil(L) - - -#undef luaL_addchar -#define luaL_addchar(B,c) \ - ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ - ((B)->b[(B)->n++] = (c))) - -#undef luaL_prepbuffer -#define luaL_prepbuffer(B) \ - luaL_prepbuffsize(B, LUAL_BUFFERSIZE) - -#undef luaL_checkversion -#define luaL_checkversion(L) \ - luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES) - -#undef luaL_newlib -#define luaL_newlib(L,l) \ - (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) - -#undef luaL_loadfile -#define luaL_loadfile(L,f) \ - luaL_loadfilex(L,f,NULL) - -#undef luaL_dofile -#define luaL_dofile(L, fn) \ - (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) - - -/* -** {============================================================ -** Compatibility with deprecated conversions -** ============================================================= -*/ -#if defined(LUA_COMPAT_APIINTCASTS) - -#undef luaL_checkunsigned -#define luaL_checkunsigned(L,a) \ - ((lua_Unsigned)luaL_checkinteger(L,a)) - -#undef luaL_optunsigned -#define luaL_optunsigned(L,a,d) \ - ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d))) - -#undef luaL_checkint -#define luaL_checkint(L,n) \ - ((int)luaL_checkinteger(L, (n))) - -#undef luaL_optint -#define luaL_optint(L,n,d) \ - ((int)luaL_optinteger(L, (n), (d))) - -#undef luaL_checklong -#define luaL_checklong(L,n) \ - ((long)luaL_checkinteger(L, (n))) - -#undef luaL_optlong -#define luaL_optlong(L,n,d) \ - ((long)luaL_optinteger(L, (n), (d))) - -#endif /* #if defined(LUA_COMPAT_APIINTCASTS) */ - -#endif /* #ifndef HTTPLUAX_PRIVATE */ - -#endif /* HTTPLUAX_H */ diff --git a/project.toml b/project.toml index ab9c3df..fc820b3 100644 --- a/project.toml +++ b/project.toml @@ -6,8 +6,6 @@ type = "application" [build] cflags = [ "-O1", - "-DLUA_USE_C89", - "-DLUA_USE_JUMPTABLE=0", "-I./include", "-I./credentials/include", ] @@ -50,7 +48,6 @@ space = ["TRK", 150, 50, 30] [dependencies] "mvslovers/crent370" = ">=1.0.9" "mvslovers/ufsd" = "=1.0.0-dev" -"mvslovers/lua370" = ">=1.0.2" # --- Load Modules ------------------------------------------------ @@ -63,36 +60,8 @@ include = ["@@CRT1", "HTTPSTRT", "HTTPD", "HTTPPRM"] setcode = "AC(1)" [link.module.dep_includes] -"mvslovers/lua370" = "*" "mvslovers/ufsd" = "*" -# Lua extension module (custom entry point, no CRT) -[[link.module]] -name = "HTTPLUAX" -entry = "HTTPLUAX" -options = ["SIZE=(4000K,40K)", "LIST", "MAP", "XREF", "RENT"] -include = ["HTTPLUAX"] - -[link.module.dep_includes] -"mvslovers/lua370" = "*" - -# Lua CGI handler -[[link.module]] -name = "HTTPLUA" -entry = "@@CRT0" -options = ["LIST", "MAP", "XREF", "RENT"] -include = ["@@CRT1", "HTTPLUA"] - -[link.module.dep_includes] -"mvslovers/ufsd" = "*" - -# BREXX say helper (@@CRTM instead of @@CRT1) -[[link.module]] -name = "HTTPSAY" -entry = "@@CRT0" -options = ["LIST", "MAP", "XREF", "RENT"] -include = ["@@CRTM", "HTTPSAY"] - # JES2 CGI handler [[link.module]] name = "HTTPJES2" @@ -100,13 +69,6 @@ entry = "@@CRT0" options = ["LIST", "MAP", "XREF", "RENT"] include = ["@@CRT1", "CGISTART", "HTTPJES2"] -# REXX CGI handler -[[link.module]] -name = "HTTPREXX" -entry = "@@CRT0" -options = ["LIST", "MAP", "XREF", "RENT"] -include = ["@@CRT1", "CGISTART", "HTTPREXX"] - # SSI handler modules [[link.module]] name = "HTTPDM" @@ -137,5 +99,5 @@ version_files = ["VERSION"] [artifacts] headers = true -header_files = ["httpcgi.h", "httpxlat.h", "dbg.h", "errors.h"] +header_files = ["httpcgi.h", "httpxlat.h", "dbg.h", "errors.h", "types.h"] loads = true diff --git a/samplib/httpprm0 b/samplib/httpprm0 index b263607..3982019 100644 --- a/samplib/httpprm0 +++ b/samplib/httpprm0 @@ -34,18 +34,19 @@ # DEBUG=1 # # --- CGI Modules --- -# Format: CGI=PROGRAM /url/path +# Format: CGI=PROGRAM /url/pattern (URL prefix match) +# CGI=PROGRAM *.ext (extension match — uses DOCROOT) # No CGIs are registered by default. # Uncomment the lines below to enable them. # # CGI=MVSMF /zosmf/* +# CGI=HTTPLUA *.lua +# CGI=HTTPREXX *.rexx # CGI=HTTPDSRV /.dsrv # CGI=HTTPDM /.dm # CGI=HTTPDMTT /.dmtt -# CGI=HTTPDSL /dsl/* -# CGI=HTTPJES2 /jes/* -# CGI=HTTPLUA /lua/* -# CGI=HTTPREXX /rexx/* +# CGI=HTTPDSL /dsl/* (deprecated — use mvsMF dataset API) +# CGI=HTTPJES2 /jes/* (deprecated — use mvsMF jobs API) # # --- SMF Recording --- # SMF=NONE|ERROR|AUTH|ALL [TYPE=nnn] diff --git a/src/httpd.c b/src/httpd.c index 8111105..8173c00 100644 --- a/src/httpd.c +++ b/src/httpd.c @@ -86,9 +86,6 @@ initialize(int argc, char **argv) /* set the server up time */ httpd->uptime = time64(NULL); - /* httpd -> httpluax */ - httpd->luax = &httpluax; - /* Server version */ httpd->version = VERSION; diff --git a/src/httpdsrv.c b/src/httpdsrv.c index 5c121c8..9356ecf 100644 --- a/src/httpdsrv.c +++ b/src/httpdsrv.c @@ -378,14 +378,14 @@ display_httpd(HTTPD *httpd, HTTPC *httpc) "%p\n", O(ufssys), httpd->ufssys); - http_printf(httpc, + http_printf(httpc, "+%04X" - "httpd->luax" - "Lua Function Vector" - "%p\n", - O(luax), httpd->luax, sizeof(LUAX), httpd->luax); + "httpd->unused_58" + "(reserved)" + "%p\n", + O(unused_58), httpd->unused_58); - http_printf(httpc, + http_printf(httpc, "+%04X" "httpd->version" "Version String" @@ -457,28 +457,28 @@ display_httpd(HTTPD *httpd, HTTPC *httpc) "%u\n", O(active_connections), httpd->active_connections); - http_printf(httpc, + http_printf(httpc, "+%04X" - "httpd->cgilua_dataset" - "CGI Lua Dataset Name" - "\"%s\"\n", - O(cgilua_dataset), httpd->cgilua_dataset); - - http_printf(httpc, + "httpd->unused_84" + "(reserved)" + "%p\n", + O(unused_84), httpd->unused_84); + + http_printf(httpc, "+%04X" - "httpd->cgilua_path" - "CGI Lua Path Name" - "\"%s\"\n", - O(cgilua_path), httpd->cgilua_path); - - http_printf(httpc, + "httpd->unused_88" + "(reserved)" + "%p\n", + O(unused_88), httpd->unused_88); + + http_printf(httpc, "+%04X" - "httpd->cgilua_cpath" - "CGI Lua CPath Name" - "\"%s\"\n", - O(cgilua_cpath), httpd->cgilua_cpath); - - http_printf(httpc, + "httpd->unused_8C" + "(reserved)" + "%p\n", + O(unused_8C), httpd->unused_8C); + + http_printf(httpc, "+%04X" "httpd->ufs" "Unix \"like\" File System Handle" diff --git a/src/httplua.c b/src/httplua.c deleted file mode 100644 index 9110390..0000000 --- a/src/httplua.c +++ /dev/null @@ -1,1076 +0,0 @@ -/* HTTPLUA.C - CGI Program, REST style CGI program to execute lua scripts */ -#include "clibary.h" -#include "clibos.h" -#include "httpd.h" -#include "svc99.h" - -#define httpx (httpd->httpx) - -static int alloc_dummy(char *ddname); -static int alloc_temp(char *ddname, const char *tmpname); -static int free_alloc(const char *ddname); -static int process_stdout(HTTPD *httpd, HTTPC *httpc); -static int process_stderr(HTTPD *httpd, HTTPC *httpc, const char *script); -static int process_print(HTTPD *httpd, HTTPC *httpc, const char *buf); -static int main_lua(HTTPD *httpd, HTTPC *httpc, const char *script); -static void dumpstack(lua_State *L, const char *funcname); -static int setLuaPath(lua_State *L, const char *path); -static int setLuaCPath(lua_State *L, const char *path); -static char *getLuaPath(lua_State *L); - -static int open_http(lua_State *L); - -static int http_lua_publish(lua_State *L); - -#define MAXPARMS 50 /* maximum number of arguments we can handle */ - -/* we want the internal label for __start as "cgistart" for use with dumps */ -int __start(char *p, char *pgmname, int tsojbid, void **pgmr1) { - CLIBGRT *grt = __grtget(); - HTTPD *httpd = NULL; - HTTPC *httpc = NULL; - char ddstdin[12] = "DD:xxxxxxxx"; - char ddstdout[12] = "DD:xxxxxxxx"; - char ddstderr[12] = "DD:xxxxxxxx"; - int x; - int argc; - unsigned u; - char *argv[MAXPARMS + 1]; - int rc; - int parmLen; - int progLen; - char parmbuf[310]; - - /* we're going to process the callers parameter list first so we - can decide is we'll bypass the opens for the permanent datasets. - */ - if (pgmr1) { - /* save the program parameter list values (max 10 pointers) - note: the first pointer is always the raw EXEC PGM=...,PARM - or CPPL (TSO) address. - */ - for (x = 0; x < 10; x++) { - u = (unsigned)pgmr1[x]; - /* add to array of pointers from caller */ - arrayadd(&grt->grtptrs, (void *)(u & 0x7FFFFFFF)); - - if (u) { - if (strcmp((void *)u, HTTPD_EYE) == 0) { - /* this is a HTTPD pointer */ - httpd = (HTTPD *)(u & 0x7FFFFFFF); - grt->grtapp1 = httpd; - } - if (strcmp((void *)u, HTTPC_EYE) == 0) { - /* this is a HTTPC pointer */ - httpc = (HTTPC *)(u & 0x7FFFFFFF); - grt->grtapp2 = httpc; - } - } - - if (u & 0x80000000) - break; /* end of VL style address list */ - } - } - - /* if we got a HTTPC and we didn't get a HTTPD, - then use the HTTPD from the HTTPC handle */ - if (httpc && !httpd) { - httpd = httpc->httpd; - grt->grtapp1 = httpd; - } - - /* need to know if this is a TSO environment straight away - because it determines how the permanent files will be - opened */ - parmLen = ((unsigned int)p[0] << 8) | (unsigned int)p[1]; - if ((parmLen > 0) && (p[2] == 0)) { - grt->grtflag1 |= GRTFLAG1_TSO; - progLen = (unsigned int)p[3]; - } - - rc = alloc_dummy(&ddstdin[3]); - // wtof("%s: stdin %s", __func__, ddstdin); - if (rc) - goto quit; - - rc = alloc_temp(&ddstdout[3], "STDOUT"); - // wtof("%s: stdout %s", __func__, ddstdout); - if (rc) - goto quit; - - rc = alloc_temp(&ddstderr[3], "STDERR"); - // wtof("%s: stderr %s", __func__, ddstderr); - if (rc) - goto quit; - - stdout = fopen(ddstdout, "w"); - // wtof("%s: stdout 0x%08X", __func__, stdout); - if (!stdout) { - wtof("Unable to open STDOUT %s", ddstdout); - goto quit; - } - - stderr = fopen(ddstderr, "w"); - // wtof("%s: stderr 0x%08X", __func__, stderr); - if (!stderr) { - wtof("Unable to open STDERR %s", ddstderr); - goto quit; - } - - stdin = fopen(ddstdin, "r"); - // wtof("%s: stdin 0x%08X", __func__, stdin); - if (!stdin) { - stdin = fopen("'NULLFILE'", "r"); - // wtof("%s: stdin 0x%08X", __func__, stdin); - } - if (!stdin) { - wtof("Unable to open STDIN %s", ddstdin); - goto quit; - } - - if (loadenv("dd:SYSENV")) { - /* no SYSENV DD, try ENVIRON DD */ - loadenv("dd:ENVIRON"); - } - - /* initialize time zone offset for this thread */ - tzset(); - - if (parmLen >= sizeof(parmbuf) - 2) { - parmLen = sizeof(parmbuf) - 1 - 2; - } - if (parmLen < 0) - parmLen = 0; - - /* We copy the parameter into our own area because - the caller hasn't necessarily allocated room for - a terminating NUL, nor is it necessarily correct - to clobber the caller's area with NULs. */ - memset(parmbuf, 0, sizeof(parmbuf)); - if (grt->grtflag1 & GRTFLAG1_TSO) { - parmLen -= 4; - memcpy(parmbuf, p + 4, parmLen); - } else { - memcpy(parmbuf, p + 2, parmLen); - } - p = parmbuf; - - if (grt->grtflag1 & GRTFLAG1_TSO) { - argv[0] = p; - for (x = 0; x <= progLen; x++) { - if (argv[0][x] == ' ') { - argv[0][x] = 0; - break; - } - } - p += progLen; - } else { /* batch or tso "call" */ - argv[0] = pgmname; - pgmname[8] = '\0'; - pgmname = strchr(pgmname, ' '); - if (pgmname) - *pgmname = '\0'; - } - - while (*p == ' ') - p++; - - x = 1; - if (*p) { - while (x < MAXPARMS) { - char srch = ' '; - - if (*p == '"') { - p++; - srch = '"'; - } - argv[x++] = p; - p = strchr(p, srch); - if (!p) - break; - - *p = '\0'; - p++; - /* skip trailing blanks */ - while (*p == ' ') - p++; - if (*p == '\0') - break; - } - } - argv[x] = NULL; - argc = x; - - rc = main(argc, argv); - -quit: - if (stdin) { - // wtof("%s: fclose(stdin)", __func__); - fclose(stdin); - } - if (stdout) { - // wtof("%s: fclose(stdout)", __func__); - fclose(stdout); - } - if (stderr) { - // wtof("%s: fclose(stderr)", __func__); - fclose(stderr); - } - - /* release allocations */ - free_alloc(&ddstdin[3]); - free_alloc(&ddstdout[3]); - free_alloc(&ddstderr[3]); - - __exit(rc); - return (rc); -} - -int main(int argc, char **argv) { - int rc = 0; - CLIBPPA *ppa = __ppaget(); - CLIBGRT *grt = __grtget(); - CLIBCRT *crt = __crtget(); - UFS *ufs = NULL; - void *crtapp1 = NULL; - void *crtapp2 = NULL; - HTTPD *httpd = grt->grtapp1; - HTTPC *httpc = grt->grtapp2; - char *path = NULL; - char *script = NULL; - - if (!httpd) { - wtof("This program %s must be called by the HTTPD web server%s", argv[0], - ""); - /* TSO callers might not see a WTO message, so we send a STDOUT message too - */ - printf("This program %s must be called by the HTTPD web server%s", argv[0], - "\n"); - return 12; - } - - /* save for our exit/exterbnal programs */ - if (crt) { - // wtof("httplua.c:%s: crt=%p crt->crtufs=%p", __func__, crt, crt->crtufs); - crtapp1 = crt->crtapp1; - crtapp2 = crt->crtapp2; - ufs = crt->crtufs; - crt->crtapp1 = httpd; - crt->crtapp2 = httpc; - crt->crtufs = httpc->ufs; - } - - // wtof("%s: enter", argv[0]); - - // wtof("%s: ppa=0x%08X grt=0x%08X httpd=0x%08X httpc=0x%08X", - // argv[0], ppa, grt, httpd, httpc); - - /* get the request path string */ - path = http_get_env(httpc, "REQUEST_PATH"); - script = strrchr(path, '/'); - - // wtof("%s: path=\"%s\"", argv[0], path); - // wtof("%s: script=\"%s\"", argv[0], path); - - if (script) { - rc = main_lua(httpd, httpc, script); - } - -quit: - if (crt) { - /* restore crt values */ - crt->crtapp1 = crtapp1; - crt->crtapp2 = crtapp2; - crt->crtufs = ufs; - } - - // wtof("%s: exit rc=%d", argv[0], rc); - return rc; -} - -static int readable(const char *filename) { - CLIBCRT *crt = __getcrt(); - UFS *ufs = crt ? crt->crtufs : NULL; - UFSFILE *ufp = NULL; - FILE *f = NULL; - - // wtof("httplua.c:%s: enter \"%s\"", __func__, filename); - - if (ufs) { - ufp = ufs_fopen(ufs, filename, "r"); - // wtof("httplua.c:%s: ufp=%p", __func__, ufp); - if (ufp) { - /* this filename exist and is readable */ - ufs_fclose(&ufp); - goto okay; - } - } - - /* try opening as a dataset */ - f = fopen(filename, "r"); /* try to open file */ - // wtof("httplua.c:%s: f=%p", __func__, f); - if (f == NULL) - goto fail; /* open failed */ - fclose(f); - goto okay; - -fail: - // wtof("httplua.c:%s: exit 0", __func__); - return 0; - -okay: - // wtof("httplua.c:%s: exit 1", __func__); - return 1; -} - -static char *make_pathnames(const char *paths, const char *script) { - char *pathname = NULL; - int pathcount = 1; - int scriptlen = strlen(script); - int i; - char *p; - - // wtof("httplua.c:%s: enter paths=\"%s\" script=\"%s\"", __func__, paths, - // script); - - for (p = strchr(paths, ';'); p; p = strchr(p + 1, ';')) { - pathcount++; - } - - pathname = calloc(1, strlen(paths) + (scriptlen * pathcount)); - if (!pathname) - goto quit; - - for (p = pathname; *paths; paths++) { - *p = *paths; - if (*p == '?') { - strcpy(p, script); - p += scriptlen; - } else { - p++; - } - } - -quit: - // wtof("httplua.c:%s: exit pathname=\"%s\"", __func__, pathname); - return pathname; -} - -static int main_lua(HTTPD *httpd, HTTPC *httpc, const char *script) { - int rc = 0; - lua_State *L = NULL; - unsigned lines = 0; - unsigned errors = 0; - char *path = NULL; - char dataset[256]; - - // wtof("%s: enter script=\"%s\"", __func__, script); - - while (*script == '/') - script++; - - /* create new Lua state */ - L = luaL_newstate(); - // wtof("%s: lua_State=0x%08X", __func__, L); - - // dumpstack(L, __func__ ); - - /* Open Lua libraries */ - // wtof("%s: calling luaL_openlibs(L)", __func__); - luaL_openlibs(L); - - // dumpstack(L, __func__ ); - - /* Install http */ - // wtof("%s: calling luaL_requiref(L, \"http\", open_http, 1)", __func__); - luaL_requiref(L, "http", open_http, 1); - - // dumpstack(L, __func__ ); - lua_settop(L, 0); - -#if 0 /* debugging */ - path = getLuaPath(L); - wtof("%s: path=\"%s\"", __func__, path); - if (path) { - free(path); - path = NULL; - } -#endif /* debugging */ - - if (httpd->cgilua_path && httpd->cgilua_path[0]) { - setLuaPath(L, httpd->cgilua_path); - } - - if (httpd->cgilua_cpath && httpd->cgilua_cpath[0]) { - setLuaCPath(L, httpd->cgilua_cpath); - } - -#if 0 /* debugging */ - path = getLuaPath(L); - wtof("%s: path=\"%s\"", __func__, path); - if (path) { - free(path); - path = NULL; - } -#endif /* debugging */ - - // wtof("%s: ready to process script=%s", __func__, script); - - /* Here we're formatting the dataset stirng with the script - * member name to be found in the PDS allocated to the - * LUALIB DD. This should prevent any unwanted execution - * of Lua scripts from outside datasets. - */ - rc = strlen(script); - if (rc > 8) - rc = 8; - if (httpd->cgilua_dataset && httpd->cgilua_dataset[0]) { - sprintf(dataset, "%s(%.*s)", httpd->cgilua_dataset, rc, script); - if (readable(dataset)) - goto doit; - } - - // wtof("%s: httpd->cgilua_path=\"%s\"", __func__, httpd->cgilua_path); - if (httpd->cgilua_path && httpd->cgilua_path[0]) { - char *pathnames = make_pathnames(httpd->cgilua_path, script); - char *name; - char *rest; - - if (!pathnames) - goto dodd; - // wtof("%s: pathnames=\"%s\"", __func__, pathnames); - - for (name = strtok(pathnames, ";"); name; name = strtok(rest, ";")) { - rest = strtok(NULL, ""); - // wtof("%s: name=\"%s\" rest=\"%s\"", __func__, name, rest); - if (readable(name)) { - strcpy(dataset, name); - free(pathnames); - goto doit; - } - } - free(pathnames); - } - -dodd: - sprintf(dataset, "DD:CGILUA(%.*s)", rc, script); - if (readable(dataset)) - goto doit; - - /* last chance, see if the request path exist */ - script = http_get_env(httpc, "REQUEST_PATH"); - if (script) { - strcpy(dataset, script); - if (readable(dataset)) - goto doit; - } - - wtof("HTTPD417I CGI Lua script \"%s\" is not readable or does not exist", - script); - goto quit; - -doit: - // wtof("%s: calling luaL_dofile(L,\"%s\")", __func__, dataset); - rc = luaL_dofile(L, dataset); - if (rc) { - const char *s = lua_tostring(L, 1); - if (s && strstr(s, "cannot open") && strstr(s, "No Error")) { - wtof("HTTPD417I CGI Lua script \"%s\" does not exist", dataset); - } else { - /* Something went wrong, dump stack to console */ - wtof("HTTPD417E Error in CGI Lua script \"%s\"", dataset); - dumpstack(L, "HTTPD418E"); - } - } - - // dumpstack(L, __func__ ); - -#if 0 /* debugging */ - luaL_dostring(L, "if http.print then http.oprint = print, print = http.print end"); - luaL_dostring(L, "for n in pairs(_G) do print(n) end"); - luaL_dostring(L, "print('-------------------------------')"); - luaL_dostring(L, "for n in pairs(http) do print(n) end"); - luaL_dostring(L, "print('-------------------------------')"); - luaL_dostring(L, "print('http.server_version ' .. http.server_version)"); - luaL_dostring(L, "for n,v in pairs(http.vars) do print(n..'='..v) end"); - luaL_dostring(L, "print('-------------------------------')"); - luaL_dostring(L, "print(\"Hello\")"); -#endif /* debugging */ - - /* create response using STDOUT dataseet */ - // wtof("%s: calling process_stdout(httpd, httpc)", __func__); - lines = process_stdout(httpd, httpc); - - /* process any errors found in STDERR dataset */ - // wtof("%s: calling process_stderr(httpd, httpc, script)", __func__); - errors = process_stderr(httpd, httpc, script); - -quit: - if (path) - free(path); - - // wtof("%s: calling lua_close(L)", __func__); - if (L) - lua_close(L); - - if (!httpc->resp) { - if (errors) { - http_resp(httpc, 503); - http_printf(httpc, "Content-Type: %s\r\n", "text/plain"); - http_printf(httpc, "\r\n"); - http_printf(httpc, - "One or more errors occurred processing your request\n"); - } else { - http_resp(httpc, 200); - http_printf(httpc, "Content-Type: %s\r\n", "text/plain"); - http_printf(httpc, "\r\n"); - http_printf(httpc, - "Well this is weird, that Lua script \"%s\" didn't return " - "any output.\n", - script); - } - } - - httpc->state = CSTATE_DONE; - // wtof("%s: exit rc=%d", __func__, rc); - - // wtof("%s: exit rc=%d", __func__, rc); - return rc; -} - -static int setLuaPath(lua_State *L, const char *path) { - HTTPD *httpd = cgihttpd(); - - lua_getglobal(L, "package"); - - // wtof("%s: new path=\"%s\"", __func__, path); - - lua_pushstring(L, path); // push the new one - lua_setfield( - L, -2, - "path"); // set the field "path" in table at -2 with value at top of stack - lua_remove(L, -1); // get rid of package table from top of stack - - return 0; // all done! -} - -static int setLuaCPath(lua_State *L, const char *path) { - HTTPD *httpd = cgihttpd(); - - lua_getglobal(L, "package"); - - // wtof("%s: new path=\"%s\"", __func__, path); - - lua_pushstring(L, path); // push the new one - lua_setfield(L, -2, "cpath"); // set the field "path" in table at -2 with - // value at top of stack - lua_remove(L, -1); // get rid of package table from top of stack - - return 0; // all done! -} - -static char *getLuaPath(lua_State *L) { - HTTPD *httpd = cgihttpd(); - char *path; - - lua_getglobal(L, "package"); - lua_getfield(L, -1, - "path"); // get field "path" from table at top of stack (-1) - - path = strdup(lua_tostring(L, -1)); // grab path string from top of stack - // wtof("%s: path=\"%s\"", __func__, path); - - lua_pop(L, 1); // remove path string from stack - lua_pop(L, 1); // remove package table from stack - - return path; // don't forget to free this when your done -} - -static void dumpstack(lua_State *L, const char *funcname) { - HTTPD *httpd = cgihttpd(); - int top = lua_gettop(L); - int i; - int j; - char buf[256]; - - wtof("%s Stack Dump (%d)", funcname, top); - for (i = 1, j = -top; i <= top; i++, j++) { - const char *typename = luaL_typename(L, i); - sprintf(buf, "%3d (%d) %.12s", i, j, luaL_typename(L, i)); - switch (lua_type(L, i)) { - case LUA_TNUMBER: - wtof("%s %g", buf, lua_tonumber(L, i)); - break; - case LUA_TSTRING: - wtof("%s %s", buf, lua_tostring(L, i)); - break; - case LUA_TBOOLEAN: - wtof("%s %s", buf, (lua_toboolean(L, i) ? "true" : "false")); - break; - case LUA_TNIL: - wtof("%s %s", buf, "nil"); - break; - default: - wtof("%s %p", buf, lua_topointer(L, i)); - break; - } - } -} - -static int http_lua_print(lua_State *L) { - HTTPD *httpd = cgihttpd(); - HTTPC *httpc = cgihttpc(); - int top = lua_gettop(L); - int i; - const char *p; - char buf[80]; - - // wtof("%s: enter top=%d", __func__, top); - // wtof("%s: crt=%p httpd=%p httpc=%p", __func__, crt, httpd, httpc); - - for (i = 1; i <= top; i++) { - if (i > 1) /* not the first element? */ - process_print(httpd, httpc, "\t"); /* add a tab before it */ - - switch (lua_type(L, i)) { - case LUA_TNUMBER: - sprintf(buf, "%g", lua_tonumber(L, i)); - // wtof("%s: TNUMBER buf=\"%s\"", __func__, buf); - process_print(httpd, httpc, buf); - break; - case LUA_TSTRING: - p = lua_tostring(L, i); - // wtof("%s: TSTRING p=\"%s\"", __func__, p); - process_print(httpd, httpc, p); - break; - case LUA_TBOOLEAN: - sprintf(buf, "%s", (lua_toboolean(L, i) ? "true" : "false")); - // wtof("%s: TBOOLEAN buf=\"%s\"", __func__, buf); - process_print(httpd, httpc, buf); - break; - case LUA_TNIL: - p = "nil"; - // wtof("%s: TNIL p=\"%s\"", __func__, p); - process_print(httpd, httpc, p); - break; - default: - sprintf(buf, "%p", lua_topointer(L, i)); - // wtof("%s: default buf=\"%s\"", __func__, buf); - process_print(httpd, httpc, buf); - break; - } /* switch */ - // lua_pop(L, 1); /* pop result */ - } /* for */ - - lua_settop(L, 0); /* clear stack */ - -#if 0 - CLIBCRT *crt = __crtget(); - HTTPD *httpd = crt->crtapp1; - HTTPC *httpc = crt->crtapp2; - int top = lua_gettop(L); /* number of arguments */ - int i; - - for (i = 1; i <= top; i++) { /* for each argument */ - const char *s = lua_tostring(L, i); /* convert it to string */ - // wtof("%s: %3d \"%s\"", __func__, i, s); - if (i > 1) /* not the first element? */ - process_print(httpd, httpc, "\t"); /* add a tab before it */ - process_print(httpd, httpc, s); /* print it */ - lua_pop(L, 1); /* pop result */ - } -#endif - - process_print(httpd, httpc, "\n"); - // wtof("%s: exit", __func__); - - return 0; -} - -static int create_lua_vars(lua_State *L) { - HTTPD *httpd = cgihttpd(); - HTTPC *httpc = cgihttpc(); - unsigned count = array_count(&httpc->env); - unsigned n; - int i; - char *p; - char name[256]; - - lua_createtable(L, 0, count); - - for (n = 0; n < count; n++) { - HTTPV *env = httpc->env[n]; - - if (!env) - continue; - - for (i = 0; env->name[i]; i++) { - p = &env->name[i]; - if (*p == '-') { - name[i] = '_'; - } else { - name[i] = *p; - // name[i] = toupper(*p); - } - } - name[i] = 0; - - lua_pushstring(L, env->value); - lua_setfield(L, -2, name); - } - - /* returning 1 table on top of stack */ - return 1; -} - -static int open_http(lua_State *L) { - HTTPD *httpd = cgihttpd(); - luaL_Reg reg[] = { - {"print", http_lua_print}, - {"publish", http_lua_publish}, - {NULL, NULL}, - }; - - // dumpstack(L, __func__ ); - - luaL_newlib(L, reg); - - // dumpstack(L, __func__ ); - - /* create version */ - lua_pushstring(L, httpd->version); - lua_setfield(L, -2, "server_version"); - - /* create vars table */ - create_lua_vars(L); - lua_setfield(L, -2, "vars"); - - // dumpstack(L, __func__ ); - return 1; -} - -static int process_print(HTTPD *httpd, HTTPC *httpc, const char *buf) { - int rc = 0; - const char *p; - - if (!httpc->resp && __patmat(buf, "HTTP/?.? *")) { - /* looks like a HTTP response header */ - char *tmp = strdup(buf); - if (tmp) { - char *p1 = strtok(tmp, " "); /* HTTP/1.0 */ - char *p2 = strtok(NULL, " "); /* nnn */ - char *p3 = strtok(NULL, ""); /* OK or whatever */ - - if (p2) - httpc->resp = atoi(p2); - free(tmp); - } - } - - if (!httpc->resp) { - /* we don't have a HTTP response */ - http_resp(httpc, 200); - for (p = buf; *p == ' '; p++) - ; - if (p[0] == '<') { - /* looks like a HTML markup tag */ - http_printf(httpc, "Content-Type: %s\r\n", "text/html"); - } else { - /* anything else */ - http_printf(httpc, "Content-Type: %s\r\n", "text/plain"); - } - http_printf(httpc, "\r\n"); - } - - rc = http_printf(httpc, "%s", buf); - - return rc; -} - -static int process_stdout(HTTPD *httpd, HTTPC *httpc) { - int lines = 0; - FILE *fp = NULL; - char *p = NULL; - char buf[256]; - char ddstdout[12] = "DD:xxxxxxxx"; - - if (!stdout) - goto quit; - - strcpy(&ddstdout[3], stdout->ddname); - fclose(stdout); - stdout = NULL; - - /* create response */ - fp = fopen(ddstdout, "r"); - // wtof("%s: fopen(\"DD:STDOUT\",\"r\") fp=0x%08X", __func__, fp); - if (!fp) - goto quit; - - while (p = fgets(buf, sizeof(buf), fp)) { - if (!lines) { - if (!httpc->resp && __patmat(buf, "HTTP/?.? *")) { - /* looks like a HTTP response header */ - char *tmp = strdup(buf); - if (tmp) { - char *p1 = strtok(tmp, " "); /* HTTP/1.0 */ - char *p2 = strtok(NULL, " "); /* nnn */ - char *p3 = strtok(NULL, ""); /* OK or whatever */ - - if (p2) - httpc->resp = atoi(p2); - free(tmp); - } - } - - if (!httpc->resp) { - /* we don't have a HTTP response */ - http_resp(httpc, 200); - while (*p == ' ') - p++; - if (p[0] == '<') { - /* looks like a HTML markup tag */ - http_printf(httpc, "Content-Type: %s\r\n", "text/html"); - } else { - /* anything else */ - http_printf(httpc, "Content-Type: %s\r\n", "text/plain"); - } - http_printf(httpc, "\r\n"); - } - } - http_printf(httpc, "%s", buf); - lines++; - } - -quit: - if (fp) - fclose(fp); - - return lines; -} - -static int process_stderr(HTTPD *httpd, HTTPC *httpc, const char *script) { - int errors = 0; - FILE *fp = NULL; - char *p = NULL; - char buf[256]; - char ddstderr[12] = "DD:xxxxxxxx"; - - if (!stderr) - goto quit; - - strcpy(&ddstderr[3], stderr->ddname); - fclose(stderr); - stderr = NULL; - - fp = fopen(ddstderr, "r"); - // wtof("%s: fopen(\"DD:STDERR\",\"r\") fp=0x%08X", __func__, fp); - if (!fp) - goto quit; - - while (p = fgets(buf, sizeof(buf), fp)) { - if (!errors) { - wtof("HTTPD500I CGI Program HTTPLUA script \"%s\"", script); - } - // wtodumpf(buf, strlen(buf), "%s: stderr", __func__); - /* strip trailing newline */ - p = strrchr(buf, '\n'); - if (p) - *p = 0; - - wtof("HTTPD501I %s", buf); - errors++; - } - -quit: - if (fp) - fclose(fp); - return errors; -} - -static int free_alloc(const char *ddname) { - int err = 1; - unsigned count = 0; - TXT99 **txt99 = NULL; - RB99 rb99 = {0}; - - // wtof("%s: enter ddname=\"%s\"", __func__, ddname); - - /* we want to unallocate the DDNAME */ - err = __txddn(&txt99, ddname); - if (err) - goto quit; - - count = arraycount(&txt99); - if (!count) - goto quit; - - /* Set high order bit to mark end of list */ - count--; - txt99[count] = (TXT99 *)((unsigned)txt99[count] | 0x80000000); - - /* construct the request block for dynamic allocation */ - rb99.len = sizeof(RB99); - rb99.request = S99VRBUN; - rb99.flag1 = S99NOCNV; - rb99.txtptr = txt99; - - /* SVC 99 */ - err = __svc99(&rb99); - if (err) { - // wtof("%s: err=%d error=0x%04X info=0x%04X", __func__, err, rb99.error, - // rb99.info); - goto quit; - } - -quit: - if (txt99) - FreeTXT99Array(&txt99); - - // wtof("%s: exit rc=%d", __func__, err); - return err; -} - -static int alloc_temp(char *ddname, const char *tmpname) { - int err = 1; - unsigned count = 0; - TXT99 **txt99 = NULL; - RB99 rb99 = {0}; - char tempname[40]; - - // wtof("%s: enter ddname=\"%s\"", __func__, ddname); - if (!tmpname) - tmpname = "TEMP"; - snprintf(tempname, sizeof(tempname), "&%s", tmpname); - tempname[sizeof(tempname) - 1] = 0; - - /* we want the DDNAME returned to us */ - err = __txrddn(&txt99, NULL); - if (err) - goto quit; - - /* allocate this dataset */ - err = __txdsn(&txt99, tempname); - if (err) - goto quit; - - /* DISP=NEW */ - err = __txnew(&txt99, NULL); - if (err) - goto quit; - - /* BLKSIZE=27998 */ - err = __txbksz(&txt99, "27998"); - if (err) - goto quit; - - /* LRECL=255 */ - err = __txlrec(&txt99, "255"); - if (err) - goto quit; - - /* SPACE=...(pri,sec) */ - err = __txspac(&txt99, "15,15"); - if (err) - goto quit; - - /* SPACE=CYLS */ - err = __txcyl(&txt99, NULL); - if (err) - goto quit; - - /* RECFM=VB */ - err = __txrecf(&txt99, "VB"); - if (err) - goto quit; - - /* DSORG=PS */ - err = __txorg(&txt99, "PS"); - if (err) - goto quit; - - count = arraycount(&txt99); - if (!count) - goto quit; - - /* Set high order bit to mark end of list */ - count--; - txt99[count] = (TXT99 *)((unsigned)txt99[count] | 0x80000000); - - /* construct the request block for dynamic allocation */ - rb99.len = sizeof(RB99); - rb99.request = S99VRBAL; - rb99.flag1 = S99NOCNV; - rb99.txtptr = txt99; - - /* SVC 99 */ - err = __svc99(&rb99); - if (err) - goto quit; - - /* return DDNAME */ - memcpy(ddname, txt99[0]->text, 8); - -quit: - if (txt99) - FreeTXT99Array(&txt99); - - // wtof("%s: exit rc=%d", __func__, err); - return err; -} - -static int alloc_dummy(char *ddname) { - int err = 1; - unsigned count = 0; - TXT99 **txt99 = NULL; - RB99 rb99 = {0}; - - // wtof("%s: enter ddname=\"%s\"", __func__, ddname); - - /* we want the DDNAME returned to us */ - err = __txrddn(&txt99, NULL); - if (err) - goto quit; - - /* allocate dummy dataset */ - err = __txdmy(&txt99, NULL); - if (err) - goto quit; - - count = arraycount(&txt99); - if (!count) - goto quit; - - /* Set high order bit to mark end of list */ - count--; - txt99[count] = (TXT99 *)((unsigned)txt99[count] | 0x80000000); - - /* construct the request block for dynamic allocation */ - rb99.len = sizeof(RB99); - rb99.request = S99VRBAL; - rb99.flag1 = S99NOCNV; - rb99.txtptr = txt99; - - /* SVC 99 */ - err = __svc99(&rb99); - if (err) - goto quit; - - /* return DDNAME */ - memcpy(ddname, txt99[0]->text, 8); - -quit: - if (txt99) - FreeTXT99Array(&txt99); - - // wtof("%s: exit rc=%d", __func__, err); - return err; -} - -/* TSK-104: HTTPLUA moves to external project, httpd->luax dependency goes away */ -static int http_lua_publish(lua_State *L) { - HTTPD *httpd = cgihttpd(); /* needed for HTTPLUAX macro expansion */ - lua_pushinteger(L, 4); - lua_pushstring(L, "publish: not available"); - return 2; -} diff --git a/src/httpluax.c b/src/httpluax.c deleted file mode 100644 index 8d00258..0000000 --- a/src/httpluax.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * HTTPLUAX.C - Loads all Lua functions into struct of Lua function - * pointers that can then be called via pointer to function pointers. - */ -#define HTTPLUAX_PRIVATE /* we don't want the defines */ -#include "httpluax.h" - -LUAX httpluax = { - lua_ident, lua_newstate, lua_close, - lua_newthread, lua_closethread, lua_resetthread, - lua_atpanic, lua_version, lua_absindex, - lua_gettop, lua_settop, lua_pushvalue, - lua_rotate, lua_copy, lua_checkstack, - lua_xmove, lua_isnumber, lua_isstring, - lua_iscfunction, lua_isinteger, lua_isuserdata, - lua_type, lua_typename, lua_tonumberx, - lua_tointegerx, lua_toboolean, lua_tolstring, - lua_rawlen, lua_tocfunction, lua_touserdata, - lua_tothread, lua_topointer, lua_rawequal, - lua_compare, lua_pushnil, lua_pushnumber, - lua_pushinteger, lua_pushlstring, lua_pushstring, - lua_pushvfstring, lua_pushfstring, lua_pushcclosure, - lua_pushboolean, lua_pushlightuserdata, lua_pushthread, - lua_getglobal, lua_gettable, lua_getfield, - lua_geti, lua_rawget, lua_rawgeti, - lua_rawgetp, lua_createtable, lua_newuserdatauv, - lua_getmetatable, lua_getiuservalue, lua_setglobal, - lua_settable, lua_setfield, lua_seti, - lua_rawset, lua_rawseti, lua_rawsetp, - lua_setmetatable, lua_setiuservalue, lua_callk, - lua_pcallk, lua_load, lua_dump, - lua_yieldk, lua_resume, lua_status, - lua_isyieldable, lua_setwarnf, lua_warning, - lua_gc, lua_error, lua_next, - lua_concat, lua_len, lua_stringtonumber, - lua_getallocf, lua_setallocf, lua_toclose, - lua_closeslot, lua_getstack, lua_getinfo, - lua_getlocal, lua_setlocal, lua_getupvalue, - lua_setupvalue, lua_upvalueid, lua_upvaluejoin, - lua_sethook, lua_gethook, lua_gethookmask, - lua_gethookcount, lua_setcstacklimit, lua_arith, - (void*)0, (void*)0, (void*)0, - /* 0x198 (408 bytes) */ - /* LAUXLIB */ - luaL_checkversion_, luaL_getmetafield, luaL_callmeta, - luaL_tolstring, luaL_argerror, luaL_typeerror, - luaL_checklstring, luaL_optlstring, luaL_checknumber, - luaL_optnumber, luaL_checkinteger, luaL_optinteger, - luaL_checkstack, luaL_checktype, luaL_checkany, - luaL_newmetatable, luaL_setmetatable, luaL_testudata, - luaL_checkudata, luaL_where, luaL_error, - luaL_checkoption, luaL_fileresult, luaL_execresult, - luaL_ref, luaL_unref, luaL_loadfilex, - luaL_loadbufferx, luaL_loadstring, luaL_newstate, - luaL_len, luaL_addgsub, luaL_gsub, - luaL_setfuncs, luaL_getsubtable, luaL_traceback, - luaL_requiref, luaL_buffinit, luaL_prepbuffsize, - luaL_addlstring, luaL_addstring, luaL_addvalue, - luaL_pushresult, luaL_pushresultsize, luaL_buffinitsize, - luaL_openlibs, (void*)0, (void*)0 - /* 0x258 (600 bytes */ -}; diff --git a/src/httppc.c b/src/httppc.c index 9518e38..a09b133 100644 --- a/src/httppc.c +++ b/src/httppc.c @@ -79,6 +79,15 @@ httppc(HTTPC *httpc) goto check_done; } + /* extension-based CGI (pattern starts with "*."): + set SCRIPT_FILENAME = docroot + request path */ + if (cgi->path[0] == '*' && cgi->path[1] == '.') { + char scriptfile[384]; + snprintf(scriptfile, sizeof(scriptfile), "%s%s", + httpd->docroot, path); + http_set_env(httpc, "SCRIPT_FILENAME", scriptfile); + } + /* path needs to be processed by external program */ rc = http_process_cgi(httpc, cgi); goto check_done; diff --git a/src/httpprm.c b/src/httpprm.c index 0fd1394..5e61a61 100644 --- a/src/httpprm.c +++ b/src/httpprm.c @@ -109,9 +109,6 @@ set_defaults(HTTPD *httpd) httpd->bind_tries = 10; httpd->bind_sleep = 10; httpd->listen_queue = 5; - httpd->cgilua_dataset = NULL; - httpd->cgilua_path = NULL; - httpd->cgilua_cpath = NULL; httpd->unused_80 = NULL; strcpy(httpd->docroot, "/www"); httpd->codepage[0] = '\0'; @@ -303,15 +300,6 @@ parse_keyvalue(HTTPD *httpd, const char *key, const char *value) free(tmp); } - else if (strcmp(key, "CGILUA_DATASET") == 0) { - httpd->cgilua_dataset = strdup(value); - } - else if (strcmp(key, "CGILUA_PATH") == 0) { - httpd->cgilua_path = strdup(value); - } - else if (strcmp(key, "CGILUA_CPATH") == 0) { - httpd->cgilua_cpath = strdup(value); - } else if (strcmp(key, "CLIENT_TIMEOUT_MSG") == 0) { if (atoi(value) > 0) httpd->client |= HTTPD_CLIENT_INMSG; else httpd->client &= ~HTTPD_CLIENT_INMSG; diff --git a/src/httprexx.c b/src/httprexx.c deleted file mode 100644 index 5db36ad..0000000 --- a/src/httprexx.c +++ /dev/null @@ -1,587 +0,0 @@ -/* HTTPREXX.C - CGI Program, REST style CGI program to link BREXX and execute script */ -#include "httpd.h" -#include "svc99.h" -#include "clibary.h" -#include "clibos.h" - -#define httpx (httpd->httpx) - -static int link_rexx(HTTPD *httpd, HTTPC *httpc, const char *script); - -int main(int argc, char **argv) -{ - int rc = 0; - CLIBPPA *ppa = __ppaget(); - CLIBGRT *grt = __grtget(); - CLIBCRT *crt = __crtget(); - void *crtapp1= NULL; - void *crtapp2= NULL; - HTTPD *httpd = grt->grtapp1; - HTTPC *httpc = grt->grtapp2; - char *path = NULL; - char *script = NULL; - - if (!httpd) { - wtof("This program %s must be called by the HTTPD web server%s", argv[0], ""); - /* TSO callers might not see a WTO message, so we send a STDOUT message too */ - printf("This program %s must be called by the HTTPD web server%s", argv[0], "\n"); - return 12; - } - - /* save for our exit/exterbnal programs */ - if (crt) { - crtapp1 = crt->crtapp1; - crtapp2 = crt->crtapp2; - crt->crtapp1 = httpd; - crt->crtapp2 = httpc; - } - - // wtof("%s: enter", argv[0]); - - // wtof("%s: ppa=0x%08X grt=0x%08X httpd=0x%08X httpc=0x%08X", - // argv[0], ppa, grt, httpd, httpc); - - /* get the request path string */ - path = http_get_env(httpc, "REQUEST_PATH"); - script = strrchr(path, '/'); - - // wtof("%s: path=\"%s\"", argv[0], path); - // wtof("%s: script=\"%s\"", argv[0], path); - - if (script) { - rc = link_rexx(httpd, httpc, script); - } - -quit: - if (crt) { - /* restore crt values */ - crt->crtapp1 = crtapp1; - crt->crtapp2 = crtapp2; - } - - // wtof("%s: exit rc=%d", argv[0], rc); - return rc; -} - -static int link(HTTPD *httpd, HTTPC *httpc, const char *pgm, const char *script); -static int alloc_dummy(const char *ddanme); -static int alloc_temp(const char *ddname); -static int alloc_temp_vars(const char *ddname); -static int free_alloc(const char *ddname); -static int process_stdout(HTTPD *httpd, HTTPC *httpc); -static int process_stderr(HTTPD *httpd, HTTPC *httpc, const char *script); -static int process_abend(HTTPD *httpd, HTTPC *httpc, int rc); -static int create_vars(HTTPD *httpd, HTTPC *httpc); - -static int -link_rexx(HTTPD *httpd, HTTPC *httpc, const char *script) -{ - int rc = 0; - int lockrc = 0; - int lines = 0; - int errors = 0; - void *httpsay = NULL; - void *dcb = 0; - unsigned size = 0; - char ac = 0; - CDE *cde; - - // wtof("%s: enter", __func__); - - /* get the steplib DCB */ - dcb = __steplb(); - /* load the HTTPSAY module into storage */ - httpsay = __load(dcb, "HTTPSAY ", &size, &ac); - - // wtof("%s: HTTPSAY ep=%08X size=%u, ac=%u", __func__, httpsay, size, ac); - - /* Serialize (lock) the address of this function so that - * only one CGI instance (for BREXX) runs at a time. - */ - lockrc = lock(link_rexx, LOCK_EXC); - - while(*script=='/') script++; - - /* just in case we have stale allocations */ - free_alloc("STDIN"); - free_alloc("STDOUT"); - free_alloc("STDERR"); - - /* allocate dataset for BREXX */ - rc = alloc_dummy("STDIN"); - if (rc) goto quit; - - rc = alloc_temp("STDOUT"); - if (rc) goto quit; - - rc = alloc_temp("STDERR"); - if (rc) goto quit; - - /* write server/client variables to "DD:HTTPVARS" */ - rc = create_vars(httpd, httpc); - if (rc) goto quit; - - /* link to external program */ - rc = link(httpd, httpc, "BREXX", script); - if (rc < 0) process_abend(httpd, httpc, rc); - - /* create response using STDOUT dataseet */ - lines = process_stdout(httpd, httpc); - - /* process any errors found in STDERR dataset */ - errors = process_stderr(httpd, httpc, script); - -deallocate: - /* release allocations */ - free_alloc("STDIN"); - free_alloc("STDOUT"); - free_alloc("STDERR"); - free_alloc("HTTPVARS"); - -quit: - if (lockrc==0) unlock(link_rexx, LOCK_EXC); - - if (httpsay) __delete("HTTPSAY "); - - if (!httpc->resp) { - http_resp(httpc,503); - http_printf(httpc, "Content-Type: %s\r\n", "text/plain"); - http_printf(httpc, "\r\n"); - http_printf(httpc, "One or more errors occurred processing your request\n"); - } - - httpc->state = CSTATE_DONE; - // wtof("%s: exit rc=%d", __func__, rc); - return rc; -} - -static int -link(HTTPD *httpd, HTTPC *httpc, const char *pgm, const char *script) -{ - void *ppa = NULL; - int rc = -1; /* link return code */ - int prc = -1; /* pgm return code */ - void *dcb = NULL; /* no DCB for link */ - char *query; - struct { - unsigned short len; - char buf[512]; - } parms = {0, ""}; - unsigned plist[4]; - - // wtof("%s: enter", __func__); - - if (!pgm) goto quit; /* NULL program, quit */ - if (!*pgm) goto quit; /* "" program name, quit */ - - query = http_get_env(httpc, "QUERY_STRING"); - if (!query) query = ""; - - if (script) { - /* put request in quotes as parameter string */ - snprintf(parms.buf, sizeof(parms.buf)-1, "%s \"%s\"", script, query); - parms.buf[sizeof(parms.buf)-1] = 0; - parms.len = strlen(parms.buf); - } - - // wtodumpf(&parms, sizeof(parms), "%s: parms", __func__); - - /* build parameter list for the program we're linking to */ - plist[0] = (unsigned)&parms | 0x80000000; - plist[1] = 0; - plist[2] = 0; - plist[3] = 0; - - // wtodumpf(plist, sizeof(plist), "%s: plist", __func__); - - /* link to pgm, with ESTAE */ - rc = __linkds(pgm, dcb, plist, &prc); - // wtof("%s: __linkds(\"%s\",0,0x%08X,0x%08X) rc=%d prc=%d", - // __func__, pgm, plist, &prc, rc, prc); - - if (rc==0) rc = prc; - -quit: - // wtof("%s: exit rc=%d", __func__, rc); - return rc; -} - -static int -create_vars(HTTPD *httpd, HTTPC *httpc) -{ - int rc = 0; - FILE *fp = NULL; - char *p; - char name[256]; - - free_alloc("HTTPVARS"); - - rc = alloc_temp_vars("HTTPVARS"); - if (rc) goto quit; - - /* create dataset containing client variables */ - fp = fopen("DD:HTTPVARS", "w"); - if (!fp) goto quit; - - if (httpc->env) { - unsigned count = array_count(&httpc->env); - unsigned n; - for(n=0;nenv[n]; - - if (!env) continue; - - /* BREXX doesn't permit variable names with '-' in the name - * so we'll transform those to underscore characters. - */ - strcpy(name, env->name); - for(p=strchr(name,'-'); p; p=strchr(name,'-')) *p = '_'; - fprintf(fp, "%s=\"%s\"\n", name, env->value); - // wtof("%s: %s=\"%s\"", __func__, name, env->value); - } - } - -quit: - if (fp) fclose(fp); - return rc; -} - -static int -process_stdout(HTTPD *httpd, HTTPC *httpc) -{ - int lines = 0; - FILE *fp = NULL; - char *p = NULL; - char buf[256]; - - /* create response */ - fp = fopen("DD:STDOUT", "r"); - // wtof("%s: fopen(\"DD:STDOUT\",\"r\") fp=0x%08X", __func__, fp); - if (!fp) goto quit; - - while(p=fgets(buf, sizeof(buf), fp)) { - if (!lines) { - if (!httpc->resp && __patmat(buf, "HTTP/?.? *")) { - /* looks like a HTTP response header */ - char *tmp = strdup(buf); - if (tmp) { - char *p1 = strtok(tmp, " "); /* HTTP/1.0 */ - char *p2 = strtok(NULL, " "); /* nnn */ - char *p3 = strtok(NULL, ""); /* OK or whatever */ - - if (p2) httpc->resp = atoi(p2); - free(tmp); - } - } - - if (!httpc->resp) { - /* we don't have a HTTP response */ - http_resp(httpc,200); - while(*p==' ') p++; - if (p[0]=='<') { - /* looks like a HTML markup tag */ - http_printf(httpc, "Content-Type: %s\r\n", "text/html"); - } - else { - /* anything else */ - http_printf(httpc, "Content-Type: %s\r\n", "text/plain"); - } - http_printf(httpc, "\r\n"); - } - } - http_printf(httpc, "%s", buf); - lines++; - } - -quit: - if (fp) fclose(fp); - - return lines; -} - -static int -process_stderr(HTTPD *httpd, HTTPC *httpc, const char *script) -{ - int errors = 0; - FILE *fp = NULL; - char *p = NULL; - char buf[256]; - - fp = fopen("DD:STDERR", "r"); - // wtof("%s: fopen(\"DD:STDERR\",\"r\") fp=0x%08X", __func__, fp); - if (!fp) goto quit; - - while(p=fgets(buf, sizeof(buf), fp)) { - if (!errors) { - wtof("HTTPD500I CGI Program BREXX script \"%s\"", script); - } - // wtodumpf(buf, strlen(buf), "%s: stderr", __func__); - /* strip trailing newline */ - p = strrchr(buf, '\n'); - if (p) *p = 0; - - wtof("HTTPD501I %s", buf); - errors++; - } - -quit: - if (fp) fclose(fp); - return errors; -} - -static int -process_abend(HTTPD *httpd, HTTPC *httpc, int rc) -{ - /* some kind of ABEND occurred */ - unsigned abcode = (unsigned) (rc * -1); /* make positive again */ - - /* we're running in the HTTPD server */ - if (!httpc->resp) { - /* no response header was issued by CGI program */ - http_resp(httpc,503); - http_printf(httpc, "Content-Type: %s\r\n", "text/plain"); - http_printf(httpc, "\r\n"); - } - - if (abcode > 4095) { - /* system abend occurred */ - http_printf(httpc, "External program %s failed with S%03X ABEND", "BREXX", abcode >> 12); - wtof("External program %s failed with S%03X ABEND", "BREXX", abcode >> 12); - } - else { - /* user abend code */ - http_printf(httpc, "External program %s failed with U%04d ABEND", "BREXX", abcode); - wtof("External program %s failed with U%04d ABEND", "BREXX", abcode); - } - http_printf(httpc, "\n"); - - return rc; -} - -static int -alloc_dummy(const char *ddname) -{ - int err = 1; - unsigned count = 0; - TXT99 **txt99 = NULL; - RB99 rb99 = {0}; - - // wtof("%s: enter ddname=\"%s\"", __func__, ddname); - - /* allocate this dd name */ - err = __txddn(&txt99, ddname); - if (err) goto quit; - - /* allocate dummy dataset */ - err = __txdmy(&txt99, NULL); - if (err) goto quit; - - count = arraycount(&txt99); - if (!count) goto quit; - - /* Set high order bit to mark end of list */ - count--; - txt99[count] = (TXT99*)((unsigned)txt99[count] | 0x80000000); - - /* construct the request block for dynamic allocation */ - rb99.len = sizeof(RB99); - rb99.request = S99VRBAL; - rb99.flag1 = S99NOCNV; - rb99.txtptr = txt99; - - /* SVC 99 */ - err = __svc99(&rb99); - if (err) goto quit; - -quit: - if (txt99) FreeTXT99Array(&txt99); - - // wtof("%s: exit rc=%d", __func__, err); - return err; -} - -static int alloc_temp(const char *ddname) -{ - int err = 1; - unsigned count = 0; - TXT99 **txt99 = NULL; - RB99 rb99 = {0}; - char tempname[40]; - - // wtof("%s: enter ddname=\"%s\"", __func__, ddname); - - snprintf(tempname, sizeof(tempname), "&%s", ddname); - tempname[sizeof(tempname)-1] = 0; - - /* allocate this dd name */ - err = __txddn(&txt99, ddname); - if (err) goto quit; - - /* allocate this dataset */ - err = __txdsn(&txt99, tempname); - if (err) goto quit; - - /* DISP=NEW */ - err = __txnew(&txt99, NULL); - if (err) goto quit; - - /* BLKSIZE=27998 */ - err = __txbksz(&txt99, "27998"); - if (err) goto quit; - - /* LRECL=255 */ - err = __txlrec(&txt99, "255"); - if (err) goto quit; - - /* SPACE=...(pri,sec) */ - err = __txspac(&txt99, "15,15"); - if (err) goto quit; - - /* SPACE=CYLS */ - err = __txcyl(&txt99, NULL); - if (err) goto quit; - - /* RECFM=VB */ - err = __txrecf(&txt99, "VB"); - if (err) goto quit; - - /* DSORG=PS */ - err = __txorg(&txt99, "PS"); - if (err) goto quit; - - count = arraycount(&txt99); - if (!count) goto quit; - - /* Set high order bit to mark end of list */ - count--; - txt99[count] = (TXT99*)((unsigned)txt99[count] | 0x80000000); - - /* construct the request block for dynamic allocation */ - rb99.len = sizeof(RB99); - rb99.request = S99VRBAL; - rb99.flag1 = S99NOCNV; - rb99.txtptr = txt99; - - /* SVC 99 */ - err = __svc99(&rb99); - if (err) goto quit; - -quit: - if (txt99) FreeTXT99Array(&txt99); - - // wtof("%s: exit rc=%d", __func__, err); - return err; -} - -static int alloc_temp_vars(const char *ddname) -{ - int err = 1; - unsigned count = 0; - TXT99 **txt99 = NULL; - RB99 rb99 = {0}; - char tempname[40]; - - // wtof("%s: enter ddname=\"%s\"", __func__, ddname); - - snprintf(tempname, sizeof(tempname), "&%s", ddname); - tempname[sizeof(tempname)-1] = 0; - - /* allocate this dd name */ - err = __txddn(&txt99, ddname); - if (err) goto quit; - - /* allocate this dataset */ - err = __txdsn(&txt99, tempname); - if (err) goto quit; - - /* DISP=NEW */ - err = __txnew(&txt99, NULL); - if (err) goto quit; - - /* BLKSIZE=27998 */ - err = __txbksz(&txt99, "27998"); - if (err) goto quit; - - /* LRECL=8232 */ - err = __txlrec(&txt99, "8232"); - if (err) goto quit; - - /* SPACE=...(pri,sec) */ - err = __txspac(&txt99, "15,15"); - if (err) goto quit; - - /* SPACE=TRACKS */ - err = __txtrk(&txt99, NULL); - if (err) goto quit; - - /* RECFM=FB */ - err = __txrecf(&txt99, "VB"); - if (err) goto quit; - - /* DSORG=PS */ - err = __txorg(&txt99, "PS"); - if (err) goto quit; - - count = arraycount(&txt99); - if (!count) goto quit; - - /* Set high order bit to mark end of list */ - count--; - txt99[count] = (TXT99*)((unsigned)txt99[count] | 0x80000000); - - /* construct the request block for dynamic allocation */ - rb99.len = sizeof(RB99); - rb99.request = S99VRBAL; - rb99.flag1 = S99NOCNV; - rb99.txtptr = txt99; - - /* SVC 99 */ - err = __svc99(&rb99); - if (err) goto quit; - -quit: - if (txt99) FreeTXT99Array(&txt99); - - // wtof("%s: exit rc=%d", __func__, err); - return err; -} - -static int free_alloc(const char *ddname) -{ - int err = 1; - unsigned count = 0; - TXT99 **txt99 = NULL; - RB99 rb99 = {0}; - - // wtof("%s: enter ddname=\"%s\"", __func__, ddname); - - /* we want to unallocate the DDNAME */ - err = __txddn(&txt99, ddname); - if (err) goto quit; - - count = arraycount(&txt99); - if (!count) goto quit; - - /* Set high order bit to mark end of list */ - count--; - txt99[count] = (TXT99*)((unsigned)txt99[count] | 0x80000000); - - /* construct the request block for dynamic allocation */ - rb99.len = sizeof(RB99); - rb99.request = S99VRBUN; - rb99.flag1 = S99NOCNV; - rb99.txtptr = txt99; - - /* SVC 99 */ - err = __svc99(&rb99); - if (err) { - // wtof("%s: err=%d error=0x%04X info=0x%04X", __func__, err, rb99.error, rb99.info); - goto quit; - } - -quit: - if (txt99) FreeTXT99Array(&txt99); - - // wtof("%s: exit rc=%d", __func__, err); - return err; -} diff --git a/src/httpsay.c b/src/httpsay.c deleted file mode 100644 index 8b2fd10..0000000 --- a/src/httpsay.c +++ /dev/null @@ -1,162 +0,0 @@ -#include "httpd.h" -#include "clibppa.h" -#include "clibgrt.h" - -/* MVS style parameter when called from BREXX for - * ADDRESS LINKMVS "HTTPVARS var1 .. var15" - */ -typedef struct parm { - short len; - char buf[1]; -} PARM; - -/* BREXX structs */ -typedef struct efpl { - void *efplcom; /* reserved */ - void *efplbarg; /* reserved */ - void *efplearg; /* reserved */ - void *efplfb; /* reserved */ - void *efplarg; /* Pointer to arguments table */ - void *efpleval; /* Pointer to address of the EVALBLOCK */ -} EFPL; - -typedef struct argtable_entry { - void *argtable_argstring_ptr; /* Address of the argument string */ - int argtable_argstring_length; /* Length of the argument string */ -} ATE; - -typedef struct evalblock { - int evalblock_evpad1; /* reserved - set to binary zero */ - int evalblock_evsize; /* Size of EVALBLOCK in double words */ - int evalblock_evlen; /* Length of data */ - int evalblock_evpad2; /* reserved - set to binary zero */ - unsigned char evalblock_evdata[1]; /* Result */ -} EVAL; - -#define MAXPARMS 15 /* maximum number of arguments we can handle */ - -extern int main(int argc, char **argv); -extern void __exita(int status); - -static int process_say(HTTPD *httpd, HTTPC *httpc, const char *buf); - -/* initialize to 0 to prevent linkage editor from trying to resolve httpx */ -HTTPX *httpx = 0; - -/* we want to use the httpx pointer in the httpd struct for the various - http_xxx functions, so we define httpx to do just that -*/ -#define httpx (httpd->httpx) - -/* NOTE: This code expects to be called from @@CRTM which is - * a minimal @@CRT0 implementation that does not create a - * PPA area in the stack. This allows the @@PPAGET code to - * locate the PPA of the parent so that the GRT area can be - * located and used for the HTTPD and HTTPC pointers. - */ -int -__start(void *r0, char *pgmname, int tsojbid, void **r1) -{ - int rc = 0; - // CLIBPPA *ppa = __ppaget(); - CLIBGRT *grt = __grtget(); - // CLIBCRT *crt = __crtget(); - HTTPD *httpd = grt->grtapp1; - HTTPC *httpc = grt->grtapp2; - PARM *parm; - EFPL *efpl = NULL; - ATE *ate = NULL; - // EVAL *eval = NULL; - char *buf = NULL; - int i; - -#if 0 - wtof("%s: r0=0x%08X", __func__, r0); - wtodumpf(r0, 32, "r0"); - wtof("%s: r1=0x%08X", __func__, r1); - wtodumpf(r1, 32, "r1"); -#endif - -#if 1 - /* This code for ADDRESS LINKMVS "HTTPSAY var1 var2 ... var15" */ - if (r1) { - for(parm = r1[0], i=0; i < MAXPARMS; parm = r1[++i]) { - if (!parm) break; - // wtodumpf(parm, 32, "parm[%d]", i); - - buf = calloc(1, parm->len + 1); - if (buf) { - memcpy(buf, parm->buf, parm->len); - rc = process_say(httpd, httpc, buf); - free(buf); - buf = NULL; - } - - if ((unsigned)parm & 0x80000000) break; - } - } - -#else - /* this code for BREXX call HTTPSAY(parms,...) */ - if (r1) { - efpl = (EFPL *)r1; - - ate = (ATE *)efpl->efplarg; - for(i=0; i < MAXPARMS; i++, ate++) { - if (!ate || ate->argtable_argstring_ptr == (void*)0xFFFFFFFF) break; - - buf = calloc(1, ate->argtable_argstring_length + 1); - if (buf) { - memcpy(buf, ate->argtable_argstring_ptr, ate->argtable_argstring_length); - rc = process_say(httpd, httpc, buf); - free(buf); - buf = NULL; - } - } - } -#endif - -quit: - if (buf) free(buf); - __exit(rc); - return (rc); -} - -static int -process_say(HTTPD *httpd, HTTPC *httpc, const char *buf) -{ - int rc = 0; - const char *p; - - if (!httpc->resp && __patmat(buf, "HTTP/?.? *")) { - /* looks like a HTTP response header */ - char *tmp = strdup(buf); - if (tmp) { - char *p1 = strtok(tmp, " "); /* HTTP/1.0 */ - char *p2 = strtok(NULL, " "); /* nnn */ - char *p3 = strtok(NULL, ""); /* OK or whatever */ - - if (p2) httpc->resp = atoi(p2); - free(tmp); - } - } - - if (!httpc->resp) { - /* we don't have a HTTP response */ - http_resp(httpc,200); - for(p = buf; *p==' '; p++); - if (p[0]=='<') { - /* looks like a HTML markup tag */ - http_printf(httpc, "Content-Type: %s\r\n", "text/html"); - } - else { - /* anything else */ - http_printf(httpc, "Content-Type: %s\r\n", "text/plain"); - } - http_printf(httpc, "\r\n"); - } - - http_printf(httpc, "%s\n", buf); - - return rc; -} diff --git a/src/lauxlib.c b/src/lauxlib.c deleted file mode 100644 index 3b00003..0000000 --- a/src/lauxlib.c +++ /dev/null @@ -1,1310 +0,0 @@ -/* -** $Id: lauxlib.c $ -** Auxiliary functions for building Lua libraries -** See Copyright Notice in lua.h -*/ - -/* This is a copy of lauxlib.c from LUA370 with modifications - * to support UFS in the HTTPD environment. - */ - -#define lauxlib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include -#include -#include - - -/* -** This file uses only the official API of Lua. -** Any function declared here could be written as an application function. -*/ - -#include "lua.h" - -#include "lauxlib.h" - -#define HTTPLUAX_PRIVATE /* suppress defines for Lua functions */ -//#define luai_likely(x) (x) -//#define luai_unlikely(x) (x) -#include "httpd.h" - -static UFSFILE *get_ufsfile(FILE *fp) -{ - unsigned x = (unsigned)fp; - UFSFILE *f = NULL; - - if (x & 0x80000000) { - f = (UFSFILE *) (x & 0x7FFFFFFF); - } - - return f; -} - -static int is_member(const char *mem) -{ - int i; - int len; - - if (*mem=='(') mem++; - - for(i=0; mem[i] && !(mem[i]==')'); i++) { - if (i > 7) return 0; - if (i==0 && (isalpha(mem[i]) || strchr("@#$", mem[i]))) continue; - if (i >0 && (isalnum(mem[i]) || strchr("@#$", mem[i]))) continue; - return 0; // invalid character for member name - } - - if (mem[i]==')') { - len = strlen(&mem[i+1]); - } - else { - len = strlen(&mem[i]); - } - - if (len==0) { - if (i>0 && i<8) { - return 1; - } - } - return 0; -} - -static int is_dataset(const char *name) -{ - int i; - char *p; - char buf[256]; - - if (!name) return 0; - if (*name=='\'') return 1; // This has to be a dataset - - strcpyp(buf, sizeof(buf), (void*)name, 0); - buf[sizeof(buf)-1] = 0; - - for(i=1, p=buf; p[i]; p++, i++) { - if (*p=='.') { - i = 0; - continue; - } - - if (*p=='(') { - return is_member(p); - } - - if (i > 8) return 0; - - if (i==1) { - if ( isalpha(*p) || strchr("@#$", *p) ) continue; - } - else { - if ( isalnum(*p) || strchr("@#$", *p) ) continue; - } - return 0; // invalid character for dataset name - } - - if (i>1 && i<9) { - return 1; - } - return 0; -} - -static int is_pathname(const char *name) -{ - if (!name) return 0; // not path - - if (strchr(name, '\'')) return 0; // not path - - if (strchr(name, '/')) return 1; // most likely is a path - - if (is_dataset(name)) return 0; // not path, looks like a dataset name - - return 1; -} - -#if !defined(MAX_SIZET) -/* maximum value for size_t */ -#define MAX_SIZET ((size_t)(~(size_t)0)) -#endif - - -/* -** {====================================================== -** Traceback -** ======================================================= -*/ - - -#define LEVELS1 10 /* size of the first part of the stack */ -#define LEVELS2 11 /* size of the second part of the stack */ - - - -/* -** Search for 'objidx' in table at index -1. ('objidx' must be an -** absolute index.) Return 1 + string at top if it found a good name. -*/ -static int findfield (lua_State *L, int objidx, int level) { - if (level == 0 || !lua_istable(L, -1)) - return 0; /* not found */ - lua_pushnil(L); /* start 'next' loop */ - while (lua_next(L, -2)) { /* for each pair in table */ - if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ - if (lua_rawequal(L, objidx, -1)) { /* found object? */ - lua_pop(L, 1); /* remove value (but keep name) */ - return 1; - } - else if (findfield(L, objidx, level - 1)) { /* try recursively */ - /* stack: lib_name, lib_table, field_name (top) */ - lua_pushliteral(L, "."); /* place '.' between the two names */ - lua_replace(L, -3); /* (in the slot occupied by table) */ - lua_concat(L, 3); /* lib_name.field_name */ - return 1; - } - } - lua_pop(L, 1); /* remove value */ - } - return 0; /* not found */ -} - - -/* -** Search for a name for a function in all loaded modules -*/ -static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { - int top = lua_gettop(L); - lua_getinfo(L, "f", ar); /* push function */ - lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); - if (findfield(L, top + 1, 2)) { - const char *name = lua_tostring(L, -1); - if (strncmp(name, LUA_GNAME ".", 3) == 0) { /* name start with '_G.'? */ - lua_pushstring(L, name + 3); /* push name without prefix */ - lua_remove(L, -2); /* remove original name */ - } - lua_copy(L, -1, top + 1); /* copy name to proper place */ - lua_settop(L, top + 1); /* remove table "loaded" and name copy */ - return 1; - } - else { - lua_settop(L, top); /* remove function and global table */ - return 0; - } -} - - -static void pushfuncname (lua_State *L, lua_Debug *ar) { - if (pushglobalfuncname(L, ar)) { /* try first a global name */ - lua_pushfstring(L, "function '%s'", lua_tostring(L, -1)); - lua_remove(L, -2); /* remove name */ - } - else if (*ar->namewhat != '\0') /* is there a name from code? */ - lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */ - else if (*ar->what == 'm') /* main? */ - lua_pushliteral(L, "main chunk"); - else if (*ar->what != 'C') /* for Lua functions, use */ - lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); - else /* nothing left... */ - lua_pushliteral(L, "?"); -} - - -static int lastlevel (lua_State *L) { - lua_Debug ar; - int li = 1, le = 1; - /* find an upper bound */ - while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } - /* do a binary search */ - while (li < le) { - int m = (li + le)/2; - if (lua_getstack(L, m, &ar)) li = m + 1; - else le = m; - } - return le - 1; -} - - -LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, - const char *msg, int level) { - luaL_Buffer b; - lua_Debug ar; - int last = lastlevel(L1); - int limit2show = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1; - luaL_buffinit(L, &b); - if (msg) { - luaL_addstring(&b, msg); - luaL_addchar(&b, '\n'); - } - luaL_addstring(&b, "stack traceback:"); - while (lua_getstack(L1, level++, &ar)) { - if (limit2show-- == 0) { /* too many levels? */ - int n = last - level - LEVELS2 + 1; /* number of levels to skip */ - lua_pushfstring(L, "\n\t...\t(skipping %d levels)", n); - luaL_addvalue(&b); /* add warning about skip */ - level += n; /* and skip to last levels */ - } - else { - lua_getinfo(L1, "Slnt", &ar); - if (ar.currentline <= 0) - lua_pushfstring(L, "\n\t%s: in ", ar.short_src); - else - lua_pushfstring(L, "\n\t%s:%d: in ", ar.short_src, ar.currentline); - luaL_addvalue(&b); - pushfuncname(L, &ar); - luaL_addvalue(&b); - if (ar.istailcall) - luaL_addstring(&b, "\n\t(...tail calls...)"); - } - } - luaL_pushresult(&b); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Error-report functions -** ======================================================= -*/ - -LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) { - lua_Debug ar; - if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ - return luaL_error(L, "bad argument #%d (%s)", arg, extramsg); - lua_getinfo(L, "n", &ar); - if (strcmp(ar.namewhat, "method") == 0) { - arg--; /* do not count 'self' */ - if (arg == 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 = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; - return luaL_error(L, "bad argument #%d to '%s' (%s)", - arg, ar.name, extramsg); -} - - -LUALIB_API int luaL_typeerror (lua_State *L, int arg, const char *tname) { - const char *msg; - const char *typearg; /* name for the type of the actual argument */ - if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING) - typearg = lua_tostring(L, -1); /* use the given type name */ - else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA) - typearg = "light userdata"; /* special name for messages */ - else - typearg = luaL_typename(L, arg); /* standard name */ - msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg); - return luaL_argerror(L, arg, msg); -} - - -static void tag_error (lua_State *L, int arg, int tag) { - luaL_typeerror(L, arg, lua_typename(L, tag)); -} - - -/* -** The use of 'lua_pushfstring' ensures this function does not -** need reserved stack space when called. -*/ -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, "Sl", &ar); /* get info about it */ - if (ar.currentline > 0) { /* is there info? */ - lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); - return; - } - } - lua_pushfstring(L, ""); /* else, no information available... */ -} - - -/* -** Again, the use of 'lua_pushvfstring' ensures this function does -** not need reserved stack space when called. (At worst, it generates -** an error with "stack overflow" instead of the given message.) -*/ -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_fileresult (lua_State *L, int stat, const char *fname) { - int en = errno; /* calls to Lua API may change this value */ - if (stat) { - lua_pushboolean(L, 1); - return 1; - } - else { - luaL_pushfail(L); - if (fname) - lua_pushfstring(L, "%s: %s", fname, strerror(en)); - else - lua_pushstring(L, strerror(en)); - lua_pushinteger(L, en); - return 3; - } -} - - -#if !defined(l_inspectstat) /* { */ - -#if defined(LUA_USE_POSIX) - -#include - -/* -** use appropriate macros to interpret 'pclose' return status -*/ -#define l_inspectstat(stat,what) \ - if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ - else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } - -#else - -#define l_inspectstat(stat,what) /* no op */ - -#endif - -#endif /* } */ - - -LUALIB_API int luaL_execresult (lua_State *L, int stat) { - if (stat != 0 && errno != 0) /* error with an 'errno'? */ - return luaL_fileresult(L, 0, NULL); - else { - const char *what = "exit"; /* type of termination */ - l_inspectstat(stat, what); /* interpret result */ - if (*what == 'e' && stat == 0) /* successful termination? */ - lua_pushboolean(L, 1); - else - luaL_pushfail(L); - lua_pushstring(L, what); - lua_pushinteger(L, stat); - return 3; /* return true/fail,what,code */ - } -} - -/* }====================================================== */ - - - -/* -** {====================================================== -** Userdata's metatable manipulation -** ======================================================= -*/ - -LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { - if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */ - return 0; /* leave previous value on top, but return 0 */ - lua_pop(L, 1); - lua_createtable(L, 0, 2); /* create metatable */ - lua_pushstring(L, tname); - lua_setfield(L, -2, "__name"); /* metatable.__name = tname */ - lua_pushvalue(L, -1); - lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ - return 1; -} - - -LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) { - luaL_getmetatable(L, tname); - lua_setmetatable(L, -2); -} - - -LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) { - void *p = lua_touserdata(L, ud); - if (p != NULL) { /* value is a userdata? */ - if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ - luaL_getmetatable(L, tname); /* get correct metatable */ - if (!lua_rawequal(L, -1, -2)) /* not the same? */ - p = NULL; /* value is a userdata with wrong metatable */ - lua_pop(L, 2); /* remove both metatables */ - return p; - } - } - return NULL; /* value is not a userdata with a metatable */ -} - - -LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { - void *p = luaL_testudata(L, ud, tname); - luaL_argexpected(L, p != NULL, ud, tname); - return p; -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Argument check functions -** ======================================================= -*/ - -LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def, - const char *const lst[]) { - const char *name = (def) ? luaL_optstring(L, arg, def) : - luaL_checkstring(L, arg); - int i; - for (i=0; lst[i]; i++) - if (strcmp(lst[i], name) == 0) - return i; - return luaL_argerror(L, arg, - lua_pushfstring(L, "invalid option '%s'", name)); -} - - -/* -** Ensures the stack has at least 'space' extra slots, raising an error -** if it cannot fulfill the request. (The error handling needs a few -** extra slots to format the error message. In case of an error without -** this extra space, Lua will generate the same 'stack overflow' error, -** but without 'msg'.) -*/ -LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { - if (l_unlikely(!lua_checkstack(L, space))) { - if (msg) - luaL_error(L, "stack overflow (%s)", msg); - else - luaL_error(L, "stack overflow"); - } -} - - -LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) { - if (l_unlikely(lua_type(L, arg) != t)) - tag_error(L, arg, t); -} - - -LUALIB_API void luaL_checkany (lua_State *L, int arg) { - if (l_unlikely(lua_type(L, arg) == LUA_TNONE)) - luaL_argerror(L, arg, "value expected"); -} - - -LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) { - const char *s = lua_tolstring(L, arg, len); - if (l_unlikely(!s)) tag_error(L, arg, LUA_TSTRING); - return s; -} - - -LUALIB_API const char *luaL_optlstring (lua_State *L, int arg, - const char *def, size_t *len) { - if (lua_isnoneornil(L, arg)) { - if (len) - *len = (def ? strlen(def) : 0); - return def; - } - else return luaL_checklstring(L, arg, len); -} - - -LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) { - int isnum; - lua_Number d = lua_tonumberx(L, arg, &isnum); - if (l_unlikely(!isnum)) - tag_error(L, arg, LUA_TNUMBER); - return d; -} - - -LUALIB_API lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number def) { - return luaL_opt(L, luaL_checknumber, arg, def); -} - - -static void interror (lua_State *L, int arg) { - if (lua_isnumber(L, arg)) - luaL_argerror(L, arg, "number has no integer representation"); - else - tag_error(L, arg, LUA_TNUMBER); -} - - -LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) { - int isnum; - lua_Integer d = lua_tointegerx(L, arg, &isnum); - if (l_unlikely(!isnum)) { - interror(L, arg); - } - return d; -} - - -LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg, - lua_Integer def) { - return luaL_opt(L, luaL_checkinteger, arg, def); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Generic Buffer manipulation -** ======================================================= -*/ - -/* userdata to box arbitrary data */ -typedef struct UBox { - void *box; - size_t bsize; -} UBox; - - -static void *resizebox (lua_State *L, int idx, size_t newsize) { - void *ud; - lua_Alloc allocf = lua_getallocf(L, &ud); - UBox *box = (UBox *)lua_touserdata(L, idx); - void *temp = allocf(ud, box->box, box->bsize, newsize); - if (l_unlikely(temp == NULL && newsize > 0)) { /* allocation error? */ - lua_pushliteral(L, "not enough memory"); - lua_error(L); /* raise a memory error */ - } - box->box = temp; - box->bsize = newsize; - return temp; -} - - -static int boxgc (lua_State *L) { - resizebox(L, 1, 0); - return 0; -} - - -static const luaL_Reg boxmt[] = { /* box metamethods */ - {"__gc", boxgc}, - {"__close", boxgc}, - {NULL, NULL} -}; - - -static void newbox (lua_State *L) { - UBox *box = (UBox *)lua_newuserdatauv(L, sizeof(UBox), 0); - box->box = NULL; - box->bsize = 0; - if (luaL_newmetatable(L, "_UBOX*")) /* creating metatable? */ - luaL_setfuncs(L, boxmt, 0); /* set its metamethods */ - lua_setmetatable(L, -2); -} - - -/* -** check whether buffer is using a userdata on the stack as a temporary -** buffer -*/ -#define buffonstack(B) ((B)->b != (B)->init.b) - - -/* -** Whenever buffer is accessed, slot 'idx' must either be a box (which -** cannot be NULL) or it is a placeholder for the buffer. -*/ -#define checkbufferlevel(B,idx) \ - lua_assert(buffonstack(B) ? lua_touserdata(B->L, idx) != NULL \ - : lua_touserdata(B->L, idx) == (void*)B) - - -/* -** Compute new size for buffer 'B', enough to accommodate extra 'sz' -** bytes. (The test for "not big enough" also gets the case when the -** computation of 'newsize' overflows.) -*/ -static size_t newbuffsize (luaL_Buffer *B, size_t sz) { - size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */ - if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */ - return luaL_error(B->L, "buffer too large"); - if (newsize < B->n + sz) /* not big enough? */ - newsize = B->n + sz; - return newsize; -} - - -/* -** Returns a pointer to a free area with at least 'sz' bytes in buffer -** 'B'. 'boxidx' is the relative position in the stack where is the -** buffer's box or its placeholder. -*/ -static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) { - checkbufferlevel(B, boxidx); - if (B->size - B->n >= sz) /* enough space? */ - return B->b + B->n; - else { - lua_State *L = B->L; - char *newbuff; - size_t newsize = newbuffsize(B, sz); - /* create larger buffer */ - if (buffonstack(B)) /* buffer already has a box? */ - newbuff = (char *)resizebox(L, boxidx, newsize); /* resize it */ - else { /* no box yet */ - lua_remove(L, boxidx); /* remove placeholder */ - newbox(L); /* create a new box */ - lua_insert(L, boxidx); /* move box to its intended position */ - lua_toclose(L, boxidx); - newbuff = (char *)resizebox(L, boxidx, newsize); - memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ - } - B->b = newbuff; - B->size = newsize; - return newbuff + B->n; - } -} - -/* -** returns a pointer to a free area with at least 'sz' bytes -*/ -LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { - return prepbuffsize(B, sz, -1); -} - - -LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { - if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */ - char *b = prepbuffsize(B, l, -1); - memcpy(b, s, l * sizeof(char)); - luaL_addsize(B, l); - } -} - - -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) { - lua_State *L = B->L; - checkbufferlevel(B, -1); - lua_pushlstring(L, B->b, B->n); - if (buffonstack(B)) - lua_closeslot(L, -2); /* close the box */ - lua_remove(L, -2); /* remove box or placeholder from the stack */ -} - - -LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) { - luaL_addsize(B, sz); - luaL_pushresult(B); -} - - -/* -** 'luaL_addvalue' is the only function in the Buffer system where the -** box (if existent) is not on the top of the stack. So, instead of -** calling 'luaL_addlstring', it replicates the code using -2 as the -** last argument to 'prepbuffsize', signaling that the box is (or will -** be) below the string being added to the buffer. (Box creation can -** trigger an emergency GC, so we should not remove the string from the -** stack before we have the space guaranteed.) -*/ -LUALIB_API void luaL_addvalue (luaL_Buffer *B) { - lua_State *L = B->L; - size_t len; - const char *s = lua_tolstring(L, -1, &len); - char *b = prepbuffsize(B, len, -2); - memcpy(b, s, len * sizeof(char)); - luaL_addsize(B, len); - lua_pop(L, 1); /* pop string */ -} - - -LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { - B->L = L; - B->b = B->init.b; - B->n = 0; - B->size = LUAL_BUFFERSIZE; - lua_pushlightuserdata(L, (void*)B); /* push placeholder */ -} - - -LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { - luaL_buffinit(L, B); - return prepbuffsize(B, sz, -1); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Reference system -** ======================================================= -*/ - -/* index of free-list header (after the predefined values) */ -#define freelist (LUA_RIDX_LAST + 1) - -/* -** The previously freed references form a linked list: -** t[freelist] is the index of a first free index, or zero if list is -** empty; t[t[freelist]] is the index of the second element; etc. -*/ -LUALIB_API int luaL_ref (lua_State *L, int t) { - int ref; - if (lua_isnil(L, -1)) { - lua_pop(L, 1); /* remove from stack */ - return LUA_REFNIL; /* 'nil' has a unique fixed reference */ - } - t = lua_absindex(L, t); - if (lua_rawgeti(L, t, freelist) == LUA_TNIL) { /* first access? */ - ref = 0; /* list is empty */ - lua_pushinteger(L, 0); /* initialize as an empty list */ - lua_rawseti(L, t, freelist); /* ref = t[freelist] = 0 */ - } - else { /* already initialized */ - lua_assert(lua_isinteger(L, -1)); - ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */ - } - lua_pop(L, 1); /* remove element from stack */ - if (ref != 0) { /* any free element? */ - lua_rawgeti(L, t, ref); /* remove it from list */ - lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ - } - else /* no free elements */ - ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ - lua_rawseti(L, t, ref); - return ref; -} - - -LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { - if (ref >= 0) { - t = lua_absindex(L, t); - lua_rawgeti(L, t, freelist); - lua_assert(lua_isinteger(L, -1)); - lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ - lua_pushinteger(L, ref); - lua_rawseti(L, t, freelist); /* t[freelist] = ref */ - } -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Load functions -** ======================================================= -*/ - -typedef struct LoadF { - int n; /* number of pre-read characters */ - FILE *f; /* file being read */ - char buff[BUFSIZ]; /* area for reading file */ -} LoadF; - - -static const char *getF (lua_State *L, void *ud, size_t *size) -{ - LoadF *lf = (LoadF *)ud; - UFSFILE *ufp = get_ufsfile(lf->f); - - (void)L; /* not used */ - - // wtof("lauxlib.c:%s: enter ufp=%p", __func__, ufp); - - if (lf->n > 0) { /* are there pre-read characters to be read? */ - *size = lf->n; /* return them (chars already in buffer) */ - lf->n = 0; /* no more pre-read characters */ - } - else { /* read a block from file */ - /* 'fread' can return > 0 *and* set the EOF flag. If next call to - 'getF' called 'fread', it might still wait for user input. - The next check avoids this problem. */ - if (ufp) { - if (ufs_feof(ufp)) return NULL; - *size = ufs_fread(lf->buff, 1, sizeof(lf->buff), ufp); /* read block */ - // wtof("lauxlib.c:%s: ufs_fread() size=%d", __func__, *size); - } - else { - if (feof(lf->f)) return NULL; - *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ - // wtof("lauxlib.c:%s: fread() size=%d", __func__, *size); - } - } - - // wtodumpf(lf->buff, *size, "%s: lf->buff", __func__); - // wtof("lauxlib.c:%s: exit", __func__); - return lf->buff; -} - - -static int errfile (lua_State *L, const char *what, int fnameindex) { - const char *serr = strerror(errno); - const char *filename = lua_tostring(L, fnameindex) + 1; - lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); - lua_remove(L, fnameindex); - return LUA_ERRFILE; -} - - -/* -** Skip an optional BOM at the start of a stream. If there is an -** incomplete BOM (the first character is correct but the rest is -** not), returns the first character anyway to force an error -** (as no chunk can start with 0xEF). -*/ -static int skipBOM (FILE *f) -{ - UFSFILE *ufp = get_ufsfile(f); - int c; - - if (ufp) { - c = ufs_fgetc(ufp); - if (c == 0xEF && ufs_fgetc(ufp) == 0xBB && ufs_fgetc(ufp) == 0xBF) /* correct BOM? */ - return ufs_fgetc(ufp); /* ignore BOM and return next char */ - else /* no (valid) BOM */ - return c; /* return first character */ - } - else { - c = getc(f); /* read first character */ - if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF) /* correct BOM? */ - return getc(f); /* ignore BOM and return next char */ - else /* no (valid) BOM */ - return c; /* return first character */ - } -} - - -/* -** reads the first character of file 'f' and skips an optional BOM mark -** in its beginning plus its first line if it starts with '#'. Returns -** true if it skipped the first line. In any case, '*cp' has the -** first "valid" character of the file (after the optional BOM and -** a first-line comment). -*/ -static int skipcomment (FILE *f, int *cp) -{ - UFSFILE *ufp = get_ufsfile(f); - int c = *cp = skipBOM(f); - - if (c == '#') { /* first line is a comment (Unix exec. file)? */ - if (ufp) { - do { /* skip first line */ - c = ufs_fgetc(ufp); - } while (c != EOF && c != '\n'); - *cp = ufs_fgetc(ufp); /* next character after comment, if present */ - return 1; /* there was a comment */ - } - else { - do { /* skip first line */ - c = getc(f); - } while (c != EOF && c != '\n'); - *cp = getc(f); /* next character after comment, if present */ - return 1; /* there was a comment */ - } - } - - return 0; /* no comment */ -} - - -LUALIB_API int -luaL_loadfilex (lua_State *L, const char *filename, const char *mode) -{ - CLIBCRT *crt = __crtget(); - UFS *ufs = crt ? crt->crtufs : NULL; - UFSFILE *ufp = NULL; - LoadF lf = {0}; - int status, readstatus; - int c; - int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ - - // wtof("lauxlib.c:%s: enter filename=\"%s\"", __func__, filename); - // wtof("lauxlib.c:%s: crt=%p", __func__, crt); - - if (filename == NULL) { - lua_pushliteral(L, "=stdin"); - lf.f = stdin; - } - else { - lua_pushfstring(L, "@%s", filename); - - if (ufs && is_pathname(filename)) { - ufp = ufs_fopen(ufs, filename, "r"); - // wtof("lauxlib.c:%s: ufs_fopen() ufp=%p", __func__, ufp); - if (ufp) lf.f = (void*)((unsigned)ufp | 0x80000000); - } - if (!lf.f) { - lf.f = fopen(filename, "r"); - // wtof("lauxlib.c:%s: fopen() lf.f=%p", __func__, lf.f); - } - if (lf.f == NULL) return errfile(L, "open", fnameindex); - } - - lf.n = 0; - if (skipcomment(lf.f, &c)) /* read initial portion */ - lf.buff[lf.n++] = '\n'; /* add newline to correct line numbers */ - - if (c == LUA_SIGNATURE[0]) { /* binary file? */ - lf.n = 0; /* remove possible newline */ - if (filename) { /* "real" file? */ - ufp = get_ufsfile(lf.f); - - if (ufp) { - ufs_fclose(&ufp); - lf.f = NULL; - ufp = ufs_fopen(ufs, filename, "rb"); - // wtof("lauxlib.c:%s: ufs_fopen() ufp=%p", __func__, ufp); - if (ufp) lf.f = (void*)((unsigned)ufp | 0x80000000); - } - else { - lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ - // wtof("lauxlib.c:%s: freopen() lf.f=%p", __func__, lf.f); - } - if (lf.f == NULL) return errfile(L, "reopen", fnameindex); - skipcomment(lf.f, &c); /* re-read initial portion */ - } - } - - if (c != EOF) - lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ - - status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); - // wtof("lauxlib.c:%s: lua_load() status=%d", __func__, status); - - if (ufp) { - readstatus = ufs_ferror(ufp); - // wtof("lauxlib.c:%s: ufs_ferror() readstatus=%d", __func__, readstatus); - } - else { - readstatus = ferror(lf.f); - // wtof("lauxlib.c:%s: ferror() readstatus=%d", __func__, readstatus); - } - - if (filename) { - if (ufp) { - ufs_fclose(&ufp); - // wtof("lauxlib.c:%s: ufs_fclose()", __func__); - } - else { - fclose(lf.f); /* close file (even in case of errors) */ - // wtof("lauxlib.c:%s: fclose()", __func__); - } - } - - if (readstatus) { - lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ - return errfile(L, "read", fnameindex); - } - - lua_remove(L, fnameindex); - return status; -} - - -typedef struct LoadS { - const char *s; - size_t size; -} LoadS; - - -static const char *getS (lua_State *L, void *ud, size_t *size) { - LoadS *ls = (LoadS *)ud; - (void)L; /* not used */ - if (ls->size == 0) return NULL; - *size = ls->size; - ls->size = 0; - return ls->s; -} - - -LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size, - const char *name, const char *mode) { - LoadS ls; - ls.s = buff; - ls.size = size; - return lua_load(L, getS, &ls, name, mode); -} - - -LUALIB_API int luaL_loadstring (lua_State *L, const char *s) { - return luaL_loadbuffer(L, s, strlen(s), s); -} - -/* }====================================================== */ - - - -LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { - if (!lua_getmetatable(L, obj)) /* no metatable? */ - return LUA_TNIL; - else { - int tt; - lua_pushstring(L, event); - tt = lua_rawget(L, -2); - if (tt == LUA_TNIL) /* is metafield nil? */ - lua_pop(L, 2); /* remove metatable and metafield */ - else - lua_remove(L, -2); /* remove only metatable */ - return tt; /* return metafield type */ - } -} - - -LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { - obj = lua_absindex(L, obj); - if (luaL_getmetafield(L, obj, event) == LUA_TNIL) /* no metafield? */ - return 0; - lua_pushvalue(L, obj); - lua_call(L, 1, 1); - return 1; -} - - -LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) { - lua_Integer l; - int isnum; - lua_len(L, idx); - l = lua_tointegerx(L, -1, &isnum); - if (l_unlikely(!isnum)) - luaL_error(L, "object length is not an integer"); - lua_pop(L, 1); /* remove object */ - return l; -} - - -LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { - idx = lua_absindex(L,idx); - if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */ - if (!lua_isstring(L, -1)) - luaL_error(L, "'__tostring' must return a string"); - } - else { - switch (lua_type(L, idx)) { - case LUA_TNUMBER: { - if (lua_isinteger(L, idx)) - lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx)); - else - lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx)); - break; - } - case LUA_TSTRING: - lua_pushvalue(L, idx); - break; - case LUA_TBOOLEAN: - lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false")); - break; - case LUA_TNIL: - lua_pushliteral(L, "nil"); - break; - default: { - int tt = luaL_getmetafield(L, idx, "__name"); /* try name */ - const char *kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : - luaL_typename(L, idx); - lua_pushfstring(L, "%s: %p", kind, lua_topointer(L, idx)); - if (tt != LUA_TNIL) - lua_remove(L, -2); /* remove '__name' */ - break; - } - } - } - return lua_tolstring(L, -1, len); -} - - -/* -** set functions from list 'l' into table at top - 'nup'; each -** function gets the 'nup' elements at the top as upvalues. -** Returns with only the table at the stack. -*/ -LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { - luaL_checkstack(L, nup, "too many upvalues"); - for (; l->name != NULL; l++) { /* fill the table with given functions */ - if (l->func == NULL) /* place holder? */ - lua_pushboolean(L, 0); - else { - int i; - for (i = 0; i < nup; i++) /* copy upvalues to the top */ - lua_pushvalue(L, -nup); - lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ - } - lua_setfield(L, -(nup + 2), l->name); - } - lua_pop(L, nup); /* remove upvalues */ -} - - -/* -** ensure that stack[idx][fname] has a table and push that table -** into the stack -*/ -LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) { - if (lua_getfield(L, idx, fname) == LUA_TTABLE) - return 1; /* table already there */ - else { - lua_pop(L, 1); /* remove previous result */ - idx = lua_absindex(L, idx); - lua_newtable(L); - lua_pushvalue(L, -1); /* copy to be left at top */ - lua_setfield(L, idx, fname); /* assign new table to field */ - return 0; /* false, because did not find table there */ - } -} - - -/* -** Stripped-down 'require': After checking "loaded" table, calls 'openf' -** to open a module, registers the result in 'package.loaded' table and, -** if 'glb' is true, also registers the result in the global table. -** Leaves resulting module on the top. -*/ -LUALIB_API void luaL_requiref (lua_State *L, const char *modname, - lua_CFunction openf, int glb) { - luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); - lua_getfield(L, -1, modname); /* LOADED[modname] */ - if (!lua_toboolean(L, -1)) { /* package not already loaded? */ - lua_pop(L, 1); /* remove field */ - lua_pushcfunction(L, openf); - lua_pushstring(L, modname); /* argument to open function */ - lua_call(L, 1, 1); /* call 'openf' to open module */ - lua_pushvalue(L, -1); /* make copy of module (call result) */ - lua_setfield(L, -3, modname); /* LOADED[modname] = module */ - } - lua_remove(L, -2); /* remove LOADED table */ - if (glb) { - lua_pushvalue(L, -1); /* copy of module */ - lua_setglobal(L, modname); /* _G[modname] = module */ - } -} - - -LUALIB_API void luaL_addgsub (luaL_Buffer *b, const char *s, - const char *p, const char *r) { - const char *wild; - size_t l = strlen(p); - while ((wild = strstr(s, p)) != NULL) { - luaL_addlstring(b, s, wild - s); /* push prefix */ - luaL_addstring(b, r); /* push replacement in place of pattern */ - s = wild + l; /* continue after 'p' */ - } - luaL_addstring(b, s); /* push last suffix */ -} - - -LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, - const char *p, const char *r) { - luaL_Buffer b; - luaL_buffinit(L, &b); - luaL_addgsub(&b, s, p, r); - luaL_pushresult(&b); - return lua_tostring(L, -1); -} - - -static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { - (void)ud; (void)osize; /* not used */ - if (nsize == 0) { - free(ptr); - return NULL; - } - else - return realloc(ptr, nsize); -} - - -static int panic (lua_State *L) { - const char *msg = lua_tostring(L, -1); - if (msg == NULL) msg = "error object is not a string"; - lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", - msg); - return 0; /* return to Lua to abort */ -} - - -/* -** Warning functions: -** warnfoff: warning system is off -** warnfon: ready to start a new message -** warnfcont: previous message is to be continued -*/ -static void warnfoff (void *ud, const char *message, int tocont); -static void warnfon (void *ud, const char *message, int tocont); -static void warnfcont (void *ud, const char *message, int tocont); - - -/* -** Check whether message is a control message. If so, execute the -** control or ignore it if unknown. -*/ -static int checkcontrol (lua_State *L, const char *message, int tocont) { - if (tocont || *(message++) != '@') /* not a control message? */ - return 0; - else { - if (strcmp(message, "off") == 0) - lua_setwarnf(L, warnfoff, L); /* turn warnings off */ - else if (strcmp(message, "on") == 0) - lua_setwarnf(L, warnfon, L); /* turn warnings on */ - return 1; /* it was a control message */ - } -} - - -static void warnfoff (void *ud, const char *message, int tocont) { - checkcontrol((lua_State *)ud, message, tocont); -} - - -/* -** Writes the message and handle 'tocont', finishing the message -** if needed and setting the next warn function. -*/ -static void warnfcont (void *ud, const char *message, int tocont) { - lua_State *L = (lua_State *)ud; - lua_writestringerror("%s", message); /* write message */ - if (tocont) /* not the last part? */ - lua_setwarnf(L, warnfcont, L); /* to be continued */ - else { /* last part */ - lua_writestringerror("%s", "\n"); /* finish message with end-of-line */ - lua_setwarnf(L, warnfon, L); /* next call is a new message */ - } -} - - -static void warnfon (void *ud, const char *message, int tocont) { - if (checkcontrol((lua_State *)ud, message, tocont)) /* control message? */ - return; /* nothing else to be done */ - lua_writestringerror("%s", "Lua warning: "); /* start a new warning */ - warnfcont(ud, message, tocont); /* finish processing */ -} - - -LUALIB_API lua_State *luaL_newstate (void) { - lua_State *L = lua_newstate(l_alloc, NULL); - if (l_likely(L)) { - lua_atpanic(L, &panic); - lua_setwarnf(L, warnfoff, L); /* default is warnings off */ - } - return L; -} - - -LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) { - lua_Number v = lua_version(L); - if (sz != LUAL_NUMSIZES) /* check numeric types */ - luaL_error(L, "core and library have incompatible numeric types"); - else if (v != ver) - luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f", - (LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)v); -} - diff --git a/src/liolib.c b/src/liolib.c deleted file mode 100644 index 02fc0c8..0000000 --- a/src/liolib.c +++ /dev/null @@ -1,979 +0,0 @@ -/* -** $Id: liolib.c $ -** Standard I/O (and system) library -** See Copyright Notice in lua.h -*/ - -/* This is a copy of lauxlib.c from LUA370 with modifications - * to support UFS in the HTTPD environment. - */ - -#define liolib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - -#define HTTPLUAX_PRIVATE /* suppress defines for Lua functions */ -//#define luai_likely(x) (x) -//#define luai_unlikely(x) (x) -#include "httpd.h" - -static UFSFILE *get_ufsfile(FILE *fp) -{ - unsigned x = (unsigned)fp; - UFSFILE *f = NULL; - - if (x & 0x80000000) { - f = (UFSFILE *) (x & 0x7FFFFFFF); - } - - return f; -} - - - - -/* -** Change this macro to accept other modes for 'fopen' besides -** the standard ones. -*/ -#if !defined(l_checkmode) - -/* accepted extensions to 'mode' in 'fopen' */ -#if !defined(L_MODEEXT) -#define L_MODEEXT "b" -#endif - -/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */ -static int l_checkmode (const char *mode) { - return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && - (*mode != '+' || ((void)(++mode), 1)) && /* skip if char is '+' */ - (strspn(mode, L_MODEEXT) == strlen(mode))); /* check extensions */ -} - -#endif - -/* -** {====================================================== -** l_popen spawns a new process connected to the current -** one through the file streams. -** ======================================================= -*/ - -#if !defined(l_popen) /* { */ - -#if defined(LUA_USE_POSIX) /* { */ - -#define l_popen(L,c,m) (fflush(NULL), popen(c,m)) -#define l_pclose(L,file) (pclose(file)) - -#elif defined(LUA_USE_WINDOWS) /* }{ */ - -#define l_popen(L,c,m) (_popen(c,m)) -#define l_pclose(L,file) (_pclose(file)) - -#if !defined(l_checkmodep) -/* Windows accepts "[rw][bt]?" as valid modes */ -#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && \ - (m[1] == '\0' || ((m[1] == 'b' || m[1] == 't') && m[2] == '\0'))) -#endif - -#else /* }{ */ - -/* ISO C definitions */ -#define l_popen(L,c,m) \ - ((void)c, (void)m, \ - luaL_error(L, "'popen' not supported"), \ - (FILE*)0) -#define l_pclose(L,file) ((void)L, (void)file, -1) - -#endif /* } */ - -#endif /* } */ - - -#if !defined(l_checkmodep) -/* By default, Lua accepts only "r" or "w" as valid modes */ -#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && m[1] == '\0') -#endif - -/* }====================================================== */ - - -#if !defined(l_getc) /* { */ - -#if defined(LUA_USE_POSIX) -#define l_getc(f) getc_unlocked(f) -#define l_lockfile(f) flockfile(f) -#define l_unlockfile(f) funlockfile(f) -#else -#define l_getc(f) getc(f) -#define l_lockfile(f) ((void)0) -#define l_unlockfile(f) ((void)0) -#endif - -#endif /* } */ - - -/* -** {====================================================== -** l_fseek: configuration for longer offsets -** ======================================================= -*/ - -#if !defined(l_fseek) /* { */ - -#if defined(LUA_USE_POSIX) /* { */ - -#include - -#define l_fseek(f,o,w) fseeko(f,o,w) -#define l_ftell(f) ftello(f) -#define l_seeknum off_t - -#elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \ - && defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */ - -/* Windows (but not DDK) and Visual C++ 2005 or higher */ -#define l_fseek(f,o,w) _fseeki64(f,o,w) -#define l_ftell(f) _ftelli64(f) -#define l_seeknum __int64 - -#else /* }{ */ - -/* ISO C definitions */ -#define l_fseek(f,o,w) fseek(f,o,w) -#define l_ftell(f) ftell(f) -#define l_seeknum long - -#endif /* } */ - -#endif /* } */ - -/* }====================================================== */ - - - -#define IO_PREFIX "_IO_" -#define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1) -#define IO_INPUT (IO_PREFIX "input") -#define IO_OUTPUT (IO_PREFIX "output") - - -typedef luaL_Stream LStream; - - -#define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) - -#define isclosed(p) ((p)->closef == NULL) - - -static int io_type (lua_State *L) { - LStream *p; - luaL_checkany(L, 1); - p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE); - if (p == NULL) - luaL_pushfail(L); /* not a file */ - else if (isclosed(p)) - lua_pushliteral(L, "closed file"); - else - lua_pushliteral(L, "file"); - return 1; -} - - -static int f_tostring (lua_State *L) { - LStream *p = tolstream(L); - if (isclosed(p)) - lua_pushliteral(L, "file (closed)"); - else - lua_pushfstring(L, "file (%p)", p->f); - return 1; -} - - -static FILE *tofile (lua_State *L) { - LStream *p = tolstream(L); - if (l_unlikely(isclosed(p))) - luaL_error(L, "attempt to use a closed file"); - lua_assert(p->f); - return p->f; -} - - -/* -** When creating file handles, always creates a 'closed' file handle -** before opening the actual file; so, if there is a memory error, the -** handle is in a consistent state. -*/ -static LStream *newprefile (lua_State *L) { - LStream *p = (LStream *)lua_newuserdatauv(L, sizeof(LStream), 0); - p->closef = NULL; /* mark file handle as 'closed' */ - luaL_setmetatable(L, LUA_FILEHANDLE); - return p; -} - - -/* -** Calls the 'close' function from a file handle. The 'volatile' avoids -** a bug in some versions of the Clang compiler (e.g., clang 3.0 for -** 32 bits). -*/ -static int aux_close (lua_State *L) { - LStream *p = tolstream(L); - volatile lua_CFunction cf = p->closef; - p->closef = NULL; /* mark stream as closed */ - return (*cf)(L); /* close it */ -} - - -static int f_close (lua_State *L) { - tofile(L); /* make sure argument is an open stream */ - return aux_close(L); -} - - -static int io_close (lua_State *L) { - if (lua_isnone(L, 1)) /* no argument? */ - lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use default output */ - return f_close(L); -} - - -static int f_gc (lua_State *L) { - LStream *p = tolstream(L); - if (!isclosed(p) && p->f != NULL) - aux_close(L); /* ignore closed and incompletely open files */ - return 0; -} - - -/* -** function to close regular files -*/ -static int io_fclose (lua_State *L) -{ - LStream *p = tolstream(L); - UFSFILE *ufp = get_ufsfile(p->f); - int res = 0; - - if (ufp) { - ufs_fclose(&ufp); - } - else { - res = fclose(p->f); - } - - return luaL_fileresult(L, (res == 0), NULL); -} - - -static LStream *newfile (lua_State *L) -{ - LStream *p = newprefile(L); - - p->f = NULL; - p->closef = &io_fclose; - - return p; -} - - -static void opencheck (lua_State *L, const char *fname, const char *mode) -{ - CLIBCRT *crt = __crtget(); - UFS *ufs = crt ? crt->crtufs : NULL; - UFSFILE *ufp = NULL; - LStream *p = newfile(L); - - p->f = NULL; - - if (ufs) { - ufp = ufs_fopen(ufs, fname, mode); - if (ufp) p->f = (void*)((unsigned)ufp & 0x80000000); - } - - if (!p->f) { - p->f = fopen(fname, mode); - } - - if (l_unlikely(p->f == NULL)) - luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); -} - - -static int io_open (lua_State *L) -{ - CLIBCRT *crt = __crtget(); - UFS *ufs = crt ? crt->crtufs : NULL; - UFSFILE *ufp = NULL; - const char *filename = luaL_checkstring(L, 1); - const char *mode = luaL_optstring(L, 2, "r"); - LStream *p = newfile(L); - const char *md = mode; /* to traverse/check mode */ - - luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); - - p->f = NULL; - - if (ufs) { - ufp = ufs_fopen(ufs, filename, mode); - if (ufp) p->f = (void*)((unsigned)ufp & 0x80000000); - } - - if (!p->f) { - p->f = fopen(filename, mode); - } - - return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; -} - - -/* -** function to close 'popen' files -*/ -static int io_pclose (lua_State *L) { - LStream *p = tolstream(L); - errno = 0; - return luaL_execresult(L, l_pclose(L, p->f)); -} - - -static int io_popen (lua_State *L) { - const char *filename = luaL_checkstring(L, 1); - const char *mode = luaL_optstring(L, 2, "r"); - LStream *p = newprefile(L); - luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode"); - p->f = l_popen(L, filename, mode); - p->closef = &io_pclose; - return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; -} - - -static int io_tmpfile (lua_State *L) -{ - LStream *p = newfile(L); - - p->f = tmpfile(); - return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; -} - - -static FILE *getiofile (lua_State *L, const char *findex) -{ - LStream *p; - - lua_getfield(L, LUA_REGISTRYINDEX, findex); - p = (LStream *)lua_touserdata(L, -1); - - if (l_unlikely(isclosed(p))) - luaL_error(L, "default %s file is closed", findex + IOPREF_LEN); - - return p->f; -} - - -static int g_iofile (lua_State *L, const char *f, const char *mode) { - if (!lua_isnoneornil(L, 1)) { - const char *filename = lua_tostring(L, 1); - if (filename) - opencheck(L, filename, mode); - else { - tofile(L); /* check that it's a valid file handle */ - lua_pushvalue(L, 1); - } - lua_setfield(L, LUA_REGISTRYINDEX, f); - } - /* return current value */ - lua_getfield(L, LUA_REGISTRYINDEX, f); - 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); - - -/* -** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit -** in the limit for upvalues of a closure) -*/ -#define MAXARGLINE 250 - -/* -** Auxiliary function to create the iteration function for 'lines'. -** The iteration function is a closure over 'io_readline', with -** the following upvalues: -** 1) The file being read (first value in the stack) -** 2) the number of arguments to read -** 3) a boolean, true iff file has to be closed when finished ('toclose') -** *) a variable number of format arguments (rest of the stack) -*/ -static void aux_lines (lua_State *L, int toclose) { - int n = lua_gettop(L) - 1; /* number of arguments to read */ - luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments"); - lua_pushvalue(L, 1); /* file */ - lua_pushinteger(L, n); /* number of arguments to read */ - lua_pushboolean(L, toclose); /* close/not close file when finished */ - lua_rotate(L, 2, 3); /* move the three values to their positions */ - lua_pushcclosure(L, io_readline, 3 + n); -} - - -static int f_lines (lua_State *L) { - tofile(L); /* check that it's a valid file handle */ - aux_lines(L, 0); - return 1; -} - - -/* -** Return an iteration function for 'io.lines'. If file has to be -** closed, also returns the file itself as a second result (to be -** closed as the state at the exit of a generic for). -*/ -static int io_lines (lua_State *L) { - int toclose; - if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ - if (lua_isnil(L, 1)) { /* no file name? */ - lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */ - lua_replace(L, 1); /* put it at index 1 */ - tofile(L); /* check that it's a valid file handle */ - toclose = 0; /* do not close it after iteration */ - } - else { /* open a new file */ - const char *filename = luaL_checkstring(L, 1); - opencheck(L, filename, "r"); - lua_replace(L, 1); /* put file at index 1 */ - toclose = 1; /* close it after iteration */ - } - aux_lines(L, toclose); /* push iteration function */ - if (toclose) { - lua_pushnil(L); /* state */ - lua_pushnil(L); /* control */ - lua_pushvalue(L, 1); /* file is the to-be-closed variable (4th result) */ - return 4; - } - else - return 1; -} - - -/* -** {====================================================== -** READ -** ======================================================= -*/ - - -/* maximum length of a numeral */ -#if !defined (L_MAXLENNUM) -#define L_MAXLENNUM 200 -#endif - - -/* auxiliary structure used by 'read_number' */ -typedef struct { - FILE *f; /* file being read */ - int c; /* current character (look ahead) */ - int n; /* number of elements in buffer 'buff' */ - char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */ -} RN; - - -/* -** Add current char to buffer (if not out of space) and read next one -*/ -static int nextc (RN *rn) { - if (l_unlikely(rn->n >= L_MAXLENNUM)) { /* buffer overflow? */ - rn->buff[0] = '\0'; /* invalidate result */ - return 0; /* fail */ - } - else { - rn->buff[rn->n++] = rn->c; /* save current char */ - rn->c = l_getc(rn->f); /* read next one */ - return 1; - } -} - - -/* -** Accept current char if it is in 'set' (of size 2) -*/ -static int test2 (RN *rn, const char *set) { - if (rn->c == set[0] || rn->c == set[1]) - return nextc(rn); - else return 0; -} - - -/* -** Read a sequence of (hex)digits -*/ -static int readdigits (RN *rn, int hex) { - int count = 0; - while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn)) - count++; - return count; -} - - -/* -** Read a number: first reads a valid prefix of a numeral into a buffer. -** Then it calls 'lua_stringtonumber' to check whether the format is -** correct and to convert it to a Lua number. -*/ -static int read_number (lua_State *L, FILE *f) { - RN rn; - int count = 0; - int hex = 0; - char decp[2]; - rn.f = f; rn.n = 0; - decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */ - decp[1] = '.'; /* always accept a dot */ - l_lockfile(rn.f); - do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ - test2(&rn, "-+"); /* optional sign */ - if (test2(&rn, "00")) { - if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ - else count = 1; /* count initial '0' as a valid digit */ - } - count += readdigits(&rn, hex); /* integral part */ - if (test2(&rn, decp)) /* decimal point? */ - count += readdigits(&rn, hex); /* fractional part */ - if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) { /* exponent mark? */ - test2(&rn, "-+"); /* exponent sign */ - readdigits(&rn, 0); /* exponent digits */ - } - ungetc(rn.c, rn.f); /* unread look-ahead char */ - l_unlockfile(rn.f); - rn.buff[rn.n] = '\0'; /* finish string */ - if (l_likely(lua_stringtonumber(L, rn.buff))) - return 1; /* ok, it is a valid number */ - else { /* invalid format */ - lua_pushnil(L); /* "result" to be removed */ - return 0; /* read fails */ - } -} - - -static int test_eof (lua_State *L, FILE *f) -{ - UFSFILE *ufp = get_ufsfile(f); - int c; - - if (ufp) { - c = ufs_feof(ufp) ? EOF : 0; - } - else { - c = getc(f); - ungetc(c, f); /* no-op when c == EOF */ - } - - lua_pushliteral(L, ""); - return (c != EOF); -} - - -static int read_line (lua_State *L, FILE *f, int chop) { - luaL_Buffer b; - int c; - luaL_buffinit(L, &b); - do { /* may need to read several chunks to get whole line */ - char *buff = luaL_prepbuffer(&b); /* preallocate buffer space */ - int i = 0; - l_lockfile(f); /* no memory errors can happen inside the lock */ - while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n') - buff[i++] = c; /* read up to end of line or buffer limit */ - l_unlockfile(f); - luaL_addsize(&b, i); - } while (c != EOF && c != '\n'); /* repeat until end of line */ - if (!chop && c == '\n') /* want a newline and have one? */ - luaL_addchar(&b, c); /* add ending newline to result */ - luaL_pushresult(&b); /* close buffer */ - /* return ok if read something (either a newline or something else) */ - return (c == '\n' || lua_rawlen(L, -1) > 0); -} - - -static void read_all (lua_State *L, FILE *f) -{ - UFSFILE *ufp = get_ufsfile(f); - size_t nr; - luaL_Buffer b; - luaL_buffinit(L, &b); - - do { /* read file in chunks of LUAL_BUFFERSIZE bytes */ - char *p = luaL_prepbuffer(&b); - if (ufp) { - nr = ufs_fread(p, sizeof(char), LUAL_BUFFERSIZE, ufp); - } - else { - nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f); - } - luaL_addsize(&b, nr); - } while (nr == LUAL_BUFFERSIZE); - - luaL_pushresult(&b); /* close buffer */ -} - - -static int read_chars (lua_State *L, FILE *f, size_t n) -{ - UFSFILE *ufp = get_ufsfile(f); - size_t nr; /* number of chars actually read */ - char *p; - luaL_Buffer b; - - luaL_buffinit(L, &b); - p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */ - if (ufp) { - nr = ufs_fread(p, sizeof(char), n, ufp); /* try to read 'n' chars */ - } - else { - nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */ - } - luaL_addsize(&b, nr); - luaL_pushresult(&b); /* close buffer */ - return (nr > 0); /* true iff read something */ -} - - -static int g_read (lua_State *L, FILE *f, int first) -{ - UFSFILE *ufp = get_ufsfile(f); - int nargs = lua_gettop(L) - 1; - int n, success; - - if (ufp) { - ufs_clearerr(ufp); - } - else { - clearerr(f); - } - - if (nargs == 0) { /* no arguments? */ - success = read_line(L, f, 1); - 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)luaL_checkinteger(L, n); - success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); - } - else { - const char *p = luaL_checkstring(L, n); - if (*p == '*') p++; /* skip optional '*' (for compatibility) */ - switch (*p) { - case 'n': /* number */ - success = read_number(L, f); - break; - case 'l': /* line */ - success = read_line(L, f, 1); - break; - case 'L': /* line with end-of-line */ - success = read_line(L, f, 0); - break; - case 'a': /* file */ - read_all(L, f); /* read entire file */ - success = 1; /* always success */ - break; - default: - return luaL_argerror(L, n, "invalid format"); - } - } - } - } - - if (ferror(f)) - return luaL_fileresult(L, 0, NULL); - - if (!success) { - lua_pop(L, 1); /* remove last result */ - luaL_pushfail(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), 2); -} - - -/* -** Iteration function for 'lines'. -*/ -static int io_readline (lua_State *L) { - LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); - int i; - int n = (int)lua_tointeger(L, lua_upvalueindex(2)); - if (isclosed(p)) /* file is already closed? */ - return luaL_error(L, "file is already closed"); - lua_settop(L , 1); - luaL_checkstack(L, n, "too many arguments"); - for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ - lua_pushvalue(L, lua_upvalueindex(3 + i)); - n = g_read(L, p->f, 2); /* 'n' is number of results */ - lua_assert(n > 0); /* should return at least a nil */ - if (lua_toboolean(L, -n)) /* read at least one value? */ - return n; /* return them */ - else { /* first result is false: EOF or error */ - if (n > 1) { /* is there error information? */ - /* 2nd result is error message */ - return luaL_error(L, "%s", lua_tostring(L, -n + 1)); - } - if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ - lua_settop(L, 0); /* clear stack */ - lua_pushvalue(L, lua_upvalueindex(1)); /* push file at index 1 */ - aux_close(L); /* close it */ - } - return 0; - } -} - -/* }====================================================== */ - - -static int g_write (lua_State *L, FILE *f, int arg) -{ - UFSFILE *ufp = get_ufsfile(f); - int nargs = lua_gettop(L) - arg; - int status = 1; - int len; - char buf[256]; - - if (ufp) { - for (; nargs--; arg++) { - if (lua_type(L, arg) == LUA_TNUMBER) { - /* optimization: could be done exactly as for strings */ - len = lua_isinteger(L, arg) - ? sprintf(buf, LUA_INTEGER_FMT, - (LUAI_UACINT)lua_tointeger(L, arg)) - : sprintf(buf, LUA_NUMBER_FMT, - (LUAI_UACNUMBER)lua_tonumber(L, arg)); - len = strlen(buf); - status = status && (ufs_fwrite(buf, sizeof(char), len, ufp) == len); - } - else { - size_t l; - const char *s = luaL_checklstring(L, arg, &l); - status = status && (ufs_fwrite((char*)s, sizeof(char), l, ufp) == l); - } - } - } - else { - for (; nargs--; arg++) { - if (lua_type(L, arg) == LUA_TNUMBER) { - /* optimization: could be done exactly as for strings */ - len = lua_isinteger(L, arg) - ? fprintf(f, LUA_INTEGER_FMT, - (LUAI_UACINT)lua_tointeger(L, arg)) - : fprintf(f, LUA_NUMBER_FMT, - (LUAI_UACNUMBER)lua_tonumber(L, arg)); - status = status && (len > 0); - } - else { - size_t l; - const char *s = luaL_checklstring(L, arg, &l); - status = status && (fwrite(s, sizeof(char), l, f) == l); - } - } - } - - if (l_likely(status)) - return 1; /* file handle already on stack top */ - else return luaL_fileresult(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) { - FILE *f = tofile(L); - lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ - return g_write(L, f, 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); - int op = luaL_checkoption(L, 2, "cur", modenames); - lua_Integer p3 = luaL_optinteger(L, 3, 0); - l_seeknum offset = (l_seeknum)p3; - luaL_argcheck(L, (lua_Integer)offset == p3, 3, - "not an integer in proper range"); - op = l_fseek(f, offset, mode[op]); - if (l_unlikely(op)) - return luaL_fileresult(L, 0, NULL); /* error */ - else { - lua_pushinteger(L, (lua_Integer)l_ftell(f)); - return 1; - } -} - - -static int f_setvbuf (lua_State *L) { - static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; - static const char *const modenames[] = {"no", "full", "line", NULL}; - FILE *f = tofile(L); - int op = luaL_checkoption(L, 2, NULL, modenames); - lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); - int res = setvbuf(f, NULL, mode[op], (size_t)sz); - return luaL_fileresult(L, res == 0, NULL); -} - - - -static int io_flush (lua_State *L) -{ - FILE *f = getiofile(L, IO_OUTPUT); - UFSFILE *ufp = get_ufsfile(f); - int status = 0; - - if (ufp) { - ufs_fsync(ufp); - status = ufs_ferror(ufp); - } - else { - status = fflush(f); - } - - return luaL_fileresult(L, status == 0, NULL); -} - - -static int f_flush (lua_State *L) -{ - return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); -} - - -/* -** functions for 'io' library -*/ -static const luaL_Reg iolib[] = { - {"close", io_close}, - {"flush", io_flush}, - {"input", io_input}, - {"lines", io_lines}, - {"open", io_open}, - {"output", io_output}, - {"popen", io_popen}, - {"read", io_read}, - {"tmpfile", io_tmpfile}, - {"type", io_type}, - {"write", io_write}, - {NULL, NULL} -}; - - -/* -** methods for file handles -*/ -static const luaL_Reg meth[] = { - {"read", f_read}, - {"write", f_write}, - {"lines", f_lines}, - {"flush", f_flush}, - {"seek", f_seek}, - {"close", f_close}, - {"setvbuf", f_setvbuf}, - {NULL, NULL} -}; - - -/* -** metamethods for file handles -*/ -static const luaL_Reg metameth[] = { - {"__index", NULL}, /* place holder */ - {"__gc", f_gc}, - {"__close", f_gc}, - {"__tostring", f_tostring}, - {NULL, NULL} -}; - - -static void createmeta (lua_State *L) { - luaL_newmetatable(L, LUA_FILEHANDLE); /* metatable for file handles */ - luaL_setfuncs(L, metameth, 0); /* add metamethods to new metatable */ - luaL_newlibtable(L, meth); /* create method table */ - luaL_setfuncs(L, meth, 0); /* add file methods to method table */ - lua_setfield(L, -2, "__index"); /* metatable.__index = method table */ - lua_pop(L, 1); /* pop metatable */ -} - - -/* -** function to (not) close the standard files stdin, stdout, and stderr -*/ -static int io_noclose (lua_State *L) { - LStream *p = tolstream(L); - p->closef = &io_noclose; /* keep file opened */ - luaL_pushfail(L); - lua_pushliteral(L, "cannot close standard file"); - return 2; -} - - -static void createstdfile (lua_State *L, FILE *f, const char *k, - const char *fname) { - LStream *p = newprefile(L); - p->f = f; - p->closef = &io_noclose; - if (k != NULL) { - lua_pushvalue(L, -1); - lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ - } - lua_setfield(L, -2, fname); /* add file to module */ -} - - -LUAMOD_API int luaopen_io (lua_State *L) { - luaL_newlib(L, iolib); /* new module */ - createmeta(L); - /* create (and set) default files */ - createstdfile(L, stdin, IO_INPUT, "stdin"); - createstdfile(L, stdout, IO_OUTPUT, "stdout"); - createstdfile(L, stderr, NULL, "stderr"); - return 1; -} - diff --git a/src/loadlib.c b/src/loadlib.c deleted file mode 100644 index 1ffe9dc..0000000 --- a/src/loadlib.c +++ /dev/null @@ -1,946 +0,0 @@ -/* -** $Id: loadlib.c $ -** Dynamic library loader for Lua -** See Copyright Notice in lua.h -** -** This module contains an implementation of loadlib for Unix systems -** that have dlfcn, an implementation for Windows, and a stub for other -** systems. -*/ - -/* This is a copy of lauxlib.c from LUA370 with modifications - * to support UFS in the HTTPD environment. - */ - -#define loadlib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - -#define HTTPLUAX_PRIVATE /* suppress defines for Lua functions */ -//#define luai_likely(x) (x) -//#define luai_unlikely(x) (x) -#include "httpd.h" - - -/* -** LUA_IGMARK is a mark to ignore all before it when building the -** luaopen_ function name. -*/ -#if !defined (LUA_IGMARK) -#define LUA_IGMARK "-" -#endif - - -/* -** LUA_CSUBSEP is the character that replaces dots in submodule names -** when searching for a C loader. -** LUA_LSUBSEP is the character that replaces dots in submodule names -** when searching for a Lua loader. -*/ -#if !defined(LUA_CSUBSEP) -#define LUA_CSUBSEP LUA_DIRSEP -#endif - -#if !defined(LUA_LSUBSEP) -#define LUA_LSUBSEP LUA_DIRSEP -#endif - - -/* prefix for open functions in C libraries */ -#define LUA_POF "luaopen_" - -/* separator for open functions in C libraries */ -#define LUA_OFSEP "_" - - -/* -** key for table in the registry that keeps handles -** for all loaded C libraries -*/ -static const char *const CLIBS = "_CLIBS"; - -#define LIB_FAIL "open" - - -#define setprogdir(L) ((void)0) - - -/* -** Special type equivalent to '(void*)' for functions in gcc -** (to suppress warnings when converting function pointers) -*/ -typedef void (*voidf)(void); - - -/* -** system-dependent functions -*/ - -/* -** unload library 'lib' -*/ -static void lsys_unloadlib (void *lib); - -/* -** load C library in file 'path'. If 'seeglb', load with all names in -** the library global. -** Returns the library; in case of error, returns NULL plus an -** error string in the stack. -*/ -static void *lsys_load (lua_State *L, const char *path, int seeglb); - -/* -** Try to find a function named 'sym' in library 'lib'. -** Returns the function; in case of error, returns NULL plus an -** error string in the stack. -*/ -static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym); - - - - -#if defined(LUA_USE_DLOPEN) /* { */ -/* -** {======================================================================== -** This is an implementation of loadlib based on the dlfcn interface. -** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, -** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least -** as an emulation layer on top of native functions. -** ========================================================================= -*/ - -#include - -/* -** Macro to convert pointer-to-void* to pointer-to-function. This cast -** is undefined according to ISO C, but POSIX assumes that it works. -** (The '__extension__' in gnu compilers is only to avoid warnings.) -*/ -#if defined(__GNUC__) -#define cast_func(p) (__extension__ (lua_CFunction)(p)) -#else -#define cast_func(p) ((lua_CFunction)(p)) -#endif - - -static void lsys_unloadlib (void *lib) { - dlclose(lib); -} - - -static void *lsys_load (lua_State *L, const char *path, int seeglb) { - void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); - if (l_unlikely(lib == NULL)) - lua_pushstring(L, dlerror()); - return lib; -} - - -static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { - lua_CFunction f = cast_func(dlsym(lib, sym)); - if (l_unlikely(f == NULL)) - lua_pushstring(L, dlerror()); - return f; -} - -/* }====================================================== */ - - - -#elif defined(LUA_DL_DLL) /* }{ */ -/* -** {====================================================================== -** This is an implementation of loadlib for Windows using native functions. -** ======================================================================= -*/ - -#include - - -/* -** optional flags for LoadLibraryEx -*/ -#if !defined(LUA_LLE_FLAGS) -#define LUA_LLE_FLAGS 0 -#endif - - -#undef setprogdir - - -/* -** Replace in the path (on the top of the stack) any occurrence -** of LUA_EXEC_DIR with the executable's path. -*/ -static void setprogdir (lua_State *L) { - char buff[MAX_PATH + 1]; - char *lb; - DWORD nsize = sizeof(buff)/sizeof(char); - DWORD n = GetModuleFileNameA(NULL, buff, nsize); /* get exec. name */ - if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) - luaL_error(L, "unable to get ModuleFileName"); - else { - *lb = '\0'; /* cut name on the last '\\' to get the path */ - luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff); - lua_remove(L, -2); /* remove original string */ - } -} - - - - -static void pusherror (lua_State *L) { - int error = GetLastError(); - char buffer[128]; - if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL)) - lua_pushstring(L, buffer); - else - lua_pushfstring(L, "system error %d\n", error); -} - -static void lsys_unloadlib (void *lib) { - FreeLibrary((HMODULE)lib); -} - - -static void *lsys_load (lua_State *L, const char *path, int seeglb) { - HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); - (void)(seeglb); /* not used: symbols are 'global' by default */ - if (lib == NULL) pusherror(L); - return lib; -} - - -static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { - lua_CFunction f = (lua_CFunction)(voidf)GetProcAddress((HMODULE)lib, sym); - if (f == NULL) pusherror(L); - return f; -} - -/* }====================================================== */ - - -#else /* }{ */ -/* -** {====================================================== -** Fallback for other systems -** ======================================================= -*/ - -#undef LIB_FAIL -#define LIB_FAIL "absent" - - -#define DLMSG "dynamic libraries not enabled; check your Lua installation" - - -static void lsys_unloadlib (void *lib) { - (void)(lib); /* not used */ -} - - -static void *lsys_load (lua_State *L, const char *path, int seeglb) { - (void)(path); (void)(seeglb); /* not used */ - lua_pushliteral(L, DLMSG); - return NULL; -} - - -static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { - (void)(lib); (void)(sym); /* not used */ - lua_pushliteral(L, DLMSG); - return NULL; -} - -/* }====================================================== */ -#endif /* } */ - - -/* -** {================================================================== -** Set Paths -** =================================================================== -*/ - -/* -** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment -** variables that Lua check to set its paths. -*/ -#if !defined(LUA_PATH_VAR) -#define LUA_PATH_VAR "LUA_PATH" -#endif - -#if !defined(LUA_CPATH_VAR) -#define LUA_CPATH_VAR "LUA_CPATH" -#endif - - - -/* -** return registry.LUA_NOENV as a boolean -*/ -static int noenv (lua_State *L) { - int b; - lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); - b = lua_toboolean(L, -1); - lua_pop(L, 1); /* remove value */ - return b; -} - - -/* -** Set a path -*/ -static void setpath (lua_State *L, const char *fieldname, - const char *envname, - const char *dft) { - const char *dftmark; - const char *nver = lua_pushfstring(L, "%s%s", envname, LUA_VERSUFFIX); - const char *path = getenv(nver); /* try versioned name */ - if (path == NULL) /* no versioned environment variable? */ - path = getenv(envname); /* try unversioned name */ - if (path == NULL || noenv(L)) /* no environment variable? */ - lua_pushstring(L, dft); /* use default */ - else if ((dftmark = strstr(path, LUA_PATH_SEP LUA_PATH_SEP)) == NULL) - lua_pushstring(L, path); /* nothing to change */ - else { /* path contains a ";;": insert default path in its place */ - size_t len = strlen(path); - luaL_Buffer b; - luaL_buffinit(L, &b); - if (path < dftmark) { /* is there a prefix before ';;'? */ - luaL_addlstring(&b, path, dftmark - path); /* add it */ - luaL_addchar(&b, *LUA_PATH_SEP); - } - luaL_addstring(&b, dft); /* add default */ - if (dftmark < path + len - 2) { /* is there a suffix after ';;'? */ - luaL_addchar(&b, *LUA_PATH_SEP); - luaL_addlstring(&b, dftmark + 2, (path + len - 2) - dftmark); - } - luaL_pushresult(&b); - } - setprogdir(L); - lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */ - lua_pop(L, 1); /* pop versioned variable name ('nver') */ -} - -/* }================================================================== */ - - -/* -** return registry.CLIBS[path] -*/ -static void *checkclib (lua_State *L, const char *path) { - void *plib; - lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); - lua_getfield(L, -1, path); - plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ - lua_pop(L, 2); /* pop CLIBS table and 'plib' */ - return plib; -} - - -/* -** registry.CLIBS[path] = plib -- for queries -** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries -*/ -static void addtoclib (lua_State *L, const char *path, void *plib) { - lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); - lua_pushlightuserdata(L, plib); - lua_pushvalue(L, -1); - lua_setfield(L, -3, path); /* CLIBS[path] = plib */ - lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ - lua_pop(L, 1); /* pop CLIBS table */ -} - - -/* -** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib -** handles in list CLIBS -*/ -static int gctm (lua_State *L) { - lua_Integer n = luaL_len(L, 1); - for (; n >= 1; n--) { /* for each handle, in reverse order */ - lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ - lsys_unloadlib(lua_touserdata(L, -1)); - lua_pop(L, 1); /* pop handle */ - } - return 0; -} - - - -/* error codes for 'lookforfunc' */ -#define ERRLIB 1 -#define ERRFUNC 2 - -/* -** Look for a C function named 'sym' in a dynamically loaded library -** 'path'. -** First, check whether the library is already loaded; if not, try -** to load it. -** Then, if 'sym' is '*', return true (as library has been loaded). -** Otherwise, look for symbol 'sym' in the library and push a -** C function with that symbol. -** Return 0 and 'true' or a function in the stack; in case of -** errors, return an error code and an error message in the stack. -*/ -static int lookforfunc (lua_State *L, const char *path, const char *sym) { - void *reg = checkclib(L, path); /* check loaded C libraries */ - if (reg == NULL) { /* must load library? */ - reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */ - if (reg == NULL) return ERRLIB; /* unable to load library */ - addtoclib(L, path, reg); - } - if (*sym == '*') { /* loading only library (no function)? */ - lua_pushboolean(L, 1); /* return 'true' */ - return 0; /* no errors */ - } - else { - lua_CFunction f = lsys_sym(L, reg, sym); - if (f == NULL) - return ERRFUNC; /* unable to find function */ - lua_pushcfunction(L, f); /* else create new function */ - return 0; /* no errors */ - } -} - - -static int ll_loadlib (lua_State *L) { - const char *path = luaL_checkstring(L, 1); - const char *init = luaL_checkstring(L, 2); - int stat = lookforfunc(L, path, init); - if (l_likely(stat == 0)) /* no errors? */ - return 1; /* return the loaded function */ - else { /* error; error message is on stack top */ - luaL_pushfail(L); - lua_insert(L, -2); - lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); - return 3; /* return fail, error message, and where */ - } -} - - - -/* -** {====================================================== -** 'require' function -** ======================================================= -*/ - - -static int readable (const char *filename) -{ - CLIBCRT *crt = __crtget(); - UFS *ufs = crt ? crt->crtufs : NULL; - UFSFILE *ufp = NULL; - FILE *f = NULL; - - // wtof("loadlib.c:%s: enter \"%s\"", __func__, filename); - - // wtof("loadlib.c:%s: ufs=%p LUA_PATH_SEP=%s", __func__, ufs, LUA_PATH_SEP); - if (ufs) { - ufp = ufs_fopen(ufs, filename, "r"); - // wtof("loadlib.c:%s: ufp=%p", __func__, ufp); - if (ufp) { - /* this filename exist and is readable */ - ufs_fclose(&ufp); - return 1; - } - } - - /* try opening as a dataset */ - f = fopen(filename, "r"); /* try to open file */ - // wtof("loadlib.c:%s: f=%p", __func__, f); - if (f == NULL) return 0; /* open failed */ - fclose(f); - return 1; -} - - -/* -** Get the next name in '*path' = 'name1;name2;name3;...', changing -** the ending ';' to '\0' to create a zero-terminated string. Return -** NULL when list ends. -*/ -static const char *getnextfilename (char **path, char *end) -{ - static const char *pathsep = LUA_PATH_SEP; - char *sep; - char *name = *path; - - // wtof("loadlib.c:%s: enter path=%p name=%p end=%p", __func__, path, name, end); - - if (name == end) - return NULL; /* no more names */ - else if (*name == '\0') { /* from previous iteration? */ - *name = *pathsep; /* restore separator */ - name++; /* skip it */ - } - - sep = strchr(name, *pathsep); /* find next separator */ - // wtof("loadlib.c:%s: strchr(\"%s\",%c) sep=%p", __func__, name, *pathsep, sep); - if (sep == NULL) /* separator not found? */ - sep = end; /* name goes until the end */ - - *sep = '\0'; /* finish file name */ - *path = sep; /* will start next search from here */ - return name; -} - - -/* -** Given a path such as ";blabla.so;blublu.so", pushes the string -** -** no file 'blabla.so' -** no file 'blublu.so' -*/ -static void pusherrornotfound (lua_State *L, const char *path) { - luaL_Buffer b; - luaL_buffinit(L, &b); - luaL_addstring(&b, "no file '"); - luaL_addgsub(&b, path, LUA_PATH_SEP, "'\n\tno file '"); - luaL_addstring(&b, "'"); - luaL_pushresult(&b); -} - - -static const char *searchpath (lua_State *L, const char *name, - const char *path, - const char *sep, - const char *dirsep) { - luaL_Buffer buff; - char *pathname; /* path with name inserted */ - char *endpathname; /* its end */ - const char *filename; - /* separator is non-empty and appears in 'name'? */ - if (*sep != '\0' && strchr(name, *sep) != NULL) - name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ - luaL_buffinit(L, &buff); - /* add path to the buffer, replacing marks ('?') with the file name */ - luaL_addgsub(&buff, path, LUA_PATH_MARK, name); - luaL_addchar(&buff, '\0'); - pathname = luaL_buffaddr(&buff); /* writable list of file names */ - endpathname = pathname + luaL_bufflen(&buff) - 1; - while ((filename = getnextfilename(&pathname, endpathname)) != NULL) { - if (readable(filename)) /* does file exist and is readable? */ - return lua_pushstring(L, filename); /* save and return name */ - } - luaL_pushresult(&buff); /* push path to create error message */ - pusherrornotfound(L, lua_tostring(L, -1)); /* create error message */ - return NULL; /* not found */ -} - - -static int ll_searchpath (lua_State *L) { - const char *f = searchpath(L, luaL_checkstring(L, 1), - luaL_checkstring(L, 2), - luaL_optstring(L, 3, "."), - luaL_optstring(L, 4, LUA_DIRSEP)); - if (f != NULL) return 1; - else { /* error message is on top of the stack */ - luaL_pushfail(L); - lua_insert(L, -2); - return 2; /* return fail + error message */ - } -} - - -static const char *findfile (lua_State *L, const char *name, - const char *pname, - const char *dirsep) { - const char *path; - lua_getfield(L, lua_upvalueindex(1), pname); - path = lua_tostring(L, -1); - if (l_unlikely(path == NULL)) - luaL_error(L, "'package.%s' must be a string", pname); - return searchpath(L, name, path, ".", dirsep); -} - - -static int checkload (lua_State *L, int stat, const char *filename) { - if (l_likely(stat)) { /* module loaded successfully? */ - lua_pushstring(L, filename); /* will be 2nd argument to module */ - return 2; /* return open function and file name */ - } - else - return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s", - lua_tostring(L, 1), filename, lua_tostring(L, -1)); -} - - -static int searcher_Lua (lua_State *L) { - const char *filename; - const char *name = luaL_checkstring(L, 1); - filename = findfile(L, name, "path", LUA_LSUBSEP); - if (filename == NULL) return 1; /* module not found in this path */ - return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename); -} - - -/* -** Try to find a load function for module 'modname' at file 'filename'. -** First, change '.' to '_' in 'modname'; then, if 'modname' has -** the form X-Y (that is, it has an "ignore mark"), build a function -** name "luaopen_X" and look for it. (For compatibility, if that -** fails, it also tries "luaopen_Y".) If there is no ignore mark, -** look for a function named "luaopen_modname". -*/ -static int loadfunc (lua_State *L, const char *filename, const char *modname) { - const char *openfunc; - const char *mark; - modname = luaL_gsub(L, modname, ".", LUA_OFSEP); - mark = strchr(modname, *LUA_IGMARK); - if (mark) { - int stat; - openfunc = lua_pushlstring(L, modname, mark - modname); - openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc); - stat = lookforfunc(L, filename, openfunc); - if (stat != ERRFUNC) return stat; - modname = mark + 1; /* else go ahead and try old-style name */ - } - openfunc = lua_pushfstring(L, LUA_POF"%s", modname); - return lookforfunc(L, filename, openfunc); -} - - -static int searcher_C (lua_State *L) { - const char *name = luaL_checkstring(L, 1); - const char *filename = findfile(L, name, "cpath", LUA_CSUBSEP); - if (filename == NULL) return 1; /* module not found in this path */ - return checkload(L, (loadfunc(L, filename, name) == 0), filename); -} - - -static int searcher_Croot (lua_State *L) { - const char *filename; - const char *name = luaL_checkstring(L, 1); - const char *p = strchr(name, '.'); - int stat; - if (p == NULL) return 0; /* is root */ - lua_pushlstring(L, name, p - name); - filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP); - if (filename == NULL) return 1; /* root not found */ - if ((stat = loadfunc(L, filename, name)) != 0) { - if (stat != ERRFUNC) - return checkload(L, 0, filename); /* real error */ - else { /* open function not found */ - lua_pushfstring(L, "no module '%s' in file '%s'", name, filename); - return 1; - } - } - lua_pushstring(L, filename); /* will be 2nd argument to module */ - return 2; -} - - -static int searcher_preload (lua_State *L) { - const char *name = luaL_checkstring(L, 1); - lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); - if (lua_getfield(L, -1, name) == LUA_TNIL) { /* not found? */ - lua_pushfstring(L, "no field package.preload['%s']", name); - return 1; - } - else { - lua_pushliteral(L, ":preload:"); - return 2; - } -} - - -static void findloader (lua_State *L, const char *name) { - int i; - luaL_Buffer msg; /* to build error message */ - /* push 'package.searchers' to index 3 in the stack */ - if (l_unlikely(lua_getfield(L, lua_upvalueindex(1), "searchers") - != LUA_TTABLE)) - luaL_error(L, "'package.searchers' must be a table"); - luaL_buffinit(L, &msg); - /* iterate over available searchers to find a loader */ - for (i = 1; ; i++) { - luaL_addstring(&msg, "\n\t"); /* error-message prefix */ - if (l_unlikely(lua_rawgeti(L, 3, i) == LUA_TNIL)) { /* no more searchers? */ - lua_pop(L, 1); /* remove nil */ - luaL_buffsub(&msg, 2); /* remove prefix */ - luaL_pushresult(&msg); /* create error message */ - luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1)); - } - lua_pushstring(L, name); - lua_call(L, 1, 2); /* call it */ - if (lua_isfunction(L, -2)) /* did it find a loader? */ - return; /* module loader found */ - else if (lua_isstring(L, -2)) { /* searcher returned error message? */ - lua_pop(L, 1); /* remove extra return */ - luaL_addvalue(&msg); /* concatenate error message */ - } - else { /* no error message */ - lua_pop(L, 2); /* remove both returns */ - luaL_buffsub(&msg, 2); /* remove prefix */ - } - } -} - - -static int ll_require (lua_State *L) { - const char *name = luaL_checkstring(L, 1); - lua_settop(L, 1); /* LOADED table will be at index 2 */ - lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); - lua_getfield(L, 2, name); /* LOADED[name] */ - if (lua_toboolean(L, -1)) /* is it there? */ - return 1; /* package is already loaded */ - /* else must load package */ - lua_pop(L, 1); /* remove 'getfield' result */ - findloader(L, name); - lua_rotate(L, -2, 1); /* function <-> loader data */ - lua_pushvalue(L, 1); /* name is 1st argument to module loader */ - lua_pushvalue(L, -3); /* loader data is 2nd argument */ - /* stack: ...; loader data; loader function; mod. name; loader data */ - lua_call(L, 2, 1); /* run loader to load module */ - /* stack: ...; loader data; result from loader */ - if (!lua_isnil(L, -1)) /* non-nil return? */ - lua_setfield(L, 2, name); /* LOADED[name] = returned value */ - else - lua_pop(L, 1); /* pop nil */ - if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */ - lua_pushboolean(L, 1); /* use true as result */ - lua_copy(L, -1, -2); /* replace loader result */ - lua_setfield(L, 2, name); /* LOADED[name] = true */ - } - lua_rotate(L, -2, 1); /* loader data <-> module result */ - return 2; /* return module result and loader data */ -} - -/* }====================================================== */ - - - - -static const luaL_Reg pk_funcs[] = { - {"loadlib", ll_loadlib}, - {"searchpath", ll_searchpath}, - /* placeholders */ - {"preload", NULL}, - {"cpath", NULL}, - {"path", NULL}, - {"searchers", NULL}, - {"loaded", NULL}, - {NULL, NULL} -}; - - -static const luaL_Reg ll_funcs[] = { - {"require", ll_require}, - {NULL, NULL} -}; - - -static void createsearcherstable (lua_State *L) { - static const lua_CFunction searchers[] = { - searcher_preload, - searcher_Lua, - searcher_C, - searcher_Croot, - NULL - }; - int i; - /* create 'searchers' table */ - lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); - /* fill it with predefined searchers */ - for (i=0; searchers[i] != NULL; i++) { - lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ - lua_pushcclosure(L, searchers[i], 1); - lua_rawseti(L, -2, i+1); - } - lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ -} - - -/* -** create table CLIBS to keep track of loaded C libraries, -** setting a finalizer to close all libraries when closing state. -*/ -static void createclibstable (lua_State *L) { - luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); /* create CLIBS table */ - lua_createtable(L, 0, 1); /* create metatable for CLIBS */ - lua_pushcfunction(L, gctm); - lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ - lua_setmetatable(L, -2); -} - -#include "racf.h" -#include "acee.h" -#include "clibppa.h" -typedef struct upt { - char dontcare[16]; - char uptprefx[7]; - char uptprefl; -} UPT; -typedef struct pscb { - char dontcare[52]; - UPT *pscbupt; - short pscbuptl; -} PSCB; - -static char *makepath(void) -{ - CLIBPPA *ppa = __ppaget(); - ACEE *acee = racf_get_acee(); - char *path = calloc(1, strlen(LUA_PATH_DEFAULT)+128); - char prefix[12] = {0}; - char userid[12] = {0}; - int pos = 0; - int i; - - if (!path) goto quit; - - if (ppa && ppa->ppapscb) { - /* we have a TSO PSCB control block */ - PSCB *pscb = ppa->ppapscb; - - if (pscb->pscbupt && pscb->pscbuptl) { - UPT *upt = pscb->pscbupt; - char *prefx = upt->uptprefx; - char prefxlen = upt->uptprefl; - - if (prefx[0] > ' ' && prefxlen) { - for(i=0; i < prefxlen; i++) { - prefix[i] = prefx[i]; - } - sprintf(&path[pos], "%s.LUA370.LUA(?);%s.LUA(?);", prefix, prefix); - pos = strlen(path); - } - } - } - - if (acee) { - for(i=0; i<8; i++) { - if (acee->aceeuser[i+1]==' ') { - userid[i] = 0; - break; - } - userid[i] = acee->aceeuser[i+1]; - } - } - - if (userid[0] && strcmp(prefix, userid)!=0) { - sprintf(&path[pos], "%s.LUA370.LUA(?);%s.LUA(?);", userid, userid); - pos = strlen(path); - } - - strcpy(&path[pos], LUA_PATH_DEFAULT); - // wtodumpf(path, strlen(path), "%s: path", __func__); -quit: - return path; -} - -static char *makecpath(void) -{ - CLIBPPA *ppa = __ppaget(); - ACEE *acee = racf_get_acee(); - char *cpath = calloc(1, strlen(LUA_PATH_DEFAULT)+128); - char prefix[12] = {0}; - char userid[12] = {0}; - int pos = 0; - int i; - - if (!cpath) goto quit; - - if (ppa && ppa->ppapscb) { - /* we have a TSO PSCB control block */ - PSCB *pscb = ppa->ppapscb; - - if (pscb->pscbupt && pscb->pscbuptl) { - UPT *upt = pscb->pscbupt; - char *prefx = upt->uptprefx; - char prefxlen = upt->uptprefl; - - if (prefx[0] > ' ' && prefxlen) { - for(i=0; i < prefxlen; i++) { - prefix[i] = prefx[i]; - } - sprintf(&cpath[pos], "%s.LUA370.LINKLIB(?);%s.LINKLIB(?);", prefix, prefix); - pos = strlen(cpath); - } - } - } - - if (acee) { - for(i=0; iaceeuser[0]; i++) { - if (acee->aceeuser[i+1]==' ') { - userid[i] = 0; - break; - } - userid[i] = acee->aceeuser[i+1]; - } - } - - if (userid[0] && strcmp(prefix, userid)!=0) { - sprintf(&cpath[pos], "%s.LUA370.LINKLIB(?);%s.LINKLIB(?);", userid, userid); - pos = strlen(cpath); - } - - strcpy(&cpath[pos], LUA_CPATH_DEFAULT); - // wtodumpf(cpath, strlen(cpath), "%s: cpath", __func__); - -quit: - return cpath; -} - -LUAMOD_API int luaopen_package (lua_State *L) { - createclibstable(L); - luaL_newlib(L, pk_funcs); /* create 'package' table */ - createsearcherstable(L); - /* set paths */ -#if 1 - { - char *path = makepath(); - char *cpath = makecpath(); - - if (path) { - setpath(L, "path", LUA_PATH_VAR, path); - free(path); - } - else { - setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT); - } - - if (cpath) { - setpath(L, "cpath", LUA_CPATH_VAR, cpath); - free(cpath); - } - else { - setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT); - } - } -#else - setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT); - setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT); -#endif - /* store config information */ - lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" - LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); - lua_setfield(L, -2, "config"); - /* set field 'loaded' */ - luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); - lua_setfield(L, -2, "loaded"); - /* set field 'preload' */ - luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); - lua_setfield(L, -2, "preload"); - lua_pushglobaltable(L); - lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ - luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */ - lua_pop(L, 1); /* pop global table */ - return 1; /* return 'package' table */ -} -