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