1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29 /* All Rights Reserved */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <ctype.h> 37 #include <locale.h> 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 #include <limits.h> 41 #include <stdarg.h> 42 43 #define C 3 44 #define RANGE 30 45 #define LEN 255 46 #define INF 16384 47 48 char *text[2][RANGE]; 49 long lineno[2] = {1, 1}; /* no. of 1st stored line in each file */ 50 int ntext[2]; /* number of stored lines in each */ 51 long n0, n1; /* scan pointer in each */ 52 int bflag; 53 int debug = 0; 54 FILE *file[2]; 55 static int diffFound = 0; 56 57 static char *getl(int f, long n); 58 static void clrl(int f, long n); 59 static void movstr(char *s, char *t); 60 static int easysynch(void); 61 static int output(int a, int b); 62 static void change(long a, int b, long c, int d, char *s); 63 static void range(long a, int b); 64 static int cmp(char *s, char *t); 65 static FILE *dopen(char *f1, char *f2); 66 static void progerr(char *s); 67 static void error(char *err, ...); 68 static int hardsynch(void); 69 70 /* return pointer to line n of file f */ 71 static char * 72 getl(int f, long n) 73 { 74 char *t; 75 int delta, nt; 76 77 again: 78 delta = n - lineno[f]; 79 nt = ntext[f]; 80 if (delta < 0) 81 progerr("1"); 82 if (delta < nt) 83 return (text[f][delta]); 84 if (delta > nt) 85 progerr("2"); 86 if (nt >= RANGE) 87 progerr("3"); 88 if (feof(file[f])) 89 return (NULL); 90 t = text[f][nt]; 91 if (t == 0) { 92 t = text[f][nt] = (char *)malloc(LEN+1); 93 if (t == NULL) 94 if (hardsynch()) 95 goto again; 96 else 97 progerr("5"); 98 } 99 t = fgets(t, LEN, file[f]); 100 if (t != NULL) 101 ntext[f]++; 102 return (t); 103 } 104 105 /* remove thru line n of file f from storage */ 106 static void 107 clrl(int f, long n) 108 { 109 int i, j; 110 111 j = n-lineno[f]+1; 112 for (i = 0; i+j < ntext[f]; i++) 113 movstr(text[f][i+j], text[f][i]); 114 lineno[f] = n+1; 115 ntext[f] -= j; 116 } 117 118 static void 119 movstr(char *s, char *t) 120 { 121 while (*t++ = *s++) 122 continue; 123 } 124 125 int 126 main(int argc, char **argv) 127 { 128 char *s0, *s1; 129 130 if ((argc > 1) && (*argv[1] == '-')) { 131 argc--; 132 argv++; 133 while (*++argv[0]) 134 if (*argv[0] == 'b') 135 bflag++; 136 } 137 138 (void) setlocale(LC_ALL, ""); 139 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 140 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 141 #endif 142 (void) textdomain(TEXT_DOMAIN); 143 144 if (argc != 3) 145 error(gettext("must have 2 file arguments")); 146 file[0] = dopen(argv[1], argv[2]); 147 file[1] = dopen(argv[2], argv[1]); 148 for (;;) { 149 s0 = getl(0, ++n0); 150 s1 = getl(1, ++n1); 151 if (s0 == NULL || s1 == NULL) 152 break; 153 if (cmp(s0, s1) != 0) { 154 if (!easysynch() && !hardsynch()) 155 progerr("5"); 156 } else { 157 clrl(0, n0); 158 clrl(1, n1); 159 } 160 } 161 /* diff is expected to return 1 if the files differ */ 162 if (s0 == NULL && s1 == NULL) 163 return (diffFound); 164 if (s0 == NULL) { 165 (void) output(-1, INF); 166 return (1); 167 } 168 if (s1 == NULL) { 169 (void) output(INF, -1); 170 return (1); 171 } 172 /* NOTREACHED */ 173 return (0); 174 } 175 176 /* synch on C successive matches */ 177 static int 178 easysynch() 179 { 180 int i, j; 181 int k, m; 182 char *s0, *s1; 183 184 for (i = j = 1; i < RANGE && j < RANGE; i++, j++) { 185 s0 = getl(0, n0+i); 186 if (s0 == NULL) 187 return (output(INF, INF)); 188 for (k = C-1; k < j; k++) { 189 for (m = 0; m < C; m++) 190 if (cmp(getl(0, n0+i-m), 191 getl(1, n1+k-m)) != 0) 192 goto cont1; 193 return (output(i-C, k-C)); 194 cont1: 195 ; 196 } 197 s1 = getl(1, n1+j); 198 if (s1 == NULL) 199 return (output(INF, INF)); 200 for (k = C-1; k <= i; k++) { 201 for (m = 0; m < C; m++) 202 if (cmp(getl(0, n0+k-m), 203 getl(1, n1+j-m)) != 0) 204 goto cont2; 205 return (output(k-C, j-C)); 206 cont2: 207 ; 208 } 209 } 210 return (0); 211 } 212 213 static int 214 output(int a, int b) 215 { 216 int i; 217 char *s; 218 219 if (a < 0) 220 change(n0-1, 0, n1, b, "a"); 221 else if (b < 0) 222 change(n0, a, n1-1, 0, "d"); 223 else 224 change(n0, a, n1, b, "c"); 225 for (i = 0; i <= a; i++) { 226 s = getl(0, n0+i); 227 if (s == NULL) 228 break; 229 (void) printf("< %s", s); 230 clrl(0, n0+i); 231 } 232 n0 += i-1; 233 if (a >= 0 && b >= 0) 234 (void) printf("---\n"); 235 for (i = 0; i <= b; i++) { 236 s = getl(1, n1+i); 237 if (s == NULL) 238 break; 239 (void) printf("> %s", s); 240 clrl(1, n1+i); 241 } 242 diffFound = 1; 243 n1 += i-1; 244 return (1); 245 } 246 247 static void 248 change(long a, int b, long c, int d, char *s) 249 { 250 range(a, b); 251 (void) printf("%s", s); 252 range(c, d); 253 (void) printf("\n"); 254 } 255 256 static void 257 range(long a, int b) 258 { 259 if (b == INF) 260 (void) printf("%ld,$", a); 261 else if (b == 0) 262 (void) printf("%ld", a); 263 else 264 (void) printf("%ld,%ld", a, a+b); 265 } 266 267 static int 268 cmp(char *s, char *t) 269 { 270 if (debug) 271 (void) printf("%s:%s\n", s, t); 272 for (;;) { 273 if (bflag && isspace(*s) && isspace(*t)) { 274 while (isspace(*++s)) 275 ; 276 while (isspace(*++t)) 277 ; 278 } 279 if (*s != *t || *s == 0) 280 break; 281 s++; 282 t++; 283 } 284 return (*s-*t); 285 } 286 287 static FILE * 288 dopen(char *f1, char *f2) 289 { 290 FILE *f; 291 char b[PATH_MAX], *bptr, *eptr; 292 struct stat statbuf; 293 294 if (cmp(f1, "-") == 0) { 295 if (cmp(f2, "-") == 0) 296 error(gettext("can't do - -")); 297 else { 298 if (fstat(fileno(stdin), &statbuf) == -1) 299 error(gettext("can't access stdin")); 300 else 301 return (stdin); 302 } 303 } 304 if (stat(f1, &statbuf) == -1) 305 error(gettext("can't access %s"), f1); 306 if ((statbuf.st_mode & S_IFMT) == S_IFDIR) { 307 for (bptr = b; *bptr = *f1++; bptr++) 308 ; 309 *bptr++ = '/'; 310 for (eptr = f2; *eptr; eptr++) 311 if (*eptr == '/' && eptr[1] != 0 && eptr[1] != '/') 312 f2 = eptr+1; 313 while (*bptr++ = *f2++) 314 ; 315 f1 = b; 316 } 317 f = fopen(f1, "r"); 318 if (f == NULL) 319 error(gettext("can't open %s"), f1); 320 return (f); 321 } 322 323 324 static void 325 progerr(char *s) 326 { 327 error(gettext("program error %s"), s); 328 } 329 330 static void 331 error(char *err, ...) 332 { 333 va_list ap; 334 335 va_start(ap, err); 336 (void) fprintf(stderr, "diffh: "); 337 (void) vfprintf(stderr, err, ap); 338 (void) fprintf(stderr, "\n"); 339 va_end(ap); 340 exit(2); 341 } 342 343 /* stub for resychronization beyond limits of text buf */ 344 static int 345 hardsynch() 346 { 347 change(n0, INF, n1, INF, "c"); 348 (void) printf(gettext("---change record omitted\n")); 349 error(gettext("can't resynchronize")); 350 return (0); 351 } 352