1*3b6b08b5Srillig /* $NetBSD: edit.c,v 1.5 2021/08/27 17:36:37 rillig Exp $ */
25533f1ebSrmind /* $OpenBSD: edit.c,v 1.14 2006/05/25 03:20:32 ray Exp $ */
35533f1ebSrmind
45533f1ebSrmind /*
55533f1ebSrmind * Written by Raymond Lai <ray@cyth.net>.
65533f1ebSrmind * Public domain.
75533f1ebSrmind */
85533f1ebSrmind
95533f1ebSrmind #include <sys/types.h>
105533f1ebSrmind #include <sys/wait.h>
115533f1ebSrmind
125533f1ebSrmind #include <ctype.h>
135533f1ebSrmind #include <err.h>
145533f1ebSrmind #include <stdio.h>
155533f1ebSrmind #include <stdlib.h>
165533f1ebSrmind #include <string.h>
175533f1ebSrmind #include <unistd.h>
185533f1ebSrmind
195533f1ebSrmind #include "common.h"
205533f1ebSrmind #include "extern.h"
215533f1ebSrmind
225533f1ebSrmind static void edit(const char *);
235533f1ebSrmind
245533f1ebSrmind /*
255533f1ebSrmind * Takes the name of a file and opens it with an editor.
265533f1ebSrmind */
275533f1ebSrmind static void
edit(const char * filename)285533f1ebSrmind edit(const char *filename)
295533f1ebSrmind {
305533f1ebSrmind int status;
315533f1ebSrmind pid_t pid;
325533f1ebSrmind const char *editor;
335533f1ebSrmind
345533f1ebSrmind editor = getenv("VISUAL");
355533f1ebSrmind if (editor == NULL)
365533f1ebSrmind editor = getenv("EDITOR");
375533f1ebSrmind if (editor == NULL)
385533f1ebSrmind editor = "vi";
395533f1ebSrmind
405533f1ebSrmind /* Start editor on temporary file. */
415533f1ebSrmind switch (pid = fork()) {
425533f1ebSrmind case 0:
435533f1ebSrmind /* child */
44acae6852Splunky execlp(editor, editor, filename, (void *)NULL);
455533f1ebSrmind warn("could not execute editor: %s", editor);
465533f1ebSrmind cleanup(filename);
475533f1ebSrmind case -1:
485533f1ebSrmind warn("could not fork");
495533f1ebSrmind cleanup(filename);
505533f1ebSrmind }
515533f1ebSrmind
525533f1ebSrmind /* parent */
535533f1ebSrmind /* Wait for editor to exit. */
545533f1ebSrmind if (waitpid(pid, &status, 0) == -1) {
555533f1ebSrmind warn("waitpid");
565533f1ebSrmind cleanup(filename);
575533f1ebSrmind }
585533f1ebSrmind
595533f1ebSrmind /* Check that editor terminated normally. */
605533f1ebSrmind if (!WIFEXITED(status)) {
615533f1ebSrmind warn("%s terminated abnormally", editor);
625533f1ebSrmind cleanup(filename);
635533f1ebSrmind }
645533f1ebSrmind }
655533f1ebSrmind
665533f1ebSrmind /*
675533f1ebSrmind * Parse edit command. Returns 0 on success, -1 on error.
685533f1ebSrmind */
695533f1ebSrmind int
eparse(const char * cmd,const char * left,const char * right)705533f1ebSrmind eparse(const char *cmd, const char *left, const char *right)
715533f1ebSrmind {
725533f1ebSrmind FILE *file;
735533f1ebSrmind size_t nread, nwritten;
745533f1ebSrmind int fd;
755533f1ebSrmind char *filename;
765533f1ebSrmind char buf[BUFSIZ], *text;
775533f1ebSrmind
785533f1ebSrmind /* Skip whitespace. */
79*3b6b08b5Srillig while (isspace((unsigned char)(*cmd)))
805533f1ebSrmind ++cmd;
815533f1ebSrmind
825533f1ebSrmind text = NULL;
835533f1ebSrmind switch (*cmd) {
845533f1ebSrmind case '\0':
855533f1ebSrmind /* Edit empty file. */
865533f1ebSrmind break;
875533f1ebSrmind
885533f1ebSrmind case 'b':
895533f1ebSrmind /* Both strings. */
905533f1ebSrmind if (left == NULL)
915533f1ebSrmind goto RIGHT;
925533f1ebSrmind if (right == NULL)
935533f1ebSrmind goto LEFT;
945533f1ebSrmind
955533f1ebSrmind /* Neither column is blank, so print both. */
965533f1ebSrmind if (asprintf(&text, "%s\n%s\n", left, right) == -1)
975533f1ebSrmind err(2, "could not allocate memory");
985533f1ebSrmind break;
995533f1ebSrmind
1005533f1ebSrmind case 'l':
1015533f1ebSrmind LEFT:
1025533f1ebSrmind /* Skip if there is no left column. */
1035533f1ebSrmind if (left == NULL)
1045533f1ebSrmind break;
1055533f1ebSrmind
1065533f1ebSrmind if (asprintf(&text, "%s\n", left) == -1)
1075533f1ebSrmind err(2, "could not allocate memory");
1085533f1ebSrmind
1095533f1ebSrmind break;
1105533f1ebSrmind
1115533f1ebSrmind case 'r':
1125533f1ebSrmind RIGHT:
1135533f1ebSrmind /* Skip if there is no right column. */
1145533f1ebSrmind if (right == NULL)
1155533f1ebSrmind break;
1165533f1ebSrmind
1175533f1ebSrmind if (asprintf(&text, "%s\n", right) == -1)
1185533f1ebSrmind err(2, "could not allocate memory");
1195533f1ebSrmind
1205533f1ebSrmind break;
1215533f1ebSrmind
1225533f1ebSrmind default:
1235533f1ebSrmind return (-1);
1245533f1ebSrmind }
1255533f1ebSrmind
1265533f1ebSrmind /* Create temp file. */
1275533f1ebSrmind if (asprintf(&filename, "%s/sdiff.XXXXXXXXXX", tmpdir) == -1)
1285533f1ebSrmind err(2, "asprintf");
1295533f1ebSrmind if ((fd = mkstemp(filename)) == -1)
1305533f1ebSrmind err(2, "mkstemp");
1315533f1ebSrmind if (text != NULL) {
1325533f1ebSrmind size_t len;
1335533f1ebSrmind
1345533f1ebSrmind len = strlen(text);
13562a63750Slukem if ((size_t)write(fd, text, len) != len) {
1365533f1ebSrmind warn("error writing to temp file");
1375533f1ebSrmind cleanup(filename);
1385533f1ebSrmind }
1395533f1ebSrmind }
1405533f1ebSrmind close(fd);
1415533f1ebSrmind
1425533f1ebSrmind /* text is no longer used. */
1435533f1ebSrmind free(text);
1445533f1ebSrmind
1455533f1ebSrmind /* Edit temp file. */
1465533f1ebSrmind edit(filename);
1475533f1ebSrmind
1485533f1ebSrmind /* Open temporary file. */
1495533f1ebSrmind if (!(file = fopen(filename, "r"))) {
1505533f1ebSrmind warn("could not open edited file: %s", filename);
1515533f1ebSrmind cleanup(filename);
1525533f1ebSrmind }
1535533f1ebSrmind
1545533f1ebSrmind /* Copy temporary file contents to output file. */
1555533f1ebSrmind for (nread = sizeof(buf); nread == sizeof(buf);) {
1565533f1ebSrmind nread = fread(buf, sizeof(*buf), sizeof(buf), file);
1575533f1ebSrmind /* Test for error or end of file. */
1585533f1ebSrmind if (nread != sizeof(buf) &&
1595533f1ebSrmind (ferror(file) || !feof(file))) {
1605533f1ebSrmind warnx("error reading edited file: %s", filename);
1615533f1ebSrmind cleanup(filename);
1625533f1ebSrmind }
1635533f1ebSrmind
1645533f1ebSrmind /*
1655533f1ebSrmind * If we have nothing to read, break out of loop
1665533f1ebSrmind * instead of writing nothing.
1675533f1ebSrmind */
1685533f1ebSrmind if (!nread)
1695533f1ebSrmind break;
1705533f1ebSrmind
1715533f1ebSrmind /* Write data we just read. */
1725533f1ebSrmind nwritten = fwrite(buf, sizeof(*buf), nread, outfile);
1735533f1ebSrmind if (nwritten != nread) {
1745533f1ebSrmind warnx("error writing to output file");
1755533f1ebSrmind cleanup(filename);
1765533f1ebSrmind }
1775533f1ebSrmind }
1785533f1ebSrmind
1795533f1ebSrmind /* We've reached the end of the temporary file, so remove it. */
1805533f1ebSrmind if (unlink(filename))
1815533f1ebSrmind warn("could not delete: %s", filename);
1825533f1ebSrmind fclose(file);
1835533f1ebSrmind
1845533f1ebSrmind free(filename);
1855533f1ebSrmind
1865533f1ebSrmind return (0);
1875533f1ebSrmind }
188