Annotation of src/usr.bin/mg/dired.c, Revision 1.20
1.20 ! kjell 1: /* $OpenBSD: dired.c,v 1.19 2005/05/28 01:53:37 cloder 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') {
130: strlcpy(dirname, curbp->b_fname, sizeof(dirname));
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:
139: if ((bufp = eread("Dired: ", dirname, NFILEN, EFDEF | EFNEW | EFCR)) == NULL)
1.15 db 140: return (ABORT);
1.14 vincent 141: if ((bp = dired_(bufp)) == NULL)
1.15 db 142: return (FALSE);
1.9 vincent 143: bp->b_modes[0] = name_mode("fundamental");
144: bp->b_modes[1] = name_mode("dired");
145: bp->b_nmodes = 1;
1.5 millert 146: curbp = bp;
1.15 db 147: return (showbuffer(bp, curwp, WFHARD | WFMODE));
1.1 deraadt 148: }
149:
1.5 millert 150: /* ARGSUSED */
151: int
1.10 vincent 152: d_otherwindow(int f, int n)
1.1 deraadt 153: {
1.15 db 154: char dirname[NFILEN], *bufp;
1.7 mickey 155: BUFFER *bp;
156: MGWIN *wp;
1.5 millert 157:
158: dirname[0] = '\0';
1.14 vincent 159: if ((bufp = eread("Dired other window: ", dirname, NFILEN,
160: EFNEW | EFCR)) == NULL)
1.15 db 161: return (ABORT);
1.14 vincent 162: if ((bp = dired_(bufp)) == NULL)
1.15 db 163: return (FALSE);
1.5 millert 164: if ((wp = popbuf(bp)) == NULL)
1.15 db 165: return (FALSE);
1.5 millert 166: curbp = bp;
167: curwp = wp;
1.15 db 168: return (TRUE);
1.1 deraadt 169: }
170:
1.5 millert 171: /* ARGSUSED */
172: int
1.10 vincent 173: d_del(int f, int n)
1.1 deraadt 174: {
1.5 millert 175: if (n < 0)
1.15 db 176: return (FALSE);
1.5 millert 177: while (n--) {
178: if (llength(curwp->w_dotp) > 0)
179: lputc(curwp->w_dotp, 0, 'D');
180: if (lforw(curwp->w_dotp) != curbp->b_linep)
181: curwp->w_dotp = lforw(curwp->w_dotp);
182: }
183: curwp->w_flag |= WFEDIT | WFMOVE;
184: curwp->w_doto = 0;
1.15 db 185: return (TRUE);
1.1 deraadt 186: }
187:
1.5 millert 188: /* ARGSUSED */
189: int
1.10 vincent 190: d_undel(int f, int n)
1.1 deraadt 191: {
1.5 millert 192: if (n < 0)
1.15 db 193: return (d_undelbak(f, -n));
1.5 millert 194: while (n--) {
195: if (llength(curwp->w_dotp) > 0)
196: lputc(curwp->w_dotp, 0, ' ');
197: if (lforw(curwp->w_dotp) != curbp->b_linep)
198: curwp->w_dotp = lforw(curwp->w_dotp);
199: }
200: curwp->w_flag |= WFEDIT | WFMOVE;
201: curwp->w_doto = 0;
1.15 db 202: return (TRUE);
1.1 deraadt 203: }
204:
1.5 millert 205: /* ARGSUSED */
206: int
1.10 vincent 207: d_undelbak(int f, int n)
1.1 deraadt 208: {
1.5 millert 209: if (n < 0)
1.15 db 210: return (d_undel(f, -n));
1.5 millert 211: while (n--) {
212: if (llength(curwp->w_dotp) > 0)
213: lputc(curwp->w_dotp, 0, ' ');
214: if (lback(curwp->w_dotp) != curbp->b_linep)
215: curwp->w_dotp = lback(curwp->w_dotp);
216: }
217: curwp->w_doto = 0;
218: curwp->w_flag |= WFEDIT | WFMOVE;
1.15 db 219: return (TRUE);
1.1 deraadt 220: }
221:
1.5 millert 222: /* ARGSUSED */
223: int
1.10 vincent 224: d_findfile(int f, int n)
1.1 deraadt 225: {
1.15 db 226: BUFFER *bp;
227: int s;
228: char fname[NFILEN];
1.5 millert 229:
1.15 db 230: if ((s = d_makename(curwp->w_dotp, fname, sizeof(fname))) == ABORT)
231: return (FALSE);
1.12 vincent 232: if (s == TRUE)
233: bp = dired_(fname);
234: else
235: bp = findbuffer(fname);
236: if (bp == NULL)
1.15 db 237: return (FALSE);
1.5 millert 238: curbp = bp;
239: if (showbuffer(bp, curwp, WFHARD) != TRUE)
1.15 db 240: return (FALSE);
1.5 millert 241: if (bp->b_fname[0] != 0)
1.15 db 242: return (TRUE);
243: return (readin(fname));
1.1 deraadt 244: }
245:
1.5 millert 246: /* ARGSUSED */
247: int
1.10 vincent 248: d_ffotherwindow(int f, int n)
1.1 deraadt 249: {
1.7 mickey 250: char fname[NFILEN];
251: int s;
1.5 millert 252: BUFFER *bp;
253: MGWIN *wp;
254:
1.15 db 255: if ((s = d_makename(curwp->w_dotp, fname, sizeof(fname))) == ABORT)
256: return (FALSE);
1.5 millert 257: if ((bp = (s ? dired_(fname) : findbuffer(fname))) == NULL)
1.15 db 258: return (FALSE);
1.5 millert 259: if ((wp = popbuf(bp)) == NULL)
1.15 db 260: return (FALSE);
1.5 millert 261: curbp = bp;
262: curwp = wp;
263: if (bp->b_fname[0] != 0)
1.15 db 264: return (TRUE); /* never true for dired buffers */
265: return (readin(fname));
1.1 deraadt 266: }
267:
1.5 millert 268: /* ARGSUSED */
269: int
1.10 vincent 270: d_expunge(int f, int n)
1.1 deraadt 271: {
1.7 mickey 272: LINE *lp, *nlp;
1.15 db 273: char fname[NFILEN];
1.5 millert 274:
275: for (lp = lforw(curbp->b_linep); lp != curbp->b_linep; lp = nlp) {
276: nlp = lforw(lp);
277: if (llength(lp) && lgetc(lp, 0) == 'D') {
1.15 db 278: switch (d_makename(lp, fname, sizeof(fname))) {
1.5 millert 279: case ABORT:
280: ewprintf("Bad line in dired buffer");
1.15 db 281: return (FALSE);
1.5 millert 282: case FALSE:
283: if (unlink(fname) < 0) {
1.12 vincent 284: ewprintf("Could not delete '%s'",
285: basename(fname));
1.15 db 286: return (FALSE);
1.5 millert 287: }
288: break;
289: case TRUE:
290: if (rmdir(fname) < 0) {
291: ewprintf("Could not delete directory '%s'",
1.12 vincent 292: basename(fname));
1.15 db 293: return (FALSE);
1.5 millert 294: }
295: break;
296: }
297: lfree(lp);
298: curwp->w_flag |= WFHARD;
299: }
1.1 deraadt 300: }
1.15 db 301: return (TRUE);
1.1 deraadt 302: }
303:
1.5 millert 304: /* ARGSUSED */
305: int
1.10 vincent 306: d_copy(int f, int n)
1.1 deraadt 307: {
1.14 vincent 308: char frname[NFILEN], toname[NFILEN], *bufp;
309: int stat;
1.18 cloder 310: size_t off;
1.12 vincent 311: BUFFER *bp;
1.1 deraadt 312:
1.15 db 313: if (d_makename(curwp->w_dotp, frname, sizeof(frname)) != FALSE) {
1.5 millert 314: ewprintf("Not a file");
1.15 db 315: return (FALSE);
1.5 millert 316: }
1.15 db 317: off = strlcpy(toname, curbp->b_fname, sizeof(toname));
318: if (off >= sizeof(toname) - 1) { /* can't happen, really */
1.18 cloder 319: ewprintf("Directory name too long");
1.12 vincent 320: return (FALSE);
321: }
1.15 db 322: if ((bufp = eread("Copy %s to: ", toname + off, sizeof(toname) - off,
1.14 vincent 323: EFNEW | EFCR, basename(frname))) == NULL)
1.15 db 324: return (ABORT);
1.14 vincent 325: else if (bufp[0] == '\0')
1.17 otto 326: return (FALSE);
1.12 vincent 327: stat = (copy(frname, toname) >= 0) ? TRUE : FALSE;
328: if (stat != TRUE)
329: return (stat);
330: bp = dired_(curbp->b_fname);
331: return (showbuffer(bp, curwp, WFHARD | WFMODE));
1.1 deraadt 332: }
333:
1.5 millert 334: /* ARGSUSED */
335: int
1.10 vincent 336: d_rename(int f, int n)
1.1 deraadt 337: {
1.14 vincent 338: char frname[NFILEN], toname[NFILEN], *bufp;
1.18 cloder 339: int stat;
340: size_t off;
1.12 vincent 341: BUFFER *bp;
1.1 deraadt 342:
1.15 db 343: if (d_makename(curwp->w_dotp, frname, sizeof(frname)) != FALSE) {
1.5 millert 344: ewprintf("Not a file");
1.15 db 345: return (FALSE);
1.5 millert 346: }
1.15 db 347: off = strlcpy(toname, curbp->b_fname, sizeof(toname));
348: if (off >= sizeof(toname) - 1) { /* can't happen, really */
1.18 cloder 349: ewprintf("Directory name too long");
1.12 vincent 350: return (FALSE);
351: }
1.14 vincent 352: if ((bufp = eread("Rename %s to: ", toname + off,
1.15 db 353: sizeof(toname) - off, EFNEW | EFCR, basename(frname))) == NULL)
354: return (ABORT);
1.14 vincent 355: else if (bufp[0] == '\0')
1.15 db 356: return (FALSE);
1.12 vincent 357: stat = (rename(frname, toname) >= 0) ? TRUE : FALSE;
358: if (stat != TRUE)
359: return (stat);
360: bp = dired_(curbp->b_fname);
361: return (showbuffer(bp, curwp, WFHARD | WFMODE));
1.1 deraadt 362: }
363: #endif
1.12 vincent 364:
365: void
366: reaper(int signo __attribute__((unused)))
367: {
1.15 db 368: pid_t ret;
369: int status;
1.12 vincent 370:
371: while ((ret = waitpid(-1, &status, WNOHANG)) >= 0)
372: ;
373: }
374:
375: /*
376: * Pipe the currently selected file through a shell command.
377: */
378: int
379: d_shell_command(int f, int n)
380: {
1.15 db 381: char command[512], fname[MAXPATHLEN], buf[BUFSIZ], *bufp, *cp;
382: int infd, fds[2];
383: pid_t pid;
384: struct sigaction olda, newa;
385: BUFFER *bp;
386: MGWIN *wp;
387: FILE *fin;
1.12 vincent 388:
389: bp = bfind("*Shell Command Output*", TRUE);
390: if (bclear(bp) != TRUE)
391: return (ABORT);
392:
1.15 db 393: if (d_makename(curwp->w_dotp, fname, sizeof(fname)) != FALSE) {
1.12 vincent 394: ewprintf("bad line");
395: return (ABORT);
396: }
397:
398: command[0] = '\0';
1.15 db 399: if ((bufp = eread("! on %s: ", command, sizeof(command), 0,
1.14 vincent 400: basename(fname))) == NULL)
1.12 vincent 401: return (ABORT);
402: infd = open(fname, O_RDONLY);
403: if (infd == -1) {
404: ewprintf("Can't open input file : %s", strerror(errno));
405: return (ABORT);
406: }
407: if (pipe(fds) == -1) {
408: ewprintf("Can't create pipe : %s", strerror(errno));
409: close(infd);
410: return (ABORT);
411: }
412:
413: newa.sa_handler = reaper;
414: newa.sa_flags = 0;
415: if (sigaction(SIGCHLD, &newa, &olda) == -1) {
416: close(infd);
417: close(fds[0]);
418: close(fds[1]);
419: return (ABORT);
420: }
421: pid = fork();
422: switch (pid) {
423: case -1:
424: ewprintf("Can't fork");
425: return (ABORT);
426: case 0:
427: close(fds[0]);
428: dup2(infd, STDIN_FILENO);
429: dup2(fds[1], STDOUT_FILENO);
430: dup2(fds[1], STDERR_FILENO);
1.14 vincent 431: execl("/bin/sh", "sh", "-c", bufp, (char *)NULL);
1.12 vincent 432: exit(1);
433: default:
434: close(infd);
435: close(fds[1]);
436: fin = fdopen(fds[0], "r");
437: if (fin == NULL) /* "r" is surely a valid mode! */
438: panic("can't happen");
1.15 db 439: while (fgets(buf, sizeof(buf), fin) != NULL) {
1.12 vincent 440: cp = strrchr(buf, '\n');
441: if (cp == NULL && !feof(fin)) { /* too long a line */
442: int c;
443: addlinef(bp, "%s...", buf);
444: while ((c = getc(fin)) != EOF && c != '\n')
445: ;
446: continue;
447: } else if (cp)
448: *cp = '\0';
449: addline(bp, buf);
450: }
451: fclose(fin);
452: close(fds[0]);
453: break;
454: }
455: wp = popbuf(bp);
456: if (wp == NULL)
457: return (ABORT); /* XXX - free the buffer?? */
458: curwp = wp;
459: curbp = wp->w_bufp;
460: if (sigaction(SIGCHLD, &olda, NULL) == -1)
461: ewprintf("Warning, couldn't reset previous signal handler");
462: return (TRUE);
463: }
464:
465: int
466: d_create_directory(int f, int n)
467: {
1.15 db 468: char tocreate[MAXPATHLEN], *bufp;
1.18 cloder 469: size_t off;
1.15 db 470: BUFFER *bp;
1.12 vincent 471:
1.15 db 472: off = strlcpy(tocreate, curbp->b_fname, sizeof(tocreate));
473: if (off >= sizeof(tocreate) - 1)
1.12 vincent 474: return (FALSE);
1.14 vincent 475: if ((bufp = ereply("Create directory: ", tocreate + off,
1.15 db 476: sizeof(tocreate) - off)) == NULL)
1.14 vincent 477: return (ABORT);
478: else if (bufp[0] == '\0')
1.15 db 479: return (FALSE);
1.12 vincent 480: if (mkdir(tocreate, 0755) == -1) {
481: ewprintf("Creating directory: %s, %s", strerror(errno),
482: tocreate);
483: return (ABORT);
484: }
485: bp = dired_(curbp->b_fname);
486: return (showbuffer(bp, curwp, WFHARD | WFMODE));
487: }