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