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