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