/*
 *                     RCS file comparison
 */
/*****************************************************************************
 *                       rcsfcmp()
 *                       Testprogram: define FCMPTEST
 *****************************************************************************
 */

/* Copyright (C) 1982, 1988, 1989 Walter Tichy
   Copyright 1990 by Paul Eggert
   Distributed under license by the Free Software Foundation, Inc.

This file is part of RCS.

RCS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

RCS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with RCS; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.

Report problems and direct all questions to:

    rcs-bugs@cs.purdue.edu

*/





/* $Log: rcsfcmp.c%v $
 * Revision 1.2  1991/08/23  13:33:33  SGP
 * Ported to MSDOS using Borland C++
 *
 * Revision 5.5  1990/11/27  09:26:05  eggert
 * Fix comment leader bug.
 *
 * Revision 5.4  1990/11/01  05:03:42  eggert
 * Permit arbitrary data in logs and comment leaders.
 *
 * Revision 5.3  1990/09/11  02:41:15  eggert
 * Don't ignore differences inside keyword strings if -ko is set.
 *
 * Revision 5.1  1990/08/29  07:13:58  eggert
 * Clean old log messages too.
 *
 * Revision 5.0  1990/08/22  08:12:49  eggert
 * Don't append "checked in with -k by " log to logs,
 * so that checking in a program with -k doesn't change it.
 * Ansify and Posixate.  Remove lint.
 *
 * Revision 4.5  89/05/01  15:12:42  narten
 * changed copyright header to reflect current distribution rules
 * 
 * Revision 4.4  88/08/09  19:12:50  eggert
 * Shrink stdio code size.
 * 
 * Revision 4.3  87/12/18  11:40:02  narten
 * lint cleanups (Guy Harris)
 * 
 * Revision 4.2  87/10/18  10:33:06  narten
 * updting version number. Changes relative to 1.1 actually relative to 
 * 4.1
 * 
 * Revision 1.2  87/03/27  14:22:19  jenkins
 * Port to suns
 * 
 * Revision 4.1  83/05/10  16:24:04  wft
 * Marker matching now uses trymatch(). Marker pattern is now
 * checked precisely.
 * 
 * Revision 3.1  82/12/04  13:21:40  wft
 * Initial revision.
 *
 */

/*
#define FCMPTEST
*/
/* Testprogram; prints out whether two files are identical,
 * except for keywords
 */

#include  "rcsbase.h"

libId(fcmpId, "$Id: rcsfcmp.c%v 1.2 1991/08/23 13:33:33 SGP Exp $")


	int
rcsfcmp(const char *xfname,
		const char *uxfname,
		const struct hshentry *delta)
/* Function: compares the files xfname and uxfname. Returns true
 * if xfname has the same contents as uxfname, while disregarding
 * keyword values. For the LOG-keyword, rcsfcmp skips the log message
 * given by the parameter delta in xfname. Thus, rcsfcmp returns true
 * if xfname contains the same as uxfname, with the keywords expanded.
 * Implementation: character-by-character comparison until $ is found.
 * If a $ is found, read in the marker keywords; if they are real keywords
 * and identical, read in keyword value. If value is terminated properly,
 * disregard it and optionally skip log message; otherwise, compare value.
 */
{
    register int xc,uxc;
    char xkeyword[keylength+2],   uxkeyword[keylength+2];
    int eqkeyvals;
    register FILE * xfp, * uxfp;
    register int delimiter;
    register char * tp;
    register const char *sp;
    int result;
    enum markers match1,match2;

    errno = 0;
    if (!(xfp=fopen(sp=xfname,"r")) || !(errno=0, uxfp=fopen(sp=uxfname,"r"))) {
       efaterror(sp);
    }
    result=false;
    delimiter = Expand==OLD_EXPAND ? EOF : KDELIM;
    xc=getc(xfp); uxc=getc(uxfp);
    while( xc == uxc) { /* comparison loop */
        if (xc==EOF) { /* finished; everything is the same*/
            result=true;
            break;
        }
	if (xc != delimiter) {
            /* get the next characters */
            xc=getc(xfp); uxc=getc(uxfp);
        } else {
            /* try to get both keywords */
            tp = xkeyword;
            while( (xc=getc(xfp))!=EOF && (tp< xkeyword+keylength) && (xc!='\n')
				   && (xc!=KDELIM) && (xc!=VDELIM))
                *tp++ = xc;
	    *tp++ = xc;  /* add closing K/VDELIM */
            *tp='\0';
            tp = uxkeyword;
            while( (uxc=getc(uxfp))!=EOF && (tp< uxkeyword+keylength) && (uxc!='\n')
                   && (uxc!=KDELIM) && (uxc!=VDELIM))
                *tp++ = uxc;
	    *tp++ = xc;  /* add closing K/VDELIM */
            *tp='\0';
	    /* Now we have 2 keywords, or something that looks like it. */
	    match1 = trymatch(xkeyword);
	    match2 = trymatch(uxkeyword);
	    if (match1 != match2) break; /* not identical */
#ifdef FCMPTEST
	    VOID printf("found potential keywords %s and %s\n",xkeyword,uxkeyword);
#endif

	    if (match1 == Nomatch) {
		/* not a keyword pattern, but could still be identical */
		if (strcmp(xkeyword,uxkeyword)==0)
		     continue;
		else break;
	    }
#ifdef FCMPTEST
	    VOID printf("found common keyword %s\n",xkeyword);
#endif
	    eqkeyvals = 1;
	    for (;;) {
		if (xc==uxc) {
		    if (xc==KDELIM)
			break;
		} else {
		    eqkeyvals = 0;
		    if (xc==KDELIM) {
			while (uxc!=KDELIM && uxc!='\n' && uxc!=EOF)
			    uxc = getc(uxfp);
			break;
		    }
		    if (uxc==KDELIM) {
			while (xc!=KDELIM && xc!='\n' && xc!=EOF)
			    xc = getc(xfp);
			break;
		    }
		}
		if (xc=='\n' || uxc=='\n' || xc==EOF || uxc==EOF)
		    break;
		xc = getc(xfp);
		uxc = getc(uxfp);
	    }
	    if (xc!=uxc) break; /* not the same */
	    if (xc==KDELIM) {
		xc=getc(xfp); uxc=getc(uxfp); /* skip closing KDELIM */
		/* if the keyword is LOG, also skip the log message in xfp*/
		if (match1==Log) {
		    /* first, compute the number of line feeds in log msg */
		    unsigned lncnt;
		    size_t ls, ccnt;
		    lncnt = 3;
		    sp = delta->log.string;
			ls = delta->log.size;
		    if (sizeof(ciklog)-1<=ls && !strncmp(sp,ciklog,sizeof(ciklog)-1))
			continue; /* this log message wasn't inserted */
		    while (ls--) if (*sp++=='\n') lncnt++;
		    while(xc!=EOF) {
			if (xc=='\n')
			    if(--lncnt==0) break;
			xc=getc(xfp);
		    }
		    /* skip last comment leader */
		    /* Can't just skip another line here, because there may be */
		    /* additional characters on the line (after the Log....$)  */
		    for (ccnt=Comment.size; ccnt--; ) {
			xc=getc(xfp);
			if(xc=='\n') break;
			/* reads to the end of the comment leader or '\n',     */
			/* whatever comes first. This is because some editors  */
			/* strip off trailing blanks from a leader like " * ". */
		    }
		}
		} else {
		/* both end in the same character, but not a KDELIM */
		/* must compare string values.*/
#ifdef FCMPTEST
		VOID printf("non-terminated keywords %s, potentially different values\n",xkeyword);
#endif
		if (!eqkeyvals) break;
            }
        }
    }
    ffclose(xfp); ffclose(uxfp);
    return result;
}



#ifdef FCMPTEST

const char cmdid[] = "rcsfcmp";

main(int argc, char *argv[])
/* first argument: comment leader; 2nd: log message, 3rd: expanded file,
 * 4th: unexpanded file
 */
{       struct hshentry delta;

	Comment.string = argv[1];
	Comment.size = strlen(argv[1]);
	delta.log.string = argv[2];
	delta.log.size = strlen(argv[2]);
		if (rcsfcmp(argv[3],argv[4],&delta))
				VOID printf("files are the same\n");
        else    VOID printf("files are different\n");
}
#endif
