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