1*c72ea322Smillert /* $OpenBSD: diffreg.c,v 1.33 2003/07/15 23:17:56 millert Exp $ */ 2d0c3f575Sderaadt 3d0c3f575Sderaadt /* 4d0c3f575Sderaadt * Copyright (C) Caldera International Inc. 2001-2002. 5d0c3f575Sderaadt * All rights reserved. 6d0c3f575Sderaadt * 7d0c3f575Sderaadt * Redistribution and use in source and binary forms, with or without 8d0c3f575Sderaadt * modification, are permitted provided that the following conditions 9d0c3f575Sderaadt * are met: 10d0c3f575Sderaadt * 1. Redistributions of source code and documentation must retain the above 11d0c3f575Sderaadt * copyright notice, this list of conditions and the following disclaimer. 12d0c3f575Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 13d0c3f575Sderaadt * notice, this list of conditions and the following disclaimer in the 14d0c3f575Sderaadt * documentation and/or other materials provided with the distribution. 15d0c3f575Sderaadt * 3. All advertising materials mentioning features or use of this software 16d0c3f575Sderaadt * must display the following acknowledgement: 17d0c3f575Sderaadt * This product includes software developed or owned by Caldera 18d0c3f575Sderaadt * International, Inc. 19d0c3f575Sderaadt * 4. Neither the name of Caldera International, Inc. nor the names of other 20d0c3f575Sderaadt * contributors may be used to endorse or promote products derived from 21d0c3f575Sderaadt * this software without specific prior written permission. 22d0c3f575Sderaadt * 23d0c3f575Sderaadt * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 24d0c3f575Sderaadt * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 25d0c3f575Sderaadt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26d0c3f575Sderaadt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27d0c3f575Sderaadt * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 28d0c3f575Sderaadt * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29d0c3f575Sderaadt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30d0c3f575Sderaadt * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31d0c3f575Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32d0c3f575Sderaadt * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33d0c3f575Sderaadt * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34d0c3f575Sderaadt * POSSIBILITY OF SUCH DAMAGE. 35d0c3f575Sderaadt */ 364ec4b3d5Smillert /*- 374ec4b3d5Smillert * Copyright (c) 1991, 1993 384ec4b3d5Smillert * The Regents of the University of California. All rights reserved. 394ec4b3d5Smillert * 404ec4b3d5Smillert * Redistribution and use in source and binary forms, with or without 414ec4b3d5Smillert * modification, are permitted provided that the following conditions 424ec4b3d5Smillert * are met: 434ec4b3d5Smillert * 1. Redistributions of source code must retain the above copyright 444ec4b3d5Smillert * notice, this list of conditions and the following disclaimer. 454ec4b3d5Smillert * 2. Redistributions in binary form must reproduce the above copyright 464ec4b3d5Smillert * notice, this list of conditions and the following disclaimer in the 474ec4b3d5Smillert * documentation and/or other materials provided with the distribution. 484ec4b3d5Smillert * 3. Neither the name of the University nor the names of its contributors 494ec4b3d5Smillert * may be used to endorse or promote products derived from this software 504ec4b3d5Smillert * without specific prior written permission. 514ec4b3d5Smillert * 524ec4b3d5Smillert * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 534ec4b3d5Smillert * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 544ec4b3d5Smillert * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 554ec4b3d5Smillert * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 564ec4b3d5Smillert * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 574ec4b3d5Smillert * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 584ec4b3d5Smillert * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 594ec4b3d5Smillert * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 604ec4b3d5Smillert * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 614ec4b3d5Smillert * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 624ec4b3d5Smillert * SUCH DAMAGE. 634ec4b3d5Smillert * 644ec4b3d5Smillert * @(#)diffreg.c 8.1 (Berkeley) 6/6/93 654ec4b3d5Smillert */ 664ec4b3d5Smillert 674ec4b3d5Smillert #ifndef lint 68*c72ea322Smillert static const char rcsid[] = "$OpenBSD: diffreg.c,v 1.33 2003/07/15 23:17:56 millert Exp $"; 694ec4b3d5Smillert #endif /* not lint */ 70d0c3f575Sderaadt 717b6ec9e4Smillert #include <sys/param.h> 724ec4b3d5Smillert #include <sys/stat.h> 73b4bca33fSmillert #include <sys/wait.h> 7426da422aStedu 754ec4b3d5Smillert #include <ctype.h> 764ec4b3d5Smillert #include <err.h> 777b6ec9e4Smillert #include <errno.h> 7826da422aStedu #include <fcntl.h> 794ec4b3d5Smillert #include <libgen.h> 804ec4b3d5Smillert #include <stdio.h> 814ec4b3d5Smillert #include <stdlib.h> 8226da422aStedu #include <string.h> 834ec4b3d5Smillert #include <unistd.h> 84ae8d569bSderaadt 85ae8d569bSderaadt #include "diff.h" 86b4bca33fSmillert #include "pathnames.h" 8726da422aStedu 88ae8d569bSderaadt /* 89ae8d569bSderaadt * diff - compare two files. 90ae8d569bSderaadt */ 91ae8d569bSderaadt 92ae8d569bSderaadt /* 93ae8d569bSderaadt * Uses an algorithm due to Harold Stone, which finds 94ae8d569bSderaadt * a pair of longest identical subsequences in the two 95ae8d569bSderaadt * files. 96ae8d569bSderaadt * 97ae8d569bSderaadt * The major goal is to generate the match vector J. 98ae8d569bSderaadt * J[i] is the index of the line in file1 corresponding 99ae8d569bSderaadt * to line i file0. J[i] = 0 if there is no 100ae8d569bSderaadt * such line in file1. 101ae8d569bSderaadt * 102ae8d569bSderaadt * Lines are hashed so as to work in core. All potential 103ae8d569bSderaadt * matches are located by sorting the lines of each file 104ae8d569bSderaadt * on the hash (called ``value''). In particular, this 105ae8d569bSderaadt * collects the equivalence classes in file1 together. 106ae8d569bSderaadt * Subroutine equiv replaces the value of each line in 107ae8d569bSderaadt * file0 by the index of the first element of its 108ae8d569bSderaadt * matching equivalence in (the reordered) file1. 109ae8d569bSderaadt * To save space equiv squeezes file1 into a single 110ae8d569bSderaadt * array member in which the equivalence classes 111ae8d569bSderaadt * are simply concatenated, except that their first 112ae8d569bSderaadt * members are flagged by changing sign. 113ae8d569bSderaadt * 114ae8d569bSderaadt * Next the indices that point into member are unsorted into 115ae8d569bSderaadt * array class according to the original order of file0. 116ae8d569bSderaadt * 117ae8d569bSderaadt * The cleverness lies in routine stone. This marches 118ae8d569bSderaadt * through the lines of file0, developing a vector klist 119ae8d569bSderaadt * of "k-candidates". At step i a k-candidate is a matched 120ae8d569bSderaadt * pair of lines x,y (x in file0 y in file1) such that 121ae8d569bSderaadt * there is a common subsequence of length k 122ae8d569bSderaadt * between the first i lines of file0 and the first y 123ae8d569bSderaadt * lines of file1, but there is no such subsequence for 124ae8d569bSderaadt * any smaller y. x is the earliest possible mate to y 125ae8d569bSderaadt * that occurs in such a subsequence. 126ae8d569bSderaadt * 127ae8d569bSderaadt * Whenever any of the members of the equivalence class of 128ae8d569bSderaadt * lines in file1 matable to a line in file0 has serial number 129ae8d569bSderaadt * less than the y of some k-candidate, that k-candidate 130ae8d569bSderaadt * with the smallest such y is replaced. The new 131ae8d569bSderaadt * k-candidate is chained (via pred) to the current 132ae8d569bSderaadt * k-1 candidate so that the actual subsequence can 133ae8d569bSderaadt * be recovered. When a member has serial number greater 134ae8d569bSderaadt * that the y of all k-candidates, the klist is extended. 135ae8d569bSderaadt * At the end, the longest subsequence is pulled out 136ae8d569bSderaadt * and placed in the array J by unravel 137ae8d569bSderaadt * 138ae8d569bSderaadt * With J in hand, the matches there recorded are 139ae8d569bSderaadt * check'ed against reality to assure that no spurious 140ae8d569bSderaadt * matches have crept in due to hashing. If they have, 141ae8d569bSderaadt * they are broken, and "jackpot" is recorded--a harmless 142ae8d569bSderaadt * matter except that a true match for a spuriously 143ae8d569bSderaadt * mated line may now be unnecessarily reported as a change. 144ae8d569bSderaadt * 145ae8d569bSderaadt * Much of the complexity of the program comes simply 146ae8d569bSderaadt * from trying to minimize core utilization and 147ae8d569bSderaadt * maximize the range of doable problems by dynamically 148ae8d569bSderaadt * allocating what is needed and reusing what is not. 149ae8d569bSderaadt * The core requirements for problems larger than somewhat 150ae8d569bSderaadt * are (in words) 2*length(file0) + length(file1) + 151ae8d569bSderaadt * 3*(number of k-candidates installed), typically about 152ae8d569bSderaadt * 6n words for files of length n. 153ae8d569bSderaadt */ 154ae8d569bSderaadt 155ae8d569bSderaadt struct cand { 156ae8d569bSderaadt int x; 157ae8d569bSderaadt int y; 158ae8d569bSderaadt int pred; 159ae8d569bSderaadt } cand; 16026da422aStedu 161ae8d569bSderaadt struct line { 162ae8d569bSderaadt int serial; 163ae8d569bSderaadt int value; 16492af4c2dStedu } *file[2]; 16526da422aStedu 1664ec4b3d5Smillert static int *J; /* will be overlaid on class */ 1674ec4b3d5Smillert static int *class; /* will be overlaid on file[0] */ 1684ec4b3d5Smillert static int *klist; /* will be overlaid on file[0] after class */ 1694ec4b3d5Smillert static int *member; /* will be overlaid on file[1] */ 1704ec4b3d5Smillert static int clen; 1714ec4b3d5Smillert static int inifdef; /* whether or not we are in a #ifdef block */ 1724ec4b3d5Smillert static int len[2]; 1734ec4b3d5Smillert static int pref, suff; /* length of prefix and suffix */ 1744ec4b3d5Smillert static int slen[2]; 1754ec4b3d5Smillert static int anychange; 1764ec4b3d5Smillert static long *ixnew; /* will be overlaid on file[1] */ 1774ec4b3d5Smillert static long *ixold; /* will be overlaid on klist */ 1784ec4b3d5Smillert static struct cand *clist; /* merely a free storage pot for candidates */ 1794ec4b3d5Smillert static struct line *sfile[2]; /* shortened by pruning common prefix/suffix */ 1804ec4b3d5Smillert static u_char *chrtran; /* translation table for case-folding */ 181ae8d569bSderaadt 1827b6ec9e4Smillert static FILE *opentemp(const char *); 18326da422aStedu static void fetch(long *, int, int, FILE *, char *, int); 1844ec4b3d5Smillert static void output(char *, FILE *, char *, FILE *); 1854ec4b3d5Smillert static void check(char *, FILE *, char *, FILE *); 18626da422aStedu static void range(int, int, char *); 187*c72ea322Smillert static void uni_range(int, int); 1884ec4b3d5Smillert static void dump_context_vec(FILE *, FILE *); 1894ec4b3d5Smillert static void dump_unified_vec(FILE *, FILE *); 19026da422aStedu static void prepare(int, FILE *); 19126da422aStedu static void prune(void); 19226da422aStedu static void equiv(struct line *, int, struct line *, int, int *); 19326da422aStedu static void unravel(int); 19426da422aStedu static void unsort(struct line *, int, int *); 1954ec4b3d5Smillert static void change(char *, FILE *, char *, FILE *, int, int, int, int); 19626da422aStedu static void sort(struct line *, int); 1974ec4b3d5Smillert static int asciifile(FILE *); 19826da422aStedu static int newcand(int, int, int); 19926da422aStedu static int search(int *, int, int); 2004ec4b3d5Smillert static int skipline(FILE *); 20126da422aStedu static int stone(int *, int, int *, int *); 20226da422aStedu static int readhash(FILE *); 2034ec4b3d5Smillert static int files_differ(FILE *, FILE *, int); 20426da422aStedu 20526da422aStedu /* 20626da422aStedu * chrtran points to one of 2 translation tables: cup2low if folding upper to 20726da422aStedu * lower case clow2low if not folding case 208ae8d569bSderaadt */ 2098a15d8deSderaadt u_char clow2low[256] = { 21026da422aStedu 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 21126da422aStedu 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 21226da422aStedu 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 21326da422aStedu 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 21426da422aStedu 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 21526da422aStedu 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 21626da422aStedu 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 21726da422aStedu 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 21826da422aStedu 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 21926da422aStedu 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 22026da422aStedu 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 22126da422aStedu 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 22226da422aStedu 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 22326da422aStedu 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 22426da422aStedu 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 22526da422aStedu 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 22626da422aStedu 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 22726da422aStedu 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 22826da422aStedu 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 22926da422aStedu 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 23026da422aStedu 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 23126da422aStedu 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 23226da422aStedu 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 23326da422aStedu 0xfd, 0xfe, 0xff 234ae8d569bSderaadt }; 235ae8d569bSderaadt 2368a15d8deSderaadt u_char cup2low[256] = { 23726da422aStedu 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 23826da422aStedu 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 23926da422aStedu 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 24026da422aStedu 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 24126da422aStedu 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 24226da422aStedu 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61, 24326da422aStedu 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 24426da422aStedu 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 24526da422aStedu 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x60, 0x61, 0x62, 24626da422aStedu 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 24726da422aStedu 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 24826da422aStedu 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 24926da422aStedu 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 25026da422aStedu 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 25126da422aStedu 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 25226da422aStedu 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 25326da422aStedu 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 25426da422aStedu 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 25526da422aStedu 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 25626da422aStedu 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 25726da422aStedu 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 25826da422aStedu 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 25926da422aStedu 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 26026da422aStedu 0xfd, 0xfe, 0xff 261ae8d569bSderaadt }; 262ae8d569bSderaadt 263b4bca33fSmillert int 2644ec4b3d5Smillert diffreg(char *ofile1, char *ofile2, int flags) 265ae8d569bSderaadt { 2664ec4b3d5Smillert char *file1 = ofile1; 2674ec4b3d5Smillert char *file2 = ofile2; 2684ec4b3d5Smillert FILE *f1 = NULL; 2694ec4b3d5Smillert FILE *f2 = NULL; 270b4bca33fSmillert int rval = D_SAME; 271b4bca33fSmillert int i, ostdout = -1; 272b4bca33fSmillert pid_t pid = -1; 273ae8d569bSderaadt 2744ec4b3d5Smillert anychange = 0; 275ae8d569bSderaadt chrtran = (iflag ? cup2low : clow2low); 2767b6ec9e4Smillert if (S_ISDIR(stb1.st_mode) != S_ISDIR(stb2.st_mode)) 2777b6ec9e4Smillert return (D_MISMATCH); 27866e5764eSmillert if (strcmp(file1, "-") == 0 && strcmp(file2, "-") == 0) 2794ec4b3d5Smillert goto notsame; 2804ec4b3d5Smillert 2814ec4b3d5Smillert if (flags & D_EMPTY1) 2824ec4b3d5Smillert f1 = fopen(_PATH_DEVNULL, "r"); 2834ec4b3d5Smillert else { 2847b6ec9e4Smillert if (!S_ISREG(stb1.st_mode)) { 2857b6ec9e4Smillert if ((f1 = opentemp(file1)) == NULL || 2867b6ec9e4Smillert fstat(fileno(f1), &stb1) < 0) { 2874ec4b3d5Smillert warn("%s", file1); 2884ec4b3d5Smillert status |= 2; 2894ec4b3d5Smillert goto closem; 29048b947b7Smillert } 2917b6ec9e4Smillert } else if (strcmp(file1, "-") == 0) 292b1a26502Smillert f1 = stdin; 293b1a26502Smillert else 2944ec4b3d5Smillert f1 = fopen(file1, "r"); 2954ec4b3d5Smillert } 2964ec4b3d5Smillert if (f1 == NULL) { 2974ec4b3d5Smillert warn("%s", file1); 2984ec4b3d5Smillert status |= 2; 2994ec4b3d5Smillert goto closem; 3004ec4b3d5Smillert } 3014ec4b3d5Smillert 3024ec4b3d5Smillert if (flags & D_EMPTY2) 3034ec4b3d5Smillert f2 = fopen(_PATH_DEVNULL, "r"); 3044ec4b3d5Smillert else { 3057b6ec9e4Smillert if (!S_ISREG(stb2.st_mode)) { 3067b6ec9e4Smillert if ((f2 = opentemp(file2)) == NULL || 3077b6ec9e4Smillert fstat(fileno(f2), &stb2) < 0) { 3084ec4b3d5Smillert warn("%s", file2); 3094ec4b3d5Smillert status |= 2; 3104ec4b3d5Smillert goto closem; 3114ec4b3d5Smillert } 3127b6ec9e4Smillert } else if (strcmp(file2, "-") == 0) 313b1a26502Smillert f2 = stdin; 314b1a26502Smillert else 3154ec4b3d5Smillert f2 = fopen(file2, "r"); 3164ec4b3d5Smillert } 3174ec4b3d5Smillert if (f2 == NULL) { 3184ec4b3d5Smillert warn("%s", file2); 3194ec4b3d5Smillert status |= 2; 3204ec4b3d5Smillert goto closem; 3214ec4b3d5Smillert } 3224ec4b3d5Smillert 3234ec4b3d5Smillert switch (files_differ(f1, f2, flags)) { 3244ec4b3d5Smillert case 0: 325b4bca33fSmillert goto closem; 3264ec4b3d5Smillert case 1: 3274ec4b3d5Smillert break; 3284ec4b3d5Smillert default: 3294ec4b3d5Smillert /* error */ 3304ec4b3d5Smillert status |= 2; 3314ec4b3d5Smillert goto closem; 332ae8d569bSderaadt } 3334ec4b3d5Smillert 334ae8d569bSderaadt notsame: 335ae8d569bSderaadt /* 336ae8d569bSderaadt * Files certainly differ at this point; set status accordingly 337ae8d569bSderaadt */ 3384ec4b3d5Smillert status |= 1; 339b4bca33fSmillert rval = D_DIFFER; 340b4bca33fSmillert if (!asciifile(f1) || !asciifile(f2)) { 341b4bca33fSmillert rval = D_BINARY; 342cab5d83cSmillert goto closem; 343cab5d83cSmillert } 344b4bca33fSmillert if (format == D_BRIEF) 345b4bca33fSmillert goto closem; 346b4bca33fSmillert if (lflag) { 347b4bca33fSmillert /* redirect stdout to pr */ 348b4bca33fSmillert int pfd[2]; 349b4bca33fSmillert char *header; 350b4bca33fSmillert char *prargv[] = { "pr", "-h", NULL, "-f", NULL }; 351b4bca33fSmillert 352b4bca33fSmillert easprintf(&header, "%s %s %s", diffargs, file1, file2); 353b4bca33fSmillert prargv[2] = header; 354b4bca33fSmillert fflush(stdout); 355b4bca33fSmillert rewind(stdout); 356b4bca33fSmillert pipe(pfd); 357b4bca33fSmillert switch ((pid = fork())) { 358b4bca33fSmillert case -1: 359b4bca33fSmillert warnx("No more processes"); 360b4bca33fSmillert status |= 2; 361b4bca33fSmillert free(header); 362b4bca33fSmillert return (D_ERROR); 363b4bca33fSmillert case 0: 364b4bca33fSmillert /* child */ 365b4bca33fSmillert if (pfd[0] != STDIN_FILENO) { 366b4bca33fSmillert dup2(pfd[0], STDIN_FILENO); 367b4bca33fSmillert close(pfd[0]); 368b4bca33fSmillert } 369b4bca33fSmillert close(pfd[1]); 370b4bca33fSmillert execv(_PATH_PR, prargv); 371b4bca33fSmillert _exit(127); 372b4bca33fSmillert default: 373b4bca33fSmillert /* parent */ 374b4bca33fSmillert if (pfd[1] != STDOUT_FILENO) { 375b4bca33fSmillert ostdout = dup(STDOUT_FILENO); 376b4bca33fSmillert dup2(pfd[1], STDOUT_FILENO); 377b4bca33fSmillert close(pfd[1]); 378b4bca33fSmillert } 379b4bca33fSmillert close(pfd[0]); 380b4bca33fSmillert rewind(stdout); 381b4bca33fSmillert free(header); 382b4bca33fSmillert } 383b4bca33fSmillert } else { 3844ec4b3d5Smillert if (flags & D_HEADER) { 3854ec4b3d5Smillert if (format == D_EDIT) 386b4bca33fSmillert printf("ed - %s << '-*-END-*-'\n", 387b4bca33fSmillert basename(file1)); 3884ec4b3d5Smillert else 3894ec4b3d5Smillert printf("%s %s %s\n", diffargs, file1, file2); 3904ec4b3d5Smillert } 391ae8d569bSderaadt } 392ae8d569bSderaadt prepare(0, f1); 393ae8d569bSderaadt prepare(1, f2); 394ae8d569bSderaadt prune(); 395ae8d569bSderaadt sort(sfile[0], slen[0]); 396ae8d569bSderaadt sort(sfile[1], slen[1]); 397ae8d569bSderaadt 398ae8d569bSderaadt member = (int *)file[1]; 399ae8d569bSderaadt equiv(sfile[0], slen[0], sfile[1], slen[1], member); 40049dffe13Smillert member = erealloc(member, (slen[1] + 2) * sizeof(int)); 401ae8d569bSderaadt 402ae8d569bSderaadt class = (int *)file[0]; 403ae8d569bSderaadt unsort(sfile[0], slen[0], class); 40449dffe13Smillert class = erealloc(class, (slen[0] + 2) * sizeof(int)); 405ae8d569bSderaadt 40649dffe13Smillert klist = emalloc((slen[0] + 2) * sizeof(int)); 40749dffe13Smillert clist = emalloc(sizeof(cand)); 408ae8d569bSderaadt i = stone(class, slen[0], member, klist); 40926da422aStedu free(member); 41026da422aStedu free(class); 411ae8d569bSderaadt 4124ec4b3d5Smillert J = erealloc(J, (len[0] + 2) * sizeof(int)); 413ae8d569bSderaadt unravel(klist[i]); 41426da422aStedu free(clist); 41526da422aStedu free(klist); 416ae8d569bSderaadt 4174ec4b3d5Smillert ixold = erealloc(ixold, (len[0] + 2) * sizeof(long)); 4184ec4b3d5Smillert ixnew = erealloc(ixnew, (len[1] + 2) * sizeof(long)); 4194ec4b3d5Smillert check(file1, f1, file2, f2); 4204ec4b3d5Smillert output(file1, f1, file2, f2); 421b4bca33fSmillert if (ostdout != -1) { 422b4bca33fSmillert int wstatus; 4234ec4b3d5Smillert 424b4bca33fSmillert /* close the pipe to pr and restore stdout */ 425b4bca33fSmillert fflush(stdout); 426b4bca33fSmillert rewind(stdout); 427b4bca33fSmillert if (ostdout != STDOUT_FILENO) { 428b4bca33fSmillert close(STDOUT_FILENO); 429b4bca33fSmillert dup2(ostdout, STDOUT_FILENO); 430b4bca33fSmillert close(ostdout); 431b4bca33fSmillert } 432b4bca33fSmillert waitpid(pid, &wstatus, 0); 433b4bca33fSmillert } else if ((flags & D_HEADER) && format == D_EDIT) 434b4bca33fSmillert printf("w\nq\n-*-END-*-\n"); 4354ec4b3d5Smillert closem: 4364ec4b3d5Smillert if (f1 != NULL) 4374ec4b3d5Smillert fclose(f1); 4384ec4b3d5Smillert if (f2 != NULL) 4394ec4b3d5Smillert fclose(f2); 4407b6ec9e4Smillert if (file1 != ofile1) 441b1a26502Smillert free(file1); 4427b6ec9e4Smillert if (file2 != ofile2) 4434ec4b3d5Smillert free(file2); 444b4bca33fSmillert return (rval); 4454ec4b3d5Smillert } 4464ec4b3d5Smillert 4474ec4b3d5Smillert /* 4484ec4b3d5Smillert * Check to see if the given files differ. 4494ec4b3d5Smillert * Returns 0 if they are the same, 1 if different, and -1 on error. 4504ec4b3d5Smillert * XXX - could use code from cmp(1) [faster] 4514ec4b3d5Smillert */ 4524ec4b3d5Smillert static int 4534ec4b3d5Smillert files_differ(FILE *f1, FILE *f2, int flags) 4544ec4b3d5Smillert { 4554ec4b3d5Smillert char buf1[BUFSIZ], buf2[BUFSIZ]; 4564ec4b3d5Smillert size_t i, j; 4574ec4b3d5Smillert 4584ec4b3d5Smillert if ((flags & (D_EMPTY1|D_EMPTY2)) || stb1.st_size != stb2.st_size || 4594ec4b3d5Smillert (stb1.st_mode & S_IFMT) != (stb2.st_mode & S_IFMT)) 4604ec4b3d5Smillert return (1); 4614ec4b3d5Smillert for (;;) { 4624ec4b3d5Smillert i = fread(buf1, 1, sizeof(buf1), f1); 4634ec4b3d5Smillert j = fread(buf2, 1, sizeof(buf2), f2); 4644ec4b3d5Smillert if (i != j) 4654ec4b3d5Smillert return (1); 4664ec4b3d5Smillert if (i == 0 && j == 0) { 4674ec4b3d5Smillert if (ferror(f1) || ferror(f2)) 4684ec4b3d5Smillert return (1); 4694ec4b3d5Smillert return (0); 4704ec4b3d5Smillert } 4714ec4b3d5Smillert if (memcmp(buf1, buf2, i) != 0) 4724ec4b3d5Smillert return (1); 4734ec4b3d5Smillert } 474ae8d569bSderaadt } 475ae8d569bSderaadt 4767b6ec9e4Smillert static FILE * 4777b6ec9e4Smillert opentemp(const char *file) 478ae8d569bSderaadt { 4797b6ec9e4Smillert char buf[BUFSIZ], *tempdir, tempfile[MAXPATHLEN]; 4807b6ec9e4Smillert ssize_t nread; 4817b6ec9e4Smillert int ifd, ofd; 48248b947b7Smillert 48348b947b7Smillert if (strcmp(file, "-") == 0) 48448b947b7Smillert ifd = STDIN_FILENO; 48566e5764eSmillert else if ((ifd = open(file, O_RDONLY, 0644)) < 0) 4864ec4b3d5Smillert return (NULL); 48748b947b7Smillert 48848b947b7Smillert if ((tempdir = getenv("TMPDIR")) == NULL) 48948b947b7Smillert tempdir = _PATH_TMP; 4907b6ec9e4Smillert if (snprintf(tempfile, sizeof(tempfile), "%s/diff.XXXXXXXX", 4917b6ec9e4Smillert tempdir) >= sizeof(tempfile)) { 4927b6ec9e4Smillert close(ifd); 4937b6ec9e4Smillert errno = ENAMETOOLONG; 4944ec4b3d5Smillert return (NULL); 495ae8d569bSderaadt } 4967b6ec9e4Smillert 4977b6ec9e4Smillert if ((ofd = mkstemp(tempfile)) < 0) 4987b6ec9e4Smillert return (NULL); 4997b6ec9e4Smillert unlink(tempfile); 5007b6ec9e4Smillert while ((nread = read(ifd, buf, BUFSIZ)) > 0) { 5017b6ec9e4Smillert if (write(ofd, buf, nread) != nread) { 50248b947b7Smillert close(ifd); 50348b947b7Smillert close(ofd); 5047b6ec9e4Smillert return (NULL); 5057b6ec9e4Smillert } 5067b6ec9e4Smillert } 5077b6ec9e4Smillert close(ifd); 5087b6ec9e4Smillert return (fdopen(ofd, "r")); 509ae8d569bSderaadt } 510ae8d569bSderaadt 511ae8d569bSderaadt char * 51226da422aStedu splice(char *dir, char *file) 513ae8d569bSderaadt { 51449dffe13Smillert char *tail, *buf; 515ae8d569bSderaadt 5167b6ec9e4Smillert if ((tail = strrchr(file, '/')) == NULL) 517ae8d569bSderaadt tail = file; 518ae8d569bSderaadt else 519ae8d569bSderaadt tail++; 520b4bca33fSmillert easprintf(&buf, "%s/%s", dir, tail); 52149dffe13Smillert return (buf); 522ae8d569bSderaadt } 523ae8d569bSderaadt 52426da422aStedu static void 52526da422aStedu prepare(int i, FILE *fd) 526ae8d569bSderaadt { 52726da422aStedu struct line *p; 52826da422aStedu int j, h; 529ae8d569bSderaadt 5304ec4b3d5Smillert rewind(fd); 53149dffe13Smillert p = emalloc(3 * sizeof(struct line)); 53226da422aStedu for (j = 0; (h = readhash(fd));) { 53349dffe13Smillert p = erealloc(p, (++j + 3) * sizeof(struct line)); 534ae8d569bSderaadt p[j].value = h; 535ae8d569bSderaadt } 536ae8d569bSderaadt len[i] = j; 537ae8d569bSderaadt file[i] = p; 538ae8d569bSderaadt } 539ae8d569bSderaadt 54026da422aStedu static void 54126da422aStedu prune(void) 542ae8d569bSderaadt { 54326da422aStedu int i, j; 54448b8c3e3Sderaadt 545ae8d569bSderaadt for (pref = 0; pref < len[0] && pref < len[1] && 546ae8d569bSderaadt file[0][pref + 1].value == file[1][pref + 1].value; 5477d2b2b91Sderaadt pref++) 5487d2b2b91Sderaadt ; 549ae8d569bSderaadt for (suff = 0; suff < len[0] - pref && suff < len[1] - pref && 550ae8d569bSderaadt file[0][len[0] - suff].value == file[1][len[1] - suff].value; 5517d2b2b91Sderaadt suff++) 5527d2b2b91Sderaadt ; 553ae8d569bSderaadt for (j = 0; j < 2; j++) { 554ae8d569bSderaadt sfile[j] = file[j] + pref; 555ae8d569bSderaadt slen[j] = len[j] - pref - suff; 556ae8d569bSderaadt for (i = 0; i <= slen[j]; i++) 557ae8d569bSderaadt sfile[j][i].serial = i; 558ae8d569bSderaadt } 559ae8d569bSderaadt } 560ae8d569bSderaadt 56126da422aStedu static void 56226da422aStedu equiv(struct line *a, int n, struct line *b, int m, int *c) 563ae8d569bSderaadt { 56426da422aStedu int i, j; 56548b8c3e3Sderaadt 566ae8d569bSderaadt i = j = 1; 567ae8d569bSderaadt while (i <= n && j <= m) { 568ae8d569bSderaadt if (a[i].value < b[j].value) 569ae8d569bSderaadt a[i++].value = 0; 570ae8d569bSderaadt else if (a[i].value == b[j].value) 571ae8d569bSderaadt a[i++].value = j; 572ae8d569bSderaadt else 573ae8d569bSderaadt j++; 574ae8d569bSderaadt } 575ae8d569bSderaadt while (i <= n) 576ae8d569bSderaadt a[i++].value = 0; 577ae8d569bSderaadt b[m + 1].value = 0; 578ae8d569bSderaadt j = 0; 579ae8d569bSderaadt while (++j <= m) { 580ae8d569bSderaadt c[j] = -b[j].serial; 581ae8d569bSderaadt while (b[j + 1].value == b[j].value) { 582ae8d569bSderaadt j++; 583ae8d569bSderaadt c[j] = b[j].serial; 584ae8d569bSderaadt } 585ae8d569bSderaadt } 586ae8d569bSderaadt c[j] = -1; 587ae8d569bSderaadt } 588ae8d569bSderaadt 58926da422aStedu static int 59026da422aStedu stone(int *a, int n, int *b, int *c) 591ae8d569bSderaadt { 59248b8c3e3Sderaadt int i, k, y, j, l; 59348b8c3e3Sderaadt int oldc, tc, oldl; 59448b8c3e3Sderaadt 595ae8d569bSderaadt k = 0; 596ae8d569bSderaadt c[0] = newcand(0, 0, 0); 597ae8d569bSderaadt for (i = 1; i <= n; i++) { 598ae8d569bSderaadt j = a[i]; 599ae8d569bSderaadt if (j == 0) 600ae8d569bSderaadt continue; 601ae8d569bSderaadt y = -b[j]; 602ae8d569bSderaadt oldl = 0; 603ae8d569bSderaadt oldc = c[0]; 604ae8d569bSderaadt do { 605ae8d569bSderaadt if (y <= clist[oldc].y) 606ae8d569bSderaadt continue; 607ae8d569bSderaadt l = search(c, k, y); 608ae8d569bSderaadt if (l != oldl + 1) 609ae8d569bSderaadt oldc = c[l - 1]; 610ae8d569bSderaadt if (l <= k) { 611ae8d569bSderaadt if (clist[c[l]].y <= y) 612ae8d569bSderaadt continue; 613ae8d569bSderaadt tc = c[l]; 614ae8d569bSderaadt c[l] = newcand(i, y, oldc); 615ae8d569bSderaadt oldc = tc; 616ae8d569bSderaadt oldl = l; 617ae8d569bSderaadt } else { 618ae8d569bSderaadt c[l] = newcand(i, y, oldc); 619ae8d569bSderaadt k++; 620ae8d569bSderaadt break; 621ae8d569bSderaadt } 622ae8d569bSderaadt } while ((y = b[++j]) > 0); 623ae8d569bSderaadt } 624ae8d569bSderaadt return (k); 625ae8d569bSderaadt } 626ae8d569bSderaadt 62726da422aStedu static int 62826da422aStedu newcand(int x, int y, int pred) 629ae8d569bSderaadt { 63026da422aStedu struct cand *q; 63126da422aStedu 63249dffe13Smillert clist = erealloc(clist, ++clen * sizeof(cand)); 633ae8d569bSderaadt q = clist + clen - 1; 634ae8d569bSderaadt q->x = x; 635ae8d569bSderaadt q->y = y; 636ae8d569bSderaadt q->pred = pred; 637ae8d569bSderaadt return (clen - 1); 638ae8d569bSderaadt } 639ae8d569bSderaadt 64026da422aStedu static int 64126da422aStedu search(int *c, int k, int y) 642ae8d569bSderaadt { 64348b8c3e3Sderaadt int i, j, l, t; 64448b8c3e3Sderaadt 645ae8d569bSderaadt if (clist[c[k]].y < y) /* quick look for typical case */ 646ae8d569bSderaadt return (k + 1); 647ae8d569bSderaadt i = 0; 648ae8d569bSderaadt j = k + 1; 649ae8d569bSderaadt while (1) { 650ae8d569bSderaadt l = i + j; 651ae8d569bSderaadt if ((l >>= 1) <= i) 652ae8d569bSderaadt break; 653ae8d569bSderaadt t = clist[c[l]].y; 654ae8d569bSderaadt if (t > y) 655ae8d569bSderaadt j = l; 656ae8d569bSderaadt else if (t < y) 657ae8d569bSderaadt i = l; 658ae8d569bSderaadt else 659ae8d569bSderaadt return (l); 660ae8d569bSderaadt } 661ae8d569bSderaadt return (l + 1); 662ae8d569bSderaadt } 663ae8d569bSderaadt 66426da422aStedu static void 66526da422aStedu unravel(int p) 666ae8d569bSderaadt { 66726da422aStedu struct cand *q; 66848b8c3e3Sderaadt int i; 66948b8c3e3Sderaadt 670ae8d569bSderaadt for (i = 0; i <= len[0]; i++) 671ae8d569bSderaadt J[i] = i <= pref ? i : 6727d2b2b91Sderaadt i > len[0] - suff ? i + len[1] - len[0] : 0; 673ae8d569bSderaadt for (q = clist + p; q->y != 0; q = clist + q->pred) 674ae8d569bSderaadt J[q->x + pref] = q->y + pref; 675ae8d569bSderaadt } 676ae8d569bSderaadt 67726da422aStedu /* 67849dffe13Smillert * Check does double duty: 67949dffe13Smillert * 1. ferret out any fortuitous correspondences due 68049dffe13Smillert * to confounding by hashing (which result in "jackpot") 68149dffe13Smillert * 2. collect random access indexes to the two files 68226da422aStedu */ 68326da422aStedu static void 6844ec4b3d5Smillert check(char *file1, FILE *f1, char *file2, FILE *f2) 685ae8d569bSderaadt { 68648b8c3e3Sderaadt int i, j, jackpot, c, d; 687ae8d569bSderaadt long ctold, ctnew; 688ae8d569bSderaadt 6894ec4b3d5Smillert rewind(f1); 6904ec4b3d5Smillert rewind(f2); 691ae8d569bSderaadt j = 1; 692ae8d569bSderaadt ixold[0] = ixnew[0] = 0; 693ae8d569bSderaadt jackpot = 0; 694ae8d569bSderaadt ctold = ctnew = 0; 695ae8d569bSderaadt for (i = 1; i <= len[0]; i++) { 696ae8d569bSderaadt if (J[i] == 0) { 6974ec4b3d5Smillert ixold[i] = ctold += skipline(f1); 698ae8d569bSderaadt continue; 699ae8d569bSderaadt } 700ae8d569bSderaadt while (j < J[i]) { 7014ec4b3d5Smillert ixnew[j] = ctnew += skipline(f2); 702ae8d569bSderaadt j++; 703ae8d569bSderaadt } 704ae8d569bSderaadt if (bflag || wflag || iflag) { 705ae8d569bSderaadt for (;;) { 7064ec4b3d5Smillert c = getc(f1); 7074ec4b3d5Smillert d = getc(f2); 708ae8d569bSderaadt ctold++; 709ae8d569bSderaadt ctnew++; 710ae8d569bSderaadt if (bflag && isspace(c) && isspace(d)) { 711ae8d569bSderaadt do { 712ae8d569bSderaadt if (c == '\n') 713ae8d569bSderaadt break; 714ae8d569bSderaadt ctold++; 7154ec4b3d5Smillert } while (isspace(c = getc(f1))); 716ae8d569bSderaadt do { 717ae8d569bSderaadt if (d == '\n') 718ae8d569bSderaadt break; 719ae8d569bSderaadt ctnew++; 7204ec4b3d5Smillert } while (isspace(d = getc(f2))); 721ae8d569bSderaadt } else if (wflag) { 722ae8d569bSderaadt while (isspace(c) && c != '\n') { 7234ec4b3d5Smillert c = getc(f1); 724ae8d569bSderaadt ctold++; 725ae8d569bSderaadt } 726ae8d569bSderaadt while (isspace(d) && d != '\n') { 7274ec4b3d5Smillert d = getc(f2); 728ae8d569bSderaadt ctnew++; 729ae8d569bSderaadt } 730ae8d569bSderaadt } 731ae8d569bSderaadt if (chrtran[c] != chrtran[d]) { 732ae8d569bSderaadt jackpot++; 733ae8d569bSderaadt J[i] = 0; 734ae8d569bSderaadt if (c != '\n') 7354ec4b3d5Smillert ctold += skipline(f1); 736ae8d569bSderaadt if (d != '\n') 7374ec4b3d5Smillert ctnew += skipline(f2); 738ae8d569bSderaadt break; 739ae8d569bSderaadt } 740ae8d569bSderaadt if (c == '\n') 741ae8d569bSderaadt break; 742ae8d569bSderaadt } 743ae8d569bSderaadt } else { 744ae8d569bSderaadt for (;;) { 745ae8d569bSderaadt ctold++; 746ae8d569bSderaadt ctnew++; 7474ec4b3d5Smillert if ((c = getc(f1)) != (d = getc(f2))) { 748ae8d569bSderaadt /* jackpot++; */ 749ae8d569bSderaadt J[i] = 0; 750ae8d569bSderaadt if (c != '\n') 7514ec4b3d5Smillert ctold += skipline(f1); 752ae8d569bSderaadt if (d != '\n') 7534ec4b3d5Smillert ctnew += skipline(f2); 754ae8d569bSderaadt break; 755ae8d569bSderaadt } 756ae8d569bSderaadt if (c == '\n') 757ae8d569bSderaadt break; 758ae8d569bSderaadt } 759ae8d569bSderaadt } 760ae8d569bSderaadt ixold[i] = ctold; 761ae8d569bSderaadt ixnew[j] = ctnew; 762ae8d569bSderaadt j++; 763ae8d569bSderaadt } 7644ec4b3d5Smillert for (; j <= len[1]; j++) 7654ec4b3d5Smillert ixnew[j] = ctnew += skipline(f2); 766ae8d569bSderaadt /* 76748b8c3e3Sderaadt * if (jackpot) 76848b8c3e3Sderaadt * fprintf(stderr, "jackpot\n"); 769ae8d569bSderaadt */ 770ae8d569bSderaadt } 771ae8d569bSderaadt 77248b8c3e3Sderaadt /* shellsort CACM #201 */ 77326da422aStedu static void 77426da422aStedu sort(struct line *a, int n) 77548b8c3e3Sderaadt { 77648b8c3e3Sderaadt struct line *ai, *aim, w; 77748b8c3e3Sderaadt int j, m = 0, k; 778ae8d569bSderaadt 779ae8d569bSderaadt if (n == 0) 780ae8d569bSderaadt return; 781ae8d569bSderaadt for (j = 1; j <= n; j *= 2) 782ae8d569bSderaadt m = 2 * j - 1; 783ae8d569bSderaadt for (m /= 2; m != 0; m /= 2) { 784ae8d569bSderaadt k = n - m; 785ae8d569bSderaadt for (j = 1; j <= k; j++) { 786ae8d569bSderaadt for (ai = &a[j]; ai > a; ai -= m) { 787ae8d569bSderaadt aim = &ai[m]; 788ae8d569bSderaadt if (aim < ai) 789ae8d569bSderaadt break; /* wraparound */ 790ae8d569bSderaadt if (aim->value > ai[0].value || 79126da422aStedu (aim->value == ai[0].value && 79226da422aStedu aim->serial > ai[0].serial)) 793ae8d569bSderaadt break; 794ae8d569bSderaadt w.value = ai[0].value; 795ae8d569bSderaadt ai[0].value = aim->value; 796ae8d569bSderaadt aim->value = w.value; 797ae8d569bSderaadt w.serial = ai[0].serial; 798ae8d569bSderaadt ai[0].serial = aim->serial; 799ae8d569bSderaadt aim->serial = w.serial; 800ae8d569bSderaadt } 801ae8d569bSderaadt } 802ae8d569bSderaadt } 803ae8d569bSderaadt } 804ae8d569bSderaadt 80526da422aStedu static void 80626da422aStedu unsort(struct line *f, int l, int *b) 807ae8d569bSderaadt { 80848b8c3e3Sderaadt int *a, i; 80926da422aStedu 81049dffe13Smillert a = emalloc((l + 1) * sizeof(int)); 811ae8d569bSderaadt for (i = 1; i <= l; i++) 812ae8d569bSderaadt a[f[i].serial] = f[i].value; 813ae8d569bSderaadt for (i = 1; i <= l; i++) 814ae8d569bSderaadt b[i] = a[i]; 81526da422aStedu free(a); 816ae8d569bSderaadt } 817ae8d569bSderaadt 81826da422aStedu static int 8194ec4b3d5Smillert skipline(FILE *f) 820ae8d569bSderaadt { 82126da422aStedu int i, c; 822ae8d569bSderaadt 8234ec4b3d5Smillert for (i = 1; (c = getc(f)) != '\n'; i++) 824ae8d569bSderaadt if (c < 0) 825ae8d569bSderaadt return (i); 826ae8d569bSderaadt return (i); 827ae8d569bSderaadt } 828ae8d569bSderaadt 82926da422aStedu static void 8304ec4b3d5Smillert output(char *file1, FILE *f1, char *file2, FILE *f2) 831ae8d569bSderaadt { 83248b8c3e3Sderaadt int m, i0, i1, j0, j1; 83348b8c3e3Sderaadt 8344ec4b3d5Smillert rewind(f1); 8354ec4b3d5Smillert rewind(f2); 836ae8d569bSderaadt m = len[0]; 837ae8d569bSderaadt J[0] = 0; 838ae8d569bSderaadt J[m + 1] = len[1] + 1; 8394ec4b3d5Smillert if (format != D_EDIT) { 84026da422aStedu for (i0 = 1; i0 <= m; i0 = i1 + 1) { 84126da422aStedu while (i0 <= m && J[i0] == J[i0 - 1] + 1) 84226da422aStedu i0++; 843ae8d569bSderaadt j0 = J[i0 - 1] + 1; 844ae8d569bSderaadt i1 = i0 - 1; 84526da422aStedu while (i1 < m && J[i1 + 1] == 0) 84626da422aStedu i1++; 847ae8d569bSderaadt j1 = J[i1 + 1] - 1; 848ae8d569bSderaadt J[i1] = j1; 8494ec4b3d5Smillert change(file1, f1, file2, f2, i0, i1, j0, j1); 85026da422aStedu } 85126da422aStedu } else { 85226da422aStedu for (i0 = m; i0 >= 1; i0 = i1 - 1) { 85326da422aStedu while (i0 >= 1 && J[i0] == J[i0 + 1] - 1 && J[i0] != 0) 85426da422aStedu i0--; 855ae8d569bSderaadt j0 = J[i0 + 1] - 1; 856ae8d569bSderaadt i1 = i0 + 1; 85726da422aStedu while (i1 > 1 && J[i1 - 1] == 0) 85826da422aStedu i1--; 859ae8d569bSderaadt j1 = J[i1 - 1] + 1; 860ae8d569bSderaadt J[i1] = j1; 8614ec4b3d5Smillert change(file1, f1, file2, f2, i1, i0, j1, j0); 862ae8d569bSderaadt } 86326da422aStedu } 864ae8d569bSderaadt if (m == 0) 8654ec4b3d5Smillert change(file1, f1, file2, f2, 1, 0, 1, len[1]); 8664ec4b3d5Smillert if (format == D_IFDEF) { 867ae8d569bSderaadt for (;;) { 868ae8d569bSderaadt #define c i0 8694ec4b3d5Smillert c = getc(f1); 870ae8d569bSderaadt if (c < 0) 871ae8d569bSderaadt return; 872ae8d569bSderaadt putchar(c); 873ae8d569bSderaadt } 874ae8d569bSderaadt #undef c 875ae8d569bSderaadt } 8769de32c1bSmillert if (anychange != 0) { 8774ec4b3d5Smillert if (format == D_CONTEXT) 8784ec4b3d5Smillert dump_context_vec(f1, f2); 8794ec4b3d5Smillert else if (format == D_UNIFIED) 8804ec4b3d5Smillert dump_unified_vec(f1, f2); 8819de32c1bSmillert } 882ae8d569bSderaadt } 883ae8d569bSderaadt 884*c72ea322Smillert static __inline void 885*c72ea322Smillert range(int a, int b, char *separator) 886*c72ea322Smillert { 887*c72ea322Smillert printf("%d", a > b ? b : a); 888*c72ea322Smillert if (a < b) 889*c72ea322Smillert printf("%s%d", separator, b); 890*c72ea322Smillert } 891*c72ea322Smillert 892*c72ea322Smillert static __inline void 893*c72ea322Smillert uni_range(int a, int b) 894*c72ea322Smillert { 895*c72ea322Smillert if (a < b) 896*c72ea322Smillert printf("%d,%d", a, b - a + 1); 897*c72ea322Smillert else if (a == b) 898*c72ea322Smillert printf("%d", b); 899*c72ea322Smillert else 900*c72ea322Smillert printf("%d,0", b); 901*c72ea322Smillert } 902*c72ea322Smillert 903ae8d569bSderaadt /* 904ae8d569bSderaadt * The following struct is used to record change information when 9054ec4b3d5Smillert * doing a "context" or "unified" diff. (see routine "change" to 9064ec4b3d5Smillert * understand the highly mnemonic field names) 907ae8d569bSderaadt */ 908ae8d569bSderaadt struct context_vec { 909ae8d569bSderaadt int a; /* start line in old file */ 910ae8d569bSderaadt int b; /* end line in old file */ 911ae8d569bSderaadt int c; /* start line in new file */ 912ae8d569bSderaadt int d; /* end line in new file */ 913ae8d569bSderaadt }; 914ae8d569bSderaadt 91526da422aStedu struct context_vec *context_vec_start, *context_vec_end, *context_vec_ptr; 916ae8d569bSderaadt 917ae8d569bSderaadt #define MAX_CONTEXT 128 918ae8d569bSderaadt 91926da422aStedu /* 9204ec4b3d5Smillert * Indicate that there is a difference between lines a and b of the from file 92126da422aStedu * to get to lines c to d of the to file. If a is greater then b then there 92226da422aStedu * are no lines in the from file involved and this means that there were 92326da422aStedu * lines appended (beginning at b). If c is greater than d then there are 92426da422aStedu * lines missing from the to file. 925ae8d569bSderaadt */ 92626da422aStedu static void 9274ec4b3d5Smillert change(char *file1, FILE *f1, char *file2, FILE *f2, int a, int b, int c, int d) 928ae8d569bSderaadt { 9294ec4b3d5Smillert if (format != D_IFDEF && a > b && c > d) 930ae8d569bSderaadt return; 931ae8d569bSderaadt if (anychange == 0) { 932ae8d569bSderaadt anychange = 1; 9334ec4b3d5Smillert if (format == D_CONTEXT || format == D_UNIFIED) { 9344ec4b3d5Smillert printf("%s %s %s", format == D_CONTEXT ? "***" : "---", 9354ec4b3d5Smillert file1, ctime(&stb1.st_mtime)); 9364ec4b3d5Smillert printf("%s %s %s", format == D_CONTEXT ? "---" : "+++", 9374ec4b3d5Smillert file2, ctime(&stb2.st_mtime)); 9384ec4b3d5Smillert if (context_vec_start == NULL) 93949dffe13Smillert context_vec_start = emalloc(MAX_CONTEXT * 940ae8d569bSderaadt sizeof(struct context_vec)); 941ae8d569bSderaadt context_vec_end = context_vec_start + MAX_CONTEXT; 942ae8d569bSderaadt context_vec_ptr = context_vec_start - 1; 943ae8d569bSderaadt } 944ae8d569bSderaadt } 9454ec4b3d5Smillert if (format == D_CONTEXT || format == D_UNIFIED) { 946ae8d569bSderaadt /* 94790f56ad8Smillert * If this new change is within 'context' lines of 948ae8d569bSderaadt * the previous change, just add it to the change 949ae8d569bSderaadt * record. If the record is full or if this 950ae8d569bSderaadt * change is more than 'context' lines from the previous 951ae8d569bSderaadt * change, dump the record, reset it & add the new change. 952ae8d569bSderaadt */ 953ae8d569bSderaadt if (context_vec_ptr >= context_vec_end || 954ae8d569bSderaadt (context_vec_ptr >= context_vec_start && 955ae8d569bSderaadt a > (context_vec_ptr->b + 2 * context) && 9569de32c1bSmillert c > (context_vec_ptr->d + 2 * context))) { 9574ec4b3d5Smillert if (format == D_CONTEXT) 9584ec4b3d5Smillert dump_context_vec(f1, f2); 9599de32c1bSmillert else 9604ec4b3d5Smillert dump_unified_vec(f1, f2); 9619de32c1bSmillert } 962ae8d569bSderaadt context_vec_ptr++; 963ae8d569bSderaadt context_vec_ptr->a = a; 964ae8d569bSderaadt context_vec_ptr->b = b; 965ae8d569bSderaadt context_vec_ptr->c = c; 966ae8d569bSderaadt context_vec_ptr->d = d; 967ae8d569bSderaadt return; 968ae8d569bSderaadt } 9694ec4b3d5Smillert switch (format) { 970ae8d569bSderaadt 971ae8d569bSderaadt case D_NORMAL: 972ae8d569bSderaadt case D_EDIT: 973ae8d569bSderaadt range(a, b, ","); 974ae8d569bSderaadt putchar(a > b ? 'a' : c > d ? 'd' : 'c'); 9754ec4b3d5Smillert if (format == D_NORMAL) 976ae8d569bSderaadt range(c, d, ","); 977ae8d569bSderaadt putchar('\n'); 978ae8d569bSderaadt break; 979ae8d569bSderaadt case D_REVERSE: 980ae8d569bSderaadt putchar(a > b ? 'a' : c > d ? 'd' : 'c'); 981ae8d569bSderaadt range(a, b, " "); 982ae8d569bSderaadt putchar('\n'); 983ae8d569bSderaadt break; 984ae8d569bSderaadt case D_NREVERSE: 985ae8d569bSderaadt if (a > b) 986ae8d569bSderaadt printf("a%d %d\n", b, d - c + 1); 987ae8d569bSderaadt else { 988ae8d569bSderaadt printf("d%d %d\n", a, b - a + 1); 989ae8d569bSderaadt if (!(c > d)) 990ae8d569bSderaadt /* add changed lines */ 991ae8d569bSderaadt printf("a%d %d\n", b, d - c + 1); 992ae8d569bSderaadt } 993ae8d569bSderaadt break; 994ae8d569bSderaadt } 9954ec4b3d5Smillert if (format == D_NORMAL || format == D_IFDEF) { 9964ec4b3d5Smillert fetch(ixold, a, b, f1, "< ", 1); 9974ec4b3d5Smillert if (a <= b && c <= d && format == D_NORMAL) 9984ec4b3d5Smillert puts("---"); 999ae8d569bSderaadt } 10004ec4b3d5Smillert fetch(ixnew, c, d, f2, format == D_NORMAL ? "> " : "", 0); 10014ec4b3d5Smillert if ((format == D_EDIT || format == D_REVERSE) && c <= d) 10024ec4b3d5Smillert puts("."); 1003ae8d569bSderaadt if (inifdef) { 1004b4bca33fSmillert printf("#endif /* %s */\n", ifdefname); 1005ae8d569bSderaadt inifdef = 0; 1006ae8d569bSderaadt } 1007ae8d569bSderaadt } 1008ae8d569bSderaadt 100926da422aStedu static void 101026da422aStedu fetch(long *f, int a, int b, FILE *lb, char *s, int oldfile) 1011ae8d569bSderaadt { 101248b8c3e3Sderaadt int i, j, c, col, nc; 1013ae8d569bSderaadt 1014ae8d569bSderaadt /* 1015ae8d569bSderaadt * When doing #ifdef's, copy down to current line 1016ae8d569bSderaadt * if this is the first file, so that stuff makes it to output. 1017ae8d569bSderaadt */ 10184ec4b3d5Smillert if (format == D_IFDEF && oldfile) { 1019ae8d569bSderaadt long curpos = ftell(lb); 1020ae8d569bSderaadt /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ 1021ae8d569bSderaadt nc = f[a > b ? b : a - 1] - curpos; 1022ae8d569bSderaadt for (i = 0; i < nc; i++) 1023ae8d569bSderaadt putchar(getc(lb)); 1024ae8d569bSderaadt } 1025ae8d569bSderaadt if (a > b) 1026ae8d569bSderaadt return; 10274ec4b3d5Smillert if (format == D_IFDEF) { 102890f56ad8Smillert if (inifdef) { 1029b4bca33fSmillert printf("#else /* %s%s */\n", 103090f56ad8Smillert oldfile == 1 ? "!" : "", ifdefname); 103126da422aStedu } else { 103290f56ad8Smillert if (oldfile) 1033b4bca33fSmillert printf("#ifndef %s\n", ifdefname); 103490f56ad8Smillert else 1035b4bca33fSmillert printf("#ifdef %s\n", ifdefname); 1036ae8d569bSderaadt } 1037ae8d569bSderaadt inifdef = 1 + oldfile; 1038ae8d569bSderaadt } 1039ae8d569bSderaadt for (i = a; i <= b; i++) { 104091cf91eeSderaadt fseek(lb, f[i - 1], SEEK_SET); 1041ae8d569bSderaadt nc = f[i] - f[i - 1]; 10424ec4b3d5Smillert if (format != D_IFDEF) 10434ec4b3d5Smillert fputs(s, stdout); 1044ae8d569bSderaadt col = 0; 1045ae8d569bSderaadt for (j = 0; j < nc; j++) { 1046ae8d569bSderaadt c = getc(lb); 1047ae8d569bSderaadt if (c == '\t' && tflag) 1048ae8d569bSderaadt do 1049ae8d569bSderaadt putchar(' '); 10507d9f164dStedu while (++col & 7); 1051ae8d569bSderaadt else { 1052ae8d569bSderaadt putchar(c); 1053ae8d569bSderaadt col++; 1054ae8d569bSderaadt } 1055ae8d569bSderaadt } 1056ae8d569bSderaadt } 1057ae8d569bSderaadt } 1058ae8d569bSderaadt 1059ae8d569bSderaadt #define POW2 /* define only if HALFLONG is 2**n */ 1060ae8d569bSderaadt #define HALFLONG 16 1061ae8d569bSderaadt #define low(x) (x&((1L<<HALFLONG)-1)) 1062ae8d569bSderaadt #define high(x) (x>>HALFLONG) 1063ae8d569bSderaadt 1064ae8d569bSderaadt /* 1065ae8d569bSderaadt * hashing has the effect of 1066ae8d569bSderaadt * arranging line in 7-bit bytes and then 1067ae8d569bSderaadt * summing 1-s complement in 16-bit hunks 1068ae8d569bSderaadt */ 106926da422aStedu static int 107026da422aStedu readhash(FILE *f) 1071ae8d569bSderaadt { 107248b8c3e3Sderaadt unsigned int shift; 107348b8c3e3Sderaadt int t, space; 107426da422aStedu long sum; 1075ae8d569bSderaadt 1076ae8d569bSderaadt sum = 1; 1077ae8d569bSderaadt space = 0; 1078ae8d569bSderaadt if (!bflag && !wflag) { 1079ae8d569bSderaadt if (iflag) 1080ae8d569bSderaadt for (shift = 0; (t = getc(f)) != '\n'; shift += 7) { 1081ae8d569bSderaadt if (t == -1) 1082ae8d569bSderaadt return (0); 1083ae8d569bSderaadt sum += (long)chrtran[t] << (shift 1084ae8d569bSderaadt #ifdef POW2 1085ae8d569bSderaadt &= HALFLONG - 1); 1086ae8d569bSderaadt #else 1087ae8d569bSderaadt %= HALFLONG); 1088ae8d569bSderaadt #endif 1089ae8d569bSderaadt } 1090ae8d569bSderaadt else 1091ae8d569bSderaadt for (shift = 0; (t = getc(f)) != '\n'; shift += 7) { 1092ae8d569bSderaadt if (t == -1) 1093ae8d569bSderaadt return (0); 1094ae8d569bSderaadt sum += (long)t << (shift 1095ae8d569bSderaadt #ifdef POW2 1096ae8d569bSderaadt &= HALFLONG - 1); 1097ae8d569bSderaadt #else 1098ae8d569bSderaadt %= HALFLONG); 1099ae8d569bSderaadt #endif 1100ae8d569bSderaadt } 1101ae8d569bSderaadt } else { 1102ae8d569bSderaadt for (shift = 0;;) { 1103ae8d569bSderaadt switch (t = getc(f)) { 1104ae8d569bSderaadt case -1: 1105ae8d569bSderaadt return (0); 1106ae8d569bSderaadt case '\t': 1107ae8d569bSderaadt case ' ': 1108ae8d569bSderaadt space++; 1109ae8d569bSderaadt continue; 1110ae8d569bSderaadt default: 1111ae8d569bSderaadt if (space && !wflag) { 1112ae8d569bSderaadt shift += 7; 1113ae8d569bSderaadt space = 0; 1114ae8d569bSderaadt } 1115ae8d569bSderaadt sum += (long)chrtran[t] << (shift 1116ae8d569bSderaadt #ifdef POW2 1117ae8d569bSderaadt &= HALFLONG - 1); 1118ae8d569bSderaadt #else 1119ae8d569bSderaadt %= HALFLONG); 1120ae8d569bSderaadt #endif 1121ae8d569bSderaadt shift += 7; 1122ae8d569bSderaadt continue; 1123ae8d569bSderaadt case '\n': 1124ae8d569bSderaadt break; 1125ae8d569bSderaadt } 1126ae8d569bSderaadt break; 1127ae8d569bSderaadt } 1128ae8d569bSderaadt } 1129ae8d569bSderaadt sum = low(sum) + high(sum); 1130ae8d569bSderaadt return ((short) low(sum) + (short) high(sum)); 1131ae8d569bSderaadt } 1132ae8d569bSderaadt 11334ec4b3d5Smillert int 113426da422aStedu asciifile(FILE *f) 1135ae8d569bSderaadt { 113648b8c3e3Sderaadt char buf[BUFSIZ], *cp; 113726da422aStedu int cnt; 1138ae8d569bSderaadt 11394ec4b3d5Smillert if (aflag || f == NULL) 11402a1593dfStedu return (1); 11412a1593dfStedu 11424ec4b3d5Smillert rewind(f); 11434ec4b3d5Smillert cnt = fread(buf, 1, sizeof(buf), f); 1144ae8d569bSderaadt cp = buf; 1145ae8d569bSderaadt while (--cnt >= 0) 1146ae8d569bSderaadt if (*cp++ & 0200) 1147ae8d569bSderaadt return (0); 1148ae8d569bSderaadt return (1); 1149ae8d569bSderaadt } 1150ae8d569bSderaadt 11514ec4b3d5Smillert static __inline int min(int a, int b) 11524ec4b3d5Smillert { 11534ec4b3d5Smillert return (a < b ? a : b); 11544ec4b3d5Smillert } 11554ec4b3d5Smillert 11564ec4b3d5Smillert static __inline int max(int a, int b) 11574ec4b3d5Smillert { 11584ec4b3d5Smillert return (a > b ? a : b); 11594ec4b3d5Smillert } 11604ec4b3d5Smillert 1161ae8d569bSderaadt /* dump accumulated "context" diff changes */ 116226da422aStedu static void 11634ec4b3d5Smillert dump_context_vec(FILE *f1, FILE *f2) 1164ae8d569bSderaadt { 116548b8c3e3Sderaadt struct context_vec *cvp = context_vec_start; 116648b8c3e3Sderaadt int lowa, upb, lowc, upd, do_output; 116726da422aStedu int a, b, c, d; 116826da422aStedu char ch; 1169ae8d569bSderaadt 117090f56ad8Smillert if (context_vec_start > context_vec_ptr) 1171ae8d569bSderaadt return; 1172ae8d569bSderaadt 117326da422aStedu b = d = 0; /* gcc */ 1174ae8d569bSderaadt lowa = max(1, cvp->a - context); 1175ae8d569bSderaadt upb = min(len[0], context_vec_ptr->b + context); 1176ae8d569bSderaadt lowc = max(1, cvp->c - context); 1177ae8d569bSderaadt upd = min(len[1], context_vec_ptr->d + context); 1178ae8d569bSderaadt 1179ae8d569bSderaadt printf("***************\n*** "); 1180ae8d569bSderaadt range(lowa, upb, ","); 1181ae8d569bSderaadt printf(" ****\n"); 1182ae8d569bSderaadt 1183ae8d569bSderaadt /* 11844ec4b3d5Smillert * Output changes to the "old" file. The first loop suppresses 1185ae8d569bSderaadt * output if there were no changes to the "old" file (we'll see 1186ae8d569bSderaadt * the "old" lines as context in the "new" list). 1187ae8d569bSderaadt */ 1188ae8d569bSderaadt do_output = 0; 1189ae8d569bSderaadt for (; cvp <= context_vec_ptr; cvp++) 1190ae8d569bSderaadt if (cvp->a <= cvp->b) { 1191ae8d569bSderaadt cvp = context_vec_start; 1192ae8d569bSderaadt do_output++; 1193ae8d569bSderaadt break; 1194ae8d569bSderaadt } 1195ae8d569bSderaadt if (do_output) { 1196ae8d569bSderaadt while (cvp <= context_vec_ptr) { 119726da422aStedu a = cvp->a; 119826da422aStedu b = cvp->b; 119926da422aStedu c = cvp->c; 120026da422aStedu d = cvp->d; 1201ae8d569bSderaadt 1202ae8d569bSderaadt if (a <= b && c <= d) 1203ae8d569bSderaadt ch = 'c'; 1204ae8d569bSderaadt else 1205ae8d569bSderaadt ch = (a <= b) ? 'd' : 'a'; 1206ae8d569bSderaadt 1207ae8d569bSderaadt if (ch == 'a') 12084ec4b3d5Smillert fetch(ixold, lowa, b, f1, " ", 0); 1209ae8d569bSderaadt else { 12104ec4b3d5Smillert fetch(ixold, lowa, a - 1, f1, " ", 0); 12114ec4b3d5Smillert fetch(ixold, a, b, f1, 121248b8c3e3Sderaadt ch == 'c' ? "! " : "- ", 0); 1213ae8d569bSderaadt } 1214ae8d569bSderaadt lowa = b + 1; 1215ae8d569bSderaadt cvp++; 1216ae8d569bSderaadt } 12174ec4b3d5Smillert fetch(ixold, b + 1, upb, f1, " ", 0); 1218ae8d569bSderaadt } 1219ae8d569bSderaadt /* output changes to the "new" file */ 1220ae8d569bSderaadt printf("--- "); 1221ae8d569bSderaadt range(lowc, upd, ","); 1222ae8d569bSderaadt printf(" ----\n"); 1223ae8d569bSderaadt 1224ae8d569bSderaadt do_output = 0; 1225ae8d569bSderaadt for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) 1226ae8d569bSderaadt if (cvp->c <= cvp->d) { 1227ae8d569bSderaadt cvp = context_vec_start; 1228ae8d569bSderaadt do_output++; 1229ae8d569bSderaadt break; 1230ae8d569bSderaadt } 1231ae8d569bSderaadt if (do_output) { 1232ae8d569bSderaadt while (cvp <= context_vec_ptr) { 123326da422aStedu a = cvp->a; 123426da422aStedu b = cvp->b; 123526da422aStedu c = cvp->c; 123626da422aStedu d = cvp->d; 1237ae8d569bSderaadt 1238ae8d569bSderaadt if (a <= b && c <= d) 1239ae8d569bSderaadt ch = 'c'; 1240ae8d569bSderaadt else 1241ae8d569bSderaadt ch = (a <= b) ? 'd' : 'a'; 1242ae8d569bSderaadt 1243ae8d569bSderaadt if (ch == 'd') 12444ec4b3d5Smillert fetch(ixnew, lowc, d, f2, " ", 0); 1245ae8d569bSderaadt else { 12464ec4b3d5Smillert fetch(ixnew, lowc, c - 1, f2, " ", 0); 12474ec4b3d5Smillert fetch(ixnew, c, d, f2, 124848b8c3e3Sderaadt ch == 'c' ? "! " : "+ ", 0); 1249ae8d569bSderaadt } 1250ae8d569bSderaadt lowc = d + 1; 1251ae8d569bSderaadt cvp++; 1252ae8d569bSderaadt } 12534ec4b3d5Smillert fetch(ixnew, d + 1, upd, f2, " ", 0); 1254ae8d569bSderaadt } 1255ae8d569bSderaadt context_vec_ptr = context_vec_start - 1; 1256ae8d569bSderaadt } 12579de32c1bSmillert 12589de32c1bSmillert /* dump accumulated "unified" diff changes */ 12599de32c1bSmillert static void 12604ec4b3d5Smillert dump_unified_vec(FILE *f1, FILE *f2) 12619de32c1bSmillert { 12629de32c1bSmillert struct context_vec *cvp = context_vec_start; 12639de32c1bSmillert int lowa, upb, lowc, upd; 12649de32c1bSmillert int a, b, c, d; 12659de32c1bSmillert char ch; 12669de32c1bSmillert 126790f56ad8Smillert if (context_vec_start > context_vec_ptr) 12689de32c1bSmillert return; 12699de32c1bSmillert 12709de32c1bSmillert b = d = 0; /* gcc */ 12719de32c1bSmillert lowa = max(1, cvp->a - context); 12729de32c1bSmillert upb = min(len[0], context_vec_ptr->b + context); 12739de32c1bSmillert lowc = max(1, cvp->c - context); 12749de32c1bSmillert upd = min(len[1], context_vec_ptr->d + context); 12759de32c1bSmillert 1276*c72ea322Smillert fputs("@@ -", stdout); 1277*c72ea322Smillert uni_range(lowa, upb); 1278*c72ea322Smillert fputs(" +", stdout); 1279*c72ea322Smillert uni_range(lowc, upd); 1280*c72ea322Smillert fputs(" @@\n", stdout); 12819de32c1bSmillert 12829de32c1bSmillert /* 12839de32c1bSmillert * Output changes in "unified" diff format--the old and new lines 12849de32c1bSmillert * are printed together. 12859de32c1bSmillert */ 12869de32c1bSmillert for (; cvp <= context_vec_ptr; cvp++) { 12879de32c1bSmillert a = cvp->a; 12889de32c1bSmillert b = cvp->b; 12899de32c1bSmillert c = cvp->c; 12909de32c1bSmillert d = cvp->d; 12919de32c1bSmillert 12929de32c1bSmillert /* 12939de32c1bSmillert * c: both new and old changes 12949de32c1bSmillert * d: only changes in the old file 12959de32c1bSmillert * a: only changes in the new file 12969de32c1bSmillert */ 12979de32c1bSmillert if (a <= b && c <= d) 12989de32c1bSmillert ch = 'c'; 12999de32c1bSmillert else 13009de32c1bSmillert ch = (a <= b) ? 'd' : 'a'; 13019de32c1bSmillert 13029de32c1bSmillert switch (ch) { 13039de32c1bSmillert case 'c': 13044ec4b3d5Smillert fetch(ixold, lowa, a - 1, f1, " ", 0); 13054ec4b3d5Smillert fetch(ixold, a, b, f1, "-", 0); 13064ec4b3d5Smillert fetch(ixnew, c, d, f2, "+", 0); 13079de32c1bSmillert break; 13089de32c1bSmillert case 'd': 13094ec4b3d5Smillert fetch(ixold, lowa, a - 1, f1, " ", 0); 13104ec4b3d5Smillert fetch(ixold, a, b, f1, "-", 0); 13119de32c1bSmillert break; 13129de32c1bSmillert case 'a': 13134ec4b3d5Smillert fetch(ixnew, lowc, c - 1, f2, " ", 0); 13144ec4b3d5Smillert fetch(ixnew, c, d, f2, "+", 0); 13159de32c1bSmillert break; 13169de32c1bSmillert } 13179de32c1bSmillert lowa = b + 1; 13189de32c1bSmillert lowc = d + 1; 13199de32c1bSmillert } 13204ec4b3d5Smillert fetch(ixnew, d + 1, upd, f2, " ", 0); 13219de32c1bSmillert 13229de32c1bSmillert context_vec_ptr = context_vec_start - 1; 13239de32c1bSmillert } 1324