2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
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.
7 * The routines contained in this file do all the rcs file parsing and
16 /* These need to be source after cvs.h or HAVE_MMAP won't be set... */
18 # include <sys/mman.h>
19 # ifndef HAVE_GETPAGESIZE
20 # include "getpagesize.h"
23 # define MAP_FAILED NULL
27 int preserve_perms = 0;
29 /* The RCS -k options, and a set of enums that must match the array.
30 These come first so that we can use enum kflag in function
32 static const char *const kflags[] =
33 {"kv", "kvl", "k", "v", "o", "b", (char *) NULL};
34 enum kflag { KFLAG_KV = 0, KFLAG_KVL, KFLAG_K, KFLAG_V, KFLAG_O, KFLAG_B };
36 /* A structure we use to buffer the contents of an RCS file. The
37 various fields are only referenced directly by the rcsbuf_*
38 functions. We declare the struct here so that we can allocate it
39 on the stack, rather than in memory. */
43 /* Points to the current position in the buffer. */
45 /* Points just after the last valid character in the buffer. */
49 /* The name of the file, used for error messages. */
51 /* The starting file position of the data in the buffer. */
53 /* The length of the value. */
55 /* Whether the value contains an '@' string. If so, we can not
56 compress whitespace characters. */
58 /* The number of embedded '@' characters in an '@' string. If
59 this is non-zero, we must search the string for pairs of '@'
60 and convert them to a single '@'. */
64 static RCSNode *RCS_parsercsfile_i PROTO((FILE * fp, const char *rcsfile));
65 static char *RCS_getdatebranch PROTO((RCSNode * rcs, char *date, char *branch));
66 static void rcsbuf_open PROTO ((struct rcsbuffer *, FILE *fp,
67 const char *filename, unsigned long pos));
68 static void rcsbuf_close PROTO ((struct rcsbuffer *));
69 static int rcsbuf_getkey PROTO ((struct rcsbuffer *, char **keyp,
71 static int rcsbuf_getrevnum PROTO ((struct rcsbuffer *, char **revp));
73 static char *rcsbuf_fill PROTO ((struct rcsbuffer *, char *ptr, char **keyp,
76 static int rcsbuf_valcmp PROTO ((struct rcsbuffer *));
77 static char *rcsbuf_valcopy PROTO ((struct rcsbuffer *, char *val, int polish,
79 static void rcsbuf_valpolish PROTO ((struct rcsbuffer *, char *val, int polish,
81 static void rcsbuf_valpolish_internal PROTO ((struct rcsbuffer *, char *to,
82 const char *from, size_t *lenp));
83 static unsigned long rcsbuf_ftell PROTO ((struct rcsbuffer *));
84 static void rcsbuf_get_buffered PROTO ((struct rcsbuffer *, char **datap,
86 static void rcsbuf_cache PROTO ((RCSNode *, struct rcsbuffer *));
87 static void rcsbuf_cache_close PROTO ((void));
88 static void rcsbuf_cache_open PROTO ((RCSNode *, long, FILE **,
90 static int checkmagic_proc PROTO((Node *p, void *closure));
91 static void do_branches PROTO((List * list, char *val));
92 static void do_symbols PROTO((List * list, char *val));
93 static void do_locks PROTO((List * list, char *val));
94 static void free_rcsnode_contents PROTO((RCSNode *));
95 static void free_rcsvers_contents PROTO((RCSVers *));
96 static void rcsvers_delproc PROTO((Node * p));
97 static char *translate_symtag PROTO((RCSNode *, const char *));
98 static char *RCS_addbranch PROTO ((RCSNode *, const char *));
99 static char *truncate_revnum_in_place PROTO ((char *));
100 static char *truncate_revnum PROTO ((const char *));
101 static char *printable_date PROTO((const char *));
102 static char *escape_keyword_value PROTO ((const char *, int *));
103 static void expand_keywords PROTO((RCSNode *, RCSVers *, const char *,
104 const char *, size_t, enum kflag, char *,
105 size_t, char **, size_t *));
106 static void cmp_file_buffer PROTO((void *, const char *, size_t));
108 /* Routines for reading, parsing and writing RCS files. */
109 static RCSVers *getdelta PROTO ((struct rcsbuffer *, char *, char **,
111 static Deltatext *RCS_getdeltatext PROTO ((RCSNode *, FILE *,
112 struct rcsbuffer *));
113 static void freedeltatext PROTO ((Deltatext *));
115 static void RCS_putadmin PROTO ((RCSNode *, FILE *));
116 static void RCS_putdtree PROTO ((RCSNode *, char *, FILE *));
117 static void RCS_putdesc PROTO ((RCSNode *, FILE *));
118 static void putdelta PROTO ((RCSVers *, FILE *));
119 static int putrcsfield_proc PROTO ((Node *, void *));
120 static int putsymbol_proc PROTO ((Node *, void *));
121 static void RCS_copydeltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *,
122 FILE *, Deltatext *, char *));
123 static int count_delta_actions PROTO ((Node *, void *));
124 static void putdeltatext PROTO ((FILE *, Deltatext *));
126 static FILE *rcs_internal_lockfile PROTO ((char *));
127 static void rcs_internal_unlockfile PROTO ((FILE *, char *));
128 static char *rcs_lockfilename PROTO ((char *));
130 /* The RCS file reading functions are called a lot, and they do some
131 string comparisons. This macro speeds things up a bit by skipping
132 the function call when the first characters are different. It
133 evaluates its arguments multiple times. */
134 #define STREQ(a, b) ((a)[0] == (b)[0] && strcmp ((a), (b)) == 0)
137 * We don't want to use isspace() from the C library because:
139 * 1. The definition of "whitespace" in RCS files includes ASCII
140 * backspace, but the C locale doesn't.
141 * 2. isspace is an very expensive function call in some implementations
142 * due to the addition of wide character support.
144 static const char spacetab[] = {
145 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x00 - 0x0f */
146 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */
147 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */
148 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */
149 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
151 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x8f */
152 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */
153 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */
154 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */
155 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */
156 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */
157 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
158 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
159 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
160 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0 - 0xff */
163 #define whitespace(c) (spacetab[(unsigned char)c] != 0)
165 static char *rcs_lockfile;
166 static int rcs_lockfd = -1;
168 /* A few generic thoughts on error handling, in particular the
169 printing of unexpected characters that we find in the RCS file
170 (that is, why we use '\x%x' rather than %c or some such).
172 * Avoiding %c means we don't have to worry about what is printable
173 and other such stuff. In error handling, often better to keep it
176 * Hex rather than decimal or octal because character set standards
179 * Saying "character 0x%x" might make it sound like we are printing
180 a file offset. So we use '\x%x'.
182 * Would be nice to print the offset within the file, but I can
183 imagine various portability hassles (in particular, whether
184 unsigned long is always big enough to hold file offsets). */
186 /* Parse an rcsfile given a user file name and a repository. If there is
187 an error, we print an error message and return NULL. If the file
188 does not exist, we return NULL without printing anything (I'm not
189 sure this allows the caller to do anything reasonable, but it is
190 the current behavior). */
192 RCS_parse (file, repos)
201 /* We're creating a new RCSNode, so there is no hope of finding it
203 rcsbuf_cache_close ();
205 rcsfile = xmalloc (strlen (repos) + strlen (file)
206 + sizeof (RCSEXT) + sizeof (CVSATTIC) + 10);
207 (void) sprintf (rcsfile, "%s/%s%s", repos, file, RCSEXT);
208 if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) != NULL)
210 rcs = RCS_parsercsfile_i(fp, rcsfile);
217 else if (! existence_error (errno))
219 error (0, errno, "cannot open %s", rcsfile);
224 (void) sprintf (rcsfile, "%s/%s/%s%s", repos, CVSATTIC, file, RCSEXT);
225 if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) != NULL)
227 rcs = RCS_parsercsfile_i(fp, rcsfile);
230 rcs->flags |= INATTIC;
237 else if (! existence_error (errno))
239 error (0, errno, "cannot open %s", rcsfile);
243 #if defined (SERVER_SUPPORT) && !defined (FILENAMES_CASE_INSENSITIVE)
249 /* The client might be asking for a file which we do have
250 (which the client doesn't know about), but for which the
251 filename case differs. We only consider this case if the
252 regular CVS_FOPENs fail, because fopen_case is such an
254 (void) sprintf (rcsfile, "%s/%s%s", repos, file, RCSEXT);
255 status = fopen_case (rcsfile, "rb", &fp, &found_path);
258 rcs = RCS_parsercsfile_i (fp, rcsfile);
263 rcs->path = found_path;
267 else if (! existence_error (status))
269 error (0, status, "cannot open %s", rcsfile);
274 (void) sprintf (rcsfile, "%s/%s/%s%s", repos, CVSATTIC, file, RCSEXT);
275 status = fopen_case (rcsfile, "rb", &fp, &found_path);
278 rcs = RCS_parsercsfile_i (fp, rcsfile);
281 rcs->flags |= INATTIC;
286 rcs->path = found_path;
290 else if (! existence_error (status))
292 error (0, status, "cannot open %s", rcsfile);
307 * Parse a specific rcsfile.
310 RCS_parsercsfile (rcsfile)
316 /* We're creating a new RCSNode, so there is no hope of finding it
318 rcsbuf_cache_close ();
320 /* open the rcsfile */
321 if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) == NULL)
323 error (0, errno, "Couldn't open rcs file `%s'", rcsfile);
327 rcs = RCS_parsercsfile_i (fp, rcsfile);
336 RCS_parsercsfile_i (fp, rcsfile)
341 struct rcsbuffer rcsbuf;
345 rdata = (RCSNode *) xmalloc (sizeof (RCSNode));
346 memset ((char *) rdata, 0, sizeof (RCSNode));
348 rdata->path = xstrdup (rcsfile);
350 /* Process HEAD, BRANCH, and EXPAND keywords from the RCS header.
352 Most cvs operations on the main branch don't need any more
353 information. Those that do call RCS_reparsercsfile to parse
354 the rest of the header and the deltas. */
356 rcsbuf_open (&rcsbuf, fp, rcsfile, 0);
358 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
360 if (STREQ (key, RCSDESC))
363 if (STREQ (RCSHEAD, key) && value != NULL)
364 rdata->head = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *) NULL);
366 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
368 if (STREQ (key, RCSDESC))
371 if (STREQ (RCSBRANCH, key) && value != NULL)
375 rdata->branch = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *) NULL);
376 if ((numdots (rdata->branch) & 1) != 0)
378 /* turn it into a branch if it's a revision */
379 cp = strrchr (rdata->branch, '.');
384 /* Look ahead for expand, stopping when we see desc or a revision
390 if (STREQ (RCSEXPAND, key))
392 rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0,
398 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
404 if (STREQ (RCSDESC, key))
407 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
411 rdata->flags |= PARTIAL;
413 rcsbuf_cache (rdata, &rcsbuf);
418 error (0, 0, "`%s' does not appear to be a valid rcs file",
420 rcsbuf_close (&rcsbuf);
421 freercsnode (&rdata);
427 /* Do the real work of parsing an RCS file.
429 On error, die with a fatal error; if it returns at all it was successful.
431 If PFP is NULL, close the file when done. Otherwise, leave it open
432 and store the FILE * in *PFP. */
434 RCS_reparsercsfile (rdata, pfp, rcsbufp)
437 struct rcsbuffer *rcsbufp;
441 struct rcsbuffer rcsbuf;
448 assert (rdata != NULL);
449 rcsfile = rdata->path;
451 rcsbuf_cache_open (rdata, 0, &fp, &rcsbuf);
454 /* This probably shouldn't be done until later: if a file has an
455 empty revision tree (which is permissible), rdata->versions
456 should be NULL. -twp */
457 rdata->versions = getlist ();
460 * process all the special header information, break out when we get to
461 * the first revision delta
466 /* get the next key/value pair */
469 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
471 error (1, 0, "`%s' does not appear to be a valid rcs file",
478 /* Skip head, branch and expand tags; we already have them. */
479 if (STREQ (key, RCSHEAD)
480 || STREQ (key, RCSBRANCH)
481 || STREQ (key, RCSEXPAND))
486 if (STREQ (key, "access"))
490 /* We pass the POLISH parameter as 1 because
491 RCS_addaccess expects nothing but spaces. FIXME:
492 It would be easy and more efficient to change
494 rdata->access = rcsbuf_valcopy (&rcsbuf, value, 1,
500 /* We always save lock information, so that we can handle
501 -kkvl correctly when checking out a file. */
502 if (STREQ (key, "locks"))
505 rdata->locks_data = rcsbuf_valcopy (&rcsbuf, value, 0,
507 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
509 error (1, 0, "premature end of file reading %s", rcsfile);
511 if (STREQ (key, "strict") && value == NULL)
513 rdata->strict_locks = 1;
520 if (STREQ (RCSSYMBOLS, key))
523 rdata->symbols_data = rcsbuf_valcopy (&rcsbuf, value, 0,
529 * check key for '.''s and digits (probably a rev) if it is a
530 * revision or `desc', we are done with the headers and are down to the
531 * revision deltas, so we break out of the loop
534 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
537 /* Note that when comparing with RCSDATE, we are not massaging
538 VALUE from the string found in the RCS file. This is OK
539 since we know exactly what to expect. */
540 if (*cp == '\0' && strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) == 0)
543 if (STREQ (key, RCSDESC))
546 if (STREQ (key, "comment"))
548 rdata->comment = rcsbuf_valcopy (&rcsbuf, value, 0,
552 if (rdata->other == NULL)
553 rdata->other = getlist ();
555 kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
556 kv->key = xstrdup (key);
557 kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
559 if (addnode (rdata->other, kv) != 0)
561 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
566 /* if we haven't grabbed it yet, we didn't want it */
569 /* We got out of the loop, so we have the first part of the first
570 revision delta in KEY (the revision) and VALUE (the date key
571 and its value). This is what getdelta expects to receive. */
573 while ((vnode = getdelta (&rcsbuf, rcsfile, &key, &value)) != NULL)
578 q->delproc = rcsvers_delproc;
579 q->data = (char *) vnode;
580 q->key = vnode->version;
582 /* add the nodes to the list */
583 if (addnode (rdata->versions, q) != 0)
586 purify_printf("WARNING: Adding duplicate version: %s (%s)\n",
593 /* Here KEY and VALUE are whatever caused getdelta to return NULL. */
595 if (STREQ (key, RCSDESC))
597 if (rdata->desc != NULL)
600 "warning: duplicate key `%s' in RCS file `%s'",
604 rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
607 rdata->delta_pos = rcsbuf_ftell (&rcsbuf);
610 rcsbuf_cache (rdata, &rcsbuf);
616 rdata->flags &= ~PARTIAL;
619 /* Move RCS into or out of the Attic, depending on TOATTIC. If the
620 file is already in the desired place, return without doing
621 anything. At some point may want to think about how this relates
622 to RCS_rewrite but that is a bit hairy (if one wants renames to be
623 atomic, or that kind of thing). If there is an error, print a message
624 and return 1. On success, return 0. */
626 RCS_setattic (rcs, toattic)
634 /* Some systems aren't going to let us rename an open file. */
635 rcsbuf_cache_close ();
637 /* Could make the pathname computations in this file, and probably
638 in other parts of rcs.c too, easier if the REPOS and FILE
639 arguments to RCS_parse got stashed in the RCSNode. */
645 if (rcs->flags & INATTIC)
648 /* Example: rcs->path is "/foo/bar/baz,v". */
649 newpath = xmalloc (strlen (rcs->path) + sizeof CVSATTIC + 5);
650 p = last_component (rcs->path);
651 strncpy (newpath, rcs->path, p - rcs->path);
652 strcpy (newpath + (p - rcs->path), CVSATTIC);
654 /* Create the Attic directory if it doesn't exist. */
655 omask = umask (cvsumask);
656 if (CVS_MKDIR (newpath, 0777) < 0 && errno != EEXIST)
657 error (0, errno, "cannot make directory %s", newpath);
658 (void) umask (omask);
660 strcat (newpath, "/");
663 if (CVS_RENAME (rcs->path, newpath) < 0)
665 int save_errno = errno;
667 /* The checks for isreadable look awfully fishy, but
668 I'm going to leave them here for now until I
669 can think harder about whether they take care of
670 some cases which should be handled somehow. */
672 if (isreadable (rcs->path) || !isreadable (newpath))
674 error (0, save_errno, "cannot rename %s to %s",
683 if (!(rcs->flags & INATTIC))
686 newpath = xmalloc (strlen (rcs->path));
688 /* Example: rcs->path is "/foo/bar/Attic/baz,v". */
689 p = last_component (rcs->path);
690 strncpy (newpath, rcs->path, p - rcs->path - 1);
691 newpath[p - rcs->path - 1] = '\0';
692 q = newpath + (p - rcs->path - 1) - (sizeof CVSATTIC - 1);
693 assert (strncmp (q, CVSATTIC, sizeof CVSATTIC - 1) == 0);
696 if (CVS_RENAME (rcs->path, newpath) < 0)
698 error (0, errno, "failed to move `%s' out of the attic",
712 * Fully parse the RCS file. Store all keyword/value pairs, fetch the
713 * log messages for each revision, and fetch add and delete counts for
714 * each revision (we could fetch the entire text for each revision,
715 * but the only caller, log_fileproc, doesn't need that information,
716 * so we don't waste the memory required to store it). The add and
717 * delete counts are stored on the OTHER field of the RCSVERSNODE
718 * structure, under the names ";add" and ";delete", so that we don't
719 * waste the memory space of extra fields in RCSVERSNODE for code
720 * which doesn't need this information.
724 RCS_fully_parse (rcs)
728 struct rcsbuffer rcsbuf;
730 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
738 /* Rather than try to keep track of how much information we
739 have read, just read to the end of the file. */
740 if (! rcsbuf_getrevnum (&rcsbuf, &key))
743 vers = findnode (rcs->versions, key);
746 "mismatch in rcs file %s between deltas and deltatexts (%s)",
749 vnode = (RCSVers *) vers->data;
751 while (rcsbuf_getkey (&rcsbuf, &key, &value))
753 if (! STREQ (key, "text"))
757 if (vnode->other == NULL)
758 vnode->other = getlist ();
760 kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
761 kv->key = xstrdup (key);
762 kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
764 if (addnode (vnode->other, kv) != 0)
768 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
769 key, vnode->version, rcs->path);
776 if (! STREQ (vnode->version, rcs->head))
778 unsigned long add, del;
782 /* This is a change text. Store the add and delete
791 rcsbuf_valpolish (&rcsbuf, value, 0, &vallen);
793 while (cp < value + vallen)
799 if (op != 'a' && op != 'd')
801 unrecognized operation '\\x%x' in %s",
803 (void) strtoul (cp, (char **) &cp, 10);
805 error (1, 0, "space expected in %s revision %s",
806 rcs->path, vnode->version);
807 count = strtoul (cp, (char **) &cp, 10);
809 error (1, 0, "linefeed expected in %s revision %s",
810 rcs->path, vnode->version);
821 else if (cp == value + vallen)
825 premature end of value in %s revision %s",
826 rcs->path, vnode->version);
836 sprintf (buf, "%lu", add);
839 kv->key = xstrdup (";add");
840 kv->data = xstrdup (buf);
841 if (addnode (vnode->other, kv) != 0)
845 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
846 key, vnode->version, rcs->path);
850 sprintf (buf, "%lu", del);
853 kv->key = xstrdup (";delete");
854 kv->data = xstrdup (buf);
855 if (addnode (vnode->other, kv) != 0)
859 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
860 key, vnode->version, rcs->path);
865 /* We have found the "text" key which ends the data for
866 this revision. Break out of the loop and go on to the
872 rcsbuf_cache (rcs, &rcsbuf);
876 * freercsnode - free up the info for an RCSNode
882 if (rnodep == NULL || *rnodep == NULL)
885 ((*rnodep)->refcount)--;
886 if ((*rnodep)->refcount != 0)
888 *rnodep = (RCSNode *) NULL;
891 free ((*rnodep)->path);
892 if ((*rnodep)->head != (char *) NULL)
893 free ((*rnodep)->head);
894 if ((*rnodep)->branch != (char *) NULL)
895 free ((*rnodep)->branch);
896 free_rcsnode_contents (*rnodep);
897 free ((char *) *rnodep);
898 *rnodep = (RCSNode *) NULL;
902 * free_rcsnode_contents - free up the contents of an RCSNode without
903 * freeing the node itself, or the file name, or the head, or the
904 * path. This returns the RCSNode to the state it is in immediately
905 * after a call to RCS_parse.
908 free_rcsnode_contents (rnode)
911 dellist (&rnode->versions);
912 if (rnode->symbols != (List *) NULL)
913 dellist (&rnode->symbols);
914 if (rnode->symbols_data != (char *) NULL)
915 free (rnode->symbols_data);
916 if (rnode->expand != NULL)
917 free (rnode->expand);
918 if (rnode->other != (List *) NULL)
919 dellist (&rnode->other);
920 if (rnode->access != NULL)
921 free (rnode->access);
922 if (rnode->locks_data != NULL)
923 free (rnode->locks_data);
924 if (rnode->locks != (List *) NULL)
925 dellist (&rnode->locks);
926 if (rnode->comment != NULL)
927 free (rnode->comment);
928 if (rnode->desc != NULL)
932 /* free_rcsvers_contents -- free up the contents of an RCSVers node,
933 but also free the pointer to the node itself. */
934 /* Note: The `hardlinks' list is *not* freed, since it is merely a
935 pointer into the `hardlist' structure (defined in hardlink.c), and
936 that structure is freed elsewhere in the program. */
939 free_rcsvers_contents (rnode)
942 if (rnode->branches != (List *) NULL)
943 dellist (&rnode->branches);
944 if (rnode->date != (char *) NULL)
946 if (rnode->next != (char *) NULL)
948 if (rnode->author != (char *) NULL)
949 free (rnode->author);
950 if (rnode->state != (char *) NULL)
952 if (rnode->other != (List *) NULL)
953 dellist (&rnode->other);
954 if (rnode->other_delta != NULL)
955 dellist (&rnode->other_delta);
956 if (rnode->text != NULL)
957 freedeltatext (rnode->text);
958 free ((char *) rnode);
962 * rcsvers_delproc - free up an RCSVers type node
968 free_rcsvers_contents ((RCSVers *) p->data);
971 /* These functions retrieve keys and values from an RCS file using a
972 buffer. We use this somewhat complex approach because it turns out
973 that for many common operations, CVS spends most of its time
974 reading keys, so it's worth doing some fairly hairy optimization. */
976 /* The number of bytes we try to read each time we need more data. */
978 #define RCSBUF_BUFSIZE (8192)
980 /* The buffer we use to store data. This grows as needed. */
982 static char *rcsbuf_buffer = NULL;
983 static size_t rcsbuf_buffer_size = 0;
985 /* Whether rcsbuf_buffer is in use. This is used as a sanity check. */
987 static int rcsbuf_inuse;
989 /* Set up to start gathering keys and values from an RCS file. This
990 initializes RCSBUF. */
993 rcsbuf_open (rcsbuf, fp, filename, pos)
994 struct rcsbuffer *rcsbuf;
996 const char *filename;
1000 error (1, 0, "rcsbuf_open: internal error");
1005 /* When we have mmap, it is much more efficient to let the system do the
1006 * buffering and caching for us
1009 size_t mmap_off = 0;
1011 if ( fstat (fileno(fp), &fs) < 0 )
1012 error ( 1, errno, "Could not stat RCS archive %s for mapping", filename );
1016 size_t ps = getpagesize ();
1017 mmap_off = ( pos / ps ) * ps;
1020 /* Map private here since this particular buffer is read only */
1021 rcsbuf_buffer = mmap ( NULL, fs.st_size - mmap_off,
1022 PROT_READ | PROT_WRITE,
1023 MAP_PRIVATE, fileno(fp), mmap_off );
1024 if ( rcsbuf_buffer == NULL || rcsbuf_buffer == MAP_FAILED )
1025 error ( 1, errno, "Could not map memory to RCS archive %s", filename );
1027 rcsbuf_buffer_size = fs.st_size - mmap_off;
1028 rcsbuf->ptr = rcsbuf_buffer + pos - mmap_off;
1029 rcsbuf->ptrend = rcsbuf_buffer + fs.st_size - mmap_off;
1030 rcsbuf->pos = mmap_off;
1032 #else /* HAVE_MMAP */
1033 if (rcsbuf_buffer_size < RCSBUF_BUFSIZE)
1034 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, RCSBUF_BUFSIZE);
1036 rcsbuf->ptr = rcsbuf_buffer;
1037 rcsbuf->ptrend = rcsbuf_buffer;
1039 #endif /* HAVE_MMAP */
1041 rcsbuf->filename = filename;
1043 rcsbuf->at_string = 0;
1044 rcsbuf->embedded_at = 0;
1047 /* Stop gathering keys from an RCS file. */
1050 rcsbuf_close (rcsbuf)
1051 struct rcsbuffer *rcsbuf;
1054 error (1, 0, "rcsbuf_close: internal error");
1056 munmap ( rcsbuf_buffer, rcsbuf_buffer_size );
1061 /* Read a key/value pair from an RCS file. This sets *KEYP to point
1062 to the key, and *VALUEP to point to the value. A missing or empty
1063 value is indicated by setting *VALUEP to NULL.
1065 This function returns 1 on success, or 0 on EOF. If there is an
1066 error reading the file, or an EOF in an unexpected location, it
1067 gives a fatal error.
1069 This sets *KEYP and *VALUEP to point to storage managed by
1070 rcsbuf_getkey. Moreover, *VALUEP has not been massaged from the
1071 RCS format: it may contain embedded whitespace and embedded '@'
1072 characters. Call rcsbuf_valcopy or rcsbuf_valpolish to do
1073 appropriate massaging. */
1075 /* Note that the extreme hair in rcsbuf_getkey is because profiling
1076 statistics show that it was worth it. */
1079 rcsbuf_getkey (rcsbuf, keyp, valp)
1080 struct rcsbuffer *rcsbuf;
1084 register const char * const my_spacetab = spacetab;
1085 register char *ptr, *ptrend;
1088 #define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
1091 rcsbuf->at_string = 0;
1092 rcsbuf->embedded_at = 0;
1095 ptrend = rcsbuf->ptrend;
1098 assert (ptr >= rcsbuf_buffer && ptr <= rcsbuf_buffer + rcsbuf_buffer_size);
1099 assert (ptrend >= rcsbuf_buffer && ptrend <= rcsbuf_buffer + rcsbuf_buffer_size);
1102 /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
1103 buffer, move back to the start of the buffer. This keeps the
1104 buffer from growing indefinitely. */
1105 if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
1111 /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
1112 at a time, so we can't have more bytes than that past PTR. */
1113 assert (len <= RCSBUF_BUFSIZE);
1115 /* Update the POS field, which holds the file offset of the
1116 first byte in the RCSBUF_BUFFER buffer. */
1117 rcsbuf->pos += ptr - rcsbuf_buffer;
1119 memcpy (rcsbuf_buffer, ptr, len);
1120 ptr = rcsbuf_buffer;
1122 rcsbuf->ptrend = ptrend;
1124 #endif /* ndef HAVE_MMAP */
1126 /* Skip leading whitespace. */
1133 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
1138 ptrend = rcsbuf->ptrend;
1143 if (! my_whitespace (c))
1149 /* We've found the start of the key. */
1161 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
1164 error (1, 0, "EOF in key in RCS file %s",
1167 ptrend = rcsbuf->ptrend;
1171 if (c == ';' || my_whitespace (c))
1176 /* Here *KEYP points to the key in the buffer, C is the character
1177 we found at the of the key, and PTR points to the location in
1178 the buffer where we found C. We must set *PTR to \0 in order
1179 to terminate the key. If the key ended with ';', then there is
1192 /* C must be whitespace. Skip whitespace between the key and the
1193 value. If we find ';' now, there is no value. */
1200 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
1203 error (1, 0, "EOF while looking for value in RCS file %s",
1206 ptrend = rcsbuf->ptrend;
1213 rcsbuf->ptr = ptr + 1;
1216 if (! my_whitespace (c))
1221 /* Now PTR points to the start of the value, and C is the first
1222 character of the value. */
1231 /* Optimize the common case of a value composed of a single
1234 rcsbuf->at_string = 1;
1242 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1245 /* Note that we pass PTREND as the PTR value to
1246 rcsbuf_fill, so that we will wind up setting PTR to
1247 the location corresponding to the old PTREND, so
1248 that we don't search the same bytes again. */
1249 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1253 "EOF while looking for end of string in RCS file %s",
1256 ptrend = rcsbuf->ptrend;
1260 /* Handle the special case of an '@' right at the end of
1262 if (pat + 1 >= ptrend)
1265 /* Note that we pass PAT, not PTR, here. */
1266 pat = rcsbuf_fill (rcsbuf, pat, keyp, valp);
1270 /* EOF here is OK; it just means that the last
1271 character of the file was an '@' terminating a
1272 value for a key type which does not require a
1274 pat = rcsbuf->ptrend - 1;
1278 ptrend = rcsbuf->ptrend;
1280 /* Note that the value of PTR is bogus here. This is
1281 OK, because we don't use it. */
1285 if (pat + 1 >= ptrend || pat[1] != '@')
1288 /* We found an '@' pair in the string. Keep looking. */
1289 ++rcsbuf->embedded_at;
1293 /* Here PAT points to the final '@' in the string. */
1300 rcsbuf->vlen = vlen;
1305 /* Certain keywords only have a '@' string. If there is no '@'
1306 string, then the old getrcskey function assumed that they had
1307 no value, and we do the same. */
1313 if (STREQ (k, RCSDESC)
1314 || STREQ (k, "text")
1315 || STREQ (k, "log"))
1324 /* If we've already gathered a '@' string, try to skip whitespace
1335 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1338 error (1, 0, "EOF in value in RCS file %s",
1341 ptrend = rcsbuf->ptrend;
1347 /* We're done. We already set everything up for this
1349 rcsbuf->ptr = ptr + 1;
1352 if (! my_whitespace (n))
1357 /* The value extends past the '@' string. We need to undo the
1358 '@' stripping done in the default case above. This
1359 case never happens in a plain RCS file, but it can happen
1360 if user defined phrases are used. */
1361 ((*valp)--)[rcsbuf->vlen++] = '@';
1364 /* Here we have a value which is not a simple '@' string. We need
1365 to gather up everything until the next ';', including any '@'
1366 strings. *VALP points to the start of the value. If
1367 RCSBUF->VLEN is not zero, then we have already read an '@'
1368 string, and PTR points to the data following the '@' string.
1369 Otherwise, PTR points to the start of the value. */
1373 char *start, *psemi, *pat;
1375 /* Find the ';' which must end the value. */
1377 while ((psemi = memchr (ptr, ';', ptrend - ptr)) == NULL)
1382 /* Note that we pass PTREND as the PTR value to
1383 rcsbuf_fill, so that we will wind up setting PTR to the
1384 location corresponding to the old PTREND, so that we
1385 don't search the same bytes again. */
1386 slen = start - *valp;
1387 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1390 error (1, 0, "EOF in value in RCS file %s", rcsbuf->filename);
1392 start = *valp + slen;
1393 ptrend = rcsbuf->ptrend;
1397 /* See if there are any '@' strings in the value. */
1398 pat = memchr (start, '@', psemi - start);
1404 /* We're done with the value. Trim any trailing
1407 rcsbuf->ptr = psemi + 1;
1410 while (psemi > start && my_whitespace (psemi[-1]))
1414 vlen = psemi - start;
1417 rcsbuf->vlen = vlen;
1422 /* We found an '@' string in the value. We set RCSBUF->AT_STRING
1423 and RCSBUF->EMBEDDED_AT to indicate that we won't be able to
1424 compress whitespace correctly for this type of value.
1425 Since this type of value never arises in a normal RCS file,
1426 this should not be a big deal. It means that if anybody
1427 adds a phrase which can have both an '@' string and regular
1428 text, they will have to handle whitespace compression
1431 rcsbuf->at_string = 1;
1432 rcsbuf->embedded_at = -1;
1438 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1441 /* Note that we pass PTREND as the PTR value to
1442 rcsbuff_fill, so that we will wind up setting PTR
1443 to the location corresponding to the old PTREND, so
1444 that we don't search the same bytes again. */
1445 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1449 "EOF while looking for end of string in RCS file %s",
1452 ptrend = rcsbuf->ptrend;
1456 /* Handle the special case of an '@' right at the end of
1458 if (pat + 1 >= ptrend)
1461 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1464 error (1, 0, "EOF in value in RCS file %s",
1467 ptrend = rcsbuf->ptrend;
1474 /* We found an '@' pair in the string. Keep looking. */
1478 /* Here PAT points to the final '@' in the string. */
1482 #undef my_whitespace
1485 /* Read an RCS revision number from an RCS file. This sets *REVP to
1486 point to the revision number; it will point to space that is
1487 managed by the rcsbuf functions, and is only good until the next
1488 call to rcsbuf_getkey or rcsbuf_getrevnum.
1490 This function returns 1 on success, or 0 on EOF. If there is an
1491 error reading the file, or an EOF in an unexpected location, it
1492 gives a fatal error. */
1495 rcsbuf_getrevnum (rcsbuf, revp)
1496 struct rcsbuffer *rcsbuf;
1503 ptrend = rcsbuf->ptrend;
1507 /* Skip leading whitespace. */
1514 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
1519 ptrend = rcsbuf->ptrend;
1524 if (! whitespace (c))
1530 if (! isdigit ((unsigned char) c) && c != '.')
1533 unexpected '\\x%x' reading revision number in RCS file %s",
1534 c, rcsbuf->filename);
1544 ptr = rcsbuf_fill (rcsbuf, ptr, revp, (char **) NULL);
1548 "unexpected EOF reading revision number in RCS file %s",
1551 ptrend = rcsbuf->ptrend;
1557 while (isdigit ((unsigned char) c) || c == '.');
1559 if (! whitespace (c))
1561 unexpected '\\x%x' reading revision number in RCS file %s",
1562 c, rcsbuf->filename);
1566 rcsbuf->ptr = ptr + 1;
1572 /* Fill RCSBUF_BUFFER with bytes from the file associated with RCSBUF,
1573 updating PTR and the PTREND field. If KEYP and *KEYP are not NULL,
1574 then *KEYP points into the buffer, and must be adjusted if the
1575 buffer is changed. Likewise for VALP. Returns the new value of
1576 PTR, or NULL on error. */
1579 rcsbuf_fill (rcsbuf, ptr, keyp, valp)
1580 struct rcsbuffer *rcsbuf;
1587 if (rcsbuf->ptrend - rcsbuf_buffer + RCSBUF_BUFSIZE > rcsbuf_buffer_size)
1589 int poff, peoff, koff, voff;
1591 poff = ptr - rcsbuf_buffer;
1592 peoff = rcsbuf->ptrend - rcsbuf_buffer;
1593 koff = keyp == NULL ? 0 : *keyp - rcsbuf_buffer;
1594 voff = valp == NULL ? 0 : *valp - rcsbuf_buffer;
1596 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size,
1597 rcsbuf_buffer_size + RCSBUF_BUFSIZE);
1599 ptr = rcsbuf_buffer + poff;
1600 rcsbuf->ptrend = rcsbuf_buffer + peoff;
1602 *keyp = rcsbuf_buffer + koff;
1604 *valp = rcsbuf_buffer + voff;
1607 got = fread (rcsbuf->ptrend, 1, RCSBUF_BUFSIZE, rcsbuf->fp);
1610 if (ferror (rcsbuf->fp))
1611 error (1, errno, "cannot read %s", rcsbuf->filename);
1615 rcsbuf->ptrend += got;
1619 #endif /* HAVE_MMAP */
1621 /* Test whether the last value returned by rcsbuf_getkey is a composite
1625 rcsbuf_valcmp (rcsbuf)
1626 struct rcsbuffer *rcsbuf;
1628 return rcsbuf->at_string && rcsbuf->embedded_at < 0;
1631 /* Copy the value VAL returned by rcsbuf_getkey into a memory buffer,
1632 returning the memory buffer. Polish the value like
1633 rcsbuf_valpolish, q.v. */
1636 rcsbuf_valcopy (rcsbuf, val, polish, lenp)
1637 struct rcsbuffer *rcsbuf;
1653 vlen = rcsbuf->vlen;
1654 embedded_at = rcsbuf->embedded_at < 0 ? 0 : rcsbuf->embedded_at;
1656 ret = xmalloc (vlen - embedded_at + 1);
1658 if (rcsbuf->at_string ? embedded_at == 0 : ! polish)
1660 /* No special action to take. */
1661 memcpy (ret, val, vlen + 1);
1667 rcsbuf_valpolish_internal (rcsbuf, ret, val, lenp);
1671 /* Polish the value VAL returned by rcsbuf_getkey. The POLISH
1672 parameter is non-zero if multiple embedded whitespace characters
1673 should be compressed into a single whitespace character. Note that
1674 leading and trailing whitespace was already removed by
1675 rcsbuf_getkey. Within an '@' string, pairs of '@' characters are
1676 compressed into a single '@' character regardless of the value of
1677 POLISH. If LENP is not NULL, set *LENP to the length of the value. */
1680 rcsbuf_valpolish (rcsbuf, val, polish, lenp)
1681 struct rcsbuffer *rcsbuf;
1693 if (rcsbuf->at_string ? rcsbuf->embedded_at == 0 : ! polish)
1695 /* No special action to take. */
1697 *lenp = rcsbuf->vlen;
1701 rcsbuf_valpolish_internal (rcsbuf, val, val, lenp);
1704 /* Internal polishing routine, called from rcsbuf_valcopy and
1705 rcsbuf_valpolish. */
1708 rcsbuf_valpolish_internal (rcsbuf, to, from, lenp)
1709 struct rcsbuffer *rcsbuf;
1718 if (! rcsbuf->at_string)
1725 for (clen = len; clen > 0; ++from, --clen)
1732 /* Note that we know that clen can not drop to zero
1733 while we have whitespace, because we know there is
1734 no trailing whitespace. */
1735 while (whitespace (from[1]))
1748 *lenp = to - orig_to;
1752 const char *orig_from;
1760 embedded_at = rcsbuf->embedded_at;
1761 assert (embedded_at > 0);
1764 *lenp = len - embedded_at;
1766 for (clen = len; clen > 0; ++from, --clen)
1778 * FIXME: I restored this to an abort from an assert based on
1779 * advice from Larry Jones that asserts should not be used to
1780 * confirm the validity of an RCS file... This leaves two
1781 * issues here: 1) I am uncertain that the fact that we will
1782 * only find double '@'s hasn't already been confirmed; and:
1783 * 2) If this is the proper place to spot the error in the RCS
1784 * file, then we should print a much clearer error here for the
1789 if (*from != '@' || clen == 0)
1795 if (embedded_at == 0)
1797 /* We've found all the embedded '@' characters.
1798 We can just memcpy the rest of the buffer after
1799 this '@' character. */
1800 if (orig_to != orig_from)
1801 memcpy (to, from + 1, clen - 1);
1803 memmove (to, from + 1, clen - 1);
1812 assert (from == orig_from + len
1813 && to == orig_to + (len - rcsbuf->embedded_at));
1819 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1821 /* Copy the next word from the value VALP returned by rcsbuf_getkey into a
1822 memory buffer, updating VALP and returning the memory buffer. Return
1823 NULL when there are no more words. */
1826 rcsbuf_valword (rcsbuf, valp)
1827 struct rcsbuffer *rcsbuf;
1830 register const char * const my_spacetab = spacetab;
1831 register char *ptr, *pat;
1834 # define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
1839 for (ptr = *valp; my_whitespace (*ptr); ++ptr) ;
1842 assert (ptr - *valp == rcsbuf->vlen);
1848 /* PTR now points to the start of a value. Find out whether it is
1849 a num, an id, a string or a colon. */
1853 rcsbuf->vlen -= ++ptr - *valp;
1855 return xstrdup (":");
1860 int embedded_at = 0;
1864 while ((pat = strchr (pat, '@')) != NULL)
1872 /* Here PAT points to the final '@' in the string. */
1874 assert (rcsbuf->at_string);
1875 vlen = rcsbuf->vlen - (pat - *valp);
1876 rcsbuf->vlen = pat - ptr - 1;
1877 rcsbuf->embedded_at = embedded_at;
1878 ptr = rcsbuf_valcopy (rcsbuf, ptr, 0, (size_t *) NULL);
1880 rcsbuf->vlen = vlen;
1881 if (strchr (pat, '@') == NULL)
1882 rcsbuf->at_string = 0;
1884 rcsbuf->embedded_at = -1;
1888 /* *PTR is neither `:', `;' nor `@', so it should be the start of a num
1889 or an id. Make sure it is not another special character. */
1890 if (c == '$' || c == '.' || c == ',')
1892 error (1, 0, "invalid special character in RCS field in %s",
1899 /* Legitimate ID characters are digits, dots and any `graphic
1900 printing character that is not a special.' This test ought
1903 if (!isprint ((unsigned char) c) ||
1904 c == ';' || c == '$' || c == ',' || c == '@' || c == ':')
1908 /* PAT points to the last non-id character in this word, and C is
1909 the character in its memory cell. Check to make sure that it
1910 is a legitimate word delimiter -- whitespace or end. */
1911 if (c != '\0' && !my_whitespace (c))
1912 error (1, 0, "invalid special character in RCS field in %s",
1916 rcsbuf->vlen -= pat - *valp;
1918 return xstrdup (ptr);
1920 # undef my_whitespace
1925 /* Return the current position of an rcsbuf. */
1927 static unsigned long
1928 rcsbuf_ftell (rcsbuf)
1929 struct rcsbuffer *rcsbuf;
1931 return rcsbuf->pos + rcsbuf->ptr - rcsbuf_buffer;
1934 /* Return a pointer to any data buffered for RCSBUF, along with the
1938 rcsbuf_get_buffered (rcsbuf, datap, lenp)
1939 struct rcsbuffer *rcsbuf;
1943 *datap = rcsbuf->ptr;
1944 *lenp = rcsbuf->ptrend - rcsbuf->ptr;
1947 /* CVS optimizes by quickly reading some header information from a
1948 file. If it decides it needs to do more with the file, it reopens
1949 it. We speed that up here by maintaining a cache of a single open
1950 file, to save the time it takes to reopen the file in the common
1953 static RCSNode *cached_rcs;
1954 static struct rcsbuffer cached_rcsbuf;
1956 /* Cache RCS and RCSBUF. This takes responsibility for closing
1960 rcsbuf_cache (rcs, rcsbuf)
1962 struct rcsbuffer *rcsbuf;
1964 if (cached_rcs != NULL)
1965 rcsbuf_cache_close ();
1968 cached_rcsbuf = *rcsbuf;
1971 /* If there is anything in the cache, close it. */
1974 rcsbuf_cache_close ()
1976 if (cached_rcs != NULL)
1978 rcsbuf_close (&cached_rcsbuf);
1979 if (fclose (cached_rcsbuf.fp) != 0)
1980 error (0, errno, "cannot close %s", cached_rcsbuf.filename);
1981 freercsnode (&cached_rcs);
1986 /* Open an rcsbuffer for RCS, getting it from the cache if possible.
1987 Set *FPP to the file, and *RCSBUFP to the rcsbuf. The file should
1988 be put at position POS. */
1991 rcsbuf_cache_open (rcs, pos, pfp, prcsbuf)
1995 struct rcsbuffer *prcsbuf;
1998 if (cached_rcs == rcs)
2000 if (rcsbuf_ftell (&cached_rcsbuf) != pos)
2002 if (fseek (cached_rcsbuf.fp, pos, SEEK_SET) != 0)
2003 error (1, 0, "cannot fseek RCS file %s",
2004 cached_rcsbuf.filename);
2005 cached_rcsbuf.ptr = rcsbuf_buffer;
2006 cached_rcsbuf.ptrend = rcsbuf_buffer;
2007 cached_rcsbuf.pos = pos;
2009 *pfp = cached_rcsbuf.fp;
2011 /* When RCS_parse opens a file using fopen_case, it frees the
2012 filename which we cached in CACHED_RCSBUF and stores a new
2013 file name in RCS->PATH. We avoid problems here by always
2014 copying the filename over. FIXME: This is hackish. */
2015 cached_rcsbuf.filename = rcs->path;
2017 *prcsbuf = cached_rcsbuf;
2021 /* Removing RCS from the cache removes a reference to it. */
2023 if (rcs->refcount <= 0)
2024 error (1, 0, "rcsbuf_cache_open: internal error");
2028 #endif /* ifndef HAVE_MMAP */
2029 /* FIXME: If these routines can be rewritten to not write to the
2030 * rcs file buffer, there would be a considerably larger memory savings
2031 * from using mmap since the shared file would never need be copied to
2034 * If this happens, cached mmapped buffers would be usable, but don't
2035 * forget to make sure rcs->pos < pos here...
2037 if (cached_rcs != NULL)
2038 rcsbuf_cache_close ();
2040 *pfp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ);
2042 error (1, 0, "unable to reopen `%s'", rcs->path);
2046 if (fseek (*pfp, pos, SEEK_SET) != 0)
2047 error (1, 0, "cannot fseek RCS file %s", rcs->path);
2049 #endif /* ifndef HAVE_MMAP */
2050 rcsbuf_open (prcsbuf, *pfp, rcs->path, pos);
2053 #endif /* ifndef HAVE_MMAP */
2058 * process the symbols list of the rcs file
2061 do_symbols (list, val)
2071 /* skip leading whitespace */
2072 while (whitespace (*cp))
2075 /* if we got to the end, we are done */
2079 /* split it up into tag and rev */
2081 cp = strchr (cp, ':');
2084 while (!whitespace (*cp) && *cp != '\0')
2089 /* make a new node and add it to the list */
2091 p->key = xstrdup (tag);
2092 p->data = xstrdup (rev);
2093 (void) addnode (list, p);
2098 * process the locks list of the rcs file
2099 * Like do_symbols, but hash entries are keyed backwards: i.e.
2100 * an entry like `user:rev' is keyed on REV rather than on USER.
2103 do_locks (list, val)
2113 /* skip leading whitespace */
2114 while (whitespace (*cp))
2117 /* if we got to the end, we are done */
2121 /* split it up into user and rev */
2123 cp = strchr (cp, ':');
2126 while (!whitespace (*cp) && *cp != '\0')
2131 /* make a new node and add it to the list */
2133 p->key = xstrdup (rev);
2134 p->data = xstrdup (user);
2135 (void) addnode (list, p);
2140 * process the branches list of a revision delta
2143 do_branches (list, val)
2153 /* skip leading whitespace */
2154 while (whitespace (*cp))
2157 /* if we got to the end, we are done */
2161 /* find the end of this branch */
2163 while (!whitespace (*cp) && *cp != '\0')
2168 /* make a new node and add it to the list */
2170 p->key = xstrdup (branch);
2171 (void) addnode (list, p);
2178 * Returns the requested version number of the RCS file, satisfying tags and/or
2179 * dates, and walking branches, if necessary.
2181 * The result is returned; null-string if error.
2184 RCS_getversion (rcs, tag, date, force_tag_match, simple_tag)
2188 int force_tag_match;
2191 if (simple_tag != NULL)
2194 /* make sure we have something to look at... */
2195 assert (rcs != NULL);
2201 if (! RCS_nodeisbranch (rcs, tag))
2203 /* We can't get a particular date if the tag is not a
2208 /* Work out the branch. */
2209 if (! isdigit ((unsigned char) tag[0]))
2210 branch = RCS_whatbranch (rcs, tag);
2212 branch = xstrdup (tag);
2214 /* Fetch the revision of branch as of date. */
2215 rev = RCS_getdatebranch (rcs, date, branch);
2220 return (RCS_gettag (rcs, tag, force_tag_match, simple_tag));
2222 return (RCS_getdate (rcs, date, force_tag_match));
2224 return (RCS_head (rcs));
2229 * Get existing revision number corresponding to tag or revision.
2230 * Similar to RCS_gettag but less interpretation imposed.
2232 * -- If tag designates a magic branch, RCS_tag2rev
2233 * returns the magic branch number.
2234 * -- If tag is a branch tag, returns the branch number, not
2235 * the revision of the head of the branch.
2236 * If tag or revision is not valid or does not exist in file,
2240 RCS_tag2rev (rcs, tag)
2244 char *rev, *pa, *pb;
2247 assert (rcs != NULL);
2249 if (rcs->flags & PARTIAL)
2250 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2252 /* If a valid revision, try to look it up */
2253 if ( RCS_valid_rev (tag) )
2255 /* Make a copy so we can scribble on it */
2256 rev = xstrdup (tag);
2258 /* If revision exists, return the copy */
2259 if (RCS_exist_rev (rcs, tag))
2262 /* Nope, none such. If tag is not a branch we're done. */
2266 pa = strrchr (rev, '.');
2267 if (i == 1 || *(pa-1) != RCS_MAGIC_BRANCH || *(pa-2) != '.')
2270 error (1, 0, "revision `%s' does not exist", tag);
2274 /* Try for a real (that is, exists in the RCS deltas) branch
2275 (RCS_exist_rev just checks for real revisions and revisions
2276 which have tags pointing to them). */
2277 pa = RCS_getbranch (rcs, rev, 1);
2284 /* Tag is branch, but does not exist, try corresponding
2287 * FIXME: assumes all magic branches are of
2288 * form "n.n.n ... .0.n". I'll fix if somebody can
2289 * send me a method to get a magic branch tag with
2290 * the 0 in some other position -- <dan@gasboy.com>
2292 pa = strrchr (rev, '.');
2293 pb = xmalloc (strlen (rev) + 3);
2295 (void) sprintf (pb, "%s.%d.%s", rev, RCS_MAGIC_BRANCH, pa);
2298 if (RCS_exist_rev (rcs, rev))
2300 error (1, 0, "revision `%s' does not exist", tag);
2304 RCS_check_tag (tag); /* exit if not a valid tag */
2306 /* If tag is "HEAD", special case to get head RCS revision */
2307 if (tag && STREQ (tag, TAG_HEAD))
2308 return (RCS_head (rcs));
2310 /* If valid tag let translate_symtag say yea or nay. */
2311 rev = translate_symtag (rcs, tag);
2316 /* Trust the caller to print warnings. */
2321 * Find the revision for a specific tag.
2322 * If force_tag_match is set, return NULL if an exact match is not
2323 * possible otherwise return RCS_head (). We are careful to look for
2324 * and handle "magic" revisions specially.
2326 * If the matched tag is a branch tag, find the head of the branch.
2328 * Returns pointer to newly malloc'd string, or NULL.
2331 RCS_gettag (rcs, symtag, force_tag_match, simple_tag)
2334 int force_tag_match;
2338 int tag_allocated = 0;
2340 if (simple_tag != NULL)
2343 /* make sure we have something to look at... */
2344 assert (rcs != NULL);
2346 /* XXX this is probably not necessary, --jtc */
2347 if (rcs->flags & PARTIAL)
2348 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2350 /* If tag is "HEAD", special case to get head RCS revision */
2351 if (tag && STREQ (tag, TAG_HEAD))
2352 #if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */
2353 if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
2354 return ((char *) NULL); /* head request for removed file */
2357 return (RCS_head (rcs));
2359 if (!isdigit ((unsigned char) tag[0]))
2363 /* If we got a symbolic tag, resolve it to a numeric */
2364 version = translate_symtag (rcs, tag);
2365 if (version != NULL)
2368 char *magic, *branch, *cp;
2374 * If this is a magic revision, we turn it into either its
2375 * physical branch equivalent (if one exists) or into
2376 * its base revision, which we assume exists.
2378 dots = numdots (tag);
2379 if (dots > 2 && (dots & 1) != 0)
2381 branch = strrchr (tag, '.');
2386 /* see if we have .magic-branch. (".0.") */
2387 magic = xmalloc (strlen (tag) + 1);
2388 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2389 if (strncmp (magic, cp, strlen (magic)) == 0)
2391 /* it's magic. See if the branch exists */
2392 *cp = '\0'; /* turn it into a revision */
2393 (void) sprintf (magic, "%s.%s", tag, branch);
2394 branch = RCS_getbranch (rcs, magic, 1);
2408 /* The tag wasn't there, so return the head or NULL */
2409 if (force_tag_match)
2412 return (RCS_head (rcs));
2417 * numeric tag processing:
2418 * 1) revision number - just return it
2419 * 2) branch number - find head of branch
2422 /* strip trailing dots */
2423 while (tag[strlen (tag) - 1] == '.')
2424 tag[strlen (tag) - 1] = '\0';
2426 if ((numdots (tag) & 1) == 0)
2430 /* we have a branch tag, so we need to walk the branch */
2431 branch = RCS_getbranch (rcs, tag, force_tag_match);
2440 /* we have a revision tag, so make sure it exists */
2441 p = findnode (rcs->versions, tag);
2444 /* We have found a numeric revision for the revision tag.
2445 To support expanding the RCS keyword Name, if
2446 SIMPLE_TAG is not NULL, tell the the caller that this
2447 is a simple tag which co will recognize. FIXME: Are
2448 there other cases in which we should set this? In
2449 particular, what if we expand RCS keywords internally
2450 without calling co? */
2451 if (simple_tag != NULL)
2453 if (! tag_allocated)
2454 tag = xstrdup (tag);
2459 /* The revision wasn't there, so return the head or NULL */
2462 if (force_tag_match)
2465 return (RCS_head (rcs));
2471 * Return a "magic" revision as a virtual branch off of REV for the RCS file.
2472 * A "magic" revision is one which is unique in the RCS file. By unique, I
2473 * mean we return a revision which:
2474 * - has a branch of 0 (see rcs.h RCS_MAGIC_BRANCH)
2475 * - has a revision component which is not an existing branch off REV
2476 * - has a revision component which is not an existing magic revision
2477 * - is an even-numbered revision, to avoid conflicts with vendor branches
2478 * The first point is what makes it "magic".
2480 * As an example, if we pass in 1.37 as REV, we will look for an existing
2481 * branch called 1.37.2. If it did not exist, we would look for an
2482 * existing symbolic tag with a numeric part equal to 1.37.0.2. If that
2483 * didn't exist, then we know that the 1.37.2 branch can be reserved by
2484 * creating a symbolic tag with 1.37.0.2 as the numeric part.
2486 * This allows us to fork development with very little overhead -- just a
2487 * symbolic tag is used in the RCS file. When a commit is done, a physical
2488 * branch is dynamically created to hold the new revision.
2490 * Note: We assume that REV is an RCS revision and not a branch number.
2492 static char *check_rev;
2494 RCS_magicrev (rcs, rev)
2499 char *xrev, *test_branch;
2501 xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */
2504 /* only look at even numbered branches */
2505 for (rev_num = 2; ; rev_num += 2)
2507 /* see if the physical branch exists */
2508 (void) sprintf (xrev, "%s.%d", rev, rev_num);
2509 test_branch = RCS_getbranch (rcs, xrev, 1);
2510 if (test_branch != NULL) /* it did, so keep looking */
2516 /* now, create a "magic" revision */
2517 (void) sprintf (xrev, "%s.%d.%d", rev, RCS_MAGIC_BRANCH, rev_num);
2519 /* walk the symbols list to see if a magic one already exists */
2520 if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0)
2523 /* we found a free magic branch. Claim it as ours */
2529 * walklist proc to look for a match in the symbols list.
2530 * Returns 0 if the symbol does not match, 1 if it does.
2533 checkmagic_proc (p, closure)
2537 if (STREQ (check_rev, p->data))
2544 * Given an RCSNode, returns non-zero if the specified revision number
2545 * or symbolic tag resolves to a "branch" within the rcs file.
2547 * FIXME: this is the same as RCS_nodeisbranch except for the special
2548 * case for handling a null rcsnode.
2551 RCS_isbranch (rcs, rev)
2555 /* numeric revisions are easy -- even number of dots is a branch */
2556 if (isdigit ((unsigned char) *rev))
2557 return ((numdots (rev) & 1) == 0);
2559 /* assume a revision if you can't find the RCS info */
2563 /* now, look for a match in the symbols list */
2564 return (RCS_nodeisbranch (rcs, rev));
2568 * Given an RCSNode, returns non-zero if the specified revision number
2569 * or symbolic tag resolves to a "branch" within the rcs file. We do
2570 * take into account any magic branches as well.
2573 RCS_nodeisbranch (rcs, rev)
2580 assert (rcs != NULL);
2582 /* numeric revisions are easy -- even number of dots is a branch */
2583 if (isdigit ((unsigned char) *rev))
2584 return ((numdots (rev) & 1) == 0);
2586 version = translate_symtag (rcs, rev);
2587 if (version == NULL)
2589 dots = numdots (version);
2590 if ((dots & 1) == 0)
2596 /* got a symbolic tag match, but it's not a branch; see if it's magic */
2600 char *branch = strrchr (version, '.');
2601 char *cp = branch - 1;
2605 /* see if we have .magic-branch. (".0.") */
2606 magic = xmalloc (strlen (version) + 1);
2607 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2608 if (strncmp (magic, cp, strlen (magic)) == 0)
2621 * Returns a pointer to malloc'ed memory which contains the branch
2622 * for the specified *symbolic* tag. Magic branches are handled correctly.
2625 RCS_whatbranch (rcs, rev)
2632 /* assume no branch if you can't find the RCS info */
2634 return ((char *) NULL);
2636 /* now, look for a match in the symbols list */
2637 version = translate_symtag (rcs, rev);
2638 if (version == NULL)
2639 return ((char *) NULL);
2640 dots = numdots (version);
2641 if ((dots & 1) == 0)
2644 /* got a symbolic tag match, but it's not a branch; see if it's magic */
2648 char *branch = strrchr (version, '.');
2649 char *cp = branch++ - 1;
2653 /* see if we have .magic-branch. (".0.") */
2654 magic = xmalloc (strlen (version) + 1);
2655 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2656 if (strncmp (magic, cp, strlen (magic)) == 0)
2658 /* yep. it's magic. now, construct the real branch */
2659 *cp = '\0'; /* turn it into a revision */
2660 (void) sprintf (magic, "%s.%s", version, branch);
2667 return ((char *) NULL);
2671 * Get the head of the specified branch. If the branch does not exist,
2672 * return NULL or RCS_head depending on force_tag_match.
2673 * Returns NULL or a newly malloc'd string.
2676 RCS_getbranch (rcs, tag, force_tag_match)
2679 int force_tag_match;
2687 /* make sure we have something to look at... */
2688 assert (rcs != NULL);
2690 if (rcs->flags & PARTIAL)
2691 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2693 /* find out if the tag contains a dot, or is on the trunk */
2694 cp = strrchr (tag, '.');
2696 /* trunk processing is the special case */
2699 xtag = xmalloc (strlen (tag) + 1 + 1); /* +1 for an extra . */
2700 (void) strcpy (xtag, tag);
2701 (void) strcat (xtag, ".");
2702 for (cp = rcs->head; cp != NULL;)
2704 if (strncmp (xtag, cp, strlen (xtag)) == 0)
2706 p = findnode (rcs->versions, cp);
2710 if (force_tag_match)
2713 return (RCS_head (rcs));
2715 vn = (RCSVers *) p->data;
2721 if (force_tag_match)
2724 return (RCS_head (rcs));
2726 return (xstrdup (cp));
2729 /* if it had a `.', terminate the string so we have the base revision */
2732 /* look up the revision this branch is based on */
2733 p = findnode (rcs->versions, tag);
2735 /* put the . back so we have the branch again */
2740 /* if the base revision didn't exist, return head or NULL */
2741 if (force_tag_match)
2744 return (RCS_head (rcs));
2747 /* find the first element of the branch we are looking for */
2748 vn = (RCSVers *) p->data;
2749 if (vn->branches == NULL)
2751 xtag = xmalloc (strlen (tag) + 1 + 1); /* 1 for the extra '.' */
2752 (void) strcpy (xtag, tag);
2753 (void) strcat (xtag, ".");
2754 head = vn->branches->list;
2755 for (p = head->next; p != head; p = p->next)
2756 if (strncmp (p->key, xtag, strlen (xtag)) == 0)
2762 /* we didn't find a match so return head or NULL */
2763 if (force_tag_match)
2766 return (RCS_head (rcs));
2769 /* now walk the next pointers of the branch */
2773 p = findnode (rcs->versions, nextvers);
2776 /* a link in the chain is missing - return head or NULL */
2777 if (force_tag_match)
2780 return (RCS_head (rcs));
2782 vn = (RCSVers *) p->data;
2783 nextvers = vn->next;
2784 } while (nextvers != NULL);
2786 /* we have the version in our hand, so go for it */
2787 return (xstrdup (vn->version));
2790 /* Returns the head of the branch which REV is on. REV can be a
2791 branch tag or non-branch tag; symbolic or numeric.
2793 Returns a newly malloc'd string. Returns NULL if a symbolic name
2797 RCS_branch_head (rcs, rev)
2805 assert (rcs != NULL);
2807 if (RCS_nodeisbranch (rcs, rev))
2808 return RCS_getbranch (rcs, rev, 1);
2810 if (isdigit ((unsigned char) *rev))
2811 num = xstrdup (rev);
2814 num = translate_symtag (rcs, rev);
2818 br = truncate_revnum (num);
2819 retval = RCS_getbranch (rcs, br, 1);
2825 /* Get the branch point for a particular branch, that is the first
2826 revision on that branch. For example, RCS_getbranchpoint (rcs,
2827 "1.3.2") will normally return "1.3.2.1". TARGET may be either a
2828 branch number or a revision number; if a revnum, find the
2829 branchpoint of the branch to which TARGET belongs.
2831 Return RCS_head if TARGET is on the trunk or if the root node could
2832 not be found (this is sort of backwards from our behavior on a branch;
2833 the rationale is that the return value is a revision from which you
2834 can start walking the next fields and end up at TARGET).
2835 Return NULL on error. */
2838 RCS_getbranchpoint (rcs, target)
2845 int dots, isrevnum, brlen;
2847 dots = numdots (target);
2848 isrevnum = dots & 1;
2851 /* TARGET is a trunk revision; return rcs->head. */
2852 return (RCS_head (rcs));
2854 /* Get the revision number of the node at which TARGET's branch is
2855 rooted. If TARGET is a branch number, lop off the last field;
2856 if it's a revision number, lop off the last *two* fields. */
2857 branch = xstrdup (target);
2858 bp = strrchr (branch, '.');
2860 error (1, 0, "%s: confused revision number %s",
2863 while (*--bp != '.')
2867 vp = findnode (rcs->versions, branch);
2870 error (0, 0, "%s: can't find branch point %s", rcs->path, target);
2873 rev = (RCSVers *) vp->data;
2876 while (*bp && *bp != '.')
2878 brlen = bp - branch;
2880 vp = rev->branches->list->next;
2881 while (vp != rev->branches->list)
2883 /* BRANCH may be a genuine branch number, e.g. `1.1.3', or
2884 maybe a full revision number, e.g. `1.1.3.6'. We have
2885 found our branch point if the first BRANCHLEN characters
2886 of the revision number match, *and* if the following
2887 character is a dot. */
2888 if (strncmp (vp->key, branch, brlen) == 0 && vp->key[brlen] == '.')
2894 if (vp == rev->branches->list)
2896 error (0, 0, "%s: can't find branch point %s", rcs->path, target);
2900 return (xstrdup (vp->key));
2904 * Get the head of the RCS file. If branch is set, this is the head of the
2905 * branch, otherwise the real head.
2906 * Returns NULL or a newly malloc'd string.
2912 /* make sure we have something to look at... */
2913 assert (rcs != NULL);
2916 * NOTE: we call getbranch with force_tag_match set to avoid any
2917 * possibility of recursion
2920 return (RCS_getbranch (rcs, rcs->branch, 1));
2922 return (xstrdup (rcs->head));
2926 * Get the most recent revision, based on the supplied date, but use some
2927 * funky stuff and follow the vendor branch maybe
2930 RCS_getdate (rcs, date, force_tag_match)
2933 int force_tag_match;
2935 char *cur_rev = NULL;
2936 char *retval = NULL;
2938 RCSVers *vers = NULL;
2940 /* make sure we have something to look at... */
2941 assert (rcs != NULL);
2943 if (rcs->flags & PARTIAL)
2944 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2946 /* if the head is on a branch, try the branch first */
2947 if (rcs->branch != NULL)
2949 retval = RCS_getdatebranch (rcs, date, rcs->branch);
2954 /* otherwise if we have a trunk, try it */
2957 p = findnode (rcs->versions, rcs->head);
2960 error (0, 0, "%s: head revision %s doesn't exist", rcs->path,
2965 /* if the date of this one is before date, take it */
2966 vers = (RCSVers *) p->data;
2967 if (RCS_datecmp (vers->date, date) <= 0)
2969 cur_rev = vers->version;
2973 /* if there is a next version, find the node */
2974 if (vers->next != NULL)
2975 p = findnode (rcs->versions, vers->next);
2981 error (0, 0, "%s: no head revision", rcs->path);
2984 * at this point, either we have the revision we want, or we have the
2985 * first revision on the trunk (1.1?) in our hands, or we've come up
2989 /* if we found what we're looking for, and it's not 1.1 return it */
2990 if (cur_rev != NULL)
2992 if (! STREQ (cur_rev, "1.1"))
2993 return (xstrdup (cur_rev));
2995 /* This is 1.1; if the date of 1.1 is not the same as that for the
2996 1.1.1.1 version, then return 1.1. This happens when the first
2997 version of a file is created by a regular cvs add and commit,
2998 and there is a subsequent cvs import of the same file. */
2999 p = findnode (rcs->versions, "1.1.1.1");
3002 vers = (RCSVers *) p->data;
3003 if (RCS_datecmp (vers->date, date) != 0)
3004 return xstrdup ("1.1");
3008 /* look on the vendor branch */
3009 retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
3012 * if we found a match, return it; otherwise, we return the first
3013 * revision on the trunk or NULL depending on force_tag_match and the
3014 * date of the first rev
3019 if (!force_tag_match ||
3020 (vers != NULL && RCS_datecmp (vers->date, date) <= 0))
3021 return (xstrdup (vers->version));
3027 * Look up the last element on a branch that was put in before the specified
3028 * date (return the rev or NULL)
3031 RCS_getdatebranch (rcs, date, branch)
3036 char *cur_rev = NULL;
3038 char *xbranch, *xrev;
3042 /* look up the first revision on the branch */
3043 xrev = xstrdup (branch);
3044 cp = strrchr (xrev, '.');
3050 *cp = '\0'; /* turn it into a revision */
3052 assert (rcs != NULL);
3054 if (rcs->flags & PARTIAL)
3055 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3057 p = findnode (rcs->versions, xrev);
3061 vers = (RCSVers *) p->data;
3063 /* Tentatively use this revision, if it is early enough. */
3064 if (RCS_datecmp (vers->date, date) <= 0)
3065 cur_rev = vers->version;
3067 /* If no branches list, return now. This is what happens if the branch
3068 is a (magic) branch with no revisions yet. */
3069 if (vers->branches == NULL)
3070 return xstrdup (cur_rev);
3072 /* walk the branches list looking for the branch number */
3073 xbranch = xmalloc (strlen (branch) + 1 + 1); /* +1 for the extra dot */
3074 (void) strcpy (xbranch, branch);
3075 (void) strcat (xbranch, ".");
3076 for (p = vers->branches->list->next; p != vers->branches->list; p = p->next)
3077 if (strncmp (p->key, xbranch, strlen (xbranch)) == 0)
3080 if (p == vers->branches->list)
3082 /* This is what happens if the branch is a (magic) branch with
3083 no revisions yet. Similar to the case where vers->branches ==
3084 NULL, except here there was a another branch off the same
3086 return xstrdup (cur_rev);
3089 p = findnode (rcs->versions, p->key);
3091 /* walk the next pointers until you find the end, or the date is too late */
3094 vers = (RCSVers *) p->data;
3095 if (RCS_datecmp (vers->date, date) <= 0)
3096 cur_rev = vers->version;
3100 /* if there is a next version, find the node */
3101 if (vers->next != NULL)
3102 p = findnode (rcs->versions, vers->next);
3107 /* Return whatever we found, which may be NULL. */
3108 return xstrdup (cur_rev);
3112 * Compare two dates in RCS format. Beware the change in format on January 1,
3113 * 2000, when years go from 2-digit to full format.
3116 RCS_datecmp (date1, date2)
3117 char *date1, *date2;
3119 int length_diff = strlen (date1) - strlen (date2);
3121 return (length_diff ? length_diff : strcmp (date1, date2));
3124 /* Look up revision REV in RCS and return the date specified for the
3125 revision minus FUDGE seconds (FUDGE will generally be one, so that the
3126 logically previous revision will be found later, or zero, if we want
3129 The return value is the date being returned as a time_t, or (time_t)-1
3130 on error (previously was documented as zero on error; I haven't checked
3131 the callers to make sure that they really check for (time_t)-1, but
3132 the latter is what this function really returns). If DATE is non-NULL,
3133 then it must point to MAXDATELEN characters, and we store the same
3134 return value there in DATEFORM format. */
3136 RCS_getrevtime (rcs, rev, date, fudge)
3142 char tdate[MAXDATELEN];
3143 struct tm xtm, *ftm;
3148 /* make sure we have something to look at... */
3149 assert (rcs != NULL);
3151 if (rcs->flags & PARTIAL)
3152 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3154 /* look up the revision */
3155 p = findnode (rcs->versions, rev);
3158 vers = (RCSVers *) p->data;
3160 /* split up the date */
3162 (void) sscanf (vers->date, SDATEFORM, &ftm->tm_year, &ftm->tm_mon,
3163 &ftm->tm_mday, &ftm->tm_hour, &ftm->tm_min,
3166 /* If the year is from 1900 to 1999, RCS files contain only two
3167 digits, and sscanf gives us a year from 0-99. If the year is
3168 2000+, RCS files contain all four digits and we subtract 1900,
3169 because the tm_year field should contain years since 1900. */
3171 if (ftm->tm_year > 1900)
3172 ftm->tm_year -= 1900;
3174 /* put the date in a form getdate can grok */
3175 (void) sprintf (tdate, "%d/%d/%d GMT %d:%d:%d", ftm->tm_mon,
3176 ftm->tm_mday, ftm->tm_year + 1900, ftm->tm_hour,
3177 ftm->tm_min, ftm->tm_sec);
3179 /* turn it into seconds since the epoch */
3180 revdate = get_date (tdate, (struct timeb *) NULL);
3181 if (revdate != (time_t) -1)
3183 revdate -= fudge; /* remove "fudge" seconds */
3186 /* put an appropriate string into ``date'' if we were given one */
3187 ftm = gmtime (&revdate);
3188 (void) sprintf (date, DATEFORM,
3189 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
3190 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
3191 ftm->tm_min, ftm->tm_sec);
3201 assert(rcs != NULL);
3203 if (rcs->flags & PARTIAL)
3204 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3206 if (rcs->locks_data) {
3207 rcs->locks = getlist ();
3208 do_locks (rcs->locks, rcs->locks_data);
3209 free(rcs->locks_data);
3210 rcs->locks_data = NULL;
3220 assert(rcs != NULL);
3222 if (rcs->flags & PARTIAL)
3223 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3225 if (rcs->symbols_data) {
3226 rcs->symbols = getlist ();
3227 do_symbols (rcs->symbols, rcs->symbols_data);
3228 free(rcs->symbols_data);
3229 rcs->symbols_data = NULL;
3232 return rcs->symbols;
3236 * Return the version associated with a particular symbolic tag.
3237 * Returns NULL or a newly malloc'd string.
3240 translate_symtag (rcs, tag)
3244 if (rcs->flags & PARTIAL)
3245 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3247 if (rcs->symbols != NULL)
3251 /* The symbols have already been converted into a list. */
3252 p = findnode (rcs->symbols, tag);
3256 return xstrdup (p->data);
3259 if (rcs->symbols_data != NULL)
3264 /* Look through the RCS symbols information. This is like
3265 do_symbols, but we don't add the information to a list. In
3266 most cases, we will only be called once for this file, so
3267 generating the list is unnecessary overhead. */
3270 cp = rcs->symbols_data;
3271 while ((cp = strchr (cp, tag[0])) != NULL)
3273 if ((cp == rcs->symbols_data || whitespace (cp[-1]))
3274 && strncmp (cp, tag, len) == 0
3279 /* We found the tag. Return the version number. */
3283 while (! whitespace (*cp) && *cp != '\0')
3285 r = xmalloc (cp - v + 1);
3286 strncpy (r, v, cp - v);
3291 while (! whitespace (*cp) && *cp != '\0')
3302 * The argument ARG is the getopt remainder of the -k option specified on the
3303 * command line. This function returns malloc'ed space that can be used
3304 * directly in calls to RCS V5, with the -k flag munged correctly.
3307 RCS_check_kflag (arg)
3310 static const char *const keyword_usage[] =
3312 "%s %s: invalid RCS keyword expansion mode\n",
3313 "Valid expansion modes include:\n",
3314 " -kkv\tGenerate keywords using the default form.\n",
3315 " -kkvl\tLike -kkv, except locker's name inserted.\n",
3316 " -kk\tGenerate only keyword names in keyword strings.\n",
3317 " -kv\tGenerate only keyword values in keyword strings.\n",
3318 " -ko\tGenerate the old keyword string (no changes from checked in file).\n",
3319 " -kb\tGenerate binary file unmodified (merges not allowed) (RCS 5.7).\n",
3320 "(Specify the --help global option for a list of other help options)\n",
3323 /* Big enough to hold any of the strings from kflags. */
3325 char const *const *cpp = NULL;
3329 for (cpp = kflags; *cpp != NULL; cpp++)
3331 if (STREQ (arg, *cpp))
3336 if (arg == NULL || *cpp == NULL)
3338 usage (keyword_usage);
3341 (void) sprintf (karg, "-k%s", *cpp);
3342 return (xstrdup (karg));
3346 * Do some consistency checks on the symbolic tag... These should equate
3347 * pretty close to what RCS checks, though I don't know for certain.
3353 char *invalid = "$,.:;@"; /* invalid RCS tag characters */
3357 * The first character must be an alphabetic letter. The remaining
3358 * characters cannot be non-visible graphic characters, and must not be
3359 * in the set of "invalid" RCS identifier characters.
3361 if (isalpha ((unsigned char) *tag))
3363 for (cp = tag; *cp; cp++)
3365 if (!isgraph ((unsigned char) *cp))
3366 error (1, 0, "tag `%s' has non-visible graphic characters",
3368 if (strchr (invalid, *cp))
3369 error (1, 0, "tag `%s' must not contain the characters `%s'",
3374 error (1, 0, "tag `%s' must start with a letter", tag);
3378 * TRUE if argument has valid syntax for an RCS revision or
3379 * branch number. All characters must be digits or dots, first
3380 * and last characters must be digits, and no two consecutive
3381 * characters may be dots.
3383 * Intended for classifying things, so this function doesn't
3392 if (!isdigit ((unsigned char) last))
3394 while ((c = *rev++)) /* Extra parens placate -Wall gcc option */
3403 if (!isdigit ((unsigned char) c))
3406 if (!isdigit ((unsigned char) last))
3412 * Return true if RCS revision with TAG is a dead revision.
3415 RCS_isdead (rcs, tag)
3422 if (rcs->flags & PARTIAL)
3423 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3425 p = findnode (rcs->versions, tag);
3429 version = (RCSVers *) p->data;
3430 return (version->dead);
3433 /* Return the RCS keyword expansion mode. For example "b" for binary.
3434 Returns a pointer into storage which is allocated and freed along with
3435 the rest of the RCS information; the caller should not modify this
3436 storage. Returns NULL if the RCS file does not specify a keyword
3437 expansion mode; for all other errors, die with a fatal error. */
3442 /* Since RCS_parsercsfile_i now reads expand, don't need to worry
3443 about RCS_reparsercsfile. */
3444 assert (rcs != NULL);
3448 /* Set keyword expansion mode to EXPAND. For example "b" for binary. */
3450 RCS_setexpand (rcs, expand)
3454 /* Since RCS_parsercsfile_i now reads expand, don't need to worry
3455 about RCS_reparsercsfile. */
3456 assert (rcs != NULL);
3457 if (rcs->expand != NULL)
3459 rcs->expand = xstrdup (expand);
3462 /* RCS keywords, and a matching enum. */
3468 #define KEYWORD_INIT(s) (s), sizeof (s) - 1
3469 static const struct rcs_keyword keywords[] =
3471 { KEYWORD_INIT ("Author") },
3472 { KEYWORD_INIT ("Date") },
3473 { KEYWORD_INIT ("Header") },
3474 { KEYWORD_INIT ("Id") },
3475 { KEYWORD_INIT ("Locker") },
3476 { KEYWORD_INIT ("Log") },
3477 { KEYWORD_INIT ("Name") },
3478 { KEYWORD_INIT ("RCSfile") },
3479 { KEYWORD_INIT ("Revision") },
3480 { KEYWORD_INIT ("Source") },
3481 { KEYWORD_INIT ("State") },
3499 /* Convert an RCS date string into a readable string. This is like
3500 the RCS date2str function. */
3503 printable_date (rcs_date)
3504 const char *rcs_date;
3506 int year, mon, mday, hour, min, sec;
3509 (void) sscanf (rcs_date, SDATEFORM, &year, &mon, &mday, &hour, &min,
3513 sprintf (buf, "%04d/%02d/%02d %02d:%02d:%02d", year, mon, mday,
3515 return xstrdup (buf);
3518 /* Escape the characters in a string so that it can be included in an
3522 escape_keyword_value (value, free_value)
3529 for (s = value; *s != '\0'; s++)
3547 return (char *) value;
3550 ret = xmalloc (strlen (value) * 4 + 1);
3553 for (s = value, t = ret; *s != '\0'; s++, t++)
3592 /* Expand RCS keywords in the memory buffer BUF of length LEN. This
3593 applies to file RCS and version VERS. If NAME is not NULL, and is
3594 not a numeric revision, then it is the symbolic tag used for the
3595 checkout. EXPAND indicates how to expand the keywords. This
3596 function sets *RETBUF and *RETLEN to the new buffer and length.
3597 This function may modify the buffer BUF. If BUF != *RETBUF, then
3598 RETBUF is a newly allocated buffer. */
3601 expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
3613 struct expand_buffer
3615 struct expand_buffer *next;
3620 struct expand_buffer *ebuf_last = NULL;
3621 size_t ebuf_len = 0;
3623 char *srch, *srch_next;
3626 if (expand == KFLAG_O || expand == KFLAG_B)
3633 /* If we are using -kkvl, dig out the locker information if any. */
3635 if (expand == KFLAG_KVL)
3638 lock = findnode (RCS_getlocks(rcs), ver->version);
3640 locker = xstrdup (lock->data);
3643 /* RCS keywords look like $STRING$ or $STRING: VALUE$. */
3646 while ((srch_next = memchr (srch, '$', srch_len)) != NULL)
3650 const struct rcs_keyword *keyword;
3657 srch_len -= (srch_next + 1) - srch;
3658 srch = srch_next + 1;
3660 /* Look for the first non alphabetic character after the '$'. */
3661 send = srch + srch_len;
3662 for (s = srch; s < send; s++)
3663 if (! isalpha ((unsigned char) *s))
3666 /* If the first non alphabetic character is not '$' or ':',
3667 then this is not an RCS keyword. */
3668 if (s == send || (*s != '$' && *s != ':'))
3671 /* See if this is one of the keywords. */
3673 for (keyword = keywords; keyword->string != NULL; keyword++)
3675 if (keyword->len == slen
3676 && strncmp (keyword->string, srch, slen) == 0)
3681 if (keyword->string == NULL)
3684 kw = (enum keyword) (keyword - keywords);
3686 /* If the keyword ends with a ':', then the old value consists
3687 of the characters up to the next '$'. If there is no '$'
3688 before the end of the line, though, then this wasn't an RCS
3689 keyword after all. */
3692 for (; s < send; s++)
3693 if (*s == '$' || *s == '\n')
3695 if (s == send || *s != '$')
3699 /* At this point we must replace the string from SRCH to S
3700 with the expansion of the keyword KW. */
3702 /* Get the value to use. */
3704 if (expand == KFLAG_K)
3713 case KEYWORD_AUTHOR:
3714 value = ver->author;
3718 value = printable_date (ver->date);
3722 case KEYWORD_HEADER:
3729 if (kw == KEYWORD_HEADER)
3732 path = last_component (rcs->path);
3733 path = escape_keyword_value (path, &free_path);
3734 date = printable_date (ver->date);
3735 value = xmalloc (strlen (path)
3736 + strlen (ver->version)
3738 + strlen (ver->author)
3739 + strlen (ver->state)
3740 + (locker == NULL ? 0 : strlen (locker))
3743 sprintf (value, "%s %s %s %s %s%s%s",
3744 path, ver->version, date, ver->author,
3746 locker != NULL ? " " : "",
3747 locker != NULL ? locker : "");
3755 case KEYWORD_LOCKER:
3760 case KEYWORD_RCSFILE:
3761 value = escape_keyword_value (last_component (rcs->path),
3766 if (name != NULL && ! isdigit ((unsigned char) *name))
3767 value = (char *) name;
3772 case KEYWORD_REVISION:
3773 value = ver->version;
3776 case KEYWORD_SOURCE:
3777 value = escape_keyword_value (rcs->path, &free_value);
3786 sub = xmalloc (keyword->len
3787 + (value == NULL ? 0 : strlen (value))
3789 if (expand == KFLAG_V)
3791 /* Decrement SRCH and increment S to remove the $
3800 strcpy (sub, keyword->string);
3801 sublen = strlen (keyword->string);
3802 if (expand != KFLAG_K)
3805 sub[sublen + 1] = ' ';
3811 strcpy (sub + sublen, value);
3812 sublen += strlen (value);
3814 if (expand != KFLAG_V && expand != KFLAG_K)
3824 /* The Log keyword requires special handling. This behaviour
3825 is taken from RCS 5.7. The special log message is what RCS
3827 if (kw == KEYWORD_LOG
3828 && (sizeof "checked in with -k by " <= loglen
3830 || strncmp (log, "checked in with -k by ",
3831 sizeof "checked in with -k by " - 1) != 0))
3835 size_t leader_len, leader_sp_len;
3842 /* We are going to insert the trailing $ ourselves, before
3843 the log message, so we must remove it from S, if we
3844 haven't done so already. */
3845 if (expand != KFLAG_V)
3848 /* CVS never has empty log messages, but old RCS files might. */
3852 /* Find the start of the line. */
3854 while (start > buf && start[-1] != '\n')
3857 /* Copy the start of the line to use as a comment leader. */
3858 leader_len = srch - start;
3859 if (expand != KFLAG_V)
3861 leader = xmalloc (leader_len);
3862 memcpy (leader, start, leader_len);
3863 leader_sp_len = leader_len;
3864 while (leader_sp_len > 0 && leader[leader_sp_len - 1] == ' ')
3867 /* RCS does some checking for an old style of Log here,
3868 but we don't bother. RCS issues a warning if it
3869 changes anything. */
3871 /* Count the number of newlines in the log message so that
3872 we know how many copies of the leader we will need. */
3874 logend = log + loglen;
3875 for (snl = log; snl < logend; snl++)
3879 date = printable_date (ver->date);
3880 sub = xrealloc (sub,
3883 + strlen (ver->version)
3885 + strlen (ver->author)
3887 + (cnl + 2) * leader_len
3889 if (expand != KFLAG_V)
3896 memcpy (sub + sublen, leader, leader_len);
3897 sublen += leader_len;
3898 sprintf (sub + sublen, "Revision %s %s %s\n",
3899 ver->version, date, ver->author);
3900 sublen += strlen (sub + sublen);
3908 memcpy (sub + sublen, leader, leader_sp_len);
3909 sublen += leader_sp_len;
3918 memcpy (sub + sublen, leader, leader_len);
3919 sublen += leader_len;
3920 for (slnl = sl; slnl < logend && *slnl != '\n'; ++slnl)
3924 memcpy (sub + sublen, sl, slnl - sl);
3925 sublen += slnl - sl;
3930 memcpy (sub + sublen, leader, leader_sp_len);
3931 sublen += leader_sp_len;
3936 /* Now SUB contains a string which is to replace the string
3937 from SRCH to S. SUBLEN is the length of SUB. */
3939 if (srch + sublen == s)
3941 memcpy (srch, sub, sublen);
3946 struct expand_buffer *ebuf;
3948 /* We need to change the size of the buffer. We build a
3949 list of expand_buffer structures. Each expand_buffer
3950 structure represents a portion of the final output. We
3951 concatenate them back into a single buffer when we are
3952 done. This minimizes the number of potentially large
3953 buffer copies we must do. */
3957 ebufs = (struct expand_buffer *) xmalloc (sizeof *ebuf);
3960 ebufs->free_data = 0;
3961 ebuf_len = srch - buf;
3962 ebufs->len = ebuf_len;
3967 assert (srch >= ebuf_last->data);
3968 assert (srch <= ebuf_last->data + ebuf_last->len);
3969 ebuf_len -= ebuf_last->len - (srch - ebuf_last->data);
3970 ebuf_last->len = srch - ebuf_last->data;
3973 ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf);
3976 ebuf->free_data = 1;
3978 ebuf_last->next = ebuf;
3982 ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf);
3984 ebuf->len = srch_len - (s - srch);
3985 ebuf->free_data = 0;
3987 ebuf_last->next = ebuf;
3989 ebuf_len += srch_len - (s - srch);
3992 srch_len -= (s - srch);
4008 ret = xmalloc (ebuf_len);
4011 while (ebufs != NULL)
4013 struct expand_buffer *next;
4015 memcpy (ret, ebufs->data, ebufs->len);
4017 if (ebufs->free_data)
4026 /* Check out a revision from an RCS file.
4028 If PFN is not NULL, then ignore WORKFILE and SOUT. Call PFN zero
4029 or more times with the contents of the file. CALLERDAT is passed,
4030 uninterpreted, to PFN. (The current code will always call PFN
4031 exactly once for a non empty file; however, the current code
4032 assumes that it can hold the entire file contents in memory, which
4033 is not a good assumption, and might change in the future).
4035 Otherwise, if WORKFILE is not NULL, check out the revision to
4036 WORKFILE. However, if WORKFILE is not NULL, and noexec is set,
4037 then don't do anything.
4039 Otherwise, if WORKFILE is NULL, check out the revision to SOUT. If
4040 SOUT is RUN_TTY, then write the contents of the revision to
4041 standard output. When using SOUT, the output is generally a
4042 temporary file; don't bother to get the file modes correct.
4044 REV is the numeric revision to check out. It may be NULL, which
4045 means to check out the head of the default branch.
4047 If NAMETAG is not NULL, and is not a numeric revision, then it is
4048 the tag that should be used when expanding the RCS Name keyword.
4050 OPTIONS is a string such as "-kb" or "-kv" for keyword expansion
4051 options. It may be NULL to use the default expansion mode of the
4052 file, typically "-kkv".
4054 On an error which prevented checking out the file, either print a
4055 nonfatal error and return 1, or give a fatal error. On success,
4058 /* This function mimics the behavior of `rcs co' almost exactly. The
4059 chief difference is in its support for preserving file ownership,
4060 permissions, and special files across checkin and checkout -- see
4061 comments in RCS_checkin for some issues about this. -twp */
4064 RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
4071 RCSCHECKOUTPROC pfn;
4078 struct rcsbuffer rcsbuf;
4086 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4087 uid_t rcs_owner = (uid_t) -1;
4088 gid_t rcs_group = (gid_t) -1;
4090 int change_rcs_owner_or_group = 0;
4091 int change_rcs_mode = 0;
4092 int special_file = 0;
4093 unsigned long devnum_long;
4099 (void) fprintf (stderr, "%s-> checkout (%s, %s, %s, %s)\n",
4100 #ifdef SERVER_SUPPORT
4101 server_active ? "S" : " ",
4106 rev != NULL ? rev : "",
4107 options != NULL ? options : "",
4108 (pfn != NULL ? "(function)"
4111 : (sout != RUN_TTY ? sout : "(stdout)"))));
4114 assert (rev == NULL || isdigit ((unsigned char) *rev));
4116 if (noexec && workfile != NULL)
4119 assert (sout == RUN_TTY || workfile == NULL);
4120 assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL));
4122 /* Some callers, such as Checkin or remove_file, will pass us a
4124 if (rev != NULL && (numdots (rev) & 1) == 0)
4126 rev = RCS_getbranch (rcs, rev, 1);
4128 error (1, 0, "internal error: bad branch tag in checkout");
4132 if (rev == NULL || STREQ (rev, rcs->head))
4136 /* We want the head revision. Try to read it directly. */
4138 if (rcs->flags & PARTIAL)
4139 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
4141 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf);
4144 if (! rcsbuf_getrevnum (&rcsbuf, &key))
4145 error (1, 0, "unexpected EOF reading %s", rcs->path);
4146 while (rcsbuf_getkey (&rcsbuf, &key, &value))
4148 if (STREQ (key, "log"))
4149 log = rcsbuf_valcopy (&rcsbuf, value, 0, &loglen);
4150 else if (STREQ (key, "text"))
4159 error (0, 0, "internal error: cannot find head text");
4165 rcsbuf_valpolish (&rcsbuf, value, 0, &len);
4167 if (fstat (fileno (fp), &sb) < 0)
4168 error (1, errno, "cannot fstat %s", rcs->path);
4170 rcsbuf_cache (rcs, &rcsbuf);
4174 struct rcsbuffer *rcsbufp;
4176 /* It isn't the head revision of the trunk. We'll need to
4177 walk through the deltas. */
4180 if (rcs->flags & PARTIAL)
4181 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
4185 /* If RCS_deltas didn't close the file, we could use fstat
4186 here too. Probably should change it thusly.... */
4187 if (stat (rcs->path, &sb) < 0)
4188 error (1, errno, "cannot stat %s", rcs->path);
4193 if (fstat (fileno (fp), &sb) < 0)
4194 error (1, errno, "cannot fstat %s", rcs->path);
4198 RCS_deltas (rcs, fp, rcsbufp, rev, RCS_FETCH, &value, &len,
4203 /* If OPTIONS is NULL or the empty string, then the old code would
4204 invoke the RCS co program with no -k option, which means that
4205 co would use the string we have stored in rcs->expand. */
4206 if ((options == NULL || options[0] == '\0') && rcs->expand == NULL)
4210 const char *ouroptions;
4211 const char * const *cpp;
4213 if (options != NULL && options[0] != '\0')
4215 assert (options[0] == '-' && options[1] == 'k');
4216 ouroptions = options + 2;
4219 ouroptions = rcs->expand;
4221 for (cpp = kflags; *cpp != NULL; cpp++)
4222 if (STREQ (*cpp, ouroptions))
4226 expand = (enum kflag) (cpp - kflags);
4230 "internal error: unsupported substitution string -k%s",
4236 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4237 /* Handle special files and permissions, if that is desired. */
4243 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
4245 error (1, 0, "internal error: no revision information for %s",
4246 rev == NULL ? rcs->head : rev);
4247 vers = (RCSVers *) vp->data;
4249 /* First we look for symlinks, which are simplest to handle. */
4250 info = findnode (vers->other_delta, "symlink");
4255 if (pfn != NULL || (workfile == NULL && sout == RUN_TTY))
4256 error (1, 0, "symbolic link %s:%s cannot be piped",
4257 rcs->path, vers->version);
4258 if (workfile == NULL)
4263 /* Remove `dest', just in case. It's okay to get ENOENT here,
4264 since we just want the file not to be there. (TODO: decide
4265 whether it should be considered an error for `dest' to exist
4266 at this point. If so, the unlink call should be removed and
4267 `symlink' should signal the error. -twp) */
4268 if (CVS_UNLINK (dest) < 0 && !existence_error (errno))
4269 error (1, errno, "cannot remove %s", dest);
4270 if (symlink (info->data, dest) < 0)
4271 error (1, errno, "cannot create symbolic link from %s to %s",
4280 /* Next, we look at this file's hardlinks field, and see whether
4281 it is linked to any other file that has been checked out.
4282 If so, we don't do anything else -- just link it to that file.
4284 If we are checking out a file to a pipe or temporary storage,
4285 none of this should matter. Hence the `workfile != NULL'
4286 wrapper around the whole thing. -twp */
4288 if (workfile != NULL)
4290 List *links = vers->hardlinks;
4293 Node *uptodate_link;
4295 /* For each file in the hardlinks field, check to see
4296 if it exists, and if so, if it has been checked out
4297 this iteration. When walklist returns, uptodate_link
4298 should point to a hardlist node representing a file
4299 in `links' which has recently been checked out, or
4300 NULL if no file in `links' has yet been checked out. */
4302 uptodate_link = NULL;
4303 (void) walklist (links, find_checkedout_proc, &uptodate_link);
4306 /* If we've found a file that `workfile' is supposed to be
4307 linked to, and it has been checked out since CVS was
4308 invoked, then simply link workfile to that file and return.
4310 If one of these conditions is not met, then
4311 workfile is the first one in its hardlink group to
4312 be checked out, and we must continue with a full
4315 if (uptodate_link != NULL)
4317 struct hardlink_info *hlinfo =
4318 (struct hardlink_info *) uptodate_link->data;
4320 if (link (uptodate_link->key, workfile) < 0)
4321 error (1, errno, "cannot link %s to %s",
4322 workfile, uptodate_link->key);
4323 hlinfo->checked_out = 1; /* probably unnecessary */
4333 info = findnode (vers->other_delta, "owner");
4336 change_rcs_owner_or_group = 1;
4337 rcs_owner = (uid_t) strtoul (info->data, NULL, 10);
4339 info = findnode (vers->other_delta, "group");
4342 change_rcs_owner_or_group = 1;
4343 rcs_group = (gid_t) strtoul (info->data, NULL, 10);
4345 info = findnode (vers->other_delta, "permissions");
4348 change_rcs_mode = 1;
4349 rcs_mode = (mode_t) strtoul (info->data, NULL, 8);
4351 info = findnode (vers->other_delta, "special");
4354 /* If the size of `devtype' changes, fix the sscanf call also */
4357 if (sscanf (info->data, "%15s %lu",
4358 devtype, &devnum_long) < 2)
4359 error (1, 0, "%s:%s has bad `special' newphrase %s",
4360 workfile, vers->version, info->data);
4361 devnum = devnum_long;
4362 if (STREQ (devtype, "character"))
4363 special_file = S_IFCHR;
4364 else if (STREQ (devtype, "block"))
4365 special_file = S_IFBLK;
4367 error (0, 0, "%s is a special file of unsupported type `%s'",
4368 workfile, info->data);
4373 if (expand != KFLAG_O && expand != KFLAG_B)
4377 /* Don't fetch the delta node again if we already have it. */
4380 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
4382 error (1, 0, "internal error: no revision information for %s",
4383 rev == NULL ? rcs->head : rev);
4386 expand_keywords (rcs, (RCSVers *) vp->data, nametag, log, loglen,
4387 expand, value, len, &newvalue, &len);
4389 if (newvalue != value)
4409 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4411 error (1, 0, "special file %s cannot be piped to anything",
4414 /* The PFN interface is very simple to implement right now, as
4415 we always have the entire file in memory. */
4417 pfn (callerdat, value, len);
4419 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4420 else if (special_file)
4425 /* Can send either to WORKFILE or to SOUT, as long as SOUT is
4430 if (sout == RUN_TTY)
4431 error (1, 0, "special file %s cannot be written to stdout",
4436 /* Unlink `dest', just in case. It's okay if this provokes a
4438 if (CVS_UNLINK (dest) < 0 && existence_error (errno))
4439 error (1, errno, "cannot remove %s", dest);
4440 if (mknod (dest, special_file, devnum) < 0)
4441 error (1, errno, "could not create special file %s",
4445 "cannot create %s: unable to create special files on this system",
4452 /* Not a special file: write to WORKFILE or SOUT. */
4453 if (workfile == NULL)
4455 if (sout == RUN_TTY)
4459 /* Symbolic links should be removed before replacement, so that
4460 `fopen' doesn't follow the link and open the wrong file. */
4462 if (unlink_file (sout) < 0)
4463 error (1, errno, "cannot remove %s", sout);
4464 ofp = CVS_FOPEN (sout, expand == KFLAG_B ? "wb" : "w");
4466 error (1, errno, "cannot open %s", sout);
4471 /* Output is supposed to go to WORKFILE, so we should open that
4472 file. Symbolic links should be removed first (see above). */
4473 if (islink (workfile))
4474 if (unlink_file (workfile) < 0)
4475 error (1, errno, "cannot remove %s", workfile);
4477 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
4479 /* If the open failed because the existing workfile was not
4480 writable, try to chmod the file and retry the open. */
4481 if (ofp == NULL && errno == EACCES
4482 && isfile (workfile) && !iswritable (workfile))
4484 xchmod (workfile, 1);
4485 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
4490 error (0, errno, "cannot open %s", workfile);
4497 if (workfile == NULL && sout == RUN_TTY)
4499 if (expand == KFLAG_B)
4500 cvs_output_binary (value, len);
4503 /* cvs_output requires the caller to check for zero
4506 cvs_output (value, len);
4511 /* NT 4.0 is said to have trouble writing 2099999 bytes
4512 (for example) in a single fwrite. So break it down
4513 (there is no need to be writing that much at once
4514 anyway; it is possible that LARGEST_FWRITE should be
4515 somewhat larger for good performance, but for testing I
4516 want to start with a small value until/unless a bigger
4517 one proves useful). */
4518 #define LARGEST_FWRITE 8192
4520 size_t nstep = (len < LARGEST_FWRITE ? len : LARGEST_FWRITE);
4525 if (fwrite (p, 1, nstep, ofp) != nstep)
4527 error (0, errno, "cannot write %s",
4530 : (sout != RUN_TTY ? sout : "stdout")));
4546 if (workfile != NULL)
4550 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4551 if (!special_file && fclose (ofp) < 0)
4553 error (0, errno, "cannot close %s", workfile);
4557 if (change_rcs_owner_or_group)
4559 if (chown (workfile, rcs_owner, rcs_group) < 0)
4560 error (0, errno, "could not change owner or group of %s",
4564 ret = chmod (workfile,
4567 : sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
4569 if (fclose (ofp) < 0)
4571 error (0, errno, "cannot close %s", workfile);
4575 ret = chmod (workfile,
4576 sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
4580 error (0, errno, "cannot change mode of file %s",
4584 else if (sout != RUN_TTY)
4587 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4592 error (0, errno, "cannot close %s", sout);
4597 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4598 /* If we are in the business of preserving hardlinks, then
4599 mark this file as having been checked out. */
4600 if (preserve_perms && workfile != NULL)
4601 update_hardlink_info (workfile);
4607 static RCSVers *RCS_findlock_or_tip PROTO ((RCSNode *rcs));
4609 /* Find the delta currently locked by the user. From the `ci' man page:
4611 "If rev is omitted, ci tries to derive the new revision
4612 number from the caller's last lock. If the caller has
4613 locked the tip revision of a branch, the new revision is
4614 appended to that branch. The new revision number is
4615 obtained by incrementing the tip revision number. If the
4616 caller locked a non-tip revision, a new branch is started
4617 at that revision by incrementing the highest branch number
4618 at that revision. The default initial branch and level
4621 If rev is omitted and the caller has no lock, but owns the
4622 file and locking is not set to strict, then the revision
4623 is appended to the default branch (normally the trunk; see
4624 the -b option of rcs(1))."
4626 RCS_findlock_or_tip finds the unique revision locked by the caller
4627 and returns its delta node. If the caller has not locked any
4628 revisions (and is permitted to commit to an unlocked delta, as
4629 described above), return the tip of the default branch. */
4632 RCS_findlock_or_tip (rcs)
4635 char *user = getcaller();
4639 /* Find unique delta locked by caller. This code is very similar
4640 to the code in RCS_unlock -- perhaps it could be abstracted
4641 into a RCS_findlock function. */
4642 locklist = RCS_getlocks (rcs);
4644 for (p = locklist->list->next; p != locklist->list; p = p->next)
4646 if (STREQ (p->data, user))
4651 %s: multiple revisions locked by %s; please specify one", rcs->path, user);
4660 /* Found an old lock, but check that the revision still exists. */
4661 p = findnode (rcs->versions, lock->key);
4664 error (0, 0, "%s: can't unlock nonexistent revision %s",
4669 return (RCSVers *) p->data;
4672 /* No existing lock. The RCS rule is that this is an error unless
4673 locking is nonstrict AND the file is owned by the current
4674 user. Trying to determine the latter is a portability nightmare
4675 in the face of NT, VMS, AFS, and other systems with non-unix-like
4676 ideas of users and owners. In the case of CVS, we should never get
4677 here (as long as the traditional behavior of making sure to call
4678 RCS_lock persists). Anyway, we skip the RCS error checks
4679 and just return the default branch or head. The reasoning is that
4680 those error checks are to make users lock before a checkin, and we do
4681 that in other ways if at all anyway (e.g. rcslock.pl). */
4683 p = findnode (rcs->versions, RCS_getbranch (rcs, rcs->branch, 0));
4684 return (RCSVers *) p->data;
4687 /* Revision number string, R, must contain a `.'.
4688 Return a newly-malloc'd copy of the prefix of R up
4689 to but not including the final `.'. */
4697 char *dot = strrchr (r, '.');
4701 new_r = xmalloc (len + 1);
4702 memcpy (new_r, r, len);
4703 *(new_r + len) = '\0';
4707 /* Revision number string, R, must contain a `.'.
4708 R must be writable. Replace the rightmost `.' in R with
4709 the NUL byte and return a pointer to that NUL byte. */
4712 truncate_revnum_in_place (r)
4715 char *dot = strrchr (r, '.');
4721 /* Revision number strings, R and S, must each contain a `.'.
4722 R and S must be writable and must have the same number of dots.
4723 Truncate R and S for the comparison, then restored them to their
4725 Return the result (see compare_revnums) of comparing R and S
4726 ignoring differences in any component after the rightmost `.'. */
4729 compare_truncated_revnums (r, s)
4733 char *r_dot = truncate_revnum_in_place (r);
4734 char *s_dot = truncate_revnum_in_place (s);
4737 assert (numdots (r) == numdots (s));
4739 cmp = compare_revnums (r, s);
4747 /* Return a malloc'd copy of the string representing the highest branch
4748 number on BRANCHNODE. If there are no branches on BRANCHNODE, return NULL.
4749 FIXME: isn't the max rev always the last one?
4750 If so, we don't even need a loop. */
4752 static char *max_rev PROTO ((const RCSVers *));
4755 max_rev (branchnode)
4756 const RCSVers *branchnode;
4762 if (branchnode->branches == NULL)
4768 head = branchnode->branches->list;
4769 for (bp = head->next; bp != head; bp = bp->next)
4771 if (max == NULL || compare_truncated_revnums (max, bp->key) < 0)
4778 return truncate_revnum (max);
4781 /* Create BRANCH in RCS's delta tree. BRANCH may be either a branch
4782 number or a revision number. In the former case, create the branch
4783 with the specified number; in the latter case, create a new branch
4784 rooted at node BRANCH with a higher branch number than any others.
4785 Return the number of the tip node on the new branch. */
4788 RCS_addbranch (rcs, branch)
4792 char *branchpoint, *newrevnum;
4795 RCSVers *branchnode;
4797 /* Append to end by default. */
4800 branchpoint = xstrdup (branch);
4801 if ((numdots (branchpoint) & 1) == 0)
4803 truncate_revnum_in_place (branchpoint);
4806 /* Find the branch rooted at BRANCHPOINT. */
4807 nodep = findnode (rcs->versions, branchpoint);
4810 error (0, 0, "%s: can't find branch point %s", rcs->path, branchpoint);
4815 branchnode = (RCSVers *) nodep->data;
4817 /* If BRANCH was a full branch number, make sure it is higher than MAX. */
4818 if ((numdots (branch) & 1) == 1)
4820 if (branchnode->branches == NULL)
4822 /* We have to create the first branch on this node, which means
4823 appending ".2" to the revision number. */
4824 newrevnum = (char *) xmalloc (strlen (branch) + 3);
4825 strcpy (newrevnum, branch);
4826 strcat (newrevnum, ".2");
4830 char *max = max_rev (branchnode);
4832 newrevnum = increment_revnum (max);
4838 newrevnum = xstrdup (branch);
4840 if (branchnode->branches != NULL)
4845 /* Find the position of this new branch in the sorted list
4847 head = branchnode->branches->list;
4848 for (bp = head->next; bp != head; bp = bp->next)
4853 /* The existing list must be sorted on increasing revnum. */
4854 assert (bp->next == head
4855 || compare_truncated_revnums (bp->key,
4856 bp->next->key) < 0);
4857 dot = truncate_revnum_in_place (bp->key);
4858 found_pos = (compare_revnums (branch, bp->key) < 0);
4870 newrevnum = (char *) xrealloc (newrevnum, strlen (newrevnum) + 3);
4871 strcat (newrevnum, ".1");
4873 /* Add this new revision number to BRANCHPOINT's branches list. */
4874 if (branchnode->branches == NULL)
4875 branchnode->branches = getlist();
4877 bp->key = xstrdup (newrevnum);
4879 /* Append to the end of the list by default, that is, just before
4880 the header node, `list'. */
4882 marker = branchnode->branches->list;
4886 fail = insert_before (branchnode->branches, marker, bp);
4893 /* Check in to RCSFILE with revision REV (which must be greater than
4894 the largest revision) and message MESSAGE (which is checked for
4895 legality). If FLAGS & RCS_FLAGS_DEAD, check in a dead revision.
4896 If FLAGS & RCS_FLAGS_QUIET, tell ci to be quiet. If FLAGS &
4897 RCS_FLAGS_MODTIME, use the working file's modification time for the
4898 checkin time. WORKFILE is the working file to check in from, or
4899 NULL to use the usual RCS rules for deriving it from the RCSFILE.
4900 If FLAGS & RCS_FLAGS_KEEPFILE, don't unlink the working file;
4901 unlinking the working file is standard RCS behavior, but is rarely
4902 appropriate for CVS.
4904 This function should almost exactly mimic the behavior of `rcs ci'. The
4905 principal point of difference is the support here for preserving file
4906 ownership and permissions in the delta nodes. This is not a clean
4907 solution -- precisely because it diverges from RCS's behavior -- but
4908 it doesn't seem feasible to do this anywhere else in the code. [-twp]
4910 Return value is -1 for error (and errno is set to indicate the
4911 error), positive for error (and an error message has been printed),
4912 or zero for success. */
4915 RCS_checkin (rcs, workfile, message, rev, flags)
4922 RCSVers *delta, *commitpt;
4925 char *tmpfile, *changefile, *chtext;
4928 int buflen, chtextlen;
4929 int status, checkin_quiet, allocated_workfile;
4932 int adding_branch = 0;
4933 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4939 if (rcs->flags & PARTIAL)
4940 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
4942 /* Get basename of working file. Is there a library function to
4943 do this? I couldn't find one. -twp */
4944 allocated_workfile = 0;
4945 if (workfile == NULL)
4948 int extlen = strlen (RCSEXT);
4949 workfile = xstrdup (last_component (rcs->path));
4950 p = workfile + (strlen (workfile) - extlen);
4951 assert (strncmp (p, RCSEXT, extlen) == 0);
4953 allocated_workfile = 1;
4956 /* If the filename is a symbolic link, follow it and replace it
4957 with the destination of the link. We need to do this before
4958 calling rcs_internal_lockfile, or else we won't put the lock in
4960 resolve_symlink (&(rcs->path));
4962 checkin_quiet = flags & RCS_FLAGS_QUIET;
4965 cvs_output (rcs->path, 0);
4966 cvs_output (" <-- ", 7);
4967 cvs_output (workfile, 0);
4968 cvs_output ("\n", 1);
4971 /* Create new delta node. */
4972 delta = (RCSVers *) xmalloc (sizeof (RCSVers));
4973 memset (delta, 0, sizeof (RCSVers));
4974 delta->author = xstrdup (getcaller ());
4975 if (flags & RCS_FLAGS_MODTIME)
4978 if (stat (workfile, &ws) < 0)
4980 error (1, errno, "cannot stat %s", workfile);
4982 modtime = ws.st_mtime;
4985 (void) time (&modtime);
4986 ftm = gmtime (&modtime);
4987 delta->date = (char *) xmalloc (MAXDATELEN);
4988 (void) sprintf (delta->date, DATEFORM,
4989 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
4990 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
4991 ftm->tm_min, ftm->tm_sec);
4992 if (flags & RCS_FLAGS_DEAD)
4994 delta->state = xstrdup (RCSDEAD);
4998 delta->state = xstrdup ("Exp");
5000 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5001 /* If permissions should be preserved on this project, then
5002 save the permission info. */
5006 char buf[64]; /* static buffer should be safe: see usage. -twp */
5008 delta->other_delta = getlist();
5010 if (CVS_LSTAT (workfile, &sb) < 0)
5011 error (1, errno, "cannot lstat %s", workfile);
5013 if (S_ISLNK (sb.st_mode))
5016 np->type = RCSFIELD;
5017 np->key = xstrdup ("symlink");
5018 np->data = xreadlink (workfile);
5019 addnode (delta->other_delta, np);
5023 (void) sprintf (buf, "%u", sb.st_uid);
5025 np->type = RCSFIELD;
5026 np->key = xstrdup ("owner");
5027 np->data = xstrdup (buf);
5028 addnode (delta->other_delta, np);
5030 (void) sprintf (buf, "%u", sb.st_gid);
5032 np->type = RCSFIELD;
5033 np->key = xstrdup ("group");
5034 np->data = xstrdup (buf);
5035 addnode (delta->other_delta, np);
5037 (void) sprintf (buf, "%o", sb.st_mode & 07777);
5039 np->type = RCSFIELD;
5040 np->key = xstrdup ("permissions");
5041 np->data = xstrdup (buf);
5042 addnode (delta->other_delta, np);
5044 /* Save device number. */
5045 switch (sb.st_mode & S_IFMT)
5047 case S_IFREG: break;
5050 # ifdef HAVE_STRUCT_STAT_ST_RDEV
5052 np->type = RCSFIELD;
5053 np->key = xstrdup ("special");
5054 sprintf (buf, "%s %lu",
5055 ((sb.st_mode & S_IFMT) == S_IFCHR
5056 ? "character" : "block"),
5057 (unsigned long) sb.st_rdev);
5058 np->data = xstrdup (buf);
5059 addnode (delta->other_delta, np);
5062 "can't preserve %s: unable to save device files on this system",
5068 error (0, 0, "special file %s has unknown type", workfile);
5071 /* Save hardlinks. */
5072 delta->hardlinks = list_linked_files_on_disk (workfile);
5077 /* Create a new deltatext node. */
5078 dtext = (Deltatext *) xmalloc (sizeof (Deltatext));
5079 memset (dtext, 0, sizeof (Deltatext));
5081 dtext->log = make_message_rcslegal (message);
5083 /* If the delta tree is empty, then there's nothing to link the
5084 new delta into. So make a new delta tree, snarf the working
5085 file contents, and just write the new RCS file. */
5086 if (rcs->head == NULL)
5091 /* Figure out what the first revision number should be. */
5092 if (rev == NULL || *rev == '\0')
5093 newrev = xstrdup ("1.1");
5094 else if (numdots (rev) == 0)
5096 newrev = (char *) xmalloc (strlen (rev) + 3);
5097 strcpy (newrev, rev);
5098 strcat (newrev, ".1");
5101 newrev = xstrdup (rev);
5103 /* Don't need to xstrdup NEWREV because it's already dynamic, and
5104 not used for anything else. (Don't need to free it, either.) */
5106 delta->version = xstrdup (newrev);
5108 nodep->type = RCSVERS;
5109 nodep->delproc = rcsvers_delproc;
5110 nodep->data = (char *) delta;
5111 nodep->key = delta->version;
5112 (void) addnode (rcs->versions, nodep);
5114 dtext->version = xstrdup (newrev);
5116 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5117 if (preserve_perms && !S_ISREG (sb.st_mode))
5118 /* Pretend file is empty. */
5122 get_file (workfile, workfile,
5123 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5124 &dtext->text, &bufsize, &dtext->len);
5128 cvs_output ("initial revision: ", 0);
5129 cvs_output (rcs->head, 0);
5130 cvs_output ("\n", 1);
5133 /* We are probably about to invalidate any cached file. */
5134 rcsbuf_cache_close ();
5136 fout = rcs_internal_lockfile (rcs->path);
5137 RCS_putadmin (rcs, fout);
5138 RCS_putdtree (rcs, rcs->head, fout);
5139 RCS_putdesc (rcs, fout);
5140 rcs->delta_pos = ftell (fout);
5141 if (rcs->delta_pos == -1)
5142 error (1, errno, "cannot ftell for %s", rcs->path);
5143 putdeltatext (fout, dtext);
5144 rcs_internal_unlockfile (fout, rcs->path);
5146 if ((flags & RCS_FLAGS_KEEPFILE) == 0)
5148 if (unlink_file (workfile) < 0)
5149 /* FIXME-update-dir: message does not include update_dir. */
5150 error (0, errno, "cannot remove %s", workfile);
5154 cvs_output ("done\n", 5);
5160 /* Derive a new revision number. From the `ci' man page:
5162 "If rev is a revision number, it must be higher than the
5163 latest one on the branch to which rev belongs, or must
5166 If rev is a branch rather than a revision number, the new
5167 revision is appended to that branch. The level number is
5168 obtained by incrementing the tip revision number of that
5169 branch. If rev indicates a non-existing branch, that
5170 branch is created with the initial revision numbered
5173 RCS_findlock_or_tip handles the case where REV is omitted.
5174 RCS 5.7 also permits REV to be "$" or to begin with a dot, but
5175 we do not address those cases -- every routine that calls
5176 RCS_checkin passes it a numeric revision. */
5178 if (rev == NULL || *rev == '\0')
5180 /* Figure out where the commit point is by looking for locks.
5181 If the commit point is at the tip of a branch (or is the
5182 head of the delta tree), then increment its revision number
5183 to obtain the new revnum. Otherwise, start a new
5185 commitpt = RCS_findlock_or_tip (rcs);
5186 if (commitpt == NULL)
5191 else if (commitpt->next == NULL
5192 || STREQ (commitpt->version, rcs->head))
5193 delta->version = increment_revnum (commitpt->version);
5195 delta->version = RCS_addbranch (rcs, commitpt->version);
5199 /* REV is either a revision number or a branch number. Find the
5200 tip of the target branch. */
5201 char *branch, *tip, *newrev, *p;
5204 assert (isdigit ((unsigned char) *rev));
5206 newrev = xstrdup (rev);
5207 dots = numdots (newrev);
5208 isrevnum = dots & 1;
5210 branch = xstrdup (rev);
5213 p = strrchr (branch, '.');
5217 /* Find the tip of the target branch. If we got a one- or two-digit
5218 revision number, this will be the head of the tree. Exception:
5219 if rev is a single-field revision equal to the branch number of
5220 the trunk (usually "1") then we want to treat it like an ordinary
5224 tip = xstrdup (rcs->head);
5225 if (atoi (tip) != atoi (branch))
5227 newrev = (char *) xrealloc (newrev, strlen (newrev) + 3);
5228 strcat (newrev, ".1");
5229 dots = isrevnum = 1;
5233 tip = xstrdup (rcs->head);
5235 tip = RCS_getbranch (rcs, branch, 1);
5237 /* If the branch does not exist, and we were supplied an exact
5238 revision number, signal an error. Otherwise, if we were
5239 given only a branch number, create it and set COMMITPT to
5240 the branch point. */
5245 error (0, 0, "%s: can't find branch point %s",
5252 delta->version = RCS_addbranch (rcs, branch);
5253 if (!delta->version)
5261 p = strrchr (branch, '.');
5263 tip = xstrdup (branch);
5269 /* NEWREV must be higher than TIP. */
5270 if (compare_revnums (tip, newrev) >= 0)
5273 "%s: revision %s too low; must be higher than %s",
5282 delta->version = xstrdup (newrev);
5285 /* Just increment the tip number to get the new revision. */
5286 delta->version = increment_revnum (tip);
5289 nodep = findnode (rcs->versions, tip);
5290 commitpt = (RCSVers *) nodep->data;
5297 assert (delta->version != NULL);
5299 /* If COMMITPT is locked by us, break the lock. If it's locked
5300 by someone else, signal an error. */
5301 nodep = findnode (RCS_getlocks (rcs), commitpt->version);
5304 if (! STREQ (nodep->data, delta->author))
5306 /* If we are adding a branch, then leave the old lock around.
5307 That is sensible in the sense that when adding a branch,
5308 we don't need to use the lock to tell us where to check
5309 in. It is fishy in the sense that if it is our own lock,
5310 we break it. However, this is the RCS 5.7 behavior (at
5311 the end of addbranch in ci.c in RCS 5.7, it calls
5312 removelock only if it is our own lock, not someone
5317 error (0, 0, "%s: revision %s locked by %s",
5319 nodep->key, nodep->data);
5328 dtext->version = xstrdup (delta->version);
5330 /* Obtain the change text for the new delta. If DELTA is to be the
5331 new head of the tree, then its change text should be the contents
5332 of the working file, and LEAFNODE's change text should be a diff.
5333 Else, DELTA's change text should be a diff between LEAFNODE and
5334 the working file. */
5336 tmpfile = cvs_temp_name();
5337 status = RCS_checkout (rcs, NULL, commitpt->version, NULL,
5338 ((rcs->expand != NULL
5339 && STREQ (rcs->expand, "b"))
5343 (RCSCHECKOUTPROC)0, NULL);
5346 "could not check out revision %s of `%s'",
5347 commitpt->version, rcs->path);
5349 bufsize = buflen = 0;
5352 changefile = cvs_temp_name();
5354 /* Diff options should include --binary if the RCS file has -kb set
5355 in its `expand' field. */
5356 diffopts = (rcs->expand != NULL && STREQ (rcs->expand, "b")
5360 if (STREQ (commitpt->version, rcs->head) &&
5361 numdots (delta->version) == 1)
5363 /* If this revision is being inserted on the trunk, the change text
5364 for the new delta should be the contents of the working file ... */
5366 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5367 if (preserve_perms && !S_ISREG (sb.st_mode))
5368 /* Pretend file is empty. */
5372 get_file (workfile, workfile,
5373 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5374 &dtext->text, &bufsize, &dtext->len);
5376 /* ... and the change text for the old delta should be a diff. */
5377 commitpt->text = (Deltatext *) xmalloc (sizeof (Deltatext));
5378 memset (commitpt->text, 0, sizeof (Deltatext));
5381 switch (diff_exec (workfile, tmpfile, NULL, NULL, diffopts, changefile))
5387 /* FIXME-update-dir: message does not include update_dir. */
5388 error (1, errno, "error diffing %s", workfile);
5391 /* FIXME-update-dir: message does not include update_dir. */
5392 error (1, 0, "error diffing %s", workfile);
5396 /* OK, the text file case here is really dumb. Logically
5397 speaking we want diff to read the files in text mode,
5398 convert them to the canonical form found in RCS files
5399 (which, we hope at least, is independent of OS--always
5400 bare linefeeds), and then work with change texts in that
5401 format. However, diff_exec both generates change
5402 texts and produces output for user purposes (e.g. patch.c),
5403 and there is no way to distinguish between the two cases.
5404 So we actually implement the text file case by writing the
5405 change text as a text file, then reading it as a text file.
5406 This should cause no harm, but doesn't strike me as
5408 get_file (changefile, changefile,
5409 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5410 &commitpt->text->text, &bufsize, &commitpt->text->len);
5412 /* If COMMITPT->TEXT->TEXT is NULL, it means that CHANGEFILE
5413 was empty and that there are no differences between revisions.
5414 In that event, we want to force RCS_rewrite to write an empty
5415 string for COMMITPT's change text. Leaving the change text
5416 field set NULL won't work, since that means "preserve the original
5417 change text for this delta." */
5418 if (commitpt->text->text == NULL)
5420 commitpt->text->text = xstrdup ("");
5421 commitpt->text->len = 0;
5426 /* This file is not being inserted at the head, but on a side
5427 branch somewhere. Make a diff from the previous revision
5428 to the working file. */
5429 switch (diff_exec (tmpfile, workfile, NULL, NULL, diffopts, changefile))
5435 /* FIXME-update-dir: message does not include update_dir. */
5436 error (1, errno, "error diffing %s", workfile);
5439 /* FIXME-update-dir: message does not include update_dir. */
5440 error (1, 0, "error diffing %s", workfile);
5443 /* See the comment above, at the other get_file invocation,
5444 regarding binary vs. text. */
5445 get_file (changefile, changefile,
5446 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5447 &dtext->text, &bufsize,
5449 if (dtext->text == NULL)
5451 dtext->text = xstrdup ("");
5456 /* Update DELTA linkage. It is important not to do this before
5457 the very end of RCS_checkin; if an error arises that forces
5458 us to abort checking in, we must not have malformed deltas
5459 partially linked into the tree.
5461 If DELTA and COMMITPT are on different branches, do nothing --
5462 DELTA is linked to the tree through COMMITPT->BRANCHES, and we
5463 don't want to change `next' pointers.
5465 Otherwise, if the nodes are both on the trunk, link DELTA to
5466 COMMITPT; otherwise, link COMMITPT to DELTA. */
5468 if (numdots (commitpt->version) == numdots (delta->version))
5470 if (STREQ (commitpt->version, rcs->head))
5472 delta->next = rcs->head;
5473 rcs->head = xstrdup (delta->version);
5476 commitpt->next = xstrdup (delta->version);
5479 /* Add DELTA to RCS->VERSIONS. */
5480 if (rcs->versions == NULL)
5481 rcs->versions = getlist();
5483 nodep->type = RCSVERS;
5484 nodep->delproc = rcsvers_delproc;
5485 nodep->data = (char *) delta;
5486 nodep->key = delta->version;
5487 (void) addnode (rcs->versions, nodep);
5489 /* Write the new RCS file, inserting the new delta at COMMITPT. */
5492 cvs_output ("new revision: ", 14);
5493 cvs_output (delta->version, 0);
5494 cvs_output ("; previous revision: ", 21);
5495 cvs_output (commitpt->version, 0);
5496 cvs_output ("\n", 1);
5499 RCS_rewrite (rcs, dtext, commitpt->version);
5501 if ((flags & RCS_FLAGS_KEEPFILE) == 0)
5503 if (unlink_file (workfile) < 0)
5504 /* FIXME-update-dir: message does not include update_dir. */
5505 error (1, errno, "cannot remove %s", workfile);
5507 if (unlink_file (tmpfile) < 0)
5508 error (0, errno, "cannot remove %s", tmpfile);
5510 if (unlink_file (changefile) < 0)
5511 error (0, errno, "cannot remove %s", changefile);
5515 cvs_output ("done\n", 5);
5518 if (allocated_workfile)
5521 if (commitpt != NULL && commitpt->text != NULL)
5523 freedeltatext (commitpt->text);
5524 commitpt->text = NULL;
5527 freedeltatext (dtext);
5529 free_rcsvers_contents (delta);
5534 /* This structure is passed between RCS_cmp_file and cmp_file_buffer. */
5536 struct cmp_file_data
5538 const char *filename;
5543 /* Compare the contents of revision REV of RCS file RCS with the
5544 contents of the file FILENAME. OPTIONS is a string for the keyword
5545 expansion options. Return 0 if the contents of the revision are
5546 the same as the contents of the file, 1 if they are different. */
5549 RCS_cmp_file (rcs, rev, options, filename)
5553 const char *filename;
5557 struct cmp_file_data data;
5560 if (options != NULL && options[0] != '\0')
5561 binary = STREQ (options, "-kb");
5566 expand = RCS_getexpand (rcs);
5567 if (expand != NULL && STREQ (expand, "b"))
5573 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5574 /* If CVS is to deal properly with special files (when
5575 PreservePermissions is on), the best way is to check out the
5576 revision to a temporary file and call `xcmp' on the two disk
5577 files. xcmp needs to handle non-regular files properly anyway,
5578 so calling it simplifies RCS_cmp_file. We *could* just yank
5579 the delta node out of the version tree and look for device
5580 numbers, but writing to disk and calling xcmp is a better
5581 abstraction (therefore probably more robust). -twp */
5587 tmp = cvs_temp_name();
5588 retcode = RCS_checkout(rcs, NULL, rev, NULL, options, tmp, NULL, NULL);
5592 retcode = xcmp (tmp, filename);
5593 if (CVS_UNLINK (tmp) < 0)
5594 error (0, errno, "cannot remove %s", tmp);
5601 fp = CVS_FOPEN (filename, binary ? FOPEN_BINARY_READ : "r");
5603 /* FIXME-update-dir: should include update_dir in message. */
5604 error (1, errno, "cannot open file %s for comparing", filename);
5606 data.filename = filename;
5610 retcode = RCS_checkout (rcs, (char *) NULL, rev, (char *) NULL,
5611 options, RUN_TTY, cmp_file_buffer,
5614 /* If we have not yet found a difference, make sure that we are at
5615 the end of the file. */
5616 if (! data.different)
5618 if (getc (fp) != EOF)
5627 return data.different;
5631 /* This is a subroutine of RCS_cmp_file. It is passed to
5634 #define CMP_BUF_SIZE (8 * 1024)
5637 cmp_file_buffer (callerdat, buffer, len)
5642 struct cmp_file_data *data = (struct cmp_file_data *) callerdat;
5645 /* If we've already found a difference, we don't need to check
5647 if (data->different)
5650 filebuf = xmalloc (len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len);
5656 checklen = len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len;
5657 if (fread (filebuf, 1, checklen, data->fp) != checklen)
5659 if (ferror (data->fp))
5660 error (1, errno, "cannot read file %s for comparing",
5662 data->different = 1;
5667 if (memcmp (filebuf, buffer, checklen) != 0)
5669 data->different = 1;
5681 /* For RCS file RCS, make symbolic tag TAG point to revision REV.
5682 This validates that TAG is OK for a user to use. Return value is
5683 -1 for error (and errno is set to indicate the error), positive for
5684 error (and an error message has been printed), or zero for success. */
5687 RCS_settag (rcs, tag, rev)
5695 if (rcs->flags & PARTIAL)
5696 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5698 /* FIXME: This check should be moved to RCS_check_tag. There is no
5699 reason for it to be here. */
5700 if (STREQ (tag, TAG_BASE)
5701 || STREQ (tag, TAG_HEAD))
5703 /* Print the name of the tag might be considered redundant
5704 with the caller, which also prints it. Perhaps this helps
5705 clarify why the tag name is considered reserved, I don't
5707 error (0, 0, "Attempt to add reserved tag name %s", tag);
5711 /* A revision number of NULL means use the head or default branch.
5712 If rev is not NULL, it may be a symbolic tag or branch number;
5713 expand it to the correct numeric revision or branch head. */
5715 rev = rcs->branch ? rcs->branch : rcs->head;
5717 /* At this point rcs->symbol_data may not have been parsed.
5718 Calling RCS_symbols will force it to be parsed into a list
5719 which we can easily manipulate. */
5720 symbols = RCS_symbols (rcs);
5721 if (symbols == NULL)
5723 symbols = getlist ();
5724 rcs->symbols = symbols;
5726 node = findnode (symbols, tag);
5730 node->data = xstrdup (rev);
5735 node->key = xstrdup (tag);
5736 node->data = xstrdup (rev);
5737 (void) addnode_at_front (symbols, node);
5743 /* Delete the symbolic tag TAG from the RCS file RCS. Return 0 if
5744 the tag was found (and removed), or 1 if it was not present. (In
5745 either case, the tag will no longer be in RCS->SYMBOLS.) */
5748 RCS_deltag (rcs, tag)
5754 if (rcs->flags & PARTIAL)
5755 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5757 symbols = RCS_symbols (rcs);
5758 if (symbols == NULL)
5761 node = findnode (symbols, tag);
5770 /* Set the default branch of RCS to REV. */
5773 RCS_setbranch (rcs, rev)
5777 if (rcs->flags & PARTIAL)
5778 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5783 if (rev == NULL && rcs->branch == NULL)
5785 if (rev != NULL && rcs->branch != NULL && STREQ (rev, rcs->branch))
5788 if (rcs->branch != NULL)
5790 rcs->branch = xstrdup (rev);
5795 /* Lock revision REV. LOCK_QUIET is 1 to suppress output. FIXME:
5796 Most of the callers only call us because RCS_checkin still tends to
5797 like a lock (a relic of old behavior inherited from the RCS ci
5798 program). If we clean this up, only "cvs admin -l" will still need
5799 to call RCS_lock. */
5801 /* FIXME-twp: if a lock owned by someone else is broken, should this
5802 send mail to the lock owner? Prompt user? It seems like such an
5803 obscure situation for CVS as almost not worth worrying much
5807 RCS_lock (rcs, rev, lock_quiet)
5817 if (rcs->flags & PARTIAL)
5818 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5820 locks = RCS_getlocks (rcs);
5822 locks = rcs->locks = getlist();
5825 /* A revision number of NULL means lock the head or default branch. */
5827 xrev = RCS_head (rcs);
5829 xrev = RCS_gettag (rcs, rev, 1, (int *) NULL);
5831 /* Make sure that the desired revision exists. Technically,
5832 we can update the locks list without even checking this,
5833 but RCS 5.7 did this. And it can't hurt. */
5834 if (xrev == NULL || findnode (rcs->versions, xrev) == NULL)
5837 error (0, 0, "%s: revision %s absent", rcs->path, rev);
5842 /* Is this rev already locked? */
5843 p = findnode (locks, xrev);
5846 if (STREQ (p->data, user))
5848 /* We already own the lock on this revision, so do nothing. */
5854 /* Well, first of all, "rev" below should be "xrev" to avoid
5855 core dumps. But more importantly, should we really be
5856 breaking the lock unconditionally? What CVS 1.9 does (via
5857 RCS) is to prompt "Revision 1.1 is already locked by fred.
5858 Do you want to break the lock? [ny](n): ". Well, we don't
5859 want to interact with the user (certainly not at the
5860 server/protocol level, and probably not in the command-line
5861 client), but isn't it more sensible to give an error and
5862 let the user run "cvs admin -u" if they want to break the
5865 /* Break the lock. */
5868 cvs_output (rev, 0);
5869 cvs_output (" unlocked\n", 0);
5873 error (1, 0, "Revision %s is already locked by %s", xrev, p->data);
5877 /* Create a new lock. */
5879 p->key = xrev; /* already xstrdupped */
5880 p->data = xstrdup (getcaller());
5881 (void) addnode_at_front (locks, p);
5885 cvs_output (xrev, 0);
5886 cvs_output (" locked\n", 0);
5892 /* Unlock revision REV. UNLOCK_QUIET is 1 to suppress output. FIXME:
5893 Like RCS_lock, this can become a no-op if we do the checkin
5896 If REV is not null and is locked by someone else, break their
5897 lock and notify them. It is an open issue whether RCS_unlock
5898 queries the user about whether or not to break the lock. */
5901 RCS_unlock (rcs, rev, unlock_quiet)
5912 if (rcs->flags & PARTIAL)
5913 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5915 /* If rev is NULL, unlock the revision held by the caller; if more
5916 than one, make the user specify the revision explicitly. This
5917 differs from RCS which unlocks the latest revision (first in
5918 rcs->locks) held by the caller. */
5923 /* No-ops: attempts to unlock an empty tree or an unlocked file. */
5924 if (rcs->head == NULL)
5927 cvs_outerr ("can't unlock an empty tree\n", 0);
5931 locks = RCS_getlocks (rcs);
5935 cvs_outerr ("No locks are set.\n", 0);
5940 for (p = locks->list->next; p != locks->list; p = p->next)
5942 if (STREQ (p->data, user))
5948 %s: multiple revisions locked by %s; please specify one", rcs->path, user);
5957 error (0, 0, "No locks are set for %s.\n", user);
5958 return 0; /* no lock found, ergo nothing to do */
5960 xrev = xstrdup (lock->key);
5964 xrev = RCS_gettag (rcs, rev, 1, (int *) NULL);
5967 error (0, 0, "%s: revision %s absent", rcs->path, rev);
5972 lock = findnode (RCS_getlocks (rcs), xrev);
5975 /* This revision isn't locked. */
5980 if (! STREQ (lock->data, user))
5982 /* If the revision is locked by someone else, notify
5983 them. Note that this shouldn't ever happen if RCS_unlock
5984 is called with a NULL revision, since that means "whatever
5985 revision is currently locked by the caller." */
5986 char *repos, *workfile;
5989 %s: revision %s locked by %s; breaking lock", rcs->path, xrev, lock->data);
5990 repos = xstrdup (rcs->path);
5991 workfile = strrchr (repos, '/');
5993 notify_do ('C', workfile, user, NULL, NULL, repos);
6000 cvs_output (xrev, 0);
6001 cvs_output (" unlocked\n", 0);
6008 /* Add USER to the access list of RCS. Do nothing if already present.
6009 FIXME-twp: check syntax of USER to make sure it's a valid id. */
6012 RCS_addaccess (rcs, user)
6018 if (rcs->flags & PARTIAL)
6019 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6021 if (rcs->access == NULL)
6022 rcs->access = xstrdup (user);
6025 access = xstrdup (rcs->access);
6026 for (a = strtok (access, " "); a != NULL; a = strtok (NULL, " "))
6028 if (STREQ (a, user))
6035 rcs->access = (char *) xrealloc
6036 (rcs->access, strlen (rcs->access) + strlen (user) + 2);
6037 strcat (rcs->access, " ");
6038 strcat (rcs->access, user);
6042 /* Remove USER from the access list of RCS. */
6045 RCS_delaccess (rcs, user)
6052 if (rcs->flags & PARTIAL)
6053 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6055 if (rcs->access == NULL)
6066 ulen = strlen (user);
6069 if (strncmp (p, user, ulen) == 0 && (p[ulen] == '\0' || p[ulen] == ' '))
6071 p = strchr (p, ' ');
6089 if (rcs->flags & PARTIAL)
6090 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6095 static int findtag PROTO ((Node *, void *));
6097 /* Return a nonzero value if the revision specified by ARG is found. */
6104 char *rev = (char *)arg;
6106 if (STREQ (node->data, rev))
6112 /* Delete revisions between REV1 and REV2. The changes between the two
6113 revisions must be collapsed, and the result stored in the revision
6114 immediately preceding the lower one. Return 0 for successful completion,
6117 Solution: check out the revision preceding REV1 and the revision
6118 following REV2. Use call_diff to find aggregate diffs between
6119 these two revisions, and replace the delta text for the latter one
6120 with the new aggregate diff. Alternatively, we could write a
6121 function that takes two change texts and combines them to produce a
6122 new change text, without checking out any revs or calling diff. It
6123 would be hairy, but so, so cool.
6125 If INCLUSIVE is set, then TAG1 and TAG2, if non-NULL, tell us to
6126 delete that revision as well (cvs admin -o tag1:tag2). If clear,
6127 delete up to but not including that revision (cvs admin -o tag1::tag2).
6128 This does not affect TAG1 or TAG2 being NULL; the meaning of the start
6129 point in ::tag2 and :tag2 is the same and likewise for end points. */
6132 RCS_delete_revs (rcs, tag1, tag2, inclusive)
6140 RCSVers *revp = NULL;
6145 char *branchpoint = NULL;
6148 int rev1_inclusive = inclusive;
6149 int rev2_inclusive = inclusive;
6150 char *before = NULL;
6152 char *beforefile = NULL;
6153 char *afterfile = NULL;
6154 char *outfile = NULL;
6156 if (tag1 == NULL && tag2 == NULL)
6159 /* Assume error status until everything is finished. */
6162 /* Make sure both revisions exist. */
6165 rev1 = RCS_gettag (rcs, tag1, 1, NULL);
6166 if (rev1 == NULL || (nodep = findnode (rcs->versions, rev1)) == NULL)
6168 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag1);
6174 rev2 = RCS_gettag (rcs, tag2, 1, NULL);
6175 if (rev2 == NULL || (nodep = findnode (rcs->versions, rev2)) == NULL)
6177 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag2);
6182 /* If rev1 is on the trunk and rev2 is NULL, rev2 should be
6183 RCS->HEAD. (*Not* RCS_head(rcs), which may return rcs->branch
6184 instead.) We need to check this special case early, in order
6185 to make sure that rev1 and rev2 get ordered correctly. */
6186 if (rev2 == NULL && numdots (rev1) == 1)
6188 rev2 = xstrdup (rcs->head);
6195 if (rev1 != NULL && rev2 != NULL)
6197 /* A range consisting of a branch number means the latest revision
6199 if (RCS_isbranch (rcs, rev1) && STREQ (rev1, rev2))
6200 rev1 = rev2 = RCS_getbranch (rcs, rev1, 0);
6203 /* Make sure REV1 and REV2 are ordered correctly (in the
6204 same order as the next field). For revisions on the
6205 trunk, REV1 should be higher than REV2; for branches,
6206 REV1 should be lower. */
6207 /* Shouldn't we just be giving an error in the case where
6208 the user specifies the revisions in the wrong order
6209 (that is, always swap on the trunk, never swap on a
6210 branch, in the non-error cases)? It is not at all
6211 clear to me that users who specify -o 1.4:1.2 really
6212 meant to type -o 1.2:1.4, and the out of order usage
6213 has never been documented, either by cvs.texinfo or
6217 if (numdots (rev1) == 1)
6219 if (compare_revnums (rev1, rev2) <= 0)
6225 temp_inclusive = rev2_inclusive;
6226 rev2_inclusive = rev1_inclusive;
6227 rev1_inclusive = temp_inclusive;
6230 else if (compare_revnums (rev1, rev2) > 0)
6236 temp_inclusive = rev2_inclusive;
6237 rev2_inclusive = rev1_inclusive;
6238 rev1_inclusive = temp_inclusive;
6243 /* Basically the same thing; make sure that the ordering is what we
6247 assert (rev2 != NULL);
6248 if (numdots (rev2) == 1)
6250 /* Swap rev1 and rev2. */
6256 temp_inclusive = rev2_inclusive;
6257 rev2_inclusive = rev1_inclusive;
6258 rev1_inclusive = temp_inclusive;
6262 /* Put the revision number preceding the first one to delete into
6263 BEFORE (where "preceding" means according to the next field).
6264 If the first revision to delete is the first revision on its
6265 branch (e.g. 1.3.2.1), BEFORE should be the node on the trunk
6266 at which the branch is rooted. If the first revision to delete
6267 is the head revision of the trunk, set BEFORE to NULL.
6269 Note that because BEFORE may not be on the same branch as REV1,
6270 it is not very handy for navigating the revision tree. It's
6271 most useful just for checking out the revision preceding REV1. */
6273 branchpoint = RCS_getbranchpoint (rcs, rev1 != NULL ? rev1 : rev2);
6276 rev1 = xstrdup (branchpoint);
6277 if (numdots (branchpoint) > 1)
6280 bp = strrchr (branchpoint, '.');
6281 while (*--bp != '.')
6284 /* Note that this is exclusive, always, because the inclusive
6285 flag doesn't affect the meaning when rev1 == NULL. */
6286 before = xstrdup (branchpoint);
6290 else if (! STREQ (rev1, branchpoint))
6292 /* Walk deltas from BRANCHPOINT on, looking for REV1. */
6293 nodep = findnode (rcs->versions, branchpoint);
6294 revp = (RCSVers *) nodep->data;
6295 while (revp->next != NULL && ! STREQ (revp->next, rev1))
6297 revp = (RCSVers *) nodep->data;
6298 nodep = findnode (rcs->versions, revp->next);
6300 if (revp->next == NULL)
6302 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, rev1);
6306 before = xstrdup (revp->version);
6310 nodep = findnode (rcs->versions, before);
6311 rev1 = xstrdup (((RCSVers *)nodep->data)->next);
6314 else if (!rev1_inclusive)
6317 nodep = findnode (rcs->versions, before);
6318 rev1 = xstrdup (((RCSVers *)nodep->data)->next);
6320 else if (numdots (branchpoint) > 1)
6322 /* Example: rev1 is "1.3.2.1", branchpoint is "1.3.2.1".
6323 Set before to "1.3". */
6325 bp = strrchr (branchpoint, '.');
6326 while (*--bp != '.')
6329 before = xstrdup (branchpoint);
6333 /* If any revision between REV1 and REV2 is locked or is a branch point,
6334 we can't delete that revision and must abort. */
6338 while (!found && next != NULL)
6340 nodep = findnode (rcs->versions, next);
6341 revp = (RCSVers *) nodep->data;
6344 found = STREQ (revp->version, rev2);
6347 if ((!found && next != NULL) || rev2_inclusive || rev2 == NULL)
6349 if (findnode (RCS_getlocks (rcs), revp->version))
6351 error (0, 0, "%s: can't remove locked revision %s",
6356 if (revp->branches != NULL)
6358 error (0, 0, "%s: can't remove branch point %s",
6364 /* Doing this only for the :: syntax is for compatibility.
6365 See cvs.texinfo for somewhat more discussion. */
6367 && walklist (RCS_symbols (rcs), findtag, revp->version))
6369 /* We don't print which file this happens to on the theory
6370 that the caller will print the name of the file in a
6371 more useful fashion (fullname not rcs->path). */
6372 error (0, 0, "cannot remove revision %s because it has tags",
6377 /* It's misleading to print the `deleting revision' output
6378 here, since we may not actually delete these revisions.
6379 But that's how RCS does it. Bleah. Someday this should be
6380 moved to the point where the revs are actually marked for
6382 cvs_output ("deleting revision ", 0);
6383 cvs_output (revp->version, 0);
6384 cvs_output ("\n", 1);
6393 after = xstrdup (next);
6395 after = xstrdup (revp->version);
6397 else if (!inclusive)
6399 /* In the case of an empty range, for example 1.2::1.2 or
6400 1.2::1.3, we want to just do nothing. */
6406 /* This looks fishy in the cases where tag1 == NULL or tag2 == NULL.
6407 Are those cases really impossible? */
6408 assert (tag1 != NULL);
6409 assert (tag2 != NULL);
6411 error (0, 0, "%s: invalid revision range %s:%s", rcs->path,
6416 if (after == NULL && before == NULL)
6418 /* The user is trying to delete all revisions. While an
6419 RCS file without revisions makes sense to RCS (e.g. the
6420 state after "rcs -i"), CVS has never been able to cope with
6421 it. So at least for now we just make this an error.
6423 We don't include rcs->path in the message since "cvs admin"
6424 already printed "RCS file:" and the name. */
6425 error (1, 0, "attempt to delete all revisions");
6428 /* The conditionals at this point get really hairy. Here is the
6431 IF before != NULL and after == NULL
6432 THEN don't check out any revisions, just delete them
6433 IF before == NULL and after != NULL
6434 THEN only check out after's revision, and use it for the new deltatext
6436 check out both revisions and diff -n them. This could use
6437 RCS_exec_rcsdiff with some changes, like being able
6438 to suppress diagnostic messages and to direct output. */
6443 size_t bufsize, len;
6445 #if defined (__CYGWIN32__) || defined (_WIN32)
6446 /* FIXME: This is an awful kludge, but at least until I have
6447 time to work on it a little more and test it, I'd rather
6448 give a fatal error than corrupt the file. I think that we
6449 need to use "-kb" and "--binary" and "rb" to get_file
6450 (probably can do it always, not just for binary files, if
6451 we are consistent between the RCS_checkout and the diff). */
6453 char *expand = RCS_getexpand (rcs);
6454 if (expand != NULL && STREQ (expand, "b"))
6456 "admin -o not implemented yet for binary on this system");
6460 afterfile = cvs_temp_name();
6461 status = RCS_checkout (rcs, NULL, after, NULL, "-ko", afterfile,
6462 (RCSCHECKOUTPROC)0, NULL);
6468 /* We are deleting revisions from the head of the tree,
6469 so must create a new head. */
6472 get_file (afterfile, afterfile, "r", &diffbuf, &bufsize, &len);
6474 save_noexec = noexec;
6476 if (unlink_file (afterfile) < 0)
6477 error (0, errno, "cannot remove %s", afterfile);
6478 noexec = save_noexec;
6484 rcs->head = xstrdup (after);
6488 beforefile = cvs_temp_name();
6489 status = RCS_checkout (rcs, NULL, before, NULL, "-ko", beforefile,
6490 (RCSCHECKOUTPROC)0, NULL);
6494 outfile = cvs_temp_name();
6495 status = diff_exec (beforefile, afterfile, NULL, NULL, "-an", outfile);
6499 /* Not sure we need this message; will diff_exec already
6500 have printed an error? */
6501 error (0, 0, "%s: could not diff", rcs->path);
6508 get_file (outfile, outfile, "r", &diffbuf, &bufsize, &len);
6511 /* Save the new change text in after's delta node. */
6512 nodep = findnode (rcs->versions, after);
6513 revp = (RCSVers *) nodep->data;
6515 assert (revp->text == NULL);
6517 revp->text = (Deltatext *) xmalloc (sizeof (Deltatext));
6518 memset ((Deltatext *) revp->text, 0, sizeof (Deltatext));
6519 revp->text->version = xstrdup (revp->version);
6520 revp->text->text = diffbuf;
6521 revp->text->len = len;
6523 /* If DIFFBUF is NULL, it means that OUTFILE is empty and that
6524 there are no differences between the two revisions. In that
6525 case, we want to force RCS_copydeltas to write an empty string
6526 for the new change text (leaving the text field set NULL
6527 means "preserve the original change text for this delta," so
6528 we don't want that). */
6529 if (revp->text->text == NULL)
6530 revp->text->text = xstrdup ("");
6533 /* Walk through the revisions (again) to mark each one as
6534 outdated. (FIXME: would it be safe to use the `dead' field for
6537 next != NULL && (after == NULL || ! STREQ (next, after));
6540 nodep = findnode (rcs->versions, next);
6541 revp = (RCSVers *) nodep->data;
6545 /* Update delta links. If BEFORE == NULL, we're changing the
6546 head of the tree and don't need to update any `next' links. */
6549 /* If REV1 is the first node on its branch, then BEFORE is its
6550 root node (on the trunk) and we have to update its branches
6551 list. Otherwise, BEFORE is on the same branch as AFTER, and
6552 we can just change BEFORE's `next' field to point to AFTER.
6553 (This should be safe: since findnode manages its lists via
6554 the `hashnext' and `hashprev' fields, rather than `next' and
6555 `prev', mucking with `next' and `prev' should not corrupt the
6556 delta tree's internal structure. Much. -twp) */
6559 /* beforep's ->next field already should be equal to after,
6560 which I think is always NULL in this case. */
6562 else if (STREQ (rev1, branchpoint))
6564 nodep = findnode (rcs->versions, before);
6565 revp = (RCSVers *) nodep->data;
6566 nodep = revp->branches->list->next;
6567 while (nodep != revp->branches->list &&
6568 ! STREQ (nodep->key, rev1))
6569 nodep = nodep->next;
6570 assert (nodep != revp->branches->list);
6576 nodep->key = xstrdup (after);
6581 nodep = findnode (rcs->versions, before);
6582 beforep = (RCSVers *) nodep->data;
6583 free (beforep->next);
6584 beforep->next = xstrdup (after);
6595 if (branchpoint != NULL)
6602 save_noexec = noexec;
6604 if (beforefile != NULL)
6606 if (unlink_file (beforefile) < 0)
6607 error (0, errno, "cannot remove %s", beforefile);
6610 if (afterfile != NULL)
6612 if (unlink_file (afterfile) < 0)
6613 error (0, errno, "cannot remove %s", afterfile);
6616 if (outfile != NULL)
6618 if (unlink_file (outfile) < 0)
6619 error (0, errno, "cannot remove %s", outfile);
6622 noexec = save_noexec;
6628 * TRUE if there exists a symbolic tag "tag" in file.
6631 RCS_exist_tag (rcs, tag)
6636 assert (rcs != NULL);
6638 if (findnode (RCS_symbols (rcs), tag))
6645 * TRUE if RCS revision number "rev" exists.
6646 * This includes magic branch revisions, not found in rcs->versions,
6647 * but only in rcs->symbols, requiring a list walk to find them.
6648 * Take advantage of list walk callback function already used by
6649 * RCS_delete_revs, above.
6652 RCS_exist_rev (rcs, rev)
6657 assert (rcs != NULL);
6659 if (rcs->flags & PARTIAL)
6660 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6662 if (findnode(rcs->versions, rev) != 0)
6665 if (walklist (RCS_symbols(rcs), findtag, rev) != 0)
6673 /* RCS_deltas and friends. Processing of the deltas in RCS files. */
6677 /* Text of this line. Part of the same malloc'd block as the struct
6678 line itself (we probably should use the "struct hack" (char text[1])
6679 and save ourselves sizeof (char *) bytes). Does not include \n;
6680 instead has_newline indicates the presence or absence of \n. */
6682 /* Length of this line, not counting \n if has_newline is true. */
6684 /* Version in which it was introduced. */
6686 /* Nonzero if this line ends with \n. This will always be true
6687 except possibly for the last line. */
6689 /* Number of pointers to this struct line. */
6695 /* How many lines in use for this linevector? */
6696 unsigned int nlines;
6697 /* How many lines allocated for this linevector? */
6698 unsigned int lines_alloced;
6699 /* Pointer to array containing a pointer to each line. */
6700 struct line **vector;
6703 static void linevector_init PROTO ((struct linevector *));
6705 /* Initialize *VEC to be a linevector with no lines. */
6707 linevector_init (vec)
6708 struct linevector *vec;
6710 vec->lines_alloced = 0;
6715 static int linevector_add PROTO ((struct linevector *vec, const char *text,
6716 size_t len, RCSVers *vers,
6719 /* Given some text TEXT, add each of its lines to VEC before line POS
6720 (where line 0 is the first line). The last line in TEXT may or may
6721 not be \n terminated.
6722 Set the version for each of the new lines to VERS. This
6723 function returns non-zero for success. It returns zero if the line
6724 number is out of range.
6726 Each of the lines in TEXT are copied to space which is managed with
6727 the linevector (and freed by linevector_free). So the caller doesn't
6728 need to keep TEXT around after the call to this function. */
6730 linevector_add (vec, text, len, vers, pos)
6731 struct linevector *vec;
6737 const char *textend;
6741 const char *nextline_text;
6742 size_t nextline_len;
6743 int nextline_newline;
6749 textend = text + len;
6751 /* Count the number of lines we will need to add. */
6753 for (p = text; p < textend; ++p)
6754 if (*p == '\n' && p + 1 < textend)
6757 /* Expand VEC->VECTOR if needed. */
6758 if (vec->nlines + nnew >= vec->lines_alloced)
6760 if (vec->lines_alloced == 0)
6761 vec->lines_alloced = 10;
6762 while (vec->nlines + nnew >= vec->lines_alloced)
6763 vec->lines_alloced *= 2;
6764 vec->vector = xrealloc (vec->vector,
6765 vec->lines_alloced * sizeof (*vec->vector));
6768 /* Make room for the new lines in VEC->VECTOR. */
6769 for (i = vec->nlines + nnew - 1; i >= pos + nnew; --i)
6770 vec->vector[i] = vec->vector[i - nnew];
6772 if (pos > vec->nlines)
6775 /* Actually add the lines, to VEC->VECTOR. */
6777 nextline_text = text;
6778 nextline_newline = 0;
6779 for (p = text; p < textend; ++p)
6782 nextline_newline = 1;
6783 if (p + 1 == textend)
6784 /* If there are no characters beyond the last newline, we
6785 don't consider it another line. */
6787 nextline_len = p - nextline_text;
6788 q = (struct line *) xmalloc (sizeof (struct line) + nextline_len);
6790 q->text = (char *)q + sizeof (struct line);
6791 q->len = nextline_len;
6792 q->has_newline = nextline_newline;
6794 memcpy (q->text, nextline_text, nextline_len);
6795 vec->vector[i++] = q;
6797 nextline_text = (char *)p + 1;
6798 nextline_newline = 0;
6800 nextline_len = p - nextline_text;
6801 q = (struct line *) xmalloc (sizeof (struct line) + nextline_len);
6803 q->text = (char *)q + sizeof (struct line);
6804 q->len = nextline_len;
6805 q->has_newline = nextline_newline;
6807 memcpy (q->text, nextline_text, nextline_len);
6810 vec->nlines += nnew;
6815 static void linevector_delete PROTO ((struct linevector *, unsigned int,
6818 /* Remove NLINES lines from VEC at position POS (where line 0 is the
6821 linevector_delete (vec, pos, nlines)
6822 struct linevector *vec;
6824 unsigned int nlines;
6829 last = vec->nlines - nlines;
6830 for (i = pos; i < pos + nlines; ++i)
6832 if (--vec->vector[i]->refcount == 0)
6833 free (vec->vector[i]);
6835 for (i = pos; i < last; ++i)
6836 vec->vector[i] = vec->vector[i + nlines];
6837 vec->nlines -= nlines;
6840 static void linevector_copy PROTO ((struct linevector *, struct linevector *));
6842 /* Copy FROM to TO, copying the vectors but not the lines pointed to. */
6844 linevector_copy (to, from)
6845 struct linevector *to;
6846 struct linevector *from;
6850 for (ln = 0; ln < to->nlines; ++ln)
6852 if (--to->vector[ln]->refcount == 0)
6853 free (to->vector[ln]);
6855 if (from->nlines > to->lines_alloced)
6857 if (to->lines_alloced == 0)
6858 to->lines_alloced = 10;
6859 while (from->nlines > to->lines_alloced)
6860 to->lines_alloced *= 2;
6861 to->vector = (struct line **)
6862 xrealloc (to->vector, to->lines_alloced * sizeof (*to->vector));
6864 memcpy (to->vector, from->vector,
6865 from->nlines * sizeof (*to->vector));
6866 to->nlines = from->nlines;
6867 for (ln = 0; ln < to->nlines; ++ln)
6868 ++to->vector[ln]->refcount;
6871 static void linevector_free PROTO ((struct linevector *));
6873 /* Free storage associated with linevector. */
6875 linevector_free (vec)
6876 struct linevector *vec;
6880 if (vec->vector != NULL)
6882 for (ln = 0; ln < vec->nlines; ++ln)
6883 if (--vec->vector[ln]->refcount == 0)
6884 free (vec->vector[ln]);
6890 static char *month_printname PROTO ((char *));
6892 /* Given a textual string giving the month (1-12), terminated with any
6893 character not recognized by atoi, return the 3 character name to
6894 print it with. I do not think it is a good idea to change these
6895 strings based on the locale; they are standard abbreviations (for
6896 example in rfc822 mail messages) which should be widely understood.
6897 Returns a pointer into static readonly storage. */
6899 month_printname (month)
6902 static const char *const months[] =
6903 {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
6904 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
6907 mnum = atoi (month);
6908 if (mnum < 1 || mnum > 12)
6910 return (char *)months[mnum - 1];
6914 apply_rcs_changes PROTO ((struct linevector *, const char *, size_t,
6915 const char *, RCSVers *, RCSVers *));
6917 /* Apply changes to the line vector LINES. DIFFBUF is a buffer of
6918 length DIFFLEN holding the change text from an RCS file (the output
6919 of diff -n). NAME is used in error messages. The VERS field of
6920 any line added is set to ADDVERS. The VERS field of any line
6921 deleted is set to DELVERS, unless DELVERS is NULL, in which case
6922 the VERS field of deleted lines is unchanged. The function returns
6923 non-zero if the change text is applied successfully. It returns
6924 zero if the change text does not appear to apply to LINES (e.g., a
6925 line number is invalid). If the change text is improperly
6926 formatted (e.g., it is not the output of diff -n), the function
6927 calls error with a status of 1, causing the program to exit. */
6930 apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
6931 struct linevector *lines;
6932 const char *diffbuf;
6941 /* The RCS format throws us for a loop in that the deltafrags (if
6942 we define a deltafrag as an add or a delete) need to be applied
6943 in reverse order. So we stick them into a linked list. */
6945 enum {FRAG_ADD, FRAG_DELETE} type;
6947 unsigned long nlines;
6948 const char *new_lines;
6950 struct deltafrag *next;
6952 struct deltafrag *dfhead;
6953 struct deltafrag *df;
6956 for (p = diffbuf; p != NULL && p < diffbuf + difflen; )
6959 if (op != 'a' && op != 'd')
6960 /* Can't just skip over the deltafrag, because the value
6961 of op determines the syntax. */
6962 error (1, 0, "unrecognized operation '\\x%x' in %s",
6964 df = (struct deltafrag *) xmalloc (sizeof (struct deltafrag));
6967 df->pos = strtoul (p, (char **) &q, 10);
6970 error (1, 0, "number expected in %s", name);
6973 error (1, 0, "space expected in %s", name);
6974 df->nlines = strtoul (p, (char **) &q, 10);
6976 error (1, 0, "number expected in %s", name);
6979 error (1, 0, "linefeed expected in %s", name);
6985 df->type = FRAG_ADD;
6987 /* The text we want is the number of lines specified, or
6988 until the end of the value, whichever comes first (it
6989 will be the former except in the case where we are
6990 adding a line which does not end in newline). */
6991 for (q = p; i != 0; ++q)
6994 else if (q == diffbuf + difflen)
6997 error (1, 0, "premature end of change in %s", name);
7002 /* Stash away a pointer to the text we are adding. */
7010 /* Correct for the fact that line numbers in RCS files
7015 df->type = FRAG_DELETE;
7019 for (df = dfhead; df != NULL;)
7026 if (! linevector_add (lines, df->new_lines, df->len, addvers,
7031 if (df->pos > lines->nlines
7032 || df->pos + df->nlines > lines->nlines)
7034 if (delvers != NULL)
7035 for (ln = df->pos; ln < df->pos + df->nlines; ++ln)
7036 lines->vector[ln]->vers = delvers;
7037 linevector_delete (lines, df->pos, df->nlines);
7048 /* Apply an RCS change text to a buffer. The function name starts
7049 with rcs rather than RCS because this does not take an RCSNode
7050 argument. NAME is used in error messages. TEXTBUF is the text
7051 buffer to change, and TEXTLEN is the size. DIFFBUF and DIFFLEN are
7052 the change buffer and size. The new buffer is returned in *RETBUF
7053 and *RETLEN. The new buffer is allocated by xmalloc.
7055 Return 1 for success. On failure, call error and return 0. */
7058 rcs_change_text (name, textbuf, textlen, diffbuf, difflen, retbuf, retlen)
7062 const char *diffbuf;
7067 struct linevector lines;
7073 linevector_init (&lines);
7075 if (! linevector_add (&lines, textbuf, textlen, NULL, 0))
7076 error (1, 0, "cannot initialize line vector");
7078 if (! apply_rcs_changes (&lines, diffbuf, difflen, name, NULL, NULL))
7080 error (0, 0, "invalid change text in %s", name);
7090 for (ln = 0; ln < lines.nlines; ++ln)
7092 n += lines.vector[ln]->len + 1;
7097 for (ln = 0; ln < lines.nlines; ++ln)
7099 memcpy (p, lines.vector[ln]->text, lines.vector[ln]->len);
7100 p += lines.vector[ln]->len;
7101 if (lines.vector[ln]->has_newline)
7105 *retlen = p - *retbuf;
7106 assert (*retlen <= n);
7111 linevector_free (&lines);
7116 /* Walk the deltas in RCS to get to revision VERSION.
7118 If OP is RCS_ANNOTATE, then write annotations using cvs_output.
7120 If OP is RCS_FETCH, then put the contents of VERSION into a
7121 newly-malloc'd array and put a pointer to it in *TEXT. Each line
7122 is \n terminated; the caller is responsible for converting text
7123 files if desired. The total length is put in *LEN.
7125 If FP is non-NULL, it should be a file descriptor open to the file
7126 RCS with file position pointing to the deltas. We close the file
7129 If LOG is non-NULL, then *LOG is set to the log message of VERSION,
7130 and *LOGLEN is set to the length of the log message.
7132 On error, give a fatal error. */
7135 RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
7138 struct rcsbuffer *rcsbuf;
7140 enum rcs_delta_op op;
7146 struct rcsbuffer rcsbuf_local;
7147 char *branchversion;
7154 RCSVers *trunk_vers;
7156 int ishead, isnext, isversion, onbranch;
7158 struct linevector headlines;
7159 struct linevector curlines;
7160 struct linevector trunklines;
7165 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf_local);
7166 rcsbuf = &rcsbuf_local;
7177 linevector_init (&curlines);
7178 linevector_init (&headlines);
7179 linevector_init (&trunklines);
7181 /* We set BRANCHVERSION to the version we are currently looking
7182 for. Initially, this is the version on the trunk from which
7183 VERSION branches off. If VERSION is not a branch, then
7184 BRANCHVERSION is just VERSION. */
7185 branchversion = xstrdup (version);
7186 cpversion = strchr (branchversion, '.');
7187 if (cpversion != NULL)
7188 cpversion = strchr (cpversion + 1, '.');
7189 if (cpversion != NULL)
7193 if (! rcsbuf_getrevnum (rcsbuf, &key))
7194 error (1, 0, "unexpected EOF reading RCS file %s", rcs->path);
7196 if (next != NULL && ! STREQ (next, key))
7198 /* This is not the next version we need. It is a branch
7199 version which we want to ignore. */
7207 /* look up the revision */
7208 node = findnode (rcs->versions, key);
7211 "mismatch in rcs file %s between deltas and deltatexts (%s)",
7214 /* Stash the previous version. */
7217 vers = (RCSVers *) node->data;
7220 /* Compare key and trunkversion now, because key points to
7221 storage controlled by rcsbuf_getkey. */
7222 if (STREQ (branchversion, key))
7230 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7231 error (1, 0, "%s does not appear to be a valid rcs file",
7236 && STREQ (key, "log")
7237 && STREQ (branchversion, version))
7239 *log = rcsbuf_valcopy (rcsbuf, value, 0, loglen);
7242 if (STREQ (key, "text"))
7244 rcsbuf_valpolish (rcsbuf, value, 0, &vallen);
7247 if (! linevector_add (&curlines, value, vallen, NULL, 0))
7248 error (1, 0, "invalid rcs file %s", rcs->path);
7254 if (! apply_rcs_changes (&curlines, value, vallen,
7256 onbranch ? vers : NULL,
7257 onbranch ? NULL : prev_vers))
7258 error (1, 0, "invalid change text in %s", rcs->path);
7266 /* This is either the version we want, or it is the
7267 branchpoint to the version we want. */
7268 if (STREQ (branchversion, version))
7270 /* This is the version we want. */
7271 linevector_copy (&headlines, &curlines);
7275 /* We have found this version by tracking up a
7276 branch. Restore back to the lines we saved
7277 when we left the trunk, and continue tracking
7282 linevector_copy (&curlines, &trunklines);
7289 /* We need to look up the branch. */
7292 if (numdots (branchversion) < 2)
7296 /* We are leaving the trunk; save the current
7297 lines so that we can restore them when we
7298 continue tracking down the trunk. */
7300 linevector_copy (&trunklines, &curlines);
7302 /* Reset the version information we have
7303 accumulated so far. It only applies to the
7304 changes from the head to this version. */
7305 for (ln = 0; ln < curlines.nlines; ++ln)
7306 curlines.vector[ln]->vers = NULL;
7309 /* The next version we want is the entry on
7310 VERS->branches which matches this branch. For
7311 example, suppose VERSION is 1.21.4.3 and
7312 BRANCHVERSION was 1.21. Then we look for an entry
7313 starting with "1.21.4" and we'll put it (probably
7314 1.21.4.1) in NEXT. We'll advance BRANCHVERSION by
7315 two dots (in this example, to 1.21.4.3). */
7317 if (vers->branches == NULL)
7318 error (1, 0, "missing expected branches in %s",
7322 cpversion = strchr (cpversion, '.');
7323 if (cpversion == NULL)
7324 error (1, 0, "version number confusion in %s",
7326 for (p = vers->branches->list->next;
7327 p != vers->branches->list;
7329 if (strncmp (p->key, branchversion,
7330 cpversion - branchversion) == 0)
7332 if (p == vers->branches->list)
7333 error (1, 0, "missing expected branch in %s",
7338 cpversion = strchr (cpversion + 1, '.');
7339 if (cpversion != NULL)
7343 if (op == RCS_FETCH && foundhead)
7345 } while (next != NULL);
7347 free (branchversion);
7349 rcsbuf_cache (rcs, rcsbuf);
7352 error (1, 0, "could not find desired version %s in %s",
7353 version, rcs->path);
7355 /* Now print out or return the data we have just computed. */
7362 for (ln = 0; ln < headlines.nlines; ++ln)
7365 /* Period which separates year from month in date. */
7367 /* Period which separates month from day in date. */
7371 prvers = headlines.vector[ln]->vers;
7375 sprintf (buf, "%-12s (%-8.8s ",
7378 cvs_output (buf, 0);
7380 /* Now output the date. */
7381 ym = strchr (prvers->date, '.');
7384 /* ??- is an ANSI trigraph. The ANSI way to
7385 avoid it is \? but some pre ANSI compilers
7386 complain about the unrecognized escape
7387 sequence. Of course string concatenation
7388 ("??" "-???") is also an ANSI-ism. Testing
7389 __STDC__ seems to be a can of worms, since
7390 compilers do all kinds of things with it. */
7391 cvs_output ("??", 0);
7392 cvs_output ("-???", 0);
7393 cvs_output ("-??", 0);
7397 md = strchr (ym + 1, '.');
7399 cvs_output ("??", 0);
7401 cvs_output (md + 1, 2);
7403 cvs_output ("-", 1);
7404 cvs_output (month_printname (ym + 1), 0);
7405 cvs_output ("-", 1);
7406 /* Only output the last two digits of the year. Our output
7407 lines are long enough as it is without printing the
7409 cvs_output (ym - 2, 2);
7411 cvs_output ("): ", 0);
7412 if (headlines.vector[ln]->len != 0)
7413 cvs_output (headlines.vector[ln]->text,
7414 headlines.vector[ln]->len);
7415 cvs_output ("\n", 1);
7425 assert (text != NULL);
7426 assert (len != NULL);
7429 for (ln = 0; ln < headlines.nlines; ++ln)
7431 n += headlines.vector[ln]->len + 1;
7434 for (ln = 0; ln < headlines.nlines; ++ln)
7436 memcpy (p, headlines.vector[ln]->text,
7437 headlines.vector[ln]->len);
7438 p += headlines.vector[ln]->len;
7439 if (headlines.vector[ln]->has_newline)
7448 linevector_free (&curlines);
7449 linevector_free (&headlines);
7450 linevector_free (&trunklines);
7455 /* Read the information for a single delta from the RCS buffer RCSBUF,
7456 whose name is RCSFILE. *KEYP and *VALP are either NULL, or the
7457 first key/value pair to read, as set by rcsbuf_getkey. Return NULL
7458 if there are no more deltas. Store the key/value pair which
7459 terminated the read in *KEYP and *VALP. */
7462 getdelta (rcsbuf, rcsfile, keyp, valp)
7463 struct rcsbuffer *rcsbuf;
7469 char *key, *value, *cp;
7472 /* Get revision number if it wasn't passed in. This uses
7473 rcsbuf_getkey because it doesn't croak when encountering
7474 unexpected input. As a result, we have to play unholy games
7475 with `key' and `value'. */
7483 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7484 error (1, 0, "%s: unexpected EOF", rcsfile);
7487 /* Make sure that it is a revision number and not a cabbage
7490 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
7493 /* Note that when comparing with RCSDATE, we are not massaging
7494 VALUE from the string found in the RCS file. This is OK since
7495 we know exactly what to expect. */
7496 if (*cp != '\0' || strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) != 0)
7503 vnode = (RCSVers *) xmalloc (sizeof (RCSVers));
7504 memset (vnode, 0, sizeof (RCSVers));
7506 vnode->version = xstrdup (key);
7508 /* Grab the value of the date from value. Note that we are not
7509 massaging VALUE from the string found in the RCS file. */
7510 cp = value + (sizeof RCSDATE) - 1; /* skip the "date" keyword */
7511 while (whitespace (*cp)) /* take space off front of value */
7514 vnode->date = xstrdup (cp);
7516 /* Get author field. */
7517 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7519 error (1, 0, "unexpected end of file reading %s", rcsfile);
7521 if (! STREQ (key, "author"))
7523 unable to parse %s; `author' not in the expected place", rcsfile);
7524 vnode->author = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7526 /* Get state field. */
7527 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7529 error (1, 0, "unexpected end of file reading %s", rcsfile);
7531 if (! STREQ (key, "state"))
7533 unable to parse %s; `state' not in the expected place", rcsfile);
7534 vnode->state = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7535 /* The value is optional, according to rcsfile(5). */
7536 if (value != NULL && STREQ (value, RCSDEAD))
7541 /* Note that "branches" and "next" are in fact mandatory, according
7544 /* fill in the branch list (if any branches exist) */
7545 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7547 error (1, 0, "unexpected end of file reading %s", rcsfile);
7549 if (STREQ (key, RCSDESC))
7553 /* Probably could/should be a fatal error. */
7554 error (0, 0, "warning: 'branches' keyword missing from %s", rcsfile);
7557 if (value != (char *) NULL)
7559 vnode->branches = getlist ();
7560 /* Note that we are not massaging VALUE from the string found
7562 do_branches (vnode->branches, value);
7565 /* fill in the next field if there is a next revision */
7566 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7568 error (1, 0, "unexpected end of file reading %s", rcsfile);
7570 if (STREQ (key, RCSDESC))
7574 /* Probably could/should be a fatal error. */
7575 error (0, 0, "warning: 'next' keyword missing from %s", rcsfile);
7578 if (value != (char *) NULL)
7579 vnode->next = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7582 * XXX - this is where we put the symbolic link stuff???
7583 * (into newphrases in the deltas).
7587 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7588 error (1, 0, "unexpected end of file reading %s", rcsfile);
7590 /* The `desc' keyword is the end of the deltas. */
7591 if (strcmp (key, RCSDESC) == 0)
7594 #ifdef PRESERVE_PERMISSIONS_SUPPORT
7596 /* The `hardlinks' value is a group of words, which must
7597 be parsed separately and added as a list to vnode->hardlinks. */
7598 if (strcmp (key, "hardlinks") == 0)
7602 vnode->hardlinks = getlist();
7603 while ((word = rcsbuf_valword (rcsbuf, &value)) != NULL)
7605 Node *n = getnode();
7607 addnode (vnode->hardlinks, n);
7613 /* Enable use of repositories created by certain obsolete
7614 versions of CVS. This code should remain indefinately;
7615 there is no procedure for converting old repositories, and
7616 checking for it is harmless. */
7617 if (STREQ (key, RCSDEAD))
7620 if (vnode->state != NULL)
7621 free (vnode->state);
7622 vnode->state = xstrdup (RCSDEAD);
7625 /* if we have a new revision number, we're done with this delta */
7627 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
7630 /* Note that when comparing with RCSDATE, we are not massaging
7631 VALUE from the string found in the RCS file. This is OK
7632 since we know exactly what to expect. */
7633 if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0)
7636 /* At this point, key and value represent a user-defined field
7637 in the delta node. */
7638 if (vnode->other_delta == NULL)
7639 vnode->other_delta = getlist ();
7641 kv->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
7642 kv->key = xstrdup (key);
7643 kv->data = rcsbuf_valcopy (rcsbuf, value, kv->type == RCSFIELD,
7645 if (addnode (vnode->other_delta, kv) != 0)
7647 /* Complaining about duplicate keys in newphrases seems
7648 questionable, in that we don't know what they mean and
7649 doc/RCSFILES has no prohibition on several newphrases
7650 with the same key. But we can't store more than one as
7651 long as we store them in a List *. */
7652 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
7658 /* Return the key which caused us to fail back to the caller. */
7669 if (d->version != NULL)
7673 if (d->text != NULL)
7675 if (d->other != (List *) NULL)
7676 dellist (&d->other);
7681 RCS_getdeltatext (rcs, fp, rcsbuf)
7684 struct rcsbuffer *rcsbuf;
7691 /* Get the revision number. */
7692 if (! rcsbuf_getrevnum (rcsbuf, &num))
7694 /* If num == NULL, it means we reached EOF naturally. That's
7699 error (1, 0, "%s: unexpected EOF", rcs->path);
7702 p = findnode (rcs->versions, num);
7704 error (1, 0, "mismatch in rcs file %s between deltas and deltatexts (%s)",
7707 d = (Deltatext *) xmalloc (sizeof (Deltatext));
7708 d->version = xstrdup (num);
7710 /* Get the log message. */
7711 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7712 error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num);
7713 if (! STREQ (key, "log"))
7714 error (1, 0, "%s, delta %s: expected `log', got `%s'",
7715 rcs->path, num, key);
7716 d->log = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7718 /* Get random newphrases. */
7719 d->other = getlist();
7722 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7723 error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num);
7725 if (STREQ (key, "text"))
7729 p->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
7730 p->key = xstrdup (key);
7731 p->data = rcsbuf_valcopy (rcsbuf, value, p->type == RCSFIELD,
7733 if (addnode (d->other, p) < 0)
7735 error (0, 0, "warning: %s, delta %s: duplicate field `%s'",
7736 rcs->path, num, key);
7740 /* Get the change text. We already know that this key is `text'. */
7741 d->text = rcsbuf_valcopy (rcsbuf, value, 0, &d->len);
7746 /* RCS output functions, for writing RCS format files from RCSNode
7749 For most of this work, RCS 5.7 uses an `aprintf' function which aborts
7750 program upon error. Instead, these functions check the output status
7751 of the stream right before closing it, and aborts if an error condition
7752 is found. The RCS solution is probably the better one: it produces
7753 more overhead, but will produce a clearer diagnostic in the case of
7754 catastrophic error. In either case, however, the repository will probably
7755 not get corrupted. */
7758 putsymbol_proc (symnode, fparg)
7762 FILE *fp = (FILE *) fparg;
7764 /* A fiddly optimization: this code used to just call fprintf, but
7765 in an old repository with hundreds of tags this can get called
7766 hundreds of thousands of times when doing a cvs tag. Since
7767 tagging is a relatively common operation, and using putc and
7768 fputs is just as comprehensible, the change is worthwhile. */
7771 fputs (symnode->key, fp);
7773 fputs (symnode->data, fp);
7777 static int putlock_proc PROTO ((Node *, void *));
7779 /* putlock_proc is like putsymbol_proc, but key and data are reversed. */
7782 putlock_proc (symnode, fp)
7786 return fprintf ((FILE *) fp, "\n\t%s:%s", symnode->data, symnode->key);
7790 putrcsfield_proc (node, vfp)
7794 FILE *fp = (FILE *) vfp;
7796 /* Some magic keys used internally by CVS start with `;'. Skip them. */
7797 if (node->key[0] == ';')
7800 fprintf (fp, "\n%s\t", node->key);
7801 if (node->data != NULL)
7803 /* If the field's value contains evil characters,
7804 it must be stringified. */
7805 /* FIXME: This does not quite get it right. "7jk8f" is not a legal
7806 value for a value in a newpharse, according to doc/RCSFILES,
7807 because digits are not valid in an "id". We might do OK by
7808 always writing strings (enclosed in @@). Would be nice to
7809 explicitly mention this one way or another in doc/RCSFILES.
7810 A case where we are wrong in a much more clear-cut way is that
7811 we let through non-graphic characters such as whitespace and
7812 control characters. */
7814 if (node->type == RCSCMPFLD || strpbrk (node->data, "$,.:;@") == NULL)
7815 fputs (node->data, fp);
7819 expand_at_signs (node->data, (off_t) strlen (node->data), fp);
7824 /* desc, log and text fields should not be terminated with semicolon;
7825 all other fields should be. */
7826 if (! STREQ (node->key, "desc") &&
7827 ! STREQ (node->key, "log") &&
7828 ! STREQ (node->key, "text"))
7835 #ifdef PRESERVE_PERMISSIONS_SUPPORT
7837 /* Save a filename in a `hardlinks' RCS field. NODE->KEY will contain
7838 a full pathname, but currently only basenames are stored in the RCS
7839 node. Assume that the filename includes nasty characters and
7843 puthardlink_proc (node, vfp)
7847 FILE *fp = (FILE *) vfp;
7848 char *basename = strrchr (node->key, '/');
7850 if (basename == NULL)
7851 basename = node->key;
7857 (void) expand_at_signs (basename, strlen (basename), fp);
7865 /* Output the admin node for RCS into stream FP. */
7868 RCS_putadmin (rcs, fp)
7872 fprintf (fp, "%s\t%s;\n", RCSHEAD, rcs->head ? rcs->head : "");
7874 fprintf (fp, "%s\t%s;\n", RCSBRANCH, rcs->branch);
7876 fputs ("access", fp);
7880 s = xstrdup (rcs->access);
7881 for (p = strtok (s, " \n\t"); p != NULL; p = strtok (NULL, " \n\t"))
7882 fprintf (fp, "\n\t%s", p);
7887 fputs (RCSSYMBOLS, fp);
7888 /* If we haven't had to convert the symbols to a list yet, don't
7889 force a conversion now; just write out the string. */
7890 if (rcs->symbols == NULL && rcs->symbols_data != NULL)
7893 fputs (rcs->symbols_data, fp);
7896 walklist (RCS_symbols (rcs), putsymbol_proc, (void *) fp);
7899 fputs ("locks", fp);
7900 if (rcs->locks_data)
7901 fprintf (fp, "\t%s", rcs->locks_data);
7902 else if (rcs->locks)
7903 walklist (rcs->locks, putlock_proc, (void *) fp);
7904 if (rcs->strict_locks)
7905 fprintf (fp, "; strict");
7910 fprintf (fp, "comment\t@");
7911 expand_at_signs (rcs->comment, (off_t) strlen (rcs->comment), fp);
7914 if (rcs->expand && ! STREQ (rcs->expand, "kv"))
7915 fprintf (fp, "%s\t@%s@;\n", RCSEXPAND, rcs->expand);
7917 walklist (rcs->other, putrcsfield_proc, (void *) fp);
7929 /* Skip if no revision was supplied, or if it is outdated (cvs admin -o) */
7930 if (vers == NULL || vers->outdated)
7933 fprintf (fp, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches",
7935 RCSDATE, vers->date,
7936 "author", vers->author,
7937 "state", vers->state ? vers->state : "");
7939 if (vers->branches != NULL)
7941 start = vers->branches->list;
7942 for (bp = start->next; bp != start; bp = bp->next)
7943 fprintf (fp, "\n\t%s", bp->key);
7946 fprintf (fp, ";\nnext\t%s;", vers->next ? vers->next : "");
7948 walklist (vers->other_delta, putrcsfield_proc, fp);
7950 #ifdef PRESERVE_PERMISSIONS_SUPPORT
7951 if (vers->hardlinks)
7953 fprintf (fp, "\nhardlinks");
7954 walklist (vers->hardlinks, puthardlink_proc, fp);
7962 RCS_putdtree (rcs, rev, fp)
7973 /* Find the delta node for this revision. */
7974 p = findnode (rcs->versions, rev);
7978 "error parsing repository file %s, file may be corrupt.",
7982 versp = (RCSVers *) p->data;
7984 /* Print the delta node and recurse on its `next' node. This prints
7985 the trunk. If there are any branches printed on this revision,
7986 print those trunks as well. */
7987 putdelta (versp, fp);
7988 RCS_putdtree (rcs, versp->next, fp);
7989 if (versp->branches != NULL)
7991 branch = versp->branches->list;
7992 for (p = branch->next; p != branch; p = p->next)
7993 RCS_putdtree (rcs, p->key, fp);
7998 RCS_putdesc (rcs, fp)
8002 fprintf (fp, "\n\n%s\n@", RCSDESC);
8003 if (rcs->desc != NULL)
8005 off_t len = (off_t) strlen (rcs->desc);
8008 expand_at_signs (rcs->desc, len, fp);
8009 if (rcs->desc[len-1] != '\n')
8017 putdeltatext (fp, d)
8021 fprintf (fp, "\n\n%s\nlog\n@", d->version);
8024 int loglen = strlen (d->log);
8025 expand_at_signs (d->log, (off_t) loglen, fp);
8026 if (d->log[loglen-1] != '\n')
8031 walklist (d->other, putrcsfield_proc, fp);
8033 fputs ("\ntext\n@", fp);
8034 if (d->text != NULL)
8035 expand_at_signs (d->text, (off_t) d->len, fp);
8039 /* TODO: the whole mechanism for updating deltas is kludgey... more
8040 sensible would be to supply all the necessary info in a `newdeltatext'
8041 field for RCSVers nodes. -twp */
8043 /* Copy delta text nodes from FIN to FOUT. If NEWDTEXT is non-NULL, it
8044 is a new delta text node, and should be added to the tree at the
8045 node whose revision number is INSERTPT. (Note that trunk nodes are
8046 written in decreasing order, and branch nodes are written in
8047 increasing order.) */
8050 RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt)
8053 struct rcsbuffer *rcsbufin;
8055 Deltatext *newdtext;
8061 int insertbefore, found;
8070 /* Count the number of versions for which we have to do some
8071 special operation. */
8072 actions = walklist (rcs->versions, count_delta_actions, (void *) NULL);
8074 /* Make a note of whether NEWDTEXT should be inserted
8075 before or after its INSERTPT. */
8076 insertbefore = (newdtext != NULL && numdots (newdtext->version) == 1);
8078 while (actions != 0 || newdtext != NULL)
8082 dtext = RCS_getdeltatext (rcs, fin, rcsbufin);
8084 /* We shouldn't hit EOF here, because that would imply that
8085 some action was not taken, or that we could not insert
8088 error (1, 0, "internal error: EOF too early in RCS_copydeltas");
8090 found = (insertpt != NULL && STREQ (dtext->version, insertpt));
8091 if (found && insertbefore)
8093 putdeltatext (fout, newdtext);
8098 np = findnode (rcs->versions, dtext->version);
8099 dadmin = (RCSVers *) np->data;
8101 /* If this revision has been outdated, just skip it. */
8102 if (dadmin->outdated)
8104 freedeltatext (dtext);
8109 /* Update the change text for this delta. New change text
8110 data may come from cvs admin -m, cvs admin -o, or cvs ci. */
8111 if (dadmin->text != NULL)
8113 if (dadmin->text->log != NULL || dadmin->text->text != NULL)
8115 if (dadmin->text->log != NULL)
8118 dtext->log = dadmin->text->log;
8119 dadmin->text->log = NULL;
8121 if (dadmin->text->text != NULL)
8124 dtext->text = dadmin->text->text;
8125 dtext->len = dadmin->text->len;
8126 dadmin->text->text = NULL;
8129 putdeltatext (fout, dtext);
8130 freedeltatext (dtext);
8132 if (found && !insertbefore)
8134 putdeltatext (fout, newdtext);
8140 /* Copy the rest of the file directly, without bothering to
8141 interpret it. The caller will handle error checking by calling
8144 We just wrote a newline to the file, either in putdeltatext or
8145 in the caller. However, we may not have read the corresponding
8146 newline from the file, because rcsbuf_getkey returns as soon as
8147 it finds the end of the '@' string for the desc or text key.
8148 Therefore, we may read three newlines when we should really
8149 only write two, and we check for that case here. This is not
8150 an semantically important issue; we only do it to make our RCS
8151 files look traditional. */
8155 rcsbuf_get_buffered (rcsbufin, &bufrest, &buflen);
8158 if (bufrest[0] != '\n'
8159 || strncmp (bufrest, "\n\n\n", buflen < 3 ? buflen : 3) != 0)
8175 fwrite (bufrest, 1, buflen, fout);
8178 /* This bit isn't necessary when using mmap since the entire file
8179 * will already be available via the RCS buffer. Besides, the
8180 * mmap code doesn't always keep the file pointer up to date, so
8181 * this adds some data twice.
8183 while ((got = fread (buf, 1, sizeof buf, fin)) != 0)
8188 && strncmp (buf, "\n\n\n", nls) == 0)
8190 fwrite (buf + 1, 1, got - 1, fout);
8194 fwrite (buf, 1, got, fout);
8199 #endif /* HAVE_MMAP */
8202 /* A helper procedure for RCS_copydeltas. This is called via walklist
8203 to count the number of RCS revisions for which some special action
8207 count_delta_actions (np, ignore)
8213 dadmin = (RCSVers *) np->data;
8215 if (dadmin->outdated)
8218 if (dadmin->text != NULL
8219 && (dadmin->text->log != NULL || dadmin->text->text != NULL))
8228 * Clean up temporary files
8233 /* Note that the checks for existence_error are because we are
8234 called from a signal handler, so we don't know whether the
8235 files got created. */
8237 /* FIXME: Do not perform buffered I/O from an interrupt handler like
8238 this (via error). However, I'm leaving the error-calling code there
8239 in the hope that on the rare occasion the error call is actually made
8240 (e.g., a fluky I/O error or permissions problem prevents the deletion
8241 of a just-created file) reentrancy won't be an issue. */
8242 if (rcs_lockfile != NULL)
8244 char *tmp = rcs_lockfile;
8245 rcs_lockfile = NULL;
8246 if (rcs_lockfd >= 0)
8248 if (close (rcs_lockfd) != 0)
8249 error (0, errno, "error closing lock file %s", tmp);
8252 if (unlink_file (tmp) < 0
8253 && !existence_error (errno))
8254 error (0, errno, "cannot remove %s", tmp);
8258 /* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style
8259 locking on the specified RCSFILE: for a file called `foo,v', open
8260 for writing a file called `,foo,'.
8262 Note that we what do here is quite different from what RCS does.
8263 RCS creates the ,foo, file before it reads the RCS file (if it
8264 knows that it will be writing later), so that it actually serves as
8265 a lock. We don't; instead we rely on CVS writelocks. This means
8266 that if someone is running RCS on the file at the same time they
8267 are running CVS on it, they might lose (we read the file,
8268 then RCS writes it, then we write it, clobbering the
8269 changes made by RCS). I believe the current sentiment about this
8270 is "well, don't do that".
8272 A concern has been expressed about whether adopting the RCS
8273 strategy would slow us down. I don't think so, since we need to
8274 write the ,foo, file anyway (unless perhaps if O_EXCL is slower or
8277 These do not perform quite the same function as the RCS -l option
8278 for locking files: they are intended to prevent competing RCS
8279 processes from stomping all over each other's laundry. Hence,
8280 they are `internal' locking functions.
8282 If there is an error, give a fatal error; if we return we always
8283 return a non-NULL value. */
8286 rcs_internal_lockfile (rcsfile)
8291 static int first_call = 1;
8296 /* clean up if we get a signal */
8298 (void) SIG_register (SIGABRT, rcs_cleanup);
8301 (void) SIG_register (SIGHUP, rcs_cleanup);
8304 (void) SIG_register (SIGINT, rcs_cleanup);
8307 (void) SIG_register (SIGQUIT, rcs_cleanup);
8310 (void) SIG_register (SIGPIPE, rcs_cleanup);
8313 (void) SIG_register (SIGTERM, rcs_cleanup);
8317 /* Get the lock file name: `,file,' for RCS file `file,v'. */
8318 assert (rcs_lockfile == NULL);
8319 assert (rcs_lockfd < 0);
8320 rcs_lockfile = rcs_lockfilename (rcsfile);
8322 /* Use the existing RCS file mode, or read-only if this is a new
8323 file. (Really, this is a lie -- if this is a new file,
8324 RCS_checkin uses the permissions from the working copy. For
8325 actually creating the file, we use 0444 as a safe default mode.) */
8326 if (stat (rcsfile, &rstat) < 0)
8328 if (existence_error (errno))
8329 rstat.st_mode = S_IRUSR | S_IRGRP | S_IROTH;
8331 error (1, errno, "cannot stat %s", rcsfile);
8334 /* Try to open exclusively. POSIX.1 guarantees that O_EXCL|O_CREAT
8335 guarantees an exclusive open. According to the RCS source, with
8336 NFS v2 we must also throw in O_TRUNC and use an open mask that makes
8337 the file unwriteable. For extensive justification, see the comments for
8338 rcswriteopen() in rcsedit.c, in RCS 5.7. This is kind of pointless
8339 in the CVS case; see comment at the start of this file concerning
8340 general ,foo, file strategy.
8342 There is some sentiment that with NFSv3 and such, that one can
8343 rely on O_EXCL these days. This might be true for unix (I
8344 don't really know), but I am still pretty skeptical in the case
8345 of the non-unix systems. */
8346 rcs_lockfd = open (rcs_lockfile,
8347 OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
8348 S_IRUSR | S_IRGRP | S_IROTH);
8352 error (1, errno, "could not open lock file `%s'", rcs_lockfile);
8355 /* Force the file permissions, and return a stream object. */
8356 /* Because we change the modes later, we don't worry about
8357 this in the non-HAVE_FCHMOD case. */
8359 if (fchmod (rcs_lockfd, rstat.st_mode) < 0)
8360 error (1, errno, "cannot change mode for %s", rcs_lockfile);
8362 fp = fdopen (rcs_lockfd, FOPEN_BINARY_WRITE);
8364 error (1, errno, "cannot fdopen %s", rcs_lockfile);
8370 rcs_internal_unlockfile (fp, rcsfile)
8374 assert (rcs_lockfile != NULL);
8375 assert (rcs_lockfd >= 0);
8377 /* Abort if we could not write everything successfully to LOCKFILE.
8378 This is not a great error-handling mechanism, but should prevent
8379 corrupting the repository. */
8382 /* Using errno here may well be misleanding since the most recent
8383 call that set errno may not have anything whatsoever to do with
8384 the error that set the flag, but it's better than nothing. The
8385 real solution is to check each call to fprintf rather than waiting
8386 until the end like this. */
8387 error (1, errno, "error writing to lock file %s", rcs_lockfile);
8388 if (fclose (fp) == EOF)
8389 error (1, errno, "error closing lock file %s", rcs_lockfile);
8392 rename_file (rcs_lockfile, rcsfile);
8395 /* Use a temporary to make sure there's no interval
8396 (after rcs_lockfile has been freed but before it's set to NULL)
8397 during which the signal handler's use of rcs_lockfile would
8398 reference freed memory. */
8399 char *tmp = rcs_lockfile;
8400 rcs_lockfile = NULL;
8406 rcs_lockfilename (rcsfile)
8409 char *lockfile, *lockp;
8410 char *rcsbase, *rcsp, *rcsend;
8413 /* Create the lockfile name. */
8414 rcslen = strlen (rcsfile);
8415 lockfile = (char *) xmalloc (rcslen + 10);
8416 rcsbase = last_component (rcsfile);
8417 rcsend = rcsfile + rcslen - sizeof(RCSEXT);
8418 for (lockp = lockfile, rcsp = rcsfile; rcsp < rcsbase; ++rcsp)
8421 while (rcsp <= rcsend)
8429 /* Rewrite an RCS file. The basic idea here is that the caller should
8430 first call RCS_reparsercsfile, then munge the data structures as
8431 desired (via RCS_delete_revs, RCS_settag, &c), then call RCS_rewrite. */
8434 RCS_rewrite (rcs, newdtext, insertpt)
8436 Deltatext *newdtext;
8440 struct rcsbuffer rcsbufin;
8445 /* Make sure we're operating on an actual file and not a symlink. */
8446 resolve_symlink (&(rcs->path));
8448 fout = rcs_internal_lockfile (rcs->path);
8450 RCS_putadmin (rcs, fout);
8451 RCS_putdtree (rcs, rcs->head, fout);
8452 RCS_putdesc (rcs, fout);
8454 /* Open the original RCS file and seek to the first delta text. */
8455 rcsbuf_cache_open (rcs, rcs->delta_pos, &fin, &rcsbufin);
8457 /* Update delta_pos to the current position in the output file.
8458 Do NOT move these statements: they must be done after fin has
8459 been positioned at the old delta_pos, but before any delta
8460 texts have been written to fout.
8462 rcs->delta_pos = ftell (fout);
8463 if (rcs->delta_pos == -1)
8464 error (1, errno, "cannot ftell in RCS file %s", rcs->path);
8466 RCS_copydeltas (rcs, fin, &rcsbufin, fout, newdtext, insertpt);
8468 /* We don't want to call rcsbuf_cache here, since we're about to
8470 rcsbuf_close (&rcsbufin);
8472 /* The only case in which using errno here would be meaningful
8473 is if we happen to have left errno unmolested since the call
8474 which produced the error (e.g. fread). That is pretty
8475 fragile even if it happens to sometimes be true. The real
8476 solution is to make sure that all the code which reads
8477 from fin checks for errors itself (some does, some doesn't). */
8478 error (0, 0, "warning: ferror set while rewriting RCS file `%s'", rcs->path);
8479 if (fclose (fin) < 0)
8480 error (0, errno, "warning: closing RCS file `%s'", rcs->path);
8482 rcs_internal_unlockfile (fout, rcs->path);
8485 /* Abandon changes to an RCS file. */
8491 free_rcsnode_contents (rcs);
8492 rcs->symbols_data = NULL;
8495 rcs->locks_data = NULL;
8496 rcs->comment = NULL;
8498 rcs->flags |= PARTIAL;
8502 * For a given file with full pathname PATH and revision number REV,
8503 * produce a file label suitable for passing to diff. The default
8504 * file label as used by RCS 5.7 looks like this:
8506 * FILENAME <tab> YYYY/MM/DD <sp> HH:MM:SS <tab> REVNUM
8508 * The date and time used are the revision's last checkin date and time.
8509 * If REV is NULL, use the working copy's mtime instead.
8511 * /dev/null is not statted but assumed to have been created on the Epoch.
8512 * At least using the POSIX.2 definition of patch, this should cause creation
8513 * of files on platforms such as Windoze where the null IO device isn't named
8514 * /dev/null to be parsed by patch properly.
8517 make_file_label (path, rev, rcs)
8522 char datebuf[MAXDATELEN + 1];
8525 label = (char *) xmalloc (strlen (path)
8526 + (rev == NULL ? 0 : strlen (rev) + 1)
8532 char date[MAXDATELEN + 1];
8533 /* revs cannot be attached to /dev/null ... duh. */
8534 assert (strcmp(DEVNULL, path));
8535 RCS_getrevtime (rcs, rev, datebuf, 0);
8536 (void) date_to_internet (date, datebuf);
8537 (void) sprintf (label, "-L%s\t%s\t%s", path, date, rev);
8542 struct tm *wm = NULL;
8544 if (strcmp(DEVNULL, path))
8546 char *file = last_component (path);
8547 if (CVS_STAT (file, &sb) < 0)
8548 error (0, 1, "could not get info for `%s'", path);
8550 wm = gmtime (&sb.st_mtime);
8560 (void) tm_to_internet (datebuf, wm);
8561 (void) sprintf (label, "-L%s\t%s", path, datebuf);