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