commit 6cf9c0e99e3f9f2eb3987ec2732f630b55ec680f
parent a7b8ab1c3a951cec9c8ccd2f4db3ec6ef4071ddb
Author: Louis Burda <quent.burda@gmail.com>
Date: Mon, 29 May 2023 13:07:23 +0200
Remove libdvec dependency and simplify
Diffstat:
9 files changed, 209 insertions(+), 235 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -2,3 +2,4 @@ tquery
.cache
compile_commands.json
.gdb_history
+build.jst
diff --git a/.gitmodules b/.gitmodules
@@ -1,6 +0,0 @@
-[submodule "lib/liballoc"]
- path = lib/liballoc
- url = git@sinitax.com:sinitax/liballoc
-[submodule "lib/libdvec"]
- path = lib/libdvec
- url = git@sinitax.com:sinitax/libdvec
diff --git a/Makefile b/Makefile
@@ -1,8 +1,9 @@
PREFIX ?= /usr/local
BINDIR ?= /bin
-LDLIBS = -lcurses -I lib/libdvec/include -I lib/liballoc/include
-CFLAGS = -std=c99 -Wunused-function -Wunused-variable -Wconversion
+CFLAGS = -std=c99 -D_XOPEN_SOURCE=700 -Og -g \
+ -Wunused-function -Wunused-variable -Wconversion -Wsign-compare
+LDLIBS = -lcurses
all: tquery
@@ -10,16 +11,8 @@ clean:
rm -f tquery
cleanall: clean
- make -C lib/liballoc cleanall
- make -C lib/libdvec cleanall
-lib/libdvec/build/libdvec.a:
- make -C lib/libdvec build/libdvec.a
-
-lib/liballoc/build/liballoc.a:
- make -C lib/liballoc build/liballoc.a
-
-tquery: tquery.c lib/libdvec/build/libdvec.a lib/liballoc/build/liballoc.a
+tquery: tquery.c
install:
install -m755 tquery -t "$(DESTDIR)$(PREFIX)$(BINDIR)"
@@ -27,4 +20,4 @@ install:
uninstall:
rm -f "$(DESTDIR)$(PREFIX)$(BINDIR)/tquery"
-.PHONY: all clean install uninstall
+.PHONY: all clean cleanall install uninstall
diff --git a/build.jst b/build.jst
@@ -1,29 +0,0 @@
-cc = clang
-
-ldlibs = -lcurses -I lib/libdvec/include -I lib/liballoc/include
-cflags = -std=c99 -Wunused-function -Wunused-variable -Wconversion
-
-rule cc
- $cc -o $out $in $cflags $ldlibs
-
-target lib/liballoc/build/liballoc.a
- just lib/liballoc
-
-target lib/libdvec/build/libdvec.a
- just lib/libdvec
-
-target tquery
- cc tquery.c lib/liballoc/build/liballoc.a
- lib/libdvec/build/libdvec.a
-
-command clean
- rm -rf build
-
-command cleanall
- just clean
- just -C lib/liballoc cleanall
- just -C lib/libdvec cleanall
-
-command all
- just tquery
-
diff --git a/build.jst.tmpl b/build.jst.tmpl
@@ -0,0 +1,34 @@
+#default PREFIX /usr/local
+#default BINDIR /bin
+#default CC gcc
+
+#ifdef DEBUG
+#define OPT_CFLAGS -Og -g
+#else
+#define OPT_CFLAGS -O2
+#endif
+
+cflags = -std=c99 -D_XOPEN_SOURCE=700 #{OPT_CFLAGS} #{EXTRA_CFLAGS}
+ -Wunused-function -Wunused-variable -Wconversion -Wsign-compare
+ldlibs = -lcurses
+
+rule cc
+ #{CC} -o $out $in $cflags $ldlibs
+
+target tquery
+ cc tquery.c
+
+command clean
+ rm -rf build
+
+command cleanall
+ just clean
+
+command install
+ install -m755 tquery -t "#{DESTDIR}#{PREFIX}#{BINDIR}"
+
+command uninstall
+ rm -f "#{DESTDIR}#{PREFIX}#{BINDIR}/tquery"
+
+command all
+ just tquery
diff --git a/configure b/configure
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+tmpl "$@" build.jst.tmpl > build.jst
diff --git a/lib/liballoc b/lib/liballoc
@@ -1 +0,0 @@
-Subproject commit db114713e3958e350da181c8894ccf330320f66b
diff --git a/lib/libdvec b/lib/libdvec
@@ -1 +0,0 @@
-Subproject commit 83df399924762dd234c2b34f14e296bd3590c147
diff --git a/tquery.c b/tquery.c
@@ -1,104 +1,102 @@
-#define _XOPEN_SOURCE 700
-
-#include "allocator.h"
-#include "dvec.h"
-
#include <curses.h>
-#include <linux/limits.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <limits.h>
-#include <fcntl.h>
+#include <signal.h>
#include <dirent.h>
#include <unistd.h>
-#include <termios.h>
-#include <signal.h>
#include <errno.h>
-#include <assert.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#define CTRL(x) ((x) & 0x1f)
+
#define MIN(a, b) ((a) > (b) ? (b) : (a))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
-struct listnav {
+struct nav {
int wmin, wmax, wlen;
- int sel;
- int min, max;
+ int sel, min, max;
};
-static const struct allocator *ga = &stdlib_strict_heap_allocator;
+static int child_fd = -1;
+static pid_t child_pid = 0;
-static int locate_out_fd = -1;
-static pid_t locate_pid = 0;
+static char *output = NULL;
+static size_t output_len = 0;
+static size_t output_cap = 0;
-static struct dvec locate_output;
-static struct dvec locate_delims;
+static size_t *delims = NULL;
+static size_t delims_len = 0;
+static size_t delims_cap = 0;
-static struct listnav locate_nav;
+static struct nav output_nav;
static char inputbuf[2048] = { 0 };
static size_t inputlen = 0;
-static char errbuf[1024] = { 0 };
-static int errtimer = 0;
-
-static bool separate_args = false;
-static bool single_out = false;
-static bool debug = false;
+static bool separate = false;
+static bool oneshot = false;
+static bool openerr = false;
static char delim = '\n';
-static const char **cmd_argv = NULL;
+static const char **child_argv = NULL;
static void
-sigint(int sig)
-{
- if (locate_pid > 0) {
- kill(locate_pid, SIGKILL);
- waitpid(locate_pid, NULL, 0);
- locate_pid = 0;
- signal(SIGINT, sigint);
- } else {
- exit(0);
- }
-}
-
-static void __attribute__((noreturn))
-err(const char *fmt, ...)
+die(const char *fmt, ...)
{
va_list ap;
- endwin();
+ /* stdout because of swapped fds */
+
+ fputs("tquery: ", stdout);
va_start(ap, fmt);
- printf("tquery: ");
- vprintf(fmt, ap);
- printf(": %s\n", strerror(errno));
+ vfprintf(stdout, fmt, ap);
va_end(ap);
+ if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
+ fputc(' ', stderr);
+ perror(NULL);
+ } else {
+ fputc('\n', stderr);
+ }
+
exit(1);
}
+static void
+sigint(int sig)
+{
+ if (child_pid > 0) {
+ kill(child_pid, SIGKILL);
+ waitpid(child_pid, NULL, 0);
+ child_pid = 0;
+ signal(SIGINT, sigint);
+ } else {
+ exit(0);
+ }
+}
+
void
swapfd(int fd1, int fd2)
{
int fd, rc;
fd = dup(fd1);
- if (fd < 0) err("dup");
+ if (fd < 0) die("dup:");
rc = dup2(fd2, fd1);
- if (rc == -1) err("dup2");
+ if (rc == -1) die("dup2:");
rc = dup2(fd, fd2);
- if (rc == -1) err("dup2");
+ if (rc == -1) die("dup2:");
close(fd);
}
static void
-listnav_update_win(struct listnav *nav)
+nav_update_win(struct nav *nav)
{
nav->wmin = MAX(nav->wmax - nav->wlen, nav->min);
nav->wmax = MIN(nav->wmin + nav->wlen, nav->max);
@@ -106,7 +104,7 @@ listnav_update_win(struct listnav *nav)
}
static void
-listnav_init(struct listnav *nav)
+nav_init(struct nav *nav)
{
nav->sel = 0;
nav->min = 0;
@@ -117,22 +115,22 @@ listnav_init(struct listnav *nav)
}
static void
-listnav_update_bounds(struct listnav *nav, int min, int max)
+nav_update_bounds(struct nav *nav, int min, int max)
{
nav->min = min;
nav->max = max;
- listnav_update_win(nav);
+ nav_update_win(nav);
}
static void
-listnav_update_wlen(struct listnav *nav, int wlen)
+nav_update_wlen(struct nav *nav, int wlen)
{
nav->wlen = wlen;
- listnav_update_win(nav);
+ nav_update_win(nav);
}
static void
-listnav_update_sel(struct listnav *nav, int sel)
+nav_update_sel(struct nav *nav, int sel)
{
nav->sel = MAX(MIN(sel, nav->max - 1), nav->min);
if (nav->sel >= nav->wmax) {
@@ -144,28 +142,10 @@ listnav_update_sel(struct listnav *nav, int sel)
}
}
-void
-reset(void)
-{
- dvec_clear(&locate_delims);
- dvec_clear(&locate_output);
-
- if (locate_out_fd >= 0) {
- close(locate_out_fd);
- locate_out_fd = -1;
- }
-
- if (locate_pid > 0) {
- kill(locate_pid, SIGKILL);
- waitpid(locate_pid, NULL, 0);
- locate_pid = 0;
- }
-}
-
char *
findbin(const char *name)
{
- char buf[PATH_MAX];
+ static char buf[PATH_MAX];
char *path, *tok, *ntok, *end;
struct dirent *ent;
DIR *dir;
@@ -191,7 +171,7 @@ findbin(const char *name)
return NULL;
strcat(buf, "/");
strcat(buf, name);
- return strdup(buf);
+ return buf;
}
}
@@ -204,18 +184,33 @@ findbin(const char *name)
static void
spawn(const char **prefix, const char *query)
{
- struct dvec argv;
+ static const char *argv[64];
const char **arg;
const char *tok, *ntok, *end;
int out_pipe[2];
+ size_t argc;
+
+ delims_len = 0;
+ output_len = 0;
- if (pipe(out_pipe)) err("pipe");
+ if (child_fd >= 0) {
+ close(child_fd);
+ child_fd = -1;
+ }
- locate_pid = fork();
- if (locate_pid < 0) err("fork");
- if (!locate_pid) {
+ if (child_pid > 0) {
+ kill(child_pid, SIGKILL);
+ waitpid(child_pid, NULL, 0);
+ child_pid = 0;
+ }
+
+ if (pipe(out_pipe)) die("pipe:");
+
+ child_pid = fork();
+ if (child_pid < 0) die("fork:");
+ if (!child_pid) {
close(0);
- if (debug) {
+ if (openerr) {
swapfd(1, 2);
close(1);
} else {
@@ -225,50 +220,57 @@ spawn(const char **prefix, const char *query)
dup2(out_pipe[1], 1);
close(out_pipe[0]);
- dvec_init(&argv, sizeof(char *), 0, ga);
- for (arg = prefix; *arg; arg++) {
+ argc = 0;
+ for (arg = prefix; *arg && argc < 64; arg++) {
if (!strcmp(*arg, "{}")) {
arg += 1;
break;
}
- dvec_add_back(&argv, 1);
- *(const char **)dvec_back(&argv) = *arg;
+ argv[argc++] = *arg;
}
- if (separate_args) {
+ if (separate) {
ntok = tok = query;
- while (ntok && *ntok) {
+ while (ntok && *ntok && argc < 64) {
ntok = strchr(tok, ' ');
end = ntok ? ntok : tok + strlen(tok);
- dvec_add_back(&argv, 1);
- *(const char **)dvec_back(&argv)
- = strndup(tok, (size_t) (end - tok));
+ argv[argc++] = strndup(tok, (size_t) (end - tok));
tok = ntok + 1;
}
- } else {
- dvec_add_back(&argv, 1);
- *(const char **)dvec_back(&argv) = query;
+ } else if (argc < 64) {
+ argv[argc++] = query;
}
- for (; *arg; arg++) {
- dvec_add_back(&argv, 1);
- *(const char **)dvec_back(&argv) = *arg;
+ for (; *arg && argc < 64; arg++) {
+ argv[argc++] = *arg;
}
- dvec_add_back(&argv, 1);
- *(const char **)dvec_back(&argv) = NULL;
+ if (argc < 64) argv[argc++] = NULL;
+
+ if (argv[argc-1]) die("Too many arguments");
- execv(*(const char **)dvec_front(&argv), argv.data);
- fprintf(stderr, "tquery: execv '%s': %s",
- *(const char **)dvec_front(&argv), strerror(errno));
- exit(1);
+ execv(argv[0], (char *const *) argv);
+ die("execv '%s':");
} else {
close(out_pipe[1]);
- locate_out_fd = out_pipe[0];
+ child_fd = out_pipe[0];
}
}
+static void *
+addcap(void *alloc, size_t dsize, size_t min, size_t *cap)
+{
+ if (min > *cap) {
+ *cap = *cap * 2;
+ if (*cap < min) *cap = min;
+ alloc = realloc(alloc, dsize * *cap);
+ if (!alloc) die("realloc:");
+ }
+
+ return alloc;
+}
+
static void
load(void)
{
@@ -277,41 +279,34 @@ load(void)
size_t i, len;
char *start;
- nread = read(locate_out_fd, buf, BUFSIZ);
+ nread = read(child_fd, buf, BUFSIZ);
if (nread <= 0) {
- locate_pid = 0;
- close(locate_out_fd);
- locate_out_fd = -1;
+ child_pid = 0;
+ close(child_fd);
+ child_fd = -1;
return;
}
- len = dvec_len(&locate_output);
- dvec_add_back(&locate_output, (size_t) nread);
- start = dvec_at(&locate_output, len);
- memcpy(start, buf, (size_t) nread);
+ output = addcap(output, 1, output_len + (size_t) nread, &output_cap);
+ memcpy(output + output_len, buf, (size_t) nread);
+
+ start = output + output_len;
+ output_len += (size_t) nread;
for (i = len; i < len + (size_t) nread; i++, start++) {
if (*start == delim) {
*start = '\0';
- dvec_add_back(&locate_delims, 1);
- *(size_t *)dvec_back(&locate_delims) = i;
+ delims = addcap(delims, sizeof(size_t),
+ delims_len + 1, &delims_cap);
+ delims[delims_len++] = i;
}
}
}
static char *
-entry(int i)
+entry(size_t i)
{
- size_t off;
-
- assert(i >= 0);
-
- if (i == 0) {
- return dvec_at(&locate_output, 0);
- } else {
- off = *(size_t *)dvec_at(&locate_delims, (size_t) i - 1);
- return dvec_at(&locate_output, off + 1);
- }
+ return output + (i ? delims[i-1] + 1 : 0);
}
static void
@@ -326,30 +321,21 @@ update(void)
width = getmaxx(stdscr);
height = getmaxy(stdscr);
- if (errbuf[0] && errtimer >= 0) {
- attr_on(A_BOLD, NULL);
- mvprintw(0, 1, "%s", errbuf);
- attr_off(A_BOLD, NULL);
- errtimer--;
- }
-
- mvprintw(1, 1, "%lu %lu", dvec_len(&locate_output),
- dvec_len(&locate_delims));
+ mvprintw(1, 1, "%lu %lu %i", output_len, delims_len, child_pid);
mvprintw(2, 1, "> %.*s", width - 1, inputbuf);
- if (!dvec_empty(&locate_output)) {
- listnav_update_bounds(&locate_nav, 0, (int) dvec_len(&locate_delims));
- listnav_update_wlen(&locate_nav, (int) (height - miny));
+ if (output_len) {
+ nav_update_bounds(&output_nav, 0, (int) delims_len);
+ nav_update_wlen(&output_nav, (int) (height - miny));
- i = locate_nav.wmin;
- for (y = miny; y < height && i < locate_nav.wmax; y++, i++) {
- if (i == locate_nav.sel)
+ i = output_nav.wmin;
+ for (y = miny; y < height && i < output_nav.wmax; y++, i++) {
+ if (i == output_nav.sel)
attr_on(A_REVERSE, NULL);
- mvprintw((int) y, 1, "%.*s",
- width - 1, entry((int) i));
+ mvprintw((int) y, 1, "%.*s", width - 1, entry((size_t) i));
- if (i == locate_nav.sel)
+ if (i == output_nav.sel)
attr_off(A_REVERSE, NULL);
}
}
@@ -376,21 +362,21 @@ input(void)
reload = true;
break;
case KEY_PPAGE:
- listnav_update_sel(&locate_nav,
- locate_nav.sel - locate_nav.wlen / 2);
+ nav_update_sel(&output_nav,
+ output_nav.sel - output_nav.wlen / 2);
dirty = true;
break;
case KEY_NPAGE:
- listnav_update_sel(&locate_nav,
- locate_nav.sel + locate_nav.wlen / 2);
+ nav_update_sel(&output_nav,
+ output_nav.sel + output_nav.wlen / 2);
dirty = true;
break;
case KEY_DOWN:
- listnav_update_sel(&locate_nav, locate_nav.sel + 1);
+ nav_update_sel(&output_nav, output_nav.sel + 1);
dirty = true;
break;
case KEY_UP:
- listnav_update_sel(&locate_nav, locate_nav.sel - 1);
+ nav_update_sel(&output_nav, output_nav.sel - 1);
dirty = true;
break;
case '\x1b':
@@ -401,17 +387,21 @@ input(void)
case 'd':
break;
}
+ break;
case CTRL('w'):
inputlen = 0;
dirty = true;
reload = true;
break;
+ case CTRL('l'):
+ clear();
+ dirty = true;
+ break;
case '\n':
- if (!isatty(2)) {
- fprintf(stderr, "%s\n", entry(locate_nav.sel));
+ if (output_nav.sel >= 0) {
+ fputs(entry((size_t) output_nav.sel), stderr);
+ if (oneshot) exit(0);
}
- if (single_out)
- exit(0);
break;
default:
if (c < 32 || c >= 127)
@@ -427,10 +417,7 @@ input(void)
if (dirty) {
update();
- if (reload) {
- reset();
- spawn(cmd_argv, inputbuf);
- }
+ if (reload) spawn(child_argv, inputbuf);
}
}
@@ -441,10 +428,10 @@ usage(int rc, bool full)
if (full) {
fprintf(stderr, "\n");
fprintf(stderr, " -h, --help Show this message\n");
+ fprintf(stderr, " -d, --delim Set input entry delim\n");
fprintf(stderr, " -s, --single Exit after single selection\n");
- fprintf(stderr, " -d, --debug Enable debug mode\n");
+ fprintf(stderr, " -e, --stderr Dont close child stderr\n");
fprintf(stderr, " -a, --args Split the query into args\n");
- fprintf(stderr, " -c, --delim Set input entry delim\n");
fprintf(stderr, "\n");
}
exit(rc);
@@ -459,34 +446,30 @@ parse(int argc, const char **argv)
for (arg = &argv[1]; *arg; arg++) {
if (!strcmp(*arg, "-h") || !strcmp(*arg, "--help")) {
usage(0, true);
- } else if (!strcmp(*arg, "-s") || !strcmp(*arg, "--single")) {
- single_out = true;
- } else if (!strcmp(*arg, "-d") || !strcmp(*arg, "--debug")) {
- debug = true;
- } else if (!strcmp(*arg, "-a") || !strcmp(*arg, "--args")) {
- separate_args = true;
- } else if (!strcmp(*arg, "-c") || !strcmp(*arg, "--delim")) {
+ } else if (!strcmp(*arg, "-o") || !strcmp(*arg, "--oneshot")) {
+ oneshot = true;
+ } else if (!strcmp(*arg, "-e") || !strcmp(*arg, "--openerr")) {
+ openerr = true;
+ } else if (!strcmp(*arg, "-s") || !strcmp(*arg, "--separate")) {
+ separate = true;
+ } else if (!strcmp(*arg, "-d") || !strcmp(*arg, "--delim")) {
delim = **++arg;
} else if (!strcmp(*arg, "--")) {
- cmd_argv = arg + 1;
+ child_argv = arg + 1;
break;
} else {
- fprintf(stderr, "tquery: unknown option '%s'\n", arg[0]);
- exit(1);
+ die("unknown option '%s'", arg[0]);
}
}
- if (!cmd_argv || !*cmd_argv) {
+ if (!child_argv || !*child_argv) {
usage(0, false);
}
- if (*cmd_argv[0] != '/' && strncmp(cmd_argv[0], "./", 2)) {
- cmd_path = findbin(cmd_argv[0]);
- if (!cmd_path) {
- fprintf(stderr, "tquery: no '%s' in PATH\n", cmd_argv[0]);
- exit(1);
- }
- cmd_argv[0] = cmd_path;
+ if (*child_argv[0] != '/' && strncmp(child_argv[0], "./", 2)) {
+ cmd_path = findbin(child_argv[0]);
+ if (!cmd_path) die("Could not find '%s' in PATH", child_argv[0]);
+ child_argv[0] = cmd_path;
}
}
@@ -500,9 +483,7 @@ main(int argc, const char **argv)
swapfd(1, 2);
- dvec_init(&locate_output, 1, 1024 * 1024 * 25, ga);
- dvec_init(&locate_delims, sizeof(size_t), 1024, ga);
- listnav_init(&locate_nav);
+ nav_init(&output_nav);
signal(SIGINT, sigint);
@@ -516,28 +497,27 @@ main(int argc, const char **argv)
update();
- reset();
- spawn(cmd_argv, "");
+ spawn(child_argv, "");
inputlen = 0;
while (1) {
maxfd = 0;
FD_ZERO(&set);
FD_SET(0, &set);
- if (locate_pid) {
- FD_SET(locate_out_fd, &set);
- if (locate_out_fd > maxfd)
- maxfd = locate_out_fd;
+ if (child_pid) {
+ FD_SET(child_fd, &set);
+ if (child_fd > maxfd)
+ maxfd = child_fd;
}
rc = select(maxfd+1, &set, NULL, NULL, NULL);
if (rc <= 0 && errno == EINTR) {
update();
continue;
- } else if (rc <= 0) err("select");
+ } else if (rc <= 0) die("select:");
if (FD_ISSET(0, &set)) {
input();
- } else if (FD_ISSET(locate_out_fd, &set)) {
+ } else if (FD_ISSET(child_fd, &set)) {
load();
update();
}