Annotation of src/usr.bin/mg/dired.c, Revision 1.81
1.81 ! mmcc 1: /* $OpenBSD: dired.c,v 1.80 2015/10/29 19:46:47 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);
1.81 ! mmcc 676: free(argv);
1.50 lum 677: return ret;
1.12 vincent 678: }
679:
1.26 kjell 680: /* ARGSUSED */
1.12 vincent 681: int
682: d_create_directory(int f, int n)
683: {
1.57 lum 684: int ret;
1.31 deraadt 685: struct buffer *bp;
1.12 vincent 686:
1.67 lum 687: ret = ask_makedir();
1.57 lum 688: if (ret != TRUE)
689: return(ret);
690:
1.54 lum 691: if ((bp = refreshbuffer(curbp)) == NULL)
692: return (FALSE);
1.57 lum 693:
1.37 kjell 694: return (showbuffer(bp, curwp, WFFULL | WFMODE));
1.62 lum 695: }
696:
697: /* ARGSUSED */
698: int
699: d_killbuffer_cmd(int f, int n)
700: {
701: return(killbuffer_cmd(FFRAND, 0));
1.63 lum 702: }
703:
704: int
705: d_refreshbuffer(int f, int n)
706: {
707: struct buffer *bp;
708:
709: if ((bp = refreshbuffer(curbp)) == NULL)
710: return (FALSE);
711:
712: return (showbuffer(bp, curwp, WFFULL | WFMODE));
1.54 lum 713: }
714:
1.78 lum 715: /*
716: * Kill then re-open the requested dired buffer.
717: * If required, take a note of any files marked for deletion. Then once
718: * the buffer has been re-opened, remark the same files as deleted.
719: */
1.54 lum 720: struct buffer *
721: refreshbuffer(struct buffer *bp)
722: {
1.78 lum 723: char *tmp_b_fname;
724: int i, tmp_w_dotline, ddel = 0;
1.54 lum 725:
1.78 lum 726: /* remember directory path to open later */
727: tmp_b_fname = strdup(bp->b_fname);
728: if (tmp_b_fname == NULL) {
1.66 lum 729: dobeep();
1.55 lum 730: ewprintf("Out of memory");
1.61 lum 731: return (NULL);
1.55 lum 732: }
1.78 lum 733: tmp_w_dotline = curwp->w_dotline;
734:
735: /* create a list of files for deletion */
736: if (bp->b_flag & BFDIREDDEL)
737: ddel = createlist(bp);
1.54 lum 738:
739: killbuffer(bp);
740:
741: /* dired_() uses findbuffer() to create new buffer */
1.78 lum 742: if ((bp = dired_(tmp_b_fname)) == NULL) {
743: free(tmp_b_fname);
1.54 lum 744: return (NULL);
745: }
1.78 lum 746: free(tmp_b_fname);
747:
748: /* remark any previously deleted files with a 'D' */
749: if (ddel)
750: redelete(bp);
751:
752: /* find dot line */
753: bp->b_dotp = bfirstlp(bp);
754: if (tmp_w_dotline > bp->b_lines)
755: tmp_w_dotline = bp->b_lines - 1;
756: for (i = 1; i < tmp_w_dotline; i++)
757: bp->b_dotp = lforw(bp->b_dotp);
758:
759: bp->b_dotline = i;
760: bp->b_doto = 0;
761: d_warpdot(bp->b_dotp, &bp->b_doto);
762:
1.54 lum 763: curbp = bp;
764:
765: return (bp);
1.12 vincent 766: }
1.24 kjell 767:
768: static int
1.34 kjell 769: d_makename(struct line *lp, char *fn, size_t len)
1.24 kjell 770: {
1.50 lum 771: int start, nlen;
772: char *namep;
1.24 kjell 773:
1.50 lum 774: if (d_warpdot(lp, &start) == FALSE)
1.24 kjell 775: return (ABORT);
1.50 lum 776: namep = &lp->l_text[start];
777: nlen = llength(lp) - start;
778:
779: if (snprintf(fn, len, "%s%.*s", curbp->b_fname, nlen, namep) >= len)
780: return (ABORT); /* Name is too long. */
781:
782: /* Return TRUE if the entry is a directory. */
1.24 kjell 783: return ((lgetc(lp, 2) == 'd') ? TRUE : FALSE);
784: }
785:
1.50 lum 786: #define NAME_FIELD 9
787:
1.49 lum 788: static int
789: d_warpdot(struct line *dotp, int *doto)
790: {
791: char *tp = dotp->l_text;
792: int off = 0, field = 0, len;
793:
794: /*
795: * Find the byte offset to the (space-delimited) filename
796: * field in formatted ls output.
797: */
798: len = llength(dotp);
799: while (off < len) {
800: if (tp[off++] == ' ') {
1.50 lum 801: if (++field == NAME_FIELD) {
802: *doto = off;
803: return (TRUE);
804: }
1.49 lum 805: /* Skip the space. */
806: while (off < len && tp[off] == ' ')
807: off++;
808: }
809: }
1.50 lum 810: /* We didn't find the field. */
811: *doto = 0;
812: return (FALSE);
1.49 lum 813: }
814:
815: static int
1.76 jasper 816: d_forwpage(int f, int n)
1.49 lum 817: {
818: forwpage(f | FFRAND, n);
819: return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
820: }
821:
1.76 jasper 822: static int
1.49 lum 823: d_backpage (int f, int n)
824: {
825: backpage(f | FFRAND, n);
826: return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
827: }
828:
829: static int
830: d_forwline (int f, int n)
831: {
832: forwline(f | FFRAND, n);
833: return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
834: }
835:
836: static int
837: d_backline (int f, int n)
838: {
839: backline(f | FFRAND, n);
840: return (d_warpdot(curwp->w_dotp, &curwp->w_doto));
841: }
842:
1.24 kjell 843: /*
1.33 kjell 844: * XXX dname needs to have enough place to store an additional '/'.
1.24 kjell 845: */
1.31 deraadt 846: struct buffer *
1.33 kjell 847: dired_(char *dname)
1.24 kjell 848: {
1.31 deraadt 849: struct buffer *bp;
1.52 haesbaer 850: int i;
851: size_t len;
1.46 kjell 852:
1.77 lum 853: if ((dname = adjustname(dname, TRUE)) == NULL) {
1.66 lum 854: dobeep();
1.24 kjell 855: ewprintf("Bad directory name");
856: return (NULL);
857: }
858: /* this should not be done, instead adjustname() should get a flag */
1.33 kjell 859: len = strlen(dname);
860: if (dname[len - 1] != '/') {
861: dname[len++] = '/';
862: dname[len] = '\0';
1.58 lum 863: }
864: if ((access(dname, R_OK | X_OK)) == -1) {
1.66 lum 865: if (errno == EACCES) {
866: dobeep();
1.80 lum 867: ewprintf("Permission denied: %s", dname);
1.66 lum 868: }
1.58 lum 869: return (NULL);
1.24 kjell 870: }
1.73 lum 871: for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
872: if (strcmp(bp->b_fname, dname) == 0) {
873: if (fchecktime(bp) != TRUE)
874: ewprintf("Directory has changed on disk;"
875: " type g to update Dired");
876: return (bp);
877: }
878:
1.24 kjell 879: }
1.73 lum 880: bp = bfind(dname, TRUE);
1.65 lum 881: bp->b_flag |= BFREADONLY | BFIGNDIRTY;
1.50 lum 882:
883: if ((d_exec(2, bp, NULL, "ls", "-al", dname, NULL)) != TRUE)
1.24 kjell 884: return (NULL);
1.49 lum 885:
886: /* Find the line with ".." on it. */
1.41 kjell 887: bp->b_dotp = bfirstlp(bp);
1.72 lum 888: bp->b_dotline = 1;
1.49 lum 889: for (i = 0; i < bp->b_lines; i++) {
890: bp->b_dotp = lforw(bp->b_dotp);
1.72 lum 891: bp->b_dotline++;
1.50 lum 892: if (d_warpdot(bp->b_dotp, &bp->b_doto) == FALSE)
1.49 lum 893: continue;
894: if (strcmp(ltext(bp->b_dotp) + bp->b_doto, "..") == 0)
895: break;
896: }
897:
898: /* We want dot on the entry right after "..", if possible. */
1.72 lum 899: if (++i < bp->b_lines - 2) {
1.49 lum 900: bp->b_dotp = lforw(bp->b_dotp);
1.72 lum 901: bp->b_dotline++;
902: }
1.49 lum 903: d_warpdot(bp->b_dotp, &bp->b_doto);
904:
1.36 kjell 905: (void)strlcpy(bp->b_fname, dname, sizeof(bp->b_fname));
906: (void)strlcpy(bp->b_cwd, dname, sizeof(bp->b_cwd));
1.24 kjell 907: if ((bp->b_modes[1] = name_mode("dired")) == NULL) {
908: bp->b_modes[0] = name_mode("fundamental");
1.66 lum 909: dobeep();
1.24 kjell 910: ewprintf("Could not find mode dired");
911: return (NULL);
912: }
1.73 lum 913: (void)fupdstat(bp);
1.24 kjell 914: bp->b_nmodes = 1;
915: return (bp);
1.78 lum 916: }
917:
918: /*
919: * Iterate through the lines of the dired buffer looking for files
920: * collected in the linked list made in createlist(). If a line is found
921: * replace 'D' as first char in a line. As lines are found, remove the
922: * corresponding item from the linked list. Iterate for as long as there
923: * are items in the linked list or until end of buffer is found.
924: */
925: void
926: redelete(struct buffer *bp)
927: {
928: struct delentry *d1 = NULL;
929: struct line *lp, *nlp;
930: char fname[NFILEN];
931: char *p = fname;
932: size_t plen, fnlen;
933: int finished = 0;
934:
935: /* reset the deleted file buffer flag until a deleted file is found */
936: bp->b_flag &= ~BFDIREDDEL;
937:
938: for (lp = bfirstlp(bp); lp != bp->b_headp; lp = nlp) {
939: bp->b_dotp = lp;
940: if ((p = findfname(lp, p)) == NULL) {
941: nlp = lforw(lp);
942: continue;
943: }
944: plen = strlen(p);
945: SLIST_FOREACH(d1, &delhead, entry) {
946: fnlen = strlen(d1->fn);
947: if ((plen == fnlen) &&
948: (strncmp(p, d1->fn, plen) == 0)) {
949: lputc(bp->b_dotp, 0, DDELCHAR);
950: bp->b_flag |= BFDIREDDEL;
951: SLIST_REMOVE(&delhead, d1, delentry, entry);
952: if (SLIST_EMPTY(&delhead)) {
953: finished = 1;
954: break;
955: }
956: }
957: }
958: if (finished)
959: break;
960: nlp = lforw(lp);
961: }
962: while (!SLIST_EMPTY(&delhead)) {
963: d1 = SLIST_FIRST(&delhead);
964: SLIST_REMOVE_HEAD(&delhead, entry);
965: free(d1->fn);
966: free(d1);
967: }
968: return;
969: }
970:
971: /*
972: * Create a list of files marked for deletion.
973: */
974: int
975: createlist(struct buffer *bp)
976: {
977: struct delentry *d1 = NULL, *d2;
978: struct line *lp, *nlp;
979: char fname[NFILEN];
980: char *p = fname;
981: int ret = FALSE;
982:
983: for (lp = bfirstlp(bp); lp != bp->b_headp; lp = nlp) {
984: /*
985: * Check if the line has 'D' on the first char and if a valid
986: * filename can be extracted from it.
987: */
988: if (((lp->l_text[0] != DDELCHAR)) ||
989: ((p = findfname(lp, p)) == NULL)) {
990: nlp = lforw(lp);
991: continue;
992: }
993: if (SLIST_EMPTY(&delhead)) {
994: if ((d1 = malloc(sizeof(struct delentry)))
995: == NULL)
996: return (ABORT);
997: if ((d1->fn = strdup(p)) == NULL) {
998: free(d1);
999: return (ABORT);
1000: }
1001: SLIST_INSERT_HEAD(&delhead, d1, entry);
1002: } else {
1003: if ((d2 = malloc(sizeof(struct delentry)))
1004: == NULL) {
1005: free(d1->fn);
1006: free(d1);
1007: return (ABORT);
1008: }
1009: if ((d2->fn = strdup(p)) == NULL) {
1010: free(d1->fn);
1011: free(d1);
1012: free(d2);
1013: return (ABORT);
1014: }
1015: SLIST_INSERT_AFTER(d1, d2, entry);
1016: d1 = d2;
1017: }
1018: ret = TRUE;
1019: nlp = lforw(lp);
1020: }
1021: return (ret);
1022: }
1023:
1024: /*
1025: * Look for and extract a file name on a dired buffer line.
1026: */
1027: char *
1028: findfname(struct line *lp, char *fn)
1029: {
1030: int start;
1031:
1032: (void)d_warpdot(lp, &start);
1033: if (start < 1)
1034: return NULL;
1035: fn = &lp->l_text[start];
1036: return fn;
1.24 kjell 1037: }