diff options
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/lua/loslibext.c')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/lua/loslibext.c | 627 |
1 files changed, 627 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/lua/loslibext.c b/Build/source/texk/web2c/luatexdir/lua/loslibext.c new file mode 100644 index 00000000000..003b031f627 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/lua/loslibext.c @@ -0,0 +1,627 @@ +/* $Id: loslibext.c 1066 2008-02-23 10:52:51Z taco $ */ + +#include "luatex-api.h" +#include <ptexlib.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> + +/* An attempt to figure out the basic platform, does not + care about niceties like version numbers yet, + and ignores platforms where luatex is unlikely to + successfully compile without major prorting effort + (amiga|mac|os2|vms) */ + +#if defined(_WIN32) || defined(WIN32) || defined(__NT__) +#define OS_PLATTYPE "windows" +#define OS_PLATNAME "windows" +#elif defined(__GO32__) || defined(__DJGPP__) || defined(__DOS__) +#define OS_PLATTYPE "msdos" +#define OS_PLATNAME "msdos" +#else /* assume everything else is unix-y */ +#define OS_PLATTYPE "unix" +/* this is just a first guess */ +#if defined(__BSD__) + #define OS_PLATNAME "bsd" +#elif defined(__SYSV__) + #define OS_PLATNAME "sysv" +#else + #define OS_PLATNAME "generic" +#endif +/* attempt to be more precise */ +#if defined(__LINUX__) || defined (__linux) + #undef OS_PLATNAME + #define OS_PLATNAME "linux" +#elif defined(__FREEBSD__) || defined(__FreeBSD) + #undef OS_PLATNAME + #define OS_PLATNAME "freebsd" +#elif defined(__OPENBSD__) || defined(__OpenBSD) + #undef OS_PLATNAME + #define OS_PLATNAME "openbsd" +#elif defined(__SOLARIS__) + #undef OS_PLATNAME + #define OS_PLATNAME "solaris" +#elif defined(__SUNOS__) || defined(__SUN__) || defined(sun) + #undef OS_PLATNAME + #define OS_PLATNAME "sunos" +#elif defined(HPUX) || defined(__hpux) + #undef OS_PLATNAME + #define OS_PLATNAME "hpux" +#elif defined(__sgi) + #undef OS_PLATNAME + #define OS_PLATNAME "irix" +#elif defined(__MACH__) && defined(__APPLE__) + #undef OS_PLATNAME + #define OS_PLATNAME "macosx" +#endif +#endif + + + + + +/* there could be more platforms that don't have these two, + * but win32 and sunos are for sure. + * gettimeofday() for win32 is using an alternative definition + */ + +#if (! defined(WIN32)) && (! defined(__SUNOS__)) +#include <sys/time.h> /* gettimeofday() */ +#include <sys/times.h> /* times() */ +#include <sys/wait.h> +#endif + +/* set this to one for spawn instead of exec on windows */ + +#define DONT_REALLY_EXIT 1 + +#ifdef WIN32 +#include <process.h> +#define spawn_command(a,b,c) _spawnvpe(_P_WAIT,(const char *)a,(const char* const*)b,(const char* const*)c) +#if DONT_REALLY_EXIT +#define exec_command(a,b,c) exit(spawn_command((a),(b),(c))) +#else +#define exec_command(a,b,c) _execvpe((const char *)a,(const char* const*)b,(const char* const*)c) +#endif +#else +#include <unistd.h> +#define DEFAULT_PATH "/bin:/usr/bin:." + +static int +exec_command(const char *file, char *const *argv, char *const *envp) +{ + char path[PATH_MAX]; + const char *searchpath, *esp; + size_t prefixlen, filelen, totallen; + + if (strchr(file, '/')) /* Specific path */ + return execve(file, argv, envp); + + filelen = strlen(file); + + searchpath = getenv("PATH"); + if (!searchpath) + searchpath = DEFAULT_PATH; + + errno = ENOENT; /* Default errno, if execve() doesn't change it */ + + do { + esp = strchr(searchpath, ':'); + if (esp) + prefixlen = esp - searchpath; + else + prefixlen = strlen(searchpath); + + if (prefixlen == 0 || searchpath[prefixlen - 1] == '/') { + totallen = prefixlen + filelen; + if (totallen >= PATH_MAX) + continue; + memcpy(path, searchpath, prefixlen); + memcpy(path + prefixlen, file, filelen); + } else { + totallen = prefixlen + filelen + 1; + if (totallen >= PATH_MAX) + continue; + memcpy(path, searchpath, prefixlen); + path[prefixlen] = '/'; + memcpy(path + prefixlen + 1, file, filelen); + } + path[totallen] = '\0'; + + execve(path, argv, envp); + if (errno == E2BIG || errno == ENOEXEC || + errno == ENOMEM || errno == ETXTBSY) + break; /* Report this as an error, no more search */ + + searchpath = esp + 1; + } while (esp); + + return -1; +} + +/* + It is not possible to mimic |spawnve()| completely. The main problem is + that the |fork|--|waitpid| combination cannot really do identical error + reporting to the parent process, because it has to pass all the possible + error conditions as well as the actual process return status through a + single 8-bit value. + + The current implementation tries to give back meaningful results for |execve()| + errors in the child, for the cases that could also be returned by |spawnve()|, + and for |ETXTBSY|, because that can be triggered by our path searching routine. + + This implementation does not differentiate abnormal status conditions reported + by |waitpid()|, but will simply return a single error indication value. + + For all this, hyjacking a bunch of numbers in the range 1...255 is needed. + The chance of collisions is hopefully diminished by using a rather random + range in the 8-bit section. +*/ + +#define INVALID_RET_E2BIG 143 +#define INVALID_RET_ENOENT 144 +#define INVALID_RET_ENOEXEC 145 +#define INVALID_RET_ENOMEM 146 +#define INVALID_RET_ETXTBSY 147 +#define INVALID_RET_UNKNOWN 148 +#define INVALID_RET_INTR 149 + +static int +spawn_command(const char *file, char *const *argv, char *const *envp) +{ + pid_t pid, wait_pid; + int status; + pid = fork(); + if (pid<0) { + return -1; /* fork failed */ + } + if (pid>0) { /* parent */ + status = 0; + wait_pid = waitpid (pid, &status,0); + if (wait_pid == pid) { + if (WIFEXITED(status)) + return WEXITSTATUS(status); + else + return INVALID_RET_INTR; + } else { + return -1; /* some waitpid error */ + } + } else { + int f; + /* somewhat random upper limit. ignore errors on purpose */ + for (f = 0; f<256; f++) + (void)fsync(f); + + if (exec_command(file, argv, envp)) { + /* let's hope no-one uses these values */ + switch (errno) { + case E2BIG: exit(INVALID_RET_E2BIG); + case ETXTBSY: exit(INVALID_RET_ETXTBSY); + case ENOENT: exit(INVALID_RET_ENOENT); + case ENOEXEC: exit(INVALID_RET_ENOEXEC); + case ENOMEM: exit(INVALID_RET_ENOMEM); + default: exit(INVALID_RET_UNKNOWN); + } + return -1; + } + } +} + +#endif + +extern char **environ; + +static char ** +do_split_command(char *maincmd) +{ + char *piece, *start_piece; + char *cmd; + char **cmdline = NULL; + unsigned int i, j; + int ret = 0; + int in_string = 0; + int quoted = 0; + if (strlen(maincmd) == 0) + return NULL; + /* allocate the array of options first. it will probably be + be a little bit too big, but better too much than to little */ + j=2; + for (i = 0; i < strlen(maincmd); i++) { if (maincmd[i]==' ') j++; } + cmdline = malloc(sizeof(char *) * j); + for (i = 0; i < j; i++) { cmdline[i] = NULL; } + cmd = maincmd; + i = 0; + while (cmd[i] == ' ') i++; /* skip leading spaces */ + start_piece = malloc(strlen(cmd)+1); /* a buffer */ + piece = start_piece; + for (; i <= strlen(maincmd); i++) { + if (cmd[i]=='\\' && + (cmd[i+1] == '\\' || cmd[i+1] == '\'' || cmd[i+1] == '"')) { + quoted =1; + continue; + } + if (in_string && cmd[i] == in_string && !quoted) { + in_string = 0; + continue; + } + if ((cmd[i] == '"' || cmd[i] == '\'')&& !quoted) { + in_string = cmd[i]; + continue; + } + if ((in_string==0 && cmd[i] == ' ') || cmd[i]==0) { + *piece = 0; + cmdline[ret++] = xstrdup(start_piece); + piece = start_piece; + while (i < strlen(maincmd) && cmd[(i + 1)] == ' ') + i++; + continue; + } + *piece++ = cmd[i]; + quoted=0; + } + xfree(start_piece); + return cmdline; +} + +static char ** +do_flatten_command(lua_State *L, char **runcmd) { + unsigned int i, j ; + char *s; + char **cmdline = NULL; + *runcmd = NULL; + + for (j = 1;;j++) { + lua_rawgeti(L,-1,j); + if (lua_isnil(L,-1)) { + lua_pop(L,1); + break; + } + lua_pop(L,1); + } + if (j == 1) + return NULL; + cmdline = malloc(sizeof(char *) * (j+1)); + for (i = 1; i <= j; i++) { + cmdline[i] = NULL; + lua_rawgeti(L,-1,i); + if (lua_isnil(L,-1) || (s=(char *)lua_tostring(L,-1))==NULL) { + lua_pop(L,1); + if (i==1) { + xfree(cmdline) ; + return NULL; + } else { + break; + } + } else { + lua_pop(L,1); + cmdline[(i-1)] = xstrdup(s); + } + } + cmdline[i] = NULL; + + lua_rawgeti(L,-1,0); + if (lua_isnil(L,-1) || (s=(char *)lua_tostring(L,-1))==NULL) { + *runcmd = cmdline[0]; + } else { + *runcmd = xstrdup(s); + } + lua_pop(L,1); + + return cmdline; +} + + +static int os_exec (lua_State *L) { + char * maincmd, * runcmd; + char ** cmdline = NULL; + + if (lua_gettop(L)!=1) { + lua_pushnil(L); + lua_pushliteral(L,"invalid arguments passed"); + return 2; + } + if (lua_type(L,1)==LUA_TSTRING) { + maincmd = (char *)lua_tostring(L, 1); + cmdline = do_split_command(maincmd); + runcmd = cmdline[0]; + } else if (lua_type(L,1)==LUA_TTABLE) { + cmdline = do_flatten_command(L, & runcmd); + } + if (cmdline!=NULL) { +#if defined(WIN32) && DONT_REALLY_EXIT + exec_command(runcmd, cmdline, environ); +#else + if (exec_command(runcmd, cmdline, environ)==-1) { + lua_pushnil(L); + lua_pushfstring(L,"%s: %s",runcmd, strerror(errno)); + lua_pushnumber(L, errno); + return 3; + } +#endif + } + lua_pushnil(L); + lua_pushliteral(L,"invalid command line passed"); + return 2; +} + +#define do_error_return(A,B) do { \ + lua_pushnil(L); \ + lua_pushfstring(L,"%s: %s",runcmd,(A)); \ + lua_pushnumber(L, B); \ + return 3; \ + } while (0) + +static int os_spawn (lua_State *L) { + char * maincmd, * runcmd; + char ** cmdline = NULL; + int i; + + if (lua_gettop(L)!=1) { + lua_pushnil(L); + lua_pushliteral(L,"invalid arguments passed"); + return 2; + } + if (lua_type(L,1)==LUA_TSTRING) { + maincmd = (char *)lua_tostring(L, 1); + cmdline = do_split_command(maincmd); + runcmd = cmdline[0]; + } else if (lua_type(L,1)==LUA_TTABLE) { + cmdline = do_flatten_command(L, &runcmd); + } + if (cmdline!=NULL) { + i = spawn_command(runcmd, cmdline, environ); + if (i==0) { + lua_pushnumber(L, i); + return 1; + } else if (i==-1) { + /* this branch covers WIN32 as well as fork() and waitpid() errors */ + do_error_return(strerror(errno),errno); +#ifndef WIN32 + } else if (i==INVALID_RET_E2BIG) { do_error_return(strerror(E2BIG),i); + } else if (i==INVALID_RET_ENOENT) { do_error_return(strerror(ENOENT),i); + } else if (i==INVALID_RET_ENOEXEC) { do_error_return(strerror(ENOEXEC),i); + } else if (i==INVALID_RET_ENOMEM) { do_error_return(strerror(ENOMEM),i); + } else if (i==INVALID_RET_ETXTBSY) { do_error_return(strerror(ETXTBSY),i); + } else if (i==INVALID_RET_UNKNOWN) { do_error_return("execution failed",i); + } else if (i==INVALID_RET_INTR) { do_error_return("execution interrupted",i); +#endif + } else { + lua_pushnumber(L, i); + return 1; + } + } + lua_pushnil(L); + lua_pushliteral(L,"invalid command line passed"); + return 2; +} + +/* Hans wants to set env values */ + +static int os_setenv (lua_State *L) { + char *value, *key, *val; + key = (char *)luaL_optstring(L, 1, NULL); + val = (char *)luaL_optstring(L, 2, NULL); + if (key) { + if (val) { + value = xmalloc(strlen(key)+strlen(val)+2); + sprintf(value,"%s=%s",key,val); + if (putenv(value)) { + return luaL_error(L, "unable to change environment"); + } + } else { +#if defined(WIN32) || defined(__sun__) + value = xmalloc(strlen(key)+2); + sprintf(value,"%s=",key); + if (putenv(value)) { + return luaL_error(L, "unable to change environment"); + } +#else + (void)unsetenv(key); +#endif + } + } + lua_pushboolean (L, 1); + return 1; +} + + +void find_env (lua_State *L){ + char *envitem, *envitem_orig; + char *envkey; + char **envpointer; + envpointer = environ; + lua_getglobal(L,"os"); + if (envpointer!=NULL && lua_istable(L,-1)) { + luaL_checkstack(L,2,"out of stack space"); + lua_pushstring(L,"env"); + lua_newtable(L); + while (*envpointer) { + /* TODO: perhaps a memory leak here */ + luaL_checkstack(L,2,"out of stack space"); + envitem = xstrdup(*envpointer); + envitem_orig = envitem; + envkey=envitem; + while (*envitem != '=') { + envitem++; + } + *envitem=0; + envitem++; + lua_pushstring(L,envkey); + lua_pushstring(L,envitem); + lua_rawset(L,-3); + envpointer++; + free(envitem_orig); + } + lua_rawset(L,-3); + } + lua_pop(L,1); +} + +static int ex_sleep(lua_State *L) +{ + lua_Number interval = luaL_checknumber(L, 1); + lua_Number units = luaL_optnumber(L, 2, 1); +#ifdef WIN32 + Sleep(1e3 * interval / units); +#else /* assumes posix or bsd */ + usleep(1e6 * interval / units); +#endif + return 0; +} + +#if (! defined (WIN32)) && (! defined (__SUNOS__)) +static int os_times (lua_State *L) { + struct tms r; + (void)times(&r); + lua_newtable(L); + lua_pushnumber(L, ((lua_Number)(r.tms_utime))/(lua_Number)sysconf(_SC_CLK_TCK)); + lua_setfield(L,-2,"utime"); + lua_pushnumber(L, ((lua_Number)(r.tms_stime))/(lua_Number)sysconf(_SC_CLK_TCK)); + lua_setfield(L,-2,"stime"); + lua_pushnumber(L, ((lua_Number)(r.tms_cutime))/(lua_Number)sysconf(_SC_CLK_TCK)); + lua_setfield(L,-2,"cutime"); + lua_pushnumber(L, ((lua_Number)(r.tms_cstime))/(lua_Number)sysconf(_SC_CLK_TCK)); + lua_setfield(L,-2,"cstime"); + return 1; +} +#endif + +#if ! defined (__SUNOS__) + +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 +#else + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL +#endif + +static int os_gettimeofday (lua_State *L) { + double v; +#ifndef WIN32 + struct timeval tv; + gettimeofday(&tv, NULL); + v = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; +#else + FILETIME ft; + unsigned __int64 tmpres = 0; + + GetSystemTimeAsFileTime(&ft); + + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; + tmpres /= 10; + tmpres -= DELTA_EPOCH_IN_MICROSECS; /*converting file time to unix epoch*/ + v = (double)tmpres / 1000000.0; +#endif + lua_pushnumber(L, v); + return 1; +} +#endif + +static const char repl[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + +static int dirs_made = 0; + +#define MAXTRIES 36*36*36 + +char * +do_mkdtemp (char *tmpl) +{ + int count ; + int value ; + char *xes = &tmpl[strlen (tmpl) - 6]; + /* this is not really all that random, but it will do */ + if (dirs_made==0) { + srand(time(NULL)); + } + value = rand(); + for (count = 0; count < MAXTRIES; value += 8413, ++count) { + int v = value; + xes[0] = repl[v % 36]; v /= 36; + xes[1] = repl[v % 36]; v /= 36; + xes[2] = repl[v % 36]; v /= 36; + xes[3] = repl[v % 36]; v /= 36; + xes[4] = repl[v % 36]; v /= 36; + xes[5] = repl[v % 36]; + if (mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR) >= 0) { + dirs_made++; + return tmpl; + } else if (errno != EEXIST) { + return NULL; + } + } + return NULL; +} + +static int os_tmpdir (lua_State *L) { + char *s, *tempdir; + char *tmp = (char *)luaL_optstring(L, 1, "luatex.XXXXXX"); + if (tmp==NULL || + strlen(tmp)<6 || + (strcmp(tmp+strlen(tmp)-6,"XXXXXX") != 0)) { + lua_pushnil(L); + lua_pushstring(L, "Invalid argument to os.tmpdir()"); + return 2; + } else { + tempdir = xstrdup(tmp); + } +#ifdef HAVE_MKDTEMP + s = mkdtemp(tempdir); +#else + s = do_mkdtemp(tempdir); +#endif + if (s==NULL) { + int en = errno; /* calls to Lua API may change this value */ + lua_pushnil(L); + lua_pushfstring(L, "%s", strerror(en)); + return 2; + } else { + lua_pushstring(L,s); + return 1; + } +} + + +void +open_oslibext (lua_State *L, int safer_option) { + + find_env(L); + + lua_getglobal(L,"os"); + lua_pushcfunction(L, ex_sleep); + lua_setfield(L,-2,"sleep"); + lua_getglobal(L,"os"); + lua_pushliteral(L, OS_PLATTYPE); + lua_setfield(L,-2,"type"); + lua_getglobal(L,"os"); + lua_pushliteral(L, OS_PLATNAME); + lua_setfield(L,-2,"name"); +#if (! defined (WIN32)) && (! defined (__SUNOS__)) + lua_getglobal(L,"os"); + lua_pushcfunction(L, os_times); + lua_setfield(L,-2,"times"); +#endif +#if ! defined (__SUNOS__) + lua_getglobal(L,"os"); + lua_pushcfunction(L, os_gettimeofday); + lua_setfield(L,-2,"gettimeofday"); +#endif + if (!safer_option) { + lua_getglobal(L,"os"); + lua_pushcfunction(L, os_setenv); + lua_setfield(L,-2,"setenv"); + lua_getglobal(L,"os"); + lua_pushcfunction(L, os_exec); + lua_setfield(L,-2,"exec"); + lua_getglobal(L,"os"); + lua_pushcfunction(L, os_spawn); + lua_setfield(L,-2,"spawn"); + lua_getglobal(L,"os"); + lua_pushcfunction(L, os_tmpdir); + lua_setfield(L,-2,"tmpdir"); + + } + + +} |