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