2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
4 * You may distribute under the terms of the GNU General Public License as
5 * specified in the README file that comes with the CVS source distribution.
7 * The routines contained in this file do all the rcs file parsing and
18 /* These need to be source after cvs.h or HAVE_MMAP won't be set... */
20 # include <sys/mman.h>
21 # ifndef HAVE_GETPAGESIZE
22 # include "getpagesize.h"
25 # define MAP_FAILED NULL
30 int preserve_perms = 0;
32 /* The RCS -k options, and a set of enums that must match the array.
33 These come first so that we can use enum kflag in function
35 static const char *const kflags[] =
36 {"kv", "kvl", "k", "v", "o", "b", (char *) NULL};
37 enum kflag { KFLAG_KV = 0, KFLAG_KVL, KFLAG_K, KFLAG_V, KFLAG_O, KFLAG_B };
39 /* A structure we use to buffer the contents of an RCS file. The
40 various fields are only referenced directly by the rcsbuf_*
41 functions. We declare the struct here so that we can allocate it
42 on the stack, rather than in memory. */
46 /* Points to the current position in the buffer. */
48 /* Points just after the last valid character in the buffer. */
52 /* The name of the file, used for error messages. */
54 /* The starting file position of the data in the buffer. */
56 /* The length of the value. */
58 /* Whether the value contains an '@' string. If so, we can not
59 compress whitespace characters. */
61 /* The number of embedded '@' characters in an '@' string. If
62 this is non-zero, we must search the string for pairs of '@'
63 and convert them to a single '@'. */
67 static RCSNode *RCS_parsercsfile_i PROTO((FILE * fp, const char *rcsfile));
68 static char *RCS_getdatebranch PROTO((RCSNode * rcs, const char *date,
70 static void rcsbuf_open PROTO ((struct rcsbuffer *, FILE *fp,
71 const char *filename, unsigned long pos));
72 static void rcsbuf_close PROTO ((struct rcsbuffer *));
73 static int rcsbuf_getkey PROTO ((struct rcsbuffer *, char **keyp,
75 static int rcsbuf_getrevnum PROTO ((struct rcsbuffer *, char **revp));
77 static char *rcsbuf_fill PROTO ((struct rcsbuffer *, char *ptr, char **keyp,
80 static int rcsbuf_valcmp PROTO ((struct rcsbuffer *));
81 static char *rcsbuf_valcopy PROTO ((struct rcsbuffer *, char *val, int polish,
83 static void rcsbuf_valpolish PROTO ((struct rcsbuffer *, char *val, int polish,
85 static void rcsbuf_valpolish_internal PROTO ((struct rcsbuffer *, char *to,
86 const char *from, size_t *lenp));
87 static unsigned long rcsbuf_ftell PROTO ((struct rcsbuffer *));
88 static void rcsbuf_get_buffered PROTO ((struct rcsbuffer *, char **datap,
90 static void rcsbuf_cache PROTO ((RCSNode *, struct rcsbuffer *));
91 static void rcsbuf_cache_close PROTO ((void));
92 static void rcsbuf_cache_open PROTO ((RCSNode *, long, FILE **,
94 static int checkmagic_proc PROTO((Node *p, void *closure));
95 static void do_branches PROTO((List * list, char *val));
96 static void do_symbols PROTO((List * list, char *val));
97 static void do_locks PROTO((List * list, char *val));
98 static void free_rcsnode_contents PROTO((RCSNode *));
99 static void free_rcsvers_contents PROTO((RCSVers *));
100 static void rcsvers_delproc PROTO((Node * p));
101 static char *translate_symtag PROTO((RCSNode *, const char *));
102 static char *RCS_addbranch PROTO ((RCSNode *, const char *));
103 static char *truncate_revnum_in_place PROTO ((char *));
104 static char *truncate_revnum PROTO ((const char *));
105 static char *printable_date PROTO((const char *));
106 static char *escape_keyword_value PROTO ((const char *, int *));
107 static void expand_keywords PROTO((RCSNode *, RCSVers *, const char *,
108 const char *, size_t, enum kflag, char *,
109 size_t, char **, size_t *));
110 static void cmp_file_buffer PROTO((void *, const char *, size_t));
112 /* Routines for reading, parsing and writing RCS files. */
113 static RCSVers *getdelta PROTO ((struct rcsbuffer *, char *, char **,
115 static Deltatext *RCS_getdeltatext PROTO ((RCSNode *, FILE *,
116 struct rcsbuffer *));
117 static void freedeltatext PROTO ((Deltatext *));
119 static void RCS_putadmin PROTO ((RCSNode *, FILE *));
120 static void RCS_putdtree PROTO ((RCSNode *, char *, FILE *));
121 static void RCS_putdesc PROTO ((RCSNode *, FILE *));
122 static void putdelta PROTO ((RCSVers *, FILE *));
123 static int putrcsfield_proc PROTO ((Node *, void *));
124 static int putsymbol_proc PROTO ((Node *, void *));
125 static void RCS_copydeltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *,
126 FILE *, Deltatext *, char *));
127 static int count_delta_actions PROTO ((Node *, void *));
128 static void putdeltatext PROTO ((FILE *, Deltatext *));
130 static FILE *rcs_internal_lockfile PROTO ((char *));
131 static void rcs_internal_unlockfile PROTO ((FILE *, char *));
132 static char *rcs_lockfilename PROTO ((const char *));
134 /* The RCS file reading functions are called a lot, and they do some
135 string comparisons. This macro speeds things up a bit by skipping
136 the function call when the first characters are different. It
137 evaluates its arguments multiple times. */
138 #define STREQ(a, b) (*(char *)(a) == *(char *)(b) && strcmp ((a), (b)) == 0)
140 static char * getfullCVSname PROTO ((char *, char **));
143 * We don't want to use isspace() from the C library because:
145 * 1. The definition of "whitespace" in RCS files includes ASCII
146 * backspace, but the C locale doesn't.
147 * 2. isspace is an very expensive function call in some implementations
148 * due to the addition of wide character support.
150 static const char spacetab[] = {
151 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x00 - 0x0f */
152 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */
153 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */
154 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */
155 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
156 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
157 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x8f */
158 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */
159 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */
160 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */
161 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */
162 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */
163 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
164 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
165 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
166 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0 - 0xff */
169 #define whitespace(c) (spacetab[(unsigned char)c] != 0)
171 static char *rcs_lockfile;
172 static int rcs_lockfd = -1;
178 * locate_rcs ( const char* file, const char *repository , int *inattic )
180 * Find an RCS file in the repository, case insensitively when the cased name
181 * doesn't exist, we are running as the server, and a client has asked us to
184 * Most parts of CVS will want to rely instead on RCS_parse which calls this
185 * function and is called by recurse.c which then puts the result in useful
186 * places like the rcs field of struct file_info.
190 * repository the repository (including the directory)
191 * file the filename within that directory (without RCSEXT).
192 * inattic NULL or a pointer to the output boolean
196 * inattic If this input was non-null, the destination will be
197 * set to true if the file was found in the attic or
198 * false if not. If no RCS file is found, this value
203 * a newly-malloc'd array containing the absolute pathname of the RCS
204 * file that was found or NULL when none was found.
208 * errno can be set by the return value of the final call to
209 * locate_file_in_dir(). This should resolve to the system's existence error
210 * value (sometime ENOENT) if the Attic directory did not exist and ENOENT if
211 * the Attic was found but no matching files were found in the Attic or its
215 locate_rcs (repository, file, inattic)
216 const char *repository;
222 /* First, try to find the file as cased. */
223 retval = xmalloc (strlen (repository)
228 sprintf (retval, "%s/%s%s", repository, file, RCSEXT);
229 if (isreadable (retval))
235 sprintf (retval, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT);
236 if (isreadable (retval))
249 /* A few generic thoughts on error handling, in particular the
250 printing of unexpected characters that we find in the RCS file
251 (that is, why we use '\x%x' rather than %c or some such).
253 * Avoiding %c means we don't have to worry about what is printable
254 and other such stuff. In error handling, often better to keep it
257 * Hex rather than decimal or octal because character set standards
260 * Saying "character 0x%x" might make it sound like we are printing
261 a file offset. So we use '\x%x'.
263 * Would be nice to print the offset within the file, but I can
264 imagine various portability hassles (in particular, whether
265 unsigned long is always big enough to hold file offsets). */
267 /* Parse an rcsfile given a user file name and a repository. If there is
268 an error, we print an error message and return NULL. If the file
269 does not exist, we return NULL without printing anything (I'm not
270 sure this allows the caller to do anything reasonable, but it is
271 the current behavior). */
273 RCS_parse (file, repos)
279 RCSNode *retval = NULL;
283 /* We're creating a new RCSNode, so there is no hope of finding it
285 rcsbuf_cache_close ();
287 if ((rcsfile = locate_rcs (repos, file, &inattic)) == NULL)
289 /* Handle the error cases */
291 else if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) != NULL)
293 rcs = RCS_parsercsfile_i(fp, rcsfile);
298 rcs->flags |= INATTIC;
304 else if (! existence_error (errno))
307 error (0, errno, "cannot open %s", rcsfile);
314 * Parse a specific rcsfile.
317 RCS_parsercsfile (rcsfile)
323 /* We're creating a new RCSNode, so there is no hope of finding it
325 rcsbuf_cache_close ();
327 /* open the rcsfile */
328 if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) == NULL)
330 error (0, errno, "Couldn't open rcs file `%s'", rcsfile);
334 rcs = RCS_parsercsfile_i (fp, rcsfile);
344 RCS_parsercsfile_i (fp, rcsfile)
349 struct rcsbuffer rcsbuf;
353 rdata = (RCSNode *) xmalloc (sizeof (RCSNode));
354 memset ((char *)rdata, 0, sizeof (RCSNode));
356 rdata->path = xstrdup (rcsfile);
358 /* Process HEAD, BRANCH, and EXPAND keywords from the RCS header.
360 Most cvs operations on the main branch don't need any more
361 information. Those that do call RCS_reparsercsfile to parse
362 the rest of the header and the deltas. */
364 rcsbuf_open (&rcsbuf, fp, rcsfile, 0);
366 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
368 if (STREQ (key, RCSDESC))
371 if (STREQ (RCSHEAD, key) && value != NULL)
372 rdata->head = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *)NULL);
374 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
376 if (STREQ (key, RCSDESC))
379 if (STREQ (RCSBRANCH, key) && value != NULL)
383 rdata->branch = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *)NULL);
384 if ((numdots (rdata->branch) & 1) != 0)
386 /* turn it into a branch if it's a revision */
387 cp = strrchr (rdata->branch, '.');
392 /* Look ahead for expand, stopping when we see desc or a revision
398 if (STREQ (RCSEXPAND, key))
400 rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0,
406 (isdigit ((unsigned char)*cp) || *cp == '.') && *cp != '\0';
412 if (STREQ (RCSDESC, key))
415 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
419 rdata->flags |= PARTIAL;
421 rcsbuf_cache (rdata, &rcsbuf);
426 error (0, 0, "`%s' does not appear to be a valid rcs file",
428 rcsbuf_close (&rcsbuf);
429 freercsnode (&rdata);
436 /* Do the real work of parsing an RCS file.
438 On error, die with a fatal error; if it returns at all it was successful.
440 If PFP is NULL, close the file when done. Otherwise, leave it open
441 and store the FILE * in *PFP. */
443 RCS_reparsercsfile (rdata, pfp, rcsbufp)
446 struct rcsbuffer *rcsbufp;
450 struct rcsbuffer rcsbuf;
457 assert (rdata != NULL);
458 rcsfile = rdata->path;
460 rcsbuf_cache_open (rdata, 0, &fp, &rcsbuf);
463 /* This probably shouldn't be done until later: if a file has an
464 empty revision tree (which is permissible), rdata->versions
465 should be NULL. -twp */
466 rdata->versions = getlist ();
469 * process all the special header information, break out when we get to
470 * the first revision delta
475 /* get the next key/value pair */
478 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
480 error (1, 0, "`%s' does not appear to be a valid rcs file",
487 /* Skip head, branch and expand tags; we already have them. */
488 if (STREQ (key, RCSHEAD)
489 || STREQ (key, RCSBRANCH)
490 || STREQ (key, RCSEXPAND))
495 if (STREQ (key, "access"))
499 /* We pass the POLISH parameter as 1 because
500 RCS_addaccess expects nothing but spaces. FIXME:
501 It would be easy and more efficient to change
503 rdata->access = rcsbuf_valcopy (&rcsbuf, value, 1,
509 /* We always save lock information, so that we can handle
510 -kkvl correctly when checking out a file. */
511 if (STREQ (key, "locks"))
514 rdata->locks_data = rcsbuf_valcopy (&rcsbuf, value, 0,
516 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
518 error (1, 0, "premature end of file reading %s", rcsfile);
520 if (STREQ (key, "strict") && value == NULL)
522 rdata->strict_locks = 1;
529 if (STREQ (RCSSYMBOLS, key))
532 rdata->symbols_data = rcsbuf_valcopy (&rcsbuf, value, 0,
538 * check key for '.''s and digits (probably a rev) if it is a
539 * revision or `desc', we are done with the headers and are down to the
540 * revision deltas, so we break out of the loop
543 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
546 /* Note that when comparing with RCSDATE, we are not massaging
547 VALUE from the string found in the RCS file. This is OK
548 since we know exactly what to expect. */
549 if (*cp == '\0' && strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) == 0)
552 if (STREQ (key, RCSDESC))
555 if (STREQ (key, "comment"))
557 rdata->comment = rcsbuf_valcopy (&rcsbuf, value, 0,
561 if (rdata->other == NULL)
562 rdata->other = getlist ();
564 kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
565 kv->key = xstrdup (key);
566 kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
568 if (addnode (rdata->other, kv) != 0)
570 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
575 /* if we haven't grabbed it yet, we didn't want it */
578 /* We got out of the loop, so we have the first part of the first
579 revision delta in KEY (the revision) and VALUE (the date key
580 and its value). This is what getdelta expects to receive. */
582 while ((vnode = getdelta (&rcsbuf, rcsfile, &key, &value)) != NULL)
587 q->delproc = rcsvers_delproc;
589 q->key = vnode->version;
591 /* add the nodes to the list */
592 if (addnode (rdata->versions, q) != 0)
595 purify_printf("WARNING: Adding duplicate version: %s (%s)\n",
602 /* Here KEY and VALUE are whatever caused getdelta to return NULL. */
604 if (STREQ (key, RCSDESC))
606 if (rdata->desc != NULL)
609 "warning: duplicate key `%s' in RCS file `%s'",
613 rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
616 rdata->delta_pos = rcsbuf_ftell (&rcsbuf);
619 rcsbuf_cache (rdata, &rcsbuf);
625 rdata->flags &= ~PARTIAL;
628 /* Move RCS into or out of the Attic, depending on TOATTIC. If the
629 file is already in the desired place, return without doing
630 anything. At some point may want to think about how this relates
631 to RCS_rewrite but that is a bit hairy (if one wants renames to be
632 atomic, or that kind of thing). If there is an error, print a message
633 and return 1. On success, return 0. */
635 RCS_setattic (rcs, toattic)
643 /* Some systems aren't going to let us rename an open file. */
644 rcsbuf_cache_close ();
646 /* Could make the pathname computations in this file, and probably
647 in other parts of rcs.c too, easier if the REPOS and FILE
648 arguments to RCS_parse got stashed in the RCSNode. */
654 if (rcs->flags & INATTIC)
657 /* Example: rcs->path is "/foo/bar/baz,v". */
658 newpath = xmalloc (strlen (rcs->path) + sizeof CVSATTIC + 5);
659 p = last_component (rcs->path);
660 strncpy (newpath, rcs->path, p - rcs->path);
661 strcpy (newpath + (p - rcs->path), CVSATTIC);
663 /* Create the Attic directory if it doesn't exist. */
664 omask = umask (cvsumask);
665 if (CVS_MKDIR (newpath, 0777) < 0 && errno != EEXIST)
666 error (0, errno, "cannot make directory %s", newpath);
667 (void) umask (omask);
669 strcat (newpath, "/");
672 if (CVS_RENAME (rcs->path, newpath) < 0)
674 int save_errno = errno;
676 /* The checks for isreadable look awfully fishy, but
677 I'm going to leave them here for now until I
678 can think harder about whether they take care of
679 some cases which should be handled somehow. */
681 if (isreadable (rcs->path) || !isreadable (newpath))
683 error (0, save_errno, "cannot rename %s to %s",
692 if (!(rcs->flags & INATTIC))
695 newpath = xmalloc (strlen (rcs->path));
697 /* Example: rcs->path is "/foo/bar/Attic/baz,v". */
698 p = last_component (rcs->path);
699 strncpy (newpath, rcs->path, p - rcs->path - 1);
700 newpath[p - rcs->path - 1] = '\0';
701 q = newpath + (p - rcs->path - 1) - (sizeof CVSATTIC - 1);
702 assert (strncmp (q, CVSATTIC, sizeof CVSATTIC - 1) == 0);
705 if (CVS_RENAME (rcs->path, newpath) < 0)
707 error (0, errno, "failed to move `%s' out of the attic",
721 * Fully parse the RCS file. Store all keyword/value pairs, fetch the
722 * log messages for each revision, and fetch add and delete counts for
723 * each revision (we could fetch the entire text for each revision,
724 * but the only caller, log_fileproc, doesn't need that information,
725 * so we don't waste the memory required to store it). The add and
726 * delete counts are stored on the OTHER field of the RCSVERSNODE
727 * structure, under the names ";add" and ";delete", so that we don't
728 * waste the memory space of extra fields in RCSVERSNODE for code
729 * which doesn't need this information.
733 RCS_fully_parse (rcs)
737 struct rcsbuffer rcsbuf;
739 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
747 /* Rather than try to keep track of how much information we
748 have read, just read to the end of the file. */
749 if (!rcsbuf_getrevnum (&rcsbuf, &key))
752 vers = findnode (rcs->versions, key);
755 "mismatch in rcs file %s between deltas and deltatexts (%s)",
760 while (rcsbuf_getkey (&rcsbuf, &key, &value))
762 if (!STREQ (key, "text"))
766 if (vnode->other == NULL)
767 vnode->other = getlist ();
769 kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
770 kv->key = xstrdup (key);
771 kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
773 if (addnode (vnode->other, kv) != 0)
777 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
778 key, vnode->version, rcs->path);
785 if (!STREQ (vnode->version, rcs->head))
787 unsigned long add, del;
791 /* This is a change text. Store the add and delete
800 rcsbuf_valpolish (&rcsbuf, value, 0, &vallen);
802 while (cp < value + vallen)
808 if (op != 'a' && op != 'd')
810 unrecognized operation '\\x%x' in %s",
812 (void) strtoul (cp, (char **) &cp, 10);
814 error (1, 0, "space expected in %s revision %s",
815 rcs->path, vnode->version);
816 count = strtoul (cp, (char **) &cp, 10);
818 error (1, 0, "linefeed expected in %s revision %s",
819 rcs->path, vnode->version);
830 else if (cp == value + vallen)
834 premature end of value in %s revision %s",
835 rcs->path, vnode->version);
845 sprintf (buf, "%lu", add);
848 kv->key = xstrdup (";add");
849 kv->data = xstrdup (buf);
850 if (addnode (vnode->other, kv) != 0)
854 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
855 key, vnode->version, rcs->path);
859 sprintf (buf, "%lu", del);
862 kv->key = xstrdup (";delete");
863 kv->data = xstrdup (buf);
864 if (addnode (vnode->other, kv) != 0)
868 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
869 key, vnode->version, rcs->path);
874 /* We have found the "text" key which ends the data for
875 this revision. Break out of the loop and go on to the
881 rcsbuf_cache (rcs, &rcsbuf);
887 * freercsnode - free up the info for an RCSNode
893 if (rnodep == NULL || *rnodep == NULL)
896 ((*rnodep)->refcount)--;
897 if ((*rnodep)->refcount != 0)
899 *rnodep = (RCSNode *) NULL;
902 free ((*rnodep)->path);
903 if ((*rnodep)->head != (char *) NULL)
904 free ((*rnodep)->head);
905 if ((*rnodep)->branch != (char *) NULL)
906 free ((*rnodep)->branch);
907 free_rcsnode_contents (*rnodep);
908 free ((char *) *rnodep);
909 *rnodep = (RCSNode *) NULL;
913 * free_rcsnode_contents - free up the contents of an RCSNode without
914 * freeing the node itself, or the file name, or the head, or the
915 * path. This returns the RCSNode to the state it is in immediately
916 * after a call to RCS_parse.
919 free_rcsnode_contents (rnode)
922 dellist (&rnode->versions);
923 if (rnode->symbols != (List *) NULL)
924 dellist (&rnode->symbols);
925 if (rnode->symbols_data != (char *) NULL)
926 free (rnode->symbols_data);
927 if (rnode->expand != NULL)
928 free (rnode->expand);
929 if (rnode->other != (List *) NULL)
930 dellist (&rnode->other);
931 if (rnode->access != NULL)
932 free (rnode->access);
933 if (rnode->locks_data != NULL)
934 free (rnode->locks_data);
935 if (rnode->locks != (List *) NULL)
936 dellist (&rnode->locks);
937 if (rnode->comment != NULL)
938 free (rnode->comment);
939 if (rnode->desc != NULL)
943 /* free_rcsvers_contents -- free up the contents of an RCSVers node,
944 but also free the pointer to the node itself. */
945 /* Note: The `hardlinks' list is *not* freed, since it is merely a
946 pointer into the `hardlist' structure (defined in hardlink.c), and
947 that structure is freed elsewhere in the program. */
950 free_rcsvers_contents (rnode)
953 if (rnode->branches != (List *) NULL)
954 dellist (&rnode->branches);
955 if (rnode->date != (char *) NULL)
957 if (rnode->next != (char *) NULL)
959 if (rnode->author != (char *) NULL)
960 free (rnode->author);
961 if (rnode->state != (char *) NULL)
963 if (rnode->other != (List *) NULL)
964 dellist (&rnode->other);
965 if (rnode->other_delta != NULL)
966 dellist (&rnode->other_delta);
967 if (rnode->text != NULL)
968 freedeltatext (rnode->text);
969 free ((char *) rnode);
973 * rcsvers_delproc - free up an RCSVers type node
979 free_rcsvers_contents (p->data);
982 /* These functions retrieve keys and values from an RCS file using a
983 buffer. We use this somewhat complex approach because it turns out
984 that for many common operations, CVS spends most of its time
985 reading keys, so it's worth doing some fairly hairy optimization. */
987 /* The number of bytes we try to read each time we need more data. */
989 #define RCSBUF_BUFSIZE (8192)
991 /* The buffer we use to store data. This grows as needed. */
993 static char *rcsbuf_buffer = NULL;
994 static size_t rcsbuf_buffer_size = 0;
996 /* Whether rcsbuf_buffer is in use. This is used as a sanity check. */
998 static int rcsbuf_inuse;
1000 /* Set up to start gathering keys and values from an RCS file. This
1001 initializes RCSBUF. */
1004 rcsbuf_open (rcsbuf, fp, filename, pos)
1005 struct rcsbuffer *rcsbuf;
1007 const char *filename;
1011 error (1, 0, "rcsbuf_open: internal error");
1016 /* When we have mmap, it is much more efficient to let the system do the
1017 * buffering and caching for us
1020 size_t mmap_off = 0;
1022 if ( fstat (fileno(fp), &fs) < 0 )
1023 error ( 1, errno, "Could not stat RCS archive %s for mapping", filename );
1027 size_t ps = getpagesize ();
1028 mmap_off = ( pos / ps ) * ps;
1031 /* Map private here since this particular buffer is read only */
1032 rcsbuf_buffer = mmap ( NULL, fs.st_size - mmap_off,
1033 PROT_READ | PROT_WRITE,
1034 MAP_PRIVATE, fileno(fp), mmap_off );
1035 if ( rcsbuf_buffer == NULL || rcsbuf_buffer == MAP_FAILED )
1036 error ( 1, errno, "Could not map memory to RCS archive %s", filename );
1038 rcsbuf_buffer_size = fs.st_size - mmap_off;
1039 rcsbuf->ptr = rcsbuf_buffer + pos - mmap_off;
1040 rcsbuf->ptrend = rcsbuf_buffer + fs.st_size - mmap_off;
1041 rcsbuf->pos = mmap_off;
1043 #else /* HAVE_MMAP */
1044 if (rcsbuf_buffer_size < RCSBUF_BUFSIZE)
1045 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, RCSBUF_BUFSIZE);
1047 rcsbuf->ptr = rcsbuf_buffer;
1048 rcsbuf->ptrend = rcsbuf_buffer;
1050 #endif /* HAVE_MMAP */
1052 rcsbuf->filename = filename;
1054 rcsbuf->at_string = 0;
1055 rcsbuf->embedded_at = 0;
1058 /* Stop gathering keys from an RCS file. */
1061 rcsbuf_close (rcsbuf)
1062 struct rcsbuffer *rcsbuf;
1065 error (1, 0, "rcsbuf_close: internal error");
1067 munmap ( rcsbuf_buffer, rcsbuf_buffer_size );
1072 /* Read a key/value pair from an RCS file. This sets *KEYP to point
1073 to the key, and *VALUEP to point to the value. A missing or empty
1074 value is indicated by setting *VALUEP to NULL.
1076 This function returns 1 on success, or 0 on EOF. If there is an
1077 error reading the file, or an EOF in an unexpected location, it
1078 gives a fatal error.
1080 This sets *KEYP and *VALUEP to point to storage managed by
1081 rcsbuf_getkey. Moreover, *VALUEP has not been massaged from the
1082 RCS format: it may contain embedded whitespace and embedded '@'
1083 characters. Call rcsbuf_valcopy or rcsbuf_valpolish to do
1084 appropriate massaging. */
1086 /* Note that the extreme hair in rcsbuf_getkey is because profiling
1087 statistics show that it was worth it. */
1090 rcsbuf_getkey (rcsbuf, keyp, valp)
1091 struct rcsbuffer *rcsbuf;
1095 register const char * const my_spacetab = spacetab;
1096 register char *ptr, *ptrend;
1099 #define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
1102 rcsbuf->at_string = 0;
1103 rcsbuf->embedded_at = 0;
1106 ptrend = rcsbuf->ptrend;
1109 assert (ptr >= rcsbuf_buffer && ptr <= rcsbuf_buffer + rcsbuf_buffer_size);
1110 assert (ptrend >= rcsbuf_buffer && ptrend <= rcsbuf_buffer + rcsbuf_buffer_size);
1113 /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
1114 buffer, move back to the start of the buffer. This keeps the
1115 buffer from growing indefinitely. */
1116 if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
1122 /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
1123 at a time, so we can't have more bytes than that past PTR. */
1124 assert (len <= RCSBUF_BUFSIZE);
1126 /* Update the POS field, which holds the file offset of the
1127 first byte in the RCSBUF_BUFFER buffer. */
1128 rcsbuf->pos += ptr - rcsbuf_buffer;
1130 memcpy (rcsbuf_buffer, ptr, len);
1131 ptr = rcsbuf_buffer;
1133 rcsbuf->ptrend = ptrend;
1135 #endif /* ndef HAVE_MMAP */
1137 /* Skip leading whitespace. */
1144 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
1149 ptrend = rcsbuf->ptrend;
1154 if (! my_whitespace (c))
1160 /* We've found the start of the key. */
1172 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
1175 error (1, 0, "EOF in key in RCS file %s",
1178 ptrend = rcsbuf->ptrend;
1182 if (c == ';' || my_whitespace (c))
1187 /* Here *KEYP points to the key in the buffer, C is the character
1188 we found at the of the key, and PTR points to the location in
1189 the buffer where we found C. We must set *PTR to \0 in order
1190 to terminate the key. If the key ended with ';', then there is
1203 /* C must be whitespace. Skip whitespace between the key and the
1204 value. If we find ';' now, there is no value. */
1211 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
1214 error (1, 0, "EOF while looking for value in RCS file %s",
1217 ptrend = rcsbuf->ptrend;
1224 rcsbuf->ptr = ptr + 1;
1227 if (! my_whitespace (c))
1232 /* Now PTR points to the start of the value, and C is the first
1233 character of the value. */
1242 /* Optimize the common case of a value composed of a single
1245 rcsbuf->at_string = 1;
1253 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1256 /* Note that we pass PTREND as the PTR value to
1257 rcsbuf_fill, so that we will wind up setting PTR to
1258 the location corresponding to the old PTREND, so
1259 that we don't search the same bytes again. */
1260 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1264 "EOF while looking for end of string in RCS file %s",
1267 ptrend = rcsbuf->ptrend;
1271 /* Handle the special case of an '@' right at the end of
1273 if (pat + 1 >= ptrend)
1276 /* Note that we pass PAT, not PTR, here. */
1277 pat = rcsbuf_fill (rcsbuf, pat, keyp, valp);
1281 /* EOF here is OK; it just means that the last
1282 character of the file was an '@' terminating a
1283 value for a key type which does not require a
1285 pat = rcsbuf->ptrend - 1;
1289 ptrend = rcsbuf->ptrend;
1291 /* Note that the value of PTR is bogus here. This is
1292 OK, because we don't use it. */
1296 if (pat + 1 >= ptrend || pat[1] != '@')
1299 /* We found an '@' pair in the string. Keep looking. */
1300 ++rcsbuf->embedded_at;
1304 /* Here PAT points to the final '@' in the string. */
1311 rcsbuf->vlen = vlen;
1316 /* Certain keywords only have a '@' string. If there is no '@'
1317 string, then the old getrcskey function assumed that they had
1318 no value, and we do the same. */
1324 if (STREQ (k, RCSDESC)
1325 || STREQ (k, "text")
1326 || STREQ (k, "log"))
1335 /* If we've already gathered a '@' string, try to skip whitespace
1346 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1349 error (1, 0, "EOF in value in RCS file %s",
1352 ptrend = rcsbuf->ptrend;
1358 /* We're done. We already set everything up for this
1360 rcsbuf->ptr = ptr + 1;
1363 if (! my_whitespace (n))
1368 /* The value extends past the '@' string. We need to undo the
1369 '@' stripping done in the default case above. This
1370 case never happens in a plain RCS file, but it can happen
1371 if user defined phrases are used. */
1372 ((*valp)--)[rcsbuf->vlen++] = '@';
1375 /* Here we have a value which is not a simple '@' string. We need
1376 to gather up everything until the next ';', including any '@'
1377 strings. *VALP points to the start of the value. If
1378 RCSBUF->VLEN is not zero, then we have already read an '@'
1379 string, and PTR points to the data following the '@' string.
1380 Otherwise, PTR points to the start of the value. */
1384 char *start, *psemi, *pat;
1386 /* Find the ';' which must end the value. */
1388 while ((psemi = memchr (ptr, ';', ptrend - ptr)) == NULL)
1393 /* Note that we pass PTREND as the PTR value to
1394 rcsbuf_fill, so that we will wind up setting PTR to the
1395 location corresponding to the old PTREND, so that we
1396 don't search the same bytes again. */
1397 slen = start - *valp;
1398 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1401 error (1, 0, "EOF in value in RCS file %s", rcsbuf->filename);
1403 start = *valp + slen;
1404 ptrend = rcsbuf->ptrend;
1408 /* See if there are any '@' strings in the value. */
1409 pat = memchr (start, '@', psemi - start);
1415 /* We're done with the value. Trim any trailing
1418 rcsbuf->ptr = psemi + 1;
1421 while (psemi > start && my_whitespace (psemi[-1]))
1425 vlen = psemi - start;
1428 rcsbuf->vlen = vlen;
1433 /* We found an '@' string in the value. We set RCSBUF->AT_STRING
1434 and RCSBUF->EMBEDDED_AT to indicate that we won't be able to
1435 compress whitespace correctly for this type of value.
1436 Since this type of value never arises in a normal RCS file,
1437 this should not be a big deal. It means that if anybody
1438 adds a phrase which can have both an '@' string and regular
1439 text, they will have to handle whitespace compression
1442 rcsbuf->at_string = 1;
1443 rcsbuf->embedded_at = -1;
1449 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1452 /* Note that we pass PTREND as the PTR value to
1453 rcsbuff_fill, so that we will wind up setting PTR
1454 to the location corresponding to the old PTREND, so
1455 that we don't search the same bytes again. */
1456 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1460 "EOF while looking for end of string in RCS file %s",
1463 ptrend = rcsbuf->ptrend;
1467 /* Handle the special case of an '@' right at the end of
1469 if (pat + 1 >= ptrend)
1472 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1475 error (1, 0, "EOF in value in RCS file %s",
1478 ptrend = rcsbuf->ptrend;
1485 /* We found an '@' pair in the string. Keep looking. */
1489 /* Here PAT points to the final '@' in the string. */
1493 #undef my_whitespace
1496 /* Read an RCS revision number from an RCS file. This sets *REVP to
1497 point to the revision number; it will point to space that is
1498 managed by the rcsbuf functions, and is only good until the next
1499 call to rcsbuf_getkey or rcsbuf_getrevnum.
1501 This function returns 1 on success, or 0 on EOF. If there is an
1502 error reading the file, or an EOF in an unexpected location, it
1503 gives a fatal error. */
1506 rcsbuf_getrevnum (rcsbuf, revp)
1507 struct rcsbuffer *rcsbuf;
1514 ptrend = rcsbuf->ptrend;
1518 /* Skip leading whitespace. */
1525 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
1530 ptrend = rcsbuf->ptrend;
1535 if (! whitespace (c))
1541 if (! isdigit ((unsigned char) c) && c != '.')
1544 unexpected '\\x%x' reading revision number in RCS file %s",
1545 c, rcsbuf->filename);
1555 ptr = rcsbuf_fill (rcsbuf, ptr, revp, (char **) NULL);
1559 "unexpected EOF reading revision number in RCS file %s",
1562 ptrend = rcsbuf->ptrend;
1568 while (isdigit ((unsigned char) c) || c == '.');
1570 if (! whitespace (c))
1572 unexpected '\\x%x' reading revision number in RCS file %s",
1573 c, rcsbuf->filename);
1577 rcsbuf->ptr = ptr + 1;
1583 /* Fill RCSBUF_BUFFER with bytes from the file associated with RCSBUF,
1584 updating PTR and the PTREND field. If KEYP and *KEYP are not NULL,
1585 then *KEYP points into the buffer, and must be adjusted if the
1586 buffer is changed. Likewise for VALP. Returns the new value of
1587 PTR, or NULL on error. */
1590 rcsbuf_fill (rcsbuf, ptr, keyp, valp)
1591 struct rcsbuffer *rcsbuf;
1598 if (rcsbuf->ptrend - rcsbuf_buffer + RCSBUF_BUFSIZE > rcsbuf_buffer_size)
1600 int poff, peoff, koff, voff;
1602 poff = ptr - rcsbuf_buffer;
1603 peoff = rcsbuf->ptrend - rcsbuf_buffer;
1604 koff = keyp == NULL ? 0 : *keyp - rcsbuf_buffer;
1605 voff = valp == NULL ? 0 : *valp - rcsbuf_buffer;
1607 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size,
1608 rcsbuf_buffer_size + RCSBUF_BUFSIZE);
1610 ptr = rcsbuf_buffer + poff;
1611 rcsbuf->ptrend = rcsbuf_buffer + peoff;
1613 *keyp = rcsbuf_buffer + koff;
1615 *valp = rcsbuf_buffer + voff;
1618 got = fread (rcsbuf->ptrend, 1, RCSBUF_BUFSIZE, rcsbuf->fp);
1621 if (ferror (rcsbuf->fp))
1622 error (1, errno, "cannot read %s", rcsbuf->filename);
1626 rcsbuf->ptrend += got;
1630 #endif /* HAVE_MMAP */
1632 /* Test whether the last value returned by rcsbuf_getkey is a composite
1636 rcsbuf_valcmp (rcsbuf)
1637 struct rcsbuffer *rcsbuf;
1639 return rcsbuf->at_string && rcsbuf->embedded_at < 0;
1642 /* Copy the value VAL returned by rcsbuf_getkey into a memory buffer,
1643 returning the memory buffer. Polish the value like
1644 rcsbuf_valpolish, q.v. */
1647 rcsbuf_valcopy (rcsbuf, val, polish, lenp)
1648 struct rcsbuffer *rcsbuf;
1664 vlen = rcsbuf->vlen;
1665 embedded_at = rcsbuf->embedded_at < 0 ? 0 : rcsbuf->embedded_at;
1667 ret = xmalloc (vlen - embedded_at + 1);
1669 if (rcsbuf->at_string ? embedded_at == 0 : ! polish)
1671 /* No special action to take. */
1672 memcpy (ret, val, vlen + 1);
1678 rcsbuf_valpolish_internal (rcsbuf, ret, val, lenp);
1682 /* Polish the value VAL returned by rcsbuf_getkey. The POLISH
1683 parameter is non-zero if multiple embedded whitespace characters
1684 should be compressed into a single whitespace character. Note that
1685 leading and trailing whitespace was already removed by
1686 rcsbuf_getkey. Within an '@' string, pairs of '@' characters are
1687 compressed into a single '@' character regardless of the value of
1688 POLISH. If LENP is not NULL, set *LENP to the length of the value. */
1691 rcsbuf_valpolish (rcsbuf, val, polish, lenp)
1692 struct rcsbuffer *rcsbuf;
1704 if (rcsbuf->at_string ? rcsbuf->embedded_at == 0 : ! polish)
1706 /* No special action to take. */
1708 *lenp = rcsbuf->vlen;
1712 rcsbuf_valpolish_internal (rcsbuf, val, val, lenp);
1715 /* Internal polishing routine, called from rcsbuf_valcopy and
1716 rcsbuf_valpolish. */
1719 rcsbuf_valpolish_internal (rcsbuf, to, from, lenp)
1720 struct rcsbuffer *rcsbuf;
1729 if (! rcsbuf->at_string)
1736 for (clen = len; clen > 0; ++from, --clen)
1743 /* Note that we know that clen can not drop to zero
1744 while we have whitespace, because we know there is
1745 no trailing whitespace. */
1746 while (whitespace (from[1]))
1759 *lenp = to - orig_to;
1763 const char *orig_from;
1771 embedded_at = rcsbuf->embedded_at;
1772 assert (embedded_at > 0);
1775 *lenp = len - embedded_at;
1777 for (clen = len; clen > 0; ++from, --clen)
1789 * FIXME: I restored this to an abort from an assert based on
1790 * advice from Larry Jones that asserts should not be used to
1791 * confirm the validity of an RCS file... This leaves two
1792 * issues here: 1) I am uncertain that the fact that we will
1793 * only find double '@'s hasn't already been confirmed; and:
1794 * 2) If this is the proper place to spot the error in the RCS
1795 * file, then we should print a much clearer error here for the
1800 if (*from != '@' || clen == 0)
1806 if (embedded_at == 0)
1808 /* We've found all the embedded '@' characters.
1809 We can just memcpy the rest of the buffer after
1810 this '@' character. */
1811 if (orig_to != orig_from)
1812 memcpy (to, from + 1, clen - 1);
1814 memmove (to, from + 1, clen - 1);
1823 assert (from == orig_from + len
1824 && to == orig_to + (len - rcsbuf->embedded_at));
1830 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1832 /* Copy the next word from the value VALP returned by rcsbuf_getkey into a
1833 memory buffer, updating VALP and returning the memory buffer. Return
1834 NULL when there are no more words. */
1837 rcsbuf_valword (rcsbuf, valp)
1838 struct rcsbuffer *rcsbuf;
1841 register const char * const my_spacetab = spacetab;
1842 register char *ptr, *pat;
1845 # define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
1850 for (ptr = *valp; my_whitespace (*ptr); ++ptr) ;
1853 assert (ptr - *valp == rcsbuf->vlen);
1859 /* PTR now points to the start of a value. Find out whether it is
1860 a num, an id, a string or a colon. */
1864 rcsbuf->vlen -= ++ptr - *valp;
1866 return xstrdup (":");
1871 int embedded_at = 0;
1875 while ((pat = strchr (pat, '@')) != NULL)
1883 /* Here PAT points to the final '@' in the string. */
1885 assert (rcsbuf->at_string);
1886 vlen = rcsbuf->vlen - (pat - *valp);
1887 rcsbuf->vlen = pat - ptr - 1;
1888 rcsbuf->embedded_at = embedded_at;
1889 ptr = rcsbuf_valcopy (rcsbuf, ptr, 0, (size_t *) NULL);
1891 rcsbuf->vlen = vlen;
1892 if (strchr (pat, '@') == NULL)
1893 rcsbuf->at_string = 0;
1895 rcsbuf->embedded_at = -1;
1899 /* *PTR is neither `:', `;' nor `@', so it should be the start of a num
1900 or an id. Make sure it is not another special character. */
1901 if (c == '$' || c == '.' || c == ',')
1903 error (1, 0, "invalid special character in RCS field in %s",
1910 /* Legitimate ID characters are digits, dots and any `graphic
1911 printing character that is not a special.' This test ought
1914 if (!isprint ((unsigned char) c) ||
1915 c == ';' || c == '$' || c == ',' || c == '@' || c == ':')
1919 /* PAT points to the last non-id character in this word, and C is
1920 the character in its memory cell. Check to make sure that it
1921 is a legitimate word delimiter -- whitespace or end. */
1922 if (c != '\0' && !my_whitespace (c))
1923 error (1, 0, "invalid special character in RCS field in %s",
1927 rcsbuf->vlen -= pat - *valp;
1929 return xstrdup (ptr);
1931 # undef my_whitespace
1936 /* Return the current position of an rcsbuf. */
1938 static unsigned long
1939 rcsbuf_ftell (rcsbuf)
1940 struct rcsbuffer *rcsbuf;
1942 return rcsbuf->pos + rcsbuf->ptr - rcsbuf_buffer;
1945 /* Return a pointer to any data buffered for RCSBUF, along with the
1949 rcsbuf_get_buffered (rcsbuf, datap, lenp)
1950 struct rcsbuffer *rcsbuf;
1954 *datap = rcsbuf->ptr;
1955 *lenp = rcsbuf->ptrend - rcsbuf->ptr;
1958 /* CVS optimizes by quickly reading some header information from a
1959 file. If it decides it needs to do more with the file, it reopens
1960 it. We speed that up here by maintaining a cache of a single open
1961 file, to save the time it takes to reopen the file in the common
1964 static RCSNode *cached_rcs;
1965 static struct rcsbuffer cached_rcsbuf;
1967 /* Cache RCS and RCSBUF. This takes responsibility for closing
1971 rcsbuf_cache (rcs, rcsbuf)
1973 struct rcsbuffer *rcsbuf;
1975 if (cached_rcs != NULL)
1976 rcsbuf_cache_close ();
1979 cached_rcsbuf = *rcsbuf;
1982 /* If there is anything in the cache, close it. */
1985 rcsbuf_cache_close ()
1987 if (cached_rcs != NULL)
1989 rcsbuf_close (&cached_rcsbuf);
1990 if (fclose (cached_rcsbuf.fp) != 0)
1991 error (0, errno, "cannot close %s", cached_rcsbuf.filename);
1992 freercsnode (&cached_rcs);
1997 /* Open an rcsbuffer for RCS, getting it from the cache if possible.
1998 Set *FPP to the file, and *RCSBUFP to the rcsbuf. The file should
1999 be put at position POS. */
2002 rcsbuf_cache_open (rcs, pos, pfp, prcsbuf)
2006 struct rcsbuffer *prcsbuf;
2009 if (cached_rcs == rcs)
2011 if (rcsbuf_ftell (&cached_rcsbuf) != pos)
2013 if (fseek (cached_rcsbuf.fp, pos, SEEK_SET) != 0)
2014 error (1, 0, "cannot fseek RCS file %s",
2015 cached_rcsbuf.filename);
2016 cached_rcsbuf.ptr = rcsbuf_buffer;
2017 cached_rcsbuf.ptrend = rcsbuf_buffer;
2018 cached_rcsbuf.pos = pos;
2020 *pfp = cached_rcsbuf.fp;
2022 /* When RCS_parse opens a file using fopen_case, it frees the
2023 filename which we cached in CACHED_RCSBUF and stores a new
2024 file name in RCS->PATH. We avoid problems here by always
2025 copying the filename over. FIXME: This is hackish. */
2026 cached_rcsbuf.filename = rcs->path;
2028 *prcsbuf = cached_rcsbuf;
2032 /* Removing RCS from the cache removes a reference to it. */
2034 if (rcs->refcount <= 0)
2035 error (1, 0, "rcsbuf_cache_open: internal error");
2039 #endif /* ifndef HAVE_MMAP */
2040 /* FIXME: If these routines can be rewritten to not write to the
2041 * rcs file buffer, there would be a considerably larger memory savings
2042 * from using mmap since the shared file would never need be copied to
2045 * If this happens, cached mmapped buffers would be usable, but don't
2046 * forget to make sure rcs->pos < pos here...
2048 if (cached_rcs != NULL)
2049 rcsbuf_cache_close ();
2051 *pfp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ);
2053 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 #endif /* ifndef HAVE_MMAP */
2061 rcsbuf_open (prcsbuf, *pfp, rcs->path, pos);
2064 #endif /* ifndef HAVE_MMAP */
2069 * process the symbols list of the rcs file
2072 do_symbols (list, val)
2082 /* skip leading whitespace */
2083 while (whitespace (*cp))
2086 /* if we got to the end, we are done */
2090 /* split it up into tag and rev */
2092 cp = strchr (cp, ':');
2095 while (!whitespace (*cp) && *cp != '\0')
2100 /* make a new node and add it to the list */
2102 p->key = xstrdup (tag);
2103 p->data = xstrdup (rev);
2104 (void) addnode (list, p);
2109 * process the locks list of the rcs file
2110 * Like do_symbols, but hash entries are keyed backwards: i.e.
2111 * an entry like `user:rev' is keyed on REV rather than on USER.
2114 do_locks (list, val)
2124 /* skip leading whitespace */
2125 while (whitespace (*cp))
2128 /* if we got to the end, we are done */
2132 /* split it up into user and rev */
2134 cp = strchr (cp, ':');
2137 while (!whitespace (*cp) && *cp != '\0')
2142 /* make a new node and add it to the list */
2144 p->key = xstrdup (rev);
2145 p->data = xstrdup (user);
2146 (void) addnode (list, p);
2151 * process the branches list of a revision delta
2154 do_branches (list, val)
2164 /* skip leading whitespace */
2165 while (whitespace (*cp))
2168 /* if we got to the end, we are done */
2172 /* find the end of this branch */
2174 while (!whitespace (*cp) && *cp != '\0')
2179 /* make a new node and add it to the list */
2181 p->key = xstrdup (branch);
2182 (void) addnode (list, p);
2189 * Returns the requested version number of the RCS file, satisfying tags and/or
2190 * dates, and walking branches, if necessary.
2192 * The result is returned; null-string if error.
2195 RCS_getversion (rcs, tag, date, force_tag_match, simple_tag)
2199 int force_tag_match;
2202 if (simple_tag != NULL)
2205 /* make sure we have something to look at... */
2206 assert (rcs != NULL);
2212 if (! RCS_nodeisbranch (rcs, tag))
2214 /* We can't get a particular date if the tag is not a
2219 /* Work out the branch. */
2220 if (! isdigit ((unsigned char) tag[0]))
2221 branch = RCS_whatbranch (rcs, tag);
2223 branch = xstrdup (tag);
2225 /* Fetch the revision of branch as of date. */
2226 rev = RCS_getdatebranch (rcs, date, branch);
2231 return RCS_gettag (rcs, tag, force_tag_match, simple_tag);
2233 return RCS_getdate (rcs, date, force_tag_match);
2235 return RCS_head (rcs);
2242 * Get existing revision number corresponding to tag or revision.
2243 * Similar to RCS_gettag but less interpretation imposed.
2245 * -- If tag designates a magic branch, RCS_tag2rev
2246 * returns the magic branch number.
2247 * -- If tag is a branch tag, returns the branch number, not
2248 * the revision of the head of the branch.
2249 * If tag or revision is not valid or does not exist in file,
2253 RCS_tag2rev (rcs, tag)
2257 char *rev, *pa, *pb;
2260 assert (rcs != NULL);
2262 if (rcs->flags & PARTIAL)
2263 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2265 /* If a valid revision, try to look it up */
2266 if ( RCS_valid_rev (tag) )
2268 /* Make a copy so we can scribble on it */
2269 rev = xstrdup (tag);
2271 /* If revision exists, return the copy */
2272 if (RCS_exist_rev (rcs, tag))
2275 /* Nope, none such. If tag is not a branch we're done. */
2279 pa = strrchr (rev, '.');
2280 if (i == 1 || *(pa-1) != RCS_MAGIC_BRANCH || *(pa-2) != '.')
2283 error (1, 0, "revision `%s' does not exist", tag);
2287 /* Try for a real (that is, exists in the RCS deltas) branch
2288 (RCS_exist_rev just checks for real revisions and revisions
2289 which have tags pointing to them). */
2290 pa = RCS_getbranch (rcs, rev, 1);
2297 /* Tag is branch, but does not exist, try corresponding
2300 * FIXME: assumes all magic branches are of
2301 * form "n.n.n ... .0.n". I'll fix if somebody can
2302 * send me a method to get a magic branch tag with
2303 * the 0 in some other position -- <dan@gasboy.com>
2305 pa = strrchr (rev, '.');
2306 pb = xmalloc (strlen (rev) + 3);
2308 (void) sprintf (pb, "%s.%d.%s", rev, RCS_MAGIC_BRANCH, pa);
2311 if (RCS_exist_rev (rcs, rev))
2313 error (1, 0, "revision `%s' does not exist", tag);
2317 RCS_check_tag (tag); /* exit if not a valid tag */
2319 /* If tag is "HEAD", special case to get head RCS revision */
2320 if (tag && STREQ (tag, TAG_HEAD))
2321 return (RCS_head (rcs));
2323 /* If valid tag let translate_symtag say yea or nay. */
2324 rev = translate_symtag (rcs, tag);
2329 /* Trust the caller to print warnings. */
2334 * Find the revision for a specific tag.
2335 * If force_tag_match is set, return NULL if an exact match is not
2336 * possible otherwise return RCS_head (). We are careful to look for
2337 * and handle "magic" revisions specially.
2339 * If the matched tag is a branch tag, find the head of the branch.
2341 * Returns pointer to newly malloc'd string, or NULL.
2344 RCS_gettag (rcs, symtag, force_tag_match, simple_tag)
2347 int force_tag_match;
2352 if (simple_tag != NULL)
2355 /* make sure we have something to look at... */
2356 assert (rcs != NULL);
2358 /* XXX this is probably not necessary, --jtc */
2359 if (rcs->flags & PARTIAL)
2360 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2362 /* If symtag is "HEAD", special case to get head RCS revision */
2363 if (symtag && STREQ (symtag, TAG_HEAD))
2364 #if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */
2365 if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
2366 return ((char *) NULL); /* head request for removed file */
2369 return RCS_head (rcs);
2371 if (!isdigit ((unsigned char) symtag[0]))
2375 /* If we got a symbolic tag, resolve it to a numeric */
2376 version = translate_symtag (rcs, symtag);
2377 if (version != NULL)
2380 char *magic, *branch, *cp;
2385 * If this is a magic revision, we turn it into either its
2386 * physical branch equivalent (if one exists) or into
2387 * its base revision, which we assume exists.
2389 dots = numdots (tag);
2390 if (dots > 2 && (dots & 1) != 0)
2392 branch = strrchr (tag, '.');
2397 /* see if we have .magic-branch. (".0.") */
2398 magic = xmalloc (strlen (tag) + 1);
2399 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2400 if (strncmp (magic, cp, strlen (magic)) == 0)
2402 /* it's magic. See if the branch exists */
2403 *cp = '\0'; /* turn it into a revision */
2404 (void) sprintf (magic, "%s.%s", tag, branch);
2405 branch = RCS_getbranch (rcs, magic, 1);
2419 /* The tag wasn't there, so return the head or NULL */
2420 if (force_tag_match)
2423 return RCS_head (rcs);
2427 tag = xstrdup (symtag);
2429 /* tag is always allocated and numeric now. */
2432 * numeric tag processing:
2433 * 1) revision number - just return it
2434 * 2) branch number - find head of branch
2437 /* strip trailing dots */
2438 while (tag[strlen (tag) - 1] == '.')
2439 tag[strlen (tag) - 1] = '\0';
2441 if ((numdots (tag) & 1) == 0)
2445 /* we have a branch tag, so we need to walk the branch */
2446 branch = RCS_getbranch (rcs, tag, force_tag_match);
2454 /* we have a revision tag, so make sure it exists */
2455 p = findnode (rcs->versions, tag);
2458 /* We have found a numeric revision for the revision tag.
2459 To support expanding the RCS keyword Name, if
2460 SIMPLE_TAG is not NULL, tell the the caller that this
2461 is a simple tag which co will recognize. FIXME: Are
2462 there other cases in which we should set this? In
2463 particular, what if we expand RCS keywords internally
2464 without calling co? */
2465 if (simple_tag != NULL)
2471 /* The revision wasn't there, so return the head or NULL */
2473 if (force_tag_match)
2476 return RCS_head (rcs);
2482 * Return a "magic" revision as a virtual branch off of REV for the RCS file.
2483 * A "magic" revision is one which is unique in the RCS file. By unique, I
2484 * mean we return a revision which:
2485 * - has a branch of 0 (see rcs.h RCS_MAGIC_BRANCH)
2486 * - has a revision component which is not an existing branch off REV
2487 * - has a revision component which is not an existing magic revision
2488 * - is an even-numbered revision, to avoid conflicts with vendor branches
2489 * The first point is what makes it "magic".
2491 * As an example, if we pass in 1.37 as REV, we will look for an existing
2492 * branch called 1.37.2. If it did not exist, we would look for an
2493 * existing symbolic tag with a numeric part equal to 1.37.0.2. If that
2494 * didn't exist, then we know that the 1.37.2 branch can be reserved by
2495 * creating a symbolic tag with 1.37.0.2 as the numeric part.
2497 * This allows us to fork development with very little overhead -- just a
2498 * symbolic tag is used in the RCS file. When a commit is done, a physical
2499 * branch is dynamically created to hold the new revision.
2501 * Note: We assume that REV is an RCS revision and not a branch number.
2503 static char *check_rev;
2505 RCS_magicrev (rcs, rev)
2510 char *xrev, *test_branch, *local_branch_num;
2512 xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */
2515 local_branch_num = getenv("CVS_LOCAL_BRANCH_NUM");
2516 if (local_branch_num)
2518 rev_num = atoi(local_branch_num);
2527 /* only look at even numbered branches */
2528 for ( ; ; rev_num += 2)
2530 /* see if the physical branch exists */
2531 (void) sprintf (xrev, "%s.%d", rev, rev_num);
2532 test_branch = RCS_getbranch (rcs, xrev, 1);
2533 if (test_branch != NULL) /* it did, so keep looking */
2539 /* now, create a "magic" revision */
2540 (void) sprintf (xrev, "%s.%d.%d", rev, RCS_MAGIC_BRANCH, rev_num);
2542 /* walk the symbols list to see if a magic one already exists */
2543 if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0)
2546 /* we found a free magic branch. Claim it as ours */
2552 * walklist proc to look for a match in the symbols list.
2553 * Returns 0 if the symbol does not match, 1 if it does.
2556 checkmagic_proc (p, closure)
2560 if (STREQ (check_rev, p->data))
2567 * Given an RCSNode, returns non-zero if the specified revision number
2568 * or symbolic tag resolves to a "branch" within the rcs file.
2570 * FIXME: this is the same as RCS_nodeisbranch except for the special
2571 * case for handling a null rcsnode.
2574 RCS_isbranch (rcs, rev)
2578 /* numeric revisions are easy -- even number of dots is a branch */
2579 if (isdigit ((unsigned char) *rev))
2580 return ((numdots (rev) & 1) == 0);
2582 /* assume a revision if you can't find the RCS info */
2586 /* now, look for a match in the symbols list */
2587 return (RCS_nodeisbranch (rcs, rev));
2591 * Given an RCSNode, returns non-zero if the specified revision number
2592 * or symbolic tag resolves to a "branch" within the rcs file. We do
2593 * take into account any magic branches as well.
2596 RCS_nodeisbranch (rcs, rev)
2603 assert (rcs != NULL);
2605 /* numeric revisions are easy -- even number of dots is a branch */
2606 if (isdigit ((unsigned char) *rev))
2607 return ((numdots (rev) & 1) == 0);
2609 version = translate_symtag (rcs, rev);
2610 if (version == NULL)
2612 dots = numdots (version);
2613 if ((dots & 1) == 0)
2619 /* got a symbolic tag match, but it's not a branch; see if it's magic */
2623 char *branch = strrchr (version, '.');
2624 char *cp = branch - 1;
2628 /* see if we have .magic-branch. (".0.") */
2629 magic = xmalloc (strlen (version) + 1);
2630 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2631 if (strncmp (magic, cp, strlen (magic)) == 0)
2644 * Returns a pointer to malloc'ed memory which contains the branch
2645 * for the specified *symbolic* tag. Magic branches are handled correctly.
2648 RCS_whatbranch (rcs, rev)
2655 /* assume no branch if you can't find the RCS info */
2657 return ((char *) NULL);
2659 /* now, look for a match in the symbols list */
2660 version = translate_symtag (rcs, rev);
2661 if (version == NULL)
2662 return ((char *) NULL);
2663 dots = numdots (version);
2664 if ((dots & 1) == 0)
2667 /* got a symbolic tag match, but it's not a branch; see if it's magic */
2671 char *branch = strrchr (version, '.');
2672 char *cp = branch++ - 1;
2676 /* see if we have .magic-branch. (".0.") */
2677 magic = xmalloc (strlen (version) + 1);
2678 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2679 if (strncmp (magic, cp, strlen (magic)) == 0)
2681 /* yep. it's magic. now, construct the real branch */
2682 *cp = '\0'; /* turn it into a revision */
2683 (void) sprintf (magic, "%s.%s", version, branch);
2690 return ((char *) NULL);
2694 * Get the head of the specified branch. If the branch does not exist,
2695 * return NULL or RCS_head depending on force_tag_match.
2696 * Returns NULL or a newly malloc'd string.
2699 RCS_getbranch (rcs, tag, force_tag_match)
2702 int force_tag_match;
2710 /* make sure we have something to look at... */
2711 assert (rcs != NULL);
2713 if (rcs->flags & PARTIAL)
2714 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2716 /* find out if the tag contains a dot, or is on the trunk */
2717 cp = strrchr (tag, '.');
2719 /* trunk processing is the special case */
2722 xtag = xmalloc (strlen (tag) + 1 + 1); /* +1 for an extra . */
2723 (void) strcpy (xtag, tag);
2724 (void) strcat (xtag, ".");
2725 for (cp = rcs->head; cp != NULL;)
2727 if (strncmp (xtag, cp, strlen (xtag)) == 0)
2729 p = findnode (rcs->versions, cp);
2733 if (force_tag_match)
2736 return (RCS_head (rcs));
2744 if (force_tag_match)
2747 return (RCS_head (rcs));
2749 return (xstrdup (cp));
2752 /* if it had a `.', terminate the string so we have the base revision */
2755 /* look up the revision this branch is based on */
2756 p = findnode (rcs->versions, tag);
2758 /* put the . back so we have the branch again */
2763 /* if the base revision didn't exist, return head or NULL */
2764 if (force_tag_match)
2767 return (RCS_head (rcs));
2770 /* find the first element of the branch we are looking for */
2772 if (vn->branches == NULL)
2774 xtag = xmalloc (strlen (tag) + 1 + 1); /* 1 for the extra '.' */
2775 (void) strcpy (xtag, tag);
2776 (void) strcat (xtag, ".");
2777 head = vn->branches->list;
2778 for (p = head->next; p != head; p = p->next)
2779 if (strncmp (p->key, xtag, strlen (xtag)) == 0)
2785 /* we didn't find a match so return head or NULL */
2786 if (force_tag_match)
2789 return (RCS_head (rcs));
2792 /* now walk the next pointers of the branch */
2796 p = findnode (rcs->versions, nextvers);
2799 /* a link in the chain is missing - return head or NULL */
2800 if (force_tag_match)
2803 return (RCS_head (rcs));
2806 nextvers = vn->next;
2807 } while (nextvers != NULL);
2809 /* we have the version in our hand, so go for it */
2810 return (xstrdup (vn->version));
2813 /* Returns the head of the branch which REV is on. REV can be a
2814 branch tag or non-branch tag; symbolic or numeric.
2816 Returns a newly malloc'd string. Returns NULL if a symbolic name
2820 RCS_branch_head (rcs, rev)
2828 assert (rcs != NULL);
2830 if (RCS_nodeisbranch (rcs, rev))
2831 return RCS_getbranch (rcs, rev, 1);
2833 if (isdigit ((unsigned char) *rev))
2834 num = xstrdup (rev);
2837 num = translate_symtag (rcs, rev);
2841 br = truncate_revnum (num);
2842 retval = RCS_getbranch (rcs, br, 1);
2848 /* Get the branch point for a particular branch, that is the first
2849 revision on that branch. For example, RCS_getbranchpoint (rcs,
2850 "1.3.2") will normally return "1.3.2.1". TARGET may be either a
2851 branch number or a revision number; if a revnum, find the
2852 branchpoint of the branch to which TARGET belongs.
2854 Return RCS_head if TARGET is on the trunk or if the root node could
2855 not be found (this is sort of backwards from our behavior on a branch;
2856 the rationale is that the return value is a revision from which you
2857 can start walking the next fields and end up at TARGET).
2858 Return NULL on error. */
2861 RCS_getbranchpoint (rcs, target)
2868 int dots, isrevnum, brlen;
2870 dots = numdots (target);
2871 isrevnum = dots & 1;
2874 /* TARGET is a trunk revision; return rcs->head. */
2875 return (RCS_head (rcs));
2877 /* Get the revision number of the node at which TARGET's branch is
2878 rooted. If TARGET is a branch number, lop off the last field;
2879 if it's a revision number, lop off the last *two* fields. */
2880 branch = xstrdup (target);
2881 bp = strrchr (branch, '.');
2883 error (1, 0, "%s: confused revision number %s",
2886 while (*--bp != '.')
2890 vp = findnode (rcs->versions, branch);
2893 error (0, 0, "%s: can't find branch point %s", rcs->path, target);
2899 while (*bp && *bp != '.')
2901 brlen = bp - branch;
2903 vp = rev->branches->list->next;
2904 while (vp != rev->branches->list)
2906 /* BRANCH may be a genuine branch number, e.g. `1.1.3', or
2907 maybe a full revision number, e.g. `1.1.3.6'. We have
2908 found our branch point if the first BRANCHLEN characters
2909 of the revision number match, *and* if the following
2910 character is a dot. */
2911 if (strncmp (vp->key, branch, brlen) == 0 && vp->key[brlen] == '.')
2917 if (vp == rev->branches->list)
2919 error (0, 0, "%s: can't find branch point %s", rcs->path, target);
2923 return (xstrdup (vp->key));
2927 * Get the head of the RCS file. If branch is set, this is the head of the
2928 * branch, otherwise the real head.
2929 * Returns NULL or a newly malloc'd string.
2935 /* make sure we have something to look at... */
2936 assert (rcs != NULL);
2939 * NOTE: we call getbranch with force_tag_match set to avoid any
2940 * possibility of recursion
2943 return (RCS_getbranch (rcs, rcs->branch, 1));
2945 return (xstrdup (rcs->head));
2949 * Get the most recent revision, based on the supplied date, but use some
2950 * funky stuff and follow the vendor branch maybe
2953 RCS_getdate (rcs, date, force_tag_match)
2956 int force_tag_match;
2958 char *cur_rev = NULL;
2959 char *retval = NULL;
2961 RCSVers *vers = NULL;
2963 /* make sure we have something to look at... */
2964 assert (rcs != NULL);
2966 if (rcs->flags & PARTIAL)
2967 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2969 /* if the head is on a branch, try the branch first */
2970 if (rcs->branch != NULL)
2972 retval = RCS_getdatebranch (rcs, date, rcs->branch);
2977 /* otherwise if we have a trunk, try it */
2980 p = findnode (rcs->versions, rcs->head);
2983 error (0, 0, "%s: head revision %s doesn't exist", rcs->path,
2988 /* if the date of this one is before date, take it */
2990 if (RCS_datecmp (vers->date, date) <= 0)
2992 cur_rev = vers->version;
2996 /* if there is a next version, find the node */
2997 if (vers->next != NULL)
2998 p = findnode (rcs->versions, vers->next);
3004 error (0, 0, "%s: no head revision", rcs->path);
3007 * at this point, either we have the revision we want, or we have the
3008 * first revision on the trunk (1.1?) in our hands, or we've come up
3012 /* if we found what we're looking for, and it's not 1.1 return it */
3013 if (cur_rev != NULL)
3015 if (! STREQ (cur_rev, "1.1"))
3016 return (xstrdup (cur_rev));
3018 /* This is 1.1; if the date of 1.1 is not the same as that for the
3019 1.1.1.1 version, then return 1.1. This happens when the first
3020 version of a file is created by a regular cvs add and commit,
3021 and there is a subsequent cvs import of the same file. */
3022 p = findnode (rcs->versions, "1.1.1.1");
3025 char *date_1_1 = vers->date;
3028 if (RCS_datecmp (vers->date, date_1_1) != 0)
3029 return xstrdup ("1.1");
3033 /* look on the vendor branch */
3034 retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
3037 * if we found a match, return it; otherwise, we return the first
3038 * revision on the trunk or NULL depending on force_tag_match and the
3039 * date of the first rev
3044 if (vers && (!force_tag_match || RCS_datecmp (vers->date, date) <= 0))
3045 return xstrdup (vers->version);
3053 * Look up the last element on a branch that was put in before the specified
3054 * date (return the rev or NULL)
3057 RCS_getdatebranch (rcs, date, branch)
3062 char *cur_rev = NULL;
3064 char *xbranch, *xrev;
3068 /* look up the first revision on the branch */
3069 xrev = xstrdup (branch);
3070 cp = strrchr (xrev, '.');
3076 *cp = '\0'; /* turn it into a revision */
3078 assert (rcs != NULL);
3080 if (rcs->flags & PARTIAL)
3081 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3083 p = findnode (rcs->versions, xrev);
3089 /* Tentatively use this revision, if it is early enough. */
3090 if (RCS_datecmp (vers->date, date) <= 0)
3091 cur_rev = vers->version;
3093 /* If no branches list, return now. This is what happens if the branch
3094 is a (magic) branch with no revisions yet. */
3095 if (vers->branches == NULL)
3096 return xstrdup (cur_rev);
3098 /* walk the branches list looking for the branch number */
3099 xbranch = xmalloc (strlen (branch) + 1 + 1); /* +1 for the extra dot */
3100 (void) strcpy (xbranch, branch);
3101 (void) strcat (xbranch, ".");
3102 for (p = vers->branches->list->next; p != vers->branches->list; p = p->next)
3103 if (strncmp (p->key, xbranch, strlen (xbranch)) == 0)
3106 if (p == vers->branches->list)
3108 /* This is what happens if the branch is a (magic) branch with
3109 no revisions yet. Similar to the case where vers->branches ==
3110 NULL, except here there was a another branch off the same
3112 return xstrdup (cur_rev);
3115 p = findnode (rcs->versions, p->key);
3117 /* walk the next pointers until you find the end, or the date is too late */
3121 if (RCS_datecmp (vers->date, date) <= 0)
3122 cur_rev = vers->version;
3126 /* if there is a next version, find the node */
3127 if (vers->next != NULL)
3128 p = findnode (rcs->versions, vers->next);
3133 /* Return whatever we found, which may be NULL. */
3134 return xstrdup (cur_rev);
3140 * Compare two dates in RCS format. Beware the change in format on January 1,
3141 * 2000, when years go from 2-digit to full format.
3144 RCS_datecmp (date1, date2)
3145 const char *date1, *date2;
3147 int length_diff = strlen (date1) - strlen (date2);
3149 return length_diff ? length_diff : strcmp (date1, date2);
3154 /* Look up revision REV in RCS and return the date specified for the
3155 revision minus FUDGE seconds (FUDGE will generally be one, so that the
3156 logically previous revision will be found later, or zero, if we want
3159 The return value is the date being returned as a time_t, or (time_t)-1
3160 on error (previously was documented as zero on error; I haven't checked
3161 the callers to make sure that they really check for (time_t)-1, but
3162 the latter is what this function really returns). If DATE is non-NULL,
3163 then it must point to MAXDATELEN characters, and we store the same
3164 return value there in DATEFORM format. */
3166 RCS_getrevtime (rcs, rev, date, fudge)
3172 char tdate[MAXDATELEN];
3173 struct tm xtm, *ftm;
3178 /* make sure we have something to look at... */
3179 assert (rcs != NULL);
3181 if (rcs->flags & PARTIAL)
3182 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3184 /* look up the revision */
3185 p = findnode (rcs->versions, rev);
3190 /* split up the date */
3191 if (sscanf (vers->date, SDATEFORM, &xtm.tm_year, &xtm.tm_mon,
3192 &xtm.tm_mday, &xtm.tm_hour, &xtm.tm_min, &xtm.tm_sec) != 6)
3193 error (1, 0, "%s: invalid date for revision %s (%s)", rcs->path,
3196 /* If the year is from 1900 to 1999, RCS files contain only two
3197 digits, and sscanf gives us a year from 0-99. If the year is
3198 2000+, RCS files contain all four digits and we subtract 1900,
3199 because the tm_year field should contain years since 1900. */
3201 if (xtm.tm_year >= 100 && xtm.tm_year < 2000)
3202 error (0, 0, "%s: non-standard date format for revision %s (%s)",
3203 rcs->path, rev, vers->date);
3204 if (xtm.tm_year >= 1900)
3205 xtm.tm_year -= 1900;
3207 /* put the date in a form getdate can grok */
3208 (void) sprintf (tdate, "%d/%d/%d GMT %d:%d:%d", xtm.tm_mon,
3209 xtm.tm_mday, xtm.tm_year + 1900, xtm.tm_hour,
3210 xtm.tm_min, xtm.tm_sec);
3212 /* turn it into seconds since the epoch */
3213 revdate = get_date (tdate, (struct timeb *) NULL);
3214 if (revdate != (time_t) -1)
3216 revdate -= fudge; /* remove "fudge" seconds */
3219 /* put an appropriate string into ``date'' if we were given one */
3220 ftm = gmtime (&revdate);
3221 (void) sprintf (date, DATEFORM,
3222 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
3223 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
3224 ftm->tm_min, ftm->tm_sec);
3234 assert(rcs != NULL);
3236 if (rcs->flags & PARTIAL)
3237 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3239 if (rcs->locks_data) {
3240 rcs->locks = getlist ();
3241 do_locks (rcs->locks, rcs->locks_data);
3242 free(rcs->locks_data);
3243 rcs->locks_data = NULL;
3253 assert(rcs != NULL);
3255 if (rcs->flags & PARTIAL)
3256 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3258 if (rcs->symbols_data) {
3259 rcs->symbols = getlist ();
3260 do_symbols (rcs->symbols, rcs->symbols_data);
3261 free(rcs->symbols_data);
3262 rcs->symbols_data = NULL;
3265 return rcs->symbols;
3269 * Return the version associated with a particular symbolic tag.
3270 * Returns NULL or a newly malloc'd string.
3273 translate_symtag (rcs, tag)
3277 if (rcs->flags & PARTIAL)
3278 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3280 if (rcs->symbols != NULL)
3284 /* The symbols have already been converted into a list. */
3285 p = findnode (rcs->symbols, tag);
3289 return xstrdup (p->data);
3292 if (rcs->symbols_data != NULL)
3297 /* Look through the RCS symbols information. This is like
3298 do_symbols, but we don't add the information to a list. In
3299 most cases, we will only be called once for this file, so
3300 generating the list is unnecessary overhead. */
3303 cp = rcs->symbols_data;
3304 while ((cp = strchr (cp, tag[0])) != NULL)
3306 if ((cp == rcs->symbols_data || whitespace (cp[-1]))
3307 && strncmp (cp, tag, len) == 0
3312 /* We found the tag. Return the version number. */
3316 while (! whitespace (*cp) && *cp != '\0')
3318 r = xmalloc (cp - v + 1);
3319 strncpy (r, v, cp - v);
3324 while (! whitespace (*cp) && *cp != '\0')
3335 * The argument ARG is the getopt remainder of the -k option specified on the
3336 * command line. This function returns malloc'ed space that can be used
3337 * directly in calls to RCS V5, with the -k flag munged correctly.
3340 RCS_check_kflag (arg)
3343 static const char *const keyword_usage[] =
3345 "%s %s: invalid RCS keyword expansion mode\n",
3346 "Valid expansion modes include:\n",
3347 " -kkv\tGenerate keywords using the default form.\n",
3348 " -kkvl\tLike -kkv, except locker's name inserted.\n",
3349 " -kk\tGenerate only keyword names in keyword strings.\n",
3350 " -kv\tGenerate only keyword values in keyword strings.\n",
3351 " -ko\tGenerate the old keyword string (no changes from checked in file).\n",
3352 " -kb\tGenerate binary file unmodified (merges not allowed) (RCS 5.7).\n",
3353 "(Specify the --help global option for a list of other help options)\n",
3356 /* Big enough to hold any of the strings from kflags. */
3358 char const *const *cpp = NULL;
3362 for (cpp = kflags; *cpp != NULL; cpp++)
3364 if (STREQ (arg, *cpp))
3369 if (arg == NULL || *cpp == NULL)
3371 usage (keyword_usage);
3374 (void) sprintf (karg, "-k%s", *cpp);
3375 return (xstrdup (karg));
3379 * Do some consistency checks on the symbolic tag... These should equate
3380 * pretty close to what RCS checks, though I don't know for certain.
3386 char *invalid = "$,.:;@"; /* invalid RCS tag characters */
3390 * The first character must be an alphabetic letter. The remaining
3391 * characters cannot be non-visible graphic characters, and must not be
3392 * in the set of "invalid" RCS identifier characters.
3394 if (isalpha ((unsigned char) *tag))
3396 for (cp = tag; *cp; cp++)
3398 if (!isgraph ((unsigned char) *cp))
3399 error (1, 0, "tag `%s' has non-visible graphic characters",
3401 if (strchr (invalid, *cp))
3402 error (1, 0, "tag `%s' must not contain the characters `%s'",
3407 error (1, 0, "tag `%s' must start with a letter", tag);
3411 * TRUE if argument has valid syntax for an RCS revision or
3412 * branch number. All characters must be digits or dots, first
3413 * and last characters must be digits, and no two consecutive
3414 * characters may be dots.
3416 * Intended for classifying things, so this function doesn't
3425 if (!isdigit ((unsigned char) last))
3427 while ((c = *rev++)) /* Extra parens placate -Wall gcc option */
3436 if (!isdigit ((unsigned char) c))
3439 if (!isdigit ((unsigned char) last))
3445 * Return true if RCS revision with TAG is a dead revision.
3448 RCS_isdead (rcs, tag)
3455 if (rcs->flags & PARTIAL)
3456 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3458 p = findnode (rcs->versions, tag);
3463 return (version->dead);
3466 /* Return the RCS keyword expansion mode. For example "b" for binary.
3467 Returns a pointer into storage which is allocated and freed along with
3468 the rest of the RCS information; the caller should not modify this
3469 storage. Returns NULL if the RCS file does not specify a keyword
3470 expansion mode; for all other errors, die with a fatal error. */
3475 /* Since RCS_parsercsfile_i now reads expand, don't need to worry
3476 about RCS_reparsercsfile. */
3477 assert (rcs != NULL);
3481 /* Set keyword expansion mode to EXPAND. For example "b" for binary. */
3483 RCS_setexpand (rcs, expand)
3487 /* Since RCS_parsercsfile_i now reads expand, don't need to worry
3488 about RCS_reparsercsfile. */
3489 assert (rcs != NULL);
3490 if (rcs->expand != NULL)
3492 rcs->expand = xstrdup (expand);
3495 /* RCS keywords, and a matching enum. */
3502 #define KEYWORD_INIT(s) (s), sizeof (s) - 1
3503 static struct rcs_keyword keywords[] =
3505 { KEYWORD_INIT ("Author"), 1 },
3506 { KEYWORD_INIT ("Date"), 1 },
3507 { KEYWORD_INIT ("CVSHeader"), 1 },
3508 { KEYWORD_INIT ("Header"), 1 },
3509 { KEYWORD_INIT ("Id"), 1 },
3510 { KEYWORD_INIT ("Locker"), 1 },
3511 { KEYWORD_INIT ("Log"), 1 },
3512 { KEYWORD_INIT ("Name"), 1 },
3513 { KEYWORD_INIT ("RCSfile"), 1 },
3514 { KEYWORD_INIT ("Revision"), 1 },
3515 { KEYWORD_INIT ("Source"), 1 },
3516 { KEYWORD_INIT ("State"), 1 },
3536 enum keyword keyword_local = KEYWORD_ID;
3538 /* Convert an RCS date string into a readable string. This is like
3539 the RCS date2str function. */
3542 printable_date (rcs_date)
3543 const char *rcs_date;
3545 int year, mon, mday, hour, min, sec;
3548 (void) sscanf (rcs_date, SDATEFORM, &year, &mon, &mday, &hour, &min,
3552 sprintf (buf, "%04d%c%02d%c%02d %02d:%02d:%02d",
3553 year, datesep, mon, datesep, mday, hour, min, sec);
3554 return xstrdup (buf);
3557 /* Escape the characters in a string so that it can be included in an
3561 escape_keyword_value (value, free_value)
3568 for (s = value; *s != '\0'; s++)
3586 return (char *) value;
3589 ret = xmalloc (strlen (value) * 4 + 1);
3592 for (s = value, t = ret; *s != '\0'; s++, t++)
3631 /* Expand RCS keywords in the memory buffer BUF of length LEN. This
3632 applies to file RCS and version VERS. If NAME is not NULL, and is
3633 not a numeric revision, then it is the symbolic tag used for the
3634 checkout. EXPAND indicates how to expand the keywords. This
3635 function sets *RETBUF and *RETLEN to the new buffer and length.
3636 This function may modify the buffer BUF. If BUF != *RETBUF, then
3637 RETBUF is a newly allocated buffer. */
3640 expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
3652 struct expand_buffer
3654 struct expand_buffer *next;
3659 struct expand_buffer *ebuf_last = NULL;
3660 size_t ebuf_len = 0;
3662 char *srch, *srch_next;
3665 if (expand == KFLAG_O || expand == KFLAG_B)
3672 /* If we are using -kkvl, dig out the locker information if any. */
3674 if (expand == KFLAG_KVL)
3677 lock = findnode (RCS_getlocks(rcs), ver->version);
3679 locker = xstrdup (lock->data);
3682 /* RCS keywords look like $STRING$ or $STRING: VALUE$. */
3685 while ((srch_next = memchr (srch, '$', srch_len)) != NULL)
3689 const struct rcs_keyword *keyword;
3696 srch_len -= (srch_next + 1) - srch;
3697 srch = srch_next + 1;
3699 /* Look for the first non alphabetic character after the '$'. */
3700 send = srch + srch_len;
3701 for (s = srch; s < send; s++)
3702 if (! isalpha ((unsigned char) *s))
3705 /* If the first non alphabetic character is not '$' or ':',
3706 then this is not an RCS keyword. */
3707 if (s == send || (*s != '$' && *s != ':'))
3710 /* See if this is one of the keywords. */
3712 for (keyword = keywords; keyword->string != NULL; keyword++)
3714 if (keyword->expandit
3715 && keyword->len == slen
3716 && strncmp (keyword->string, srch, slen) == 0)
3721 if (keyword->string == NULL)
3724 kw = (enum keyword) (keyword - keywords);
3726 /* If the keyword ends with a ':', then the old value consists
3727 of the characters up to the next '$'. If there is no '$'
3728 before the end of the line, though, then this wasn't an RCS
3729 keyword after all. */
3732 for (; s < send; s++)
3733 if (*s == '$' || *s == '\n')
3735 if (s == send || *s != '$')
3739 /* At this point we must replace the string from SRCH to S
3740 with the expansion of the keyword KW. */
3742 /* Get the value to use. */
3744 if (expand == KFLAG_K)
3753 case KEYWORD_AUTHOR:
3754 value = ver->author;
3758 value = printable_date (ver->date);
3762 case KEYWORD_CVSHEADER:
3763 case KEYWORD_HEADER:
3765 case KEYWORD_LOCALID:
3773 if (kw == KEYWORD_HEADER ||
3774 (kw == KEYWORD_LOCALID &&
3775 keyword_local == KEYWORD_HEADER))
3777 else if (kw == KEYWORD_CVSHEADER ||
3778 (kw == KEYWORD_LOCALID &&
3779 keyword_local == KEYWORD_CVSHEADER))
3780 path = getfullCVSname(rcs->path, &old_path);
3782 path = last_component (rcs->path);
3783 path = escape_keyword_value (path, &free_path);
3784 date = printable_date (ver->date);
3785 value = xmalloc (strlen (path)
3786 + strlen (ver->version)
3788 + strlen (ver->author)
3789 + strlen (ver->state)
3790 + (locker == NULL ? 0 : strlen (locker))
3793 sprintf (value, "%s %s %s %s %s%s%s",
3794 path, ver->version, date, ver->author,
3796 locker != NULL ? " " : "",
3797 locker != NULL ? locker : "");
3799 /* If free_path is set then we know we allocated path
3800 * and we can discard the const.
3802 free ((char *)path);
3810 case KEYWORD_LOCKER:
3815 case KEYWORD_RCSFILE:
3816 value = escape_keyword_value (last_component (rcs->path),
3821 if (name != NULL && ! isdigit ((unsigned char) *name))
3822 value = (char *) name;
3827 case KEYWORD_REVISION:
3828 value = ver->version;
3831 case KEYWORD_SOURCE:
3832 value = escape_keyword_value (rcs->path, &free_value);
3841 sub = xmalloc (keyword->len
3842 + (value == NULL ? 0 : strlen (value))
3844 if (expand == KFLAG_V)
3846 /* Decrement SRCH and increment S to remove the $
3855 strcpy (sub, keyword->string);
3856 sublen = strlen (keyword->string);
3857 if (expand != KFLAG_K)
3860 sub[sublen + 1] = ' ';
3866 strcpy (sub + sublen, value);
3867 sublen += strlen (value);
3869 if (expand != KFLAG_V && expand != KFLAG_K)
3879 /* The Log keyword requires special handling. This behaviour
3880 is taken from RCS 5.7. The special log message is what RCS
3882 if (kw == KEYWORD_LOG
3883 && (sizeof "checked in with -k by " <= loglen
3885 || strncmp (log, "checked in with -k by ",
3886 sizeof "checked in with -k by " - 1) != 0))
3890 size_t leader_len, leader_sp_len;
3897 /* We are going to insert the trailing $ ourselves, before
3898 the log message, so we must remove it from S, if we
3899 haven't done so already. */
3900 if (expand != KFLAG_V)
3903 /* CVS never has empty log messages, but old RCS files might. */
3907 /* Find the start of the line. */
3909 while (start > buf && start[-1] != '\n')
3912 /* Copy the start of the line to use as a comment leader. */
3913 leader_len = srch - start;
3914 if (expand != KFLAG_V)
3916 leader = xmalloc (leader_len);
3917 memcpy (leader, start, leader_len);
3918 leader_sp_len = leader_len;
3919 while (leader_sp_len > 0 && leader[leader_sp_len - 1] == ' ')
3922 /* RCS does some checking for an old style of Log here,
3923 but we don't bother. RCS issues a warning if it
3924 changes anything. */
3926 /* Count the number of newlines in the log message so that
3927 we know how many copies of the leader we will need. */
3929 logend = log + loglen;
3930 for (snl = log; snl < logend; snl++)
3934 date = printable_date (ver->date);
3935 sub = xrealloc (sub,
3938 + strlen (ver->version)
3940 + strlen (ver->author)
3942 + (cnl + 2) * leader_len
3944 if (expand != KFLAG_V)
3951 memcpy (sub + sublen, leader, leader_len);
3952 sublen += leader_len;
3953 sprintf (sub + sublen, "Revision %s %s %s\n",
3954 ver->version, date, ver->author);
3955 sublen += strlen (sub + sublen);
3963 memcpy (sub + sublen, leader, leader_sp_len);
3964 sublen += leader_sp_len;
3973 memcpy (sub + sublen, leader, leader_len);
3974 sublen += leader_len;
3975 for (slnl = sl; slnl < logend && *slnl != '\n'; ++slnl)
3979 memcpy (sub + sublen, sl, slnl - sl);
3980 sublen += slnl - sl;
3985 memcpy (sub + sublen, leader, leader_sp_len);
3986 sublen += leader_sp_len;
3991 /* Now SUB contains a string which is to replace the string
3992 from SRCH to S. SUBLEN is the length of SUB. */
3994 if (srch + sublen == s)
3996 memcpy (srch, sub, sublen);
4001 struct expand_buffer *ebuf;
4003 /* We need to change the size of the buffer. We build a
4004 list of expand_buffer structures. Each expand_buffer
4005 structure represents a portion of the final output. We
4006 concatenate them back into a single buffer when we are
4007 done. This minimizes the number of potentially large
4008 buffer copies we must do. */
4012 ebufs = (struct expand_buffer *) xmalloc (sizeof *ebuf);
4015 ebufs->free_data = 0;
4016 ebuf_len = srch - buf;
4017 ebufs->len = ebuf_len;
4022 assert (srch >= ebuf_last->data);
4023 assert (srch <= ebuf_last->data + ebuf_last->len);
4024 ebuf_len -= ebuf_last->len - (srch - ebuf_last->data);
4025 ebuf_last->len = srch - ebuf_last->data;
4028 ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf);
4031 ebuf->free_data = 1;
4033 ebuf_last->next = ebuf;
4037 ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf);
4039 ebuf->len = srch_len - (s - srch);
4040 ebuf->free_data = 0;
4042 ebuf_last->next = ebuf;
4044 ebuf_len += srch_len - (s - srch);
4047 srch_len -= (s - srch);
4063 ret = xmalloc (ebuf_len);
4066 while (ebufs != NULL)
4068 struct expand_buffer *next;
4070 memcpy (ret, ebufs->data, ebufs->len);
4072 if (ebufs->free_data)
4083 /* Check out a revision from an RCS file.
4085 If PFN is not NULL, then ignore WORKFILE and SOUT. Call PFN zero
4086 or more times with the contents of the file. CALLERDAT is passed,
4087 uninterpreted, to PFN. (The current code will always call PFN
4088 exactly once for a non empty file; however, the current code
4089 assumes that it can hold the entire file contents in memory, which
4090 is not a good assumption, and might change in the future).
4092 Otherwise, if WORKFILE is not NULL, check out the revision to
4093 WORKFILE. However, if WORKFILE is not NULL, and noexec is set,
4094 then don't do anything.
4096 Otherwise, if WORKFILE is NULL, check out the revision to SOUT. If
4097 SOUT is RUN_TTY, then write the contents of the revision to
4098 standard output. When using SOUT, the output is generally a
4099 temporary file; don't bother to get the file modes correct.
4101 REV is the numeric revision to check out. It may be NULL, which
4102 means to check out the head of the default branch.
4104 If NAMETAG is not NULL, and is not a numeric revision, then it is
4105 the tag that should be used when expanding the RCS Name keyword.
4107 OPTIONS is a string such as "-kb" or "-kv" for keyword expansion
4108 options. It may be NULL to use the default expansion mode of the
4109 file, typically "-kkv".
4111 On an error which prevented checking out the file, either print a
4112 nonfatal error and return 1, or give a fatal error. On success,
4115 /* This function mimics the behavior of `rcs co' almost exactly. The
4116 chief difference is in its support for preserving file ownership,
4117 permissions, and special files across checkin and checkout -- see
4118 comments in RCS_checkin for some issues about this. -twp */
4121 RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
4123 const char *workfile;
4125 const char *nametag;
4126 const char *options;
4128 RCSCHECKOUTPROC pfn;
4135 struct rcsbuffer rcsbuf;
4143 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4144 uid_t rcs_owner = (uid_t) -1;
4145 gid_t rcs_group = (gid_t) -1;
4147 int change_rcs_owner_or_group = 0;
4148 int change_rcs_mode = 0;
4149 int special_file = 0;
4150 unsigned long devnum_long;
4156 (void) fprintf (stderr, "%s-> RCS_checkout (%s, %s, %s, %s, %s)\n",
4157 #ifdef SERVER_SUPPORT
4158 server_active ? "S" : " ",
4163 rev != NULL ? rev : "",
4164 nametag != NULL ? nametag : "",
4165 options != NULL ? options : "",
4166 (pfn != NULL ? "(function)"
4169 : (sout != RUN_TTY ? sout : "(stdout)"))));
4172 assert (rev == NULL || isdigit ((unsigned char) *rev));
4174 if (noexec && workfile != NULL)
4177 assert (sout == RUN_TTY || workfile == NULL);
4178 assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL));
4180 /* Some callers, such as Checkin or remove_file, will pass us a
4182 if (rev != NULL && (numdots (rev) & 1) == 0)
4184 rev = RCS_getbranch (rcs, rev, 1);
4186 error (1, 0, "internal error: bad branch tag in checkout");
4190 if (rev == NULL || STREQ (rev, rcs->head))
4194 /* We want the head revision. Try to read it directly. */
4196 if (rcs->flags & PARTIAL)
4197 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
4199 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf);
4202 if (! rcsbuf_getrevnum (&rcsbuf, &key))
4203 error (1, 0, "unexpected EOF reading %s", rcs->path);
4204 while (rcsbuf_getkey (&rcsbuf, &key, &value))
4206 if (STREQ (key, "log"))
4207 log = rcsbuf_valcopy (&rcsbuf, value, 0, &loglen);
4208 else if (STREQ (key, "text"))
4217 error (0, 0, "internal error: cannot find head text");
4219 /* It's okay to discard the const when free_rev is set, because
4220 * we know we allocated it in this function.
4226 rcsbuf_valpolish (&rcsbuf, value, 0, &len);
4228 if (fstat (fileno (fp), &sb) < 0)
4229 error (1, errno, "cannot fstat %s", rcs->path);
4231 rcsbuf_cache (rcs, &rcsbuf);
4235 struct rcsbuffer *rcsbufp;
4237 /* It isn't the head revision of the trunk. We'll need to
4238 walk through the deltas. */
4241 if (rcs->flags & PARTIAL)
4242 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
4246 /* If RCS_deltas didn't close the file, we could use fstat
4247 here too. Probably should change it thusly.... */
4248 if (stat (rcs->path, &sb) < 0)
4249 error (1, errno, "cannot stat %s", rcs->path);
4254 if (fstat (fileno (fp), &sb) < 0)
4255 error (1, errno, "cannot fstat %s", rcs->path);
4259 RCS_deltas (rcs, fp, rcsbufp, rev, RCS_FETCH, &value, &len,
4264 /* If OPTIONS is NULL or the empty string, then the old code would
4265 invoke the RCS co program with no -k option, which means that
4266 co would use the string we have stored in rcs->expand. */
4267 if ((options == NULL || options[0] == '\0') && rcs->expand == NULL)
4271 const char *ouroptions;
4272 const char * const *cpp;
4274 if (options != NULL && options[0] != '\0')
4276 assert (options[0] == '-' && options[1] == 'k');
4277 ouroptions = options + 2;
4280 ouroptions = rcs->expand;
4282 for (cpp = kflags; *cpp != NULL; cpp++)
4283 if (STREQ (*cpp, ouroptions))
4287 expand = (enum kflag) (cpp - kflags);
4291 "internal error: unsupported substitution string -k%s",
4297 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4298 /* Handle special files and permissions, if that is desired. */
4304 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
4306 error (1, 0, "internal error: no revision information for %s",
4307 rev == NULL ? rcs->head : rev);
4310 /* First we look for symlinks, which are simplest to handle. */
4311 info = findnode (vers->other_delta, "symlink");
4316 if (pfn != NULL || (workfile == NULL && sout == RUN_TTY))
4317 error (1, 0, "symbolic link %s:%s cannot be piped",
4318 rcs->path, vers->version);
4319 if (workfile == NULL)
4324 /* Remove `dest', just in case. It's okay to get ENOENT here,
4325 since we just want the file not to be there. (TODO: decide
4326 whether it should be considered an error for `dest' to exist
4327 at this point. If so, the unlink call should be removed and
4328 `symlink' should signal the error. -twp) */
4329 if (CVS_UNLINK (dest) < 0 && !existence_error (errno))
4330 error (1, errno, "cannot remove %s", dest);
4331 if (symlink (info->data, dest) < 0)
4332 error (1, errno, "cannot create symbolic link from %s to %s",
4333 dest, (char *)info->data);
4337 /* It's okay to discard the const when free_rev is set, because
4338 * we know we allocated it in this function.
4344 /* Next, we look at this file's hardlinks field, and see whether
4345 it is linked to any other file that has been checked out.
4346 If so, we don't do anything else -- just link it to that file.
4348 If we are checking out a file to a pipe or temporary storage,
4349 none of this should matter. Hence the `workfile != NULL'
4350 wrapper around the whole thing. -twp */
4352 if (workfile != NULL)
4354 List *links = vers->hardlinks;
4357 Node *uptodate_link;
4359 /* For each file in the hardlinks field, check to see
4360 if it exists, and if so, if it has been checked out
4361 this iteration. When walklist returns, uptodate_link
4362 should point to a hardlist node representing a file
4363 in `links' which has recently been checked out, or
4364 NULL if no file in `links' has yet been checked out. */
4366 uptodate_link = NULL;
4367 (void) walklist (links, find_checkedout_proc, &uptodate_link);
4370 /* If we've found a file that `workfile' is supposed to be
4371 linked to, and it has been checked out since CVS was
4372 invoked, then simply link workfile to that file and return.
4374 If one of these conditions is not met, then
4375 workfile is the first one in its hardlink group to
4376 be checked out, and we must continue with a full
4379 if (uptodate_link != NULL)
4381 struct hardlink_info *hlinfo = uptodate_link->data;
4383 if (link (uptodate_link->key, workfile) < 0)
4384 error (1, errno, "cannot link %s to %s",
4385 workfile, uptodate_link->key);
4386 hlinfo->checked_out = 1; /* probably unnecessary */
4390 /* It's okay to discard the const when free_rev is set,
4391 * because we know we allocated it in this function.
4399 info = findnode (vers->other_delta, "owner");
4402 change_rcs_owner_or_group = 1;
4403 rcs_owner = (uid_t) strtoul (info->data, NULL, 10);
4405 info = findnode (vers->other_delta, "group");
4408 change_rcs_owner_or_group = 1;
4409 rcs_group = (gid_t) strtoul (info->data, NULL, 10);
4411 info = findnode (vers->other_delta, "permissions");
4414 change_rcs_mode = 1;
4415 rcs_mode = (mode_t) strtoul (info->data, NULL, 8);
4417 info = findnode (vers->other_delta, "special");
4420 /* If the size of `devtype' changes, fix the sscanf call also */
4423 if (sscanf (info->data, "%15s %lu",
4424 devtype, &devnum_long) < 2)
4425 error (1, 0, "%s:%s has bad `special' newphrase %s",
4426 workfile, vers->version, (char *)info->data);
4427 devnum = devnum_long;
4428 if (STREQ (devtype, "character"))
4429 special_file = S_IFCHR;
4430 else if (STREQ (devtype, "block"))
4431 special_file = S_IFBLK;
4433 error (0, 0, "%s is a special file of unsupported type `%s'",
4434 workfile, (char *)info->data);
4437 #endif /* PRESERVE_PERMISSIONS_SUPPORT */
4439 if (expand != KFLAG_O && expand != KFLAG_B)
4443 /* Don't fetch the delta node again if we already have it. */
4446 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
4448 error (1, 0, "internal error: no revision information for %s",
4449 rev == NULL ? rcs->head : rev);
4452 expand_keywords (rcs, vp->data, nametag, log, loglen,
4453 expand, value, len, &newvalue, &len);
4455 if (newvalue != value)
4465 /* It's okay to discard the const when free_rev is set, because
4466 * we know we allocated it in this function.
4478 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4480 error (1, 0, "special file %s cannot be piped to anything",
4483 /* The PFN interface is very simple to implement right now, as
4484 we always have the entire file in memory. */
4486 pfn (callerdat, value, len);
4488 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4489 else if (special_file)
4494 /* Can send either to WORKFILE or to SOUT, as long as SOUT is
4499 if (sout == RUN_TTY)
4500 error (1, 0, "special file %s cannot be written to stdout",
4505 /* Unlink `dest', just in case. It's okay if this provokes a
4507 if (CVS_UNLINK (dest) < 0 && existence_error (errno))
4508 error (1, errno, "cannot remove %s", dest);
4509 if (mknod (dest, special_file, devnum) < 0)
4510 error (1, errno, "could not create special file %s",
4514 "cannot create %s: unable to create special files on this system",
4521 /* Not a special file: write to WORKFILE or SOUT. */
4522 if (workfile == NULL)
4524 if (sout == RUN_TTY)
4528 /* Symbolic links should be removed before replacement, so that
4529 `fopen' doesn't follow the link and open the wrong file. */
4531 if (unlink_file (sout) < 0)
4532 error (1, errno, "cannot remove %s", sout);
4533 ofp = CVS_FOPEN (sout, expand == KFLAG_B ? "wb" : "w");
4535 error (1, errno, "cannot open %s", sout);
4540 /* Output is supposed to go to WORKFILE, so we should open that
4541 file. Symbolic links should be removed first (see above). */
4542 if (islink (workfile))
4543 if (unlink_file (workfile) < 0)
4544 error (1, errno, "cannot remove %s", workfile);
4546 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
4548 /* If the open failed because the existing workfile was not
4549 writable, try to chmod the file and retry the open. */
4550 if (ofp == NULL && errno == EACCES
4551 && isfile (workfile) && !iswritable (workfile))
4553 xchmod (workfile, 1);
4554 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
4559 error (0, errno, "cannot open %s", workfile);
4566 if (workfile == NULL && sout == RUN_TTY)
4568 if (expand == KFLAG_B)
4569 cvs_output_binary (value, len);
4572 /* cvs_output requires the caller to check for zero
4575 cvs_output (value, len);
4580 /* NT 4.0 is said to have trouble writing 2099999 bytes
4581 (for example) in a single fwrite. So break it down
4582 (there is no need to be writing that much at once
4583 anyway; it is possible that LARGEST_FWRITE should be
4584 somewhat larger for good performance, but for testing I
4585 want to start with a small value until/unless a bigger
4586 one proves useful). */
4587 #define LARGEST_FWRITE 8192
4589 size_t nstep = (len < LARGEST_FWRITE ? len : LARGEST_FWRITE);
4594 if (fwrite (p, 1, nstep, ofp) != nstep)
4596 error (0, errno, "cannot write %s",
4599 : (sout != RUN_TTY ? sout : "stdout")));
4615 if (workfile != NULL)
4619 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4620 if (!special_file && fclose (ofp) < 0)
4622 error (0, errno, "cannot close %s", workfile);
4626 if (change_rcs_owner_or_group)
4628 if (chown (workfile, rcs_owner, rcs_group) < 0)
4629 error (0, errno, "could not change owner or group of %s",
4633 ret = chmod (workfile,
4636 : sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
4638 if (fclose (ofp) < 0)
4640 error (0, errno, "cannot close %s", workfile);
4644 ret = chmod (workfile,
4645 sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
4649 error (0, errno, "cannot change mode of file %s",
4653 else if (sout != RUN_TTY)
4656 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4661 error (0, errno, "cannot close %s", sout);
4666 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4667 /* If we are in the business of preserving hardlinks, then
4668 mark this file as having been checked out. */
4669 if (preserve_perms && workfile != NULL)
4670 update_hardlink_info (workfile);
4676 static RCSVers *RCS_findlock_or_tip PROTO ((RCSNode *rcs));
4678 /* Find the delta currently locked by the user. From the `ci' man page:
4680 "If rev is omitted, ci tries to derive the new revision
4681 number from the caller's last lock. If the caller has
4682 locked the tip revision of a branch, the new revision is
4683 appended to that branch. The new revision number is
4684 obtained by incrementing the tip revision number. If the
4685 caller locked a non-tip revision, a new branch is started
4686 at that revision by incrementing the highest branch number
4687 at that revision. The default initial branch and level
4690 If rev is omitted and the caller has no lock, but owns the
4691 file and locking is not set to strict, then the revision
4692 is appended to the default branch (normally the trunk; see
4693 the -b option of rcs(1))."
4695 RCS_findlock_or_tip finds the unique revision locked by the caller
4696 and returns its delta node. If the caller has not locked any
4697 revisions (and is permitted to commit to an unlocked delta, as
4698 described above), return the tip of the default branch. */
4701 RCS_findlock_or_tip (rcs)
4704 char *user = getcaller();
4708 /* Find unique delta locked by caller. This code is very similar
4709 to the code in RCS_unlock -- perhaps it could be abstracted
4710 into a RCS_findlock function. */
4711 locklist = RCS_getlocks (rcs);
4713 for (p = locklist->list->next; p != locklist->list; p = p->next)
4715 if (STREQ (p->data, user))
4720 %s: multiple revisions locked by %s; please specify one", rcs->path, user);
4729 /* Found an old lock, but check that the revision still exists. */
4730 p = findnode (rcs->versions, lock->key);
4733 error (0, 0, "%s: can't unlock nonexistent revision %s",
4741 /* No existing lock. The RCS rule is that this is an error unless
4742 locking is nonstrict AND the file is owned by the current
4743 user. Trying to determine the latter is a portability nightmare
4744 in the face of NT, VMS, AFS, and other systems with non-unix-like
4745 ideas of users and owners. In the case of CVS, we should never get
4746 here (as long as the traditional behavior of making sure to call
4747 RCS_lock persists). Anyway, we skip the RCS error checks
4748 and just return the default branch or head. The reasoning is that
4749 those error checks are to make users lock before a checkin, and we do
4750 that in other ways if at all anyway (e.g. rcslock.pl). */
4752 p = findnode (rcs->versions, RCS_getbranch (rcs, rcs->branch, 0));
4756 /* Revision number string, R, must contain a `.'.
4757 Return a newly-malloc'd copy of the prefix of R up
4758 to but not including the final `.'. */
4766 char *dot = strrchr (r, '.');
4770 new_r = xmalloc (len + 1);
4771 memcpy (new_r, r, len);
4772 *(new_r + len) = '\0';
4776 /* Revision number string, R, must contain a `.'.
4777 R must be writable. Replace the rightmost `.' in R with
4778 the NUL byte and return a pointer to that NUL byte. */
4781 truncate_revnum_in_place (r)
4784 char *dot = strrchr (r, '.');
4790 /* Revision number strings, R and S, must each contain a `.'.
4791 R and S must be writable and must have the same number of dots.
4792 Truncate R and S for the comparison, then restored them to their
4794 Return the result (see compare_revnums) of comparing R and S
4795 ignoring differences in any component after the rightmost `.'. */
4798 compare_truncated_revnums (r, s)
4802 char *r_dot = truncate_revnum_in_place (r);
4803 char *s_dot = truncate_revnum_in_place (s);
4806 assert (numdots (r) == numdots (s));
4808 cmp = compare_revnums (r, s);
4816 /* Return a malloc'd copy of the string representing the highest branch
4817 number on BRANCHNODE. If there are no branches on BRANCHNODE, return NULL.
4818 FIXME: isn't the max rev always the last one?
4819 If so, we don't even need a loop. */
4821 static char *max_rev PROTO ((const RCSVers *));
4824 max_rev (branchnode)
4825 const RCSVers *branchnode;
4831 if (branchnode->branches == NULL)
4837 head = branchnode->branches->list;
4838 for (bp = head->next; bp != head; bp = bp->next)
4840 if (max == NULL || compare_truncated_revnums (max, bp->key) < 0)
4847 return truncate_revnum (max);
4850 /* Create BRANCH in RCS's delta tree. BRANCH may be either a branch
4851 number or a revision number. In the former case, create the branch
4852 with the specified number; in the latter case, create a new branch
4853 rooted at node BRANCH with a higher branch number than any others.
4854 Return the number of the tip node on the new branch. */
4857 RCS_addbranch (rcs, branch)
4861 char *branchpoint, *newrevnum;
4864 RCSVers *branchnode;
4866 /* Append to end by default. */
4869 branchpoint = xstrdup (branch);
4870 if ((numdots (branchpoint) & 1) == 0)
4872 truncate_revnum_in_place (branchpoint);
4875 /* Find the branch rooted at BRANCHPOINT. */
4876 nodep = findnode (rcs->versions, branchpoint);
4879 error (0, 0, "%s: can't find branch point %s", rcs->path, branchpoint);
4884 branchnode = nodep->data;
4886 /* If BRANCH was a full branch number, make sure it is higher than MAX. */
4887 if ((numdots (branch) & 1) == 1)
4889 if (branchnode->branches == NULL)
4891 /* We have to create the first branch on this node, which means
4892 appending ".2" to the revision number. */
4893 newrevnum = (char *) xmalloc (strlen (branch) + 3);
4894 strcpy (newrevnum, branch);
4895 strcat (newrevnum, ".2");
4899 char *max = max_rev (branchnode);
4901 newrevnum = increment_revnum (max);
4907 newrevnum = xstrdup (branch);
4909 if (branchnode->branches != NULL)
4914 /* Find the position of this new branch in the sorted list
4916 head = branchnode->branches->list;
4917 for (bp = head->next; bp != head; bp = bp->next)
4922 /* The existing list must be sorted on increasing revnum. */
4923 assert (bp->next == head
4924 || compare_truncated_revnums (bp->key,
4925 bp->next->key) < 0);
4926 dot = truncate_revnum_in_place (bp->key);
4927 found_pos = (compare_revnums (branch, bp->key) < 0);
4939 newrevnum = (char *) xrealloc (newrevnum, strlen (newrevnum) + 3);
4940 strcat (newrevnum, ".1");
4942 /* Add this new revision number to BRANCHPOINT's branches list. */
4943 if (branchnode->branches == NULL)
4944 branchnode->branches = getlist();
4946 bp->key = xstrdup (newrevnum);
4948 /* Append to the end of the list by default, that is, just before
4949 the header node, `list'. */
4951 marker = branchnode->branches->list;
4955 fail = insert_before (branchnode->branches, marker, bp);
4962 /* Check in to RCSFILE with revision REV (which must be greater than
4963 the largest revision) and message MESSAGE (which is checked for
4964 legality). If FLAGS & RCS_FLAGS_DEAD, check in a dead revision.
4965 If FLAGS & RCS_FLAGS_QUIET, tell ci to be quiet. If FLAGS &
4966 RCS_FLAGS_MODTIME, use the working file's modification time for the
4967 checkin time. WORKFILE is the working file to check in from, or
4968 NULL to use the usual RCS rules for deriving it from the RCSFILE.
4969 If FLAGS & RCS_FLAGS_KEEPFILE, don't unlink the working file;
4970 unlinking the working file is standard RCS behavior, but is rarely
4971 appropriate for CVS.
4973 This function should almost exactly mimic the behavior of `rcs ci'. The
4974 principal point of difference is the support here for preserving file
4975 ownership and permissions in the delta nodes. This is not a clean
4976 solution -- precisely because it diverges from RCS's behavior -- but
4977 it doesn't seem feasible to do this anywhere else in the code. [-twp]
4979 Return value is -1 for error (and errno is set to indicate the
4980 error), positive for error (and an error message has been printed),
4981 or zero for success. */
4984 RCS_checkin (rcs, workfile_in, message, rev, flags)
4986 const char *workfile_in;
4987 const char *message;
4991 RCSVers *delta, *commitpt;
4994 char *tmpfile, *changefile;
4997 int status, checkin_quiet;
5000 int adding_branch = 0;
5001 char *workfile = xstrdup (workfile_in);
5002 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5008 if (rcs->flags & PARTIAL)
5009 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5011 /* Get basename of working file. Is there a library function to
5012 do this? I couldn't find one. -twp */
5013 if (workfile == NULL)
5016 int extlen = strlen (RCSEXT);
5017 workfile = xstrdup (last_component (rcs->path));
5018 p = workfile + (strlen (workfile) - extlen);
5019 assert (strncmp (p, RCSEXT, extlen) == 0);
5023 /* If the filename is a symbolic link, follow it and replace it
5024 with the destination of the link. We need to do this before
5025 calling rcs_internal_lockfile, or else we won't put the lock in
5027 resolve_symlink (&(rcs->path));
5029 checkin_quiet = flags & RCS_FLAGS_QUIET;
5032 cvs_output (rcs->path, 0);
5033 cvs_output (" <-- ", 7);
5034 cvs_output (workfile, 0);
5035 cvs_output ("\n", 1);
5038 /* Create new delta node. */
5039 delta = (RCSVers *) xmalloc (sizeof (RCSVers));
5040 memset (delta, 0, sizeof (RCSVers));
5041 delta->author = xstrdup (getcaller ());
5042 if (flags & RCS_FLAGS_MODTIME)
5045 if (stat (workfile, &ws) < 0)
5047 error (1, errno, "cannot stat %s", workfile);
5049 modtime = ws.st_mtime;
5052 (void) time (&modtime);
5053 ftm = gmtime (&modtime);
5054 delta->date = (char *) xmalloc (MAXDATELEN);
5055 (void) sprintf (delta->date, DATEFORM,
5056 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
5057 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
5058 ftm->tm_min, ftm->tm_sec);
5059 if (flags & RCS_FLAGS_DEAD)
5061 delta->state = xstrdup (RCSDEAD);
5065 delta->state = xstrdup ("Exp");
5067 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5068 /* If permissions should be preserved on this project, then
5069 save the permission info. */
5073 char buf[64]; /* static buffer should be safe: see usage. -twp */
5075 delta->other_delta = getlist();
5077 if (CVS_LSTAT (workfile, &sb) < 0)
5078 error (1, errno, "cannot lstat %s", workfile);
5080 if (S_ISLNK (sb.st_mode))
5083 np->type = RCSFIELD;
5084 np->key = xstrdup ("symlink");
5085 np->data = xreadlink (workfile);
5086 addnode (delta->other_delta, np);
5090 (void) sprintf (buf, "%u", sb.st_uid);
5092 np->type = RCSFIELD;
5093 np->key = xstrdup ("owner");
5094 np->data = xstrdup (buf);
5095 addnode (delta->other_delta, np);
5097 (void) sprintf (buf, "%u", sb.st_gid);
5099 np->type = RCSFIELD;
5100 np->key = xstrdup ("group");
5101 np->data = xstrdup (buf);
5102 addnode (delta->other_delta, np);
5104 (void) sprintf (buf, "%o", sb.st_mode & 07777);
5106 np->type = RCSFIELD;
5107 np->key = xstrdup ("permissions");
5108 np->data = xstrdup (buf);
5109 addnode (delta->other_delta, np);
5111 /* Save device number. */
5112 switch (sb.st_mode & S_IFMT)
5114 case S_IFREG: break;
5117 # ifdef HAVE_STRUCT_STAT_ST_RDEV
5119 np->type = RCSFIELD;
5120 np->key = xstrdup ("special");
5121 sprintf (buf, "%s %lu",
5122 ((sb.st_mode & S_IFMT) == S_IFCHR
5123 ? "character" : "block"),
5124 (unsigned long) sb.st_rdev);
5125 np->data = xstrdup (buf);
5126 addnode (delta->other_delta, np);
5129 "can't preserve %s: unable to save device files on this system",
5135 error (0, 0, "special file %s has unknown type", workfile);
5138 /* Save hardlinks. */
5139 delta->hardlinks = list_linked_files_on_disk (workfile);
5144 /* Create a new deltatext node. */
5145 dtext = (Deltatext *) xmalloc (sizeof (Deltatext));
5146 memset (dtext, 0, sizeof (Deltatext));
5148 dtext->log = make_message_rcslegal (message);
5150 /* If the delta tree is empty, then there's nothing to link the
5151 new delta into. So make a new delta tree, snarf the working
5152 file contents, and just write the new RCS file. */
5153 if (rcs->head == NULL)
5158 /* Figure out what the first revision number should be. */
5159 if (rev == NULL || *rev == '\0')
5160 newrev = xstrdup ("1.1");
5161 else if (numdots (rev) == 0)
5163 newrev = (char *) xmalloc (strlen (rev) + 3);
5164 strcpy (newrev, rev);
5165 strcat (newrev, ".1");
5168 newrev = xstrdup (rev);
5170 /* Don't need to xstrdup NEWREV because it's already dynamic, and
5171 not used for anything else. (Don't need to free it, either.) */
5173 delta->version = xstrdup (newrev);
5175 nodep->type = RCSVERS;
5176 nodep->delproc = rcsvers_delproc;
5177 nodep->data = delta;
5178 nodep->key = delta->version;
5179 (void) addnode (rcs->versions, nodep);
5181 dtext->version = xstrdup (newrev);
5183 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5184 if (preserve_perms && !S_ISREG (sb.st_mode))
5185 /* Pretend file is empty. */
5189 get_file (workfile, workfile,
5190 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5191 &dtext->text, &bufsize, &dtext->len);
5195 cvs_output ("initial revision: ", 0);
5196 cvs_output (rcs->head, 0);
5197 cvs_output ("\n", 1);
5200 /* We are probably about to invalidate any cached file. */
5201 rcsbuf_cache_close ();
5203 fout = rcs_internal_lockfile (rcs->path);
5204 RCS_putadmin (rcs, fout);
5205 RCS_putdtree (rcs, rcs->head, fout);
5206 RCS_putdesc (rcs, fout);
5207 rcs->delta_pos = ftell (fout);
5208 if (rcs->delta_pos == -1)
5209 error (1, errno, "cannot ftell for %s", rcs->path);
5210 putdeltatext (fout, dtext);
5211 rcs_internal_unlockfile (fout, rcs->path);
5213 if ((flags & RCS_FLAGS_KEEPFILE) == 0)
5215 if (unlink_file (workfile) < 0)
5216 /* FIXME-update-dir: message does not include update_dir. */
5217 error (0, errno, "cannot remove %s", workfile);
5221 cvs_output ("done\n", 5);
5227 /* Derive a new revision number. From the `ci' man page:
5229 "If rev is a revision number, it must be higher than the
5230 latest one on the branch to which rev belongs, or must
5233 If rev is a branch rather than a revision number, the new
5234 revision is appended to that branch. The level number is
5235 obtained by incrementing the tip revision number of that
5236 branch. If rev indicates a non-existing branch, that
5237 branch is created with the initial revision numbered
5240 RCS_findlock_or_tip handles the case where REV is omitted.
5241 RCS 5.7 also permits REV to be "$" or to begin with a dot, but
5242 we do not address those cases -- every routine that calls
5243 RCS_checkin passes it a numeric revision. */
5245 if (rev == NULL || *rev == '\0')
5247 /* Figure out where the commit point is by looking for locks.
5248 If the commit point is at the tip of a branch (or is the
5249 head of the delta tree), then increment its revision number
5250 to obtain the new revnum. Otherwise, start a new
5252 commitpt = RCS_findlock_or_tip (rcs);
5253 if (commitpt == NULL)
5258 else if (commitpt->next == NULL
5259 || STREQ (commitpt->version, rcs->head))
5260 delta->version = increment_revnum (commitpt->version);
5262 delta->version = RCS_addbranch (rcs, commitpt->version);
5266 /* REV is either a revision number or a branch number. Find the
5267 tip of the target branch. */
5268 char *branch, *tip, *newrev, *p;
5271 assert (isdigit ((unsigned char) *rev));
5273 newrev = xstrdup (rev);
5274 dots = numdots (newrev);
5275 isrevnum = dots & 1;
5277 branch = xstrdup (rev);
5280 p = strrchr (branch, '.');
5284 /* Find the tip of the target branch. If we got a one- or two-digit
5285 revision number, this will be the head of the tree. Exception:
5286 if rev is a single-field revision equal to the branch number of
5287 the trunk (usually "1") then we want to treat it like an ordinary
5291 tip = xstrdup (rcs->head);
5292 if (atoi (tip) != atoi (branch))
5294 newrev = (char *) xrealloc (newrev, strlen (newrev) + 3);
5295 strcat (newrev, ".1");
5296 dots = isrevnum = 1;
5300 tip = xstrdup (rcs->head);
5302 tip = RCS_getbranch (rcs, branch, 1);
5304 /* If the branch does not exist, and we were supplied an exact
5305 revision number, signal an error. Otherwise, if we were
5306 given only a branch number, create it and set COMMITPT to
5307 the branch point. */
5312 error (0, 0, "%s: can't find branch point %s",
5319 delta->version = RCS_addbranch (rcs, branch);
5320 if (!delta->version)
5328 p = strrchr (branch, '.');
5330 tip = xstrdup (branch);
5336 /* NEWREV must be higher than TIP. */
5337 if (compare_revnums (tip, newrev) >= 0)
5340 "%s: revision %s too low; must be higher than %s",
5349 delta->version = xstrdup (newrev);
5352 /* Just increment the tip number to get the new revision. */
5353 delta->version = increment_revnum (tip);
5356 nodep = findnode (rcs->versions, tip);
5357 commitpt = nodep->data;
5364 assert (delta->version != NULL);
5366 /* If COMMITPT is locked by us, break the lock. If it's locked
5367 by someone else, signal an error. */
5368 nodep = findnode (RCS_getlocks (rcs), commitpt->version);
5371 if (! STREQ (nodep->data, delta->author))
5373 /* If we are adding a branch, then leave the old lock around.
5374 That is sensible in the sense that when adding a branch,
5375 we don't need to use the lock to tell us where to check
5376 in. It is fishy in the sense that if it is our own lock,
5377 we break it. However, this is the RCS 5.7 behavior (at
5378 the end of addbranch in ci.c in RCS 5.7, it calls
5379 removelock only if it is our own lock, not someone
5384 error (0, 0, "%s: revision %s locked by %s",
5386 nodep->key, (char *)nodep->data);
5395 dtext->version = xstrdup (delta->version);
5397 /* Obtain the change text for the new delta. If DELTA is to be the
5398 new head of the tree, then its change text should be the contents
5399 of the working file, and LEAFNODE's change text should be a diff.
5400 Else, DELTA's change text should be a diff between LEAFNODE and
5401 the working file. */
5403 tmpfile = cvs_temp_name();
5404 status = RCS_checkout (rcs, NULL, commitpt->version, NULL,
5405 ((rcs->expand != NULL
5406 && STREQ (rcs->expand, "b"))
5410 (RCSCHECKOUTPROC)0, NULL);
5413 "could not check out revision %s of `%s'",
5414 commitpt->version, rcs->path);
5417 changefile = cvs_temp_name();
5419 /* Diff options should include --binary if the RCS file has -kb set
5420 in its `expand' field. */
5421 diffopts = (rcs->expand != NULL && STREQ (rcs->expand, "b")
5425 if (STREQ (commitpt->version, rcs->head) &&
5426 numdots (delta->version) == 1)
5428 /* If this revision is being inserted on the trunk, the change text
5429 for the new delta should be the contents of the working file ... */
5431 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5432 if (preserve_perms && !S_ISREG (sb.st_mode))
5433 /* Pretend file is empty. */
5437 get_file (workfile, workfile,
5438 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5439 &dtext->text, &bufsize, &dtext->len);
5441 /* ... and the change text for the old delta should be a diff. */
5442 commitpt->text = (Deltatext *) xmalloc (sizeof (Deltatext));
5443 memset (commitpt->text, 0, sizeof (Deltatext));
5446 switch (diff_exec (workfile, tmpfile, NULL, NULL, diffopts, changefile))
5452 /* FIXME-update-dir: message does not include update_dir. */
5453 error (1, errno, "error diffing %s", workfile);
5456 /* FIXME-update-dir: message does not include update_dir. */
5457 error (1, 0, "error diffing %s", workfile);
5461 /* OK, the text file case here is really dumb. Logically
5462 speaking we want diff to read the files in text mode,
5463 convert them to the canonical form found in RCS files
5464 (which, we hope at least, is independent of OS--always
5465 bare linefeeds), and then work with change texts in that
5466 format. However, diff_exec both generates change
5467 texts and produces output for user purposes (e.g. patch.c),
5468 and there is no way to distinguish between the two cases.
5469 So we actually implement the text file case by writing the
5470 change text as a text file, then reading it as a text file.
5471 This should cause no harm, but doesn't strike me as
5473 get_file (changefile, changefile,
5474 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5475 &commitpt->text->text, &bufsize, &commitpt->text->len);
5477 /* If COMMITPT->TEXT->TEXT is NULL, it means that CHANGEFILE
5478 was empty and that there are no differences between revisions.
5479 In that event, we want to force RCS_rewrite to write an empty
5480 string for COMMITPT's change text. Leaving the change text
5481 field set NULL won't work, since that means "preserve the original
5482 change text for this delta." */
5483 if (commitpt->text->text == NULL)
5485 commitpt->text->text = xstrdup ("");
5486 commitpt->text->len = 0;
5491 /* This file is not being inserted at the head, but on a side
5492 branch somewhere. Make a diff from the previous revision
5493 to the working file. */
5494 switch (diff_exec (tmpfile, workfile, NULL, NULL, diffopts, changefile))
5500 /* FIXME-update-dir: message does not include update_dir. */
5501 error (1, errno, "error diffing %s", workfile);
5504 /* FIXME-update-dir: message does not include update_dir. */
5505 error (1, 0, "error diffing %s", workfile);
5508 /* See the comment above, at the other get_file invocation,
5509 regarding binary vs. text. */
5510 get_file (changefile, changefile,
5511 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5512 &dtext->text, &bufsize,
5514 if (dtext->text == NULL)
5516 dtext->text = xstrdup ("");
5521 /* Update DELTA linkage. It is important not to do this before
5522 the very end of RCS_checkin; if an error arises that forces
5523 us to abort checking in, we must not have malformed deltas
5524 partially linked into the tree.
5526 If DELTA and COMMITPT are on different branches, do nothing --
5527 DELTA is linked to the tree through COMMITPT->BRANCHES, and we
5528 don't want to change `next' pointers.
5530 Otherwise, if the nodes are both on the trunk, link DELTA to
5531 COMMITPT; otherwise, link COMMITPT to DELTA. */
5533 if (numdots (commitpt->version) == numdots (delta->version))
5535 if (STREQ (commitpt->version, rcs->head))
5537 delta->next = rcs->head;
5538 rcs->head = xstrdup (delta->version);
5541 commitpt->next = xstrdup (delta->version);
5544 /* Add DELTA to RCS->VERSIONS. */
5545 if (rcs->versions == NULL)
5546 rcs->versions = getlist();
5548 nodep->type = RCSVERS;
5549 nodep->delproc = rcsvers_delproc;
5550 nodep->data = delta;
5551 nodep->key = delta->version;
5552 (void) addnode (rcs->versions, nodep);
5554 /* Write the new RCS file, inserting the new delta at COMMITPT. */
5557 cvs_output ("new revision: ", 14);
5558 cvs_output (delta->version, 0);
5559 cvs_output ("; previous revision: ", 21);
5560 cvs_output (commitpt->version, 0);
5561 cvs_output ("\n", 1);
5564 RCS_rewrite (rcs, dtext, commitpt->version);
5566 if ((flags & RCS_FLAGS_KEEPFILE) == 0)
5568 if (unlink_file (workfile) < 0)
5569 /* FIXME-update-dir: message does not include update_dir. */
5570 error (1, errno, "cannot remove %s", workfile);
5572 if (unlink_file (tmpfile) < 0)
5573 error (0, errno, "cannot remove %s", tmpfile);
5575 if (unlink_file (changefile) < 0)
5576 error (0, errno, "cannot remove %s", changefile);
5580 cvs_output ("done\n", 5);
5585 if (commitpt != NULL && commitpt->text != NULL)
5587 freedeltatext (commitpt->text);
5588 commitpt->text = NULL;
5591 freedeltatext (dtext);
5593 free_rcsvers_contents (delta);
5600 /* This structure is passed between RCS_cmp_file and cmp_file_buffer. */
5601 struct cmp_file_data
5603 const char *filename;
5608 /* Compare the contents of revision REV1 of RCS file RCS with the
5609 contents of REV2 if given, otherwise, compare with the contents of
5610 the file FILENAME. OPTIONS is a string for the keyword
5611 expansion options. Return 0 if the contents of the revision are
5612 the same as the contents of the file, 1 if they are different. */
5614 RCS_cmp_file (rcs, rev1, rev1_cache, rev2, options, filename)
5619 const char *options;
5620 const char *filename;
5624 if (options != NULL && options[0] != '\0')
5625 binary = STREQ (options, "-kb");
5630 expand = RCS_getexpand (rcs);
5631 if (expand != NULL && STREQ (expand, "b"))
5637 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5638 /* If CVS is to deal properly with special files (when
5639 PreservePermissions is on), the best way is to check out the
5640 revision to a temporary file and call `xcmp' on the two disk
5641 files. xcmp needs to handle non-regular files properly anyway,
5642 so calling it simplifies RCS_cmp_file. We *could* just yank
5643 the delta node out of the version tree and look for device
5644 numbers, but writing to disk and calling xcmp is a better
5645 abstraction (therefore probably more robust). -twp */
5652 tmp = cvs_temp_name();
5653 retcode = RCS_checkout(rcs, NULL, rev, NULL, options, tmp, NULL, NULL);
5657 retcode = xcmp (tmp, filename);
5658 if (CVS_UNLINK (tmp) < 0)
5659 error (0, errno, "cannot remove %s", tmp);
5667 struct cmp_file_data data;
5668 const char *use_file1;
5669 char *tmpfile = NULL;
5673 /* Open & cache rev1 */
5674 tmpfile = cvs_temp_name();
5675 if (RCS_checkout (rcs, NULL, rev1, NULL, options, tmpfile,
5676 (RCSCHECKOUTPROC)0, NULL))
5678 "cannot check out revision %s of %s",
5680 use_file1 = tmpfile;
5681 if (rev1_cache != NULL)
5682 *rev1_cache = tmpfile;
5685 use_file1 = filename;
5687 fp = CVS_FOPEN (use_file1, binary ? FOPEN_BINARY_READ : "r");
5689 /* FIXME-update-dir: should include update_dir in message. */
5690 error (1, errno, "cannot open file %s for comparing", use_file1);
5692 data.filename = use_file1;
5696 if (RCS_checkout (rcs, (char *)NULL, rev2 ? rev2 : rev1,
5697 (char *)NULL, options, RUN_TTY, cmp_file_buffer,
5700 "cannot check out revision %s of %s",
5701 rev2 ? rev2 : rev1, rcs->path);
5703 /* If we have not yet found a difference, make sure that we are at
5704 the end of the file. */
5705 if (!data.different)
5707 if (getc (fp) != EOF)
5712 if (rev1_cache == NULL && tmpfile)
5714 if (CVS_UNLINK (tmpfile ) < 0)
5715 error (0, errno, "cannot remove %s", tmpfile);
5719 return data.different;
5725 /* This is a subroutine of RCS_cmp_file. It is passed to
5727 #define CMP_BUF_SIZE (8 * 1024)
5730 cmp_file_buffer (callerdat, buffer, len)
5735 struct cmp_file_data *data = (struct cmp_file_data *)callerdat;
5738 /* If we've already found a difference, we don't need to check
5740 if (data->different)
5743 filebuf = xmalloc (len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len);
5749 checklen = len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len;
5750 if (fread (filebuf, 1, checklen, data->fp) != checklen)
5752 if (ferror (data->fp))
5753 error (1, errno, "cannot read file %s for comparing",
5755 data->different = 1;
5760 if (memcmp (filebuf, buffer, checklen) != 0)
5762 data->different = 1;
5776 /* For RCS file RCS, make symbolic tag TAG point to revision REV.
5777 This validates that TAG is OK for a user to use. Return value is
5778 -1 for error (and errno is set to indicate the error), positive for
5779 error (and an error message has been printed), or zero for success. */
5782 RCS_settag (rcs, tag, rev)
5790 if (rcs->flags & PARTIAL)
5791 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5793 /* FIXME: This check should be moved to RCS_check_tag. There is no
5794 reason for it to be here. */
5795 if (STREQ (tag, TAG_BASE)
5796 || STREQ (tag, TAG_HEAD))
5798 /* Print the name of the tag might be considered redundant
5799 with the caller, which also prints it. Perhaps this helps
5800 clarify why the tag name is considered reserved, I don't
5802 error (0, 0, "Attempt to add reserved tag name %s", tag);
5806 /* A revision number of NULL means use the head or default branch.
5807 If rev is not NULL, it may be a symbolic tag or branch number;
5808 expand it to the correct numeric revision or branch head. */
5810 rev = rcs->branch ? rcs->branch : rcs->head;
5812 /* At this point rcs->symbol_data may not have been parsed.
5813 Calling RCS_symbols will force it to be parsed into a list
5814 which we can easily manipulate. */
5815 symbols = RCS_symbols (rcs);
5816 if (symbols == NULL)
5818 symbols = getlist ();
5819 rcs->symbols = symbols;
5821 node = findnode (symbols, tag);
5825 node->data = xstrdup (rev);
5830 node->key = xstrdup (tag);
5831 node->data = xstrdup (rev);
5832 (void) addnode_at_front (symbols, node);
5838 /* Delete the symbolic tag TAG from the RCS file RCS. Return 0 if
5839 the tag was found (and removed), or 1 if it was not present. (In
5840 either case, the tag will no longer be in RCS->SYMBOLS.) */
5843 RCS_deltag (rcs, tag)
5849 if (rcs->flags & PARTIAL)
5850 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5852 symbols = RCS_symbols (rcs);
5853 if (symbols == NULL)
5856 node = findnode (symbols, tag);
5865 /* Set the default branch of RCS to REV. */
5868 RCS_setbranch (rcs, rev)
5872 if (rcs->flags & PARTIAL)
5873 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5878 if (rev == NULL && rcs->branch == NULL)
5880 if (rev != NULL && rcs->branch != NULL && STREQ (rev, rcs->branch))
5883 if (rcs->branch != NULL)
5885 rcs->branch = xstrdup (rev);
5890 /* Lock revision REV. LOCK_QUIET is 1 to suppress output. FIXME:
5891 Most of the callers only call us because RCS_checkin still tends to
5892 like a lock (a relic of old behavior inherited from the RCS ci
5893 program). If we clean this up, only "cvs admin -l" will still need
5894 to call RCS_lock. */
5896 /* FIXME-twp: if a lock owned by someone else is broken, should this
5897 send mail to the lock owner? Prompt user? It seems like such an
5898 obscure situation for CVS as almost not worth worrying much
5902 RCS_lock (rcs, rev, lock_quiet)
5912 if (rcs->flags & PARTIAL)
5913 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5915 locks = RCS_getlocks (rcs);
5917 locks = rcs->locks = getlist();
5920 /* A revision number of NULL means lock the head or default branch. */
5922 xrev = RCS_head (rcs);
5924 xrev = RCS_gettag (rcs, rev, 1, (int *) NULL);
5926 /* Make sure that the desired revision exists. Technically,
5927 we can update the locks list without even checking this,
5928 but RCS 5.7 did this. And it can't hurt. */
5929 if (xrev == NULL || findnode (rcs->versions, xrev) == NULL)
5932 error (0, 0, "%s: revision %s absent", rcs->path, rev);
5937 /* Is this rev already locked? */
5938 p = findnode (locks, xrev);
5941 if (STREQ (p->data, user))
5943 /* We already own the lock on this revision, so do nothing. */
5949 /* Well, first of all, "rev" below should be "xrev" to avoid
5950 core dumps. But more importantly, should we really be
5951 breaking the lock unconditionally? What CVS 1.9 does (via
5952 RCS) is to prompt "Revision 1.1 is already locked by fred.
5953 Do you want to break the lock? [ny](n): ". Well, we don't
5954 want to interact with the user (certainly not at the
5955 server/protocol level, and probably not in the command-line
5956 client), but isn't it more sensible to give an error and
5957 let the user run "cvs admin -u" if they want to break the
5960 /* Break the lock. */
5963 cvs_output (rev, 0);
5964 cvs_output (" unlocked\n", 0);
5968 error (1, 0, "Revision %s is already locked by %s", xrev, (char *)p->data);
5972 /* Create a new lock. */
5974 p->key = xrev; /* already xstrdupped */
5975 p->data = xstrdup (getcaller());
5976 (void) addnode_at_front (locks, p);
5980 cvs_output (xrev, 0);
5981 cvs_output (" locked\n", 0);
5987 /* Unlock revision REV. UNLOCK_QUIET is 1 to suppress output. FIXME:
5988 Like RCS_lock, this can become a no-op if we do the checkin
5991 If REV is not null and is locked by someone else, break their
5992 lock and notify them. It is an open issue whether RCS_unlock
5993 queries the user about whether or not to break the lock. */
5996 RCS_unlock (rcs, rev, unlock_quiet)
6007 if (rcs->flags & PARTIAL)
6008 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6010 /* If rev is NULL, unlock the revision held by the caller; if more
6011 than one, make the user specify the revision explicitly. This
6012 differs from RCS which unlocks the latest revision (first in
6013 rcs->locks) held by the caller. */
6018 /* No-ops: attempts to unlock an empty tree or an unlocked file. */
6019 if (rcs->head == NULL)
6022 cvs_outerr ("can't unlock an empty tree\n", 0);
6026 locks = RCS_getlocks (rcs);
6030 cvs_outerr ("No locks are set.\n", 0);
6035 for (p = locks->list->next; p != locks->list; p = p->next)
6037 if (STREQ (p->data, user))
6043 %s: multiple revisions locked by %s; please specify one", rcs->path, user);
6052 error (0, 0, "No locks are set for %s.\n", user);
6053 return 0; /* no lock found, ergo nothing to do */
6055 xrev = xstrdup (lock->key);
6059 xrev = RCS_gettag (rcs, rev, 1, (int *) NULL);
6062 error (0, 0, "%s: revision %s absent", rcs->path, rev);
6067 lock = findnode (RCS_getlocks (rcs), xrev);
6070 /* This revision isn't locked. */
6075 if (! STREQ (lock->data, user))
6077 /* If the revision is locked by someone else, notify
6078 them. Note that this shouldn't ever happen if RCS_unlock
6079 is called with a NULL revision, since that means "whatever
6080 revision is currently locked by the caller." */
6081 char *repos, *workfile;
6084 %s: revision %s locked by %s; breaking lock", rcs->path, xrev, (char *)lock->data);
6085 repos = xstrdup (rcs->path);
6086 workfile = strrchr (repos, '/');
6088 notify_do ('C', workfile, user, NULL, NULL, repos);
6095 cvs_output (xrev, 0);
6096 cvs_output (" unlocked\n", 0);
6103 /* Add USER to the access list of RCS. Do nothing if already present.
6104 FIXME-twp: check syntax of USER to make sure it's a valid id. */
6107 RCS_addaccess (rcs, user)
6113 if (rcs->flags & PARTIAL)
6114 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6116 if (rcs->access == NULL)
6117 rcs->access = xstrdup (user);
6120 access = xstrdup (rcs->access);
6121 for (a = strtok (access, " "); a != NULL; a = strtok (NULL, " "))
6123 if (STREQ (a, user))
6130 rcs->access = (char *) xrealloc
6131 (rcs->access, strlen (rcs->access) + strlen (user) + 2);
6132 strcat (rcs->access, " ");
6133 strcat (rcs->access, user);
6137 /* Remove USER from the access list of RCS. */
6140 RCS_delaccess (rcs, user)
6147 if (rcs->flags & PARTIAL)
6148 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6150 if (rcs->access == NULL)
6161 ulen = strlen (user);
6164 if (strncmp (p, user, ulen) == 0 && (p[ulen] == '\0' || p[ulen] == ' '))
6166 p = strchr (p, ' ');
6184 if (rcs->flags & PARTIAL)
6185 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6190 static int findtag PROTO ((Node *, void *));
6192 /* Return a nonzero value if the revision specified by ARG is found. */
6199 char *rev = (char *)arg;
6201 if (STREQ (node->data, rev))
6207 /* Delete revisions between REV1 and REV2. The changes between the two
6208 revisions must be collapsed, and the result stored in the revision
6209 immediately preceding the lower one. Return 0 for successful completion,
6212 Solution: check out the revision preceding REV1 and the revision
6213 following REV2. Use call_diff to find aggregate diffs between
6214 these two revisions, and replace the delta text for the latter one
6215 with the new aggregate diff. Alternatively, we could write a
6216 function that takes two change texts and combines them to produce a
6217 new change text, without checking out any revs or calling diff. It
6218 would be hairy, but so, so cool.
6220 If INCLUSIVE is set, then TAG1 and TAG2, if non-NULL, tell us to
6221 delete that revision as well (cvs admin -o tag1:tag2). If clear,
6222 delete up to but not including that revision (cvs admin -o tag1::tag2).
6223 This does not affect TAG1 or TAG2 being NULL; the meaning of the start
6224 point in ::tag2 and :tag2 is the same and likewise for end points. */
6227 RCS_delete_revs (rcs, tag1, tag2, inclusive)
6235 RCSVers *revp = NULL;
6240 char *branchpoint = NULL;
6243 int rev1_inclusive = inclusive;
6244 int rev2_inclusive = inclusive;
6245 char *before = NULL;
6247 char *beforefile = NULL;
6248 char *afterfile = NULL;
6249 char *outfile = NULL;
6251 if (tag1 == NULL && tag2 == NULL)
6254 /* Assume error status until everything is finished. */
6257 /* Make sure both revisions exist. */
6260 rev1 = RCS_gettag (rcs, tag1, 1, NULL);
6261 if (rev1 == NULL || (nodep = findnode (rcs->versions, rev1)) == NULL)
6263 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag1);
6269 rev2 = RCS_gettag (rcs, tag2, 1, NULL);
6270 if (rev2 == NULL || (nodep = findnode (rcs->versions, rev2)) == NULL)
6272 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag2);
6277 /* If rev1 is on the trunk and rev2 is NULL, rev2 should be
6278 RCS->HEAD. (*Not* RCS_head(rcs), which may return rcs->branch
6279 instead.) We need to check this special case early, in order
6280 to make sure that rev1 and rev2 get ordered correctly. */
6281 if (rev2 == NULL && numdots (rev1) == 1)
6283 rev2 = xstrdup (rcs->head);
6290 if (rev1 != NULL && rev2 != NULL)
6292 /* A range consisting of a branch number means the latest revision
6294 if (RCS_isbranch (rcs, rev1) && STREQ (rev1, rev2))
6295 rev1 = rev2 = RCS_getbranch (rcs, rev1, 0);
6298 /* Make sure REV1 and REV2 are ordered correctly (in the
6299 same order as the next field). For revisions on the
6300 trunk, REV1 should be higher than REV2; for branches,
6301 REV1 should be lower. */
6302 /* Shouldn't we just be giving an error in the case where
6303 the user specifies the revisions in the wrong order
6304 (that is, always swap on the trunk, never swap on a
6305 branch, in the non-error cases)? It is not at all
6306 clear to me that users who specify -o 1.4:1.2 really
6307 meant to type -o 1.2:1.4, and the out of order usage
6308 has never been documented, either by cvs.texinfo or
6312 if (numdots (rev1) == 1)
6314 if (compare_revnums (rev1, rev2) <= 0)
6320 temp_inclusive = rev2_inclusive;
6321 rev2_inclusive = rev1_inclusive;
6322 rev1_inclusive = temp_inclusive;
6325 else if (compare_revnums (rev1, rev2) > 0)
6331 temp_inclusive = rev2_inclusive;
6332 rev2_inclusive = rev1_inclusive;
6333 rev1_inclusive = temp_inclusive;
6338 /* Basically the same thing; make sure that the ordering is what we
6342 assert (rev2 != NULL);
6343 if (numdots (rev2) == 1)
6345 /* Swap rev1 and rev2. */
6351 temp_inclusive = rev2_inclusive;
6352 rev2_inclusive = rev1_inclusive;
6353 rev1_inclusive = temp_inclusive;
6357 /* Put the revision number preceding the first one to delete into
6358 BEFORE (where "preceding" means according to the next field).
6359 If the first revision to delete is the first revision on its
6360 branch (e.g. 1.3.2.1), BEFORE should be the node on the trunk
6361 at which the branch is rooted. If the first revision to delete
6362 is the head revision of the trunk, set BEFORE to NULL.
6364 Note that because BEFORE may not be on the same branch as REV1,
6365 it is not very handy for navigating the revision tree. It's
6366 most useful just for checking out the revision preceding REV1. */
6368 branchpoint = RCS_getbranchpoint (rcs, rev1 != NULL ? rev1 : rev2);
6371 rev1 = xstrdup (branchpoint);
6372 if (numdots (branchpoint) > 1)
6375 bp = strrchr (branchpoint, '.');
6376 while (*--bp != '.')
6379 /* Note that this is exclusive, always, because the inclusive
6380 flag doesn't affect the meaning when rev1 == NULL. */
6381 before = xstrdup (branchpoint);
6385 else if (! STREQ (rev1, branchpoint))
6387 /* Walk deltas from BRANCHPOINT on, looking for REV1. */
6388 nodep = findnode (rcs->versions, branchpoint);
6390 while (revp->next != NULL && ! STREQ (revp->next, rev1))
6393 nodep = findnode (rcs->versions, revp->next);
6395 if (revp->next == NULL)
6397 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, rev1);
6401 before = xstrdup (revp->version);
6405 nodep = findnode (rcs->versions, before);
6406 rev1 = xstrdup (((RCSVers *)nodep->data)->next);
6409 else if (!rev1_inclusive)
6412 nodep = findnode (rcs->versions, before);
6413 rev1 = xstrdup (((RCSVers *)nodep->data)->next);
6415 else if (numdots (branchpoint) > 1)
6417 /* Example: rev1 is "1.3.2.1", branchpoint is "1.3.2.1".
6418 Set before to "1.3". */
6420 bp = strrchr (branchpoint, '.');
6421 while (*--bp != '.')
6424 before = xstrdup (branchpoint);
6428 /* If any revision between REV1 and REV2 is locked or is a branch point,
6429 we can't delete that revision and must abort. */
6433 while (!found && next != NULL)
6435 nodep = findnode (rcs->versions, next);
6439 found = STREQ (revp->version, rev2);
6442 if ((!found && next != NULL) || rev2_inclusive || rev2 == NULL)
6444 if (findnode (RCS_getlocks (rcs), revp->version))
6446 error (0, 0, "%s: can't remove locked revision %s",
6451 if (revp->branches != NULL)
6453 error (0, 0, "%s: can't remove branch point %s",
6459 /* Doing this only for the :: syntax is for compatibility.
6460 See cvs.texinfo for somewhat more discussion. */
6462 && walklist (RCS_symbols (rcs), findtag, revp->version))
6464 /* We don't print which file this happens to on the theory
6465 that the caller will print the name of the file in a
6466 more useful fashion (fullname not rcs->path). */
6467 error (0, 0, "cannot remove revision %s because it has tags",
6472 /* It's misleading to print the `deleting revision' output
6473 here, since we may not actually delete these revisions.
6474 But that's how RCS does it. Bleah. Someday this should be
6475 moved to the point where the revs are actually marked for
6477 cvs_output ("deleting revision ", 0);
6478 cvs_output (revp->version, 0);
6479 cvs_output ("\n", 1);
6488 after = xstrdup (next);
6490 after = xstrdup (revp->version);
6492 else if (!inclusive)
6494 /* In the case of an empty range, for example 1.2::1.2 or
6495 1.2::1.3, we want to just do nothing. */
6501 /* This looks fishy in the cases where tag1 == NULL or tag2 == NULL.
6502 Are those cases really impossible? */
6503 assert (tag1 != NULL);
6504 assert (tag2 != NULL);
6506 error (0, 0, "%s: invalid revision range %s:%s", rcs->path,
6511 if (after == NULL && before == NULL)
6513 /* The user is trying to delete all revisions. While an
6514 RCS file without revisions makes sense to RCS (e.g. the
6515 state after "rcs -i"), CVS has never been able to cope with
6516 it. So at least for now we just make this an error.
6518 We don't include rcs->path in the message since "cvs admin"
6519 already printed "RCS file:" and the name. */
6520 error (1, 0, "attempt to delete all revisions");
6523 /* The conditionals at this point get really hairy. Here is the
6526 IF before != NULL and after == NULL
6527 THEN don't check out any revisions, just delete them
6528 IF before == NULL and after != NULL
6529 THEN only check out after's revision, and use it for the new deltatext
6531 check out both revisions and diff -n them. This could use
6532 RCS_exec_rcsdiff with some changes, like being able
6533 to suppress diagnostic messages and to direct output. */
6538 size_t bufsize, len;
6540 #if defined (WOE32) && !defined (__CYGWIN32__)
6541 /* FIXME: This is an awful kludge, but at least until I have
6542 time to work on it a little more and test it, I'd rather
6543 give a fatal error than corrupt the file. I think that we
6544 need to use "-kb" and "--binary" and "rb" to get_file
6545 (probably can do it always, not just for binary files, if
6546 we are consistent between the RCS_checkout and the diff). */
6548 char *expand = RCS_getexpand (rcs);
6549 if (expand != NULL && STREQ (expand, "b"))
6551 "admin -o not implemented yet for binary on this system");
6555 afterfile = cvs_temp_name();
6556 status = RCS_checkout (rcs, NULL, after, NULL, "-ko", afterfile,
6557 (RCSCHECKOUTPROC)0, NULL);
6563 /* We are deleting revisions from the head of the tree,
6564 so must create a new head. */
6567 get_file (afterfile, afterfile, "r", &diffbuf, &bufsize, &len);
6569 save_noexec = noexec;
6571 if (unlink_file (afterfile) < 0)
6572 error (0, errno, "cannot remove %s", afterfile);
6573 noexec = save_noexec;
6579 rcs->head = xstrdup (after);
6583 beforefile = cvs_temp_name();
6584 status = RCS_checkout (rcs, NULL, before, NULL, "-ko", beforefile,
6585 (RCSCHECKOUTPROC)0, NULL);
6589 outfile = cvs_temp_name();
6590 status = diff_exec (beforefile, afterfile, NULL, NULL, "-an", outfile);
6594 /* Not sure we need this message; will diff_exec already
6595 have printed an error? */
6596 error (0, 0, "%s: could not diff", rcs->path);
6603 get_file (outfile, outfile, "r", &diffbuf, &bufsize, &len);
6606 /* Save the new change text in after's delta node. */
6607 nodep = findnode (rcs->versions, after);
6610 assert (revp->text == NULL);
6612 revp->text = (Deltatext *) xmalloc (sizeof (Deltatext));
6613 memset ((Deltatext *) revp->text, 0, sizeof (Deltatext));
6614 revp->text->version = xstrdup (revp->version);
6615 revp->text->text = diffbuf;
6616 revp->text->len = len;
6618 /* If DIFFBUF is NULL, it means that OUTFILE is empty and that
6619 there are no differences between the two revisions. In that
6620 case, we want to force RCS_copydeltas to write an empty string
6621 for the new change text (leaving the text field set NULL
6622 means "preserve the original change text for this delta," so
6623 we don't want that). */
6624 if (revp->text->text == NULL)
6625 revp->text->text = xstrdup ("");
6628 /* Walk through the revisions (again) to mark each one as
6629 outdated. (FIXME: would it be safe to use the `dead' field for
6632 next != NULL && (after == NULL || ! STREQ (next, after));
6635 nodep = findnode (rcs->versions, next);
6640 /* Update delta links. If BEFORE == NULL, we're changing the
6641 head of the tree and don't need to update any `next' links. */
6644 /* If REV1 is the first node on its branch, then BEFORE is its
6645 root node (on the trunk) and we have to update its branches
6646 list. Otherwise, BEFORE is on the same branch as AFTER, and
6647 we can just change BEFORE's `next' field to point to AFTER.
6648 (This should be safe: since findnode manages its lists via
6649 the `hashnext' and `hashprev' fields, rather than `next' and
6650 `prev', mucking with `next' and `prev' should not corrupt the
6651 delta tree's internal structure. Much. -twp) */
6654 /* beforep's ->next field already should be equal to after,
6655 which I think is always NULL in this case. */
6657 else if (STREQ (rev1, branchpoint))
6659 nodep = findnode (rcs->versions, before);
6661 nodep = revp->branches->list->next;
6662 while (nodep != revp->branches->list &&
6663 ! STREQ (nodep->key, rev1))
6664 nodep = nodep->next;
6665 assert (nodep != revp->branches->list);
6671 nodep->key = xstrdup (after);
6676 nodep = findnode (rcs->versions, before);
6677 beforep = nodep->data;
6678 free (beforep->next);
6679 beforep->next = xstrdup (after);
6690 if (branchpoint != NULL)
6697 save_noexec = noexec;
6699 if (beforefile != NULL)
6701 if (unlink_file (beforefile) < 0)
6702 error (0, errno, "cannot remove %s", beforefile);
6705 if (afterfile != NULL)
6707 if (unlink_file (afterfile) < 0)
6708 error (0, errno, "cannot remove %s", afterfile);
6711 if (outfile != NULL)
6713 if (unlink_file (outfile) < 0)
6714 error (0, errno, "cannot remove %s", outfile);
6717 noexec = save_noexec;
6723 * TRUE if there exists a symbolic tag "tag" in file.
6726 RCS_exist_tag (rcs, tag)
6731 assert (rcs != NULL);
6733 if (findnode (RCS_symbols (rcs), tag))
6740 * TRUE if RCS revision number "rev" exists.
6741 * This includes magic branch revisions, not found in rcs->versions,
6742 * but only in rcs->symbols, requiring a list walk to find them.
6743 * Take advantage of list walk callback function already used by
6744 * RCS_delete_revs, above.
6747 RCS_exist_rev (rcs, rev)
6752 assert (rcs != NULL);
6754 if (rcs->flags & PARTIAL)
6755 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6757 if (findnode(rcs->versions, rev) != 0)
6760 if (walklist (RCS_symbols(rcs), findtag, rev) != 0)
6768 /* RCS_deltas and friends. Processing of the deltas in RCS files. */
6772 /* Text of this line. Part of the same malloc'd block as the struct
6773 line itself (we probably should use the "struct hack" (char text[1])
6774 and save ourselves sizeof (char *) bytes). Does not include \n;
6775 instead has_newline indicates the presence or absence of \n. */
6777 /* Length of this line, not counting \n if has_newline is true. */
6779 /* Version in which it was introduced. */
6781 /* Nonzero if this line ends with \n. This will always be true
6782 except possibly for the last line. */
6784 /* Number of pointers to this struct line. */
6790 /* How many lines in use for this linevector? */
6791 unsigned int nlines;
6792 /* How many lines allocated for this linevector? */
6793 unsigned int lines_alloced;
6794 /* Pointer to array containing a pointer to each line. */
6795 struct line **vector;
6798 static void linevector_init PROTO ((struct linevector *));
6800 /* Initialize *VEC to be a linevector with no lines. */
6802 linevector_init (vec)
6803 struct linevector *vec;
6805 vec->lines_alloced = 0;
6810 static int linevector_add PROTO ((struct linevector *vec, const char *text,
6811 size_t len, RCSVers *vers,
6814 /* Given some text TEXT, add each of its lines to VEC before line POS
6815 (where line 0 is the first line). The last line in TEXT may or may
6816 not be \n terminated.
6817 Set the version for each of the new lines to VERS. This
6818 function returns non-zero for success. It returns zero if the line
6819 number is out of range.
6821 Each of the lines in TEXT are copied to space which is managed with
6822 the linevector (and freed by linevector_free). So the caller doesn't
6823 need to keep TEXT around after the call to this function. */
6825 linevector_add (vec, text, len, vers, pos)
6826 struct linevector *vec;
6832 const char *textend;
6836 const char *nextline_text;
6837 size_t nextline_len;
6838 int nextline_newline;
6844 textend = text + len;
6846 /* Count the number of lines we will need to add. */
6848 for (p = text; p < textend; ++p)
6849 if (*p == '\n' && p + 1 < textend)
6852 /* Expand VEC->VECTOR if needed. */
6853 if (vec->nlines + nnew >= vec->lines_alloced)
6855 if (vec->lines_alloced == 0)
6856 vec->lines_alloced = 10;
6857 while (vec->nlines + nnew >= vec->lines_alloced)
6858 vec->lines_alloced *= 2;
6859 vec->vector = xrealloc (vec->vector,
6860 vec->lines_alloced * sizeof (*vec->vector));
6863 /* Make room for the new lines in VEC->VECTOR. */
6864 for (i = vec->nlines + nnew - 1; i >= pos + nnew; --i)
6865 vec->vector[i] = vec->vector[i - nnew];
6867 if (pos > vec->nlines)
6870 /* Actually add the lines, to VEC->VECTOR. */
6872 nextline_text = text;
6873 nextline_newline = 0;
6874 for (p = text; p < textend; ++p)
6877 nextline_newline = 1;
6878 if (p + 1 == textend)
6879 /* If there are no characters beyond the last newline, we
6880 don't consider it another line. */
6882 nextline_len = p - nextline_text;
6883 q = (struct line *) xmalloc (sizeof (struct line) + nextline_len);
6885 q->text = (char *)q + sizeof (struct line);
6886 q->len = nextline_len;
6887 q->has_newline = nextline_newline;
6889 memcpy (q->text, nextline_text, nextline_len);
6890 vec->vector[i++] = q;
6892 nextline_text = (char *)p + 1;
6893 nextline_newline = 0;
6895 nextline_len = p - nextline_text;
6896 q = (struct line *) xmalloc (sizeof (struct line) + nextline_len);
6898 q->text = (char *)q + sizeof (struct line);
6899 q->len = nextline_len;
6900 q->has_newline = nextline_newline;
6902 memcpy (q->text, nextline_text, nextline_len);
6905 vec->nlines += nnew;
6910 static void linevector_delete PROTO ((struct linevector *, unsigned int,
6913 /* Remove NLINES lines from VEC at position POS (where line 0 is the
6916 linevector_delete (vec, pos, nlines)
6917 struct linevector *vec;
6919 unsigned int nlines;
6924 last = vec->nlines - nlines;
6925 for (i = pos; i < pos + nlines; ++i)
6927 if (--vec->vector[i]->refcount == 0)
6928 free (vec->vector[i]);
6930 for (i = pos; i < last; ++i)
6931 vec->vector[i] = vec->vector[i + nlines];
6932 vec->nlines -= nlines;
6935 static void linevector_copy PROTO ((struct linevector *, struct linevector *));
6937 /* Copy FROM to TO, copying the vectors but not the lines pointed to. */
6939 linevector_copy (to, from)
6940 struct linevector *to;
6941 struct linevector *from;
6945 for (ln = 0; ln < to->nlines; ++ln)
6947 if (--to->vector[ln]->refcount == 0)
6948 free (to->vector[ln]);
6950 if (from->nlines > to->lines_alloced)
6952 if (to->lines_alloced == 0)
6953 to->lines_alloced = 10;
6954 while (from->nlines > to->lines_alloced)
6955 to->lines_alloced *= 2;
6956 to->vector = (struct line **)
6957 xrealloc (to->vector, to->lines_alloced * sizeof (*to->vector));
6959 memcpy (to->vector, from->vector,
6960 from->nlines * sizeof (*to->vector));
6961 to->nlines = from->nlines;
6962 for (ln = 0; ln < to->nlines; ++ln)
6963 ++to->vector[ln]->refcount;
6966 static void linevector_free PROTO ((struct linevector *));
6968 /* Free storage associated with linevector. */
6970 linevector_free (vec)
6971 struct linevector *vec;
6975 if (vec->vector != NULL)
6977 for (ln = 0; ln < vec->nlines; ++ln)
6978 if (--vec->vector[ln]->refcount == 0)
6979 free (vec->vector[ln]);
6985 static char *month_printname PROTO ((char *));
6987 /* Given a textual string giving the month (1-12), terminated with any
6988 character not recognized by atoi, return the 3 character name to
6989 print it with. I do not think it is a good idea to change these
6990 strings based on the locale; they are standard abbreviations (for
6991 example in rfc822 mail messages) which should be widely understood.
6992 Returns a pointer into static readonly storage. */
6994 month_printname (month)
6997 static const char *const months[] =
6998 {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
6999 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
7002 mnum = atoi (month);
7003 if (mnum < 1 || mnum > 12)
7005 return (char *)months[mnum - 1];
7009 apply_rcs_changes PROTO ((struct linevector *, const char *, size_t,
7010 const char *, RCSVers *, RCSVers *));
7012 /* Apply changes to the line vector LINES. DIFFBUF is a buffer of
7013 length DIFFLEN holding the change text from an RCS file (the output
7014 of diff -n). NAME is used in error messages. The VERS field of
7015 any line added is set to ADDVERS. The VERS field of any line
7016 deleted is set to DELVERS, unless DELVERS is NULL, in which case
7017 the VERS field of deleted lines is unchanged. The function returns
7018 non-zero if the change text is applied successfully. It returns
7019 zero if the change text does not appear to apply to LINES (e.g., a
7020 line number is invalid). If the change text is improperly
7021 formatted (e.g., it is not the output of diff -n), the function
7022 calls error with a status of 1, causing the program to exit. */
7025 apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
7026 struct linevector *lines;
7027 const char *diffbuf;
7036 /* The RCS format throws us for a loop in that the deltafrags (if
7037 we define a deltafrag as an add or a delete) need to be applied
7038 in reverse order. So we stick them into a linked list. */
7040 enum {FRAG_ADD, FRAG_DELETE} type;
7042 unsigned long nlines;
7043 const char *new_lines;
7045 struct deltafrag *next;
7047 struct deltafrag *dfhead;
7048 struct deltafrag *df;
7051 for (p = diffbuf; p != NULL && p < diffbuf + difflen; )
7054 if (op != 'a' && op != 'd')
7055 /* Can't just skip over the deltafrag, because the value
7056 of op determines the syntax. */
7057 error (1, 0, "unrecognized operation '\\x%x' in %s",
7059 df = (struct deltafrag *) xmalloc (sizeof (struct deltafrag));
7062 df->pos = strtoul (p, (char **) &q, 10);
7065 error (1, 0, "number expected in %s", name);
7068 error (1, 0, "space expected in %s", name);
7069 df->nlines = strtoul (p, (char **) &q, 10);
7071 error (1, 0, "number expected in %s", name);
7074 error (1, 0, "linefeed expected in %s", name);
7080 df->type = FRAG_ADD;
7082 /* The text we want is the number of lines specified, or
7083 until the end of the value, whichever comes first (it
7084 will be the former except in the case where we are
7085 adding a line which does not end in newline). */
7086 for (q = p; i != 0; ++q)
7089 else if (q == diffbuf + difflen)
7092 error (1, 0, "premature end of change in %s", name);
7097 /* Stash away a pointer to the text we are adding. */
7105 /* Correct for the fact that line numbers in RCS files
7110 df->type = FRAG_DELETE;
7114 for (df = dfhead; df != NULL;)
7121 if (! linevector_add (lines, df->new_lines, df->len, addvers,
7126 if (df->pos > lines->nlines
7127 || df->pos + df->nlines > lines->nlines)
7129 if (delvers != NULL)
7130 for (ln = df->pos; ln < df->pos + df->nlines; ++ln)
7131 lines->vector[ln]->vers = delvers;
7132 linevector_delete (lines, df->pos, df->nlines);
7143 /* Apply an RCS change text to a buffer. The function name starts
7144 with rcs rather than RCS because this does not take an RCSNode
7145 argument. NAME is used in error messages. TEXTBUF is the text
7146 buffer to change, and TEXTLEN is the size. DIFFBUF and DIFFLEN are
7147 the change buffer and size. The new buffer is returned in *RETBUF
7148 and *RETLEN. The new buffer is allocated by xmalloc.
7150 Return 1 for success. On failure, call error and return 0. */
7153 rcs_change_text (name, textbuf, textlen, diffbuf, difflen, retbuf, retlen)
7157 const char *diffbuf;
7162 struct linevector lines;
7168 linevector_init (&lines);
7170 if (! linevector_add (&lines, textbuf, textlen, NULL, 0))
7171 error (1, 0, "cannot initialize line vector");
7173 if (! apply_rcs_changes (&lines, diffbuf, difflen, name, NULL, NULL))
7175 error (0, 0, "invalid change text in %s", name);
7185 for (ln = 0; ln < lines.nlines; ++ln)
7187 n += lines.vector[ln]->len + 1;
7192 for (ln = 0; ln < lines.nlines; ++ln)
7194 memcpy (p, lines.vector[ln]->text, lines.vector[ln]->len);
7195 p += lines.vector[ln]->len;
7196 if (lines.vector[ln]->has_newline)
7200 *retlen = p - *retbuf;
7201 assert (*retlen <= n);
7206 linevector_free (&lines);
7211 /* Walk the deltas in RCS to get to revision VERSION.
7213 If OP is RCS_ANNOTATE, then write annotations using cvs_output.
7215 If OP is RCS_FETCH, then put the contents of VERSION into a
7216 newly-malloc'd array and put a pointer to it in *TEXT. Each line
7217 is \n terminated; the caller is responsible for converting text
7218 files if desired. The total length is put in *LEN.
7220 If FP is non-NULL, it should be a file descriptor open to the file
7221 RCS with file position pointing to the deltas. We close the file
7224 If LOG is non-NULL, then *LOG is set to the log message of VERSION,
7225 and *LOGLEN is set to the length of the log message.
7227 On error, give a fatal error. */
7230 RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
7233 struct rcsbuffer *rcsbuf;
7234 const char *version;
7235 enum rcs_delta_op op;
7241 struct rcsbuffer rcsbuf_local;
7242 char *branchversion;
7249 RCSVers *trunk_vers;
7251 int ishead, isnext, isversion, onbranch;
7253 struct linevector headlines;
7254 struct linevector curlines;
7255 struct linevector trunklines;
7260 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf_local);
7261 rcsbuf = &rcsbuf_local;
7272 linevector_init (&curlines);
7273 linevector_init (&headlines);
7274 linevector_init (&trunklines);
7276 /* We set BRANCHVERSION to the version we are currently looking
7277 for. Initially, this is the version on the trunk from which
7278 VERSION branches off. If VERSION is not a branch, then
7279 BRANCHVERSION is just VERSION. */
7280 branchversion = xstrdup (version);
7281 cpversion = strchr (branchversion, '.');
7282 if (cpversion != NULL)
7283 cpversion = strchr (cpversion + 1, '.');
7284 if (cpversion != NULL)
7288 if (! rcsbuf_getrevnum (rcsbuf, &key))
7289 error (1, 0, "unexpected EOF reading RCS file %s", rcs->path);
7291 if (next != NULL && ! STREQ (next, key))
7293 /* This is not the next version we need. It is a branch
7294 version which we want to ignore. */
7302 /* look up the revision */
7303 node = findnode (rcs->versions, key);
7306 "mismatch in rcs file %s between deltas and deltatexts (%s)",
7309 /* Stash the previous version. */
7315 /* Compare key and trunkversion now, because key points to
7316 storage controlled by rcsbuf_getkey. */
7317 if (STREQ (branchversion, key))
7325 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7326 error (1, 0, "%s does not appear to be a valid rcs file",
7331 && STREQ (key, "log")
7332 && STREQ (branchversion, version))
7334 *log = rcsbuf_valcopy (rcsbuf, value, 0, loglen);
7337 if (STREQ (key, "text"))
7339 rcsbuf_valpolish (rcsbuf, value, 0, &vallen);
7342 if (! linevector_add (&curlines, value, vallen, NULL, 0))
7343 error (1, 0, "invalid rcs file %s", rcs->path);
7349 if (! apply_rcs_changes (&curlines, value, vallen,
7351 onbranch ? vers : NULL,
7352 onbranch ? NULL : prev_vers))
7353 error (1, 0, "invalid change text in %s", rcs->path);
7361 /* This is either the version we want, or it is the
7362 branchpoint to the version we want. */
7363 if (STREQ (branchversion, version))
7365 /* This is the version we want. */
7366 linevector_copy (&headlines, &curlines);
7370 /* We have found this version by tracking up a
7371 branch. Restore back to the lines we saved
7372 when we left the trunk, and continue tracking
7377 linevector_copy (&curlines, &trunklines);
7384 /* We need to look up the branch. */
7387 if (numdots (branchversion) < 2)
7391 /* We are leaving the trunk; save the current
7392 lines so that we can restore them when we
7393 continue tracking down the trunk. */
7395 linevector_copy (&trunklines, &curlines);
7397 /* Reset the version information we have
7398 accumulated so far. It only applies to the
7399 changes from the head to this version. */
7400 for (ln = 0; ln < curlines.nlines; ++ln)
7401 curlines.vector[ln]->vers = NULL;
7404 /* The next version we want is the entry on
7405 VERS->branches which matches this branch. For
7406 example, suppose VERSION is 1.21.4.3 and
7407 BRANCHVERSION was 1.21. Then we look for an entry
7408 starting with "1.21.4" and we'll put it (probably
7409 1.21.4.1) in NEXT. We'll advance BRANCHVERSION by
7410 two dots (in this example, to 1.21.4.3). */
7412 if (vers->branches == NULL)
7413 error (1, 0, "missing expected branches in %s",
7417 cpversion = strchr (cpversion, '.');
7418 if (cpversion == NULL)
7419 error (1, 0, "version number confusion in %s",
7421 for (p = vers->branches->list->next;
7422 p != vers->branches->list;
7424 if (strncmp (p->key, branchversion,
7425 cpversion - branchversion) == 0)
7427 if (p == vers->branches->list)
7428 error (1, 0, "missing expected branch in %s",
7433 cpversion = strchr (cpversion + 1, '.');
7434 if (cpversion != NULL)
7438 if (op == RCS_FETCH && foundhead)
7440 } while (next != NULL);
7442 free (branchversion);
7444 rcsbuf_cache (rcs, rcsbuf);
7447 error (1, 0, "could not find desired version %s in %s",
7448 version, rcs->path);
7450 /* Now print out or return the data we have just computed. */
7457 for (ln = 0; ln < headlines.nlines; ++ln)
7460 /* Period which separates year from month in date. */
7462 /* Period which separates month from day in date. */
7466 prvers = headlines.vector[ln]->vers;
7470 buf = xmalloc (strlen (prvers->version) + 24);
7471 sprintf (buf, "%-12s (%-8.8s ",
7474 cvs_output (buf, 0);
7477 /* Now output the date. */
7478 ym = strchr (prvers->date, '.');
7481 /* ??- is an ANSI trigraph. The ANSI way to
7482 avoid it is \? but some pre ANSI compilers
7483 complain about the unrecognized escape
7484 sequence. Of course string concatenation
7485 ("??" "-???") is also an ANSI-ism. Testing
7486 __STDC__ seems to be a can of worms, since
7487 compilers do all kinds of things with it. */
7488 cvs_output ("??", 0);
7489 cvs_output ("-???", 0);
7490 cvs_output ("-??", 0);
7494 md = strchr (ym + 1, '.');
7496 cvs_output ("??", 0);
7498 cvs_output (md + 1, 2);
7500 cvs_output ("-", 1);
7501 cvs_output (month_printname (ym + 1), 0);
7502 cvs_output ("-", 1);
7503 /* Only output the last two digits of the year. Our output
7504 lines are long enough as it is without printing the
7506 cvs_output (ym - 2, 2);
7508 cvs_output ("): ", 0);
7509 if (headlines.vector[ln]->len != 0)
7510 cvs_output (headlines.vector[ln]->text,
7511 headlines.vector[ln]->len);
7512 cvs_output ("\n", 1);
7522 assert (text != NULL);
7523 assert (len != NULL);
7526 for (ln = 0; ln < headlines.nlines; ++ln)
7528 n += headlines.vector[ln]->len + 1;
7531 for (ln = 0; ln < headlines.nlines; ++ln)
7533 memcpy (p, headlines.vector[ln]->text,
7534 headlines.vector[ln]->len);
7535 p += headlines.vector[ln]->len;
7536 if (headlines.vector[ln]->has_newline)
7545 linevector_free (&curlines);
7546 linevector_free (&headlines);
7547 linevector_free (&trunklines);
7552 /* Read the information for a single delta from the RCS buffer RCSBUF,
7553 whose name is RCSFILE. *KEYP and *VALP are either NULL, or the
7554 first key/value pair to read, as set by rcsbuf_getkey. Return NULL
7555 if there are no more deltas. Store the key/value pair which
7556 terminated the read in *KEYP and *VALP. */
7559 getdelta (rcsbuf, rcsfile, keyp, valp)
7560 struct rcsbuffer *rcsbuf;
7566 char *key, *value, *cp;
7569 /* Get revision number if it wasn't passed in. This uses
7570 rcsbuf_getkey because it doesn't croak when encountering
7571 unexpected input. As a result, we have to play unholy games
7572 with `key' and `value'. */
7580 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7581 error (1, 0, "%s: unexpected EOF", rcsfile);
7584 /* Make sure that it is a revision number and not a cabbage
7587 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
7590 /* Note that when comparing with RCSDATE, we are not massaging
7591 VALUE from the string found in the RCS file. This is OK since
7592 we know exactly what to expect. */
7593 if (*cp != '\0' || strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) != 0)
7600 vnode = (RCSVers *) xmalloc (sizeof (RCSVers));
7601 memset (vnode, 0, sizeof (RCSVers));
7603 vnode->version = xstrdup (key);
7605 /* Grab the value of the date from value. Note that we are not
7606 massaging VALUE from the string found in the RCS file. */
7607 cp = value + (sizeof RCSDATE) - 1; /* skip the "date" keyword */
7608 while (whitespace (*cp)) /* take space off front of value */
7611 vnode->date = xstrdup (cp);
7613 /* Get author field. */
7614 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7616 error (1, 0, "unexpected end of file reading %s", rcsfile);
7618 if (! STREQ (key, "author"))
7620 unable to parse %s; `author' not in the expected place", rcsfile);
7621 vnode->author = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7623 /* Get state field. */
7624 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7626 error (1, 0, "unexpected end of file reading %s", rcsfile);
7628 if (! STREQ (key, "state"))
7630 unable to parse %s; `state' not in the expected place", rcsfile);
7631 vnode->state = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7632 /* The value is optional, according to rcsfile(5). */
7633 if (value != NULL && STREQ (value, RCSDEAD))
7638 /* Note that "branches" and "next" are in fact mandatory, according
7641 /* fill in the branch list (if any branches exist) */
7642 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7644 error (1, 0, "unexpected end of file reading %s", rcsfile);
7646 if (STREQ (key, RCSDESC))
7650 /* Probably could/should be a fatal error. */
7651 error (0, 0, "warning: 'branches' keyword missing from %s", rcsfile);
7654 if (value != (char *) NULL)
7656 vnode->branches = getlist ();
7657 /* Note that we are not massaging VALUE from the string found
7659 do_branches (vnode->branches, value);
7662 /* fill in the next field if there is a next revision */
7663 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7665 error (1, 0, "unexpected end of file reading %s", rcsfile);
7667 if (STREQ (key, RCSDESC))
7671 /* Probably could/should be a fatal error. */
7672 error (0, 0, "warning: 'next' keyword missing from %s", rcsfile);
7675 if (value != (char *) NULL)
7676 vnode->next = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7679 * XXX - this is where we put the symbolic link stuff???
7680 * (into newphrases in the deltas).
7684 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7685 error (1, 0, "unexpected end of file reading %s", rcsfile);
7687 /* The `desc' keyword is the end of the deltas. */
7688 if (strcmp (key, RCSDESC) == 0)
7691 #ifdef PRESERVE_PERMISSIONS_SUPPORT
7693 /* The `hardlinks' value is a group of words, which must
7694 be parsed separately and added as a list to vnode->hardlinks. */
7695 if (strcmp (key, "hardlinks") == 0)
7699 vnode->hardlinks = getlist();
7700 while ((word = rcsbuf_valword (rcsbuf, &value)) != NULL)
7702 Node *n = getnode();
7704 addnode (vnode->hardlinks, n);
7710 /* Enable use of repositories created by certain obsolete
7711 versions of CVS. This code should remain indefinately;
7712 there is no procedure for converting old repositories, and
7713 checking for it is harmless. */
7714 if (STREQ (key, RCSDEAD))
7717 if (vnode->state != NULL)
7718 free (vnode->state);
7719 vnode->state = xstrdup (RCSDEAD);
7722 /* if we have a new revision number, we're done with this delta */
7724 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
7727 /* Note that when comparing with RCSDATE, we are not massaging
7728 VALUE from the string found in the RCS file. This is OK
7729 since we know exactly what to expect. */
7730 if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0)
7733 /* At this point, key and value represent a user-defined field
7734 in the delta node. */
7735 if (vnode->other_delta == NULL)
7736 vnode->other_delta = getlist ();
7738 kv->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
7739 kv->key = xstrdup (key);
7740 kv->data = rcsbuf_valcopy (rcsbuf, value, kv->type == RCSFIELD,
7742 if (addnode (vnode->other_delta, kv) != 0)
7744 /* Complaining about duplicate keys in newphrases seems
7745 questionable, in that we don't know what they mean and
7746 doc/RCSFILES has no prohibition on several newphrases
7747 with the same key. But we can't store more than one as
7748 long as we store them in a List *. */
7749 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
7755 /* Return the key which caused us to fail back to the caller. */
7766 if (d->version != NULL)
7770 if (d->text != NULL)
7772 if (d->other != (List *) NULL)
7773 dellist (&d->other);
7778 RCS_getdeltatext (rcs, fp, rcsbuf)
7781 struct rcsbuffer *rcsbuf;
7788 /* Get the revision number. */
7789 if (! rcsbuf_getrevnum (rcsbuf, &num))
7791 /* If num == NULL, it means we reached EOF naturally. That's
7796 error (1, 0, "%s: unexpected EOF", rcs->path);
7799 p = findnode (rcs->versions, num);
7801 error (1, 0, "mismatch in rcs file %s between deltas and deltatexts (%s)",
7804 d = (Deltatext *) xmalloc (sizeof (Deltatext));
7805 d->version = xstrdup (num);
7807 /* Get the log message. */
7808 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7809 error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num);
7810 if (! STREQ (key, "log"))
7811 error (1, 0, "%s, delta %s: expected `log', got `%s'",
7812 rcs->path, num, key);
7813 d->log = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7815 /* Get random newphrases. */
7816 d->other = getlist();
7819 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7820 error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num);
7822 if (STREQ (key, "text"))
7826 p->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
7827 p->key = xstrdup (key);
7828 p->data = rcsbuf_valcopy (rcsbuf, value, p->type == RCSFIELD,
7830 if (addnode (d->other, p) < 0)
7832 error (0, 0, "warning: %s, delta %s: duplicate field `%s'",
7833 rcs->path, num, key);
7837 /* Get the change text. We already know that this key is `text'. */
7838 d->text = rcsbuf_valcopy (rcsbuf, value, 0, &d->len);
7843 /* RCS output functions, for writing RCS format files from RCSNode
7846 For most of this work, RCS 5.7 uses an `aprintf' function which aborts
7847 program upon error. Instead, these functions check the output status
7848 of the stream right before closing it, and aborts if an error condition
7849 is found. The RCS solution is probably the better one: it produces
7850 more overhead, but will produce a clearer diagnostic in the case of
7851 catastrophic error. In either case, however, the repository will probably
7852 not get corrupted. */
7855 putsymbol_proc (symnode, fparg)
7859 FILE *fp = (FILE *) fparg;
7861 /* A fiddly optimization: this code used to just call fprintf, but
7862 in an old repository with hundreds of tags this can get called
7863 hundreds of thousands of times when doing a cvs tag. Since
7864 tagging is a relatively common operation, and using putc and
7865 fputs is just as comprehensible, the change is worthwhile. */
7868 fputs (symnode->key, fp);
7870 fputs (symnode->data, fp);
7874 static int putlock_proc PROTO ((Node *, void *));
7876 /* putlock_proc is like putsymbol_proc, but key and data are reversed. */
7879 putlock_proc (symnode, fp)
7883 return fprintf ((FILE *) fp, "\n\t%s:%s", (char *)symnode->data, symnode->key);
7887 putrcsfield_proc (node, vfp)
7891 FILE *fp = (FILE *) vfp;
7893 /* Some magic keys used internally by CVS start with `;'. Skip them. */
7894 if (node->key[0] == ';')
7897 fprintf (fp, "\n%s\t", node->key);
7898 if (node->data != NULL)
7900 /* If the field's value contains evil characters,
7901 it must be stringified. */
7902 /* FIXME: This does not quite get it right. "7jk8f" is not a legal
7903 value for a value in a newpharse, according to doc/RCSFILES,
7904 because digits are not valid in an "id". We might do OK by
7905 always writing strings (enclosed in @@). Would be nice to
7906 explicitly mention this one way or another in doc/RCSFILES.
7907 A case where we are wrong in a much more clear-cut way is that
7908 we let through non-graphic characters such as whitespace and
7909 control characters. */
7911 if (node->type == RCSCMPFLD || strpbrk (node->data, "$,.:;@") == NULL)
7912 fputs (node->data, fp);
7916 expand_at_signs (node->data, (off_t) strlen (node->data), fp);
7921 /* desc, log and text fields should not be terminated with semicolon;
7922 all other fields should be. */
7923 if (! STREQ (node->key, "desc") &&
7924 ! STREQ (node->key, "log") &&
7925 ! STREQ (node->key, "text"))
7932 #ifdef PRESERVE_PERMISSIONS_SUPPORT
7934 /* Save a filename in a `hardlinks' RCS field. NODE->KEY will contain
7935 a full pathname, but currently only basenames are stored in the RCS
7936 node. Assume that the filename includes nasty characters and
7940 puthardlink_proc (node, vfp)
7944 FILE *fp = (FILE *) vfp;
7945 char *basename = strrchr (node->key, '/');
7947 if (basename == NULL)
7948 basename = node->key;
7954 (void) expand_at_signs (basename, strlen (basename), fp);
7962 /* Output the admin node for RCS into stream FP. */
7965 RCS_putadmin (rcs, fp)
7969 fprintf (fp, "%s\t%s;\n", RCSHEAD, rcs->head ? rcs->head : "");
7971 fprintf (fp, "%s\t%s;\n", RCSBRANCH, rcs->branch);
7973 fputs ("access", fp);
7977 s = xstrdup (rcs->access);
7978 for (p = strtok (s, " \n\t"); p != NULL; p = strtok (NULL, " \n\t"))
7979 fprintf (fp, "\n\t%s", p);
7984 fputs (RCSSYMBOLS, fp);
7985 /* If we haven't had to convert the symbols to a list yet, don't
7986 force a conversion now; just write out the string. */
7987 if (rcs->symbols == NULL && rcs->symbols_data != NULL)
7990 fputs (rcs->symbols_data, fp);
7993 walklist (RCS_symbols (rcs), putsymbol_proc, (void *) fp);
7996 fputs ("locks", fp);
7997 if (rcs->locks_data)
7998 fprintf (fp, "\t%s", rcs->locks_data);
7999 else if (rcs->locks)
8000 walklist (rcs->locks, putlock_proc, (void *) fp);
8001 if (rcs->strict_locks)
8002 fprintf (fp, "; strict");
8007 fprintf (fp, "comment\t@");
8008 expand_at_signs (rcs->comment, (off_t) strlen (rcs->comment), fp);
8011 if (rcs->expand && ! STREQ (rcs->expand, "kv"))
8012 fprintf (fp, "%s\t@%s@;\n", RCSEXPAND, rcs->expand);
8014 walklist (rcs->other, putrcsfield_proc, (void *) fp);
8026 /* Skip if no revision was supplied, or if it is outdated (cvs admin -o) */
8027 if (vers == NULL || vers->outdated)
8030 fprintf (fp, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches",
8032 RCSDATE, vers->date,
8033 "author", vers->author,
8034 "state", vers->state ? vers->state : "");
8036 if (vers->branches != NULL)
8038 start = vers->branches->list;
8039 for (bp = start->next; bp != start; bp = bp->next)
8040 fprintf (fp, "\n\t%s", bp->key);
8043 fprintf (fp, ";\nnext\t%s;", vers->next ? vers->next : "");
8045 walklist (vers->other_delta, putrcsfield_proc, fp);
8047 #ifdef PRESERVE_PERMISSIONS_SUPPORT
8048 if (vers->hardlinks)
8050 fprintf (fp, "\nhardlinks");
8051 walklist (vers->hardlinks, puthardlink_proc, fp);
8059 RCS_putdtree (rcs, rev, fp)
8070 /* Find the delta node for this revision. */
8071 p = findnode (rcs->versions, rev);
8075 "error parsing repository file %s, file may be corrupt.",
8081 /* Print the delta node and recurse on its `next' node. This prints
8082 the trunk. If there are any branches printed on this revision,
8083 print those trunks as well. */
8084 putdelta (versp, fp);
8085 RCS_putdtree (rcs, versp->next, fp);
8086 if (versp->branches != NULL)
8088 branch = versp->branches->list;
8089 for (p = branch->next; p != branch; p = p->next)
8090 RCS_putdtree (rcs, p->key, fp);
8095 RCS_putdesc (rcs, fp)
8099 fprintf (fp, "\n\n%s\n@", RCSDESC);
8100 if (rcs->desc != NULL)
8102 off_t len = (off_t) strlen (rcs->desc);
8105 expand_at_signs (rcs->desc, len, fp);
8106 if (rcs->desc[len-1] != '\n')
8114 putdeltatext (fp, d)
8118 fprintf (fp, "\n\n%s\nlog\n@", d->version);
8121 int loglen = strlen (d->log);
8122 expand_at_signs (d->log, (off_t) loglen, fp);
8123 if (d->log[loglen-1] != '\n')
8128 walklist (d->other, putrcsfield_proc, fp);
8130 fputs ("\ntext\n@", fp);
8131 if (d->text != NULL)
8132 expand_at_signs (d->text, (off_t) d->len, fp);
8136 /* TODO: the whole mechanism for updating deltas is kludgey... more
8137 sensible would be to supply all the necessary info in a `newdeltatext'
8138 field for RCSVers nodes. -twp */
8140 /* Copy delta text nodes from FIN to FOUT. If NEWDTEXT is non-NULL, it
8141 is a new delta text node, and should be added to the tree at the
8142 node whose revision number is INSERTPT. (Note that trunk nodes are
8143 written in decreasing order, and branch nodes are written in
8144 increasing order.) */
8147 RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt)
8150 struct rcsbuffer *rcsbufin;
8152 Deltatext *newdtext;
8158 int insertbefore, found;
8167 /* Count the number of versions for which we have to do some
8168 special operation. */
8169 actions = walklist (rcs->versions, count_delta_actions, (void *) NULL);
8171 /* Make a note of whether NEWDTEXT should be inserted
8172 before or after its INSERTPT. */
8173 insertbefore = (newdtext != NULL && numdots (newdtext->version) == 1);
8175 while (actions != 0 || newdtext != NULL)
8179 dtext = RCS_getdeltatext (rcs, fin, rcsbufin);
8181 /* We shouldn't hit EOF here, because that would imply that
8182 some action was not taken, or that we could not insert
8185 error (1, 0, "internal error: EOF too early in RCS_copydeltas");
8187 found = (insertpt != NULL && STREQ (dtext->version, insertpt));
8188 if (found && insertbefore)
8190 putdeltatext (fout, newdtext);
8195 np = findnode (rcs->versions, dtext->version);
8198 /* If this revision has been outdated, just skip it. */
8199 if (dadmin->outdated)
8201 freedeltatext (dtext);
8206 /* Update the change text for this delta. New change text
8207 data may come from cvs admin -m, cvs admin -o, or cvs ci. */
8208 if (dadmin->text != NULL)
8210 if (dadmin->text->log != NULL || dadmin->text->text != NULL)
8212 if (dadmin->text->log != NULL)
8215 dtext->log = dadmin->text->log;
8216 dadmin->text->log = NULL;
8218 if (dadmin->text->text != NULL)
8221 dtext->text = dadmin->text->text;
8222 dtext->len = dadmin->text->len;
8223 dadmin->text->text = NULL;
8226 putdeltatext (fout, dtext);
8227 freedeltatext (dtext);
8229 if (found && !insertbefore)
8231 putdeltatext (fout, newdtext);
8237 /* Copy the rest of the file directly, without bothering to
8238 interpret it. The caller will handle error checking by calling
8241 We just wrote a newline to the file, either in putdeltatext or
8242 in the caller. However, we may not have read the corresponding
8243 newline from the file, because rcsbuf_getkey returns as soon as
8244 it finds the end of the '@' string for the desc or text key.
8245 Therefore, we may read three newlines when we should really
8246 only write two, and we check for that case here. This is not
8247 an semantically important issue; we only do it to make our RCS
8248 files look traditional. */
8252 rcsbuf_get_buffered (rcsbufin, &bufrest, &buflen);
8255 if (bufrest[0] != '\n'
8256 || strncmp (bufrest, "\n\n\n", buflen < 3 ? buflen : 3) != 0)
8272 fwrite (bufrest, 1, buflen, fout);
8275 /* This bit isn't necessary when using mmap since the entire file
8276 * will already be available via the RCS buffer. Besides, the
8277 * mmap code doesn't always keep the file pointer up to date, so
8278 * this adds some data twice.
8280 while ((got = fread (buf, 1, sizeof buf, fin)) != 0)
8285 && strncmp (buf, "\n\n\n", nls) == 0)
8287 fwrite (buf + 1, 1, got - 1, fout);
8291 fwrite (buf, 1, got, fout);
8296 #endif /* HAVE_MMAP */
8299 /* A helper procedure for RCS_copydeltas. This is called via walklist
8300 to count the number of RCS revisions for which some special action
8304 count_delta_actions (np, ignore)
8308 RCSVers *dadmin = np->data;
8310 if (dadmin->outdated)
8313 if (dadmin->text != NULL
8314 && (dadmin->text->log != NULL || dadmin->text->text != NULL))
8323 * Clean up temporary files
8328 /* Note that the checks for existence_error are because we are
8329 called from a signal handler, so we don't know whether the
8330 files got created. */
8332 /* FIXME: Do not perform buffered I/O from an interrupt handler like
8333 this (via error). However, I'm leaving the error-calling code there
8334 in the hope that on the rare occasion the error call is actually made
8335 (e.g., a fluky I/O error or permissions problem prevents the deletion
8336 of a just-created file) reentrancy won't be an issue. */
8337 if (rcs_lockfile != NULL)
8339 char *tmp = rcs_lockfile;
8340 rcs_lockfile = NULL;
8341 if (rcs_lockfd >= 0)
8343 if (close (rcs_lockfd) != 0)
8344 error (0, errno, "error closing lock file %s", tmp);
8347 if (unlink_file (tmp) < 0
8348 && !existence_error (errno))
8349 error (0, errno, "cannot remove %s", tmp);
8353 /* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style
8354 locking on the specified RCSFILE: for a file called `foo,v', open
8355 for writing a file called `,foo,'.
8357 Note that we what do here is quite different from what RCS does.
8358 RCS creates the ,foo, file before it reads the RCS file (if it
8359 knows that it will be writing later), so that it actually serves as
8360 a lock. We don't; instead we rely on CVS writelocks. This means
8361 that if someone is running RCS on the file at the same time they
8362 are running CVS on it, they might lose (we read the file,
8363 then RCS writes it, then we write it, clobbering the
8364 changes made by RCS). I believe the current sentiment about this
8365 is "well, don't do that".
8367 A concern has been expressed about whether adopting the RCS
8368 strategy would slow us down. I don't think so, since we need to
8369 write the ,foo, file anyway (unless perhaps if O_EXCL is slower or
8372 These do not perform quite the same function as the RCS -l option
8373 for locking files: they are intended to prevent competing RCS
8374 processes from stomping all over each other's laundry. Hence,
8375 they are `internal' locking functions.
8377 If there is an error, give a fatal error; if we return we always
8378 return a non-NULL value. */
8381 rcs_internal_lockfile (rcsfile)
8386 static int first_call = 1;
8391 /* clean up if we get a signal */
8393 (void) SIG_register (SIGABRT, rcs_cleanup);
8396 (void) SIG_register (SIGHUP, rcs_cleanup);
8399 (void) SIG_register (SIGINT, rcs_cleanup);
8402 (void) SIG_register (SIGQUIT, rcs_cleanup);
8405 (void) SIG_register (SIGPIPE, rcs_cleanup);
8408 (void) SIG_register (SIGTERM, rcs_cleanup);
8412 /* Get the lock file name: `,file,' for RCS file `file,v'. */
8413 assert (rcs_lockfile == NULL);
8414 assert (rcs_lockfd < 0);
8415 rcs_lockfile = rcs_lockfilename (rcsfile);
8417 /* Use the existing RCS file mode, or read-only if this is a new
8418 file. (Really, this is a lie -- if this is a new file,
8419 RCS_checkin uses the permissions from the working copy. For
8420 actually creating the file, we use 0444 as a safe default mode.) */
8421 if (stat (rcsfile, &rstat) < 0)
8423 if (existence_error (errno))
8424 rstat.st_mode = S_IRUSR | S_IRGRP | S_IROTH;
8426 error (1, errno, "cannot stat %s", rcsfile);
8429 /* Try to open exclusively. POSIX.1 guarantees that O_EXCL|O_CREAT
8430 guarantees an exclusive open. According to the RCS source, with
8431 NFS v2 we must also throw in O_TRUNC and use an open mask that makes
8432 the file unwriteable. For extensive justification, see the comments for
8433 rcswriteopen() in rcsedit.c, in RCS 5.7. This is kind of pointless
8434 in the CVS case; see comment at the start of this file concerning
8435 general ,foo, file strategy.
8437 There is some sentiment that with NFSv3 and such, that one can
8438 rely on O_EXCL these days. This might be true for unix (I
8439 don't really know), but I am still pretty skeptical in the case
8440 of the non-unix systems. */
8441 rcs_lockfd = open (rcs_lockfile,
8442 OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
8443 S_IRUSR | S_IRGRP | S_IROTH);
8447 error (1, errno, "could not open lock file `%s'", rcs_lockfile);
8450 /* Force the file permissions, and return a stream object. */
8451 /* Because we change the modes later, we don't worry about
8452 this in the non-HAVE_FCHMOD case. */
8454 if (fchmod (rcs_lockfd, rstat.st_mode) < 0)
8455 error (1, errno, "cannot change mode for %s", rcs_lockfile);
8457 fp = fdopen (rcs_lockfd, FOPEN_BINARY_WRITE);
8459 error (1, errno, "cannot fdopen %s", rcs_lockfile);
8465 rcs_internal_unlockfile (fp, rcsfile)
8469 assert (rcs_lockfile != NULL);
8470 assert (rcs_lockfd >= 0);
8472 /* Abort if we could not write everything successfully to LOCKFILE.
8473 This is not a great error-handling mechanism, but should prevent
8474 corrupting the repository. */
8477 /* Using errno here may well be misleanding since the most recent
8478 call that set errno may not have anything whatsoever to do with
8479 the error that set the flag, but it's better than nothing. The
8480 real solution is to check each call to fprintf rather than waiting
8481 until the end like this. */
8482 error (1, errno, "error writing to lock file %s", rcs_lockfile);
8483 if (fclose (fp) == EOF)
8484 error (1, errno, "error closing lock file %s", rcs_lockfile);
8487 rename_file (rcs_lockfile, rcsfile);
8490 /* Use a temporary to make sure there's no interval
8491 (after rcs_lockfile has been freed but before it's set to NULL)
8492 during which the signal handler's use of rcs_lockfile would
8493 reference freed memory. */
8494 char *tmp = rcs_lockfile;
8495 rcs_lockfile = NULL;
8501 rcs_lockfilename (rcsfile)
8502 const char *rcsfile;
8504 char *lockfile, *lockp;
8505 const char *rcsbase, *rcsp, *rcsend;
8508 /* Create the lockfile name. */
8509 rcslen = strlen (rcsfile);
8510 lockfile = (char *) xmalloc (rcslen + 10);
8511 rcsbase = last_component (rcsfile);
8512 rcsend = rcsfile + rcslen - sizeof(RCSEXT);
8513 for (lockp = lockfile, rcsp = rcsfile; rcsp < rcsbase; ++rcsp)
8516 while (rcsp <= rcsend)
8524 /* Rewrite an RCS file. The basic idea here is that the caller should
8525 first call RCS_reparsercsfile, then munge the data structures as
8526 desired (via RCS_delete_revs, RCS_settag, &c), then call RCS_rewrite. */
8529 RCS_rewrite (rcs, newdtext, insertpt)
8531 Deltatext *newdtext;
8535 struct rcsbuffer rcsbufin;
8540 /* Make sure we're operating on an actual file and not a symlink. */
8541 resolve_symlink (&(rcs->path));
8543 fout = rcs_internal_lockfile (rcs->path);
8545 RCS_putadmin (rcs, fout);
8546 RCS_putdtree (rcs, rcs->head, fout);
8547 RCS_putdesc (rcs, fout);
8549 /* Open the original RCS file and seek to the first delta text. */
8550 rcsbuf_cache_open (rcs, rcs->delta_pos, &fin, &rcsbufin);
8552 /* Update delta_pos to the current position in the output file.
8553 Do NOT move these statements: they must be done after fin has
8554 been positioned at the old delta_pos, but before any delta
8555 texts have been written to fout.
8557 rcs->delta_pos = ftell (fout);
8558 if (rcs->delta_pos == -1)
8559 error (1, errno, "cannot ftell in RCS file %s", rcs->path);
8561 RCS_copydeltas (rcs, fin, &rcsbufin, fout, newdtext, insertpt);
8563 /* We don't want to call rcsbuf_cache here, since we're about to
8565 rcsbuf_close (&rcsbufin);
8567 /* The only case in which using errno here would be meaningful
8568 is if we happen to have left errno unmolested since the call
8569 which produced the error (e.g. fread). That is pretty
8570 fragile even if it happens to sometimes be true. The real
8571 solution is to make sure that all the code which reads
8572 from fin checks for errors itself (some does, some doesn't). */
8573 error (0, 0, "warning: ferror set while rewriting RCS file `%s'", rcs->path);
8574 if (fclose (fin) < 0)
8575 error (0, errno, "warning: closing RCS file `%s'", rcs->path);
8577 rcs_internal_unlockfile (fout, rcs->path);
8580 /* Abandon changes to an RCS file. */
8586 free_rcsnode_contents (rcs);
8587 rcs->symbols_data = NULL;
8590 rcs->locks_data = NULL;
8591 rcs->comment = NULL;
8593 rcs->flags |= PARTIAL;
8597 * For a given file with full pathname PATH and revision number REV,
8598 * produce a file label suitable for passing to diff. The default
8599 * file label as used by RCS 5.7 looks like this:
8601 * FILENAME <tab> YYYY/MM/DD <sp> HH:MM:SS <tab> REVNUM
8603 * The date and time used are the revision's last checkin date and time.
8604 * If REV is NULL, use the working copy's mtime instead.
8606 * /dev/null is not statted but assumed to have been created on the Epoch.
8607 * At least using the POSIX.2 definition of patch, this should cause creation
8608 * of files on platforms such as Windoze where the null IO device isn't named
8609 * /dev/null to be parsed by patch properly.
8612 make_file_label (path, rev, rcs)
8617 char datebuf[MAXDATELEN + 1];
8620 label = (char *) xmalloc (strlen (path)
8621 + (rev == NULL ? 0 : strlen (rev) + 1)
8627 char date[MAXDATELEN + 1];
8628 /* revs cannot be attached to /dev/null ... duh. */
8629 assert (strcmp(DEVNULL, path));
8630 RCS_getrevtime (rcs, rev, datebuf, 0);
8631 (void) date_to_internet (date, datebuf);
8632 (void) sprintf (label, "-L%s\t%s\t%s", path, date, rev);
8639 if (strcmp(DEVNULL, path))
8641 const char *file = last_component (path);
8642 if (CVS_STAT (file, &sb) < 0)
8643 /* Assume that if the stat fails,then the later read for the
8646 error (1, errno, "could not get info for `%s'", path);
8647 wm = gmtime (&sb.st_mtime);
8655 (void) tm_to_internet (datebuf, wm);
8656 (void) sprintf (label, "-L%s\t%s", path, datebuf);
8662 RCS_setlocalid (arg)
8665 char *copy, *next, *key;
8667 copy = xstrdup(arg);
8669 key = strtok(next, "=");
8671 keywords[KEYWORD_LOCALID].string = xstrdup(key);
8672 keywords[KEYWORD_LOCALID].len = strlen(key);
8673 keywords[KEYWORD_LOCALID].expandit = 1;
8676 while (key = strtok(NULL, ",")) {
8677 if (!strcmp(key, keywords[KEYWORD_ID].string))
8678 keyword_local = KEYWORD_ID;
8679 else if (!strcmp(key, keywords[KEYWORD_HEADER].string))
8680 keyword_local = KEYWORD_HEADER;
8681 else if (!strcmp(key, keywords[KEYWORD_CVSHEADER].string))
8682 keyword_local = KEYWORD_CVSHEADER;
8684 error(1, 0, "Unknown LocalId mode: %s", key);
8696 struct rcs_keyword *keyword;
8698 copy = xstrdup(arg);
8713 for (keyword = keywords; keyword->string != NULL; keyword++)
8715 keyword->expandit = 0;
8718 key = strtok(next, ",");
8720 for (keyword = keywords; keyword->string != NULL; keyword++) {
8721 if (strcmp (keyword->string, key) == 0)
8722 keyword->expandit = include;
8724 key = strtok(NULL, ",");
8730 #define ATTIC "/" CVSATTIC
8732 getfullCVSname(CVSname, pathstore)
8733 char *CVSname, **pathstore;
8735 if (current_parsed_root->directory) {
8738 int alen = sizeof(ATTIC) - 1;
8740 *pathstore = xstrdup(CVSname);
8741 if ((c = strrchr(*pathstore, '/')) != NULL) {
8742 if (c - *pathstore >= alen) {
8743 if (!strncmp(c - alen, ATTIC, alen)) {
8744 while (*c != '\0') {
8753 rootlen = strlen(current_parsed_root->directory);
8754 if (!strncmp(*pathstore, current_parsed_root->directory, rootlen) &&
8755 (*pathstore)[rootlen] == '/')
8756 CVSname = (*pathstore + rootlen + 1);
8758 CVSname = (*pathstore);