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
15 /* These need to be source after cvs.h or HAVE_MMAP won't be set... */
17 # include <sys/mman.h>
18 # ifndef HAVE_GETPAGESIZE
19 # include "getpagesize.h"
22 # define MAP_FAILED NULL
26 int preserve_perms = 0;
28 /* The RCS -k options, and a set of enums that must match the array.
29 These come first so that we can use enum kflag in function
31 static const char *const kflags[] =
32 {"kv", "kvl", "k", "v", "o", "b", (char *) NULL};
33 enum kflag { KFLAG_KV = 0, KFLAG_KVL, KFLAG_K, KFLAG_V, KFLAG_O, KFLAG_B };
35 /* A structure we use to buffer the contents of an RCS file. The
36 various fields are only referenced directly by the rcsbuf_*
37 functions. We declare the struct here so that we can allocate it
38 on the stack, rather than in memory. */
42 /* Points to the current position in the buffer. */
44 /* Points just after the last valid character in the buffer. */
48 /* The name of the file, used for error messages. */
50 /* The starting file position of the data in the buffer. */
52 /* The length of the value. */
54 /* Whether the value contains an '@' string. If so, we can not
55 compress whitespace characters. */
57 /* The number of embedded '@' characters in an '@' string. If
58 this is non-zero, we must search the string for pairs of '@'
59 and convert them to a single '@'. */
63 static RCSNode *RCS_parsercsfile_i (FILE * fp, const char *rcsfile);
64 static char *RCS_getdatebranch (RCSNode * rcs, const char *date,
66 static void rcsbuf_open (struct rcsbuffer *, FILE *fp,
67 const char *filename, unsigned long pos);
68 static void rcsbuf_close (struct rcsbuffer *);
69 static int rcsbuf_getkey (struct rcsbuffer *, char **keyp,
71 static int rcsbuf_getrevnum (struct rcsbuffer *, char **revp);
72 static char *rcsbuf_fill (struct rcsbuffer *, char *ptr, char **keyp,
74 static int rcsbuf_valcmp (struct rcsbuffer *);
75 static char *rcsbuf_valcopy (struct rcsbuffer *, char *val, int polish,
77 static void rcsbuf_valpolish (struct rcsbuffer *, char *val, int polish,
79 static void rcsbuf_valpolish_internal (struct rcsbuffer *, char *to,
80 const char *from, size_t *lenp);
81 static off_t rcsbuf_ftello (struct rcsbuffer *);
82 static void rcsbuf_get_buffered (struct rcsbuffer *, char **datap,
84 static void rcsbuf_cache (RCSNode *, struct rcsbuffer *);
85 static void rcsbuf_cache_close (void);
86 static void rcsbuf_cache_open (RCSNode *, off_t, FILE **,
88 static int checkmagic_proc (Node *p, void *closure);
89 static void do_branches (List * list, char *val);
90 static void do_symbols (List * list, char *val);
91 static void do_locks (List * list, char *val);
92 static void free_rcsnode_contents (RCSNode *);
93 static void free_rcsvers_contents (RCSVers *);
94 static void rcsvers_delproc (Node * p);
95 static char *translate_symtag (RCSNode *, const char *);
96 static char *RCS_addbranch (RCSNode *, const char *);
97 static char *truncate_revnum_in_place (char *);
98 static char *truncate_revnum (const char *);
99 static char *printable_date (const char *);
100 static char *escape_keyword_value (const char *, int *);
101 static void expand_keywords (RCSNode *, RCSVers *, const char *,
102 const char *, size_t, enum kflag, char *,
103 size_t, char **, size_t *);
104 static void cmp_file_buffer (void *, const char *, size_t);
106 /* Routines for reading, parsing and writing RCS files. */
107 static RCSVers *getdelta (struct rcsbuffer *, char *, char **,
109 static Deltatext *RCS_getdeltatext (RCSNode *, FILE *,
111 static void freedeltatext (Deltatext *);
113 static void RCS_putadmin (RCSNode *, FILE *);
114 static void RCS_putdtree (RCSNode *, char *, FILE *);
115 static void RCS_putdesc (RCSNode *, FILE *);
116 static void putdelta (RCSVers *, FILE *);
117 static int putrcsfield_proc (Node *, void *);
118 static int putsymbol_proc (Node *, void *);
119 static void RCS_copydeltas (RCSNode *, FILE *, struct rcsbuffer *,
120 FILE *, Deltatext *, char *);
121 static int count_delta_actions (Node *, void *);
122 static void putdeltatext (FILE *, Deltatext *);
124 static FILE *rcs_internal_lockfile (char *);
125 static void rcs_internal_unlockfile (FILE *, char *);
126 static char *rcs_lockfilename (const char *);
128 /* The RCS file reading functions are called a lot, and they do some
129 string comparisons. This macro speeds things up a bit by skipping
130 the function call when the first characters are different. It
131 evaluates its arguments multiple times. */
132 #define STREQ(a, b) (*(char *)(a) == *(char *)(b) && strcmp ((a), (b)) == 0)
134 static char * getfullCVSname (char *, char **);
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 = NULL;
166 static int rcs_lockfd = -1;
172 * locate_rcs ( const char* file, const char *repository , int *inattic )
174 * Find an RCS file in the repository, case insensitively when the cased name
175 * doesn't exist, we are running as the server, and a client has asked us to
178 * Most parts of CVS will want to rely instead on RCS_parse which calls this
179 * function and is called by recurse.c which then puts the result in useful
180 * places like the rcs field of struct file_info.
184 * repository the repository (including the directory)
185 * file the filename within that directory (without RCSEXT).
186 * inattic NULL or a pointer to the output boolean
190 * inattic If this input was non-null, the destination will be
191 * set to true if the file was found in the attic or
192 * false if not. If no RCS file is found, this value
197 * a newly-malloc'd array containing the absolute pathname of the RCS
198 * file that was found or NULL when none was found.
202 * errno can be set by the return value of the final call to
203 * locate_file_in_dir(). This should resolve to the system's existence error
204 * value (sometime ENOENT) if the Attic directory did not exist and ENOENT if
205 * the Attic was found but no matching files were found in the Attic or its
209 locate_rcs (const char *repository, const char *file, int *inattic)
213 /* First, try to find the file as cased. */
214 retval = xmalloc (strlen (repository)
219 sprintf (retval, "%s/%s%s", repository, file, RCSEXT);
220 if (isreadable (retval))
226 sprintf (retval, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT);
227 if (isreadable (retval))
240 /* A few generic thoughts on error handling, in particular the
241 printing of unexpected characters that we find in the RCS file
242 (that is, why we use '\x%x' rather than %c or some such).
244 * Avoiding %c means we don't have to worry about what is printable
245 and other such stuff. In error handling, often better to keep it
248 * Hex rather than decimal or octal because character set standards
251 * Saying "character 0x%x" might make it sound like we are printing
252 a file offset. So we use '\x%x'.
254 * Would be nice to print the offset within the file, but I can
255 imagine various portability hassles (in particular, whether
256 unsigned long is always big enough to hold file offsets). */
258 /* Parse an rcsfile given a user file name and a repository. If there is
259 an error, we print an error message and return NULL. If the file
260 does not exist, we return NULL without printing anything (I'm not
261 sure this allows the caller to do anything reasonable, but it is
262 the current behavior). */
264 RCS_parse (const char *file, const char *repos)
268 RCSNode *retval = NULL;
272 /* We're creating a new RCSNode, so there is no hope of finding it
274 rcsbuf_cache_close ();
276 if ((rcsfile = locate_rcs (repos, file, &inattic)) == NULL)
278 /* Handle the error cases */
280 else if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) != NULL)
282 rcs = RCS_parsercsfile_i(fp, rcsfile);
287 rcs->flags |= INATTIC;
293 else if (! existence_error (errno))
296 error (0, errno, "cannot open %s", rcsfile);
303 * Parse a specific rcsfile.
306 RCS_parsercsfile (const char *rcsfile)
311 /* We're creating a new RCSNode, so there is no hope of finding it
313 rcsbuf_cache_close ();
315 /* open the rcsfile */
316 if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) == NULL)
318 error (0, errno, "Couldn't open rcs file `%s'", rcsfile);
322 rcs = RCS_parsercsfile_i (fp, rcsfile);
332 RCS_parsercsfile_i (FILE *fp, const char *rcsfile)
335 struct rcsbuffer rcsbuf;
339 rdata = (RCSNode *) xmalloc (sizeof (RCSNode));
340 memset ((char *)rdata, 0, sizeof (RCSNode));
342 rdata->path = xstrdup (rcsfile);
344 /* Process HEAD, BRANCH, and EXPAND keywords from the RCS header.
346 Most cvs operations on the main branch don't need any more
347 information. Those that do call RCS_reparsercsfile to parse
348 the rest of the header and the deltas. */
350 rcsbuf_open (&rcsbuf, fp, rcsfile, 0);
352 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
354 if (STREQ (key, RCSDESC))
357 if (STREQ (RCSHEAD, key) && value != NULL)
358 rdata->head = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *)NULL);
360 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
362 if (STREQ (key, RCSDESC))
365 if (STREQ (RCSBRANCH, key) && value != NULL)
369 rdata->branch = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *)NULL);
370 if ((numdots (rdata->branch) & 1) != 0)
372 /* turn it into a branch if it's a revision */
373 cp = strrchr (rdata->branch, '.');
378 /* Look ahead for expand, stopping when we see desc or a revision
384 if (STREQ (RCSEXPAND, key))
386 rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0,
392 (isdigit ((unsigned char)*cp) || *cp == '.') && *cp != '\0';
398 if (STREQ (RCSDESC, key))
401 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
405 rdata->flags |= PARTIAL;
407 rcsbuf_cache (rdata, &rcsbuf);
412 error (0, 0, "`%s' does not appear to be a valid rcs file",
414 rcsbuf_close (&rcsbuf);
415 freercsnode (&rdata);
422 /* Do the real work of parsing an RCS file.
424 On error, die with a fatal error; if it returns at all it was successful.
426 If PFP is NULL, close the file when done. Otherwise, leave it open
427 and store the FILE * in *PFP. */
429 RCS_reparsercsfile (RCSNode *rdata, FILE **pfp, struct rcsbuffer *rcsbufp)
433 struct rcsbuffer rcsbuf;
440 assert (rdata != NULL);
441 rcsfile = rdata->path;
443 rcsbuf_cache_open (rdata, 0, &fp, &rcsbuf);
446 /* This probably shouldn't be done until later: if a file has an
447 empty revision tree (which is permissible), rdata->versions
448 should be NULL. -twp */
449 rdata->versions = getlist ();
452 * process all the special header information, break out when we get to
453 * the first revision delta
458 /* get the next key/value pair */
461 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
463 error (1, 0, "`%s' does not appear to be a valid rcs file",
470 /* Skip head, branch and expand tags; we already have them. */
471 if (STREQ (key, RCSHEAD)
472 || STREQ (key, RCSBRANCH)
473 || STREQ (key, RCSEXPAND))
478 if (STREQ (key, "access"))
482 /* We pass the POLISH parameter as 1 because
483 RCS_addaccess expects nothing but spaces. FIXME:
484 It would be easy and more efficient to change
486 rdata->access = rcsbuf_valcopy (&rcsbuf, value, 1,
492 /* We always save lock information, so that we can handle
493 -kkvl correctly when checking out a file. */
494 if (STREQ (key, "locks"))
497 rdata->locks_data = rcsbuf_valcopy (&rcsbuf, value, 0,
499 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
501 error (1, 0, "premature end of file reading %s", rcsfile);
503 if (STREQ (key, "strict") && value == NULL)
505 rdata->strict_locks = 1;
512 if (STREQ (RCSSYMBOLS, key))
515 rdata->symbols_data = rcsbuf_valcopy (&rcsbuf, value, 0,
521 * check key for '.''s and digits (probably a rev) if it is a
522 * revision or `desc', we are done with the headers and are down to the
523 * revision deltas, so we break out of the loop
526 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
529 /* Note that when comparing with RCSDATE, we are not massaging
530 VALUE from the string found in the RCS file. This is OK
531 since we know exactly what to expect. */
532 if (*cp == '\0' && strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) == 0)
535 if (STREQ (key, RCSDESC))
538 if (STREQ (key, "comment"))
540 rdata->comment = rcsbuf_valcopy (&rcsbuf, value, 0,
544 if (rdata->other == NULL)
545 rdata->other = getlist ();
547 kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
548 kv->key = xstrdup (key);
549 kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
551 if (addnode (rdata->other, kv) != 0)
553 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
558 /* if we haven't grabbed it yet, we didn't want it */
561 /* We got out of the loop, so we have the first part of the first
562 revision delta in KEY (the revision) and VALUE (the date key
563 and its value). This is what getdelta expects to receive. */
565 while ((vnode = getdelta (&rcsbuf, rcsfile, &key, &value)) != NULL)
570 q->delproc = rcsvers_delproc;
572 q->key = vnode->version;
574 /* add the nodes to the list */
575 if (addnode (rdata->versions, q) != 0)
578 purify_printf("WARNING: Adding duplicate version: %s (%s)\n",
585 /* Here KEY and VALUE are whatever caused getdelta to return NULL. */
587 if (STREQ (key, RCSDESC))
589 if (rdata->desc != NULL)
592 "warning: duplicate key `%s' in RCS file `%s'",
596 rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
599 rdata->delta_pos = rcsbuf_ftello (&rcsbuf);
602 rcsbuf_cache (rdata, &rcsbuf);
608 rdata->flags &= ~PARTIAL;
611 /* Move RCS into or out of the Attic, depending on TOATTIC. If the
612 file is already in the desired place, return without doing
613 anything. At some point may want to think about how this relates
614 to RCS_rewrite but that is a bit hairy (if one wants renames to be
615 atomic, or that kind of thing). If there is an error, print a message
616 and return 1. On success, return 0. */
618 RCS_setattic (RCSNode *rcs, int toattic)
624 /* Some systems aren't going to let us rename an open file. */
625 rcsbuf_cache_close ();
627 /* Could make the pathname computations in this file, and probably
628 in other parts of rcs.c too, easier if the REPOS and FILE
629 arguments to RCS_parse got stashed in the RCSNode. */
635 if (rcs->flags & INATTIC)
638 /* Example: rcs->path is "/foo/bar/baz,v". */
639 newpath = xmalloc (strlen (rcs->path) + sizeof CVSATTIC + 5);
640 p = last_component (rcs->path);
641 strncpy (newpath, rcs->path, p - rcs->path);
642 strcpy (newpath + (p - rcs->path), CVSATTIC);
644 /* Create the Attic directory if it doesn't exist. */
645 omask = umask (cvsumask);
646 if (CVS_MKDIR (newpath, 0777) < 0 && errno != EEXIST)
647 error (0, errno, "cannot make directory %s", newpath);
648 (void) umask (omask);
650 strcat (newpath, "/");
653 if (CVS_RENAME (rcs->path, newpath) < 0)
655 int save_errno = errno;
657 /* The checks for isreadable look awfully fishy, but
658 I'm going to leave them here for now until I
659 can think harder about whether they take care of
660 some cases which should be handled somehow. */
662 if (isreadable (rcs->path) || !isreadable (newpath))
664 error (0, save_errno, "cannot rename %s to %s",
673 if (!(rcs->flags & INATTIC))
676 newpath = xmalloc (strlen (rcs->path));
678 /* Example: rcs->path is "/foo/bar/Attic/baz,v". */
679 p = last_component (rcs->path);
680 strncpy (newpath, rcs->path, p - rcs->path - 1);
681 newpath[p - rcs->path - 1] = '\0';
682 q = newpath + (p - rcs->path - 1) - (sizeof CVSATTIC - 1);
683 assert (strncmp (q, CVSATTIC, sizeof CVSATTIC - 1) == 0);
686 if (CVS_RENAME (rcs->path, newpath) < 0)
688 error (0, errno, "failed to move `%s' out of the attic",
702 * Fully parse the RCS file. Store all keyword/value pairs, fetch the
703 * log messages for each revision, and fetch add and delete counts for
704 * each revision (we could fetch the entire text for each revision,
705 * but the only caller, log_fileproc, doesn't need that information,
706 * so we don't waste the memory required to store it). The add and
707 * delete counts are stored on the OTHER field of the RCSVERSNODE
708 * structure, under the names ";add" and ";delete", so that we don't
709 * waste the memory space of extra fields in RCSVERSNODE for code
710 * which doesn't need this information.
714 RCS_fully_parse (RCSNode *rcs)
717 struct rcsbuffer rcsbuf;
719 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
727 /* Rather than try to keep track of how much information we
728 have read, just read to the end of the file. */
729 if (!rcsbuf_getrevnum (&rcsbuf, &key))
732 vers = findnode (rcs->versions, key);
735 "mismatch in rcs file %s between deltas and deltatexts (%s)",
740 while (rcsbuf_getkey (&rcsbuf, &key, &value))
742 if (!STREQ (key, "text"))
746 if (vnode->other == NULL)
747 vnode->other = getlist ();
749 kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
750 kv->key = xstrdup (key);
751 kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
753 if (addnode (vnode->other, kv) != 0)
757 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
758 key, vnode->version, rcs->path);
765 if (!STREQ (vnode->version, rcs->head))
767 unsigned long add, del;
771 /* This is a change text. Store the add and delete
780 rcsbuf_valpolish (&rcsbuf, value, 0, &vallen);
782 while (cp < value + vallen)
788 if (op != 'a' && op != 'd')
790 unrecognized operation '\\x%x' in %s",
792 (void) strtoul (cp, (char **) &cp, 10);
794 error (1, 0, "space expected in %s revision %s",
795 rcs->path, vnode->version);
796 count = strtoul (cp, (char **) &cp, 10);
798 error (1, 0, "linefeed expected in %s revision %s",
799 rcs->path, vnode->version);
810 else if (cp == value + vallen)
814 premature end of value in %s revision %s",
815 rcs->path, vnode->version);
825 sprintf (buf, "%lu", add);
828 kv->key = xstrdup (";add");
829 kv->data = xstrdup (buf);
830 if (addnode (vnode->other, kv) != 0)
834 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
835 key, vnode->version, rcs->path);
839 sprintf (buf, "%lu", del);
842 kv->key = xstrdup (";delete");
843 kv->data = xstrdup (buf);
844 if (addnode (vnode->other, kv) != 0)
848 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
849 key, vnode->version, rcs->path);
854 /* We have found the "text" key which ends the data for
855 this revision. Break out of the loop and go on to the
861 rcsbuf_cache (rcs, &rcsbuf);
867 * freercsnode - free up the info for an RCSNode
870 freercsnode (RCSNode **rnodep)
872 if (rnodep == NULL || *rnodep == NULL)
875 ((*rnodep)->refcount)--;
876 if ((*rnodep)->refcount != 0)
878 *rnodep = (RCSNode *) NULL;
881 free ((*rnodep)->path);
882 if ((*rnodep)->head != (char *) NULL)
883 free ((*rnodep)->head);
884 if ((*rnodep)->branch != (char *) NULL)
885 free ((*rnodep)->branch);
886 free_rcsnode_contents (*rnodep);
887 free ((char *) *rnodep);
888 *rnodep = (RCSNode *) NULL;
892 * free_rcsnode_contents - free up the contents of an RCSNode without
893 * freeing the node itself, or the file name, or the head, or the
894 * path. This returns the RCSNode to the state it is in immediately
895 * after a call to RCS_parse.
898 free_rcsnode_contents (RCSNode *rnode)
900 dellist (&rnode->versions);
901 if (rnode->symbols != (List *) NULL)
902 dellist (&rnode->symbols);
903 if (rnode->symbols_data != (char *) NULL)
904 free (rnode->symbols_data);
905 if (rnode->expand != NULL)
906 free (rnode->expand);
907 if (rnode->other != (List *) NULL)
908 dellist (&rnode->other);
909 if (rnode->access != NULL)
910 free (rnode->access);
911 if (rnode->locks_data != NULL)
912 free (rnode->locks_data);
913 if (rnode->locks != (List *) NULL)
914 dellist (&rnode->locks);
915 if (rnode->comment != NULL)
916 free (rnode->comment);
917 if (rnode->desc != NULL)
921 /* free_rcsvers_contents -- free up the contents of an RCSVers node,
922 but also free the pointer to the node itself. */
923 /* Note: The `hardlinks' list is *not* freed, since it is merely a
924 pointer into the `hardlist' structure (defined in hardlink.c), and
925 that structure is freed elsewhere in the program. */
928 free_rcsvers_contents (RCSVers *rnode)
930 if (rnode->branches != (List *) NULL)
931 dellist (&rnode->branches);
932 if (rnode->date != (char *) NULL)
934 if (rnode->next != (char *) NULL)
936 if (rnode->author != (char *) NULL)
937 free (rnode->author);
938 if (rnode->state != (char *) NULL)
940 if (rnode->other != (List *) NULL)
941 dellist (&rnode->other);
942 if (rnode->other_delta != NULL)
943 dellist (&rnode->other_delta);
944 if (rnode->text != NULL)
945 freedeltatext (rnode->text);
946 free ((char *) rnode);
950 * rcsvers_delproc - free up an RCSVers type node
953 rcsvers_delproc (Node *p)
955 free_rcsvers_contents (p->data);
958 /* These functions retrieve keys and values from an RCS file using a
959 buffer. We use this somewhat complex approach because it turns out
960 that for many common operations, CVS spends most of its time
961 reading keys, so it's worth doing some fairly hairy optimization. */
963 /* The number of bytes we try to read each time we need more data. */
965 #define RCSBUF_BUFSIZE (8192)
967 /* The buffer we use to store data. This grows as needed. */
969 static char *rcsbuf_buffer = NULL;
970 static size_t rcsbuf_buffer_size = 0;
972 /* Whether rcsbuf_buffer is in use. This is used as a sanity check. */
974 static int rcsbuf_inuse;
976 /* Set up to start gathering keys and values from an RCS file. This
977 initializes RCSBUF. */
980 rcsbuf_open (struct rcsbuffer *rcsbuf, FILE *fp, const char *filename, long unsigned int pos)
983 error (1, 0, "rcsbuf_open: internal error");
988 /* When we have mmap, it is much more efficient to let the system do the
989 * buffering and caching for us
994 if ( fstat (fileno(fp), &fs) < 0 )
995 error ( 1, errno, "Could not stat RCS archive %s for mapping", filename );
999 size_t ps = getpagesize ();
1000 mmap_off = ( pos / ps ) * ps;
1003 /* Map private here since this particular buffer is read only */
1004 rcsbuf_buffer = mmap ( NULL, fs.st_size - mmap_off,
1005 PROT_READ | PROT_WRITE,
1006 MAP_PRIVATE, fileno(fp), mmap_off );
1007 if ( rcsbuf_buffer == NULL || rcsbuf_buffer == MAP_FAILED )
1008 error ( 1, errno, "Could not map memory to RCS archive %s", filename );
1010 rcsbuf_buffer_size = fs.st_size - mmap_off;
1011 rcsbuf->ptr = rcsbuf_buffer + pos - mmap_off;
1012 rcsbuf->ptrend = rcsbuf_buffer + fs.st_size - mmap_off;
1013 rcsbuf->pos = mmap_off;
1015 #else /* HAVE_MMAP */
1016 if (rcsbuf_buffer_size < RCSBUF_BUFSIZE)
1017 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, RCSBUF_BUFSIZE);
1019 rcsbuf->ptr = rcsbuf_buffer;
1020 rcsbuf->ptrend = rcsbuf_buffer;
1022 #endif /* HAVE_MMAP */
1024 rcsbuf->filename = filename;
1026 rcsbuf->at_string = 0;
1027 rcsbuf->embedded_at = 0;
1030 /* Stop gathering keys from an RCS file. */
1033 rcsbuf_close (struct rcsbuffer *rcsbuf)
1036 error (1, 0, "rcsbuf_close: internal error");
1038 munmap ( rcsbuf_buffer, rcsbuf_buffer_size );
1043 /* Read a key/value pair from an RCS file. This sets *KEYP to point
1044 to the key, and *VALUEP to point to the value. A missing or empty
1045 value is indicated by setting *VALUEP to NULL.
1047 This function returns 1 on success, or 0 on EOF. If there is an
1048 error reading the file, or an EOF in an unexpected location, it
1049 gives a fatal error.
1051 This sets *KEYP and *VALUEP to point to storage managed by
1052 rcsbuf_getkey. Moreover, *VALUEP has not been massaged from the
1053 RCS format: it may contain embedded whitespace and embedded '@'
1054 characters. Call rcsbuf_valcopy or rcsbuf_valpolish to do
1055 appropriate massaging. */
1057 /* Note that the extreme hair in rcsbuf_getkey is because profiling
1058 statistics show that it was worth it. */
1061 rcsbuf_getkey (struct rcsbuffer *rcsbuf, char **keyp, char **valp)
1063 register const char * const my_spacetab = spacetab;
1064 register char *ptr, *ptrend;
1067 #define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
1070 rcsbuf->at_string = 0;
1071 rcsbuf->embedded_at = 0;
1074 ptrend = rcsbuf->ptrend;
1077 assert (ptr >= rcsbuf_buffer && ptr <= rcsbuf_buffer + rcsbuf_buffer_size);
1078 assert (ptrend >= rcsbuf_buffer && ptrend <= rcsbuf_buffer + rcsbuf_buffer_size);
1081 /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
1082 buffer, move back to the start of the buffer. This keeps the
1083 buffer from growing indefinitely. */
1084 if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
1090 /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
1091 at a time, so we can't have more bytes than that past PTR. */
1092 assert (len <= RCSBUF_BUFSIZE);
1094 /* Update the POS field, which holds the file offset of the
1095 first byte in the RCSBUF_BUFFER buffer. */
1096 rcsbuf->pos += ptr - rcsbuf_buffer;
1098 memcpy (rcsbuf_buffer, ptr, len);
1099 ptr = rcsbuf_buffer;
1101 rcsbuf->ptrend = ptrend;
1103 #endif /* HAVE_MMAP */
1105 /* Skip leading whitespace. */
1111 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
1114 ptrend = rcsbuf->ptrend;
1118 if (! my_whitespace (c))
1124 /* We've found the start of the key. */
1135 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
1137 error (1, 0, "EOF in key in RCS file %s",
1139 ptrend = rcsbuf->ptrend;
1142 if (c == ';' || my_whitespace (c))
1147 /* Here *KEYP points to the key in the buffer, C is the character
1148 we found at the of the key, and PTR points to the location in
1149 the buffer where we found C. We must set *PTR to \0 in order
1150 to terminate the key. If the key ended with ';', then there is
1163 /* C must be whitespace. Skip whitespace between the key and the
1164 value. If we find ';' now, there is no value. */
1170 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
1172 error (1, 0, "EOF while looking for value in RCS file %s",
1174 ptrend = rcsbuf->ptrend;
1180 rcsbuf->ptr = ptr + 1;
1183 if (! my_whitespace (c))
1188 /* Now PTR points to the start of the value, and C is the first
1189 character of the value. */
1198 /* Optimize the common case of a value composed of a single
1201 rcsbuf->at_string = 1;
1209 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1211 /* Note that we pass PTREND as the PTR value to
1212 rcsbuf_fill, so that we will wind up setting PTR to
1213 the location corresponding to the old PTREND, so
1214 that we don't search the same bytes again. */
1215 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1218 "EOF while looking for end of string in RCS file %s",
1220 ptrend = rcsbuf->ptrend;
1223 /* Handle the special case of an '@' right at the end of
1225 if (pat + 1 >= ptrend)
1227 /* Note that we pass PAT, not PTR, here. */
1228 pat = rcsbuf_fill (rcsbuf, pat, keyp, valp);
1231 /* EOF here is OK; it just means that the last
1232 character of the file was an '@' terminating a
1233 value for a key type which does not require a
1235 pat = rcsbuf->ptrend - 1;
1238 ptrend = rcsbuf->ptrend;
1240 /* Note that the value of PTR is bogus here. This is
1241 OK, because we don't use it. */
1244 if (pat + 1 >= ptrend || pat[1] != '@')
1247 /* We found an '@' pair in the string. Keep looking. */
1248 ++rcsbuf->embedded_at;
1252 /* Here PAT points to the final '@' in the string. */
1259 rcsbuf->vlen = vlen;
1264 /* Certain keywords only have a '@' string. If there is no '@'
1265 string, then the old getrcskey function assumed that they had
1266 no value, and we do the same. */
1272 if (STREQ (k, RCSDESC)
1273 || STREQ (k, "text")
1274 || STREQ (k, "log"))
1283 /* If we've already gathered a '@' string, try to skip whitespace
1293 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1295 error (1, 0, "EOF in value in RCS file %s",
1297 ptrend = rcsbuf->ptrend;
1302 /* We're done. We already set everything up for this
1304 rcsbuf->ptr = ptr + 1;
1307 if (! my_whitespace (n))
1312 /* The value extends past the '@' string. We need to undo the
1313 '@' stripping done in the default case above. This
1314 case never happens in a plain RCS file, but it can happen
1315 if user defined phrases are used. */
1316 ((*valp)--)[rcsbuf->vlen++] = '@';
1319 /* Here we have a value which is not a simple '@' string. We need
1320 to gather up everything until the next ';', including any '@'
1321 strings. *VALP points to the start of the value. If
1322 RCSBUF->VLEN is not zero, then we have already read an '@'
1323 string, and PTR points to the data following the '@' string.
1324 Otherwise, PTR points to the start of the value. */
1328 char *start, *psemi, *pat;
1330 /* Find the ';' which must end the value. */
1332 while ((psemi = memchr (ptr, ';', ptrend - ptr)) == NULL)
1336 /* Note that we pass PTREND as the PTR value to
1337 rcsbuf_fill, so that we will wind up setting PTR to the
1338 location corresponding to the old PTREND, so that we
1339 don't search the same bytes again. */
1340 slen = start - *valp;
1341 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1343 error (1, 0, "EOF in value in RCS file %s", rcsbuf->filename);
1344 start = *valp + slen;
1345 ptrend = rcsbuf->ptrend;
1348 /* See if there are any '@' strings in the value. */
1349 pat = memchr (start, '@', psemi - start);
1355 /* We're done with the value. Trim any trailing
1358 rcsbuf->ptr = psemi + 1;
1361 while (psemi > start && my_whitespace (psemi[-1]))
1365 vlen = psemi - start;
1368 rcsbuf->vlen = vlen;
1373 /* We found an '@' string in the value. We set RCSBUF->AT_STRING
1374 and RCSBUF->EMBEDDED_AT to indicate that we won't be able to
1375 compress whitespace correctly for this type of value.
1376 Since this type of value never arises in a normal RCS file,
1377 this should not be a big deal. It means that if anybody
1378 adds a phrase which can have both an '@' string and regular
1379 text, they will have to handle whitespace compression
1382 rcsbuf->at_string = 1;
1383 rcsbuf->embedded_at = -1;
1389 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1391 /* Note that we pass PTREND as the PTR value to
1392 rcsbuff_fill, so that we will wind up setting PTR
1393 to the location corresponding to the old PTREND, so
1394 that we don't search the same bytes again. */
1395 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1398 "EOF while looking for end of string in RCS file %s",
1400 ptrend = rcsbuf->ptrend;
1403 /* Handle the special case of an '@' right at the end of
1405 if (pat + 1 >= ptrend)
1407 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1409 error (1, 0, "EOF in value in RCS file %s",
1411 ptrend = rcsbuf->ptrend;
1417 /* We found an '@' pair in the string. Keep looking. */
1421 /* Here PAT points to the final '@' in the string. */
1425 #undef my_whitespace
1428 /* Read an RCS revision number from an RCS file. This sets *REVP to
1429 point to the revision number; it will point to space that is
1430 managed by the rcsbuf functions, and is only good until the next
1431 call to rcsbuf_getkey or rcsbuf_getrevnum.
1433 This function returns 1 on success, or 0 on EOF. If there is an
1434 error reading the file, or an EOF in an unexpected location, it
1435 gives a fatal error. */
1438 rcsbuf_getrevnum (struct rcsbuffer *rcsbuf, char **revp)
1444 ptrend = rcsbuf->ptrend;
1448 /* Skip leading whitespace. */
1454 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
1457 ptrend = rcsbuf->ptrend;
1461 if (! whitespace (c))
1467 if (! isdigit ((unsigned char) c) && c != '.')
1470 unexpected '\\x%x' reading revision number in RCS file %s",
1471 c, rcsbuf->filename);
1480 ptr = rcsbuf_fill (rcsbuf, ptr, revp, (char **) NULL);
1483 "unexpected EOF reading revision number in RCS file %s",
1485 ptrend = rcsbuf->ptrend;
1490 while (isdigit ((unsigned char) c) || c == '.');
1492 if (! whitespace (c))
1494 unexpected '\\x%x' reading revision number in RCS file %s",
1495 c, rcsbuf->filename);
1499 rcsbuf->ptr = ptr + 1;
1504 /* Fill RCSBUF_BUFFER with bytes from the file associated with RCSBUF,
1505 updating PTR and the PTREND field. If KEYP and *KEYP are not NULL,
1506 then *KEYP points into the buffer, and must be adjusted if the
1507 buffer is changed. Likewise for VALP. Returns the new value of
1508 PTR, or NULL on error. */
1511 rcsbuf_fill (rcsbuf, ptr, keyp, valp)
1512 struct rcsbuffer *rcsbuf;
1519 #else /* HAVE_MMAP */
1522 if (rcsbuf->ptrend - rcsbuf_buffer + RCSBUF_BUFSIZE > rcsbuf_buffer_size)
1524 int poff, peoff, koff, voff;
1526 poff = ptr - rcsbuf_buffer;
1527 peoff = rcsbuf->ptrend - rcsbuf_buffer;
1528 koff = keyp == NULL ? 0 : *keyp - rcsbuf_buffer;
1529 voff = valp == NULL ? 0 : *valp - rcsbuf_buffer;
1531 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size,
1532 rcsbuf_buffer_size + RCSBUF_BUFSIZE);
1534 ptr = rcsbuf_buffer + poff;
1535 rcsbuf->ptrend = rcsbuf_buffer + peoff;
1537 *keyp = rcsbuf_buffer + koff;
1539 *valp = rcsbuf_buffer + voff;
1542 got = fread (rcsbuf->ptrend, 1, RCSBUF_BUFSIZE, rcsbuf->fp);
1545 if (ferror (rcsbuf->fp))
1546 error (1, errno, "cannot read %s", rcsbuf->filename);
1550 rcsbuf->ptrend += got;
1553 #endif /* HAVE_MMAP */
1556 /* Test whether the last value returned by rcsbuf_getkey is a composite
1560 rcsbuf_valcmp (struct rcsbuffer *rcsbuf)
1562 return rcsbuf->at_string && rcsbuf->embedded_at < 0;
1565 /* Copy the value VAL returned by rcsbuf_getkey into a memory buffer,
1566 returning the memory buffer. Polish the value like
1567 rcsbuf_valpolish, q.v. */
1570 rcsbuf_valcopy (struct rcsbuffer *rcsbuf, char *val, int polish, size_t *lenp)
1583 vlen = rcsbuf->vlen;
1584 embedded_at = rcsbuf->embedded_at < 0 ? 0 : rcsbuf->embedded_at;
1586 ret = xmalloc (vlen - embedded_at + 1);
1588 if (rcsbuf->at_string ? embedded_at == 0 : ! polish)
1590 /* No special action to take. */
1591 memcpy (ret, val, vlen + 1);
1597 rcsbuf_valpolish_internal (rcsbuf, ret, val, lenp);
1601 /* Polish the value VAL returned by rcsbuf_getkey. The POLISH
1602 parameter is non-zero if multiple embedded whitespace characters
1603 should be compressed into a single whitespace character. Note that
1604 leading and trailing whitespace was already removed by
1605 rcsbuf_getkey. Within an '@' string, pairs of '@' characters are
1606 compressed into a single '@' character regardless of the value of
1607 POLISH. If LENP is not NULL, set *LENP to the length of the value. */
1610 rcsbuf_valpolish (struct rcsbuffer *rcsbuf, char *val, int polish, size_t *lenp)
1619 if (rcsbuf->at_string ? rcsbuf->embedded_at == 0 : ! polish)
1621 /* No special action to take. */
1623 *lenp = rcsbuf->vlen;
1627 rcsbuf_valpolish_internal (rcsbuf, val, val, lenp);
1630 /* Internal polishing routine, called from rcsbuf_valcopy and
1631 rcsbuf_valpolish. */
1634 rcsbuf_valpolish_internal (struct rcsbuffer *rcsbuf, char *to, const char *from, size_t *lenp)
1640 if (! rcsbuf->at_string)
1647 for (clen = len; clen > 0; ++from, --clen)
1654 /* Note that we know that clen can not drop to zero
1655 while we have whitespace, because we know there is
1656 no trailing whitespace. */
1657 while (whitespace (from[1]))
1670 *lenp = to - orig_to;
1674 const char *orig_from;
1682 embedded_at = rcsbuf->embedded_at;
1683 assert (embedded_at > 0);
1686 *lenp = len - embedded_at;
1688 for (clen = len; clen > 0; ++from, --clen)
1700 * FIXME: I restored this to an abort from an assert based on
1701 * advice from Larry Jones that asserts should not be used to
1702 * confirm the validity of an RCS file... This leaves two
1703 * issues here: 1) I am uncertain that the fact that we will
1704 * only find double '@'s hasn't already been confirmed; and:
1705 * 2) If this is the proper place to spot the error in the RCS
1706 * file, then we should print a much clearer error here for the
1711 if (*from != '@' || clen == 0)
1717 if (embedded_at == 0)
1719 /* We've found all the embedded '@' characters.
1720 We can just memcpy the rest of the buffer after
1721 this '@' character. */
1722 if (orig_to != orig_from)
1723 memcpy (to, from + 1, clen - 1);
1725 memmove (to, from + 1, clen - 1);
1734 assert (from == orig_from + len
1735 && to == orig_to + (len - rcsbuf->embedded_at));
1741 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1743 /* Copy the next word from the value VALP returned by rcsbuf_getkey into a
1744 memory buffer, updating VALP and returning the memory buffer. Return
1745 NULL when there are no more words. */
1748 rcsbuf_valword (rcsbuf, valp)
1749 struct rcsbuffer *rcsbuf;
1752 register const char * const my_spacetab = spacetab;
1753 register char *ptr, *pat;
1756 # define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
1761 for (ptr = *valp; my_whitespace (*ptr); ++ptr) ;
1764 assert (ptr - *valp == rcsbuf->vlen);
1770 /* PTR now points to the start of a value. Find out whether it is
1771 a num, an id, a string or a colon. */
1775 rcsbuf->vlen -= ++ptr - *valp;
1777 return xstrdup (":");
1782 int embedded_at = 0;
1786 while ((pat = strchr (pat, '@')) != NULL)
1794 /* Here PAT points to the final '@' in the string. */
1796 assert (rcsbuf->at_string);
1797 vlen = rcsbuf->vlen - (pat - *valp);
1798 rcsbuf->vlen = pat - ptr - 1;
1799 rcsbuf->embedded_at = embedded_at;
1800 ptr = rcsbuf_valcopy (rcsbuf, ptr, 0, (size_t *) NULL);
1802 rcsbuf->vlen = vlen;
1803 if (strchr (pat, '@') == NULL)
1804 rcsbuf->at_string = 0;
1806 rcsbuf->embedded_at = -1;
1810 /* *PTR is neither `:', `;' nor `@', so it should be the start of a num
1811 or an id. Make sure it is not another special character. */
1812 if (c == '$' || c == '.' || c == ',')
1814 error (1, 0, "invalid special character in RCS field in %s",
1821 /* Legitimate ID characters are digits, dots and any `graphic
1822 printing character that is not a special.' This test ought
1825 if (!isprint ((unsigned char) c) ||
1826 c == ';' || c == '$' || c == ',' || c == '@' || c == ':')
1830 /* PAT points to the last non-id character in this word, and C is
1831 the character in its memory cell. Check to make sure that it
1832 is a legitimate word delimiter -- whitespace or end. */
1833 if (c != '\0' && !my_whitespace (c))
1834 error (1, 0, "invalid special character in RCS field in %s",
1838 rcsbuf->vlen -= pat - *valp;
1840 return xstrdup (ptr);
1842 # undef my_whitespace
1847 /* Return the current position of an rcsbuf. */
1850 rcsbuf_ftello (struct rcsbuffer *rcsbuf)
1852 return rcsbuf->pos + rcsbuf->ptr - rcsbuf_buffer;
1855 /* Return a pointer to any data buffered for RCSBUF, along with the
1859 rcsbuf_get_buffered (struct rcsbuffer *rcsbuf, char **datap, size_t *lenp)
1861 *datap = rcsbuf->ptr;
1862 *lenp = rcsbuf->ptrend - rcsbuf->ptr;
1865 /* CVS optimizes by quickly reading some header information from a
1866 file. If it decides it needs to do more with the file, it reopens
1867 it. We speed that up here by maintaining a cache of a single open
1868 file, to save the time it takes to reopen the file in the common
1871 static RCSNode *cached_rcs;
1872 static struct rcsbuffer cached_rcsbuf;
1874 /* Cache RCS and RCSBUF. This takes responsibility for closing
1878 rcsbuf_cache (RCSNode *rcs, struct rcsbuffer *rcsbuf)
1880 if (cached_rcs != NULL)
1881 rcsbuf_cache_close ();
1884 cached_rcsbuf = *rcsbuf;
1887 /* If there is anything in the cache, close it. */
1890 rcsbuf_cache_close (void)
1892 if (cached_rcs != NULL)
1894 rcsbuf_close (&cached_rcsbuf);
1895 if (fclose (cached_rcsbuf.fp) != 0)
1896 error (0, errno, "cannot close %s", cached_rcsbuf.filename);
1897 freercsnode (&cached_rcs);
1902 /* Open an rcsbuffer for RCS, getting it from the cache if possible.
1903 Set *FPP to the file, and *RCSBUFP to the rcsbuf. The file should
1904 be put at position POS. */
1907 rcsbuf_cache_open (RCSNode *rcs, off_t pos, FILE **pfp,
1908 struct rcsbuffer *prcsbuf)
1911 if (cached_rcs == rcs)
1913 if (rcsbuf_ftello (&cached_rcsbuf) != pos)
1915 if (fseeko (cached_rcsbuf.fp, pos, SEEK_SET) != 0)
1916 error (1, 0, "cannot fseeko RCS file %s",
1917 cached_rcsbuf.filename);
1918 cached_rcsbuf.ptr = rcsbuf_buffer;
1919 cached_rcsbuf.ptrend = rcsbuf_buffer;
1920 cached_rcsbuf.pos = pos;
1922 *pfp = cached_rcsbuf.fp;
1924 /* When RCS_parse opens a file using fopen_case, it frees the
1925 filename which we cached in CACHED_RCSBUF and stores a new
1926 file name in RCS->PATH. We avoid problems here by always
1927 copying the filename over. FIXME: This is hackish. */
1928 cached_rcsbuf.filename = rcs->path;
1930 *prcsbuf = cached_rcsbuf;
1934 /* Removing RCS from the cache removes a reference to it. */
1936 if (rcs->refcount <= 0)
1937 error (1, 0, "rcsbuf_cache_open: internal error");
1941 #endif /* ifndef HAVE_MMAP */
1942 /* FIXME: If these routines can be rewritten to not write to the
1943 * rcs file buffer, there would be a considerably larger memory savings
1944 * from using mmap since the shared file would never need be copied to
1947 * If this happens, cached mmapped buffers would be usable, but don't
1948 * forget to make sure rcs->pos < pos here...
1950 if (cached_rcs != NULL)
1951 rcsbuf_cache_close ();
1953 *pfp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ);
1955 error (1, 0, "unable to reopen `%s'", rcs->path);
1959 if (fseeko (*pfp, pos, SEEK_SET) != 0)
1960 error (1, 0, "cannot fseeko RCS file %s", rcs->path);
1962 #endif /* ifndef HAVE_MMAP */
1963 rcsbuf_open (prcsbuf, *pfp, rcs->path, pos);
1966 #endif /* ifndef HAVE_MMAP */
1971 * process the symbols list of the rcs file
1974 do_symbols (List *list, char *val)
1982 /* skip leading whitespace */
1983 while (whitespace (*cp))
1986 /* if we got to the end, we are done */
1990 /* split it up into tag and rev */
1992 cp = strchr (cp, ':');
1995 while (!whitespace (*cp) && *cp != '\0')
2000 /* make a new node and add it to the list */
2002 p->key = xstrdup (tag);
2003 p->data = xstrdup (rev);
2004 (void) addnode (list, p);
2009 * process the locks list of the rcs file
2010 * Like do_symbols, but hash entries are keyed backwards: i.e.
2011 * an entry like `user:rev' is keyed on REV rather than on USER.
2014 do_locks (List *list, char *val)
2022 /* skip leading whitespace */
2023 while (whitespace (*cp))
2026 /* if we got to the end, we are done */
2030 /* split it up into user and rev */
2032 cp = strchr (cp, ':');
2035 while (!whitespace (*cp) && *cp != '\0')
2040 /* make a new node and add it to the list */
2042 p->key = xstrdup (rev);
2043 p->data = xstrdup (user);
2044 (void) addnode (list, p);
2049 * process the branches list of a revision delta
2052 do_branches (List *list, char *val)
2060 /* skip leading whitespace */
2061 while (whitespace (*cp))
2064 /* if we got to the end, we are done */
2068 /* find the end of this branch */
2070 while (!whitespace (*cp) && *cp != '\0')
2075 /* make a new node and add it to the list */
2077 p->key = xstrdup (branch);
2078 (void) addnode (list, p);
2087 * Returns the requested version number of the RCS file, satisfying tags and/or
2088 * dates, and walking branches, if necessary.
2090 * The result is returned; null-string if error.
2093 RCS_getversion (RCSNode *rcs, const char *tag, const char *date,
2094 int force_tag_match, int *simple_tag)
2096 if (simple_tag != NULL)
2099 /* make sure we have something to look at... */
2100 assert (rcs != NULL);
2106 if (! RCS_nodeisbranch (rcs, tag))
2108 /* We can't get a particular date if the tag is not a
2113 /* Work out the branch. */
2114 if (! isdigit ((unsigned char) tag[0]))
2115 branch = RCS_whatbranch (rcs, tag);
2117 branch = xstrdup (tag);
2119 /* Fetch the revision of branch as of date. */
2120 rev = RCS_getdatebranch (rcs, date, branch);
2125 return RCS_gettag (rcs, tag, force_tag_match, simple_tag);
2127 return RCS_getdate (rcs, date, force_tag_match);
2129 return RCS_head (rcs);
2136 * Get existing revision number corresponding to tag or revision.
2137 * Similar to RCS_gettag but less interpretation imposed.
2139 * -- If tag designates a magic branch, RCS_tag2rev
2140 * returns the magic branch number.
2141 * -- If tag is a branch tag, returns the branch number, not
2142 * the revision of the head of the branch.
2143 * If tag or revision is not valid or does not exist in file,
2147 RCS_tag2rev (RCSNode *rcs, char *tag)
2149 char *rev, *pa, *pb;
2152 assert (rcs != NULL);
2154 if (rcs->flags & PARTIAL)
2155 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2157 /* If a valid revision, try to look it up */
2158 if ( RCS_valid_rev (tag) )
2160 /* Make a copy so we can scribble on it */
2161 rev = xstrdup (tag);
2163 /* If revision exists, return the copy */
2164 if (RCS_exist_rev (rcs, tag))
2167 /* Nope, none such. If tag is not a branch we're done. */
2171 pa = strrchr (rev, '.');
2172 if (i == 1 || *(pa-1) != RCS_MAGIC_BRANCH || *(pa-2) != '.')
2175 error (1, 0, "revision `%s' does not exist", tag);
2179 /* Try for a real (that is, exists in the RCS deltas) branch
2180 (RCS_exist_rev just checks for real revisions and revisions
2181 which have tags pointing to them). */
2182 pa = RCS_getbranch (rcs, rev, 1);
2189 /* Tag is branch, but does not exist, try corresponding
2192 * FIXME: assumes all magic branches are of
2193 * form "n.n.n ... .0.n". I'll fix if somebody can
2194 * send me a method to get a magic branch tag with
2195 * the 0 in some other position -- <dan@gasboy.com>
2197 pa = strrchr (rev, '.');
2198 pb = xmalloc (strlen (rev) + 3);
2200 (void) sprintf (pb, "%s.%d.%s", rev, RCS_MAGIC_BRANCH, pa);
2203 if (RCS_exist_rev (rcs, rev))
2205 error (1, 0, "revision `%s' does not exist", tag);
2209 RCS_check_tag (tag); /* exit if not a valid tag */
2211 /* If tag is "HEAD", special case to get head RCS revision */
2212 if (tag && STREQ (tag, TAG_HEAD))
2213 return (RCS_head (rcs));
2215 /* If valid tag let translate_symtag say yea or nay. */
2216 rev = translate_symtag (rcs, tag);
2221 /* Trust the caller to print warnings. */
2226 * Find the revision for a specific tag.
2227 * If force_tag_match is set, return NULL if an exact match is not
2228 * possible otherwise return RCS_head (). We are careful to look for
2229 * and handle "magic" revisions specially.
2231 * If the matched tag is a branch tag, find the head of the branch.
2233 * Returns pointer to newly malloc'd string, or NULL.
2236 RCS_gettag (RCSNode *rcs, const char *symtag, int force_tag_match,
2241 if (simple_tag != NULL)
2244 /* make sure we have something to look at... */
2245 assert (rcs != NULL);
2247 /* XXX this is probably not necessary, --jtc */
2248 if (rcs->flags & PARTIAL)
2249 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2251 /* If symtag is "HEAD", special case to get head RCS revision */
2252 if (symtag && STREQ (symtag, TAG_HEAD))
2253 #if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */
2254 if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
2255 return ((char *) NULL); /* head request for removed file */
2258 return RCS_head (rcs);
2260 if (!isdigit ((unsigned char) symtag[0]))
2264 /* If we got a symbolic tag, resolve it to a numeric */
2265 version = translate_symtag (rcs, symtag);
2266 if (version != NULL)
2269 char *magic, *branch, *cp;
2274 * If this is a magic revision, we turn it into either its
2275 * physical branch equivalent (if one exists) or into
2276 * its base revision, which we assume exists.
2278 dots = numdots (tag);
2279 if (dots > 2 && (dots & 1) != 0)
2281 branch = strrchr (tag, '.');
2286 /* see if we have .magic-branch. (".0.") */
2287 magic = xmalloc (strlen (tag) + 1);
2288 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2289 if (strncmp (magic, cp, strlen (magic)) == 0)
2291 /* it's magic. See if the branch exists */
2292 *cp = '\0'; /* turn it into a revision */
2293 (void) sprintf (magic, "%s.%s", tag, branch);
2294 branch = RCS_getbranch (rcs, magic, 1);
2308 /* The tag wasn't there, so return the head or NULL */
2309 if (force_tag_match)
2312 return RCS_head (rcs);
2316 tag = xstrdup (symtag);
2318 /* tag is always allocated and numeric now. */
2321 * numeric tag processing:
2322 * 1) revision number - just return it
2323 * 2) branch number - find head of branch
2326 /* strip trailing dots */
2327 while (tag[strlen (tag) - 1] == '.')
2328 tag[strlen (tag) - 1] = '\0';
2330 if ((numdots (tag) & 1) == 0)
2334 /* we have a branch tag, so we need to walk the branch */
2335 branch = RCS_getbranch (rcs, tag, force_tag_match);
2343 /* we have a revision tag, so make sure it exists */
2344 p = findnode (rcs->versions, tag);
2347 /* We have found a numeric revision for the revision tag.
2348 To support expanding the RCS keyword Name, if
2349 SIMPLE_TAG is not NULL, tell the the caller that this
2350 is a simple tag which co will recognize. FIXME: Are
2351 there other cases in which we should set this? In
2352 particular, what if we expand RCS keywords internally
2353 without calling co? */
2354 if (simple_tag != NULL)
2360 /* The revision wasn't there, so return the head or NULL */
2362 if (force_tag_match)
2365 return RCS_head (rcs);
2371 * Return a "magic" revision as a virtual branch off of REV for the RCS file.
2372 * A "magic" revision is one which is unique in the RCS file. By unique, I
2373 * mean we return a revision which:
2374 * - has a branch of 0 (see rcs.h RCS_MAGIC_BRANCH)
2375 * - has a revision component which is not an existing branch off REV
2376 * - has a revision component which is not an existing magic revision
2377 * - is an even-numbered revision, to avoid conflicts with vendor branches
2378 * The first point is what makes it "magic".
2380 * As an example, if we pass in 1.37 as REV, we will look for an existing
2381 * branch called 1.37.2. If it did not exist, we would look for an
2382 * existing symbolic tag with a numeric part equal to 1.37.0.2. If that
2383 * didn't exist, then we know that the 1.37.2 branch can be reserved by
2384 * creating a symbolic tag with 1.37.0.2 as the numeric part.
2386 * This allows us to fork development with very little overhead -- just a
2387 * symbolic tag is used in the RCS file. When a commit is done, a physical
2388 * branch is dynamically created to hold the new revision.
2390 * Note: We assume that REV is an RCS revision and not a branch number.
2392 static char *check_rev;
2394 RCS_magicrev (RCSNode *rcs, char *rev)
2397 char *xrev, *test_branch, *local_branch_num;
2399 xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */
2402 local_branch_num = getenv("CVS_LOCAL_BRANCH_NUM");
2403 if (local_branch_num)
2405 rev_num = atoi(local_branch_num);
2414 /* only look at even numbered branches */
2415 for ( ; ; rev_num += 2)
2417 /* see if the physical branch exists */
2418 (void) sprintf (xrev, "%s.%d", rev, rev_num);
2419 test_branch = RCS_getbranch (rcs, xrev, 1);
2420 if (test_branch != NULL) /* it did, so keep looking */
2426 /* now, create a "magic" revision */
2427 (void) sprintf (xrev, "%s.%d.%d", rev, RCS_MAGIC_BRANCH, rev_num);
2429 /* walk the symbols list to see if a magic one already exists */
2430 if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0)
2433 /* we found a free magic branch. Claim it as ours */
2439 * walklist proc to look for a match in the symbols list.
2440 * Returns 0 if the symbol does not match, 1 if it does.
2443 checkmagic_proc (Node *p, void *closure)
2445 if (STREQ (check_rev, p->data))
2452 * Given an RCSNode, returns non-zero if the specified revision number
2453 * or symbolic tag resolves to a "branch" within the rcs file.
2455 * FIXME: this is the same as RCS_nodeisbranch except for the special
2456 * case for handling a null rcsnode.
2459 RCS_isbranch (RCSNode *rcs, const char *rev)
2461 /* numeric revisions are easy -- even number of dots is a branch */
2462 if (isdigit ((unsigned char) *rev))
2463 return ((numdots (rev) & 1) == 0);
2465 /* assume a revision if you can't find the RCS info */
2469 /* now, look for a match in the symbols list */
2470 return (RCS_nodeisbranch (rcs, rev));
2474 * Given an RCSNode, returns non-zero if the specified revision number
2475 * or symbolic tag resolves to a "branch" within the rcs file. We do
2476 * take into account any magic branches as well.
2479 RCS_nodeisbranch (RCSNode *rcs, const char *rev)
2484 assert (rcs != NULL);
2486 /* numeric revisions are easy -- even number of dots is a branch */
2487 if (isdigit ((unsigned char) *rev))
2488 return ((numdots (rev) & 1) == 0);
2490 version = translate_symtag (rcs, rev);
2491 if (version == NULL)
2493 dots = numdots (version);
2494 if ((dots & 1) == 0)
2500 /* got a symbolic tag match, but it's not a branch; see if it's magic */
2504 char *branch = strrchr (version, '.');
2505 char *cp = branch - 1;
2509 /* see if we have .magic-branch. (".0.") */
2510 magic = xmalloc (strlen (version) + 1);
2511 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2512 if (strncmp (magic, cp, strlen (magic)) == 0)
2525 * Returns a pointer to malloc'ed memory which contains the branch
2526 * for the specified *symbolic* tag. Magic branches are handled correctly.
2529 RCS_whatbranch (RCSNode *rcs, const char *rev)
2534 /* assume no branch if you can't find the RCS info */
2536 return ((char *) NULL);
2538 /* now, look for a match in the symbols list */
2539 version = translate_symtag (rcs, rev);
2540 if (version == NULL)
2541 return ((char *) NULL);
2542 dots = numdots (version);
2543 if ((dots & 1) == 0)
2546 /* got a symbolic tag match, but it's not a branch; see if it's magic */
2550 char *branch = strrchr (version, '.');
2551 char *cp = branch++ - 1;
2555 /* see if we have .magic-branch. (".0.") */
2556 magic = xmalloc (strlen (version) + 1);
2557 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2558 if (strncmp (magic, cp, strlen (magic)) == 0)
2560 /* yep. it's magic. now, construct the real branch */
2561 *cp = '\0'; /* turn it into a revision */
2562 (void) sprintf (magic, "%s.%s", version, branch);
2569 return ((char *) NULL);
2573 * Get the head of the specified branch. If the branch does not exist,
2574 * return NULL or RCS_head depending on force_tag_match.
2575 * Returns NULL or a newly malloc'd string.
2578 RCS_getbranch (RCSNode *rcs, const char *tag, int force_tag_match)
2586 /* make sure we have something to look at... */
2587 assert (rcs != NULL);
2589 if (rcs->flags & PARTIAL)
2590 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2592 /* find out if the tag contains a dot, or is on the trunk */
2593 cp = strrchr (tag, '.');
2595 /* trunk processing is the special case */
2598 xtag = xmalloc (strlen (tag) + 1 + 1); /* +1 for an extra . */
2599 (void) strcpy (xtag, tag);
2600 (void) strcat (xtag, ".");
2601 for (cp = rcs->head; cp != NULL;)
2603 if (strncmp (xtag, cp, strlen (xtag)) == 0)
2605 p = findnode (rcs->versions, cp);
2609 if (force_tag_match)
2612 return (RCS_head (rcs));
2620 if (force_tag_match)
2623 return (RCS_head (rcs));
2625 return (xstrdup (cp));
2628 /* if it had a `.', terminate the string so we have the base revision */
2631 /* look up the revision this branch is based on */
2632 p = findnode (rcs->versions, tag);
2634 /* put the . back so we have the branch again */
2639 /* if the base revision didn't exist, return head or NULL */
2640 if (force_tag_match)
2643 return (RCS_head (rcs));
2646 /* find the first element of the branch we are looking for */
2648 if (vn->branches == NULL)
2650 xtag = xmalloc (strlen (tag) + 1 + 1); /* 1 for the extra '.' */
2651 (void) strcpy (xtag, tag);
2652 (void) strcat (xtag, ".");
2653 head = vn->branches->list;
2654 for (p = head->next; p != head; p = p->next)
2655 if (strncmp (p->key, xtag, strlen (xtag)) == 0)
2661 /* we didn't find a match so return head or NULL */
2662 if (force_tag_match)
2665 return (RCS_head (rcs));
2668 /* now walk the next pointers of the branch */
2672 p = findnode (rcs->versions, nextvers);
2675 /* a link in the chain is missing - return head or NULL */
2676 if (force_tag_match)
2679 return (RCS_head (rcs));
2682 nextvers = vn->next;
2683 } while (nextvers != NULL);
2685 /* we have the version in our hand, so go for it */
2686 return (xstrdup (vn->version));
2689 /* Returns the head of the branch which REV is on. REV can be a
2690 branch tag or non-branch tag; symbolic or numeric.
2692 Returns a newly malloc'd string. Returns NULL if a symbolic name
2696 RCS_branch_head (RCSNode *rcs, char *rev)
2702 assert (rcs != NULL);
2704 if (RCS_nodeisbranch (rcs, rev))
2705 return RCS_getbranch (rcs, rev, 1);
2707 if (isdigit ((unsigned char) *rev))
2708 num = xstrdup (rev);
2711 num = translate_symtag (rcs, rev);
2715 br = truncate_revnum (num);
2716 retval = RCS_getbranch (rcs, br, 1);
2722 /* Get the branch point for a particular branch, that is the first
2723 revision on that branch. For example, RCS_getbranchpoint (rcs,
2724 "1.3.2") will normally return "1.3.2.1". TARGET may be either a
2725 branch number or a revision number; if a revnum, find the
2726 branchpoint of the branch to which TARGET belongs.
2728 Return RCS_head if TARGET is on the trunk or if the root node could
2729 not be found (this is sort of backwards from our behavior on a branch;
2730 the rationale is that the return value is a revision from which you
2731 can start walking the next fields and end up at TARGET).
2732 Return NULL on error. */
2735 RCS_getbranchpoint (RCSNode *rcs, char *target)
2740 int dots, isrevnum, brlen;
2742 dots = numdots (target);
2743 isrevnum = dots & 1;
2746 /* TARGET is a trunk revision; return rcs->head. */
2747 return (RCS_head (rcs));
2749 /* Get the revision number of the node at which TARGET's branch is
2750 rooted. If TARGET is a branch number, lop off the last field;
2751 if it's a revision number, lop off the last *two* fields. */
2752 branch = xstrdup (target);
2753 bp = strrchr (branch, '.');
2755 error (1, 0, "%s: confused revision number %s",
2758 while (*--bp != '.')
2762 vp = findnode (rcs->versions, branch);
2765 error (0, 0, "%s: can't find branch point %s", rcs->path, target);
2771 while (*bp && *bp != '.')
2773 brlen = bp - branch;
2775 vp = rev->branches->list->next;
2776 while (vp != rev->branches->list)
2778 /* BRANCH may be a genuine branch number, e.g. `1.1.3', or
2779 maybe a full revision number, e.g. `1.1.3.6'. We have
2780 found our branch point if the first BRANCHLEN characters
2781 of the revision number match, *and* if the following
2782 character is a dot. */
2783 if (strncmp (vp->key, branch, brlen) == 0 && vp->key[brlen] == '.')
2789 if (vp == rev->branches->list)
2791 error (0, 0, "%s: can't find branch point %s", rcs->path, target);
2795 return (xstrdup (vp->key));
2799 * Get the head of the RCS file. If branch is set, this is the head of the
2800 * branch, otherwise the real head.
2801 * Returns NULL or a newly malloc'd string.
2804 RCS_head (RCSNode *rcs)
2806 /* make sure we have something to look at... */
2807 assert (rcs != NULL);
2810 * NOTE: we call getbranch with force_tag_match set to avoid any
2811 * possibility of recursion
2814 return (RCS_getbranch (rcs, rcs->branch, 1));
2816 return (xstrdup (rcs->head));
2820 * Get the most recent revision, based on the supplied date, but use some
2821 * funky stuff and follow the vendor branch maybe
2824 RCS_getdate (RCSNode *rcs, const char *date, int force_tag_match)
2826 char *cur_rev = NULL;
2827 char *retval = NULL;
2829 RCSVers *vers = NULL;
2831 /* make sure we have something to look at... */
2832 assert (rcs != NULL);
2834 if (rcs->flags & PARTIAL)
2835 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2837 /* if the head is on a branch, try the branch first */
2838 if (rcs->branch != NULL)
2840 retval = RCS_getdatebranch (rcs, date, rcs->branch);
2845 /* otherwise if we have a trunk, try it */
2848 p = findnode (rcs->versions, rcs->head);
2851 error (0, 0, "%s: head revision %s doesn't exist", rcs->path,
2856 /* if the date of this one is before date, take it */
2858 if (RCS_datecmp (vers->date, date) <= 0)
2860 cur_rev = vers->version;
2864 /* if there is a next version, find the node */
2865 if (vers->next != NULL)
2866 p = findnode (rcs->versions, vers->next);
2872 error (0, 0, "%s: no head revision", rcs->path);
2875 * at this point, either we have the revision we want, or we have the
2876 * first revision on the trunk (1.1?) in our hands, or we've come up
2880 /* if we found what we're looking for, and it's not 1.1 return it */
2881 if (cur_rev != NULL)
2883 if (! STREQ (cur_rev, "1.1"))
2884 return (xstrdup (cur_rev));
2886 /* This is 1.1; if the date of 1.1 is not the same as that for the
2887 1.1.1.1 version, then return 1.1. This happens when the first
2888 version of a file is created by a regular cvs add and commit,
2889 and there is a subsequent cvs import of the same file. */
2890 p = findnode (rcs->versions, "1.1.1.1");
2893 char *date_1_1 = vers->date;
2896 if (RCS_datecmp (vers->date, date_1_1) != 0)
2897 return xstrdup ("1.1");
2901 /* look on the vendor branch */
2902 retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
2905 * if we found a match, return it; otherwise, we return the first
2906 * revision on the trunk or NULL depending on force_tag_match and the
2907 * date of the first rev
2912 if (!force_tag_match ||
2913 (vers != NULL && RCS_datecmp (vers->date, date) <= 0))
2914 return xstrdup (vers->version);
2922 * Look up the last element on a branch that was put in before or on
2923 * the specified date and time (return the rev or NULL)
2926 RCS_getdatebranch (RCSNode *rcs, const char *date, const char *branch)
2928 char *cur_rev = NULL;
2930 char *xbranch, *xrev;
2934 /* look up the first revision on the branch */
2935 xrev = xstrdup (branch);
2936 cp = strrchr (xrev, '.');
2942 *cp = '\0'; /* turn it into a revision */
2944 assert (rcs != NULL);
2946 if (rcs->flags & PARTIAL)
2947 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2949 p = findnode (rcs->versions, xrev);
2955 /* Tentatively use this revision, if it is early enough. */
2956 if (RCS_datecmp (vers->date, date) <= 0)
2957 cur_rev = vers->version;
2959 /* If no branches list, return now. This is what happens if the branch
2960 is a (magic) branch with no revisions yet. */
2961 if (vers->branches == NULL)
2962 return xstrdup (cur_rev);
2964 /* walk the branches list looking for the branch number */
2965 xbranch = xmalloc (strlen (branch) + 1 + 1); /* +1 for the extra dot */
2966 (void) strcpy (xbranch, branch);
2967 (void) strcat (xbranch, ".");
2968 for (p = vers->branches->list->next; p != vers->branches->list; p = p->next)
2969 if (strncmp (p->key, xbranch, strlen (xbranch)) == 0)
2972 if (p == vers->branches->list)
2974 /* This is what happens if the branch is a (magic) branch with
2975 no revisions yet. Similar to the case where vers->branches ==
2976 NULL, except here there was a another branch off the same
2978 return xstrdup (cur_rev);
2981 p = findnode (rcs->versions, p->key);
2983 /* walk the next pointers until you find the end, or the date is too late */
2987 if (RCS_datecmp (vers->date, date) <= 0)
2988 cur_rev = vers->version;
2992 /* if there is a next version, find the node */
2993 if (vers->next != NULL)
2994 p = findnode (rcs->versions, vers->next);
2999 /* Return whatever we found, which may be NULL. */
3000 return xstrdup (cur_rev);
3006 * Compare two dates in RCS format. Beware the change in format on January 1,
3007 * 2000, when years go from 2-digit to full format.
3010 RCS_datecmp (const char *date1, const char *date2)
3012 int length_diff = strlen (date1) - strlen (date2);
3014 return length_diff ? length_diff : strcmp (date1, date2);
3019 /* Look up revision REV in RCS and return the date specified for the
3020 revision minus FUDGE seconds (FUDGE will generally be one, so that the
3021 logically previous revision will be found later, or zero, if we want
3024 The return value is the date being returned as a time_t, or (time_t)-1
3025 on error (previously was documented as zero on error; I haven't checked
3026 the callers to make sure that they really check for (time_t)-1, but
3027 the latter is what this function really returns). If DATE is non-NULL,
3028 then it must point to MAXDATELEN characters, and we store the same
3029 return value there in DATEFORM format. */
3031 RCS_getrevtime (RCSNode *rcs, const char *rev, char *date, int fudge)
3033 char tdate[MAXDATELEN];
3034 struct tm xtm, *ftm;
3039 /* make sure we have something to look at... */
3040 assert (rcs != NULL);
3042 if (rcs->flags & PARTIAL)
3043 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3045 /* look up the revision */
3046 p = findnode (rcs->versions, rev);
3051 /* split up the date */
3052 if (sscanf (vers->date, SDATEFORM, &xtm.tm_year, &xtm.tm_mon,
3053 &xtm.tm_mday, &xtm.tm_hour, &xtm.tm_min, &xtm.tm_sec) != 6)
3054 error (1, 0, "%s: invalid date for revision %s (%s)", rcs->path,
3057 /* If the year is from 1900 to 1999, RCS files contain only two
3058 digits, and sscanf gives us a year from 0-99. If the year is
3059 2000+, RCS files contain all four digits and we subtract 1900,
3060 because the tm_year field should contain years since 1900. */
3062 if (xtm.tm_year >= 100 && xtm.tm_year < 2000)
3063 error (0, 0, "%s: non-standard date format for revision %s (%s)",
3064 rcs->path, rev, vers->date);
3065 if (xtm.tm_year >= 1900)
3066 xtm.tm_year -= 1900;
3068 /* put the date in a form getdate can grok */
3069 (void) sprintf (tdate, "%d/%d/%d GMT %d:%d:%d", xtm.tm_mon,
3070 xtm.tm_mday, xtm.tm_year + 1900, xtm.tm_hour,
3071 xtm.tm_min, xtm.tm_sec);
3073 /* turn it into seconds since the epoch */
3074 revdate = get_date (tdate, (struct timeb *) NULL);
3075 if (revdate != (time_t) -1)
3077 revdate -= fudge; /* remove "fudge" seconds */
3080 /* put an appropriate string into ``date'' if we were given one */
3081 ftm = gmtime (&revdate);
3082 (void) sprintf (date, DATEFORM,
3083 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
3084 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
3085 ftm->tm_min, ftm->tm_sec);
3092 RCS_getlocks (RCSNode *rcs)
3094 assert(rcs != NULL);
3096 if (rcs->flags & PARTIAL)
3097 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3099 if (rcs->locks_data) {
3100 rcs->locks = getlist ();
3101 do_locks (rcs->locks, rcs->locks_data);
3102 free(rcs->locks_data);
3103 rcs->locks_data = NULL;
3110 RCS_symbols(RCSNode *rcs)
3112 assert(rcs != NULL);
3114 if (rcs->flags & PARTIAL)
3115 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3117 if (rcs->symbols_data) {
3118 rcs->symbols = getlist ();
3119 do_symbols (rcs->symbols, rcs->symbols_data);
3120 free(rcs->symbols_data);
3121 rcs->symbols_data = NULL;
3124 return rcs->symbols;
3128 * Return the version associated with a particular symbolic tag.
3129 * Returns NULL or a newly malloc'd string.
3132 translate_symtag (RCSNode *rcs, const char *tag)
3134 if (rcs->flags & PARTIAL)
3135 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3137 if (rcs->symbols != NULL)
3141 /* The symbols have already been converted into a list. */
3142 p = findnode (rcs->symbols, tag);
3146 return xstrdup (p->data);
3149 if (rcs->symbols_data != NULL)
3154 /* Look through the RCS symbols information. This is like
3155 do_symbols, but we don't add the information to a list. In
3156 most cases, we will only be called once for this file, so
3157 generating the list is unnecessary overhead. */
3160 cp = rcs->symbols_data;
3161 while ((cp = strchr (cp, tag[0])) != NULL)
3163 if ((cp == rcs->symbols_data || whitespace (cp[-1]))
3164 && strncmp (cp, tag, len) == 0
3169 /* We found the tag. Return the version number. */
3173 while (! whitespace (*cp) && *cp != '\0')
3175 r = xmalloc (cp - v + 1);
3176 strncpy (r, v, cp - v);
3181 while (! whitespace (*cp) && *cp != '\0')
3192 * The argument ARG is the getopt remainder of the -k option specified on the
3193 * command line. This function returns malloc'ed space that can be used
3194 * directly in calls to RCS V5, with the -k flag munged correctly.
3197 RCS_check_kflag (const char *arg)
3199 static const char *const keyword_usage[] =
3201 "%s %s: invalid RCS keyword expansion mode\n",
3202 "Valid expansion modes include:\n",
3203 " -kkv\tGenerate keywords using the default form.\n",
3204 " -kkvl\tLike -kkv, except locker's name inserted.\n",
3205 " -kk\tGenerate only keyword names in keyword strings.\n",
3206 " -kv\tGenerate only keyword values in keyword strings.\n",
3207 " -ko\tGenerate the old keyword string (no changes from checked in file).\n",
3208 " -kb\tGenerate binary file unmodified (merges not allowed) (RCS 5.7).\n",
3209 "(Specify the --help global option for a list of other help options)\n",
3212 /* Big enough to hold any of the strings from kflags. */
3214 char const *const *cpp = NULL;
3218 for (cpp = kflags; *cpp != NULL; cpp++)
3220 if (STREQ (arg, *cpp))
3225 if (arg == NULL || *cpp == NULL)
3227 usage (keyword_usage);
3230 (void) sprintf (karg, "-k%s", *cpp);
3231 return (xstrdup (karg));
3235 * Do some consistency checks on the symbolic tag... These should equate
3236 * pretty close to what RCS checks, though I don't know for certain.
3239 RCS_check_tag (const char *tag)
3241 char *invalid = "$,.:;@"; /* invalid RCS tag characters */
3245 * The first character must be an alphabetic letter. The remaining
3246 * characters cannot be non-visible graphic characters, and must not be
3247 * in the set of "invalid" RCS identifier characters.
3249 if (isalpha ((unsigned char) *tag))
3251 for (cp = tag; *cp; cp++)
3253 if (!isgraph ((unsigned char) *cp))
3254 error (1, 0, "tag `%s' has non-visible graphic characters",
3256 if (strchr (invalid, *cp))
3257 error (1, 0, "tag `%s' must not contain the characters `%s'",
3262 error (1, 0, "tag `%s' must start with a letter", tag);
3266 * TRUE if argument has valid syntax for an RCS revision or
3267 * branch number. All characters must be digits or dots, first
3268 * and last characters must be digits, and no two consecutive
3269 * characters may be dots.
3271 * Intended for classifying things, so this function doesn't
3275 RCS_valid_rev (char *rev)
3279 if (!isdigit ((unsigned char) last))
3281 while ((c = *rev++)) /* Extra parens placate -Wall gcc option */
3290 if (!isdigit ((unsigned char) c))
3293 if (!isdigit ((unsigned char) last))
3299 * Return true if RCS revision with TAG is a dead revision.
3302 RCS_isdead (RCSNode *rcs, const char *tag)
3307 if (rcs->flags & PARTIAL)
3308 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3310 p = findnode (rcs->versions, tag);
3315 return (version->dead);
3318 /* Return the RCS keyword expansion mode. For example "b" for binary.
3319 Returns a pointer into storage which is allocated and freed along with
3320 the rest of the RCS information; the caller should not modify this
3321 storage. Returns NULL if the RCS file does not specify a keyword
3322 expansion mode; for all other errors, die with a fatal error. */
3324 RCS_getexpand (RCSNode *rcs)
3326 /* Since RCS_parsercsfile_i now reads expand, don't need to worry
3327 about RCS_reparsercsfile. */
3328 assert (rcs != NULL);
3334 /* Set keyword expansion mode to EXPAND. For example "b" for binary. */
3336 RCS_setexpand (RCSNode *rcs, const char *expand)
3338 /* Since RCS_parsercsfile_i now reads expand, don't need to worry
3339 about RCS_reparsercsfile. */
3340 assert (rcs != NULL);
3341 if (rcs->expand != NULL)
3343 rcs->expand = xstrdup (expand);
3348 /* RCS keywords, and a matching enum. */
3355 #define KEYWORD_INIT(s) (s), sizeof (s) - 1
3356 static struct rcs_keyword keywords[] =
3358 { KEYWORD_INIT ("Author"), 1 },
3359 { KEYWORD_INIT ("Date"), 1 },
3360 { KEYWORD_INIT ("CVSHeader"), 1 },
3361 { KEYWORD_INIT ("Header"), 1 },
3362 { KEYWORD_INIT ("Id"), 1 },
3363 { KEYWORD_INIT ("Locker"), 1 },
3364 { KEYWORD_INIT ("Log"), 1 },
3365 { KEYWORD_INIT ("Name"), 1 },
3366 { KEYWORD_INIT ("RCSfile"), 1 },
3367 { KEYWORD_INIT ("Revision"), 1 },
3368 { KEYWORD_INIT ("Source"), 1 },
3369 { KEYWORD_INIT ("State"), 1 },
3370 { NULL, 0, 0 }, /* localid */
3389 enum keyword keyword_local = KEYWORD_ID;
3391 /* Convert an RCS date string into a readable string. This is like
3392 the RCS date2str function. */
3395 printable_date (const char *rcs_date)
3397 int year, mon, mday, hour, min, sec;
3400 (void) sscanf (rcs_date, SDATEFORM, &year, &mon, &mday, &hour, &min,
3404 sprintf (buf, "%04d/%02d/%02d %02d:%02d:%02d", year, mon, mday,
3406 return xstrdup (buf);
3409 /* Escape the characters in a string so that it can be included in an
3413 escape_keyword_value (const char *value, int *free_value)
3418 for (s = value; *s != '\0'; s++)
3436 return (char *) value;
3439 ret = xmalloc (strlen (value) * 4 + 1);
3442 for (s = value, t = ret; *s != '\0'; s++, t++)
3481 /* Expand RCS keywords in the memory buffer BUF of length LEN. This
3482 applies to file RCS and version VERS. If NAME is not NULL, and is
3483 not a numeric revision, then it is the symbolic tag used for the
3484 checkout. EXPAND indicates how to expand the keywords. This
3485 function sets *RETBUF and *RETLEN to the new buffer and length.
3486 This function may modify the buffer BUF. If BUF != *RETBUF, then
3487 RETBUF is a newly allocated buffer. */
3490 expand_keywords (RCSNode *rcs, RCSVers *ver, const char *name, const char *log, size_t loglen, enum kflag expand, char *buf, size_t len, char **retbuf, size_t *retlen)
3492 struct expand_buffer
3494 struct expand_buffer *next;
3499 struct expand_buffer *ebuf_last = NULL;
3500 size_t ebuf_len = 0;
3502 char *srch, *srch_next;
3505 if (expand == KFLAG_O || expand == KFLAG_B)
3512 /* If we are using -kkvl, dig out the locker information if any. */
3514 if (expand == KFLAG_KVL)
3517 lock = findnode (RCS_getlocks(rcs), ver->version);
3519 locker = xstrdup (lock->data);
3522 /* RCS keywords look like $STRING$ or $STRING: VALUE$. */
3525 while ((srch_next = memchr (srch, '$', srch_len)) != NULL)
3529 const struct rcs_keyword *keyword;
3536 srch_len -= (srch_next + 1) - srch;
3537 srch = srch_next + 1;
3539 /* Look for the first non alphabetic character after the '$'. */
3540 send = srch + srch_len;
3541 for (s = srch; s < send; s++)
3542 if (! isalpha ((unsigned char) *s))
3545 /* If the first non alphabetic character is not '$' or ':',
3546 then this is not an RCS keyword. */
3547 if (s == send || (*s != '$' && *s != ':'))
3550 /* See if this is one of the keywords. */
3552 for (keyword = keywords; keyword->string != NULL; keyword++)
3554 if (keyword->expandit
3555 && keyword->len == slen
3556 && strncmp (keyword->string, srch, slen) == 0)
3561 if (keyword->string == NULL)
3564 kw = (enum keyword) (keyword - keywords);
3566 /* If the keyword ends with a ':', then the old value consists
3567 of the characters up to the next '$'. If there is no '$'
3568 before the end of the line, though, then this wasn't an RCS
3569 keyword after all. */
3572 for (; s < send; s++)
3573 if (*s == '$' || *s == '\n')
3575 if (s == send || *s != '$')
3579 /* At this point we must replace the string from SRCH to S
3580 with the expansion of the keyword KW. */
3582 /* Get the value to use. */
3584 if (expand == KFLAG_K)
3593 case KEYWORD_AUTHOR:
3594 value = ver->author;
3598 value = printable_date (ver->date);
3602 case KEYWORD_CVSHEADER:
3603 case KEYWORD_HEADER:
3605 case KEYWORD_LOCALID:
3613 if (kw == KEYWORD_HEADER ||
3614 (kw == KEYWORD_LOCALID &&
3615 keyword_local == KEYWORD_HEADER))
3617 else if (kw == KEYWORD_CVSHEADER ||
3618 (kw == KEYWORD_LOCALID &&
3619 keyword_local == KEYWORD_CVSHEADER))
3620 path = getfullCVSname(rcs->path, &old_path);
3622 path = last_component (rcs->path);
3623 path = escape_keyword_value (path, &free_path);
3624 date = printable_date (ver->date);
3625 value = xmalloc (strlen (path)
3626 + strlen (ver->version)
3628 + strlen (ver->author)
3629 + strlen (ver->state)
3630 + (locker == NULL ? 0 : strlen (locker))
3633 sprintf (value, "%s %s %s %s %s%s%s",
3634 path, ver->version, date, ver->author,
3636 locker != NULL ? " " : "",
3637 locker != NULL ? locker : "");
3639 /* If free_path is set then we know we allocated path
3640 * and we can discard the const.
3642 free ((char *)path);
3650 case KEYWORD_LOCKER:
3655 case KEYWORD_RCSFILE:
3656 value = escape_keyword_value (last_component (rcs->path),
3661 if (name != NULL && ! isdigit ((unsigned char) *name))
3662 value = (char *) name;
3667 case KEYWORD_REVISION:
3668 value = ver->version;
3671 case KEYWORD_SOURCE:
3672 value = escape_keyword_value (rcs->path, &free_value);
3681 sub = xmalloc (keyword->len
3682 + (value == NULL ? 0 : strlen (value))
3684 if (expand == KFLAG_V)
3686 /* Decrement SRCH and increment S to remove the $
3695 strcpy (sub, keyword->string);
3696 sublen = strlen (keyword->string);
3697 if (expand != KFLAG_K)
3700 sub[sublen + 1] = ' ';
3706 strcpy (sub + sublen, value);
3707 sublen += strlen (value);
3709 if (expand != KFLAG_V && expand != KFLAG_K)
3719 /* The Log keyword requires special handling. This behaviour
3720 is taken from RCS 5.7. The special log message is what RCS
3722 if (kw == KEYWORD_LOG
3723 && (sizeof "checked in with -k by " <= loglen
3725 || strncmp (log, "checked in with -k by ",
3726 sizeof "checked in with -k by " - 1) != 0))
3730 size_t leader_len, leader_sp_len;
3737 /* We are going to insert the trailing $ ourselves, before
3738 the log message, so we must remove it from S, if we
3739 haven't done so already. */
3740 if (expand != KFLAG_V)
3743 /* CVS never has empty log messages, but old RCS files might. */
3747 /* Find the start of the line. */
3749 while (start > buf && start[-1] != '\n')
3752 /* Copy the start of the line to use as a comment leader. */
3753 leader_len = srch - start;
3754 if (expand != KFLAG_V)
3756 leader = xmalloc (leader_len);
3757 memcpy (leader, start, leader_len);
3758 leader_sp_len = leader_len;
3759 while (leader_sp_len > 0 && leader[leader_sp_len - 1] == ' ')
3762 /* RCS does some checking for an old style of Log here,
3763 but we don't bother. RCS issues a warning if it
3764 changes anything. */
3766 /* Count the number of newlines in the log message so that
3767 we know how many copies of the leader we will need. */
3769 logend = log + loglen;
3770 for (snl = log; snl < logend; snl++)
3774 date = printable_date (ver->date);
3775 sub = xrealloc (sub,
3778 + strlen (ver->version)
3780 + strlen (ver->author)
3782 + (cnl + 2) * leader_len
3784 if (expand != KFLAG_V)
3791 memcpy (sub + sublen, leader, leader_len);
3792 sublen += leader_len;
3793 sprintf (sub + sublen, "Revision %s %s %s\n",
3794 ver->version, date, ver->author);
3795 sublen += strlen (sub + sublen);
3803 memcpy (sub + sublen, leader, leader_sp_len);
3804 sublen += leader_sp_len;
3813 memcpy (sub + sublen, leader, leader_len);
3814 sublen += leader_len;
3815 for (slnl = sl; slnl < logend && *slnl != '\n'; ++slnl)
3819 memcpy (sub + sublen, sl, slnl - sl);
3820 sublen += slnl - sl;
3825 memcpy (sub + sublen, leader, leader_sp_len);
3826 sublen += leader_sp_len;
3831 /* Now SUB contains a string which is to replace the string
3832 from SRCH to S. SUBLEN is the length of SUB. */
3834 if (srch + sublen == s)
3836 memcpy (srch, sub, sublen);
3841 struct expand_buffer *ebuf;
3843 /* We need to change the size of the buffer. We build a
3844 list of expand_buffer structures. Each expand_buffer
3845 structure represents a portion of the final output. We
3846 concatenate them back into a single buffer when we are
3847 done. This minimizes the number of potentially large
3848 buffer copies we must do. */
3852 ebufs = (struct expand_buffer *) xmalloc (sizeof *ebuf);
3855 ebufs->free_data = 0;
3856 ebuf_len = srch - buf;
3857 ebufs->len = ebuf_len;
3862 assert (srch >= ebuf_last->data);
3863 assert (srch <= ebuf_last->data + ebuf_last->len);
3864 ebuf_len -= ebuf_last->len - (srch - ebuf_last->data);
3865 ebuf_last->len = srch - ebuf_last->data;
3868 ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf);
3871 ebuf->free_data = 1;
3873 ebuf_last->next = ebuf;
3877 ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf);
3879 ebuf->len = srch_len - (s - srch);
3880 ebuf->free_data = 0;
3882 ebuf_last->next = ebuf;
3884 ebuf_len += srch_len - (s - srch);
3887 srch_len -= (s - srch);
3903 ret = xmalloc (ebuf_len);
3906 while (ebufs != NULL)
3908 struct expand_buffer *next;
3910 memcpy (ret, ebufs->data, ebufs->len);
3912 if (ebufs->free_data)
3923 /* Check out a revision from an RCS file.
3925 If PFN is not NULL, then ignore WORKFILE and SOUT. Call PFN zero
3926 or more times with the contents of the file. CALLERDAT is passed,
3927 uninterpreted, to PFN. (The current code will always call PFN
3928 exactly once for a non empty file; however, the current code
3929 assumes that it can hold the entire file contents in memory, which
3930 is not a good assumption, and might change in the future).
3932 Otherwise, if WORKFILE is not NULL, check out the revision to
3933 WORKFILE. However, if WORKFILE is not NULL, and noexec is set,
3934 then don't do anything.
3936 Otherwise, if WORKFILE is NULL, check out the revision to SOUT. If
3937 SOUT is RUN_TTY, then write the contents of the revision to
3938 standard output. When using SOUT, the output is generally a
3939 temporary file; don't bother to get the file modes correct.
3941 REV is the numeric revision to check out. It may be NULL, which
3942 means to check out the head of the default branch.
3944 If NAMETAG is not NULL, and is not a numeric revision, then it is
3945 the tag that should be used when expanding the RCS Name keyword.
3947 OPTIONS is a string such as "-kb" or "-kv" for keyword expansion
3948 options. It may be NULL to use the default expansion mode of the
3949 file, typically "-kkv".
3951 On an error which prevented checking out the file, either print a
3952 nonfatal error and return 1, or give a fatal error. On success,
3955 /* This function mimics the behavior of `rcs co' almost exactly. The
3956 chief difference is in its support for preserving file ownership,
3957 permissions, and special files across checkin and checkout -- see
3958 comments in RCS_checkin for some issues about this. -twp */
3961 RCS_checkout (RCSNode *rcs, const char *workfile, const char *rev,
3962 const char *nametag, const char *options, const char *sout,
3963 RCSCHECKOUTPROC pfn, void *callerdat)
3969 struct rcsbuffer rcsbuf;
3977 #ifdef PRESERVE_PERMISSIONS_SUPPORT
3978 uid_t rcs_owner = (uid_t) -1;
3979 gid_t rcs_group = (gid_t) -1;
3981 int change_rcs_owner_or_group = 0;
3982 int change_rcs_mode = 0;
3983 int special_file = 0;
3984 unsigned long devnum_long;
3988 TRACE ( 1, "RCS_checkout (%s, %s, %s, %s, %s)",
3990 rev != NULL ? rev : "",
3991 nametag != NULL ? nametag : "",
3992 options != NULL ? options : "",
3993 (pfn != NULL ? "(function)"
3994 : (workfile != NULL ? workfile
3995 : (sout != RUN_TTY ? sout
3996 : "(stdout)" ) ) ) );
3998 assert (rev == NULL || isdigit ((unsigned char) *rev));
4000 if (noexec && workfile != NULL)
4003 assert (sout == RUN_TTY || workfile == NULL);
4004 assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL));
4006 /* Some callers, such as Checkin or remove_file, will pass us a
4008 if (rev != NULL && (numdots (rev) & 1) == 0)
4010 rev = RCS_getbranch (rcs, rev, 1);
4012 error (1, 0, "internal error: bad branch tag in checkout");
4016 if (rev == NULL || STREQ (rev, rcs->head))
4020 /* We want the head revision. Try to read it directly. */
4022 if (rcs->flags & PARTIAL)
4023 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
4025 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf);
4028 if (! rcsbuf_getrevnum (&rcsbuf, &key))
4029 error (1, 0, "unexpected EOF reading %s", rcs->path);
4030 while (rcsbuf_getkey (&rcsbuf, &key, &value))
4032 if (STREQ (key, "log"))
4033 log = rcsbuf_valcopy (&rcsbuf, value, 0, &loglen);
4034 else if (STREQ (key, "text"))
4043 error (0, 0, "internal error: cannot find head text");
4045 /* It's okay to discard the const when free_rev is set, because
4046 * we know we allocated it in this function.
4052 rcsbuf_valpolish (&rcsbuf, value, 0, &len);
4054 if (fstat (fileno (fp), &sb) < 0)
4055 error (1, errno, "cannot fstat %s", rcs->path);
4057 rcsbuf_cache (rcs, &rcsbuf);
4061 struct rcsbuffer *rcsbufp;
4063 /* It isn't the head revision of the trunk. We'll need to
4064 walk through the deltas. */
4067 if (rcs->flags & PARTIAL)
4068 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
4072 /* If RCS_deltas didn't close the file, we could use fstat
4073 here too. Probably should change it thusly.... */
4074 if( CVS_STAT( rcs->path, &sb ) < 0 )
4075 error (1, errno, "cannot stat %s", rcs->path);
4080 if (fstat (fileno (fp), &sb) < 0)
4081 error (1, errno, "cannot fstat %s", rcs->path);
4085 RCS_deltas (rcs, fp, rcsbufp, rev, RCS_FETCH, &value, &len,
4090 /* If OPTIONS is NULL or the empty string, then the old code would
4091 invoke the RCS co program with no -k option, which means that
4092 co would use the string we have stored in rcs->expand. */
4093 if ((options == NULL || options[0] == '\0') && rcs->expand == NULL)
4097 const char *ouroptions;
4098 const char * const *cpp;
4100 if (options != NULL && options[0] != '\0')
4102 assert (options[0] == '-' && options[1] == 'k');
4103 ouroptions = options + 2;
4106 ouroptions = rcs->expand;
4108 for (cpp = kflags; *cpp != NULL; cpp++)
4109 if (STREQ (*cpp, ouroptions))
4113 expand = (enum kflag) (cpp - kflags);
4117 "internal error: unsupported substitution string -k%s",
4123 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4124 /* Handle special files and permissions, if that is desired. */
4130 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
4132 error (1, 0, "internal error: no revision information for %s",
4133 rev == NULL ? rcs->head : rev);
4136 /* First we look for symlinks, which are simplest to handle. */
4137 info = findnode (vers->other_delta, "symlink");
4142 if (pfn != NULL || (workfile == NULL && sout == RUN_TTY))
4143 error (1, 0, "symbolic link %s:%s cannot be piped",
4144 rcs->path, vers->version);
4145 if (workfile == NULL)
4150 /* Remove `dest', just in case. It's okay to get ENOENT here,
4151 since we just want the file not to be there. (TODO: decide
4152 whether it should be considered an error for `dest' to exist
4153 at this point. If so, the unlink call should be removed and
4154 `symlink' should signal the error. -twp) */
4155 if (CVS_UNLINK (dest) < 0 && !existence_error (errno))
4156 error (1, errno, "cannot remove %s", dest);
4157 if (symlink (info->data, dest) < 0)
4158 error (1, errno, "cannot create symbolic link from %s to %s",
4159 dest, (char *)info->data);
4163 /* It's okay to discard the const when free_rev is set, because
4164 * we know we allocated it in this function.
4170 /* Next, we look at this file's hardlinks field, and see whether
4171 it is linked to any other file that has been checked out.
4172 If so, we don't do anything else -- just link it to that file.
4174 If we are checking out a file to a pipe or temporary storage,
4175 none of this should matter. Hence the `workfile != NULL'
4176 wrapper around the whole thing. -twp */
4178 if (workfile != NULL)
4180 List *links = vers->hardlinks;
4183 Node *uptodate_link;
4185 /* For each file in the hardlinks field, check to see
4186 if it exists, and if so, if it has been checked out
4187 this iteration. When walklist returns, uptodate_link
4188 should point to a hardlist node representing a file
4189 in `links' which has recently been checked out, or
4190 NULL if no file in `links' has yet been checked out. */
4192 uptodate_link = NULL;
4193 (void) walklist (links, find_checkedout_proc, &uptodate_link);
4196 /* If we've found a file that `workfile' is supposed to be
4197 linked to, and it has been checked out since CVS was
4198 invoked, then simply link workfile to that file and return.
4200 If one of these conditions is not met, then
4201 workfile is the first one in its hardlink group to
4202 be checked out, and we must continue with a full
4205 if (uptodate_link != NULL)
4207 struct hardlink_info *hlinfo = uptodate_link->data;
4209 if (link (uptodate_link->key, workfile) < 0)
4210 error (1, errno, "cannot link %s to %s",
4211 workfile, uptodate_link->key);
4212 hlinfo->checked_out = 1; /* probably unnecessary */
4216 /* It's okay to discard the const when free_rev is set,
4217 * because we know we allocated it in this function.
4225 info = findnode (vers->other_delta, "owner");
4228 change_rcs_owner_or_group = 1;
4229 rcs_owner = (uid_t) strtoul (info->data, NULL, 10);
4231 info = findnode (vers->other_delta, "group");
4234 change_rcs_owner_or_group = 1;
4235 rcs_group = (gid_t) strtoul (info->data, NULL, 10);
4237 info = findnode (vers->other_delta, "permissions");
4240 change_rcs_mode = 1;
4241 rcs_mode = (mode_t) strtoul (info->data, NULL, 8);
4243 info = findnode (vers->other_delta, "special");
4246 /* If the size of `devtype' changes, fix the sscanf call also */
4249 if (sscanf (info->data, "%15s %lu",
4250 devtype, &devnum_long) < 2)
4251 error (1, 0, "%s:%s has bad `special' newphrase %s",
4252 workfile, vers->version, (char *)info->data);
4253 devnum = devnum_long;
4254 if (STREQ (devtype, "character"))
4255 special_file = S_IFCHR;
4256 else if (STREQ (devtype, "block"))
4257 special_file = S_IFBLK;
4259 error (0, 0, "%s is a special file of unsupported type `%s'",
4260 workfile, (char *)info->data);
4263 #endif /* PRESERVE_PERMISSIONS_SUPPORT */
4265 if (expand != KFLAG_O && expand != KFLAG_B)
4269 /* Don't fetch the delta node again if we already have it. */
4272 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
4274 error (1, 0, "internal error: no revision information for %s",
4275 rev == NULL ? rcs->head : rev);
4278 expand_keywords (rcs, vp->data, nametag, log, loglen,
4279 expand, value, len, &newvalue, &len);
4281 if (newvalue != value)
4291 /* It's okay to discard the const when free_rev is set, because
4292 * we know we allocated it in this function.
4304 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4306 error (1, 0, "special file %s cannot be piped to anything",
4309 /* The PFN interface is very simple to implement right now, as
4310 we always have the entire file in memory. */
4312 pfn (callerdat, value, len);
4314 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4315 else if (special_file)
4320 /* Can send either to WORKFILE or to SOUT, as long as SOUT is
4325 if (sout == RUN_TTY)
4326 error (1, 0, "special file %s cannot be written to stdout",
4331 /* Unlink `dest', just in case. It's okay if this provokes a
4333 if (CVS_UNLINK (dest) < 0 && existence_error (errno))
4334 error (1, errno, "cannot remove %s", dest);
4335 if (mknod (dest, special_file, devnum) < 0)
4336 error (1, errno, "could not create special file %s",
4340 "cannot create %s: unable to create special files on this system",
4347 /* Not a special file: write to WORKFILE or SOUT. */
4348 if (workfile == NULL)
4350 if (sout == RUN_TTY)
4354 /* Symbolic links should be removed before replacement, so that
4355 `fopen' doesn't follow the link and open the wrong file. */
4357 if (unlink_file (sout) < 0)
4358 error (1, errno, "cannot remove %s", sout);
4359 ofp = CVS_FOPEN (sout, expand == KFLAG_B ? "wb" : "w");
4361 error (1, errno, "cannot open %s", sout);
4366 /* Output is supposed to go to WORKFILE, so we should open that
4367 file. Symbolic links should be removed first (see above). */
4368 if (islink (workfile))
4369 if (unlink_file (workfile) < 0)
4370 error (1, errno, "cannot remove %s", workfile);
4372 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
4374 /* If the open failed because the existing workfile was not
4375 writable, try to chmod the file and retry the open. */
4376 if (ofp == NULL && errno == EACCES
4377 && isfile (workfile) && !iswritable (workfile))
4379 xchmod (workfile, 1);
4380 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
4385 error (0, errno, "cannot open %s", workfile);
4392 if (workfile == NULL && sout == RUN_TTY)
4394 if (expand == KFLAG_B)
4395 cvs_output_binary (value, len);
4398 /* cvs_output requires the caller to check for zero
4401 cvs_output (value, len);
4406 /* NT 4.0 is said to have trouble writing 2099999 bytes
4407 (for example) in a single fwrite. So break it down
4408 (there is no need to be writing that much at once
4409 anyway; it is possible that LARGEST_FWRITE should be
4410 somewhat larger for good performance, but for testing I
4411 want to start with a small value until/unless a bigger
4412 one proves useful). */
4413 #define LARGEST_FWRITE 8192
4415 size_t nstep = (len < LARGEST_FWRITE ? len : LARGEST_FWRITE);
4420 if (fwrite (p, 1, nstep, ofp) != nstep)
4422 error (0, errno, "cannot write %s",
4425 : (sout != RUN_TTY ? sout : "stdout")));
4441 if (workfile != NULL)
4445 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4446 if (!special_file && fclose (ofp) < 0)
4448 error (0, errno, "cannot close %s", workfile);
4452 if (change_rcs_owner_or_group)
4454 if (chown (workfile, rcs_owner, rcs_group) < 0)
4455 error (0, errno, "could not change owner or group of %s",
4459 ret = chmod (workfile,
4462 : sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
4464 if (fclose (ofp) < 0)
4466 error (0, errno, "cannot close %s", workfile);
4470 ret = chmod (workfile,
4471 sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
4475 error (0, errno, "cannot change mode of file %s",
4479 else if (sout != RUN_TTY)
4482 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4487 error (0, errno, "cannot close %s", sout);
4492 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4493 /* If we are in the business of preserving hardlinks, then
4494 mark this file as having been checked out. */
4495 if (preserve_perms && workfile != NULL)
4496 update_hardlink_info (workfile);
4502 static RCSVers *RCS_findlock_or_tip (RCSNode *rcs);
4504 /* Find the delta currently locked by the user. From the `ci' man page:
4506 "If rev is omitted, ci tries to derive the new revision
4507 number from the caller's last lock. If the caller has
4508 locked the tip revision of a branch, the new revision is
4509 appended to that branch. The new revision number is
4510 obtained by incrementing the tip revision number. If the
4511 caller locked a non-tip revision, a new branch is started
4512 at that revision by incrementing the highest branch number
4513 at that revision. The default initial branch and level
4516 If rev is omitted and the caller has no lock, but owns the
4517 file and locking is not set to strict, then the revision
4518 is appended to the default branch (normally the trunk; see
4519 the -b option of rcs(1))."
4521 RCS_findlock_or_tip finds the unique revision locked by the caller
4522 and returns its delta node. If the caller has not locked any
4523 revisions (and is permitted to commit to an unlocked delta, as
4524 described above), return the tip of the default branch. */
4527 RCS_findlock_or_tip (RCSNode *rcs)
4529 char *user = getcaller();
4533 /* Find unique delta locked by caller. This code is very similar
4534 to the code in RCS_unlock -- perhaps it could be abstracted
4535 into a RCS_findlock function. */
4536 locklist = RCS_getlocks (rcs);
4538 for (p = locklist->list->next; p != locklist->list; p = p->next)
4540 if (STREQ (p->data, user))
4545 %s: multiple revisions locked by %s; please specify one", rcs->path, user);
4554 /* Found an old lock, but check that the revision still exists. */
4555 p = findnode (rcs->versions, lock->key);
4558 error (0, 0, "%s: can't unlock nonexistent revision %s",
4566 /* No existing lock. The RCS rule is that this is an error unless
4567 locking is nonstrict AND the file is owned by the current
4568 user. Trying to determine the latter is a portability nightmare
4569 in the face of NT, VMS, AFS, and other systems with non-unix-like
4570 ideas of users and owners. In the case of CVS, we should never get
4571 here (as long as the traditional behavior of making sure to call
4572 RCS_lock persists). Anyway, we skip the RCS error checks
4573 and just return the default branch or head. The reasoning is that
4574 those error checks are to make users lock before a checkin, and we do
4575 that in other ways if at all anyway (e.g. rcslock.pl). */
4577 p = findnode (rcs->versions, RCS_getbranch (rcs, rcs->branch, 0));
4581 /* Revision number string, R, must contain a `.'.
4582 Return a newly-malloc'd copy of the prefix of R up
4583 to but not including the final `.'. */
4586 truncate_revnum (const char *r)
4590 char *dot = strrchr (r, '.');
4594 new_r = xmalloc (len + 1);
4595 memcpy (new_r, r, len);
4596 *(new_r + len) = '\0';
4600 /* Revision number string, R, must contain a `.'.
4601 R must be writable. Replace the rightmost `.' in R with
4602 the NUL byte and return a pointer to that NUL byte. */
4605 truncate_revnum_in_place (char *r)
4607 char *dot = strrchr (r, '.');
4613 /* Revision number strings, R and S, must each contain a `.'.
4614 R and S must be writable and must have the same number of dots.
4615 Truncate R and S for the comparison, then restored them to their
4617 Return the result (see compare_revnums) of comparing R and S
4618 ignoring differences in any component after the rightmost `.'. */
4621 compare_truncated_revnums (char *r, char *s)
4623 char *r_dot = truncate_revnum_in_place (r);
4624 char *s_dot = truncate_revnum_in_place (s);
4627 assert (numdots (r) == numdots (s));
4629 cmp = compare_revnums (r, s);
4637 /* Return a malloc'd copy of the string representing the highest branch
4638 number on BRANCHNODE. If there are no branches on BRANCHNODE, return NULL.
4639 FIXME: isn't the max rev always the last one?
4640 If so, we don't even need a loop. */
4642 static char *max_rev (const RCSVers *);
4645 max_rev (const RCSVers *branchnode)
4651 if (branchnode->branches == NULL)
4657 head = branchnode->branches->list;
4658 for (bp = head->next; bp != head; bp = bp->next)
4660 if (max == NULL || compare_truncated_revnums (max, bp->key) < 0)
4667 return truncate_revnum (max);
4670 /* Create BRANCH in RCS's delta tree. BRANCH may be either a branch
4671 number or a revision number. In the former case, create the branch
4672 with the specified number; in the latter case, create a new branch
4673 rooted at node BRANCH with a higher branch number than any others.
4674 Return the number of the tip node on the new branch. */
4677 RCS_addbranch (RCSNode *rcs, const char *branch)
4679 char *branchpoint, *newrevnum;
4682 RCSVers *branchnode;
4684 /* Append to end by default. */
4687 branchpoint = xstrdup (branch);
4688 if ((numdots (branchpoint) & 1) == 0)
4690 truncate_revnum_in_place (branchpoint);
4693 /* Find the branch rooted at BRANCHPOINT. */
4694 nodep = findnode (rcs->versions, branchpoint);
4697 error (0, 0, "%s: can't find branch point %s", rcs->path, branchpoint);
4702 branchnode = nodep->data;
4704 /* If BRANCH was a full branch number, make sure it is higher than MAX. */
4705 if ((numdots (branch) & 1) == 1)
4707 if (branchnode->branches == NULL)
4709 /* We have to create the first branch on this node, which means
4710 appending ".2" to the revision number. */
4711 newrevnum = (char *) xmalloc (strlen (branch) + 3);
4712 strcpy (newrevnum, branch);
4713 strcat (newrevnum, ".2");
4717 char *max = max_rev (branchnode);
4719 newrevnum = increment_revnum (max);
4725 newrevnum = xstrdup (branch);
4727 if (branchnode->branches != NULL)
4732 /* Find the position of this new branch in the sorted list
4734 head = branchnode->branches->list;
4735 for (bp = head->next; bp != head; bp = bp->next)
4740 /* The existing list must be sorted on increasing revnum. */
4741 assert (bp->next == head
4742 || compare_truncated_revnums (bp->key,
4743 bp->next->key) < 0);
4744 dot = truncate_revnum_in_place (bp->key);
4745 found_pos = (compare_revnums (branch, bp->key) < 0);
4757 newrevnum = (char *) xrealloc (newrevnum, strlen (newrevnum) + 3);
4758 strcat (newrevnum, ".1");
4760 /* Add this new revision number to BRANCHPOINT's branches list. */
4761 if (branchnode->branches == NULL)
4762 branchnode->branches = getlist();
4764 bp->key = xstrdup (newrevnum);
4766 /* Append to the end of the list by default, that is, just before
4767 the header node, `list'. */
4769 marker = branchnode->branches->list;
4773 fail = insert_before (branchnode->branches, marker, bp);
4780 /* Check in to RCSFILE with revision REV (which must be greater than
4781 the largest revision) and message MESSAGE (which is checked for
4782 validity). If FLAGS & RCS_FLAGS_DEAD, check in a dead revision.
4783 If FLAGS & RCS_FLAGS_QUIET, tell ci to be quiet. If FLAGS &
4784 RCS_FLAGS_MODTIME, use the working file's modification time for the
4785 checkin time. WORKFILE is the working file to check in from, or
4786 NULL to use the usual RCS rules for deriving it from the RCSFILE.
4787 If FLAGS & RCS_FLAGS_KEEPFILE, don't unlink the working file;
4788 unlinking the working file is standard RCS behavior, but is rarely
4789 appropriate for CVS.
4791 This function should almost exactly mimic the behavior of `rcs ci'. The
4792 principal point of difference is the support here for preserving file
4793 ownership and permissions in the delta nodes. This is not a clean
4794 solution -- precisely because it diverges from RCS's behavior -- but
4795 it doesn't seem feasible to do this anywhere else in the code. [-twp]
4797 Return value is -1 for error (and errno is set to indicate the
4798 error), positive for error (and an error message has been printed),
4799 or zero for success. */
4802 RCS_checkin (RCSNode *rcs, const char *workfile_in, const char *message,
4803 const char *rev, int flags)
4805 RCSVers *delta, *commitpt;
4808 char *tmpfile, *changefile;
4811 int status, checkin_quiet;
4814 int adding_branch = 0;
4815 char *workfile = xstrdup (workfile_in);
4816 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4822 if (rcs->flags & PARTIAL)
4823 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
4825 /* Get basename of working file. Is there a library function to
4826 do this? I couldn't find one. -twp */
4827 if (workfile == NULL)
4830 int extlen = strlen (RCSEXT);
4831 workfile = xstrdup (last_component (rcs->path));
4832 p = workfile + (strlen (workfile) - extlen);
4833 assert (strncmp (p, RCSEXT, extlen) == 0);
4837 /* If the filename is a symbolic link, follow it and replace it
4838 with the destination of the link. We need to do this before
4839 calling rcs_internal_lockfile, or else we won't put the lock in
4841 resolve_symlink (&(rcs->path));
4843 checkin_quiet = flags & RCS_FLAGS_QUIET;
4844 if (!(checkin_quiet || really_quiet))
4846 cvs_output (rcs->path, 0);
4847 cvs_output (" <-- ", 7);
4848 cvs_output (workfile, 0);
4849 cvs_output ("\n", 1);
4852 /* Create new delta node. */
4853 delta = (RCSVers *) xmalloc (sizeof (RCSVers));
4854 memset (delta, 0, sizeof (RCSVers));
4855 delta->author = xstrdup (getcaller ());
4856 if (flags & RCS_FLAGS_MODTIME)
4859 if( CVS_STAT( workfile, &ws ) < 0 )
4861 error (1, errno, "cannot stat %s", workfile);
4863 modtime = ws.st_mtime;
4866 (void) time (&modtime);
4867 ftm = gmtime (&modtime);
4868 delta->date = (char *) xmalloc (MAXDATELEN);
4869 (void) sprintf (delta->date, DATEFORM,
4870 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
4871 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
4872 ftm->tm_min, ftm->tm_sec);
4873 if (flags & RCS_FLAGS_DEAD)
4875 delta->state = xstrdup (RCSDEAD);
4879 delta->state = xstrdup ("Exp");
4881 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4882 /* If permissions should be preserved on this project, then
4883 save the permission info. */
4887 char buf[64]; /* static buffer should be safe: see usage. -twp */
4889 delta->other_delta = getlist();
4891 if (CVS_LSTAT (workfile, &sb) < 0)
4892 error (1, errno, "cannot lstat %s", workfile);
4894 if (S_ISLNK (sb.st_mode))
4897 np->type = RCSFIELD;
4898 np->key = xstrdup ("symlink");
4899 np->data = xreadlink (workfile);
4900 addnode (delta->other_delta, np);
4904 (void) sprintf (buf, "%u", sb.st_uid);
4906 np->type = RCSFIELD;
4907 np->key = xstrdup ("owner");
4908 np->data = xstrdup (buf);
4909 addnode (delta->other_delta, np);
4911 (void) sprintf (buf, "%u", sb.st_gid);
4913 np->type = RCSFIELD;
4914 np->key = xstrdup ("group");
4915 np->data = xstrdup (buf);
4916 addnode (delta->other_delta, np);
4918 (void) sprintf (buf, "%o", sb.st_mode & 07777);
4920 np->type = RCSFIELD;
4921 np->key = xstrdup ("permissions");
4922 np->data = xstrdup (buf);
4923 addnode (delta->other_delta, np);
4925 /* Save device number. */
4926 switch (sb.st_mode & S_IFMT)
4928 case S_IFREG: break;
4931 # ifdef HAVE_STRUCT_STAT_ST_RDEV
4933 np->type = RCSFIELD;
4934 np->key = xstrdup ("special");
4935 sprintf (buf, "%s %lu",
4936 ((sb.st_mode & S_IFMT) == S_IFCHR
4937 ? "character" : "block"),
4938 (unsigned long) sb.st_rdev);
4939 np->data = xstrdup (buf);
4940 addnode (delta->other_delta, np);
4943 "can't preserve %s: unable to save device files on this system",
4949 error (0, 0, "special file %s has unknown type", workfile);
4952 /* Save hardlinks. */
4953 delta->hardlinks = list_linked_files_on_disk (workfile);
4958 /* Create a new deltatext node. */
4959 dtext = (Deltatext *) xmalloc (sizeof (Deltatext));
4960 memset (dtext, 0, sizeof (Deltatext));
4962 dtext->log = make_message_rcsvalid (message);
4964 /* If the delta tree is empty, then there's nothing to link the
4965 new delta into. So make a new delta tree, snarf the working
4966 file contents, and just write the new RCS file. */
4967 if (rcs->head == NULL)
4972 /* Figure out what the first revision number should be. */
4973 if (rev == NULL || *rev == '\0')
4974 newrev = xstrdup ("1.1");
4975 else if (numdots (rev) == 0)
4977 newrev = (char *) xmalloc (strlen (rev) + 3);
4978 strcpy (newrev, rev);
4979 strcat (newrev, ".1");
4982 newrev = xstrdup (rev);
4984 /* Don't need to xstrdup NEWREV because it's already dynamic, and
4985 not used for anything else. (Don't need to free it, either.) */
4987 delta->version = xstrdup (newrev);
4989 nodep->type = RCSVERS;
4990 nodep->delproc = rcsvers_delproc;
4991 nodep->data = delta;
4992 nodep->key = delta->version;
4993 (void) addnode (rcs->versions, nodep);
4995 dtext->version = xstrdup (newrev);
4997 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4998 if (preserve_perms && !S_ISREG (sb.st_mode))
4999 /* Pretend file is empty. */
5003 get_file (workfile, workfile,
5004 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5005 &dtext->text, &bufsize, &dtext->len);
5007 if (!(checkin_quiet || really_quiet))
5009 cvs_output ("initial revision: ", 0);
5010 cvs_output (rcs->head, 0);
5011 cvs_output ("\n", 1);
5014 /* We are probably about to invalidate any cached file. */
5015 rcsbuf_cache_close ();
5017 fout = rcs_internal_lockfile (rcs->path);
5018 RCS_putadmin (rcs, fout);
5019 RCS_putdtree (rcs, rcs->head, fout);
5020 RCS_putdesc (rcs, fout);
5021 rcs->delta_pos = ftello (fout);
5022 if (rcs->delta_pos == -1)
5023 error (1, errno, "cannot ftello for %s", rcs->path);
5024 putdeltatext (fout, dtext);
5025 rcs_internal_unlockfile (fout, rcs->path);
5027 if ((flags & RCS_FLAGS_KEEPFILE) == 0)
5029 if (unlink_file (workfile) < 0)
5030 /* FIXME-update-dir: message does not include update_dir. */
5031 error (0, errno, "cannot remove %s", workfile);
5038 /* Derive a new revision number. From the `ci' man page:
5040 "If rev is a revision number, it must be higher than the
5041 latest one on the branch to which rev belongs, or must
5044 If rev is a branch rather than a revision number, the new
5045 revision is appended to that branch. The level number is
5046 obtained by incrementing the tip revision number of that
5047 branch. If rev indicates a non-existing branch, that
5048 branch is created with the initial revision numbered
5051 RCS_findlock_or_tip handles the case where REV is omitted.
5052 RCS 5.7 also permits REV to be "$" or to begin with a dot, but
5053 we do not address those cases -- every routine that calls
5054 RCS_checkin passes it a numeric revision. */
5056 if (rev == NULL || *rev == '\0')
5058 /* Figure out where the commit point is by looking for locks.
5059 If the commit point is at the tip of a branch (or is the
5060 head of the delta tree), then increment its revision number
5061 to obtain the new revnum. Otherwise, start a new
5063 commitpt = RCS_findlock_or_tip (rcs);
5064 if (commitpt == NULL)
5069 else if (commitpt->next == NULL
5070 || STREQ (commitpt->version, rcs->head))
5071 delta->version = increment_revnum (commitpt->version);
5073 delta->version = RCS_addbranch (rcs, commitpt->version);
5077 /* REV is either a revision number or a branch number. Find the
5078 tip of the target branch. */
5079 char *branch, *tip, *newrev, *p;
5082 assert (isdigit ((unsigned char) *rev));
5084 newrev = xstrdup (rev);
5085 dots = numdots (newrev);
5086 isrevnum = dots & 1;
5088 branch = xstrdup (rev);
5091 p = strrchr (branch, '.');
5095 /* Find the tip of the target branch. If we got a one- or two-digit
5096 revision number, this will be the head of the tree. Exception:
5097 if rev is a single-field revision equal to the branch number of
5098 the trunk (usually "1") then we want to treat it like an ordinary
5102 tip = xstrdup (rcs->head);
5103 if (atoi (tip) != atoi (branch))
5105 newrev = (char *) xrealloc (newrev, strlen (newrev) + 3);
5106 strcat (newrev, ".1");
5107 dots = isrevnum = 1;
5111 tip = xstrdup (rcs->head);
5113 tip = RCS_getbranch (rcs, branch, 1);
5115 /* If the branch does not exist, and we were supplied an exact
5116 revision number, signal an error. Otherwise, if we were
5117 given only a branch number, create it and set COMMITPT to
5118 the branch point. */
5123 error (0, 0, "%s: can't find branch point %s",
5130 delta->version = RCS_addbranch (rcs, branch);
5131 if (!delta->version)
5139 p = strrchr (branch, '.');
5141 tip = xstrdup (branch);
5147 /* NEWREV must be higher than TIP. */
5148 if (compare_revnums (tip, newrev) >= 0)
5151 "%s: revision %s too low; must be higher than %s",
5160 delta->version = xstrdup (newrev);
5163 /* Just increment the tip number to get the new revision. */
5164 delta->version = increment_revnum (tip);
5167 nodep = findnode (rcs->versions, tip);
5168 commitpt = nodep->data;
5175 assert (delta->version != NULL);
5177 /* If COMMITPT is locked by us, break the lock. If it's locked
5178 by someone else, signal an error. */
5179 nodep = findnode (RCS_getlocks (rcs), commitpt->version);
5182 if (! STREQ (nodep->data, delta->author))
5184 /* If we are adding a branch, then leave the old lock around.
5185 That is sensible in the sense that when adding a branch,
5186 we don't need to use the lock to tell us where to check
5187 in. It is fishy in the sense that if it is our own lock,
5188 we break it. However, this is the RCS 5.7 behavior (at
5189 the end of addbranch in ci.c in RCS 5.7, it calls
5190 removelock only if it is our own lock, not someone
5195 error (0, 0, "%s: revision %s locked by %s",
5197 nodep->key, (char *)nodep->data);
5206 dtext->version = xstrdup (delta->version);
5208 /* Obtain the change text for the new delta. If DELTA is to be the
5209 new head of the tree, then its change text should be the contents
5210 of the working file, and LEAFNODE's change text should be a diff.
5211 Else, DELTA's change text should be a diff between LEAFNODE and
5212 the working file. */
5214 tmpfile = cvs_temp_name();
5215 status = RCS_checkout (rcs, NULL, commitpt->version, NULL,
5216 ((rcs->expand != NULL
5217 && STREQ (rcs->expand, "b"))
5221 (RCSCHECKOUTPROC)0, NULL);
5224 "could not check out revision %s of `%s'",
5225 commitpt->version, rcs->path);
5228 changefile = cvs_temp_name();
5230 /* Diff options should include --binary if the RCS file has -kb set
5231 in its `expand' field. */
5232 diffopts = (rcs->expand != NULL && STREQ (rcs->expand, "b")
5236 if (STREQ (commitpt->version, rcs->head) &&
5237 numdots (delta->version) == 1)
5239 /* If this revision is being inserted on the trunk, the change text
5240 for the new delta should be the contents of the working file ... */
5242 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5243 if (preserve_perms && !S_ISREG (sb.st_mode))
5244 /* Pretend file is empty. */
5248 get_file (workfile, workfile,
5249 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5250 &dtext->text, &bufsize, &dtext->len);
5252 /* ... and the change text for the old delta should be a diff. */
5253 commitpt->text = (Deltatext *) xmalloc (sizeof (Deltatext));
5254 memset (commitpt->text, 0, sizeof (Deltatext));
5257 switch (diff_exec (workfile, tmpfile, NULL, NULL, diffopts, changefile))
5263 /* FIXME-update-dir: message does not include update_dir. */
5264 error (1, errno, "error diffing %s", workfile);
5267 /* FIXME-update-dir: message does not include update_dir. */
5268 error (1, 0, "error diffing %s", workfile);
5272 /* OK, the text file case here is really dumb. Logically
5273 speaking we want diff to read the files in text mode,
5274 convert them to the canonical form found in RCS files
5275 (which, we hope at least, is independent of OS--always
5276 bare linefeeds), and then work with change texts in that
5277 format. However, diff_exec both generates change
5278 texts and produces output for user purposes (e.g. patch.c),
5279 and there is no way to distinguish between the two cases.
5280 So we actually implement the text file case by writing the
5281 change text as a text file, then reading it as a text file.
5282 This should cause no harm, but doesn't strike me as
5284 get_file (changefile, changefile,
5285 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5286 &commitpt->text->text, &bufsize, &commitpt->text->len);
5288 /* If COMMITPT->TEXT->TEXT is NULL, it means that CHANGEFILE
5289 was empty and that there are no differences between revisions.
5290 In that event, we want to force RCS_rewrite to write an empty
5291 string for COMMITPT's change text. Leaving the change text
5292 field set NULL won't work, since that means "preserve the original
5293 change text for this delta." */
5294 if (commitpt->text->text == NULL)
5296 commitpt->text->text = xstrdup ("");
5297 commitpt->text->len = 0;
5302 /* This file is not being inserted at the head, but on a side
5303 branch somewhere. Make a diff from the previous revision
5304 to the working file. */
5305 switch (diff_exec (tmpfile, workfile, NULL, NULL, diffopts, changefile))
5311 /* FIXME-update-dir: message does not include update_dir. */
5312 error (1, errno, "error diffing %s", workfile);
5315 /* FIXME-update-dir: message does not include update_dir. */
5316 error (1, 0, "error diffing %s", workfile);
5319 /* See the comment above, at the other get_file invocation,
5320 regarding binary vs. text. */
5321 get_file (changefile, changefile,
5322 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5323 &dtext->text, &bufsize,
5325 if (dtext->text == NULL)
5327 dtext->text = xstrdup ("");
5332 /* Update DELTA linkage. It is important not to do this before
5333 the very end of RCS_checkin; if an error arises that forces
5334 us to abort checking in, we must not have malformed deltas
5335 partially linked into the tree.
5337 If DELTA and COMMITPT are on different branches, do nothing --
5338 DELTA is linked to the tree through COMMITPT->BRANCHES, and we
5339 don't want to change `next' pointers.
5341 Otherwise, if the nodes are both on the trunk, link DELTA to
5342 COMMITPT; otherwise, link COMMITPT to DELTA. */
5344 if (numdots (commitpt->version) == numdots (delta->version))
5346 if (STREQ (commitpt->version, rcs->head))
5348 delta->next = rcs->head;
5349 rcs->head = xstrdup (delta->version);
5352 commitpt->next = xstrdup (delta->version);
5355 /* Add DELTA to RCS->VERSIONS. */
5356 if (rcs->versions == NULL)
5357 rcs->versions = getlist();
5359 nodep->type = RCSVERS;
5360 nodep->delproc = rcsvers_delproc;
5361 nodep->data = delta;
5362 nodep->key = delta->version;
5363 (void) addnode (rcs->versions, nodep);
5365 /* Write the new RCS file, inserting the new delta at COMMITPT. */
5366 if (!(checkin_quiet || really_quiet))
5368 cvs_output ("new revision: ", 14);
5369 cvs_output (delta->version, 0);
5370 cvs_output ("; previous revision: ", 21);
5371 cvs_output (commitpt->version, 0);
5372 cvs_output ("\n", 1);
5375 RCS_rewrite (rcs, dtext, commitpt->version);
5377 if ((flags & RCS_FLAGS_KEEPFILE) == 0)
5379 if (unlink_file (workfile) < 0)
5380 /* FIXME-update-dir: message does not include update_dir. */
5381 error (1, errno, "cannot remove %s", workfile);
5383 if (unlink_file (tmpfile) < 0)
5384 error (0, errno, "cannot remove %s", tmpfile);
5386 if (unlink_file (changefile) < 0)
5387 error (0, errno, "cannot remove %s", changefile);
5393 if (commitpt != NULL && commitpt->text != NULL)
5395 freedeltatext (commitpt->text);
5396 commitpt->text = NULL;
5399 freedeltatext (dtext);
5401 free_rcsvers_contents (delta);
5408 /* This structure is passed between RCS_cmp_file and cmp_file_buffer. */
5409 struct cmp_file_data
5411 const char *filename;
5416 /* Compare the contents of revision REV1 of RCS file RCS with the
5417 contents of REV2 if given, otherwise, compare with the contents of
5418 the file FILENAME. OPTIONS is a string for the keyword
5419 expansion options. Return 0 if the contents of the revision are
5420 the same as the contents of the file, 1 if they are different. */
5422 RCS_cmp_file (RCSNode *rcs, const char *rev1, char **rev1_cache,
5423 const char *rev2, const char *options, const char *filename)
5427 TRACE (TRACE_FUNCTION, "RCS_cmp_file( %s, %s, %s, %s, %s )",
5428 rcs->path ? rcs->path : "(null)",
5429 rev1 ? rev1 : "(null)", rev2 ? rev2 : "(null)",
5430 options ? options : "(null)", filename ? filename : "(null)");
5432 if (options != NULL && options[0] != '\0')
5433 binary = STREQ (options, "-kb");
5438 expand = RCS_getexpand (rcs);
5439 if (expand != NULL && STREQ (expand, "b"))
5445 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5446 /* If CVS is to deal properly with special files (when
5447 PreservePermissions is on), the best way is to check out the
5448 revision to a temporary file and call `xcmp' on the two disk
5449 files. xcmp needs to handle non-regular files properly anyway,
5450 so calling it simplifies RCS_cmp_file. We *could* just yank
5451 the delta node out of the version tree and look for device
5452 numbers, but writing to disk and calling xcmp is a better
5453 abstraction (therefore probably more robust). -twp */
5460 tmp = cvs_temp_name();
5461 retcode = RCS_checkout(rcs, NULL, rev, NULL, options, tmp, NULL, NULL);
5465 retcode = xcmp (tmp, filename);
5466 if (CVS_UNLINK (tmp) < 0)
5467 error (0, errno, "cannot remove %s", tmp);
5475 struct cmp_file_data data;
5476 const char *use_file1;
5477 char *tmpfile = NULL;
5481 /* Open & cache rev1 */
5482 tmpfile = cvs_temp_name();
5483 if (RCS_checkout (rcs, NULL, rev1, NULL, options, tmpfile,
5484 (RCSCHECKOUTPROC)0, NULL))
5486 "cannot check out revision %s of %s",
5488 use_file1 = tmpfile;
5489 if (rev1_cache != NULL)
5490 *rev1_cache = tmpfile;
5493 use_file1 = filename;
5495 fp = CVS_FOPEN (use_file1, binary ? FOPEN_BINARY_READ : "r");
5497 /* FIXME-update-dir: should include update_dir in message. */
5498 error (1, errno, "cannot open file %s for comparing", use_file1);
5500 data.filename = use_file1;
5504 if (RCS_checkout (rcs, NULL, rev2 ? rev2 : rev1, NULL, options,
5505 RUN_TTY, cmp_file_buffer, &data ))
5507 "cannot check out revision %s of %s",
5508 rev2 ? rev2 : rev1, rcs->path);
5510 /* If we have not yet found a difference, make sure that we are at
5511 the end of the file. */
5512 if (!data.different)
5514 if (getc (fp) != EOF)
5519 if (rev1_cache == NULL && tmpfile)
5521 if (CVS_UNLINK (tmpfile ) < 0)
5522 error (0, errno, "cannot remove %s", tmpfile);
5526 return data.different;
5532 /* This is a subroutine of RCS_cmp_file. It is passed to
5534 #define CMP_BUF_SIZE (8 * 1024)
5537 cmp_file_buffer (void *callerdat, const char *buffer, size_t len)
5539 struct cmp_file_data *data = callerdat;
5542 /* If we've already found a difference, we don't need to check
5544 if (data->different)
5547 filebuf = xmalloc (len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len);
5553 checklen = len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len;
5554 if (fread (filebuf, 1, checklen, data->fp) != checklen)
5556 if (ferror (data->fp))
5557 error (1, errno, "cannot read file %s for comparing",
5559 data->different = 1;
5564 if (memcmp (filebuf, buffer, checklen) != 0)
5566 data->different = 1;
5580 /* For RCS file RCS, make symbolic tag TAG point to revision REV.
5581 This validates that TAG is OK for a user to use. Return value is
5582 -1 for error (and errno is set to indicate the error), positive for
5583 error (and an error message has been printed), or zero for success. */
5586 RCS_settag (RCSNode *rcs, const char *tag, const char *rev)
5591 if (rcs->flags & PARTIAL)
5592 RCS_reparsercsfile (rcs, NULL, NULL);
5594 /* FIXME: This check should be moved to RCS_check_tag. There is no
5595 reason for it to be here. */
5596 if (STREQ (tag, TAG_BASE)
5597 || STREQ (tag, TAG_HEAD))
5599 /* Print the name of the tag might be considered redundant
5600 with the caller, which also prints it. Perhaps this helps
5601 clarify why the tag name is considered reserved, I don't
5603 error (0, 0, "Attempt to add reserved tag name %s", tag);
5607 /* A revision number of NULL means use the head or default branch.
5608 If rev is not NULL, it may be a symbolic tag or branch number;
5609 expand it to the correct numeric revision or branch head. */
5611 rev = rcs->branch ? rcs->branch : rcs->head;
5613 /* At this point rcs->symbol_data may not have been parsed.
5614 Calling RCS_symbols will force it to be parsed into a list
5615 which we can easily manipulate. */
5616 symbols = RCS_symbols (rcs);
5617 if (symbols == NULL)
5619 symbols = getlist ();
5620 rcs->symbols = symbols;
5622 node = findnode (symbols, tag);
5626 node->data = xstrdup (rev);
5631 node->key = xstrdup (tag);
5632 node->data = xstrdup (rev);
5633 (void)addnode_at_front (symbols, node);
5641 /* Delete the symbolic tag TAG from the RCS file RCS. Return 0 if
5642 the tag was found (and removed), or 1 if it was not present. (In
5643 either case, the tag will no longer be in RCS->SYMBOLS.) */
5646 RCS_deltag (RCSNode *rcs, const char *tag)
5650 if (rcs->flags & PARTIAL)
5651 RCS_reparsercsfile (rcs, NULL, NULL);
5653 symbols = RCS_symbols (rcs);
5654 if (symbols == NULL)
5657 node = findnode (symbols, tag);
5668 /* Set the default branch of RCS to REV. */
5670 RCS_setbranch (RCSNode *rcs, const char *rev)
5672 if (rcs->flags & PARTIAL)
5673 RCS_reparsercsfile (rcs, NULL, NULL);
5678 if (rev == NULL && rcs->branch == NULL)
5680 if (rev != NULL && rcs->branch != NULL && STREQ (rev, rcs->branch))
5683 if (rcs->branch != NULL)
5685 rcs->branch = xstrdup (rev);
5692 /* Lock revision REV. LOCK_QUIET is 1 to suppress output. FIXME:
5693 Most of the callers only call us because RCS_checkin still tends to
5694 like a lock (a relic of old behavior inherited from the RCS ci
5695 program). If we clean this up, only "cvs admin -l" will still need
5696 to call RCS_lock. */
5698 /* FIXME-twp: if a lock owned by someone else is broken, should this
5699 send mail to the lock owner? Prompt user? It seems like such an
5700 obscure situation for CVS as almost not worth worrying much
5703 RCS_lock (RCSNode *rcs, const char *rev, int lock_quiet)
5710 if (rcs->flags & PARTIAL)
5711 RCS_reparsercsfile (rcs, NULL, NULL);
5713 locks = RCS_getlocks (rcs);
5715 locks = rcs->locks = getlist();
5718 /* A revision number of NULL means lock the head or default branch. */
5720 xrev = RCS_head (rcs);
5722 xrev = RCS_gettag (rcs, rev, 1, NULL);
5724 /* Make sure that the desired revision exists. Technically,
5725 we can update the locks list without even checking this,
5726 but RCS 5.7 did this. And it can't hurt. */
5727 if (xrev == NULL || findnode (rcs->versions, xrev) == NULL)
5730 error (0, 0, "%s: revision %s absent", rcs->path, rev);
5735 /* Is this rev already locked? */
5736 p = findnode (locks, xrev);
5739 if (STREQ (p->data, user))
5741 /* We already own the lock on this revision, so do nothing. */
5747 /* Well, first of all, "rev" below should be "xrev" to avoid
5748 core dumps. But more importantly, should we really be
5749 breaking the lock unconditionally? What CVS 1.9 does (via
5750 RCS) is to prompt "Revision 1.1 is already locked by fred.
5751 Do you want to break the lock? [ny](n): ". Well, we don't
5752 want to interact with the user (certainly not at the
5753 server/protocol level, and probably not in the command-line
5754 client), but isn't it more sensible to give an error and
5755 let the user run "cvs admin -u" if they want to break the
5758 /* Break the lock. */
5761 cvs_output (rev, 0);
5762 cvs_output (" unlocked\n", 0);
5766 error (1, 0, "Revision %s is already locked by %s",
5767 xrev, (char *)p->data);
5771 /* Create a new lock. */
5773 p->key = xrev; /* already xstrdupped */
5774 p->data = xstrdup (getcaller());
5775 (void)addnode_at_front (locks, p);
5779 cvs_output (xrev, 0);
5780 cvs_output (" locked\n", 0);
5788 /* Unlock revision REV. UNLOCK_QUIET is 1 to suppress output. FIXME:
5789 Like RCS_lock, this can become a no-op if we do the checkin
5792 If REV is not null and is locked by someone else, break their
5793 lock and notify them. It is an open issue whether RCS_unlock
5794 queries the user about whether or not to break the lock. */
5796 RCS_unlock (RCSNode *rcs, char *rev, int unlock_quiet)
5804 if (rcs->flags & PARTIAL)
5805 RCS_reparsercsfile (rcs, NULL, NULL);
5807 /* If rev is NULL, unlock the revision held by the caller; if more
5808 than one, make the user specify the revision explicitly. This
5809 differs from RCS which unlocks the latest revision (first in
5810 rcs->locks) held by the caller. */
5815 /* No-ops: attempts to unlock an empty tree or an unlocked file. */
5816 if (rcs->head == NULL)
5819 cvs_outerr ("can't unlock an empty tree\n", 0);
5823 locks = RCS_getlocks (rcs);
5827 cvs_outerr ("No locks are set.\n", 0);
5832 for (p = locks->list->next; p != locks->list; p = p->next)
5834 if (STREQ (p->data, user))
5840 %s: multiple revisions locked by %s; please specify one", rcs->path, user);
5849 error (0, 0, "No locks are set for %s.\n", user);
5850 return 0; /* no lock found, ergo nothing to do */
5852 xrev = xstrdup (lock->key);
5856 xrev = RCS_gettag (rcs, rev, 1, (int *) NULL);
5859 error (0, 0, "%s: revision %s absent", rcs->path, rev);
5864 lock = findnode (RCS_getlocks (rcs), xrev);
5867 /* This revision isn't locked. */
5872 if (! STREQ (lock->data, user))
5874 /* If the revision is locked by someone else, notify
5875 them. Note that this shouldn't ever happen if RCS_unlock
5876 is called with a NULL revision, since that means "whatever
5877 revision is currently locked by the caller." */
5878 char *repos, *workfile;
5881 %s: revision %s locked by %s; breaking lock", rcs->path, xrev, (char *)lock->data);
5882 repos = xstrdup (rcs->path);
5883 workfile = strrchr (repos, '/');
5885 notify_do ('C', workfile, user, NULL, NULL, repos);
5892 cvs_output (xrev, 0);
5893 cvs_output (" unlocked\n", 0);
5902 /* Add USER to the access list of RCS. Do nothing if already present.
5903 FIXME-twp: check syntax of USER to make sure it's a valid id. */
5906 RCS_addaccess (RCSNode *rcs, char *user)
5910 if (rcs->flags & PARTIAL)
5911 RCS_reparsercsfile (rcs, NULL, NULL);
5913 if (rcs->access == NULL)
5914 rcs->access = xstrdup (user);
5917 access = xstrdup (rcs->access);
5918 for (a = strtok (access, " "); a != NULL; a = strtok (NULL, " "))
5920 if (STREQ (a, user))
5927 rcs->access = (char *) xrealloc
5928 (rcs->access, strlen (rcs->access) + strlen (user) + 2);
5929 strcat (rcs->access, " ");
5930 strcat (rcs->access, user);
5936 /* Remove USER from the access list of RCS. */
5938 RCS_delaccess (RCSNode *rcs, char *user)
5943 if (rcs->flags & PARTIAL)
5944 RCS_reparsercsfile (rcs, NULL, NULL);
5946 if (rcs->access == NULL)
5957 ulen = strlen (user);
5960 if (strncmp (p, user, ulen) == 0 && (p[ulen] == '\0' || p[ulen] == ' '))
5962 p = strchr (p, ' ');
5979 RCS_getaccess (RCSNode *rcs)
5981 if (rcs->flags & PARTIAL)
5982 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5989 /* Return a nonzero value if the revision specified by ARG is found. */
5991 findtag (Node *node, void *arg)
5995 if (STREQ (node->data, rev))
6003 /* Delete revisions between REV1 and REV2. The changes between the two
6004 revisions must be collapsed, and the result stored in the revision
6005 immediately preceding the lower one. Return 0 for successful completion,
6008 Solution: check out the revision preceding REV1 and the revision
6009 following REV2. Use call_diff to find aggregate diffs between
6010 these two revisions, and replace the delta text for the latter one
6011 with the new aggregate diff. Alternatively, we could write a
6012 function that takes two change texts and combines them to produce a
6013 new change text, without checking out any revs or calling diff. It
6014 would be hairy, but so, so cool.
6016 If INCLUSIVE is set, then TAG1 and TAG2, if non-NULL, tell us to
6017 delete that revision as well (cvs admin -o tag1:tag2). If clear,
6018 delete up to but not including that revision (cvs admin -o tag1::tag2).
6019 This does not affect TAG1 or TAG2 being NULL; the meaning of the start
6020 point in ::tag2 and :tag2 is the same and likewise for end points. */
6022 RCS_delete_revs (RCSNode *rcs, char *tag1, char *tag2, int inclusive)
6026 RCSVers *revp = NULL;
6031 char *branchpoint = NULL;
6034 int rev1_inclusive = inclusive;
6035 int rev2_inclusive = inclusive;
6036 char *before = NULL;
6038 char *beforefile = NULL;
6039 char *afterfile = NULL;
6040 char *outfile = NULL;
6042 if (tag1 == NULL && tag2 == NULL)
6045 /* Assume error status until everything is finished. */
6048 /* Make sure both revisions exist. */
6051 rev1 = RCS_gettag (rcs, tag1, 1, NULL);
6052 if (rev1 == NULL || (nodep = findnode (rcs->versions, rev1)) == NULL)
6054 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag1);
6060 rev2 = RCS_gettag (rcs, tag2, 1, NULL);
6061 if (rev2 == NULL || (nodep = findnode (rcs->versions, rev2)) == NULL)
6063 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag2);
6068 /* If rev1 is on the trunk and rev2 is NULL, rev2 should be
6069 RCS->HEAD. (*Not* RCS_head(rcs), which may return rcs->branch
6070 instead.) We need to check this special case early, in order
6071 to make sure that rev1 and rev2 get ordered correctly. */
6072 if (rev2 == NULL && numdots (rev1) == 1)
6074 rev2 = xstrdup (rcs->head);
6081 if (rev1 != NULL && rev2 != NULL)
6083 /* A range consisting of a branch number means the latest revision
6085 if (RCS_isbranch (rcs, rev1) && STREQ (rev1, rev2))
6086 rev1 = rev2 = RCS_getbranch (rcs, rev1, 0);
6089 /* Make sure REV1 and REV2 are ordered correctly (in the
6090 same order as the next field). For revisions on the
6091 trunk, REV1 should be higher than REV2; for branches,
6092 REV1 should be lower. */
6093 /* Shouldn't we just be giving an error in the case where
6094 the user specifies the revisions in the wrong order
6095 (that is, always swap on the trunk, never swap on a
6096 branch, in the non-error cases)? It is not at all
6097 clear to me that users who specify -o 1.4:1.2 really
6098 meant to type -o 1.2:1.4, and the out of order usage
6099 has never been documented, either by cvs.texinfo or
6103 if (numdots (rev1) == 1)
6105 if (compare_revnums (rev1, rev2) <= 0)
6111 temp_inclusive = rev2_inclusive;
6112 rev2_inclusive = rev1_inclusive;
6113 rev1_inclusive = temp_inclusive;
6116 else if (compare_revnums (rev1, rev2) > 0)
6122 temp_inclusive = rev2_inclusive;
6123 rev2_inclusive = rev1_inclusive;
6124 rev1_inclusive = temp_inclusive;
6129 /* Basically the same thing; make sure that the ordering is what we
6133 assert (rev2 != NULL);
6134 if (numdots (rev2) == 1)
6136 /* Swap rev1 and rev2. */
6142 temp_inclusive = rev2_inclusive;
6143 rev2_inclusive = rev1_inclusive;
6144 rev1_inclusive = temp_inclusive;
6148 /* Put the revision number preceding the first one to delete into
6149 BEFORE (where "preceding" means according to the next field).
6150 If the first revision to delete is the first revision on its
6151 branch (e.g. 1.3.2.1), BEFORE should be the node on the trunk
6152 at which the branch is rooted. If the first revision to delete
6153 is the head revision of the trunk, set BEFORE to NULL.
6155 Note that because BEFORE may not be on the same branch as REV1,
6156 it is not very handy for navigating the revision tree. It's
6157 most useful just for checking out the revision preceding REV1. */
6159 branchpoint = RCS_getbranchpoint (rcs, rev1 != NULL ? rev1 : rev2);
6162 rev1 = xstrdup (branchpoint);
6163 if (numdots (branchpoint) > 1)
6166 bp = strrchr (branchpoint, '.');
6167 while (*--bp != '.')
6170 /* Note that this is exclusive, always, because the inclusive
6171 flag doesn't affect the meaning when rev1 == NULL. */
6172 before = xstrdup (branchpoint);
6176 else if (! STREQ (rev1, branchpoint))
6178 /* Walk deltas from BRANCHPOINT on, looking for REV1. */
6179 nodep = findnode (rcs->versions, branchpoint);
6181 while (revp->next != NULL && ! STREQ (revp->next, rev1))
6184 nodep = findnode (rcs->versions, revp->next);
6186 if (revp->next == NULL)
6188 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, rev1);
6192 before = xstrdup (revp->version);
6196 nodep = findnode (rcs->versions, before);
6197 rev1 = xstrdup (((RCSVers *)nodep->data)->next);
6200 else if (!rev1_inclusive)
6203 nodep = findnode (rcs->versions, before);
6204 rev1 = xstrdup (((RCSVers *)nodep->data)->next);
6206 else if (numdots (branchpoint) > 1)
6208 /* Example: rev1 is "1.3.2.1", branchpoint is "1.3.2.1".
6209 Set before to "1.3". */
6211 bp = strrchr (branchpoint, '.');
6212 while (*--bp != '.')
6215 before = xstrdup (branchpoint);
6219 /* If any revision between REV1 and REV2 is locked or is a branch point,
6220 we can't delete that revision and must abort. */
6224 while (!found && next != NULL)
6226 nodep = findnode (rcs->versions, next);
6230 found = STREQ (revp->version, rev2);
6233 if ((!found && next != NULL) || rev2_inclusive || rev2 == NULL)
6235 if (findnode (RCS_getlocks (rcs), revp->version))
6237 error (0, 0, "%s: can't remove locked revision %s",
6242 if (revp->branches != NULL)
6244 error (0, 0, "%s: can't remove branch point %s",
6250 /* Doing this only for the :: syntax is for compatibility.
6251 See cvs.texinfo for somewhat more discussion. */
6253 && walklist (RCS_symbols (rcs), findtag, revp->version))
6255 /* We don't print which file this happens to on the theory
6256 that the caller will print the name of the file in a
6257 more useful fashion (fullname not rcs->path). */
6258 error (0, 0, "cannot remove revision %s because it has tags",
6263 /* It's misleading to print the `deleting revision' output
6264 here, since we may not actually delete these revisions.
6265 But that's how RCS does it. Bleah. Someday this should be
6266 moved to the point where the revs are actually marked for
6268 cvs_output ("deleting revision ", 0);
6269 cvs_output (revp->version, 0);
6270 cvs_output ("\n", 1);
6279 after = xstrdup (next);
6281 after = xstrdup (revp->version);
6283 else if (!inclusive)
6285 /* In the case of an empty range, for example 1.2::1.2 or
6286 1.2::1.3, we want to just do nothing. */
6292 /* This looks fishy in the cases where tag1 == NULL or tag2 == NULL.
6293 Are those cases really impossible? */
6294 assert (tag1 != NULL);
6295 assert (tag2 != NULL);
6297 error (0, 0, "%s: invalid revision range %s:%s", rcs->path,
6302 if (after == NULL && before == NULL)
6304 /* The user is trying to delete all revisions. While an
6305 RCS file without revisions makes sense to RCS (e.g. the
6306 state after "rcs -i"), CVS has never been able to cope with
6307 it. So at least for now we just make this an error.
6309 We don't include rcs->path in the message since "cvs admin"
6310 already printed "RCS file:" and the name. */
6311 error (1, 0, "attempt to delete all revisions");
6314 /* The conditionals at this point get really hairy. Here is the
6317 IF before != NULL and after == NULL
6318 THEN don't check out any revisions, just delete them
6319 IF before == NULL and after != NULL
6320 THEN only check out after's revision, and use it for the new deltatext
6322 check out both revisions and diff -n them. This could use
6323 RCS_exec_rcsdiff with some changes, like being able
6324 to suppress diagnostic messages and to direct output. */
6329 size_t bufsize, len;
6331 #if defined (WOE32) && !defined (__CYGWIN32__)
6332 /* FIXME: This is an awful kludge, but at least until I have
6333 time to work on it a little more and test it, I'd rather
6334 give a fatal error than corrupt the file. I think that we
6335 need to use "-kb" and "--binary" and "rb" to get_file
6336 (probably can do it always, not just for binary files, if
6337 we are consistent between the RCS_checkout and the diff). */
6339 char *expand = RCS_getexpand (rcs);
6340 if (expand != NULL && STREQ (expand, "b"))
6342 "admin -o not implemented yet for binary on this system");
6346 afterfile = cvs_temp_name();
6347 status = RCS_checkout (rcs, NULL, after, NULL, "-ko", afterfile,
6348 (RCSCHECKOUTPROC)0, NULL);
6354 /* We are deleting revisions from the head of the tree,
6355 so must create a new head. */
6358 get_file (afterfile, afterfile, "r", &diffbuf, &bufsize, &len);
6360 save_noexec = noexec;
6362 if (unlink_file (afterfile) < 0)
6363 error (0, errno, "cannot remove %s", afterfile);
6364 noexec = save_noexec;
6370 rcs->head = xstrdup (after);
6374 beforefile = cvs_temp_name();
6375 status = RCS_checkout (rcs, NULL, before, NULL, "-ko", beforefile,
6376 (RCSCHECKOUTPROC)0, NULL);
6380 outfile = cvs_temp_name();
6381 status = diff_exec (beforefile, afterfile, NULL, NULL, "-an",
6386 /* Not sure we need this message; will diff_exec already
6387 have printed an error? */
6388 error (0, 0, "%s: could not diff", rcs->path);
6395 get_file (outfile, outfile, "r", &diffbuf, &bufsize, &len);
6398 /* Save the new change text in after's delta node. */
6399 nodep = findnode (rcs->versions, after);
6402 assert (revp->text == NULL);
6404 revp->text = (Deltatext *) xmalloc (sizeof (Deltatext));
6405 memset ((Deltatext *) revp->text, 0, sizeof (Deltatext));
6406 revp->text->version = xstrdup (revp->version);
6407 revp->text->text = diffbuf;
6408 revp->text->len = len;
6410 /* If DIFFBUF is NULL, it means that OUTFILE is empty and that
6411 there are no differences between the two revisions. In that
6412 case, we want to force RCS_copydeltas to write an empty string
6413 for the new change text (leaving the text field set NULL
6414 means "preserve the original change text for this delta," so
6415 we don't want that). */
6416 if (revp->text->text == NULL)
6417 revp->text->text = xstrdup ("");
6420 /* Walk through the revisions (again) to mark each one as
6421 outdated. (FIXME: would it be safe to use the `dead' field for
6424 next != NULL && (after == NULL || ! STREQ (next, after));
6427 nodep = findnode (rcs->versions, next);
6432 /* Update delta links. If BEFORE == NULL, we're changing the
6433 head of the tree and don't need to update any `next' links. */
6436 /* If REV1 is the first node on its branch, then BEFORE is its
6437 root node (on the trunk) and we have to update its branches
6438 list. Otherwise, BEFORE is on the same branch as AFTER, and
6439 we can just change BEFORE's `next' field to point to AFTER.
6440 (This should be safe: since findnode manages its lists via
6441 the `hashnext' and `hashprev' fields, rather than `next' and
6442 `prev', mucking with `next' and `prev' should not corrupt the
6443 delta tree's internal structure. Much. -twp) */
6446 /* beforep's ->next field already should be equal to after,
6447 which I think is always NULL in this case. */
6449 else if (STREQ (rev1, branchpoint))
6451 nodep = findnode (rcs->versions, before);
6453 nodep = revp->branches->list->next;
6454 while (nodep != revp->branches->list &&
6455 ! STREQ (nodep->key, rev1))
6456 nodep = nodep->next;
6457 assert (nodep != revp->branches->list);
6463 nodep->key = xstrdup (after);
6468 nodep = findnode (rcs->versions, before);
6469 beforep = nodep->data;
6470 free (beforep->next);
6471 beforep->next = xstrdup (after);
6482 if (branchpoint != NULL)
6489 save_noexec = noexec;
6491 if (beforefile != NULL)
6493 if (unlink_file (beforefile) < 0)
6494 error (0, errno, "cannot remove %s", beforefile);
6497 if (afterfile != NULL)
6499 if (unlink_file (afterfile) < 0)
6500 error (0, errno, "cannot remove %s", afterfile);
6503 if (outfile != NULL)
6505 if (unlink_file (outfile) < 0)
6506 error (0, errno, "cannot remove %s", outfile);
6509 noexec = save_noexec;
6517 * TRUE if there exists a symbolic tag "tag" in file.
6520 RCS_exist_tag (RCSNode *rcs, char *tag)
6523 assert (rcs != NULL);
6525 if (findnode (RCS_symbols (rcs), tag))
6532 * TRUE if RCS revision number "rev" exists.
6533 * This includes magic branch revisions, not found in rcs->versions,
6534 * but only in rcs->symbols, requiring a list walk to find them.
6535 * Take advantage of list walk callback function already used by
6536 * RCS_delete_revs, above.
6539 RCS_exist_rev (RCSNode *rcs, char *rev)
6542 assert (rcs != NULL);
6544 if (rcs->flags & PARTIAL)
6545 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6547 if (findnode(rcs->versions, rev) != 0)
6550 if (walklist (RCS_symbols(rcs), findtag, rev) != 0)
6558 /* RCS_deltas and friends. Processing of the deltas in RCS files. */
6562 /* Text of this line. Part of the same malloc'd block as the struct
6563 line itself (we probably should use the "struct hack" (char text[1])
6564 and save ourselves sizeof (char *) bytes). Does not include \n;
6565 instead has_newline indicates the presence or absence of \n. */
6567 /* Length of this line, not counting \n if has_newline is true. */
6569 /* Version in which it was introduced. */
6571 /* Nonzero if this line ends with \n. This will always be true
6572 except possibly for the last line. */
6574 /* Number of pointers to this struct line. */
6580 /* How many lines in use for this linevector? */
6581 unsigned int nlines;
6582 /* How many lines allocated for this linevector? */
6583 unsigned int lines_alloced;
6584 /* Pointer to array containing a pointer to each line. */
6585 struct line **vector;
6588 static void linevector_init (struct linevector *);
6590 /* Initialize *VEC to be a linevector with no lines. */
6592 linevector_init (struct linevector *vec)
6594 vec->lines_alloced = 0;
6599 static int linevector_add (struct linevector *vec, const char *text,
6600 size_t len, RCSVers *vers,
6603 /* Given some text TEXT, add each of its lines to VEC before line POS
6604 (where line 0 is the first line). The last line in TEXT may or may
6605 not be \n terminated.
6606 Set the version for each of the new lines to VERS. This
6607 function returns non-zero for success. It returns zero if the line
6608 number is out of range.
6610 Each of the lines in TEXT are copied to space which is managed with
6611 the linevector (and freed by linevector_free). So the caller doesn't
6612 need to keep TEXT around after the call to this function. */
6614 linevector_add (struct linevector *vec, const char *text, size_t len, RCSVers *vers, unsigned int pos)
6616 const char *textend;
6620 const char *nextline_text;
6621 size_t nextline_len;
6622 int nextline_newline;
6628 textend = text + len;
6630 /* Count the number of lines we will need to add. */
6632 for (p = text; p < textend; ++p)
6633 if (*p == '\n' && p + 1 < textend)
6636 /* Expand VEC->VECTOR if needed. */
6637 if (vec->nlines + nnew >= vec->lines_alloced)
6639 if (vec->lines_alloced == 0)
6640 vec->lines_alloced = 10;
6641 while (vec->nlines + nnew >= vec->lines_alloced)
6642 vec->lines_alloced *= 2;
6643 vec->vector = xrealloc (vec->vector,
6644 vec->lines_alloced * sizeof (*vec->vector));
6647 /* Make room for the new lines in VEC->VECTOR. */
6648 for (i = vec->nlines + nnew - 1; i >= pos + nnew; --i)
6649 vec->vector[i] = vec->vector[i - nnew];
6651 if (pos > vec->nlines)
6654 /* Actually add the lines, to VEC->VECTOR. */
6656 nextline_text = text;
6657 nextline_newline = 0;
6658 for (p = text; p < textend; ++p)
6661 nextline_newline = 1;
6662 if (p + 1 == textend)
6663 /* If there are no characters beyond the last newline, we
6664 don't consider it another line. */
6666 nextline_len = p - nextline_text;
6667 q = (struct line *) xmalloc (sizeof (struct line) + nextline_len);
6669 q->text = (char *)q + sizeof (struct line);
6670 q->len = nextline_len;
6671 q->has_newline = nextline_newline;
6673 memcpy (q->text, nextline_text, nextline_len);
6674 vec->vector[i++] = q;
6676 nextline_text = (char *)p + 1;
6677 nextline_newline = 0;
6679 nextline_len = p - nextline_text;
6680 q = (struct line *) xmalloc (sizeof (struct line) + nextline_len);
6682 q->text = (char *)q + sizeof (struct line);
6683 q->len = nextline_len;
6684 q->has_newline = nextline_newline;
6686 memcpy (q->text, nextline_text, nextline_len);
6689 vec->nlines += nnew;
6694 static void linevector_delete (struct linevector *, unsigned int,
6697 /* Remove NLINES lines from VEC at position POS (where line 0 is the
6700 linevector_delete (struct linevector *vec, unsigned int pos, unsigned int nlines)
6705 last = vec->nlines - nlines;
6706 for (i = pos; i < pos + nlines; ++i)
6708 if (--vec->vector[i]->refcount == 0)
6709 free (vec->vector[i]);
6711 for (i = pos; i < last; ++i)
6712 vec->vector[i] = vec->vector[i + nlines];
6713 vec->nlines -= nlines;
6716 static void linevector_copy (struct linevector *, struct linevector *);
6718 /* Copy FROM to TO, copying the vectors but not the lines pointed to. */
6720 linevector_copy (struct linevector *to, struct linevector *from)
6724 for (ln = 0; ln < to->nlines; ++ln)
6726 if (--to->vector[ln]->refcount == 0)
6727 free (to->vector[ln]);
6729 if (from->nlines > to->lines_alloced)
6731 if (to->lines_alloced == 0)
6732 to->lines_alloced = 10;
6733 while (from->nlines > to->lines_alloced)
6734 to->lines_alloced *= 2;
6735 to->vector = (struct line **)
6736 xrealloc (to->vector, to->lines_alloced * sizeof (*to->vector));
6738 memcpy (to->vector, from->vector,
6739 from->nlines * sizeof (*to->vector));
6740 to->nlines = from->nlines;
6741 for (ln = 0; ln < to->nlines; ++ln)
6742 ++to->vector[ln]->refcount;
6745 static void linevector_free (struct linevector *);
6747 /* Free storage associated with linevector. */
6749 linevector_free (struct linevector *vec)
6753 if (vec->vector != NULL)
6755 for (ln = 0; ln < vec->nlines; ++ln)
6756 if (--vec->vector[ln]->refcount == 0)
6757 free (vec->vector[ln]);
6763 static char *month_printname (char *);
6765 /* Given a textual string giving the month (1-12), terminated with any
6766 character not recognized by atoi, return the 3 character name to
6767 print it with. I do not think it is a good idea to change these
6768 strings based on the locale; they are standard abbreviations (for
6769 example in rfc822 mail messages) which should be widely understood.
6770 Returns a pointer into static readonly storage. */
6772 month_printname (char *month)
6774 static const char *const months[] =
6775 {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
6776 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
6779 mnum = atoi (month);
6780 if (mnum < 1 || mnum > 12)
6782 return (char *)months[mnum - 1];
6786 apply_rcs_changes (struct linevector *, const char *, size_t,
6787 const char *, RCSVers *, RCSVers *);
6789 /* Apply changes to the line vector LINES. DIFFBUF is a buffer of
6790 length DIFFLEN holding the change text from an RCS file (the output
6791 of diff -n). NAME is used in error messages. The VERS field of
6792 any line added is set to ADDVERS. The VERS field of any line
6793 deleted is set to DELVERS, unless DELVERS is NULL, in which case
6794 the VERS field of deleted lines is unchanged. The function returns
6795 non-zero if the change text is applied successfully. It returns
6796 zero if the change text does not appear to apply to LINES (e.g., a
6797 line number is invalid). If the change text is improperly
6798 formatted (e.g., it is not the output of diff -n), the function
6799 calls error with a status of 1, causing the program to exit. */
6802 apply_rcs_changes (struct linevector *lines, const char *diffbuf, size_t difflen, const char *name, RCSVers *addvers, RCSVers *delvers)
6807 /* The RCS format throws us for a loop in that the deltafrags (if
6808 we define a deltafrag as an add or a delete) need to be applied
6809 in reverse order. So we stick them into a linked list. */
6811 enum {FRAG_ADD, FRAG_DELETE} type;
6813 unsigned long nlines;
6814 const char *new_lines;
6816 struct deltafrag *next;
6818 struct deltafrag *dfhead;
6819 struct deltafrag *df;
6822 for (p = diffbuf; p != NULL && p < diffbuf + difflen; )
6825 if (op != 'a' && op != 'd')
6826 /* Can't just skip over the deltafrag, because the value
6827 of op determines the syntax. */
6828 error (1, 0, "unrecognized operation '\\x%x' in %s",
6830 df = (struct deltafrag *) xmalloc (sizeof (struct deltafrag));
6833 df->pos = strtoul (p, (char **) &q, 10);
6836 error (1, 0, "number expected in %s", name);
6839 error (1, 0, "space expected in %s", name);
6840 df->nlines = strtoul (p, (char **) &q, 10);
6842 error (1, 0, "number expected in %s", name);
6845 error (1, 0, "linefeed expected in %s", name);
6851 df->type = FRAG_ADD;
6853 /* The text we want is the number of lines specified, or
6854 until the end of the value, whichever comes first (it
6855 will be the former except in the case where we are
6856 adding a line which does not end in newline). */
6857 for (q = p; i != 0; ++q)
6860 else if (q == diffbuf + difflen)
6863 error (1, 0, "premature end of change in %s", name);
6868 /* Stash away a pointer to the text we are adding. */
6876 /* Correct for the fact that line numbers in RCS files
6881 df->type = FRAG_DELETE;
6885 for (df = dfhead; df != NULL;)
6892 if (! linevector_add (lines, df->new_lines, df->len, addvers,
6897 if (df->pos > lines->nlines
6898 || df->pos + df->nlines > lines->nlines)
6900 if (delvers != NULL)
6901 for (ln = df->pos; ln < df->pos + df->nlines; ++ln)
6902 lines->vector[ln]->vers = delvers;
6903 linevector_delete (lines, df->pos, df->nlines);
6914 /* Apply an RCS change text to a buffer. The function name starts
6915 with rcs rather than RCS because this does not take an RCSNode
6916 argument. NAME is used in error messages. TEXTBUF is the text
6917 buffer to change, and TEXTLEN is the size. DIFFBUF and DIFFLEN are
6918 the change buffer and size. The new buffer is returned in *RETBUF
6919 and *RETLEN. The new buffer is allocated by xmalloc.
6921 Return 1 for success. On failure, call error and return 0. */
6924 rcs_change_text (const char *name, char *textbuf, size_t textlen, const char *diffbuf, size_t difflen, char **retbuf, size_t *retlen)
6926 struct linevector lines;
6932 linevector_init (&lines);
6934 if (! linevector_add (&lines, textbuf, textlen, NULL, 0))
6935 error (1, 0, "cannot initialize line vector");
6937 if (! apply_rcs_changes (&lines, diffbuf, difflen, name, NULL, NULL))
6939 error (0, 0, "invalid change text in %s", name);
6949 for (ln = 0; ln < lines.nlines; ++ln)
6951 n += lines.vector[ln]->len + 1;
6956 for (ln = 0; ln < lines.nlines; ++ln)
6958 memcpy (p, lines.vector[ln]->text, lines.vector[ln]->len);
6959 p += lines.vector[ln]->len;
6960 if (lines.vector[ln]->has_newline)
6964 *retlen = p - *retbuf;
6965 assert (*retlen <= n);
6970 linevector_free (&lines);
6975 /* Walk the deltas in RCS to get to revision VERSION.
6977 If OP is RCS_ANNOTATE, then write annotations using cvs_output.
6979 If OP is RCS_FETCH, then put the contents of VERSION into a
6980 newly-malloc'd array and put a pointer to it in *TEXT. Each line
6981 is \n terminated; the caller is responsible for converting text
6982 files if desired. The total length is put in *LEN.
6984 If FP is non-NULL, it should be a file descriptor open to the file
6985 RCS with file position pointing to the deltas. We close the file
6988 If LOG is non-NULL, then *LOG is set to the log message of VERSION,
6989 and *LOGLEN is set to the length of the log message.
6991 On error, give a fatal error. */
6994 RCS_deltas (RCSNode *rcs, FILE *fp, struct rcsbuffer *rcsbuf,
6995 const char *version, enum rcs_delta_op op, char **text,
6996 size_t *len, char **log, size_t *loglen)
6998 struct rcsbuffer rcsbuf_local;
6999 char *branchversion;
7006 RCSVers *trunk_vers;
7008 int ishead, isnext, isversion, onbranch;
7010 struct linevector headlines;
7011 struct linevector curlines;
7012 struct linevector trunklines;
7017 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf_local);
7018 rcsbuf = &rcsbuf_local;
7029 linevector_init (&curlines);
7030 linevector_init (&headlines);
7031 linevector_init (&trunklines);
7033 /* We set BRANCHVERSION to the version we are currently looking
7034 for. Initially, this is the version on the trunk from which
7035 VERSION branches off. If VERSION is not a branch, then
7036 BRANCHVERSION is just VERSION. */
7037 branchversion = xstrdup (version);
7038 cpversion = strchr (branchversion, '.');
7039 if (cpversion != NULL)
7040 cpversion = strchr (cpversion + 1, '.');
7041 if (cpversion != NULL)
7045 if (! rcsbuf_getrevnum (rcsbuf, &key))
7046 error (1, 0, "unexpected EOF reading RCS file %s", rcs->path);
7048 if (next != NULL && ! STREQ (next, key))
7050 /* This is not the next version we need. It is a branch
7051 version which we want to ignore. */
7059 /* look up the revision */
7060 node = findnode (rcs->versions, key);
7063 "mismatch in rcs file %s between deltas and deltatexts (%s)",
7066 /* Stash the previous version. */
7072 /* Compare key and trunkversion now, because key points to
7073 storage controlled by rcsbuf_getkey. */
7074 if (STREQ (branchversion, key))
7082 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7083 error (1, 0, "%s does not appear to be a valid rcs file",
7088 && STREQ (key, "log")
7089 && STREQ (branchversion, version))
7091 *log = rcsbuf_valcopy (rcsbuf, value, 0, loglen);
7094 if (STREQ (key, "text"))
7096 rcsbuf_valpolish (rcsbuf, value, 0, &vallen);
7099 if (! linevector_add (&curlines, value, vallen, NULL, 0))
7100 error (1, 0, "invalid rcs file %s", rcs->path);
7106 if (! apply_rcs_changes (&curlines, value, vallen,
7108 onbranch ? vers : NULL,
7109 onbranch ? NULL : prev_vers))
7110 error (1, 0, "invalid change text in %s", rcs->path);
7118 /* This is either the version we want, or it is the
7119 branchpoint to the version we want. */
7120 if (STREQ (branchversion, version))
7122 /* This is the version we want. */
7123 linevector_copy (&headlines, &curlines);
7127 /* We have found this version by tracking up a
7128 branch. Restore back to the lines we saved
7129 when we left the trunk, and continue tracking
7134 linevector_copy (&curlines, &trunklines);
7141 /* We need to look up the branch. */
7144 if (numdots (branchversion) < 2)
7148 /* We are leaving the trunk; save the current
7149 lines so that we can restore them when we
7150 continue tracking down the trunk. */
7152 linevector_copy (&trunklines, &curlines);
7154 /* Reset the version information we have
7155 accumulated so far. It only applies to the
7156 changes from the head to this version. */
7157 for (ln = 0; ln < curlines.nlines; ++ln)
7158 curlines.vector[ln]->vers = NULL;
7161 /* The next version we want is the entry on
7162 VERS->branches which matches this branch. For
7163 example, suppose VERSION is 1.21.4.3 and
7164 BRANCHVERSION was 1.21. Then we look for an entry
7165 starting with "1.21.4" and we'll put it (probably
7166 1.21.4.1) in NEXT. We'll advance BRANCHVERSION by
7167 two dots (in this example, to 1.21.4.3). */
7169 if (vers->branches == NULL)
7170 error (1, 0, "missing expected branches in %s",
7174 cpversion = strchr (cpversion, '.');
7175 if (cpversion == NULL)
7176 error (1, 0, "version number confusion in %s",
7178 for (p = vers->branches->list->next;
7179 p != vers->branches->list;
7181 if (strncmp (p->key, branchversion,
7182 cpversion - branchversion) == 0)
7184 if (p == vers->branches->list)
7185 error (1, 0, "missing expected branch in %s",
7190 cpversion = strchr (cpversion + 1, '.');
7191 if (cpversion != NULL)
7195 if (op == RCS_FETCH && foundhead)
7197 } while (next != NULL);
7199 free (branchversion);
7201 rcsbuf_cache (rcs, rcsbuf);
7204 error (1, 0, "could not find desired version %s in %s",
7205 version, rcs->path);
7207 /* Now print out or return the data we have just computed. */
7214 for (ln = 0; ln < headlines.nlines; ++ln)
7217 /* Period which separates year from month in date. */
7219 /* Period which separates month from day in date. */
7223 prvers = headlines.vector[ln]->vers;
7227 sprintf (buf, "%-12s (%-8.8s ",
7230 cvs_output (buf, 0);
7232 /* Now output the date. */
7233 ym = strchr (prvers->date, '.');
7236 cvs_output ("??", 0);
7237 cvs_output ("-???", 0);
7238 cvs_output ("-??", 0);
7242 md = strchr (ym + 1, '.');
7244 cvs_output ("??", 0);
7246 cvs_output (md + 1, 2);
7248 cvs_output ("-", 1);
7249 cvs_output (month_printname (ym + 1), 0);
7250 cvs_output ("-", 1);
7251 /* Only output the last two digits of the year. Our output
7252 lines are long enough as it is without printing the
7254 cvs_output (ym - 2, 2);
7256 cvs_output ("): ", 0);
7257 if (headlines.vector[ln]->len != 0)
7258 cvs_output (headlines.vector[ln]->text,
7259 headlines.vector[ln]->len);
7260 cvs_output ("\n", 1);
7270 assert (text != NULL);
7271 assert (len != NULL);
7274 for (ln = 0; ln < headlines.nlines; ++ln)
7276 n += headlines.vector[ln]->len + 1;
7279 for (ln = 0; ln < headlines.nlines; ++ln)
7281 memcpy (p, headlines.vector[ln]->text,
7282 headlines.vector[ln]->len);
7283 p += headlines.vector[ln]->len;
7284 if (headlines.vector[ln]->has_newline)
7293 linevector_free (&curlines);
7294 linevector_free (&headlines);
7295 linevector_free (&trunklines);
7300 /* Read the information for a single delta from the RCS buffer RCSBUF,
7301 whose name is RCSFILE. *KEYP and *VALP are either NULL, or the
7302 first key/value pair to read, as set by rcsbuf_getkey. Return NULL
7303 if there are no more deltas. Store the key/value pair which
7304 terminated the read in *KEYP and *VALP. */
7307 getdelta (struct rcsbuffer *rcsbuf, char *rcsfile, char **keyp, char **valp)
7310 char *key, *value, *cp;
7313 /* Get revision number if it wasn't passed in. This uses
7314 rcsbuf_getkey because it doesn't croak when encountering
7315 unexpected input. As a result, we have to play unholy games
7316 with `key' and `value'. */
7324 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7325 error (1, 0, "%s: unexpected EOF", rcsfile);
7328 /* Make sure that it is a revision number and not a cabbage
7331 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
7334 /* Note that when comparing with RCSDATE, we are not massaging
7335 VALUE from the string found in the RCS file. This is OK since
7336 we know exactly what to expect. */
7337 if (*cp != '\0' || strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) != 0)
7344 vnode = (RCSVers *) xmalloc (sizeof (RCSVers));
7345 memset (vnode, 0, sizeof (RCSVers));
7347 vnode->version = xstrdup (key);
7349 /* Grab the value of the date from value. Note that we are not
7350 massaging VALUE from the string found in the RCS file. */
7351 cp = value + (sizeof RCSDATE) - 1; /* skip the "date" keyword */
7352 while (whitespace (*cp)) /* take space off front of value */
7355 vnode->date = xstrdup (cp);
7357 /* Get author field. */
7358 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7360 error (1, 0, "unexpected end of file reading %s", rcsfile);
7362 if (! STREQ (key, "author"))
7364 unable to parse %s; `author' not in the expected place", rcsfile);
7365 vnode->author = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7367 /* Get state field. */
7368 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7370 error (1, 0, "unexpected end of file reading %s", rcsfile);
7372 if (! STREQ (key, "state"))
7374 unable to parse %s; `state' not in the expected place", rcsfile);
7375 vnode->state = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7376 /* The value is optional, according to rcsfile(5). */
7377 if (value != NULL && STREQ (value, RCSDEAD))
7382 /* Note that "branches" and "next" are in fact mandatory, according
7385 /* fill in the branch list (if any branches exist) */
7386 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7388 error (1, 0, "unexpected end of file reading %s", rcsfile);
7390 if (STREQ (key, RCSDESC))
7394 /* Probably could/should be a fatal error. */
7395 error (0, 0, "warning: 'branches' keyword missing from %s", rcsfile);
7398 if (value != (char *) NULL)
7400 vnode->branches = getlist ();
7401 /* Note that we are not massaging VALUE from the string found
7403 do_branches (vnode->branches, value);
7406 /* fill in the next field if there is a next revision */
7407 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7409 error (1, 0, "unexpected end of file reading %s", rcsfile);
7411 if (STREQ (key, RCSDESC))
7415 /* Probably could/should be a fatal error. */
7416 error (0, 0, "warning: 'next' keyword missing from %s", rcsfile);
7419 if (value != (char *) NULL)
7420 vnode->next = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7423 * XXX - this is where we put the symbolic link stuff???
7424 * (into newphrases in the deltas).
7428 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7429 error (1, 0, "unexpected end of file reading %s", rcsfile);
7431 /* The `desc' keyword is the end of the deltas. */
7432 if (strcmp (key, RCSDESC) == 0)
7435 #ifdef PRESERVE_PERMISSIONS_SUPPORT
7437 /* The `hardlinks' value is a group of words, which must
7438 be parsed separately and added as a list to vnode->hardlinks. */
7439 if (strcmp (key, "hardlinks") == 0)
7443 vnode->hardlinks = getlist();
7444 while ((word = rcsbuf_valword (rcsbuf, &value)) != NULL)
7446 Node *n = getnode();
7448 addnode (vnode->hardlinks, n);
7454 /* Enable use of repositories created by certain obsolete
7455 versions of CVS. This code should remain indefinately;
7456 there is no procedure for converting old repositories, and
7457 checking for it is harmless. */
7458 if (STREQ (key, RCSDEAD))
7461 if (vnode->state != NULL)
7462 free (vnode->state);
7463 vnode->state = xstrdup (RCSDEAD);
7466 /* if we have a new revision number, we're done with this delta */
7468 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
7471 /* Note that when comparing with RCSDATE, we are not massaging
7472 VALUE from the string found in the RCS file. This is OK
7473 since we know exactly what to expect. */
7474 if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0)
7477 /* At this point, key and value represent a user-defined field
7478 in the delta node. */
7479 if (vnode->other_delta == NULL)
7480 vnode->other_delta = getlist ();
7482 kv->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
7483 kv->key = xstrdup (key);
7484 kv->data = rcsbuf_valcopy (rcsbuf, value, kv->type == RCSFIELD,
7486 if (addnode (vnode->other_delta, kv) != 0)
7488 /* Complaining about duplicate keys in newphrases seems
7489 questionable, in that we don't know what they mean and
7490 doc/RCSFILES has no prohibition on several newphrases
7491 with the same key. But we can't store more than one as
7492 long as we store them in a List *. */
7493 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
7499 /* Return the key which caused us to fail back to the caller. */
7507 freedeltatext (Deltatext *d)
7509 if (d->version != NULL)
7513 if (d->text != NULL)
7515 if (d->other != (List *) NULL)
7516 dellist (&d->other);
7521 RCS_getdeltatext (RCSNode *rcs, FILE *fp, struct rcsbuffer *rcsbuf)
7528 /* Get the revision number. */
7529 if (! rcsbuf_getrevnum (rcsbuf, &num))
7531 /* If num == NULL, it means we reached EOF naturally. That's
7536 error (1, 0, "%s: unexpected EOF", rcs->path);
7539 p = findnode (rcs->versions, num);
7541 error (1, 0, "mismatch in rcs file %s between deltas and deltatexts (%s)",
7544 d = (Deltatext *) xmalloc (sizeof (Deltatext));
7545 d->version = xstrdup (num);
7547 /* Get the log message. */
7548 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7549 error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num);
7550 if (! STREQ (key, "log"))
7551 error (1, 0, "%s, delta %s: expected `log', got `%s'",
7552 rcs->path, num, key);
7553 d->log = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7555 /* Get random newphrases. */
7556 d->other = getlist();
7559 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7560 error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num);
7562 if (STREQ (key, "text"))
7566 p->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
7567 p->key = xstrdup (key);
7568 p->data = rcsbuf_valcopy (rcsbuf, value, p->type == RCSFIELD,
7570 if (addnode (d->other, p) < 0)
7572 error (0, 0, "warning: %s, delta %s: duplicate field `%s'",
7573 rcs->path, num, key);
7577 /* Get the change text. We already know that this key is `text'. */
7578 d->text = rcsbuf_valcopy (rcsbuf, value, 0, &d->len);
7583 /* RCS output functions, for writing RCS format files from RCSNode
7586 For most of this work, RCS 5.7 uses an `aprintf' function which aborts
7587 program upon error. Instead, these functions check the output status
7588 of the stream right before closing it, and aborts if an error condition
7589 is found. The RCS solution is probably the better one: it produces
7590 more overhead, but will produce a clearer diagnostic in the case of
7591 catastrophic error. In either case, however, the repository will probably
7592 not get corrupted. */
7595 putsymbol_proc (Node *symnode, void *fparg)
7597 FILE *fp = (FILE *) fparg;
7599 /* A fiddly optimization: this code used to just call fprintf, but
7600 in an old repository with hundreds of tags this can get called
7601 hundreds of thousands of times when doing a cvs tag. Since
7602 tagging is a relatively common operation, and using putc and
7603 fputs is just as comprehensible, the change is worthwhile. */
7606 fputs (symnode->key, fp);
7608 fputs (symnode->data, fp);
7612 static int putlock_proc (Node *, void *);
7614 /* putlock_proc is like putsymbol_proc, but key and data are reversed. */
7617 putlock_proc (Node *symnode, void *fp)
7619 return fprintf ((FILE *) fp, "\n\t%s:%s", (char *)symnode->data, symnode->key);
7623 putrcsfield_proc (Node *node, void *vfp)
7625 FILE *fp = (FILE *) vfp;
7627 /* Some magic keys used internally by CVS start with `;'. Skip them. */
7628 if (node->key[0] == ';')
7631 fprintf (fp, "\n%s\t", node->key);
7632 if (node->data != NULL)
7634 /* If the field's value contains evil characters,
7635 it must be stringified. */
7636 /* FIXME: This does not quite get it right. "7jk8f" is not a valid
7637 value for a value in a newpharse, according to doc/RCSFILES,
7638 because digits are not valid in an "id". We might do OK by
7639 always writing strings (enclosed in @@). Would be nice to
7640 explicitly mention this one way or another in doc/RCSFILES.
7641 A case where we are wrong in a much more clear-cut way is that
7642 we let through non-graphic characters such as whitespace and
7643 control characters. */
7645 if (node->type == RCSCMPFLD || strpbrk (node->data, "$,.:;@") == NULL)
7646 fputs (node->data, fp);
7650 expand_at_signs (node->data, (off_t) strlen (node->data), fp);
7655 /* desc, log and text fields should not be terminated with semicolon;
7656 all other fields should be. */
7657 if (! STREQ (node->key, "desc") &&
7658 ! STREQ (node->key, "log") &&
7659 ! STREQ (node->key, "text"))
7666 #ifdef PRESERVE_PERMISSIONS_SUPPORT
7668 /* Save a filename in a `hardlinks' RCS field. NODE->KEY will contain
7669 a full pathname, but currently only basenames are stored in the RCS
7670 node. Assume that the filename includes nasty characters and
7674 puthardlink_proc (node, vfp)
7678 FILE *fp = (FILE *) vfp;
7679 char *basename = strrchr (node->key, '/');
7681 if (basename == NULL)
7682 basename = node->key;
7688 (void) expand_at_signs (basename, strlen (basename), fp);
7696 /* Output the admin node for RCS into stream FP. */
7699 RCS_putadmin (RCSNode *rcs, FILE *fp)
7701 fprintf (fp, "%s\t%s;\n", RCSHEAD, rcs->head ? rcs->head : "");
7703 fprintf (fp, "%s\t%s;\n", RCSBRANCH, rcs->branch);
7705 fputs ("access", fp);
7709 s = xstrdup (rcs->access);
7710 for (p = strtok (s, " \n\t"); p != NULL; p = strtok (NULL, " \n\t"))
7711 fprintf (fp, "\n\t%s", p);
7716 fputs (RCSSYMBOLS, fp);
7717 /* If we haven't had to convert the symbols to a list yet, don't
7718 force a conversion now; just write out the string. */
7719 if (rcs->symbols == NULL && rcs->symbols_data != NULL)
7722 fputs (rcs->symbols_data, fp);
7725 walklist (RCS_symbols (rcs), putsymbol_proc, (void *) fp);
7728 fputs ("locks", fp);
7729 if (rcs->locks_data)
7730 fprintf (fp, "\t%s", rcs->locks_data);
7731 else if (rcs->locks)
7732 walklist (rcs->locks, putlock_proc, (void *) fp);
7733 if (rcs->strict_locks)
7734 fprintf (fp, "; strict");
7739 fprintf (fp, "comment\t@");
7740 expand_at_signs (rcs->comment, (off_t) strlen (rcs->comment), fp);
7743 if (rcs->expand && ! STREQ (rcs->expand, "kv"))
7744 fprintf (fp, "%s\t@%s@;\n", RCSEXPAND, rcs->expand);
7746 walklist (rcs->other, putrcsfield_proc, (void *) fp);
7752 putdelta (RCSVers *vers, FILE *fp)
7756 /* Skip if no revision was supplied, or if it is outdated (cvs admin -o) */
7757 if (vers == NULL || vers->outdated)
7760 fprintf (fp, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches",
7762 RCSDATE, vers->date,
7763 "author", vers->author,
7764 "state", vers->state ? vers->state : "");
7766 if (vers->branches != NULL)
7768 start = vers->branches->list;
7769 for (bp = start->next; bp != start; bp = bp->next)
7770 fprintf (fp, "\n\t%s", bp->key);
7773 fprintf (fp, ";\nnext\t%s;", vers->next ? vers->next : "");
7775 walklist (vers->other_delta, putrcsfield_proc, fp);
7777 #ifdef PRESERVE_PERMISSIONS_SUPPORT
7778 if (vers->hardlinks)
7780 fprintf (fp, "\nhardlinks");
7781 walklist (vers->hardlinks, puthardlink_proc, fp);
7789 RCS_putdtree (RCSNode *rcs, char *rev, FILE *fp)
7797 /* Find the delta node for this revision. */
7798 p = findnode (rcs->versions, rev);
7802 "error parsing repository file %s, file may be corrupt.",
7808 /* Print the delta node and recurse on its `next' node. This prints
7809 the trunk. If there are any branches printed on this revision,
7810 print those trunks as well. */
7811 putdelta (versp, fp);
7812 RCS_putdtree (rcs, versp->next, fp);
7813 if (versp->branches != NULL)
7815 branch = versp->branches->list;
7816 for (p = branch->next; p != branch; p = p->next)
7817 RCS_putdtree (rcs, p->key, fp);
7822 RCS_putdesc (RCSNode *rcs, FILE *fp)
7824 fprintf (fp, "\n\n%s\n@", RCSDESC);
7825 if (rcs->desc != NULL)
7827 off_t len = (off_t) strlen (rcs->desc);
7830 expand_at_signs (rcs->desc, len, fp);
7831 if (rcs->desc[len-1] != '\n')
7839 putdeltatext (FILE *fp, Deltatext *d)
7841 fprintf (fp, "\n\n%s\nlog\n@", d->version);
7844 int loglen = strlen (d->log);
7845 expand_at_signs (d->log, (off_t) loglen, fp);
7846 if (d->log[loglen-1] != '\n')
7851 walklist (d->other, putrcsfield_proc, fp);
7853 fputs ("\ntext\n@", fp);
7854 if (d->text != NULL)
7855 expand_at_signs (d->text, (off_t) d->len, fp);
7859 /* TODO: the whole mechanism for updating deltas is kludgey... more
7860 sensible would be to supply all the necessary info in a `newdeltatext'
7861 field for RCSVers nodes. -twp */
7863 /* Copy delta text nodes from FIN to FOUT. If NEWDTEXT is non-NULL, it
7864 is a new delta text node, and should be added to the tree at the
7865 node whose revision number is INSERTPT. (Note that trunk nodes are
7866 written in decreasing order, and branch nodes are written in
7867 increasing order.) */
7870 RCS_copydeltas (RCSNode *rcs, FILE *fin, struct rcsbuffer *rcsbufin, FILE *fout, Deltatext *newdtext, char *insertpt)
7875 int insertbefore, found;
7884 /* Count the number of versions for which we have to do some
7885 special operation. */
7886 actions = walklist (rcs->versions, count_delta_actions, (void *) NULL);
7888 /* Make a note of whether NEWDTEXT should be inserted
7889 before or after its INSERTPT. */
7890 insertbefore = (newdtext != NULL && numdots (newdtext->version) == 1);
7892 while (actions != 0 || newdtext != NULL)
7896 dtext = RCS_getdeltatext (rcs, fin, rcsbufin);
7898 /* We shouldn't hit EOF here, because that would imply that
7899 some action was not taken, or that we could not insert
7902 error (1, 0, "internal error: EOF too early in RCS_copydeltas");
7904 found = (insertpt != NULL && STREQ (dtext->version, insertpt));
7905 if (found && insertbefore)
7907 putdeltatext (fout, newdtext);
7912 np = findnode (rcs->versions, dtext->version);
7915 /* If this revision has been outdated, just skip it. */
7916 if (dadmin->outdated)
7918 freedeltatext (dtext);
7923 /* Update the change text for this delta. New change text
7924 data may come from cvs admin -m, cvs admin -o, or cvs ci. */
7925 if (dadmin->text != NULL)
7927 if (dadmin->text->log != NULL || dadmin->text->text != NULL)
7929 if (dadmin->text->log != NULL)
7932 dtext->log = dadmin->text->log;
7933 dadmin->text->log = NULL;
7935 if (dadmin->text->text != NULL)
7938 dtext->text = dadmin->text->text;
7939 dtext->len = dadmin->text->len;
7940 dadmin->text->text = NULL;
7943 putdeltatext (fout, dtext);
7944 freedeltatext (dtext);
7946 if (found && !insertbefore)
7948 putdeltatext (fout, newdtext);
7954 /* Copy the rest of the file directly, without bothering to
7955 interpret it. The caller will handle error checking by calling
7958 We just wrote a newline to the file, either in putdeltatext or
7959 in the caller. However, we may not have read the corresponding
7960 newline from the file, because rcsbuf_getkey returns as soon as
7961 it finds the end of the '@' string for the desc or text key.
7962 Therefore, we may read three newlines when we should really
7963 only write two, and we check for that case here. This is not
7964 an semantically important issue; we only do it to make our RCS
7965 files look traditional. */
7969 rcsbuf_get_buffered (rcsbufin, &bufrest, &buflen);
7972 if (bufrest[0] != '\n'
7973 || strncmp (bufrest, "\n\n\n", buflen < 3 ? buflen : 3) != 0)
7989 fwrite (bufrest, 1, buflen, fout);
7992 /* This bit isn't necessary when using mmap since the entire file
7993 * will already be available via the RCS buffer. Besides, the
7994 * mmap code doesn't always keep the file pointer up to date, so
7995 * this adds some data twice.
7997 while ((got = fread (buf, 1, sizeof buf, fin)) != 0)
8002 && strncmp (buf, "\n\n\n", nls) == 0)
8004 fwrite (buf + 1, 1, got - 1, fout);
8008 fwrite (buf, 1, got, fout);
8013 #endif /* HAVE_MMAP */
8016 /* A helper procedure for RCS_copydeltas. This is called via walklist
8017 to count the number of RCS revisions for which some special action
8021 count_delta_actions (Node *np, void *ignore)
8023 RCSVers *dadmin = np->data;
8025 if (dadmin->outdated)
8028 if (dadmin->text != NULL
8029 && (dadmin->text->log != NULL || dadmin->text->text != NULL))
8040 * Clean up temporary files.
8043 * This function needs to be reentrant since a call to exit() can cause a
8044 * call to this function, which can then be interrupted by a signal, which
8045 * can cause a second call to this function.
8053 static short int never_run_again = 0;
8055 TRACE (TRACE_FUNCTION, "rcs_cleanup()");
8057 /* Since main_cleanup() always calls exit() (via error (1, ...)), we avoid
8058 * allowing this function to be called twice as an optimization.
8060 * If we are already in a signal critical section, assume we were called
8061 * via the signal handler and set a flag which will prevent future calls.
8062 * The only time that we should get into one of these functions otherwise
8063 * while still in a critical section is if error(1,...) is called from a
8064 * critical section, in which case we are exiting and interrupts are
8065 * already being ignored.
8067 * For Lock_Cleanup(), this is not a run_once variable since Lock_Cleanup()
8068 * can be called to clean up the current lock set multiple times by the
8069 * same run of a CVS command.
8071 * For server_cleanup() and rcs_cleanup(), this is not a run_once variable
8072 * since a call to the cleanup function from atexit() could be interrupted
8073 * by the interrupt handler.
8075 if (never_run_again) return;
8076 if (SIG_inCrSect()) never_run_again = 1;
8078 /* FIXME: Do not perform buffered I/O from an interrupt handler like
8079 * this (via error). However, I'm leaving the error-calling code there
8080 * in the hope that on the rare occasion the error call is actually made
8081 * (e.g., a fluky I/O error or permissions problem prevents the deletion
8082 * of a just-created file) reentrancy won't be an issue.
8085 /* Avoid being interrupted during calls which set globals to NULL. This
8086 * avoids having interrupt handlers attempt to use these global variables
8087 * in inconsistent states.
8090 if (rcs_lockfile != NULL)
8092 /* Use a tmp var since any of these functions could call exit, causing
8093 * us to be called a second time.
8095 char *tmp = rcs_lockfile;
8096 rcs_lockfile = NULL;
8097 if (rcs_lockfd >= 0)
8099 if (close (rcs_lockfd) != 0)
8100 error (0, errno, "error closing lock file %s", tmp);
8104 /* Note that the checks for existence_error are because we can be
8105 * called from a signal handler, so we don't know whether the
8106 * files got created.
8108 if (unlink_file (tmp) < 0
8109 && !existence_error (errno))
8110 error (0, errno, "cannot remove %s", tmp);
8117 /* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style
8118 locking on the specified RCSFILE: for a file called `foo,v', open
8119 for writing a file called `,foo,'.
8121 Note that we what do here is quite different from what RCS does.
8122 RCS creates the ,foo, file before it reads the RCS file (if it
8123 knows that it will be writing later), so that it actually serves as
8124 a lock. We don't; instead we rely on CVS writelocks. This means
8125 that if someone is running RCS on the file at the same time they
8126 are running CVS on it, they might lose (we read the file,
8127 then RCS writes it, then we write it, clobbering the
8128 changes made by RCS). I believe the current sentiment about this
8129 is "well, don't do that".
8131 A concern has been expressed about whether adopting the RCS
8132 strategy would slow us down. I don't think so, since we need to
8133 write the ,foo, file anyway (unless perhaps if O_EXCL is slower or
8136 These do not perform quite the same function as the RCS -l option
8137 for locking files: they are intended to prevent competing RCS
8138 processes from stomping all over each other's laundry. Hence,
8139 they are `internal' locking functions.
8141 If there is an error, give a fatal error; if we return we always
8142 return a non-NULL value. */
8145 rcs_internal_lockfile (char *rcsfile)
8149 static int first_call = 1;
8154 /* Clean up if we get a signal or exit. */
8155 cleanup_register (rcs_cleanup);
8158 /* Get the lock file name: `,file,' for RCS file `file,v'. */
8159 assert (rcs_lockfile == NULL);
8160 assert (rcs_lockfd < 0);
8161 rcs_lockfile = rcs_lockfilename (rcsfile);
8163 /* Use the existing RCS file mode, or read-only if this is a new
8164 file. (Really, this is a lie -- if this is a new file,
8165 RCS_checkin uses the permissions from the working copy. For
8166 actually creating the file, we use 0444 as a safe default mode.) */
8167 if( CVS_STAT( rcsfile, &rstat ) < 0 )
8169 if (existence_error (errno))
8170 rstat.st_mode = S_IRUSR | S_IRGRP | S_IROTH;
8172 error (1, errno, "cannot stat %s", rcsfile);
8175 /* Try to open exclusively. POSIX.1 guarantees that O_EXCL|O_CREAT
8176 guarantees an exclusive open. According to the RCS source, with
8177 NFS v2 we must also throw in O_TRUNC and use an open mask that makes
8178 the file unwriteable. For extensive justification, see the comments for
8179 rcswriteopen() in rcsedit.c, in RCS 5.7. This is kind of pointless
8180 in the CVS case; see comment at the start of this file concerning
8181 general ,foo, file strategy.
8183 There is some sentiment that with NFSv3 and such, that one can
8184 rely on O_EXCL these days. This might be true for unix (I
8185 don't really know), but I am still pretty skeptical in the case
8186 of the non-unix systems. */
8187 rcs_lockfd = open (rcs_lockfile,
8188 OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
8189 S_IRUSR | S_IRGRP | S_IROTH);
8193 error (1, errno, "could not open lock file `%s'", rcs_lockfile);
8196 /* Force the file permissions, and return a stream object. */
8197 /* Because we change the modes later, we don't worry about
8198 this in the non-HAVE_FCHMOD case. */
8200 if (fchmod (rcs_lockfd, rstat.st_mode) < 0)
8201 error (1, errno, "cannot change mode for %s", rcs_lockfile);
8203 fp = fdopen (rcs_lockfd, FOPEN_BINARY_WRITE);
8205 error (1, errno, "cannot fdopen %s", rcs_lockfile);
8211 rcs_internal_unlockfile (FILE *fp, char *rcsfile)
8213 assert (rcs_lockfile != NULL);
8214 assert (rcs_lockfd >= 0);
8216 /* Abort if we could not write everything successfully to LOCKFILE.
8217 This is not a great error-handling mechanism, but should prevent
8218 corrupting the repository. */
8221 /* Using errno here may well be misleanding since the most recent
8222 call that set errno may not have anything whatsoever to do with
8223 the error that set the flag, but it's better than nothing. The
8224 real solution is to check each call to fprintf rather than waiting
8225 until the end like this. */
8226 error (1, errno, "error writing to lock file %s", rcs_lockfile);
8227 if (fclose (fp) == EOF)
8228 error (1, errno, "error closing lock file %s", rcs_lockfile);
8231 rename_file (rcs_lockfile, rcsfile);
8234 /* Use a temporary to make sure there's no interval
8235 (after rcs_lockfile has been freed but before it's set to NULL)
8236 during which the signal handler's use of rcs_lockfile would
8237 reference freed memory. */
8238 char *tmp = rcs_lockfile;
8239 rcs_lockfile = NULL;
8245 rcs_lockfilename (const char *rcsfile)
8247 char *lockfile, *lockp;
8248 const char *rcsbase, *rcsp, *rcsend;
8251 /* Create the lockfile name. */
8252 rcslen = strlen (rcsfile);
8253 lockfile = (char *) xmalloc (rcslen + 10);
8254 rcsbase = last_component (rcsfile);
8255 rcsend = rcsfile + rcslen - sizeof(RCSEXT);
8256 for (lockp = lockfile, rcsp = rcsfile; rcsp < rcsbase; ++rcsp)
8259 while (rcsp <= rcsend)
8267 /* Rewrite an RCS file. The basic idea here is that the caller should
8268 first call RCS_reparsercsfile, then munge the data structures as
8269 desired (via RCS_delete_revs, RCS_settag, &c), then call RCS_rewrite. */
8272 RCS_rewrite (RCSNode *rcs, Deltatext *newdtext, char *insertpt)
8275 struct rcsbuffer rcsbufin;
8280 /* Make sure we're operating on an actual file and not a symlink. */
8281 resolve_symlink (&(rcs->path));
8283 fout = rcs_internal_lockfile (rcs->path);
8285 RCS_putadmin (rcs, fout);
8286 RCS_putdtree (rcs, rcs->head, fout);
8287 RCS_putdesc (rcs, fout);
8289 /* Open the original RCS file and seek to the first delta text. */
8290 rcsbuf_cache_open (rcs, rcs->delta_pos, &fin, &rcsbufin);
8292 /* Update delta_pos to the current position in the output file.
8293 Do NOT move these statements: they must be done after fin has
8294 been positioned at the old delta_pos, but before any delta
8295 texts have been written to fout.
8297 rcs->delta_pos = ftello (fout);
8298 if (rcs->delta_pos == -1)
8299 error (1, errno, "cannot ftello in RCS file %s", rcs->path);
8301 RCS_copydeltas (rcs, fin, &rcsbufin, fout, newdtext, insertpt);
8303 /* We don't want to call rcsbuf_cache here, since we're about to
8305 rcsbuf_close (&rcsbufin);
8307 /* The only case in which using errno here would be meaningful
8308 is if we happen to have left errno unmolested since the call
8309 which produced the error (e.g. fread). That is pretty
8310 fragile even if it happens to sometimes be true. The real
8311 solution is to make sure that all the code which reads
8312 from fin checks for errors itself (some does, some doesn't). */
8313 error (0, 0, "warning: ferror set while rewriting RCS file `%s'", rcs->path);
8314 if (fclose (fin) < 0)
8315 error (0, errno, "warning: closing RCS file `%s'", rcs->path);
8317 rcs_internal_unlockfile (fout, rcs->path);
8320 /* Abandon changes to an RCS file. */
8323 RCS_abandon (RCSNode *rcs)
8325 free_rcsnode_contents (rcs);
8326 rcs->symbols_data = NULL;
8329 rcs->locks_data = NULL;
8330 rcs->comment = NULL;
8332 rcs->flags |= PARTIAL;
8336 * For a given file with full pathname PATH and revision number REV,
8337 * produce a file label suitable for passing to diff. The default
8338 * file label as used by RCS 5.7 looks like this:
8340 * FILENAME <tab> YYYY/MM/DD <sp> HH:MM:SS <tab> REVNUM
8342 * The date and time used are the revision's last checkin date and time.
8343 * If REV is NULL, use the working copy's mtime instead.
8345 * /dev/null is not statted but assumed to have been created on the Epoch.
8346 * At least using the POSIX.2 definition of patch, this should cause creation
8347 * of files on platforms such as Windoze where the null IO device isn't named
8348 * /dev/null to be parsed by patch properly.
8351 make_file_label (const char *path, const char *rev, RCSNode *rcs)
8353 char datebuf[MAXDATELEN + 1];
8356 label = (char *) xmalloc (strlen (path)
8357 + (rev == NULL ? 0 : strlen (rev) + 1)
8363 char date[MAXDATELEN + 1];
8364 /* revs cannot be attached to /dev/null ... duh. */
8365 assert (strcmp(DEVNULL, path));
8366 RCS_getrevtime (rcs, rev, datebuf, 0);
8367 (void) date_to_internet (date, datebuf);
8368 (void) sprintf (label, "-L%s\t%s\t%s", path, date, rev);
8375 if (strcmp(DEVNULL, path))
8377 const char *file = last_component (path);
8378 if (CVS_STAT (file, &sb) < 0)
8379 /* Assume that if the stat fails,then the later read for the
8382 error (1, errno, "could not get info for `%s'", path);
8383 wm = gmtime (&sb.st_mtime);
8391 (void) tm_to_internet (datebuf, wm);
8392 (void) sprintf (label, "-L%s\t%s", path, datebuf);
8398 RCS_setlocalid (const char *arg)
8400 char *copy, *next, *key;
8402 copy = xstrdup(arg);
8404 key = strtok(next, "=");
8406 keywords[KEYWORD_LOCALID].string = xstrdup(key);
8407 keywords[KEYWORD_LOCALID].len = strlen(key);
8408 keywords[KEYWORD_LOCALID].expandit = 1;
8411 while ((key = strtok(NULL, ",")) != NULL) {
8412 if (!strcmp(key, keywords[KEYWORD_ID].string))
8413 keyword_local = KEYWORD_ID;
8414 else if (!strcmp(key, keywords[KEYWORD_HEADER].string))
8415 keyword_local = KEYWORD_HEADER;
8416 else if (!strcmp(key, keywords[KEYWORD_CVSHEADER].string))
8417 keyword_local = KEYWORD_CVSHEADER;
8419 error(1, 0, "Unknown LocalId mode: %s", key);
8425 RCS_setincexc (const char *arg)
8430 struct rcs_keyword *keyword;
8432 copy = xstrdup(arg);
8447 for (keyword = keywords; keyword->string != NULL; keyword++)
8449 keyword->expandit = 0;
8452 key = strtok(next, ",");
8454 for (keyword = keywords; keyword->string != NULL; keyword++) {
8455 if (strcmp (keyword->string, key) == 0)
8456 keyword->expandit = include;
8458 key = strtok(NULL, ",");
8464 #define ATTIC "/" CVSATTIC
8466 getfullCVSname(char *CVSname, char **pathstore)
8468 if (current_parsed_root->directory) {
8471 int alen = sizeof(ATTIC) - 1;
8473 *pathstore = xstrdup(CVSname);
8474 if ((c = strrchr(*pathstore, '/')) != NULL) {
8475 if (c - *pathstore >= alen) {
8476 if (!strncmp(c - alen, ATTIC, alen)) {
8477 while (*c != '\0') {
8486 rootlen = strlen(current_parsed_root->directory);
8487 if (!strncmp(*pathstore, current_parsed_root->directory, rootlen) &&
8488 (*pathstore)[rootlen] == '/')
8489 CVSname = (*pathstore + rootlen + 1);
8491 CVSname = (*pathstore);