]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/sdiff/edit.c
DIRDEPS_BUILD: Add some missing dirctories to the build.
[FreeBSD/FreeBSD.git] / usr.bin / sdiff / edit.c
1 /*      $OpenBSD: edit.c,v 1.19 2009/06/07 13:29:50 ray Exp $ */
2
3 /*
4  * Written by Raymond Lai <ray@cyth.net>.
5  * Public domain.
6  */
7
8 #include <sys/cdefs.h>
9 __FBSDID("$FreeBSD$");
10
11 #include <sys/types.h>
12 #include <sys/wait.h>
13
14 #include <ctype.h>
15 #include <err.h>
16 #include <errno.h>
17 #include <paths.h>
18 #include <signal.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23
24 #include "common.h"
25 #include "extern.h"
26
27 int editit(const char *);
28
29 /*
30  * Execute an editor on the specified pathname, which is interpreted
31  * from the shell.  This means flags may be included.
32  *
33  * Returns -1 on error, or the exit value on success.
34  */
35 int
36 editit(const char *pathname)
37 {
38         sig_t sighup, sigint, sigquit, sigchld;
39         pid_t pid;
40         int saved_errno, st, ret = -1;
41         const char *ed;
42
43         ed = getenv("VISUAL");
44         if (ed == NULL)
45                 ed = getenv("EDITOR");
46         if (ed == NULL)
47                 ed = _PATH_VI;
48
49         sighup = signal(SIGHUP, SIG_IGN);
50         sigint = signal(SIGINT, SIG_IGN);
51         sigquit = signal(SIGQUIT, SIG_IGN);
52         sigchld = signal(SIGCHLD, SIG_DFL);
53         if ((pid = fork()) == -1)
54                 goto fail;
55         if (pid == 0) {
56                 execlp(ed, ed, pathname, (char *)NULL);
57                 _exit(127);
58         }
59         while (waitpid(pid, &st, 0) == -1)
60                 if (errno != EINTR)
61                         goto fail;
62         if (!WIFEXITED(st))
63                 errno = EINTR;
64         else
65                 ret = WEXITSTATUS(st);
66
67  fail:
68         saved_errno = errno;
69         (void)signal(SIGHUP, sighup);
70         (void)signal(SIGINT, sigint);
71         (void)signal(SIGQUIT, sigquit);
72         (void)signal(SIGCHLD, sigchld);
73         errno = saved_errno;
74         return (ret);
75 }
76
77 /*
78  * Parse edit command.  Returns 0 on success, -1 on error.
79  */
80 int
81 eparse(const char *cmd, const char *left, const char *right)
82 {
83         FILE *file;
84         size_t nread;
85         int fd;
86         char *filename;
87         char buf[BUFSIZ], *text;
88
89         /* Skip whitespace. */
90         while (isspace(*cmd))
91                 ++cmd;
92
93         text = NULL;
94         switch (*cmd) {
95         case '\0':
96                 /* Edit empty file. */
97                 break;
98
99         case 'b':
100                 /* Both strings. */
101                 if (left == NULL)
102                         goto RIGHT;
103                 if (right == NULL)
104                         goto LEFT;
105
106                 /* Neither column is blank, so print both. */
107                 if (asprintf(&text, "%s\n%s\n", left, right) == -1)
108                         err(2, "could not allocate memory");
109                 break;
110
111         case 'l':
112 LEFT:
113                 /* Skip if there is no left column. */
114                 if (left == NULL)
115                         break;
116
117                 if (asprintf(&text, "%s\n", left) == -1)
118                         err(2, "could not allocate memory");
119
120                 break;
121
122         case 'r':
123 RIGHT:
124                 /* Skip if there is no right column. */
125                 if (right == NULL)
126                         break;
127
128                 if (asprintf(&text, "%s\n", right) == -1)
129                         err(2, "could not allocate memory");
130
131                 break;
132
133         default:
134                 return (-1);
135         }
136
137         /* Create temp file. */
138         if (asprintf(&filename, "%s/sdiff.XXXXXXXXXX", tmpdir) == -1)
139                 err(2, "asprintf");
140         if ((fd = mkstemp(filename)) == -1)
141                 err(2, "mkstemp");
142         if (text != NULL) {
143                 size_t len;
144                 ssize_t nwritten;
145
146                 len = strlen(text);
147                 if ((nwritten = write(fd, text, len)) == -1 ||
148                     (size_t)nwritten != len) {
149                         warn("error writing to temp file");
150                         cleanup(filename);
151                 }
152         }
153         close(fd);
154
155         /* text is no longer used. */
156         free(text);
157
158         /* Edit temp file. */
159         if (editit(filename) == -1) {
160                 warn("error editing %s", filename);
161                 cleanup(filename);
162         }
163
164         /* Open temporary file. */
165         if (!(file = fopen(filename, "r"))) {
166                 warn("could not open edited file: %s", filename);
167                 cleanup(filename);
168         }
169
170         /* Copy temporary file contents to output file. */
171         for (nread = sizeof(buf); nread == sizeof(buf);) {
172                 size_t nwritten;
173
174                 nread = fread(buf, sizeof(*buf), sizeof(buf), file);
175                 /* Test for error or end of file. */
176                 if (nread != sizeof(buf) &&
177                     (ferror(file) || !feof(file))) {
178                         warnx("error reading edited file: %s", filename);
179                         cleanup(filename);
180                 }
181
182                 /*
183                  * If we have nothing to read, break out of loop
184                  * instead of writing nothing.
185                  */
186                 if (!nread)
187                         break;
188
189                 /* Write data we just read. */
190                 nwritten = fwrite(buf, sizeof(*buf), nread, outfp);
191                 if (nwritten != nread) {
192                         warnx("error writing to output file");
193                         cleanup(filename);
194                 }
195         }
196
197         /* We've reached the end of the temporary file, so remove it. */
198         if (unlink(filename))
199                 warn("could not delete: %s", filename);
200         fclose(file);
201
202         free(filename);
203
204         return (0);
205 }