Annotation of src/usr.bin/mg/dired.c, Revision 1.79
1.79 ! lum 1: /* $OpenBSD: dired.c,v 1.78 2015/10/12 19:08:39 lum Exp $ */
1.6 niklas 2:
1.20 kjell 3: /* This file is in the public domain. */
4:
5: /* dired module for mg 2a
6: * by Robert A. Larson
7: */
1.1 deraadt 8:
1.70 bcallah 9: #include <sys/queue.h>
10: #include <sys/resource.h>
1.12 vincent 11: #include <sys/stat.h>
1.25 deraadt 12: #include <sys/time.h>
1.70 bcallah 13: #include <sys/types.h>
1.12 vincent 14: #include <sys/wait.h>
1.24 kjell 15: #include <ctype.h>
1.54 lum 16: #include <err.h>
1.12 vincent 17: #include <errno.h>
1.70 bcallah 18: #include <fcntl.h>
1.12 vincent 19: #include <libgen.h>
1.70 bcallah 20: #include <limits.h>
21: #include <signal.h>
1.50 lum 22: #include <stdarg.h>
1.70 bcallah 23: #include <stdio.h>
24: #include <stdlib.h>
25: #include <string.h>
26: #include <unistd.h>
27:
28: #include "def.h"
29: #include "funmap.h"
30: #include "kbd.h"
1.1 deraadt 31:
1.24 kjell 32: void dired_init(void);
1.27 kjell 33: static int dired(int, int);
34: static int d_otherwindow(int, int);
35: static int d_undel(int, int);
36: static int d_undelbak(int, int);
37: static int d_findfile(int, int);
38: static int d_ffotherwindow(int, int);
39: static int d_expunge(int, int);
40: static int d_copy(int, int);
41: static int d_del(int, int);
42: static int d_rename(int, int);
1.50 lum 43: static int d_exec(int, struct buffer *, const char *, const char *, ...);
1.27 kjell 44: static int d_shell_command(int, int);
45: static int d_create_directory(int, int);
1.34 kjell 46: static int d_makename(struct line *, char *, size_t);
1.49 lum 47: static int d_warpdot(struct line *, int *);
48: static int d_forwpage(int, int);
49: static int d_backpage(int, int);
50: static int d_forwline(int, int);
51: static int d_backline(int, int);
1.62 lum 52: static int d_killbuffer_cmd(int, int);
1.63 lum 53: static int d_refreshbuffer(int, int);
1.47 lum 54: static void reaper(int);
1.54 lum 55: static struct buffer *refreshbuffer(struct buffer *);
1.78 lum 56: static int createlist(struct buffer *);
57: static void redelete(struct buffer *);
58: static char *findfname(struct line *, char *);
1.1 deraadt 59:
1.23 kjell 60: extern struct keymap_s helpmap, cXmap, metamap;
61:
1.78 lum 62: const char DDELCHAR = 'D';
63:
64: /*
65: * Structure which holds a linked list of file names marked for
66: * deletion. Used to maintain dired buffer 'state' between refreshes.
67: */
68: struct delentry {
69: SLIST_ENTRY(delentry) entry;
70: char *fn;
71: };
72: SLIST_HEAD(slisthead, delentry) delhead = SLIST_HEAD_INITIALIZER(delhead);
73:
1.23 kjell 74: static PF dirednul[] = {
75: setmark, /* ^@ */
76: gotobol, /* ^A */
77: backchar, /* ^B */
78: rescan, /* ^C */
79: d_del, /* ^D */
80: gotoeol, /* ^E */
81: forwchar, /* ^F */
82: ctrlg, /* ^G */
83: NULL, /* ^H */
1.12 vincent 84: };
85:
1.23 kjell 86: static PF diredcl[] = {
87: reposition, /* ^L */
1.15 db 88: d_findfile, /* ^M */
1.49 lum 89: d_forwline, /* ^N */
1.23 kjell 90: rescan, /* ^O */
1.49 lum 91: d_backline, /* ^P */
1.23 kjell 92: rescan, /* ^Q */
93: backisearch, /* ^R */
94: forwisearch, /* ^S */
95: rescan, /* ^T */
96: universal_argument, /* ^U */
1.49 lum 97: d_forwpage, /* ^V */
1.23 kjell 98: rescan, /* ^W */
99: NULL /* ^X */
100: };
101:
102: static PF diredcz[] = {
103: spawncli, /* ^Z */
104: NULL, /* esc */
105: rescan, /* ^\ */
106: rescan, /* ^] */
107: rescan, /* ^^ */
108: rescan, /* ^_ */
1.49 lum 109: d_forwline, /* SP */
1.27 kjell 110: d_shell_command, /* ! */
111: rescan, /* " */
112: rescan, /* # */
113: rescan, /* $ */
114: rescan, /* % */
115: rescan, /* & */
116: rescan, /* ' */
117: rescan, /* ( */
118: rescan, /* ) */
119: rescan, /* * */
120: d_create_directory /* + */
1.23 kjell 121: };
122:
123: static PF diredc[] = {
124: d_copy, /* c */
125: d_del, /* d */
126: d_findfile, /* e */
1.63 lum 127: d_findfile, /* f */
128: d_refreshbuffer /* g */
1.23 kjell 129: };
130:
131: static PF diredn[] = {
1.49 lum 132: d_forwline, /* n */
1.23 kjell 133: d_ffotherwindow, /* o */
1.49 lum 134: d_backline, /* p */
1.62 lum 135: d_killbuffer_cmd, /* q */
1.23 kjell 136: d_rename, /* r */
137: rescan, /* s */
138: rescan, /* t */
139: d_undel, /* u */
140: rescan, /* v */
141: rescan, /* w */
142: d_expunge /* x */
143: };
144:
145: static PF direddl[] = {
146: d_undelbak /* del */
1.9 vincent 147: };
1.13 deraadt 148:
1.49 lum 149: static PF diredbp[] = {
1.76 jasper 150: d_backpage /* v */
1.49 lum 151: };
152:
153: static PF dirednull[] = {
154: NULL
155: };
156:
1.71 bcallah 157: static struct KEYMAPE (1) d_backpagemap = {
158: 1,
1.49 lum 159: 1,
1.76 jasper 160: rescan,
1.49 lum 161: {
162: {
163: 'v', 'v', diredbp, NULL
164: }
165: }
166: };
167:
1.71 bcallah 168: static struct KEYMAPE (7) diredmap = {
169: 7,
170: 7,
1.9 vincent 171: rescan,
172: {
1.23 kjell 173: {
174: CCHR('@'), CCHR('H'), dirednul, (KEYMAP *) & helpmap
175: },
176: {
177: CCHR('L'), CCHR('X'), diredcl, (KEYMAP *) & cXmap
178: },
179: {
1.76 jasper 180: CCHR('['), CCHR('['), dirednull, (KEYMAP *) &
1.49 lum 181: d_backpagemap
182: },
183: {
1.27 kjell 184: CCHR('Z'), '+', diredcz, (KEYMAP *) & metamap
1.23 kjell 185: },
186: {
1.63 lum 187: 'c', 'g', diredc, NULL
1.23 kjell 188: },
189: {
190: 'n', 'x', diredn, NULL
191: },
192: {
193: CCHR('?'), CCHR('?'), direddl, NULL
194: },
1.9 vincent 195: }
196: };
197:
1.23 kjell 198: void
199: dired_init(void)
200: {
1.27 kjell 201: funmap_add(dired, "dired");
1.60 lum 202: funmap_add(d_undelbak, "dired-unmark-backward");
1.53 lum 203: funmap_add(d_create_directory, "dired-create-directory");
1.60 lum 204: funmap_add(d_copy, "dired-do-copy");
205: funmap_add(d_expunge, "dired-do-flagged-delete");
1.27 kjell 206: funmap_add(d_findfile, "dired-find-file");
207: funmap_add(d_ffotherwindow, "dired-find-file-other-window");
1.60 lum 208: funmap_add(d_del, "dired-flag-file-deletion");
1.49 lum 209: funmap_add(d_forwline, "dired-next-line");
1.27 kjell 210: funmap_add(d_otherwindow, "dired-other-window");
1.49 lum 211: funmap_add(d_backline, "dired-previous-line");
1.60 lum 212: funmap_add(d_rename, "dired-do-rename");
1.49 lum 213: funmap_add(d_backpage, "dired-scroll-down");
214: funmap_add(d_forwpage, "dired-scroll-up");
1.60 lum 215: funmap_add(d_undel, "dired-unmark");
1.62 lum 216: funmap_add(d_killbuffer_cmd, "quit-window");
1.23 kjell 217: maps_add((KEYMAP *)&diredmap, "dired");
1.27 kjell 218: dobindkey(fundamental_map, "dired", "^Xd");
1.23 kjell 219: }
1.12 vincent 220:
1.5 millert 221: /* ARGSUSED */
222: int
1.10 vincent 223: dired(int f, int n)
1.1 deraadt 224: {
1.33 kjell 225: char dname[NFILEN], *bufp, *slash;
1.31 deraadt 226: struct buffer *bp;
1.1 deraadt 227:
1.69 bcallah 228: if (curbp->b_fname[0] != '\0') {
1.33 kjell 229: (void)strlcpy(dname, curbp->b_fname, sizeof(dname));
230: if ((slash = strrchr(dname, '/')) != NULL) {
1.19 cloder 231: *(slash + 1) = '\0';
232: }
233: } else {
1.33 kjell 234: if (getcwd(dname, sizeof(dname)) == NULL)
235: dname[0] = '\0';
1.19 cloder 236: }
237:
1.33 kjell 238: if ((bufp = eread("Dired: ", dname, NFILEN,
1.21 kjell 239: EFDEF | EFNEW | EFCR)) == NULL)
1.15 db 240: return (ABORT);
1.21 kjell 241: if (bufp[0] == '\0')
242: return (FALSE);
1.14 vincent 243: if ((bp = dired_(bufp)) == NULL)
1.15 db 244: return (FALSE);
1.23 kjell 245:
1.5 millert 246: curbp = bp;
1.37 kjell 247: return (showbuffer(bp, curwp, WFFULL | WFMODE));
1.1 deraadt 248: }
249:
1.5 millert 250: /* ARGSUSED */
251: int
1.10 vincent 252: d_otherwindow(int f, int n)
1.1 deraadt 253: {
1.33 kjell 254: char dname[NFILEN], *bufp, *slash;
1.31 deraadt 255: struct buffer *bp;
256: struct mgwin *wp;
1.5 millert 257:
1.69 bcallah 258: if (curbp->b_fname[0] != '\0') {
1.33 kjell 259: (void)strlcpy(dname, curbp->b_fname, sizeof(dname));
260: if ((slash = strrchr(dname, '/')) != NULL) {
1.23 kjell 261: *(slash + 1) = '\0';
262: }
263: } else {
1.33 kjell 264: if (getcwd(dname, sizeof(dname)) == NULL)
265: dname[0] = '\0';
1.23 kjell 266: }
267:
1.33 kjell 268: if ((bufp = eread("Dired other window: ", dname, NFILEN,
1.21 kjell 269: EFDEF | EFNEW | EFCR)) == NULL)
1.15 db 270: return (ABORT);
1.21 kjell 271: else if (bufp[0] == '\0')
272: return (FALSE);
1.14 vincent 273: if ((bp = dired_(bufp)) == NULL)
1.15 db 274: return (FALSE);
1.45 kjell 275: if ((wp = popbuf(bp, WNONE)) == NULL)
1.15 db 276: return (FALSE);
1.5 millert 277: curbp = bp;
278: curwp = wp;
1.15 db 279: return (TRUE);
1.1 deraadt 280: }
281:
1.5 millert 282: /* ARGSUSED */
283: int
1.10 vincent 284: d_del(int f, int n)
1.1 deraadt 285: {
1.5 millert 286: if (n < 0)
1.15 db 287: return (FALSE);
1.5 millert 288: while (n--) {
1.79 ! lum 289: if (d_warpdot(curwp->w_dotp, &curwp->w_doto) == TRUE) {
1.78 lum 290: lputc(curwp->w_dotp, 0, DDELCHAR);
291: curbp->b_flag |= BFDIREDDEL;
292: }
1.74 lum 293: if (lforw(curwp->w_dotp) != curbp->b_headp) {
1.5 millert 294: curwp->w_dotp = lforw(curwp->w_dotp);
1.74 lum 295: curwp->w_dotline++;
296: }
1.5 millert 297: }
1.44 kjell 298: curwp->w_rflag |= WFEDIT | WFMOVE;
1.56 lum 299: return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
1.1 deraadt 300: }
301:
1.5 millert 302: /* ARGSUSED */
303: int
1.10 vincent 304: d_undel(int f, int n)
1.1 deraadt 305: {
1.5 millert 306: if (n < 0)
1.15 db 307: return (d_undelbak(f, -n));
1.5 millert 308: while (n--) {
309: if (llength(curwp->w_dotp) > 0)
310: lputc(curwp->w_dotp, 0, ' ');
1.74 lum 311: if (lforw(curwp->w_dotp) != curbp->b_headp) {
1.5 millert 312: curwp->w_dotp = lforw(curwp->w_dotp);
1.74 lum 313: curwp->w_dotline++;
314: }
1.5 millert 315: }
1.44 kjell 316: curwp->w_rflag |= WFEDIT | WFMOVE;
1.56 lum 317: return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
1.1 deraadt 318: }
319:
1.5 millert 320: /* ARGSUSED */
321: int
1.10 vincent 322: d_undelbak(int f, int n)
1.1 deraadt 323: {
1.5 millert 324: if (n < 0)
1.15 db 325: return (d_undel(f, -n));
1.5 millert 326: while (n--) {
1.74 lum 327: if (lback(curwp->w_dotp) != curbp->b_headp) {
1.64 lum 328: curwp->w_dotp = lback(curwp->w_dotp);
1.74 lum 329: curwp->w_dotline--;
330: }
1.5 millert 331: if (llength(curwp->w_dotp) > 0)
332: lputc(curwp->w_dotp, 0, ' ');
333: }
1.44 kjell 334: curwp->w_rflag |= WFEDIT | WFMOVE;
1.56 lum 335: return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
1.1 deraadt 336: }
337:
1.5 millert 338: /* ARGSUSED */
339: int
1.10 vincent 340: d_findfile(int f, int n)
1.1 deraadt 341: {
1.31 deraadt 342: struct buffer *bp;
343: int s;
344: char fname[NFILEN];
1.5 millert 345:
1.15 db 346: if ((s = d_makename(curwp->w_dotp, fname, sizeof(fname))) == ABORT)
347: return (FALSE);
1.12 vincent 348: if (s == TRUE)
349: bp = dired_(fname);
350: else
351: bp = findbuffer(fname);
352: if (bp == NULL)
1.15 db 353: return (FALSE);
1.5 millert 354: curbp = bp;
1.37 kjell 355: if (showbuffer(bp, curwp, WFFULL) != TRUE)
1.15 db 356: return (FALSE);
1.5 millert 357: if (bp->b_fname[0] != 0)
1.15 db 358: return (TRUE);
359: return (readin(fname));
1.1 deraadt 360: }
361:
1.5 millert 362: /* ARGSUSED */
363: int
1.10 vincent 364: d_ffotherwindow(int f, int n)
1.1 deraadt 365: {
1.31 deraadt 366: char fname[NFILEN];
367: int s;
368: struct buffer *bp;
369: struct mgwin *wp;
1.5 millert 370:
1.15 db 371: if ((s = d_makename(curwp->w_dotp, fname, sizeof(fname))) == ABORT)
372: return (FALSE);
1.5 millert 373: if ((bp = (s ? dired_(fname) : findbuffer(fname))) == NULL)
1.15 db 374: return (FALSE);
1.45 kjell 375: if ((wp = popbuf(bp, WNONE)) == NULL)
1.15 db 376: return (FALSE);
1.5 millert 377: curbp = bp;
378: curwp = wp;
379: if (bp->b_fname[0] != 0)
1.15 db 380: return (TRUE); /* never true for dired buffers */
381: return (readin(fname));
1.1 deraadt 382: }
383:
1.5 millert 384: /* ARGSUSED */
385: int
1.10 vincent 386: d_expunge(int f, int n)
1.1 deraadt 387: {
1.31 deraadt 388: struct line *lp, *nlp;
1.48 kjell 389: char fname[NFILEN], sname[NFILEN];
1.74 lum 390: int tmp;
391:
392: tmp = curwp->w_dotline;
393: curwp->w_dotline = 0;
1.5 millert 394:
1.41 kjell 395: for (lp = bfirstlp(curbp); lp != curbp->b_headp; lp = nlp) {
1.74 lum 396: curwp->w_dotline++;
1.5 millert 397: nlp = lforw(lp);
398: if (llength(lp) && lgetc(lp, 0) == 'D') {
1.15 db 399: switch (d_makename(lp, fname, sizeof(fname))) {
1.5 millert 400: case ABORT:
1.66 lum 401: dobeep();
1.5 millert 402: ewprintf("Bad line in dired buffer");
1.74 lum 403: curwp->w_dotline = tmp;
1.15 db 404: return (FALSE);
1.5 millert 405: case FALSE:
406: if (unlink(fname) < 0) {
1.48 kjell 407: (void)xbasename(sname, fname, NFILEN);
1.66 lum 408: dobeep();
1.48 kjell 409: ewprintf("Could not delete '%s'", sname);
1.74 lum 410: curwp->w_dotline = tmp;
1.15 db 411: return (FALSE);
1.5 millert 412: }
413: break;
414: case TRUE:
415: if (rmdir(fname) < 0) {
1.48 kjell 416: (void)xbasename(sname, fname, NFILEN);
1.66 lum 417: dobeep();
1.48 kjell 418: ewprintf("Could not delete directory "
419: "'%s'", sname);
1.74 lum 420: curwp->w_dotline = tmp;
1.15 db 421: return (FALSE);
1.5 millert 422: }
423: break;
424: }
425: lfree(lp);
1.39 kjell 426: curwp->w_bufp->b_lines--;
1.74 lum 427: if (tmp > curwp->w_dotline)
428: tmp--;
1.44 kjell 429: curwp->w_rflag |= WFFULL;
1.5 millert 430: }
1.1 deraadt 431: }
1.74 lum 432: curwp->w_dotline = tmp;
1.75 lum 433: d_warpdot(curwp->w_dotp, &curwp->w_doto);
1.78 lum 434:
435: /* we have deleted all items successfully, remove del flag */
436: curbp->b_flag &= ~BFDIREDDEL;
437:
1.15 db 438: return (TRUE);
1.1 deraadt 439: }
440:
1.5 millert 441: /* ARGSUSED */
442: int
1.10 vincent 443: d_copy(int f, int n)
1.1 deraadt 444: {
1.59 lum 445: char frname[NFILEN], toname[NFILEN], sname[NFILEN];
446: char *topath, *bufp;
447: int ret;
448: size_t off;
449: struct buffer *bp;
1.1 deraadt 450:
1.15 db 451: if (d_makename(curwp->w_dotp, frname, sizeof(frname)) != FALSE) {
1.66 lum 452: dobeep();
1.5 millert 453: ewprintf("Not a file");
1.15 db 454: return (FALSE);
1.5 millert 455: }
1.15 db 456: off = strlcpy(toname, curbp->b_fname, sizeof(toname));
457: if (off >= sizeof(toname) - 1) { /* can't happen, really */
1.66 lum 458: dobeep();
1.18 cloder 459: ewprintf("Directory name too long");
1.12 vincent 460: return (FALSE);
461: }
1.48 kjell 462: (void)xbasename(sname, frname, NFILEN);
463: bufp = eread("Copy %s to: ", toname, sizeof(toname),
464: EFDEF | EFNEW | EFCR, sname);
1.76 jasper 465: if (bufp == NULL)
1.15 db 466: return (ABORT);
1.14 vincent 467: else if (bufp[0] == '\0')
1.17 otto 468: return (FALSE);
1.59 lum 469:
470: topath = adjustname(toname, TRUE);
471: ret = (copy(frname, topath) >= 0) ? TRUE : FALSE;
1.33 kjell 472: if (ret != TRUE)
473: return (ret);
1.54 lum 474: if ((bp = refreshbuffer(curbp)) == NULL)
475: return (FALSE);
1.37 kjell 476: return (showbuffer(bp, curwp, WFFULL | WFMODE));
1.1 deraadt 477: }
478:
1.5 millert 479: /* ARGSUSED */
480: int
1.10 vincent 481: d_rename(int f, int n)
1.1 deraadt 482: {
1.59 lum 483: char frname[NFILEN], toname[NFILEN];
484: char *topath, *bufp;
1.33 kjell 485: int ret;
1.31 deraadt 486: size_t off;
487: struct buffer *bp;
1.48 kjell 488: char sname[NFILEN];
1.1 deraadt 489:
1.15 db 490: if (d_makename(curwp->w_dotp, frname, sizeof(frname)) != FALSE) {
1.66 lum 491: dobeep();
1.5 millert 492: ewprintf("Not a file");
1.15 db 493: return (FALSE);
1.5 millert 494: }
1.15 db 495: off = strlcpy(toname, curbp->b_fname, sizeof(toname));
496: if (off >= sizeof(toname) - 1) { /* can't happen, really */
1.66 lum 497: dobeep();
1.18 cloder 498: ewprintf("Directory name too long");
1.12 vincent 499: return (FALSE);
500: }
1.48 kjell 501: (void)xbasename(sname, frname, NFILEN);
502: bufp = eread("Rename %s to: ", toname,
503: sizeof(toname), EFDEF | EFNEW | EFCR, sname);
504: if (bufp == NULL)
1.15 db 505: return (ABORT);
1.14 vincent 506: else if (bufp[0] == '\0')
1.15 db 507: return (FALSE);
1.59 lum 508:
509: topath = adjustname(toname, TRUE);
510: ret = (rename(frname, topath) >= 0) ? TRUE : FALSE;
1.33 kjell 511: if (ret != TRUE)
512: return (ret);
1.54 lum 513: if ((bp = refreshbuffer(curbp)) == NULL)
514: return (FALSE);
1.37 kjell 515: return (showbuffer(bp, curwp, WFFULL | WFMODE));
1.1 deraadt 516: }
1.12 vincent 517:
1.31 deraadt 518: /* ARGSUSED */
1.12 vincent 519: void
520: reaper(int signo __attribute__((unused)))
521: {
1.22 deraadt 522: int save_errno = errno, status;
1.12 vincent 523:
1.25 deraadt 524: while (waitpid(-1, &status, WNOHANG) >= 0)
1.12 vincent 525: ;
1.22 deraadt 526: errno = save_errno;
1.12 vincent 527: }
528:
529: /*
530: * Pipe the currently selected file through a shell command.
531: */
1.26 kjell 532: /* ARGSUSED */
1.12 vincent 533: int
534: d_shell_command(int f, int n)
535: {
1.68 guenther 536: char command[512], fname[PATH_MAX], *bufp;
1.31 deraadt 537: struct buffer *bp;
538: struct mgwin *wp;
1.50 lum 539: char sname[NFILEN];
1.12 vincent 540:
541: bp = bfind("*Shell Command Output*", TRUE);
542: if (bclear(bp) != TRUE)
543: return (ABORT);
544:
1.15 db 545: if (d_makename(curwp->w_dotp, fname, sizeof(fname)) != FALSE) {
1.66 lum 546: dobeep();
1.12 vincent 547: ewprintf("bad line");
548: return (ABORT);
549: }
550:
551: command[0] = '\0';
1.48 kjell 552: (void)xbasename(sname, fname, NFILEN);
553: bufp = eread("! on %s: ", command, sizeof(command), EFNEW, sname);
554: if (bufp == NULL)
1.12 vincent 555: return (ABORT);
1.50 lum 556:
557: if (d_exec(0, bp, fname, "sh", "-c", command, NULL) != TRUE)
558: return (ABORT);
559:
560: if ((wp = popbuf(bp, WNONE)) == NULL)
561: return (ABORT); /* XXX - free the buffer?? */
562: curwp = wp;
563: curbp = wp->w_bufp;
564: return (TRUE);
565: }
566:
567: /*
568: * Pipe input file to cmd and insert the command's output in the
569: * given buffer. Each line will be prefixed with the given
570: * number of spaces.
571: */
572: static int
573: d_exec(int space, struct buffer *bp, const char *input, const char *cmd, ...)
574: {
575: char buf[BUFSIZ];
576: va_list ap;
577: struct sigaction olda, newa;
578: char **argv = NULL, *cp;
579: FILE *fin;
580: int fds[2] = { -1, -1 };
581: int infd = -1;
582: int ret = (ABORT), n;
583: pid_t pid;
584:
585: if (sigaction(SIGCHLD, NULL, &olda) == -1)
586: return (ABORT);
587:
588: /* Find the number of arguments. */
589: va_start(ap, cmd);
590: for (n = 2; va_arg(ap, char *) != NULL; n++)
591: ;
592: va_end(ap);
593:
594: /* Allocate and build the argv. */
595: if ((argv = calloc(n, sizeof(*argv))) == NULL) {
1.66 lum 596: dobeep();
1.50 lum 597: ewprintf("Can't allocate argv : %s", strerror(errno));
598: goto out;
599: }
600:
601: n = 1;
602: argv[0] = (char *)cmd;
603: va_start(ap, cmd);
604: while ((argv[n] = va_arg(ap, char *)) != NULL)
605: n++;
606: va_end(ap);
607:
608: if (input == NULL)
609: input = "/dev/null";
610:
611: if ((infd = open(input, O_RDONLY)) == -1) {
1.66 lum 612: dobeep();
1.12 vincent 613: ewprintf("Can't open input file : %s", strerror(errno));
1.50 lum 614: goto out;
1.12 vincent 615: }
1.50 lum 616:
1.12 vincent 617: if (pipe(fds) == -1) {
1.66 lum 618: dobeep();
1.12 vincent 619: ewprintf("Can't create pipe : %s", strerror(errno));
1.50 lum 620: goto out;
1.12 vincent 621: }
622:
623: newa.sa_handler = reaper;
624: newa.sa_flags = 0;
1.50 lum 625: if (sigaction(SIGCHLD, &newa, NULL) == -1)
626: goto out;
627:
628: if ((pid = fork()) == -1) {
1.66 lum 629: dobeep();
1.50 lum 630: ewprintf("Can't fork");
631: goto out;
1.12 vincent 632: }
1.50 lum 633:
1.12 vincent 634: switch (pid) {
1.50 lum 635: case 0: /* Child */
1.12 vincent 636: close(fds[0]);
637: dup2(infd, STDIN_FILENO);
638: dup2(fds[1], STDOUT_FILENO);
639: dup2(fds[1], STDERR_FILENO);
1.50 lum 640: if (execvp(argv[0], argv) == -1)
641: ewprintf("Can't exec %s: %s", argv[0], strerror(errno));
1.12 vincent 642: exit(1);
1.29 deraadt 643: break;
1.50 lum 644: default: /* Parent */
1.12 vincent 645: close(infd);
646: close(fds[1]);
1.50 lum 647: infd = fds[1] = -1;
648: if ((fin = fdopen(fds[0], "r")) == NULL)
649: goto out;
1.15 db 650: while (fgets(buf, sizeof(buf), fin) != NULL) {
1.12 vincent 651: cp = strrchr(buf, '\n');
652: if (cp == NULL && !feof(fin)) { /* too long a line */
653: int c;
1.50 lum 654: addlinef(bp, "%*s%s...", space, "", buf);
1.12 vincent 655: while ((c = getc(fin)) != EOF && c != '\n')
656: ;
657: continue;
658: } else if (cp)
659: *cp = '\0';
1.50 lum 660: addlinef(bp, "%*s%s", space, "", buf);
1.12 vincent 661: }
662: fclose(fin);
663: break;
664: }
1.50 lum 665: ret = (TRUE);
666:
667: out:
1.12 vincent 668: if (sigaction(SIGCHLD, &olda, NULL) == -1)
669: ewprintf("Warning, couldn't reset previous signal handler");
1.50 lum 670: if (fds[0] != -1)
671: close(fds[0]);
672: if (fds[1] != -1)
673: close(fds[1]);
674: if (infd != -1)
675: close(infd);
676: if (argv != NULL)
677: free(argv);
678: return ret;
1.12 vincent 679: }
680:
1.26 kjell 681: /* ARGSUSED */
1.12 vincent 682: int
683: d_create_directory(int f, int n)
684: {
1.57 lum 685: int ret;
1.31 deraadt 686: struct buffer *bp;
1.12 vincent 687:
1.67 lum 688: ret = ask_makedir();
1.57 lum 689: if (ret != TRUE)
690: return(ret);
691:
1.54 lum 692: if ((bp = refreshbuffer(curbp)) == NULL)
693: return (FALSE);
1.57 lum 694:
1.37 kjell 695: return (showbuffer(bp, curwp, WFFULL | WFMODE));
1.62 lum 696: }
697:
698: /* ARGSUSED */
699: int
700: d_killbuffer_cmd(int f, int n)
701: {
702: return(killbuffer_cmd(FFRAND, 0));
1.63 lum 703: }
704:
705: int
706: d_refreshbuffer(int f, int n)
707: {
708: struct buffer *bp;
709:
710: if ((bp = refreshbuffer(curbp)) == NULL)
711: return (FALSE);
712:
713: return (showbuffer(bp, curwp, WFFULL | WFMODE));
1.54 lum 714: }
715:
1.78 lum 716: /*
717: * Kill then re-open the requested dired buffer.
718: * If required, take a note of any files marked for deletion. Then once
719: * the buffer has been re-opened, remark the same files as deleted.
720: */
1.54 lum 721: struct buffer *
722: refreshbuffer(struct buffer *bp)
723: {
1.78 lum 724: char *tmp_b_fname;
725: int i, tmp_w_dotline, ddel = 0;
1.54 lum 726:
1.78 lum 727: /* remember directory path to open later */
728: tmp_b_fname = strdup(bp->b_fname);
729: if (tmp_b_fname == NULL) {
1.66 lum 730: dobeep();
1.55 lum 731: ewprintf("Out of memory");
1.61 lum 732: return (NULL);
1.55 lum 733: }
1.78 lum 734: tmp_w_dotline = curwp->w_dotline;
735:
736: /* create a list of files for deletion */
737: if (bp->b_flag & BFDIREDDEL)
738: ddel = createlist(bp);
1.54 lum 739:
740: killbuffer(bp);
741:
742: /* dired_() uses findbuffer() to create new buffer */
1.78 lum 743: if ((bp = dired_(tmp_b_fname)) == NULL) {
744: free(tmp_b_fname);
1.54 lum 745: return (NULL);
746: }
1.78 lum 747: free(tmp_b_fname);
748:
749: /* remark any previously deleted files with a 'D' */
750: if (ddel)
751: redelete(bp);
752:
753: /* find dot line */
754: bp->b_dotp = bfirstlp(bp);
755: if (tmp_w_dotline > bp->b_lines)
756: tmp_w_dotline = bp->b_lines - 1;
757: for (i = 1; i < tmp_w_dotline; i++)
758: bp->b_dotp = lforw(bp->b_dotp);
759:
760: bp->b_dotline = i;
761: bp->b_doto = 0;
762: d_warpdot(bp->b_dotp, &bp->b_doto);
763:
1.54 lum 764: curbp = bp;
765:
766: return (bp);
1.12 vincent 767: }
1.24 kjell 768:
769: static int
1.34 kjell 770: d_makename(struct line *lp, char *fn, size_t len)
1.24 kjell 771: {
1.50 lum 772: int start, nlen;
773: char *namep;
1.24 kjell 774:
1.50 lum 775: if (d_warpdot(lp, &start) == FALSE)
1.24 kjell 776: return (ABORT);
1.50 lum 777: namep = &lp->l_text[start];
778: nlen = llength(lp) - start;
779:
780: if (snprintf(fn, len, "%s%.*s", curbp->b_fname, nlen, namep) >= len)
781: return (ABORT); /* Name is too long. */
782:
783: /* Return TRUE if the entry is a directory. */
1.24 kjell 784: return ((lgetc(lp, 2) == 'd') ? TRUE : FALSE);
785: }
786:
1.50 lum 787: #define NAME_FIELD 9
788:
1.49 lum 789: static int
790: d_warpdot(struct line *dotp, int *doto)
791: {
792: char *tp = dotp->l_text;
793: int off = 0, field = 0, len;
794:
795: /*
796: * Find the byte offset to the (space-delimited) filename
797: * field in formatted ls output.
798: */
799: len = llength(dotp);
800: while (off < len) {
801: if (tp[off++] == ' ') {
1.50 lum 802: if (++field == NAME_FIELD) {
803: *doto = off;
804: return (TRUE);
805: }
1.49 lum 806: /* Skip the space. */
807: while (off < len && tp[off] == ' ')
808: off++;
809: }
810: }
1.50 lum 811: /* We didn't find the field. */
812: *doto = 0;
813: return (FALSE);
1.49 lum 814: }
815:
816: static int
1.76 jasper 817: d_forwpage(int f, int n)
1.49 lum 818: {
819: forwpage(f | FFRAND, n);
820: return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
821: }
822:
1.76 jasper 823: static int
1.49 lum 824: d_backpage (int f, int n)
825: {
826: backpage(f | FFRAND, n);
827: return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
828: }
829:
830: static int
831: d_forwline (int f, int n)
832: {
833: forwline(f | FFRAND, n);
834: return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
835: }
836:
837: static int
838: d_backline (int f, int n)
839: {
840: backline(f | FFRAND, n);
841: return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
842: }
843:
1.24 kjell 844: /*
1.33 kjell 845: * XXX dname needs to have enough place to store an additional '/'.
1.24 kjell 846: */
1.31 deraadt 847: struct buffer *
1.33 kjell 848: dired_(char *dname)
1.24 kjell 849: {
1.31 deraadt 850: struct buffer *bp;
1.52 haesbaer 851: int i;
852: size_t len;
1.46 kjell 853:
1.77 lum 854: if ((dname = adjustname(dname, TRUE)) == NULL) {
1.66 lum 855: dobeep();
1.24 kjell 856: ewprintf("Bad directory name");
857: return (NULL);
858: }
859: /* this should not be done, instead adjustname() should get a flag */
1.33 kjell 860: len = strlen(dname);
861: if (dname[len - 1] != '/') {
862: dname[len++] = '/';
863: dname[len] = '\0';
1.58 lum 864: }
865: if ((access(dname, R_OK | X_OK)) == -1) {
1.66 lum 866: if (errno == EACCES) {
867: dobeep();
1.58 lum 868: ewprintf("Permission denied");
1.66 lum 869: }
1.58 lum 870: return (NULL);
1.24 kjell 871: }
1.73 lum 872: for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
873: if (strcmp(bp->b_fname, dname) == 0) {
874: if (fchecktime(bp) != TRUE)
875: ewprintf("Directory has changed on disk;"
876: " type g to update Dired");
877: return (bp);
878: }
879:
1.24 kjell 880: }
1.73 lum 881: bp = bfind(dname, TRUE);
1.65 lum 882: bp->b_flag |= BFREADONLY | BFIGNDIRTY;
1.50 lum 883:
884: if ((d_exec(2, bp, NULL, "ls", "-al", dname, NULL)) != TRUE)
1.24 kjell 885: return (NULL);
1.49 lum 886:
887: /* Find the line with ".." on it. */
1.41 kjell 888: bp->b_dotp = bfirstlp(bp);
1.72 lum 889: bp->b_dotline = 1;
1.49 lum 890: for (i = 0; i < bp->b_lines; i++) {
891: bp->b_dotp = lforw(bp->b_dotp);
1.72 lum 892: bp->b_dotline++;
1.50 lum 893: if (d_warpdot(bp->b_dotp, &bp->b_doto) == FALSE)
1.49 lum 894: continue;
895: if (strcmp(ltext(bp->b_dotp) + bp->b_doto, "..") == 0)
896: break;
897: }
898:
899: /* We want dot on the entry right after "..", if possible. */
1.72 lum 900: if (++i < bp->b_lines - 2) {
1.49 lum 901: bp->b_dotp = lforw(bp->b_dotp);
1.72 lum 902: bp->b_dotline++;
903: }
1.49 lum 904: d_warpdot(bp->b_dotp, &bp->b_doto);
905:
1.36 kjell 906: (void)strlcpy(bp->b_fname, dname, sizeof(bp->b_fname));
907: (void)strlcpy(bp->b_cwd, dname, sizeof(bp->b_cwd));
1.24 kjell 908: if ((bp->b_modes[1] = name_mode("dired")) == NULL) {
909: bp->b_modes[0] = name_mode("fundamental");
1.66 lum 910: dobeep();
1.24 kjell 911: ewprintf("Could not find mode dired");
912: return (NULL);
913: }
1.73 lum 914: (void)fupdstat(bp);
1.24 kjell 915: bp->b_nmodes = 1;
916: return (bp);
1.78 lum 917: }
918:
919: /*
920: * Iterate through the lines of the dired buffer looking for files
921: * collected in the linked list made in createlist(). If a line is found
922: * replace 'D' as first char in a line. As lines are found, remove the
923: * corresponding item from the linked list. Iterate for as long as there
924: * are items in the linked list or until end of buffer is found.
925: */
926: void
927: redelete(struct buffer *bp)
928: {
929: struct delentry *d1 = NULL;
930: struct line *lp, *nlp;
931: char fname[NFILEN];
932: char *p = fname;
933: size_t plen, fnlen;
934: int finished = 0;
935:
936: /* reset the deleted file buffer flag until a deleted file is found */
937: bp->b_flag &= ~BFDIREDDEL;
938:
939: for (lp = bfirstlp(bp); lp != bp->b_headp; lp = nlp) {
940: bp->b_dotp = lp;
941: if ((p = findfname(lp, p)) == NULL) {
942: nlp = lforw(lp);
943: continue;
944: }
945: plen = strlen(p);
946: SLIST_FOREACH(d1, &delhead, entry) {
947: fnlen = strlen(d1->fn);
948: if ((plen == fnlen) &&
949: (strncmp(p, d1->fn, plen) == 0)) {
950: lputc(bp->b_dotp, 0, DDELCHAR);
951: bp->b_flag |= BFDIREDDEL;
952: SLIST_REMOVE(&delhead, d1, delentry, entry);
953: if (SLIST_EMPTY(&delhead)) {
954: finished = 1;
955: break;
956: }
957: }
958: }
959: if (finished)
960: break;
961: nlp = lforw(lp);
962: }
963: while (!SLIST_EMPTY(&delhead)) {
964: d1 = SLIST_FIRST(&delhead);
965: SLIST_REMOVE_HEAD(&delhead, entry);
966: free(d1->fn);
967: free(d1);
968: }
969: return;
970: }
971:
972: /*
973: * Create a list of files marked for deletion.
974: */
975: int
976: createlist(struct buffer *bp)
977: {
978: struct delentry *d1 = NULL, *d2;
979: struct line *lp, *nlp;
980: char fname[NFILEN];
981: char *p = fname;
982: int ret = FALSE;
983:
984: for (lp = bfirstlp(bp); lp != bp->b_headp; lp = nlp) {
985: /*
986: * Check if the line has 'D' on the first char and if a valid
987: * filename can be extracted from it.
988: */
989: if (((lp->l_text[0] != DDELCHAR)) ||
990: ((p = findfname(lp, p)) == NULL)) {
991: nlp = lforw(lp);
992: continue;
993: }
994: if (SLIST_EMPTY(&delhead)) {
995: if ((d1 = malloc(sizeof(struct delentry)))
996: == NULL)
997: return (ABORT);
998: if ((d1->fn = strdup(p)) == NULL) {
999: free(d1);
1000: return (ABORT);
1001: }
1002: SLIST_INSERT_HEAD(&delhead, d1, entry);
1003: } else {
1004: if ((d2 = malloc(sizeof(struct delentry)))
1005: == NULL) {
1006: free(d1->fn);
1007: free(d1);
1008: return (ABORT);
1009: }
1010: if ((d2->fn = strdup(p)) == NULL) {
1011: free(d1->fn);
1012: free(d1);
1013: free(d2);
1014: return (ABORT);
1015: }
1016: SLIST_INSERT_AFTER(d1, d2, entry);
1017: d1 = d2;
1018: }
1019: ret = TRUE;
1020: nlp = lforw(lp);
1021: }
1022: return (ret);
1023: }
1024:
1025: /*
1026: * Look for and extract a file name on a dired buffer line.
1027: */
1028: char *
1029: findfname(struct line *lp, char *fn)
1030: {
1031: int start;
1032:
1033: (void)d_warpdot(lp, &start);
1034: if (start < 1)
1035: return NULL;
1036: fn = &lp->l_text[start];
1037: return fn;
1.24 kjell 1038: }