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