#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "common.h"
#include "extern.h"
static void edit(const char *);
static void
edit(const char *filename)
{
int status;
pid_t pid;
const char *editor;
editor = getenv("VISUAL");
if (editor == NULL)
editor = getenv("EDITOR");
if (editor == NULL)
editor = "vi";
switch (pid = fork()) {
case 0:
execlp(editor, editor, filename, (void *)NULL);
warn("could not execute editor: %s", editor);
cleanup(filename);
case -1:
warn("could not fork");
cleanup(filename);
}
if (waitpid(pid, &status, 0) == -1) {
warn("waitpid");
cleanup(filename);
}
if (!WIFEXITED(status)) {
warn("%s terminated abnormally", editor);
cleanup(filename);
}
}
int
eparse(const char *cmd, const char *left, const char *right)
{
FILE *file;
size_t nread, nwritten;
int fd;
char *filename;
char buf[BUFSIZ], *text;
while (isspace((unsigned char)(*cmd)))
++cmd;
text = NULL;
switch (*cmd) {
case '\0':
break;
case 'b':
if (left == NULL)
goto RIGHT;
if (right == NULL)
goto LEFT;
if (asprintf(&text, "%s\n%s\n", left, right) == -1)
err(2, "could not allocate memory");
break;
case 'l':
LEFT:
if (left == NULL)
break;
if (asprintf(&text, "%s\n", left) == -1)
err(2, "could not allocate memory");
break;
case 'r':
RIGHT:
if (right == NULL)
break;
if (asprintf(&text, "%s\n", right) == -1)
err(2, "could not allocate memory");
break;
default:
return (-1);
}
if (asprintf(&filename, "%s/sdiff.XXXXXXXXXX", tmpdir) == -1)
err(2, "asprintf");
if ((fd = mkstemp(filename)) == -1)
err(2, "mkstemp");
if (text != NULL) {
size_t len;
len = strlen(text);
if ((size_t)write(fd, text, len) != len) {
warn("error writing to temp file");
cleanup(filename);
}
}
close(fd);
free(text);
edit(filename);
if (!(file = fopen(filename, "r"))) {
warn("could not open edited file: %s", filename);
cleanup(filename);
}
for (nread = sizeof(buf); nread == sizeof(buf);) {
nread = fread(buf, sizeof(*buf), sizeof(buf), file);
if (nread != sizeof(buf) &&
(ferror(file) || !feof(file))) {
warnx("error reading edited file: %s", filename);
cleanup(filename);
}
if (!nread)
break;
nwritten = fwrite(buf, sizeof(*buf), nread, outfile);
if (nwritten != nread) {
warnx("error writing to output file");
cleanup(filename);
}
}
if (unlink(filename))
warn("could not delete: %s", filename);
fclose(file);
free(filename);
return (0);
}