[BACK]Return to dired.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Annotation of src/usr.bin/mg/dired.c, Revision 1.88

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