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 15This file is part of RCS. 16 17RCS is free software; you can redistribute it and/or modify 18it under the terms of the GNU General Public License as published by 19the Free Software Foundation; either version 2, or (at your option) 20any later version. 21 22RCS is distributed in the hope that it will be useful, 23but WITHOUT ANY WARRANTY; without even the implied warranty of 24MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25GNU General Public License for more details. 26 27You should have received a copy of the GNU General Public License 28along with RCS; see the file COPYING. 29If not, write to the Free Software Foundation, 3059 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 31 32Report problems and direct all questions to: 33 34 rcs-bugs@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 124libId(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 128discardkeyval(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 144rcsfcmp(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 340char const cmdid[] = "rcsfcmp"; 341 342main(argc, argv) 343int 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