[BACK]Return to diff_internals.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / cvs

Annotation of src/usr.bin/cvs/diff_internals.c, Revision 1.1

1.1     ! joris       1: /*     $OpenBSD: diff.c,v 1.90 2006/04/14 23:29:01 joris Exp $ */
        !             2: /*
        !             3:  * Copyright (C) Caldera International Inc.  2001-2002.
        !             4:  * All rights reserved.
        !             5:  *
        !             6:  * Redistribution and use in source and binary forms, with or without
        !             7:  * modification, are permitted provided that the following conditions
        !             8:  * are met:
        !             9:  * 1. Redistributions of source code and documentation must retain the above
        !            10:  *    copyright notice, this list of conditions and the following disclaimer.
        !            11:  * 2. Redistributions in binary form must reproduce the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer in the
        !            13:  *    documentation and/or other materials provided with the distribution.
        !            14:  * 3. All advertising materials mentioning features or use of this software
        !            15:  *    must display the following acknowledgement:
        !            16:  *     This product includes software developed or owned by Caldera
        !            17:  *     International, Inc.
        !            18:  * 4. Neither the name of Caldera International, Inc. nor the names of other
        !            19:  *    contributors may be used to endorse or promote products derived from
        !            20:  *    this software without specific prior written permission.
        !            21:  *
        !            22:  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
        !            23:  * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
        !            24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            25:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            26:  * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
        !            27:  * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            28:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            29:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
        !            31:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
        !            32:  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            33:  * POSSIBILITY OF SUCH DAMAGE.
        !            34:  */
        !            35: /*-
        !            36:  * Copyright (c) 1991, 1993
        !            37:  *     The Regents of the University of California.  All rights reserved.
        !            38:  * Copyright (c) 2004 Jean-Francois Brousseau.  All rights reserved.
        !            39:  *
        !            40:  * Redistribution and use in source and binary forms, with or without
        !            41:  * modification, are permitted provided that the following conditions
        !            42:  * are met:
        !            43:  * 1. Redistributions of source code must retain the above copyright
        !            44:  *    notice, this list of conditions and the following disclaimer.
        !            45:  * 2. Redistributions in binary form must reproduce the above copyright
        !            46:  *    notice, this list of conditions and the following disclaimer in the
        !            47:  *    documentation and/or other materials provided with the distribution.
        !            48:  * 3. Neither the name of the University nor the names of its contributors
        !            49:  *    may be used to endorse or promote products derived from this software
        !            50:  *    without specific prior written permission.
        !            51:  *
        !            52:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            53:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            54:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            55:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            56:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            57:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            58:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            59:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            60:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            61:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            62:  * SUCH DAMAGE.
        !            63:  *
        !            64:  *     @(#)diffreg.c   8.1 (Berkeley) 6/6/93
        !            65:  */
        !            66: /*
        !            67:  *     Uses an algorithm due to Harold Stone, which finds
        !            68:  *     a pair of longest identical subsequences in the two
        !            69:  *     files.
        !            70:  *
        !            71:  *     The major goal is to generate the match vector J.
        !            72:  *     J[i] is the index of the line in file1 corresponding
        !            73:  *     to line i file0. J[i] = 0 if there is no
        !            74:  *     such line in file1.
        !            75:  *
        !            76:  *     Lines are hashed so as to work in core. All potential
        !            77:  *     matches are located by sorting the lines of each file
        !            78:  *     on the hash (called ``value''). In particular, this
        !            79:  *     collects the equivalence classes in file1 together.
        !            80:  *     Subroutine equiv replaces the value of each line in
        !            81:  *     file0 by the index of the first element of its
        !            82:  *     matching equivalence in (the reordered) file1.
        !            83:  *     To save space equiv squeezes file1 into a single
        !            84:  *     array member in which the equivalence classes
        !            85:  *     are simply concatenated, except that their first
        !            86:  *     members are flagged by changing sign.
        !            87:  *
        !            88:  *     Next the indices that point into member are unsorted into
        !            89:  *     array class according to the original order of file0.
        !            90:  *
        !            91:  *     The cleverness lies in routine stone. This marches
        !            92:  *     through the lines of file0, developing a vector klist
        !            93:  *     of "k-candidates". At step i a k-candidate is a matched
        !            94:  *     pair of lines x,y (x in file0 y in file1) such that
        !            95:  *     there is a common subsequence of length k
        !            96:  *     between the first i lines of file0 and the first y
        !            97:  *     lines of file1, but there is no such subsequence for
        !            98:  *     any smaller y. x is the earliest possible mate to y
        !            99:  *     that occurs in such a subsequence.
        !           100:  *
        !           101:  *     Whenever any of the members of the equivalence class of
        !           102:  *     lines in file1 matable to a line in file0 has serial number
        !           103:  *     less than the y of some k-candidate, that k-candidate
        !           104:  *     with the smallest such y is replaced. The new
        !           105:  *     k-candidate is chained (via pred) to the current
        !           106:  *     k-1 candidate so that the actual subsequence can
        !           107:  *     be recovered. When a member has serial number greater
        !           108:  *     that the y of all k-candidates, the klist is extended.
        !           109:  *     At the end, the longest subsequence is pulled out
        !           110:  *     and placed in the array J by unravel
        !           111:  *
        !           112:  *     With J in hand, the matches there recorded are
        !           113:  *     check'ed against reality to assure that no spurious
        !           114:  *     matches have crept in due to hashing. If they have,
        !           115:  *     they are broken, and "jackpot" is recorded--a harmless
        !           116:  *     matter except that a true match for a spuriously
        !           117:  *     mated line may now be unnecessarily reported as a change.
        !           118:  *
        !           119:  *     Much of the complexity of the program comes simply
        !           120:  *     from trying to minimize core utilization and
        !           121:  *     maximize the range of doable problems by dynamically
        !           122:  *     allocating what is needed and reusing what is not.
        !           123:  *     The core requirements for problems larger than somewhat
        !           124:  *     are (in words) 2*length(file0) + length(file1) +
        !           125:  *     3*(number of k-candidates installed),  typically about
        !           126:  *     6n words for files of length n.
        !           127:  */
        !           128:
        !           129: #include "includes.h"
        !           130:
        !           131: #include "buf.h"
        !           132: #include "cvs.h"
        !           133: #include "diff.h"
        !           134: #include "log.h"
        !           135:
        !           136: #include "xmalloc.h"
        !           137:
        !           138: struct cand {
        !           139:        int     x;
        !           140:        int     y;
        !           141:        int     pred;
        !           142: } cand;
        !           143:
        !           144: struct line {
        !           145:        int     serial;
        !           146:        int     value;
        !           147: } *file[2];
        !           148:
        !           149: /*
        !           150:  * The following struct is used to record change in formation when
        !           151:  * doing a "context" or "unified" diff.  (see routine "change" to
        !           152:  * understand the highly mnemonic field names)
        !           153:  */
        !           154: struct context_vec {
        !           155:        int     a;      /* start line in old file */
        !           156:        int     b;      /* end line in old file */
        !           157:        int     c;      /* start line in new file */
        !           158:        int     d;      /* end line in new file */
        !           159: };
        !           160:
        !           161: struct diff_arg {
        !           162:        char    *rev1;
        !           163:        char    *rev2;
        !           164:        char    *date1;
        !           165:        char    *date2;
        !           166: };
        !           167:
        !           168: static void     output(FILE *, FILE *);
        !           169: static void     check(FILE *, FILE *);
        !           170: static void     range(int, int, char *);
        !           171: static void     uni_range(int, int);
        !           172: static void     dump_context_vec(FILE *, FILE *);
        !           173: static void     dump_unified_vec(FILE *, FILE *);
        !           174: static int      prepare(int, FILE *, off_t);
        !           175: static void     prune(void);
        !           176: static void     equiv(struct line *, int, struct line *, int, int *);
        !           177: static void     unravel(int);
        !           178: static void     unsort(struct line *, int, int *);
        !           179: static void     change(FILE *, FILE *, int, int, int, int);
        !           180: static void     sort(struct line *, int);
        !           181: static int      ignoreline(char *);
        !           182: static int      asciifile(FILE *);
        !           183: static void     fetch(long *, int, int, FILE *, int, int);
        !           184: static int      newcand(int, int, int);
        !           185: static int      search(int *, int, int);
        !           186: static int      skipline(FILE *);
        !           187: static int      isqrt(int);
        !           188: static int      stone(int *, int, int *, int *);
        !           189: static int      readhash(FILE *);
        !           190: static int      files_differ(FILE *, FILE *);
        !           191: static char    *match_function(const long *, int, FILE *);
        !           192: static char    *preadline(int, size_t, off_t);
        !           193:
        !           194: static int aflag, bflag, dflag, iflag, pflag, tflag, Tflag, wflag;
        !           195: static int context = 3;
        !           196: int diff_format = D_NORMAL;
        !           197: char *diff_file = NULL;
        !           198: RCSNUM *diff_rev1 = NULL;
        !           199: RCSNUM *diff_rev2 = NULL;
        !           200: char diffargs[128];
        !           201: static struct stat stb1, stb2;
        !           202: static char *ifdefname, *ignore_pats;
        !           203: regex_t ignore_re;
        !           204:
        !           205: static int  *J;                        /* will be overlaid on class */
        !           206: static int  *class;            /* will be overlaid on file[0] */
        !           207: static int  *klist;            /* will be overlaid on file[0] after class */
        !           208: static int  *member;           /* will be overlaid on file[1] */
        !           209: static int   clen;
        !           210: static int   inifdef;          /* whether or not we are in a #ifdef block */
        !           211: static int   diff_len[2];
        !           212: static int   pref, suff;       /* length of prefix and suffix */
        !           213: static int   slen[2];
        !           214: static int   anychange;
        !           215: static long *ixnew;            /* will be overlaid on file[1] */
        !           216: static long *ixold;            /* will be overlaid on klist */
        !           217: static struct cand *clist;     /* merely a free storage pot for candidates */
        !           218: static int   clistlen;         /* the length of clist */
        !           219: static struct line *sfile[2];  /* shortened by pruning common prefix/suffix */
        !           220: static u_char *chrtran;                /* translation table for case-folding */
        !           221: static struct context_vec *context_vec_start;
        !           222: static struct context_vec *context_vec_end;
        !           223: static struct context_vec *context_vec_ptr;
        !           224:
        !           225: #define FUNCTION_CONTEXT_SIZE  41
        !           226: static char lastbuf[FUNCTION_CONTEXT_SIZE];
        !           227: static int  lastline;
        !           228: static int  lastmatchline;
        !           229: BUF  *diffbuf = NULL;
        !           230:
        !           231: /*
        !           232:  * chrtran points to one of 2 translation tables: cup2low if folding upper to
        !           233:  * lower case clow2low if not folding case
        !           234:  */
        !           235: u_char clow2low[256] = {
        !           236:        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
        !           237:        0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
        !           238:        0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
        !           239:        0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
        !           240:        0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
        !           241:        0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41,
        !           242:        0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
        !           243:        0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
        !           244:        0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62,
        !           245:        0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
        !           246:        0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
        !           247:        0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
        !           248:        0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
        !           249:        0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
        !           250:        0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
        !           251:        0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
        !           252:        0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
        !           253:        0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
        !           254:        0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
        !           255:        0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
        !           256:        0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
        !           257:        0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1,
        !           258:        0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
        !           259:        0xfd, 0xfe, 0xff
        !           260: };
        !           261:
        !           262: u_char cup2low[256] = {
        !           263:        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
        !           264:        0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
        !           265:        0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
        !           266:        0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
        !           267:        0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
        !           268:        0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61,
        !           269:        0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
        !           270:        0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
        !           271:        0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x60, 0x61, 0x62,
        !           272:        0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
        !           273:        0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
        !           274:        0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
        !           275:        0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
        !           276:        0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
        !           277:        0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
        !           278:        0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
        !           279:        0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
        !           280:        0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
        !           281:        0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
        !           282:        0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
        !           283:        0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
        !           284:        0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1,
        !           285:        0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
        !           286:        0xfd, 0xfe, 0xff
        !           287: };
        !           288:
        !           289: int
        !           290: cvs_diffreg(const char *file1, const char *file2, BUF *out)
        !           291: {
        !           292:        FILE *f1, *f2;
        !           293:        int i, rval;
        !           294:        void *tmp;
        !           295:
        !           296:        f1 = f2 = NULL;
        !           297:        rval = D_SAME;
        !           298:        anychange = 0;
        !           299:        lastline = 0;
        !           300:        lastmatchline = 0;
        !           301:        context_vec_ptr = context_vec_start - 1;
        !           302:        chrtran = (iflag ? cup2low : clow2low);
        !           303:        if (out != NULL)
        !           304:                diffbuf = out;
        !           305:
        !           306:        f1 = fopen(file1, "r");
        !           307:        if (f1 == NULL) {
        !           308:                cvs_log(LP_ERR, "%s", file1);
        !           309:                goto closem;
        !           310:        }
        !           311:
        !           312:        f2 = fopen(file2, "r");
        !           313:        if (f2 == NULL) {
        !           314:                cvs_log(LP_ERR, "%s", file2);
        !           315:                goto closem;
        !           316:        }
        !           317:
        !           318:        if (stat(file1, &stb1) < 0) {
        !           319:                cvs_log(LP_ERR, "%s", file1);
        !           320:                goto closem;
        !           321:        }
        !           322:        if (stat(file2, &stb2) < 0) {
        !           323:                cvs_log(LP_ERR, "%s", file2);
        !           324:                goto closem;
        !           325:        }
        !           326:        switch (files_differ(f1, f2)) {
        !           327:        case 0:
        !           328:                goto closem;
        !           329:        case 1:
        !           330:                break;
        !           331:        default:
        !           332:                /* error */
        !           333:                goto closem;
        !           334:        }
        !           335:
        !           336:        if (!asciifile(f1) || !asciifile(f2)) {
        !           337:                rval = D_BINARY;
        !           338:                goto closem;
        !           339:        }
        !           340:        if (prepare(0, f1, stb1.st_size) < 0 ||
        !           341:            prepare(1, f2, stb2.st_size) < 0) {
        !           342:                goto closem;
        !           343:        }
        !           344:        prune();
        !           345:        sort(sfile[0], slen[0]);
        !           346:        sort(sfile[1], slen[1]);
        !           347:
        !           348:        member = (int *)file[1];
        !           349:        equiv(sfile[0], slen[0], sfile[1], slen[1], member);
        !           350:        tmp = xrealloc(member, slen[1] + 2, sizeof(*member));
        !           351:        member = tmp;
        !           352:
        !           353:        class = (int *)file[0];
        !           354:        unsort(sfile[0], slen[0], class);
        !           355:        tmp = xrealloc(class, slen[0] + 2, sizeof(*class));
        !           356:        class = tmp;
        !           357:
        !           358:        klist = xcalloc(slen[0] + 2, sizeof(*klist));
        !           359:        clen = 0;
        !           360:        clistlen = 100;
        !           361:        clist = xcalloc(clistlen, sizeof(*clist));
        !           362:
        !           363:        if ((i = stone(class, slen[0], member, klist)) < 0)
        !           364:                goto closem;
        !           365:
        !           366:        xfree(member);
        !           367:        xfree(class);
        !           368:
        !           369:        tmp = xrealloc(J, diff_len[0] + 2, sizeof(*J));
        !           370:        J = tmp;
        !           371:        unravel(klist[i]);
        !           372:        xfree(clist);
        !           373:        xfree(klist);
        !           374:
        !           375:        tmp = xrealloc(ixold, diff_len[0] + 2, sizeof(*ixold));
        !           376:        ixold = tmp;
        !           377:
        !           378:        tmp = xrealloc(ixnew, diff_len[1] + 2, sizeof(*ixnew));
        !           379:        ixnew = tmp;
        !           380:        check(f1, f2);
        !           381:        output(f1, f2);
        !           382:
        !           383: closem:
        !           384:        if (anychange == 1) {
        !           385:                if (rval == D_SAME)
        !           386:                        rval = D_DIFFER;
        !           387:        }
        !           388:        if (f1 != NULL)
        !           389:                fclose(f1);
        !           390:        if (f2 != NULL)
        !           391:                fclose(f2);
        !           392:
        !           393:        return (rval);
        !           394: }
        !           395:
        !           396: /*
        !           397:  * Check to see if the given files differ.
        !           398:  * Returns 0 if they are the same, 1 if different, and -1 on error.
        !           399:  * XXX - could use code from cmp(1) [faster]
        !           400:  */
        !           401: static int
        !           402: files_differ(FILE *f1, FILE *f2)
        !           403: {
        !           404:        char buf1[BUFSIZ], buf2[BUFSIZ];
        !           405:        size_t i, j;
        !           406:
        !           407:        if (stb1.st_size != stb2.st_size)
        !           408:                return (1);
        !           409:        for (;;) {
        !           410:                i = fread(buf1, (size_t)1, sizeof(buf1), f1);
        !           411:                j = fread(buf2, (size_t)1, sizeof(buf2), f2);
        !           412:                if (i != j)
        !           413:                        return (1);
        !           414:                if (i == 0 && j == 0) {
        !           415:                        if (ferror(f1) || ferror(f2))
        !           416:                                return (1);
        !           417:                        return (0);
        !           418:                }
        !           419:                if (memcmp(buf1, buf2, i) != 0)
        !           420:                        return (1);
        !           421:        }
        !           422: }
        !           423:
        !           424: static int
        !           425: prepare(int i, FILE *fd, off_t filesize)
        !           426: {
        !           427:        void *tmp;
        !           428:        struct line *p;
        !           429:        int j, h;
        !           430:        size_t sz;
        !           431:
        !           432:        rewind(fd);
        !           433:
        !           434:        sz = ((size_t)filesize <= SIZE_MAX ? (size_t)filesize : SIZE_MAX) / 25;
        !           435:        if (sz < 100)
        !           436:                sz = 100;
        !           437:
        !           438:        p = xcalloc(sz + 3, sizeof(*p));
        !           439:        for (j = 0; (h = readhash(fd));) {
        !           440:                if (j == (int)sz) {
        !           441:                        sz = sz * 3 / 2;
        !           442:                        tmp = xrealloc(p, sz + 3, sizeof(*p));
        !           443:                        p = tmp;
        !           444:                }
        !           445:                p[++j].value = h;
        !           446:        }
        !           447:        diff_len[i] = j;
        !           448:        file[i] = p;
        !           449:
        !           450:        return (0);
        !           451: }
        !           452:
        !           453: static void
        !           454: prune(void)
        !           455: {
        !           456:        int i, j;
        !           457:
        !           458:        for (pref = 0; pref < diff_len[0] && pref < diff_len[1] &&
        !           459:            file[0][pref + 1].value == file[1][pref + 1].value;
        !           460:            pref++)
        !           461:                ;
        !           462:        for (suff = 0;
        !           463:            (suff < diff_len[0] - pref) && (suff < diff_len[1] - pref) &&
        !           464:            (file[0][diff_len[0] - suff].value ==
        !           465:            file[1][diff_len[1] - suff].value);
        !           466:            suff++)
        !           467:                ;
        !           468:        for (j = 0; j < 2; j++) {
        !           469:                sfile[j] = file[j] + pref;
        !           470:                slen[j] = diff_len[j] - pref - suff;
        !           471:                for (i = 0; i <= slen[j]; i++)
        !           472:                        sfile[j][i].serial = i;
        !           473:        }
        !           474: }
        !           475:
        !           476: static void
        !           477: equiv(struct line *a, int n, struct line *b, int m, int *c)
        !           478: {
        !           479:        int i, j;
        !           480:
        !           481:        i = j = 1;
        !           482:        while (i <= n && j <= m) {
        !           483:                if (a[i].value < b[j].value)
        !           484:                        a[i++].value = 0;
        !           485:                else if (a[i].value == b[j].value)
        !           486:                        a[i++].value = j;
        !           487:                else
        !           488:                        j++;
        !           489:        }
        !           490:        while (i <= n)
        !           491:                a[i++].value = 0;
        !           492:        b[m + 1].value = 0;
        !           493:        j = 0;
        !           494:        while (++j <= m) {
        !           495:                c[j] = -b[j].serial;
        !           496:                while (b[j + 1].value == b[j].value) {
        !           497:                        j++;
        !           498:                        c[j] = b[j].serial;
        !           499:                }
        !           500:        }
        !           501:        c[j] = -1;
        !           502: }
        !           503:
        !           504: /* Code taken from ping.c */
        !           505: static int
        !           506: isqrt(int n)
        !           507: {
        !           508:        int y, x = 1;
        !           509:
        !           510:        if (n == 0)
        !           511:                return (0);
        !           512:
        !           513:        do { /* newton was a stinker */
        !           514:                y = x;
        !           515:                x = n / x;
        !           516:                x += y;
        !           517:                x /= 2;
        !           518:        } while (x - y > 1 || x - y < -1);
        !           519:
        !           520:        return (x);
        !           521: }
        !           522:
        !           523: static int
        !           524: stone(int *a, int n, int *b, int *c)
        !           525: {
        !           526:        int ret;
        !           527:        int i, k, y, j, l;
        !           528:        int oldc, tc, oldl;
        !           529:        u_int numtries;
        !           530:
        !           531:        /* XXX move the isqrt() out of the macro to avoid multiple calls */
        !           532:        const u_int bound = dflag ? UINT_MAX : MAX(256, (u_int)isqrt(n));
        !           533:
        !           534:        k = 0;
        !           535:        if ((ret = newcand(0, 0, 0)) < 0)
        !           536:                return (-1);
        !           537:        c[0] = ret;
        !           538:        for (i = 1; i <= n; i++) {
        !           539:                j = a[i];
        !           540:                if (j == 0)
        !           541:                        continue;
        !           542:                y = -b[j];
        !           543:                oldl = 0;
        !           544:                oldc = c[0];
        !           545:                numtries = 0;
        !           546:                do {
        !           547:                        if (y <= clist[oldc].y)
        !           548:                                continue;
        !           549:                        l = search(c, k, y);
        !           550:                        if (l != oldl + 1)
        !           551:                                oldc = c[l - 1];
        !           552:                        if (l <= k) {
        !           553:                                if (clist[c[l]].y <= y)
        !           554:                                        continue;
        !           555:                                tc = c[l];
        !           556:                                if ((ret = newcand(i, y, oldc)) < 0)
        !           557:                                        return (-1);
        !           558:                                c[l] = ret;
        !           559:                                oldc = tc;
        !           560:                                oldl = l;
        !           561:                                numtries++;
        !           562:                        } else {
        !           563:                                if ((ret = newcand(i, y, oldc)) < 0)
        !           564:                                        return (-1);
        !           565:                                c[l] = ret;
        !           566:                                k++;
        !           567:                                break;
        !           568:                        }
        !           569:                } while ((y = b[++j]) > 0 && numtries < bound);
        !           570:        }
        !           571:        return (k);
        !           572: }
        !           573:
        !           574: static int
        !           575: newcand(int x, int y, int pred)
        !           576: {
        !           577:        struct cand *q, *tmp;
        !           578:        int newclistlen;
        !           579:
        !           580:        if (clen == clistlen) {
        !           581:                newclistlen = clistlen * 11 / 10;
        !           582:                tmp = xrealloc(clist, newclistlen, sizeof(*clist));
        !           583:                clist = tmp;
        !           584:                clistlen = newclistlen;
        !           585:        }
        !           586:        q = clist + clen;
        !           587:        q->x = x;
        !           588:        q->y = y;
        !           589:        q->pred = pred;
        !           590:        return (clen++);
        !           591: }
        !           592:
        !           593: static int
        !           594: search(int *c, int k, int y)
        !           595: {
        !           596:        int i, j, l, t;
        !           597:
        !           598:        if (clist[c[k]].y < y)  /* quick look for typical case */
        !           599:                return (k + 1);
        !           600:        i = 0;
        !           601:        j = k + 1;
        !           602:        for (;;) {
        !           603:                l = (i + j) / 2;
        !           604:                if (l <= i)
        !           605:                        break;
        !           606:                t = clist[c[l]].y;
        !           607:                if (t > y)
        !           608:                        j = l;
        !           609:                else if (t < y)
        !           610:                        i = l;
        !           611:                else
        !           612:                        return (l);
        !           613:        }
        !           614:        return (l + 1);
        !           615: }
        !           616:
        !           617: static void
        !           618: unravel(int p)
        !           619: {
        !           620:        struct cand *q;
        !           621:        int i;
        !           622:
        !           623:        for (i = 0; i <= diff_len[0]; i++)
        !           624:                J[i] = i <= pref ? i :
        !           625:                    i > diff_len[0] - suff ? i + diff_len[1] - diff_len[0] : 0;
        !           626:        for (q = clist + p; q->y != 0; q = clist + q->pred)
        !           627:                J[q->x + pref] = q->y + pref;
        !           628: }
        !           629:
        !           630: /*
        !           631:  * Check does double duty:
        !           632:  *  1. ferret out any fortuitous correspondences due
        !           633:  *     to confounding by hashing (which result in "jackpot")
        !           634:  *  2.  collect random access indexes to the two files
        !           635:  */
        !           636: static void
        !           637: check(FILE *f1, FILE *f2)
        !           638: {
        !           639:        int i, j, jackpot, c, d;
        !           640:        long ctold, ctnew;
        !           641:
        !           642:        rewind(f1);
        !           643:        rewind(f2);
        !           644:        j = 1;
        !           645:        ixold[0] = ixnew[0] = 0;
        !           646:        jackpot = 0;
        !           647:        ctold = ctnew = 0;
        !           648:        for (i = 1; i <= diff_len[0]; i++) {
        !           649:                if (J[i] == 0) {
        !           650:                        ixold[i] = ctold += skipline(f1);
        !           651:                        continue;
        !           652:                }
        !           653:                while (j < J[i]) {
        !           654:                        ixnew[j] = ctnew += skipline(f2);
        !           655:                        j++;
        !           656:                }
        !           657:                if (bflag == 1 || wflag == 1 || iflag == 1) {
        !           658:                        for (;;) {
        !           659:                                c = getc(f1);
        !           660:                                d = getc(f2);
        !           661:                                /*
        !           662:                                 * GNU diff ignores a missing newline
        !           663:                                 * in one file if bflag || wflag.
        !           664:                                 */
        !           665:                                if ((bflag == 1 || wflag == 1) &&
        !           666:                                    ((c == EOF && d == '\n') ||
        !           667:                                    (c == '\n' && d == EOF))) {
        !           668:                                        break;
        !           669:                                }
        !           670:                                ctold++;
        !           671:                                ctnew++;
        !           672:                                if (bflag == 1 && isspace(c) && isspace(d)) {
        !           673:                                        do {
        !           674:                                                if (c == '\n')
        !           675:                                                        break;
        !           676:                                                ctold++;
        !           677:                                        } while (isspace(c = getc(f1)));
        !           678:                                        do {
        !           679:                                                if (d == '\n')
        !           680:                                                        break;
        !           681:                                                ctnew++;
        !           682:                                        } while (isspace(d = getc(f2)));
        !           683:                                } else if (wflag == 1) {
        !           684:                                        while (isspace(c) && c != '\n') {
        !           685:                                                c = getc(f1);
        !           686:                                                ctold++;
        !           687:                                        }
        !           688:                                        while (isspace(d) && d != '\n') {
        !           689:                                                d = getc(f2);
        !           690:                                                ctnew++;
        !           691:                                        }
        !           692:                                }
        !           693:                                if (chrtran[c] != chrtran[d]) {
        !           694:                                        jackpot++;
        !           695:                                        J[i] = 0;
        !           696:                                        if (c != '\n' && c != EOF)
        !           697:                                                ctold += skipline(f1);
        !           698:                                        if (d != '\n' && c != EOF)
        !           699:                                                ctnew += skipline(f2);
        !           700:                                        break;
        !           701:                                }
        !           702:                                if (c == '\n' || c == EOF)
        !           703:                                        break;
        !           704:                        }
        !           705:                } else {
        !           706:                        for (;;) {
        !           707:                                ctold++;
        !           708:                                ctnew++;
        !           709:                                if ((c = getc(f1)) != (d = getc(f2))) {
        !           710:                                        /* jackpot++; */
        !           711:                                        J[i] = 0;
        !           712:                                        if (c != '\n' && c != EOF)
        !           713:                                                ctold += skipline(f1);
        !           714:                                        if (d != '\n' && c != EOF)
        !           715:                                                ctnew += skipline(f2);
        !           716:                                        break;
        !           717:                                }
        !           718:                                if (c == '\n' || c == EOF)
        !           719:                                        break;
        !           720:                        }
        !           721:                }
        !           722:                ixold[i] = ctold;
        !           723:                ixnew[j] = ctnew;
        !           724:                j++;
        !           725:        }
        !           726:        for (; j <= diff_len[1]; j++)
        !           727:                ixnew[j] = ctnew += skipline(f2);
        !           728:        /*
        !           729:         * if (jackpot != 0)
        !           730:         *      cvs_printf("jackpot\n");
        !           731:         */
        !           732: }
        !           733:
        !           734: /* shellsort CACM #201 */
        !           735: static void
        !           736: sort(struct line *a, int n)
        !           737: {
        !           738:        struct line *ai, *aim, w;
        !           739:        int j, m = 0, k;
        !           740:
        !           741:        if (n == 0)
        !           742:                return;
        !           743:        for (j = 1; j <= n; j *= 2)
        !           744:                m = 2 * j - 1;
        !           745:        for (m /= 2; m != 0; m /= 2) {
        !           746:                k = n - m;
        !           747:                for (j = 1; j <= k; j++) {
        !           748:                        for (ai = &a[j]; ai > a; ai -= m) {
        !           749:                                aim = &ai[m];
        !           750:                                if (aim < ai)
        !           751:                                        break;  /* wraparound */
        !           752:                                if (aim->value > ai[0].value ||
        !           753:                                    (aim->value == ai[0].value &&
        !           754:                                        aim->serial > ai[0].serial))
        !           755:                                        break;
        !           756:                                w.value = ai[0].value;
        !           757:                                ai[0].value = aim->value;
        !           758:                                aim->value = w.value;
        !           759:                                w.serial = ai[0].serial;
        !           760:                                ai[0].serial = aim->serial;
        !           761:                                aim->serial = w.serial;
        !           762:                        }
        !           763:                }
        !           764:        }
        !           765: }
        !           766:
        !           767: static void
        !           768: unsort(struct line *f, int l, int *b)
        !           769: {
        !           770:        int *a, i;
        !           771:
        !           772:        a = xcalloc(l + 1, sizeof(*a));
        !           773:        for (i = 1; i <= l; i++)
        !           774:                a[f[i].serial] = f[i].value;
        !           775:        for (i = 1; i <= l; i++)
        !           776:                b[i] = a[i];
        !           777:        xfree(a);
        !           778: }
        !           779:
        !           780: static int
        !           781: skipline(FILE *f)
        !           782: {
        !           783:        int i, c;
        !           784:
        !           785:        for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++)
        !           786:                continue;
        !           787:        return (i);
        !           788: }
        !           789:
        !           790: static void
        !           791: output(FILE *f1, FILE *f2)
        !           792: {
        !           793:        int m, i0, i1, j0, j1;
        !           794:
        !           795:        rewind(f1);
        !           796:        rewind(f2);
        !           797:        m = diff_len[0];
        !           798:        J[0] = 0;
        !           799:        J[m + 1] = diff_len[1] + 1;
        !           800:        for (i0 = 1; i0 <= m; i0 = i1 + 1) {
        !           801:                while (i0 <= m && J[i0] == J[i0 - 1] + 1)
        !           802:                        i0++;
        !           803:                j0 = J[i0 - 1] + 1;
        !           804:                i1 = i0 - 1;
        !           805:                while (i1 < m && J[i1 + 1] == 0)
        !           806:                        i1++;
        !           807:                j1 = J[i1 + 1] - 1;
        !           808:                J[i1] = j1;
        !           809:                change(f1, f2, i0, i1, j0, j1);
        !           810:        }
        !           811:        if (m == 0)
        !           812:                change(f1, f2, 1, 0, 1, diff_len[1]);
        !           813:        if (diff_format == D_IFDEF) {
        !           814:                for (;;) {
        !           815: #define        c i0
        !           816:                        if ((c = getc(f1)) == EOF)
        !           817:                                return;
        !           818:                        diff_output("%c", c);
        !           819:                }
        !           820: #undef c
        !           821:        }
        !           822:        if (anychange != 0) {
        !           823:                if (diff_format == D_CONTEXT)
        !           824:                        dump_context_vec(f1, f2);
        !           825:                else if (diff_format == D_UNIFIED)
        !           826:                        dump_unified_vec(f1, f2);
        !           827:        }
        !           828: }
        !           829:
        !           830: static __inline void
        !           831: range(int a, int b, char *separator)
        !           832: {
        !           833:        diff_output("%d", a > b ? b : a);
        !           834:        if (a < b)
        !           835:                diff_output("%s%d", separator, b);
        !           836: }
        !           837:
        !           838: static __inline void
        !           839: uni_range(int a, int b)
        !           840: {
        !           841:        if (a < b)
        !           842:                diff_output("%d,%d", a, b - a + 1);
        !           843:        else if (a == b)
        !           844:                diff_output("%d", b);
        !           845:        else
        !           846:                diff_output("%d,0", b);
        !           847: }
        !           848:
        !           849: static char *
        !           850: preadline(int fd, size_t rlen, off_t off)
        !           851: {
        !           852:        char *line;
        !           853:        ssize_t nr;
        !           854:
        !           855:        line = xmalloc(rlen + 1);
        !           856:        if ((nr = pread(fd, line, rlen, off)) < 0) {
        !           857:                cvs_log(LP_ERR, "preadline failed");
        !           858:                return (NULL);
        !           859:        }
        !           860:        line[nr] = '\0';
        !           861:        return (line);
        !           862: }
        !           863:
        !           864: static int
        !           865: ignoreline(char *line)
        !           866: {
        !           867:        int ret;
        !           868:
        !           869:        ret = regexec(&ignore_re, line, (size_t)0, NULL, 0);
        !           870:        xfree(line);
        !           871:        return (ret == 0);      /* if it matched, it should be ignored. */
        !           872: }
        !           873:
        !           874: /*
        !           875:  * Indicate that there is a difference between lines a and b of the from file
        !           876:  * to get to lines c to d of the to file.  If a is greater then b then there
        !           877:  * are no lines in the from file involved and this means that there were
        !           878:  * lines appended (beginning at b).  If c is greater than d then there are
        !           879:  * lines missing from the to file.
        !           880:  */
        !           881: static void
        !           882: change(FILE *f1, FILE *f2, int a, int b, int c, int d)
        !           883: {
        !           884:        int i;
        !           885:        static size_t max_context = 64;
        !           886:        char buf[64];
        !           887:        struct tm *t;
        !           888:
        !           889:        if (diff_format != D_IFDEF && a > b && c > d)
        !           890:                return;
        !           891:        if (ignore_pats != NULL) {
        !           892:                char *line;
        !           893:                /*
        !           894:                 * All lines in the change, insert, or delete must
        !           895:                 * match an ignore pattern for the change to be
        !           896:                 * ignored.
        !           897:                 */
        !           898:                if (a <= b) {           /* Changes and deletes. */
        !           899:                        for (i = a; i <= b; i++) {
        !           900:                                line = preadline(fileno(f1),
        !           901:                                    ixold[i] - ixold[i - 1], ixold[i - 1]);
        !           902:                                if (!ignoreline(line))
        !           903:                                        goto proceed;
        !           904:                        }
        !           905:                }
        !           906:                if (a > b || c <= d) {  /* Changes and inserts. */
        !           907:                        for (i = c; i <= d; i++) {
        !           908:                                line = preadline(fileno(f2),
        !           909:                                    ixnew[i] - ixnew[i - 1], ixnew[i - 1]);
        !           910:                                if (!ignoreline(line))
        !           911:                                        goto proceed;
        !           912:                        }
        !           913:                }
        !           914:                return;
        !           915:        }
        !           916: proceed:
        !           917:        if (diff_format == D_CONTEXT || diff_format == D_UNIFIED) {
        !           918:                /*
        !           919:                 * Allocate change records as needed.
        !           920:                 */
        !           921:                if (context_vec_ptr == context_vec_end - 1) {
        !           922:                        struct context_vec *tmp;
        !           923:                        ptrdiff_t offset = context_vec_ptr - context_vec_start;
        !           924:                        max_context <<= 1;
        !           925:                        tmp = xrealloc(context_vec_start, max_context,
        !           926:                            sizeof(*context_vec_start));
        !           927:                        context_vec_start = tmp;
        !           928:                        context_vec_end = context_vec_start + max_context;
        !           929:                        context_vec_ptr = context_vec_start + offset;
        !           930:                }
        !           931:                if (anychange == 0) {
        !           932:                        /*
        !           933:                         * Print the context/unidiff header first time through.
        !           934:                         */
        !           935:                        t = localtime(&stb1.st_mtime);
        !           936:                        (void)strftime(buf, sizeof(buf),
        !           937:                            "%d %b %G %H:%M:%S", t);
        !           938:
        !           939:                        diff_output("%s %s      %s",
        !           940:                            diff_format == D_CONTEXT ? "***" : "---", diff_file,
        !           941:                            buf);
        !           942:
        !           943:                        if (diff_rev1 != NULL) {
        !           944:                                rcsnum_tostr(diff_rev1, buf, sizeof(buf));
        !           945:                                diff_output("\t%s", buf);
        !           946:                        }
        !           947:
        !           948:                        printf("\n");
        !           949:
        !           950:                        t = localtime(&stb2.st_mtime);
        !           951:                        (void)strftime(buf, sizeof(buf),
        !           952:                            "%d %b %G %H:%M:%S", t);
        !           953:
        !           954:                        diff_output("%s %s      %s",
        !           955:                            diff_format == D_CONTEXT ? "---" : "+++", diff_file,
        !           956:                            buf);
        !           957:
        !           958:                        if (diff_rev2 != NULL) {
        !           959:                                rcsnum_tostr(diff_rev2, buf, sizeof(buf));
        !           960:                                diff_output("\t%s", buf);
        !           961:                        }
        !           962:
        !           963:                        printf("\n");
        !           964:                        anychange = 1;
        !           965:                } else if (a > context_vec_ptr->b + (2 * context) + 1 &&
        !           966:                    c > context_vec_ptr->d + (2 * context) + 1) {
        !           967:                        /*
        !           968:                         * If this change is more than 'context' lines from the
        !           969:                         * previous change, dump the record and reset it.
        !           970:                         */
        !           971:                        if (diff_format == D_CONTEXT)
        !           972:                                dump_context_vec(f1, f2);
        !           973:                        else
        !           974:                                dump_unified_vec(f1, f2);
        !           975:                }
        !           976:                context_vec_ptr++;
        !           977:                context_vec_ptr->a = a;
        !           978:                context_vec_ptr->b = b;
        !           979:                context_vec_ptr->c = c;
        !           980:                context_vec_ptr->d = d;
        !           981:                return;
        !           982:        }
        !           983:        if (anychange == 0)
        !           984:                anychange = 1;
        !           985:        switch (diff_format) {
        !           986:        case D_BRIEF:
        !           987:                return;
        !           988:        case D_NORMAL:
        !           989:                range(a, b, ",");
        !           990:                diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c');
        !           991:                if (diff_format == D_NORMAL)
        !           992:                        range(c, d, ",");
        !           993:                diff_output("\n");
        !           994:                break;
        !           995:        case D_RCSDIFF:
        !           996:                if (a > b)
        !           997:                        diff_output("a%d %d\n", b, d - c + 1);
        !           998:                else {
        !           999:                        diff_output("d%d %d\n", a, b - a + 1);
        !          1000:
        !          1001:                        if (!(c > d))   /* add changed lines */
        !          1002:                                diff_output("a%d %d\n", b, d - c + 1);
        !          1003:                }
        !          1004:                break;
        !          1005:        }
        !          1006:        if (diff_format == D_NORMAL || diff_format == D_IFDEF) {
        !          1007:                fetch(ixold, a, b, f1, '<', 1);
        !          1008:                if (a <= b && c <= d && diff_format == D_NORMAL)
        !          1009:                        diff_output("---\n");
        !          1010:        }
        !          1011:        fetch(ixnew, c, d, f2, diff_format == D_NORMAL ? '>' : '\0', 0);
        !          1012:        if (inifdef) {
        !          1013:                diff_output("#endif /* %s */\n", ifdefname);
        !          1014:                inifdef = 0;
        !          1015:        }
        !          1016: }
        !          1017:
        !          1018: static void
        !          1019: fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile)
        !          1020: {
        !          1021:        long j, nc;
        !          1022:        int i, c, col;
        !          1023:
        !          1024:        /*
        !          1025:         * When doing #ifdef's, copy down to current line
        !          1026:         * if this is the first file, so that stuff makes it to output.
        !          1027:         */
        !          1028:        if (diff_format == D_IFDEF && oldfile) {
        !          1029:                long curpos = ftell(lb);
        !          1030:                /* print through if append (a>b), else to (nb: 0 vs 1 orig) */
        !          1031:                nc = f[a > b ? b : a - 1] - curpos;
        !          1032:                for (i = 0; i < nc; i++)
        !          1033:                        diff_output("%c", getc(lb));
        !          1034:        }
        !          1035:        if (a > b)
        !          1036:                return;
        !          1037:        if (diff_format == D_IFDEF) {
        !          1038:                if (inifdef) {
        !          1039:                        diff_output("#else /* %s%s */\n",
        !          1040:                            oldfile == 1 ? "!" : "", ifdefname);
        !          1041:                } else {
        !          1042:                        if (oldfile)
        !          1043:                                diff_output("#ifndef %s\n", ifdefname);
        !          1044:                        else
        !          1045:                                diff_output("#ifdef %s\n", ifdefname);
        !          1046:                }
        !          1047:                inifdef = 1 + oldfile;
        !          1048:        }
        !          1049:        for (i = a; i <= b; i++) {
        !          1050:                fseek(lb, f[i - 1], SEEK_SET);
        !          1051:                nc = f[i] - f[i - 1];
        !          1052:                if (diff_format != D_IFDEF && ch != '\0') {
        !          1053:                        diff_output("%c", ch);
        !          1054:                        if (Tflag == 1 && (diff_format == D_NORMAL ||
        !          1055:                            diff_format == D_CONTEXT ||
        !          1056:                            diff_format == D_UNIFIED))
        !          1057:                                diff_output("\t");
        !          1058:                        else if (diff_format != D_UNIFIED)
        !          1059:                                diff_output(" ");
        !          1060:                }
        !          1061:                col = 0;
        !          1062:                for (j = 0; j < nc; j++) {
        !          1063:                        if ((c = getc(lb)) == EOF) {
        !          1064:                                if (diff_format == D_RCSDIFF)
        !          1065:                                        cvs_log(LP_ERR,
        !          1066:                                            "No newline at end of file");
        !          1067:                                else
        !          1068:                                        diff_output("\n\\ No newline at end of "
        !          1069:                                            "file");
        !          1070:                                return;
        !          1071:                        }
        !          1072:                        if (c == '\t' && tflag == 1) {
        !          1073:                                do {
        !          1074:                                        diff_output(" ");
        !          1075:                                } while (++col & 7);
        !          1076:                        } else {
        !          1077:                                diff_output("%c", c);
        !          1078:                                col++;
        !          1079:                        }
        !          1080:                }
        !          1081:        }
        !          1082: }
        !          1083:
        !          1084: /*
        !          1085:  * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578.
        !          1086:  */
        !          1087: static int
        !          1088: readhash(FILE *f)
        !          1089: {
        !          1090:        int i, t, space;
        !          1091:        int sum;
        !          1092:
        !          1093:        sum = 1;
        !          1094:        space = 0;
        !          1095:        if (bflag != 1 && wflag != 1) {
        !          1096:                if (iflag == 1)
        !          1097:                        for (i = 0; (t = getc(f)) != '\n'; i++) {
        !          1098:                                if (t == EOF) {
        !          1099:                                        if (i == 0)
        !          1100:                                                return (0);
        !          1101:                                        break;
        !          1102:                                }
        !          1103:                                sum = sum * 127 + chrtran[t];
        !          1104:                        }
        !          1105:                else
        !          1106:                        for (i = 0; (t = getc(f)) != '\n'; i++) {
        !          1107:                                if (t == EOF) {
        !          1108:                                        if (i == 0)
        !          1109:                                                return (0);
        !          1110:                                        break;
        !          1111:                                }
        !          1112:                                sum = sum * 127 + t;
        !          1113:                        }
        !          1114:        } else {
        !          1115:                for (i = 0;;) {
        !          1116:                        switch (t = getc(f)) {
        !          1117:                        case '\t':
        !          1118:                        case ' ':
        !          1119:                                space++;
        !          1120:                                continue;
        !          1121:                        default:
        !          1122:                                if (space != 0 && wflag != 1) {
        !          1123:                                        i++;
        !          1124:                                        space = 0;
        !          1125:                                }
        !          1126:                                sum = sum * 127 + chrtran[t];
        !          1127:                                i++;
        !          1128:                                continue;
        !          1129:                        case EOF:
        !          1130:                                if (i == 0)
        !          1131:                                        return (0);
        !          1132:                                /* FALLTHROUGH */
        !          1133:                        case '\n':
        !          1134:                                break;
        !          1135:                        }
        !          1136:                        break;
        !          1137:                }
        !          1138:        }
        !          1139:        /*
        !          1140:         * There is a remote possibility that we end up with a zero sum.
        !          1141:         * Zero is used as an EOF marker, so return 1 instead.
        !          1142:         */
        !          1143:        return (sum == 0 ? 1 : sum);
        !          1144: }
        !          1145:
        !          1146: static int
        !          1147: asciifile(FILE *f)
        !          1148: {
        !          1149:        char buf[BUFSIZ];
        !          1150:        size_t i, cnt;
        !          1151:
        !          1152:        if (aflag == 1 || f == NULL)
        !          1153:                return (1);
        !          1154:
        !          1155:        rewind(f);
        !          1156:        cnt = fread(buf, (size_t)1, sizeof(buf), f);
        !          1157:        for (i = 0; i < cnt; i++)
        !          1158:                if (!isprint(buf[i]) && !isspace(buf[i]))
        !          1159:                        return (0);
        !          1160:        return (1);
        !          1161: }
        !          1162:
        !          1163: static char*
        !          1164: match_function(const long *f, int pos, FILE *fp)
        !          1165: {
        !          1166:        unsigned char buf[FUNCTION_CONTEXT_SIZE];
        !          1167:        size_t nc;
        !          1168:        int last = lastline;
        !          1169:        char *p;
        !          1170:
        !          1171:        lastline = pos;
        !          1172:        while (pos > last) {
        !          1173:                fseek(fp, f[pos - 1], SEEK_SET);
        !          1174:                nc = f[pos] - f[pos - 1];
        !          1175:                if (nc >= sizeof(buf))
        !          1176:                        nc = sizeof(buf) - 1;
        !          1177:                nc = fread(buf, (size_t)1, nc, fp);
        !          1178:                if (nc > 0) {
        !          1179:                        buf[nc] = '\0';
        !          1180:                        p = strchr((const char *)buf, '\n');
        !          1181:                        if (p != NULL)
        !          1182:                                *p = '\0';
        !          1183:                        if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') {
        !          1184:                                strlcpy(lastbuf, (const char *)buf,
        !          1185:                                    sizeof lastbuf);
        !          1186:                                lastmatchline = pos;
        !          1187:                                return lastbuf;
        !          1188:                        }
        !          1189:                }
        !          1190:                pos--;
        !          1191:        }
        !          1192:        return (lastmatchline > 0) ? lastbuf : NULL;
        !          1193: }
        !          1194:
        !          1195:
        !          1196: /* dump accumulated "context" diff changes */
        !          1197: static void
        !          1198: dump_context_vec(FILE *f1, FILE *f2)
        !          1199: {
        !          1200:        struct context_vec *cvp = context_vec_start;
        !          1201:        int lowa, upb, lowc, upd, do_output;
        !          1202:        int a, b, c, d;
        !          1203:        char ch, *f;
        !          1204:
        !          1205:        if (context_vec_start > context_vec_ptr)
        !          1206:                return;
        !          1207:
        !          1208:        b = d = 0;              /* gcc */
        !          1209:        lowa = MAX(1, cvp->a - context);
        !          1210:        upb = MIN(diff_len[0], context_vec_ptr->b + context);
        !          1211:        lowc = MAX(1, cvp->c - context);
        !          1212:        upd = MIN(diff_len[1], context_vec_ptr->d + context);
        !          1213:
        !          1214:        diff_output("***************");
        !          1215:        if (pflag == 1) {
        !          1216:                f = match_function(ixold, lowa - 1, f1);
        !          1217:                if (f != NULL) {
        !          1218:                        diff_output(" ");
        !          1219:                        diff_output("%s", f);
        !          1220:                }
        !          1221:        }
        !          1222:        diff_output("\n*** ");
        !          1223:        range(lowa, upb, ",");
        !          1224:        diff_output(" ****\n");
        !          1225:
        !          1226:        /*
        !          1227:         * Output changes to the "old" file.  The first loop suppresses
        !          1228:         * output if there were no changes to the "old" file (we'll see
        !          1229:         * the "old" lines as context in the "new" list).
        !          1230:         */
        !          1231:        do_output = 0;
        !          1232:        for (; cvp <= context_vec_ptr; cvp++)
        !          1233:                if (cvp->a <= cvp->b) {
        !          1234:                        cvp = context_vec_start;
        !          1235:                        do_output++;
        !          1236:                        break;
        !          1237:                }
        !          1238:        if (do_output != 0) {
        !          1239:                while (cvp <= context_vec_ptr) {
        !          1240:                        a = cvp->a;
        !          1241:                        b = cvp->b;
        !          1242:                        c = cvp->c;
        !          1243:                        d = cvp->d;
        !          1244:
        !          1245:                        if (a <= b && c <= d)
        !          1246:                                ch = 'c';
        !          1247:                        else
        !          1248:                                ch = (a <= b) ? 'd' : 'a';
        !          1249:
        !          1250:                        if (ch == 'a')
        !          1251:                                fetch(ixold, lowa, b, f1, ' ', 0);
        !          1252:                        else {
        !          1253:                                fetch(ixold, lowa, a - 1, f1, ' ', 0);
        !          1254:                                fetch(ixold, a, b, f1,
        !          1255:                                    ch == 'c' ? '!' : '-', 0);
        !          1256:                        }
        !          1257:                        lowa = b + 1;
        !          1258:                        cvp++;
        !          1259:                }
        !          1260:                fetch(ixold, b + 1, upb, f1, ' ', 0);
        !          1261:        }
        !          1262:        /* output changes to the "new" file */
        !          1263:        diff_output("--- ");
        !          1264:        range(lowc, upd, ",");
        !          1265:        diff_output(" ----\n");
        !          1266:
        !          1267:        do_output = 0;
        !          1268:        for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++)
        !          1269:                if (cvp->c <= cvp->d) {
        !          1270:                        cvp = context_vec_start;
        !          1271:                        do_output++;
        !          1272:                        break;
        !          1273:                }
        !          1274:        if (do_output != 0) {
        !          1275:                while (cvp <= context_vec_ptr) {
        !          1276:                        a = cvp->a;
        !          1277:                        b = cvp->b;
        !          1278:                        c = cvp->c;
        !          1279:                        d = cvp->d;
        !          1280:
        !          1281:                        if (a <= b && c <= d)
        !          1282:                                ch = 'c';
        !          1283:                        else
        !          1284:                                ch = (a <= b) ? 'd' : 'a';
        !          1285:
        !          1286:                        if (ch == 'd')
        !          1287:                                fetch(ixnew, lowc, d, f2, ' ', 0);
        !          1288:                        else {
        !          1289:                                fetch(ixnew, lowc, c - 1, f2, ' ', 0);
        !          1290:                                fetch(ixnew, c, d, f2,
        !          1291:                                    ch == 'c' ? '!' : '+', 0);
        !          1292:                        }
        !          1293:                        lowc = d + 1;
        !          1294:                        cvp++;
        !          1295:                }
        !          1296:                fetch(ixnew, d + 1, upd, f2, ' ', 0);
        !          1297:        }
        !          1298:        context_vec_ptr = context_vec_start - 1;
        !          1299: }
        !          1300:
        !          1301: /* dump accumulated "unified" diff changes */
        !          1302: static void
        !          1303: dump_unified_vec(FILE *f1, FILE *f2)
        !          1304: {
        !          1305:        struct context_vec *cvp = context_vec_start;
        !          1306:        int lowa, upb, lowc, upd;
        !          1307:        int a, b, c, d;
        !          1308:        char ch, *f;
        !          1309:
        !          1310:        if (context_vec_start > context_vec_ptr)
        !          1311:                return;
        !          1312:
        !          1313:        b = d = 0;              /* gcc */
        !          1314:        lowa = MAX(1, cvp->a - context);
        !          1315:        upb = MIN(diff_len[0], context_vec_ptr->b + context);
        !          1316:        lowc = MAX(1, cvp->c - context);
        !          1317:        upd = MIN(diff_len[1], context_vec_ptr->d + context);
        !          1318:
        !          1319:        diff_output("@@ -");
        !          1320:        uni_range(lowa, upb);
        !          1321:        diff_output(" +");
        !          1322:        uni_range(lowc, upd);
        !          1323:        diff_output(" @@");
        !          1324:        if (pflag == 1) {
        !          1325:                f = match_function(ixold, lowa - 1, f1);
        !          1326:                if (f != NULL) {
        !          1327:                        diff_output(" ");
        !          1328:                        diff_output("%s", f);
        !          1329:                }
        !          1330:        }
        !          1331:        diff_output("\n");
        !          1332:
        !          1333:        /*
        !          1334:         * Output changes in "unified" diff format--the old and new lines
        !          1335:         * are printed together.
        !          1336:         */
        !          1337:        for (; cvp <= context_vec_ptr; cvp++) {
        !          1338:                a = cvp->a;
        !          1339:                b = cvp->b;
        !          1340:                c = cvp->c;
        !          1341:                d = cvp->d;
        !          1342:
        !          1343:                /*
        !          1344:                 * c: both new and old changes
        !          1345:                 * d: only changes in the old file
        !          1346:                 * a: only changes in the new file
        !          1347:                 */
        !          1348:                if (a <= b && c <= d)
        !          1349:                        ch = 'c';
        !          1350:                else
        !          1351:                        ch = (a <= b) ? 'd' : 'a';
        !          1352:
        !          1353:                switch (ch) {
        !          1354:                case 'c':
        !          1355:                        fetch(ixold, lowa, a - 1, f1, ' ', 0);
        !          1356:                        fetch(ixold, a, b, f1, '-', 0);
        !          1357:                        fetch(ixnew, c, d, f2, '+', 0);
        !          1358:                        break;
        !          1359:                case 'd':
        !          1360:                        fetch(ixold, lowa, a - 1, f1, ' ', 0);
        !          1361:                        fetch(ixold, a, b, f1, '-', 0);
        !          1362:                        break;
        !          1363:                case 'a':
        !          1364:                        fetch(ixnew, lowc, c - 1, f2, ' ', 0);
        !          1365:                        fetch(ixnew, c, d, f2, '+', 0);
        !          1366:                        break;
        !          1367:                }
        !          1368:                lowa = b + 1;
        !          1369:                lowc = d + 1;
        !          1370:        }
        !          1371:        fetch(ixnew, d + 1, upd, f2, ' ', 0);
        !          1372:
        !          1373:        context_vec_ptr = context_vec_start - 1;
        !          1374: }
        !          1375:
        !          1376: void
        !          1377: diff_output(const char *fmt, ...)
        !          1378: {
        !          1379:        va_list vap;
        !          1380:        int i;
        !          1381:        char *str;
        !          1382:
        !          1383:        va_start(vap, fmt);
        !          1384:        i = vasprintf(&str, fmt, vap);
        !          1385:        va_end(vap);
        !          1386:        if (i == -1)
        !          1387:                fatal("diff_output: %s", strerror(errno));
        !          1388:        if (diffbuf != NULL)
        !          1389:                cvs_buf_append(diffbuf, str, strlen(str));
        !          1390:        else
        !          1391:                cvs_printf("%s", str);
        !          1392:        xfree(str);
        !          1393: }