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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 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 } 174 175 /* synch on C successive matches */ 176 static int 177 easysynch() 178 { 179 int i, j; 180 int k, m; 181 char *s0, *s1; 182 183 for (i = j = 1; i < RANGE && j < RANGE; i++, j++) { 184 s0 = getl(0, n0+i); 185 if (s0 == NULL) 186 return (output(INF, INF)); 187 for (k = C-1; k < j; k++) { 188 for (m = 0; m < C; m++) 189 if (cmp(getl(0, n0+i-m), 190 getl(1, n1+k-m)) != 0) 191 goto cont1; 192 return (output(i-C, k-C)); 193 cont1: 194 ; 195 } 196 s1 = getl(1, n1+j); 197 if (s1 == NULL) 198 return (output(INF, INF)); 199 for (k = C-1; k <= i; k++) { 200 for (m = 0; m < C; m++) 201 if (cmp(getl(0, n0+k-m), 202 getl(1, n1+j-m)) != 0) 203 goto cont2; 204 return (output(k-C, j-C)); 205 cont2: 206 ; 207 } 208 } 209 return (0); 210 } 211 212 static int 213 output(int a, int b) 214 { 215 int i; 216 char *s; 217 218 if (a < 0) 219 change(n0-1, 0, n1, b, "a"); 220 else if (b < 0) 221 change(n0, a, n1-1, 0, "d"); 222 else 223 change(n0, a, n1, b, "c"); 224 for (i = 0; i <= a; i++) { 225 s = getl(0, n0+i); 226 if (s == NULL) 227 break; 228 (void) printf("< %s", s); 229 clrl(0, n0+i); 230 } 231 n0 += i-1; 232 if (a >= 0 && b >= 0) 233 (void) printf("---\n"); 234 for (i = 0; i <= b; i++) { 235 s = getl(1, n1+i); 236 if (s == NULL) 237 break; 238 (void) printf("> %s", s); 239 clrl(1, n1+i); 240 } 241 diffFound = 1; 242 n1 += i-1; 243 return (1); 244 } 245 246 static void 247 change(long a, int b, long c, int d, char *s) 248 { 249 range(a, b); 250 (void) printf("%s", s); 251 range(c, d); 252 (void) printf("\n"); 253 } 254 255 static void 256 range(long a, int b) 257 { 258 if (b == INF) 259 (void) printf("%ld,$", a); 260 else if (b == 0) 261 (void) printf("%ld", a); 262 else 263 (void) printf("%ld,%ld", a, a+b); 264 } 265 266 static int 267 cmp(char *s, char *t) 268 { 269 if (debug) 270 (void) printf("%s:%s\n", s, t); 271 for (;;) { 272 if (bflag && isspace(*s) && isspace(*t)) { 273 while (isspace(*++s)) 274 ; 275 while (isspace(*++t)) 276 ; 277 } 278 if (*s != *t || *s == 0) 279 break; 280 s++; 281 t++; 282 } 283 return (*s-*t); 284 } 285 286 static FILE * 287 dopen(char *f1, char *f2) 288 { 289 FILE *f; 290 char b[PATH_MAX], *bptr, *eptr; 291 struct stat statbuf; 292 293 if (cmp(f1, "-") == 0) { 294 if (cmp(f2, "-") == 0) 295 error(gettext("can't do - -")); 296 else { 297 if (fstat(fileno(stdin), &statbuf) == -1) 298 error(gettext("can't access stdin")); 299 else 300 return (stdin); 301 } 302 } 303 if (stat(f1, &statbuf) == -1) 304 error(gettext("can't access %s"), f1); 305 if ((statbuf.st_mode & S_IFMT) == S_IFDIR) { 306 for (bptr = b; *bptr = *f1++; bptr++) 307 ; 308 *bptr++ = '/'; 309 for (eptr = f2; *eptr; eptr++) 310 if (*eptr == '/' && eptr[1] != 0 && eptr[1] != '/') 311 f2 = eptr+1; 312 while (*bptr++ = *f2++) 313 ; 314 f1 = b; 315 } 316 f = fopen(f1, "r"); 317 if (f == NULL) 318 error(gettext("can't open %s"), f1); 319 return (f); 320 } 321 322 323 static void 324 progerr(char *s) 325 { 326 error(gettext("program error %s"), s); 327 } 328 329 static void 330 error(char *err, ...) 331 { 332 va_list ap; 333 334 va_start(ap, err); 335 (void) fprintf(stderr, "diffh: "); 336 (void) vfprintf(stderr, err, ap); 337 (void) fprintf(stderr, "\n"); 338 va_end(ap); 339 exit(2); 340 } 341 342 /* stub for resychronization beyond limits of text buf */ 343 static int 344 hardsynch() 345 { 346 change(n0, INF, n1, INF, "c"); 347 (void) printf(gettext("---change record omitted\n")); 348 error(gettext("can't resynchronize")); 349 return (0); 350 } 351