mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-22 21:32:31 +00:00
Make improvements
- Introduce path module to redbean - Fix glitch with linenoise printing extra line on eof - Introduce closefrom() and close_range() system calls - Make file descriptor closing more secure in pledge.com
This commit is contained in:
parent
439ad21b12
commit
1837dc2e85
31 changed files with 806 additions and 75 deletions
166
tool/net/lpath.c
Normal file
166
tool/net/lpath.c
Normal file
|
@ -0,0 +1,166 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "third_party/lua/lauxlib.h"
|
||||
|
||||
/**
|
||||
* @fileoverview redbean unix path manipulation module
|
||||
*/
|
||||
|
||||
// path.basename(str)
|
||||
// └─→ str
|
||||
static int LuaPathBasename(lua_State *L) {
|
||||
size_t i, n;
|
||||
const char *p;
|
||||
if ((p = luaL_optlstring(L, 1, 0, &n)) && n) {
|
||||
while (n > 1 && p[n - 1] == '/') --n;
|
||||
i = n - 1;
|
||||
while (i && p[i - 1] != '/') --i;
|
||||
lua_pushlstring(L, p + i, n - i);
|
||||
} else {
|
||||
lua_pushlstring(L, ".", 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// path.dirname(str)
|
||||
// └─→ str
|
||||
static int LuaPathDirname(lua_State *L) {
|
||||
size_t n;
|
||||
const char *p;
|
||||
if ((p = luaL_optlstring(L, 1, 0, &n)) && n--) {
|
||||
for (; p[n] == '/'; n--) {
|
||||
if (!n) goto ReturnSlash;
|
||||
}
|
||||
for (; p[n] != '/'; n--) {
|
||||
if (!n) goto ReturnDot;
|
||||
}
|
||||
for (; p[n] == '/'; n--) {
|
||||
if (!n) goto ReturnSlash;
|
||||
}
|
||||
lua_pushlstring(L, p, n + 1);
|
||||
return 1;
|
||||
}
|
||||
ReturnDot:
|
||||
lua_pushlstring(L, ".", 1);
|
||||
return 1;
|
||||
ReturnSlash:
|
||||
lua_pushlstring(L, "/", 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// path.join(str, ...)
|
||||
// └─→ str
|
||||
static int LuaPathJoin(lua_State *L) {
|
||||
int i, n;
|
||||
size_t z;
|
||||
bool gotstr;
|
||||
const char *c;
|
||||
luaL_Buffer b;
|
||||
bool needslash;
|
||||
if ((n = lua_gettop(L))) {
|
||||
luaL_buffinit(L, &b);
|
||||
gotstr = false;
|
||||
needslash = false;
|
||||
for (i = 1; i <= n; ++i) {
|
||||
if (lua_isnoneornil(L, i)) continue;
|
||||
gotstr = true;
|
||||
c = luaL_checklstring(L, i, &z);
|
||||
if (z) {
|
||||
if (c[0] == '/') {
|
||||
luaL_buffsub(&b, luaL_bufflen(&b));
|
||||
} else if (needslash) {
|
||||
luaL_addchar(&b, '/');
|
||||
}
|
||||
luaL_addlstring(&b, c, z);
|
||||
needslash = c[z - 1] != '/';
|
||||
} else if (needslash) {
|
||||
luaL_addchar(&b, '/');
|
||||
needslash = false;
|
||||
}
|
||||
}
|
||||
if (gotstr) {
|
||||
luaL_pushresult(&b);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
luaL_error(L, "missing argument");
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
static int CheckPath(lua_State *L, int type, int flags) {
|
||||
int olderr;
|
||||
struct stat st;
|
||||
const char *path;
|
||||
path = luaL_checkstring(L, 1);
|
||||
olderr = errno;
|
||||
if (fstatat(AT_FDCWD, path, &st, flags) != -1) {
|
||||
lua_pushboolean(L, !type || (st.st_mode & S_IFMT) == type);
|
||||
} else {
|
||||
errno = olderr;
|
||||
lua_pushboolean(L, false);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// path.exists(str)
|
||||
// └─→ bool
|
||||
static int LuaPathExists(lua_State *L) {
|
||||
return CheckPath(L, 0, 0);
|
||||
}
|
||||
|
||||
// path.isfile(str)
|
||||
// └─→ bool
|
||||
static int LuaPathIsfile(lua_State *L) {
|
||||
return CheckPath(L, S_IFREG, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
|
||||
// path.islink(str)
|
||||
// └─→ bool
|
||||
static int LuaPathIslink(lua_State *L) {
|
||||
return CheckPath(L, S_IFLNK, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
|
||||
// path.isdir(str)
|
||||
// └─→ bool
|
||||
static int LuaPathIsdir(lua_State *L) {
|
||||
return CheckPath(L, S_IFDIR, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
|
||||
static const luaL_Reg kLuaPath[] = {
|
||||
{"basename", LuaPathBasename}, //
|
||||
{"dirname", LuaPathDirname}, //
|
||||
{"exists", LuaPathExists}, //
|
||||
{"isdir", LuaPathIsdir}, //
|
||||
{"isfile", LuaPathIsfile}, //
|
||||
{"islink", LuaPathIslink}, //
|
||||
{"join", LuaPathJoin}, //
|
||||
{0}, //
|
||||
};
|
||||
|
||||
int LuaPath(lua_State *L) {
|
||||
luaL_newlib(L, kLuaPath);
|
||||
return 1;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue