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