File: [local] / src / usr.bin / mg / dired.c (download)
Revision 1.12, Fri Aug 15 23:23:18 2003 UTC (20 years, 10 months ago) by vincent
Branch: MAIN
Changes since 1.11: +257 -20 lines
make dired work more like emacs. (well, make it _work_, and then add a
bunch of missing commands)
|
/* $OpenBSD: dired.c,v 1.12 2003/08/15 23:23:18 vincent Exp $ */
/* dired module for mg 2a */
/* by Robert A. Larson */
#include "def.h"
#include "kbd.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <libgen.h>
#ifndef NO_DIRED
int d_findfile(int, int);
static PF dired_cmds_1[] = {
forwline, /* space */
d_shell_command, /* ! */
rescan, /* " */
rescan, /* # */
rescan, /* $ */
rescan, /* % */
rescan, /* & */
rescan, /* ' */
rescan, /* ( */
rescan, /* ) */
rescan, /* * */
d_create_directory, /* + */
};
static PF dired_cmds_2[] = {
rescan, /* a */
rescan, /* b */
rescan, /* c */
rescan, /* d */
d_findfile, /* e */
d_findfile, /* f */
rescan, /* g */
rescan, /* h */
rescan, /* i */
rescan, /* j */
rescan, /* k */
rescan, /* l */
rescan, /* m */
forwline, /* n */
d_ffotherwindow, /* o */
rescan, /* p */
rescan, /* q */
rescan, /* r */
rescan, /* s */
rescan, /* t */
rescan, /* u */
d_findfile, /* v */
rescan, /* w */
d_expunge, /* x */
rescan, /* y */
rescan, /* z */
};
static PF dired_cmds_3[] = {
rescan, /* A */
rescan, /* B */
d_copy, /* C */
d_del, /* D */
rescan, /* E */
rescan, /* F */
rescan, /* G */
rescan, /* H */
rescan, /* I */
rescan, /* J */
rescan, /* K */
rescan, /* L */
rescan, /* M */
rescan, /* N */
rescan, /* O */
rescan, /* P */
rescan, /* Q */
d_rename, /* R */
rescan, /* S */
rescan, /* T */
rescan, /* U */
d_findfile, /* V */
rescan, /* W */
d_expunge, /* X */
rescan, /* Y */
rescan, /* Z */
};
static PF dired_pf[] = {
d_findfile, /* ^M */
rescan, /* ^N */
d_findfile, /* ^O */
};
static struct KEYMAPE (4 + IMAPEXT) diredmap = {
4,
4 + IMAPEXT,
rescan,
{
{ CCHR('M'), CCHR('O'), dired_pf, NULL },
{ ' ', '+', dired_cmds_1, NULL },
{ 'A', 'Z', dired_cmds_3, NULL },
{ 'a', 'z', dired_cmds_2, NULL }
}
};
/* ARGSUSED */
int
dired(int f, int n)
{
static int inited = 0;
char dirname[NFILEN];
BUFFER *bp;
if (inited == 0) {
maps_add((KEYMAP *)&diredmap, "dired");
inited = 1;
}
dirname[0] = '\0';
if (eread("Dired: ", dirname, NFILEN, EFNEW | EFCR) == ABORT)
return ABORT;
if ((bp = dired_(dirname)) == NULL)
return FALSE;
bp->b_modes[0] = name_mode("fundamental");
bp->b_modes[1] = name_mode("dired");
bp->b_nmodes = 1;
curbp = bp;
return showbuffer(bp, curwp, WFHARD | WFMODE);
}
/* ARGSUSED */
int
d_otherwindow(int f, int n)
{
char dirname[NFILEN];
BUFFER *bp;
MGWIN *wp;
dirname[0] = '\0';
if (eread("Dired other window: ", dirname, NFILEN, EFNEW | EFCR)
== ABORT)
return ABORT;
if ((bp = dired_(dirname)) == NULL)
return FALSE;
if ((wp = popbuf(bp)) == NULL)
return FALSE;
curbp = bp;
curwp = wp;
return TRUE;
}
/* ARGSUSED */
int
d_del(int f, int n)
{
if (n < 0)
return FALSE;
while (n--) {
if (llength(curwp->w_dotp) > 0)
lputc(curwp->w_dotp, 0, 'D');
if (lforw(curwp->w_dotp) != curbp->b_linep)
curwp->w_dotp = lforw(curwp->w_dotp);
}
curwp->w_flag |= WFEDIT | WFMOVE;
curwp->w_doto = 0;
return TRUE;
}
/* ARGSUSED */
int
d_undel(int f, int n)
{
if (n < 0)
return d_undelbak(f, -n);
while (n--) {
if (llength(curwp->w_dotp) > 0)
lputc(curwp->w_dotp, 0, ' ');
if (lforw(curwp->w_dotp) != curbp->b_linep)
curwp->w_dotp = lforw(curwp->w_dotp);
}
curwp->w_flag |= WFEDIT | WFMOVE;
curwp->w_doto = 0;
return TRUE;
}
/* ARGSUSED */
int
d_undelbak(int f, int n)
{
if (n < 0)
return d_undel(f, -n);
while (n--) {
if (llength(curwp->w_dotp) > 0)
lputc(curwp->w_dotp, 0, ' ');
if (lback(curwp->w_dotp) != curbp->b_linep)
curwp->w_dotp = lback(curwp->w_dotp);
}
curwp->w_doto = 0;
curwp->w_flag |= WFEDIT | WFMOVE;
return TRUE;
}
/* ARGSUSED */
int
d_findfile(int f, int n)
{
BUFFER *bp;
int s;
char fname[NFILEN];
if ((s = d_makename(curwp->w_dotp, fname, sizeof fname)) == ABORT)
return FALSE;
if (s == TRUE)
bp = dired_(fname);
else
bp = findbuffer(fname);
if (bp == NULL)
return FALSE;
curbp = bp;
if (showbuffer(bp, curwp, WFHARD) != TRUE)
return FALSE;
if (bp->b_fname[0] != 0)
return TRUE;
return readin(fname);
}
/* ARGSUSED */
int
d_ffotherwindow(int f, int n)
{
char fname[NFILEN];
int s;
BUFFER *bp;
MGWIN *wp;
if ((s = d_makename(curwp->w_dotp, fname, sizeof fname)) == ABORT)
return FALSE;
if ((bp = (s ? dired_(fname) : findbuffer(fname))) == NULL)
return FALSE;
if ((wp = popbuf(bp)) == NULL)
return FALSE;
curbp = bp;
curwp = wp;
if (bp->b_fname[0] != 0)
return TRUE; /* never true for dired buffers */
return readin(fname);
}
/* ARGSUSED */
int
d_expunge(int f, int n)
{
LINE *lp, *nlp;
char fname[NFILEN];
for (lp = lforw(curbp->b_linep); lp != curbp->b_linep; lp = nlp) {
nlp = lforw(lp);
if (llength(lp) && lgetc(lp, 0) == 'D') {
switch (d_makename(lp, fname, sizeof fname)) {
case ABORT:
ewprintf("Bad line in dired buffer");
return FALSE;
case FALSE:
if (unlink(fname) < 0) {
ewprintf("Could not delete '%s'",
basename(fname));
return FALSE;
}
break;
case TRUE:
if (rmdir(fname) < 0) {
ewprintf("Could not delete directory '%s'",
basename(fname));
return FALSE;
}
break;
}
lfree(lp);
curwp->w_flag |= WFHARD;
}
}
return TRUE;
}
/* ARGSUSED */
int
d_copy(int f, int n)
{
char frname[NFILEN], toname[NFILEN];
int stat, off;
BUFFER *bp;
if (d_makename(curwp->w_dotp, frname, sizeof frname) != FALSE) {
ewprintf("Not a file");
return FALSE;
}
off = strlcpy(toname, curbp->b_fname, sizeof toname);
if (off >= sizeof toname - 1) { /* can't happen, really */
ewprintf("too long directory name");
return (FALSE);
}
if ((stat = eread("Copy %s to: ", toname + off, sizeof toname - off,
EFNEW | EFCR, basename(frname))) != TRUE)
return (stat);
stat = (copy(frname, toname) >= 0) ? TRUE : FALSE;
if (stat != TRUE)
return (stat);
bp = dired_(curbp->b_fname);
return (showbuffer(bp, curwp, WFHARD | WFMODE));
}
/* ARGSUSED */
int
d_rename(int f, int n)
{
char frname[NFILEN], toname[NFILEN];
int stat, off;
BUFFER *bp;
if (d_makename(curwp->w_dotp, frname, sizeof frname) != FALSE) {
ewprintf("Not a file");
return FALSE;
}
off = strlcpy(toname, curbp->b_fname, sizeof toname);
if (off >= sizeof toname - 1) { /* can't happen, really */
ewprintf("too long directory name");
return (FALSE);
}
if ((stat = eread("Rename %s to: ", toname + off,
sizeof toname - off, EFNEW | EFCR, basename(frname))) != TRUE)
return stat;
stat = (rename(frname, toname) >= 0) ? TRUE : FALSE;
if (stat != TRUE)
return (stat);
bp = dired_(curbp->b_fname);
return (showbuffer(bp, curwp, WFHARD | WFMODE));
}
#endif
void
reaper(int signo __attribute__((unused)))
{
pid_t ret;
int status;
while ((ret = waitpid(-1, &status, WNOHANG)) >= 0)
;
}
/*
* Pipe the currently selected file through a shell command.
*/
int
d_shell_command(int f, int n)
{
char command[512], fname[MAXPATHLEN], buf[BUFSIZ], *cp;
int infd, fds[2];
pid_t pid;
struct sigaction olda, newa;
BUFFER *bp;
MGWIN *wp;
FILE *fin;
bp = bfind("*Shell Command Output*", TRUE);
if (bclear(bp) != TRUE)
return (ABORT);
if (d_makename(curwp->w_dotp, fname, sizeof fname) != FALSE) {
ewprintf("bad line");
return (ABORT);
}
command[0] = '\0';
if (eread("! on %s: ", command, sizeof command, 0,
basename(fname)) == ABORT)
return (ABORT);
infd = open(fname, O_RDONLY);
if (infd == -1) {
ewprintf("Can't open input file : %s", strerror(errno));
return (ABORT);
}
if (pipe(fds) == -1) {
ewprintf("Can't create pipe : %s", strerror(errno));
close(infd);
return (ABORT);
}
newa.sa_handler = reaper;
newa.sa_flags = 0;
if (sigaction(SIGCHLD, &newa, &olda) == -1) {
close(infd);
close(fds[0]);
close(fds[1]);
return (ABORT);
}
pid = fork();
switch (pid) {
case -1:
ewprintf("Can't fork");
return (ABORT);
case 0:
close(fds[0]);
dup2(infd, STDIN_FILENO);
dup2(fds[1], STDOUT_FILENO);
dup2(fds[1], STDERR_FILENO);
execl("/bin/sh", "sh", "-c", command, (char *)NULL);
exit(1);
default:
close(infd);
close(fds[1]);
fin = fdopen(fds[0], "r");
if (fin == NULL) /* "r" is surely a valid mode! */
panic("can't happen");
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);
while ((c = getc(fin)) != EOF && c != '\n')
;
continue;
} else if (cp)
*cp = '\0';
addline(bp, buf);
}
fclose(fin);
close(fds[0]);
break;
}
wp = popbuf(bp);
if (wp == NULL)
return (ABORT); /* XXX - free the buffer?? */
curwp = wp;
curbp = wp->w_bufp;
if (sigaction(SIGCHLD, &olda, NULL) == -1)
ewprintf("Warning, couldn't reset previous signal handler");
return (TRUE);
}
int
d_create_directory(int f, int n)
{
char tocreate[MAXPATHLEN], off;
int stat;
BUFFER *bp;
off = strlcpy(tocreate, curbp->b_fname, sizeof tocreate);
if (off >= sizeof tocreate - 1)
return (FALSE);
if ((stat = ereply("Create directory: ", tocreate + off,
sizeof tocreate - off))
!= TRUE)
return (stat);
if (mkdir(tocreate, 0755) == -1) {
ewprintf("Creating directory: %s, %s", strerror(errno),
tocreate);
return (ABORT);
}
bp = dired_(curbp->b_fname);
return (showbuffer(bp, curwp, WFHARD | WFMODE));
}