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