rcsfcmp.c revision 256198
1117395Skan/* Compare working files, ignoring RCS keyword strings. */ 2132718Skan 3117395Skan/***************************************************************************** 4117395Skan * rcsfcmp() 5117395Skan * Testprogram: define FCMPTEST 6117395Skan ***************************************************************************** 7117395Skan */ 8117395Skan 9117395Skan/* Copyright 1982, 1988, 1989 Walter Tichy 10117395Skan Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert 11117395Skan Distributed under license by the Free Software Foundation, Inc. 12117395Skan 13117395SkanThis file is part of RCS. 14117395Skan 15117395SkanRCS is free software; you can redistribute it and/or modify 16117395Skanit under the terms of the GNU General Public License as published by 17117395Skanthe Free Software Foundation; either version 2, or (at your option) 18117395Skanany later version. 19117395Skan 20117395SkanRCS is distributed in the hope that it will be useful, 21117395Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of 22117395SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23117395SkanGNU General Public License for more details. 24117395Skan 25117395SkanYou should have received a copy of the GNU General Public License 26117395Skanalong with RCS; see the file COPYING. 27117395SkanIf not, write to the Free Software Foundation, 28117395Skan59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 29117395Skan 30132718SkanReport problems and direct all questions to: 31132718Skan 32132718Skan rcs-bugs@cs.purdue.edu 33132718Skan 34132718Skan*/ 35132718Skan 36132718Skan 37117395Skan 38117395Skan 39132718Skan 40117395Skan/* 41117395Skan * Revision 5.14 1995/06/16 06:19:24 eggert 42132718Skan * Update FSF address. 43117395Skan * 44132718Skan * Revision 5.13 1995/06/01 16:23:43 eggert 45132718Skan * (rcsfcmp): Add -kb support. 46132718Skan * 47132718Skan * Revision 5.12 1994/03/17 14:05:48 eggert 48132718Skan * Normally calculate the $Log prefix from context, not from RCS file. 49132718Skan * Calculate line numbers correctly even if the $Log prefix contains newlines. 50132718Skan * Remove lint. 51132718Skan * 52132718Skan * Revision 5.11 1993/11/03 17:42:27 eggert 53132718Skan * Fix yet another off-by-one error when comparing Log string expansions. 54132718Skan * 55117395Skan * Revision 5.10 1992/07/28 16:12:44 eggert 56117395Skan * Statement macro names now end in _. 57132718Skan * 58117395Skan * Revision 5.9 1991/10/07 17:32:46 eggert 59117395Skan * Count log lines correctly. 60117395Skan * 61117395Skan * Revision 5.8 1991/08/19 03:13:55 eggert 62132718Skan * Tune. 63132718Skan * 64132718Skan * Revision 5.7 1991/04/21 11:58:22 eggert 65132718Skan * Fix errno bug. Add MS-DOS support. 66117395Skan * 67117395Skan * Revision 5.6 1991/02/28 19:18:47 eggert 68117395Skan * Open work file at most once. 69132718Skan * 70132718Skan * Revision 5.5 1990/11/27 09:26:05 eggert 71132718Skan * Fix comment leader bug. 72117395Skan * 73132718Skan * Revision 5.4 1990/11/01 05:03:42 eggert 74132718Skan * Permit arbitrary data in logs and comment leaders. 75117395Skan * 76132718Skan * Revision 5.3 1990/09/11 02:41:15 eggert 77132718Skan * Don't ignore differences inside keyword strings if -ko is set. 78132718Skan * 79132718Skan * Revision 5.1 1990/08/29 07:13:58 eggert 80117395Skan * Clean old log messages too. 81117395Skan * 82117395Skan * Revision 5.0 1990/08/22 08:12:49 eggert 83132718Skan * Don't append "checked in with -k by " log to logs, 84117395Skan * so that checking in a program with -k doesn't change it. 85117395Skan * Ansify and Posixate. Remove lint. 86117395Skan * 87117395Skan * Revision 4.5 89/05/01 15:12:42 narten 88117395Skan * changed copyright header to reflect current distribution rules 89117395Skan * 90132718Skan * Revision 4.4 88/08/09 19:12:50 eggert 91117395Skan * Shrink stdio code size. 92117395Skan * 93132718Skan * Revision 4.3 87/12/18 11:40:02 narten 94132718Skan * lint cleanups (Guy Harris) 95132718Skan * 96132718Skan * Revision 4.2 87/10/18 10:33:06 narten 97132718Skan * updting version number. Changes relative to 1.1 actually relative to 98117395Skan * 4.1 99117395Skan * 100117395Skan * Revision 1.2 87/03/27 14:22:19 jenkins 101117395Skan * Port to suns 102117395Skan * 103132718Skan * Revision 4.1 83/05/10 16:24:04 wft 104117395Skan * Marker matching now uses trymatch(). Marker pattern is now 105132718Skan * checked precisely. 106132718Skan * 107132718Skan * Revision 3.1 82/12/04 13:21:40 wft 108132718Skan * Initial revision. 109132718Skan * 110117395Skan */ 111132718Skan 112117395Skan/* 113132718Skan#define FCMPTEST 114132718Skan*/ 115132718Skan/* Testprogram; prints out whether two files are identical, 116132718Skan * except for keywords 117132718Skan */ 118132718Skan 119132718Skan#include "rcsbase.h" 120117395Skan 121132718SkanlibId(fcmpId, "$FreeBSD: head/gnu/usr.bin/rcs/lib/rcsfcmp.c 50472 1999-08-27 23:37:10Z peter $") 122132718Skan 123132718Skan static int discardkeyval P((int,RILE*)); 124132718Skan static int 125132718Skandiscardkeyval(c, f) 126132718Skan register int c; 127132718Skan register RILE *f; 128117395Skan{ 129117395Skan for (;;) 130132718Skan switch (c) { 131117395Skan case KDELIM: 132132718Skan case '\n': 133132718Skan return c; 134117395Skan default: 135132718Skan Igeteof_(f, c, return EOF;) 136117395Skan break; 137132718Skan } 138117395Skan} 139132718Skan 140117395Skan int 141132718Skanrcsfcmp(xfp, xstatp, uname, delta) 142117395Skan register RILE *xfp; 143132718Skan struct stat const *xstatp; 144117395Skan char const *uname; 145132718Skan struct hshentry const *delta; 146117395Skan/* Compare the files xfp and uname. Return zero 147132718Skan * if xfp has the same contents as uname and neither has keywords, 148132718Skan * otherwise -1 if they are the same ignoring keyword values, 149132718Skan * and 1 if they differ even ignoring 150117395Skan * keyword values. For the LOG-keyword, rcsfcmp skips the log message 151117395Skan * given by the parameter delta in xfp. Thus, rcsfcmp returns nonpositive 152117395Skan * if xfp contains the same as uname, with the keywords expanded. 153132718Skan * Implementation: character-by-character comparison until $ is found. 154117395Skan * If a $ is found, read in the marker keywords; if they are real keywords 155117395Skan * and identical, read in keyword value. If value is terminated properly, 156132718Skan * disregard it and optionally skip log message; otherwise, compare value. 157132718Skan */ 158132718Skan{ 159132718Skan register int xc, uc; 160132718Skan char xkeyword[keylength+2]; 161132718Skan int eqkeyvals; 162132718Skan register RILE *ufp; 163132718Skan register int xeof, ueof; 164132718Skan register char * tp; 165132718Skan register char const *sp; 166132718Skan register size_t leaderlen; 167117395Skan int result; 168117395Skan enum markers match1; 169132718Skan struct stat ustat; 170132718Skan 171132718Skan if (!(ufp = Iopen(uname, FOPEN_R_WORK, &ustat))) { 172132718Skan efaterror(uname); 173132718Skan } 174132718Skan xeof = ueof = false; 175132718Skan if (MIN_UNEXPAND <= Expand) { 176132718Skan if (!(result = xstatp->st_size!=ustat.st_size)) { 177132718Skan# if large_memory && maps_memory 178132718Skan result = !!memcmp(xfp->base,ufp->base,(size_t)xstatp->st_size); 179132718Skan# else 180132718Skan for (;;) { 181132718Skan /* get the next characters */ 182132718Skan Igeteof_(xfp, xc, xeof=true;) 183117395Skan Igeteof_(ufp, uc, ueof=true;) 184132718Skan if (xeof | ueof) 185117395Skan goto eof; 186132718Skan if (xc != uc) 187132718Skan goto return1; 188132718Skan } 189132718Skan# endif 190132718Skan } 191132718Skan } else { 192132718Skan xc = 0; 193132718Skan uc = 0; /* Keep lint happy. */ 194132718Skan leaderlen = 0; 195132718Skan result = 0; 196132718Skan 197132718Skan for (;;) { 198132718Skan if (xc != KDELIM) { 199117395Skan /* get the next characters */ 200117395Skan Igeteof_(xfp, xc, xeof=true;) 201 Igeteof_(ufp, uc, ueof=true;) 202 if (xeof | ueof) 203 goto eof; 204 } else { 205 /* try to get both keywords */ 206 tp = xkeyword; 207 for (;;) { 208 Igeteof_(xfp, xc, xeof=true;) 209 Igeteof_(ufp, uc, ueof=true;) 210 if (xeof | ueof) 211 goto eof; 212 if (xc != uc) 213 break; 214 switch (xc) { 215 default: 216 if (xkeyword+keylength <= tp) 217 break; 218 *tp++ = xc; 219 continue; 220 case '\n': case KDELIM: case VDELIM: 221 break; 222 } 223 break; 224 } 225 if ( 226 (xc==KDELIM || xc==VDELIM) && (uc==KDELIM || uc==VDELIM) && 227 (*tp = xc, (match1 = trymatch(xkeyword)) != Nomatch) 228 ) { 229#ifdef FCMPTEST 230 VOID printf("found common keyword %s\n",xkeyword); 231#endif 232 result = -1; 233 for (;;) { 234 if (xc != uc) { 235 xc = discardkeyval(xc, xfp); 236 uc = discardkeyval(uc, ufp); 237 if ((xeof = xc==EOF) | (ueof = uc==EOF)) 238 goto eof; 239 eqkeyvals = false; 240 break; 241 } 242 switch (xc) { 243 default: 244 Igeteof_(xfp, xc, xeof=true;) 245 Igeteof_(ufp, uc, ueof=true;) 246 if (xeof | ueof) 247 goto eof; 248 continue; 249 250 case '\n': case KDELIM: 251 eqkeyvals = true; 252 break; 253 } 254 break; 255 } 256 if (xc != uc) 257 goto return1; 258 if (xc==KDELIM) { 259 /* Skip closing KDELIM. */ 260 Igeteof_(xfp, xc, xeof=true;) 261 Igeteof_(ufp, uc, ueof=true;) 262 if (xeof | ueof) 263 goto eof; 264 /* if the keyword is LOG, also skip the log message in xfp*/ 265 if (match1==Log) { 266 /* first, compute the number of line feeds in log msg */ 267 int lncnt; 268 size_t ls, ccnt; 269 sp = delta->log.string; 270 ls = delta->log.size; 271 if (ls<sizeof(ciklog)-1 || memcmp(sp,ciklog,sizeof(ciklog)-1)) { 272 /* 273 * This log message was inserted. Skip its header. 274 * The number of newlines to skip is 275 * 1 + (C+1)*(1+L+1), where C is the number of newlines 276 * in the comment leader, and L is the number of 277 * newlines in the log string. 278 */ 279 int c1 = 1; 280 for (ccnt=Comment.size; ccnt--; ) 281 c1 += Comment.string[ccnt] == '\n'; 282 lncnt = 2*c1 + 1; 283 while (ls--) if (*sp++=='\n') lncnt += c1; 284 for (;;) { 285 if (xc=='\n') 286 if(--lncnt==0) break; 287 Igeteof_(xfp, xc, goto returnresult;) 288 } 289 /* skip last comment leader */ 290 /* Can't just skip another line here, because there may be */ 291 /* additional characters on the line (after the Log....$) */ 292 ccnt = RCSversion<VERSION(5) ? Comment.size : leaderlen; 293 do { 294 Igeteof_(xfp, xc, goto returnresult;) 295 /* 296 * Read to the end of the comment leader or '\n', 297 * whatever comes first, because the leader's 298 * trailing white space was probably stripped. 299 */ 300 } while (ccnt-- && (xc!='\n' || --c1)); 301 } 302 } 303 } else { 304 /* both end in the same character, but not a KDELIM */ 305 /* must compare string values.*/ 306#ifdef FCMPTEST 307 VOID printf("non-terminated keywords %s, potentially different values\n",xkeyword); 308#endif 309 if (!eqkeyvals) 310 goto return1; 311 } 312 } 313 } 314 if (xc != uc) 315 goto return1; 316 if (xc == '\n') 317 leaderlen = 0; 318 else 319 leaderlen++; 320 } 321 } 322 323 eof: 324 if (xeof==ueof) 325 goto returnresult; 326 return1: 327 result = 1; 328 returnresult: 329 Ifclose(ufp); 330 return result; 331} 332 333 334 335#ifdef FCMPTEST 336 337char const cmdid[] = "rcsfcmp"; 338 339main(argc, argv) 340int argc; char *argv[]; 341/* first argument: comment leader; 2nd: log message, 3rd: expanded file, 342 * 4th: unexpanded file 343 */ 344{ struct hshentry delta; 345 346 Comment.string = argv[1]; 347 Comment.size = strlen(argv[1]); 348 delta.log.string = argv[2]; 349 delta.log.size = strlen(argv[2]); 350 if (rcsfcmp(Iopen(argv[3], FOPEN_R_WORK, (struct stat*)0), argv[4], &delta)) 351 VOID printf("files are the same\n"); 352 else VOID printf("files are different\n"); 353} 354#endif 355