about summary refs log tree commit diff homepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile11
-rw-r--r--merge.c120
3 files changed, 128 insertions, 4 deletions
diff --git a/.gitignore b/.gitignore
index d08a301..c072f2b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
 chroot.tar
 client
 help
+merge
 meta
 root
 server
diff --git a/Makefile b/Makefile
index 87b37f6..0be6b77 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 USER = torus
 
-all: server client help meta
+all: server client help meta merge
 
 server: server.c torus.h
 	$(CC) -Wall -Wextra -Wpedantic $(CFLAGS) -o server server.c
@@ -14,13 +14,16 @@ help: help.c torus.h
 meta: meta.c torus.h
 	$(CC) -Wall -Wextra -Wpedantic $(CFLAGS) -o meta meta.c
 
+merge: merge.c torus.h
+	$(CC) -Wall -Wextra -Wpedantic $(CFLAGS) -lcurses -o merge merge.c
+
 termcap: termcap.diff
 	patch -p0 -o termcap < termcap.diff
 
 termcap.db: termcap
 	cap_mkdb termcap
 
-chroot.tar: server client help meta termcap.db
+chroot.tar: server client help termcap.db
 	mkdir -p root
 	install -d -o root -g wheel \
 	    root/bin \
@@ -40,10 +43,10 @@ chroot.tar: server client help meta termcap.db
 	    root/lib
 	install -o root -g wheel -m 444 termcap.db root/usr/share/misc
 	install -o root -g wheel -m 555 /bin/sh root/bin
-	install -o root -g wheel -m 555 server client help meta root/bin
+	install -o root -g wheel -m 555 server client help root/bin
 	tar -c -f chroot.tar -C root bin home lib libexec usr
 
 clean:
-	rm -f server client help meta termcap termcap.db chroot.tar
+	rm -f server client help meta merge termcap termcap.db chroot.tar
 
 .PHONY: all clean
diff --git a/merge.c b/merge.c
new file mode 100644
index 0000000..04396d6
--- /dev/null
+++ b/merge.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2017, June McEnroe <june@causal.agency>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <curses.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#undef COLOR_BLACK
+#undef COLOR_RED
+#undef COLOR_GREEN
+#undef COLOR_YELLOW
+#undef COLOR_BLUE
+#undef COLOR_MAGENTA
+#undef COLOR_CYAN
+#undef COLOR_WHITE
+#include "torus.h"
+
+static ssize_t writeAll(int fd, const char *buf, size_t len) {
+    ssize_t writeLen;
+    while (0 < (writeLen = write(fd, buf, len))) {
+        buf += writeLen;
+        len -= writeLen;
+    }
+    return writeLen;
+}
+
+static void drawTile(int offsetY, const struct Tile *tile) {
+    for (int y = 0; y < CELL_ROWS; ++y) {
+        for (int x = 0; x < CELL_COLS; ++x) {
+            uint8_t color = tile->colors[y][x];
+            char cell = tile->cells[y][x];
+
+            int attrs = COLOR_PAIR(color & ~COLOR_BRIGHT);
+            if (color & COLOR_BRIGHT) attrs |= A_BOLD;
+            mvaddch(offsetY + y, x, attrs | cell);
+        }
+    }
+}
+
+int main(int argc, char *argv[]) {
+    if (argc != 4) return EX_USAGE;
+
+    int a = open(argv[1], O_RDONLY);
+    if (a < 0) err(EX_IOERR, "%s", argv[1]);
+
+    int b = open(argv[2], O_RDONLY);
+    if (b < 0) err(EX_IOERR, "%s", argv[2]);
+
+    int c = open(argv[3], O_WRONLY | O_CREAT, 0644);
+    if (c < 0) err(EX_IOERR, "%s", argv[3]);
+
+    initscr();
+    cbreak();
+    noecho();
+    keypad(stdscr, true);
+    set_escdelay(100);
+    start_color();
+    for (int bg = COLOR_BLACK; bg < COLOR_BRIGHT; ++bg) {
+        for (int fg = COLOR_BLACK; fg < COLOR_BRIGHT; ++fg) {
+            init_pair(bg << 4 | fg, fg, bg);
+        }
+    }
+    mvhline(CELL_ROWS, 0, 0, CELL_COLS);
+
+    struct Tile tileA, tileB;
+    for (;;) {
+        ssize_t lenA = read(a, &tileA, sizeof(tileA));
+        if (lenA < 0) err(EX_IOERR, "%s", argv[1]);
+
+        ssize_t lenB = read(b, &tileB, sizeof(tileB));
+        if (lenB < 0) err(EX_IOERR, "%s", argv[2]);
+
+        if (!lenA && !lenB) break;
+        if (!lenA || !lenB) errx(EX_IOERR, "different size inputs");
+
+        if (tileA.modify == tileB.modify) {
+            ssize_t lenC = writeAll(c, (char *)&tileA, sizeof(tileA));
+            if (lenC < 0) err(EX_IOERR, "%s", argv[3]);
+            continue;
+        }
+
+        drawTile(0, &tileA);
+        drawTile(CELL_ROWS + 1, &tileB);
+        refresh();
+
+        const struct Tile *choice;
+        int ch;
+retry:
+        ch = getch();
+        if (ch == 'a') {
+            choice = &tileA;
+        } else if (ch == 'b') {
+            choice = &tileB;
+        } else {
+            goto retry;
+        }
+
+        ssize_t lenC = writeAll(c, (char *)choice, sizeof(*choice));
+        if (lenC < 0) err(EX_IOERR, "%s", argv[3]);
+    }
+
+    endwin();
+    return EX_OK;
+}