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

1.1     ! tedu        1: /*     $Id: edit.c,v 1.4 2005/12/15 16:19:27 ray Exp $ */
        !             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(). */
        !           247:        free((char *)filename);
        !           248:
        !           249:        return (0);
        !           250: }