2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
4 * You may distribute under the terms of the GNU General Public License as
5 * specified in the README file that comes with the CVS source distribution.
7 * The routines contained in this file do all the rcs file parsing and
16 int preserve_perms = 0;
18 /* The RCS -k options, and a set of enums that must match the array.
19 These come first so that we can use enum kflag in function
21 static const char *const kflags[] =
22 {"kv", "kvl", "k", "v", "o", "b", (char *) NULL};
23 enum kflag { KFLAG_KV = 0, KFLAG_KVL, KFLAG_K, KFLAG_V, KFLAG_O, KFLAG_B };
25 /* A structure we use to buffer the contents of an RCS file. The
26 various fields are only referenced directly by the rcsbuf_*
27 functions. We declare the struct here so that we can allocate it
28 on the stack, rather than in memory. */
32 /* Points to the current position in the buffer. */
34 /* Points just after the last valid character in the buffer. */
38 /* The name of the file, used for error messages. */
40 /* The starting file position of the data in the buffer. */
42 /* The length of the value. */
44 /* Whether the value contains an '@' string. If so, we can not
45 compress whitespace characters. */
47 /* The number of embedded '@' characters in an '@' string. If
48 this is non-zero, we must search the string for pairs of '@'
49 and convert them to a single '@'. */
53 static RCSNode *RCS_parsercsfile_i PROTO((FILE * fp, const char *rcsfile));
54 static char *RCS_getdatebranch PROTO((RCSNode * rcs, char *date, char *branch));
55 static void rcsbuf_open PROTO ((struct rcsbuffer *, FILE *fp,
56 const char *filename, unsigned long pos));
57 static void rcsbuf_close PROTO ((struct rcsbuffer *));
58 static int rcsbuf_getkey PROTO ((struct rcsbuffer *, char **keyp,
60 static int rcsbuf_getrevnum PROTO ((struct rcsbuffer *, char **revp));
61 static char *rcsbuf_fill PROTO ((struct rcsbuffer *, char *ptr, char **keyp,
63 static char *rcsbuf_valcopy PROTO ((struct rcsbuffer *, char *val, int polish,
65 static void rcsbuf_valpolish PROTO ((struct rcsbuffer *, char *val, int polish,
67 static void rcsbuf_valpolish_internal PROTO ((struct rcsbuffer *, char *to,
68 const char *from, size_t *lenp));
69 static unsigned long rcsbuf_ftell PROTO ((struct rcsbuffer *));
70 static void rcsbuf_get_buffered PROTO ((struct rcsbuffer *, char **datap,
72 static void rcsbuf_cache PROTO ((RCSNode *, struct rcsbuffer *));
73 static void rcsbuf_cache_close PROTO ((void));
74 static void rcsbuf_cache_open PROTO ((RCSNode *, long, FILE **,
76 static int checkmagic_proc PROTO((Node *p, void *closure));
77 static void do_branches PROTO((List * list, char *val));
78 static void do_symbols PROTO((List * list, char *val));
79 static void do_locks PROTO((List * list, char *val));
80 static void free_rcsnode_contents PROTO((RCSNode *));
81 static void free_rcsvers_contents PROTO((RCSVers *));
82 static void rcsvers_delproc PROTO((Node * p));
83 static char *translate_symtag PROTO((RCSNode *, const char *));
84 static char *printable_date PROTO((const char *));
85 static char *escape_keyword_value PROTO ((const char *, int *));
86 static void expand_keywords PROTO((RCSNode *, RCSVers *, const char *,
87 const char *, size_t, enum kflag, char *,
88 size_t, char **, size_t *));
89 static void cmp_file_buffer PROTO((void *, const char *, size_t));
91 enum rcs_delta_op {RCS_ANNOTATE, RCS_FETCH};
92 static void RCS_deltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *, char *,
93 enum rcs_delta_op, char **, size_t *,
96 /* Routines for reading, parsing and writing RCS files. */
97 static RCSVers *getdelta PROTO ((struct rcsbuffer *, char *, char **,
99 static Deltatext *RCS_getdeltatext PROTO ((RCSNode *, FILE *,
100 struct rcsbuffer *));
101 static void freedeltatext PROTO ((Deltatext *));
103 static void RCS_putadmin PROTO ((RCSNode *, FILE *));
104 static void RCS_putdtree PROTO ((RCSNode *, char *, FILE *));
105 static void RCS_putdesc PROTO ((RCSNode *, FILE *));
106 static void putdelta PROTO ((RCSVers *, FILE *));
107 static int putrcsfield_proc PROTO ((Node *, void *));
108 static int putsymbol_proc PROTO ((Node *, void *));
109 static void RCS_copydeltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *,
110 FILE *, Deltatext *, char *));
111 static int count_delta_actions PROTO ((Node *, void *));
112 static void putdeltatext PROTO ((FILE *, Deltatext *));
114 static FILE *rcs_internal_lockfile PROTO ((char *));
115 static void rcs_internal_unlockfile PROTO ((FILE *, char *));
116 static char *rcs_lockfilename PROTO ((char *));
118 /* The RCS file reading functions are called a lot, and they do some
119 string comparisons. This macro speeds things up a bit by skipping
120 the function call when the first characters are different. It
121 evaluates its arguments multiple times. */
122 #define STREQ(a, b) ((a)[0] == (b)[0] && strcmp ((a), (b)) == 0)
125 * We don't want to use isspace() from the C library because:
127 * 1. The definition of "whitespace" in RCS files includes ASCII
128 * backspace, but the C locale doesn't.
129 * 2. isspace is an very expensive function call in some implementations
130 * due to the addition of wide character support.
132 static const char spacetab[] = {
133 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x00 - 0x0f */
134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */
135 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */
136 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */
137 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
138 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
139 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x8f */
140 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */
141 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */
142 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */
143 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */
144 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */
145 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
146 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
147 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
148 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0 - 0xff */
151 #define whitespace(c) (spacetab[(unsigned char)c] != 0)
153 /* Parse an rcsfile given a user file name and a repository. If there is
154 an error, we print an error message and return NULL. If the file
155 does not exist, we return NULL without printing anything (I'm not
156 sure this allows the caller to do anything reasonable, but it is
157 the current behavior). */
159 RCS_parse (file, repos)
168 /* We're creating a new RCSNode, so there is no hope of finding it
170 rcsbuf_cache_close ();
172 rcsfile = xmalloc (strlen (repos) + strlen (file)
173 + sizeof (RCSEXT) + sizeof (CVSATTIC) + 10);
174 (void) sprintf (rcsfile, "%s/%s%s", repos, file, RCSEXT);
175 if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) != NULL)
177 rcs = RCS_parsercsfile_i(fp, rcsfile);
184 else if (! existence_error (errno))
186 error (0, errno, "cannot open %s", rcsfile);
191 (void) sprintf (rcsfile, "%s/%s/%s%s", repos, CVSATTIC, file, RCSEXT);
192 if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) != NULL)
194 rcs = RCS_parsercsfile_i(fp, rcsfile);
197 rcs->flags |= INATTIC;
204 else if (! existence_error (errno))
206 error (0, errno, "cannot open %s", rcsfile);
210 #if defined (SERVER_SUPPORT) && !defined (FILENAMES_CASE_INSENSITIVE)
216 /* The client might be asking for a file which we do have
217 (which the client doesn't know about), but for which the
218 filename case differs. We only consider this case if the
219 regular CVS_FOPENs fail, because fopen_case is such an
221 (void) sprintf (rcsfile, "%s/%s%s", repos, file, RCSEXT);
222 status = fopen_case (rcsfile, "rb", &fp, &found_path);
225 rcs = RCS_parsercsfile_i (fp, rcsfile);
230 rcs->path = found_path;
234 else if (! existence_error (status))
236 error (0, status, "cannot open %s", rcsfile);
241 (void) sprintf (rcsfile, "%s/%s/%s%s", repos, CVSATTIC, file, RCSEXT);
242 status = fopen_case (rcsfile, "rb", &fp, &found_path);
245 rcs = RCS_parsercsfile_i (fp, rcsfile);
248 rcs->flags |= INATTIC;
253 rcs->path = found_path;
257 else if (! existence_error (status))
259 error (0, status, "cannot open %s", rcsfile);
274 * Parse a specific rcsfile.
277 RCS_parsercsfile (rcsfile)
283 /* We're creating a new RCSNode, so there is no hope of finding it
285 rcsbuf_cache_close ();
287 /* open the rcsfile */
288 if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) == NULL)
290 error (0, errno, "Couldn't open rcs file `%s'", rcsfile);
294 rcs = RCS_parsercsfile_i (fp, rcsfile);
303 RCS_parsercsfile_i (fp, rcsfile)
308 struct rcsbuffer rcsbuf;
312 rdata = (RCSNode *) xmalloc (sizeof (RCSNode));
313 memset ((char *) rdata, 0, sizeof (RCSNode));
315 rdata->path = xstrdup (rcsfile);
317 /* Process HEAD, BRANCH, and EXPAND keywords from the RCS header.
319 Most cvs operations on the main branch don't need any more
320 information. Those that do call RCS_reparsercsfile to parse
321 the rest of the header and the deltas. */
323 rcsbuf_open (&rcsbuf, fp, rcsfile, 0);
325 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
327 if (STREQ (key, RCSDESC))
330 if (STREQ (RCSHEAD, key) && value != NULL)
331 rdata->head = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *) NULL);
333 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
335 if (STREQ (key, RCSDESC))
338 if (STREQ (RCSBRANCH, key) && value != NULL)
342 rdata->branch = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *) NULL);
343 if ((numdots (rdata->branch) & 1) != 0)
345 /* turn it into a branch if it's a revision */
346 cp = strrchr (rdata->branch, '.');
351 /* Look ahead for expand, stopping when we see desc or a revision
357 if (STREQ (RCSEXPAND, key))
359 rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0,
364 for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
369 if (STREQ (RCSDESC, key))
372 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
376 rdata->flags |= PARTIAL;
378 rcsbuf_cache (rdata, &rcsbuf);
383 error (0, 0, "`%s' does not appear to be a valid rcs file",
385 rcsbuf_close (&rcsbuf);
386 freercsnode (&rdata);
392 /* Do the real work of parsing an RCS file.
394 On error, die with a fatal error; if it returns at all it was successful.
396 If PFP is NULL, close the file when done. Otherwise, leave it open
397 and store the FILE * in *PFP. */
399 RCS_reparsercsfile (rdata, pfp, rcsbufp)
402 struct rcsbuffer *rcsbufp;
406 struct rcsbuffer rcsbuf;
413 assert (rdata != NULL);
414 rcsfile = rdata->path;
416 rcsbuf_cache_open (rdata, 0, &fp, &rcsbuf);
419 /* This probably shouldn't be done until later: if a file has an
420 empty revision tree (which is permissible), rdata->versions
421 should be NULL. -twp */
422 rdata->versions = getlist ();
425 * process all the special header information, break out when we get to
426 * the first revision delta
431 /* get the next key/value pair */
434 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
436 error (1, 0, "`%s' does not appear to be a valid rcs file",
443 /* Skip head, branch and expand tags; we already have them. */
444 if (STREQ (key, RCSHEAD)
445 || STREQ (key, RCSBRANCH)
446 || STREQ (key, RCSEXPAND))
451 if (STREQ (key, "access"))
455 /* We pass the POLISH parameter as 1 because
456 RCS_addaccess expects nothing but spaces. FIXME:
457 It would be easy and more efficient to change
459 rdata->access = rcsbuf_valcopy (&rcsbuf, value, 1,
465 /* We always save lock information, so that we can handle
466 -kkvl correctly when checking out a file. */
467 if (STREQ (key, "locks"))
470 rdata->locks_data = rcsbuf_valcopy (&rcsbuf, value, 0,
472 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
474 error (1, 0, "premature end of file reading %s", rcsfile);
476 if (STREQ (key, "strict") && value == NULL)
478 rdata->strict_locks = 1;
485 if (STREQ (RCSSYMBOLS, key))
488 rdata->symbols_data = rcsbuf_valcopy (&rcsbuf, value, 0,
494 * check key for '.''s and digits (probably a rev) if it is a
495 * revision or `desc', we are done with the headers and are down to the
496 * revision deltas, so we break out of the loop
498 for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
500 /* Note that when comparing with RCSDATE, we are not massaging
501 VALUE from the string found in the RCS file. This is OK
502 since we know exactly what to expect. */
503 if (*cp == '\0' && strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) == 0)
506 if (STREQ (key, RCSDESC))
509 if (STREQ (key, "comment"))
511 rdata->comment = rcsbuf_valcopy (&rcsbuf, value, 0,
515 if (rdata->other == NULL)
516 rdata->other = getlist ();
519 kv->key = xstrdup (key);
520 kv->data = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
521 if (addnode (rdata->other, kv) != 0)
523 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
528 /* if we haven't grabbed it yet, we didn't want it */
531 /* We got out of the loop, so we have the first part of the first
532 revision delta in KEY (the revision) and VALUE (the date key
533 and its value). This is what getdelta expects to receive. */
535 while ((vnode = getdelta (&rcsbuf, rcsfile, &key, &value)) != NULL)
540 q->delproc = rcsvers_delproc;
541 q->data = (char *) vnode;
542 q->key = vnode->version;
544 /* add the nodes to the list */
545 if (addnode (rdata->versions, q) != 0)
548 purify_printf("WARNING: Adding duplicate version: %s (%s)\n",
555 /* Here KEY and VALUE are whatever caused getdelta to return NULL. */
557 if (STREQ (key, RCSDESC))
559 if (rdata->desc != NULL)
562 "warning: duplicate key `%s' in RCS file `%s'",
566 rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *) NULL);
569 rdata->delta_pos = rcsbuf_ftell (&rcsbuf);
572 rcsbuf_cache (rdata, &rcsbuf);
578 rdata->flags &= ~PARTIAL;
582 * Fully parse the RCS file. Store all keyword/value pairs, fetch the
583 * log messages for each revision, and fetch add and delete counts for
584 * each revision (we could fetch the entire text for each revision,
585 * but the only caller, log_fileproc, doesn't need that information,
586 * so we don't waste the memory required to store it). The add and
587 * delete counts are stored on the OTHER field of the RCSVERSNODE
588 * structure, under the names ";add" and ";delete", so that we don't
589 * waste the memory space of extra fields in RCSVERSNODE for code
590 * which doesn't need this information.
594 RCS_fully_parse (rcs)
598 struct rcsbuffer rcsbuf;
600 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
608 /* Rather than try to keep track of how much information we
609 have read, just read to the end of the file. */
610 if (! rcsbuf_getrevnum (&rcsbuf, &key))
613 vers = findnode (rcs->versions, key);
616 "mismatch in rcs file %s between deltas and deltatexts",
619 vnode = (RCSVers *) vers->data;
621 while (rcsbuf_getkey (&rcsbuf, &key, &value))
623 if (! STREQ (key, "text"))
627 if (vnode->other == NULL)
628 vnode->other = getlist ();
631 kv->key = xstrdup (key);
632 kv->data = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
633 if (addnode (vnode->other, kv) != 0)
637 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
638 key, vnode->version, rcs->path);
645 if (! STREQ (vnode->version, rcs->head))
647 unsigned long add, del;
651 /* This is a change text. Store the add and delete
660 rcsbuf_valpolish (&rcsbuf, value, 0, &vallen);
662 while (cp < value + vallen)
668 if (op != 'a' && op != 'd')
669 error (1, 0, "unrecognized operation '%c' in %s",
671 (void) strtoul (cp, (char **) &cp, 10);
673 error (1, 0, "space expected in %s",
675 count = strtoul (cp, (char **) &cp, 10);
677 error (1, 0, "linefeed expected in %s",
689 else if (cp == value + vallen)
693 invalid rcs file %s: premature end of value",
704 sprintf (buf, "%lu", add);
707 kv->key = xstrdup (";add");
708 kv->data = xstrdup (buf);
709 if (addnode (vnode->other, kv) != 0)
713 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
714 key, vnode->version, rcs->path);
718 sprintf (buf, "%lu", del);
721 kv->key = xstrdup (";delete");
722 kv->data = xstrdup (buf);
723 if (addnode (vnode->other, kv) != 0)
727 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
728 key, vnode->version, rcs->path);
733 /* We have found the "text" key which ends the data for
734 this revision. Break out of the loop and go on to the
740 rcsbuf_cache (rcs, &rcsbuf);
744 * freercsnode - free up the info for an RCSNode
750 if (rnodep == NULL || *rnodep == NULL)
753 ((*rnodep)->refcount)--;
754 if ((*rnodep)->refcount != 0)
756 *rnodep = (RCSNode *) NULL;
759 free ((*rnodep)->path);
760 if ((*rnodep)->head != (char *) NULL)
761 free ((*rnodep)->head);
762 if ((*rnodep)->branch != (char *) NULL)
763 free ((*rnodep)->branch);
764 free_rcsnode_contents (*rnodep);
765 free ((char *) *rnodep);
766 *rnodep = (RCSNode *) NULL;
770 * free_rcsnode_contents - free up the contents of an RCSNode without
771 * freeing the node itself, or the file name, or the head, or the
772 * path. This returns the RCSNode to the state it is in immediately
773 * after a call to RCS_parse.
776 free_rcsnode_contents (rnode)
779 dellist (&rnode->versions);
780 if (rnode->symbols != (List *) NULL)
781 dellist (&rnode->symbols);
782 if (rnode->symbols_data != (char *) NULL)
783 free (rnode->symbols_data);
784 if (rnode->expand != NULL)
785 free (rnode->expand);
786 if (rnode->other != (List *) NULL)
787 dellist (&rnode->other);
788 if (rnode->access != NULL)
789 free (rnode->access);
790 if (rnode->locks_data != NULL)
791 free (rnode->locks_data);
792 if (rnode->locks != (List *) NULL)
793 dellist (&rnode->locks);
794 if (rnode->comment != NULL)
795 free (rnode->comment);
796 if (rnode->desc != NULL)
800 /* free_rcsvers_contents -- free up the contents of an RCSVers node,
801 but also free the pointer to the node itself. */
804 free_rcsvers_contents (rnode)
807 if (rnode->branches != (List *) NULL)
808 dellist (&rnode->branches);
809 if (rnode->date != (char *) NULL)
811 if (rnode->next != (char *) NULL)
813 if (rnode->author != (char *) NULL)
814 free (rnode->author);
815 if (rnode->state != (char *) NULL)
817 if (rnode->other != (List *) NULL)
818 dellist (&rnode->other);
819 if (rnode->other_delta != NULL)
820 dellist (&rnode->other_delta);
821 if (rnode->text != NULL)
822 freedeltatext (rnode->text);
823 free ((char *) rnode);
827 * rcsvers_delproc - free up an RCSVers type node
833 free_rcsvers_contents ((RCSVers *) p->data);
836 /* These functions retrieve keys and values from an RCS file using a
837 buffer. We use this somewhat complex approach because it turns out
838 that for many common operations, CVS spends most of its time
839 reading keys, so it's worth doing some fairly hairy optimization. */
841 /* The number of bytes we try to read each time we need more data. */
843 #define RCSBUF_BUFSIZE (8192)
845 /* The buffer we use to store data. This grows as needed. */
847 static char *rcsbuf_buffer = NULL;
848 static size_t rcsbuf_buffer_size = 0;
850 /* Whether rcsbuf_buffer is in use. This is used as a sanity check. */
852 static int rcsbuf_inuse;
854 /* Set up to start gathering keys and values from an RCS file. This
855 initializes RCSBUF. */
858 rcsbuf_open (rcsbuf, fp, filename, pos)
859 struct rcsbuffer *rcsbuf;
861 const char *filename;
865 error (1, 0, "rcsbuf_open: internal error");
868 if (rcsbuf_buffer_size < RCSBUF_BUFSIZE)
869 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, RCSBUF_BUFSIZE);
871 rcsbuf->ptr = rcsbuf_buffer;
872 rcsbuf->ptrend = rcsbuf_buffer;
874 rcsbuf->filename = filename;
877 rcsbuf->at_string = 0;
878 rcsbuf->embedded_at = 0;
881 /* Stop gathering keys from an RCS file. */
884 rcsbuf_close (rcsbuf)
885 struct rcsbuffer *rcsbuf;
888 error (1, 0, "rcsbuf_close: internal error");
892 /* Read a key/value pair from an RCS file. This sets *KEYP to point
893 to the key, and *VALUEP to point to the value. A missing or empty
894 value is indicated by setting *VALUEP to NULL.
896 This function returns 1 on success, or 0 on EOF. If there is an
897 error reading the file, or an EOF in an unexpected location, it
900 This sets *KEYP and *VALUEP to point to storage managed by
901 rcsbuf_getkey. Moreover, *VALUEP has not been massaged from the
902 RCS format: it may contain embedded whitespace and embedded '@'
903 characters. Call rcsbuf_valcopy or rcsbuf_valpolish to do
904 appropriate massaging. */
907 rcsbuf_getkey (rcsbuf, keyp, valp)
908 struct rcsbuffer *rcsbuf;
912 register const char * const my_spacetab = spacetab;
913 register char *ptr, *ptrend;
916 #define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
919 rcsbuf->at_string = 0;
920 rcsbuf->embedded_at = 0;
923 ptrend = rcsbuf->ptrend;
926 if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size)
929 /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
930 buffer, move back to the start of the buffer. This keeps the
931 buffer from growing indefinitely. */
932 if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
938 /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
939 at a time, so we can't have more bytes than that past PTR. */
940 if (len > RCSBUF_BUFSIZE)
943 /* Update the POS field, which holds the file offset of the
944 first byte in the RCSBUF_BUFFER buffer. */
945 rcsbuf->pos += ptr - rcsbuf_buffer;
947 memcpy (rcsbuf_buffer, ptr, len);
950 rcsbuf->ptrend = ptrend;
953 /* Skip leading whitespace. */
959 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
962 ptrend = rcsbuf->ptrend;
966 if (! my_whitespace (c))
972 /* We've found the start of the key. */
983 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
985 error (1, 0, "EOF in key in RCS file %s",
987 ptrend = rcsbuf->ptrend;
990 if (c == ';' || my_whitespace (c))
995 /* Here *KEYP points to the key in the buffer, C is the character
996 we found at the of the key, and PTR points to the location in
997 the buffer where we found C. We must set *PTR to \0 in order
998 to terminate the key. If the key ended with ';', then there is
1011 /* C must be whitespace. Skip whitespace between the key and the
1012 value. If we find ';' now, there is no value. */
1018 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
1020 error (1, 0, "EOF while looking for value in RCS file %s",
1022 ptrend = rcsbuf->ptrend;
1028 rcsbuf->ptr = ptr + 1;
1031 if (! my_whitespace (c))
1036 /* Now PTR points to the start of the value, and C is the first
1037 character of the value. */
1046 /* Optimize the common case of a value composed of a single
1049 rcsbuf->at_string = 1;
1057 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1059 /* Note that we pass PTREND as the PTR value to
1060 rcsbuf_fill, so that we will wind up setting PTR to
1061 the location corresponding to the old PTREND, so
1062 that we don't search the same bytes again. */
1063 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1066 "EOF while looking for end of string in RCS file %s",
1068 ptrend = rcsbuf->ptrend;
1071 /* Handle the special case of an '@' right at the end of
1073 if (pat + 1 >= ptrend)
1075 /* Note that we pass PAT, not PTR, here. */
1076 pat = rcsbuf_fill (rcsbuf, pat, keyp, valp);
1079 /* EOF here is OK; it just means that the last
1080 character of the file was an '@' terminating a
1081 value for a key type which does not require a
1083 pat = rcsbuf->ptrend - 1;
1086 ptrend = rcsbuf->ptrend;
1088 /* Note that the value of PTR is bogus here. This is
1089 OK, because we don't use it. */
1092 if (pat + 1 >= ptrend || pat[1] != '@')
1095 /* We found an '@' pair in the string. Keep looking. */
1096 ++rcsbuf->embedded_at;
1100 /* Here PAT points to the final '@' in the string. */
1107 rcsbuf->vlen = vlen;
1112 /* Certain keywords only have a '@' string. If there is no '@'
1113 string, then the old getrcskey function assumed that they had
1114 no value, and we do the same. */
1120 if (STREQ (k, RCSDESC)
1121 || STREQ (k, "text")
1122 || STREQ (k, "log"))
1131 /* If we've already gathered a '@' string, try to skip whitespace
1141 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1143 error (1, 0, "EOF in value in RCS file %s",
1145 ptrend = rcsbuf->ptrend;
1150 /* We're done. We already set everything up for this
1152 rcsbuf->ptr = ptr + 1;
1155 if (! my_whitespace (n))
1160 /* The value extends past the '@' string. We need to undo the
1161 closing of the '@' done in the default case above. This
1162 case never happens in a plain RCS file, but it can happen
1163 if user defined phrases are used. */
1164 if (rcsbuf->vlen != 0)
1165 (*valp)[rcsbuf->vlen] = ' ';
1170 /* Here we have a value which is not a simple '@' string. We need
1171 to gather up everything until the next ';', including any '@'
1172 strings. *VALP points to the start of the value. If
1173 RCSBUF->VLEN is not zero, then we have already read an '@'
1174 string, and PTR points to the data following the '@' string.
1175 Otherwise, PTR points to the start of the value. */
1179 char *start, *psemi, *pat;
1181 /* Find the ';' which must end the value. */
1183 while ((psemi = memchr (ptr, ';', ptrend - ptr)) == NULL)
1187 /* Note that we pass PTREND as the PTR value to
1188 rcsbuf_fill, so that we will wind up setting PTR to the
1189 location corresponding to the old PTREND, so that we
1190 don't search the same bytes again. */
1191 slen = start - *valp;
1192 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1194 error (1, 0, "EOF in value in RCS file %s", rcsbuf->filename);
1195 start = *valp + slen;
1196 ptrend = rcsbuf->ptrend;
1199 /* See if there are any '@' strings in the value. */
1200 pat = memchr (start, '@', psemi - start);
1206 /* We're done with the value. Trim any trailing
1209 rcsbuf->ptr = psemi + 1;
1212 while (psemi > start && my_whitespace (psemi[-1]))
1216 vlen = psemi - start;
1219 rcsbuf->vlen = vlen;
1224 /* We found an '@' string in the value. We set
1225 RCSBUF->AT_STRING, which means that we won't be able to
1226 compress whitespace correctly for this type of value.
1227 Since this type of value never arises in a normal RCS file,
1228 this should not be a big deal. It means that if anybody
1229 adds a phrase which can have both an '@' string and regular
1230 text, they will have to handle whitespace compression
1233 rcsbuf->at_string = 1;
1241 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1243 /* Note that we pass PTREND as the PTR value to
1244 rcsbuff_fill, so that we will wind up setting PTR
1245 to the location corresponding to the old PTREND, so
1246 that we don't search the same bytes again. */
1247 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1250 "EOF while looking for end of string in RCS file %s",
1252 ptrend = rcsbuf->ptrend;
1255 /* Handle the special case of an '@' right at the end of
1257 if (pat + 1 >= ptrend)
1259 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1261 error (1, 0, "EOF in value in RCS file %s",
1263 ptrend = rcsbuf->ptrend;
1269 /* We found an '@' pair in the string. Keep looking. */
1270 ++rcsbuf->embedded_at;
1274 /* Here PAT points to the final '@' in the string. */
1281 #undef my_whitespace
1284 /* Read an RCS revision number from an RCS file. This sets *REVP to
1285 point to the revision number; it will point to space that is
1286 managed by the rcsbuf functions, and is only good until the next
1287 call to rcsbuf_getkey or rcsbuf_getrevnum.
1289 This function returns 1 on success, or 0 on EOF. If there is an
1290 error reading the file, or an EOF in an unexpected location, it
1291 gives a fatal error. */
1294 rcsbuf_getrevnum (rcsbuf, revp)
1295 struct rcsbuffer *rcsbuf;
1302 ptrend = rcsbuf->ptrend;
1306 /* Skip leading whitespace. */
1312 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
1315 ptrend = rcsbuf->ptrend;
1319 if (! whitespace (c))
1325 if (! isdigit (c) && c != '.')
1327 "unexpected `%c' reading revision number in RCS file %s",
1328 c, rcsbuf->filename);
1337 ptr = rcsbuf_fill (rcsbuf, ptr, revp, (char **) NULL);
1340 "unexpected EOF reading revision number in RCS file %s",
1342 ptrend = rcsbuf->ptrend;
1347 while (isdigit (c) || c == '.');
1349 if (! whitespace (c))
1350 error (1, 0, "unexpected `%c' reading revision number in RCS file %s",
1351 c, rcsbuf->filename);
1355 rcsbuf->ptr = ptr + 1;
1360 /* Fill RCSBUF_BUFFER with bytes from the file associated with RCSBUF,
1361 updating PTR and the PTREND field. If KEYP and *KEYP are not NULL,
1362 then *KEYP points into the buffer, and must be adjusted if the
1363 buffer is changed. Likewise for VALP. Returns the new value of
1364 PTR, or NULL on error. */
1367 rcsbuf_fill (rcsbuf, ptr, keyp, valp)
1368 struct rcsbuffer *rcsbuf;
1375 if (rcsbuf->ptrend - rcsbuf_buffer + RCSBUF_BUFSIZE > rcsbuf_buffer_size)
1377 int poff, peoff, koff, voff;
1379 poff = ptr - rcsbuf_buffer;
1380 peoff = rcsbuf->ptrend - rcsbuf_buffer;
1381 if (keyp != NULL && *keyp != NULL)
1382 koff = *keyp - rcsbuf_buffer;
1383 if (valp != NULL && *valp != NULL)
1384 voff = *valp - rcsbuf_buffer;
1386 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size,
1387 rcsbuf_buffer_size + RCSBUF_BUFSIZE);
1389 ptr = rcsbuf_buffer + poff;
1390 rcsbuf->ptrend = rcsbuf_buffer + peoff;
1391 if (keyp != NULL && *keyp != NULL)
1392 *keyp = rcsbuf_buffer + koff;
1393 if (valp != NULL && *valp != NULL)
1394 *valp = rcsbuf_buffer + voff;
1397 got = fread (rcsbuf->ptrend, 1, RCSBUF_BUFSIZE, rcsbuf->fp);
1400 if (ferror (rcsbuf->fp))
1401 error (1, errno, "cannot read %s", rcsbuf->filename);
1405 rcsbuf->ptrend += got;
1410 /* Copy the value VAL returned by rcsbuf_getkey into a memory buffer,
1411 returning the memory buffer. Polish the value like
1412 rcsbuf_valpolish, q.v. */
1415 rcsbuf_valcopy (rcsbuf, val, polish, lenp)
1416 struct rcsbuffer *rcsbuf;
1432 vlen = rcsbuf->vlen;
1433 embedded_at = rcsbuf->embedded_at;
1435 ret = xmalloc (vlen - embedded_at + 1);
1437 if (rcsbuf->at_string ? embedded_at == 0 : ! polish)
1439 /* No special action to take. */
1440 memcpy (ret, val, vlen + 1);
1446 rcsbuf_valpolish_internal (rcsbuf, ret, val, lenp);
1450 /* Polish the value VAL returned by rcsbuf_getkey. The POLISH
1451 parameter is non-zero if multiple embedded whitespace characters
1452 should be compressed into a single whitespace character. Note that
1453 leading and trailing whitespace was already removed by
1454 rcsbuf_getkey. Within an '@' string, pairs of '@' characters are
1455 compressed into a single '@' character regardless of the value of
1456 POLISH. If LENP is not NULL, set *LENP to the length of the value. */
1459 rcsbuf_valpolish (rcsbuf, val, polish, lenp)
1460 struct rcsbuffer *rcsbuf;
1472 if (rcsbuf->at_string ? rcsbuf->embedded_at == 0 : ! polish)
1474 /* No special action to take. */
1476 *lenp = rcsbuf->vlen;
1480 rcsbuf_valpolish_internal (rcsbuf, val, val, lenp);
1483 /* Internal polishing routine, called from rcsbuf_valcopy and
1484 rcsbuf_valpolish. */
1487 rcsbuf_valpolish_internal (rcsbuf, to, from, lenp)
1488 struct rcsbuffer *rcsbuf;
1497 if (! rcsbuf->at_string)
1504 for (clen = len; clen > 0; ++from, --clen)
1511 /* Note that we know that clen can not drop to zero
1512 while we have whitespace, because we know there is
1513 no trailing whitespace. */
1514 while (whitespace (from[1]))
1527 *lenp = to - orig_to;
1531 const char *orig_from;
1539 embedded_at = rcsbuf->embedded_at;
1542 *lenp = len - embedded_at;
1544 for (clen = len; clen > 0; ++from, --clen)
1555 if (*from != '@' || clen == 0)
1561 if (embedded_at == 0)
1563 /* We've found all the embedded '@' characters.
1564 We can just memcpy the rest of the buffer after
1565 this '@' character. */
1566 if (orig_to != orig_from)
1567 memcpy (to, from + 1, clen - 1);
1569 memmove (to, from + 1, clen - 1);
1578 if (from != orig_from + len
1579 || to != orig_to + (len - rcsbuf->embedded_at))
1588 /* Return the current position of an rcsbuf. */
1590 static unsigned long
1591 rcsbuf_ftell (rcsbuf)
1592 struct rcsbuffer *rcsbuf;
1594 return rcsbuf->pos + (rcsbuf->ptr - rcsbuf_buffer);
1597 /* Return a pointer to any data buffered for RCSBUF, along with the
1601 rcsbuf_get_buffered (rcsbuf, datap, lenp)
1602 struct rcsbuffer *rcsbuf;
1606 *datap = rcsbuf->ptr;
1607 *lenp = rcsbuf->ptrend - rcsbuf->ptr;
1610 /* CVS optimizes by quickly reading some header information from a
1611 file. If it decides it needs to do more with the file, it reopens
1612 it. We speed that up here by maintaining a cache of a single open
1613 file, to save the time it takes to reopen the file in the common
1616 static RCSNode *cached_rcs;
1617 static struct rcsbuffer cached_rcsbuf;
1619 /* Cache RCS and RCSBUF. This takes responsibility for closing
1623 rcsbuf_cache (rcs, rcsbuf)
1625 struct rcsbuffer *rcsbuf;
1627 if (cached_rcs != NULL)
1628 rcsbuf_cache_close ();
1631 cached_rcsbuf = *rcsbuf;
1634 /* If there is anything in the cache, close it. */
1637 rcsbuf_cache_close ()
1639 if (cached_rcs != NULL)
1641 if (fclose (cached_rcsbuf.fp) != 0)
1642 error (0, errno, "cannot close %s", cached_rcsbuf.filename);
1643 rcsbuf_close (&cached_rcsbuf);
1644 freercsnode (&cached_rcs);
1649 /* Open an rcsbuffer for RCS, getting it from the cache if possible.
1650 Set *FPP to the file, and *RCSBUFP to the rcsbuf. The file should
1651 be put at position POS. */
1654 rcsbuf_cache_open (rcs, pos, pfp, prcsbuf)
1658 struct rcsbuffer *prcsbuf;
1660 if (cached_rcs == rcs)
1662 if (rcsbuf_ftell (&cached_rcsbuf) != pos)
1664 if (fseek (cached_rcsbuf.fp, pos, SEEK_SET) != 0)
1665 error (1, 0, "cannot fseek RCS file %s",
1666 cached_rcsbuf.filename);
1667 cached_rcsbuf.ptr = rcsbuf_buffer;
1668 cached_rcsbuf.ptrend = rcsbuf_buffer;
1669 cached_rcsbuf.pos = pos;
1671 *pfp = cached_rcsbuf.fp;
1673 /* When RCS_parse opens a file using fopen_case, it frees the
1674 filename which we cached in CACHED_RCSBUF and stores a new
1675 file name in RCS->PATH. We avoid problems here by always
1676 copying the filename over. FIXME: This is hackish. */
1677 cached_rcsbuf.filename = rcs->path;
1679 *prcsbuf = cached_rcsbuf;
1683 /* Removing RCS from the cache removes a reference to it. */
1685 if (rcs->refcount <= 0)
1686 error (1, 0, "rcsbuf_cache_open: internal error");
1690 if (cached_rcs != NULL)
1691 rcsbuf_cache_close ();
1693 *pfp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ);
1695 error (1, 0, "unable to reopen `%s'", rcs->path);
1698 if (fseek (*pfp, pos, SEEK_SET) != 0)
1699 error (1, 0, "cannot fseek RCS file %s", rcs->path);
1701 rcsbuf_open (prcsbuf, *pfp, rcs->path, pos);
1707 * process the symbols list of the rcs file
1710 do_symbols (list, val)
1720 /* skip leading whitespace */
1721 while (whitespace (*cp))
1724 /* if we got to the end, we are done */
1728 /* split it up into tag and rev */
1730 cp = strchr (cp, ':');
1733 while (!whitespace (*cp) && *cp != '\0')
1738 /* make a new node and add it to the list */
1740 p->key = xstrdup (tag);
1741 p->data = xstrdup (rev);
1742 (void) addnode (list, p);
1747 * process the locks list of the rcs file
1748 * Like do_symbols, but hash entries are keyed backwards: i.e.
1749 * an entry like `user:rev' is keyed on REV rather than on USER.
1752 do_locks (list, val)
1762 /* skip leading whitespace */
1763 while (whitespace (*cp))
1766 /* if we got to the end, we are done */
1770 /* split it up into user and rev */
1772 cp = strchr (cp, ':');
1775 while (!whitespace (*cp) && *cp != '\0')
1780 /* make a new node and add it to the list */
1782 p->key = xstrdup (rev);
1783 p->data = xstrdup (user);
1784 (void) addnode (list, p);
1789 * process the branches list of a revision delta
1792 do_branches (list, val)
1802 /* skip leading whitespace */
1803 while (whitespace (*cp))
1806 /* if we got to the end, we are done */
1810 /* find the end of this branch */
1812 while (!whitespace (*cp) && *cp != '\0')
1817 /* make a new node and add it to the list */
1819 p->key = xstrdup (branch);
1820 (void) addnode (list, p);
1827 * Returns the requested version number of the RCS file, satisfying tags and/or
1828 * dates, and walking branches, if necessary.
1830 * The result is returned; null-string if error.
1833 RCS_getversion (rcs, tag, date, force_tag_match, simple_tag)
1837 int force_tag_match;
1840 if (simple_tag != NULL)
1843 /* make sure we have something to look at... */
1844 assert (rcs != NULL);
1850 if (! RCS_nodeisbranch (rcs, tag))
1852 /* We can't get a particular date if the tag is not a
1857 /* Work out the branch. */
1858 if (! isdigit (tag[0]))
1859 branch = RCS_whatbranch (rcs, tag);
1861 branch = xstrdup (tag);
1863 /* Fetch the revision of branch as of date. */
1864 rev = RCS_getdatebranch (rcs, date, branch);
1869 return (RCS_gettag (rcs, tag, force_tag_match, simple_tag));
1871 return (RCS_getdate (rcs, date, force_tag_match));
1873 return (RCS_head (rcs));
1878 * Find the revision for a specific tag.
1879 * If force_tag_match is set, return NULL if an exact match is not
1880 * possible otherwise return RCS_head (). We are careful to look for
1881 * and handle "magic" revisions specially.
1883 * If the matched tag is a branch tag, find the head of the branch.
1885 * Returns pointer to newly malloc'd string, or NULL.
1888 RCS_gettag (rcs, symtag, force_tag_match, simple_tag)
1891 int force_tag_match;
1895 int tag_allocated = 0;
1897 if (simple_tag != NULL)
1900 /* make sure we have something to look at... */
1901 assert (rcs != NULL);
1903 /* XXX this is probably not necessary, --jtc */
1904 if (rcs->flags & PARTIAL)
1905 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
1907 /* If tag is "HEAD", special case to get head RCS revision */
1908 if (tag && (STREQ (tag, TAG_HEAD) || *tag == '\0'))
1909 #if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */
1910 if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
1911 return ((char *) NULL); /* head request for removed file */
1914 return (RCS_head (rcs));
1916 if (!isdigit (tag[0]))
1920 /* If we got a symbolic tag, resolve it to a numeric */
1921 version = translate_symtag (rcs, tag);
1922 if (version != NULL)
1925 char *magic, *branch, *cp;
1931 * If this is a magic revision, we turn it into either its
1932 * physical branch equivalent (if one exists) or into
1933 * its base revision, which we assume exists.
1935 dots = numdots (tag);
1936 if (dots > 2 && (dots & 1) != 0)
1938 branch = strrchr (tag, '.');
1943 /* see if we have .magic-branch. (".0.") */
1944 magic = xmalloc (strlen (tag) + 1);
1945 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
1946 if (strncmp (magic, cp, strlen (magic)) == 0)
1948 /* it's magic. See if the branch exists */
1949 *cp = '\0'; /* turn it into a revision */
1950 (void) sprintf (magic, "%s.%s", tag, branch);
1951 branch = RCS_getbranch (rcs, magic, 1);
1965 /* The tag wasn't there, so return the head or NULL */
1966 if (force_tag_match)
1969 return (RCS_head (rcs));
1974 * numeric tag processing:
1975 * 1) revision number - just return it
1976 * 2) branch number - find head of branch
1979 /* strip trailing dots */
1980 while (tag[strlen (tag) - 1] == '.')
1981 tag[strlen (tag) - 1] = '\0';
1983 if ((numdots (tag) & 1) == 0)
1987 /* we have a branch tag, so we need to walk the branch */
1988 branch = RCS_getbranch (rcs, tag, force_tag_match);
1997 /* we have a revision tag, so make sure it exists */
1998 p = findnode (rcs->versions, tag);
2001 /* We have found a numeric revision for the revision tag.
2002 To support expanding the RCS keyword Name, if
2003 SIMPLE_TAG is not NULL, tell the the caller that this
2004 is a simple tag which co will recognize. FIXME: Are
2005 there other cases in which we should set this? In
2006 particular, what if we expand RCS keywords internally
2007 without calling co? */
2008 if (simple_tag != NULL)
2010 if (! tag_allocated)
2011 tag = xstrdup (tag);
2016 /* The revision wasn't there, so return the head or NULL */
2019 if (force_tag_match)
2022 return (RCS_head (rcs));
2028 * Return a "magic" revision as a virtual branch off of REV for the RCS file.
2029 * A "magic" revision is one which is unique in the RCS file. By unique, I
2030 * mean we return a revision which:
2031 * - has a branch of 0 (see rcs.h RCS_MAGIC_BRANCH)
2032 * - has a revision component which is not an existing branch off REV
2033 * - has a revision component which is not an existing magic revision
2034 * - is an even-numbered revision, to avoid conflicts with vendor branches
2035 * The first point is what makes it "magic".
2037 * As an example, if we pass in 1.37 as REV, we will look for an existing
2038 * branch called 1.37.2. If it did not exist, we would look for an
2039 * existing symbolic tag with a numeric part equal to 1.37.0.2. If that
2040 * didn't exist, then we know that the 1.37.2 branch can be reserved by
2041 * creating a symbolic tag with 1.37.0.2 as the numeric part.
2043 * This allows us to fork development with very little overhead -- just a
2044 * symbolic tag is used in the RCS file. When a commit is done, a physical
2045 * branch is dynamically created to hold the new revision.
2047 * Note: We assume that REV is an RCS revision and not a branch number.
2049 static char *check_rev;
2051 RCS_magicrev (rcs, rev)
2056 char *xrev, *test_branch;
2058 xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */
2061 /* only look at even numbered branches */
2062 for (rev_num = 2; ; rev_num += 2)
2064 /* see if the physical branch exists */
2065 (void) sprintf (xrev, "%s.%d", rev, rev_num);
2066 test_branch = RCS_getbranch (rcs, xrev, 1);
2067 if (test_branch != NULL) /* it did, so keep looking */
2073 /* now, create a "magic" revision */
2074 (void) sprintf (xrev, "%s.%d.%d", rev, RCS_MAGIC_BRANCH, rev_num);
2076 /* walk the symbols list to see if a magic one already exists */
2077 if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0)
2080 /* we found a free magic branch. Claim it as ours */
2086 * walklist proc to look for a match in the symbols list.
2087 * Returns 0 if the symbol does not match, 1 if it does.
2090 checkmagic_proc (p, closure)
2094 if (STREQ (check_rev, p->data))
2101 * Given an RCSNode, returns non-zero if the specified revision number
2102 * or symbolic tag resolves to a "branch" within the rcs file.
2104 * FIXME: this is the same as RCS_nodeisbranch except for the special
2105 * case for handling a null rcsnode.
2108 RCS_isbranch (rcs, rev)
2112 /* numeric revisions are easy -- even number of dots is a branch */
2114 return ((numdots (rev) & 1) == 0);
2116 /* assume a revision if you can't find the RCS info */
2120 /* now, look for a match in the symbols list */
2121 return (RCS_nodeisbranch (rcs, rev));
2125 * Given an RCSNode, returns non-zero if the specified revision number
2126 * or symbolic tag resolves to a "branch" within the rcs file. We do
2127 * take into account any magic branches as well.
2130 RCS_nodeisbranch (rcs, rev)
2137 assert (rcs != NULL);
2139 /* numeric revisions are easy -- even number of dots is a branch */
2141 return ((numdots (rev) & 1) == 0);
2143 version = translate_symtag (rcs, rev);
2144 if (version == NULL)
2146 dots = numdots (version);
2147 if ((dots & 1) == 0)
2153 /* got a symbolic tag match, but it's not a branch; see if it's magic */
2157 char *branch = strrchr (version, '.');
2158 char *cp = branch - 1;
2162 /* see if we have .magic-branch. (".0.") */
2163 magic = xmalloc (strlen (version) + 1);
2164 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2165 if (strncmp (magic, cp, strlen (magic)) == 0)
2178 * Returns a pointer to malloc'ed memory which contains the branch
2179 * for the specified *symbolic* tag. Magic branches are handled correctly.
2182 RCS_whatbranch (rcs, rev)
2189 /* assume no branch if you can't find the RCS info */
2191 return ((char *) NULL);
2193 /* now, look for a match in the symbols list */
2194 version = translate_symtag (rcs, rev);
2195 if (version == NULL)
2196 return ((char *) NULL);
2197 dots = numdots (version);
2198 if ((dots & 1) == 0)
2201 /* got a symbolic tag match, but it's not a branch; see if it's magic */
2205 char *branch = strrchr (version, '.');
2206 char *cp = branch++ - 1;
2210 /* see if we have .magic-branch. (".0.") */
2211 magic = xmalloc (strlen (version) + 1);
2212 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2213 if (strncmp (magic, cp, strlen (magic)) == 0)
2215 /* yep. it's magic. now, construct the real branch */
2216 *cp = '\0'; /* turn it into a revision */
2217 (void) sprintf (magic, "%s.%s", version, branch);
2224 return ((char *) NULL);
2228 * Get the head of the specified branch. If the branch does not exist,
2229 * return NULL or RCS_head depending on force_tag_match.
2230 * Returns NULL or a newly malloc'd string.
2233 RCS_getbranch (rcs, tag, force_tag_match)
2236 int force_tag_match;
2244 /* make sure we have something to look at... */
2245 assert (rcs != NULL);
2247 if (rcs->flags & PARTIAL)
2248 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2250 /* find out if the tag contains a dot, or is on the trunk */
2251 cp = strrchr (tag, '.');
2253 /* trunk processing is the special case */
2256 xtag = xmalloc (strlen (tag) + 1 + 1); /* +1 for an extra . */
2257 (void) strcpy (xtag, tag);
2258 (void) strcat (xtag, ".");
2259 for (cp = rcs->head; cp != NULL;)
2261 if (strncmp (xtag, cp, strlen (xtag)) == 0)
2263 p = findnode (rcs->versions, cp);
2267 if (force_tag_match)
2270 return (RCS_head (rcs));
2272 vn = (RCSVers *) p->data;
2278 if (force_tag_match)
2281 return (RCS_head (rcs));
2283 return (xstrdup (cp));
2286 /* if it had a `.', terminate the string so we have the base revision */
2289 /* look up the revision this branch is based on */
2290 p = findnode (rcs->versions, tag);
2292 /* put the . back so we have the branch again */
2297 /* if the base revision didn't exist, return head or NULL */
2298 if (force_tag_match)
2301 return (RCS_head (rcs));
2304 /* find the first element of the branch we are looking for */
2305 vn = (RCSVers *) p->data;
2306 if (vn->branches == NULL)
2308 xtag = xmalloc (strlen (tag) + 1 + 1); /* 1 for the extra '.' */
2309 (void) strcpy (xtag, tag);
2310 (void) strcat (xtag, ".");
2311 head = vn->branches->list;
2312 for (p = head->next; p != head; p = p->next)
2313 if (strncmp (p->key, xtag, strlen (xtag)) == 0)
2319 /* we didn't find a match so return head or NULL */
2320 if (force_tag_match)
2323 return (RCS_head (rcs));
2326 /* now walk the next pointers of the branch */
2330 p = findnode (rcs->versions, nextvers);
2333 /* a link in the chain is missing - return head or NULL */
2334 if (force_tag_match)
2337 return (RCS_head (rcs));
2339 vn = (RCSVers *) p->data;
2340 nextvers = vn->next;
2341 } while (nextvers != NULL);
2343 /* we have the version in our hand, so go for it */
2344 return (xstrdup (vn->version));
2347 /* Get the branch point for a particular branch, that is the first
2348 revision on that branch. For example, RCS_getbranchpoint (rcs,
2349 "1.3.2") will normally return "1.3.2.1". TARGET may be either a
2350 branch number or a revision number; if a revnum, find the
2351 branchpoint of the branch to which TARGET belongs.
2353 Return RCS_head if TARGET is on the trunk or if the root node could
2354 not be found (this is sort of backwards from our behavior on a branch;
2355 the rationale is that the return value is a revision from which you
2356 can start walking the next fields and end up at TARGET).
2357 Return NULL on error. */
2360 RCS_getbranchpoint (rcs, target)
2367 int dots, isrevnum, brlen;
2369 dots = numdots (target);
2370 isrevnum = dots & 1;
2373 /* TARGET is a trunk revision; return rcs->head. */
2374 return (RCS_head (rcs));
2376 /* Get the revision number of the node at which TARGET's branch is
2377 rooted. If TARGET is a branch number, lop off the last field;
2378 if it's a revision number, lop off the last *two* fields. */
2379 branch = xstrdup (target);
2380 bp = strrchr (branch, '.');
2382 error (1, 0, "%s: confused revision number %s",
2385 while (*--bp != '.')
2389 vp = findnode (rcs->versions, branch);
2392 error (0, 0, "%s: can't find branch point %s", rcs->path, target);
2395 rev = (RCSVers *) vp->data;
2398 while (*bp && *bp != '.')
2400 brlen = bp - branch;
2402 vp = rev->branches->list->next;
2403 while (vp != rev->branches->list)
2405 /* BRANCH may be a genuine branch number, e.g. `1.1.3', or
2406 maybe a full revision number, e.g. `1.1.3.6'. We have
2407 found our branch point if the first BRANCHLEN characters
2408 of the revision number match, *and* if the following
2409 character is a dot. */
2410 if (strncmp (vp->key, branch, brlen) == 0 && vp->key[brlen] == '.')
2416 if (vp == rev->branches->list)
2418 error (0, 0, "%s: can't find branch point %s", rcs->path, target);
2422 return (xstrdup (vp->key));
2426 * Get the head of the RCS file. If branch is set, this is the head of the
2427 * branch, otherwise the real head.
2428 * Returns NULL or a newly malloc'd string.
2434 /* make sure we have something to look at... */
2435 assert (rcs != NULL);
2438 * NOTE: we call getbranch with force_tag_match set to avoid any
2439 * possibility of recursion
2442 return (RCS_getbranch (rcs, rcs->branch, 1));
2444 return (xstrdup (rcs->head));
2448 * Get the most recent revision, based on the supplied date, but use some
2449 * funky stuff and follow the vendor branch maybe
2452 RCS_getdate (rcs, date, force_tag_match)
2455 int force_tag_match;
2457 char *cur_rev = NULL;
2458 char *retval = NULL;
2460 RCSVers *vers = NULL;
2462 /* make sure we have something to look at... */
2463 assert (rcs != NULL);
2465 if (rcs->flags & PARTIAL)
2466 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2468 /* if the head is on a branch, try the branch first */
2469 if (rcs->branch != NULL)
2470 retval = RCS_getdatebranch (rcs, date, rcs->branch);
2472 /* if we found a match, we are done */
2476 /* otherwise if we have a trunk, try it */
2479 p = findnode (rcs->versions, rcs->head);
2482 /* if the date of this one is before date, take it */
2483 vers = (RCSVers *) p->data;
2484 if (RCS_datecmp (vers->date, date) <= 0)
2486 cur_rev = vers->version;
2490 /* if there is a next version, find the node */
2491 if (vers->next != NULL)
2492 p = findnode (rcs->versions, vers->next);
2499 * at this point, either we have the revision we want, or we have the
2500 * first revision on the trunk (1.1?) in our hands
2503 /* if we found what we're looking for, and it's not 1.1 return it */
2504 if (cur_rev != NULL && ! STREQ (cur_rev, "1.1"))
2505 return (xstrdup (cur_rev));
2507 /* look on the vendor branch */
2508 retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
2511 * if we found a match, return it; otherwise, we return the first
2512 * revision on the trunk or NULL depending on force_tag_match and the
2513 * date of the first rev
2518 if (!force_tag_match || RCS_datecmp (vers->date, date) <= 0)
2519 return (xstrdup (vers->version));
2525 * Look up the last element on a branch that was put in before the specified
2526 * date (return the rev or NULL)
2529 RCS_getdatebranch (rcs, date, branch)
2534 char *cur_rev = NULL;
2536 char *xbranch, *xrev;
2540 /* look up the first revision on the branch */
2541 xrev = xstrdup (branch);
2542 cp = strrchr (xrev, '.');
2548 *cp = '\0'; /* turn it into a revision */
2550 assert (rcs != NULL);
2552 if (rcs->flags & PARTIAL)
2553 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2555 p = findnode (rcs->versions, xrev);
2559 vers = (RCSVers *) p->data;
2561 /* Tentatively use this revision, if it is early enough. */
2562 if (RCS_datecmp (vers->date, date) <= 0)
2563 cur_rev = vers->version;
2565 /* If no branches list, return now. This is what happens if the branch
2566 is a (magic) branch with no revisions yet. */
2567 if (vers->branches == NULL)
2568 return xstrdup (cur_rev);
2570 /* walk the branches list looking for the branch number */
2571 xbranch = xmalloc (strlen (branch) + 1 + 1); /* +1 for the extra dot */
2572 (void) strcpy (xbranch, branch);
2573 (void) strcat (xbranch, ".");
2574 for (p = vers->branches->list->next; p != vers->branches->list; p = p->next)
2575 if (strncmp (p->key, xbranch, strlen (xbranch)) == 0)
2578 if (p == vers->branches->list)
2580 /* This is what happens if the branch is a (magic) branch with
2581 no revisions yet. Similar to the case where vers->branches ==
2582 NULL, except here there was a another branch off the same
2584 return xstrdup (cur_rev);
2587 p = findnode (rcs->versions, p->key);
2589 /* walk the next pointers until you find the end, or the date is too late */
2592 vers = (RCSVers *) p->data;
2593 if (RCS_datecmp (vers->date, date) <= 0)
2594 cur_rev = vers->version;
2598 /* if there is a next version, find the node */
2599 if (vers->next != NULL)
2600 p = findnode (rcs->versions, vers->next);
2605 /* Return whatever we found, which may be NULL. */
2606 return xstrdup (cur_rev);
2610 * Compare two dates in RCS format. Beware the change in format on January 1,
2611 * 2000, when years go from 2-digit to full format.
2614 RCS_datecmp (date1, date2)
2615 char *date1, *date2;
2617 int length_diff = strlen (date1) - strlen (date2);
2619 return (length_diff ? length_diff : strcmp (date1, date2));
2622 /* Look up revision REV in RCS and return the date specified for the
2623 revision minus FUDGE seconds (FUDGE will generally be one, so that the
2624 logically previous revision will be found later, or zero, if we want
2627 The return value is the date being returned as a time_t, or (time_t)-1
2628 on error (previously was documented as zero on error; I haven't checked
2629 the callers to make sure that they really check for (time_t)-1, but
2630 the latter is what this function really returns). If DATE is non-NULL,
2631 then it must point to MAXDATELEN characters, and we store the same
2632 return value there in DATEFORM format. */
2634 RCS_getrevtime (rcs, rev, date, fudge)
2640 char tdate[MAXDATELEN];
2641 struct tm xtm, *ftm;
2646 /* make sure we have something to look at... */
2647 assert (rcs != NULL);
2649 if (rcs->flags & PARTIAL)
2650 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2652 /* look up the revision */
2653 p = findnode (rcs->versions, rev);
2656 vers = (RCSVers *) p->data;
2658 /* split up the date */
2660 (void) sscanf (vers->date, SDATEFORM, &ftm->tm_year, &ftm->tm_mon,
2661 &ftm->tm_mday, &ftm->tm_hour, &ftm->tm_min,
2664 /* If the year is from 1900 to 1999, RCS files contain only two
2665 digits, and sscanf gives us a year from 0-99. If the year is
2666 2000+, RCS files contain all four digits and we subtract 1900,
2667 because the tm_year field should contain years since 1900. */
2669 if (ftm->tm_year > 1900)
2670 ftm->tm_year -= 1900;
2672 /* put the date in a form getdate can grok */
2673 (void) sprintf (tdate, "%d/%d/%d GMT %d:%d:%d", ftm->tm_mon,
2674 ftm->tm_mday, ftm->tm_year + 1900, ftm->tm_hour,
2675 ftm->tm_min, ftm->tm_sec);
2677 /* turn it into seconds since the epoch */
2678 revdate = get_date (tdate, (struct timeb *) NULL);
2679 if (revdate != (time_t) -1)
2681 revdate -= fudge; /* remove "fudge" seconds */
2684 /* put an appropriate string into ``date'' if we were given one */
2685 ftm = gmtime (&revdate);
2686 (void) sprintf (date, DATEFORM,
2687 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
2688 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
2689 ftm->tm_min, ftm->tm_sec);
2699 assert(rcs != NULL);
2701 if (rcs->flags & PARTIAL)
2702 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2704 if (rcs->locks_data) {
2705 rcs->locks = getlist ();
2706 do_locks (rcs->locks, rcs->locks_data);
2707 free(rcs->locks_data);
2708 rcs->locks_data = NULL;
2718 assert(rcs != NULL);
2720 if (rcs->flags & PARTIAL)
2721 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2723 if (rcs->symbols_data) {
2724 rcs->symbols = getlist ();
2725 do_symbols (rcs->symbols, rcs->symbols_data);
2726 free(rcs->symbols_data);
2727 rcs->symbols_data = NULL;
2730 return rcs->symbols;
2734 * Return the version associated with a particular symbolic tag.
2735 * Returns NULL or a newly malloc'd string.
2738 translate_symtag (rcs, tag)
2742 if (rcs->flags & PARTIAL)
2743 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2745 if (rcs->symbols != NULL)
2749 /* The symbols have already been converted into a list. */
2750 p = findnode (rcs->symbols, tag);
2754 return xstrdup (p->data);
2757 if (rcs->symbols_data != NULL)
2762 /* Look through the RCS symbols information. This is like
2763 do_symbols, but we don't add the information to a list. In
2764 most cases, we will only be called once for this file, so
2765 generating the list is unnecessary overhead. */
2768 cp = rcs->symbols_data;
2769 while ((cp = strchr (cp, tag[0])) != NULL)
2771 if ((cp == rcs->symbols_data || whitespace (cp[-1]))
2772 && strncmp (cp, tag, len) == 0
2777 /* We found the tag. Return the version number. */
2781 while (! whitespace (*cp) && *cp != '\0')
2783 r = xmalloc (cp - v + 1);
2784 strncpy (r, v, cp - v);
2789 while (! whitespace (*cp) && *cp != '\0')
2798 * The argument ARG is the getopt remainder of the -k option specified on the
2799 * command line. This function returns malloc'ed space that can be used
2800 * directly in calls to RCS V5, with the -k flag munged correctly.
2803 RCS_check_kflag (arg)
2806 static const char *const keyword_usage[] =
2808 "%s %s: invalid RCS keyword expansion mode\n",
2809 "Valid expansion modes include:\n",
2810 " -kkv\tGenerate keywords using the default form.\n",
2811 " -kkvl\tLike -kkv, except locker's name inserted.\n",
2812 " -kk\tGenerate only keyword names in keyword strings.\n",
2813 " -kv\tGenerate only keyword values in keyword strings.\n",
2814 " -ko\tGenerate the old keyword string (no changes from checked in file).\n",
2815 " -kb\tGenerate binary file unmodified (merges not allowed) (RCS 5.7).\n",
2816 "(Specify the --help global option for a list of other help options)\n",
2819 /* Big enough to hold any of the strings from kflags. */
2821 char const *const *cpp = NULL;
2825 for (cpp = kflags; *cpp != NULL; cpp++)
2827 if (STREQ (arg, *cpp))
2832 if (arg == NULL || *cpp == NULL)
2834 usage (keyword_usage);
2837 (void) sprintf (karg, "-k%s", *cpp);
2838 return (xstrdup (karg));
2842 * Do some consistency checks on the symbolic tag... These should equate
2843 * pretty close to what RCS checks, though I don't know for certain.
2849 char *invalid = "$,.:;@"; /* invalid RCS tag characters */
2853 * The first character must be an alphabetic letter. The remaining
2854 * characters cannot be non-visible graphic characters, and must not be
2855 * in the set of "invalid" RCS identifier characters.
2859 for (cp = tag; *cp; cp++)
2862 error (1, 0, "tag `%s' has non-visible graphic characters",
2864 if (strchr (invalid, *cp))
2865 error (1, 0, "tag `%s' must not contain the characters `%s'",
2870 error (1, 0, "tag `%s' must start with a letter", tag);
2874 * Return true if RCS revision with TAG is a dead revision.
2877 RCS_isdead (rcs, tag)
2884 if (rcs->flags & PARTIAL)
2885 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2887 p = findnode (rcs->versions, tag);
2891 version = (RCSVers *) p->data;
2892 return (version->dead);
2895 /* Return the RCS keyword expansion mode. For example "b" for binary.
2896 Returns a pointer into storage which is allocated and freed along with
2897 the rest of the RCS information; the caller should not modify this
2898 storage. Returns NULL if the RCS file does not specify a keyword
2899 expansion mode; for all other errors, die with a fatal error. */
2904 assert (rcs != NULL);
2908 /* RCS keywords, and a matching enum. */
2914 #define KEYWORD_INIT(s) (s), sizeof (s) - 1
2915 static const struct rcs_keyword keywords[] =
2917 { KEYWORD_INIT ("Author") },
2918 { KEYWORD_INIT ("Date") },
2919 { KEYWORD_INIT ("Header") },
2920 { KEYWORD_INIT ("Id") },
2921 { KEYWORD_INIT ("Locker") },
2922 { KEYWORD_INIT ("Log") },
2923 { KEYWORD_INIT ("Name") },
2924 { KEYWORD_INIT ("RCSfile") },
2925 { KEYWORD_INIT ("Revision") },
2926 { KEYWORD_INIT ("Source") },
2927 { KEYWORD_INIT ("State") },
2945 /* Convert an RCS date string into a readable string. This is like
2946 the RCS date2str function. */
2949 printable_date (rcs_date)
2950 const char *rcs_date;
2952 int year, mon, mday, hour, min, sec;
2955 (void) sscanf (rcs_date, SDATEFORM, &year, &mon, &mday, &hour, &min,
2959 sprintf (buf, "%04d/%02d/%02d %02d:%02d:%02d", year, mon, mday,
2961 return xstrdup (buf);
2964 /* Escape the characters in a string so that it can be included in an
2968 escape_keyword_value (value, free_value)
2975 for (s = value; *s != '\0'; s++)
2993 return (char *) value;
2996 ret = xmalloc (strlen (value) * 4 + 1);
2999 for (s = value, t = ret; *s != '\0'; s++, t++)
3038 /* Expand RCS keywords in the memory buffer BUF of length LEN. This
3039 applies to file RCS and version VERS. If NAME is not NULL, and is
3040 not a numeric revision, then it is the symbolic tag used for the
3041 checkout. EXPAND indicates how to expand the keywords. This
3042 function sets *RETBUF and *RETLEN to the new buffer and length.
3043 This function may modify the buffer BUF. If BUF != *RETBUF, then
3044 RETBUF is a newly allocated buffer. */
3047 expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
3059 struct expand_buffer
3061 struct expand_buffer *next;
3066 struct expand_buffer *ebuf_last = NULL;
3067 size_t ebuf_len = 0;
3069 char *srch, *srch_next;
3072 if (expand == KFLAG_O || expand == KFLAG_B)
3079 /* If we are using -kkvl, dig out the locker information if any. */
3081 if (expand == KFLAG_KVL)
3084 lock = findnode (RCS_getlocks(rcs), ver->version);
3086 locker = xstrdup (lock->data);
3089 /* RCS keywords look like $STRING$ or $STRING: VALUE$. */
3092 while ((srch_next = memchr (srch, '$', srch_len)) != NULL)
3096 const struct rcs_keyword *keyword;
3103 srch_len -= (srch_next + 1) - srch;
3104 srch = srch_next + 1;
3106 /* Look for the first non alphabetic character after the '$'. */
3107 send = srch + srch_len;
3108 for (s = srch; s < send; s++)
3112 /* If the first non alphabetic character is not '$' or ':',
3113 then this is not an RCS keyword. */
3114 if (s == send || (*s != '$' && *s != ':'))
3117 /* See if this is one of the keywords. */
3119 for (keyword = keywords; keyword->string != NULL; keyword++)
3121 if (keyword->len == slen
3122 && strncmp (keyword->string, srch, slen) == 0)
3127 if (keyword->string == NULL)
3130 kw = (enum keyword) (keyword - keywords);
3132 /* If the keyword ends with a ':', then the old value consists
3133 of the characters up to the next '$'. If there is no '$'
3134 before the end of the line, though, then this wasn't an RCS
3135 keyword after all. */
3138 for (; s < send; s++)
3139 if (*s == '$' || *s == '\n')
3141 if (s == send || *s != '$')
3145 /* At this point we must replace the string from SRCH to S
3146 with the expansion of the keyword KW. */
3148 /* Get the value to use. */
3150 if (expand == KFLAG_K)
3159 case KEYWORD_AUTHOR:
3160 value = ver->author;
3164 value = printable_date (ver->date);
3168 case KEYWORD_HEADER:
3175 if (kw == KEYWORD_HEADER)
3178 path = last_component (rcs->path);
3179 path = escape_keyword_value (path, &free_path);
3180 date = printable_date (ver->date);
3181 value = xmalloc (strlen (path)
3182 + strlen (ver->version)
3184 + strlen (ver->author)
3185 + strlen (ver->state)
3186 + (locker == NULL ? 0 : strlen (locker))
3189 sprintf (value, "%s %s %s %s %s%s%s",
3190 path, ver->version, date, ver->author,
3192 locker != NULL ? " " : "",
3193 locker != NULL ? locker : "");
3201 case KEYWORD_LOCKER:
3206 case KEYWORD_RCSFILE:
3207 value = escape_keyword_value (last_component (rcs->path),
3212 if (name != NULL && ! isdigit (*name))
3213 value = (char *) name;
3218 case KEYWORD_REVISION:
3219 value = ver->version;
3222 case KEYWORD_SOURCE:
3223 value = escape_keyword_value (rcs->path, &free_value);
3232 sub = xmalloc (keyword->len
3233 + (value == NULL ? 0 : strlen (value))
3235 if (expand == KFLAG_V)
3237 /* Decrement SRCH and increment S to remove the $
3246 strcpy (sub, keyword->string);
3247 sublen = strlen (keyword->string);
3248 if (expand != KFLAG_K)
3251 sub[sublen + 1] = ' ';
3257 strcpy (sub + sublen, value);
3258 sublen += strlen (value);
3260 if (expand != KFLAG_V && expand != KFLAG_K)
3270 /* The Log keyword requires special handling. This behaviour
3271 is taken from RCS 5.7. The special log message is what RCS
3273 if (kw == KEYWORD_LOG
3274 && (sizeof "checked in with -k by " <= loglen
3275 || strncmp (log, "checked in with -k by ",
3276 sizeof "checked in with -k by " - 1) != 0))
3280 size_t leader_len, leader_sp_len;
3287 /* We are going to insert the trailing $ ourselves, before
3288 the log message, so we must remove it from S, if we
3289 haven't done so already. */
3290 if (expand != KFLAG_V)
3293 /* Find the start of the line. */
3295 while (start > buf && start[-1] != '\n')
3298 /* Copy the start of the line to use as a comment leader. */
3299 leader_len = srch - start;
3300 if (expand != KFLAG_V)
3302 leader = xmalloc (leader_len);
3303 memcpy (leader, start, leader_len);
3304 leader_sp_len = leader_len;
3305 while (leader_sp_len > 0 && leader[leader_sp_len - 1] == ' ')
3308 /* RCS does some checking for an old style of Log here,
3309 but we don't bother. RCS issues a warning if it
3310 changes anything. */
3312 /* Count the number of newlines in the log message so that
3313 we know how many copies of the leader we will need. */
3315 logend = log + loglen;
3316 for (snl = log; snl < logend; snl++)
3320 date = printable_date (ver->date);
3321 sub = xrealloc (sub,
3324 + strlen (ver->version)
3326 + strlen (ver->author)
3328 + (cnl + 2) * leader_len
3330 if (expand != KFLAG_V)
3337 memcpy (sub + sublen, leader, leader_len);
3338 sublen += leader_len;
3339 sprintf (sub + sublen, "Revision %s %s %s\n",
3340 ver->version, date, ver->author);
3341 sublen += strlen (sub + sublen);
3349 memcpy (sub + sublen, leader, leader_sp_len);
3350 sublen += leader_sp_len;
3359 memcpy (sub + sublen, leader, leader_len);
3360 sublen += leader_len;
3361 for (slnl = sl; slnl < logend && *slnl != '\n'; ++slnl)
3365 memcpy (sub + sublen, sl, slnl - sl);
3366 sublen += slnl - sl;
3371 memcpy (sub + sublen, leader, leader_sp_len);
3372 sublen += leader_sp_len;
3377 /* Now SUB contains a string which is to replace the string
3378 from SRCH to S. SUBLEN is the length of SUB. */
3380 if (srch + sublen == s)
3382 memcpy (srch, sub, sublen);
3387 struct expand_buffer *ebuf;
3389 /* We need to change the size of the buffer. We build a
3390 list of expand_buffer structures. Each expand_buffer
3391 structure represents a portion of the final output. We
3392 concatenate them back into a single buffer when we are
3393 done. This minimizes the number of potentially large
3394 buffer copies we must do. */
3398 ebufs = (struct expand_buffer *) xmalloc (sizeof *ebuf);
3401 ebufs->free_data = 0;
3402 ebuf_len = srch - buf;
3403 ebufs->len = ebuf_len;
3408 assert (srch >= ebuf_last->data);
3409 assert (srch <= ebuf_last->data + ebuf_last->len);
3410 ebuf_len -= ebuf_last->len - (srch - ebuf_last->data);
3411 ebuf_last->len = srch - ebuf_last->data;
3414 ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf);
3417 ebuf->free_data = 1;
3419 ebuf_last->next = ebuf;
3423 ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf);
3425 ebuf->len = srch_len - (s - srch);
3426 ebuf->free_data = 0;
3428 ebuf_last->next = ebuf;
3430 ebuf_len += srch_len - (s - srch);
3433 srch_len -= (s - srch);
3449 ret = xmalloc (ebuf_len);
3452 while (ebufs != NULL)
3454 struct expand_buffer *next;
3456 memcpy (ret, ebufs->data, ebufs->len);
3458 if (ebufs->free_data)
3467 /* Check out a revision from an RCS file.
3469 If PFN is not NULL, then ignore WORKFILE and SOUT. Call PFN zero
3470 or more times with the contents of the file. CALLERDAT is passed,
3471 uninterpreted, to PFN. (The current code will always call PFN
3472 exactly once for a non empty file; however, the current code
3473 assumes that it can hold the entire file contents in memory, which
3474 is not a good assumption, and might change in the future).
3476 Otherwise, if WORKFILE is not NULL, check out the revision to
3477 WORKFILE. However, if WORKFILE is not NULL, and noexec is set,
3478 then don't do anything.
3480 Otherwise, if WORKFILE is NULL, check out the revision to SOUT. If
3481 SOUT is RUN_TTY, then write the contents of the revision to
3482 standard output. When using SOUT, the output is generally a
3483 temporary file; don't bother to get the file modes correct.
3485 REV is the numeric revision to check out. It may be NULL, which
3486 means to check out the head of the default branch.
3488 If NAMETAG is not NULL, and is not a numeric revision, then it is
3489 the tag that should be used when expanding the RCS Name keyword.
3491 OPTIONS is a string such as "-kb" or "-kv" for keyword expansion
3492 options. It may be NULL to use the default expansion mode of the
3493 file, typically "-kkv".
3495 On an error which prevented checking out the file, either print a
3496 nonfatal error and return 1, or give a fatal error. On success,
3499 /* This function mimics the behavior of `rcs co' almost exactly. The
3500 chief difference is in its support for preserving file ownership,
3501 permissions, and special files across checkin and checkout -- see
3502 comments in RCS_checkin for some issues about this. -twp */
3505 RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
3512 RCSCHECKOUTPROC pfn;
3519 struct rcsbuffer rcsbuf;
3527 #ifdef PRESERVE_PERMISSIONS_SUPPORT
3531 int change_rcs_owner = 0;
3532 int change_rcs_group = 0;
3533 int change_rcs_mode = 0;
3534 int special_file = 0;
3535 unsigned long devnum_long;
3541 (void) fprintf (stderr, "%s-> checkout (%s, %s, %s, %s)\n",
3542 #ifdef SERVER_SUPPORT
3543 server_active ? "S" : " ",
3548 rev != NULL ? rev : "",
3549 options != NULL ? options : "",
3550 (pfn != NULL ? "(function)"
3553 : (sout != RUN_TTY ? sout : "(stdout)"))));
3556 assert (rev == NULL || isdigit (*rev));
3558 if (noexec && workfile != NULL)
3561 assert (sout == RUN_TTY || workfile == NULL);
3562 assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL));
3564 /* Some callers, such as Checkin or remove_file, will pass us a
3566 if (rev != NULL && (numdots (rev) & 1) == 0)
3568 rev = RCS_getbranch (rcs, rev, 1);
3570 error (1, 0, "internal error: bad branch tag in checkout");
3574 if (rev == NULL || STREQ (rev, rcs->head))
3578 /* We want the head revision. Try to read it directly. */
3580 if (rcs->flags & PARTIAL)
3581 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
3583 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf);
3586 if (! rcsbuf_getrevnum (&rcsbuf, &key))
3587 error (1, 0, "unexpected EOF reading %s", rcs->path);
3588 while (rcsbuf_getkey (&rcsbuf, &key, &value))
3590 if (STREQ (key, "log"))
3591 log = rcsbuf_valcopy (&rcsbuf, value, 0, &loglen);
3592 else if (STREQ (key, "text"))
3601 error (0, 0, "internal error: cannot find head text");
3607 rcsbuf_valpolish (&rcsbuf, value, 0, &len);
3609 if (fstat (fileno (fp), &sb) < 0)
3610 error (1, errno, "cannot fstat %s", rcs->path);
3612 rcsbuf_cache (rcs, &rcsbuf);
3616 struct rcsbuffer *rcsbufp;
3618 /* It isn't the head revision of the trunk. We'll need to
3619 walk through the deltas. */
3622 if (rcs->flags & PARTIAL)
3623 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
3627 /* If RCS_deltas didn't close the file, we could use fstat
3628 here too. Probably should change it thusly.... */
3629 if (stat (rcs->path, &sb) < 0)
3630 error (1, errno, "cannot stat %s", rcs->path);
3635 if (fstat (fileno (fp), &sb) < 0)
3636 error (1, errno, "cannot fstat %s", rcs->path);
3640 RCS_deltas (rcs, fp, rcsbufp, rev, RCS_FETCH, &value, &len,
3645 /* If OPTIONS is NULL or the empty string, then the old code would
3646 invoke the RCS co program with no -k option, which means that
3647 co would use the string we have stored in rcs->expand. */
3648 if ((options == NULL || options[0] == '\0') && rcs->expand == NULL)
3652 const char *ouroptions;
3653 const char * const *cpp;
3655 if (options != NULL && options[0] != '\0')
3657 assert (options[0] == '-' && options[1] == 'k');
3658 ouroptions = options + 2;
3661 ouroptions = rcs->expand;
3663 for (cpp = kflags; *cpp != NULL; cpp++)
3664 if (STREQ (*cpp, ouroptions))
3668 expand = (enum kflag) (cpp - kflags);
3672 "internal error: unsupported substitution string -k%s",
3678 #ifdef PRESERVE_PERMISSIONS_SUPPORT
3679 /* Handle special files and permissions, if that is desired. */
3684 struct hardlink_info *hlinfo;
3686 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
3688 error (1, 0, "internal error: no revision information for %s",
3689 rev == NULL ? rcs->head : rev);
3690 vers = (RCSVers *) vp->data;
3692 /* First we look for symlinks, which are simplest to handle. */
3693 info = findnode (vers->other_delta, "symlink");
3698 if (pfn != NULL || (workfile == NULL && sout == RUN_TTY))
3699 error (1, 0, "symbolic link %s:%s cannot be piped",
3700 rcs->path, vers->version);
3701 if (workfile == NULL)
3706 /* Remove `dest', just in case. It's okay to get ENOENT here,
3707 since we just want the file not to be there. (TODO: decide
3708 whether it should be considered an error for `dest' to exist
3709 at this point. If so, the unlink call should be removed and
3710 `symlink' should signal the error. -twp) */
3711 if (unlink (dest) < 0 && existence_error (errno))
3712 error (1, errno, "cannot remove %s", dest);
3713 if (symlink (info->data, dest) < 0)
3714 error (1, errno, "cannot create symbolic link from %s to %s",
3723 /* Next, we look at this file's hardlinks field, and see whether
3724 it is linked to any other file that has been checked out.
3725 If so, we don't do anything else -- just link it to that file.
3727 If we are checking out a file to a pipe or temporary storage,
3728 none of this should matter. Hence the `workfile != NULL'
3729 wrapper around the whole thing. -twp */
3731 if (workfile != NULL)
3733 info = findnode (vers->other_delta, "hardlinks");
3736 char *links = xstrdup (info->data);
3737 char *working_dir = xgetwd();
3738 char *p, *file = NULL;
3739 Node *n, *uptodate_link;
3741 /* For each file in the hardlinks field, check to see
3742 if it exists, and if so, if it has been checked out
3744 uptodate_link = NULL;
3745 for (p = strtok (links, " ");
3746 p != NULL && uptodate_link == NULL;
3747 p = strtok (NULL, " "))
3750 xmalloc (sizeof(char) *
3751 (strlen(working_dir) + strlen(p) + 2));
3752 sprintf (file, "%s/%s", working_dir, p);
3753 n = lookup_file_by_inode (file);
3756 if (strcmp (p, workfile) != 0)
3758 /* One of the files that WORKFILE should be
3759 linked to is not even in the working directory.
3760 The user should probably be warned. */
3762 "warning: %s should be hardlinked to %s, but is missing",
3769 /* hlinfo may be NULL if, for instance, a file is being
3771 hlinfo = (struct hardlink_info *) n->data;
3772 if (hlinfo && hlinfo->checked_out)
3779 /* If we've found a file that `workfile' is supposed to be
3780 linked to, and it has been checked out since CVS was
3781 invoked, then simply link workfile to that file.
3783 If one of these conditions is not met, then we're
3784 checking out workfile to a temp file or stdout, or
3785 workfile is the first one in its hardlink group to be
3786 checked out. Either way we must continue with a full
3789 if (uptodate_link != NULL)
3791 if (link (uptodate_link->key, workfile) < 0)
3792 error (1, errno, "cannot link %s to %s",
3793 workfile, uptodate_link->key);
3794 hlinfo->checked_out = 1; /* probably unnecessary */
3804 info = findnode (vers->other_delta, "owner");
3807 change_rcs_owner = 1;
3808 rcs_owner = (uid_t) strtoul (info->data, NULL, 10);
3810 info = findnode (vers->other_delta, "group");
3813 change_rcs_group = 1;
3814 rcs_group = (gid_t) strtoul (info->data, NULL, 10);
3816 info = findnode (vers->other_delta, "permissions");
3819 change_rcs_mode = 1;
3820 rcs_mode = (mode_t) strtoul (info->data, NULL, 8);
3822 info = findnode (vers->other_delta, "special");
3825 /* If the size of `devtype' changes, fix the sscanf call also */
3828 if (sscanf (info->data, "%16s %lu",
3829 devtype, &devnum_long) < 2)
3830 error (1, 0, "%s:%s has bad `special' newphrase %s",
3831 workfile, vers->version, info->data);
3832 devnum = devnum_long;
3833 if (strcmp (devtype, "character") == 0)
3834 special_file = S_IFCHR;
3835 else if (strcmp (devtype, "block") == 0)
3836 special_file = S_IFBLK;
3838 error (0, 0, "%s is a special file of unsupported type `%s'",
3839 workfile, info->data);
3844 if (expand != KFLAG_O && expand != KFLAG_B)
3848 /* Don't fetch the delta node again if we already have it. */
3851 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
3853 error (1, 0, "internal error: no revision information for %s",
3854 rev == NULL ? rcs->head : rev);
3857 expand_keywords (rcs, (RCSVers *) vp->data, nametag, log, loglen,
3858 expand, value, len, &newvalue, &len);
3860 if (newvalue != value)
3877 #ifdef PRESERVE_PERMISSIONS_SUPPORT
3879 error (1, 0, "special file %s cannot be piped to anything",
3882 /* The PFN interface is very simple to implement right now, as
3883 we always have the entire file in memory. */
3885 pfn (callerdat, value, len);
3887 #ifdef PRESERVE_PERMISSIONS_SUPPORT
3888 else if (special_file)
3892 /* Can send either to WORKFILE or to SOUT, as long as SOUT is
3897 if (sout == RUN_TTY)
3898 error (1, 0, "special file %s cannot be written to stdout",
3903 /* Unlink `dest', just in case. It's okay if this provokes a
3905 if (unlink (dest) < 0 && existence_error (errno))
3906 error (1, errno, "cannot remove %s", dest);
3907 if (mknod (dest, special_file, devnum) < 0)
3908 error (1, errno, "could not create special file %s",
3914 /* Not a special file: write to WORKFILE or SOUT. */
3915 if (workfile == NULL)
3917 if (sout == RUN_TTY)
3921 /* Symbolic links should be removed before replacement, so that
3922 `fopen' doesn't follow the link and open the wrong file. */
3924 if (unlink_file (sout) < 0)
3925 error (1, errno, "cannot remove %s", sout);
3926 ofp = CVS_FOPEN (sout, expand == KFLAG_B ? "wb" : "w");
3928 error (1, errno, "cannot open %s", sout);
3933 /* Output is supposed to go to WORKFILE, so we should open that
3934 file. Symbolic links should be removed first (see above). */
3935 if (islink (workfile))
3936 if (unlink_file (workfile) < 0)
3937 error (1, errno, "cannot remove %s", workfile);
3938 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
3940 error (1, errno, "cannot open %s", workfile);
3943 if (workfile == NULL && sout == RUN_TTY)
3945 if (expand == KFLAG_B)
3946 cvs_output_binary (value, len);
3949 /* cvs_output requires the caller to check for zero
3952 cvs_output (value, len);
3957 /* NT 4.0 is said to have trouble writing 2099999 bytes
3958 (for example) in a single fwrite. So break it down
3959 (there is no need to be writing that much at once
3960 anyway; it is possible that LARGEST_FWRITE should be
3961 somewhat larger for good performance, but for testing I
3962 want to start with a small value until/unless a bigger
3963 one proves useful). */
3964 #define LARGEST_FWRITE 8192
3966 size_t nstep = (len < LARGEST_FWRITE ? len : LARGEST_FWRITE);
3971 if (fwrite (p, 1, nstep, ofp) != nstep)
3972 error (1, errno, "cannot write %s",
3975 : (sout != RUN_TTY ? sout : "stdout")));
3984 if (workfile != NULL)
3988 #ifdef PRESERVE_PERMISSIONS_SUPPORT
3989 if (!special_file && fclose (ofp) < 0)
3990 error (1, errno, "cannot close %s", workfile);
3992 if (change_rcs_owner || change_rcs_group)
3994 if (chown (workfile, rcs_owner, rcs_group) < 0)
3995 error (0, errno, "could not change file ownership on %s",
3999 ret = chmod (workfile,
4002 : sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
4004 if (fclose (ofp) < 0)
4005 error (1, errno, "cannot close %s", workfile);
4007 ret = chmod (workfile,
4008 sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
4012 error (0, errno, "cannot change mode of file %s",
4016 else if (sout != RUN_TTY)
4019 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4023 error (1, errno, "cannot close %s", sout);
4026 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4027 /* If we are in the business of preserving hardlinks, then
4028 mark this file as having been checked out. */
4029 if (preserve_perms && workfile != NULL)
4030 update_hardlink_info (workfile);
4041 static RCSVers *RCS_findlock_or_tip PROTO ((RCSNode *rcs));
4043 /* Find the delta currently locked by the user. From the `ci' man page:
4045 "If rev is omitted, ci tries to derive the new revision
4046 number from the caller's last lock. If the caller has
4047 locked the tip revision of a branch, the new revision is
4048 appended to that branch. The new revision number is
4049 obtained by incrementing the tip revision number. If the
4050 caller locked a non-tip revision, a new branch is started
4051 at that revision by incrementing the highest branch number
4052 at that revision. The default initial branch and level
4055 If rev is omitted and the caller has no lock, but owns the
4056 file and locking is not set to strict, then the revision
4057 is appended to the default branch (normally the trunk; see
4058 the -b option of rcs(1))."
4060 RCS_findlock_or_tip finds the unique revision locked by the caller
4061 and returns its delta node. If the caller has not locked any
4062 revisions (and is permitted to commit to an unlocked delta, as
4063 described above), return the tip of the default branch. */
4066 RCS_findlock_or_tip (rcs)
4069 char *user = getcaller();
4073 /* Find unique delta locked by caller. This code is very similar
4074 to the code in RCS_unlock -- perhaps it could be abstracted
4075 into a RCS_findlock function. */
4076 locklist = RCS_getlocks (rcs);
4078 for (p = locklist->list->next; p != locklist->list; p = p->next)
4080 if (STREQ (p->data, user))
4085 %s: multiple revisions locked by %s; please specify one", rcs->path, user);
4094 /* Found an old lock, but check that the revision still exists. */
4095 p = findnode (rcs->versions, lock->key);
4098 error (0, 0, "%s: can't unlock nonexistent revision %s",
4103 return (RCSVers *) p->data;
4106 /* No existing lock. The RCS rule is that this is an error unless
4107 locking is nonstrict AND the file is owned by the current
4108 user. Trying to determine the latter is a portability nightmare
4109 in the face of NT, VMS, AFS, and other systems with non-unix-like
4110 ideas of users and owners. In the case of CVS, we should never get
4111 here (as long as the traditional behavior of making sure to call
4112 RCS_lock persists). Anyway, we skip the RCS error checks
4113 and just return the default branch or head. The reasoning is that
4114 those error checks are to make users lock before a checkin, and we do
4115 that in other ways if at all anyway (e.g. rcslock.pl). */
4117 p = findnode (rcs->versions, RCS_getbranch (rcs, rcs->branch, 0));
4118 return (RCSVers *) p->data;
4121 /* Revision number string, R, must contain a `.'.
4122 Return a newly-malloc'd copy of the prefix of R up
4123 to but not including the final `.'. */
4131 char *dot = strrchr (r, '.');
4135 new_r = xmalloc (len + 1);
4136 memcpy (new_r, r, len);
4137 *(new_r + len) = '\0';
4141 /* Revision number string, R, must contain a `.'.
4142 R must be writable. Replace the rightmost `.' in R with
4143 the NUL byte and return a pointer to that NUL byte. */
4146 truncate_revnum_in_place (r)
4149 char *dot = strrchr (r, '.');
4155 /* Revision number strings, R and S, must each contain a `.'.
4156 R and S must be writable and must have the same number of dots.
4157 Truncate R and S for the comparison, then restored them to their
4159 Return the result (see compare_revnums) of comparing R and S
4160 ignoring differences in any component after the rightmost `.'. */
4163 compare_truncated_revnums (r, s)
4167 char *r_dot = truncate_revnum_in_place (r);
4168 char *s_dot = truncate_revnum_in_place (s);
4171 assert (numdots (r) == numdots (s));
4173 cmp = compare_revnums (r, s);
4181 /* Return a malloc'd copy of the string representing the highest branch
4182 number on BRANCHNODE. If there are no branches on BRANCHNODE, return NULL.
4183 FIXME: isn't the max rev always the last one?
4184 If so, we don't even need a loop. */
4186 static char *max_rev PROTO ((const RCSVers *));
4189 max_rev (branchnode)
4190 const RCSVers *branchnode;
4196 if (branchnode->branches == NULL)
4202 head = branchnode->branches->list;
4203 for (bp = head->next; bp != head; bp = bp->next)
4205 if (max == NULL || compare_truncated_revnums (max, bp->key) < 0)
4212 return truncate_revnum (max);
4215 /* Create BRANCH in RCS's delta tree. BRANCH may be either a branch
4216 number or a revision number. In the former case, create the branch
4217 with the specified number; in the latter case, create a new branch
4218 rooted at node BRANCH with a higher branch number than any others.
4219 Return the number of the tip node on the new branch. */
4222 RCS_addbranch (rcs, branch)
4226 char *branchpoint, *newrevnum;
4229 RCSVers *branchnode;
4231 /* Append to end by default. */
4234 branchpoint = xstrdup (branch);
4235 if ((numdots (branchpoint) & 1) == 0)
4237 truncate_revnum_in_place (branchpoint);
4240 /* Find the branch rooted at BRANCHPOINT. */
4241 nodep = findnode (rcs->versions, branchpoint);
4244 error (0, 0, "%s: can't find branch point %s", rcs->path, branchpoint);
4247 branchnode = (RCSVers *) nodep->data;
4249 /* If BRANCH was a full branch number, make sure it is higher than MAX. */
4250 if ((numdots (branch) & 1) == 1)
4252 if (branchnode->branches == NULL)
4254 /* We have to create the first branch on this node, which means
4255 appending ".2" to the revision number. */
4256 newrevnum = (char *) xmalloc (strlen (branch) + 3);
4257 strcpy (newrevnum, branch);
4258 strcat (newrevnum, ".2");
4262 char *max = max_rev (branchnode);
4264 newrevnum = increment_revnum (max);
4270 newrevnum = xstrdup (branch);
4272 if (branchnode->branches != NULL)
4277 /* Find the position of this new branch in the sorted list
4279 head = branchnode->branches->list;
4280 for (bp = head->next; bp != head; bp = bp->next)
4285 /* The existing list must be sorted on increasing revnum. */
4286 assert (bp->next == head
4287 || compare_truncated_revnums (bp->key,
4288 bp->next->key) < 0);
4289 dot = truncate_revnum_in_place (bp->key);
4290 found_pos = (compare_revnums (branch, bp->key) < 0);
4302 newrevnum = (char *) xrealloc (newrevnum, strlen (newrevnum) + 3);
4303 strcat (newrevnum, ".1");
4305 /* Add this new revision number to BRANCHPOINT's branches list. */
4306 if (branchnode->branches == NULL)
4307 branchnode->branches = getlist();
4309 bp->key = xstrdup (newrevnum);
4311 /* Append to the end of the list by default, that is, just before
4312 the header node, `list'. */
4314 marker = branchnode->branches->list;
4318 fail = insert_before (branchnode->branches, marker, bp);
4325 /* Check in to RCSFILE with revision REV (which must be greater than
4326 the largest revision) and message MESSAGE (which is checked for
4327 legality). If FLAGS & RCS_FLAGS_DEAD, check in a dead revision.
4328 If FLAGS & RCS_FLAGS_QUIET, tell ci to be quiet. If FLAGS &
4329 RCS_FLAGS_MODTIME, use the working file's modification time for the
4330 checkin time. WORKFILE is the working file to check in from, or
4331 NULL to use the usual RCS rules for deriving it from the RCSFILE.
4332 If FLAGS & RCS_FLAGS_KEEPFILE, don't unlink the working file;
4333 unlinking the working file is standard RCS behavior, but is rarely
4334 appropriate for CVS.
4336 This function should almost exactly mimic the behavior of `rcs ci'. The
4337 principal point of difference is the support here for preserving file
4338 ownership and permissions in the delta nodes. This is not a clean
4339 solution -- precisely because it diverges from RCS's behavior -- but
4340 it doesn't seem feasible to do this anywhere else in the code. [-twp]
4342 Return value is -1 for error (and errno is set to indicate the
4343 error), positive for error (and an error message has been printed),
4344 or zero for success. */
4347 RCS_checkin (rcs, workfile, message, rev, flags)
4354 RCSVers *delta, *commitpt;
4357 char *tmpfile, *changefile, *chtext;
4360 int buflen, chtextlen;
4361 int status, checkin_quiet, allocated_workfile;
4367 if (rcs->flags & PARTIAL)
4368 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
4370 /* Get basename of working file. Is there a library function to
4371 do this? I couldn't find one. -twp */
4372 allocated_workfile = 0;
4373 if (workfile == NULL)
4376 int extlen = strlen (RCSEXT);
4377 workfile = xstrdup (last_component (rcs->path));
4378 p = workfile + (strlen (workfile) - extlen);
4379 assert (strncmp (p, RCSEXT, extlen) == 0);
4381 allocated_workfile = 1;
4384 checkin_quiet = flags & RCS_FLAGS_QUIET;
4387 cvs_output (rcs->path, 0);
4388 cvs_output (" <-- ", 7);
4389 cvs_output (workfile, 0);
4390 cvs_output ("\n", 1);
4393 /* Create new delta node. */
4394 delta = (RCSVers *) xmalloc (sizeof (RCSVers));
4395 memset (delta, 0, sizeof (RCSVers));
4396 delta->author = xstrdup (getcaller ());
4397 if (flags & RCS_FLAGS_MODTIME)
4400 if (stat (workfile, &ws) < 0)
4402 error (1, errno, "cannot stat %s", workfile);
4404 modtime = ws.st_mtime;
4407 (void) time (&modtime);
4408 ftm = gmtime (&modtime);
4409 delta->date = (char *) xmalloc (MAXDATELEN);
4410 (void) sprintf (delta->date, DATEFORM,
4411 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
4412 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
4413 ftm->tm_min, ftm->tm_sec);
4414 if (flags & RCS_FLAGS_DEAD)
4416 delta->state = xstrdup (RCSDEAD);
4420 delta->state = xstrdup ("Exp");
4422 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4423 /* If permissions should be preserved on this project, then
4424 save the permission info. */
4429 char buf[64]; /* static buffer should be safe: see usage. -twp */
4432 delta->other_delta = getlist();
4434 if (CVS_LSTAT (workfile, &sb) < 0)
4435 error (1, 1, "cannot lstat %s", workfile);
4437 if (S_ISLNK (sb.st_mode))
4440 np->key = xstrdup ("symlink");
4441 np->data = xreadlink (workfile);
4442 addnode (delta->other_delta, np);
4446 (void) sprintf (buf, "%u", sb.st_uid);
4448 np->key = xstrdup ("owner");
4449 np->data = xstrdup (buf);
4450 addnode (delta->other_delta, np);
4452 (void) sprintf (buf, "%u", sb.st_gid);
4454 np->key = xstrdup ("group");
4455 np->data = xstrdup (buf);
4456 addnode (delta->other_delta, np);
4458 (void) sprintf (buf, "%o", sb.st_mode & 07777);
4460 np->key = xstrdup ("permissions");
4461 np->data = xstrdup (buf);
4462 addnode (delta->other_delta, np);
4464 /* Save device number. */
4465 switch (sb.st_mode & S_IFMT)
4467 case S_IFREG: break;
4471 np->key = xstrdup ("special");
4472 sprintf (buf, "%s %lu",
4473 ((sb.st_mode & S_IFMT) == S_IFCHR
4474 ? "character" : "block"),
4475 (unsigned long) sb.st_rdev);
4476 np->data = xstrdup (buf);
4477 addnode (delta->other_delta, np);
4481 error (0, 0, "special file %s has unknown type", workfile);
4484 /* Save hardlinks. */
4485 fullpath = xgetwd();
4486 fullpath = xrealloc (fullpath,
4487 strlen(fullpath) + strlen(workfile) + 2);
4488 sprintf (fullpath + strlen(fullpath), "/%s", workfile);
4490 np = lookup_file_by_inode (fullpath);
4493 error (1, 0, "lost information on %s's linkage", workfile);
4497 struct hardlink_info *hlinfo;
4498 hlinfo = (struct hardlink_info *) np->data;
4500 np->key = xstrdup ("hardlinks");
4501 np->data = xstrdup (hlinfo->links);
4502 (void) addnode (delta->other_delta, np);
4508 /* Create a new deltatext node. */
4509 dtext = (Deltatext *) xmalloc (sizeof (Deltatext));
4510 memset (dtext, 0, sizeof (Deltatext));
4512 dtext->log = make_message_rcslegal (message);
4514 /* If the delta tree is empty, then there's nothing to link the
4515 new delta into. So make a new delta tree, snarf the working
4516 file contents, and just write the new RCS file. */
4517 if (rcs->head == NULL)
4522 /* Figure out what the first revision number should be. */
4523 if (rev == NULL || *rev == '\0')
4524 newrev = xstrdup ("1.1");
4525 else if (numdots (rev) == 0)
4527 newrev = (char *) xmalloc (strlen (rev) + 3);
4528 strcpy (newrev, rev);
4529 strcat (newrev, ".1");
4532 newrev = xstrdup (rev);
4534 /* Don't need to xstrdup NEWREV because it's already dynamic, and
4535 not used for anything else. (Don't need to free it, either.) */
4537 delta->version = xstrdup (newrev);
4539 nodep->type = RCSVERS;
4540 nodep->key = xstrdup (newrev);
4541 nodep->data = (char *) delta;
4542 (void) addnode (rcs->versions, nodep);
4544 dtext->version = xstrdup (newrev);
4546 get_file (workfile, workfile,
4547 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
4548 &dtext->text, &bufsize, &dtext->len);
4552 cvs_output ("initial revision: ", 0);
4553 cvs_output (rcs->head, 0);
4554 cvs_output ("\n", 1);
4557 /* We are probably about to invalidate any cached file. */
4558 rcsbuf_cache_close ();
4560 fout = rcs_internal_lockfile (rcs->path);
4561 RCS_putadmin (rcs, fout);
4562 RCS_putdtree (rcs, rcs->head, fout);
4563 RCS_putdesc (rcs, fout);
4564 rcs->delta_pos = ftell (fout);
4565 if (rcs->delta_pos == -1)
4566 error (1, errno, "cannot ftell for %s", rcs->path);
4567 putdeltatext (fout, dtext);
4568 rcs_internal_unlockfile (fout, rcs->path);
4569 freedeltatext (dtext);
4571 if ((flags & RCS_FLAGS_KEEPFILE) == 0)
4573 if (unlink_file (workfile) < 0)
4574 /* FIXME-update-dir: message does not include update_dir. */
4575 error (0, errno, "cannot remove %s", workfile);
4579 cvs_output ("done\n", 5);
4584 /* Derive a new revision number. From the `ci' man page:
4586 "If rev is a revision number, it must be higher than the
4587 latest one on the branch to which rev belongs, or must
4590 If rev is a branch rather than a revision number, the new
4591 revision is appended to that branch. The level number is
4592 obtained by incrementing the tip revision number of that
4593 branch. If rev indicates a non-existing branch, that
4594 branch is created with the initial revision numbered
4597 RCS_findlock_or_tip handles the case where REV is omitted.
4598 RCS 5.7 also permits REV to be "$" or to begin with a dot, but
4599 we do not address those cases -- every routine that calls
4600 RCS_checkin passes it a numeric revision. */
4602 if (rev == NULL || *rev == '\0')
4604 /* Figure out where the commit point is by looking for locks.
4605 If the commit point is at the tip of a branch (or is the
4606 head of the delta tree), then increment its revision number
4607 to obtain the new revnum. Otherwise, start a new
4609 commitpt = RCS_findlock_or_tip (rcs);
4610 if (commitpt == NULL)
4615 else if (commitpt->next == NULL
4616 || STREQ (commitpt->version, rcs->head))
4617 delta->version = increment_revnum (commitpt->version);
4619 delta->version = RCS_addbranch (rcs, commitpt->version);
4623 /* REV is either a revision number or a branch number. Find the
4624 tip of the target branch. */
4625 char *branch, *tip, *newrev, *p;
4628 assert (isdigit(*rev));
4630 newrev = xstrdup (rev);
4631 dots = numdots (newrev);
4632 isrevnum = dots & 1;
4634 branch = xstrdup (rev);
4637 p = strrchr (branch, '.');
4641 /* Find the tip of the target branch. If we got a one- or two-digit
4642 revision number, this will be the head of the tree. Exception:
4643 if rev is a single-field revision equal to the branch number of
4644 the trunk (usually "1") then we want to treat it like an ordinary
4648 tip = xstrdup (rcs->head);
4649 if (atoi (tip) != atoi (branch))
4651 newrev = (char *) xrealloc (newrev, strlen (newrev) + 3);
4652 strcat (newrev, ".1");
4653 dots = isrevnum = 1;
4657 tip = xstrdup (rcs->head);
4659 tip = RCS_getbranch (rcs, branch, 1);
4661 /* If the branch does not exist, and we were supplied an exact
4662 revision number, signal an error. Otherwise, if we were
4663 given only a branch number, create it and set COMMITPT to
4664 the branch point. */
4669 error (0, 0, "%s: can't find branch point %s",
4676 delta->version = RCS_addbranch (rcs, branch);
4677 p = strrchr (branch, '.');
4679 tip = xstrdup (branch);
4685 /* NEWREV must be higher than TIP. */
4686 if (compare_revnums (tip, newrev) >= 0)
4689 "%s: revision %s too low; must be higher than %s",
4698 delta->version = xstrdup (newrev);
4701 /* Just increment the tip number to get the new revision. */
4702 delta->version = increment_revnum (tip);
4705 nodep = findnode (rcs->versions, tip);
4706 commitpt = (RCSVers *) nodep->data;
4713 assert (delta->version != NULL);
4715 /* If COMMITPT is locked by us, break the lock. If it's locked
4716 by someone else, signal an error. */
4717 nodep = findnode (RCS_getlocks (rcs), commitpt->version);
4720 if (! STREQ (nodep->data, delta->author))
4722 error (0, 0, "%s: revision %s locked by %s",
4724 nodep->key, nodep->data);
4731 dtext->version = xstrdup (delta->version);
4733 /* Obtain the change text for the new delta. If DELTA is to be the
4734 new head of the tree, then its change text should be the contents
4735 of the working file, and LEAFNODE's change text should be a diff.
4736 Else, DELTA's change text should be a diff between LEAFNODE and
4737 the working file. */
4739 tmpfile = cvs_temp_name();
4740 status = RCS_checkout (rcs, NULL, commitpt->version, NULL,
4741 ((rcs->expand != NULL
4742 && STREQ (rcs->expand, "b"))
4746 (RCSCHECKOUTPROC)0, NULL);
4749 "could not check out revision %s of `%s'",
4750 commitpt->version, rcs->path);
4752 bufsize = buflen = 0;
4755 changefile = cvs_temp_name();
4757 /* Diff options should include --binary if the RCS file has -kb set
4758 in its `expand' field. */
4759 diffopts = (rcs->expand != NULL && STREQ (rcs->expand, "b")
4763 if (STREQ (commitpt->version, rcs->head) &&
4764 numdots (delta->version) == 1)
4766 /* If this revision is being inserted on the trunk, the change text
4767 for the new delta should be the contents of the working file ... */
4769 get_file (workfile, workfile,
4770 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
4771 &dtext->text, &bufsize, &dtext->len);
4773 /* ... and the change text for the old delta should be a diff. */
4774 commitpt->text = (Deltatext *) xmalloc (sizeof (Deltatext));
4775 memset (commitpt->text, 0, sizeof (Deltatext));
4778 switch (diff_exec (workfile, tmpfile, diffopts, changefile))
4784 /* FIXME-update-dir: message does not include update_dir. */
4785 error (1, errno, "error diffing %s", workfile);
4788 /* FIXME-update-dir: message does not include update_dir. */
4789 error (1, 0, "error diffing %s", workfile);
4793 /* OK, the text file case here is really dumb. Logically
4794 speaking we want diff to read the files in text mode,
4795 convert them to the canonical form found in RCS files
4796 (which, we hope at least, is independent of OS--always
4797 bare linefeeds), and then work with change texts in that
4798 format. However, diff_exec both generates change
4799 texts and produces output for user purposes (e.g. patch.c),
4800 and there is no way to distinguish between the two cases.
4801 So we actually implement the text file case by writing the
4802 change text as a text file, then reading it as a text file.
4803 This should cause no harm, but doesn't strike me as
4805 get_file (changefile, changefile,
4806 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
4807 &commitpt->text->text, &bufsize, &commitpt->text->len);
4809 /* If COMMITPT->TEXT->TEXT is NULL, it means that CHANGEFILE
4810 was empty and that there are no differences between revisions.
4811 In that event, we want to force RCS_rewrite to write an empty
4812 string for COMMITPT's change text. Leaving the change text
4813 field set NULL won't work, since that means "preserve the original
4814 change text for this delta." */
4815 if (commitpt->text->text == NULL)
4817 commitpt->text->text = xstrdup ("");
4818 commitpt->text->len = 0;
4823 /* This file is not being inserted at the head, but on a side
4824 branch somewhere. Make a diff from the previous revision
4825 to the working file. */
4826 switch (diff_exec (tmpfile, workfile, diffopts, changefile))
4832 /* FIXME-update-dir: message does not include update_dir. */
4833 error (1, errno, "error diffing %s", workfile);
4836 /* FIXME-update-dir: message does not include update_dir. */
4837 error (1, 0, "error diffing %s", workfile);
4840 /* See the comment above, at the other get_file invocation,
4841 regarding binary vs. text. */
4842 get_file (changefile, changefile,
4843 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
4844 &dtext->text, &bufsize,
4846 if (dtext->text == NULL)
4848 dtext->text = xstrdup ("");
4853 /* Update DELTA linkage. It is important not to do this before
4854 the very end of RCS_checkin; if an error arises that forces
4855 us to abort checking in, we must not have malformed deltas
4856 partially linked into the tree.
4858 If DELTA and COMMITPT are on different branches, do nothing --
4859 DELTA is linked to the tree through COMMITPT->BRANCHES, and we
4860 don't want to change `next' pointers.
4862 Otherwise, if the nodes are both on the trunk, link DELTA to
4863 COMMITPT; otherwise, link COMMITPT to DELTA. */
4865 if (numdots (commitpt->version) == numdots (delta->version))
4867 if (STREQ (commitpt->version, rcs->head))
4869 delta->next = rcs->head;
4870 rcs->head = xstrdup (delta->version);
4873 commitpt->next = xstrdup (delta->version);
4876 /* Add DELTA to RCS->VERSIONS. */
4877 if (rcs->versions == NULL)
4878 rcs->versions = getlist();
4880 nodep->type = RCSVERS;
4881 nodep->key = xstrdup (delta->version);
4882 nodep->data = (char *) delta;
4883 (void) addnode (rcs->versions, nodep);
4885 /* Write the new RCS file, inserting the new delta at COMMITPT. */
4888 cvs_output ("new revision: ", 14);
4889 cvs_output (delta->version, 0);
4890 cvs_output ("; previous revision: ", 21);
4891 cvs_output (commitpt->version, 0);
4892 cvs_output ("\n", 1);
4895 RCS_rewrite (rcs, dtext, commitpt->version);
4897 if ((flags & RCS_FLAGS_KEEPFILE) == 0)
4899 if (unlink_file (workfile) < 0)
4900 /* FIXME-update-dir: message does not include update_dir. */
4901 error (1, errno, "cannot remove %s", workfile);
4903 if (unlink_file (tmpfile) < 0)
4904 error (0, errno, "cannot remove %s", tmpfile);
4905 if (unlink_file (changefile) < 0)
4906 error (0, errno, "cannot remove %s", changefile);
4909 cvs_output ("done\n", 5);
4912 if (allocated_workfile)
4915 if (commitpt != NULL && commitpt->text != NULL)
4917 freedeltatext (commitpt->text);
4918 commitpt->text = NULL;
4921 freedeltatext (dtext);
4923 free_rcsvers_contents (delta);
4928 /* This structure is passed between RCS_cmp_file and cmp_file_buffer. */
4930 struct cmp_file_data
4932 const char *filename;
4937 /* Compare the contents of revision REV of RCS file RCS with the
4938 contents of the file FILENAME. OPTIONS is a string for the keyword
4939 expansion options. Return 0 if the contents of the revision are
4940 the same as the contents of the file, 1 if they are different. */
4943 RCS_cmp_file (rcs, rev, options, filename)
4947 const char *filename;
4951 struct cmp_file_data data;
4954 if (options != NULL && options[0] != '\0')
4955 binary = STREQ (options, "-kb");
4960 expand = RCS_getexpand (rcs);
4961 if (expand != NULL && STREQ (expand, "b"))
4967 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4968 /* If CVS is to deal properly with special files (when
4969 PreservePermissions is on), the best way is to check out the
4970 revision to a temporary file and call `xcmp' on the two disk
4971 files. xcmp needs to handle non-regular files properly anyway,
4972 so calling it simplifies RCS_cmp_file. We *could* just yank
4973 the delta node out of the version tree and look for device
4974 numbers, but writing to disk and calling xcmp is a better
4975 abstraction (therefore probably more robust). -twp */
4981 tmp = cvs_temp_name();
4982 retcode = RCS_checkout(rcs, NULL, rev, NULL, options, tmp, NULL, NULL);
4986 retcode = xcmp (tmp, filename);
4987 if (CVS_UNLINK (tmp) < 0)
4988 error (0, errno, "cannot remove %s", tmp);
4994 fp = CVS_FOPEN (filename, binary ? FOPEN_BINARY_READ : "r");
4996 data.filename = filename;
5000 retcode = RCS_checkout (rcs, (char *) NULL, rev, (char *) NULL,
5001 options, RUN_TTY, cmp_file_buffer,
5004 /* If we have not yet found a difference, make sure that we are at
5005 the end of the file. */
5006 if (! data.different)
5008 if (getc (fp) != EOF)
5017 return data.different;
5021 /* This is a subroutine of RCS_cmp_file. It is passed to
5024 #define CMP_BUF_SIZE (8 * 1024)
5027 cmp_file_buffer (callerdat, buffer, len)
5032 struct cmp_file_data *data = (struct cmp_file_data *) callerdat;
5035 /* If we've already found a difference, we don't need to check
5037 if (data->different)
5040 filebuf = xmalloc (len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len);
5046 checklen = len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len;
5047 if (fread (filebuf, 1, checklen, data->fp) != checklen)
5049 if (ferror (data->fp))
5050 error (1, errno, "cannot read file %s for comparing",
5052 data->different = 1;
5057 if (memcmp (filebuf, buffer, checklen) != 0)
5059 data->different = 1;
5071 /* For RCS file RCS, make symbolic tag TAG point to revision REV.
5072 This validates that TAG is OK for a user to use. Return value is
5073 -1 for error (and errno is set to indicate the error), positive for
5074 error (and an error message has been printed), or zero for success. */
5077 RCS_settag (rcs, tag, rev)
5085 if (rcs->flags & PARTIAL)
5086 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5088 /* FIXME: This check should be moved to RCS_check_tag. There is no
5089 reason for it to be here. */
5090 if (STREQ (tag, TAG_BASE)
5091 || STREQ (tag, TAG_HEAD))
5093 /* Print the name of the tag might be considered redundant
5094 with the caller, which also prints it. Perhaps this helps
5095 clarify why the tag name is considered reserved, I don't
5097 error (0, 0, "Attempt to add reserved tag name %s", tag);
5101 /* A revision number of NULL means use the head or default branch.
5102 If rev is not NULL, it may be a symbolic tag or branch number;
5103 expand it to the correct numeric revision or branch head. */
5105 rev = rcs->branch ? rcs->branch : rcs->head;
5107 /* At this point rcs->symbol_data may not have been parsed.
5108 Calling RCS_symbols will force it to be parsed into a list
5109 which we can easily manipulate. */
5110 symbols = RCS_symbols (rcs);
5111 if (symbols == NULL)
5113 symbols = getlist ();
5114 rcs->symbols = symbols;
5116 node = findnode (symbols, tag);
5120 node->data = xstrdup (rev);
5125 node->key = xstrdup (tag);
5126 node->data = xstrdup (rev);
5127 (void) addnode_at_front (symbols, node);
5133 /* Delete the symbolic tag TAG from the RCS file RCS. Return 0 if
5134 the tag was found (and removed), or 1 if it was not present. (In
5135 either case, the tag will no longer be in RCS->SYMBOLS.) */
5138 RCS_deltag (rcs, tag)
5144 if (rcs->flags & PARTIAL)
5145 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5147 symbols = RCS_symbols (rcs);
5148 if (symbols == NULL)
5151 node = findnode (symbols, tag);
5160 /* Set the default branch of RCS to REV. */
5163 RCS_setbranch (rcs, rev)
5167 if (rcs->flags & PARTIAL)
5168 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5173 if (rev == NULL && rcs->branch == NULL)
5175 if (rev != NULL && rcs->branch != NULL && STREQ (rev, rcs->branch))
5178 if (rcs->branch != NULL)
5180 rcs->branch = xstrdup (rev);
5185 /* Lock revision REV. LOCK_QUIET is 1 to suppress output. FIXME:
5186 This is only required because the RCS ci program requires a lock.
5187 If we eventually do the checkin ourselves, this can become a no-op. */
5188 /* FIXME-twp: if a lock owned by someone else is broken, should this
5189 send mail to the lock owner? Prompt user? It seems like such an
5190 obscure situation for CVS as almost not worth worrying much
5194 RCS_lock (rcs, rev, lock_quiet)
5204 if (rcs->flags & PARTIAL)
5205 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5207 locks = RCS_getlocks (rcs);
5209 locks = rcs->locks = getlist();
5212 /* A revision number of NULL means lock the head or default branch. */
5214 xrev = RCS_head (rcs);
5216 /* If rev is a branch number, lock the latest revision on that
5217 branch. I think that if the branch doesn't exist, it's
5218 okay to return 0 -- that just means that the branch is new,
5219 so we don't need to lock it anyway. -twp */
5220 else if (RCS_nodeisbranch (rcs, rev))
5222 xrev = RCS_getbranch (rcs, (char *) rev, 1);
5226 error (0, 0, "%s: branch %s absent", rcs->path, rev);
5232 xrev = xstrdup (rev);
5234 /* Make sure that the desired revision exists. Technically,
5235 we can update the locks list without even checking this,
5236 but RCS 5.7 did this. And it can't hurt. */
5237 if (findnode (rcs->versions, xrev) == NULL)
5240 error (0, 0, "%s: revision %s absent", rcs->path, xrev);
5245 /* Is this rev already locked? */
5246 p = findnode (locks, xrev);
5249 if (STREQ (p->data, user))
5251 /* We already own the lock on this revision, so do nothing. */
5256 /* Break the lock. */
5259 cvs_output (rev, 0);
5260 cvs_output (" unlocked\n", 0);
5265 /* Create a new lock. */
5267 p->key = xrev; /* already xstrdupped */
5268 p->data = xstrdup (getcaller());
5269 (void) addnode_at_front (locks, p);
5273 cvs_output (xrev, 0);
5274 cvs_output (" locked\n", 0);
5280 /* Unlock revision REV. UNLOCK_QUIET is 1 to suppress output. FIXME:
5281 Like RCS_lock, this can become a no-op if we do the checkin
5284 If REV is not null and is locked by someone else, break their
5285 lock and notify them. It is an open issue whether RCS_unlock
5286 queries the user about whether or not to break the lock. */
5289 RCS_unlock (rcs, rev, unlock_quiet)
5300 if (rcs->flags & PARTIAL)
5301 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5303 /* If rev is NULL, unlock the latest revision (first in
5304 rcs->locks) held by the caller. */
5309 /* No-ops: attempts to unlock an empty tree or an unlocked file. */
5310 if (rcs->head == NULL)
5313 cvs_outerr ("can't unlock an empty tree\n", 0);
5317 locks = RCS_getlocks (rcs);
5321 cvs_outerr ("No locks are set.\n", 0);
5326 for (p = locks->list->next; p != locks->list; p = p->next)
5328 if (STREQ (p->data, user))
5334 %s: multiple revisions locked by %s; please specify one", rcs->path, user);
5341 return 0; /* no lock found, ergo nothing to do */
5342 xrev = xstrdup (lock->key);
5344 else if (RCS_nodeisbranch (rcs, rev))
5346 /* If rev is a branch number, unlock the latest revision on that
5348 xrev = RCS_getbranch (rcs, (char *) rev, 1);
5351 error (0, 0, "%s: branch %s absent", rcs->path, rev);
5356 /* REV is an exact revision number. */
5357 xrev = xstrdup (rev);
5359 lock = findnode (RCS_getlocks (rcs), xrev);
5362 /* This revision isn't locked. */
5367 if (! STREQ (lock->data, user))
5369 /* If the revision is locked by someone else, notify
5370 them. Note that this shouldn't ever happen if RCS_unlock
5371 is called with a NULL revision, since that means "whatever
5372 revision is currently locked by the caller." */
5373 char *repos, *workfile;
5374 repos = xstrdup (rcs->path);
5375 workfile = strrchr (repos, '/');
5377 notify_do ('C', workfile, user, NULL, NULL, repos);
5384 cvs_output (xrev, 0);
5385 cvs_output (" unlocked\n", 0);
5392 /* Add USER to the access list of RCS. Do nothing if already present.
5393 FIXME-twp: check syntax of USER to make sure it's a valid id. */
5396 RCS_addaccess (rcs, user)
5402 if (rcs->flags & PARTIAL)
5403 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5405 if (rcs->access == NULL)
5406 rcs->access = xstrdup (user);
5409 access = xstrdup (rcs->access);
5410 for (a = strtok (access, " "); a != NULL; a = strtok (NULL, " "))
5412 if (STREQ (a, user))
5418 rcs->access = (char *) xrealloc
5419 (rcs->access, strlen (rcs->access) + strlen (user) + 2);
5420 strcat (rcs->access, " ");
5421 strcat (rcs->access, user);
5425 /* Remove USER from the access list of RCS. */
5428 RCS_delaccess (rcs, user)
5435 if (rcs->flags & PARTIAL)
5436 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5438 if (rcs->access == NULL)
5442 ulen = strlen (user);
5445 if (p[ulen] == '\0' || p[ulen] == ' ')
5446 if (strncmp (p, user, ulen) == 0)
5448 p = strchr (p, ' ');
5466 if (rcs->flags & PARTIAL)
5467 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5472 static int findtag PROTO ((Node *, void *));
5474 /* Return a nonzero value if the revision specified by ARG is found. */
5481 char *rev = (char *)arg;
5483 if (STREQ (node->data, rev))
5489 /* Delete revisions between REV1 and REV2. The changes between the two
5490 revisions must be collapsed, and the result stored in the revision
5491 immediately preceding the lower one. Return 0 for successful completion,
5494 Solution: check out the revision preceding REV1 and the revision
5495 following REV2. Use call_diff to find aggregate diffs between
5496 these two revisions, and replace the delta text for the latter one
5497 with the new aggregate diff. Alternatively, we could write a
5498 function that takes two change texts and combines them to produce a
5499 new change text, without checking out any revs or calling diff. It
5500 would be hairy, but so, so cool.
5502 If INCLUSIVE is set, then TAG1 and TAG2, if non-NULL, tell us to
5503 delete that revision as well (cvs admin -o tag1:tag2). If clear,
5504 delete up to but not including that revision (cvs admin -o tag1::tag2).
5505 This does not affect TAG1 or TAG2 being NULL; the meaning of the start
5506 point in ::tag2 and :tag2 is the same and likewise for end points. */
5509 RCS_delete_revs (rcs, tag1, tag2, inclusive)
5517 RCSVers *revp = NULL;
5522 char *branchpoint = NULL;
5525 int rev1_inclusive = inclusive;
5526 int rev2_inclusive = inclusive;
5527 char *before = NULL;
5529 char *beforefile = NULL;
5530 char *afterfile = NULL;
5531 char *outfile = NULL;
5533 if (tag1 == NULL && tag2 == NULL)
5536 /* Assume error status until everything is finished. */
5539 /* Make sure both revisions exist. */
5542 rev1 = RCS_gettag (rcs, tag1, 1, NULL);
5543 if (rev1 == NULL || (nodep = findnode (rcs->versions, rev1)) == NULL)
5545 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag1);
5551 rev2 = RCS_gettag (rcs, tag2, 1, NULL);
5552 if (rev2 == NULL || (nodep = findnode (rcs->versions, rev2)) == NULL)
5554 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag2);
5559 /* If rev1 is on the trunk and rev2 is NULL, rev2 should be
5560 RCS->HEAD. (*Not* RCS_head(rcs), which may return rcs->branch
5561 instead.) We need to check this special case early, in order
5562 to make sure that rev1 and rev2 get ordered correctly. */
5563 if (rev2 == NULL && numdots (rev1) == 1)
5565 rev2 = xstrdup (rcs->head);
5572 if (rev1 != NULL && rev2 != NULL)
5574 /* A range consisting of a branch number means the latest revision
5576 if (RCS_isbranch (rcs, rev1) && STREQ (rev1, rev2))
5577 rev1 = rev2 = RCS_getbranch (rcs, rev1, 0);
5580 /* Make sure REV1 and REV2 are ordered correctly (in the
5581 same order as the next field). For revisions on the
5582 trunk, REV1 should be higher than REV2; for branches,
5583 REV1 should be lower. */
5584 /* Shouldn't we just be giving an error in the case where
5585 the user specifies the revisions in the wrong order
5586 (that is, always swap on the trunk, never swap on a
5587 branch, in the non-error cases)? It is not at all
5588 clear to me that users who specify -o 1.4:1.2 really
5589 meant to type -o 1.2:1.4, and the out of order usage
5590 has never been documented, either by cvs.texinfo or
5594 if (numdots (rev1) == 1)
5596 if (compare_revnums (rev1, rev2) <= 0)
5602 temp_inclusive = rev2_inclusive;
5603 rev2_inclusive = rev1_inclusive;
5604 rev1_inclusive = temp_inclusive;
5607 else if (compare_revnums (rev1, rev2) > 0)
5613 temp_inclusive = rev2_inclusive;
5614 rev2_inclusive = rev1_inclusive;
5615 rev1_inclusive = temp_inclusive;
5620 /* Basically the same thing; make sure that the ordering is what we
5624 assert (rev2 != NULL);
5625 if (numdots (rev2) == 1)
5627 /* Swap rev1 and rev2. */
5633 temp_inclusive = rev2_inclusive;
5634 rev2_inclusive = rev1_inclusive;
5635 rev1_inclusive = temp_inclusive;
5639 /* Put the revision number preceding the first one to delete into
5640 BEFORE (where "preceding" means according to the next field).
5641 If the first revision to delete is the first revision on its
5642 branch (e.g. 1.3.2.1), BEFORE should be the node on the trunk
5643 at which the branch is rooted. If the first revision to delete
5644 is the head revision of the trunk, set BEFORE to NULL.
5646 Note that because BEFORE may not be on the same branch as REV1,
5647 it is not very handy for navigating the revision tree. It's
5648 most useful just for checking out the revision preceding REV1. */
5650 branchpoint = RCS_getbranchpoint (rcs, rev1 != NULL ? rev1 : rev2);
5653 rev1 = xstrdup (branchpoint);
5654 if (numdots (branchpoint) > 1)
5657 bp = strrchr (branchpoint, '.');
5658 while (*--bp != '.')
5661 /* Note that this is exclusive, always, because the inclusive
5662 flag doesn't affect the meaning when rev1 == NULL. */
5663 before = xstrdup (branchpoint);
5667 else if (! STREQ (rev1, branchpoint))
5669 /* Walk deltas from BRANCHPOINT on, looking for REV1. */
5670 nodep = findnode (rcs->versions, branchpoint);
5671 revp = (RCSVers *) nodep->data;
5672 while (revp->next != NULL && ! STREQ (revp->next, rev1))
5674 revp = (RCSVers *) nodep->data;
5675 nodep = findnode (rcs->versions, revp->next);
5677 if (revp->next == NULL)
5679 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, rev1);
5683 before = xstrdup (revp->version);
5687 nodep = findnode (rcs->versions, before);
5688 rev1 = xstrdup (((RCSVers *)nodep->data)->next);
5691 else if (!rev1_inclusive)
5694 nodep = findnode (rcs->versions, before);
5695 rev1 = xstrdup (((RCSVers *)nodep->data)->next);
5697 else if (numdots (branchpoint) > 1)
5699 /* Example: rev1 is "1.3.2.1", branchpoint is "1.3.2.1".
5700 Set before to "1.3". */
5702 bp = strrchr (branchpoint, '.');
5703 while (*--bp != '.')
5706 before = xstrdup (branchpoint);
5710 /* If any revision between REV1 and REV2 is locked or is a branch point,
5711 we can't delete that revision and must abort. */
5715 while (!found && next != NULL)
5717 nodep = findnode (rcs->versions, next);
5718 revp = (RCSVers *) nodep->data;
5721 found = STREQ (revp->version, rev2);
5724 if ((!found && next != NULL) || rev2_inclusive || rev2 == NULL)
5726 if (findnode (RCS_getlocks (rcs), revp->version))
5728 error (0, 0, "%s: can't remove locked revision %s",
5733 if (revp->branches != NULL)
5735 error (0, 0, "%s: can't remove branch point %s",
5741 /* Doing this only for the :: syntax is for compatibility.
5742 See cvs.texinfo for somewhat more discussion. */
5744 && walklist (RCS_symbols (rcs), findtag, revp->version))
5746 /* We don't print which file this happens to on the theory
5747 that the caller will print the name of the file in a
5748 more useful fashion (fullname not rcs->path). */
5749 error (0, 0, "cannot remove revision %s because it has tags",
5754 /* It's misleading to print the `deleting revision' output
5755 here, since we may not actually delete these revisions.
5756 But that's how RCS does it. Bleah. Someday this should be
5757 moved to the point where the revs are actually marked for
5759 cvs_output ("deleting revision ", 0);
5760 cvs_output (revp->version, 0);
5761 cvs_output ("\n", 1);
5770 after = xstrdup (next);
5772 after = xstrdup (revp->version);
5774 else if (!inclusive)
5776 /* In the case of an empty range, for example 1.2::1.2 or
5777 1.2::1.3, we want to just do nothing. */
5783 /* This looks fishy in the cases where tag1 == NULL or tag2 == NULL.
5784 Are those cases really impossible? */
5785 assert (tag1 != NULL);
5786 assert (tag2 != NULL);
5788 error (0, 0, "%s: invalid revision range %s:%s", rcs->path,
5793 /* The conditionals at this point get really hairy. Here is the
5796 IF before != NULL and after == NULL
5797 THEN don't check out any revisions, just delete them
5798 IF before == NULL and after != NULL
5799 THEN only check out after's revision, and use it for the new deltatext
5801 check out both revisions and diff -n them. This could use
5802 RCS_exec_rcsdiff with some changes, like being able
5803 to suppress diagnostic messages and to direct output. */
5805 assert (before != NULL || after != NULL);
5810 size_t bufsize, len;
5812 afterfile = cvs_temp_name();
5813 status = RCS_checkout (rcs, NULL, after, NULL, NULL, afterfile,
5814 (RCSCHECKOUTPROC)0, NULL);
5820 /* We are deleting revisions from the head of the tree,
5821 so must create a new head. */
5824 get_file (afterfile, afterfile, "r", &diffbuf, &bufsize, &len);
5826 save_noexec = noexec;
5828 if (unlink_file (afterfile) < 0)
5829 error (0, errno, "cannot remove %s", afterfile);
5830 noexec = save_noexec;
5836 rcs->head = xstrdup (after);
5840 beforefile = cvs_temp_name();
5841 status = RCS_checkout (rcs, NULL, before, NULL, NULL, beforefile,
5842 (RCSCHECKOUTPROC)0, NULL);
5846 outfile = cvs_temp_name();
5847 status = diff_exec (beforefile, afterfile, "-n", outfile);
5851 /* Not sure we need this message; will diff_exec already
5852 have printed an error? */
5853 error (0, 0, "%s: could not diff", rcs->path);
5860 get_file (outfile, outfile, "r", &diffbuf, &bufsize, &len);
5863 /* Save the new change text in after's delta node. */
5864 nodep = findnode (rcs->versions, after);
5865 revp = (RCSVers *) nodep->data;
5867 assert (revp->text == NULL);
5869 revp->text = (Deltatext *) xmalloc (sizeof (Deltatext));
5870 memset ((Deltatext *) revp->text, 0, sizeof (Deltatext));
5871 revp->text->version = xstrdup (revp->version);
5872 revp->text->text = diffbuf;
5873 revp->text->len = len;
5875 /* If DIFFBUF is NULL, it means that OUTFILE is empty and that
5876 there are no differences between the two revisions. In that
5877 case, we want to force RCS_copydeltas to write an empty string
5878 for the new change text (leaving the text field set NULL
5879 means "preserve the original change text for this delta," so
5880 we don't want that). */
5881 if (revp->text->text == NULL)
5882 revp->text->text = xstrdup ("");
5885 /* Walk through the revisions (again) to mark each one as
5886 outdated. (FIXME: would it be safe to use the `dead' field for
5889 next != NULL && (after == NULL || ! STREQ (next, after));
5892 nodep = findnode (rcs->versions, next);
5893 revp = (RCSVers *) nodep->data;
5897 /* Update delta links. If BEFORE == NULL, we're changing the
5898 head of the tree and don't need to update any `next' links. */
5901 /* If REV1 is the first node on its branch, then BEFORE is its
5902 root node (on the trunk) and we have to update its branches
5903 list. Otherwise, BEFORE is on the same branch as AFTER, and
5904 we can just change BEFORE's `next' field to point to AFTER.
5905 (This should be safe: since findnode manages its lists via
5906 the `hashnext' and `hashprev' fields, rather than `next' and
5907 `prev', mucking with `next' and `prev' should not corrupt the
5908 delta tree's internal structure. Much. -twp) */
5911 /* beforep's ->next field already should be equal to after,
5912 which I think is always NULL in this case. */
5914 else if (STREQ (rev1, branchpoint))
5916 nodep = findnode (rcs->versions, before);
5917 revp = (RCSVers *) nodep->data;
5918 nodep = revp->branches->list->next;
5919 while (nodep != revp->branches->list &&
5920 ! STREQ (nodep->key, rev1))
5921 nodep = nodep->next;
5922 assert (nodep != revp->branches->list);
5928 nodep->key = xstrdup (after);
5933 nodep = findnode (rcs->versions, before);
5934 beforep = (RCSVers *) nodep->data;
5935 free (beforep->next);
5936 beforep->next = xstrdup (after);
5947 if (branchpoint != NULL)
5954 save_noexec = noexec;
5956 if (beforefile != NULL)
5958 if (unlink_file (beforefile) < 0)
5959 error (0, errno, "cannot remove %s", beforefile);
5962 if (afterfile != NULL)
5964 if (unlink_file (afterfile) < 0)
5965 error (0, errno, "cannot remove %s", afterfile);
5968 if (outfile != NULL)
5970 if (unlink_file (outfile) < 0)
5971 error (0, errno, "cannot remove %s", outfile);
5974 noexec = save_noexec;
5979 /* RCS_deltas and friends. Processing of the deltas in RCS files. */
5983 /* Text of this line. Part of the same malloc'd block as the struct
5984 line itself (we probably should use the "struct hack" (char text[1])
5985 and save ourselves sizeof (char *) bytes). Does not include \n;
5986 instead has_newline indicates the presence or absence of \n. */
5988 /* Length of this line, not counting \n if has_newline is true. */
5990 /* Version in which it was introduced. */
5992 /* Nonzero if this line ends with \n. This will always be true
5993 except possibly for the last line. */
5995 /* Number of pointers to this struct line. */
6001 /* How many lines in use for this linevector? */
6002 unsigned int nlines;
6003 /* How many lines allocated for this linevector? */
6004 unsigned int lines_alloced;
6005 /* Pointer to array containing a pointer to each line. */
6006 struct line **vector;
6009 static void linevector_init PROTO ((struct linevector *));
6011 /* Initialize *VEC to be a linevector with no lines. */
6013 linevector_init (vec)
6014 struct linevector *vec;
6016 vec->lines_alloced = 0;
6021 static int linevector_add PROTO ((struct linevector *vec, const char *text,
6022 size_t len, RCSVers *vers,
6025 /* Given some text TEXT, add each of its lines to VEC before line POS
6026 (where line 0 is the first line). The last line in TEXT may or may
6027 not be \n terminated.
6028 Set the version for each of the new lines to VERS. This
6029 function returns non-zero for success. It returns zero if the line
6030 number is out of range.
6032 Each of the lines in TEXT are copied to space which is managed with
6033 the linevector (and freed by linevector_free). So the caller doesn't
6034 need to keep TEXT around after the call to this function. */
6036 linevector_add (vec, text, len, vers, pos)
6037 struct linevector *vec;
6043 const char *textend;
6047 const char *nextline_text;
6048 size_t nextline_len;
6049 int nextline_newline;
6055 textend = text + len;
6057 /* Count the number of lines we will need to add. */
6059 for (p = text; p < textend; ++p)
6060 if (*p == '\n' && p + 1 < textend)
6063 /* Expand VEC->VECTOR if needed. */
6064 if (vec->nlines + nnew >= vec->lines_alloced)
6066 if (vec->lines_alloced == 0)
6067 vec->lines_alloced = 10;
6068 while (vec->nlines + nnew >= vec->lines_alloced)
6069 vec->lines_alloced *= 2;
6070 vec->vector = xrealloc (vec->vector,
6071 vec->lines_alloced * sizeof (*vec->vector));
6074 /* Make room for the new lines in VEC->VECTOR. */
6075 for (i = vec->nlines + nnew - 1; i >= pos + nnew; --i)
6076 vec->vector[i] = vec->vector[i - nnew];
6078 if (pos > vec->nlines)
6081 /* Actually add the lines, to VEC->VECTOR. */
6083 nextline_text = text;
6084 nextline_newline = 0;
6085 for (p = text; p < textend; ++p)
6088 nextline_newline = 1;
6089 if (p + 1 == textend)
6090 /* If there are no characters beyond the last newline, we
6091 don't consider it another line. */
6093 nextline_len = p - nextline_text;
6094 q = (struct line *) xmalloc (sizeof (struct line) + nextline_len);
6096 q->text = (char *)q + sizeof (struct line);
6097 q->len = nextline_len;
6098 q->has_newline = nextline_newline;
6100 memcpy (q->text, nextline_text, nextline_len);
6101 vec->vector[i++] = q;
6103 nextline_text = (char *)p + 1;
6104 nextline_newline = 0;
6106 nextline_len = p - nextline_text;
6107 q = (struct line *) xmalloc (sizeof (struct line) + nextline_len);
6109 q->text = (char *)q + sizeof (struct line);
6110 q->len = nextline_len;
6111 q->has_newline = nextline_newline;
6113 memcpy (q->text, nextline_text, nextline_len);
6116 vec->nlines += nnew;
6121 static void linevector_delete PROTO ((struct linevector *, unsigned int,
6124 /* Remove NLINES lines from VEC at position POS (where line 0 is the
6127 linevector_delete (vec, pos, nlines)
6128 struct linevector *vec;
6130 unsigned int nlines;
6135 last = vec->nlines - nlines;
6136 for (i = pos; i < pos + nlines; ++i)
6138 if (--vec->vector[i]->refcount == 0)
6139 free (vec->vector[i]);
6141 for (i = pos; i < last; ++i)
6142 vec->vector[i] = vec->vector[i + nlines];
6143 vec->nlines -= nlines;
6146 static void linevector_copy PROTO ((struct linevector *, struct linevector *));
6148 /* Copy FROM to TO, copying the vectors but not the lines pointed to. */
6150 linevector_copy (to, from)
6151 struct linevector *to;
6152 struct linevector *from;
6156 for (ln = 0; ln < to->nlines; ++ln)
6158 if (--to->vector[ln]->refcount == 0)
6159 free (to->vector[ln]);
6161 if (from->nlines > to->lines_alloced)
6163 if (to->lines_alloced == 0)
6164 to->lines_alloced = 10;
6165 while (from->nlines > to->lines_alloced)
6166 to->lines_alloced *= 2;
6167 to->vector = (struct line **)
6168 xrealloc (to->vector, to->lines_alloced * sizeof (*to->vector));
6170 memcpy (to->vector, from->vector,
6171 from->nlines * sizeof (*to->vector));
6172 to->nlines = from->nlines;
6173 for (ln = 0; ln < to->nlines; ++ln)
6174 ++to->vector[ln]->refcount;
6177 static void linevector_free PROTO ((struct linevector *));
6179 /* Free storage associated with linevector. */
6181 linevector_free (vec)
6182 struct linevector *vec;
6186 if (vec->vector != NULL)
6188 for (ln = 0; ln < vec->nlines; ++ln)
6189 if (--vec->vector[ln]->refcount == 0)
6190 free (vec->vector[ln]);
6196 static char *month_printname PROTO ((char *));
6198 /* Given a textual string giving the month (1-12), terminated with any
6199 character not recognized by atoi, return the 3 character name to
6200 print it with. I do not think it is a good idea to change these
6201 strings based on the locale; they are standard abbreviations (for
6202 example in rfc822 mail messages) which should be widely understood.
6203 Returns a pointer into static readonly storage. */
6205 month_printname (month)
6208 static const char *const months[] =
6209 {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
6210 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
6213 mnum = atoi (month);
6214 if (mnum < 1 || mnum > 12)
6216 return (char *)months[mnum - 1];
6220 apply_rcs_changes PROTO ((struct linevector *, const char *, size_t,
6221 const char *, RCSVers *, RCSVers *));
6223 /* Apply changes to the line vector LINES. DIFFBUF is a buffer of
6224 length DIFFLEN holding the change text from an RCS file (the output
6225 of diff -n). NAME is used in error messages. The VERS field of
6226 any line added is set to ADDVERS. The VERS field of any line
6227 deleted is set to DELVERS, unless DELVERS is NULL, in which case
6228 the VERS field of deleted lines is unchanged. The function returns
6229 non-zero if the change text is applied successfully. It returns
6230 zero if the change text does not appear to apply to LINES (e.g., a
6231 line number is invalid). If the change text is improperly
6232 formatted (e.g., it is not the output of diff -n), the function
6233 calls error with a status of 1, causing the program to exit. */
6236 apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
6237 struct linevector *lines;
6238 const char *diffbuf;
6247 /* The RCS format throws us for a loop in that the deltafrags (if
6248 we define a deltafrag as an add or a delete) need to be applied
6249 in reverse order. So we stick them into a linked list. */
6251 enum {ADD, DELETE} type;
6253 unsigned long nlines;
6254 const char *new_lines;
6256 struct deltafrag *next;
6258 struct deltafrag *dfhead;
6259 struct deltafrag *df;
6262 for (p = diffbuf; p != NULL && p < diffbuf + difflen; )
6265 if (op != 'a' && op != 'd')
6266 /* Can't just skip over the deltafrag, because the value
6267 of op determines the syntax. */
6268 error (1, 0, "unrecognized operation '%c' in %s", op, name);
6269 df = (struct deltafrag *) xmalloc (sizeof (struct deltafrag));
6272 df->pos = strtoul (p, (char **) &q, 10);
6275 error (1, 0, "number expected in %s", name);
6278 error (1, 0, "space expected in %s", name);
6279 df->nlines = strtoul (p, (char **) &q, 10);
6281 error (1, 0, "number expected in %s", name);
6284 error (1, 0, "linefeed expected in %s", name);
6292 /* The text we want is the number of lines specified, or
6293 until the end of the value, whichever comes first (it
6294 will be the former except in the case where we are
6295 adding a line which does not end in newline). */
6296 for (q = p; i != 0; ++q)
6299 else if (q == diffbuf + difflen)
6302 error (1, 0, "premature end of change in %s", name);
6307 /* Stash away a pointer to the text we are adding. */
6315 /* Correct for the fact that line numbers in RCS files
6324 for (df = dfhead; df != NULL;)
6331 if (! linevector_add (lines, df->new_lines, df->len, addvers,
6336 if (df->pos > lines->nlines
6337 || df->pos + df->nlines > lines->nlines)
6339 if (delvers != NULL)
6340 for (ln = df->pos; ln < df->pos + df->nlines; ++ln)
6341 lines->vector[ln]->vers = delvers;
6342 linevector_delete (lines, df->pos, df->nlines);
6353 /* Apply an RCS change text to a buffer. The function name starts
6354 with rcs rather than RCS because this does not take an RCSNode
6355 argument. NAME is used in error messages. TEXTBUF is the text
6356 buffer to change, and TEXTLEN is the size. DIFFBUF and DIFFLEN are
6357 the change buffer and size. The new buffer is returned in *RETBUF
6358 and *RETLEN. The new buffer is allocated by xmalloc.
6360 Return 1 for success. On failure, call error and return 0. */
6363 rcs_change_text (name, textbuf, textlen, diffbuf, difflen, retbuf, retlen)
6367 const char *diffbuf;
6372 struct linevector lines;
6378 linevector_init (&lines);
6380 if (! linevector_add (&lines, textbuf, textlen, NULL, 0))
6381 error (1, 0, "cannot initialize line vector");
6383 if (! apply_rcs_changes (&lines, diffbuf, difflen, name, NULL, NULL))
6385 error (0, 0, "invalid change text in %s", name);
6395 for (ln = 0; ln < lines.nlines; ++ln)
6397 n += lines.vector[ln]->len + 1;
6402 for (ln = 0; ln < lines.nlines; ++ln)
6404 memcpy (p, lines.vector[ln]->text, lines.vector[ln]->len);
6405 p += lines.vector[ln]->len;
6406 if (lines.vector[ln]->has_newline)
6410 *retlen = p - *retbuf;
6411 assert (*retlen <= n);
6416 linevector_free (&lines);
6421 /* Walk the deltas in RCS to get to revision VERSION.
6423 If OP is RCS_ANNOTATE, then write annotations using cvs_output.
6425 If OP is RCS_FETCH, then put the contents of VERSION into a
6426 newly-malloc'd array and put a pointer to it in *TEXT. Each line
6427 is \n terminated; the caller is responsible for converting text
6428 files if desired. The total length is put in *LEN.
6430 If FP is non-NULL, it should be a file descriptor open to the file
6431 RCS with file position pointing to the deltas. We close the file
6434 If LOG is non-NULL, then *LOG is set to the log message of VERSION,
6435 and *LOGLEN is set to the length of the log message.
6437 On error, give a fatal error. */
6440 RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
6443 struct rcsbuffer *rcsbuf;
6445 enum rcs_delta_op op;
6451 struct rcsbuffer rcsbuf_local;
6452 char *branchversion;
6459 RCSVers *trunk_vers;
6461 int ishead, isnext, isversion, onbranch;
6463 struct linevector headlines;
6464 struct linevector curlines;
6465 struct linevector trunklines;
6470 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf_local);
6471 rcsbuf = &rcsbuf_local;
6482 linevector_init (&curlines);
6483 linevector_init (&headlines);
6484 linevector_init (&trunklines);
6486 /* We set BRANCHVERSION to the version we are currently looking
6487 for. Initially, this is the version on the trunk from which
6488 VERSION branches off. If VERSION is not a branch, then
6489 BRANCHVERSION is just VERSION. */
6490 branchversion = xstrdup (version);
6491 cpversion = strchr (branchversion, '.');
6492 if (cpversion != NULL)
6493 cpversion = strchr (cpversion + 1, '.');
6494 if (cpversion != NULL)
6498 if (! rcsbuf_getrevnum (rcsbuf, &key))
6499 error (1, 0, "unexpected EOF reading RCS file %s", rcs->path);
6501 if (next != NULL && ! STREQ (next, key))
6503 /* This is not the next version we need. It is a branch
6504 version which we want to ignore. */
6512 /* look up the revision */
6513 node = findnode (rcs->versions, key);
6516 "mismatch in rcs file %s between deltas and deltatexts",
6519 /* Stash the previous version. */
6522 vers = (RCSVers *) node->data;
6525 /* Compare key and trunkversion now, because key points to
6526 storage controlled by rcsbuf_getkey. */
6527 if (STREQ (branchversion, key))
6535 if (! rcsbuf_getkey (rcsbuf, &key, &value))
6536 error (1, 0, "%s does not appear to be a valid rcs file",
6541 && STREQ (key, "log")
6542 && STREQ (branchversion, version))
6544 *log = rcsbuf_valcopy (rcsbuf, value, 0, loglen);
6547 if (STREQ (key, "text"))
6549 rcsbuf_valpolish (rcsbuf, value, 0, &vallen);
6552 if (! linevector_add (&curlines, value, vallen, NULL, 0))
6553 error (1, 0, "invalid rcs file %s", rcs->path);
6559 if (! apply_rcs_changes (&curlines, value, vallen,
6561 onbranch ? vers : NULL,
6562 onbranch ? NULL : prev_vers))
6563 error (1, 0, "invalid change text in %s", rcs->path);
6571 /* This is either the version we want, or it is the
6572 branchpoint to the version we want. */
6573 if (STREQ (branchversion, version))
6575 /* This is the version we want. */
6576 linevector_copy (&headlines, &curlines);
6580 /* We have found this version by tracking up a
6581 branch. Restore back to the lines we saved
6582 when we left the trunk, and continue tracking
6587 linevector_copy (&curlines, &trunklines);
6594 /* We need to look up the branch. */
6597 if (numdots (branchversion) < 2)
6601 /* We are leaving the trunk; save the current
6602 lines so that we can restore them when we
6603 continue tracking down the trunk. */
6605 linevector_copy (&trunklines, &curlines);
6607 /* Reset the version information we have
6608 accumulated so far. It only applies to the
6609 changes from the head to this version. */
6610 for (ln = 0; ln < curlines.nlines; ++ln)
6611 curlines.vector[ln]->vers = NULL;
6614 /* The next version we want is the entry on
6615 VERS->branches which matches this branch. For
6616 example, suppose VERSION is 1.21.4.3 and
6617 BRANCHVERSION was 1.21. Then we look for an entry
6618 starting with "1.21.4" and we'll put it (probably
6619 1.21.4.1) in NEXT. We'll advance BRANCHVERSION by
6620 two dots (in this example, to 1.21.4.3). */
6622 if (vers->branches == NULL)
6623 error (1, 0, "missing expected branches in %s",
6627 cpversion = strchr (cpversion, '.');
6628 if (cpversion == NULL)
6629 error (1, 0, "version number confusion in %s",
6631 for (p = vers->branches->list->next;
6632 p != vers->branches->list;
6634 if (strncmp (p->key, branchversion,
6635 cpversion - branchversion) == 0)
6637 if (p == vers->branches->list)
6638 error (1, 0, "missing expected branch in %s",
6643 cpversion = strchr (cpversion + 1, '.');
6644 if (cpversion != NULL)
6648 if (op == RCS_FETCH && foundhead)
6650 } while (next != NULL);
6652 free (branchversion);
6654 rcsbuf_cache (rcs, rcsbuf);
6657 error (1, 0, "could not find desired version %s in %s",
6658 version, rcs->path);
6660 /* Now print out or return the data we have just computed. */
6667 for (ln = 0; ln < headlines.nlines; ++ln)
6670 /* Period which separates year from month in date. */
6672 /* Period which separates month from day in date. */
6676 prvers = headlines.vector[ln]->vers;
6680 sprintf (buf, "%-12s (%-8.8s ",
6683 cvs_output (buf, 0);
6685 /* Now output the date. */
6686 ym = strchr (prvers->date, '.');
6689 /* ??- is an ANSI trigraph. The ANSI way to
6690 avoid it is \? but some pre ANSI compilers
6691 complain about the unrecognized escape
6692 sequence. Of course string concatenation
6693 ("??" "-???") is also an ANSI-ism. Testing
6694 __STDC__ seems to be a can of worms, since
6695 compilers do all kinds of things with it. */
6696 cvs_output ("??", 0);
6697 cvs_output ("-???", 0);
6698 cvs_output ("-??", 0);
6702 md = strchr (ym + 1, '.');
6704 cvs_output ("??", 0);
6706 cvs_output (md + 1, 2);
6708 cvs_output ("-", 1);
6709 cvs_output (month_printname (ym + 1), 0);
6710 cvs_output ("-", 1);
6711 /* Only output the last two digits of the year. Our output
6712 lines are long enough as it is without printing the
6714 cvs_output (ym - 2, 2);
6716 cvs_output ("): ", 0);
6717 if (headlines.vector[ln]->len != 0)
6718 cvs_output (headlines.vector[ln]->text,
6719 headlines.vector[ln]->len);
6720 cvs_output ("\n", 1);
6730 assert (text != NULL);
6731 assert (len != NULL);
6734 for (ln = 0; ln < headlines.nlines; ++ln)
6736 n += headlines.vector[ln]->len + 1;
6739 for (ln = 0; ln < headlines.nlines; ++ln)
6741 memcpy (p, headlines.vector[ln]->text,
6742 headlines.vector[ln]->len);
6743 p += headlines.vector[ln]->len;
6744 if (headlines.vector[ln]->has_newline)
6753 linevector_free (&curlines);
6754 linevector_free (&headlines);
6755 linevector_free (&trunklines);
6760 /* Read the information for a single delta from the RCS buffer RCSBUF,
6761 whose name is RCSFILE. *KEYP and *VALP are either NULL, or the
6762 first key/value pair to read, as set by rcsbuf_getkey. Return NULL
6763 if there are no more deltas. Store the key/value pair which
6764 terminated the read in *KEYP and *VALP. */
6767 getdelta (rcsbuf, rcsfile, keyp, valp)
6768 struct rcsbuffer *rcsbuf;
6774 char *key, *value, *cp;
6777 /* Get revision number if it wasn't passed in. This uses
6778 rcsbuf_getkey because it doesn't croak when encountering
6779 unexpected input. As a result, we have to play unholy games
6780 with `key' and `value'. */
6788 if (! rcsbuf_getkey (rcsbuf, &key, &value))
6789 error (1, 0, "%s: unexpected EOF", rcsfile);
6792 /* Make sure that it is a revision number and not a cabbage
6794 for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
6796 /* Note that when comparing with RCSDATE, we are not massaging
6797 VALUE from the string found in the RCS file. This is OK since
6798 we know exactly what to expect. */
6799 if (*cp != '\0' || strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) != 0)
6806 vnode = (RCSVers *) xmalloc (sizeof (RCSVers));
6807 memset (vnode, 0, sizeof (RCSVers));
6809 vnode->version = xstrdup (key);
6811 /* Grab the value of the date from value. Note that we are not
6812 massaging VALUE from the string found in the RCS file. */
6813 cp = value + (sizeof RCSDATE) - 1; /* skip the "date" keyword */
6814 while (whitespace (*cp)) /* take space off front of value */
6817 vnode->date = xstrdup (cp);
6819 /* Get author field. */
6820 if (! rcsbuf_getkey (rcsbuf, &key, &value))
6822 error (1, 0, "unexpected end of file reading %s", rcsfile);
6824 if (! STREQ (key, "author"))
6826 unable to parse %s; `author' not in the expected place", rcsfile);
6827 vnode->author = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
6829 /* Get state field. */
6830 if (! rcsbuf_getkey (rcsbuf, &key, &value))
6832 error (1, 0, "unexpected end of file reading %s", rcsfile);
6834 if (! STREQ (key, "state"))
6836 unable to parse %s; `state' not in the expected place", rcsfile);
6837 vnode->state = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
6838 if (STREQ (value, "dead"))
6843 /* Note that "branches" and "next" are in fact mandatory, according
6846 /* fill in the branch list (if any branches exist) */
6847 if (! rcsbuf_getkey (rcsbuf, &key, &value))
6849 error (1, 0, "unexpected end of file reading %s", rcsfile);
6851 if (STREQ (key, RCSDESC))
6855 /* Probably could/should be a fatal error. */
6856 error (0, 0, "warning: 'branches' keyword missing from %s", rcsfile);
6859 if (value != (char *) NULL)
6861 vnode->branches = getlist ();
6862 /* Note that we are not massaging VALUE from the string found
6864 do_branches (vnode->branches, value);
6867 /* fill in the next field if there is a next revision */
6868 if (! rcsbuf_getkey (rcsbuf, &key, &value))
6870 error (1, 0, "unexpected end of file reading %s", rcsfile);
6872 if (STREQ (key, RCSDESC))
6876 /* Probably could/should be a fatal error. */
6877 error (0, 0, "warning: 'next' keyword missing from %s", rcsfile);
6880 if (value != (char *) NULL)
6881 vnode->next = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
6884 * XXX - this is where we put the symbolic link stuff???
6885 * (into newphrases in the deltas).
6889 if (! rcsbuf_getkey (rcsbuf, &key, &value))
6890 error (1, 0, "unexpected end of file reading %s", rcsfile);
6892 if (STREQ (key, RCSDESC))
6895 /* Enable use of repositories created by certain obsolete
6896 versions of CVS. This code should remain indefinately;
6897 there is no procedure for converting old repositories, and
6898 checking for it is harmless. */
6899 if (STREQ (key, RCSDEAD))
6902 if (vnode->state != NULL)
6903 free (vnode->state);
6904 vnode->state = xstrdup ("dead");
6907 /* if we have a new revision number, we're done with this delta */
6908 for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
6910 /* Note that when comparing with RCSDATE, we are not massaging
6911 VALUE from the string found in the RCS file. This is OK
6912 since we know exactly what to expect. */
6913 if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0)
6916 /* At this point, key and value represent a user-defined field
6917 in the delta node. */
6918 if (vnode->other_delta == NULL)
6919 vnode->other_delta = getlist ();
6921 kv->type = RCSFIELD;
6922 kv->key = xstrdup (key);
6923 kv->data = rcsbuf_valcopy (rcsbuf, value, 1, (size_t *) NULL);
6924 if (addnode (vnode->other_delta, kv) != 0)
6926 /* Complaining about duplicate keys in newphrases seems
6927 questionable, in that we don't know what they mean and
6928 doc/RCSFILES has no prohibition on several newphrases
6929 with the same key. But we can't store more than one as
6930 long as we store them in a List *. */
6931 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
6937 /* Return the key which caused us to fail back to the caller. */
6948 if (d->version != NULL)
6952 if (d->text != NULL)
6954 if (d->other != (List *) NULL)
6955 dellist (&d->other);
6960 RCS_getdeltatext (rcs, fp, rcsbuf)
6963 struct rcsbuffer *rcsbuf;
6970 /* Get the revision number. */
6971 if (! rcsbuf_getrevnum (rcsbuf, &num))
6973 /* If num == NULL, it means we reached EOF naturally. That's
6978 error (1, 0, "%s: unexpected EOF", rcs->path);
6981 p = findnode (rcs->versions, num);
6983 error (1, 0, "mismatch in rcs file %s between deltas and deltatexts",
6986 d = (Deltatext *) xmalloc (sizeof (Deltatext));
6987 d->version = xstrdup (num);
6989 /* Get the log message. */
6990 if (! rcsbuf_getkey (rcsbuf, &key, &value))
6991 error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num);
6992 if (! STREQ (key, "log"))
6993 error (1, 0, "%s, delta %s: expected `log', got `%s'",
6994 rcs->path, num, key);
6995 d->log = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
6997 /* Get random newphrases. */
6998 d->other = getlist();
7001 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7002 error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num);
7004 if (STREQ (key, "text"))
7009 p->key = xstrdup (key);
7010 p->data = rcsbuf_valcopy (rcsbuf, value, 1, (size_t *) NULL);
7011 if (addnode (d->other, p) < 0)
7013 error (0, 0, "warning: %s, delta %s: duplicate field `%s'",
7014 rcs->path, num, key);
7018 /* Get the change text. We already know that this key is `text'. */
7019 d->text = rcsbuf_valcopy (rcsbuf, value, 0, &d->len);
7024 /* RCS output functions, for writing RCS format files from RCSNode
7027 For most of this work, RCS 5.7 uses an `aprintf' function which aborts
7028 program upon error. Instead, these functions check the output status
7029 of the stream right before closing it, and aborts if an error condition
7030 is found. The RCS solution is probably the better one: it produces
7031 more overhead, but will produce a clearer diagnostic in the case of
7032 catastrophic error. In either case, however, the repository will probably
7033 not get corrupted. */
7036 putsymbol_proc (symnode, fparg)
7040 FILE *fp = (FILE *) fparg;
7042 /* A fiddly optimization: this code used to just call fprintf, but
7043 in an old repository with hundreds of tags this can get called
7044 hundreds of thousands of times when doing a cvs tag. Since
7045 tagging is a relatively common operation, and using putc and
7046 fputs is just as comprehensible, the change is worthwhile. */
7049 fputs (symnode->key, fp);
7051 fputs (symnode->data, fp);
7055 static int putlock_proc PROTO ((Node *, void *));
7057 /* putlock_proc is like putsymbol_proc, but key and data are reversed. */
7060 putlock_proc (symnode, fp)
7064 return fprintf ((FILE *) fp, "\n\t%s:%s", symnode->data, symnode->key);
7068 putrcsfield_proc (node, vfp)
7072 FILE *fp = (FILE *) vfp;
7074 /* Some magic keys used internally by CVS start with `;'. Skip them. */
7075 if (node->key[0] == ';')
7078 fprintf (fp, "\n%s\t", node->key);
7079 if (node->data != NULL)
7081 /* If the field's value contains evil characters,
7082 it must be stringified. */
7083 /* FIXME: This does not quite get it right. "7jk8f" is not a legal
7084 value for a value in a newpharse, according to doc/RCSFILES,
7085 because digits are not valid in an "id". We might do OK by
7086 always writing strings (enclosed in @@). Would be nice to
7087 explicitly mention this one way or another in doc/RCSFILES.
7088 A case where we are wrong in a much more clear-cut way is that
7089 we let through non-graphic characters such as whitespace and
7090 control characters. */
7091 int n = strcspn (node->data, "$,.:;@");
7092 if (node->data[n] == 0)
7093 fputs (node->data, fp);
7097 expand_at_signs (node->data, (off_t) strlen (node->data), fp);
7102 /* desc, log and text fields should not be terminated with semicolon;
7103 all other fields should be. */
7104 if (! STREQ (node->key, "desc") &&
7105 ! STREQ (node->key, "log") &&
7106 ! STREQ (node->key, "text"))
7113 /* Output the admin node for RCS into stream FP. */
7116 RCS_putadmin (rcs, fp)
7120 fprintf (fp, "%s\t%s;\n", RCSHEAD, rcs->head ? rcs->head : "");
7122 fprintf (fp, "%s\t%s;\n", RCSBRANCH, rcs->branch);
7124 fputs ("access", fp);
7128 s = xstrdup (rcs->access);
7129 for (p = strtok (s, " \n\t"); p != NULL; p = strtok (NULL, " \n\t"))
7130 fprintf (fp, "\n\t%s", p);
7135 fputs (RCSSYMBOLS, fp);
7136 /* If we haven't had to convert the symbols to a list yet, don't
7137 force a conversion now; just write out the string. */
7138 if (rcs->symbols == NULL && rcs->symbols_data != NULL)
7141 fputs (rcs->symbols_data, fp);
7144 walklist (RCS_symbols (rcs), putsymbol_proc, (void *) fp);
7147 fputs ("locks", fp);
7148 if (rcs->locks_data)
7149 fprintf (fp, "\t%s", rcs->locks_data);
7150 else if (rcs->locks)
7151 walklist (rcs->locks, putlock_proc, (void *) fp);
7152 if (rcs->strict_locks)
7153 fprintf (fp, "; strict");
7158 fprintf (fp, "comment\t@");
7159 expand_at_signs (rcs->comment, (off_t) strlen (rcs->comment), fp);
7162 if (rcs->expand && ! STREQ (rcs->expand, "kv"))
7163 fprintf (fp, "%s\t@%s@;\n", RCSEXPAND, rcs->expand);
7165 walklist (rcs->other, putrcsfield_proc, (void *) fp);
7177 /* Skip if no revision was supplied, or if it is outdated (cvs admin -o) */
7178 if (vers == NULL || vers->outdated)
7181 fprintf (fp, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches",
7183 RCSDATE, vers->date,
7184 "author", vers->author,
7185 "state", vers->state ? vers->state : "");
7187 if (vers->branches != NULL)
7189 start = vers->branches->list;
7190 for (bp = start->next; bp != start; bp = bp->next)
7191 fprintf (fp, "\n\t%s", bp->key);
7194 fprintf (fp, ";\nnext\t%s;", vers->next ? vers->next : "");
7196 walklist (vers->other_delta, putrcsfield_proc, fp);
7202 RCS_putdtree (rcs, rev, fp)
7213 /* Find the delta node for this revision. */
7214 p = findnode (rcs->versions, rev);
7216 versp = (RCSVers *) p->data;
7218 /* Print the delta node and recurse on its `next' node. This prints
7219 the trunk. If there are any branches printed on this revision,
7220 print those trunks as well. */
7221 putdelta (versp, fp);
7222 RCS_putdtree (rcs, versp->next, fp);
7223 if (versp->branches != NULL)
7225 branch = versp->branches->list;
7226 for (p = branch->next; p != branch; p = p->next)
7227 RCS_putdtree (rcs, p->key, fp);
7232 RCS_putdesc (rcs, fp)
7236 fprintf (fp, "\n\n%s\n@", RCSDESC);
7237 if (rcs->desc != NULL)
7239 off_t len = (off_t) strlen (rcs->desc);
7242 expand_at_signs (rcs->desc, len, fp);
7243 if (rcs->desc[len-1] != '\n')
7251 putdeltatext (fp, d)
7255 fprintf (fp, "\n\n%s\nlog\n@", d->version);
7258 int loglen = strlen (d->log);
7259 expand_at_signs (d->log, (off_t) loglen, fp);
7260 if (d->log[loglen-1] != '\n')
7265 walklist (d->other, putrcsfield_proc, fp);
7267 fputs ("\ntext\n@", fp);
7268 if (d->text != NULL)
7269 expand_at_signs (d->text, (off_t) d->len, fp);
7273 /* TODO: the whole mechanism for updating deltas is kludgey... more
7274 sensible would be to supply all the necessary info in a `newdeltatext'
7275 field for RCSVers nodes. -twp */
7277 /* Copy delta text nodes from FIN to FOUT. If NEWDTEXT is non-NULL, it
7278 is a new delta text node, and should be added to the tree at the
7279 node whose revision number is INSERTPT. (Note that trunk nodes are
7280 written in decreasing order, and branch nodes are written in
7281 increasing order.) */
7284 RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt)
7287 struct rcsbuffer *rcsbufin;
7289 Deltatext *newdtext;
7295 int insertbefore, found;
7302 /* Count the number of versions for which we have to do some
7303 special operation. */
7304 actions = walklist (rcs->versions, count_delta_actions, (void *) NULL);
7306 /* Make a note of whether NEWDTEXT should be inserted
7307 before or after its INSERTPT. */
7308 insertbefore = (newdtext != NULL && numdots (newdtext->version) == 1);
7310 while (actions != 0 || newdtext != NULL)
7314 dtext = RCS_getdeltatext (rcs, fin, rcsbufin);
7316 /* We shouldn't hit EOF here, because that would imply that
7317 some action was not taken, or that we could not insert
7320 error (1, 0, "internal error: EOF too early in RCS_copydeltas");
7322 found = (insertpt != NULL && STREQ (dtext->version, insertpt));
7323 if (found && insertbefore)
7325 putdeltatext (fout, newdtext);
7330 np = findnode (rcs->versions, dtext->version);
7331 dadmin = (RCSVers *) np->data;
7333 /* If this revision has been outdated, just skip it. */
7334 if (dadmin->outdated)
7340 /* Update the change text for this delta. New change text
7341 data may come from cvs admin -m, cvs admin -o, or cvs ci. */
7342 if (dadmin->text != NULL)
7344 if (dadmin->text->log != NULL || dadmin->text->text != NULL)
7346 if (dadmin->text->log != NULL)
7349 dtext->log = dadmin->text->log;
7350 dadmin->text->log = NULL;
7352 if (dadmin->text->text != NULL)
7355 dtext->text = dadmin->text->text;
7356 dtext->len = dadmin->text->len;
7357 dadmin->text->text = NULL;
7360 putdeltatext (fout, dtext);
7361 freedeltatext (dtext);
7363 if (found && !insertbefore)
7365 putdeltatext (fout, newdtext);
7371 /* Copy the rest of the file directly, without bothering to
7372 interpret it. The caller will handle error checking by calling
7375 We just wrote a newline to the file, either in putdeltatext or
7376 in the caller. However, we may not have read the corresponding
7377 newline from the file, because rcsbuf_getkey returns as soon as
7378 it finds the end of the '@' string for the desc or text key.
7379 Therefore, we may read three newlines when we should really
7380 only write two, and we check for that case here. This is not
7381 an semantically important issue; we only do it to make our RCS
7382 files look traditional. */
7386 rcsbuf_get_buffered (rcsbufin, &bufrest, &buflen);
7389 if (bufrest[0] != '\n'
7390 || strncmp (bufrest, "\n\n\n", buflen < 3 ? buflen : 3) != 0)
7406 fwrite (bufrest, 1, buflen, fout);
7409 while ((got = fread (buf, 1, sizeof buf, fin)) != 0)
7414 && strncmp (buf, "\n\n\n", nls) == 0)
7416 fwrite (buf + 1, 1, got - 1, fout);
7420 fwrite (buf, 1, got, fout);
7427 /* A helper procedure for RCS_copydeltas. This is called via walklist
7428 to count the number of RCS revisions for which some special action
7432 count_delta_actions (np, ignore)
7438 dadmin = (RCSVers *) np->data;
7440 if (dadmin->outdated)
7443 if (dadmin->text != NULL
7444 && (dadmin->text->log != NULL || dadmin->text->text != NULL))
7452 /* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style
7453 locking on the specified RCSFILE: for a file called `foo,v', open
7454 for writing a file called `,foo,'.
7456 Note that we what do here is quite different from what RCS does.
7457 RCS creates the ,foo, file before it reads the RCS file (if it
7458 knows that it will be writing later), so that it actually serves as
7459 a lock. We don't; instead we rely on CVS writelocks. This means
7460 that if someone is running RCS on the file at the same time they
7461 are running CVS on it, they might lose (we read the file,
7462 then RCS writes it, then we write it, clobbering the
7463 changes made by RCS). I believe the current sentiment about this
7464 is "well, don't do that".
7466 A concern has been expressed about whether adopting the RCS
7467 strategy would slow us down. I don't think so, since we need to
7468 write the ,foo, file anyway (unless perhaps if O_EXCL is slower or
7471 These do not perform quite the same function as the RCS -l option
7472 for locking files: they are intended to prevent competing RCS
7473 processes from stomping all over each other's laundry. Hence,
7474 they are `internal' locking functions.
7476 Note that we don't clean up the ,foo, file on ^C. We probably should.
7477 I'm not completely sure whether RCS does or not (I looked at the code
7478 a little, and didn't find it).
7480 If there is an error, give a fatal error; if we return we always
7481 return a non-NULL value. */
7484 rcs_internal_lockfile (rcsfile)
7492 /* Get the lock file name: `,file,' for RCS file `file,v'. */
7493 lockfile = rcs_lockfilename (rcsfile);
7495 /* Use the existing RCS file mode, or read-only if this is a new
7496 file. (Really, this is a lie -- if this is a new file,
7497 RCS_checkin uses the permissions from the working copy. For
7498 actually creating the file, we use 0444 as a safe default mode.) */
7499 if (stat (rcsfile, &rstat) < 0)
7501 if (existence_error (errno))
7502 rstat.st_mode = S_IRUSR | S_IRGRP | S_IROTH;
7504 error (1, errno, "cannot stat %s", rcsfile);
7507 /* Try to open exclusively. POSIX.1 guarantees that O_EXCL|O_CREAT
7508 guarantees an exclusive open. According to the RCS source, with
7509 NFS v2 we must also throw in O_TRUNC and use an open mask that makes
7510 the file unwriteable. For extensive justification, see the comments for
7511 rcswriteopen() in rcsedit.c, in RCS 5.7. This is kind of pointless
7512 in the CVS case; see comment at the start of this file concerning
7513 general ,foo, file strategy.
7515 There is some sentiment that with NFSv3 and such, that one can
7516 rely on O_EXCL these days. This might be true for unix (I
7517 don't really know), but I am still pretty skeptical in the case
7518 of the non-unix systems. */
7519 fd = open (lockfile, OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
7520 S_IRUSR | S_IRGRP | S_IROTH);
7524 error (1, errno, "could not open lock file `%s'", lockfile);
7529 /* Force the file permissions, and return a stream object. */
7530 /* Because we change the modes later, we don't worry about
7531 this in the non-HAVE_FCHMOD case. */
7533 if (fchmod (fd, rstat.st_mode) < 0)
7534 error (1, errno, "cannot change mode for %s", lockfile);
7536 fp = fdopen (fd, FOPEN_BINARY_WRITE);
7538 error (1, errno, "cannot fdopen %s", lockfile);
7543 rcs_internal_unlockfile (fp, rcsfile)
7549 /* Get the lock file name: `,file,' for RCS file `file,v'. */
7550 lockfile = rcs_lockfilename (rcsfile);
7552 /* Abort if we could not write everything successfully to LOCKFILE.
7553 This is not a great error-handling mechanism, but should prevent
7554 corrupting the repository. */
7557 /* The only case in which using errno here would be meaningful
7558 is if we happen to have left errno unmolested since the call
7559 which produced the error (e.g. fprintf). That is pretty
7560 fragile even if it happens to sometimes be true. The real
7561 solution is to check each call to fprintf rather than waiting
7562 until the end like this. */
7563 error (1, 0, "error writing to lock file %s", lockfile);
7564 if (fclose (fp) == EOF)
7565 error (1, errno, "error closing lock file %s", lockfile);
7567 rename_file (lockfile, rcsfile);
7572 rcs_lockfilename (rcsfile)
7575 char *lockfile, *lockp;
7576 char *rcsbase, *rcsp, *rcsend;
7579 /* Create the lockfile name. */
7580 rcslen = strlen (rcsfile);
7581 lockfile = (char *) xmalloc (rcslen + 10);
7582 rcsbase = last_component (rcsfile);
7583 rcsend = rcsfile + rcslen - sizeof(RCSEXT);
7584 for (lockp = lockfile, rcsp = rcsfile; rcsp < rcsbase; ++rcsp)
7587 while (rcsp <= rcsend)
7595 /* Rewrite an RCS file. The basic idea here is that the caller should
7596 first call RCS_reparsercsfile, then munge the data structures as
7597 desired (via RCS_delete_revs, RCS_settag, &c), then call RCS_rewrite. */
7600 RCS_rewrite (rcs, newdtext, insertpt)
7602 Deltatext *newdtext;
7606 struct rcsbuffer rcsbufin;
7611 fout = rcs_internal_lockfile (rcs->path);
7613 RCS_putadmin (rcs, fout);
7614 RCS_putdtree (rcs, rcs->head, fout);
7615 RCS_putdesc (rcs, fout);
7617 /* Open the original RCS file and seek to the first delta text. */
7618 rcsbuf_cache_open (rcs, rcs->delta_pos, &fin, &rcsbufin);
7620 /* Update delta_pos to the current position in the output file.
7621 Do NOT move these statements: they must be done after fin has
7622 been positioned at the old delta_pos, but before any delta
7623 texts have been written to fout. */
7624 rcs->delta_pos = ftell (fout);
7625 if (rcs->delta_pos == -1)
7626 error (1, errno, "cannot ftell in RCS file %s", rcs->path);
7628 RCS_copydeltas (rcs, fin, &rcsbufin, fout, newdtext, insertpt);
7630 /* We don't want to call rcsbuf_cache here, since we're about to
7632 rcsbuf_close (&rcsbufin);
7634 /* The only case in which using errno here would be meaningful
7635 is if we happen to have left errno unmolested since the call
7636 which produced the error (e.g. fread). That is pretty
7637 fragile even if it happens to sometimes be true. The real
7638 solution is to make sure that all the code which reads
7639 from fin checks for errors itself (some does, some doesn't). */
7640 error (0, 0, "warning: when closing RCS file `%s'", rcs->path);
7641 if (fclose (fin) < 0)
7642 error (0, errno, "warning: closing RCS file `%s'", rcs->path);
7644 rcs_internal_unlockfile (fout, rcs->path);
7648 /* Annotate command. In rcs.c for historical reasons (from back when
7649 what is now RCS_deltas was part of annotate_fileproc). */
7651 /* Options from the command line. */
7653 static int force_tag_match = 1;
7654 static char *tag = NULL;
7655 static char *date = NULL;
7657 static int annotate_fileproc PROTO ((void *callerdat, struct file_info *));
7660 annotate_fileproc (callerdat, finfo)
7662 struct file_info *finfo;
7665 struct rcsbuffer *rcsbufp = NULL;
7666 struct rcsbuffer rcsbuf;
7669 if (finfo->rcs == NULL)
7672 if (finfo->rcs->flags & PARTIAL)
7674 RCS_reparsercsfile (finfo->rcs, &fp, &rcsbuf);
7678 version = RCS_getversion (finfo->rcs, tag, date, force_tag_match,
7680 if (version == NULL)
7683 /* Distinguish output for various files if we are processing
7685 cvs_outerr ("Annotations for ", 0);
7686 cvs_outerr (finfo->fullname, 0);
7687 cvs_outerr ("\n***************\n", 0);
7689 RCS_deltas (finfo->rcs, fp, rcsbufp, version, RCS_ANNOTATE, (char **) NULL,
7690 (size_t) NULL, (char **) NULL, (size_t *) NULL);
7695 static const char *const annotate_usage[] =
7697 "Usage: %s %s [-lRf] [-r rev|-D date] [files...]\n",
7698 "\t-l\tLocal directory only, no recursion.\n",
7699 "\t-R\tProcess directories recursively.\n",
7700 "\t-f\tUse head revision if tag/date not found.\n",
7701 "\t-r rev\tAnnotate file as of specified revision/tag.\n",
7702 "\t-D date\tAnnotate file as of specified date.\n",
7703 "(Specify the --help global option for a list of other help options)\n",
7707 /* Command to show the revision, date, and author where each line of a
7708 file was modified. */
7711 annotate (argc, argv)
7719 usage (annotate_usage);
7722 while ((c = getopt (argc, argv, "+lr:D:fR")) != -1)
7736 date = Make_Date (optarg);
7739 force_tag_match = 0;
7743 usage (annotate_usage);
7750 #ifdef CLIENT_SUPPORT
7758 if (!force_tag_match)
7760 option_with_arg ("-r", tag);
7762 client_senddate (date);
7763 send_file_names (argc, argv, SEND_EXPAND_WILD);
7764 send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
7765 send_to_server ("annotate\012", 0);
7766 return get_responses_and_close ();
7768 #endif /* CLIENT_SUPPORT */
7770 return start_recursion (annotate_fileproc, (FILESDONEPROC) NULL,
7771 (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
7772 argc, argv, local, W_LOCAL, 0, 1, (char *)NULL,
7777 * For a given file with full pathname PATH and revision number REV,
7778 * produce a file label suitable for passing to diff. The default
7779 * file label as used by RCS 5.7 looks like this:
7781 * FILENAME <tab> YYYY/MM/DD <sp> HH:MM:SS <tab> REVNUM
7783 * The date and time used are the revision's last checkin date and time.
7784 * If REV is NULL, use the working copy's mtime instead.
7787 make_file_label (path, rev, rcs)
7792 char datebuf[MAXDATELEN];
7796 file = last_component (path);
7797 label = (char *) xmalloc (strlen (file)
7798 + (rev == NULL ? 0 : strlen (rev))
7804 RCS_getrevtime (rcs, rev, datebuf, 0);
7805 date = printable_date (datebuf);
7806 (void) sprintf (label, "-L%s\t%s\t%s", file, date, rev);
7814 if (CVS_STAT (file, &sb) < 0)
7815 error (0, 1, "could not get info for `%s'", path);
7818 wm = gmtime (&sb.st_mtime);
7819 (void) sprintf (datebuf, "%04d/%02d/%02d %02d:%02d:%02d",
7820 wm->tm_year + 1900, wm->tm_mon + 1,
7821 wm->tm_mday, wm->tm_hour,
7822 wm->tm_min, wm->tm_sec);
7823 (void) sprintf (label, "-L%s\t%s", file, datebuf);