shithub: ips

Download patch

ref: cb299c23ec8270a86863785b7b71fdb40efab2a3
parent: cc747ead109a2d48e0242108addf3cb8d349f2d3
author: Jacob Moody <moody@posixcafe.org>
date: Wed May 3 18:43:04 EDT 2023

refactor and add ipsdiff

--- a/ips.c
+++ /dev/null
@@ -1,97 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-
-#define GET2(p) (u16int)(p)[1] | (u16int)(p)[0]<<8
-#define GET3(p) (u16int)(p)[2] | (u16int)(p)[1]<<8 | (u16int)(p[0])<<16
-
-enum{
-	Hdrsz = 3 + 2,
-	RLEsz = 2 + 1,
-};
-
-static uchar section[Hdrsz + 0xFFFF + RLEsz];
-static Biobuf *ips;
-
-static int
-readsect(u32int *off, u16int *sz)
-{
-	u16int count;
-	uchar val;
-
-	if(Bread(ips, section, 3) != 3)
-		sysfatal("short read of off: %r");
-	if(memcmp(section, "EOF", 3) == 0)
-		return 0;
-	if(Bread(ips, section + 3, 2) != 2)
-		sysfatal("short read of size: %r");
-	*off = GET3(section);
-
-	*sz = GET2(section + 3);
-	if(*sz == 0){
-		if(Bread(ips, section + Hdrsz + 0xFFFF, RLEsz) != RLEsz)
-			sysfatal("short read of RLE: %r");
-		count = GET2(section + Hdrsz + 0xFFFF);
-		val = section[Hdrsz + 0xFFFF + 2];
-		memset(section + Hdrsz, val, count);
-		*sz = count;
-	} else if(Bread(ips, section + Hdrsz, *sz) != *sz)
-		sysfatal("short read of data: %r");
-	return 1;
-}
-
-void
-usage(void)
-{
-	fprint(2, "usage: %s patch.ips <file.orig >file.new\n", argv0);
-	exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
-	ulong dot, x;
-	long n;
-	uchar buf[8192];
-	u32int off;
-	u16int sz;
-
-	ARGBEGIN{
-	default:
-		usage();
-	}ARGEND;
-	if(argc < 1)
-		usage();
-
-	ips = Bopen(argv[0], OREAD);
-	if(ips == nil)
-		sysfatal("open: %r");
-
-	if(Bread(ips, buf, 5) != 5)
-		sysfatal("short read on magic: %r");
-	if(memcmp(buf, "PATCH", 5) != 0)
-		sysfatal("bad magic");
-
-	if(readsect(&off, &sz) == 0)
-		sysfatal("not a single section");
-
-	for(dot = 0; (n = read(0, buf, sizeof buf)) > 0; dot += n){
-		while(off < dot+n){
-			if(off < dot)
-				sysfatal("skipped region");
-			if(off + sz > dot + n){
-				x = (dot + n) - off;
-				memcpy(buf + (off - dot), section + Hdrsz, x);
-				memmove(section + Hdrsz, section + Hdrsz + x, sz - x);
-				sz -= x;
-				off += x;
-				break;
-			}
-			memcpy(buf + (off - dot), section + Hdrsz, sz);
-			if(readsect(&off, &sz) == 0)
-				break;
-		}
-		write(1, buf, n);
-	}
-	exits(nil);
-}
--- /dev/null
+++ b/ipsdiff.c
@@ -1,0 +1,121 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+#define PUT2(p, u) (p)[0] = (u)>>8, (p)[1] = (u)
+#define PUT3(p, u) (p)[0] = (u)>>16, (p)[1] = (u)>>8, (p)[2] = (u)
+
+Biobuf *ips;
+typedef struct Bin Bin;
+struct Bin{
+	int fd;
+	long dot;
+	long n, off;
+	uchar data[0xFFFF];
+};
+
+static Bin base, modded;
+static int dump = 0;
+
+static long
+slurp(Bin *b)
+{
+	long n;
+
+	n = readn(b->fd, b->data + b->off, sizeof b->data - b->off);
+	if(n < 0)
+		sysfatal("read: %r");
+	b->n = b->off + n;
+	return n;
+}
+
+static void
+emit(u32int off, uchar *data, u16int size)
+{
+	uchar buf[3 + 2];
+
+	if(size == 0)
+		return;
+	PUT3(buf, off);
+	PUT2(buf+3, size);
+	if(dump)
+		fprint(2, "%ud %ud\n", off, size);
+	if(Bwrite(ips, buf, sizeof buf) != sizeof buf)
+		sysfatal("Bwrite: %r");
+	if(Bwrite(ips, data, size) != size)
+		sysfatal("Bwrite: %r");
+}
+
+static void
+diff(Bin *a, Bin *b)
+{
+	uchar *ap, *bp;
+	uchar *ac, *bc;
+	uchar *ae, *be;
+	int x;
+
+	ap = a->data;
+	bp = b->data;
+	ae = a->data + a->n;
+	be = b->data + b->n;
+
+	if(a->n != b->n)
+		sysfatal("desync: %ld %ld", a->n, a->n);
+
+	while(ap < ae && bp < be){
+		if(*ap == *bp){
+			ap++;
+			bp++;
+			continue;
+		}
+		// FIXME: better way of expanding diff context
+		x = 32;
+		for(ac = ap, bc = bp; ac < ae && bc < be; ac++, bc++){
+			if(--x <= 0 && *ac == *bc)
+				break;
+		}
+		emit(a->dot + (ap - a->data), bp, bc - bp);
+		ap = ac;
+		bp = bc;
+	}
+	a->dot += a->n;
+	b->dot += b->n;
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s base modified >patch.ips", argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	ARGBEGIN{
+	case 'd':
+		dump++;
+		break;
+	default:
+		usage();
+	}ARGEND;
+	if(argc < 2)
+		usage();
+
+	ips = Bfdopen(1, OWRITE);
+	if(ips == nil)
+		sysfatal("Bfdopen: %r");
+	Bwrite(ips, "PATCH", 5);
+
+	base.fd = open(argv[0], OREAD);
+	modded.fd = open(argv[1], OREAD);
+	if(base.fd < 0 || modded.fd < 0)
+		sysfatal("open: %r");
+
+	while(slurp(&base) != 0 && slurp(&modded) != 0)
+		diff(&base, &modded);
+
+	Bwrite(ips, "EOF", 3);
+	Bflush(ips);
+	exits(nil);
+}
--- /dev/null
+++ b/ipspatch.c
@@ -1,0 +1,102 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+#define GET2(p) (u16int)(p)[1] | (u16int)(p)[0]<<8
+#define GET3(p) (u16int)(p)[2] | (u16int)(p)[1]<<8 | (u16int)(p[0])<<16
+
+enum{
+	Hdrsz = 3 + 2,
+	RLEsz = 2 + 1,
+};
+
+static uchar section[Hdrsz + 0xFFFF + RLEsz];
+static Biobuf *ips;
+static int dump = 0;
+
+static int
+readsect(u32int *off, u16int *sz)
+{
+	u16int count;
+	uchar val;
+
+	if(Bread(ips, section, 3) != 3)
+		sysfatal("short read of off: %r");
+	if(memcmp(section, "EOF", 3) == 0)
+		return 0;
+	if(Bread(ips, section + 3, 2) != 2)
+		sysfatal("short read of size: %r");
+	*off = GET3(section);
+
+	*sz = GET2(section + 3);
+	if(*sz == 0){
+		if(Bread(ips, section + Hdrsz + 0xFFFF, RLEsz) != RLEsz)
+			sysfatal("short read of RLE: %r");
+		count = GET2(section + Hdrsz + 0xFFFF);
+		val = section[Hdrsz + 0xFFFF + 2];
+		memset(section + Hdrsz, val, count);
+		*sz = count;
+	} else if(Bread(ips, section + Hdrsz, *sz) != *sz)
+		sysfatal("short read of data: %r");
+	//fprint(2, "%ud %ud\n", *off, *sz);
+	return 1;
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s patch.ips <file.orig >file.new\n", argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	ulong dot, x;
+	long n;
+	uchar buf[8192];
+	u32int off;
+	u16int sz;
+
+	ARGBEGIN{
+	case 'd':
+		dump++;
+		break;
+	default:
+		usage();
+	}ARGEND;
+	if(argc < 1)
+		usage();
+
+	ips = Bopen(argv[0], OREAD);
+	if(ips == nil)
+		sysfatal("open: %r");
+
+	if(Bread(ips, buf, 5) != 5)
+		sysfatal("short read on magic: %r");
+	if(memcmp(buf, "PATCH", 5) != 0)
+		sysfatal("bad magic");
+
+	if(readsect(&off, &sz) == 0)
+		sysfatal("not a single section");
+
+	for(dot = 0; (n = read(0, buf, sizeof buf)) > 0; dot += n){
+		while(off < dot+n){
+			if(off < dot)
+				sysfatal("skipped region");
+			if(off + sz > dot + n){
+				x = (dot + n) - off;
+				memcpy(buf + (off - dot), section + Hdrsz, x);
+				memmove(section + Hdrsz, section + Hdrsz + x, sz - x);
+				sz -= x;
+				off += x;
+				break;
+			}
+			memcpy(buf + (off - dot), section + Hdrsz, sz);
+			if(readsect(&off, &sz) == 0)
+				break;
+		}
+		write(1, buf, n);
+	}
+	exits(nil);
+}
--- a/mkfile
+++ b/mkfile
@@ -1,8 +1,8 @@
 </$objtype/mkfile
 
 BIN=$home/bin/$objtype
-TARG=ips
-OFILES=\
-	ips.$O\
+TARG=\
+	ipsdiff\
+	ipspatch\
 
-</sys/src/cmd/mkone
+</sys/src/cmd/mkmany