1 /* $OpenBSD: rcsparse.c,v 1.6 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 "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 { "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 155 /* 156 * head [REVISION]; 157 * [branch BRANCH]; 158 * access [LOGIN ...]; 159 * symbols [SYMBOL:REVISION ...]; 160 * locks [LOGIN:REVISION ...]; 161 * [strict;] 162 * [comment [@[...]@];] 163 * [expand [@[...]@];] 164 */ 165 static struct rcs_section sec_admin[] = { 166 { RCS_TOK_HEAD, rcsparse_head, MANDATORY }, 167 { RCS_TOK_BRANCH, rcsparse_branch, OPTIONAL }, 168 { RCS_TOK_ACCESS, rcsparse_access, MANDATORY }, 169 { RCS_TOK_SYMBOLS, rcsparse_symbols, MANDATORY }, 170 { RCS_TOK_LOCKS, rcsparse_locks, MANDATORY }, 171 { RCS_TOK_STRICT, rcsparse_strict, OPTIONAL }, 172 { RCS_TOK_COMMENT, rcsparse_comment, OPTIONAL }, 173 { RCS_TOK_EXPAND, rcsparse_expand, OPTIONAL }, 174 { 0, NULL, 0 } 175 }; 176 177 /* 178 * REVISION 179 * date [YY]YY.MM.DD.HH.MM.SS; 180 * author LOGIN; 181 * state STATE; 182 * branches [REVISION ...]; 183 * next [REVISION]; 184 * [commitid ID;] 185 */ 186 static struct rcs_section sec_delta[] = { 187 { RCS_TYPE_REVISION, rcsparse_deltarevision, MANDATORY }, 188 { RCS_TOK_DATE, rcsparse_date, MANDATORY }, 189 { RCS_TOK_AUTHOR, rcsparse_author, MANDATORY }, 190 { RCS_TOK_STATE, rcsparse_state, MANDATORY }, 191 { RCS_TOK_BRANCHES, rcsparse_branches, MANDATORY }, 192 { RCS_TOK_NEXT, rcsparse_next, MANDATORY }, 193 { RCS_TOK_COMMITID, rcsparse_commitid, OPTIONAL }, 194 { 0, NULL, 0 } 195 }; 196 197 /* 198 * REVISION 199 * log @[...]@ 200 * text @[...]@ 201 */ 202 static struct rcs_section sec_deltatext[] = { 203 { RCS_TYPE_REVISION, rcsparse_textrevision, MANDATORY }, 204 { RCS_TOK_LOG, rcsparse_log, MANDATORY }, 205 { RCS_TOK_TEXT, rcsparse_text, MANDATORY }, 206 { 0, NULL, 0 } 207 }; 208 209 /* 210 * rcsparse_init() 211 * 212 * Initializes the parsing data structure and parses the admin section of 213 * RCS file <rfp>. 214 * 215 * Returns 0 on success or 1 on failure. 216 */ 217 int 218 rcsparse_init(RCSFILE *rfp) 219 { 220 struct rcs_pdata *pdp; 221 222 if (rfp->rf_flags & RCS_PARSED) 223 return (0); 224 225 pdp = xmalloc(sizeof(*pdp)); 226 pdp->rp_buf = xmalloc(RCS_BUFSIZE); 227 pdp->rp_blen = RCS_BUFSIZE; 228 pdp->rp_bufend = pdp->rp_buf + pdp->rp_blen - 1; 229 pdp->rp_token = -1; 230 pdp->rp_lineno = 1; 231 pdp->rp_msglineno = 1; 232 233 /* ditch the strict lock */ 234 rfp->rf_flags &= ~RCS_SLOCK; 235 rfp->rf_pdata = pdp; 236 237 if (rcsparse(rfp, sec_admin)) { 238 rcsparse_free(rfp); 239 return (1); 240 } 241 242 if ((rfp->rf_flags & RCS_PARSE_FULLY) && 243 rcsparse_deltatexts(rfp, NULL)) { 244 rcsparse_free(rfp); 245 return (1); 246 } 247 248 rfp->rf_flags |= RCS_SYNCED; 249 return (0); 250 } 251 252 /* 253 * rcsparse_deltas() 254 * 255 * Parse deltas. If <rev> is not NULL, parse only as far as that 256 * revision. If <rev> is NULL, parse all deltas. 257 * 258 * Returns 0 on success or 1 on error. 259 */ 260 int 261 rcsparse_deltas(RCSFILE *rfp, RCSNUM *rev) 262 { 263 int ret; 264 struct rcs_delta *enddelta; 265 266 if ((rfp->rf_flags & PARSED_DELTAS) || (rfp->rf_flags & RCS_CREATE)) 267 return (0); 268 269 for (;;) { 270 ret = rcsparse_delta(rfp); 271 if (rev != NULL) { 272 enddelta = TAILQ_LAST(&(rfp->rf_delta), rcs_dlist); 273 if (enddelta == NULL) 274 return (1); 275 276 if (rcsnum_cmp(enddelta->rd_num, rev, 0) == 0) 277 break; 278 } 279 280 if (ret == 0) { 281 rfp->rf_flags |= PARSED_DELTAS; 282 break; 283 } 284 else if (ret == -1) 285 return (1); 286 } 287 288 return (0); 289 } 290 291 /* 292 * rcsparse_deltatexts() 293 * 294 * Parse deltatexts. If <rev> is not NULL, parse only as far as that 295 * revision. If <rev> is NULL, parse everything. 296 * 297 * Returns 0 on success or 1 on error. 298 */ 299 int 300 rcsparse_deltatexts(RCSFILE *rfp, RCSNUM *rev) 301 { 302 int ret; 303 struct rcs_delta *rdp; 304 305 if ((rfp->rf_flags & PARSED_DELTATEXTS) || 306 (rfp->rf_flags & RCS_CREATE)) 307 return (0); 308 309 if (!(rfp->rf_flags & PARSED_DESC)) 310 if (rcsparse_desc(rfp)) 311 return (1); 312 313 rdp = (rev != NULL) ? rcs_findrev(rfp, rev) : NULL; 314 315 for (;;) { 316 if (rdp != NULL && rdp->rd_text != NULL) 317 break; 318 ret = rcsparse_deltatext(rfp); 319 if (ret == 0) { 320 rfp->rf_flags |= PARSED_DELTATEXTS; 321 break; 322 } 323 else if (ret == -1) 324 return (1); 325 } 326 327 return (0); 328 } 329 330 /* 331 * rcsparse_free() 332 * 333 * Free the contents of the <rfp>'s parser data structure. 334 */ 335 void 336 rcsparse_free(RCSFILE *rfp) 337 { 338 struct rcs_pdata *pdp; 339 340 pdp = rfp->rf_pdata; 341 342 if (pdp->rp_buf != NULL) 343 xfree(pdp->rp_buf); 344 if (pdp->rp_token == RCS_TYPE_REVISION) 345 rcsnum_free(pdp->rp_value.rev); 346 xfree(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 /* XXX - do something with commitid */ 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 xfree(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 xfree(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 xfree(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 type = 0; 918 switch (c) { 919 case '@': 920 ret = rcsparse_string(rfp, allowed); 921 if (ret == EOF && ferror(rfp->rf_file)) { 922 rcsparse_warnx(rfp, "error during parsing"); 923 return (0); 924 } 925 return (ret); 926 /* NOTREACHED */ 927 case ':': 928 type = RCS_TOK_COLON; 929 if (type & allowed) 930 return (type); 931 rcsparse_warnx(rfp, "unexpected token \"%c\"", c); 932 return (0); 933 /* NOTREACHED */ 934 case ';': 935 type = RCS_TOK_SCOLON; 936 if (type & allowed) 937 return (type); 938 rcsparse_warnx(rfp, "unexpected token \"%c\"", c); 939 return (0); 940 /* NOTREACHED */ 941 case ',': 942 type = RCS_TOK_COMMA; 943 if (type & allowed) 944 return (type); 945 rcsparse_warnx(rfp, "unexpected token \"%c\"", c); 946 return (0); 947 /* NOTREACHED */ 948 default: 949 if (!isgraph(c)) { 950 rcsparse_warnx(rfp, "unexpected character 0x%.2X", c); 951 return (0); 952 } 953 break; 954 } 955 allowed &= ~(RCS_TOK_COLON|RCS_TOK_SCOLON|RCS_TOK_COMMA); 956 957 bp = pdp->rp_buf; 958 pdp->rp_tlen = 0; 959 *bp = '\0'; 960 961 for (;;) { 962 if (c == EOF) { 963 if (ferror(rfp->rf_file)) 964 rcsparse_warnx(rfp, "error during parsing"); 965 else 966 rcsparse_warnx(rfp, "unexpected end of file"); 967 return (0); 968 } else if (c == '\n') 969 pdp->rp_lineno++; 970 971 RBUF_PUTC(c); 972 973 c = getc(rfp->rf_file); 974 975 if (isspace(c)) { 976 if (c == '\n') 977 pdp->rp_lineno++; 978 RBUF_PUTC('\0'); 979 break; 980 } else if (c == ';' || c == ':' || c == ',') { 981 ungetc(c, rfp->rf_file); 982 RBUF_PUTC('\0'); 983 break; 984 } else if (!isgraph(c)) { 985 rcsparse_warnx(rfp, "unexpected character 0x%.2X", c); 986 return (0); 987 } 988 } 989 990 switch (allowed) { 991 case RCS_TYPE_COMMITID: 992 /* XXX validate commitid */ 993 break; 994 case RCS_TYPE_LOGIN: 995 if (!valid_login(pdp->rp_buf)) { 996 rcsparse_warnx(rfp, "invalid login \"%s\"", 997 pdp->rp_buf); 998 return (0); 999 } 1000 pdp->rp_value.str = xstrdup(pdp->rp_buf); 1001 break; 1002 case RCS_TYPE_SYMBOL: 1003 if (!rcs_sym_check(pdp->rp_buf)) { 1004 rcsparse_warnx(rfp, "invalid symbol \"%s\"", 1005 pdp->rp_buf); 1006 return (0); 1007 } 1008 pdp->rp_value.str = xstrdup(pdp->rp_buf); 1009 break; 1010 /* FALLTHROUGH */ 1011 case RCS_TYPE_STATE: 1012 if (rcs_state_check(pdp->rp_buf)) { 1013 rcsparse_warnx(rfp, "invalid state \"%s\"", 1014 pdp->rp_buf); 1015 return (0); 1016 } 1017 pdp->rp_value.str = xstrdup(pdp->rp_buf); 1018 break; 1019 case RCS_TYPE_DATE: 1020 if ((datenum = rcsnum_parse(pdp->rp_buf)) == NULL) { 1021 rcsparse_warnx(rfp, "invalid date \"%s\"", pdp->rp_buf); 1022 return (0); 1023 } 1024 if (datenum->rn_len != 6) { 1025 rcsnum_free(datenum); 1026 rcsparse_warnx(rfp, "invalid date \"%s\"", pdp->rp_buf); 1027 return (0); 1028 } 1029 pdp->rp_value.date.tm_year = datenum->rn_id[0]; 1030 if (pdp->rp_value.date.tm_year >= 1900) 1031 pdp->rp_value.date.tm_year -= 1900; 1032 pdp->rp_value.date.tm_mon = datenum->rn_id[1] - 1; 1033 pdp->rp_value.date.tm_mday = datenum->rn_id[2]; 1034 pdp->rp_value.date.tm_hour = datenum->rn_id[3]; 1035 pdp->rp_value.date.tm_min = datenum->rn_id[4]; 1036 pdp->rp_value.date.tm_sec = datenum->rn_id[5]; 1037 rcsnum_free(datenum); 1038 break; 1039 case RCS_TYPE_NUMBER: 1040 pdp->rp_value.rev = rcsnum_parse(pdp->rp_buf); 1041 if (pdp->rp_value.rev == NULL) { 1042 rcsparse_warnx(rfp, "invalid number \"%s\"", 1043 pdp->rp_buf); 1044 return (0); 1045 } 1046 break; 1047 case RCS_TYPE_BRANCH: 1048 pdp->rp_value.rev = rcsnum_parse(pdp->rp_buf); 1049 if (pdp->rp_value.rev == NULL) { 1050 rcsparse_warnx(rfp, "invalid branch \"%s\"", 1051 pdp->rp_buf); 1052 return (0); 1053 } 1054 if (!RCSNUM_ISBRANCH(pdp->rp_value.rev)) { 1055 rcsnum_free(pdp->rp_value.rev); 1056 rcsparse_warnx(rfp, "expected branch, got \"%s\"", 1057 pdp->rp_buf); 1058 return (0); 1059 } 1060 break; 1061 case RCS_TYPE_KEYWORD: 1062 if (islower(*pdp->rp_buf)) { 1063 p = bsearch(pdp->rp_buf, keywords, 1064 sizeof(keywords) / sizeof(keywords[0]), 1065 sizeof(keywords[0]), kw_cmp); 1066 if (p != NULL) 1067 return (p->k_val); 1068 } 1069 allowed = RCS_TYPE_REVISION; 1070 /* FALLTHROUGH */ 1071 case RCS_TYPE_REVISION: 1072 pdp->rp_value.rev = rcsnum_parse(pdp->rp_buf); 1073 if (pdp->rp_value.rev != NULL) { 1074 if (RCSNUM_ISBRANCH(pdp->rp_value.rev)) { 1075 rcsnum_free(pdp->rp_value.rev); 1076 rcsparse_warnx(rfp, 1077 "expected revision, got \"%s\"", 1078 pdp->rp_buf); 1079 return (0); 1080 } 1081 break; 1082 } 1083 /* FALLTHROUGH */ 1084 default: 1085 RBUF_PUTC('\0'); 1086 rcsparse_warnx(rfp, "unexpected token \"%s\"", pdp->rp_buf); 1087 return (0); 1088 /* NOTREACHED */ 1089 } 1090 1091 return (allowed); 1092 } 1093 1094 static int 1095 rcsparse(RCSFILE *rfp, struct rcs_section *sec) 1096 { 1097 struct rcs_pdata *pdp; 1098 int i, token; 1099 1100 pdp = (struct rcs_pdata *)rfp->rf_pdata; 1101 i = 0; 1102 1103 token = 0; 1104 for (i = 0; sec[i].token != 0; i++) { 1105 token = rcsparse_token(rfp, RCS_TYPE_KEYWORD); 1106 if (token == 0) 1107 return (1); 1108 1109 while (token != sec[i].token) { 1110 if (sec[i].parse == NULL) 1111 goto end; 1112 if (sec[i].opt) { 1113 i++; 1114 continue; 1115 } 1116 if (token == EOF || (!(rfp->rf_flags & PARSED_DELTAS) && 1117 token == RCS_TOK_DESC)) 1118 goto end; 1119 rcsparse_warnx(rfp, "unexpected token \"%s\"", 1120 pdp->rp_buf); 1121 return (1); 1122 } 1123 1124 if (sec[i].parse(rfp, pdp)) 1125 return (1); 1126 } 1127 end: 1128 if (token == RCS_TYPE_REVISION) 1129 pdp->rp_token = token; 1130 else if (token == RCS_TOK_DESC) 1131 pdp->rp_token = RCS_TOK_DESC; 1132 else if (token == EOF) 1133 rfp->rf_flags |= RCS_PARSED; 1134 1135 return (0); 1136 } 1137 1138 static int 1139 rcsparse_deltatext(RCSFILE *rfp) 1140 { 1141 int ret; 1142 1143 if (rfp->rf_flags & PARSED_DELTATEXTS) 1144 return (0); 1145 1146 if (!(rfp->rf_flags & PARSED_DESC)) 1147 if ((ret = rcsparse_desc(rfp))) 1148 return (ret); 1149 1150 if (rcsparse(rfp, sec_deltatext)) 1151 return (-1); 1152 1153 if (rfp->rf_flags & RCS_PARSED) 1154 rfp->rf_flags |= PARSED_DELTATEXTS; 1155 1156 return (1); 1157 } 1158 1159 static int 1160 rcsparse_delta(RCSFILE *rfp) 1161 { 1162 struct rcs_pdata *pdp; 1163 1164 if (rfp->rf_flags & PARSED_DELTAS) 1165 return (0); 1166 1167 pdp = (struct rcs_pdata *)rfp->rf_pdata; 1168 if (pdp->rp_token == RCS_TOK_DESC) { 1169 rfp->rf_flags |= PARSED_DELTAS; 1170 return (0); 1171 } 1172 1173 if (rcsparse(rfp, sec_delta)) 1174 return (-1); 1175 1176 if (pdp->rp_delta != NULL) { 1177 TAILQ_INSERT_TAIL(&rfp->rf_delta, pdp->rp_delta, rd_list); 1178 pdp->rp_delta = NULL; 1179 rfp->rf_ndelta++; 1180 return (1); 1181 } 1182 1183 return (0); 1184 } 1185 1186 /* 1187 * rcsparse_growbuf() 1188 * 1189 * Attempt to grow the internal parse buffer for the RCS file <rf> by 1190 * RCS_BUFEXTSIZE. 1191 * In case of failure, the original buffer is left unmodified. 1192 */ 1193 static void 1194 rcsparse_growbuf(RCSFILE *rfp) 1195 { 1196 struct rcs_pdata *pdp = (struct rcs_pdata *)rfp->rf_pdata; 1197 1198 pdp->rp_buf = xrealloc(pdp->rp_buf, 1, 1199 pdp->rp_blen + RCS_BUFEXTSIZE); 1200 pdp->rp_blen += RCS_BUFEXTSIZE; 1201 pdp->rp_bufend = pdp->rp_buf + pdp->rp_blen - 1; 1202 } 1203 1204 /* 1205 * Borrowed from src/usr.sbin/user/user.c: 1206 * return 1 if `login' is a valid login name 1207 */ 1208 static int 1209 valid_login(char *login_name) 1210 { 1211 unsigned char *cp; 1212 1213 /* The first character cannot be a hyphen */ 1214 if (*login_name == '-') 1215 return 0; 1216 1217 for (cp = login_name ; *cp ; cp++) { 1218 /* We allow '$' as the last character for samba */ 1219 if (!isalnum(*cp) && *cp != '.' && *cp != '_' && *cp != '-' && 1220 !(*cp == '$' && *(cp + 1) == '\0')) { 1221 return 0; 1222 } 1223 } 1224 if ((char *)cp - login_name > _PW_NAME_LEN) 1225 return 0; 1226 return 1; 1227 } 1228 1229 static int 1230 kw_cmp(const void *k, const void *e) 1231 { 1232 return (strcmp(k, ((const struct rcs_keyword *)e)->k_name)); 1233 } 1234 1235 static void 1236 rcsparse_warnx(RCSFILE *rfp, char *fmt, ...) 1237 { 1238 struct rcs_pdata *pdp; 1239 va_list ap; 1240 char *nfmt; 1241 1242 pdp = (struct rcs_pdata *)rfp->rf_pdata; 1243 va_start(ap, fmt); 1244 if (asprintf(&nfmt, "%s:%d: %s", rfp->rf_path, pdp->rp_msglineno, fmt) 1245 == -1) 1246 nfmt = fmt; 1247 cvs_vlog(LP_ERR, nfmt, ap); 1248 va_end(ap); 1249 if (nfmt != fmt) 1250 free(nfmt); 1251 } 1252