= fname) {
if (*p == '.') {
lua_pushstring(L, p + 1);
return 1;
}
p--;
}
return 0;
}
/* ------------------------------------------------------ */
/* cwd and concat */
static int
lua_cwd(lua_State *L)
{
#ifdef _WIN32
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 _WIN32
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
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 _WIN32
SB sb;
struct _finddata_t info;
intptr_t 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 & ((intptr_t)1<<(drive-'A'))) {
lua_pushfstring(L, "%c:/", drive);
lua_rawseti(L, -2, ++k);
}
}
else if (dirp(L, 1)) {
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;
}
/* ------------------------------------------------------ */
/* tmpname */
static const char *tmpnames_key = "tmpname_sentinel";
struct tmpname_s {
struct tmpname_s *next;
char tmp[4];
};
static int
gc_tmpname(lua_State *L)
{
if (lua_isuserdata(L, -1))
{
struct tmpname_s **pp = (struct tmpname_s **)lua_touserdata(L, -1);
while (pp && *pp)
{
struct tmpname_s *p = *pp;
*pp = p->next;
remove(p->tmp);
free(p);
}
}
return 0;
}
static void
add_tmpname(lua_State *L, const char *tmp)
{
struct tmpname_s **pp = 0;
lua_pushlightuserdata(L, (void*)tmpnames_key);
lua_rawget(L, LUA_REGISTRYINDEX);
if (lua_isuserdata(L, -1))
{
pp = (struct tmpname_s **)lua_touserdata(L, -1);
lua_pop(L, 1);
}
else
{
lua_pop(L, 1);
/* create sentinel */
lua_pushlightuserdata(L, (void*)tmpnames_key);
pp = (struct tmpname_s **)lua_newuserdata(L, sizeof(void*));
pp[0] = 0;
lua_createtable(L, 0, 1);
lua_pushcfunction(L, gc_tmpname);
lua_setfield(L,-2,"__gc");
lua_setmetatable(L, -2);
lua_rawset(L, LUA_REGISTRYINDEX);
}
while (pp && *pp)
{
struct tmpname_s *p = *pp;
if (!strcmp(p->tmp, tmp)) return;
pp = &(p->next);
}
if (pp)
{
int len = strlen(tmp);
struct tmpname_s *t = (struct tmpname_s*)malloc(len + sizeof(struct tmpname_s));
if (t)
{
t->next = 0;
memcpy(t->tmp, tmp, len);
t->tmp[len] = 0;
*pp = t;
}
}
}
static int
lua_tmpname(lua_State *L)
{
#ifdef _WIN32
char *tmp = _tempnam("c:/temp", "luatmp");
#else
char *tmp = tempnam(NULL, "luatmp");
#endif
if (tmp)
{
lua_pushstring(L, tmp);
add_tmpname(L, tmp);
free(tmp);
return 1;
}
else
{
lua_pushnil(L);
return 1;
}
}
/* ------------------------------------------------------ */
/* mkdir, rmdir */
static int
pushresult (lua_State *L, int i, const char *filename) {
int en = errno;
if (i) {
lua_pushboolean(L, 1);
return 1;
}
else {
lua_pushnil(L);
lua_pushfstring(L, "%s: %s", filename, strerror(en));
lua_pushinteger(L, en);
return 3;
}
}
static int
lua_mkdir(lua_State *L)
{
int status = 0;
const char *s = luaL_checkstring(L, 1);
lua_pushcfunction(L, lua_mkdir);
lua_pushcfunction(L, lua_dirname);
lua_pushvalue(L, 1);
lua_call(L, 1, 1);
if (! dirp(L, -1))
lua_call(L, 1, 3);
#ifdef _WIN32
status = _mkdir(s);
#else
status = mkdir(s, 0777);
#endif
return pushresult(L, status == 0, s);
}
static int
lua_rmdir(lua_State *L)
{
const char *s = luaL_checkstring(L, 1);
#ifdef _WIN32
int status = _rmdir(s);
#else
int status = rmdir(s);
#endif
return pushresult(L, status == 0, s);
}
/* ------------------------------------------------------ */
/* uname */
static int
lua_uname(lua_State *L)
{
#if defined(_WIN32)
const char *name;
SYSTEM_INFO info;
lua_pushliteral(L, "Windows");
name = getenv("COMPUTERNAME");
lua_pushstring(L, name ? name : "");
memset(&info, 0, sizeof(info));
GetSystemInfo(&info);
if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
lua_pushliteral(L, "AMD64");
else if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
lua_pushliteral(L, "X86");
else if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM)
lua_pushliteral(L, "ARM");
else if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
lua_pushliteral(L, "IA64");
else if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
lua_pushstring(L, "");
return 3;
#else
# if defined(HAVE_SYS_UTSNAME_H)
struct utsname info;
if (uname(&info) >= 0)
{
lua_pushstring(L, info.sysname);
lua_pushstring(L, info.nodename);
lua_pushstring(L, info.machine);
return 3;
}
# endif
lua_pushstring(L, "Unknown");
return 1;
#endif
}
static int
lua_getregistryvalue(lua_State *L)
{
#ifdef _WIN32
static char *keynames[] = {
"HKEY_CLASSES_ROOT",
"HKEY_CURRENT_CONFIG",
"HKEY_CURRENT_USER",
"HKEY_LOCAL_MACHINE",
"HKEY_USERS",
NULL };
static HKEY keys[] = {
HKEY_CLASSES_ROOT,
HKEY_CURRENT_CONFIG,
HKEY_CURRENT_USER,
HKEY_LOCAL_MACHINE,
HKEY_USERS
};
HKEY rkey = keys[ luaL_checkoption(L, 1, NULL, keynames) ];
const char *subkey = luaL_checkstring(L, 2);
const char *value = luaL_checkstring(L, 3);
HKEY skey;
DWORD type;
DWORD len = 0;
char *data = NULL;
LONG res;
res = RegOpenKeyExA(rkey, subkey, 0, KEY_READ, &skey);
if (res != ERROR_SUCCESS)
{
lua_pushnil(L);
lua_pushinteger(L, res);
if (res == ERROR_FILE_NOT_FOUND)
lua_pushstring(L, "subkey not found");
if (res == ERROR_ACCESS_DENIED)
lua_pushstring(L, "subkey access denied");
else
return 2;
return 3;
}
res = RegQueryValueExA(skey, value, NULL, &type, (LPBYTE)data, &len);
if (len > 0)
{
len += 8;
data = (char*)malloc(len);
if (! data)
luaL_error(L, "out of memory");
res = RegQueryValueExA(skey, value, NULL, &type, (LPBYTE)data, &len);
}
RegCloseKey(skey);
if (res != ERROR_SUCCESS)
{
if (data)
free(data);
lua_pushnil(L);
lua_pushinteger(L, res);
if (res == ERROR_FILE_NOT_FOUND)
lua_pushstring(L, "value not found");
if (res == ERROR_ACCESS_DENIED)
lua_pushstring(L, "value access denied");
else
return 2;
return 3;
}
switch(type)
{
case REG_DWORD:
lua_pushinteger(L, (lua_Integer)*(const DWORD*)data);
if (data)
free(data);
return 1;
case REG_EXPAND_SZ:
if (data && len > 0)
{
if ((len = ExpandEnvironmentStrings(data, NULL, 0)) > 0)
{
char *buf = (char*)malloc(len + 8);
if (!buf)
luaL_error(L, "out of memory");
len = ExpandEnvironmentStrings(data, buf, len+8);
free(data);
data = buf;
}
}
/* fall thru */
case REG_SZ:
if (data && len > 0)
if (((const char*)data)[len-1] == 0)
len -= 1;
/* fall thru */
case REG_BINARY:
if (data && len > 0)
lua_pushlstring(L, (const char*)data, (int)len);
else
lua_pushliteral(L, "");
if (data)
free(data);
return 1;
/* unimplemented */
case REG_QWORD:
case REG_MULTI_SZ:
default:
lua_pushnil(L);
lua_pushinteger(L, res);
lua_pushfstring(L, "getting registry type %d not implemented", type);
return 3;
}
#else
luaL_error(L, "This function exists only on windows");
return 0;
#endif
}
/* ------------------------------------------------------ */
/* require (with global flag) */
#ifdef HAVE_DLOPEN
# define NEED_PATH_REQUIRE 1
# include