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