diff options
author | Ronan Collobert <ronan@collobert.com> | 2012-01-25 17:55:20 +0400 |
---|---|---|
committer | Ronan Collobert <ronan@collobert.com> | 2012-01-25 17:55:20 +0400 |
commit | 04c55e41e4f948da1895bcaeac0885582434f66f (patch) | |
tree | 248ef6735f58a39b92e17cc0feb7271ea6dc83db |
initial revamp of torch7 tree
-rw-r--r-- | CMakeLists.txt | 36 | ||||
-rw-r--r-- | dok/index.dok | 204 | ||||
-rw-r--r-- | init.lua.in | 83 | ||||
-rw-r--r-- | paths.c | 813 | ||||
-rw-r--r-- | paths.h.in | 84 |
5 files changed, 1220 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d771d66 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,36 @@ +# -*- cmake -*- + +INCLUDE(CheckIncludeFiles) +INCLUDE(CheckFunctionExists) + +IF (UNIX OR NOT WIN32) + CHECK_INCLUDE_FILES(fcntl.h HAVE_FCNTL_H) + CHECK_INCLUDE_FILES(unistd.h HAVE_UNISTD_H) + CHECK_INCLUDE_FILES(dirent.h HAVE_DIRENT_H) + CHECK_INCLUDE_FILES(time.h HAVE_TIME_H) + CHECK_INCLUDE_FILES(sys/time.h HAVE_SYS_TIME_H) + CHECK_INCLUDE_FILES(sys/ndir.h HAVE_SYS_NDIR_H) + CHECK_INCLUDE_FILES(sys/dir.h HAVE_SYS_DIR_H) + CHECK_INCLUDE_FILES(ndir.h HAVE_NDIR_H) + CHECK_FUNCTION_EXISTS(getcwd HAVE_GETCWD) +ENDIF (UNIX OR NOT WIN32) + + +INCLUDE_DIRECTORIES( + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}") + +CONFIGURE_FILE("paths.h.in" "${CMAKE_CURRENT_BINARY_DIR}/paths.h") +CONFIGURE_FILE("init.lua.in" "${CMAKE_CURRENT_BINARY_DIR}/init.lua") + +SET(src + "${CMAKE_CURRENT_SOURCE_DIR}/paths.c" + "${CMAKE_CURRENT_BINARY_DIR}/paths.h" ) + +SET(luasrc + "${CMAKE_CURRENT_BINARY_DIR}/init.lua") + +ADD_TORCH_PACKAGE(paths "${src}" "${luasrc}" "System") +ADD_TORCH_DOK(dok paths "Fundamentals" "Paths and files utilities" 1.) + +TARGET_LINK_LIBRARIES(paths ${LUA_LIBRARIES}) diff --git a/dok/index.dok b/dok/index.dok new file mode 100644 index 0000000..e118196 --- /dev/null +++ b/dok/index.dok @@ -0,0 +1,204 @@ +====== Filename Manipulation Package ====== +{{anchor:paths.dok}} + +This package provides portable functions to manipulate filenames. + +When this package is loaded, it also computes a number of useful +variables indicating where the various Torch components are installed. +Do not change their values. + + +==== Manipulating file names ==== +{{anchor:paths.filenames.dok}} + +The following functions can be used +to manipulate filenames in a portable way +over multiple platforms. + + +=== paths.filep(path) === +{{anchor:paths.filep}} + +Return a boolean indicating whether ''path'' +refers to an existing file. + +=== paths.dirp(path) === +{{anchor:paths.dirp}} + +Return a boolean indicating whether ''path'' +refers to an existing directory. + +=== paths.basename(path,[suffix]) === +{{anchor:paths.basename}} + +Return the last path component of ''path'' +and optionally strip the suffix ''suffix''. +This is similar to the well know shell command ''"basename"''. + +=== paths.dirname(path) === +{{anchor:paths.dirname}} + +Return the name of directory containing file ''path''. +This is similar to the well known shell command ''"dirname"''. + +=== paths.concat([path1,....,pathn]) === +{{anchor:paths.concat}} + +Concatenates relative filenames. + +First this function computes the full filename +of ''path1'' relative to the current directory. +Then it successively computes the full filenames +of arguments ''path2'' to ''pathn'' relative to +the filename returned for the previous argument. +Finally the last result is returned. + +Calling this function without argument returns the +full name of the current directory. + + +=== paths.cwd() === +{{anchor:paths.cwd}} + +Return the full path of the current directory. + + +=== paths.execdir() === +{{anchor:paths.execdir}} + +Return the name of the directory containing the +current Lua executable. +When the module ''paths'' is first loaded, +this information is used to relocate +the variables indicating +the location of the various Torch components. + + +==== Accessing directories ==== +{{anchor:paths.dirs.dok}} + +The following functions can be used +to examine directory contents. + + +=== paths.dir(dname) === +{{anchor:paths.dir}} + +Return a table containing the files in directory ''dname''. +This function return ''nil'' if the specified directory +does not exists. + +=== paths.files(dname) === +{{anchor:paths.files}} + +Returns an iterator over the files located in directory ''dname''. +This can be used in ***for*** expression as shown below: +<file> + for f in paths.files(".") do + print(f) + end +</file> + + +==== Finding files relative to a Lua script ==== +{{anchor:paths.findingfiles.dok}} + +=== paths.thisfile([arg]) === +{{anchor:paths.thisfile}} + +Calling ''paths.thisfile()'' without argument +inside a lua file returns returns the full +pathname of the file from which it is called. +This function always returns ''nil'' when called +interactively. + +Calling ''paths.thisfile(arg)'' with a string argument ''arg'' +returns the full pathname of the file ''arg'' relative +to the directory containing the file from which +function ''paths.thisfile'' is invoked. This is useful, +for instance, to locate files located in the same +directory as a lua script. + + +=== paths.dofile(filename) === +{{anchor:paths.dofile}} + +This function is similar to the standard Lua function ''dofile'' +but interprets ''filename'' relative to the directory containing +the file that contains the call to ''paths.dofile'', +or to the current directory when ''paths.dofile'' is +called interactively. + +==== Well known directories ==== +{{anchor:paths.wellknowndirs.dok}} + +These variables indicate where the various Torch components are installed. +It is not advisable to change their values! + + +=== paths.install_prefix === +{{anchor:paths.install_prefix}} + +The base directory of the Torch installation. + +=== paths.install_bin === +{{anchor:paths.install_bin}} + +The name of the directory containing the executable programs. +Under Windows, this directory also contains +the dynamically loadable libraries (''.dll''). + +=== paths.install_man === +{{anchor:paths.install_man}} + +The name of the directory containing the unix style manual pages. + +=== paths.install_lib === +{{anchor:paths.install_lib}} + +The name of the directory containing the object code libraries. +Under Unix, this directory also contains the dynamically +loadable libraries (''.so'' or ''.dylib''). + +=== paths.install_share === +{{anchor:paths.install_share}} + +The name of the directory containing processor independent data files, +such as lua code and other text files. + +=== paths.install_include === +{{anchor:paths.install_include}} + +The name of the directory containing the include files +for the various Torch libraries. + +=== paths.install_hlp === +{{anchor:paths.install_hlp}} + +The name of the directory containing the Torch help files. + +=== paths.install_html === +{{anchor:paths.install_html}} + +The name of the directory containing the HTML version +of the Torch help files. These files are generated +when you enable the CMake option ''HTML_DOC''. + +=== paths.install_cmake === +{{anchor:paths.install_cmake}} + +The name of the directory containing the CMake files +used by external Torch modules. + +=== paths.install_lua_path === +{{anchor:paths.install_lua_path}} + +The name of the directory containing the Lua packages. +This directory is used to build variable ''package.path''. + +=== paths.install_lua_cpath === +{{anchor:paths.install_lua_cpath}} + +The name of the directory containing the Lua loadable binary modules. +This directory is used to build variable ''package.cpath''. + diff --git a/init.lua.in b/init.lua.in new file mode 100644 index 0000000..e7c80a3 --- /dev/null +++ b/init.lua.in @@ -0,0 +1,83 @@ +# -*- lua -*- + +require 'libpaths' + +local assert = assert +local debug = debug +local pcall = pcall +local type = type +local g = _G + +module('paths') + +install_prefix = [[@Torch_INSTALL_PREFIX@]] +install_bin_subdir = [[@Torch_INSTALL_BIN_SUBDIR@]] +install_man_subdir = [[@Torch_INSTALL_MAN_SUBDIR@]] +install_lib_subdir = [[@Torch_INSTALL_LIB_SUBDIR@]] +install_share_subdir = [[@Torch_INSTALL_SHARE_SUBDIR@]] +install_include_subdir = [[@Torch_INSTALL_INCLUDE_SUBDIR@]] +install_hlp_subdir = [[@Torch_INSTALL_HLP_SUBDIR@]] +install_html_subdir = [[@Torch_INSTALL_HTML_SUBDIR@]] +install_cmake_subdir = [[@Torch_INSTALL_CMAKE_SUBDIR@]] +install_lua_path_subdir = [[@Torch_INSTALL_LUA_PATH_SUBDIR@]] +install_lua_cpath_subdir = [[@Torch_INSTALL_LUA_CPATH_SUBDIR@]] +install_bin_ridbus = [[@Torch_INSTALL_BIN_RIDBUS@]] +install_cmake_ridbus = [[@Torch_INSTALL_CMAKE_RIDBUS@]] + +local e = execdir() +if e ~= nil then + install_prefix = concat(e,install_bin_ridbus) +end + +install_bin = concat(install_prefix, install_bin_subdir) +install_man = concat(install_prefix, install_man_subdir) +install_lib = concat(install_prefix, install_lib_subdir) +install_share = concat(install_prefix, install_share_subdir) +install_include = concat(install_prefix, install_include_subdir) +install_hlp = concat(install_prefix, install_hlp_subdir) +install_html = concat(install_prefix, install_html_subdir) +install_cmake = concat(install_prefix, install_cmake_subdir) +install_lua_path = concat(install_prefix, install_lua_path_subdir) +install_lua_cpath = concat(install_prefix, install_lua_cpath_subdir) + +assert(concat(install_bin,install_bin_ridbus) == install_prefix) +assert(concat(install_cmake,install_cmake_ridbus) == install_prefix) + + +function files(s) + local d = dir(s) + local n = 0 + return function() + n = n + 1 + if (d and n <= #d) then + return d[n] + else + return nil + end + end +end + +function thisfile(arg, depth) + local s = debug.getinfo(depth or 2).source + if type(s) ~= "string" then + s = nil + elseif s:match("^@") then -- when called from a file + s = concat(s:sub(2)) + elseif s:match("^qt[.]") then -- when called from a qtide editor + local function z(s) return g.qt[s].fileName:tostring() end + local b, f = pcall(z, s:sub(4)); + if b and f and f ~= "" then s = f else s = nil end + end + if type(arg) == "string" then + if s then s = concat(dirname(s), arg) else s = arg end + end + return s +end + +function dofile(f, depth) + local s = thisfile(nil, 1 + (depth or 2)) + if s and s ~= "" then + f = concat(dirname(s),f) + end + return g.dofile(f) +end @@ -0,0 +1,813 @@ +/* -*- C -*- */ + + +#include "paths.h" + + + + +/* ------------------------------------------------------ */ +/* Utils to manipulate strings */ + + +#define SBINCREMENT 256 + +typedef struct { + char *buffer; + int maxlen; + int len; +} SB; + +static void +sbinit(SB *sb) +{ + sb->buffer = (char*)malloc(SBINCREMENT); + sb->maxlen = SBINCREMENT; + sb->len = 0; +} + +static char * +sbfree(SB *sb) +{ + if (sb->buffer) + free(sb->buffer); + sb->buffer = 0; + return 0; +} + +static void +sbgrow(SB *sb, int n) +{ + if (sb->buffer && sb->len + n > sb->maxlen) + { + int nlen = sb->maxlen; + while (sb->len + n > nlen) + nlen += SBINCREMENT; + sb->buffer = (char*)realloc(sb->buffer, nlen); + sb->maxlen = nlen; + } +} + +static void +sbadd1(SB *sb, char c) +{ + sbgrow(sb, 1); + if (sb->buffer) + sb->buffer[sb->len++] = c; +} + +static void +sbaddn(SB *sb, const char *s, int n) +{ + sbgrow(sb, n); + if (sb->buffer && s && n) + memcpy(sb->buffer + sb->len, s, n); + else if (sb->buffer && n) + sbfree(sb); + sb->len += n; +} + +static void +sbaddsf(SB *sb, char *s) +{ + if (s) + sbaddn(sb, s, strlen(s)); + else + sbfree(sb); + if (s) + free((void*)s); +} + +static void +sbslash(SB *sb) +{ + int i; + if (sb->buffer && sb->len) + for(i=0; i<sb->len; i++) + if (sb->buffer[i]=='\\') + sb->buffer[i]='/'; +} + +static int +sbpush(lua_State *L, SB *sb) +{ + sbslash(sb); + lua_pushlstring(L, sb->buffer, sb->len); + sbfree(sb); + return 1; +} + +static int +sbsetpush(lua_State *L, SB *sb, const char *s) +{ + sbfree(sb); + lua_pushstring(L, s); + return 1; +} + + +/* ------------------------------------------------------ */ +/* filep, dirp, basename, dirname */ + + +static int +filep(lua_State *L) +{ + const char *s = luaL_checkstring(L, 1); +#ifdef LUA_WIN + struct _stat buf; + if (_stat(s,&buf) < 0) + return 0; + if (buf.st_mode & S_IFDIR) + return 0; +#else + struct stat buf; + if (stat(s,&buf) < 0) + return 0; + if (buf.st_mode & S_IFDIR) + return 0; +#endif + return 1; +} + + +static int +dirp(lua_State *L) +{ + const char *s = luaL_checkstring(L, 1); +#ifdef LUA_WIN + struct _stat buf; + const char *last; + if ((s[0]=='/' || s[0]=='\\') && + (s[1]=='/' || s[1]=='\\') && !s[2]) + return 1; + last = s + strlen(s); + if (*last=='/' || *last=='\\' || *last==':') + { + lua_settop(L, 1); + lua_pushliteral(L, "."); + lua_concat(L, 2); + s = lua_tostring(L, -1); + } + if (_stat(s,&buf)==0) + if (buf.st_mode & S_IFDIR) + return 1; +#else + struct stat buf; + if (stat(s,&buf)==0) + if (buf.st_mode & S_IFDIR) + return 1; +#endif + return 0; +} + + +static int +lua_filep(lua_State *L) +{ + lua_pushboolean(L, filep(L)); + return 1; +} + + +static int +lua_dirp(lua_State *L) +{ + lua_pushboolean(L, dirp(L)); + return 1; +} + + +static int +lua_basename(lua_State *L) +{ + const char *fname = luaL_checkstring(L, 1); + const char *suffix = luaL_optstring(L, 2, 0); + +#ifdef LUA_WIN + + int sl; + const char *p, *s; + SB sb; + sbinit(&sb); + /* Special cases */ + if (fname[0] && fname[1]==':') { + sbaddn(&sb, fname, 2); + fname += 2; + if (fname[0]=='/' || fname[0]=='\\') + sbadd1(&sb, '/'); + while (fname[0]=='/' || fname[0]=='\\') + fname += 1; + if (fname[0]==0) + return sbpush(L, &sb); + sb.len = 0; + } + /* Position p after last nontrivial slash */ + s = p = fname; + while (*s) { + if ((s[0]=='\\' || s[0]=='/') && + (s[1] && s[1]!='/' && s[1]!='\\' ) ) + p = s + 1; + s++; + } + /* Copy into buffer */ + while (*p && *p!='/' && *p!='\\') + sbadd1(&sb, *p++); + /* Process suffix */ + if (suffix==0 || suffix[0]==0) + return sbpush(L, &sb); + if (suffix[0]=='.') + suffix += 1; + if (suffix[0]==0) + return sbpush(L, &sb); + sl = strlen(suffix); + if (sb.len > sl) { + s = sb.buffer + sb.len - (sl + 1); + if (s[0]=='.' && _strnicmp(s+1,suffix, sl)==0) + sb.len = s - sb.buffer; + } + return sbpush(L, &sb); + +#else + + int sl; + const char *s, *p; + SB sb; + sbinit(&sb); + /* Position p after last nontrivial slash */ + s = p = fname; + while (*s) { + if (s[0]=='/' && s[1] && s[1]!='/') + p = s + 1; + s++; + } + /* Copy into buffer */ + while (*p && *p!='/') + sbadd1(&sb, *p++); + /* Process suffix */ + if (suffix==0 || suffix[0]==0) + return sbpush(L, &sb); + if (suffix[0]=='.') + suffix += 1; + if (suffix[0]==0) + return sbpush(L, &sb); + sl = strlen(suffix); + if (sb.len > sl) { + s = sb.buffer + sb.len - (sl + 1); + if (s[0]=='.' && strncmp(s+1,suffix, sl)==0) + sb.len = s - sb.buffer; + } + return sbpush(L, &sb); + +#endif +} + + +static int +lua_dirname(lua_State *L) +{ + const char *fname = luaL_checkstring(L, 1); + +#ifdef LUA_WIN + + const char *s; + const char *p; + SB sb; + sbinit(&sb); + /* Handle leading drive specifier */ + if (isalpha((unsigned char)fname[0]) && fname[1]==':') { + sbadd1(&sb, *fname++); + sbadd1(&sb, *fname++); + } + /* Search last non terminal / or \ */ + p = 0; + s = fname; + while (*s) { + if ((s[0]=='\\' || s[0]=='/') && + (s[1] && s[1]!='/' && s[1]!='\\') ) + p = s; + s++; + } + /* Cannot find non terminal / or \ */ + if (p == 0) { + if (sb.len > 0) { + if (fname[0]==0 || fname[0]=='/' || fname[0]=='\\') + sbadd1(&sb, '/'); + return sbpush(L, &sb); + } else { + if (fname[0]=='/' || fname[0]=='\\') + return sbsetpush(L, &sb, "//"); + else + return sbsetpush(L, &sb, "."); + } + } + /* Single leading slash */ + if (p == fname) { + sbadd1(&sb, '/'); + return sbpush(L, &sb); + } + /* Backtrack all slashes */ + while (p>fname && (p[-1]=='/' || p[-1]=='\\')) + p--; + /* Multiple leading slashes */ + if (p == fname) + return sbsetpush(L, &sb, "//"); + /* Regular case */ + s = fname; + do { + sbadd1(&sb, *s++); + } while (s<p); + return sbpush(L, &sb); + +#else + + const char *s = fname; + const char *p = 0; + SB sb; + sbinit(&sb); + while (*s) { + if (s[0]=='/' && s[1] && s[1]!='/') + p = s; + s++; + } + if (!p) { + if (fname[0]=='/') + return sbsetpush(L, &sb, fname); + else + return sbsetpush(L, &sb, "."); + } + s = fname; + do { + sbadd1(&sb, *s++); + } while (s<p); + return sbpush(L, &sb); + +#endif +} + + + +/* ------------------------------------------------------ */ +/* cwd and concat */ + + +static int +lua_cwd(lua_State *L) +{ +#ifdef LUA_WIN + + char drv[2]; + int l; + SB sb; + sbinit(&sb); + drv[0] = '.'; drv[1] = 0; + l = GetFullPathNameA(drv, sb.maxlen, sb.buffer, 0); + if (l > sb.maxlen) { + sbgrow(&sb, l+1); + l = GetFullPathNameA(drv, sb.maxlen, sb.buffer, 0); + } + if (l <= 0) + return sbsetpush(L, &sb, "."); + sb.len += l; + return sbpush(L, &sb); + +#elif HAVE_GETCWD + + const char *s; + SB sb; + sbinit(&sb); + s = getcwd(sb.buffer, sb.maxlen); + while (!s && errno==ERANGE) + { + sbgrow(&sb, sb.maxlen + SBINCREMENT); + s = getcwd(sb.buffer, sb.maxlen); + } + if (! s) + return sbsetpush(L, &sb, "."); + sb.len += strlen(s); + return sbpush(L, &sb); + +#else + + const char *s; + SB sb; + sbinit(&sb); + sbgrow(&sb, PATH_MAX); + s = getwd(sb.buffer); + if (! s) + return sbsetpush(L, &sb, "."); + sb.len += strlen(s); + return sbpush(L, &sb); + +#endif +} + + + +static int +concat_fname(lua_State *L, const char *fname) +{ + const char *from = lua_tostring(L, -1); + +#ifdef LUA_WIN + + const char *s; + SB sb; + sbinit(&sb); + sbaddn(&sb, from, strlen(from)); + if (fname==0) + return sbpush(L, &sb); + /* Handle absolute part of fname */ + if (fname[0]=='/' || fname[0]=='\\') { + if (fname[1]=='/' || fname[1]=='\\') { + sb.len = 0; /* Case //abcd */ + sbaddn(&sb, "//", 2); + } else { + char drive; + if (sb.len >= 2 && sb.buffer[1]==':' /* Case "/abcd" */ + && isalpha((unsigned char)(sb.buffer[0])) ) + drive = sb.buffer[0]; + else + drive = _getdrive() + 'A' - 1; + sb.len = 0; + sbadd1(&sb, drive); + sbaddn(&sb, ":/", 2); + } + } else if (fname[0] && /* Case "x:abcd" */ + isalpha((unsigned char)(fname[0])) && fname[1]==':') { + if (fname[2]!='/' && fname[2]!='\\') { + if (sb.len < 2 || sb.buffer[1]!=':' + || !isalpha((unsigned char)(sb.buffer[0])) + || (toupper((unsigned char)sb.buffer[0]) != + toupper((unsigned char)fname[0]) ) ) + { + int l; + char drv[4]; + sb.len = 0; + drv[0]=fname[0]; drv[1]=':'; drv[2]='.'; drv[3]=0; + l = GetFullPathNameA(drv, sb.maxlen, sb.buffer, 0); + if (l > sb.maxlen) { + sbgrow(&sb, l+1); + l = GetFullPathNameA(drv, sb.maxlen, sb.buffer, 0); + } + if (l <= 0) + sbaddn(&sb, drv, 3); + else + sb.len += l; + } + fname += 2; + } else { + sb.len = 0; /* Case "x:/abcd" */ + sbadd1(&sb, toupper((unsigned char)fname[0])); + sbaddn(&sb, ":/", 2); + fname += 2; + while (*fname == '/' || *fname == '\\') + fname += 1; + } + } + /* Process path components */ + for (;;) + { + while (*fname=='/' || *fname=='\\') + fname ++; + if (*fname == 0) + return sbpush(L, &sb); + if (fname[0]=='.') { + if (fname[1]=='/' || fname[1]=='\\' || fname[1]==0) { + fname += 1; + continue; + } + if (fname[1]=='.') + if (fname[2]=='/' || fname[2]=='\\' || fname[2]==0) { + size_t l; + fname += 2; + lua_pushcfunction(L, lua_dirname); + sbpush(L, &sb); + lua_call(L, 1, 1); + s = lua_tolstring(L, -1, &l); + sbinit(&sb); + sbaddn(&sb, s, l); + lua_pop(L, 1); + continue; + } + } + if (sb.len==0 || + (sb.buffer[sb.len-1]!='/' && sb.buffer[sb.len-1]!='\\') ) + sbadd1(&sb, '/'); + while (*fname && *fname!='/' && *fname!='\\') + sbadd1(&sb, *fname++); + } + +#else + + const char *s; + SB sb; + sbinit(&sb); + + if (fname && fname[0]=='/') + sbadd1(&sb, '/'); + else + sbaddn(&sb, from, strlen(from)); + for (;;) { + while (fname && fname[0]=='/') + fname++; + if (!fname || !fname[0]) { + sbadd1(&sb, '/'); + while (sb.len > 1 && sb.buffer[sb.len-1]=='/') + sb.len --; + return sbpush(L, &sb); + } + if (fname[0]=='.') { + if (fname[1]=='/' || fname[1]==0) { + fname +=1; + continue; + } + if (fname[1]=='.') + if (fname[2]=='/' || fname[2]==0) { + fname +=2; + while (sb.len > 0 && sb.buffer[sb.len-1]=='/') + sb.len --; + while (sb.len > 0 && sb.buffer[sb.len-1]!='/') + sb.len --; + continue; + } + } + if (sb.len == 0 || sb.buffer[sb.len-1] != '/') + sbadd1(&sb, '/'); + while (*fname!=0 && *fname!='/') + sbadd1(&sb, *fname++); + } + + +#endif + +} + + +static int +lua_concatfname(lua_State *L) +{ + int i; + int narg = lua_gettop(L); + lua_cwd(L); + for (i=1; i<=narg; i++) + { + concat_fname(L, luaL_checkstring(L, i)); + lua_remove(L, -2); + } + return 1; +} + + + +/* ------------------------------------------------------ */ +/* execdir */ + + +static int +lua_execdir(lua_State *L) +{ + const char *s = 0; +#if HAVE_LUA_EXECUTABLE_DIR + s = lua_executable_dir(0); +#endif + if (s && s[0]) + lua_pushstring(L, s); + else + lua_pushnil(L); + return 1; +} + + + +/* ------------------------------------------------------ */ +/* file lists */ + + +static int +lua_dir(lua_State *L) +{ + int k = 0; + const char *s = luaL_checkstring(L, 1); + +#ifdef LUA_WIN + + SB sb; + struct _finddata_t info; + long hfind; + /* special cases */ + lua_createtable(L, 0, 0); + if ((s[0]=='/' || s[0]=='\\') && + (s[1]=='/' || s[1]=='\\') && !s[2]) + { + int drive; + hfind = GetLogicalDrives(); + for (drive='A'; drive<='Z'; drive++) + if (hfind & (1<<(drive-'A'))) { + lua_pushfstring(L, "%c:/", drive); + lua_rawseti(L, -2, ++k); + } + } + else if (dirp(L)) { + lua_pushliteral(L, ".."); + lua_rawseti(L, -2, ++k); + } else { + lua_pushnil(L); + return 1; + } + /* files */ + sbinit(&sb); + sbaddn(&sb, s, strlen(s)); + if (sb.len>0 && sb.buffer[sb.len-1]!='/' && sb.buffer[sb.len-1]!='\\') + sbadd1(&sb, '/'); + sbaddn(&sb, "*.*", 3); + sbadd1(&sb, 0); + hfind = _findfirst(sb.buffer, &info); + if (hfind != -1) { + do { + if (strcmp(".",info.name) && strcmp("..",info.name)) { + lua_pushstring(L, info.name); + lua_rawseti(L, -2, ++k); + } + } while ( _findnext(hfind, &info) != -1 ); + _findclose(hfind); + } + sbfree(&sb); + +#else + + DIR *dirp; + struct dirent *d; + dirp = opendir(s); + if (dirp) { + lua_createtable(L, 0, 0); + while ((d = readdir(dirp))) { + int n = NAMLEN(d); + lua_pushlstring(L, d->d_name, n); + lua_rawseti(L, -2, ++k); + } + closedir(dirp); + } else + lua_pushnil(L); + +#endif + + return 1; +} + + + +/* ------------------------------------------------------ */ +/* require (with global flag) */ + +#ifdef LUA_DL_DLOPEN +# define NEED_PATH_REQUIRE 1 +# include <dlfcn.h> +# ifndef RTLD_LAZY +# define RTLD_LAZY 1 +# endif +# ifndef RTLD_GLOBAL +# define RTLD_GLOBAL 0 +# endif +# define LL_LOAD(h,fname) h=dlopen(fname,RTLD_LAZY|RTLD_GLOBAL) +# define LL_SYM(h,sym) dlsym(h, sym) +#endif + +#ifdef LUA_DL_DLL +# define NEED_PATH_REQUIRE 1 +# include <windows.h> +# define LL_LOAD(h,fname) h=(void*)LoadLibraryA(fname) +# define LL_SYM(h,sym) GetProcAddress((HINSTANCE)h,sym) +#endif + +#if NEED_PATH_REQUIRE + +// {{{ functions copied or derived 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; +} + +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; +} + +static const char *pushfilename (lua_State *L, const char *name) +{ + const char *path; + const char *filename; + lua_getfield(L, LUA_GLOBALSINDEX, "package"); + lua_getfield(L, -1, "cpath"); + lua_remove(L, -2); + if (! (path = lua_tostring(L, -1))) + luaL_error(L, LUA_QL("package.cpath") " must be a string"); + lua_pushliteral(L, ""); + while ((path = pushnexttemplate(L, path))) { + filename = luaL_gsub(L, lua_tostring(L, -1), "?", name); + lua_remove(L, -2); + if (readable(filename)) + { // stack: cpath errmsg filename + lua_remove(L, -3); + lua_remove(L, -2); + return lua_tostring(L, -1); + } + lua_pushfstring(L, "\n\tno file " LUA_QS, filename); + lua_remove(L, -2); /* remove file name */ + lua_concat(L, 2); /* add entry to possible error message */ + } + lua_pushfstring(L, "module " LUA_QS " not found", name); + lua_replace(L, -3); + lua_concat(L, 2); + lua_error(L); + return 0; +} + +// functions copied or derived from loadlib.c }}} + +static int +path_require(lua_State *L) +{ + const char *filename; + lua_CFunction func; + void *handle; + const char *name = luaL_checkstring(L, 1); + lua_settop(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); // index 2 + lua_getfield(L, 2, name); + if (lua_toboolean(L, -1)) + return 1; + filename = pushfilename(L, name); // index 3 + LL_LOAD(handle, filename); + if (! handle) + luaL_error(L, "cannot load " LUA_QS, filename); + lua_pushfstring(L, "luaopen_%s", name); // index 4 + func = (lua_CFunction)LL_SYM(handle, lua_tostring(L, -1)); + if (! func) + luaL_error(L, "no symbol " LUA_QS " in module " LUA_QS, + lua_tostring(L, -1), filename); + lua_pushboolean(L, 1); + lua_setfield(L, 2, name); + lua_pushcfunction(L, func); + lua_pushstring(L, name); + lua_call(L, 1, 1); + if (! lua_isnil(L, -1)) + lua_setfield(L, 2, name); + lua_getfield(L, 2, name); + return 1; +} + +#else + +// fallback to calling require + +static int +path_require(lua_State *L) +{ + int narg = lua_gettop(L); + lua_getfield(L, LUA_GLOBALSINDEX, "require"); + lua_insert(L, 1); + lua_call(L, narg, 1); + return 1; +} + +#endif + + +/* ------------------------------------------------------ */ +/* register */ + + +static const struct luaL_Reg paths__ [] = { + {"filep", lua_filep}, + {"dirp", lua_dirp}, + {"basename", lua_basename}, + {"dirname", lua_dirname}, + {"cwd", lua_cwd}, + {"concat", lua_concatfname}, + {"execdir", lua_execdir}, + {"dir", lua_dir}, + {"require", path_require}, + {NULL, NULL} +}; + + +PATHS_API int +luaopen_libpaths(lua_State *L) +{ + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setfield(L, LUA_GLOBALSINDEX, "paths"); + luaL_register(L, NULL, paths__); + return 1; +} diff --git a/paths.h.in b/paths.h.in new file mode 100644 index 0000000..935160f --- /dev/null +++ b/paths.h.in @@ -0,0 +1,84 @@ +/* -*- C -*- */ + +#include "lua.h" +#include "lauxlib.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#ifdef LUA_BUILD_AS_DLL +# ifdef paths_EXPORTS +# define PATHS_API __declspec(dllexport) +# else +# define PATHS_API __declspec(dllimport) +# endif +#else +# define PATHS_API /**/ +#endif + + +#ifdef LUA_WIN + +# include <errno.h> +# include <windows.h> +# include <direct.h> +# include <io.h> +# include <time.h> +# include <process.h> +# include <fcntl.h> +# include <sys/types.h> +# include <sys/stat.h> + +#else + +#cmakedefine HAVE_DIRENT_H 1 +#cmakedefine HAVE_FCNTL_H 1 +#cmakedefine HAVE_UNISTD_H 1 +#cmakedefine HAVE_TIME_H 1 +#cmakedefine HAVE_SYS_TIME_H 1 +#cmakedefine HAVE_SYS_NDIR_H 1 +#cmakedefine HAVE_SYS_DIR_H 1 +#cmakedefine HAVE_NDIR_H 1 +#cmakedefine HAVE_GETCWD 1 + +# include <errno.h> +# include <sys/types.h> +# include <sys/stat.h> +# if HAVE_FCNTL_H +# include <fcntl.h> +# endif +# if HAVE_UNISTD_H +# include <unistd.h> +# endif +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# endif +# if HAVE_TIME_H +# include <time.h> +# endif +# ifdef HAVE_UNISTD_H +# include <unistd.h> +# endif +# ifdef HAVE_DIRENT_H +# include <dirent.h> +# define NAMLEN(dirent) strlen((dirent)->d_name) +# else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include <sys/ndir.h> +# endif +# if HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# if HAVE_NDIR_H +# include <ndir.h> +# endif +# endif + +#endif + + + |