xref: /dflybsd-src/gnu/usr.bin/rcs/lib/rcskeep.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /* Extract RCS keyword string values from working files.  */
286d7f5d3SJohn Marino 
386d7f5d3SJohn Marino /* Copyright 1982, 1988, 1989 Walter Tichy
486d7f5d3SJohn Marino    Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
586d7f5d3SJohn Marino    Distributed under license by the Free Software Foundation, Inc.
686d7f5d3SJohn Marino 
786d7f5d3SJohn Marino This file is part of RCS.
886d7f5d3SJohn Marino 
986d7f5d3SJohn Marino RCS is free software; you can redistribute it and/or modify
1086d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
1186d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
1286d7f5d3SJohn Marino any later version.
1386d7f5d3SJohn Marino 
1486d7f5d3SJohn Marino RCS is distributed in the hope that it will be useful,
1586d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
1686d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1786d7f5d3SJohn Marino GNU General Public License for more details.
1886d7f5d3SJohn Marino 
1986d7f5d3SJohn Marino You should have received a copy of the GNU General Public License
2086d7f5d3SJohn Marino along with RCS; see the file COPYING.
2186d7f5d3SJohn Marino If not, write to the Free Software Foundation,
2286d7f5d3SJohn Marino 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2386d7f5d3SJohn Marino 
2486d7f5d3SJohn Marino Report problems and direct all questions to:
2586d7f5d3SJohn Marino 
2686d7f5d3SJohn Marino     rcs-bugs@cs.purdue.edu
2786d7f5d3SJohn Marino 
2886d7f5d3SJohn Marino */
2986d7f5d3SJohn Marino 
3086d7f5d3SJohn Marino /*
3186d7f5d3SJohn Marino  * $FreeBSD: src/gnu/usr.bin/rcs/lib/rcskeep.c,v 1.8 1999/08/27 23:36:46 peter Exp $
3286d7f5d3SJohn Marino  * $DragonFly: src/gnu/usr.bin/rcs/lib/rcskeep.c,v 1.2 2003/06/17 04:25:47 dillon Exp $
3386d7f5d3SJohn Marino  *
3486d7f5d3SJohn Marino  * Revision 5.10  1995/06/16 06:19:24  eggert
3586d7f5d3SJohn Marino  * Update FSF address.
3686d7f5d3SJohn Marino  *
3786d7f5d3SJohn Marino  * Revision 5.9  1995/06/01 16:23:43  eggert
3886d7f5d3SJohn Marino  * (getoldkeys): Don't panic if a Name: is empty.
3986d7f5d3SJohn Marino  *
4086d7f5d3SJohn Marino  * Revision 5.8  1994/03/17 14:05:48  eggert
4186d7f5d3SJohn Marino  * Remove lint.
4286d7f5d3SJohn Marino  *
4386d7f5d3SJohn Marino  * Revision 5.7  1993/11/09 17:40:15  eggert
4486d7f5d3SJohn Marino  * Use simpler timezone parsing strategy now that we're using ISO 8601 format.
4586d7f5d3SJohn Marino  *
4686d7f5d3SJohn Marino  * Revision 5.6  1993/11/03 17:42:27  eggert
4786d7f5d3SJohn Marino  * Scan for Name keyword.  Improve quality of diagnostics.
4886d7f5d3SJohn Marino  *
4986d7f5d3SJohn Marino  * Revision 5.5  1992/07/28  16:12:44  eggert
5086d7f5d3SJohn Marino  * Statement macro names now end in _.
5186d7f5d3SJohn Marino  *
5286d7f5d3SJohn Marino  * Revision 5.4  1991/08/19  03:13:55  eggert
5386d7f5d3SJohn Marino  * Tune.
5486d7f5d3SJohn Marino  *
5586d7f5d3SJohn Marino  * Revision 5.3  1991/04/21  11:58:25  eggert
5686d7f5d3SJohn Marino  * Shorten names to keep them distinct on shortname hosts.
5786d7f5d3SJohn Marino  *
5886d7f5d3SJohn Marino  * Revision 5.2  1990/10/04  06:30:20  eggert
5986d7f5d3SJohn Marino  * Parse time zone offsets; future RCS versions may output them.
6086d7f5d3SJohn Marino  *
6186d7f5d3SJohn Marino  * Revision 5.1  1990/09/20  02:38:56  eggert
6286d7f5d3SJohn Marino  * ci -k now checks dates more thoroughly.
6386d7f5d3SJohn Marino  *
6486d7f5d3SJohn Marino  * Revision 5.0  1990/08/22  08:12:53  eggert
6586d7f5d3SJohn Marino  * Retrieve old log message if there is one.
6686d7f5d3SJohn Marino  * Don't require final newline.
6786d7f5d3SJohn Marino  * Remove compile-time limits; use malloc instead.  Tune.
6886d7f5d3SJohn Marino  * Permit dates past 1999/12/31.  Ansify and Posixate.
6986d7f5d3SJohn Marino  *
7086d7f5d3SJohn Marino  * Revision 4.6  89/05/01  15:12:56  narten
7186d7f5d3SJohn Marino  * changed copyright header to reflect current distribution rules
7286d7f5d3SJohn Marino  *
7386d7f5d3SJohn Marino  * Revision 4.5  88/08/09  19:13:03  eggert
7486d7f5d3SJohn Marino  * Remove lint and speed up by making FILE *fp local, not global.
7586d7f5d3SJohn Marino  *
7686d7f5d3SJohn Marino  * Revision 4.4  87/12/18  11:44:21  narten
7786d7f5d3SJohn Marino  * more lint cleanups (Guy Harris)
7886d7f5d3SJohn Marino  *
7986d7f5d3SJohn Marino  * Revision 4.3  87/10/18  10:35:50  narten
8086d7f5d3SJohn Marino  * Updating version numbers. Changes relative to 1.1 actually relative
8186d7f5d3SJohn Marino  * to 4.1
8286d7f5d3SJohn Marino  *
8386d7f5d3SJohn Marino  * Revision 1.3  87/09/24  14:00:00  narten
8486d7f5d3SJohn Marino  * Sources now pass through lint (if you ignore printf/sprintf/fprintf
8586d7f5d3SJohn Marino  * warnings)
8686d7f5d3SJohn Marino  *
8786d7f5d3SJohn Marino  * Revision 1.2  87/03/27  14:22:29  jenkins
8886d7f5d3SJohn Marino  * Port to suns
8986d7f5d3SJohn Marino  *
9086d7f5d3SJohn Marino  * Revision 4.1  83/05/10  16:26:44  wft
9186d7f5d3SJohn Marino  * Added new markers Id and RCSfile; extraction added.
9286d7f5d3SJohn Marino  * Marker matching with trymatch().
9386d7f5d3SJohn Marino  *
9486d7f5d3SJohn Marino  * Revision 3.2  82/12/24  12:08:26  wft
9586d7f5d3SJohn Marino  * added missing #endif.
9686d7f5d3SJohn Marino  *
9786d7f5d3SJohn Marino  * Revision 3.1  82/12/04  13:22:41  wft
9886d7f5d3SJohn Marino  * Initial revision.
9986d7f5d3SJohn Marino  *
10086d7f5d3SJohn Marino  */
10186d7f5d3SJohn Marino 
10286d7f5d3SJohn Marino #include  "rcsbase.h"
10386d7f5d3SJohn Marino 
10486d7f5d3SJohn Marino libId(keepId, "$DragonFly: src/gnu/usr.bin/rcs/lib/rcskeep.c,v 1.2 2003/06/17 04:25:47 dillon Exp $")
10586d7f5d3SJohn Marino 
10686d7f5d3SJohn Marino static int badly_terminated P((void));
10786d7f5d3SJohn Marino static int checknum P((char const*));
10886d7f5d3SJohn Marino static int get0val P((int,RILE*,struct buf*,int));
10986d7f5d3SJohn Marino static int getval P((RILE*,struct buf*,int));
11086d7f5d3SJohn Marino static int keepdate P((RILE*));
11186d7f5d3SJohn Marino static int keepid P((int,RILE*,struct buf*));
11286d7f5d3SJohn Marino static int keeprev P((RILE*));
11386d7f5d3SJohn Marino 
11486d7f5d3SJohn Marino int prevkeys;
11586d7f5d3SJohn Marino struct buf prevauthor, prevdate, prevname, prevrev, prevstate;
11686d7f5d3SJohn Marino 
11786d7f5d3SJohn Marino 	int
getoldkeys(fp)11886d7f5d3SJohn Marino getoldkeys(fp)
11986d7f5d3SJohn Marino 	register RILE *fp;
12086d7f5d3SJohn Marino /* Function: Tries to read keyword values for author, date,
12186d7f5d3SJohn Marino  * revision number, and state out of the file fp.
12286d7f5d3SJohn Marino  * If fp is null, workname is opened and closed instead of using fp.
12386d7f5d3SJohn Marino  * The results are placed into
12486d7f5d3SJohn Marino  * prevauthor, prevdate, prevname, prevrev, prevstate.
12586d7f5d3SJohn Marino  * Aborts immediately if it finds an error and returns false.
12686d7f5d3SJohn Marino  * If it returns true, it doesn't mean that any of the
12786d7f5d3SJohn Marino  * values were found; instead, check to see whether the corresponding arrays
12886d7f5d3SJohn Marino  * contain the empty string.
12986d7f5d3SJohn Marino  */
13086d7f5d3SJohn Marino {
13186d7f5d3SJohn Marino     register int c;
13286d7f5d3SJohn Marino     char keyword[keylength+1];
13386d7f5d3SJohn Marino     register char * tp;
13486d7f5d3SJohn Marino     int needs_closing;
13586d7f5d3SJohn Marino     int prevname_found;
13686d7f5d3SJohn Marino 
13786d7f5d3SJohn Marino     if (prevkeys)
13886d7f5d3SJohn Marino 	return true;
13986d7f5d3SJohn Marino 
14086d7f5d3SJohn Marino     needs_closing = false;
14186d7f5d3SJohn Marino     if (!fp) {
14286d7f5d3SJohn Marino 	if (!(fp = Iopen(workname, FOPEN_R_WORK, (struct stat*)0))) {
14386d7f5d3SJohn Marino 	    eerror(workname);
14486d7f5d3SJohn Marino 	    return false;
14586d7f5d3SJohn Marino 	}
14686d7f5d3SJohn Marino 	needs_closing = true;
14786d7f5d3SJohn Marino     }
14886d7f5d3SJohn Marino 
14986d7f5d3SJohn Marino     /* initialize to empty */
15086d7f5d3SJohn Marino     bufscpy(&prevauthor, "");
15186d7f5d3SJohn Marino     bufscpy(&prevdate, "");
15286d7f5d3SJohn Marino     bufscpy(&prevname, "");  prevname_found = 0;
15386d7f5d3SJohn Marino     bufscpy(&prevrev, "");
15486d7f5d3SJohn Marino     bufscpy(&prevstate, "");
15586d7f5d3SJohn Marino 
15686d7f5d3SJohn Marino     c = '\0'; /* anything but KDELIM */
15786d7f5d3SJohn Marino     for (;;) {
15886d7f5d3SJohn Marino         if ( c==KDELIM) {
15986d7f5d3SJohn Marino 	    do {
16086d7f5d3SJohn Marino 		/* try to get keyword */
16186d7f5d3SJohn Marino 		tp = keyword;
16286d7f5d3SJohn Marino 		for (;;) {
16386d7f5d3SJohn Marino 		    Igeteof_(fp, c, goto ok;)
16486d7f5d3SJohn Marino 		    switch (c) {
16586d7f5d3SJohn Marino 			default:
16686d7f5d3SJohn Marino 			    if (keyword+keylength <= tp)
16786d7f5d3SJohn Marino 				break;
16886d7f5d3SJohn Marino 			    *tp++ = c;
16986d7f5d3SJohn Marino 			    continue;
17086d7f5d3SJohn Marino 
17186d7f5d3SJohn Marino 			case '\n': case KDELIM: case VDELIM:
17286d7f5d3SJohn Marino 			    break;
17386d7f5d3SJohn Marino 		    }
17486d7f5d3SJohn Marino 		    break;
17586d7f5d3SJohn Marino 		}
17686d7f5d3SJohn Marino 	    } while (c==KDELIM);
17786d7f5d3SJohn Marino             if (c!=VDELIM) continue;
17886d7f5d3SJohn Marino 	    *tp = c;
17986d7f5d3SJohn Marino 	    Igeteof_(fp, c, break;)
18086d7f5d3SJohn Marino 	    switch (c) {
18186d7f5d3SJohn Marino 		case ' ': case '\t': break;
18286d7f5d3SJohn Marino 		default: continue;
18386d7f5d3SJohn Marino 	    }
18486d7f5d3SJohn Marino 
18586d7f5d3SJohn Marino 	    switch (trymatch(keyword)) {
18686d7f5d3SJohn Marino             case Author:
18786d7f5d3SJohn Marino 		if (!keepid(0, fp, &prevauthor))
18886d7f5d3SJohn Marino 		    return false;
18986d7f5d3SJohn Marino 		c = 0;
19086d7f5d3SJohn Marino                 break;
19186d7f5d3SJohn Marino             case Date:
19286d7f5d3SJohn Marino 		if (!(c = keepdate(fp)))
19386d7f5d3SJohn Marino 		    return false;
19486d7f5d3SJohn Marino                 break;
19586d7f5d3SJohn Marino             case Header:
19686d7f5d3SJohn Marino             case Id:
19786d7f5d3SJohn Marino 	    case LocalId:
19886d7f5d3SJohn Marino 		if (!(
19986d7f5d3SJohn Marino 		      getval(fp, (struct buf*)0, false) &&
20086d7f5d3SJohn Marino 		      keeprev(fp) &&
20186d7f5d3SJohn Marino 		      (c = keepdate(fp)) &&
20286d7f5d3SJohn Marino 		      keepid(c, fp, &prevauthor) &&
20386d7f5d3SJohn Marino 		      keepid(0, fp, &prevstate)
20486d7f5d3SJohn Marino 		))
20586d7f5d3SJohn Marino 		    return false;
20686d7f5d3SJohn Marino 		/* Skip either ``who'' (new form) or ``Locker: who'' (old).  */
20786d7f5d3SJohn Marino 		if (getval(fp, (struct buf*)0, true) &&
20886d7f5d3SJohn Marino 		    getval(fp, (struct buf*)0, true))
20986d7f5d3SJohn Marino 			c = 0;
21086d7f5d3SJohn Marino 		else if (nerror)
21186d7f5d3SJohn Marino 			return false;
21286d7f5d3SJohn Marino 		else
21386d7f5d3SJohn Marino 			c = KDELIM;
21486d7f5d3SJohn Marino 		break;
21586d7f5d3SJohn Marino             case Locker:
21686d7f5d3SJohn Marino 		(void) getval(fp, (struct buf*)0, false);
21786d7f5d3SJohn Marino 		c = 0;
21886d7f5d3SJohn Marino 		break;
21986d7f5d3SJohn Marino             case Log:
22086d7f5d3SJohn Marino             case RCSfile:
22186d7f5d3SJohn Marino             case Source:
22286d7f5d3SJohn Marino 		if (!getval(fp, (struct buf*)0, false))
22386d7f5d3SJohn Marino 		    return false;
22486d7f5d3SJohn Marino 		c = 0;
22586d7f5d3SJohn Marino                 break;
22686d7f5d3SJohn Marino 	    case Name:
22786d7f5d3SJohn Marino 		if (getval(fp, &prevname, false)) {
22886d7f5d3SJohn Marino 		    if (*prevname.string)
22986d7f5d3SJohn Marino 			checkssym(prevname.string);
23086d7f5d3SJohn Marino 		    prevname_found = 1;
23186d7f5d3SJohn Marino 		}
23286d7f5d3SJohn Marino 		c = 0;
23386d7f5d3SJohn Marino 		break;
23486d7f5d3SJohn Marino             case Revision:
23586d7f5d3SJohn Marino 		if (!keeprev(fp))
23686d7f5d3SJohn Marino 		    return false;
23786d7f5d3SJohn Marino 		c = 0;
23886d7f5d3SJohn Marino                 break;
23986d7f5d3SJohn Marino             case State:
24086d7f5d3SJohn Marino 		if (!keepid(0, fp, &prevstate))
24186d7f5d3SJohn Marino 		    return false;
24286d7f5d3SJohn Marino 		c = 0;
24386d7f5d3SJohn Marino                 break;
24486d7f5d3SJohn Marino             default:
24586d7f5d3SJohn Marino                continue;
24686d7f5d3SJohn Marino             }
24786d7f5d3SJohn Marino 	    if (!c) {
24886d7f5d3SJohn Marino 		Igeteof_(fp, c, c=0;)
24986d7f5d3SJohn Marino             }
25086d7f5d3SJohn Marino 	    if (c != KDELIM) {
25186d7f5d3SJohn Marino 		workerror("closing %c missing on keyword", KDELIM);
25286d7f5d3SJohn Marino 		return false;
25386d7f5d3SJohn Marino 	    }
25486d7f5d3SJohn Marino 	    if (prevname_found &&
25586d7f5d3SJohn Marino 		*prevauthor.string && *prevdate.string &&
25686d7f5d3SJohn Marino 		*prevrev.string && *prevstate.string
25786d7f5d3SJohn Marino 	    )
25886d7f5d3SJohn Marino                 break;
25986d7f5d3SJohn Marino         }
26086d7f5d3SJohn Marino 	Igeteof_(fp, c, break;)
26186d7f5d3SJohn Marino     }
26286d7f5d3SJohn Marino 
26386d7f5d3SJohn Marino  ok:
26486d7f5d3SJohn Marino     if (needs_closing)
26586d7f5d3SJohn Marino 	Ifclose(fp);
26686d7f5d3SJohn Marino     else
26786d7f5d3SJohn Marino 	Irewind(fp);
26886d7f5d3SJohn Marino     prevkeys = true;
26986d7f5d3SJohn Marino     return true;
27086d7f5d3SJohn Marino }
27186d7f5d3SJohn Marino 
27286d7f5d3SJohn Marino 	static int
badly_terminated()27386d7f5d3SJohn Marino badly_terminated()
27486d7f5d3SJohn Marino {
27586d7f5d3SJohn Marino 	workerror("badly terminated keyword value");
27686d7f5d3SJohn Marino 	return false;
27786d7f5d3SJohn Marino }
27886d7f5d3SJohn Marino 
27986d7f5d3SJohn Marino 	static int
getval(fp,target,optional)28086d7f5d3SJohn Marino getval(fp, target, optional)
28186d7f5d3SJohn Marino 	register RILE *fp;
28286d7f5d3SJohn Marino 	struct buf *target;
28386d7f5d3SJohn Marino 	int optional;
28486d7f5d3SJohn Marino /* Reads a keyword value from FP into TARGET.
28586d7f5d3SJohn Marino  * Returns true if one is found, false otherwise.
28686d7f5d3SJohn Marino  * Does not modify target if it is 0.
28786d7f5d3SJohn Marino  * Do not report an error if OPTIONAL is set and KDELIM is found instead.
28886d7f5d3SJohn Marino  */
28986d7f5d3SJohn Marino {
29086d7f5d3SJohn Marino 	int c;
29186d7f5d3SJohn Marino 	Igeteof_(fp, c, return badly_terminated();)
29286d7f5d3SJohn Marino 	return get0val(c, fp, target, optional);
29386d7f5d3SJohn Marino }
29486d7f5d3SJohn Marino 
29586d7f5d3SJohn Marino 	static int
get0val(c,fp,target,optional)29686d7f5d3SJohn Marino get0val(c, fp, target, optional)
29786d7f5d3SJohn Marino 	register int c;
29886d7f5d3SJohn Marino 	register RILE *fp;
29986d7f5d3SJohn Marino 	struct buf *target;
30086d7f5d3SJohn Marino 	int optional;
30186d7f5d3SJohn Marino /* Reads a keyword value from C+FP into TARGET, perhaps OPTIONALly.
30286d7f5d3SJohn Marino  * Same as getval, except C is the lookahead character.
30386d7f5d3SJohn Marino  */
30486d7f5d3SJohn Marino {   register char * tp;
30586d7f5d3SJohn Marino     char const *tlim;
30686d7f5d3SJohn Marino     register int got1;
30786d7f5d3SJohn Marino 
30886d7f5d3SJohn Marino     if (target) {
30986d7f5d3SJohn Marino 	bufalloc(target, 1);
31086d7f5d3SJohn Marino 	tp = target->string;
31186d7f5d3SJohn Marino 	tlim = tp + target->size;
31286d7f5d3SJohn Marino     } else
31386d7f5d3SJohn Marino 	tlim = tp = 0;
31486d7f5d3SJohn Marino     got1 = false;
31586d7f5d3SJohn Marino     for (;;) {
31686d7f5d3SJohn Marino 	switch (c) {
31786d7f5d3SJohn Marino 	    default:
31886d7f5d3SJohn Marino 		got1 = true;
31986d7f5d3SJohn Marino 		if (tp) {
32086d7f5d3SJohn Marino 		    *tp++ = c;
32186d7f5d3SJohn Marino 		    if (tlim <= tp)
32286d7f5d3SJohn Marino 			tp = bufenlarge(target, &tlim);
32386d7f5d3SJohn Marino 		}
32486d7f5d3SJohn Marino 		break;
32586d7f5d3SJohn Marino 
32686d7f5d3SJohn Marino 	    case ' ':
32786d7f5d3SJohn Marino 	    case '\t':
32886d7f5d3SJohn Marino 		if (tp) {
32986d7f5d3SJohn Marino 		    *tp = 0;
33086d7f5d3SJohn Marino #		    ifdef KEEPTEST
33186d7f5d3SJohn Marino 			VOID printf("getval: %s\n", target);
33286d7f5d3SJohn Marino #		    endif
33386d7f5d3SJohn Marino 		}
33486d7f5d3SJohn Marino 		return got1;
33586d7f5d3SJohn Marino 
33686d7f5d3SJohn Marino 	    case KDELIM:
33786d7f5d3SJohn Marino 		if (!got1 && optional)
33886d7f5d3SJohn Marino 		    return false;
33986d7f5d3SJohn Marino 		/* fall into */
34086d7f5d3SJohn Marino 	    case '\n':
34186d7f5d3SJohn Marino 	    case 0:
34286d7f5d3SJohn Marino 		return badly_terminated();
34386d7f5d3SJohn Marino 	}
34486d7f5d3SJohn Marino 	Igeteof_(fp, c, return badly_terminated();)
34586d7f5d3SJohn Marino     }
34686d7f5d3SJohn Marino }
34786d7f5d3SJohn Marino 
34886d7f5d3SJohn Marino 
34986d7f5d3SJohn Marino 	static int
keepdate(fp)35086d7f5d3SJohn Marino keepdate(fp)
35186d7f5d3SJohn Marino 	RILE *fp;
35286d7f5d3SJohn Marino /* Function: reads a date prevdate; checks format
35386d7f5d3SJohn Marino  * Return 0 on error, lookahead character otherwise.
35486d7f5d3SJohn Marino  */
35586d7f5d3SJohn Marino {
35686d7f5d3SJohn Marino     struct buf prevday, prevtime;
35786d7f5d3SJohn Marino     register int c;
35886d7f5d3SJohn Marino 
35986d7f5d3SJohn Marino     c = 0;
36086d7f5d3SJohn Marino     bufautobegin(&prevday);
36186d7f5d3SJohn Marino     if (getval(fp,&prevday,false)) {
36286d7f5d3SJohn Marino 	bufautobegin(&prevtime);
36386d7f5d3SJohn Marino 	if (getval(fp,&prevtime,false)) {
36486d7f5d3SJohn Marino 	    Igeteof_(fp, c, c=0;)
36586d7f5d3SJohn Marino 	    if (c) {
36686d7f5d3SJohn Marino 		register char const *d = prevday.string, *t = prevtime.string;
36786d7f5d3SJohn Marino 		bufalloc(&prevdate, strlen(d) + strlen(t) + 9);
36886d7f5d3SJohn Marino 		VOID sprintf(prevdate.string, "%s%s %s%s",
36986d7f5d3SJohn Marino 		    /* Parse dates put out by old versions of RCS.  */
37086d7f5d3SJohn Marino 		      isdigit(d[0]) && isdigit(d[1]) && !isdigit(d[2])
37186d7f5d3SJohn Marino 		    ? "19" : "",
37286d7f5d3SJohn Marino 		    d, t,
37386d7f5d3SJohn Marino 		    strchr(t,'-') || strchr(t,'+')  ?  ""  :  "+0000"
37486d7f5d3SJohn Marino 		);
37586d7f5d3SJohn Marino 	    }
37686d7f5d3SJohn Marino 	}
37786d7f5d3SJohn Marino 	bufautoend(&prevtime);
37886d7f5d3SJohn Marino     }
37986d7f5d3SJohn Marino     bufautoend(&prevday);
38086d7f5d3SJohn Marino     return c;
38186d7f5d3SJohn Marino }
38286d7f5d3SJohn Marino 
38386d7f5d3SJohn Marino 	static int
keepid(c,fp,b)38486d7f5d3SJohn Marino keepid(c, fp, b)
38586d7f5d3SJohn Marino 	int c;
38686d7f5d3SJohn Marino 	RILE *fp;
38786d7f5d3SJohn Marino 	struct buf *b;
38886d7f5d3SJohn Marino /* Get previous identifier from C+FP into B.  */
38986d7f5d3SJohn Marino {
39086d7f5d3SJohn Marino 	if (!c) {
39186d7f5d3SJohn Marino 	    Igeteof_(fp, c, return false;)
39286d7f5d3SJohn Marino 	}
39386d7f5d3SJohn Marino 	if (!get0val(c, fp, b, false))
39486d7f5d3SJohn Marino 	    return false;
39586d7f5d3SJohn Marino 	checksid(b->string);
39686d7f5d3SJohn Marino 	return !nerror;
39786d7f5d3SJohn Marino }
39886d7f5d3SJohn Marino 
39986d7f5d3SJohn Marino 	static int
keeprev(fp)40086d7f5d3SJohn Marino keeprev(fp)
40186d7f5d3SJohn Marino 	RILE *fp;
40286d7f5d3SJohn Marino /* Get previous revision from FP into prevrev.  */
40386d7f5d3SJohn Marino {
40486d7f5d3SJohn Marino 	return getval(fp,&prevrev,false) && checknum(prevrev.string);
40586d7f5d3SJohn Marino }
40686d7f5d3SJohn Marino 
40786d7f5d3SJohn Marino 
40886d7f5d3SJohn Marino 	static int
checknum(s)40986d7f5d3SJohn Marino checknum(s)
41086d7f5d3SJohn Marino 	char const *s;
41186d7f5d3SJohn Marino {
41286d7f5d3SJohn Marino     register char const *sp;
41386d7f5d3SJohn Marino     register int dotcount = 0;
41486d7f5d3SJohn Marino     for (sp=s; ; sp++) {
41586d7f5d3SJohn Marino 	switch (*sp) {
41686d7f5d3SJohn Marino 	    case 0:
41786d7f5d3SJohn Marino 		if (dotcount & 1)
41886d7f5d3SJohn Marino 		    return true;
41986d7f5d3SJohn Marino 		else
42086d7f5d3SJohn Marino 		    break;
42186d7f5d3SJohn Marino 
42286d7f5d3SJohn Marino 	    case '.':
42386d7f5d3SJohn Marino 		dotcount++;
42486d7f5d3SJohn Marino 		continue;
42586d7f5d3SJohn Marino 
42686d7f5d3SJohn Marino 	    default:
42786d7f5d3SJohn Marino 		if (isdigit(*sp))
42886d7f5d3SJohn Marino 		    continue;
42986d7f5d3SJohn Marino 		break;
43086d7f5d3SJohn Marino 	}
43186d7f5d3SJohn Marino 	break;
43286d7f5d3SJohn Marino     }
43386d7f5d3SJohn Marino     workerror("%s is not a revision number", s);
43486d7f5d3SJohn Marino     return false;
43586d7f5d3SJohn Marino }
43686d7f5d3SJohn Marino 
43786d7f5d3SJohn Marino 
43886d7f5d3SJohn Marino 
43986d7f5d3SJohn Marino #ifdef KEEPTEST
44086d7f5d3SJohn Marino 
44186d7f5d3SJohn Marino /* Print the keyword values found.  */
44286d7f5d3SJohn Marino 
44386d7f5d3SJohn Marino char const cmdid[] ="keeptest";
44486d7f5d3SJohn Marino 
44586d7f5d3SJohn Marino 	int
main(argc,argv)44686d7f5d3SJohn Marino main(argc, argv)
44786d7f5d3SJohn Marino int  argc; char  *argv[];
44886d7f5d3SJohn Marino {
44986d7f5d3SJohn Marino         while (*(++argv)) {
45086d7f5d3SJohn Marino 		workname = *argv;
45186d7f5d3SJohn Marino 		getoldkeys((RILE*)0);
45286d7f5d3SJohn Marino                 VOID printf("%s:  revision: %s, date: %s, author: %s, name: %s, state: %s\n",
45386d7f5d3SJohn Marino 			    *argv, prevrev.string, prevdate.string, prevauthor.string, prevname.string, prevstate.string);
45486d7f5d3SJohn Marino 	}
45586d7f5d3SJohn Marino 	exitmain(EXIT_SUCCESS);
45686d7f5d3SJohn Marino }
45786d7f5d3SJohn Marino #endif
458