10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 22*236Schin 23*236Schin /* 24*236Schin * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25*236Schin * Use is subject to license terms. 26*236Schin */ 27*236Schin 280Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 290Sstevel@tonic-gate /* All Rights Reserved */ 300Sstevel@tonic-gate 310Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <stdio.h> 340Sstevel@tonic-gate #include <stdlib.h> 350Sstevel@tonic-gate #include <unistd.h> 360Sstevel@tonic-gate #include <ctype.h> 370Sstevel@tonic-gate #include <locale.h> 380Sstevel@tonic-gate #include <sys/types.h> 390Sstevel@tonic-gate #include <sys/stat.h> 400Sstevel@tonic-gate #include <limits.h> 410Sstevel@tonic-gate #include <stdarg.h> 420Sstevel@tonic-gate 430Sstevel@tonic-gate #define C 3 440Sstevel@tonic-gate #define RANGE 30 450Sstevel@tonic-gate #define LEN 255 460Sstevel@tonic-gate #define INF 16384 470Sstevel@tonic-gate 480Sstevel@tonic-gate char *text[2][RANGE]; 490Sstevel@tonic-gate long lineno[2] = {1, 1}; /* no. of 1st stored line in each file */ 500Sstevel@tonic-gate int ntext[2]; /* number of stored lines in each */ 510Sstevel@tonic-gate long n0, n1; /* scan pointer in each */ 520Sstevel@tonic-gate int bflag; 530Sstevel@tonic-gate int debug = 0; 540Sstevel@tonic-gate FILE *file[2]; 550Sstevel@tonic-gate static int diffFound = 0; 560Sstevel@tonic-gate 570Sstevel@tonic-gate static char *getl(int f, long n); 580Sstevel@tonic-gate static void clrl(int f, long n); 590Sstevel@tonic-gate static void movstr(char *s, char *t); 600Sstevel@tonic-gate static int easysynch(void); 610Sstevel@tonic-gate static int output(int a, int b); 620Sstevel@tonic-gate static void change(long a, int b, long c, int d, char *s); 630Sstevel@tonic-gate static void range(long a, int b); 640Sstevel@tonic-gate static int cmp(char *s, char *t); 650Sstevel@tonic-gate static FILE *dopen(char *f1, char *f2); 660Sstevel@tonic-gate static void progerr(char *s); 670Sstevel@tonic-gate static void error(char *err, ...); 680Sstevel@tonic-gate static int hardsynch(void); 690Sstevel@tonic-gate 700Sstevel@tonic-gate /* return pointer to line n of file f */ 710Sstevel@tonic-gate static char * 720Sstevel@tonic-gate getl(int f, long n) 730Sstevel@tonic-gate { 740Sstevel@tonic-gate char *t; 750Sstevel@tonic-gate int delta, nt; 760Sstevel@tonic-gate 770Sstevel@tonic-gate again: 780Sstevel@tonic-gate delta = n - lineno[f]; 790Sstevel@tonic-gate nt = ntext[f]; 800Sstevel@tonic-gate if (delta < 0) 810Sstevel@tonic-gate progerr("1"); 820Sstevel@tonic-gate if (delta < nt) 830Sstevel@tonic-gate return (text[f][delta]); 840Sstevel@tonic-gate if (delta > nt) 850Sstevel@tonic-gate progerr("2"); 860Sstevel@tonic-gate if (nt >= RANGE) 870Sstevel@tonic-gate progerr("3"); 880Sstevel@tonic-gate if (feof(file[f])) 890Sstevel@tonic-gate return (NULL); 900Sstevel@tonic-gate t = text[f][nt]; 910Sstevel@tonic-gate if (t == 0) { 920Sstevel@tonic-gate t = text[f][nt] = (char *)malloc(LEN+1); 930Sstevel@tonic-gate if (t == NULL) 940Sstevel@tonic-gate if (hardsynch()) 950Sstevel@tonic-gate goto again; 960Sstevel@tonic-gate else 970Sstevel@tonic-gate progerr("5"); 980Sstevel@tonic-gate } 990Sstevel@tonic-gate t = fgets(t, LEN, file[f]); 1000Sstevel@tonic-gate if (t != NULL) 1010Sstevel@tonic-gate ntext[f]++; 1020Sstevel@tonic-gate return (t); 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate /* remove thru line n of file f from storage */ 1060Sstevel@tonic-gate static void 1070Sstevel@tonic-gate clrl(int f, long n) 1080Sstevel@tonic-gate { 1090Sstevel@tonic-gate int i, j; 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate j = n-lineno[f]+1; 1120Sstevel@tonic-gate for (i = 0; i+j < ntext[f]; i++) 1130Sstevel@tonic-gate movstr(text[f][i+j], text[f][i]); 1140Sstevel@tonic-gate lineno[f] = n+1; 1150Sstevel@tonic-gate ntext[f] -= j; 1160Sstevel@tonic-gate } 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate static void 1190Sstevel@tonic-gate movstr(char *s, char *t) 1200Sstevel@tonic-gate { 1210Sstevel@tonic-gate while (*t++ = *s++) 1220Sstevel@tonic-gate continue; 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate int 1260Sstevel@tonic-gate main(int argc, char **argv) 1270Sstevel@tonic-gate { 1280Sstevel@tonic-gate char *s0, *s1; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate if ((argc > 1) && (*argv[1] == '-')) { 1310Sstevel@tonic-gate argc--; 1320Sstevel@tonic-gate argv++; 1330Sstevel@tonic-gate while (*++argv[0]) 1340Sstevel@tonic-gate if (*argv[0] == 'b') 1350Sstevel@tonic-gate bflag++; 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1390Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 1400Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 1410Sstevel@tonic-gate #endif 1420Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate if (argc != 3) 1450Sstevel@tonic-gate error(gettext("must have 2 file arguments")); 1460Sstevel@tonic-gate file[0] = dopen(argv[1], argv[2]); 1470Sstevel@tonic-gate file[1] = dopen(argv[2], argv[1]); 1480Sstevel@tonic-gate for (;;) { 1490Sstevel@tonic-gate s0 = getl(0, ++n0); 1500Sstevel@tonic-gate s1 = getl(1, ++n1); 1510Sstevel@tonic-gate if (s0 == NULL || s1 == NULL) 1520Sstevel@tonic-gate break; 1530Sstevel@tonic-gate if (cmp(s0, s1) != 0) { 1540Sstevel@tonic-gate if (!easysynch() && !hardsynch()) 1550Sstevel@tonic-gate progerr("5"); 1560Sstevel@tonic-gate } else { 1570Sstevel@tonic-gate clrl(0, n0); 1580Sstevel@tonic-gate clrl(1, n1); 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate } 1610Sstevel@tonic-gate /* diff is expected to return 1 if the files differ */ 1620Sstevel@tonic-gate if (s0 == NULL && s1 == NULL) 1630Sstevel@tonic-gate return (diffFound); 1640Sstevel@tonic-gate if (s0 == NULL) { 1650Sstevel@tonic-gate (void) output(-1, INF); 1660Sstevel@tonic-gate return (1); 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate if (s1 == NULL) { 1690Sstevel@tonic-gate (void) output(INF, -1); 1700Sstevel@tonic-gate return (1); 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate /* NOTREACHED */ 173*236Schin return (0); 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate /* synch on C successive matches */ 1770Sstevel@tonic-gate static int 1780Sstevel@tonic-gate easysynch() 1790Sstevel@tonic-gate { 1800Sstevel@tonic-gate int i, j; 1810Sstevel@tonic-gate int k, m; 1820Sstevel@tonic-gate char *s0, *s1; 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate for (i = j = 1; i < RANGE && j < RANGE; i++, j++) { 1850Sstevel@tonic-gate s0 = getl(0, n0+i); 1860Sstevel@tonic-gate if (s0 == NULL) 1870Sstevel@tonic-gate return (output(INF, INF)); 1880Sstevel@tonic-gate for (k = C-1; k < j; k++) { 1890Sstevel@tonic-gate for (m = 0; m < C; m++) 1900Sstevel@tonic-gate if (cmp(getl(0, n0+i-m), 1910Sstevel@tonic-gate getl(1, n1+k-m)) != 0) 1920Sstevel@tonic-gate goto cont1; 1930Sstevel@tonic-gate return (output(i-C, k-C)); 1940Sstevel@tonic-gate cont1: 1950Sstevel@tonic-gate ; 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate s1 = getl(1, n1+j); 1980Sstevel@tonic-gate if (s1 == NULL) 1990Sstevel@tonic-gate return (output(INF, INF)); 2000Sstevel@tonic-gate for (k = C-1; k <= i; k++) { 2010Sstevel@tonic-gate for (m = 0; m < C; m++) 2020Sstevel@tonic-gate if (cmp(getl(0, n0+k-m), 2030Sstevel@tonic-gate getl(1, n1+j-m)) != 0) 2040Sstevel@tonic-gate goto cont2; 2050Sstevel@tonic-gate return (output(k-C, j-C)); 2060Sstevel@tonic-gate cont2: 2070Sstevel@tonic-gate ; 2080Sstevel@tonic-gate } 2090Sstevel@tonic-gate } 2100Sstevel@tonic-gate return (0); 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate static int 2140Sstevel@tonic-gate output(int a, int b) 2150Sstevel@tonic-gate { 2160Sstevel@tonic-gate int i; 2170Sstevel@tonic-gate char *s; 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate if (a < 0) 2200Sstevel@tonic-gate change(n0-1, 0, n1, b, "a"); 2210Sstevel@tonic-gate else if (b < 0) 2220Sstevel@tonic-gate change(n0, a, n1-1, 0, "d"); 2230Sstevel@tonic-gate else 2240Sstevel@tonic-gate change(n0, a, n1, b, "c"); 2250Sstevel@tonic-gate for (i = 0; i <= a; i++) { 2260Sstevel@tonic-gate s = getl(0, n0+i); 2270Sstevel@tonic-gate if (s == NULL) 2280Sstevel@tonic-gate break; 2290Sstevel@tonic-gate (void) printf("< %s", s); 2300Sstevel@tonic-gate clrl(0, n0+i); 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate n0 += i-1; 2330Sstevel@tonic-gate if (a >= 0 && b >= 0) 2340Sstevel@tonic-gate (void) printf("---\n"); 2350Sstevel@tonic-gate for (i = 0; i <= b; i++) { 2360Sstevel@tonic-gate s = getl(1, n1+i); 2370Sstevel@tonic-gate if (s == NULL) 2380Sstevel@tonic-gate break; 2390Sstevel@tonic-gate (void) printf("> %s", s); 2400Sstevel@tonic-gate clrl(1, n1+i); 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate diffFound = 1; 2430Sstevel@tonic-gate n1 += i-1; 2440Sstevel@tonic-gate return (1); 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate static void 2480Sstevel@tonic-gate change(long a, int b, long c, int d, char *s) 2490Sstevel@tonic-gate { 2500Sstevel@tonic-gate range(a, b); 2510Sstevel@tonic-gate (void) printf("%s", s); 2520Sstevel@tonic-gate range(c, d); 2530Sstevel@tonic-gate (void) printf("\n"); 2540Sstevel@tonic-gate } 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate static void 2570Sstevel@tonic-gate range(long a, int b) 2580Sstevel@tonic-gate { 2590Sstevel@tonic-gate if (b == INF) 2600Sstevel@tonic-gate (void) printf("%ld,$", a); 2610Sstevel@tonic-gate else if (b == 0) 2620Sstevel@tonic-gate (void) printf("%ld", a); 2630Sstevel@tonic-gate else 2640Sstevel@tonic-gate (void) printf("%ld,%ld", a, a+b); 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate static int 2680Sstevel@tonic-gate cmp(char *s, char *t) 2690Sstevel@tonic-gate { 2700Sstevel@tonic-gate if (debug) 2710Sstevel@tonic-gate (void) printf("%s:%s\n", s, t); 2720Sstevel@tonic-gate for (;;) { 2730Sstevel@tonic-gate if (bflag && isspace(*s) && isspace(*t)) { 2740Sstevel@tonic-gate while (isspace(*++s)) 2750Sstevel@tonic-gate ; 2760Sstevel@tonic-gate while (isspace(*++t)) 2770Sstevel@tonic-gate ; 2780Sstevel@tonic-gate } 2790Sstevel@tonic-gate if (*s != *t || *s == 0) 2800Sstevel@tonic-gate break; 2810Sstevel@tonic-gate s++; 2820Sstevel@tonic-gate t++; 2830Sstevel@tonic-gate } 2840Sstevel@tonic-gate return (*s-*t); 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate static FILE * 2880Sstevel@tonic-gate dopen(char *f1, char *f2) 2890Sstevel@tonic-gate { 2900Sstevel@tonic-gate FILE *f; 2910Sstevel@tonic-gate char b[PATH_MAX], *bptr, *eptr; 2920Sstevel@tonic-gate struct stat statbuf; 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate if (cmp(f1, "-") == 0) { 2950Sstevel@tonic-gate if (cmp(f2, "-") == 0) 2960Sstevel@tonic-gate error(gettext("can't do - -")); 2970Sstevel@tonic-gate else { 2980Sstevel@tonic-gate if (fstat(fileno(stdin), &statbuf) == -1) 2990Sstevel@tonic-gate error(gettext("can't access stdin")); 3000Sstevel@tonic-gate else 3010Sstevel@tonic-gate return (stdin); 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate if (stat(f1, &statbuf) == -1) 3050Sstevel@tonic-gate error(gettext("can't access %s"), f1); 3060Sstevel@tonic-gate if ((statbuf.st_mode & S_IFMT) == S_IFDIR) { 3070Sstevel@tonic-gate for (bptr = b; *bptr = *f1++; bptr++) 3080Sstevel@tonic-gate ; 3090Sstevel@tonic-gate *bptr++ = '/'; 3100Sstevel@tonic-gate for (eptr = f2; *eptr; eptr++) 3110Sstevel@tonic-gate if (*eptr == '/' && eptr[1] != 0 && eptr[1] != '/') 3120Sstevel@tonic-gate f2 = eptr+1; 3130Sstevel@tonic-gate while (*bptr++ = *f2++) 3140Sstevel@tonic-gate ; 3150Sstevel@tonic-gate f1 = b; 3160Sstevel@tonic-gate } 3170Sstevel@tonic-gate f = fopen(f1, "r"); 3180Sstevel@tonic-gate if (f == NULL) 3190Sstevel@tonic-gate error(gettext("can't open %s"), f1); 3200Sstevel@tonic-gate return (f); 3210Sstevel@tonic-gate } 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate static void 3250Sstevel@tonic-gate progerr(char *s) 3260Sstevel@tonic-gate { 3270Sstevel@tonic-gate error(gettext("program error %s"), s); 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate static void 3310Sstevel@tonic-gate error(char *err, ...) 3320Sstevel@tonic-gate { 3330Sstevel@tonic-gate va_list ap; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate va_start(ap, err); 3360Sstevel@tonic-gate (void) fprintf(stderr, "diffh: "); 3370Sstevel@tonic-gate (void) vfprintf(stderr, err, ap); 3380Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 3390Sstevel@tonic-gate va_end(ap); 3400Sstevel@tonic-gate exit(2); 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate /* stub for resychronization beyond limits of text buf */ 3440Sstevel@tonic-gate static int 3450Sstevel@tonic-gate hardsynch() 3460Sstevel@tonic-gate { 3470Sstevel@tonic-gate change(n0, INF, n1, INF, "c"); 3480Sstevel@tonic-gate (void) printf(gettext("---change record omitted\n")); 3490Sstevel@tonic-gate error(gettext("can't resynchronize")); 3500Sstevel@tonic-gate return (0); 3510Sstevel@tonic-gate } 352