]> pd.if.org Git - pd_readline/blob - mg/dired.c
184c9f7de4ba44559cf30a9af7b7c3886d8740ec
[pd_readline] / mg / dired.c
1 /*      $OpenBSD: dired.c,v 1.51 2012/03/14 13:56:35 lum Exp $  */
2
3 /* This file is in the public domain. */
4
5 /* dired module for mg 2a
6  * by Robert A. Larson
7  */
8
9 #include "def.h"
10 #include "funmap.h"
11 #include "kbd.h"
12
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <sys/time.h>
16 #include <sys/resource.h>
17 #include <sys/wait.h>
18
19 #include <ctype.h>
20 #include <signal.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <libgen.h>
24 #include <stdarg.h>
25
26 void             dired_init(void);
27 static int       dired(int, int);
28 static int       d_otherwindow(int, int);
29 static int       d_undel(int, int);
30 static int       d_undelbak(int, int);
31 static int       d_findfile(int, int);
32 static int       d_ffotherwindow(int, int);
33 static int       d_expunge(int, int);
34 static int       d_copy(int, int);
35 static int       d_del(int, int);
36 static int       d_rename(int, int);
37 static int       d_exec(int, struct buffer *, const char *, const char *, ...);
38 static int       d_shell_command(int, int);
39 static int       d_create_directory(int, int);
40 static int       d_makename(struct line *, char *, size_t);
41 static int       d_warpdot(struct line *, int *);
42 static int       d_forwpage(int, int);
43 static int       d_backpage(int, int);
44 static int       d_forwline(int, int);
45 static int       d_backline(int, int);
46 static void      reaper(int);
47
48 extern struct keymap_s helpmap, cXmap, metamap;
49
50 static PF dirednul[] = {
51         setmark,                /* ^@ */
52         gotobol,                /* ^A */
53         backchar,               /* ^B */
54         rescan,                 /* ^C */
55         d_del,                  /* ^D */
56         gotoeol,                /* ^E */
57         forwchar,               /* ^F */
58         ctrlg,                  /* ^G */
59         NULL,                   /* ^H */
60 };
61
62 static PF diredcl[] = {
63         reposition,             /* ^L */
64         d_findfile,             /* ^M */
65         d_forwline,             /* ^N */
66         rescan,                 /* ^O */
67         d_backline,             /* ^P */
68         rescan,                 /* ^Q */
69         backisearch,            /* ^R */
70         forwisearch,            /* ^S */
71         rescan,                 /* ^T */
72         universal_argument,     /* ^U */
73         d_forwpage,             /* ^V */
74         rescan,                 /* ^W */
75         NULL                    /* ^X */
76 };
77
78 static PF diredcz[] = {
79         spawncli,               /* ^Z */
80         NULL,                   /* esc */
81         rescan,                 /* ^\ */
82         rescan,                 /* ^] */
83         rescan,                 /* ^^ */
84         rescan,                 /* ^_ */
85         d_forwline,             /* SP */
86         d_shell_command,        /* ! */
87         rescan,                 /* " */
88         rescan,                 /* # */
89         rescan,                 /* $ */
90         rescan,                 /* % */
91         rescan,                 /* & */
92         rescan,                 /* ' */
93         rescan,                 /* ( */
94         rescan,                 /* ) */
95         rescan,                 /* * */
96         d_create_directory      /* + */
97 };
98
99 static PF diredc[] = {
100         d_copy,                 /* c */
101         d_del,                  /* d */
102         d_findfile,             /* e */
103         d_findfile              /* f */
104 };
105
106 static PF diredn[] = {
107         d_forwline,             /* n */
108         d_ffotherwindow,        /* o */
109         d_backline,             /* p */
110         rescan,                 /* q */
111         d_rename,               /* r */
112         rescan,                 /* s */
113         rescan,                 /* t */
114         d_undel,                /* u */
115         rescan,                 /* v */
116         rescan,                 /* w */
117         d_expunge               /* x */
118 };
119
120 static PF direddl[] = {
121         d_undelbak              /* del */
122 };
123
124 static PF diredbp[] = {
125         d_backpage              /* v */ 
126 };
127
128 static PF dirednull[] = {
129         NULL
130 };
131
132 #ifndef DIRED_XMAPS
133 #define NDIRED_XMAPS    0       /* number of extra map sections */
134 #endif /* DIRED_XMAPS */
135
136 static struct KEYMAPE (1 + IMAPEXT) d_backpagemap = {
137         1,
138         1 + IMAPEXT,
139         rescan,                 
140         {
141                 {
142                 'v', 'v', diredbp, NULL
143                 }
144         }
145 };
146
147 static struct KEYMAPE (7 + NDIRED_XMAPS + IMAPEXT) diredmap = {
148         7 + NDIRED_XMAPS,
149         7 + NDIRED_XMAPS + IMAPEXT,
150         rescan,
151         {
152                 {
153                         CCHR('@'), CCHR('H'), dirednul, (KEYMAP *) & helpmap
154                 },
155                 {
156                         CCHR('L'), CCHR('X'), diredcl, (KEYMAP *) & cXmap
157                 },
158                 {
159                         CCHR('['), CCHR('['), dirednull, (KEYMAP *) & 
160                         d_backpagemap
161                 },
162                 {
163                         CCHR('Z'), '+', diredcz, (KEYMAP *) & metamap
164                 },
165                 {
166                         'c', 'f', diredc, NULL
167                 },
168                 {
169                         'n', 'x', diredn, NULL
170                 },
171                 {
172                         CCHR('?'), CCHR('?'), direddl, NULL
173                 },
174 #ifdef  DIRED_XMAPS
175                 DIRED_XMAPS,    /* map sections for dired mode keys      */
176 #endif /* DIRED_XMAPS */
177         }
178 };
179
180 void
181 dired_init(void)
182 {
183         funmap_add(dired, "dired");
184         funmap_add(d_undelbak, "dired-backup-unflag");
185         funmap_add(d_copy, "dired-copy-file");
186         funmap_add(d_expunge, "dired-do-deletions");
187         funmap_add(d_findfile, "dired-find-file");
188         funmap_add(d_ffotherwindow, "dired-find-file-other-window");
189         funmap_add(d_del, "dired-flag-file-deleted");
190         funmap_add(d_forwline, "dired-next-line");
191         funmap_add(d_otherwindow, "dired-other-window");
192         funmap_add(d_backline, "dired-previous-line");
193         funmap_add(d_rename, "dired-rename-file");
194         funmap_add(d_backpage, "dired-scroll-down");
195         funmap_add(d_forwpage, "dired-scroll-up");
196         funmap_add(d_undel, "dired-unflag");
197         maps_add((KEYMAP *)&diredmap, "dired");
198         dobindkey(fundamental_map, "dired", "^Xd");
199 }
200
201 /* ARGSUSED */
202 int
203 dired(int f, int n)
204 {
205         char             dname[NFILEN], *bufp, *slash;
206         struct buffer   *bp;
207
208         if (curbp->b_fname && curbp->b_fname[0] != '\0') {
209                 (void)strlcpy(dname, curbp->b_fname, sizeof(dname));
210                 if ((slash = strrchr(dname, '/')) != NULL) {
211                         *(slash + 1) = '\0';
212                 }
213         } else {
214                 if (getcwd(dname, sizeof(dname)) == NULL)
215                         dname[0] = '\0';
216         }
217
218         if ((bufp = eread("Dired: ", dname, NFILEN,
219             EFDEF | EFNEW | EFCR)) == NULL)
220                 return (ABORT);
221         if (bufp[0] == '\0')
222                 return (FALSE);
223         if ((bp = dired_(bufp)) == NULL)
224                 return (FALSE);
225
226         curbp = bp;
227         return (showbuffer(bp, curwp, WFFULL | WFMODE));
228 }
229
230 /* ARGSUSED */
231 int
232 d_otherwindow(int f, int n)
233 {
234         char             dname[NFILEN], *bufp, *slash;
235         struct buffer   *bp;
236         struct mgwin    *wp;
237
238         if (curbp->b_fname && curbp->b_fname[0] != '\0') {
239                 (void)strlcpy(dname, curbp->b_fname, sizeof(dname));
240                 if ((slash = strrchr(dname, '/')) != NULL) {
241                         *(slash + 1) = '\0';
242                 }
243         } else {
244                 if (getcwd(dname, sizeof(dname)) == NULL)
245                         dname[0] = '\0';
246         }
247
248         if ((bufp = eread("Dired other window: ", dname, NFILEN,
249             EFDEF | EFNEW | EFCR)) == NULL)
250                 return (ABORT);
251         else if (bufp[0] == '\0')
252                 return (FALSE);
253         if ((bp = dired_(bufp)) == NULL)
254                 return (FALSE);
255         if ((wp = popbuf(bp, WNONE)) == NULL)
256                 return (FALSE);
257         curbp = bp;
258         curwp = wp;
259         return (TRUE);
260 }
261
262 /* ARGSUSED */
263 int
264 d_del(int f, int n)
265 {
266         if (n < 0)
267                 return (FALSE);
268         while (n--) {
269                 if (llength(curwp->w_dotp) > 0)
270                         lputc(curwp->w_dotp, 0, 'D');
271                 if (lforw(curwp->w_dotp) != curbp->b_headp)
272                         curwp->w_dotp = lforw(curwp->w_dotp);
273         }
274         curwp->w_rflag |= WFEDIT | WFMOVE;
275         curwp->w_doto = 0;
276         return (TRUE);
277 }
278
279 /* ARGSUSED */
280 int
281 d_undel(int f, int n)
282 {
283         if (n < 0)
284                 return (d_undelbak(f, -n));
285         while (n--) {
286                 if (llength(curwp->w_dotp) > 0)
287                         lputc(curwp->w_dotp, 0, ' ');
288                 if (lforw(curwp->w_dotp) != curbp->b_headp)
289                         curwp->w_dotp = lforw(curwp->w_dotp);
290         }
291         curwp->w_rflag |= WFEDIT | WFMOVE;
292         curwp->w_doto = 0;
293         return (TRUE);
294 }
295
296 /* ARGSUSED */
297 int
298 d_undelbak(int f, int n)
299 {
300         if (n < 0)
301                 return (d_undel(f, -n));
302         while (n--) {
303                 if (llength(curwp->w_dotp) > 0)
304                         lputc(curwp->w_dotp, 0, ' ');
305                 if (lback(curwp->w_dotp) != curbp->b_headp)
306                         curwp->w_dotp = lback(curwp->w_dotp);
307         }
308         curwp->w_doto = 0;
309         curwp->w_rflag |= WFEDIT | WFMOVE;
310         return (TRUE);
311 }
312
313 /* ARGSUSED */
314 int
315 d_findfile(int f, int n)
316 {
317         struct buffer   *bp;
318         int              s;
319         char             fname[NFILEN];
320
321         if ((s = d_makename(curwp->w_dotp, fname, sizeof(fname))) == ABORT)
322                 return (FALSE);
323         if (s == TRUE)
324                 bp = dired_(fname);
325         else
326                 bp = findbuffer(fname);
327         if (bp == NULL)
328                 return (FALSE);
329         curbp = bp;
330         if (showbuffer(bp, curwp, WFFULL) != TRUE)
331                 return (FALSE);
332         if (bp->b_fname[0] != 0)
333                 return (TRUE);
334         return (readin(fname));
335 }
336
337 /* ARGSUSED */
338 int
339 d_ffotherwindow(int f, int n)
340 {
341         char             fname[NFILEN];
342         int              s;
343         struct buffer   *bp;
344         struct mgwin    *wp;
345
346         if ((s = d_makename(curwp->w_dotp, fname, sizeof(fname))) == ABORT)
347                 return (FALSE);
348         if ((bp = (s ? dired_(fname) : findbuffer(fname))) == NULL)
349                 return (FALSE);
350         if ((wp = popbuf(bp, WNONE)) == NULL)
351                 return (FALSE);
352         curbp = bp;
353         curwp = wp;
354         if (bp->b_fname[0] != 0)
355                 return (TRUE);  /* never true for dired buffers */
356         return (readin(fname));
357 }
358
359 /* ARGSUSED */
360 int
361 d_expunge(int f, int n)
362 {
363         struct line     *lp, *nlp;
364         char             fname[NFILEN], sname[NFILEN];
365
366         for (lp = bfirstlp(curbp); lp != curbp->b_headp; lp = nlp) {
367                 nlp = lforw(lp);
368                 if (llength(lp) && lgetc(lp, 0) == 'D') {
369                         switch (d_makename(lp, fname, sizeof(fname))) {
370                         case ABORT:
371                                 ewprintf("Bad line in dired buffer");
372                                 return (FALSE);
373                         case FALSE:
374                                 if (unlink(fname) < 0) {
375                                         (void)xbasename(sname, fname, NFILEN);
376                                         ewprintf("Could not delete '%s'", sname);
377                                         return (FALSE);
378                                 }
379                                 break;
380                         case TRUE:
381                                 if (rmdir(fname) < 0) {
382                                         (void)xbasename(sname, fname, NFILEN);
383                                         ewprintf("Could not delete directory "
384                                             "'%s'", sname);
385                                         return (FALSE);
386                                 }
387                                 break;
388                         }
389                         lfree(lp);
390                         curwp->w_bufp->b_lines--;
391                         curwp->w_rflag |= WFFULL;
392                 }
393         }
394         return (TRUE);
395 }
396
397 /* ARGSUSED */
398 int
399 d_copy(int f, int n)
400 {
401         char    frname[NFILEN], toname[NFILEN], sname[NFILEN], *bufp;
402         int     ret;
403         size_t  off;
404         struct buffer *bp;
405
406         if (d_makename(curwp->w_dotp, frname, sizeof(frname)) != FALSE) {
407                 ewprintf("Not a file");
408                 return (FALSE);
409         }
410         off = strlcpy(toname, curbp->b_fname, sizeof(toname));
411         if (off >= sizeof(toname) - 1) {        /* can't happen, really */
412                 ewprintf("Directory name too long");
413                 return (FALSE);
414         }
415         (void)xbasename(sname, frname, NFILEN);
416         bufp = eread("Copy %s to: ", toname, sizeof(toname),
417             EFDEF | EFNEW | EFCR, sname);
418         if (bufp == NULL) 
419                 return (ABORT);
420         else if (bufp[0] == '\0')
421                 return (FALSE);
422         ret = (copy(frname, toname) >= 0) ? TRUE : FALSE;
423         if (ret != TRUE)
424                 return (ret);
425         bp = dired_(curbp->b_fname);
426         return (showbuffer(bp, curwp, WFFULL | WFMODE));
427 }
428
429 /* ARGSUSED */
430 int
431 d_rename(int f, int n)
432 {
433         char             frname[NFILEN], toname[NFILEN], *bufp;
434         int              ret;
435         size_t           off;
436         struct buffer   *bp;
437         char             sname[NFILEN];
438
439         if (d_makename(curwp->w_dotp, frname, sizeof(frname)) != FALSE) {
440                 ewprintf("Not a file");
441                 return (FALSE);
442         }
443         off = strlcpy(toname, curbp->b_fname, sizeof(toname));
444         if (off >= sizeof(toname) - 1) {        /* can't happen, really */
445                 ewprintf("Directory name too long");
446                 return (FALSE);
447         }
448         (void)xbasename(sname, frname, NFILEN);
449         bufp = eread("Rename %s to: ", toname,
450             sizeof(toname), EFDEF | EFNEW | EFCR, sname);
451         if (bufp == NULL)
452                 return (ABORT);
453         else if (bufp[0] == '\0')
454                 return (FALSE);
455         ret = (rename(frname, toname) >= 0) ? TRUE : FALSE;
456         if (ret != TRUE)
457                 return (ret);
458         bp = dired_(curbp->b_fname);
459         return (showbuffer(bp, curwp, WFFULL | WFMODE));
460 }
461
462 /* ARGSUSED */
463 void
464 reaper(int signo __attribute__((unused)))
465 {
466         int     save_errno = errno, status;
467
468         while (waitpid(-1, &status, WNOHANG) >= 0)
469                 ;
470         errno = save_errno;
471 }
472
473 /*
474  * Pipe the currently selected file through a shell command.
475  */
476 /* ARGSUSED */
477 int
478 d_shell_command(int f, int n)
479 {
480         char             command[512], fname[MAXPATHLEN], *bufp;
481         struct buffer   *bp;
482         struct mgwin    *wp;
483         char             sname[NFILEN];
484
485         bp = bfind("*Shell Command Output*", TRUE);
486         if (bclear(bp) != TRUE)
487                 return (ABORT);
488
489         if (d_makename(curwp->w_dotp, fname, sizeof(fname)) != FALSE) {
490                 ewprintf("bad line");
491                 return (ABORT);
492         }
493
494         command[0] = '\0';
495         (void)xbasename(sname, fname, NFILEN);
496         bufp = eread("! on %s: ", command, sizeof(command), EFNEW, sname);
497         if (bufp == NULL)
498                 return (ABORT);
499
500         if (d_exec(0, bp, fname, "sh", "-c", command, NULL) != TRUE)
501                 return (ABORT);
502
503         if ((wp = popbuf(bp, WNONE)) == NULL)
504                 return (ABORT); /* XXX - free the buffer?? */
505         curwp = wp;
506         curbp = wp->w_bufp;
507         return (TRUE);
508 }
509
510 /*
511  * Pipe input file to cmd and insert the command's output in the
512  * given buffer.  Each line will be prefixed with the given
513  * number of spaces.
514  */
515 static int
516 d_exec(int space, struct buffer *bp, const char *input, const char *cmd, ...)
517 {
518         char     buf[BUFSIZ];
519         va_list  ap;
520         struct   sigaction olda, newa;
521         char    **argv = NULL, *cp;
522         FILE    *fin;
523         int      fds[2] = { -1, -1 };
524         int      infd = -1;
525         int      ret = (ABORT), n;
526         pid_t    pid;
527
528         if (sigaction(SIGCHLD, NULL, &olda) == -1)
529                 return (ABORT);
530
531         /* Find the number of arguments. */
532         va_start(ap, cmd);
533         for (n = 2; va_arg(ap, char *) != NULL; n++)
534                 ;
535         va_end(ap);
536
537         /* Allocate and build the argv. */
538         if ((argv = calloc(n, sizeof(*argv))) == NULL) {
539                 ewprintf("Can't allocate argv : %s", strerror(errno));
540                 goto out;
541         }
542
543         n = 1;
544         argv[0] = (char *)cmd;
545         va_start(ap, cmd);
546         while ((argv[n] = va_arg(ap, char *)) != NULL)
547                 n++;
548         va_end(ap);
549
550         if (input == NULL)
551                 input = "/dev/null";
552
553         if ((infd = open(input, O_RDONLY)) == -1) {
554                 ewprintf("Can't open input file : %s", strerror(errno));
555                 goto out;
556         }
557
558         if (pipe(fds) == -1) {
559                 ewprintf("Can't create pipe : %s", strerror(errno));
560                 goto out;
561         }
562
563         newa.sa_handler = reaper;
564         newa.sa_flags = 0;
565         if (sigaction(SIGCHLD, &newa, NULL) == -1)
566                 goto out;
567
568         if ((pid = fork()) == -1) {
569                 ewprintf("Can't fork");
570                 goto out;
571         }
572
573         switch (pid) {
574         case 0: /* Child */
575                 close(fds[0]);
576                 dup2(infd, STDIN_FILENO);
577                 dup2(fds[1], STDOUT_FILENO);
578                 dup2(fds[1], STDERR_FILENO);
579                 if (execvp(argv[0], argv) == -1)
580                         ewprintf("Can't exec %s: %s", argv[0], strerror(errno));
581                 exit(1);
582                 break;
583         default: /* Parent */
584                 close(infd);
585                 close(fds[1]);
586                 infd = fds[1] = -1;
587                 if ((fin = fdopen(fds[0], "r")) == NULL)
588                         goto out;
589                 while (fgets(buf, sizeof(buf), fin) != NULL) {
590                         cp = strrchr(buf, '\n');
591                         if (cp == NULL && !feof(fin)) { /* too long a line */
592                                 int c;
593                                 addlinef(bp, "%*s%s...", space, "", buf);
594                                 while ((c = getc(fin)) != EOF && c != '\n')
595                                         ;
596                                 continue;
597                         } else if (cp)
598                                 *cp = '\0';
599                         addlinef(bp, "%*s%s", space, "", buf);
600                 }
601                 fclose(fin);
602                 break;
603         }
604         ret = (TRUE);
605
606 out:
607         if (sigaction(SIGCHLD, &olda, NULL) == -1)
608                 ewprintf("Warning, couldn't reset previous signal handler");
609         if (fds[0] != -1)
610                 close(fds[0]);
611         if (fds[1] != -1)
612                 close(fds[1]);
613         if (infd != -1)
614                 close(infd);
615         if (argv != NULL)
616                 free(argv);
617         return ret;
618 }
619
620 /* ARGSUSED */
621 int
622 d_create_directory(int f, int n)
623 {
624         char     tocreate[MAXPATHLEN], *bufp;
625         size_t  off;
626         struct buffer   *bp;
627
628         off = strlcpy(tocreate, curbp->b_fname, sizeof(tocreate));
629         if (off >= sizeof(tocreate) - 1)
630                 return (FALSE);
631         if ((bufp = eread("Create directory: ", tocreate,
632             sizeof(tocreate), EFDEF | EFNEW | EFCR)) == NULL)
633                 return (ABORT);
634         else if (bufp[0] == '\0')
635                 return (FALSE);
636         if (mkdir(tocreate, 0755) == -1) {
637                 ewprintf("Creating directory: %s, %s", strerror(errno),
638                     tocreate);
639                 return (FALSE);
640         }
641         bp = dired_(curbp->b_fname);
642         return (showbuffer(bp, curwp, WFFULL | WFMODE));
643 }
644
645 static int
646 d_makename(struct line *lp, char *fn, size_t len)
647 {
648         int      start, nlen;
649         char    *namep;
650
651         if (d_warpdot(lp, &start) == FALSE)
652                 return (ABORT);
653         namep = &lp->l_text[start];
654         nlen = llength(lp) - start;
655
656         if (snprintf(fn, len, "%s%.*s", curbp->b_fname, nlen, namep) >= len)
657                 return (ABORT); /* Name is too long. */
658
659         /* Return TRUE if the entry is a directory. */
660         return ((lgetc(lp, 2) == 'd') ? TRUE : FALSE);
661 }
662
663 #define NAME_FIELD      9
664
665 static int
666 d_warpdot(struct line *dotp, int *doto)
667 {
668         char *tp = dotp->l_text;
669         int off = 0, field = 0, len;
670
671         /*
672          * Find the byte offset to the (space-delimited) filename
673          * field in formatted ls output.
674          */
675         len = llength(dotp);
676         while (off < len) {
677                 if (tp[off++] == ' ') {
678                         if (++field == NAME_FIELD) {
679                                 *doto = off;
680                                 return (TRUE);
681                         }
682                         /* Skip the space. */
683                         while (off < len && tp[off] == ' ')
684                                 off++;
685                 }
686         }
687         /* We didn't find the field. */
688         *doto = 0;
689         return (FALSE);
690 }
691
692 static int
693 d_forwpage(int f, int n) 
694 {
695         forwpage(f | FFRAND, n);
696         return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
697 }
698
699 static int 
700 d_backpage (int f, int n)
701 {
702         backpage(f | FFRAND, n);
703         return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
704 }
705
706 static int
707 d_forwline (int f, int n)
708 {
709         forwline(f | FFRAND, n);
710         return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
711 }
712
713 static int
714 d_backline (int f, int n)
715 {
716         backline(f | FFRAND, n);
717         return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
718 }
719
720 /*
721  * XXX dname needs to have enough place to store an additional '/'.
722  */
723 struct buffer *
724 dired_(char *dname)
725 {
726         struct buffer   *bp;
727         int              len, i;
728
729         if ((fopen(dname,"r")) == NULL) {
730                 if (errno == EACCES)
731                         ewprintf("Permission denied");
732                 return (NULL);
733         }
734         if ((dname = adjustname(dname, FALSE)) == NULL) {
735                 ewprintf("Bad directory name");
736                 return (NULL);
737         }
738         /* this should not be done, instead adjustname() should get a flag */
739         len = strlen(dname);
740         if (dname[len - 1] != '/') {
741                 dname[len++] = '/';
742                 dname[len] = '\0';
743         }
744         if ((bp = findbuffer(dname)) == NULL) {
745                 ewprintf("Could not create buffer");
746                 return (NULL);
747         }
748         if (bclear(bp) != TRUE)
749                 return (NULL);
750         bp->b_flag |= BFREADONLY;
751
752         if ((d_exec(2, bp, NULL, "ls", "-al", dname, NULL)) != TRUE)
753                 return (NULL);
754
755         /* Find the line with ".." on it. */
756         bp->b_dotp = bfirstlp(bp);
757         for (i = 0; i < bp->b_lines; i++) {
758                 bp->b_dotp = lforw(bp->b_dotp);
759                 if (d_warpdot(bp->b_dotp, &bp->b_doto) == FALSE)
760                         continue;
761                 if (strcmp(ltext(bp->b_dotp) + bp->b_doto, "..") == 0)
762                         break;
763         }
764
765         /* We want dot on the entry right after "..", if possible. */
766         if (++i < bp->b_lines - 2)
767                 bp->b_dotp = lforw(bp->b_dotp);
768         d_warpdot(bp->b_dotp, &bp->b_doto);
769
770         (void)strlcpy(bp->b_fname, dname, sizeof(bp->b_fname));
771         (void)strlcpy(bp->b_cwd, dname, sizeof(bp->b_cwd));
772         if ((bp->b_modes[1] = name_mode("dired")) == NULL) {
773                 bp->b_modes[0] = name_mode("fundamental");
774                 ewprintf("Could not find mode dired");
775                 return (NULL);
776         }
777         bp->b_nmodes = 1;
778         return (bp);
779 }