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

Annotation of src/usr.bin/sdiff/edit.c, Revision 1.4

1.4     ! tedu        1: /*     $OpenBSD: edit.c,v 1.3 2005/12/27 04:18:07 tedu Exp $ */
1.1       tedu        2:
                      3: /*
                      4:  * Written by Raymond Lai <ray@cyth.net>.
                      5:  * Public domain.
                      6:  */
                      7:
                      8: #include <sys/types.h>
                      9: #include <sys/wait.h>
                     10:
                     11: #include <assert.h>
                     12: #include <ctype.h>
                     13: #include <err.h>
                     14: #include <stdio.h>
                     15: #include <stdlib.h>
                     16: #include <unistd.h>
                     17:
                     18: #include "extern.h"
                     19:
                     20: __dead static void cleanup(const char *);
                     21: static void edit(const char *);
                     22: static char *xmktemp(const char *);
                     23:
                     24: static void
                     25: cleanup(const char *filename)
                     26: {
                     27:        if (unlink(filename))
                     28:                err(2, "could not delete: %s", filename);
                     29:        exit(2);
                     30: }
                     31:
                     32: /*
                     33:  * Takes the name of a file and opens it with an editor.
                     34:  */
                     35: static void
                     36: edit(const char *filename)
                     37: {
                     38:        int status;
                     39:        pid_t pid;
                     40:        const char *editor;
                     41:
                     42:        editor = getenv("VISUAL");
                     43:        if (editor == NULL)
                     44:                editor = getenv("EDITOR");
                     45:        if (editor == NULL)
                     46:                editor = "vi";
                     47:
                     48:        /* Start editor on temporary file. */
                     49:        switch (pid = fork()) {
                     50:        case 0:
                     51:                /* child */
                     52:                execlp(editor, editor, filename, (void *)NULL);
                     53:                warn("could not execute editor: %s", editor);
                     54:                cleanup(filename);
                     55:                /* NOTREACHED */
                     56:        case -1:
                     57:                warn("could not fork");
                     58:                cleanup(filename);
                     59:                /* NOTREACHED */
                     60:        }
                     61:
                     62:        /* parent */
                     63:        /* Wait for editor to exit. */
                     64:        if (waitpid(pid, &status, 0) == -1) {
                     65:                warn("waitpid");
                     66:                cleanup(filename);
                     67:                /* NOTREACHED */
                     68:        }
                     69:
                     70:        /* Check that editor terminated normally. */
                     71:        if (!WIFEXITED(status)) {
                     72:                warn("%s terminated abnormally", editor);
                     73:                cleanup(filename);
                     74:                /* NOTREACHED */
                     75:        }
                     76: }
                     77:
                     78: /*
                     79:  * Creates and returns the name of a temporary file.  Takes a string
                     80:  * (or NULL) is written to the temporary file.  The returned string
                     81:  * needs to be freed.
                     82:  */
                     83: static char *
                     84: xmktemp(const char *s)
                     85: {
                     86:        FILE *file;
                     87:        int fd;
                     88:        const char *tmpdir;
                     89:        char *filename;
                     90:
                     91:        /* If TMPDIR is set, use it; otherwise use /tmp. */
                     92:        if (!(tmpdir = getenv("TMPDIR")))
                     93:                tmpdir = "/tmp";
                     94:        if (asprintf(&filename, "%s/sdiff.XXXXXXXXXX", tmpdir) == -1)
                     95:                err(2, "could not allocate memory");
                     96:
                     97:        /* Create temp file. */
                     98:        if ((fd = mkstemp(filename)) == -1)
                     99:                err(2, "could not create temporary file");
                    100:
                    101:        /* If we don't write anything to the file, just close. */
                    102:        if (s == NULL) {
                    103:                if (close(fd)) {
                    104:                        warn("could not close %s", filename);
                    105:                        cleanup(filename);
                    106:                        /* NOTREACHED */
                    107:                }
                    108:
                    109:                return (filename);
                    110:        }
                    111:
                    112:        /* Open temp file for writing. */
                    113:        if ((file = fdopen(fd, "w")) == NULL) {
                    114:                warn("could not open %s", filename);
                    115:                cleanup(filename);
                    116:                /* NOTREACHED */
                    117:        }
                    118:
                    119:        /* Write to file. */
                    120:        if (fputs(s, file)) {
                    121:                warn("could not write to %s", filename);
                    122:                cleanup(filename);
                    123:                /* NOTREACHED */
                    124:        }
                    125:
                    126:        /* Close temp file. */
                    127:        if (fclose(file)) {
                    128:                warn("could not close %s", filename);
                    129:                cleanup(filename);
                    130:                /* NOTREACHED */
                    131:        }
                    132:
                    133:        return (filename);
                    134: }
                    135:
                    136: /*
                    137:  * Parse edit command.  Returns 0 on success, -1 on error.
                    138:  */
                    139: int
                    140: eparse(const char *cmd, const char *left, const char *right)
                    141: {
                    142:        FILE *file;
                    143:        size_t nread, nwritten;
                    144:        const char *filename;
                    145:        char buf[BUFSIZ], *text;
                    146:
                    147:        assert(cmd);
                    148:
                    149:        /* Skip whitespace. */
                    150:        while (isspace(*cmd))
                    151:                ++cmd;
                    152:
                    153:        text = NULL;
                    154:        switch (*cmd) {
                    155:        case '\0':
                    156:                /* Edit empty file. */
                    157:                break;
                    158:
                    159:        case 'b':
                    160:                /* Both strings. */
                    161:                if (left == NULL)
                    162:                        goto RIGHT;
                    163:                if (right == NULL)
                    164:                        goto LEFT;
                    165:
                    166:                /* Neither column is blank, so print both. */
                    167:                if (asprintf(&text, "%s%s\n", left, right) == -1)
                    168:                        err(2, "could not allocate memory");
                    169:                break;
                    170:
                    171: LEFT:
                    172:        case 'l':
                    173:                /* Skip if there is no left column. */
                    174:                if (left == NULL)
                    175:                        break;
                    176:
                    177:                if (asprintf(&text, "%s\n", left) == -1)
                    178:                        err(2, "could not allocate memory");
                    179:
                    180:                break;
                    181:
                    182: RIGHT:
                    183:        case 'r':
                    184:                /* Skip if there is no right column. */
                    185:                if (right == NULL)
                    186:                        break;
                    187:
                    188:                if (asprintf(&text, "%s\n", right) == -1)
                    189:                        err(2, "could not allocate memory");
                    190:
                    191:                break;
                    192:
                    193:        default:
                    194:                return (-1);
                    195:        }
                    196:
                    197:        /* Create temp file. */
                    198:        filename = xmktemp(text);
                    199:
                    200:        /* text is no longer used. */
                    201:        free(text);
                    202:
                    203:        /* Edit temp file. */
                    204:        edit(filename);
                    205:
                    206:        /* Open temporary file. */
                    207:        if (!(file = fopen(filename, "r"))) {
                    208:                warn("could not open edited file: %s", filename);
                    209:                cleanup(filename);
                    210:                /* NOTREACHED */
                    211:        }
                    212:
                    213:        /* Copy temporary file contents to output file. */
                    214:        for (nread = sizeof(buf); nread == sizeof(buf);) {
                    215:                nread = fread(buf, sizeof(*buf), sizeof(buf), file);
                    216:                /* Test for error or end of file. */
                    217:                if (nread != sizeof(buf) &&
                    218:                    (ferror(file) || !feof(file))) {
                    219:                        warnx("error reading edited file: %s", filename);
                    220:                        cleanup(filename);
                    221:                        /* NOTREACHED */
                    222:                }
                    223:
                    224:                /*
                    225:                 * If we have nothing to read, break out of loop
                    226:                 * instead of writing nothing.
                    227:                 */
                    228:                if (!nread)
                    229:                        break;
                    230:
                    231:                /* Write data we just read. */
                    232:                nwritten = fwrite(buf, sizeof(*buf), nread, outfile);
                    233:                if (nwritten != nread) {
                    234:                        warnx("error writing to output file");
                    235:                        cleanup(filename);
                    236:                        /* NOTREACHED */
                    237:                }
                    238:        }
                    239:
                    240:        /* We've reached the end of the temporary file, so remove it. */
                    241:        if (unlink(filename))
                    242:                warn("could not delete: %s", filename);
                    243:        if (fclose(file))
                    244:                warn("could not close: %s", filename);
                    245:
                    246:        /* filename was malloc()ed in xmktemp(). */
1.4     ! tedu      247:        free((void *)filename);
1.1       tedu      248:
                    249:        return (0);
                    250: }