summaryrefslogtreecommitdiff
path: root/usr.bin/mg
diff options
context:
space:
mode:
authorlum <lum@cvs.openbsd.org>2011-08-31 03:40:54 +0000
committerlum <lum@cvs.openbsd.org>2011-08-31 03:40:54 +0000
commit25108f168b8130aaf586da0db20af8d89fca7521 (patch)
treeae9ba50f4fa29f05be8ed80d45926a4da1c0933c /usr.bin/mg
parent66b9d80cc59d22a289b0aa9c5a51ca77635f9b9e (diff)
Allow dired mode to open files regardless of characters in
filename, from Henri Kemppainen. Tested, reviewed and a tweak each from Loganaden Velvindron and myself. ok jasper@
Diffstat (limited to 'usr.bin/mg')
-rw-r--r--usr.bin/mg/dired.c198
1 files changed, 114 insertions, 84 deletions
diff --git a/usr.bin/mg/dired.c b/usr.bin/mg/dired.c
index 9adf076ac17..524290e15cc 100644
--- a/usr.bin/mg/dired.c
+++ b/usr.bin/mg/dired.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dired.c,v 1.49 2011/08/29 11:02:06 lum Exp $ */
+/* $OpenBSD: dired.c,v 1.50 2011/08/31 03:40:53 lum Exp $ */
/* This file is in the public domain. */
@@ -21,6 +21,7 @@
#include <fcntl.h>
#include <errno.h>
#include <libgen.h>
+#include <stdarg.h>
void dired_init(void);
static int dired(int, int);
@@ -33,6 +34,7 @@ static int d_expunge(int, int);
static int d_copy(int, int);
static int d_del(int, int);
static int d_rename(int, int);
+static int d_exec(int, struct buffer *, const char *, const char *, ...);
static int d_shell_command(int, int);
static int d_create_directory(int, int);
static int d_makename(struct line *, char *, size_t);
@@ -483,14 +485,10 @@ reaper(int signo __attribute__((unused)))
int
d_shell_command(int f, int n)
{
- char command[512], fname[MAXPATHLEN], buf[BUFSIZ], *bufp, *cp;
- int infd, fds[2];
- pid_t pid;
- struct sigaction olda, newa;
+ char command[512], fname[MAXPATHLEN], *bufp;
struct buffer *bp;
struct mgwin *wp;
- FILE *fin;
- char sname[NFILEN];
+ char sname[NFILEN];
bp = bfind("*Shell Command Output*", TRUE);
if (bclear(bp) != TRUE)
@@ -506,68 +504,125 @@ d_shell_command(int f, int n)
bufp = eread("! on %s: ", command, sizeof(command), EFNEW, sname);
if (bufp == NULL)
return (ABORT);
- infd = open(fname, O_RDONLY);
- if (infd == -1) {
+
+ if (d_exec(0, bp, fname, "sh", "-c", command, NULL) != TRUE)
+ return (ABORT);
+
+ if ((wp = popbuf(bp, WNONE)) == NULL)
+ return (ABORT); /* XXX - free the buffer?? */
+ curwp = wp;
+ curbp = wp->w_bufp;
+ return (TRUE);
+}
+
+/*
+ * Pipe input file to cmd and insert the command's output in the
+ * given buffer. Each line will be prefixed with the given
+ * number of spaces.
+ */
+static int
+d_exec(int space, struct buffer *bp, const char *input, const char *cmd, ...)
+{
+ char buf[BUFSIZ];
+ va_list ap;
+ struct sigaction olda, newa;
+ char **argv = NULL, *cp;
+ FILE *fin;
+ int fds[2] = { -1, -1 };
+ int infd = -1;
+ int ret = (ABORT), n;
+ pid_t pid;
+
+ if (sigaction(SIGCHLD, NULL, &olda) == -1)
+ return (ABORT);
+
+ /* Find the number of arguments. */
+ va_start(ap, cmd);
+ for (n = 2; va_arg(ap, char *) != NULL; n++)
+ ;
+ va_end(ap);
+
+ /* Allocate and build the argv. */
+ if ((argv = calloc(n, sizeof(*argv))) == NULL) {
+ ewprintf("Can't allocate argv : %s", strerror(errno));
+ goto out;
+ }
+
+ n = 1;
+ argv[0] = (char *)cmd;
+ va_start(ap, cmd);
+ while ((argv[n] = va_arg(ap, char *)) != NULL)
+ n++;
+ va_end(ap);
+
+ if (input == NULL)
+ input = "/dev/null";
+
+ if ((infd = open(input, O_RDONLY)) == -1) {
ewprintf("Can't open input file : %s", strerror(errno));
- return (FALSE);
+ goto out;
}
+
if (pipe(fds) == -1) {
ewprintf("Can't create pipe : %s", strerror(errno));
- close(infd);
- return (FALSE);
+ goto out;
}
newa.sa_handler = reaper;
newa.sa_flags = 0;
- if (sigaction(SIGCHLD, &newa, &olda) == -1) {
- close(infd);
- close(fds[0]);
- close(fds[1]);
- return (ABORT);
+ if (sigaction(SIGCHLD, &newa, NULL) == -1)
+ goto out;
+
+ if ((pid = fork()) == -1) {
+ ewprintf("Can't fork");
+ goto out;
}
- pid = fork();
+
switch (pid) {
- case -1:
- ewprintf("Can't fork");
- return (ABORT);
- case 0:
+ case 0: /* Child */
close(fds[0]);
dup2(infd, STDIN_FILENO);
dup2(fds[1], STDOUT_FILENO);
dup2(fds[1], STDERR_FILENO);
- execl("/bin/sh", "sh", "-c", bufp, (char *)NULL);
+ if (execvp(argv[0], argv) == -1)
+ ewprintf("Can't exec %s: %s", argv[0], strerror(errno));
exit(1);
break;
- default:
+ default: /* Parent */
close(infd);
close(fds[1]);
- fin = fdopen(fds[0], "r");
- if (fin == NULL) /* "r" is surely a valid mode! */
- panic("can't happen");
+ infd = fds[1] = -1;
+ if ((fin = fdopen(fds[0], "r")) == NULL)
+ goto out;
while (fgets(buf, sizeof(buf), fin) != NULL) {
cp = strrchr(buf, '\n');
if (cp == NULL && !feof(fin)) { /* too long a line */
int c;
- addlinef(bp, "%s...", buf);
+ addlinef(bp, "%*s%s...", space, "", buf);
while ((c = getc(fin)) != EOF && c != '\n')
;
continue;
} else if (cp)
*cp = '\0';
- addline(bp, buf);
+ addlinef(bp, "%*s%s", space, "", buf);
}
fclose(fin);
- close(fds[0]);
break;
}
- wp = popbuf(bp, WNONE);
- if (wp == NULL)
- return (ABORT); /* XXX - free the buffer?? */
- curwp = wp;
- curbp = wp->w_bufp;
+ ret = (TRUE);
+
+out:
if (sigaction(SIGCHLD, &olda, NULL) == -1)
ewprintf("Warning, couldn't reset previous signal handler");
- return (TRUE);
+ if (fds[0] != -1)
+ close(fds[0]);
+ if (fds[1] != -1)
+ close(fds[1]);
+ if (infd != -1)
+ close(infd);
+ if (argv != NULL)
+ free(argv);
+ return ret;
}
/* ARGSUSED */
@@ -595,35 +650,26 @@ d_create_directory(int f, int n)
return (showbuffer(bp, curwp, WFFULL | WFMODE));
}
-#define NAME_FIELD 8
-
static int
d_makename(struct line *lp, char *fn, size_t len)
{
- int i;
- char *p, *ep;
+ int start, nlen;
+ char *namep;
- if (strlcpy(fn, curbp->b_fname, len) >= len)
- return (FALSE);
- if ((p = lp->l_text) == NULL)
+ if (d_warpdot(lp, &start) == FALSE)
return (ABORT);
- ep = lp->l_text + llength(lp);
- p++; /* skip action letter, if any */
- for (i = 0; i < NAME_FIELD; i++) {
- while (p < ep && isspace(*p))
- p++;
- while (p < ep && !isspace(*p))
- p++;
- while (p < ep && isspace(*p))
- p++;
- if (p == ep)
- return (ABORT);
- }
- if (strlcat(fn, p, len) >= len)
- return (FALSE);
+ namep = &lp->l_text[start];
+ nlen = llength(lp) - start;
+
+ if (snprintf(fn, len, "%s%.*s", curbp->b_fname, nlen, namep) >= len)
+ return (ABORT); /* Name is too long. */
+
+ /* Return TRUE if the entry is a directory. */
return ((lgetc(lp, 2) == 'd') ? TRUE : FALSE);
}
+#define NAME_FIELD 9
+
static int
d_warpdot(struct line *dotp, int *doto)
{
@@ -637,15 +683,18 @@ d_warpdot(struct line *dotp, int *doto)
len = llength(dotp);
while (off < len) {
if (tp[off++] == ' ') {
- if (++field == 9)
- break;
+ if (++field == NAME_FIELD) {
+ *doto = off;
+ return (TRUE);
+ }
/* Skip the space. */
while (off < len && tp[off] == ' ')
off++;
}
}
- *doto = off;
- return (TRUE);
+ /* We didn't find the field. */
+ *doto = 0;
+ return (FALSE);
}
static int
@@ -683,9 +732,7 @@ struct buffer *
dired_(char *dname)
{
struct buffer *bp;
- FILE *dirpipe;
- char line[256];
- int len, ret, i;
+ int len, i;
if ((fopen(dname,"r")) == NULL) {
if (errno == EACCES)
@@ -709,32 +756,15 @@ dired_(char *dname)
if (bclear(bp) != TRUE)
return (NULL);
bp->b_flag |= BFREADONLY;
- ret = snprintf(line, sizeof(line), "ls -al %s", dname);
- if (ret < 0 || ret >= sizeof(line)) {
- ewprintf("Path too long");
- return (NULL);
- }
- if ((dirpipe = popen(line, "r")) == NULL) {
- ewprintf("Problem opening pipe to ls");
- return (NULL);
- }
- line[0] = line[1] = ' ';
- while (fgets(&line[2], sizeof(line) - 2, dirpipe) != NULL) {
- line[strcspn(line, "\n")] = '\0'; /* remove ^J */
- (void) addline(bp, line);
- }
- if (pclose(dirpipe) == -1) {
- ewprintf("Problem closing pipe to ls : %s",
- strerror(errno));
+
+ if ((d_exec(2, bp, NULL, "ls", "-al", dname, NULL)) != TRUE)
return (NULL);
- }
/* Find the line with ".." on it. */
bp->b_dotp = bfirstlp(bp);
for (i = 0; i < bp->b_lines; i++) {
bp->b_dotp = lforw(bp->b_dotp);
- d_warpdot(bp->b_dotp, &bp->b_doto);
- if (bp->b_doto >= llength(bp->b_dotp))
+ if (d_warpdot(bp->b_dotp, &bp->b_doto) == FALSE)
continue;
if (strcmp(ltext(bp->b_dotp) + bp->b_doto, "..") == 0)
break;