Home | History | Annotate | Line # | Download | only in src
      1 /*	$NetBSD: rcsfcmp.c,v 1.2 2016/01/14 04:22:39 christos Exp $	*/
      2 
      3 /* Compare working files, ignoring RCS keyword strings.  */
      4 
      5 /*****************************************************************************
      6  *                       rcsfcmp()
      7  *                       Testprogram: define FCMPTEST
      8  *****************************************************************************
      9  */
     10 
     11 /* Copyright 1982, 1988, 1989 Walter Tichy
     12    Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
     13    Distributed under license by the Free Software Foundation, Inc.
     14 
     15 This file is part of RCS.
     16 
     17 RCS is free software; you can redistribute it and/or modify
     18 it under the terms of the GNU General Public License as published by
     19 the Free Software Foundation; either version 2, or (at your option)
     20 any later version.
     21 
     22 RCS is distributed in the hope that it will be useful,
     23 but WITHOUT ANY WARRANTY; without even the implied warranty of
     24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     25 GNU General Public License for more details.
     26 
     27 You should have received a copy of the GNU General Public License
     28 along with RCS; see the file COPYING.
     29 If not, write to the Free Software Foundation,
     30 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     31 
     32 Report problems and direct all questions to:
     33 
     34     rcs-bugs (at) cs.purdue.edu
     35 
     36 */
     37 
     38 
     39 
     40 
     41 
     42 /*
     43  * Log: rcsfcmp.c,v
     44  * Revision 5.14  1995/06/16 06:19:24  eggert
     45  * Update FSF address.
     46  *
     47  * Revision 5.13  1995/06/01 16:23:43  eggert
     48  * (rcsfcmp): Add -kb support.
     49  *
     50  * Revision 5.12  1994/03/17 14:05:48  eggert
     51  * Normally calculate the $Log prefix from context, not from RCS file.
     52  * Calculate line numbers correctly even if the $Log prefix contains newlines.
     53  * Remove lint.
     54  *
     55  * Revision 5.11  1993/11/03 17:42:27  eggert
     56  * Fix yet another off-by-one error when comparing Log string expansions.
     57  *
     58  * Revision 5.10  1992/07/28 16:12:44  eggert
     59  * Statement macro names now end in _.
     60  *
     61  * Revision 5.9  1991/10/07  17:32:46  eggert
     62  * Count log lines correctly.
     63  *
     64  * Revision 5.8  1991/08/19  03:13:55  eggert
     65  * Tune.
     66  *
     67  * Revision 5.7  1991/04/21  11:58:22  eggert
     68  * Fix errno bug.  Add MS-DOS support.
     69  *
     70  * Revision 5.6  1991/02/28  19:18:47  eggert
     71  * Open work file at most once.
     72  *
     73  * Revision 5.5  1990/11/27  09:26:05  eggert
     74  * Fix comment leader bug.
     75  *
     76  * Revision 5.4  1990/11/01  05:03:42  eggert
     77  * Permit arbitrary data in logs and comment leaders.
     78  *
     79  * Revision 5.3  1990/09/11  02:41:15  eggert
     80  * Don't ignore differences inside keyword strings if -ko is set.
     81  *
     82  * Revision 5.1  1990/08/29  07:13:58  eggert
     83  * Clean old log messages too.
     84  *
     85  * Revision 5.0  1990/08/22  08:12:49  eggert
     86  * Don't append "checked in with -k by " log to logs,
     87  * so that checking in a program with -k doesn't change it.
     88  * Ansify and Posixate.  Remove lint.
     89  *
     90  * Revision 4.5  89/05/01  15:12:42  narten
     91  * changed copyright header to reflect current distribution rules
     92  *
     93  * Revision 4.4  88/08/09  19:12:50  eggert
     94  * Shrink stdio code size.
     95  *
     96  * Revision 4.3  87/12/18  11:40:02  narten
     97  * lint cleanups (Guy Harris)
     98  *
     99  * Revision 4.2  87/10/18  10:33:06  narten
    100  * updting version number. Changes relative to 1.1 actually relative to
    101  * 4.1
    102  *
    103  * Revision 1.2  87/03/27  14:22:19  jenkins
    104  * Port to suns
    105  *
    106  * Revision 4.1  83/05/10  16:24:04  wft
    107  * Marker matching now uses trymatch(). Marker pattern is now
    108  * checked precisely.
    109  *
    110  * Revision 3.1  82/12/04  13:21:40  wft
    111  * Initial revision.
    112  *
    113  */
    114 
    115 /*
    116 #define FCMPTEST
    117 */
    118 /* Testprogram; prints out whether two files are identical,
    119  * except for keywords
    120  */
    121 
    122 #include  "rcsbase.h"
    123 
    124 libId(fcmpId, "Id: rcsfcmp.c,v 5.14 1995/06/16 06:19:24 eggert Exp ")
    125 
    126 	static int discardkeyval P((int,RILE*));
    127 	static int
    128 discardkeyval(c, f)
    129 	register int c;
    130 	register RILE *f;
    131 {
    132 	for (;;)
    133 		switch (c) {
    134 			case KDELIM:
    135 			case '\n':
    136 				return c;
    137 			default:
    138 				Igeteof_(f, c, return EOF;)
    139 				break;
    140 		}
    141 }
    142 
    143 	int
    144 rcsfcmp(xfp, xstatp, uname, delta)
    145 	register RILE *xfp;
    146 	struct stat const *xstatp;
    147 	char const *uname;
    148 	struct hshentry const *delta;
    149 /* Compare the files xfp and uname.  Return zero
    150  * if xfp has the same contents as uname and neither has keywords,
    151  * otherwise -1 if they are the same ignoring keyword values,
    152  * and 1 if they differ even ignoring
    153  * keyword values. For the LOG-keyword, rcsfcmp skips the log message
    154  * given by the parameter delta in xfp.  Thus, rcsfcmp returns nonpositive
    155  * if xfp contains the same as uname, with the keywords expanded.
    156  * Implementation: character-by-character comparison until $ is found.
    157  * If a $ is found, read in the marker keywords; if they are real keywords
    158  * and identical, read in keyword value. If value is terminated properly,
    159  * disregard it and optionally skip log message; otherwise, compare value.
    160  */
    161 {
    162     register int xc, uc;
    163     char xkeyword[keylength+2];
    164     int eqkeyvals;
    165     register RILE *ufp;
    166     register int xeof, ueof;
    167     register char * tp;
    168     register char const *sp;
    169     register size_t leaderlen;
    170     int result;
    171     enum markers match1;
    172     struct stat ustat;
    173 
    174     if (!(ufp = Iopen(uname, FOPEN_R_WORK, &ustat))) {
    175        efaterror(uname);
    176     }
    177     xeof = ueof = false;
    178     if (MIN_UNEXPAND <= Expand) {
    179 	if (!(result = xstatp->st_size!=ustat.st_size)) {
    180 #	    if large_memory && maps_memory
    181 		result = !!memcmp(xfp->base,ufp->base,(size_t)xstatp->st_size);
    182 #	    else
    183 		for (;;) {
    184 		    /* get the next characters */
    185 		    Igeteof_(xfp, xc, xeof=true;)
    186 		    Igeteof_(ufp, uc, ueof=true;)
    187 		    if (xeof | ueof)
    188 			goto eof;
    189 		    if (xc != uc)
    190 			goto return1;
    191 		}
    192 #	    endif
    193 	}
    194     } else {
    195 	xc = 0;
    196 	uc = 0; /* Keep lint happy.  */
    197 	leaderlen = 0;
    198 	result = 0;
    199 
    200 	for (;;) {
    201 	  if (xc != KDELIM) {
    202 	    /* get the next characters */
    203 	    Igeteof_(xfp, xc, xeof=true;)
    204 	    Igeteof_(ufp, uc, ueof=true;)
    205 	    if (xeof | ueof)
    206 		goto eof;
    207 	  } else {
    208 	    /* try to get both keywords */
    209 	    tp = xkeyword;
    210 	    for (;;) {
    211 		Igeteof_(xfp, xc, xeof=true;)
    212 		Igeteof_(ufp, uc, ueof=true;)
    213 		if (xeof | ueof)
    214 		    goto eof;
    215 		if (xc != uc)
    216 		    break;
    217 		switch (xc) {
    218 		    default:
    219 			if (xkeyword+keylength <= tp)
    220 			    break;
    221 			*tp++ = xc;
    222 			continue;
    223 		    case '\n': case KDELIM: case VDELIM:
    224 			break;
    225 		}
    226 		break;
    227 	    }
    228 	    if (
    229 		(xc==KDELIM || xc==VDELIM)  &&  (uc==KDELIM || uc==VDELIM)  &&
    230 		(*tp = xc,  (match1 = trymatch(xkeyword)) != Nomatch)
    231 	    ) {
    232 #ifdef FCMPTEST
    233 	      VOID printf("found common keyword %s\n",xkeyword);
    234 #endif
    235 	      result = -1;
    236 	      for (;;) {
    237 		  if (xc != uc) {
    238 		      xc = discardkeyval(xc, xfp);
    239 		      uc = discardkeyval(uc, ufp);
    240 		      if ((xeof = xc==EOF)  |  (ueof = uc==EOF))
    241 			  goto eof;
    242 		      eqkeyvals = false;
    243 		      break;
    244 		  }
    245 		  switch (xc) {
    246 		      default:
    247 			  Igeteof_(xfp, xc, xeof=true;)
    248 			  Igeteof_(ufp, uc, ueof=true;)
    249 			  if (xeof | ueof)
    250 			      goto eof;
    251 			  continue;
    252 
    253 		      case '\n': case KDELIM:
    254 			  eqkeyvals = true;
    255 			  break;
    256 		  }
    257 		  break;
    258 	      }
    259 	      if (xc != uc)
    260 		  goto return1;
    261 	      if (xc==KDELIM) {
    262 		  /* Skip closing KDELIM.  */
    263 		  Igeteof_(xfp, xc, xeof=true;)
    264 		  Igeteof_(ufp, uc, ueof=true;)
    265 		  if (xeof | ueof)
    266 		      goto eof;
    267 		  /* if the keyword is LOG, also skip the log message in xfp*/
    268 		  if (match1==Log) {
    269 		      /* first, compute the number of line feeds in log msg */
    270 		      int lncnt;
    271 		      size_t ls, ccnt;
    272 		      sp = delta->log.string;
    273 		      ls = delta->log.size;
    274 		      if (ls<sizeof(ciklog)-1 || memcmp(sp,ciklog,sizeof(ciklog)-1)) {
    275 			/*
    276 			* This log message was inserted.  Skip its header.
    277 			* The number of newlines to skip is
    278 			* 1 + (C+1)*(1+L+1), where C is the number of newlines
    279 			* in the comment leader, and L is the number of
    280 			* newlines in the log string.
    281 			*/
    282 			int c1 = 1;
    283 			for (ccnt=Comment.size; ccnt--; )
    284 			    c1 += Comment.string[ccnt] == '\n';
    285 			lncnt = 2*c1 + 1;
    286 			while (ls--) if (*sp++=='\n') lncnt += c1;
    287 			for (;;) {
    288 			    if (xc=='\n')
    289 				if(--lncnt==0) break;
    290 			    Igeteof_(xfp, xc, goto returnresult;)
    291 			}
    292 			/* skip last comment leader */
    293 			/* Can't just skip another line here, because there may be */
    294 			/* additional characters on the line (after the Log....$)  */
    295 			ccnt = RCSversion<VERSION(5) ? Comment.size : leaderlen;
    296 			do {
    297 			    Igeteof_(xfp, xc, goto returnresult;)
    298 			    /*
    299 			     * Read to the end of the comment leader or '\n',
    300 			     * whatever comes first, because the leader's
    301 			     * trailing white space was probably stripped.
    302 			     */
    303 			} while (ccnt-- && (xc!='\n' || --c1));
    304 		      }
    305 		  }
    306 	      } else {
    307 		  /* both end in the same character, but not a KDELIM */
    308 		  /* must compare string values.*/
    309 #ifdef FCMPTEST
    310 		  VOID printf("non-terminated keywords %s, potentially different values\n",xkeyword);
    311 #endif
    312 		  if (!eqkeyvals)
    313 		      goto return1;
    314 	      }
    315 	    }
    316 	  }
    317 	  if (xc != uc)
    318 	      goto return1;
    319 	  if (xc == '\n')
    320 	      leaderlen = 0;
    321 	  else
    322 	      leaderlen++;
    323 	}
    324     }
    325 
    326   eof:
    327     if (xeof==ueof)
    328 	goto returnresult;
    329   return1:
    330     result = 1;
    331   returnresult:
    332     Ifclose(ufp);
    333     return result;
    334 }
    335 
    336 
    337 
    338 #ifdef FCMPTEST
    339 
    340 char const cmdid[] = "rcsfcmp";
    341 
    342 main(argc, argv)
    343 int  argc; char  *argv[];
    344 /* first argument: comment leader; 2nd: log message, 3rd: expanded file,
    345  * 4th: unexpanded file
    346  */
    347 {       struct hshentry delta;
    348 
    349 	Comment.string = argv[1];
    350 	Comment.size = strlen(argv[1]);
    351 	delta.log.string = argv[2];
    352 	delta.log.size = strlen(argv[2]);
    353 	if (rcsfcmp(Iopen(argv[3], FOPEN_R_WORK, (struct stat*)0), argv[4], &delta))
    354                 VOID printf("files are the same\n");
    355         else    VOID printf("files are different\n");
    356 }
    357 #endif
    358