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
22 /* These need to be source after cvs.h or HAVE_MMAP won't be set... */
24 # include <sys/mman.h>
25 # ifndef HAVE_GETPAGESIZE
26 # include "getpagesize.h"
29 # define MAP_FAILED NULL
33 #ifdef MMAP_FALLBACK_TEST
34 void *my_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
36 if (rand() & 1) return mmap(addr, len, prot, flags, fd, offset);
42 int preserve_perms = 0;
44 /* The RCS -k options, and a set of enums that must match the array.
45 These come first so that we can use enum kflag in function
47 static const char *const kflags[] =
48 {"kv", "kvl", "k", "v", "o", "b", (char *) NULL};
49 enum kflag { KFLAG_KV = 0, KFLAG_KVL, KFLAG_K, KFLAG_V, KFLAG_O, KFLAG_B };
51 /* A structure we use to buffer the contents of an RCS file. The
52 various fields are only referenced directly by the rcsbuf_*
53 functions. We declare the struct here so that we can allocate it
54 on the stack, rather than in memory. */
58 /* Points to the current position in the buffer. */
60 /* Points just after the last valid character in the buffer. */
64 /* The name of the file, used for error messages. */
66 /* The starting file position of the data in the buffer. */
68 /* The length of the value. */
70 /* Whether the value contains an '@' string. If so, we can not
71 compress whitespace characters. */
73 /* The number of embedded '@' characters in an '@' string. If
74 this is non-zero, we must search the string for pairs of '@'
75 and convert them to a single '@'. */
77 /* Whether the buffer has been mmap'ed or not. */
81 static RCSNode *RCS_parsercsfile_i PROTO((FILE * fp, const char *rcsfile));
82 static char *RCS_getdatebranch PROTO((RCSNode * rcs, const char *date,
84 static void rcsbuf_open PROTO ((struct rcsbuffer *, FILE *fp,
85 const char *filename, unsigned long pos));
86 static void rcsbuf_close PROTO ((struct rcsbuffer *));
87 static int rcsbuf_getkey PROTO ((struct rcsbuffer *, char **keyp,
89 static int rcsbuf_getrevnum PROTO ((struct rcsbuffer *, char **revp));
90 static char *rcsbuf_fill PROTO ((struct rcsbuffer *, char *ptr, char **keyp,
92 static int rcsbuf_valcmp PROTO ((struct rcsbuffer *));
93 static char *rcsbuf_valcopy PROTO ((struct rcsbuffer *, char *val, int polish,
95 static void rcsbuf_valpolish PROTO ((struct rcsbuffer *, char *val, int polish,
97 static void rcsbuf_valpolish_internal PROTO ((struct rcsbuffer *, char *to,
98 const char *from, size_t *lenp));
99 static unsigned long rcsbuf_ftell PROTO ((struct rcsbuffer *));
100 static void rcsbuf_get_buffered PROTO ((struct rcsbuffer *, char **datap,
102 static void rcsbuf_cache PROTO ((RCSNode *, struct rcsbuffer *));
103 static void rcsbuf_cache_close PROTO ((void));
104 static void rcsbuf_cache_open PROTO ((RCSNode *, long, FILE **,
105 struct rcsbuffer *));
106 static int checkmagic_proc PROTO((Node *p, void *closure));
107 static void do_branches PROTO((List * list, char *val));
108 static void do_symbols PROTO((List * list, char *val));
109 static void do_locks PROTO((List * list, char *val));
110 static void free_rcsnode_contents PROTO((RCSNode *));
111 static void free_rcsvers_contents PROTO((RCSVers *));
112 static void rcsvers_delproc PROTO((Node * p));
113 static char *translate_symtag PROTO((RCSNode *, const char *));
114 static char *RCS_addbranch PROTO ((RCSNode *, const char *));
115 static char *truncate_revnum_in_place PROTO ((char *));
116 static char *truncate_revnum PROTO ((const char *));
117 static char *printable_date PROTO((const char *));
118 static char *escape_keyword_value PROTO ((const char *, int *));
119 static void expand_keywords PROTO((RCSNode *, RCSVers *, const char *,
120 const char *, size_t, enum kflag, char *,
121 size_t, char **, size_t *));
122 static void cmp_file_buffer PROTO((void *, const char *, size_t));
124 /* Routines for reading, parsing and writing RCS files. */
125 static RCSVers *getdelta PROTO ((struct rcsbuffer *, char *, char **,
127 static Deltatext *RCS_getdeltatext PROTO ((RCSNode *, FILE *,
128 struct rcsbuffer *));
129 static void freedeltatext PROTO ((Deltatext *));
131 static void RCS_putadmin PROTO ((RCSNode *, FILE *));
132 static void RCS_putdtree PROTO ((RCSNode *, char *, FILE *));
133 static void RCS_putdesc PROTO ((RCSNode *, FILE *));
134 static void putdelta PROTO ((RCSVers *, FILE *));
135 static int putrcsfield_proc PROTO ((Node *, void *));
136 static int putsymbol_proc PROTO ((Node *, void *));
137 static void RCS_copydeltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *,
138 FILE *, Deltatext *, char *));
139 static int count_delta_actions PROTO ((Node *, void *));
140 static void putdeltatext PROTO ((FILE *, Deltatext *));
142 static FILE *rcs_internal_lockfile PROTO ((char *));
143 static void rcs_internal_unlockfile PROTO ((FILE *, char *));
144 static char *rcs_lockfilename PROTO ((const char *));
146 /* The RCS file reading functions are called a lot, and they do some
147 string comparisons. This macro speeds things up a bit by skipping
148 the function call when the first characters are different. It
149 evaluates its arguments multiple times. */
150 #define STREQ(a, b) (*(char *)(a) == *(char *)(b) && strcmp ((a), (b)) == 0)
153 * We don't want to use isspace() from the C library because:
155 * 1. The definition of "whitespace" in RCS files includes ASCII
156 * backspace, but the C locale doesn't.
157 * 2. isspace is an very expensive function call in some implementations
158 * due to the addition of wide character support.
160 static const char spacetab[] = {
161 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x00 - 0x0f */
162 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */
163 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */
164 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */
165 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
166 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
167 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x8f */
168 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */
169 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */
170 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */
171 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */
172 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */
173 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
174 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
175 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
176 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0 - 0xff */
179 #define whitespace(c) (spacetab[(unsigned char)c] != 0)
181 static char *rcs_lockfile;
182 static int rcs_lockfd = -1;
188 * locate_rcs ( const char* file, const char *repository , int *inattic )
190 * Find an RCS file in the repository, case insensitively when the cased name
191 * doesn't exist, we are running as the server, and a client has asked us to
194 * Most parts of CVS will want to rely instead on RCS_parse which calls this
195 * function and is called by recurse.c which then puts the result in useful
196 * places like the rcs field of struct file_info.
200 * repository the repository (including the directory)
201 * file the filename within that directory (without RCSEXT).
202 * inattic NULL or a pointer to the output boolean
206 * inattic If this input was non-null, the destination will be
207 * set to true if the file was found in the attic or
208 * false if not. If no RCS file is found, this value
213 * a newly-malloc'd array containing the absolute pathname of the RCS
214 * file that was found or NULL when none was found.
218 * errno can be set by the return value of the final call to
219 * locate_file_in_dir(). This should resolve to the system's existence error
220 * value (sometime ENOENT) if the Attic directory did not exist and ENOENT if
221 * the Attic was found but no matching files were found in the Attic or its
225 locate_rcs (repository, file, inattic)
226 const char *repository;
232 /* First, try to find the file as cased. */
233 retval = xmalloc (strlen (repository)
238 sprintf (retval, "%s/%s%s", repository, file, RCSEXT);
239 if (isreadable (retval))
245 sprintf (retval, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT);
246 if (isreadable (retval))
259 /* A few generic thoughts on error handling, in particular the
260 printing of unexpected characters that we find in the RCS file
261 (that is, why we use '\x%x' rather than %c or some such).
263 * Avoiding %c means we don't have to worry about what is printable
264 and other such stuff. In error handling, often better to keep it
267 * Hex rather than decimal or octal because character set standards
270 * Saying "character 0x%x" might make it sound like we are printing
271 a file offset. So we use '\x%x'.
273 * Would be nice to print the offset within the file, but I can
274 imagine various portability hassles (in particular, whether
275 unsigned long is always big enough to hold file offsets). */
277 /* Parse an rcsfile given a user file name and a repository. If there is
278 an error, we print an error message and return NULL. If the file
279 does not exist, we return NULL without printing anything (I'm not
280 sure this allows the caller to do anything reasonable, but it is
281 the current behavior). */
283 RCS_parse (file, repos)
289 RCSNode *retval = NULL;
293 /* We're creating a new RCSNode, so there is no hope of finding it
295 rcsbuf_cache_close ();
297 if ((rcsfile = locate_rcs (repos, file, &inattic)) == NULL)
299 /* Handle the error cases */
301 else if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) != NULL)
303 rcs = RCS_parsercsfile_i(fp, rcsfile);
308 rcs->flags |= INATTIC;
314 else if (! existence_error (errno))
316 error (0, errno, "cannot open %s", rcsfile);
324 * Parse a specific rcsfile.
327 RCS_parsercsfile (rcsfile)
333 /* We're creating a new RCSNode, so there is no hope of finding it
335 rcsbuf_cache_close ();
337 /* open the rcsfile */
338 if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) == NULL)
340 error (0, errno, "Couldn't open rcs file `%s'", rcsfile);
344 rcs = RCS_parsercsfile_i (fp, rcsfile);
354 RCS_parsercsfile_i (fp, rcsfile)
359 struct rcsbuffer rcsbuf;
363 rdata = (RCSNode *) xmalloc (sizeof (RCSNode));
364 memset ((char *)rdata, 0, sizeof (RCSNode));
366 rdata->path = xstrdup (rcsfile);
368 /* Process HEAD, BRANCH, and EXPAND keywords from the RCS header.
370 Most cvs operations on the main branch don't need any more
371 information. Those that do call RCS_reparsercsfile to parse
372 the rest of the header and the deltas. */
374 rcsbuf_open (&rcsbuf, fp, rcsfile, 0);
376 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
378 if (STREQ (key, RCSDESC))
381 if (STREQ (RCSHEAD, key) && value != NULL)
382 rdata->head = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *)NULL);
384 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
386 if (STREQ (key, RCSDESC))
389 if (STREQ (RCSBRANCH, key) && value != NULL)
393 rdata->branch = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *)NULL);
394 if ((numdots (rdata->branch) & 1) != 0)
396 /* turn it into a branch if it's a revision */
397 cp = strrchr (rdata->branch, '.');
402 /* Look ahead for expand, stopping when we see desc or a revision
408 if (STREQ (RCSEXPAND, key))
410 rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0,
416 (isdigit ((unsigned char)*cp) || *cp == '.') && *cp != '\0';
422 if (STREQ (RCSDESC, key))
425 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
429 rdata->flags |= PARTIAL;
431 rcsbuf_cache (rdata, &rcsbuf);
436 error (0, 0, "`%s' does not appear to be a valid rcs file",
438 rcsbuf_close (&rcsbuf);
439 freercsnode (&rdata);
446 /* Do the real work of parsing an RCS file.
448 On error, die with a fatal error; if it returns at all it was successful.
450 If PFP is NULL, close the file when done. Otherwise, leave it open
451 and store the FILE * in *PFP. */
453 RCS_reparsercsfile (rdata, pfp, rcsbufp)
456 struct rcsbuffer *rcsbufp;
460 struct rcsbuffer rcsbuf;
467 assert (rdata != NULL);
468 rcsfile = rdata->path;
470 rcsbuf_cache_open (rdata, 0, &fp, &rcsbuf);
473 /* This probably shouldn't be done until later: if a file has an
474 empty revision tree (which is permissible), rdata->versions
475 should be NULL. -twp */
476 rdata->versions = getlist ();
479 * process all the special header information, break out when we get to
480 * the first revision delta
485 /* get the next key/value pair */
488 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
490 error (1, 0, "`%s' does not appear to be a valid rcs file",
497 /* Skip head, branch and expand tags; we already have them. */
498 if (STREQ (key, RCSHEAD)
499 || STREQ (key, RCSBRANCH)
500 || STREQ (key, RCSEXPAND))
505 if (STREQ (key, "access"))
509 /* We pass the POLISH parameter as 1 because
510 RCS_addaccess expects nothing but spaces. FIXME:
511 It would be easy and more efficient to change
516 "Duplicate `access' keyword found in RCS file.");
517 free (rdata->access);
519 rdata->access = rcsbuf_valcopy (&rcsbuf, value, 1, NULL);
524 /* We always save lock information, so that we can handle
525 -kkvl correctly when checking out a file. */
526 if (STREQ (key, "locks"))
530 if (rdata->locks_data)
533 "Duplicate `locks' keyword found in RCS file.");
534 free (rdata->locks_data);
536 rdata->locks_data = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
538 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
540 error (1, 0, "premature end of file reading %s", rcsfile);
542 if (STREQ (key, "strict") && value == NULL)
544 rdata->strict_locks = 1;
551 if (STREQ (RCSSYMBOLS, key))
555 if (rdata->symbols_data)
558 "Duplicate `%s' keyword found in RCS file.",
560 free (rdata->symbols_data);
562 rdata->symbols_data = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
568 * check key for '.''s and digits (probably a rev) if it is a
569 * revision or `desc', we are done with the headers and are down to the
570 * revision deltas, so we break out of the loop
573 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
576 /* Note that when comparing with RCSDATE, we are not massaging
577 VALUE from the string found in the RCS file. This is OK
578 since we know exactly what to expect. */
579 if (*cp == '\0' && strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) == 0)
582 if (STREQ (key, RCSDESC))
585 if (STREQ (key, "comment"))
590 "warning: duplicate key `%s' in RCS file `%s'",
592 free (rdata->comment);
594 rdata->comment = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
597 if (rdata->other == NULL)
598 rdata->other = getlist ();
600 kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
601 kv->key = xstrdup (key);
602 kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
604 if (addnode (rdata->other, kv) != 0)
606 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
611 /* if we haven't grabbed it yet, we didn't want it */
614 /* We got out of the loop, so we have the first part of the first
615 revision delta in KEY (the revision) and VALUE (the date key
616 and its value). This is what getdelta expects to receive. */
618 while ((vnode = getdelta (&rcsbuf, rcsfile, &key, &value)) != NULL)
623 q->delproc = rcsvers_delproc;
625 q->key = vnode->version;
627 /* add the nodes to the list */
628 if (addnode (rdata->versions, q))
629 error (1, 0, "Multiple %s revision deltas found in `%s'",
633 /* Here KEY and VALUE are whatever caused getdelta to return NULL. */
635 if (STREQ (key, RCSDESC))
637 if (rdata->desc != NULL)
640 "warning: duplicate key `%s' in RCS file `%s'",
644 rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
647 rdata->delta_pos = rcsbuf_ftell (&rcsbuf);
650 rcsbuf_cache (rdata, &rcsbuf);
656 rdata->flags &= ~PARTIAL;
659 /* Move RCS into or out of the Attic, depending on TOATTIC. If the
660 file is already in the desired place, return without doing
661 anything. At some point may want to think about how this relates
662 to RCS_rewrite but that is a bit hairy (if one wants renames to be
663 atomic, or that kind of thing). If there is an error, print a message
664 and return 1. On success, return 0. */
666 RCS_setattic (rcs, toattic)
674 /* Some systems aren't going to let us rename an open file. */
675 rcsbuf_cache_close ();
677 /* Could make the pathname computations in this file, and probably
678 in other parts of rcs.c too, easier if the REPOS and FILE
679 arguments to RCS_parse got stashed in the RCSNode. */
685 if (rcs->flags & INATTIC)
688 /* Example: rcs->path is "/foo/bar/baz,v". */
689 newpath = xmalloc (strlen (rcs->path) + sizeof CVSATTIC + 5);
690 p = last_component (rcs->path);
691 strncpy (newpath, rcs->path, p - rcs->path);
692 strcpy (newpath + (p - rcs->path), CVSATTIC);
694 /* Create the Attic directory if it doesn't exist. */
695 omask = umask (cvsumask);
696 if (CVS_MKDIR (newpath, 0777) < 0 && errno != EEXIST)
697 error (0, errno, "cannot make directory %s", newpath);
698 (void) umask (omask);
700 strcat (newpath, "/");
703 if (CVS_RENAME (rcs->path, newpath) < 0)
705 int save_errno = errno;
707 /* The checks for isreadable look awfully fishy, but
708 I'm going to leave them here for now until I
709 can think harder about whether they take care of
710 some cases which should be handled somehow. */
712 if (isreadable (rcs->path) || !isreadable (newpath))
714 error (0, save_errno, "cannot rename %s to %s",
723 if (!(rcs->flags & INATTIC))
726 newpath = xmalloc (strlen (rcs->path));
728 /* Example: rcs->path is "/foo/bar/Attic/baz,v". */
729 p = last_component (rcs->path);
730 strncpy (newpath, rcs->path, p - rcs->path - 1);
731 newpath[p - rcs->path - 1] = '\0';
732 q = newpath + (p - rcs->path - 1) - (sizeof CVSATTIC - 1);
733 assert (strncmp (q, CVSATTIC, sizeof CVSATTIC - 1) == 0);
736 if (CVS_RENAME (rcs->path, newpath) < 0)
738 error (0, errno, "failed to move `%s' out of the attic",
752 * Fully parse the RCS file. Store all keyword/value pairs, fetch the
753 * log messages for each revision, and fetch add and delete counts for
754 * each revision (we could fetch the entire text for each revision,
755 * but the only caller, log_fileproc, doesn't need that information,
756 * so we don't waste the memory required to store it). The add and
757 * delete counts are stored on the OTHER field of the RCSVERSNODE
758 * structure, under the names ";add" and ";delete", so that we don't
759 * waste the memory space of extra fields in RCSVERSNODE for code
760 * which doesn't need this information.
764 RCS_fully_parse (rcs)
768 struct rcsbuffer rcsbuf;
770 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
778 /* Rather than try to keep track of how much information we
779 have read, just read to the end of the file. */
780 if (!rcsbuf_getrevnum (&rcsbuf, &key))
783 vers = findnode (rcs->versions, key);
786 "Delta text %s without revision information in `%s'.",
791 while (rcsbuf_getkey (&rcsbuf, &key, &value))
793 if (!STREQ (key, "text"))
797 if (vnode->other == NULL)
798 vnode->other = getlist ();
800 kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
801 kv->key = xstrdup (key);
802 kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
804 if (addnode (vnode->other, kv) != 0)
808 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
809 key, vnode->version, rcs->path);
816 if (!STREQ (vnode->version, rcs->head))
818 unsigned long add, del;
822 /* This is a change text. Store the add and delete
831 rcsbuf_valpolish (&rcsbuf, value, 0, &vallen);
833 while (cp < value + vallen)
839 if (op != 'a' && op != 'd')
841 unrecognized operation '\\x%x' in %s revision %s",
842 op, rcs->path, vnode->version);
843 (void) strtoul (cp, (char **) &cp, 10);
845 error (1, 0, "space expected in %s revision %s",
846 rcs->path, vnode->version);
847 count = strtoul (cp, (char **) &cp, 10);
849 error (1, 0, "linefeed expected in %s revision %s",
850 rcs->path, vnode->version);
861 else if (cp == value + vallen)
865 premature end of value in %s revision %s",
866 rcs->path, vnode->version);
876 sprintf (buf, "%lu", add);
879 kv->key = xstrdup (";add");
880 kv->data = xstrdup (buf);
881 if (addnode (vnode->other, kv) != 0)
885 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
886 key, vnode->version, rcs->path);
890 sprintf (buf, "%lu", del);
893 kv->key = xstrdup (";delete");
894 kv->data = xstrdup (buf);
895 if (addnode (vnode->other, kv) != 0)
899 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
900 key, vnode->version, rcs->path);
905 /* We have found the "text" key which ends the data for
906 this revision. Break out of the loop and go on to the
912 rcsbuf_cache (rcs, &rcsbuf);
918 * freercsnode - free up the info for an RCSNode
924 if (rnodep == NULL || *rnodep == NULL)
927 ((*rnodep)->refcount)--;
928 if ((*rnodep)->refcount != 0)
930 *rnodep = (RCSNode *) NULL;
933 free ((*rnodep)->path);
934 if ((*rnodep)->head != (char *) NULL)
935 free ((*rnodep)->head);
936 if ((*rnodep)->branch != (char *) NULL)
937 free ((*rnodep)->branch);
938 free_rcsnode_contents (*rnodep);
939 free ((char *) *rnodep);
940 *rnodep = (RCSNode *) NULL;
944 * free_rcsnode_contents - free up the contents of an RCSNode without
945 * freeing the node itself, or the file name, or the head, or the
946 * path. This returns the RCSNode to the state it is in immediately
947 * after a call to RCS_parse.
950 free_rcsnode_contents (rnode)
953 dellist (&rnode->versions);
954 if (rnode->symbols != (List *) NULL)
955 dellist (&rnode->symbols);
956 if (rnode->symbols_data != (char *) NULL)
957 free (rnode->symbols_data);
958 if (rnode->expand != NULL)
959 free (rnode->expand);
960 if (rnode->other != (List *) NULL)
961 dellist (&rnode->other);
962 if (rnode->access != NULL)
963 free (rnode->access);
964 if (rnode->locks_data != NULL)
965 free (rnode->locks_data);
966 if (rnode->locks != (List *) NULL)
967 dellist (&rnode->locks);
968 if (rnode->comment != NULL)
969 free (rnode->comment);
970 if (rnode->desc != NULL)
974 /* free_rcsvers_contents -- free up the contents of an RCSVers node,
975 but also free the pointer to the node itself. */
976 /* Note: The `hardlinks' list is *not* freed, since it is merely a
977 pointer into the `hardlist' structure (defined in hardlink.c), and
978 that structure is freed elsewhere in the program. */
981 free_rcsvers_contents (rnode)
984 if (rnode->branches != (List *) NULL)
985 dellist (&rnode->branches);
986 if (rnode->date != (char *) NULL)
988 if (rnode->next != (char *) NULL)
990 if (rnode->author != (char *) NULL)
991 free (rnode->author);
992 if (rnode->state != (char *) NULL)
994 if (rnode->other != (List *) NULL)
995 dellist (&rnode->other);
996 if (rnode->other_delta != NULL)
997 dellist (&rnode->other_delta);
998 if (rnode->text != NULL)
999 freedeltatext (rnode->text);
1000 free ((char *) rnode);
1004 * rcsvers_delproc - free up an RCSVers type node
1010 free_rcsvers_contents (p->data);
1013 /* These functions retrieve keys and values from an RCS file using a
1014 buffer. We use this somewhat complex approach because it turns out
1015 that for many common operations, CVS spends most of its time
1016 reading keys, so it's worth doing some fairly hairy optimization. */
1018 /* The number of bytes we try to read each time we need more data. */
1020 #define RCSBUF_BUFSIZE (8192)
1022 /* The buffer we use to store data. This grows as needed. */
1024 static char *rcsbuf_buffer = NULL;
1025 static size_t rcsbuf_buffer_size = 0;
1027 /* Whether rcsbuf_buffer is in use. This is used as a sanity check. */
1029 static int rcsbuf_inuse;
1031 /* Set up to start gathering keys and values from an RCS file. This
1032 initializes RCSBUF. */
1035 rcsbuf_open (rcsbuf, fp, filename, pos)
1036 struct rcsbuffer *rcsbuf;
1038 const char *filename;
1044 size_t mmap_off = 0;
1048 error (1, 0, "rcsbuf_open: internal error");
1052 /* When we have mmap, it is much more efficient to let the system do the
1053 * buffering and caching for us
1056 if ( fstat (fileno(fp), &fs) < 0 )
1057 error ( 1, errno, "Could not stat RCS archive %s for mapping", filename );
1061 size_t ps = getpagesize ();
1062 mmap_off = ( pos / ps ) * ps;
1065 /* Map private here since this particular buffer is read only */
1066 p = mmap ( NULL, fs.st_size - mmap_off, PROT_READ | PROT_WRITE,
1067 MAP_PRIVATE, fileno(fp), mmap_off );
1068 if (p != NULL && p != MAP_FAILED)
1070 if (rcsbuf_buffer) free (rcsbuf_buffer);
1072 rcsbuf_buffer_size = fs.st_size - mmap_off;
1073 rcsbuf->mmapped = 1;
1074 rcsbuf->ptr = rcsbuf_buffer + pos - mmap_off;
1075 rcsbuf->ptrend = rcsbuf_buffer + fs.st_size - mmap_off;
1076 rcsbuf->pos = mmap_off;
1080 #ifndef MMAP_FALLBACK_TEST
1081 error (0, errno, "Could not map memory to RCS archive %s", filename);
1083 #endif /* HAVE_MMAP */
1084 if (rcsbuf_buffer_size < RCSBUF_BUFSIZE)
1085 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, RCSBUF_BUFSIZE);
1087 rcsbuf->mmapped = 0;
1088 rcsbuf->ptr = rcsbuf_buffer;
1089 rcsbuf->ptrend = rcsbuf_buffer;
1093 #endif /* HAVE_MMAP */
1095 rcsbuf->filename = filename;
1097 rcsbuf->at_string = 0;
1098 rcsbuf->embedded_at = 0;
1101 /* Stop gathering keys from an RCS file. */
1104 rcsbuf_close (rcsbuf)
1105 struct rcsbuffer *rcsbuf;
1108 error (1, 0, "rcsbuf_close: internal error");
1110 if (rcsbuf->mmapped)
1112 munmap ( rcsbuf_buffer, rcsbuf_buffer_size );
1113 rcsbuf_buffer = NULL;
1114 rcsbuf_buffer_size = 0;
1120 /* Read a key/value pair from an RCS file. This sets *KEYP to point
1121 to the key, and *VALUEP to point to the value. A missing or empty
1122 value is indicated by setting *VALUEP to NULL.
1124 This function returns 1 on success, or 0 on EOF. If there is an
1125 error reading the file, or an EOF in an unexpected location, it
1126 gives a fatal error.
1128 This sets *KEYP and *VALUEP to point to storage managed by
1129 rcsbuf_getkey. Moreover, *VALUEP has not been massaged from the
1130 RCS format: it may contain embedded whitespace and embedded '@'
1131 characters. Call rcsbuf_valcopy or rcsbuf_valpolish to do
1132 appropriate massaging. */
1134 /* Note that the extreme hair in rcsbuf_getkey is because profiling
1135 statistics show that it was worth it. */
1138 rcsbuf_getkey (rcsbuf, keyp, valp)
1139 struct rcsbuffer *rcsbuf;
1143 register const char * const my_spacetab = spacetab;
1144 register char *ptr, *ptrend;
1147 #define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
1150 rcsbuf->at_string = 0;
1151 rcsbuf->embedded_at = 0;
1154 ptrend = rcsbuf->ptrend;
1157 assert (ptr >= rcsbuf_buffer && ptr <= rcsbuf_buffer + rcsbuf_buffer_size);
1158 assert (ptrend >= rcsbuf_buffer && ptrend <= rcsbuf_buffer + rcsbuf_buffer_size);
1160 /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
1161 buffer, move back to the start of the buffer. This keeps the
1162 buffer from growing indefinitely. */
1163 if (!rcsbuf->mmapped && ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
1169 /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
1170 at a time, so we can't have more bytes than that past PTR. */
1171 assert (len <= RCSBUF_BUFSIZE);
1173 /* Update the POS field, which holds the file offset of the
1174 first byte in the RCSBUF_BUFFER buffer. */
1175 rcsbuf->pos += ptr - rcsbuf_buffer;
1177 memcpy (rcsbuf_buffer, ptr, len);
1178 ptr = rcsbuf_buffer;
1180 rcsbuf->ptrend = ptrend;
1183 /* Skip leading whitespace. */
1189 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
1192 ptrend = rcsbuf->ptrend;
1196 if (! my_whitespace (c))
1202 /* We've found the start of the key. */
1213 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
1215 error (1, 0, "EOF in key in RCS file %s",
1217 ptrend = rcsbuf->ptrend;
1220 if (c == ';' || my_whitespace (c))
1225 /* Here *KEYP points to the key in the buffer, C is the character
1226 we found at the of the key, and PTR points to the location in
1227 the buffer where we found C. We must set *PTR to \0 in order
1228 to terminate the key. If the key ended with ';', then there is
1241 /* C must be whitespace. Skip whitespace between the key and the
1242 value. If we find ';' now, there is no value. */
1248 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
1250 error (1, 0, "EOF while looking for value in RCS file %s",
1252 ptrend = rcsbuf->ptrend;
1258 rcsbuf->ptr = ptr + 1;
1261 if (! my_whitespace (c))
1266 /* Now PTR points to the start of the value, and C is the first
1267 character of the value. */
1276 /* Optimize the common case of a value composed of a single
1279 rcsbuf->at_string = 1;
1287 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1289 /* Note that we pass PTREND as the PTR value to
1290 rcsbuf_fill, so that we will wind up setting PTR to
1291 the location corresponding to the old PTREND, so
1292 that we don't search the same bytes again. */
1293 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1296 "EOF while looking for end of string in RCS file %s",
1298 ptrend = rcsbuf->ptrend;
1301 /* Handle the special case of an '@' right at the end of
1303 if (pat + 1 >= ptrend)
1305 /* Note that we pass PAT, not PTR, here. */
1306 pat = rcsbuf_fill (rcsbuf, pat, keyp, valp);
1309 /* EOF here is OK; it just means that the last
1310 character of the file was an '@' terminating a
1311 value for a key type which does not require a
1313 pat = rcsbuf->ptrend - 1;
1316 ptrend = rcsbuf->ptrend;
1318 /* Note that the value of PTR is bogus here. This is
1319 OK, because we don't use it. */
1322 if (pat + 1 >= ptrend || pat[1] != '@')
1325 /* We found an '@' pair in the string. Keep looking. */
1326 ++rcsbuf->embedded_at;
1330 /* Here PAT points to the final '@' in the string. */
1337 rcsbuf->vlen = vlen;
1342 /* Certain keywords only have a '@' string. If there is no '@'
1343 string, then the old getrcskey function assumed that they had
1344 no value, and we do the same. */
1350 if (STREQ (k, RCSDESC)
1351 || STREQ (k, "text")
1352 || STREQ (k, "log"))
1361 /* If we've already gathered a '@' string, try to skip whitespace
1371 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1373 error (1, 0, "EOF in value in RCS file %s",
1375 ptrend = rcsbuf->ptrend;
1380 /* We're done. We already set everything up for this
1382 rcsbuf->ptr = ptr + 1;
1385 if (! my_whitespace (n))
1390 /* The value extends past the '@' string. We need to undo the
1391 '@' stripping done in the default case above. This
1392 case never happens in a plain RCS file, but it can happen
1393 if user defined phrases are used. */
1394 ((*valp)--)[rcsbuf->vlen++] = '@';
1397 /* Here we have a value which is not a simple '@' string. We need
1398 to gather up everything until the next ';', including any '@'
1399 strings. *VALP points to the start of the value. If
1400 RCSBUF->VLEN is not zero, then we have already read an '@'
1401 string, and PTR points to the data following the '@' string.
1402 Otherwise, PTR points to the start of the value. */
1406 char *start, *psemi, *pat;
1408 /* Find the ';' which must end the value. */
1410 while ((psemi = memchr (ptr, ';', ptrend - ptr)) == NULL)
1414 /* Note that we pass PTREND as the PTR value to
1415 rcsbuf_fill, so that we will wind up setting PTR to the
1416 location corresponding to the old PTREND, so that we
1417 don't search the same bytes again. */
1418 slen = start - *valp;
1419 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1421 error (1, 0, "EOF in value in RCS file %s", rcsbuf->filename);
1422 start = *valp + slen;
1423 ptrend = rcsbuf->ptrend;
1426 /* See if there are any '@' strings in the value. */
1427 pat = memchr (start, '@', psemi - start);
1433 /* We're done with the value. Trim any trailing
1436 rcsbuf->ptr = psemi + 1;
1439 while (psemi > start && my_whitespace (psemi[-1]))
1443 vlen = psemi - start;
1446 rcsbuf->vlen = vlen;
1451 /* We found an '@' string in the value. We set RCSBUF->AT_STRING
1452 and RCSBUF->EMBEDDED_AT to indicate that we won't be able to
1453 compress whitespace correctly for this type of value.
1454 Since this type of value never arises in a normal RCS file,
1455 this should not be a big deal. It means that if anybody
1456 adds a phrase which can have both an '@' string and regular
1457 text, they will have to handle whitespace compression
1460 rcsbuf->at_string = 1;
1461 rcsbuf->embedded_at = -1;
1467 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1469 /* Note that we pass PTREND as the PTR value to
1470 rcsbuff_fill, so that we will wind up setting PTR
1471 to the location corresponding to the old PTREND, so
1472 that we don't search the same bytes again. */
1473 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1476 "EOF while looking for end of string in RCS file %s",
1478 ptrend = rcsbuf->ptrend;
1481 /* Handle the special case of an '@' right at the end of
1483 if (pat + 1 >= ptrend)
1485 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1487 error (1, 0, "EOF in value in RCS file %s",
1489 ptrend = rcsbuf->ptrend;
1495 /* We found an '@' pair in the string. Keep looking. */
1499 /* Here PAT points to the final '@' in the string. */
1503 #undef my_whitespace
1506 /* Read an RCS revision number from an RCS file. This sets *REVP to
1507 point to the revision number; it will point to space that is
1508 managed by the rcsbuf functions, and is only good until the next
1509 call to rcsbuf_getkey or rcsbuf_getrevnum.
1511 This function returns 1 on success, or 0 on EOF. If there is an
1512 error reading the file, or an EOF in an unexpected location, it
1513 gives a fatal error. */
1516 rcsbuf_getrevnum (rcsbuf, revp)
1517 struct rcsbuffer *rcsbuf;
1524 ptrend = rcsbuf->ptrend;
1528 /* Skip leading whitespace. */
1534 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
1537 ptrend = rcsbuf->ptrend;
1541 if (! whitespace (c))
1547 if (! isdigit ((unsigned char) c) && c != '.')
1550 unexpected '\\x%x' reading revision number in RCS file %s",
1551 c, rcsbuf->filename);
1560 ptr = rcsbuf_fill (rcsbuf, ptr, revp, (char **) NULL);
1563 "unexpected EOF reading revision number in RCS file %s",
1565 ptrend = rcsbuf->ptrend;
1570 while (isdigit ((unsigned char) c) || c == '.');
1572 if (! whitespace (c))
1574 unexpected '\\x%x' reading revision number in RCS file %s",
1575 c, rcsbuf->filename);
1579 rcsbuf->ptr = ptr + 1;
1584 /* Fill RCSBUF_BUFFER with bytes from the file associated with RCSBUF,
1585 updating PTR and the PTREND field. If KEYP and *KEYP are not NULL,
1586 then *KEYP points into the buffer, and must be adjusted if the
1587 buffer is changed. Likewise for VALP. Returns the new value of
1588 PTR, or NULL on error. */
1591 rcsbuf_fill (rcsbuf, ptr, keyp, valp)
1592 struct rcsbuffer *rcsbuf;
1599 if (rcsbuf->mmapped)
1602 if (rcsbuf->ptrend - rcsbuf_buffer + RCSBUF_BUFSIZE > rcsbuf_buffer_size)
1604 int poff, peoff, koff, voff;
1606 poff = ptr - rcsbuf_buffer;
1607 peoff = rcsbuf->ptrend - rcsbuf_buffer;
1608 koff = keyp == NULL ? 0 : *keyp - rcsbuf_buffer;
1609 voff = valp == NULL ? 0 : *valp - rcsbuf_buffer;
1611 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size,
1612 rcsbuf_buffer_size + RCSBUF_BUFSIZE);
1614 ptr = rcsbuf_buffer + poff;
1615 rcsbuf->ptrend = rcsbuf_buffer + peoff;
1617 *keyp = rcsbuf_buffer + koff;
1619 *valp = rcsbuf_buffer + voff;
1622 got = fread (rcsbuf->ptrend, 1, RCSBUF_BUFSIZE, rcsbuf->fp);
1625 if (ferror (rcsbuf->fp))
1626 error (1, errno, "cannot read %s", rcsbuf->filename);
1630 rcsbuf->ptrend += got;
1635 /* Test whether the last value returned by rcsbuf_getkey is a composite
1639 rcsbuf_valcmp (rcsbuf)
1640 struct rcsbuffer *rcsbuf;
1642 return rcsbuf->at_string && rcsbuf->embedded_at < 0;
1645 /* Copy the value VAL returned by rcsbuf_getkey into a memory buffer,
1646 returning the memory buffer. Polish the value like
1647 rcsbuf_valpolish, q.v. */
1650 rcsbuf_valcopy (rcsbuf, val, polish, lenp)
1651 struct rcsbuffer *rcsbuf;
1667 vlen = rcsbuf->vlen;
1668 embedded_at = rcsbuf->embedded_at < 0 ? 0 : rcsbuf->embedded_at;
1670 ret = xmalloc (vlen - embedded_at + 1);
1672 if (rcsbuf->at_string ? embedded_at == 0 : ! polish)
1674 /* No special action to take. */
1675 memcpy (ret, val, vlen + 1);
1681 rcsbuf_valpolish_internal (rcsbuf, ret, val, lenp);
1685 /* Polish the value VAL returned by rcsbuf_getkey. The POLISH
1686 parameter is non-zero if multiple embedded whitespace characters
1687 should be compressed into a single whitespace character. Note that
1688 leading and trailing whitespace was already removed by
1689 rcsbuf_getkey. Within an '@' string, pairs of '@' characters are
1690 compressed into a single '@' character regardless of the value of
1691 POLISH. If LENP is not NULL, set *LENP to the length of the value. */
1694 rcsbuf_valpolish (rcsbuf, val, polish, lenp)
1695 struct rcsbuffer *rcsbuf;
1707 if (rcsbuf->at_string ? rcsbuf->embedded_at == 0 : ! polish)
1709 /* No special action to take. */
1711 *lenp = rcsbuf->vlen;
1715 rcsbuf_valpolish_internal (rcsbuf, val, val, lenp);
1718 /* Internal polishing routine, called from rcsbuf_valcopy and
1719 rcsbuf_valpolish. */
1722 rcsbuf_valpolish_internal (rcsbuf, to, from, lenp)
1723 struct rcsbuffer *rcsbuf;
1732 if (! rcsbuf->at_string)
1739 for (clen = len; clen > 0; ++from, --clen)
1746 /* Note that we know that clen can not drop to zero
1747 while we have whitespace, because we know there is
1748 no trailing whitespace. */
1749 while (whitespace (from[1]))
1762 *lenp = to - orig_to;
1766 const char *orig_from;
1774 embedded_at = rcsbuf->embedded_at;
1775 assert (embedded_at > 0);
1778 *lenp = len - embedded_at;
1780 for (clen = len; clen > 0; ++from, --clen)
1792 * FIXME: I restored this to an abort from an assert based on
1793 * advice from Larry Jones that asserts should not be used to
1794 * confirm the validity of an RCS file... This leaves two
1795 * issues here: 1) I am uncertain that the fact that we will
1796 * only find double '@'s hasn't already been confirmed; and:
1797 * 2) If this is the proper place to spot the error in the RCS
1798 * file, then we should print a much clearer error here for the
1803 if (*from != '@' || clen == 0)
1809 if (embedded_at == 0)
1811 /* We've found all the embedded '@' characters.
1812 We can just memcpy the rest of the buffer after
1813 this '@' character. */
1814 if (orig_to != orig_from)
1815 memcpy (to, from + 1, clen - 1);
1817 memmove (to, from + 1, clen - 1);
1826 assert (from == orig_from + len
1827 && to == orig_to + (len - rcsbuf->embedded_at));
1833 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1835 /* Copy the next word from the value VALP returned by rcsbuf_getkey into a
1836 memory buffer, updating VALP and returning the memory buffer. Return
1837 NULL when there are no more words. */
1840 rcsbuf_valword (rcsbuf, valp)
1841 struct rcsbuffer *rcsbuf;
1844 register const char * const my_spacetab = spacetab;
1845 register char *ptr, *pat;
1848 # define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
1853 for (ptr = *valp; my_whitespace (*ptr); ++ptr) ;
1856 assert (ptr - *valp == rcsbuf->vlen);
1862 /* PTR now points to the start of a value. Find out whether it is
1863 a num, an id, a string or a colon. */
1867 rcsbuf->vlen -= ++ptr - *valp;
1869 return xstrdup (":");
1874 int embedded_at = 0;
1878 while ((pat = strchr (pat, '@')) != NULL)
1886 /* Here PAT points to the final '@' in the string. */
1888 assert (rcsbuf->at_string);
1889 vlen = rcsbuf->vlen - (pat - *valp);
1890 rcsbuf->vlen = pat - ptr - 1;
1891 rcsbuf->embedded_at = embedded_at;
1892 ptr = rcsbuf_valcopy (rcsbuf, ptr, 0, (size_t *) NULL);
1894 rcsbuf->vlen = vlen;
1895 if (strchr (pat, '@') == NULL)
1896 rcsbuf->at_string = 0;
1898 rcsbuf->embedded_at = -1;
1902 /* *PTR is neither `:', `;' nor `@', so it should be the start of a num
1903 or an id. Make sure it is not another special character. */
1904 if (c == '$' || c == '.' || c == ',')
1906 error (1, 0, "invalid special character in RCS field in %s",
1913 /* Legitimate ID characters are digits, dots and any `graphic
1914 printing character that is not a special.' This test ought
1917 if (!isprint ((unsigned char) c) ||
1918 c == ';' || c == '$' || c == ',' || c == '@' || c == ':')
1922 /* PAT points to the last non-id character in this word, and C is
1923 the character in its memory cell. Check to make sure that it
1924 is a legitimate word delimiter -- whitespace or end. */
1925 if (c != '\0' && !my_whitespace (c))
1926 error (1, 0, "invalid special character in RCS field in %s",
1930 rcsbuf->vlen -= pat - *valp;
1932 return xstrdup (ptr);
1934 # undef my_whitespace
1939 /* Return the current position of an rcsbuf. */
1941 static unsigned long
1942 rcsbuf_ftell (rcsbuf)
1943 struct rcsbuffer *rcsbuf;
1945 return rcsbuf->pos + (rcsbuf->ptr - rcsbuf_buffer);
1948 /* Return a pointer to any data buffered for RCSBUF, along with the
1952 rcsbuf_get_buffered (rcsbuf, datap, lenp)
1953 struct rcsbuffer *rcsbuf;
1957 *datap = rcsbuf->ptr;
1958 *lenp = rcsbuf->ptrend - rcsbuf->ptr;
1961 /* CVS optimizes by quickly reading some header information from a
1962 file. If it decides it needs to do more with the file, it reopens
1963 it. We speed that up here by maintaining a cache of a single open
1964 file, to save the time it takes to reopen the file in the common
1967 static RCSNode *cached_rcs;
1968 static struct rcsbuffer cached_rcsbuf;
1970 /* Cache RCS and RCSBUF. This takes responsibility for closing
1974 rcsbuf_cache (rcs, rcsbuf)
1976 struct rcsbuffer *rcsbuf;
1978 if (cached_rcs != NULL)
1979 rcsbuf_cache_close ();
1982 cached_rcsbuf = *rcsbuf;
1985 /* If there is anything in the cache, close it. */
1988 rcsbuf_cache_close ()
1990 if (cached_rcs != NULL)
1992 rcsbuf_close (&cached_rcsbuf);
1993 if (fclose (cached_rcsbuf.fp) != 0)
1994 error (0, errno, "cannot close %s", cached_rcsbuf.filename);
1995 freercsnode (&cached_rcs);
2000 /* Open an rcsbuffer for RCS, getting it from the cache if possible.
2001 Set *FPP to the file, and *RCSBUFP to the rcsbuf. The file should
2002 be put at position POS. */
2005 rcsbuf_cache_open (rcs, pos, pfp, prcsbuf)
2009 struct rcsbuffer *prcsbuf;
2011 if (cached_rcs == rcs && !cached_rcsbuf.mmapped)
2013 if (rcsbuf_ftell (&cached_rcsbuf) != pos)
2015 if (fseek (cached_rcsbuf.fp, pos, SEEK_SET) != 0)
2016 error (1, 0, "cannot fseek RCS file %s",
2017 cached_rcsbuf.filename);
2018 cached_rcsbuf.ptr = rcsbuf_buffer;
2019 cached_rcsbuf.ptrend = rcsbuf_buffer;
2020 cached_rcsbuf.pos = pos;
2022 *pfp = cached_rcsbuf.fp;
2024 /* When RCS_parse opens a file using fopen_case, it frees the
2025 filename which we cached in CACHED_RCSBUF and stores a new
2026 file name in RCS->PATH. We avoid problems here by always
2027 copying the filename over. FIXME: This is hackish. */
2028 cached_rcsbuf.filename = rcs->path;
2030 *prcsbuf = cached_rcsbuf;
2034 /* Removing RCS from the cache removes a reference to it. */
2036 if (rcs->refcount <= 0)
2037 error (1, 0, "rcsbuf_cache_open: internal error");
2041 /* FIXME: If these routines can be rewritten to not write to the
2042 * rcs file buffer, there would be a considerably larger memory savings
2043 * from using mmap since the shared file would never need be copied to
2046 * If this happens, cached mmapped buffers would be usable, but don't
2047 * forget to make sure rcs->pos < pos here...
2049 if (cached_rcs != NULL)
2050 rcsbuf_cache_close ();
2052 *pfp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ);
2054 error (1, 0, "unable to reopen `%s'", rcs->path);
2057 if (fseek (*pfp, pos, SEEK_SET) != 0)
2058 error (1, 0, "cannot fseek RCS file %s", rcs->path);
2060 rcsbuf_open (prcsbuf, *pfp, rcs->path, pos);
2066 * process the symbols list of the rcs file
2069 do_symbols (list, val)
2081 /* skip leading whitespace */
2082 while (whitespace (*cp))
2085 /* if we got to the end, we are done */
2089 /* split it up into tag and rev */
2091 cp = strchr (cp, ':');
2094 while (!whitespace (*cp) && *cp != '\0')
2099 /* make a new node and add it to the list */
2101 p->key = xstrdup (tag);
2102 p->data = xstrdup (rev);
2103 (void) addnode (list, p);
2108 * process the locks list of the rcs file
2109 * Like do_symbols, but hash entries are keyed backwards: i.e.
2110 * an entry like `user:rev' is keyed on REV rather than on USER.
2113 do_locks (list, val)
2125 /* skip leading whitespace */
2126 while (whitespace (*cp))
2129 /* if we got to the end, we are done */
2133 /* split it up into user and rev */
2135 cp = strchr (cp, ':');
2138 while (!whitespace (*cp) && *cp != '\0')
2143 /* make a new node and add it to the list */
2145 p->key = xstrdup (rev);
2146 p->data = xstrdup (user);
2147 (void) addnode (list, p);
2152 * process the branches list of a revision delta
2155 do_branches (list, val)
2165 /* skip leading whitespace */
2166 while (whitespace (*cp))
2169 /* if we got to the end, we are done */
2173 /* find the end of this branch */
2175 while (!whitespace (*cp) && *cp != '\0')
2180 /* make a new node and add it to the list */
2182 p->key = xstrdup (branch);
2183 (void) addnode (list, p);
2190 * Returns the requested version number of the RCS file, satisfying tags and/or
2191 * dates, and walking branches, if necessary.
2193 * The result is returned; null-string if error.
2196 RCS_getversion (rcs, tag, date, force_tag_match, simple_tag)
2200 int force_tag_match;
2203 if (simple_tag != NULL)
2206 /* make sure we have something to look at... */
2207 assert (rcs != NULL);
2213 if (! RCS_nodeisbranch (rcs, tag))
2215 /* We can't get a particular date if the tag is not a
2220 /* Work out the branch. */
2221 if (! isdigit ((unsigned char) tag[0]))
2222 branch = RCS_whatbranch (rcs, tag);
2224 branch = xstrdup (tag);
2226 /* Fetch the revision of branch as of date. */
2227 rev = RCS_getdatebranch (rcs, date, branch);
2232 return RCS_gettag (rcs, tag, force_tag_match, simple_tag);
2234 return RCS_getdate (rcs, date, force_tag_match);
2236 return RCS_head (rcs);
2243 * Get existing revision number corresponding to tag or revision.
2244 * Similar to RCS_gettag but less interpretation imposed.
2246 * -- If tag designates a magic branch, RCS_tag2rev
2247 * returns the magic branch number.
2248 * -- If tag is a branch tag, returns the branch number, not
2249 * the revision of the head of the branch.
2250 * If tag or revision is not valid or does not exist in file,
2254 RCS_tag2rev (rcs, tag)
2258 char *rev, *pa, *pb;
2261 assert (rcs != NULL);
2263 if (rcs->flags & PARTIAL)
2264 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2266 /* If a valid revision, try to look it up */
2267 if ( RCS_valid_rev (tag) )
2269 /* Make a copy so we can scribble on it */
2270 rev = xstrdup (tag);
2272 /* If revision exists, return the copy */
2273 if (RCS_exist_rev (rcs, tag))
2276 /* Nope, none such. If tag is not a branch we're done. */
2280 pa = strrchr (rev, '.');
2281 if (i == 1 || *(pa-1) != RCS_MAGIC_BRANCH || *(pa-2) != '.')
2284 error (1, 0, "revision `%s' does not exist", tag);
2288 /* Try for a real (that is, exists in the RCS deltas) branch
2289 (RCS_exist_rev just checks for real revisions and revisions
2290 which have tags pointing to them). */
2291 pa = RCS_getbranch (rcs, rev, 1);
2298 /* Tag is branch, but does not exist, try corresponding
2301 * FIXME: assumes all magic branches are of
2302 * form "n.n.n ... .0.n". I'll fix if somebody can
2303 * send me a method to get a magic branch tag with
2304 * the 0 in some other position -- <dan@gasboy.com>
2306 pa = strrchr (rev, '.');
2308 /* This might happen, for instance, if an RCS file only contained
2309 * revisions 2.x and higher, and REV == "1".
2311 error (1, 0, "revision `%s' does not exist", tag);
2313 pb = xmalloc (strlen (rev) + 3);
2315 (void) sprintf (pb, "%s.%d.%s", rev, RCS_MAGIC_BRANCH, pa);
2318 if (RCS_exist_rev (rcs, rev))
2320 error (1, 0, "revision `%s' does not exist", tag);
2324 RCS_check_tag (tag); /* exit if not a valid tag */
2326 /* If tag is "HEAD", special case to get head RCS revision */
2327 if (tag && STREQ (tag, TAG_HEAD))
2328 return (RCS_head (rcs));
2330 /* If valid tag let translate_symtag say yea or nay. */
2331 rev = translate_symtag (rcs, tag);
2336 /* Trust the caller to print warnings. */
2341 * Find the revision for a specific tag.
2342 * If force_tag_match is set, return NULL if an exact match is not
2343 * possible otherwise return RCS_head (). We are careful to look for
2344 * and handle "magic" revisions specially.
2346 * If the matched tag is a branch tag, find the head of the branch.
2348 * Returns pointer to newly malloc'd string, or NULL.
2351 RCS_gettag (rcs, symtag, force_tag_match, simple_tag)
2354 int force_tag_match;
2359 if (simple_tag != NULL)
2362 /* make sure we have something to look at... */
2363 assert (rcs != NULL);
2365 /* XXX this is probably not necessary, --jtc */
2366 if (rcs->flags & PARTIAL)
2367 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2369 /* If symtag is "HEAD", special case to get head RCS revision */
2370 if (symtag && STREQ (symtag, TAG_HEAD))
2371 #if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */
2372 if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
2373 return ((char *) NULL); /* head request for removed file */
2376 return RCS_head (rcs);
2378 if (!isdigit ((unsigned char) symtag[0]))
2382 /* If we got a symbolic tag, resolve it to a numeric */
2383 version = translate_symtag (rcs, symtag);
2384 if (version != NULL)
2387 char *magic, *branch, *cp;
2392 * If this is a magic revision, we turn it into either its
2393 * physical branch equivalent (if one exists) or into
2394 * its base revision, which we assume exists.
2396 dots = numdots (tag);
2397 if (dots > 2 && (dots & 1) != 0)
2399 branch = strrchr (tag, '.');
2404 /* see if we have .magic-branch. (".0.") */
2405 magic = xmalloc (strlen (tag) + 1);
2406 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2407 if (strncmp (magic, cp, strlen (magic)) == 0)
2409 /* it's magic. See if the branch exists */
2410 *cp = '\0'; /* turn it into a revision */
2411 (void) sprintf (magic, "%s.%s", tag, branch);
2412 branch = RCS_getbranch (rcs, magic, 1);
2426 /* The tag wasn't there, so return the head or NULL */
2427 if (force_tag_match)
2430 return RCS_head (rcs);
2434 tag = xstrdup (symtag);
2436 /* tag is always allocated and numeric now. */
2439 * numeric tag processing:
2440 * 1) revision number - just return it
2441 * 2) branch number - find head of branch
2444 /* strip trailing dots */
2445 while (tag[strlen (tag) - 1] == '.')
2446 tag[strlen (tag) - 1] = '\0';
2448 if ((numdots (tag) & 1) == 0)
2452 /* we have a branch tag, so we need to walk the branch */
2453 branch = RCS_getbranch (rcs, tag, force_tag_match);
2461 /* we have a revision tag, so make sure it exists */
2462 p = findnode (rcs->versions, tag);
2465 /* We have found a numeric revision for the revision tag.
2466 To support expanding the RCS keyword Name, if
2467 SIMPLE_TAG is not NULL, tell the the caller that this
2468 is a simple tag which co will recognize. FIXME: Are
2469 there other cases in which we should set this? In
2470 particular, what if we expand RCS keywords internally
2471 without calling co? */
2472 if (simple_tag != NULL)
2478 /* The revision wasn't there, so return the head or NULL */
2480 if (force_tag_match)
2483 return RCS_head (rcs);
2489 * Return a "magic" revision as a virtual branch off of REV for the RCS file.
2490 * A "magic" revision is one which is unique in the RCS file. By unique, I
2491 * mean we return a revision which:
2492 * - has a branch of 0 (see rcs.h RCS_MAGIC_BRANCH)
2493 * - has a revision component which is not an existing branch off REV
2494 * - has a revision component which is not an existing magic revision
2495 * - is an even-numbered revision, to avoid conflicts with vendor branches
2496 * The first point is what makes it "magic".
2498 * As an example, if we pass in 1.37 as REV, we will look for an existing
2499 * branch called 1.37.2. If it did not exist, we would look for an
2500 * existing symbolic tag with a numeric part equal to 1.37.0.2. If that
2501 * didn't exist, then we know that the 1.37.2 branch can be reserved by
2502 * creating a symbolic tag with 1.37.0.2 as the numeric part.
2504 * This allows us to fork development with very little overhead -- just a
2505 * symbolic tag is used in the RCS file. When a commit is done, a physical
2506 * branch is dynamically created to hold the new revision.
2508 * Note: We assume that REV is an RCS revision and not a branch number.
2510 static char *check_rev;
2512 RCS_magicrev (rcs, rev)
2517 char *xrev, *test_branch;
2519 xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */
2522 /* only look at even numbered branches */
2523 for (rev_num = 2; ; rev_num += 2)
2525 /* see if the physical branch exists */
2526 (void) sprintf (xrev, "%s.%d", rev, rev_num);
2527 test_branch = RCS_getbranch (rcs, xrev, 1);
2528 if (test_branch != NULL) /* it did, so keep looking */
2534 /* now, create a "magic" revision */
2535 (void) sprintf (xrev, "%s.%d.%d", rev, RCS_MAGIC_BRANCH, rev_num);
2537 /* walk the symbols list to see if a magic one already exists */
2538 if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0)
2541 /* we found a free magic branch. Claim it as ours */
2547 * walklist proc to look for a match in the symbols list.
2548 * Returns 0 if the symbol does not match, 1 if it does.
2551 checkmagic_proc (p, closure)
2555 if (STREQ (check_rev, p->data))
2562 * Given an RCSNode, returns non-zero if the specified revision number
2563 * or symbolic tag resolves to a "branch" within the rcs file.
2565 * FIXME: this is the same as RCS_nodeisbranch except for the special
2566 * case for handling a null rcsnode.
2569 RCS_isbranch (rcs, rev)
2573 /* numeric revisions are easy -- even number of dots is a branch */
2574 if (isdigit ((unsigned char) *rev))
2575 return ((numdots (rev) & 1) == 0);
2577 /* assume a revision if you can't find the RCS info */
2581 /* now, look for a match in the symbols list */
2582 return (RCS_nodeisbranch (rcs, rev));
2586 * Given an RCSNode, returns non-zero if the specified revision number
2587 * or symbolic tag resolves to a "branch" within the rcs file. We do
2588 * take into account any magic branches as well.
2591 RCS_nodeisbranch (rcs, rev)
2598 assert (rcs != NULL);
2600 /* numeric revisions are easy -- even number of dots is a branch */
2601 if (isdigit ((unsigned char) *rev))
2602 return ((numdots (rev) & 1) == 0);
2604 version = translate_symtag (rcs, rev);
2605 if (version == NULL)
2607 dots = numdots (version);
2608 if ((dots & 1) == 0)
2614 /* got a symbolic tag match, but it's not a branch; see if it's magic */
2618 char *branch = strrchr (version, '.');
2619 char *cp = branch - 1;
2623 /* see if we have .magic-branch. (".0.") */
2624 magic = xmalloc (strlen (version) + 1);
2625 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2626 if (strncmp (magic, cp, strlen (magic)) == 0)
2639 * Returns a pointer to malloc'ed memory which contains the branch
2640 * for the specified *symbolic* tag. Magic branches are handled correctly.
2643 RCS_whatbranch (rcs, rev)
2650 /* assume no branch if you can't find the RCS info */
2652 return ((char *) NULL);
2654 /* now, look for a match in the symbols list */
2655 version = translate_symtag (rcs, rev);
2656 if (version == NULL)
2657 return ((char *) NULL);
2658 dots = numdots (version);
2659 if ((dots & 1) == 0)
2662 /* got a symbolic tag match, but it's not a branch; see if it's magic */
2666 char *branch = strrchr (version, '.');
2667 char *cp = branch++ - 1;
2671 /* see if we have .magic-branch. (".0.") */
2672 magic = xmalloc (strlen (version) + 1);
2673 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2674 if (strncmp (magic, cp, strlen (magic)) == 0)
2676 /* yep. it's magic. now, construct the real branch */
2677 *cp = '\0'; /* turn it into a revision */
2678 (void) sprintf (magic, "%s.%s", version, branch);
2685 return ((char *) NULL);
2689 * Get the head of the specified branch. If the branch does not exist,
2690 * return NULL or RCS_head depending on force_tag_match.
2691 * Returns NULL or a newly malloc'd string.
2694 RCS_getbranch (rcs, tag, force_tag_match)
2697 int force_tag_match;
2705 /* make sure we have something to look at... */
2706 assert (rcs != NULL);
2708 if (rcs->flags & PARTIAL)
2709 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2711 /* find out if the tag contains a dot, or is on the trunk */
2712 cp = strrchr (tag, '.');
2714 /* trunk processing is the special case */
2717 xtag = xmalloc (strlen (tag) + 1 + 1); /* +1 for an extra . */
2718 (void) strcpy (xtag, tag);
2719 (void) strcat (xtag, ".");
2720 for (cp = rcs->head; cp != NULL;)
2722 if (strncmp (xtag, cp, strlen (xtag)) == 0)
2724 p = findnode (rcs->versions, cp);
2728 if (force_tag_match)
2731 return (RCS_head (rcs));
2739 if (force_tag_match)
2742 return (RCS_head (rcs));
2744 return (xstrdup (cp));
2747 /* if it had a `.', terminate the string so we have the base revision */
2750 /* look up the revision this branch is based on */
2751 p = findnode (rcs->versions, tag);
2753 /* put the . back so we have the branch again */
2758 /* if the base revision didn't exist, return head or NULL */
2759 if (force_tag_match)
2762 return (RCS_head (rcs));
2765 /* find the first element of the branch we are looking for */
2767 if (vn->branches == NULL)
2769 xtag = xmalloc (strlen (tag) + 1 + 1); /* 1 for the extra '.' */
2770 (void) strcpy (xtag, tag);
2771 (void) strcat (xtag, ".");
2772 head = vn->branches->list;
2773 for (p = head->next; p != head; p = p->next)
2774 if (strncmp (p->key, xtag, strlen (xtag)) == 0)
2780 /* we didn't find a match so return head or NULL */
2781 if (force_tag_match)
2784 return (RCS_head (rcs));
2787 /* now walk the next pointers of the branch */
2791 p = findnode (rcs->versions, nextvers);
2794 /* a link in the chain is missing - return head or NULL */
2795 if (force_tag_match)
2798 return (RCS_head (rcs));
2801 nextvers = vn->next;
2802 } while (nextvers != NULL);
2804 /* we have the version in our hand, so go for it */
2805 return (xstrdup (vn->version));
2808 /* Returns the head of the branch which REV is on. REV can be a
2809 branch tag or non-branch tag; symbolic or numeric.
2811 Returns a newly malloc'd string. Returns NULL if a symbolic name
2815 RCS_branch_head (rcs, rev)
2823 assert (rcs != NULL);
2825 if (RCS_nodeisbranch (rcs, rev))
2826 return RCS_getbranch (rcs, rev, 1);
2828 if (isdigit ((unsigned char) *rev))
2829 num = xstrdup (rev);
2832 num = translate_symtag (rcs, rev);
2836 br = truncate_revnum (num);
2837 retval = RCS_getbranch (rcs, br, 1);
2843 /* Get the branch point for a particular branch, that is the first
2844 revision on that branch. For example, RCS_getbranchpoint (rcs,
2845 "1.3.2") will normally return "1.3.2.1". TARGET may be either a
2846 branch number or a revision number; if a revnum, find the
2847 branchpoint of the branch to which TARGET belongs.
2849 Return RCS_head if TARGET is on the trunk or if the root node could
2850 not be found (this is sort of backwards from our behavior on a branch;
2851 the rationale is that the return value is a revision from which you
2852 can start walking the next fields and end up at TARGET).
2853 Return NULL on error. */
2856 RCS_getbranchpoint (rcs, target)
2863 int dots, isrevnum, brlen;
2865 dots = numdots (target);
2866 isrevnum = dots & 1;
2869 /* TARGET is a trunk revision; return rcs->head. */
2870 return (RCS_head (rcs));
2872 /* Get the revision number of the node at which TARGET's branch is
2873 rooted. If TARGET is a branch number, lop off the last field;
2874 if it's a revision number, lop off the last *two* fields. */
2875 branch = xstrdup (target);
2876 bp = strrchr (branch, '.');
2878 error (1, 0, "%s: confused revision number %s",
2881 while (*--bp != '.')
2885 vp = findnode (rcs->versions, branch);
2888 error (0, 0, "%s: can't find branch point %s", rcs->path, target);
2895 while (*bp && *bp != '.')
2897 brlen = bp - branch;
2899 vp = rev->branches->list->next;
2900 while (vp != rev->branches->list)
2902 /* BRANCH may be a genuine branch number, e.g. `1.1.3', or
2903 maybe a full revision number, e.g. `1.1.3.6'. We have
2904 found our branch point if the first BRANCHLEN characters
2905 of the revision number match, *and* if the following
2906 character is a dot. */
2907 if (strncmp (vp->key, branch, brlen) == 0 && vp->key[brlen] == '.')
2913 if (vp == rev->branches->list)
2915 error (0, 0, "%s: can't find branch point %s", rcs->path, target);
2919 return (xstrdup (vp->key));
2923 * Get the head of the RCS file. If branch is set, this is the head of the
2924 * branch, otherwise the real head.
2925 * Returns NULL or a newly malloc'd string.
2931 /* make sure we have something to look at... */
2932 assert (rcs != NULL);
2935 * NOTE: we call getbranch with force_tag_match set to avoid any
2936 * possibility of recursion
2939 return (RCS_getbranch (rcs, rcs->branch, 1));
2941 return (xstrdup (rcs->head));
2945 * Get the most recent revision, based on the supplied date, but use some
2946 * funky stuff and follow the vendor branch maybe
2949 RCS_getdate (rcs, date, force_tag_match)
2952 int force_tag_match;
2954 char *cur_rev = NULL;
2955 char *retval = NULL;
2957 RCSVers *vers = NULL;
2959 /* make sure we have something to look at... */
2960 assert (rcs != NULL);
2962 if (rcs->flags & PARTIAL)
2963 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2965 /* if the head is on a branch, try the branch first */
2966 if (rcs->branch != NULL)
2968 retval = RCS_getdatebranch (rcs, date, rcs->branch);
2973 /* otherwise if we have a trunk, try it */
2976 p = findnode (rcs->versions, rcs->head);
2979 error (0, 0, "%s: head revision %s doesn't exist", rcs->path,
2984 /* if the date of this one is before date, take it */
2986 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);
3000 error (0, 0, "%s: no head revision", rcs->path);
3003 * at this point, either we have the revision we want, or we have the
3004 * first revision on the trunk (1.1?) in our hands, or we've come up
3008 /* if we found what we're looking for, and it's not 1.1 return it */
3009 if (cur_rev != NULL)
3011 if (! STREQ (cur_rev, "1.1"))
3012 return (xstrdup (cur_rev));
3014 /* This is 1.1; if the date of 1.1 is not the same as that for the
3015 1.1.1.1 version, then return 1.1. This happens when the first
3016 version of a file is created by a regular cvs add and commit,
3017 and there is a subsequent cvs import of the same file. */
3018 p = findnode (rcs->versions, "1.1.1.1");
3021 char *date_1_1 = vers->date;
3023 assert (p->data != NULL);
3026 if (RCS_datecmp (vers->date, date_1_1) != 0)
3027 return xstrdup ("1.1");
3031 /* look on the vendor branch */
3032 retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
3035 * if we found a match, return it; otherwise, we return the first
3036 * revision on the trunk or NULL depending on force_tag_match and the
3037 * date of the first rev
3042 if (vers && (!force_tag_match || RCS_datecmp (vers->date, date) <= 0))
3043 return xstrdup (vers->version);
3051 * Look up the last element on a branch that was put in before the specified
3052 * date (return the rev or NULL)
3055 RCS_getdatebranch (rcs, date, branch)
3060 char *cur_rev = NULL;
3062 char *xbranch, *xrev;
3066 /* look up the first revision on the branch */
3067 xrev = xstrdup (branch);
3068 cp = strrchr (xrev, '.');
3074 *cp = '\0'; /* turn it into a revision */
3076 assert (rcs != NULL);
3078 if (rcs->flags & PARTIAL)
3079 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3081 p = findnode (rcs->versions, xrev);
3087 /* Tentatively use this revision, if it is early enough. */
3088 if (RCS_datecmp (vers->date, date) <= 0)
3089 cur_rev = vers->version;
3091 /* If no branches list, return now. This is what happens if the branch
3092 is a (magic) branch with no revisions yet. */
3093 if (vers->branches == NULL)
3094 return xstrdup (cur_rev);
3096 /* walk the branches list looking for the branch number */
3097 xbranch = xmalloc (strlen (branch) + 1 + 1); /* +1 for the extra dot */
3098 (void) strcpy (xbranch, branch);
3099 (void) strcat (xbranch, ".");
3100 for (p = vers->branches->list->next; p != vers->branches->list; p = p->next)
3101 if (strncmp (p->key, xbranch, strlen (xbranch)) == 0)
3104 if (p == vers->branches->list)
3106 /* This is what happens if the branch is a (magic) branch with
3107 no revisions yet. Similar to the case where vers->branches ==
3108 NULL, except here there was a another branch off the same
3110 return xstrdup (cur_rev);
3113 p = findnode (rcs->versions, p->key);
3115 /* walk the next pointers until you find the end, or the date is too late */
3119 if (RCS_datecmp (vers->date, date) <= 0)
3120 cur_rev = vers->version;
3124 /* if there is a next version, find the node */
3125 if (vers->next != NULL)
3126 p = findnode (rcs->versions, vers->next);
3131 /* Return whatever we found, which may be NULL. */
3132 return xstrdup (cur_rev);
3138 * Compare two dates in RCS format. Beware the change in format on January 1,
3139 * 2000, when years go from 2-digit to full format.
3142 RCS_datecmp (date1, date2)
3143 const char *date1, *date2;
3145 int length_diff = strlen (date1) - strlen (date2);
3147 return length_diff ? length_diff : strcmp (date1, date2);
3152 /* Look up revision REV in RCS and return the date specified for the
3153 revision minus FUDGE seconds (FUDGE will generally be one, so that the
3154 logically previous revision will be found later, or zero, if we want
3157 The return value is the date being returned as a time_t, or (time_t)-1
3158 on error (previously was documented as zero on error; I haven't checked
3159 the callers to make sure that they really check for (time_t)-1, but
3160 the latter is what this function really returns). If DATE is non-NULL,
3161 then it must point to MAXDATELEN characters, and we store the same
3162 return value there in DATEFORM format. */
3164 RCS_getrevtime (rcs, rev, date, fudge)
3170 char tdate[MAXDATELEN];
3171 struct tm xtm, *ftm;
3176 /* make sure we have something to look at... */
3177 assert (rcs != NULL);
3179 if (rcs->flags & PARTIAL)
3180 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3182 /* look up the revision */
3183 p = findnode (rcs->versions, rev);
3188 /* split up the date */
3189 if (sscanf (vers->date, SDATEFORM, &xtm.tm_year, &xtm.tm_mon,
3190 &xtm.tm_mday, &xtm.tm_hour, &xtm.tm_min, &xtm.tm_sec) != 6)
3191 error (1, 0, "%s: invalid date for revision %s (%s)", rcs->path,
3194 /* If the year is from 1900 to 1999, RCS files contain only two
3195 digits, and sscanf gives us a year from 0-99. If the year is
3196 2000+, RCS files contain all four digits and we subtract 1900,
3197 because the tm_year field should contain years since 1900. */
3199 if (xtm.tm_year >= 100 && xtm.tm_year < 2000)
3200 error (0, 0, "%s: non-standard date format for revision %s (%s)",
3201 rcs->path, rev, vers->date);
3202 if (xtm.tm_year >= 1900)
3203 xtm.tm_year -= 1900;
3205 /* put the date in a form getdate can grok */
3206 (void) sprintf (tdate, "%d/%d/%d GMT %d:%d:%d", xtm.tm_mon,
3207 xtm.tm_mday, xtm.tm_year + 1900, xtm.tm_hour,
3208 xtm.tm_min, xtm.tm_sec);
3210 /* turn it into seconds since the epoch */
3211 revdate = get_date (tdate, (struct timeb *) NULL);
3212 if (revdate != (time_t) -1)
3214 revdate -= fudge; /* remove "fudge" seconds */
3217 /* put an appropriate string into ``date'' if we were given one */
3218 ftm = gmtime (&revdate);
3219 (void) sprintf (date, DATEFORM,
3220 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
3221 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
3222 ftm->tm_min, ftm->tm_sec);
3232 assert(rcs != NULL);
3234 if (rcs->flags & PARTIAL)
3235 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3237 if (rcs->locks_data) {
3238 rcs->locks = getlist ();
3239 do_locks (rcs->locks, rcs->locks_data);
3240 free(rcs->locks_data);
3241 rcs->locks_data = NULL;
3251 assert(rcs != NULL);
3253 if (rcs->flags & PARTIAL)
3254 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3256 if (rcs->symbols_data) {
3257 rcs->symbols = getlist ();
3258 do_symbols (rcs->symbols, rcs->symbols_data);
3259 free(rcs->symbols_data);
3260 rcs->symbols_data = NULL;
3263 return rcs->symbols;
3267 * Return the version associated with a particular symbolic tag.
3268 * Returns NULL or a newly malloc'd string.
3271 translate_symtag (rcs, tag)
3275 if (rcs->flags & PARTIAL)
3276 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3278 if (rcs->symbols != NULL)
3282 /* The symbols have already been converted into a list. */
3283 p = findnode (rcs->symbols, tag);
3287 return xstrdup (p->data);
3290 if (rcs->symbols_data != NULL)
3295 /* Look through the RCS symbols information. This is like
3296 do_symbols, but we don't add the information to a list. In
3297 most cases, we will only be called once for this file, so
3298 generating the list is unnecessary overhead. */
3301 cp = rcs->symbols_data;
3302 /* Keeping track of LAST below isn't strictly necessary, now that tags
3303 * should be parsed for validity before they are accepted, but tags
3304 * with spaces used to cause the code below to loop indefintely, so
3305 * I have corrected for that. Now, in the event that I missed
3306 * something, the server cannot be hung. -DRP
3309 while ((cp = strchr (cp, tag[0])) != NULL)
3311 if (cp == last) break;
3312 if ((cp == rcs->symbols_data || whitespace (cp[-1]))
3313 && strncmp (cp, tag, len) == 0
3318 /* We found the tag. Return the version number. */
3322 while (! whitespace (*cp) && *cp != '\0')
3324 r = xmalloc (cp - v + 1);
3325 strncpy (r, v, cp - v);
3330 while (! whitespace (*cp) && *cp != '\0')
3342 * The argument ARG is the getopt remainder of the -k option specified on the
3343 * command line. This function returns malloc'ed space that can be used
3344 * directly in calls to RCS V5, with the -k flag munged correctly.
3347 RCS_check_kflag (arg)
3350 static const char *const keyword_usage[] =
3352 "%s %s: invalid RCS keyword expansion mode\n",
3353 "Valid expansion modes include:\n",
3354 " -kkv\tGenerate keywords using the default form.\n",
3355 " -kkvl\tLike -kkv, except locker's name inserted.\n",
3356 " -kk\tGenerate only keyword names in keyword strings.\n",
3357 " -kv\tGenerate only keyword values in keyword strings.\n",
3358 " -ko\tGenerate the old keyword string (no changes from checked in file).\n",
3359 " -kb\tGenerate binary file unmodified (merges not allowed) (RCS 5.7).\n",
3360 "(Specify the --help global option for a list of other help options)\n",
3363 /* Big enough to hold any of the strings from kflags. */
3365 char const *const *cpp = NULL;
3369 for (cpp = kflags; *cpp != NULL; cpp++)
3371 if (STREQ (arg, *cpp))
3376 if (arg == NULL || *cpp == NULL)
3378 usage (keyword_usage);
3381 (void) sprintf (karg, "-k%s", *cpp);
3382 return (xstrdup (karg));
3386 * Do some consistency checks on the symbolic tag... These should equate
3387 * pretty close to what RCS checks, though I don't know for certain.
3393 char *invalid = "$,.:;@"; /* invalid RCS tag characters */
3397 * The first character must be an alphabetic letter. The remaining
3398 * characters cannot be non-visible graphic characters, and must not be
3399 * in the set of "invalid" RCS identifier characters.
3401 if (isalpha ((unsigned char) *tag))
3403 for (cp = tag; *cp; cp++)
3405 if (!isgraph ((unsigned char) *cp))
3406 error (1, 0, "tag `%s' has non-visible graphic characters",
3408 if (strchr (invalid, *cp))
3409 error (1, 0, "tag `%s' must not contain the characters `%s'",
3414 error (1, 0, "tag `%s' must start with a letter", tag);
3418 * TRUE if argument has valid syntax for an RCS revision or
3419 * branch number. All characters must be digits or dots, first
3420 * and last characters must be digits, and no two consecutive
3421 * characters may be dots.
3423 * Intended for classifying things, so this function doesn't
3432 if (!isdigit ((unsigned char) last))
3434 while ((c = *rev++)) /* Extra parens placate -Wall gcc option */
3443 if (!isdigit ((unsigned char) c))
3446 if (!isdigit ((unsigned char) last))
3452 * Return true if RCS revision with TAG is a dead revision.
3455 RCS_isdead (rcs, tag)
3462 assert (rcs != NULL);
3464 if (rcs->flags & PARTIAL)
3465 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3467 p = findnode (rcs->versions, tag);
3472 return (version->dead);
3475 /* Return the RCS keyword expansion mode. For example "b" for binary.
3476 Returns a pointer into storage which is allocated and freed along with
3477 the rest of the RCS information; the caller should not modify this
3478 storage. Returns NULL if the RCS file does not specify a keyword
3479 expansion mode; for all other errors, die with a fatal error. */
3484 /* Since RCS_parsercsfile_i now reads expand, don't need to worry
3485 about RCS_reparsercsfile. */
3486 assert (rcs != NULL);
3490 /* Set keyword expansion mode to EXPAND. For example "b" for binary. */
3492 RCS_setexpand (rcs, expand)
3496 /* Since RCS_parsercsfile_i now reads expand, don't need to worry
3497 about RCS_reparsercsfile. */
3498 assert (rcs != NULL);
3499 if (rcs->expand != NULL)
3501 rcs->expand = xstrdup (expand);
3504 /* RCS keywords, and a matching enum. */
3510 #define KEYWORD_INIT(s) (s), sizeof (s) - 1
3511 static const struct rcs_keyword keywords[] =
3513 { KEYWORD_INIT ("Author") },
3514 { KEYWORD_INIT ("Date") },
3515 { KEYWORD_INIT ("Header") },
3516 { KEYWORD_INIT ("Id") },
3517 { KEYWORD_INIT ("Locker") },
3518 { KEYWORD_INIT ("Log") },
3519 { KEYWORD_INIT ("Name") },
3520 { KEYWORD_INIT ("RCSfile") },
3521 { KEYWORD_INIT ("Revision") },
3522 { KEYWORD_INIT ("Source") },
3523 { KEYWORD_INIT ("State") },
3541 /* Convert an RCS date string into a readable string. This is like
3542 the RCS date2str function. */
3545 printable_date (rcs_date)
3546 const char *rcs_date;
3548 int year, mon, mday, hour, min, sec;
3551 (void) sscanf (rcs_date, SDATEFORM, &year, &mon, &mday, &hour, &min,
3555 sprintf (buf, "%04d/%02d/%02d %02d:%02d:%02d", year, mon, mday,
3557 return xstrdup (buf);
3560 /* Escape the characters in a string so that it can be included in an
3564 escape_keyword_value (value, free_value)
3571 for (s = value; *s != '\0'; s++)
3589 return (char *) value;
3592 ret = xmalloc (strlen (value) * 4 + 1);
3595 for (s = value, t = ret; *s != '\0'; s++, t++)
3634 /* Expand RCS keywords in the memory buffer BUF of length LEN. This
3635 applies to file RCS and version VERS. If NAME is not NULL, and is
3636 not a numeric revision, then it is the symbolic tag used for the
3637 checkout. EXPAND indicates how to expand the keywords. This
3638 function sets *RETBUF and *RETLEN to the new buffer and length.
3639 This function may modify the buffer BUF. If BUF != *RETBUF, then
3640 RETBUF is a newly allocated buffer. */
3643 expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
3655 struct expand_buffer
3657 struct expand_buffer *next;
3662 struct expand_buffer *ebuf_last = NULL;
3663 size_t ebuf_len = 0;
3665 char *srch, *srch_next;
3668 if (expand == KFLAG_O || expand == KFLAG_B)
3675 /* If we are using -kkvl, dig out the locker information if any. */
3677 if (expand == KFLAG_KVL)
3680 lock = findnode (RCS_getlocks(rcs), ver->version);
3682 locker = xstrdup (lock->data);
3685 /* RCS keywords look like $STRING$ or $STRING: VALUE$. */
3688 while ((srch_next = memchr (srch, '$', srch_len)) != NULL)
3692 const struct rcs_keyword *keyword;
3699 srch_len -= (srch_next + 1) - srch;
3700 srch = srch_next + 1;
3702 /* Look for the first non alphabetic character after the '$'. */
3703 send = srch + srch_len;
3704 for (s = srch; s < send; s++)
3705 if (! isalpha ((unsigned char) *s))
3708 /* If the first non alphabetic character is not '$' or ':',
3709 then this is not an RCS keyword. */
3710 if (s == send || (*s != '$' && *s != ':'))
3713 /* See if this is one of the keywords. */
3715 for (keyword = keywords; keyword->string != NULL; keyword++)
3717 if (keyword->len == slen
3718 && strncmp (keyword->string, srch, slen) == 0)
3723 if (keyword->string == NULL)
3726 kw = (enum keyword) (keyword - keywords);
3728 /* If the keyword ends with a ':', then the old value consists
3729 of the characters up to the next '$'. If there is no '$'
3730 before the end of the line, though, then this wasn't an RCS
3731 keyword after all. */
3734 for (; s < send; s++)
3735 if (*s == '$' || *s == '\n')
3737 if (s == send || *s != '$')
3741 /* At this point we must replace the string from SRCH to S
3742 with the expansion of the keyword KW. */
3744 /* Get the value to use. */
3746 if (expand == KFLAG_K)
3755 case KEYWORD_AUTHOR:
3756 value = ver->author;
3760 value = printable_date (ver->date);
3764 case KEYWORD_HEADER:
3771 if (kw == KEYWORD_HEADER)
3774 path = last_component (rcs->path);
3775 path = escape_keyword_value (path, &free_path);
3776 date = printable_date (ver->date);
3777 value = xmalloc (strlen (path)
3778 + strlen (ver->version)
3780 + strlen (ver->author)
3781 + strlen (ver->state)
3782 + (locker == NULL ? 0 : strlen (locker))
3785 sprintf (value, "%s %s %s %s %s%s%s",
3786 path, ver->version, date, ver->author,
3788 locker != NULL ? " " : "",
3789 locker != NULL ? locker : "");
3791 /* If free_path is set then we know we allocated path
3792 * and we can discard the const.
3794 free ((char *)path);
3800 case KEYWORD_LOCKER:
3805 case KEYWORD_RCSFILE:
3806 value = escape_keyword_value (last_component (rcs->path),
3811 if (name != NULL && ! isdigit ((unsigned char) *name))
3812 value = (char *) name;
3817 case KEYWORD_REVISION:
3818 value = ver->version;
3821 case KEYWORD_SOURCE:
3822 value = escape_keyword_value (rcs->path, &free_value);
3831 sub = xmalloc (keyword->len
3832 + (value == NULL ? 0 : strlen (value))
3834 if (expand == KFLAG_V)
3836 /* Decrement SRCH and increment S to remove the $
3845 strcpy (sub, keyword->string);
3846 sublen = strlen (keyword->string);
3847 if (expand != KFLAG_K)
3850 sub[sublen + 1] = ' ';
3856 strcpy (sub + sublen, value);
3857 sublen += strlen (value);
3859 if (expand != KFLAG_V && expand != KFLAG_K)
3869 /* The Log keyword requires special handling. This behaviour
3870 is taken from RCS 5.7. The special log message is what RCS
3872 if (kw == KEYWORD_LOG
3873 && (sizeof "checked in with -k by " <= loglen
3875 || strncmp (log, "checked in with -k by ",
3876 sizeof "checked in with -k by " - 1) != 0))
3880 size_t leader_len, leader_sp_len;
3887 /* We are going to insert the trailing $ ourselves, before
3888 the log message, so we must remove it from S, if we
3889 haven't done so already. */
3890 if (expand != KFLAG_V)
3893 /* CVS never has empty log messages, but old RCS files might. */
3897 /* Find the start of the line. */
3899 while (start > buf && start[-1] != '\n')
3902 /* Copy the start of the line to use as a comment leader. */
3903 leader_len = srch - start;
3904 if (expand != KFLAG_V)
3906 leader = xmalloc (leader_len);
3907 memcpy (leader, start, leader_len);
3908 leader_sp_len = leader_len;
3909 while (leader_sp_len > 0 && leader[leader_sp_len - 1] == ' ')
3912 /* RCS does some checking for an old style of Log here,
3913 but we don't bother. RCS issues a warning if it
3914 changes anything. */
3916 /* Count the number of newlines in the log message so that
3917 we know how many copies of the leader we will need. */
3919 logend = log + loglen;
3920 for (snl = log; snl < logend; snl++)
3924 /* If the log message did not end in a newline, increment
3925 * the newline count so we have space for the extra leader.
3926 * Failure to do so results in a buffer overrun.
3928 if (loglen && snl[-1] != '\n')
3931 date = printable_date (ver->date);
3932 sub = xrealloc (sub,
3935 + strlen (ver->version)
3937 + strlen (ver->author)
3939 /* Use CNL + 2 below: One leader for each log
3940 * line, plus the Revision/Author/Date line,
3941 * plus a trailing blank line.
3943 + (cnl + 2) * leader_len
3945 if (expand != KFLAG_V)
3952 memcpy (sub + sublen, leader, leader_len);
3953 sublen += leader_len;
3954 sprintf (sub + sublen, "Revision %s %s %s\n",
3955 ver->version, date, ver->author);
3956 sublen += strlen (sub + sublen);
3964 memcpy (sub + sublen, leader, leader_sp_len);
3965 sublen += leader_sp_len;
3974 memcpy (sub + sublen, leader, leader_len);
3975 sublen += leader_len;
3976 for (slnl = sl; slnl < logend && *slnl != '\n'; ++slnl)
3980 memcpy (sub + sublen, sl, slnl - sl);
3981 sublen += slnl - sl;
3982 if (slnl == logend && slnl[-1] != '\n')
3984 /* There was no EOL at the end of the log message. Add
3994 memcpy (sub + sublen, leader, leader_sp_len);
3995 sublen += leader_sp_len;
4000 /* Now SUB contains a string which is to replace the string
4001 from SRCH to S. SUBLEN is the length of SUB. */
4003 if (srch + sublen == s)
4005 memcpy (srch, sub, sublen);
4010 struct expand_buffer *ebuf;
4012 /* We need to change the size of the buffer. We build a
4013 list of expand_buffer structures. Each expand_buffer
4014 structure represents a portion of the final output. We
4015 concatenate them back into a single buffer when we are
4016 done. This minimizes the number of potentially large
4017 buffer copies we must do. */
4021 ebufs = (struct expand_buffer *) xmalloc (sizeof *ebuf);
4024 ebufs->free_data = 0;
4025 ebuf_len = srch - buf;
4026 ebufs->len = ebuf_len;
4031 assert (srch >= ebuf_last->data);
4032 assert (srch <= ebuf_last->data + ebuf_last->len);
4033 ebuf_len -= ebuf_last->len - (srch - ebuf_last->data);
4034 ebuf_last->len = srch - ebuf_last->data;
4037 ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf);
4040 ebuf->free_data = 1;
4042 ebuf_last->next = ebuf;
4046 ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf);
4048 ebuf->len = srch_len - (s - srch);
4049 ebuf->free_data = 0;
4051 ebuf_last->next = ebuf;
4053 ebuf_len += srch_len - (s - srch);
4056 srch_len -= (s - srch);
4072 ret = xmalloc (ebuf_len);
4075 while (ebufs != NULL)
4077 struct expand_buffer *next;
4079 memcpy (ret, ebufs->data, ebufs->len);
4081 if (ebufs->free_data)
4092 /* Check out a revision from an RCS file.
4094 If PFN is not NULL, then ignore WORKFILE and SOUT. Call PFN zero
4095 or more times with the contents of the file. CALLERDAT is passed,
4096 uninterpreted, to PFN. (The current code will always call PFN
4097 exactly once for a non empty file; however, the current code
4098 assumes that it can hold the entire file contents in memory, which
4099 is not a good assumption, and might change in the future).
4101 Otherwise, if WORKFILE is not NULL, check out the revision to
4102 WORKFILE. However, if WORKFILE is not NULL, and noexec is set,
4103 then don't do anything.
4105 Otherwise, if WORKFILE is NULL, check out the revision to SOUT. If
4106 SOUT is RUN_TTY, then write the contents of the revision to
4107 standard output. When using SOUT, the output is generally a
4108 temporary file; don't bother to get the file modes correct. When
4109 NOEXEC is set, WORKFILEs are not written but SOUTs are.
4111 REV is the numeric revision to check out. It may be NULL, which
4112 means to check out the head of the default branch.
4114 If NAMETAG is not NULL, and is not a numeric revision, then it is
4115 the tag that should be used when expanding the RCS Name keyword.
4117 OPTIONS is a string such as "-kb" or "-kv" for keyword expansion
4118 options. It may be NULL to use the default expansion mode of the
4119 file, typically "-kkv".
4121 On an error which prevented checking out the file, either print a
4122 nonfatal error and return 1, or give a fatal error. On success,
4125 /* This function mimics the behavior of `rcs co' almost exactly. The
4126 chief difference is in its support for preserving file ownership,
4127 permissions, and special files across checkin and checkout -- see
4128 comments in RCS_checkin for some issues about this. -twp */
4131 RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
4133 const char *workfile;
4135 const char *nametag;
4136 const char *options;
4138 RCSCHECKOUTPROC pfn;
4146 struct rcsbuffer rcsbuf;
4154 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4155 uid_t rcs_owner = (uid_t) -1;
4156 gid_t rcs_group = (gid_t) -1;
4158 int change_rcs_owner_or_group = 0;
4159 int change_rcs_mode = 0;
4160 int special_file = 0;
4161 unsigned long devnum_long;
4167 (void) fprintf (stderr, "%s-> RCS_checkout (%s, %s, %s, %s, %s)\n",
4168 #ifdef SERVER_SUPPORT
4169 server_active ? "S" : " ",
4174 rev != NULL ? rev : "",
4175 nametag != NULL ? nametag : "",
4176 options != NULL ? options : "",
4177 (pfn != NULL ? "(function)"
4180 : (sout != RUN_TTY ? sout : "(stdout)"))));
4183 assert (rev == NULL || isdigit ((unsigned char) *rev));
4185 if (noexec && !server_active && workfile != NULL)
4188 assert (sout == RUN_TTY || workfile == NULL);
4189 assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL));
4191 /* Some callers, such as Checkin or remove_file, will pass us a
4193 if (rev != NULL && (numdots (rev) & 1) == 0)
4195 rev = RCS_getbranch (rcs, rev, 1);
4197 error (1, 0, "internal error: bad branch tag in checkout");
4201 if (rev == NULL || STREQ (rev, rcs->head))
4205 /* We want the head revision. Try to read it directly. */
4207 if (rcs->flags & PARTIAL)
4208 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
4210 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf);
4213 if (! rcsbuf_getrevnum (&rcsbuf, &key))
4214 error (1, 0, "unexpected EOF reading %s", rcs->path);
4216 if (!STREQ (rcs->head, key))
4217 error (1, 0, "Expected head revision %s, found %s.",
4220 while (rcsbuf_getkey (&rcsbuf, &key, &value))
4222 if (STREQ (key, "log"))
4227 "Duplicate log keyword found for head revision in RCS file.");
4230 log = rcsbuf_valcopy (&rcsbuf, value, 0, &loglen);
4232 else if (STREQ (key, "text"))
4241 error (0, 0, "internal error: cannot find head text");
4243 /* It's okay to discard the const when free_rev is set, because
4244 * we know we allocated it in this function.
4250 rcsbuf_valpolish (&rcsbuf, value, 0, &len);
4252 if (fstat (fileno (fp), &sb) < 0)
4253 error (1, errno, "cannot fstat %s", rcs->path);
4255 rcsbuf_cache (rcs, &rcsbuf);
4259 struct rcsbuffer *rcsbufp;
4261 /* It isn't the head revision of the trunk. We'll need to
4262 walk through the deltas. */
4265 if (rcs->flags & PARTIAL)
4266 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
4270 /* If RCS_deltas didn't close the file, we could use fstat
4271 here too. Probably should change it thusly.... */
4272 if (stat (rcs->path, &sb) < 0)
4273 error (1, errno, "cannot stat %s", rcs->path);
4278 if (fstat (fileno (fp), &sb) < 0)
4279 error (1, errno, "cannot fstat %s", rcs->path);
4283 RCS_deltas (rcs, fp, rcsbufp, rev, RCS_FETCH, &value, &len,
4288 /* If OPTIONS is NULL or the empty string, then the old code would
4289 invoke the RCS co program with no -k option, which means that
4290 co would use the string we have stored in rcs->expand. */
4291 if ((options == NULL || options[0] == '\0') && rcs->expand == NULL)
4295 const char *ouroptions;
4296 const char * const *cpp;
4298 if (options != NULL && options[0] != '\0')
4300 assert (options[0] == '-' && options[1] == 'k');
4301 ouroptions = options + 2;
4304 ouroptions = rcs->expand;
4306 for (cpp = kflags; *cpp != NULL; cpp++)
4307 if (STREQ (*cpp, ouroptions))
4311 expand = (enum kflag) (cpp - kflags);
4315 "internal error: unsupported substitution string -k%s",
4321 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4322 /* Handle special files and permissions, if that is desired. */
4328 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
4330 error (1, 0, "internal error: no revision information for %s",
4331 rev == NULL ? rcs->head : rev);
4334 /* First we look for symlinks, which are simplest to handle. */
4335 info = findnode (vers->other_delta, "symlink");
4340 if (pfn != NULL || (workfile == NULL && sout == RUN_TTY))
4341 error (1, 0, "symbolic link %s:%s cannot be piped",
4342 rcs->path, vers->version);
4343 if (workfile == NULL)
4348 /* Remove `dest', just in case. It's okay to get ENOENT here,
4349 since we just want the file not to be there. (TODO: decide
4350 whether it should be considered an error for `dest' to exist
4351 at this point. If so, the unlink call should be removed and
4352 `symlink' should signal the error. -twp) */
4353 if (CVS_UNLINK (dest) < 0 && !existence_error (errno))
4354 error (1, errno, "cannot remove %s", dest);
4355 if (symlink (info->data, dest) < 0)
4356 error (1, errno, "cannot create symbolic link from %s to %s",
4357 dest, (char *)info->data);
4361 /* It's okay to discard the const when free_rev is set, because
4362 * we know we allocated it in this function.
4368 /* Next, we look at this file's hardlinks field, and see whether
4369 it is linked to any other file that has been checked out.
4370 If so, we don't do anything else -- just link it to that file.
4372 If we are checking out a file to a pipe or temporary storage,
4373 none of this should matter. Hence the `workfile != NULL'
4374 wrapper around the whole thing. -twp */
4376 if (workfile != NULL)
4378 List *links = vers->hardlinks;
4381 Node *uptodate_link;
4383 /* For each file in the hardlinks field, check to see
4384 if it exists, and if so, if it has been checked out
4385 this iteration. When walklist returns, uptodate_link
4386 should point to a hardlist node representing a file
4387 in `links' which has recently been checked out, or
4388 NULL if no file in `links' has yet been checked out. */
4390 uptodate_link = NULL;
4391 (void) walklist (links, find_checkedout_proc, &uptodate_link);
4394 /* If we've found a file that `workfile' is supposed to be
4395 linked to, and it has been checked out since CVS was
4396 invoked, then simply link workfile to that file and return.
4398 If one of these conditions is not met, then
4399 workfile is the first one in its hardlink group to
4400 be checked out, and we must continue with a full
4403 if (uptodate_link != NULL)
4405 struct hardlink_info *hlinfo = uptodate_link->data;
4407 if (link (uptodate_link->key, workfile) < 0)
4408 error (1, errno, "cannot link %s to %s",
4409 workfile, uptodate_link->key);
4410 hlinfo->checked_out = 1; /* probably unnecessary */
4414 /* It's okay to discard the const when free_rev is set,
4415 * because we know we allocated it in this function.
4423 info = findnode (vers->other_delta, "owner");
4426 change_rcs_owner_or_group = 1;
4427 rcs_owner = (uid_t) strtoul (info->data, NULL, 10);
4429 info = findnode (vers->other_delta, "group");
4432 change_rcs_owner_or_group = 1;
4433 rcs_group = (gid_t) strtoul (info->data, NULL, 10);
4435 info = findnode (vers->other_delta, "permissions");
4438 change_rcs_mode = 1;
4439 rcs_mode = (mode_t) strtoul (info->data, NULL, 8);
4441 info = findnode (vers->other_delta, "special");
4444 /* If the size of `devtype' changes, fix the sscanf call also */
4447 if (sscanf (info->data, "%15s %lu",
4448 devtype, &devnum_long) < 2)
4449 error (1, 0, "%s:%s has bad `special' newphrase %s",
4450 workfile, vers->version, (char *)info->data);
4451 devnum = devnum_long;
4452 if (STREQ (devtype, "character"))
4453 special_file = S_IFCHR;
4454 else if (STREQ (devtype, "block"))
4455 special_file = S_IFBLK;
4457 error (0, 0, "%s is a special file of unsupported type `%s'",
4458 workfile, (char *)info->data);
4461 #endif /* PRESERVE_PERMISSIONS_SUPPORT */
4463 if (expand != KFLAG_O && expand != KFLAG_B)
4467 /* Don't fetch the delta node again if we already have it. */
4470 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
4472 error (1, 0, "internal error: no revision information for %s",
4473 rev == NULL ? rcs->head : rev);
4476 expand_keywords (rcs, vp->data, nametag, log, loglen,
4477 expand, value, len, &newvalue, &len);
4479 if (newvalue != value)
4489 /* It's okay to discard the const when free_rev is set, because
4490 * we know we allocated it in this function.
4502 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4504 error (1, 0, "special file %s cannot be piped to anything",
4507 /* The PFN interface is very simple to implement right now, as
4508 we always have the entire file in memory. */
4510 pfn (callerdat, value, len);
4512 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4513 else if (special_file)
4518 /* Can send either to WORKFILE or to SOUT, as long as SOUT is
4523 if (sout == RUN_TTY)
4524 error (1, 0, "special file %s cannot be written to stdout",
4529 /* Unlink `dest', just in case. It's okay if this provokes a
4531 if (CVS_UNLINK (dest) < 0 && existence_error (errno))
4532 error (1, errno, "cannot remove %s", dest);
4533 if (mknod (dest, special_file, devnum) < 0)
4534 error (1, errno, "could not create special file %s",
4538 "cannot create %s: unable to create special files on this system",
4545 /* Not a special file: write to WORKFILE or SOUT. */
4546 if (workfile == NULL)
4548 if (sout == RUN_TTY)
4552 /* Symbolic links should be removed before replacement, so that
4553 `fopen' doesn't follow the link and open the wrong file. */
4555 if (unlink_file (sout) < 0)
4556 error (1, errno, "cannot remove %s", sout);
4557 ofp = CVS_FOPEN (sout, expand == KFLAG_B ? "wb" : "w");
4559 error (1, errno, "cannot open %s", sout);
4564 /* Output is supposed to go to WORKFILE, so we should open that
4565 file. Symbolic links should be removed first (see above). */
4566 if (islink (workfile))
4567 if (unlink_file (workfile) < 0)
4568 error (1, errno, "cannot remove %s", workfile);
4570 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
4572 /* If the open failed because the existing workfile was not
4573 writable, try to chmod the file and retry the open. */
4574 if (ofp == NULL && errno == EACCES
4575 && isfile (workfile) && !iswritable (workfile))
4577 xchmod (workfile, 1);
4578 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
4583 error (0, errno, "cannot open %s", workfile);
4590 if (workfile == NULL && sout == RUN_TTY)
4592 if (expand == KFLAG_B)
4593 cvs_output_binary (value, len);
4596 /* cvs_output requires the caller to check for zero
4599 cvs_output (value, len);
4604 /* NT 4.0 is said to have trouble writing 2099999 bytes
4605 (for example) in a single fwrite. So break it down
4606 (there is no need to be writing that much at once
4607 anyway; it is possible that LARGEST_FWRITE should be
4608 somewhat larger for good performance, but for testing I
4609 want to start with a small value until/unless a bigger
4610 one proves useful). */
4611 #define LARGEST_FWRITE 8192
4613 size_t nstep = (len < LARGEST_FWRITE ? len : LARGEST_FWRITE);
4618 if (fwrite (p, 1, nstep, ofp) != nstep)
4620 error (0, errno, "cannot write %s",
4623 : (sout != RUN_TTY ? sout : "stdout")));
4639 if (workfile != NULL)
4643 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4644 if (!special_file && fclose (ofp) < 0)
4646 error (0, errno, "cannot close %s", workfile);
4650 if (change_rcs_owner_or_group)
4652 if (chown (workfile, rcs_owner, rcs_group) < 0)
4653 error (0, errno, "could not change owner or group of %s",
4657 ret = chmod (workfile,
4660 : sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
4662 if (fclose (ofp) < 0)
4664 error (0, errno, "cannot close %s", workfile);
4668 ret = chmod (workfile,
4669 sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
4673 error (0, errno, "cannot change mode of file %s",
4677 else if (sout != RUN_TTY)
4680 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4685 error (0, errno, "cannot close %s", sout);
4690 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4691 /* If we are in the business of preserving hardlinks, then
4692 mark this file as having been checked out. */
4693 if (preserve_perms && workfile != NULL)
4694 update_hardlink_info (workfile);
4700 static RCSVers *RCS_findlock_or_tip PROTO ((RCSNode *rcs));
4702 /* Find the delta currently locked by the user. From the `ci' man page:
4704 "If rev is omitted, ci tries to derive the new revision
4705 number from the caller's last lock. If the caller has
4706 locked the tip revision of a branch, the new revision is
4707 appended to that branch. The new revision number is
4708 obtained by incrementing the tip revision number. If the
4709 caller locked a non-tip revision, a new branch is started
4710 at that revision by incrementing the highest branch number
4711 at that revision. The default initial branch and level
4714 If rev is omitted and the caller has no lock, but owns the
4715 file and locking is not set to strict, then the revision
4716 is appended to the default branch (normally the trunk; see
4717 the -b option of rcs(1))."
4719 RCS_findlock_or_tip finds the unique revision locked by the caller
4720 and returns its delta node. If the caller has not locked any
4721 revisions (and is permitted to commit to an unlocked delta, as
4722 described above), return the tip of the default branch. */
4725 RCS_findlock_or_tip (rcs)
4728 char *user = getcaller();
4731 char *defaultrev = NULL;
4733 /* Find unique delta locked by caller. This code is very similar
4734 to the code in RCS_unlock -- perhaps it could be abstracted
4735 into a RCS_findlock function. */
4736 locklist = RCS_getlocks (rcs);
4738 for (p = locklist->list->next; p != locklist->list; p = p->next)
4740 if (STREQ (p->data, user))
4745 %s: multiple revisions locked by %s; please specify one", rcs->path, user);
4754 /* Found an old lock, but check that the revision still exists. */
4755 p = findnode (rcs->versions, lock->key);
4758 error (0, 0, "%s: can't unlock nonexistent revision %s",
4766 /* No existing lock. The RCS rule is that this is an error unless
4767 locking is nonstrict AND the file is owned by the current
4768 user. Trying to determine the latter is a portability nightmare
4769 in the face of NT, VMS, AFS, and other systems with non-unix-like
4770 ideas of users and owners. In the case of CVS, we should never get
4771 here (as long as the traditional behavior of making sure to call
4772 RCS_lock persists). Anyway, we skip the RCS error checks
4773 and just return the default branch or head. The reasoning is that
4774 those error checks are to make users lock before a checkin, and we do
4775 that in other ways if at all anyway (e.g. rcslock.pl). */
4777 defaultrev = RCS_getbranch (rcs, rcs->branch, 0);
4778 p = findnode (rcs->versions, defaultrev);
4779 if (defaultrev != NULL)
4783 error (0, 0, "RCS file `%s' does not contain its default revision.",
4791 /* Revision number string, R, must contain a `.'.
4792 Return a newly-malloc'd copy of the prefix of R up
4793 to but not including the final `.'. */
4801 char *dot = strrchr (r, '.');
4805 new_r = xmalloc (len + 1);
4806 memcpy (new_r, r, len);
4807 *(new_r + len) = '\0';
4811 /* Revision number string, R, must contain a `.'.
4812 R must be writable. Replace the rightmost `.' in R with
4813 the NUL byte and return a pointer to that NUL byte. */
4816 truncate_revnum_in_place (r)
4819 char *dot = strrchr (r, '.');
4825 /* Revision number strings, R and S, must each contain a `.'.
4826 R and S must be writable and must have the same number of dots.
4827 Truncate R and S for the comparison, then restored them to their
4829 Return the result (see compare_revnums) of comparing R and S
4830 ignoring differences in any component after the rightmost `.'. */
4833 compare_truncated_revnums (r, s)
4837 char *r_dot = truncate_revnum_in_place (r);
4838 char *s_dot = truncate_revnum_in_place (s);
4841 assert (numdots (r) == numdots (s));
4843 cmp = compare_revnums (r, s);
4851 /* Return a malloc'd copy of the string representing the highest branch
4852 number on BRANCHNODE. If there are no branches on BRANCHNODE, return NULL.
4853 FIXME: isn't the max rev always the last one?
4854 If so, we don't even need a loop. */
4856 static char *max_rev PROTO ((const RCSVers *));
4859 max_rev (branchnode)
4860 const RCSVers *branchnode;
4866 if (branchnode->branches == NULL)
4872 head = branchnode->branches->list;
4873 for (bp = head->next; bp != head; bp = bp->next)
4875 if (max == NULL || compare_truncated_revnums (max, bp->key) < 0)
4882 return truncate_revnum (max);
4885 /* Create BRANCH in RCS's delta tree. BRANCH may be either a branch
4886 number or a revision number. In the former case, create the branch
4887 with the specified number; in the latter case, create a new branch
4888 rooted at node BRANCH with a higher branch number than any others.
4889 Return the number of the tip node on the new branch. */
4892 RCS_addbranch (rcs, branch)
4896 char *branchpoint, *newrevnum;
4899 RCSVers *branchnode;
4903 /* Append to end by default. */
4906 branchpoint = xstrdup (branch);
4907 if ((numdots (branchpoint) & 1) == 0)
4909 truncate_revnum_in_place (branchpoint);
4912 /* Find the branch rooted at BRANCHPOINT. */
4913 nodep = findnode (rcs->versions, branchpoint);
4916 error (0, 0, "%s: can't find branch point %s", rcs->path, branchpoint);
4921 branchnode = nodep->data;
4923 /* If BRANCH was a full branch number, make sure it is higher than MAX. */
4924 if ((numdots (branch) & 1) == 1)
4926 if (branchnode->branches == NULL)
4928 /* We have to create the first branch on this node, which means
4929 appending ".2" to the revision number. */
4930 newrevnum = (char *) xmalloc (strlen (branch) + 3);
4931 strcpy (newrevnum, branch);
4932 strcat (newrevnum, ".2");
4936 char *max = max_rev (branchnode);
4938 newrevnum = increment_revnum (max);
4944 newrevnum = xstrdup (branch);
4946 if (branchnode->branches != NULL)
4951 /* Find the position of this new branch in the sorted list
4953 head = branchnode->branches->list;
4954 for (bp = head->next; bp != head; bp = bp->next)
4959 /* The existing list must be sorted on increasing revnum. */
4960 assert (bp->next == head
4961 || compare_truncated_revnums (bp->key,
4962 bp->next->key) < 0);
4963 dot = truncate_revnum_in_place (bp->key);
4964 found_pos = (compare_revnums (branch, bp->key) < 0);
4976 newrevnum = (char *) xrealloc (newrevnum, strlen (newrevnum) + 3);
4977 strcat (newrevnum, ".1");
4979 /* Add this new revision number to BRANCHPOINT's branches list. */
4980 if (branchnode->branches == NULL)
4981 branchnode->branches = getlist();
4983 bp->key = xstrdup (newrevnum);
4985 /* Append to the end of the list by default, that is, just before
4986 the header node, `list'. */
4988 marker = branchnode->branches->list;
4992 fail = insert_before (branchnode->branches, marker, bp);
4999 /* Check in to RCSFILE with revision REV (which must be greater than
5000 the largest revision) and message MESSAGE (which is checked for
5001 legality). If FLAGS & RCS_FLAGS_DEAD, check in a dead revision.
5002 If FLAGS & RCS_FLAGS_QUIET, tell ci to be quiet. If FLAGS &
5003 RCS_FLAGS_MODTIME, use the working file's modification time for the
5004 checkin time. WORKFILE is the working file to check in from, or
5005 NULL to use the usual RCS rules for deriving it from the RCSFILE.
5006 If FLAGS & RCS_FLAGS_KEEPFILE, don't unlink the working file;
5007 unlinking the working file is standard RCS behavior, but is rarely
5008 appropriate for CVS.
5010 This function should almost exactly mimic the behavior of `rcs ci'. The
5011 principal point of difference is the support here for preserving file
5012 ownership and permissions in the delta nodes. This is not a clean
5013 solution -- precisely because it diverges from RCS's behavior -- but
5014 it doesn't seem feasible to do this anywhere else in the code. [-twp]
5016 Return value is -1 for error (and errno is set to indicate the
5017 error), positive for error (and an error message has been printed),
5018 or zero for success. */
5021 RCS_checkin (rcs, workfile_in, message, rev, citime, flags)
5023 const char *workfile_in;
5024 const char *message;
5029 RCSVers *delta, *commitpt;
5032 char *tmpfile, *changefile;
5034 size_t darg_allocated = 0;
5035 char **dargv = NULL;
5037 int status, checkin_quiet;
5040 int adding_branch = 0;
5041 char *workfile = xstrdup (workfile_in);
5042 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5048 if (rcs->flags & PARTIAL)
5049 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5051 /* Get basename of working file. Is there a library function to
5052 do this? I couldn't find one. -twp */
5053 if (workfile == NULL)
5056 int extlen = strlen (RCSEXT);
5058 workfile = xstrdup (last_component (rcs->path));
5059 p = workfile + (strlen (workfile) - extlen);
5060 assert (strncmp (p, RCSEXT, extlen) == 0);
5064 /* If the filename is a symbolic link, follow it and replace it
5065 with the destination of the link. We need to do this before
5066 calling rcs_internal_lockfile, or else we won't put the lock in
5068 resolve_symlink (&(rcs->path));
5070 checkin_quiet = flags & RCS_FLAGS_QUIET;
5073 cvs_output (rcs->path, 0);
5074 cvs_output (" <-- ", 7);
5075 cvs_output (workfile, 0);
5076 cvs_output ("\n", 1);
5079 /* Create new delta node. */
5080 delta = (RCSVers *) xmalloc (sizeof (RCSVers));
5081 memset (delta, 0, sizeof (RCSVers));
5082 delta->author = xstrdup (getcaller ());
5083 if (flags & RCS_FLAGS_MODTIME)
5086 if (stat (workfile, &ws) < 0)
5088 error (1, errno, "cannot stat %s", workfile);
5090 modtime = ws.st_mtime;
5092 else if (flags & RCS_FLAGS_USETIME)
5095 (void) time (&modtime);
5096 ftm = gmtime (&modtime);
5097 delta->date = (char *) xmalloc (MAXDATELEN);
5098 (void) sprintf (delta->date, DATEFORM,
5099 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
5100 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
5101 ftm->tm_min, ftm->tm_sec);
5102 if (flags & RCS_FLAGS_DEAD)
5104 delta->state = xstrdup (RCSDEAD);
5108 delta->state = xstrdup ("Exp");
5110 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5111 /* If permissions should be preserved on this project, then
5112 save the permission info. */
5116 char buf[64]; /* static buffer should be safe: see usage. -twp */
5118 delta->other_delta = getlist();
5120 if (CVS_LSTAT (workfile, &sb) < 0)
5121 error (1, errno, "cannot lstat %s", workfile);
5123 if (S_ISLNK (sb.st_mode))
5126 np->type = RCSFIELD;
5127 np->key = xstrdup ("symlink");
5128 np->data = xreadlink (workfile);
5129 addnode (delta->other_delta, np);
5133 (void) sprintf (buf, "%u", sb.st_uid);
5135 np->type = RCSFIELD;
5136 np->key = xstrdup ("owner");
5137 np->data = xstrdup (buf);
5138 addnode (delta->other_delta, np);
5140 (void) sprintf (buf, "%u", sb.st_gid);
5142 np->type = RCSFIELD;
5143 np->key = xstrdup ("group");
5144 np->data = xstrdup (buf);
5145 addnode (delta->other_delta, np);
5147 (void) sprintf (buf, "%o", sb.st_mode & 07777);
5149 np->type = RCSFIELD;
5150 np->key = xstrdup ("permissions");
5151 np->data = xstrdup (buf);
5152 addnode (delta->other_delta, np);
5154 /* Save device number. */
5155 switch (sb.st_mode & S_IFMT)
5157 case S_IFREG: break;
5160 # ifdef HAVE_STRUCT_STAT_ST_RDEV
5162 np->type = RCSFIELD;
5163 np->key = xstrdup ("special");
5164 sprintf (buf, "%s %lu",
5165 ((sb.st_mode & S_IFMT) == S_IFCHR
5166 ? "character" : "block"),
5167 (unsigned long) sb.st_rdev);
5168 np->data = xstrdup (buf);
5169 addnode (delta->other_delta, np);
5172 "can't preserve %s: unable to save device files on this system",
5178 error (0, 0, "special file %s has unknown type", workfile);
5181 /* Save hardlinks. */
5182 delta->hardlinks = list_linked_files_on_disk (workfile);
5187 /* Create a new deltatext node. */
5188 dtext = (Deltatext *) xmalloc (sizeof (Deltatext));
5189 memset (dtext, 0, sizeof (Deltatext));
5191 dtext->log = make_message_rcslegal (message);
5193 /* If the delta tree is empty, then there's nothing to link the
5194 new delta into. So make a new delta tree, snarf the working
5195 file contents, and just write the new RCS file. */
5196 if (rcs->head == NULL)
5201 /* Figure out what the first revision number should be. */
5202 if (rev == NULL || *rev == '\0')
5203 newrev = xstrdup ("1.1");
5204 else if (numdots (rev) == 0)
5206 newrev = (char *) xmalloc (strlen (rev) + 3);
5207 strcpy (newrev, rev);
5208 strcat (newrev, ".1");
5211 newrev = xstrdup (rev);
5213 /* Don't need to xstrdup NEWREV because it's already dynamic, and
5214 not used for anything else. (Don't need to free it, either.) */
5216 delta->version = xstrdup (newrev);
5218 nodep->type = RCSVERS;
5219 nodep->delproc = rcsvers_delproc;
5220 nodep->data = delta;
5221 nodep->key = delta->version;
5222 (void) addnode (rcs->versions, nodep);
5224 dtext->version = xstrdup (newrev);
5226 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5227 if (preserve_perms && !S_ISREG (sb.st_mode))
5228 /* Pretend file is empty. */
5232 get_file (workfile, workfile,
5233 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5234 &dtext->text, &bufsize, &dtext->len);
5238 cvs_output ("initial revision: ", 0);
5239 cvs_output (rcs->head, 0);
5240 cvs_output ("\n", 1);
5243 /* We are probably about to invalidate any cached file. */
5244 rcsbuf_cache_close ();
5246 fout = rcs_internal_lockfile (rcs->path);
5247 RCS_putadmin (rcs, fout);
5248 RCS_putdtree (rcs, rcs->head, fout);
5249 RCS_putdesc (rcs, fout);
5250 rcs->delta_pos = ftell (fout);
5251 if (rcs->delta_pos == -1)
5252 error (1, errno, "cannot ftell for %s", rcs->path);
5253 putdeltatext (fout, dtext);
5254 rcs_internal_unlockfile (fout, rcs->path);
5256 if ((flags & RCS_FLAGS_KEEPFILE) == 0)
5258 if (unlink_file (workfile) < 0)
5259 /* FIXME-update-dir: message does not include update_dir. */
5260 error (0, errno, "cannot remove %s", workfile);
5264 cvs_output ("done\n", 5);
5270 /* Derive a new revision number. From the `ci' man page:
5272 "If rev is a revision number, it must be higher than the
5273 latest one on the branch to which rev belongs, or must
5276 If rev is a branch rather than a revision number, the new
5277 revision is appended to that branch. The level number is
5278 obtained by incrementing the tip revision number of that
5279 branch. If rev indicates a non-existing branch, that
5280 branch is created with the initial revision numbered
5283 RCS_findlock_or_tip handles the case where REV is omitted.
5284 RCS 5.7 also permits REV to be "$" or to begin with a dot, but
5285 we do not address those cases -- every routine that calls
5286 RCS_checkin passes it a numeric revision. */
5288 if (rev == NULL || *rev == '\0')
5290 /* Figure out where the commit point is by looking for locks.
5291 If the commit point is at the tip of a branch (or is the
5292 head of the delta tree), then increment its revision number
5293 to obtain the new revnum. Otherwise, start a new
5295 commitpt = RCS_findlock_or_tip (rcs);
5296 if (commitpt == NULL)
5301 else if (commitpt->next == NULL
5302 || STREQ (commitpt->version, rcs->head))
5303 delta->version = increment_revnum (commitpt->version);
5305 delta->version = RCS_addbranch (rcs, commitpt->version);
5309 /* REV is either a revision number or a branch number. Find the
5310 tip of the target branch. */
5311 char *branch, *tip, *newrev, *p;
5314 assert (isdigit ((unsigned char) *rev));
5316 newrev = xstrdup (rev);
5317 dots = numdots (newrev);
5318 isrevnum = dots & 1;
5320 branch = xstrdup (rev);
5323 p = strrchr (branch, '.');
5327 /* Find the tip of the target branch. If we got a one- or two-digit
5328 revision number, this will be the head of the tree. Exception:
5329 if rev is a single-field revision equal to the branch number of
5330 the trunk (usually "1") then we want to treat it like an ordinary
5334 tip = xstrdup (rcs->head);
5335 assert (tip != NULL);
5336 if (atoi (tip) != atoi (branch))
5338 newrev = (char *) xrealloc (newrev, strlen (newrev) + 3);
5339 strcat (newrev, ".1");
5340 dots = isrevnum = 1;
5344 tip = xstrdup (rcs->head);
5346 tip = RCS_getbranch (rcs, branch, 1);
5348 /* If the branch does not exist, and we were supplied an exact
5349 revision number, signal an error. Otherwise, if we were
5350 given only a branch number, create it and set COMMITPT to
5351 the branch point. */
5356 error (0, 0, "%s: can't find branch point %s",
5363 delta->version = RCS_addbranch (rcs, branch);
5364 if (!delta->version)
5372 p = strrchr (branch, '.');
5374 tip = xstrdup (branch);
5380 /* NEWREV must be higher than TIP. */
5381 if (compare_revnums (tip, newrev) >= 0)
5384 "%s: revision %s too low; must be higher than %s",
5393 delta->version = xstrdup (newrev);
5396 /* Just increment the tip number to get the new revision. */
5397 delta->version = increment_revnum (tip);
5400 nodep = findnode (rcs->versions, tip);
5401 commitpt = nodep->data;
5408 assert (delta->version != NULL);
5410 /* If COMMITPT is locked by us, break the lock. If it's locked
5411 by someone else, signal an error. */
5412 nodep = findnode (RCS_getlocks (rcs), commitpt->version);
5415 if (! STREQ (nodep->data, delta->author))
5417 /* If we are adding a branch, then leave the old lock around.
5418 That is sensible in the sense that when adding a branch,
5419 we don't need to use the lock to tell us where to check
5420 in. It is fishy in the sense that if it is our own lock,
5421 we break it. However, this is the RCS 5.7 behavior (at
5422 the end of addbranch in ci.c in RCS 5.7, it calls
5423 removelock only if it is our own lock, not someone
5428 error (0, 0, "%s: revision %s locked by %s",
5430 nodep->key, (char *)nodep->data);
5439 dtext->version = xstrdup (delta->version);
5441 /* Obtain the change text for the new delta. If DELTA is to be the
5442 new head of the tree, then its change text should be the contents
5443 of the working file, and LEAFNODE's change text should be a diff.
5444 Else, DELTA's change text should be a diff between LEAFNODE and
5445 the working file. */
5447 tmpfile = cvs_temp_name();
5448 status = RCS_checkout (rcs, NULL, commitpt->version, NULL,
5449 ((rcs->expand != NULL
5450 && STREQ (rcs->expand, "b"))
5454 (RCSCHECKOUTPROC)0, NULL);
5457 "could not check out revision %s of `%s'",
5458 commitpt->version, rcs->path);
5461 changefile = cvs_temp_name();
5463 /* Diff options should include --binary if the RCS file has -kb set
5464 in its `expand' field. */
5465 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-a");
5466 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n");
5467 if (rcs->expand && STREQ (rcs->expand, "b"))
5468 run_add_arg_p (&dargc, &darg_allocated, &dargv, "--binary");
5470 if (STREQ (commitpt->version, rcs->head) &&
5471 numdots (delta->version) == 1)
5473 /* If this revision is being inserted on the trunk, the change text
5474 for the new delta should be the contents of the working file ... */
5476 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5477 if (preserve_perms && !S_ISREG (sb.st_mode))
5478 /* Pretend file is empty. */
5482 get_file (workfile, workfile,
5483 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5484 &dtext->text, &bufsize, &dtext->len);
5486 /* ... and the change text for the old delta should be a diff. */
5487 commitpt->text = (Deltatext *) xmalloc (sizeof (Deltatext));
5488 memset (commitpt->text, 0, sizeof (Deltatext));
5491 switch (diff_exec (workfile, tmpfile, NULL, NULL,
5492 dargc, dargv, changefile))
5498 /* FIXME-update-dir: message does not include update_dir. */
5499 error (1, errno, "error diffing %s", workfile);
5502 /* FIXME-update-dir: message does not include update_dir. */
5503 error (1, 0, "error diffing %s", workfile);
5507 /* OK, the text file case here is really dumb. Logically
5508 speaking we want diff to read the files in text mode,
5509 convert them to the canonical form found in RCS files
5510 (which, we hope at least, is independent of OS--always
5511 bare linefeeds), and then work with change texts in that
5512 format. However, diff_exec both generates change
5513 texts and produces output for user purposes (e.g. patch.c),
5514 and there is no way to distinguish between the two cases.
5515 So we actually implement the text file case by writing the
5516 change text as a text file, then reading it as a text file.
5517 This should cause no harm, but doesn't strike me as
5519 get_file (changefile, changefile,
5520 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5521 &commitpt->text->text, &bufsize, &commitpt->text->len);
5523 /* If COMMITPT->TEXT->TEXT is NULL, it means that CHANGEFILE
5524 was empty and that there are no differences between revisions.
5525 In that event, we want to force RCS_rewrite to write an empty
5526 string for COMMITPT's change text. Leaving the change text
5527 field set NULL won't work, since that means "preserve the original
5528 change text for this delta." */
5529 if (commitpt->text->text == NULL)
5531 commitpt->text->text = xstrdup ("");
5532 commitpt->text->len = 0;
5537 /* This file is not being inserted at the head, but on a side
5538 branch somewhere. Make a diff from the previous revision
5539 to the working file. */
5540 switch (diff_exec (tmpfile, workfile, NULL, NULL,
5541 dargc, dargv, changefile))
5547 /* FIXME-update-dir: message does not include update_dir. */
5548 error (1, errno, "error diffing %s", workfile);
5551 /* FIXME-update-dir: message does not include update_dir. */
5552 error (1, 0, "error diffing %s", workfile);
5555 /* See the comment above, at the other get_file invocation,
5556 regarding binary vs. text. */
5557 get_file (changefile, changefile,
5558 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5559 &dtext->text, &bufsize,
5561 if (dtext->text == NULL)
5563 dtext->text = xstrdup ("");
5568 run_arg_free_p (dargc, dargv);
5571 /* Update DELTA linkage. It is important not to do this before
5572 the very end of RCS_checkin; if an error arises that forces
5573 us to abort checking in, we must not have malformed deltas
5574 partially linked into the tree.
5576 If DELTA and COMMITPT are on different branches, do nothing --
5577 DELTA is linked to the tree through COMMITPT->BRANCHES, and we
5578 don't want to change `next' pointers.
5580 Otherwise, if the nodes are both on the trunk, link DELTA to
5581 COMMITPT; otherwise, link COMMITPT to DELTA. */
5583 if (numdots (commitpt->version) == numdots (delta->version))
5585 if (STREQ (commitpt->version, rcs->head))
5587 delta->next = rcs->head;
5588 rcs->head = xstrdup (delta->version);
5591 commitpt->next = xstrdup (delta->version);
5594 /* Add DELTA to RCS->VERSIONS. */
5595 if (rcs->versions == NULL)
5596 rcs->versions = getlist();
5598 nodep->type = RCSVERS;
5599 nodep->delproc = rcsvers_delproc;
5600 nodep->data = delta;
5601 nodep->key = delta->version;
5602 (void) addnode (rcs->versions, nodep);
5604 /* Write the new RCS file, inserting the new delta at COMMITPT. */
5607 cvs_output ("new revision: ", 14);
5608 cvs_output (delta->version, 0);
5609 cvs_output ("; previous revision: ", 21);
5610 cvs_output (commitpt->version, 0);
5611 cvs_output ("\n", 1);
5614 RCS_rewrite (rcs, dtext, commitpt->version);
5616 if ((flags & RCS_FLAGS_KEEPFILE) == 0)
5618 if (unlink_file (workfile) < 0)
5619 /* FIXME-update-dir: message does not include update_dir. */
5620 error (1, errno, "cannot remove %s", workfile);
5622 if (unlink_file (tmpfile) < 0)
5623 error (0, errno, "cannot remove %s", tmpfile);
5625 if (unlink_file (changefile) < 0)
5626 error (0, errno, "cannot remove %s", changefile);
5630 cvs_output ("done\n", 5);
5635 if (commitpt != NULL && commitpt->text != NULL)
5637 freedeltatext (commitpt->text);
5638 commitpt->text = NULL;
5641 freedeltatext (dtext);
5644 /* If delta has not been added to a List, then freeing the Node key
5645 * won't free delta->version.
5647 if (delta->version) free (delta->version);
5648 free_rcsvers_contents (delta);
5656 /* This structure is passed between RCS_cmp_file and cmp_file_buffer. */
5657 struct cmp_file_data
5659 const char *filename;
5664 /* Compare the contents of revision REV1 of RCS file RCS with the
5665 contents of REV2 if given, otherwise, compare with the contents of
5666 the file FILENAME. OPTIONS is a string for the keyword
5667 expansion options. Return 0 if the contents of the revision are
5668 the same as the contents of the file, 1 if they are different. */
5670 RCS_cmp_file (rcs, rev1, rev1_cache, rev2, options, filename)
5675 const char *options;
5676 const char *filename;
5680 if (options != NULL && options[0] != '\0')
5681 binary = STREQ (options, "-kb");
5686 expand = RCS_getexpand (rcs);
5687 if (expand != NULL && STREQ (expand, "b"))
5693 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5694 /* If CVS is to deal properly with special files (when
5695 PreservePermissions is on), the best way is to check out the
5696 revision to a temporary file and call `xcmp' on the two disk
5697 files. xcmp needs to handle non-regular files properly anyway,
5698 so calling it simplifies RCS_cmp_file. We *could* just yank
5699 the delta node out of the version tree and look for device
5700 numbers, but writing to disk and calling xcmp is a better
5701 abstraction (therefore probably more robust). -twp */
5708 tmp = cvs_temp_name();
5709 retcode = RCS_checkout(rcs, NULL, rev, NULL, options, tmp, NULL, NULL);
5713 retcode = xcmp (tmp, filename);
5714 if (CVS_UNLINK (tmp) < 0)
5715 error (0, errno, "cannot remove %s", tmp);
5723 struct cmp_file_data data;
5724 const char *use_file1;
5725 char *tmpfile = NULL;
5729 /* Open & cache rev1 */
5730 tmpfile = cvs_temp_name();
5731 if (RCS_checkout (rcs, NULL, rev1, NULL, options, tmpfile,
5732 (RCSCHECKOUTPROC)0, NULL))
5734 "cannot check out revision %s of %s",
5736 use_file1 = tmpfile;
5737 if (rev1_cache != NULL)
5738 *rev1_cache = tmpfile;
5741 use_file1 = filename;
5743 fp = CVS_FOPEN (use_file1, binary ? FOPEN_BINARY_READ : "r");
5745 /* FIXME-update-dir: should include update_dir in message. */
5746 error (1, errno, "cannot open file %s for comparing", use_file1);
5748 data.filename = use_file1;
5752 if (RCS_checkout (rcs, (char *)NULL, rev2 ? rev2 : rev1,
5753 (char *)NULL, options, RUN_TTY, cmp_file_buffer,
5756 "cannot check out revision %s of %s",
5757 rev2 ? rev2 : rev1, rcs->path);
5759 /* If we have not yet found a difference, make sure that we are at
5760 the end of the file. */
5761 if (!data.different)
5763 if (getc (fp) != EOF)
5768 if (rev1_cache == NULL && tmpfile)
5770 if (CVS_UNLINK (tmpfile ) < 0)
5771 error (0, errno, "cannot remove %s", tmpfile);
5775 return data.different;
5781 /* This is a subroutine of RCS_cmp_file. It is passed to
5783 #define CMP_BUF_SIZE (8 * 1024)
5786 cmp_file_buffer (callerdat, buffer, len)
5791 struct cmp_file_data *data = (struct cmp_file_data *)callerdat;
5794 /* If we've already found a difference, we don't need to check
5796 if (data->different)
5799 filebuf = xmalloc (len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len);
5805 checklen = len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len;
5806 if (fread (filebuf, 1, checklen, data->fp) != checklen)
5808 if (ferror (data->fp))
5809 error (1, errno, "cannot read file %s for comparing",
5811 data->different = 1;
5816 if (memcmp (filebuf, buffer, checklen) != 0)
5818 data->different = 1;
5832 /* For RCS file RCS, make symbolic tag TAG point to revision REV.
5833 This validates that TAG is OK for a user to use. Return value is
5834 -1 for error (and errno is set to indicate the error), positive for
5835 error (and an error message has been printed), or zero for success. */
5838 RCS_settag (rcs, tag, rev)
5846 if (rcs->flags & PARTIAL)
5847 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5849 /* FIXME: This check should be moved to RCS_check_tag. There is no
5850 reason for it to be here. */
5851 if (STREQ (tag, TAG_BASE)
5852 || STREQ (tag, TAG_HEAD))
5854 /* Print the name of the tag might be considered redundant
5855 with the caller, which also prints it. Perhaps this helps
5856 clarify why the tag name is considered reserved, I don't
5858 error (0, 0, "Attempt to add reserved tag name %s", tag);
5862 /* A revision number of NULL means use the head or default branch.
5863 If rev is not NULL, it may be a symbolic tag or branch number;
5864 expand it to the correct numeric revision or branch head. */
5866 rev = rcs->branch ? rcs->branch : rcs->head;
5868 /* At this point rcs->symbol_data may not have been parsed.
5869 Calling RCS_symbols will force it to be parsed into a list
5870 which we can easily manipulate. */
5871 symbols = RCS_symbols (rcs);
5872 if (symbols == NULL)
5874 symbols = getlist ();
5875 rcs->symbols = symbols;
5877 node = findnode (symbols, tag);
5881 node->data = xstrdup (rev);
5886 node->key = xstrdup (tag);
5887 node->data = xstrdup (rev);
5888 (void) addnode_at_front (symbols, node);
5894 /* Delete the symbolic tag TAG from the RCS file RCS. Return 0 if
5895 the tag was found (and removed), or 1 if it was not present. (In
5896 either case, the tag will no longer be in RCS->SYMBOLS.) */
5899 RCS_deltag (rcs, tag)
5905 if (rcs->flags & PARTIAL)
5906 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5908 symbols = RCS_symbols (rcs);
5909 if (symbols == NULL)
5912 node = findnode (symbols, tag);
5921 /* Set the default branch of RCS to REV. */
5924 RCS_setbranch (rcs, rev)
5928 if (rcs->flags & PARTIAL)
5929 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5934 if (rev == NULL && rcs->branch == NULL)
5936 if (rev != NULL && rcs->branch != NULL && STREQ (rev, rcs->branch))
5939 if (rcs->branch != NULL)
5941 rcs->branch = xstrdup (rev);
5946 /* Lock revision REV. LOCK_QUIET is 1 to suppress output. FIXME:
5947 Most of the callers only call us because RCS_checkin still tends to
5948 like a lock (a relic of old behavior inherited from the RCS ci
5949 program). If we clean this up, only "cvs admin -l" will still need
5950 to call RCS_lock. */
5952 /* FIXME-twp: if a lock owned by someone else is broken, should this
5953 send mail to the lock owner? Prompt user? It seems like such an
5954 obscure situation for CVS as almost not worth worrying much
5958 RCS_lock (rcs, rev, lock_quiet)
5968 if (rcs->flags & PARTIAL)
5969 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5971 locks = RCS_getlocks (rcs);
5973 locks = rcs->locks = getlist();
5976 /* A revision number of NULL means lock the head or default branch. */
5978 xrev = RCS_head (rcs);
5980 xrev = RCS_gettag (rcs, rev, 1, (int *) NULL);
5982 /* Make sure that the desired revision exists. Technically,
5983 we can update the locks list without even checking this,
5984 but RCS 5.7 did this. And it can't hurt. */
5985 if (xrev == NULL || findnode (rcs->versions, xrev) == NULL)
5988 error (0, 0, "%s: revision %s absent", rcs->path, rev);
5993 /* Is this rev already locked? */
5994 p = findnode (locks, xrev);
5997 if (STREQ (p->data, user))
5999 /* We already own the lock on this revision, so do nothing. */
6005 /* Well, first of all, "rev" below should be "xrev" to avoid
6006 core dumps. But more importantly, should we really be
6007 breaking the lock unconditionally? What CVS 1.9 does (via
6008 RCS) is to prompt "Revision 1.1 is already locked by fred.
6009 Do you want to break the lock? [ny](n): ". Well, we don't
6010 want to interact with the user (certainly not at the
6011 server/protocol level, and probably not in the command-line
6012 client), but isn't it more sensible to give an error and
6013 let the user run "cvs admin -u" if they want to break the
6016 /* Break the lock. */
6019 cvs_output (rev, 0);
6020 cvs_output (" unlocked\n", 0);
6024 error (1, 0, "Revision %s is already locked by %s", xrev, (char *)p->data);
6028 /* Create a new lock. */
6030 p->key = xrev; /* already xstrdupped */
6031 p->data = xstrdup (getcaller());
6032 (void) addnode_at_front (locks, p);
6036 cvs_output (xrev, 0);
6037 cvs_output (" locked\n", 0);
6043 /* Unlock revision REV. UNLOCK_QUIET is 1 to suppress output. FIXME:
6044 Like RCS_lock, this can become a no-op if we do the checkin
6047 If REV is not null and is locked by someone else, break their
6048 lock and notify them. It is an open issue whether RCS_unlock
6049 queries the user about whether or not to break the lock. */
6052 RCS_unlock (rcs, rev, unlock_quiet)
6063 if (rcs->flags & PARTIAL)
6064 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6066 /* If rev is NULL, unlock the revision held by the caller; if more
6067 than one, make the user specify the revision explicitly. This
6068 differs from RCS which unlocks the latest revision (first in
6069 rcs->locks) held by the caller. */
6074 /* No-ops: attempts to unlock an empty tree or an unlocked file. */
6075 if (rcs->head == NULL)
6078 cvs_outerr ("can't unlock an empty tree\n", 0);
6082 locks = RCS_getlocks (rcs);
6086 cvs_outerr ("No locks are set.\n", 0);
6091 for (p = locks->list->next; p != locks->list; p = p->next)
6093 if (STREQ (p->data, user))
6099 %s: multiple revisions locked by %s; please specify one", rcs->path, user);
6108 error (0, 0, "No locks are set for %s.\n", user);
6109 return 0; /* no lock found, ergo nothing to do */
6111 xrev = xstrdup (lock->key);
6115 xrev = RCS_gettag (rcs, rev, 1, (int *) NULL);
6118 error (0, 0, "%s: revision %s absent", rcs->path, rev);
6123 lock = findnode (RCS_getlocks (rcs), xrev);
6126 /* This revision isn't locked. */
6131 if (! STREQ (lock->data, user))
6133 /* If the revision is locked by someone else, notify
6134 them. Note that this shouldn't ever happen if RCS_unlock
6135 is called with a NULL revision, since that means "whatever
6136 revision is currently locked by the caller." */
6137 char *repos, *workfile;
6140 %s: revision %s locked by %s; breaking lock", rcs->path, xrev, (char *)lock->data);
6141 repos = xstrdup (rcs->path);
6142 workfile = strrchr (repos, '/');
6144 notify_do ('C', workfile, user, NULL, NULL, repos);
6151 cvs_output (xrev, 0);
6152 cvs_output (" unlocked\n", 0);
6159 /* Add USER to the access list of RCS. Do nothing if already present.
6160 FIXME-twp: check syntax of USER to make sure it's a valid id. */
6163 RCS_addaccess (rcs, user)
6169 if (rcs->flags & PARTIAL)
6170 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6172 if (rcs->access == NULL)
6173 rcs->access = xstrdup (user);
6176 access = xstrdup (rcs->access);
6177 for (a = strtok (access, " "); a != NULL; a = strtok (NULL, " "))
6179 if (STREQ (a, user))
6186 rcs->access = (char *) xrealloc
6187 (rcs->access, strlen (rcs->access) + strlen (user) + 2);
6188 strcat (rcs->access, " ");
6189 strcat (rcs->access, user);
6193 /* Remove USER from the access list of RCS. */
6196 RCS_delaccess (rcs, user)
6203 if (rcs->flags & PARTIAL)
6204 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6206 if (rcs->access == NULL)
6217 ulen = strlen (user);
6220 if (strncmp (p, user, ulen) == 0 && (p[ulen] == '\0' || p[ulen] == ' '))
6222 p = strchr (p, ' ');
6240 if (rcs->flags & PARTIAL)
6241 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6246 static int findtag PROTO ((Node *, void *));
6248 /* Return a nonzero value if the revision specified by ARG is found. */
6255 char *rev = (char *)arg;
6257 if (STREQ (node->data, rev))
6263 static int findmagictag PROTO ((Node *, void *));
6265 /* Return a nonzero value if a magic tag rooted at ARG is found. */
6268 findmagictag (node, arg)
6272 char *rev = (char *)arg;
6273 size_t len = strlen (rev);
6275 if (strncmp (node->data, rev, len) == 0 &&
6276 strncmp ((char *)node->data + len, ".0.", 3) == 0)
6282 /* Delete revisions between REV1 and REV2. The changes between the two
6283 revisions must be collapsed, and the result stored in the revision
6284 immediately preceding the lower one. Return 0 for successful completion,
6287 Solution: check out the revision preceding REV1 and the revision
6288 following REV2. Use call_diff to find aggregate diffs between
6289 these two revisions, and replace the delta text for the latter one
6290 with the new aggregate diff. Alternatively, we could write a
6291 function that takes two change texts and combines them to produce a
6292 new change text, without checking out any revs or calling diff. It
6293 would be hairy, but so, so cool.
6295 If INCLUSIVE is set, then TAG1 and TAG2, if non-NULL, tell us to
6296 delete that revision as well (cvs admin -o tag1:tag2). If clear,
6297 delete up to but not including that revision (cvs admin -o tag1::tag2).
6298 This does not affect TAG1 or TAG2 being NULL; the meaning of the start
6299 point in ::tag2 and :tag2 is the same and likewise for end points. */
6302 RCS_delete_revs (rcs, tag1, tag2, inclusive)
6310 RCSVers *revp = NULL;
6315 char *branchpoint = NULL;
6318 int rev1_inclusive = inclusive;
6319 int rev2_inclusive = inclusive;
6320 char *before = NULL;
6322 char *beforefile = NULL;
6323 char *afterfile = NULL;
6324 char *outfile = NULL;
6326 if (tag1 == NULL && tag2 == NULL)
6329 /* Assume error status until everything is finished. */
6332 /* Make sure both revisions exist. */
6335 rev1 = RCS_gettag (rcs, tag1, 1, NULL);
6336 if (rev1 == NULL || (nodep = findnode (rcs->versions, rev1)) == NULL)
6338 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag1);
6344 rev2 = RCS_gettag (rcs, tag2, 1, NULL);
6345 if (rev2 == NULL || (nodep = findnode (rcs->versions, rev2)) == NULL)
6347 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag2);
6352 /* If rev1 is on the trunk and rev2 is NULL, rev2 should be
6353 RCS->HEAD. (*Not* RCS_head(rcs), which may return rcs->branch
6354 instead.) We need to check this special case early, in order
6355 to make sure that rev1 and rev2 get ordered correctly. */
6356 if (rev2 == NULL && numdots (rev1) == 1)
6358 rev2 = xstrdup (rcs->head);
6365 if (rev1 != NULL && rev2 != NULL)
6367 /* A range consisting of a branch number means the latest revision
6369 if (RCS_isbranch (rcs, rev1) && STREQ (rev1, rev2))
6371 char *tmp = RCS_getbranch (rcs, rev1, 0);
6378 /* Make sure REV1 and REV2 are ordered correctly (in the
6379 same order as the next field). For revisions on the
6380 trunk, REV1 should be higher than REV2; for branches,
6381 REV1 should be lower. */
6382 /* Shouldn't we just be giving an error in the case where
6383 the user specifies the revisions in the wrong order
6384 (that is, always swap on the trunk, never swap on a
6385 branch, in the non-error cases)? It is not at all
6386 clear to me that users who specify -o 1.4:1.2 really
6387 meant to type -o 1.2:1.4, and the out of order usage
6388 has never been documented, either by cvs.texinfo or
6392 if (numdots (rev1) == 1)
6394 if (compare_revnums (rev1, rev2) <= 0)
6400 temp_inclusive = rev2_inclusive;
6401 rev2_inclusive = rev1_inclusive;
6402 rev1_inclusive = temp_inclusive;
6405 else if (compare_revnums (rev1, rev2) > 0)
6411 temp_inclusive = rev2_inclusive;
6412 rev2_inclusive = rev1_inclusive;
6413 rev1_inclusive = temp_inclusive;
6418 /* Basically the same thing; make sure that the ordering is what we
6422 assert (rev2 != NULL);
6423 if (numdots (rev2) == 1)
6425 /* Swap rev1 and rev2. */
6431 temp_inclusive = rev2_inclusive;
6432 rev2_inclusive = rev1_inclusive;
6433 rev1_inclusive = temp_inclusive;
6437 /* Put the revision number preceding the first one to delete into
6438 BEFORE (where "preceding" means according to the next field).
6439 If the first revision to delete is the first revision on its
6440 branch (e.g. 1.3.2.1), BEFORE should be the node on the trunk
6441 at which the branch is rooted. If the first revision to delete
6442 is the head revision of the trunk, set BEFORE to NULL.
6444 Note that because BEFORE may not be on the same branch as REV1,
6445 it is not very handy for navigating the revision tree. It's
6446 most useful just for checking out the revision preceding REV1. */
6448 branchpoint = RCS_getbranchpoint (rcs, rev1 != NULL ? rev1 : rev2);
6451 rev1 = xstrdup (branchpoint);
6452 if (numdots (branchpoint) > 1)
6455 bp = strrchr (branchpoint, '.');
6456 while (*--bp != '.')
6459 /* Note that this is exclusive, always, because the inclusive
6460 flag doesn't affect the meaning when rev1 == NULL. */
6461 before = xstrdup (branchpoint);
6465 else if (! STREQ (rev1, branchpoint))
6467 /* Walk deltas from BRANCHPOINT on, looking for REV1. */
6468 nodep = findnode (rcs->versions, branchpoint);
6470 while (revp->next != NULL && ! STREQ (revp->next, rev1))
6473 nodep = findnode (rcs->versions, revp->next);
6475 if (revp->next == NULL)
6477 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, rev1);
6481 before = xstrdup (revp->version);
6485 nodep = findnode (rcs->versions, before);
6486 rev1 = xstrdup (((RCSVers *)nodep->data)->next);
6489 else if (!rev1_inclusive)
6492 nodep = findnode (rcs->versions, before);
6493 rev1 = xstrdup (((RCSVers *)nodep->data)->next);
6495 else if (numdots (branchpoint) > 1)
6497 /* Example: rev1 is "1.3.2.1", branchpoint is "1.3.2.1".
6498 Set before to "1.3". */
6500 bp = strrchr (branchpoint, '.');
6501 while (*--bp != '.')
6504 before = xstrdup (branchpoint);
6508 /* If any revision between REV1 and REV2 is locked or is a branch point,
6509 we can't delete that revision and must abort. */
6513 while (!found && next != NULL)
6515 nodep = findnode (rcs->versions, next);
6519 found = STREQ (revp->version, rev2);
6522 if ((!found && next != NULL) || rev2_inclusive || rev2 == NULL)
6524 if (findnode (RCS_getlocks (rcs), revp->version))
6526 error (0, 0, "%s: can't remove locked revision %s",
6531 if (revp->branches != NULL)
6533 error (0, 0, "%s: can't remove branch point %s",
6539 /* Doing this only for the :: syntax is for compatibility.
6540 See cvs.texinfo for somewhat more discussion. */
6542 (walklist (RCS_symbols (rcs), findtag, revp->version) ||
6543 walklist (RCS_symbols (rcs), findmagictag, revp->version)))
6545 /* We don't print which file this happens to on the theory
6546 that the caller will print the name of the file in a
6547 more useful fashion (fullname not rcs->path). */
6548 error (0, 0, "cannot remove revision %s because it has tags",
6553 /* It's misleading to print the `deleting revision' output
6554 here, since we may not actually delete these revisions.
6555 But that's how RCS does it. Bleah. Someday this should be
6556 moved to the point where the revs are actually marked for
6558 cvs_output ("deleting revision ", 0);
6559 cvs_output (revp->version, 0);
6560 cvs_output ("\n", 1);
6569 after = xstrdup (next);
6571 after = xstrdup (revp->version);
6573 else if (!inclusive)
6575 /* In the case of an empty range, for example 1.2::1.2 or
6576 1.2::1.3, we want to just do nothing. */
6582 /* This looks fishy in the cases where tag1 == NULL or tag2 == NULL.
6583 Are those cases really impossible? */
6584 assert (tag1 != NULL);
6585 assert (tag2 != NULL);
6587 error (0, 0, "%s: invalid revision range %s:%s", rcs->path,
6592 if (after == NULL && before == NULL)
6594 /* The user is trying to delete all revisions. While an
6595 RCS file without revisions makes sense to RCS (e.g. the
6596 state after "rcs -i"), CVS has never been able to cope with
6597 it. So at least for now we just make this an error.
6599 We don't include rcs->path in the message since "cvs admin"
6600 already printed "RCS file:" and the name. */
6601 error (1, 0, "attempt to delete all revisions");
6604 /* The conditionals at this point get really hairy. Here is the
6607 IF before != NULL and after == NULL
6608 THEN don't check out any revisions, just delete them
6609 IF before == NULL and after != NULL
6610 THEN only check out after's revision, and use it for the new deltatext
6612 check out both revisions and diff -n them. This could use
6613 RCS_exec_rcsdiff with some changes, like being able
6614 to suppress diagnostic messages and to direct output. */
6619 size_t bufsize, len;
6621 #if defined (WOE32) && !defined (__CYGWIN32__)
6622 /* FIXME: This is an awful kludge, but at least until I have
6623 time to work on it a little more and test it, I'd rather
6624 give a fatal error than corrupt the file. I think that we
6625 need to use "-kb" and "--binary" and "rb" to get_file
6626 (probably can do it always, not just for binary files, if
6627 we are consistent between the RCS_checkout and the diff). */
6629 char *expand = RCS_getexpand (rcs);
6630 if (expand != NULL && STREQ (expand, "b"))
6632 "admin -o not implemented yet for binary on this system");
6636 afterfile = cvs_temp_name();
6637 status = RCS_checkout (rcs, NULL, after, NULL, "-ko", afterfile,
6638 (RCSCHECKOUTPROC)0, NULL);
6644 /* We are deleting revisions from the head of the tree,
6645 so must create a new head. */
6648 get_file (afterfile, afterfile, "r", &diffbuf, &bufsize, &len);
6650 save_noexec = noexec;
6652 if (unlink_file (afterfile) < 0)
6653 error (0, errno, "cannot remove %s", afterfile);
6654 noexec = save_noexec;
6660 rcs->head = xstrdup (after);
6665 size_t darg_allocated = 0;
6666 char **dargv = NULL;
6668 beforefile = cvs_temp_name();
6669 status = RCS_checkout (rcs, NULL, before, NULL, "-ko", beforefile,
6670 (RCSCHECKOUTPROC)0, NULL);
6674 outfile = cvs_temp_name();
6675 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-a");
6676 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n");
6677 status = diff_exec (beforefile, afterfile, NULL, NULL,
6678 dargc, dargv, outfile);
6679 run_arg_free_p (dargc, dargv);
6684 /* Not sure we need this message; will diff_exec already
6685 have printed an error? */
6686 error (0, 0, "%s: could not diff", rcs->path);
6693 get_file (outfile, outfile, "r", &diffbuf, &bufsize, &len);
6696 /* Save the new change text in after's delta node. */
6697 nodep = findnode (rcs->versions, after);
6700 assert (revp->text == NULL);
6702 revp->text = (Deltatext *) xmalloc (sizeof (Deltatext));
6703 memset ((Deltatext *) revp->text, 0, sizeof (Deltatext));
6704 revp->text->version = xstrdup (revp->version);
6705 revp->text->text = diffbuf;
6706 revp->text->len = len;
6708 /* If DIFFBUF is NULL, it means that OUTFILE is empty and that
6709 there are no differences between the two revisions. In that
6710 case, we want to force RCS_copydeltas to write an empty string
6711 for the new change text (leaving the text field set NULL
6712 means "preserve the original change text for this delta," so
6713 we don't want that). */
6714 if (revp->text->text == NULL)
6715 revp->text->text = xstrdup ("");
6718 /* Walk through the revisions (again) to mark each one as
6719 outdated. (FIXME: would it be safe to use the `dead' field for
6722 next != NULL && (after == NULL || ! STREQ (next, after));
6725 nodep = findnode (rcs->versions, next);
6730 /* Update delta links. If BEFORE == NULL, we're changing the
6731 head of the tree and don't need to update any `next' links. */
6734 /* If REV1 is the first node on its branch, then BEFORE is its
6735 root node (on the trunk) and we have to update its branches
6736 list. Otherwise, BEFORE is on the same branch as AFTER, and
6737 we can just change BEFORE's `next' field to point to AFTER.
6738 (This should be safe: since findnode manages its lists via
6739 the `hashnext' and `hashprev' fields, rather than `next' and
6740 `prev', mucking with `next' and `prev' should not corrupt the
6741 delta tree's internal structure. Much. -twp) */
6744 /* beforep's ->next field already should be equal to after,
6745 which I think is always NULL in this case. */
6747 else if (STREQ (rev1, branchpoint))
6749 nodep = findnode (rcs->versions, before);
6751 nodep = revp->branches->list->next;
6752 while (nodep != revp->branches->list &&
6753 ! STREQ (nodep->key, rev1))
6754 nodep = nodep->next;
6755 assert (nodep != revp->branches->list);
6761 nodep->key = xstrdup (after);
6766 nodep = findnode (rcs->versions, before);
6767 beforep = nodep->data;
6768 free (beforep->next);
6769 beforep->next = xstrdup (after);
6778 if (rev2 && rev2 != rev1)
6780 if (branchpoint != NULL)
6787 save_noexec = noexec;
6789 if (beforefile != NULL)
6791 if (unlink_file (beforefile) < 0)
6792 error (0, errno, "cannot remove %s", beforefile);
6795 if (afterfile != NULL)
6797 if (unlink_file (afterfile) < 0)
6798 error (0, errno, "cannot remove %s", afterfile);
6801 if (outfile != NULL)
6803 if (unlink_file (outfile) < 0)
6804 error (0, errno, "cannot remove %s", outfile);
6807 noexec = save_noexec;
6813 * TRUE if there exists a symbolic tag "tag" in file.
6816 RCS_exist_tag (rcs, tag)
6821 assert (rcs != NULL);
6823 if (findnode (RCS_symbols (rcs), tag))
6830 * TRUE if RCS revision number "rev" exists.
6831 * This includes magic branch revisions, not found in rcs->versions,
6832 * but only in rcs->symbols, requiring a list walk to find them.
6833 * Take advantage of list walk callback function already used by
6834 * RCS_delete_revs, above.
6837 RCS_exist_rev (rcs, rev)
6842 assert (rcs != NULL);
6844 if (rcs->flags & PARTIAL)
6845 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6847 if (findnode(rcs->versions, rev) != 0)
6850 if (walklist (RCS_symbols(rcs), findtag, rev) != 0)
6858 /* RCS_deltas and friends. Processing of the deltas in RCS files. */
6862 /* Text of this line. Part of the same malloc'd block as the struct
6863 line itself (we probably should use the "struct hack" (char text[1])
6864 and save ourselves sizeof (char *) bytes). Does not include \n;
6865 instead has_newline indicates the presence or absence of \n. */
6867 /* Length of this line, not counting \n if has_newline is true. */
6869 /* Version in which it was introduced. */
6871 /* Nonzero if this line ends with \n. This will always be true
6872 except possibly for the last line. */
6874 /* Number of pointers to this struct line. */
6880 /* How many lines in use for this linevector? */
6881 unsigned int nlines;
6882 /* How many lines allocated for this linevector? */
6883 unsigned int lines_alloced;
6884 /* Pointer to array containing a pointer to each line. */
6885 struct line **vector;
6888 static void linevector_init PROTO ((struct linevector *));
6890 /* Initialize *VEC to be a linevector with no lines. */
6892 linevector_init (vec)
6893 struct linevector *vec;
6895 vec->lines_alloced = 0;
6900 static int linevector_add PROTO ((struct linevector *vec, const char *text,
6901 size_t len, RCSVers *vers,
6904 /* Given some text TEXT, add each of its lines to VEC before line POS
6905 (where line 0 is the first line). The last line in TEXT may or may
6906 not be \n terminated.
6907 Set the version for each of the new lines to VERS. This
6908 function returns non-zero for success. It returns zero if the line
6909 number is out of range.
6911 Each of the lines in TEXT are copied to space which is managed with
6912 the linevector (and freed by linevector_free). So the caller doesn't
6913 need to keep TEXT around after the call to this function. */
6915 linevector_add (vec, text, len, vers, pos)
6916 struct linevector *vec;
6922 const char *textend;
6926 const char *nextline_text;
6927 size_t nextline_len;
6928 int nextline_newline;
6934 textend = text + len;
6936 /* Count the number of lines we will need to add. */
6938 for (p = text; p < textend; ++p)
6939 if (*p == '\n' && p + 1 < textend)
6942 /* Expand VEC->VECTOR if needed. */
6943 if (vec->nlines + nnew >= vec->lines_alloced)
6945 if (vec->lines_alloced == 0)
6946 vec->lines_alloced = 10;
6947 while (vec->nlines + nnew >= vec->lines_alloced)
6948 vec->lines_alloced *= 2;
6949 vec->vector = xrealloc (vec->vector,
6950 vec->lines_alloced * sizeof (*vec->vector));
6953 /* Make room for the new lines in VEC->VECTOR. */
6954 for (i = vec->nlines + nnew - 1; i >= pos + nnew; --i)
6955 vec->vector[i] = vec->vector[i - nnew];
6957 if (pos > vec->nlines)
6960 /* Actually add the lines, to VEC->VECTOR. */
6962 nextline_text = text;
6963 nextline_newline = 0;
6964 for (p = text; p < textend; ++p)
6967 nextline_newline = 1;
6968 if (p + 1 == textend)
6969 /* If there are no characters beyond the last newline, we
6970 don't consider it another line. */
6972 nextline_len = p - nextline_text;
6973 q = (struct line *) xmalloc (sizeof (struct line) + nextline_len);
6975 q->text = (char *)q + sizeof (struct line);
6976 q->len = nextline_len;
6977 q->has_newline = nextline_newline;
6979 memcpy (q->text, nextline_text, nextline_len);
6980 vec->vector[i++] = q;
6982 nextline_text = (char *)p + 1;
6983 nextline_newline = 0;
6985 nextline_len = p - nextline_text;
6986 q = (struct line *) xmalloc (sizeof (struct line) + nextline_len);
6988 q->text = (char *)q + sizeof (struct line);
6989 q->len = nextline_len;
6990 q->has_newline = nextline_newline;
6992 memcpy (q->text, nextline_text, nextline_len);
6995 vec->nlines += nnew;
7000 static void linevector_copy PROTO ((struct linevector *, struct linevector *));
7002 /* Copy FROM to TO, copying the vectors but not the lines pointed to. */
7004 linevector_copy (to, from)
7005 struct linevector *to;
7006 struct linevector *from;
7010 for (ln = 0; ln < to->nlines; ++ln)
7012 if (--to->vector[ln]->refcount == 0)
7013 free (to->vector[ln]);
7015 if (from->nlines > to->lines_alloced)
7017 if (to->lines_alloced == 0)
7018 to->lines_alloced = 10;
7019 while (from->nlines > to->lines_alloced)
7020 to->lines_alloced *= 2;
7021 to->vector = (struct line **)
7022 xrealloc (to->vector, to->lines_alloced * sizeof (*to->vector));
7024 memcpy (to->vector, from->vector,
7025 from->nlines * sizeof (*to->vector));
7026 to->nlines = from->nlines;
7027 for (ln = 0; ln < to->nlines; ++ln)
7028 ++to->vector[ln]->refcount;
7031 static void linevector_free PROTO ((struct linevector *));
7033 /* Free storage associated with linevector. */
7035 linevector_free (vec)
7036 struct linevector *vec;
7040 if (vec->vector != NULL)
7042 for (ln = 0; ln < vec->nlines; ++ln)
7043 if (vec->vector[ln] && --vec->vector[ln]->refcount == 0)
7044 free (vec->vector[ln]);
7050 static char *month_printname PROTO ((char *));
7052 /* Given a textual string giving the month (1-12), terminated with any
7053 character not recognized by atoi, return the 3 character name to
7054 print it with. I do not think it is a good idea to change these
7055 strings based on the locale; they are standard abbreviations (for
7056 example in rfc822 mail messages) which should be widely understood.
7057 Returns a pointer into static readonly storage. */
7059 month_printname (month)
7062 static const char *const months[] =
7063 {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
7064 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
7067 mnum = atoi (month);
7068 if (mnum < 1 || mnum > 12)
7070 return (char *)months[mnum - 1];
7074 apply_rcs_changes PROTO ((struct linevector *, const char *, size_t,
7075 const char *, RCSVers *, RCSVers *));
7077 /* Apply changes to the line vector LINES. DIFFBUF is a buffer of
7078 * length DIFFLEN holding the change text from an RCS file (the output
7079 * of diff -n). NAME is used in error messages. The VERS field of
7080 * any line added is set to ADDVERS. The VERS field of any line
7081 * deleted is set to DELVERS, unless DELVERS is NULL, in which case
7082 * the VERS field of deleted lines is unchanged.
7085 * Non-zero if the change text is applied successfully to ORIG_LINES.
7087 * If the change text does not appear to apply to ORIG_LINES (e.g., a
7088 * line number is invalid), this function will return zero and ORIG_LINES
7089 * will remain unmolested.
7092 * If the change text is improperly formatted (e.g., it is not the output
7093 * of diff -n), the function calls error with a status of 1, causing the
7097 apply_rcs_changes (orig_lines, diffbuf, difflen, name, addvers, delvers)
7098 struct linevector *orig_lines;
7099 const char *diffbuf;
7108 /* The RCS format throws us for a loop in that the deltafrags (if
7109 we define a deltafrag as an add or a delete) need to be applied
7110 in reverse order. So we stick them into a linked list. */
7112 enum {FRAG_ADD, FRAG_DELETE} type;
7114 unsigned long nlines;
7115 const char *new_lines;
7117 struct deltafrag *next;
7119 struct deltafrag *dfhead;
7120 struct deltafrag **dftail;
7121 struct deltafrag *df;
7122 unsigned long numlines, lastmodline, offset;
7123 struct linevector lines;
7128 numlines = orig_lines->nlines; /* start with init # of lines */
7129 for (p = diffbuf; p != NULL && p < diffbuf + difflen; )
7132 if (op != 'a' && op != 'd')
7133 /* Can't just skip over the deltafrag, because the value
7134 of op determines the syntax. */
7135 error (1, 0, "unrecognized operation '\\x%x' in %s",
7137 *dftail = df = xmalloc (sizeof *df);
7138 *(dftail = &df->next) = NULL;
7140 df->pos = strtoul (p, (char **) &q, 10);
7143 error (1, 0, "number expected in %s", name);
7146 error (1, 0, "space expected in %s", name);
7147 df->nlines = strtoul (p, (char **) &q, 10);
7149 error (1, 0, "number expected in %s", name);
7152 error (1, 0, "linefeed expected in %s", name);
7158 df->type = FRAG_ADD;
7160 /* The text we want is the number of lines specified, or
7161 until the end of the value, whichever comes first (it
7162 will be the former except in the case where we are
7163 adding a line which does not end in newline). */
7164 for (q = p; i != 0; ++q)
7167 else if (q == diffbuf + difflen)
7170 error (1, 0, "premature end of change in %s", name);
7175 /* Stash away a pointer to the text we are adding. */
7180 numlines += df->nlines;
7184 /* Correct for the fact that line numbers in RCS files
7189 df->type = FRAG_DELETE;
7190 numlines -= df->nlines;
7194 /* New temp data structure to hold new org before
7195 copy back into original structure. */
7196 lines.nlines = lines.lines_alloced = numlines;
7197 lines.vector = xmalloc (numlines * sizeof *lines.vector);
7199 /* We changed the list order to first to last -- so the
7200 list never gets larger than the size numlines. */
7203 /* offset created when adding/removing lines
7204 between new and original structure */
7207 for (df = dfhead; df != NULL; )
7210 unsigned long deltaend;
7212 if (df->pos > orig_lines->nlines)
7215 /* On error, just free the rest of the list. */
7218 /* Here we need to get to the line where the next insert will
7219 begin, which is DF->pos in ORIG_LINES. We will fill up to
7220 DF->pos - OFFSET in LINES with original items. */
7221 for (deltaend = df->pos - offset;
7222 lastmodline < deltaend;
7225 /* we need to copy from the orig structure into new one */
7226 lines.vector[lastmodline] =
7227 orig_lines->vector[lastmodline + offset];
7228 lines.vector[lastmodline]->refcount++;
7235 const char *textend, *p;
7236 const char *nextline_text;
7238 int nextline_newline;
7239 size_t nextline_len;
7241 textend = df->new_lines + df->len;
7242 nextline_newline = 0;
7243 nextline_text = df->new_lines;
7244 for (p = df->new_lines; p < textend; ++p)
7248 nextline_newline = 1;
7249 if (p + 1 == textend)
7251 /* If there are no characters beyond the
7252 last newline, we don't consider it
7257 nextline_len = p - nextline_text;
7258 q = xmalloc (sizeof *q + nextline_len);
7260 q->text = (char *)(q + 1);
7261 q->len = nextline_len;
7262 q->has_newline = nextline_newline;
7264 memcpy (q->text, nextline_text, nextline_len);
7265 lines.vector[lastmodline++] = q;
7268 nextline_text = (char *)p + 1;
7269 nextline_newline = 0;
7272 nextline_len = p - nextline_text;
7273 q = xmalloc (sizeof *q + nextline_len);
7275 q->text = (char *)(q + 1);
7276 q->len = nextline_len;
7277 q->has_newline = nextline_newline;
7279 memcpy (q->text, nextline_text, nextline_len);
7280 lines.vector[lastmodline++] = q;
7282 /* For each line we add the offset between the #'s
7289 /* we are removing this many lines from the source. */
7290 offset += df->nlines;
7292 if (df->pos + df->nlines > orig_lines->nlines)
7295 for (ln = df->pos; ln < df->pos + df->nlines; ++ln)
7296 if (orig_lines->vector[ln]->refcount > 1)
7297 /* Annotate needs this but, since the original
7298 * vector is disposed of before returning from
7299 * this function, we only need keep track if
7300 * there are multiple references.
7302 orig_lines->vector[ln]->vers = delvers;
7314 /* No reason to try and move a half-mutated and known invalid
7315 * text into the output buffer.
7317 linevector_free (&lines);
7321 /* add the rest of the remaining lines to the data vector */
7322 for (; lastmodline < numlines; lastmodline++)
7324 /* we need to copy from the orig structure into new one */
7325 lines.vector[lastmodline] = orig_lines->vector[lastmodline
7327 lines.vector[lastmodline]->refcount++;
7330 /* Move the lines vector to the original structure for output,
7331 * first deleting the old.
7333 linevector_free (orig_lines);
7334 orig_lines->vector = lines.vector;
7335 orig_lines->lines_alloced = numlines;
7336 orig_lines->nlines = lines.nlines;
7342 /* Apply an RCS change text to a buffer. The function name starts
7343 with rcs rather than RCS because this does not take an RCSNode
7344 argument. NAME is used in error messages. TEXTBUF is the text
7345 buffer to change, and TEXTLEN is the size. DIFFBUF and DIFFLEN are
7346 the change buffer and size. The new buffer is returned in *RETBUF
7347 and *RETLEN. The new buffer is allocated by xmalloc.
7349 Return 1 for success. On failure, call error and return 0. */
7352 rcs_change_text (name, textbuf, textlen, diffbuf, difflen, retbuf, retlen)
7356 const char *diffbuf;
7361 struct linevector lines;
7367 linevector_init (&lines);
7369 if (! linevector_add (&lines, textbuf, textlen, NULL, 0))
7370 error (1, 0, "cannot initialize line vector");
7372 if (! apply_rcs_changes (&lines, diffbuf, difflen, name, NULL, NULL))
7374 error (0, 0, "invalid change text in %s", name);
7384 for (ln = 0; ln < lines.nlines; ++ln)
7386 n += lines.vector[ln]->len + 1;
7391 for (ln = 0; ln < lines.nlines; ++ln)
7393 memcpy (p, lines.vector[ln]->text, lines.vector[ln]->len);
7394 p += lines.vector[ln]->len;
7395 if (lines.vector[ln]->has_newline)
7399 *retlen = p - *retbuf;
7400 assert (*retlen <= n);
7405 linevector_free (&lines);
7410 /* Walk the deltas in RCS to get to revision VERSION.
7412 If OP is RCS_ANNOTATE, then write annotations using cvs_output.
7414 If OP is RCS_FETCH, then put the contents of VERSION into a
7415 newly-malloc'd array and put a pointer to it in *TEXT. Each line
7416 is \n terminated; the caller is responsible for converting text
7417 files if desired. The total length is put in *LEN.
7419 If FP is non-NULL, it should be a file descriptor open to the file
7420 RCS with file position pointing to the deltas. We close the file
7423 If LOG is non-NULL, then *LOG is set to the log message of VERSION,
7424 and *LOGLEN is set to the length of the log message.
7426 On error, give a fatal error. */
7429 RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
7432 struct rcsbuffer *rcsbuf;
7433 const char *version;
7434 enum rcs_delta_op op;
7440 struct rcsbuffer rcsbuf_local;
7441 char *branchversion;
7448 RCSVers *trunk_vers;
7450 int ishead, isnext, isversion, onbranch;
7452 struct linevector headlines;
7453 struct linevector curlines;
7454 struct linevector trunklines;
7461 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf_local);
7462 rcsbuf = &rcsbuf_local;
7467 if (log) *log = NULL;
7477 linevector_init (&curlines);
7478 linevector_init (&headlines);
7479 linevector_init (&trunklines);
7481 /* We set BRANCHVERSION to the version we are currently looking
7482 for. Initially, this is the version on the trunk from which
7483 VERSION branches off. If VERSION is not a branch, then
7484 BRANCHVERSION is just VERSION. */
7485 branchversion = xstrdup (version);
7486 cpversion = strchr (branchversion, '.');
7487 if (cpversion != NULL)
7488 cpversion = strchr (cpversion + 1, '.');
7489 if (cpversion != NULL)
7493 if (! rcsbuf_getrevnum (rcsbuf, &key))
7494 error (1, 0, "unexpected EOF reading RCS file %s", rcs->path);
7496 /* look up the revision */
7497 node = findnode (rcs->versions, key);
7500 "Delta text %s without revision information in `%s'.",
7503 if (next != NULL && ! STREQ (next, key))
7505 /* This is not the next version we need. It is a branch
7506 version which we want to ignore. */
7514 /* Stash the previous version. */
7520 /* Compare key and trunkversion now, because key points to
7521 storage controlled by rcsbuf_getkey. */
7522 if (STREQ (branchversion, key))
7530 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7531 error (1, 0, "%s does not appear to be a valid rcs file",
7536 && STREQ (key, "log")
7537 && STREQ (branchversion, version))
7541 error (0, 0, "Duplicate `log' keyword in RCS file (`%s').",
7545 *log = rcsbuf_valcopy (rcsbuf, value, 0, loglen);
7548 if (STREQ (key, "text"))
7550 rcsbuf_valpolish (rcsbuf, value, 0, &vallen);
7553 if (! linevector_add (&curlines, value, vallen, NULL, 0))
7554 error (1, 0, "invalid rcs file %s", rcs->path);
7560 if (! apply_rcs_changes (&curlines, value, vallen,
7562 onbranch ? vers : NULL,
7563 onbranch ? NULL : prev_vers))
7564 error (1, 0, "invalid change text in %s", rcs->path);
7572 /* This is either the version we want, or it is the
7573 branchpoint to the version we want. */
7574 if (STREQ (branchversion, version))
7576 /* This is the version we want. */
7577 linevector_copy (&headlines, &curlines);
7581 /* We have found this version by tracking up a
7582 branch. Restore back to the lines we saved
7583 when we left the trunk, and continue tracking
7588 linevector_copy (&curlines, &trunklines);
7595 /* We need to look up the branch. */
7598 if (numdots (branchversion) < 2)
7602 /* We are leaving the trunk; save the current
7603 lines so that we can restore them when we
7604 continue tracking down the trunk. */
7606 linevector_copy (&trunklines, &curlines);
7608 /* Reset the version information we have
7609 accumulated so far. It only applies to the
7610 changes from the head to this version. */
7611 for (ln = 0; ln < curlines.nlines; ++ln)
7612 curlines.vector[ln]->vers = NULL;
7615 /* The next version we want is the entry on
7616 VERS->branches which matches this branch. For
7617 example, suppose VERSION is 1.21.4.3 and
7618 BRANCHVERSION was 1.21. Then we look for an entry
7619 starting with "1.21.4" and we'll put it (probably
7620 1.21.4.1) in NEXT. We'll advance BRANCHVERSION by
7621 two dots (in this example, to 1.21.4.3). */
7623 if (vers->branches == NULL)
7624 error (1, 0, "missing expected branches in %s",
7627 error (1, 0, "Invalid revision number in `%s'.",
7631 cpversion = strchr (cpversion, '.');
7632 if (cpversion == NULL)
7633 error (1, 0, "version number confusion in %s",
7635 for (p = vers->branches->list->next;
7636 p != vers->branches->list;
7638 if (strncmp (p->key, branchversion,
7639 cpversion - branchversion) == 0)
7641 if (p == vers->branches->list)
7642 error (1, 0, "missing expected branch in %s",
7647 cpversion = strchr (cpversion + 1, '.');
7648 if (cpversion != NULL)
7652 if (op == RCS_FETCH && foundhead)
7654 } while (next != NULL);
7656 free (branchversion);
7658 rcsbuf_cache (rcs, rcsbuf);
7661 error (1, 0, "could not find desired version %s in %s",
7662 version, rcs->path);
7664 /* Now print out or return the data we have just computed. */
7671 for (ln = 0; ln < headlines.nlines; ++ln)
7674 /* Period which separates year from month in date. */
7676 /* Period which separates month from day in date. */
7680 prvers = headlines.vector[ln]->vers;
7684 buf = xmalloc (strlen (prvers->version) + 24);
7685 sprintf (buf, "%-12s (%-8.8s ",
7688 cvs_output (buf, 0);
7691 /* Now output the date. */
7692 ym = strchr (prvers->date, '.');
7695 /* ??- is an ANSI trigraph. The ANSI way to
7696 avoid it is \? but some pre ANSI compilers
7697 complain about the unrecognized escape
7698 sequence. Of course string concatenation
7699 ("??" "-???") is also an ANSI-ism. Testing
7700 __STDC__ seems to be a can of worms, since
7701 compilers do all kinds of things with it. */
7702 cvs_output ("??", 0);
7703 cvs_output ("-???", 0);
7704 cvs_output ("-??", 0);
7708 md = strchr (ym + 1, '.');
7710 cvs_output ("??", 0);
7712 cvs_output (md + 1, 2);
7714 cvs_output ("-", 1);
7715 cvs_output (month_printname (ym + 1), 0);
7716 cvs_output ("-", 1);
7717 /* Only output the last two digits of the year. Our output
7718 lines are long enough as it is without printing the
7720 cvs_output (ym - 2, 2);
7722 cvs_output ("): ", 0);
7723 if (headlines.vector[ln]->len != 0)
7724 cvs_output (headlines.vector[ln]->text,
7725 headlines.vector[ln]->len);
7726 cvs_output ("\n", 1);
7736 assert (text != NULL);
7737 assert (len != NULL);
7740 for (ln = 0; ln < headlines.nlines; ++ln)
7742 n += headlines.vector[ln]->len + 1;
7745 for (ln = 0; ln < headlines.nlines; ++ln)
7747 memcpy (p, headlines.vector[ln]->text,
7748 headlines.vector[ln]->len);
7749 p += headlines.vector[ln]->len;
7750 if (headlines.vector[ln]->has_newline)
7759 linevector_free (&curlines);
7760 linevector_free (&headlines);
7761 linevector_free (&trunklines);
7766 /* Read the information for a single delta from the RCS buffer RCSBUF,
7767 whose name is RCSFILE. *KEYP and *VALP are either NULL, or the
7768 first key/value pair to read, as set by rcsbuf_getkey. Return NULL
7769 if there are no more deltas. Store the key/value pair which
7770 terminated the read in *KEYP and *VALP. */
7773 getdelta (rcsbuf, rcsfile, keyp, valp)
7774 struct rcsbuffer *rcsbuf;
7780 char *key, *value, *cp;
7783 /* Get revision number if it wasn't passed in. This uses
7784 rcsbuf_getkey because it doesn't croak when encountering
7785 unexpected input. As a result, we have to play unholy games
7786 with `key' and `value'. */
7794 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7795 error (1, 0, "%s: unexpected EOF", rcsfile);
7798 /* Make sure that it is a revision number and not a cabbage
7801 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
7804 /* Note that when comparing with RCSDATE, we are not massaging
7805 VALUE from the string found in the RCS file. This is OK since
7806 we know exactly what to expect. */
7807 if (*cp != '\0' || strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) != 0)
7814 vnode = (RCSVers *) xmalloc (sizeof (RCSVers));
7815 memset (vnode, 0, sizeof (RCSVers));
7817 vnode->version = xstrdup (key);
7819 /* Grab the value of the date from value. Note that we are not
7820 massaging VALUE from the string found in the RCS file. */
7821 cp = value + (sizeof RCSDATE) - 1; /* skip the "date" keyword */
7822 while (whitespace (*cp)) /* take space off front of value */
7825 vnode->date = xstrdup (cp);
7827 /* Get author field. */
7828 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7830 error (1, 0, "unexpected end of file reading %s", rcsfile);
7832 if (! STREQ (key, "author"))
7834 unable to parse %s; `author' not in the expected place", rcsfile);
7835 vnode->author = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7837 /* Get state field. */
7838 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7840 error (1, 0, "unexpected end of file reading %s", rcsfile);
7842 if (! STREQ (key, "state"))
7844 unable to parse %s; `state' not in the expected place", rcsfile);
7845 vnode->state = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7846 /* The value is optional, according to rcsfile(5). */
7847 if (value != NULL && STREQ (value, RCSDEAD))
7852 /* Note that "branches" and "next" are in fact mandatory, according
7855 /* fill in the branch list (if any branches exist) */
7856 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7858 error (1, 0, "unexpected end of file reading %s", rcsfile);
7860 if (STREQ (key, RCSDESC))
7864 /* Probably could/should be a fatal error. */
7865 error (0, 0, "warning: 'branches' keyword missing from %s", rcsfile);
7868 if (value != (char *) NULL)
7870 vnode->branches = getlist ();
7871 /* Note that we are not massaging VALUE from the string found
7873 do_branches (vnode->branches, value);
7876 /* fill in the next field if there is a next revision */
7877 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7879 error (1, 0, "unexpected end of file reading %s", rcsfile);
7881 if (STREQ (key, RCSDESC))
7885 /* Probably could/should be a fatal error. */
7886 error (0, 0, "warning: 'next' keyword missing from %s", rcsfile);
7889 if (value != (char *) NULL)
7890 vnode->next = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7893 * XXX - this is where we put the symbolic link stuff???
7894 * (into newphrases in the deltas).
7898 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7899 error (1, 0, "unexpected end of file reading %s", rcsfile);
7901 /* The `desc' keyword is the end of the deltas. */
7902 if (strcmp (key, RCSDESC) == 0)
7905 #ifdef PRESERVE_PERMISSIONS_SUPPORT
7907 /* The `hardlinks' value is a group of words, which must
7908 be parsed separately and added as a list to vnode->hardlinks. */
7909 if (strcmp (key, "hardlinks") == 0)
7913 vnode->hardlinks = getlist();
7914 while ((word = rcsbuf_valword (rcsbuf, &value)) != NULL)
7916 Node *n = getnode();
7918 addnode (vnode->hardlinks, n);
7924 /* Enable use of repositories created by certain obsolete
7925 versions of CVS. This code should remain indefinately;
7926 there is no procedure for converting old repositories, and
7927 checking for it is harmless. */
7928 if (STREQ (key, RCSDEAD))
7931 if (vnode->state != NULL)
7932 free (vnode->state);
7933 vnode->state = xstrdup (RCSDEAD);
7936 /* if we have a new revision number, we're done with this delta */
7938 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
7941 /* Note that when comparing with RCSDATE, we are not massaging
7942 VALUE from the string found in the RCS file. This is OK
7943 since we know exactly what to expect. */
7944 if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0)
7947 /* At this point, key and value represent a user-defined field
7948 in the delta node. */
7949 if (vnode->other_delta == NULL)
7950 vnode->other_delta = getlist ();
7952 kv->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
7953 kv->key = xstrdup (key);
7954 kv->data = rcsbuf_valcopy (rcsbuf, value, kv->type == RCSFIELD,
7956 if (addnode (vnode->other_delta, kv) != 0)
7958 /* Complaining about duplicate keys in newphrases seems
7959 questionable, in that we don't know what they mean and
7960 doc/RCSFILES has no prohibition on several newphrases
7961 with the same key. But we can't store more than one as
7962 long as we store them in a List *. */
7963 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
7969 /* Return the key which caused us to fail back to the caller. */
7980 if (d->version != NULL)
7984 if (d->text != NULL)
7986 if (d->other != (List *) NULL)
7987 dellist (&d->other);
7992 RCS_getdeltatext (rcs, fp, rcsbuf)
7995 struct rcsbuffer *rcsbuf;
8002 /* Get the revision number. */
8003 if (! rcsbuf_getrevnum (rcsbuf, &num))
8005 /* If num == NULL, it means we reached EOF naturally. That's
8010 error (1, 0, "%s: unexpected EOF", rcs->path);
8013 p = findnode (rcs->versions, num);
8016 "Delta text %s without revision information in `%s'.",
8019 d = (Deltatext *) xmalloc (sizeof (Deltatext));
8020 d->version = xstrdup (num);
8022 /* Get the log message. */
8023 if (! rcsbuf_getkey (rcsbuf, &key, &value))
8024 error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num);
8025 if (! STREQ (key, "log"))
8026 error (1, 0, "%s, delta %s: expected `log', got `%s'",
8027 rcs->path, num, key);
8028 d->log = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
8030 /* Get random newphrases. */
8031 d->other = getlist();
8034 if (! rcsbuf_getkey (rcsbuf, &key, &value))
8035 error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num);
8037 if (STREQ (key, "text"))
8041 p->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
8042 p->key = xstrdup (key);
8043 p->data = rcsbuf_valcopy (rcsbuf, value, p->type == RCSFIELD,
8045 if (addnode (d->other, p) < 0)
8047 error (0, 0, "warning: %s, delta %s: duplicate field `%s'",
8048 rcs->path, num, key);
8052 /* Get the change text. We already know that this key is `text'. */
8053 d->text = rcsbuf_valcopy (rcsbuf, value, 0, &d->len);
8058 /* RCS output functions, for writing RCS format files from RCSNode
8061 For most of this work, RCS 5.7 uses an `aprintf' function which aborts
8062 program upon error. Instead, these functions check the output status
8063 of the stream right before closing it, and aborts if an error condition
8064 is found. The RCS solution is probably the better one: it produces
8065 more overhead, but will produce a clearer diagnostic in the case of
8066 catastrophic error. In either case, however, the repository will probably
8067 not get corrupted. */
8070 putsymbol_proc (symnode, fparg)
8074 FILE *fp = (FILE *) fparg;
8076 /* A fiddly optimization: this code used to just call fprintf, but
8077 in an old repository with hundreds of tags this can get called
8078 hundreds of thousands of times when doing a cvs tag. Since
8079 tagging is a relatively common operation, and using putc and
8080 fputs is just as comprehensible, the change is worthwhile. */
8083 fputs (symnode->key, fp);
8085 fputs (symnode->data, fp);
8089 static int putlock_proc PROTO ((Node *, void *));
8091 /* putlock_proc is like putsymbol_proc, but key and data are reversed. */
8094 putlock_proc (symnode, fp)
8098 return fprintf ((FILE *) fp, "\n\t%s:%s", (char *)symnode->data, symnode->key);
8102 putrcsfield_proc (node, vfp)
8106 FILE *fp = (FILE *) vfp;
8108 /* Some magic keys used internally by CVS start with `;'. Skip them. */
8109 if (node->key[0] == ';')
8112 fprintf (fp, "\n%s\t", node->key);
8113 if (node->data != NULL)
8115 /* If the field's value contains evil characters,
8116 it must be stringified. */
8117 /* FIXME: This does not quite get it right. "7jk8f" is not a legal
8118 value for a value in a newpharse, according to doc/RCSFILES,
8119 because digits are not valid in an "id". We might do OK by
8120 always writing strings (enclosed in @@). Would be nice to
8121 explicitly mention this one way or another in doc/RCSFILES.
8122 A case where we are wrong in a much more clear-cut way is that
8123 we let through non-graphic characters such as whitespace and
8124 control characters. */
8126 if (node->type == RCSCMPFLD || strpbrk (node->data, "$,.:;@") == NULL)
8127 fputs (node->data, fp);
8131 expand_at_signs (node->data, (off_t) strlen (node->data), fp);
8136 /* desc, log and text fields should not be terminated with semicolon;
8137 all other fields should be. */
8138 if (! STREQ (node->key, "desc") &&
8139 ! STREQ (node->key, "log") &&
8140 ! STREQ (node->key, "text"))
8147 #ifdef PRESERVE_PERMISSIONS_SUPPORT
8149 /* Save a filename in a `hardlinks' RCS field. NODE->KEY will contain
8150 a full pathname, but currently only basenames are stored in the RCS
8151 node. Assume that the filename includes nasty characters and
8155 puthardlink_proc (node, vfp)
8159 FILE *fp = (FILE *) vfp;
8160 char *basename = strrchr (node->key, '/');
8162 if (basename == NULL)
8163 basename = node->key;
8169 (void) expand_at_signs (basename, strlen (basename), fp);
8177 /* Output the admin node for RCS into stream FP. */
8180 RCS_putadmin (rcs, fp)
8184 fprintf (fp, "%s\t%s;\n", RCSHEAD, rcs->head ? rcs->head : "");
8186 fprintf (fp, "%s\t%s;\n", RCSBRANCH, rcs->branch);
8188 fputs ("access", fp);
8192 s = xstrdup (rcs->access);
8193 for (p = strtok (s, " \n\t"); p != NULL; p = strtok (NULL, " \n\t"))
8194 fprintf (fp, "\n\t%s", p);
8199 fputs (RCSSYMBOLS, fp);
8200 /* If we haven't had to convert the symbols to a list yet, don't
8201 force a conversion now; just write out the string. */
8202 if (rcs->symbols == NULL && rcs->symbols_data != NULL)
8205 fputs (rcs->symbols_data, fp);
8208 walklist (RCS_symbols (rcs), putsymbol_proc, (void *) fp);
8211 fputs ("locks", fp);
8212 if (rcs->locks_data)
8213 fprintf (fp, "\t%s", rcs->locks_data);
8214 else if (rcs->locks)
8215 walklist (rcs->locks, putlock_proc, (void *) fp);
8216 if (rcs->strict_locks)
8217 fprintf (fp, "; strict");
8222 fprintf (fp, "comment\t@");
8223 expand_at_signs (rcs->comment, (off_t) strlen (rcs->comment), fp);
8226 if (rcs->expand && ! STREQ (rcs->expand, "kv"))
8227 fprintf (fp, "%s\t@%s@;\n", RCSEXPAND, rcs->expand);
8229 walklist (rcs->other, putrcsfield_proc, (void *) fp);
8241 /* Skip if no revision was supplied, or if it is outdated (cvs admin -o) */
8242 if (vers == NULL || vers->outdated)
8245 fprintf (fp, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches",
8247 RCSDATE, vers->date,
8248 "author", vers->author,
8249 "state", vers->state ? vers->state : "");
8251 if (vers->branches != NULL)
8253 start = vers->branches->list;
8254 for (bp = start->next; bp != start; bp = bp->next)
8255 fprintf (fp, "\n\t%s", bp->key);
8258 fprintf (fp, ";\nnext\t%s;", vers->next ? vers->next : "");
8260 walklist (vers->other_delta, putrcsfield_proc, fp);
8262 #ifdef PRESERVE_PERMISSIONS_SUPPORT
8263 if (vers->hardlinks)
8265 fprintf (fp, "\nhardlinks");
8266 walklist (vers->hardlinks, puthardlink_proc, fp);
8274 RCS_putdtree (rcs, rev, fp)
8282 /* Previously, this function used a recursive implementation, but
8283 if the trunk has a huge number of revisions and the program
8284 stack is not big, a stack overflow could occur, so this
8285 nonrecursive version was developed to be more safe. */
8286 Node *branchlist, *onebranch;
8288 List *onebranchlist;
8293 branches = getlist();
8295 for (; rev != NULL;)
8297 /* Find the delta node for this revision. */
8298 p = findnode (rcs->versions, rev);
8302 "error parsing repository file %s, file may be corrupt.",
8308 /* Print the delta node and go for its `next' node. This
8309 prints the trunk. If there are any branches printed on this
8310 revision, mark we have some. */
8311 putdelta (versp, fp);
8312 /* Store branch information into branch list so to write its
8314 if (versp->branches != NULL)
8317 branch->data = versp->branches;
8319 addnode(branches, branch);
8325 /* If there are any branches printed on this revision,
8326 print those trunks as well. */
8327 branchlist = branches->list;
8328 for (branch = branchlist->next;
8329 branch != branchlist;
8330 branch = branch->next)
8332 onebranchlist = (List *)(branch->data);
8333 onebranch = onebranchlist->list;
8334 for (p = onebranch->next; p != onebranch; p = p->next)
8335 RCS_putdtree (rcs, p->key, fp);
8337 branch->data = NULL; /* so to prevent its freeing on dellist */
8344 RCS_putdesc (rcs, fp)
8348 fprintf (fp, "\n\n%s\n@", RCSDESC);
8349 if (rcs->desc != NULL)
8351 off_t len = (off_t) strlen (rcs->desc);
8354 expand_at_signs (rcs->desc, len, fp);
8355 if (rcs->desc[len-1] != '\n')
8363 putdeltatext (fp, d)
8367 fprintf (fp, "\n\n%s\nlog\n@", d->version);
8370 int loglen = strlen (d->log);
8371 expand_at_signs (d->log, (off_t) loglen, fp);
8372 if (d->log[loglen-1] != '\n')
8377 walklist (d->other, putrcsfield_proc, fp);
8379 fputs ("\ntext\n@", fp);
8380 if (d->text != NULL)
8381 expand_at_signs (d->text, (off_t) d->len, fp);
8385 /* TODO: the whole mechanism for updating deltas is kludgey... more
8386 sensible would be to supply all the necessary info in a `newdeltatext'
8387 field for RCSVers nodes. -twp */
8389 /* Copy delta text nodes from FIN to FOUT. If NEWDTEXT is non-NULL, it
8390 is a new delta text node, and should be added to the tree at the
8391 node whose revision number is INSERTPT. (Note that trunk nodes are
8392 written in decreasing order, and branch nodes are written in
8393 increasing order.) */
8396 RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt)
8399 struct rcsbuffer *rcsbufin;
8401 Deltatext *newdtext;
8407 int insertbefore, found;
8414 /* Count the number of versions for which we have to do some
8415 special operation. */
8416 actions = walklist (rcs->versions, count_delta_actions, (void *) NULL);
8418 /* Make a note of whether NEWDTEXT should be inserted
8419 before or after its INSERTPT. */
8420 insertbefore = (newdtext != NULL && numdots (newdtext->version) == 1);
8422 while (actions != 0 || newdtext != NULL)
8426 dtext = RCS_getdeltatext (rcs, fin, rcsbufin);
8428 /* We shouldn't hit EOF here, because that would imply that
8429 some action was not taken, or that we could not insert
8432 error (1, 0, "internal error: EOF too early in RCS_copydeltas");
8434 found = (insertpt != NULL && STREQ (dtext->version, insertpt));
8435 if (found && insertbefore)
8437 putdeltatext (fout, newdtext);
8442 np = findnode (rcs->versions, dtext->version);
8445 "Delta text %s without revision information in `%s'.",
8446 dtext->version, rcs->path);
8450 /* If this revision has been outdated, just skip it. */
8451 if (dadmin->outdated)
8453 freedeltatext (dtext);
8458 /* Update the change text for this delta. New change text
8459 data may come from cvs admin -m, cvs admin -o, or cvs ci. */
8460 if (dadmin->text != NULL)
8462 if (dadmin->text->log != NULL || dadmin->text->text != NULL)
8464 if (dadmin->text->log != NULL)
8467 dtext->log = dadmin->text->log;
8468 dadmin->text->log = NULL;
8470 if (dadmin->text->text != NULL)
8473 dtext->text = dadmin->text->text;
8474 dtext->len = dadmin->text->len;
8475 dadmin->text->text = NULL;
8478 putdeltatext (fout, dtext);
8479 freedeltatext (dtext);
8481 if (found && !insertbefore)
8483 putdeltatext (fout, newdtext);
8489 /* Copy the rest of the file directly, without bothering to
8490 interpret it. The caller will handle error checking by calling
8493 We just wrote a newline to the file, either in putdeltatext or
8494 in the caller. However, we may not have read the corresponding
8495 newline from the file, because rcsbuf_getkey returns as soon as
8496 it finds the end of the '@' string for the desc or text key.
8497 Therefore, we may read three newlines when we should really
8498 only write two, and we check for that case here. This is not
8499 an semantically important issue; we only do it to make our RCS
8500 files look traditional. */
8504 rcsbuf_get_buffered (rcsbufin, &bufrest, &buflen);
8507 if (bufrest[0] != '\n'
8508 || strncmp (bufrest, "\n\n\n", buflen < 3 ? buflen : 3) != 0)
8524 fwrite (bufrest, 1, buflen, fout);
8526 if (!rcsbufin->mmapped)
8528 /* This bit isn't necessary when using mmap since the entire file
8529 * will already be available via the RCS buffer. Besides, the
8530 * mmap code doesn't always keep the file pointer up to date, so
8531 * this adds some data twice.
8533 while ((got = fread (buf, 1, sizeof buf, fin)) != 0)
8538 && strncmp (buf, "\n\n\n", nls) == 0)
8540 fwrite (buf + 1, 1, got - 1, fout);
8544 fwrite (buf, 1, got, fout);
8552 /* A helper procedure for RCS_copydeltas. This is called via walklist
8553 to count the number of RCS revisions for which some special action
8557 count_delta_actions (np, ignore)
8561 RCSVers *dadmin = np->data;
8563 if (dadmin->outdated)
8566 if (dadmin->text != NULL
8567 && (dadmin->text->log != NULL || dadmin->text->text != NULL))
8576 * Clean up temporary files
8581 /* Note that the checks for existence_error are because we are
8582 called from a signal handler, so we don't know whether the
8583 files got created. */
8585 /* FIXME: Do not perform buffered I/O from an interrupt handler like
8586 this (via error). However, I'm leaving the error-calling code there
8587 in the hope that on the rare occasion the error call is actually made
8588 (e.g., a fluky I/O error or permissions problem prevents the deletion
8589 of a just-created file) reentrancy won't be an issue. */
8590 if (rcs_lockfile != NULL)
8592 char *tmp = rcs_lockfile;
8593 rcs_lockfile = NULL;
8594 if (rcs_lockfd >= 0)
8596 if (close (rcs_lockfd) != 0)
8597 error (0, errno, "error closing lock file %s", tmp);
8600 if (unlink_file (tmp) < 0
8601 && !existence_error (errno))
8602 error (0, errno, "cannot remove %s", tmp);
8606 /* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style
8607 locking on the specified RCSFILE: for a file called `foo,v', open
8608 for writing a file called `,foo,'.
8610 Note that we what do here is quite different from what RCS does.
8611 RCS creates the ,foo, file before it reads the RCS file (if it
8612 knows that it will be writing later), so that it actually serves as
8613 a lock. We don't; instead we rely on CVS writelocks. This means
8614 that if someone is running RCS on the file at the same time they
8615 are running CVS on it, they might lose (we read the file,
8616 then RCS writes it, then we write it, clobbering the
8617 changes made by RCS). I believe the current sentiment about this
8618 is "well, don't do that".
8620 A concern has been expressed about whether adopting the RCS
8621 strategy would slow us down. I don't think so, since we need to
8622 write the ,foo, file anyway (unless perhaps if O_EXCL is slower or
8625 These do not perform quite the same function as the RCS -l option
8626 for locking files: they are intended to prevent competing RCS
8627 processes from stomping all over each other's laundry. Hence,
8628 they are `internal' locking functions.
8630 If there is an error, give a fatal error; if we return we always
8631 return a non-NULL value. */
8634 rcs_internal_lockfile (rcsfile)
8639 static int first_call = 1;
8644 /* clean up if we get a signal */
8646 (void) SIG_register (SIGABRT, rcs_cleanup);
8649 (void) SIG_register (SIGHUP, rcs_cleanup);
8652 (void) SIG_register (SIGINT, rcs_cleanup);
8655 (void) SIG_register (SIGQUIT, rcs_cleanup);
8658 (void) SIG_register (SIGPIPE, rcs_cleanup);
8661 (void) SIG_register (SIGTERM, rcs_cleanup);
8665 /* Get the lock file name: `,file,' for RCS file `file,v'. */
8666 assert (rcs_lockfile == NULL);
8667 assert (rcs_lockfd < 0);
8668 rcs_lockfile = rcs_lockfilename (rcsfile);
8670 /* Use the existing RCS file mode, or read-only if this is a new
8671 file. (Really, this is a lie -- if this is a new file,
8672 RCS_checkin uses the permissions from the working copy. For
8673 actually creating the file, we use 0444 as a safe default mode.) */
8674 if (stat (rcsfile, &rstat) < 0)
8676 if (existence_error (errno))
8677 rstat.st_mode = S_IRUSR | S_IRGRP | S_IROTH;
8679 error (1, errno, "cannot stat %s", rcsfile);
8682 /* Try to open exclusively. POSIX.1 guarantees that O_EXCL|O_CREAT
8683 guarantees an exclusive open. According to the RCS source, with
8684 NFS v2 we must also throw in O_TRUNC and use an open mask that makes
8685 the file unwriteable. For extensive justification, see the comments for
8686 rcswriteopen() in rcsedit.c, in RCS 5.7. This is kind of pointless
8687 in the CVS case; see comment at the start of this file concerning
8688 general ,foo, file strategy.
8690 There is some sentiment that with NFSv3 and such, that one can
8691 rely on O_EXCL these days. This might be true for unix (I
8692 don't really know), but I am still pretty skeptical in the case
8693 of the non-unix systems. */
8694 rcs_lockfd = open (rcs_lockfile,
8695 OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
8696 S_IRUSR | S_IRGRP | S_IROTH);
8700 error (1, errno, "could not open lock file `%s'", rcs_lockfile);
8703 /* Force the file permissions, and return a stream object. */
8704 /* Because we change the modes later, we don't worry about
8705 this in the non-HAVE_FCHMOD case. */
8707 if (fchmod (rcs_lockfd, rstat.st_mode) < 0)
8708 error (1, errno, "cannot change mode for %s", rcs_lockfile);
8710 fp = fdopen (rcs_lockfd, FOPEN_BINARY_WRITE);
8712 error (1, errno, "cannot fdopen %s", rcs_lockfile);
8718 rcs_internal_unlockfile (fp, rcsfile)
8722 assert (rcs_lockfile != NULL);
8723 assert (rcs_lockfd >= 0);
8725 /* Abort if we could not write everything successfully to LOCKFILE.
8726 This is not a great error-handling mechanism, but should prevent
8727 corrupting the repository. */
8730 /* Using errno here may well be misleanding since the most recent
8731 call that set errno may not have anything whatsoever to do with
8732 the error that set the flag, but it's better than nothing. The
8733 real solution is to check each call to fprintf rather than waiting
8734 until the end like this. */
8735 error (1, errno, "error writing to lock file %s", rcs_lockfile);
8737 /* Flush and sync the file, or the user may be told the commit completed,
8738 * while a server crash/power failure could still cause the data to be
8741 * Invoking rename(",<file>," , "<file>,v") on Linux and almost all UNIXs
8742 * only flushes the inode for the target file to disk, it does not
8743 * guarantee flush of the kernel buffers allocated for the ,<file>,.
8744 * Depending upon the load on the machine, the Linux kernel's flush daemon
8745 * process may not flush for a while. In the meantime the CVS transaction
8746 * could have been declared committed to the end CVS user (CVS process has
8747 * returned the final "OK"). If the machine crashes prior to syncing the
8748 * changes to disk, the committed transaction can be lost.
8750 if (fflush (fp) != 0)
8751 error (1, errno, "error flushing file `%s' to kernel buffers",
8754 if (fsync (rcs_lockfd) < 0)
8755 error (1, errno, "error fsyncing file `%s'", rcs_lockfile);
8758 if (fclose (fp) == EOF)
8759 error (1, errno, "error closing lock file %s", rcs_lockfile);
8762 rename_file (rcs_lockfile, rcsfile);
8765 /* Use a temporary to make sure there's no interval
8766 (after rcs_lockfile has been freed but before it's set to NULL)
8767 during which the signal handler's use of rcs_lockfile would
8768 reference freed memory. */
8769 char *tmp = rcs_lockfile;
8770 rcs_lockfile = NULL;
8776 rcs_lockfilename (rcsfile)
8777 const char *rcsfile;
8779 char *lockfile, *lockp;
8780 const char *rcsbase, *rcsp, *rcsend;
8783 /* Create the lockfile name. */
8784 rcslen = strlen (rcsfile);
8785 lockfile = (char *) xmalloc (rcslen + 10);
8786 rcsbase = last_component (rcsfile);
8787 rcsend = rcsfile + rcslen - sizeof(RCSEXT);
8788 for (lockp = lockfile, rcsp = rcsfile; rcsp < rcsbase; ++rcsp)
8791 while (rcsp <= rcsend)
8799 /* Rewrite an RCS file. The basic idea here is that the caller should
8800 first call RCS_reparsercsfile, then munge the data structures as
8801 desired (via RCS_delete_revs, RCS_settag, &c), then call RCS_rewrite. */
8804 RCS_rewrite (rcs, newdtext, insertpt)
8806 Deltatext *newdtext;
8810 struct rcsbuffer rcsbufin;
8817 /* Make sure we're operating on an actual file and not a symlink. */
8818 resolve_symlink (&(rcs->path));
8820 fout = rcs_internal_lockfile (rcs->path);
8822 RCS_putadmin (rcs, fout);
8823 RCS_putdtree (rcs, rcs->head, fout);
8824 RCS_putdesc (rcs, fout);
8826 /* Open the original RCS file and seek to the first delta text. */
8827 rcsbuf_cache_open (rcs, rcs->delta_pos, &fin, &rcsbufin);
8829 /* Update delta_pos to the current position in the output file.
8830 Do NOT move these statements: they must be done after fin has
8831 been positioned at the old delta_pos, but before any delta
8832 texts have been written to fout.
8834 rcs->delta_pos = ftell (fout);
8835 if (rcs->delta_pos == -1)
8836 error (1, errno, "cannot ftell in RCS file %s", rcs->path);
8838 RCS_copydeltas (rcs, fin, &rcsbufin, fout, newdtext, insertpt);
8840 /* We don't want to call rcsbuf_cache here, since we're about to
8842 rcsbuf_close (&rcsbufin);
8844 /* The only case in which using errno here would be meaningful
8845 is if we happen to have left errno unmolested since the call
8846 which produced the error (e.g. fread). That is pretty
8847 fragile even if it happens to sometimes be true. The real
8848 solution is to make sure that all the code which reads
8849 from fin checks for errors itself (some does, some doesn't). */
8850 error (0, 0, "warning: ferror set while rewriting RCS file `%s'", rcs->path);
8851 if (fclose (fin) < 0)
8852 error (0, errno, "warning: closing RCS file `%s'", rcs->path);
8854 rcs_internal_unlockfile (fout, rcs->path);
8857 /* Abandon changes to an RCS file. */
8863 free_rcsnode_contents (rcs);
8864 rcs->symbols_data = NULL;
8867 rcs->locks_data = NULL;
8868 rcs->comment = NULL;
8870 rcs->flags |= PARTIAL;
8874 * For a given file with full pathname PATH and revision number REV,
8875 * produce a file label suitable for passing to diff. The default
8876 * file label as used by RCS 5.7 looks like this:
8878 * FILENAME <tab> YYYY/MM/DD <sp> HH:MM:SS <tab> REVNUM
8880 * The date and time used are the revision's last checkin date and time.
8881 * If REV is NULL, use the working copy's mtime instead.
8883 * /dev/null is not statted but assumed to have been created on the Epoch.
8884 * At least using the POSIX.2 definition of patch, this should cause creation
8885 * of files on platforms such as Windoze where the null IO device isn't named
8886 * /dev/null to be parsed by patch properly.
8889 make_file_label (path, rev, rcs)
8894 char datebuf[MAXDATELEN + 1];
8897 label = (char *) xmalloc (strlen (path)
8898 + (rev == NULL ? 0 : strlen (rev) + 1)
8904 char date[MAXDATELEN + 1];
8905 /* revs cannot be attached to /dev/null ... duh. */
8906 assert (strcmp(DEVNULL, path));
8907 RCS_getrevtime (rcs, rev, datebuf, 0);
8908 (void) date_to_internet (date, datebuf);
8909 (void) sprintf (label, "-L%s\t%s\t%s", path, date, rev);
8916 if (strcmp(DEVNULL, path))
8918 const char *file = last_component (path);
8919 if (CVS_STAT (file, &sb) < 0)
8920 /* Assume that if the stat fails,then the later read for the
8923 error (1, errno, "could not get info for `%s'", path);
8924 wm = gmtime (&sb.st_mtime);
8932 (void) tm_to_internet (datebuf, wm);
8933 (void) sprintf (label, "-L%s\t%s", path, datebuf);