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