[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.23, Thu Oct 13 05:47:44 2005 UTC (18 years, 8 months ago) by kjell
Branch: MAIN
Changes since 1.22: +115 -94 lines

Fix dired mode. Make deletions work, and keystrokes match emacs.
* dired-other-window should default to current buffer's path.
* Remove redundant code (from Han Boetes)
* Move initialization (and since we're here, fix mail-mode initialization
  too)
* Remove redundant keymap in dired.c, and replace it with
  the better one that was being ignored in keymap.c.

/*	$OpenBSD: dired.c,v 1.23 2005/10/13 05:47:44 kjell Exp $	*/

/* This file is in the public domain. */

/* 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

void dired_init(void);

extern struct keymap_s helpmap, cXmap, metamap;

static PF dirednul[] = {
	setmark,		/* ^@ */
	gotobol,		/* ^A */
	backchar,		/* ^B */
	rescan,			/* ^C */
	d_del,			/* ^D */
	gotoeol,		/* ^E */
	forwchar,		/* ^F */
	ctrlg,			/* ^G */
#ifndef NO_HELP
	NULL,			/* ^H */
#endif /* !NO_HELP */
};

static PF diredcl[] = {
	reposition,		/* ^L */
	d_findfile,		/* ^M */
	forwline,		/* ^N */
	rescan,			/* ^O */
	backline,		/* ^P */
	rescan,			/* ^Q */
	backisearch,		/* ^R */
	forwisearch,		/* ^S */
	rescan,			/* ^T */
	universal_argument,	/* ^U */
	forwpage,		/* ^V */
	rescan,			/* ^W */
	NULL			/* ^X */
};

static PF diredcz[] = {
	spawncli,		/* ^Z */
	NULL,			/* esc */
	rescan,			/* ^\ */
	rescan,			/* ^] */
	rescan,			/* ^^ */
	rescan,			/* ^_ */
	forwline		/* SP */
};

static PF diredc[] = {
	d_copy,			/* c */
	d_del,			/* d */
	d_findfile,		/* e */
	d_findfile		/* f */
};

static PF diredn[] = {
	forwline,		/* n */
	d_ffotherwindow,	/* o */
	backline,		/* p */
	rescan,			/* q */
	d_rename,		/* r */
	rescan,			/* s */
	rescan,			/* t */
	d_undel,		/* u */
	rescan,			/* v */
	rescan,			/* w */
	d_expunge		/* x */
};

static PF direddl[] = {
	d_undelbak		/* del */
};

#ifndef	DIRED_XMAPS
#define	NDIRED_XMAPS	0	/* number of extra map sections */
#endif /* DIRED_XMAPS */

static struct KEYMAPE (6 + NDIRED_XMAPS + IMAPEXT) diredmap = {
	6 + NDIRED_XMAPS,
	6 + NDIRED_XMAPS + IMAPEXT,
	rescan,
	{
#ifndef NO_HELP
		{
			CCHR('@'), CCHR('H'), dirednul, (KEYMAP *) & helpmap
		},
#else /* !NO_HELP */
		{
			CCHR('@'), CCHR('G'), dirednul, NULL
		},
#endif /* !NO_HELP */
		{
			CCHR('L'), CCHR('X'), diredcl, (KEYMAP *) & cXmap
		},
		{
			CCHR('Z'), ' ', diredcz, (KEYMAP *) & metamap
		},
		{
			'c', 'f', diredc, NULL
		},
		{
			'n', 'x', diredn, NULL
		},
		{
			CCHR('?'), CCHR('?'), direddl, NULL
		},
#ifdef	DIRED_XMAPS
		DIRED_XMAPS,	/* map sections for dired mode keys	 */
#endif /* DIRED_XMAPS */
	}
};

void
dired_init(void)
{
	maps_add((KEYMAP *)&diredmap, "dired");
}

/* ARGSUSED */
int
dired(int f, int n)
{
	char	     dirname[NFILEN], *bufp, *slash;
	BUFFER	    *bp;

	if (curbp->b_fname && curbp->b_fname[0] != '\0') {
		(void)strlcpy(dirname, curbp->b_fname, sizeof(dirname));
		if ((slash = strrchr(dirname, '/')) != NULL) {
			*(slash + 1) = '\0';
		}
	} else {
		if (getcwd(dirname, sizeof(dirname)) == NULL)
			dirname[0] = '\0';
	}

	if ((bufp = eread("Dired: ", dirname, NFILEN,
	    EFDEF | EFNEW | EFCR)) == NULL)
		return (ABORT);
	if (bufp[0] == '\0')
		return (FALSE);
	if ((bp = dired_(bufp)) == NULL)
		return (FALSE);

	curbp = bp;
	return (showbuffer(bp, curwp, WFHARD | WFMODE));
}

/* ARGSUSED */
int
d_otherwindow(int f, int n)
{
	char	 dirname[NFILEN], *bufp, *slash;
	BUFFER	*bp;
	MGWIN	*wp;

	if (curbp->b_fname && curbp->b_fname[0] != '\0') {
		(void)strlcpy(dirname, curbp->b_fname, sizeof(dirname));
		if ((slash = strrchr(dirname, '/')) != NULL) {
			*(slash + 1) = '\0';
		}
	} else {
		if (getcwd(dirname, sizeof(dirname)) == NULL)
			dirname[0] = '\0';
	}

	if ((bufp = eread("Dired other window: ", dirname, NFILEN,
	    EFDEF | EFNEW | EFCR)) == NULL)
		return (ABORT);
	else if (bufp[0] == '\0')
		return (FALSE);
	if ((bp = dired_(bufp)) == 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], *bufp;
	int	stat;
	size_t	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("Directory name too long");
		return (FALSE);
	}
	if ((bufp = eread("Copy %s to: ", toname, sizeof(toname),
	    EFDEF | EFNEW | EFCR, basename(frname))) == NULL)
		return (ABORT);
	else if (bufp[0] == '\0')
		return (FALSE);
	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], *bufp;
	int	stat;
	size_t	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("Directory name too long");
		return (FALSE);
	}
	if ((bufp = eread("Rename %s to: ", toname,
	    sizeof(toname), EFDEF | EFNEW | EFCR, basename(frname))) == NULL)
		return (ABORT);
	else if (bufp[0] == '\0')
		return (FALSE);
	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)))
{
	int	save_errno = errno, status;
	pid_t	ret;

	while ((ret = waitpid(-1, &status, WNOHANG)) >= 0)
		;
	errno = save_errno;
}

/*
 * Pipe the currently selected file through a shell command.
 */
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;
	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 ((bufp = eread("! on %s: ", command, sizeof(command), EFNEW,
	    basename(fname))) == NULL)
		return (ABORT);
	infd = open(fname, O_RDONLY);
	if (infd == -1) {
		ewprintf("Can't open input file : %s", strerror(errno));
		return (FALSE);
	}
	if (pipe(fds) == -1) {
		ewprintf("Can't create pipe : %s", strerror(errno));
		close(infd);
		return (FALSE);
	}

	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", bufp, (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], *bufp;
	size_t  off;
	BUFFER	*bp;

	off = strlcpy(tocreate, curbp->b_fname, sizeof(tocreate));
	if (off >= sizeof(tocreate) - 1)
		return (FALSE);
	if ((bufp = eread("Create directory: ", tocreate,
	    sizeof(tocreate), EFDEF | EFNEW | EFCR)) == NULL)
		return (ABORT);
	else if (bufp[0] == '\0')
		return (FALSE);
	if (mkdir(tocreate, 0755) == -1) {
		ewprintf("Creating directory: %s, %s", strerror(errno),
		    tocreate);
		return (FALSE);
	}
	bp = dired_(curbp->b_fname);
	return (showbuffer(bp, curwp, WFHARD | WFMODE));
}