From 346a78ddc09c65d2f244b1c5b0cecf378c48cbde Mon Sep 17 00:00:00 2001 From: Gavin Hayes Date: Tue, 16 Apr 2024 04:47:54 -0400 Subject: [PATCH] add __paginate_file --- libc/runtime/runtime.h | 1 + libc/x/paginate.c | 86 +++++++++++++++++++++++++++++++----------- 2 files changed, 64 insertions(+), 23 deletions(-) diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index db0dfb253..76fb46983 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -103,6 +103,7 @@ int verynice(void); void __warn_if_powersave(void); void _Exit1(int) libcesque wontreturn; void __paginate(int, const char *); +void __paginate_file(int, const char *); /* memory management */ void _weakfree(void *); void *_mapanon(size_t) attributeallocsize((1)) mallocesque; diff --git a/libc/x/paginate.c b/libc/x/paginate.c index 20b6e04ad..73bc8065b 100644 --- a/libc/x/paginate.c +++ b/libc/x/paginate.c @@ -24,46 +24,86 @@ #include "libc/mem/gc.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" +#include "libc/sysv/consts/o.h" #include "libc/temp.h" #include "libc/x/x.h" +static char *get_pagerpath(char *pathbuf, size_t pathbufsz) { + char *pagerpath; + if (strcmp(nulltoempty(getenv("TERM")), "dumb") && isatty(0) && isatty(1) && + ((pagerpath = commandv("less", pathbuf, pathbufsz)) || + (pagerpath = commandv("more", pathbuf, pathbufsz)) || + (pagerpath = commandv("more.exe", pathbuf, pathbufsz)) || + (pagerpath = commandv("more.com", pathbuf, pathbufsz)))) { + return pagerpath; + } + return 0; +} + +static bool run_pager(char *args[hasatleast 3]) { + char16_t widepath[PATH_MAX]; + int n, pid; + if (IsWindows() && !strcasecmp(args[0], "/C/Windows/System32/more.com") && + (((n = __mkntpath(args[1], widepath)) == -1) || + !(args[1] = gc(utf16to8(widepath, n, 0))))) { + return false; + } + if ((pid = fork()) != -1) { + putenv("LC_ALL=C.UTF-8"); + putenv("LESSCHARSET=utf-8"); + putenv("LESS=-RS"); + if (!pid) { + execv(args[0], args); + _Exit(127); + } + waitpid(pid, 0, 0); + return true; + } + return false; +} + /** * Displays wall of text in terminal with pagination. */ void __paginate(int fd, const char *s) { - int tfd, pid; + int tfd; char *args[3] = {0}; char tmppath[] = "/tmp/paginate.XXXXXX"; char progpath[PATH_MAX]; - char16_t widepath[PATH_MAX]; - int n; - if (strcmp(nulltoempty(getenv("TERM")), "dumb") && isatty(0) && isatty(1) && - ((args[0] = commandv("less", progpath, sizeof(progpath))) || - (args[0] = commandv("more", progpath, sizeof(progpath))) || - (args[0] = commandv("more.exe", progpath, sizeof(progpath))) || - (args[0] = commandv("more.com", progpath, sizeof(progpath))))) { + if ((args[0] = get_pagerpath(progpath, sizeof(progpath)))) { if ((tfd = mkstemp(tmppath)) != -1) { + // defer((void*)unlink, tmppath); write(tfd, s, strlen(s)); close(tfd); args[1] = tmppath; - if (!IsWindows() || strcasecmp(args[0], "/C/Windows/System32/more.com") || - (((n = __mkntpath(tmppath, widepath)) != -1) && - (args[1] = gc(utf16to8(widepath, n, 0))))) { - if ((pid = fork()) != -1) { - putenv("LC_ALL=C.UTF-8"); - putenv("LESSCHARSET=utf-8"); - putenv("LESS=-RS"); - if (!pid) { - execv(args[0], args); - _Exit(127); - } - waitpid(pid, 0, 0); - unlink(tmppath); - return; - } + if (run_pager(args)) { + unlink(tmppath); + return; } unlink(tmppath); } } write(fd, s, strlen(s)); } + +/** + * Displays a file in terminal with pagination + */ +void __paginate_file(int fd, const char *path) { + char *args[3] = {0}; + char progpath[PATH_MAX]; + if ((args[0] = get_pagerpath(progpath, sizeof(progpath)))) { + args[1] = (char *)path; + if (run_pager(args)) { + return; + } + } + int sfd = open(path, O_RDONLY); + if (sfd != -1) { + ssize_t n; + while ((n = read(sfd, progpath, sizeof(progpath)) > 0)) { + write(fd, progpath, n); + } + } + close(sfd); +}