[BACK]Return to dired.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

File: [local] / src / usr.bin / mg / dired.c (download)

Revision 1.13, Sat Aug 16 00:24:51 2003 UTC (20 years, 9 months ago) by deraadt
Branch: MAIN
CVS Tags: OPENBSD_3_5_BASE, OPENBSD_3_5, OPENBSD_3_4_BASE, OPENBSD_3_4
Changes since 1.12: +2 -2 lines

spacing

/*	$OpenBSD: dired.c,v 1.13 2003/08/16 00:24:51 deraadt 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));
}