static char * catpath(const char *from, const char *fname) { SB sb; sbinit(&sb); if (fname && fname[0]=='/') sbadd1(&sb, '/'); else if (from) sbaddsf(&sb, catpath(NULL,from)); else { char *cwd = 0; while (sb.buffer && !cwd) { cwd = getcwd(sb.buffer + sb.len, sb.maxlen - sb.len); if (cwd || errno != ERANGE) break; sbgrow(&sb, sb.maxlen - sb.len + SBINCREMENT); } if (cwd) sb.len += strlen(cwd); else sbfree(&sb); } for (;;) { while (fname && fname[0]=='/') fname++; if (!fname || !fname[0]) { while (&sb.buffer && sb.len>0 && sb.buffer[sb.len-1]=='/') sb.len -= 1; sbadd1(&sb, 0); return sb.buffer; } 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.buffer && sb.len>0 && sb.buffer[sb.len-1]=='/') sb.len -= 1; while (sb.buffer && sb.len>0 && sb.buffer[sb.len-1]!='/') sb.len -= 1; continue; } } if (sb.len==0 || (sb.buffer && sb.buffer[sb.len-1]!='/')) sbadd1(&sb, '/'); while (*fname!=0 && *fname!='/') sbadd1(&sb, *fname++); } sbadd1(&sb, 0); return sb.buffer; }
static const char * executable_dir(const char *progname) { SB sb; struct stat sbuf; if (! progname) return 0; sbinit(&sb); if (progname[0]=='/') sbaddn(&sb, progname, strlen(progname)); else if (strchr(progname,'/')) sbaddsf(&sb,catpath(NULL,progname)); else { char *p = getenv("PATH"); for (;;) { sb.len = 0; if (! (p && *p)) return sbfree(&sb); while (*p && *p!=':') sbadd1(&sb, *p++); if (*p ==':') p++; sbadd1(&sb, 0); sb.len = 0; sbaddsf(&sb, catpath(sb.buffer, progname)); sbadd1(&sb, 0); if (sb.buffer && stat(sb.buffer,&sbuf)>=0 && S_ISREG(sbuf.st_mode)) if (access(sb.buffer, X_OK) >= 0) break; } } #ifdef S_ISLNK sbadd1(&sb, 0); while(sb.buffer && lstat(sb.buffer,&sbuf)>=0 && S_ISLNK(sbuf.st_mode)) { int h,l; sbaddn(&sb,"../",3); h = sb.len; while ((l=readlink(sb.buffer,sb.buffer+h,sb.maxlen-h))>=sb.maxlen-h) sbgrow(&sb, sb.maxlen - h + SBINCREMENT); if (l < 0) return sbfree(&sb); sb.len = h + l; sbadd1(&sb,0); sb.len = 0; sbaddsf(&sb, catpath(sb.buffer,sb.buffer+h-3)); sbadd1(&sb,0); } #endif while (sb.buffer && sb.len>0 && sb.buffer[sb.len-1]=='/') sb.len -= 1; while (sb.buffer && sb.len>0 && sb.buffer[sb.len-1]!='/') sb.len -= 1; while (sb.buffer && sb.len>0 && sb.buffer[sb.len-1]=='/') sb.len -= 1; sbadd1(&sb, 0); return sb.buffer; }
static const char * relocate_path(const char *dir, const char *s) { SB sb; const char *r; const char *execdir = LUA_EXECDIR; int lexecdir = strlen(execdir); int ldir = strlen(dir); sbinit(&sb); while ((r = strstr(s, execdir))) { sbaddn(&sb, s, r-s); sbaddn(&sb, dir, ldir); s = r + lexecdir; while (is_slash(s[0])) { if (is_dot(s[1]) && is_slash(s[2])) { s += 2; continue; } if (is_dot(s[1]) && is_dot(s[2]) && is_slash(s[3]) ) { s += 3; while (sb.buffer && sb.len>0 && is_slash(sb.buffer[sb.len-1])) sb.len -= 1; while (sb.buffer && sb.len>0 && !is_slash(sb.buffer[sb.len-1])) sb.len -= 1; while (sb.buffer && sb.len>0 && is_slash(sb.buffer[sb.len-1])) sb.len -= 1; continue; } break; } } sbaddn(&sb, s, strlen(s)); sbadd1(&sb, 0); #ifdef LUA_WIN r = _strdup(sb.buffer); #else r = strdup(sb.buffer); #endif sbfree(&sb); return r; }
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; 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, 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; }
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_dirname(lua_State *L) { const char *fname = luaL_checkstring(L, 1); #ifdef _WIN32 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 }
static int lua_basename(lua_State *L) { const char *fname = luaL_checkstring(L, 1); const char *suffix = luaL_optstring(L, 2, 0); #ifdef _WIN32 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 }