[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.20

1.20    ! deraadt     1: /*     $OpenBSD: edit.c,v 1.19 2009/06/07 13:29:50 ray 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 <ctype.h>
                     12: #include <err.h>
1.16      ray        13: #include <errno.h>
                     14: #include <paths.h>
                     15: #include <signal.h>
1.1       tedu       16: #include <stdio.h>
                     17: #include <stdlib.h>
1.14      ray        18: #include <string.h>
1.1       tedu       19: #include <unistd.h>
                     20:
1.12      otto       21: #include "common.h"
1.1       tedu       22: #include "extern.h"
                     23:
1.16      ray        24: int editit(const char *);
1.1       tedu       25:
                     26: /*
1.17      ray        27:  * Execute an editor on the specified pathname, which is interpreted
                     28:  * from the shell.  This means flags may be included.
                     29:  *
                     30:  * Returns -1 on error, or the exit value on success.
1.1       tedu       31:  */
1.16      ray        32: int
                     33: editit(const char *pathname)
1.1       tedu       34: {
1.16      ray        35:        char *argp[] = {"sh", "-c", NULL, NULL}, *ed, *p;
1.18      deraadt    36:        sig_t sighup, sigint, sigquit, sigchld;
1.1       tedu       37:        pid_t pid;
1.18      deraadt    38:        int saved_errno, st, ret = -1;
1.16      ray        39:
                     40:        ed = getenv("VISUAL");
                     41:        if (ed == NULL || ed[0] == '\0')
                     42:                ed = getenv("EDITOR");
                     43:        if (ed == NULL || ed[0] == '\0')
                     44:                ed = _PATH_VI;
                     45:        if (asprintf(&p, "%s %s", ed, pathname) == -1)
                     46:                return (-1);
                     47:        argp[2] = p;
1.1       tedu       48:
1.16      ray        49:        sighup = signal(SIGHUP, SIG_IGN);
                     50:        sigint = signal(SIGINT, SIG_IGN);
                     51:        sigquit = signal(SIGQUIT, SIG_IGN);
1.18      deraadt    52:        sigchld = signal(SIGCHLD, SIG_DFL);
1.17      ray        53:        if ((pid = fork()) == -1)
                     54:                goto fail;
1.16      ray        55:        if (pid == 0) {
                     56:                execv(_PATH_BSHELL, argp);
                     57:                _exit(127);
1.1       tedu       58:        }
1.17      ray        59:        while (waitpid(pid, &st, 0) == -1)
                     60:                if (errno != EINTR)
                     61:                        goto fail;
1.18      deraadt    62:        if (!WIFEXITED(st))
1.17      ray        63:                errno = EINTR;
1.18      deraadt    64:        else
                     65:                ret = WEXITSTATUS(st);
1.17      ray        66:
                     67:  fail:
                     68:        saved_errno = errno;
                     69:        (void)signal(SIGHUP, sighup);
                     70:        (void)signal(SIGINT, sigint);
                     71:        (void)signal(SIGQUIT, sigquit);
1.18      deraadt    72:        (void)signal(SIGCHLD, sigchld);
1.17      ray        73:        free(p);
                     74:        errno = saved_errno;
1.18      deraadt    75:        return (ret);
1.1       tedu       76: }
                     77:
                     78: /*
                     79:  * Parse edit command.  Returns 0 on success, -1 on error.
                     80:  */
                     81: int
                     82: eparse(const char *cmd, const char *left, const char *right)
                     83: {
                     84:        FILE *file;
1.15      steven     85:        size_t nread;
1.14      ray        86:        int fd;
1.11      otto       87:        char *filename;
1.1       tedu       88:        char buf[BUFSIZ], *text;
                     89:
                     90:        /* Skip whitespace. */
1.20    ! deraadt    91:        while (isspace((unsigned char)*cmd))
1.1       tedu       92:                ++cmd;
                     93:
                     94:        text = NULL;
                     95:        switch (*cmd) {
                     96:        case '\0':
                     97:                /* Edit empty file. */
                     98:                break;
                     99:
                    100:        case 'b':
                    101:                /* Both strings. */
                    102:                if (left == NULL)
                    103:                        goto RIGHT;
1.9       deraadt   104:                if (right == NULL)
1.1       tedu      105:                        goto LEFT;
                    106:
                    107:                /* Neither column is blank, so print both. */
1.10      claudio   108:                if (asprintf(&text, "%s\n%s\n", left, right) == -1)
1.1       tedu      109:                        err(2, "could not allocate memory");
                    110:                break;
                    111:
1.8       deraadt   112:        case 'l':
1.1       tedu      113: LEFT:
                    114:                /* Skip if there is no left column. */
                    115:                if (left == NULL)
                    116:                        break;
                    117:
                    118:                if (asprintf(&text, "%s\n", left) == -1)
                    119:                        err(2, "could not allocate memory");
                    120:
                    121:                break;
                    122:
1.8       deraadt   123:        case 'r':
1.1       tedu      124: RIGHT:
                    125:                /* Skip if there is no right column. */
                    126:                if (right == NULL)
                    127:                        break;
                    128:
                    129:                if (asprintf(&text, "%s\n", right) == -1)
                    130:                        err(2, "could not allocate memory");
                    131:
                    132:                break;
                    133:
                    134:        default:
                    135:                return (-1);
                    136:        }
                    137:
                    138:        /* Create temp file. */
1.14      ray       139:        if (asprintf(&filename, "%s/sdiff.XXXXXXXXXX", tmpdir) == -1)
                    140:                err(2, "asprintf");
                    141:        if ((fd = mkstemp(filename)) == -1)
                    142:                err(2, "mkstemp");
                    143:        if (text != NULL) {
                    144:                size_t len;
1.15      steven    145:                ssize_t nwritten;
1.14      ray       146:
                    147:                len = strlen(text);
                    148:                if ((nwritten = write(fd, text, len)) == -1 ||
                    149:                    nwritten != len) {
                    150:                        warn("error writing to temp file");
                    151:                        cleanup(filename);
                    152:                }
                    153:        }
                    154:        close(fd);
1.1       tedu      155:
                    156:        /* text is no longer used. */
                    157:        free(text);
                    158:
                    159:        /* Edit temp file. */
1.16      ray       160:        if (editit(filename) == -1) {
1.17      ray       161:                warn("error editing %s", filename);
1.16      ray       162:                cleanup(filename);
                    163:        }
1.1       tedu      164:
                    165:        /* Open temporary file. */
                    166:        if (!(file = fopen(filename, "r"))) {
                    167:                warn("could not open edited file: %s", filename);
                    168:                cleanup(filename);
                    169:        }
                    170:
                    171:        /* Copy temporary file contents to output file. */
                    172:        for (nread = sizeof(buf); nread == sizeof(buf);) {
1.15      steven    173:                size_t nwritten;
                    174:
1.1       tedu      175:                nread = fread(buf, sizeof(*buf), sizeof(buf), file);
                    176:                /* Test for error or end of file. */
                    177:                if (nread != sizeof(buf) &&
                    178:                    (ferror(file) || !feof(file))) {
                    179:                        warnx("error reading edited file: %s", filename);
                    180:                        cleanup(filename);
                    181:                }
                    182:
                    183:                /*
                    184:                 * If we have nothing to read, break out of loop
                    185:                 * instead of writing nothing.
                    186:                 */
                    187:                if (!nread)
                    188:                        break;
                    189:
                    190:                /* Write data we just read. */
1.19      ray       191:                nwritten = fwrite(buf, sizeof(*buf), nread, outfp);
1.1       tedu      192:                if (nwritten != nread) {
                    193:                        warnx("error writing to output file");
                    194:                        cleanup(filename);
                    195:                }
                    196:        }
                    197:
                    198:        /* We've reached the end of the temporary file, so remove it. */
                    199:        if (unlink(filename))
                    200:                warn("could not delete: %s", filename);
1.5       tedu      201:        fclose(file);
1.1       tedu      202:
1.11      otto      203:        free(filename);
1.1       tedu      204:
                    205:        return (0);
                    206: }