1*3e12c5d1SDavid du Colombier #include <u.h> 2*3e12c5d1SDavid du Colombier #include <libc.h> 3*3e12c5d1SDavid du Colombier #include <bio.h> 4*3e12c5d1SDavid du Colombier #include "diff.h" 5*3e12c5d1SDavid du Colombier 6*3e12c5d1SDavid du Colombier struct line { 7*3e12c5d1SDavid du Colombier int serial; 8*3e12c5d1SDavid du Colombier int value; 9*3e12c5d1SDavid du Colombier }; 10*3e12c5d1SDavid du Colombier extern struct line *file[2]; 11*3e12c5d1SDavid du Colombier extern int len[2]; 12*3e12c5d1SDavid du Colombier extern long *ixold, *ixnew; 13*3e12c5d1SDavid du Colombier extern int *J; 14*3e12c5d1SDavid du Colombier 15*3e12c5d1SDavid du Colombier static Biobuf *input[2]; 16*3e12c5d1SDavid du Colombier static char *file1, *file2; 17*3e12c5d1SDavid du Colombier static int firstchange; 18*3e12c5d1SDavid du Colombier 19*3e12c5d1SDavid du Colombier #define MAXLINELEN 4096 20*3e12c5d1SDavid du Colombier #define MIN(x, y) ((x) < (y) ? (x): (y)) 21*3e12c5d1SDavid du Colombier 22*3e12c5d1SDavid du Colombier static int 23*3e12c5d1SDavid du Colombier readline(Biobuf *bp, char *buf) 24*3e12c5d1SDavid du Colombier { 25*3e12c5d1SDavid du Colombier int c; 26*3e12c5d1SDavid du Colombier char *p, *e; 27*3e12c5d1SDavid du Colombier 28*3e12c5d1SDavid du Colombier p = buf; 29*3e12c5d1SDavid du Colombier e = p + MAXLINELEN-1; 30*3e12c5d1SDavid du Colombier do { 31*3e12c5d1SDavid du Colombier c = Bgetc(bp); 32*3e12c5d1SDavid du Colombier if (c < 0) { 33*3e12c5d1SDavid du Colombier if (p == buf) 34*3e12c5d1SDavid du Colombier return -1; 35*3e12c5d1SDavid du Colombier break; 36*3e12c5d1SDavid du Colombier } 37*3e12c5d1SDavid du Colombier if (c == '\n') 38*3e12c5d1SDavid du Colombier break; 39*3e12c5d1SDavid du Colombier *p++ = c; 40*3e12c5d1SDavid du Colombier } while (p < e); 41*3e12c5d1SDavid du Colombier *p = 0; 42*3e12c5d1SDavid du Colombier if (c != '\n' && c >= 0) { 43*3e12c5d1SDavid du Colombier do c = Bgetc(bp); 44*3e12c5d1SDavid du Colombier while (c >= 0 && c != '\n'); 45*3e12c5d1SDavid du Colombier } 46*3e12c5d1SDavid du Colombier return p - buf; 47*3e12c5d1SDavid du Colombier } 48*3e12c5d1SDavid du Colombier 49*3e12c5d1SDavid du Colombier #define HALFLONG 16 50*3e12c5d1SDavid du Colombier #define low(x) (x&((1L<<HALFLONG)-1)) 51*3e12c5d1SDavid du Colombier #define high(x) (x>>HALFLONG) 52*3e12c5d1SDavid du Colombier 53*3e12c5d1SDavid du Colombier /* 54*3e12c5d1SDavid du Colombier * hashing has the effect of 55*3e12c5d1SDavid du Colombier * arranging line in 7-bit bytes and then 56*3e12c5d1SDavid du Colombier * summing 1-s complement in 16-bit hunks 57*3e12c5d1SDavid du Colombier */ 58*3e12c5d1SDavid du Colombier static int 59*3e12c5d1SDavid du Colombier readhash(Biobuf *bp, char *buf) 60*3e12c5d1SDavid du Colombier { 61*3e12c5d1SDavid du Colombier long sum; 62*3e12c5d1SDavid du Colombier unsigned shift; 63*3e12c5d1SDavid du Colombier char *p; 64*3e12c5d1SDavid du Colombier int len, space; 65*3e12c5d1SDavid du Colombier 66*3e12c5d1SDavid du Colombier sum = 1; 67*3e12c5d1SDavid du Colombier shift = 0; 68*3e12c5d1SDavid du Colombier if ((len = readline(bp, buf)) == -1) 69*3e12c5d1SDavid du Colombier return 0; 70*3e12c5d1SDavid du Colombier p = buf; 71*3e12c5d1SDavid du Colombier switch(bflag) /* various types of white space handling */ 72*3e12c5d1SDavid du Colombier { 73*3e12c5d1SDavid du Colombier case 0: 74*3e12c5d1SDavid du Colombier while (len--) { 75*3e12c5d1SDavid du Colombier sum += (long)*p++ << (shift &= (HALFLONG-1)); 76*3e12c5d1SDavid du Colombier shift += 7; 77*3e12c5d1SDavid du Colombier } 78*3e12c5d1SDavid du Colombier break; 79*3e12c5d1SDavid du Colombier case 1: 80*3e12c5d1SDavid du Colombier /* 81*3e12c5d1SDavid du Colombier * coalesce multiple white-space 82*3e12c5d1SDavid du Colombier */ 83*3e12c5d1SDavid du Colombier for (space = 0; len--; p++) { 84*3e12c5d1SDavid du Colombier if (isspace(*p)) { 85*3e12c5d1SDavid du Colombier space++; 86*3e12c5d1SDavid du Colombier continue; 87*3e12c5d1SDavid du Colombier } 88*3e12c5d1SDavid du Colombier if (space) { 89*3e12c5d1SDavid du Colombier shift += 7; 90*3e12c5d1SDavid du Colombier space = 0; 91*3e12c5d1SDavid du Colombier } 92*3e12c5d1SDavid du Colombier sum += (long)*p << (shift &= (HALFLONG-1)); 93*3e12c5d1SDavid du Colombier shift += 7; 94*3e12c5d1SDavid du Colombier } 95*3e12c5d1SDavid du Colombier break; 96*3e12c5d1SDavid du Colombier default: 97*3e12c5d1SDavid du Colombier /* 98*3e12c5d1SDavid du Colombier * strip all white-space 99*3e12c5d1SDavid du Colombier */ 100*3e12c5d1SDavid du Colombier while (len--) { 101*3e12c5d1SDavid du Colombier if (isspace(*p)) { 102*3e12c5d1SDavid du Colombier p++; 103*3e12c5d1SDavid du Colombier continue; 104*3e12c5d1SDavid du Colombier } 105*3e12c5d1SDavid du Colombier sum += (long)*p++ << (shift &= (HALFLONG-1)); 106*3e12c5d1SDavid du Colombier shift += 7; 107*3e12c5d1SDavid du Colombier } 108*3e12c5d1SDavid du Colombier break; 109*3e12c5d1SDavid du Colombier } 110*3e12c5d1SDavid du Colombier sum = low(sum) + high(sum); 111*3e12c5d1SDavid du Colombier return ((short)low(sum) + (short)high(sum)); 112*3e12c5d1SDavid du Colombier } 113*3e12c5d1SDavid du Colombier 114*3e12c5d1SDavid du Colombier Biobuf * 115*3e12c5d1SDavid du Colombier prepare(int i, char *arg) 116*3e12c5d1SDavid du Colombier { 117*3e12c5d1SDavid du Colombier struct line *p; 118*3e12c5d1SDavid du Colombier int j, h; 119*3e12c5d1SDavid du Colombier Biobuf *bp; 120*3e12c5d1SDavid du Colombier char *cp, buf[MAXLINELEN]; 121*3e12c5d1SDavid du Colombier int nbytes; 122*3e12c5d1SDavid du Colombier Rune r; 123*3e12c5d1SDavid du Colombier 124*3e12c5d1SDavid du Colombier bp = Bopen(arg, OREAD); 125*3e12c5d1SDavid du Colombier if (!bp) { 126*3e12c5d1SDavid du Colombier panic(mflag ? 0: 2, "cannot open %s\n", arg); 127*3e12c5d1SDavid du Colombier return 0; 128*3e12c5d1SDavid du Colombier } 129*3e12c5d1SDavid du Colombier nbytes = Bread(bp, buf, MIN(1024, MAXLINELEN)); 130*3e12c5d1SDavid du Colombier if (nbytes > 0) { 131*3e12c5d1SDavid du Colombier cp = buf; 132*3e12c5d1SDavid du Colombier while (cp < buf+nbytes-1) { 133*3e12c5d1SDavid du Colombier /* 134*3e12c5d1SDavid du Colombier * heuristic for a binary file in the 135*3e12c5d1SDavid du Colombier * brave new UNICODE world 136*3e12c5d1SDavid du Colombier */ 137*3e12c5d1SDavid du Colombier cp += chartorune(&r, cp); 138*3e12c5d1SDavid du Colombier if (r == 0 || (r > 0x7f && r <= 0xa0)) { 139*3e12c5d1SDavid du Colombier Bclose(bp); 140*3e12c5d1SDavid du Colombier panic(mflag ? 0: 2, "binary file %s\n", arg); 141*3e12c5d1SDavid du Colombier return 0; 142*3e12c5d1SDavid du Colombier } 143*3e12c5d1SDavid du Colombier } 144*3e12c5d1SDavid du Colombier Bseek(bp, 0, 0); 145*3e12c5d1SDavid du Colombier } 146*3e12c5d1SDavid du Colombier p = MALLOC(struct line, 3); 147*3e12c5d1SDavid du Colombier for (j = 0; h = readhash(bp, buf); p[j].value = h) 148*3e12c5d1SDavid du Colombier p = REALLOC(p, struct line, (++j+3)); 149*3e12c5d1SDavid du Colombier len[i] = j; 150*3e12c5d1SDavid du Colombier file[i] = p; 151*3e12c5d1SDavid du Colombier input[i] = bp; /*fix*/ 152*3e12c5d1SDavid du Colombier if (i == 0) { /*fix*/ 153*3e12c5d1SDavid du Colombier file1 = arg; 154*3e12c5d1SDavid du Colombier firstchange = 0; 155*3e12c5d1SDavid du Colombier } 156*3e12c5d1SDavid du Colombier else 157*3e12c5d1SDavid du Colombier file2 = arg; 158*3e12c5d1SDavid du Colombier return bp; 159*3e12c5d1SDavid du Colombier } 160*3e12c5d1SDavid du Colombier 161*3e12c5d1SDavid du Colombier static int 162*3e12c5d1SDavid du Colombier squishspace(char *buf) 163*3e12c5d1SDavid du Colombier { 164*3e12c5d1SDavid du Colombier char *p, *q; 165*3e12c5d1SDavid du Colombier int space; 166*3e12c5d1SDavid du Colombier 167*3e12c5d1SDavid du Colombier for (space = 0, q = p = buf; *q; q++) { 168*3e12c5d1SDavid du Colombier if (isspace(*q)) { 169*3e12c5d1SDavid du Colombier space++; 170*3e12c5d1SDavid du Colombier continue; 171*3e12c5d1SDavid du Colombier } 172*3e12c5d1SDavid du Colombier if (space && bflag == 1) { 173*3e12c5d1SDavid du Colombier *p++ = ' '; 174*3e12c5d1SDavid du Colombier space = 0; 175*3e12c5d1SDavid du Colombier } 176*3e12c5d1SDavid du Colombier *p++ = *q; 177*3e12c5d1SDavid du Colombier } 178*3e12c5d1SDavid du Colombier *p = 0; 179*3e12c5d1SDavid du Colombier return p - buf; 180*3e12c5d1SDavid du Colombier } 181*3e12c5d1SDavid du Colombier 182*3e12c5d1SDavid du Colombier /* 183*3e12c5d1SDavid du Colombier * need to fix up for unexpected EOF's 184*3e12c5d1SDavid du Colombier */ 185*3e12c5d1SDavid du Colombier void 186*3e12c5d1SDavid du Colombier check(Biobuf *bf, Biobuf *bt) 187*3e12c5d1SDavid du Colombier { 188*3e12c5d1SDavid du Colombier int f, t, flen, tlen; 189*3e12c5d1SDavid du Colombier char fbuf[MAXLINELEN], tbuf[MAXLINELEN]; 190*3e12c5d1SDavid du Colombier 191*3e12c5d1SDavid du Colombier ixold[0] = ixnew[0] = 0; 192*3e12c5d1SDavid du Colombier for (f = t = 1; f < len[0]; f++) { 193*3e12c5d1SDavid du Colombier flen = readline(bf, fbuf); 194*3e12c5d1SDavid du Colombier ixold[f] = ixold[f-1] + flen + 1; /* ftell(bf) */ 195*3e12c5d1SDavid du Colombier if (J[f] == 0) 196*3e12c5d1SDavid du Colombier continue; 197*3e12c5d1SDavid du Colombier do { 198*3e12c5d1SDavid du Colombier tlen = readline(bt, tbuf); 199*3e12c5d1SDavid du Colombier ixnew[t] = ixnew[t-1] + tlen + 1; /* ftell(bt) */ 200*3e12c5d1SDavid du Colombier } while (t++ < J[f]); 201*3e12c5d1SDavid du Colombier if (bflag) { 202*3e12c5d1SDavid du Colombier flen = squishspace(fbuf); 203*3e12c5d1SDavid du Colombier tlen = squishspace(tbuf); 204*3e12c5d1SDavid du Colombier } 205*3e12c5d1SDavid du Colombier if (flen != tlen || strcmp(fbuf, tbuf)) 206*3e12c5d1SDavid du Colombier J[f] = 0; 207*3e12c5d1SDavid du Colombier } 208*3e12c5d1SDavid du Colombier while (t < len[1]) { 209*3e12c5d1SDavid du Colombier tlen = readline(bt, tbuf); 210*3e12c5d1SDavid du Colombier ixnew[t] = ixnew[t-1] + tlen + 1; /* fseek(bt) */ 211*3e12c5d1SDavid du Colombier t++; 212*3e12c5d1SDavid du Colombier } 213*3e12c5d1SDavid du Colombier } 214*3e12c5d1SDavid du Colombier 215*3e12c5d1SDavid du Colombier static void 216*3e12c5d1SDavid du Colombier range(int a, int b, char *separator) 217*3e12c5d1SDavid du Colombier { 218*3e12c5d1SDavid du Colombier Bprint(&stdout, "%d", a > b ? b: a); 219*3e12c5d1SDavid du Colombier if (a < b) 220*3e12c5d1SDavid du Colombier Bprint(&stdout, "%s%d", separator, b); 221*3e12c5d1SDavid du Colombier } 222*3e12c5d1SDavid du Colombier 223*3e12c5d1SDavid du Colombier static void 224*3e12c5d1SDavid du Colombier fetch(long *f, int a, int b, Biobuf *bp, char *s) 225*3e12c5d1SDavid du Colombier { 226*3e12c5d1SDavid du Colombier char buf[MAXLINELEN]; 227*3e12c5d1SDavid du Colombier 228*3e12c5d1SDavid du Colombier Bseek(bp, f[a-1], 0); 229*3e12c5d1SDavid du Colombier while (a++ <= b) { 230*3e12c5d1SDavid du Colombier readline(bp, buf); 231*3e12c5d1SDavid du Colombier Bprint(&stdout, "%s%s\n", s, buf); 232*3e12c5d1SDavid du Colombier } 233*3e12c5d1SDavid du Colombier } 234*3e12c5d1SDavid du Colombier 235*3e12c5d1SDavid du Colombier void 236*3e12c5d1SDavid du Colombier change(int a, int b, int c, int d) 237*3e12c5d1SDavid du Colombier { 238*3e12c5d1SDavid du Colombier if (a > b && c > d) 239*3e12c5d1SDavid du Colombier return; 240*3e12c5d1SDavid du Colombier anychange = 1; 241*3e12c5d1SDavid du Colombier if (mflag && firstchange == 0) { 242*3e12c5d1SDavid du Colombier Bprint(&stdout, "diff %s %s\n", file1, file2); 243*3e12c5d1SDavid du Colombier firstchange = 1; 244*3e12c5d1SDavid du Colombier } 245*3e12c5d1SDavid du Colombier if (mode != 'f') { 246*3e12c5d1SDavid du Colombier range(a, b, ","); 247*3e12c5d1SDavid du Colombier Bputc(&stdout, a > b ? 'a': c > d ? 'd': 'c'); 248*3e12c5d1SDavid du Colombier if (mode != 'e') 249*3e12c5d1SDavid du Colombier range(c, d, ","); 250*3e12c5d1SDavid du Colombier } 251*3e12c5d1SDavid du Colombier else { 252*3e12c5d1SDavid du Colombier Bputc(&stdout, a > b ? 'a': c > d ? 'd': 'c'); 253*3e12c5d1SDavid du Colombier range(a, b, " "); 254*3e12c5d1SDavid du Colombier } 255*3e12c5d1SDavid du Colombier Bputc(&stdout, '\n'); 256*3e12c5d1SDavid du Colombier if (mode == 0) { 257*3e12c5d1SDavid du Colombier fetch(ixold, a, b, input[0], "< "); 258*3e12c5d1SDavid du Colombier if (a <= b && c <= d) 259*3e12c5d1SDavid du Colombier Bprint(&stdout, "---\n"); 260*3e12c5d1SDavid du Colombier } 261*3e12c5d1SDavid du Colombier fetch(ixnew, c, d, input[1], mode == 0 ? "> ": ""); 262*3e12c5d1SDavid du Colombier if (mode != 0 && c <= d) 263*3e12c5d1SDavid du Colombier Bprint(&stdout, ".\n"); 264*3e12c5d1SDavid du Colombier } 265