Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / gnu / usr.bin / rcs / lib / rcsfcmp.c
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  * $FreeBSD: src/gnu/usr.bin/rcs/lib/rcsfcmp.c,v 1.7 1999/08/27 23:36:45 peter Exp $
42  * $DragonFly: src/gnu/usr.bin/rcs/lib/rcsfcmp.c,v 1.2 2003/06/17 04:25:47 dillon Exp $
43  *
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
124 libId(fcmpId, "$DragonFly: src/gnu/usr.bin/rcs/lib/rcsfcmp.c,v 1.2 2003/06/17 04:25:47 dillon Exp $")
125
126         static int discardkeyval P((int,RILE*));
127         static int
128 discardkeyval(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
144 rcsfcmp(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
340 char const cmdid[] = "rcsfcmp";
341
342 main(argc, argv)
343 int  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