summaryrefslogtreecommitdiff
path: root/usr.bin/mg/dired.c
diff options
context:
space:
mode:
authorMark Lumsden <lum@cvs.openbsd.org>2015-10-12 19:08:40 +0000
committerMark Lumsden <lum@cvs.openbsd.org>2015-10-12 19:08:40 +0000
commitbef9fbc9c42535416b8c2c7060a9b4d7d640ad2d (patch)
treec63e3d229978bb8e39c9545a55b921c3cc03dc59 /usr.bin/mg/dired.c
parent7c050e2a5bcfd91ff2adc349e49d2fedde256dac (diff)
Maintain a list of files marked for deletion while refreshing a dired
buffer. Previously, when refreshing the buffer the files marked for deletion would be lost. Since the relationship between the files that have been marked for deletion and those that exist on disk is volatile, I have chosen to implement the discovery of marked files during the refresh function as opposed to maintaining a dired buffer specific list.
Diffstat (limited to 'usr.bin/mg/dired.c')
-rw-r--r--usr.bin/mg/dired.c188
1 files changed, 179 insertions, 9 deletions
diff --git a/usr.bin/mg/dired.c b/usr.bin/mg/dired.c
index 4d943d49f34..3fb6199c4a6 100644
--- a/usr.bin/mg/dired.c
+++ b/usr.bin/mg/dired.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dired.c,v 1.77 2015/09/28 11:56:17 lum Exp $ */
+/* $OpenBSD: dired.c,v 1.78 2015/10/12 19:08:39 lum Exp $ */
/* This file is in the public domain. */
@@ -53,9 +53,24 @@ static int d_killbuffer_cmd(int, int);
static int d_refreshbuffer(int, int);
static void reaper(int);
static struct buffer *refreshbuffer(struct buffer *);
+static int createlist(struct buffer *);
+static void redelete(struct buffer *);
+static char *findfname(struct line *, char *);
extern struct keymap_s helpmap, cXmap, metamap;
+const char DDELCHAR = 'D';
+
+/*
+ * Structure which holds a linked list of file names marked for
+ * deletion. Used to maintain dired buffer 'state' between refreshes.
+ */
+struct delentry {
+ SLIST_ENTRY(delentry) entry;
+ char *fn;
+};
+SLIST_HEAD(slisthead, delentry) delhead = SLIST_HEAD_INITIALIZER(delhead);
+
static PF dirednul[] = {
setmark, /* ^@ */
gotobol, /* ^A */
@@ -271,8 +286,10 @@ 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 (llength(curwp->w_dotp) > 0) {
+ lputc(curwp->w_dotp, 0, DDELCHAR);
+ curbp->b_flag |= BFDIREDDEL;
+ }
if (lforw(curwp->w_dotp) != curbp->b_headp) {
curwp->w_dotp = lforw(curwp->w_dotp);
curwp->w_dotline++;
@@ -414,6 +431,10 @@ d_expunge(int f, int n)
}
curwp->w_dotline = tmp;
d_warpdot(curwp->w_dotp, &curwp->w_doto);
+
+ /* we have deleted all items successfully, remove del flag */
+ curbp->b_flag &= ~BFDIREDDEL;
+
return (TRUE);
}
@@ -692,26 +713,54 @@ d_refreshbuffer(int f, int n)
return (showbuffer(bp, curwp, WFFULL | WFMODE));
}
+/*
+ * Kill then re-open the requested dired buffer.
+ * If required, take a note of any files marked for deletion. Then once
+ * the buffer has been re-opened, remark the same files as deleted.
+ */
struct buffer *
refreshbuffer(struct buffer *bp)
{
- char *tmp;
+ char *tmp_b_fname;
+ int i, tmp_w_dotline, ddel = 0;
- tmp = strdup(bp->b_fname);
- if (tmp == NULL) {
+ /* remember directory path to open later */
+ tmp_b_fname = strdup(bp->b_fname);
+ if (tmp_b_fname == NULL) {
dobeep();
ewprintf("Out of memory");
return (NULL);
}
+ tmp_w_dotline = curwp->w_dotline;
+
+ /* create a list of files for deletion */
+ if (bp->b_flag & BFDIREDDEL)
+ ddel = createlist(bp);
killbuffer(bp);
/* dired_() uses findbuffer() to create new buffer */
- if ((bp = dired_(tmp)) == NULL) {
- free(tmp);
+ if ((bp = dired_(tmp_b_fname)) == NULL) {
+ free(tmp_b_fname);
return (NULL);
}
- free(tmp);
+ free(tmp_b_fname);
+
+ /* remark any previously deleted files with a 'D' */
+ if (ddel)
+ redelete(bp);
+
+ /* find dot line */
+ bp->b_dotp = bfirstlp(bp);
+ if (tmp_w_dotline > bp->b_lines)
+ tmp_w_dotline = bp->b_lines - 1;
+ for (i = 1; i < tmp_w_dotline; i++)
+ bp->b_dotp = lforw(bp->b_dotp);
+
+ bp->b_dotline = i;
+ bp->b_doto = 0;
+ d_warpdot(bp->b_dotp, &bp->b_doto);
+
curbp = bp;
return (bp);
@@ -866,3 +915,124 @@ dired_(char *dname)
bp->b_nmodes = 1;
return (bp);
}
+
+/*
+ * Iterate through the lines of the dired buffer looking for files
+ * collected in the linked list made in createlist(). If a line is found
+ * replace 'D' as first char in a line. As lines are found, remove the
+ * corresponding item from the linked list. Iterate for as long as there
+ * are items in the linked list or until end of buffer is found.
+ */
+void
+redelete(struct buffer *bp)
+{
+ struct delentry *d1 = NULL;
+ struct line *lp, *nlp;
+ char fname[NFILEN];
+ char *p = fname;
+ size_t plen, fnlen;
+ int finished = 0;
+
+ /* reset the deleted file buffer flag until a deleted file is found */
+ bp->b_flag &= ~BFDIREDDEL;
+
+ for (lp = bfirstlp(bp); lp != bp->b_headp; lp = nlp) {
+ bp->b_dotp = lp;
+ if ((p = findfname(lp, p)) == NULL) {
+ nlp = lforw(lp);
+ continue;
+ }
+ plen = strlen(p);
+ SLIST_FOREACH(d1, &delhead, entry) {
+ fnlen = strlen(d1->fn);
+ if ((plen == fnlen) &&
+ (strncmp(p, d1->fn, plen) == 0)) {
+ lputc(bp->b_dotp, 0, DDELCHAR);
+ bp->b_flag |= BFDIREDDEL;
+ SLIST_REMOVE(&delhead, d1, delentry, entry);
+ if (SLIST_EMPTY(&delhead)) {
+ finished = 1;
+ break;
+ }
+ }
+ }
+ if (finished)
+ break;
+ nlp = lforw(lp);
+ }
+ while (!SLIST_EMPTY(&delhead)) {
+ d1 = SLIST_FIRST(&delhead);
+ SLIST_REMOVE_HEAD(&delhead, entry);
+ free(d1->fn);
+ free(d1);
+ }
+ return;
+}
+
+/*
+ * Create a list of files marked for deletion.
+ */
+int
+createlist(struct buffer *bp)
+{
+ struct delentry *d1 = NULL, *d2;
+ struct line *lp, *nlp;
+ char fname[NFILEN];
+ char *p = fname;
+ int ret = FALSE;
+
+ for (lp = bfirstlp(bp); lp != bp->b_headp; lp = nlp) {
+ /*
+ * Check if the line has 'D' on the first char and if a valid
+ * filename can be extracted from it.
+ */
+ if (((lp->l_text[0] != DDELCHAR)) ||
+ ((p = findfname(lp, p)) == NULL)) {
+ nlp = lforw(lp);
+ continue;
+ }
+ if (SLIST_EMPTY(&delhead)) {
+ if ((d1 = malloc(sizeof(struct delentry)))
+ == NULL)
+ return (ABORT);
+ if ((d1->fn = strdup(p)) == NULL) {
+ free(d1);
+ return (ABORT);
+ }
+ SLIST_INSERT_HEAD(&delhead, d1, entry);
+ } else {
+ if ((d2 = malloc(sizeof(struct delentry)))
+ == NULL) {
+ free(d1->fn);
+ free(d1);
+ return (ABORT);
+ }
+ if ((d2->fn = strdup(p)) == NULL) {
+ free(d1->fn);
+ free(d1);
+ free(d2);
+ return (ABORT);
+ }
+ SLIST_INSERT_AFTER(d1, d2, entry);
+ d1 = d2;
+ }
+ ret = TRUE;
+ nlp = lforw(lp);
+ }
+ return (ret);
+}
+
+/*
+ * Look for and extract a file name on a dired buffer line.
+ */
+char *
+findfname(struct line *lp, char *fn)
+{
+ int start;
+
+ (void)d_warpdot(lp, &start);
+ if (start < 1)
+ return NULL;
+ fn = &lp->l_text[start];
+ return fn;
+}