]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - gnu/usr.bin/rcs/lib/rcsfcmp.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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  * Revision 5.14  1995/06/16 06:19:24  eggert
42  * Update FSF address.
43  *
44  * Revision 5.13  1995/06/01 16:23:43  eggert
45  * (rcsfcmp): Add -kb support.
46  *
47  * Revision 5.12  1994/03/17 14:05:48  eggert
48  * Normally calculate the $Log prefix from context, not from RCS file.
49  * Calculate line numbers correctly even if the $Log prefix contains newlines.
50  * Remove lint.
51  *
52  * Revision 5.11  1993/11/03 17:42:27  eggert
53  * Fix yet another off-by-one error when comparing Log string expansions.
54  *
55  * Revision 5.10  1992/07/28 16:12:44  eggert
56  * Statement macro names now end in _.
57  *
58  * Revision 5.9  1991/10/07  17:32:46  eggert
59  * Count log lines correctly.
60  *
61  * Revision 5.8  1991/08/19  03:13:55  eggert
62  * Tune.
63  *
64  * Revision 5.7  1991/04/21  11:58:22  eggert
65  * Fix errno bug.  Add MS-DOS support.
66  *
67  * Revision 5.6  1991/02/28  19:18:47  eggert
68  * Open work file at most once.
69  *
70  * Revision 5.5  1990/11/27  09:26:05  eggert
71  * Fix comment leader bug.
72  *
73  * Revision 5.4  1990/11/01  05:03:42  eggert
74  * Permit arbitrary data in logs and comment leaders.
75  *
76  * Revision 5.3  1990/09/11  02:41:15  eggert
77  * Don't ignore differences inside keyword strings if -ko is set.
78  *
79  * Revision 5.1  1990/08/29  07:13:58  eggert
80  * Clean old log messages too.
81  *
82  * Revision 5.0  1990/08/22  08:12:49  eggert
83  * Don't append "checked in with -k by " log to logs,
84  * so that checking in a program with -k doesn't change it.
85  * Ansify and Posixate.  Remove lint.
86  *
87  * Revision 4.5  89/05/01  15:12:42  narten
88  * changed copyright header to reflect current distribution rules
89  *
90  * Revision 4.4  88/08/09  19:12:50  eggert
91  * Shrink stdio code size.
92  *
93  * Revision 4.3  87/12/18  11:40:02  narten
94  * lint cleanups (Guy Harris)
95  *
96  * Revision 4.2  87/10/18  10:33:06  narten
97  * updting version number. Changes relative to 1.1 actually relative to
98  * 4.1
99  *
100  * Revision 1.2  87/03/27  14:22:19  jenkins
101  * Port to suns
102  *
103  * Revision 4.1  83/05/10  16:24:04  wft
104  * Marker matching now uses trymatch(). Marker pattern is now
105  * checked precisely.
106  *
107  * Revision 3.1  82/12/04  13:21:40  wft
108  * Initial revision.
109  *
110  */
111
112 /*
113 #define FCMPTEST
114 */
115 /* Testprogram; prints out whether two files are identical,
116  * except for keywords
117  */
118
119 #include  "rcsbase.h"
120
121 libId(fcmpId, "$FreeBSD$")
122
123         static int discardkeyval P((int,RILE*));
124         static int
125 discardkeyval(c, f)
126         register int c;
127         register RILE *f;
128 {
129         for (;;)
130                 switch (c) {
131                         case KDELIM:
132                         case '\n':
133                                 return c;
134                         default:
135                                 Igeteof_(f, c, return EOF;)
136                                 break;
137                 }
138 }
139
140         int
141 rcsfcmp(xfp, xstatp, uname, delta)
142         register RILE *xfp;
143         struct stat const *xstatp;
144         char const *uname;
145         struct hshentry const *delta;
146 /* Compare the files xfp and uname.  Return zero
147  * if xfp has the same contents as uname and neither has keywords,
148  * otherwise -1 if they are the same ignoring keyword values,
149  * and 1 if they differ even ignoring
150  * keyword values. For the LOG-keyword, rcsfcmp skips the log message
151  * given by the parameter delta in xfp.  Thus, rcsfcmp returns nonpositive
152  * if xfp contains the same as uname, with the keywords expanded.
153  * Implementation: character-by-character comparison until $ is found.
154  * If a $ is found, read in the marker keywords; if they are real keywords
155  * and identical, read in keyword value. If value is terminated properly,
156  * disregard it and optionally skip log message; otherwise, compare value.
157  */
158 {
159     register int xc, uc;
160     char xkeyword[keylength+2];
161     int eqkeyvals;
162     register RILE *ufp;
163     register int xeof, ueof;
164     register char * tp;
165     register char const *sp;
166     register size_t leaderlen;
167     int result;
168     enum markers match1;
169     struct stat ustat;
170
171     if (!(ufp = Iopen(uname, FOPEN_R_WORK, &ustat))) {
172        efaterror(uname);
173     }
174     xeof = ueof = false;
175     if (MIN_UNEXPAND <= Expand) {
176         if (!(result = xstatp->st_size!=ustat.st_size)) {
177 #           if large_memory && maps_memory
178                 result = !!memcmp(xfp->base,ufp->base,(size_t)xstatp->st_size);
179 #           else
180                 for (;;) {
181                     /* get the next characters */
182                     Igeteof_(xfp, xc, xeof=true;)
183                     Igeteof_(ufp, uc, ueof=true;)
184                     if (xeof | ueof)
185                         goto eof;
186                     if (xc != uc)
187                         goto return1;
188                 }
189 #           endif
190         }
191     } else {
192         xc = 0;
193         uc = 0; /* Keep lint happy.  */
194         leaderlen = 0;
195         result = 0;
196
197         for (;;) {
198           if (xc != KDELIM) {
199             /* get the next characters */
200             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
337 char const cmdid[] = "rcsfcmp";
338
339 main(argc, argv)
340 int  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