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: }