Bug Summary

File:src/usr.bin/cvs/rcsparse.c
Warning:line 1107, column 2
Value stored to 'i' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name rcsparse.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/cvs/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/cvs -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/cvs/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/cvs/rcsparse.c
1/* $OpenBSD: rcsparse.c,v 1.13 2016/10/13 20:51:25 fcambus Exp $ */
2/*
3 * Copyright (c) 2010 Tobias Stoeckmann <tobias@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <sys/queue.h>
19
20#include <ctype.h>
21#include <err.h>
22#include <pwd.h>
23#include <stdarg.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28
29#include "log.h"
30#include "rcs.h"
31#include "rcsparse.h"
32#include "xmalloc.h"
33
34#define RCS_BUFSIZE16384 16384
35#define RCS_BUFEXTSIZE8192 8192
36
37/* RCS token types */
38#define RCS_TOK_HEAD(1 << 0) (1 << 0)
39#define RCS_TOK_BRANCH(1 << 1) (1 << 1)
40#define RCS_TOK_ACCESS(1 << 2) (1 << 2)
41#define RCS_TOK_SYMBOLS(1 << 3) (1 << 3)
42#define RCS_TOK_LOCKS(1 << 4) (1 << 4)
43#define RCS_TOK_STRICT(1 << 5) (1 << 5)
44#define RCS_TOK_COMMENT(1 << 6) (1 << 6)
45#define RCS_TOK_COMMITID(1 << 7) (1 << 7)
46#define RCS_TOK_EXPAND(1 << 8) (1 << 8)
47#define RCS_TOK_DESC(1 << 9) (1 << 9)
48#define RCS_TOK_DATE(1 << 10) (1 << 10)
49#define RCS_TOK_AUTHOR(1 << 11) (1 << 11)
50#define RCS_TOK_STATE(1 << 12) (1 << 12)
51#define RCS_TOK_BRANCHES(1 << 13) (1 << 13)
52#define RCS_TOK_NEXT(1 << 14) (1 << 14)
53#define RCS_TOK_LOG(1 << 15) (1 << 15)
54#define RCS_TOK_TEXT(1 << 16) (1 << 16)
55#define RCS_TOK_COLON(1 << 17) (1 << 17)
56#define RCS_TOK_COMMA(1 << 18) (1 << 18)
57#define RCS_TOK_SCOLON(1 << 19) (1 << 19)
58
59#define RCS_TYPE_STRING(1 << 20) (1 << 20)
60#define RCS_TYPE_NUMBER(1 << 21) (1 << 21)
61#define RCS_TYPE_BRANCH(1 << 22) (1 << 22)
62#define RCS_TYPE_REVISION(1 << 23) (1 << 23)
63#define RCS_TYPE_LOGIN(1 << 24) (1 << 24)
64#define RCS_TYPE_STATE(1 << 25) (1 << 25)
65#define RCS_TYPE_SYMBOL(1 << 26) (1 << 26)
66#define RCS_TYPE_DATE(1 << 27) (1 << 27)
67#define RCS_TYPE_KEYWORD(1 << 28) (1 << 28)
68#define RCS_TYPE_COMMITID(1 << 29) (1 << 29)
69
70#define MANDATORY0 0
71#define OPTIONAL1 1
72
73/* opaque parse data */
74struct rcs_pdata {
75 char *rp_buf;
76 size_t rp_blen;
77 char *rp_bufend;
78 size_t rp_tlen;
79
80 struct rcs_delta *rp_delta;
81 int rp_lineno;
82 int rp_msglineno;
83 int rp_token;
84
85 union {
86 RCSNUM *rev;
87 char *str;
88 struct tm date;
89 } rp_value;
90};
91
92struct rcs_keyword {
93 const char *k_name;
94 int k_val;
95};
96
97struct rcs_section {
98 int token;
99 int (*parse)(RCSFILE *, struct rcs_pdata *);
100 int opt;
101};
102
103/* this has to be sorted always */
104static const struct rcs_keyword keywords[] = {
105 { "access", RCS_TOK_ACCESS(1 << 2)},
106 { "author", RCS_TOK_AUTHOR(1 << 11)},
107 { "branch", RCS_TOK_BRANCH(1 << 1)},
108 { "branches", RCS_TOK_BRANCHES(1 << 13)},
109 { "comment", RCS_TOK_COMMENT(1 << 6)},
110 { "commitid", RCS_TOK_COMMITID(1 << 7)},
111 { "date", RCS_TOK_DATE(1 << 10)},
112 { "desc", RCS_TOK_DESC(1 << 9)},
113 { "expand", RCS_TOK_EXPAND(1 << 8)},
114 { "head", RCS_TOK_HEAD(1 << 0)},
115 { "locks", RCS_TOK_LOCKS(1 << 4)},
116 { "log", RCS_TOK_LOG(1 << 15)},
117 { "next", RCS_TOK_NEXT(1 << 14)},
118 { "state", RCS_TOK_STATE(1 << 12)},
119 { "strict", RCS_TOK_STRICT(1 << 5)},
120 { "symbols", RCS_TOK_SYMBOLS(1 << 3)},
121 { "text", RCS_TOK_TEXT(1 << 16)}
122};
123
124/* parser functions specified in rcs_section structs */
125static int rcsparse_head(RCSFILE *, struct rcs_pdata *);
126static int rcsparse_branch(RCSFILE *, struct rcs_pdata *);
127static int rcsparse_access(RCSFILE *, struct rcs_pdata *);
128static int rcsparse_symbols(RCSFILE *, struct rcs_pdata *);
129static int rcsparse_locks(RCSFILE *, struct rcs_pdata *);
130static int rcsparse_strict(RCSFILE *, struct rcs_pdata *);
131static int rcsparse_comment(RCSFILE *, struct rcs_pdata *);
132static int rcsparse_commitid(RCSFILE *, struct rcs_pdata *);
133static int rcsparse_expand(RCSFILE *, struct rcs_pdata *);
134static int rcsparse_deltarevision(RCSFILE *, struct rcs_pdata *);
135static int rcsparse_date(RCSFILE *, struct rcs_pdata *);
136static int rcsparse_author(RCSFILE *, struct rcs_pdata *);
137static int rcsparse_state(RCSFILE *, struct rcs_pdata *);
138static int rcsparse_branches(RCSFILE *, struct rcs_pdata *);
139static int rcsparse_next(RCSFILE *, struct rcs_pdata *);
140static int rcsparse_textrevision(RCSFILE *, struct rcs_pdata *);
141static int rcsparse_log(RCSFILE *, struct rcs_pdata *);
142static int rcsparse_text(RCSFILE *, struct rcs_pdata *);
143
144static int rcsparse_delta(RCSFILE *);
145static int rcsparse_deltatext(RCSFILE *);
146static int rcsparse_desc(RCSFILE *);
147
148static int kw_cmp(const void *, const void *);
149static int rcsparse(RCSFILE *, struct rcs_section *);
150static void rcsparse_growbuf(RCSFILE *);
151static int rcsparse_string(RCSFILE *, int);
152static int rcsparse_token(RCSFILE *, int);
153static void rcsparse_warnx(RCSFILE *, char *, ...);
154static int valid_login(char *);
155static int valid_commitid(char *);
156
157/*
158 * head [REVISION];
159 * [branch BRANCH];
160 * access [LOGIN ...];
161 * symbols [SYMBOL:REVISION ...];
162 * locks [LOGIN:REVISION ...];
163 * [strict;]
164 * [comment [@[...]@];]
165 * [expand [@[...]@];]
166 */
167static struct rcs_section sec_admin[] = {
168 { RCS_TOK_HEAD(1 << 0), rcsparse_head, MANDATORY0 },
169 { RCS_TOK_BRANCH(1 << 1), rcsparse_branch, OPTIONAL1 },
170 { RCS_TOK_ACCESS(1 << 2), rcsparse_access, MANDATORY0 },
171 { RCS_TOK_SYMBOLS(1 << 3), rcsparse_symbols, MANDATORY0 },
172 { RCS_TOK_LOCKS(1 << 4), rcsparse_locks, MANDATORY0 },
173 { RCS_TOK_STRICT(1 << 5), rcsparse_strict, OPTIONAL1 },
174 { RCS_TOK_COMMENT(1 << 6), rcsparse_comment, OPTIONAL1 },
175 { RCS_TOK_EXPAND(1 << 8), rcsparse_expand, OPTIONAL1 },
176 { 0, NULL((void *)0), 0 }
177};
178
179/*
180 * REVISION
181 * date [YY]YY.MM.DD.HH.MM.SS;
182 * author LOGIN;
183 * state STATE;
184 * branches [REVISION ...];
185 * next [REVISION];
186 * [commitid ID;]
187 */
188static struct rcs_section sec_delta[] = {
189 { RCS_TYPE_REVISION(1 << 23), rcsparse_deltarevision, MANDATORY0 },
190 { RCS_TOK_DATE(1 << 10), rcsparse_date, MANDATORY0 },
191 { RCS_TOK_AUTHOR(1 << 11), rcsparse_author, MANDATORY0 },
192 { RCS_TOK_STATE(1 << 12), rcsparse_state, MANDATORY0 },
193 { RCS_TOK_BRANCHES(1 << 13), rcsparse_branches, MANDATORY0 },
194 { RCS_TOK_NEXT(1 << 14), rcsparse_next, MANDATORY0 },
195 { RCS_TOK_COMMITID(1 << 7), rcsparse_commitid, OPTIONAL1 },
196 { 0, NULL((void *)0), 0 }
197};
198
199/*
200 * REVISION
201 * log @[...]@
202 * text @[...]@
203 */
204static struct rcs_section sec_deltatext[] = {
205 { RCS_TYPE_REVISION(1 << 23), rcsparse_textrevision, MANDATORY0 },
206 { RCS_TOK_LOG(1 << 15), rcsparse_log, MANDATORY0 },
207 { RCS_TOK_TEXT(1 << 16), rcsparse_text, MANDATORY0 },
208 { 0, NULL((void *)0), 0 }
209};
210
211/*
212 * rcsparse_init()
213 *
214 * Initializes the parsing data structure and parses the admin section of
215 * RCS file <rfp>.
216 *
217 * Returns 0 on success or 1 on failure.
218 */
219int
220rcsparse_init(RCSFILE *rfp)
221{
222 struct rcs_pdata *pdp;
223
224 if (rfp->rf_flags & RCS_PARSED(1<<4))
225 return (0);
226
227 pdp = xcalloc(1, sizeof(*pdp));
228 pdp->rp_buf = xmalloc(RCS_BUFSIZE16384);
229 pdp->rp_blen = RCS_BUFSIZE16384;
230 pdp->rp_bufend = pdp->rp_buf + pdp->rp_blen - 1;
231 pdp->rp_token = -1;
232 pdp->rp_lineno = 1;
233 pdp->rp_msglineno = 1;
234
235 /* ditch the strict lock */
236 rfp->rf_flags &= ~RCS_SLOCK(1<<6);
237 rfp->rf_pdata = pdp;
238
239 if (rcsparse(rfp, sec_admin)) {
240 rcsparse_free(rfp);
241 return (1);
242 }
243
244 if ((rfp->rf_flags & RCS_PARSE_FULLY(1<<3)) &&
245 rcsparse_deltatexts(rfp, NULL((void *)0))) {
246 rcsparse_free(rfp);
247 return (1);
248 }
249
250 rfp->rf_flags |= RCS_SYNCED(1<<5);
251 return (0);
252}
253
254/*
255 * rcsparse_deltas()
256 *
257 * Parse deltas. If <rev> is not NULL, parse only as far as that
258 * revision. If <rev> is NULL, parse all deltas.
259 *
260 * Returns 0 on success or 1 on error.
261 */
262int
263rcsparse_deltas(RCSFILE *rfp, RCSNUM *rev)
264{
265 int ret;
266 struct rcs_delta *enddelta;
267
268 if ((rfp->rf_flags & PARSED_DELTAS(1<<7)) || (rfp->rf_flags & RCS_CREATE(1<<2)))
269 return (0);
270
271 for (;;) {
272 ret = rcsparse_delta(rfp);
273 if (rev != NULL((void *)0)) {
274 enddelta = TAILQ_LAST(&(rfp->rf_delta), rcs_dlist)(*(((struct rcs_dlist *)((&(rfp->rf_delta))->tqh_last
))->tqh_last))
;
275 if (enddelta == NULL((void *)0))
276 return (1);
277
278 if (rcsnum_cmp(enddelta->rd_num, rev, 0) == 0)
279 break;
280 }
281
282 if (ret == 0) {
283 rfp->rf_flags |= PARSED_DELTAS(1<<7);
284 break;
285 }
286 else if (ret == -1)
287 return (1);
288 }
289
290 return (0);
291}
292
293/*
294 * rcsparse_deltatexts()
295 *
296 * Parse deltatexts. If <rev> is not NULL, parse only as far as that
297 * revision. If <rev> is NULL, parse everything.
298 *
299 * Returns 0 on success or 1 on error.
300 */
301int
302rcsparse_deltatexts(RCSFILE *rfp, RCSNUM *rev)
303{
304 int ret;
305 struct rcs_delta *rdp;
306
307 if ((rfp->rf_flags & PARSED_DELTATEXTS(1<<9)) ||
308 (rfp->rf_flags & RCS_CREATE(1<<2)))
309 return (0);
310
311 if (!(rfp->rf_flags & PARSED_DESC(1<<8)))
312 if (rcsparse_desc(rfp))
313 return (1);
314
315 rdp = (rev != NULL((void *)0)) ? rcs_findrev(rfp, rev) : NULL((void *)0);
316
317 for (;;) {
318 if (rdp != NULL((void *)0) && rdp->rd_text != NULL((void *)0))
319 break;
320 ret = rcsparse_deltatext(rfp);
321 if (ret == 0) {
322 rfp->rf_flags |= PARSED_DELTATEXTS(1<<9);
323 break;
324 }
325 else if (ret == -1)
326 return (1);
327 }
328
329 return (0);
330}
331
332/*
333 * rcsparse_free()
334 *
335 * Free the contents of the <rfp>'s parser data structure.
336 */
337void
338rcsparse_free(RCSFILE *rfp)
339{
340 struct rcs_pdata *pdp;
341
342 pdp = rfp->rf_pdata;
343
344 free(pdp->rp_buf);
345 if (pdp->rp_token == RCS_TYPE_REVISION(1 << 23))
346 free(pdp->rp_value.rev);
347 free(pdp);
348}
349
350/*
351 * rcsparse_desc()
352 *
353 * Parse desc of the RCS file <rfp>. By calling rcsparse_desc, all deltas
354 * will be parsed in order to proceed the reading cursor to the desc keyword.
355 *
356 * desc @[...]@;
357 *
358 * Returns 0 on success or 1 on error.
359 */
360static int
361rcsparse_desc(RCSFILE *rfp)
362{
363 struct rcs_pdata *pdp;
364
365 if (rfp->rf_flags & PARSED_DESC(1<<8))
366 return (0);
367
368 if (!(rfp->rf_flags & PARSED_DELTAS(1<<7)) && rcsparse_deltas(rfp, NULL((void *)0)))
369 return (1);
370
371 pdp = (struct rcs_pdata *)rfp->rf_pdata;
372
373 if (rcsparse_token(rfp, RCS_TOK_DESC(1 << 9)) != RCS_TOK_DESC(1 << 9) ||
374 rcsparse_token(rfp, RCS_TYPE_STRING(1 << 20)) != RCS_TYPE_STRING(1 << 20))
375 return (1);
376
377 rfp->rf_desc = pdp->rp_value.str;
378 rfp->rf_flags |= PARSED_DESC(1<<8);
379
380 return (0);
381}
382
383/*
384 * rcsparse_deltarevision()
385 *
386 * Called upon reaching a new REVISION entry in the delta section.
387 * A new rcs_delta structure will be prepared in pdp->rp_delta for further
388 * parsing.
389 *
390 * REVISION
391 *
392 * Always returns 0.
393 */
394static int
395rcsparse_deltarevision(RCSFILE *rfp, struct rcs_pdata *pdp)
396{
397 struct rcs_delta *rdp;
398
399 rdp = xcalloc(1, sizeof(*rdp));
400 TAILQ_INIT(&rdp->rd_branches)do { (&rdp->rd_branches)->tqh_first = ((void *)0); (
&rdp->rd_branches)->tqh_last = &(&rdp->rd_branches
)->tqh_first; } while (0)
;
401 rdp->rd_num = pdp->rp_value.rev;
402 pdp->rp_delta = rdp;
403
404 return (0);
405}
406
407/*
408 * rcsparse_date()
409 *
410 * Parses the specified date of current delta pdp->rp_delta.
411 *
412 * date YYYY.MM.DD.HH.MM.SS;
413 *
414 * Returns 0 on success or 1 on failure.
415 */
416static int
417rcsparse_date(RCSFILE *rfp, struct rcs_pdata *pdp)
418{
419 if (rcsparse_token(rfp, RCS_TYPE_DATE(1 << 27)) != RCS_TYPE_DATE(1 << 27))
420 return (1);
421
422 pdp->rp_delta->rd_date = pdp->rp_value.date;
423
424 return (rcsparse_token(rfp, RCS_TOK_SCOLON(1 << 19)) != RCS_TOK_SCOLON(1 << 19));
425}
426
427/*
428 * rcsparse_author()
429 *
430 * Parses the specified author of current delta pdp->rp_delta.
431 *
432 * author LOGIN;
433 *
434 * Returns 0 on success or 1 on failure.
435 */
436static int
437rcsparse_author(RCSFILE *rfp, struct rcs_pdata *pdp)
438{
439 if (rcsparse_token(rfp, RCS_TYPE_LOGIN(1 << 24)) != RCS_TYPE_LOGIN(1 << 24))
440 return (1);
441
442 pdp->rp_delta->rd_author = pdp->rp_value.str;
443
444 return (rcsparse_token(rfp, RCS_TOK_SCOLON(1 << 19)) != RCS_TOK_SCOLON(1 << 19));
445}
446
447/*
448 * rcsparse_state()
449 *
450 * Parses the specified state of current delta pdp->rp_delta.
451 *
452 * state STATE;
453 *
454 * Returns 0 on success or 1 on failure.
455 */
456static int
457rcsparse_state(RCSFILE *rfp, struct rcs_pdata *pdp)
458{
459 if (rcsparse_token(rfp, RCS_TYPE_STATE(1 << 25)) != RCS_TYPE_STATE(1 << 25))
460 return (1);
461
462 pdp->rp_delta->rd_state = pdp->rp_value.str;
463
464 return (rcsparse_token(rfp, RCS_TOK_SCOLON(1 << 19)) != RCS_TOK_SCOLON(1 << 19));
465}
466
467/*
468 * rcsparse_branches()
469 *
470 * Parses the specified branches of current delta pdp->rp_delta.
471 *
472 * branches [REVISION ...];
473 *
474 * Returns 0 on success or 1 on failure.
475 */
476static int
477rcsparse_branches(RCSFILE *rfp, struct rcs_pdata *pdp)
478{
479 struct rcs_branch *rb;
480 int type;
481
482 while ((type = rcsparse_token(rfp, RCS_TOK_SCOLON(1 << 19)|RCS_TYPE_REVISION(1 << 23)))
483 == RCS_TYPE_REVISION(1 << 23)) {
484 rb = xmalloc(sizeof(*rb));
485 rb->rb_num = pdp->rp_value.rev;
486 TAILQ_INSERT_TAIL(&(pdp->rp_delta->rd_branches), rb, rb_list)do { (rb)->rb_list.tqe_next = ((void *)0); (rb)->rb_list
.tqe_prev = (&(pdp->rp_delta->rd_branches))->tqh_last
; *(&(pdp->rp_delta->rd_branches))->tqh_last = (
rb); (&(pdp->rp_delta->rd_branches))->tqh_last =
&(rb)->rb_list.tqe_next; } while (0)
;
487 }
488
489 return (type != RCS_TOK_SCOLON(1 << 19));
490}
491
492/*
493 * rcsparse_next()
494 *
495 * Parses the specified next revision of current delta pdp->rp_delta.
496 *
497 * next [REVISION];
498 *
499 * Returns 0 on success or 1 on failure.
500 */
501static int
502rcsparse_next(RCSFILE *rfp, struct rcs_pdata *pdp)
503{
504 int type;
505
506 type = rcsparse_token(rfp, RCS_TYPE_REVISION(1 << 23)|RCS_TOK_SCOLON(1 << 19));
507 if (type == RCS_TYPE_REVISION(1 << 23)) {
508 pdp->rp_delta->rd_next = pdp->rp_value.rev;
509 type = rcsparse_token(rfp, RCS_TOK_SCOLON(1 << 19));
510 } else
511 pdp->rp_delta->rd_next = rcsnum_alloc();
512
513 return (type != RCS_TOK_SCOLON(1 << 19));
514}
515
516/*
517 * rcsparse_commitid()
518 *
519 * Parses the specified commit id of current delta pdp->rp_delta. The
520 * commitid keyword is optional and can be omitted.
521 *
522 * [commitid ID;]
523 *
524 * Returns 0 on success or 1 on failure.
525 */
526static int
527rcsparse_commitid(RCSFILE *rfp, struct rcs_pdata *pdp)
528{
529 if (rcsparse_token(rfp, RCS_TYPE_COMMITID(1 << 29)) != RCS_TYPE_COMMITID(1 << 29))
530 return (1);
531
532 pdp->rp_delta->rd_commitid = pdp->rp_value.str;
533
534 return (rcsparse_token(rfp, RCS_TOK_SCOLON(1 << 19)) != RCS_TOK_SCOLON(1 << 19));
535}
536
537/*
538 * rcsparse_textrevision()
539 *
540 * Called upon reaching a new REVISION entry in the delta text section.
541 * pdp->rp_delta will be set to REVISION's delta (created in delta section)
542 * for further parsing.
543 *
544 * REVISION
545 *
546 * Returns 0 on success or 1 on failure.
547 */
548static int
549rcsparse_textrevision(RCSFILE *rfp, struct rcs_pdata *pdp)
550{
551 struct rcs_delta *rdp;
552
553 TAILQ_FOREACH(rdp, &rfp->rf_delta, rd_list)for((rdp) = ((&rfp->rf_delta)->tqh_first); (rdp) !=
((void *)0); (rdp) = ((rdp)->rd_list.tqe_next))
{
554 if (rcsnum_cmp(rdp->rd_num, pdp->rp_value.rev, 0) == 0)
555 break;
556 }
557 if (rdp == NULL((void *)0)) {
558 rcsparse_warnx(rfp, "delta for revision \"%s\" not found",
559 pdp->rp_buf);
560 free(pdp->rp_value.rev);
561 return (1);
562 }
563 pdp->rp_delta = rdp;
564
565 free(pdp->rp_value.rev);
566 return (0);
567}
568
569/*
570 * rcsparse_log()
571 *
572 * Parses the specified log of current deltatext pdp->rp_delta.
573 *
574 * log @[...]@
575 *
576 * Returns 0 on success or 1 on failure.
577 */
578static int
579rcsparse_log(RCSFILE *rfp, struct rcs_pdata *pdp)
580{
581 if (rcsparse_token(rfp, RCS_TYPE_STRING(1 << 20)) != RCS_TYPE_STRING(1 << 20))
582 return (1);
583
584 pdp->rp_delta->rd_log = pdp->rp_value.str;
585
586 return (0);
587}
588
589/*
590 * rcsparse_text()
591 *
592 * Parses the specified text of current deltatext pdp->rp_delta.
593 *
594 * text @[...]@
595 *
596 * Returns 0 on success or 1 on failure.
597 */
598static int
599rcsparse_text(RCSFILE *rfp, struct rcs_pdata *pdp)
600{
601 if (rcsparse_token(rfp, RCS_TYPE_STRING(1 << 20)) != RCS_TYPE_STRING(1 << 20))
602 return (1);
603
604 pdp->rp_delta->rd_tlen = pdp->rp_tlen - 1;
605 if (pdp->rp_delta->rd_tlen == 0) {
606 pdp->rp_delta->rd_text = xstrdup("");
607 } else {
608 pdp->rp_delta->rd_text = xmalloc(pdp->rp_delta->rd_tlen);
609 memcpy(pdp->rp_delta->rd_text, pdp->rp_buf,
610 pdp->rp_delta->rd_tlen);
611 }
612 free(pdp->rp_value.str);
613
614 return (0);
615}
616
617/*
618 * rcsparse_head()
619 *
620 * Parses the head revision of RCS file <rfp>.
621 *
622 * head [REVISION];
623 *
624 * Returns 0 on success or 1 on failure.
625 */
626static int
627rcsparse_head(RCSFILE *rfp, struct rcs_pdata *pdp)
628{
629 int type;
630
631 type = rcsparse_token(rfp, RCS_TYPE_REVISION(1 << 23)|RCS_TOK_SCOLON(1 << 19));
632 if (type == RCS_TYPE_REVISION(1 << 23)) {
633 rfp->rf_head = pdp->rp_value.rev;
634 type = rcsparse_token(rfp, RCS_TOK_SCOLON(1 << 19));
635 }
636
637 return (type != RCS_TOK_SCOLON(1 << 19));
638}
639
640/*
641 * rcsparse_branch()
642 *
643 * Parses the default branch of RCS file <rfp>. The branch keyword is
644 * optional and can be omitted.
645 *
646 * [branch BRANCH;]
647 *
648 * Returns 0 on success or 1 on failure.
649 */
650static int
651rcsparse_branch(RCSFILE *rfp, struct rcs_pdata *pdp)
652{
653 int type;
654
655 type = rcsparse_token(rfp, RCS_TYPE_BRANCH(1 << 22)|RCS_TOK_SCOLON(1 << 19));
656 if (type == RCS_TYPE_BRANCH(1 << 22)) {
657 rfp->rf_branch = pdp->rp_value.rev;
658 type = rcsparse_token(rfp, RCS_TOK_SCOLON(1 << 19));
659 }
660
661 return (type != RCS_TOK_SCOLON(1 << 19));
662}
663
664/*
665 * rcsparse_access()
666 *
667 * Parses the access list of RCS file <rfp>.
668 *
669 * access [LOGIN ...];
670 *
671 * Returns 0 on success or 1 on failure.
672 */
673static int
674rcsparse_access(RCSFILE *rfp, struct rcs_pdata *pdp)
675{
676 struct rcs_access *ap;
677 int type;
678
679 while ((type = rcsparse_token(rfp, RCS_TOK_SCOLON(1 << 19)|RCS_TYPE_LOGIN(1 << 24)))
680 == RCS_TYPE_LOGIN(1 << 24)) {
681 ap = xmalloc(sizeof(*ap));
682 ap->ra_name = pdp->rp_value.str;
683 TAILQ_INSERT_TAIL(&(rfp->rf_access), ap, ra_list)do { (ap)->ra_list.tqe_next = ((void *)0); (ap)->ra_list
.tqe_prev = (&(rfp->rf_access))->tqh_last; *(&(
rfp->rf_access))->tqh_last = (ap); (&(rfp->rf_access
))->tqh_last = &(ap)->ra_list.tqe_next; } while (0)
;
684 }
685
686 return (type != RCS_TOK_SCOLON(1 << 19));
687}
688
689/*
690 * rcsparse_symbols()
691 *
692 * Parses the symbol list of RCS file <rfp>.
693 *
694 * symbols [SYMBOL:REVISION ...];
695 *
696 * Returns 0 on success or 1 on failure.
697 */
698static int
699rcsparse_symbols(RCSFILE *rfp, struct rcs_pdata *pdp)
700{
701 struct rcs_sym *symp;
702 char *name;
703 int type;
704
705 while ((type = rcsparse_token(rfp, RCS_TOK_SCOLON(1 << 19)|RCS_TYPE_SYMBOL(1 << 26))) ==
706 RCS_TYPE_SYMBOL(1 << 26)) {
707 name = pdp->rp_value.str;
708 if (rcsparse_token(rfp, RCS_TOK_COLON(1 << 17)) != RCS_TOK_COLON(1 << 17) ||
709 rcsparse_token(rfp, RCS_TYPE_NUMBER(1 << 21)) != RCS_TYPE_NUMBER(1 << 21)) {
710 free(name);
711 return (1);
712 }
713 symp = xmalloc(sizeof(*symp));
714 symp->rs_name = name;
715 symp->rs_num = pdp->rp_value.rev;
716 TAILQ_INSERT_TAIL(&(rfp->rf_symbols), symp, rs_list)do { (symp)->rs_list.tqe_next = ((void *)0); (symp)->rs_list
.tqe_prev = (&(rfp->rf_symbols))->tqh_last; *(&
(rfp->rf_symbols))->tqh_last = (symp); (&(rfp->rf_symbols
))->tqh_last = &(symp)->rs_list.tqe_next; } while (
0)
;
717 }
718
719 return (type != RCS_TOK_SCOLON(1 << 19));
720}
721
722/*
723 * rcsparse_locks()
724 *
725 * Parses the lock list of RCS file <rfp>.
726 *
727 * locks [SYMBOL:REVISION ...];
728 *
729 * Returns 0 on success or 1 on failure.
730 */
731static int
732rcsparse_locks(RCSFILE *rfp, struct rcs_pdata *pdp)
733{
734 struct rcs_lock *lkp;
735 char *name;
736 int type;
737
738 while ((type = rcsparse_token(rfp, RCS_TOK_SCOLON(1 << 19)|RCS_TYPE_LOGIN(1 << 24))) ==
739 RCS_TYPE_LOGIN(1 << 24)) {
740 name = pdp->rp_value.str;
741 if (rcsparse_token(rfp, RCS_TOK_COLON(1 << 17)) != RCS_TOK_COLON(1 << 17) ||
742 rcsparse_token(rfp, RCS_TYPE_REVISION(1 << 23)) !=
743 RCS_TYPE_REVISION(1 << 23)) {
744 free(name);
745 return (1);
746 }
747 lkp = xmalloc(sizeof(*lkp));
748 lkp->rl_name = name;
749 lkp->rl_num = pdp->rp_value.rev;
750 TAILQ_INSERT_TAIL(&(rfp->rf_locks), lkp, rl_list)do { (lkp)->rl_list.tqe_next = ((void *)0); (lkp)->rl_list
.tqe_prev = (&(rfp->rf_locks))->tqh_last; *(&(rfp
->rf_locks))->tqh_last = (lkp); (&(rfp->rf_locks
))->tqh_last = &(lkp)->rl_list.tqe_next; } while (0
)
;
751 }
752
753 return (type != RCS_TOK_SCOLON(1 << 19));
754}
755
756/*
757 * rcsparse_locks()
758 *
759 * Parses the strict keyword of RCS file <rfp>. The strict keyword is
760 * optional and can be omitted.
761 *
762 * [strict;]
763 *
764 * Returns 0 on success or 1 on failure.
765 */
766static int
767rcsparse_strict(RCSFILE *rfp, struct rcs_pdata *pdp)
768{
769 rfp->rf_flags |= RCS_SLOCK(1<<6);
770
771 return (rcsparse_token(rfp, RCS_TOK_SCOLON(1 << 19)) != RCS_TOK_SCOLON(1 << 19));
772}
773
774/*
775 * rcsparse_comment()
776 *
777 * Parses the comment of RCS file <rfp>. The comment keyword is optional
778 * and can be omitted.
779 *
780 * [comment [@[...]@];]
781 *
782 * Returns 0 on success or 1 on failure.
783 */
784static int
785rcsparse_comment(RCSFILE *rfp, struct rcs_pdata *pdp)
786{
787 int type;
788
789 type = rcsparse_token(rfp, RCS_TYPE_STRING(1 << 20)|RCS_TOK_SCOLON(1 << 19));
790 if (type == RCS_TYPE_STRING(1 << 20)) {
791 rfp->rf_comment = pdp->rp_value.str;
792 type = rcsparse_token(rfp, RCS_TOK_SCOLON(1 << 19));
793 }
794
795 return (type != RCS_TOK_SCOLON(1 << 19));
796}
797
798/*
799 * rcsparse_expand()
800 *
801 * Parses expand of RCS file <rfp>. The expand keyword is optional and
802 * can be omitted.
803 *
804 * [expand [@[...]@];]
805 *
806 * Returns 0 on success or 1 on failure.
807 */
808static int
809rcsparse_expand(RCSFILE *rfp, struct rcs_pdata *pdp)
810{
811 int type;
812
813 type = rcsparse_token(rfp, RCS_TYPE_STRING(1 << 20)|RCS_TOK_SCOLON(1 << 19));
814 if (type == RCS_TYPE_STRING(1 << 20)) {
815 rfp->rf_expand = pdp->rp_value.str;
816 type = rcsparse_token(rfp, RCS_TOK_SCOLON(1 << 19));
817 }
818
819 return (type != RCS_TOK_SCOLON(1 << 19));
820}
821
822#define RBUF_PUTC(ch)do { if (bp == pdp->rp_bufend - 1) { len = bp - pdp->rp_buf
; rcsparse_growbuf(rfp); bp = pdp->rp_buf + len; } *(bp++)
= (ch); pdp->rp_tlen++; } while (0);
\
823do { \
824 if (bp == pdp->rp_bufend - 1) { \
825 len = bp - pdp->rp_buf; \
826 rcsparse_growbuf(rfp); \
827 bp = pdp->rp_buf + len; \
828 } \
829 *(bp++) = (ch); \
830 pdp->rp_tlen++; \
831} while (0);
832
833static int
834rcsparse_string(RCSFILE *rfp, int allowed)
835{
836 struct rcs_pdata *pdp;
837 int c;
838 size_t len;
839 char *bp;
840
841 pdp = (struct rcs_pdata *)rfp->rf_pdata;
842
843 bp = pdp->rp_buf;
844 pdp->rp_tlen = 0;
845 *bp = '\0';
846
847 for (;;) {
848 c = getc(rfp->rf_file)(!__isthreaded ? (--(rfp->rf_file)->_r < 0 ? __srget
(rfp->rf_file) : (int)(*(rfp->rf_file)->_p++)) : (getc
)(rfp->rf_file))
;
849 if (c == '@') {
850 c = getc(rfp->rf_file)(!__isthreaded ? (--(rfp->rf_file)->_r < 0 ? __srget
(rfp->rf_file) : (int)(*(rfp->rf_file)->_p++)) : (getc
)(rfp->rf_file))
;
851 if (c == EOF(-1)) {
852 return (EOF(-1));
853 } else if (c != '@') {
854 ungetc(c, rfp->rf_file);
855 break;
856 }
857 }
858
859 if (c == EOF(-1)) {
860 return (EOF(-1));
861 } else if (c == '\n')
862 pdp->rp_lineno++;
863
864 RBUF_PUTC(c)do { if (bp == pdp->rp_bufend - 1) { len = bp - pdp->rp_buf
; rcsparse_growbuf(rfp); bp = pdp->rp_buf + len; } *(bp++)
= (c); pdp->rp_tlen++; } while (0);
;
865 }
866
867 bp = pdp->rp_buf + pdp->rp_tlen;
868 RBUF_PUTC('\0')do { if (bp == pdp->rp_bufend - 1) { len = bp - pdp->rp_buf
; rcsparse_growbuf(rfp); bp = pdp->rp_buf + len; } *(bp++)
= ('\0'); pdp->rp_tlen++; } while (0);
;
869
870 if (!(allowed & RCS_TYPE_STRING(1 << 20))) {
871 rcsparse_warnx(rfp, "unexpected RCS string");
872 return (0);
873 }
874
875 pdp->rp_value.str = xstrdup(pdp->rp_buf);
876
877 return (RCS_TYPE_STRING(1 << 20));
878}
879
880static int
881rcsparse_token(RCSFILE *rfp, int allowed)
882{
883 const struct rcs_keyword *p;
884 struct rcs_pdata *pdp;
885 int c, pre, ret, type;
886 char *bp;
887 size_t len;
888 RCSNUM *datenum;
889
890 pdp = (struct rcs_pdata *)rfp->rf_pdata;
891
892 if (pdp->rp_token != -1) {
893 /* no need to check for allowed here */
894 type = pdp->rp_token;
895 pdp->rp_token = -1;
896 return (type);
897 }
898
899 /* skip whitespaces */
900 c = EOF(-1);
901 do {
902 pre = c;
903 c = getc(rfp->rf_file)(!__isthreaded ? (--(rfp->rf_file)->_r < 0 ? __srget
(rfp->rf_file) : (int)(*(rfp->rf_file)->_p++)) : (getc
)(rfp->rf_file))
;
904 if (c == EOF(-1)) {
905 if (ferror(rfp->rf_file)(!__isthreaded ? (((rfp->rf_file)->_flags & 0x0040)
!= 0) : (ferror)(rfp->rf_file))
) {
906 rcsparse_warnx(rfp, "error during parsing");
907 return (0);
908 }
909 if (pre != '\n')
910 rcsparse_warnx(rfp,
911 "no newline at end of file");
912 return (EOF(-1));
913 } else if (c == '\n')
914 pdp->rp_lineno++;
915 } while (isspace(c));
916
917 pdp->rp_msglineno = pdp->rp_lineno;
918 type = 0;
919 switch (c) {
920 case '@':
921 ret = rcsparse_string(rfp, allowed);
922 if (ret == EOF(-1) && ferror(rfp->rf_file)(!__isthreaded ? (((rfp->rf_file)->_flags & 0x0040)
!= 0) : (ferror)(rfp->rf_file))
) {
923 rcsparse_warnx(rfp, "error during parsing");
924 return (0);
925 }
926 return (ret);
927 /* NOTREACHED */
928 case ':':
929 type = RCS_TOK_COLON(1 << 17);
930 if (type & allowed)
931 return (type);
932 rcsparse_warnx(rfp, "unexpected token \"%c\"", c);
933 return (0);
934 /* NOTREACHED */
935 case ';':
936 type = RCS_TOK_SCOLON(1 << 19);
937 if (type & allowed)
938 return (type);
939 rcsparse_warnx(rfp, "unexpected token \"%c\"", c);
940 return (0);
941 /* NOTREACHED */
942 case ',':
943 type = RCS_TOK_COMMA(1 << 18);
944 if (type & allowed)
945 return (type);
946 rcsparse_warnx(rfp, "unexpected token \"%c\"", c);
947 return (0);
948 /* NOTREACHED */
949 default:
950 if (!isgraph(c)) {
951 rcsparse_warnx(rfp, "unexpected character 0x%.2X", c);
952 return (0);
953 }
954 break;
955 }
956 allowed &= ~(RCS_TOK_COLON(1 << 17)|RCS_TOK_SCOLON(1 << 19)|RCS_TOK_COMMA(1 << 18));
957
958 bp = pdp->rp_buf;
959 pdp->rp_tlen = 0;
960 *bp = '\0';
961
962 for (;;) {
963 if (c == EOF(-1)) {
964 if (ferror(rfp->rf_file)(!__isthreaded ? (((rfp->rf_file)->_flags & 0x0040)
!= 0) : (ferror)(rfp->rf_file))
)
965 rcsparse_warnx(rfp, "error during parsing");
966 else
967 rcsparse_warnx(rfp, "unexpected end of file");
968 return (0);
969 } else if (c == '\n')
970 pdp->rp_lineno++;
971
972 RBUF_PUTC(c)do { if (bp == pdp->rp_bufend - 1) { len = bp - pdp->rp_buf
; rcsparse_growbuf(rfp); bp = pdp->rp_buf + len; } *(bp++)
= (c); pdp->rp_tlen++; } while (0);
;
973
974 c = getc(rfp->rf_file)(!__isthreaded ? (--(rfp->rf_file)->_r < 0 ? __srget
(rfp->rf_file) : (int)(*(rfp->rf_file)->_p++)) : (getc
)(rfp->rf_file))
;
975
976 if (isspace(c)) {
977 if (c == '\n')
978 pdp->rp_lineno++;
979 RBUF_PUTC('\0')do { if (bp == pdp->rp_bufend - 1) { len = bp - pdp->rp_buf
; rcsparse_growbuf(rfp); bp = pdp->rp_buf + len; } *(bp++)
= ('\0'); pdp->rp_tlen++; } while (0);
;
980 break;
981 } else if (c == ';' || c == ':' || c == ',') {
982 ungetc(c, rfp->rf_file);
983 RBUF_PUTC('\0')do { if (bp == pdp->rp_bufend - 1) { len = bp - pdp->rp_buf
; rcsparse_growbuf(rfp); bp = pdp->rp_buf + len; } *(bp++)
= ('\0'); pdp->rp_tlen++; } while (0);
;
984 break;
985 } else if (!isgraph(c)) {
986 rcsparse_warnx(rfp, "unexpected character 0x%.2X", c);
987 return (0);
988 }
989 }
990
991 switch (allowed) {
992 case RCS_TYPE_COMMITID(1 << 29):
993 if (!valid_commitid(pdp->rp_buf)) {
994 rcsparse_warnx(rfp, "invalid commitid \"%s\"",
995 pdp->rp_buf);
996 return (0);
997 }
998 pdp->rp_value.str = xstrdup(pdp->rp_buf);
999 break;
1000 case RCS_TYPE_LOGIN(1 << 24):
1001 if (!valid_login(pdp->rp_buf)) {
1002 rcsparse_warnx(rfp, "invalid login \"%s\"",
1003 pdp->rp_buf);
1004 return (0);
1005 }
1006 pdp->rp_value.str = xstrdup(pdp->rp_buf);
1007 break;
1008 case RCS_TYPE_SYMBOL(1 << 26):
1009 if (!rcs_sym_check(pdp->rp_buf)) {
1010 rcsparse_warnx(rfp, "invalid symbol \"%s\"",
1011 pdp->rp_buf);
1012 return (0);
1013 }
1014 pdp->rp_value.str = xstrdup(pdp->rp_buf);
1015 break;
1016 /* FALLTHROUGH */
1017 case RCS_TYPE_STATE(1 << 25):
1018 if (rcs_state_check(pdp->rp_buf)) {
1019 rcsparse_warnx(rfp, "invalid state \"%s\"",
1020 pdp->rp_buf);
1021 return (0);
1022 }
1023 pdp->rp_value.str = xstrdup(pdp->rp_buf);
1024 break;
1025 case RCS_TYPE_DATE(1 << 27):
1026 if ((datenum = rcsnum_parse(pdp->rp_buf)) == NULL((void *)0)) {
1027 rcsparse_warnx(rfp, "invalid date \"%s\"", pdp->rp_buf);
1028 return (0);
1029 }
1030 if (datenum->rn_len != 6) {
1031 free(datenum);
1032 rcsparse_warnx(rfp, "invalid date \"%s\"", pdp->rp_buf);
1033 return (0);
1034 }
1035 pdp->rp_value.date.tm_year = datenum->rn_id[0];
1036 if (pdp->rp_value.date.tm_year >= 1900)
1037 pdp->rp_value.date.tm_year -= 1900;
1038 pdp->rp_value.date.tm_mon = datenum->rn_id[1] - 1;
1039 pdp->rp_value.date.tm_mday = datenum->rn_id[2];
1040 pdp->rp_value.date.tm_hour = datenum->rn_id[3];
1041 pdp->rp_value.date.tm_min = datenum->rn_id[4];
1042 pdp->rp_value.date.tm_sec = datenum->rn_id[5];
1043 free(datenum);
1044 break;
1045 case RCS_TYPE_NUMBER(1 << 21):
1046 pdp->rp_value.rev = rcsnum_parse(pdp->rp_buf);
1047 if (pdp->rp_value.rev == NULL((void *)0)) {
1048 rcsparse_warnx(rfp, "invalid number \"%s\"",
1049 pdp->rp_buf);
1050 return (0);
1051 }
1052 break;
1053 case RCS_TYPE_BRANCH(1 << 22):
1054 pdp->rp_value.rev = rcsnum_parse(pdp->rp_buf);
1055 if (pdp->rp_value.rev == NULL((void *)0)) {
1056 rcsparse_warnx(rfp, "invalid branch \"%s\"",
1057 pdp->rp_buf);
1058 return (0);
1059 }
1060 if (!RCSNUM_ISBRANCH(pdp->rp_value.rev)((pdp->rp_value.rev)->rn_len % 2)) {
1061 free(pdp->rp_value.rev);
1062 rcsparse_warnx(rfp, "expected branch, got \"%s\"",
1063 pdp->rp_buf);
1064 return (0);
1065 }
1066 break;
1067 case RCS_TYPE_KEYWORD(1 << 28):
1068 if (islower(*pdp->rp_buf)) {
1069 p = bsearch(pdp->rp_buf, keywords,
1070 sizeof(keywords) / sizeof(keywords[0]),
1071 sizeof(keywords[0]), kw_cmp);
1072 if (p != NULL((void *)0))
1073 return (p->k_val);
1074 }
1075 allowed = RCS_TYPE_REVISION(1 << 23);
1076 /* FALLTHROUGH */
1077 case RCS_TYPE_REVISION(1 << 23):
1078 pdp->rp_value.rev = rcsnum_parse(pdp->rp_buf);
1079 if (pdp->rp_value.rev != NULL((void *)0)) {
1080 if (RCSNUM_ISBRANCH(pdp->rp_value.rev)((pdp->rp_value.rev)->rn_len % 2)) {
1081 free(pdp->rp_value.rev);
1082 rcsparse_warnx(rfp,
1083 "expected revision, got \"%s\"",
1084 pdp->rp_buf);
1085 return (0);
1086 }
1087 break;
1088 }
1089 /* FALLTHROUGH */
1090 default:
1091 RBUF_PUTC('\0')do { if (bp == pdp->rp_bufend - 1) { len = bp - pdp->rp_buf
; rcsparse_growbuf(rfp); bp = pdp->rp_buf + len; } *(bp++)
= ('\0'); pdp->rp_tlen++; } while (0);
;
1092 rcsparse_warnx(rfp, "unexpected token \"%s\"", pdp->rp_buf);
1093 return (0);
1094 /* NOTREACHED */
1095 }
1096
1097 return (allowed);
1098}
1099
1100static int
1101rcsparse(RCSFILE *rfp, struct rcs_section *sec)
1102{
1103 struct rcs_pdata *pdp;
1104 int i, token;
1105
1106 pdp = (struct rcs_pdata *)rfp->rf_pdata;
1107 i = 0;
Value stored to 'i' is never read
1108
1109 token = 0;
1110 for (i = 0; sec[i].token != 0; i++) {
1111 token = rcsparse_token(rfp, RCS_TYPE_KEYWORD(1 << 28));
1112 if (token == 0)
1113 return (1);
1114
1115 while (token != sec[i].token) {
1116 if (sec[i].parse == NULL((void *)0))
1117 goto end;
1118 if (sec[i].opt) {
1119 i++;
1120 continue;
1121 }
1122 if (token == EOF(-1) || (!(rfp->rf_flags & PARSED_DELTAS(1<<7)) &&
1123 token == RCS_TOK_DESC(1 << 9)))
1124 goto end;
1125 rcsparse_warnx(rfp, "unexpected token \"%s\"",
1126 pdp->rp_buf);
1127 return (1);
1128 }
1129
1130 if (sec[i].parse(rfp, pdp))
1131 return (1);
1132 }
1133end:
1134 if (token == RCS_TYPE_REVISION(1 << 23))
1135 pdp->rp_token = token;
1136 else if (token == RCS_TOK_DESC(1 << 9))
1137 pdp->rp_token = RCS_TOK_DESC(1 << 9);
1138 else if (token == EOF(-1))
1139 rfp->rf_flags |= RCS_PARSED(1<<4);
1140
1141 return (0);
1142}
1143
1144static int
1145rcsparse_deltatext(RCSFILE *rfp)
1146{
1147 int ret;
1148
1149 if (rfp->rf_flags & PARSED_DELTATEXTS(1<<9))
1150 return (0);
1151
1152 if (!(rfp->rf_flags & PARSED_DESC(1<<8)))
1153 if ((ret = rcsparse_desc(rfp)))
1154 return (ret);
1155
1156 if (rcsparse(rfp, sec_deltatext))
1157 return (-1);
1158
1159 if (rfp->rf_flags & RCS_PARSED(1<<4))
1160 rfp->rf_flags |= PARSED_DELTATEXTS(1<<9);
1161
1162 return (1);
1163}
1164
1165static int
1166rcsparse_delta(RCSFILE *rfp)
1167{
1168 struct rcs_pdata *pdp;
1169
1170 if (rfp->rf_flags & PARSED_DELTAS(1<<7))
1171 return (0);
1172
1173 pdp = (struct rcs_pdata *)rfp->rf_pdata;
1174 if (pdp->rp_token == RCS_TOK_DESC(1 << 9)) {
1175 rfp->rf_flags |= PARSED_DELTAS(1<<7);
1176 return (0);
1177 }
1178
1179 if (rcsparse(rfp, sec_delta))
1180 return (-1);
1181
1182 if (pdp->rp_delta != NULL((void *)0)) {
1183 TAILQ_INSERT_TAIL(&rfp->rf_delta, pdp->rp_delta, rd_list)do { (pdp->rp_delta)->rd_list.tqe_next = ((void *)0); (
pdp->rp_delta)->rd_list.tqe_prev = (&rfp->rf_delta
)->tqh_last; *(&rfp->rf_delta)->tqh_last = (pdp->
rp_delta); (&rfp->rf_delta)->tqh_last = &(pdp->
rp_delta)->rd_list.tqe_next; } while (0)
;
1184 pdp->rp_delta = NULL((void *)0);
1185 rfp->rf_ndelta++;
1186 return (1);
1187 }
1188
1189 return (0);
1190}
1191
1192/*
1193 * rcsparse_growbuf()
1194 *
1195 * Attempt to grow the internal parse buffer for the RCS file <rf> by
1196 * RCS_BUFEXTSIZE.
1197 * In case of failure, the original buffer is left unmodified.
1198 */
1199static void
1200rcsparse_growbuf(RCSFILE *rfp)
1201{
1202 struct rcs_pdata *pdp = (struct rcs_pdata *)rfp->rf_pdata;
1203
1204 pdp->rp_buf = xreallocarray(pdp->rp_buf, 1,
1205 pdp->rp_blen + RCS_BUFEXTSIZE8192);
1206 pdp->rp_blen += RCS_BUFEXTSIZE8192;
1207 pdp->rp_bufend = pdp->rp_buf + pdp->rp_blen - 1;
1208}
1209
1210/*
1211 * Borrowed from src/usr.sbin/user/user.c:
1212 * return 1 if `login' is a valid login name
1213 */
1214static int
1215valid_login(char *login_name)
1216{
1217 unsigned char *cp;
1218
1219 /* The first character cannot be a hyphen */
1220 if (*login_name == '-')
1221 return 0;
1222
1223 for (cp = login_name ; *cp ; cp++) {
1224 /* We allow '$' as the last character for samba */
1225 if (!isalnum(*cp) && *cp != '.' && *cp != '_' && *cp != '-' &&
1226 !(*cp == '$' && *(cp + 1) == '\0')) {
1227 return 0;
1228 }
1229 }
1230 if ((char *)cp - login_name > _PW_NAME_LEN31)
1231 return 0;
1232 return 1;
1233}
1234
1235static int
1236valid_commitid(char *commitid)
1237{
1238 unsigned char *cp;
1239
1240 /* A-Za-z0-9 */
1241 for (cp = commitid; *cp ; cp++) {
1242 if (!isalnum(*cp))
1243 return 0;
1244 }
1245 if ((char *)cp - commitid > RCS_COMMITID_MAXLEN64)
1246 return 0;
1247 return 1;
1248}
1249
1250static int
1251kw_cmp(const void *k, const void *e)
1252{
1253 return (strcmp(k, ((const struct rcs_keyword *)e)->k_name));
1254}
1255
1256static void
1257rcsparse_warnx(RCSFILE *rfp, char *fmt, ...)
1258{
1259 struct rcs_pdata *pdp;
1260 va_list ap;
1261 char *msg;
1262
1263 pdp = (struct rcs_pdata *)rfp->rf_pdata;
1264 va_start(ap, fmt)__builtin_va_start(ap, fmt);
1265 if (vasprintf(&msg, fmt, ap) == -1) {
1266 cvs_log(LP_ERRNO2, "vasprintf");
1267 va_end(ap)__builtin_va_end(ap);
1268 return;
1269 }
1270 va_end(ap)__builtin_va_end(ap);
1271 cvs_log(LP_ERR1, "%s:%d: %s", rfp->rf_path, pdp->rp_msglineno, msg);
1272 free(msg);
1273}