#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <paths.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "common.h"
#include "extern.h"
int editit(const char *);
int
editit(const char *pathname)
{
char *argp[] = {"sh", "-c", NULL, NULL}, *ed, *p;
sig_t sighup, sigint, sigquit, sigchld;
pid_t pid;
int saved_errno, st, ret = -1;
ed = getenv("VISUAL");
if (ed == NULL || ed[0] == '\0')
ed = getenv("EDITOR");
if (ed == NULL || ed[0] == '\0')
ed = _PATH_VI;
if (asprintf(&p, "%s %s", ed, pathname) == -1)
return (-1);
argp[2] = p;
sighup = signal(SIGHUP, SIG_IGN);
sigint = signal(SIGINT, SIG_IGN);
sigquit = signal(SIGQUIT, SIG_IGN);
sigchld = signal(SIGCHLD, SIG_DFL);
if ((pid = fork()) == -1)
goto fail;
if (pid == 0) {
execv(_PATH_BSHELL, argp);
_exit(127);
}
while (waitpid(pid, &st, 0) == -1)
if (errno != EINTR)
goto fail;
if (!WIFEXITED(st))
errno = EINTR;
else
ret = WEXITSTATUS(st);
fail:
saved_errno = errno;
(void)signal(SIGHUP, sighup);
(void)signal(SIGINT, sigint);
(void)signal(SIGQUIT, sigquit);
(void)signal(SIGCHLD, sigchld);
free(p);
errno = saved_errno;
return (ret);
}
int
eparse(const char *cmd, const char *left, const char *right)
{
FILE *file;
size_t nread;
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;
ssize_t nwritten;
len = strlen(text);
if ((nwritten = write(fd, text, len)) == -1 ||
nwritten != len) {
warn("error writing to temp file");
cleanup(filename);
}
}
close(fd);
free(text);
if (editit(filename) == -1) {
warn("error editing %s", filename);
cleanup(filename);
}
if (!(file = fopen(filename, "r"))) {
warn("could not open edited file: %s", filename);
cleanup(filename);
}
for (nread = sizeof(buf); nread == sizeof(buf);) {
size_t nwritten;
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, outfp);
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);
}