=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/cvs/diff.c,v retrieving revision 1.90 retrieving revision 1.91 diff -u -r1.90 -r1.91 --- src/usr.bin/cvs/diff.c 2006/04/14 23:29:01 1.90 +++ src/usr.bin/cvs/diff.c 2006/05/27 03:30:30 1.91 @@ -1,305 +1,30 @@ -/* $OpenBSD: diff.c,v 1.90 2006/04/14 23:29:01 joris Exp $ */ +/* $OpenBSD: diff.c,v 1.91 2006/05/27 03:30:30 joris Exp $ */ /* - * Copyright (C) Caldera International Inc. 2001-2002. - * All rights reserved. + * Copyright (c) 2006 Joris Vink * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code and documentation must retain the above - * copyright notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed or owned by Caldera - * International, Inc. - * 4. Neither the name of Caldera International, Inc. nor the names of other - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA - * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, - * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 2004 Jean-Francois Brousseau. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)diffreg.c 8.1 (Berkeley) 6/6/93 - */ -/* - * Uses an algorithm due to Harold Stone, which finds - * a pair of longest identical subsequences in the two - * files. - * - * The major goal is to generate the match vector J. - * J[i] is the index of the line in file1 corresponding - * to line i file0. J[i] = 0 if there is no - * such line in file1. - * - * Lines are hashed so as to work in core. All potential - * matches are located by sorting the lines of each file - * on the hash (called ``value''). In particular, this - * collects the equivalence classes in file1 together. - * Subroutine equiv replaces the value of each line in - * file0 by the index of the first element of its - * matching equivalence in (the reordered) file1. - * To save space equiv squeezes file1 into a single - * array member in which the equivalence classes - * are simply concatenated, except that their first - * members are flagged by changing sign. - * - * Next the indices that point into member are unsorted into - * array class according to the original order of file0. - * - * The cleverness lies in routine stone. This marches - * through the lines of file0, developing a vector klist - * of "k-candidates". At step i a k-candidate is a matched - * pair of lines x,y (x in file0 y in file1) such that - * there is a common subsequence of length k - * between the first i lines of file0 and the first y - * lines of file1, but there is no such subsequence for - * any smaller y. x is the earliest possible mate to y - * that occurs in such a subsequence. - * - * Whenever any of the members of the equivalence class of - * lines in file1 matable to a line in file0 has serial number - * less than the y of some k-candidate, that k-candidate - * with the smallest such y is replaced. The new - * k-candidate is chained (via pred) to the current - * k-1 candidate so that the actual subsequence can - * be recovered. When a member has serial number greater - * that the y of all k-candidates, the klist is extended. - * At the end, the longest subsequence is pulled out - * and placed in the array J by unravel - * - * With J in hand, the matches there recorded are - * check'ed against reality to assure that no spurious - * matches have crept in due to hashing. If they have, - * they are broken, and "jackpot" is recorded--a harmless - * matter except that a true match for a spuriously - * mated line may now be unnecessarily reported as a change. - * - * Much of the complexity of the program comes simply - * from trying to minimize core utilization and - * maximize the range of doable problems by dynamically - * allocating what is needed and reusing what is not. - * The core requirements for problems larger than somewhat - * are (in words) 2*length(file0) + length(file1) + - * 3*(number of k-candidates installed), typically about - * 6n words for files of length n. - */ #include "includes.h" -#include "buf.h" #include "cvs.h" #include "diff.h" #include "log.h" #include "proto.h" -#include "xmalloc.h" +int cvs_diff(int, char **); +void cvs_diff_local(struct cvs_file *); -struct cand { - int x; - int y; - int pred; -} cand; - -struct line { - int serial; - int value; -} *file[2]; - -/* - * The following struct is used to record change in formation when - * doing a "context" or "unified" diff. (see routine "change" to - * understand the highly mnemonic field names) - */ -struct context_vec { - int a; /* start line in old file */ - int b; /* end line in old file */ - int c; /* start line in new file */ - int d; /* end line in new file */ -}; - -struct diff_arg { - char *rev1; - char *rev2; - char *date1; - char *date2; -}; - -#if !defined(RCSPROG) -static int cvs_diff_init(struct cvs_cmd *, int, char **, int *); -static int cvs_diff_remote(CVSFILE *, void *); -static int cvs_diff_local(CVSFILE *, void *); -static int cvs_diff_pre_exec(struct cvsroot *); -static int cvs_diff_cleanup(void); -#endif - -static void output(FILE *, FILE *); -static void check(FILE *, FILE *); -static void range(int, int, char *); -static void uni_range(int, int); -static void dump_context_vec(FILE *, FILE *); -static void dump_unified_vec(FILE *, FILE *); -static int prepare(int, FILE *, off_t); -static void prune(void); -static void equiv(struct line *, int, struct line *, int, int *); -static void unravel(int); -static void unsort(struct line *, int, int *); -static void change(FILE *, FILE *, int, int, int, int); -static void sort(struct line *, int); -static int ignoreline(char *); -static int asciifile(FILE *); -static void fetch(long *, int, int, FILE *, int, int); -static int newcand(int, int, int); -static int search(int *, int, int); -static int skipline(FILE *); -static int isqrt(int); -static int stone(int *, int, int *, int *); -static int readhash(FILE *); -static int files_differ(FILE *, FILE *); -static char *match_function(const long *, int, FILE *); -static char *preadline(int, size_t, off_t); - - -#if !defined(RCSPROG) -static int Nflag; -#endif -static int aflag, bflag, dflag, iflag, pflag, tflag, Tflag, wflag; -static int context = 3; -int diff_format = D_NORMAL; -char *diff_file = NULL; -RCSNUM *diff_rev1 = NULL; -RCSNUM *diff_rev2 = NULL; -char diffargs[128]; -static struct stat stb1, stb2; -static char *ifdefname, *ignore_pats; -regex_t ignore_re; - -static int *J; /* will be overlaid on class */ -static int *class; /* will be overlaid on file[0] */ -static int *klist; /* will be overlaid on file[0] after class */ -static int *member; /* will be overlaid on file[1] */ -static int clen; -static int inifdef; /* whether or not we are in a #ifdef block */ -static int diff_len[2]; -static int pref, suff; /* length of prefix and suffix */ -static int slen[2]; -static int anychange; -static long *ixnew; /* will be overlaid on file[1] */ -static long *ixold; /* will be overlaid on klist */ -static struct cand *clist; /* merely a free storage pot for candidates */ -static int clistlen; /* the length of clist */ -static struct line *sfile[2]; /* shortened by pruning common prefix/suffix */ -static u_char *chrtran; /* translation table for case-folding */ -static struct context_vec *context_vec_start; -static struct context_vec *context_vec_end; -static struct context_vec *context_vec_ptr; - -#define FUNCTION_CONTEXT_SIZE 41 -static char lastbuf[FUNCTION_CONTEXT_SIZE]; -static int lastline; -static int lastmatchline; -BUF *diffbuf = NULL; - -/* - * chrtran points to one of 2 translation tables: cup2low if folding upper to - * lower case clow2low if not folding case - */ -u_char clow2low[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, - 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, - 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, - 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, - 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, - 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, - 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, - 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, - 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, - 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, - 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, - 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, - 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, - 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, - 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, - 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, - 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, - 0xfd, 0xfe, 0xff -}; - -u_char cup2low[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, - 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, - 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61, - 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, - 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x60, 0x61, 0x62, - 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, - 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, - 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, - 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, - 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, - 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, - 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, - 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, - 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, - 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, - 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, - 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, - 0xfd, 0xfe, 0xff -}; - -#if !defined(RCSPROG) struct cvs_cmd cvs_cmd_diff = { CVS_OP_DIFF, CVS_REQ_DIFF, "diff", { "di", "dif" }, @@ -308,1456 +33,173 @@ "[-k mode] [file ...]", "cD:iklNnpr:Ru", NULL, - CF_RECURSE | CF_IGNORE | CF_SORT | CF_KNOWN, - cvs_diff_init, - cvs_diff_pre_exec, - cvs_diff_remote, - cvs_diff_local, - NULL, - cvs_diff_cleanup, - CVS_CMD_SENDARGS2 | CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR + cvs_diff }; - -struct cvs_cmd cvs_cmd_rdiff = { - CVS_OP_RDIFF, CVS_REQ_DIFF, "rdiff", - { "pa", "patch" }, - "Create 'patch' format diffs between releases", - "[-flR] [-c | -u] [-s | -t] [-V ver] -D date | -r rev " - "[-D date2 | -rev2] module ...", - "cD:flRr:stuV:", - NULL, - CF_RECURSE | CF_IGNORE | CF_SORT | CF_KNOWN, - cvs_diff_init, - cvs_diff_pre_exec, - cvs_diff_remote, - cvs_diff_local, - NULL, - cvs_diff_cleanup, - CVS_CMD_SENDARGS2 | CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR -}; -#endif - -#if !defined(RCSPROG) -static struct diff_arg *dap = NULL; - -static int -cvs_diff_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg) +int +cvs_diff(int argc, char **argv) { int ch; + char *arg = "."; + struct cvs_recursion cr; - dap = xmalloc(sizeof(*dap)); - dap->date1 = dap->date2 = dap->rev1 = dap->rev2 = NULL; strlcpy(diffargs, argv[0], sizeof(diffargs)); - while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) { + while ((ch = getopt(argc, argv, cvs_cmd_diff.cmd_opts)) != -1) { switch (ch) { case 'c': strlcat(diffargs, " -c", sizeof(diffargs)); diff_format = D_CONTEXT; break; - case 'D': - if (dap->date1 == NULL && dap->rev1 == NULL) { - dap->date1 = optarg; - } else if (dap->date2 == NULL && dap->rev2 == NULL) { - dap->date2 = optarg; - } else { - cvs_log(LP_ERR, - "no more than two revisions/dates can " - "be specified"); - } - break; - case 'l': - strlcat(diffargs, " -l", sizeof(diffargs)); - cvs_cmd_diff.file_flags &= ~CF_RECURSE; - break; - case 'i': - strlcat(diffargs, " -i", sizeof(diffargs)); - iflag = 1; - break; - case 'N': - strlcat(diffargs, " -N", sizeof(diffargs)); - Nflag = 1; - break; case 'n': strlcat(diffargs, " -n", sizeof(diffargs)); diff_format = D_RCSDIFF; break; - case 'p': - strlcat(diffargs, " -p", sizeof(diffargs)); - pflag = 1; - break; case 'r': - if (dap->rev1 == NULL && dap->date1 == NULL) { - dap->rev1 = optarg; - } else if (dap->rev2 == NULL && - dap->date2 == NULL) { - dap->rev2 = optarg; + if (diff_rev1 == NULL) { + diff_rev1 = rcsnum_parse(optarg); + if (diff_rev1 == NULL) + fatal("rcsnum_parse failed"); + } else if (diff_rev2 == NULL) { + diff_rev2 = rcsnum_parse(optarg); + if (diff_rev2 == NULL) + fatal("rcsnum_parse failed"); } else { - cvs_log(LP_ERR, - "no more than two revisions/dates can " - "be specified"); - return (CVS_EX_USAGE); + fatal("no more than 2 revisions/dates can" + " be specified"); } break; - case 'R': - cvs_cmd_diff.file_flags |= CF_RECURSE; - break; case 'u': strlcat(diffargs, " -u", sizeof(diffargs)); diff_format = D_UNIFIED; break; default: - return (CVS_EX_USAGE); + fatal("%s", cvs_cmd_diff.cmd_synopsis); } } - *arg = optind; - return (0); -} + argc -= optind; + argv += optind; -int -cvs_diff_cleanup(void) -{ - if (dap != NULL) { - xfree(dap); - dap = NULL; - } - return (0); -} + cr.enterdir = NULL; + cr.leavedir = NULL; + cr.local = cvs_diff_local; + cr.remote = NULL; -/* - * cvs_diff_pre_exec() - * - */ -int -cvs_diff_pre_exec(struct cvsroot *root) -{ - if (root->cr_method != CVS_METHOD_LOCAL) { - /* send the flags */ - if (Nflag == 1) - cvs_sendarg(root, "-N", 0); - if (pflag == 1) - cvs_sendarg(root, "-p", 0); - - if (diff_format == D_CONTEXT) - cvs_sendarg(root, "-c", 0); - else if (diff_format == D_UNIFIED) - cvs_sendarg(root, "-u", 0); - - if (dap->rev1 != NULL) { - cvs_sendarg(root, "-r", 0); - cvs_sendarg(root, dap->rev1, 0); - } else if (dap->date1 != NULL) { - cvs_sendarg(root, "-D", 0); - cvs_sendarg(root, dap->date1, 0); - } - if (dap->rev2 != NULL) { - cvs_sendarg(root, "-r", 0); - cvs_sendarg(root, dap->rev2, 0); - } else if (dap->date2 != NULL) { - cvs_sendarg(root, "-D", 0); - cvs_sendarg(root, dap->date2, 0); - } - } - - return (0); -} - - -/* - * cvs_diff_file() - * - * Diff a single file. - */ -static int -cvs_diff_remote(struct cvs_file *cfp, void *arg) -{ - char fpath[MAXPATHLEN]; - struct cvsroot *root; - - if (cfp->cf_type == DT_DIR) { - if (cfp->cf_cvstat == CVS_FST_UNKNOWN) { - root = cfp->cf_parent->cf_root; - cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name); - } else { - root = cfp->cf_root; -#if 0 - if (cfp->cf_parent == NULL || - (root != cfp->cf_parent->cf_root)) { - cvs_connect(root); - cvs_diff_pre_exec(root); - } -#endif - - cvs_senddir(root, cfp); - } - - return (0); - } - - if (cfp->cf_cvstat == CVS_FST_LOST) { - cvs_log(LP_WARN, "cannot find file %s", cfp->cf_name); - return (0); - } - - diff_file = cvs_file_getpath(cfp, fpath, sizeof(fpath)); - - if (cfp->cf_parent != NULL) - root = cfp->cf_parent->cf_root; + if (argc > 0) + cvs_file_run(argc, argv, &cr); else - root = NULL; + cvs_file_run(1, &arg, &cr); - if (cfp->cf_cvstat == CVS_FST_UNKNOWN) { - cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name); - return (0); - } - - cvs_sendentry(root, cfp); - - if (cfp->cf_cvstat == CVS_FST_UPTODATE) { - cvs_sendreq(root, CVS_REQ_UNCHANGED, cfp->cf_name); - return (0); - } - - /* at this point, the file is modified */ - cvs_sendreq(root, CVS_REQ_MODIFIED, cfp->cf_name); - cvs_sendfile(root, diff_file); - return (0); } -static int -cvs_diff_local(CVSFILE *cf, void *arg) +void +cvs_diff_local(struct cvs_file *cf) { - char buf[64]; - char fpath[MAXPATHLEN], rcspath[MAXPATHLEN]; - char path_tmp1[MAXPATHLEN], path_tmp2[MAXPATHLEN]; + size_t len; + RCSNUM *r1; BUF *b1, *b2; - RCSNUM *r1, *r2; - RCSFILE *rf; + struct stat st; struct timeval tv[2], tv2[2]; + char rbuf[16], p1[MAXPATHLEN], p2[MAXPATHLEN]; - memset(&tv, 0, sizeof(tv)); - memset(&tv2, 0, sizeof(tv2)); + cvs_log(LP_TRACE, "cvs_diff_local(%s)", cf->file_path); - rf = NULL; - diff_file = cvs_file_getpath(cf, fpath, sizeof(fpath)); - - if (cf->cf_type == DT_DIR) { + if (cf->file_type == CVS_DIR) { if (verbosity > 1) - cvs_log(LP_NOTICE, "Diffing %s", fpath); - return (0); - } - - if (cf->cf_cvstat == CVS_FST_LOST) { - cvs_log(LP_WARN, "cannot find file %s", cf->cf_name); - return (0); - } - - if (cf->cf_cvstat == CVS_FST_UNKNOWN) { - cvs_log(LP_WARN, "I know nothing about %s", diff_file); - return (0); - } else if (cf->cf_cvstat == CVS_FST_UPTODATE) - return (0); - - /* at this point, the file is modified */ - cvs_rcs_getpath(cf, rcspath, sizeof(rcspath)); - - if ((rf = rcs_open(rcspath, RCS_READ)) == NULL) - fatal("cvs_diff_local: rcs_open `%s': %s", rcspath, - rcs_errstr(rcs_errno)); - - cvs_printf("Index: %s\n%s\nRCS file: %s\n", diff_file, - RCS_DIFF_DIV, rcspath); - - if (dap->rev1 == NULL) - r1 = cf->cf_lrev; - else { - if ((r1 = rcsnum_parse(dap->rev1)) == NULL) - fatal("cvs_diff_local: rcsnum_parse failed"); - } - - cvs_printf("retrieving revision %s\n", - rcsnum_tostr(r1, buf, sizeof(buf))); - b1 = rcs_getrev(rf, r1); - - if (b1 == NULL) { - cvs_log(LP_ERR, "failed to retrieve revision %s", - rcsnum_tostr(r1, buf, sizeof(buf))); - if (r1 != cf->cf_lrev) - rcsnum_free(r1); - rcs_close(rf); - return (CVS_EX_DATA); - } - tv[0].tv_sec = (long)rcs_rev_getdate(rf, r1); - tv[1].tv_sec = tv[0].tv_sec; - - if (r1 != cf->cf_lrev) - rcsnum_free(r1); - - if (dap->rev2 != NULL) { - cvs_printf("retrieving revision %s\n", dap->rev2); - if ((r2 = rcsnum_parse(dap->rev2)) == NULL) { - rcs_close(rf); - return (CVS_EX_DATA); - } - b2 = rcs_getrev(rf, r2); - tv2[0].tv_sec = (long)rcs_rev_getdate(rf, r2); - tv2[1].tv_sec = tv2[0].tv_sec; - rcsnum_free(r2); - } else { - struct stat st; - if (stat(diff_file, &st) < 0) { - cvs_log(LP_ERR, "failed to retrieve revision %s", - dap->rev2); - cvs_buf_free(b1); - return (CVS_EX_DATA); - } - b2 = cvs_buf_load(diff_file, BUF_AUTOEXT); - tv2[0].tv_sec = st.st_mtime; - tv2[1].tv_sec = st.st_mtime; - } - - rcs_close(rf); - - if (b2 == NULL) { - cvs_log(LP_ERR, "failed to retrieve revision %s", - dap->rev2); - cvs_buf_free(b1); - return (CVS_EX_DATA); - } - - cvs_printf("%s", diffargs); - cvs_printf(" -r%s", buf); - if (dap->rev2 != NULL) - cvs_printf(" -r%s", dap->rev2); - cvs_printf(" %s\n", diff_file); - strlcpy(path_tmp1, cvs_tmpdir, sizeof(path_tmp1)); - strlcat(path_tmp1, "/diff1.XXXXXXXXXX", sizeof(path_tmp1)); - cvs_buf_write_stmp(b1, path_tmp1, 0600); - cvs_buf_free(b1); - if (utimes(path_tmp1, (const struct timeval *)&tv) < 0) - cvs_log(LP_ERRNO, "error setting utimes"); - - strlcpy(path_tmp2, cvs_tmpdir, sizeof(path_tmp2)); - strlcat(path_tmp2, "/diff2.XXXXXXXXXX", sizeof(path_tmp2)); - cvs_buf_write_stmp(b2, path_tmp2, 0600); - cvs_buf_free(b2); - if (utimes(path_tmp2, (const struct timeval *)&tv2) < 0) - cvs_log(LP_ERRNO, "error setting utimes"); - - cvs_diffreg(path_tmp1, path_tmp2, NULL); - (void)unlink(path_tmp1); - (void)unlink(path_tmp2); - - return (0); -} -#endif - - -int -cvs_diffreg(const char *file1, const char *file2, BUF *out) -{ - FILE *f1, *f2; - int i, rval; - void *tmp; - - f1 = f2 = NULL; - rval = D_SAME; - anychange = 0; - lastline = 0; - lastmatchline = 0; - context_vec_ptr = context_vec_start - 1; - chrtran = (iflag ? cup2low : clow2low); - if (out != NULL) - diffbuf = out; - - f1 = fopen(file1, "r"); - if (f1 == NULL) { - cvs_log(LP_ERRNO, "%s", file1); - goto closem; - } - - f2 = fopen(file2, "r"); - if (f2 == NULL) { - cvs_log(LP_ERRNO, "%s", file2); - goto closem; - } - - if (stat(file1, &stb1) < 0) { - cvs_log(LP_ERRNO, "%s", file1); - goto closem; - } - if (stat(file2, &stb2) < 0) { - cvs_log(LP_ERRNO, "%s", file2); - goto closem; - } - switch (files_differ(f1, f2)) { - case 0: - goto closem; - case 1: - break; - default: - /* error */ - goto closem; - } - - if (!asciifile(f1) || !asciifile(f2)) { - rval = D_BINARY; - goto closem; - } - if (prepare(0, f1, stb1.st_size) < 0 || - prepare(1, f2, stb2.st_size) < 0) { - goto closem; - } - prune(); - sort(sfile[0], slen[0]); - sort(sfile[1], slen[1]); - - member = (int *)file[1]; - equiv(sfile[0], slen[0], sfile[1], slen[1], member); - tmp = xrealloc(member, slen[1] + 2, sizeof(*member)); - member = tmp; - - class = (int *)file[0]; - unsort(sfile[0], slen[0], class); - tmp = xrealloc(class, slen[0] + 2, sizeof(*class)); - class = tmp; - - klist = xcalloc(slen[0] + 2, sizeof(*klist)); - clen = 0; - clistlen = 100; - clist = xcalloc(clistlen, sizeof(*clist)); - - if ((i = stone(class, slen[0], member, klist)) < 0) - goto closem; - - xfree(member); - xfree(class); - - tmp = xrealloc(J, diff_len[0] + 2, sizeof(*J)); - J = tmp; - unravel(klist[i]); - xfree(clist); - xfree(klist); - - tmp = xrealloc(ixold, diff_len[0] + 2, sizeof(*ixold)); - ixold = tmp; - - tmp = xrealloc(ixnew, diff_len[1] + 2, sizeof(*ixnew)); - ixnew = tmp; - check(f1, f2); - output(f1, f2); - -closem: - if (anychange == 1) { - if (rval == D_SAME) - rval = D_DIFFER; - } - if (f1 != NULL) - fclose(f1); - if (f2 != NULL) - fclose(f2); - - return (rval); -} - -/* - * Check to see if the given files differ. - * Returns 0 if they are the same, 1 if different, and -1 on error. - * XXX - could use code from cmp(1) [faster] - */ -static int -files_differ(FILE *f1, FILE *f2) -{ - char buf1[BUFSIZ], buf2[BUFSIZ]; - size_t i, j; - - if (stb1.st_size != stb2.st_size) - return (1); - for (;;) { - i = fread(buf1, (size_t)1, sizeof(buf1), f1); - j = fread(buf2, (size_t)1, sizeof(buf2), f2); - if (i != j) - return (1); - if (i == 0 && j == 0) { - if (ferror(f1) || ferror(f2)) - return (1); - return (0); - } - if (memcmp(buf1, buf2, i) != 0) - return (1); - } -} - -static int -prepare(int i, FILE *fd, off_t filesize) -{ - void *tmp; - struct line *p; - int j, h; - size_t sz; - - rewind(fd); - - sz = ((size_t)filesize <= SIZE_MAX ? (size_t)filesize : SIZE_MAX) / 25; - if (sz < 100) - sz = 100; - - p = xcalloc(sz + 3, sizeof(*p)); - for (j = 0; (h = readhash(fd));) { - if (j == (int)sz) { - sz = sz * 3 / 2; - tmp = xrealloc(p, sz + 3, sizeof(*p)); - p = tmp; - } - p[++j].value = h; - } - diff_len[i] = j; - file[i] = p; - - return (0); -} - -static void -prune(void) -{ - int i, j; - - for (pref = 0; pref < diff_len[0] && pref < diff_len[1] && - file[0][pref + 1].value == file[1][pref + 1].value; - pref++) - ; - for (suff = 0; - (suff < diff_len[0] - pref) && (suff < diff_len[1] - pref) && - (file[0][diff_len[0] - suff].value == - file[1][diff_len[1] - suff].value); - suff++) - ; - for (j = 0; j < 2; j++) { - sfile[j] = file[j] + pref; - slen[j] = diff_len[j] - pref - suff; - for (i = 0; i <= slen[j]; i++) - sfile[j][i].serial = i; - } -} - -static void -equiv(struct line *a, int n, struct line *b, int m, int *c) -{ - int i, j; - - i = j = 1; - while (i <= n && j <= m) { - if (a[i].value < b[j].value) - a[i++].value = 0; - else if (a[i].value == b[j].value) - a[i++].value = j; - else - j++; - } - while (i <= n) - a[i++].value = 0; - b[m + 1].value = 0; - j = 0; - while (++j <= m) { - c[j] = -b[j].serial; - while (b[j + 1].value == b[j].value) { - j++; - c[j] = b[j].serial; - } - } - c[j] = -1; -} - -/* Code taken from ping.c */ -static int -isqrt(int n) -{ - int y, x = 1; - - if (n == 0) - return (0); - - do { /* newton was a stinker */ - y = x; - x = n / x; - x += y; - x /= 2; - } while (x - y > 1 || x - y < -1); - - return (x); -} - -static int -stone(int *a, int n, int *b, int *c) -{ - int ret; - int i, k, y, j, l; - int oldc, tc, oldl; - u_int numtries; - - /* XXX move the isqrt() out of the macro to avoid multiple calls */ - const u_int bound = dflag ? UINT_MAX : MAX(256, (u_int)isqrt(n)); - - k = 0; - if ((ret = newcand(0, 0, 0)) < 0) - return (-1); - c[0] = ret; - for (i = 1; i <= n; i++) { - j = a[i]; - if (j == 0) - continue; - y = -b[j]; - oldl = 0; - oldc = c[0]; - numtries = 0; - do { - if (y <= clist[oldc].y) - continue; - l = search(c, k, y); - if (l != oldl + 1) - oldc = c[l - 1]; - if (l <= k) { - if (clist[c[l]].y <= y) - continue; - tc = c[l]; - if ((ret = newcand(i, y, oldc)) < 0) - return (-1); - c[l] = ret; - oldc = tc; - oldl = l; - numtries++; - } else { - if ((ret = newcand(i, y, oldc)) < 0) - return (-1); - c[l] = ret; - k++; - break; - } - } while ((y = b[++j]) > 0 && numtries < bound); - } - return (k); -} - -static int -newcand(int x, int y, int pred) -{ - struct cand *q, *tmp; - int newclistlen; - - if (clen == clistlen) { - newclistlen = clistlen * 11 / 10; - tmp = xrealloc(clist, newclistlen, sizeof(*clist)); - clist = tmp; - clistlen = newclistlen; - } - q = clist + clen; - q->x = x; - q->y = y; - q->pred = pred; - return (clen++); -} - -static int -search(int *c, int k, int y) -{ - int i, j, l, t; - - if (clist[c[k]].y < y) /* quick look for typical case */ - return (k + 1); - i = 0; - j = k + 1; - for (;;) { - l = (i + j) / 2; - if (l <= i) - break; - t = clist[c[l]].y; - if (t > y) - j = l; - else if (t < y) - i = l; - else - return (l); - } - return (l + 1); -} - -static void -unravel(int p) -{ - struct cand *q; - int i; - - for (i = 0; i <= diff_len[0]; i++) - J[i] = i <= pref ? i : - i > diff_len[0] - suff ? i + diff_len[1] - diff_len[0] : 0; - for (q = clist + p; q->y != 0; q = clist + q->pred) - J[q->x + pref] = q->y + pref; -} - -/* - * Check does double duty: - * 1. ferret out any fortuitous correspondences due - * to confounding by hashing (which result in "jackpot") - * 2. collect random access indexes to the two files - */ -static void -check(FILE *f1, FILE *f2) -{ - int i, j, jackpot, c, d; - long ctold, ctnew; - - rewind(f1); - rewind(f2); - j = 1; - ixold[0] = ixnew[0] = 0; - jackpot = 0; - ctold = ctnew = 0; - for (i = 1; i <= diff_len[0]; i++) { - if (J[i] == 0) { - ixold[i] = ctold += skipline(f1); - continue; - } - while (j < J[i]) { - ixnew[j] = ctnew += skipline(f2); - j++; - } - if (bflag == 1 || wflag == 1 || iflag == 1) { - for (;;) { - c = getc(f1); - d = getc(f2); - /* - * GNU diff ignores a missing newline - * in one file if bflag || wflag. - */ - if ((bflag == 1 || wflag == 1) && - ((c == EOF && d == '\n') || - (c == '\n' && d == EOF))) { - break; - } - ctold++; - ctnew++; - if (bflag == 1 && isspace(c) && isspace(d)) { - do { - if (c == '\n') - break; - ctold++; - } while (isspace(c = getc(f1))); - do { - if (d == '\n') - break; - ctnew++; - } while (isspace(d = getc(f2))); - } else if (wflag == 1) { - while (isspace(c) && c != '\n') { - c = getc(f1); - ctold++; - } - while (isspace(d) && d != '\n') { - d = getc(f2); - ctnew++; - } - } - if (chrtran[c] != chrtran[d]) { - jackpot++; - J[i] = 0; - if (c != '\n' && c != EOF) - ctold += skipline(f1); - if (d != '\n' && c != EOF) - ctnew += skipline(f2); - break; - } - if (c == '\n' || c == EOF) - break; - } - } else { - for (;;) { - ctold++; - ctnew++; - if ((c = getc(f1)) != (d = getc(f2))) { - /* jackpot++; */ - J[i] = 0; - if (c != '\n' && c != EOF) - ctold += skipline(f1); - if (d != '\n' && c != EOF) - ctnew += skipline(f2); - break; - } - if (c == '\n' || c == EOF) - break; - } - } - ixold[i] = ctold; - ixnew[j] = ctnew; - j++; - } - for (; j <= diff_len[1]; j++) - ixnew[j] = ctnew += skipline(f2); - /* - * if (jackpot != 0) - * cvs_printf("jackpot\n"); - */ -} - -/* shellsort CACM #201 */ -static void -sort(struct line *a, int n) -{ - struct line *ai, *aim, w; - int j, m = 0, k; - - if (n == 0) + cvs_log(LP_NOTICE, "Diffing inside %s", cf->file_path); return; - for (j = 1; j <= n; j *= 2) - m = 2 * j - 1; - for (m /= 2; m != 0; m /= 2) { - k = n - m; - for (j = 1; j <= k; j++) { - for (ai = &a[j]; ai > a; ai -= m) { - aim = &ai[m]; - if (aim < ai) - break; /* wraparound */ - if (aim->value > ai[0].value || - (aim->value == ai[0].value && - aim->serial > ai[0].serial)) - break; - w.value = ai[0].value; - ai[0].value = aim->value; - aim->value = w.value; - w.serial = ai[0].serial; - ai[0].serial = aim->serial; - aim->serial = w.serial; - } - } } -} -static void -unsort(struct line *f, int l, int *b) -{ - int *a, i; + cvs_file_classify(cf); - a = xcalloc(l + 1, sizeof(*a)); - for (i = 1; i <= l; i++) - a[f[i].serial] = f[i].value; - for (i = 1; i <= l; i++) - b[i] = a[i]; - xfree(a); -} - -static int -skipline(FILE *f) -{ - int i, c; - - for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++) - continue; - return (i); -} - -static void -output(FILE *f1, FILE *f2) -{ - int m, i0, i1, j0, j1; - - rewind(f1); - rewind(f2); - m = diff_len[0]; - J[0] = 0; - J[m + 1] = diff_len[1] + 1; - for (i0 = 1; i0 <= m; i0 = i1 + 1) { - while (i0 <= m && J[i0] == J[i0 - 1] + 1) - i0++; - j0 = J[i0 - 1] + 1; - i1 = i0 - 1; - while (i1 < m && J[i1 + 1] == 0) - i1++; - j1 = J[i1 + 1] - 1; - J[i1] = j1; - change(f1, f2, i0, i1, j0, j1); - } - if (m == 0) - change(f1, f2, 1, 0, 1, diff_len[1]); - if (diff_format == D_IFDEF) { - for (;;) { -#define c i0 - if ((c = getc(f1)) == EOF) - return; - diff_output("%c", c); - } -#undef c - } - if (anychange != 0) { - if (diff_format == D_CONTEXT) - dump_context_vec(f1, f2); - else if (diff_format == D_UNIFIED) - dump_unified_vec(f1, f2); - } -} - -static __inline void -range(int a, int b, char *separator) -{ - diff_output("%d", a > b ? b : a); - if (a < b) - diff_output("%s%d", separator, b); -} - -static __inline void -uni_range(int a, int b) -{ - if (a < b) - diff_output("%d,%d", a, b - a + 1); - else if (a == b) - diff_output("%d", b); - else - diff_output("%d,0", b); -} - -static char * -preadline(int fd, size_t rlen, off_t off) -{ - char *line; - ssize_t nr; - - line = xmalloc(rlen + 1); - if ((nr = pread(fd, line, rlen, off)) < 0) { - cvs_log(LP_ERRNO, "preadline failed"); - return (NULL); - } - line[nr] = '\0'; - return (line); -} - -static int -ignoreline(char *line) -{ - int ret; - - ret = regexec(&ignore_re, line, (size_t)0, NULL, 0); - xfree(line); - return (ret == 0); /* if it matched, it should be ignored. */ -} - -/* - * Indicate that there is a difference between lines a and b of the from file - * to get to lines c to d of the to file. If a is greater then b then there - * are no lines in the from file involved and this means that there were - * lines appended (beginning at b). If c is greater than d then there are - * lines missing from the to file. - */ -static void -change(FILE *f1, FILE *f2, int a, int b, int c, int d) -{ - int i; - static size_t max_context = 64; - char buf[64]; - struct tm *t; - - if (diff_format != D_IFDEF && a > b && c > d) + if (cf->file_status == FILE_LOST) { + cvs_log(LP_ERR, "cannot find file %s", cf->file_path); return; - if (ignore_pats != NULL) { - char *line; - /* - * All lines in the change, insert, or delete must - * match an ignore pattern for the change to be - * ignored. - */ - if (a <= b) { /* Changes and deletes. */ - for (i = a; i <= b; i++) { - line = preadline(fileno(f1), - ixold[i] - ixold[i - 1], ixold[i - 1]); - if (!ignoreline(line)) - goto proceed; - } - } - if (a > b || c <= d) { /* Changes and inserts. */ - for (i = c; i <= d; i++) { - line = preadline(fileno(f2), - ixnew[i] - ixnew[i - 1], ixnew[i - 1]); - if (!ignoreline(line)) - goto proceed; - } - } + } else if (cf->file_status == FILE_UNKNOWN) { + cvs_log(LP_ERR, "I know nothing about %s", cf->file_path); return; - } -proceed: - if (diff_format == D_CONTEXT || diff_format == D_UNIFIED) { - /* - * Allocate change records as needed. - */ - if (context_vec_ptr == context_vec_end - 1) { - struct context_vec *tmp; - ptrdiff_t offset = context_vec_ptr - context_vec_start; - max_context <<= 1; - tmp = xrealloc(context_vec_start, max_context, - sizeof(*context_vec_start)); - context_vec_start = tmp; - context_vec_end = context_vec_start + max_context; - context_vec_ptr = context_vec_start + offset; - } - if (anychange == 0) { - /* - * Print the context/unidiff header first time through. - */ - t = localtime(&stb1.st_mtime); - (void)strftime(buf, sizeof(buf), - "%Y/%m/%d %H:%M:%S", t); - - diff_output("%s %s %s", - diff_format == D_CONTEXT ? "***" : "---", diff_file, - buf); - - if (diff_rev1 != NULL) { - rcsnum_tostr(diff_rev1, buf, sizeof(buf)); - diff_output("\t%s", buf); - } - - printf("\n"); - - t = localtime(&stb2.st_mtime); - (void)strftime(buf, sizeof(buf), - "%Y/%m/%d %H:%M:%S", t); - - diff_output("%s %s %s", - diff_format == D_CONTEXT ? "---" : "+++", diff_file, - buf); - - if (diff_rev2 != NULL) { - rcsnum_tostr(diff_rev2, buf, sizeof(buf)); - diff_output("\t%s", buf); - } - - printf("\n"); - anychange = 1; - } else if (a > context_vec_ptr->b + (2 * context) + 1 && - c > context_vec_ptr->d + (2 * context) + 1) { - /* - * If this change is more than 'context' lines from the - * previous change, dump the record and reset it. - */ - if (diff_format == D_CONTEXT) - dump_context_vec(f1, f2); - else - dump_unified_vec(f1, f2); - } - context_vec_ptr++; - context_vec_ptr->a = a; - context_vec_ptr->b = b; - context_vec_ptr->c = c; - context_vec_ptr->d = d; + } else if (cf->file_status == FILE_UPTODATE && diff_rev2 == NULL) return; - } - if (anychange == 0) - anychange = 1; - switch (diff_format) { - case D_BRIEF: - return; - case D_NORMAL: - range(a, b, ","); - diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c'); - if (diff_format == D_NORMAL) - range(c, d, ","); - diff_output("\n"); - break; - case D_RCSDIFF: - if (a > b) - diff_output("a%d %d\n", b, d - c + 1); - else { - diff_output("d%d %d\n", a, b - a + 1); - if (!(c > d)) /* add changed lines */ - diff_output("a%d %d\n", b, d - c + 1); - } - break; - } - if (diff_format == D_NORMAL || diff_format == D_IFDEF) { - fetch(ixold, a, b, f1, '<', 1); - if (a <= b && c <= d && diff_format == D_NORMAL) - diff_output("---\n"); - } - fetch(ixnew, c, d, f2, diff_format == D_NORMAL ? '>' : '\0', 0); - if (inifdef) { - diff_output("#endif /* %s */\n", ifdefname); - inifdef = 0; - } -} + diff_file = cf->file_path; + cvs_printf("Index: %s\n%s\nRCS file: %s\n", cf->file_path, + RCS_DIFF_DIV, cf->file_rpath); -static void -fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile) -{ - long j, nc; - int i, c, col; + if (diff_rev1 != NULL) + r1 = diff_rev1; + else + r1 = cf->file_ent->ce_rev; - /* - * When doing #ifdef's, copy down to current line - * if this is the first file, so that stuff makes it to output. - */ - if (diff_format == D_IFDEF && oldfile) { - long curpos = ftell(lb); - /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ - nc = f[a > b ? b : a - 1] - curpos; - for (i = 0; i < nc; i++) - diff_output("%c", getc(lb)); - } - if (a > b) - return; - if (diff_format == D_IFDEF) { - if (inifdef) { - diff_output("#else /* %s%s */\n", - oldfile == 1 ? "!" : "", ifdefname); - } else { - if (oldfile) - diff_output("#ifndef %s\n", ifdefname); - else - diff_output("#ifdef %s\n", ifdefname); - } - inifdef = 1 + oldfile; - } - for (i = a; i <= b; i++) { - fseek(lb, f[i - 1], SEEK_SET); - nc = f[i] - f[i - 1]; - if (diff_format != D_IFDEF && ch != '\0') { - diff_output("%c", ch); - if (Tflag == 1 && (diff_format == D_NORMAL || - diff_format == D_CONTEXT || - diff_format == D_UNIFIED)) - diff_output("\t"); - else if (diff_format != D_UNIFIED) - diff_output(" "); - } - col = 0; - for (j = 0; j < nc; j++) { - if ((c = getc(lb)) == EOF) { - if (diff_format == D_RCSDIFF) - cvs_log(LP_WARN, - "No newline at end of file"); - else - diff_output("\n\\ No newline at end of " - "file"); - return; - } - if (c == '\t' && tflag == 1) { - do { - diff_output(" "); - } while (++col & 7); - } else { - diff_output("%c", c); - col++; - } - } - } -} + diff_rev1 = r1; + rcsnum_tostr(r1, rbuf , sizeof(rbuf)); + cvs_printf("retrieving revision %s\n", rbuf); + if ((b1 = rcs_getrev(cf->file_rcs, r1)) == NULL) + fatal("failed to retrieve revision %s", rbuf); -/* - * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578. - */ -static int -readhash(FILE *f) -{ - int i, t, space; - int sum; + tv[0].tv_sec = rcs_rev_getdate(cf->file_rcs, r1); + tv[0].tv_usec = 0; + tv[1] = tv[0]; - sum = 1; - space = 0; - if (bflag != 1 && wflag != 1) { - if (iflag == 1) - for (i = 0; (t = getc(f)) != '\n'; i++) { - if (t == EOF) { - if (i == 0) - return (0); - break; - } - sum = sum * 127 + chrtran[t]; - } - else - for (i = 0; (t = getc(f)) != '\n'; i++) { - if (t == EOF) { - if (i == 0) - return (0); - break; - } - sum = sum * 127 + t; - } + if (diff_rev2 != NULL) { + rcsnum_tostr(diff_rev2, rbuf, sizeof(rbuf)); + cvs_printf("retrieving revision %s\n", rbuf); + if ((b2 = rcs_getrev(cf->file_rcs, diff_rev2)) == NULL) + fatal("failed to retrieve revision %s", rbuf); + + tv2[0].tv_sec = rcs_rev_getdate(cf->file_rcs, diff_rev2); + tv2[0].tv_usec = 0; + tv2[1] = tv2[0]; } else { - for (i = 0;;) { - switch (t = getc(f)) { - case '\t': - case ' ': - space++; - continue; - default: - if (space != 0 && wflag != 1) { - i++; - space = 0; - } - sum = sum * 127 + chrtran[t]; - i++; - continue; - case EOF: - if (i == 0) - return (0); - /* FALLTHROUGH */ - case '\n': - break; - } - break; - } - } - /* - * There is a remote possibility that we end up with a zero sum. - * Zero is used as an EOF marker, so return 1 instead. - */ - return (sum == 0 ? 1 : sum); -} + if (fstat(cf->fd, &st) == -1) + fatal("fstat failed %s", strerror(errno)); + if ((b2 = cvs_buf_load(cf->file_path, BUF_AUTOEXT)) == NULL) + fatal("failed to load %s", cf->file_path); -static int -asciifile(FILE *f) -{ - char buf[BUFSIZ]; - size_t i, cnt; + st.st_mtime = cvs_hack_time(st.st_mtime, 1); + if (st.st_mtime == 0) + fatal("cvs_diff_local: to gmt failed"); - if (aflag == 1 || f == NULL) - return (1); - - rewind(f); - cnt = fread(buf, (size_t)1, sizeof(buf), f); - for (i = 0; i < cnt; i++) - if (!isprint(buf[i]) && !isspace(buf[i])) - return (0); - return (1); -} - -static char* -match_function(const long *f, int pos, FILE *fp) -{ - unsigned char buf[FUNCTION_CONTEXT_SIZE]; - size_t nc; - int last = lastline; - char *p; - - lastline = pos; - while (pos > last) { - fseek(fp, f[pos - 1], SEEK_SET); - nc = f[pos] - f[pos - 1]; - if (nc >= sizeof(buf)) - nc = sizeof(buf) - 1; - nc = fread(buf, (size_t)1, nc, fp); - if (nc > 0) { - buf[nc] = '\0'; - p = strchr((const char *)buf, '\n'); - if (p != NULL) - *p = '\0'; - if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') { - strlcpy(lastbuf, (const char *)buf, - sizeof lastbuf); - lastmatchline = pos; - return lastbuf; - } - } - pos--; + tv2[0].tv_sec = st.st_mtime; + tv2[0].tv_usec = 0; + tv2[1] = tv2[0]; } - return (lastmatchline > 0) ? lastbuf : NULL; -} + cvs_printf("%s", diffargs); -/* dump accumulated "context" diff changes */ -static void -dump_context_vec(FILE *f1, FILE *f2) -{ - struct context_vec *cvp = context_vec_start; - int lowa, upb, lowc, upd, do_output; - int a, b, c, d; - char ch, *f; + rcsnum_tostr(r1, rbuf, sizeof(rbuf)); + cvs_printf(" -r%s", rbuf); - if (context_vec_start > context_vec_ptr) - return; - - b = d = 0; /* gcc */ - lowa = MAX(1, cvp->a - context); - upb = MIN(diff_len[0], context_vec_ptr->b + context); - lowc = MAX(1, cvp->c - context); - upd = MIN(diff_len[1], context_vec_ptr->d + context); - - diff_output("***************"); - if (pflag == 1) { - f = match_function(ixold, lowa - 1, f1); - if (f != NULL) { - diff_output(" "); - diff_output("%s", f); - } + if (diff_rev2 != NULL) { + rcsnum_tostr(diff_rev2, rbuf, sizeof(rbuf)); + cvs_printf(" -r%s", rbuf); } - diff_output("\n*** "); - range(lowa, upb, ","); - diff_output(" ****\n"); - /* - * Output changes to the "old" file. The first loop suppresses - * output if there were no changes to the "old" file (we'll see - * the "old" lines as context in the "new" list). - */ - do_output = 0; - for (; cvp <= context_vec_ptr; cvp++) - if (cvp->a <= cvp->b) { - cvp = context_vec_start; - do_output++; - break; - } - if (do_output != 0) { - while (cvp <= context_vec_ptr) { - a = cvp->a; - b = cvp->b; - c = cvp->c; - d = cvp->d; + cvs_printf(" %s\n", cf->file_path); - if (a <= b && c <= d) - ch = 'c'; - else - ch = (a <= b) ? 'd' : 'a'; + len = strlcpy(p1, cvs_tmpdir, sizeof(p1)); + if (len >= sizeof(p1)) + fatal("cvs_diff_local: truncation"); - if (ch == 'a') - fetch(ixold, lowa, b, f1, ' ', 0); - else { - fetch(ixold, lowa, a - 1, f1, ' ', 0); - fetch(ixold, a, b, f1, - ch == 'c' ? '!' : '-', 0); - } - lowa = b + 1; - cvp++; - } - fetch(ixold, b + 1, upb, f1, ' ', 0); - } - /* output changes to the "new" file */ - diff_output("--- "); - range(lowc, upd, ","); - diff_output(" ----\n"); + len = strlcat(p1, "/diff1.XXXXXXXXXX", sizeof(p1)); + if (len >= sizeof(p1)) + fatal("cvs_diff_local: truncation"); - do_output = 0; - for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) - if (cvp->c <= cvp->d) { - cvp = context_vec_start; - do_output++; - break; - } - if (do_output != 0) { - while (cvp <= context_vec_ptr) { - a = cvp->a; - b = cvp->b; - c = cvp->c; - d = cvp->d; + cvs_buf_write_stmp(b1, p1, 0600, tv); + cvs_buf_free(b1); - if (a <= b && c <= d) - ch = 'c'; - else - ch = (a <= b) ? 'd' : 'a'; + len = strlcpy(p2, cvs_tmpdir, sizeof(p2)); + if (len >= sizeof(p2)) + fatal("cvs_diff_local: truncation"); - if (ch == 'd') - fetch(ixnew, lowc, d, f2, ' ', 0); - else { - fetch(ixnew, lowc, c - 1, f2, ' ', 0); - fetch(ixnew, c, d, f2, - ch == 'c' ? '!' : '+', 0); - } - lowc = d + 1; - cvp++; - } - fetch(ixnew, d + 1, upd, f2, ' ', 0); - } - context_vec_ptr = context_vec_start - 1; -} + len = strlcat(p2, "/diff2.XXXXXXXXXX", sizeof(p2)); + if (len >= sizeof(p2)) + fatal("cvs_diff_local: truncation"); -/* dump accumulated "unified" diff changes */ -static void -dump_unified_vec(FILE *f1, FILE *f2) -{ - struct context_vec *cvp = context_vec_start; - int lowa, upb, lowc, upd; - int a, b, c, d; - char ch, *f; + cvs_buf_write_stmp(b2, p2, 0600, tv2); + cvs_buf_free(b2); - if (context_vec_start > context_vec_ptr) - return; - - b = d = 0; /* gcc */ - lowa = MAX(1, cvp->a - context); - upb = MIN(diff_len[0], context_vec_ptr->b + context); - lowc = MAX(1, cvp->c - context); - upd = MIN(diff_len[1], context_vec_ptr->d + context); - - diff_output("@@ -"); - uni_range(lowa, upb); - diff_output(" +"); - uni_range(lowc, upd); - diff_output(" @@"); - if (pflag == 1) { - f = match_function(ixold, lowa - 1, f1); - if (f != NULL) { - diff_output(" "); - diff_output("%s", f); - } - } - diff_output("\n"); - - /* - * Output changes in "unified" diff format--the old and new lines - * are printed together. - */ - for (; cvp <= context_vec_ptr; cvp++) { - a = cvp->a; - b = cvp->b; - c = cvp->c; - d = cvp->d; - - /* - * c: both new and old changes - * d: only changes in the old file - * a: only changes in the new file - */ - if (a <= b && c <= d) - ch = 'c'; - else - ch = (a <= b) ? 'd' : 'a'; - - switch (ch) { - case 'c': - fetch(ixold, lowa, a - 1, f1, ' ', 0); - fetch(ixold, a, b, f1, '-', 0); - fetch(ixnew, c, d, f2, '+', 0); - break; - case 'd': - fetch(ixold, lowa, a - 1, f1, ' ', 0); - fetch(ixold, a, b, f1, '-', 0); - break; - case 'a': - fetch(ixnew, lowc, c - 1, f2, ' ', 0); - fetch(ixnew, c, d, f2, '+', 0); - break; - } - lowa = b + 1; - lowc = d + 1; - } - fetch(ixnew, d + 1, upd, f2, ' ', 0); - - context_vec_ptr = context_vec_start - 1; -} - -void -diff_output(const char *fmt, ...) -{ - va_list vap; - int i; - char *str; - - va_start(vap, fmt); - i = vasprintf(&str, fmt, vap); - va_end(vap); - if (i == -1) - fatal("diff_output: %s", strerror(errno)); - if (diffbuf != NULL) - cvs_buf_append(diffbuf, str, strlen(str)); - else - cvs_printf("%s", str); - xfree(str); + cvs_diffreg(p1, p2, NULL); + cvs_worklist_run(&temp_files, cvs_worklist_unlink); }