xref: /minix3/usr.bin/sdiff/edit.c (revision ce982eb75720d2a0e553066b5b6315c7adf622a6)
1*ce982eb7SThomas Cort /*	$NetBSD: edit.c,v 1.4 2011/09/01 07:18:51 plunky Exp $	*/
2*ce982eb7SThomas Cort /*	$OpenBSD: edit.c,v 1.14 2006/05/25 03:20:32 ray Exp $ */
3*ce982eb7SThomas Cort 
4*ce982eb7SThomas Cort /*
5*ce982eb7SThomas Cort  * Written by Raymond Lai <ray@cyth.net>.
6*ce982eb7SThomas Cort  * Public domain.
7*ce982eb7SThomas Cort  */
8*ce982eb7SThomas Cort 
9*ce982eb7SThomas Cort #include <sys/types.h>
10*ce982eb7SThomas Cort #include <sys/wait.h>
11*ce982eb7SThomas Cort 
12*ce982eb7SThomas Cort #include <ctype.h>
13*ce982eb7SThomas Cort #include <err.h>
14*ce982eb7SThomas Cort #include <stdio.h>
15*ce982eb7SThomas Cort #include <stdlib.h>
16*ce982eb7SThomas Cort #include <string.h>
17*ce982eb7SThomas Cort #include <unistd.h>
18*ce982eb7SThomas Cort 
19*ce982eb7SThomas Cort #include "common.h"
20*ce982eb7SThomas Cort #include "extern.h"
21*ce982eb7SThomas Cort 
22*ce982eb7SThomas Cort static void edit(const char *);
23*ce982eb7SThomas Cort 
24*ce982eb7SThomas Cort /*
25*ce982eb7SThomas Cort  * Takes the name of a file and opens it with an editor.
26*ce982eb7SThomas Cort  */
27*ce982eb7SThomas Cort static void
edit(const char * filename)28*ce982eb7SThomas Cort edit(const char *filename)
29*ce982eb7SThomas Cort {
30*ce982eb7SThomas Cort 	int status;
31*ce982eb7SThomas Cort 	pid_t pid;
32*ce982eb7SThomas Cort 	const char *editor;
33*ce982eb7SThomas Cort 
34*ce982eb7SThomas Cort 	editor = getenv("VISUAL");
35*ce982eb7SThomas Cort 	if (editor == NULL)
36*ce982eb7SThomas Cort 		editor = getenv("EDITOR");
37*ce982eb7SThomas Cort 	if (editor == NULL)
38*ce982eb7SThomas Cort 		editor = "vi";
39*ce982eb7SThomas Cort 
40*ce982eb7SThomas Cort 	/* Start editor on temporary file. */
41*ce982eb7SThomas Cort 	switch (pid = fork()) {
42*ce982eb7SThomas Cort 	case 0:
43*ce982eb7SThomas Cort 		/* child */
44*ce982eb7SThomas Cort 		execlp(editor, editor, filename, (void *)NULL);
45*ce982eb7SThomas Cort 		warn("could not execute editor: %s", editor);
46*ce982eb7SThomas Cort 		cleanup(filename);
47*ce982eb7SThomas Cort 	case -1:
48*ce982eb7SThomas Cort 		warn("could not fork");
49*ce982eb7SThomas Cort 		cleanup(filename);
50*ce982eb7SThomas Cort 	}
51*ce982eb7SThomas Cort 
52*ce982eb7SThomas Cort 	/* parent */
53*ce982eb7SThomas Cort 	/* Wait for editor to exit. */
54*ce982eb7SThomas Cort 	if (waitpid(pid, &status, 0) == -1) {
55*ce982eb7SThomas Cort 		warn("waitpid");
56*ce982eb7SThomas Cort 		cleanup(filename);
57*ce982eb7SThomas Cort 	}
58*ce982eb7SThomas Cort 
59*ce982eb7SThomas Cort 	/* Check that editor terminated normally. */
60*ce982eb7SThomas Cort 	if (!WIFEXITED(status)) {
61*ce982eb7SThomas Cort 		warn("%s terminated abnormally", editor);
62*ce982eb7SThomas Cort 		cleanup(filename);
63*ce982eb7SThomas Cort 	}
64*ce982eb7SThomas Cort }
65*ce982eb7SThomas Cort 
66*ce982eb7SThomas Cort /*
67*ce982eb7SThomas Cort  * Parse edit command.  Returns 0 on success, -1 on error.
68*ce982eb7SThomas Cort  */
69*ce982eb7SThomas Cort int
eparse(const char * cmd,const char * left,const char * right)70*ce982eb7SThomas Cort eparse(const char *cmd, const char *left, const char *right)
71*ce982eb7SThomas Cort {
72*ce982eb7SThomas Cort 	FILE *file;
73*ce982eb7SThomas Cort 	size_t nread, nwritten;
74*ce982eb7SThomas Cort 	int fd;
75*ce982eb7SThomas Cort 	char *filename;
76*ce982eb7SThomas Cort 	char buf[BUFSIZ], *text;
77*ce982eb7SThomas Cort 
78*ce982eb7SThomas Cort 	/* Skip whitespace. */
79*ce982eb7SThomas Cort 	while (isspace((int)(*cmd)))
80*ce982eb7SThomas Cort 		++cmd;
81*ce982eb7SThomas Cort 
82*ce982eb7SThomas Cort 	text = NULL;
83*ce982eb7SThomas Cort 	switch (*cmd) {
84*ce982eb7SThomas Cort 	case '\0':
85*ce982eb7SThomas Cort 		/* Edit empty file. */
86*ce982eb7SThomas Cort 		break;
87*ce982eb7SThomas Cort 
88*ce982eb7SThomas Cort 	case 'b':
89*ce982eb7SThomas Cort 		/* Both strings. */
90*ce982eb7SThomas Cort 		if (left == NULL)
91*ce982eb7SThomas Cort 			goto RIGHT;
92*ce982eb7SThomas Cort 		if (right == NULL)
93*ce982eb7SThomas Cort 			goto LEFT;
94*ce982eb7SThomas Cort 
95*ce982eb7SThomas Cort 		/* Neither column is blank, so print both. */
96*ce982eb7SThomas Cort 		if (asprintf(&text, "%s\n%s\n", left, right) == -1)
97*ce982eb7SThomas Cort 			err(2, "could not allocate memory");
98*ce982eb7SThomas Cort 		break;
99*ce982eb7SThomas Cort 
100*ce982eb7SThomas Cort 	case 'l':
101*ce982eb7SThomas Cort LEFT:
102*ce982eb7SThomas Cort 		/* Skip if there is no left column. */
103*ce982eb7SThomas Cort 		if (left == NULL)
104*ce982eb7SThomas Cort 			break;
105*ce982eb7SThomas Cort 
106*ce982eb7SThomas Cort 		if (asprintf(&text, "%s\n", left) == -1)
107*ce982eb7SThomas Cort 			err(2, "could not allocate memory");
108*ce982eb7SThomas Cort 
109*ce982eb7SThomas Cort 		break;
110*ce982eb7SThomas Cort 
111*ce982eb7SThomas Cort 	case 'r':
112*ce982eb7SThomas Cort RIGHT:
113*ce982eb7SThomas Cort 		/* Skip if there is no right column. */
114*ce982eb7SThomas Cort 		if (right == NULL)
115*ce982eb7SThomas Cort 			break;
116*ce982eb7SThomas Cort 
117*ce982eb7SThomas Cort 		if (asprintf(&text, "%s\n", right) == -1)
118*ce982eb7SThomas Cort 			err(2, "could not allocate memory");
119*ce982eb7SThomas Cort 
120*ce982eb7SThomas Cort 		break;
121*ce982eb7SThomas Cort 
122*ce982eb7SThomas Cort 	default:
123*ce982eb7SThomas Cort 		return (-1);
124*ce982eb7SThomas Cort 	}
125*ce982eb7SThomas Cort 
126*ce982eb7SThomas Cort 	/* Create temp file. */
127*ce982eb7SThomas Cort 	if (asprintf(&filename, "%s/sdiff.XXXXXXXXXX", tmpdir) == -1)
128*ce982eb7SThomas Cort 		err(2, "asprintf");
129*ce982eb7SThomas Cort 	if ((fd = mkstemp(filename)) == -1)
130*ce982eb7SThomas Cort 		err(2, "mkstemp");
131*ce982eb7SThomas Cort 	if (text != NULL) {
132*ce982eb7SThomas Cort 		size_t len;
133*ce982eb7SThomas Cort 
134*ce982eb7SThomas Cort 		len = strlen(text);
135*ce982eb7SThomas Cort 		if ((size_t)write(fd, text, len) != len) {
136*ce982eb7SThomas Cort 			warn("error writing to temp file");
137*ce982eb7SThomas Cort 			cleanup(filename);
138*ce982eb7SThomas Cort 		}
139*ce982eb7SThomas Cort 	}
140*ce982eb7SThomas Cort 	close(fd);
141*ce982eb7SThomas Cort 
142*ce982eb7SThomas Cort 	/* text is no longer used. */
143*ce982eb7SThomas Cort 	free(text);
144*ce982eb7SThomas Cort 
145*ce982eb7SThomas Cort 	/* Edit temp file. */
146*ce982eb7SThomas Cort 	edit(filename);
147*ce982eb7SThomas Cort 
148*ce982eb7SThomas Cort 	/* Open temporary file. */
149*ce982eb7SThomas Cort 	if (!(file = fopen(filename, "r"))) {
150*ce982eb7SThomas Cort 		warn("could not open edited file: %s", filename);
151*ce982eb7SThomas Cort 		cleanup(filename);
152*ce982eb7SThomas Cort 	}
153*ce982eb7SThomas Cort 
154*ce982eb7SThomas Cort 	/* Copy temporary file contents to output file. */
155*ce982eb7SThomas Cort 	for (nread = sizeof(buf); nread == sizeof(buf);) {
156*ce982eb7SThomas Cort 		nread = fread(buf, sizeof(*buf), sizeof(buf), file);
157*ce982eb7SThomas Cort 		/* Test for error or end of file. */
158*ce982eb7SThomas Cort 		if (nread != sizeof(buf) &&
159*ce982eb7SThomas Cort 		    (ferror(file) || !feof(file))) {
160*ce982eb7SThomas Cort 			warnx("error reading edited file: %s", filename);
161*ce982eb7SThomas Cort 			cleanup(filename);
162*ce982eb7SThomas Cort 		}
163*ce982eb7SThomas Cort 
164*ce982eb7SThomas Cort 		/*
165*ce982eb7SThomas Cort 		 * If we have nothing to read, break out of loop
166*ce982eb7SThomas Cort 		 * instead of writing nothing.
167*ce982eb7SThomas Cort 		 */
168*ce982eb7SThomas Cort 		if (!nread)
169*ce982eb7SThomas Cort 			break;
170*ce982eb7SThomas Cort 
171*ce982eb7SThomas Cort 		/* Write data we just read. */
172*ce982eb7SThomas Cort 		nwritten = fwrite(buf, sizeof(*buf), nread, outfile);
173*ce982eb7SThomas Cort 		if (nwritten != nread) {
174*ce982eb7SThomas Cort 			warnx("error writing to output file");
175*ce982eb7SThomas Cort 			cleanup(filename);
176*ce982eb7SThomas Cort 		}
177*ce982eb7SThomas Cort 	}
178*ce982eb7SThomas Cort 
179*ce982eb7SThomas Cort 	/* We've reached the end of the temporary file, so remove it. */
180*ce982eb7SThomas Cort 	if (unlink(filename))
181*ce982eb7SThomas Cort 		warn("could not delete: %s", filename);
182*ce982eb7SThomas Cort 	fclose(file);
183*ce982eb7SThomas Cort 
184*ce982eb7SThomas Cort 	free(filename);
185*ce982eb7SThomas Cort 
186*ce982eb7SThomas Cort 	return (0);
187*ce982eb7SThomas Cort }
188