Annotation of src/usr.bin/mg/dired.c, Revision 1.22
1.22 ! deraadt 1: /* $OpenBSD: dired.c,v 1.21 2005/08/09 00:53:48 kjell 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:
9: #include "def.h"
1.9 vincent 10: #include "kbd.h"
1.12 vincent 11: #include <sys/types.h>
12: #include <sys/stat.h>
13: #include <sys/wait.h>
14:
15: #include <signal.h>
16: #include <fcntl.h>
17: #include <errno.h>
18: #include <libgen.h>
1.1 deraadt 19:
20: #ifndef NO_DIRED
1.11 vincent 21:
22: int d_findfile(int, int);
1.1 deraadt 23:
1.12 vincent 24: static PF dired_cmds_1[] = {
25: forwline, /* space */
26: d_shell_command, /* ! */
27: rescan, /* " */
28: rescan, /* # */
29: rescan, /* $ */
30: rescan, /* % */
31: rescan, /* & */
32: rescan, /* ' */
33: rescan, /* ( */
34: rescan, /* ) */
35: rescan, /* * */
1.15 db 36: d_create_directory /* + */
1.12 vincent 37: };
38:
39: static PF dired_cmds_2[] = {
1.15 db 40: rescan, /* a */
41: rescan, /* b */
42: rescan, /* c */
43: rescan, /* d */
44: d_findfile, /* e */
45: d_findfile, /* f */
46: rescan, /* g */
47: rescan, /* h */
48: rescan, /* i */
49: rescan, /* j */
50: rescan, /* k */
51: rescan, /* l */
52: rescan, /* m */
53: forwline, /* n */
54: d_ffotherwindow, /* o */
55: rescan, /* p */
56: rescan, /* q */
57: rescan, /* r */
58: rescan, /* s */
59: rescan, /* t */
60: rescan, /* u */
61: d_findfile, /* v */
62: rescan, /* w */
63: d_expunge, /* x */
64: rescan, /* y */
65: rescan /* z */
1.12 vincent 66: };
67:
68: static PF dired_cmds_3[] = {
1.15 db 69: rescan, /* A */
70: rescan, /* B */
71: d_copy, /* C */
72: d_del, /* D */
73: rescan, /* E */
74: rescan, /* F */
75: rescan, /* G */
76: rescan, /* H */
77: rescan, /* I */
78: rescan, /* J */
79: rescan, /* K */
80: rescan, /* L */
81: rescan, /* M */
82: rescan, /* N */
83: rescan, /* O */
84: rescan, /* P */
85: rescan, /* Q */
86: d_rename, /* R */
87: rescan, /* S */
88: rescan, /* T */
89: rescan, /* U */
90: d_findfile, /* V */
91: rescan, /* W */
92: d_expunge, /* X */
93: rescan, /* Y */
94: rescan /* Z */
1.12 vincent 95: };
96:
1.9 vincent 97: static PF dired_pf[] = {
1.15 db 98: d_findfile, /* ^M */
99: rescan, /* ^N */
100: d_findfile /* ^O */
1.9 vincent 101: };
1.13 deraadt 102:
1.12 vincent 103: static struct KEYMAPE (4 + IMAPEXT) diredmap = {
104: 4,
105: 4 + IMAPEXT,
1.9 vincent 106: rescan,
107: {
1.12 vincent 108: { CCHR('M'), CCHR('O'), dired_pf, NULL },
109: { ' ', '+', dired_cmds_1, NULL },
110: { 'A', 'Z', dired_cmds_3, NULL },
111: { 'a', 'z', dired_cmds_2, NULL }
1.9 vincent 112: }
113: };
114:
1.12 vincent 115:
1.5 millert 116: /* ARGSUSED */
117: int
1.10 vincent 118: dired(int f, int n)
1.1 deraadt 119: {
1.15 db 120: static int inited = 0;
1.19 cloder 121: char dirname[NFILEN], *bufp, *slash;
1.15 db 122: BUFFER *bp;
1.1 deraadt 123:
1.9 vincent 124: if (inited == 0) {
125: maps_add((KEYMAP *)&diredmap, "dired");
126: inited = 1;
127: }
128:
1.19 cloder 129: if (curbp->b_fname && curbp->b_fname[0] != '\0') {
1.21 kjell 130: (void)strlcpy(dirname, curbp->b_fname, sizeof(dirname));
1.19 cloder 131: if ((slash = strrchr(dirname, '/')) != NULL) {
132: *(slash + 1) = '\0';
133: }
134: } else {
135: if (getcwd(dirname, sizeof(dirname)) == NULL)
136: dirname[0] = '\0';
137: }
138:
1.21 kjell 139: if ((bufp = eread("Dired: ", dirname, NFILEN,
140: EFDEF | EFNEW | EFCR)) == NULL)
1.15 db 141: return (ABORT);
1.21 kjell 142: if (bufp[0] == '\0')
143: return (FALSE);
1.14 vincent 144: if ((bp = dired_(bufp)) == NULL)
1.15 db 145: return (FALSE);
1.9 vincent 146: bp->b_modes[0] = name_mode("fundamental");
147: bp->b_modes[1] = name_mode("dired");
148: bp->b_nmodes = 1;
1.5 millert 149: curbp = bp;
1.15 db 150: return (showbuffer(bp, curwp, WFHARD | WFMODE));
1.1 deraadt 151: }
152:
1.5 millert 153: /* ARGSUSED */
154: int
1.10 vincent 155: d_otherwindow(int f, int n)
1.1 deraadt 156: {
1.15 db 157: char dirname[NFILEN], *bufp;
1.7 mickey 158: BUFFER *bp;
159: MGWIN *wp;
1.5 millert 160:
161: dirname[0] = '\0';
1.14 vincent 162: if ((bufp = eread("Dired other window: ", dirname, NFILEN,
1.21 kjell 163: EFDEF | EFNEW | EFCR)) == NULL)
1.15 db 164: return (ABORT);
1.21 kjell 165: else if (bufp[0] == '\0')
166: return (FALSE);
1.14 vincent 167: if ((bp = dired_(bufp)) == NULL)
1.15 db 168: return (FALSE);
1.5 millert 169: if ((wp = popbuf(bp)) == NULL)
1.15 db 170: return (FALSE);
1.5 millert 171: curbp = bp;
172: curwp = wp;
1.15 db 173: return (TRUE);
1.1 deraadt 174: }
175:
1.5 millert 176: /* ARGSUSED */
177: int
1.10 vincent 178: d_del(int f, int n)
1.1 deraadt 179: {
1.5 millert 180: if (n < 0)
1.15 db 181: return (FALSE);
1.5 millert 182: while (n--) {
183: if (llength(curwp->w_dotp) > 0)
184: lputc(curwp->w_dotp, 0, 'D');
185: if (lforw(curwp->w_dotp) != curbp->b_linep)
186: curwp->w_dotp = lforw(curwp->w_dotp);
187: }
188: curwp->w_flag |= WFEDIT | WFMOVE;
189: curwp->w_doto = 0;
1.15 db 190: return (TRUE);
1.1 deraadt 191: }
192:
1.5 millert 193: /* ARGSUSED */
194: int
1.10 vincent 195: d_undel(int f, int n)
1.1 deraadt 196: {
1.5 millert 197: if (n < 0)
1.15 db 198: return (d_undelbak(f, -n));
1.5 millert 199: while (n--) {
200: if (llength(curwp->w_dotp) > 0)
201: lputc(curwp->w_dotp, 0, ' ');
202: if (lforw(curwp->w_dotp) != curbp->b_linep)
203: curwp->w_dotp = lforw(curwp->w_dotp);
204: }
205: curwp->w_flag |= WFEDIT | WFMOVE;
206: curwp->w_doto = 0;
1.15 db 207: return (TRUE);
1.1 deraadt 208: }
209:
1.5 millert 210: /* ARGSUSED */
211: int
1.10 vincent 212: d_undelbak(int f, int n)
1.1 deraadt 213: {
1.5 millert 214: if (n < 0)
1.15 db 215: return (d_undel(f, -n));
1.5 millert 216: while (n--) {
217: if (llength(curwp->w_dotp) > 0)
218: lputc(curwp->w_dotp, 0, ' ');
219: if (lback(curwp->w_dotp) != curbp->b_linep)
220: curwp->w_dotp = lback(curwp->w_dotp);
221: }
222: curwp->w_doto = 0;
223: curwp->w_flag |= WFEDIT | WFMOVE;
1.15 db 224: return (TRUE);
1.1 deraadt 225: }
226:
1.5 millert 227: /* ARGSUSED */
228: int
1.10 vincent 229: d_findfile(int f, int n)
1.1 deraadt 230: {
1.15 db 231: BUFFER *bp;
232: int s;
233: char fname[NFILEN];
1.5 millert 234:
1.15 db 235: if ((s = d_makename(curwp->w_dotp, fname, sizeof(fname))) == ABORT)
236: return (FALSE);
1.12 vincent 237: if (s == TRUE)
238: bp = dired_(fname);
239: else
240: bp = findbuffer(fname);
241: if (bp == NULL)
1.15 db 242: return (FALSE);
1.5 millert 243: curbp = bp;
244: if (showbuffer(bp, curwp, WFHARD) != TRUE)
1.15 db 245: return (FALSE);
1.5 millert 246: if (bp->b_fname[0] != 0)
1.15 db 247: return (TRUE);
248: return (readin(fname));
1.1 deraadt 249: }
250:
1.5 millert 251: /* ARGSUSED */
252: int
1.10 vincent 253: d_ffotherwindow(int f, int n)
1.1 deraadt 254: {
1.7 mickey 255: char fname[NFILEN];
256: int s;
1.5 millert 257: BUFFER *bp;
258: MGWIN *wp;
259:
1.15 db 260: if ((s = d_makename(curwp->w_dotp, fname, sizeof(fname))) == ABORT)
261: return (FALSE);
1.5 millert 262: if ((bp = (s ? dired_(fname) : findbuffer(fname))) == NULL)
1.15 db 263: return (FALSE);
1.5 millert 264: if ((wp = popbuf(bp)) == NULL)
1.15 db 265: return (FALSE);
1.5 millert 266: curbp = bp;
267: curwp = wp;
268: if (bp->b_fname[0] != 0)
1.15 db 269: return (TRUE); /* never true for dired buffers */
270: return (readin(fname));
1.1 deraadt 271: }
272:
1.5 millert 273: /* ARGSUSED */
274: int
1.10 vincent 275: d_expunge(int f, int n)
1.1 deraadt 276: {
1.7 mickey 277: LINE *lp, *nlp;
1.15 db 278: char fname[NFILEN];
1.5 millert 279:
280: for (lp = lforw(curbp->b_linep); lp != curbp->b_linep; lp = nlp) {
281: nlp = lforw(lp);
282: if (llength(lp) && lgetc(lp, 0) == 'D') {
1.15 db 283: switch (d_makename(lp, fname, sizeof(fname))) {
1.5 millert 284: case ABORT:
285: ewprintf("Bad line in dired buffer");
1.15 db 286: return (FALSE);
1.5 millert 287: case FALSE:
288: if (unlink(fname) < 0) {
1.12 vincent 289: ewprintf("Could not delete '%s'",
290: basename(fname));
1.15 db 291: return (FALSE);
1.5 millert 292: }
293: break;
294: case TRUE:
295: if (rmdir(fname) < 0) {
296: ewprintf("Could not delete directory '%s'",
1.12 vincent 297: basename(fname));
1.15 db 298: return (FALSE);
1.5 millert 299: }
300: break;
301: }
302: lfree(lp);
303: curwp->w_flag |= WFHARD;
304: }
1.1 deraadt 305: }
1.15 db 306: return (TRUE);
1.1 deraadt 307: }
308:
1.5 millert 309: /* ARGSUSED */
310: int
1.10 vincent 311: d_copy(int f, int n)
1.1 deraadt 312: {
1.14 vincent 313: char frname[NFILEN], toname[NFILEN], *bufp;
314: int stat;
1.18 cloder 315: size_t off;
1.12 vincent 316: BUFFER *bp;
1.1 deraadt 317:
1.15 db 318: if (d_makename(curwp->w_dotp, frname, sizeof(frname)) != FALSE) {
1.5 millert 319: ewprintf("Not a file");
1.15 db 320: return (FALSE);
1.5 millert 321: }
1.15 db 322: off = strlcpy(toname, curbp->b_fname, sizeof(toname));
323: if (off >= sizeof(toname) - 1) { /* can't happen, really */
1.18 cloder 324: ewprintf("Directory name too long");
1.12 vincent 325: return (FALSE);
326: }
1.21 kjell 327: if ((bufp = eread("Copy %s to: ", toname, sizeof(toname),
328: EFDEF | EFNEW | EFCR, basename(frname))) == NULL)
1.15 db 329: return (ABORT);
1.14 vincent 330: else if (bufp[0] == '\0')
1.17 otto 331: return (FALSE);
1.12 vincent 332: stat = (copy(frname, toname) >= 0) ? TRUE : FALSE;
333: if (stat != TRUE)
334: return (stat);
335: bp = dired_(curbp->b_fname);
336: return (showbuffer(bp, curwp, WFHARD | WFMODE));
1.1 deraadt 337: }
338:
1.5 millert 339: /* ARGSUSED */
340: int
1.10 vincent 341: d_rename(int f, int n)
1.1 deraadt 342: {
1.14 vincent 343: char frname[NFILEN], toname[NFILEN], *bufp;
1.18 cloder 344: int stat;
345: size_t off;
1.12 vincent 346: BUFFER *bp;
1.1 deraadt 347:
1.15 db 348: if (d_makename(curwp->w_dotp, frname, sizeof(frname)) != FALSE) {
1.5 millert 349: ewprintf("Not a file");
1.15 db 350: return (FALSE);
1.5 millert 351: }
1.15 db 352: off = strlcpy(toname, curbp->b_fname, sizeof(toname));
353: if (off >= sizeof(toname) - 1) { /* can't happen, really */
1.18 cloder 354: ewprintf("Directory name too long");
1.12 vincent 355: return (FALSE);
356: }
1.21 kjell 357: if ((bufp = eread("Rename %s to: ", toname,
358: sizeof(toname), EFDEF | EFNEW | EFCR, basename(frname))) == NULL)
1.15 db 359: return (ABORT);
1.14 vincent 360: else if (bufp[0] == '\0')
1.15 db 361: return (FALSE);
1.12 vincent 362: stat = (rename(frname, toname) >= 0) ? TRUE : FALSE;
363: if (stat != TRUE)
364: return (stat);
365: bp = dired_(curbp->b_fname);
366: return (showbuffer(bp, curwp, WFHARD | WFMODE));
1.1 deraadt 367: }
368: #endif
1.12 vincent 369:
370: void
371: reaper(int signo __attribute__((unused)))
372: {
1.22 ! deraadt 373: int save_errno = errno, status;
1.15 db 374: pid_t ret;
1.12 vincent 375:
376: while ((ret = waitpid(-1, &status, WNOHANG)) >= 0)
377: ;
1.22 ! deraadt 378: errno = save_errno;
1.12 vincent 379: }
380:
381: /*
382: * Pipe the currently selected file through a shell command.
383: */
384: int
385: d_shell_command(int f, int n)
386: {
1.15 db 387: char command[512], fname[MAXPATHLEN], buf[BUFSIZ], *bufp, *cp;
388: int infd, fds[2];
389: pid_t pid;
390: struct sigaction olda, newa;
391: BUFFER *bp;
392: MGWIN *wp;
393: FILE *fin;
1.12 vincent 394:
395: bp = bfind("*Shell Command Output*", TRUE);
396: if (bclear(bp) != TRUE)
397: return (ABORT);
398:
1.15 db 399: if (d_makename(curwp->w_dotp, fname, sizeof(fname)) != FALSE) {
1.12 vincent 400: ewprintf("bad line");
401: return (ABORT);
402: }
403:
404: command[0] = '\0';
1.21 kjell 405: if ((bufp = eread("! on %s: ", command, sizeof(command), EFNEW,
1.14 vincent 406: basename(fname))) == NULL)
1.12 vincent 407: return (ABORT);
408: infd = open(fname, O_RDONLY);
409: if (infd == -1) {
410: ewprintf("Can't open input file : %s", strerror(errno));
1.21 kjell 411: return (FALSE);
1.12 vincent 412: }
413: if (pipe(fds) == -1) {
414: ewprintf("Can't create pipe : %s", strerror(errno));
415: close(infd);
1.21 kjell 416: return (FALSE);
1.12 vincent 417: }
418:
419: newa.sa_handler = reaper;
420: newa.sa_flags = 0;
421: if (sigaction(SIGCHLD, &newa, &olda) == -1) {
422: close(infd);
423: close(fds[0]);
424: close(fds[1]);
425: return (ABORT);
426: }
427: pid = fork();
428: switch (pid) {
429: case -1:
430: ewprintf("Can't fork");
431: return (ABORT);
432: case 0:
433: close(fds[0]);
434: dup2(infd, STDIN_FILENO);
435: dup2(fds[1], STDOUT_FILENO);
436: dup2(fds[1], STDERR_FILENO);
1.14 vincent 437: execl("/bin/sh", "sh", "-c", bufp, (char *)NULL);
1.12 vincent 438: exit(1);
439: default:
440: close(infd);
441: close(fds[1]);
442: fin = fdopen(fds[0], "r");
443: if (fin == NULL) /* "r" is surely a valid mode! */
444: panic("can't happen");
1.15 db 445: while (fgets(buf, sizeof(buf), fin) != NULL) {
1.12 vincent 446: cp = strrchr(buf, '\n');
447: if (cp == NULL && !feof(fin)) { /* too long a line */
448: int c;
449: addlinef(bp, "%s...", buf);
450: while ((c = getc(fin)) != EOF && c != '\n')
451: ;
452: continue;
453: } else if (cp)
454: *cp = '\0';
455: addline(bp, buf);
456: }
457: fclose(fin);
458: close(fds[0]);
459: break;
460: }
461: wp = popbuf(bp);
462: if (wp == NULL)
463: return (ABORT); /* XXX - free the buffer?? */
464: curwp = wp;
465: curbp = wp->w_bufp;
466: if (sigaction(SIGCHLD, &olda, NULL) == -1)
467: ewprintf("Warning, couldn't reset previous signal handler");
468: return (TRUE);
469: }
470:
471: int
472: d_create_directory(int f, int n)
473: {
1.15 db 474: char tocreate[MAXPATHLEN], *bufp;
1.18 cloder 475: size_t off;
1.15 db 476: BUFFER *bp;
1.12 vincent 477:
1.15 db 478: off = strlcpy(tocreate, curbp->b_fname, sizeof(tocreate));
479: if (off >= sizeof(tocreate) - 1)
1.12 vincent 480: return (FALSE);
1.21 kjell 481: if ((bufp = eread("Create directory: ", tocreate,
482: sizeof(tocreate), EFDEF | EFNEW | EFCR)) == NULL)
1.14 vincent 483: return (ABORT);
484: else if (bufp[0] == '\0')
1.15 db 485: return (FALSE);
1.12 vincent 486: if (mkdir(tocreate, 0755) == -1) {
487: ewprintf("Creating directory: %s, %s", strerror(errno),
488: tocreate);
1.21 kjell 489: return (FALSE);
1.12 vincent 490: }
491: bp = dired_(curbp->b_fname);
492: return (showbuffer(bp, curwp, WFHARD | WFMODE));
493: }