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_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 = xcalloc(1, 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 free(pdp->rp_buf); 345 if (pdp->rp_token == RCS_TYPE_REVISION) 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) 366 return (0); 367 368 if (!(rfp->rf_flags & PARSED_DELTAS) && rcsparse_deltas(rfp, NULL)) 369 return (1); 370 371 pdp = (struct rcs_pdata *)rfp->rf_pdata; 372 373 if (rcsparse_token(rfp, RCS_TOK_DESC) != RCS_TOK_DESC || 374 rcsparse_token(rfp, RCS_TYPE_STRING) != RCS_TYPE_STRING) 375 return (1); 376 377 rfp->rf_desc = pdp->rp_value.str; 378 rfp->rf_flags |= PARSED_DESC; 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); 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) != RCS_TYPE_DATE) 420 return (1); 421 422 pdp->rp_delta->rd_date = pdp->rp_value.date; 423 424 return (rcsparse_token(rfp, RCS_TOK_SCOLON) != RCS_TOK_SCOLON); 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) != RCS_TYPE_LOGIN) 440 return (1); 441 442 pdp->rp_delta->rd_author = pdp->rp_value.str; 443 444 return (rcsparse_token(rfp, RCS_TOK_SCOLON) != RCS_TOK_SCOLON); 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) != RCS_TYPE_STATE) 460 return (1); 461 462 pdp->rp_delta->rd_state = pdp->rp_value.str; 463 464 return (rcsparse_token(rfp, RCS_TOK_SCOLON) != RCS_TOK_SCOLON); 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|RCS_TYPE_REVISION)) 483 == RCS_TYPE_REVISION) { 484 rb = xmalloc(sizeof(*rb)); 485 rb->rb_num = pdp->rp_value.rev; 486 TAILQ_INSERT_TAIL(&(pdp->rp_delta->rd_branches), rb, rb_list); 487 } 488 489 return (type != RCS_TOK_SCOLON); 490 } 491 492 /* 493 * rcsparse_next() 494 * 495 * Parses the specified next revision of current delta pdp->rp_delta. 496 * 497 * next [REVISION]; 498 * 499 * Returns 0 on success or 1 on failure. 500 */ 501 static int 502 rcsparse_next(RCSFILE *rfp, struct rcs_pdata *pdp) 503 { 504 int type; 505 506 type = rcsparse_token(rfp, RCS_TYPE_REVISION|RCS_TOK_SCOLON); 507 if (type == RCS_TYPE_REVISION) { 508 pdp->rp_delta->rd_next = pdp->rp_value.rev; 509 type = rcsparse_token(rfp, RCS_TOK_SCOLON); 510 } else 511 pdp->rp_delta->rd_next = rcsnum_alloc(); 512 513 return (type != RCS_TOK_SCOLON); 514 } 515 516 /* 517 * rcsparse_commitid() 518 * 519 * Parses the specified commit id of current delta pdp->rp_delta. The 520 * commitid keyword is optional and can be omitted. 521 * 522 * [commitid ID;] 523 * 524 * Returns 0 on success or 1 on failure. 525 */ 526 static int 527 rcsparse_commitid(RCSFILE *rfp, struct rcs_pdata *pdp) 528 { 529 if (rcsparse_token(rfp, RCS_TYPE_COMMITID) != RCS_TYPE_COMMITID) 530 return (1); 531 532 pdp->rp_delta->rd_commitid = pdp->rp_value.str; 533 534 return (rcsparse_token(rfp, RCS_TOK_SCOLON) != RCS_TOK_SCOLON); 535 } 536 537 /* 538 * rcsparse_textrevision() 539 * 540 * Called upon reaching a new REVISION entry in the delta text section. 541 * pdp->rp_delta will be set to REVISION's delta (created in delta section) 542 * for further parsing. 543 * 544 * REVISION 545 * 546 * Returns 0 on success or 1 on failure. 547 */ 548 static int 549 rcsparse_textrevision(RCSFILE *rfp, struct rcs_pdata *pdp) 550 { 551 struct rcs_delta *rdp; 552 553 TAILQ_FOREACH(rdp, &rfp->rf_delta, rd_list) { 554 if (rcsnum_cmp(rdp->rd_num, pdp->rp_value.rev, 0) == 0) 555 break; 556 } 557 if (rdp == NULL) { 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) != RCS_TYPE_STRING) 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) != RCS_TYPE_STRING) 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|RCS_TOK_SCOLON); 632 if (type == RCS_TYPE_REVISION) { 633 rfp->rf_head = pdp->rp_value.rev; 634 type = rcsparse_token(rfp, RCS_TOK_SCOLON); 635 } 636 637 return (type != RCS_TOK_SCOLON); 638 } 639 640 /* 641 * rcsparse_branch() 642 * 643 * Parses the default branch of RCS file <rfp>. The branch keyword is 644 * optional and can be omitted. 645 * 646 * [branch BRANCH;] 647 * 648 * Returns 0 on success or 1 on failure. 649 */ 650 static int 651 rcsparse_branch(RCSFILE *rfp, struct rcs_pdata *pdp) 652 { 653 int type; 654 655 type = rcsparse_token(rfp, RCS_TYPE_BRANCH|RCS_TOK_SCOLON); 656 if (type == RCS_TYPE_BRANCH) { 657 rfp->rf_branch = pdp->rp_value.rev; 658 type = rcsparse_token(rfp, RCS_TOK_SCOLON); 659 } 660 661 return (type != RCS_TOK_SCOLON); 662 } 663 664 /* 665 * rcsparse_access() 666 * 667 * Parses the access list of RCS file <rfp>. 668 * 669 * access [LOGIN ...]; 670 * 671 * Returns 0 on success or 1 on failure. 672 */ 673 static int 674 rcsparse_access(RCSFILE *rfp, struct rcs_pdata *pdp) 675 { 676 struct rcs_access *ap; 677 int type; 678 679 while ((type = rcsparse_token(rfp, RCS_TOK_SCOLON|RCS_TYPE_LOGIN)) 680 == RCS_TYPE_LOGIN) { 681 ap = xmalloc(sizeof(*ap)); 682 ap->ra_name = pdp->rp_value.str; 683 TAILQ_INSERT_TAIL(&(rfp->rf_access), ap, ra_list); 684 } 685 686 return (type != RCS_TOK_SCOLON); 687 } 688 689 /* 690 * rcsparse_symbols() 691 * 692 * Parses the symbol list of RCS file <rfp>. 693 * 694 * symbols [SYMBOL:REVISION ...]; 695 * 696 * Returns 0 on success or 1 on failure. 697 */ 698 static int 699 rcsparse_symbols(RCSFILE *rfp, struct rcs_pdata *pdp) 700 { 701 struct rcs_sym *symp; 702 char *name; 703 int type; 704 705 while ((type = rcsparse_token(rfp, RCS_TOK_SCOLON|RCS_TYPE_SYMBOL)) == 706 RCS_TYPE_SYMBOL) { 707 name = pdp->rp_value.str; 708 if (rcsparse_token(rfp, RCS_TOK_COLON) != RCS_TOK_COLON || 709 rcsparse_token(rfp, RCS_TYPE_NUMBER) != RCS_TYPE_NUMBER) { 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); 717 } 718 719 return (type != RCS_TOK_SCOLON); 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|RCS_TYPE_LOGIN)) == 739 RCS_TYPE_LOGIN) { 740 name = pdp->rp_value.str; 741 if (rcsparse_token(rfp, RCS_TOK_COLON) != RCS_TOK_COLON || 742 rcsparse_token(rfp, RCS_TYPE_REVISION) != 743 RCS_TYPE_REVISION) { 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); 751 } 752 753 return (type != RCS_TOK_SCOLON); 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; 770 771 return (rcsparse_token(rfp, RCS_TOK_SCOLON) != RCS_TOK_SCOLON); 772 } 773 774 /* 775 * rcsparse_comment() 776 * 777 * Parses the comment of RCS file <rfp>. The comment keyword is optional 778 * and can be omitted. 779 * 780 * [comment [@[...]@];] 781 * 782 * Returns 0 on success or 1 on failure. 783 */ 784 static int 785 rcsparse_comment(RCSFILE *rfp, struct rcs_pdata *pdp) 786 { 787 int type; 788 789 type = rcsparse_token(rfp, RCS_TYPE_STRING|RCS_TOK_SCOLON); 790 if (type == RCS_TYPE_STRING) { 791 rfp->rf_comment = pdp->rp_value.str; 792 type = rcsparse_token(rfp, RCS_TOK_SCOLON); 793 } 794 795 return (type != RCS_TOK_SCOLON); 796 } 797 798 /* 799 * rcsparse_expand() 800 * 801 * Parses expand of RCS file <rfp>. The expand keyword is optional and 802 * can be omitted. 803 * 804 * [expand [@[...]@];] 805 * 806 * Returns 0 on success or 1 on failure. 807 */ 808 static int 809 rcsparse_expand(RCSFILE *rfp, struct rcs_pdata *pdp) 810 { 811 int type; 812 813 type = rcsparse_token(rfp, RCS_TYPE_STRING|RCS_TOK_SCOLON); 814 if (type == RCS_TYPE_STRING) { 815 rfp->rf_expand = pdp->rp_value.str; 816 type = rcsparse_token(rfp, RCS_TOK_SCOLON); 817 } 818 819 return (type != RCS_TOK_SCOLON); 820 } 821 822 #define RBUF_PUTC(ch) \ 823 do { \ 824 if (bp == pdp->rp_bufend - 1) { \ 825 len = bp - pdp->rp_buf; \ 826 rcsparse_growbuf(rfp); \ 827 bp = pdp->rp_buf + len; \ 828 } \ 829 *(bp++) = (ch); \ 830 pdp->rp_tlen++; \ 831 } while (0); 832 833 static int 834 rcsparse_string(RCSFILE *rfp, int allowed) 835 { 836 struct rcs_pdata *pdp; 837 int c; 838 size_t len; 839 char *bp; 840 841 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); 849 if (c == '@') { 850 c = getc(rfp->rf_file); 851 if (c == EOF) { 852 return (EOF); 853 } else if (c != '@') { 854 ungetc(c, rfp->rf_file); 855 break; 856 } 857 } 858 859 if (c == EOF) { 860 return (EOF); 861 } else if (c == '\n') 862 pdp->rp_lineno++; 863 864 RBUF_PUTC(c); 865 } 866 867 bp = pdp->rp_buf + pdp->rp_tlen; 868 RBUF_PUTC('\0'); 869 870 if (!(allowed & RCS_TYPE_STRING)) { 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); 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; 901 do { 902 pre = c; 903 c = getc(rfp->rf_file); 904 if (c == EOF) { 905 if (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); 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 && 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; 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; 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; 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|RCS_TOK_SCOLON|RCS_TOK_COMMA); 957 958 bp = pdp->rp_buf; 959 pdp->rp_tlen = 0; 960 *bp = '\0'; 961 962 for (;;) { 963 if (c == EOF) { 964 if (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); 973 974 c = getc(rfp->rf_file); 975 976 if (isspace(c)) { 977 if (c == '\n') 978 pdp->rp_lineno++; 979 RBUF_PUTC('\0'); 980 break; 981 } else if (c == ';' || c == ':' || c == ',') { 982 ungetc(c, rfp->rf_file); 983 RBUF_PUTC('\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: 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: 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: 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: 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: 1026 if ((datenum = rcsnum_parse(pdp->rp_buf)) == NULL) { 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: 1046 pdp->rp_value.rev = rcsnum_parse(pdp->rp_buf); 1047 if (pdp->rp_value.rev == NULL) { 1048 rcsparse_warnx(rfp, "invalid number \"%s\"", 1049 pdp->rp_buf); 1050 return (0); 1051 } 1052 break; 1053 case RCS_TYPE_BRANCH: 1054 pdp->rp_value.rev = rcsnum_parse(pdp->rp_buf); 1055 if (pdp->rp_value.rev == NULL) { 1056 rcsparse_warnx(rfp, "invalid branch \"%s\"", 1057 pdp->rp_buf); 1058 return (0); 1059 } 1060 if (!RCSNUM_ISBRANCH(pdp->rp_value.rev)) { 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: 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) 1073 return (p->k_val); 1074 } 1075 allowed = RCS_TYPE_REVISION; 1076 /* FALLTHROUGH */ 1077 case RCS_TYPE_REVISION: 1078 pdp->rp_value.rev = rcsnum_parse(pdp->rp_buf); 1079 if (pdp->rp_value.rev != NULL) { 1080 if (RCSNUM_ISBRANCH(pdp->rp_value.rev)) { 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'); 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; 1108 1109 token = 0; 1110 for (i = 0; sec[i].token != 0; i++) { 1111 token = rcsparse_token(rfp, RCS_TYPE_KEYWORD); 1112 if (token == 0) 1113 return (1); 1114 1115 while (token != sec[i].token) { 1116 if (sec[i].parse == NULL) 1117 goto end; 1118 if (sec[i].opt) { 1119 i++; 1120 continue; 1121 } 1122 if (token == EOF || (!(rfp->rf_flags & PARSED_DELTAS) && 1123 token == RCS_TOK_DESC)) 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) 1135 pdp->rp_token = token; 1136 else if (token == RCS_TOK_DESC) 1137 pdp->rp_token = RCS_TOK_DESC; 1138 else if (token == EOF) 1139 rfp->rf_flags |= RCS_PARSED; 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) 1150 return (0); 1151 1152 if (!(rfp->rf_flags & PARSED_DESC)) 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) 1160 rfp->rf_flags |= PARSED_DELTATEXTS; 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) 1171 return (0); 1172 1173 pdp = (struct rcs_pdata *)rfp->rf_pdata; 1174 if (pdp->rp_token == RCS_TOK_DESC) { 1175 rfp->rf_flags |= PARSED_DELTAS; 1176 return (0); 1177 } 1178 1179 if (rcsparse(rfp, sec_delta)) 1180 return (-1); 1181 1182 if (pdp->rp_delta != NULL) { 1183 TAILQ_INSERT_TAIL(&rfp->rf_delta, pdp->rp_delta, rd_list); 1184 pdp->rp_delta = NULL; 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_BUFEXTSIZE); 1206 pdp->rp_blen += RCS_BUFEXTSIZE; 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_LEN) 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_MAXLEN) 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); 1265 if (vasprintf(&msg, fmt, ap) == -1) { 1266 cvs_log(LP_ERRNO, "vasprintf"); 1267 va_end(ap); 1268 return; 1269 } 1270 va_end(ap); 1271 cvs_log(LP_ERR, "%s:%d: %s", rfp->rf_path, pdp->rp_msglineno, msg); 1272 free(msg); 1273 } 1274