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