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