]> pd.if.org Git - pd_readline/blobdiff - mg/dired.c
Added mg from an OpenBSD mirror site. Many thanks to the OpenBSD team and the mg...
[pd_readline] / mg / dired.c
diff --git a/mg/dired.c b/mg/dired.c
new file mode 100644 (file)
index 0000000..184c9f7
--- /dev/null
@@ -0,0 +1,779 @@
+/*     $OpenBSD: dired.c,v 1.51 2012/03/14 13:56:35 lum Exp $  */
+
+/* This file is in the public domain. */
+
+/* dired module for mg 2a
+ * by Robert A. Larson
+ */
+
+#include "def.h"
+#include "funmap.h"
+#include "kbd.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <libgen.h>
+#include <stdarg.h>
+
+void            dired_init(void);
+static int      dired(int, int);
+static int      d_otherwindow(int, int);
+static int      d_undel(int, int);
+static int      d_undelbak(int, int);
+static int      d_findfile(int, int);
+static int      d_ffotherwindow(int, int);
+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);
+static int      d_warpdot(struct line *, int *);
+static int      d_forwpage(int, int);
+static int      d_backpage(int, int);
+static int      d_forwline(int, int);
+static int      d_backline(int, int);
+static void     reaper(int);
+
+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 */
+       NULL,                   /* ^H */
+};
+
+static PF diredcl[] = {
+       reposition,             /* ^L */
+       d_findfile,             /* ^M */
+       d_forwline,             /* ^N */
+       rescan,                 /* ^O */
+       d_backline,             /* ^P */
+       rescan,                 /* ^Q */
+       backisearch,            /* ^R */
+       forwisearch,            /* ^S */
+       rescan,                 /* ^T */
+       universal_argument,     /* ^U */
+       d_forwpage,             /* ^V */
+       rescan,                 /* ^W */
+       NULL                    /* ^X */
+};
+
+static PF diredcz[] = {
+       spawncli,               /* ^Z */
+       NULL,                   /* esc */
+       rescan,                 /* ^\ */
+       rescan,                 /* ^] */
+       rescan,                 /* ^^ */
+       rescan,                 /* ^_ */
+       d_forwline,             /* SP */
+       d_shell_command,        /* ! */
+       rescan,                 /* " */
+       rescan,                 /* # */
+       rescan,                 /* $ */
+       rescan,                 /* % */
+       rescan,                 /* & */
+       rescan,                 /* ' */
+       rescan,                 /* ( */
+       rescan,                 /* ) */
+       rescan,                 /* * */
+       d_create_directory      /* + */
+};
+
+static PF diredc[] = {
+       d_copy,                 /* c */
+       d_del,                  /* d */
+       d_findfile,             /* e */
+       d_findfile              /* f */
+};
+
+static PF diredn[] = {
+       d_forwline,             /* n */
+       d_ffotherwindow,        /* o */
+       d_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 */
+};
+
+static PF diredbp[] = {
+       d_backpage              /* v */ 
+};
+
+static PF dirednull[] = {
+       NULL
+};
+
+#ifndef        DIRED_XMAPS
+#define        NDIRED_XMAPS    0       /* number of extra map sections */
+#endif /* DIRED_XMAPS */
+
+static struct KEYMAPE (1 + IMAPEXT) d_backpagemap = {
+       1,
+       1 + IMAPEXT,
+       rescan,                 
+       {
+               {
+               'v', 'v', diredbp, NULL
+               }
+       }
+};
+
+static struct KEYMAPE (7 + NDIRED_XMAPS + IMAPEXT) diredmap = {
+       7 + NDIRED_XMAPS,
+       7 + NDIRED_XMAPS + IMAPEXT,
+       rescan,
+       {
+               {
+                       CCHR('@'), CCHR('H'), dirednul, (KEYMAP *) & helpmap
+               },
+               {
+                       CCHR('L'), CCHR('X'), diredcl, (KEYMAP *) & cXmap
+               },
+               {
+                       CCHR('['), CCHR('['), dirednull, (KEYMAP *) & 
+                       d_backpagemap
+               },
+               {
+                       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)
+{
+       funmap_add(dired, "dired");
+       funmap_add(d_undelbak, "dired-backup-unflag");
+       funmap_add(d_copy, "dired-copy-file");
+       funmap_add(d_expunge, "dired-do-deletions");
+       funmap_add(d_findfile, "dired-find-file");
+       funmap_add(d_ffotherwindow, "dired-find-file-other-window");
+       funmap_add(d_del, "dired-flag-file-deleted");
+       funmap_add(d_forwline, "dired-next-line");
+       funmap_add(d_otherwindow, "dired-other-window");
+       funmap_add(d_backline, "dired-previous-line");
+       funmap_add(d_rename, "dired-rename-file");
+       funmap_add(d_backpage, "dired-scroll-down");
+       funmap_add(d_forwpage, "dired-scroll-up");
+       funmap_add(d_undel, "dired-unflag");
+       maps_add((KEYMAP *)&diredmap, "dired");
+       dobindkey(fundamental_map, "dired", "^Xd");
+}
+
+/* ARGSUSED */
+int
+dired(int f, int n)
+{
+       char             dname[NFILEN], *bufp, *slash;
+       struct buffer   *bp;
+
+       if (curbp->b_fname && curbp->b_fname[0] != '\0') {
+               (void)strlcpy(dname, curbp->b_fname, sizeof(dname));
+               if ((slash = strrchr(dname, '/')) != NULL) {
+                       *(slash + 1) = '\0';
+               }
+       } else {
+               if (getcwd(dname, sizeof(dname)) == NULL)
+                       dname[0] = '\0';
+       }
+
+       if ((bufp = eread("Dired: ", dname, 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, WFFULL | WFMODE));
+}
+
+/* ARGSUSED */
+int
+d_otherwindow(int f, int n)
+{
+       char             dname[NFILEN], *bufp, *slash;
+       struct buffer   *bp;
+       struct mgwin    *wp;
+
+       if (curbp->b_fname && curbp->b_fname[0] != '\0') {
+               (void)strlcpy(dname, curbp->b_fname, sizeof(dname));
+               if ((slash = strrchr(dname, '/')) != NULL) {
+                       *(slash + 1) = '\0';
+               }
+       } else {
+               if (getcwd(dname, sizeof(dname)) == NULL)
+                       dname[0] = '\0';
+       }
+
+       if ((bufp = eread("Dired other window: ", dname, 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, WNONE)) == 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_headp)
+                       curwp->w_dotp = lforw(curwp->w_dotp);
+       }
+       curwp->w_rflag |= 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_headp)
+                       curwp->w_dotp = lforw(curwp->w_dotp);
+       }
+       curwp->w_rflag |= 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_headp)
+                       curwp->w_dotp = lback(curwp->w_dotp);
+       }
+       curwp->w_doto = 0;
+       curwp->w_rflag |= WFEDIT | WFMOVE;
+       return (TRUE);
+}
+
+/* ARGSUSED */
+int
+d_findfile(int f, int n)
+{
+       struct 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, WFFULL) != 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;
+       struct buffer   *bp;
+       struct 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, WNONE)) == 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)
+{
+       struct line     *lp, *nlp;
+       char             fname[NFILEN], sname[NFILEN];
+
+       for (lp = bfirstlp(curbp); lp != curbp->b_headp; 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) {
+                                       (void)xbasename(sname, fname, NFILEN);
+                                       ewprintf("Could not delete '%s'", sname);
+                                       return (FALSE);
+                               }
+                               break;
+                       case TRUE:
+                               if (rmdir(fname) < 0) {
+                                       (void)xbasename(sname, fname, NFILEN);
+                                       ewprintf("Could not delete directory "
+                                           "'%s'", sname);
+                                       return (FALSE);
+                               }
+                               break;
+                       }
+                       lfree(lp);
+                       curwp->w_bufp->b_lines--;
+                       curwp->w_rflag |= WFFULL;
+               }
+       }
+       return (TRUE);
+}
+
+/* ARGSUSED */
+int
+d_copy(int f, int n)
+{
+       char    frname[NFILEN], toname[NFILEN], sname[NFILEN], *bufp;
+       int     ret;
+       size_t  off;
+       struct 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);
+       }
+       (void)xbasename(sname, frname, NFILEN);
+       bufp = eread("Copy %s to: ", toname, sizeof(toname),
+           EFDEF | EFNEW | EFCR, sname);
+       if (bufp == NULL) 
+               return (ABORT);
+       else if (bufp[0] == '\0')
+               return (FALSE);
+       ret = (copy(frname, toname) >= 0) ? TRUE : FALSE;
+       if (ret != TRUE)
+               return (ret);
+       bp = dired_(curbp->b_fname);
+       return (showbuffer(bp, curwp, WFFULL | WFMODE));
+}
+
+/* ARGSUSED */
+int
+d_rename(int f, int n)
+{
+       char             frname[NFILEN], toname[NFILEN], *bufp;
+       int              ret;
+       size_t           off;
+       struct buffer   *bp;
+       char             sname[NFILEN];
+
+       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);
+       }
+       (void)xbasename(sname, frname, NFILEN);
+       bufp = eread("Rename %s to: ", toname,
+           sizeof(toname), EFDEF | EFNEW | EFCR, sname);
+       if (bufp == NULL)
+               return (ABORT);
+       else if (bufp[0] == '\0')
+               return (FALSE);
+       ret = (rename(frname, toname) >= 0) ? TRUE : FALSE;
+       if (ret != TRUE)
+               return (ret);
+       bp = dired_(curbp->b_fname);
+       return (showbuffer(bp, curwp, WFFULL | WFMODE));
+}
+
+/* ARGSUSED */
+void
+reaper(int signo __attribute__((unused)))
+{
+       int     save_errno = errno, status;
+
+       while (waitpid(-1, &status, WNOHANG) >= 0)
+               ;
+       errno = save_errno;
+}
+
+/*
+ * Pipe the currently selected file through a shell command.
+ */
+/* ARGSUSED */
+int
+d_shell_command(int f, int n)
+{
+       char             command[512], fname[MAXPATHLEN], *bufp;
+       struct buffer   *bp;
+       struct mgwin    *wp;
+       char             sname[NFILEN];
+
+       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';
+       (void)xbasename(sname, fname, NFILEN);
+       bufp = eread("! on %s: ", command, sizeof(command), EFNEW, sname);
+       if (bufp == NULL)
+               return (ABORT);
+
+       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));
+               goto out;
+       }
+
+       if (pipe(fds) == -1) {
+               ewprintf("Can't create pipe : %s", strerror(errno));
+               goto out;
+       }
+
+       newa.sa_handler = reaper;
+       newa.sa_flags = 0;
+       if (sigaction(SIGCHLD, &newa, NULL) == -1)
+               goto out;
+
+       if ((pid = fork()) == -1) {
+               ewprintf("Can't fork");
+               goto out;
+       }
+
+       switch (pid) {
+       case 0: /* Child */
+               close(fds[0]);
+               dup2(infd, STDIN_FILENO);
+               dup2(fds[1], STDOUT_FILENO);
+               dup2(fds[1], STDERR_FILENO);
+               if (execvp(argv[0], argv) == -1)
+                       ewprintf("Can't exec %s: %s", argv[0], strerror(errno));
+               exit(1);
+               break;
+       default: /* Parent */
+               close(infd);
+               close(fds[1]);
+               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%s...", space, "", buf);
+                               while ((c = getc(fin)) != EOF && c != '\n')
+                                       ;
+                               continue;
+                       } else if (cp)
+                               *cp = '\0';
+                       addlinef(bp, "%*s%s", space, "", buf);
+               }
+               fclose(fin);
+               break;
+       }
+       ret = (TRUE);
+
+out:
+       if (sigaction(SIGCHLD, &olda, NULL) == -1)
+               ewprintf("Warning, couldn't reset previous signal handler");
+       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 */
+int
+d_create_directory(int f, int n)
+{
+       char     tocreate[MAXPATHLEN], *bufp;
+       size_t  off;
+       struct 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, WFFULL | WFMODE));
+}
+
+static int
+d_makename(struct line *lp, char *fn, size_t len)
+{
+       int      start, nlen;
+       char    *namep;
+
+       if (d_warpdot(lp, &start) == FALSE)
+               return (ABORT);
+       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)
+{
+       char *tp = dotp->l_text;
+       int off = 0, field = 0, len;
+
+       /*
+        * Find the byte offset to the (space-delimited) filename
+        * field in formatted ls output.
+        */
+       len = llength(dotp);
+       while (off < len) {
+               if (tp[off++] == ' ') {
+                       if (++field == NAME_FIELD) {
+                               *doto = off;
+                               return (TRUE);
+                       }
+                       /* Skip the space. */
+                       while (off < len && tp[off] == ' ')
+                               off++;
+               }
+       }
+       /* We didn't find the field. */
+       *doto = 0;
+       return (FALSE);
+}
+
+static int
+d_forwpage(int f, int n) 
+{
+       forwpage(f | FFRAND, n);
+       return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
+}
+
+static int 
+d_backpage (int f, int n)
+{
+       backpage(f | FFRAND, n);
+       return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
+}
+
+static int
+d_forwline (int f, int n)
+{
+       forwline(f | FFRAND, n);
+       return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
+}
+
+static int
+d_backline (int f, int n)
+{
+       backline(f | FFRAND, n);
+       return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
+}
+
+/*
+ * XXX dname needs to have enough place to store an additional '/'.
+ */
+struct buffer *
+dired_(char *dname)
+{
+       struct buffer   *bp;
+       int              len, i;
+
+       if ((fopen(dname,"r")) == NULL) {
+               if (errno == EACCES)
+                       ewprintf("Permission denied");
+               return (NULL);
+       }
+       if ((dname = adjustname(dname, FALSE)) == NULL) {
+               ewprintf("Bad directory name");
+               return (NULL);
+       }
+       /* this should not be done, instead adjustname() should get a flag */
+       len = strlen(dname);
+       if (dname[len - 1] != '/') {
+               dname[len++] = '/';
+               dname[len] = '\0';
+       }
+       if ((bp = findbuffer(dname)) == NULL) {
+               ewprintf("Could not create buffer");
+               return (NULL);
+       }
+       if (bclear(bp) != TRUE)
+               return (NULL);
+       bp->b_flag |= BFREADONLY;
+
+       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);
+               if (d_warpdot(bp->b_dotp, &bp->b_doto) == FALSE)
+                       continue;
+               if (strcmp(ltext(bp->b_dotp) + bp->b_doto, "..") == 0)
+                       break;
+       }
+
+       /* We want dot on the entry right after "..", if possible. */
+       if (++i < bp->b_lines - 2)
+               bp->b_dotp = lforw(bp->b_dotp);
+       d_warpdot(bp->b_dotp, &bp->b_doto);
+
+       (void)strlcpy(bp->b_fname, dname, sizeof(bp->b_fname));
+       (void)strlcpy(bp->b_cwd, dname, sizeof(bp->b_cwd));
+       if ((bp->b_modes[1] = name_mode("dired")) == NULL) {
+               bp->b_modes[0] = name_mode("fundamental");
+               ewprintf("Could not find mode dired");
+               return (NULL);
+       }
+       bp->b_nmodes = 1;
+       return (bp);
+}