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