1 /* 2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc. 3 * 4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, 5 * and others. 6 * 7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk 8 * Portions Copyright (C) 1989-1992, Brian Berliner 9 * 10 * You may distribute under the terms of the GNU General Public License as 11 * specified in the README file that comes with the CVS source distribution. 12 * 13 * The routines contained in this file do all the rcs file parsing and 14 * manipulation 15 */ 16 17 #include "cvs.h" 18 #include "edit.h" 19 #include "hardlink.h" 20 21 /* These need to be source after cvs.h or HAVE_MMAP won't be set... */ 22 #ifdef HAVE_MMAP 23 # include "getpagesize.h" 24 # include <sys/mman.h> 25 26 /* Define MAP_FILE when it isn't otherwise. */ 27 # ifndef MAP_FILE 28 # define MAP_FILE 0 29 # endif 30 /* Define MAP_FAILED for old systems which neglect to. */ 31 # ifndef MAP_FAILED 32 # define MAP_FAILED ((void *)-1) 33 # endif 34 #endif 35 36 /* The RCS -k options, and a set of enums that must match the array. 37 These come first so that we can use enum kflag in function 38 prototypes. */ 39 static const char *const kflags[] = 40 {"kv", "kvl", "k", "v", "o", "b", NULL}; 41 enum kflag { KFLAG_KV = 0, KFLAG_KVL, KFLAG_K, KFLAG_V, KFLAG_O, KFLAG_B }; 42 43 /* A structure we use to buffer the contents of an RCS file. The 44 various fields are only referenced directly by the rcsbuf_* 45 functions. We declare the struct here so that we can allocate it 46 on the stack, rather than in memory. */ 47 48 struct rcsbuffer 49 { 50 /* Points to the current position in the buffer. */ 51 char *ptr; 52 /* Points just after the last valid character in the buffer. */ 53 char *ptrend; 54 /* The file. */ 55 FILE *fp; 56 /* The name of the file, used for error messages. */ 57 const char *filename; 58 /* The starting file position of the data in the buffer. */ 59 unsigned long pos; 60 /* The length of the value. */ 61 size_t vlen; 62 /* Whether the value contains an '@' string. If so, we can not 63 compress whitespace characters. */ 64 int at_string; 65 /* The number of embedded '@' characters in an '@' string. If 66 this is non-zero, we must search the string for pairs of '@' 67 and convert them to a single '@'. */ 68 int embedded_at; 69 }; 70 71 static RCSNode *RCS_parsercsfile_i (FILE * fp, const char *rcsfile); 72 static char *RCS_getdatebranch (RCSNode * rcs, const char *date, 73 const char *branch); 74 static void rcsbuf_open (struct rcsbuffer *, FILE *fp, 75 const char *filename, unsigned long pos); 76 static void rcsbuf_close (struct rcsbuffer *); 77 static int rcsbuf_getkey (struct rcsbuffer *, char **keyp, char **valp); 78 static int rcsbuf_getrevnum (struct rcsbuffer *, char **revp); 79 static char *rcsbuf_fill (struct rcsbuffer *, char *ptr, char **keyp, 80 char **valp); 81 static int rcsbuf_valcmp (struct rcsbuffer *); 82 static char *rcsbuf_valcopy (struct rcsbuffer *, char *val, int polish, 83 size_t *lenp); 84 static void rcsbuf_valpolish (struct rcsbuffer *, char *val, int polish, 85 size_t *lenp); 86 static void rcsbuf_valpolish_internal (struct rcsbuffer *, char *to, 87 const char *from, size_t *lenp); 88 static off_t rcsbuf_ftello (struct rcsbuffer *); 89 static void rcsbuf_get_buffered (struct rcsbuffer *, char **datap, 90 size_t *lenp); 91 static void rcsbuf_cache (RCSNode *, struct rcsbuffer *); 92 static void rcsbuf_cache_close (void); 93 static void rcsbuf_cache_open (RCSNode *, off_t, FILE **, struct rcsbuffer *); 94 static int checkmagic_proc (Node *p, void *closure); 95 static void do_branches (List * list, char *val); 96 static void do_symbols (List * list, char *val); 97 static void do_locks (List * list, char *val); 98 static void free_rcsnode_contents (RCSNode *); 99 static void free_rcsvers_contents (RCSVers *); 100 static void rcsvers_delproc (Node * p); 101 static char *translate_symtag (RCSNode *, const char *); 102 static char *RCS_addbranch (RCSNode *, const char *); 103 static char *truncate_revnum_in_place (char *); 104 static char *truncate_revnum (const char *); 105 static char *printable_date (const char *); 106 static char *escape_keyword_value (const char *, int *); 107 static void expand_keywords (RCSNode *, RCSVers *, const char *, 108 const char *, size_t, enum kflag, char *, 109 size_t, char **, size_t *); 110 static void cmp_file_buffer (void *, const char *, size_t); 111 112 /* Routines for reading, parsing and writing RCS files. */ 113 static RCSVers *getdelta (struct rcsbuffer *, char *, char **, char **); 114 static Deltatext *RCS_getdeltatext (RCSNode *, FILE *, struct rcsbuffer *); 115 static void freedeltatext (Deltatext *); 116 117 static void RCS_putadmin (RCSNode *, FILE *); 118 static void RCS_putdtree (RCSNode *, char *, FILE *); 119 static void RCS_putdesc (RCSNode *, FILE *); 120 static void putdelta (RCSVers *, FILE *); 121 static int putrcsfield_proc (Node *, void *); 122 static int putsymbol_proc (Node *, void *); 123 static void RCS_copydeltas (RCSNode *, FILE *, struct rcsbuffer *, FILE *, 124 Deltatext *, char *); 125 static int count_delta_actions (Node *, void *); 126 static void putdeltatext (FILE *, Deltatext *); 127 128 static FILE *rcs_internal_lockfile (char *); 129 static void rcs_internal_unlockfile (FILE *, char *); 130 static char *rcs_lockfilename (const char *); 131 132 /* The RCS file reading functions are called a lot, and they do some 133 string comparisons. This macro speeds things up a bit by skipping 134 the function call when the first characters are different. It 135 evaluates its arguments multiple times. */ 136 #define STREQ(a, b) (*(char *)(a) == *(char *)(b) && strcmp ((a), (b)) == 0) 137 138 static char * getfullCVSname (char *, char **); 139 140 /* 141 * We don't want to use isspace() from the C library because: 142 * 143 * 1. The definition of "whitespace" in RCS files includes ASCII 144 * backspace, but the C locale doesn't. 145 * 2. isspace is an very expensive function call in some implementations 146 * due to the addition of wide character support. 147 */ 148 static const char spacetab[] = { 149 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x00 - 0x0f */ 150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */ 151 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */ 152 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */ 153 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */ 154 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */ 155 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x8f */ 156 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */ 157 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */ 158 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */ 159 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */ 160 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */ 161 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */ 162 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */ 163 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */ 164 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0 - 0xff */ 165 }; 166 167 #define whitespace(c) (spacetab[(unsigned char)c] != 0) 168 169 static char *rcs_lockfile = NULL; 170 static int rcs_lockfd = -1; 171 172 173 174 /* 175 * char * 176 * locate_rcs ( const char* file, const char *repository , int *inattic ) 177 * 178 * Find an RCS file in the repository, case insensitively when the cased name 179 * doesn't exist, we are running as the server, and a client has asked us to 180 * ignore case. 181 * 182 * Most parts of CVS will want to rely instead on RCS_parse which calls this 183 * function and is called by recurse.c which then puts the result in useful 184 * places like the rcs field of struct file_info. 185 * 186 * INPUTS 187 * 188 * repository the repository (including the directory) 189 * file the filename within that directory (without RCSEXT). 190 * inattic NULL or a pointer to the output boolean 191 * 192 * OUTPUTS 193 * 194 * inattic If this input was non-null, the destination will be 195 * set to true if the file was found in the attic or 196 * false if not. If no RCS file is found, this value 197 * is undefined. 198 * 199 * RETURNS 200 * 201 * a newly-malloc'd array containing the absolute pathname of the RCS 202 * file that was found or NULL when none was found. 203 * 204 * ERRORS 205 * 206 * errno can be set by the return value of the final call to 207 * locate_file_in_dir(). This should resolve to the system's existence error 208 * value (sometime ENOENT) if the Attic directory did not exist and ENOENT if 209 * the Attic was found but no matching files were found in the Attic or its 210 * parent. 211 */ 212 static char * 213 locate_rcs (const char *repository, const char *file, int *inattic) 214 { 215 char *retval; 216 217 /* First, try to find the file as cased. */ 218 retval = xmalloc (strlen (repository) 219 + sizeof (CVSATTIC) 220 + strlen (file) 221 + sizeof (RCSEXT) 222 + 3); 223 sprintf (retval, "%s/%s%s", repository, file, RCSEXT); 224 if (isreadable (retval)) 225 { 226 if (inattic) 227 *inattic = 0; 228 return retval; 229 } 230 sprintf (retval, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT); 231 if (isreadable (retval)) 232 { 233 if (inattic) 234 *inattic = 1; 235 return retval; 236 } 237 free (retval); 238 239 return NULL; 240 } 241 242 243 244 /* A few generic thoughts on error handling, in particular the 245 printing of unexpected characters that we find in the RCS file 246 (that is, why we use '\x%x' rather than %c or some such). 247 248 * Avoiding %c means we don't have to worry about what is printable 249 and other such stuff. In error handling, often better to keep it 250 simple. 251 252 * Hex rather than decimal or octal because character set standards 253 tend to use hex. 254 255 * Saying "character 0x%x" might make it sound like we are printing 256 a file offset. So we use '\x%x'. 257 258 * Would be nice to print the offset within the file, but I can 259 imagine various portability hassles (in particular, whether 260 unsigned long is always big enough to hold file offsets). */ 261 262 /* Parse an rcsfile given a user file name and a repository. If there is 263 an error, we print an error message and return NULL. If the file 264 does not exist, we return NULL without printing anything (I'm not 265 sure this allows the caller to do anything reasonable, but it is 266 the current behavior). */ 267 RCSNode * 268 RCS_parse (const char *file, const char *repos) 269 { 270 RCSNode *rcs; 271 FILE *fp; 272 RCSNode *retval = NULL; 273 char *rcsfile; 274 int inattic; 275 276 /* We're creating a new RCSNode, so there is no hope of finding it 277 in the cache. */ 278 rcsbuf_cache_close (); 279 280 if (!(rcsfile = locate_rcs (repos, file, &inattic))) 281 { 282 /* Handle the error cases */ 283 } 284 else if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ))) 285 { 286 rcs = RCS_parsercsfile_i (fp, rcsfile); 287 if (rcs) 288 { 289 rcs->flags |= VALID; 290 if (inattic) 291 rcs->flags |= INATTIC; 292 } 293 294 free (rcsfile); 295 retval = rcs; 296 } 297 else if (!existence_error (errno)) 298 { 299 error (0, errno, "cannot open `%s'", rcsfile); 300 free (rcsfile); 301 } 302 303 return retval; 304 } 305 306 307 308 /* 309 * Parse a specific rcsfile. 310 */ 311 RCSNode * 312 RCS_parsercsfile (const char *rcsfile) 313 { 314 FILE *fp; 315 RCSNode *rcs; 316 317 /* We're creating a new RCSNode, so there is no hope of finding it 318 in the cache. */ 319 rcsbuf_cache_close (); 320 321 /* open the rcsfile */ 322 if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) == NULL) 323 { 324 error (0, errno, "Couldn't open rcs file `%s'", rcsfile); 325 return NULL; 326 } 327 328 rcs = RCS_parsercsfile_i (fp, rcsfile); 329 330 return rcs; 331 } 332 333 334 335 /* 336 */ 337 static RCSNode * 338 RCS_parsercsfile_i (FILE *fp, const char *rcsfile) 339 { 340 RCSNode *rdata; 341 struct rcsbuffer rcsbuf; 342 char *key, *value; 343 344 /* make a node */ 345 rdata = xmalloc (sizeof (RCSNode)); 346 memset (rdata, 0, sizeof (RCSNode)); 347 rdata->refcount = 1; 348 rdata->path = xstrdup (rcsfile); 349 rdata->print_path = xstrdup (primary_root_inverse_translate (rcsfile)); 350 351 /* Process HEAD, BRANCH, and EXPAND keywords from the RCS header. 352 353 Most cvs operations on the main branch don't need any more 354 information. Those that do call RCS_reparsercsfile to parse 355 the rest of the header and the deltas. */ 356 357 rcsbuf_open (&rcsbuf, fp, rcsfile, 0); 358 359 if (! rcsbuf_getkey (&rcsbuf, &key, &value)) 360 goto l_error; 361 if (STREQ (key, RCSDESC)) 362 goto l_error; 363 364 if (STREQ (RCSHEAD, key) && value != NULL) 365 rdata->head = rcsbuf_valcopy (&rcsbuf, value, 0, NULL); 366 367 if (! rcsbuf_getkey (&rcsbuf, &key, &value)) 368 goto l_error; 369 if (STREQ (key, RCSDESC)) 370 goto l_error; 371 372 if (STREQ (RCSBRANCH, key) && value != NULL) 373 { 374 char *cp; 375 376 rdata->branch = rcsbuf_valcopy (&rcsbuf, value, 0, NULL); 377 if ((numdots (rdata->branch) & 1) != 0) 378 { 379 /* turn it into a branch if it's a revision */ 380 cp = strrchr (rdata->branch, '.'); 381 *cp = '\0'; 382 } 383 } 384 385 /* Look ahead for expand, stopping when we see desc or a revision 386 number. */ 387 while (1) 388 { 389 char *cp; 390 391 if (STREQ (RCSEXPAND, key)) 392 { 393 rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0, NULL); 394 break; 395 } 396 397 for (cp = key; 398 (isdigit ((unsigned char)*cp) || *cp == '.') && *cp != '\0'; 399 cp++) 400 /* do nothing */ ; 401 if (*cp == '\0') 402 break; 403 404 if (STREQ (RCSDESC, key)) 405 break; 406 407 if (! rcsbuf_getkey (&rcsbuf, &key, &value)) 408 break; 409 } 410 411 rdata->flags |= PARTIAL; 412 413 rcsbuf_cache (rdata, &rcsbuf); 414 415 return rdata; 416 417 l_error: 418 error (0, 0, "`%s' does not appear to be a valid rcs file", 419 rcsfile); 420 rcsbuf_close (&rcsbuf); 421 freercsnode (&rdata); 422 fclose (fp); 423 return NULL; 424 } 425 426 427 428 /* Do the real work of parsing an RCS file. 429 430 On error, die with a fatal error; if it returns at all it was successful. 431 432 If PFP is NULL, close the file when done. Otherwise, leave it open 433 and store the FILE * in *PFP. */ 434 void 435 RCS_reparsercsfile (RCSNode *rdata, FILE **pfp, struct rcsbuffer *rcsbufp) 436 { 437 FILE *fp; 438 char *rcsfile; 439 struct rcsbuffer rcsbuf; 440 Node *q, *kv; 441 RCSVers *vnode; 442 int gotkey; 443 char *cp; 444 char *key, *value; 445 446 assert (rdata != NULL); 447 rcsfile = rdata->path; 448 449 rcsbuf_cache_open (rdata, 0, &fp, &rcsbuf); 450 451 /* make a node */ 452 /* This probably shouldn't be done until later: if a file has an 453 empty revision tree (which is permissible), rdata->versions 454 should be NULL. -twp */ 455 rdata->versions = getlist (); 456 457 /* 458 * process all the special header information, break out when we get to 459 * the first revision delta 460 */ 461 gotkey = 0; 462 for (;;) 463 { 464 /* get the next key/value pair */ 465 if (!gotkey) 466 { 467 if (! rcsbuf_getkey (&rcsbuf, &key, &value)) 468 { 469 error (1, 0, "`%s' does not appear to be a valid rcs file", 470 rcsfile); 471 } 472 } 473 474 gotkey = 0; 475 476 /* Skip head, branch and expand tags; we already have them. */ 477 if (STREQ (key, RCSHEAD) 478 || STREQ (key, RCSBRANCH) 479 || STREQ (key, RCSEXPAND)) 480 { 481 continue; 482 } 483 484 if (STREQ (key, "access")) 485 { 486 if (value != NULL) 487 { 488 /* We pass the POLISH parameter as 1 because 489 RCS_addaccess expects nothing but spaces. FIXME: 490 It would be easy and more efficient to change 491 RCS_addaccess. */ 492 if (rdata->access) 493 { 494 error (0, 0, 495 "Duplicate `access' keyword found in RCS file."); 496 free (rdata->access); 497 } 498 rdata->access = rcsbuf_valcopy (&rcsbuf, value, 1, NULL); 499 } 500 continue; 501 } 502 503 /* We always save lock information, so that we can handle 504 -kkvl correctly when checking out a file. */ 505 if (STREQ (key, "locks")) 506 { 507 if (value != NULL) 508 { 509 if (rdata->locks_data) 510 { 511 error (0, 0, 512 "Duplicate `locks' keyword found in RCS file."); 513 free (rdata->locks_data); 514 } 515 rdata->locks_data = rcsbuf_valcopy (&rcsbuf, value, 0, NULL); 516 } 517 if (! rcsbuf_getkey (&rcsbuf, &key, &value)) 518 { 519 error (1, 0, "premature end of file reading %s", rcsfile); 520 } 521 if (STREQ (key, "strict") && value == NULL) 522 { 523 rdata->strict_locks = 1; 524 } 525 else 526 gotkey = 1; 527 continue; 528 } 529 530 if (STREQ (RCSSYMBOLS, key)) 531 { 532 if (value != NULL) 533 { 534 if (rdata->symbols_data) 535 { 536 error (0, 0, 537 "Duplicate `%s' keyword found in RCS file.", 538 RCSSYMBOLS); 539 free (rdata->symbols_data); 540 } 541 rdata->symbols_data = rcsbuf_valcopy (&rcsbuf, value, 0, NULL); 542 } 543 continue; 544 } 545 546 /* 547 * check key for '.''s and digits (probably a rev) if it is a 548 * revision or `desc', we are done with the headers and are down to the 549 * revision deltas, so we break out of the loop 550 */ 551 for (cp = key; 552 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0'; 553 cp++) 554 /* do nothing */ ; 555 /* Note that when comparing with RCSDATE, we are not massaging 556 VALUE from the string found in the RCS file. This is OK 557 since we know exactly what to expect. */ 558 if (*cp == '\0' && strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) == 0) 559 break; 560 561 if (STREQ (key, RCSDESC)) 562 break; 563 564 if (STREQ (key, "comment")) 565 { 566 if (rdata->comment) 567 { 568 error (0, 0, 569 "warning: duplicate key `%s' in RCS file `%s'", 570 key, rcsfile); 571 free (rdata->comment); 572 } 573 rdata->comment = rcsbuf_valcopy (&rcsbuf, value, 0, NULL); 574 continue; 575 } 576 if (rdata->other == NULL) 577 rdata->other = getlist (); 578 kv = getnode (); 579 kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD; 580 kv->key = xstrdup (key); 581 kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD, NULL); 582 if (addnode (rdata->other, kv) != 0) 583 { 584 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'", 585 key, rcsfile); 586 freenode (kv); 587 } 588 589 /* if we haven't grabbed it yet, we didn't want it */ 590 } 591 592 /* We got out of the loop, so we have the first part of the first 593 revision delta in KEY (the revision) and VALUE (the date key 594 and its value). This is what getdelta expects to receive. */ 595 596 while ((vnode = getdelta (&rcsbuf, rcsfile, &key, &value)) != NULL) 597 { 598 /* get the node */ 599 q = getnode (); 600 q->type = RCSVERS; 601 q->delproc = rcsvers_delproc; 602 q->data = vnode; 603 q->key = vnode->version; 604 605 /* add the nodes to the list */ 606 if (addnode (rdata->versions, q) != 0) 607 { 608 #if 0 609 purify_printf("WARNING: Adding duplicate version: %s (%s)\n", 610 q->key, rcsfile); 611 freenode (q); 612 #endif 613 } 614 } 615 616 /* Here KEY and VALUE are whatever caused getdelta to return NULL. */ 617 618 if (STREQ (key, RCSDESC)) 619 { 620 if (rdata->desc != NULL) 621 { 622 error (0, 0, 623 "warning: duplicate key `%s' in RCS file `%s'", 624 key, rcsfile); 625 free (rdata->desc); 626 } 627 rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 1, NULL); 628 } 629 630 rdata->delta_pos = rcsbuf_ftello (&rcsbuf); 631 632 if (pfp == NULL) 633 rcsbuf_cache (rdata, &rcsbuf); 634 else 635 { 636 *pfp = fp; 637 *rcsbufp = rcsbuf; 638 } 639 rdata->flags &= ~PARTIAL; 640 } 641 642 643 644 /* Move RCS into or out of the Attic, depending on TOATTIC. If the 645 file is already in the desired place, return without doing 646 anything. At some point may want to think about how this relates 647 to RCS_rewrite but that is a bit hairy (if one wants renames to be 648 atomic, or that kind of thing). If there is an error, print a message 649 and return 1. On success, return 0. */ 650 int 651 RCS_setattic (RCSNode *rcs, int toattic) 652 { 653 char *newpath; 654 const char *p; 655 char *q; 656 657 /* Some systems aren't going to let us rename an open file. */ 658 rcsbuf_cache_close (); 659 660 /* Could make the pathname computations in this file, and probably 661 in other parts of rcs.c too, easier if the REPOS and FILE 662 arguments to RCS_parse got stashed in the RCSNode. */ 663 664 if (toattic) 665 { 666 mode_t omask; 667 668 if (rcs->flags & INATTIC) 669 return 0; 670 671 /* Example: rcs->path is "/foo/bar/baz,v". */ 672 newpath = xmalloc (strlen (rcs->path) + sizeof CVSATTIC + 5); 673 p = last_component (rcs->path); 674 strncpy (newpath, rcs->path, p - rcs->path); 675 strcpy (newpath + (p - rcs->path), CVSATTIC); 676 677 /* Create the Attic directory if it doesn't exist. */ 678 omask = umask (cvsumask); 679 if (CVS_MKDIR (newpath, 0777) < 0 && errno != EEXIST) 680 error (0, errno, "cannot make directory %s", newpath); 681 (void) umask (omask); 682 683 strcat (newpath, "/"); 684 strcat (newpath, p); 685 686 if (CVS_RENAME (rcs->path, newpath) < 0) 687 { 688 int save_errno = errno; 689 690 /* The checks for isreadable look awfully fishy, but 691 I'm going to leave them here for now until I 692 can think harder about whether they take care of 693 some cases which should be handled somehow. */ 694 695 if (isreadable (rcs->path) || !isreadable (newpath)) 696 { 697 error (0, save_errno, "cannot rename %s to %s", 698 rcs->path, newpath); 699 free (newpath); 700 return 1; 701 } 702 } 703 } 704 else 705 { 706 if (!(rcs->flags & INATTIC)) 707 return 0; 708 709 newpath = xmalloc (strlen (rcs->path)); 710 711 /* Example: rcs->path is "/foo/bar/Attic/baz,v". */ 712 p = last_component (rcs->path); 713 strncpy (newpath, rcs->path, p - rcs->path - 1); 714 newpath[p - rcs->path - 1] = '\0'; 715 q = newpath + (p - rcs->path - 1) - (sizeof CVSATTIC - 1); 716 assert (strncmp (q, CVSATTIC, sizeof CVSATTIC - 1) == 0); 717 strcpy (q, p); 718 719 if (CVS_RENAME (rcs->path, newpath) < 0) 720 { 721 error (0, errno, "failed to move `%s' out of the attic", 722 rcs->path); 723 free (newpath); 724 return 1; 725 } 726 } 727 728 free (rcs->path); 729 rcs->path = newpath; 730 731 return 0; 732 } 733 734 735 736 /* 737 * Fully parse the RCS file. Store all keyword/value pairs, fetch the 738 * log messages for each revision, and fetch add and delete counts for 739 * each revision (we could fetch the entire text for each revision, 740 * but the only caller, log_fileproc, doesn't need that information, 741 * so we don't waste the memory required to store it). The add and 742 * delete counts are stored on the OTHER field of the RCSVERSNODE 743 * structure, under the names ";add" and ";delete", so that we don't 744 * waste the memory space of extra fields in RCSVERSNODE for code 745 * which doesn't need this information. 746 */ 747 void 748 RCS_fully_parse (RCSNode *rcs) 749 { 750 FILE *fp; 751 struct rcsbuffer rcsbuf; 752 753 RCS_reparsercsfile (rcs, &fp, &rcsbuf); 754 755 while (1) 756 { 757 char *key, *value; 758 Node *vers; 759 RCSVers *vnode; 760 761 /* Rather than try to keep track of how much information we 762 have read, just read to the end of the file. */ 763 if (!rcsbuf_getrevnum (&rcsbuf, &key)) 764 break; 765 766 vers = findnode (rcs->versions, key); 767 if (vers == NULL) 768 error (1, 0, 769 "mismatch in rcs file %s between deltas and deltatexts (%s)", 770 rcs->print_path, key); 771 772 vnode = vers->data; 773 774 while (rcsbuf_getkey (&rcsbuf, &key, &value)) 775 { 776 if (!STREQ (key, "text")) 777 { 778 Node *kv; 779 780 if (vnode->other == NULL) 781 vnode->other = getlist (); 782 kv = getnode (); 783 kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD; 784 kv->key = xstrdup (key); 785 kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD, 786 NULL); 787 if (addnode (vnode->other, kv) != 0) 788 { 789 error (0, 0, 790 "\ 791 warning: duplicate key `%s' in version `%s' of RCS file `%s'", 792 key, vnode->version, rcs->print_path); 793 freenode (kv); 794 } 795 796 continue; 797 } 798 799 if (!STREQ (vnode->version, rcs->head)) 800 { 801 unsigned long add, del; 802 char buf[50]; 803 Node *kv; 804 805 /* This is a change text. Store the add and delete 806 counts. */ 807 add = 0; 808 del = 0; 809 if (value != NULL) 810 { 811 size_t vallen; 812 const char *cp; 813 814 rcsbuf_valpolish (&rcsbuf, value, 0, &vallen); 815 cp = value; 816 while (cp < value + vallen) 817 { 818 char op; 819 unsigned long count; 820 821 op = *cp++; 822 if (op != 'a' && op != 'd') 823 error (1, 0, "\ 824 unrecognized operation '\\x%x' in %s", 825 op, rcs->print_path); 826 (void) strtoul (cp, (char **) &cp, 10); 827 if (*cp++ != ' ') 828 error (1, 0, "space expected in %s revision %s", 829 rcs->print_path, vnode->version); 830 count = strtoul (cp, (char **) &cp, 10); 831 if (*cp++ != '\012') 832 error (1, 0, "linefeed expected in %s revision %s", 833 rcs->print_path, vnode->version); 834 835 if (op == 'd') 836 del += count; 837 else 838 { 839 add += count; 840 while (count != 0) 841 { 842 if (*cp == '\012') 843 --count; 844 else if (cp == value + vallen) 845 { 846 if (count != 1) 847 error (1, 0, "\ 848 premature end of value in %s revision %s", 849 rcs->print_path, vnode->version); 850 else 851 break; 852 } 853 ++cp; 854 } 855 } 856 } 857 } 858 859 sprintf (buf, "%lu", add); 860 kv = getnode (); 861 kv->type = RCSFIELD; 862 kv->key = xstrdup (";add"); 863 kv->data = xstrdup (buf); 864 if (addnode (vnode->other, kv) != 0) 865 { 866 error (0, 0, 867 "\ 868 warning: duplicate key `%s' in version `%s' of RCS file `%s'", 869 key, vnode->version, rcs->print_path); 870 freenode (kv); 871 } 872 873 sprintf (buf, "%lu", del); 874 kv = getnode (); 875 kv->type = RCSFIELD; 876 kv->key = xstrdup (";delete"); 877 kv->data = xstrdup (buf); 878 if (addnode (vnode->other, kv) != 0) 879 { 880 error (0, 0, 881 "\ 882 warning: duplicate key `%s' in version `%s' of RCS file `%s'", 883 key, vnode->version, rcs->print_path); 884 freenode (kv); 885 } 886 } 887 888 /* We have found the "text" key which ends the data for 889 this revision. Break out of the loop and go on to the 890 next revision. */ 891 break; 892 } 893 } 894 895 rcsbuf_cache (rcs, &rcsbuf); 896 } 897 898 899 900 /* 901 * freercsnode - free up the info for an RCSNode 902 */ 903 void 904 freercsnode (RCSNode **rnodep) 905 { 906 if (rnodep == NULL || *rnodep == NULL) 907 return; 908 909 ((*rnodep)->refcount)--; 910 if ((*rnodep)->refcount != 0) 911 { 912 *rnodep = NULL; 913 return; 914 } 915 free ((*rnodep)->path); 916 free ((*rnodep)->print_path); 917 if ((*rnodep)->head != NULL) 918 free ((*rnodep)->head); 919 if ((*rnodep)->branch != NULL) 920 free ((*rnodep)->branch); 921 free_rcsnode_contents (*rnodep); 922 free (*rnodep); 923 *rnodep = NULL; 924 } 925 926 927 928 /* 929 * free_rcsnode_contents - free up the contents of an RCSNode without 930 * freeing the node itself, or the file name, or the head, or the 931 * path. This returns the RCSNode to the state it is in immediately 932 * after a call to RCS_parse. 933 */ 934 static void 935 free_rcsnode_contents (RCSNode *rnode) 936 { 937 dellist (&rnode->versions); 938 if (rnode->symbols != NULL) 939 dellist (&rnode->symbols); 940 if (rnode->symbols_data != NULL) 941 free (rnode->symbols_data); 942 if (rnode->expand != NULL) 943 free (rnode->expand); 944 if (rnode->other != NULL) 945 dellist (&rnode->other); 946 if (rnode->access != NULL) 947 free (rnode->access); 948 if (rnode->locks_data != NULL) 949 free (rnode->locks_data); 950 if (rnode->locks != NULL) 951 dellist (&rnode->locks); 952 if (rnode->comment != NULL) 953 free (rnode->comment); 954 if (rnode->desc != NULL) 955 free (rnode->desc); 956 } 957 958 959 960 /* free_rcsvers_contents -- free up the contents of an RCSVers node, 961 but also free the pointer to the node itself. */ 962 /* Note: The `hardlinks' list is *not* freed, since it is merely a 963 pointer into the `hardlist' structure (defined in hardlink.c), and 964 that structure is freed elsewhere in the program. */ 965 static void 966 free_rcsvers_contents (RCSVers *rnode) 967 { 968 if (rnode->branches != NULL) 969 dellist (&rnode->branches); 970 if (rnode->date != NULL) 971 free (rnode->date); 972 if (rnode->next != NULL) 973 free (rnode->next); 974 if (rnode->author != NULL) 975 free (rnode->author); 976 if (rnode->state != NULL) 977 free (rnode->state); 978 if (rnode->other != NULL) 979 dellist (&rnode->other); 980 if (rnode->other_delta != NULL) 981 dellist (&rnode->other_delta); 982 if (rnode->text != NULL) 983 freedeltatext (rnode->text); 984 free (rnode); 985 } 986 987 988 989 /* 990 * rcsvers_delproc - free up an RCSVers type node 991 */ 992 static void 993 rcsvers_delproc (Node *p) 994 { 995 free_rcsvers_contents (p->data); 996 } 997 998 999 1000 /* These functions retrieve keys and values from an RCS file using a 1001 buffer. We use this somewhat complex approach because it turns out 1002 that for many common operations, CVS spends most of its time 1003 reading keys, so it's worth doing some fairly hairy optimization. */ 1004 1005 /* The number of bytes we try to read each time we need more data. */ 1006 1007 #define RCSBUF_BUFSIZE (8192) 1008 1009 /* The buffer we use to store data. This grows as needed. */ 1010 1011 static char *rcsbuf_buffer = NULL; 1012 static size_t rcsbuf_buffer_size = 0; 1013 1014 /* Whether rcsbuf_buffer is in use. This is used as a sanity check. */ 1015 1016 static int rcsbuf_inuse; 1017 1018 /* Set up to start gathering keys and values from an RCS file. This 1019 initializes RCSBUF. */ 1020 1021 static void 1022 rcsbuf_open (struct rcsbuffer *rcsbuf, FILE *fp, const char *filename, 1023 long unsigned int pos) 1024 { 1025 if (rcsbuf_inuse) 1026 error (1, 0, "rcsbuf_open: internal error"); 1027 rcsbuf_inuse = 1; 1028 1029 #ifdef HAVE_MMAP 1030 { 1031 /* When we have mmap, it is much more efficient to let the system do the 1032 * buffering and caching for us 1033 */ 1034 struct stat fs; 1035 size_t mmap_off = 0; 1036 1037 if ( fstat (fileno(fp), &fs) < 0 ) 1038 error ( 1, errno, "Could not stat RCS archive %s for mapping", filename ); 1039 1040 if (pos) 1041 { 1042 size_t ps = getpagesize (); 1043 mmap_off = ( pos / ps ) * ps; 1044 } 1045 1046 /* Map private here since this particular buffer is read only */ 1047 rcsbuf_buffer = mmap ( NULL, fs.st_size - mmap_off, 1048 PROT_READ | PROT_WRITE, 1049 MAP_PRIVATE, fileno(fp), mmap_off ); 1050 if ( rcsbuf_buffer == NULL || rcsbuf_buffer == MAP_FAILED ) 1051 error ( 1, errno, "Could not map memory to RCS archive %s", filename ); 1052 1053 rcsbuf_buffer_size = fs.st_size - mmap_off; 1054 rcsbuf->ptr = rcsbuf_buffer + pos - mmap_off; 1055 rcsbuf->ptrend = rcsbuf_buffer + fs.st_size - mmap_off; 1056 rcsbuf->pos = mmap_off; 1057 } 1058 #else /* !HAVE_MMAP */ 1059 if (rcsbuf_buffer_size < RCSBUF_BUFSIZE) 1060 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, RCSBUF_BUFSIZE); 1061 1062 rcsbuf->ptr = rcsbuf_buffer; 1063 rcsbuf->ptrend = rcsbuf_buffer; 1064 rcsbuf->pos = pos; 1065 #endif /* HAVE_MMAP */ 1066 rcsbuf->fp = fp; 1067 rcsbuf->filename = filename; 1068 rcsbuf->vlen = 0; 1069 rcsbuf->at_string = 0; 1070 rcsbuf->embedded_at = 0; 1071 } 1072 1073 1074 1075 /* Stop gathering keys from an RCS file. */ 1076 static void 1077 rcsbuf_close (struct rcsbuffer *rcsbuf) 1078 { 1079 if (! rcsbuf_inuse) 1080 error (1, 0, "rcsbuf_close: internal error"); 1081 #ifdef HAVE_MMAP 1082 munmap ( rcsbuf_buffer, rcsbuf_buffer_size ); 1083 #endif 1084 rcsbuf_inuse = 0; 1085 } 1086 1087 1088 1089 /* Read a key/value pair from an RCS file. This sets *KEYP to point 1090 to the key, and *VALUEP to point to the value. A missing or empty 1091 value is indicated by setting *VALUEP to NULL. 1092 1093 This function returns 1 on success, or 0 on EOF. If there is an 1094 error reading the file, or an EOF in an unexpected location, it 1095 gives a fatal error. 1096 1097 This sets *KEYP and *VALUEP to point to storage managed by 1098 rcsbuf_getkey. Moreover, *VALUEP has not been massaged from the 1099 RCS format: it may contain embedded whitespace and embedded '@' 1100 characters. Call rcsbuf_valcopy or rcsbuf_valpolish to do 1101 appropriate massaging. */ 1102 1103 /* Note that the extreme hair in rcsbuf_getkey is because profiling 1104 statistics show that it was worth it. */ 1105 static int 1106 rcsbuf_getkey (struct rcsbuffer *rcsbuf, char **keyp, char **valp) 1107 { 1108 register const char * const my_spacetab = spacetab; 1109 register char *ptr, *ptrend; 1110 char c; 1111 1112 #define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0) 1113 1114 rcsbuf->vlen = 0; 1115 rcsbuf->at_string = 0; 1116 rcsbuf->embedded_at = 0; 1117 1118 ptr = rcsbuf->ptr; 1119 ptrend = rcsbuf->ptrend; 1120 1121 /* Sanity check. */ 1122 assert (ptr >= rcsbuf_buffer && ptr <= rcsbuf_buffer + rcsbuf_buffer_size); 1123 assert (ptrend >= rcsbuf_buffer && ptrend <= rcsbuf_buffer + rcsbuf_buffer_size); 1124 1125 #ifndef HAVE_MMAP 1126 /* If the pointer is more than RCSBUF_BUFSIZE bytes into the 1127 buffer, move back to the start of the buffer. This keeps the 1128 buffer from growing indefinitely. */ 1129 if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE) 1130 { 1131 int len; 1132 1133 len = ptrend - ptr; 1134 1135 /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes 1136 at a time, so we can't have more bytes than that past PTR. */ 1137 assert (len <= RCSBUF_BUFSIZE); 1138 1139 /* Update the POS field, which holds the file offset of the 1140 first byte in the RCSBUF_BUFFER buffer. */ 1141 rcsbuf->pos += ptr - rcsbuf_buffer; 1142 1143 memcpy (rcsbuf_buffer, ptr, len); 1144 ptr = rcsbuf_buffer; 1145 ptrend = ptr + len; 1146 rcsbuf->ptrend = ptrend; 1147 } 1148 #endif /* HAVE_MMAP */ 1149 1150 /* Skip leading whitespace. */ 1151 1152 while (1) 1153 { 1154 if (ptr >= ptrend) 1155 { 1156 ptr = rcsbuf_fill (rcsbuf, ptr, NULL, NULL); 1157 if (ptr == NULL) 1158 return 0; 1159 ptrend = rcsbuf->ptrend; 1160 } 1161 1162 c = *ptr; 1163 if (! my_whitespace (c)) 1164 break; 1165 1166 ++ptr; 1167 } 1168 1169 /* We've found the start of the key. */ 1170 1171 *keyp = ptr; 1172 1173 if (c != ';') 1174 { 1175 while (1) 1176 { 1177 ++ptr; 1178 if (ptr >= ptrend) 1179 { 1180 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, NULL); 1181 if (ptr == NULL) 1182 error (1, 0, "EOF in key in RCS file %s", 1183 primary_root_inverse_translate (rcsbuf->filename)); 1184 ptrend = rcsbuf->ptrend; 1185 } 1186 c = *ptr; 1187 if (c == ';' || my_whitespace (c)) 1188 break; 1189 } 1190 } 1191 1192 /* Here *KEYP points to the key in the buffer, C is the character 1193 we found at the of the key, and PTR points to the location in 1194 the buffer where we found C. We must set *PTR to \0 in order 1195 to terminate the key. If the key ended with ';', then there is 1196 no value. */ 1197 1198 *ptr = '\0'; 1199 ++ptr; 1200 1201 if (c == ';') 1202 { 1203 *valp = NULL; 1204 rcsbuf->ptr = ptr; 1205 return 1; 1206 } 1207 1208 /* C must be whitespace. Skip whitespace between the key and the 1209 value. If we find ';' now, there is no value. */ 1210 1211 while (1) 1212 { 1213 if (ptr >= ptrend) 1214 { 1215 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, NULL); 1216 if (ptr == NULL) 1217 error (1, 0, "EOF while looking for value in RCS file %s", 1218 primary_root_inverse_translate (rcsbuf->filename)); 1219 ptrend = rcsbuf->ptrend; 1220 } 1221 c = *ptr; 1222 if (c == ';') 1223 { 1224 *valp = NULL; 1225 rcsbuf->ptr = ptr + 1; 1226 return 1; 1227 } 1228 if (! my_whitespace (c)) 1229 break; 1230 ++ptr; 1231 } 1232 1233 /* Now PTR points to the start of the value, and C is the first 1234 character of the value. */ 1235 1236 if (c != '@') 1237 *valp = ptr; 1238 else 1239 { 1240 char *pat; 1241 size_t vlen; 1242 1243 /* Optimize the common case of a value composed of a single 1244 '@' string. */ 1245 1246 rcsbuf->at_string = 1; 1247 1248 ++ptr; 1249 1250 *valp = ptr; 1251 1252 while (1) 1253 { 1254 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL) 1255 { 1256 /* Note that we pass PTREND as the PTR value to 1257 rcsbuf_fill, so that we will wind up setting PTR to 1258 the location corresponding to the old PTREND, so 1259 that we don't search the same bytes again. */ 1260 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp); 1261 if (ptr == NULL) 1262 error (1, 0, 1263 "EOF while looking for end of string in RCS file %s", 1264 primary_root_inverse_translate (rcsbuf->filename)); 1265 ptrend = rcsbuf->ptrend; 1266 } 1267 1268 /* Handle the special case of an '@' right at the end of 1269 the known bytes. */ 1270 if (pat + 1 >= ptrend) 1271 { 1272 /* Note that we pass PAT, not PTR, here. */ 1273 pat = rcsbuf_fill (rcsbuf, pat, keyp, valp); 1274 if (pat == NULL) 1275 { 1276 /* EOF here is OK; it just means that the last 1277 character of the file was an '@' terminating a 1278 value for a key type which does not require a 1279 trailing ';'. */ 1280 pat = rcsbuf->ptrend - 1; 1281 1282 } 1283 ptrend = rcsbuf->ptrend; 1284 1285 /* Note that the value of PTR is bogus here. This is 1286 OK, because we don't use it. */ 1287 } 1288 1289 if (pat + 1 >= ptrend || pat[1] != '@') 1290 break; 1291 1292 /* We found an '@' pair in the string. Keep looking. */ 1293 ++rcsbuf->embedded_at; 1294 ptr = pat + 2; 1295 } 1296 1297 /* Here PAT points to the final '@' in the string. */ 1298 1299 *pat = '\0'; 1300 1301 vlen = pat - *valp; 1302 if (vlen == 0) 1303 *valp = NULL; 1304 rcsbuf->vlen = vlen; 1305 1306 ptr = pat + 1; 1307 } 1308 1309 /* Certain keywords only have a '@' string. If there is no '@' 1310 string, then the old getrcskey function assumed that they had 1311 no value, and we do the same. */ 1312 1313 { 1314 char *k; 1315 1316 k = *keyp; 1317 if (STREQ (k, RCSDESC) 1318 || STREQ (k, "text") 1319 || STREQ (k, "log")) 1320 { 1321 if (c != '@') 1322 *valp = NULL; 1323 rcsbuf->ptr = ptr; 1324 return 1; 1325 } 1326 } 1327 1328 /* If we've already gathered a '@' string, try to skip whitespace 1329 and find a ';'. */ 1330 if (c == '@') 1331 { 1332 while (1) 1333 { 1334 char n; 1335 1336 if (ptr >= ptrend) 1337 { 1338 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp); 1339 if (ptr == NULL) 1340 error (1, 0, "EOF in value in RCS file %s", 1341 primary_root_inverse_translate (rcsbuf->filename)); 1342 ptrend = rcsbuf->ptrend; 1343 } 1344 n = *ptr; 1345 if (n == ';') 1346 { 1347 /* We're done. We already set everything up for this 1348 case above. */ 1349 rcsbuf->ptr = ptr + 1; 1350 return 1; 1351 } 1352 if (! my_whitespace (n)) 1353 break; 1354 ++ptr; 1355 } 1356 1357 /* The value extends past the '@' string. We need to undo the 1358 '@' stripping done in the default case above. This 1359 case never happens in a plain RCS file, but it can happen 1360 if user defined phrases are used. */ 1361 ((*valp)--)[rcsbuf->vlen++] = '@'; 1362 } 1363 1364 /* Here we have a value which is not a simple '@' string. We need 1365 to gather up everything until the next ';', including any '@' 1366 strings. *VALP points to the start of the value. If 1367 RCSBUF->VLEN is not zero, then we have already read an '@' 1368 string, and PTR points to the data following the '@' string. 1369 Otherwise, PTR points to the start of the value. */ 1370 1371 while (1) 1372 { 1373 char *start, *psemi, *pat; 1374 1375 /* Find the ';' which must end the value. */ 1376 start = ptr; 1377 while ((psemi = memchr (ptr, ';', ptrend - ptr)) == NULL) 1378 { 1379 int slen; 1380 1381 /* Note that we pass PTREND as the PTR value to 1382 rcsbuf_fill, so that we will wind up setting PTR to the 1383 location corresponding to the old PTREND, so that we 1384 don't search the same bytes again. */ 1385 slen = start - *valp; 1386 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp); 1387 if (ptr == NULL) 1388 error (1, 0, "EOF in value in RCS file %s", 1389 primary_root_inverse_translate (rcsbuf->filename)); 1390 start = *valp + slen; 1391 ptrend = rcsbuf->ptrend; 1392 } 1393 1394 /* See if there are any '@' strings in the value. */ 1395 pat = memchr (start, '@', psemi - start); 1396 1397 if (pat == NULL) 1398 { 1399 size_t vlen; 1400 1401 /* We're done with the value. Trim any trailing 1402 whitespace. */ 1403 1404 rcsbuf->ptr = psemi + 1; 1405 1406 start = *valp; 1407 while (psemi > start && my_whitespace (psemi[-1])) 1408 --psemi; 1409 *psemi = '\0'; 1410 1411 vlen = psemi - start; 1412 if (vlen == 0) 1413 *valp = NULL; 1414 rcsbuf->vlen = vlen; 1415 1416 return 1; 1417 } 1418 1419 /* We found an '@' string in the value. We set RCSBUF->AT_STRING 1420 and RCSBUF->EMBEDDED_AT to indicate that we won't be able to 1421 compress whitespace correctly for this type of value. 1422 Since this type of value never arises in a normal RCS file, 1423 this should not be a big deal. It means that if anybody 1424 adds a phrase which can have both an '@' string and regular 1425 text, they will have to handle whitespace compression 1426 themselves. */ 1427 1428 rcsbuf->at_string = 1; 1429 rcsbuf->embedded_at = -1; 1430 1431 ptr = pat + 1; 1432 1433 while (1) 1434 { 1435 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL) 1436 { 1437 /* Note that we pass PTREND as the PTR value to 1438 rcsbuff_fill, so that we will wind up setting PTR 1439 to the location corresponding to the old PTREND, so 1440 that we don't search the same bytes again. */ 1441 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp); 1442 if (ptr == NULL) 1443 error (1, 0, 1444 "EOF while looking for end of string in RCS file %s", 1445 primary_root_inverse_translate (rcsbuf->filename)); 1446 ptrend = rcsbuf->ptrend; 1447 } 1448 1449 /* Handle the special case of an '@' right at the end of 1450 the known bytes. */ 1451 if (pat + 1 >= ptrend) 1452 { 1453 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp); 1454 if (ptr == NULL) 1455 error (1, 0, "EOF in value in RCS file %s", 1456 primary_root_inverse_translate (rcsbuf->filename)); 1457 ptrend = rcsbuf->ptrend; 1458 } 1459 1460 if (pat[1] != '@') 1461 break; 1462 1463 /* We found an '@' pair in the string. Keep looking. */ 1464 ptr = pat + 2; 1465 } 1466 1467 /* Here PAT points to the final '@' in the string. */ 1468 ptr = pat + 1; 1469 } 1470 1471 #undef my_whitespace 1472 } 1473 1474 1475 1476 /* Read an RCS revision number from an RCS file. This sets *REVP to 1477 point to the revision number; it will point to space that is 1478 managed by the rcsbuf functions, and is only good until the next 1479 call to rcsbuf_getkey or rcsbuf_getrevnum. 1480 1481 This function returns 1 on success, or 0 on EOF. If there is an 1482 error reading the file, or an EOF in an unexpected location, it 1483 gives a fatal error. */ 1484 static int 1485 rcsbuf_getrevnum (struct rcsbuffer *rcsbuf, char **revp) 1486 { 1487 char *ptr, *ptrend; 1488 char c; 1489 1490 ptr = rcsbuf->ptr; 1491 ptrend = rcsbuf->ptrend; 1492 1493 *revp = NULL; 1494 1495 /* Skip leading whitespace. */ 1496 1497 while (1) 1498 { 1499 if (ptr >= ptrend) 1500 { 1501 ptr = rcsbuf_fill (rcsbuf, ptr, NULL, NULL); 1502 if (ptr == NULL) 1503 return 0; 1504 ptrend = rcsbuf->ptrend; 1505 } 1506 1507 c = *ptr; 1508 if (! whitespace (c)) 1509 break; 1510 1511 ++ptr; 1512 } 1513 1514 if (! isdigit ((unsigned char) c) && c != '.') 1515 error (1, 0, 1516 "\ 1517 unexpected '\\x%x' reading revision number in RCS file %s", 1518 c, primary_root_inverse_translate (rcsbuf->filename)); 1519 1520 *revp = ptr; 1521 1522 do 1523 { 1524 ++ptr; 1525 if (ptr >= ptrend) 1526 { 1527 ptr = rcsbuf_fill (rcsbuf, ptr, revp, NULL); 1528 if (ptr == NULL) 1529 error (1, 0, 1530 "unexpected EOF reading revision number in RCS file %s", 1531 primary_root_inverse_translate (rcsbuf->filename)); 1532 ptrend = rcsbuf->ptrend; 1533 } 1534 1535 c = *ptr; 1536 } 1537 while (isdigit ((unsigned char) c) || c == '.'); 1538 1539 if (! whitespace (c)) 1540 error (1, 0, "\ 1541 unexpected '\\x%x' reading revision number in RCS file %s", 1542 c, primary_root_inverse_translate (rcsbuf->filename)); 1543 1544 *ptr = '\0'; 1545 1546 rcsbuf->ptr = ptr + 1; 1547 1548 return 1; 1549 } 1550 1551 1552 1553 /* Fill RCSBUF_BUFFER with bytes from the file associated with RCSBUF, 1554 updating PTR and the PTREND field. If KEYP and *KEYP are not NULL, 1555 then *KEYP points into the buffer, and must be adjusted if the 1556 buffer is changed. Likewise for VALP. Returns the new value of 1557 PTR, or NULL on error. */ 1558 static char * 1559 rcsbuf_fill (struct rcsbuffer *rcsbuf, char *ptr, char **keyp, char **valp) 1560 { 1561 #ifdef HAVE_MMAP 1562 return NULL; 1563 #else /* HAVE_MMAP */ 1564 int got; 1565 1566 if (rcsbuf->ptrend - rcsbuf_buffer + RCSBUF_BUFSIZE > rcsbuf_buffer_size) 1567 { 1568 int poff, peoff, koff, voff; 1569 1570 poff = ptr - rcsbuf_buffer; 1571 peoff = rcsbuf->ptrend - rcsbuf_buffer; 1572 koff = keyp == NULL ? 0 : *keyp - rcsbuf_buffer; 1573 voff = valp == NULL ? 0 : *valp - rcsbuf_buffer; 1574 1575 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, 1576 rcsbuf_buffer_size + RCSBUF_BUFSIZE); 1577 1578 ptr = rcsbuf_buffer + poff; 1579 rcsbuf->ptrend = rcsbuf_buffer + peoff; 1580 if (keyp != NULL) 1581 *keyp = rcsbuf_buffer + koff; 1582 if (valp != NULL) 1583 *valp = rcsbuf_buffer + voff; 1584 } 1585 1586 got = fread (rcsbuf->ptrend, 1, RCSBUF_BUFSIZE, rcsbuf->fp); 1587 if (got == 0) 1588 { 1589 if (ferror (rcsbuf->fp)) 1590 error (1, errno, "cannot read %s", rcsbuf->filename); 1591 return NULL; 1592 } 1593 1594 rcsbuf->ptrend += got; 1595 1596 return ptr; 1597 #endif /* HAVE_MMAP */ 1598 } 1599 1600 1601 1602 /* Test whether the last value returned by rcsbuf_getkey is a composite 1603 value or not. */ 1604 static int 1605 rcsbuf_valcmp (struct rcsbuffer *rcsbuf) 1606 { 1607 return rcsbuf->at_string && rcsbuf->embedded_at < 0; 1608 } 1609 1610 1611 1612 /* Copy the value VAL returned by rcsbuf_getkey into a memory buffer, 1613 returning the memory buffer. Polish the value like 1614 rcsbuf_valpolish, q.v. */ 1615 static char * 1616 rcsbuf_valcopy (struct rcsbuffer *rcsbuf, char *val, int polish, size_t *lenp) 1617 { 1618 size_t vlen; 1619 int embedded_at; 1620 char *ret; 1621 1622 if (val == NULL) 1623 { 1624 if (lenp != NULL) 1625 *lenp = 0; 1626 return NULL; 1627 } 1628 1629 vlen = rcsbuf->vlen; 1630 embedded_at = rcsbuf->embedded_at < 0 ? 0 : rcsbuf->embedded_at; 1631 1632 ret = xmalloc (vlen - embedded_at + 1); 1633 1634 if (rcsbuf->at_string ? embedded_at == 0 : ! polish) 1635 { 1636 /* No special action to take. */ 1637 memcpy (ret, val, vlen + 1); 1638 if (lenp != NULL) 1639 *lenp = vlen; 1640 return ret; 1641 } 1642 1643 rcsbuf_valpolish_internal (rcsbuf, ret, val, lenp); 1644 return ret; 1645 } 1646 1647 1648 1649 /* Polish the value VAL returned by rcsbuf_getkey. The POLISH 1650 parameter is non-zero if multiple embedded whitespace characters 1651 should be compressed into a single whitespace character. Note that 1652 leading and trailing whitespace was already removed by 1653 rcsbuf_getkey. Within an '@' string, pairs of '@' characters are 1654 compressed into a single '@' character regardless of the value of 1655 POLISH. If LENP is not NULL, set *LENP to the length of the value. */ 1656 static void 1657 rcsbuf_valpolish (struct rcsbuffer *rcsbuf, char *val, int polish, 1658 size_t *lenp) 1659 { 1660 if (val == NULL) 1661 { 1662 if (lenp != NULL) 1663 *lenp= 0; 1664 return; 1665 } 1666 1667 if (rcsbuf->at_string ? rcsbuf->embedded_at == 0 : ! polish) 1668 { 1669 /* No special action to take. */ 1670 if (lenp != NULL) 1671 *lenp = rcsbuf->vlen; 1672 return; 1673 } 1674 1675 rcsbuf_valpolish_internal (rcsbuf, val, val, lenp); 1676 } 1677 1678 1679 1680 /* Internal polishing routine, called from rcsbuf_valcopy and 1681 rcsbuf_valpolish. */ 1682 static void 1683 rcsbuf_valpolish_internal (struct rcsbuffer *rcsbuf, char *to, 1684 const char *from, size_t *lenp) 1685 { 1686 size_t len; 1687 1688 len = rcsbuf->vlen; 1689 1690 if (! rcsbuf->at_string) 1691 { 1692 char *orig_to; 1693 size_t clen; 1694 1695 orig_to = to; 1696 1697 for (clen = len; clen > 0; ++from, --clen) 1698 { 1699 char c; 1700 1701 c = *from; 1702 if (whitespace (c)) 1703 { 1704 /* Note that we know that clen can not drop to zero 1705 while we have whitespace, because we know there is 1706 no trailing whitespace. */ 1707 while (whitespace (from[1])) 1708 { 1709 ++from; 1710 --clen; 1711 } 1712 c = ' '; 1713 } 1714 *to++ = c; 1715 } 1716 1717 *to = '\0'; 1718 1719 if (lenp != NULL) 1720 *lenp = to - orig_to; 1721 } 1722 else 1723 { 1724 const char *orig_from; 1725 char *orig_to; 1726 int embedded_at; 1727 size_t clen; 1728 1729 orig_from = from; 1730 orig_to = to; 1731 1732 embedded_at = rcsbuf->embedded_at; 1733 assert (embedded_at > 0); 1734 1735 if (lenp != NULL) 1736 *lenp = len - embedded_at; 1737 1738 for (clen = len; clen > 0; ++from, --clen) 1739 { 1740 char c; 1741 1742 c = *from; 1743 *to++ = c; 1744 if (c == '@') 1745 { 1746 ++from; 1747 1748 /* Sanity check. 1749 * 1750 * FIXME: I restored this to an abort from an assert based on 1751 * advice from Larry Jones that asserts should not be used to 1752 * confirm the validity of an RCS file... This leaves two 1753 * issues here: 1) I am uncertain that the fact that we will 1754 * only find double '@'s hasn't already been confirmed; and: 1755 * 2) If this is the proper place to spot the error in the RCS 1756 * file, then we should print a much clearer error here for the 1757 * user!!!!!!! 1758 * 1759 * - DRP 1760 */ 1761 if (*from != '@' || clen == 0) 1762 abort (); 1763 1764 --clen; 1765 1766 --embedded_at; 1767 if (embedded_at == 0) 1768 { 1769 /* We've found all the embedded '@' characters. 1770 We can just memcpy the rest of the buffer after 1771 this '@' character. */ 1772 if (orig_to != orig_from) 1773 memcpy (to, from + 1, clen - 1); 1774 else 1775 memmove (to, from + 1, clen - 1); 1776 from += clen; 1777 to += clen - 1; 1778 break; 1779 } 1780 } 1781 } 1782 1783 /* Sanity check. */ 1784 assert (from == orig_from + len 1785 && to == orig_to + (len - rcsbuf->embedded_at)); 1786 1787 *to = '\0'; 1788 } 1789 } 1790 1791 1792 1793 #ifdef PRESERVE_PERMISSIONS_SUPPORT 1794 1795 /* Copy the next word from the value VALP returned by rcsbuf_getkey into a 1796 memory buffer, updating VALP and returning the memory buffer. Return 1797 NULL when there are no more words. */ 1798 1799 static char * 1800 rcsbuf_valword (struct rcsbuffer *rcsbuf, char **valp) 1801 { 1802 register const char * const my_spacetab = spacetab; 1803 register char *ptr, *pat; 1804 char c; 1805 1806 # define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0) 1807 1808 if (*valp == NULL) 1809 return NULL; 1810 1811 for (ptr = *valp; my_whitespace (*ptr); ++ptr) ; 1812 if (*ptr == '\0') 1813 { 1814 assert (ptr - *valp == rcsbuf->vlen); 1815 *valp = NULL; 1816 rcsbuf->vlen = 0; 1817 return NULL; 1818 } 1819 1820 /* PTR now points to the start of a value. Find out whether it is 1821 a num, an id, a string or a colon. */ 1822 c = *ptr; 1823 if (c == ':') 1824 { 1825 rcsbuf->vlen -= ++ptr - *valp; 1826 *valp = ptr; 1827 return xstrdup (":"); 1828 } 1829 1830 if (c == '@') 1831 { 1832 int embedded_at = 0; 1833 size_t vlen; 1834 1835 pat = ++ptr; 1836 while ((pat = strchr (pat, '@')) != NULL) 1837 { 1838 if (pat[1] != '@') 1839 break; 1840 ++embedded_at; 1841 pat += 2; 1842 } 1843 1844 /* Here PAT points to the final '@' in the string. */ 1845 *pat++ = '\0'; 1846 assert (rcsbuf->at_string); 1847 vlen = rcsbuf->vlen - (pat - *valp); 1848 rcsbuf->vlen = pat - ptr - 1; 1849 rcsbuf->embedded_at = embedded_at; 1850 ptr = rcsbuf_valcopy (rcsbuf, ptr, 0, NULL); 1851 *valp = pat; 1852 rcsbuf->vlen = vlen; 1853 if (strchr (pat, '@') == NULL) 1854 rcsbuf->at_string = 0; 1855 else 1856 rcsbuf->embedded_at = -1; 1857 return ptr; 1858 } 1859 1860 /* *PTR is neither `:', `;' nor `@', so it should be the start of a num 1861 or an id. Make sure it is not another special character. */ 1862 if (c == '$' || c == '.' || c == ',') 1863 error (1, 0, "invalid special character in RCS field in %s", 1864 primary_root_inverse_translate (rcsbuf->filename)); 1865 1866 pat = ptr; 1867 while (1) 1868 { 1869 /* Legitimate ID characters are digits, dots and any `graphic 1870 printing character that is not a special.' This test ought 1871 to do the trick. */ 1872 c = *++pat; 1873 if (!isprint ((unsigned char) c) || 1874 c == ';' || c == '$' || c == ',' || c == '@' || c == ':') 1875 break; 1876 } 1877 1878 /* PAT points to the last non-id character in this word, and C is 1879 the character in its memory cell. Check to make sure that it 1880 is a legitimate word delimiter -- whitespace or end. */ 1881 if (c != '\0' && !my_whitespace (c)) 1882 error (1, 0, "invalid special character in RCS field in %s", 1883 primary_root_inverse_translate (rcsbuf->filename)); 1884 1885 *pat = '\0'; 1886 rcsbuf->vlen -= pat - *valp; 1887 *valp = pat; 1888 return xstrdup (ptr); 1889 1890 # undef my_whitespace 1891 } 1892 1893 #endif /* PRESERVE_PERMISSIONS_SUPPORT */ 1894 1895 1896 1897 /* Return the current position of an rcsbuf. */ 1898 static off_t 1899 rcsbuf_ftello (struct rcsbuffer *rcsbuf) 1900 { 1901 return rcsbuf->pos + rcsbuf->ptr - rcsbuf_buffer; 1902 } 1903 1904 1905 1906 /* Return a pointer to any data buffered for RCSBUF, along with the 1907 length. */ 1908 static void 1909 rcsbuf_get_buffered (struct rcsbuffer *rcsbuf, char **datap, size_t *lenp) 1910 { 1911 *datap = rcsbuf->ptr; 1912 *lenp = rcsbuf->ptrend - rcsbuf->ptr; 1913 } 1914 1915 1916 1917 /* CVS optimizes by quickly reading some header information from a 1918 file. If it decides it needs to do more with the file, it reopens 1919 it. We speed that up here by maintaining a cache of a single open 1920 file, to save the time it takes to reopen the file in the common 1921 case. */ 1922 static RCSNode *cached_rcs; 1923 static struct rcsbuffer cached_rcsbuf; 1924 1925 /* Cache RCS and RCSBUF. This takes responsibility for closing 1926 RCSBUF->FP. */ 1927 static void 1928 rcsbuf_cache (RCSNode *rcs, struct rcsbuffer *rcsbuf) 1929 { 1930 if (cached_rcs != NULL) 1931 rcsbuf_cache_close (); 1932 cached_rcs = rcs; 1933 ++rcs->refcount; 1934 cached_rcsbuf = *rcsbuf; 1935 } 1936 1937 1938 1939 /* If there is anything in the cache, close it. */ 1940 static void 1941 rcsbuf_cache_close (void) 1942 { 1943 if (cached_rcs != NULL) 1944 { 1945 rcsbuf_close (&cached_rcsbuf); 1946 if (fclose (cached_rcsbuf.fp) != 0) 1947 error (0, errno, "cannot close %s", cached_rcsbuf.filename); 1948 freercsnode (&cached_rcs); 1949 cached_rcs = NULL; 1950 } 1951 } 1952 1953 1954 1955 /* Open an rcsbuffer for RCS, getting it from the cache if possible. 1956 Set *FPP to the file, and *RCSBUFP to the rcsbuf. The file should 1957 be put at position POS. */ 1958 static void 1959 rcsbuf_cache_open (RCSNode *rcs, off_t pos, FILE **pfp, 1960 struct rcsbuffer *prcsbuf) 1961 { 1962 #ifndef HAVE_MMAP 1963 if (cached_rcs == rcs) 1964 { 1965 if (rcsbuf_ftello (&cached_rcsbuf) != pos) 1966 { 1967 if (fseeko (cached_rcsbuf.fp, pos, SEEK_SET) != 0) 1968 error (1, 0, "cannot fseeko RCS file %s", 1969 cached_rcsbuf.filename); 1970 cached_rcsbuf.ptr = rcsbuf_buffer; 1971 cached_rcsbuf.ptrend = rcsbuf_buffer; 1972 cached_rcsbuf.pos = pos; 1973 } 1974 *pfp = cached_rcsbuf.fp; 1975 1976 /* When RCS_parse opens a file using fopen_case, it frees the 1977 filename which we cached in CACHED_RCSBUF and stores a new 1978 file name in RCS->PATH. We avoid problems here by always 1979 copying the filename over. FIXME: This is hackish. */ 1980 cached_rcsbuf.filename = rcs->path; 1981 1982 *prcsbuf = cached_rcsbuf; 1983 1984 cached_rcs = NULL; 1985 1986 /* Removing RCS from the cache removes a reference to it. */ 1987 --rcs->refcount; 1988 if (rcs->refcount <= 0) 1989 error (1, 0, "rcsbuf_cache_open: internal error"); 1990 } 1991 else 1992 { 1993 #endif /* ifndef HAVE_MMAP */ 1994 /* FIXME: If these routines can be rewritten to not write to the 1995 * rcs file buffer, there would be a considerably larger memory savings 1996 * from using mmap since the shared file would never need be copied to 1997 * process memory. 1998 * 1999 * If this happens, cached mmapped buffers would be usable, but don't 2000 * forget to make sure rcs->pos < pos here... 2001 */ 2002 if (cached_rcs != NULL) 2003 rcsbuf_cache_close (); 2004 2005 *pfp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ); 2006 if (*pfp == NULL) 2007 error (1, 0, "unable to reopen `%s'", rcs->path); 2008 #ifndef HAVE_MMAP 2009 if (pos != 0) 2010 { 2011 if (fseeko (*pfp, pos, SEEK_SET) != 0) 2012 error (1, 0, "cannot fseeko RCS file %s", rcs->path); 2013 } 2014 #endif /* ifndef HAVE_MMAP */ 2015 rcsbuf_open (prcsbuf, *pfp, rcs->path, pos); 2016 #ifndef HAVE_MMAP 2017 } 2018 #endif /* ifndef HAVE_MMAP */ 2019 } 2020 2021 2022 2023 /* 2024 * process the symbols list of the rcs file 2025 */ 2026 static void 2027 do_symbols (List *list, char *val) 2028 { 2029 Node *p; 2030 char *cp = val; 2031 char *tag, *rev; 2032 2033 assert (cp); 2034 2035 for (;;) 2036 { 2037 /* skip leading whitespace */ 2038 while (whitespace (*cp)) 2039 cp++; 2040 2041 /* if we got to the end, we are done */ 2042 if (*cp == '\0') 2043 break; 2044 2045 /* split it up into tag and rev */ 2046 tag = cp; 2047 cp = strchr (cp, ':'); 2048 *cp++ = '\0'; 2049 rev = cp; 2050 while (!whitespace (*cp) && *cp != '\0') 2051 cp++; 2052 if (*cp != '\0') 2053 *cp++ = '\0'; 2054 2055 /* make a new node and add it to the list */ 2056 p = getnode (); 2057 p->key = xstrdup (tag); 2058 p->data = xstrdup (rev); 2059 (void) addnode (list, p); 2060 } 2061 } 2062 2063 2064 2065 /* 2066 * process the locks list of the rcs file 2067 * Like do_symbols, but hash entries are keyed backwards: i.e. 2068 * an entry like `user:rev' is keyed on REV rather than on USER. 2069 */ 2070 static void 2071 do_locks (List *list, char *val) 2072 { 2073 Node *p; 2074 char *cp = val; 2075 char *user, *rev; 2076 2077 assert (cp); 2078 2079 for (;;) 2080 { 2081 /* skip leading whitespace */ 2082 while (whitespace (*cp)) 2083 cp++; 2084 2085 /* if we got to the end, we are done */ 2086 if (*cp == '\0') 2087 break; 2088 2089 /* split it up into user and rev */ 2090 user = cp; 2091 cp = strchr (cp, ':'); 2092 *cp++ = '\0'; 2093 rev = cp; 2094 while (!whitespace (*cp) && *cp != '\0') 2095 cp++; 2096 if (*cp != '\0') 2097 *cp++ = '\0'; 2098 2099 /* make a new node and add it to the list */ 2100 p = getnode (); 2101 p->key = xstrdup (rev); 2102 p->data = xstrdup (user); 2103 (void) addnode (list, p); 2104 } 2105 } 2106 2107 2108 2109 /* 2110 * process the branches list of a revision delta 2111 */ 2112 static void 2113 do_branches (List *list, char *val) 2114 { 2115 Node *p; 2116 char *cp = val; 2117 char *branch; 2118 2119 for (;;) 2120 { 2121 /* skip leading whitespace */ 2122 while (whitespace (*cp)) 2123 cp++; 2124 2125 /* if we got to the end, we are done */ 2126 if (*cp == '\0') 2127 break; 2128 2129 /* find the end of this branch */ 2130 branch = cp; 2131 while (!whitespace (*cp) && *cp != '\0') 2132 cp++; 2133 if (*cp != '\0') 2134 *cp++ = '\0'; 2135 2136 /* make a new node and add it to the list */ 2137 p = getnode (); 2138 p->key = xstrdup (branch); 2139 (void) addnode (list, p); 2140 } 2141 } 2142 2143 2144 2145 /* 2146 * Version Number 2147 * 2148 * Returns the requested version number of the RCS file, satisfying tags and/or 2149 * dates, and walking branches, if necessary. 2150 * 2151 * The result is returned; null-string if error. 2152 */ 2153 char * 2154 RCS_getversion (RCSNode *rcs, const char *tag, const char *date, 2155 int force_tag_match, int *simple_tag) 2156 { 2157 if (simple_tag != NULL) 2158 *simple_tag = 0; 2159 2160 /* make sure we have something to look at... */ 2161 assert (rcs != NULL); 2162 2163 if (tag && date) 2164 { 2165 char *branch, *rev; 2166 2167 if (! RCS_nodeisbranch (rcs, tag)) 2168 { 2169 /* We can't get a particular date if the tag is not a 2170 branch. */ 2171 return NULL; 2172 } 2173 2174 /* Work out the branch. */ 2175 if (! isdigit ((unsigned char) tag[0])) 2176 branch = RCS_whatbranch (rcs, tag); 2177 else 2178 branch = xstrdup (tag); 2179 2180 /* Fetch the revision of branch as of date. */ 2181 rev = RCS_getdatebranch (rcs, date, branch); 2182 free (branch); 2183 return rev; 2184 } 2185 else if (tag) 2186 return RCS_gettag (rcs, tag, force_tag_match, simple_tag); 2187 else if (date) 2188 return RCS_getdate (rcs, date, force_tag_match); 2189 else 2190 return RCS_head (rcs); 2191 2192 } 2193 2194 2195 2196 /* 2197 * Get existing revision number corresponding to tag or revision. 2198 * Similar to RCS_gettag but less interpretation imposed. 2199 * For example: 2200 * -- If tag designates a magic branch, RCS_tag2rev 2201 * returns the magic branch number. 2202 * -- If tag is a branch tag, returns the branch number, not 2203 * the revision of the head of the branch. 2204 * If tag or revision is not valid or does not exist in file, 2205 * return NULL. 2206 */ 2207 char * 2208 RCS_tag2rev (RCSNode *rcs, char *tag) 2209 { 2210 char *rev, *pa, *pb; 2211 int i; 2212 2213 assert (rcs != NULL); 2214 2215 if (rcs->flags & PARTIAL) 2216 RCS_reparsercsfile (rcs, NULL, NULL); 2217 2218 /* If a valid revision, try to look it up */ 2219 if ( RCS_valid_rev (tag) ) 2220 { 2221 /* Make a copy so we can scribble on it */ 2222 rev = xstrdup (tag); 2223 2224 /* If revision exists, return the copy */ 2225 if (RCS_exist_rev (rcs, tag)) 2226 return rev; 2227 2228 /* Nope, none such. If tag is not a branch we're done. */ 2229 i = numdots (rev); 2230 if ((i & 1) == 1 ) 2231 { 2232 pa = strrchr (rev, '.'); 2233 if (i == 1 || *(pa-1) != RCS_MAGIC_BRANCH || *(pa-2) != '.') 2234 { 2235 free (rev); 2236 error (1, 0, "revision `%s' does not exist", tag); 2237 } 2238 } 2239 2240 /* Try for a real (that is, exists in the RCS deltas) branch 2241 (RCS_exist_rev just checks for real revisions and revisions 2242 which have tags pointing to them). */ 2243 pa = RCS_getbranch (rcs, rev, 1); 2244 if (pa != NULL) 2245 { 2246 free (pa); 2247 return rev; 2248 } 2249 2250 /* Tag is branch, but does not exist, try corresponding 2251 * magic branch tag. 2252 * 2253 * FIXME: assumes all magic branches are of 2254 * form "n.n.n ... .0.n". I'll fix if somebody can 2255 * send me a method to get a magic branch tag with 2256 * the 0 in some other position -- <dan@gasboy.com> 2257 */ 2258 pa = strrchr (rev, '.'); 2259 if (!pa) 2260 /* This might happen, for instance, if an RCS file only contained 2261 * revisions 2.x and higher, and REV == "1". 2262 */ 2263 error (1, 0, "revision `%s' does not exist", tag); 2264 2265 *pa++ = 0; 2266 pb = Xasprintf ("%s.%d.%s", rev, RCS_MAGIC_BRANCH, pa); 2267 free (rev); 2268 rev = pb; 2269 if (RCS_exist_rev (rcs, rev)) 2270 return rev; 2271 error (1, 0, "revision `%s' does not exist", tag); 2272 } 2273 2274 2275 RCS_check_tag (tag); /* exit if not a valid tag */ 2276 2277 /* If tag is "HEAD", special case to get head RCS revision */ 2278 if (tag && STREQ (tag, TAG_HEAD)) 2279 return RCS_head (rcs); 2280 2281 /* If valid tag let translate_symtag say yea or nay. */ 2282 rev = translate_symtag (rcs, tag); 2283 2284 if (rev) 2285 return rev; 2286 2287 /* Trust the caller to print warnings. */ 2288 return NULL; 2289 } 2290 2291 2292 2293 /* 2294 * Find the revision for a specific tag. 2295 * If force_tag_match is set, return NULL if an exact match is not 2296 * possible otherwise return RCS_head (). We are careful to look for 2297 * and handle "magic" revisions specially. 2298 * 2299 * If the matched tag is a branch tag, find the head of the branch. 2300 * 2301 * Returns pointer to newly malloc'd string, or NULL. 2302 */ 2303 char * 2304 RCS_gettag (RCSNode *rcs, const char *symtag, int force_tag_match, 2305 int *simple_tag) 2306 { 2307 char *tag; 2308 2309 if (simple_tag != NULL) 2310 *simple_tag = 0; 2311 2312 /* make sure we have something to look at... */ 2313 assert (rcs != NULL); 2314 2315 /* XXX this is probably not necessary, --jtc */ 2316 if (rcs->flags & PARTIAL) 2317 RCS_reparsercsfile (rcs, NULL, NULL); 2318 2319 /* If symtag is "HEAD", special case to get head RCS revision */ 2320 if (symtag && STREQ (symtag, TAG_HEAD)) 2321 #if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */ 2322 if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC)) 2323 return NULL; /* head request for removed file */ 2324 else 2325 #endif 2326 return RCS_head (rcs); 2327 2328 if (!isdigit ((unsigned char) symtag[0])) 2329 { 2330 char *version; 2331 2332 /* If we got a symbolic tag, resolve it to a numeric */ 2333 version = translate_symtag (rcs, symtag); 2334 if (version != NULL) 2335 { 2336 int dots; 2337 char *magic, *branch, *cp; 2338 2339 tag = version; 2340 2341 /* 2342 * If this is a magic revision, we turn it into either its 2343 * physical branch equivalent (if one exists) or into 2344 * its base revision, which we assume exists. 2345 */ 2346 dots = numdots (tag); 2347 if (dots > 2 && (dots & 1) != 0) 2348 { 2349 branch = strrchr (tag, '.'); 2350 cp = branch++ - 1; 2351 while (*cp != '.') 2352 cp--; 2353 2354 /* see if we have .magic-branch. (".0.") */ 2355 magic = xmalloc (strlen (tag) + 1); 2356 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH); 2357 if (strncmp (magic, cp, strlen (magic)) == 0) 2358 { 2359 /* it's magic. See if the branch exists */ 2360 *cp = '\0'; /* turn it into a revision */ 2361 (void) sprintf (magic, "%s.%s", tag, branch); 2362 branch = RCS_getbranch (rcs, magic, 1); 2363 free (magic); 2364 if (branch != NULL) 2365 { 2366 free (tag); 2367 return branch; 2368 } 2369 return tag; 2370 } 2371 free (magic); 2372 } 2373 } 2374 else 2375 { 2376 /* The tag wasn't there, so return the head or NULL */ 2377 if (force_tag_match) 2378 return NULL; 2379 else 2380 return RCS_head (rcs); 2381 } 2382 } 2383 else 2384 tag = xstrdup (symtag); 2385 2386 /* tag is always allocated and numeric now. */ 2387 2388 /* 2389 * numeric tag processing: 2390 * 1) revision number - just return it 2391 * 2) branch number - find head of branch 2392 */ 2393 2394 /* strip trailing dots */ 2395 while (tag[strlen (tag) - 1] == '.') 2396 tag[strlen (tag) - 1] = '\0'; 2397 2398 if ((numdots (tag) & 1) == 0) 2399 { 2400 char *branch; 2401 2402 /* we have a branch tag, so we need to walk the branch */ 2403 branch = RCS_getbranch (rcs, tag, force_tag_match); 2404 free (tag); 2405 return branch; 2406 } 2407 else 2408 { 2409 Node *p; 2410 2411 /* we have a revision tag, so make sure it exists */ 2412 p = findnode (rcs->versions, tag); 2413 if (p != NULL) 2414 { 2415 /* We have found a numeric revision for the revision tag. 2416 To support expanding the RCS keyword Name, if 2417 SIMPLE_TAG is not NULL, tell the the caller that this 2418 is a simple tag which co will recognize. FIXME: Are 2419 there other cases in which we should set this? In 2420 particular, what if we expand RCS keywords internally 2421 without calling co? */ 2422 if (simple_tag != NULL) 2423 *simple_tag = 1; 2424 return tag; 2425 } 2426 else 2427 { 2428 /* The revision wasn't there, so return the head or NULL */ 2429 free (tag); 2430 if (force_tag_match) 2431 return NULL; 2432 else 2433 return RCS_head (rcs); 2434 } 2435 } 2436 } 2437 2438 2439 2440 /* 2441 * Return a "magic" revision as a virtual branch off of REV for the RCS file. 2442 * A "magic" revision is one which is unique in the RCS file. By unique, I 2443 * mean we return a revision which: 2444 * - has a branch of 0 (see rcs.h RCS_MAGIC_BRANCH) 2445 * - has a revision component which is not an existing branch off REV 2446 * - has a revision component which is not an existing magic revision 2447 * - is an even-numbered revision, to avoid conflicts with vendor branches 2448 * The first point is what makes it "magic". 2449 * 2450 * As an example, if we pass in 1.37 as REV, we will look for an existing 2451 * branch called 1.37.2. If it did not exist, we would look for an 2452 * existing symbolic tag with a numeric part equal to 1.37.0.2. If that 2453 * didn't exist, then we know that the 1.37.2 branch can be reserved by 2454 * creating a symbolic tag with 1.37.0.2 as the numeric part. 2455 * 2456 * This allows us to fork development with very little overhead -- just a 2457 * symbolic tag is used in the RCS file. When a commit is done, a physical 2458 * branch is dynamically created to hold the new revision. 2459 * 2460 * Note: We assume that REV is an RCS revision and not a branch number. 2461 */ 2462 static char *check_rev; 2463 char * 2464 RCS_magicrev (RCSNode *rcs, char *rev) 2465 { 2466 int rev_num; 2467 char *xrev, *test_branch, *local_branch_num; 2468 2469 xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */ 2470 check_rev = xrev; 2471 2472 local_branch_num = getenv("CVS_LOCAL_BRANCH_NUM"); 2473 if (local_branch_num) 2474 { 2475 rev_num = atoi(local_branch_num); 2476 if (rev_num < 2) 2477 rev_num = 2; 2478 else 2479 rev_num &= ~1; 2480 } 2481 else 2482 rev_num = 2; 2483 2484 /* only look at even numbered branches */ 2485 for ( ; ; rev_num += 2) 2486 { 2487 /* see if the physical branch exists */ 2488 (void) sprintf (xrev, "%s.%d", rev, rev_num); 2489 test_branch = RCS_getbranch (rcs, xrev, 1); 2490 if (test_branch != NULL) /* it did, so keep looking */ 2491 { 2492 free (test_branch); 2493 continue; 2494 } 2495 2496 /* now, create a "magic" revision */ 2497 (void) sprintf (xrev, "%s.%d.%d", rev, RCS_MAGIC_BRANCH, rev_num); 2498 2499 /* walk the symbols list to see if a magic one already exists */ 2500 if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0) 2501 continue; 2502 2503 /* we found a free magic branch. Claim it as ours */ 2504 return xrev; 2505 } 2506 } 2507 2508 2509 2510 /* 2511 * walklist proc to look for a match in the symbols list. 2512 * Returns 0 if the symbol does not match, 1 if it does. 2513 */ 2514 static int 2515 checkmagic_proc (Node *p, void *closure) 2516 { 2517 if (STREQ (check_rev, p->data)) 2518 return 1; 2519 else 2520 return 0; 2521 } 2522 2523 2524 2525 /* 2526 * Given an RCSNode, returns non-zero if the specified revision number 2527 * or symbolic tag resolves to a "branch" within the rcs file. 2528 * 2529 * FIXME: this is the same as RCS_nodeisbranch except for the special 2530 * case for handling a null rcsnode. 2531 */ 2532 int 2533 RCS_isbranch (RCSNode *rcs, const char *rev) 2534 { 2535 /* numeric revisions are easy -- even number of dots is a branch */ 2536 if (isdigit ((unsigned char) *rev)) 2537 return (numdots (rev) & 1) == 0; 2538 2539 /* assume a revision if you can't find the RCS info */ 2540 if (rcs == NULL) 2541 return 0; 2542 2543 /* now, look for a match in the symbols list */ 2544 return RCS_nodeisbranch (rcs, rev); 2545 } 2546 2547 2548 2549 /* 2550 * Given an RCSNode, returns non-zero if the specified revision number 2551 * or symbolic tag resolves to a "branch" within the rcs file. We do 2552 * take into account any magic branches as well. 2553 */ 2554 int 2555 RCS_nodeisbranch (RCSNode *rcs, const char *rev) 2556 { 2557 int dots; 2558 char *version; 2559 2560 assert (rcs != NULL); 2561 2562 /* numeric revisions are easy -- even number of dots is a branch */ 2563 if (isdigit ((unsigned char) *rev)) 2564 return (numdots (rev) & 1) == 0; 2565 2566 version = translate_symtag (rcs, rev); 2567 if (version == NULL) 2568 return 0; 2569 dots = numdots (version); 2570 if ((dots & 1) == 0) 2571 { 2572 free (version); 2573 return 1; 2574 } 2575 2576 /* got a symbolic tag match, but it's not a branch; see if it's magic */ 2577 if (dots > 2) 2578 { 2579 char *magic; 2580 char *branch = strrchr (version, '.'); 2581 char *cp = branch - 1; 2582 while (*cp != '.') 2583 cp--; 2584 2585 /* see if we have .magic-branch. (".0.") */ 2586 magic = Xasprintf (".%d.", RCS_MAGIC_BRANCH); 2587 if (strncmp (magic, cp, strlen (magic)) == 0) 2588 { 2589 free (magic); 2590 free (version); 2591 return 1; 2592 } 2593 free (magic); 2594 } 2595 free (version); 2596 return 0; 2597 } 2598 2599 2600 2601 /* 2602 * Returns a pointer to malloc'ed memory which contains the branch 2603 * for the specified *symbolic* tag. Magic branches are handled correctly. 2604 */ 2605 char * 2606 RCS_whatbranch (RCSNode *rcs, const char *rev) 2607 { 2608 char *version; 2609 int dots; 2610 2611 /* assume no branch if you can't find the RCS info */ 2612 if (rcs == NULL) 2613 return NULL; 2614 2615 /* now, look for a match in the symbols list */ 2616 version = translate_symtag (rcs, rev); 2617 if (version == NULL) 2618 return NULL; 2619 dots = numdots (version); 2620 if ((dots & 1) == 0) 2621 return version; 2622 2623 /* got a symbolic tag match, but it's not a branch; see if it's magic */ 2624 if (dots > 2) 2625 { 2626 char *magic; 2627 char *branch = strrchr (version, '.'); 2628 char *cp = branch++ - 1; 2629 while (*cp != '.') 2630 cp--; 2631 2632 /* see if we have .magic-branch. (".0.") */ 2633 magic = xmalloc (strlen (version) + 1); 2634 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH); 2635 if (strncmp (magic, cp, strlen (magic)) == 0) 2636 { 2637 /* yep. it's magic. now, construct the real branch */ 2638 *cp = '\0'; /* turn it into a revision */ 2639 (void) sprintf (magic, "%s.%s", version, branch); 2640 free (version); 2641 return magic; 2642 } 2643 free (magic); 2644 } 2645 free (version); 2646 return NULL; 2647 } 2648 2649 2650 2651 /* 2652 * Get the head of the specified branch. If the branch does not exist, 2653 * return NULL or RCS_head depending on force_tag_match. 2654 * Returns NULL or a newly malloc'd string. 2655 */ 2656 char * 2657 RCS_getbranch (RCSNode *rcs, const char *tag, int force_tag_match) 2658 { 2659 Node *p, *head; 2660 RCSVers *vn; 2661 char *xtag; 2662 char *nextvers; 2663 char *cp; 2664 2665 /* make sure we have something to look at... */ 2666 assert (rcs != NULL); 2667 2668 if (rcs->flags & PARTIAL) 2669 RCS_reparsercsfile (rcs, NULL, NULL); 2670 2671 /* find out if the tag contains a dot, or is on the trunk */ 2672 cp = strrchr (tag, '.'); 2673 2674 /* trunk processing is the special case */ 2675 if (cp == NULL) 2676 { 2677 xtag = Xasprintf ("%s.", tag); 2678 for (cp = rcs->head; cp != NULL;) 2679 { 2680 if (strncmp (xtag, cp, strlen (xtag)) == 0) 2681 break; 2682 p = findnode (rcs->versions, cp); 2683 if (p == NULL) 2684 { 2685 free (xtag); 2686 if (force_tag_match) 2687 return NULL; 2688 else 2689 return RCS_head (rcs); 2690 } 2691 vn = p->data; 2692 cp = vn->next; 2693 } 2694 free (xtag); 2695 if (cp == NULL) 2696 { 2697 if (force_tag_match) 2698 return NULL; 2699 else 2700 return RCS_head (rcs); 2701 } 2702 return xstrdup (cp); 2703 } 2704 2705 /* if it had a `.', terminate the string so we have the base revision */ 2706 *cp = '\0'; 2707 2708 /* look up the revision this branch is based on */ 2709 p = findnode (rcs->versions, tag); 2710 2711 /* put the . back so we have the branch again */ 2712 *cp = '.'; 2713 2714 if (p == NULL) 2715 { 2716 /* if the base revision didn't exist, return head or NULL */ 2717 if (force_tag_match) 2718 return NULL; 2719 else 2720 return RCS_head (rcs); 2721 } 2722 2723 /* find the first element of the branch we are looking for */ 2724 vn = p->data; 2725 if (vn->branches == NULL) 2726 return NULL; 2727 xtag = Xasprintf ("%s.", tag); 2728 head = vn->branches->list; 2729 for (p = head->next; p != head; p = p->next) 2730 if (strncmp (p->key, xtag, strlen (xtag)) == 0) 2731 break; 2732 free (xtag); 2733 2734 if (p == head) 2735 { 2736 /* we didn't find a match so return head or NULL */ 2737 if (force_tag_match) 2738 return NULL; 2739 else 2740 return RCS_head (rcs); 2741 } 2742 2743 /* now walk the next pointers of the branch */ 2744 nextvers = p->key; 2745 do 2746 { 2747 p = findnode (rcs->versions, nextvers); 2748 if (p == NULL) 2749 { 2750 /* a link in the chain is missing - return head or NULL */ 2751 if (force_tag_match) 2752 return NULL; 2753 else 2754 return RCS_head (rcs); 2755 } 2756 vn = p->data; 2757 nextvers = vn->next; 2758 } while (nextvers != NULL); 2759 2760 /* we have the version in our hand, so go for it */ 2761 return xstrdup (vn->version); 2762 } 2763 2764 2765 2766 /* Returns the head of the branch which REV is on. REV can be a 2767 branch tag or non-branch tag; symbolic or numeric. 2768 2769 Returns a newly malloc'd string. Returns NULL if a symbolic name 2770 isn't found. */ 2771 char * 2772 RCS_branch_head (RCSNode *rcs, char *rev) 2773 { 2774 char *num; 2775 char *br; 2776 char *retval; 2777 2778 assert (rcs != NULL); 2779 2780 if (RCS_nodeisbranch (rcs, rev)) 2781 return RCS_getbranch (rcs, rev, 1); 2782 2783 if (isdigit ((unsigned char) *rev)) 2784 num = xstrdup (rev); 2785 else 2786 { 2787 num = translate_symtag (rcs, rev); 2788 if (num == NULL) 2789 return NULL; 2790 } 2791 br = truncate_revnum (num); 2792 retval = RCS_getbranch (rcs, br, 1); 2793 free (br); 2794 free (num); 2795 return retval; 2796 } 2797 2798 2799 2800 /* Get the branch point for a particular branch, that is the first 2801 revision on that branch. For example, RCS_getbranchpoint (rcs, 2802 "1.3.2") will normally return "1.3.2.1". TARGET may be either a 2803 branch number or a revision number; if a revnum, find the 2804 branchpoint of the branch to which TARGET belongs. 2805 2806 Return RCS_head if TARGET is on the trunk or if the root node could 2807 not be found (this is sort of backwards from our behavior on a branch; 2808 the rationale is that the return value is a revision from which you 2809 can start walking the next fields and end up at TARGET). 2810 Return NULL on error. */ 2811 static char * 2812 RCS_getbranchpoint (RCSNode *rcs, char *target) 2813 { 2814 char *branch, *bp; 2815 Node *vp; 2816 RCSVers *rev; 2817 int dots, isrevnum, brlen; 2818 2819 dots = numdots (target); 2820 isrevnum = dots & 1; 2821 2822 if (dots == 1) 2823 /* TARGET is a trunk revision; return rcs->head. */ 2824 return RCS_head (rcs); 2825 2826 /* Get the revision number of the node at which TARGET's branch is 2827 rooted. If TARGET is a branch number, lop off the last field; 2828 if it's a revision number, lop off the last *two* fields. */ 2829 branch = xstrdup (target); 2830 bp = strrchr (branch, '.'); 2831 if (bp == NULL) 2832 error (1, 0, "%s: confused revision number %s", 2833 rcs->print_path, target); 2834 if (isrevnum) 2835 while (*--bp != '.') 2836 ; 2837 *bp = '\0'; 2838 2839 vp = findnode (rcs->versions, branch); 2840 if (vp == NULL) 2841 { 2842 error (0, 0, "%s: can't find branch point %s", rcs->print_path, target); 2843 free (branch); 2844 return NULL; 2845 } 2846 rev = vp->data; 2847 2848 *bp++ = '.'; 2849 while (*bp && *bp != '.') 2850 ++bp; 2851 brlen = bp - branch; 2852 2853 vp = rev->branches->list->next; 2854 while (vp != rev->branches->list) 2855 { 2856 /* BRANCH may be a genuine branch number, e.g. `1.1.3', or 2857 maybe a full revision number, e.g. `1.1.3.6'. We have 2858 found our branch point if the first BRANCHLEN characters 2859 of the revision number match, *and* if the following 2860 character is a dot. */ 2861 if (strncmp (vp->key, branch, brlen) == 0 && vp->key[brlen] == '.') 2862 break; 2863 vp = vp->next; 2864 } 2865 2866 free (branch); 2867 if (vp == rev->branches->list) 2868 { 2869 error (0, 0, "%s: can't find branch point %s", rcs->print_path, target); 2870 return NULL; 2871 } 2872 else 2873 return xstrdup (vp->key); 2874 } 2875 2876 2877 2878 /* 2879 * Get the head of the RCS file. If branch is set, this is the head of the 2880 * branch, otherwise the real head. 2881 * 2882 * INPUTS 2883 * rcs The parsed rcs node information. 2884 * 2885 * RETURNS 2886 * NULL when rcs->branch exists and cannot be found. 2887 * A newly malloc'd string, otherwise. 2888 */ 2889 char * 2890 RCS_head (RCSNode *rcs) 2891 { 2892 /* make sure we have something to look at... */ 2893 assert (rcs); 2894 2895 /* 2896 * NOTE: we call getbranch with force_tag_match set to avoid any 2897 * possibility of recursion 2898 */ 2899 if (rcs->branch) 2900 return RCS_getbranch (rcs, rcs->branch, 1); 2901 else 2902 return xstrdup (rcs->head); 2903 } 2904 2905 2906 2907 /* 2908 * Get the most recent revision, based on the supplied date, but use some 2909 * funky stuff and follow the vendor branch maybe 2910 */ 2911 char * 2912 RCS_getdate (RCSNode *rcs, const char *date, int force_tag_match) 2913 { 2914 char *cur_rev = NULL; 2915 char *retval = NULL; 2916 Node *p; 2917 RCSVers *vers = NULL; 2918 2919 /* make sure we have something to look at... */ 2920 assert (rcs != NULL); 2921 2922 if (rcs->flags & PARTIAL) 2923 RCS_reparsercsfile (rcs, NULL, NULL); 2924 2925 /* if the head is on a branch, try the branch first */ 2926 if (rcs->branch != NULL) 2927 { 2928 retval = RCS_getdatebranch (rcs, date, rcs->branch); 2929 if (retval != NULL) 2930 return retval; 2931 } 2932 2933 /* otherwise if we have a trunk, try it */ 2934 if (rcs->head) 2935 { 2936 p = findnode (rcs->versions, rcs->head); 2937 if (p == NULL) 2938 { 2939 error (0, 0, "%s: head revision %s doesn't exist", rcs->print_path, 2940 rcs->head); 2941 } 2942 while (p != NULL) 2943 { 2944 /* if the date of this one is before date, take it */ 2945 vers = p->data; 2946 if (RCS_datecmp (vers->date, date) <= 0) 2947 { 2948 cur_rev = vers->version; 2949 break; 2950 } 2951 2952 /* if there is a next version, find the node */ 2953 if (vers->next != NULL) 2954 p = findnode (rcs->versions, vers->next); 2955 else 2956 p = NULL; 2957 } 2958 } 2959 else 2960 error (0, 0, "%s: no head revision", rcs->print_path); 2961 2962 /* 2963 * at this point, either we have the revision we want, or we have the 2964 * first revision on the trunk (1.1?) in our hands, or we've come up 2965 * completely empty 2966 */ 2967 2968 /* if we found what we're looking for, and it's not 1.1 return it */ 2969 if (cur_rev != NULL) 2970 { 2971 if (! STREQ (cur_rev, "1.1")) 2972 return xstrdup (cur_rev); 2973 2974 /* This is 1.1; if the date of 1.1 is not the same as that for the 2975 1.1.1.1 version, then return 1.1. This happens when the first 2976 version of a file is created by a regular cvs add and commit, 2977 and there is a subsequent cvs import of the same file. */ 2978 p = findnode (rcs->versions, "1.1.1.1"); 2979 if (p) 2980 { 2981 char *date_1_1 = vers->date; 2982 2983 vers = p->data; 2984 if (RCS_datecmp (vers->date, date_1_1) != 0) 2985 return xstrdup ("1.1"); 2986 } 2987 } 2988 2989 /* look on the vendor branch */ 2990 retval = RCS_getdatebranch (rcs, date, CVSBRANCH); 2991 2992 /* 2993 * if we found a match, return it; otherwise, we return the first 2994 * revision on the trunk or NULL depending on force_tag_match and the 2995 * date of the first rev 2996 */ 2997 if (retval != NULL) 2998 return retval; 2999 3000 if (vers && (!force_tag_match || RCS_datecmp (vers->date, date) <= 0)) 3001 return xstrdup (vers->version); 3002 else 3003 return NULL; 3004 } 3005 3006 3007 3008 /* 3009 * Look up the last element on a branch that was put in before or on 3010 * the specified date and time (return the rev or NULL) 3011 */ 3012 static char * 3013 RCS_getdatebranch (RCSNode *rcs, const char *date, const char *branch) 3014 { 3015 char *cur_rev = NULL; 3016 char *cp; 3017 char *xbranch, *xrev; 3018 Node *p; 3019 RCSVers *vers; 3020 3021 /* look up the first revision on the branch */ 3022 xrev = xstrdup (branch); 3023 cp = strrchr (xrev, '.'); 3024 if (cp == NULL) 3025 { 3026 free (xrev); 3027 return NULL; 3028 } 3029 *cp = '\0'; /* turn it into a revision */ 3030 3031 assert (rcs != NULL); 3032 3033 if (rcs->flags & PARTIAL) 3034 RCS_reparsercsfile (rcs, NULL, NULL); 3035 3036 p = findnode (rcs->versions, xrev); 3037 free (xrev); 3038 if (p == NULL) 3039 return NULL; 3040 vers = p->data; 3041 3042 /* Tentatively use this revision, if it is early enough. */ 3043 if (RCS_datecmp (vers->date, date) <= 0) 3044 cur_rev = vers->version; 3045 3046 /* If no branches list, return now. This is what happens if the branch 3047 is a (magic) branch with no revisions yet. */ 3048 if (vers->branches == NULL) 3049 return xstrdup (cur_rev); 3050 3051 /* walk the branches list looking for the branch number */ 3052 xbranch = Xasprintf ("%s.", branch); 3053 for (p = vers->branches->list->next; p != vers->branches->list; p = p->next) 3054 if (strncmp (p->key, xbranch, strlen (xbranch)) == 0) 3055 break; 3056 free (xbranch); 3057 if (p == vers->branches->list) 3058 { 3059 /* This is what happens if the branch is a (magic) branch with 3060 no revisions yet. Similar to the case where vers->branches == 3061 NULL, except here there was a another branch off the same 3062 branchpoint. */ 3063 return xstrdup (cur_rev); 3064 } 3065 3066 p = findnode (rcs->versions, p->key); 3067 3068 /* walk the next pointers until you find the end, or the date is too late */ 3069 while (p != NULL) 3070 { 3071 vers = p->data; 3072 if (RCS_datecmp (vers->date, date) <= 0) 3073 cur_rev = vers->version; 3074 else 3075 break; 3076 3077 /* if there is a next version, find the node */ 3078 if (vers->next != NULL) 3079 p = findnode (rcs->versions, vers->next); 3080 else 3081 p = NULL; 3082 } 3083 3084 /* Return whatever we found, which may be NULL. */ 3085 return xstrdup (cur_rev); 3086 } 3087 3088 3089 3090 /* 3091 * Compare two dates in RCS format. Beware the change in format on January 1, 3092 * 2000, when years go from 2-digit to full format. 3093 */ 3094 int 3095 RCS_datecmp (const char *date1, const char *date2) 3096 { 3097 int length_diff = strlen (date1) - strlen (date2); 3098 3099 return length_diff ? length_diff : strcmp (date1, date2); 3100 } 3101 3102 3103 3104 /* Look up revision REV in RCS and return the date specified for the 3105 revision minus FUDGE seconds (FUDGE will generally be one, so that the 3106 logically previous revision will be found later, or zero, if we want 3107 the exact date). 3108 3109 The return value is the date being returned as a time_t, or (time_t)-1 3110 on error (previously was documented as zero on error; I haven't checked 3111 the callers to make sure that they really check for (time_t)-1, but 3112 the latter is what this function really returns). If DATE is non-NULL, 3113 then it must point to MAXDATELEN characters, and we store the same 3114 return value there in DATEFORM format. */ 3115 time_t 3116 RCS_getrevtime (RCSNode *rcs, const char *rev, char *date, int fudge) 3117 { 3118 char *tdate; 3119 struct tm xtm, *ftm; 3120 struct timespec revdate; 3121 Node *p; 3122 RCSVers *vers; 3123 3124 /* make sure we have something to look at... */ 3125 assert (rcs != NULL); 3126 3127 if (rcs->flags & PARTIAL) 3128 RCS_reparsercsfile (rcs, NULL, NULL); 3129 3130 /* look up the revision */ 3131 p = findnode (rcs->versions, rev); 3132 if (p == NULL) 3133 return -1; 3134 vers = p->data; 3135 3136 /* split up the date */ 3137 if (sscanf (vers->date, SDATEFORM, &xtm.tm_year, &xtm.tm_mon, 3138 &xtm.tm_mday, &xtm.tm_hour, &xtm.tm_min, &xtm.tm_sec) != 6) 3139 error (1, 0, "%s: invalid date for revision %s (%s)", rcs->print_path, 3140 rev, vers->date); 3141 3142 /* If the year is from 1900 to 1999, RCS files contain only two 3143 digits, and sscanf gives us a year from 0-99. If the year is 3144 2000+, RCS files contain all four digits and we subtract 1900, 3145 because the tm_year field should contain years since 1900. */ 3146 3147 if (xtm.tm_year >= 100 && xtm.tm_year < 2000) 3148 error (0, 0, "%s: non-standard date format for revision %s (%s)", 3149 rcs->print_path, rev, vers->date); 3150 if (xtm.tm_year >= 1900) 3151 xtm.tm_year -= 1900; 3152 3153 /* put the date in a form getdate can grok */ 3154 tdate = Xasprintf ("%d-%d-%d %d:%d:%d -0000", 3155 xtm.tm_year + 1900, xtm.tm_mon, xtm.tm_mday, 3156 xtm.tm_hour, xtm.tm_min, xtm.tm_sec); 3157 3158 /* Turn it into seconds since the epoch. 3159 * 3160 * We use a struct timespec since that is what getdate requires, then 3161 * truncate the nanoseconds. 3162 */ 3163 if (!get_date (&revdate, tdate, NULL)) 3164 { 3165 free (tdate); 3166 return (time_t)-1; 3167 } 3168 free (tdate); 3169 3170 revdate.tv_sec -= fudge; /* remove "fudge" seconds */ 3171 if (date) 3172 { 3173 /* Put an appropriate string into `date', if we were given one. */ 3174 ftm = gmtime (&revdate.tv_sec); 3175 (void) sprintf (date, DATEFORM, 3176 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), 3177 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, 3178 ftm->tm_min, ftm->tm_sec); 3179 } 3180 3181 return revdate.tv_sec; 3182 } 3183 3184 3185 3186 List * 3187 RCS_getlocks (RCSNode *rcs) 3188 { 3189 assert(rcs != NULL); 3190 3191 if (rcs->flags & PARTIAL) 3192 RCS_reparsercsfile (rcs, NULL, NULL); 3193 3194 if (rcs->locks_data) { 3195 rcs->locks = getlist (); 3196 do_locks (rcs->locks, rcs->locks_data); 3197 free(rcs->locks_data); 3198 rcs->locks_data = NULL; 3199 } 3200 3201 return rcs->locks; 3202 } 3203 3204 3205 3206 List * 3207 RCS_symbols(RCSNode *rcs) 3208 { 3209 assert(rcs != NULL); 3210 3211 if (rcs->flags & PARTIAL) 3212 RCS_reparsercsfile (rcs, NULL, NULL); 3213 3214 if (rcs->symbols_data) { 3215 rcs->symbols = getlist (); 3216 do_symbols (rcs->symbols, rcs->symbols_data); 3217 free(rcs->symbols_data); 3218 rcs->symbols_data = NULL; 3219 } 3220 3221 return rcs->symbols; 3222 } 3223 3224 3225 3226 /* 3227 * Return the version associated with a particular symbolic tag. 3228 * Returns NULL or a newly malloc'd string. 3229 */ 3230 static char * 3231 translate_symtag (RCSNode *rcs, const char *tag) 3232 { 3233 if (rcs->flags & PARTIAL) 3234 RCS_reparsercsfile (rcs, NULL, NULL); 3235 3236 if (rcs->symbols != NULL) 3237 { 3238 Node *p; 3239 3240 /* The symbols have already been converted into a list. */ 3241 p = findnode (rcs->symbols, tag); 3242 if (p == NULL) 3243 return NULL; 3244 3245 return xstrdup (p->data); 3246 } 3247 3248 if (rcs->symbols_data != NULL) 3249 { 3250 size_t len; 3251 char *cp, *last; 3252 3253 /* Look through the RCS symbols information. This is like 3254 do_symbols, but we don't add the information to a list. In 3255 most cases, we will only be called once for this file, so 3256 generating the list is unnecessary overhead. */ 3257 3258 len = strlen (tag); 3259 cp = rcs->symbols_data; 3260 /* Keeping track of LAST below isn't strictly necessary, now that tags 3261 * should be parsed for validity before they are accepted, but tags 3262 * with spaces used to cause the code below to loop indefintely, so 3263 * I have corrected for that. Now, in the event that I missed 3264 * something, the server cannot be hung. -DRP 3265 */ 3266 last = NULL; 3267 while ((cp = strchr (cp, tag[0])) != NULL) 3268 { 3269 if (cp == last) break; 3270 if ((cp == rcs->symbols_data || whitespace (cp[-1])) 3271 && strncmp (cp, tag, len) == 0 3272 && cp[len] == ':') 3273 { 3274 char *v, *r; 3275 3276 /* We found the tag. Return the version number. */ 3277 3278 cp += len + 1; 3279 v = cp; 3280 while (! whitespace (*cp) && *cp != '\0') 3281 ++cp; 3282 r = xmalloc (cp - v + 1); 3283 strncpy (r, v, cp - v); 3284 r[cp - v] = '\0'; 3285 return r; 3286 } 3287 3288 while (! whitespace (*cp) && *cp != '\0') 3289 ++cp; 3290 if (*cp == '\0') 3291 break; 3292 last = cp; 3293 } 3294 } 3295 3296 return NULL; 3297 } 3298 3299 3300 3301 /* 3302 * The argument ARG is the getopt remainder of the -k option specified on the 3303 * command line. This function returns malloc'ed space that can be used 3304 * directly in calls to RCS V5, with the -k flag munged correctly. 3305 */ 3306 char * 3307 RCS_check_kflag (const char *arg) 3308 { 3309 static const char *const keyword_usage[] = 3310 { 3311 "%s %s: invalid RCS keyword expansion mode\n", 3312 "Valid expansion modes include:\n", 3313 " -kkv\tGenerate keywords using the default form.\n", 3314 " -kkvl\tLike -kkv, except locker's name inserted.\n", 3315 " -kk\tGenerate only keyword names in keyword strings.\n", 3316 " -kv\tGenerate only keyword values in keyword strings.\n", 3317 " -ko\tGenerate the old keyword string (no changes from checked in file).\n", 3318 " -kb\tGenerate binary file unmodified (merges not allowed) (RCS 5.7).\n", 3319 "(Specify the --help global option for a list of other help options)\n", 3320 NULL, 3321 }; 3322 char const *const *cpp = NULL; 3323 3324 if (arg) 3325 { 3326 for (cpp = kflags; *cpp != NULL; cpp++) 3327 { 3328 if (STREQ (arg, *cpp)) 3329 break; 3330 } 3331 } 3332 3333 if (arg == NULL || *cpp == NULL) 3334 { 3335 usage (keyword_usage); 3336 } 3337 3338 return Xasprintf ("-k%s", *cpp); 3339 } 3340 3341 3342 3343 /* 3344 * Do some consistency checks on the symbolic tag... These should equate 3345 * pretty close to what RCS checks, though I don't know for certain. 3346 */ 3347 void 3348 RCS_check_tag (const char *tag) 3349 { 3350 char *invalid = "$,.:;@"; /* invalid RCS tag characters */ 3351 const char *cp; 3352 3353 /* 3354 * The first character must be an alphabetic letter. The remaining 3355 * characters cannot be non-visible graphic characters, and must not be 3356 * in the set of "invalid" RCS identifier characters. 3357 */ 3358 if (isalpha ((unsigned char) *tag)) 3359 { 3360 for (cp = tag; *cp; cp++) 3361 { 3362 if (!isgraph ((unsigned char) *cp)) 3363 error (1, 0, "tag `%s' has non-visible graphic characters", 3364 tag); 3365 if (strchr (invalid, *cp)) 3366 error (1, 0, "tag `%s' must not contain the characters `%s'", 3367 tag, invalid); 3368 } 3369 } 3370 else 3371 error (1, 0, "tag `%s' must start with a letter", tag); 3372 } 3373 3374 3375 3376 /* 3377 * TRUE if argument has valid syntax for an RCS revision or 3378 * branch number. All characters must be digits or dots, first 3379 * and last characters must be digits, and no two consecutive 3380 * characters may be dots. 3381 * 3382 * Intended for classifying things, so this function doesn't 3383 * call error. 3384 */ 3385 int 3386 RCS_valid_rev (const char *rev) 3387 { 3388 char last, c; 3389 last = *rev++; 3390 if (!isdigit ((unsigned char) last)) 3391 return 0; 3392 while ((c = *rev++)) /* Extra parens placate -Wall gcc option */ 3393 { 3394 if (c == '.') 3395 { 3396 if (last == '.') 3397 return 0; 3398 continue; 3399 } 3400 last = c; 3401 if (!isdigit ((unsigned char) c)) 3402 return 0; 3403 } 3404 if (!isdigit ((unsigned char) last)) 3405 return 0; 3406 return 1; 3407 } 3408 3409 3410 3411 /* 3412 * Return true if RCS revision with TAG is a dead revision. 3413 */ 3414 int 3415 RCS_isdead (RCSNode *rcs, const char *tag) 3416 { 3417 Node *p; 3418 RCSVers *version; 3419 3420 if (rcs->flags & PARTIAL) 3421 RCS_reparsercsfile (rcs, NULL, NULL); 3422 3423 p = findnode (rcs->versions, tag); 3424 if (p == NULL) 3425 return 0; 3426 3427 version = p->data; 3428 return version->dead; 3429 } 3430 3431 3432 3433 /* Return the RCS keyword expansion mode. For example "b" for binary. 3434 Returns a pointer into storage which is allocated and freed along with 3435 the rest of the RCS information; the caller should not modify this 3436 storage. Returns NULL if the RCS file does not specify a keyword 3437 expansion mode; for all other errors, die with a fatal error. */ 3438 char * 3439 RCS_getexpand (RCSNode *rcs) 3440 { 3441 /* Since RCS_parsercsfile_i now reads expand, don't need to worry 3442 about RCS_reparsercsfile. */ 3443 assert (rcs != NULL); 3444 return rcs->expand; 3445 } 3446 3447 3448 3449 /* Set keyword expansion mode to EXPAND. For example "b" for binary. */ 3450 void 3451 RCS_setexpand (RCSNode *rcs, const char *expand) 3452 { 3453 /* Since RCS_parsercsfile_i now reads expand, don't need to worry 3454 about RCS_reparsercsfile. */ 3455 assert (rcs != NULL); 3456 if (rcs->expand != NULL) 3457 free (rcs->expand); 3458 rcs->expand = xstrdup (expand); 3459 } 3460 3461 3462 3463 /* RCS keywords, and a matching enum. */ 3464 enum keyword 3465 { 3466 KEYWORD_AUTHOR = 0, 3467 KEYWORD_DATE, 3468 KEYWORD_CVSHEADER, 3469 KEYWORD_HEADER, 3470 KEYWORD_ID, 3471 KEYWORD_LOCKER, 3472 KEYWORD_LOG, 3473 KEYWORD_NAME, 3474 KEYWORD_RCSFILE, 3475 KEYWORD_REVISION, 3476 KEYWORD_SOURCE, 3477 KEYWORD_STATE, 3478 KEYWORD_LOCALID 3479 }; 3480 struct rcs_keyword 3481 { 3482 const char *string; 3483 size_t len; 3484 enum keyword expandto; 3485 bool expandit; 3486 }; 3487 3488 3489 3490 static inline struct rcs_keyword * 3491 new_keywords (void) 3492 { 3493 struct rcs_keyword *new; 3494 new = xcalloc (KEYWORD_LOCALID + 2, sizeof (struct rcs_keyword)); 3495 3496 #define KEYWORD_INIT(k, i, s) \ 3497 k[i].string = s; \ 3498 k[i].len = sizeof s - 1; \ 3499 k[i].expandto = i; \ 3500 k[i].expandit = true 3501 3502 KEYWORD_INIT (new, KEYWORD_AUTHOR, "Author"); 3503 KEYWORD_INIT (new, KEYWORD_DATE, "Date"); 3504 KEYWORD_INIT (new, KEYWORD_CVSHEADER, "CVSHeader"); 3505 KEYWORD_INIT (new, KEYWORD_HEADER, "Header"); 3506 KEYWORD_INIT (new, KEYWORD_ID, "Id"); 3507 KEYWORD_INIT (new, KEYWORD_LOCKER, "Locker"); 3508 KEYWORD_INIT (new, KEYWORD_LOG, "Log"); 3509 KEYWORD_INIT (new, KEYWORD_NAME, "Name"); 3510 KEYWORD_INIT (new, KEYWORD_RCSFILE, "RCSfile"); 3511 KEYWORD_INIT (new, KEYWORD_REVISION, "Revision"); 3512 KEYWORD_INIT (new, KEYWORD_SOURCE, "Source"); 3513 KEYWORD_INIT (new, KEYWORD_STATE, "State"); 3514 3515 return new; 3516 } 3517 3518 3519 3520 void 3521 free_keywords (void *keywords) 3522 { 3523 free (keywords); 3524 } 3525 3526 3527 3528 /* Convert an RCS date string into a readable string. This is like 3529 the RCS date2str function. */ 3530 static char * 3531 printable_date (const char *rcs_date) 3532 { 3533 int year, mon, mday, hour, min, sec; 3534 char buf[100]; 3535 3536 (void) sscanf (rcs_date, SDATEFORM, &year, &mon, &mday, &hour, &min, 3537 &sec); 3538 if (year < 1900) 3539 year += 1900; 3540 sprintf (buf, "%04d/%02d/%02d %02d:%02d:%02d", year, mon, mday, 3541 hour, min, sec); 3542 return xstrdup (buf); 3543 } 3544 3545 3546 3547 /* Escape the characters in a string so that it can be included in an 3548 RCS value. */ 3549 static char * 3550 escape_keyword_value (const char *value, int *free_value) 3551 { 3552 char *ret, *t; 3553 const char *s; 3554 3555 for (s = value; *s != '\0'; s++) 3556 { 3557 char c; 3558 3559 c = *s; 3560 if (c == '\t' 3561 || c == '\n' 3562 || c == '\\' 3563 || c == ' ' 3564 || c == '$') 3565 { 3566 break; 3567 } 3568 } 3569 3570 if (*s == '\0') 3571 { 3572 *free_value = 0; 3573 return (char *) value; 3574 } 3575 3576 ret = xmalloc (strlen (value) * 4 + 1); 3577 *free_value = 1; 3578 3579 for (s = value, t = ret; *s != '\0'; s++, t++) 3580 { 3581 switch (*s) 3582 { 3583 default: 3584 *t = *s; 3585 break; 3586 case '\t': 3587 *t++ = '\\'; 3588 *t = 't'; 3589 break; 3590 case '\n': 3591 *t++ = '\\'; 3592 *t = 'n'; 3593 break; 3594 case '\\': 3595 *t++ = '\\'; 3596 *t = '\\'; 3597 break; 3598 case ' ': 3599 *t++ = '\\'; 3600 *t++ = '0'; 3601 *t++ = '4'; 3602 *t = '0'; 3603 break; 3604 case '$': 3605 *t++ = '\\'; 3606 *t++ = '0'; 3607 *t++ = '4'; 3608 *t = '4'; 3609 break; 3610 } 3611 } 3612 3613 *t = '\0'; 3614 3615 return ret; 3616 } 3617 3618 3619 3620 /* Expand RCS keywords in the memory buffer BUF of length LEN. This 3621 applies to file RCS and version VERS. If NAME is not NULL, and is 3622 not a numeric revision, then it is the symbolic tag used for the 3623 checkout. EXPAND indicates how to expand the keywords. This 3624 function sets *RETBUF and *RETLEN to the new buffer and length. 3625 This function may modify the buffer BUF. If BUF != *RETBUF, then 3626 RETBUF is a newly allocated buffer. */ 3627 static void 3628 expand_keywords (RCSNode *rcs, RCSVers *ver, const char *name, const char *log, 3629 size_t loglen, enum kflag expand, char *buf, size_t len, 3630 char **retbuf, size_t *retlen) 3631 { 3632 struct expand_buffer 3633 { 3634 struct expand_buffer *next; 3635 char *data; 3636 size_t len; 3637 int free_data; 3638 } *ebufs = NULL; 3639 struct expand_buffer *ebuf_last = NULL; 3640 size_t ebuf_len = 0; 3641 char *locker; 3642 char *srch, *srch_next; 3643 size_t srch_len; 3644 const struct rcs_keyword *keywords; 3645 3646 if (!config /* For `cvs init', config may not be set. */ 3647 ||expand == KFLAG_O || expand == KFLAG_B) 3648 { 3649 *retbuf = buf; 3650 *retlen = len; 3651 return; 3652 } 3653 3654 if (!config->keywords) config->keywords = new_keywords (); 3655 keywords = config->keywords; 3656 3657 /* If we are using -kkvl, dig out the locker information if any. */ 3658 locker = NULL; 3659 if (expand == KFLAG_KVL) 3660 { 3661 Node *lock; 3662 lock = findnode (RCS_getlocks(rcs), ver->version); 3663 if (lock != NULL) 3664 locker = xstrdup (lock->data); 3665 } 3666 3667 /* RCS keywords look like $STRING$ or $STRING: VALUE$. */ 3668 srch = buf; 3669 srch_len = len; 3670 while ((srch_next = memchr (srch, '$', srch_len)) != NULL) 3671 { 3672 char *s, *send; 3673 size_t slen; 3674 const struct rcs_keyword *keyword; 3675 char *value; 3676 int free_value; 3677 char *sub; 3678 size_t sublen; 3679 3680 srch_len -= (srch_next + 1) - srch; 3681 srch = srch_next + 1; 3682 3683 /* Look for the first non alphabetic character after the '$'. */ 3684 send = srch + srch_len; 3685 for (s = srch; s < send; s++) 3686 if (! isalpha ((unsigned char) *s)) 3687 break; 3688 3689 /* If the first non alphabetic character is not '$' or ':', 3690 then this is not an RCS keyword. */ 3691 if (s == send || (*s != '$' && *s != ':')) 3692 continue; 3693 3694 /* See if this is one of the keywords. */ 3695 slen = s - srch; 3696 for (keyword = keywords; keyword->string != NULL; keyword++) 3697 { 3698 if (keyword->expandit 3699 && keyword->len == slen 3700 && strncmp (keyword->string, srch, slen) == 0) 3701 { 3702 break; 3703 } 3704 } 3705 if (keyword->string == NULL) 3706 continue; 3707 3708 /* If the keyword ends with a ':', then the old value consists 3709 of the characters up to the next '$'. If there is no '$' 3710 before the end of the line, though, then this wasn't an RCS 3711 keyword after all. */ 3712 if (*s == ':') 3713 { 3714 for (; s < send; s++) 3715 if (*s == '$' || *s == '\n') 3716 break; 3717 if (s == send || *s != '$') 3718 continue; 3719 } 3720 3721 /* At this point we must replace the string from SRCH to S 3722 with the expansion of the keyword KW. */ 3723 3724 /* Get the value to use. */ 3725 free_value = 0; 3726 if (expand == KFLAG_K) 3727 value = NULL; 3728 else 3729 { 3730 switch (keyword->expandto) 3731 { 3732 default: 3733 assert (!"unreached"); 3734 3735 case KEYWORD_AUTHOR: 3736 value = ver->author; 3737 break; 3738 3739 case KEYWORD_DATE: 3740 value = printable_date (ver->date); 3741 free_value = 1; 3742 break; 3743 3744 case KEYWORD_CVSHEADER: 3745 case KEYWORD_HEADER: 3746 case KEYWORD_ID: 3747 case KEYWORD_LOCALID: 3748 { 3749 const char *path; 3750 int free_path; 3751 char *date; 3752 char *old_path; 3753 3754 old_path = NULL; 3755 if (keyword->expandto == KEYWORD_HEADER) 3756 path = rcs->print_path; 3757 else if (keyword->expandto == KEYWORD_CVSHEADER) 3758 path = getfullCVSname (rcs->print_path, &old_path); 3759 else 3760 path = last_component (rcs->print_path); 3761 path = escape_keyword_value (path, &free_path); 3762 date = printable_date (ver->date); 3763 value = Xasprintf ("%s %s %s %s %s%s%s", 3764 path, ver->version, date, ver->author, 3765 ver->state, 3766 locker != NULL ? " " : "", 3767 locker != NULL ? locker : ""); 3768 if (free_path) 3769 /* If free_path is set then we know we allocated path 3770 * and we can discard the const. 3771 */ 3772 free ((char *)path); 3773 if (old_path) 3774 free (old_path); 3775 free (date); 3776 free_value = 1; 3777 } 3778 break; 3779 3780 case KEYWORD_LOCKER: 3781 value = locker; 3782 break; 3783 3784 case KEYWORD_LOG: 3785 case KEYWORD_RCSFILE: 3786 value = escape_keyword_value (last_component (rcs->print_path), 3787 &free_value); 3788 break; 3789 3790 case KEYWORD_NAME: 3791 if (name != NULL && ! isdigit ((unsigned char) *name)) 3792 value = (char *) name; 3793 else 3794 value = NULL; 3795 break; 3796 3797 case KEYWORD_REVISION: 3798 value = ver->version; 3799 break; 3800 3801 case KEYWORD_SOURCE: 3802 value = escape_keyword_value (rcs->print_path, &free_value); 3803 break; 3804 3805 case KEYWORD_STATE: 3806 value = ver->state; 3807 break; 3808 } 3809 } 3810 3811 sub = xmalloc (keyword->len 3812 + (value == NULL ? 0 : strlen (value)) 3813 + 10); 3814 if (expand == KFLAG_V) 3815 { 3816 /* Decrement SRCH and increment S to remove the $ 3817 characters. */ 3818 --srch; 3819 ++srch_len; 3820 ++s; 3821 sublen = 0; 3822 } 3823 else 3824 { 3825 strcpy (sub, keyword->string); 3826 sublen = strlen (keyword->string); 3827 if (expand != KFLAG_K) 3828 { 3829 sub[sublen] = ':'; 3830 sub[sublen + 1] = ' '; 3831 sublen += 2; 3832 } 3833 } 3834 if (value != NULL) 3835 { 3836 strcpy (sub + sublen, value); 3837 sublen += strlen (value); 3838 } 3839 if (expand != KFLAG_V && expand != KFLAG_K) 3840 { 3841 sub[sublen] = ' '; 3842 ++sublen; 3843 sub[sublen] = '\0'; 3844 } 3845 3846 if (free_value) 3847 free (value); 3848 3849 /* The Log keyword requires special handling. This behaviour 3850 is taken from RCS 5.7. The special log message is what RCS 3851 uses for ci -k. */ 3852 if (keyword->expandto == KEYWORD_LOG 3853 && (sizeof "checked in with -k by " <= loglen 3854 || log == NULL 3855 || strncmp (log, "checked in with -k by ", 3856 sizeof "checked in with -k by " - 1) != 0)) 3857 { 3858 char *start; 3859 char *leader; 3860 size_t leader_len, leader_sp_len; 3861 const char *logend; 3862 const char *snl; 3863 int cnl; 3864 char *date; 3865 const char *sl; 3866 3867 /* We are going to insert the trailing $ ourselves, before 3868 the log message, so we must remove it from S, if we 3869 haven't done so already. */ 3870 if (expand != KFLAG_V) 3871 ++s; 3872 3873 /* CVS never has empty log messages, but old RCS files might. */ 3874 if (log == NULL) 3875 log = ""; 3876 3877 /* Find the start of the line. */ 3878 start = srch; 3879 leader_len = 0; 3880 while (start > buf && start[-1] != '\n' 3881 && leader_len <= xsum (config->MaxCommentLeaderLength, 3882 expand != KFLAG_V ? 1 : 0)) 3883 { 3884 --start; 3885 ++leader_len; 3886 } 3887 3888 if (expand != KFLAG_V) 3889 /* When automagically determined and !KFLAG_V, we wish to avoid 3890 * including the leading `$' of the Log keyword in our leader. 3891 */ 3892 --leader_len; 3893 3894 /* If the automagically determined leader exceeds the limit set in 3895 * CVSROOT/config, try to use a fallback. 3896 */ 3897 if (leader_len > config->MaxCommentLeaderLength) 3898 { 3899 if (config->UseArchiveCommentLeader && rcs->comment) 3900 { 3901 leader = xstrdup (rcs->comment); 3902 leader_len = strlen (rcs->comment); 3903 } 3904 else 3905 { 3906 error (0, 0, 3907 "Skipping `$" "Log$' keyword due to excessive comment leader."); 3908 continue; 3909 } 3910 } 3911 else /* leader_len <= config->MaxCommentLeaderLength */ 3912 { 3913 /* Copy the start of the line to use as a comment leader. */ 3914 leader = xmalloc (leader_len); 3915 memcpy (leader, start, leader_len); 3916 } 3917 3918 leader_sp_len = leader_len; 3919 while (leader_sp_len > 0 && isspace (leader[leader_sp_len - 1])) 3920 --leader_sp_len; 3921 3922 /* RCS does some checking for an old style of Log here, 3923 but we don't bother. RCS issues a warning if it 3924 changes anything. */ 3925 3926 /* Count the number of newlines in the log message so that 3927 we know how many copies of the leader we will need. */ 3928 cnl = 0; 3929 logend = log + loglen; 3930 for (snl = log; snl < logend; snl++) 3931 if (*snl == '\n') 3932 ++cnl; 3933 3934 /* If the log message did not end in a newline, increment 3935 * the newline count so we have space for the extra leader. 3936 * Failure to do so results in a buffer overrun. 3937 */ 3938 if (loglen && snl[-1] != '\n') 3939 ++cnl; 3940 3941 date = printable_date (ver->date); 3942 sub = xrealloc (sub, 3943 (sublen 3944 + sizeof "Revision" 3945 + strlen (ver->version) 3946 + strlen (date) 3947 + strlen (ver->author) 3948 + loglen 3949 /* Use CNL + 2 below: One leader for each log 3950 * line, plus the Revision/Author/Date line, 3951 * plus a trailing blank line. 3952 */ 3953 + (cnl + 2) * leader_len 3954 + 20)); 3955 if (expand != KFLAG_V) 3956 { 3957 sub[sublen] = '$'; 3958 ++sublen; 3959 } 3960 sub[sublen] = '\n'; 3961 ++sublen; 3962 memcpy (sub + sublen, leader, leader_len); 3963 sublen += leader_len; 3964 sprintf (sub + sublen, "Revision %s %s %s\n", 3965 ver->version, date, ver->author); 3966 sublen += strlen (sub + sublen); 3967 free (date); 3968 3969 sl = log; 3970 while (sl < logend) 3971 { 3972 if (*sl == '\n') 3973 { 3974 memcpy (sub + sublen, leader, leader_sp_len); 3975 sublen += leader_sp_len; 3976 sub[sublen] = '\n'; 3977 ++sublen; 3978 ++sl; 3979 } 3980 else 3981 { 3982 const char *slnl; 3983 3984 memcpy (sub + sublen, leader, leader_len); 3985 sublen += leader_len; 3986 for (slnl = sl; slnl < logend && *slnl != '\n'; ++slnl) 3987 ; 3988 if (slnl < logend) 3989 ++slnl; 3990 memcpy (sub + sublen, sl, slnl - sl); 3991 sublen += slnl - sl; 3992 if (slnl == logend && slnl[-1] != '\n') 3993 { 3994 /* There was no EOL at the end of the log message. Add 3995 * one. 3996 */ 3997 sub[sublen] = '\n'; 3998 ++sublen; 3999 } 4000 sl = slnl; 4001 } 4002 } 4003 4004 memcpy (sub + sublen, leader, leader_sp_len); 4005 sublen += leader_sp_len; 4006 4007 free (leader); 4008 } 4009 4010 /* Now SUB contains a string which is to replace the string 4011 from SRCH to S. SUBLEN is the length of SUB. */ 4012 4013 if (srch + sublen == s) 4014 { 4015 memcpy (srch, sub, sublen); 4016 free (sub); 4017 } 4018 else 4019 { 4020 struct expand_buffer *ebuf; 4021 4022 /* We need to change the size of the buffer. We build a 4023 list of expand_buffer structures. Each expand_buffer 4024 structure represents a portion of the final output. We 4025 concatenate them back into a single buffer when we are 4026 done. This minimizes the number of potentially large 4027 buffer copies we must do. */ 4028 4029 if (ebufs == NULL) 4030 { 4031 ebufs = xmalloc (sizeof *ebuf); 4032 ebufs->next = NULL; 4033 ebufs->data = buf; 4034 ebufs->free_data = 0; 4035 ebuf_len = srch - buf; 4036 ebufs->len = ebuf_len; 4037 ebuf_last = ebufs; 4038 } 4039 else 4040 { 4041 assert (srch >= ebuf_last->data); 4042 assert (srch <= ebuf_last->data + ebuf_last->len); 4043 ebuf_len -= ebuf_last->len - (srch - ebuf_last->data); 4044 ebuf_last->len = srch - ebuf_last->data; 4045 } 4046 4047 ebuf = xmalloc (sizeof *ebuf); 4048 ebuf->data = sub; 4049 ebuf->len = sublen; 4050 ebuf->free_data = 1; 4051 ebuf->next = NULL; 4052 ebuf_last->next = ebuf; 4053 ebuf_last = ebuf; 4054 ebuf_len += sublen; 4055 4056 ebuf = xmalloc (sizeof *ebuf); 4057 ebuf->data = s; 4058 ebuf->len = srch_len - (s - srch); 4059 ebuf->free_data = 0; 4060 ebuf->next = NULL; 4061 ebuf_last->next = ebuf; 4062 ebuf_last = ebuf; 4063 ebuf_len += srch_len - (s - srch); 4064 } 4065 4066 srch_len -= (s - srch); 4067 srch = s; 4068 } 4069 4070 if (locker != NULL) 4071 free (locker); 4072 4073 if (ebufs == NULL) 4074 { 4075 *retbuf = buf; 4076 *retlen = len; 4077 } 4078 else 4079 { 4080 char *ret; 4081 4082 ret = xmalloc (ebuf_len); 4083 *retbuf = ret; 4084 *retlen = ebuf_len; 4085 while (ebufs != NULL) 4086 { 4087 struct expand_buffer *next; 4088 4089 memcpy (ret, ebufs->data, ebufs->len); 4090 ret += ebufs->len; 4091 if (ebufs->free_data) 4092 free (ebufs->data); 4093 next = ebufs->next; 4094 free (ebufs); 4095 ebufs = next; 4096 } 4097 } 4098 } 4099 4100 4101 4102 /* Check out a revision from an RCS file. 4103 4104 If PFN is not NULL, then ignore WORKFILE and SOUT. Call PFN zero 4105 or more times with the contents of the file. CALLERDAT is passed, 4106 uninterpreted, to PFN. (The current code will always call PFN 4107 exactly once for a non empty file; however, the current code 4108 assumes that it can hold the entire file contents in memory, which 4109 is not a good assumption, and might change in the future). 4110 4111 Otherwise, if WORKFILE is not NULL, check out the revision to 4112 WORKFILE. However, if WORKFILE is not NULL, and noexec is set, 4113 then don't do anything. 4114 4115 Otherwise, if WORKFILE is NULL, check out the revision to SOUT. If 4116 SOUT is RUN_TTY, then write the contents of the revision to 4117 standard output. When using SOUT, the output is generally a 4118 temporary file; don't bother to get the file modes correct. When 4119 NOEXEC is set, WORKFILEs are not written but SOUTs are. 4120 4121 REV is the numeric revision to check out. It may be NULL, which 4122 means to check out the head of the default branch. 4123 4124 If NAMETAG is not NULL, and is not a numeric revision, then it is 4125 the tag that should be used when expanding the RCS Name keyword. 4126 4127 OPTIONS is a string such as "-kb" or "-kv" for keyword expansion 4128 options. It may be NULL to use the default expansion mode of the 4129 file, typically "-kkv". 4130 4131 On an error which prevented checking out the file, either print a 4132 nonfatal error and return 1, or give a fatal error. On success, 4133 return 0. */ 4134 4135 /* This function mimics the behavior of `rcs co' almost exactly. The 4136 chief difference is in its support for preserving file ownership, 4137 permissions, and special files across checkin and checkout -- see 4138 comments in RCS_checkin for some issues about this. -twp */ 4139 int 4140 RCS_checkout (RCSNode *rcs, const char *workfile, const char *rev, 4141 const char *nametag, const char *options, const char *sout, 4142 RCSCHECKOUTPROC pfn, void *callerdat) 4143 { 4144 int free_rev = 0; 4145 enum kflag expand; 4146 FILE *fp, 4147 *ofp = NULL; /* Initialize since -Wall doesn't understand that 4148 * error (1, ...) does not return. 4149 */ 4150 struct stat sb; 4151 struct rcsbuffer rcsbuf; 4152 char *key; 4153 char *value; 4154 size_t len; 4155 int free_value = 0; 4156 char *log = NULL; 4157 size_t loglen = 0; 4158 Node *vp = NULL; 4159 #ifdef PRESERVE_PERMISSIONS_SUPPORT 4160 uid_t rcs_owner = (uid_t) -1; 4161 gid_t rcs_group = (gid_t) -1; 4162 mode_t rcs_mode; 4163 int change_rcs_owner_or_group = 0; 4164 int change_rcs_mode = 0; 4165 int special_file = 0; 4166 unsigned long devnum_long; 4167 dev_t devnum = 0; 4168 #endif 4169 4170 TRACE (TRACE_FUNCTION, "RCS_checkout (%s, %s, %s, %s, %s)", 4171 rcs->path, 4172 rev != NULL ? rev : "", 4173 nametag != NULL ? nametag : "", 4174 options != NULL ? options : "", 4175 (pfn != NULL ? "(function)" 4176 : (workfile != NULL ? workfile 4177 : (sout != RUN_TTY ? sout 4178 : "(stdout)")))); 4179 4180 assert (rev == NULL || isdigit ((unsigned char) *rev)); 4181 4182 if (noexec && !server_active && workfile != NULL) 4183 return 0; 4184 4185 assert (sout == RUN_TTY || workfile == NULL); 4186 assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL)); 4187 4188 /* Some callers, such as Checkin or remove_file, will pass us a 4189 branch. */ 4190 if (rev != NULL && (numdots (rev) & 1) == 0) 4191 { 4192 rev = RCS_getbranch (rcs, rev, 1); 4193 if (rev == NULL) 4194 error (1, 0, "internal error: bad branch tag in checkout"); 4195 free_rev = 1; 4196 } 4197 4198 if (rev == NULL || STREQ (rev, rcs->head)) 4199 { 4200 int gothead; 4201 4202 /* We want the head revision. Try to read it directly. */ 4203 4204 if (rcs->flags & PARTIAL) 4205 RCS_reparsercsfile (rcs, &fp, &rcsbuf); 4206 else 4207 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf); 4208 4209 gothead = 0; 4210 if (! rcsbuf_getrevnum (&rcsbuf, &key)) 4211 error (1, 0, "unexpected EOF reading %s", rcs->print_path); 4212 while (rcsbuf_getkey (&rcsbuf, &key, &value)) 4213 { 4214 if (STREQ (key, "log")) 4215 { 4216 if (log) 4217 { 4218 error (0, 0, 4219 "Duplicate log keyword found for head revision in RCS file."); 4220 free (log); 4221 } 4222 log = rcsbuf_valcopy (&rcsbuf, value, 0, &loglen); 4223 } 4224 else if (STREQ (key, "text")) 4225 { 4226 gothead = 1; 4227 break; 4228 } 4229 } 4230 4231 if (! gothead) 4232 { 4233 error (0, 0, "internal error: cannot find head text"); 4234 if (free_rev) 4235 /* It's okay to discard the const when free_rev is set, because 4236 * we know we allocated it in this function. 4237 */ 4238 free ((char *)rev); 4239 return 1; 4240 } 4241 4242 rcsbuf_valpolish (&rcsbuf, value, 0, &len); 4243 4244 if (fstat (fileno (fp), &sb) < 0) 4245 error (1, errno, "cannot fstat %s", rcs->path); 4246 4247 rcsbuf_cache (rcs, &rcsbuf); 4248 } 4249 else 4250 { 4251 struct rcsbuffer *rcsbufp; 4252 4253 /* It isn't the head revision of the trunk. We'll need to 4254 walk through the deltas. */ 4255 4256 fp = NULL; 4257 if (rcs->flags & PARTIAL) 4258 RCS_reparsercsfile (rcs, &fp, &rcsbuf); 4259 4260 if (fp == NULL) 4261 { 4262 /* If RCS_deltas didn't close the file, we could use fstat 4263 here too. Probably should change it thusly.... */ 4264 if (stat (rcs->path, &sb) < 0) 4265 error (1, errno, "cannot stat %s", rcs->path); 4266 rcsbufp = NULL; 4267 } 4268 else 4269 { 4270 if (fstat (fileno (fp), &sb) < 0) 4271 error (1, errno, "cannot fstat %s", rcs->path); 4272 rcsbufp = &rcsbuf; 4273 } 4274 4275 RCS_deltas (rcs, fp, rcsbufp, rev, RCS_FETCH, &value, &len, 4276 &log, &loglen); 4277 free_value = 1; 4278 } 4279 4280 /* If OPTIONS is NULL or the empty string, then the old code would 4281 invoke the RCS co program with no -k option, which means that 4282 co would use the string we have stored in rcs->expand. */ 4283 if ((options == NULL || options[0] == '\0') && rcs->expand == NULL) 4284 expand = KFLAG_KV; 4285 else 4286 { 4287 const char *ouroptions; 4288 const char * const *cpp; 4289 4290 if (options != NULL && options[0] != '\0') 4291 { 4292 assert (options[0] == '-' && options[1] == 'k'); 4293 ouroptions = options + 2; 4294 } 4295 else 4296 ouroptions = rcs->expand; 4297 4298 for (cpp = kflags; *cpp != NULL; cpp++) 4299 if (STREQ (*cpp, ouroptions)) 4300 break; 4301 4302 if (*cpp != NULL) 4303 expand = (enum kflag) (cpp - kflags); 4304 else 4305 { 4306 error (0, 0, 4307 "internal error: unsupported substitution string -k%s", 4308 ouroptions); 4309 expand = KFLAG_KV; 4310 } 4311 } 4312 4313 #ifdef PRESERVE_PERMISSIONS_SUPPORT 4314 /* Handle special files and permissions, if that is desired. */ 4315 if (preserve_perms) 4316 { 4317 RCSVers *vers; 4318 Node *info; 4319 4320 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev); 4321 if (vp == NULL) 4322 error (1, 0, "internal error: no revision information for %s", 4323 rev == NULL ? rcs->head : rev); 4324 vers = vp->data; 4325 4326 /* First we look for symlinks, which are simplest to handle. */ 4327 info = findnode (vers->other_delta, "symlink"); 4328 if (info != NULL) 4329 { 4330 char *dest; 4331 4332 if (pfn != NULL || (workfile == NULL && sout == RUN_TTY)) 4333 error (1, 0, "symbolic link %s:%s cannot be piped", 4334 rcs->path, vers->version); 4335 if (workfile == NULL) 4336 dest = sout; 4337 else 4338 dest = workfile; 4339 4340 /* Remove `dest', just in case. It's okay to get ENOENT here, 4341 since we just want the file not to be there. (TODO: decide 4342 whether it should be considered an error for `dest' to exist 4343 at this point. If so, the unlink call should be removed and 4344 `symlink' should signal the error. -twp) */ 4345 if (CVS_UNLINK (dest) < 0 && !existence_error (errno)) 4346 error (1, errno, "cannot remove %s", dest); 4347 if (symlink (info->data, dest) < 0) 4348 error (1, errno, "cannot create symbolic link from %s to %s", 4349 dest, (char *)info->data); 4350 if (free_value) 4351 free (value); 4352 if (free_rev) 4353 /* It's okay to discard the const when free_rev is set, because 4354 * we know we allocated it in this function. 4355 */ 4356 free ((char *)rev); 4357 return 0; 4358 } 4359 4360 /* Next, we look at this file's hardlinks field, and see whether 4361 it is linked to any other file that has been checked out. 4362 If so, we don't do anything else -- just link it to that file. 4363 4364 If we are checking out a file to a pipe or temporary storage, 4365 none of this should matter. Hence the `workfile != NULL' 4366 wrapper around the whole thing. -twp */ 4367 4368 if (workfile != NULL) 4369 { 4370 List *links = vers->hardlinks; 4371 if (links != NULL) 4372 { 4373 Node *uptodate_link; 4374 4375 /* For each file in the hardlinks field, check to see 4376 if it exists, and if so, if it has been checked out 4377 this iteration. When walklist returns, uptodate_link 4378 should point to a hardlist node representing a file 4379 in `links' which has recently been checked out, or 4380 NULL if no file in `links' has yet been checked out. */ 4381 4382 uptodate_link = NULL; 4383 (void) walklist (links, find_checkedout_proc, &uptodate_link); 4384 dellist (&links); 4385 4386 /* If we've found a file that `workfile' is supposed to be 4387 linked to, and it has been checked out since CVS was 4388 invoked, then simply link workfile to that file and return. 4389 4390 If one of these conditions is not met, then 4391 workfile is the first one in its hardlink group to 4392 be checked out, and we must continue with a full 4393 checkout. */ 4394 4395 if (uptodate_link != NULL) 4396 { 4397 struct hardlink_info *hlinfo = uptodate_link->data; 4398 4399 if (link (uptodate_link->key, workfile) < 0) 4400 error (1, errno, "cannot link %s to %s", 4401 workfile, uptodate_link->key); 4402 hlinfo->checked_out = 1; /* probably unnecessary */ 4403 if (free_value) 4404 free (value); 4405 if (free_rev) 4406 /* It's okay to discard the const when free_rev is set, 4407 * because we know we allocated it in this function. 4408 */ 4409 free ((char *)rev); 4410 return 0; 4411 } 4412 } 4413 } 4414 4415 info = findnode (vers->other_delta, "owner"); 4416 if (info != NULL) 4417 { 4418 change_rcs_owner_or_group = 1; 4419 rcs_owner = (uid_t) strtoul (info->data, NULL, 10); 4420 } 4421 info = findnode (vers->other_delta, "group"); 4422 if (info != NULL) 4423 { 4424 change_rcs_owner_or_group = 1; 4425 rcs_group = (gid_t) strtoul (info->data, NULL, 10); 4426 } 4427 info = findnode (vers->other_delta, "permissions"); 4428 if (info != NULL) 4429 { 4430 change_rcs_mode = 1; 4431 rcs_mode = (mode_t) strtoul (info->data, NULL, 8); 4432 } 4433 info = findnode (vers->other_delta, "special"); 4434 if (info != NULL) 4435 { 4436 /* If the size of `devtype' changes, fix the sscanf call also */ 4437 char devtype[16]; 4438 4439 if (sscanf (info->data, "%15s %lu", 4440 devtype, &devnum_long) < 2) 4441 error (1, 0, "%s:%s has bad `special' newphrase %s", 4442 workfile, vers->version, (char *)info->data); 4443 devnum = devnum_long; 4444 if (STREQ (devtype, "character")) 4445 special_file = S_IFCHR; 4446 else if (STREQ (devtype, "block")) 4447 special_file = S_IFBLK; 4448 else 4449 error (0, 0, "%s is a special file of unsupported type `%s'", 4450 workfile, (char *)info->data); 4451 } 4452 } 4453 #endif /* PRESERVE_PERMISSIONS_SUPPORT */ 4454 4455 if (expand != KFLAG_O && expand != KFLAG_B) 4456 { 4457 char *newvalue; 4458 4459 /* Don't fetch the delta node again if we already have it. */ 4460 if (vp == NULL) 4461 { 4462 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev); 4463 if (vp == NULL) 4464 error (1, 0, "internal error: no revision information for %s", 4465 rev == NULL ? rcs->head : rev); 4466 } 4467 4468 expand_keywords (rcs, vp->data, nametag, log, loglen, 4469 expand, value, len, &newvalue, &len); 4470 4471 if (newvalue != value) 4472 { 4473 if (free_value) 4474 free (value); 4475 value = newvalue; 4476 free_value = 1; 4477 } 4478 } 4479 4480 if (free_rev) 4481 /* It's okay to discard the const when free_rev is set, because 4482 * we know we allocated it in this function. 4483 */ 4484 free ((char *)rev); 4485 4486 if (log != NULL) 4487 { 4488 free (log); 4489 log = NULL; 4490 } 4491 4492 if (pfn != NULL) 4493 { 4494 #ifdef PRESERVE_PERMISSIONS_SUPPORT 4495 if (special_file) 4496 error (1, 0, "special file %s cannot be piped to anything", 4497 rcs->path); 4498 #endif 4499 /* The PFN interface is very simple to implement right now, as 4500 we always have the entire file in memory. */ 4501 if (len != 0) 4502 pfn (callerdat, value, len); 4503 } 4504 #ifdef PRESERVE_PERMISSIONS_SUPPORT 4505 else if (special_file) 4506 { 4507 # ifdef HAVE_MKNOD 4508 char *dest; 4509 4510 /* Can send either to WORKFILE or to SOUT, as long as SOUT is 4511 not RUN_TTY. */ 4512 dest = workfile; 4513 if (dest == NULL) 4514 { 4515 if (sout == RUN_TTY) 4516 error (1, 0, "special file %s cannot be written to stdout", 4517 rcs->path); 4518 dest = sout; 4519 } 4520 4521 /* Unlink `dest', just in case. It's okay if this provokes a 4522 ENOENT error. */ 4523 if (CVS_UNLINK (dest) < 0 && existence_error (errno)) 4524 error (1, errno, "cannot remove %s", dest); 4525 if (mknod (dest, special_file, devnum) < 0) 4526 error (1, errno, "could not create special file %s", 4527 dest); 4528 # else 4529 error (1, 0, 4530 "cannot create %s: unable to create special files on this system", 4531 workfile); 4532 # endif 4533 } 4534 #endif 4535 else 4536 { 4537 /* Not a special file: write to WORKFILE or SOUT. */ 4538 if (workfile == NULL) 4539 { 4540 if (sout == RUN_TTY) 4541 ofp = stdout; 4542 else 4543 { 4544 /* Symbolic links should be removed before replacement, so that 4545 `fopen' doesn't follow the link and open the wrong file. */ 4546 if (islink (sout)) 4547 if (unlink_file (sout) < 0) 4548 error (1, errno, "cannot remove %s", sout); 4549 ofp = CVS_FOPEN (sout, expand == KFLAG_B ? "wb" : "w"); 4550 if (ofp == NULL) 4551 error (1, errno, "cannot open %s", sout); 4552 } 4553 } 4554 else 4555 { 4556 /* Output is supposed to go to WORKFILE, so we should open that 4557 file. Symbolic links should be removed first (see above). */ 4558 if (islink (workfile)) 4559 if (unlink_file (workfile) < 0) 4560 error (1, errno, "cannot remove %s", workfile); 4561 4562 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w"); 4563 4564 /* If the open failed because the existing workfile was not 4565 writable, try to chmod the file and retry the open. */ 4566 if (ofp == NULL && errno == EACCES 4567 && isfile (workfile) && !iswritable (workfile)) 4568 { 4569 xchmod (workfile, 1); 4570 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w"); 4571 } 4572 4573 if (ofp == NULL) 4574 { 4575 error (0, errno, "cannot open %s", workfile); 4576 if (free_value) 4577 free (value); 4578 return 1; 4579 } 4580 } 4581 4582 if (workfile == NULL && sout == RUN_TTY) 4583 { 4584 if (expand == KFLAG_B) 4585 cvs_output_binary (value, len); 4586 else 4587 { 4588 /* cvs_output requires the caller to check for zero 4589 length. */ 4590 if (len > 0) 4591 cvs_output (value, len); 4592 } 4593 } 4594 else 4595 { 4596 /* NT 4.0 is said to have trouble writing 2099999 bytes 4597 (for example) in a single fwrite. So break it down 4598 (there is no need to be writing that much at once 4599 anyway; it is possible that LARGEST_FWRITE should be 4600 somewhat larger for good performance, but for testing I 4601 want to start with a small value until/unless a bigger 4602 one proves useful). */ 4603 #define LARGEST_FWRITE 8192 4604 size_t nleft = len; 4605 size_t nstep = (len < LARGEST_FWRITE ? len : LARGEST_FWRITE); 4606 char *p = value; 4607 4608 while (nleft > 0) 4609 { 4610 if (fwrite (p, 1, nstep, ofp) != nstep) 4611 { 4612 error (0, errno, "cannot write %s", 4613 (workfile != NULL 4614 ? workfile 4615 : (sout != RUN_TTY ? sout : "stdout"))); 4616 if (free_value) 4617 free (value); 4618 return 1; 4619 } 4620 p += nstep; 4621 nleft -= nstep; 4622 if (nleft < nstep) 4623 nstep = nleft; 4624 } 4625 } 4626 } 4627 4628 if (free_value) 4629 free (value); 4630 4631 if (workfile != NULL) 4632 { 4633 int ret; 4634 4635 #ifdef PRESERVE_PERMISSIONS_SUPPORT 4636 if (!special_file && fclose (ofp) < 0) 4637 { 4638 error (0, errno, "cannot close %s", workfile); 4639 return 1; 4640 } 4641 4642 if (change_rcs_owner_or_group) 4643 { 4644 if (chown (workfile, rcs_owner, rcs_group) < 0) 4645 error (0, errno, "could not change owner or group of %s", 4646 workfile); 4647 } 4648 4649 ret = chmod (workfile, 4650 change_rcs_mode 4651 ? rcs_mode 4652 : sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH)); 4653 #else 4654 if (fclose (ofp) < 0) 4655 { 4656 error (0, errno, "cannot close %s", workfile); 4657 return 1; 4658 } 4659 4660 ret = chmod (workfile, 4661 sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH)); 4662 #endif 4663 if (ret < 0) 4664 { 4665 error (0, errno, "cannot change mode of file %s", 4666 workfile); 4667 } 4668 } 4669 else if (sout != RUN_TTY) 4670 { 4671 if ( 4672 #ifdef PRESERVE_PERMISSIONS_SUPPORT 4673 !special_file && 4674 #endif 4675 fclose (ofp) < 0) 4676 { 4677 error (0, errno, "cannot close %s", sout); 4678 return 1; 4679 } 4680 } 4681 4682 #ifdef PRESERVE_PERMISSIONS_SUPPORT 4683 /* If we are in the business of preserving hardlinks, then 4684 mark this file as having been checked out. */ 4685 if (preserve_perms && workfile != NULL) 4686 update_hardlink_info (workfile); 4687 #endif 4688 4689 return 0; 4690 } 4691 4692 4693 4694 /* Find the delta currently locked by the user. From the `ci' man page: 4695 4696 "If rev is omitted, ci tries to derive the new revision 4697 number from the caller's last lock. If the caller has 4698 locked the tip revision of a branch, the new revision is 4699 appended to that branch. The new revision number is 4700 obtained by incrementing the tip revision number. If the 4701 caller locked a non-tip revision, a new branch is started 4702 at that revision by incrementing the highest branch number 4703 at that revision. The default initial branch and level 4704 numbers are 1. 4705 4706 If rev is omitted and the caller has no lock, but owns the 4707 file and locking is not set to strict, then the revision 4708 is appended to the default branch (normally the trunk; see 4709 the -b option of rcs(1))." 4710 4711 RCS_findlock_or_tip finds the unique revision locked by the caller 4712 and returns its delta node. If the caller has not locked any 4713 revisions (and is permitted to commit to an unlocked delta, as 4714 described above), return the tip of the default branch. */ 4715 static RCSVers * 4716 RCS_findlock_or_tip (RCSNode *rcs) 4717 { 4718 char *user = getcaller(); 4719 Node *lock, *p; 4720 List *locklist; 4721 4722 /* Find unique delta locked by caller. This code is very similar 4723 to the code in RCS_unlock -- perhaps it could be abstracted 4724 into a RCS_findlock function. */ 4725 locklist = RCS_getlocks (rcs); 4726 lock = NULL; 4727 for (p = locklist->list->next; p != locklist->list; p = p->next) 4728 { 4729 if (STREQ (p->data, user)) 4730 { 4731 if (lock != NULL) 4732 { 4733 error (0, 0, "\ 4734 %s: multiple revisions locked by %s; please specify one", rcs->print_path, user); 4735 return NULL; 4736 } 4737 lock = p; 4738 } 4739 } 4740 4741 if (lock != NULL) 4742 { 4743 /* Found an old lock, but check that the revision still exists. */ 4744 p = findnode (rcs->versions, lock->key); 4745 if (p == NULL) 4746 { 4747 error (0, 0, "%s: can't unlock nonexistent revision %s", 4748 rcs->print_path, 4749 lock->key); 4750 return NULL; 4751 } 4752 return p->data; 4753 } 4754 4755 /* No existing lock. The RCS rule is that this is an error unless 4756 locking is nonstrict AND the file is owned by the current 4757 user. Trying to determine the latter is a portability nightmare 4758 in the face of NT, VMS, AFS, and other systems with non-unix-like 4759 ideas of users and owners. In the case of CVS, we should never get 4760 here (as long as the traditional behavior of making sure to call 4761 RCS_lock persists). Anyway, we skip the RCS error checks 4762 and just return the default branch or head. The reasoning is that 4763 those error checks are to make users lock before a checkin, and we do 4764 that in other ways if at all anyway (e.g. rcslock.pl). */ 4765 4766 p = findnode (rcs->versions, RCS_getbranch (rcs, rcs->branch, 0)); 4767 if (!p) 4768 { 4769 error (0, 0, "RCS file `%s' does not contain its default revision.", 4770 rcs->path); 4771 return NULL; 4772 } 4773 4774 return p->data; 4775 } 4776 4777 4778 4779 /* Revision number string, R, must contain a `.'. 4780 Return a newly-malloc'd copy of the prefix of R up 4781 to but not including the final `.'. */ 4782 static char * 4783 truncate_revnum (const char *r) 4784 { 4785 size_t len; 4786 char *new_r; 4787 char *dot = strrchr (r, '.'); 4788 4789 assert (dot); 4790 len = dot - r; 4791 new_r = xmalloc (len + 1); 4792 memcpy (new_r, r, len); 4793 *(new_r + len) = '\0'; 4794 return new_r; 4795 } 4796 4797 4798 4799 /* Revision number string, R, must contain a `.'. 4800 R must be writable. Replace the rightmost `.' in R with 4801 the NUL byte and return a pointer to that NUL byte. */ 4802 static char * 4803 truncate_revnum_in_place (char *r) 4804 { 4805 char *dot = strrchr (r, '.'); 4806 assert (dot); 4807 *dot = '\0'; 4808 return dot; 4809 } 4810 4811 4812 4813 /* Revision number strings, R and S, must each contain a `.'. 4814 R and S must be writable and must have the same number of dots. 4815 Truncate R and S for the comparison, then restored them to their 4816 original state. 4817 Return the result (see compare_revnums) of comparing R and S 4818 ignoring differences in any component after the rightmost `.'. */ 4819 static int 4820 compare_truncated_revnums (char *r, char *s) 4821 { 4822 char *r_dot = truncate_revnum_in_place (r); 4823 char *s_dot = truncate_revnum_in_place (s); 4824 int cmp; 4825 4826 assert (numdots (r) == numdots (s)); 4827 4828 cmp = compare_revnums (r, s); 4829 4830 *r_dot = '.'; 4831 *s_dot = '.'; 4832 4833 return cmp; 4834 } 4835 4836 4837 4838 /* Return a malloc'd copy of the string representing the highest branch 4839 number on BRANCHNODE. If there are no branches on BRANCHNODE, return NULL. 4840 FIXME: isn't the max rev always the last one? 4841 If so, we don't even need a loop. */ 4842 static char * 4843 max_rev (const RCSVers *branchnode) 4844 { 4845 Node *head; 4846 Node *bp; 4847 char *max; 4848 4849 if (branchnode->branches == NULL) 4850 { 4851 return NULL; 4852 } 4853 4854 max = NULL; 4855 head = branchnode->branches->list; 4856 for (bp = head->next; bp != head; bp = bp->next) 4857 { 4858 if (max == NULL || compare_truncated_revnums (max, bp->key) < 0) 4859 { 4860 max = bp->key; 4861 } 4862 } 4863 assert (max); 4864 4865 return truncate_revnum (max); 4866 } 4867 4868 4869 4870 /* Create BRANCH in RCS's delta tree. BRANCH may be either a branch 4871 number or a revision number. In the former case, create the branch 4872 with the specified number; in the latter case, create a new branch 4873 rooted at node BRANCH with a higher branch number than any others. 4874 Return the number of the tip node on the new branch. */ 4875 static char * 4876 RCS_addbranch (RCSNode *rcs, const char *branch) 4877 { 4878 char *branchpoint, *newrevnum; 4879 Node *nodep, *bp; 4880 Node *marker; 4881 RCSVers *branchnode; 4882 4883 assert (branch); 4884 4885 /* Append to end by default. */ 4886 marker = NULL; 4887 4888 branchpoint = xstrdup (branch); 4889 if ((numdots (branchpoint) & 1) == 0) 4890 { 4891 truncate_revnum_in_place (branchpoint); 4892 } 4893 4894 /* Find the branch rooted at BRANCHPOINT. */ 4895 nodep = findnode (rcs->versions, branchpoint); 4896 if (nodep == NULL) 4897 { 4898 error (0, 0, "%s: can't find branch point %s", rcs->print_path, branchpoint); 4899 free (branchpoint); 4900 return NULL; 4901 } 4902 free (branchpoint); 4903 branchnode = nodep->data; 4904 4905 /* If BRANCH was a full branch number, make sure it is higher than MAX. */ 4906 if ((numdots (branch) & 1) == 1) 4907 { 4908 if (branchnode->branches == NULL) 4909 { 4910 /* We have to create the first branch on this node, which means 4911 appending ".2" to the revision number. */ 4912 newrevnum = Xasprintf ("%s.2", branch); 4913 } 4914 else 4915 { 4916 char *max = max_rev (branchnode); 4917 assert (max); 4918 newrevnum = increment_revnum (max); 4919 free (max); 4920 } 4921 } 4922 else 4923 { 4924 newrevnum = xstrdup (branch); 4925 4926 if (branchnode->branches != NULL) 4927 { 4928 Node *head; 4929 Node *bp; 4930 4931 /* Find the position of this new branch in the sorted list 4932 of branches. */ 4933 head = branchnode->branches->list; 4934 for (bp = head->next; bp != head; bp = bp->next) 4935 { 4936 char *dot; 4937 int found_pos; 4938 4939 /* The existing list must be sorted on increasing revnum. */ 4940 assert (bp->next == head 4941 || compare_truncated_revnums (bp->key, 4942 bp->next->key) < 0); 4943 dot = truncate_revnum_in_place (bp->key); 4944 found_pos = (compare_revnums (branch, bp->key) < 0); 4945 *dot = '.'; 4946 4947 if (found_pos) 4948 { 4949 break; 4950 } 4951 } 4952 marker = bp; 4953 } 4954 } 4955 4956 newrevnum = xrealloc (newrevnum, strlen (newrevnum) + 3); 4957 strcat (newrevnum, ".1"); 4958 4959 /* Add this new revision number to BRANCHPOINT's branches list. */ 4960 if (branchnode->branches == NULL) 4961 branchnode->branches = getlist(); 4962 bp = getnode(); 4963 bp->key = xstrdup (newrevnum); 4964 4965 /* Append to the end of the list by default, that is, just before 4966 the header node, `list'. */ 4967 if (marker == NULL) 4968 marker = branchnode->branches->list; 4969 4970 { 4971 int fail; 4972 fail = insert_before (branchnode->branches, marker, bp); 4973 assert (!fail); 4974 } 4975 4976 return newrevnum; 4977 } 4978 4979 4980 4981 /* Check in to RCSFILE with revision REV (which must be greater than 4982 the largest revision) and message MESSAGE (which is checked for 4983 validity). If FLAGS & RCS_FLAGS_DEAD, check in a dead revision. 4984 If FLAGS & RCS_FLAGS_QUIET, tell ci to be quiet. If FLAGS & 4985 RCS_FLAGS_MODTIME, use the working file's modification time for the 4986 checkin time. WORKFILE is the working file to check in from, or 4987 NULL to use the usual RCS rules for deriving it from the RCSFILE. 4988 If FLAGS & RCS_FLAGS_KEEPFILE, don't unlink the working file; 4989 unlinking the working file is standard RCS behavior, but is rarely 4990 appropriate for CVS. 4991 4992 UPDATE_DIR is used to print the path for the file. This argument is 4993 unnecessary when FLAGS & RCS_FLAGS_QUIET since the path won't be printed 4994 anyhow. 4995 4996 This function should almost exactly mimic the behavior of `rcs ci'. The 4997 principal point of difference is the support here for preserving file 4998 ownership and permissions in the delta nodes. This is not a clean 4999 solution -- precisely because it diverges from RCS's behavior -- but 5000 it doesn't seem feasible to do this anywhere else in the code. [-twp] 5001 5002 Return value is -1 for error (and errno is set to indicate the 5003 error), positive for error (and an error message has been printed), 5004 or zero for success. */ 5005 int 5006 RCS_checkin (RCSNode *rcs, const char *update_dir, const char *workfile_in, 5007 const char *message, const char *rev, time_t citime, int flags) 5008 { 5009 RCSVers *delta, *commitpt; 5010 Deltatext *dtext; 5011 Node *nodep; 5012 char *tmpfile, *changefile; 5013 int dargc = 0; 5014 size_t darg_allocated = 0; 5015 char **dargv = NULL; 5016 size_t bufsize; 5017 int status, checkin_quiet; 5018 struct tm *ftm; 5019 time_t modtime; 5020 int adding_branch = 0; 5021 char *workfile = xstrdup (workfile_in); 5022 #ifdef PRESERVE_PERMISSIONS_SUPPORT 5023 struct stat sb; 5024 #endif 5025 Node *np; 5026 5027 commitpt = NULL; 5028 5029 if (rcs->flags & PARTIAL) 5030 RCS_reparsercsfile (rcs, NULL, NULL); 5031 5032 /* Get basename of working file. Is there a library function to 5033 do this? I couldn't find one. -twp */ 5034 if (workfile == NULL) 5035 { 5036 char *p; 5037 int extlen = strlen (RCSEXT); 5038 assert (rcs->path); 5039 workfile = xstrdup (last_component (rcs->path)); 5040 p = workfile + (strlen (workfile) - extlen); 5041 assert (strncmp (p, RCSEXT, extlen) == 0); 5042 *p = '\0'; 5043 } 5044 5045 /* If the filename is a symbolic link, follow it and replace it 5046 with the destination of the link. We need to do this before 5047 calling rcs_internal_lockfile, or else we won't put the lock in 5048 the right place. */ 5049 resolve_symlink (&(rcs->path)); 5050 5051 checkin_quiet = flags & RCS_FLAGS_QUIET; 5052 if (!(checkin_quiet || really_quiet)) 5053 { 5054 cvs_output (rcs->path, 0); 5055 cvs_output (" <-- ", 7); 5056 if (update_dir && strlen (update_dir)) 5057 { 5058 cvs_output (update_dir, 0); 5059 cvs_output ("/", 1); 5060 } 5061 cvs_output (workfile, 0); 5062 cvs_output ("\n", 1); 5063 } 5064 5065 /* Create new delta node. */ 5066 delta = xmalloc (sizeof (RCSVers)); 5067 memset (delta, 0, sizeof (RCSVers)); 5068 delta->author = xstrdup (getcaller ()); 5069 if (flags & RCS_FLAGS_MODTIME) 5070 { 5071 struct stat ws; 5072 if (stat (workfile, &ws) < 0) 5073 { 5074 error (1, errno, "cannot stat %s", workfile); 5075 } 5076 modtime = ws.st_mtime; 5077 } 5078 else if (flags & RCS_FLAGS_USETIME) 5079 modtime = citime; 5080 else 5081 (void) time (&modtime); 5082 ftm = gmtime (&modtime); 5083 delta->date = Xasprintf (DATEFORM, 5084 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), 5085 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, 5086 ftm->tm_min, ftm->tm_sec); 5087 if (flags & RCS_FLAGS_DEAD) 5088 { 5089 delta->state = xstrdup (RCSDEAD); 5090 delta->dead = 1; 5091 } 5092 else 5093 delta->state = xstrdup ("Exp"); 5094 5095 delta->other_delta = getlist(); 5096 5097 /* save the commit ID */ 5098 np = getnode(); 5099 np->type = RCSFIELD; 5100 np->key = xstrdup ("commitid"); 5101 np->data = xstrdup(global_session_id); 5102 addnode (delta->other_delta, np); 5103 5104 5105 #ifdef PRESERVE_PERMISSIONS_SUPPORT 5106 /* If permissions should be preserved on this project, then 5107 save the permission info. */ 5108 if (preserve_perms) 5109 { 5110 Node *np; 5111 char buf[64]; /* static buffer should be safe: see usage. -twp */ 5112 5113 delta->other_delta = getlist(); 5114 5115 if (lstat (workfile, &sb) < 0) 5116 error (1, errno, "cannot lstat %s", workfile); 5117 5118 if (S_ISLNK (sb.st_mode)) 5119 { 5120 np = getnode(); 5121 np->type = RCSFIELD; 5122 np->key = xstrdup ("symlink"); 5123 np->data = Xreadlink (workfile, sb.st_size); 5124 addnode (delta->other_delta, np); 5125 } 5126 else 5127 { 5128 (void) sprintf (buf, "%u", sb.st_uid); 5129 np = getnode(); 5130 np->type = RCSFIELD; 5131 np->key = xstrdup ("owner"); 5132 np->data = xstrdup (buf); 5133 addnode (delta->other_delta, np); 5134 5135 (void) sprintf (buf, "%u", sb.st_gid); 5136 np = getnode(); 5137 np->type = RCSFIELD; 5138 np->key = xstrdup ("group"); 5139 np->data = xstrdup (buf); 5140 addnode (delta->other_delta, np); 5141 5142 (void) sprintf (buf, "%o", sb.st_mode & 07777); 5143 np = getnode(); 5144 np->type = RCSFIELD; 5145 np->key = xstrdup ("permissions"); 5146 np->data = xstrdup (buf); 5147 addnode (delta->other_delta, np); 5148 5149 /* Save device number. */ 5150 switch (sb.st_mode & S_IFMT) 5151 { 5152 case S_IFREG: break; 5153 case S_IFCHR: 5154 case S_IFBLK: 5155 # ifdef HAVE_STRUCT_STAT_ST_RDEV 5156 np = getnode(); 5157 np->type = RCSFIELD; 5158 np->key = xstrdup ("special"); 5159 sprintf (buf, "%s %lu", 5160 ((sb.st_mode & S_IFMT) == S_IFCHR 5161 ? "character" : "block"), 5162 (unsigned long) sb.st_rdev); 5163 np->data = xstrdup (buf); 5164 addnode (delta->other_delta, np); 5165 # else 5166 error (0, 0, 5167 "can't preserve %s: unable to save device files on this system", 5168 workfile); 5169 # endif 5170 break; 5171 5172 default: 5173 error (0, 0, "special file %s has unknown type", workfile); 5174 } 5175 5176 /* Save hardlinks. */ 5177 delta->hardlinks = list_linked_files_on_disk (workfile); 5178 } 5179 } 5180 #endif 5181 5182 /* Create a new deltatext node. */ 5183 dtext = xmalloc (sizeof (Deltatext)); 5184 memset (dtext, 0, sizeof (Deltatext)); 5185 5186 dtext->log = make_message_rcsvalid (message); 5187 5188 /* If the delta tree is empty, then there's nothing to link the 5189 new delta into. So make a new delta tree, snarf the working 5190 file contents, and just write the new RCS file. */ 5191 if (rcs->head == NULL) 5192 { 5193 char *newrev; 5194 FILE *fout; 5195 5196 /* Figure out what the first revision number should be. */ 5197 if (rev == NULL || *rev == '\0') 5198 newrev = xstrdup ("1.1"); 5199 else if (numdots (rev) == 0) 5200 { 5201 newrev = Xasprintf ("%s.1", rev); 5202 } 5203 else 5204 newrev = xstrdup (rev); 5205 5206 /* Don't need to xstrdup NEWREV because it's already dynamic, and 5207 not used for anything else. (Don't need to free it, either.) */ 5208 rcs->head = newrev; 5209 delta->version = xstrdup (newrev); 5210 nodep = getnode(); 5211 nodep->type = RCSVERS; 5212 nodep->delproc = rcsvers_delproc; 5213 nodep->data = delta; 5214 nodep->key = delta->version; 5215 (void) addnode (rcs->versions, nodep); 5216 5217 dtext->version = xstrdup (newrev); 5218 bufsize = 0; 5219 #ifdef PRESERVE_PERMISSIONS_SUPPORT 5220 if (preserve_perms && !S_ISREG (sb.st_mode)) 5221 /* Pretend file is empty. */ 5222 bufsize = 0; 5223 else 5224 #endif 5225 get_file (workfile, workfile, 5226 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r", 5227 &dtext->text, &bufsize, &dtext->len); 5228 5229 if (!(checkin_quiet || really_quiet)) 5230 { 5231 cvs_output ("initial revision: ", 0); 5232 cvs_output (rcs->head, 0); 5233 cvs_output ("\n", 1); 5234 } 5235 5236 /* We are probably about to invalidate any cached file. */ 5237 rcsbuf_cache_close (); 5238 5239 fout = rcs_internal_lockfile (rcs->path); 5240 RCS_putadmin (rcs, fout); 5241 RCS_putdtree (rcs, rcs->head, fout); 5242 RCS_putdesc (rcs, fout); 5243 rcs->delta_pos = ftello (fout); 5244 if (rcs->delta_pos == -1) 5245 error (1, errno, "cannot ftello for %s", rcs->path); 5246 putdeltatext (fout, dtext); 5247 rcs_internal_unlockfile (fout, rcs->path); 5248 5249 if ((flags & RCS_FLAGS_KEEPFILE) == 0) 5250 { 5251 if (unlink_file (workfile) < 0) 5252 /* FIXME-update-dir: message does not include update_dir. */ 5253 error (0, errno, "cannot remove %s", workfile); 5254 } 5255 5256 status = 0; 5257 goto checkin_done; 5258 } 5259 5260 /* Derive a new revision number. From the `ci' man page: 5261 5262 "If rev is a revision number, it must be higher than the 5263 latest one on the branch to which rev belongs, or must 5264 start a new branch. 5265 5266 If rev is a branch rather than a revision number, the new 5267 revision is appended to that branch. The level number is 5268 obtained by incrementing the tip revision number of that 5269 branch. If rev indicates a non-existing branch, that 5270 branch is created with the initial revision numbered 5271 rev.1." 5272 5273 RCS_findlock_or_tip handles the case where REV is omitted. 5274 RCS 5.7 also permits REV to be "$" or to begin with a dot, but 5275 we do not address those cases -- every routine that calls 5276 RCS_checkin passes it a numeric revision. */ 5277 5278 if (rev == NULL || *rev == '\0') 5279 { 5280 /* Figure out where the commit point is by looking for locks. 5281 If the commit point is at the tip of a branch (or is the 5282 head of the delta tree), then increment its revision number 5283 to obtain the new revnum. Otherwise, start a new 5284 branch. */ 5285 commitpt = RCS_findlock_or_tip (rcs); 5286 if (commitpt == NULL) 5287 { 5288 status = 1; 5289 goto checkin_done; 5290 } 5291 else if (commitpt->next == NULL 5292 || STREQ (commitpt->version, rcs->head)) 5293 delta->version = increment_revnum (commitpt->version); 5294 else 5295 delta->version = RCS_addbranch (rcs, commitpt->version); 5296 } 5297 else 5298 { 5299 /* REV is either a revision number or a branch number. Find the 5300 tip of the target branch. */ 5301 char *branch, *tip, *newrev, *p; 5302 int dots, isrevnum; 5303 5304 assert (isdigit ((unsigned char) *rev)); 5305 5306 newrev = xstrdup (rev); 5307 dots = numdots (newrev); 5308 isrevnum = dots & 1; 5309 5310 branch = xstrdup (rev); 5311 if (isrevnum) 5312 { 5313 p = strrchr (branch, '.'); 5314 *p = '\0'; 5315 } 5316 5317 /* Find the tip of the target branch. If we got a one- or two-digit 5318 revision number, this will be the head of the tree. Exception: 5319 if rev is a single-field revision equal to the branch number of 5320 the trunk (usually "1") then we want to treat it like an ordinary 5321 branch revision. */ 5322 if (dots == 0) 5323 { 5324 tip = xstrdup (rcs->head); 5325 if (atoi (tip) != atoi (branch)) 5326 { 5327 newrev = xrealloc (newrev, strlen (newrev) + 3); 5328 strcat (newrev, ".1"); 5329 dots = isrevnum = 1; 5330 } 5331 } 5332 else if (dots == 1) 5333 tip = xstrdup (rcs->head); 5334 else 5335 tip = RCS_getbranch (rcs, branch, 1); 5336 5337 /* If the branch does not exist, and we were supplied an exact 5338 revision number, signal an error. Otherwise, if we were 5339 given only a branch number, create it and set COMMITPT to 5340 the branch point. */ 5341 if (tip == NULL) 5342 { 5343 if (isrevnum) 5344 { 5345 error (0, 0, "%s: can't find branch point %s", 5346 rcs->print_path, branch); 5347 free (branch); 5348 free (newrev); 5349 status = 1; 5350 goto checkin_done; 5351 } 5352 delta->version = RCS_addbranch (rcs, branch); 5353 if (!delta->version) 5354 { 5355 free (branch); 5356 free (newrev); 5357 status = 1; 5358 goto checkin_done; 5359 } 5360 adding_branch = 1; 5361 p = strrchr (branch, '.'); 5362 *p = '\0'; 5363 tip = xstrdup (branch); 5364 } 5365 else 5366 { 5367 if (isrevnum) 5368 { 5369 /* NEWREV must be higher than TIP. */ 5370 if (compare_revnums (tip, newrev) >= 0) 5371 { 5372 error (0, 0, 5373 "%s: revision %s too low; must be higher than %s", 5374 rcs->print_path, 5375 newrev, tip); 5376 free (branch); 5377 free (newrev); 5378 free (tip); 5379 status = 1; 5380 goto checkin_done; 5381 } 5382 delta->version = xstrdup (newrev); 5383 } 5384 else 5385 /* Just increment the tip number to get the new revision. */ 5386 delta->version = increment_revnum (tip); 5387 } 5388 5389 nodep = findnode (rcs->versions, tip); 5390 commitpt = nodep->data; 5391 5392 free (branch); 5393 free (newrev); 5394 free (tip); 5395 } 5396 5397 assert (delta->version != NULL); 5398 5399 /* If COMMITPT is locked by us, break the lock. If it's locked 5400 by someone else, signal an error. */ 5401 nodep = findnode (RCS_getlocks (rcs), commitpt->version); 5402 if (nodep != NULL) 5403 { 5404 if (! STREQ (nodep->data, delta->author)) 5405 { 5406 /* If we are adding a branch, then leave the old lock around. 5407 That is sensible in the sense that when adding a branch, 5408 we don't need to use the lock to tell us where to check 5409 in. It is fishy in the sense that if it is our own lock, 5410 we break it. However, this is the RCS 5.7 behavior (at 5411 the end of addbranch in ci.c in RCS 5.7, it calls 5412 removelock only if it is our own lock, not someone 5413 else's). */ 5414 5415 if (!adding_branch) 5416 { 5417 error (0, 0, "%s: revision %s locked by %s", 5418 rcs->print_path, 5419 nodep->key, (char *)nodep->data); 5420 status = 1; 5421 goto checkin_done; 5422 } 5423 } 5424 else 5425 delnode (nodep); 5426 } 5427 5428 dtext->version = xstrdup (delta->version); 5429 5430 /* Obtain the change text for the new delta. If DELTA is to be the 5431 new head of the tree, then its change text should be the contents 5432 of the working file, and LEAFNODE's change text should be a diff. 5433 Else, DELTA's change text should be a diff between LEAFNODE and 5434 the working file. */ 5435 5436 tmpfile = cvs_temp_name(); 5437 status = RCS_checkout (rcs, NULL, commitpt->version, NULL, 5438 ((rcs->expand != NULL 5439 && STREQ (rcs->expand, "b")) 5440 ? "-kb" 5441 : "-ko"), 5442 tmpfile, 5443 NULL, NULL); 5444 if (status != 0) 5445 error (1, 0, 5446 "could not check out revision %s of `%s'", 5447 commitpt->version, rcs->print_path); 5448 5449 bufsize = 0; 5450 changefile = cvs_temp_name(); 5451 5452 /* Diff options should include --binary if the RCS file has -kb set 5453 in its `expand' field. */ 5454 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-a"); 5455 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n"); 5456 if (rcs->expand != NULL && STREQ (rcs->expand, "b")) 5457 run_add_arg_p (&dargc, &darg_allocated, &dargv, "--binary"); 5458 5459 if (STREQ (commitpt->version, rcs->head) && 5460 numdots (delta->version) == 1) 5461 { 5462 /* If this revision is being inserted on the trunk, the change text 5463 for the new delta should be the contents of the working file ... */ 5464 bufsize = 0; 5465 #ifdef PRESERVE_PERMISSIONS_SUPPORT 5466 if (preserve_perms && !S_ISREG (sb.st_mode)) 5467 /* Pretend file is empty. */ 5468 ; 5469 else 5470 #endif 5471 get_file (workfile, workfile, 5472 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r", 5473 &dtext->text, &bufsize, &dtext->len); 5474 5475 /* ... and the change text for the old delta should be a diff. */ 5476 commitpt->text = xmalloc (sizeof (Deltatext)); 5477 memset (commitpt->text, 0, sizeof (Deltatext)); 5478 5479 bufsize = 0; 5480 switch (diff_exec (workfile, tmpfile, NULL, NULL, 5481 dargc, dargv, changefile)) 5482 { 5483 case 0: 5484 case 1: 5485 break; 5486 case -1: 5487 /* FIXME-update-dir: message does not include update_dir. */ 5488 error (1, errno, "error diffing %s", workfile); 5489 break; 5490 default: 5491 /* FIXME-update-dir: message does not include update_dir. */ 5492 error (1, 0, "error diffing %s", workfile); 5493 break; 5494 } 5495 5496 /* OK, the text file case here is really dumb. Logically 5497 speaking we want diff to read the files in text mode, 5498 convert them to the canonical form found in RCS files 5499 (which, we hope at least, is independent of OS--always 5500 bare linefeeds), and then work with change texts in that 5501 format. However, diff_exec both generates change 5502 texts and produces output for user purposes (e.g. patch.c), 5503 and there is no way to distinguish between the two cases. 5504 So we actually implement the text file case by writing the 5505 change text as a text file, then reading it as a text file. 5506 This should cause no harm, but doesn't strike me as 5507 immensely clean. */ 5508 get_file (changefile, changefile, 5509 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r", 5510 &commitpt->text->text, &bufsize, &commitpt->text->len); 5511 5512 /* If COMMITPT->TEXT->TEXT is NULL, it means that CHANGEFILE 5513 was empty and that there are no differences between revisions. 5514 In that event, we want to force RCS_rewrite to write an empty 5515 string for COMMITPT's change text. Leaving the change text 5516 field set NULL won't work, since that means "preserve the original 5517 change text for this delta." */ 5518 if (commitpt->text->text == NULL) 5519 { 5520 commitpt->text->text = xstrdup (""); 5521 commitpt->text->len = 0; 5522 } 5523 } 5524 else 5525 { 5526 /* This file is not being inserted at the head, but on a side 5527 branch somewhere. Make a diff from the previous revision 5528 to the working file. */ 5529 switch (diff_exec (tmpfile, workfile, NULL, NULL, 5530 dargc, dargv, changefile)) 5531 { 5532 case 0: 5533 case 1: 5534 break; 5535 case -1: 5536 /* FIXME-update-dir: message does not include update_dir. */ 5537 error (1, errno, "error diffing %s", workfile); 5538 break; 5539 default: 5540 /* FIXME-update-dir: message does not include update_dir. */ 5541 error (1, 0, "error diffing %s", workfile); 5542 break; 5543 } 5544 /* See the comment above, at the other get_file invocation, 5545 regarding binary vs. text. */ 5546 get_file (changefile, changefile, 5547 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r", 5548 &dtext->text, &bufsize, 5549 &dtext->len); 5550 if (dtext->text == NULL) 5551 { 5552 dtext->text = xstrdup (""); 5553 dtext->len = 0; 5554 } 5555 } 5556 5557 run_arg_free_p (dargc, dargv); 5558 free (dargv); 5559 5560 /* Update DELTA linkage. It is important not to do this before 5561 the very end of RCS_checkin; if an error arises that forces 5562 us to abort checking in, we must not have malformed deltas 5563 partially linked into the tree. 5564 5565 If DELTA and COMMITPT are on different branches, do nothing -- 5566 DELTA is linked to the tree through COMMITPT->BRANCHES, and we 5567 don't want to change `next' pointers. 5568 5569 Otherwise, if the nodes are both on the trunk, link DELTA to 5570 COMMITPT; otherwise, link COMMITPT to DELTA. */ 5571 5572 if (numdots (commitpt->version) == numdots (delta->version)) 5573 { 5574 if (STREQ (commitpt->version, rcs->head)) 5575 { 5576 delta->next = rcs->head; 5577 rcs->head = xstrdup (delta->version); 5578 } 5579 else 5580 commitpt->next = xstrdup (delta->version); 5581 } 5582 5583 /* Add DELTA to RCS->VERSIONS. */ 5584 if (rcs->versions == NULL) 5585 rcs->versions = getlist(); 5586 nodep = getnode(); 5587 nodep->type = RCSVERS; 5588 nodep->delproc = rcsvers_delproc; 5589 nodep->data = delta; 5590 nodep->key = delta->version; 5591 (void) addnode (rcs->versions, nodep); 5592 5593 /* Write the new RCS file, inserting the new delta at COMMITPT. */ 5594 if (!(checkin_quiet || really_quiet)) 5595 { 5596 cvs_output ("new revision: ", 14); 5597 cvs_output (delta->version, 0); 5598 cvs_output ("; previous revision: ", 21); 5599 cvs_output (commitpt->version, 0); 5600 cvs_output ("\n", 1); 5601 } 5602 5603 RCS_rewrite (rcs, dtext, commitpt->version); 5604 5605 if ((flags & RCS_FLAGS_KEEPFILE) == 0) 5606 { 5607 if (unlink_file (workfile) < 0) 5608 /* FIXME-update-dir: message does not include update_dir. */ 5609 error (1, errno, "cannot remove %s", workfile); 5610 } 5611 if (unlink_file (tmpfile) < 0) 5612 error (0, errno, "cannot remove %s", tmpfile); 5613 free (tmpfile); 5614 if (unlink_file (changefile) < 0) 5615 error (0, errno, "cannot remove %s", changefile); 5616 free (changefile); 5617 5618 checkin_done: 5619 free (workfile); 5620 5621 if (commitpt != NULL && commitpt->text != NULL) 5622 { 5623 freedeltatext (commitpt->text); 5624 commitpt->text = NULL; 5625 } 5626 5627 freedeltatext (dtext); 5628 if (status != 0) 5629 { 5630 /* If delta has not been added to a List, then freeing the Node key 5631 * won't free delta->version. 5632 */ 5633 if (delta->version) free (delta->version); 5634 free_rcsvers_contents (delta); 5635 } 5636 5637 return status; 5638 } 5639 5640 5641 5642 /* This structure is passed between RCS_cmp_file and cmp_file_buffer. */ 5643 struct cmp_file_data 5644 { 5645 const char *filename; 5646 FILE *fp; 5647 int different; 5648 }; 5649 5650 /* Compare the contents of revision REV1 of RCS file RCS with the 5651 contents of REV2 if given, otherwise, compare with the contents of 5652 the file FILENAME. OPTIONS is a string for the keyword 5653 expansion options. Return 0 if the contents of the revision are 5654 the same as the contents of the file, 1 if they are different. */ 5655 int 5656 RCS_cmp_file (RCSNode *rcs, const char *rev1, char **rev1_cache, 5657 const char *rev2, const char *options, const char *filename) 5658 { 5659 int binary; 5660 5661 TRACE (TRACE_FUNCTION, "RCS_cmp_file( %s, %s, %s, %s, %s )", 5662 rcs->path ? rcs->path : "(null)", 5663 rev1 ? rev1 : "(null)", rev2 ? rev2 : "(null)", 5664 options ? options : "(null)", filename ? filename : "(null)"); 5665 5666 if (options != NULL && options[0] != '\0') 5667 binary = STREQ (options, "-kb"); 5668 else 5669 { 5670 char *expand; 5671 5672 expand = RCS_getexpand (rcs); 5673 if (expand != NULL && STREQ (expand, "b")) 5674 binary = 1; 5675 else 5676 binary = 0; 5677 } 5678 5679 #ifdef PRESERVE_PERMISSIONS_SUPPORT 5680 /* If CVS is to deal properly with special files (when 5681 PreservePermissions is on), the best way is to check out the 5682 revision to a temporary file and call `xcmp' on the two disk 5683 files. xcmp needs to handle non-regular files properly anyway, 5684 so calling it simplifies RCS_cmp_file. We *could* just yank 5685 the delta node out of the version tree and look for device 5686 numbers, but writing to disk and calling xcmp is a better 5687 abstraction (therefore probably more robust). -twp */ 5688 5689 if (preserve_perms) 5690 { 5691 char *tmp; 5692 int retcode; 5693 5694 tmp = cvs_temp_name(); 5695 retcode = RCS_checkout(rcs, NULL, rev, NULL, options, tmp, NULL, NULL); 5696 if (retcode != 0) 5697 return 1; 5698 5699 retcode = xcmp (tmp, filename); 5700 if (CVS_UNLINK (tmp) < 0) 5701 error (0, errno, "cannot remove %s", tmp); 5702 free (tmp); 5703 return retcode; 5704 } 5705 else 5706 #endif 5707 { 5708 FILE *fp; 5709 struct cmp_file_data data; 5710 const char *use_file1; 5711 char *tmpfile = NULL; 5712 5713 if (rev2 != NULL) 5714 { 5715 /* Open & cache rev1 */ 5716 tmpfile = cvs_temp_name(); 5717 if (RCS_checkout (rcs, NULL, rev1, NULL, options, tmpfile, 5718 NULL, NULL)) 5719 error (1, errno, 5720 "cannot check out revision %s of %s", 5721 rev1, rcs->print_path); 5722 use_file1 = tmpfile; 5723 if (rev1_cache != NULL) 5724 *rev1_cache = tmpfile; 5725 } 5726 else 5727 use_file1 = filename; 5728 5729 fp = CVS_FOPEN (use_file1, binary ? FOPEN_BINARY_READ : "r"); 5730 if (fp == NULL) 5731 /* FIXME-update-dir: should include update_dir in message. */ 5732 error (1, errno, "cannot open file %s for comparing", use_file1); 5733 5734 data.filename = use_file1; 5735 data.fp = fp; 5736 data.different = 0; 5737 5738 if (RCS_checkout (rcs, NULL, rev2 ? rev2 : rev1, NULL, options, 5739 RUN_TTY, cmp_file_buffer, &data )) 5740 error (1, errno, 5741 "cannot check out revision %s of %s", 5742 rev2 ? rev2 : rev1, rcs->print_path); 5743 5744 /* If we have not yet found a difference, make sure that we are at 5745 the end of the file. */ 5746 if (!data.different) 5747 { 5748 if (getc (fp) != EOF) 5749 data.different = 1; 5750 } 5751 5752 fclose (fp); 5753 if (rev1_cache == NULL && tmpfile) 5754 { 5755 if (CVS_UNLINK (tmpfile ) < 0) 5756 error (0, errno, "cannot remove %s", tmpfile); 5757 free (tmpfile); 5758 } 5759 5760 return data.different; 5761 } 5762 } 5763 5764 5765 5766 /* This is a subroutine of RCS_cmp_file. It is passed to 5767 RCS_checkout. */ 5768 #define CMP_BUF_SIZE (8 * 1024) 5769 5770 static void 5771 cmp_file_buffer (void *callerdat, const char *buffer, size_t len) 5772 { 5773 struct cmp_file_data *data = callerdat; 5774 char *filebuf; 5775 5776 /* If we've already found a difference, we don't need to check 5777 further. */ 5778 if (data->different) 5779 return; 5780 5781 filebuf = xmalloc (len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len); 5782 5783 while (len > 0) 5784 { 5785 size_t checklen; 5786 5787 checklen = len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len; 5788 if (fread (filebuf, 1, checklen, data->fp) != checklen) 5789 { 5790 if (ferror (data->fp)) 5791 error (1, errno, "cannot read file %s for comparing", 5792 data->filename); 5793 data->different = 1; 5794 free (filebuf); 5795 return; 5796 } 5797 5798 if (memcmp (filebuf, buffer, checklen) != 0) 5799 { 5800 data->different = 1; 5801 free (filebuf); 5802 return; 5803 } 5804 5805 buffer += checklen; 5806 len -= checklen; 5807 } 5808 5809 free (filebuf); 5810 } 5811 5812 5813 5814 /* For RCS file RCS, make symbolic tag TAG point to revision REV. 5815 This validates that TAG is OK for a user to use. Return value is 5816 -1 for error (and errno is set to indicate the error), positive for 5817 error (and an error message has been printed), or zero for success. */ 5818 int 5819 RCS_settag (RCSNode *rcs, const char *tag, const char *rev) 5820 { 5821 List *symbols; 5822 Node *node; 5823 5824 if (rcs->flags & PARTIAL) 5825 RCS_reparsercsfile (rcs, NULL, NULL); 5826 5827 /* FIXME: This check should be moved to RCS_check_tag. There is no 5828 reason for it to be here. */ 5829 if (STREQ (tag, TAG_BASE) 5830 || STREQ (tag, TAG_HEAD)) 5831 { 5832 /* Print the name of the tag might be considered redundant 5833 with the caller, which also prints it. Perhaps this helps 5834 clarify why the tag name is considered reserved, I don't 5835 know. */ 5836 error (0, 0, "Attempt to add reserved tag name %s", tag); 5837 return 1; 5838 } 5839 5840 /* A revision number of NULL means use the head or default branch. 5841 If rev is not NULL, it may be a symbolic tag or branch number; 5842 expand it to the correct numeric revision or branch head. */ 5843 if (rev == NULL) 5844 rev = rcs->branch ? rcs->branch : rcs->head; 5845 5846 /* At this point rcs->symbol_data may not have been parsed. 5847 Calling RCS_symbols will force it to be parsed into a list 5848 which we can easily manipulate. */ 5849 symbols = RCS_symbols (rcs); 5850 if (symbols == NULL) 5851 { 5852 symbols = getlist (); 5853 rcs->symbols = symbols; 5854 } 5855 node = findnode (symbols, tag); 5856 if (node != NULL) 5857 { 5858 free (node->data); 5859 node->data = xstrdup (rev); 5860 } 5861 else 5862 { 5863 node = getnode (); 5864 node->key = xstrdup (tag); 5865 node->data = xstrdup (rev); 5866 (void)addnode_at_front (symbols, node); 5867 } 5868 5869 return 0; 5870 } 5871 5872 5873 5874 /* Delete the symbolic tag TAG from the RCS file RCS. Return 0 if 5875 the tag was found (and removed), or 1 if it was not present. (In 5876 either case, the tag will no longer be in RCS->SYMBOLS.) */ 5877 int 5878 RCS_deltag (RCSNode *rcs, const char *tag) 5879 { 5880 List *symbols; 5881 Node *node; 5882 if (rcs->flags & PARTIAL) 5883 RCS_reparsercsfile (rcs, NULL, NULL); 5884 5885 symbols = RCS_symbols (rcs); 5886 if (symbols == NULL) 5887 return 1; 5888 5889 node = findnode (symbols, tag); 5890 if (node == NULL) 5891 return 1; 5892 5893 delnode (node); 5894 5895 return 0; 5896 } 5897 5898 5899 5900 /* Set the default branch of RCS to REV. */ 5901 int 5902 RCS_setbranch (RCSNode *rcs, const char *rev) 5903 { 5904 if (rcs->flags & PARTIAL) 5905 RCS_reparsercsfile (rcs, NULL, NULL); 5906 5907 if (rev && ! *rev) 5908 rev = NULL; 5909 5910 if (rev == NULL && rcs->branch == NULL) 5911 return 0; 5912 if (rev != NULL && rcs->branch != NULL && STREQ (rev, rcs->branch)) 5913 return 0; 5914 5915 if (rcs->branch != NULL) 5916 free (rcs->branch); 5917 rcs->branch = xstrdup (rev); 5918 5919 return 0; 5920 } 5921 5922 5923 5924 /* Lock revision REV. LOCK_QUIET is 1 to suppress output. FIXME: 5925 Most of the callers only call us because RCS_checkin still tends to 5926 like a lock (a relic of old behavior inherited from the RCS ci 5927 program). If we clean this up, only "cvs admin -l" will still need 5928 to call RCS_lock. */ 5929 5930 /* FIXME-twp: if a lock owned by someone else is broken, should this 5931 send mail to the lock owner? Prompt user? It seems like such an 5932 obscure situation for CVS as almost not worth worrying much 5933 about. */ 5934 int 5935 RCS_lock (RCSNode *rcs, const char *rev, int lock_quiet) 5936 { 5937 List *locks; 5938 Node *p; 5939 char *user; 5940 char *xrev = NULL; 5941 5942 if (rcs->flags & PARTIAL) 5943 RCS_reparsercsfile (rcs, NULL, NULL); 5944 5945 locks = RCS_getlocks (rcs); 5946 if (locks == NULL) 5947 locks = rcs->locks = getlist(); 5948 user = getcaller(); 5949 5950 /* A revision number of NULL means lock the head or default branch. */ 5951 if (rev == NULL) 5952 xrev = RCS_head (rcs); 5953 else 5954 xrev = RCS_gettag (rcs, rev, 1, NULL); 5955 5956 /* Make sure that the desired revision exists. Technically, 5957 we can update the locks list without even checking this, 5958 but RCS 5.7 did this. And it can't hurt. */ 5959 if (xrev == NULL || findnode (rcs->versions, xrev) == NULL) 5960 { 5961 if (!lock_quiet) 5962 error (0, 0, "%s: revision %s absent", rcs->print_path, rev); 5963 free (xrev); 5964 return 1; 5965 } 5966 5967 /* Is this rev already locked? */ 5968 p = findnode (locks, xrev); 5969 if (p != NULL) 5970 { 5971 if (STREQ (p->data, user)) 5972 { 5973 /* We already own the lock on this revision, so do nothing. */ 5974 free (xrev); 5975 return 0; 5976 } 5977 5978 #if 0 5979 /* Well, first of all, "rev" below should be "xrev" to avoid 5980 core dumps. But more importantly, should we really be 5981 breaking the lock unconditionally? What CVS 1.9 does (via 5982 RCS) is to prompt "Revision 1.1 is already locked by fred. 5983 Do you want to break the lock? [ny](n): ". Well, we don't 5984 want to interact with the user (certainly not at the 5985 server/protocol level, and probably not in the command-line 5986 client), but isn't it more sensible to give an error and 5987 let the user run "cvs admin -u" if they want to break the 5988 lock? */ 5989 5990 /* Break the lock. */ 5991 if (!lock_quiet) 5992 { 5993 cvs_output (rev, 0); 5994 cvs_output (" unlocked\n", 0); 5995 } 5996 delnode (p); 5997 #else 5998 error (1, 0, "Revision %s is already locked by %s", 5999 xrev, (char *)p->data); 6000 #endif 6001 } 6002 6003 /* Create a new lock. */ 6004 p = getnode(); 6005 p->key = xrev; /* already xstrdupped */ 6006 p->data = xstrdup (getcaller()); 6007 (void)addnode_at_front (locks, p); 6008 6009 if (!lock_quiet) 6010 { 6011 cvs_output (xrev, 0); 6012 cvs_output (" locked\n", 0); 6013 } 6014 6015 return 0; 6016 } 6017 6018 6019 6020 /* Unlock revision REV. UNLOCK_QUIET is 1 to suppress output. FIXME: 6021 Like RCS_lock, this can become a no-op if we do the checkin 6022 ourselves. 6023 6024 If REV is not null and is locked by someone else, break their 6025 lock and notify them. It is an open issue whether RCS_unlock 6026 queries the user about whether or not to break the lock. */ 6027 int 6028 RCS_unlock (RCSNode *rcs, char *rev, int unlock_quiet) 6029 { 6030 Node *lock; 6031 List *locks; 6032 char *user; 6033 char *xrev = NULL; 6034 6035 user = getcaller(); 6036 if (rcs->flags & PARTIAL) 6037 RCS_reparsercsfile (rcs, NULL, NULL); 6038 6039 /* If rev is NULL, unlock the revision held by the caller; if more 6040 than one, make the user specify the revision explicitly. This 6041 differs from RCS which unlocks the latest revision (first in 6042 rcs->locks) held by the caller. */ 6043 if (rev == NULL) 6044 { 6045 Node *p; 6046 6047 /* No-ops: attempts to unlock an empty tree or an unlocked file. */ 6048 if (rcs->head == NULL) 6049 { 6050 if (!unlock_quiet) 6051 cvs_outerr ("can't unlock an empty tree\n", 0); 6052 return 0; 6053 } 6054 6055 locks = RCS_getlocks (rcs); 6056 if (locks == NULL) 6057 { 6058 if (!unlock_quiet) 6059 cvs_outerr ("No locks are set.\n", 0); 6060 return 0; 6061 } 6062 6063 lock = NULL; 6064 for (p = locks->list->next; p != locks->list; p = p->next) 6065 { 6066 if (STREQ (p->data, user)) 6067 { 6068 if (lock != NULL) 6069 { 6070 if (!unlock_quiet) 6071 error (0, 0, "\ 6072 %s: multiple revisions locked by %s; please specify one", rcs->print_path, user); 6073 return 1; 6074 } 6075 lock = p; 6076 } 6077 } 6078 if (lock == NULL) 6079 { 6080 if (!unlock_quiet) 6081 error (0, 0, "No locks are set for %s.\n", user); 6082 return 0; /* no lock found, ergo nothing to do */ 6083 } 6084 xrev = xstrdup (lock->key); 6085 } 6086 else 6087 { 6088 xrev = RCS_gettag (rcs, rev, 1, NULL); 6089 if (xrev == NULL) 6090 { 6091 error (0, 0, "%s: revision %s absent", rcs->print_path, rev); 6092 return 1; 6093 } 6094 } 6095 6096 lock = findnode (RCS_getlocks (rcs), xrev); 6097 if (lock == NULL) 6098 { 6099 /* This revision isn't locked. */ 6100 free (xrev); 6101 return 0; 6102 } 6103 6104 if (! STREQ (lock->data, user)) 6105 { 6106 /* If the revision is locked by someone else, notify 6107 them. Note that this shouldn't ever happen if RCS_unlock 6108 is called with a NULL revision, since that means "whatever 6109 revision is currently locked by the caller." */ 6110 char *repos, *workfile; 6111 if (!unlock_quiet) 6112 error (0, 0, "\ 6113 %s: revision %s locked by %s; breaking lock", rcs->print_path, xrev, 6114 (char *)lock->data); 6115 repos = xstrdup (rcs->path); 6116 workfile = strrchr (repos, '/'); 6117 *workfile++ = '\0'; 6118 notify_do ('C', workfile, NULL, user, NULL, NULL, repos); 6119 free (repos); 6120 } 6121 6122 delnode (lock); 6123 if (!unlock_quiet) 6124 { 6125 cvs_output (xrev, 0); 6126 cvs_output (" unlocked\n", 0); 6127 } 6128 6129 free (xrev); 6130 return 0; 6131 } 6132 6133 6134 6135 /* Add USER to the access list of RCS. Do nothing if already present. 6136 FIXME-twp: check syntax of USER to make sure it's a valid id. */ 6137 6138 void 6139 RCS_addaccess (RCSNode *rcs, char *user) 6140 { 6141 char *access, *a; 6142 6143 if (rcs->flags & PARTIAL) 6144 RCS_reparsercsfile (rcs, NULL, NULL); 6145 6146 if (rcs->access == NULL) 6147 rcs->access = xstrdup (user); 6148 else 6149 { 6150 access = xstrdup (rcs->access); 6151 for (a = strtok (access, " "); a != NULL; a = strtok (NULL, " ")) 6152 { 6153 if (STREQ (a, user)) 6154 { 6155 free (access); 6156 return; 6157 } 6158 } 6159 free (access); 6160 rcs->access = xrealloc (rcs->access, 6161 strlen (rcs->access) + strlen (user) + 2); 6162 strcat (rcs->access, " "); 6163 strcat (rcs->access, user); 6164 } 6165 } 6166 6167 6168 6169 /* Remove USER from the access list of RCS. */ 6170 void 6171 RCS_delaccess (RCSNode *rcs, char *user) 6172 { 6173 char *p, *s; 6174 int ulen; 6175 6176 if (rcs->flags & PARTIAL) 6177 RCS_reparsercsfile (rcs, NULL, NULL); 6178 6179 if (rcs->access == NULL) 6180 return; 6181 6182 if (user == NULL) 6183 { 6184 free (rcs->access); 6185 rcs->access = NULL; 6186 return; 6187 } 6188 6189 p = rcs->access; 6190 ulen = strlen (user); 6191 while (p != NULL) 6192 { 6193 if (strncmp (p, user, ulen) == 0 && (p[ulen] == '\0' || p[ulen] == ' ')) 6194 break; 6195 p = strchr (p, ' '); 6196 if (p != NULL) 6197 ++p; 6198 } 6199 6200 if (p == NULL) 6201 return; 6202 6203 s = p + ulen; 6204 while (*s != '\0') 6205 *p++ = *s++; 6206 *p = '\0'; 6207 } 6208 6209 6210 6211 char * 6212 RCS_getaccess (RCSNode *rcs) 6213 { 6214 if (rcs->flags & PARTIAL) 6215 RCS_reparsercsfile (rcs, NULL, NULL); 6216 6217 return rcs->access; 6218 } 6219 6220 6221 6222 /* Return a nonzero value if the revision specified by ARG is found. */ 6223 static int 6224 findtag (Node *node, void *arg) 6225 { 6226 char *rev = arg; 6227 6228 if (STREQ (node->data, rev)) 6229 return 1; 6230 else 6231 return 0; 6232 } 6233 6234 6235 6236 /* Delete revisions between REV1 and REV2. The changes between the two 6237 revisions must be collapsed, and the result stored in the revision 6238 immediately preceding the lower one. Return 0 for successful completion, 6239 1 otherwise. 6240 6241 Solution: check out the revision preceding REV1 and the revision 6242 following REV2. Use call_diff to find aggregate diffs between 6243 these two revisions, and replace the delta text for the latter one 6244 with the new aggregate diff. Alternatively, we could write a 6245 function that takes two change texts and combines them to produce a 6246 new change text, without checking out any revs or calling diff. It 6247 would be hairy, but so, so cool. 6248 6249 If INCLUSIVE is set, then TAG1 and TAG2, if non-NULL, tell us to 6250 delete that revision as well (cvs admin -o tag1:tag2). If clear, 6251 delete up to but not including that revision (cvs admin -o tag1::tag2). 6252 This does not affect TAG1 or TAG2 being NULL; the meaning of the start 6253 point in ::tag2 and :tag2 is the same and likewise for end points. */ 6254 int 6255 RCS_delete_revs (RCSNode *rcs, char *tag1, char *tag2, int inclusive) 6256 { 6257 char *next; 6258 Node *nodep; 6259 RCSVers *revp = NULL; 6260 RCSVers *beforep; 6261 int status, found; 6262 int save_noexec; 6263 6264 char *branchpoint = NULL; 6265 char *rev1 = NULL; 6266 char *rev2 = NULL; 6267 int rev1_inclusive = inclusive; 6268 int rev2_inclusive = inclusive; 6269 char *before = NULL; 6270 char *after = NULL; 6271 char *beforefile = NULL; 6272 char *afterfile = NULL; 6273 char *outfile = NULL; 6274 6275 if (tag1 == NULL && tag2 == NULL) 6276 return 0; 6277 6278 /* Assume error status until everything is finished. */ 6279 status = 1; 6280 6281 /* Make sure both revisions exist. */ 6282 if (tag1 != NULL) 6283 { 6284 rev1 = RCS_gettag (rcs, tag1, 1, NULL); 6285 if (rev1 == NULL || (nodep = findnode (rcs->versions, rev1)) == NULL) 6286 { 6287 error (0, 0, "%s: Revision %s doesn't exist.", rcs->print_path, tag1); 6288 goto delrev_done; 6289 } 6290 } 6291 if (tag2 != NULL) 6292 { 6293 rev2 = RCS_gettag (rcs, tag2, 1, NULL); 6294 if (rev2 == NULL || (nodep = findnode (rcs->versions, rev2)) == NULL) 6295 { 6296 error (0, 0, "%s: Revision %s doesn't exist.", rcs->print_path, tag2); 6297 goto delrev_done; 6298 } 6299 } 6300 6301 /* If rev1 is on the trunk and rev2 is NULL, rev2 should be 6302 RCS->HEAD. (*Not* RCS_head(rcs), which may return rcs->branch 6303 instead.) We need to check this special case early, in order 6304 to make sure that rev1 and rev2 get ordered correctly. */ 6305 if (rev2 == NULL && numdots (rev1) == 1) 6306 { 6307 rev2 = xstrdup (rcs->head); 6308 rev2_inclusive = 1; 6309 } 6310 6311 if (rev2 == NULL) 6312 rev2_inclusive = 1; 6313 6314 if (rev1 != NULL && rev2 != NULL) 6315 { 6316 /* A range consisting of a branch number means the latest revision 6317 on that branch. */ 6318 if (RCS_isbranch (rcs, rev1) && STREQ (rev1, rev2)) 6319 { 6320 char *tmp = RCS_getbranch (rcs, rev1, 0); 6321 free (rev1); 6322 free (rev2); 6323 rev1 = rev2 = tmp; 6324 } 6325 else 6326 { 6327 /* Make sure REV1 and REV2 are ordered correctly (in the 6328 same order as the next field). For revisions on the 6329 trunk, REV1 should be higher than REV2; for branches, 6330 REV1 should be lower. */ 6331 /* Shouldn't we just be giving an error in the case where 6332 the user specifies the revisions in the wrong order 6333 (that is, always swap on the trunk, never swap on a 6334 branch, in the non-error cases)? It is not at all 6335 clear to me that users who specify -o 1.4:1.2 really 6336 meant to type -o 1.2:1.4, and the out of order usage 6337 has never been documented, either by cvs.texinfo or 6338 rcs(1). */ 6339 char *temp; 6340 int temp_inclusive; 6341 if (numdots (rev1) == 1) 6342 { 6343 if (compare_revnums (rev1, rev2) <= 0) 6344 { 6345 temp = rev2; 6346 rev2 = rev1; 6347 rev1 = temp; 6348 6349 temp_inclusive = rev2_inclusive; 6350 rev2_inclusive = rev1_inclusive; 6351 rev1_inclusive = temp_inclusive; 6352 } 6353 } 6354 else if (compare_revnums (rev1, rev2) > 0) 6355 { 6356 temp = rev2; 6357 rev2 = rev1; 6358 rev1 = temp; 6359 6360 temp_inclusive = rev2_inclusive; 6361 rev2_inclusive = rev1_inclusive; 6362 rev1_inclusive = temp_inclusive; 6363 } 6364 } 6365 } 6366 6367 /* Basically the same thing; make sure that the ordering is what we 6368 need. */ 6369 if (rev1 == NULL) 6370 { 6371 assert (rev2 != NULL); 6372 if (numdots (rev2) == 1) 6373 { 6374 /* Swap rev1 and rev2. */ 6375 int temp_inclusive; 6376 6377 rev1 = rev2; 6378 rev2 = NULL; 6379 6380 temp_inclusive = rev2_inclusive; 6381 rev2_inclusive = rev1_inclusive; 6382 rev1_inclusive = temp_inclusive; 6383 } 6384 } 6385 6386 /* Put the revision number preceding the first one to delete into 6387 BEFORE (where "preceding" means according to the next field). 6388 If the first revision to delete is the first revision on its 6389 branch (e.g. 1.3.2.1), BEFORE should be the node on the trunk 6390 at which the branch is rooted. If the first revision to delete 6391 is the head revision of the trunk, set BEFORE to NULL. 6392 6393 Note that because BEFORE may not be on the same branch as REV1, 6394 it is not very handy for navigating the revision tree. It's 6395 most useful just for checking out the revision preceding REV1. */ 6396 before = NULL; 6397 branchpoint = RCS_getbranchpoint (rcs, rev1 != NULL ? rev1 : rev2); 6398 if (rev1 == NULL) 6399 { 6400 rev1 = xstrdup (branchpoint); 6401 if (numdots (branchpoint) > 1) 6402 { 6403 char *bp; 6404 bp = strrchr (branchpoint, '.'); 6405 while (*--bp != '.') 6406 ; 6407 *bp = '\0'; 6408 /* Note that this is exclusive, always, because the inclusive 6409 flag doesn't affect the meaning when rev1 == NULL. */ 6410 before = xstrdup (branchpoint); 6411 *bp = '.'; 6412 } 6413 } 6414 else if (! STREQ (rev1, branchpoint)) 6415 { 6416 /* Walk deltas from BRANCHPOINT on, looking for REV1. */ 6417 nodep = findnode (rcs->versions, branchpoint); 6418 revp = nodep->data; 6419 while (revp->next != NULL && ! STREQ (revp->next, rev1)) 6420 { 6421 revp = nodep->data; 6422 nodep = findnode (rcs->versions, revp->next); 6423 } 6424 if (revp->next == NULL) 6425 { 6426 error (0, 0, "%s: Revision %s doesn't exist.", rcs->print_path, rev1); 6427 goto delrev_done; 6428 } 6429 if (rev1_inclusive) 6430 before = xstrdup (revp->version); 6431 else 6432 { 6433 before = rev1; 6434 nodep = findnode (rcs->versions, before); 6435 rev1 = xstrdup (((RCSVers *)nodep->data)->next); 6436 } 6437 } 6438 else if (!rev1_inclusive) 6439 { 6440 before = rev1; 6441 nodep = findnode (rcs->versions, before); 6442 rev1 = xstrdup (((RCSVers *)nodep->data)->next); 6443 } 6444 else if (numdots (branchpoint) > 1) 6445 { 6446 /* Example: rev1 is "1.3.2.1", branchpoint is "1.3.2.1". 6447 Set before to "1.3". */ 6448 char *bp; 6449 bp = strrchr (branchpoint, '.'); 6450 while (*--bp != '.') 6451 ; 6452 *bp = '\0'; 6453 before = xstrdup (branchpoint); 6454 *bp = '.'; 6455 } 6456 6457 /* If any revision between REV1 and REV2 is locked or is a branch point, 6458 we can't delete that revision and must abort. */ 6459 after = NULL; 6460 next = rev1; 6461 found = 0; 6462 while (!found && next != NULL) 6463 { 6464 nodep = findnode (rcs->versions, next); 6465 revp = nodep->data; 6466 6467 if (rev2 != NULL) 6468 found = STREQ (revp->version, rev2); 6469 next = revp->next; 6470 6471 if ((!found && next != NULL) || rev2_inclusive || rev2 == NULL) 6472 { 6473 if (findnode (RCS_getlocks (rcs), revp->version)) 6474 { 6475 error (0, 0, "%s: can't remove locked revision %s", 6476 rcs->print_path, 6477 revp->version); 6478 goto delrev_done; 6479 } 6480 if (revp->branches != NULL) 6481 { 6482 error (0, 0, "%s: can't remove branch point %s", 6483 rcs->print_path, 6484 revp->version); 6485 goto delrev_done; 6486 } 6487 6488 /* Doing this only for the :: syntax is for compatibility. 6489 See cvs.texinfo for somewhat more discussion. */ 6490 if (!inclusive 6491 && walklist (RCS_symbols (rcs), findtag, revp->version)) 6492 { 6493 /* We don't print which file this happens to on the theory 6494 that the caller will print the name of the file in a 6495 more useful fashion (fullname not rcs->path). */ 6496 error (0, 0, "cannot remove revision %s because it has tags", 6497 revp->version); 6498 goto delrev_done; 6499 } 6500 6501 /* It's misleading to print the `deleting revision' output 6502 here, since we may not actually delete these revisions. 6503 But that's how RCS does it. Bleah. Someday this should be 6504 moved to the point where the revs are actually marked for 6505 deletion. -twp */ 6506 cvs_output ("deleting revision ", 0); 6507 cvs_output (revp->version, 0); 6508 cvs_output ("\n", 1); 6509 } 6510 } 6511 6512 if (rev2 == NULL) 6513 ; 6514 else if (found) 6515 { 6516 if (rev2_inclusive) 6517 after = xstrdup (next); 6518 else 6519 after = xstrdup (revp->version); 6520 } 6521 else if (!inclusive) 6522 { 6523 /* In the case of an empty range, for example 1.2::1.2 or 6524 1.2::1.3, we want to just do nothing. */ 6525 status = 0; 6526 goto delrev_done; 6527 } 6528 else 6529 { 6530 /* This looks fishy in the cases where tag1 == NULL or tag2 == NULL. 6531 Are those cases really impossible? */ 6532 assert (tag1 != NULL); 6533 assert (tag2 != NULL); 6534 6535 error (0, 0, "%s: invalid revision range %s:%s", rcs->print_path, 6536 tag1, tag2); 6537 goto delrev_done; 6538 } 6539 6540 if (after == NULL && before == NULL) 6541 { 6542 /* The user is trying to delete all revisions. While an 6543 RCS file without revisions makes sense to RCS (e.g. the 6544 state after "rcs -i"), CVS has never been able to cope with 6545 it. So at least for now we just make this an error. 6546 6547 We don't include rcs->path in the message since "cvs admin" 6548 already printed "RCS file:" and the name. */ 6549 error (1, 0, "attempt to delete all revisions"); 6550 } 6551 6552 /* The conditionals at this point get really hairy. Here is the 6553 general idea: 6554 6555 IF before != NULL and after == NULL 6556 THEN don't check out any revisions, just delete them 6557 IF before == NULL and after != NULL 6558 THEN only check out after's revision, and use it for the new deltatext 6559 ELSE 6560 check out both revisions and diff -n them. This could use 6561 RCS_exec_rcsdiff with some changes, like being able 6562 to suppress diagnostic messages and to direct output. */ 6563 6564 if (after != NULL) 6565 { 6566 char *diffbuf; 6567 size_t bufsize, len; 6568 6569 #if defined (WOE32) && !defined (__CYGWIN32__) 6570 /* FIXME: This is an awful kludge, but at least until I have 6571 time to work on it a little more and test it, I'd rather 6572 give a fatal error than corrupt the file. I think that we 6573 need to use "-kb" and "--binary" and "rb" to get_file 6574 (probably can do it always, not just for binary files, if 6575 we are consistent between the RCS_checkout and the diff). */ 6576 { 6577 char *expand = RCS_getexpand (rcs); 6578 if (expand != NULL && STREQ (expand, "b")) 6579 error (1, 0, 6580 "admin -o not implemented yet for binary on this system"); 6581 } 6582 #endif /* WOE32 */ 6583 6584 afterfile = cvs_temp_name(); 6585 status = RCS_checkout (rcs, NULL, after, NULL, "-ko", afterfile, 6586 NULL, NULL); 6587 if (status > 0) 6588 goto delrev_done; 6589 6590 if (before == NULL) 6591 { 6592 /* We are deleting revisions from the head of the tree, 6593 so must create a new head. */ 6594 diffbuf = NULL; 6595 bufsize = 0; 6596 get_file (afterfile, afterfile, "r", &diffbuf, &bufsize, &len); 6597 6598 save_noexec = noexec; 6599 noexec = 0; 6600 if (unlink_file (afterfile) < 0) 6601 error (0, errno, "cannot remove %s", afterfile); 6602 noexec = save_noexec; 6603 6604 free (afterfile); 6605 afterfile = NULL; 6606 6607 free (rcs->head); 6608 rcs->head = xstrdup (after); 6609 } 6610 else 6611 { 6612 int dargc = 0; 6613 size_t darg_allocated = 0; 6614 char **dargv = NULL; 6615 6616 beforefile = cvs_temp_name(); 6617 status = RCS_checkout (rcs, NULL, before, NULL, "-ko", beforefile, 6618 NULL, NULL); 6619 if (status > 0) 6620 goto delrev_done; 6621 6622 outfile = cvs_temp_name(); 6623 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-a"); 6624 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n"); 6625 status = diff_exec (beforefile, afterfile, NULL, NULL, 6626 dargc, dargv, outfile); 6627 run_arg_free_p (dargc, dargv); 6628 free (dargv); 6629 6630 if (status == 2) 6631 { 6632 /* Not sure we need this message; will diff_exec already 6633 have printed an error? */ 6634 error (0, 0, "%s: could not diff", rcs->print_path); 6635 status = 1; 6636 goto delrev_done; 6637 } 6638 6639 diffbuf = NULL; 6640 bufsize = 0; 6641 get_file (outfile, outfile, "r", &diffbuf, &bufsize, &len); 6642 } 6643 6644 /* Save the new change text in after's delta node. */ 6645 nodep = findnode (rcs->versions, after); 6646 revp = nodep->data; 6647 6648 assert (revp->text == NULL); 6649 6650 revp->text = xmalloc (sizeof (Deltatext)); 6651 memset (revp->text, 0, sizeof (Deltatext)); 6652 revp->text->version = xstrdup (revp->version); 6653 revp->text->text = diffbuf; 6654 revp->text->len = len; 6655 6656 /* If DIFFBUF is NULL, it means that OUTFILE is empty and that 6657 there are no differences between the two revisions. In that 6658 case, we want to force RCS_copydeltas to write an empty string 6659 for the new change text (leaving the text field set NULL 6660 means "preserve the original change text for this delta," so 6661 we don't want that). */ 6662 if (revp->text->text == NULL) 6663 revp->text->text = xstrdup (""); 6664 } 6665 6666 /* Walk through the revisions (again) to mark each one as 6667 outdated. (FIXME: would it be safe to use the `dead' field for 6668 this? Doubtful.) */ 6669 for (next = rev1; 6670 next != NULL && (after == NULL || ! STREQ (next, after)); 6671 next = revp->next) 6672 { 6673 nodep = findnode (rcs->versions, next); 6674 revp = nodep->data; 6675 revp->outdated = 1; 6676 } 6677 6678 /* Update delta links. If BEFORE == NULL, we're changing the 6679 head of the tree and don't need to update any `next' links. */ 6680 if (before != NULL) 6681 { 6682 /* If REV1 is the first node on its branch, then BEFORE is its 6683 root node (on the trunk) and we have to update its branches 6684 list. Otherwise, BEFORE is on the same branch as AFTER, and 6685 we can just change BEFORE's `next' field to point to AFTER. 6686 (This should be safe: since findnode manages its lists via 6687 the `hashnext' and `hashprev' fields, rather than `next' and 6688 `prev', mucking with `next' and `prev' should not corrupt the 6689 delta tree's internal structure. Much. -twp) */ 6690 6691 if (rev1 == NULL) 6692 /* beforep's ->next field already should be equal to after, 6693 which I think is always NULL in this case. */ 6694 ; 6695 else if (STREQ (rev1, branchpoint)) 6696 { 6697 nodep = findnode (rcs->versions, before); 6698 revp = nodep->data; 6699 nodep = revp->branches->list->next; 6700 while (nodep != revp->branches->list && 6701 ! STREQ (nodep->key, rev1)) 6702 nodep = nodep->next; 6703 assert (nodep != revp->branches->list); 6704 if (after == NULL) 6705 delnode (nodep); 6706 else 6707 { 6708 free (nodep->key); 6709 nodep->key = xstrdup (after); 6710 } 6711 } 6712 else 6713 { 6714 nodep = findnode (rcs->versions, before); 6715 beforep = nodep->data; 6716 free (beforep->next); 6717 beforep->next = xstrdup (after); 6718 } 6719 } 6720 6721 status = 0; 6722 6723 delrev_done: 6724 if (rev1 != NULL) 6725 free (rev1); 6726 if (rev2 && rev2 != rev1) 6727 free (rev2); 6728 if (branchpoint != NULL) 6729 free (branchpoint); 6730 if (before != NULL) 6731 free (before); 6732 if (after != NULL) 6733 free (after); 6734 6735 save_noexec = noexec; 6736 noexec = 0; 6737 if (beforefile != NULL) 6738 { 6739 if (unlink_file (beforefile) < 0) 6740 error (0, errno, "cannot remove %s", beforefile); 6741 free (beforefile); 6742 } 6743 if (afterfile != NULL) 6744 { 6745 if (unlink_file (afterfile) < 0) 6746 error (0, errno, "cannot remove %s", afterfile); 6747 free (afterfile); 6748 } 6749 if (outfile != NULL) 6750 { 6751 if (unlink_file (outfile) < 0) 6752 error (0, errno, "cannot remove %s", outfile); 6753 free (outfile); 6754 } 6755 noexec = save_noexec; 6756 6757 return status; 6758 } 6759 6760 6761 6762 /* 6763 * TRUE if there exists a symbolic tag "tag" in file. 6764 */ 6765 int 6766 RCS_exist_tag (RCSNode *rcs, char *tag) 6767 { 6768 6769 assert (rcs != NULL); 6770 6771 if (findnode (RCS_symbols (rcs), tag)) 6772 return 1; 6773 return 0; 6774 6775 } 6776 6777 6778 6779 /* 6780 * TRUE if RCS revision number "rev" exists. 6781 * This includes magic branch revisions, not found in rcs->versions, 6782 * but only in rcs->symbols, requiring a list walk to find them. 6783 * Take advantage of list walk callback function already used by 6784 * RCS_delete_revs, above. 6785 */ 6786 int 6787 RCS_exist_rev (RCSNode *rcs, char *rev) 6788 { 6789 6790 assert (rcs != NULL); 6791 6792 if (rcs->flags & PARTIAL) 6793 RCS_reparsercsfile (rcs, NULL, NULL); 6794 6795 if (findnode(rcs->versions, rev) != 0) 6796 return 1; 6797 6798 if (walklist (RCS_symbols(rcs), findtag, rev) != 0) 6799 return 1; 6800 6801 return 0; 6802 6803 } 6804 6805 6806 6807 6808 /* RCS_deltas and friends. Processing of the deltas in RCS files. */ 6809 struct line 6810 { 6811 /* Text of this line. Part of the same malloc'd block as the struct 6812 line itself (we probably should use the "struct hack" (char text[1]) 6813 and save ourselves sizeof (char *) bytes). Does not include \n; 6814 instead has_newline indicates the presence or absence of \n. */ 6815 char *text; 6816 /* Length of this line, not counting \n if has_newline is true. */ 6817 size_t len; 6818 /* Version in which it was introduced. */ 6819 RCSVers *vers; 6820 /* Nonzero if this line ends with \n. This will always be true 6821 except possibly for the last line. */ 6822 int has_newline; 6823 /* Number of pointers to this struct line. */ 6824 int refcount; 6825 }; 6826 6827 struct linevector 6828 { 6829 /* How many lines in use for this linevector? */ 6830 unsigned int nlines; 6831 /* How many lines allocated for this linevector? */ 6832 unsigned int lines_alloced; 6833 /* Pointer to array containing a pointer to each line. */ 6834 struct line **vector; 6835 }; 6836 6837 6838 6839 /* Initialize *VEC to be a linevector with no lines. */ 6840 static void 6841 linevector_init (struct linevector *vec) 6842 { 6843 vec->lines_alloced = 0; 6844 vec->nlines = 0; 6845 vec->vector = NULL; 6846 } 6847 6848 6849 6850 /* Given some text TEXT, add each of its lines to VEC before line POS 6851 (where line 0 is the first line). The last line in TEXT may or may 6852 not be \n terminated. 6853 Set the version for each of the new lines to VERS. This 6854 function returns non-zero for success. It returns zero if the line 6855 number is out of range. 6856 6857 Each of the lines in TEXT are copied to space which is managed with 6858 the linevector (and freed by linevector_free). So the caller doesn't 6859 need to keep TEXT around after the call to this function. */ 6860 static int 6861 linevector_add (struct linevector *vec, const char *text, size_t len, 6862 RCSVers *vers, unsigned int pos) 6863 { 6864 const char *textend; 6865 unsigned int i; 6866 unsigned int nnew; 6867 const char *p; 6868 const char *nextline_text; 6869 size_t nextline_len; 6870 int nextline_newline; 6871 struct line *q; 6872 6873 if (len == 0) 6874 return 1; 6875 6876 textend = text + len; 6877 6878 /* Count the number of lines we will need to add. */ 6879 nnew = 1; 6880 for (p = text; p < textend; ++p) 6881 if (*p == '\n' && p + 1 < textend) 6882 ++nnew; 6883 6884 /* Expand VEC->VECTOR if needed. */ 6885 if (vec->nlines + nnew >= vec->lines_alloced) 6886 { 6887 if (vec->lines_alloced == 0) 6888 vec->lines_alloced = 10; 6889 while (vec->nlines + nnew >= vec->lines_alloced) 6890 vec->lines_alloced *= 2; 6891 vec->vector = xnrealloc (vec->vector, 6892 vec->lines_alloced, sizeof (*vec->vector)); 6893 } 6894 6895 /* Make room for the new lines in VEC->VECTOR. */ 6896 for (i = vec->nlines + nnew - 1; i >= pos + nnew; --i) 6897 vec->vector[i] = vec->vector[i - nnew]; 6898 6899 if (pos > vec->nlines) 6900 return 0; 6901 6902 /* Actually add the lines, to VEC->VECTOR. */ 6903 i = pos; 6904 nextline_text = text; 6905 nextline_newline = 0; 6906 for (p = text; p < textend; ++p) 6907 if (*p == '\n') 6908 { 6909 nextline_newline = 1; 6910 if (p + 1 == textend) 6911 /* If there are no characters beyond the last newline, we 6912 don't consider it another line. */ 6913 break; 6914 nextline_len = p - nextline_text; 6915 q = xmalloc (sizeof (struct line) + nextline_len); 6916 q->vers = vers; 6917 q->text = (char *)q + sizeof (struct line); 6918 q->len = nextline_len; 6919 q->has_newline = nextline_newline; 6920 q->refcount = 1; 6921 memcpy (q->text, nextline_text, nextline_len); 6922 vec->vector[i++] = q; 6923 6924 nextline_text = (char *)p + 1; 6925 nextline_newline = 0; 6926 } 6927 nextline_len = p - nextline_text; 6928 q = xmalloc (sizeof (struct line) + nextline_len); 6929 q->vers = vers; 6930 q->text = (char *)q + sizeof (struct line); 6931 q->len = nextline_len; 6932 q->has_newline = nextline_newline; 6933 q->refcount = 1; 6934 memcpy (q->text, nextline_text, nextline_len); 6935 vec->vector[i] = q; 6936 6937 vec->nlines += nnew; 6938 6939 return 1; 6940 } 6941 6942 6943 6944 /* Remove NLINES lines from VEC at position POS (where line 0 is the 6945 first line). */ 6946 static void 6947 linevector_delete (struct linevector *vec, unsigned int pos, 6948 unsigned int nlines) 6949 { 6950 unsigned int i; 6951 unsigned int last; 6952 6953 last = vec->nlines - nlines; 6954 for (i = pos; i < pos + nlines; ++i) 6955 { 6956 if (--vec->vector[i]->refcount == 0) 6957 free (vec->vector[i]); 6958 } 6959 for (i = pos; i < last; ++i) 6960 vec->vector[i] = vec->vector[i + nlines]; 6961 vec->nlines -= nlines; 6962 } 6963 6964 6965 6966 /* Copy FROM to TO, copying the vectors but not the lines pointed to. */ 6967 static void 6968 linevector_copy (struct linevector *to, struct linevector *from) 6969 { 6970 unsigned int ln; 6971 6972 for (ln = 0; ln < to->nlines; ++ln) 6973 { 6974 if (--to->vector[ln]->refcount == 0) 6975 free (to->vector[ln]); 6976 } 6977 if (from->nlines > to->lines_alloced) 6978 { 6979 if (to->lines_alloced == 0) 6980 to->lines_alloced = 10; 6981 while (from->nlines > to->lines_alloced) 6982 to->lines_alloced *= 2; 6983 to->vector = xnrealloc (to->vector, 6984 to->lines_alloced, 6985 sizeof (*to->vector)); 6986 } 6987 memcpy (to->vector, from->vector, 6988 xtimes (from->nlines, sizeof (*to->vector))); 6989 to->nlines = from->nlines; 6990 for (ln = 0; ln < to->nlines; ++ln) 6991 ++to->vector[ln]->refcount; 6992 } 6993 6994 6995 6996 /* Free storage associated with linevector. */ 6997 static void 6998 linevector_free (struct linevector *vec) 6999 { 7000 unsigned int ln; 7001 7002 if (vec->vector != NULL) 7003 { 7004 for (ln = 0; ln < vec->nlines; ++ln) 7005 if (--vec->vector[ln]->refcount == 0) 7006 free (vec->vector[ln]); 7007 7008 free (vec->vector); 7009 } 7010 } 7011 7012 7013 7014 /* Given a textual string giving the month (1-12), terminated with any 7015 character not recognized by atoi, return the 3 character name to 7016 print it with. I do not think it is a good idea to change these 7017 strings based on the locale; they are standard abbreviations (for 7018 example in rfc822 mail messages) which should be widely understood. 7019 Returns a pointer into static readonly storage. */ 7020 static const char * 7021 month_printname (const char *month) 7022 { 7023 static const char *const months[] = 7024 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 7025 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 7026 int mnum; 7027 7028 mnum = atoi (month); 7029 if (mnum < 1 || mnum > 12) 7030 return "???"; 7031 return months[mnum - 1]; 7032 } 7033 7034 7035 7036 /* Apply changes to the line vector LINES. DIFFBUF is a buffer of 7037 length DIFFLEN holding the change text from an RCS file (the output 7038 of diff -n). NAME is used in error messages. The VERS field of 7039 any line added is set to ADDVERS. The VERS field of any line 7040 deleted is set to DELVERS, unless DELVERS is NULL, in which case 7041 the VERS field of deleted lines is unchanged. The function returns 7042 non-zero if the change text is applied successfully. It returns 7043 zero if the change text does not appear to apply to LINES (e.g., a 7044 line number is invalid). If the change text is improperly 7045 formatted (e.g., it is not the output of diff -n), the function 7046 calls error with a status of 1, causing the program to exit. */ 7047 static int 7048 apply_rcs_changes (struct linevector *lines, const char *diffbuf, 7049 size_t difflen, const char *name, RCSVers *addvers, 7050 RCSVers *delvers) 7051 { 7052 const char *p; 7053 const char *q; 7054 int op; 7055 /* The RCS format throws us for a loop in that the deltafrags (if 7056 we define a deltafrag as an add or a delete) need to be applied 7057 in reverse order. So we stick them into a linked list. */ 7058 struct deltafrag { 7059 enum {FRAG_ADD, FRAG_DELETE} type; 7060 unsigned long pos; 7061 unsigned long nlines; 7062 const char *new_lines; 7063 size_t len; 7064 struct deltafrag *next; 7065 }; 7066 struct deltafrag *dfhead; 7067 struct deltafrag *df; 7068 int err; 7069 7070 dfhead = NULL; 7071 for (p = diffbuf; p != NULL && p < diffbuf + difflen; ) 7072 { 7073 op = *p++; 7074 if (op != 'a' && op != 'd') 7075 /* Can't just skip over the deltafrag, because the value 7076 of op determines the syntax. */ 7077 error (1, 0, "unrecognized operation '\\x%x' in %s", 7078 op, name); 7079 df = xmalloc (sizeof (struct deltafrag)); 7080 df->next = dfhead; 7081 dfhead = df; 7082 df->pos = strtoul (p, (char **) &q, 10); 7083 7084 if (p == q) 7085 error (1, 0, "number expected in %s", name); 7086 p = q; 7087 if (*p++ != ' ') 7088 error (1, 0, "space expected in %s", name); 7089 df->nlines = strtoul (p, (char **) &q, 10); 7090 if (p == q) 7091 error (1, 0, "number expected in %s", name); 7092 p = q; 7093 if (*p++ != '\012') 7094 error (1, 0, "linefeed expected in %s", name); 7095 7096 if (op == 'a') 7097 { 7098 unsigned int i; 7099 7100 df->type = FRAG_ADD; 7101 i = df->nlines; 7102 /* The text we want is the number of lines specified, or 7103 until the end of the value, whichever comes first (it 7104 will be the former except in the case where we are 7105 adding a line which does not end in newline). */ 7106 for (q = p; i != 0; ++q) 7107 if (*q == '\n') 7108 --i; 7109 else if (q == diffbuf + difflen) 7110 { 7111 if (i != 1) 7112 error (1, 0, "premature end of change in %s", name); 7113 else 7114 break; 7115 } 7116 7117 /* Stash away a pointer to the text we are adding. */ 7118 df->new_lines = p; 7119 df->len = q - p; 7120 7121 p = q; 7122 } 7123 else 7124 { 7125 /* Correct for the fact that line numbers in RCS files 7126 start with 1. */ 7127 --df->pos; 7128 7129 assert (op == 'd'); 7130 df->type = FRAG_DELETE; 7131 } 7132 } 7133 7134 err = 0; 7135 for (df = dfhead; df != NULL;) 7136 { 7137 unsigned int ln; 7138 7139 /* Once an error is encountered, just free the rest of the list and 7140 * return. 7141 */ 7142 if (!err) 7143 switch (df->type) 7144 { 7145 case FRAG_ADD: 7146 if (! linevector_add (lines, df->new_lines, df->len, addvers, 7147 df->pos)) 7148 err = 1; 7149 break; 7150 case FRAG_DELETE: 7151 if (df->pos > lines->nlines 7152 || df->pos + df->nlines > lines->nlines) 7153 return 0; 7154 if (delvers != NULL) 7155 for (ln = df->pos; ln < df->pos + df->nlines; ++ln) 7156 lines->vector[ln]->vers = delvers; 7157 linevector_delete (lines, df->pos, df->nlines); 7158 break; 7159 } 7160 7161 df = df->next; 7162 free (dfhead); 7163 dfhead = df; 7164 } 7165 7166 return !err; 7167 } 7168 7169 7170 7171 /* Apply an RCS change text to a buffer. The function name starts 7172 with rcs rather than RCS because this does not take an RCSNode 7173 argument. NAME is used in error messages. TEXTBUF is the text 7174 buffer to change, and TEXTLEN is the size. DIFFBUF and DIFFLEN are 7175 the change buffer and size. The new buffer is returned in *RETBUF 7176 and *RETLEN. The new buffer is allocated by xmalloc. 7177 7178 Return 1 for success. On failure, call error and return 0. */ 7179 int 7180 rcs_change_text (const char *name, char *textbuf, size_t textlen, 7181 const char *diffbuf, size_t difflen, char **retbuf, 7182 size_t *retlen) 7183 { 7184 struct linevector lines; 7185 int ret; 7186 7187 *retbuf = NULL; 7188 *retlen = 0; 7189 7190 linevector_init (&lines); 7191 7192 if (! linevector_add (&lines, textbuf, textlen, NULL, 0)) 7193 error (1, 0, "cannot initialize line vector"); 7194 7195 if (! apply_rcs_changes (&lines, diffbuf, difflen, name, NULL, NULL)) 7196 { 7197 error (0, 0, "invalid change text in %s", name); 7198 ret = 0; 7199 } 7200 else 7201 { 7202 char *p; 7203 size_t n; 7204 unsigned int ln; 7205 7206 n = 0; 7207 for (ln = 0; ln < lines.nlines; ++ln) 7208 /* 1 for \n */ 7209 n += lines.vector[ln]->len + 1; 7210 7211 p = xmalloc (n); 7212 *retbuf = p; 7213 7214 for (ln = 0; ln < lines.nlines; ++ln) 7215 { 7216 memcpy (p, lines.vector[ln]->text, lines.vector[ln]->len); 7217 p += lines.vector[ln]->len; 7218 if (lines.vector[ln]->has_newline) 7219 *p++ = '\n'; 7220 } 7221 7222 *retlen = p - *retbuf; 7223 assert (*retlen <= n); 7224 7225 ret = 1; 7226 } 7227 7228 linevector_free (&lines); 7229 7230 return ret; 7231 } 7232 7233 7234 7235 /* Walk the deltas in RCS to get to revision VERSION. 7236 7237 If OP is RCS_ANNOTATE, then write annotations using cvs_output. 7238 7239 If OP is RCS_FETCH, then put the contents of VERSION into a 7240 newly-malloc'd array and put a pointer to it in *TEXT. Each line 7241 is \n terminated; the caller is responsible for converting text 7242 files if desired. The total length is put in *LEN. 7243 7244 If FP is non-NULL, it should be a file descriptor open to the file 7245 RCS with file position pointing to the deltas. We close the file 7246 when we are done. 7247 7248 If LOG is non-NULL, then *LOG is set to the log message of VERSION, 7249 and *LOGLEN is set to the length of the log message. 7250 7251 On error, give a fatal error. */ 7252 void 7253 RCS_deltas (RCSNode *rcs, FILE *fp, struct rcsbuffer *rcsbuf, 7254 const char *version, enum rcs_delta_op op, char **text, 7255 size_t *len, char **log, size_t *loglen) 7256 { 7257 struct rcsbuffer rcsbuf_local; 7258 char *branchversion; 7259 char *cpversion; 7260 char *key; 7261 char *value; 7262 size_t vallen; 7263 RCSVers *vers; 7264 RCSVers *prev_vers; 7265 RCSVers *trunk_vers; 7266 char *next; 7267 int ishead, isnext, isversion, onbranch; 7268 Node *node; 7269 struct linevector headlines; 7270 struct linevector curlines; 7271 struct linevector trunklines; 7272 int foundhead; 7273 7274 assert (version); 7275 7276 if (fp == NULL) 7277 { 7278 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf_local); 7279 rcsbuf = &rcsbuf_local; 7280 } 7281 7282 if (log) *log = NULL; 7283 7284 ishead = 1; 7285 vers = NULL; 7286 prev_vers = NULL; 7287 trunk_vers = NULL; 7288 next = NULL; 7289 onbranch = 0; 7290 foundhead = 0; 7291 7292 linevector_init (&curlines); 7293 linevector_init (&headlines); 7294 linevector_init (&trunklines); 7295 7296 /* We set BRANCHVERSION to the version we are currently looking 7297 for. Initially, this is the version on the trunk from which 7298 VERSION branches off. If VERSION is not a branch, then 7299 BRANCHVERSION is just VERSION. */ 7300 branchversion = xstrdup (version); 7301 cpversion = strchr (branchversion, '.'); 7302 if (cpversion != NULL) 7303 cpversion = strchr (cpversion + 1, '.'); 7304 if (cpversion != NULL) 7305 *cpversion = '\0'; 7306 7307 do { 7308 if (! rcsbuf_getrevnum (rcsbuf, &key)) 7309 error (1, 0, "unexpected EOF reading RCS file %s", rcs->print_path); 7310 7311 if (next != NULL && ! STREQ (next, key)) 7312 { 7313 /* This is not the next version we need. It is a branch 7314 version which we want to ignore. */ 7315 isnext = 0; 7316 isversion = 0; 7317 } 7318 else 7319 { 7320 isnext = 1; 7321 7322 /* look up the revision */ 7323 node = findnode (rcs->versions, key); 7324 if (node == NULL) 7325 error (1, 0, 7326 "mismatch in rcs file %s between deltas and deltatexts (%s)", 7327 rcs->print_path, key); 7328 7329 /* Stash the previous version. */ 7330 prev_vers = vers; 7331 7332 vers = node->data; 7333 next = vers->next; 7334 7335 /* Compare key and trunkversion now, because key points to 7336 storage controlled by rcsbuf_getkey. */ 7337 if (STREQ (branchversion, key)) 7338 isversion = 1; 7339 else 7340 isversion = 0; 7341 } 7342 7343 while (1) 7344 { 7345 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7346 error (1, 0, "%s does not appear to be a valid rcs file", 7347 rcs->print_path); 7348 7349 if (log != NULL 7350 && isversion 7351 && STREQ (key, "log") 7352 && STREQ (branchversion, version)) 7353 { 7354 if (*log != NULL) 7355 { 7356 error (0, 0, "Duplicate `log' keyword in RCS file (`%s').", 7357 rcs->print_path); 7358 free (*log); 7359 } 7360 *log = rcsbuf_valcopy (rcsbuf, value, 0, loglen); 7361 } 7362 7363 if (STREQ (key, "text")) 7364 { 7365 rcsbuf_valpolish (rcsbuf, value, 0, &vallen); 7366 if (ishead) 7367 { 7368 if (! linevector_add (&curlines, value, vallen, NULL, 0)) 7369 error (1, 0, "invalid rcs file %s", rcs->print_path); 7370 7371 ishead = 0; 7372 } 7373 else if (isnext) 7374 { 7375 if (! apply_rcs_changes (&curlines, value, vallen, 7376 rcs->path, 7377 onbranch ? vers : NULL, 7378 onbranch ? NULL : prev_vers)) 7379 error (1, 0, "invalid change text in %s", rcs->print_path); 7380 } 7381 break; 7382 } 7383 } 7384 7385 if (isversion) 7386 { 7387 /* This is either the version we want, or it is the 7388 branchpoint to the version we want. */ 7389 if (STREQ (branchversion, version)) 7390 { 7391 /* This is the version we want. */ 7392 linevector_copy (&headlines, &curlines); 7393 foundhead = 1; 7394 if (onbranch) 7395 { 7396 /* We have found this version by tracking up a 7397 branch. Restore back to the lines we saved 7398 when we left the trunk, and continue tracking 7399 down the trunk. */ 7400 onbranch = 0; 7401 vers = trunk_vers; 7402 next = vers->next; 7403 linevector_copy (&curlines, &trunklines); 7404 } 7405 } 7406 else 7407 { 7408 Node *p; 7409 7410 /* We need to look up the branch. */ 7411 onbranch = 1; 7412 7413 if (numdots (branchversion) < 2) 7414 { 7415 unsigned int ln; 7416 7417 /* We are leaving the trunk; save the current 7418 lines so that we can restore them when we 7419 continue tracking down the trunk. */ 7420 trunk_vers = vers; 7421 linevector_copy (&trunklines, &curlines); 7422 7423 /* Reset the version information we have 7424 accumulated so far. It only applies to the 7425 changes from the head to this version. */ 7426 for (ln = 0; ln < curlines.nlines; ++ln) 7427 curlines.vector[ln]->vers = NULL; 7428 } 7429 7430 /* The next version we want is the entry on 7431 VERS->branches which matches this branch. For 7432 example, suppose VERSION is 1.21.4.3 and 7433 BRANCHVERSION was 1.21. Then we look for an entry 7434 starting with "1.21.4" and we'll put it (probably 7435 1.21.4.1) in NEXT. We'll advance BRANCHVERSION by 7436 two dots (in this example, to 1.21.4.3). */ 7437 7438 if (vers->branches == NULL) 7439 error (1, 0, "missing expected branches in %s", 7440 rcs->print_path); 7441 if (!cpversion) 7442 error (1, 0, "Invalid revision number in `%s'.", 7443 rcs->print_path); 7444 *cpversion = '.'; 7445 ++cpversion; 7446 cpversion = strchr (cpversion, '.'); 7447 if (cpversion == NULL) 7448 error (1, 0, "version number confusion in %s", 7449 rcs->print_path); 7450 for (p = vers->branches->list->next; 7451 p != vers->branches->list; 7452 p = p->next) 7453 if (strncmp (p->key, branchversion, 7454 cpversion - branchversion) == 0) 7455 break; 7456 if (p == vers->branches->list) 7457 error (1, 0, "missing expected branch in %s", 7458 rcs->print_path); 7459 7460 next = p->key; 7461 7462 cpversion = strchr (cpversion + 1, '.'); 7463 if (cpversion != NULL) 7464 *cpversion = '\0'; 7465 } 7466 } 7467 if (op == RCS_FETCH && foundhead) 7468 break; 7469 } while (next != NULL); 7470 7471 free (branchversion); 7472 7473 rcsbuf_cache (rcs, rcsbuf); 7474 7475 if (! foundhead) 7476 error (1, 0, "could not find desired version %s in %s", 7477 version, rcs->print_path); 7478 7479 /* Now print out or return the data we have just computed. */ 7480 switch (op) 7481 { 7482 case RCS_ANNOTATE: 7483 { 7484 unsigned int ln; 7485 7486 for (ln = 0; ln < headlines.nlines; ++ln) 7487 { 7488 char *buf; 7489 /* Period which separates year from month in date. */ 7490 char *ym; 7491 /* Period which separates month from day in date. */ 7492 char *md; 7493 RCSVers *prvers; 7494 7495 prvers = headlines.vector[ln]->vers; 7496 if (prvers == NULL) 7497 prvers = vers; 7498 7499 buf = xmalloc (strlen (prvers->version) + 24); 7500 sprintf (buf, "%-12s (%-8.8s ", 7501 prvers->version, 7502 prvers->author); 7503 cvs_output (buf, 0); 7504 free (buf); 7505 7506 /* Now output the date. */ 7507 ym = strchr (prvers->date, '.'); 7508 if (ym == NULL) 7509 { 7510 cvs_output ("??", 0); 7511 cvs_output ("-???", 0); 7512 cvs_output ("-??", 0); 7513 } 7514 else 7515 { 7516 md = strchr (ym + 1, '.'); 7517 if (md == NULL) 7518 cvs_output ("??", 0); 7519 else 7520 cvs_output (md + 1, 2); 7521 7522 cvs_output ("-", 1); 7523 cvs_output (month_printname (ym + 1), 0); 7524 cvs_output ("-", 1); 7525 /* Only output the last two digits of the year. Our output 7526 lines are long enough as it is without printing the 7527 century. */ 7528 cvs_output (ym - 2, 2); 7529 } 7530 cvs_output ("): ", 0); 7531 if (headlines.vector[ln]->len != 0) 7532 cvs_output (headlines.vector[ln]->text, 7533 headlines.vector[ln]->len); 7534 cvs_output ("\n", 1); 7535 } 7536 } 7537 break; 7538 case RCS_FETCH: 7539 { 7540 char *p; 7541 size_t n; 7542 unsigned int ln; 7543 7544 assert (text != NULL); 7545 assert (len != NULL); 7546 7547 n = 0; 7548 for (ln = 0; ln < headlines.nlines; ++ln) 7549 /* 1 for \n */ 7550 n += headlines.vector[ln]->len + 1; 7551 p = xmalloc (n); 7552 *text = p; 7553 for (ln = 0; ln < headlines.nlines; ++ln) 7554 { 7555 memcpy (p, headlines.vector[ln]->text, 7556 headlines.vector[ln]->len); 7557 p += headlines.vector[ln]->len; 7558 if (headlines.vector[ln]->has_newline) 7559 *p++ = '\n'; 7560 } 7561 *len = p - *text; 7562 assert (*len <= n); 7563 } 7564 break; 7565 } 7566 7567 linevector_free (&curlines); 7568 linevector_free (&headlines); 7569 linevector_free (&trunklines); 7570 7571 return; 7572 } 7573 7574 7575 7576 /* Read the information for a single delta from the RCS buffer RCSBUF, 7577 whose name is RCSFILE. *KEYP and *VALP are either NULL, or the 7578 first key/value pair to read, as set by rcsbuf_getkey. Return NULL 7579 if there are no more deltas. Store the key/value pair which 7580 terminated the read in *KEYP and *VALP. */ 7581 static RCSVers * 7582 getdelta (struct rcsbuffer *rcsbuf, char *rcsfile, char **keyp, char **valp) 7583 { 7584 RCSVers *vnode; 7585 char *key, *value, *cp; 7586 Node *kv; 7587 7588 /* Get revision number if it wasn't passed in. This uses 7589 rcsbuf_getkey because it doesn't croak when encountering 7590 unexpected input. As a result, we have to play unholy games 7591 with `key' and `value'. */ 7592 if (*keyp != NULL) 7593 { 7594 key = *keyp; 7595 value = *valp; 7596 } 7597 else 7598 { 7599 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7600 error (1, 0, "%s: unexpected EOF", rcsfile); 7601 } 7602 7603 /* Make sure that it is a revision number and not a cabbage 7604 or something. */ 7605 for (cp = key; 7606 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0'; 7607 cp++) 7608 /* do nothing */ ; 7609 /* Note that when comparing with RCSDATE, we are not massaging 7610 VALUE from the string found in the RCS file. This is OK since 7611 we know exactly what to expect. */ 7612 if (*cp != '\0' || strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) != 0) 7613 { 7614 *keyp = key; 7615 *valp = value; 7616 return NULL; 7617 } 7618 7619 vnode = xmalloc (sizeof (RCSVers)); 7620 memset (vnode, 0, sizeof (RCSVers)); 7621 7622 vnode->version = xstrdup (key); 7623 7624 /* Grab the value of the date from value. Note that we are not 7625 massaging VALUE from the string found in the RCS file. */ 7626 cp = value + (sizeof RCSDATE) - 1; /* skip the "date" keyword */ 7627 while (whitespace (*cp)) /* take space off front of value */ 7628 cp++; 7629 7630 vnode->date = xstrdup (cp); 7631 7632 /* Get author field. */ 7633 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7634 { 7635 error (1, 0, "unexpected end of file reading %s", rcsfile); 7636 } 7637 if (! STREQ (key, "author")) 7638 error (1, 0, "\ 7639 unable to parse %s; `author' not in the expected place", rcsfile); 7640 vnode->author = rcsbuf_valcopy (rcsbuf, value, 0, NULL); 7641 7642 /* Get state field. */ 7643 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7644 { 7645 error (1, 0, "unexpected end of file reading %s", rcsfile); 7646 } 7647 if (! STREQ (key, "state")) 7648 error (1, 0, "\ 7649 unable to parse %s; `state' not in the expected place", rcsfile); 7650 vnode->state = rcsbuf_valcopy (rcsbuf, value, 0, NULL); 7651 /* The value is optional, according to rcsfile(5). */ 7652 if (value != NULL && STREQ (value, RCSDEAD)) 7653 { 7654 vnode->dead = 1; 7655 } 7656 7657 /* Note that "branches" and "next" are in fact mandatory, according 7658 to doc/RCSFILES. */ 7659 7660 /* fill in the branch list (if any branches exist) */ 7661 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7662 { 7663 error (1, 0, "unexpected end of file reading %s", rcsfile); 7664 } 7665 if (STREQ (key, RCSDESC)) 7666 { 7667 *keyp = key; 7668 *valp = value; 7669 /* Probably could/should be a fatal error. */ 7670 error (0, 0, "warning: 'branches' keyword missing from %s", rcsfile); 7671 return vnode; 7672 } 7673 if (value != NULL) 7674 { 7675 vnode->branches = getlist (); 7676 /* Note that we are not massaging VALUE from the string found 7677 in the RCS file. */ 7678 do_branches (vnode->branches, value); 7679 } 7680 7681 /* fill in the next field if there is a next revision */ 7682 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7683 { 7684 error (1, 0, "unexpected end of file reading %s", rcsfile); 7685 } 7686 if (STREQ (key, RCSDESC)) 7687 { 7688 *keyp = key; 7689 *valp = value; 7690 /* Probably could/should be a fatal error. */ 7691 error (0, 0, "warning: 'next' keyword missing from %s", rcsfile); 7692 return vnode; 7693 } 7694 if (value != NULL) 7695 vnode->next = rcsbuf_valcopy (rcsbuf, value, 0, NULL); 7696 7697 /* 7698 * XXX - this is where we put the symbolic link stuff??? 7699 * (into newphrases in the deltas). 7700 */ 7701 while (1) 7702 { 7703 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7704 error (1, 0, "unexpected end of file reading %s", rcsfile); 7705 7706 /* The `desc' keyword is the end of the deltas. */ 7707 if (strcmp (key, RCSDESC) == 0) 7708 break; 7709 7710 #ifdef PRESERVE_PERMISSIONS_SUPPORT 7711 7712 /* The `hardlinks' value is a group of words, which must 7713 be parsed separately and added as a list to vnode->hardlinks. */ 7714 if (strcmp (key, "hardlinks") == 0) 7715 { 7716 char *word; 7717 7718 vnode->hardlinks = getlist(); 7719 while ((word = rcsbuf_valword (rcsbuf, &value)) != NULL) 7720 { 7721 Node *n = getnode(); 7722 n->key = word; 7723 addnode (vnode->hardlinks, n); 7724 } 7725 continue; 7726 } 7727 #endif 7728 7729 /* Enable use of repositories created by certain obsolete 7730 versions of CVS. This code should remain indefinately; 7731 there is no procedure for converting old repositories, and 7732 checking for it is harmless. */ 7733 if (STREQ (key, RCSDEAD)) 7734 { 7735 vnode->dead = 1; 7736 if (vnode->state != NULL) 7737 free (vnode->state); 7738 vnode->state = xstrdup (RCSDEAD); 7739 continue; 7740 } 7741 /* if we have a new revision number, we're done with this delta */ 7742 for (cp = key; 7743 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0'; 7744 cp++) 7745 /* do nothing */ ; 7746 /* Note that when comparing with RCSDATE, we are not massaging 7747 VALUE from the string found in the RCS file. This is OK 7748 since we know exactly what to expect. */ 7749 if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0) 7750 break; 7751 7752 /* At this point, key and value represent a user-defined field 7753 in the delta node. */ 7754 if (vnode->other_delta == NULL) 7755 vnode->other_delta = getlist (); 7756 kv = getnode (); 7757 kv->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD; 7758 kv->key = xstrdup (key); 7759 kv->data = rcsbuf_valcopy (rcsbuf, value, kv->type == RCSFIELD, NULL); 7760 if (addnode (vnode->other_delta, kv) != 0) 7761 { 7762 /* Complaining about duplicate keys in newphrases seems 7763 questionable, in that we don't know what they mean and 7764 doc/RCSFILES has no prohibition on several newphrases 7765 with the same key. But we can't store more than one as 7766 long as we store them in a List *. */ 7767 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'", 7768 key, rcsfile); 7769 freenode (kv); 7770 } 7771 } 7772 7773 /* Return the key which caused us to fail back to the caller. */ 7774 *keyp = key; 7775 *valp = value; 7776 7777 return vnode; 7778 } 7779 7780 7781 7782 static void 7783 freedeltatext (Deltatext *d) 7784 { 7785 if (d->version != NULL) 7786 free (d->version); 7787 if (d->log != NULL) 7788 free (d->log); 7789 if (d->text != NULL) 7790 free (d->text); 7791 if (d->other != NULL) 7792 dellist (&d->other); 7793 free (d); 7794 } 7795 7796 static Deltatext * 7797 RCS_getdeltatext (RCSNode *rcs, FILE *fp, struct rcsbuffer *rcsbuf) 7798 { 7799 char *num; 7800 char *key, *value; 7801 Node *p; 7802 Deltatext *d; 7803 7804 /* Get the revision number. */ 7805 if (! rcsbuf_getrevnum (rcsbuf, &num)) 7806 { 7807 /* If num == NULL, it means we reached EOF naturally. That's 7808 fine. */ 7809 if (num == NULL) 7810 return NULL; 7811 else 7812 error (1, 0, "%s: unexpected EOF", rcs->print_path); 7813 } 7814 7815 p = findnode (rcs->versions, num); 7816 if (p == NULL) 7817 error (1, 0, "mismatch in rcs file %s between deltas and deltatexts (%s)", 7818 rcs->print_path, num); 7819 7820 d = xmalloc (sizeof (Deltatext)); 7821 d->version = xstrdup (num); 7822 7823 /* Get the log message. */ 7824 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7825 error (1, 0, "%s, delta %s: unexpected EOF", rcs->print_path, num); 7826 if (! STREQ (key, "log")) 7827 error (1, 0, "%s, delta %s: expected `log', got `%s'", 7828 rcs->print_path, num, key); 7829 d->log = rcsbuf_valcopy (rcsbuf, value, 0, NULL); 7830 7831 /* Get random newphrases. */ 7832 d->other = getlist(); 7833 while (1) 7834 { 7835 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7836 error (1, 0, "%s, delta %s: unexpected EOF", rcs->print_path, num); 7837 7838 if (STREQ (key, "text")) 7839 break; 7840 7841 p = getnode(); 7842 p->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD; 7843 p->key = xstrdup (key); 7844 p->data = rcsbuf_valcopy (rcsbuf, value, p->type == RCSFIELD, NULL); 7845 if (addnode (d->other, p) < 0) 7846 { 7847 error (0, 0, "warning: %s, delta %s: duplicate field `%s'", 7848 rcs->print_path, num, key); 7849 } 7850 } 7851 7852 /* Get the change text. We already know that this key is `text'. */ 7853 d->text = rcsbuf_valcopy (rcsbuf, value, 0, &d->len); 7854 7855 return d; 7856 } 7857 7858 7859 7860 /* RCS output functions, for writing RCS format files from RCSNode 7861 structures. 7862 7863 For most of this work, RCS 5.7 uses an `aprintf' function which aborts 7864 program upon error. Instead, these functions check the output status 7865 of the stream right before closing it, and aborts if an error condition 7866 is found. The RCS solution is probably the better one: it produces 7867 more overhead, but will produce a clearer diagnostic in the case of 7868 catastrophic error. In either case, however, the repository will probably 7869 not get corrupted. */ 7870 static int 7871 putsymbol_proc (Node *symnode, void *fparg) 7872 { 7873 FILE *fp = fparg; 7874 7875 /* A fiddly optimization: this code used to just call fprintf, but 7876 in an old repository with hundreds of tags this can get called 7877 hundreds of thousands of times when doing a cvs tag. Since 7878 tagging is a relatively common operation, and using putc and 7879 fputs is just as comprehensible, the change is worthwhile. */ 7880 putc ('\n', fp); 7881 putc ('\t', fp); 7882 fputs (symnode->key, fp); 7883 putc (':', fp); 7884 fputs (symnode->data, fp); 7885 return 0; 7886 } 7887 7888 7889 7890 /* putlock_proc is like putsymbol_proc, but key and data are reversed. */ 7891 static int 7892 putlock_proc (Node *symnode, void *fp) 7893 { 7894 return fprintf (fp, "\n\t%s:%s", (char *)symnode->data, symnode->key); 7895 } 7896 7897 7898 7899 static int 7900 putrcsfield_proc (Node *node, void *vfp) 7901 { 7902 FILE *fp = vfp; 7903 7904 /* Some magic keys used internally by CVS start with `;'. Skip them. */ 7905 if (node->key[0] == ';') 7906 return 0; 7907 7908 fprintf (fp, "\n%s\t", node->key); 7909 if (node->data != NULL) 7910 { 7911 /* If the field's value contains evil characters, 7912 it must be stringified. */ 7913 /* FIXME: This does not quite get it right. "7jk8f" is not a valid 7914 value for a value in a newpharse, according to doc/RCSFILES, 7915 because digits are not valid in an "id". We might do OK by 7916 always writing strings (enclosed in @@). Would be nice to 7917 explicitly mention this one way or another in doc/RCSFILES. 7918 A case where we are wrong in a much more clear-cut way is that 7919 we let through non-graphic characters such as whitespace and 7920 control characters. */ 7921 7922 if (node->type == RCSCMPFLD || strpbrk (node->data, "$,.:;@") == NULL) 7923 fputs (node->data, fp); 7924 else 7925 { 7926 putc ('@', fp); 7927 expand_at_signs (node->data, (off_t) strlen (node->data), fp); 7928 putc ('@', fp); 7929 } 7930 } 7931 7932 /* desc, log and text fields should not be terminated with semicolon; 7933 all other fields should be. */ 7934 if (! STREQ (node->key, "desc") && 7935 ! STREQ (node->key, "log") && 7936 ! STREQ (node->key, "text")) 7937 { 7938 putc (';', fp); 7939 } 7940 return 0; 7941 } 7942 7943 7944 7945 #ifdef PRESERVE_PERMISSIONS_SUPPORT 7946 7947 /* Save a filename in a `hardlinks' RCS field. NODE->KEY will contain 7948 a full pathname, but currently only basenames are stored in the RCS 7949 node. Assume that the filename includes nasty characters and 7950 @-escape it. */ 7951 7952 static int 7953 puthardlink_proc (node, vfp) 7954 Node *node; 7955 void *vfp; 7956 { 7957 FILE *fp = vfp; 7958 char *basename = strrchr (node->key, '/'); 7959 7960 if (basename == NULL) 7961 basename = node->key; 7962 else 7963 ++basename; 7964 7965 putc ('\t', fp); 7966 putc ('@', fp); 7967 (void) expand_at_signs (basename, strlen (basename), fp); 7968 putc ('@', fp); 7969 7970 return 0; 7971 } 7972 7973 #endif /* PRESERVE_PERMISSIONS_SUPPORT */ 7974 7975 7976 7977 /* Output the admin node for RCS into stream FP. */ 7978 static void 7979 RCS_putadmin (RCSNode *rcs, FILE *fp) 7980 { 7981 fprintf (fp, "%s\t%s;\n", RCSHEAD, rcs->head ? rcs->head : ""); 7982 if (rcs->branch) 7983 fprintf (fp, "%s\t%s;\n", RCSBRANCH, rcs->branch); 7984 7985 fputs ("access", fp); 7986 if (rcs->access) 7987 { 7988 char *p, *s; 7989 s = xstrdup (rcs->access); 7990 for (p = strtok (s, " \n\t"); p != NULL; p = strtok (NULL, " \n\t")) 7991 fprintf (fp, "\n\t%s", p); 7992 free (s); 7993 } 7994 fputs (";\n", fp); 7995 7996 fputs (RCSSYMBOLS, fp); 7997 /* If we haven't had to convert the symbols to a list yet, don't 7998 force a conversion now; just write out the string. */ 7999 if (rcs->symbols == NULL && rcs->symbols_data != NULL) 8000 { 8001 fputs ("\n\t", fp); 8002 fputs (rcs->symbols_data, fp); 8003 } 8004 else 8005 walklist (RCS_symbols (rcs), putsymbol_proc, fp); 8006 fputs (";\n", fp); 8007 8008 fputs ("locks", fp); 8009 if (rcs->locks_data) 8010 fprintf (fp, "\t%s", rcs->locks_data); 8011 else if (rcs->locks) 8012 walklist (rcs->locks, putlock_proc, fp); 8013 if (rcs->strict_locks) 8014 fprintf (fp, "; strict"); 8015 fputs (";\n", fp); 8016 8017 if (rcs->comment) 8018 { 8019 fprintf (fp, "comment\t@"); 8020 expand_at_signs (rcs->comment, (off_t) strlen (rcs->comment), fp); 8021 fputs ("@;\n", fp); 8022 } 8023 if (rcs->expand && ! STREQ (rcs->expand, "kv")) 8024 fprintf (fp, "%s\t@%s@;\n", RCSEXPAND, rcs->expand); 8025 8026 walklist (rcs->other, putrcsfield_proc, fp); 8027 8028 putc ('\n', fp); 8029 } 8030 8031 8032 8033 static void 8034 putdelta (RCSVers *vers, FILE *fp) 8035 { 8036 Node *bp, *start; 8037 8038 /* Skip if no revision was supplied, or if it is outdated (cvs admin -o) */ 8039 if (vers == NULL || vers->outdated) 8040 return; 8041 8042 fprintf (fp, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches", 8043 vers->version, 8044 RCSDATE, vers->date, 8045 "author", vers->author, 8046 "state", vers->state ? vers->state : ""); 8047 8048 if (vers->branches != NULL) 8049 { 8050 start = vers->branches->list; 8051 for (bp = start->next; bp != start; bp = bp->next) 8052 fprintf (fp, "\n\t%s", bp->key); 8053 } 8054 8055 fprintf (fp, ";\nnext\t%s;", vers->next ? vers->next : ""); 8056 8057 walklist (vers->other_delta, putrcsfield_proc, fp); 8058 8059 #ifdef PRESERVE_PERMISSIONS_SUPPORT 8060 if (vers->hardlinks) 8061 { 8062 fprintf (fp, "\nhardlinks"); 8063 walklist (vers->hardlinks, puthardlink_proc, fp); 8064 putc (';', fp); 8065 } 8066 #endif 8067 putc ('\n', fp); 8068 } 8069 8070 8071 8072 static void 8073 RCS_putdtree (RCSNode *rcs, char *rev, FILE *fp) 8074 { 8075 RCSVers *versp; 8076 Node *p, *branch; 8077 8078 /* Previously, this function used a recursive implementation, but 8079 if the trunk has a huge number of revisions and the program 8080 stack is not big, a stack overflow could occur, so this 8081 nonrecursive version was developed to be more safe. */ 8082 Node *branchlist, *onebranch; 8083 List *branches; 8084 List *onebranchlist; 8085 8086 if (rev == NULL) 8087 return; 8088 8089 branches = getlist(); 8090 8091 for (; rev != NULL;) 8092 { 8093 /* Find the delta node for this revision. */ 8094 p = findnode (rcs->versions, rev); 8095 if (p == NULL) 8096 { 8097 error (1, 0, 8098 "error parsing repository file %s, file may be corrupt.", 8099 rcs->path); 8100 } 8101 8102 versp = p->data; 8103 8104 /* Print the delta node and go for its `next' node. This 8105 prints the trunk. If there are any branches printed on this 8106 revision, mark we have some. */ 8107 putdelta (versp, fp); 8108 /* Store branch information into branch list so to write its 8109 trunk afterwards */ 8110 if (versp->branches != NULL) 8111 { 8112 branch = getnode(); 8113 branch->data = versp->branches; 8114 8115 addnode(branches, branch); 8116 } 8117 8118 rev = versp->next; 8119 } 8120 8121 /* If there are any branches printed on this revision, 8122 print those trunks as well. */ 8123 branchlist = branches->list; 8124 for (branch = branchlist->next; 8125 branch != branchlist; 8126 branch = branch->next) 8127 { 8128 onebranchlist = (List *)(branch->data); 8129 onebranch = onebranchlist->list; 8130 for (p = onebranch->next; p != onebranch; p = p->next) 8131 RCS_putdtree (rcs, p->key, fp); 8132 8133 branch->data = NULL; /* so to prevent its freeing on dellist */ 8134 } 8135 8136 dellist(&branches); 8137 } 8138 8139 8140 8141 static void 8142 RCS_putdesc (RCSNode *rcs, FILE *fp) 8143 { 8144 fprintf (fp, "\n\n%s\n@", RCSDESC); 8145 if (rcs->desc != NULL) 8146 { 8147 off_t len = (off_t) strlen (rcs->desc); 8148 if (len > 0) 8149 { 8150 expand_at_signs (rcs->desc, len, fp); 8151 if (rcs->desc[len-1] != '\n') 8152 putc ('\n', fp); 8153 } 8154 } 8155 fputs ("@\n", fp); 8156 } 8157 8158 8159 8160 static void 8161 putdeltatext (FILE *fp, Deltatext *d) 8162 { 8163 fprintf (fp, "\n\n%s\nlog\n@", d->version); 8164 if (d->log != NULL) 8165 { 8166 int loglen = strlen (d->log); 8167 expand_at_signs (d->log, (off_t) loglen, fp); 8168 if (d->log[loglen-1] != '\n') 8169 putc ('\n', fp); 8170 } 8171 putc ('@', fp); 8172 8173 walklist (d->other, putrcsfield_proc, fp); 8174 8175 fputs ("\ntext\n@", fp); 8176 if (d->text != NULL) 8177 expand_at_signs (d->text, (off_t) d->len, fp); 8178 fputs ("@\n", fp); 8179 } 8180 8181 8182 8183 /* TODO: the whole mechanism for updating deltas is kludgey... more 8184 sensible would be to supply all the necessary info in a `newdeltatext' 8185 field for RCSVers nodes. -twp */ 8186 8187 /* Copy delta text nodes from FIN to FOUT. If NEWDTEXT is non-NULL, it 8188 is a new delta text node, and should be added to the tree at the 8189 node whose revision number is INSERTPT. (Note that trunk nodes are 8190 written in decreasing order, and branch nodes are written in 8191 increasing order.) */ 8192 static void 8193 RCS_copydeltas (RCSNode *rcs, FILE *fin, struct rcsbuffer *rcsbufin, 8194 FILE *fout, Deltatext *newdtext, char *insertpt) 8195 { 8196 int actions; 8197 RCSVers *dadmin; 8198 Node *np; 8199 int insertbefore, found; 8200 char *bufrest; 8201 int nls; 8202 size_t buflen; 8203 #ifndef HAVE_MMAP 8204 char buf[8192]; 8205 int got; 8206 #endif 8207 8208 /* Count the number of versions for which we have to do some 8209 special operation. */ 8210 actions = walklist (rcs->versions, count_delta_actions, NULL); 8211 8212 /* Make a note of whether NEWDTEXT should be inserted 8213 before or after its INSERTPT. */ 8214 insertbefore = (newdtext != NULL && numdots (newdtext->version) == 1); 8215 8216 while (actions != 0 || newdtext != NULL) 8217 { 8218 Deltatext *dtext; 8219 8220 dtext = RCS_getdeltatext (rcs, fin, rcsbufin); 8221 8222 /* We shouldn't hit EOF here, because that would imply that 8223 some action was not taken, or that we could not insert 8224 NEWDTEXT. */ 8225 if (dtext == NULL) 8226 error (1, 0, "internal error: EOF too early in RCS_copydeltas"); 8227 8228 found = (insertpt != NULL && STREQ (dtext->version, insertpt)); 8229 if (found && insertbefore) 8230 { 8231 putdeltatext (fout, newdtext); 8232 newdtext = NULL; 8233 insertpt = NULL; 8234 } 8235 8236 np = findnode (rcs->versions, dtext->version); 8237 dadmin = np->data; 8238 8239 /* If this revision has been outdated, just skip it. */ 8240 if (dadmin->outdated) 8241 { 8242 freedeltatext (dtext); 8243 --actions; 8244 continue; 8245 } 8246 8247 /* Update the change text for this delta. New change text 8248 data may come from cvs admin -m, cvs admin -o, or cvs ci. */ 8249 if (dadmin->text != NULL) 8250 { 8251 if (dadmin->text->log != NULL || dadmin->text->text != NULL) 8252 --actions; 8253 if (dadmin->text->log != NULL) 8254 { 8255 free (dtext->log); 8256 dtext->log = dadmin->text->log; 8257 dadmin->text->log = NULL; 8258 } 8259 if (dadmin->text->text != NULL) 8260 { 8261 free (dtext->text); 8262 dtext->text = dadmin->text->text; 8263 dtext->len = dadmin->text->len; 8264 dadmin->text->text = NULL; 8265 } 8266 } 8267 putdeltatext (fout, dtext); 8268 freedeltatext (dtext); 8269 8270 if (found && !insertbefore) 8271 { 8272 putdeltatext (fout, newdtext); 8273 newdtext = NULL; 8274 insertpt = NULL; 8275 } 8276 } 8277 8278 /* Copy the rest of the file directly, without bothering to 8279 interpret it. The caller will handle error checking by calling 8280 ferror. 8281 8282 We just wrote a newline to the file, either in putdeltatext or 8283 in the caller. However, we may not have read the corresponding 8284 newline from the file, because rcsbuf_getkey returns as soon as 8285 it finds the end of the '@' string for the desc or text key. 8286 Therefore, we may read three newlines when we should really 8287 only write two, and we check for that case here. This is not 8288 an semantically important issue; we only do it to make our RCS 8289 files look traditional. */ 8290 8291 nls = 3; 8292 8293 rcsbuf_get_buffered (rcsbufin, &bufrest, &buflen); 8294 if (buflen > 0) 8295 { 8296 if (bufrest[0] != '\n' 8297 || strncmp (bufrest, "\n\n\n", buflen < 3 ? buflen : 3) != 0) 8298 { 8299 nls = 0; 8300 } 8301 else 8302 { 8303 if (buflen < 3) 8304 nls -= buflen; 8305 else 8306 { 8307 ++bufrest; 8308 --buflen; 8309 nls = 0; 8310 } 8311 } 8312 8313 fwrite (bufrest, 1, buflen, fout); 8314 } 8315 #ifndef HAVE_MMAP 8316 /* This bit isn't necessary when using mmap since the entire file 8317 * will already be available via the RCS buffer. Besides, the 8318 * mmap code doesn't always keep the file pointer up to date, so 8319 * this adds some data twice. 8320 */ 8321 while ((got = fread (buf, 1, sizeof buf, fin)) != 0) 8322 { 8323 if (nls > 0 8324 && got >= nls 8325 && buf[0] == '\n' 8326 && strncmp (buf, "\n\n\n", nls) == 0) 8327 { 8328 fwrite (buf + 1, 1, got - 1, fout); 8329 } 8330 else 8331 { 8332 fwrite (buf, 1, got, fout); 8333 } 8334 8335 nls = 0; 8336 } 8337 #endif /* HAVE_MMAP */ 8338 } 8339 8340 8341 8342 /* A helper procedure for RCS_copydeltas. This is called via walklist 8343 to count the number of RCS revisions for which some special action 8344 is required. */ 8345 static int 8346 count_delta_actions (Node *np, void *ignore) 8347 { 8348 RCSVers *dadmin = np->data; 8349 8350 if (dadmin->outdated) 8351 return 1; 8352 8353 if (dadmin->text != NULL 8354 && (dadmin->text->log != NULL || dadmin->text->text != NULL)) 8355 { 8356 return 1; 8357 } 8358 8359 return 0; 8360 } 8361 8362 8363 8364 /* 8365 * Clean up temporary files. 8366 * 8367 * NOTES 8368 * This function needs to be reentrant since a call to exit() can cause a 8369 * call to this function, which can then be interrupted by a signal, which 8370 * can cause a second call to this function. 8371 * 8372 * RETURNS 8373 * Nothing. 8374 */ 8375 static void 8376 rcs_cleanup (void) 8377 { 8378 TRACE (TRACE_FUNCTION, "rcs_cleanup()"); 8379 8380 /* FIXME: Do not perform buffered I/O from an interrupt handler like 8381 * this (via error). However, I'm leaving the error-calling code there 8382 * in the hope that on the rare occasion the error call is actually made 8383 * (e.g., a fluky I/O error or permissions problem prevents the deletion 8384 * of a just-created file) reentrancy won't be an issue. 8385 */ 8386 8387 /* We don't want to be interrupted during calls which set globals to NULL, 8388 * but we know that by the time we reach this function, interrupts have 8389 * already been blocked. 8390 */ 8391 if (rcs_lockfile != NULL) 8392 { 8393 /* Use a tmp var since any of these functions could call exit, causing 8394 * us to be called a second time. 8395 */ 8396 char *tmp = rcs_lockfile; 8397 rcs_lockfile = NULL; 8398 if (rcs_lockfd >= 0) 8399 { 8400 if (close (rcs_lockfd) != 0) 8401 error (0, errno, "error closing lock file %s", tmp); 8402 rcs_lockfd = -1; 8403 } 8404 8405 /* Note that the checks for existence_error are because we can be 8406 * called from a signal handler, so we don't know whether the 8407 * files got created. 8408 */ 8409 if (unlink_file (tmp) < 0 8410 && !existence_error (errno)) 8411 error (0, errno, "cannot remove %s", tmp); 8412 } 8413 } 8414 8415 8416 8417 /* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style 8418 locking on the specified RCSFILE: for a file called `foo,v', open 8419 for writing a file called `,foo,'. 8420 8421 Note that we what do here is quite different from what RCS does. 8422 RCS creates the ,foo, file before it reads the RCS file (if it 8423 knows that it will be writing later), so that it actually serves as 8424 a lock. We don't; instead we rely on CVS writelocks. This means 8425 that if someone is running RCS on the file at the same time they 8426 are running CVS on it, they might lose (we read the file, 8427 then RCS writes it, then we write it, clobbering the 8428 changes made by RCS). I believe the current sentiment about this 8429 is "well, don't do that". 8430 8431 A concern has been expressed about whether adopting the RCS 8432 strategy would slow us down. I don't think so, since we need to 8433 write the ,foo, file anyway (unless perhaps if O_EXCL is slower or 8434 something). 8435 8436 These do not perform quite the same function as the RCS -l option 8437 for locking files: they are intended to prevent competing RCS 8438 processes from stomping all over each other's laundry. Hence, 8439 they are `internal' locking functions. 8440 8441 If there is an error, give a fatal error; if we return we always 8442 return a non-NULL value. */ 8443 static FILE * 8444 rcs_internal_lockfile (char *rcsfile) 8445 { 8446 struct stat rstat; 8447 FILE *fp; 8448 static int first_call = 1; 8449 8450 if (first_call) 8451 { 8452 first_call = 0; 8453 /* Clean up if we get a signal or exit. */ 8454 cleanup_register (rcs_cleanup); 8455 } 8456 8457 /* Get the lock file name: `,file,' for RCS file `file,v'. */ 8458 assert (rcs_lockfile == NULL); 8459 assert (rcs_lockfd < 0); 8460 rcs_lockfile = rcs_lockfilename (rcsfile); 8461 8462 /* Use the existing RCS file mode, or read-only if this is a new 8463 file. (Really, this is a lie -- if this is a new file, 8464 RCS_checkin uses the permissions from the working copy. For 8465 actually creating the file, we use 0444 as a safe default mode.) */ 8466 if (stat (rcsfile, &rstat) < 0) 8467 { 8468 if (existence_error (errno)) 8469 rstat.st_mode = S_IRUSR | S_IRGRP | S_IROTH; 8470 else 8471 error (1, errno, "cannot stat %s", rcsfile); 8472 } 8473 8474 /* Try to open exclusively. POSIX.1 guarantees that O_EXCL|O_CREAT 8475 guarantees an exclusive open. According to the RCS source, with 8476 NFS v2 we must also throw in O_TRUNC and use an open mask that makes 8477 the file unwriteable. For extensive justification, see the comments for 8478 rcswriteopen() in rcsedit.c, in RCS 5.7. This is kind of pointless 8479 in the CVS case; see comment at the start of this file concerning 8480 general ,foo, file strategy. 8481 8482 There is some sentiment that with NFSv3 and such, that one can 8483 rely on O_EXCL these days. This might be true for unix (I 8484 don't really know), but I am still pretty skeptical in the case 8485 of the non-unix systems. */ 8486 rcs_lockfd = open (rcs_lockfile, 8487 OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, 8488 S_IRUSR | S_IRGRP | S_IROTH); 8489 8490 if (rcs_lockfd < 0) 8491 { 8492 error (1, errno, "could not open lock file `%s'", rcs_lockfile); 8493 } 8494 8495 /* Force the file permissions, and return a stream object. */ 8496 /* Because we change the modes later, we don't worry about 8497 this in the non-HAVE_FCHMOD case. */ 8498 #ifdef HAVE_FCHMOD 8499 if (fchmod (rcs_lockfd, rstat.st_mode) < 0) 8500 error (1, errno, "cannot change mode for %s", rcs_lockfile); 8501 #endif 8502 fp = fdopen (rcs_lockfd, FOPEN_BINARY_WRITE); 8503 if (fp == NULL) 8504 error (1, errno, "cannot fdopen %s", rcs_lockfile); 8505 8506 return fp; 8507 } 8508 8509 8510 8511 static void 8512 rcs_internal_unlockfile (FILE *fp, char *rcsfile) 8513 { 8514 assert (rcs_lockfile != NULL); 8515 assert (rcs_lockfd >= 0); 8516 8517 /* Abort if we could not write everything successfully to LOCKFILE. 8518 This is not a great error-handling mechanism, but should prevent 8519 corrupting the repository. */ 8520 8521 if (ferror (fp)) 8522 /* Using errno here may well be misleanding since the most recent 8523 call that set errno may not have anything whatsoever to do with 8524 the error that set the flag, but it's better than nothing. The 8525 real solution is to check each call to fprintf rather than waiting 8526 until the end like this. */ 8527 error (1, errno, "error writing to lock file %s", rcs_lockfile); 8528 8529 /* Flush and sync the file, or the user may be told the commit completed, 8530 * while a server crash/power failure could still cause the data to be 8531 * lost. 8532 * 8533 * Invoking rename(",<file>," , "<file>,v") on Linux and almost all UNIXs 8534 * only flushes the inode for the target file to disk, it does not 8535 * guarantee flush of the kernel buffers allocated for the ,<file>,. 8536 * Depending upon the load on the machine, the Linux kernel's flush daemon 8537 * process may not flush for a while. In the meantime the CVS transaction 8538 * could have been declared committed to the end CVS user (CVS process has 8539 * returned the final "OK"). If the machine crashes prior to syncing the 8540 * changes to disk, the committed transaction can be lost. 8541 */ 8542 if (fflush (fp) != 0) 8543 error (1, errno, "error flushing file `%s' to kernel buffers", 8544 rcs_lockfile); 8545 #ifdef HAVE_FSYNC 8546 if (fsync (rcs_lockfd) < 0) 8547 error (1, errno, "error fsyncing file `%s'", rcs_lockfile); 8548 #endif 8549 8550 if (fclose (fp) == EOF) 8551 error (1, errno, "error closing lock file %s", rcs_lockfile); 8552 rcs_lockfd = -1; 8553 8554 rename_file (rcs_lockfile, rcsfile); 8555 8556 { 8557 /* Use a temporary to make sure there's no interval 8558 (after rcs_lockfile has been freed but before it's set to NULL) 8559 during which the signal handler's use of rcs_lockfile would 8560 reference freed memory. */ 8561 char *tmp = rcs_lockfile; 8562 rcs_lockfile = NULL; 8563 free (tmp); 8564 } 8565 } 8566 8567 8568 8569 static char * 8570 rcs_lockfilename (const char *rcsfile) 8571 { 8572 char *lockfile, *lockp; 8573 const char *rcsbase, *rcsp, *rcsend; 8574 int rcslen; 8575 8576 /* Create the lockfile name. */ 8577 rcslen = strlen (rcsfile); 8578 lockfile = xmalloc (rcslen + 10); 8579 rcsbase = last_component (rcsfile); 8580 rcsend = rcsfile + rcslen - sizeof(RCSEXT); 8581 for (lockp = lockfile, rcsp = rcsfile; rcsp < rcsbase; ++rcsp) 8582 *lockp++ = *rcsp; 8583 *lockp++ = ','; 8584 while (rcsp <= rcsend) 8585 *lockp++ = *rcsp++; 8586 *lockp++ = ','; 8587 *lockp = '\0'; 8588 8589 return lockfile; 8590 } 8591 8592 8593 8594 /* Rewrite an RCS file. The basic idea here is that the caller should 8595 first call RCS_reparsercsfile, then munge the data structures as 8596 desired (via RCS_delete_revs, RCS_settag, &c), then call RCS_rewrite. */ 8597 void 8598 RCS_rewrite (RCSNode *rcs, Deltatext *newdtext, char *insertpt) 8599 { 8600 FILE *fin, *fout; 8601 struct rcsbuffer rcsbufin; 8602 8603 if (noexec) 8604 return; 8605 8606 /* Make sure we're operating on an actual file and not a symlink. */ 8607 resolve_symlink (&(rcs->path)); 8608 8609 fout = rcs_internal_lockfile (rcs->path); 8610 8611 RCS_putadmin (rcs, fout); 8612 RCS_putdtree (rcs, rcs->head, fout); 8613 RCS_putdesc (rcs, fout); 8614 8615 /* Open the original RCS file and seek to the first delta text. */ 8616 rcsbuf_cache_open (rcs, rcs->delta_pos, &fin, &rcsbufin); 8617 8618 /* Update delta_pos to the current position in the output file. 8619 Do NOT move these statements: they must be done after fin has 8620 been positioned at the old delta_pos, but before any delta 8621 texts have been written to fout. 8622 */ 8623 rcs->delta_pos = ftello (fout); 8624 if (rcs->delta_pos == -1) 8625 error (1, errno, "cannot ftello in RCS file %s", rcs->path); 8626 8627 RCS_copydeltas (rcs, fin, &rcsbufin, fout, newdtext, insertpt); 8628 8629 /* We don't want to call rcsbuf_cache here, since we're about to 8630 delete the file. */ 8631 rcsbuf_close (&rcsbufin); 8632 if (ferror (fin)) 8633 /* The only case in which using errno here would be meaningful 8634 is if we happen to have left errno unmolested since the call 8635 which produced the error (e.g. fread). That is pretty 8636 fragile even if it happens to sometimes be true. The real 8637 solution is to make sure that all the code which reads 8638 from fin checks for errors itself (some does, some doesn't). */ 8639 error (0, 0, "warning: ferror set while rewriting RCS file `%s'", rcs->path); 8640 if (fclose (fin) < 0) 8641 error (0, errno, "warning: closing RCS file `%s'", rcs->path); 8642 8643 rcs_internal_unlockfile (fout, rcs->path); 8644 } 8645 8646 8647 8648 /* Abandon changes to an RCS file. */ 8649 void 8650 RCS_abandon (RCSNode *rcs) 8651 { 8652 free_rcsnode_contents (rcs); 8653 rcs->symbols_data = NULL; 8654 rcs->expand = NULL; 8655 rcs->access = NULL; 8656 rcs->locks_data = NULL; 8657 rcs->comment = NULL; 8658 rcs->desc = NULL; 8659 rcs->flags |= PARTIAL; 8660 } 8661 8662 8663 8664 /* 8665 * For a given file with full pathname PATH and revision number REV, 8666 * produce a file label suitable for passing to diff. The default 8667 * file label as used by RCS 5.7 looks like this: 8668 * 8669 * FILENAME <tab> YYYY/MM/DD <sp> HH:MM:SS <tab> REVNUM 8670 * 8671 * The date and time used are the revision's last checkin date and time. 8672 * If REV is NULL, use the working copy's mtime instead. 8673 * 8674 * /dev/null is not statted but assumed to have been created on the Epoch. 8675 * At least using the POSIX.2 definition of patch, this should cause creation 8676 * of files on platforms such as Windoze where the null IO device isn't named 8677 * /dev/null to be parsed by patch properly. 8678 */ 8679 char * 8680 make_file_label (const char *path, const char *rev, RCSNode *rcs) 8681 { 8682 char datebuf[MAXDATELEN + 1]; 8683 char *label; 8684 8685 if (rev) 8686 { 8687 char date[MAXDATELEN + 1]; 8688 /* revs cannot be attached to /dev/null ... duh. */ 8689 assert (strcmp(DEVNULL, path)); 8690 RCS_getrevtime (rcs, rev, datebuf, 0); 8691 (void) date_to_internet (date, datebuf); 8692 label = Xasprintf ("-L%s\t%s\t%s", path, date, rev); 8693 } 8694 else 8695 { 8696 struct stat sb; 8697 struct tm *wm; 8698 8699 if (strcmp(DEVNULL, path)) 8700 { 8701 const char *file = last_component (path); 8702 if (stat (file, &sb) < 0) 8703 /* Assume that if the stat fails,then the later read for the 8704 * diff will too. 8705 */ 8706 error (1, errno, "could not get info for `%s'", path); 8707 wm = gmtime (&sb.st_mtime); 8708 } 8709 else 8710 { 8711 time_t t = 0; 8712 wm = gmtime(&t); 8713 } 8714 8715 (void) tm_to_internet (datebuf, wm); 8716 label = Xasprintf ("-L%s\t%s", path, datebuf); 8717 } 8718 return label; 8719 } 8720 8721 8722 8723 /* 8724 * Set up a local/custom RCS keyword for expansion. 8725 * 8726 * INPUTS 8727 * infopath Path to file being parsed, for error messages. 8728 * ln Line number of INFOPATH being processed, for error 8729 * messages. 8730 * keywords_in 8731 * arg 8732 * 8733 * OUTPUTS 8734 * keywords_in 8735 */ 8736 void 8737 RCS_setlocalid (const char *infopath, unsigned int ln, 8738 void **keywords_in, const char *arg) 8739 { 8740 char *copy, *next, *key, *s; 8741 struct rcs_keyword *keywords; 8742 enum keyword save_expandto; 8743 8744 if (!*keywords_in) 8745 *keywords_in = new_keywords (); 8746 keywords = *keywords_in; 8747 8748 copy = xstrdup (arg); 8749 next = copy; 8750 key = strtok (next, "="); 8751 8752 /* 8753 * Validate key 8754 */ 8755 for (s = key; *s != '\0'; s++) 8756 { 8757 if (! isalpha ((unsigned char) *s)) 8758 { 8759 if (!parse_error (infopath, ln)) 8760 error (0, 0, 8761 "%s [%u]: LocalKeyword ignored: Bad character `%c' in key `%s'", 8762 primary_root_inverse_translate (infopath), 8763 ln, *s, key); 8764 free (copy); 8765 return; 8766 } 8767 } 8768 8769 save_expandto = keywords[KEYWORD_LOCALID].expandto; 8770 8771 /* options? */ 8772 while ((key = strtok (NULL, ",")) != NULL) { 8773 if (!strcmp(key, keywords[KEYWORD_ID].string)) 8774 keywords[KEYWORD_LOCALID].expandto = KEYWORD_ID; 8775 else if (!strcmp(key, keywords[KEYWORD_HEADER].string)) 8776 keywords[KEYWORD_LOCALID].expandto = KEYWORD_HEADER; 8777 else if (!strcmp(key, keywords[KEYWORD_CVSHEADER].string)) 8778 keywords[KEYWORD_LOCALID].expandto = KEYWORD_CVSHEADER; 8779 else 8780 { 8781 keywords[KEYWORD_LOCALID].expandto = save_expandto; 8782 if (!parse_error (infopath, ln)) 8783 error (0, 0, 8784 "%s [%u]: LocalKeyword ignored: Unknown LocalId mode: `%s'", 8785 primary_root_inverse_translate (infopath), 8786 ln, key); 8787 free (copy); 8788 return; 8789 } 8790 } 8791 8792 keywords[KEYWORD_LOCALID].string = xstrdup (next); 8793 keywords[KEYWORD_LOCALID].len = strlen (next); 8794 keywords[KEYWORD_LOCALID].expandit = 1; 8795 8796 free (copy); 8797 } 8798 8799 8800 8801 void 8802 RCS_setincexc (void **keywords_in, const char *arg) 8803 { 8804 char *key; 8805 char *copy, *next; 8806 bool include = false; 8807 struct rcs_keyword *keyword; 8808 struct rcs_keyword *keywords; 8809 8810 if (!*keywords_in) 8811 *keywords_in = new_keywords (); 8812 keywords = *keywords_in; 8813 8814 copy = xstrdup(arg); 8815 next = copy; 8816 switch (*next++) { 8817 case 'e': 8818 include = false; 8819 break; 8820 case 'i': 8821 include = true; 8822 break; 8823 default: 8824 free(copy); 8825 return; 8826 } 8827 8828 if (include) 8829 for (keyword = keywords; keyword->string != NULL; keyword++) 8830 { 8831 keyword->expandit = false; 8832 } 8833 8834 key = strtok(next, ","); 8835 while (key) { 8836 for (keyword = keywords; keyword->string != NULL; keyword++) { 8837 if (strcmp (keyword->string, key) == 0) 8838 keyword->expandit = include; 8839 } 8840 key = strtok(NULL, ","); 8841 } 8842 free(copy); 8843 return; 8844 } 8845 8846 8847 8848 #define ATTIC "/" CVSATTIC 8849 static char * 8850 getfullCVSname(char *CVSname, char **pathstore) 8851 { 8852 if (current_parsed_root->directory) { 8853 int rootlen; 8854 char *c = NULL; 8855 int alen = sizeof(ATTIC) - 1; 8856 8857 *pathstore = xstrdup(CVSname); 8858 if ((c = strrchr(*pathstore, '/')) != NULL) { 8859 if (c - *pathstore >= alen) { 8860 if (!strncmp(c - alen, ATTIC, alen)) { 8861 while (*c != '\0') { 8862 *(c - alen) = *c; 8863 c++; 8864 } 8865 *(c - alen) = '\0'; 8866 } 8867 } 8868 } 8869 8870 rootlen = strlen(current_parsed_root->directory); 8871 if (!strncmp(*pathstore, current_parsed_root->directory, rootlen) && 8872 (*pathstore)[rootlen] == '/') 8873 CVSname = (*pathstore + rootlen + 1); 8874 else 8875 CVSname = (*pathstore); 8876 } 8877 return CVSname; 8878 } 8879