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