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