2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner
10 * You may distribute under the terms of the GNU General Public License as
11 * specified in the README file that comes with the CVS source distribution.
13 * The routines contained in this file do all the rcs file parsing and
21 /* These need to be source after cvs.h or HAVE_MMAP won't be set... */
23 # include "getpagesize.h"
24 # include <sys/mman.h>
26 /* Define MAP_FILE when it isn't otherwise. */
30 /* Define MAP_FAILED for old systems which neglect to. */
32 # define MAP_FAILED ((void *)-1)
36 /* The RCS -k options, and a set of enums that must match the array.
37 These come first so that we can use enum kflag in function
39 static const char *const kflags[] =
40 {"kv", "kvl", "k", "v", "o", "b", NULL};
41 enum kflag { KFLAG_KV = 0, KFLAG_KVL, KFLAG_K, KFLAG_V, KFLAG_O, KFLAG_B };
43 /* A structure we use to buffer the contents of an RCS file. The
44 various fields are only referenced directly by the rcsbuf_*
45 functions. We declare the struct here so that we can allocate it
46 on the stack, rather than in memory. */
50 /* Points to the current position in the buffer. */
52 /* Points just after the last valid character in the buffer. */
56 /* The name of the file, used for error messages. */
58 /* The starting file position of the data in the buffer. */
60 /* The length of the value. */
62 /* Whether the value contains an '@' string. If so, we can not
63 compress whitespace characters. */
65 /* The number of embedded '@' characters in an '@' string. If
66 this is non-zero, we must search the string for pairs of '@'
67 and convert them to a single '@'. */
71 static RCSNode *RCS_parsercsfile_i (FILE * fp, const char *rcsfile);
72 static char *RCS_getdatebranch (RCSNode * rcs, const char *date,
74 static void rcsbuf_open (struct rcsbuffer *, FILE *fp,
75 const char *filename, unsigned long pos);
76 static void rcsbuf_close (struct rcsbuffer *);
77 static int rcsbuf_getkey (struct rcsbuffer *, char **keyp, char **valp);
78 static int rcsbuf_getrevnum (struct rcsbuffer *, char **revp);
79 static char *rcsbuf_fill (struct rcsbuffer *, char *ptr, char **keyp,
81 static int rcsbuf_valcmp (struct rcsbuffer *);
82 static char *rcsbuf_valcopy (struct rcsbuffer *, char *val, int polish,
84 static void rcsbuf_valpolish (struct rcsbuffer *, char *val, int polish,
86 static void rcsbuf_valpolish_internal (struct rcsbuffer *, char *to,
87 const char *from, size_t *lenp);
88 static off_t rcsbuf_ftello (struct rcsbuffer *);
89 static void rcsbuf_get_buffered (struct rcsbuffer *, char **datap,
91 static void rcsbuf_cache (RCSNode *, struct rcsbuffer *);
92 static void rcsbuf_cache_close (void);
93 static void rcsbuf_cache_open (RCSNode *, off_t, FILE **, struct rcsbuffer *);
94 static int checkmagic_proc (Node *p, void *closure);
95 static void do_branches (List * list, char *val);
96 static void do_symbols (List * list, char *val);
97 static void do_locks (List * list, char *val);
98 static void free_rcsnode_contents (RCSNode *);
99 static void free_rcsvers_contents (RCSVers *);
100 static void rcsvers_delproc (Node * p);
101 static char *translate_symtag (RCSNode *, const char *);
102 static char *RCS_addbranch (RCSNode *, const char *);
103 static char *truncate_revnum_in_place (char *);
104 static char *truncate_revnum (const char *);
105 static char *printable_date (const char *);
106 static char *mdoc_date (const char *);
107 static char *escape_keyword_value (const char *, int *);
108 static void expand_keywords (RCSNode *, RCSVers *, const char *,
109 const char *, size_t, enum kflag, char *,
110 size_t, char **, size_t *);
111 static void cmp_file_buffer (void *, const char *, size_t);
113 /* Routines for reading, parsing and writing RCS files. */
114 static RCSVers *getdelta (struct rcsbuffer *, char *, char **, char **);
115 static Deltatext *RCS_getdeltatext (RCSNode *, FILE *, struct rcsbuffer *);
116 static void freedeltatext (Deltatext *);
118 static void RCS_putadmin (RCSNode *, FILE *);
119 static void RCS_putdtree (RCSNode *, char *, FILE *);
120 static void RCS_putdesc (RCSNode *, FILE *);
121 static void putdelta (RCSVers *, FILE *);
122 static int putrcsfield_proc (Node *, void *);
123 static int putsymbol_proc (Node *, void *);
124 static void RCS_copydeltas (RCSNode *, FILE *, struct rcsbuffer *, FILE *,
125 Deltatext *, char *);
126 static int count_delta_actions (Node *, void *);
127 static void putdeltatext (FILE *, Deltatext *);
129 static FILE *rcs_internal_lockfile (char *);
130 static void rcs_internal_unlockfile (FILE *, char *);
131 static char *rcs_lockfilename (const char *);
133 /* The RCS file reading functions are called a lot, and they do some
134 string comparisons. This macro speeds things up a bit by skipping
135 the function call when the first characters are different. It
136 evaluates its arguments multiple times. */
137 #define STREQ(a, b) (*(char *)(a) == *(char *)(b) && strcmp ((a), (b)) == 0)
139 static char * getfullCVSname (char *, char **);
142 * We don't want to use isspace() from the C library because:
144 * 1. The definition of "whitespace" in RCS files includes ASCII
145 * backspace, but the C locale doesn't.
146 * 2. isspace is an very expensive function call in some implementations
147 * due to the addition of wide character support.
149 static const char spacetab[] = {
150 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x00 - 0x0f */
151 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */
152 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */
153 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */
154 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
155 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
156 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x8f */
157 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */
158 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */
159 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */
160 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */
161 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */
162 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
163 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
164 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
165 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0 - 0xff */
168 #define whitespace(c) (spacetab[(unsigned char)c] != 0)
170 static char *rcs_lockfile = NULL;
171 static int rcs_lockfd = -1;
177 * locate_rcs ( const char* file, const char *repository , int *inattic )
179 * Find an RCS file in the repository, case insensitively when the cased name
180 * doesn't exist, we are running as the server, and a client has asked us to
183 * Most parts of CVS will want to rely instead on RCS_parse which calls this
184 * function and is called by recurse.c which then puts the result in useful
185 * places like the rcs field of struct file_info.
189 * repository the repository (including the directory)
190 * file the filename within that directory (without RCSEXT).
191 * inattic NULL or a pointer to the output boolean
195 * inattic If this input was non-null, the destination will be
196 * set to true if the file was found in the attic or
197 * false if not. If no RCS file is found, this value
202 * a newly-malloc'd array containing the absolute pathname of the RCS
203 * file that was found or NULL when none was found.
207 * errno can be set by the return value of the final call to
208 * locate_file_in_dir(). This should resolve to the system's existence error
209 * value (sometime ENOENT) if the Attic directory did not exist and ENOENT if
210 * the Attic was found but no matching files were found in the Attic or its
214 locate_rcs (const char *repository, const char *file, int *inattic)
218 /* First, try to find the file as cased. */
219 retval = xmalloc (strlen (repository)
224 sprintf (retval, "%s/%s%s", repository, file, RCSEXT);
225 if (isreadable (retval))
231 sprintf (retval, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT);
232 if (isreadable (retval))
245 /* A few generic thoughts on error handling, in particular the
246 printing of unexpected characters that we find in the RCS file
247 (that is, why we use '\x%x' rather than %c or some such).
249 * Avoiding %c means we don't have to worry about what is printable
250 and other such stuff. In error handling, often better to keep it
253 * Hex rather than decimal or octal because character set standards
256 * Saying "character 0x%x" might make it sound like we are printing
257 a file offset. So we use '\x%x'.
259 * Would be nice to print the offset within the file, but I can
260 imagine various portability hassles (in particular, whether
261 unsigned long is always big enough to hold file offsets). */
263 /* Parse an rcsfile given a user file name and a repository. If there is
264 an error, we print an error message and return NULL. If the file
265 does not exist, we return NULL without printing anything (I'm not
266 sure this allows the caller to do anything reasonable, but it is
267 the current behavior). */
269 RCS_parse (const char *file, const char *repos)
273 RCSNode *retval = NULL;
277 /* We're creating a new RCSNode, so there is no hope of finding it
279 rcsbuf_cache_close ();
281 if (!(rcsfile = locate_rcs (repos, file, &inattic)))
283 /* Handle the error cases */
285 else if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)))
287 rcs = RCS_parsercsfile_i (fp, rcsfile);
292 rcs->flags |= INATTIC;
298 else if (!existence_error (errno))
300 error (0, errno, "cannot open `%s'", rcsfile);
310 * Parse a specific rcsfile.
313 RCS_parsercsfile (const char *rcsfile)
318 /* We're creating a new RCSNode, so there is no hope of finding it
320 rcsbuf_cache_close ();
322 /* open the rcsfile */
323 if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) == NULL)
325 error (0, errno, "Couldn't open rcs file `%s'", rcsfile);
329 rcs = RCS_parsercsfile_i (fp, rcsfile);
339 RCS_parsercsfile_i (FILE *fp, const char *rcsfile)
342 struct rcsbuffer rcsbuf;
346 rdata = xmalloc (sizeof (RCSNode));
347 memset (rdata, 0, sizeof (RCSNode));
349 rdata->path = xstrdup (rcsfile);
350 rdata->print_path = xstrdup (primary_root_inverse_translate (rcsfile));
352 /* Process HEAD, BRANCH, and EXPAND keywords from the RCS header.
354 Most cvs operations on the main branch don't need any more
355 information. Those that do call RCS_reparsercsfile to parse
356 the rest of the header and the deltas. */
358 rcsbuf_open (&rcsbuf, fp, rcsfile, 0);
360 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
362 if (STREQ (key, RCSDESC))
365 if (STREQ (RCSHEAD, key) && value != NULL)
366 rdata->head = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
368 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
370 if (STREQ (key, RCSDESC))
373 if (STREQ (RCSBRANCH, key) && value != NULL)
377 rdata->branch = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
378 if ((numdots (rdata->branch) & 1) != 0)
380 /* turn it into a branch if it's a revision */
381 cp = strrchr (rdata->branch, '.');
386 /* Look ahead for expand, stopping when we see desc or a revision
392 if (STREQ (RCSEXPAND, key))
394 rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
399 (isdigit ((unsigned char)*cp) || *cp == '.') && *cp != '\0';
405 if (STREQ (RCSDESC, key))
408 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
412 rdata->flags |= PARTIAL;
414 rcsbuf_cache (rdata, &rcsbuf);
419 error (0, 0, "`%s' does not appear to be a valid rcs file",
421 rcsbuf_close (&rcsbuf);
422 freercsnode (&rdata);
429 /* Do the real work of parsing an RCS file.
431 On error, die with a fatal error; if it returns at all it was successful.
433 If PFP is NULL, close the file when done. Otherwise, leave it open
434 and store the FILE * in *PFP. */
436 RCS_reparsercsfile (RCSNode *rdata, FILE **pfp, struct rcsbuffer *rcsbufp)
440 struct rcsbuffer rcsbuf;
447 assert (rdata != NULL);
448 rcsfile = rdata->path;
450 rcsbuf_cache_open (rdata, 0, &fp, &rcsbuf);
453 /* This probably shouldn't be done until later: if a file has an
454 empty revision tree (which is permissible), rdata->versions
455 should be NULL. -twp */
456 rdata->versions = getlist ();
459 * process all the special header information, break out when we get to
460 * the first revision delta
465 /* get the next key/value pair */
468 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
470 error (1, 0, "`%s' does not appear to be a valid rcs file",
477 /* Skip head, branch and expand tags; we already have them. */
478 if (STREQ (key, RCSHEAD)
479 || STREQ (key, RCSBRANCH)
480 || STREQ (key, RCSEXPAND))
485 if (STREQ (key, "access"))
489 /* We pass the POLISH parameter as 1 because
490 RCS_addaccess expects nothing but spaces. FIXME:
491 It would be easy and more efficient to change
496 "Duplicate `access' keyword found in RCS file.");
497 free (rdata->access);
499 rdata->access = rcsbuf_valcopy (&rcsbuf, value, 1, NULL);
504 /* We always save lock information, so that we can handle
505 -kkvl correctly when checking out a file. */
506 if (STREQ (key, "locks"))
510 if (rdata->locks_data)
513 "Duplicate `locks' keyword found in RCS file.");
514 free (rdata->locks_data);
516 rdata->locks_data = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
518 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
520 error (1, 0, "premature end of file reading %s", rcsfile);
522 if (STREQ (key, "strict") && value == NULL)
524 rdata->strict_locks = 1;
531 if (STREQ (RCSSYMBOLS, key))
535 if (rdata->symbols_data)
538 "Duplicate `%s' keyword found in RCS file.",
540 free (rdata->symbols_data);
542 rdata->symbols_data = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
548 * check key for '.''s and digits (probably a rev) if it is a
549 * revision or `desc', we are done with the headers and are down to the
550 * revision deltas, so we break out of the loop
553 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
556 /* Note that when comparing with RCSDATE, we are not massaging
557 VALUE from the string found in the RCS file. This is OK
558 since we know exactly what to expect. */
559 if (*cp == '\0' && strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) == 0)
562 if (STREQ (key, RCSDESC))
565 if (STREQ (key, "comment"))
570 "warning: duplicate key `%s' in RCS file `%s'",
572 free (rdata->comment);
574 rdata->comment = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
577 if (rdata->other == NULL)
578 rdata->other = getlist ();
580 kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
581 kv->key = xstrdup (key);
582 kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD, NULL);
583 if (addnode (rdata->other, kv) != 0)
585 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
590 /* if we haven't grabbed it yet, we didn't want it */
593 /* We got out of the loop, so we have the first part of the first
594 revision delta in KEY (the revision) and VALUE (the date key
595 and its value). This is what getdelta expects to receive. */
597 while ((vnode = getdelta (&rcsbuf, rcsfile, &key, &value)) != NULL)
602 q->delproc = rcsvers_delproc;
604 q->key = vnode->version;
606 /* add the nodes to the list */
607 if (addnode (rdata->versions, q) != 0)
610 purify_printf("WARNING: Adding duplicate version: %s (%s)\n",
617 /* Here KEY and VALUE are whatever caused getdelta to return NULL. */
619 if (STREQ (key, RCSDESC))
621 if (rdata->desc != NULL)
624 "warning: duplicate key `%s' in RCS file `%s'",
628 rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 1, NULL);
631 rdata->delta_pos = rcsbuf_ftello (&rcsbuf);
634 rcsbuf_cache (rdata, &rcsbuf);
640 rdata->flags &= ~PARTIAL;
645 /* Move RCS into or out of the Attic, depending on TOATTIC. If the
646 file is already in the desired place, return without doing
647 anything. At some point may want to think about how this relates
648 to RCS_rewrite but that is a bit hairy (if one wants renames to be
649 atomic, or that kind of thing). If there is an error, print a message
650 and return 1. On success, return 0. */
652 RCS_setattic (RCSNode *rcs, int toattic)
658 /* Some systems aren't going to let us rename an open file. */
659 rcsbuf_cache_close ();
661 /* Could make the pathname computations in this file, and probably
662 in other parts of rcs.c too, easier if the REPOS and FILE
663 arguments to RCS_parse got stashed in the RCSNode. */
669 if (rcs->flags & INATTIC)
672 /* Example: rcs->path is "/foo/bar/baz,v". */
673 newpath = xmalloc (strlen (rcs->path) + sizeof CVSATTIC + 5);
674 p = last_component (rcs->path);
675 strncpy (newpath, rcs->path, p - rcs->path);
676 strcpy (newpath + (p - rcs->path), CVSATTIC);
678 /* Create the Attic directory if it doesn't exist. */
679 omask = umask (cvsumask);
680 if (CVS_MKDIR (newpath, 0777) < 0 && errno != EEXIST)
681 error (0, errno, "cannot make directory %s", newpath);
682 (void) umask (omask);
684 strcat (newpath, "/");
687 if (CVS_RENAME (rcs->path, newpath) < 0)
689 int save_errno = errno;
691 /* The checks for isreadable look awfully fishy, but
692 I'm going to leave them here for now until I
693 can think harder about whether they take care of
694 some cases which should be handled somehow. */
696 if (isreadable (rcs->path) || !isreadable (newpath))
698 error (0, save_errno, "cannot rename %s to %s",
707 if (!(rcs->flags & INATTIC))
710 newpath = xmalloc (strlen (rcs->path));
712 /* Example: rcs->path is "/foo/bar/Attic/baz,v". */
713 p = last_component (rcs->path);
714 strncpy (newpath, rcs->path, p - rcs->path - 1);
715 newpath[p - rcs->path - 1] = '\0';
716 q = newpath + (p - rcs->path - 1) - (sizeof CVSATTIC - 1);
717 assert (strncmp (q, CVSATTIC, sizeof CVSATTIC - 1) == 0);
720 if (CVS_RENAME (rcs->path, newpath) < 0)
722 error (0, errno, "failed to move `%s' out of the attic",
738 * Fully parse the RCS file. Store all keyword/value pairs, fetch the
739 * log messages for each revision, and fetch add and delete counts for
740 * each revision (we could fetch the entire text for each revision,
741 * but the only caller, log_fileproc, doesn't need that information,
742 * so we don't waste the memory required to store it). The add and
743 * delete counts are stored on the OTHER field of the RCSVERSNODE
744 * structure, under the names ";add" and ";delete", so that we don't
745 * waste the memory space of extra fields in RCSVERSNODE for code
746 * which doesn't need this information.
749 RCS_fully_parse (RCSNode *rcs)
752 struct rcsbuffer rcsbuf;
754 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
762 /* Rather than try to keep track of how much information we
763 have read, just read to the end of the file. */
764 if (!rcsbuf_getrevnum (&rcsbuf, &key))
767 vers = findnode (rcs->versions, key);
770 "mismatch in rcs file %s between deltas and deltatexts (%s)",
771 rcs->print_path, key);
775 while (rcsbuf_getkey (&rcsbuf, &key, &value))
777 if (!STREQ (key, "text"))
781 if (vnode->other == NULL)
782 vnode->other = getlist ();
784 kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
785 kv->key = xstrdup (key);
786 kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
788 if (addnode (vnode->other, kv) != 0)
792 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
793 key, vnode->version, rcs->print_path);
800 if (!STREQ (vnode->version, rcs->head))
802 unsigned long add, del;
806 /* This is a change text. Store the add and delete
815 rcsbuf_valpolish (&rcsbuf, value, 0, &vallen);
817 while (cp < value + vallen)
823 if (op != 'a' && op != 'd')
825 unrecognized operation '\\x%x' in %s",
826 op, rcs->print_path);
827 (void) strtoul (cp, (char **) &cp, 10);
829 error (1, 0, "space expected in %s revision %s",
830 rcs->print_path, vnode->version);
831 count = strtoul (cp, (char **) &cp, 10);
833 error (1, 0, "linefeed expected in %s revision %s",
834 rcs->print_path, vnode->version);
845 else if (cp == value + vallen)
849 premature end of value in %s revision %s",
850 rcs->print_path, vnode->version);
860 sprintf (buf, "%lu", add);
863 kv->key = xstrdup (";add");
864 kv->data = xstrdup (buf);
865 if (addnode (vnode->other, kv) != 0)
869 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
870 key, vnode->version, rcs->print_path);
874 sprintf (buf, "%lu", del);
877 kv->key = xstrdup (";delete");
878 kv->data = xstrdup (buf);
879 if (addnode (vnode->other, kv) != 0)
883 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
884 key, vnode->version, rcs->print_path);
889 /* We have found the "text" key which ends the data for
890 this revision. Break out of the loop and go on to the
896 rcsbuf_cache (rcs, &rcsbuf);
902 * freercsnode - free up the info for an RCSNode
905 freercsnode (RCSNode **rnodep)
907 if (rnodep == NULL || *rnodep == NULL)
910 ((*rnodep)->refcount)--;
911 if ((*rnodep)->refcount != 0)
916 free ((*rnodep)->path);
917 free ((*rnodep)->print_path);
918 if ((*rnodep)->head != NULL)
919 free ((*rnodep)->head);
920 if ((*rnodep)->branch != NULL)
921 free ((*rnodep)->branch);
922 free_rcsnode_contents (*rnodep);
930 * free_rcsnode_contents - free up the contents of an RCSNode without
931 * freeing the node itself, or the file name, or the head, or the
932 * path. This returns the RCSNode to the state it is in immediately
933 * after a call to RCS_parse.
936 free_rcsnode_contents (RCSNode *rnode)
938 dellist (&rnode->versions);
939 if (rnode->symbols != NULL)
940 dellist (&rnode->symbols);
941 if (rnode->symbols_data != NULL)
942 free (rnode->symbols_data);
943 if (rnode->expand != NULL)
944 free (rnode->expand);
945 if (rnode->other != NULL)
946 dellist (&rnode->other);
947 if (rnode->access != NULL)
948 free (rnode->access);
949 if (rnode->locks_data != NULL)
950 free (rnode->locks_data);
951 if (rnode->locks != NULL)
952 dellist (&rnode->locks);
953 if (rnode->comment != NULL)
954 free (rnode->comment);
955 if (rnode->desc != NULL)
961 /* free_rcsvers_contents -- free up the contents of an RCSVers node,
962 but also free the pointer to the node itself. */
963 /* Note: The `hardlinks' list is *not* freed, since it is merely a
964 pointer into the `hardlist' structure (defined in hardlink.c), and
965 that structure is freed elsewhere in the program. */
967 free_rcsvers_contents (RCSVers *rnode)
969 if (rnode->branches != NULL)
970 dellist (&rnode->branches);
971 if (rnode->date != NULL)
973 if (rnode->next != NULL)
975 if (rnode->author != NULL)
976 free (rnode->author);
977 if (rnode->state != NULL)
979 if (rnode->other != NULL)
980 dellist (&rnode->other);
981 if (rnode->other_delta != NULL)
982 dellist (&rnode->other_delta);
983 if (rnode->text != NULL)
984 freedeltatext (rnode->text);
991 * rcsvers_delproc - free up an RCSVers type node
994 rcsvers_delproc (Node *p)
996 free_rcsvers_contents (p->data);
1001 /* These functions retrieve keys and values from an RCS file using a
1002 buffer. We use this somewhat complex approach because it turns out
1003 that for many common operations, CVS spends most of its time
1004 reading keys, so it's worth doing some fairly hairy optimization. */
1006 /* The number of bytes we try to read each time we need more data. */
1008 #define RCSBUF_BUFSIZE (8192)
1010 /* The buffer we use to store data. This grows as needed. */
1012 static char *rcsbuf_buffer = NULL;
1013 static size_t rcsbuf_buffer_size = 0;
1015 /* Whether rcsbuf_buffer is in use. This is used as a sanity check. */
1017 static int rcsbuf_inuse;
1019 /* Set up to start gathering keys and values from an RCS file. This
1020 initializes RCSBUF. */
1023 rcsbuf_open (struct rcsbuffer *rcsbuf, FILE *fp, const char *filename,
1024 long unsigned int pos)
1027 error (1, 0, "rcsbuf_open: internal error");
1032 /* When we have mmap, it is much more efficient to let the system do the
1033 * buffering and caching for us
1036 size_t mmap_off = 0;
1038 if ( fstat (fileno(fp), &fs) < 0 )
1039 error ( 1, errno, "Could not stat RCS archive %s for mapping", filename );
1043 size_t ps = getpagesize ();
1044 mmap_off = ( pos / ps ) * ps;
1047 /* Map private here since this particular buffer is read only */
1048 rcsbuf_buffer = mmap ( NULL, fs.st_size - mmap_off,
1049 PROT_READ | PROT_WRITE,
1050 MAP_PRIVATE, fileno(fp), mmap_off );
1051 if ( rcsbuf_buffer == NULL || rcsbuf_buffer == MAP_FAILED )
1052 error ( 1, errno, "Could not map memory to RCS archive %s", filename );
1054 rcsbuf_buffer_size = fs.st_size - mmap_off;
1055 rcsbuf->ptr = rcsbuf_buffer + pos - mmap_off;
1056 rcsbuf->ptrend = rcsbuf_buffer + fs.st_size - mmap_off;
1057 rcsbuf->pos = mmap_off;
1059 #else /* !HAVE_MMAP */
1060 if (rcsbuf_buffer_size < RCSBUF_BUFSIZE)
1061 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, RCSBUF_BUFSIZE);
1063 rcsbuf->ptr = rcsbuf_buffer;
1064 rcsbuf->ptrend = rcsbuf_buffer;
1066 #endif /* HAVE_MMAP */
1068 rcsbuf->filename = filename;
1070 rcsbuf->at_string = 0;
1071 rcsbuf->embedded_at = 0;
1076 /* Stop gathering keys from an RCS file. */
1078 rcsbuf_close (struct rcsbuffer *rcsbuf)
1081 error (1, 0, "rcsbuf_close: internal error");
1083 munmap ( rcsbuf_buffer, rcsbuf_buffer_size );
1090 /* Read a key/value pair from an RCS file. This sets *KEYP to point
1091 to the key, and *VALUEP to point to the value. A missing or empty
1092 value is indicated by setting *VALUEP to NULL.
1094 This function returns 1 on success, or 0 on EOF. If there is an
1095 error reading the file, or an EOF in an unexpected location, it
1096 gives a fatal error.
1098 This sets *KEYP and *VALUEP to point to storage managed by
1099 rcsbuf_getkey. Moreover, *VALUEP has not been massaged from the
1100 RCS format: it may contain embedded whitespace and embedded '@'
1101 characters. Call rcsbuf_valcopy or rcsbuf_valpolish to do
1102 appropriate massaging. */
1104 /* Note that the extreme hair in rcsbuf_getkey is because profiling
1105 statistics show that it was worth it. */
1107 rcsbuf_getkey (struct rcsbuffer *rcsbuf, char **keyp, char **valp)
1109 register const char * const my_spacetab = spacetab;
1110 register char *ptr, *ptrend;
1113 #define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
1116 rcsbuf->at_string = 0;
1117 rcsbuf->embedded_at = 0;
1120 ptrend = rcsbuf->ptrend;
1123 assert (ptr >= rcsbuf_buffer && ptr <= rcsbuf_buffer + rcsbuf_buffer_size);
1124 assert (ptrend >= rcsbuf_buffer && ptrend <= rcsbuf_buffer + rcsbuf_buffer_size);
1127 /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
1128 buffer, move back to the start of the buffer. This keeps the
1129 buffer from growing indefinitely. */
1130 if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
1136 /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
1137 at a time, so we can't have more bytes than that past PTR. */
1138 assert (len <= RCSBUF_BUFSIZE);
1140 /* Update the POS field, which holds the file offset of the
1141 first byte in the RCSBUF_BUFFER buffer. */
1142 rcsbuf->pos += ptr - rcsbuf_buffer;
1144 memcpy (rcsbuf_buffer, ptr, len);
1145 ptr = rcsbuf_buffer;
1147 rcsbuf->ptrend = ptrend;
1149 #endif /* HAVE_MMAP */
1151 /* Skip leading whitespace. */
1157 ptr = rcsbuf_fill (rcsbuf, ptr, NULL, NULL);
1160 ptrend = rcsbuf->ptrend;
1164 if (! my_whitespace (c))
1170 /* We've found the start of the key. */
1181 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, NULL);
1183 error (1, 0, "EOF in key in RCS file %s",
1184 primary_root_inverse_translate (rcsbuf->filename));
1185 ptrend = rcsbuf->ptrend;
1188 if (c == ';' || my_whitespace (c))
1193 /* Here *KEYP points to the key in the buffer, C is the character
1194 we found at the of the key, and PTR points to the location in
1195 the buffer where we found C. We must set *PTR to \0 in order
1196 to terminate the key. If the key ended with ';', then there is
1209 /* C must be whitespace. Skip whitespace between the key and the
1210 value. If we find ';' now, there is no value. */
1216 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, NULL);
1218 error (1, 0, "EOF while looking for value in RCS file %s",
1219 primary_root_inverse_translate (rcsbuf->filename));
1220 ptrend = rcsbuf->ptrend;
1226 rcsbuf->ptr = ptr + 1;
1229 if (! my_whitespace (c))
1234 /* Now PTR points to the start of the value, and C is the first
1235 character of the value. */
1244 /* Optimize the common case of a value composed of a single
1247 rcsbuf->at_string = 1;
1255 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1257 /* Note that we pass PTREND as the PTR value to
1258 rcsbuf_fill, so that we will wind up setting PTR to
1259 the location corresponding to the old PTREND, so
1260 that we don't search the same bytes again. */
1261 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1264 "EOF while looking for end of string in RCS file %s",
1265 primary_root_inverse_translate (rcsbuf->filename));
1266 ptrend = rcsbuf->ptrend;
1269 /* Handle the special case of an '@' right at the end of
1271 if (pat + 1 >= ptrend)
1273 /* Note that we pass PAT, not PTR, here. */
1274 pat = rcsbuf_fill (rcsbuf, pat, keyp, valp);
1277 /* EOF here is OK; it just means that the last
1278 character of the file was an '@' terminating a
1279 value for a key type which does not require a
1281 pat = rcsbuf->ptrend - 1;
1284 ptrend = rcsbuf->ptrend;
1286 /* Note that the value of PTR is bogus here. This is
1287 OK, because we don't use it. */
1290 if (pat + 1 >= ptrend || pat[1] != '@')
1293 /* We found an '@' pair in the string. Keep looking. */
1294 ++rcsbuf->embedded_at;
1298 /* Here PAT points to the final '@' in the string. */
1305 rcsbuf->vlen = vlen;
1310 /* Certain keywords only have a '@' string. If there is no '@'
1311 string, then the old getrcskey function assumed that they had
1312 no value, and we do the same. */
1318 if (STREQ (k, RCSDESC)
1319 || STREQ (k, "text")
1320 || STREQ (k, "log"))
1329 /* If we've already gathered a '@' string, try to skip whitespace
1339 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1341 error (1, 0, "EOF in value in RCS file %s",
1342 primary_root_inverse_translate (rcsbuf->filename));
1343 ptrend = rcsbuf->ptrend;
1348 /* We're done. We already set everything up for this
1350 rcsbuf->ptr = ptr + 1;
1353 if (! my_whitespace (n))
1358 /* The value extends past the '@' string. We need to undo the
1359 '@' stripping done in the default case above. This
1360 case never happens in a plain RCS file, but it can happen
1361 if user defined phrases are used. */
1362 ((*valp)--)[rcsbuf->vlen++] = '@';
1365 /* Here we have a value which is not a simple '@' string. We need
1366 to gather up everything until the next ';', including any '@'
1367 strings. *VALP points to the start of the value. If
1368 RCSBUF->VLEN is not zero, then we have already read an '@'
1369 string, and PTR points to the data following the '@' string.
1370 Otherwise, PTR points to the start of the value. */
1374 char *start, *psemi, *pat;
1376 /* Find the ';' which must end the value. */
1378 while ((psemi = memchr (ptr, ';', ptrend - ptr)) == NULL)
1382 /* Note that we pass PTREND as the PTR value to
1383 rcsbuf_fill, so that we will wind up setting PTR to the
1384 location corresponding to the old PTREND, so that we
1385 don't search the same bytes again. */
1386 slen = start - *valp;
1387 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1389 error (1, 0, "EOF in value in RCS file %s",
1390 primary_root_inverse_translate (rcsbuf->filename));
1391 start = *valp + slen;
1392 ptrend = rcsbuf->ptrend;
1395 /* See if there are any '@' strings in the value. */
1396 pat = memchr (start, '@', psemi - start);
1402 /* We're done with the value. Trim any trailing
1405 rcsbuf->ptr = psemi + 1;
1408 while (psemi > start && my_whitespace (psemi[-1]))
1412 vlen = psemi - start;
1415 rcsbuf->vlen = vlen;
1420 /* We found an '@' string in the value. We set RCSBUF->AT_STRING
1421 and RCSBUF->EMBEDDED_AT to indicate that we won't be able to
1422 compress whitespace correctly for this type of value.
1423 Since this type of value never arises in a normal RCS file,
1424 this should not be a big deal. It means that if anybody
1425 adds a phrase which can have both an '@' string and regular
1426 text, they will have to handle whitespace compression
1429 rcsbuf->at_string = 1;
1430 rcsbuf->embedded_at = -1;
1436 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1438 /* Note that we pass PTREND as the PTR value to
1439 rcsbuff_fill, so that we will wind up setting PTR
1440 to the location corresponding to the old PTREND, so
1441 that we don't search the same bytes again. */
1442 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1445 "EOF while looking for end of string in RCS file %s",
1446 primary_root_inverse_translate (rcsbuf->filename));
1447 ptrend = rcsbuf->ptrend;
1450 /* Handle the special case of an '@' right at the end of
1452 if (pat + 1 >= ptrend)
1454 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1456 error (1, 0, "EOF in value in RCS file %s",
1457 primary_root_inverse_translate (rcsbuf->filename));
1458 ptrend = rcsbuf->ptrend;
1464 /* We found an '@' pair in the string. Keep looking. */
1468 /* Here PAT points to the final '@' in the string. */
1472 #undef my_whitespace
1477 /* Read an RCS revision number from an RCS file. This sets *REVP to
1478 point to the revision number; it will point to space that is
1479 managed by the rcsbuf functions, and is only good until the next
1480 call to rcsbuf_getkey or rcsbuf_getrevnum.
1482 This function returns 1 on success, or 0 on EOF. If there is an
1483 error reading the file, or an EOF in an unexpected location, it
1484 gives a fatal error. */
1486 rcsbuf_getrevnum (struct rcsbuffer *rcsbuf, char **revp)
1492 ptrend = rcsbuf->ptrend;
1496 /* Skip leading whitespace. */
1502 ptr = rcsbuf_fill (rcsbuf, ptr, NULL, NULL);
1505 ptrend = rcsbuf->ptrend;
1509 if (! whitespace (c))
1515 if (! isdigit ((unsigned char) c) && c != '.')
1518 unexpected '\\x%x' reading revision number in RCS file %s",
1519 c, primary_root_inverse_translate (rcsbuf->filename));
1528 ptr = rcsbuf_fill (rcsbuf, ptr, revp, NULL);
1531 "unexpected EOF reading revision number in RCS file %s",
1532 primary_root_inverse_translate (rcsbuf->filename));
1533 ptrend = rcsbuf->ptrend;
1538 while (isdigit ((unsigned char) c) || c == '.');
1540 if (! whitespace (c))
1542 unexpected '\\x%x' reading revision number in RCS file %s",
1543 c, primary_root_inverse_translate (rcsbuf->filename));
1547 rcsbuf->ptr = ptr + 1;
1554 /* Fill RCSBUF_BUFFER with bytes from the file associated with RCSBUF,
1555 updating PTR and the PTREND field. If KEYP and *KEYP are not NULL,
1556 then *KEYP points into the buffer, and must be adjusted if the
1557 buffer is changed. Likewise for VALP. Returns the new value of
1558 PTR, or NULL on error. */
1560 rcsbuf_fill (struct rcsbuffer *rcsbuf, char *ptr, char **keyp, char **valp)
1564 #else /* HAVE_MMAP */
1567 if (rcsbuf->ptrend - rcsbuf_buffer + RCSBUF_BUFSIZE > rcsbuf_buffer_size)
1569 int poff, peoff, koff, voff;
1571 poff = ptr - rcsbuf_buffer;
1572 peoff = rcsbuf->ptrend - rcsbuf_buffer;
1573 koff = keyp == NULL ? 0 : *keyp - rcsbuf_buffer;
1574 voff = valp == NULL ? 0 : *valp - rcsbuf_buffer;
1576 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size,
1577 rcsbuf_buffer_size + RCSBUF_BUFSIZE);
1579 ptr = rcsbuf_buffer + poff;
1580 rcsbuf->ptrend = rcsbuf_buffer + peoff;
1582 *keyp = rcsbuf_buffer + koff;
1584 *valp = rcsbuf_buffer + voff;
1587 got = fread (rcsbuf->ptrend, 1, RCSBUF_BUFSIZE, rcsbuf->fp);
1590 if (ferror (rcsbuf->fp))
1591 error (1, errno, "cannot read %s", rcsbuf->filename);
1595 rcsbuf->ptrend += got;
1598 #endif /* HAVE_MMAP */
1603 /* Test whether the last value returned by rcsbuf_getkey is a composite
1606 rcsbuf_valcmp (struct rcsbuffer *rcsbuf)
1608 return rcsbuf->at_string && rcsbuf->embedded_at < 0;
1613 /* Copy the value VAL returned by rcsbuf_getkey into a memory buffer,
1614 returning the memory buffer. Polish the value like
1615 rcsbuf_valpolish, q.v. */
1617 rcsbuf_valcopy (struct rcsbuffer *rcsbuf, char *val, int polish, size_t *lenp)
1630 vlen = rcsbuf->vlen;
1631 embedded_at = rcsbuf->embedded_at < 0 ? 0 : rcsbuf->embedded_at;
1633 ret = xmalloc (vlen - embedded_at + 1);
1635 if (rcsbuf->at_string ? embedded_at == 0 : ! polish)
1637 /* No special action to take. */
1638 memcpy (ret, val, vlen + 1);
1644 rcsbuf_valpolish_internal (rcsbuf, ret, val, lenp);
1650 /* Polish the value VAL returned by rcsbuf_getkey. The POLISH
1651 parameter is non-zero if multiple embedded whitespace characters
1652 should be compressed into a single whitespace character. Note that
1653 leading and trailing whitespace was already removed by
1654 rcsbuf_getkey. Within an '@' string, pairs of '@' characters are
1655 compressed into a single '@' character regardless of the value of
1656 POLISH. If LENP is not NULL, set *LENP to the length of the value. */
1658 rcsbuf_valpolish (struct rcsbuffer *rcsbuf, char *val, int polish,
1668 if (rcsbuf->at_string ? rcsbuf->embedded_at == 0 : ! polish)
1670 /* No special action to take. */
1672 *lenp = rcsbuf->vlen;
1676 rcsbuf_valpolish_internal (rcsbuf, val, val, lenp);
1681 /* Internal polishing routine, called from rcsbuf_valcopy and
1682 rcsbuf_valpolish. */
1684 rcsbuf_valpolish_internal (struct rcsbuffer *rcsbuf, char *to,
1685 const char *from, size_t *lenp)
1691 if (! rcsbuf->at_string)
1698 for (clen = len; clen > 0; ++from, --clen)
1705 /* Note that we know that clen can not drop to zero
1706 while we have whitespace, because we know there is
1707 no trailing whitespace. */
1708 while (whitespace (from[1]))
1721 *lenp = to - orig_to;
1725 const char *orig_from;
1733 embedded_at = rcsbuf->embedded_at;
1734 assert (embedded_at > 0);
1737 *lenp = len - embedded_at;
1739 for (clen = len; clen > 0; ++from, --clen)
1751 * FIXME: I restored this to an abort from an assert based on
1752 * advice from Larry Jones that asserts should not be used to
1753 * confirm the validity of an RCS file... This leaves two
1754 * issues here: 1) I am uncertain that the fact that we will
1755 * only find double '@'s hasn't already been confirmed; and:
1756 * 2) If this is the proper place to spot the error in the RCS
1757 * file, then we should print a much clearer error here for the
1762 if (*from != '@' || clen == 0)
1768 if (embedded_at == 0)
1770 /* We've found all the embedded '@' characters.
1771 We can just memcpy the rest of the buffer after
1772 this '@' character. */
1773 if (orig_to != orig_from)
1774 memcpy (to, from + 1, clen - 1);
1776 memmove (to, from + 1, clen - 1);
1785 assert (from == orig_from + len
1786 && to == orig_to + (len - rcsbuf->embedded_at));
1794 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1796 /* Copy the next word from the value VALP returned by rcsbuf_getkey into a
1797 memory buffer, updating VALP and returning the memory buffer. Return
1798 NULL when there are no more words. */
1801 rcsbuf_valword (struct rcsbuffer *rcsbuf, char **valp)
1803 register const char * const my_spacetab = spacetab;
1804 register char *ptr, *pat;
1807 # define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
1812 for (ptr = *valp; my_whitespace (*ptr); ++ptr) ;
1815 assert (ptr - *valp == rcsbuf->vlen);
1821 /* PTR now points to the start of a value. Find out whether it is
1822 a num, an id, a string or a colon. */
1826 rcsbuf->vlen -= ++ptr - *valp;
1828 return xstrdup (":");
1833 int embedded_at = 0;
1837 while ((pat = strchr (pat, '@')) != NULL)
1845 /* Here PAT points to the final '@' in the string. */
1847 assert (rcsbuf->at_string);
1848 vlen = rcsbuf->vlen - (pat - *valp);
1849 rcsbuf->vlen = pat - ptr - 1;
1850 rcsbuf->embedded_at = embedded_at;
1851 ptr = rcsbuf_valcopy (rcsbuf, ptr, 0, NULL);
1853 rcsbuf->vlen = vlen;
1854 if (strchr (pat, '@') == NULL)
1855 rcsbuf->at_string = 0;
1857 rcsbuf->embedded_at = -1;
1861 /* *PTR is neither `:', `;' nor `@', so it should be the start of a num
1862 or an id. Make sure it is not another special character. */
1863 if (c == '$' || c == '.' || c == ',')
1864 error (1, 0, "invalid special character in RCS field in %s",
1865 primary_root_inverse_translate (rcsbuf->filename));
1870 /* Legitimate ID characters are digits, dots and any `graphic
1871 printing character that is not a special.' This test ought
1874 if (!isprint ((unsigned char) c) ||
1875 c == ';' || c == '$' || c == ',' || c == '@' || c == ':')
1879 /* PAT points to the last non-id character in this word, and C is
1880 the character in its memory cell. Check to make sure that it
1881 is a legitimate word delimiter -- whitespace or end. */
1882 if (c != '\0' && !my_whitespace (c))
1883 error (1, 0, "invalid special character in RCS field in %s",
1884 primary_root_inverse_translate (rcsbuf->filename));
1887 rcsbuf->vlen -= pat - *valp;
1889 return xstrdup (ptr);
1891 # undef my_whitespace
1894 #endif /* PRESERVE_PERMISSIONS_SUPPORT */
1898 /* Return the current position of an rcsbuf. */
1900 rcsbuf_ftello (struct rcsbuffer *rcsbuf)
1902 return rcsbuf->pos + rcsbuf->ptr - rcsbuf_buffer;
1907 /* Return a pointer to any data buffered for RCSBUF, along with the
1910 rcsbuf_get_buffered (struct rcsbuffer *rcsbuf, char **datap, size_t *lenp)
1912 *datap = rcsbuf->ptr;
1913 *lenp = rcsbuf->ptrend - rcsbuf->ptr;
1918 /* CVS optimizes by quickly reading some header information from a
1919 file. If it decides it needs to do more with the file, it reopens
1920 it. We speed that up here by maintaining a cache of a single open
1921 file, to save the time it takes to reopen the file in the common
1923 static RCSNode *cached_rcs;
1924 static struct rcsbuffer cached_rcsbuf;
1926 /* Cache RCS and RCSBUF. This takes responsibility for closing
1929 rcsbuf_cache (RCSNode *rcs, struct rcsbuffer *rcsbuf)
1931 if (cached_rcs != NULL)
1932 rcsbuf_cache_close ();
1935 cached_rcsbuf = *rcsbuf;
1940 /* If there is anything in the cache, close it. */
1942 rcsbuf_cache_close (void)
1944 if (cached_rcs != NULL)
1946 rcsbuf_close (&cached_rcsbuf);
1947 if (fclose (cached_rcsbuf.fp) != 0)
1948 error (0, errno, "cannot close %s", cached_rcsbuf.filename);
1949 freercsnode (&cached_rcs);
1956 /* Open an rcsbuffer for RCS, getting it from the cache if possible.
1957 Set *FPP to the file, and *RCSBUFP to the rcsbuf. The file should
1958 be put at position POS. */
1960 rcsbuf_cache_open (RCSNode *rcs, off_t pos, FILE **pfp,
1961 struct rcsbuffer *prcsbuf)
1964 if (cached_rcs == rcs)
1966 if (rcsbuf_ftello (&cached_rcsbuf) != pos)
1968 if (fseeko (cached_rcsbuf.fp, pos, SEEK_SET) != 0)
1969 error (1, 0, "cannot fseeko RCS file %s",
1970 cached_rcsbuf.filename);
1971 cached_rcsbuf.ptr = rcsbuf_buffer;
1972 cached_rcsbuf.ptrend = rcsbuf_buffer;
1973 cached_rcsbuf.pos = pos;
1975 *pfp = cached_rcsbuf.fp;
1977 /* When RCS_parse opens a file using fopen_case, it frees the
1978 filename which we cached in CACHED_RCSBUF and stores a new
1979 file name in RCS->PATH. We avoid problems here by always
1980 copying the filename over. FIXME: This is hackish. */
1981 cached_rcsbuf.filename = rcs->path;
1983 *prcsbuf = cached_rcsbuf;
1987 /* Removing RCS from the cache removes a reference to it. */
1989 if (rcs->refcount <= 0)
1990 error (1, 0, "rcsbuf_cache_open: internal error");
1994 #endif /* ifndef HAVE_MMAP */
1995 /* FIXME: If these routines can be rewritten to not write to the
1996 * rcs file buffer, there would be a considerably larger memory savings
1997 * from using mmap since the shared file would never need be copied to
2000 * If this happens, cached mmapped buffers would be usable, but don't
2001 * forget to make sure rcs->pos < pos here...
2003 if (cached_rcs != NULL)
2004 rcsbuf_cache_close ();
2006 *pfp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ);
2008 error (1, 0, "unable to reopen `%s'", rcs->path);
2012 if (fseeko (*pfp, pos, SEEK_SET) != 0)
2013 error (1, 0, "cannot fseeko RCS file %s", rcs->path);
2015 #endif /* ifndef HAVE_MMAP */
2016 rcsbuf_open (prcsbuf, *pfp, rcs->path, pos);
2019 #endif /* ifndef HAVE_MMAP */
2025 * process the symbols list of the rcs file
2028 do_symbols (List *list, char *val)
2038 /* skip leading whitespace */
2039 while (whitespace (*cp))
2042 /* if we got to the end, we are done */
2046 /* split it up into tag and rev */
2048 cp = strchr (cp, ':');
2051 while (!whitespace (*cp) && *cp != '\0')
2056 /* make a new node and add it to the list */
2058 p->key = xstrdup (tag);
2059 p->data = xstrdup (rev);
2060 (void) addnode (list, p);
2067 * process the locks list of the rcs file
2068 * Like do_symbols, but hash entries are keyed backwards: i.e.
2069 * an entry like `user:rev' is keyed on REV rather than on USER.
2072 do_locks (List *list, char *val)
2082 /* skip leading whitespace */
2083 while (whitespace (*cp))
2086 /* if we got to the end, we are done */
2090 /* split it up into user and rev */
2092 cp = strchr (cp, ':');
2095 while (!whitespace (*cp) && *cp != '\0')
2100 /* make a new node and add it to the list */
2102 p->key = xstrdup (rev);
2103 p->data = xstrdup (user);
2104 (void) addnode (list, p);
2111 * process the branches list of a revision delta
2114 do_branches (List *list, char *val)
2122 /* skip leading whitespace */
2123 while (whitespace (*cp))
2126 /* if we got to the end, we are done */
2130 /* find the end of this branch */
2132 while (!whitespace (*cp) && *cp != '\0')
2137 /* make a new node and add it to the list */
2139 p->key = xstrdup (branch);
2140 (void) addnode (list, p);
2149 * Returns the requested version number of the RCS file, satisfying tags and/or
2150 * dates, and walking branches, if necessary.
2152 * The result is returned; null-string if error.
2155 RCS_getversion (RCSNode *rcs, const char *tag, const char *date,
2156 int force_tag_match, int *simple_tag)
2158 if (simple_tag != NULL)
2161 /* make sure we have something to look at... */
2162 assert (rcs != NULL);
2168 if (! RCS_nodeisbranch (rcs, tag))
2170 if (! strcmp (date, "BASE"))
2171 return RCS_gettag (rcs, tag, force_tag_match, simple_tag);
2172 /* We can't get a particular date if the tag is not a
2177 /* Work out the branch. */
2178 if (! isdigit ((unsigned char) tag[0]))
2179 branch = RCS_whatbranch (rcs, tag);
2181 branch = xstrdup (tag);
2183 if (! strcmp (date, "BASE"))
2185 /* Cut off the branch suffix and return. */
2186 rev = strrchr (branch, '.');
2192 /* Fetch the revision of branch as of date. */
2193 rev = RCS_getdatebranch (rcs, date, branch);
2198 return RCS_gettag (rcs, tag, force_tag_match, simple_tag);
2200 return RCS_getdate (rcs, date, force_tag_match);
2202 return RCS_head (rcs);
2209 * Get existing revision number corresponding to tag or revision.
2210 * Similar to RCS_gettag but less interpretation imposed.
2212 * -- If tag designates a magic branch, RCS_tag2rev
2213 * returns the magic branch number.
2214 * -- If tag is a branch tag, returns the branch number, not
2215 * the revision of the head of the branch.
2216 * If tag or revision is not valid or does not exist in file,
2220 RCS_tag2rev (RCSNode *rcs, char *tag)
2222 char *rev, *pa, *pb;
2225 assert (rcs != NULL);
2227 if (rcs->flags & PARTIAL)
2228 RCS_reparsercsfile (rcs, NULL, NULL);
2230 /* If a valid revision, try to look it up */
2231 if ( RCS_valid_rev (tag) )
2233 /* Make a copy so we can scribble on it */
2234 rev = xstrdup (tag);
2236 /* If revision exists, return the copy */
2237 if (RCS_exist_rev (rcs, tag))
2240 /* Nope, none such. If tag is not a branch we're done. */
2244 pa = strrchr (rev, '.');
2245 if (i == 1 || *(pa-1) != RCS_MAGIC_BRANCH || *(pa-2) != '.')
2248 error (1, 0, "revision `%s' does not exist", tag);
2252 /* Try for a real (that is, exists in the RCS deltas) branch
2253 (RCS_exist_rev just checks for real revisions and revisions
2254 which have tags pointing to them). */
2255 pa = RCS_getbranch (rcs, rev, 1);
2262 /* Tag is branch, but does not exist, try corresponding
2265 * FIXME: assumes all magic branches are of
2266 * form "n.n.n ... .0.n". I'll fix if somebody can
2267 * send me a method to get a magic branch tag with
2268 * the 0 in some other position -- <dan@gasboy.com>
2270 pa = strrchr (rev, '.');
2272 /* This might happen, for instance, if an RCS file only contained
2273 * revisions 2.x and higher, and REV == "1".
2275 error (1, 0, "revision `%s' does not exist", tag);
2278 pb = Xasprintf ("%s.%d.%s", rev, RCS_MAGIC_BRANCH, pa);
2281 if (RCS_exist_rev (rcs, rev))
2283 error (1, 0, "revision `%s' does not exist", tag);
2287 RCS_check_tag (tag); /* exit if not a valid tag */
2289 /* If tag is "HEAD", special case to get head RCS revision */
2290 if (tag && STREQ (tag, TAG_HEAD))
2291 return RCS_head (rcs);
2293 /* If valid tag let translate_symtag say yea or nay. */
2294 rev = translate_symtag (rcs, tag);
2299 /* Trust the caller to print warnings. */
2306 * Find the revision for a specific tag.
2307 * If force_tag_match is set, return NULL if an exact match is not
2308 * possible otherwise return RCS_head (). We are careful to look for
2309 * and handle "magic" revisions specially.
2311 * If the matched tag is a branch tag, find the head of the branch.
2313 * Returns pointer to newly malloc'd string, or NULL.
2316 RCS_gettag (RCSNode *rcs, const char *symtag, int force_tag_match,
2321 if (simple_tag != NULL)
2324 /* make sure we have something to look at... */
2325 assert (rcs != NULL);
2327 /* XXX this is probably not necessary, --jtc */
2328 if (rcs->flags & PARTIAL)
2329 RCS_reparsercsfile (rcs, NULL, NULL);
2331 /* If symtag is "HEAD", special case to get head RCS revision */
2332 if (symtag && STREQ (symtag, TAG_HEAD))
2333 #if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */
2334 if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
2335 return NULL; /* head request for removed file */
2338 return RCS_head (rcs);
2340 if (!isdigit ((unsigned char) symtag[0]))
2344 /* If we got a symbolic tag, resolve it to a numeric */
2345 version = translate_symtag (rcs, symtag);
2346 if (version != NULL)
2349 char *magic, *branch, *cp;
2354 * If this is a magic revision, we turn it into either its
2355 * physical branch equivalent (if one exists) or into
2356 * its base revision, which we assume exists.
2358 dots = numdots (tag);
2359 if (dots > 2 && (dots & 1) != 0)
2361 branch = strrchr (tag, '.');
2366 /* see if we have .magic-branch. (".0.") */
2367 magic = xmalloc (strlen (tag) + 1);
2368 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2369 if (strncmp (magic, cp, strlen (magic)) == 0)
2371 /* it's magic. See if the branch exists */
2372 *cp = '\0'; /* turn it into a revision */
2373 (void) sprintf (magic, "%s.%s", tag, branch);
2374 branch = RCS_getbranch (rcs, magic, 1);
2388 /* The tag wasn't there, so return the head or NULL */
2389 if (force_tag_match)
2392 return RCS_head (rcs);
2396 tag = xstrdup (symtag);
2398 /* tag is always allocated and numeric now. */
2401 * numeric tag processing:
2402 * 1) revision number - just return it
2403 * 2) branch number - find head of branch
2406 /* strip trailing dots */
2407 while (tag[strlen (tag) - 1] == '.')
2408 tag[strlen (tag) - 1] = '\0';
2410 if ((numdots (tag) & 1) == 0)
2414 /* we have a branch tag, so we need to walk the branch */
2415 branch = RCS_getbranch (rcs, tag, force_tag_match);
2423 /* we have a revision tag, so make sure it exists */
2424 p = findnode (rcs->versions, tag);
2427 /* We have found a numeric revision for the revision tag.
2428 To support expanding the RCS keyword Name, if
2429 SIMPLE_TAG is not NULL, tell the the caller that this
2430 is a simple tag which co will recognize. FIXME: Are
2431 there other cases in which we should set this? In
2432 particular, what if we expand RCS keywords internally
2433 without calling co? */
2434 if (simple_tag != NULL)
2440 /* The revision wasn't there, so return the head or NULL */
2442 if (force_tag_match)
2445 return RCS_head (rcs);
2453 * Return a "magic" revision as a virtual branch off of REV for the RCS file.
2454 * A "magic" revision is one which is unique in the RCS file. By unique, I
2455 * mean we return a revision which:
2456 * - has a branch of 0 (see rcs.h RCS_MAGIC_BRANCH)
2457 * - has a revision component which is not an existing branch off REV
2458 * - has a revision component which is not an existing magic revision
2459 * - is an even-numbered revision, to avoid conflicts with vendor branches
2460 * The first point is what makes it "magic".
2462 * As an example, if we pass in 1.37 as REV, we will look for an existing
2463 * branch called 1.37.2. If it did not exist, we would look for an
2464 * existing symbolic tag with a numeric part equal to 1.37.0.2. If that
2465 * didn't exist, then we know that the 1.37.2 branch can be reserved by
2466 * creating a symbolic tag with 1.37.0.2 as the numeric part.
2468 * This allows us to fork development with very little overhead -- just a
2469 * symbolic tag is used in the RCS file. When a commit is done, a physical
2470 * branch is dynamically created to hold the new revision.
2472 * Note: We assume that REV is an RCS revision and not a branch number.
2474 static char *check_rev;
2476 RCS_magicrev (RCSNode *rcs, char *rev)
2479 char *xrev, *test_branch, *local_branch_num;
2481 xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */
2484 local_branch_num = getenv("CVS_LOCAL_BRANCH_NUM");
2485 if (local_branch_num)
2487 rev_num = atoi(local_branch_num);
2496 /* only look at even numbered branches */
2497 for ( ; ; rev_num += 2)
2499 /* see if the physical branch exists */
2500 (void) sprintf (xrev, "%s.%d", rev, rev_num);
2501 test_branch = RCS_getbranch (rcs, xrev, 1);
2502 if (test_branch != NULL) /* it did, so keep looking */
2508 /* now, create a "magic" revision */
2509 (void) sprintf (xrev, "%s.%d.%d", rev, RCS_MAGIC_BRANCH, rev_num);
2511 /* walk the symbols list to see if a magic one already exists */
2512 if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0)
2515 /* we found a free magic branch. Claim it as ours */
2523 * walklist proc to look for a match in the symbols list.
2524 * Returns 0 if the symbol does not match, 1 if it does.
2527 checkmagic_proc (Node *p, void *closure)
2529 if (STREQ (check_rev, p->data))
2538 * Given an RCSNode, returns non-zero if the specified revision number
2539 * or symbolic tag resolves to a "branch" within the rcs file.
2541 * FIXME: this is the same as RCS_nodeisbranch except for the special
2542 * case for handling a null rcsnode.
2545 RCS_isbranch (RCSNode *rcs, const char *rev)
2547 /* numeric revisions are easy -- even number of dots is a branch */
2548 if (isdigit ((unsigned char) *rev))
2549 return (numdots (rev) & 1) == 0;
2551 /* assume a revision if you can't find the RCS info */
2555 /* now, look for a match in the symbols list */
2556 return RCS_nodeisbranch (rcs, rev);
2562 * Given an RCSNode, returns non-zero if the specified revision number
2563 * or symbolic tag resolves to a "branch" within the rcs file. We do
2564 * take into account any magic branches as well.
2567 RCS_nodeisbranch (RCSNode *rcs, const char *rev)
2572 assert (rcs != NULL);
2574 /* numeric revisions are easy -- even number of dots is a branch */
2575 if (isdigit ((unsigned char) *rev))
2576 return (numdots (rev) & 1) == 0;
2578 version = translate_symtag (rcs, rev);
2579 if (version == NULL)
2581 dots = numdots (version);
2582 if ((dots & 1) == 0)
2588 /* got a symbolic tag match, but it's not a branch; see if it's magic */
2592 char *branch = strrchr (version, '.');
2593 char *cp = branch - 1;
2597 /* see if we have .magic-branch. (".0.") */
2598 magic = Xasprintf (".%d.", RCS_MAGIC_BRANCH);
2599 if (strncmp (magic, cp, strlen (magic)) == 0)
2614 * Returns a pointer to malloc'ed memory which contains the branch
2615 * for the specified *symbolic* tag. Magic branches are handled correctly.
2618 RCS_whatbranch (RCSNode *rcs, const char *rev)
2623 /* assume no branch if you can't find the RCS info */
2627 /* now, look for a match in the symbols list */
2628 version = translate_symtag (rcs, rev);
2629 if (version == NULL)
2631 dots = numdots (version);
2632 if ((dots & 1) == 0)
2635 /* got a symbolic tag match, but it's not a branch; see if it's magic */
2639 char *branch = strrchr (version, '.');
2640 char *cp = branch++ - 1;
2644 /* see if we have .magic-branch. (".0.") */
2645 magic = xmalloc (strlen (version) + 1);
2646 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2647 if (strncmp (magic, cp, strlen (magic)) == 0)
2649 /* yep. it's magic. now, construct the real branch */
2650 *cp = '\0'; /* turn it into a revision */
2651 (void) sprintf (magic, "%s.%s", version, branch);
2664 * Get the head of the specified branch. If the branch does not exist,
2665 * return NULL or RCS_head depending on force_tag_match.
2666 * Returns NULL or a newly malloc'd string.
2669 RCS_getbranch (RCSNode *rcs, const char *tag, int force_tag_match)
2677 /* make sure we have something to look at... */
2678 assert (rcs != NULL);
2680 if (rcs->flags & PARTIAL)
2681 RCS_reparsercsfile (rcs, NULL, NULL);
2683 /* find out if the tag contains a dot, or is on the trunk */
2684 cp = strrchr (tag, '.');
2686 /* trunk processing is the special case */
2689 xtag = Xasprintf ("%s.", tag);
2690 for (cp = rcs->head; cp != NULL;)
2692 if (strncmp (xtag, cp, strlen (xtag)) == 0)
2694 p = findnode (rcs->versions, cp);
2698 if (force_tag_match)
2701 return RCS_head (rcs);
2709 if (force_tag_match)
2712 return RCS_head (rcs);
2714 return xstrdup (cp);
2717 /* if it had a `.', terminate the string so we have the base revision */
2720 /* look up the revision this branch is based on */
2721 p = findnode (rcs->versions, tag);
2723 /* put the . back so we have the branch again */
2728 /* if the base revision didn't exist, return head or NULL */
2729 if (force_tag_match)
2732 return RCS_head (rcs);
2735 /* find the first element of the branch we are looking for */
2737 if (vn->branches == NULL)
2739 xtag = Xasprintf ("%s.", tag);
2740 head = vn->branches->list;
2741 for (p = head->next; p != head; p = p->next)
2742 if (strncmp (p->key, xtag, strlen (xtag)) == 0)
2748 /* we didn't find a match so return head or NULL */
2749 if (force_tag_match)
2752 return RCS_head (rcs);
2755 /* now walk the next pointers of the branch */
2759 p = findnode (rcs->versions, nextvers);
2762 /* a link in the chain is missing - return head or NULL */
2763 if (force_tag_match)
2766 return RCS_head (rcs);
2769 nextvers = vn->next;
2770 } while (nextvers != NULL);
2772 /* we have the version in our hand, so go for it */
2773 return xstrdup (vn->version);
2778 /* Returns the head of the branch which REV is on. REV can be a
2779 branch tag or non-branch tag; symbolic or numeric.
2781 Returns a newly malloc'd string. Returns NULL if a symbolic name
2784 RCS_branch_head (RCSNode *rcs, char *rev)
2790 assert (rcs != NULL);
2792 if (RCS_nodeisbranch (rcs, rev))
2793 return RCS_getbranch (rcs, rev, 1);
2795 if (isdigit ((unsigned char) *rev))
2796 num = xstrdup (rev);
2799 num = translate_symtag (rcs, rev);
2803 br = truncate_revnum (num);
2804 retval = RCS_getbranch (rcs, br, 1);
2812 /* Get the branch point for a particular branch, that is the first
2813 revision on that branch. For example, RCS_getbranchpoint (rcs,
2814 "1.3.2") will normally return "1.3.2.1". TARGET may be either a
2815 branch number or a revision number; if a revnum, find the
2816 branchpoint of the branch to which TARGET belongs.
2818 Return RCS_head if TARGET is on the trunk or if the root node could
2819 not be found (this is sort of backwards from our behavior on a branch;
2820 the rationale is that the return value is a revision from which you
2821 can start walking the next fields and end up at TARGET).
2822 Return NULL on error. */
2824 RCS_getbranchpoint (RCSNode *rcs, char *target)
2829 int dots, isrevnum, brlen;
2831 dots = numdots (target);
2832 isrevnum = dots & 1;
2835 /* TARGET is a trunk revision; return rcs->head. */
2836 return RCS_head (rcs);
2838 /* Get the revision number of the node at which TARGET's branch is
2839 rooted. If TARGET is a branch number, lop off the last field;
2840 if it's a revision number, lop off the last *two* fields. */
2841 branch = xstrdup (target);
2842 bp = strrchr (branch, '.');
2844 error (1, 0, "%s: confused revision number %s",
2845 rcs->print_path, target);
2847 while (*--bp != '.')
2851 vp = findnode (rcs->versions, branch);
2854 error (0, 0, "%s: can't find branch point %s", rcs->print_path, target);
2861 while (*bp && *bp != '.')
2863 brlen = bp - branch;
2865 vp = rev->branches->list->next;
2866 while (vp != rev->branches->list)
2868 /* BRANCH may be a genuine branch number, e.g. `1.1.3', or
2869 maybe a full revision number, e.g. `1.1.3.6'. We have
2870 found our branch point if the first BRANCHLEN characters
2871 of the revision number match, *and* if the following
2872 character is a dot. */
2873 if (strncmp (vp->key, branch, brlen) == 0 && vp->key[brlen] == '.')
2879 if (vp == rev->branches->list)
2881 error (0, 0, "%s: can't find branch point %s", rcs->print_path, target);
2885 return xstrdup (vp->key);
2891 * Get the head of the RCS file. If branch is set, this is the head of the
2892 * branch, otherwise the real head.
2895 * rcs The parsed rcs node information.
2898 * NULL when rcs->branch exists and cannot be found.
2899 * A newly malloc'd string, otherwise.
2902 RCS_head (RCSNode *rcs)
2904 /* make sure we have something to look at... */
2908 * NOTE: we call getbranch with force_tag_match set to avoid any
2909 * possibility of recursion
2912 return RCS_getbranch (rcs, rcs->branch, 1);
2914 return xstrdup (rcs->head);
2920 * Get the most recent revision, based on the supplied date, but use some
2921 * funky stuff and follow the vendor branch maybe
2924 RCS_getdate (RCSNode *rcs, const char *date, int force_tag_match)
2926 char *cur_rev = NULL;
2927 char *retval = NULL;
2929 RCSVers *vers = NULL;
2931 /* make sure we have something to look at... */
2932 assert (rcs != NULL);
2934 if (rcs->flags & PARTIAL)
2935 RCS_reparsercsfile (rcs, NULL, NULL);
2937 /* if the head is on a branch, try the branch first */
2938 if (rcs->branch != NULL)
2940 retval = RCS_getdatebranch (rcs, date, rcs->branch);
2945 /* otherwise if we have a trunk, try it */
2948 p = findnode (rcs->versions, rcs->head);
2951 error (0, 0, "%s: head revision %s doesn't exist", rcs->print_path,
2956 /* if the date of this one is before date, take it */
2958 if (RCS_datecmp (vers->date, date) <= 0)
2960 cur_rev = vers->version;
2964 /* if there is a next version, find the node */
2965 if (vers->next != NULL)
2966 p = findnode (rcs->versions, vers->next);
2972 error (0, 0, "%s: no head revision", rcs->print_path);
2975 * at this point, either we have the revision we want, or we have the
2976 * first revision on the trunk (1.1?) in our hands, or we've come up
2980 /* if we found what we're looking for, and it's not 1.1 return it */
2981 if (cur_rev != NULL)
2983 if (! STREQ (cur_rev, "1.1"))
2984 return xstrdup (cur_rev);
2986 /* This is 1.1; if the date of 1.1 is not the same as that for the
2987 1.1.1.1 version, then return 1.1. This happens when the first
2988 version of a file is created by a regular cvs add and commit,
2989 and there is a subsequent cvs import of the same file. */
2990 p = findnode (rcs->versions, "1.1.1.1");
2993 char *date_1_1 = vers->date;
2996 if (RCS_datecmp (vers->date, date_1_1) != 0)
2997 return xstrdup ("1.1");
3001 /* look on the vendor branch */
3002 retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
3005 * if we found a match, return it; otherwise, we return the first
3006 * revision on the trunk or NULL depending on force_tag_match and the
3007 * date of the first rev
3012 if (vers && (!force_tag_match || RCS_datecmp (vers->date, date) <= 0))
3013 return xstrdup (vers->version);
3021 * Look up the last element on a branch that was put in before or on
3022 * the specified date and time (return the rev or NULL)
3025 RCS_getdatebranch (RCSNode *rcs, const char *date, const char *branch)
3027 char *cur_rev = NULL;
3029 char *xbranch, *xrev;
3033 /* look up the first revision on the branch */
3034 xrev = xstrdup (branch);
3035 cp = strrchr (xrev, '.');
3041 *cp = '\0'; /* turn it into a revision */
3043 assert (rcs != NULL);
3045 if (rcs->flags & PARTIAL)
3046 RCS_reparsercsfile (rcs, NULL, NULL);
3048 p = findnode (rcs->versions, xrev);
3054 /* Tentatively use this revision, if it is early enough. */
3055 if (RCS_datecmp (vers->date, date) <= 0)
3056 cur_rev = vers->version;
3058 /* If no branches list, return now. This is what happens if the branch
3059 is a (magic) branch with no revisions yet. */
3060 if (vers->branches == NULL)
3061 return xstrdup (cur_rev);
3063 /* walk the branches list looking for the branch number */
3064 xbranch = Xasprintf ("%s.", branch);
3065 for (p = vers->branches->list->next; p != vers->branches->list; p = p->next)
3066 if (strncmp (p->key, xbranch, strlen (xbranch)) == 0)
3069 if (p == vers->branches->list)
3071 /* This is what happens if the branch is a (magic) branch with
3072 no revisions yet. Similar to the case where vers->branches ==
3073 NULL, except here there was a another branch off the same
3075 return xstrdup (cur_rev);
3078 p = findnode (rcs->versions, p->key);
3080 /* walk the next pointers until you find the end, or the date is too late */
3084 if (RCS_datecmp (vers->date, date) <= 0)
3085 cur_rev = vers->version;
3089 /* if there is a next version, find the node */
3090 if (vers->next != NULL)
3091 p = findnode (rcs->versions, vers->next);
3096 /* Return whatever we found, which may be NULL. */
3097 return xstrdup (cur_rev);
3103 * Compare two dates in RCS format. Beware the change in format on January 1,
3104 * 2000, when years go from 2-digit to full format.
3107 RCS_datecmp (const char *date1, const char *date2)
3109 int length_diff = strlen (date1) - strlen (date2);
3111 return length_diff ? length_diff : strcmp (date1, date2);
3116 /* Look up revision REV in RCS and return the date specified for the
3117 revision minus FUDGE seconds (FUDGE will generally be one, so that the
3118 logically previous revision will be found later, or zero, if we want
3121 The return value is the date being returned as a time_t, or (time_t)-1
3122 on error (previously was documented as zero on error; I haven't checked
3123 the callers to make sure that they really check for (time_t)-1, but
3124 the latter is what this function really returns). If DATE is non-NULL,
3125 then it must point to MAXDATELEN characters, and we store the same
3126 return value there in DATEFORM format. */
3128 RCS_getrevtime (RCSNode *rcs, const char *rev, char *date, int fudge)
3131 struct tm xtm, *ftm;
3132 struct timespec revdate;
3137 /* make sure we have something to look at... */
3138 assert (rcs != NULL);
3140 if (rcs->flags & PARTIAL)
3141 RCS_reparsercsfile (rcs, NULL, NULL);
3143 /* look up the revision */
3144 p = findnode (rcs->versions, rev);
3149 /* split up the date */
3150 if (sscanf (vers->date, SDATEFORM, &y, &xtm.tm_mon,
3151 &xtm.tm_mday, &xtm.tm_hour, &xtm.tm_min, &xtm.tm_sec) != 6)
3152 error (1, 0, "%s: invalid date for revision %s (%s)", rcs->print_path,
3155 /* If the year is from 1900 to 1999, RCS files contain only two
3156 digits, and sscanf gives us a year from 0-99. If the year is
3157 2000+, RCS files contain all four digits and we subtract 1900,
3158 because the tm_year field should contain years since 1900. */
3160 if (y >= 100 && y < 2000)
3161 error (0, 0, "%s: non-standard date format for revision %s (%s)",
3162 rcs->print_path, rev, vers->date);
3163 xtm.tm_year = y - ((y >= 1900) ? 1900 : 0);
3165 /* put the date in a form getdate can grok */
3166 tdate = Xasprintf ("%ld-%d-%d %d:%d:%d -0000",
3167 (long)xtm.tm_year + 1900, xtm.tm_mon, xtm.tm_mday,
3168 xtm.tm_hour, xtm.tm_min, xtm.tm_sec);
3170 /* Turn it into seconds since the epoch.
3172 * We use a struct timespec since that is what getdate requires, then
3173 * truncate the nanoseconds.
3175 if (!get_date (&revdate, tdate, NULL))
3182 revdate.tv_sec -= fudge; /* remove "fudge" seconds */
3185 /* Put an appropriate string into `date', if we were given one. */
3186 ftm = gmtime (&revdate.tv_sec);
3187 (void) sprintf (date, DATEFORM,
3188 (long)ftm->tm_year + (ftm->tm_year < 100 ? 0L : 1900L),
3189 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
3190 ftm->tm_min, ftm->tm_sec);
3193 return revdate.tv_sec;
3199 RCS_getlocks (RCSNode *rcs)
3201 assert(rcs != NULL);
3203 if (rcs->flags & PARTIAL)
3204 RCS_reparsercsfile (rcs, NULL, NULL);
3206 if (rcs->locks_data) {
3207 rcs->locks = getlist ();
3208 do_locks (rcs->locks, rcs->locks_data);
3209 free(rcs->locks_data);
3210 rcs->locks_data = NULL;
3219 RCS_symbols(RCSNode *rcs)
3221 assert(rcs != NULL);
3223 if (rcs->flags & PARTIAL)
3224 RCS_reparsercsfile (rcs, NULL, NULL);
3226 if (rcs->symbols_data) {
3227 rcs->symbols = getlist ();
3228 do_symbols (rcs->symbols, rcs->symbols_data);
3229 free(rcs->symbols_data);
3230 rcs->symbols_data = NULL;
3233 return rcs->symbols;
3239 * Return the version associated with a particular symbolic tag.
3240 * Returns NULL or a newly malloc'd string.
3243 translate_symtag (RCSNode *rcs, const char *tag)
3245 if (rcs->flags & PARTIAL)
3246 RCS_reparsercsfile (rcs, NULL, NULL);
3248 if (rcs->symbols != NULL)
3252 /* The symbols have already been converted into a list. */
3253 p = findnode (rcs->symbols, tag);
3257 return xstrdup (p->data);
3260 if (rcs->symbols_data != NULL)
3265 /* Look through the RCS symbols information. This is like
3266 do_symbols, but we don't add the information to a list. In
3267 most cases, we will only be called once for this file, so
3268 generating the list is unnecessary overhead. */
3271 cp = rcs->symbols_data;
3272 /* Keeping track of LAST below isn't strictly necessary, now that tags
3273 * should be parsed for validity before they are accepted, but tags
3274 * with spaces used to cause the code below to loop indefintely, so
3275 * I have corrected for that. Now, in the event that I missed
3276 * something, the server cannot be hung. -DRP
3279 while ((cp = strchr (cp, tag[0])) != NULL)
3281 if (cp == last) break;
3282 if ((cp == rcs->symbols_data || whitespace (cp[-1]))
3283 && strncmp (cp, tag, len) == 0
3288 /* We found the tag. Return the version number. */
3292 while (! whitespace (*cp) && *cp != '\0')
3294 r = xmalloc (cp - v + 1);
3295 strncpy (r, v, cp - v);
3300 while (! whitespace (*cp) && *cp != '\0')
3314 * The argument ARG is the getopt remainder of the -k option specified on the
3315 * command line. This function returns malloc'ed space that can be used
3316 * directly in calls to RCS V5, with the -k flag munged correctly.
3319 RCS_check_kflag (const char *arg)
3321 static const char *const keyword_usage[] =
3323 "%s %s: invalid RCS keyword expansion mode\n",
3324 "Valid expansion modes include:\n",
3325 " -kkv\tGenerate keywords using the default form.\n",
3326 " -kkvl\tLike -kkv, except locker's name inserted.\n",
3327 " -kk\tGenerate only keyword names in keyword strings.\n",
3328 " -kv\tGenerate only keyword values in keyword strings.\n",
3329 " -ko\tGenerate the old keyword string (no changes from checked in file).\n",
3330 " -kb\tGenerate binary file unmodified (merges not allowed) (RCS 5.7).\n",
3331 "(Specify the --help global option for a list of other help options)\n",
3334 char const *const *cpp = NULL;
3338 for (cpp = kflags; *cpp != NULL; cpp++)
3340 if (STREQ (arg, *cpp))
3345 if (arg == NULL || *cpp == NULL)
3347 usage (keyword_usage);
3350 return Xasprintf ("-k%s", *cpp);
3356 * Do some consistency checks on the symbolic tag... These should equate
3357 * pretty close to what RCS checks, though I don't know for certain.
3360 RCS_check_tag (const char *tag)
3362 char *invalid = "$,.:;@"; /* invalid RCS tag characters */
3366 * The first character must be an alphabetic letter. The remaining
3367 * characters cannot be non-visible graphic characters, and must not be
3368 * in the set of "invalid" RCS identifier characters.
3370 if (isalpha ((unsigned char) *tag))
3372 for (cp = tag; *cp; cp++)
3374 if (!isgraph ((unsigned char) *cp))
3375 error (1, 0, "tag `%s' has non-visible graphic characters",
3377 if (strchr (invalid, *cp))
3378 error (1, 0, "tag `%s' must not contain the characters `%s'",
3383 error (1, 0, "tag `%s' must start with a letter", tag);
3389 * TRUE if argument has valid syntax for an RCS revision or
3390 * branch number. All characters must be digits or dots, first
3391 * and last characters must be digits, and no two consecutive
3392 * characters may be dots.
3394 * Intended for classifying things, so this function doesn't
3398 RCS_valid_rev (const char *rev)
3402 if (!isdigit ((unsigned char) last))
3404 while ((c = *rev++)) /* Extra parens placate -Wall gcc option */
3413 if (!isdigit ((unsigned char) c))
3416 if (!isdigit ((unsigned char) last))
3424 * Return true if RCS revision with TAG is a dead revision.
3427 RCS_isdead (RCSNode *rcs, const char *tag)
3432 if (rcs->flags & PARTIAL)
3433 RCS_reparsercsfile (rcs, NULL, NULL);
3435 p = findnode (rcs->versions, tag);
3440 return version->dead;
3445 /* Return the RCS keyword expansion mode. For example "b" for binary.
3446 Returns a pointer into storage which is allocated and freed along with
3447 the rest of the RCS information; the caller should not modify this
3448 storage. Returns NULL if the RCS file does not specify a keyword
3449 expansion mode; for all other errors, die with a fatal error. */
3451 RCS_getexpand (RCSNode *rcs)
3453 /* Since RCS_parsercsfile_i now reads expand, don't need to worry
3454 about RCS_reparsercsfile. */
3455 assert (rcs != NULL);
3461 /* Set keyword expansion mode to EXPAND. For example "b" for binary. */
3463 RCS_setexpand (RCSNode *rcs, const char *expand)
3465 /* Since RCS_parsercsfile_i now reads expand, don't need to worry
3466 about RCS_reparsercsfile. */
3467 assert (rcs != NULL);
3468 if (rcs->expand != NULL)
3470 rcs->expand = xstrdup (expand);
3475 /* RCS keywords, and a matching enum. */
3497 enum keyword expandto;
3503 static inline struct rcs_keyword *
3506 struct rcs_keyword *new;
3507 new = xcalloc (KEYWORD_LOCALID + 2, sizeof (struct rcs_keyword));
3509 #define KEYWORD_INIT(k, i, s) \
3511 k[i].len = sizeof s - 1; \
3512 k[i].expandto = i; \
3513 k[i].expandit = true
3515 KEYWORD_INIT (new, KEYWORD_AUTHOR, "Author");
3516 KEYWORD_INIT (new, KEYWORD_DATE, "Date");
3517 KEYWORD_INIT (new, KEYWORD_CVSHEADER, "CVSHeader");
3518 KEYWORD_INIT (new, KEYWORD_HEADER, "Header");
3519 KEYWORD_INIT (new, KEYWORD_ID, "Id");
3520 KEYWORD_INIT (new, KEYWORD_LOCKER, "Locker");
3521 KEYWORD_INIT (new, KEYWORD_LOG, "Log");
3522 KEYWORD_INIT (new, KEYWORD_NAME, "Name");
3523 KEYWORD_INIT (new, KEYWORD_RCSFILE, "RCSfile");
3524 KEYWORD_INIT (new, KEYWORD_REVISION, "Revision");
3525 KEYWORD_INIT (new, KEYWORD_SOURCE, "Source");
3526 KEYWORD_INIT (new, KEYWORD_STATE, "State");
3527 KEYWORD_INIT (new, KEYWORD_MDOCDATE, "Mdocdate");
3535 free_keywords (void *keywords)
3542 /* Convert an RCS date string into a readable string. This is like
3543 the RCS date2str function. */
3545 printable_date (const char *rcs_date)
3547 int year, mon, mday, hour, min, sec;
3550 (void) sscanf (rcs_date, SDATEFORM, &year, &mon, &mday, &hour, &min,
3554 sprintf (buf, "%04d/%02d/%02d %02d:%02d:%02d", year, mon, mday,
3556 return xstrdup (buf);
3561 /* Convert an RCS date string into an mdoc string. This is like
3562 the RCS date2str function, but for manual pages. */
3564 mdoc_date (const char *rcs_date)
3566 int year, mon, mday, hour, min, sec;
3568 const char *months[] = { "January", "February", "March", "April",
3569 "May", "June", "July", "August",
3570 "September", "October", "November", "December",
3573 (void) sscanf (rcs_date, SDATEFORM, &year, &mon, &mday, &hour, &min,
3575 if (mon < 1 || mon > 12)
3579 sprintf (buf, "%s %d %04d", months[mon - 1], mday, year);
3580 return xstrdup (buf);
3585 /* Escape the characters in a string so that it can be included in an
3588 escape_keyword_value (const char *value, int *free_value)
3593 for (s = value; *s != '\0'; s++)
3611 return (char *) value;
3614 ret = xmalloc (strlen (value) * 4 + 1);
3617 for (s = value, t = ret; *s != '\0'; s++, t++)
3658 /* Expand RCS keywords in the memory buffer BUF of length LEN. This
3659 applies to file RCS and version VERS. If NAME is not NULL, and is
3660 not a numeric revision, then it is the symbolic tag used for the
3661 checkout. EXPAND indicates how to expand the keywords. This
3662 function sets *RETBUF and *RETLEN to the new buffer and length.
3663 This function may modify the buffer BUF. If BUF != *RETBUF, then
3664 RETBUF is a newly allocated buffer. */
3666 expand_keywords (RCSNode *rcs, RCSVers *ver, const char *name, const char *log,
3667 size_t loglen, enum kflag expand, char *buf, size_t len,
3668 char **retbuf, size_t *retlen)
3670 struct expand_buffer
3672 struct expand_buffer *next;
3677 struct expand_buffer *ebuf_last = NULL;
3678 size_t ebuf_len = 0;
3680 char *srch, *srch_next;
3682 const struct rcs_keyword *keywords;
3684 if (!config /* For `cvs init', config may not be set. */
3685 ||expand == KFLAG_O || expand == KFLAG_B)
3692 if (!config->keywords) config->keywords = new_keywords ();
3693 keywords = config->keywords;
3695 /* If we are using -kkvl, dig out the locker information if any. */
3697 if (expand == KFLAG_KVL)
3700 lock = findnode (RCS_getlocks(rcs), ver->version);
3702 locker = xstrdup (lock->data);
3705 /* RCS keywords look like $STRING$ or $STRING: VALUE$. */
3708 while ((srch_next = memchr (srch, '$', srch_len)) != NULL)
3712 const struct rcs_keyword *keyword;
3718 srch_len -= (srch_next + 1) - srch;
3719 srch = srch_next + 1;
3721 /* Look for the first non alphanumeric character after the '$'. */
3722 send = srch + srch_len;
3723 for (s = srch; s < send; s++)
3724 if (! isalnum ((unsigned char) *s))
3727 /* If the first non alphanumeric character is not '$' or ':',
3728 then this is not an RCS keyword. */
3729 if (s == send || (*s != '$' && *s != ':'))
3732 /* See if this is one of the keywords. */
3734 for (keyword = keywords; keyword->string != NULL; keyword++)
3736 if (keyword->expandit
3737 && keyword->len == slen
3738 && strncmp (keyword->string, srch, slen) == 0)
3743 if (keyword->string == NULL)
3746 /* If the keyword ends with a ':', then the old value consists
3747 of the characters up to the next '$'. If there is no '$'
3748 before the end of the line, though, then this wasn't an RCS
3749 keyword after all. */
3752 for (; s < send; s++)
3753 if (*s == '$' || *s == '\n')
3755 if (s == send || *s != '$')
3759 /* At this point we must replace the string from SRCH to S
3760 with the expansion of the keyword KW. */
3762 /* Get the value to use. */
3764 if (expand == KFLAG_K)
3768 switch (keyword->expandto)
3771 assert (!"unreached");
3773 case KEYWORD_AUTHOR:
3774 value = ver->author;
3778 value = printable_date (ver->date);
3782 case KEYWORD_MDOCDATE:
3783 value = mdoc_date (ver->date);
3787 case KEYWORD_CVSHEADER:
3788 case KEYWORD_HEADER:
3790 case KEYWORD_LOCALID:
3798 if (keyword->expandto == KEYWORD_HEADER)
3799 path = rcs->print_path;
3800 else if (keyword->expandto == KEYWORD_CVSHEADER)
3801 path = getfullCVSname (rcs->print_path, &old_path);
3803 path = last_component (rcs->print_path);
3804 path = escape_keyword_value (path, &free_path);
3805 date = printable_date (ver->date);
3806 value = Xasprintf ("%s %s %s %s %s%s%s",
3807 path, ver->version, date, ver->author,
3809 locker != NULL ? " " : "",
3810 locker != NULL ? locker : "");
3812 /* If free_path is set then we know we allocated path
3813 * and we can discard the const.
3815 free ((char *)path);
3823 case KEYWORD_LOCKER:
3828 case KEYWORD_RCSFILE:
3829 value = escape_keyword_value (last_component (rcs->print_path),
3834 if (name != NULL && ! isdigit ((unsigned char) *name))
3835 value = (char *) name;
3840 case KEYWORD_REVISION:
3841 value = ver->version;
3844 case KEYWORD_SOURCE:
3845 value = escape_keyword_value (rcs->print_path, &free_value);
3854 sub = xmalloc (keyword->len
3855 + (value == NULL ? 0 : strlen (value))
3857 if (expand == KFLAG_V)
3859 /* Decrement SRCH and increment S to remove the $
3868 strcpy (sub, keyword->string);
3869 sublen = strlen (keyword->string);
3870 if (expand != KFLAG_K)
3873 sub[sublen + 1] = ' ';
3879 strcpy (sub + sublen, value);
3880 sublen += strlen (value);
3882 if (expand != KFLAG_V && expand != KFLAG_K)
3892 /* The Log keyword requires special handling. This behaviour
3893 is taken from RCS 5.7. The special log message is what RCS
3895 if (keyword->expandto == KEYWORD_LOG
3896 && (sizeof "checked in with -k by " <= loglen
3898 || strncmp (log, "checked in with -k by ",
3899 sizeof "checked in with -k by " - 1) != 0))
3903 size_t leader_len, leader_sp_len;
3910 /* We are going to insert the trailing $ ourselves, before
3911 the log message, so we must remove it from S, if we
3912 haven't done so already. */
3913 if (expand != KFLAG_V)
3916 /* CVS never has empty log messages, but old RCS files might. */
3920 /* Find the start of the line. */
3923 while (start > buf && start[-1] != '\n'
3924 && leader_len <= xsum (config->MaxCommentLeaderLength,
3925 expand != KFLAG_V ? 1 : 0))
3931 if (expand != KFLAG_V)
3932 /* When automagically determined and !KFLAG_V, we wish to avoid
3933 * including the leading `$' of the Log keyword in our leader.