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 } 780