Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / gnu / usr.bin / rcs / lib / rcskeep.c
1 /* Extract RCS keyword string values from working files.  */
2
3 /* Copyright 1982, 1988, 1989 Walter Tichy
4    Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
5    Distributed under license by the Free Software Foundation, Inc.
6
7 This file is part of RCS.
8
9 RCS is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 RCS is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with RCS; see the file COPYING.
21 If not, write to the Free Software Foundation,
22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 Report problems and direct all questions to:
25
26     rcs-bugs@cs.purdue.edu
27
28 */
29
30 /*
31  * $FreeBSD: src/gnu/usr.bin/rcs/lib/rcskeep.c,v 1.8 1999/08/27 23:36:46 peter Exp $
32  * $DragonFly: src/gnu/usr.bin/rcs/lib/rcskeep.c,v 1.2 2003/06/17 04:25:47 dillon Exp $
33  *
34  * Revision 5.10  1995/06/16 06:19:24  eggert
35  * Update FSF address.
36  *
37  * Revision 5.9  1995/06/01 16:23:43  eggert
38  * (getoldkeys): Don't panic if a Name: is empty.
39  *
40  * Revision 5.8  1994/03/17 14:05:48  eggert
41  * Remove lint.
42  *
43  * Revision 5.7  1993/11/09 17:40:15  eggert
44  * Use simpler timezone parsing strategy now that we're using ISO 8601 format.
45  *
46  * Revision 5.6  1993/11/03 17:42:27  eggert
47  * Scan for Name keyword.  Improve quality of diagnostics.
48  *
49  * Revision 5.5  1992/07/28  16:12:44  eggert
50  * Statement macro names now end in _.
51  *
52  * Revision 5.4  1991/08/19  03:13:55  eggert
53  * Tune.
54  *
55  * Revision 5.3  1991/04/21  11:58:25  eggert
56  * Shorten names to keep them distinct on shortname hosts.
57  *
58  * Revision 5.2  1990/10/04  06:30:20  eggert
59  * Parse time zone offsets; future RCS versions may output them.
60  *
61  * Revision 5.1  1990/09/20  02:38:56  eggert
62  * ci -k now checks dates more thoroughly.
63  *
64  * Revision 5.0  1990/08/22  08:12:53  eggert
65  * Retrieve old log message if there is one.
66  * Don't require final newline.
67  * Remove compile-time limits; use malloc instead.  Tune.
68  * Permit dates past 1999/12/31.  Ansify and Posixate.
69  *
70  * Revision 4.6  89/05/01  15:12:56  narten
71  * changed copyright header to reflect current distribution rules
72  *
73  * Revision 4.5  88/08/09  19:13:03  eggert
74  * Remove lint and speed up by making FILE *fp local, not global.
75  *
76  * Revision 4.4  87/12/18  11:44:21  narten
77  * more lint cleanups (Guy Harris)
78  *
79  * Revision 4.3  87/10/18  10:35:50  narten
80  * Updating version numbers. Changes relative to 1.1 actually relative
81  * to 4.1
82  *
83  * Revision 1.3  87/09/24  14:00:00  narten
84  * Sources now pass through lint (if you ignore printf/sprintf/fprintf
85  * warnings)
86  *
87  * Revision 1.2  87/03/27  14:22:29  jenkins
88  * Port to suns
89  *
90  * Revision 4.1  83/05/10  16:26:44  wft
91  * Added new markers Id and RCSfile; extraction added.
92  * Marker matching with trymatch().
93  *
94  * Revision 3.2  82/12/24  12:08:26  wft
95  * added missing #endif.
96  *
97  * Revision 3.1  82/12/04  13:22:41  wft
98  * Initial revision.
99  *
100  */
101
102 #include  "rcsbase.h"
103
104 libId(keepId, "$DragonFly: src/gnu/usr.bin/rcs/lib/rcskeep.c,v 1.2 2003/06/17 04:25:47 dillon Exp $")
105
106 static int badly_terminated P((void));
107 static int checknum P((char const*));
108 static int get0val P((int,RILE*,struct buf*,int));
109 static int getval P((RILE*,struct buf*,int));
110 static int keepdate P((RILE*));
111 static int keepid P((int,RILE*,struct buf*));
112 static int keeprev P((RILE*));
113
114 int prevkeys;
115 struct buf prevauthor, prevdate, prevname, prevrev, prevstate;
116
117         int
118 getoldkeys(fp)
119         register RILE *fp;
120 /* Function: Tries to read keyword values for author, date,
121  * revision number, and state out of the file fp.
122  * If fp is null, workname is opened and closed instead of using fp.
123  * The results are placed into
124  * prevauthor, prevdate, prevname, prevrev, prevstate.
125  * Aborts immediately if it finds an error and returns false.
126  * If it returns true, it doesn't mean that any of the
127  * values were found; instead, check to see whether the corresponding arrays
128  * contain the empty string.
129  */
130 {
131     register int c;
132     char keyword[keylength+1];
133     register char * tp;
134     int needs_closing;
135     int prevname_found;
136
137     if (prevkeys)
138         return true;
139
140     needs_closing = false;
141     if (!fp) {
142         if (!(fp = Iopen(workname, FOPEN_R_WORK, (struct stat*)0))) {
143             eerror(workname);
144             return false;
145         }
146         needs_closing = true;
147     }
148
149     /* initialize to empty */
150     bufscpy(&prevauthor, "");
151     bufscpy(&prevdate, "");
152     bufscpy(&prevname, "");  prevname_found = 0;
153     bufscpy(&prevrev, "");
154     bufscpy(&prevstate, "");
155
156     c = '\0'; /* anything but KDELIM */
157     for (;;) {
158         if ( c==KDELIM) {
159             do {
160                 /* try to get keyword */
161                 tp = keyword;
162                 for (;;) {
163                     Igeteof_(fp, c, goto ok;)
164                     switch (c) {
165                         default:
166                             if (keyword+keylength <= tp)
167                                 break;
168                             *tp++ = c;
169                             continue;
170
171                         case '\n': case KDELIM: case VDELIM:
172                             break;
173                     }
174                     break;
175                 }
176             } while (c==KDELIM);
177             if (c!=VDELIM) continue;
178             *tp = c;
179             Igeteof_(fp, c, break;)
180             switch (c) {
181                 case ' ': case '\t': break;
182                 default: continue;
183             }
184
185             switch (trymatch(keyword)) {
186             case Author:
187                 if (!keepid(0, fp, &prevauthor))
188                     return false;
189                 c = 0;
190                 break;
191             case Date:
192                 if (!(c = keepdate(fp)))
193                     return false;
194                 break;
195             case Header:
196             case Id:
197             case LocalId:
198                 if (!(
199                       getval(fp, (struct buf*)0, false) &&
200                       keeprev(fp) &&
201                       (c = keepdate(fp)) &&
202                       keepid(c, fp, &prevauthor) &&
203                       keepid(0, fp, &prevstate)
204                 ))
205                     return false;
206                 /* Skip either ``who'' (new form) or ``Locker: who'' (old).  */
207                 if (getval(fp, (struct buf*)0, true) &&
208                     getval(fp, (struct buf*)0, true))
209                         c = 0;
210                 else if (nerror)
211                         return false;
212                 else
213                         c = KDELIM;
214                 break;
215             case Locker:
216                 (void) getval(fp, (struct buf*)0, false);
217                 c = 0;
218                 break;
219             case Log:
220             case RCSfile:
221             case Source:
222                 if (!getval(fp, (struct buf*)0, false))
223                     return false;
224                 c = 0;
225                 break;
226             case Name:
227                 if (getval(fp, &prevname, false)) {
228                     if (*prevname.string)
229                         checkssym(prevname.string);
230                     prevname_found = 1;
231                 }
232                 c = 0;
233                 break;
234             case Revision:
235                 if (!keeprev(fp))
236                     return false;
237                 c = 0;
238                 break;
239             case State:
240                 if (!keepid(0, fp, &prevstate))
241                     return false;
242                 c = 0;
243                 break;
244             default:
245                continue;
246             }
247             if (!c)
248                 Igeteof_(fp, c, c=0;)
249             if (c != KDELIM) {
250                 workerror("closing %c missing on keyword", KDELIM);
251                 return false;
252             }
253             if (prevname_found &&
254                 *prevauthor.string && *prevdate.string &&
255                 *prevrev.string && *prevstate.string
256             )
257                 break;
258         }
259         Igeteof_(fp, c, break;)
260     }
261
262  ok:
263     if (needs_closing)
264         Ifclose(fp);
265     else
266         Irewind(fp);
267     prevkeys = true;
268     return true;
269 }
270
271         static int
272 badly_terminated()
273 {
274         workerror("badly terminated keyword value");
275         return false;
276 }
277
278         static int
279 getval(fp, target, optional)
280         register RILE *fp;
281         struct buf *target;
282         int optional;
283 /* Reads a keyword value from FP into TARGET.
284  * Returns true if one is found, false otherwise.
285  * Does not modify target if it is 0.
286  * Do not report an error if OPTIONAL is set and KDELIM is found instead.
287  */
288 {
289         int c;
290         Igeteof_(fp, c, return badly_terminated();)
291         return get0val(c, fp, target, optional);
292 }
293
294         static int
295 get0val(c, fp, target, optional)
296         register int c;
297         register RILE *fp;
298         struct buf *target;
299         int optional;
300 /* Reads a keyword value from C+FP into TARGET, perhaps OPTIONALly.
301  * Same as getval, except C is the lookahead character.
302  */
303 {   register char * tp;
304     char const *tlim;
305     register int got1;
306
307     if (target) {
308         bufalloc(target, 1);
309         tp = target->string;
310         tlim = tp + target->size;
311     } else
312         tlim = tp = 0;
313     got1 = false;
314     for (;;) {
315         switch (c) {
316             default:
317                 got1 = true;
318                 if (tp) {
319                     *tp++ = c;
320                     if (tlim <= tp)
321                         tp = bufenlarge(target, &tlim);
322                 }
323                 break;
324
325             case ' ':
326             case '\t':
327                 if (tp) {
328                     *tp = 0;
329 #                   ifdef KEEPTEST
330                         VOID printf("getval: %s\n", target);
331 #                   endif
332                 }
333                 return got1;
334
335             case KDELIM:
336                 if (!got1 && optional)
337                     return false;
338                 /* fall into */
339             case '\n':
340             case 0:
341                 return badly_terminated();
342         }
343         Igeteof_(fp, c, return badly_terminated();)
344     }
345 }
346
347
348         static int
349 keepdate(fp)
350         RILE *fp;
351 /* Function: reads a date prevdate; checks format
352  * Return 0 on error, lookahead character otherwise.
353  */
354 {
355     struct buf prevday, prevtime;
356     register int c;
357
358     c = 0;
359     bufautobegin(&prevday);
360     if (getval(fp,&prevday,false)) {
361         bufautobegin(&prevtime);
362         if (getval(fp,&prevtime,false)) {
363             Igeteof_(fp, c, c=0;)
364             if (c) {
365                 register char const *d = prevday.string, *t = prevtime.string;
366                 bufalloc(&prevdate, strlen(d) + strlen(t) + 9);
367                 VOID sprintf(prevdate.string, "%s%s %s%s",
368                     /* Parse dates put out by old versions of RCS.  */
369                       isdigit(d[0]) && isdigit(d[1]) && !isdigit(d[2])
370                     ? "19" : "",
371                     d, t,
372                     strchr(t,'-') || strchr(t,'+')  ?  ""  :  "+0000"
373                 );
374             }
375         }
376         bufautoend(&prevtime);
377     }
378     bufautoend(&prevday);
379     return c;
380 }
381
382         static int
383 keepid(c, fp, b)
384         int c;
385         RILE *fp;
386         struct buf *b;
387 /* Get previous identifier from C+FP into B.  */
388 {
389         if (!c)
390             Igeteof_(fp, c, return false;)
391         if (!get0val(c, fp, b, false))
392             return false;
393         checksid(b->string);
394         return !nerror;
395 }
396
397         static int
398 keeprev(fp)
399         RILE *fp;
400 /* Get previous revision from FP into prevrev.  */
401 {
402         return getval(fp,&prevrev,false) && checknum(prevrev.string);
403 }
404
405
406         static int
407 checknum(s)
408         char const *s;
409 {
410     register char const *sp;
411     register int dotcount = 0;
412     for (sp=s; ; sp++) {
413         switch (*sp) {
414             case 0:
415                 if (dotcount & 1)
416                     return true;
417                 else
418                     break;
419
420             case '.':
421                 dotcount++;
422                 continue;
423
424             default:
425                 if (isdigit(*sp))
426                     continue;
427                 break;
428         }
429         break;
430     }
431     workerror("%s is not a revision number", s);
432     return false;
433 }
434
435
436
437 #ifdef KEEPTEST
438
439 /* Print the keyword values found.  */
440
441 char const cmdid[] ="keeptest";
442
443         int
444 main(argc, argv)
445 int  argc; char  *argv[];
446 {
447         while (*(++argv)) {
448                 workname = *argv;
449                 getoldkeys((RILE*)0);
450                 VOID printf("%s:  revision: %s, date: %s, author: %s, name: %s, state: %s\n",
451                             *argv, prevrev.string, prevdate.string, prevauthor.string, prevname.string, prevstate.string);
452         }
453         exitmain(EXIT_SUCCESS);
454 }
455 #endif