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