commit 50592339bf450037972b85777d1c524e35545aa8
parent 47d659c5fc930f0815c2bf5a24b3c2228b13695e
Author: sin <sin@2f30.org>
Date: Fri, 2 Aug 2019 15:43:07 +0100
Implement nopen(1)
Diffstat:
M | Makefile | | | 48 | ++++++++++++++++++++++++++++-------------------- |
D | config.def.h | | | 102 | ------------------------------------------------------------------------------- |
M | noice.1 | | | 24 | ++++++++---------------- |
M | noice.c | | | 113 | ++++--------------------------------------------------------------------------- |
A | noiceconf.def.h | | | 93 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | nopen.1 | | | 31 | +++++++++++++++++++++++++++++++ |
A | nopen.c | | | 95 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | nopenconf.def.h | | | 9 | +++++++++ |
A | spawn.c | | | 43 | +++++++++++++++++++++++++++++++++++++++++++ |
M | strverscmp.c | | | 2 | ++ |
M | util.h | | | 21 | +++++++++++++-------- |
11 files changed, 327 insertions(+), 254 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,45 +1,53 @@
VERSION = 0.8
-
PREFIX = /usr/local
MANPREFIX = $(PREFIX)/man
#CPPFLAGS = -DDEBUG
#CFLAGS = -g
-LDLIBS = -lcurses
-DISTFILES = noice.c strlcat.c strlcpy.c strverscmp.c util.h config.def.h\
- noice.1 Makefile README LICENSE
-OBJ = noice.o strlcat.o strlcpy.o strverscmp.o
-BIN = noice
+NOICELDLIBS = -lcurses
+NOPENLDLIBS =
+NOICEOBJ = noice.o spawn.o strlcat.o strlcpy.o strverscmp.o
+NOPENOBJ = nopen.o spawn.o
+BIN = noice nopen
+MAN = noice.1 nopen.1
all: $(BIN)
-$(BIN): $(OBJ)
- $(CC) $(CFLAGS) -o $@ $(OBJ) $(LDFLAGS) $(LDLIBS)
+noice: $(NOICEOBJ)
+ $(CC) $(CFLAGS) -o $@ $(NOICEOBJ) $(LDFLAGS) $(NOICELDLIBS)
+
+nopen: $(NOPENOBJ)
+ $(CC) $(CFLAGS) -o $@ $(NOPENOBJ) $(LDFLAGS) $(NOPENLDLIBS)
-noice.o: util.h config.h
+noice.o: noiceconf.h util.h
+nopen.o: nopenconf.h util.h
+spawn.o: util.h
strlcat.o: util.h
strlcpy.o: util.h
+strverscmp.o: util.h
+
+noiceconf.h:
+ cp noiceconf.def.h $@
-config.h:
- cp config.def.h $@
+nopenconf.h:
+ cp nopenconf.def.h $@
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
- cp -f $(BIN).1 $(DESTDIR)$(MANPREFIX)/man1
+ cp -f $(MAN) $(DESTDIR)$(MANPREFIX)/man1
uninstall:
- rm -f $(DESTDIR)$(PREFIX)/bin/$(BIN)
- rm -f $(DESTDIR)$(MANPREFIX)/man1/$(BIN).1
+ cd $(DESTDIR)$(PREFIX)/bin && rm -f $(BIN)
+ cd $(DESTDIR)$(MANPREFIX)/man1 && rm -f $(MAN)
-dist:
+dist: clean
mkdir -p noice-$(VERSION)
- cp $(DISTFILES) noice-$(VERSION)
- tar -cf noice-$(VERSION).tar noice-$(VERSION)
- gzip noice-$(VERSION).tar
- rm -rf noice-$(VERSION)
+ cp `find . -maxdepth 1 -type f` noice-$(VERSION)
+ tar -c noice-$(VERSION) | gzip > noice-$(VERSION).tar.gz
clean:
- rm -f $(BIN) $(OBJ) noice-$(VERSION).tar.gz
+ rm -f $(BIN) $(NOICEOBJ) $(NOPENOBJ) noice-$(VERSION).tar.gz
+ rm -rf noice-$(VERSION)
diff --git a/config.def.h b/config.def.h
@@ -1,102 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#define CWD "cwd: "
-#define CURSR " > "
-#define EMPTY " "
-
-int dirorder = 0; /* Set to 1 to sort by directory first */
-int mtimeorder = 0; /* Set to 1 to sort by time modified */
-int icaseorder = 0; /* Set to 1 to sort by ignoring case */
-int versorder = 0; /* Set to 1 to sort by version number */
-int idletimeout = 0; /* Screensaver timeout in seconds, 0 to disable */
-int showhidden = 0; /* Set to 1 to show hidden files by default */
-int usecolor = 0; /* Set to 1 to enable color attributes */
-char *idlecmd = "rain"; /* The screensaver program */
-
-/* See curs_attr(3) for valid video attributes */
-#define CURSR_ATTR A_NORMAL
-#define DIR_ATTR A_NORMAL | COLOR_PAIR(4)
-#define LINK_ATTR A_NORMAL | COLOR_PAIR(6)
-#define SOCK_ATTR A_NORMAL | COLOR_PAIR(1)
-#define FIFO_ATTR A_NORMAL | COLOR_PAIR(5)
-#define EXEC_ATTR A_NORMAL | COLOR_PAIR(2)
-
-/* Colors to use with COLOR_PAIR(n) as attributes */
-struct cpair pairs[] = {
- { .fg = 0, .bg = 0 },
- /* pairs start at 1 */
- { COLOR_RED, -1 },
- { COLOR_GREEN, -1 },
- { COLOR_YELLOW, -1 },
- { COLOR_BLUE, -1 },
- { COLOR_MAGENTA, -1 },
- { COLOR_CYAN, -1 },
-};
-
-struct assoc assocs[] = {
- { .regex = "\\.(avi|mp4|mkv|mp3|ogg|flac|mov)$", .file = "mpv", .argv = { "mpv", "{}", NULL } },
- { .regex = "\\.(png|jpg|gif)$", .file = "sxiv", .argv = { "sxiv", "{}", NULL} },
- { .regex = "\\.(html|svg)$", .file = "firefox", .argv = { "firefox", "{}", NULL } },
- { .regex = "\\.pdf$", .file = "mupdf", .argv = { "mupdf", "{}", NULL} },
- { .regex = "\\.sh$", .file = "sh", .argv = { "sh", "{}", NULL} },
- { .regex = ".", .file = "less", .argv = { "less", "{}", NULL } },
-};
-
-struct key bindings[] = {
- /* Quit */
- { 'q', SEL_QUIT },
- /* Back */
- { KEY_BACKSPACE, SEL_BACK },
- { KEY_LEFT, SEL_BACK },
- { 'h', SEL_BACK },
- { CONTROL('H'), SEL_BACK },
- /* Inside */
- { KEY_ENTER, SEL_GOIN },
- { '\r', SEL_GOIN },
- { KEY_RIGHT, SEL_GOIN },
- { 'l', SEL_GOIN },
- /* Filter */
- { '/', SEL_FLTR },
- { '&', SEL_FLTR },
- /* Next */
- { 'j', SEL_NEXT },
- { KEY_DOWN, SEL_NEXT },
- { CONTROL('N'), SEL_NEXT },
- /* Previous */
- { 'k', SEL_PREV },
- { KEY_UP, SEL_PREV },
- { CONTROL('P'), SEL_PREV },
- /* Page down */
- { KEY_NPAGE, SEL_PGDN },
- { CONTROL('D'), SEL_PGDN },
- /* Page up */
- { KEY_PPAGE, SEL_PGUP },
- { CONTROL('U'), SEL_PGUP },
- /* Home */
- { KEY_HOME, SEL_HOME },
- { META('<'), SEL_HOME },
- { '^', SEL_HOME },
- /* End */
- { KEY_END, SEL_END },
- { META('>'), SEL_END },
- { '$', SEL_END },
- /* Change dir */
- { 'c', SEL_CD },
- { '~', SEL_CDHOME },
- /* Toggle hide .dot files */
- { '.', SEL_TOGGLEDOT },
- /* Toggle sort by directory first */
- { 'd', SEL_DSORT },
- /* Toggle sort by time */
- { 't', SEL_MTIME },
- /* Toggle case sensitivity */
- { 'i', SEL_ICASE },
- /* Toggle sort by version number */
- { 'v', SEL_VERS },
- { CONTROL('L'), SEL_REDRAW },
- /* Run command */
- { 'z', SEL_RUN, "top" },
- { '!', SEL_RUN, "sh", "SHELL" },
- /* Run command with argument */
- { 'e', SEL_RUNARG, "vi", "EDITOR" },
- { 'p', SEL_RUNARG, "less", "PAGER" },
-};
diff --git a/noice.1 b/noice.1
@@ -1,4 +1,4 @@
-.Dd March 31, 2019
+.Dd August 2, 2019
.Dt NOICE 1
.Os
.Sh NAME
@@ -84,23 +84,13 @@ directory you came out of.
.Sh CONFIGURATION
.Nm
is configured by modifying
-.Pa config.h
+.Pa noiceconf.h
and recompiling the code.
.Pp
-The file associations are specified by regexes
-matching on the currently selected filename.
-If a match is found the associated program is executed
-with the filename passed in as the argument.
-If no match is found the program
-.Xr less 1
-is invoked.
-This is useful for editing text files as one can use the
-.Ic v
-command in
-.Xr less 1
-to edit the file using the
-.Ev EDITOR
-environment variable.
+.Nm
+invokes
+.Xr nopen 1
+to open a file in the user's preferred application.
.Sh FILTERS
Filters allow you to use regexes to display only the matched
entries in the current directory view.
@@ -131,6 +121,8 @@ commands respectively.
If you are using
.Xr urxvt 1
you might have to set backspace key to DEC.
+.Sh SEE ALSO
+.Xr nopen 1
.Sh AUTHORS
.An Lazaros Koromilas Aq Mt lostd@2f30.org ,
.An Dimitris Papastamos Aq Mt sin@2f30.org .
diff --git a/noice.c b/noice.c
@@ -1,7 +1,6 @@
/* See LICENSE file for copyright and license details. */
#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/wait.h>
#include <curses.h>
#include <dirent.h>
@@ -20,21 +19,12 @@
#include "util.h"
-#define NR_ARGS 32
-#define LEN(x) (sizeof(x) / sizeof(*(x)))
#undef MIN
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define ISODD(x) ((x) & 1)
#define CONTROL(c) ((c) ^ 0x40)
#define META(c) ((c) ^ 0x80)
-struct assoc {
- char *regex; /* Regex to match on filename */
- char *file;
- char *argv[NR_ARGS];
- regex_t regcomp;
-};
-
struct cpair {
int fg;
int bg;
@@ -71,7 +61,7 @@ struct key {
char *env; /* Environment variable to run */
};
-#include "config.h"
+#include "noiceconf.h"
struct entry {
char name[PATH_MAX];
@@ -167,59 +157,6 @@ xdirname(const char *path)
return out;
}
-void
-spawnvp(char *dir, char *file, char *argv[])
-{
- pid_t pid;
- int status;
-
- pid = fork();
- if (pid == 0) {
- if (dir != NULL)
- chdir(dir);
- execvp(file, argv);
- _exit(1);
- } else {
- /* Ignore interruptions */
- while (waitpid(pid, &status, 0) == -1)
- DPRINTF_D(status);
- DPRINTF_D(pid);
- }
-}
-
-void
-spawnlp(char *dir, char *file, char *argv0, ...)
-{
- char *argv[NR_ARGS];
- va_list ap;
- int argc;
-
- va_start(ap, argv0);
- argv[0] = argv0;
- for (argc = 1; argv[argc] = va_arg(ap, char *); argc++)
- ;
- argv[argc] = NULL;
- va_end(ap);
- spawnvp(dir, file, argv);
-}
-
-void
-spawnassoc(struct assoc *assoc, char *arg)
-{
- char *argv[NR_ARGS];
- int i;
-
- for (i = 0; assoc->argv[i]; i++) {
- if (strcmp(assoc->argv[i], "{}") == 0) {
- argv[i] = arg;
- continue;
- }
- argv[i] = assoc->argv[i];
- }
- argv[i] = NULL;
- spawnvp(NULL, assoc->file, argv);
-}
-
char *
xgetenv(char *name, char *fallback)
{
@@ -231,21 +168,6 @@ xgetenv(char *name, char *fallback)
return value && value[0] ? value : fallback;
}
-struct assoc *
-openwith(char *file)
-{
- int i;
-
- for (i = 0; i < LEN(assocs); i++) {
- if (regexec(&assocs[i].regcomp, file, 0, NULL, 0) == 0) {
- DPRINTF_S(assocs[i].argv[0]);
- return &assocs[i];
- }
- }
-
- return NULL;
-}
-
int
setfilter(regex_t *regex, char *filter)
{
@@ -671,7 +593,6 @@ browse(char *ipath, char *ifilter)
char path[PATH_MAX], oldpath[PATH_MAX], newpath[PATH_MAX];
char fltr[LINE_MAX];
char *dir, *tmp, *run, *env;
- struct assoc *assoc;
struct stat sb;
regex_t re;
int r, fd;
@@ -744,13 +665,8 @@ nochange:
strlcpy(fltr, ifilter, sizeof(fltr));
goto begin;
case S_IFREG:
- assoc = openwith(newpath);
- if (assoc == NULL) {
- printmsg("No association");
- goto nochange;
- }
exitcurses();
- spawnassoc(assoc, newpath);
+ spawnlp(path, "nopen", "nopen", newpath, (void *)0);
initcurses();
continue;
default:
@@ -869,7 +785,7 @@ nochange:
mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
run = xgetenv(env, run);
exitcurses();
- spawnlp(path, run, run, NULL);
+ spawnlp(path, run, run, (void *)0);
initcurses();
goto begin;
case SEL_RUNARG:
@@ -878,7 +794,7 @@ nochange:
mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
run = xgetenv(env, run);
exitcurses();
- spawnlp(path, run, run, dents[cur].name, NULL);
+ spawnlp(path, run, run, dents[cur].name, (void *)0);
initcurses();
goto begin;
}
@@ -886,31 +802,13 @@ nochange:
if (idletimeout != 0 && idle == idletimeout) {
idle = 0;
exitcurses();
- spawnlp(NULL, idlecmd, idlecmd, NULL);
+ spawnlp(NULL, idlecmd, idlecmd, (void *)0);
initcurses();
}
}
}
void
-initassocs(void)
-{
- char errbuf[256];
- int i, r;
-
- for (i = 0; i < LEN(assocs); i++) {
- r = regcomp(&assocs[i].regcomp, assocs[i].regex,
- REG_NOSUB | REG_EXTENDED | REG_ICASE);
- if (r != 0) {
- regerror(r, &assocs[i].regcomp, errbuf, sizeof(errbuf));
- fprintf(stderr, "invalid regex assocs[%d]: %s: %s\n",
- i, assocs[i].regex, errbuf);
- exit(1);
- }
- }
-}
-
-void
usage(char *argv0)
{
fprintf(stderr, "usage: %s [dir]\n", argv0);
@@ -954,7 +852,6 @@ main(int argc, char *argv[])
/* Set locale before curses setup */
setlocale(LC_ALL, "");
- initassocs();
initcurses();
browse(ipath, ifilter);
exitcurses();
diff --git a/noiceconf.def.h b/noiceconf.def.h
@@ -0,0 +1,93 @@
+/* See LICENSE file for copyright and license details. */
+#define CWD "cwd: "
+#define CURSR " > "
+#define EMPTY " "
+
+int dirorder = 0; /* Set to 1 to sort by directory first */
+int mtimeorder = 0; /* Set to 1 to sort by time modified */
+int icaseorder = 0; /* Set to 1 to sort by ignoring case */
+int versorder = 0; /* Set to 1 to sort by version number */
+int idletimeout = 0; /* Screensaver timeout in seconds, 0 to disable */
+int showhidden = 0; /* Set to 1 to show hidden files by default */
+int usecolor = 0; /* Set to 1 to enable color attributes */
+char *idlecmd = "rain"; /* The screensaver program */
+
+/* See curs_attr(3) for valid video attributes */
+#define CURSR_ATTR A_NORMAL
+#define DIR_ATTR A_NORMAL | COLOR_PAIR(4)
+#define LINK_ATTR A_NORMAL | COLOR_PAIR(6)
+#define SOCK_ATTR A_NORMAL | COLOR_PAIR(1)
+#define FIFO_ATTR A_NORMAL | COLOR_PAIR(5)
+#define EXEC_ATTR A_NORMAL | COLOR_PAIR(2)
+
+/* Colors to use with COLOR_PAIR(n) as attributes */
+struct cpair pairs[] = {
+ { .fg = 0, .bg = 0 },
+ /* pairs start at 1 */
+ { COLOR_RED, -1 },
+ { COLOR_GREEN, -1 },
+ { COLOR_YELLOW, -1 },
+ { COLOR_BLUE, -1 },
+ { COLOR_MAGENTA, -1 },
+ { COLOR_CYAN, -1 },
+};
+
+struct key bindings[] = {
+ /* Quit */
+ { 'q', SEL_QUIT },
+ /* Back */
+ { KEY_BACKSPACE, SEL_BACK },
+ { KEY_LEFT, SEL_BACK },
+ { 'h', SEL_BACK },
+ { CONTROL('H'), SEL_BACK },
+ /* Inside */
+ { KEY_ENTER, SEL_GOIN },
+ { '\r', SEL_GOIN },
+ { KEY_RIGHT, SEL_GOIN },
+ { 'l', SEL_GOIN },
+ /* Filter */
+ { '/', SEL_FLTR },
+ { '&', SEL_FLTR },
+ /* Next */
+ { 'j', SEL_NEXT },
+ { KEY_DOWN, SEL_NEXT },
+ { CONTROL('N'), SEL_NEXT },
+ /* Previous */
+ { 'k', SEL_PREV },
+ { KEY_UP, SEL_PREV },
+ { CONTROL('P'), SEL_PREV },
+ /* Page down */
+ { KEY_NPAGE, SEL_PGDN },
+ { CONTROL('D'), SEL_PGDN },
+ /* Page up */
+ { KEY_PPAGE, SEL_PGUP },
+ { CONTROL('U'), SEL_PGUP },
+ /* Home */
+ { KEY_HOME, SEL_HOME },
+ { META('<'), SEL_HOME },
+ { '^', SEL_HOME },
+ /* End */
+ { KEY_END, SEL_END },
+ { META('>'), SEL_END },
+ { '$', SEL_END },
+ /* Change dir */
+ { 'c', SEL_CD },
+ { '~', SEL_CDHOME },
+ /* Toggle hide .dot files */
+ { '.', SEL_TOGGLEDOT },
+ /* Toggle sort by directory first */
+ { 'd', SEL_DSORT },
+ /* Toggle sort by time */
+ { 't', SEL_MTIME },
+ /* Toggle case sensitivity */
+ { 'i', SEL_ICASE },
+ /* Toggle sort by version number */
+ { 'v', SEL_VERS },
+ { CONTROL('L'), SEL_REDRAW },
+ /* Run command */
+ { 'z', SEL_RUN, "top" },
+ { '!', SEL_RUN, "sh", "SHELL" },
+ /* Run command with argument */
+ { 'e', SEL_RUNARG, "vi", "EDITOR" },
+ { 'p', SEL_RUNARG, "less", "PAGER" },
+};
diff --git a/nopen.1 b/nopen.1
@@ -0,0 +1,31 @@
+.Dd August 2, 2019
+.Dt NOPEN 1
+.Os
+.Sh NAME
+.Nm nopen
+.Nd opens a file in the user's preferred application
+.Sh SYNOPSIS
+.Nm
+.Ar file...
+.Sh DESCRIPTION
+.Nm
+opens the files provided as arguments with the user's proferred
+application.
+.Pp
+The file associations are specified by regexes
+matching on the currently selected filename.
+If a match is found the associated program is executed
+with the filename passed in as the argument.
+If no match is found the program
+.Xr less 1
+is invoked.
+.Sh CONFIGURATION
+.Nm
+is configured by modifying
+.Pa nopenconf.h
+and recompiling the code.
+.Sh SEE ALSO
+.Xr noice 1
+.Sh AUTHORS
+.An Lazaros Koromilas Aq Mt lostd@2f30.org ,
+.An Dimitris Papastamos Aq Mt sin@2f30.org .
diff --git a/nopen.c b/nopen.c
@@ -0,0 +1,95 @@
+/* See LICENSE file for copyright and license details. */
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "util.h"
+
+struct assoc {
+ char *regex; /* Regex to match on filename */
+ char *file;
+ char *argv[NR_ARGS];
+ regex_t regcomp;
+};
+
+#include "nopenconf.h"
+
+void
+spawnassoc(struct assoc *assoc, char *arg)
+{
+ char *argv[NR_ARGS];
+ int i;
+
+ for (i = 0; assoc->argv[i]; i++) {
+ if (strcmp(assoc->argv[i], "{}") == 0) {
+ argv[i] = arg;
+ continue;
+ }
+ argv[i] = assoc->argv[i];
+ }
+ argv[i] = NULL;
+ spawnvp(NULL, assoc->file, argv);
+}
+
+struct assoc *
+openwith(char *file)
+{
+ int i;
+
+ for (i = 0; i < LEN(assocs); i++) {
+ if (regexec(&assocs[i].regcomp, file, 0, NULL, 0) == 0)
+ return &assocs[i];
+ }
+
+ return NULL;
+}
+
+void
+initassocs(void)
+{
+ char errbuf[256];
+ int i, r;
+
+ for (i = 0; i < LEN(assocs); i++) {
+ r = regcomp(&assocs[i].regcomp, assocs[i].regex,
+ REG_NOSUB | REG_EXTENDED | REG_ICASE);
+ if (r != 0) {
+ regerror(r, &assocs[i].regcomp, errbuf, sizeof(errbuf));
+ fprintf(stderr, "invalid regex assocs[%d]: %s: %s\n",
+ i, assocs[i].regex, errbuf);
+ exit(1);
+ }
+ }
+}
+
+void
+usage(char *argv0)
+{
+ fprintf(stderr, "usage: %s file...\n", argv0);
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ if (argc == 1)
+ usage(argv[0]);
+ argc--;
+ argv++;
+ initassocs();
+ for (; *argv != NULL; argv++) {
+ struct assoc *assoc;
+
+ assoc = openwith(argv[0]);
+ if (assoc == NULL)
+ continue;
+ spawnassoc(assoc, argv[0]);
+ }
+ return 0;
+}
diff --git a/nopenconf.def.h b/nopenconf.def.h
@@ -0,0 +1,9 @@
+/* See LICENSE file for copyright and license details. */
+struct assoc assocs[] = {
+ { .regex = "\\.(avi|mp4|mkv|mp3|ogg|flac|mov)$", .file = "mpv", .argv = { "mpv", "{}", NULL } },
+ { .regex = "\\.(png|jpg|gif)$", .file = "sxiv", .argv = { "sxiv", "{}", NULL} },
+ { .regex = "\\.(html|svg)$", .file = "firefox", .argv = { "firefox", "{}", NULL } },
+ { .regex = "\\.pdf$", .file = "mupdf", .argv = { "mupdf", "{}", NULL} },
+ { .regex = "\\.sh$", .file = "sh", .argv = { "sh", "{}", NULL} },
+ { .regex = ".", .file = "less", .argv = { "less", "{}", NULL } },
+};
diff --git a/spawn.c b/spawn.c
@@ -0,0 +1,43 @@
+/* See LICENSE file for copyright and license details. */
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "util.h"
+
+void
+spawnvp(char *dir, char *file, char *argv[])
+{
+ pid_t pid;
+ int status;
+
+ pid = fork();
+ if (pid == 0) {
+ if (dir != NULL)
+ chdir(dir);
+ execvp(file, argv);
+ _exit(1);
+ } else {
+ /* Ignore interruptions */
+ while (waitpid(pid, &status, 0) == -1)
+ ;
+ }
+}
+
+void
+spawnlp(char *dir, char *file, char *argv0, ...)
+{
+ char *argv[NR_ARGS];
+ va_list ap;
+ int argc;
+
+ va_start(ap, argv0);
+ argv[0] = argv0;
+ for (argc = 1; argv[argc] = va_arg(ap, char *); argc++)
+ ;
+ argv[argc] = NULL;
+ va_end(ap);
+ spawnvp(dir, file, argv);
+}
diff --git a/strverscmp.c b/strverscmp.c
@@ -1,6 +1,8 @@
+/* See LICENSE file for copyright and license details. */
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
+
#include "util.h"
int
diff --git a/util.h b/util.h
@@ -1,12 +1,6 @@
/* See LICENSE file for copyright and license details. */
-#undef strlcat
-size_t strlcat(char *, const char *, size_t);
-#undef strlcpy
-size_t strlcpy(char *, const char *, size_t);
-#undef dprintf
-int dprintf(int, const char *, ...);
-#undef strverscmp
-int strverscmp(const char *, const char *);
+#define LEN(x) (sizeof(x) / sizeof(*(x)))
+#define NR_ARGS 32
#ifdef DEBUG
#define DEBUG_FD 8
@@ -22,3 +16,14 @@ int strverscmp(const char *, const char *);
#define DPRINTF_P(x)
#define DPRINTF_LLU(x)
#endif /* DEBUG */
+
+#undef strlcat
+size_t strlcat(char *, const char *, size_t);
+#undef strlcpy
+size_t strlcpy(char *, const char *, size_t);
+#undef dprintf
+int dprintf(int, const char *, ...);
+
+int strverscmp(const char *, const char *);
+void spawnvp(char *, char *, char *[]);
+void spawnlp(char *, char *, char *, ...);