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