File: | src/usr.bin/cvs/rcsparse.c |
Warning: | line 1107, column 2 Value stored to 'i' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 */ |
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(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 */ |
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(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 | */ |
188 | static 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 | */ |
204 | static 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 | */ |
219 | int |
220 | rcsparse_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 | */ |
262 | int |
263 | rcsparse_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 | */ |
301 | int |
302 | rcsparse_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 | */ |
337 | void |
338 | rcsparse_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 | */ |
360 | static int |
361 | rcsparse_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 | */ |
394 | static int |
395 | rcsparse_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 | */ |
416 | static int |
417 | rcsparse_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 | */ |
436 | static int |
437 | rcsparse_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 | */ |
456 | static int |
457 | rcsparse_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 | */ |
476 | static int |
477 | rcsparse_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 | */ |
501 | static int |
502 | rcsparse_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 | */ |
526 | static int |
527 | rcsparse_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 | */ |
548 | static int |
549 | rcsparse_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 | */ |
578 | static int |
579 | rcsparse_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 | */ |
598 | static int |
599 | rcsparse_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 | */ |
626 | static int |
627 | rcsparse_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 | */ |
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(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 | */ |
673 | static int |
674 | rcsparse_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 | */ |
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 | 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 | */ |
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 | 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 | */ |
766 | static int |
767 | rcsparse_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 | */ |
784 | static int |
785 | rcsparse_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 | */ |
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(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); \ |
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 | 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 | |
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 | 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 | |
1100 | static int |
1101 | rcsparse(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 | } |
1133 | end: |
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 | |
1144 | static int |
1145 | rcsparse_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 | |
1165 | static int |
1166 | rcsparse_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 | */ |
1199 | static void |
1200 | rcsparse_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 | */ |
1214 | static int |
1215 | valid_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 | |
1235 | static int |
1236 | valid_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 | |
1250 | static int |
1251 | kw_cmp(const void *k, const void *e) |
1252 | { |
1253 | return (strcmp(k, ((const struct rcs_keyword *)e)->k_name)); |
1254 | } |
1255 | |
1256 | static void |
1257 | rcsparse_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 | } |