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