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