lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Continuing from the older thread, here is a patch to Lua 5.1-beta
interpreter (only lua.c is modified), enabling running Lua scripts from
the shell with no need to type the exact location of scripts, provided
the script to be run is located on the so-called LUA_RPATH.

LUA_RPATH ("run-path") is a string-template like LUA_PATH or LUA_CPATH
(i.e., question marks are used for replacement).

It may be set as:
a) the value of the environment variable LUA_RPATH (higher priority), or

b) the global variable LUA_RPATH, from the file pointed to by LUA_INIT
(lower priority).

For this feature to be activated, the script name should be prefixed by
a `@' character on the command line.

E.g., provided LUA_RPATH is
   ./?.lua;/home/shmuel/run/lua/?.lua;/home/shmuel/run/lua/?/?.lua;

one can run
   /home/shmuel/run/lua/lbackup/lbackup.lua <parameters>

by specifying
   lua @lbackup <parameters>
from any directory.

[Any comments and criticism are welcome].

--
Shmuel


diff -urN lua-5.1-beta-old/src/lua.c lua-5.1-beta/src/lua.c
--- lua-5.1-beta-old/src/lua.c	Mon Oct 24 19:38:48 2005
+++ lua-5.1-beta/src/lua.c	Tue Jan 10 00:11:20 2006
@@ -235,20 +235,81 @@
 }
 
 
+/* copied from loadlib.c */
+static int readable (const char *filename) {
+  FILE *f = fopen(filename, "r");  /* try to open file */
+  if (f == NULL) return 0;  /* open failed */
+  fclose(f);
+  return 1;
+}
+
+
+/* copied from loadlib.c */
+static const char *pushnexttemplate (lua_State *L, const char *path) {
+  const char *l;
+  while (*path == *LUA_PATHSEP) path++;  /* skip separators */
+  if (*path == '\0') return NULL;  /* no more templates */
+  l = strchr(path, *LUA_PATHSEP);  /* find next separator */
+  if (l == NULL) l = path + strlen(path);
+  lua_pushlstring(L, path, l - path);  /* template */
+  return l;
+}
+
+
+/* copied from loadlib.c and truncated a bit */
+static const char *findfile (lua_State *L, const char *name,
+                                           const char *pname) {
+  const char *path = pname;
+  while ((path = pushnexttemplate(L, path)) != NULL) {
+    const char *filename;
+    filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name);
+    if (readable(filename))  /* does file exist and is readable? */
+      return filename;  /* return that file name */
+    lua_pop(L, 2);  /* remove path template and file name */
+  }
+  return NULL;  /* not found */
+}
+
+
 static int handle_script (lua_State *L, char **argv, int n) {
+  const char *rpath = NULL;
   int status;
   const char *fname;
   int narg = getargs(L, argv, n);  /* collect arguments */
   lua_setglobal(L, "arg");
   fname = argv[n];
-  if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) 
+  if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0)
     fname = NULL;  /* stdin */
-  status = luaL_loadfile(L, fname);
+
+  if(fname && (fname[0] == '@')) {
+    ++fname;
+    rpath = getenv("LUA_RPATH");
+    if(rpath)
+      lua_pushstring(L, rpath);
+    else {
+      lua_getglobal(L, "LUA_RPATH");
+      rpath = lua_tostring(L, -1);
+    }
+    /* get `full_script_ name` */
+    if(rpath && (rpath = findfile(L, fname, rpath)) != NULL) {
+      /* set arg[0] = `full_script_name` */
+      lua_getglobal(L, "arg");
+      lua_pushstring(L, rpath);
+      lua_rawseti(L, -2, 0);
+      /* load the script file */
+      status = luaL_loadfile(L, rpath);
+      lua_insert(L, -5);
+      lua_pop(L, 4);
+    }
+    else lua_pop(L,1);
+  }
+  if(!rpath)
+    status = luaL_loadfile(L, fname);
   lua_insert(L, -(narg+1));
   if (status == 0)
     status = docall(L, narg, 0);
   else
-    lua_pop(L, narg);      
+    lua_pop(L, narg);
   return report(L, status);
 }