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 *RCS_addbranch PROTO ((RCSNode *, const char *));
85 static char *truncate_revnum_in_place PROTO ((char *));
86 static char *truncate_revnum PROTO ((const char *));
87 static char *printable_date PROTO((const char *));
88 static char *escape_keyword_value PROTO ((const char *, int *));
89 static void expand_keywords PROTO((RCSNode *, RCSVers *, const char *,
90 const char *, size_t, enum kflag, char *,
91 size_t, char **, size_t *));
92 static void cmp_file_buffer PROTO((void *, const char *, size_t));
94 enum rcs_delta_op {RCS_ANNOTATE, RCS_FETCH};
95 static void RCS_deltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *, char *,
96 enum rcs_delta_op, char **, size_t *,
99 /* Routines for reading, parsing and writing RCS files. */
100 static RCSVers *getdelta PROTO ((struct rcsbuffer *, char *, char **,
102 static Deltatext *RCS_getdeltatext PROTO ((RCSNode *, FILE *,
103 struct rcsbuffer *));
104 static void freedeltatext PROTO ((Deltatext *));
106 static void RCS_putadmin PROTO ((RCSNode *, FILE *));
107 static void RCS_putdtree PROTO ((RCSNode *, char *, FILE *));
108 static void RCS_putdesc PROTO ((RCSNode *, FILE *));
109 static void putdelta PROTO ((RCSVers *, FILE *));
110 static int putrcsfield_proc PROTO ((Node *, void *));
111 static int putsymbol_proc PROTO ((Node *, void *));
112 static void RCS_copydeltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *,
113 FILE *, Deltatext *, char *));
114 static int count_delta_actions PROTO ((Node *, void *));
115 static void putdeltatext PROTO ((FILE *, Deltatext *));
117 static FILE *rcs_internal_lockfile PROTO ((char *));
118 static void rcs_internal_unlockfile PROTO ((FILE *, char *));
119 static char *rcs_lockfilename PROTO ((char *));
121 /* The RCS file reading functions are called a lot, and they do some
122 string comparisons. This macro speeds things up a bit by skipping
123 the function call when the first characters are different. It
124 evaluates its arguments multiple times. */
125 #define STREQ(a, b) ((a)[0] == (b)[0] && strcmp ((a), (b)) == 0)
127 static char * getfullCVSname PROTO ((char *, char **));
130 * We don't want to use isspace() from the C library because:
132 * 1. The definition of "whitespace" in RCS files includes ASCII
133 * backspace, but the C locale doesn't.
134 * 2. isspace is an very expensive function call in some implementations
135 * due to the addition of wide character support.
137 static const char spacetab[] = {
138 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x00 - 0x0f */
139 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */
140 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */
141 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */
142 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
143 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
144 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x8f */
145 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */
146 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */
147 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */
148 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */
149 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */
150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
151 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
152 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
153 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0 - 0xff */
156 #define whitespace(c) (spacetab[(unsigned char)c] != 0)
158 /* Parse an rcsfile given a user file name and a repository. If there is
159 an error, we print an error message and return NULL. If the file
160 does not exist, we return NULL without printing anything (I'm not
161 sure this allows the caller to do anything reasonable, but it is
162 the current behavior). */
164 RCS_parse (file, repos)
173 /* We're creating a new RCSNode, so there is no hope of finding it
175 rcsbuf_cache_close ();
177 rcsfile = xmalloc (strlen (repos) + strlen (file)
178 + sizeof (RCSEXT) + sizeof (CVSATTIC) + 10);
179 (void) sprintf (rcsfile, "%s/%s%s", repos, file, RCSEXT);
180 if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) != NULL)
182 rcs = RCS_parsercsfile_i(fp, rcsfile);
189 else if (! existence_error (errno))
191 error (0, errno, "cannot open %s", rcsfile);
196 (void) sprintf (rcsfile, "%s/%s/%s%s", repos, CVSATTIC, file, RCSEXT);
197 if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) != NULL)
199 rcs = RCS_parsercsfile_i(fp, rcsfile);
202 rcs->flags |= INATTIC;
209 else if (! existence_error (errno))
211 error (0, errno, "cannot open %s", rcsfile);
215 #if defined (SERVER_SUPPORT) && !defined (FILENAMES_CASE_INSENSITIVE)
221 /* The client might be asking for a file which we do have
222 (which the client doesn't know about), but for which the
223 filename case differs. We only consider this case if the
224 regular CVS_FOPENs fail, because fopen_case is such an
226 (void) sprintf (rcsfile, "%s/%s%s", repos, file, RCSEXT);
227 status = fopen_case (rcsfile, "rb", &fp, &found_path);
230 rcs = RCS_parsercsfile_i (fp, rcsfile);
235 rcs->path = found_path;
239 else if (! existence_error (status))
241 error (0, status, "cannot open %s", rcsfile);
246 (void) sprintf (rcsfile, "%s/%s/%s%s", repos, CVSATTIC, file, RCSEXT);
247 status = fopen_case (rcsfile, "rb", &fp, &found_path);
250 rcs = RCS_parsercsfile_i (fp, rcsfile);
253 rcs->flags |= INATTIC;
258 rcs->path = found_path;
262 else if (! existence_error (status))
264 error (0, status, "cannot open %s", rcsfile);
279 * Parse a specific rcsfile.
282 RCS_parsercsfile (rcsfile)
288 /* We're creating a new RCSNode, so there is no hope of finding it
290 rcsbuf_cache_close ();
292 /* open the rcsfile */
293 if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) == NULL)
295 error (0, errno, "Couldn't open rcs file `%s'", rcsfile);
299 rcs = RCS_parsercsfile_i (fp, rcsfile);
308 RCS_parsercsfile_i (fp, rcsfile)
313 struct rcsbuffer rcsbuf;
317 rdata = (RCSNode *) xmalloc (sizeof (RCSNode));
318 memset ((char *) rdata, 0, sizeof (RCSNode));
320 rdata->path = xstrdup (rcsfile);
322 /* Process HEAD, BRANCH, and EXPAND keywords from the RCS header.
324 Most cvs operations on the main branch don't need any more
325 information. Those that do call RCS_reparsercsfile to parse
326 the rest of the header and the deltas. */
328 rcsbuf_open (&rcsbuf, fp, rcsfile, 0);
330 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
332 if (STREQ (key, RCSDESC))
335 if (STREQ (RCSHEAD, key) && value != NULL)
336 rdata->head = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *) NULL);
338 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
340 if (STREQ (key, RCSDESC))
343 if (STREQ (RCSBRANCH, key) && value != NULL)
347 rdata->branch = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *) NULL);
348 if ((numdots (rdata->branch) & 1) != 0)
350 /* turn it into a branch if it's a revision */
351 cp = strrchr (rdata->branch, '.');
356 /* Look ahead for expand, stopping when we see desc or a revision
362 if (STREQ (RCSEXPAND, key))
364 rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0,
369 for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
374 if (STREQ (RCSDESC, key))
377 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
381 rdata->flags |= PARTIAL;
383 rcsbuf_cache (rdata, &rcsbuf);
388 error (0, 0, "`%s' does not appear to be a valid rcs file",
390 rcsbuf_close (&rcsbuf);
391 freercsnode (&rdata);
397 /* Do the real work of parsing an RCS file.
399 On error, die with a fatal error; if it returns at all it was successful.
401 If PFP is NULL, close the file when done. Otherwise, leave it open
402 and store the FILE * in *PFP. */
404 RCS_reparsercsfile (rdata, pfp, rcsbufp)
407 struct rcsbuffer *rcsbufp;
411 struct rcsbuffer rcsbuf;
418 assert (rdata != NULL);
419 rcsfile = rdata->path;
421 rcsbuf_cache_open (rdata, 0, &fp, &rcsbuf);
424 /* This probably shouldn't be done until later: if a file has an
425 empty revision tree (which is permissible), rdata->versions
426 should be NULL. -twp */
427 rdata->versions = getlist ();
430 * process all the special header information, break out when we get to
431 * the first revision delta
436 /* get the next key/value pair */
439 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
441 error (1, 0, "`%s' does not appear to be a valid rcs file",
448 /* Skip head, branch and expand tags; we already have them. */
449 if (STREQ (key, RCSHEAD)
450 || STREQ (key, RCSBRANCH)
451 || STREQ (key, RCSEXPAND))
456 if (STREQ (key, "access"))
460 /* We pass the POLISH parameter as 1 because
461 RCS_addaccess expects nothing but spaces. FIXME:
462 It would be easy and more efficient to change
464 rdata->access = rcsbuf_valcopy (&rcsbuf, value, 1,
470 /* We always save lock information, so that we can handle
471 -kkvl correctly when checking out a file. */
472 if (STREQ (key, "locks"))
475 rdata->locks_data = rcsbuf_valcopy (&rcsbuf, value, 0,
477 if (! rcsbuf_getkey (&rcsbuf, &key, &value))
479 error (1, 0, "premature end of file reading %s", rcsfile);
481 if (STREQ (key, "strict") && value == NULL)
483 rdata->strict_locks = 1;
490 if (STREQ (RCSSYMBOLS, key))
493 rdata->symbols_data = rcsbuf_valcopy (&rcsbuf, value, 0,
499 * check key for '.''s and digits (probably a rev) if it is a
500 * revision or `desc', we are done with the headers and are down to the
501 * revision deltas, so we break out of the loop
503 for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
505 /* Note that when comparing with RCSDATE, we are not massaging
506 VALUE from the string found in the RCS file. This is OK
507 since we know exactly what to expect. */
508 if (*cp == '\0' && strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) == 0)
511 if (STREQ (key, RCSDESC))
514 if (STREQ (key, "comment"))
516 rdata->comment = rcsbuf_valcopy (&rcsbuf, value, 0,
520 if (rdata->other == NULL)
521 rdata->other = getlist ();
524 kv->key = xstrdup (key);
525 kv->data = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
526 if (addnode (rdata->other, kv) != 0)
528 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
533 /* if we haven't grabbed it yet, we didn't want it */
536 /* We got out of the loop, so we have the first part of the first
537 revision delta in KEY (the revision) and VALUE (the date key
538 and its value). This is what getdelta expects to receive. */
540 while ((vnode = getdelta (&rcsbuf, rcsfile, &key, &value)) != NULL)
545 q->delproc = rcsvers_delproc;
546 q->data = (char *) vnode;
547 q->key = vnode->version;
549 /* add the nodes to the list */
550 if (addnode (rdata->versions, q) != 0)
553 purify_printf("WARNING: Adding duplicate version: %s (%s)\n",
560 /* Here KEY and VALUE are whatever caused getdelta to return NULL. */
562 if (STREQ (key, RCSDESC))
564 if (rdata->desc != NULL)
567 "warning: duplicate key `%s' in RCS file `%s'",
571 /* Don't need to rcsbuf_valcopy `value' because
572 getdelta already did that. */
573 rdata->desc = xstrdup (value);
576 rdata->delta_pos = rcsbuf_ftell (&rcsbuf);
579 rcsbuf_cache (rdata, &rcsbuf);
585 rdata->flags &= ~PARTIAL;
589 * Fully parse the RCS file. Store all keyword/value pairs, fetch the
590 * log messages for each revision, and fetch add and delete counts for
591 * each revision (we could fetch the entire text for each revision,
592 * but the only caller, log_fileproc, doesn't need that information,
593 * so we don't waste the memory required to store it). The add and
594 * delete counts are stored on the OTHER field of the RCSVERSNODE
595 * structure, under the names ";add" and ";delete", so that we don't
596 * waste the memory space of extra fields in RCSVERSNODE for code
597 * which doesn't need this information.
601 RCS_fully_parse (rcs)
605 struct rcsbuffer rcsbuf;
607 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
615 /* Rather than try to keep track of how much information we
616 have read, just read to the end of the file. */
617 if (! rcsbuf_getrevnum (&rcsbuf, &key))
620 vers = findnode (rcs->versions, key);
623 "mismatch in rcs file %s between deltas and deltatexts",
626 vnode = (RCSVers *) vers->data;
628 while (rcsbuf_getkey (&rcsbuf, &key, &value))
630 if (! STREQ (key, "text"))
634 if (vnode->other == NULL)
635 vnode->other = getlist ();
638 kv->key = xstrdup (key);
639 kv->data = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
640 if (addnode (vnode->other, kv) != 0)
644 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
645 key, vnode->version, rcs->path);
652 if (! STREQ (vnode->version, rcs->head))
654 unsigned long add, del;
658 /* This is a change text. Store the add and delete
667 rcsbuf_valpolish (&rcsbuf, value, 0, &vallen);
669 while (cp < value + vallen)
675 if (op != 'a' && op != 'd')
676 error (1, 0, "unrecognized operation '%c' in %s",
678 (void) strtoul (cp, (char **) &cp, 10);
680 error (1, 0, "space expected in %s",
682 count = strtoul (cp, (char **) &cp, 10);
684 error (1, 0, "linefeed expected in %s",
696 else if (cp == value + vallen)
700 invalid rcs file %s: premature end of value",
711 sprintf (buf, "%lu", add);
714 kv->key = xstrdup (";add");
715 kv->data = xstrdup (buf);
716 if (addnode (vnode->other, kv) != 0)
720 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
721 key, vnode->version, rcs->path);
725 sprintf (buf, "%lu", del);
728 kv->key = xstrdup (";delete");
729 kv->data = xstrdup (buf);
730 if (addnode (vnode->other, kv) != 0)
734 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
735 key, vnode->version, rcs->path);
740 /* We have found the "text" key which ends the data for
741 this revision. Break out of the loop and go on to the
747 rcsbuf_cache (rcs, &rcsbuf);
751 * freercsnode - free up the info for an RCSNode
757 if (rnodep == NULL || *rnodep == NULL)
760 ((*rnodep)->refcount)--;
761 if ((*rnodep)->refcount != 0)
763 *rnodep = (RCSNode *) NULL;
766 free ((*rnodep)->path);
767 if ((*rnodep)->head != (char *) NULL)
768 free ((*rnodep)->head);
769 if ((*rnodep)->branch != (char *) NULL)
770 free ((*rnodep)->branch);
771 free_rcsnode_contents (*rnodep);
772 free ((char *) *rnodep);
773 *rnodep = (RCSNode *) NULL;
777 * free_rcsnode_contents - free up the contents of an RCSNode without
778 * freeing the node itself, or the file name, or the head, or the
779 * path. This returns the RCSNode to the state it is in immediately
780 * after a call to RCS_parse.
783 free_rcsnode_contents (rnode)
786 dellist (&rnode->versions);
787 if (rnode->symbols != (List *) NULL)
788 dellist (&rnode->symbols);
789 if (rnode->symbols_data != (char *) NULL)
790 free (rnode->symbols_data);
791 if (rnode->expand != NULL)
792 free (rnode->expand);
793 if (rnode->other != (List *) NULL)
794 dellist (&rnode->other);
795 if (rnode->access != NULL)
796 free (rnode->access);
797 if (rnode->locks_data != NULL)
798 free (rnode->locks_data);
799 if (rnode->locks != (List *) NULL)
800 dellist (&rnode->locks);
801 if (rnode->comment != NULL)
802 free (rnode->comment);
803 if (rnode->desc != NULL)
807 /* free_rcsvers_contents -- free up the contents of an RCSVers node,
808 but also free the pointer to the node itself. */
809 /* Note: The `hardlinks' list is *not* freed, since it is merely a
810 pointer into the `hardlist' structure (defined in hardlink.c), and
811 that structure is freed elsewhere in the program. */
814 free_rcsvers_contents (rnode)
817 if (rnode->branches != (List *) NULL)
818 dellist (&rnode->branches);
819 if (rnode->date != (char *) NULL)
821 if (rnode->next != (char *) NULL)
823 if (rnode->author != (char *) NULL)
824 free (rnode->author);
825 if (rnode->state != (char *) NULL)
827 if (rnode->other != (List *) NULL)
828 dellist (&rnode->other);
829 if (rnode->other_delta != NULL)
830 dellist (&rnode->other_delta);
831 if (rnode->text != NULL)
832 freedeltatext (rnode->text);
833 free ((char *) rnode);
837 * rcsvers_delproc - free up an RCSVers type node
843 free_rcsvers_contents ((RCSVers *) p->data);
846 /* These functions retrieve keys and values from an RCS file using a
847 buffer. We use this somewhat complex approach because it turns out
848 that for many common operations, CVS spends most of its time
849 reading keys, so it's worth doing some fairly hairy optimization. */
851 /* The number of bytes we try to read each time we need more data. */
853 #define RCSBUF_BUFSIZE (8192)
855 /* The buffer we use to store data. This grows as needed. */
857 static char *rcsbuf_buffer = NULL;
858 static size_t rcsbuf_buffer_size = 0;
860 /* Whether rcsbuf_buffer is in use. This is used as a sanity check. */
862 static int rcsbuf_inuse;
864 /* Set up to start gathering keys and values from an RCS file. This
865 initializes RCSBUF. */
868 rcsbuf_open (rcsbuf, fp, filename, pos)
869 struct rcsbuffer *rcsbuf;
871 const char *filename;
875 error (1, 0, "rcsbuf_open: internal error");
878 if (rcsbuf_buffer_size < RCSBUF_BUFSIZE)
879 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, RCSBUF_BUFSIZE);
881 rcsbuf->ptr = rcsbuf_buffer;
882 rcsbuf->ptrend = rcsbuf_buffer;
884 rcsbuf->filename = filename;
887 rcsbuf->at_string = 0;
888 rcsbuf->embedded_at = 0;
891 /* Stop gathering keys from an RCS file. */
894 rcsbuf_close (rcsbuf)
895 struct rcsbuffer *rcsbuf;
898 error (1, 0, "rcsbuf_close: internal error");
902 /* Read a key/value pair from an RCS file. This sets *KEYP to point
903 to the key, and *VALUEP to point to the value. A missing or empty
904 value is indicated by setting *VALUEP to NULL.
906 This function returns 1 on success, or 0 on EOF. If there is an
907 error reading the file, or an EOF in an unexpected location, it
910 This sets *KEYP and *VALUEP to point to storage managed by
911 rcsbuf_getkey. Moreover, *VALUEP has not been massaged from the
912 RCS format: it may contain embedded whitespace and embedded '@'
913 characters. Call rcsbuf_valcopy or rcsbuf_valpolish to do
914 appropriate massaging. */
917 rcsbuf_getkey (rcsbuf, keyp, valp)
918 struct rcsbuffer *rcsbuf;
922 register const char * const my_spacetab = spacetab;
923 register char *ptr, *ptrend;
926 #define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
929 rcsbuf->at_string = 0;
930 rcsbuf->embedded_at = 0;
933 ptrend = rcsbuf->ptrend;
936 if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size)
939 /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
940 buffer, move back to the start of the buffer. This keeps the
941 buffer from growing indefinitely. */
942 if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
948 /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
949 at a time, so we can't have more bytes than that past PTR. */
950 if (len > RCSBUF_BUFSIZE)
953 /* Update the POS field, which holds the file offset of the
954 first byte in the RCSBUF_BUFFER buffer. */
955 rcsbuf->pos += ptr - rcsbuf_buffer;
957 memcpy (rcsbuf_buffer, ptr, len);
960 rcsbuf->ptrend = ptrend;
963 /* Skip leading whitespace. */
969 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
972 ptrend = rcsbuf->ptrend;
976 if (! my_whitespace (c))
982 /* We've found the start of the key. */
993 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
995 error (1, 0, "EOF in key in RCS file %s",
997 ptrend = rcsbuf->ptrend;
1000 if (c == ';' || my_whitespace (c))
1005 /* Here *KEYP points to the key in the buffer, C is the character
1006 we found at the of the key, and PTR points to the location in
1007 the buffer where we found C. We must set *PTR to \0 in order
1008 to terminate the key. If the key ended with ';', then there is
1021 /* C must be whitespace. Skip whitespace between the key and the
1022 value. If we find ';' now, there is no value. */
1028 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
1030 error (1, 0, "EOF while looking for value in RCS file %s",
1032 ptrend = rcsbuf->ptrend;
1038 rcsbuf->ptr = ptr + 1;
1041 if (! my_whitespace (c))
1046 /* Now PTR points to the start of the value, and C is the first
1047 character of the value. */
1056 /* Optimize the common case of a value composed of a single
1059 rcsbuf->at_string = 1;
1067 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1069 /* Note that we pass PTREND as the PTR value to
1070 rcsbuf_fill, so that we will wind up setting PTR to
1071 the location corresponding to the old PTREND, so
1072 that we don't search the same bytes again. */
1073 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1076 "EOF while looking for end of string in RCS file %s",
1078 ptrend = rcsbuf->ptrend;
1081 /* Handle the special case of an '@' right at the end of
1083 if (pat + 1 >= ptrend)
1085 /* Note that we pass PAT, not PTR, here. */
1086 pat = rcsbuf_fill (rcsbuf, pat, keyp, valp);
1089 /* EOF here is OK; it just means that the last
1090 character of the file was an '@' terminating a
1091 value for a key type which does not require a
1093 pat = rcsbuf->ptrend - 1;
1096 ptrend = rcsbuf->ptrend;
1098 /* Note that the value of PTR is bogus here. This is
1099 OK, because we don't use it. */
1102 if (pat + 1 >= ptrend || pat[1] != '@')
1105 /* We found an '@' pair in the string. Keep looking. */
1106 ++rcsbuf->embedded_at;
1110 /* Here PAT points to the final '@' in the string. */
1117 rcsbuf->vlen = vlen;
1122 /* Certain keywords only have a '@' string. If there is no '@'
1123 string, then the old getrcskey function assumed that they had
1124 no value, and we do the same. */
1130 if (STREQ (k, RCSDESC)
1131 || STREQ (k, "text")
1132 || STREQ (k, "log"))
1141 /* If we've already gathered a '@' string, try to skip whitespace
1151 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1153 error (1, 0, "EOF in value in RCS file %s",
1155 ptrend = rcsbuf->ptrend;
1160 /* We're done. We already set everything up for this
1162 rcsbuf->ptr = ptr + 1;
1165 if (! my_whitespace (n))
1170 /* The value extends past the '@' string. We need to undo the
1171 closing of the '@' done in the default case above. This
1172 case never happens in a plain RCS file, but it can happen
1173 if user defined phrases are used. */
1174 if (rcsbuf->vlen != 0)
1175 (*valp)[rcsbuf->vlen] = ' ';
1180 /* Here we have a value which is not a simple '@' string. We need
1181 to gather up everything until the next ';', including any '@'
1182 strings. *VALP points to the start of the value. If
1183 RCSBUF->VLEN is not zero, then we have already read an '@'
1184 string, and PTR points to the data following the '@' string.
1185 Otherwise, PTR points to the start of the value. */
1189 char *start, *psemi, *pat;
1191 /* Find the ';' which must end the value. */
1193 while ((psemi = memchr (ptr, ';', ptrend - ptr)) == NULL)
1197 /* Note that we pass PTREND as the PTR value to
1198 rcsbuf_fill, so that we will wind up setting PTR to the
1199 location corresponding to the old PTREND, so that we
1200 don't search the same bytes again. */
1201 slen = start - *valp;
1202 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1204 error (1, 0, "EOF in value in RCS file %s", rcsbuf->filename);
1205 start = *valp + slen;
1206 ptrend = rcsbuf->ptrend;
1209 /* See if there are any '@' strings in the value. */
1210 pat = memchr (start, '@', psemi - start);
1216 /* We're done with the value. Trim any trailing
1219 rcsbuf->ptr = psemi + 1;
1222 while (psemi > start && my_whitespace (psemi[-1]))
1226 vlen = psemi - start;
1229 rcsbuf->vlen = vlen;
1234 /* We found an '@' string in the value. We set
1235 RCSBUF->AT_STRING, which means that we won't be able to
1236 compress whitespace correctly for this type of value.
1237 Since this type of value never arises in a normal RCS file,
1238 this should not be a big deal. It means that if anybody
1239 adds a phrase which can have both an '@' string and regular
1240 text, they will have to handle whitespace compression
1243 rcsbuf->at_string = 1;
1251 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1253 /* Note that we pass PTREND as the PTR value to
1254 rcsbuff_fill, so that we will wind up setting PTR
1255 to the location corresponding to the old PTREND, so
1256 that we don't search the same bytes again. */
1257 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1260 "EOF while looking for end of string in RCS file %s",
1262 ptrend = rcsbuf->ptrend;
1265 /* Handle the special case of an '@' right at the end of
1267 if (pat + 1 >= ptrend)
1269 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1271 error (1, 0, "EOF in value in RCS file %s",
1273 ptrend = rcsbuf->ptrend;
1279 /* We found an '@' pair in the string. Keep looking. */
1280 ++rcsbuf->embedded_at;
1284 /* Here PAT points to the final '@' in the string. */
1291 #undef my_whitespace
1294 /* TODO: Eliminate redundant code in rcsbuf_getkey, rcsbuf_getid,
1295 rcsbuf_getstring, rcsbuf_getword. These last three functions were
1296 all created by hacking monstrous swaths of code from rcsbuf_getkey,
1297 and some engineering would make the code easier to read and
1300 Note that the extreme hair in rcsbuf_getkey is because profiling
1301 statistics show that it was worth it.
1303 We probably could be processing "hardlinks" by first calling
1304 rcsbuf_getkey, and breaking up the value afterwards; the code to
1305 break it up would not need to be hacked for speed. This would
1306 remove the need for rcsbuf_getword, rcsbuf_getid, and
1307 rcsbuf_getstring, as the other calls are easy to remove. */
1309 /* Read an `id' (in the sense of rcsfile(5)) from RCSBUF, and store in
1313 rcsbuf_getid (rcsbuf, idp)
1314 struct rcsbuffer *rcsbuf;
1317 register const char * const my_spacetab = spacetab;
1318 register char *ptr, *ptrend;
1321 #define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
1324 rcsbuf->at_string = 0;
1325 rcsbuf->embedded_at = 0;
1328 ptrend = rcsbuf->ptrend;
1331 if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size)
1334 /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
1335 buffer, move back to the start of the buffer. This keeps the
1336 buffer from growing indefinitely. */
1337 if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
1343 /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
1344 at a time, so we can't have more bytes than that past PTR. */
1345 if (len > RCSBUF_BUFSIZE)
1348 /* Update the POS field, which holds the file offset of the
1349 first byte in the RCSBUF_BUFFER buffer. */
1350 rcsbuf->pos += ptr - rcsbuf_buffer;
1352 memcpy (rcsbuf_buffer, ptr, len);
1353 ptr = rcsbuf_buffer;
1355 rcsbuf->ptrend = ptrend;
1358 /* Skip leading whitespace. */
1364 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
1367 ptrend = rcsbuf->ptrend;
1371 if (! my_whitespace (c))
1377 /* We've found the start of the key. */
1388 ptr = rcsbuf_fill (rcsbuf, ptr, idp, (char **) NULL);
1390 error (1, 0, "EOF in key in RCS file %s",
1392 ptrend = rcsbuf->ptrend;
1395 if (c == ';' || my_whitespace (c))
1400 /* Here *IDP points to the id in the buffer, C is the character
1401 we found at the end of the key, and PTR points to the location in
1402 the buffer where we found C. We may not set *PTR to \0, because
1403 it may overwrite a terminating semicolon. The calling function
1404 must copy and terminate the id on its own. */
1409 #undef my_whitespace
1412 /* Read an RCS @-delimited string. Store the result in STRP. */
1415 rcsbuf_getstring (rcsbuf, strp)
1416 struct rcsbuffer *rcsbuf;
1419 register const char * const my_spacetab = spacetab;
1420 register char *ptr, *ptrend;
1425 #define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
1428 rcsbuf->at_string = 0;
1429 rcsbuf->embedded_at = 0;
1432 ptrend = rcsbuf->ptrend;
1435 if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size)
1438 /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
1439 buffer, move back to the start of the buffer. This keeps the
1440 buffer from growing indefinitely. */
1441 if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
1447 /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
1448 at a time, so we can't have more bytes than that past PTR. */
1449 if (len > RCSBUF_BUFSIZE)
1452 /* Update the POS field, which holds the file offset of the
1453 first byte in the RCSBUF_BUFFER buffer. */
1454 rcsbuf->pos += ptr - rcsbuf_buffer;
1456 memcpy (rcsbuf_buffer, ptr, len);
1457 ptr = rcsbuf_buffer;
1459 rcsbuf->ptrend = ptrend;
1462 /* Skip leading whitespace. */
1468 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
1470 error (1, 0, "unexpected end of file reading %s",
1472 ptrend = rcsbuf->ptrend;
1476 if (! my_whitespace (c))
1482 /* PTR should now point to the start of a string. */
1484 error (1, 0, "expected @-string at `%c' in %s", c, rcsbuf->filename);
1486 /* Optimize the common case of a value composed of a single
1489 rcsbuf->at_string = 1;
1497 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1499 /* Note that we pass PTREND as the PTR value to
1500 rcsbuf_fill, so that we will wind up setting PTR to
1501 the location corresponding to the old PTREND, so
1502 that we don't search the same bytes again. */
1503 ptr = rcsbuf_fill (rcsbuf, ptrend, NULL, strp);
1506 "EOF while looking for end of string in RCS file %s",
1508 ptrend = rcsbuf->ptrend;
1511 /* Handle the special case of an '@' right at the end of
1513 if (pat + 1 >= ptrend)
1515 /* Note that we pass PAT, not PTR, here. */
1516 pat = rcsbuf_fill (rcsbuf, pat, NULL, strp);
1519 /* EOF here is OK; it just means that the last
1520 character of the file was an '@' terminating a
1521 value for a key type which does not require a
1523 pat = rcsbuf->ptrend - 1;
1526 ptrend = rcsbuf->ptrend;
1528 /* Note that the value of PTR is bogus here. This is
1529 OK, because we don't use it. */
1532 if (pat + 1 >= ptrend || pat[1] != '@')
1535 /* We found an '@' pair in the string. Keep looking. */
1536 ++rcsbuf->embedded_at;
1540 /* Here PAT points to the final '@' in the string. */
1547 rcsbuf->vlen = vlen;
1548 rcsbuf->ptr = pat + 1;
1552 #undef my_whitespace
1555 /* Read an RCS `word', in the sense of rcsfile(5) (an id, a num, a
1556 @-delimited string, or `:'). Store the result in WORDP. If a
1557 `;' is reached without reading any text, the result is NULL. */
1560 rcsbuf_getword (rcsbuf, wordp)
1561 struct rcsbuffer *rcsbuf;
1564 register const char * const my_spacetab = spacetab;
1565 register char *ptr, *ptrend;
1568 #define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
1571 rcsbuf->at_string = 0;
1572 rcsbuf->embedded_at = 0;
1575 ptrend = rcsbuf->ptrend;
1578 if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size)
1581 /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
1582 buffer, move back to the start of the buffer. This keeps the
1583 buffer from growing indefinitely. */
1584 if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
1590 /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
1591 at a time, so we can't have more bytes than that past PTR. */
1592 if (len > RCSBUF_BUFSIZE)
1595 /* Update the POS field, which holds the file offset of the
1596 first byte in the RCSBUF_BUFFER buffer. */
1597 rcsbuf->pos += ptr - rcsbuf_buffer;
1599 memcpy (rcsbuf_buffer, ptr, len);
1600 ptr = rcsbuf_buffer;
1602 rcsbuf->ptrend = ptrend;
1605 /* Skip leading whitespace. */
1611 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
1613 error (1, 0, "unexpected end of file reading %s",
1615 ptrend = rcsbuf->ptrend;
1619 if (! my_whitespace (c))
1625 /* If we have reached `;', there is no value. */
1635 /* PTR now points to the start of a value. Find out whether it is
1636 a num, an id, a string or a colon. */
1650 /* Optimize the common case of a value composed of a single
1653 rcsbuf->at_string = 1;
1661 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1663 /* Note that we pass PTREND as the PTR value to
1664 rcsbuf_fill, so that we will wind up setting PTR to
1665 the location corresponding to the old PTREND, so
1666 that we don't search the same bytes again. */
1667 ptr = rcsbuf_fill (rcsbuf, ptrend, NULL, wordp);
1670 "EOF while looking for end of string in RCS file %s",
1672 ptrend = rcsbuf->ptrend;
1675 /* Handle the special case of an '@' right at the end of
1677 if (pat + 1 >= ptrend)
1679 /* Note that we pass PAT, not PTR, here. */
1680 pat = rcsbuf_fill (rcsbuf, pat, NULL, wordp);
1683 /* EOF here is OK; it just means that the last
1684 character of the file was an '@' terminating a
1685 value for a key type which does not require a
1687 pat = rcsbuf->ptrend - 1;
1690 ptrend = rcsbuf->ptrend;
1692 /* Note that the value of PTR is bogus here. This is
1693 OK, because we don't use it. */
1696 if (pat + 1 >= ptrend || pat[1] != '@')
1699 /* We found an '@' pair in the string. Keep looking. */
1700 ++rcsbuf->embedded_at;
1704 /* Here PAT points to the final '@' in the string. */
1708 vlen = pat - *wordp;
1711 rcsbuf->vlen = vlen;
1712 rcsbuf->ptr = pat + 1;
1717 /* C is neither `:', `;' nor `@', so it should be the start of a num
1718 or an id. Make sure it is not another special character. */
1719 if (c == '$' || c == '.' || c == ',')
1721 error (1, 0, "illegal special character in RCS field in %s",
1730 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, wordp);
1732 error (1, 0, "unexpected end of file reading %s",
1734 ptrend = rcsbuf->ptrend;
1737 /* Legitimate ID characters are digits, dots and any `graphic
1738 printing character that is not a special.' This test ought
1742 c != ';' && c != '$' && c != ',' && c != '@' && c != ':')
1750 /* PTR points to the last non-id character in this word, and C is
1751 the character in its memory cell. Check to make sure that it
1752 is a legitimate word delimiter -- whitespace or semicolon. */
1753 if (c == ';' || my_whitespace (c))
1755 rcsbuf->vlen = ptr - *wordp;
1760 error (1, 0, "illegal special character in RCS field in %s",
1762 /* Shut up compiler warnings. */
1765 #undef my_whitespace
1768 /* Read an RCS revision number from an RCS file. This sets *REVP to
1769 point to the revision number; it will point to space that is
1770 managed by the rcsbuf functions, and is only good until the next
1771 call to rcsbuf_getkey or rcsbuf_getrevnum.
1773 This function returns 1 on success, or 0 on EOF. If there is an
1774 error reading the file, or an EOF in an unexpected location, it
1775 gives a fatal error. */
1778 rcsbuf_getrevnum (rcsbuf, revp)
1779 struct rcsbuffer *rcsbuf;
1786 ptrend = rcsbuf->ptrend;
1790 /* Skip leading whitespace. */
1796 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
1799 ptrend = rcsbuf->ptrend;
1803 if (! whitespace (c))
1809 if (! isdigit (c) && c != '.')
1811 "unexpected `%c' reading revision number in RCS file %s",
1812 c, rcsbuf->filename);
1821 ptr = rcsbuf_fill (rcsbuf, ptr, revp, (char **) NULL);
1824 "unexpected EOF reading revision number in RCS file %s",
1826 ptrend = rcsbuf->ptrend;
1831 while (isdigit (c) || c == '.');
1833 if (! whitespace (c))
1834 error (1, 0, "unexpected `%c' reading revision number in RCS file %s",
1835 c, rcsbuf->filename);
1839 rcsbuf->ptr = ptr + 1;
1844 /* Fill RCSBUF_BUFFER with bytes from the file associated with RCSBUF,
1845 updating PTR and the PTREND field. If KEYP and *KEYP are not NULL,
1846 then *KEYP points into the buffer, and must be adjusted if the
1847 buffer is changed. Likewise for VALP. Returns the new value of
1848 PTR, or NULL on error. */
1851 rcsbuf_fill (rcsbuf, ptr, keyp, valp)
1852 struct rcsbuffer *rcsbuf;
1859 if (rcsbuf->ptrend - rcsbuf_buffer + RCSBUF_BUFSIZE > rcsbuf_buffer_size)
1861 int poff, peoff, koff, voff;
1863 poff = ptr - rcsbuf_buffer;
1864 peoff = rcsbuf->ptrend - rcsbuf_buffer;
1865 if (keyp != NULL && *keyp != NULL)
1866 koff = *keyp - rcsbuf_buffer;
1867 if (valp != NULL && *valp != NULL)
1868 voff = *valp - rcsbuf_buffer;
1870 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size,
1871 rcsbuf_buffer_size + RCSBUF_BUFSIZE);
1873 ptr = rcsbuf_buffer + poff;
1874 rcsbuf->ptrend = rcsbuf_buffer + peoff;
1875 if (keyp != NULL && *keyp != NULL)
1876 *keyp = rcsbuf_buffer + koff;
1877 if (valp != NULL && *valp != NULL)
1878 *valp = rcsbuf_buffer + voff;
1881 got = fread (rcsbuf->ptrend, 1, RCSBUF_BUFSIZE, rcsbuf->fp);
1884 if (ferror (rcsbuf->fp))
1885 error (1, errno, "cannot read %s", rcsbuf->filename);
1889 rcsbuf->ptrend += got;
1894 /* Copy the value VAL returned by rcsbuf_getkey into a memory buffer,
1895 returning the memory buffer. Polish the value like
1896 rcsbuf_valpolish, q.v. */
1899 rcsbuf_valcopy (rcsbuf, val, polish, lenp)
1900 struct rcsbuffer *rcsbuf;
1916 vlen = rcsbuf->vlen;
1917 embedded_at = rcsbuf->embedded_at;
1919 ret = xmalloc (vlen - embedded_at + 1);
1921 if (rcsbuf->at_string ? embedded_at == 0 : ! polish)
1923 /* No special action to take. */
1924 memcpy (ret, val, vlen + 1);
1930 rcsbuf_valpolish_internal (rcsbuf, ret, val, lenp);
1934 /* Polish the value VAL returned by rcsbuf_getkey. The POLISH
1935 parameter is non-zero if multiple embedded whitespace characters
1936 should be compressed into a single whitespace character. Note that
1937 leading and trailing whitespace was already removed by
1938 rcsbuf_getkey. Within an '@' string, pairs of '@' characters are
1939 compressed into a single '@' character regardless of the value of
1940 POLISH. If LENP is not NULL, set *LENP to the length of the value. */
1943 rcsbuf_valpolish (rcsbuf, val, polish, lenp)
1944 struct rcsbuffer *rcsbuf;
1956 if (rcsbuf->at_string ? rcsbuf->embedded_at == 0 : ! polish)
1958 /* No special action to take. */
1960 *lenp = rcsbuf->vlen;
1964 rcsbuf_valpolish_internal (rcsbuf, val, val, lenp);
1967 /* Internal polishing routine, called from rcsbuf_valcopy and
1968 rcsbuf_valpolish. */
1971 rcsbuf_valpolish_internal (rcsbuf, to, from, lenp)
1972 struct rcsbuffer *rcsbuf;
1981 if (! rcsbuf->at_string)
1988 for (clen = len; clen > 0; ++from, --clen)
1995 /* Note that we know that clen can not drop to zero
1996 while we have whitespace, because we know there is
1997 no trailing whitespace. */
1998 while (whitespace (from[1]))
2011 *lenp = to - orig_to;
2015 const char *orig_from;
2023 embedded_at = rcsbuf->embedded_at;
2026 *lenp = len - embedded_at;
2028 for (clen = len; clen > 0; ++from, --clen)
2039 if (*from != '@' || clen == 0)
2045 if (embedded_at == 0)
2047 /* We've found all the embedded '@' characters.
2048 We can just memcpy the rest of the buffer after
2049 this '@' character. */
2050 if (orig_to != orig_from)
2051 memcpy (to, from + 1, clen - 1);
2053 memmove (to, from + 1, clen - 1);
2062 if (from != orig_from + len
2063 || to != orig_to + (len - rcsbuf->embedded_at))
2072 /* Return the current position of an rcsbuf. */
2074 static unsigned long
2075 rcsbuf_ftell (rcsbuf)
2076 struct rcsbuffer *rcsbuf;
2078 return rcsbuf->pos + (rcsbuf->ptr - rcsbuf_buffer);
2081 /* Return a pointer to any data buffered for RCSBUF, along with the
2085 rcsbuf_get_buffered (rcsbuf, datap, lenp)
2086 struct rcsbuffer *rcsbuf;
2090 *datap = rcsbuf->ptr;
2091 *lenp = rcsbuf->ptrend - rcsbuf->ptr;
2094 /* CVS optimizes by quickly reading some header information from a
2095 file. If it decides it needs to do more with the file, it reopens
2096 it. We speed that up here by maintaining a cache of a single open
2097 file, to save the time it takes to reopen the file in the common
2100 static RCSNode *cached_rcs;
2101 static struct rcsbuffer cached_rcsbuf;
2103 /* Cache RCS and RCSBUF. This takes responsibility for closing
2107 rcsbuf_cache (rcs, rcsbuf)
2109 struct rcsbuffer *rcsbuf;
2111 if (cached_rcs != NULL)
2112 rcsbuf_cache_close ();
2115 cached_rcsbuf = *rcsbuf;
2118 /* If there is anything in the cache, close it. */
2121 rcsbuf_cache_close ()
2123 if (cached_rcs != NULL)
2125 if (fclose (cached_rcsbuf.fp) != 0)
2126 error (0, errno, "cannot close %s", cached_rcsbuf.filename);
2127 rcsbuf_close (&cached_rcsbuf);
2128 freercsnode (&cached_rcs);
2133 /* Open an rcsbuffer for RCS, getting it from the cache if possible.
2134 Set *FPP to the file, and *RCSBUFP to the rcsbuf. The file should
2135 be put at position POS. */
2138 rcsbuf_cache_open (rcs, pos, pfp, prcsbuf)
2142 struct rcsbuffer *prcsbuf;
2144 if (cached_rcs == rcs)
2146 if (rcsbuf_ftell (&cached_rcsbuf) != pos)
2148 if (fseek (cached_rcsbuf.fp, pos, SEEK_SET) != 0)
2149 error (1, 0, "cannot fseek RCS file %s",
2150 cached_rcsbuf.filename);
2151 cached_rcsbuf.ptr = rcsbuf_buffer;
2152 cached_rcsbuf.ptrend = rcsbuf_buffer;
2153 cached_rcsbuf.pos = pos;
2155 *pfp = cached_rcsbuf.fp;
2157 /* When RCS_parse opens a file using fopen_case, it frees the
2158 filename which we cached in CACHED_RCSBUF and stores a new
2159 file name in RCS->PATH. We avoid problems here by always
2160 copying the filename over. FIXME: This is hackish. */
2161 cached_rcsbuf.filename = rcs->path;
2163 *prcsbuf = cached_rcsbuf;
2167 /* Removing RCS from the cache removes a reference to it. */
2169 if (rcs->refcount <= 0)
2170 error (1, 0, "rcsbuf_cache_open: internal error");
2174 if (cached_rcs != NULL)
2175 rcsbuf_cache_close ();
2177 *pfp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ);
2179 error (1, 0, "unable to reopen `%s'", rcs->path);
2182 if (fseek (*pfp, pos, SEEK_SET) != 0)
2183 error (1, 0, "cannot fseek RCS file %s", rcs->path);
2185 rcsbuf_open (prcsbuf, *pfp, rcs->path, pos);
2191 * process the symbols list of the rcs file
2194 do_symbols (list, val)
2204 /* skip leading whitespace */
2205 while (whitespace (*cp))
2208 /* if we got to the end, we are done */
2212 /* split it up into tag and rev */
2214 cp = strchr (cp, ':');
2217 while (!whitespace (*cp) && *cp != '\0')
2222 /* make a new node and add it to the list */
2224 p->key = xstrdup (tag);
2225 p->data = xstrdup (rev);
2226 (void) addnode (list, p);
2231 * process the locks list of the rcs file
2232 * Like do_symbols, but hash entries are keyed backwards: i.e.
2233 * an entry like `user:rev' is keyed on REV rather than on USER.
2236 do_locks (list, val)
2246 /* skip leading whitespace */
2247 while (whitespace (*cp))
2250 /* if we got to the end, we are done */
2254 /* split it up into user and rev */
2256 cp = strchr (cp, ':');
2259 while (!whitespace (*cp) && *cp != '\0')
2264 /* make a new node and add it to the list */
2266 p->key = xstrdup (rev);
2267 p->data = xstrdup (user);
2268 (void) addnode (list, p);
2273 * process the branches list of a revision delta
2276 do_branches (list, val)
2286 /* skip leading whitespace */
2287 while (whitespace (*cp))
2290 /* if we got to the end, we are done */
2294 /* find the end of this branch */
2296 while (!whitespace (*cp) && *cp != '\0')
2301 /* make a new node and add it to the list */
2303 p->key = xstrdup (branch);
2304 (void) addnode (list, p);
2311 * Returns the requested version number of the RCS file, satisfying tags and/or
2312 * dates, and walking branches, if necessary.
2314 * The result is returned; null-string if error.
2317 RCS_getversion (rcs, tag, date, force_tag_match, simple_tag)
2321 int force_tag_match;
2324 if (simple_tag != NULL)
2327 /* make sure we have something to look at... */
2328 assert (rcs != NULL);
2334 if (! RCS_nodeisbranch (rcs, tag))
2336 /* We can't get a particular date if the tag is not a
2341 /* Work out the branch. */
2342 if (! isdigit (tag[0]))
2343 branch = RCS_whatbranch (rcs, tag);
2345 branch = xstrdup (tag);
2347 /* Fetch the revision of branch as of date. */
2348 rev = RCS_getdatebranch (rcs, date, branch);
2353 return (RCS_gettag (rcs, tag, force_tag_match, simple_tag));
2355 return (RCS_getdate (rcs, date, force_tag_match));
2357 return (RCS_head (rcs));
2362 * Get existing revision number corresponding to tag or revision.
2363 * Similar to RCS_gettag but less interpretation imposed.
2365 * -- If tag designates a magic branch, RCS_tag2rev
2366 * returns the magic branch number.
2367 * -- If tag is a branch tag, returns the branch number, not
2368 * the revision of the head of the branch.
2369 * If tag or revision is not valid or does not exist in file,
2373 RCS_tag2rev (rcs, tag)
2377 char *rev, *pa, *pb;
2380 assert (rcs != NULL);
2382 if (rcs->flags & PARTIAL)
2383 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2385 /* If a valid revision, try to look it up */
2386 if ( RCS_valid_rev (tag) )
2388 /* Make a copy so we can scribble on it */
2389 rev = xstrdup (tag);
2391 /* If revision exists, return the copy */
2392 if (RCS_exist_rev (rcs, tag))
2395 /* Nope, none such. If tag is not a branch we're done. */
2399 pa = strrchr (rev, '.');
2400 if (i == 1 || *(pa-1) != RCS_MAGIC_BRANCH || *(pa-2) != '.')
2403 error (1, 0, "revision `%s' does not exist", tag);
2407 /* Tag is branch, but does not exist, try corresponding
2410 * FIXME: assumes all magic branches are of
2411 * form "n.n.n ... .0.n". I'll fix if somebody can
2412 * send me a method to get a magic branch tag with
2413 * the 0 in some other position -- <dan@gasboy.com>
2415 pa = strrchr (rev, '.');
2416 pb = xmalloc (strlen (rev) + 3);
2418 (void) sprintf (pb, "%s.%d.%s", rev, RCS_MAGIC_BRANCH, pa);
2421 if (RCS_exist_rev (rcs, rev))
2423 error (1, 0, "revision `%s' does not exist", tag);
2427 RCS_check_tag (tag); /* exit if not a valid tag */
2429 /* If tag is "HEAD", special case to get head RCS revision */
2430 if (tag && (strcmp (tag, TAG_HEAD) == 0))
2431 return (RCS_head (rcs));
2433 /* If valid tag let translate_symtag say yea or nay. */
2434 rev = translate_symtag (rcs, tag);
2439 error (1, 0, "tag `%s' does not exist", tag);
2440 /* NOT REACHED -- error (1 ... ) does not return here */
2445 * Find the revision for a specific tag.
2446 * If force_tag_match is set, return NULL if an exact match is not
2447 * possible otherwise return RCS_head (). We are careful to look for
2448 * and handle "magic" revisions specially.
2450 * If the matched tag is a branch tag, find the head of the branch.
2452 * Returns pointer to newly malloc'd string, or NULL.
2455 RCS_gettag (rcs, symtag, force_tag_match, simple_tag)
2458 int force_tag_match;
2462 int tag_allocated = 0;
2464 if (simple_tag != NULL)
2467 /* make sure we have something to look at... */
2468 assert (rcs != NULL);
2470 /* XXX this is probably not necessary, --jtc */
2471 if (rcs->flags & PARTIAL)
2472 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2474 /* If tag is "HEAD", special case to get head RCS revision */
2475 if (tag && (STREQ (tag, TAG_HEAD) || *tag == '\0'))
2476 #if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */
2477 if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
2478 return ((char *) NULL); /* head request for removed file */
2481 return (RCS_head (rcs));
2483 if (!isdigit (tag[0]))
2487 /* If we got a symbolic tag, resolve it to a numeric */
2488 version = translate_symtag (rcs, tag);
2489 if (version != NULL)
2492 char *magic, *branch, *cp;
2498 * If this is a magic revision, we turn it into either its
2499 * physical branch equivalent (if one exists) or into
2500 * its base revision, which we assume exists.
2502 dots = numdots (tag);
2503 if (dots > 2 && (dots & 1) != 0)
2505 branch = strrchr (tag, '.');
2510 /* see if we have .magic-branch. (".0.") */
2511 magic = xmalloc (strlen (tag) + 1);
2512 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2513 if (strncmp (magic, cp, strlen (magic)) == 0)
2515 /* it's magic. See if the branch exists */
2516 *cp = '\0'; /* turn it into a revision */
2517 (void) sprintf (magic, "%s.%s", tag, branch);
2518 branch = RCS_getbranch (rcs, magic, 1);
2532 /* The tag wasn't there, so return the head or NULL */
2533 if (force_tag_match)
2536 return (RCS_head (rcs));
2541 * numeric tag processing:
2542 * 1) revision number - just return it
2543 * 2) branch number - find head of branch
2546 /* strip trailing dots */
2547 while (tag[strlen (tag) - 1] == '.')
2548 tag[strlen (tag) - 1] = '\0';
2550 if ((numdots (tag) & 1) == 0)
2554 /* we have a branch tag, so we need to walk the branch */
2555 branch = RCS_getbranch (rcs, tag, force_tag_match);
2564 /* we have a revision tag, so make sure it exists */
2565 p = findnode (rcs->versions, tag);
2568 /* We have found a numeric revision for the revision tag.
2569 To support expanding the RCS keyword Name, if
2570 SIMPLE_TAG is not NULL, tell the the caller that this
2571 is a simple tag which co will recognize. FIXME: Are
2572 there other cases in which we should set this? In
2573 particular, what if we expand RCS keywords internally
2574 without calling co? */
2575 if (simple_tag != NULL)
2577 if (! tag_allocated)
2578 tag = xstrdup (tag);
2583 /* The revision wasn't there, so return the head or NULL */
2586 if (force_tag_match)
2589 return (RCS_head (rcs));
2595 * Return a "magic" revision as a virtual branch off of REV for the RCS file.
2596 * A "magic" revision is one which is unique in the RCS file. By unique, I
2597 * mean we return a revision which:
2598 * - has a branch of 0 (see rcs.h RCS_MAGIC_BRANCH)
2599 * - has a revision component which is not an existing branch off REV
2600 * - has a revision component which is not an existing magic revision
2601 * - is an even-numbered revision, to avoid conflicts with vendor branches
2602 * The first point is what makes it "magic".
2604 * As an example, if we pass in 1.37 as REV, we will look for an existing
2605 * branch called 1.37.2. If it did not exist, we would look for an
2606 * existing symbolic tag with a numeric part equal to 1.37.0.2. If that
2607 * didn't exist, then we know that the 1.37.2 branch can be reserved by
2608 * creating a symbolic tag with 1.37.0.2 as the numeric part.
2610 * This allows us to fork development with very little overhead -- just a
2611 * symbolic tag is used in the RCS file. When a commit is done, a physical
2612 * branch is dynamically created to hold the new revision.
2614 * Note: We assume that REV is an RCS revision and not a branch number.
2616 static char *check_rev;
2618 RCS_magicrev (rcs, rev)
2623 char *xrev, *test_branch, *local_branch_num;
2625 xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */
2628 local_branch_num = getenv("CVS_LOCAL_BRANCH_NUM");
2629 if (local_branch_num)
2631 rev_num = atoi(local_branch_num);
2640 /* only look at even numbered branches */
2641 for ( ; ; rev_num += 2)
2643 /* see if the physical branch exists */
2644 (void) sprintf (xrev, "%s.%d", rev, rev_num);
2645 test_branch = RCS_getbranch (rcs, xrev, 1);
2646 if (test_branch != NULL) /* it did, so keep looking */
2652 /* now, create a "magic" revision */
2653 (void) sprintf (xrev, "%s.%d.%d", rev, RCS_MAGIC_BRANCH, rev_num);
2655 /* walk the symbols list to see if a magic one already exists */
2656 if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0)
2659 /* we found a free magic branch. Claim it as ours */
2665 * walklist proc to look for a match in the symbols list.
2666 * Returns 0 if the symbol does not match, 1 if it does.
2669 checkmagic_proc (p, closure)
2673 if (STREQ (check_rev, p->data))
2680 * Given an RCSNode, returns non-zero if the specified revision number
2681 * or symbolic tag resolves to a "branch" within the rcs file.
2683 * FIXME: this is the same as RCS_nodeisbranch except for the special
2684 * case for handling a null rcsnode.
2687 RCS_isbranch (rcs, rev)
2691 /* numeric revisions are easy -- even number of dots is a branch */
2693 return ((numdots (rev) & 1) == 0);
2695 /* assume a revision if you can't find the RCS info */
2699 /* now, look for a match in the symbols list */
2700 return (RCS_nodeisbranch (rcs, rev));
2704 * Given an RCSNode, returns non-zero if the specified revision number
2705 * or symbolic tag resolves to a "branch" within the rcs file. We do
2706 * take into account any magic branches as well.
2709 RCS_nodeisbranch (rcs, rev)
2716 assert (rcs != NULL);
2718 /* numeric revisions are easy -- even number of dots is a branch */
2720 return ((numdots (rev) & 1) == 0);
2722 version = translate_symtag (rcs, rev);
2723 if (version == NULL)
2725 dots = numdots (version);
2726 if ((dots & 1) == 0)
2732 /* got a symbolic tag match, but it's not a branch; see if it's magic */
2736 char *branch = strrchr (version, '.');
2737 char *cp = branch - 1;
2741 /* see if we have .magic-branch. (".0.") */
2742 magic = xmalloc (strlen (version) + 1);
2743 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2744 if (strncmp (magic, cp, strlen (magic)) == 0)
2757 * Returns a pointer to malloc'ed memory which contains the branch
2758 * for the specified *symbolic* tag. Magic branches are handled correctly.
2761 RCS_whatbranch (rcs, rev)
2768 /* assume no branch if you can't find the RCS info */
2770 return ((char *) NULL);
2772 /* now, look for a match in the symbols list */
2773 version = translate_symtag (rcs, rev);
2774 if (version == NULL)
2775 return ((char *) NULL);
2776 dots = numdots (version);
2777 if ((dots & 1) == 0)
2780 /* got a symbolic tag match, but it's not a branch; see if it's magic */
2784 char *branch = strrchr (version, '.');
2785 char *cp = branch++ - 1;
2789 /* see if we have .magic-branch. (".0.") */
2790 magic = xmalloc (strlen (version) + 1);
2791 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2792 if (strncmp (magic, cp, strlen (magic)) == 0)
2794 /* yep. it's magic. now, construct the real branch */
2795 *cp = '\0'; /* turn it into a revision */
2796 (void) sprintf (magic, "%s.%s", version, branch);
2803 return ((char *) NULL);
2807 * Get the head of the specified branch. If the branch does not exist,
2808 * return NULL or RCS_head depending on force_tag_match.
2809 * Returns NULL or a newly malloc'd string.
2812 RCS_getbranch (rcs, tag, force_tag_match)
2815 int force_tag_match;
2823 /* make sure we have something to look at... */
2824 assert (rcs != NULL);
2826 if (rcs->flags & PARTIAL)
2827 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2829 /* find out if the tag contains a dot, or is on the trunk */
2830 cp = strrchr (tag, '.');
2832 /* trunk processing is the special case */
2835 xtag = xmalloc (strlen (tag) + 1 + 1); /* +1 for an extra . */
2836 (void) strcpy (xtag, tag);
2837 (void) strcat (xtag, ".");
2838 for (cp = rcs->head; cp != NULL;)
2840 if (strncmp (xtag, cp, strlen (xtag)) == 0)
2842 p = findnode (rcs->versions, cp);
2846 if (force_tag_match)
2849 return (RCS_head (rcs));
2851 vn = (RCSVers *) p->data;
2857 if (force_tag_match)
2860 return (RCS_head (rcs));
2862 return (xstrdup (cp));
2865 /* if it had a `.', terminate the string so we have the base revision */
2868 /* look up the revision this branch is based on */
2869 p = findnode (rcs->versions, tag);
2871 /* put the . back so we have the branch again */
2876 /* if the base revision didn't exist, return head or NULL */
2877 if (force_tag_match)
2880 return (RCS_head (rcs));
2883 /* find the first element of the branch we are looking for */
2884 vn = (RCSVers *) p->data;
2885 if (vn->branches == NULL)
2887 xtag = xmalloc (strlen (tag) + 1 + 1); /* 1 for the extra '.' */
2888 (void) strcpy (xtag, tag);
2889 (void) strcat (xtag, ".");
2890 head = vn->branches->list;
2891 for (p = head->next; p != head; p = p->next)
2892 if (strncmp (p->key, xtag, strlen (xtag)) == 0)
2898 /* we didn't find a match so return head or NULL */
2899 if (force_tag_match)
2902 return (RCS_head (rcs));
2905 /* now walk the next pointers of the branch */
2909 p = findnode (rcs->versions, nextvers);
2912 /* a link in the chain is missing - return head or NULL */
2913 if (force_tag_match)
2916 return (RCS_head (rcs));
2918 vn = (RCSVers *) p->data;
2919 nextvers = vn->next;
2920 } while (nextvers != NULL);
2922 /* we have the version in our hand, so go for it */
2923 return (xstrdup (vn->version));
2926 /* Returns the head of the branch which REV is on. REV can be a
2927 branch tag or non-branch tag; symbolic or numeric.
2929 Returns a newly malloc'd string. Returns NULL if a symbolic name
2933 RCS_branch_head (rcs, rev)
2941 assert (rcs != NULL);
2943 if (RCS_nodeisbranch (rcs, rev))
2944 return RCS_getbranch (rcs, rev, 1);
2947 num = xstrdup (rev);
2950 num = translate_symtag (rcs, rev);
2954 br = truncate_revnum (num);
2955 retval = RCS_getbranch (rcs, br, 1);
2961 /* Get the branch point for a particular branch, that is the first
2962 revision on that branch. For example, RCS_getbranchpoint (rcs,
2963 "1.3.2") will normally return "1.3.2.1". TARGET may be either a
2964 branch number or a revision number; if a revnum, find the
2965 branchpoint of the branch to which TARGET belongs.
2967 Return RCS_head if TARGET is on the trunk or if the root node could
2968 not be found (this is sort of backwards from our behavior on a branch;
2969 the rationale is that the return value is a revision from which you
2970 can start walking the next fields and end up at TARGET).
2971 Return NULL on error. */
2974 RCS_getbranchpoint (rcs, target)
2981 int dots, isrevnum, brlen;
2983 dots = numdots (target);
2984 isrevnum = dots & 1;
2987 /* TARGET is a trunk revision; return rcs->head. */
2988 return (RCS_head (rcs));
2990 /* Get the revision number of the node at which TARGET's branch is
2991 rooted. If TARGET is a branch number, lop off the last field;
2992 if it's a revision number, lop off the last *two* fields. */
2993 branch = xstrdup (target);
2994 bp = strrchr (branch, '.');
2996 error (1, 0, "%s: confused revision number %s",
2999 while (*--bp != '.')
3003 vp = findnode (rcs->versions, branch);
3006 error (0, 0, "%s: can't find branch point %s", rcs->path, target);
3009 rev = (RCSVers *) vp->data;
3012 while (*bp && *bp != '.')
3014 brlen = bp - branch;
3016 vp = rev->branches->list->next;
3017 while (vp != rev->branches->list)
3019 /* BRANCH may be a genuine branch number, e.g. `1.1.3', or
3020 maybe a full revision number, e.g. `1.1.3.6'. We have
3021 found our branch point if the first BRANCHLEN characters
3022 of the revision number match, *and* if the following
3023 character is a dot. */
3024 if (strncmp (vp->key, branch, brlen) == 0 && vp->key[brlen] == '.')
3030 if (vp == rev->branches->list)
3032 error (0, 0, "%s: can't find branch point %s", rcs->path, target);
3036 return (xstrdup (vp->key));
3040 * Get the head of the RCS file. If branch is set, this is the head of the
3041 * branch, otherwise the real head.
3042 * Returns NULL or a newly malloc'd string.
3048 /* make sure we have something to look at... */
3049 assert (rcs != NULL);
3052 * NOTE: we call getbranch with force_tag_match set to avoid any
3053 * possibility of recursion
3056 return (RCS_getbranch (rcs, rcs->branch, 1));
3058 return (xstrdup (rcs->head));
3062 * Get the most recent revision, based on the supplied date, but use some
3063 * funky stuff and follow the vendor branch maybe
3066 RCS_getdate (rcs, date, force_tag_match)
3069 int force_tag_match;
3071 char *cur_rev = NULL;
3072 char *retval = NULL;
3074 RCSVers *vers = NULL;
3076 /* make sure we have something to look at... */
3077 assert (rcs != NULL);
3079 if (rcs->flags & PARTIAL)
3080 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3082 /* if the head is on a branch, try the branch first */
3083 if (rcs->branch != NULL)
3084 retval = RCS_getdatebranch (rcs, date, rcs->branch);
3086 /* if we found a match, we are done */
3090 /* otherwise if we have a trunk, try it */
3093 p = findnode (rcs->versions, rcs->head);
3096 /* if the date of this one is before date, take it */
3097 vers = (RCSVers *) p->data;
3098 if (RCS_datecmp (vers->date, date) <= 0)
3100 cur_rev = vers->version;
3104 /* if there is a next version, find the node */
3105 if (vers->next != NULL)
3106 p = findnode (rcs->versions, vers->next);
3113 * at this point, either we have the revision we want, or we have the
3114 * first revision on the trunk (1.1?) in our hands
3117 /* if we found what we're looking for, and it's not 1.1 return it */
3118 if (cur_rev != NULL && ! STREQ (cur_rev, "1.1"))
3119 return (xstrdup (cur_rev));
3121 /* look on the vendor branch */
3122 retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
3125 * if we found a match, return it; otherwise, we return the first
3126 * revision on the trunk or NULL depending on force_tag_match and the
3127 * date of the first rev
3132 if (!force_tag_match || RCS_datecmp (vers->date, date) <= 0)
3133 return (xstrdup (vers->version));
3139 * Look up the last element on a branch that was put in before the specified
3140 * date (return the rev or NULL)
3143 RCS_getdatebranch (rcs, date, branch)
3148 char *cur_rev = NULL;
3150 char *xbranch, *xrev;
3154 /* look up the first revision on the branch */
3155 xrev = xstrdup (branch);
3156 cp = strrchr (xrev, '.');
3162 *cp = '\0'; /* turn it into a revision */
3164 assert (rcs != NULL);
3166 if (rcs->flags & PARTIAL)
3167 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3169 p = findnode (rcs->versions, xrev);
3173 vers = (RCSVers *) p->data;
3175 /* Tentatively use this revision, if it is early enough. */
3176 if (RCS_datecmp (vers->date, date) <= 0)
3177 cur_rev = vers->version;
3179 /* If no branches list, return now. This is what happens if the branch
3180 is a (magic) branch with no revisions yet. */
3181 if (vers->branches == NULL)
3182 return xstrdup (cur_rev);
3184 /* walk the branches list looking for the branch number */
3185 xbranch = xmalloc (strlen (branch) + 1 + 1); /* +1 for the extra dot */
3186 (void) strcpy (xbranch, branch);
3187 (void) strcat (xbranch, ".");
3188 for (p = vers->branches->list->next; p != vers->branches->list; p = p->next)
3189 if (strncmp (p->key, xbranch, strlen (xbranch)) == 0)
3192 if (p == vers->branches->list)
3194 /* This is what happens if the branch is a (magic) branch with
3195 no revisions yet. Similar to the case where vers->branches ==
3196 NULL, except here there was a another branch off the same
3198 return xstrdup (cur_rev);
3201 p = findnode (rcs->versions, p->key);
3203 /* walk the next pointers until you find the end, or the date is too late */
3206 vers = (RCSVers *) p->data;
3207 if (RCS_datecmp (vers->date, date) <= 0)
3208 cur_rev = vers->version;
3212 /* if there is a next version, find the node */
3213 if (vers->next != NULL)
3214 p = findnode (rcs->versions, vers->next);
3219 /* Return whatever we found, which may be NULL. */
3220 return xstrdup (cur_rev);
3224 * Compare two dates in RCS format. Beware the change in format on January 1,
3225 * 2000, when years go from 2-digit to full format.
3228 RCS_datecmp (date1, date2)
3229 char *date1, *date2;
3231 int length_diff = strlen (date1) - strlen (date2);
3233 return (length_diff ? length_diff : strcmp (date1, date2));
3236 /* Look up revision REV in RCS and return the date specified for the
3237 revision minus FUDGE seconds (FUDGE will generally be one, so that the
3238 logically previous revision will be found later, or zero, if we want
3241 The return value is the date being returned as a time_t, or (time_t)-1
3242 on error (previously was documented as zero on error; I haven't checked
3243 the callers to make sure that they really check for (time_t)-1, but
3244 the latter is what this function really returns). If DATE is non-NULL,
3245 then it must point to MAXDATELEN characters, and we store the same
3246 return value there in DATEFORM format. */
3248 RCS_getrevtime (rcs, rev, date, fudge)
3254 char tdate[MAXDATELEN];
3255 struct tm xtm, *ftm;
3260 /* make sure we have something to look at... */
3261 assert (rcs != NULL);
3263 if (rcs->flags & PARTIAL)
3264 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3266 /* look up the revision */
3267 p = findnode (rcs->versions, rev);
3270 vers = (RCSVers *) p->data;
3272 /* split up the date */
3274 (void) sscanf (vers->date, SDATEFORM, &ftm->tm_year, &ftm->tm_mon,
3275 &ftm->tm_mday, &ftm->tm_hour, &ftm->tm_min,
3278 /* If the year is from 1900 to 1999, RCS files contain only two
3279 digits, and sscanf gives us a year from 0-99. If the year is
3280 2000+, RCS files contain all four digits and we subtract 1900,
3281 because the tm_year field should contain years since 1900. */
3283 if (ftm->tm_year > 1900)
3284 ftm->tm_year -= 1900;
3286 /* put the date in a form getdate can grok */
3287 (void) sprintf (tdate, "%d/%d/%d GMT %d:%d:%d", ftm->tm_mon,
3288 ftm->tm_mday, ftm->tm_year + 1900, ftm->tm_hour,
3289 ftm->tm_min, ftm->tm_sec);
3291 /* turn it into seconds since the epoch */
3292 revdate = get_date (tdate, (struct timeb *) NULL);
3293 if (revdate != (time_t) -1)
3295 revdate -= fudge; /* remove "fudge" seconds */
3298 /* put an appropriate string into ``date'' if we were given one */
3299 ftm = gmtime (&revdate);
3300 (void) sprintf (date, DATEFORM,
3301 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
3302 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
3303 ftm->tm_min, ftm->tm_sec);
3313 assert(rcs != NULL);
3315 if (rcs->flags & PARTIAL)
3316 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3318 if (rcs->locks_data) {
3319 rcs->locks = getlist ();
3320 do_locks (rcs->locks, rcs->locks_data);
3321 free(rcs->locks_data);
3322 rcs->locks_data = NULL;
3332 assert(rcs != NULL);
3334 if (rcs->flags & PARTIAL)
3335 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3337 if (rcs->symbols_data) {
3338 rcs->symbols = getlist ();
3339 do_symbols (rcs->symbols, rcs->symbols_data);
3340 free(rcs->symbols_data);
3341 rcs->symbols_data = NULL;
3344 return rcs->symbols;
3348 * Return the version associated with a particular symbolic tag.
3349 * Returns NULL or a newly malloc'd string.
3352 translate_symtag (rcs, tag)
3356 if (rcs->flags & PARTIAL)
3357 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3359 if (rcs->symbols != NULL)
3363 /* The symbols have already been converted into a list. */
3364 p = findnode (rcs->symbols, tag);
3368 return xstrdup (p->data);
3371 if (rcs->symbols_data != NULL)
3376 /* Look through the RCS symbols information. This is like
3377 do_symbols, but we don't add the information to a list. In
3378 most cases, we will only be called once for this file, so
3379 generating the list is unnecessary overhead. */
3382 cp = rcs->symbols_data;
3383 while ((cp = strchr (cp, tag[0])) != NULL)
3385 if ((cp == rcs->symbols_data || whitespace (cp[-1]))
3386 && strncmp (cp, tag, len) == 0
3391 /* We found the tag. Return the version number. */
3395 while (! whitespace (*cp) && *cp != '\0')
3397 r = xmalloc (cp - v + 1);
3398 strncpy (r, v, cp - v);
3403 while (! whitespace (*cp) && *cp != '\0')
3412 * The argument ARG is the getopt remainder of the -k option specified on the
3413 * command line. This function returns malloc'ed space that can be used
3414 * directly in calls to RCS V5, with the -k flag munged correctly.
3417 RCS_check_kflag (arg)
3420 static const char *const keyword_usage[] =
3422 "%s %s: invalid RCS keyword expansion mode\n",
3423 "Valid expansion modes include:\n",
3424 " -kkv\tGenerate keywords using the default form.\n",
3425 " -kkvl\tLike -kkv, except locker's name inserted.\n",
3426 " -kk\tGenerate only keyword names in keyword strings.\n",
3427 " -kv\tGenerate only keyword values in keyword strings.\n",
3428 " -ko\tGenerate the old keyword string (no changes from checked in file).\n",
3429 " -kb\tGenerate binary file unmodified (merges not allowed) (RCS 5.7).\n",
3430 "(Specify the --help global option for a list of other help options)\n",
3433 /* Big enough to hold any of the strings from kflags. */
3435 char const *const *cpp = NULL;
3439 for (cpp = kflags; *cpp != NULL; cpp++)
3441 if (STREQ (arg, *cpp))
3446 if (arg == NULL || *cpp == NULL)
3448 usage (keyword_usage);
3451 (void) sprintf (karg, "-k%s", *cpp);
3452 return (xstrdup (karg));
3456 * Do some consistency checks on the symbolic tag... These should equate
3457 * pretty close to what RCS checks, though I don't know for certain.
3463 char *invalid = "$,.:;@"; /* invalid RCS tag characters */
3467 * The first character must be an alphabetic letter. The remaining
3468 * characters cannot be non-visible graphic characters, and must not be
3469 * in the set of "invalid" RCS identifier characters.
3473 for (cp = tag; *cp; cp++)
3476 error (1, 0, "tag `%s' has non-visible graphic characters",
3478 if (strchr (invalid, *cp))
3479 error (1, 0, "tag `%s' must not contain the characters `%s'",
3484 error (1, 0, "tag `%s' must start with a letter", tag);
3488 * TRUE if argument has valid syntax for an RCS revision or
3489 * branch number. All characters must be digits or dots, first
3490 * and last characters must be digits, and no two consecutive
3491 * characters may be dots.
3493 * Intended for classifying things, so this function doesn't
3502 if (!isdigit (last))
3504 while ((c = *rev++)) /* Extra parens placate -Wall gcc option */
3516 if (!isdigit (last))
3522 * Return true if RCS revision with TAG is a dead revision.
3525 RCS_isdead (rcs, tag)
3532 if (rcs->flags & PARTIAL)
3533 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3535 p = findnode (rcs->versions, tag);
3539 version = (RCSVers *) p->data;
3540 return (version->dead);
3543 /* Return the RCS keyword expansion mode. For example "b" for binary.
3544 Returns a pointer into storage which is allocated and freed along with
3545 the rest of the RCS information; the caller should not modify this
3546 storage. Returns NULL if the RCS file does not specify a keyword
3547 expansion mode; for all other errors, die with a fatal error. */
3552 assert (rcs != NULL);
3556 /* RCS keywords, and a matching enum. */
3563 #define KEYWORD_INIT(s) (s), sizeof (s) - 1
3564 static struct rcs_keyword keywords[] =
3566 { KEYWORD_INIT ("Author"), 1 },
3567 { KEYWORD_INIT ("Date"), 1 },
3568 { KEYWORD_INIT ("CVSHeader"), 1 },
3569 { KEYWORD_INIT ("Header"), 1 },
3570 { KEYWORD_INIT ("Id"), 1 },
3571 { KEYWORD_INIT ("Locker"), 1 },
3572 { KEYWORD_INIT ("Log"), 1 },
3573 { KEYWORD_INIT ("Name"), 1 },
3574 { KEYWORD_INIT ("RCSfile"), 1 },
3575 { KEYWORD_INIT ("Revision"), 1 },
3576 { KEYWORD_INIT ("Source"), 1 },
3577 { KEYWORD_INIT ("State"), 1 },
3597 enum keyword keyword_local = KEYWORD_ID;
3599 /* Convert an RCS date string into a readable string. This is like
3600 the RCS date2str function. */
3603 printable_date (rcs_date)
3604 const char *rcs_date;
3606 int year, mon, mday, hour, min, sec;
3609 (void) sscanf (rcs_date, SDATEFORM, &year, &mon, &mday, &hour, &min,
3613 sprintf (buf, "%04d/%02d/%02d %02d:%02d:%02d", year, mon, mday,
3615 return xstrdup (buf);
3618 /* Escape the characters in a string so that it can be included in an
3622 escape_keyword_value (value, free_value)
3629 for (s = value; *s != '\0'; s++)
3647 return (char *) value;
3650 ret = xmalloc (strlen (value) * 4 + 1);
3653 for (s = value, t = ret; *s != '\0'; s++, t++)
3692 /* Expand RCS keywords in the memory buffer BUF of length LEN. This
3693 applies to file RCS and version VERS. If NAME is not NULL, and is
3694 not a numeric revision, then it is the symbolic tag used for the
3695 checkout. EXPAND indicates how to expand the keywords. This
3696 function sets *RETBUF and *RETLEN to the new buffer and length.
3697 This function may modify the buffer BUF. If BUF != *RETBUF, then
3698 RETBUF is a newly allocated buffer. */
3701 expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
3713 struct expand_buffer
3715 struct expand_buffer *next;
3720 struct expand_buffer *ebuf_last = NULL;
3721 size_t ebuf_len = 0;
3723 char *srch, *srch_next;
3726 if (expand == KFLAG_O || expand == KFLAG_B)
3733 /* If we are using -kkvl, dig out the locker information if any. */
3735 if (expand == KFLAG_KVL)
3738 lock = findnode (RCS_getlocks(rcs), ver->version);
3740 locker = xstrdup (lock->data);
3743 /* RCS keywords look like $STRING$ or $STRING: VALUE$. */
3746 while ((srch_next = memchr (srch, '$', srch_len)) != NULL)
3750 const struct rcs_keyword *keyword;
3757 srch_len -= (srch_next + 1) - srch;
3758 srch = srch_next + 1;
3760 /* Look for the first non alphabetic character after the '$'. */
3761 send = srch + srch_len;
3762 for (s = srch; s < send; s++)
3766 /* If the first non alphabetic character is not '$' or ':',
3767 then this is not an RCS keyword. */
3768 if (s == send || (*s != '$' && *s != ':'))
3771 /* See if this is one of the keywords. */
3773 for (keyword = keywords; keyword->string != NULL; keyword++)
3775 if (keyword->expandit
3776 && keyword->len == slen
3777 && strncmp (keyword->string, srch, slen) == 0)
3782 if (keyword->string == NULL)
3785 kw = (enum keyword) (keyword - keywords);
3787 /* If the keyword ends with a ':', then the old value consists
3788 of the characters up to the next '$'. If there is no '$'
3789 before the end of the line, though, then this wasn't an RCS
3790 keyword after all. */
3793 for (; s < send; s++)
3794 if (*s == '$' || *s == '\n')
3796 if (s == send || *s != '$')
3800 /* At this point we must replace the string from SRCH to S
3801 with the expansion of the keyword KW. */
3803 /* Get the value to use. */
3805 if (expand == KFLAG_K)
3814 case KEYWORD_AUTHOR:
3815 value = ver->author;
3819 value = printable_date (ver->date);
3823 case KEYWORD_CVSHEADER:
3824 case KEYWORD_HEADER:
3826 case KEYWORD_LOCALID:
3834 if (kw == KEYWORD_HEADER ||
3835 (kw == KEYWORD_LOCALID &&
3836 keyword_local == KEYWORD_HEADER))
3838 else if (kw == KEYWORD_CVSHEADER ||
3839 (kw == KEYWORD_LOCALID &&
3840 keyword_local == KEYWORD_CVSHEADER))
3841 path = getfullCVSname(rcs->path, &old_path);
3843 path = last_component (rcs->path);
3844 path = escape_keyword_value (path, &free_path);
3845 date = printable_date (ver->date);
3846 value = xmalloc (strlen (path)
3847 + strlen (ver->version)
3849 + strlen (ver->author)
3850 + strlen (ver->state)
3851 + (locker == NULL ? 0 : strlen (locker))
3854 sprintf (value, "%s %s %s %s %s%s%s",
3855 path, ver->version, date, ver->author,
3857 locker != NULL ? " " : "",
3858 locker != NULL ? locker : "");
3868 case KEYWORD_LOCKER:
3873 case KEYWORD_RCSFILE:
3874 value = escape_keyword_value (last_component (rcs->path),
3879 if (name != NULL && ! isdigit (*name))
3880 value = (char *) name;
3885 case KEYWORD_REVISION:
3886 value = ver->version;
3889 case KEYWORD_SOURCE:
3890 value = escape_keyword_value (rcs->path, &free_value);
3899 sub = xmalloc (keyword->len
3900 + (value == NULL ? 0 : strlen (value))
3902 if (expand == KFLAG_V)
3904 /* Decrement SRCH and increment S to remove the $
3913 strcpy (sub, keyword->string);
3914 sublen = strlen (keyword->string);
3915 if (expand != KFLAG_K)
3918 sub[sublen + 1] = ' ';
3924 strcpy (sub + sublen, value);
3925 sublen += strlen (value);
3927 if (expand != KFLAG_V && expand != KFLAG_K)
3937 /* The Log keyword requires special handling. This behaviour
3938 is taken from RCS 5.7. The special log message is what RCS
3940 if (kw == KEYWORD_LOG
3941 && (sizeof "checked in with -k by " <= loglen
3942 || strncmp (log, "checked in with -k by ",
3943 sizeof "checked in with -k by " - 1) != 0))
3947 size_t leader_len, leader_sp_len;
3954 /* We are going to insert the trailing $ ourselves, before
3955 the log message, so we must remove it from S, if we
3956 haven't done so already. */
3957 if (expand != KFLAG_V)
3960 /* Find the start of the line. */
3962 while (start > buf && start[-1] != '\n')
3965 /* Copy the start of the line to use as a comment leader. */
3966 leader_len = srch - start;
3967 if (expand != KFLAG_V)
3969 leader = xmalloc (leader_len);
3970 memcpy (leader, start, leader_len);
3971 leader_sp_len = leader_len;
3972 while (leader_sp_len > 0 && leader[leader_sp_len - 1] == ' ')
3975 /* RCS does some checking for an old style of Log here,
3976 but we don't bother. RCS issues a warning if it
3977 changes anything. */
3979 /* Count the number of newlines in the log message so that
3980 we know how many copies of the leader we will need. */
3982 logend = log + loglen;
3983 for (snl = log; snl < logend; snl++)
3987 date = printable_date (ver->date);
3988 sub = xrealloc (sub,
3991 + strlen (ver->version)
3993 + strlen (ver->author)
3995 + (cnl + 2) * leader_len
3997 if (expand != KFLAG_V)
4004 memcpy (sub + sublen, leader, leader_len);
4005 sublen += leader_len;
4006 sprintf (sub + sublen, "Revision %s %s %s\n",
4007 ver->version, date, ver->author);
4008 sublen += strlen (sub + sublen);
4016 memcpy (sub + sublen, leader, leader_sp_len);
4017 sublen += leader_sp_len;
4026 memcpy (sub + sublen, leader, leader_len);
4027 sublen += leader_len;
4028 for (slnl = sl; slnl < logend && *slnl != '\n'; ++slnl)
4032 memcpy (sub + sublen, sl, slnl - sl);
4033 sublen += slnl - sl;
4038 memcpy (sub + sublen, leader, leader_sp_len);
4039 sublen += leader_sp_len;
4044 /* Now SUB contains a string which is to replace the string
4045 from SRCH to S. SUBLEN is the length of SUB. */
4047 if (srch + sublen == s)
4049 memcpy (srch, sub, sublen);
4054 struct expand_buffer *ebuf;
4056 /* We need to change the size of the buffer. We build a
4057 list of expand_buffer structures. Each expand_buffer
4058 structure represents a portion of the final output. We
4059 concatenate them back into a single buffer when we are
4060 done. This minimizes the number of potentially large
4061 buffer copies we must do. */
4065 ebufs = (struct expand_buffer *) xmalloc (sizeof *ebuf);
4068 ebufs->free_data = 0;
4069 ebuf_len = srch - buf;
4070 ebufs->len = ebuf_len;
4075 assert (srch >= ebuf_last->data);
4076 assert (srch <= ebuf_last->data + ebuf_last->len);
4077 ebuf_len -= ebuf_last->len - (srch - ebuf_last->data);
4078 ebuf_last->len = srch - ebuf_last->data;
4081 ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf);
4084 ebuf->free_data = 1;
4086 ebuf_last->next = ebuf;
4090 ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf);
4092 ebuf->len = srch_len - (s - srch);
4093 ebuf->free_data = 0;
4095 ebuf_last->next = ebuf;
4097 ebuf_len += srch_len - (s - srch);
4100 srch_len -= (s - srch);
4116 ret = xmalloc (ebuf_len);
4119 while (ebufs != NULL)
4121 struct expand_buffer *next;
4123 memcpy (ret, ebufs->data, ebufs->len);
4125 if (ebufs->free_data)
4134 /* Check out a revision from an RCS file.
4136 If PFN is not NULL, then ignore WORKFILE and SOUT. Call PFN zero
4137 or more times with the contents of the file. CALLERDAT is passed,
4138 uninterpreted, to PFN. (The current code will always call PFN
4139 exactly once for a non empty file; however, the current code
4140 assumes that it can hold the entire file contents in memory, which
4141 is not a good assumption, and might change in the future).
4143 Otherwise, if WORKFILE is not NULL, check out the revision to
4144 WORKFILE. However, if WORKFILE is not NULL, and noexec is set,
4145 then don't do anything.
4147 Otherwise, if WORKFILE is NULL, check out the revision to SOUT. If
4148 SOUT is RUN_TTY, then write the contents of the revision to
4149 standard output. When using SOUT, the output is generally a
4150 temporary file; don't bother to get the file modes correct.
4152 REV is the numeric revision to check out. It may be NULL, which
4153 means to check out the head of the default branch.
4155 If NAMETAG is not NULL, and is not a numeric revision, then it is
4156 the tag that should be used when expanding the RCS Name keyword.
4158 OPTIONS is a string such as "-kb" or "-kv" for keyword expansion
4159 options. It may be NULL to use the default expansion mode of the
4160 file, typically "-kkv".
4162 On an error which prevented checking out the file, either print a
4163 nonfatal error and return 1, or give a fatal error. On success,
4166 /* This function mimics the behavior of `rcs co' almost exactly. The
4167 chief difference is in its support for preserving file ownership,
4168 permissions, and special files across checkin and checkout -- see
4169 comments in RCS_checkin for some issues about this. -twp */
4172 RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
4179 RCSCHECKOUTPROC pfn;
4186 struct rcsbuffer rcsbuf;
4194 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4195 uid_t rcs_owner = (uid_t) -1;
4196 gid_t rcs_group = (gid_t) -1;
4198 int change_rcs_owner_or_group = 0;
4199 int change_rcs_mode = 0;
4200 int special_file = 0;
4201 unsigned long devnum_long;
4207 (void) fprintf (stderr, "%s-> checkout (%s, %s, %s, %s)\n",
4208 #ifdef SERVER_SUPPORT
4209 server_active ? "S" : " ",
4214 rev != NULL ? rev : "",
4215 options != NULL ? options : "",
4216 (pfn != NULL ? "(function)"
4219 : (sout != RUN_TTY ? sout : "(stdout)"))));
4222 assert (rev == NULL || isdigit (*rev));
4224 if (noexec && workfile != NULL)
4227 assert (sout == RUN_TTY || workfile == NULL);
4228 assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL));
4230 /* Some callers, such as Checkin or remove_file, will pass us a
4232 if (rev != NULL && (numdots (rev) & 1) == 0)
4234 rev = RCS_getbranch (rcs, rev, 1);
4236 error (1, 0, "internal error: bad branch tag in checkout");
4240 if (rev == NULL || STREQ (rev, rcs->head))
4244 /* We want the head revision. Try to read it directly. */
4246 if (rcs->flags & PARTIAL)
4247 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
4249 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf);
4252 if (! rcsbuf_getrevnum (&rcsbuf, &key))
4253 error (1, 0, "unexpected EOF reading %s", rcs->path);
4254 while (rcsbuf_getkey (&rcsbuf, &key, &value))
4256 if (STREQ (key, "log"))
4257 log = rcsbuf_valcopy (&rcsbuf, value, 0, &loglen);
4258 else if (STREQ (key, "text"))
4267 error (0, 0, "internal error: cannot find head text");
4273 rcsbuf_valpolish (&rcsbuf, value, 0, &len);
4275 if (fstat (fileno (fp), &sb) < 0)
4276 error (1, errno, "cannot fstat %s", rcs->path);
4278 rcsbuf_cache (rcs, &rcsbuf);
4282 struct rcsbuffer *rcsbufp;
4284 /* It isn't the head revision of the trunk. We'll need to
4285 walk through the deltas. */
4288 if (rcs->flags & PARTIAL)
4289 RCS_reparsercsfile (rcs, &fp, &rcsbuf);
4293 /* If RCS_deltas didn't close the file, we could use fstat
4294 here too. Probably should change it thusly.... */
4295 if (stat (rcs->path, &sb) < 0)
4296 error (1, errno, "cannot stat %s", rcs->path);
4301 if (fstat (fileno (fp), &sb) < 0)
4302 error (1, errno, "cannot fstat %s", rcs->path);
4306 RCS_deltas (rcs, fp, rcsbufp, rev, RCS_FETCH, &value, &len,
4311 /* If OPTIONS is NULL or the empty string, then the old code would
4312 invoke the RCS co program with no -k option, which means that
4313 co would use the string we have stored in rcs->expand. */
4314 if ((options == NULL || options[0] == '\0') && rcs->expand == NULL)
4318 const char *ouroptions;
4319 const char * const *cpp;
4321 if (options != NULL && options[0] != '\0')
4323 assert (options[0] == '-' && options[1] == 'k');
4324 ouroptions = options + 2;
4327 ouroptions = rcs->expand;
4329 for (cpp = kflags; *cpp != NULL; cpp++)
4330 if (STREQ (*cpp, ouroptions))
4334 expand = (enum kflag) (cpp - kflags);
4338 "internal error: unsupported substitution string -k%s",
4344 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4345 /* Handle special files and permissions, if that is desired. */
4351 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
4353 error (1, 0, "internal error: no revision information for %s",
4354 rev == NULL ? rcs->head : rev);
4355 vers = (RCSVers *) vp->data;
4357 /* First we look for symlinks, which are simplest to handle. */
4358 info = findnode (vers->other_delta, "symlink");
4363 if (pfn != NULL || (workfile == NULL && sout == RUN_TTY))
4364 error (1, 0, "symbolic link %s:%s cannot be piped",
4365 rcs->path, vers->version);
4366 if (workfile == NULL)
4371 /* Remove `dest', just in case. It's okay to get ENOENT here,
4372 since we just want the file not to be there. (TODO: decide
4373 whether it should be considered an error for `dest' to exist
4374 at this point. If so, the unlink call should be removed and
4375 `symlink' should signal the error. -twp) */
4376 if (unlink (dest) < 0 && !existence_error (errno))
4377 error (1, errno, "cannot remove %s", dest);
4378 if (symlink (info->data, dest) < 0)
4379 error (1, errno, "cannot create symbolic link from %s to %s",
4388 /* Next, we look at this file's hardlinks field, and see whether
4389 it is linked to any other file that has been checked out.
4390 If so, we don't do anything else -- just link it to that file.
4392 If we are checking out a file to a pipe or temporary storage,
4393 none of this should matter. Hence the `workfile != NULL'
4394 wrapper around the whole thing. -twp */
4396 if (workfile != NULL)
4398 List *links = vers->hardlinks;
4401 Node *uptodate_link;
4403 /* For each file in the hardlinks field, check to see
4404 if it exists, and if so, if it has been checked out
4405 this iteration. When walklist returns, uptodate_link
4406 should point to a hardlist node representing a file
4407 in `links' which has recently been checked out, or
4408 NULL if no file in `links' has yet been checked out. */
4410 uptodate_link = NULL;
4411 (void) walklist (links, find_checkedout_proc, &uptodate_link);
4414 /* If we've found a file that `workfile' is supposed to be
4415 linked to, and it has been checked out since CVS was
4416 invoked, then simply link workfile to that file and return.
4418 If one of these conditions is not met, then
4419 workfile is the first one in its hardlink group to
4420 be checked out, and we must continue with a full
4423 if (uptodate_link != NULL)
4425 struct hardlink_info *hlinfo =
4426 (struct hardlink_info *) uptodate_link->data;
4428 if (link (uptodate_link->key, workfile) < 0)
4429 error (1, errno, "cannot link %s to %s",
4430 workfile, uptodate_link->key);
4431 hlinfo->checked_out = 1; /* probably unnecessary */
4441 info = findnode (vers->other_delta, "owner");
4444 change_rcs_owner_or_group = 1;
4445 rcs_owner = (uid_t) strtoul (info->data, NULL, 10);
4447 info = findnode (vers->other_delta, "group");
4450 change_rcs_owner_or_group = 1;
4451 rcs_group = (gid_t) strtoul (info->data, NULL, 10);
4453 info = findnode (vers->other_delta, "permissions");
4456 change_rcs_mode = 1;
4457 rcs_mode = (mode_t) strtoul (info->data, NULL, 8);
4459 info = findnode (vers->other_delta, "special");
4462 /* If the size of `devtype' changes, fix the sscanf call also */
4465 if (sscanf (info->data, "%16s %lu",
4466 devtype, &devnum_long) < 2)
4467 error (1, 0, "%s:%s has bad `special' newphrase %s",
4468 workfile, vers->version, info->data);
4469 devnum = devnum_long;
4470 if (strcmp (devtype, "character") == 0)
4471 special_file = S_IFCHR;
4472 else if (strcmp (devtype, "block") == 0)
4473 special_file = S_IFBLK;
4475 error (0, 0, "%s is a special file of unsupported type `%s'",
4476 workfile, info->data);
4481 if (expand != KFLAG_O && expand != KFLAG_B)
4485 /* Don't fetch the delta node again if we already have it. */
4488 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
4490 error (1, 0, "internal error: no revision information for %s",
4491 rev == NULL ? rcs->head : rev);
4494 expand_keywords (rcs, (RCSVers *) vp->data, nametag, log, loglen,
4495 expand, value, len, &newvalue, &len);
4497 if (newvalue != value)
4517 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4519 error (1, 0, "special file %s cannot be piped to anything",
4522 /* The PFN interface is very simple to implement right now, as
4523 we always have the entire file in memory. */
4525 pfn (callerdat, value, len);
4527 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4528 else if (special_file)
4532 /* Can send either to WORKFILE or to SOUT, as long as SOUT is
4537 if (sout == RUN_TTY)
4538 error (1, 0, "special file %s cannot be written to stdout",
4543 /* Unlink `dest', just in case. It's okay if this provokes a
4545 if (unlink (dest) < 0 && existence_error (errno))
4546 error (1, errno, "cannot remove %s", dest);
4547 if (mknod (dest, special_file, devnum) < 0)
4548 error (1, errno, "could not create special file %s",
4554 /* Not a special file: write to WORKFILE or SOUT. */
4555 if (workfile == NULL)
4557 if (sout == RUN_TTY)
4561 /* Symbolic links should be removed before replacement, so that
4562 `fopen' doesn't follow the link and open the wrong file. */
4564 if (unlink_file (sout) < 0)
4565 error (1, errno, "cannot remove %s", sout);
4566 ofp = CVS_FOPEN (sout, expand == KFLAG_B ? "wb" : "w");
4568 error (1, errno, "cannot open %s", sout);
4573 /* Output is supposed to go to WORKFILE, so we should open that
4574 file. Symbolic links should be removed first (see above). */
4575 if (islink (workfile))
4576 if (unlink_file (workfile) < 0)
4577 error (1, errno, "cannot remove %s", workfile);
4579 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
4581 /* If the open failed because the existing workfile was not
4582 writable, try to chmod the file and retry the open. */
4583 if (ofp == NULL && errno == EACCES
4584 && isfile (workfile) && !iswritable (workfile))
4586 xchmod (workfile, 1);
4587 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
4592 error (0, errno, "cannot open %s", workfile);
4599 if (workfile == NULL && sout == RUN_TTY)
4601 if (expand == KFLAG_B)
4602 cvs_output_binary (value, len);
4605 /* cvs_output requires the caller to check for zero
4608 cvs_output (value, len);
4613 /* NT 4.0 is said to have trouble writing 2099999 bytes
4614 (for example) in a single fwrite. So break it down
4615 (there is no need to be writing that much at once
4616 anyway; it is possible that LARGEST_FWRITE should be
4617 somewhat larger for good performance, but for testing I
4618 want to start with a small value until/unless a bigger
4619 one proves useful). */
4620 #define LARGEST_FWRITE 8192
4622 size_t nstep = (len < LARGEST_FWRITE ? len : LARGEST_FWRITE);
4627 if (fwrite (p, 1, nstep, ofp) != nstep)
4629 error (0, errno, "cannot write %s",
4632 : (sout != RUN_TTY ? sout : "stdout")));
4648 if (workfile != NULL)
4652 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4653 if (!special_file && fclose (ofp) < 0)
4655 error (0, errno, "cannot close %s", workfile);
4659 if (change_rcs_owner_or_group)
4661 if (chown (workfile, rcs_owner, rcs_group) < 0)
4662 error (0, errno, "could not change owner or group of %s",
4666 ret = chmod (workfile,
4669 : sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
4671 if (fclose (ofp) < 0)
4673 error (0, errno, "cannot close %s", workfile);
4677 ret = chmod (workfile,
4678 sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
4682 error (0, errno, "cannot change mode of file %s",
4686 else if (sout != RUN_TTY)
4689 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4694 error (0, errno, "cannot close %s", sout);
4699 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4700 /* If we are in the business of preserving hardlinks, then
4701 mark this file as having been checked out. */
4702 if (preserve_perms && workfile != NULL)
4703 update_hardlink_info (workfile);
4709 static RCSVers *RCS_findlock_or_tip PROTO ((RCSNode *rcs));
4711 /* Find the delta currently locked by the user. From the `ci' man page:
4713 "If rev is omitted, ci tries to derive the new revision
4714 number from the caller's last lock. If the caller has
4715 locked the tip revision of a branch, the new revision is
4716 appended to that branch. The new revision number is
4717 obtained by incrementing the tip revision number. If the
4718 caller locked a non-tip revision, a new branch is started
4719 at that revision by incrementing the highest branch number
4720 at that revision. The default initial branch and level
4723 If rev is omitted and the caller has no lock, but owns the
4724 file and locking is not set to strict, then the revision
4725 is appended to the default branch (normally the trunk; see
4726 the -b option of rcs(1))."
4728 RCS_findlock_or_tip finds the unique revision locked by the caller
4729 and returns its delta node. If the caller has not locked any
4730 revisions (and is permitted to commit to an unlocked delta, as
4731 described above), return the tip of the default branch. */
4734 RCS_findlock_or_tip (rcs)
4737 char *user = getcaller();
4741 /* Find unique delta locked by caller. This code is very similar
4742 to the code in RCS_unlock -- perhaps it could be abstracted
4743 into a RCS_findlock function. */
4744 locklist = RCS_getlocks (rcs);
4746 for (p = locklist->list->next; p != locklist->list; p = p->next)
4748 if (STREQ (p->data, user))
4753 %s: multiple revisions locked by %s; please specify one", rcs->path, user);
4762 /* Found an old lock, but check that the revision still exists. */
4763 p = findnode (rcs->versions, lock->key);
4766 error (0, 0, "%s: can't unlock nonexistent revision %s",
4771 return (RCSVers *) p->data;
4774 /* No existing lock. The RCS rule is that this is an error unless
4775 locking is nonstrict AND the file is owned by the current
4776 user. Trying to determine the latter is a portability nightmare
4777 in the face of NT, VMS, AFS, and other systems with non-unix-like
4778 ideas of users and owners. In the case of CVS, we should never get
4779 here (as long as the traditional behavior of making sure to call
4780 RCS_lock persists). Anyway, we skip the RCS error checks
4781 and just return the default branch or head. The reasoning is that
4782 those error checks are to make users lock before a checkin, and we do
4783 that in other ways if at all anyway (e.g. rcslock.pl). */
4785 p = findnode (rcs->versions, RCS_getbranch (rcs, rcs->branch, 0));
4786 return (RCSVers *) p->data;
4789 /* Revision number string, R, must contain a `.'.
4790 Return a newly-malloc'd copy of the prefix of R up
4791 to but not including the final `.'. */
4799 char *dot = strrchr (r, '.');
4803 new_r = xmalloc (len + 1);
4804 memcpy (new_r, r, len);
4805 *(new_r + len) = '\0';
4809 /* Revision number string, R, must contain a `.'.
4810 R must be writable. Replace the rightmost `.' in R with
4811 the NUL byte and return a pointer to that NUL byte. */
4814 truncate_revnum_in_place (r)
4817 char *dot = strrchr (r, '.');
4823 /* Revision number strings, R and S, must each contain a `.'.
4824 R and S must be writable and must have the same number of dots.
4825 Truncate R and S for the comparison, then restored them to their
4827 Return the result (see compare_revnums) of comparing R and S
4828 ignoring differences in any component after the rightmost `.'. */
4831 compare_truncated_revnums (r, s)
4835 char *r_dot = truncate_revnum_in_place (r);
4836 char *s_dot = truncate_revnum_in_place (s);
4839 assert (numdots (r) == numdots (s));
4841 cmp = compare_revnums (r, s);
4849 /* Return a malloc'd copy of the string representing the highest branch
4850 number on BRANCHNODE. If there are no branches on BRANCHNODE, return NULL.
4851 FIXME: isn't the max rev always the last one?
4852 If so, we don't even need a loop. */
4854 static char *max_rev PROTO ((const RCSVers *));
4857 max_rev (branchnode)
4858 const RCSVers *branchnode;
4864 if (branchnode->branches == NULL)
4870 head = branchnode->branches->list;
4871 for (bp = head->next; bp != head; bp = bp->next)
4873 if (max == NULL || compare_truncated_revnums (max, bp->key) < 0)
4880 return truncate_revnum (max);
4883 /* Create BRANCH in RCS's delta tree. BRANCH may be either a branch
4884 number or a revision number. In the former case, create the branch
4885 with the specified number; in the latter case, create a new branch
4886 rooted at node BRANCH with a higher branch number than any others.
4887 Return the number of the tip node on the new branch. */
4890 RCS_addbranch (rcs, branch)
4894 char *branchpoint, *newrevnum;
4897 RCSVers *branchnode;
4899 /* Append to end by default. */
4902 branchpoint = xstrdup (branch);
4903 if ((numdots (branchpoint) & 1) == 0)
4905 truncate_revnum_in_place (branchpoint);
4908 /* Find the branch rooted at BRANCHPOINT. */
4909 nodep = findnode (rcs->versions, branchpoint);
4912 error (0, 0, "%s: can't find branch point %s", rcs->path, branchpoint);
4915 branchnode = (RCSVers *) nodep->data;
4917 /* If BRANCH was a full branch number, make sure it is higher than MAX. */
4918 if ((numdots (branch) & 1) == 1)
4920 if (branchnode->branches == NULL)
4922 /* We have to create the first branch on this node, which means
4923 appending ".2" to the revision number. */
4924 newrevnum = (char *) xmalloc (strlen (branch) + 3);
4925 strcpy (newrevnum, branch);
4926 strcat (newrevnum, ".2");
4930 char *max = max_rev (branchnode);
4932 newrevnum = increment_revnum (max);
4938 newrevnum = xstrdup (branch);
4940 if (branchnode->branches != NULL)
4945 /* Find the position of this new branch in the sorted list
4947 head = branchnode->branches->list;
4948 for (bp = head->next; bp != head; bp = bp->next)
4953 /* The existing list must be sorted on increasing revnum. */
4954 assert (bp->next == head
4955 || compare_truncated_revnums (bp->key,
4956 bp->next->key) < 0);
4957 dot = truncate_revnum_in_place (bp->key);
4958 found_pos = (compare_revnums (branch, bp->key) < 0);
4970 newrevnum = (char *) xrealloc (newrevnum, strlen (newrevnum) + 3);
4971 strcat (newrevnum, ".1");
4973 /* Add this new revision number to BRANCHPOINT's branches list. */
4974 if (branchnode->branches == NULL)
4975 branchnode->branches = getlist();
4977 bp->key = xstrdup (newrevnum);
4979 /* Append to the end of the list by default, that is, just before
4980 the header node, `list'. */
4982 marker = branchnode->branches->list;
4986 fail = insert_before (branchnode->branches, marker, bp);
4993 /* Check in to RCSFILE with revision REV (which must be greater than
4994 the largest revision) and message MESSAGE (which is checked for
4995 legality). If FLAGS & RCS_FLAGS_DEAD, check in a dead revision.
4996 If FLAGS & RCS_FLAGS_QUIET, tell ci to be quiet. If FLAGS &
4997 RCS_FLAGS_MODTIME, use the working file's modification time for the
4998 checkin time. WORKFILE is the working file to check in from, or
4999 NULL to use the usual RCS rules for deriving it from the RCSFILE.
5000 If FLAGS & RCS_FLAGS_KEEPFILE, don't unlink the working file;
5001 unlinking the working file is standard RCS behavior, but is rarely
5002 appropriate for CVS.
5004 This function should almost exactly mimic the behavior of `rcs ci'. The
5005 principal point of difference is the support here for preserving file
5006 ownership and permissions in the delta nodes. This is not a clean
5007 solution -- precisely because it diverges from RCS's behavior -- but
5008 it doesn't seem feasible to do this anywhere else in the code. [-twp]
5010 Return value is -1 for error (and errno is set to indicate the
5011 error), positive for error (and an error message has been printed),
5012 or zero for success. */
5015 RCS_checkin (rcs, workfile, message, rev, flags)
5022 RCSVers *delta, *commitpt;
5025 char *tmpfile, *changefile, *chtext;
5028 int buflen, chtextlen;
5029 int status, checkin_quiet, allocated_workfile;
5032 int adding_branch = 0;
5036 if (rcs->flags & PARTIAL)
5037 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5039 /* Get basename of working file. Is there a library function to
5040 do this? I couldn't find one. -twp */
5041 allocated_workfile = 0;
5042 if (workfile == NULL)
5045 int extlen = strlen (RCSEXT);
5046 workfile = xstrdup (last_component (rcs->path));
5047 p = workfile + (strlen (workfile) - extlen);
5048 assert (strncmp (p, RCSEXT, extlen) == 0);
5050 allocated_workfile = 1;
5053 /* Is the backend file a symbolic link? Follow it and replace the
5054 filename with the destination of the link. */
5056 while (islink (rcs->path))
5059 #ifdef HAVE_READLINK
5060 /* The clean thing to do is probably to have each filesubr.c
5061 implement this (with an error if not supported by the
5062 platform, in which case islink would presumably return 0).
5063 But that would require editing each filesubr.c and so the
5064 expedient hack seems to be looking at HAVE_READLINK. */
5065 newname = xreadlink (rcs->path);
5067 error (1, 0, "internal error: islink doesn't like readlink");
5070 if (isabsolute (newname))
5073 rcs->path = newname;
5077 char *oldname = last_component (rcs->path);
5078 int dirlen = oldname - rcs->path;
5079 char *fullnewname = xmalloc (dirlen + strlen (newname) + 1);
5080 strncpy (fullnewname, rcs->path, dirlen);
5081 strcpy (fullnewname + dirlen, newname);
5084 rcs->path = fullnewname;
5088 checkin_quiet = flags & RCS_FLAGS_QUIET;
5091 cvs_output (rcs->path, 0);
5092 cvs_output (" <-- ", 7);
5093 cvs_output (workfile, 0);
5094 cvs_output ("\n", 1);
5097 /* Create new delta node. */
5098 delta = (RCSVers *) xmalloc (sizeof (RCSVers));
5099 memset (delta, 0, sizeof (RCSVers));
5100 delta->author = xstrdup (getcaller ());
5101 if (flags & RCS_FLAGS_MODTIME)
5104 if (stat (workfile, &ws) < 0)
5106 error (1, errno, "cannot stat %s", workfile);
5108 modtime = ws.st_mtime;
5111 (void) time (&modtime);
5112 ftm = gmtime (&modtime);
5113 delta->date = (char *) xmalloc (MAXDATELEN);
5114 (void) sprintf (delta->date, DATEFORM,
5115 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
5116 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
5117 ftm->tm_min, ftm->tm_sec);
5118 if (flags & RCS_FLAGS_DEAD)
5120 delta->state = xstrdup (RCSDEAD);
5124 delta->state = xstrdup ("Exp");
5126 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5127 /* If permissions should be preserved on this project, then
5128 save the permission info. */
5133 char buf[64]; /* static buffer should be safe: see usage. -twp */
5135 delta->other_delta = getlist();
5137 if (CVS_LSTAT (workfile, &sb) < 0)
5138 error (1, 1, "cannot lstat %s", workfile);
5140 if (S_ISLNK (sb.st_mode))
5143 np->key = xstrdup ("symlink");
5144 np->data = xreadlink (workfile);
5145 addnode (delta->other_delta, np);
5149 (void) sprintf (buf, "%u", sb.st_uid);
5151 np->key = xstrdup ("owner");
5152 np->data = xstrdup (buf);
5153 addnode (delta->other_delta, np);
5155 (void) sprintf (buf, "%u", sb.st_gid);
5157 np->key = xstrdup ("group");
5158 np->data = xstrdup (buf);
5159 addnode (delta->other_delta, np);
5161 (void) sprintf (buf, "%o", sb.st_mode & 07777);
5163 np->key = xstrdup ("permissions");
5164 np->data = xstrdup (buf);
5165 addnode (delta->other_delta, np);
5167 /* Save device number. */
5168 switch (sb.st_mode & S_IFMT)
5170 case S_IFREG: break;
5174 np->key = xstrdup ("special");
5175 sprintf (buf, "%s %lu",
5176 ((sb.st_mode & S_IFMT) == S_IFCHR
5177 ? "character" : "block"),
5178 (unsigned long) sb.st_rdev);
5179 np->data = xstrdup (buf);
5180 addnode (delta->other_delta, np);
5184 error (0, 0, "special file %s has unknown type", workfile);
5187 /* Save hardlinks. */
5188 delta->hardlinks = list_linked_files_on_disk (workfile);
5193 /* Create a new deltatext node. */
5194 dtext = (Deltatext *) xmalloc (sizeof (Deltatext));
5195 memset (dtext, 0, sizeof (Deltatext));
5197 dtext->log = make_message_rcslegal (message);
5199 /* If the delta tree is empty, then there's nothing to link the
5200 new delta into. So make a new delta tree, snarf the working
5201 file contents, and just write the new RCS file. */
5202 if (rcs->head == NULL)
5207 /* Figure out what the first revision number should be. */
5208 if (rev == NULL || *rev == '\0')
5209 newrev = xstrdup ("1.1");
5210 else if (numdots (rev) == 0)
5212 newrev = (char *) xmalloc (strlen (rev) + 3);
5213 strcpy (newrev, rev);
5214 strcat (newrev, ".1");
5217 newrev = xstrdup (rev);
5219 /* Don't need to xstrdup NEWREV because it's already dynamic, and
5220 not used for anything else. (Don't need to free it, either.) */
5222 delta->version = xstrdup (newrev);
5224 nodep->type = RCSVERS;
5225 nodep->key = xstrdup (newrev);
5226 nodep->data = (char *) delta;
5227 (void) addnode (rcs->versions, nodep);
5229 dtext->version = xstrdup (newrev);
5231 get_file (workfile, workfile,
5232 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5233 &dtext->text, &bufsize, &dtext->len);
5237 cvs_output ("initial revision: ", 0);
5238 cvs_output (rcs->head, 0);
5239 cvs_output ("\n", 1);
5242 /* We are probably about to invalidate any cached file. */
5243 rcsbuf_cache_close ();
5245 fout = rcs_internal_lockfile (rcs->path);
5246 RCS_putadmin (rcs, fout);
5247 RCS_putdtree (rcs, rcs->head, fout);
5248 RCS_putdesc (rcs, fout);
5249 rcs->delta_pos = ftell (fout);
5250 if (rcs->delta_pos == -1)
5251 error (1, errno, "cannot ftell for %s", rcs->path);
5252 putdeltatext (fout, dtext);
5253 rcs_internal_unlockfile (fout, rcs->path);
5254 freedeltatext (dtext);
5256 if ((flags & RCS_FLAGS_KEEPFILE) == 0)
5258 if (unlink_file (workfile) < 0)
5259 /* FIXME-update-dir: message does not include update_dir. */
5260 error (0, errno, "cannot remove %s", workfile);
5264 cvs_output ("done\n", 5);
5269 /* Derive a new revision number. From the `ci' man page:
5271 "If rev is a revision number, it must be higher than the
5272 latest one on the branch to which rev belongs, or must
5275 If rev is a branch rather than a revision number, the new
5276 revision is appended to that branch. The level number is
5277 obtained by incrementing the tip revision number of that
5278 branch. If rev indicates a non-existing branch, that
5279 branch is created with the initial revision numbered
5282 RCS_findlock_or_tip handles the case where REV is omitted.
5283 RCS 5.7 also permits REV to be "$" or to begin with a dot, but
5284 we do not address those cases -- every routine that calls
5285 RCS_checkin passes it a numeric revision. */
5287 if (rev == NULL || *rev == '\0')
5289 /* Figure out where the commit point is by looking for locks.
5290 If the commit point is at the tip of a branch (or is the
5291 head of the delta tree), then increment its revision number
5292 to obtain the new revnum. Otherwise, start a new
5294 commitpt = RCS_findlock_or_tip (rcs);
5295 if (commitpt == NULL)
5300 else if (commitpt->next == NULL
5301 || STREQ (commitpt->version, rcs->head))
5302 delta->version = increment_revnum (commitpt->version);
5304 delta->version = RCS_addbranch (rcs, commitpt->version);
5308 /* REV is either a revision number or a branch number. Find the
5309 tip of the target branch. */
5310 char *branch, *tip, *newrev, *p;
5313 assert (isdigit(*rev));
5315 newrev = xstrdup (rev);
5316 dots = numdots (newrev);
5317 isrevnum = dots & 1;
5319 branch = xstrdup (rev);
5322 p = strrchr (branch, '.');
5326 /* Find the tip of the target branch. If we got a one- or two-digit
5327 revision number, this will be the head of the tree. Exception:
5328 if rev is a single-field revision equal to the branch number of
5329 the trunk (usually "1") then we want to treat it like an ordinary
5333 tip = xstrdup (rcs->head);
5334 if (atoi (tip) != atoi (branch))
5336 newrev = (char *) xrealloc (newrev, strlen (newrev) + 3);
5337 strcat (newrev, ".1");
5338 dots = isrevnum = 1;
5342 tip = xstrdup (rcs->head);
5344 tip = RCS_getbranch (rcs, branch, 1);
5346 /* If the branch does not exist, and we were supplied an exact
5347 revision number, signal an error. Otherwise, if we were
5348 given only a branch number, create it and set COMMITPT to
5349 the branch point. */
5354 error (0, 0, "%s: can't find branch point %s",
5361 delta->version = RCS_addbranch (rcs, branch);
5363 p = strrchr (branch, '.');
5365 tip = xstrdup (branch);
5371 /* NEWREV must be higher than TIP. */
5372 if (compare_revnums (tip, newrev) >= 0)
5375 "%s: revision %s too low; must be higher than %s",
5384 delta->version = xstrdup (newrev);
5387 /* Just increment the tip number to get the new revision. */
5388 delta->version = increment_revnum (tip);
5391 nodep = findnode (rcs->versions, tip);
5392 commitpt = (RCSVers *) nodep->data;
5399 assert (delta->version != NULL);
5401 /* If COMMITPT is locked by us, break the lock. If it's locked
5402 by someone else, signal an error. */
5403 nodep = findnode (RCS_getlocks (rcs), commitpt->version);
5406 if (! STREQ (nodep->data, delta->author))
5408 /* If we are adding a branch, then leave the old lock around.
5409 That is sensible in the sense that when adding a branch,
5410 we don't need to use the lock to tell us where to check
5411 in. It is fishy in the sense that if it is our own lock,
5412 we break it. However, this is the RCS 5.7 behavior (at
5413 the end of addbranch in ci.c in RCS 5.7, it calls
5414 removelock only if it is our own lock, not someone
5419 error (0, 0, "%s: revision %s locked by %s",
5421 nodep->key, nodep->data);
5430 dtext->version = xstrdup (delta->version);
5432 /* Obtain the change text for the new delta. If DELTA is to be the
5433 new head of the tree, then its change text should be the contents
5434 of the working file, and LEAFNODE's change text should be a diff.
5435 Else, DELTA's change text should be a diff between LEAFNODE and
5436 the working file. */
5438 tmpfile = cvs_temp_name();
5439 status = RCS_checkout (rcs, NULL, commitpt->version, NULL,
5440 ((rcs->expand != NULL
5441 && STREQ (rcs->expand, "b"))
5445 (RCSCHECKOUTPROC)0, NULL);
5448 "could not check out revision %s of `%s'",
5449 commitpt->version, rcs->path);
5451 bufsize = buflen = 0;
5454 changefile = cvs_temp_name();
5456 /* Diff options should include --binary if the RCS file has -kb set
5457 in its `expand' field. */
5458 diffopts = (rcs->expand != NULL && STREQ (rcs->expand, "b")
5462 if (STREQ (commitpt->version, rcs->head) &&
5463 numdots (delta->version) == 1)
5465 /* If this revision is being inserted on the trunk, the change text
5466 for the new delta should be the contents of the working file ... */
5468 get_file (workfile, workfile,
5469 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5470 &dtext->text, &bufsize, &dtext->len);
5472 /* ... and the change text for the old delta should be a diff. */
5473 commitpt->text = (Deltatext *) xmalloc (sizeof (Deltatext));
5474 memset (commitpt->text, 0, sizeof (Deltatext));
5477 switch (diff_exec (workfile, tmpfile, diffopts, changefile))
5483 /* FIXME-update-dir: message does not include update_dir. */
5484 error (1, errno, "error diffing %s", workfile);
5487 /* FIXME-update-dir: message does not include update_dir. */
5488 error (1, 0, "error diffing %s", workfile);
5492 /* OK, the text file case here is really dumb. Logically
5493 speaking we want diff to read the files in text mode,
5494 convert them to the canonical form found in RCS files
5495 (which, we hope at least, is independent of OS--always
5496 bare linefeeds), and then work with change texts in that
5497 format. However, diff_exec both generates change
5498 texts and produces output for user purposes (e.g. patch.c),
5499 and there is no way to distinguish between the two cases.
5500 So we actually implement the text file case by writing the
5501 change text as a text file, then reading it as a text file.
5502 This should cause no harm, but doesn't strike me as
5504 get_file (changefile, changefile,
5505 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5506 &commitpt->text->text, &bufsize, &commitpt->text->len);
5508 /* If COMMITPT->TEXT->TEXT is NULL, it means that CHANGEFILE
5509 was empty and that there are no differences between revisions.
5510 In that event, we want to force RCS_rewrite to write an empty
5511 string for COMMITPT's change text. Leaving the change text
5512 field set NULL won't work, since that means "preserve the original
5513 change text for this delta." */
5514 if (commitpt->text->text == NULL)
5516 commitpt->text->text = xstrdup ("");
5517 commitpt->text->len = 0;
5522 /* This file is not being inserted at the head, but on a side
5523 branch somewhere. Make a diff from the previous revision
5524 to the working file. */
5525 switch (diff_exec (tmpfile, workfile, diffopts, changefile))
5531 /* FIXME-update-dir: message does not include update_dir. */
5532 error (1, errno, "error diffing %s", workfile);
5535 /* FIXME-update-dir: message does not include update_dir. */
5536 error (1, 0, "error diffing %s", workfile);
5539 /* See the comment above, at the other get_file invocation,
5540 regarding binary vs. text. */
5541 get_file (changefile, changefile,
5542 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5543 &dtext->text, &bufsize,
5545 if (dtext->text == NULL)
5547 dtext->text = xstrdup ("");
5552 /* Update DELTA linkage. It is important not to do this before
5553 the very end of RCS_checkin; if an error arises that forces
5554 us to abort checking in, we must not have malformed deltas
5555 partially linked into the tree.
5557 If DELTA and COMMITPT are on different branches, do nothing --
5558 DELTA is linked to the tree through COMMITPT->BRANCHES, and we
5559 don't want to change `next' pointers.
5561 Otherwise, if the nodes are both on the trunk, link DELTA to
5562 COMMITPT; otherwise, link COMMITPT to DELTA. */
5564 if (numdots (commitpt->version) == numdots (delta->version))
5566 if (STREQ (commitpt->version, rcs->head))
5568 delta->next = rcs->head;
5569 rcs->head = xstrdup (delta->version);
5572 commitpt->next = xstrdup (delta->version);
5575 /* Add DELTA to RCS->VERSIONS. */
5576 if (rcs->versions == NULL)
5577 rcs->versions = getlist();
5579 nodep->type = RCSVERS;
5580 nodep->key = xstrdup (delta->version);
5581 nodep->data = (char *) delta;
5582 (void) addnode (rcs->versions, nodep);
5584 /* Write the new RCS file, inserting the new delta at COMMITPT. */
5587 cvs_output ("new revision: ", 14);
5588 cvs_output (delta->version, 0);
5589 cvs_output ("; previous revision: ", 21);
5590 cvs_output (commitpt->version, 0);
5591 cvs_output ("\n", 1);
5594 RCS_rewrite (rcs, dtext, commitpt->version);
5596 if ((flags & RCS_FLAGS_KEEPFILE) == 0)
5598 if (unlink_file (workfile) < 0)
5599 /* FIXME-update-dir: message does not include update_dir. */
5600 error (1, errno, "cannot remove %s", workfile);
5602 if (unlink_file (tmpfile) < 0)
5603 error (0, errno, "cannot remove %s", tmpfile);
5604 if (unlink_file (changefile) < 0)
5605 error (0, errno, "cannot remove %s", changefile);
5608 cvs_output ("done\n", 5);
5611 if (allocated_workfile)
5614 if (commitpt != NULL && commitpt->text != NULL)
5616 freedeltatext (commitpt->text);
5617 commitpt->text = NULL;
5620 freedeltatext (dtext);
5622 free_rcsvers_contents (delta);
5627 /* This structure is passed between RCS_cmp_file and cmp_file_buffer. */
5629 struct cmp_file_data
5631 const char *filename;
5636 /* Compare the contents of revision REV of RCS file RCS with the
5637 contents of the file FILENAME. OPTIONS is a string for the keyword
5638 expansion options. Return 0 if the contents of the revision are
5639 the same as the contents of the file, 1 if they are different. */
5642 RCS_cmp_file (rcs, rev, options, filename)
5646 const char *filename;
5650 struct cmp_file_data data;
5653 if (options != NULL && options[0] != '\0')
5654 binary = STREQ (options, "-kb");
5659 expand = RCS_getexpand (rcs);
5660 if (expand != NULL && STREQ (expand, "b"))
5666 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5667 /* If CVS is to deal properly with special files (when
5668 PreservePermissions is on), the best way is to check out the
5669 revision to a temporary file and call `xcmp' on the two disk
5670 files. xcmp needs to handle non-regular files properly anyway,
5671 so calling it simplifies RCS_cmp_file. We *could* just yank
5672 the delta node out of the version tree and look for device
5673 numbers, but writing to disk and calling xcmp is a better
5674 abstraction (therefore probably more robust). -twp */
5680 tmp = cvs_temp_name();
5681 retcode = RCS_checkout(rcs, NULL, rev, NULL, options, tmp, NULL, NULL);
5685 retcode = xcmp (tmp, filename);
5686 if (CVS_UNLINK (tmp) < 0)
5687 error (0, errno, "cannot remove %s", tmp);
5693 fp = CVS_FOPEN (filename, binary ? FOPEN_BINARY_READ : "r");
5695 /* FIXME-update-dir: should include update_dir in message. */
5696 error (1, errno, "cannot open file %s for comparing", filename);
5698 data.filename = filename;
5702 retcode = RCS_checkout (rcs, (char *) NULL, rev, (char *) NULL,
5703 options, RUN_TTY, cmp_file_buffer,
5706 /* If we have not yet found a difference, make sure that we are at
5707 the end of the file. */
5708 if (! data.different)
5710 if (getc (fp) != EOF)
5719 return data.different;
5723 /* This is a subroutine of RCS_cmp_file. It is passed to
5726 #define CMP_BUF_SIZE (8 * 1024)
5729 cmp_file_buffer (callerdat, buffer, len)
5734 struct cmp_file_data *data = (struct cmp_file_data *) callerdat;
5737 /* If we've already found a difference, we don't need to check
5739 if (data->different)
5742 filebuf = xmalloc (len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len);
5748 checklen = len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len;
5749 if (fread (filebuf, 1, checklen, data->fp) != checklen)
5751 if (ferror (data->fp))
5752 error (1, errno, "cannot read file %s for comparing",
5754 data->different = 1;
5759 if (memcmp (filebuf, buffer, checklen) != 0)
5761 data->different = 1;
5773 /* For RCS file RCS, make symbolic tag TAG point to revision REV.
5774 This validates that TAG is OK for a user to use. Return value is
5775 -1 for error (and errno is set to indicate the error), positive for
5776 error (and an error message has been printed), or zero for success. */
5779 RCS_settag (rcs, tag, rev)
5787 if (rcs->flags & PARTIAL)
5788 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5790 /* FIXME: This check should be moved to RCS_check_tag. There is no
5791 reason for it to be here. */
5792 if (STREQ (tag, TAG_BASE)
5793 || STREQ (tag, TAG_HEAD))
5795 /* Print the name of the tag might be considered redundant
5796 with the caller, which also prints it. Perhaps this helps
5797 clarify why the tag name is considered reserved, I don't
5799 error (0, 0, "Attempt to add reserved tag name %s", tag);
5803 /* A revision number of NULL means use the head or default branch.
5804 If rev is not NULL, it may be a symbolic tag or branch number;
5805 expand it to the correct numeric revision or branch head. */
5807 rev = rcs->branch ? rcs->branch : rcs->head;
5809 /* At this point rcs->symbol_data may not have been parsed.
5810 Calling RCS_symbols will force it to be parsed into a list
5811 which we can easily manipulate. */
5812 symbols = RCS_symbols (rcs);
5813 if (symbols == NULL)
5815 symbols = getlist ();
5816 rcs->symbols = symbols;
5818 node = findnode (symbols, tag);
5822 node->data = xstrdup (rev);
5827 node->key = xstrdup (tag);
5828 node->data = xstrdup (rev);
5829 (void) addnode_at_front (symbols, node);
5835 /* Delete the symbolic tag TAG from the RCS file RCS. Return 0 if
5836 the tag was found (and removed), or 1 if it was not present. (In
5837 either case, the tag will no longer be in RCS->SYMBOLS.) */
5840 RCS_deltag (rcs, tag)
5846 if (rcs->flags & PARTIAL)
5847 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5849 symbols = RCS_symbols (rcs);
5850 if (symbols == NULL)
5853 node = findnode (symbols, tag);
5862 /* Set the default branch of RCS to REV. */
5865 RCS_setbranch (rcs, rev)
5869 if (rcs->flags & PARTIAL)
5870 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5875 if (rev == NULL && rcs->branch == NULL)
5877 if (rev != NULL && rcs->branch != NULL && STREQ (rev, rcs->branch))
5880 if (rcs->branch != NULL)
5882 rcs->branch = xstrdup (rev);
5887 /* Lock revision REV. LOCK_QUIET is 1 to suppress output. FIXME:
5888 Most of the callers only call us because RCS_checkin still tends to
5889 like a lock (a relic of old behavior inherited from the RCS ci
5890 program). If we clean this up, only "cvs admin -l" will still need
5891 to call RCS_lock. */
5893 /* FIXME-twp: if a lock owned by someone else is broken, should this
5894 send mail to the lock owner? Prompt user? It seems like such an
5895 obscure situation for CVS as almost not worth worrying much
5899 RCS_lock (rcs, rev, lock_quiet)
5909 if (rcs->flags & PARTIAL)
5910 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
5912 locks = RCS_getlocks (rcs);
5914 locks = rcs->locks = getlist();
5917 /* A revision number of NULL means lock the head or default branch. */
5919 xrev = RCS_head (rcs);
5921 /* If rev is a branch number, lock the latest revision on that
5922 branch. I think that if the branch doesn't exist, it's
5923 okay to return 0 -- that just means that the branch is new,
5924 so we don't need to lock it anyway. -twp */
5925 else if (RCS_nodeisbranch (rcs, rev))
5927 xrev = RCS_getbranch (rcs, (char *) rev, 1);
5931 error (0, 0, "%s: branch %s absent", rcs->path, rev);
5937 xrev = xstrdup (rev);
5939 /* Make sure that the desired revision exists. Technically,
5940 we can update the locks list without even checking this,
5941 but RCS 5.7 did this. And it can't hurt. */
5942 if (findnode (rcs->versions, xrev) == NULL)
5945 error (0, 0, "%s: revision %s absent", rcs->path, xrev);
5950 /* Is this rev already locked? */
5951 p = findnode (locks, xrev);
5954 if (STREQ (p->data, user))
5956 /* We already own the lock on this revision, so do nothing. */
5962 /* Well, first of all, "rev" below should be "xrev" to avoid
5963 core dumps. But more importantly, should we really be
5964 breaking the lock unconditionally? What CVS 1.9 does (via
5965 RCS) is to prompt "Revision 1.1 is already locked by fred.
5966 Do you want to break the lock? [ny](n): ". Well, we don't
5967 want to interact with the user (certainly not at the
5968 server/protocol level, and probably not in the command-line
5969 client), but isn't it more sensible to give an error and
5970 let the user run "cvs admin -u" if they want to break the
5973 /* Break the lock. */
5976 cvs_output (rev, 0);
5977 cvs_output (" unlocked\n", 0);
5981 error (1, 0, "Revision %s is already locked by %s", xrev, p->data);
5985 /* Create a new lock. */
5987 p->key = xrev; /* already xstrdupped */
5988 p->data = xstrdup (getcaller());
5989 (void) addnode_at_front (locks, p);
5993 cvs_output (xrev, 0);
5994 cvs_output (" locked\n", 0);
6000 /* Unlock revision REV. UNLOCK_QUIET is 1 to suppress output. FIXME:
6001 Like RCS_lock, this can become a no-op if we do the checkin
6004 If REV is not null and is locked by someone else, break their
6005 lock and notify them. It is an open issue whether RCS_unlock
6006 queries the user about whether or not to break the lock. */
6009 RCS_unlock (rcs, rev, unlock_quiet)
6020 if (rcs->flags & PARTIAL)
6021 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6023 /* If rev is NULL, unlock the latest revision (first in
6024 rcs->locks) held by the caller. */
6029 /* No-ops: attempts to unlock an empty tree or an unlocked file. */
6030 if (rcs->head == NULL)
6033 cvs_outerr ("can't unlock an empty tree\n", 0);
6037 locks = RCS_getlocks (rcs);
6041 cvs_outerr ("No locks are set.\n", 0);
6046 for (p = locks->list->next; p != locks->list; p = p->next)
6048 if (STREQ (p->data, user))
6054 %s: multiple revisions locked by %s; please specify one", rcs->path, user);
6061 return 0; /* no lock found, ergo nothing to do */
6062 xrev = xstrdup (lock->key);
6064 else if (RCS_nodeisbranch (rcs, rev))
6066 /* If rev is a branch number, unlock the latest revision on that
6068 xrev = RCS_getbranch (rcs, (char *) rev, 1);
6071 error (0, 0, "%s: branch %s absent", rcs->path, rev);
6076 /* REV is an exact revision number. */
6077 xrev = xstrdup (rev);
6079 lock = findnode (RCS_getlocks (rcs), xrev);
6082 /* This revision isn't locked. */
6087 if (! STREQ (lock->data, user))
6089 /* If the revision is locked by someone else, notify
6090 them. Note that this shouldn't ever happen if RCS_unlock
6091 is called with a NULL revision, since that means "whatever
6092 revision is currently locked by the caller." */
6093 char *repos, *workfile;
6094 repos = xstrdup (rcs->path);
6095 workfile = strrchr (repos, '/');
6097 notify_do ('C', workfile, user, NULL, NULL, repos);
6104 cvs_output (xrev, 0);
6105 cvs_output (" unlocked\n", 0);
6112 /* Add USER to the access list of RCS. Do nothing if already present.
6113 FIXME-twp: check syntax of USER to make sure it's a valid id. */
6116 RCS_addaccess (rcs, user)
6122 if (rcs->flags & PARTIAL)
6123 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6125 if (rcs->access == NULL)
6126 rcs->access = xstrdup (user);
6129 access = xstrdup (rcs->access);
6130 for (a = strtok (access, " "); a != NULL; a = strtok (NULL, " "))
6132 if (STREQ (a, user))
6138 rcs->access = (char *) xrealloc
6139 (rcs->access, strlen (rcs->access) + strlen (user) + 2);
6140 strcat (rcs->access, " ");
6141 strcat (rcs->access, user);
6145 /* Remove USER from the access list of RCS. */
6148 RCS_delaccess (rcs, user)
6155 if (rcs->flags & PARTIAL)
6156 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6158 if (rcs->access == NULL)
6162 ulen = strlen (user);
6165 if (p[ulen] == '\0' || p[ulen] == ' ')
6166 if (strncmp (p, user, ulen) == 0)
6168 p = strchr (p, ' ');
6186 if (rcs->flags & PARTIAL)
6187 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6192 static int findtag PROTO ((Node *, void *));
6194 /* Return a nonzero value if the revision specified by ARG is found. */
6201 char *rev = (char *)arg;
6203 if (STREQ (node->data, rev))
6209 /* Delete revisions between REV1 and REV2. The changes between the two
6210 revisions must be collapsed, and the result stored in the revision
6211 immediately preceding the lower one. Return 0 for successful completion,
6214 Solution: check out the revision preceding REV1 and the revision
6215 following REV2. Use call_diff to find aggregate diffs between
6216 these two revisions, and replace the delta text for the latter one
6217 with the new aggregate diff. Alternatively, we could write a
6218 function that takes two change texts and combines them to produce a
6219 new change text, without checking out any revs or calling diff. It
6220 would be hairy, but so, so cool.
6222 If INCLUSIVE is set, then TAG1 and TAG2, if non-NULL, tell us to
6223 delete that revision as well (cvs admin -o tag1:tag2). If clear,
6224 delete up to but not including that revision (cvs admin -o tag1::tag2).
6225 This does not affect TAG1 or TAG2 being NULL; the meaning of the start
6226 point in ::tag2 and :tag2 is the same and likewise for end points. */
6229 RCS_delete_revs (rcs, tag1, tag2, inclusive)
6237 RCSVers *revp = NULL;
6242 char *branchpoint = NULL;
6245 int rev1_inclusive = inclusive;
6246 int rev2_inclusive = inclusive;
6247 char *before = NULL;
6249 char *beforefile = NULL;
6250 char *afterfile = NULL;
6251 char *outfile = NULL;
6253 if (tag1 == NULL && tag2 == NULL)
6256 /* Assume error status until everything is finished. */
6259 /* Make sure both revisions exist. */
6262 rev1 = RCS_gettag (rcs, tag1, 1, NULL);
6263 if (rev1 == NULL || (nodep = findnode (rcs->versions, rev1)) == NULL)
6265 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag1);
6271 rev2 = RCS_gettag (rcs, tag2, 1, NULL);
6272 if (rev2 == NULL || (nodep = findnode (rcs->versions, rev2)) == NULL)
6274 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag2);
6279 /* If rev1 is on the trunk and rev2 is NULL, rev2 should be
6280 RCS->HEAD. (*Not* RCS_head(rcs), which may return rcs->branch
6281 instead.) We need to check this special case early, in order
6282 to make sure that rev1 and rev2 get ordered correctly. */
6283 if (rev2 == NULL && numdots (rev1) == 1)
6285 rev2 = xstrdup (rcs->head);
6292 if (rev1 != NULL && rev2 != NULL)
6294 /* A range consisting of a branch number means the latest revision
6296 if (RCS_isbranch (rcs, rev1) && STREQ (rev1, rev2))
6297 rev1 = rev2 = RCS_getbranch (rcs, rev1, 0);
6300 /* Make sure REV1 and REV2 are ordered correctly (in the
6301 same order as the next field). For revisions on the
6302 trunk, REV1 should be higher than REV2; for branches,
6303 REV1 should be lower. */
6304 /* Shouldn't we just be giving an error in the case where
6305 the user specifies the revisions in the wrong order
6306 (that is, always swap on the trunk, never swap on a
6307 branch, in the non-error cases)? It is not at all
6308 clear to me that users who specify -o 1.4:1.2 really
6309 meant to type -o 1.2:1.4, and the out of order usage
6310 has never been documented, either by cvs.texinfo or
6314 if (numdots (rev1) == 1)
6316 if (compare_revnums (rev1, rev2) <= 0)
6322 temp_inclusive = rev2_inclusive;
6323 rev2_inclusive = rev1_inclusive;
6324 rev1_inclusive = temp_inclusive;
6327 else if (compare_revnums (rev1, rev2) > 0)
6333 temp_inclusive = rev2_inclusive;
6334 rev2_inclusive = rev1_inclusive;
6335 rev1_inclusive = temp_inclusive;
6340 /* Basically the same thing; make sure that the ordering is what we
6344 assert (rev2 != NULL);
6345 if (numdots (rev2) == 1)
6347 /* Swap rev1 and rev2. */
6353 temp_inclusive = rev2_inclusive;
6354 rev2_inclusive = rev1_inclusive;
6355 rev1_inclusive = temp_inclusive;
6359 /* Put the revision number preceding the first one to delete into
6360 BEFORE (where "preceding" means according to the next field).
6361 If the first revision to delete is the first revision on its
6362 branch (e.g. 1.3.2.1), BEFORE should be the node on the trunk
6363 at which the branch is rooted. If the first revision to delete
6364 is the head revision of the trunk, set BEFORE to NULL.
6366 Note that because BEFORE may not be on the same branch as REV1,
6367 it is not very handy for navigating the revision tree. It's
6368 most useful just for checking out the revision preceding REV1. */
6370 branchpoint = RCS_getbranchpoint (rcs, rev1 != NULL ? rev1 : rev2);
6373 rev1 = xstrdup (branchpoint);
6374 if (numdots (branchpoint) > 1)
6377 bp = strrchr (branchpoint, '.');
6378 while (*--bp != '.')
6381 /* Note that this is exclusive, always, because the inclusive
6382 flag doesn't affect the meaning when rev1 == NULL. */
6383 before = xstrdup (branchpoint);
6387 else if (! STREQ (rev1, branchpoint))
6389 /* Walk deltas from BRANCHPOINT on, looking for REV1. */
6390 nodep = findnode (rcs->versions, branchpoint);
6391 revp = (RCSVers *) nodep->data;
6392 while (revp->next != NULL && ! STREQ (revp->next, rev1))
6394 revp = (RCSVers *) nodep->data;
6395 nodep = findnode (rcs->versions, revp->next);
6397 if (revp->next == NULL)
6399 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, rev1);
6403 before = xstrdup (revp->version);
6407 nodep = findnode (rcs->versions, before);
6408 rev1 = xstrdup (((RCSVers *)nodep->data)->next);
6411 else if (!rev1_inclusive)
6414 nodep = findnode (rcs->versions, before);
6415 rev1 = xstrdup (((RCSVers *)nodep->data)->next);
6417 else if (numdots (branchpoint) > 1)
6419 /* Example: rev1 is "1.3.2.1", branchpoint is "1.3.2.1".
6420 Set before to "1.3". */
6422 bp = strrchr (branchpoint, '.');
6423 while (*--bp != '.')
6426 before = xstrdup (branchpoint);
6430 /* If any revision between REV1 and REV2 is locked or is a branch point,
6431 we can't delete that revision and must abort. */
6435 while (!found && next != NULL)
6437 nodep = findnode (rcs->versions, next);
6438 revp = (RCSVers *) nodep->data;
6441 found = STREQ (revp->version, rev2);
6444 if ((!found && next != NULL) || rev2_inclusive || rev2 == NULL)
6446 if (findnode (RCS_getlocks (rcs), revp->version))
6448 error (0, 0, "%s: can't remove locked revision %s",
6453 if (revp->branches != NULL)
6455 error (0, 0, "%s: can't remove branch point %s",
6461 /* Doing this only for the :: syntax is for compatibility.
6462 See cvs.texinfo for somewhat more discussion. */
6464 && walklist (RCS_symbols (rcs), findtag, revp->version))
6466 /* We don't print which file this happens to on the theory
6467 that the caller will print the name of the file in a
6468 more useful fashion (fullname not rcs->path). */
6469 error (0, 0, "cannot remove revision %s because it has tags",
6474 /* It's misleading to print the `deleting revision' output
6475 here, since we may not actually delete these revisions.
6476 But that's how RCS does it. Bleah. Someday this should be
6477 moved to the point where the revs are actually marked for
6479 cvs_output ("deleting revision ", 0);
6480 cvs_output (revp->version, 0);
6481 cvs_output ("\n", 1);
6490 after = xstrdup (next);
6492 after = xstrdup (revp->version);
6494 else if (!inclusive)
6496 /* In the case of an empty range, for example 1.2::1.2 or
6497 1.2::1.3, we want to just do nothing. */
6503 /* This looks fishy in the cases where tag1 == NULL or tag2 == NULL.
6504 Are those cases really impossible? */
6505 assert (tag1 != NULL);
6506 assert (tag2 != NULL);
6508 error (0, 0, "%s: invalid revision range %s:%s", rcs->path,
6513 if (after == NULL && before == NULL)
6515 /* The user is trying to delete all revisions. While an
6516 RCS file without revisions makes sense to RCS (e.g. the
6517 state after "rcs -i"), CVS has never been able to cope with
6518 it. So at least for now we just make this an error.
6520 We don't include rcs->path in the message since "cvs admin"
6521 already printed "RCS file:" and the name. */
6522 error (1, 0, "attempt to delete all revisions");
6525 /* The conditionals at this point get really hairy. Here is the
6528 IF before != NULL and after == NULL
6529 THEN don't check out any revisions, just delete them
6530 IF before == NULL and after != NULL
6531 THEN only check out after's revision, and use it for the new deltatext
6533 check out both revisions and diff -n them. This could use
6534 RCS_exec_rcsdiff with some changes, like being able
6535 to suppress diagnostic messages and to direct output. */
6540 size_t bufsize, len;
6542 afterfile = cvs_temp_name();
6543 status = RCS_checkout (rcs, NULL, after, NULL, NULL, afterfile,
6544 (RCSCHECKOUTPROC)0, NULL);
6550 /* We are deleting revisions from the head of the tree,
6551 so must create a new head. */
6554 get_file (afterfile, afterfile, "r", &diffbuf, &bufsize, &len);
6556 save_noexec = noexec;
6558 if (unlink_file (afterfile) < 0)
6559 error (0, errno, "cannot remove %s", afterfile);
6560 noexec = save_noexec;
6566 rcs->head = xstrdup (after);
6570 beforefile = cvs_temp_name();
6571 status = RCS_checkout (rcs, NULL, before, NULL, NULL, beforefile,
6572 (RCSCHECKOUTPROC)0, NULL);
6576 outfile = cvs_temp_name();
6577 status = diff_exec (beforefile, afterfile, "-n", outfile);
6581 /* Not sure we need this message; will diff_exec already
6582 have printed an error? */
6583 error (0, 0, "%s: could not diff", rcs->path);
6590 get_file (outfile, outfile, "r", &diffbuf, &bufsize, &len);
6593 /* Save the new change text in after's delta node. */
6594 nodep = findnode (rcs->versions, after);
6595 revp = (RCSVers *) nodep->data;
6597 assert (revp->text == NULL);
6599 revp->text = (Deltatext *) xmalloc (sizeof (Deltatext));
6600 memset ((Deltatext *) revp->text, 0, sizeof (Deltatext));
6601 revp->text->version = xstrdup (revp->version);
6602 revp->text->text = diffbuf;
6603 revp->text->len = len;
6605 /* If DIFFBUF is NULL, it means that OUTFILE is empty and that
6606 there are no differences between the two revisions. In that
6607 case, we want to force RCS_copydeltas to write an empty string
6608 for the new change text (leaving the text field set NULL
6609 means "preserve the original change text for this delta," so
6610 we don't want that). */
6611 if (revp->text->text == NULL)
6612 revp->text->text = xstrdup ("");
6615 /* Walk through the revisions (again) to mark each one as
6616 outdated. (FIXME: would it be safe to use the `dead' field for
6619 next != NULL && (after == NULL || ! STREQ (next, after));
6622 nodep = findnode (rcs->versions, next);
6623 revp = (RCSVers *) nodep->data;
6627 /* Update delta links. If BEFORE == NULL, we're changing the
6628 head of the tree and don't need to update any `next' links. */
6631 /* If REV1 is the first node on its branch, then BEFORE is its
6632 root node (on the trunk) and we have to update its branches
6633 list. Otherwise, BEFORE is on the same branch as AFTER, and
6634 we can just change BEFORE's `next' field to point to AFTER.
6635 (This should be safe: since findnode manages its lists via
6636 the `hashnext' and `hashprev' fields, rather than `next' and
6637 `prev', mucking with `next' and `prev' should not corrupt the
6638 delta tree's internal structure. Much. -twp) */
6641 /* beforep's ->next field already should be equal to after,
6642 which I think is always NULL in this case. */
6644 else if (STREQ (rev1, branchpoint))
6646 nodep = findnode (rcs->versions, before);
6647 revp = (RCSVers *) nodep->data;
6648 nodep = revp->branches->list->next;
6649 while (nodep != revp->branches->list &&
6650 ! STREQ (nodep->key, rev1))
6651 nodep = nodep->next;
6652 assert (nodep != revp->branches->list);
6658 nodep->key = xstrdup (after);
6663 nodep = findnode (rcs->versions, before);
6664 beforep = (RCSVers *) nodep->data;
6665 free (beforep->next);
6666 beforep->next = xstrdup (after);
6677 if (branchpoint != NULL)
6684 save_noexec = noexec;
6686 if (beforefile != NULL)
6688 if (unlink_file (beforefile) < 0)
6689 error (0, errno, "cannot remove %s", beforefile);
6692 if (afterfile != NULL)
6694 if (unlink_file (afterfile) < 0)
6695 error (0, errno, "cannot remove %s", afterfile);
6698 if (outfile != NULL)
6700 if (unlink_file (outfile) < 0)
6701 error (0, errno, "cannot remove %s", outfile);
6704 noexec = save_noexec;
6710 * TRUE if there exists a symbolic tag "tag" in file.
6713 RCS_exist_tag (rcs, tag)
6718 assert (rcs != NULL);
6720 if (findnode (RCS_symbols (rcs), tag))
6727 * TRUE if RCS revision number "rev" exists.
6728 * This includes magic branch revisions, not found in rcs->versions,
6729 * but only in rcs->symbols, requiring a list walk to find them.
6730 * Take advantage of list walk callback function already used by
6731 * RCS_delete_revs, above.
6734 RCS_exist_rev (rcs, rev)
6739 assert (rcs != NULL);
6741 if (rcs->flags & PARTIAL)
6742 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
6744 if (findnode(rcs->versions, rev) != 0)
6747 if (walklist (RCS_symbols(rcs), findtag, rev) != 0)
6755 /* RCS_deltas and friends. Processing of the deltas in RCS files. */
6759 /* Text of this line. Part of the same malloc'd block as the struct
6760 line itself (we probably should use the "struct hack" (char text[1])
6761 and save ourselves sizeof (char *) bytes). Does not include \n;
6762 instead has_newline indicates the presence or absence of \n. */
6764 /* Length of this line, not counting \n if has_newline is true. */
6766 /* Version in which it was introduced. */
6768 /* Nonzero if this line ends with \n. This will always be true
6769 except possibly for the last line. */
6771 /* Number of pointers to this struct line. */
6777 /* How many lines in use for this linevector? */
6778 unsigned int nlines;
6779 /* How many lines allocated for this linevector? */
6780 unsigned int lines_alloced;
6781 /* Pointer to array containing a pointer to each line. */
6782 struct line **vector;
6785 static void linevector_init PROTO ((struct linevector *));
6787 /* Initialize *VEC to be a linevector with no lines. */
6789 linevector_init (vec)
6790 struct linevector *vec;
6792 vec->lines_alloced = 0;
6797 static int linevector_add PROTO ((struct linevector *vec, const char *text,
6798 size_t len, RCSVers *vers,
6801 /* Given some text TEXT, add each of its lines to VEC before line POS
6802 (where line 0 is the first line). The last line in TEXT may or may
6803 not be \n terminated.
6804 Set the version for each of the new lines to VERS. This
6805 function returns non-zero for success. It returns zero if the line
6806 number is out of range.
6808 Each of the lines in TEXT are copied to space which is managed with
6809 the linevector (and freed by linevector_free). So the caller doesn't
6810 need to keep TEXT around after the call to this function. */
6812 linevector_add (vec, text, len, vers, pos)
6813 struct linevector *vec;
6819 const char *textend;
6823 const char *nextline_text;
6824 size_t nextline_len;
6825 int nextline_newline;
6831 textend = text + len;
6833 /* Count the number of lines we will need to add. */
6835 for (p = text; p < textend; ++p)
6836 if (*p == '\n' && p + 1 < textend)
6839 /* Expand VEC->VECTOR if needed. */
6840 if (vec->nlines + nnew >= vec->lines_alloced)
6842 if (vec->lines_alloced == 0)
6843 vec->lines_alloced = 10;
6844 while (vec->nlines + nnew >= vec->lines_alloced)
6845 vec->lines_alloced *= 2;
6846 vec->vector = xrealloc (vec->vector,
6847 vec->lines_alloced * sizeof (*vec->vector));
6850 /* Make room for the new lines in VEC->VECTOR. */
6851 for (i = vec->nlines + nnew - 1; i >= pos + nnew; --i)
6852 vec->vector[i] = vec->vector[i - nnew];
6854 if (pos > vec->nlines)
6857 /* Actually add the lines, to VEC->VECTOR. */
6859 nextline_text = text;
6860 nextline_newline = 0;
6861 for (p = text; p < textend; ++p)
6864 nextline_newline = 1;
6865 if (p + 1 == textend)
6866 /* If there are no characters beyond the last newline, we
6867 don't consider it another line. */
6869 nextline_len = p - nextline_text;
6870 q = (struct line *) xmalloc (sizeof (struct line) + nextline_len);
6872 q->text = (char *)q + sizeof (struct line);
6873 q->len = nextline_len;
6874 q->has_newline = nextline_newline;
6876 memcpy (q->text, nextline_text, nextline_len);
6877 vec->vector[i++] = q;
6879 nextline_text = (char *)p + 1;
6880 nextline_newline = 0;
6882 nextline_len = p - nextline_text;
6883 q = (struct line *) xmalloc (sizeof (struct line) + nextline_len);
6885 q->text = (char *)q + sizeof (struct line);
6886 q->len = nextline_len;
6887 q->has_newline = nextline_newline;
6889 memcpy (q->text, nextline_text, nextline_len);
6892 vec->nlines += nnew;
6897 static void linevector_delete PROTO ((struct linevector *, unsigned int,
6900 /* Remove NLINES lines from VEC at position POS (where line 0 is the
6903 linevector_delete (vec, pos, nlines)
6904 struct linevector *vec;
6906 unsigned int nlines;
6911 last = vec->nlines - nlines;
6912 for (i = pos; i < pos + nlines; ++i)
6914 if (--vec->vector[i]->refcount == 0)
6915 free (vec->vector[i]);
6917 for (i = pos; i < last; ++i)
6918 vec->vector[i] = vec->vector[i + nlines];
6919 vec->nlines -= nlines;
6922 static void linevector_copy PROTO ((struct linevector *, struct linevector *));
6924 /* Copy FROM to TO, copying the vectors but not the lines pointed to. */
6926 linevector_copy (to, from)
6927 struct linevector *to;
6928 struct linevector *from;
6932 for (ln = 0; ln < to->nlines; ++ln)
6934 if (--to->vector[ln]->refcount == 0)
6935 free (to->vector[ln]);
6937 if (from->nlines > to->lines_alloced)
6939 if (to->lines_alloced == 0)
6940 to->lines_alloced = 10;
6941 while (from->nlines > to->lines_alloced)
6942 to->lines_alloced *= 2;
6943 to->vector = (struct line **)
6944 xrealloc (to->vector, to->lines_alloced * sizeof (*to->vector));
6946 memcpy (to->vector, from->vector,
6947 from->nlines * sizeof (*to->vector));
6948 to->nlines = from->nlines;
6949 for (ln = 0; ln < to->nlines; ++ln)
6950 ++to->vector[ln]->refcount;
6953 static void linevector_free PROTO ((struct linevector *));
6955 /* Free storage associated with linevector. */
6957 linevector_free (vec)
6958 struct linevector *vec;
6962 if (vec->vector != NULL)
6964 for (ln = 0; ln < vec->nlines; ++ln)
6965 if (--vec->vector[ln]->refcount == 0)
6966 free (vec->vector[ln]);
6972 static char *month_printname PROTO ((char *));
6974 /* Given a textual string giving the month (1-12), terminated with any
6975 character not recognized by atoi, return the 3 character name to
6976 print it with. I do not think it is a good idea to change these
6977 strings based on the locale; they are standard abbreviations (for
6978 example in rfc822 mail messages) which should be widely understood.
6979 Returns a pointer into static readonly storage. */
6981 month_printname (month)
6984 static const char *const months[] =
6985 {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
6986 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
6989 mnum = atoi (month);
6990 if (mnum < 1 || mnum > 12)
6992 return (char *)months[mnum - 1];
6996 apply_rcs_changes PROTO ((struct linevector *, const char *, size_t,
6997 const char *, RCSVers *, RCSVers *));
6999 /* Apply changes to the line vector LINES. DIFFBUF is a buffer of
7000 length DIFFLEN holding the change text from an RCS file (the output
7001 of diff -n). NAME is used in error messages. The VERS field of
7002 any line added is set to ADDVERS. The VERS field of any line
7003 deleted is set to DELVERS, unless DELVERS is NULL, in which case
7004 the VERS field of deleted lines is unchanged. The function returns
7005 non-zero if the change text is applied successfully. It returns
7006 zero if the change text does not appear to apply to LINES (e.g., a
7007 line number is invalid). If the change text is improperly
7008 formatted (e.g., it is not the output of diff -n), the function
7009 calls error with a status of 1, causing the program to exit. */
7012 apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
7013 struct linevector *lines;
7014 const char *diffbuf;
7023 /* The RCS format throws us for a loop in that the deltafrags (if
7024 we define a deltafrag as an add or a delete) need to be applied
7025 in reverse order. So we stick them into a linked list. */
7027 enum {ADD, DELETE} type;
7029 unsigned long nlines;
7030 const char *new_lines;
7032 struct deltafrag *next;
7034 struct deltafrag *dfhead;
7035 struct deltafrag *df;
7038 for (p = diffbuf; p != NULL && p < diffbuf + difflen; )
7041 if (op != 'a' && op != 'd')
7042 /* Can't just skip over the deltafrag, because the value
7043 of op determines the syntax. */
7044 error (1, 0, "unrecognized operation '%c' in %s", op, name);
7045 df = (struct deltafrag *) xmalloc (sizeof (struct deltafrag));
7048 df->pos = strtoul (p, (char **) &q, 10);
7051 error (1, 0, "number expected in %s", name);
7054 error (1, 0, "space expected in %s", name);
7055 df->nlines = strtoul (p, (char **) &q, 10);
7057 error (1, 0, "number expected in %s", name);
7060 error (1, 0, "linefeed expected in %s", name);
7068 /* The text we want is the number of lines specified, or
7069 until the end of the value, whichever comes first (it
7070 will be the former except in the case where we are
7071 adding a line which does not end in newline). */
7072 for (q = p; i != 0; ++q)
7075 else if (q == diffbuf + difflen)
7078 error (1, 0, "premature end of change in %s", name);
7083 /* Stash away a pointer to the text we are adding. */
7091 /* Correct for the fact that line numbers in RCS files
7100 for (df = dfhead; df != NULL;)
7107 if (! linevector_add (lines, df->new_lines, df->len, addvers,
7112 if (df->pos > lines->nlines
7113 || df->pos + df->nlines > lines->nlines)
7115 if (delvers != NULL)
7116 for (ln = df->pos; ln < df->pos + df->nlines; ++ln)
7117 lines->vector[ln]->vers = delvers;
7118 linevector_delete (lines, df->pos, df->nlines);
7129 /* Apply an RCS change text to a buffer. The function name starts
7130 with rcs rather than RCS because this does not take an RCSNode
7131 argument. NAME is used in error messages. TEXTBUF is the text
7132 buffer to change, and TEXTLEN is the size. DIFFBUF and DIFFLEN are
7133 the change buffer and size. The new buffer is returned in *RETBUF
7134 and *RETLEN. The new buffer is allocated by xmalloc.
7136 Return 1 for success. On failure, call error and return 0. */
7139 rcs_change_text (name, textbuf, textlen, diffbuf, difflen, retbuf, retlen)
7143 const char *diffbuf;
7148 struct linevector lines;
7154 linevector_init (&lines);
7156 if (! linevector_add (&lines, textbuf, textlen, NULL, 0))
7157 error (1, 0, "cannot initialize line vector");
7159 if (! apply_rcs_changes (&lines, diffbuf, difflen, name, NULL, NULL))
7161 error (0, 0, "invalid change text in %s", name);
7171 for (ln = 0; ln < lines.nlines; ++ln)
7173 n += lines.vector[ln]->len + 1;
7178 for (ln = 0; ln < lines.nlines; ++ln)
7180 memcpy (p, lines.vector[ln]->text, lines.vector[ln]->len);
7181 p += lines.vector[ln]->len;
7182 if (lines.vector[ln]->has_newline)
7186 *retlen = p - *retbuf;
7187 assert (*retlen <= n);
7192 linevector_free (&lines);
7197 /* Walk the deltas in RCS to get to revision VERSION.
7199 If OP is RCS_ANNOTATE, then write annotations using cvs_output.
7201 If OP is RCS_FETCH, then put the contents of VERSION into a
7202 newly-malloc'd array and put a pointer to it in *TEXT. Each line
7203 is \n terminated; the caller is responsible for converting text
7204 files if desired. The total length is put in *LEN.
7206 If FP is non-NULL, it should be a file descriptor open to the file
7207 RCS with file position pointing to the deltas. We close the file
7210 If LOG is non-NULL, then *LOG is set to the log message of VERSION,
7211 and *LOGLEN is set to the length of the log message.
7213 On error, give a fatal error. */
7216 RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
7219 struct rcsbuffer *rcsbuf;
7221 enum rcs_delta_op op;
7227 struct rcsbuffer rcsbuf_local;
7228 char *branchversion;
7235 RCSVers *trunk_vers;
7237 int ishead, isnext, isversion, onbranch;
7239 struct linevector headlines;
7240 struct linevector curlines;
7241 struct linevector trunklines;
7246 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf_local);
7247 rcsbuf = &rcsbuf_local;
7258 linevector_init (&curlines);
7259 linevector_init (&headlines);
7260 linevector_init (&trunklines);
7262 /* We set BRANCHVERSION to the version we are currently looking
7263 for. Initially, this is the version on the trunk from which
7264 VERSION branches off. If VERSION is not a branch, then
7265 BRANCHVERSION is just VERSION. */
7266 branchversion = xstrdup (version);
7267 cpversion = strchr (branchversion, '.');
7268 if (cpversion != NULL)
7269 cpversion = strchr (cpversion + 1, '.');
7270 if (cpversion != NULL)
7274 if (! rcsbuf_getrevnum (rcsbuf, &key))
7275 error (1, 0, "unexpected EOF reading RCS file %s", rcs->path);
7277 if (next != NULL && ! STREQ (next, key))
7279 /* This is not the next version we need. It is a branch
7280 version which we want to ignore. */
7288 /* look up the revision */
7289 node = findnode (rcs->versions, key);
7292 "mismatch in rcs file %s between deltas and deltatexts",
7295 /* Stash the previous version. */
7298 vers = (RCSVers *) node->data;
7301 /* Compare key and trunkversion now, because key points to
7302 storage controlled by rcsbuf_getkey. */
7303 if (STREQ (branchversion, key))
7311 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7312 error (1, 0, "%s does not appear to be a valid rcs file",
7317 && STREQ (key, "log")
7318 && STREQ (branchversion, version))
7320 *log = rcsbuf_valcopy (rcsbuf, value, 0, loglen);
7323 if (STREQ (key, "text"))
7325 rcsbuf_valpolish (rcsbuf, value, 0, &vallen);
7328 if (! linevector_add (&curlines, value, vallen, NULL, 0))
7329 error (1, 0, "invalid rcs file %s", rcs->path);
7335 if (! apply_rcs_changes (&curlines, value, vallen,
7337 onbranch ? vers : NULL,
7338 onbranch ? NULL : prev_vers))
7339 error (1, 0, "invalid change text in %s", rcs->path);
7347 /* This is either the version we want, or it is the
7348 branchpoint to the version we want. */
7349 if (STREQ (branchversion, version))
7351 /* This is the version we want. */
7352 linevector_copy (&headlines, &curlines);
7356 /* We have found this version by tracking up a
7357 branch. Restore back to the lines we saved
7358 when we left the trunk, and continue tracking
7363 linevector_copy (&curlines, &trunklines);
7370 /* We need to look up the branch. */
7373 if (numdots (branchversion) < 2)
7377 /* We are leaving the trunk; save the current
7378 lines so that we can restore them when we
7379 continue tracking down the trunk. */
7381 linevector_copy (&trunklines, &curlines);
7383 /* Reset the version information we have
7384 accumulated so far. It only applies to the
7385 changes from the head to this version. */
7386 for (ln = 0; ln < curlines.nlines; ++ln)
7387 curlines.vector[ln]->vers = NULL;
7390 /* The next version we want is the entry on
7391 VERS->branches which matches this branch. For
7392 example, suppose VERSION is 1.21.4.3 and
7393 BRANCHVERSION was 1.21. Then we look for an entry
7394 starting with "1.21.4" and we'll put it (probably
7395 1.21.4.1) in NEXT. We'll advance BRANCHVERSION by
7396 two dots (in this example, to 1.21.4.3). */
7398 if (vers->branches == NULL)
7399 error (1, 0, "missing expected branches in %s",
7403 cpversion = strchr (cpversion, '.');
7404 if (cpversion == NULL)
7405 error (1, 0, "version number confusion in %s",
7407 for (p = vers->branches->list->next;
7408 p != vers->branches->list;
7410 if (strncmp (p->key, branchversion,
7411 cpversion - branchversion) == 0)
7413 if (p == vers->branches->list)
7414 error (1, 0, "missing expected branch in %s",
7419 cpversion = strchr (cpversion + 1, '.');
7420 if (cpversion != NULL)
7424 if (op == RCS_FETCH && foundhead)
7426 } while (next != NULL);
7428 free (branchversion);
7430 rcsbuf_cache (rcs, rcsbuf);
7433 error (1, 0, "could not find desired version %s in %s",
7434 version, rcs->path);
7436 /* Now print out or return the data we have just computed. */
7443 for (ln = 0; ln < headlines.nlines; ++ln)
7446 /* Period which separates year from month in date. */
7448 /* Period which separates month from day in date. */
7452 prvers = headlines.vector[ln]->vers;
7456 sprintf (buf, "%-12s (%-8.8s ",
7459 cvs_output (buf, 0);
7461 /* Now output the date. */
7462 ym = strchr (prvers->date, '.');
7465 /* ??- is an ANSI trigraph. The ANSI way to
7466 avoid it is \? but some pre ANSI compilers
7467 complain about the unrecognized escape
7468 sequence. Of course string concatenation
7469 ("??" "-???") is also an ANSI-ism. Testing
7470 __STDC__ seems to be a can of worms, since
7471 compilers do all kinds of things with it. */
7472 cvs_output ("??", 0);
7473 cvs_output ("-???", 0);
7474 cvs_output ("-??", 0);
7478 md = strchr (ym + 1, '.');
7480 cvs_output ("??", 0);
7482 cvs_output (md + 1, 2);
7484 cvs_output ("-", 1);
7485 cvs_output (month_printname (ym + 1), 0);
7486 cvs_output ("-", 1);
7487 /* Only output the last two digits of the year. Our output
7488 lines are long enough as it is without printing the
7490 cvs_output (ym - 2, 2);
7492 cvs_output ("): ", 0);
7493 if (headlines.vector[ln]->len != 0)
7494 cvs_output (headlines.vector[ln]->text,
7495 headlines.vector[ln]->len);
7496 cvs_output ("\n", 1);
7506 assert (text != NULL);
7507 assert (len != NULL);
7510 for (ln = 0; ln < headlines.nlines; ++ln)
7512 n += headlines.vector[ln]->len + 1;
7515 for (ln = 0; ln < headlines.nlines; ++ln)
7517 memcpy (p, headlines.vector[ln]->text,
7518 headlines.vector[ln]->len);
7519 p += headlines.vector[ln]->len;
7520 if (headlines.vector[ln]->has_newline)
7529 linevector_free (&curlines);
7530 linevector_free (&headlines);
7531 linevector_free (&trunklines);
7536 /* Read the information for a single delta from the RCS buffer RCSBUF,
7537 whose name is RCSFILE. *KEYP and *VALP are either NULL, or the
7538 first key/value pair to read, as set by rcsbuf_getkey. Return NULL
7539 if there are no more deltas. Store the key/value pair which
7540 terminated the read in *KEYP and *VALP. */
7543 getdelta (rcsbuf, rcsfile, keyp, valp)
7544 struct rcsbuffer *rcsbuf;
7550 char *key, *value, *keybuf, *valbuf, *cp;
7553 /* Get revision number if it wasn't passed in. This uses
7554 rcsbuf_getkey because it doesn't croak when encountering
7555 unexpected input. As a result, we have to play unholy games
7556 with `key' and `value'. */
7564 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7565 error (1, 0, "%s: unexpected EOF", rcsfile);
7568 /* Make sure that it is a revision number and not a cabbage
7570 for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
7572 /* Note that when comparing with RCSDATE, we are not massaging
7573 VALUE from the string found in the RCS file. This is OK since
7574 we know exactly what to expect. */
7575 if (*cp != '\0' || strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) != 0)
7582 vnode = (RCSVers *) xmalloc (sizeof (RCSVers));
7583 memset (vnode, 0, sizeof (RCSVers));
7585 vnode->version = xstrdup (key);
7587 /* Grab the value of the date from value. Note that we are not
7588 massaging VALUE from the string found in the RCS file. */
7589 cp = value + (sizeof RCSDATE) - 1; /* skip the "date" keyword */
7590 while (whitespace (*cp)) /* take space off front of value */
7593 vnode->date = xstrdup (cp);
7595 /* Get author field. */
7596 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7598 error (1, 0, "unexpected end of file reading %s", rcsfile);
7600 if (! STREQ (key, "author"))
7602 unable to parse %s; `author' not in the expected place", rcsfile);
7603 vnode->author = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7605 /* Get state field. */
7606 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7608 error (1, 0, "unexpected end of file reading %s", rcsfile);
7610 if (! STREQ (key, "state"))
7612 unable to parse %s; `state' not in the expected place", rcsfile);
7613 vnode->state = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7614 /* The value is optional, according to rcsfile(5). */
7615 if (value != NULL && STREQ (value, "dead"))
7620 /* Note that "branches" and "next" are in fact mandatory, according
7623 /* fill in the branch list (if any branches exist) */
7624 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7626 error (1, 0, "unexpected end of file reading %s", rcsfile);
7628 if (STREQ (key, RCSDESC))
7632 /* Probably could/should be a fatal error. */
7633 error (0, 0, "warning: 'branches' keyword missing from %s", rcsfile);
7636 if (value != (char *) NULL)
7638 vnode->branches = getlist ();
7639 /* Note that we are not massaging VALUE from the string found
7641 do_branches (vnode->branches, value);
7644 /* fill in the next field if there is a next revision */
7645 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7647 error (1, 0, "unexpected end of file reading %s", rcsfile);
7649 if (STREQ (key, RCSDESC))
7653 /* Probably could/should be a fatal error. */
7654 error (0, 0, "warning: 'next' keyword missing from %s", rcsfile);
7657 if (value != (char *) NULL)
7658 vnode->next = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7661 * XXX - this is where we put the symbolic link stuff???
7662 * (into newphrases in the deltas).
7671 if (! rcsbuf_getid (rcsbuf, &keybuf))
7672 error (1, 0, "unexpected end of file reading %s", rcsfile);
7674 /* rcsbuf_getid did not terminate the key, so copy it to new space. */
7675 len = rcsbuf->ptr - keybuf;
7676 key = (char *) xmalloc (sizeof(char) * (len + 1));
7677 strncpy (key, keybuf, len);
7680 /* The `desc' keyword has only a single string value, with no
7681 trailing semicolon, so it must be handled specially. */
7682 if (STREQ (key, RCSDESC))
7684 (void) rcsbuf_getstring (rcsbuf, &valbuf);
7685 value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen);
7689 #ifdef PRESERVE_PERMISSIONS_SUPPORT
7690 /* The `hardlinks' value is a group of words, which must
7691 be parsed separately and added as a list to vnode->hardlinks. */
7692 if (STREQ (key, "hardlinks"))
7696 vnode->hardlinks = getlist();
7699 if (! rcsbuf_getword (rcsbuf, &valbuf))
7700 error (1, 0, "unexpected end of file reading %s", rcsfile);
7704 n->key = rcsbuf_valcopy (rcsbuf, valbuf, 1, NULL);
7705 addnode (vnode->hardlinks, n);
7711 /* Get the value. */
7715 if (! rcsbuf_getword (rcsbuf, &valbuf))
7716 error (1, 0, "unexpected end of file reading %s", rcsfile);
7720 /* Copy valbuf to new space so we can polish it, then
7721 append it to value. */
7725 value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen);
7731 temp_value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen);
7732 len = strlen (value);
7733 value = (char *) xrealloc
7734 (value, sizeof(char) * (len + valbuflen + 2));
7736 strcpy (value + len + 1, temp_value);
7741 /* Enable use of repositories created by certain obsolete
7742 versions of CVS. This code should remain indefinately;
7743 there is no procedure for converting old repositories, and
7744 checking for it is harmless. */
7745 if (STREQ (key, RCSDEAD))
7748 if (vnode->state != NULL)
7749 free (vnode->state);
7750 vnode->state = xstrdup ("dead");
7753 /* if we have a new revision number, we're done with this delta */
7754 for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
7756 /* Note that when comparing with RCSDATE, we are not massaging
7757 VALUE from the string found in the RCS file. This is OK
7758 since we know exactly what to expect. */
7759 if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0)
7762 /* At this point, key and value represent a user-defined field
7763 in the delta node. */
7764 if (vnode->other_delta == NULL)
7765 vnode->other_delta = getlist ();
7767 kv->type = RCSFIELD;
7770 if (addnode (vnode->other_delta, kv) != 0)
7772 /* Complaining about duplicate keys in newphrases seems
7773 questionable, in that we don't know what they mean and
7774 doc/RCSFILES has no prohibition on several newphrases
7775 with the same key. But we can't store more than one as
7776 long as we store them in a List *. */
7777 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
7783 /* Return the key which caused us to fail back to the caller. */
7794 if (d->version != NULL)
7798 if (d->text != NULL)
7800 if (d->other != (List *) NULL)
7801 dellist (&d->other);
7806 RCS_getdeltatext (rcs, fp, rcsbuf)
7809 struct rcsbuffer *rcsbuf;
7816 /* Get the revision number. */
7817 if (! rcsbuf_getrevnum (rcsbuf, &num))
7819 /* If num == NULL, it means we reached EOF naturally. That's
7824 error (1, 0, "%s: unexpected EOF", rcs->path);
7827 p = findnode (rcs->versions, num);
7829 error (1, 0, "mismatch in rcs file %s between deltas and deltatexts",
7832 d = (Deltatext *) xmalloc (sizeof (Deltatext));
7833 d->version = xstrdup (num);
7835 /* Get the log message. */
7836 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7837 error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num);
7838 if (! STREQ (key, "log"))
7839 error (1, 0, "%s, delta %s: expected `log', got `%s'",
7840 rcs->path, num, key);
7841 d->log = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
7843 /* Get random newphrases. */
7844 d->other = getlist();
7847 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7848 error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num);
7850 if (STREQ (key, "text"))
7855 p->key = xstrdup (key);
7856 p->data = rcsbuf_valcopy (rcsbuf, value, 1, (size_t *) NULL);
7857 if (addnode (d->other, p) < 0)
7859 error (0, 0, "warning: %s, delta %s: duplicate field `%s'",
7860 rcs->path, num, key);
7864 /* Get the change text. We already know that this key is `text'. */
7865 d->text = rcsbuf_valcopy (rcsbuf, value, 0, &d->len);
7870 /* RCS output functions, for writing RCS format files from RCSNode
7873 For most of this work, RCS 5.7 uses an `aprintf' function which aborts
7874 program upon error. Instead, these functions check the output status
7875 of the stream right before closing it, and aborts if an error condition
7876 is found. The RCS solution is probably the better one: it produces
7877 more overhead, but will produce a clearer diagnostic in the case of
7878 catastrophic error. In either case, however, the repository will probably
7879 not get corrupted. */
7882 putsymbol_proc (symnode, fparg)
7886 FILE *fp = (FILE *) fparg;
7888 /* A fiddly optimization: this code used to just call fprintf, but
7889 in an old repository with hundreds of tags this can get called
7890 hundreds of thousands of times when doing a cvs tag. Since
7891 tagging is a relatively common operation, and using putc and
7892 fputs is just as comprehensible, the change is worthwhile. */
7895 fputs (symnode->key, fp);
7897 fputs (symnode->data, fp);
7901 static int putlock_proc PROTO ((Node *, void *));
7903 /* putlock_proc is like putsymbol_proc, but key and data are reversed. */
7906 putlock_proc (symnode, fp)
7910 return fprintf ((FILE *) fp, "\n\t%s:%s", symnode->data, symnode->key);
7914 putrcsfield_proc (node, vfp)
7918 FILE *fp = (FILE *) vfp;
7920 /* Some magic keys used internally by CVS start with `;'. Skip them. */
7921 if (node->key[0] == ';')
7924 fprintf (fp, "\n%s\t", node->key);
7925 if (node->data != NULL)
7927 /* If the field's value contains evil characters,
7928 it must be stringified. */
7929 /* FIXME: This does not quite get it right. "7jk8f" is not a legal
7930 value for a value in a newpharse, according to doc/RCSFILES,
7931 because digits are not valid in an "id". We might do OK by
7932 always writing strings (enclosed in @@). Would be nice to
7933 explicitly mention this one way or another in doc/RCSFILES.
7934 A case where we are wrong in a much more clear-cut way is that
7935 we let through non-graphic characters such as whitespace and
7936 control characters. */
7937 int n = strcspn (node->data, "$,.:;@");
7938 if (node->data[n] == 0)
7939 fputs (node->data, fp);
7943 expand_at_signs (node->data, (off_t) strlen (node->data), fp);
7948 /* desc, log and text fields should not be terminated with semicolon;
7949 all other fields should be. */
7950 if (! STREQ (node->key, "desc") &&
7951 ! STREQ (node->key, "log") &&
7952 ! STREQ (node->key, "text"))
7959 #ifdef PRESERVE_PERMISSIONS_SUPPORT
7961 /* Save a filename in a `hardlinks' RCS field. NODE->KEY will contain
7962 a full pathname, but currently only basenames are stored in the RCS
7963 node. Assume that the filename includes nasty characters and
7967 puthardlink_proc (node, vfp)
7971 FILE *fp = (FILE *) vfp;
7972 char *basename = strrchr (node->key, '/');
7974 if (basename == NULL)
7975 basename = node->key;
7981 (void) expand_at_signs (basename, strlen (basename), fp);
7989 /* Output the admin node for RCS into stream FP. */
7992 RCS_putadmin (rcs, fp)
7996 fprintf (fp, "%s\t%s;\n", RCSHEAD, rcs->head ? rcs->head : "");
7998 fprintf (fp, "%s\t%s;\n", RCSBRANCH, rcs->branch);
8000 fputs ("access", fp);
8004 s = xstrdup (rcs->access);
8005 for (p = strtok (s, " \n\t"); p != NULL; p = strtok (NULL, " \n\t"))
8006 fprintf (fp, "\n\t%s", p);
8011 fputs (RCSSYMBOLS, fp);
8012 /* If we haven't had to convert the symbols to a list yet, don't
8013 force a conversion now; just write out the string. */
8014 if (rcs->symbols == NULL && rcs->symbols_data != NULL)
8017 fputs (rcs->symbols_data, fp);
8020 walklist (RCS_symbols (rcs), putsymbol_proc, (void *) fp);
8023 fputs ("locks", fp);
8024 if (rcs->locks_data)
8025 fprintf (fp, "\t%s", rcs->locks_data);
8026 else if (rcs->locks)
8027 walklist (rcs->locks, putlock_proc, (void *) fp);
8028 if (rcs->strict_locks)
8029 fprintf (fp, "; strict");
8034 fprintf (fp, "comment\t@");
8035 expand_at_signs (rcs->comment, (off_t) strlen (rcs->comment), fp);
8038 if (rcs->expand && ! STREQ (rcs->expand, "kv"))
8039 fprintf (fp, "%s\t@%s@;\n", RCSEXPAND, rcs->expand);
8041 walklist (rcs->other, putrcsfield_proc, (void *) fp);
8053 /* Skip if no revision was supplied, or if it is outdated (cvs admin -o) */
8054 if (vers == NULL || vers->outdated)
8057 fprintf (fp, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches",
8059 RCSDATE, vers->date,
8060 "author", vers->author,
8061 "state", vers->state ? vers->state : "");
8063 if (vers->branches != NULL)
8065 start = vers->branches->list;
8066 for (bp = start->next; bp != start; bp = bp->next)
8067 fprintf (fp, "\n\t%s", bp->key);
8070 fprintf (fp, ";\nnext\t%s;", vers->next ? vers->next : "");
8072 walklist (vers->other_delta, putrcsfield_proc, fp);
8074 #ifdef PRESERVE_PERMISSIONS_SUPPORT
8075 if (vers->hardlinks)
8077 fprintf (fp, "\nhardlinks");
8078 walklist (vers->hardlinks, puthardlink_proc, fp);
8086 RCS_putdtree (rcs, rev, fp)
8097 /* Find the delta node for this revision. */
8098 p = findnode (rcs->versions, rev);
8100 versp = (RCSVers *) p->data;
8102 /* Print the delta node and recurse on its `next' node. This prints
8103 the trunk. If there are any branches printed on this revision,
8104 print those trunks as well. */
8105 putdelta (versp, fp);
8106 RCS_putdtree (rcs, versp->next, fp);
8107 if (versp->branches != NULL)
8109 branch = versp->branches->list;
8110 for (p = branch->next; p != branch; p = p->next)
8111 RCS_putdtree (rcs, p->key, fp);
8116 RCS_putdesc (rcs, fp)
8120 fprintf (fp, "\n\n%s\n@", RCSDESC);
8121 if (rcs->desc != NULL)
8123 off_t len = (off_t) strlen (rcs->desc);
8126 expand_at_signs (rcs->desc, len, fp);
8127 if (rcs->desc[len-1] != '\n')
8135 putdeltatext (fp, d)
8139 fprintf (fp, "\n\n%s\nlog\n@", d->version);
8142 int loglen = strlen (d->log);
8143 expand_at_signs (d->log, (off_t) loglen, fp);
8144 if (d->log[loglen-1] != '\n')
8149 walklist (d->other, putrcsfield_proc, fp);
8151 fputs ("\ntext\n@", fp);
8152 if (d->text != NULL)
8153 expand_at_signs (d->text, (off_t) d->len, fp);
8157 /* TODO: the whole mechanism for updating deltas is kludgey... more
8158 sensible would be to supply all the necessary info in a `newdeltatext'
8159 field for RCSVers nodes. -twp */
8161 /* Copy delta text nodes from FIN to FOUT. If NEWDTEXT is non-NULL, it
8162 is a new delta text node, and should be added to the tree at the
8163 node whose revision number is INSERTPT. (Note that trunk nodes are
8164 written in decreasing order, and branch nodes are written in
8165 increasing order.) */
8168 RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt)
8171 struct rcsbuffer *rcsbufin;
8173 Deltatext *newdtext;
8179 int insertbefore, found;
8186 /* Count the number of versions for which we have to do some
8187 special operation. */
8188 actions = walklist (rcs->versions, count_delta_actions, (void *) NULL);
8190 /* Make a note of whether NEWDTEXT should be inserted
8191 before or after its INSERTPT. */
8192 insertbefore = (newdtext != NULL && numdots (newdtext->version) == 1);
8194 while (actions != 0 || newdtext != NULL)
8198 dtext = RCS_getdeltatext (rcs, fin, rcsbufin);
8200 /* We shouldn't hit EOF here, because that would imply that
8201 some action was not taken, or that we could not insert
8204 error (1, 0, "internal error: EOF too early in RCS_copydeltas");
8206 found = (insertpt != NULL && STREQ (dtext->version, insertpt));
8207 if (found && insertbefore)
8209 putdeltatext (fout, newdtext);
8214 np = findnode (rcs->versions, dtext->version);
8215 dadmin = (RCSVers *) np->data;
8217 /* If this revision has been outdated, just skip it. */
8218 if (dadmin->outdated)
8224 /* Update the change text for this delta. New change text
8225 data may come from cvs admin -m, cvs admin -o, or cvs ci. */
8226 if (dadmin->text != NULL)
8228 if (dadmin->text->log != NULL || dadmin->text->text != NULL)
8230 if (dadmin->text->log != NULL)
8233 dtext->log = dadmin->text->log;
8234 dadmin->text->log = NULL;
8236 if (dadmin->text->text != NULL)
8239 dtext->text = dadmin->text->text;
8240 dtext->len = dadmin->text->len;
8241 dadmin->text->text = NULL;
8244 putdeltatext (fout, dtext);
8245 freedeltatext (dtext);
8247 if (found && !insertbefore)
8249 putdeltatext (fout, newdtext);
8255 /* Copy the rest of the file directly, without bothering to
8256 interpret it. The caller will handle error checking by calling
8259 We just wrote a newline to the file, either in putdeltatext or
8260 in the caller. However, we may not have read the corresponding
8261 newline from the file, because rcsbuf_getkey returns as soon as
8262 it finds the end of the '@' string for the desc or text key.
8263 Therefore, we may read three newlines when we should really
8264 only write two, and we check for that case here. This is not
8265 an semantically important issue; we only do it to make our RCS
8266 files look traditional. */
8270 rcsbuf_get_buffered (rcsbufin, &bufrest, &buflen);
8273 if (bufrest[0] != '\n'
8274 || strncmp (bufrest, "\n\n\n", buflen < 3 ? buflen : 3) != 0)
8290 fwrite (bufrest, 1, buflen, fout);
8293 while ((got = fread (buf, 1, sizeof buf, fin)) != 0)
8298 && strncmp (buf, "\n\n\n", nls) == 0)
8300 fwrite (buf + 1, 1, got - 1, fout);
8304 fwrite (buf, 1, got, fout);
8311 /* A helper procedure for RCS_copydeltas. This is called via walklist
8312 to count the number of RCS revisions for which some special action
8316 count_delta_actions (np, ignore)
8322 dadmin = (RCSVers *) np->data;
8324 if (dadmin->outdated)
8327 if (dadmin->text != NULL
8328 && (dadmin->text->log != NULL || dadmin->text->text != NULL))
8336 /* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style
8337 locking on the specified RCSFILE: for a file called `foo,v', open
8338 for writing a file called `,foo,'.
8340 Note that we what do here is quite different from what RCS does.
8341 RCS creates the ,foo, file before it reads the RCS file (if it
8342 knows that it will be writing later), so that it actually serves as
8343 a lock. We don't; instead we rely on CVS writelocks. This means
8344 that if someone is running RCS on the file at the same time they
8345 are running CVS on it, they might lose (we read the file,
8346 then RCS writes it, then we write it, clobbering the
8347 changes made by RCS). I believe the current sentiment about this
8348 is "well, don't do that".
8350 A concern has been expressed about whether adopting the RCS
8351 strategy would slow us down. I don't think so, since we need to
8352 write the ,foo, file anyway (unless perhaps if O_EXCL is slower or
8355 These do not perform quite the same function as the RCS -l option
8356 for locking files: they are intended to prevent competing RCS
8357 processes from stomping all over each other's laundry. Hence,
8358 they are `internal' locking functions.
8360 Note that we don't clean up the ,foo, file on ^C. We probably should.
8361 I'm not completely sure whether RCS does or not (I looked at the code
8362 a little, and didn't find it).
8364 If there is an error, give a fatal error; if we return we always
8365 return a non-NULL value. */
8368 rcs_internal_lockfile (rcsfile)
8376 /* Get the lock file name: `,file,' for RCS file `file,v'. */
8377 lockfile = rcs_lockfilename (rcsfile);
8379 /* Use the existing RCS file mode, or read-only if this is a new
8380 file. (Really, this is a lie -- if this is a new file,
8381 RCS_checkin uses the permissions from the working copy. For
8382 actually creating the file, we use 0444 as a safe default mode.) */
8383 if (stat (rcsfile, &rstat) < 0)
8385 if (existence_error (errno))
8386 rstat.st_mode = S_IRUSR | S_IRGRP | S_IROTH;
8388 error (1, errno, "cannot stat %s", rcsfile);
8391 /* Try to open exclusively. POSIX.1 guarantees that O_EXCL|O_CREAT
8392 guarantees an exclusive open. According to the RCS source, with
8393 NFS v2 we must also throw in O_TRUNC and use an open mask that makes
8394 the file unwriteable. For extensive justification, see the comments for
8395 rcswriteopen() in rcsedit.c, in RCS 5.7. This is kind of pointless
8396 in the CVS case; see comment at the start of this file concerning
8397 general ,foo, file strategy.
8399 There is some sentiment that with NFSv3 and such, that one can
8400 rely on O_EXCL these days. This might be true for unix (I
8401 don't really know), but I am still pretty skeptical in the case
8402 of the non-unix systems. */
8403 fd = open (lockfile, OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
8404 S_IRUSR | S_IRGRP | S_IROTH);
8408 error (1, errno, "could not open lock file `%s'", lockfile);
8411 /* Force the file permissions, and return a stream object. */
8412 /* Because we change the modes later, we don't worry about
8413 this in the non-HAVE_FCHMOD case. */
8415 if (fchmod (fd, rstat.st_mode) < 0)
8416 error (1, errno, "cannot change mode for %s", lockfile);
8418 fp = fdopen (fd, FOPEN_BINARY_WRITE);
8420 error (1, errno, "cannot fdopen %s", lockfile);
8428 rcs_internal_unlockfile (fp, rcsfile)
8434 /* Get the lock file name: `,file,' for RCS file `file,v'. */
8435 lockfile = rcs_lockfilename (rcsfile);
8437 /* Abort if we could not write everything successfully to LOCKFILE.
8438 This is not a great error-handling mechanism, but should prevent
8439 corrupting the repository. */
8442 /* The only case in which using errno here would be meaningful
8443 is if we happen to have left errno unmolested since the call
8444 which produced the error (e.g. fprintf). That is pretty
8445 fragile even if it happens to sometimes be true. The real
8446 solution is to check each call to fprintf rather than waiting
8447 until the end like this. */
8448 error (1, 0, "error writing to lock file %s", lockfile);
8449 if (fclose (fp) == EOF)
8450 error (1, errno, "error closing lock file %s", lockfile);
8452 rename_file (lockfile, rcsfile);
8457 rcs_lockfilename (rcsfile)
8460 char *lockfile, *lockp;
8461 char *rcsbase, *rcsp, *rcsend;
8464 /* Create the lockfile name. */
8465 rcslen = strlen (rcsfile);
8466 lockfile = (char *) xmalloc (rcslen + 10);
8467 rcsbase = last_component (rcsfile);
8468 rcsend = rcsfile + rcslen - sizeof(RCSEXT);
8469 for (lockp = lockfile, rcsp = rcsfile; rcsp < rcsbase; ++rcsp)
8472 while (rcsp <= rcsend)
8480 /* Rewrite an RCS file. The basic idea here is that the caller should
8481 first call RCS_reparsercsfile, then munge the data structures as
8482 desired (via RCS_delete_revs, RCS_settag, &c), then call RCS_rewrite. */
8485 RCS_rewrite (rcs, newdtext, insertpt)
8487 Deltatext *newdtext;
8491 struct rcsbuffer rcsbufin;
8496 fout = rcs_internal_lockfile (rcs->path);
8498 RCS_putadmin (rcs, fout);
8499 RCS_putdtree (rcs, rcs->head, fout);
8500 RCS_putdesc (rcs, fout);
8502 /* Open the original RCS file and seek to the first delta text. */
8503 rcsbuf_cache_open (rcs, rcs->delta_pos, &fin, &rcsbufin);
8505 /* Update delta_pos to the current position in the output file.
8506 Do NOT move these statements: they must be done after fin has
8507 been positioned at the old delta_pos, but before any delta
8508 texts have been written to fout. */
8509 rcs->delta_pos = ftell (fout);
8510 if (rcs->delta_pos == -1)
8511 error (1, errno, "cannot ftell in RCS file %s", rcs->path);
8513 RCS_copydeltas (rcs, fin, &rcsbufin, fout, newdtext, insertpt);
8515 /* We don't want to call rcsbuf_cache here, since we're about to
8517 rcsbuf_close (&rcsbufin);
8519 /* The only case in which using errno here would be meaningful
8520 is if we happen to have left errno unmolested since the call
8521 which produced the error (e.g. fread). That is pretty
8522 fragile even if it happens to sometimes be true. The real
8523 solution is to make sure that all the code which reads
8524 from fin checks for errors itself (some does, some doesn't). */
8525 error (0, 0, "warning: when closing RCS file `%s'", rcs->path);
8526 if (fclose (fin) < 0)
8527 error (0, errno, "warning: closing RCS file `%s'", rcs->path);
8529 rcs_internal_unlockfile (fout, rcs->path);
8533 /* Annotate command. In rcs.c for historical reasons (from back when
8534 what is now RCS_deltas was part of annotate_fileproc). */
8536 /* Options from the command line. */
8538 static int force_tag_match = 1;
8539 static char *tag = NULL;
8540 static char *date = NULL;
8542 static int annotate_fileproc PROTO ((void *callerdat, struct file_info *));
8545 annotate_fileproc (callerdat, finfo)
8547 struct file_info *finfo;
8550 struct rcsbuffer *rcsbufp = NULL;
8551 struct rcsbuffer rcsbuf;
8554 if (finfo->rcs == NULL)
8557 if (finfo->rcs->flags & PARTIAL)
8559 RCS_reparsercsfile (finfo->rcs, &fp, &rcsbuf);
8563 version = RCS_getversion (finfo->rcs, tag, date, force_tag_match,
8565 if (version == NULL)
8568 /* Distinguish output for various files if we are processing
8570 cvs_outerr ("Annotations for ", 0);
8571 cvs_outerr (finfo->fullname, 0);
8572 cvs_outerr ("\n***************\n", 0);
8574 RCS_deltas (finfo->rcs, fp, rcsbufp, version, RCS_ANNOTATE, (char **) NULL,
8575 (size_t) NULL, (char **) NULL, (size_t *) NULL);
8580 static const char *const annotate_usage[] =
8582 "Usage: %s %s [-lRf] [-r rev|-D date] [files...]\n",
8583 "\t-l\tLocal directory only, no recursion.\n",
8584 "\t-R\tProcess directories recursively.\n",
8585 "\t-f\tUse head revision if tag/date not found.\n",
8586 "\t-r rev\tAnnotate file as of specified revision/tag.\n",
8587 "\t-D date\tAnnotate file as of specified date.\n",
8588 "(Specify the --help global option for a list of other help options)\n",
8592 /* Command to show the revision, date, and author where each line of a
8593 file was modified. */
8596 annotate (argc, argv)
8604 usage (annotate_usage);
8607 while ((c = getopt (argc, argv, "+lr:D:fR")) != -1)
8621 date = Make_Date (optarg);
8624 force_tag_match = 0;
8628 usage (annotate_usage);
8635 #ifdef CLIENT_SUPPORT
8643 if (!force_tag_match)
8645 option_with_arg ("-r", tag);
8647 client_senddate (date);
8648 send_file_names (argc, argv, SEND_EXPAND_WILD);
8649 send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
8650 send_to_server ("annotate\012", 0);
8651 return get_responses_and_close ();
8653 #endif /* CLIENT_SUPPORT */
8656 tag_check_valid (tag, argc, argv, local, 0, "");
8658 return start_recursion (annotate_fileproc, (FILESDONEPROC) NULL,
8659 (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
8660 argc, argv, local, W_LOCAL, 0, 1, (char *)NULL,
8665 * For a given file with full pathname PATH and revision number REV,
8666 * produce a file label suitable for passing to diff. The default
8667 * file label as used by RCS 5.7 looks like this:
8669 * FILENAME <tab> YYYY/MM/DD <sp> HH:MM:SS <tab> REVNUM
8671 * The date and time used are the revision's last checkin date and time.
8672 * If REV is NULL, use the working copy's mtime instead.
8675 make_file_label (path, rev, rcs)
8680 char datebuf[MAXDATELEN];
8684 file = last_component (path);
8685 label = (char *) xmalloc (strlen (file)
8686 + (rev == NULL ? 0 : strlen (rev))
8692 RCS_getrevtime (rcs, rev, datebuf, 0);
8693 date = printable_date (datebuf);
8694 (void) sprintf (label, "-L%s\t%s\t%s", file, date, rev);
8702 if (CVS_STAT (file, &sb) < 0)
8703 error (0, 1, "could not get info for `%s'", path);
8706 wm = gmtime (&sb.st_mtime);
8707 (void) sprintf (datebuf, "%04d/%02d/%02d %02d:%02d:%02d",
8708 wm->tm_year + 1900, wm->tm_mon + 1,
8709 wm->tm_mday, wm->tm_hour,
8710 wm->tm_min, wm->tm_sec);
8711 (void) sprintf (label, "-L%s\t%s", file, datebuf);
8718 RCS_setlocalid (arg)
8721 char *copy, *next, *key;
8723 copy = xstrdup(arg);
8725 key = strtok(next, "=");
8727 keywords[KEYWORD_LOCALID].string = xstrdup(key);
8728 keywords[KEYWORD_LOCALID].len = strlen(key);
8729 keywords[KEYWORD_LOCALID].expandit = 1;
8732 while (key = strtok(NULL, ",")) {
8733 if (!strcmp(key, keywords[KEYWORD_ID].string))
8734 keyword_local = KEYWORD_ID;
8735 else if (!strcmp(key, keywords[KEYWORD_HEADER].string))
8736 keyword_local = KEYWORD_HEADER;
8737 else if (!strcmp(key, keywords[KEYWORD_CVSHEADER].string))
8738 keyword_local = KEYWORD_CVSHEADER;
8740 error(1, 0, "Unknown LocalId mode: %s", key);
8752 struct rcs_keyword *keyword;
8754 copy = xstrdup(arg);
8769 for (keyword = keywords; keyword->string != NULL; keyword++)
8771 keyword->expandit = 0;
8774 key = strtok(next, ",");
8776 for (keyword = keywords; keyword->string != NULL; keyword++) {
8777 if (strcmp (keyword->string, key) == 0)
8778 keyword->expandit = include;
8780 key = strtok(NULL, ",");
8786 #define ATTIC "/" CVSATTIC
8788 getfullCVSname(CVSname, pathstore)
8789 char *CVSname, **pathstore;
8791 if (CVSroot_directory) {
8794 int alen = sizeof(ATTIC) - 1;
8796 *pathstore = xstrdup(CVSname);
8797 if ((c = strrchr(*pathstore, '/')) != NULL) {
8798 if (c - *pathstore >= alen) {
8799 if (!strncmp(c - alen, ATTIC, alen)) {
8800 while (*c != '\0') {
8809 rootlen = strlen(CVSroot_directory);
8810 if (!strncmp(*pathstore, CVSroot_directory, rootlen) &&
8811 (*pathstore)[rootlen] == '/')
8812 CVSname = (*pathstore + rootlen + 1);
8814 CVSname = (*pathstore);