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