> > 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) {