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 */ 220Sstevel@tonic-gate /* 23*236Schin * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 280Sstevel@tonic-gate /* All Rights Reserved */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate /* 310Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 320Sstevel@tonic-gate * The Regents of the University of California 330Sstevel@tonic-gate * All Rights Reserved 340Sstevel@tonic-gate * 350Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 360Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 370Sstevel@tonic-gate * contributors. 380Sstevel@tonic-gate */ 390Sstevel@tonic-gate 400Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 410Sstevel@tonic-gate 420Sstevel@tonic-gate /* 430Sstevel@tonic-gate * diff - differential file comparison 440Sstevel@tonic-gate * 450Sstevel@tonic-gate * Uses an algorithm which finds 460Sstevel@tonic-gate * a pair of longest identical subsequences in the two 470Sstevel@tonic-gate * files. 480Sstevel@tonic-gate * 490Sstevel@tonic-gate * The major goal is to generate the match vector J. 500Sstevel@tonic-gate * J[i] is the index of the line in file1 corresponding 510Sstevel@tonic-gate * to line i file0. J[i] = 0 if there is no 520Sstevel@tonic-gate * such line in file1. 530Sstevel@tonic-gate * 540Sstevel@tonic-gate * Lines are hashed so as to work in core. All potential 550Sstevel@tonic-gate * matches are located by sorting the lines of each file 560Sstevel@tonic-gate * on the hash (called value). In particular, this 570Sstevel@tonic-gate * collects the equivalence classes in file1 together. 580Sstevel@tonic-gate * Subroutine equiv replaces the value of each line in 590Sstevel@tonic-gate * file0 by the index of the first element of its 600Sstevel@tonic-gate * matching equivalence in (the reordered) file1. 610Sstevel@tonic-gate * To save space equiv squeezes file1 into a single 620Sstevel@tonic-gate * array member in which the equivalence classes 630Sstevel@tonic-gate * are simply concatenated, except that their first 640Sstevel@tonic-gate * members are flagged by changing sign. 650Sstevel@tonic-gate * 660Sstevel@tonic-gate * Next the indices that point into member are unsorted into 670Sstevel@tonic-gate * array class according to the original order of file0. 680Sstevel@tonic-gate * 690Sstevel@tonic-gate * The cleverness lies in routine stone. This marches 700Sstevel@tonic-gate * through the lines of file0, developing a vector klist 710Sstevel@tonic-gate * of "k-candidates". At step i a k-candidate is a matched 720Sstevel@tonic-gate * pair of lines x,y (x in file0 y in file1) such that 730Sstevel@tonic-gate * there is a common subsequence of lenght k 740Sstevel@tonic-gate * between the first i lines of file0 and the first y 750Sstevel@tonic-gate * lines of file1, but there is no such subsequence for 760Sstevel@tonic-gate * any smaller y. x is the earliest possible mate to y 770Sstevel@tonic-gate * that occurs in such a subsequence. 780Sstevel@tonic-gate * 790Sstevel@tonic-gate * Whenever any of the members of the equivalence class of 800Sstevel@tonic-gate * lines in file1 matable to a line in file0 has serial number 810Sstevel@tonic-gate * less than the y of some k-candidate, that k-candidate 820Sstevel@tonic-gate * with the smallest such y is replaced. The new 830Sstevel@tonic-gate * k-candidate is chained (via pred) to the current 840Sstevel@tonic-gate * k-1 candidate so that the actual subsequence can 850Sstevel@tonic-gate * be recovered. When a member has serial number greater 860Sstevel@tonic-gate * that the y of all k-candidates, the klist is extended. 870Sstevel@tonic-gate * At the end, the longest subsequence is pulled out 880Sstevel@tonic-gate * and placed in the array J by unravel. 890Sstevel@tonic-gate * 900Sstevel@tonic-gate * With J in hand, the matches there recorded are 910Sstevel@tonic-gate * checked against reality to assure that no spurious 920Sstevel@tonic-gate * matches have crept in due to hashing. If they have, 930Sstevel@tonic-gate * they are broken, and "jackpot " is recorded--a harmless 940Sstevel@tonic-gate * matter except that a true match for a spuriously 950Sstevel@tonic-gate * mated line may now be unnecessarily reported as a change. 960Sstevel@tonic-gate * 970Sstevel@tonic-gate * Much of the complexity of the program comes simply 980Sstevel@tonic-gate * from trying to minimize core utilization and 990Sstevel@tonic-gate * maximize the range of doable problems by dynamically 1000Sstevel@tonic-gate * allocating what is needed and reusing what is not. 1010Sstevel@tonic-gate * The core requirements for problems larger than somewhat 1020Sstevel@tonic-gate * are (in words) 2*length(file0) + length(file1) + 1030Sstevel@tonic-gate * 3*(number of k-candidates installed), typically about 1040Sstevel@tonic-gate * 6n words for files of length n. 1050Sstevel@tonic-gate */ 1060Sstevel@tonic-gate #include <stdio.h> 1070Sstevel@tonic-gate #include <wchar.h> 1080Sstevel@tonic-gate #include <ctype.h> 1090Sstevel@tonic-gate #include <stdlib.h> 1100Sstevel@tonic-gate #include <limits.h> 1110Sstevel@tonic-gate #include <sys/types.h> 1120Sstevel@tonic-gate #include <sys/stat.h> 1130Sstevel@tonic-gate #include <sys/wait.h> 1140Sstevel@tonic-gate #include <unistd.h> 1150Sstevel@tonic-gate #include <signal.h> 1160Sstevel@tonic-gate #include <fcntl.h> 1170Sstevel@tonic-gate #include <dirent.h> 1180Sstevel@tonic-gate #include <locale.h> 1190Sstevel@tonic-gate #include <stdarg.h> 1200Sstevel@tonic-gate #include <errno.h> 1210Sstevel@tonic-gate #include <string.h> 1220Sstevel@tonic-gate #include "diff.h" 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate #define CHRTRAN(x) (iflag ? (iswupper(x) ? towlower(x) : (x)) : (x)) 1250Sstevel@tonic-gate #define NCCHRTRAN(x) (iswupper(x) ? towlower(x) : (x)) 1260Sstevel@tonic-gate #define max(a, b) ((a) < (b) ? (b) : (a)) 1270Sstevel@tonic-gate #define min(a, b) ((a) > (b) ? (b) : (a)) 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate int pref, suff; /* length of prefix and suffix */ 1300Sstevel@tonic-gate int *class; /* will be overlaid on file[0] */ 1310Sstevel@tonic-gate int *member; /* will be overlaid on file[1] */ 1320Sstevel@tonic-gate int *klist; /* will be overlaid on file[0] after class */ 1330Sstevel@tonic-gate struct cand *clist; /* merely a free storage pot for candidates */ 1340Sstevel@tonic-gate int clen = 0; 1350Sstevel@tonic-gate int *J; /* will be overlaid on class */ 1360Sstevel@tonic-gate long *ixold; /* will be overlaid on klist */ 1370Sstevel@tonic-gate long *ixnew; /* will be overlaid on file[1] */ 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate static int mbcurmax; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate static void error(const char *); 1420Sstevel@tonic-gate static void unravel(int); 1430Sstevel@tonic-gate static void check(void); 1440Sstevel@tonic-gate static void output(void); 1450Sstevel@tonic-gate static void change(int, int, int, int); 1460Sstevel@tonic-gate static void range(int, int, char *); 1470Sstevel@tonic-gate static void fetch(long *, int, int, int, char *, int); 1480Sstevel@tonic-gate static void dump_context_vec(void); 1490Sstevel@tonic-gate static void diffdir(char **); 1500Sstevel@tonic-gate static void setfile(char **, char **, char *); 1510Sstevel@tonic-gate static void scanpr(struct dir *, int, char *, char *, 1520Sstevel@tonic-gate char *, char *, char *); 1530Sstevel@tonic-gate static void only(struct dir *, int); 1540Sstevel@tonic-gate static void sort(struct line *, int); 1550Sstevel@tonic-gate static void unsort(struct line *, int, int *); 1560Sstevel@tonic-gate static void filename(char **, char **, struct stat *, char **); 1570Sstevel@tonic-gate static void prepare(int, char *); 1580Sstevel@tonic-gate static void prune(void); 1590Sstevel@tonic-gate static void equiv(struct line *, int, struct line *, int, int *); 1600Sstevel@tonic-gate static void done(void); 1610Sstevel@tonic-gate static void noroom(void); 1620Sstevel@tonic-gate static void usage(void); 1630Sstevel@tonic-gate static void initbuf(FILE *, int, long); 1640Sstevel@tonic-gate static void resetbuf(int); 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate static int stone(int *, int, int *, int *); 1670Sstevel@tonic-gate static int newcand(int, int, int); 1680Sstevel@tonic-gate static int search(int *, int, int); 1690Sstevel@tonic-gate static int skipline(int); 1700Sstevel@tonic-gate static int readhash(FILE *, int, char *); 1710Sstevel@tonic-gate static int entcmp(struct dir *, struct dir *); 1720Sstevel@tonic-gate static int compare(struct dir *); 1730Sstevel@tonic-gate static int calldiff(char *); 1740Sstevel@tonic-gate static int binary(int); 1750Sstevel@tonic-gate static int filebinary(FILE *); 1760Sstevel@tonic-gate static int isbinary(char *, int); 1770Sstevel@tonic-gate static int useless(char *); 1780Sstevel@tonic-gate static char *copytemp(char *); 1790Sstevel@tonic-gate static char *pfiletype(mode_t); 1800Sstevel@tonic-gate static struct dir *setupdir(char *); 1810Sstevel@tonic-gate static wint_t getbufwchar(int, int *); 1820Sstevel@tonic-gate static wint_t wcput(wint_t); 1830Sstevel@tonic-gate static long ftellbuf(int); 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate /* 1870Sstevel@tonic-gate * error message string constants 1880Sstevel@tonic-gate */ 1890Sstevel@tonic-gate #define BAD_MB_ERR "invalid multibyte character encountered" 1900Sstevel@tonic-gate #define NO_PROCS_ERR "no more processes" 1910Sstevel@tonic-gate #define NO_MEM_ERR "out of memory" 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate static void * 1940Sstevel@tonic-gate talloc(size_t n) 1950Sstevel@tonic-gate { 1960Sstevel@tonic-gate void *p; 1970Sstevel@tonic-gate p = malloc(n); 1980Sstevel@tonic-gate if (p == NULL) 1990Sstevel@tonic-gate noroom(); 2000Sstevel@tonic-gate return (p); 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate static void * 2040Sstevel@tonic-gate ralloc(void *p, size_t n) /* compacting reallocation */ 2050Sstevel@tonic-gate { 2060Sstevel@tonic-gate void *q; 2070Sstevel@tonic-gate #if 0 2080Sstevel@tonic-gate free(p); 2090Sstevel@tonic-gate #endif 2100Sstevel@tonic-gate q = realloc(p, n); 2110Sstevel@tonic-gate if (q == NULL) 2120Sstevel@tonic-gate noroom(); 2130Sstevel@tonic-gate return (q); 2140Sstevel@tonic-gate } 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate 217*236Schin int 2180Sstevel@tonic-gate main(int argc, char **argv) 2190Sstevel@tonic-gate { 2200Sstevel@tonic-gate int k; 2210Sstevel@tonic-gate char *argp; 2220Sstevel@tonic-gate int flag; /* option flag read by getopt() */ 2230Sstevel@tonic-gate int i, j; 2240Sstevel@tonic-gate char buf1[BUFSIZ], buf2[BUFSIZ]; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2280Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 2290Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 2300Sstevel@tonic-gate #endif 2310Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate mbcurmax = MB_CUR_MAX; 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate diffargv = argv; 2360Sstevel@tonic-gate whichtemp = 0; 2370Sstevel@tonic-gate while ((flag = getopt(argc, argv, "bitwcuefhnlrsC:D:S:U:")) != EOF) { 2380Sstevel@tonic-gate switch (flag) { 2390Sstevel@tonic-gate case 'D': 2400Sstevel@tonic-gate opt = D_IFDEF; 2410Sstevel@tonic-gate wantelses = 1; 2420Sstevel@tonic-gate ifdef1 = ""; 2430Sstevel@tonic-gate ifdef2 = optarg; 2440Sstevel@tonic-gate break; 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate case 'b': 2470Sstevel@tonic-gate bflag = 1; 2480Sstevel@tonic-gate break; 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate case 'C': 2510Sstevel@tonic-gate case 'U': 2520Sstevel@tonic-gate opt = D_CONTEXT; 2530Sstevel@tonic-gate argp = optarg; 2540Sstevel@tonic-gate context = 0; 2550Sstevel@tonic-gate while (*argp >= '0' && *argp <= '9') 2560Sstevel@tonic-gate context *= 10, context += *argp++ - '0'; 2570Sstevel@tonic-gate if (*argp) 2580Sstevel@tonic-gate error(gettext("use [ -C num | -U num ]")); 2590Sstevel@tonic-gate if (flag == 'U') 2600Sstevel@tonic-gate uflag++; 2610Sstevel@tonic-gate else 2620Sstevel@tonic-gate uflag = 0; 2630Sstevel@tonic-gate break; 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate case 'c': 2660Sstevel@tonic-gate case 'u': 2670Sstevel@tonic-gate opt = D_CONTEXT; 2680Sstevel@tonic-gate context = 3; 2690Sstevel@tonic-gate if (flag == 'u') 2700Sstevel@tonic-gate uflag++; 2710Sstevel@tonic-gate else 2720Sstevel@tonic-gate uflag = 0; 2730Sstevel@tonic-gate break; 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate case 'e': 2760Sstevel@tonic-gate opt = D_EDIT; 2770Sstevel@tonic-gate break; 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate case 'f': 2800Sstevel@tonic-gate opt = D_REVERSE; 2810Sstevel@tonic-gate break; 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate case 'h': 2840Sstevel@tonic-gate hflag++; 2850Sstevel@tonic-gate break; 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate case 'i': 2880Sstevel@tonic-gate iflag = 1; 2890Sstevel@tonic-gate break; 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate case 'l': 2920Sstevel@tonic-gate lflag = 1; 2930Sstevel@tonic-gate break; 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate case 'n': 2960Sstevel@tonic-gate opt = D_NREVERSE; 2970Sstevel@tonic-gate break; 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate case 'r': 3000Sstevel@tonic-gate rflag = 1; 3010Sstevel@tonic-gate break; 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate case 'S': 3040Sstevel@tonic-gate (void) strcpy(start, optarg); 3050Sstevel@tonic-gate break; 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate case 's': 3080Sstevel@tonic-gate sflag = 1; 3090Sstevel@tonic-gate break; 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate case 't': 3120Sstevel@tonic-gate tflag = 1; 3130Sstevel@tonic-gate break; 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate case 'w': 3160Sstevel@tonic-gate wflag = 1; 3170Sstevel@tonic-gate break; 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate case '?': 3200Sstevel@tonic-gate usage(); 3210Sstevel@tonic-gate break; 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate default: 3240Sstevel@tonic-gate /* Not sure how it would get here, but just in case */ 3250Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 3260Sstevel@tonic-gate (void) fprintf(stderr, 3270Sstevel@tonic-gate gettext("invalid option -%c\n"), flag); 3280Sstevel@tonic-gate usage(); 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate argc -= optind; 3330Sstevel@tonic-gate argv = &argv[optind]; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate if (opt != D_CONTEXT && uflag) 3360Sstevel@tonic-gate uflag = 0; 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate if (argc != 2) 3390Sstevel@tonic-gate error(gettext("two filename arguments required")); 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate file1 = argv[0]; 3420Sstevel@tonic-gate file2 = argv[1]; 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate if (hflag) { 3450Sstevel@tonic-gate if (opt) { 3460Sstevel@tonic-gate error( 3470Sstevel@tonic-gate gettext("-h doesn't support -e, -f, -n, -c, or -I")); 3480Sstevel@tonic-gate } else { 3490Sstevel@tonic-gate diffargv[0] = "diffh"; 3500Sstevel@tonic-gate (void) execv(diffh, diffargv); 3510Sstevel@tonic-gate (void) fprintf(stderr, "diffh: "); 3520Sstevel@tonic-gate perror(diffh); 3530Sstevel@tonic-gate status = 2; 3540Sstevel@tonic-gate done(); 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate if (strcmp(file1, "-") == 0) { 3600Sstevel@tonic-gate if (fstat(fileno(stdin), &stb1) == 0) 3610Sstevel@tonic-gate stb1.st_mode = S_IFREG; 3620Sstevel@tonic-gate else { 3630Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 3640Sstevel@tonic-gate perror("stdin"); 3650Sstevel@tonic-gate done(); 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate } else if (stat(file1, &stb1) < 0) { 3680Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 3690Sstevel@tonic-gate perror(file1); 3700Sstevel@tonic-gate done(); 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate if (strcmp(file2, "-") == 0) { 3740Sstevel@tonic-gate if (strcmp(file1, "-") == 0) 3750Sstevel@tonic-gate error(gettext("cannot specify - -")); 3760Sstevel@tonic-gate else { 3770Sstevel@tonic-gate if (fstat(fileno(stdin), &stb2) == 0) 3780Sstevel@tonic-gate stb2.st_mode = S_IFREG; 3790Sstevel@tonic-gate else { 3800Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 3810Sstevel@tonic-gate perror("stdin"); 3820Sstevel@tonic-gate done(); 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate } 3850Sstevel@tonic-gate } else if (stat(file2, &stb2) < 0) { 3860Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 3870Sstevel@tonic-gate perror(file2); 3880Sstevel@tonic-gate done(); 3890Sstevel@tonic-gate } 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate if ((stb1.st_mode & S_IFMT) == S_IFDIR && 3920Sstevel@tonic-gate (stb2.st_mode & S_IFMT) == S_IFDIR) { 3930Sstevel@tonic-gate diffdir(argv); 3940Sstevel@tonic-gate done(); 3950Sstevel@tonic-gate } 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate filename(&file1, &file2, &stb1, &input_file1); 3980Sstevel@tonic-gate filename(&file2, &file1, &stb2, &input_file2); 3990Sstevel@tonic-gate if ((input[0] = fopen(file1, "r")) == NULL) { 4000Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 4010Sstevel@tonic-gate perror(file1); 4020Sstevel@tonic-gate status = 2; 4030Sstevel@tonic-gate done(); 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate initbuf(input[0], 0, 0); 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate if ((input[1] = fopen(file2, "r")) == NULL) { 4080Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 4090Sstevel@tonic-gate perror(file2); 4100Sstevel@tonic-gate status = 2; 4110Sstevel@tonic-gate done(); 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate initbuf(input[1], 1, 0); 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate if (stb1.st_size != stb2.st_size) 4160Sstevel@tonic-gate goto notsame; 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate for (;;) { 4190Sstevel@tonic-gate i = fread(buf1, 1, BUFSIZ, input[0]); 4200Sstevel@tonic-gate j = fread(buf2, 1, BUFSIZ, input[1]); 4210Sstevel@tonic-gate if (ferror(input[0]) || ferror(input[1])) { 4220Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 4230Sstevel@tonic-gate (void) fprintf(stderr, gettext("Error reading ")); 4240Sstevel@tonic-gate perror(ferror(input[0])? file1:file2); 4250Sstevel@tonic-gate (void) fclose(input[0]); 4260Sstevel@tonic-gate (void) fclose(input[1]); 4270Sstevel@tonic-gate status = 2; 4280Sstevel@tonic-gate done(); 4290Sstevel@tonic-gate } 4300Sstevel@tonic-gate if (i != j) 4310Sstevel@tonic-gate goto notsame; 4320Sstevel@tonic-gate if (i == 0 && j == 0) { 4330Sstevel@tonic-gate /* files are the same; diff -D needs to print one */ 4340Sstevel@tonic-gate if (opt == D_IFDEF) { 4350Sstevel@tonic-gate rewind(input[0]); 4360Sstevel@tonic-gate while (i = fread(buf1, 1, BUFSIZ, input[0])) 4370Sstevel@tonic-gate (void) fwrite(buf1, 1, i, stdout); 4380Sstevel@tonic-gate } 4390Sstevel@tonic-gate (void) fclose(input[0]); 4400Sstevel@tonic-gate (void) fclose(input[1]); 4410Sstevel@tonic-gate status = 0; 4420Sstevel@tonic-gate goto same; /* files don't differ */ 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate for (j = 0; j < i; j++) 4450Sstevel@tonic-gate if (buf1[j] != buf2[j]) 4460Sstevel@tonic-gate goto notsame; 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate notsame: 4500Sstevel@tonic-gate status = 1; 4510Sstevel@tonic-gate if (filebinary(input[0]) || filebinary(input[1])) { 4520Sstevel@tonic-gate if (ferror(input[0]) || ferror(input[1])) { 4530Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 4540Sstevel@tonic-gate (void) fprintf(stderr, gettext("Error reading ")); 4550Sstevel@tonic-gate perror(ferror(input[0])? file1:file2); 4560Sstevel@tonic-gate (void) fclose(input[0]); 4570Sstevel@tonic-gate (void) fclose(input[1]); 4580Sstevel@tonic-gate status = 2; 4590Sstevel@tonic-gate done(); 4600Sstevel@tonic-gate } 4610Sstevel@tonic-gate (void) printf(gettext("Binary files %s and %s differ\n"), 4620Sstevel@tonic-gate file1, file2); 4630Sstevel@tonic-gate (void) fclose(input[0]); 4640Sstevel@tonic-gate (void) fclose(input[1]); 4650Sstevel@tonic-gate done(); 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate prepare(0, file1); 4680Sstevel@tonic-gate prepare(1, file2); 4690Sstevel@tonic-gate prune(); 4700Sstevel@tonic-gate sort(sfile[0], slen[0]); 4710Sstevel@tonic-gate sort(sfile[1], slen[1]); 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate member = (int *)file[1]; 4740Sstevel@tonic-gate equiv(sfile[0], slen[0], sfile[1], slen[1], member); 4750Sstevel@tonic-gate member = (int *)ralloc((void *)member, (slen[1] + 2) * sizeof (int)); 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate class = (int *)file[0]; 4780Sstevel@tonic-gate unsort(sfile[0], slen[0], class); 4790Sstevel@tonic-gate class = (int *)ralloc((void *)class, (slen[0] + 2) * sizeof (int)); 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate klist = (int *)talloc((slen[0] + 2) * sizeof (int)); 4820Sstevel@tonic-gate clist = (struct cand *)talloc(sizeof (cand)); 4830Sstevel@tonic-gate k = stone(class, slen[0], member, klist); 4840Sstevel@tonic-gate free((void *)member); 4850Sstevel@tonic-gate free((void *)class); 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate J = (int *)talloc((len[0] + 2) * sizeof (int)); 4880Sstevel@tonic-gate unravel(klist[k]); 4890Sstevel@tonic-gate free((char *)clist); 4900Sstevel@tonic-gate free((char *)klist); 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate ixold = (long *)talloc((len[0] + 2) * sizeof (long)); 4930Sstevel@tonic-gate ixnew = (long *)talloc((len[1] + 2) * sizeof (long)); 4940Sstevel@tonic-gate check(); 4950Sstevel@tonic-gate output(); 4960Sstevel@tonic-gate status = anychange; 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate same: 4990Sstevel@tonic-gate if (opt == D_CONTEXT && anychange == 0) 5000Sstevel@tonic-gate (void) printf(gettext("No differences encountered\n")); 5010Sstevel@tonic-gate done(); 5020Sstevel@tonic-gate /*NOTREACHED*/ 503*236Schin return (0); 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate static int 5070Sstevel@tonic-gate stone(int *a, int n, int *b, int *c) 5080Sstevel@tonic-gate { 5090Sstevel@tonic-gate int i, k, y; 5100Sstevel@tonic-gate int j, l; 5110Sstevel@tonic-gate int oldc, tc; 5120Sstevel@tonic-gate int oldl; 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate k = 0; 5150Sstevel@tonic-gate c[0] = newcand(0, 0, 0); 5160Sstevel@tonic-gate for (i = 1; i <= n; i++) { 5170Sstevel@tonic-gate j = a[i]; 5180Sstevel@tonic-gate if (j == 0) 5190Sstevel@tonic-gate continue; 5200Sstevel@tonic-gate y = -b[j]; 5210Sstevel@tonic-gate oldl = 0; 5220Sstevel@tonic-gate oldc = c[0]; 5230Sstevel@tonic-gate do { 5240Sstevel@tonic-gate if (y <= clist[oldc].y) 5250Sstevel@tonic-gate continue; 5260Sstevel@tonic-gate l = search(c, k, y); 5270Sstevel@tonic-gate if (l != oldl+1) 5280Sstevel@tonic-gate oldc = c[l-1]; 5290Sstevel@tonic-gate if (l <= k) { 5300Sstevel@tonic-gate if (clist[c[l]].y <= y) 5310Sstevel@tonic-gate continue; 5320Sstevel@tonic-gate tc = c[l]; 5330Sstevel@tonic-gate c[l] = newcand(i, y, oldc); 5340Sstevel@tonic-gate oldc = tc; 5350Sstevel@tonic-gate oldl = l; 5360Sstevel@tonic-gate } else { 5370Sstevel@tonic-gate c[l] = newcand(i, y, oldc); 5380Sstevel@tonic-gate k++; 5390Sstevel@tonic-gate break; 5400Sstevel@tonic-gate } 5410Sstevel@tonic-gate } while ((y = b[++j]) > 0); 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate return (k); 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate static int 5470Sstevel@tonic-gate newcand(int x, int y, int pred) 5480Sstevel@tonic-gate { 5490Sstevel@tonic-gate struct cand *q; 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate clist = (struct cand *)ralloc((void *)clist, ++clen * sizeof (cand)); 5520Sstevel@tonic-gate q = clist + clen -1; 5530Sstevel@tonic-gate q->x = x; 5540Sstevel@tonic-gate q->y = y; 5550Sstevel@tonic-gate q->pred = pred; 5560Sstevel@tonic-gate return (clen - 1); 5570Sstevel@tonic-gate } 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate static int 5600Sstevel@tonic-gate search(int *c, int k, int y) 5610Sstevel@tonic-gate { 5620Sstevel@tonic-gate int i, j, l; 5630Sstevel@tonic-gate int t; 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate if (clist[c[k]].y < y) /* quick look for typical case */ 5660Sstevel@tonic-gate return (k + 1); 5670Sstevel@tonic-gate i = 0; 5680Sstevel@tonic-gate j = k+1; 5690Sstevel@tonic-gate while ((l = (i + j) / 2) > i) { 5700Sstevel@tonic-gate t = clist[c[l]].y; 5710Sstevel@tonic-gate if (t > y) 5720Sstevel@tonic-gate j = l; 5730Sstevel@tonic-gate else if (t < y) 5740Sstevel@tonic-gate i = l; 5750Sstevel@tonic-gate else 5760Sstevel@tonic-gate return (l); 5770Sstevel@tonic-gate } 5780Sstevel@tonic-gate return (l + 1); 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate static void 5820Sstevel@tonic-gate unravel(int p) 5830Sstevel@tonic-gate { 5840Sstevel@tonic-gate int i; 5850Sstevel@tonic-gate struct cand *q; 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate for (i = 0; i <= len[0]; i++) 5880Sstevel@tonic-gate J[i] = i <= pref ? i : 5890Sstevel@tonic-gate i > len[0] - suff ? i + len[1] - len[0]: 5900Sstevel@tonic-gate 0; 5910Sstevel@tonic-gate for (q = clist + p; q->y != 0; q = clist + q->pred) 5920Sstevel@tonic-gate J[q->x + pref] = q->y + pref; 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate /* 5960Sstevel@tonic-gate * check does double duty: 5970Sstevel@tonic-gate * 1. ferret out any fortuitous correspondences due to confounding by 5980Sstevel@tonic-gate * hashing (which result in "jackpot") 5990Sstevel@tonic-gate * 2. collect random access indexes to the two files 6000Sstevel@tonic-gate */ 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate static void 6030Sstevel@tonic-gate check(void) 6040Sstevel@tonic-gate { 6050Sstevel@tonic-gate wint_t c, d; 6060Sstevel@tonic-gate int i, j; 6070Sstevel@tonic-gate /* int jackpot; */ 6080Sstevel@tonic-gate int mlen; 6090Sstevel@tonic-gate long ctold, ctnew; 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate resetbuf(0); 6120Sstevel@tonic-gate resetbuf(1); 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate j = 1; 6150Sstevel@tonic-gate ixold[0] = ixnew[0] = 0; 6160Sstevel@tonic-gate /* jackpot = 0; */ 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate /* 6190Sstevel@tonic-gate * ctold and ctnew are byte positions within the file (suitable for 6200Sstevel@tonic-gate * lseek()). After we get a character with getwc(), instead of 6210Sstevel@tonic-gate * just incrementing the byte position by 1, we have to determine 6220Sstevel@tonic-gate * how many bytes the character actually is. This is the reason for 6230Sstevel@tonic-gate * the wctomb() calls here and in skipline(). 6240Sstevel@tonic-gate */ 6250Sstevel@tonic-gate ctold = ctnew = 0; 6260Sstevel@tonic-gate for (i = 1; i <= len[0]; i++) { 6270Sstevel@tonic-gate if (J[i] == 0) { 6280Sstevel@tonic-gate ixold[i] = ctold += skipline(0); 6290Sstevel@tonic-gate continue; 6300Sstevel@tonic-gate } 6310Sstevel@tonic-gate while (j < J[i]) { 6320Sstevel@tonic-gate ixnew[j] = ctnew += skipline(1); 6330Sstevel@tonic-gate j++; 6340Sstevel@tonic-gate } 6350Sstevel@tonic-gate if (bflag || wflag || iflag) { 6360Sstevel@tonic-gate for (;;) { 6370Sstevel@tonic-gate c = getbufwchar(0, &mlen); 6380Sstevel@tonic-gate ctold += mlen; 6390Sstevel@tonic-gate d = getbufwchar(1, &mlen); 6400Sstevel@tonic-gate ctnew += mlen; 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate if (bflag && iswspace(c) && iswspace(d)) { 6430Sstevel@tonic-gate while (iswspace(c)) { 6440Sstevel@tonic-gate if (c == '\n' || c == WEOF) 6450Sstevel@tonic-gate break; 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate c = getbufwchar(0, &mlen); 6480Sstevel@tonic-gate ctold += mlen; 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate while (iswspace(d)) { 6510Sstevel@tonic-gate if (d == '\n' || d == WEOF) 6520Sstevel@tonic-gate break; 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate d = getbufwchar(1, &mlen); 6550Sstevel@tonic-gate ctnew += mlen; 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate } else if (wflag) { 6580Sstevel@tonic-gate while (iswspace(c) && c != '\n') { 6590Sstevel@tonic-gate c = getbufwchar(0, &mlen); 6600Sstevel@tonic-gate ctold += mlen; 6610Sstevel@tonic-gate } 6620Sstevel@tonic-gate while (iswspace(d) && d != '\n') { 6630Sstevel@tonic-gate d = getbufwchar(1, &mlen); 6640Sstevel@tonic-gate ctnew += mlen; 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate } 6670Sstevel@tonic-gate if (c == WEOF || d == WEOF) { 6680Sstevel@tonic-gate if (c != d) { 6690Sstevel@tonic-gate /* jackpot++; */ 6700Sstevel@tonic-gate J[i] = 0; 6710Sstevel@tonic-gate if (c != '\n' && c != WEOF) 6720Sstevel@tonic-gate ctold += skipline(0); 6730Sstevel@tonic-gate if (d != '\n' && d != WEOF) 6740Sstevel@tonic-gate ctnew += skipline(1); 6750Sstevel@tonic-gate break; 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate break; 6780Sstevel@tonic-gate } else { 6790Sstevel@tonic-gate if (CHRTRAN(c) != CHRTRAN(d)) { 6800Sstevel@tonic-gate /* jackpot++; */ 6810Sstevel@tonic-gate J[i] = 0; 6820Sstevel@tonic-gate if (c != '\n') 6830Sstevel@tonic-gate ctold += skipline(0); 6840Sstevel@tonic-gate if (d != '\n') 6850Sstevel@tonic-gate ctnew += skipline(1); 6860Sstevel@tonic-gate break; 6870Sstevel@tonic-gate } 6880Sstevel@tonic-gate if (c == '\n') 6890Sstevel@tonic-gate break; 6900Sstevel@tonic-gate } 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate } else { 6930Sstevel@tonic-gate for (;;) { 6940Sstevel@tonic-gate c = getbufwchar(0, &mlen); 6950Sstevel@tonic-gate ctold += mlen; 6960Sstevel@tonic-gate d = getbufwchar(1, &mlen); 6970Sstevel@tonic-gate ctnew += mlen; 6980Sstevel@tonic-gate if (c != d) { 6990Sstevel@tonic-gate /* jackpot++; */ 7000Sstevel@tonic-gate J[i] = 0; 7010Sstevel@tonic-gate if (c != '\n' && c != WEOF) 7020Sstevel@tonic-gate ctold += skipline(0); 7030Sstevel@tonic-gate if (d != '\n' && d != WEOF) 7040Sstevel@tonic-gate ctnew += skipline(1); 7050Sstevel@tonic-gate break; 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate if (c == '\n' || c == WEOF) 7080Sstevel@tonic-gate break; 7090Sstevel@tonic-gate } 7100Sstevel@tonic-gate } 7110Sstevel@tonic-gate ixold[i] = ctold; 7120Sstevel@tonic-gate ixnew[j] = ctnew; 7130Sstevel@tonic-gate j++; 7140Sstevel@tonic-gate } 7150Sstevel@tonic-gate for (; j <= len[1]; j++) { 7160Sstevel@tonic-gate ixnew[j] = ctnew += skipline(1); 7170Sstevel@tonic-gate } 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate /* if(jackpot) */ 7200Sstevel@tonic-gate /* fprintf(stderr, "diff: jackpot\n"); */ 7210Sstevel@tonic-gate } 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate static int 7240Sstevel@tonic-gate skipline(int f) 7250Sstevel@tonic-gate { 7260Sstevel@tonic-gate int i; 7270Sstevel@tonic-gate wint_t c; 7280Sstevel@tonic-gate int mlen; 7290Sstevel@tonic-gate 7300Sstevel@tonic-gate for (i = 1; c = getbufwchar(f, &mlen); ) { 7310Sstevel@tonic-gate if (c == '\n' || c == WEOF) 7320Sstevel@tonic-gate return (i); 7330Sstevel@tonic-gate i += mlen; 7340Sstevel@tonic-gate } 7350Sstevel@tonic-gate return (i); 7360Sstevel@tonic-gate } 7370Sstevel@tonic-gate 7380Sstevel@tonic-gate static void 7390Sstevel@tonic-gate output(void) 7400Sstevel@tonic-gate { 7410Sstevel@tonic-gate int m; 7420Sstevel@tonic-gate wint_t wc; 7430Sstevel@tonic-gate int i0, i1, j1; 7440Sstevel@tonic-gate int j0; 7450Sstevel@tonic-gate int mlen; 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate resetbuf(0); 7480Sstevel@tonic-gate resetbuf(1); 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate m = len[0]; 7510Sstevel@tonic-gate J[0] = 0; 7520Sstevel@tonic-gate J[m + 1] = len[1] + 1; 7530Sstevel@tonic-gate if (opt != D_EDIT) 7540Sstevel@tonic-gate for (i0 = 1; i0 <= m; i0 = i1+1) { 7550Sstevel@tonic-gate while (i0 <= m && J[i0] == J[i0 - 1] + 1) 7560Sstevel@tonic-gate i0++; 7570Sstevel@tonic-gate j0 = J[i0 - 1] + 1; 7580Sstevel@tonic-gate i1 = i0 - 1; 7590Sstevel@tonic-gate while (i1 < m && J[i1 + 1] == 0) 7600Sstevel@tonic-gate i1++; 7610Sstevel@tonic-gate j1 = J[i1 + 1] - 1; 7620Sstevel@tonic-gate J[i1] = j1; 7630Sstevel@tonic-gate change(i0, i1, j0, j1); 7640Sstevel@tonic-gate } else for (i0 = m; i0 >= 1; i0 = i1 - 1) { 7650Sstevel@tonic-gate while (i0 >= 1 && J[i0] == J[i0 + 1] - 1 && J[i0] != 0) 7660Sstevel@tonic-gate i0--; 7670Sstevel@tonic-gate j0 = J[i0 + 1] - 1; 7680Sstevel@tonic-gate i1 = i0 + 1; 7690Sstevel@tonic-gate while (i1 > 1 && J[i1 - 1] == 0) 7700Sstevel@tonic-gate i1--; 7710Sstevel@tonic-gate j1 = J[i1 - 1] + 1; 7720Sstevel@tonic-gate J[i1] = j1; 7730Sstevel@tonic-gate change(i1, i0, j1, j0); 7740Sstevel@tonic-gate } 7750Sstevel@tonic-gate if (m == 0) 7760Sstevel@tonic-gate change(1, 0, 1, len[1]); 7770Sstevel@tonic-gate if (opt == D_IFDEF) { 7780Sstevel@tonic-gate for (;;) { 7790Sstevel@tonic-gate wc = getbufwchar(0, &mlen); 7800Sstevel@tonic-gate if (wc == WEOF) 7810Sstevel@tonic-gate return; 7820Sstevel@tonic-gate (void) wcput(wc); 7830Sstevel@tonic-gate } 7840Sstevel@tonic-gate } 7850Sstevel@tonic-gate if (anychange && opt == D_CONTEXT) 7860Sstevel@tonic-gate dump_context_vec(); 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate /* 7910Sstevel@tonic-gate * indicate that there is a difference between lines a and b of the from file 7920Sstevel@tonic-gate * to get to lines c to d of the to file. 7930Sstevel@tonic-gate * If a is greater then b then there are no lines in the from file involved 7940Sstevel@tonic-gate * and this means that there were lines appended (beginning at b). 7950Sstevel@tonic-gate * If c is greater than d then there are lines missing from the to file. 7960Sstevel@tonic-gate */ 7970Sstevel@tonic-gate static void 7980Sstevel@tonic-gate change(int a, int b, int c, int d) 7990Sstevel@tonic-gate { 8000Sstevel@tonic-gate char time_buf[BUFSIZ]; 8010Sstevel@tonic-gate char *dcmsg; 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate if (opt != D_IFDEF && a > b && c > d) 8040Sstevel@tonic-gate return; 8050Sstevel@tonic-gate if (anychange == 0) { 8060Sstevel@tonic-gate anychange = 1; 8070Sstevel@tonic-gate if (opt == D_CONTEXT) { 8080Sstevel@tonic-gate /* 8090Sstevel@tonic-gate * TRANSLATION_NOTE_FOR_DC 8100Sstevel@tonic-gate * This message is the format of file 8110Sstevel@tonic-gate * timestamps written with the -C and 8120Sstevel@tonic-gate * -c options. 8130Sstevel@tonic-gate * %a -- locale's abbreviated weekday name 8140Sstevel@tonic-gate * %b -- locale's abbreviated month name 8150Sstevel@tonic-gate * %e -- day of month [1,31] 8160Sstevel@tonic-gate * %T -- Time as %H:%M:%S 8170Sstevel@tonic-gate * %Y -- Year, including the century 8180Sstevel@tonic-gate */ 8190Sstevel@tonic-gate dcmsg = dcgettext(NULL, "%a %b %e %T %Y", LC_TIME); 8200Sstevel@tonic-gate (void) cftime(time_buf, dcmsg, &stb1.st_mtime); 8210Sstevel@tonic-gate if (uflag) 8220Sstevel@tonic-gate (void) printf("--- %s %s\n", input_file1, 8230Sstevel@tonic-gate time_buf); 8240Sstevel@tonic-gate else 8250Sstevel@tonic-gate (void) printf("*** %s %s\n", input_file1, 8260Sstevel@tonic-gate time_buf); 8270Sstevel@tonic-gate (void) cftime(time_buf, dcmsg, &stb2.st_mtime); 8280Sstevel@tonic-gate if (uflag) 8290Sstevel@tonic-gate (void) printf("+++ %s %s\n", input_file2, 8300Sstevel@tonic-gate time_buf); 8310Sstevel@tonic-gate else 8320Sstevel@tonic-gate (void) printf("--- %s %s\n", input_file2, 8330Sstevel@tonic-gate time_buf); 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate context_vec_start = (struct context_vec *) 8360Sstevel@tonic-gate malloc(MAX_CONTEXT * 8370Sstevel@tonic-gate sizeof (struct context_vec)); 8380Sstevel@tonic-gate if (context_vec_start == NULL) 8390Sstevel@tonic-gate error(gettext(NO_MEM_ERR)); 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate context_vec_end = context_vec_start + (MAX_CONTEXT - 1); 8420Sstevel@tonic-gate context_vec_ptr = context_vec_start - 1; 8430Sstevel@tonic-gate } 8440Sstevel@tonic-gate } 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate if (opt == D_CONTEXT) { 8470Sstevel@tonic-gate /* 8480Sstevel@tonic-gate * if this new change is within 'context' lines of 8490Sstevel@tonic-gate * the previous change, just add it to the change 8500Sstevel@tonic-gate * record. If the record is full or if this 8510Sstevel@tonic-gate * change is more than 'context' lines from the previous 8520Sstevel@tonic-gate * change, dump the record, reset it & add the new change. 8530Sstevel@tonic-gate */ 8540Sstevel@tonic-gate if (context_vec_ptr >= context_vec_end || 8550Sstevel@tonic-gate (context_vec_ptr >= context_vec_start && 8560Sstevel@tonic-gate a > (context_vec_ptr->b + 2 * context) && 8570Sstevel@tonic-gate c > (context_vec_ptr->d + 2 * context))) 8580Sstevel@tonic-gate dump_context_vec(); 8590Sstevel@tonic-gate 8600Sstevel@tonic-gate context_vec_ptr++; 8610Sstevel@tonic-gate context_vec_ptr->a = a; 8620Sstevel@tonic-gate context_vec_ptr->b = b; 8630Sstevel@tonic-gate context_vec_ptr->c = c; 8640Sstevel@tonic-gate context_vec_ptr->d = d; 8650Sstevel@tonic-gate return; 8660Sstevel@tonic-gate } 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate switch (opt) { 8690Sstevel@tonic-gate case D_NORMAL: 8700Sstevel@tonic-gate case D_EDIT: 8710Sstevel@tonic-gate range(a, b, ","); 8720Sstevel@tonic-gate (void) putchar(a > b ? 'a' : c > d ? 'd' : 'c'); 8730Sstevel@tonic-gate if (opt == D_NORMAL) range(c, d, ","); 8740Sstevel@tonic-gate (void) printf("\n"); 8750Sstevel@tonic-gate break; 8760Sstevel@tonic-gate case D_REVERSE: 8770Sstevel@tonic-gate (void) putchar(a > b ? 'a' : c > d ? 'd' : 'c'); 8780Sstevel@tonic-gate range(a, b, " "); 8790Sstevel@tonic-gate (void) printf("\n"); 8800Sstevel@tonic-gate break; 8810Sstevel@tonic-gate case D_NREVERSE: 8820Sstevel@tonic-gate if (a > b) 8830Sstevel@tonic-gate (void) printf("a%d %d\n", b, d - c + 1); 8840Sstevel@tonic-gate else { 8850Sstevel@tonic-gate (void) printf("d%d %d\n", a, b - a + 1); 8860Sstevel@tonic-gate if (!(c > d)) 8870Sstevel@tonic-gate /* add changed lines */ 8880Sstevel@tonic-gate (void) printf("a%d %d\n", b, d - c + 1); 8890Sstevel@tonic-gate } 8900Sstevel@tonic-gate break; 8910Sstevel@tonic-gate } 8920Sstevel@tonic-gate if (opt == D_NORMAL || opt == D_IFDEF) { 8930Sstevel@tonic-gate fetch(ixold, a, b, 0, "< ", 1); 8940Sstevel@tonic-gate if (a <= b && c <= d && opt == D_NORMAL) 8950Sstevel@tonic-gate (void) prints("---\n"); 8960Sstevel@tonic-gate } 8970Sstevel@tonic-gate fetch(ixnew, c, d, 1, opt == D_NORMAL?"> ":empty, 0); 8980Sstevel@tonic-gate if ((opt == D_EDIT || opt == D_REVERSE) && c <= d) 8990Sstevel@tonic-gate (void) prints(".\n"); 9000Sstevel@tonic-gate if (inifdef) { 9010Sstevel@tonic-gate (void) fprintf(stdout, "#endif /* %s */\n", endifname); 9020Sstevel@tonic-gate inifdef = 0; 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate } 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate static void 9070Sstevel@tonic-gate range(int a, int b, char *separator) 9080Sstevel@tonic-gate { 9090Sstevel@tonic-gate (void) printf("%d", a > b ? b : a); 9100Sstevel@tonic-gate if (a < b) { 9110Sstevel@tonic-gate (void) printf("%s%d", separator, b); 9120Sstevel@tonic-gate } 9130Sstevel@tonic-gate } 9140Sstevel@tonic-gate 9150Sstevel@tonic-gate static void 9160Sstevel@tonic-gate fetch(long *f, int a, int b, int filen, char *s, int oldfile) 9170Sstevel@tonic-gate { 9180Sstevel@tonic-gate int i; 9190Sstevel@tonic-gate int col; 9200Sstevel@tonic-gate int nc; 9210Sstevel@tonic-gate int mlen = 0; 9220Sstevel@tonic-gate wint_t ch; 9230Sstevel@tonic-gate FILE *lb; 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate lb = input[filen]; 9260Sstevel@tonic-gate /* 9270Sstevel@tonic-gate * When doing #ifdef's, copy down to current line 9280Sstevel@tonic-gate * if this is the first file, so that stuff makes it to output. 9290Sstevel@tonic-gate */ 9300Sstevel@tonic-gate if (opt == D_IFDEF && oldfile) { 9310Sstevel@tonic-gate long curpos = ftellbuf(filen); 9320Sstevel@tonic-gate /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ 9330Sstevel@tonic-gate nc = f[(a > b) ? b : (a - 1) ] - curpos; 9340Sstevel@tonic-gate for (i = 0; i < nc; i += mlen) { 9350Sstevel@tonic-gate ch = getbufwchar(filen, &mlen); 9360Sstevel@tonic-gate if (ch == WEOF) { 9370Sstevel@tonic-gate (void) putchar('\n'); 9380Sstevel@tonic-gate break; 9390Sstevel@tonic-gate } else { 9400Sstevel@tonic-gate (void) wcput(ch); 9410Sstevel@tonic-gate } 9420Sstevel@tonic-gate } 9430Sstevel@tonic-gate } 9440Sstevel@tonic-gate if (a > b) 9450Sstevel@tonic-gate return; 9460Sstevel@tonic-gate if (opt == D_IFDEF) { 9470Sstevel@tonic-gate int oneflag = (*ifdef1 != '\0') != (*ifdef2 != '\0'); 9480Sstevel@tonic-gate if (inifdef) 9490Sstevel@tonic-gate (void) fprintf(stdout, "#else /* %s%s */\n", 9500Sstevel@tonic-gate oneflag && oldfile == 1 ? "!" : "", ifdef2); 9510Sstevel@tonic-gate else { 9520Sstevel@tonic-gate if (oneflag) { 9530Sstevel@tonic-gate /* There was only one ifdef given */ 9540Sstevel@tonic-gate endifname = ifdef2; 9550Sstevel@tonic-gate if (oldfile) 9560Sstevel@tonic-gate (void) fprintf(stdout, 9570Sstevel@tonic-gate "#ifndef %s\n", endifname); 9580Sstevel@tonic-gate else 9590Sstevel@tonic-gate (void) fprintf(stdout, 9600Sstevel@tonic-gate "#ifdef %s\n", endifname); 9610Sstevel@tonic-gate } else { 9620Sstevel@tonic-gate endifname = oldfile ? ifdef1 : ifdef2; 9630Sstevel@tonic-gate (void) fprintf(stdout, 9640Sstevel@tonic-gate "#ifdef %s\n", endifname); 9650Sstevel@tonic-gate } 9660Sstevel@tonic-gate } 9670Sstevel@tonic-gate inifdef = 1 + oldfile; 9680Sstevel@tonic-gate } 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate for (i = a; i <= b; i++) { 9710Sstevel@tonic-gate (void) fseek(lb, f[i - 1], SEEK_SET); 9720Sstevel@tonic-gate initbuf(lb, filen, f[i - 1]); 9730Sstevel@tonic-gate if (opt != D_IFDEF) 9740Sstevel@tonic-gate (void) prints(s); 9750Sstevel@tonic-gate col = 0; 9760Sstevel@tonic-gate while (ch = getbufwchar(filen, &mlen)) { 9770Sstevel@tonic-gate if (ch != '\n' && ch != WEOF) { 9780Sstevel@tonic-gate if (ch == '\t' && tflag) 9790Sstevel@tonic-gate do 9800Sstevel@tonic-gate (void) putchar(' '); 9810Sstevel@tonic-gate while (++col & 7); 9820Sstevel@tonic-gate else { 9830Sstevel@tonic-gate (void) wcput(ch); 9840Sstevel@tonic-gate col++; 9850Sstevel@tonic-gate } 9860Sstevel@tonic-gate } else 9870Sstevel@tonic-gate break; 9880Sstevel@tonic-gate } 9890Sstevel@tonic-gate (void) putchar('\n'); 9900Sstevel@tonic-gate } 9910Sstevel@tonic-gate } 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate /* 9940Sstevel@tonic-gate * hashing has the effect of 9950Sstevel@tonic-gate * arranging line in 7-bit bytes and then 9960Sstevel@tonic-gate * summing 1-s complement in 16-bit hunks 9970Sstevel@tonic-gate */ 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate static int 10000Sstevel@tonic-gate readhash(FILE *f, int filen, char *str) 10010Sstevel@tonic-gate { 10020Sstevel@tonic-gate long sum; 10030Sstevel@tonic-gate unsigned int shift; 10040Sstevel@tonic-gate int space; 10050Sstevel@tonic-gate int t; 10060Sstevel@tonic-gate wint_t wt; 10070Sstevel@tonic-gate int mlen; 10080Sstevel@tonic-gate 10090Sstevel@tonic-gate sum = 1; 10100Sstevel@tonic-gate space = 0; 10110Sstevel@tonic-gate if (!bflag && !wflag) { 10120Sstevel@tonic-gate if (iflag) 10130Sstevel@tonic-gate if (mbcurmax == 1) { 10140Sstevel@tonic-gate /* In this case, diff doesn't have to take */ 10150Sstevel@tonic-gate /* care of multibyte characters. */ 10160Sstevel@tonic-gate for (shift = 0; (t = getc(f)) != '\n'; 10170Sstevel@tonic-gate shift += 7) { 10180Sstevel@tonic-gate if (t == EOF) { 10190Sstevel@tonic-gate if (shift) { 10200Sstevel@tonic-gate (void) fprintf(stderr, 10210Sstevel@tonic-gate gettext("Warning: missing newline at end of file %s\n"), str); 10220Sstevel@tonic-gate break; 10230Sstevel@tonic-gate } else 10240Sstevel@tonic-gate return (0); 10250Sstevel@tonic-gate } 10260Sstevel@tonic-gate sum += (isupper(t) ? tolower(t) : t) << 10270Sstevel@tonic-gate (shift &= HALFMASK); 10280Sstevel@tonic-gate } 10290Sstevel@tonic-gate } else { 10300Sstevel@tonic-gate /* In this case, diff needs to take care of */ 10310Sstevel@tonic-gate /* multibyte characters. */ 10320Sstevel@tonic-gate for (shift = 0; 10330Sstevel@tonic-gate (wt = getbufwchar(filen, &mlen)) != '\n'; 10340Sstevel@tonic-gate shift += 7) { 10350Sstevel@tonic-gate if (wt == WEOF) { 10360Sstevel@tonic-gate if (shift) { 10370Sstevel@tonic-gate (void) fprintf(stderr, 10380Sstevel@tonic-gate gettext("Warning: missing newline at end of file %s\n"), str); 10390Sstevel@tonic-gate break; 10400Sstevel@tonic-gate } else 10410Sstevel@tonic-gate return (0); 10420Sstevel@tonic-gate } 10430Sstevel@tonic-gate sum += NCCHRTRAN(wt) << 10440Sstevel@tonic-gate (shift &= HALFMASK); 10450Sstevel@tonic-gate } 10460Sstevel@tonic-gate } 10470Sstevel@tonic-gate else 10480Sstevel@tonic-gate /* In this case, diff doesn't have to take care of */ 10490Sstevel@tonic-gate /* multibyte characters. */ 10500Sstevel@tonic-gate for (shift = 0; (t = getc(f)) != '\n'; shift += 7) { 10510Sstevel@tonic-gate if (t == EOF) { 10520Sstevel@tonic-gate if (shift) { 10530Sstevel@tonic-gate (void) fprintf(stderr, 10540Sstevel@tonic-gate gettext("Warning: missing newline at end of file %s\n"), str); 10550Sstevel@tonic-gate break; 10560Sstevel@tonic-gate } else 10570Sstevel@tonic-gate return (0); 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate sum += (long)t << (shift &= HALFMASK); 10600Sstevel@tonic-gate } 10610Sstevel@tonic-gate } else { 10620Sstevel@tonic-gate /* In this case, diff needs to take care of */ 10630Sstevel@tonic-gate /* multibyte characters. */ 10640Sstevel@tonic-gate for (shift = 0; ; ) { 10650Sstevel@tonic-gate wt = getbufwchar(filen, &mlen); 10660Sstevel@tonic-gate 10670Sstevel@tonic-gate if (wt != '\n' && iswspace(wt)) { 10680Sstevel@tonic-gate space++; 10690Sstevel@tonic-gate continue; 10700Sstevel@tonic-gate } else { 10710Sstevel@tonic-gate switch (wt) { 10720Sstevel@tonic-gate case WEOF: 10730Sstevel@tonic-gate if (shift) { 10740Sstevel@tonic-gate (void) fprintf(stderr, 10750Sstevel@tonic-gate gettext("Warning: missing newline at end of file %s\n"), str); 10760Sstevel@tonic-gate break; 10770Sstevel@tonic-gate } else 10780Sstevel@tonic-gate return (0); 10790Sstevel@tonic-gate default: 10800Sstevel@tonic-gate if (space && !wflag) { 10810Sstevel@tonic-gate shift += 7; 10820Sstevel@tonic-gate space = 0; 10830Sstevel@tonic-gate } 10840Sstevel@tonic-gate sum += CHRTRAN(wt) << 10850Sstevel@tonic-gate (shift &= HALFMASK); 10860Sstevel@tonic-gate shift += 7; 10870Sstevel@tonic-gate continue; 10880Sstevel@tonic-gate case L'\n': 10890Sstevel@tonic-gate break; 10900Sstevel@tonic-gate } 10910Sstevel@tonic-gate } 10920Sstevel@tonic-gate break; 10930Sstevel@tonic-gate } 10940Sstevel@tonic-gate } 10950Sstevel@tonic-gate return (sum); 10960Sstevel@tonic-gate } 10970Sstevel@tonic-gate 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate /* dump accumulated "context" diff changes */ 11000Sstevel@tonic-gate static void 11010Sstevel@tonic-gate dump_context_vec(void) 11020Sstevel@tonic-gate { 11030Sstevel@tonic-gate int a, b, c, d; 11040Sstevel@tonic-gate char ch; 11050Sstevel@tonic-gate struct context_vec *cvp = context_vec_start; 11060Sstevel@tonic-gate int lowa, upb, lowc, upd; 11070Sstevel@tonic-gate int do_output; 11080Sstevel@tonic-gate 11090Sstevel@tonic-gate if (cvp > context_vec_ptr) 11100Sstevel@tonic-gate return; 11110Sstevel@tonic-gate 11120Sstevel@tonic-gate lowa = max(1, cvp->a - context); 11130Sstevel@tonic-gate upb = min(len[0], context_vec_ptr->b + context); 11140Sstevel@tonic-gate lowc = max(1, cvp->c - context); 11150Sstevel@tonic-gate upd = min(len[1], context_vec_ptr->d + context); 11160Sstevel@tonic-gate 11170Sstevel@tonic-gate if (uflag) { 11180Sstevel@tonic-gate (void) printf("@@ -%d,%d +%d,%d @@\n", 11190Sstevel@tonic-gate lowa, upb - lowa + 1, 11200Sstevel@tonic-gate lowc, upd - lowc + 1); 11210Sstevel@tonic-gate } else { 11220Sstevel@tonic-gate (void) printf("***************\n*** "); 11230Sstevel@tonic-gate range(lowa, upb, ","); 11240Sstevel@tonic-gate (void) printf(" ****\n"); 11250Sstevel@tonic-gate } 11260Sstevel@tonic-gate 11270Sstevel@tonic-gate /* 11280Sstevel@tonic-gate * output changes to the "old" file. The first loop suppresses 11290Sstevel@tonic-gate * output if there were no changes to the "old" file (we'll see 11300Sstevel@tonic-gate * the "old" lines as context in the "new" list). 11310Sstevel@tonic-gate */ 11320Sstevel@tonic-gate if (uflag) 11330Sstevel@tonic-gate do_output = 1; 11340Sstevel@tonic-gate else 11350Sstevel@tonic-gate for (do_output = 0; cvp <= context_vec_ptr; cvp++) 11360Sstevel@tonic-gate if (cvp->a <= cvp->b) { 11370Sstevel@tonic-gate cvp = context_vec_start; 11380Sstevel@tonic-gate do_output++; 11390Sstevel@tonic-gate break; 11400Sstevel@tonic-gate } 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate if (do_output) { 11430Sstevel@tonic-gate while (cvp <= context_vec_ptr) { 11440Sstevel@tonic-gate a = cvp->a; b = cvp->b; c = cvp->c; d = cvp->d; 11450Sstevel@tonic-gate 11460Sstevel@tonic-gate if (a <= b && c <= d) 11470Sstevel@tonic-gate ch = 'c'; 11480Sstevel@tonic-gate else 11490Sstevel@tonic-gate ch = (a <= b) ? 'd' : 'a'; 11500Sstevel@tonic-gate 11510Sstevel@tonic-gate if (ch == 'a') { 11520Sstevel@tonic-gate /* The last argument should not affect */ 11530Sstevel@tonic-gate /* the behavior of fetch() */ 11540Sstevel@tonic-gate fetch(ixold, lowa, b, 0, uflag ? " " : " ", 1); 11550Sstevel@tonic-gate if (uflag) 11560Sstevel@tonic-gate fetch(ixnew, c, d, 1, "+", 0); 11570Sstevel@tonic-gate } else if (ch == 'd') { 11580Sstevel@tonic-gate fetch(ixold, lowa, a - 1, 0, uflag ? " " : 11590Sstevel@tonic-gate " ", 1); 11600Sstevel@tonic-gate fetch(ixold, a, b, 0, uflag ? "-" : "- ", 1); 11610Sstevel@tonic-gate } else { 11620Sstevel@tonic-gate /* The last argument should not affect */ 11630Sstevel@tonic-gate /* the behavior of fetch() */ 11640Sstevel@tonic-gate fetch(ixold, lowa, a-1, 0, uflag ? " " : " ", 11650Sstevel@tonic-gate 1); 11660Sstevel@tonic-gate if (uflag) { 11670Sstevel@tonic-gate fetch(ixold, a, b, 0, "-", 1); 11680Sstevel@tonic-gate fetch(ixnew, c, d, 1, "+", 0); 11690Sstevel@tonic-gate } else 11700Sstevel@tonic-gate fetch(ixold, a, b, 0, "! ", 1); 11710Sstevel@tonic-gate } 11720Sstevel@tonic-gate lowa = b + 1; 11730Sstevel@tonic-gate cvp++; 11740Sstevel@tonic-gate } 11750Sstevel@tonic-gate /* The last argument should not affect the behavior */ 11760Sstevel@tonic-gate /* of fetch() */ 11770Sstevel@tonic-gate fetch(ixold, b+1, upb, 0, uflag ? " " : " ", 1); 11780Sstevel@tonic-gate } 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate if (uflag) { 11810Sstevel@tonic-gate context_vec_ptr = context_vec_start - 1; 11820Sstevel@tonic-gate return; 11830Sstevel@tonic-gate } 11840Sstevel@tonic-gate 11850Sstevel@tonic-gate /* output changes to the "new" file */ 11860Sstevel@tonic-gate (void) printf("--- "); 11870Sstevel@tonic-gate range(lowc, upd, ","); 11880Sstevel@tonic-gate (void) printf(" ----\n"); 11890Sstevel@tonic-gate 11900Sstevel@tonic-gate do_output = 0; 11910Sstevel@tonic-gate for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) 11920Sstevel@tonic-gate if (cvp->c <= cvp->d) { 11930Sstevel@tonic-gate cvp = context_vec_start; 11940Sstevel@tonic-gate do_output++; 11950Sstevel@tonic-gate break; 11960Sstevel@tonic-gate } 11970Sstevel@tonic-gate 11980Sstevel@tonic-gate if (do_output) { 11990Sstevel@tonic-gate while (cvp <= context_vec_ptr) { 12000Sstevel@tonic-gate a = cvp->a; b = cvp->b; c = cvp->c; d = cvp->d; 12010Sstevel@tonic-gate 12020Sstevel@tonic-gate if (a <= b && c <= d) 12030Sstevel@tonic-gate ch = 'c'; 12040Sstevel@tonic-gate else 12050Sstevel@tonic-gate ch = (a <= b) ? 'd' : 'a'; 12060Sstevel@tonic-gate 12070Sstevel@tonic-gate if (ch == 'd') 12080Sstevel@tonic-gate /* The last argument should not affect */ 12090Sstevel@tonic-gate /* the behavior of fetch() */ 12100Sstevel@tonic-gate fetch(ixnew, lowc, d, 1, " ", 0); 12110Sstevel@tonic-gate else { 12120Sstevel@tonic-gate /* The last argument should not affect */ 12130Sstevel@tonic-gate /* the behavior of fetch() */ 12140Sstevel@tonic-gate fetch(ixnew, lowc, c - 1, 1, " ", 0); 12150Sstevel@tonic-gate fetch(ixnew, c, d, 1, 12160Sstevel@tonic-gate ch == 'c' ? "! " : "+ ", 0); 12170Sstevel@tonic-gate } 12180Sstevel@tonic-gate lowc = d + 1; 12190Sstevel@tonic-gate cvp++; 12200Sstevel@tonic-gate } 12210Sstevel@tonic-gate /* The last argument should not affect the behavior */ 12220Sstevel@tonic-gate /* of fetch() */ 12230Sstevel@tonic-gate fetch(ixnew, d + 1, upd, 1, " ", 0); 12240Sstevel@tonic-gate } 12250Sstevel@tonic-gate context_vec_ptr = context_vec_start - 1; 12260Sstevel@tonic-gate } 12270Sstevel@tonic-gate 12280Sstevel@tonic-gate 12290Sstevel@tonic-gate 12300Sstevel@tonic-gate /* 12310Sstevel@tonic-gate * diff - directory comparison 12320Sstevel@tonic-gate */ 12330Sstevel@tonic-gate 12340Sstevel@tonic-gate struct dir *setupdir(); 12350Sstevel@tonic-gate int header; 12360Sstevel@tonic-gate char title[2 * BUFSIZ], *etitle; 12370Sstevel@tonic-gate 12380Sstevel@tonic-gate static void 12390Sstevel@tonic-gate diffdir(char **argv) 12400Sstevel@tonic-gate { 12410Sstevel@tonic-gate struct dir *d1, *d2; 12420Sstevel@tonic-gate struct dir *dir1, *dir2; 12430Sstevel@tonic-gate int i; 12440Sstevel@tonic-gate int cmp; 12450Sstevel@tonic-gate int result, dirstatus; 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate if (opt == D_IFDEF) 12480Sstevel@tonic-gate error(gettext("cannot specify -D with directories")); 12490Sstevel@tonic-gate 12500Sstevel@tonic-gate if (opt == D_EDIT && (sflag || lflag)) { 12510Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 12520Sstevel@tonic-gate (void) fprintf(stderr, gettext( 12530Sstevel@tonic-gate "warning: should not give -s or -l with -e\n")); 12540Sstevel@tonic-gate } 12550Sstevel@tonic-gate dirstatus = 0; 12560Sstevel@tonic-gate title[0] = 0; 12570Sstevel@tonic-gate (void) strcpy(title, "diff "); 12580Sstevel@tonic-gate for (i = 1; diffargv[i + 2]; i++) { 12590Sstevel@tonic-gate if (strcmp(diffargv[i], "-") == 0) { 12600Sstevel@tonic-gate continue; /* Skip -S and its argument */ 12610Sstevel@tonic-gate } 12620Sstevel@tonic-gate (void) strcat(title, diffargv[i]); 12630Sstevel@tonic-gate (void) strcat(title, " "); 12640Sstevel@tonic-gate } 12650Sstevel@tonic-gate for (etitle = title; *etitle; etitle++) 12660Sstevel@tonic-gate ; 12670Sstevel@tonic-gate setfile(&file1, &efile1, file1); 12680Sstevel@tonic-gate setfile(&file2, &efile2, file2); 12690Sstevel@tonic-gate argv[0] = file1; 12700Sstevel@tonic-gate argv[1] = file2; 12710Sstevel@tonic-gate dir1 = setupdir(file1); 12720Sstevel@tonic-gate dir2 = setupdir(file2); 12730Sstevel@tonic-gate d1 = dir1; d2 = dir2; 12740Sstevel@tonic-gate while (d1->d_entry != 0 || d2->d_entry != 0) { 12750Sstevel@tonic-gate if (d1->d_entry && useless(d1->d_entry)) { 12760Sstevel@tonic-gate d1++; 12770Sstevel@tonic-gate continue; 12780Sstevel@tonic-gate } 12790Sstevel@tonic-gate if (d2->d_entry && useless(d2->d_entry)) { 12800Sstevel@tonic-gate d2++; 12810Sstevel@tonic-gate continue; 12820Sstevel@tonic-gate } 12830Sstevel@tonic-gate if (d1->d_entry == 0) 12840Sstevel@tonic-gate cmp = 1; 12850Sstevel@tonic-gate else if (d2->d_entry == 0) 12860Sstevel@tonic-gate cmp = -1; 12870Sstevel@tonic-gate else 12880Sstevel@tonic-gate cmp = strcmp(d1->d_entry, d2->d_entry); 12890Sstevel@tonic-gate if (cmp < 0) { 12900Sstevel@tonic-gate if (lflag) 12910Sstevel@tonic-gate d1->d_flags |= ONLY; 12920Sstevel@tonic-gate else if (opt == 0 || opt == 2) 12930Sstevel@tonic-gate only(d1, 1); 12940Sstevel@tonic-gate d1++; 12950Sstevel@tonic-gate if (dirstatus == 0) 12960Sstevel@tonic-gate dirstatus = 1; 12970Sstevel@tonic-gate } else if (cmp == 0) { 12980Sstevel@tonic-gate result = compare(d1); 12990Sstevel@tonic-gate if (result > dirstatus) 13000Sstevel@tonic-gate dirstatus = result; 13010Sstevel@tonic-gate d1++; 13020Sstevel@tonic-gate d2++; 13030Sstevel@tonic-gate } else { 13040Sstevel@tonic-gate if (lflag) 13050Sstevel@tonic-gate d2->d_flags |= ONLY; 13060Sstevel@tonic-gate else if (opt == 0 || opt == 2) 13070Sstevel@tonic-gate only(d2, 2); 13080Sstevel@tonic-gate d2++; 13090Sstevel@tonic-gate if (dirstatus == 0) 13100Sstevel@tonic-gate dirstatus = 1; 13110Sstevel@tonic-gate } 13120Sstevel@tonic-gate } 13130Sstevel@tonic-gate if (lflag) { 13140Sstevel@tonic-gate scanpr(dir1, ONLY, 13150Sstevel@tonic-gate gettext("Only in %.*s"), file1, efile1, 0, 0); 13160Sstevel@tonic-gate scanpr(dir2, ONLY, 13170Sstevel@tonic-gate gettext("Only in %.*s"), file2, efile2, 0, 0); 13180Sstevel@tonic-gate scanpr(dir1, SAME, 13190Sstevel@tonic-gate gettext("Common identical files in %.*s and %.*s"), 13200Sstevel@tonic-gate file1, efile1, file2, efile2); 13210Sstevel@tonic-gate scanpr(dir1, DIFFER, 13220Sstevel@tonic-gate gettext("Binary files which differ in %.*s and %.*s"), 13230Sstevel@tonic-gate file1, efile1, file2, efile2); 13240Sstevel@tonic-gate scanpr(dir1, DIRECT, 13250Sstevel@tonic-gate gettext("Common subdirectories of %.*s and %.*s"), 13260Sstevel@tonic-gate file1, efile1, file2, efile2); 13270Sstevel@tonic-gate } 13280Sstevel@tonic-gate if (rflag) { 13290Sstevel@tonic-gate if (header && lflag) 13300Sstevel@tonic-gate (void) printf("\f"); 13310Sstevel@tonic-gate for (d1 = dir1; d1->d_entry; d1++) { 13320Sstevel@tonic-gate if ((d1->d_flags & DIRECT) == 0) 13330Sstevel@tonic-gate continue; 13340Sstevel@tonic-gate (void) strcpy(efile1, d1->d_entry); 13350Sstevel@tonic-gate (void) strcpy(efile2, d1->d_entry); 13360Sstevel@tonic-gate result = calldiff((char *)0); 13370Sstevel@tonic-gate if (result > dirstatus) 13380Sstevel@tonic-gate dirstatus = result; 13390Sstevel@tonic-gate } 13400Sstevel@tonic-gate } 13410Sstevel@tonic-gate status = dirstatus; 13420Sstevel@tonic-gate } 13430Sstevel@tonic-gate 13440Sstevel@tonic-gate static void 13450Sstevel@tonic-gate setfile(char **fpp, char **epp, char *file) 13460Sstevel@tonic-gate { 13470Sstevel@tonic-gate char *cp; 13480Sstevel@tonic-gate 13490Sstevel@tonic-gate *fpp = (char *)malloc(BUFSIZ); 13500Sstevel@tonic-gate if (*fpp == 0) { 13510Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 13520Sstevel@tonic-gate (void) fprintf(stderr, gettext("out of memory\n")); 13530Sstevel@tonic-gate exit(1); 13540Sstevel@tonic-gate } 13550Sstevel@tonic-gate (void) strcpy(*fpp, file); 13560Sstevel@tonic-gate for (cp = *fpp; *cp; cp++) 13570Sstevel@tonic-gate continue; 13580Sstevel@tonic-gate *cp++ = '/'; 13590Sstevel@tonic-gate *cp = 0; 13600Sstevel@tonic-gate *epp = cp; 13610Sstevel@tonic-gate } 13620Sstevel@tonic-gate 13630Sstevel@tonic-gate static void 13640Sstevel@tonic-gate scanpr(struct dir *dp, int test, 13650Sstevel@tonic-gate char *title, char *file1, char *efile1, char *file2, char *efile2) 13660Sstevel@tonic-gate { 13670Sstevel@tonic-gate int titled = 0; 13680Sstevel@tonic-gate 13690Sstevel@tonic-gate for (; dp->d_entry; dp++) { 13700Sstevel@tonic-gate if ((dp->d_flags & test) == 0) 13710Sstevel@tonic-gate continue; 13720Sstevel@tonic-gate if (titled == 0) { 13730Sstevel@tonic-gate if (header == 0) 13740Sstevel@tonic-gate header = 1; 13750Sstevel@tonic-gate else 13760Sstevel@tonic-gate (void) printf("\n"); 13770Sstevel@tonic-gate (void) printf(title, 13780Sstevel@tonic-gate efile1 - file1 - 1, file1, 13790Sstevel@tonic-gate efile2 - file2 - 1, file2); 13800Sstevel@tonic-gate (void) printf(":\n"); 13810Sstevel@tonic-gate titled = 1; 13820Sstevel@tonic-gate } 13830Sstevel@tonic-gate (void) printf("\t%s\n", dp->d_entry); 13840Sstevel@tonic-gate } 13850Sstevel@tonic-gate } 13860Sstevel@tonic-gate 13870Sstevel@tonic-gate static void 13880Sstevel@tonic-gate only(struct dir *dp, int which) 13890Sstevel@tonic-gate { 13900Sstevel@tonic-gate char *file = which == 1 ? file1 : file2; 13910Sstevel@tonic-gate char *efile = which == 1 ? efile1 : efile2; 13920Sstevel@tonic-gate 13930Sstevel@tonic-gate (void) printf(gettext("Only in %.*s: %s\n"), efile - file - 1, file, 13940Sstevel@tonic-gate dp->d_entry); 13950Sstevel@tonic-gate } 13960Sstevel@tonic-gate 13970Sstevel@tonic-gate int entcmp(); 13980Sstevel@tonic-gate 13990Sstevel@tonic-gate static struct dir * 14000Sstevel@tonic-gate setupdir(char *cp) 14010Sstevel@tonic-gate { 14020Sstevel@tonic-gate struct dir *dp = 0, *ep; 14030Sstevel@tonic-gate struct dirent64 *rp; 14040Sstevel@tonic-gate int nitems; 14050Sstevel@tonic-gate int size; 14060Sstevel@tonic-gate DIR *dirp; 14070Sstevel@tonic-gate 14080Sstevel@tonic-gate dirp = opendir(cp); 14090Sstevel@tonic-gate if (dirp == NULL) { 14100Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 14110Sstevel@tonic-gate perror(cp); 14120Sstevel@tonic-gate done(); 14130Sstevel@tonic-gate } 14140Sstevel@tonic-gate nitems = 0; 14150Sstevel@tonic-gate dp = (struct dir *)malloc(sizeof (struct dir)); 14160Sstevel@tonic-gate if (dp == 0) 14170Sstevel@tonic-gate error(gettext(NO_MEM_ERR)); 14180Sstevel@tonic-gate 14190Sstevel@tonic-gate while (rp = readdir64(dirp)) { 14200Sstevel@tonic-gate ep = &dp[nitems++]; 14210Sstevel@tonic-gate ep->d_reclen = rp->d_reclen; 14220Sstevel@tonic-gate ep->d_entry = 0; 14230Sstevel@tonic-gate ep->d_flags = 0; 14240Sstevel@tonic-gate size = strlen(rp->d_name); 14250Sstevel@tonic-gate if (size > 0) { 14260Sstevel@tonic-gate ep->d_entry = (char *)malloc(size + 1); 14270Sstevel@tonic-gate if (ep->d_entry == 0) 14280Sstevel@tonic-gate error(gettext(NO_MEM_ERR)); 14290Sstevel@tonic-gate 14300Sstevel@tonic-gate (void) strcpy(ep->d_entry, rp->d_name); 14310Sstevel@tonic-gate } 14320Sstevel@tonic-gate dp = (struct dir *)realloc((char *)dp, 14330Sstevel@tonic-gate (nitems + 1) * sizeof (struct dir)); 14340Sstevel@tonic-gate if (dp == 0) 14350Sstevel@tonic-gate error(gettext(NO_MEM_ERR)); 14360Sstevel@tonic-gate } 14370Sstevel@tonic-gate dp[nitems].d_entry = 0; /* delimiter */ 14380Sstevel@tonic-gate (void) closedir(dirp); 14390Sstevel@tonic-gate qsort(dp, nitems, sizeof (struct dir), 14400Sstevel@tonic-gate (int (*)(const void *, const void *))entcmp); 14410Sstevel@tonic-gate return (dp); 14420Sstevel@tonic-gate } 14430Sstevel@tonic-gate 14440Sstevel@tonic-gate static int 14450Sstevel@tonic-gate entcmp(struct dir *d1, struct dir *d2) 14460Sstevel@tonic-gate { 14470Sstevel@tonic-gate return (strcmp(d1->d_entry, d2->d_entry)); 14480Sstevel@tonic-gate } 14490Sstevel@tonic-gate 14500Sstevel@tonic-gate static int 14510Sstevel@tonic-gate compare(struct dir *dp) 14520Sstevel@tonic-gate { 14530Sstevel@tonic-gate int i, j; 14540Sstevel@tonic-gate int f1 = -1, f2 = -1; 14550Sstevel@tonic-gate mode_t fmt1, fmt2; 14560Sstevel@tonic-gate struct stat stb1, stb2; 14570Sstevel@tonic-gate char buf1[BUFSIZ], buf2[BUFSIZ]; 14580Sstevel@tonic-gate int result; 14590Sstevel@tonic-gate 14600Sstevel@tonic-gate (void) strcpy(efile1, dp->d_entry); 14610Sstevel@tonic-gate (void) strcpy(efile2, dp->d_entry); 14620Sstevel@tonic-gate 14630Sstevel@tonic-gate if (stat(file1, &stb1) == -1) { 14640Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 14650Sstevel@tonic-gate perror(file1); 14660Sstevel@tonic-gate return (2); 14670Sstevel@tonic-gate } 14680Sstevel@tonic-gate if (stat(file2, &stb2) == -1) { 14690Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 14700Sstevel@tonic-gate perror(file2); 14710Sstevel@tonic-gate return (2); 14720Sstevel@tonic-gate } 14730Sstevel@tonic-gate 14740Sstevel@tonic-gate fmt1 = stb1.st_mode & S_IFMT; 14750Sstevel@tonic-gate fmt2 = stb2.st_mode & S_IFMT; 14760Sstevel@tonic-gate 14770Sstevel@tonic-gate if (fmt1 == S_IFREG) { 14780Sstevel@tonic-gate f1 = open(file1, O_RDONLY); 14790Sstevel@tonic-gate if (f1 < 0) { 14800Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 14810Sstevel@tonic-gate perror(file1); 14820Sstevel@tonic-gate return (2); 14830Sstevel@tonic-gate } 14840Sstevel@tonic-gate } 14850Sstevel@tonic-gate 14860Sstevel@tonic-gate if (fmt2 == S_IFREG) { 14870Sstevel@tonic-gate f2 = open(file2, O_RDONLY); 14880Sstevel@tonic-gate if (f2 < 0) { 14890Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 14900Sstevel@tonic-gate perror(file2); 14910Sstevel@tonic-gate (void) close(f1); 14920Sstevel@tonic-gate return (2); 14930Sstevel@tonic-gate } 14940Sstevel@tonic-gate } 14950Sstevel@tonic-gate 14960Sstevel@tonic-gate if (fmt1 != S_IFREG || fmt2 != S_IFREG) { 14970Sstevel@tonic-gate if (fmt1 == fmt2) { 14980Sstevel@tonic-gate switch (fmt1) { 14990Sstevel@tonic-gate 15000Sstevel@tonic-gate case S_IFDIR: 15010Sstevel@tonic-gate dp->d_flags = DIRECT; 15020Sstevel@tonic-gate if (lflag || opt == D_EDIT) 15030Sstevel@tonic-gate goto closem; 15040Sstevel@tonic-gate (void) printf(gettext( 15050Sstevel@tonic-gate "Common subdirectories: %s and %s\n"), 15060Sstevel@tonic-gate file1, file2); 15070Sstevel@tonic-gate goto closem; 15080Sstevel@tonic-gate 15090Sstevel@tonic-gate case S_IFCHR: 15100Sstevel@tonic-gate case S_IFBLK: 15110Sstevel@tonic-gate if (stb1.st_rdev == stb2.st_rdev) 15120Sstevel@tonic-gate goto same; 15130Sstevel@tonic-gate (void) printf(gettext( 15140Sstevel@tonic-gate "Special files %s and %s differ\n"), 15150Sstevel@tonic-gate file1, file2); 15160Sstevel@tonic-gate break; 15170Sstevel@tonic-gate 15180Sstevel@tonic-gate case S_IFLNK: 15190Sstevel@tonic-gate if ((i = readlink(file1, buf1, BUFSIZ)) == -1) { 15200Sstevel@tonic-gate (void) fprintf(stderr, gettext( 15210Sstevel@tonic-gate "diff: cannot read link\n")); 15220Sstevel@tonic-gate return (2); 15230Sstevel@tonic-gate } 15240Sstevel@tonic-gate 15250Sstevel@tonic-gate if ((j = readlink(file2, buf2, BUFSIZ)) == -1) { 15260Sstevel@tonic-gate (void) fprintf(stderr, gettext( 15270Sstevel@tonic-gate "diff: cannot read link\n")); 15280Sstevel@tonic-gate return (2); 15290Sstevel@tonic-gate } 15300Sstevel@tonic-gate 15310Sstevel@tonic-gate if (i == j) { 15320Sstevel@tonic-gate if (strncmp(buf1, buf2, i) == 0) 15330Sstevel@tonic-gate goto same; 15340Sstevel@tonic-gate } 15350Sstevel@tonic-gate 15360Sstevel@tonic-gate (void) printf(gettext( 15370Sstevel@tonic-gate "Symbolic links %s and %s differ\n"), 15380Sstevel@tonic-gate file1, file2); 15390Sstevel@tonic-gate break; 15400Sstevel@tonic-gate 15410Sstevel@tonic-gate case S_IFIFO: 15420Sstevel@tonic-gate if (stb1.st_ino == stb2.st_ino) 15430Sstevel@tonic-gate goto same; 15440Sstevel@tonic-gate (void) printf(gettext( 15450Sstevel@tonic-gate "Named pipes %s and %s differ\n"), 15460Sstevel@tonic-gate file1, file2); 15470Sstevel@tonic-gate break; 15480Sstevel@tonic-gate } 15490Sstevel@tonic-gate } else { 15500Sstevel@tonic-gate if (lflag) 15510Sstevel@tonic-gate dp->d_flags |= DIFFER; 15520Sstevel@tonic-gate else if (opt == D_NORMAL || opt == D_CONTEXT) { 15530Sstevel@tonic-gate /* 15540Sstevel@tonic-gate * TRANSLATION_NOTE 15550Sstevel@tonic-gate * The second and fourth parameters will take the gettext'ed string 15560Sstevel@tonic-gate * of one of the following: 15570Sstevel@tonic-gate * a directory 15580Sstevel@tonic-gate * a character special file 15590Sstevel@tonic-gate * a block special file 15600Sstevel@tonic-gate * a plain file 15610Sstevel@tonic-gate * a named pipe 15620Sstevel@tonic-gate * a socket 15630Sstevel@tonic-gate * a door 15640Sstevel@tonic-gate * an event port 15650Sstevel@tonic-gate * an unknown type 15660Sstevel@tonic-gate */ 15670Sstevel@tonic-gate (void) printf( 15680Sstevel@tonic-gate gettext("File %s is %s while file %s is %s\n"), 15690Sstevel@tonic-gate file1, pfiletype(fmt1), 15700Sstevel@tonic-gate file2, pfiletype(fmt2)); 15710Sstevel@tonic-gate } 15720Sstevel@tonic-gate } 15730Sstevel@tonic-gate (void) close(f1); (void) close(f2); 15740Sstevel@tonic-gate return (1); 15750Sstevel@tonic-gate } 15760Sstevel@tonic-gate if (stb1.st_size != stb2.st_size) 15770Sstevel@tonic-gate goto notsame; 15780Sstevel@tonic-gate for (;;) { 15790Sstevel@tonic-gate i = read(f1, buf1, BUFSIZ); 15800Sstevel@tonic-gate j = read(f2, buf2, BUFSIZ); 15810Sstevel@tonic-gate if (i < 0 || j < 0) { 15820Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 15830Sstevel@tonic-gate (void) fprintf(stderr, gettext("Error reading ")); 15840Sstevel@tonic-gate perror(i < 0 ? file1: file2); 15850Sstevel@tonic-gate (void) close(f1); (void) close(f2); 15860Sstevel@tonic-gate return (2); 15870Sstevel@tonic-gate } 15880Sstevel@tonic-gate if (i != j) 15890Sstevel@tonic-gate goto notsame; 15900Sstevel@tonic-gate if (i == 0 && j == 0) 15910Sstevel@tonic-gate goto same; 15920Sstevel@tonic-gate for (j = 0; j < i; j++) 15930Sstevel@tonic-gate if (buf1[j] != buf2[j]) 15940Sstevel@tonic-gate goto notsame; 15950Sstevel@tonic-gate } 15960Sstevel@tonic-gate same: 15970Sstevel@tonic-gate if (sflag == 0) 15980Sstevel@tonic-gate goto closem; 15990Sstevel@tonic-gate if (lflag) 16000Sstevel@tonic-gate dp->d_flags = SAME; 16010Sstevel@tonic-gate else 16020Sstevel@tonic-gate (void) printf(gettext("Files %s and %s are identical\n"), 16030Sstevel@tonic-gate file1, file2); 16040Sstevel@tonic-gate 16050Sstevel@tonic-gate closem: 16060Sstevel@tonic-gate (void) close(f1); (void) close(f2); 16070Sstevel@tonic-gate return (0); 16080Sstevel@tonic-gate 16090Sstevel@tonic-gate notsame: 16100Sstevel@tonic-gate if (binary(f1) || binary(f2)) { 16110Sstevel@tonic-gate if (lflag) 16120Sstevel@tonic-gate dp->d_flags |= DIFFER; 16130Sstevel@tonic-gate else if (opt == D_NORMAL || opt == D_CONTEXT) 16140Sstevel@tonic-gate (void) printf( 16150Sstevel@tonic-gate gettext("Binary files %s and %s differ\n"), 16160Sstevel@tonic-gate file1, file2); 16170Sstevel@tonic-gate (void) close(f1); (void) close(f2); 16180Sstevel@tonic-gate return (1); 16190Sstevel@tonic-gate } 16200Sstevel@tonic-gate (void) close(f1); (void) close(f2); 16210Sstevel@tonic-gate anychange = 1; 16220Sstevel@tonic-gate if (lflag) { 16230Sstevel@tonic-gate result = calldiff(title); 16240Sstevel@tonic-gate } else { 16250Sstevel@tonic-gate if (opt == D_EDIT) 16260Sstevel@tonic-gate (void) printf("ed - %s << '-*-END-*-'\n", dp->d_entry); 16270Sstevel@tonic-gate else 16280Sstevel@tonic-gate (void) printf("%s%s %s\n", title, file1, file2); 16290Sstevel@tonic-gate result = calldiff((char *)0); 16300Sstevel@tonic-gate if (opt == D_EDIT) 16310Sstevel@tonic-gate (void) printf("w\nq\n-*-END-*-\n"); 16320Sstevel@tonic-gate } 16330Sstevel@tonic-gate return (result); 16340Sstevel@tonic-gate } 16350Sstevel@tonic-gate 16360Sstevel@tonic-gate char *prargs[] = { "pr", "-h", 0, 0, 0 }; 16370Sstevel@tonic-gate 16380Sstevel@tonic-gate static int 16390Sstevel@tonic-gate calldiff(char *wantpr) 16400Sstevel@tonic-gate { 16410Sstevel@tonic-gate pid_t pid; 16420Sstevel@tonic-gate int diffstatus, pv[2]; 16430Sstevel@tonic-gate 16440Sstevel@tonic-gate prargs[2] = wantpr; 16450Sstevel@tonic-gate (void) fflush(stdout); 16460Sstevel@tonic-gate if (wantpr) { 16470Sstevel@tonic-gate (void) sprintf(etitle, "%s %s", file1, file2); 16480Sstevel@tonic-gate (void) pipe(pv); 16490Sstevel@tonic-gate pid = fork(); 16500Sstevel@tonic-gate if (pid == (pid_t)-1) 16510Sstevel@tonic-gate error(gettext(NO_PROCS_ERR)); 16520Sstevel@tonic-gate 16530Sstevel@tonic-gate if (pid == 0) { 16540Sstevel@tonic-gate (void) close(0); 16550Sstevel@tonic-gate (void) dup(pv[0]); 16560Sstevel@tonic-gate (void) close(pv[0]); 16570Sstevel@tonic-gate (void) close(pv[1]); 16580Sstevel@tonic-gate (void) execv(pr+5, prargs); 16590Sstevel@tonic-gate (void) execv(pr, prargs); 16600Sstevel@tonic-gate perror(pr); 16610Sstevel@tonic-gate done(); 16620Sstevel@tonic-gate } 16630Sstevel@tonic-gate } 16640Sstevel@tonic-gate pid = fork(); 16650Sstevel@tonic-gate if (pid == (pid_t)-1) 16660Sstevel@tonic-gate error(gettext(NO_PROCS_ERR)); 16670Sstevel@tonic-gate 16680Sstevel@tonic-gate if (pid == 0) { 16690Sstevel@tonic-gate if (wantpr) { 16700Sstevel@tonic-gate (void) close(1); 16710Sstevel@tonic-gate (void) dup(pv[1]); 16720Sstevel@tonic-gate (void) close(pv[0]); 16730Sstevel@tonic-gate (void) close(pv[1]); 16740Sstevel@tonic-gate } 16750Sstevel@tonic-gate (void) execv(diff+5, diffargv); 16760Sstevel@tonic-gate (void) execv(diff, diffargv); 16770Sstevel@tonic-gate perror(diff); 16780Sstevel@tonic-gate done(); 16790Sstevel@tonic-gate } 16800Sstevel@tonic-gate if (wantpr) { 16810Sstevel@tonic-gate (void) close(pv[0]); 16820Sstevel@tonic-gate (void) close(pv[1]); 16830Sstevel@tonic-gate } 16840Sstevel@tonic-gate while (wait(&diffstatus) != pid) 16850Sstevel@tonic-gate continue; 16860Sstevel@tonic-gate while (wait((int *)0) != (pid_t)-1) 16870Sstevel@tonic-gate continue; 16880Sstevel@tonic-gate if ((diffstatus&0177) != 0) 16890Sstevel@tonic-gate return (2); 16900Sstevel@tonic-gate else 16910Sstevel@tonic-gate return ((diffstatus>>8) & 0377); 16920Sstevel@tonic-gate } 16930Sstevel@tonic-gate 16940Sstevel@tonic-gate static char * 16950Sstevel@tonic-gate pfiletype(mode_t fmt) 16960Sstevel@tonic-gate { 16970Sstevel@tonic-gate /* 16980Sstevel@tonic-gate * TRANSLATION_NOTE 16990Sstevel@tonic-gate * The following 9 messages will be used in the second and 17000Sstevel@tonic-gate * the fourth parameters of the message 17010Sstevel@tonic-gate * "File %s is %s while file %s is %s\n" 17020Sstevel@tonic-gate */ 17030Sstevel@tonic-gate switch (fmt) { 17040Sstevel@tonic-gate 17050Sstevel@tonic-gate case S_IFDIR: 17060Sstevel@tonic-gate return (gettext("a directory")); 17070Sstevel@tonic-gate break; 17080Sstevel@tonic-gate 17090Sstevel@tonic-gate case S_IFCHR: 17100Sstevel@tonic-gate return (gettext("a character special file")); 17110Sstevel@tonic-gate break; 17120Sstevel@tonic-gate 17130Sstevel@tonic-gate case S_IFBLK: 17140Sstevel@tonic-gate return (gettext("a block special file")); 17150Sstevel@tonic-gate break; 17160Sstevel@tonic-gate 17170Sstevel@tonic-gate case S_IFREG: 17180Sstevel@tonic-gate return (gettext("a plain file")); 17190Sstevel@tonic-gate break; 17200Sstevel@tonic-gate 17210Sstevel@tonic-gate case S_IFIFO: 17220Sstevel@tonic-gate return (gettext("a named pipe")); 17230Sstevel@tonic-gate break; 17240Sstevel@tonic-gate 17250Sstevel@tonic-gate case S_IFSOCK: 17260Sstevel@tonic-gate return (gettext("a socket")); 17270Sstevel@tonic-gate break; 17280Sstevel@tonic-gate 17290Sstevel@tonic-gate case S_IFDOOR: 17300Sstevel@tonic-gate return (gettext("a door")); 17310Sstevel@tonic-gate break; 17320Sstevel@tonic-gate 17330Sstevel@tonic-gate case S_IFPORT: 17340Sstevel@tonic-gate return (gettext("an event port")); 17350Sstevel@tonic-gate break; 17360Sstevel@tonic-gate 17370Sstevel@tonic-gate default: 17380Sstevel@tonic-gate return (gettext("an unknown type")); 17390Sstevel@tonic-gate break; 17400Sstevel@tonic-gate } 17410Sstevel@tonic-gate } 17420Sstevel@tonic-gate 17430Sstevel@tonic-gate static int 17440Sstevel@tonic-gate binary(int f) 17450Sstevel@tonic-gate { 17460Sstevel@tonic-gate char buf[BUFSIZ]; 17470Sstevel@tonic-gate int cnt; 17480Sstevel@tonic-gate 17490Sstevel@tonic-gate (void) lseek(f, (long)0, SEEK_SET); 17500Sstevel@tonic-gate cnt = read(f, buf, BUFSIZ); 17510Sstevel@tonic-gate if (cnt < 0) 17520Sstevel@tonic-gate return (1); 17530Sstevel@tonic-gate return (isbinary(buf, cnt)); 17540Sstevel@tonic-gate } 17550Sstevel@tonic-gate 17560Sstevel@tonic-gate static int 17570Sstevel@tonic-gate filebinary(FILE *f) 17580Sstevel@tonic-gate { 17590Sstevel@tonic-gate char buf[BUFSIZ]; 17600Sstevel@tonic-gate int cnt; 17610Sstevel@tonic-gate 17620Sstevel@tonic-gate (void) fseek(f, (long)0, SEEK_SET); 17630Sstevel@tonic-gate cnt = fread(buf, 1, BUFSIZ, f); 17640Sstevel@tonic-gate if (ferror(f)) 17650Sstevel@tonic-gate return (1); 17660Sstevel@tonic-gate return (isbinary(buf, cnt)); 17670Sstevel@tonic-gate } 17680Sstevel@tonic-gate 17690Sstevel@tonic-gate 17700Sstevel@tonic-gate /* 17710Sstevel@tonic-gate * We consider a "binary" file to be one that: 17720Sstevel@tonic-gate * contains a null character ("diff" doesn't handle them correctly, and 17730Sstevel@tonic-gate * neither do many other UNIX text-processing commands). 17740Sstevel@tonic-gate * Characters with their 8th bit set do NOT make a file binary; they may be 17750Sstevel@tonic-gate * legitimate text characters, or parts of same. 17760Sstevel@tonic-gate */ 17770Sstevel@tonic-gate static int 17780Sstevel@tonic-gate isbinary(char *buf, int cnt) 17790Sstevel@tonic-gate { 17800Sstevel@tonic-gate char *cp; 17810Sstevel@tonic-gate 17820Sstevel@tonic-gate cp = buf; 17830Sstevel@tonic-gate while (--cnt >= 0) 17840Sstevel@tonic-gate if (*cp++ == '\0') 17850Sstevel@tonic-gate return (1); 17860Sstevel@tonic-gate return (0); 17870Sstevel@tonic-gate } 17880Sstevel@tonic-gate 17890Sstevel@tonic-gate 17900Sstevel@tonic-gate /* 17910Sstevel@tonic-gate * THIS IS CRUDE. 17920Sstevel@tonic-gate */ 17930Sstevel@tonic-gate static int 17940Sstevel@tonic-gate useless(char *cp) 17950Sstevel@tonic-gate { 17960Sstevel@tonic-gate 17970Sstevel@tonic-gate if (cp[0] == '.') { 17980Sstevel@tonic-gate if (cp[1] == '\0') 17990Sstevel@tonic-gate return (1); /* directory "." */ 18000Sstevel@tonic-gate if (cp[1] == '.' && cp[2] == '\0') 18010Sstevel@tonic-gate return (1); /* directory ".." */ 18020Sstevel@tonic-gate } 18030Sstevel@tonic-gate if (start && strcmp(start, cp) > 0) 18040Sstevel@tonic-gate return (1); 18050Sstevel@tonic-gate return (0); 18060Sstevel@tonic-gate } 18070Sstevel@tonic-gate 18080Sstevel@tonic-gate 18090Sstevel@tonic-gate void 18100Sstevel@tonic-gate sort(struct line *a, int n) /* shellsort CACM #201 */ 18110Sstevel@tonic-gate { 18120Sstevel@tonic-gate struct line w; 18130Sstevel@tonic-gate int j, m; 18140Sstevel@tonic-gate struct line *ai; 18150Sstevel@tonic-gate struct line *aim; 18160Sstevel@tonic-gate int k; 18170Sstevel@tonic-gate 18180Sstevel@tonic-gate for (j = 1, m = 0; j <= n; j *= 2) 18190Sstevel@tonic-gate m = 2 * j - 1; 18200Sstevel@tonic-gate for (m /= 2; m != 0; m /= 2) { 18210Sstevel@tonic-gate k = n - m; 18220Sstevel@tonic-gate for (j = 1; j <= k; j++) { 18230Sstevel@tonic-gate for (ai = &a[j]; ai > a; ai -= m) { 18240Sstevel@tonic-gate aim = &ai[m]; 18250Sstevel@tonic-gate if (aim < ai) 18260Sstevel@tonic-gate break; /* wraparound */ 18270Sstevel@tonic-gate if (aim->value > ai[0].value || 18280Sstevel@tonic-gate aim->value == ai[0].value && 18290Sstevel@tonic-gate aim->serial > ai[0].serial) 18300Sstevel@tonic-gate break; 18310Sstevel@tonic-gate w.value = ai[0].value; 18320Sstevel@tonic-gate ai[0].value = aim->value; 18330Sstevel@tonic-gate aim->value = w.value; 18340Sstevel@tonic-gate w.serial = ai[0].serial; 18350Sstevel@tonic-gate ai[0].serial = aim->serial; 18360Sstevel@tonic-gate aim->serial = w.serial; 18370Sstevel@tonic-gate } 18380Sstevel@tonic-gate } 18390Sstevel@tonic-gate } 18400Sstevel@tonic-gate } 18410Sstevel@tonic-gate 18420Sstevel@tonic-gate static void 18430Sstevel@tonic-gate unsort(struct line *f, int l, int *b) 18440Sstevel@tonic-gate { 18450Sstevel@tonic-gate int *a; 18460Sstevel@tonic-gate int i; 18470Sstevel@tonic-gate 18480Sstevel@tonic-gate a = (int *)talloc((l + 1) * sizeof (int)); 18490Sstevel@tonic-gate for (i = 1; i <= l; i++) 18500Sstevel@tonic-gate a[f[i].serial] = f[i].value; 18510Sstevel@tonic-gate for (i = 1; i <= l; i++) 18520Sstevel@tonic-gate b[i] = a[i]; 18530Sstevel@tonic-gate free((char *)a); 18540Sstevel@tonic-gate } 18550Sstevel@tonic-gate 18560Sstevel@tonic-gate static void 18570Sstevel@tonic-gate filename(char **pa1, char **pa2, struct stat *st, char **ifile) 18580Sstevel@tonic-gate { 18590Sstevel@tonic-gate char *a1, *b1, *a2; 18600Sstevel@tonic-gate 18610Sstevel@tonic-gate a1 = *pa1; 18620Sstevel@tonic-gate a2 = *pa2; 18630Sstevel@tonic-gate 18640Sstevel@tonic-gate if (strcmp(*pa1, "-") == 0) 18650Sstevel@tonic-gate *ifile = strdup("-"); 18660Sstevel@tonic-gate else 18670Sstevel@tonic-gate *ifile = strdup(*pa1); 18680Sstevel@tonic-gate 18690Sstevel@tonic-gate if (*ifile == (char *)NULL) { 18700Sstevel@tonic-gate (void) fprintf(stderr, gettext( 18710Sstevel@tonic-gate "no more memory - try again later\n")); 18720Sstevel@tonic-gate status = 2; 18730Sstevel@tonic-gate done(); 18740Sstevel@tonic-gate } 18750Sstevel@tonic-gate 18760Sstevel@tonic-gate if ((st->st_mode & S_IFMT) == S_IFDIR) { 18770Sstevel@tonic-gate b1 = *pa1 = (char *)malloc(PATH_MAX); 18780Sstevel@tonic-gate while (*b1++ = *a1++) 18790Sstevel@tonic-gate ; 18800Sstevel@tonic-gate b1[-1] = '/'; 18810Sstevel@tonic-gate a1 = b1; 18820Sstevel@tonic-gate while (*a1++ = *a2++) 18830Sstevel@tonic-gate if (*a2 && *a2 != '/' && a2[-1] == '/') 18840Sstevel@tonic-gate a1 = b1; 18850Sstevel@tonic-gate *ifile = strdup(*pa1); 18860Sstevel@tonic-gate 18870Sstevel@tonic-gate if (*ifile == (char *)NULL) { 18880Sstevel@tonic-gate (void) fprintf(stderr, gettext( 18890Sstevel@tonic-gate "no more memory - try again later\n")); 18900Sstevel@tonic-gate status = 2; 18910Sstevel@tonic-gate done(); 18920Sstevel@tonic-gate } 18930Sstevel@tonic-gate 18940Sstevel@tonic-gate if (stat(*pa1, st) < 0) { 18950Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 18960Sstevel@tonic-gate perror(*pa1); 18970Sstevel@tonic-gate done(); 18980Sstevel@tonic-gate } 18990Sstevel@tonic-gate } else if ((st->st_mode & S_IFMT) == S_IFCHR) 19000Sstevel@tonic-gate *pa1 = copytemp(a1); 19010Sstevel@tonic-gate else if (a1[0] == '-' && a1[1] == 0) { 19020Sstevel@tonic-gate *pa1 = copytemp(a1); /* hack! */ 19030Sstevel@tonic-gate if (stat(*pa1, st) < 0) { 19040Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 19050Sstevel@tonic-gate perror(*pa1); 19060Sstevel@tonic-gate done(); 19070Sstevel@tonic-gate } 19080Sstevel@tonic-gate } 19090Sstevel@tonic-gate } 19100Sstevel@tonic-gate 19110Sstevel@tonic-gate static char * 19120Sstevel@tonic-gate copytemp(char *fn) 19130Sstevel@tonic-gate { 19140Sstevel@tonic-gate int ifd, ofd; /* input and output file descriptors */ 19150Sstevel@tonic-gate int i; 19160Sstevel@tonic-gate char template[13]; /* template for temp file name */ 19170Sstevel@tonic-gate char buf[BUFSIZ]; 19180Sstevel@tonic-gate 19190Sstevel@tonic-gate /* 19200Sstevel@tonic-gate * a "-" file is interpreted as fd 0 for pre-/dev/fd systems 19210Sstevel@tonic-gate * ... let's hope this goes away soon! 19220Sstevel@tonic-gate */ 19230Sstevel@tonic-gate if ((ifd = (strcmp(fn, "-") ? open(fn, 0) : 0)) < 0) { 19240Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 19250Sstevel@tonic-gate (void) fprintf(stderr, gettext("cannot open %s\n"), fn); 19260Sstevel@tonic-gate done(); 19270Sstevel@tonic-gate } 19280Sstevel@tonic-gate (void) signal(SIGHUP, (void (*)(int))done); 19290Sstevel@tonic-gate (void) signal(SIGINT, (void (*)(int))done); 19300Sstevel@tonic-gate (void) signal(SIGPIPE, (void (*)(int))done); 19310Sstevel@tonic-gate (void) signal(SIGTERM, (void (*)(int))done); 19320Sstevel@tonic-gate (void) strcpy(template, "/tmp/dXXXXXX"); 19330Sstevel@tonic-gate if ((ofd = mkstemp(template)) < 0) { 19340Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 19350Sstevel@tonic-gate (void) fprintf(stderr, gettext("cannot create %s\n"), template); 19360Sstevel@tonic-gate done(); 19370Sstevel@tonic-gate } 19380Sstevel@tonic-gate (void) strcpy(tempfile[whichtemp++], template); 19390Sstevel@tonic-gate while ((i = read(ifd, buf, BUFSIZ)) > 0) 19400Sstevel@tonic-gate if (write(ofd, buf, i) != i) { 19410Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 19420Sstevel@tonic-gate (void) fprintf(stderr, 19430Sstevel@tonic-gate gettext("write failed %s\n"), template); 19440Sstevel@tonic-gate done(); 19450Sstevel@tonic-gate } 19460Sstevel@tonic-gate (void) close(ifd); (void) close(ofd); 19470Sstevel@tonic-gate return (tempfile[whichtemp-1]); 19480Sstevel@tonic-gate } 19490Sstevel@tonic-gate 19500Sstevel@tonic-gate static void 19510Sstevel@tonic-gate prepare(int i, char *arg) 19520Sstevel@tonic-gate { 19530Sstevel@tonic-gate struct line *p; 19540Sstevel@tonic-gate int j, h; 19550Sstevel@tonic-gate 19560Sstevel@tonic-gate (void) fseek(input[i], (long)0, SEEK_SET); 19570Sstevel@tonic-gate p = (struct line *)talloc(3 * sizeof (line)); 19580Sstevel@tonic-gate for (j = 0; h = readhash(input[i], i, arg); ) { 19590Sstevel@tonic-gate p = (struct line *)ralloc((void *)p, (++j + 3) * sizeof (line)); 19600Sstevel@tonic-gate p[j].value = h; 19610Sstevel@tonic-gate } 19620Sstevel@tonic-gate len[i] = j; 19630Sstevel@tonic-gate file[i] = p; 19640Sstevel@tonic-gate } 19650Sstevel@tonic-gate 19660Sstevel@tonic-gate static void 19670Sstevel@tonic-gate prune(void) 19680Sstevel@tonic-gate { 19690Sstevel@tonic-gate int i, j; 19700Sstevel@tonic-gate 19710Sstevel@tonic-gate for (pref = 0; pref < len[0] && pref < len[1] && 19720Sstevel@tonic-gate file[0][pref + 1].value == file[1][pref + 1].value; 19730Sstevel@tonic-gate pref++) 19740Sstevel@tonic-gate ; 19750Sstevel@tonic-gate for (suff = 0; (suff < len[0] - pref) && 19760Sstevel@tonic-gate (suff < len[1] - pref) && 19770Sstevel@tonic-gate (file[0][len[0] - suff].value == 19780Sstevel@tonic-gate file[1][len[1] - suff].value); 19790Sstevel@tonic-gate suff++) 19800Sstevel@tonic-gate ; 19810Sstevel@tonic-gate 19820Sstevel@tonic-gate /* decremnt suff by 2 iff suff >= 2, ensure that suff is never < 0 */ 19830Sstevel@tonic-gate if (suff >= 2) 19840Sstevel@tonic-gate suff -= 2; 19850Sstevel@tonic-gate 19860Sstevel@tonic-gate for (j = 0; j < 2; j++) { 19870Sstevel@tonic-gate sfile[j] = file[j] + pref; 19880Sstevel@tonic-gate slen[j] = len[j] - pref - suff; 19890Sstevel@tonic-gate for (i = 0; i <= slen[j]; i++) 19900Sstevel@tonic-gate sfile[j][i].serial = i; 19910Sstevel@tonic-gate } 19920Sstevel@tonic-gate } 19930Sstevel@tonic-gate 19940Sstevel@tonic-gate static void 19950Sstevel@tonic-gate equiv(struct line *a, int n, struct line *b, int m, int *c) 19960Sstevel@tonic-gate { 19970Sstevel@tonic-gate int i, j; 19980Sstevel@tonic-gate i = j = 1; 19990Sstevel@tonic-gate while (i <= n && j <= m) { 20000Sstevel@tonic-gate if (a[i].value < b[j].value) 20010Sstevel@tonic-gate a[i++].value = 0; 20020Sstevel@tonic-gate else if (a[i].value == b[j].value) 20030Sstevel@tonic-gate a[i++].value = j; 20040Sstevel@tonic-gate else 20050Sstevel@tonic-gate j++; 20060Sstevel@tonic-gate } 20070Sstevel@tonic-gate while (i <= n) 20080Sstevel@tonic-gate a[i++].value = 0; 20090Sstevel@tonic-gate b[m+1].value = 0; j = 0; 20100Sstevel@tonic-gate while (++j <= m) { 20110Sstevel@tonic-gate c[j] = -b[j].serial; 20120Sstevel@tonic-gate while (b[j + 1].value == b[j].value) { 20130Sstevel@tonic-gate j++; 20140Sstevel@tonic-gate c[j] = b[j].serial; 20150Sstevel@tonic-gate } 20160Sstevel@tonic-gate } 20170Sstevel@tonic-gate c[j] = -1; 20180Sstevel@tonic-gate } 20190Sstevel@tonic-gate 20200Sstevel@tonic-gate static void 20210Sstevel@tonic-gate done(void) 20220Sstevel@tonic-gate { 20230Sstevel@tonic-gate if (whichtemp) (void) unlink(tempfile[0]); 20240Sstevel@tonic-gate if (whichtemp == 2) (void) unlink(tempfile[1]); 20250Sstevel@tonic-gate exit(status); 20260Sstevel@tonic-gate } 20270Sstevel@tonic-gate 20280Sstevel@tonic-gate static void 20290Sstevel@tonic-gate noroom(void) 20300Sstevel@tonic-gate { 20310Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 20320Sstevel@tonic-gate (void) fprintf(stderr, gettext("files too big, try -h\n")); 20330Sstevel@tonic-gate done(); 20340Sstevel@tonic-gate } 20350Sstevel@tonic-gate 20360Sstevel@tonic-gate static void 20370Sstevel@tonic-gate error(const char *s) 20380Sstevel@tonic-gate { 20390Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 20400Sstevel@tonic-gate (void) fprintf(stderr, s); 20410Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 20420Sstevel@tonic-gate done(); 20430Sstevel@tonic-gate } 20440Sstevel@tonic-gate 20450Sstevel@tonic-gate static void 20460Sstevel@tonic-gate usage(void) 20470Sstevel@tonic-gate { 20480Sstevel@tonic-gate (void) fprintf(stderr, gettext( 20490Sstevel@tonic-gate "usage: diff [-bitw] [-c | -e | -f | -h | -n | -u] file1 " 20500Sstevel@tonic-gate "file2\n" 20510Sstevel@tonic-gate " diff [-bitw] [-C number | -U number] file1 file2\n" 20520Sstevel@tonic-gate " diff [-bitw] [-D string] file1 file2\n" 20530Sstevel@tonic-gate " diff [-bitw] [-c | -e | -f | -h | -n | -u] [-l] [-r] " 20540Sstevel@tonic-gate "[-s] [-S name] directory1 directory2\n")); 20550Sstevel@tonic-gate status = 2; 20560Sstevel@tonic-gate done(); 20570Sstevel@tonic-gate } 20580Sstevel@tonic-gate 20590Sstevel@tonic-gate #define NW 1024 20600Sstevel@tonic-gate struct buff { 20610Sstevel@tonic-gate FILE *iop; /* I/O stream */ 20620Sstevel@tonic-gate char buf[NW + MB_LEN_MAX]; /* buffer */ 20630Sstevel@tonic-gate char *ptr; /* current pointer in the buffer */ 20640Sstevel@tonic-gate int buffered; /* if non-zero, buffer has data */ 20650Sstevel@tonic-gate long offset; /* offset in the file */ 20660Sstevel@tonic-gate }; 20670Sstevel@tonic-gate 20680Sstevel@tonic-gate static struct buff bufwchar[2]; 20690Sstevel@tonic-gate 20700Sstevel@tonic-gate /* 20710Sstevel@tonic-gate * Initializes the buff structure for specified 20720Sstevel@tonic-gate * I/O stream. Also sets the specified offset 20730Sstevel@tonic-gate */ 20740Sstevel@tonic-gate static void 20750Sstevel@tonic-gate initbuf(FILE *iop, int filen, long offset) 20760Sstevel@tonic-gate { 20770Sstevel@tonic-gate bufwchar[filen].iop = iop; 20780Sstevel@tonic-gate bufwchar[filen].ptr = NULL; 20790Sstevel@tonic-gate bufwchar[filen].buffered = 0; 20800Sstevel@tonic-gate bufwchar[filen].offset = offset; 20810Sstevel@tonic-gate } 20820Sstevel@tonic-gate 20830Sstevel@tonic-gate /* 20840Sstevel@tonic-gate * Reset a buff structure, and rewind the associated file. 20850Sstevel@tonic-gate */ 20860Sstevel@tonic-gate static void 20870Sstevel@tonic-gate resetbuf(int filen) 20880Sstevel@tonic-gate { 20890Sstevel@tonic-gate bufwchar[filen].ptr = NULL; 20900Sstevel@tonic-gate bufwchar[filen].buffered = bufwchar[filen].offset = 0; 20910Sstevel@tonic-gate rewind(bufwchar[filen].iop); 20920Sstevel@tonic-gate } 20930Sstevel@tonic-gate 20940Sstevel@tonic-gate 20950Sstevel@tonic-gate /* 20960Sstevel@tonic-gate * Returns the current offset in the file 20970Sstevel@tonic-gate */ 20980Sstevel@tonic-gate static long 20990Sstevel@tonic-gate ftellbuf(int filen) 21000Sstevel@tonic-gate { 21010Sstevel@tonic-gate return (bufwchar[filen].offset); 21020Sstevel@tonic-gate } 21030Sstevel@tonic-gate 21040Sstevel@tonic-gate static wint_t 21050Sstevel@tonic-gate wcput(wint_t wc) 21060Sstevel@tonic-gate { 21070Sstevel@tonic-gate char mbs[MB_LEN_MAX]; 21080Sstevel@tonic-gate unsigned char *p; 21090Sstevel@tonic-gate int n; 21100Sstevel@tonic-gate 21110Sstevel@tonic-gate n = wctomb(mbs, (wchar_t)wc); 21120Sstevel@tonic-gate if (n > 0) { 21130Sstevel@tonic-gate p = (unsigned char *)mbs; 21140Sstevel@tonic-gate while (n--) { 21150Sstevel@tonic-gate (void) putc((*p++), stdout); 21160Sstevel@tonic-gate } 21170Sstevel@tonic-gate return (wc); 21180Sstevel@tonic-gate } else if (n < 0) { 21190Sstevel@tonic-gate (void) putc((int)(wc & 0xff), stdout); 21200Sstevel@tonic-gate return (wc & 0xff); 21210Sstevel@tonic-gate } else { 21220Sstevel@tonic-gate /* this should not happen */ 21230Sstevel@tonic-gate return (WEOF); 21240Sstevel@tonic-gate } 21250Sstevel@tonic-gate } 21260Sstevel@tonic-gate 21270Sstevel@tonic-gate /* 21280Sstevel@tonic-gate * Reads one wide-character from the file associated with filen. 21290Sstevel@tonic-gate * If multibyte locales, the input is buffered. 21300Sstevel@tonic-gate * 21310Sstevel@tonic-gate * Input: filen the file number (0 or 1) 21320Sstevel@tonic-gate * Output: *len number of bytes to make wide-character 21330Sstevel@tonic-gate * Return: wide-character 21340Sstevel@tonic-gate */ 21350Sstevel@tonic-gate static wint_t 21360Sstevel@tonic-gate getbufwchar(int filen, int *len) 21370Sstevel@tonic-gate { 21380Sstevel@tonic-gate 21390Sstevel@tonic-gate int i, num, clen; 21400Sstevel@tonic-gate wchar_t wc; 21410Sstevel@tonic-gate size_t mxlen; 21420Sstevel@tonic-gate 21430Sstevel@tonic-gate if (mbcurmax == 1) { 21440Sstevel@tonic-gate /* If sigle byte locale, use getc() */ 21450Sstevel@tonic-gate int ch; 21460Sstevel@tonic-gate 21470Sstevel@tonic-gate ch = getc(bufwchar[filen].iop); 21480Sstevel@tonic-gate bufwchar[filen].offset++; 21490Sstevel@tonic-gate *len = 1; 21500Sstevel@tonic-gate 21510Sstevel@tonic-gate if (isascii(ch) || (ch == EOF)) { 21520Sstevel@tonic-gate return ((wint_t)ch); 21530Sstevel@tonic-gate } else { 21540Sstevel@tonic-gate wchar_t wc; 21550Sstevel@tonic-gate char str[2] = {0, 0}; 21560Sstevel@tonic-gate 21570Sstevel@tonic-gate str[0] = (char)ch; 21580Sstevel@tonic-gate if (mbtowc(&wc, str, 1) > 0) { 21590Sstevel@tonic-gate return ((wint_t)wc); 21600Sstevel@tonic-gate } else { 21610Sstevel@tonic-gate return ((wint_t)ch); 21620Sstevel@tonic-gate } 21630Sstevel@tonic-gate } 21640Sstevel@tonic-gate } else { 21650Sstevel@tonic-gate mxlen = mbcurmax; 21660Sstevel@tonic-gate } 21670Sstevel@tonic-gate 21680Sstevel@tonic-gate if (bufwchar[filen].buffered == 0) { 21690Sstevel@tonic-gate /* Not buffered */ 21700Sstevel@tonic-gate bufwchar[filen].ptr = &(bufwchar[filen].buf[MB_LEN_MAX]); 21710Sstevel@tonic-gate num = fread((void *)bufwchar[filen].ptr, 21720Sstevel@tonic-gate sizeof (char), NW, bufwchar[filen].iop); 21730Sstevel@tonic-gate if (ferror(bufwchar[filen].iop)) { 21740Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 21750Sstevel@tonic-gate (void) fprintf(stderr, gettext("Error reading ")); 21760Sstevel@tonic-gate perror((filen == 0) ? file1 : file2); 21770Sstevel@tonic-gate status = 2; 21780Sstevel@tonic-gate done(); 21790Sstevel@tonic-gate } 21800Sstevel@tonic-gate if (num == 0) 21810Sstevel@tonic-gate return (WEOF); 21820Sstevel@tonic-gate bufwchar[filen].buffered = num; 21830Sstevel@tonic-gate } 21840Sstevel@tonic-gate 21850Sstevel@tonic-gate if (bufwchar[filen].buffered < mbcurmax) { 21860Sstevel@tonic-gate for (i = 0; i < bufwchar[filen].buffered; i++) { 21870Sstevel@tonic-gate bufwchar[filen].buf[MB_LEN_MAX - 21880Sstevel@tonic-gate (bufwchar[filen].buffered - i)] = 21890Sstevel@tonic-gate *(bufwchar[filen].ptr + i); 21900Sstevel@tonic-gate } 21910Sstevel@tonic-gate bufwchar[filen].ptr = &(bufwchar[filen].buf[MB_LEN_MAX]); 21920Sstevel@tonic-gate num = fread((void *)bufwchar[filen].ptr, 21930Sstevel@tonic-gate sizeof (char), NW, bufwchar[filen].iop); 21940Sstevel@tonic-gate if (ferror(bufwchar[filen].iop)) { 21950Sstevel@tonic-gate (void) fprintf(stderr, "diff: "); 21960Sstevel@tonic-gate (void) fprintf(stderr, gettext("Error reading ")); 21970Sstevel@tonic-gate perror((filen == 0) ? file1 : file2); 21980Sstevel@tonic-gate status = 2; 21990Sstevel@tonic-gate done(); 22000Sstevel@tonic-gate } 22010Sstevel@tonic-gate bufwchar[filen].ptr = &(bufwchar[filen].buf[MB_LEN_MAX - 22020Sstevel@tonic-gate bufwchar[filen].buffered]); 22030Sstevel@tonic-gate bufwchar[filen].buffered += num; 22040Sstevel@tonic-gate if (bufwchar[filen].buffered < mbcurmax) { 22050Sstevel@tonic-gate mxlen = bufwchar[filen].buffered; 22060Sstevel@tonic-gate } 22070Sstevel@tonic-gate } 22080Sstevel@tonic-gate 22090Sstevel@tonic-gate clen = mbtowc(&wc, bufwchar[filen].ptr, mxlen); 22100Sstevel@tonic-gate if (clen <= 0) { 22110Sstevel@tonic-gate (bufwchar[filen].buffered)--; 22120Sstevel@tonic-gate *len = 1; 22130Sstevel@tonic-gate (bufwchar[filen].offset)++; 22140Sstevel@tonic-gate wc = (wchar_t)((unsigned char)*bufwchar[filen].ptr++); 22150Sstevel@tonic-gate return ((wint_t)wc); 22160Sstevel@tonic-gate } else { 22170Sstevel@tonic-gate bufwchar[filen].buffered -= clen; 22180Sstevel@tonic-gate bufwchar[filen].ptr += clen; 22190Sstevel@tonic-gate bufwchar[filen].offset += clen; 22200Sstevel@tonic-gate *len = clen; 22210Sstevel@tonic-gate return ((wint_t)wc); 22220Sstevel@tonic-gate } 22230Sstevel@tonic-gate } 2224