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