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

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