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