GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/rcs/rcsparse.c Lines: 0 399 0.0 %
Date: 2016-12-06 Branches: 0 287 0.0 %

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