113b5b548SBaptiste Daroussin /* $OpenBSD: edit.c,v 1.19 2009/06/07 13:29:50 ray Exp $ */ 213b5b548SBaptiste Daroussin 313b5b548SBaptiste Daroussin /* 413b5b548SBaptiste Daroussin * Written by Raymond Lai <ray@cyth.net>. 513b5b548SBaptiste Daroussin * Public domain. 613b5b548SBaptiste Daroussin */ 713b5b548SBaptiste Daroussin 813b5b548SBaptiste Daroussin #include <sys/cdefs.h> 913b5b548SBaptiste Daroussin __FBSDID("$FreeBSD$"); 1013b5b548SBaptiste Daroussin 1113b5b548SBaptiste Daroussin #include <sys/types.h> 1213b5b548SBaptiste Daroussin #include <sys/wait.h> 1313b5b548SBaptiste Daroussin 1413b5b548SBaptiste Daroussin #include <ctype.h> 1513b5b548SBaptiste Daroussin #include <err.h> 1613b5b548SBaptiste Daroussin #include <errno.h> 1713b5b548SBaptiste Daroussin #include <paths.h> 1813b5b548SBaptiste Daroussin #include <signal.h> 1913b5b548SBaptiste Daroussin #include <stdio.h> 2013b5b548SBaptiste Daroussin #include <stdlib.h> 2113b5b548SBaptiste Daroussin #include <string.h> 2213b5b548SBaptiste Daroussin #include <unistd.h> 2313b5b548SBaptiste Daroussin 2413b5b548SBaptiste Daroussin #include "common.h" 2513b5b548SBaptiste Daroussin #include "extern.h" 2613b5b548SBaptiste Daroussin 2713b5b548SBaptiste Daroussin int editit(const char *); 2813b5b548SBaptiste Daroussin 2913b5b548SBaptiste Daroussin /* 3013b5b548SBaptiste Daroussin * Execute an editor on the specified pathname, which is interpreted 3113b5b548SBaptiste Daroussin * from the shell. This means flags may be included. 3213b5b548SBaptiste Daroussin * 3313b5b548SBaptiste Daroussin * Returns -1 on error, or the exit value on success. 3413b5b548SBaptiste Daroussin */ 3513b5b548SBaptiste Daroussin int 3613b5b548SBaptiste Daroussin editit(const char *pathname) 3713b5b548SBaptiste Daroussin { 3813b5b548SBaptiste Daroussin sig_t sighup, sigint, sigquit, sigchld; 3913b5b548SBaptiste Daroussin pid_t pid; 4013b5b548SBaptiste Daroussin int saved_errno, st, ret = -1; 4115eaa1aeSBaptiste Daroussin const char *ed; 4213b5b548SBaptiste Daroussin 43*1ddda798SBaptiste Daroussin ed = getenv("VISUAL"); 44*1ddda798SBaptiste Daroussin if (ed == NULL) 45*1ddda798SBaptiste Daroussin ed = getenv("EDITOR"); 46*1ddda798SBaptiste Daroussin if (ed == NULL) 4713b5b548SBaptiste Daroussin ed = _PATH_VI; 4813b5b548SBaptiste Daroussin 4913b5b548SBaptiste Daroussin sighup = signal(SIGHUP, SIG_IGN); 5013b5b548SBaptiste Daroussin sigint = signal(SIGINT, SIG_IGN); 5113b5b548SBaptiste Daroussin sigquit = signal(SIGQUIT, SIG_IGN); 5213b5b548SBaptiste Daroussin sigchld = signal(SIGCHLD, SIG_DFL); 5313b5b548SBaptiste Daroussin if ((pid = fork()) == -1) 5413b5b548SBaptiste Daroussin goto fail; 5513b5b548SBaptiste Daroussin if (pid == 0) { 5615eaa1aeSBaptiste Daroussin execlp(ed, ed, pathname, (char *)NULL); 5713b5b548SBaptiste Daroussin _exit(127); 5813b5b548SBaptiste Daroussin } 5913b5b548SBaptiste Daroussin while (waitpid(pid, &st, 0) == -1) 6013b5b548SBaptiste Daroussin if (errno != EINTR) 6113b5b548SBaptiste Daroussin goto fail; 6213b5b548SBaptiste Daroussin if (!WIFEXITED(st)) 6313b5b548SBaptiste Daroussin errno = EINTR; 6413b5b548SBaptiste Daroussin else 6513b5b548SBaptiste Daroussin ret = WEXITSTATUS(st); 6613b5b548SBaptiste Daroussin 6713b5b548SBaptiste Daroussin fail: 6813b5b548SBaptiste Daroussin saved_errno = errno; 6913b5b548SBaptiste Daroussin (void)signal(SIGHUP, sighup); 7013b5b548SBaptiste Daroussin (void)signal(SIGINT, sigint); 7113b5b548SBaptiste Daroussin (void)signal(SIGQUIT, sigquit); 7213b5b548SBaptiste Daroussin (void)signal(SIGCHLD, sigchld); 7313b5b548SBaptiste Daroussin errno = saved_errno; 7413b5b548SBaptiste Daroussin return (ret); 7513b5b548SBaptiste Daroussin } 7613b5b548SBaptiste Daroussin 7713b5b548SBaptiste Daroussin /* 7813b5b548SBaptiste Daroussin * Parse edit command. Returns 0 on success, -1 on error. 7913b5b548SBaptiste Daroussin */ 8013b5b548SBaptiste Daroussin int 8113b5b548SBaptiste Daroussin eparse(const char *cmd, const char *left, const char *right) 8213b5b548SBaptiste Daroussin { 8313b5b548SBaptiste Daroussin FILE *file; 8413b5b548SBaptiste Daroussin size_t nread; 8513b5b548SBaptiste Daroussin int fd; 8613b5b548SBaptiste Daroussin char *filename; 8713b5b548SBaptiste Daroussin char buf[BUFSIZ], *text; 8813b5b548SBaptiste Daroussin 8913b5b548SBaptiste Daroussin /* Skip whitespace. */ 9013b5b548SBaptiste Daroussin while (isspace(*cmd)) 9113b5b548SBaptiste Daroussin ++cmd; 9213b5b548SBaptiste Daroussin 9313b5b548SBaptiste Daroussin text = NULL; 9413b5b548SBaptiste Daroussin switch (*cmd) { 9513b5b548SBaptiste Daroussin case '\0': 9613b5b548SBaptiste Daroussin /* Edit empty file. */ 9713b5b548SBaptiste Daroussin break; 9813b5b548SBaptiste Daroussin 9913b5b548SBaptiste Daroussin case 'b': 10013b5b548SBaptiste Daroussin /* Both strings. */ 10113b5b548SBaptiste Daroussin if (left == NULL) 10213b5b548SBaptiste Daroussin goto RIGHT; 10313b5b548SBaptiste Daroussin if (right == NULL) 10413b5b548SBaptiste Daroussin goto LEFT; 10513b5b548SBaptiste Daroussin 10613b5b548SBaptiste Daroussin /* Neither column is blank, so print both. */ 10713b5b548SBaptiste Daroussin if (asprintf(&text, "%s\n%s\n", left, right) == -1) 10813b5b548SBaptiste Daroussin err(2, "could not allocate memory"); 10913b5b548SBaptiste Daroussin break; 11013b5b548SBaptiste Daroussin 11113b5b548SBaptiste Daroussin case 'l': 11213b5b548SBaptiste Daroussin LEFT: 11313b5b548SBaptiste Daroussin /* Skip if there is no left column. */ 11413b5b548SBaptiste Daroussin if (left == NULL) 11513b5b548SBaptiste Daroussin break; 11613b5b548SBaptiste Daroussin 11713b5b548SBaptiste Daroussin if (asprintf(&text, "%s\n", left) == -1) 11813b5b548SBaptiste Daroussin err(2, "could not allocate memory"); 11913b5b548SBaptiste Daroussin 12013b5b548SBaptiste Daroussin break; 12113b5b548SBaptiste Daroussin 12213b5b548SBaptiste Daroussin case 'r': 12313b5b548SBaptiste Daroussin RIGHT: 12413b5b548SBaptiste Daroussin /* Skip if there is no right column. */ 12513b5b548SBaptiste Daroussin if (right == NULL) 12613b5b548SBaptiste Daroussin break; 12713b5b548SBaptiste Daroussin 12813b5b548SBaptiste Daroussin if (asprintf(&text, "%s\n", right) == -1) 12913b5b548SBaptiste Daroussin err(2, "could not allocate memory"); 13013b5b548SBaptiste Daroussin 13113b5b548SBaptiste Daroussin break; 13213b5b548SBaptiste Daroussin 13313b5b548SBaptiste Daroussin default: 13413b5b548SBaptiste Daroussin return (-1); 13513b5b548SBaptiste Daroussin } 13613b5b548SBaptiste Daroussin 13713b5b548SBaptiste Daroussin /* Create temp file. */ 13813b5b548SBaptiste Daroussin if (asprintf(&filename, "%s/sdiff.XXXXXXXXXX", tmpdir) == -1) 13913b5b548SBaptiste Daroussin err(2, "asprintf"); 14013b5b548SBaptiste Daroussin if ((fd = mkstemp(filename)) == -1) 14113b5b548SBaptiste Daroussin err(2, "mkstemp"); 14213b5b548SBaptiste Daroussin if (text != NULL) { 14313b5b548SBaptiste Daroussin size_t len; 14413b5b548SBaptiste Daroussin ssize_t nwritten; 14513b5b548SBaptiste Daroussin 14613b5b548SBaptiste Daroussin len = strlen(text); 14713b5b548SBaptiste Daroussin if ((nwritten = write(fd, text, len)) == -1 || 14813b5b548SBaptiste Daroussin (size_t)nwritten != len) { 14913b5b548SBaptiste Daroussin warn("error writing to temp file"); 15013b5b548SBaptiste Daroussin cleanup(filename); 15113b5b548SBaptiste Daroussin } 15213b5b548SBaptiste Daroussin } 15313b5b548SBaptiste Daroussin close(fd); 15413b5b548SBaptiste Daroussin 15513b5b548SBaptiste Daroussin /* text is no longer used. */ 15613b5b548SBaptiste Daroussin free(text); 15713b5b548SBaptiste Daroussin 15813b5b548SBaptiste Daroussin /* Edit temp file. */ 15913b5b548SBaptiste Daroussin if (editit(filename) == -1) { 16013b5b548SBaptiste Daroussin warn("error editing %s", filename); 16113b5b548SBaptiste Daroussin cleanup(filename); 16213b5b548SBaptiste Daroussin } 16313b5b548SBaptiste Daroussin 16413b5b548SBaptiste Daroussin /* Open temporary file. */ 16513b5b548SBaptiste Daroussin if (!(file = fopen(filename, "r"))) { 16613b5b548SBaptiste Daroussin warn("could not open edited file: %s", filename); 16713b5b548SBaptiste Daroussin cleanup(filename); 16813b5b548SBaptiste Daroussin } 16913b5b548SBaptiste Daroussin 17013b5b548SBaptiste Daroussin /* Copy temporary file contents to output file. */ 17113b5b548SBaptiste Daroussin for (nread = sizeof(buf); nread == sizeof(buf);) { 17213b5b548SBaptiste Daroussin size_t nwritten; 17313b5b548SBaptiste Daroussin 17413b5b548SBaptiste Daroussin nread = fread(buf, sizeof(*buf), sizeof(buf), file); 17513b5b548SBaptiste Daroussin /* Test for error or end of file. */ 17613b5b548SBaptiste Daroussin if (nread != sizeof(buf) && 17713b5b548SBaptiste Daroussin (ferror(file) || !feof(file))) { 17813b5b548SBaptiste Daroussin warnx("error reading edited file: %s", filename); 17913b5b548SBaptiste Daroussin cleanup(filename); 18013b5b548SBaptiste Daroussin } 18113b5b548SBaptiste Daroussin 18213b5b548SBaptiste Daroussin /* 18313b5b548SBaptiste Daroussin * If we have nothing to read, break out of loop 18413b5b548SBaptiste Daroussin * instead of writing nothing. 18513b5b548SBaptiste Daroussin */ 18613b5b548SBaptiste Daroussin if (!nread) 18713b5b548SBaptiste Daroussin break; 18813b5b548SBaptiste Daroussin 18913b5b548SBaptiste Daroussin /* Write data we just read. */ 19013b5b548SBaptiste Daroussin nwritten = fwrite(buf, sizeof(*buf), nread, outfp); 19113b5b548SBaptiste Daroussin if (nwritten != nread) { 19213b5b548SBaptiste Daroussin warnx("error writing to output file"); 19313b5b548SBaptiste Daroussin cleanup(filename); 19413b5b548SBaptiste Daroussin } 19513b5b548SBaptiste Daroussin } 19613b5b548SBaptiste Daroussin 19713b5b548SBaptiste Daroussin /* We've reached the end of the temporary file, so remove it. */ 19813b5b548SBaptiste Daroussin if (unlink(filename)) 19913b5b548SBaptiste Daroussin warn("could not delete: %s", filename); 20013b5b548SBaptiste Daroussin fclose(file); 20113b5b548SBaptiste Daroussin 20213b5b548SBaptiste Daroussin free(filename); 20313b5b548SBaptiste Daroussin 20413b5b548SBaptiste Daroussin return (0); 20513b5b548SBaptiste Daroussin } 206