> > The warpdot() has at least one issue. It leads to 
> > segfaults if you try to open a directory like (BCD).

New diff below.  I wanted to make d_warpdot behave exactly
like the rest of mg functions in that it'd take the two standard
int (f, n) arguments, and dereference curwp->* to do its job.
This was sort of a dead end, since curwp is only set after
everything's been done and the various places that call
dired_() have also called showbuffer() (or the alternative).
All of these would've needed an additional function call, or
a lot of restructuring.

Instead I made warpdot take the line pointer (dotp) and
a pointer to doto, giving it all it needs to operate on
the line mostly like the rest of mg.  Now it does the usual
end-of-line check by comparing doto to llength().  Looking
for the NUL byte while iterating over the string was never
the right approach for l_text.

These changes mean dired_() can no longer do horrible evil
like computing the dot offset based on an internal char array
which may or may not reflect the reality of what's actually in
the buffer.  This is what caused the segfaults you noticed.

It follows that the "first entry after .." logic is no longer
interleaved with a bunch of unrelated stuff.  Now it's done
in a separate step after all the ls output has been read.

I also noticed some missing names in the list of keybindings,
and added corresponding funmap_add lines.

Index: dired.c
===================================================================
RCS file: /cvs/src/usr.bin/mg/dired.c,v
retrieving revision 1.48
diff -u -p -r1.48 dired.c
--- dired.c     23 Jan 2011 00:45:03 -0000      1.48
+++ dired.c     27 Aug 2011 22:32:36 -0000
@@ -36,6 +36,11 @@ static int    d_rename(int, int);
 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;
@@ -57,15 +62,15 @@ static PF dirednul[] = {
 static PF diredcl[] = {
        reposition,             /* ^L */
        d_findfile,             /* ^M */
-       forwline,               /* ^N */
+       d_forwline,             /* ^N */
        rescan,                 /* ^O */
-       backline,               /* ^P */
+       d_backline,             /* ^P */
        rescan,                 /* ^Q */
        backisearch,            /* ^R */
        forwisearch,            /* ^S */
        rescan,                 /* ^T */
        universal_argument,     /* ^U */
-       forwpage,               /* ^V */
+       d_forwpage,             /* ^V */
        rescan,                 /* ^W */
        NULL                    /* ^X */
 };
@@ -77,7 +82,7 @@ static PF diredcz[] = {
        rescan,                 /* ^] */
        rescan,                 /* ^^ */
        rescan,                 /* ^_ */
-       forwline,               /* SP */
+       d_forwline,             /* SP */
        d_shell_command,        /* ! */
        rescan,                 /* " */
        rescan,                 /* # */
@@ -99,9 +104,9 @@ static PF diredc[] = {
 };
 
 static PF diredn[] = {
-       forwline,               /* n */
+       d_forwline,             /* n */
        d_ffotherwindow,        /* o */
-       backline,               /* p */
+       d_backline,             /* p */
        rescan,                 /* q */
        d_rename,               /* r */
        rescan,                 /* s */
@@ -116,13 +121,32 @@ 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 (6 + NDIRED_XMAPS + IMAPEXT) diredmap = {
-       6 + NDIRED_XMAPS,
-       6 + NDIRED_XMAPS + IMAPEXT,
+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,
        {
 #ifndef NO_HELP
@@ -138,6 +162,10 @@ static struct KEYMAPE (6 + NDIRED_XMAPS 
                        CCHR('L'), CCHR('X'), diredcl, (KEYMAP *) & cXmap
                },
                {
+                       CCHR('['), CCHR('['), dirednull, (KEYMAP *) & 
+                       d_backpagemap
+               },
+               {
                        CCHR('Z'), '+', diredcz, (KEYMAP *) & metamap
                },
                {
@@ -165,8 +193,12 @@ dired_init(void)
        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");
@@ -592,6 +624,58 @@ d_makename(struct line *lp, char *fn, si
        return ((lgetc(lp, 2) == 'd') ? TRUE : FALSE);
 }
 
+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++] == ' ') {
+                       /* Skip the space. */
+                       while (off < len && tp[off] == ' ')
+                               off++;
+                       if (++field == 9)
+                               break;
+               }
+       }
+       *doto = off;
+       return (TRUE);
+}
+
+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 '/'.
  */
@@ -601,9 +685,7 @@ dired_(char *dname)
        struct buffer   *bp;
        FILE    *dirpipe;
        char     line[256];
-       int      len, ret, counter, warp;
-       counter = 0;
-       warp = 0;
+       int      len, ret, i;
 
        if ((fopen(dname,"r")) == NULL) {
                if (errno == EACCES)
@@ -640,26 +722,29 @@ dired_(char *dname)
        while (fgets(&line[2], sizeof(line) - 2, dirpipe) != NULL) {
                line[strcspn(line, "\n")] = '\0'; /* remove ^J   */
                (void) addline(bp, line);
-               if ((strrchr(line,' ')) != NULL) {
-                       counter++;
-                       if ((strcmp((strrchr(line,' '))," ..")) == 0)  
-                               warp = counter;
-               }
        }
-       if ((strrchr(line,' ')) != NULL) {
-               if (strcmp((strrchr(line,' '))," ..") == 0) 
-                       warp = counter - 1;
-       }               
-       if ((strrchr(line,' ')) != NULL)
-               bp->b_doto = strrchr(line,' ') - line + 1;
        if (pclose(dirpipe) == -1) {
                ewprintf("Problem closing pipe to ls : %s",
                    strerror(errno));
                return (NULL);
        }
+
+       /* Find the line with ".." on it. */
        bp->b_dotp = bfirstlp(bp);
-       while (warp--)
-               bp->b_dotp  = lforw(bp->b_dotp);
+       for (i = 0; i < bp->b_lines; i++) {
+               bp->b_dotp = lforw(bp->b_dotp);
+               d_warpdot(bp->b_dotp, &bp->b_doto);
+               if (bp->b_doto >= llength(bp->b_dotp))
+                       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) {

Reply via email to