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 alphabetic character after the '$'. */ 3550 send = srch + srch_len; 3551 for (s = srch; s < send; s++) 3552 if (! isalpha ((unsigned char) *s)) 3553 break; 3554 3555 /* If the first non alphabetic character is not '$' or ':', 3556 then this is not an RCS keyword. */ 3557 if (s == send || (*s != '$' && *s != ':')) 3558 continue; 3559 3560 /* See if this is one of the keywords. */ 3561 slen = s - srch; 3562 for (keyword = keywords; keyword->string != NULL; keyword++) 3563 { 3564 if (keyword->len == slen 3565 && strncmp (keyword->string, srch, slen) == 0) 3566 { 3567 break; 3568 } 3569 } 3570 if (keyword->string == NULL) 3571 continue; 3572 3573 kw = (enum keyword) (keyword - keywords); 3574 3575 /* If the keyword ends with a ':', then the old value consists 3576 of the characters up to the next '$'. If there is no '$' 3577 before the end of the line, though, then this wasn't an RCS 3578 keyword after all. */ 3579 if (*s == ':') 3580 { 3581 for (; s < send; s++) 3582 if (*s == '$' || *s == '\n') 3583 break; 3584 if (s == send || *s != '$') 3585 continue; 3586 } 3587 3588 /* At this point we must replace the string from SRCH to S 3589 with the expansion of the keyword KW. */ 3590 3591 /* Get the value to use. */ 3592 free_value = 0; 3593 if (expand == KFLAG_K) 3594 value = NULL; 3595 else 3596 { 3597 switch (kw) 3598 { 3599 default: 3600 abort (); 3601 3602 case KEYWORD_AUTHOR: 3603 value = ver->author; 3604 break; 3605 3606 case KEYWORD_DATE: 3607 value = printable_date (ver->date); 3608 free_value = 1; 3609 break; 3610 3611 case KEYWORD_HEADER: 3612 case KEYWORD_ID: 3613 case KEYWORD_LOCALID: 3614 { 3615 char *path; 3616 int free_path; 3617 char *date; 3618 3619 if (kw == KEYWORD_HEADER) 3620 path = rcs->path; 3621 else 3622 path = last_component (rcs->path); 3623 path = escape_keyword_value (path, &free_path); 3624 date = printable_date (ver->date); 3625 value = xmalloc (strlen (path) 3626 + strlen (ver->version) 3627 + strlen (date) 3628 + strlen (ver->author) 3629 + strlen (ver->state) 3630 + (locker == NULL ? 0 : strlen (locker)) 3631 + 20); 3632 3633 sprintf (value, "%s %s %s %s %s%s%s", 3634 path, ver->version, date, ver->author, 3635 ver->state, 3636 locker != NULL ? " " : "", 3637 locker != NULL ? locker : ""); 3638 if (free_path) 3639 free (path); 3640 free (date); 3641 free_value = 1; 3642 } 3643 break; 3644 3645 case KEYWORD_LOCKER: 3646 value = locker; 3647 break; 3648 3649 case KEYWORD_LOG: 3650 case KEYWORD_RCSFILE: 3651 value = escape_keyword_value (last_component (rcs->path), 3652 &free_value); 3653 break; 3654 3655 case KEYWORD_NAME: 3656 if (name != NULL && ! isdigit ((unsigned char) *name)) 3657 value = (char *) name; 3658 else 3659 value = NULL; 3660 break; 3661 3662 case KEYWORD_REVISION: 3663 value = ver->version; 3664 break; 3665 3666 case KEYWORD_SOURCE: 3667 value = escape_keyword_value (rcs->path, &free_value); 3668 break; 3669 3670 case KEYWORD_STATE: 3671 value = ver->state; 3672 break; 3673 } 3674 } 3675 3676 sub = xmalloc (keyword->len 3677 + (value == NULL ? 0 : strlen (value)) 3678 + 10); 3679 if (expand == KFLAG_V) 3680 { 3681 /* Decrement SRCH and increment S to remove the $ 3682 characters. */ 3683 --srch; 3684 ++srch_len; 3685 ++s; 3686 sublen = 0; 3687 } 3688 else 3689 { 3690 strcpy (sub, keyword->string); 3691 sublen = strlen (keyword->string); 3692 if (expand != KFLAG_K) 3693 { 3694 sub[sublen] = ':'; 3695 sub[sublen + 1] = ' '; 3696 sublen += 2; 3697 } 3698 } 3699 if (value != NULL) 3700 { 3701 strcpy (sub + sublen, value); 3702 sublen += strlen (value); 3703 } 3704 if (expand != KFLAG_V && expand != KFLAG_K) 3705 { 3706 sub[sublen] = ' '; 3707 ++sublen; 3708 sub[sublen] = '\0'; 3709 } 3710 3711 if (free_value) 3712 free (value); 3713 3714 /* The Log keyword requires special handling. This behaviour 3715 is taken from RCS 5.7. The special log message is what RCS 3716 uses for ci -k. */ 3717 if (kw == KEYWORD_LOG 3718 && (sizeof "checked in with -k by " <= loglen 3719 || log == NULL 3720 || strncmp (log, "checked in with -k by ", 3721 sizeof "checked in with -k by " - 1) != 0)) 3722 { 3723 char *start; 3724 char *leader; 3725 size_t leader_len, leader_sp_len; 3726 const char *logend; 3727 const char *snl; 3728 int cnl; 3729 char *date; 3730 const char *sl; 3731 3732 /* We are going to insert the trailing $ ourselves, before 3733 the log message, so we must remove it from S, if we 3734 haven't done so already. */ 3735 if (expand != KFLAG_V) 3736 ++s; 3737 3738 /* CVS never has empty log messages, but old RCS files might. */ 3739 if (log == NULL) 3740 log = ""; 3741 3742 /* Find the start of the line. */ 3743 start = srch; 3744 while (start > buf && start[-1] != '\n') 3745 --start; 3746 3747 /* Copy the start of the line to use as a comment leader. */ 3748 leader_len = srch - start; 3749 if (expand != KFLAG_V) 3750 --leader_len; 3751 leader = xmalloc (leader_len); 3752 memcpy (leader, start, leader_len); 3753 leader_sp_len = leader_len; 3754 while (leader_sp_len > 0 && leader[leader_sp_len - 1] == ' ') 3755 --leader_sp_len; 3756 3757 /* RCS does some checking for an old style of Log here, 3758 but we don't bother. RCS issues a warning if it 3759 changes anything. */ 3760 3761 /* Count the number of newlines in the log message so that 3762 we know how many copies of the leader we will need. */ 3763 cnl = 0; 3764 logend = log + loglen; 3765 for (snl = log; snl < logend; snl++) 3766 if (*snl == '\n') 3767 ++cnl; 3768 3769 date = printable_date (ver->date); 3770 sub = xrealloc (sub, 3771 (sublen 3772 + sizeof "Revision" 3773 + strlen (ver->version) 3774 + strlen (date) 3775 + strlen (ver->author) 3776 + loglen 3777 + (cnl + 2) * leader_len 3778 + 20)); 3779 if (expand != KFLAG_V) 3780 { 3781 sub[sublen] = '$'; 3782 ++sublen; 3783 } 3784 sub[sublen] = '\n'; 3785 ++sublen; 3786 memcpy (sub + sublen, leader, leader_len); 3787 sublen += leader_len; 3788 sprintf (sub + sublen, "Revision %s %s %s\n", 3789 ver->version, date, ver->author); 3790 sublen += strlen (sub + sublen); 3791 free (date); 3792 3793 sl = log; 3794 while (sl < logend) 3795 { 3796 if (*sl == '\n') 3797 { 3798 memcpy (sub + sublen, leader, leader_sp_len); 3799 sublen += leader_sp_len; 3800 sub[sublen] = '\n'; 3801 ++sublen; 3802 ++sl; 3803 } 3804 else 3805 { 3806 const char *slnl; 3807 3808 memcpy (sub + sublen, leader, leader_len); 3809 sublen += leader_len; 3810 for (slnl = sl; slnl < logend && *slnl != '\n'; ++slnl) 3811 ; 3812 if (slnl < logend) 3813 ++slnl; 3814 memcpy (sub + sublen, sl, slnl - sl); 3815 sublen += slnl - sl; 3816 sl = slnl; 3817 } 3818 } 3819 3820 memcpy (sub + sublen, leader, leader_sp_len); 3821 sublen += leader_sp_len; 3822 3823 free (leader); 3824 } 3825 3826 /* Now SUB contains a string which is to replace the string 3827 from SRCH to S. SUBLEN is the length of SUB. */ 3828 3829 if (srch + sublen == s) 3830 { 3831 memcpy (srch, sub, sublen); 3832 free (sub); 3833 } 3834 else 3835 { 3836 struct expand_buffer *ebuf; 3837 3838 /* We need to change the size of the buffer. We build a 3839 list of expand_buffer structures. Each expand_buffer 3840 structure represents a portion of the final output. We 3841 concatenate them back into a single buffer when we are 3842 done. This minimizes the number of potentially large 3843 buffer copies we must do. */ 3844 3845 if (ebufs == NULL) 3846 { 3847 ebufs = (struct expand_buffer *) xmalloc (sizeof *ebuf); 3848 ebufs->next = NULL; 3849 ebufs->data = buf; 3850 ebufs->free_data = 0; 3851 ebuf_len = srch - buf; 3852 ebufs->len = ebuf_len; 3853 ebuf_last = ebufs; 3854 } 3855 else 3856 { 3857 assert (srch >= ebuf_last->data); 3858 assert (srch <= ebuf_last->data + ebuf_last->len); 3859 ebuf_len -= ebuf_last->len - (srch - ebuf_last->data); 3860 ebuf_last->len = srch - ebuf_last->data; 3861 } 3862 3863 ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf); 3864 ebuf->data = sub; 3865 ebuf->len = sublen; 3866 ebuf->free_data = 1; 3867 ebuf->next = NULL; 3868 ebuf_last->next = ebuf; 3869 ebuf_last = ebuf; 3870 ebuf_len += sublen; 3871 3872 ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf); 3873 ebuf->data = s; 3874 ebuf->len = srch_len - (s - srch); 3875 ebuf->free_data = 0; 3876 ebuf->next = NULL; 3877 ebuf_last->next = ebuf; 3878 ebuf_last = ebuf; 3879 ebuf_len += srch_len - (s - srch); 3880 } 3881 3882 srch_len -= (s - srch); 3883 srch = s; 3884 } 3885 3886 if (locker != NULL) 3887 free (locker); 3888 3889 if (ebufs == NULL) 3890 { 3891 *retbuf = buf; 3892 *retlen = len; 3893 } 3894 else 3895 { 3896 char *ret; 3897 3898 ret = xmalloc (ebuf_len); 3899 *retbuf = ret; 3900 *retlen = ebuf_len; 3901 while (ebufs != NULL) 3902 { 3903 struct expand_buffer *next; 3904 3905 memcpy (ret, ebufs->data, ebufs->len); 3906 ret += ebufs->len; 3907 if (ebufs->free_data) 3908 free (ebufs->data); 3909 next = ebufs->next; 3910 free (ebufs); 3911 ebufs = next; 3912 } 3913 } 3914 } 3915 3916 /* Check out a revision from an RCS file. 3917 3918 If PFN is not NULL, then ignore WORKFILE and SOUT. Call PFN zero 3919 or more times with the contents of the file. CALLERDAT is passed, 3920 uninterpreted, to PFN. (The current code will always call PFN 3921 exactly once for a non empty file; however, the current code 3922 assumes that it can hold the entire file contents in memory, which 3923 is not a good assumption, and might change in the future). 3924 3925 Otherwise, if WORKFILE is not NULL, check out the revision to 3926 WORKFILE. However, if WORKFILE is not NULL, and noexec is set, 3927 then don't do anything. 3928 3929 Otherwise, if WORKFILE is NULL, check out the revision to SOUT. If 3930 SOUT is RUN_TTY, then write the contents of the revision to 3931 standard output. When using SOUT, the output is generally a 3932 temporary file; don't bother to get the file modes correct. 3933 3934 REV is the numeric revision to check out. It may be NULL, which 3935 means to check out the head of the default branch. 3936 3937 If NAMETAG is not NULL, and is not a numeric revision, then it is 3938 the tag that should be used when expanding the RCS Name keyword. 3939 3940 OPTIONS is a string such as "-kb" or "-kv" for keyword expansion 3941 options. It may be NULL to use the default expansion mode of the 3942 file, typically "-kkv". 3943 3944 On an error which prevented checking out the file, either print a 3945 nonfatal error and return 1, or give a fatal error. On success, 3946 return 0. */ 3947 3948 /* This function mimics the behavior of `rcs co' almost exactly. The 3949 chief difference is in its support for preserving file ownership, 3950 permissions, and special files across checkin and checkout -- see 3951 comments in RCS_checkin for some issues about this. -twp */ 3952 3953 int 3954 RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat) 3955 RCSNode *rcs; 3956 char *workfile; 3957 char *rev; 3958 char *nametag; 3959 char *options; 3960 char *sout; 3961 RCSCHECKOUTPROC pfn; 3962 void *callerdat; 3963 { 3964 int free_rev = 0; 3965 enum kflag expand; 3966 FILE *fp, *ofp; 3967 struct stat sb; 3968 struct rcsbuffer rcsbuf; 3969 char *key; 3970 char *value; 3971 size_t len; 3972 int free_value = 0; 3973 char *log = NULL; 3974 size_t loglen; 3975 Node *vp = NULL; 3976 #ifdef PRESERVE_PERMISSIONS_SUPPORT 3977 uid_t rcs_owner = (uid_t) -1; 3978 gid_t rcs_group = (gid_t) -1; 3979 mode_t rcs_mode; 3980 int change_rcs_owner_or_group = 0; 3981 int change_rcs_mode = 0; 3982 int special_file = 0; 3983 unsigned long devnum_long; 3984 dev_t devnum = 0; 3985 #endif 3986 3987 if (trace) 3988 { 3989 (void) fprintf (stderr, "%s-> checkout (%s, %s, %s, %s)\n", 3990 #ifdef SERVER_SUPPORT 3991 server_active ? "S" : " ", 3992 #else 3993 "", 3994 #endif 3995 rcs->path, 3996 rev != NULL ? rev : "", 3997 options != NULL ? options : "", 3998 (pfn != NULL ? "(function)" 3999 : (workfile != NULL 4000 ? workfile 4001 : (sout != RUN_TTY ? sout : "(stdout)")))); 4002 } 4003 4004 assert (rev == NULL || isdigit ((unsigned char) *rev)); 4005 4006 if (noexec && workfile != NULL) 4007 return 0; 4008 4009 assert (sout == RUN_TTY || workfile == NULL); 4010 assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL)); 4011 4012 /* Some callers, such as Checkin or remove_file, will pass us a 4013 branch. */ 4014 if (rev != NULL && (numdots (rev) & 1) == 0) 4015 { 4016 rev = RCS_getbranch (rcs, rev, 1); 4017 if (rev == NULL) 4018 error (1, 0, "internal error: bad branch tag in checkout"); 4019 free_rev = 1; 4020 } 4021 4022 if (rev == NULL || STREQ (rev, rcs->head)) 4023 { 4024 int gothead; 4025 4026 /* We want the head revision. Try to read it directly. */ 4027 4028 if (rcs->flags & PARTIAL) 4029 RCS_reparsercsfile (rcs, &fp, &rcsbuf); 4030 else 4031 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf); 4032 4033 gothead = 0; 4034 if (! rcsbuf_getrevnum (&rcsbuf, &key)) 4035 error (1, 0, "unexpected EOF reading %s", rcs->path); 4036 while (rcsbuf_getkey (&rcsbuf, &key, &value)) 4037 { 4038 if (STREQ (key, "log")) 4039 log = rcsbuf_valcopy (&rcsbuf, value, 0, &loglen); 4040 else if (STREQ (key, "text")) 4041 { 4042 gothead = 1; 4043 break; 4044 } 4045 } 4046 4047 if (! gothead) 4048 { 4049 error (0, 0, "internal error: cannot find head text"); 4050 if (free_rev) 4051 free (rev); 4052 return 1; 4053 } 4054 4055 rcsbuf_valpolish (&rcsbuf, value, 0, &len); 4056 4057 if (fstat (fileno (fp), &sb) < 0) 4058 error (1, errno, "cannot fstat %s", rcs->path); 4059 4060 rcsbuf_cache (rcs, &rcsbuf); 4061 } 4062 else 4063 { 4064 struct rcsbuffer *rcsbufp; 4065 4066 /* It isn't the head revision of the trunk. We'll need to 4067 walk through the deltas. */ 4068 4069 fp = NULL; 4070 if (rcs->flags & PARTIAL) 4071 RCS_reparsercsfile (rcs, &fp, &rcsbuf); 4072 4073 if (fp == NULL) 4074 { 4075 /* If RCS_deltas didn't close the file, we could use fstat 4076 here too. Probably should change it thusly.... */ 4077 if (stat (rcs->path, &sb) < 0) 4078 error (1, errno, "cannot stat %s", rcs->path); 4079 rcsbufp = NULL; 4080 } 4081 else 4082 { 4083 if (fstat (fileno (fp), &sb) < 0) 4084 error (1, errno, "cannot fstat %s", rcs->path); 4085 rcsbufp = &rcsbuf; 4086 } 4087 4088 RCS_deltas (rcs, fp, rcsbufp, rev, RCS_FETCH, &value, &len, 4089 &log, &loglen); 4090 free_value = 1; 4091 } 4092 4093 /* If OPTIONS is NULL or the empty string, then the old code would 4094 invoke the RCS co program with no -k option, which means that 4095 co would use the string we have stored in rcs->expand. */ 4096 if ((options == NULL || options[0] == '\0') && rcs->expand == NULL) 4097 expand = KFLAG_KV; 4098 else 4099 { 4100 const char *ouroptions; 4101 const char * const *cpp; 4102 4103 if (options != NULL && options[0] != '\0') 4104 { 4105 assert (options[0] == '-' && options[1] == 'k'); 4106 ouroptions = options + 2; 4107 } 4108 else 4109 ouroptions = rcs->expand; 4110 4111 for (cpp = kflags; *cpp != NULL; cpp++) 4112 if (STREQ (*cpp, ouroptions)) 4113 break; 4114 4115 if (*cpp != NULL) 4116 expand = (enum kflag) (cpp - kflags); 4117 else 4118 { 4119 error (0, 0, 4120 "internal error: unsupported substitution string -k%s", 4121 ouroptions); 4122 expand = KFLAG_KV; 4123 } 4124 } 4125 4126 #ifdef PRESERVE_PERMISSIONS_SUPPORT 4127 /* Handle special files and permissions, if that is desired. */ 4128 if (preserve_perms) 4129 { 4130 RCSVers *vers; 4131 Node *info; 4132 4133 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev); 4134 if (vp == NULL) 4135 error (1, 0, "internal error: no revision information for %s", 4136 rev == NULL ? rcs->head : rev); 4137 vers = (RCSVers *) vp->data; 4138 4139 /* First we look for symlinks, which are simplest to handle. */ 4140 info = findnode (vers->other_delta, "symlink"); 4141 if (info != NULL) 4142 { 4143 char *dest; 4144 4145 if (pfn != NULL || (workfile == NULL && sout == RUN_TTY)) 4146 error (1, 0, "symbolic link %s:%s cannot be piped", 4147 rcs->path, vers->version); 4148 if (workfile == NULL) 4149 dest = sout; 4150 else 4151 dest = workfile; 4152 4153 /* Remove `dest', just in case. It's okay to get ENOENT here, 4154 since we just want the file not to be there. (TODO: decide 4155 whether it should be considered an error for `dest' to exist 4156 at this point. If so, the unlink call should be removed and 4157 `symlink' should signal the error. -twp) */ 4158 if (unlink (dest) < 0 && !existence_error (errno)) 4159 error (1, errno, "cannot remove %s", dest); 4160 if (symlink (info->data, dest) < 0) 4161 error (1, errno, "cannot create symbolic link from %s to %s", 4162 dest, info->data); 4163 if (free_value) 4164 free (value); 4165 if (free_rev) 4166 free (rev); 4167 return 0; 4168 } 4169 4170 /* Next, we look at this file's hardlinks field, and see whether 4171 it is linked to any other file that has been checked out. 4172 If so, we don't do anything else -- just link it to that file. 4173 4174 If we are checking out a file to a pipe or temporary storage, 4175 none of this should matter. Hence the `workfile != NULL' 4176 wrapper around the whole thing. -twp */ 4177 4178 if (workfile != NULL) 4179 { 4180 List *links = vers->hardlinks; 4181 if (links != NULL) 4182 { 4183 Node *uptodate_link; 4184 4185 /* For each file in the hardlinks field, check to see 4186 if it exists, and if so, if it has been checked out 4187 this iteration. When walklist returns, uptodate_link 4188 should point to a hardlist node representing a file 4189 in `links' which has recently been checked out, or 4190 NULL if no file in `links' has yet been checked out. */ 4191 4192 uptodate_link = NULL; 4193 (void) walklist (links, find_checkedout_proc, &uptodate_link); 4194 dellist (&links); 4195 4196 /* If we've found a file that `workfile' is supposed to be 4197 linked to, and it has been checked out since CVS was 4198 invoked, then simply link workfile to that file and return. 4199 4200 If one of these conditions is not met, then 4201 workfile is the first one in its hardlink group to 4202 be checked out, and we must continue with a full 4203 checkout. */ 4204 4205 if (uptodate_link != NULL) 4206 { 4207 struct hardlink_info *hlinfo = 4208 (struct hardlink_info *) uptodate_link->data; 4209 4210 if (link (uptodate_link->key, workfile) < 0) 4211 error (1, errno, "cannot link %s to %s", 4212 workfile, uptodate_link->key); 4213 hlinfo->checked_out = 1; /* probably unnecessary */ 4214 if (free_value) 4215 free (value); 4216 if (free_rev) 4217 free (rev); 4218 return 0; 4219 } 4220 } 4221 } 4222 4223 info = findnode (vers->other_delta, "owner"); 4224 if (info != NULL) 4225 { 4226 change_rcs_owner_or_group = 1; 4227 rcs_owner = (uid_t) strtoul (info->data, NULL, 10); 4228 } 4229 info = findnode (vers->other_delta, "group"); 4230 if (info != NULL) 4231 { 4232 change_rcs_owner_or_group = 1; 4233 rcs_group = (gid_t) strtoul (info->data, NULL, 10); 4234 } 4235 info = findnode (vers->other_delta, "permissions"); 4236 if (info != NULL) 4237 { 4238 change_rcs_mode = 1; 4239 rcs_mode = (mode_t) strtoul (info->data, NULL, 8); 4240 } 4241 info = findnode (vers->other_delta, "special"); 4242 if (info != NULL) 4243 { 4244 /* If the size of `devtype' changes, fix the sscanf call also */ 4245 char devtype[16+1]; 4246 4247 if (sscanf (info->data, "%16s %lu", 4248 devtype, &devnum_long) < 2) 4249 error (1, 0, "%s:%s has bad `special' newphrase %s", 4250 workfile, vers->version, info->data); 4251 devnum = devnum_long; 4252 if (STREQ (devtype, "character")) 4253 special_file = S_IFCHR; 4254 else if (STREQ (devtype, "block")) 4255 special_file = S_IFBLK; 4256 else 4257 error (0, 0, "%s is a special file of unsupported type `%s'", 4258 workfile, info->data); 4259 } 4260 } 4261 #endif 4262 4263 if (expand != KFLAG_O && expand != KFLAG_B) 4264 { 4265 char *newvalue; 4266 4267 /* Don't fetch the delta node again if we already have it. */ 4268 if (vp == NULL) 4269 { 4270 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev); 4271 if (vp == NULL) 4272 error (1, 0, "internal error: no revision information for %s", 4273 rev == NULL ? rcs->head : rev); 4274 } 4275 4276 expand_keywords (rcs, (RCSVers *) vp->data, nametag, log, loglen, 4277 expand, value, len, &newvalue, &len); 4278 4279 if (newvalue != value) 4280 { 4281 if (free_value) 4282 free (value); 4283 value = newvalue; 4284 free_value = 1; 4285 } 4286 } 4287 4288 if (free_rev) 4289 free (rev); 4290 4291 if (log != NULL) 4292 { 4293 free (log); 4294 log = NULL; 4295 } 4296 4297 if (pfn != NULL) 4298 { 4299 #ifdef PRESERVE_PERMISSIONS_SUPPORT 4300 if (special_file) 4301 error (1, 0, "special file %s cannot be piped to anything", 4302 rcs->path); 4303 #endif 4304 /* The PFN interface is very simple to implement right now, as 4305 we always have the entire file in memory. */ 4306 if (len != 0) 4307 pfn (callerdat, value, len); 4308 } 4309 #ifdef PRESERVE_PERMISSIONS_SUPPORT 4310 else if (special_file) 4311 { 4312 #ifdef HAVE_MKNOD 4313 char *dest; 4314 4315 /* Can send either to WORKFILE or to SOUT, as long as SOUT is 4316 not RUN_TTY. */ 4317 dest = workfile; 4318 if (dest == NULL) 4319 { 4320 if (sout == RUN_TTY) 4321 error (1, 0, "special file %s cannot be written to stdout", 4322 rcs->path); 4323 dest = sout; 4324 } 4325 4326 /* Unlink `dest', just in case. It's okay if this provokes a 4327 ENOENT error. */ 4328 if (unlink (dest) < 0 && existence_error (errno)) 4329 error (1, errno, "cannot remove %s", dest); 4330 if (mknod (dest, special_file, devnum) < 0) 4331 error (1, errno, "could not create special file %s", 4332 dest); 4333 #else 4334 error (1, 0, 4335 "cannot create %s: unable to create special files on this system", 4336 workfile); 4337 #endif 4338 } 4339 #endif 4340 else 4341 { 4342 /* Not a special file: write to WORKFILE or SOUT. */ 4343 if (workfile == NULL) 4344 { 4345 if (sout == RUN_TTY) 4346 ofp = stdout; 4347 else 4348 { 4349 /* Symbolic links should be removed before replacement, so that 4350 `fopen' doesn't follow the link and open the wrong file. */ 4351 if (islink (sout)) 4352 if (unlink_file (sout) < 0) 4353 error (1, errno, "cannot remove %s", sout); 4354 ofp = CVS_FOPEN (sout, expand == KFLAG_B ? "wb" : "w"); 4355 if (ofp == NULL) 4356 error (1, errno, "cannot open %s", sout); 4357 } 4358 } 4359 else 4360 { 4361 /* Output is supposed to go to WORKFILE, so we should open that 4362 file. Symbolic links should be removed first (see above). */ 4363 if (islink (workfile)) 4364 if (unlink_file (workfile) < 0) 4365 error (1, errno, "cannot remove %s", workfile); 4366 4367 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w"); 4368 4369 /* If the open failed because the existing workfile was not 4370 writable, try to chmod the file and retry the open. */ 4371 if (ofp == NULL && errno == EACCES 4372 && isfile (workfile) && !iswritable (workfile)) 4373 { 4374 xchmod (workfile, 1); 4375 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w"); 4376 } 4377 4378 if (ofp == NULL) 4379 { 4380 error (0, errno, "cannot open %s", workfile); 4381 if (free_value) 4382 free (value); 4383 return 1; 4384 } 4385 } 4386 4387 if (workfile == NULL && sout == RUN_TTY) 4388 { 4389 if (expand == KFLAG_B) 4390 cvs_output_binary (value, len); 4391 else 4392 { 4393 /* cvs_output requires the caller to check for zero 4394 length. */ 4395 if (len > 0) 4396 cvs_output (value, len); 4397 } 4398 } 4399 else 4400 { 4401 /* NT 4.0 is said to have trouble writing 2099999 bytes 4402 (for example) in a single fwrite. So break it down 4403 (there is no need to be writing that much at once 4404 anyway; it is possible that LARGEST_FWRITE should be 4405 somewhat larger for good performance, but for testing I 4406 want to start with a small value until/unless a bigger 4407 one proves useful). */ 4408 #define LARGEST_FWRITE 8192 4409 size_t nleft = len; 4410 size_t nstep = (len < LARGEST_FWRITE ? len : LARGEST_FWRITE); 4411 char *p = value; 4412 4413 while (nleft > 0) 4414 { 4415 if (fwrite (p, 1, nstep, ofp) != nstep) 4416 { 4417 error (0, errno, "cannot write %s", 4418 (workfile != NULL 4419 ? workfile 4420 : (sout != RUN_TTY ? sout : "stdout"))); 4421 if (free_value) 4422 free (value); 4423 return 1; 4424 } 4425 p += nstep; 4426 nleft -= nstep; 4427 if (nleft < nstep) 4428 nstep = nleft; 4429 } 4430 } 4431 } 4432 4433 if (free_value) 4434 free (value); 4435 4436 if (workfile != NULL) 4437 { 4438 int ret; 4439 4440 #ifdef PRESERVE_PERMISSIONS_SUPPORT 4441 if (!special_file && fclose (ofp) < 0) 4442 { 4443 error (0, errno, "cannot close %s", workfile); 4444 return 1; 4445 } 4446 4447 if (change_rcs_owner_or_group) 4448 { 4449 if (chown (workfile, rcs_owner, rcs_group) < 0) 4450 error (0, errno, "could not change owner or group of %s", 4451 workfile); 4452 } 4453 4454 ret = chmod (workfile, 4455 change_rcs_mode 4456 ? rcs_mode 4457 : sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH)); 4458 #else 4459 if (fclose (ofp) < 0) 4460 { 4461 error (0, errno, "cannot close %s", workfile); 4462 return 1; 4463 } 4464 4465 ret = chmod (workfile, 4466 sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH)); 4467 #endif 4468 if (ret < 0) 4469 { 4470 error (0, errno, "cannot change mode of file %s", 4471 workfile); 4472 } 4473 } 4474 else if (sout != RUN_TTY) 4475 { 4476 if ( 4477 #ifdef PRESERVE_PERMISSIONS_SUPPORT 4478 !special_file && 4479 #endif 4480 fclose (ofp) < 0) 4481 { 4482 error (0, errno, "cannot close %s", sout); 4483 return 1; 4484 } 4485 } 4486 4487 #ifdef PRESERVE_PERMISSIONS_SUPPORT 4488 /* If we are in the business of preserving hardlinks, then 4489 mark this file as having been checked out. */ 4490 if (preserve_perms && workfile != NULL) 4491 update_hardlink_info (workfile); 4492 #endif 4493 4494 return 0; 4495 } 4496 4497 static RCSVers *RCS_findlock_or_tip PROTO ((RCSNode *rcs)); 4498 4499 /* Find the delta currently locked by the user. From the `ci' man page: 4500 4501 "If rev is omitted, ci tries to derive the new revision 4502 number from the caller's last lock. If the caller has 4503 locked the tip revision of a branch, the new revision is 4504 appended to that branch. The new revision number is 4505 obtained by incrementing the tip revision number. If the 4506 caller locked a non-tip revision, a new branch is started 4507 at that revision by incrementing the highest branch number 4508 at that revision. The default initial branch and level 4509 numbers are 1. 4510 4511 If rev is omitted and the caller has no lock, but owns the 4512 file and locking is not set to strict, then the revision 4513 is appended to the default branch (normally the trunk; see 4514 the -b option of rcs(1))." 4515 4516 RCS_findlock_or_tip finds the unique revision locked by the caller 4517 and returns its delta node. If the caller has not locked any 4518 revisions (and is permitted to commit to an unlocked delta, as 4519 described above), return the tip of the default branch. */ 4520 4521 static RCSVers * 4522 RCS_findlock_or_tip (rcs) 4523 RCSNode *rcs; 4524 { 4525 char *user = getcaller(); 4526 Node *lock, *p; 4527 List *locklist; 4528 4529 /* Find unique delta locked by caller. This code is very similar 4530 to the code in RCS_unlock -- perhaps it could be abstracted 4531 into a RCS_findlock function. */ 4532 locklist = RCS_getlocks (rcs); 4533 lock = NULL; 4534 for (p = locklist->list->next; p != locklist->list; p = p->next) 4535 { 4536 if (STREQ (p->data, user)) 4537 { 4538 if (lock != NULL) 4539 { 4540 error (0, 0, "\ 4541 %s: multiple revisions locked by %s; please specify one", rcs->path, user); 4542 return NULL; 4543 } 4544 lock = p; 4545 } 4546 } 4547 4548 if (lock != NULL) 4549 { 4550 /* Found an old lock, but check that the revision still exists. */ 4551 p = findnode (rcs->versions, lock->key); 4552 if (p == NULL) 4553 { 4554 error (0, 0, "%s: can't unlock nonexistent revision %s", 4555 rcs->path, 4556 lock->key); 4557 return NULL; 4558 } 4559 return (RCSVers *) p->data; 4560 } 4561 4562 /* No existing lock. The RCS rule is that this is an error unless 4563 locking is nonstrict AND the file is owned by the current 4564 user. Trying to determine the latter is a portability nightmare 4565 in the face of NT, VMS, AFS, and other systems with non-unix-like 4566 ideas of users and owners. In the case of CVS, we should never get 4567 here (as long as the traditional behavior of making sure to call 4568 RCS_lock persists). Anyway, we skip the RCS error checks 4569 and just return the default branch or head. The reasoning is that 4570 those error checks are to make users lock before a checkin, and we do 4571 that in other ways if at all anyway (e.g. rcslock.pl). */ 4572 4573 p = findnode (rcs->versions, RCS_getbranch (rcs, rcs->branch, 0)); 4574 return (RCSVers *) p->data; 4575 } 4576 4577 /* Revision number string, R, must contain a `.'. 4578 Return a newly-malloc'd copy of the prefix of R up 4579 to but not including the final `.'. */ 4580 4581 static char * 4582 truncate_revnum (r) 4583 const char *r; 4584 { 4585 size_t len; 4586 char *new_r; 4587 char *dot = strrchr (r, '.'); 4588 4589 assert (dot); 4590 len = dot - r; 4591 new_r = xmalloc (len + 1); 4592 memcpy (new_r, r, len); 4593 *(new_r + len) = '\0'; 4594 return new_r; 4595 } 4596 4597 /* Revision number string, R, must contain a `.'. 4598 R must be writable. Replace the rightmost `.' in R with 4599 the NUL byte and return a pointer to that NUL byte. */ 4600 4601 static char * 4602 truncate_revnum_in_place (r) 4603 char *r; 4604 { 4605 char *dot = strrchr (r, '.'); 4606 assert (dot); 4607 *dot = '\0'; 4608 return dot; 4609 } 4610 4611 /* Revision number strings, R and S, must each contain a `.'. 4612 R and S must be writable and must have the same number of dots. 4613 Truncate R and S for the comparison, then restored them to their 4614 original state. 4615 Return the result (see compare_revnums) of comparing R and S 4616 ignoring differences in any component after the rightmost `.'. */ 4617 4618 static int 4619 compare_truncated_revnums (r, s) 4620 char *r; 4621 char *s; 4622 { 4623 char *r_dot = truncate_revnum_in_place (r); 4624 char *s_dot = truncate_revnum_in_place (s); 4625 int cmp; 4626 4627 assert (numdots (r) == numdots (s)); 4628 4629 cmp = compare_revnums (r, s); 4630 4631 *r_dot = '.'; 4632 *s_dot = '.'; 4633 4634 return cmp; 4635 } 4636 4637 /* Return a malloc'd copy of the string representing the highest branch 4638 number on BRANCHNODE. If there are no branches on BRANCHNODE, return NULL. 4639 FIXME: isn't the max rev always the last one? 4640 If so, we don't even need a loop. */ 4641 4642 static char *max_rev PROTO ((const RCSVers *)); 4643 4644 static char * 4645 max_rev (branchnode) 4646 const RCSVers *branchnode; 4647 { 4648 Node *head; 4649 Node *bp; 4650 char *max; 4651 4652 if (branchnode->branches == NULL) 4653 { 4654 return NULL; 4655 } 4656 4657 max = NULL; 4658 head = branchnode->branches->list; 4659 for (bp = head->next; bp != head; bp = bp->next) 4660 { 4661 if (max == NULL || compare_truncated_revnums (max, bp->key) < 0) 4662 { 4663 max = bp->key; 4664 } 4665 } 4666 assert (max); 4667 4668 return truncate_revnum (max); 4669 } 4670 4671 /* Create BRANCH in RCS's delta tree. BRANCH may be either a branch 4672 number or a revision number. In the former case, create the branch 4673 with the specified number; in the latter case, create a new branch 4674 rooted at node BRANCH with a higher branch number than any others. 4675 Return the number of the tip node on the new branch. */ 4676 4677 static char * 4678 RCS_addbranch (rcs, branch) 4679 RCSNode *rcs; 4680 const char *branch; 4681 { 4682 char *branchpoint, *newrevnum; 4683 Node *nodep, *bp; 4684 Node *marker; 4685 RCSVers *branchnode; 4686 4687 /* Append to end by default. */ 4688 marker = NULL; 4689 4690 branchpoint = xstrdup (branch); 4691 if ((numdots (branchpoint) & 1) == 0) 4692 { 4693 truncate_revnum_in_place (branchpoint); 4694 } 4695 4696 /* Find the branch rooted at BRANCHPOINT. */ 4697 nodep = findnode (rcs->versions, branchpoint); 4698 if (nodep == NULL) 4699 { 4700 error (0, 0, "%s: can't find branch point %s", rcs->path, branchpoint); 4701 free (branchpoint); 4702 return NULL; 4703 } 4704 free (branchpoint); 4705 branchnode = (RCSVers *) nodep->data; 4706 4707 /* If BRANCH was a full branch number, make sure it is higher than MAX. */ 4708 if ((numdots (branch) & 1) == 1) 4709 { 4710 if (branchnode->branches == NULL) 4711 { 4712 /* We have to create the first branch on this node, which means 4713 appending ".2" to the revision number. */ 4714 newrevnum = (char *) xmalloc (strlen (branch) + 3); 4715 strcpy (newrevnum, branch); 4716 strcat (newrevnum, ".2"); 4717 } 4718 else 4719 { 4720 char *max = max_rev (branchnode); 4721 assert (max); 4722 newrevnum = increment_revnum (max); 4723 free (max); 4724 } 4725 } 4726 else 4727 { 4728 newrevnum = xstrdup (branch); 4729 4730 if (branchnode->branches != NULL) 4731 { 4732 Node *head; 4733 Node *bp; 4734 4735 /* Find the position of this new branch in the sorted list 4736 of branches. */ 4737 head = branchnode->branches->list; 4738 for (bp = head->next; bp != head; bp = bp->next) 4739 { 4740 char *dot; 4741 int found_pos; 4742 4743 /* The existing list must be sorted on increasing revnum. */ 4744 assert (bp->next == head 4745 || compare_truncated_revnums (bp->key, 4746 bp->next->key) < 0); 4747 dot = truncate_revnum_in_place (bp->key); 4748 found_pos = (compare_revnums (branch, bp->key) < 0); 4749 *dot = '.'; 4750 4751 if (found_pos) 4752 { 4753 break; 4754 } 4755 } 4756 marker = bp; 4757 } 4758 } 4759 4760 newrevnum = (char *) xrealloc (newrevnum, strlen (newrevnum) + 3); 4761 strcat (newrevnum, ".1"); 4762 4763 /* Add this new revision number to BRANCHPOINT's branches list. */ 4764 if (branchnode->branches == NULL) 4765 branchnode->branches = getlist(); 4766 bp = getnode(); 4767 bp->key = xstrdup (newrevnum); 4768 4769 /* Append to the end of the list by default, that is, just before 4770 the header node, `list'. */ 4771 if (marker == NULL) 4772 marker = branchnode->branches->list; 4773 4774 { 4775 int fail; 4776 fail = insert_before (branchnode->branches, marker, bp); 4777 assert (!fail); 4778 } 4779 4780 return newrevnum; 4781 } 4782 4783 /* Check in to RCSFILE with revision REV (which must be greater than 4784 the largest revision) and message MESSAGE (which is checked for 4785 legality). If FLAGS & RCS_FLAGS_DEAD, check in a dead revision. 4786 If FLAGS & RCS_FLAGS_QUIET, tell ci to be quiet. If FLAGS & 4787 RCS_FLAGS_MODTIME, use the working file's modification time for the 4788 checkin time. WORKFILE is the working file to check in from, or 4789 NULL to use the usual RCS rules for deriving it from the RCSFILE. 4790 If FLAGS & RCS_FLAGS_KEEPFILE, don't unlink the working file; 4791 unlinking the working file is standard RCS behavior, but is rarely 4792 appropriate for CVS. 4793 4794 This function should almost exactly mimic the behavior of `rcs ci'. The 4795 principal point of difference is the support here for preserving file 4796 ownership and permissions in the delta nodes. This is not a clean 4797 solution -- precisely because it diverges from RCS's behavior -- but 4798 it doesn't seem feasible to do this anywhere else in the code. [-twp] 4799 4800 Return value is -1 for error (and errno is set to indicate the 4801 error), positive for error (and an error message has been printed), 4802 or zero for success. */ 4803 4804 int 4805 RCS_checkin (rcs, workfile, message, rev, flags) 4806 RCSNode *rcs; 4807 char *workfile; 4808 char *message; 4809 char *rev; 4810 int flags; 4811 { 4812 RCSVers *delta, *commitpt; 4813 Deltatext *dtext; 4814 Node *nodep; 4815 char *tmpfile, *changefile, *chtext; 4816 char *diffopts; 4817 size_t bufsize; 4818 int buflen, chtextlen; 4819 int status, checkin_quiet, allocated_workfile; 4820 struct tm *ftm; 4821 time_t modtime; 4822 int adding_branch = 0; 4823 #ifdef PRESERVE_PERMISSIONS_SUPPORT 4824 struct stat sb; 4825 #endif 4826 4827 commitpt = NULL; 4828 4829 if (rcs->flags & PARTIAL) 4830 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 4831 4832 /* Get basename of working file. Is there a library function to 4833 do this? I couldn't find one. -twp */ 4834 allocated_workfile = 0; 4835 if (workfile == NULL) 4836 { 4837 char *p; 4838 int extlen = strlen (RCSEXT); 4839 workfile = xstrdup (last_component (rcs->path)); 4840 p = workfile + (strlen (workfile) - extlen); 4841 assert (strncmp (p, RCSEXT, extlen) == 0); 4842 *p = '\0'; 4843 allocated_workfile = 1; 4844 } 4845 4846 /* If the filename is a symbolic link, follow it and replace it 4847 with the destination of the link. We need to do this before 4848 calling rcs_internal_lockfile, or else we won't put the lock in 4849 the right place. */ 4850 resolve_symlink (&(rcs->path)); 4851 4852 checkin_quiet = flags & RCS_FLAGS_QUIET; 4853 if (!checkin_quiet) 4854 { 4855 cvs_output (rcs->path, 0); 4856 cvs_output (" <-- ", 7); 4857 cvs_output (workfile, 0); 4858 cvs_output ("\n", 1); 4859 } 4860 4861 /* Create new delta node. */ 4862 delta = (RCSVers *) xmalloc (sizeof (RCSVers)); 4863 memset (delta, 0, sizeof (RCSVers)); 4864 delta->author = xstrdup (getcaller ()); 4865 if (flags & RCS_FLAGS_MODTIME) 4866 { 4867 struct stat ws; 4868 if (stat (workfile, &ws) < 0) 4869 { 4870 error (1, errno, "cannot stat %s", workfile); 4871 } 4872 modtime = ws.st_mtime; 4873 } 4874 else 4875 (void) time (&modtime); 4876 ftm = gmtime (&modtime); 4877 delta->date = (char *) xmalloc (MAXDATELEN); 4878 (void) sprintf (delta->date, DATEFORM, 4879 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), 4880 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, 4881 ftm->tm_min, ftm->tm_sec); 4882 if (flags & RCS_FLAGS_DEAD) 4883 { 4884 delta->state = xstrdup (RCSDEAD); 4885 delta->dead = 1; 4886 } 4887 else 4888 delta->state = xstrdup ("Exp"); 4889 4890 #ifdef PRESERVE_PERMISSIONS_SUPPORT 4891 /* If permissions should be preserved on this project, then 4892 save the permission info. */ 4893 if (preserve_perms) 4894 { 4895 Node *np; 4896 char buf[64]; /* static buffer should be safe: see usage. -twp */ 4897 4898 delta->other_delta = getlist(); 4899 4900 if (CVS_LSTAT (workfile, &sb) < 0) 4901 error (1, 1, "cannot lstat %s", workfile); 4902 4903 if (S_ISLNK (sb.st_mode)) 4904 { 4905 np = getnode(); 4906 np->type = RCSFIELD; 4907 np->key = xstrdup ("symlink"); 4908 np->data = xreadlink (workfile); 4909 addnode (delta->other_delta, np); 4910 } 4911 else 4912 { 4913 (void) sprintf (buf, "%u", sb.st_uid); 4914 np = getnode(); 4915 np->type = RCSFIELD; 4916 np->key = xstrdup ("owner"); 4917 np->data = xstrdup (buf); 4918 addnode (delta->other_delta, np); 4919 4920 (void) sprintf (buf, "%u", sb.st_gid); 4921 np = getnode(); 4922 np->type = RCSFIELD; 4923 np->key = xstrdup ("group"); 4924 np->data = xstrdup (buf); 4925 addnode (delta->other_delta, np); 4926 4927 (void) sprintf (buf, "%o", sb.st_mode & 07777); 4928 np = getnode(); 4929 np->type = RCSFIELD; 4930 np->key = xstrdup ("permissions"); 4931 np->data = xstrdup (buf); 4932 addnode (delta->other_delta, np); 4933 4934 /* Save device number. */ 4935 switch (sb.st_mode & S_IFMT) 4936 { 4937 case S_IFREG: break; 4938 case S_IFCHR: 4939 case S_IFBLK: 4940 #ifdef HAVE_ST_RDEV 4941 np = getnode(); 4942 np->type = RCSFIELD; 4943 np->key = xstrdup ("special"); 4944 sprintf (buf, "%s %lu", 4945 ((sb.st_mode & S_IFMT) == S_IFCHR 4946 ? "character" : "block"), 4947 (unsigned long) sb.st_rdev); 4948 np->data = xstrdup (buf); 4949 addnode (delta->other_delta, np); 4950 #else 4951 error (0, 0, 4952 "can't preserve %s: unable to save device files on this system", 4953 workfile); 4954 #endif 4955 break; 4956 4957 default: 4958 error (0, 0, "special file %s has unknown type", workfile); 4959 } 4960 4961 /* Save hardlinks. */ 4962 delta->hardlinks = list_linked_files_on_disk (workfile); 4963 } 4964 } 4965 #endif 4966 4967 /* Create a new deltatext node. */ 4968 dtext = (Deltatext *) xmalloc (sizeof (Deltatext)); 4969 memset (dtext, 0, sizeof (Deltatext)); 4970 4971 dtext->log = make_message_rcslegal (message); 4972 4973 /* If the delta tree is empty, then there's nothing to link the 4974 new delta into. So make a new delta tree, snarf the working 4975 file contents, and just write the new RCS file. */ 4976 if (rcs->head == NULL) 4977 { 4978 char *newrev; 4979 FILE *fout; 4980 4981 /* Figure out what the first revision number should be. */ 4982 if (rev == NULL || *rev == '\0') 4983 newrev = xstrdup ("1.1"); 4984 else if (numdots (rev) == 0) 4985 { 4986 newrev = (char *) xmalloc (strlen (rev) + 3); 4987 strcpy (newrev, rev); 4988 strcat (newrev, ".1"); 4989 } 4990 else 4991 newrev = xstrdup (rev); 4992 4993 /* Don't need to xstrdup NEWREV because it's already dynamic, and 4994 not used for anything else. (Don't need to free it, either.) */ 4995 rcs->head = newrev; 4996 delta->version = xstrdup (newrev); 4997 nodep = getnode(); 4998 nodep->type = RCSVERS; 4999 nodep->delproc = rcsvers_delproc; 5000 nodep->data = (char *) delta; 5001 nodep->key = delta->version; 5002 (void) addnode (rcs->versions, nodep); 5003 5004 dtext->version = xstrdup (newrev); 5005 bufsize = 0; 5006 #ifdef PRESERVE_PERMISSIONS_SUPPORT 5007 if (preserve_perms && !S_ISREG (sb.st_mode)) 5008 /* Pretend file is empty. */ 5009 bufsize = 0; 5010 else 5011 #endif 5012 get_file (workfile, workfile, 5013 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r", 5014 &dtext->text, &bufsize, &dtext->len); 5015 5016 if (!checkin_quiet) 5017 { 5018 cvs_output ("initial revision: ", 0); 5019 cvs_output (rcs->head, 0); 5020 cvs_output ("\n", 1); 5021 } 5022 5023 /* We are probably about to invalidate any cached file. */ 5024 rcsbuf_cache_close (); 5025 5026 fout = rcs_internal_lockfile (rcs->path); 5027 RCS_putadmin (rcs, fout); 5028 RCS_putdtree (rcs, rcs->head, fout); 5029 RCS_putdesc (rcs, fout); 5030 rcs->delta_pos = ftell (fout); 5031 if (rcs->delta_pos == -1) 5032 error (1, errno, "cannot ftell for %s", rcs->path); 5033 putdeltatext (fout, dtext); 5034 rcs_internal_unlockfile (fout, rcs->path); 5035 5036 if ((flags & RCS_FLAGS_KEEPFILE) == 0) 5037 { 5038 if (unlink_file (workfile) < 0) 5039 /* FIXME-update-dir: message does not include update_dir. */ 5040 error (0, errno, "cannot remove %s", workfile); 5041 } 5042 5043 if (!checkin_quiet) 5044 cvs_output ("done\n", 5); 5045 5046 status = 0; 5047 goto checkin_done; 5048 } 5049 5050 /* Derive a new revision number. From the `ci' man page: 5051 5052 "If rev is a revision number, it must be higher than the 5053 latest one on the branch to which rev belongs, or must 5054 start a new branch. 5055 5056 If rev is a branch rather than a revision number, the new 5057 revision is appended to that branch. The level number is 5058 obtained by incrementing the tip revision number of that 5059 branch. If rev indicates a non-existing branch, that 5060 branch is created with the initial revision numbered 5061 rev.1." 5062 5063 RCS_findlock_or_tip handles the case where REV is omitted. 5064 RCS 5.7 also permits REV to be "$" or to begin with a dot, but 5065 we do not address those cases -- every routine that calls 5066 RCS_checkin passes it a numeric revision. */ 5067 5068 if (rev == NULL || *rev == '\0') 5069 { 5070 /* Figure out where the commit point is by looking for locks. 5071 If the commit point is at the tip of a branch (or is the 5072 head of the delta tree), then increment its revision number 5073 to obtain the new revnum. Otherwise, start a new 5074 branch. */ 5075 commitpt = RCS_findlock_or_tip (rcs); 5076 if (commitpt == NULL) 5077 { 5078 status = 1; 5079 goto checkin_done; 5080 } 5081 else if (commitpt->next == NULL 5082 || STREQ (commitpt->version, rcs->head)) 5083 delta->version = increment_revnum (commitpt->version); 5084 else 5085 delta->version = RCS_addbranch (rcs, commitpt->version); 5086 } 5087 else 5088 { 5089 /* REV is either a revision number or a branch number. Find the 5090 tip of the target branch. */ 5091 char *branch, *tip, *newrev, *p; 5092 int dots, isrevnum; 5093 5094 assert (isdigit ((unsigned char) *rev)); 5095 5096 newrev = xstrdup (rev); 5097 dots = numdots (newrev); 5098 isrevnum = dots & 1; 5099 5100 branch = xstrdup (rev); 5101 if (isrevnum) 5102 { 5103 p = strrchr (branch, '.'); 5104 *p = '\0'; 5105 } 5106 5107 /* Find the tip of the target branch. If we got a one- or two-digit 5108 revision number, this will be the head of the tree. Exception: 5109 if rev is a single-field revision equal to the branch number of 5110 the trunk (usually "1") then we want to treat it like an ordinary 5111 branch revision. */ 5112 if (dots == 0) 5113 { 5114 tip = xstrdup (rcs->head); 5115 if (atoi (tip) != atoi (branch)) 5116 { 5117 newrev = (char *) xrealloc (newrev, strlen (newrev) + 3); 5118 strcat (newrev, ".1"); 5119 dots = isrevnum = 1; 5120 } 5121 } 5122 else if (dots == 1) 5123 tip = xstrdup (rcs->head); 5124 else 5125 tip = RCS_getbranch (rcs, branch, 1); 5126 5127 /* If the branch does not exist, and we were supplied an exact 5128 revision number, signal an error. Otherwise, if we were 5129 given only a branch number, create it and set COMMITPT to 5130 the branch point. */ 5131 if (tip == NULL) 5132 { 5133 if (isrevnum) 5134 { 5135 error (0, 0, "%s: can't find branch point %s", 5136 rcs->path, branch); 5137 free (branch); 5138 free (newrev); 5139 status = 1; 5140 goto checkin_done; 5141 } 5142 delta->version = RCS_addbranch (rcs, branch); 5143 if (!delta->version) 5144 { 5145 free (branch); 5146 free (newrev); 5147 status = 1; 5148 goto checkin_done; 5149 } 5150 adding_branch = 1; 5151 p = strrchr (branch, '.'); 5152 *p = '\0'; 5153 tip = xstrdup (branch); 5154 } 5155 else 5156 { 5157 if (isrevnum) 5158 { 5159 /* NEWREV must be higher than TIP. */ 5160 if (compare_revnums (tip, newrev) >= 0) 5161 { 5162 error (0, 0, 5163 "%s: revision %s too low; must be higher than %s", 5164 rcs->path, 5165 newrev, tip); 5166 free (branch); 5167 free (newrev); 5168 free (tip); 5169 status = 1; 5170 goto checkin_done; 5171 } 5172 delta->version = xstrdup (newrev); 5173 } 5174 else 5175 /* Just increment the tip number to get the new revision. */ 5176 delta->version = increment_revnum (tip); 5177 } 5178 5179 nodep = findnode (rcs->versions, tip); 5180 commitpt = (RCSVers *) nodep->data; 5181 5182 free (branch); 5183 free (newrev); 5184 free (tip); 5185 } 5186 5187 assert (delta->version != NULL); 5188 5189 /* If COMMITPT is locked by us, break the lock. If it's locked 5190 by someone else, signal an error. */ 5191 nodep = findnode (RCS_getlocks (rcs), commitpt->version); 5192 if (nodep != NULL) 5193 { 5194 if (! STREQ (nodep->data, delta->author)) 5195 { 5196 /* If we are adding a branch, then leave the old lock around. 5197 That is sensible in the sense that when adding a branch, 5198 we don't need to use the lock to tell us where to check 5199 in. It is fishy in the sense that if it is our own lock, 5200 we break it. However, this is the RCS 5.7 behavior (at 5201 the end of addbranch in ci.c in RCS 5.7, it calls 5202 removelock only if it is our own lock, not someone 5203 else's). */ 5204 5205 if (!adding_branch) 5206 { 5207 error (0, 0, "%s: revision %s locked by %s", 5208 rcs->path, 5209 nodep->key, nodep->data); 5210 status = 1; 5211 goto checkin_done; 5212 } 5213 } 5214 else 5215 delnode (nodep); 5216 } 5217 5218 dtext->version = xstrdup (delta->version); 5219 5220 /* Obtain the change text for the new delta. If DELTA is to be the 5221 new head of the tree, then its change text should be the contents 5222 of the working file, and LEAFNODE's change text should be a diff. 5223 Else, DELTA's change text should be a diff between LEAFNODE and 5224 the working file. */ 5225 5226 tmpfile = cvs_temp_name(); 5227 status = RCS_checkout (rcs, NULL, commitpt->version, NULL, 5228 ((rcs->expand != NULL 5229 && STREQ (rcs->expand, "b")) 5230 ? "-kb" 5231 : "-ko"), 5232 tmpfile, 5233 (RCSCHECKOUTPROC)0, NULL); 5234 if (status != 0) 5235 error (1, 0, 5236 "could not check out revision %s of `%s'", 5237 commitpt->version, rcs->path); 5238 5239 bufsize = buflen = 0; 5240 chtext = NULL; 5241 chtextlen = 0; 5242 changefile = cvs_temp_name(); 5243 5244 /* Diff options should include --binary if the RCS file has -kb set 5245 in its `expand' field. */ 5246 diffopts = (rcs->expand != NULL && STREQ (rcs->expand, "b") 5247 ? "-a -n --binary" 5248 : "-a -n"); 5249 5250 if (STREQ (commitpt->version, rcs->head) && 5251 numdots (delta->version) == 1) 5252 { 5253 /* If this revision is being inserted on the trunk, the change text 5254 for the new delta should be the contents of the working file ... */ 5255 bufsize = 0; 5256 #ifdef PRESERVE_PERMISSIONS_SUPPORT 5257 if (preserve_perms && !S_ISREG (sb.st_mode)) 5258 /* Pretend file is empty. */ 5259 ; 5260 else 5261 #endif 5262 get_file (workfile, workfile, 5263 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r", 5264 &dtext->text, &bufsize, &dtext->len); 5265 5266 /* ... and the change text for the old delta should be a diff. */ 5267 commitpt->text = (Deltatext *) xmalloc (sizeof (Deltatext)); 5268 memset (commitpt->text, 0, sizeof (Deltatext)); 5269 5270 bufsize = 0; 5271 switch (diff_exec (workfile, tmpfile, diffopts, changefile)) 5272 { 5273 case 0: 5274 case 1: 5275 break; 5276 case -1: 5277 /* FIXME-update-dir: message does not include update_dir. */ 5278 error (1, errno, "error diffing %s", workfile); 5279 break; 5280 default: 5281 /* FIXME-update-dir: message does not include update_dir. */ 5282 error (1, 0, "error diffing %s", workfile); 5283 break; 5284 } 5285 5286 /* OK, the text file case here is really dumb. Logically 5287 speaking we want diff to read the files in text mode, 5288 convert them to the canonical form found in RCS files 5289 (which, we hope at least, is independent of OS--always 5290 bare linefeeds), and then work with change texts in that 5291 format. However, diff_exec both generates change 5292 texts and produces output for user purposes (e.g. patch.c), 5293 and there is no way to distinguish between the two cases. 5294 So we actually implement the text file case by writing the 5295 change text as a text file, then reading it as a text file. 5296 This should cause no harm, but doesn't strike me as 5297 immensely clean. */ 5298 get_file (changefile, changefile, 5299 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r", 5300 &commitpt->text->text, &bufsize, &commitpt->text->len); 5301 5302 /* If COMMITPT->TEXT->TEXT is NULL, it means that CHANGEFILE 5303 was empty and that there are no differences between revisions. 5304 In that event, we want to force RCS_rewrite to write an empty 5305 string for COMMITPT's change text. Leaving the change text 5306 field set NULL won't work, since that means "preserve the original 5307 change text for this delta." */ 5308 if (commitpt->text->text == NULL) 5309 { 5310 commitpt->text->text = xstrdup (""); 5311 commitpt->text->len = 0; 5312 } 5313 } 5314 else 5315 { 5316 /* This file is not being inserted at the head, but on a side 5317 branch somewhere. Make a diff from the previous revision 5318 to the working file. */ 5319 switch (diff_exec (tmpfile, workfile, diffopts, changefile)) 5320 { 5321 case 0: 5322 case 1: 5323 break; 5324 case -1: 5325 /* FIXME-update-dir: message does not include update_dir. */ 5326 error (1, errno, "error diffing %s", workfile); 5327 break; 5328 default: 5329 /* FIXME-update-dir: message does not include update_dir. */ 5330 error (1, 0, "error diffing %s", workfile); 5331 break; 5332 } 5333 /* See the comment above, at the other get_file invocation, 5334 regarding binary vs. text. */ 5335 get_file (changefile, changefile, 5336 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r", 5337 &dtext->text, &bufsize, 5338 &dtext->len); 5339 if (dtext->text == NULL) 5340 { 5341 dtext->text = xstrdup (""); 5342 dtext->len = 0; 5343 } 5344 } 5345 5346 /* Update DELTA linkage. It is important not to do this before 5347 the very end of RCS_checkin; if an error arises that forces 5348 us to abort checking in, we must not have malformed deltas 5349 partially linked into the tree. 5350 5351 If DELTA and COMMITPT are on different branches, do nothing -- 5352 DELTA is linked to the tree through COMMITPT->BRANCHES, and we 5353 don't want to change `next' pointers. 5354 5355 Otherwise, if the nodes are both on the trunk, link DELTA to 5356 COMMITPT; otherwise, link COMMITPT to DELTA. */ 5357 5358 if (numdots (commitpt->version) == numdots (delta->version)) 5359 { 5360 if (STREQ (commitpt->version, rcs->head)) 5361 { 5362 delta->next = rcs->head; 5363 rcs->head = xstrdup (delta->version); 5364 } 5365 else 5366 commitpt->next = xstrdup (delta->version); 5367 } 5368 5369 /* Add DELTA to RCS->VERSIONS. */ 5370 if (rcs->versions == NULL) 5371 rcs->versions = getlist(); 5372 nodep = getnode(); 5373 nodep->type = RCSVERS; 5374 nodep->delproc = rcsvers_delproc; 5375 nodep->data = (char *) delta; 5376 nodep->key = delta->version; 5377 (void) addnode (rcs->versions, nodep); 5378 5379 /* Write the new RCS file, inserting the new delta at COMMITPT. */ 5380 if (!checkin_quiet) 5381 { 5382 cvs_output ("new revision: ", 14); 5383 cvs_output (delta->version, 0); 5384 cvs_output ("; previous revision: ", 21); 5385 cvs_output (commitpt->version, 0); 5386 cvs_output ("\n", 1); 5387 } 5388 5389 RCS_rewrite (rcs, dtext, commitpt->version); 5390 5391 if ((flags & RCS_FLAGS_KEEPFILE) == 0) 5392 { 5393 if (unlink_file (workfile) < 0) 5394 /* FIXME-update-dir: message does not include update_dir. */ 5395 error (1, errno, "cannot remove %s", workfile); 5396 } 5397 if (unlink_file (tmpfile) < 0) 5398 error (0, errno, "cannot remove %s", tmpfile); 5399 free (tmpfile); 5400 if (unlink_file (changefile) < 0) 5401 error (0, errno, "cannot remove %s", changefile); 5402 free (changefile); 5403 5404 if (!checkin_quiet) 5405 cvs_output ("done\n", 5); 5406 5407 checkin_done: 5408 if (allocated_workfile) 5409 free (workfile); 5410 5411 if (commitpt != NULL && commitpt->text != NULL) 5412 { 5413 freedeltatext (commitpt->text); 5414 commitpt->text = NULL; 5415 } 5416 5417 freedeltatext (dtext); 5418 if (status != 0) 5419 free_rcsvers_contents (delta); 5420 5421 return status; 5422 } 5423 5424 /* This structure is passed between RCS_cmp_file and cmp_file_buffer. */ 5425 5426 struct cmp_file_data 5427 { 5428 const char *filename; 5429 FILE *fp; 5430 int different; 5431 }; 5432 5433 /* Compare the contents of revision REV of RCS file RCS with the 5434 contents of the file FILENAME. OPTIONS is a string for the keyword 5435 expansion options. Return 0 if the contents of the revision are 5436 the same as the contents of the file, 1 if they are different. */ 5437 5438 int 5439 RCS_cmp_file (rcs, rev, options, filename) 5440 RCSNode *rcs; 5441 char *rev; 5442 char *options; 5443 const char *filename; 5444 { 5445 int binary; 5446 FILE *fp; 5447 struct cmp_file_data data; 5448 int retcode; 5449 5450 if (options != NULL && options[0] != '\0') 5451 binary = STREQ (options, "-kb"); 5452 else 5453 { 5454 char *expand; 5455 5456 expand = RCS_getexpand (rcs); 5457 if (expand != NULL && STREQ (expand, "b")) 5458 binary = 1; 5459 else 5460 binary = 0; 5461 } 5462 5463 #ifdef PRESERVE_PERMISSIONS_SUPPORT 5464 /* If CVS is to deal properly with special files (when 5465 PreservePermissions is on), the best way is to check out the 5466 revision to a temporary file and call `xcmp' on the two disk 5467 files. xcmp needs to handle non-regular files properly anyway, 5468 so calling it simplifies RCS_cmp_file. We *could* just yank 5469 the delta node out of the version tree and look for device 5470 numbers, but writing to disk and calling xcmp is a better 5471 abstraction (therefore probably more robust). -twp */ 5472 5473 if (preserve_perms) 5474 { 5475 char *tmp; 5476 5477 tmp = cvs_temp_name(); 5478 retcode = RCS_checkout(rcs, NULL, rev, NULL, options, tmp, NULL, NULL); 5479 if (retcode != 0) 5480 return 1; 5481 5482 retcode = xcmp (tmp, filename); 5483 if (CVS_UNLINK (tmp) < 0) 5484 error (0, errno, "cannot remove %s", tmp); 5485 free (tmp); 5486 return retcode; 5487 } 5488 else 5489 #endif 5490 { 5491 fp = CVS_FOPEN (filename, binary ? FOPEN_BINARY_READ : "r"); 5492 if (fp == NULL) 5493 /* FIXME-update-dir: should include update_dir in message. */ 5494 error (1, errno, "cannot open file %s for comparing", filename); 5495 5496 data.filename = filename; 5497 data.fp = fp; 5498 data.different = 0; 5499 5500 retcode = RCS_checkout (rcs, (char *) NULL, rev, (char *) NULL, 5501 options, RUN_TTY, cmp_file_buffer, 5502 (void *) &data); 5503 5504 /* If we have not yet found a difference, make sure that we are at 5505 the end of the file. */ 5506 if (! data.different) 5507 { 5508 if (getc (fp) != EOF) 5509 data.different = 1; 5510 } 5511 5512 fclose (fp); 5513 5514 if (retcode != 0) 5515 return 1; 5516 5517 return data.different; 5518 } 5519 } 5520 5521 /* This is a subroutine of RCS_cmp_file. It is passed to 5522 RCS_checkout. */ 5523 5524 #define CMP_BUF_SIZE (8 * 1024) 5525 5526 static void 5527 cmp_file_buffer (callerdat, buffer, len) 5528 void *callerdat; 5529 const char *buffer; 5530 size_t len; 5531 { 5532 struct cmp_file_data *data = (struct cmp_file_data *) callerdat; 5533 char *filebuf; 5534 5535 /* If we've already found a difference, we don't need to check 5536 further. */ 5537 if (data->different) 5538 return; 5539 5540 filebuf = xmalloc (len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len); 5541 5542 while (len > 0) 5543 { 5544 size_t checklen; 5545 5546 checklen = len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len; 5547 if (fread (filebuf, 1, checklen, data->fp) != checklen) 5548 { 5549 if (ferror (data->fp)) 5550 error (1, errno, "cannot read file %s for comparing", 5551 data->filename); 5552 data->different = 1; 5553 free (filebuf); 5554 return; 5555 } 5556 5557 if (memcmp (filebuf, buffer, checklen) != 0) 5558 { 5559 data->different = 1; 5560 free (filebuf); 5561 return; 5562 } 5563 5564 buffer += checklen; 5565 len -= checklen; 5566 } 5567 5568 free (filebuf); 5569 } 5570 5571 /* For RCS file RCS, make symbolic tag TAG point to revision REV. 5572 This validates that TAG is OK for a user to use. Return value is 5573 -1 for error (and errno is set to indicate the error), positive for 5574 error (and an error message has been printed), or zero for success. */ 5575 5576 int 5577 RCS_settag (rcs, tag, rev) 5578 RCSNode *rcs; 5579 const char *tag; 5580 const char *rev; 5581 { 5582 List *symbols; 5583 Node *node; 5584 5585 if (rcs->flags & PARTIAL) 5586 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 5587 5588 /* FIXME: This check should be moved to RCS_check_tag. There is no 5589 reason for it to be here. */ 5590 if (STREQ (tag, TAG_BASE) 5591 || STREQ (tag, TAG_HEAD)) 5592 { 5593 /* Print the name of the tag might be considered redundant 5594 with the caller, which also prints it. Perhaps this helps 5595 clarify why the tag name is considered reserved, I don't 5596 know. */ 5597 error (0, 0, "Attempt to add reserved tag name %s", tag); 5598 return 1; 5599 } 5600 5601 /* A revision number of NULL means use the head or default branch. 5602 If rev is not NULL, it may be a symbolic tag or branch number; 5603 expand it to the correct numeric revision or branch head. */ 5604 if (rev == NULL) 5605 rev = rcs->branch ? rcs->branch : rcs->head; 5606 5607 /* At this point rcs->symbol_data may not have been parsed. 5608 Calling RCS_symbols will force it to be parsed into a list 5609 which we can easily manipulate. */ 5610 symbols = RCS_symbols (rcs); 5611 if (symbols == NULL) 5612 { 5613 symbols = getlist (); 5614 rcs->symbols = symbols; 5615 } 5616 node = findnode (symbols, tag); 5617 if (node != NULL) 5618 { 5619 free (node->data); 5620 node->data = xstrdup (rev); 5621 } 5622 else 5623 { 5624 node = getnode (); 5625 node->key = xstrdup (tag); 5626 node->data = xstrdup (rev); 5627 (void) addnode_at_front (symbols, node); 5628 } 5629 5630 return 0; 5631 } 5632 5633 /* Delete the symbolic tag TAG from the RCS file RCS. Return 0 if 5634 the tag was found (and removed), or 1 if it was not present. (In 5635 either case, the tag will no longer be in RCS->SYMBOLS.) */ 5636 5637 int 5638 RCS_deltag (rcs, tag) 5639 RCSNode *rcs; 5640 const char *tag; 5641 { 5642 List *symbols; 5643 Node *node; 5644 if (rcs->flags & PARTIAL) 5645 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 5646 5647 symbols = RCS_symbols (rcs); 5648 if (symbols == NULL) 5649 return 1; 5650 5651 node = findnode (symbols, tag); 5652 if (node == NULL) 5653 return 1; 5654 5655 delnode (node); 5656 5657 return 0; 5658 } 5659 5660 /* Set the default branch of RCS to REV. */ 5661 5662 int 5663 RCS_setbranch (rcs, rev) 5664 RCSNode *rcs; 5665 const char *rev; 5666 { 5667 if (rcs->flags & PARTIAL) 5668 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 5669 5670 if (rev && ! *rev) 5671 rev = NULL; 5672 5673 if (rev == NULL && rcs->branch == NULL) 5674 return 0; 5675 if (rev != NULL && rcs->branch != NULL && STREQ (rev, rcs->branch)) 5676 return 0; 5677 5678 if (rcs->branch != NULL) 5679 free (rcs->branch); 5680 rcs->branch = xstrdup (rev); 5681 5682 return 0; 5683 } 5684 5685 /* Lock revision REV. LOCK_QUIET is 1 to suppress output. FIXME: 5686 Most of the callers only call us because RCS_checkin still tends to 5687 like a lock (a relic of old behavior inherited from the RCS ci 5688 program). If we clean this up, only "cvs admin -l" will still need 5689 to call RCS_lock. */ 5690 5691 /* FIXME-twp: if a lock owned by someone else is broken, should this 5692 send mail to the lock owner? Prompt user? It seems like such an 5693 obscure situation for CVS as almost not worth worrying much 5694 about. */ 5695 5696 int 5697 RCS_lock (rcs, rev, lock_quiet) 5698 RCSNode *rcs; 5699 const char *rev; 5700 int lock_quiet; 5701 { 5702 List *locks; 5703 Node *p; 5704 char *user; 5705 char *xrev = NULL; 5706 5707 if (rcs->flags & PARTIAL) 5708 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 5709 5710 locks = RCS_getlocks (rcs); 5711 if (locks == NULL) 5712 locks = rcs->locks = getlist(); 5713 user = getcaller(); 5714 5715 /* A revision number of NULL means lock the head or default branch. */ 5716 if (rev == NULL) 5717 xrev = RCS_head (rcs); 5718 5719 /* If rev is a branch number, lock the latest revision on that 5720 branch. I think that if the branch doesn't exist, it's 5721 okay to return 0 -- that just means that the branch is new, 5722 so we don't need to lock it anyway. -twp */ 5723 else if (RCS_nodeisbranch (rcs, rev)) 5724 { 5725 xrev = RCS_getbranch (rcs, (char *) rev, 1); 5726 if (xrev == NULL) 5727 { 5728 if (!lock_quiet) 5729 error (0, 0, "%s: branch %s absent", rcs->path, rev); 5730 return 1; 5731 } 5732 } 5733 5734 if (xrev == NULL) 5735 xrev = xstrdup (rev); 5736 5737 /* Make sure that the desired revision exists. Technically, 5738 we can update the locks list without even checking this, 5739 but RCS 5.7 did this. And it can't hurt. */ 5740 if (findnode (rcs->versions, xrev) == NULL) 5741 { 5742 if (!lock_quiet) 5743 error (0, 0, "%s: revision %s absent", rcs->path, xrev); 5744 free (xrev); 5745 return 1; 5746 } 5747 5748 /* Is this rev already locked? */ 5749 p = findnode (locks, xrev); 5750 if (p != NULL) 5751 { 5752 if (STREQ (p->data, user)) 5753 { 5754 /* We already own the lock on this revision, so do nothing. */ 5755 free (xrev); 5756 return 0; 5757 } 5758 5759 #if 0 5760 /* Well, first of all, "rev" below should be "xrev" to avoid 5761 core dumps. But more importantly, should we really be 5762 breaking the lock unconditionally? What CVS 1.9 does (via 5763 RCS) is to prompt "Revision 1.1 is already locked by fred. 5764 Do you want to break the lock? [ny](n): ". Well, we don't 5765 want to interact with the user (certainly not at the 5766 server/protocol level, and probably not in the command-line 5767 client), but isn't it more sensible to give an error and 5768 let the user run "cvs admin -u" if they want to break the 5769 lock? */ 5770 5771 /* Break the lock. */ 5772 if (!lock_quiet) 5773 { 5774 cvs_output (rev, 0); 5775 cvs_output (" unlocked\n", 0); 5776 } 5777 delnode (p); 5778 #else 5779 error (1, 0, "Revision %s is already locked by %s", xrev, p->data); 5780 #endif 5781 } 5782 5783 /* Create a new lock. */ 5784 p = getnode(); 5785 p->key = xrev; /* already xstrdupped */ 5786 p->data = xstrdup (getcaller()); 5787 (void) addnode_at_front (locks, p); 5788 5789 if (!lock_quiet) 5790 { 5791 cvs_output (xrev, 0); 5792 cvs_output (" locked\n", 0); 5793 } 5794 5795 return 0; 5796 } 5797 5798 /* Unlock revision REV. UNLOCK_QUIET is 1 to suppress output. FIXME: 5799 Like RCS_lock, this can become a no-op if we do the checkin 5800 ourselves. 5801 5802 If REV is not null and is locked by someone else, break their 5803 lock and notify them. It is an open issue whether RCS_unlock 5804 queries the user about whether or not to break the lock. */ 5805 5806 int 5807 RCS_unlock (rcs, rev, unlock_quiet) 5808 RCSNode *rcs; 5809 const char *rev; 5810 int unlock_quiet; 5811 { 5812 Node *lock; 5813 List *locks; 5814 char *user; 5815 char *xrev = NULL; 5816 5817 user = getcaller(); 5818 if (rcs->flags & PARTIAL) 5819 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 5820 5821 /* If rev is NULL, unlock the latest revision (first in 5822 rcs->locks) held by the caller. */ 5823 if (rev == NULL) 5824 { 5825 Node *p; 5826 5827 /* No-ops: attempts to unlock an empty tree or an unlocked file. */ 5828 if (rcs->head == NULL) 5829 { 5830 if (!unlock_quiet) 5831 cvs_outerr ("can't unlock an empty tree\n", 0); 5832 return 0; 5833 } 5834 5835 locks = RCS_getlocks (rcs); 5836 if (locks == NULL) 5837 { 5838 if (!unlock_quiet) 5839 cvs_outerr ("No locks are set.\n", 0); 5840 return 0; 5841 } 5842 5843 lock = NULL; 5844 for (p = locks->list->next; p != locks->list; p = p->next) 5845 { 5846 if (lock != NULL) 5847 { 5848 if (!unlock_quiet) 5849 error (0, 0, "\ 5850 %s: multiple revisions locked by %s; please specify one", rcs->path, user); 5851 return 1; 5852 } 5853 lock = p; 5854 } 5855 if (lock == NULL) 5856 return 0; /* no lock found, ergo nothing to do */ 5857 xrev = xstrdup (lock->key); 5858 } 5859 else if (RCS_nodeisbranch (rcs, rev)) 5860 { 5861 /* If rev is a branch number, unlock the latest revision on that 5862 branch. */ 5863 xrev = RCS_getbranch (rcs, (char *) rev, 1); 5864 if (xrev == NULL) 5865 { 5866 error (0, 0, "%s: branch %s absent", rcs->path, rev); 5867 return 1; 5868 } 5869 } 5870 else 5871 /* REV is an exact revision number. */ 5872 xrev = xstrdup (rev); 5873 5874 lock = findnode (RCS_getlocks (rcs), xrev); 5875 if (lock == NULL) 5876 { 5877 /* This revision isn't locked. */ 5878 free (xrev); 5879 return 0; 5880 } 5881 5882 if (! STREQ (lock->data, user)) 5883 { 5884 /* If the revision is locked by someone else, notify 5885 them. Note that this shouldn't ever happen if RCS_unlock 5886 is called with a NULL revision, since that means "whatever 5887 revision is currently locked by the caller." */ 5888 char *repos, *workfile; 5889 repos = xstrdup (rcs->path); 5890 workfile = strrchr (repos, '/'); 5891 *workfile++ = '\0'; 5892 notify_do ('C', workfile, user, NULL, NULL, repos); 5893 free (repos); 5894 } 5895 5896 delnode (lock); 5897 if (!unlock_quiet) 5898 { 5899 cvs_output (xrev, 0); 5900 cvs_output (" unlocked\n", 0); 5901 } 5902 5903 free (xrev); 5904 return 0; 5905 } 5906 5907 /* Add USER to the access list of RCS. Do nothing if already present. 5908 FIXME-twp: check syntax of USER to make sure it's a valid id. */ 5909 5910 void 5911 RCS_addaccess (rcs, user) 5912 RCSNode *rcs; 5913 char *user; 5914 { 5915 char *access, *a; 5916 5917 if (rcs->flags & PARTIAL) 5918 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 5919 5920 if (rcs->access == NULL) 5921 rcs->access = xstrdup (user); 5922 else 5923 { 5924 access = xstrdup (rcs->access); 5925 for (a = strtok (access, " "); a != NULL; a = strtok (NULL, " ")) 5926 { 5927 if (STREQ (a, user)) 5928 { 5929 free (access); 5930 return; 5931 } 5932 } 5933 free (access); 5934 rcs->access = (char *) xrealloc 5935 (rcs->access, strlen (rcs->access) + strlen (user) + 2); 5936 strcat (rcs->access, " "); 5937 strcat (rcs->access, user); 5938 } 5939 } 5940 5941 /* Remove USER from the access list of RCS. */ 5942 5943 void 5944 RCS_delaccess (rcs, user) 5945 RCSNode *rcs; 5946 char *user; 5947 { 5948 char *p, *s; 5949 int ulen; 5950 5951 if (rcs->flags & PARTIAL) 5952 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 5953 5954 if (rcs->access == NULL) 5955 return; 5956 5957 if (user == NULL) 5958 { 5959 free (rcs->access); 5960 rcs->access = NULL; 5961 return; 5962 } 5963 5964 p = rcs->access; 5965 ulen = strlen (user); 5966 while (p != NULL) 5967 { 5968 if (strncmp (p, user, ulen) == 0 && (p[ulen] == '\0' || p[ulen] == ' ')) 5969 break; 5970 p = strchr (p, ' '); 5971 if (p != NULL) 5972 ++p; 5973 } 5974 5975 if (p == NULL) 5976 return; 5977 5978 s = p + ulen; 5979 while (*s != '\0') 5980 *p++ = *s++; 5981 *p = '\0'; 5982 } 5983 5984 char * 5985 RCS_getaccess (rcs) 5986 RCSNode *rcs; 5987 { 5988 if (rcs->flags & PARTIAL) 5989 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 5990 5991 return rcs->access; 5992 } 5993 5994 static int findtag PROTO ((Node *, void *)); 5995 5996 /* Return a nonzero value if the revision specified by ARG is found. */ 5997 5998 static int 5999 findtag (node, arg) 6000 Node *node; 6001 void *arg; 6002 { 6003 char *rev = (char *)arg; 6004 6005 if (STREQ (node->data, rev)) 6006 return 1; 6007 else 6008 return 0; 6009 } 6010 6011 /* Delete revisions between REV1 and REV2. The changes between the two 6012 revisions must be collapsed, and the result stored in the revision 6013 immediately preceding the lower one. Return 0 for successful completion, 6014 1 otherwise. 6015 6016 Solution: check out the revision preceding REV1 and the revision 6017 following REV2. Use call_diff to find aggregate diffs between 6018 these two revisions, and replace the delta text for the latter one 6019 with the new aggregate diff. Alternatively, we could write a 6020 function that takes two change texts and combines them to produce a 6021 new change text, without checking out any revs or calling diff. It 6022 would be hairy, but so, so cool. 6023 6024 If INCLUSIVE is set, then TAG1 and TAG2, if non-NULL, tell us to 6025 delete that revision as well (cvs admin -o tag1:tag2). If clear, 6026 delete up to but not including that revision (cvs admin -o tag1::tag2). 6027 This does not affect TAG1 or TAG2 being NULL; the meaning of the start 6028 point in ::tag2 and :tag2 is the same and likewise for end points. */ 6029 6030 int 6031 RCS_delete_revs (rcs, tag1, tag2, inclusive) 6032 RCSNode *rcs; 6033 char *tag1; 6034 char *tag2; 6035 int inclusive; 6036 { 6037 char *next; 6038 Node *nodep; 6039 RCSVers *revp = NULL; 6040 RCSVers *beforep; 6041 int status, found; 6042 int save_noexec; 6043 6044 char *branchpoint = NULL; 6045 char *rev1 = NULL; 6046 char *rev2 = NULL; 6047 int rev1_inclusive = inclusive; 6048 int rev2_inclusive = inclusive; 6049 char *before = NULL; 6050 char *after = NULL; 6051 char *beforefile = NULL; 6052 char *afterfile = NULL; 6053 char *outfile = NULL; 6054 6055 if (tag1 == NULL && tag2 == NULL) 6056 return 0; 6057 6058 /* Assume error status until everything is finished. */ 6059 status = 1; 6060 6061 /* Make sure both revisions exist. */ 6062 if (tag1 != NULL) 6063 { 6064 rev1 = RCS_gettag (rcs, tag1, 1, NULL); 6065 if (rev1 == NULL || (nodep = findnode (rcs->versions, rev1)) == NULL) 6066 { 6067 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag1); 6068 goto delrev_done; 6069 } 6070 } 6071 if (tag2 != NULL) 6072 { 6073 rev2 = RCS_gettag (rcs, tag2, 1, NULL); 6074 if (rev2 == NULL || (nodep = findnode (rcs->versions, rev2)) == NULL) 6075 { 6076 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag2); 6077 goto delrev_done; 6078 } 6079 } 6080 6081 /* If rev1 is on the trunk and rev2 is NULL, rev2 should be 6082 RCS->HEAD. (*Not* RCS_head(rcs), which may return rcs->branch 6083 instead.) We need to check this special case early, in order 6084 to make sure that rev1 and rev2 get ordered correctly. */ 6085 if (rev2 == NULL && numdots (rev1) == 1) 6086 { 6087 rev2 = xstrdup (rcs->head); 6088 rev2_inclusive = 1; 6089 } 6090 6091 if (rev2 == NULL) 6092 rev2_inclusive = 1; 6093 6094 if (rev1 != NULL && rev2 != NULL) 6095 { 6096 /* A range consisting of a branch number means the latest revision 6097 on that branch. */ 6098 if (RCS_isbranch (rcs, rev1) && STREQ (rev1, rev2)) 6099 rev1 = rev2 = RCS_getbranch (rcs, rev1, 0); 6100 else 6101 { 6102 /* Make sure REV1 and REV2 are ordered correctly (in the 6103 same order as the next field). For revisions on the 6104 trunk, REV1 should be higher than REV2; for branches, 6105 REV1 should be lower. */ 6106 /* Shouldn't we just be giving an error in the case where 6107 the user specifies the revisions in the wrong order 6108 (that is, always swap on the trunk, never swap on a 6109 branch, in the non-error cases)? It is not at all 6110 clear to me that users who specify -o 1.4:1.2 really 6111 meant to type -o 1.2:1.4, and the out of order usage 6112 has never been documented, either by cvs.texinfo or 6113 rcs(1). */ 6114 char *temp; 6115 int temp_inclusive; 6116 if (numdots (rev1) == 1) 6117 { 6118 if (compare_revnums (rev1, rev2) <= 0) 6119 { 6120 temp = rev2; 6121 rev2 = rev1; 6122 rev1 = temp; 6123 6124 temp_inclusive = rev2_inclusive; 6125 rev2_inclusive = rev1_inclusive; 6126 rev1_inclusive = temp_inclusive; 6127 } 6128 } 6129 else if (compare_revnums (rev1, rev2) > 0) 6130 { 6131 temp = rev2; 6132 rev2 = rev1; 6133 rev1 = temp; 6134 6135 temp_inclusive = rev2_inclusive; 6136 rev2_inclusive = rev1_inclusive; 6137 rev1_inclusive = temp_inclusive; 6138 } 6139 } 6140 } 6141 6142 /* Basically the same thing; make sure that the ordering is what we 6143 need. */ 6144 if (rev1 == NULL) 6145 { 6146 assert (rev2 != NULL); 6147 if (numdots (rev2) == 1) 6148 { 6149 /* Swap rev1 and rev2. */ 6150 int temp_inclusive; 6151 6152 rev1 = rev2; 6153 rev2 = NULL; 6154 6155 temp_inclusive = rev2_inclusive; 6156 rev2_inclusive = rev1_inclusive; 6157 rev1_inclusive = temp_inclusive; 6158 } 6159 } 6160 6161 /* Put the revision number preceding the first one to delete into 6162 BEFORE (where "preceding" means according to the next field). 6163 If the first revision to delete is the first revision on its 6164 branch (e.g. 1.3.2.1), BEFORE should be the node on the trunk 6165 at which the branch is rooted. If the first revision to delete 6166 is the head revision of the trunk, set BEFORE to NULL. 6167 6168 Note that because BEFORE may not be on the same branch as REV1, 6169 it is not very handy for navigating the revision tree. It's 6170 most useful just for checking out the revision preceding REV1. */ 6171 before = NULL; 6172 branchpoint = RCS_getbranchpoint (rcs, rev1 != NULL ? rev1 : rev2); 6173 if (rev1 == NULL) 6174 { 6175 rev1 = xstrdup (branchpoint); 6176 if (numdots (branchpoint) > 1) 6177 { 6178 char *bp; 6179 bp = strrchr (branchpoint, '.'); 6180 while (*--bp != '.') 6181 ; 6182 *bp = '\0'; 6183 /* Note that this is exclusive, always, because the inclusive 6184 flag doesn't affect the meaning when rev1 == NULL. */ 6185 before = xstrdup (branchpoint); 6186 *bp = '.'; 6187 } 6188 } 6189 else if (! STREQ (rev1, branchpoint)) 6190 { 6191 /* Walk deltas from BRANCHPOINT on, looking for REV1. */ 6192 nodep = findnode (rcs->versions, branchpoint); 6193 revp = (RCSVers *) nodep->data; 6194 while (revp->next != NULL && ! STREQ (revp->next, rev1)) 6195 { 6196 revp = (RCSVers *) nodep->data; 6197 nodep = findnode (rcs->versions, revp->next); 6198 } 6199 if (revp->next == NULL) 6200 { 6201 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, rev1); 6202 goto delrev_done; 6203 } 6204 if (rev1_inclusive) 6205 before = xstrdup (revp->version); 6206 else 6207 { 6208 before = rev1; 6209 nodep = findnode (rcs->versions, before); 6210 rev1 = xstrdup (((RCSVers *)nodep->data)->next); 6211 } 6212 } 6213 else if (!rev1_inclusive) 6214 { 6215 before = rev1; 6216 nodep = findnode (rcs->versions, before); 6217 rev1 = xstrdup (((RCSVers *)nodep->data)->next); 6218 } 6219 else if (numdots (branchpoint) > 1) 6220 { 6221 /* Example: rev1 is "1.3.2.1", branchpoint is "1.3.2.1". 6222 Set before to "1.3". */ 6223 char *bp; 6224 bp = strrchr (branchpoint, '.'); 6225 while (*--bp != '.') 6226 ; 6227 *bp = '\0'; 6228 before = xstrdup (branchpoint); 6229 *bp = '.'; 6230 } 6231 6232 /* If any revision between REV1 and REV2 is locked or is a branch point, 6233 we can't delete that revision and must abort. */ 6234 after = NULL; 6235 next = rev1; 6236 found = 0; 6237 while (!found && next != NULL) 6238 { 6239 nodep = findnode (rcs->versions, next); 6240 revp = (RCSVers *) nodep->data; 6241 6242 if (rev2 != NULL) 6243 found = STREQ (revp->version, rev2); 6244 next = revp->next; 6245 6246 if ((!found && next != NULL) || rev2_inclusive || rev2 == NULL) 6247 { 6248 if (findnode (RCS_getlocks (rcs), revp->version)) 6249 { 6250 error (0, 0, "%s: can't remove locked revision %s", 6251 rcs->path, 6252 revp->version); 6253 goto delrev_done; 6254 } 6255 if (revp->branches != NULL) 6256 { 6257 error (0, 0, "%s: can't remove branch point %s", 6258 rcs->path, 6259 revp->version); 6260 goto delrev_done; 6261 } 6262 6263 /* Doing this only for the :: syntax is for compatibility. 6264 See cvs.texinfo for somewhat more discussion. */ 6265 if (!inclusive 6266 && walklist (RCS_symbols (rcs), findtag, revp->version)) 6267 { 6268 /* We don't print which file this happens to on the theory 6269 that the caller will print the name of the file in a 6270 more useful fashion (fullname not rcs->path). */ 6271 error (0, 0, "cannot remove revision %s because it has tags", 6272 revp->version); 6273 goto delrev_done; 6274 } 6275 6276 /* It's misleading to print the `deleting revision' output 6277 here, since we may not actually delete these revisions. 6278 But that's how RCS does it. Bleah. Someday this should be 6279 moved to the point where the revs are actually marked for 6280 deletion. -twp */ 6281 cvs_output ("deleting revision ", 0); 6282 cvs_output (revp->version, 0); 6283 cvs_output ("\n", 1); 6284 } 6285 } 6286 6287 if (rev2 == NULL) 6288 ; 6289 else if (found) 6290 { 6291 if (rev2_inclusive) 6292 after = xstrdup (next); 6293 else 6294 after = xstrdup (revp->version); 6295 } 6296 else if (!inclusive) 6297 { 6298 /* In the case of an empty range, for example 1.2::1.2 or 6299 1.2::1.3, we want to just do nothing. */ 6300 status = 0; 6301 goto delrev_done; 6302 } 6303 else 6304 { 6305 /* This looks fishy in the cases where tag1 == NULL or tag2 == NULL. 6306 Are those cases really impossible? */ 6307 assert (tag1 != NULL); 6308 assert (tag2 != NULL); 6309 6310 error (0, 0, "%s: invalid revision range %s:%s", rcs->path, 6311 tag1, tag2); 6312 goto delrev_done; 6313 } 6314 6315 if (after == NULL && before == NULL) 6316 { 6317 /* The user is trying to delete all revisions. While an 6318 RCS file without revisions makes sense to RCS (e.g. the 6319 state after "rcs -i"), CVS has never been able to cope with 6320 it. So at least for now we just make this an error. 6321 6322 We don't include rcs->path in the message since "cvs admin" 6323 already printed "RCS file:" and the name. */ 6324 error (1, 0, "attempt to delete all revisions"); 6325 } 6326 6327 /* The conditionals at this point get really hairy. Here is the 6328 general idea: 6329 6330 IF before != NULL and after == NULL 6331 THEN don't check out any revisions, just delete them 6332 IF before == NULL and after != NULL 6333 THEN only check out after's revision, and use it for the new deltatext 6334 ELSE 6335 check out both revisions and diff -n them. This could use 6336 RCS_exec_rcsdiff with some changes, like being able 6337 to suppress diagnostic messages and to direct output. */ 6338 6339 if (after != NULL) 6340 { 6341 char *diffbuf; 6342 size_t bufsize, len; 6343 6344 #if defined (__CYGWIN32__) || defined (_WIN32) 6345 /* FIXME: This is an awful kludge, but at least until I have 6346 time to work on it a little more and test it, I'd rather 6347 give a fatal error than corrupt the file. I think that we 6348 need to use "-kb" and "--binary" and "rb" to get_file 6349 (probably can do it always, not just for binary files, if 6350 we are consistent between the RCS_checkout and the diff). */ 6351 { 6352 char *expand = RCS_getexpand (rcs); 6353 if (expand != NULL && STREQ (expand, "b")) 6354 error (1, 0, 6355 "admin -o not implemented yet for binary on this system"); 6356 } 6357 #endif 6358 6359 afterfile = cvs_temp_name(); 6360 status = RCS_checkout (rcs, NULL, after, NULL, "-ko", afterfile, 6361 (RCSCHECKOUTPROC)0, NULL); 6362 if (status > 0) 6363 goto delrev_done; 6364 6365 if (before == NULL) 6366 { 6367 /* We are deleting revisions from the head of the tree, 6368 so must create a new head. */ 6369 diffbuf = NULL; 6370 bufsize = 0; 6371 get_file (afterfile, afterfile, "r", &diffbuf, &bufsize, &len); 6372 6373 save_noexec = noexec; 6374 noexec = 0; 6375 if (unlink_file (afterfile) < 0) 6376 error (0, errno, "cannot remove %s", afterfile); 6377 noexec = save_noexec; 6378 6379 free (afterfile); 6380 afterfile = NULL; 6381 6382 free (rcs->head); 6383 rcs->head = xstrdup (after); 6384 } 6385 else 6386 { 6387 beforefile = cvs_temp_name(); 6388 status = RCS_checkout (rcs, NULL, before, NULL, "-ko", beforefile, 6389 (RCSCHECKOUTPROC)0, NULL); 6390 if (status > 0) 6391 goto delrev_done; 6392 6393 outfile = cvs_temp_name(); 6394 status = diff_exec (beforefile, afterfile, "-an", outfile); 6395 6396 if (status == 2) 6397 { 6398 /* Not sure we need this message; will diff_exec already 6399 have printed an error? */ 6400 error (0, 0, "%s: could not diff", rcs->path); 6401 status = 1; 6402 goto delrev_done; 6403 } 6404 6405 diffbuf = NULL; 6406 bufsize = 0; 6407 get_file (outfile, outfile, "r", &diffbuf, &bufsize, &len); 6408 } 6409 6410 /* Save the new change text in after's delta node. */ 6411 nodep = findnode (rcs->versions, after); 6412 revp = (RCSVers *) nodep->data; 6413 6414 assert (revp->text == NULL); 6415 6416 revp->text = (Deltatext *) xmalloc (sizeof (Deltatext)); 6417 memset ((Deltatext *) revp->text, 0, sizeof (Deltatext)); 6418 revp->text->version = xstrdup (revp->version); 6419 revp->text->text = diffbuf; 6420 revp->text->len = len; 6421 6422 /* If DIFFBUF is NULL, it means that OUTFILE is empty and that 6423 there are no differences between the two revisions. In that 6424 case, we want to force RCS_copydeltas to write an empty string 6425 for the new change text (leaving the text field set NULL 6426 means "preserve the original change text for this delta," so 6427 we don't want that). */ 6428 if (revp->text->text == NULL) 6429 revp->text->text = xstrdup (""); 6430 } 6431 6432 /* Walk through the revisions (again) to mark each one as 6433 outdated. (FIXME: would it be safe to use the `dead' field for 6434 this? Doubtful.) */ 6435 for (next = rev1; 6436 next != NULL && (after == NULL || ! STREQ (next, after)); 6437 next = revp->next) 6438 { 6439 nodep = findnode (rcs->versions, next); 6440 revp = (RCSVers *) nodep->data; 6441 revp->outdated = 1; 6442 } 6443 6444 /* Update delta links. If BEFORE == NULL, we're changing the 6445 head of the tree and don't need to update any `next' links. */ 6446 if (before != NULL) 6447 { 6448 /* If REV1 is the first node on its branch, then BEFORE is its 6449 root node (on the trunk) and we have to update its branches 6450 list. Otherwise, BEFORE is on the same branch as AFTER, and 6451 we can just change BEFORE's `next' field to point to AFTER. 6452 (This should be safe: since findnode manages its lists via 6453 the `hashnext' and `hashprev' fields, rather than `next' and 6454 `prev', mucking with `next' and `prev' should not corrupt the 6455 delta tree's internal structure. Much. -twp) */ 6456 6457 if (rev1 == NULL) 6458 /* beforep's ->next field already should be equal to after, 6459 which I think is always NULL in this case. */ 6460 ; 6461 else if (STREQ (rev1, branchpoint)) 6462 { 6463 nodep = findnode (rcs->versions, before); 6464 revp = (RCSVers *) nodep->data; 6465 nodep = revp->branches->list->next; 6466 while (nodep != revp->branches->list && 6467 ! STREQ (nodep->key, rev1)) 6468 nodep = nodep->next; 6469 assert (nodep != revp->branches->list); 6470 if (after == NULL) 6471 delnode (nodep); 6472 else 6473 { 6474 free (nodep->key); 6475 nodep->key = xstrdup (after); 6476 } 6477 } 6478 else 6479 { 6480 nodep = findnode (rcs->versions, before); 6481 beforep = (RCSVers *) nodep->data; 6482 free (beforep->next); 6483 beforep->next = xstrdup (after); 6484 } 6485 } 6486 6487 status = 0; 6488 6489 delrev_done: 6490 if (rev1 != NULL) 6491 free (rev1); 6492 if (rev2 != NULL) 6493 free (rev2); 6494 if (branchpoint != NULL) 6495 free (branchpoint); 6496 if (before != NULL) 6497 free (before); 6498 if (after != NULL) 6499 free (after); 6500 6501 save_noexec = noexec; 6502 noexec = 0; 6503 if (beforefile != NULL) 6504 { 6505 if (unlink_file (beforefile) < 0) 6506 error (0, errno, "cannot remove %s", beforefile); 6507 free (beforefile); 6508 } 6509 if (afterfile != NULL) 6510 { 6511 if (unlink_file (afterfile) < 0) 6512 error (0, errno, "cannot remove %s", afterfile); 6513 free (afterfile); 6514 } 6515 if (outfile != NULL) 6516 { 6517 if (unlink_file (outfile) < 0) 6518 error (0, errno, "cannot remove %s", outfile); 6519 free (outfile); 6520 } 6521 noexec = save_noexec; 6522 6523 return status; 6524 } 6525 6526 /* 6527 * TRUE if there exists a symbolic tag "tag" in file. 6528 */ 6529 int 6530 RCS_exist_tag (rcs, tag) 6531 RCSNode *rcs; 6532 char *tag; 6533 { 6534 6535 assert (rcs != NULL); 6536 6537 if (findnode (RCS_symbols (rcs), tag)) 6538 return 1; 6539 return 0; 6540 6541 } 6542 6543 /* 6544 * TRUE if RCS revision number "rev" exists. 6545 * This includes magic branch revisions, not found in rcs->versions, 6546 * but only in rcs->symbols, requiring a list walk to find them. 6547 * Take advantage of list walk callback function already used by 6548 * RCS_delete_revs, above. 6549 */ 6550 int 6551 RCS_exist_rev (rcs, rev) 6552 RCSNode *rcs; 6553 char *rev; 6554 { 6555 6556 assert (rcs != NULL); 6557 6558 if (rcs->flags & PARTIAL) 6559 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 6560 6561 if (findnode(rcs->versions, rev) != 0) 6562 return 1; 6563 6564 if (walklist (RCS_symbols(rcs), findtag, rev) != 0) 6565 return 1; 6566 6567 return 0; 6568 6569 } 6570 6571 6572 /* RCS_deltas and friends. Processing of the deltas in RCS files. */ 6573 6574 struct line 6575 { 6576 /* Text of this line. Part of the same malloc'd block as the struct 6577 line itself (we probably should use the "struct hack" (char text[1]) 6578 and save ourselves sizeof (char *) bytes). Does not include \n; 6579 instead has_newline indicates the presence or absence of \n. */ 6580 char *text; 6581 /* Length of this line, not counting \n if has_newline is true. */ 6582 size_t len; 6583 /* Version in which it was introduced. */ 6584 RCSVers *vers; 6585 /* Nonzero if this line ends with \n. This will always be true 6586 except possibly for the last line. */ 6587 int has_newline; 6588 /* Number of pointers to this struct line. */ 6589 int refcount; 6590 }; 6591 6592 struct linevector 6593 { 6594 /* How many lines in use for this linevector? */ 6595 unsigned int nlines; 6596 /* How many lines allocated for this linevector? */ 6597 unsigned int lines_alloced; 6598 /* Pointer to array containing a pointer to each line. */ 6599 struct line **vector; 6600 }; 6601 6602 static void linevector_init PROTO ((struct linevector *)); 6603 6604 /* Initialize *VEC to be a linevector with no lines. */ 6605 static void 6606 linevector_init (vec) 6607 struct linevector *vec; 6608 { 6609 vec->lines_alloced = 0; 6610 vec->nlines = 0; 6611 vec->vector = NULL; 6612 } 6613 6614 static int linevector_add PROTO ((struct linevector *vec, const char *text, 6615 size_t len, RCSVers *vers, 6616 unsigned int pos)); 6617 6618 /* Given some text TEXT, add each of its lines to VEC before line POS 6619 (where line 0 is the first line). The last line in TEXT may or may 6620 not be \n terminated. 6621 Set the version for each of the new lines to VERS. This 6622 function returns non-zero for success. It returns zero if the line 6623 number is out of range. 6624 6625 Each of the lines in TEXT are copied to space which is managed with 6626 the linevector (and freed by linevector_free). So the caller doesn't 6627 need to keep TEXT around after the call to this function. */ 6628 static int 6629 linevector_add (vec, text, len, vers, pos) 6630 struct linevector *vec; 6631 const char *text; 6632 size_t len; 6633 RCSVers *vers; 6634 unsigned int pos; 6635 { 6636 const char *textend; 6637 unsigned int i; 6638 unsigned int nnew; 6639 const char *p; 6640 const char *nextline_text; 6641 size_t nextline_len; 6642 int nextline_newline; 6643 struct line *q; 6644 6645 if (len == 0) 6646 return 1; 6647 6648 textend = text + len; 6649 6650 /* Count the number of lines we will need to add. */ 6651 nnew = 1; 6652 for (p = text; p < textend; ++p) 6653 if (*p == '\n' && p + 1 < textend) 6654 ++nnew; 6655 6656 /* Expand VEC->VECTOR if needed. */ 6657 if (vec->nlines + nnew >= vec->lines_alloced) 6658 { 6659 if (vec->lines_alloced == 0) 6660 vec->lines_alloced = 10; 6661 while (vec->nlines + nnew >= vec->lines_alloced) 6662 vec->lines_alloced *= 2; 6663 vec->vector = xrealloc (vec->vector, 6664 vec->lines_alloced * sizeof (*vec->vector)); 6665 } 6666 6667 /* Make room for the new lines in VEC->VECTOR. */ 6668 for (i = vec->nlines + nnew - 1; i >= pos + nnew; --i) 6669 vec->vector[i] = vec->vector[i - nnew]; 6670 6671 if (pos > vec->nlines) 6672 return 0; 6673 6674 /* Actually add the lines, to VEC->VECTOR. */ 6675 i = pos; 6676 nextline_text = text; 6677 nextline_newline = 0; 6678 for (p = text; p < textend; ++p) 6679 if (*p == '\n') 6680 { 6681 nextline_newline = 1; 6682 if (p + 1 == textend) 6683 /* If there are no characters beyond the last newline, we 6684 don't consider it another line. */ 6685 break; 6686 nextline_len = p - nextline_text; 6687 q = (struct line *) xmalloc (sizeof (struct line) + nextline_len); 6688 q->vers = vers; 6689 q->text = (char *)q + sizeof (struct line); 6690 q->len = nextline_len; 6691 q->has_newline = nextline_newline; 6692 q->refcount = 1; 6693 memcpy (q->text, nextline_text, nextline_len); 6694 vec->vector[i++] = q; 6695 6696 nextline_text = (char *)p + 1; 6697 nextline_newline = 0; 6698 } 6699 nextline_len = p - nextline_text; 6700 q = (struct line *) xmalloc (sizeof (struct line) + nextline_len); 6701 q->vers = vers; 6702 q->text = (char *)q + sizeof (struct line); 6703 q->len = nextline_len; 6704 q->has_newline = nextline_newline; 6705 q->refcount = 1; 6706 memcpy (q->text, nextline_text, nextline_len); 6707 vec->vector[i] = q; 6708 6709 vec->nlines += nnew; 6710 6711 return 1; 6712 } 6713 6714 static void linevector_delete PROTO ((struct linevector *, unsigned int, 6715 unsigned int)); 6716 6717 /* Remove NLINES lines from VEC at position POS (where line 0 is the 6718 first line). */ 6719 static void 6720 linevector_delete (vec, pos, nlines) 6721 struct linevector *vec; 6722 unsigned int pos; 6723 unsigned int nlines; 6724 { 6725 unsigned int i; 6726 unsigned int last; 6727 6728 last = vec->nlines - nlines; 6729 for (i = pos; i < pos + nlines; ++i) 6730 { 6731 if (--vec->vector[i]->refcount == 0) 6732 free (vec->vector[i]); 6733 } 6734 for (i = pos; i < last; ++i) 6735 vec->vector[i] = vec->vector[i + nlines]; 6736 vec->nlines -= nlines; 6737 } 6738 6739 static void linevector_copy PROTO ((struct linevector *, struct linevector *)); 6740 6741 /* Copy FROM to TO, copying the vectors but not the lines pointed to. */ 6742 static void 6743 linevector_copy (to, from) 6744 struct linevector *to; 6745 struct linevector *from; 6746 { 6747 unsigned int ln; 6748 6749 for (ln = 0; ln < to->nlines; ++ln) 6750 { 6751 if (--to->vector[ln]->refcount == 0) 6752 free (to->vector[ln]); 6753 } 6754 if (from->nlines > to->lines_alloced) 6755 { 6756 if (to->lines_alloced == 0) 6757 to->lines_alloced = 10; 6758 while (from->nlines > to->lines_alloced) 6759 to->lines_alloced *= 2; 6760 to->vector = (struct line **) 6761 xrealloc (to->vector, to->lines_alloced * sizeof (*to->vector)); 6762 } 6763 memcpy (to->vector, from->vector, 6764 from->nlines * sizeof (*to->vector)); 6765 to->nlines = from->nlines; 6766 for (ln = 0; ln < to->nlines; ++ln) 6767 ++to->vector[ln]->refcount; 6768 } 6769 6770 static void linevector_free PROTO ((struct linevector *)); 6771 6772 /* Free storage associated with linevector. */ 6773 static void 6774 linevector_free (vec) 6775 struct linevector *vec; 6776 { 6777 unsigned int ln; 6778 6779 if (vec->vector != NULL) 6780 { 6781 for (ln = 0; ln < vec->nlines; ++ln) 6782 if (--vec->vector[ln]->refcount == 0) 6783 free (vec->vector[ln]); 6784 6785 free (vec->vector); 6786 } 6787 } 6788 6789 static char *month_printname PROTO ((char *)); 6790 6791 /* Given a textual string giving the month (1-12), terminated with any 6792 character not recognized by atoi, return the 3 character name to 6793 print it with. I do not think it is a good idea to change these 6794 strings based on the locale; they are standard abbreviations (for 6795 example in rfc822 mail messages) which should be widely understood. 6796 Returns a pointer into static readonly storage. */ 6797 static char * 6798 month_printname (month) 6799 char *month; 6800 { 6801 static const char *const months[] = 6802 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 6803 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 6804 int mnum; 6805 6806 mnum = atoi (month); 6807 if (mnum < 1 || mnum > 12) 6808 return "???"; 6809 return (char *)months[mnum - 1]; 6810 } 6811 6812 static int 6813 apply_rcs_changes PROTO ((struct linevector *, const char *, size_t, 6814 const char *, RCSVers *, RCSVers *)); 6815 6816 /* Apply changes to the line vector LINES. DIFFBUF is a buffer of 6817 length DIFFLEN holding the change text from an RCS file (the output 6818 of diff -n). NAME is used in error messages. The VERS field of 6819 any line added is set to ADDVERS. The VERS field of any line 6820 deleted is set to DELVERS, unless DELVERS is NULL, in which case 6821 the VERS field of deleted lines is unchanged. The function returns 6822 non-zero if the change text is applied successfully. It returns 6823 zero if the change text does not appear to apply to LINES (e.g., a 6824 line number is invalid). If the change text is improperly 6825 formatted (e.g., it is not the output of diff -n), the function 6826 calls error with a status of 1, causing the program to exit. */ 6827 6828 static int 6829 apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers) 6830 struct linevector *lines; 6831 const char *diffbuf; 6832 size_t difflen; 6833 const char *name; 6834 RCSVers *addvers; 6835 RCSVers *delvers; 6836 { 6837 const char *p; 6838 const char *q; 6839 int op; 6840 /* The RCS format throws us for a loop in that the deltafrags (if 6841 we define a deltafrag as an add or a delete) need to be applied 6842 in reverse order. So we stick them into a linked list. */ 6843 struct deltafrag { 6844 enum {FRAG_ADD, FRAG_DELETE} type; 6845 unsigned long pos; 6846 unsigned long nlines; 6847 const char *new_lines; 6848 size_t len; 6849 struct deltafrag *next; 6850 }; 6851 struct deltafrag *dfhead; 6852 struct deltafrag *df; 6853 6854 dfhead = NULL; 6855 for (p = diffbuf; p != NULL && p < diffbuf + difflen; ) 6856 { 6857 op = *p++; 6858 if (op != 'a' && op != 'd') 6859 /* Can't just skip over the deltafrag, because the value 6860 of op determines the syntax. */ 6861 error (1, 0, "unrecognized operation '\\x%x' in %s", 6862 op, name); 6863 df = (struct deltafrag *) xmalloc (sizeof (struct deltafrag)); 6864 df->next = dfhead; 6865 dfhead = df; 6866 df->pos = strtoul (p, (char **) &q, 10); 6867 6868 if (p == q) 6869 error (1, 0, "number expected in %s", name); 6870 p = q; 6871 if (*p++ != ' ') 6872 error (1, 0, "space expected in %s", name); 6873 df->nlines = strtoul (p, (char **) &q, 10); 6874 if (p == q) 6875 error (1, 0, "number expected in %s", name); 6876 p = q; 6877 if (*p++ != '\012') 6878 error (1, 0, "linefeed expected in %s", name); 6879 6880 if (op == 'a') 6881 { 6882 unsigned int i; 6883 6884 df->type = FRAG_ADD; 6885 i = df->nlines; 6886 /* The text we want is the number of lines specified, or 6887 until the end of the value, whichever comes first (it 6888 will be the former except in the case where we are 6889 adding a line which does not end in newline). */ 6890 for (q = p; i != 0; ++q) 6891 if (*q == '\n') 6892 --i; 6893 else if (q == diffbuf + difflen) 6894 { 6895 if (i != 1) 6896 error (1, 0, "premature end of change in %s", name); 6897 else 6898 break; 6899 } 6900 6901 /* Stash away a pointer to the text we are adding. */ 6902 df->new_lines = p; 6903 df->len = q - p; 6904 6905 p = q; 6906 } 6907 else 6908 { 6909 /* Correct for the fact that line numbers in RCS files 6910 start with 1. */ 6911 --df->pos; 6912 6913 assert (op == 'd'); 6914 df->type = FRAG_DELETE; 6915 } 6916 } 6917 6918 for (df = dfhead; df != NULL;) 6919 { 6920 unsigned int ln; 6921 6922 switch (df->type) 6923 { 6924 case FRAG_ADD: 6925 if (! linevector_add (lines, df->new_lines, df->len, addvers, 6926 df->pos)) 6927 return 0; 6928 break; 6929 case FRAG_DELETE: 6930 if (df->pos > lines->nlines 6931 || df->pos + df->nlines > lines->nlines) 6932 return 0; 6933 if (delvers != NULL) 6934 for (ln = df->pos; ln < df->pos + df->nlines; ++ln) 6935 lines->vector[ln]->vers = delvers; 6936 linevector_delete (lines, df->pos, df->nlines); 6937 break; 6938 } 6939 df = df->next; 6940 free (dfhead); 6941 dfhead = df; 6942 } 6943 6944 return 1; 6945 } 6946 6947 /* Apply an RCS change text to a buffer. The function name starts 6948 with rcs rather than RCS because this does not take an RCSNode 6949 argument. NAME is used in error messages. TEXTBUF is the text 6950 buffer to change, and TEXTLEN is the size. DIFFBUF and DIFFLEN are 6951 the change buffer and size. The new buffer is returned in *RETBUF 6952 and *RETLEN. The new buffer is allocated by xmalloc. 6953 6954 Return 1 for success. On failure, call error and return 0. */ 6955 6956 int 6957 rcs_change_text (name, textbuf, textlen, diffbuf, difflen, retbuf, retlen) 6958 const char *name; 6959 char *textbuf; 6960 size_t textlen; 6961 const char *diffbuf; 6962 size_t difflen; 6963 char **retbuf; 6964 size_t *retlen; 6965 { 6966 struct linevector lines; 6967 int ret; 6968 6969 *retbuf = NULL; 6970 *retlen = 0; 6971 6972 linevector_init (&lines); 6973 6974 if (! linevector_add (&lines, textbuf, textlen, NULL, 0)) 6975 error (1, 0, "cannot initialize line vector"); 6976 6977 if (! apply_rcs_changes (&lines, diffbuf, difflen, name, NULL, NULL)) 6978 { 6979 error (0, 0, "invalid change text in %s", name); 6980 ret = 0; 6981 } 6982 else 6983 { 6984 char *p; 6985 size_t n; 6986 unsigned int ln; 6987 6988 n = 0; 6989 for (ln = 0; ln < lines.nlines; ++ln) 6990 /* 1 for \n */ 6991 n += lines.vector[ln]->len + 1; 6992 6993 p = xmalloc (n); 6994 *retbuf = p; 6995 6996 for (ln = 0; ln < lines.nlines; ++ln) 6997 { 6998 memcpy (p, lines.vector[ln]->text, lines.vector[ln]->len); 6999 p += lines.vector[ln]->len; 7000 if (lines.vector[ln]->has_newline) 7001 *p++ = '\n'; 7002 } 7003 7004 *retlen = p - *retbuf; 7005 assert (*retlen <= n); 7006 7007 ret = 1; 7008 } 7009 7010 linevector_free (&lines); 7011 7012 return ret; 7013 } 7014 7015 /* Walk the deltas in RCS to get to revision VERSION. 7016 7017 If OP is RCS_ANNOTATE, then write annotations using cvs_output. 7018 7019 If OP is RCS_FETCH, then put the contents of VERSION into a 7020 newly-malloc'd array and put a pointer to it in *TEXT. Each line 7021 is \n terminated; the caller is responsible for converting text 7022 files if desired. The total length is put in *LEN. 7023 7024 If FP is non-NULL, it should be a file descriptor open to the file 7025 RCS with file position pointing to the deltas. We close the file 7026 when we are done. 7027 7028 If LOG is non-NULL, then *LOG is set to the log message of VERSION, 7029 and *LOGLEN is set to the length of the log message. 7030 7031 On error, give a fatal error. */ 7032 7033 static void 7034 RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen) 7035 RCSNode *rcs; 7036 FILE *fp; 7037 struct rcsbuffer *rcsbuf; 7038 char *version; 7039 enum rcs_delta_op op; 7040 char **text; 7041 size_t *len; 7042 char **log; 7043 size_t *loglen; 7044 { 7045 struct rcsbuffer rcsbuf_local; 7046 char *branchversion; 7047 char *cpversion; 7048 char *key; 7049 char *value; 7050 size_t vallen; 7051 RCSVers *vers; 7052 RCSVers *prev_vers; 7053 RCSVers *trunk_vers; 7054 char *next; 7055 int ishead, isnext, isversion, onbranch; 7056 Node *node; 7057 struct linevector headlines; 7058 struct linevector curlines; 7059 struct linevector trunklines; 7060 int foundhead; 7061 7062 if (fp == NULL) 7063 { 7064 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf_local); 7065 rcsbuf = &rcsbuf_local; 7066 } 7067 7068 ishead = 1; 7069 vers = NULL; 7070 prev_vers = NULL; 7071 trunk_vers = NULL; 7072 next = NULL; 7073 onbranch = 0; 7074 foundhead = 0; 7075 7076 linevector_init (&curlines); 7077 linevector_init (&headlines); 7078 linevector_init (&trunklines); 7079 7080 /* We set BRANCHVERSION to the version we are currently looking 7081 for. Initially, this is the version on the trunk from which 7082 VERSION branches off. If VERSION is not a branch, then 7083 BRANCHVERSION is just VERSION. */ 7084 branchversion = xstrdup (version); 7085 cpversion = strchr (branchversion, '.'); 7086 if (cpversion != NULL) 7087 cpversion = strchr (cpversion + 1, '.'); 7088 if (cpversion != NULL) 7089 *cpversion = '\0'; 7090 7091 do { 7092 if (! rcsbuf_getrevnum (rcsbuf, &key)) 7093 error (1, 0, "unexpected EOF reading RCS file %s", rcs->path); 7094 7095 if (next != NULL && ! STREQ (next, key)) 7096 { 7097 /* This is not the next version we need. It is a branch 7098 version which we want to ignore. */ 7099 isnext = 0; 7100 isversion = 0; 7101 } 7102 else 7103 { 7104 isnext = 1; 7105 7106 /* look up the revision */ 7107 node = findnode (rcs->versions, key); 7108 if (node == NULL) 7109 error (1, 0, 7110 "mismatch in rcs file %s between deltas and deltatexts", 7111 rcs->path); 7112 7113 /* Stash the previous version. */ 7114 prev_vers = vers; 7115 7116 vers = (RCSVers *) node->data; 7117 next = vers->next; 7118 7119 /* Compare key and trunkversion now, because key points to 7120 storage controlled by rcsbuf_getkey. */ 7121 if (STREQ (branchversion, key)) 7122 isversion = 1; 7123 else 7124 isversion = 0; 7125 } 7126 7127 while (1) 7128 { 7129 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7130 error (1, 0, "%s does not appear to be a valid rcs file", 7131 rcs->path); 7132 7133 if (log != NULL 7134 && isversion 7135 && STREQ (key, "log") 7136 && STREQ (branchversion, version)) 7137 { 7138 *log = rcsbuf_valcopy (rcsbuf, value, 0, loglen); 7139 } 7140 7141 if (STREQ (key, "text")) 7142 { 7143 rcsbuf_valpolish (rcsbuf, value, 0, &vallen); 7144 if (ishead) 7145 { 7146 if (! linevector_add (&curlines, value, vallen, NULL, 0)) 7147 error (1, 0, "invalid rcs file %s", rcs->path); 7148 7149 ishead = 0; 7150 } 7151 else if (isnext) 7152 { 7153 if (! apply_rcs_changes (&curlines, value, vallen, 7154 rcs->path, 7155 onbranch ? vers : NULL, 7156 onbranch ? NULL : prev_vers)) 7157 error (1, 0, "invalid change text in %s", rcs->path); 7158 } 7159 break; 7160 } 7161 } 7162 7163 if (isversion) 7164 { 7165 /* This is either the version we want, or it is the 7166 branchpoint to the version we want. */ 7167 if (STREQ (branchversion, version)) 7168 { 7169 /* This is the version we want. */ 7170 linevector_copy (&headlines, &curlines); 7171 foundhead = 1; 7172 if (onbranch) 7173 { 7174 /* We have found this version by tracking up a 7175 branch. Restore back to the lines we saved 7176 when we left the trunk, and continue tracking 7177 down the trunk. */ 7178 onbranch = 0; 7179 vers = trunk_vers; 7180 next = vers->next; 7181 linevector_copy (&curlines, &trunklines); 7182 } 7183 } 7184 else 7185 { 7186 Node *p; 7187 7188 /* We need to look up the branch. */ 7189 onbranch = 1; 7190 7191 if (numdots (branchversion) < 2) 7192 { 7193 unsigned int ln; 7194 7195 /* We are leaving the trunk; save the current 7196 lines so that we can restore them when we 7197 continue tracking down the trunk. */ 7198 trunk_vers = vers; 7199 linevector_copy (&trunklines, &curlines); 7200 7201 /* Reset the version information we have 7202 accumulated so far. It only applies to the 7203 changes from the head to this version. */ 7204 for (ln = 0; ln < curlines.nlines; ++ln) 7205 curlines.vector[ln]->vers = NULL; 7206 } 7207 7208 /* The next version we want is the entry on 7209 VERS->branches which matches this branch. For 7210 example, suppose VERSION is 1.21.4.3 and 7211 BRANCHVERSION was 1.21. Then we look for an entry 7212 starting with "1.21.4" and we'll put it (probably 7213 1.21.4.1) in NEXT. We'll advance BRANCHVERSION by 7214 two dots (in this example, to 1.21.4.3). */ 7215 7216 if (vers->branches == NULL) 7217 error (1, 0, "missing expected branches in %s", 7218 rcs->path); 7219 *cpversion = '.'; 7220 ++cpversion; 7221 cpversion = strchr (cpversion, '.'); 7222 if (cpversion == NULL) 7223 error (1, 0, "version number confusion in %s", 7224 rcs->path); 7225 for (p = vers->branches->list->next; 7226 p != vers->branches->list; 7227 p = p->next) 7228 if (strncmp (p->key, branchversion, 7229 cpversion - branchversion) == 0) 7230 break; 7231 if (p == vers->branches->list) 7232 error (1, 0, "missing expected branch in %s", 7233 rcs->path); 7234 7235 next = p->key; 7236 7237 cpversion = strchr (cpversion + 1, '.'); 7238 if (cpversion != NULL) 7239 *cpversion = '\0'; 7240 } 7241 } 7242 if (op == RCS_FETCH && foundhead) 7243 break; 7244 } while (next != NULL); 7245 7246 free (branchversion); 7247 7248 rcsbuf_cache (rcs, rcsbuf); 7249 7250 if (! foundhead) 7251 error (1, 0, "could not find desired version %s in %s", 7252 version, rcs->path); 7253 7254 /* Now print out or return the data we have just computed. */ 7255 switch (op) 7256 { 7257 case RCS_ANNOTATE: 7258 { 7259 unsigned int ln; 7260 7261 for (ln = 0; ln < headlines.nlines; ++ln) 7262 { 7263 char buf[80]; 7264 /* Period which separates year from month in date. */ 7265 char *ym; 7266 /* Period which separates month from day in date. */ 7267 char *md; 7268 RCSVers *prvers; 7269 7270 prvers = headlines.vector[ln]->vers; 7271 if (prvers == NULL) 7272 prvers = vers; 7273 7274 sprintf (buf, "%-12s (%-8.8s ", 7275 prvers->version, 7276 prvers->author); 7277 cvs_output (buf, 0); 7278 7279 /* Now output the date. */ 7280 ym = strchr (prvers->date, '.'); 7281 if (ym == NULL) 7282 { 7283 /* ??- is an ANSI trigraph. The ANSI way to 7284 avoid it is \? but some pre ANSI compilers 7285 complain about the unrecognized escape 7286 sequence. Of course string concatenation 7287 ("??" "-???") is also an ANSI-ism. Testing 7288 __STDC__ seems to be a can of worms, since 7289 compilers do all kinds of things with it. */ 7290 cvs_output ("??", 0); 7291 cvs_output ("-???", 0); 7292 cvs_output ("-??", 0); 7293 } 7294 else 7295 { 7296 md = strchr (ym + 1, '.'); 7297 if (md == NULL) 7298 cvs_output ("??", 0); 7299 else 7300 cvs_output (md + 1, 2); 7301 7302 cvs_output ("-", 1); 7303 cvs_output (month_printname (ym + 1), 0); 7304 cvs_output ("-", 1); 7305 /* Only output the last two digits of the year. Our output 7306 lines are long enough as it is without printing the 7307 century. */ 7308 cvs_output (ym - 2, 2); 7309 } 7310 cvs_output ("): ", 0); 7311 if (headlines.vector[ln]->len != 0) 7312 cvs_output (headlines.vector[ln]->text, 7313 headlines.vector[ln]->len); 7314 cvs_output ("\n", 1); 7315 } 7316 } 7317 break; 7318 case RCS_FETCH: 7319 { 7320 char *p; 7321 size_t n; 7322 unsigned int ln; 7323 7324 assert (text != NULL); 7325 assert (len != NULL); 7326 7327 n = 0; 7328 for (ln = 0; ln < headlines.nlines; ++ln) 7329 /* 1 for \n */ 7330 n += headlines.vector[ln]->len + 1; 7331 p = xmalloc (n); 7332 *text = p; 7333 for (ln = 0; ln < headlines.nlines; ++ln) 7334 { 7335 memcpy (p, headlines.vector[ln]->text, 7336 headlines.vector[ln]->len); 7337 p += headlines.vector[ln]->len; 7338 if (headlines.vector[ln]->has_newline) 7339 *p++ = '\n'; 7340 } 7341 *len = p - *text; 7342 assert (*len <= n); 7343 } 7344 break; 7345 } 7346 7347 linevector_free (&curlines); 7348 linevector_free (&headlines); 7349 linevector_free (&trunklines); 7350 7351 return; 7352 } 7353 7354 /* Read the information for a single delta from the RCS buffer RCSBUF, 7355 whose name is RCSFILE. *KEYP and *VALP are either NULL, or the 7356 first key/value pair to read, as set by rcsbuf_getkey. Return NULL 7357 if there are no more deltas. Store the key/value pair which 7358 terminated the read in *KEYP and *VALP. */ 7359 7360 static RCSVers * 7361 getdelta (rcsbuf, rcsfile, keyp, valp) 7362 struct rcsbuffer *rcsbuf; 7363 char *rcsfile; 7364 char **keyp; 7365 char **valp; 7366 { 7367 RCSVers *vnode; 7368 char *key, *value, *cp; 7369 Node *kv; 7370 7371 /* Get revision number if it wasn't passed in. This uses 7372 rcsbuf_getkey because it doesn't croak when encountering 7373 unexpected input. As a result, we have to play unholy games 7374 with `key' and `value'. */ 7375 if (*keyp != NULL) 7376 { 7377 key = *keyp; 7378 value = *valp; 7379 } 7380 else 7381 { 7382 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7383 error (1, 0, "%s: unexpected EOF", rcsfile); 7384 } 7385 7386 /* Make sure that it is a revision number and not a cabbage 7387 or something. */ 7388 for (cp = key; 7389 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0'; 7390 cp++) 7391 /* do nothing */ ; 7392 /* Note that when comparing with RCSDATE, we are not massaging 7393 VALUE from the string found in the RCS file. This is OK since 7394 we know exactly what to expect. */ 7395 if (*cp != '\0' || strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) != 0) 7396 { 7397 *keyp = key; 7398 *valp = value; 7399 return NULL; 7400 } 7401 7402 vnode = (RCSVers *) xmalloc (sizeof (RCSVers)); 7403 memset (vnode, 0, sizeof (RCSVers)); 7404 7405 vnode->version = xstrdup (key); 7406 7407 /* Grab the value of the date from value. Note that we are not 7408 massaging VALUE from the string found in the RCS file. */ 7409 cp = value + (sizeof RCSDATE) - 1; /* skip the "date" keyword */ 7410 while (whitespace (*cp)) /* take space off front of value */ 7411 cp++; 7412 7413 vnode->date = xstrdup (cp); 7414 7415 /* Get author field. */ 7416 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7417 { 7418 error (1, 0, "unexpected end of file reading %s", rcsfile); 7419 } 7420 if (! STREQ (key, "author")) 7421 error (1, 0, "\ 7422 unable to parse %s; `author' not in the expected place", rcsfile); 7423 vnode->author = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL); 7424 7425 /* Get state field. */ 7426 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7427 { 7428 error (1, 0, "unexpected end of file reading %s", rcsfile); 7429 } 7430 if (! STREQ (key, "state")) 7431 error (1, 0, "\ 7432 unable to parse %s; `state' not in the expected place", rcsfile); 7433 vnode->state = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL); 7434 /* The value is optional, according to rcsfile(5). */ 7435 if (value != NULL && STREQ (value, "dead")) 7436 { 7437 vnode->dead = 1; 7438 } 7439 7440 /* Note that "branches" and "next" are in fact mandatory, according 7441 to doc/RCSFILES. */ 7442 7443 /* fill in the branch list (if any branches exist) */ 7444 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7445 { 7446 error (1, 0, "unexpected end of file reading %s", rcsfile); 7447 } 7448 if (STREQ (key, RCSDESC)) 7449 { 7450 *keyp = key; 7451 *valp = value; 7452 /* Probably could/should be a fatal error. */ 7453 error (0, 0, "warning: 'branches' keyword missing from %s", rcsfile); 7454 return vnode; 7455 } 7456 if (value != (char *) NULL) 7457 { 7458 vnode->branches = getlist (); 7459 /* Note that we are not massaging VALUE from the string found 7460 in the RCS file. */ 7461 do_branches (vnode->branches, value); 7462 } 7463 7464 /* fill in the next field if there is a next revision */ 7465 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7466 { 7467 error (1, 0, "unexpected end of file reading %s", rcsfile); 7468 } 7469 if (STREQ (key, RCSDESC)) 7470 { 7471 *keyp = key; 7472 *valp = value; 7473 /* Probably could/should be a fatal error. */ 7474 error (0, 0, "warning: 'next' keyword missing from %s", rcsfile); 7475 return vnode; 7476 } 7477 if (value != (char *) NULL) 7478 vnode->next = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL); 7479 7480 /* 7481 * XXX - this is where we put the symbolic link stuff??? 7482 * (into newphrases in the deltas). 7483 */ 7484 while (1) 7485 { 7486 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7487 error (1, 0, "unexpected end of file reading %s", rcsfile); 7488 7489 /* The `desc' keyword is the end of the deltas. */ 7490 if (strcmp (key, RCSDESC) == 0) 7491 break; 7492 7493 #ifdef PRESERVE_PERMISSIONS_SUPPORT 7494 7495 /* The `hardlinks' value is a group of words, which must 7496 be parsed separately and added as a list to vnode->hardlinks. */ 7497 if (strcmp (key, "hardlinks") == 0) 7498 { 7499 char *word; 7500 7501 vnode->hardlinks = getlist(); 7502 while ((word = rcsbuf_valword (rcsbuf, &value)) != NULL) 7503 { 7504 Node *n = getnode(); 7505 n->key = word; 7506 addnode (vnode->hardlinks, n); 7507 } 7508 continue; 7509 } 7510 #endif 7511 7512 /* Enable use of repositories created by certain obsolete 7513 versions of CVS. This code should remain indefinately; 7514 there is no procedure for converting old repositories, and 7515 checking for it is harmless. */ 7516 if (STREQ (key, RCSDEAD)) 7517 { 7518 vnode->dead = 1; 7519 if (vnode->state != NULL) 7520 free (vnode->state); 7521 vnode->state = xstrdup ("dead"); 7522 continue; 7523 } 7524 /* if we have a new revision number, we're done with this delta */ 7525 for (cp = key; 7526 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0'; 7527 cp++) 7528 /* do nothing */ ; 7529 /* Note that when comparing with RCSDATE, we are not massaging 7530 VALUE from the string found in the RCS file. This is OK 7531 since we know exactly what to expect. */ 7532 if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0) 7533 break; 7534 7535 /* At this point, key and value represent a user-defined field 7536 in the delta node. */ 7537 if (vnode->other_delta == NULL) 7538 vnode->other_delta = getlist (); 7539 kv = getnode (); 7540 kv->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD; 7541 kv->key = xstrdup (key); 7542 kv->data = rcsbuf_valcopy (rcsbuf, value, kv->type == RCSFIELD, 7543 (size_t *) NULL); 7544 if (addnode (vnode->other_delta, kv) != 0) 7545 { 7546 /* Complaining about duplicate keys in newphrases seems 7547 questionable, in that we don't know what they mean and 7548 doc/RCSFILES has no prohibition on several newphrases 7549 with the same key. But we can't store more than one as 7550 long as we store them in a List *. */ 7551 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'", 7552 key, rcsfile); 7553 freenode (kv); 7554 } 7555 } 7556 7557 /* Return the key which caused us to fail back to the caller. */ 7558 *keyp = key; 7559 *valp = value; 7560 7561 return vnode; 7562 } 7563 7564 static void 7565 freedeltatext (d) 7566 Deltatext *d; 7567 { 7568 if (d->version != NULL) 7569 free (d->version); 7570 if (d->log != NULL) 7571 free (d->log); 7572 if (d->text != NULL) 7573 free (d->text); 7574 if (d->other != (List *) NULL) 7575 dellist (&d->other); 7576 free (d); 7577 } 7578 7579 static Deltatext * 7580 RCS_getdeltatext (rcs, fp, rcsbuf) 7581 RCSNode *rcs; 7582 FILE *fp; 7583 struct rcsbuffer *rcsbuf; 7584 { 7585 char *num; 7586 char *key, *value; 7587 Node *p; 7588 Deltatext *d; 7589 7590 /* Get the revision number. */ 7591 if (! rcsbuf_getrevnum (rcsbuf, &num)) 7592 { 7593 /* If num == NULL, it means we reached EOF naturally. That's 7594 fine. */ 7595 if (num == NULL) 7596 return NULL; 7597 else 7598 error (1, 0, "%s: unexpected EOF", rcs->path); 7599 } 7600 7601 p = findnode (rcs->versions, num); 7602 if (p == NULL) 7603 error (1, 0, "mismatch in rcs file %s between deltas and deltatexts", 7604 rcs->path); 7605 7606 d = (Deltatext *) xmalloc (sizeof (Deltatext)); 7607 d->version = xstrdup (num); 7608 7609 /* Get the log message. */ 7610 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7611 error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num); 7612 if (! STREQ (key, "log")) 7613 error (1, 0, "%s, delta %s: expected `log', got `%s'", 7614 rcs->path, num, key); 7615 d->log = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL); 7616 7617 /* Get random newphrases. */ 7618 d->other = getlist(); 7619 while (1) 7620 { 7621 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7622 error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num); 7623 7624 if (STREQ (key, "text")) 7625 break; 7626 7627 p = getnode(); 7628 p->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD; 7629 p->key = xstrdup (key); 7630 p->data = rcsbuf_valcopy (rcsbuf, value, p->type == RCSFIELD, 7631 (size_t *) NULL); 7632 if (addnode (d->other, p) < 0) 7633 { 7634 error (0, 0, "warning: %s, delta %s: duplicate field `%s'", 7635 rcs->path, num, key); 7636 } 7637 } 7638 7639 /* Get the change text. We already know that this key is `text'. */ 7640 d->text = rcsbuf_valcopy (rcsbuf, value, 0, &d->len); 7641 7642 return d; 7643 } 7644 7645 /* RCS output functions, for writing RCS format files from RCSNode 7646 structures. 7647 7648 For most of this work, RCS 5.7 uses an `aprintf' function which aborts 7649 program upon error. Instead, these functions check the output status 7650 of the stream right before closing it, and aborts if an error condition 7651 is found. The RCS solution is probably the better one: it produces 7652 more overhead, but will produce a clearer diagnostic in the case of 7653 catastrophic error. In either case, however, the repository will probably 7654 not get corrupted. */ 7655 7656 static int 7657 putsymbol_proc (symnode, fparg) 7658 Node *symnode; 7659 void *fparg; 7660 { 7661 FILE *fp = (FILE *) fparg; 7662 7663 /* A fiddly optimization: this code used to just call fprintf, but 7664 in an old repository with hundreds of tags this can get called 7665 hundreds of thousands of times when doing a cvs tag. Since 7666 tagging is a relatively common operation, and using putc and 7667 fputs is just as comprehensible, the change is worthwhile. */ 7668 putc ('\n', fp); 7669 putc ('\t', fp); 7670 fputs (symnode->key, fp); 7671 putc (':', fp); 7672 fputs (symnode->data, fp); 7673 return 0; 7674 } 7675 7676 static int putlock_proc PROTO ((Node *, void *)); 7677 7678 /* putlock_proc is like putsymbol_proc, but key and data are reversed. */ 7679 7680 static int 7681 putlock_proc (symnode, fp) 7682 Node *symnode; 7683 void *fp; 7684 { 7685 return fprintf ((FILE *) fp, "\n\t%s:%s", symnode->data, symnode->key); 7686 } 7687 7688 static int 7689 putrcsfield_proc (node, vfp) 7690 Node *node; 7691 void *vfp; 7692 { 7693 FILE *fp = (FILE *) vfp; 7694 7695 /* Some magic keys used internally by CVS start with `;'. Skip them. */ 7696 if (node->key[0] == ';') 7697 return 0; 7698 7699 fprintf (fp, "\n%s\t", node->key); 7700 if (node->data != NULL) 7701 { 7702 /* If the field's value contains evil characters, 7703 it must be stringified. */ 7704 /* FIXME: This does not quite get it right. "7jk8f" is not a legal 7705 value for a value in a newpharse, according to doc/RCSFILES, 7706 because digits are not valid in an "id". We might do OK by 7707 always writing strings (enclosed in @@). Would be nice to 7708 explicitly mention this one way or another in doc/RCSFILES. 7709 A case where we are wrong in a much more clear-cut way is that 7710 we let through non-graphic characters such as whitespace and 7711 control characters. */ 7712 7713 if (node->type == RCSCMPFLD || strpbrk (node->data, "$,.:;@") == NULL) 7714 fputs (node->data, fp); 7715 else 7716 { 7717 putc ('@', fp); 7718 expand_at_signs (node->data, (off_t) strlen (node->data), fp); 7719 putc ('@', fp); 7720 } 7721 } 7722 7723 /* desc, log and text fields should not be terminated with semicolon; 7724 all other fields should be. */ 7725 if (! STREQ (node->key, "desc") && 7726 ! STREQ (node->key, "log") && 7727 ! STREQ (node->key, "text")) 7728 { 7729 putc (';', fp); 7730 } 7731 return 0; 7732 } 7733 7734 #ifdef PRESERVE_PERMISSIONS_SUPPORT 7735 7736 /* Save a filename in a `hardlinks' RCS field. NODE->KEY will contain 7737 a full pathname, but currently only basenames are stored in the RCS 7738 node. Assume that the filename includes nasty characters and 7739 @-escape it. */ 7740 7741 static int 7742 puthardlink_proc (node, vfp) 7743 Node *node; 7744 void *vfp; 7745 { 7746 FILE *fp = (FILE *) vfp; 7747 char *basename = strrchr (node->key, '/'); 7748 7749 if (basename == NULL) 7750 basename = node->key; 7751 else 7752 ++basename; 7753 7754 putc ('\t', fp); 7755 putc ('@', fp); 7756 (void) expand_at_signs (basename, strlen (basename), fp); 7757 putc ('@', fp); 7758 7759 return 0; 7760 } 7761 7762 #endif 7763 7764 /* Output the admin node for RCS into stream FP. */ 7765 7766 static void 7767 RCS_putadmin (rcs, fp) 7768 RCSNode *rcs; 7769 FILE *fp; 7770 { 7771 fprintf (fp, "%s\t%s;\n", RCSHEAD, rcs->head ? rcs->head : ""); 7772 if (rcs->branch) 7773 fprintf (fp, "%s\t%s;\n", RCSBRANCH, rcs->branch); 7774 7775 fputs ("access", fp); 7776 if (rcs->access) 7777 { 7778 char *p, *s; 7779 s = xstrdup (rcs->access); 7780 for (p = strtok (s, " \n\t"); p != NULL; p = strtok (NULL, " \n\t")) 7781 fprintf (fp, "\n\t%s", p); 7782 free (s); 7783 } 7784 fputs (";\n", fp); 7785 7786 fputs (RCSSYMBOLS, fp); 7787 /* If we haven't had to convert the symbols to a list yet, don't 7788 force a conversion now; just write out the string. */ 7789 if (rcs->symbols == NULL && rcs->symbols_data != NULL) 7790 { 7791 fputs ("\n\t", fp); 7792 fputs (rcs->symbols_data, fp); 7793 } 7794 else 7795 walklist (RCS_symbols (rcs), putsymbol_proc, (void *) fp); 7796 fputs (";\n", fp); 7797 7798 fputs ("locks", fp); 7799 if (rcs->locks_data) 7800 fprintf (fp, "\t%s", rcs->locks_data); 7801 else if (rcs->locks) 7802 walklist (rcs->locks, putlock_proc, (void *) fp); 7803 if (rcs->strict_locks) 7804 fprintf (fp, "; strict"); 7805 fputs (";\n", fp); 7806 7807 if (rcs->comment) 7808 { 7809 fprintf (fp, "comment\t@"); 7810 expand_at_signs (rcs->comment, (off_t) strlen (rcs->comment), fp); 7811 fputs ("@;\n", fp); 7812 } 7813 if (rcs->expand && ! STREQ (rcs->expand, "kv")) 7814 fprintf (fp, "%s\t@%s@;\n", RCSEXPAND, rcs->expand); 7815 7816 walklist (rcs->other, putrcsfield_proc, (void *) fp); 7817 7818 putc ('\n', fp); 7819 } 7820 7821 static void 7822 putdelta (vers, fp) 7823 RCSVers *vers; 7824 FILE *fp; 7825 { 7826 Node *bp, *start; 7827 7828 /* Skip if no revision was supplied, or if it is outdated (cvs admin -o) */ 7829 if (vers == NULL || vers->outdated) 7830 return; 7831 7832 fprintf (fp, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches", 7833 vers->version, 7834 RCSDATE, vers->date, 7835 "author", vers->author, 7836 "state", vers->state ? vers->state : ""); 7837 7838 if (vers->branches != NULL) 7839 { 7840 start = vers->branches->list; 7841 for (bp = start->next; bp != start; bp = bp->next) 7842 fprintf (fp, "\n\t%s", bp->key); 7843 } 7844 7845 fprintf (fp, ";\nnext\t%s;", vers->next ? vers->next : ""); 7846 7847 walklist (vers->other_delta, putrcsfield_proc, fp); 7848 7849 #ifdef PRESERVE_PERMISSIONS_SUPPORT 7850 if (vers->hardlinks) 7851 { 7852 fprintf (fp, "\nhardlinks"); 7853 walklist (vers->hardlinks, puthardlink_proc, fp); 7854 putc (';', fp); 7855 } 7856 #endif 7857 putc ('\n', fp); 7858 } 7859 7860 static void 7861 RCS_putdtree (rcs, rev, fp) 7862 RCSNode *rcs; 7863 char *rev; 7864 FILE *fp; 7865 { 7866 RCSVers *versp; 7867 Node *p, *branch; 7868 7869 if (rev == NULL) 7870 return; 7871 7872 /* Find the delta node for this revision. */ 7873 p = findnode (rcs->versions, rev); 7874 if (p == NULL) 7875 { 7876 error (1, 0, 7877 "error parsing repository file %s, file may be corrupt.", 7878 rcs->path); 7879 } 7880 7881 versp = (RCSVers *) p->data; 7882 7883 /* Print the delta node and recurse on its `next' node. This prints 7884 the trunk. If there are any branches printed on this revision, 7885 print those trunks as well. */ 7886 putdelta (versp, fp); 7887 RCS_putdtree (rcs, versp->next, fp); 7888 if (versp->branches != NULL) 7889 { 7890 branch = versp->branches->list; 7891 for (p = branch->next; p != branch; p = p->next) 7892 RCS_putdtree (rcs, p->key, fp); 7893 } 7894 } 7895 7896 static void 7897 RCS_putdesc (rcs, fp) 7898 RCSNode *rcs; 7899 FILE *fp; 7900 { 7901 fprintf (fp, "\n\n%s\n@", RCSDESC); 7902 if (rcs->desc != NULL) 7903 { 7904 off_t len = (off_t) strlen (rcs->desc); 7905 if (len > 0) 7906 { 7907 expand_at_signs (rcs->desc, len, fp); 7908 if (rcs->desc[len-1] != '\n') 7909 putc ('\n', fp); 7910 } 7911 } 7912 fputs ("@\n", fp); 7913 } 7914 7915 static void 7916 putdeltatext (fp, d) 7917 FILE *fp; 7918 Deltatext *d; 7919 { 7920 fprintf (fp, "\n\n%s\nlog\n@", d->version); 7921 if (d->log != NULL) 7922 { 7923 int loglen = strlen (d->log); 7924 expand_at_signs (d->log, (off_t) loglen, fp); 7925 if (d->log[loglen-1] != '\n') 7926 putc ('\n', fp); 7927 } 7928 putc ('@', fp); 7929 7930 walklist (d->other, putrcsfield_proc, fp); 7931 7932 fputs ("\ntext\n@", fp); 7933 if (d->text != NULL) 7934 expand_at_signs (d->text, (off_t) d->len, fp); 7935 fputs ("@\n", fp); 7936 } 7937 7938 /* TODO: the whole mechanism for updating deltas is kludgey... more 7939 sensible would be to supply all the necessary info in a `newdeltatext' 7940 field for RCSVers nodes. -twp */ 7941 7942 /* Copy delta text nodes from FIN to FOUT. If NEWDTEXT is non-NULL, it 7943 is a new delta text node, and should be added to the tree at the 7944 node whose revision number is INSERTPT. (Note that trunk nodes are 7945 written in decreasing order, and branch nodes are written in 7946 increasing order.) */ 7947 7948 static void 7949 RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt) 7950 RCSNode *rcs; 7951 FILE *fin; 7952 struct rcsbuffer *rcsbufin; 7953 FILE *fout; 7954 Deltatext *newdtext; 7955 char *insertpt; 7956 { 7957 int actions; 7958 RCSVers *dadmin; 7959 Node *np; 7960 int insertbefore, found; 7961 char *bufrest; 7962 int nls; 7963 size_t buflen; 7964 char buf[8192]; 7965 int got; 7966 7967 /* Count the number of versions for which we have to do some 7968 special operation. */ 7969 actions = walklist (rcs->versions, count_delta_actions, (void *) NULL); 7970 7971 /* Make a note of whether NEWDTEXT should be inserted 7972 before or after its INSERTPT. */ 7973 insertbefore = (newdtext != NULL && numdots (newdtext->version) == 1); 7974 7975 while (actions != 0 || newdtext != NULL) 7976 { 7977 Deltatext *dtext; 7978 7979 dtext = RCS_getdeltatext (rcs, fin, rcsbufin); 7980 7981 /* We shouldn't hit EOF here, because that would imply that 7982 some action was not taken, or that we could not insert 7983 NEWDTEXT. */ 7984 if (dtext == NULL) 7985 error (1, 0, "internal error: EOF too early in RCS_copydeltas"); 7986 7987 found = (insertpt != NULL && STREQ (dtext->version, insertpt)); 7988 if (found && insertbefore) 7989 { 7990 putdeltatext (fout, newdtext); 7991 newdtext = NULL; 7992 insertpt = NULL; 7993 } 7994 7995 np = findnode (rcs->versions, dtext->version); 7996 dadmin = (RCSVers *) np->data; 7997 7998 /* If this revision has been outdated, just skip it. */ 7999 if (dadmin->outdated) 8000 { 8001 freedeltatext (dtext); 8002 --actions; 8003 continue; 8004 } 8005 8006 /* Update the change text for this delta. New change text 8007 data may come from cvs admin -m, cvs admin -o, or cvs ci. */ 8008 if (dadmin->text != NULL) 8009 { 8010 if (dadmin->text->log != NULL || dadmin->text->text != NULL) 8011 --actions; 8012 if (dadmin->text->log != NULL) 8013 { 8014 free (dtext->log); 8015 dtext->log = dadmin->text->log; 8016 dadmin->text->log = NULL; 8017 } 8018 if (dadmin->text->text != NULL) 8019 { 8020 free (dtext->text); 8021 dtext->text = dadmin->text->text; 8022 dtext->len = dadmin->text->len; 8023 dadmin->text->text = NULL; 8024 } 8025 } 8026 putdeltatext (fout, dtext); 8027 freedeltatext (dtext); 8028 8029 if (found && !insertbefore) 8030 { 8031 putdeltatext (fout, newdtext); 8032 newdtext = NULL; 8033 insertpt = NULL; 8034 } 8035 } 8036 8037 /* Copy the rest of the file directly, without bothering to 8038 interpret it. The caller will handle error checking by calling 8039 ferror. 8040 8041 We just wrote a newline to the file, either in putdeltatext or 8042 in the caller. However, we may not have read the corresponding 8043 newline from the file, because rcsbuf_getkey returns as soon as 8044 it finds the end of the '@' string for the desc or text key. 8045 Therefore, we may read three newlines when we should really 8046 only write two, and we check for that case here. This is not 8047 an semantically important issue; we only do it to make our RCS 8048 files look traditional. */ 8049 8050 nls = 3; 8051 8052 rcsbuf_get_buffered (rcsbufin, &bufrest, &buflen); 8053 if (buflen > 0) 8054 { 8055 if (bufrest[0] != '\n' 8056 || strncmp (bufrest, "\n\n\n", buflen < 3 ? buflen : 3) != 0) 8057 { 8058 nls = 0; 8059 } 8060 else 8061 { 8062 if (buflen < 3) 8063 nls -= buflen; 8064 else 8065 { 8066 ++bufrest; 8067 --buflen; 8068 nls = 0; 8069 } 8070 } 8071 8072 fwrite (bufrest, 1, buflen, fout); 8073 } 8074 8075 while ((got = fread (buf, 1, sizeof buf, fin)) != 0) 8076 { 8077 if (nls > 0 8078 && got >= nls 8079 && buf[0] == '\n' 8080 && strncmp (buf, "\n\n\n", nls) == 0) 8081 { 8082 fwrite (buf + 1, 1, got - 1, fout); 8083 } 8084 else 8085 { 8086 fwrite (buf, 1, got, fout); 8087 } 8088 8089 nls = 0; 8090 } 8091 } 8092 8093 /* A helper procedure for RCS_copydeltas. This is called via walklist 8094 to count the number of RCS revisions for which some special action 8095 is required. */ 8096 8097 static int 8098 count_delta_actions (np, ignore) 8099 Node *np; 8100 void *ignore; 8101 { 8102 RCSVers *dadmin; 8103 8104 dadmin = (RCSVers *) np->data; 8105 8106 if (dadmin->outdated) 8107 return 1; 8108 8109 if (dadmin->text != NULL 8110 && (dadmin->text->log != NULL || dadmin->text->text != NULL)) 8111 { 8112 return 1; 8113 } 8114 8115 return 0; 8116 } 8117 8118 /* 8119 * Clean up temporary files 8120 */ 8121 RETSIGTYPE 8122 rcs_cleanup () 8123 { 8124 /* Note that the checks for existence_error are because we are 8125 called from a signal handler, so we don't know whether the 8126 files got created. */ 8127 8128 /* FIXME: Do not perform buffered I/O from an interrupt handler like 8129 this (via error). However, I'm leaving the error-calling code there 8130 in the hope that on the rare occasion the error call is actually made 8131 (e.g., a fluky I/O error or permissions problem prevents the deletion 8132 of a just-created file) reentrancy won't be an issue. */ 8133 if (rcs_lockfile != NULL) 8134 { 8135 char *tmp = rcs_lockfile; 8136 rcs_lockfile = NULL; 8137 if (rcs_lockfd >= 0) 8138 { 8139 if (close (rcs_lockfd) != 0) 8140 error (0, errno, "error closing lock file %s", tmp); 8141 rcs_lockfd = -1; 8142 } 8143 if (unlink_file (tmp) < 0 8144 && !existence_error (errno)) 8145 error (0, errno, "cannot remove %s", tmp); 8146 } 8147 } 8148 8149 /* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style 8150 locking on the specified RCSFILE: for a file called `foo,v', open 8151 for writing a file called `,foo,'. 8152 8153 Note that we what do here is quite different from what RCS does. 8154 RCS creates the ,foo, file before it reads the RCS file (if it 8155 knows that it will be writing later), so that it actually serves as 8156 a lock. We don't; instead we rely on CVS writelocks. This means 8157 that if someone is running RCS on the file at the same time they 8158 are running CVS on it, they might lose (we read the file, 8159 then RCS writes it, then we write it, clobbering the 8160 changes made by RCS). I believe the current sentiment about this 8161 is "well, don't do that". 8162 8163 A concern has been expressed about whether adopting the RCS 8164 strategy would slow us down. I don't think so, since we need to 8165 write the ,foo, file anyway (unless perhaps if O_EXCL is slower or 8166 something). 8167 8168 These do not perform quite the same function as the RCS -l option 8169 for locking files: they are intended to prevent competing RCS 8170 processes from stomping all over each other's laundry. Hence, 8171 they are `internal' locking functions. 8172 8173 If there is an error, give a fatal error; if we return we always 8174 return a non-NULL value. */ 8175 8176 static FILE * 8177 rcs_internal_lockfile (rcsfile) 8178 char *rcsfile; 8179 { 8180 struct stat rstat; 8181 FILE *fp; 8182 static int first_call = 1; 8183 8184 if (first_call) 8185 { 8186 first_call = 0; 8187 /* clean up if we get a signal */ 8188 #ifdef SIGABRT 8189 (void) SIG_register (SIGABRT, rcs_cleanup); 8190 #endif 8191 #ifdef SIGHUP 8192 (void) SIG_register (SIGHUP, rcs_cleanup); 8193 #endif 8194 #ifdef SIGINT 8195 (void) SIG_register (SIGINT, rcs_cleanup); 8196 #endif 8197 #ifdef SIGQUIT 8198 (void) SIG_register (SIGQUIT, rcs_cleanup); 8199 #endif 8200 #ifdef SIGPIPE 8201 (void) SIG_register (SIGPIPE, rcs_cleanup); 8202 #endif 8203 #ifdef SIGTERM 8204 (void) SIG_register (SIGTERM, rcs_cleanup); 8205 #endif 8206 } 8207 8208 /* Get the lock file name: `,file,' for RCS file `file,v'. */ 8209 assert (rcs_lockfile == NULL); 8210 assert (rcs_lockfd < 0); 8211 rcs_lockfile = rcs_lockfilename (rcsfile); 8212 8213 /* Use the existing RCS file mode, or read-only if this is a new 8214 file. (Really, this is a lie -- if this is a new file, 8215 RCS_checkin uses the permissions from the working copy. For 8216 actually creating the file, we use 0444 as a safe default mode.) */ 8217 if (stat (rcsfile, &rstat) < 0) 8218 { 8219 if (existence_error (errno)) 8220 rstat.st_mode = S_IRUSR | S_IRGRP | S_IROTH; 8221 else 8222 error (1, errno, "cannot stat %s", rcsfile); 8223 } 8224 8225 /* Try to open exclusively. POSIX.1 guarantees that O_EXCL|O_CREAT 8226 guarantees an exclusive open. According to the RCS source, with 8227 NFS v2 we must also throw in O_TRUNC and use an open mask that makes 8228 the file unwriteable. For extensive justification, see the comments for 8229 rcswriteopen() in rcsedit.c, in RCS 5.7. This is kind of pointless 8230 in the CVS case; see comment at the start of this file concerning 8231 general ,foo, file strategy. 8232 8233 There is some sentiment that with NFSv3 and such, that one can 8234 rely on O_EXCL these days. This might be true for unix (I 8235 don't really know), but I am still pretty skeptical in the case 8236 of the non-unix systems. */ 8237 rcs_lockfd = open (rcs_lockfile, 8238 OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, 8239 S_IRUSR | S_IRGRP | S_IROTH); 8240 8241 if (rcs_lockfd < 0) 8242 { 8243 error (1, errno, "could not open lock file `%s'", rcs_lockfile); 8244 } 8245 8246 /* Force the file permissions, and return a stream object. */ 8247 /* Because we change the modes later, we don't worry about 8248 this in the non-HAVE_FCHMOD case. */ 8249 #ifdef HAVE_FCHMOD 8250 if (fchmod (rcs_lockfd, rstat.st_mode) < 0) 8251 error (1, errno, "cannot change mode for %s", rcs_lockfile); 8252 #endif 8253 fp = fdopen (rcs_lockfd, FOPEN_BINARY_WRITE); 8254 if (fp == NULL) 8255 error (1, errno, "cannot fdopen %s", rcs_lockfile); 8256 8257 return fp; 8258 } 8259 8260 static void 8261 rcs_internal_unlockfile (fp, rcsfile) 8262 FILE *fp; 8263 char *rcsfile; 8264 { 8265 assert (rcs_lockfile != NULL); 8266 assert (rcs_lockfd >= 0); 8267 8268 /* Abort if we could not write everything successfully to LOCKFILE. 8269 This is not a great error-handling mechanism, but should prevent 8270 corrupting the repository. */ 8271 8272 if (ferror (fp)) 8273 /* The only case in which using errno here would be meaningful 8274 is if we happen to have left errno unmolested since the call 8275 which produced the error (e.g. fprintf). That is pretty 8276 fragile even if it happens to sometimes be true. The real 8277 solution is to check each call to fprintf rather than waiting 8278 until the end like this. */ 8279 error (1, 0, "error writing to lock file %s", rcs_lockfile); 8280 if (fclose (fp) == EOF) 8281 error (1, errno, "error closing lock file %s", rcs_lockfile); 8282 rcs_lockfd = -1; 8283 8284 rename_file (rcs_lockfile, rcsfile); 8285 8286 { 8287 /* Use a temporary to make sure there's no interval 8288 (after rcs_lockfile has been freed but before it's set to NULL) 8289 during which the signal handler's use of rcs_lockfile would 8290 reference freed memory. */ 8291 char *tmp = rcs_lockfile; 8292 rcs_lockfile = NULL; 8293 free (tmp); 8294 } 8295 } 8296 8297 static char * 8298 rcs_lockfilename (rcsfile) 8299 char *rcsfile; 8300 { 8301 char *lockfile, *lockp; 8302 char *rcsbase, *rcsp, *rcsend; 8303 int rcslen; 8304 8305 /* Create the lockfile name. */ 8306 rcslen = strlen (rcsfile); 8307 lockfile = (char *) xmalloc (rcslen + 10); 8308 rcsbase = last_component (rcsfile); 8309 rcsend = rcsfile + rcslen - sizeof(RCSEXT); 8310 for (lockp = lockfile, rcsp = rcsfile; rcsp < rcsbase; ++rcsp) 8311 *lockp++ = *rcsp; 8312 *lockp++ = ','; 8313 while (rcsp <= rcsend) 8314 *lockp++ = *rcsp++; 8315 *lockp++ = ','; 8316 *lockp = '\0'; 8317 8318 return lockfile; 8319 } 8320 8321 /* Rewrite an RCS file. The basic idea here is that the caller should 8322 first call RCS_reparsercsfile, then munge the data structures as 8323 desired (via RCS_delete_revs, RCS_settag, &c), then call RCS_rewrite. */ 8324 8325 void 8326 RCS_rewrite (rcs, newdtext, insertpt) 8327 RCSNode *rcs; 8328 Deltatext *newdtext; 8329 char *insertpt; 8330 { 8331 FILE *fin, *fout; 8332 struct rcsbuffer rcsbufin; 8333 8334 if (noexec) 8335 return; 8336 8337 /* Make sure we're operating on an actual file and not a symlink. */ 8338 resolve_symlink (&(rcs->path)); 8339 8340 fout = rcs_internal_lockfile (rcs->path); 8341 8342 RCS_putadmin (rcs, fout); 8343 RCS_putdtree (rcs, rcs->head, fout); 8344 RCS_putdesc (rcs, fout); 8345 8346 /* Open the original RCS file and seek to the first delta text. */ 8347 rcsbuf_cache_open (rcs, rcs->delta_pos, &fin, &rcsbufin); 8348 8349 /* Update delta_pos to the current position in the output file. 8350 Do NOT move these statements: they must be done after fin has 8351 been positioned at the old delta_pos, but before any delta 8352 texts have been written to fout. */ 8353 rcs->delta_pos = ftell (fout); 8354 if (rcs->delta_pos == -1) 8355 error (1, errno, "cannot ftell in RCS file %s", rcs->path); 8356 8357 RCS_copydeltas (rcs, fin, &rcsbufin, fout, newdtext, insertpt); 8358 8359 /* We don't want to call rcsbuf_cache here, since we're about to 8360 delete the file. */ 8361 rcsbuf_close (&rcsbufin); 8362 if (ferror (fin)) 8363 /* The only case in which using errno here would be meaningful 8364 is if we happen to have left errno unmolested since the call 8365 which produced the error (e.g. fread). That is pretty 8366 fragile even if it happens to sometimes be true. The real 8367 solution is to make sure that all the code which reads 8368 from fin checks for errors itself (some does, some doesn't). */ 8369 error (0, 0, "warning: when closing RCS file `%s'", rcs->path); 8370 if (fclose (fin) < 0) 8371 error (0, errno, "warning: closing RCS file `%s'", rcs->path); 8372 8373 rcs_internal_unlockfile (fout, rcs->path); 8374 } 8375 8376 /* Abandon changes to an RCS file. */ 8377 8378 void 8379 RCS_abandon (rcs) 8380 RCSNode *rcs; 8381 { 8382 free_rcsnode_contents (rcs); 8383 rcs->symbols_data = NULL; 8384 rcs->expand = NULL; 8385 rcs->access = NULL; 8386 rcs->locks_data = NULL; 8387 rcs->comment = NULL; 8388 rcs->desc = NULL; 8389 rcs->flags |= PARTIAL; 8390 } 8391 8392 8393 /* Annotate command. In rcs.c for historical reasons (from back when 8394 what is now RCS_deltas was part of annotate_fileproc). */ 8395 8396 /* Options from the command line. */ 8397 8398 static int force_tag_match = 1; 8399 static char *tag = NULL; 8400 static char *date = NULL; 8401 8402 static int annotate_fileproc PROTO ((void *callerdat, struct file_info *)); 8403 8404 static int 8405 annotate_fileproc (callerdat, finfo) 8406 void *callerdat; 8407 struct file_info *finfo; 8408 { 8409 FILE *fp = NULL; 8410 struct rcsbuffer *rcsbufp = NULL; 8411 struct rcsbuffer rcsbuf; 8412 char *version; 8413 8414 if (finfo->rcs == NULL) 8415 return (1); 8416 8417 if (finfo->rcs->flags & PARTIAL) 8418 { 8419 RCS_reparsercsfile (finfo->rcs, &fp, &rcsbuf); 8420 rcsbufp = &rcsbuf; 8421 } 8422 8423 version = RCS_getversion (finfo->rcs, tag, date, force_tag_match, 8424 (int *) NULL); 8425 if (version == NULL) 8426 return 0; 8427 8428 /* Distinguish output for various files if we are processing 8429 several files. */ 8430 cvs_outerr ("Annotations for ", 0); 8431 cvs_outerr (finfo->fullname, 0); 8432 cvs_outerr ("\n***************\n", 0); 8433 8434 RCS_deltas (finfo->rcs, fp, rcsbufp, version, RCS_ANNOTATE, NULL, 8435 NULL, NULL, NULL); 8436 free (version); 8437 return 0; 8438 } 8439 8440 static const char *const annotate_usage[] = 8441 { 8442 "Usage: %s %s [-lRf] [-r rev|-D date] [files...]\n", 8443 "\t-l\tLocal directory only, no recursion.\n", 8444 "\t-R\tProcess directories recursively.\n", 8445 "\t-f\tUse head revision if tag/date not found.\n", 8446 "\t-r rev\tAnnotate file as of specified revision/tag.\n", 8447 "\t-D date\tAnnotate file as of specified date.\n", 8448 "(Specify the --help global option for a list of other help options)\n", 8449 NULL 8450 }; 8451 8452 /* Command to show the revision, date, and author where each line of a 8453 file was modified. */ 8454 8455 int 8456 annotate (argc, argv) 8457 int argc; 8458 char **argv; 8459 { 8460 int local = 0; 8461 int c; 8462 8463 if (argc == -1) 8464 usage (annotate_usage); 8465 8466 optind = 0; 8467 while ((c = getopt (argc, argv, "+lr:D:fR")) != -1) 8468 { 8469 switch (c) 8470 { 8471 case 'l': 8472 local = 1; 8473 break; 8474 case 'R': 8475 local = 0; 8476 break; 8477 case 'r': 8478 tag = optarg; 8479 break; 8480 case 'D': 8481 date = Make_Date (optarg); 8482 break; 8483 case 'f': 8484 force_tag_match = 0; 8485 break; 8486 case '?': 8487 default: 8488 usage (annotate_usage); 8489 break; 8490 } 8491 } 8492 argc -= optind; 8493 argv += optind; 8494 8495 #ifdef CLIENT_SUPPORT 8496 if (client_active) 8497 { 8498 start_server (); 8499 ign_setup (); 8500 8501 if (local) 8502 send_arg ("-l"); 8503 if (!force_tag_match) 8504 send_arg ("-f"); 8505 option_with_arg ("-r", tag); 8506 if (date) 8507 client_senddate (date); 8508 send_files (argc, argv, local, 0, SEND_NO_CONTENTS); 8509 send_file_names (argc, argv, SEND_EXPAND_WILD); 8510 send_to_server ("annotate\012", 0); 8511 return get_responses_and_close (); 8512 } 8513 #endif /* CLIENT_SUPPORT */ 8514 8515 if (tag != NULL) 8516 tag_check_valid (tag, argc, argv, local, 0, ""); 8517 8518 return start_recursion (annotate_fileproc, (FILESDONEPROC) NULL, 8519 (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, 8520 argc, argv, local, W_LOCAL, 0, 1, (char *)NULL, 8521 1); 8522 } 8523 8524 /* 8525 * For a given file with full pathname PATH and revision number REV, 8526 * produce a file label suitable for passing to diff. The default 8527 * file label as used by RCS 5.7 looks like this: 8528 * 8529 * FILENAME <tab> YYYY/MM/DD <sp> HH:MM:SS <tab> REVNUM 8530 * 8531 * The date and time used are the revision's last checkin date and time. 8532 * If REV is NULL, use the working copy's mtime instead. 8533 */ 8534 char * 8535 make_file_label (path, rev, rcs) 8536 char *path; 8537 char *rev; 8538 RCSNode *rcs; 8539 { 8540 char datebuf[MAXDATELEN]; 8541 char *label; 8542 char *file; 8543 8544 file = last_component (path); 8545 label = (char *) xmalloc (strlen (path) 8546 + (rev == NULL ? 0 : strlen (rev)) 8547 + 50); 8548 8549 if (rev) 8550 { 8551 char *date; 8552 RCS_getrevtime (rcs, rev, datebuf, 0); 8553 date = printable_date (datebuf); 8554 (void) sprintf (label, "-L%s\t%s\t%s", path, date, rev); 8555 free (date); 8556 } 8557 else 8558 { 8559 struct stat sb; 8560 struct tm *wm; 8561 8562 if (CVS_STAT (file, &sb) < 0) 8563 error (0, 1, "could not get info for `%s'", path); 8564 else 8565 { 8566 wm = gmtime (&sb.st_mtime); 8567 (void) sprintf (datebuf, "%04d/%02d/%02d %02d:%02d:%02d", 8568 wm->tm_year + 1900, wm->tm_mon + 1, 8569 wm->tm_mday, wm->tm_hour, 8570 wm->tm_min, wm->tm_sec); 8571 (void) sprintf (label, "-L%s\t%s", path, datebuf); 8572 } 8573 } 8574 return label; 8575 } 8576