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