2 * Copyright (c) 2008-2009, Ulf Lilleengen <lulf@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include "rcstokenizer.h"
40 * This is an RCS-parser using lex for tokenizing and makes sure the RCS syntax
41 * is correct as it constructs an RCS file that is used by csup.
44 static void asserttoken(yyscan_t *, int);
45 static int parse_admin(struct rcsfile *, yyscan_t *);
46 static int parse_deltas(struct rcsfile *, yyscan_t *, int);
47 static int parse_deltatexts(struct rcsfile *, yyscan_t *, int);
48 static char *duptext(yyscan_t *, int *);
52 STAILQ_ENTRY(string) next;
56 asserttoken(yyscan_t *sp, int token)
66 duptext(yyscan_t *sp, int *arglen)
71 tmp = rcsget_text(*sp);
72 len = rcsget_leng(*sp);
73 val = xmalloc(len + 1);
74 memcpy(val, tmp, len);
82 * Start up parser, and use the rcsfile hook to add objects.
85 rcsparse_run(struct rcsfile *rf, FILE *infp, int ro)
92 rcslex_init(&scanner);
93 rcsset_in(infp, scanner);
94 tok = parse_admin(rf, &scanner);
95 tok = parse_deltas(rf, &scanner, tok);
96 assert(tok == KEYWORD);
97 asserttoken(&scanner, STRING);
98 desc = duptext(&scanner, NULL);
99 rcsfile_setval(rf, RCSFILE_DESC, desc);
101 tok = rcslex(scanner);
102 /* Parse deltatexts if we need to edit. */
104 error = parse_deltatexts(rf, &scanner, tok);
108 rcslex_destroy(scanner);
113 * Parse the admin part of a RCS file.
116 parse_admin(struct rcsfile *rf, yyscan_t *sp)
118 char *branch, *comment, *expand, *head, *id, *revnum, *tag, *tmp;
125 asserttoken(sp, KEYWORD);
126 asserttoken(sp, NUM);
127 head = duptext(sp, NULL);
128 rcsfile_setval(rf, RCSFILE_HEAD, head);
130 asserttoken(sp, SEMIC);
132 /* { branch {num}; } */
134 if (token == KEYWORD_TWO) {
135 asserttoken(sp, NUM);
136 branch = duptext(sp, NULL);
137 rcsfile_setval(rf, RCSFILE_BRANCH, branch);
139 asserttoken(sp, SEMIC);
144 assert(token == KEYWORD);
146 while (token == ID) {
147 id = duptext(sp, NULL);
148 rcsfile_addaccess(rf, id);
152 assert(token == SEMIC);
154 /* symbols {sym : num}*; */
155 asserttoken(sp, KEYWORD);
157 while (token == ID) {
158 tag = duptext(sp, NULL);
159 asserttoken(sp, COLON);
160 asserttoken(sp, NUM);
161 revnum = duptext(sp, NULL);
162 rcsfile_importtag(rf, tag, revnum);
167 assert(token == SEMIC);
169 /* locks {id : num}*; */
170 asserttoken(sp, KEYWORD);
172 while (token == ID) {
173 /* XXX: locks field is skipped */
174 asserttoken(sp, COLON);
175 asserttoken(sp, NUM);
178 assert(token == SEMIC);
180 while (token == KEYWORD) {
181 tmp = rcsget_text(*sp);
184 if (!strcmp(tmp, "strict")) {
185 rcsfile_setval(rf, RCSFILE_STRICT, tmp);
186 asserttoken(sp, SEMIC);
187 /* { comment {string}; } */
188 } else if (!strcmp(tmp, "comment")) {
190 if (token == STRING) {
191 comment = duptext(sp, NULL);
192 rcsfile_setval(rf, RCSFILE_COMMENT, comment);
195 asserttoken(sp, SEMIC);
196 /* { expand {string}; } */
197 } else if (!strcmp(tmp, "expand")) {
199 if (token == STRING) {
200 expand = duptext(sp, NULL);
201 rcsfile_setval(rf, RCSFILE_EXPAND, expand);
204 asserttoken(sp, SEMIC);
208 while (token == ID) {
210 /* XXX: newphrases ignored */
211 while (token == ID || token == NUM || token == STRING ||
215 asserttoken(sp, SEMIC);
226 parse_deltas(struct rcsfile *rf, yyscan_t *sp, int token)
228 STAILQ_HEAD(, string) branchlist;
229 char *revnum, *revdate, *author, *state, *next;
231 /* In case we don't have deltas. */
239 assert(token == NUM);
240 revnum = duptext(sp, NULL);
242 asserttoken(sp, KEYWORD);
243 asserttoken(sp, NUM);
244 revdate = duptext(sp, NULL);
245 asserttoken(sp, SEMIC);
247 asserttoken(sp, KEYWORD);
249 author = duptext(sp, NULL);
250 asserttoken(sp, SEMIC);
252 asserttoken(sp, KEYWORD);
255 state = duptext(sp, NULL);
258 assert(token == SEMIC);
259 /* branches {num}*; */
260 asserttoken(sp, KEYWORD);
262 STAILQ_INIT(&branchlist);
265 assert(token == SEMIC);
267 asserttoken(sp, KEYWORD);
270 next = duptext(sp, NULL);
273 assert(token == SEMIC);
276 while (token == ID) {
278 /* XXX: newphrases ignored. */
279 while (token == ID || token == NUM || token == STRING ||
283 asserttoken(sp, SEMIC);
286 rcsfile_importdelta(rf, revnum, revdate, author, state, next);
294 } while (token == NUM);
300 * Parse RCS deltatexts.
303 parse_deltatexts(struct rcsfile *rf, yyscan_t *sp, int token)
306 char *log, *revnum, *text;
310 /* In case we don't have deltatexts. */
315 assert(token == NUM);
316 revnum = duptext(sp, NULL);
317 /* Get delta we're adding text to. */
318 d = rcsfile_getdelta(rf, revnum);
322 * XXX: The RCS file is corrupt, but lie and say it is ok.
323 * If it is actually broken, then the MD5 mismatch will
330 asserttoken(sp, KEYWORD);
331 asserttoken(sp, STRING);
332 log = duptext(sp, &len);
333 error = rcsdelta_addlog(d, log, len);
339 while (token == ID) {
341 /* XXX: newphrases ignored. */
342 while (token == ID || token == NUM || token == STRING ||
346 asserttoken(sp, SEMIC);
350 assert(token == KEYWORD);
351 asserttoken(sp, STRING);
352 text = duptext(sp, &len);
353 error = rcsdelta_addtext(d, text, len);
355 * If this happens, something is wrong with the RCS file, and it
362 } while (token == NUM);