1*fa28c6faSchristos /* $NetBSD: rcskeep.c,v 1.2 2016/01/14 04:22:39 christos Exp $ */
27bdc2678Schristos
37bdc2678Schristos /* Extract RCS keyword string values from working files. */
47bdc2678Schristos
57bdc2678Schristos /* Copyright 1982, 1988, 1989 Walter Tichy
67bdc2678Schristos Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
77bdc2678Schristos Distributed under license by the Free Software Foundation, Inc.
87bdc2678Schristos
97bdc2678Schristos This file is part of RCS.
107bdc2678Schristos
117bdc2678Schristos RCS is free software; you can redistribute it and/or modify
127bdc2678Schristos it under the terms of the GNU General Public License as published by
137bdc2678Schristos the Free Software Foundation; either version 2, or (at your option)
147bdc2678Schristos any later version.
157bdc2678Schristos
167bdc2678Schristos RCS is distributed in the hope that it will be useful,
177bdc2678Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
187bdc2678Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
197bdc2678Schristos GNU General Public License for more details.
207bdc2678Schristos
217bdc2678Schristos You should have received a copy of the GNU General Public License
227bdc2678Schristos along with RCS; see the file COPYING.
237bdc2678Schristos If not, write to the Free Software Foundation,
247bdc2678Schristos 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
257bdc2678Schristos
267bdc2678Schristos Report problems and direct all questions to:
277bdc2678Schristos
287bdc2678Schristos rcs-bugs@cs.purdue.edu
297bdc2678Schristos
307bdc2678Schristos */
317bdc2678Schristos
327bdc2678Schristos /*
337bdc2678Schristos * Log: rcskeep.c,v
347bdc2678Schristos * Revision 5.10 1995/06/16 06:19:24 eggert
357bdc2678Schristos * Update FSF address.
367bdc2678Schristos *
377bdc2678Schristos * Revision 5.9 1995/06/01 16:23:43 eggert
387bdc2678Schristos * (getoldkeys): Don't panic if a Name: is empty.
397bdc2678Schristos *
407bdc2678Schristos * Revision 5.8 1994/03/17 14:05:48 eggert
417bdc2678Schristos * Remove lint.
427bdc2678Schristos *
437bdc2678Schristos * Revision 5.7 1993/11/09 17:40:15 eggert
447bdc2678Schristos * Use simpler timezone parsing strategy now that we're using ISO 8601 format.
457bdc2678Schristos *
467bdc2678Schristos * Revision 5.6 1993/11/03 17:42:27 eggert
477bdc2678Schristos * Scan for Name keyword. Improve quality of diagnostics.
487bdc2678Schristos *
497bdc2678Schristos * Revision 5.5 1992/07/28 16:12:44 eggert
507bdc2678Schristos * Statement macro names now end in _.
517bdc2678Schristos *
527bdc2678Schristos * Revision 5.4 1991/08/19 03:13:55 eggert
537bdc2678Schristos * Tune.
547bdc2678Schristos *
557bdc2678Schristos * Revision 5.3 1991/04/21 11:58:25 eggert
567bdc2678Schristos * Shorten names to keep them distinct on shortname hosts.
577bdc2678Schristos *
587bdc2678Schristos * Revision 5.2 1990/10/04 06:30:20 eggert
597bdc2678Schristos * Parse time zone offsets; future RCS versions may output them.
607bdc2678Schristos *
617bdc2678Schristos * Revision 5.1 1990/09/20 02:38:56 eggert
627bdc2678Schristos * ci -k now checks dates more thoroughly.
637bdc2678Schristos *
647bdc2678Schristos * Revision 5.0 1990/08/22 08:12:53 eggert
657bdc2678Schristos * Retrieve old log message if there is one.
667bdc2678Schristos * Don't require final newline.
677bdc2678Schristos * Remove compile-time limits; use malloc instead. Tune.
687bdc2678Schristos * Permit dates past 1999/12/31. Ansify and Posixate.
697bdc2678Schristos *
707bdc2678Schristos * Revision 4.6 89/05/01 15:12:56 narten
717bdc2678Schristos * changed copyright header to reflect current distribution rules
727bdc2678Schristos *
737bdc2678Schristos * Revision 4.5 88/08/09 19:13:03 eggert
747bdc2678Schristos * Remove lint and speed up by making FILE *fp local, not global.
757bdc2678Schristos *
767bdc2678Schristos * Revision 4.4 87/12/18 11:44:21 narten
777bdc2678Schristos * more lint cleanups (Guy Harris)
787bdc2678Schristos *
797bdc2678Schristos * Revision 4.3 87/10/18 10:35:50 narten
807bdc2678Schristos * Updating version numbers. Changes relative to 1.1 actually relative
817bdc2678Schristos * to 4.1
827bdc2678Schristos *
837bdc2678Schristos * Revision 1.3 87/09/24 14:00:00 narten
847bdc2678Schristos * Sources now pass through lint (if you ignore printf/sprintf/fprintf
857bdc2678Schristos * warnings)
867bdc2678Schristos *
877bdc2678Schristos * Revision 1.2 87/03/27 14:22:29 jenkins
887bdc2678Schristos * Port to suns
897bdc2678Schristos *
907bdc2678Schristos * Revision 4.1 83/05/10 16:26:44 wft
917bdc2678Schristos * Added new markers Id and RCSfile; extraction added.
927bdc2678Schristos * Marker matching with trymatch().
937bdc2678Schristos *
947bdc2678Schristos * Revision 3.2 82/12/24 12:08:26 wft
957bdc2678Schristos * added missing #endif.
967bdc2678Schristos *
977bdc2678Schristos * Revision 3.1 82/12/04 13:22:41 wft
987bdc2678Schristos * Initial revision.
997bdc2678Schristos *
1007bdc2678Schristos */
1017bdc2678Schristos
1027bdc2678Schristos #include "rcsbase.h"
1037bdc2678Schristos
1047bdc2678Schristos libId(keepId, "Id: rcskeep.c,v 5.10 1995/06/16 06:19:24 eggert Exp ")
1057bdc2678Schristos
1067bdc2678Schristos static int badly_terminated P((void));
1077bdc2678Schristos static int checknum P((char const*));
1087bdc2678Schristos static int get0val P((int,RILE*,struct buf*,int));
1097bdc2678Schristos static int getval P((RILE*,struct buf*,int));
1107bdc2678Schristos static int keepdate P((RILE*));
1117bdc2678Schristos static int keepid P((int,RILE*,struct buf*));
1127bdc2678Schristos static int keeprev P((RILE*));
1137bdc2678Schristos
1147bdc2678Schristos int prevkeys;
1157bdc2678Schristos struct buf prevauthor, prevdate, prevname, prevrev, prevstate;
1167bdc2678Schristos
1177bdc2678Schristos int
getoldkeys(fp)1187bdc2678Schristos getoldkeys(fp)
1197bdc2678Schristos register RILE *fp;
1207bdc2678Schristos /* Function: Tries to read keyword values for author, date,
1217bdc2678Schristos * revision number, and state out of the file fp.
1227bdc2678Schristos * If fp is null, workname is opened and closed instead of using fp.
1237bdc2678Schristos * The results are placed into
1247bdc2678Schristos * prevauthor, prevdate, prevname, prevrev, prevstate.
1257bdc2678Schristos * Aborts immediately if it finds an error and returns false.
1267bdc2678Schristos * If it returns true, it doesn't mean that any of the
1277bdc2678Schristos * values were found; instead, check to see whether the corresponding arrays
1287bdc2678Schristos * contain the empty string.
1297bdc2678Schristos */
1307bdc2678Schristos {
1317bdc2678Schristos register int c;
1327bdc2678Schristos char keyword[keylength+1];
1337bdc2678Schristos register char * tp;
1347bdc2678Schristos int needs_closing;
1357bdc2678Schristos int prevname_found;
1367bdc2678Schristos
1377bdc2678Schristos if (prevkeys)
1387bdc2678Schristos return true;
1397bdc2678Schristos
1407bdc2678Schristos needs_closing = false;
1417bdc2678Schristos if (!fp) {
1427bdc2678Schristos if (!(fp = Iopen(workname, FOPEN_R_WORK, (struct stat*)0))) {
1437bdc2678Schristos eerror(workname);
1447bdc2678Schristos return false;
1457bdc2678Schristos }
1467bdc2678Schristos needs_closing = true;
1477bdc2678Schristos }
1487bdc2678Schristos
1497bdc2678Schristos /* initialize to empty */
1507bdc2678Schristos bufscpy(&prevauthor, "");
1517bdc2678Schristos bufscpy(&prevdate, "");
1527bdc2678Schristos bufscpy(&prevname, ""); prevname_found = 0;
1537bdc2678Schristos bufscpy(&prevrev, "");
1547bdc2678Schristos bufscpy(&prevstate, "");
1557bdc2678Schristos
1567bdc2678Schristos c = '\0'; /* anything but KDELIM */
1577bdc2678Schristos for (;;) {
1587bdc2678Schristos if ( c==KDELIM) {
1597bdc2678Schristos do {
1607bdc2678Schristos /* try to get keyword */
1617bdc2678Schristos tp = keyword;
1627bdc2678Schristos for (;;) {
1637bdc2678Schristos Igeteof_(fp, c, goto ok;)
1647bdc2678Schristos switch (c) {
1657bdc2678Schristos default:
1667bdc2678Schristos if (keyword+keylength <= tp)
1677bdc2678Schristos break;
1687bdc2678Schristos *tp++ = c;
1697bdc2678Schristos continue;
1707bdc2678Schristos
1717bdc2678Schristos case '\n': case KDELIM: case VDELIM:
1727bdc2678Schristos break;
1737bdc2678Schristos }
1747bdc2678Schristos break;
1757bdc2678Schristos }
1767bdc2678Schristos } while (c==KDELIM);
1777bdc2678Schristos if (c!=VDELIM) continue;
1787bdc2678Schristos *tp = c;
1797bdc2678Schristos Igeteof_(fp, c, break;)
1807bdc2678Schristos switch (c) {
1817bdc2678Schristos case ' ': case '\t': break;
1827bdc2678Schristos default: continue;
1837bdc2678Schristos }
1847bdc2678Schristos
1857bdc2678Schristos switch (trymatch(keyword)) {
1867bdc2678Schristos case Author:
1877bdc2678Schristos if (!keepid(0, fp, &prevauthor))
1887bdc2678Schristos return false;
1897bdc2678Schristos c = 0;
1907bdc2678Schristos break;
1917bdc2678Schristos case Date:
1927bdc2678Schristos if (!(c = keepdate(fp)))
1937bdc2678Schristos return false;
1947bdc2678Schristos break;
1957bdc2678Schristos case Header:
1967bdc2678Schristos case Id:
197*fa28c6faSchristos #ifdef LOCALID
198*fa28c6faSchristos case LocalId:
199*fa28c6faSchristos #endif
2007bdc2678Schristos if (!(
2017bdc2678Schristos getval(fp, (struct buf*)0, false) &&
2027bdc2678Schristos keeprev(fp) &&
2037bdc2678Schristos (c = keepdate(fp)) &&
2047bdc2678Schristos keepid(c, fp, &prevauthor) &&
2057bdc2678Schristos keepid(0, fp, &prevstate)
2067bdc2678Schristos ))
2077bdc2678Schristos return false;
2087bdc2678Schristos /* Skip either ``who'' (new form) or ``Locker: who'' (old). */
2097bdc2678Schristos if (getval(fp, (struct buf*)0, true) &&
2107bdc2678Schristos getval(fp, (struct buf*)0, true))
2117bdc2678Schristos c = 0;
2127bdc2678Schristos else if (nerror)
2137bdc2678Schristos return false;
2147bdc2678Schristos else
2157bdc2678Schristos c = KDELIM;
2167bdc2678Schristos break;
2177bdc2678Schristos case Locker:
2187bdc2678Schristos (void) getval(fp, (struct buf*)0, false);
2197bdc2678Schristos c = 0;
2207bdc2678Schristos break;
2217bdc2678Schristos case Log:
2227bdc2678Schristos case RCSfile:
2237bdc2678Schristos case Source:
2247bdc2678Schristos if (!getval(fp, (struct buf*)0, false))
2257bdc2678Schristos return false;
2267bdc2678Schristos c = 0;
2277bdc2678Schristos break;
2287bdc2678Schristos case Name:
2297bdc2678Schristos if (getval(fp, &prevname, false)) {
2307bdc2678Schristos if (*prevname.string)
2317bdc2678Schristos checkssym(prevname.string);
2327bdc2678Schristos prevname_found = 1;
2337bdc2678Schristos }
2347bdc2678Schristos c = 0;
2357bdc2678Schristos break;
2367bdc2678Schristos case Revision:
2377bdc2678Schristos if (!keeprev(fp))
2387bdc2678Schristos return false;
2397bdc2678Schristos c = 0;
2407bdc2678Schristos break;
2417bdc2678Schristos case State:
2427bdc2678Schristos if (!keepid(0, fp, &prevstate))
2437bdc2678Schristos return false;
2447bdc2678Schristos c = 0;
2457bdc2678Schristos break;
2467bdc2678Schristos default:
2477bdc2678Schristos continue;
2487bdc2678Schristos }
2497bdc2678Schristos if (!c)
2507bdc2678Schristos Igeteof_(fp, c, c=0;)
2517bdc2678Schristos if (c != KDELIM) {
2527bdc2678Schristos workerror("closing %c missing on keyword", KDELIM);
2537bdc2678Schristos return false;
2547bdc2678Schristos }
2557bdc2678Schristos if (prevname_found &&
2567bdc2678Schristos *prevauthor.string && *prevdate.string &&
2577bdc2678Schristos *prevrev.string && *prevstate.string
2587bdc2678Schristos )
2597bdc2678Schristos break;
2607bdc2678Schristos }
2617bdc2678Schristos Igeteof_(fp, c, break;)
2627bdc2678Schristos }
2637bdc2678Schristos
2647bdc2678Schristos ok:
2657bdc2678Schristos if (needs_closing)
2667bdc2678Schristos Ifclose(fp);
2677bdc2678Schristos else
2687bdc2678Schristos Irewind(fp);
2697bdc2678Schristos prevkeys = true;
2707bdc2678Schristos return true;
2717bdc2678Schristos }
2727bdc2678Schristos
2737bdc2678Schristos static int
badly_terminated()2747bdc2678Schristos badly_terminated()
2757bdc2678Schristos {
2767bdc2678Schristos workerror("badly terminated keyword value");
2777bdc2678Schristos return false;
2787bdc2678Schristos }
2797bdc2678Schristos
2807bdc2678Schristos static int
getval(fp,target,optional)2817bdc2678Schristos getval(fp, target, optional)
2827bdc2678Schristos register RILE *fp;
2837bdc2678Schristos struct buf *target;
2847bdc2678Schristos int optional;
2857bdc2678Schristos /* Reads a keyword value from FP into TARGET.
2867bdc2678Schristos * Returns true if one is found, false otherwise.
2877bdc2678Schristos * Does not modify target if it is 0.
2887bdc2678Schristos * Do not report an error if OPTIONAL is set and KDELIM is found instead.
2897bdc2678Schristos */
2907bdc2678Schristos {
2917bdc2678Schristos int c;
2927bdc2678Schristos Igeteof_(fp, c, return badly_terminated();)
2937bdc2678Schristos return get0val(c, fp, target, optional);
2947bdc2678Schristos }
2957bdc2678Schristos
2967bdc2678Schristos static int
get0val(c,fp,target,optional)2977bdc2678Schristos get0val(c, fp, target, optional)
2987bdc2678Schristos register int c;
2997bdc2678Schristos register RILE *fp;
3007bdc2678Schristos struct buf *target;
3017bdc2678Schristos int optional;
3027bdc2678Schristos /* Reads a keyword value from C+FP into TARGET, perhaps OPTIONALly.
3037bdc2678Schristos * Same as getval, except C is the lookahead character.
3047bdc2678Schristos */
3057bdc2678Schristos { register char * tp;
3067bdc2678Schristos char const *tlim;
3077bdc2678Schristos register int got1;
3087bdc2678Schristos
3097bdc2678Schristos if (target) {
3107bdc2678Schristos bufalloc(target, 1);
3117bdc2678Schristos tp = target->string;
3127bdc2678Schristos tlim = tp + target->size;
3137bdc2678Schristos } else
3147bdc2678Schristos tlim = tp = 0;
3157bdc2678Schristos got1 = false;
3167bdc2678Schristos for (;;) {
3177bdc2678Schristos switch (c) {
3187bdc2678Schristos default:
3197bdc2678Schristos got1 = true;
3207bdc2678Schristos if (tp) {
3217bdc2678Schristos *tp++ = c;
3227bdc2678Schristos if (tlim <= tp)
3237bdc2678Schristos tp = bufenlarge(target, &tlim);
3247bdc2678Schristos }
3257bdc2678Schristos break;
3267bdc2678Schristos
3277bdc2678Schristos case ' ':
3287bdc2678Schristos case '\t':
3297bdc2678Schristos if (tp) {
3307bdc2678Schristos *tp = 0;
3317bdc2678Schristos # ifdef KEEPTEST
3327bdc2678Schristos VOID printf("getval: %s\n", target);
3337bdc2678Schristos # endif
3347bdc2678Schristos }
3357bdc2678Schristos return got1;
3367bdc2678Schristos
3377bdc2678Schristos case KDELIM:
3387bdc2678Schristos if (!got1 && optional)
3397bdc2678Schristos return false;
3407bdc2678Schristos /* fall into */
3417bdc2678Schristos case '\n':
3427bdc2678Schristos case 0:
3437bdc2678Schristos return badly_terminated();
3447bdc2678Schristos }
3457bdc2678Schristos Igeteof_(fp, c, return badly_terminated();)
3467bdc2678Schristos }
3477bdc2678Schristos }
3487bdc2678Schristos
3497bdc2678Schristos
3507bdc2678Schristos static int
keepdate(fp)3517bdc2678Schristos keepdate(fp)
3527bdc2678Schristos RILE *fp;
3537bdc2678Schristos /* Function: reads a date prevdate; checks format
3547bdc2678Schristos * Return 0 on error, lookahead character otherwise.
3557bdc2678Schristos */
3567bdc2678Schristos {
3577bdc2678Schristos struct buf prevday, prevtime;
3587bdc2678Schristos register int c;
3597bdc2678Schristos
3607bdc2678Schristos c = 0;
3617bdc2678Schristos bufautobegin(&prevday);
3627bdc2678Schristos if (getval(fp,&prevday,false)) {
3637bdc2678Schristos bufautobegin(&prevtime);
3647bdc2678Schristos if (getval(fp,&prevtime,false)) {
3657bdc2678Schristos Igeteof_(fp, c, c=0;)
3667bdc2678Schristos if (c) {
3677bdc2678Schristos register char const *d = prevday.string, *t = prevtime.string;
3687bdc2678Schristos bufalloc(&prevdate, strlen(d) + strlen(t) + 9);
3697bdc2678Schristos VOID sprintf(prevdate.string, "%s%s %s%s",
3707bdc2678Schristos /* Parse dates put out by old versions of RCS. */
3717bdc2678Schristos isdigit(d[0]) && isdigit(d[1]) && !isdigit(d[2])
3727bdc2678Schristos ? "19" : "",
3737bdc2678Schristos d, t,
3747bdc2678Schristos strchr(t,'-') || strchr(t,'+') ? "" : "+0000"
3757bdc2678Schristos );
3767bdc2678Schristos }
3777bdc2678Schristos }
3787bdc2678Schristos bufautoend(&prevtime);
3797bdc2678Schristos }
3807bdc2678Schristos bufautoend(&prevday);
3817bdc2678Schristos return c;
3827bdc2678Schristos }
3837bdc2678Schristos
3847bdc2678Schristos static int
keepid(c,fp,b)3857bdc2678Schristos keepid(c, fp, b)
3867bdc2678Schristos int c;
3877bdc2678Schristos RILE *fp;
3887bdc2678Schristos struct buf *b;
3897bdc2678Schristos /* Get previous identifier from C+FP into B. */
3907bdc2678Schristos {
3917bdc2678Schristos if (!c)
3927bdc2678Schristos Igeteof_(fp, c, return false;)
3937bdc2678Schristos if (!get0val(c, fp, b, false))
3947bdc2678Schristos return false;
3957bdc2678Schristos checksid(b->string);
3967bdc2678Schristos return !nerror;
3977bdc2678Schristos }
3987bdc2678Schristos
3997bdc2678Schristos static int
keeprev(fp)4007bdc2678Schristos keeprev(fp)
4017bdc2678Schristos RILE *fp;
4027bdc2678Schristos /* Get previous revision from FP into prevrev. */
4037bdc2678Schristos {
4047bdc2678Schristos return getval(fp,&prevrev,false) && checknum(prevrev.string);
4057bdc2678Schristos }
4067bdc2678Schristos
4077bdc2678Schristos
4087bdc2678Schristos static int
checknum(s)4097bdc2678Schristos checknum(s)
4107bdc2678Schristos char const *s;
4117bdc2678Schristos {
4127bdc2678Schristos register char const *sp;
4137bdc2678Schristos register int dotcount = 0;
4147bdc2678Schristos for (sp=s; ; sp++) {
4157bdc2678Schristos switch (*sp) {
4167bdc2678Schristos case 0:
4177bdc2678Schristos if (dotcount & 1)
4187bdc2678Schristos return true;
4197bdc2678Schristos else
4207bdc2678Schristos break;
4217bdc2678Schristos
4227bdc2678Schristos case '.':
4237bdc2678Schristos dotcount++;
4247bdc2678Schristos continue;
4257bdc2678Schristos
4267bdc2678Schristos default:
4277bdc2678Schristos if (isdigit(*sp))
4287bdc2678Schristos continue;
4297bdc2678Schristos break;
4307bdc2678Schristos }
4317bdc2678Schristos break;
4327bdc2678Schristos }
4337bdc2678Schristos workerror("%s is not a revision number", s);
4347bdc2678Schristos return false;
4357bdc2678Schristos }
4367bdc2678Schristos
4377bdc2678Schristos
4387bdc2678Schristos
4397bdc2678Schristos #ifdef KEEPTEST
4407bdc2678Schristos
4417bdc2678Schristos /* Print the keyword values found. */
4427bdc2678Schristos
4437bdc2678Schristos char const cmdid[] ="keeptest";
4447bdc2678Schristos
4457bdc2678Schristos int
main(argc,argv)4467bdc2678Schristos main(argc, argv)
4477bdc2678Schristos int argc; char *argv[];
4487bdc2678Schristos {
4497bdc2678Schristos while (*(++argv)) {
4507bdc2678Schristos workname = *argv;
4517bdc2678Schristos getoldkeys((RILE*)0);
4527bdc2678Schristos VOID printf("%s: revision: %s, date: %s, author: %s, name: %s, state: %s\n",
4537bdc2678Schristos *argv, prevrev.string, prevdate.string, prevauthor.string, prevname.string, prevstate.string);
4547bdc2678Schristos }
4557bdc2678Schristos exitmain(EXIT_SUCCESS);
4567bdc2678Schristos }
4577bdc2678Schristos #endif
458