GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/rcs/rcsparse.c Lines: 297 437 68.0 %
Date: 2017-11-07 Branches: 178 297 59.9 %

Line Branch Exec Source
1
/*	$OpenBSD: rcsparse.c,v 1.16 2016/08/26 09:02:54 guenther 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 <time.h>
28
#include <unistd.h>
29
30
#include "rcs.h"
31
#include "rcsparse.h"
32
#include "xmalloc.h"
33
34
#define RCS_BUFSIZE	16384
35
#define RCS_BUFEXTSIZE	8192
36
37
/* RCS token types */
38
#define RCS_TOK_HEAD		(1 << 0)
39
#define RCS_TOK_BRANCH		(1 << 1)
40
#define RCS_TOK_ACCESS		(1 << 2)
41
#define RCS_TOK_SYMBOLS		(1 << 3)
42
#define RCS_TOK_LOCKS		(1 << 4)
43
#define RCS_TOK_STRICT		(1 << 5)
44
#define RCS_TOK_COMMENT		(1 << 6)
45
#define RCS_TOK_COMMITID	(1 << 7)
46
#define RCS_TOK_EXPAND		(1 << 8)
47
#define RCS_TOK_DESC		(1 << 9)
48
#define RCS_TOK_DATE		(1 << 10)
49
#define RCS_TOK_AUTHOR		(1 << 11)
50
#define RCS_TOK_STATE		(1 << 12)
51
#define RCS_TOK_BRANCHES	(1 << 13)
52
#define RCS_TOK_NEXT		(1 << 14)
53
#define RCS_TOK_LOG		(1 << 15)
54
#define RCS_TOK_TEXT		(1 << 16)
55
#define RCS_TOK_COLON		(1 << 17)
56
#define RCS_TOK_COMMA		(1 << 18)
57
#define RCS_TOK_SCOLON		(1 << 19)
58
59
#define RCS_TYPE_STRING		(1 << 20)
60
#define RCS_TYPE_NUMBER		(1 << 21)
61
#define RCS_TYPE_BRANCH		(1 << 22)
62
#define RCS_TYPE_REVISION	(1 << 23)
63
#define RCS_TYPE_LOGIN		(1 << 24)
64
#define RCS_TYPE_STATE		(1 << 25)
65
#define RCS_TYPE_SYMBOL		(1 << 26)
66
#define RCS_TYPE_DATE		(1 << 27)
67
#define RCS_TYPE_KEYWORD	(1 << 28)
68
#define RCS_TYPE_COMMITID	(1 << 29)
69
70
#define MANDATORY	0
71
#define OPTIONAL	1
72
73
/* opaque parse data */
74
struct 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
92
struct rcs_keyword {
93
	const char	*k_name;
94
	int		 k_val;
95
};
96
97
struct rcs_section {
98
	int	token;
99
	int	(*parse)(RCSFILE *, struct rcs_pdata *);
100
	int	opt;
101
};
102
103
/* this has to be sorted always */
104
static const struct rcs_keyword keywords[] = {
105
	{ "access",		RCS_TOK_ACCESS},
106
	{ "author",		RCS_TOK_AUTHOR},
107
	{ "branch",		RCS_TOK_BRANCH},
108
	{ "branches",		RCS_TOK_BRANCHES},
109
	{ "comment",		RCS_TOK_COMMENT},
110
	{ "commitid",		RCS_TOK_COMMITID},
111
	{ "date",		RCS_TOK_DATE},
112
	{ "desc",		RCS_TOK_DESC},
113
	{ "expand",		RCS_TOK_EXPAND},
114
	{ "head",		RCS_TOK_HEAD},
115
	{ "locks",		RCS_TOK_LOCKS},
116
	{ "log",		RCS_TOK_LOG},
117
	{ "next",		RCS_TOK_NEXT},
118
	{ "state",		RCS_TOK_STATE},
119
	{ "strict",		RCS_TOK_STRICT},
120
	{ "symbols",		RCS_TOK_SYMBOLS},
121
	{ "text",		RCS_TOK_TEXT}
122
};
123
124
/* parser functions specified in rcs_section structs */
125
static int	rcsparse_head(RCSFILE *, struct rcs_pdata *);
126
static int	rcsparse_branch(RCSFILE *, struct rcs_pdata *);
127
static int	rcsparse_access(RCSFILE *, struct rcs_pdata *);
128
static int	rcsparse_symbols(RCSFILE *, struct rcs_pdata *);
129
static int	rcsparse_locks(RCSFILE *, struct rcs_pdata *);
130
static int	rcsparse_strict(RCSFILE *, struct rcs_pdata *);
131
static int	rcsparse_comment(RCSFILE *, struct rcs_pdata *);
132
static int	rcsparse_commitid(RCSFILE *, struct rcs_pdata *);
133
static int	rcsparse_expand(RCSFILE *, struct rcs_pdata *);
134
static int	rcsparse_deltarevision(RCSFILE *, struct rcs_pdata *);
135
static int	rcsparse_date(RCSFILE *, struct rcs_pdata *);
136
static int	rcsparse_author(RCSFILE *, struct rcs_pdata *);
137
static int	rcsparse_state(RCSFILE *, struct rcs_pdata *);
138
static int	rcsparse_branches(RCSFILE *, struct rcs_pdata *);
139
static int	rcsparse_next(RCSFILE *, struct rcs_pdata *);
140
static int	rcsparse_textrevision(RCSFILE *, struct rcs_pdata *);
141
static int	rcsparse_log(RCSFILE *, struct rcs_pdata *);
142
static int	rcsparse_text(RCSFILE *, struct rcs_pdata *);
143
144
static int	rcsparse_delta(RCSFILE *);
145
static int	rcsparse_deltatext(RCSFILE *);
146
static int	rcsparse_desc(RCSFILE *);
147
148
static int	kw_cmp(const void *, const void *);
149
static int	rcsparse(RCSFILE *, struct rcs_section *);
150
static void	rcsparse_growbuf(RCSFILE *);
151
static int	rcsparse_string(RCSFILE *, int);
152
static int	rcsparse_token(RCSFILE *, int);
153
static void	rcsparse_warnx(RCSFILE *, char *, ...);
154
static int	valid_login(char *);
155
static 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
 */
167
static struct rcs_section sec_admin[] = {
168
	{ RCS_TOK_HEAD, rcsparse_head, MANDATORY },
169
	{ RCS_TOK_BRANCH, rcsparse_branch, OPTIONAL },
170
	{ RCS_TOK_ACCESS, rcsparse_access, MANDATORY },
171
	{ RCS_TOK_SYMBOLS, rcsparse_symbols, MANDATORY },
172
	{ RCS_TOK_LOCKS, rcsparse_locks, MANDATORY },
173
	{ RCS_TOK_STRICT, rcsparse_strict, OPTIONAL },
174
	{ RCS_TOK_COMMENT, rcsparse_comment, OPTIONAL },
175
	{ RCS_TOK_EXPAND, rcsparse_expand, OPTIONAL },
176
	{ 0, NULL, 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
 */
188
static struct rcs_section sec_delta[] = {
189
	{ RCS_TYPE_REVISION, rcsparse_deltarevision, MANDATORY },
190
	{ RCS_TOK_DATE, rcsparse_date, MANDATORY },
191
	{ RCS_TOK_AUTHOR, rcsparse_author, MANDATORY },
192
	{ RCS_TOK_STATE, rcsparse_state, MANDATORY },
193
	{ RCS_TOK_BRANCHES, rcsparse_branches, MANDATORY },
194
	{ RCS_TOK_NEXT, rcsparse_next, MANDATORY },
195
	{ RCS_TOK_COMMITID, rcsparse_commitid, OPTIONAL },
196
	{ 0, NULL, 0 }
197
};
198
199
/*
200
 * REVISION
201
 * log @[...]@
202
 * text @[...]@
203
 */
204
static struct rcs_section sec_deltatext[] = {
205
	{ RCS_TYPE_REVISION, rcsparse_textrevision, MANDATORY },
206
	{ RCS_TOK_LOG, rcsparse_log, MANDATORY },
207
	{ RCS_TOK_TEXT, rcsparse_text, MANDATORY },
208
	{ 0, NULL, 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
 */
219
int
220
rcsparse_init(RCSFILE *rfp)
221
{
222
	struct rcs_pdata *pdp;
223
224
250
	if (rfp->rf_flags & RCS_PARSED)
225
		return (0);
226
227
125
	pdp = xcalloc(1, sizeof(*pdp));
228
125
	pdp->rp_buf = xmalloc(RCS_BUFSIZE);
229
125
	pdp->rp_blen = RCS_BUFSIZE;
230
125
	pdp->rp_bufend = pdp->rp_buf + pdp->rp_blen - 1;
231
125
	pdp->rp_token = -1;
232
125
	pdp->rp_lineno = 1;
233
125
	pdp->rp_msglineno = 1;
234
235
	/* ditch the strict lock */
236
125
	rfp->rf_flags &= ~RCS_SLOCK;
237
125
	rfp->rf_pdata = pdp;
238
239
125
	if (rcsparse(rfp, sec_admin)) {
240
		rcsparse_free(rfp);
241
		return (1);
242
	}
243
244

240
	if ((rfp->rf_flags & RCS_PARSE_FULLY) &&
245
115
	    rcsparse_deltatexts(rfp, NULL)) {
246
1
		rcsparse_free(rfp);
247
1
		return (1);
248
	}
249
250
124
	rfp->rf_flags |= RCS_SYNCED;
251
124
	return (0);
252
125
}
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
 */
262
int
263
rcsparse_deltas(RCSFILE *rfp, RCSNUM *rev)
264
{
265
	int ret;
266
	struct rcs_delta *enddelta;
267
268

635
	if ((rfp->rf_flags & PARSED_DELTAS) || (rfp->rf_flags & RCS_CREATE))
269
116
		return (0);
270
271
	for (;;) {
272
384
		ret = rcsparse_delta(rfp);
273
384
		if (rev != NULL) {
274
6
			enddelta = TAILQ_LAST(&(rfp->rf_delta), rcs_dlist);
275
6
			if (enddelta == NULL)
276
				return (1);
277
278
6
			if (rcsnum_cmp(enddelta->rd_num, rev, 0) == 0)
279
				break;
280
		}
281
282
378
		if (ret == 0) {
283
124
			rfp->rf_flags |= PARSED_DELTAS;
284
124
			break;
285
		}
286
254
		else if (ret == -1)
287
			return (1);
288
	}
289
290
130
	return (0);
291
246
}
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
 */
301
int
302
rcsparse_deltatexts(RCSFILE *rfp, RCSNUM *rev)
303
{
304
	int ret;
305
	struct rcs_delta *rdp;
306
307

922
	if ((rfp->rf_flags & PARSED_DELTATEXTS) ||
308
216
	    (rfp->rf_flags & RCS_CREATE))
309
224
		return (0);
310
311
129
	if (!(rfp->rf_flags & PARSED_DESC))
312
124
		if (rcsparse_desc(rfp))
313
			return (1);
314
315
271
	rdp = (rev != NULL) ? rcs_findrev(rfp, rev) : NULL;
316
317
129
	for (;;) {
318

529
		if (rdp != NULL && rdp->rd_text != NULL)
319
			break;
320
490
		ret = rcsparse_deltatext(rfp);
321
490
		if (ret == 0) {
322
115
			rfp->rf_flags |= PARSED_DELTATEXTS;
323
115
			break;
324
		}
325
375
		else if (ret == -1)
326
1
			return (1);
327
	}
328
329
128
	return (0);
330
353
}
331
332
/*
333
 * rcsparse_free()
334
 *
335
 * Free the contents of the <rfp>'s parser data structure.
336
 */
337
void
338
rcsparse_free(RCSFILE *rfp)
339
{
340
	struct rcs_pdata *pdp;
341
342
242
	pdp = rfp->rf_pdata;
343
344
121
	free(pdp->rp_buf);
345
121
	if (pdp->rp_token == RCS_TYPE_REVISION)
346
		rcsnum_free(pdp->rp_value.rev);
347
121
	free(pdp);
348
121
}
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
 */
360
static int
361
rcsparse_desc(RCSFILE *rfp)
362
{
363
	struct rcs_pdata *pdp;
364
365
248
	if (rfp->rf_flags & PARSED_DESC)
366
		return (0);
367
368

239
	if (!(rfp->rf_flags & PARSED_DELTAS) && rcsparse_deltas(rfp, NULL))
369
		return (1);
370
371
124
	pdp = (struct rcs_pdata *)rfp->rf_pdata;
372
373

248
	if (rcsparse_token(rfp, RCS_TOK_DESC) != RCS_TOK_DESC ||
374
124
	    rcsparse_token(rfp, RCS_TYPE_STRING) != RCS_TYPE_STRING)
375
		return (1);
376
377
124
	rfp->rf_desc = pdp->rp_value.str;
378
124
	rfp->rf_flags |= PARSED_DESC;
379
380
124
	return (0);
381
124
}
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
 */
394
static int
395
rcsparse_deltarevision(RCSFILE *rfp, struct rcs_pdata *pdp)
396
{
397
	struct rcs_delta *rdp;
398
399
520
	rdp = xcalloc(1, sizeof(*rdp));
400
260
	TAILQ_INIT(&rdp->rd_branches);
401
260
	rdp->rd_num = pdp->rp_value.rev;
402
260
	pdp->rp_delta = rdp;
403
404
260
	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
 */
416
static int
417
rcsparse_date(RCSFILE *rfp, struct rcs_pdata *pdp)
418
{
419
520
	if (rcsparse_token(rfp, RCS_TYPE_DATE) != RCS_TYPE_DATE)
420
		return (1);
421
422
260
	pdp->rp_delta->rd_date = pdp->rp_value.date;
423
424
260
	return (rcsparse_token(rfp, RCS_TOK_SCOLON) != RCS_TOK_SCOLON);
425
260
}
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
 */
436
static int
437
rcsparse_author(RCSFILE *rfp, struct rcs_pdata *pdp)
438
{
439
520
	if (rcsparse_token(rfp, RCS_TYPE_LOGIN) != RCS_TYPE_LOGIN)
440
		return (1);
441
442
260
	pdp->rp_delta->rd_author = pdp->rp_value.str;
443
444
260
	return (rcsparse_token(rfp, RCS_TOK_SCOLON) != RCS_TOK_SCOLON);
445
260
}
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
 */
456
static int
457
rcsparse_state(RCSFILE *rfp, struct rcs_pdata *pdp)
458
{
459
520
	if (rcsparse_token(rfp, RCS_TYPE_STATE) != RCS_TYPE_STATE)
460
		return (1);
461
462
260
	pdp->rp_delta->rd_state = pdp->rp_value.str;
463
464
260
	return (rcsparse_token(rfp, RCS_TOK_SCOLON) != RCS_TOK_SCOLON);
465
260
}
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
 */
476
static int
477
rcsparse_branches(RCSFILE *rfp, struct rcs_pdata *pdp)
478
{
479
	struct rcs_branch *rb;
480
	int type;
481
482
1040
	while ((type = rcsparse_token(rfp, RCS_TOK_SCOLON|RCS_TYPE_REVISION))
483
260
	    == RCS_TYPE_REVISION) {
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);
487
	}
488
489
260
	return (type != RCS_TOK_SCOLON);
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
 */
501
static int
502
rcsparse_next(RCSFILE *rfp, struct rcs_pdata *pdp)
503
{
504
	int type;
505
506
520
	type = rcsparse_token(rfp, RCS_TYPE_REVISION|RCS_TOK_SCOLON);
507
260
	if (type == RCS_TYPE_REVISION) {
508
149
		pdp->rp_delta->rd_next = pdp->rp_value.rev;
509
149
		type = rcsparse_token(rfp, RCS_TOK_SCOLON);
510
149
	} else
511
111
		pdp->rp_delta->rd_next = rcsnum_alloc();
512
513
260
	return (type != RCS_TOK_SCOLON);
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
 */
526
static int
527
rcsparse_commitid(RCSFILE *rfp, struct rcs_pdata *pdp)
528
{
529
	if (rcsparse_token(rfp, RCS_TYPE_COMMITID) != RCS_TYPE_COMMITID)
530
		return (1);
531
532
	pdp->rp_delta->rd_commitid = pdp->rp_value.str;
533
534
	return (rcsparse_token(rfp, RCS_TOK_SCOLON) != RCS_TOK_SCOLON);
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
 */
548
static int
549
rcsparse_textrevision(RCSFILE *rfp, struct rcs_pdata *pdp)
550
{
551
	struct rcs_delta *rdp;
552
553
1550
	TAILQ_FOREACH(rdp, &rfp->rf_delta, rd_list) {
554
645
		if (rcsnum_cmp(rdp->rd_num, pdp->rp_value.rev, 0) == 0)
555
			break;
556
	}
557
260
	if (rdp == NULL) {
558
		rcsparse_warnx(rfp, "delta for revision \"%s\" not found",
559
		    pdp->rp_buf);
560
		rcsnum_free(pdp->rp_value.rev);
561
		return (1);
562
	}
563
260
	pdp->rp_delta = rdp;
564
565
260
	rcsnum_free(pdp->rp_value.rev);
566
260
	return (0);
567
260
}
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
 */
578
static int
579
rcsparse_log(RCSFILE *rfp, struct rcs_pdata *pdp)
580
{
581
520
	if (rcsparse_token(rfp, RCS_TYPE_STRING) != RCS_TYPE_STRING)
582
		return (1);
583
584
260
	pdp->rp_delta->rd_log = pdp->rp_value.str;
585
586
260
	return (0);
587
260
}
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
 */
598
static int
599
rcsparse_text(RCSFILE *rfp, struct rcs_pdata *pdp)
600
{
601
520
	if (rcsparse_token(rfp, RCS_TYPE_STRING) != RCS_TYPE_STRING)
602
1
		return (1);
603
604
259
	pdp->rp_delta->rd_tlen = pdp->rp_tlen - 1;
605
259
	if (pdp->rp_delta->rd_tlen == 0) {
606
20
		pdp->rp_delta->rd_text = xstrdup("");
607
20
	} else {
608
239
		pdp->rp_delta->rd_text = xmalloc(pdp->rp_delta->rd_tlen);
609
478
		memcpy(pdp->rp_delta->rd_text, pdp->rp_buf,
610
239
		    pdp->rp_delta->rd_tlen);
611
	}
612
259
	free(pdp->rp_value.str);
613
614
259
	return (0);
615
260
}
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
 */
626
static int
627
rcsparse_head(RCSFILE *rfp, struct rcs_pdata *pdp)
628
{
629
	int type;
630
631
250
	type = rcsparse_token(rfp, RCS_TYPE_REVISION|RCS_TOK_SCOLON);
632
125
	if (type == RCS_TYPE_REVISION) {
633
111
		rfp->rf_head = pdp->rp_value.rev;
634
111
		type = rcsparse_token(rfp, RCS_TOK_SCOLON);
635
111
	}
636
637
125
	return (type != RCS_TOK_SCOLON);
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
 */
650
static int
651
rcsparse_branch(RCSFILE *rfp, struct rcs_pdata *pdp)
652
{
653
	int type;
654
655
	type = rcsparse_token(rfp, RCS_TYPE_BRANCH|RCS_TOK_SCOLON);
656
	if (type == RCS_TYPE_BRANCH) {
657
		rfp->rf_branch = pdp->rp_value.rev;
658
		type = rcsparse_token(rfp, RCS_TOK_SCOLON);
659
	}
660
661
	return (type != RCS_TOK_SCOLON);
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
 */
673
static int
674
rcsparse_access(RCSFILE *rfp, struct rcs_pdata *pdp)
675
{
676
	struct rcs_access *ap;
677
	int type;
678
679
554
	while ((type = rcsparse_token(rfp, RCS_TOK_SCOLON|RCS_TYPE_LOGIN))
680
143
	    == RCS_TYPE_LOGIN) {
681
18
		ap = xmalloc(sizeof(*ap));
682
18
		ap->ra_name = pdp->rp_value.str;
683
18
		TAILQ_INSERT_TAIL(&(rfp->rf_access), ap, ra_list);
684
	}
685
686
125
	return (type != RCS_TOK_SCOLON);
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
 */
698
static int
699
rcsparse_symbols(RCSFILE *rfp, struct rcs_pdata *pdp)
700
{
701
	struct rcs_sym *symp;
702
	char *name;
703
	int type;
704
705
427
	while ((type = rcsparse_token(rfp, RCS_TOK_SCOLON|RCS_TYPE_SYMBOL)) ==
706
	    RCS_TYPE_SYMBOL) {
707
26
		name = pdp->rp_value.str;
708

52
		if (rcsparse_token(rfp, RCS_TOK_COLON) != RCS_TOK_COLON ||
709
26
		    rcsparse_token(rfp, RCS_TYPE_NUMBER) != RCS_TYPE_NUMBER) {
710
			free(name);
711
			return (1);
712
		}
713
26
		symp = xmalloc(sizeof(*symp));
714
26
		symp->rs_name = name;
715
26
		symp->rs_num = pdp->rp_value.rev;
716
26
		TAILQ_INSERT_TAIL(&(rfp->rf_symbols), symp, rs_list);
717
	}
718
719
125
	return (type != RCS_TOK_SCOLON);
720
125
}
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
 */
731
static int
732
rcsparse_locks(RCSFILE *rfp, struct rcs_pdata *pdp)
733
{
734
	struct rcs_lock *lkp;
735
	char *name;
736
	int type;
737
738
509
	while ((type = rcsparse_token(rfp, RCS_TOK_SCOLON|RCS_TYPE_LOGIN)) ==
739
	    RCS_TYPE_LOGIN) {
740
67
		name = pdp->rp_value.str;
741

134
		if (rcsparse_token(rfp, RCS_TOK_COLON) != RCS_TOK_COLON ||
742
67
		    rcsparse_token(rfp, RCS_TYPE_REVISION) !=
743
		    RCS_TYPE_REVISION) {
744
			free(name);
745
			return (1);
746
		}
747
67
		lkp = xmalloc(sizeof(*lkp));
748
67
		lkp->rl_name = name;
749
67
		lkp->rl_num = pdp->rp_value.rev;
750
67
		TAILQ_INSERT_TAIL(&(rfp->rf_locks), lkp, rl_list);
751
	}
752
753
125
	return (type != RCS_TOK_SCOLON);
754
125
}
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
 */
766
static int
767
rcsparse_strict(RCSFILE *rfp, struct rcs_pdata *pdp)
768
{
769
250
	rfp->rf_flags |= RCS_SLOCK;
770
771
125
	return (rcsparse_token(rfp, RCS_TOK_SCOLON) != RCS_TOK_SCOLON);
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
 */
784
static int
785
rcsparse_comment(RCSFILE *rfp, struct rcs_pdata *pdp)
786
{
787
	int type;
788
789
250
	type = rcsparse_token(rfp, RCS_TYPE_STRING|RCS_TOK_SCOLON);
790
125
	if (type == RCS_TYPE_STRING) {
791
125
		rfp->rf_comment = pdp->rp_value.str;
792
125
		type = rcsparse_token(rfp, RCS_TOK_SCOLON);
793
125
	}
794
795
125
	return (type != RCS_TOK_SCOLON);
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
 */
808
static int
809
rcsparse_expand(RCSFILE *rfp, struct rcs_pdata *pdp)
810
{
811
	int type;
812
813
	type = rcsparse_token(rfp, RCS_TYPE_STRING|RCS_TOK_SCOLON);
814
	if (type == RCS_TYPE_STRING) {
815
		rfp->rf_expand = pdp->rp_value.str;
816
		type = rcsparse_token(rfp, RCS_TOK_SCOLON);
817
	}
818
819
	return (type != RCS_TOK_SCOLON);
820
}
821
822
#define RBUF_PUTC(ch) \
823
do { \
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
833
static int
834
rcsparse_string(RCSFILE *rfp, int allowed)
835
{
836
	struct rcs_pdata *pdp;
837
	int c;
838
	size_t len;
839
	char *bp;
840
841
1538
	pdp = (struct rcs_pdata *)rfp->rf_pdata;
842
843
769
	bp = pdp->rp_buf;
844
769
	pdp->rp_tlen = 0;
845
769
	*bp = '\0';
846
847
15819
	for (;;) {
848

63276
		c = getc(rfp->rf_file);
849
15819
		if (c == '@') {
850

3072
			c = getc(rfp->rf_file);
851
768
			if (c == EOF) {
852
				return (EOF);
853
768
			} else if (c != '@') {
854
768
				ungetc(c, rfp->rf_file);
855
				break;
856
			}
857
		}
858
859
15051
		if (c == EOF) {
860
1
			return (EOF);
861
15050
		} else if (c == '\n')
862
1284
			pdp->rp_lineno++;
863
864
30100
		RBUF_PUTC(c);
865
	}
866
867
768
	bp = pdp->rp_buf + pdp->rp_tlen;
868
1536
	RBUF_PUTC('\0');
869
870
768
	if (!(allowed & RCS_TYPE_STRING)) {
871
		rcsparse_warnx(rfp, "unexpected RCS string");
872
		return (0);
873
	}
874
875
768
	pdp->rp_value.str = xstrdup(pdp->rp_buf);
876
877
768
	return (RCS_TYPE_STRING);
878
769
}
879
880
static int
881
rcsparse_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
15740
	pdp = (struct rcs_pdata *)rfp->rf_pdata;
891
892
7870
	if (pdp->rp_token != -1) {
893
		/* no need to check for allowed here */
894
		type = pdp->rp_token;
895
384
		pdp->rp_token = -1;
896
384
		return (type);
897
	}
898
899
	/* skip whitespaces */
900
	c = EOF;
901
7486
	do {
902
		pre = c;
903

45748
		c = getc(rfp->rf_file);
904
11437
		if (c == EOF) {
905

230
			if (ferror(rfp->rf_file)) {
906
				rcsparse_warnx(rfp, "error during parsing");
907
				return (0);
908
			}
909
115
			if (pre != '\n')
910
				rcsparse_warnx(rfp,
911
				    "no newline at end of file");
912
115
			return (EOF);
913
11322
		} else if (c == '\n')
914
3195
			pdp->rp_lineno++;
915
11322
	} while (isspace(c));
916
917
7371
	pdp->rp_msglineno = pdp->rp_lineno;
918

7371
	switch (c) {
919
	case '@':
920
769
		ret = rcsparse_string(rfp, allowed);
921


771
		if (ret == EOF && ferror(rfp->rf_file)) {
922
			rcsparse_warnx(rfp, "error during parsing");
923
			return (0);
924
		}
925
769
		return (ret);
926
		/* NOTREACHED */
927
	case ':':
928
		type = RCS_TOK_COLON;
929
93
		if (type & allowed)
930
93
			return (type);
931
		rcsparse_warnx(rfp, "unexpected token \"%c\"", c);
932
		return (0);
933
		/* NOTREACHED */
934
	case ';':
935
		type = RCS_TOK_SCOLON;
936
2050
		if (type & allowed)
937
2050
			return (type);
938
		rcsparse_warnx(rfp, "unexpected token \"%c\"", c);
939
		return (0);
940
		/* NOTREACHED */
941
	case ',':
942
		type = RCS_TOK_COMMA;
943
		if (type & allowed)
944
			return (type);
945
		rcsparse_warnx(rfp, "unexpected token \"%c\"", c);
946
		return (0);
947
		/* NOTREACHED */
948
	default:
949
4459
		if (!isgraph(c)) {
950
			rcsparse_warnx(rfp, "unexpected character 0x%.2X", c);
951
			return (0);
952
		}
953
		break;
954
	}
955
4459
	allowed &= ~(RCS_TOK_COLON|RCS_TOK_SCOLON|RCS_TOK_COMMA);
956
957
4459
	bp = pdp->rp_buf;
958
4459
	pdp->rp_tlen = 0;
959
4459
	*bp = '\0';
960
961
4459
	for (;;) {
962
23775
		if (c == EOF) {
963
			if (ferror(rfp->rf_file))
964
				rcsparse_warnx(rfp, "error during parsing");
965
			else
966
				rcsparse_warnx(rfp, "unexpected end of file");
967
			return (0);
968
23775
		} else if (c == '\n')
969
			pdp->rp_lineno++;
970
971
47550
		RBUF_PUTC(c);
972
973

95100
		c = getc(rfp->rf_file);
974
975
23775
		if (isspace(c)) {
976
2566
			if (c == '\n')
977
1276
				pdp->rp_lineno++;
978
5132
			RBUF_PUTC('\0');
979
2566
			break;
980
21209
		} else if (c == ';' || c == ':' || c == ',') {
981
1893
			ungetc(c, rfp->rf_file);
982
3786
			RBUF_PUTC('\0');
983
1893
			break;
984
19316
		} else if (!isgraph(c)) {
985
			rcsparse_warnx(rfp, "unexpected character 0x%.2X", c);
986
			return (0);
987
		}
988
	}
989
990


4979
	switch (allowed) {
991
	case RCS_TYPE_COMMITID:
992
		if (!valid_commitid(pdp->rp_buf)) {
993
			rcsparse_warnx(rfp, "invalid commitid \"%s\"",
994
			    pdp->rp_buf);
995
			return (0);
996
		}
997
		pdp->rp_value.str = xstrdup(pdp->rp_buf);
998
		break;
999
	case RCS_TYPE_LOGIN:
1000
345
		if (!valid_login(pdp->rp_buf)) {
1001
			rcsparse_warnx(rfp, "invalid login \"%s\"",
1002
			    pdp->rp_buf);
1003
			return (0);
1004
		}
1005
345
		pdp->rp_value.str = xstrdup(pdp->rp_buf);
1006
345
		break;
1007
	case RCS_TYPE_SYMBOL:
1008
26
		if (!rcs_sym_check(pdp->rp_buf)) {
1009
			rcsparse_warnx(rfp, "invalid symbol \"%s\"",
1010
			    pdp->rp_buf);
1011
			return (0);
1012
		}
1013
26
		pdp->rp_value.str = xstrdup(pdp->rp_buf);
1014
26
		break;
1015
		/* FALLTHROUGH */
1016
	case RCS_TYPE_STATE:
1017
260
		if (rcs_state_check(pdp->rp_buf)) {
1018
			rcsparse_warnx(rfp, "invalid state \"%s\"",
1019
			    pdp->rp_buf);
1020
			return (0);
1021
		}
1022
260
		pdp->rp_value.str = xstrdup(pdp->rp_buf);
1023
260
		break;
1024
	case RCS_TYPE_DATE:
1025
260
		if ((datenum = rcsnum_parse(pdp->rp_buf)) == NULL) {
1026
			rcsparse_warnx(rfp, "invalid date \"%s\"", pdp->rp_buf);
1027
			return (0);
1028
		}
1029
260
		if (datenum->rn_len != 6) {
1030
			rcsnum_free(datenum);
1031
			rcsparse_warnx(rfp, "invalid date \"%s\"", pdp->rp_buf);
1032
			return (0);
1033
		}
1034
260
		pdp->rp_value.date.tm_year = datenum->rn_id[0];
1035
260
		if (pdp->rp_value.date.tm_year >= 1900)
1036
260
			pdp->rp_value.date.tm_year -= 1900;
1037
260
		pdp->rp_value.date.tm_mon = datenum->rn_id[1] - 1;
1038
260
		pdp->rp_value.date.tm_mday = datenum->rn_id[2];
1039
260
		pdp->rp_value.date.tm_hour = datenum->rn_id[3];
1040
260
		pdp->rp_value.date.tm_min = datenum->rn_id[4];
1041
260
		pdp->rp_value.date.tm_sec = datenum->rn_id[5];
1042
260
		rcsnum_free(datenum);
1043
260
		break;
1044
	case RCS_TYPE_NUMBER:
1045
26
		pdp->rp_value.rev = rcsnum_parse(pdp->rp_buf);
1046
26
		if (pdp->rp_value.rev == NULL) {
1047
			rcsparse_warnx(rfp, "invalid number \"%s\"",
1048
			    pdp->rp_buf);
1049
			return (0);
1050
		}
1051
		break;
1052
	case RCS_TYPE_BRANCH:
1053
		pdp->rp_value.rev = rcsnum_parse(pdp->rp_buf);
1054
		if (pdp->rp_value.rev == NULL) {
1055
			rcsparse_warnx(rfp, "invalid branch \"%s\"",
1056
			    pdp->rp_buf);
1057
			return (0);
1058
		}
1059
		if (!RCSNUM_ISBRANCH(pdp->rp_value.rev)) {
1060
			rcsnum_free(pdp->rp_value.rev);
1061
			rcsparse_warnx(rfp, "expected branch, got \"%s\"",
1062
			    pdp->rp_buf);
1063
			return (0);
1064
		}
1065
		break;
1066
	case RCS_TYPE_KEYWORD:
1067
3215
		if (islower(*pdp->rp_buf)) {
1068
2695
			p = bsearch(pdp->rp_buf, keywords,
1069
			    sizeof(keywords) / sizeof(keywords[0]),
1070
			    sizeof(keywords[0]), kw_cmp);
1071
2695
			if (p != NULL)
1072
2695
				return (p->k_val);
1073
		}
1074
520
		allowed = RCS_TYPE_REVISION;
1075
		/* FALLTHROUGH */
1076
	case RCS_TYPE_REVISION:
1077
847
		pdp->rp_value.rev = rcsnum_parse(pdp->rp_buf);
1078
847
		if (pdp->rp_value.rev != NULL) {
1079
847
			if (RCSNUM_ISBRANCH(pdp->rp_value.rev)) {
1080
				rcsnum_free(pdp->rp_value.rev);
1081
				rcsparse_warnx(rfp,
1082
				    "expected revision, got \"%s\"",
1083
				    pdp->rp_buf);
1084
				return (0);
1085
			}
1086
			break;
1087
		}
1088
		/* FALLTHROUGH */
1089
	default:
1090
		RBUF_PUTC('\0');
1091
		rcsparse_warnx(rfp, "unexpected token \"%s\"", pdp->rp_buf);
1092
		return (0);
1093
		/* NOTREACHED */
1094
	}
1095
1096
1764
	return (allowed);
1097
7870
}
1098
1099
static int
1100
rcsparse(RCSFILE *rfp, struct rcs_section *sec)
1101
{
1102
	struct rcs_pdata *pdp;
1103
	int i, token;
1104
1105
1520
	pdp = (struct rcs_pdata *)rfp->rf_pdata;
1106
1107
	token = 0;
1108
7698
	for (i = 0; sec[i].token != 0; i++) {
1109
3590
		token = rcsparse_token(rfp, RCS_TYPE_KEYWORD);
1110
3590
		if (token == 0)
1111
			return (1);
1112
1113
4100
		while (token != sec[i].token) {
1114
1010
			if (sec[i].parse == NULL)
1115
				goto end;
1116
625
			if (sec[i].opt) {
1117
510
				i++;
1118
510
				continue;
1119
			}
1120

115
			if (token == EOF || (!(rfp->rf_flags & PARSED_DELTAS) &&
1121
			    token == RCS_TOK_DESC))
1122
				goto end;
1123
			rcsparse_warnx(rfp, "unexpected token \"%s\"",
1124
			    pdp->rp_buf);
1125
			return (1);
1126
		}
1127
1128
3090
		if (sec[i].parse(rfp, pdp))
1129
1
			return (1);
1130
	}
1131
end:
1132
759
	if (token == RCS_TYPE_REVISION)
1133
260
		pdp->rp_token = token;
1134
499
	else if (token == RCS_TOK_DESC)
1135
125
		pdp->rp_token = RCS_TOK_DESC;
1136
374
	else if (token == EOF)
1137
115
		rfp->rf_flags |= RCS_PARSED;
1138
1139
759
	return (0);
1140
760
}
1141
1142
static int
1143
rcsparse_deltatext(RCSFILE *rfp)
1144
{
1145
	int ret;
1146
1147
980
	if (rfp->rf_flags & PARSED_DELTATEXTS)
1148
115
		return (0);
1149
1150
375
	if (!(rfp->rf_flags & PARSED_DESC))
1151
		if ((ret = rcsparse_desc(rfp)))
1152
			return (ret);
1153
1154
375
	if (rcsparse(rfp, sec_deltatext))
1155
1
		return (-1);
1156
1157
374
	if (rfp->rf_flags & RCS_PARSED)
1158
115
		rfp->rf_flags |= PARSED_DELTATEXTS;
1159
1160
374
	return (1);
1161
490
}
1162
1163
static int
1164
rcsparse_delta(RCSFILE *rfp)
1165
{
1166
	struct rcs_pdata *pdp;
1167
1168
768
	if (rfp->rf_flags & PARSED_DELTAS)
1169
		return (0);
1170
1171
384
	pdp = (struct rcs_pdata *)rfp->rf_pdata;
1172
384
	if (pdp->rp_token == RCS_TOK_DESC) {
1173
124
		rfp->rf_flags |= PARSED_DELTAS;
1174
124
		return (0);
1175
	}
1176
1177
260
	if (rcsparse(rfp, sec_delta))
1178
		return (-1);
1179
1180
260
	if (pdp->rp_delta != NULL) {
1181
260
		TAILQ_INSERT_TAIL(&rfp->rf_delta, pdp->rp_delta, rd_list);
1182
260
		pdp->rp_delta = NULL;
1183
260
		rfp->rf_ndelta++;
1184
260
		return (1);
1185
	}
1186
1187
	return (0);
1188
384
}
1189
1190
/*
1191
 * rcsparse_growbuf()
1192
 *
1193
 * Attempt to grow the internal parse buffer for the RCS file <rf> by
1194
 * RCS_BUFEXTSIZE.
1195
 * In case of failure, the original buffer is left unmodified.
1196
 */
1197
static void
1198
rcsparse_growbuf(RCSFILE *rfp)
1199
{
1200
	struct rcs_pdata *pdp = (struct rcs_pdata *)rfp->rf_pdata;
1201
1202
	pdp->rp_buf = xreallocarray(pdp->rp_buf, 1,
1203
		pdp->rp_blen + RCS_BUFEXTSIZE);
1204
	pdp->rp_blen += RCS_BUFEXTSIZE;
1205
	pdp->rp_bufend = pdp->rp_buf + pdp->rp_blen - 1;
1206
}
1207
1208
/*
1209
 * Borrowed from src/usr.sbin/user/user.c:
1210
 * return 1 if `login' is a valid login name
1211
 */
1212
static int
1213
valid_login(char *login_name)
1214
{
1215
	unsigned char *cp;
1216
1217
	/* The first character cannot be a hyphen */
1218
690
	if (*login_name == '-')
1219
		return 0;
1220
1221
3478
	for (cp = login_name ; *cp ; cp++) {
1222
		/* We allow '$' as the last character for samba */
1223


1394
		if (!isalnum(*cp) && *cp != '.' && *cp != '_' && *cp != '-' &&
1224
		    !(*cp == '$' && *(cp + 1) == '\0')) {
1225
			return 0;
1226
		}
1227
	}
1228
345
	if ((char *)cp - login_name > _PW_NAME_LEN)
1229
		return 0;
1230
345
	return 1;
1231
345
}
1232
1233
static int
1234
valid_commitid(char *commitid)
1235
{
1236
	unsigned char *cp;
1237
1238
	/* A-Za-z0-9 */
1239
	for (cp = commitid; *cp ; cp++) {
1240
		if (!isalnum(*cp))
1241
			return 0;
1242
	}
1243
	if ((char *)cp - commitid > RCS_COMMITID_MAXLEN)
1244
		return 0;
1245
	return 1;
1246
}
1247
1248
static int
1249
kw_cmp(const void *k, const void *e)
1250
{
1251
19230
	return (strcmp(k, ((const struct rcs_keyword *)e)->k_name));
1252
}
1253
1254
static void
1255
rcsparse_warnx(RCSFILE *rfp, char *fmt, ...)
1256
{
1257
	struct rcs_pdata *pdp;
1258
	va_list ap;
1259
	char *msg;
1260
1261
	pdp = (struct rcs_pdata *)rfp->rf_pdata;
1262
	va_start(ap, fmt);
1263
	if (vasprintf(&msg, fmt, ap) == -1) {
1264
		warn("vasprintf");
1265
		va_end(ap);
1266
		return;
1267
	}
1268
	va_end(ap);
1269
	warnx("%s:%d: %s", rfp->rf_path, pdp->rp_msglineno, msg);
1270
	free(msg);
1271
}