1 /* $OpenBSD: rcsparse.c,v 1.8 2014/11/16 19:14:34 bluhm 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_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 if (rfp->rf_flags & RCS_PARSED) 225 return (0); 226 227 pdp = xmalloc(sizeof(*pdp)); 228 pdp->rp_buf = xmalloc(RCS_BUFSIZE); 229 pdp->rp_blen = RCS_BUFSIZE; 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; 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) && 245 rcsparse_deltatexts(rfp, NULL)) { 246 rcsparse_free(rfp); 247 return (1); 248 } 249 250 rfp->rf_flags |= RCS_SYNCED; 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) || (rfp->rf_flags & RCS_CREATE)) 269 return (0); 270 271 for (;;) { 272 ret = rcsparse_delta(rfp); 273 if (rev != NULL) { 274 enddelta = TAILQ_LAST(&(rfp->rf_delta), rcs_dlist); 275 if (enddelta == NULL) 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; 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) || 308 (rfp->rf_flags & RCS_CREATE)) 309 return (0); 310 311 if (!(rfp->rf_flags & PARSED_DESC)) 312 if (rcsparse_desc(rfp)) 313 return (1); 314 315 rdp = (rev != NULL) ? rcs_findrev(rfp, rev) : NULL; 316 317 for (;;) { 318 if (rdp != NULL && rdp->rd_text != NULL) 319 break; 320 ret = rcsparse_deltatext(rfp); 321 if (ret == 0) { 322 rfp->rf_flags |= PARSED_DELTATEXTS; 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 if (pdp->rp_buf != NULL) 345 xfree(pdp->rp_buf); 346 if (pdp->rp_token == RCS_TYPE_REVISION) 347 rcsnum_free(pdp->rp_value.rev); 348 xfree(pdp); 349 } 350 351 /* 352 * rcsparse_desc() 353 * 354 * Parse desc of the RCS file <rfp>. By calling rcsparse_desc, all deltas 355 * will be parsed in order to proceed the reading cursor to the desc keyword. 356 * 357 * desc @[...]@; 358 * 359 * Returns 0 on success or 1 on error. 360 */ 361 static int 362 rcsparse_desc(RCSFILE *rfp) 363 { 364 struct rcs_pdata *pdp; 365 366 if (rfp->rf_flags & PARSED_DESC) 367 return (0); 368 369 if (!(rfp->rf_flags & PARSED_DELTAS) && rcsparse_deltas(rfp, NULL)) 370 return (1); 371 372 pdp = (struct rcs_pdata *)rfp->rf_pdata; 373 374 if (rcsparse_token(rfp, RCS_TOK_DESC) != RCS_TOK_DESC || 375 rcsparse_token(rfp, RCS_TYPE_STRING) != RCS_TYPE_STRING) 376 return (1); 377 378 rfp->rf_desc = pdp->rp_value.str; 379 rfp->rf_flags |= PARSED_DESC; 380 381 return (0); 382 } 383 384 /* 385 * rcsparse_deltarevision() 386 * 387 * Called upon reaching a new REVISION entry in the delta section. 388 * A new rcs_delta structure will be prepared in pdp->rp_delta for further 389 * parsing. 390 * 391 * REVISION 392 * 393 * Always returns 0. 394 */ 395 static int 396 rcsparse_deltarevision(RCSFILE *rfp, struct rcs_pdata *pdp) 397 { 398 struct rcs_delta *rdp; 399 400 rdp = xcalloc(1, sizeof(*rdp)); 401 TAILQ_INIT(&rdp->rd_branches); 402 rdp->rd_num = pdp->rp_value.rev; 403 pdp->rp_delta = rdp; 404 405 return (0); 406 } 407 408 /* 409 * rcsparse_date() 410 * 411 * Parses the specified date of current delta pdp->rp_delta. 412 * 413 * date YYYY.MM.DD.HH.MM.SS; 414 * 415 * Returns 0 on success or 1 on failure. 416 */ 417 static int 418 rcsparse_date(RCSFILE *rfp, struct rcs_pdata *pdp) 419 { 420 if (rcsparse_token(rfp, RCS_TYPE_DATE) != RCS_TYPE_DATE) 421 return (1); 422 423 pdp->rp_delta->rd_date = pdp->rp_value.date; 424 425 return (rcsparse_token(rfp, RCS_TOK_SCOLON) != RCS_TOK_SCOLON); 426 } 427 428 /* 429 * rcsparse_author() 430 * 431 * Parses the specified author of current delta pdp->rp_delta. 432 * 433 * author LOGIN; 434 * 435 * Returns 0 on success or 1 on failure. 436 */ 437 static int 438 rcsparse_author(RCSFILE *rfp, struct rcs_pdata *pdp) 439 { 440 if (rcsparse_token(rfp, RCS_TYPE_LOGIN) != RCS_TYPE_LOGIN) 441 return (1); 442 443 pdp->rp_delta->rd_author = pdp->rp_value.str; 444 445 return (rcsparse_token(rfp, RCS_TOK_SCOLON) != RCS_TOK_SCOLON); 446 } 447 448 /* 449 * rcsparse_state() 450 * 451 * Parses the specified state of current delta pdp->rp_delta. 452 * 453 * state STATE; 454 * 455 * Returns 0 on success or 1 on failure. 456 */ 457 static int 458 rcsparse_state(RCSFILE *rfp, struct rcs_pdata *pdp) 459 { 460 if (rcsparse_token(rfp, RCS_TYPE_STATE) != RCS_TYPE_STATE) 461 return (1); 462 463 pdp->rp_delta->rd_state = pdp->rp_value.str; 464 465 return (rcsparse_token(rfp, RCS_TOK_SCOLON) != RCS_TOK_SCOLON); 466 } 467 468 /* 469 * rcsparse_branches() 470 * 471 * Parses the specified branches of current delta pdp->rp_delta. 472 * 473 * branches [REVISION ...]; 474 * 475 * Returns 0 on success or 1 on failure. 476 */ 477 static int 478 rcsparse_branches(RCSFILE *rfp, struct rcs_pdata *pdp) 479 { 480 struct rcs_branch *rb; 481 int type; 482 483 while ((type = rcsparse_token(rfp, RCS_TOK_SCOLON|RCS_TYPE_REVISION)) 484 == RCS_TYPE_REVISION) { 485 rb = xmalloc(sizeof(*rb)); 486 rb->rb_num = pdp->rp_value.rev; 487 TAILQ_INSERT_TAIL(&(pdp->rp_delta->rd_branches), rb, rb_list); 488 } 489 490 return (type != RCS_TOK_SCOLON); 491 } 492 493 /* 494 * rcsparse_next() 495 * 496 * Parses the specified next revision of current delta pdp->rp_delta. 497 * 498 * next [REVISION]; 499 * 500 * Returns 0 on success or 1 on failure. 501 */ 502 static int 503 rcsparse_next(RCSFILE *rfp, struct rcs_pdata *pdp) 504 { 505 int type; 506 507 type = rcsparse_token(rfp, RCS_TYPE_REVISION|RCS_TOK_SCOLON); 508 if (type == RCS_TYPE_REVISION) { 509 pdp->rp_delta->rd_next = pdp->rp_value.rev; 510 type = rcsparse_token(rfp, RCS_TOK_SCOLON); 511 } else 512 pdp->rp_delta->rd_next = rcsnum_alloc(); 513 514 return (type != RCS_TOK_SCOLON); 515 } 516 517 /* 518 * rcsparse_commitid() 519 * 520 * Parses the specified commit id of current delta pdp->rp_delta. The 521 * commitid keyword is optional and can be omitted. 522 * 523 * [commitid ID;] 524 * 525 * Returns 0 on success or 1 on failure. 526 */ 527 static int 528 rcsparse_commitid(RCSFILE *rfp, struct rcs_pdata *pdp) 529 { 530 if (rcsparse_token(rfp, RCS_TYPE_COMMITID) != RCS_TYPE_COMMITID) 531 return (1); 532 533 pdp->rp_delta->rd_commitid = pdp->rp_value.str; 534 535 return (rcsparse_token(rfp, RCS_TOK_SCOLON) != RCS_TOK_SCOLON); 536 } 537 538 /* 539 * rcsparse_textrevision() 540 * 541 * Called upon reaching a new REVISION entry in the delta text section. 542 * pdp->rp_delta will be set to REVISION's delta (created in delta section) 543 * for further parsing. 544 * 545 * REVISION 546 * 547 * Returns 0 on success or 1 on failure. 548 */ 549 static int 550 rcsparse_textrevision(RCSFILE *rfp, struct rcs_pdata *pdp) 551 { 552 struct rcs_delta *rdp; 553 554 TAILQ_FOREACH(rdp, &rfp->rf_delta, rd_list) { 555 if (rcsnum_cmp(rdp->rd_num, pdp->rp_value.rev, 0) == 0) 556 break; 557 } 558 if (rdp == NULL) { 559 rcsparse_warnx(rfp, "delta for revision \"%s\" not found", 560 pdp->rp_buf); 561 rcsnum_free(pdp->rp_value.rev); 562 return (1); 563 } 564 pdp->rp_delta = rdp; 565 566 rcsnum_free(pdp->rp_value.rev); 567 return (0); 568 } 569 570 /* 571 * rcsparse_log() 572 * 573 * Parses the specified log of current deltatext pdp->rp_delta. 574 * 575 * log @[...]@ 576 * 577 * Returns 0 on success or 1 on failure. 578 */ 579 static int 580 rcsparse_log(RCSFILE *rfp, struct rcs_pdata *pdp) 581 { 582 if (rcsparse_token(rfp, RCS_TYPE_STRING) != RCS_TYPE_STRING) 583 return (1); 584 585 pdp->rp_delta->rd_log = pdp->rp_value.str; 586 587 return (0); 588 } 589 590 /* 591 * rcsparse_text() 592 * 593 * Parses the specified text of current deltatext pdp->rp_delta. 594 * 595 * text @[...]@ 596 * 597 * Returns 0 on success or 1 on failure. 598 */ 599 static int 600 rcsparse_text(RCSFILE *rfp, struct rcs_pdata *pdp) 601 { 602 if (rcsparse_token(rfp, RCS_TYPE_STRING) != RCS_TYPE_STRING) 603 return (1); 604 605 pdp->rp_delta->rd_tlen = pdp->rp_tlen - 1; 606 if (pdp->rp_delta->rd_tlen == 0) { 607 pdp->rp_delta->rd_text = xstrdup(""); 608 } else { 609 pdp->rp_delta->rd_text = xmalloc(pdp->rp_delta->rd_tlen); 610 memcpy(pdp->rp_delta->rd_text, pdp->rp_buf, 611 pdp->rp_delta->rd_tlen); 612 } 613 xfree(pdp->rp_value.str); 614 615 return (0); 616 } 617 618 /* 619 * rcsparse_head() 620 * 621 * Parses the head revision of RCS file <rfp>. 622 * 623 * head [REVISION]; 624 * 625 * Returns 0 on success or 1 on failure. 626 */ 627 static int 628 rcsparse_head(RCSFILE *rfp, struct rcs_pdata *pdp) 629 { 630 int type; 631 632 type = rcsparse_token(rfp, RCS_TYPE_REVISION|RCS_TOK_SCOLON); 633 if (type == RCS_TYPE_REVISION) { 634 rfp->rf_head = pdp->rp_value.rev; 635 type = rcsparse_token(rfp, RCS_TOK_SCOLON); 636 } 637 638 return (type != RCS_TOK_SCOLON); 639 } 640 641 /* 642 * rcsparse_branch() 643 * 644 * Parses the default branch of RCS file <rfp>. The branch keyword is 645 * optional and can be omitted. 646 * 647 * [branch BRANCH;] 648 * 649 * Returns 0 on success or 1 on failure. 650 */ 651 static int 652 rcsparse_branch(RCSFILE *rfp, struct rcs_pdata *pdp) 653 { 654 int type; 655 656 type = rcsparse_token(rfp, RCS_TYPE_BRANCH|RCS_TOK_SCOLON); 657 if (type == RCS_TYPE_BRANCH) { 658 rfp->rf_branch = pdp->rp_value.rev; 659 type = rcsparse_token(rfp, RCS_TOK_SCOLON); 660 } 661 662 return (type != RCS_TOK_SCOLON); 663 } 664 665 /* 666 * rcsparse_access() 667 * 668 * Parses the access list of RCS file <rfp>. 669 * 670 * access [LOGIN ...]; 671 * 672 * Returns 0 on success or 1 on failure. 673 */ 674 static int 675 rcsparse_access(RCSFILE *rfp, struct rcs_pdata *pdp) 676 { 677 struct rcs_access *ap; 678 int type; 679 680 while ((type = rcsparse_token(rfp, RCS_TOK_SCOLON|RCS_TYPE_LOGIN)) 681 == RCS_TYPE_LOGIN) { 682 ap = xmalloc(sizeof(*ap)); 683 ap->ra_name = pdp->rp_value.str; 684 TAILQ_INSERT_TAIL(&(rfp->rf_access), ap, ra_list); 685 } 686 687 return (type != RCS_TOK_SCOLON); 688 } 689 690 /* 691 * rcsparse_symbols() 692 * 693 * Parses the symbol list of RCS file <rfp>. 694 * 695 * symbols [SYMBOL:REVISION ...]; 696 * 697 * Returns 0 on success or 1 on failure. 698 */ 699 static int 700 rcsparse_symbols(RCSFILE *rfp, struct rcs_pdata *pdp) 701 { 702 struct rcs_sym *symp; 703 char *name; 704 int type; 705 706 while ((type = rcsparse_token(rfp, RCS_TOK_SCOLON|RCS_TYPE_SYMBOL)) == 707 RCS_TYPE_SYMBOL) { 708 name = pdp->rp_value.str; 709 if (rcsparse_token(rfp, RCS_TOK_COLON) != RCS_TOK_COLON || 710 rcsparse_token(rfp, RCS_TYPE_NUMBER) != RCS_TYPE_NUMBER) { 711 xfree(name); 712 return (1); 713 } 714 symp = xmalloc(sizeof(*symp)); 715 symp->rs_name = name; 716 symp->rs_num = pdp->rp_value.rev; 717 TAILQ_INSERT_TAIL(&(rfp->rf_symbols), symp, rs_list); 718 } 719 720 return (type != RCS_TOK_SCOLON); 721 } 722 723 /* 724 * rcsparse_locks() 725 * 726 * Parses the lock list of RCS file <rfp>. 727 * 728 * locks [SYMBOL:REVISION ...]; 729 * 730 * Returns 0 on success or 1 on failure. 731 */ 732 static int 733 rcsparse_locks(RCSFILE *rfp, struct rcs_pdata *pdp) 734 { 735 struct rcs_lock *lkp; 736 char *name; 737 int type; 738 739 while ((type = rcsparse_token(rfp, RCS_TOK_SCOLON|RCS_TYPE_LOGIN)) == 740 RCS_TYPE_LOGIN) { 741 name = pdp->rp_value.str; 742 if (rcsparse_token(rfp, RCS_TOK_COLON) != RCS_TOK_COLON || 743 rcsparse_token(rfp, RCS_TYPE_REVISION) != 744 RCS_TYPE_REVISION) { 745 xfree(name); 746 return (1); 747 } 748 lkp = xmalloc(sizeof(*lkp)); 749 lkp->rl_name = name; 750 lkp->rl_num = pdp->rp_value.rev; 751 TAILQ_INSERT_TAIL(&(rfp->rf_locks), lkp, rl_list); 752 } 753 754 return (type != RCS_TOK_SCOLON); 755 } 756 757 /* 758 * rcsparse_locks() 759 * 760 * Parses the strict keyword of RCS file <rfp>. The strict keyword is 761 * optional and can be omitted. 762 * 763 * [strict;] 764 * 765 * Returns 0 on success or 1 on failure. 766 */ 767 static int 768 rcsparse_strict(RCSFILE *rfp, struct rcs_pdata *pdp) 769 { 770 rfp->rf_flags |= RCS_SLOCK; 771 772 return (rcsparse_token(rfp, RCS_TOK_SCOLON) != RCS_TOK_SCOLON); 773 } 774 775 /* 776 * rcsparse_comment() 777 * 778 * Parses the comment of RCS file <rfp>. The comment keyword is optional 779 * and can be omitted. 780 * 781 * [comment [@[...]@];] 782 * 783 * Returns 0 on success or 1 on failure. 784 */ 785 static int 786 rcsparse_comment(RCSFILE *rfp, struct rcs_pdata *pdp) 787 { 788 int type; 789 790 type = rcsparse_token(rfp, RCS_TYPE_STRING|RCS_TOK_SCOLON); 791 if (type == RCS_TYPE_STRING) { 792 rfp->rf_comment = pdp->rp_value.str; 793 type = rcsparse_token(rfp, RCS_TOK_SCOLON); 794 } 795 796 return (type != RCS_TOK_SCOLON); 797 } 798 799 /* 800 * rcsparse_expand() 801 * 802 * Parses expand of RCS file <rfp>. The expand keyword is optional and 803 * can be omitted. 804 * 805 * [expand [@[...]@];] 806 * 807 * Returns 0 on success or 1 on failure. 808 */ 809 static int 810 rcsparse_expand(RCSFILE *rfp, struct rcs_pdata *pdp) 811 { 812 int type; 813 814 type = rcsparse_token(rfp, RCS_TYPE_STRING|RCS_TOK_SCOLON); 815 if (type == RCS_TYPE_STRING) { 816 rfp->rf_expand = pdp->rp_value.str; 817 type = rcsparse_token(rfp, RCS_TOK_SCOLON); 818 } 819 820 return (type != RCS_TOK_SCOLON); 821 } 822 823 #define RBUF_PUTC(ch) \ 824 do { \ 825 if (bp == pdp->rp_bufend - 1) { \ 826 len = bp - pdp->rp_buf; \ 827 rcsparse_growbuf(rfp); \ 828 bp = pdp->rp_buf + len; \ 829 } \ 830 *(bp++) = (ch); \ 831 pdp->rp_tlen++; \ 832 } while (0); 833 834 static int 835 rcsparse_string(RCSFILE *rfp, int allowed) 836 { 837 struct rcs_pdata *pdp; 838 int c; 839 size_t len; 840 char *bp; 841 842 pdp = (struct rcs_pdata *)rfp->rf_pdata; 843 844 bp = pdp->rp_buf; 845 pdp->rp_tlen = 0; 846 *bp = '\0'; 847 848 for (;;) { 849 c = getc(rfp->rf_file); 850 if (c == '@') { 851 c = getc(rfp->rf_file); 852 if (c == EOF) { 853 return (EOF); 854 } else if (c != '@') { 855 ungetc(c, rfp->rf_file); 856 break; 857 } 858 } 859 860 if (c == EOF) { 861 return (EOF); 862 } else if (c == '\n') 863 pdp->rp_lineno++; 864 865 RBUF_PUTC(c); 866 } 867 868 bp = pdp->rp_buf + pdp->rp_tlen; 869 RBUF_PUTC('\0'); 870 871 if (!(allowed & RCS_TYPE_STRING)) { 872 rcsparse_warnx(rfp, "unexpected RCS string"); 873 return (0); 874 } 875 876 pdp->rp_value.str = xstrdup(pdp->rp_buf); 877 878 return (RCS_TYPE_STRING); 879 } 880 881 static int 882 rcsparse_token(RCSFILE *rfp, int allowed) 883 { 884 const struct rcs_keyword *p; 885 struct rcs_pdata *pdp; 886 int c, pre, ret, type; 887 char *bp; 888 size_t len; 889 RCSNUM *datenum; 890 891 pdp = (struct rcs_pdata *)rfp->rf_pdata; 892 893 if (pdp->rp_token != -1) { 894 /* no need to check for allowed here */ 895 type = pdp->rp_token; 896 pdp->rp_token = -1; 897 return (type); 898 } 899 900 /* skip whitespaces */ 901 c = EOF; 902 do { 903 pre = c; 904 c = getc(rfp->rf_file); 905 if (c == EOF) { 906 if (ferror(rfp->rf_file)) { 907 rcsparse_warnx(rfp, "error during parsing"); 908 return (0); 909 } 910 if (pre != '\n') 911 rcsparse_warnx(rfp, 912 "no newline at end of file"); 913 return (EOF); 914 } else if (c == '\n') 915 pdp->rp_lineno++; 916 } while (isspace(c)); 917 918 pdp->rp_msglineno = pdp->rp_lineno; 919 type = 0; 920 switch (c) { 921 case '@': 922 ret = rcsparse_string(rfp, allowed); 923 if (ret == EOF && ferror(rfp->rf_file)) { 924 rcsparse_warnx(rfp, "error during parsing"); 925 return (0); 926 } 927 return (ret); 928 /* NOTREACHED */ 929 case ':': 930 type = RCS_TOK_COLON; 931 if (type & allowed) 932 return (type); 933 rcsparse_warnx(rfp, "unexpected token \"%c\"", c); 934 return (0); 935 /* NOTREACHED */ 936 case ';': 937 type = RCS_TOK_SCOLON; 938 if (type & allowed) 939 return (type); 940 rcsparse_warnx(rfp, "unexpected token \"%c\"", c); 941 return (0); 942 /* NOTREACHED */ 943 case ',': 944 type = RCS_TOK_COMMA; 945 if (type & allowed) 946 return (type); 947 rcsparse_warnx(rfp, "unexpected token \"%c\"", c); 948 return (0); 949 /* NOTREACHED */ 950 default: 951 if (!isgraph(c)) { 952 rcsparse_warnx(rfp, "unexpected character 0x%.2X", c); 953 return (0); 954 } 955 break; 956 } 957 allowed &= ~(RCS_TOK_COLON|RCS_TOK_SCOLON|RCS_TOK_COMMA); 958 959 bp = pdp->rp_buf; 960 pdp->rp_tlen = 0; 961 *bp = '\0'; 962 963 for (;;) { 964 if (c == EOF) { 965 if (ferror(rfp->rf_file)) 966 rcsparse_warnx(rfp, "error during parsing"); 967 else 968 rcsparse_warnx(rfp, "unexpected end of file"); 969 return (0); 970 } else if (c == '\n') 971 pdp->rp_lineno++; 972 973 RBUF_PUTC(c); 974 975 c = getc(rfp->rf_file); 976 977 if (isspace(c)) { 978 if (c == '\n') 979 pdp->rp_lineno++; 980 RBUF_PUTC('\0'); 981 break; 982 } else if (c == ';' || c == ':' || c == ',') { 983 ungetc(c, rfp->rf_file); 984 RBUF_PUTC('\0'); 985 break; 986 } else if (!isgraph(c)) { 987 rcsparse_warnx(rfp, "unexpected character 0x%.2X", c); 988 return (0); 989 } 990 } 991 992 switch (allowed) { 993 case RCS_TYPE_COMMITID: 994 if (!valid_commitid(pdp->rp_buf)) { 995 rcsparse_warnx(rfp, "invalid commitid \"%s\"", 996 pdp->rp_buf); 997 return (0); 998 } 999 pdp->rp_value.str = xstrdup(pdp->rp_buf); 1000 break; 1001 case RCS_TYPE_LOGIN: 1002 if (!valid_login(pdp->rp_buf)) { 1003 rcsparse_warnx(rfp, "invalid login \"%s\"", 1004 pdp->rp_buf); 1005 return (0); 1006 } 1007 pdp->rp_value.str = xstrdup(pdp->rp_buf); 1008 break; 1009 case RCS_TYPE_SYMBOL: 1010 if (!rcs_sym_check(pdp->rp_buf)) { 1011 rcsparse_warnx(rfp, "invalid symbol \"%s\"", 1012 pdp->rp_buf); 1013 return (0); 1014 } 1015 pdp->rp_value.str = xstrdup(pdp->rp_buf); 1016 break; 1017 /* FALLTHROUGH */ 1018 case RCS_TYPE_STATE: 1019 if (rcs_state_check(pdp->rp_buf)) { 1020 rcsparse_warnx(rfp, "invalid state \"%s\"", 1021 pdp->rp_buf); 1022 return (0); 1023 } 1024 pdp->rp_value.str = xstrdup(pdp->rp_buf); 1025 break; 1026 case RCS_TYPE_DATE: 1027 if ((datenum = rcsnum_parse(pdp->rp_buf)) == NULL) { 1028 rcsparse_warnx(rfp, "invalid date \"%s\"", pdp->rp_buf); 1029 return (0); 1030 } 1031 if (datenum->rn_len != 6) { 1032 rcsnum_free(datenum); 1033 rcsparse_warnx(rfp, "invalid date \"%s\"", pdp->rp_buf); 1034 return (0); 1035 } 1036 pdp->rp_value.date.tm_year = datenum->rn_id[0]; 1037 if (pdp->rp_value.date.tm_year >= 1900) 1038 pdp->rp_value.date.tm_year -= 1900; 1039 pdp->rp_value.date.tm_mon = datenum->rn_id[1] - 1; 1040 pdp->rp_value.date.tm_mday = datenum->rn_id[2]; 1041 pdp->rp_value.date.tm_hour = datenum->rn_id[3]; 1042 pdp->rp_value.date.tm_min = datenum->rn_id[4]; 1043 pdp->rp_value.date.tm_sec = datenum->rn_id[5]; 1044 rcsnum_free(datenum); 1045 break; 1046 case RCS_TYPE_NUMBER: 1047 pdp->rp_value.rev = rcsnum_parse(pdp->rp_buf); 1048 if (pdp->rp_value.rev == NULL) { 1049 rcsparse_warnx(rfp, "invalid number \"%s\"", 1050 pdp->rp_buf); 1051 return (0); 1052 } 1053 break; 1054 case RCS_TYPE_BRANCH: 1055 pdp->rp_value.rev = rcsnum_parse(pdp->rp_buf); 1056 if (pdp->rp_value.rev == NULL) { 1057 rcsparse_warnx(rfp, "invalid branch \"%s\"", 1058 pdp->rp_buf); 1059 return (0); 1060 } 1061 if (!RCSNUM_ISBRANCH(pdp->rp_value.rev)) { 1062 rcsnum_free(pdp->rp_value.rev); 1063 rcsparse_warnx(rfp, "expected branch, got \"%s\"", 1064 pdp->rp_buf); 1065 return (0); 1066 } 1067 break; 1068 case RCS_TYPE_KEYWORD: 1069 if (islower(*pdp->rp_buf)) { 1070 p = bsearch(pdp->rp_buf, keywords, 1071 sizeof(keywords) / sizeof(keywords[0]), 1072 sizeof(keywords[0]), kw_cmp); 1073 if (p != NULL) 1074 return (p->k_val); 1075 } 1076 allowed = RCS_TYPE_REVISION; 1077 /* FALLTHROUGH */ 1078 case RCS_TYPE_REVISION: 1079 pdp->rp_value.rev = rcsnum_parse(pdp->rp_buf); 1080 if (pdp->rp_value.rev != NULL) { 1081 if (RCSNUM_ISBRANCH(pdp->rp_value.rev)) { 1082 rcsnum_free(pdp->rp_value.rev); 1083 rcsparse_warnx(rfp, 1084 "expected revision, got \"%s\"", 1085 pdp->rp_buf); 1086 return (0); 1087 } 1088 break; 1089 } 1090 /* FALLTHROUGH */ 1091 default: 1092 RBUF_PUTC('\0'); 1093 rcsparse_warnx(rfp, "unexpected token \"%s\"", pdp->rp_buf); 1094 return (0); 1095 /* NOTREACHED */ 1096 } 1097 1098 return (allowed); 1099 } 1100 1101 static int 1102 rcsparse(RCSFILE *rfp, struct rcs_section *sec) 1103 { 1104 struct rcs_pdata *pdp; 1105 int i, token; 1106 1107 pdp = (struct rcs_pdata *)rfp->rf_pdata; 1108 i = 0; 1109 1110 token = 0; 1111 for (i = 0; sec[i].token != 0; i++) { 1112 token = rcsparse_token(rfp, RCS_TYPE_KEYWORD); 1113 if (token == 0) 1114 return (1); 1115 1116 while (token != sec[i].token) { 1117 if (sec[i].parse == NULL) 1118 goto end; 1119 if (sec[i].opt) { 1120 i++; 1121 continue; 1122 } 1123 if (token == EOF || (!(rfp->rf_flags & PARSED_DELTAS) && 1124 token == RCS_TOK_DESC)) 1125 goto end; 1126 rcsparse_warnx(rfp, "unexpected token \"%s\"", 1127 pdp->rp_buf); 1128 return (1); 1129 } 1130 1131 if (sec[i].parse(rfp, pdp)) 1132 return (1); 1133 } 1134 end: 1135 if (token == RCS_TYPE_REVISION) 1136 pdp->rp_token = token; 1137 else if (token == RCS_TOK_DESC) 1138 pdp->rp_token = RCS_TOK_DESC; 1139 else if (token == EOF) 1140 rfp->rf_flags |= RCS_PARSED; 1141 1142 return (0); 1143 } 1144 1145 static int 1146 rcsparse_deltatext(RCSFILE *rfp) 1147 { 1148 int ret; 1149 1150 if (rfp->rf_flags & PARSED_DELTATEXTS) 1151 return (0); 1152 1153 if (!(rfp->rf_flags & PARSED_DESC)) 1154 if ((ret = rcsparse_desc(rfp))) 1155 return (ret); 1156 1157 if (rcsparse(rfp, sec_deltatext)) 1158 return (-1); 1159 1160 if (rfp->rf_flags & RCS_PARSED) 1161 rfp->rf_flags |= PARSED_DELTATEXTS; 1162 1163 return (1); 1164 } 1165 1166 static int 1167 rcsparse_delta(RCSFILE *rfp) 1168 { 1169 struct rcs_pdata *pdp; 1170 1171 if (rfp->rf_flags & PARSED_DELTAS) 1172 return (0); 1173 1174 pdp = (struct rcs_pdata *)rfp->rf_pdata; 1175 if (pdp->rp_token == RCS_TOK_DESC) { 1176 rfp->rf_flags |= PARSED_DELTAS; 1177 return (0); 1178 } 1179 1180 if (rcsparse(rfp, sec_delta)) 1181 return (-1); 1182 1183 if (pdp->rp_delta != NULL) { 1184 TAILQ_INSERT_TAIL(&rfp->rf_delta, pdp->rp_delta, rd_list); 1185 pdp->rp_delta = NULL; 1186 rfp->rf_ndelta++; 1187 return (1); 1188 } 1189 1190 return (0); 1191 } 1192 1193 /* 1194 * rcsparse_growbuf() 1195 * 1196 * Attempt to grow the internal parse buffer for the RCS file <rf> by 1197 * RCS_BUFEXTSIZE. 1198 * In case of failure, the original buffer is left unmodified. 1199 */ 1200 static void 1201 rcsparse_growbuf(RCSFILE *rfp) 1202 { 1203 struct rcs_pdata *pdp = (struct rcs_pdata *)rfp->rf_pdata; 1204 1205 pdp->rp_buf = xrealloc(pdp->rp_buf, 1, 1206 pdp->rp_blen + RCS_BUFEXTSIZE); 1207 pdp->rp_blen += RCS_BUFEXTSIZE; 1208 pdp->rp_bufend = pdp->rp_buf + pdp->rp_blen - 1; 1209 } 1210 1211 /* 1212 * Borrowed from src/usr.sbin/user/user.c: 1213 * return 1 if `login' is a valid login name 1214 */ 1215 static int 1216 valid_login(char *login_name) 1217 { 1218 unsigned char *cp; 1219 1220 /* The first character cannot be a hyphen */ 1221 if (*login_name == '-') 1222 return 0; 1223 1224 for (cp = login_name ; *cp ; cp++) { 1225 /* We allow '$' as the last character for samba */ 1226 if (!isalnum(*cp) && *cp != '.' && *cp != '_' && *cp != '-' && 1227 !(*cp == '$' && *(cp + 1) == '\0')) { 1228 return 0; 1229 } 1230 } 1231 if ((char *)cp - login_name > _PW_NAME_LEN) 1232 return 0; 1233 return 1; 1234 } 1235 1236 static int 1237 valid_commitid(char *commitid) 1238 { 1239 unsigned char *cp; 1240 1241 /* A-Za-z0-9 */ 1242 for (cp = commitid; *cp ; cp++) { 1243 if (!isalnum(*cp)) 1244 return 0; 1245 } 1246 if ((char *)cp - commitid > RCS_COMMITID_MAXLEN) 1247 return 0; 1248 return 1; 1249 } 1250 1251 static int 1252 kw_cmp(const void *k, const void *e) 1253 { 1254 return (strcmp(k, ((const struct rcs_keyword *)e)->k_name)); 1255 } 1256 1257 static void 1258 rcsparse_warnx(RCSFILE *rfp, char *fmt, ...) 1259 { 1260 struct rcs_pdata *pdp; 1261 va_list ap; 1262 char *msg; 1263 1264 pdp = (struct rcs_pdata *)rfp->rf_pdata; 1265 va_start(ap, fmt); 1266 if (vasprintf(&msg, fmt, ap) == -1) { 1267 cvs_log(LP_ERRNO, "vasprintf"); 1268 va_end(ap); 1269 return; 1270 } 1271 va_end(ap); 1272 cvs_log(LP_ERR, "%s:%d: %s", rfp->rf_path, pdp->rp_msglineno, msg); 1273 free(msg); 1274 } 1275