Bring cvs-1.12.9 into the CVS repository
[dragonfly.git] / contrib / cvs-1.12.9 / src / rcs.c
1 /*
2  * Copyright (c) 1992, Brian Berliner and Jeff Polk
3  * 
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.
6  * 
7  * The routines contained in this file do all the rcs file parsing and
8  * manipulation
9  */
10
11 #include "cvs.h"
12 #include "edit.h"
13 #include "hardlink.h"
14
15 /* These need to be source after cvs.h or HAVE_MMAP won't be set... */
16 #ifdef HAVE_MMAP
17 # include <sys/mman.h>
18 # ifndef HAVE_GETPAGESIZE
19 #  include "getpagesize.h"
20 # endif
21 # ifndef MAP_FAILED
22 #  define MAP_FAILED NULL
23 # endif
24 #endif
25
26 int preserve_perms = 0;
27
28 /* The RCS -k options, and a set of enums that must match the array.
29    These come first so that we can use enum kflag in function
30    prototypes.  */
31 static const char *const kflags[] =
32   {"kv", "kvl", "k", "v", "o", "b", (char *) NULL};
33 enum kflag { KFLAG_KV = 0, KFLAG_KVL, KFLAG_K, KFLAG_V, KFLAG_O, KFLAG_B };
34
35 /* A structure we use to buffer the contents of an RCS file.  The
36    various fields are only referenced directly by the rcsbuf_*
37    functions.  We declare the struct here so that we can allocate it
38    on the stack, rather than in memory.  */
39
40 struct rcsbuffer
41 {
42     /* Points to the current position in the buffer.  */
43     char *ptr;
44     /* Points just after the last valid character in the buffer.  */
45     char *ptrend;
46     /* The file.  */
47     FILE *fp;
48     /* The name of the file, used for error messages.  */
49     const char *filename;
50     /* The starting file position of the data in the buffer.  */
51     unsigned long pos;
52     /* The length of the value.  */
53     size_t vlen;
54     /* Whether the value contains an '@' string.  If so, we can not
55        compress whitespace characters.  */
56     int at_string;
57     /* The number of embedded '@' characters in an '@' string.  If
58        this is non-zero, we must search the string for pairs of '@'
59        and convert them to a single '@'.  */
60     int embedded_at;
61 };
62
63 static RCSNode *RCS_parsercsfile_i (FILE * fp, const char *rcsfile);
64 static char *RCS_getdatebranch (RCSNode * rcs, const char *date,
65                                 const char *branch);
66 static void rcsbuf_open (struct rcsbuffer *, FILE *fp,
67                          const char *filename, unsigned long pos);
68 static void rcsbuf_close (struct rcsbuffer *);
69 static int rcsbuf_getkey (struct rcsbuffer *, char **keyp,
70                                  char **valp);
71 static int rcsbuf_getrevnum (struct rcsbuffer *, char **revp);
72 static char *rcsbuf_fill (struct rcsbuffer *, char *ptr, char **keyp,
73                           char **valp);
74 static int rcsbuf_valcmp (struct rcsbuffer *);
75 static char *rcsbuf_valcopy (struct rcsbuffer *, char *val, int polish,
76                              size_t *lenp);
77 static void rcsbuf_valpolish (struct rcsbuffer *, char *val, int polish,
78                               size_t *lenp);
79 static void rcsbuf_valpolish_internal (struct rcsbuffer *, char *to,
80                                        const char *from, size_t *lenp);
81 static off_t rcsbuf_ftello (struct rcsbuffer *);
82 static void rcsbuf_get_buffered (struct rcsbuffer *, char **datap,
83                                         size_t *lenp);
84 static void rcsbuf_cache (RCSNode *, struct rcsbuffer *);
85 static void rcsbuf_cache_close (void);
86 static void rcsbuf_cache_open (RCSNode *, off_t, FILE **,
87                                       struct rcsbuffer *);
88 static int checkmagic_proc (Node *p, void *closure);
89 static void do_branches (List * list, char *val);
90 static void do_symbols (List * list, char *val);
91 static void do_locks (List * list, char *val);
92 static void free_rcsnode_contents (RCSNode *);
93 static void free_rcsvers_contents (RCSVers *);
94 static void rcsvers_delproc (Node * p);
95 static char *translate_symtag (RCSNode *, const char *);
96 static char *RCS_addbranch (RCSNode *, const char *);
97 static char *truncate_revnum_in_place (char *);
98 static char *truncate_revnum (const char *);
99 static char *printable_date (const char *);
100 static char *escape_keyword_value (const char *, int *);
101 static void expand_keywords (RCSNode *, RCSVers *, const char *,
102                              const char *, size_t, enum kflag, char *,
103                              size_t, char **, size_t *);
104 static void cmp_file_buffer (void *, const char *, size_t);
105
106 /* Routines for reading, parsing and writing RCS files. */
107 static RCSVers *getdelta (struct rcsbuffer *, char *, char **,
108                                  char **);
109 static Deltatext *RCS_getdeltatext (RCSNode *, FILE *,
110                                            struct rcsbuffer *);
111 static void freedeltatext (Deltatext *);
112
113 static void RCS_putadmin (RCSNode *, FILE *);
114 static void RCS_putdtree (RCSNode *, char *, FILE *);
115 static void RCS_putdesc (RCSNode *, FILE *);
116 static void putdelta (RCSVers *, FILE *);
117 static int putrcsfield_proc (Node *, void *);
118 static int putsymbol_proc (Node *, void *);
119 static void RCS_copydeltas (RCSNode *, FILE *, struct rcsbuffer *,
120                                    FILE *, Deltatext *, char *);
121 static int count_delta_actions (Node *, void *);
122 static void putdeltatext (FILE *, Deltatext *);
123
124 static FILE *rcs_internal_lockfile (char *);
125 static void rcs_internal_unlockfile (FILE *, char *);
126 static char *rcs_lockfilename (const char *);
127
128 /* The RCS file reading functions are called a lot, and they do some
129    string comparisons.  This macro speeds things up a bit by skipping
130    the function call when the first characters are different.  It
131    evaluates its arguments multiple times.  */
132 #define STREQ(a, b) (*(char *)(a) == *(char *)(b) && strcmp ((a), (b)) == 0)
133
134 static char * getfullCVSname (char *, char **);
135
136 /*
137  * We don't want to use isspace() from the C library because:
138  *
139  * 1. The definition of "whitespace" in RCS files includes ASCII
140  *    backspace, but the C locale doesn't.
141  * 2. isspace is an very expensive function call in some implementations
142  *    due to the addition of wide character support.
143  */
144 static const char spacetab[] = {
145         0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x00 - 0x0f */
146         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */
147         1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */
148         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */
149         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
150         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
151         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x8f */
152         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */
153         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */
154         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */
155         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */
156         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */
157         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
158         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
159         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
160         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  /* 0xf0 - 0xff */
161 };
162
163 #define whitespace(c)   (spacetab[(unsigned char)c] != 0)
164
165 static char *rcs_lockfile = NULL;
166 static int rcs_lockfd = -1;
167
168
169
170 /*
171  * char *
172  * locate_rcs ( const char* file, const char *repository , int *inattic )
173  *
174  * Find an RCS file in the repository, case insensitively when the cased name
175  * doesn't exist, we are running as the server, and a client has asked us to
176  * ignore case.
177  *
178  * Most parts of CVS will want to rely instead on RCS_parse which calls this
179  * function and is called by recurse.c which then puts the result in useful
180  * places like the rcs field of struct file_info.
181  *
182  * INPUTS
183  *
184  *  repository          the repository (including the directory)
185  *  file                the filename within that directory (without RCSEXT).
186  *  inattic             NULL or a pointer to the output boolean
187  *
188  * OUTPUTS
189  *
190  *  inattic             If this input was non-null, the destination will be
191  *                      set to true if the file was found in the attic or
192  *                      false if not.  If no RCS file is found, this value
193  *                      is undefined.
194  *
195  * RETURNS
196  *
197  *  a newly-malloc'd array containing the absolute pathname of the RCS
198  *  file that was found or NULL when none was found.
199  *
200  * ERRORS
201  *
202  *  errno can be set by the return value of the final call to
203  *  locate_file_in_dir().  This should resolve to the system's existence error
204  *  value (sometime ENOENT) if the Attic directory did not exist and ENOENT if
205  *  the Attic was found but no matching files were found in the Attic or its
206  *  parent.
207  */
208 static char *
209 locate_rcs (const char *repository, const char *file, int *inattic)
210 {
211     char *retval;
212
213     /* First, try to find the file as cased. */
214     retval = xmalloc (strlen (repository)
215                       + sizeof (CVSATTIC)
216                       + strlen (file)
217                       + sizeof (RCSEXT)
218                       + 3);
219     sprintf (retval, "%s/%s%s", repository, file, RCSEXT);
220     if (isreadable (retval))
221     {
222         if (inattic)
223             *inattic = 0;
224         return retval;
225     }
226     sprintf (retval, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT);
227     if (isreadable (retval))
228     {
229         if (inattic)
230             *inattic = 1;
231         return retval;
232     }
233     free (retval);
234
235     return NULL;
236 }
237
238
239
240 /* A few generic thoughts on error handling, in particular the
241    printing of unexpected characters that we find in the RCS file
242    (that is, why we use '\x%x' rather than %c or some such).
243
244    * Avoiding %c means we don't have to worry about what is printable
245    and other such stuff.  In error handling, often better to keep it
246    simple.
247
248    * Hex rather than decimal or octal because character set standards
249    tend to use hex.
250
251    * Saying "character 0x%x" might make it sound like we are printing
252    a file offset.  So we use '\x%x'.
253
254    * Would be nice to print the offset within the file, but I can
255    imagine various portability hassles (in particular, whether
256    unsigned long is always big enough to hold file offsets).  */
257
258 /* Parse an rcsfile given a user file name and a repository.  If there is
259    an error, we print an error message and return NULL.  If the file
260    does not exist, we return NULL without printing anything (I'm not
261    sure this allows the caller to do anything reasonable, but it is
262    the current behavior).  */
263 RCSNode *
264 RCS_parse (const char *file, const char *repos)
265 {
266     RCSNode *rcs;
267     FILE *fp;
268     RCSNode *retval = NULL;
269     char *rcsfile;
270     int inattic;
271
272     /* We're creating a new RCSNode, so there is no hope of finding it
273        in the cache.  */
274     rcsbuf_cache_close ();
275
276     if ((rcsfile = locate_rcs (repos, file, &inattic)) == NULL)
277     {
278         /* Handle the error cases */
279     }
280     else if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) != NULL) 
281     {
282         rcs = RCS_parsercsfile_i(fp, rcsfile);
283         if (rcs != NULL)
284         {       
285             rcs->flags |= VALID;
286             if ( inattic )
287                 rcs->flags |= INATTIC;
288         }
289
290         free ( rcsfile );
291         retval = rcs;
292     }
293     else if (! existence_error (errno))
294     {
295         free ( rcsfile );
296         error (0, errno, "cannot open %s", rcsfile);
297     }
298
299     return retval;
300 }
301
302 /*
303  * Parse a specific rcsfile.
304  */
305 RCSNode *
306 RCS_parsercsfile (const char *rcsfile)
307 {
308     FILE *fp;
309     RCSNode *rcs;
310
311     /* We're creating a new RCSNode, so there is no hope of finding it
312        in the cache.  */
313     rcsbuf_cache_close ();
314
315     /* open the rcsfile */
316     if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) == NULL)
317     {
318         error (0, errno, "Couldn't open rcs file `%s'", rcsfile);
319         return (NULL);
320     }
321
322     rcs = RCS_parsercsfile_i (fp, rcsfile);
323
324     return (rcs);
325 }
326
327
328
329 /*
330  */ 
331 static RCSNode *
332 RCS_parsercsfile_i (FILE *fp, const char *rcsfile)
333 {
334     RCSNode *rdata;
335     struct rcsbuffer rcsbuf;
336     char *key, *value;
337
338     /* make a node */
339     rdata = (RCSNode *) xmalloc (sizeof (RCSNode));
340     memset ((char *)rdata, 0, sizeof (RCSNode));
341     rdata->refcount = 1;
342     rdata->path = xstrdup (rcsfile);
343
344     /* Process HEAD, BRANCH, and EXPAND keywords from the RCS header.
345
346        Most cvs operations on the main branch don't need any more
347        information.  Those that do call RCS_reparsercsfile to parse
348        the rest of the header and the deltas.  */
349
350     rcsbuf_open (&rcsbuf, fp, rcsfile, 0);
351
352     if (! rcsbuf_getkey (&rcsbuf, &key, &value))
353         goto l_error;
354     if (STREQ (key, RCSDESC))
355         goto l_error;
356
357     if (STREQ (RCSHEAD, key) && value != NULL)
358         rdata->head = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *)NULL);
359
360     if (! rcsbuf_getkey (&rcsbuf, &key, &value))
361         goto l_error;
362     if (STREQ (key, RCSDESC))
363         goto l_error;
364
365     if (STREQ (RCSBRANCH, key) && value != NULL)
366     {
367         char *cp;
368
369         rdata->branch = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *)NULL);
370         if ((numdots (rdata->branch) & 1) != 0)
371         {
372             /* turn it into a branch if it's a revision */
373             cp = strrchr (rdata->branch, '.');
374             *cp = '\0';
375         }
376     }
377
378     /* Look ahead for expand, stopping when we see desc or a revision
379        number.  */
380     while (1)
381     {
382         char *cp;
383
384         if (STREQ (RCSEXPAND, key))
385         {
386             rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0,
387                                             (size_t *)NULL);
388             break;
389         }
390
391         for (cp = key;
392              (isdigit ((unsigned char)*cp) || *cp == '.') && *cp != '\0';
393              cp++)
394             /* do nothing */ ;
395         if (*cp == '\0')
396             break;
397
398         if (STREQ (RCSDESC, key))
399             break;
400
401         if (! rcsbuf_getkey (&rcsbuf, &key, &value))
402             break;
403     }
404
405     rdata->flags |= PARTIAL;
406
407     rcsbuf_cache (rdata, &rcsbuf);
408
409     return rdata;
410
411 l_error:
412     error (0, 0, "`%s' does not appear to be a valid rcs file",
413            rcsfile);
414     rcsbuf_close (&rcsbuf);
415     freercsnode (&rdata);
416     fclose (fp);
417     return NULL;
418 }
419
420
421
422 /* Do the real work of parsing an RCS file.
423
424    On error, die with a fatal error; if it returns at all it was successful.
425
426    If PFP is NULL, close the file when done.  Otherwise, leave it open
427    and store the FILE * in *PFP.  */
428 void
429 RCS_reparsercsfile (RCSNode *rdata, FILE **pfp, struct rcsbuffer *rcsbufp)
430 {
431     FILE *fp;
432     char *rcsfile;
433     struct rcsbuffer rcsbuf;
434     Node *q, *kv;
435     RCSVers *vnode;
436     int gotkey;
437     char *cp;
438     char *key, *value;
439
440     assert (rdata != NULL);
441     rcsfile = rdata->path;
442
443     rcsbuf_cache_open (rdata, 0, &fp, &rcsbuf);
444
445     /* make a node */
446     /* This probably shouldn't be done until later: if a file has an
447        empty revision tree (which is permissible), rdata->versions
448        should be NULL. -twp */
449     rdata->versions = getlist ();
450
451     /*
452      * process all the special header information, break out when we get to
453      * the first revision delta
454      */
455     gotkey = 0;
456     for (;;)
457     {
458         /* get the next key/value pair */
459         if (!gotkey)
460         {
461             if (! rcsbuf_getkey (&rcsbuf, &key, &value))
462             {
463                 error (1, 0, "`%s' does not appear to be a valid rcs file",
464                        rcsfile);
465             }
466         }
467
468         gotkey = 0;
469
470         /* Skip head, branch and expand tags; we already have them. */
471         if (STREQ (key, RCSHEAD)
472             || STREQ (key, RCSBRANCH)
473             || STREQ (key, RCSEXPAND))
474         {
475             continue;
476         }
477
478         if (STREQ (key, "access"))
479         {
480             if (value != NULL)
481             {
482                 /* We pass the POLISH parameter as 1 because
483                    RCS_addaccess expects nothing but spaces.  FIXME:
484                    It would be easy and more efficient to change
485                    RCS_addaccess.  */
486                 rdata->access = rcsbuf_valcopy (&rcsbuf, value, 1,
487                                                 (size_t *) NULL);
488             }
489             continue;
490         }
491
492         /* We always save lock information, so that we can handle
493            -kkvl correctly when checking out a file. */
494         if (STREQ (key, "locks"))
495         {
496             if (value != NULL)
497                 rdata->locks_data = rcsbuf_valcopy (&rcsbuf, value, 0,
498                                                     (size_t *) NULL);
499             if (! rcsbuf_getkey (&rcsbuf, &key, &value))
500             {
501                 error (1, 0, "premature end of file reading %s", rcsfile);
502             }
503             if (STREQ (key, "strict") && value == NULL)
504             {
505                 rdata->strict_locks = 1;
506             }
507             else
508                 gotkey = 1;
509             continue;
510         }
511
512         if (STREQ (RCSSYMBOLS, key))
513         {
514             if (value != NULL)
515                 rdata->symbols_data = rcsbuf_valcopy (&rcsbuf, value, 0,
516                                                       (size_t *) NULL);
517             continue;
518         }
519
520         /*
521          * check key for '.''s and digits (probably a rev) if it is a
522          * revision or `desc', we are done with the headers and are down to the
523          * revision deltas, so we break out of the loop
524          */
525         for (cp = key;
526              (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
527              cp++)
528              /* do nothing */ ;
529         /* Note that when comparing with RCSDATE, we are not massaging
530            VALUE from the string found in the RCS file.  This is OK
531            since we know exactly what to expect.  */
532         if (*cp == '\0' && strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) == 0)
533             break;
534
535         if (STREQ (key, RCSDESC))
536             break;
537
538         if (STREQ (key, "comment"))
539         {
540             rdata->comment = rcsbuf_valcopy (&rcsbuf, value, 0,
541                                              (size_t *) NULL);
542             continue;
543         }
544         if (rdata->other == NULL)
545             rdata->other = getlist ();
546         kv = getnode ();
547         kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
548         kv->key = xstrdup (key);
549         kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
550                                    (size_t *) NULL);
551         if (addnode (rdata->other, kv) != 0)
552         {
553             error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
554                    key, rcsfile);
555             freenode (kv);
556         }
557
558         /* if we haven't grabbed it yet, we didn't want it */
559     }
560
561     /* We got out of the loop, so we have the first part of the first
562        revision delta in KEY (the revision) and VALUE (the date key
563        and its value).  This is what getdelta expects to receive.  */
564
565     while ((vnode = getdelta (&rcsbuf, rcsfile, &key, &value)) != NULL)
566     {
567         /* get the node */
568         q = getnode ();
569         q->type = RCSVERS;
570         q->delproc = rcsvers_delproc;
571         q->data = vnode;
572         q->key = vnode->version;
573
574         /* add the nodes to the list */
575         if (addnode (rdata->versions, q) != 0)
576         {
577 #if 0
578                 purify_printf("WARNING: Adding duplicate version: %s (%s)\n",
579                          q->key, rcsfile);
580                 freenode (q);
581 #endif
582         }
583     }
584
585     /* Here KEY and VALUE are whatever caused getdelta to return NULL.  */
586
587     if (STREQ (key, RCSDESC))
588     {
589         if (rdata->desc != NULL)
590         {
591             error (0, 0,
592                    "warning: duplicate key `%s' in RCS file `%s'",
593                    key, rcsfile);
594             free (rdata->desc);
595         }
596         rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
597     }
598
599     rdata->delta_pos = rcsbuf_ftello (&rcsbuf);
600
601     if (pfp == NULL)
602         rcsbuf_cache (rdata, &rcsbuf);
603     else
604     {
605         *pfp = fp;
606         *rcsbufp = rcsbuf;
607     }
608     rdata->flags &= ~PARTIAL;
609 }
610
611 /* Move RCS into or out of the Attic, depending on TOATTIC.  If the
612    file is already in the desired place, return without doing
613    anything.  At some point may want to think about how this relates
614    to RCS_rewrite but that is a bit hairy (if one wants renames to be
615    atomic, or that kind of thing).  If there is an error, print a message
616    and return 1.  On success, return 0.  */
617 int
618 RCS_setattic (RCSNode *rcs, int toattic)
619 {
620     char *newpath;
621     const char *p;
622     char *q;
623
624     /* Some systems aren't going to let us rename an open file.  */
625     rcsbuf_cache_close ();
626
627     /* Could make the pathname computations in this file, and probably
628        in other parts of rcs.c too, easier if the REPOS and FILE
629        arguments to RCS_parse got stashed in the RCSNode.  */
630
631     if (toattic)
632     {
633         mode_t omask;
634
635         if (rcs->flags & INATTIC)
636             return 0;
637
638         /* Example: rcs->path is "/foo/bar/baz,v".  */
639         newpath = xmalloc (strlen (rcs->path) + sizeof CVSATTIC + 5);
640         p = last_component (rcs->path);
641         strncpy (newpath, rcs->path, p - rcs->path);
642         strcpy (newpath + (p - rcs->path), CVSATTIC);
643
644         /* Create the Attic directory if it doesn't exist.  */
645         omask = umask (cvsumask);
646         if (CVS_MKDIR (newpath, 0777) < 0 && errno != EEXIST)
647             error (0, errno, "cannot make directory %s", newpath);
648         (void) umask (omask);
649
650         strcat (newpath, "/");
651         strcat (newpath, p);
652
653         if (CVS_RENAME (rcs->path, newpath) < 0)
654         {
655             int save_errno = errno;
656
657             /* The checks for isreadable look awfully fishy, but
658                I'm going to leave them here for now until I
659                can think harder about whether they take care of
660                some cases which should be handled somehow.  */
661
662             if (isreadable (rcs->path) || !isreadable (newpath))
663             {
664                 error (0, save_errno, "cannot rename %s to %s",
665                        rcs->path, newpath);
666                 free (newpath);
667                 return 1;
668             }
669         }
670     }
671     else
672     {
673         if (!(rcs->flags & INATTIC))
674             return 0;
675
676         newpath = xmalloc (strlen (rcs->path));
677
678         /* Example: rcs->path is "/foo/bar/Attic/baz,v".  */
679         p = last_component (rcs->path);
680         strncpy (newpath, rcs->path, p - rcs->path - 1);
681         newpath[p - rcs->path - 1] = '\0';
682         q = newpath + (p - rcs->path - 1) - (sizeof CVSATTIC - 1);
683         assert (strncmp (q, CVSATTIC, sizeof CVSATTIC - 1) == 0);
684         strcpy (q, p);
685
686         if (CVS_RENAME (rcs->path, newpath) < 0)
687         {
688             error (0, errno, "failed to move `%s' out of the attic",
689                    rcs->path);
690             free (newpath);
691             return 1;
692         }
693     }
694
695     free (rcs->path);
696     rcs->path = newpath;
697
698     return 0;
699 }
700
701 /*
702  * Fully parse the RCS file.  Store all keyword/value pairs, fetch the
703  * log messages for each revision, and fetch add and delete counts for
704  * each revision (we could fetch the entire text for each revision,
705  * but the only caller, log_fileproc, doesn't need that information,
706  * so we don't waste the memory required to store it).  The add and
707  * delete counts are stored on the OTHER field of the RCSVERSNODE
708  * structure, under the names ";add" and ";delete", so that we don't
709  * waste the memory space of extra fields in RCSVERSNODE for code
710  * which doesn't need this information.
711  */
712
713 void
714 RCS_fully_parse (RCSNode *rcs)
715 {
716     FILE *fp;
717     struct rcsbuffer rcsbuf;
718
719     RCS_reparsercsfile (rcs, &fp, &rcsbuf);
720
721     while (1)
722     {
723         char *key, *value;
724         Node *vers;
725         RCSVers *vnode;
726
727         /* Rather than try to keep track of how much information we
728            have read, just read to the end of the file.  */
729         if (!rcsbuf_getrevnum (&rcsbuf, &key))
730             break;
731
732         vers = findnode (rcs->versions, key);
733         if (vers == NULL)
734             error (1, 0,
735                    "mismatch in rcs file %s between deltas and deltatexts (%s)",
736                    rcs->path, key);
737
738         vnode = vers->data;
739
740         while (rcsbuf_getkey (&rcsbuf, &key, &value))
741         {
742             if (!STREQ (key, "text"))
743             {
744                 Node *kv;
745
746                 if (vnode->other == NULL)
747                     vnode->other = getlist ();
748                 kv = getnode ();
749                 kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
750                 kv->key = xstrdup (key);
751                 kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
752                                            (size_t *)NULL);
753                 if (addnode (vnode->other, kv) != 0)
754                 {
755                     error (0, 0,
756                            "\
757 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
758                            key, vnode->version, rcs->path);
759                     freenode (kv);
760                 }
761
762                 continue;
763             }
764
765             if (!STREQ (vnode->version, rcs->head))
766             {
767                 unsigned long add, del;
768                 char buf[50];
769                 Node *kv;
770
771                 /* This is a change text.  Store the add and delete
772                    counts.  */
773                 add = 0;
774                 del = 0;
775                 if (value != NULL)
776                 {
777                     size_t vallen;
778                     const char *cp;
779
780                     rcsbuf_valpolish (&rcsbuf, value, 0, &vallen);
781                     cp = value;
782                     while (cp < value + vallen)
783                     {
784                         char op;
785                         unsigned long count;
786
787                         op = *cp++;
788                         if (op != 'a' && op  != 'd')
789                             error (1, 0, "\
790 unrecognized operation '\\x%x' in %s",
791                                    op, rcs->path);
792                         (void) strtoul (cp, (char **) &cp, 10);
793                         if (*cp++ != ' ')
794                             error (1, 0, "space expected in %s revision %s",
795                                    rcs->path, vnode->version);
796                         count = strtoul (cp, (char **) &cp, 10);
797                         if (*cp++ != '\012')
798                             error (1, 0, "linefeed expected in %s revision %s",
799                                    rcs->path, vnode->version);
800
801                         if (op == 'd')
802                             del += count;
803                         else
804                         {
805                             add += count;
806                             while (count != 0)
807                             {
808                                 if (*cp == '\012')
809                                     --count;
810                                 else if (cp == value + vallen)
811                                 {
812                                     if (count != 1)
813                                         error (1, 0, "\
814 premature end of value in %s revision %s",
815                                                rcs->path, vnode->version);
816                                     else
817                                         break;
818                                 }
819                                 ++cp;
820                             }
821                         }
822                     }
823                 }
824
825                 sprintf (buf, "%lu", add);
826                 kv = getnode ();
827                 kv->type = RCSFIELD;
828                 kv->key = xstrdup (";add");
829                 kv->data = xstrdup (buf);
830                 if (addnode (vnode->other, kv) != 0)
831                 {
832                     error (0, 0,
833                            "\
834 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
835                            key, vnode->version, rcs->path);
836                     freenode (kv);
837                 }
838
839                 sprintf (buf, "%lu", del);
840                 kv = getnode ();
841                 kv->type = RCSFIELD;
842                 kv->key = xstrdup (";delete");
843                 kv->data = xstrdup (buf);
844                 if (addnode (vnode->other, kv) != 0)
845                 {
846                     error (0, 0,
847                            "\
848 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
849                            key, vnode->version, rcs->path);
850                     freenode (kv);
851                 }
852             }
853
854             /* We have found the "text" key which ends the data for
855                this revision.  Break out of the loop and go on to the
856                next revision.  */
857             break;
858         }
859     }
860
861     rcsbuf_cache (rcs, &rcsbuf);
862 }
863
864
865
866 /*
867  * freercsnode - free up the info for an RCSNode
868  */
869 void
870 freercsnode (RCSNode **rnodep)
871 {
872     if (rnodep == NULL || *rnodep == NULL)
873         return;
874
875     ((*rnodep)->refcount)--;
876     if ((*rnodep)->refcount != 0)
877     {
878         *rnodep = (RCSNode *) NULL;
879         return;
880     }
881     free ((*rnodep)->path);
882     if ((*rnodep)->head != (char *) NULL)
883         free ((*rnodep)->head);
884     if ((*rnodep)->branch != (char *) NULL)
885         free ((*rnodep)->branch);
886     free_rcsnode_contents (*rnodep);
887     free ((char *) *rnodep);
888     *rnodep = (RCSNode *) NULL;
889 }
890
891 /*
892  * free_rcsnode_contents - free up the contents of an RCSNode without
893  * freeing the node itself, or the file name, or the head, or the
894  * path.  This returns the RCSNode to the state it is in immediately
895  * after a call to RCS_parse.
896  */
897 static void
898 free_rcsnode_contents (RCSNode *rnode)
899 {
900     dellist (&rnode->versions);
901     if (rnode->symbols != (List *) NULL)
902         dellist (&rnode->symbols);
903     if (rnode->symbols_data != (char *) NULL)
904         free (rnode->symbols_data);
905     if (rnode->expand != NULL)
906         free (rnode->expand);
907     if (rnode->other != (List *) NULL)
908         dellist (&rnode->other);
909     if (rnode->access != NULL)
910         free (rnode->access);
911     if (rnode->locks_data != NULL)
912         free (rnode->locks_data);
913     if (rnode->locks != (List *) NULL)
914         dellist (&rnode->locks);
915     if (rnode->comment != NULL)
916         free (rnode->comment);
917     if (rnode->desc != NULL)
918         free (rnode->desc);
919 }
920
921 /* free_rcsvers_contents -- free up the contents of an RCSVers node,
922    but also free the pointer to the node itself. */
923 /* Note: The `hardlinks' list is *not* freed, since it is merely a
924    pointer into the `hardlist' structure (defined in hardlink.c), and
925    that structure is freed elsewhere in the program. */
926
927 static void
928 free_rcsvers_contents (RCSVers *rnode)
929 {
930     if (rnode->branches != (List *) NULL)
931         dellist (&rnode->branches);
932     if (rnode->date != (char *) NULL)
933         free (rnode->date);
934     if (rnode->next != (char *) NULL)
935         free (rnode->next);
936     if (rnode->author != (char *) NULL)
937         free (rnode->author);
938     if (rnode->state != (char *) NULL)
939         free (rnode->state);
940     if (rnode->other != (List *) NULL)
941         dellist (&rnode->other);
942     if (rnode->other_delta != NULL)
943         dellist (&rnode->other_delta);
944     if (rnode->text != NULL)
945         freedeltatext (rnode->text);
946     free ((char *) rnode);
947 }
948
949 /*
950  * rcsvers_delproc - free up an RCSVers type node
951  */
952 static void
953 rcsvers_delproc (Node *p)
954 {
955     free_rcsvers_contents (p->data);
956 }
957 \f
958 /* These functions retrieve keys and values from an RCS file using a
959    buffer.  We use this somewhat complex approach because it turns out
960    that for many common operations, CVS spends most of its time
961    reading keys, so it's worth doing some fairly hairy optimization.  */
962
963 /* The number of bytes we try to read each time we need more data.  */
964
965 #define RCSBUF_BUFSIZE (8192)
966
967 /* The buffer we use to store data.  This grows as needed.  */
968
969 static char *rcsbuf_buffer = NULL;
970 static size_t rcsbuf_buffer_size = 0;
971
972 /* Whether rcsbuf_buffer is in use.  This is used as a sanity check.  */
973
974 static int rcsbuf_inuse;
975
976 /* Set up to start gathering keys and values from an RCS file.  This
977    initializes RCSBUF.  */
978
979 static void
980 rcsbuf_open (struct rcsbuffer *rcsbuf, FILE *fp, const char *filename, long unsigned int pos)
981 {
982     if (rcsbuf_inuse)
983         error (1, 0, "rcsbuf_open: internal error");
984     rcsbuf_inuse = 1;
985
986 #ifdef HAVE_MMAP
987     {
988         /* When we have mmap, it is much more efficient to let the system do the
989          * buffering and caching for us
990          */
991         struct stat fs;
992         size_t mmap_off = 0;
993
994         if ( fstat (fileno(fp), &fs) < 0 )
995             error ( 1, errno, "Could not stat RCS archive %s for mapping", filename );
996
997         if (pos)
998         {
999             size_t ps = getpagesize ();
1000             mmap_off = ( pos / ps ) * ps;
1001         }
1002
1003         /* Map private here since this particular buffer is read only */
1004         rcsbuf_buffer = mmap ( NULL, fs.st_size - mmap_off,
1005                                 PROT_READ | PROT_WRITE,
1006                                 MAP_PRIVATE, fileno(fp), mmap_off );
1007         if ( rcsbuf_buffer == NULL || rcsbuf_buffer == MAP_FAILED )
1008             error ( 1, errno, "Could not map memory to RCS archive %s", filename );
1009
1010         rcsbuf_buffer_size = fs.st_size - mmap_off;
1011         rcsbuf->ptr = rcsbuf_buffer + pos - mmap_off;
1012         rcsbuf->ptrend = rcsbuf_buffer + fs.st_size - mmap_off;
1013         rcsbuf->pos = mmap_off;
1014     }
1015 #else /* HAVE_MMAP */
1016     if (rcsbuf_buffer_size < RCSBUF_BUFSIZE)
1017         expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, RCSBUF_BUFSIZE);
1018
1019     rcsbuf->ptr = rcsbuf_buffer;
1020     rcsbuf->ptrend = rcsbuf_buffer;
1021     rcsbuf->pos = pos;
1022 #endif /* HAVE_MMAP */
1023     rcsbuf->fp = fp;
1024     rcsbuf->filename = filename;
1025     rcsbuf->vlen = 0;
1026     rcsbuf->at_string = 0;
1027     rcsbuf->embedded_at = 0;
1028 }
1029
1030 /* Stop gathering keys from an RCS file.  */
1031
1032 static void
1033 rcsbuf_close (struct rcsbuffer *rcsbuf)
1034 {
1035     if (! rcsbuf_inuse)
1036         error (1, 0, "rcsbuf_close: internal error");
1037 #ifdef HAVE_MMAP
1038     munmap ( rcsbuf_buffer, rcsbuf_buffer_size );
1039 #endif
1040     rcsbuf_inuse = 0;
1041 }
1042
1043 /* Read a key/value pair from an RCS file.  This sets *KEYP to point
1044    to the key, and *VALUEP to point to the value.  A missing or empty
1045    value is indicated by setting *VALUEP to NULL.
1046
1047    This function returns 1 on success, or 0 on EOF.  If there is an
1048    error reading the file, or an EOF in an unexpected location, it
1049    gives a fatal error.
1050
1051    This sets *KEYP and *VALUEP to point to storage managed by
1052    rcsbuf_getkey.  Moreover, *VALUEP has not been massaged from the
1053    RCS format: it may contain embedded whitespace and embedded '@'
1054    characters.  Call rcsbuf_valcopy or rcsbuf_valpolish to do
1055    appropriate massaging.  */
1056
1057 /* Note that the extreme hair in rcsbuf_getkey is because profiling
1058    statistics show that it was worth it. */
1059
1060 static int
1061 rcsbuf_getkey (struct rcsbuffer *rcsbuf, char **keyp, char **valp)
1062 {
1063     register const char * const my_spacetab = spacetab;
1064     register char *ptr, *ptrend;
1065     char c;
1066
1067 #define my_whitespace(c)        (my_spacetab[(unsigned char)c] != 0)
1068
1069     rcsbuf->vlen = 0;
1070     rcsbuf->at_string = 0;
1071     rcsbuf->embedded_at = 0;
1072
1073     ptr = rcsbuf->ptr;
1074     ptrend = rcsbuf->ptrend;
1075
1076     /* Sanity check.  */
1077     assert (ptr >= rcsbuf_buffer && ptr <= rcsbuf_buffer + rcsbuf_buffer_size);
1078     assert (ptrend >= rcsbuf_buffer && ptrend <= rcsbuf_buffer + rcsbuf_buffer_size);
1079
1080 #ifndef HAVE_MMAP
1081     /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
1082        buffer, move back to the start of the buffer.  This keeps the
1083        buffer from growing indefinitely.  */
1084     if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
1085     {
1086         int len;
1087
1088         len = ptrend - ptr;
1089
1090         /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
1091            at a time, so we can't have more bytes than that past PTR.  */
1092         assert (len <= RCSBUF_BUFSIZE);
1093
1094         /* Update the POS field, which holds the file offset of the
1095            first byte in the RCSBUF_BUFFER buffer.  */
1096         rcsbuf->pos += ptr - rcsbuf_buffer;
1097
1098         memcpy (rcsbuf_buffer, ptr, len);
1099         ptr = rcsbuf_buffer;
1100         ptrend = ptr + len;
1101         rcsbuf->ptrend = ptrend;
1102     }
1103 #endif /* HAVE_MMAP */
1104
1105     /* Skip leading whitespace.  */
1106
1107     while (1)
1108     {
1109         if (ptr >= ptrend)
1110         {
1111             ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
1112             if (ptr == NULL)
1113                 return 0;
1114             ptrend = rcsbuf->ptrend;
1115         }
1116
1117         c = *ptr;
1118         if (! my_whitespace (c))
1119             break;
1120
1121         ++ptr;
1122     }
1123
1124     /* We've found the start of the key.  */
1125
1126     *keyp = ptr;
1127
1128     if (c != ';')
1129     {
1130         while (1)
1131         {
1132             ++ptr;
1133             if (ptr >= ptrend)
1134             {
1135                 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
1136                 if (ptr == NULL)
1137                     error (1, 0, "EOF in key in RCS file %s",
1138                            rcsbuf->filename);
1139                 ptrend = rcsbuf->ptrend;
1140             }
1141             c = *ptr;
1142             if (c == ';' || my_whitespace (c))
1143                 break;
1144         }
1145     }
1146
1147     /* Here *KEYP points to the key in the buffer, C is the character
1148        we found at the of the key, and PTR points to the location in
1149        the buffer where we found C.  We must set *PTR to \0 in order
1150        to terminate the key.  If the key ended with ';', then there is
1151        no value.  */
1152
1153     *ptr = '\0';
1154     ++ptr;
1155
1156     if (c == ';')
1157     {
1158         *valp = NULL;
1159         rcsbuf->ptr = ptr;
1160         return 1;
1161     }
1162
1163     /* C must be whitespace.  Skip whitespace between the key and the
1164        value.  If we find ';' now, there is no value.  */
1165
1166     while (1)
1167     {
1168         if (ptr >= ptrend)
1169         {
1170             ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
1171             if (ptr == NULL)
1172                 error (1, 0, "EOF while looking for value in RCS file %s",
1173                        rcsbuf->filename);
1174             ptrend = rcsbuf->ptrend;
1175         }
1176         c = *ptr;
1177         if (c == ';')
1178         {
1179             *valp = NULL;
1180             rcsbuf->ptr = ptr + 1;
1181             return 1;
1182         }
1183         if (! my_whitespace (c))
1184             break;
1185         ++ptr;
1186     }
1187
1188     /* Now PTR points to the start of the value, and C is the first
1189        character of the value.  */
1190
1191     if (c != '@')
1192         *valp = ptr;
1193     else
1194     {
1195         char *pat;
1196         size_t vlen;
1197
1198         /* Optimize the common case of a value composed of a single
1199            '@' string.  */
1200
1201         rcsbuf->at_string = 1;
1202
1203         ++ptr;
1204
1205         *valp = ptr;
1206
1207         while (1)
1208         {
1209             while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1210             {
1211                 /* Note that we pass PTREND as the PTR value to
1212                    rcsbuf_fill, so that we will wind up setting PTR to
1213                    the location corresponding to the old PTREND, so
1214                    that we don't search the same bytes again.  */
1215                 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1216                 if (ptr == NULL)
1217                     error (1, 0,
1218                            "EOF while looking for end of string in RCS file %s",
1219                            rcsbuf->filename);
1220                 ptrend = rcsbuf->ptrend;
1221             }
1222
1223             /* Handle the special case of an '@' right at the end of
1224                the known bytes.  */
1225             if (pat + 1 >= ptrend)
1226             {
1227                 /* Note that we pass PAT, not PTR, here.  */
1228                 pat = rcsbuf_fill (rcsbuf, pat, keyp, valp);
1229                 if (pat == NULL)
1230                 {
1231                     /* EOF here is OK; it just means that the last
1232                        character of the file was an '@' terminating a
1233                        value for a key type which does not require a
1234                        trailing ';'.  */
1235                     pat = rcsbuf->ptrend - 1;
1236
1237                 }
1238                 ptrend = rcsbuf->ptrend;
1239
1240                 /* Note that the value of PTR is bogus here.  This is
1241                    OK, because we don't use it.  */
1242             }
1243
1244             if (pat + 1 >= ptrend || pat[1] != '@')
1245                 break;
1246
1247             /* We found an '@' pair in the string.  Keep looking.  */
1248             ++rcsbuf->embedded_at;
1249             ptr = pat + 2;
1250         }
1251
1252         /* Here PAT points to the final '@' in the string.  */
1253
1254         *pat = '\0';
1255
1256         vlen = pat - *valp;
1257         if (vlen == 0)
1258             *valp = NULL;
1259         rcsbuf->vlen = vlen;
1260
1261         ptr = pat + 1;
1262     }
1263
1264     /* Certain keywords only have a '@' string.  If there is no '@'
1265        string, then the old getrcskey function assumed that they had
1266        no value, and we do the same.  */
1267
1268     {
1269         char *k;
1270
1271         k = *keyp;
1272         if (STREQ (k, RCSDESC)
1273             || STREQ (k, "text")
1274             || STREQ (k, "log"))
1275         {
1276             if (c != '@')
1277                 *valp = NULL;
1278             rcsbuf->ptr = ptr;
1279             return 1;
1280         }
1281     }
1282
1283     /* If we've already gathered a '@' string, try to skip whitespace
1284        and find a ';'.  */
1285     if (c == '@')
1286     {
1287         while (1)
1288         {
1289             char n;
1290
1291             if (ptr >= ptrend)
1292             {
1293                 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1294                 if (ptr == NULL)
1295                     error (1, 0, "EOF in value in RCS file %s",
1296                            rcsbuf->filename);
1297                 ptrend = rcsbuf->ptrend;
1298             }
1299             n = *ptr;
1300             if (n == ';')
1301             {
1302                 /* We're done.  We already set everything up for this
1303                    case above.  */
1304                 rcsbuf->ptr = ptr + 1;
1305                 return 1;
1306             }
1307             if (! my_whitespace (n))
1308                 break;
1309             ++ptr;
1310         }
1311
1312         /* The value extends past the '@' string.  We need to undo the
1313            '@' stripping done in the default case above.  This
1314            case never happens in a plain RCS file, but it can happen
1315            if user defined phrases are used.  */
1316         ((*valp)--)[rcsbuf->vlen++] = '@';
1317     }
1318
1319     /* Here we have a value which is not a simple '@' string.  We need
1320        to gather up everything until the next ';', including any '@'
1321        strings.  *VALP points to the start of the value.  If
1322        RCSBUF->VLEN is not zero, then we have already read an '@'
1323        string, and PTR points to the data following the '@' string.
1324        Otherwise, PTR points to the start of the value.  */
1325
1326     while (1)
1327     {
1328         char *start, *psemi, *pat;
1329
1330         /* Find the ';' which must end the value.  */
1331         start = ptr;
1332         while ((psemi = memchr (ptr, ';', ptrend - ptr)) == NULL)
1333         {
1334             int slen;
1335
1336             /* Note that we pass PTREND as the PTR value to
1337                rcsbuf_fill, so that we will wind up setting PTR to the
1338                location corresponding to the old PTREND, so that we
1339                don't search the same bytes again.  */
1340             slen = start - *valp;
1341             ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1342             if (ptr == NULL)
1343                 error (1, 0, "EOF in value in RCS file %s", rcsbuf->filename);
1344             start = *valp + slen;
1345             ptrend = rcsbuf->ptrend;
1346         }
1347
1348         /* See if there are any '@' strings in the value.  */
1349         pat = memchr (start, '@', psemi - start);
1350
1351         if (pat == NULL)
1352         {
1353             size_t vlen;
1354
1355             /* We're done with the value.  Trim any trailing
1356                whitespace.  */
1357
1358             rcsbuf->ptr = psemi + 1;
1359
1360             start = *valp;
1361             while (psemi > start && my_whitespace (psemi[-1]))
1362                 --psemi;
1363             *psemi = '\0';
1364
1365             vlen = psemi - start;
1366             if (vlen == 0)
1367                 *valp = NULL;
1368             rcsbuf->vlen = vlen;
1369
1370             return 1;
1371         }
1372
1373         /* We found an '@' string in the value.  We set RCSBUF->AT_STRING
1374            and RCSBUF->EMBEDDED_AT to indicate that we won't be able to
1375            compress whitespace correctly for this type of value.
1376            Since this type of value never arises in a normal RCS file,
1377            this should not be a big deal.  It means that if anybody
1378            adds a phrase which can have both an '@' string and regular
1379            text, they will have to handle whitespace compression
1380            themselves.  */
1381
1382         rcsbuf->at_string = 1;
1383         rcsbuf->embedded_at = -1;
1384
1385         ptr = pat + 1;
1386
1387         while (1)
1388         {
1389             while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1390             {
1391                 /* Note that we pass PTREND as the PTR value to
1392                    rcsbuff_fill, so that we will wind up setting PTR
1393                    to the location corresponding to the old PTREND, so
1394                    that we don't search the same bytes again.  */
1395                 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1396                 if (ptr == NULL)
1397                     error (1, 0,
1398                            "EOF while looking for end of string in RCS file %s",
1399                            rcsbuf->filename);
1400                 ptrend = rcsbuf->ptrend;
1401             }
1402
1403             /* Handle the special case of an '@' right at the end of
1404                the known bytes.  */
1405             if (pat + 1 >= ptrend)
1406             {
1407                 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1408                 if (ptr == NULL)
1409                     error (1, 0, "EOF in value in RCS file %s",
1410                            rcsbuf->filename);
1411                 ptrend = rcsbuf->ptrend;
1412             }
1413
1414             if (pat[1] != '@')
1415                 break;
1416
1417             /* We found an '@' pair in the string.  Keep looking.  */
1418             ptr = pat + 2;
1419         }
1420
1421         /* Here PAT points to the final '@' in the string.  */
1422         ptr = pat + 1;
1423     }
1424
1425 #undef my_whitespace
1426 }
1427
1428 /* Read an RCS revision number from an RCS file.  This sets *REVP to
1429    point to the revision number; it will point to space that is
1430    managed by the rcsbuf functions, and is only good until the next
1431    call to rcsbuf_getkey or rcsbuf_getrevnum.
1432
1433    This function returns 1 on success, or 0 on EOF.  If there is an
1434    error reading the file, or an EOF in an unexpected location, it
1435    gives a fatal error.  */
1436
1437 static int
1438 rcsbuf_getrevnum (struct rcsbuffer *rcsbuf, char **revp)
1439 {
1440     char *ptr, *ptrend;
1441     char c;
1442
1443     ptr = rcsbuf->ptr;
1444     ptrend = rcsbuf->ptrend;
1445
1446     *revp = NULL;
1447
1448     /* Skip leading whitespace.  */
1449
1450     while (1)
1451     {
1452         if (ptr >= ptrend)
1453         {
1454             ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
1455             if (ptr == NULL)
1456                 return 0;
1457             ptrend = rcsbuf->ptrend;
1458         }
1459
1460         c = *ptr;
1461         if (! whitespace (c))
1462             break;
1463
1464         ++ptr;
1465     }
1466
1467     if (! isdigit ((unsigned char) c) && c != '.')
1468         error (1, 0,
1469                "\
1470 unexpected '\\x%x' reading revision number in RCS file %s",
1471                c, rcsbuf->filename);
1472
1473     *revp = ptr;
1474
1475     do
1476     {
1477         ++ptr;
1478         if (ptr >= ptrend)
1479         {
1480             ptr = rcsbuf_fill (rcsbuf, ptr, revp, (char **) NULL);
1481             if (ptr == NULL)
1482                 error (1, 0,
1483                        "unexpected EOF reading revision number in RCS file %s",
1484                        rcsbuf->filename);
1485             ptrend = rcsbuf->ptrend;
1486         }
1487
1488         c = *ptr;
1489     }
1490     while (isdigit ((unsigned char) c) || c == '.');
1491
1492     if (! whitespace (c))
1493         error (1, 0, "\
1494 unexpected '\\x%x' reading revision number in RCS file %s",
1495                c, rcsbuf->filename);
1496
1497     *ptr = '\0';
1498
1499     rcsbuf->ptr = ptr + 1;
1500
1501     return 1;
1502 }
1503
1504 /* Fill RCSBUF_BUFFER with bytes from the file associated with RCSBUF,
1505    updating PTR and the PTREND field.  If KEYP and *KEYP are not NULL,
1506    then *KEYP points into the buffer, and must be adjusted if the
1507    buffer is changed.  Likewise for VALP.  Returns the new value of
1508    PTR, or NULL on error.  */
1509
1510 static char *
1511 rcsbuf_fill (rcsbuf, ptr, keyp, valp)
1512     struct rcsbuffer *rcsbuf;
1513     char *ptr;
1514     char **keyp;
1515     char **valp;
1516 {
1517 #ifdef HAVE_MMAP
1518     return NULL;
1519 #else /* HAVE_MMAP */
1520     int got;
1521
1522     if (rcsbuf->ptrend - rcsbuf_buffer + RCSBUF_BUFSIZE > rcsbuf_buffer_size)
1523     {
1524         int poff, peoff, koff, voff;
1525
1526         poff = ptr - rcsbuf_buffer;
1527         peoff = rcsbuf->ptrend - rcsbuf_buffer;
1528         koff = keyp == NULL ? 0 : *keyp - rcsbuf_buffer;
1529         voff = valp == NULL ? 0 : *valp - rcsbuf_buffer;
1530
1531         expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size,
1532                        rcsbuf_buffer_size + RCSBUF_BUFSIZE);
1533
1534         ptr = rcsbuf_buffer + poff;
1535         rcsbuf->ptrend = rcsbuf_buffer + peoff;
1536         if (keyp != NULL)
1537             *keyp = rcsbuf_buffer + koff;
1538         if (valp != NULL)
1539             *valp = rcsbuf_buffer + voff;
1540     }
1541
1542     got = fread (rcsbuf->ptrend, 1, RCSBUF_BUFSIZE, rcsbuf->fp);
1543     if (got == 0)
1544     {
1545         if (ferror (rcsbuf->fp))
1546             error (1, errno, "cannot read %s", rcsbuf->filename);
1547         return NULL;
1548     }
1549
1550     rcsbuf->ptrend += got;
1551
1552     return ptr;
1553 #endif /* HAVE_MMAP */
1554 }
1555
1556 /* Test whether the last value returned by rcsbuf_getkey is a composite
1557    value or not. */
1558    
1559 static int
1560 rcsbuf_valcmp (struct rcsbuffer *rcsbuf)
1561 {
1562     return rcsbuf->at_string && rcsbuf->embedded_at < 0;
1563 }
1564
1565 /* Copy the value VAL returned by rcsbuf_getkey into a memory buffer,
1566    returning the memory buffer.  Polish the value like
1567    rcsbuf_valpolish, q.v.  */
1568
1569 static char *
1570 rcsbuf_valcopy (struct rcsbuffer *rcsbuf, char *val, int polish, size_t *lenp)
1571 {
1572     size_t vlen;
1573     int embedded_at;
1574     char *ret;
1575
1576     if (val == NULL)
1577     {
1578         if (lenp != NULL)
1579             *lenp = 0;
1580         return NULL;
1581     }
1582
1583     vlen = rcsbuf->vlen;
1584     embedded_at = rcsbuf->embedded_at < 0 ? 0 : rcsbuf->embedded_at;
1585
1586     ret = xmalloc (vlen - embedded_at + 1);
1587
1588     if (rcsbuf->at_string ? embedded_at == 0 : ! polish)
1589     {
1590         /* No special action to take.  */
1591         memcpy (ret, val, vlen + 1);
1592         if (lenp != NULL)
1593             *lenp = vlen;
1594         return ret;
1595     }
1596
1597     rcsbuf_valpolish_internal (rcsbuf, ret, val, lenp);
1598     return ret;
1599 }
1600
1601 /* Polish the value VAL returned by rcsbuf_getkey.  The POLISH
1602    parameter is non-zero if multiple embedded whitespace characters
1603    should be compressed into a single whitespace character.  Note that
1604    leading and trailing whitespace was already removed by
1605    rcsbuf_getkey.  Within an '@' string, pairs of '@' characters are
1606    compressed into a single '@' character regardless of the value of
1607    POLISH.  If LENP is not NULL, set *LENP to the length of the value.  */
1608
1609 static void
1610 rcsbuf_valpolish (struct rcsbuffer *rcsbuf, char *val, int polish, size_t *lenp)
1611 {
1612     if (val == NULL)
1613     {
1614         if (lenp != NULL)
1615             *lenp= 0;
1616         return;
1617     }
1618
1619     if (rcsbuf->at_string ? rcsbuf->embedded_at == 0 : ! polish)
1620     {
1621         /* No special action to take.  */
1622         if (lenp != NULL)
1623             *lenp = rcsbuf->vlen;
1624         return;
1625     }
1626
1627     rcsbuf_valpolish_internal (rcsbuf, val, val, lenp);
1628 }
1629
1630 /* Internal polishing routine, called from rcsbuf_valcopy and
1631    rcsbuf_valpolish.  */
1632
1633 static void
1634 rcsbuf_valpolish_internal (struct rcsbuffer *rcsbuf, char *to, const char *from, size_t *lenp)
1635 {
1636     size_t len;
1637
1638     len = rcsbuf->vlen;
1639
1640     if (! rcsbuf->at_string)
1641     {
1642         char *orig_to;
1643         size_t clen;
1644
1645         orig_to = to;
1646
1647         for (clen = len; clen > 0; ++from, --clen)
1648         {
1649             char c;
1650
1651             c = *from;
1652             if (whitespace (c))
1653             {
1654                 /* Note that we know that clen can not drop to zero
1655                    while we have whitespace, because we know there is
1656                    no trailing whitespace.  */
1657                 while (whitespace (from[1]))
1658                 {
1659                     ++from;
1660                     --clen;
1661                 }
1662                 c = ' ';
1663             }
1664             *to++ = c;
1665         }
1666
1667         *to = '\0';
1668
1669         if (lenp != NULL)
1670             *lenp = to - orig_to;
1671     }
1672     else
1673     {
1674         const char *orig_from;
1675         char *orig_to;
1676         int embedded_at;
1677         size_t clen;
1678
1679         orig_from = from;
1680         orig_to = to;
1681
1682         embedded_at = rcsbuf->embedded_at;
1683         assert (embedded_at > 0);
1684
1685         if (lenp != NULL)
1686             *lenp = len - embedded_at;
1687
1688         for (clen = len; clen > 0; ++from, --clen)
1689         {
1690             char c;
1691
1692             c = *from;
1693             *to++ = c;
1694             if (c == '@')
1695             {
1696                 ++from;
1697
1698                 /* Sanity check.
1699                  *
1700                  * FIXME: I restored this to an abort from an assert based on
1701                  * advice from Larry Jones that asserts should not be used to
1702                  * confirm the validity of an RCS file...  This leaves two
1703                  * issues here: 1) I am uncertain that the fact that we will
1704                  * only find double '@'s hasn't already been confirmed; and:
1705                  * 2) If this is the proper place to spot the error in the RCS
1706                  * file, then we should print a much clearer error here for the
1707                  * user!!!!!!!
1708                  *
1709                  *      - DRP
1710                  */
1711                 if (*from != '@' || clen == 0)
1712                     abort ();
1713
1714                 --clen;
1715
1716                 --embedded_at;
1717                 if (embedded_at == 0)
1718                 {
1719                     /* We've found all the embedded '@' characters.
1720                        We can just memcpy the rest of the buffer after
1721                        this '@' character.  */
1722                     if (orig_to != orig_from)
1723                         memcpy (to, from + 1, clen - 1);
1724                     else
1725                         memmove (to, from + 1, clen - 1);
1726                     from += clen;
1727                     to += clen - 1;
1728                     break;
1729                 }
1730             }
1731         }
1732
1733         /* Sanity check.  */
1734         assert (from == orig_from + len
1735             && to == orig_to + (len - rcsbuf->embedded_at));
1736
1737         *to = '\0';
1738     }
1739 }
1740
1741 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1742
1743 /* Copy the next word from the value VALP returned by rcsbuf_getkey into a
1744    memory buffer, updating VALP and returning the memory buffer.  Return
1745    NULL when there are no more words. */
1746
1747 static char *
1748 rcsbuf_valword (rcsbuf, valp)
1749     struct rcsbuffer *rcsbuf;
1750     char **valp;
1751 {
1752     register const char * const my_spacetab = spacetab;
1753     register char *ptr, *pat;
1754     char c;
1755
1756 # define my_whitespace(c)       (my_spacetab[(unsigned char)c] != 0)
1757
1758     if (*valp == NULL)
1759         return NULL;
1760
1761     for (ptr = *valp; my_whitespace (*ptr); ++ptr) ;
1762     if (*ptr == '\0')
1763     {
1764         assert (ptr - *valp == rcsbuf->vlen);
1765         *valp = NULL;
1766         rcsbuf->vlen = 0;
1767         return NULL;
1768     }
1769
1770     /* PTR now points to the start of a value.  Find out whether it is
1771        a num, an id, a string or a colon. */
1772     c = *ptr;
1773     if (c == ':')
1774     {
1775         rcsbuf->vlen -= ++ptr - *valp;
1776         *valp = ptr;
1777         return xstrdup (":");
1778     }
1779
1780     if (c == '@')
1781     {
1782         int embedded_at = 0;
1783         size_t vlen;
1784
1785         pat = ++ptr;
1786         while ((pat = strchr (pat, '@')) != NULL)
1787         {
1788             if (pat[1] != '@')
1789                 break;
1790             ++embedded_at;
1791             pat += 2;
1792         }
1793
1794         /* Here PAT points to the final '@' in the string.  */
1795         *pat++ = '\0';
1796         assert (rcsbuf->at_string);
1797         vlen = rcsbuf->vlen - (pat - *valp);
1798         rcsbuf->vlen = pat - ptr - 1;
1799         rcsbuf->embedded_at = embedded_at;
1800         ptr = rcsbuf_valcopy (rcsbuf, ptr, 0, (size_t *) NULL);
1801         *valp = pat;
1802         rcsbuf->vlen = vlen;
1803         if (strchr (pat, '@') == NULL)
1804             rcsbuf->at_string = 0;
1805         else
1806             rcsbuf->embedded_at = -1;
1807         return ptr;
1808     }
1809
1810     /* *PTR is neither `:', `;' nor `@', so it should be the start of a num
1811        or an id.  Make sure it is not another special character. */
1812     if (c == '$' || c == '.' || c == ',')
1813     {
1814         error (1, 0, "invalid special character in RCS field in %s",
1815                rcsbuf->filename);
1816     }
1817
1818     pat = ptr;
1819     while (1)
1820     {
1821         /* Legitimate ID characters are digits, dots and any `graphic
1822            printing character that is not a special.' This test ought
1823            to do the trick. */
1824         c = *++pat;
1825         if (!isprint ((unsigned char) c) ||
1826             c == ';' || c == '$' || c == ',' || c == '@' || c == ':')
1827             break;
1828     }
1829
1830     /* PAT points to the last non-id character in this word, and C is
1831        the character in its memory cell.  Check to make sure that it
1832        is a legitimate word delimiter -- whitespace or end. */
1833     if (c != '\0' && !my_whitespace (c))
1834         error (1, 0, "invalid special character in RCS field in %s",
1835                rcsbuf->filename);
1836
1837     *pat = '\0';
1838     rcsbuf->vlen -= pat - *valp;
1839     *valp = pat;
1840     return xstrdup (ptr);
1841
1842 # undef my_whitespace
1843 }
1844
1845 #endif
1846
1847 /* Return the current position of an rcsbuf.  */
1848
1849 static off_t
1850 rcsbuf_ftello (struct rcsbuffer *rcsbuf)
1851 {
1852     return rcsbuf->pos + rcsbuf->ptr - rcsbuf_buffer;
1853 }
1854
1855 /* Return a pointer to any data buffered for RCSBUF, along with the
1856    length.  */
1857
1858 static void
1859 rcsbuf_get_buffered (struct rcsbuffer *rcsbuf, char **datap, size_t *lenp)
1860 {
1861     *datap = rcsbuf->ptr;
1862     *lenp = rcsbuf->ptrend - rcsbuf->ptr;
1863 }
1864
1865 /* CVS optimizes by quickly reading some header information from a
1866    file.  If it decides it needs to do more with the file, it reopens
1867    it.  We speed that up here by maintaining a cache of a single open
1868    file, to save the time it takes to reopen the file in the common
1869    case.  */
1870
1871 static RCSNode *cached_rcs;
1872 static struct rcsbuffer cached_rcsbuf;
1873
1874 /* Cache RCS and RCSBUF.  This takes responsibility for closing
1875    RCSBUF->FP.  */
1876
1877 static void
1878 rcsbuf_cache (RCSNode *rcs, struct rcsbuffer *rcsbuf)
1879 {
1880     if (cached_rcs != NULL)
1881         rcsbuf_cache_close ();
1882     cached_rcs = rcs;
1883     ++rcs->refcount;
1884     cached_rcsbuf = *rcsbuf;
1885 }
1886
1887 /* If there is anything in the cache, close it.  */
1888
1889 static void
1890 rcsbuf_cache_close (void)
1891 {
1892     if (cached_rcs != NULL)
1893     {
1894         rcsbuf_close (&cached_rcsbuf);
1895         if (fclose (cached_rcsbuf.fp) != 0)
1896             error (0, errno, "cannot close %s", cached_rcsbuf.filename);
1897         freercsnode (&cached_rcs);
1898         cached_rcs = NULL;
1899     }
1900 }
1901
1902 /* Open an rcsbuffer for RCS, getting it from the cache if possible.
1903    Set *FPP to the file, and *RCSBUFP to the rcsbuf.  The file should
1904    be put at position POS.  */
1905
1906 static void
1907 rcsbuf_cache_open (RCSNode *rcs, off_t pos, FILE **pfp,
1908                    struct rcsbuffer *prcsbuf)
1909 {
1910 #ifndef HAVE_MMAP
1911     if (cached_rcs == rcs)
1912     {
1913         if (rcsbuf_ftello (&cached_rcsbuf) != pos)
1914         {
1915             if (fseeko (cached_rcsbuf.fp, pos, SEEK_SET) != 0)
1916                 error (1, 0, "cannot fseeko RCS file %s",
1917                        cached_rcsbuf.filename);
1918             cached_rcsbuf.ptr = rcsbuf_buffer;
1919             cached_rcsbuf.ptrend = rcsbuf_buffer;
1920             cached_rcsbuf.pos = pos;
1921         }
1922         *pfp = cached_rcsbuf.fp;
1923
1924         /* When RCS_parse opens a file using fopen_case, it frees the
1925            filename which we cached in CACHED_RCSBUF and stores a new
1926            file name in RCS->PATH.  We avoid problems here by always
1927            copying the filename over.  FIXME: This is hackish.  */
1928         cached_rcsbuf.filename = rcs->path;
1929
1930         *prcsbuf = cached_rcsbuf;
1931
1932         cached_rcs = NULL;
1933
1934         /* Removing RCS from the cache removes a reference to it.  */
1935         --rcs->refcount;
1936         if (rcs->refcount <= 0)
1937             error (1, 0, "rcsbuf_cache_open: internal error");
1938     }
1939     else
1940     {
1941 #endif /* ifndef HAVE_MMAP */
1942         /* FIXME:  If these routines can be rewritten to not write to the
1943          * rcs file buffer, there would be a considerably larger memory savings
1944          * from using mmap since the shared file would never need be copied to
1945          * process memory.
1946          *
1947          * If this happens, cached mmapped buffers would be usable, but don't
1948          * forget to make sure rcs->pos < pos here...
1949          */
1950         if (cached_rcs != NULL)
1951             rcsbuf_cache_close ();
1952
1953         *pfp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ);
1954         if (*pfp == NULL)
1955             error (1, 0, "unable to reopen `%s'", rcs->path);
1956 #ifndef HAVE_MMAP
1957         if (pos != 0)
1958         {
1959             if (fseeko (*pfp, pos, SEEK_SET) != 0)
1960                 error (1, 0, "cannot fseeko RCS file %s", rcs->path);
1961         }
1962 #endif /* ifndef HAVE_MMAP */
1963         rcsbuf_open (prcsbuf, *pfp, rcs->path, pos);
1964 #ifndef HAVE_MMAP
1965     }
1966 #endif /* ifndef HAVE_MMAP */
1967 }
1968
1969 \f
1970 /*
1971  * process the symbols list of the rcs file
1972  */
1973 static void
1974 do_symbols (List *list, char *val)
1975 {
1976     Node *p;
1977     char *cp = val;
1978     char *tag, *rev;
1979
1980     for (;;)
1981     {
1982         /* skip leading whitespace */
1983         while (whitespace (*cp))
1984             cp++;
1985
1986         /* if we got to the end, we are done */
1987         if (*cp == '\0')
1988             break;
1989
1990         /* split it up into tag and rev */
1991         tag = cp;
1992         cp = strchr (cp, ':');
1993         *cp++ = '\0';
1994         rev = cp;
1995         while (!whitespace (*cp) && *cp != '\0')
1996             cp++;
1997         if (*cp != '\0')
1998             *cp++ = '\0';
1999
2000         /* make a new node and add it to the list */
2001         p = getnode ();
2002         p->key = xstrdup (tag);
2003         p->data = xstrdup (rev);
2004         (void) addnode (list, p);
2005     }
2006 }
2007
2008 /*
2009  * process the locks list of the rcs file
2010  * Like do_symbols, but hash entries are keyed backwards: i.e.
2011  * an entry like `user:rev' is keyed on REV rather than on USER.
2012  */
2013 static void
2014 do_locks (List *list, char *val)
2015 {
2016     Node *p;
2017     char *cp = val;
2018     char *user, *rev;
2019
2020     for (;;)
2021     {
2022         /* skip leading whitespace */
2023         while (whitespace (*cp))
2024             cp++;
2025
2026         /* if we got to the end, we are done */
2027         if (*cp == '\0')
2028             break;
2029
2030         /* split it up into user and rev */
2031         user = cp;
2032         cp = strchr (cp, ':');
2033         *cp++ = '\0';
2034         rev = cp;
2035         while (!whitespace (*cp) && *cp != '\0')
2036             cp++;
2037         if (*cp != '\0')
2038             *cp++ = '\0';
2039
2040         /* make a new node and add it to the list */
2041         p = getnode ();
2042         p->key = xstrdup (rev);
2043         p->data = xstrdup (user);
2044         (void) addnode (list, p);
2045     }
2046 }
2047
2048 /*
2049  * process the branches list of a revision delta
2050  */
2051 static void
2052 do_branches (List *list, char *val)
2053 {
2054     Node *p;
2055     char *cp = val;
2056     char *branch;
2057
2058     for (;;)
2059     {
2060         /* skip leading whitespace */
2061         while (whitespace (*cp))
2062             cp++;
2063
2064         /* if we got to the end, we are done */
2065         if (*cp == '\0')
2066             break;
2067
2068         /* find the end of this branch */
2069         branch = cp;
2070         while (!whitespace (*cp) && *cp != '\0')
2071             cp++;
2072         if (*cp != '\0')
2073             *cp++ = '\0';
2074
2075         /* make a new node and add it to the list */
2076         p = getnode ();
2077         p->key = xstrdup (branch);
2078         (void) addnode (list, p);
2079     }
2080 }
2081
2082
2083
2084 /*
2085  * Version Number
2086  * 
2087  * Returns the requested version number of the RCS file, satisfying tags and/or
2088  * dates, and walking branches, if necessary.
2089  * 
2090  * The result is returned; null-string if error.
2091  */
2092 char *
2093 RCS_getversion (RCSNode *rcs, const char *tag, const char *date,
2094                 int force_tag_match, int *simple_tag)
2095 {
2096     if (simple_tag != NULL)
2097         *simple_tag = 0;
2098
2099     /* make sure we have something to look at... */
2100     assert (rcs != NULL);
2101
2102     if (tag && date)
2103     {
2104         char *branch, *rev;
2105
2106         if (! RCS_nodeisbranch (rcs, tag))
2107         {
2108             /* We can't get a particular date if the tag is not a
2109                branch.  */
2110             return NULL;
2111         }
2112
2113         /* Work out the branch.  */
2114         if (! isdigit ((unsigned char) tag[0]))
2115             branch = RCS_whatbranch (rcs, tag);
2116         else
2117             branch = xstrdup (tag);
2118
2119         /* Fetch the revision of branch as of date.  */
2120         rev = RCS_getdatebranch (rcs, date, branch);
2121         free (branch);
2122         return (rev);
2123     }
2124     else if (tag)
2125         return RCS_gettag (rcs, tag, force_tag_match, simple_tag);
2126     else if (date)
2127         return RCS_getdate (rcs, date, force_tag_match);
2128     else
2129         return RCS_head (rcs);
2130
2131 }
2132
2133
2134
2135 /*
2136  * Get existing revision number corresponding to tag or revision.
2137  * Similar to RCS_gettag but less interpretation imposed.
2138  * For example:
2139  * -- If tag designates a magic branch, RCS_tag2rev
2140  *    returns the magic branch number.
2141  * -- If tag is a branch tag, returns the branch number, not
2142  *    the revision of the head of the branch.
2143  * If tag or revision is not valid or does not exist in file,
2144  * return NULL.
2145  */
2146 char *
2147 RCS_tag2rev (RCSNode *rcs, char *tag)
2148 {
2149     char *rev, *pa, *pb;
2150     int i;
2151
2152     assert (rcs != NULL);
2153
2154     if (rcs->flags & PARTIAL)
2155         RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2156
2157     /* If a valid revision, try to look it up */
2158     if ( RCS_valid_rev (tag) )
2159     {
2160         /* Make a copy so we can scribble on it */
2161         rev =  xstrdup (tag);
2162
2163         /* If revision exists, return the copy */
2164         if (RCS_exist_rev (rcs, tag))
2165             return rev;
2166
2167         /* Nope, none such. If tag is not a branch we're done. */ 
2168         i = numdots (rev);
2169         if ((i & 1) == 1 )
2170         {
2171             pa = strrchr (rev, '.');
2172             if (i == 1 || *(pa-1) != RCS_MAGIC_BRANCH || *(pa-2) != '.')
2173             {
2174                 free (rev);
2175                 error (1, 0, "revision `%s' does not exist", tag);
2176             }
2177         }
2178
2179         /* Try for a real (that is, exists in the RCS deltas) branch
2180            (RCS_exist_rev just checks for real revisions and revisions
2181            which have tags pointing to them).  */
2182         pa = RCS_getbranch (rcs, rev, 1);
2183         if (pa != NULL)
2184         {
2185             free (pa);
2186             return rev;
2187         }
2188
2189        /* Tag is branch, but does not exist, try corresponding 
2190         * magic branch tag.
2191         *
2192         * FIXME: assumes all magic branches are of       
2193         * form "n.n.n ... .0.n".  I'll fix if somebody can
2194         * send me a method to get a magic branch tag with
2195         * the 0 in some other position -- <dan@gasboy.com>
2196         */ 
2197         pa = strrchr (rev, '.');
2198         pb = xmalloc (strlen (rev) + 3);
2199         *pa++ = 0;
2200         (void) sprintf (pb, "%s.%d.%s", rev, RCS_MAGIC_BRANCH, pa);
2201         free (rev);
2202         rev = pb;
2203         if (RCS_exist_rev (rcs, rev))
2204             return rev;
2205         error (1, 0, "revision `%s' does not exist", tag);
2206     }
2207
2208
2209     RCS_check_tag (tag); /* exit if not a valid tag */
2210
2211     /* If tag is "HEAD", special case to get head RCS revision */
2212     if (tag && STREQ (tag, TAG_HEAD))
2213         return (RCS_head (rcs));
2214
2215     /* If valid tag let translate_symtag say yea or nay. */
2216     rev = translate_symtag (rcs, tag);
2217
2218     if (rev)
2219         return rev;
2220
2221     /* Trust the caller to print warnings. */
2222     return NULL;
2223 }
2224
2225 /*
2226  * Find the revision for a specific tag.
2227  * If force_tag_match is set, return NULL if an exact match is not
2228  * possible otherwise return RCS_head ().  We are careful to look for
2229  * and handle "magic" revisions specially.
2230  * 
2231  * If the matched tag is a branch tag, find the head of the branch.
2232  * 
2233  * Returns pointer to newly malloc'd string, or NULL.
2234  */
2235 char *
2236 RCS_gettag (RCSNode *rcs, const char *symtag, int force_tag_match,
2237             int *simple_tag)
2238 {
2239     char *tag;
2240
2241     if (simple_tag != NULL)
2242         *simple_tag = 0;
2243
2244     /* make sure we have something to look at... */
2245     assert (rcs != NULL);
2246
2247     /* XXX this is probably not necessary, --jtc */
2248     if (rcs->flags & PARTIAL) 
2249         RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2250
2251     /* If symtag is "HEAD", special case to get head RCS revision */
2252     if (symtag && STREQ (symtag, TAG_HEAD))
2253 #if 0 /* This #if 0 is only in the Cygnus code.  Why?  Death support?  */
2254         if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
2255             return ((char *) NULL);     /* head request for removed file */
2256         else
2257 #endif
2258             return RCS_head (rcs);
2259
2260     if (!isdigit ((unsigned char) symtag[0]))
2261     {
2262         char *version;
2263
2264         /* If we got a symbolic tag, resolve it to a numeric */
2265         version = translate_symtag (rcs, symtag);
2266         if (version != NULL)
2267         {
2268             int dots;
2269             char *magic, *branch, *cp;
2270
2271             tag = version;
2272
2273             /*
2274              * If this is a magic revision, we turn it into either its
2275              * physical branch equivalent (if one exists) or into
2276              * its base revision, which we assume exists.
2277              */
2278             dots = numdots (tag);
2279             if (dots > 2 && (dots & 1) != 0)
2280             {
2281                 branch = strrchr (tag, '.');
2282                 cp = branch++ - 1;
2283                 while (*cp != '.')
2284                     cp--;
2285
2286                 /* see if we have .magic-branch. (".0.") */
2287                 magic = xmalloc (strlen (tag) + 1);
2288                 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2289                 if (strncmp (magic, cp, strlen (magic)) == 0)
2290                 {
2291                     /* it's magic.  See if the branch exists */
2292                     *cp = '\0';         /* turn it into a revision */
2293                     (void) sprintf (magic, "%s.%s", tag, branch);
2294                     branch = RCS_getbranch (rcs, magic, 1);
2295                     free (magic);
2296                     if (branch != NULL)
2297                     {
2298                         free (tag);
2299                         return branch;
2300                     }
2301                     return tag;
2302                 }
2303                 free (magic);
2304             }
2305         }
2306         else
2307         {
2308             /* The tag wasn't there, so return the head or NULL */
2309             if (force_tag_match)
2310                 return NULL;
2311             else
2312                 return RCS_head (rcs);
2313         }
2314     }
2315     else
2316         tag = xstrdup (symtag);
2317
2318     /* tag is always allocated and numeric now.  */
2319
2320     /*
2321      * numeric tag processing:
2322      *          1) revision number - just return it
2323      *          2) branch number   - find head of branch
2324      */
2325
2326     /* strip trailing dots */
2327     while (tag[strlen (tag) - 1] == '.')
2328         tag[strlen (tag) - 1] = '\0';
2329
2330     if ((numdots (tag) & 1) == 0)
2331     {
2332         char *branch;
2333
2334         /* we have a branch tag, so we need to walk the branch */
2335         branch = RCS_getbranch (rcs, tag, force_tag_match);
2336         free (tag);
2337         return branch;
2338     }
2339     else
2340     {
2341         Node *p;
2342
2343         /* we have a revision tag, so make sure it exists */
2344         p = findnode (rcs->versions, tag);
2345         if (p != NULL)
2346         {
2347             /* We have found a numeric revision for the revision tag.
2348                To support expanding the RCS keyword Name, if
2349                SIMPLE_TAG is not NULL, tell the the caller that this
2350                is a simple tag which co will recognize.  FIXME: Are
2351                there other cases in which we should set this?  In
2352                particular, what if we expand RCS keywords internally
2353                without calling co?  */
2354             if (simple_tag != NULL)
2355                 *simple_tag = 1;
2356             return tag;
2357         }
2358         else
2359         {
2360             /* The revision wasn't there, so return the head or NULL */
2361             free (tag);
2362             if (force_tag_match)
2363                 return NULL;
2364             else
2365                 return RCS_head (rcs);
2366         }
2367     }
2368 }
2369
2370 /*
2371  * Return a "magic" revision as a virtual branch off of REV for the RCS file.
2372  * A "magic" revision is one which is unique in the RCS file.  By unique, I
2373  * mean we return a revision which:
2374  *      - has a branch of 0 (see rcs.h RCS_MAGIC_BRANCH)
2375  *      - has a revision component which is not an existing branch off REV
2376  *      - has a revision component which is not an existing magic revision
2377  *      - is an even-numbered revision, to avoid conflicts with vendor branches
2378  * The first point is what makes it "magic".
2379  *
2380  * As an example, if we pass in 1.37 as REV, we will look for an existing
2381  * branch called 1.37.2.  If it did not exist, we would look for an
2382  * existing symbolic tag with a numeric part equal to 1.37.0.2.  If that
2383  * didn't exist, then we know that the 1.37.2 branch can be reserved by
2384  * creating a symbolic tag with 1.37.0.2 as the numeric part.
2385  *
2386  * This allows us to fork development with very little overhead -- just a
2387  * symbolic tag is used in the RCS file.  When a commit is done, a physical
2388  * branch is dynamically created to hold the new revision.
2389  *
2390  * Note: We assume that REV is an RCS revision and not a branch number.
2391  */
2392 static char *check_rev;
2393 char *
2394 RCS_magicrev (RCSNode *rcs, char *rev)
2395 {
2396     int rev_num;
2397     char *xrev, *test_branch, *local_branch_num;
2398
2399     xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */
2400     check_rev = xrev;
2401
2402     local_branch_num = getenv("CVS_LOCAL_BRANCH_NUM");
2403     if (local_branch_num)
2404     {
2405       rev_num = atoi(local_branch_num);
2406       if (rev_num < 2)
2407         rev_num = 2;
2408       else
2409         rev_num &= ~1;
2410     }
2411     else
2412       rev_num = 2;
2413
2414     /* only look at even numbered branches */
2415     for ( ; ; rev_num += 2)
2416     {
2417         /* see if the physical branch exists */
2418         (void) sprintf (xrev, "%s.%d", rev, rev_num);
2419         test_branch = RCS_getbranch (rcs, xrev, 1);
2420         if (test_branch != NULL)        /* it did, so keep looking */
2421         {
2422             free (test_branch);
2423             continue;
2424         }
2425
2426         /* now, create a "magic" revision */
2427         (void) sprintf (xrev, "%s.%d.%d", rev, RCS_MAGIC_BRANCH, rev_num);
2428
2429         /* walk the symbols list to see if a magic one already exists */
2430         if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0)
2431             continue;
2432
2433         /* we found a free magic branch.  Claim it as ours */
2434         return (xrev);
2435     }
2436 }
2437
2438 /*
2439  * walklist proc to look for a match in the symbols list.
2440  * Returns 0 if the symbol does not match, 1 if it does.
2441  */
2442 static int
2443 checkmagic_proc (Node *p, void *closure)
2444 {
2445     if (STREQ (check_rev, p->data))
2446         return (1);
2447     else
2448         return (0);
2449 }
2450
2451 /*
2452  * Given an RCSNode, returns non-zero if the specified revision number 
2453  * or symbolic tag resolves to a "branch" within the rcs file.
2454  *
2455  * FIXME: this is the same as RCS_nodeisbranch except for the special 
2456  *        case for handling a null rcsnode.
2457  */
2458 int
2459 RCS_isbranch (RCSNode *rcs, const char *rev)
2460 {
2461     /* numeric revisions are easy -- even number of dots is a branch */
2462     if (isdigit ((unsigned char) *rev))
2463         return ((numdots (rev) & 1) == 0);
2464
2465     /* assume a revision if you can't find the RCS info */
2466     if (rcs == NULL)
2467         return (0);
2468
2469     /* now, look for a match in the symbols list */
2470     return (RCS_nodeisbranch (rcs, rev));
2471 }
2472
2473 /*
2474  * Given an RCSNode, returns non-zero if the specified revision number
2475  * or symbolic tag resolves to a "branch" within the rcs file.  We do
2476  * take into account any magic branches as well.
2477  */
2478 int
2479 RCS_nodeisbranch (RCSNode *rcs, const char *rev)
2480 {
2481     int dots;
2482     char *version;
2483
2484     assert (rcs != NULL);
2485
2486     /* numeric revisions are easy -- even number of dots is a branch */
2487     if (isdigit ((unsigned char) *rev))
2488         return ((numdots (rev) & 1) == 0);
2489
2490     version = translate_symtag (rcs, rev);
2491     if (version == NULL)
2492         return (0);
2493     dots = numdots (version);
2494     if ((dots & 1) == 0)
2495     {
2496         free (version);
2497         return (1);
2498     }
2499
2500     /* got a symbolic tag match, but it's not a branch; see if it's magic */
2501     if (dots > 2)
2502     {
2503         char *magic;
2504         char *branch = strrchr (version, '.');
2505         char *cp = branch - 1;
2506         while (*cp != '.')
2507             cp--;
2508
2509         /* see if we have .magic-branch. (".0.") */
2510         magic = xmalloc (strlen (version) + 1);
2511         (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2512         if (strncmp (magic, cp, strlen (magic)) == 0)
2513         {
2514             free (magic);
2515             free (version);
2516             return (1);
2517         }
2518         free (magic);
2519     }
2520     free (version);
2521     return (0);
2522 }
2523
2524 /*
2525  * Returns a pointer to malloc'ed memory which contains the branch
2526  * for the specified *symbolic* tag.  Magic branches are handled correctly.
2527  */
2528 char *
2529 RCS_whatbranch (RCSNode *rcs, const char *rev)
2530 {
2531     char *version;
2532     int dots;
2533
2534     /* assume no branch if you can't find the RCS info */
2535     if (rcs == NULL)
2536         return ((char *) NULL);
2537
2538     /* now, look for a match in the symbols list */
2539     version = translate_symtag (rcs, rev);
2540     if (version == NULL)
2541         return ((char *) NULL);
2542     dots = numdots (version);
2543     if ((dots & 1) == 0)
2544         return (version);
2545
2546     /* got a symbolic tag match, but it's not a branch; see if it's magic */
2547     if (dots > 2)
2548     {
2549         char *magic;
2550         char *branch = strrchr (version, '.');
2551         char *cp = branch++ - 1;
2552         while (*cp != '.')
2553             cp--;
2554
2555         /* see if we have .magic-branch. (".0.") */
2556         magic = xmalloc (strlen (version) + 1);
2557         (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2558         if (strncmp (magic, cp, strlen (magic)) == 0)
2559         {
2560             /* yep.  it's magic.  now, construct the real branch */
2561             *cp = '\0';                 /* turn it into a revision */
2562             (void) sprintf (magic, "%s.%s", version, branch);
2563             free (version);
2564             return (magic);
2565         }
2566         free (magic);
2567     }
2568     free (version);
2569     return ((char *) NULL);
2570 }
2571
2572 /*
2573  * Get the head of the specified branch.  If the branch does not exist,
2574  * return NULL or RCS_head depending on force_tag_match.
2575  * Returns NULL or a newly malloc'd string.
2576  */
2577 char *
2578 RCS_getbranch (RCSNode *rcs, const char *tag, int force_tag_match)
2579 {
2580     Node *p, *head;
2581     RCSVers *vn;
2582     char *xtag;
2583     char *nextvers;
2584     char *cp;
2585
2586     /* make sure we have something to look at... */
2587     assert (rcs != NULL);
2588
2589     if (rcs->flags & PARTIAL)
2590         RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2591
2592     /* find out if the tag contains a dot, or is on the trunk */
2593     cp = strrchr (tag, '.');
2594
2595     /* trunk processing is the special case */
2596     if (cp == NULL)
2597     {
2598         xtag = xmalloc (strlen (tag) + 1 + 1);  /* +1 for an extra . */
2599         (void) strcpy (xtag, tag);
2600         (void) strcat (xtag, ".");
2601         for (cp = rcs->head; cp != NULL;)
2602         {
2603             if (strncmp (xtag, cp, strlen (xtag)) == 0)
2604                 break;
2605             p = findnode (rcs->versions, cp);
2606             if (p == NULL)
2607             {
2608                 free (xtag);
2609                 if (force_tag_match)
2610                     return (NULL);
2611                 else
2612                     return (RCS_head (rcs));
2613             }
2614             vn = p->data;
2615             cp = vn->next;
2616         }
2617         free (xtag);
2618         if (cp == NULL)
2619         {
2620             if (force_tag_match)
2621                 return (NULL);
2622             else
2623                 return (RCS_head (rcs));
2624         }
2625         return (xstrdup (cp));
2626     }
2627
2628     /* if it had a `.', terminate the string so we have the base revision */
2629     *cp = '\0';
2630
2631     /* look up the revision this branch is based on */
2632     p = findnode (rcs->versions, tag);
2633
2634     /* put the . back so we have the branch again */
2635     *cp = '.';
2636
2637     if (p == NULL)
2638     {
2639         /* if the base revision didn't exist, return head or NULL */
2640         if (force_tag_match)
2641             return (NULL);
2642         else
2643             return (RCS_head (rcs));
2644     }
2645
2646     /* find the first element of the branch we are looking for */
2647     vn = p->data;
2648     if (vn->branches == NULL)
2649         return (NULL);
2650     xtag = xmalloc (strlen (tag) + 1 + 1);      /* 1 for the extra '.' */
2651     (void) strcpy (xtag, tag);
2652     (void) strcat (xtag, ".");
2653     head = vn->branches->list;
2654     for (p = head->next; p != head; p = p->next)
2655         if (strncmp (p->key, xtag, strlen (xtag)) == 0)
2656             break;
2657     free (xtag);
2658
2659     if (p == head)
2660     {
2661         /* we didn't find a match so return head or NULL */
2662         if (force_tag_match)
2663             return (NULL);
2664         else
2665             return (RCS_head (rcs));
2666     }
2667
2668     /* now walk the next pointers of the branch */
2669     nextvers = p->key;
2670     do
2671     {
2672         p = findnode (rcs->versions, nextvers);
2673         if (p == NULL)
2674         {
2675             /* a link in the chain is missing - return head or NULL */
2676             if (force_tag_match)
2677                 return (NULL);
2678             else
2679                 return (RCS_head (rcs));
2680         }
2681         vn = p->data;
2682         nextvers = vn->next;
2683     } while (nextvers != NULL);
2684
2685     /* we have the version in our hand, so go for it */
2686     return (xstrdup (vn->version));
2687 }
2688
2689 /* Returns the head of the branch which REV is on.  REV can be a
2690    branch tag or non-branch tag; symbolic or numeric.
2691
2692    Returns a newly malloc'd string.  Returns NULL if a symbolic name
2693    isn't found.  */
2694
2695 char *
2696 RCS_branch_head (RCSNode *rcs, char *rev)
2697 {
2698     char *num;
2699     char *br;
2700     char *retval;
2701
2702     assert (rcs != NULL);
2703
2704     if (RCS_nodeisbranch (rcs, rev))
2705         return RCS_getbranch (rcs, rev, 1);
2706
2707     if (isdigit ((unsigned char) *rev))
2708         num = xstrdup (rev);
2709     else
2710     {
2711         num = translate_symtag (rcs, rev);
2712         if (num == NULL)
2713             return NULL;
2714     }
2715     br = truncate_revnum (num);
2716     retval = RCS_getbranch (rcs, br, 1);
2717     free (br);
2718     free (num);
2719     return retval;
2720 }
2721
2722 /* Get the branch point for a particular branch, that is the first
2723    revision on that branch.  For example, RCS_getbranchpoint (rcs,
2724    "1.3.2") will normally return "1.3.2.1".  TARGET may be either a
2725    branch number or a revision number; if a revnum, find the
2726    branchpoint of the branch to which TARGET belongs.
2727
2728    Return RCS_head if TARGET is on the trunk or if the root node could
2729    not be found (this is sort of backwards from our behavior on a branch;
2730    the rationale is that the return value is a revision from which you
2731    can start walking the next fields and end up at TARGET).
2732    Return NULL on error.  */
2733
2734 static char *
2735 RCS_getbranchpoint (RCSNode *rcs, char *target)
2736 {
2737     char *branch, *bp;
2738     Node *vp;
2739     RCSVers *rev;
2740     int dots, isrevnum, brlen;
2741
2742     dots = numdots (target);
2743     isrevnum = dots & 1;
2744
2745     if (dots == 1)
2746         /* TARGET is a trunk revision; return rcs->head. */
2747         return (RCS_head (rcs));
2748
2749     /* Get the revision number of the node at which TARGET's branch is
2750        rooted.  If TARGET is a branch number, lop off the last field;
2751        if it's a revision number, lop off the last *two* fields. */
2752     branch = xstrdup (target);
2753     bp = strrchr (branch, '.');
2754     if (bp == NULL)
2755         error (1, 0, "%s: confused revision number %s",
2756                rcs->path, target);
2757     if (isrevnum)
2758         while (*--bp != '.')
2759             ;
2760     *bp = '\0';
2761
2762     vp = findnode (rcs->versions, branch);
2763     if (vp == NULL)
2764     {   
2765         error (0, 0, "%s: can't find branch point %s", rcs->path, target);
2766         return NULL;
2767     }
2768     rev = vp->data;
2769
2770     *bp++ = '.';
2771     while (*bp && *bp != '.')
2772         ++bp;
2773     brlen = bp - branch;
2774
2775     vp = rev->branches->list->next;
2776     while (vp != rev->branches->list)
2777     {
2778         /* BRANCH may be a genuine branch number, e.g. `1.1.3', or
2779            maybe a full revision number, e.g. `1.1.3.6'.  We have
2780            found our branch point if the first BRANCHLEN characters
2781            of the revision number match, *and* if the following
2782            character is a dot. */
2783         if (strncmp (vp->key, branch, brlen) == 0 && vp->key[brlen] == '.')
2784             break;
2785         vp = vp->next;
2786     }
2787
2788     free (branch);
2789     if (vp == rev->branches->list)
2790     {
2791         error (0, 0, "%s: can't find branch point %s", rcs->path, target);
2792         return NULL;
2793     }
2794     else
2795         return (xstrdup (vp->key));
2796 }
2797
2798 /*
2799  * Get the head of the RCS file.  If branch is set, this is the head of the
2800  * branch, otherwise the real head.
2801  * Returns NULL or a newly malloc'd string.
2802  */
2803 char *
2804 RCS_head (RCSNode *rcs)
2805 {
2806     /* make sure we have something to look at... */
2807     assert (rcs != NULL);
2808
2809     /*
2810      * NOTE: we call getbranch with force_tag_match set to avoid any
2811      * possibility of recursion
2812      */
2813     if (rcs->branch)
2814         return (RCS_getbranch (rcs, rcs->branch, 1));
2815     else
2816         return (xstrdup (rcs->head));
2817 }
2818
2819 /*
2820  * Get the most recent revision, based on the supplied date, but use some
2821  * funky stuff and follow the vendor branch maybe
2822  */
2823 char *
2824 RCS_getdate (RCSNode *rcs, const char *date, int force_tag_match)
2825 {
2826     char *cur_rev = NULL;
2827     char *retval = NULL;
2828     Node *p;
2829     RCSVers *vers = NULL;
2830
2831     /* make sure we have something to look at... */
2832     assert (rcs != NULL);
2833
2834     if (rcs->flags & PARTIAL)
2835         RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2836
2837     /* if the head is on a branch, try the branch first */
2838     if (rcs->branch != NULL)
2839     {
2840         retval = RCS_getdatebranch (rcs, date, rcs->branch);
2841         if (retval != NULL)
2842             return (retval);
2843     }
2844
2845     /* otherwise if we have a trunk, try it */
2846     if (rcs->head)
2847     {
2848         p = findnode (rcs->versions, rcs->head);
2849         if (p == NULL)
2850         {
2851             error (0, 0, "%s: head revision %s doesn't exist", rcs->path,
2852                    rcs->head);
2853         }
2854         while (p != NULL)
2855         {
2856             /* if the date of this one is before date, take it */
2857             vers = p->data;
2858             if (RCS_datecmp (vers->date, date) <= 0)
2859             {
2860                 cur_rev = vers->version;
2861                 break;
2862             }
2863
2864             /* if there is a next version, find the node */
2865             if (vers->next != NULL)
2866                 p = findnode (rcs->versions, vers->next);
2867             else
2868                 p = (Node *) NULL;
2869         }
2870     }
2871     else
2872         error (0, 0, "%s: no head revision", rcs->path);
2873
2874     /*
2875      * at this point, either we have the revision we want, or we have the
2876      * first revision on the trunk (1.1?) in our hands, or we've come up
2877      * completely empty
2878      */
2879
2880     /* if we found what we're looking for, and it's not 1.1 return it */
2881     if (cur_rev != NULL)
2882     {
2883         if (! STREQ (cur_rev, "1.1"))
2884             return (xstrdup (cur_rev));
2885
2886         /* This is 1.1;  if the date of 1.1 is not the same as that for the
2887            1.1.1.1 version, then return 1.1.  This happens when the first
2888            version of a file is created by a regular cvs add and commit,
2889            and there is a subsequent cvs import of the same file.  */
2890         p = findnode (rcs->versions, "1.1.1.1");
2891         if (p)
2892         {
2893             char *date_1_1 = vers->date;
2894
2895             vers = p->data;
2896             if (RCS_datecmp (vers->date, date_1_1) != 0)
2897                 return xstrdup ("1.1");
2898         }
2899     }
2900
2901     /* look on the vendor branch */
2902     retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
2903
2904     /*
2905      * if we found a match, return it; otherwise, we return the first
2906      * revision on the trunk or NULL depending on force_tag_match and the
2907      * date of the first rev
2908      */
2909     if (retval != NULL)
2910         return (retval);
2911
2912     if (!force_tag_match ||
2913         (vers != NULL && RCS_datecmp (vers->date, date) <= 0))
2914         return xstrdup (vers->version);
2915     else
2916         return NULL;
2917 }
2918
2919
2920
2921 /*
2922  * Look up the last element on a branch that was put in before or on
2923  * the specified date and time (return the rev or NULL)
2924  */
2925 static char *
2926 RCS_getdatebranch (RCSNode *rcs, const char *date, const char *branch)
2927 {
2928     char *cur_rev = NULL;
2929     char *cp;
2930     char *xbranch, *xrev;
2931     Node *p;
2932     RCSVers *vers;
2933
2934     /* look up the first revision on the branch */
2935     xrev = xstrdup (branch);
2936     cp = strrchr (xrev, '.');
2937     if (cp == NULL)
2938     {
2939         free (xrev);
2940         return (NULL);
2941     }
2942     *cp = '\0';                         /* turn it into a revision */
2943
2944     assert (rcs != NULL);
2945
2946     if (rcs->flags & PARTIAL)
2947         RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
2948
2949     p = findnode (rcs->versions, xrev);
2950     free (xrev);
2951     if (p == NULL)
2952         return (NULL);
2953     vers = p->data;
2954
2955     /* Tentatively use this revision, if it is early enough.  */
2956     if (RCS_datecmp (vers->date, date) <= 0)
2957         cur_rev = vers->version;
2958
2959     /* If no branches list, return now.  This is what happens if the branch
2960        is a (magic) branch with no revisions yet.  */
2961     if (vers->branches == NULL)
2962         return xstrdup (cur_rev);
2963
2964     /* walk the branches list looking for the branch number */
2965     xbranch = xmalloc (strlen (branch) + 1 + 1); /* +1 for the extra dot */
2966     (void) strcpy (xbranch, branch);
2967     (void) strcat (xbranch, ".");
2968     for (p = vers->branches->list->next; p != vers->branches->list; p = p->next)
2969         if (strncmp (p->key, xbranch, strlen (xbranch)) == 0)
2970             break;
2971     free (xbranch);
2972     if (p == vers->branches->list)
2973     {
2974         /* This is what happens if the branch is a (magic) branch with
2975            no revisions yet.  Similar to the case where vers->branches ==
2976            NULL, except here there was a another branch off the same
2977            branchpoint.  */
2978         return xstrdup (cur_rev);
2979     }
2980
2981     p = findnode (rcs->versions, p->key);
2982
2983     /* walk the next pointers until you find the end, or the date is too late */
2984     while (p != NULL)
2985     {
2986         vers = p->data;
2987         if (RCS_datecmp (vers->date, date) <= 0)
2988             cur_rev = vers->version;
2989         else
2990             break;
2991
2992         /* if there is a next version, find the node */
2993         if (vers->next != NULL)
2994             p = findnode (rcs->versions, vers->next);
2995         else
2996             p = (Node *) NULL;
2997     }
2998
2999     /* Return whatever we found, which may be NULL.  */
3000     return xstrdup (cur_rev);
3001 }
3002
3003
3004
3005 /*
3006  * Compare two dates in RCS format. Beware the change in format on January 1,
3007  * 2000, when years go from 2-digit to full format.
3008  */
3009 int
3010 RCS_datecmp (const char *date1, const char *date2)
3011 {
3012     int length_diff = strlen (date1) - strlen (date2);
3013
3014     return length_diff ? length_diff : strcmp (date1, date2);
3015 }
3016
3017
3018
3019 /* Look up revision REV in RCS and return the date specified for the
3020    revision minus FUDGE seconds (FUDGE will generally be one, so that the
3021    logically previous revision will be found later, or zero, if we want
3022    the exact date).
3023
3024    The return value is the date being returned as a time_t, or (time_t)-1
3025    on error (previously was documented as zero on error; I haven't checked
3026    the callers to make sure that they really check for (time_t)-1, but
3027    the latter is what this function really returns).  If DATE is non-NULL,
3028    then it must point to MAXDATELEN characters, and we store the same
3029    return value there in DATEFORM format.  */
3030 time_t
3031 RCS_getrevtime (RCSNode *rcs, const char *rev, char *date, int fudge)
3032 {
3033     char tdate[MAXDATELEN];
3034     struct tm xtm, *ftm;
3035     time_t revdate = 0;
3036     Node *p;
3037     RCSVers *vers;
3038
3039     /* make sure we have something to look at... */
3040     assert (rcs != NULL);
3041
3042     if (rcs->flags & PARTIAL)
3043         RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3044
3045     /* look up the revision */
3046     p = findnode (rcs->versions, rev);
3047     if (p == NULL)
3048         return (-1);
3049     vers = p->data;
3050
3051     /* split up the date */
3052     if (sscanf (vers->date, SDATEFORM, &xtm.tm_year, &xtm.tm_mon,
3053                 &xtm.tm_mday, &xtm.tm_hour, &xtm.tm_min, &xtm.tm_sec) != 6)
3054         error (1, 0, "%s: invalid date for revision %s (%s)", rcs->path,
3055                rev, vers->date);
3056
3057     /* If the year is from 1900 to 1999, RCS files contain only two
3058        digits, and sscanf gives us a year from 0-99.  If the year is
3059        2000+, RCS files contain all four digits and we subtract 1900,
3060        because the tm_year field should contain years since 1900.  */
3061
3062     if (xtm.tm_year >= 100 && xtm.tm_year < 2000)
3063         error (0, 0, "%s: non-standard date format for revision %s (%s)",
3064                rcs->path, rev, vers->date);
3065     if (xtm.tm_year >= 1900)
3066         xtm.tm_year -= 1900;
3067
3068     /* put the date in a form getdate can grok */
3069     (void) sprintf (tdate, "%d/%d/%d GMT %d:%d:%d", xtm.tm_mon,
3070                     xtm.tm_mday, xtm.tm_year + 1900, xtm.tm_hour,
3071                     xtm.tm_min, xtm.tm_sec);
3072
3073     /* turn it into seconds since the epoch */
3074     revdate = get_date (tdate, (struct timeb *) NULL);
3075     if (revdate != (time_t) -1)
3076     {
3077         revdate -= fudge;               /* remove "fudge" seconds */
3078         if (date)
3079         {
3080             /* put an appropriate string into ``date'' if we were given one */
3081             ftm = gmtime (&revdate);
3082             (void) sprintf (date, DATEFORM,
3083                             ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
3084                             ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
3085                             ftm->tm_min, ftm->tm_sec);
3086         }
3087     }
3088     return revdate;
3089 }
3090
3091 List *
3092 RCS_getlocks (RCSNode *rcs)
3093 {
3094     assert(rcs != NULL);
3095
3096     if (rcs->flags & PARTIAL)
3097         RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3098
3099     if (rcs->locks_data) {
3100         rcs->locks = getlist ();
3101         do_locks (rcs->locks, rcs->locks_data);
3102         free(rcs->locks_data);
3103         rcs->locks_data = NULL;
3104     }
3105
3106     return rcs->locks;
3107 }
3108
3109 List *
3110 RCS_symbols(RCSNode *rcs)
3111 {
3112     assert(rcs != NULL);
3113
3114     if (rcs->flags & PARTIAL)
3115         RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3116
3117     if (rcs->symbols_data) {
3118         rcs->symbols = getlist ();
3119         do_symbols (rcs->symbols, rcs->symbols_data);
3120         free(rcs->symbols_data);
3121         rcs->symbols_data = NULL;
3122     }
3123
3124     return rcs->symbols;
3125 }
3126
3127 /*
3128  * Return the version associated with a particular symbolic tag.
3129  * Returns NULL or a newly malloc'd string.
3130  */
3131 static char *
3132 translate_symtag (RCSNode *rcs, const char *tag)
3133 {
3134     if (rcs->flags & PARTIAL)
3135         RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3136
3137     if (rcs->symbols != NULL)
3138     {
3139         Node *p;
3140
3141         /* The symbols have already been converted into a list.  */
3142         p = findnode (rcs->symbols, tag);
3143         if (p == NULL)
3144             return NULL;
3145
3146         return xstrdup (p->data);
3147     }
3148
3149     if (rcs->symbols_data != NULL)
3150     {
3151         size_t len;
3152         char *cp;
3153
3154         /* Look through the RCS symbols information.  This is like
3155            do_symbols, but we don't add the information to a list.  In
3156            most cases, we will only be called once for this file, so
3157            generating the list is unnecessary overhead.  */
3158
3159         len = strlen (tag);
3160         cp = rcs->symbols_data;
3161         while ((cp = strchr (cp, tag[0])) != NULL)
3162         {
3163             if ((cp == rcs->symbols_data || whitespace (cp[-1]))
3164                 && strncmp (cp, tag, len) == 0
3165                 && cp[len] == ':')
3166             {
3167                 char *v, *r;
3168
3169                 /* We found the tag.  Return the version number.  */
3170
3171                 cp += len + 1;
3172                 v = cp;
3173                 while (! whitespace (*cp) && *cp != '\0')
3174                     ++cp;
3175                 r = xmalloc (cp - v + 1);
3176                 strncpy (r, v, cp - v);
3177                 r[cp - v] = '\0';
3178                 return r;
3179             }
3180
3181             while (! whitespace (*cp) && *cp != '\0')
3182                 ++cp;
3183             if (*cp == '\0')
3184                 break;
3185         }
3186     }
3187
3188     return NULL;
3189 }
3190
3191 /*
3192  * The argument ARG is the getopt remainder of the -k option specified on the
3193  * command line.  This function returns malloc'ed space that can be used
3194  * directly in calls to RCS V5, with the -k flag munged correctly.
3195  */
3196 char *
3197 RCS_check_kflag (const char *arg)
3198 {
3199     static const char *const  keyword_usage[] =
3200     {
3201       "%s %s: invalid RCS keyword expansion mode\n",
3202       "Valid expansion modes include:\n",
3203       "   -kkv\tGenerate keywords using the default form.\n",
3204       "   -kkvl\tLike -kkv, except locker's name inserted.\n",
3205       "   -kk\tGenerate only keyword names in keyword strings.\n",
3206       "   -kv\tGenerate only keyword values in keyword strings.\n",
3207       "   -ko\tGenerate the old keyword string (no changes from checked in file).\n",
3208       "   -kb\tGenerate binary file unmodified (merges not allowed) (RCS 5.7).\n",
3209       "(Specify the --help global option for a list of other help options)\n",
3210       NULL,
3211     };
3212     /* Big enough to hold any of the strings from kflags.  */
3213     char karg[10];
3214     char const *const *cpp = NULL;
3215
3216     if (arg)
3217     {
3218         for (cpp = kflags; *cpp != NULL; cpp++)
3219         {
3220             if (STREQ (arg, *cpp))
3221                 break;
3222         }
3223     }
3224
3225     if (arg == NULL || *cpp == NULL)
3226     {
3227         usage (keyword_usage);
3228     }
3229
3230     (void) sprintf (karg, "-k%s", *cpp);
3231     return (xstrdup (karg));
3232 }
3233
3234 /*
3235  * Do some consistency checks on the symbolic tag... These should equate
3236  * pretty close to what RCS checks, though I don't know for certain.
3237  */
3238 void
3239 RCS_check_tag (const char *tag)
3240 {
3241     char *invalid = "$,.:;@";           /* invalid RCS tag characters */
3242     const char *cp;
3243
3244     /*
3245      * The first character must be an alphabetic letter. The remaining
3246      * characters cannot be non-visible graphic characters, and must not be
3247      * in the set of "invalid" RCS identifier characters.
3248      */
3249     if (isalpha ((unsigned char) *tag))
3250     {
3251         for (cp = tag; *cp; cp++)
3252         {
3253             if (!isgraph ((unsigned char) *cp))
3254                 error (1, 0, "tag `%s' has non-visible graphic characters",
3255                        tag);
3256             if (strchr (invalid, *cp))
3257                 error (1, 0, "tag `%s' must not contain the characters `%s'",
3258                        tag, invalid);
3259         }
3260     }
3261     else
3262         error (1, 0, "tag `%s' must start with a letter", tag);
3263 }
3264
3265 /*
3266  * TRUE if argument has valid syntax for an RCS revision or 
3267  * branch number.  All characters must be digits or dots, first 
3268  * and last characters must be digits, and no two consecutive 
3269  * characters may be dots.
3270  *
3271  * Intended for classifying things, so this function doesn't 
3272  * call error.
3273  */
3274 int 
3275 RCS_valid_rev (char *rev)
3276 {
3277    char last, c;
3278    last = *rev++;
3279    if (!isdigit ((unsigned char) last))
3280        return 0;
3281    while ((c = *rev++))   /* Extra parens placate -Wall gcc option */
3282    {
3283        if (c == '.')
3284        {
3285            if (last == '.')
3286                return 0;
3287            continue;
3288        }
3289        last = c;
3290        if (!isdigit ((unsigned char) c))
3291            return 0;
3292    }
3293    if (!isdigit ((unsigned char) last))
3294        return 0;
3295    return 1;
3296 }
3297
3298 /*
3299  * Return true if RCS revision with TAG is a dead revision.
3300  */
3301 int
3302 RCS_isdead (RCSNode *rcs, const char *tag)
3303 {
3304     Node *p;
3305     RCSVers *version;
3306
3307     if (rcs->flags & PARTIAL)
3308         RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
3309
3310     p = findnode (rcs->versions, tag);
3311     if (p == NULL)
3312         return (0);
3313
3314     version = p->data;
3315     return (version->dead);
3316 }
3317
3318 /* Return the RCS keyword expansion mode.  For example "b" for binary.
3319    Returns a pointer into storage which is allocated and freed along with
3320    the rest of the RCS information; the caller should not modify this
3321    storage.  Returns NULL if the RCS file does not specify a keyword
3322    expansion mode; for all other errors, die with a fatal error.  */
3323 char *
3324 RCS_getexpand (RCSNode *rcs)
3325 {
3326     /* Since RCS_parsercsfile_i now reads expand, don't need to worry
3327        about RCS_reparsercsfile.  */
3328     assert (rcs != NULL);
3329     return rcs->expand;
3330 }
3331
3332
3333
3334 /* Set keyword expansion mode to EXPAND.  For example "b" for binary.  */
3335 void
3336 RCS_setexpand (RCSNode *rcs, const char *expand)
3337 {
3338     /* Since RCS_parsercsfile_i now reads expand, don't need to worry
3339        about RCS_reparsercsfile.  */
3340     assert (rcs != NULL);
3341     if (rcs->expand != NULL)
3342         free (rcs->expand);
3343     rcs->expand = xstrdup (expand);
3344 }
3345
3346
3347
3348 /* RCS keywords, and a matching enum.  */
3349 struct rcs_keyword
3350 {
3351     const char *string;
3352     size_t len;
3353     int expandit;
3354 };
3355 #define KEYWORD_INIT(s) (s), sizeof (s) - 1
3356 static struct rcs_keyword keywords[] =
3357 {
3358     { KEYWORD_INIT ("Author"), 1 },
3359     { KEYWORD_INIT ("Date"), 1 },
3360     { KEYWORD_INIT ("CVSHeader"), 1 },
3361     { KEYWORD_INIT ("Header"), 1 },
3362     { KEYWORD_INIT ("Id"), 1 },
3363     { KEYWORD_INIT ("Locker"), 1 },
3364     { KEYWORD_INIT ("Log"), 1 },
3365     { KEYWORD_INIT ("Name"), 1 },
3366     { KEYWORD_INIT ("RCSfile"), 1 },
3367     { KEYWORD_INIT ("Revision"), 1 },
3368     { KEYWORD_INIT ("Source"), 1 },
3369     { KEYWORD_INIT ("State"), 1 },
3370     { NULL, 0, 0 },             /* localid */
3371     { NULL, 0, 0 }
3372 };
3373 enum keyword
3374 {
3375     KEYWORD_AUTHOR = 0,
3376     KEYWORD_DATE,
3377     KEYWORD_CVSHEADER,
3378     KEYWORD_HEADER,
3379     KEYWORD_ID,
3380     KEYWORD_LOCKER,
3381     KEYWORD_LOG,
3382     KEYWORD_NAME,
3383     KEYWORD_RCSFILE,
3384     KEYWORD_REVISION,
3385     KEYWORD_SOURCE,
3386     KEYWORD_STATE,
3387     KEYWORD_LOCALID
3388 };
3389 enum keyword keyword_local = KEYWORD_ID;
3390
3391 /* Convert an RCS date string into a readable string.  This is like
3392    the RCS date2str function.  */
3393
3394 static char *
3395 printable_date (const char *rcs_date)
3396 {
3397     int year, mon, mday, hour, min, sec;
3398     char buf[100];
3399
3400     (void) sscanf (rcs_date, SDATEFORM, &year, &mon, &mday, &hour, &min,
3401                    &sec);
3402     if (year < 1900)
3403         year += 1900;
3404     sprintf (buf, "%04d/%02d/%02d %02d:%02d:%02d", year, mon, mday,
3405              hour, min, sec);
3406     return xstrdup (buf);
3407 }
3408
3409 /* Escape the characters in a string so that it can be included in an
3410    RCS value.  */
3411
3412 static char *
3413 escape_keyword_value (const char *value, int *free_value)
3414 {
3415     char *ret, *t;
3416     const char *s;
3417
3418     for (s = value; *s != '\0'; s++)
3419     {
3420         char c;
3421
3422         c = *s;
3423         if (c == '\t'
3424             || c == '\n'
3425             || c == '\\'
3426             || c == ' '
3427             || c == '$')
3428         {
3429             break;
3430         }
3431     }
3432
3433     if (*s == '\0')
3434     {
3435         *free_value = 0;
3436         return (char *) value;
3437     }
3438
3439     ret = xmalloc (strlen (value) * 4 + 1);
3440     *free_value = 1;
3441
3442     for (s = value, t = ret; *s != '\0'; s++, t++)
3443     {
3444         switch (*s)
3445         {
3446         default:
3447             *t = *s;
3448             break;
3449         case '\t':
3450             *t++ = '\\';
3451             *t = 't';
3452             break;
3453         case '\n':
3454             *t++ = '\\';
3455             *t = 'n';
3456             break;
3457         case '\\':
3458             *t++ = '\\';
3459             *t = '\\';
3460             break;
3461         case ' ':
3462             *t++ = '\\';
3463             *t++ = '0';
3464             *t++ = '4';
3465             *t = '0';
3466             break;
3467         case '$':
3468             *t++ = '\\';
3469             *t++ = '0';
3470             *t++ = '4';
3471             *t = '4';
3472             break;
3473         }
3474     }
3475
3476     *t = '\0';
3477
3478     return ret;
3479 }
3480
3481 /* Expand RCS keywords in the memory buffer BUF of length LEN.  This
3482    applies to file RCS and version VERS.  If NAME is not NULL, and is
3483    not a numeric revision, then it is the symbolic tag used for the
3484    checkout.  EXPAND indicates how to expand the keywords.  This
3485    function sets *RETBUF and *RETLEN to the new buffer and length.
3486    This function may modify the buffer BUF.  If BUF != *RETBUF, then
3487    RETBUF is a newly allocated buffer.  */
3488
3489 static void
3490 expand_keywords (RCSNode *rcs, RCSVers *ver, const char *name, const char *log, size_t loglen, enum kflag expand, char *buf, size_t len, char **retbuf, size_t *retlen)
3491 {
3492     struct expand_buffer
3493     {
3494         struct expand_buffer *next;
3495         char *data;
3496         size_t len;
3497         int free_data;
3498     } *ebufs = NULL;
3499     struct expand_buffer *ebuf_last = NULL;
3500     size_t ebuf_len = 0;
3501     char *locker;
3502     char *srch, *srch_next;
3503     size_t srch_len;
3504
3505     if (expand == KFLAG_O || expand == KFLAG_B)
3506     {
3507         *retbuf = buf;
3508         *retlen = len;
3509         return;
3510     }
3511
3512     /* If we are using -kkvl, dig out the locker information if any.  */
3513     locker = NULL;
3514     if (expand == KFLAG_KVL)
3515     {
3516         Node *lock;
3517         lock = findnode (RCS_getlocks(rcs), ver->version);
3518         if (lock != NULL)
3519             locker = xstrdup (lock->data);
3520     }
3521
3522     /* RCS keywords look like $STRING$ or $STRING: VALUE$.  */
3523     srch = buf;
3524     srch_len = len;
3525     while ((srch_next = memchr (srch, '$', srch_len)) != NULL)
3526     {
3527         char *s, *send;
3528         size_t slen;
3529         const struct rcs_keyword *keyword;
3530         enum keyword kw;
3531         char *value;
3532         int free_value;
3533         char *sub;
3534         size_t sublen;
3535
3536         srch_len -= (srch_next + 1) - srch;
3537         srch = srch_next + 1;
3538
3539         /* Look for the first non alphabetic character after the '$'.  */
3540         send = srch + srch_len;
3541         for (s = srch; s < send; s++)
3542             if (! isalpha ((unsigned char) *s))
3543                 break;
3544
3545         /* If the first non alphabetic character is not '$' or ':',
3546            then this is not an RCS keyword.  */
3547         if (s == send || (*s != '$' && *s != ':'))
3548             continue;
3549
3550         /* See if this is one of the keywords.  */
3551         slen = s - srch;
3552         for (keyword = keywords; keyword->string != NULL; keyword++)
3553         {
3554             if (keyword->expandit
3555                 && keyword->len == slen
3556                 && strncmp (keyword->string, srch, slen) == 0)
3557             {
3558                 break;
3559             }
3560         }
3561         if (keyword->string == NULL)
3562             continue;
3563
3564         kw = (enum keyword) (keyword - keywords);
3565
3566         /* If the keyword ends with a ':', then the old value consists
3567            of the characters up to the next '$'.  If there is no '$'
3568            before the end of the line, though, then this wasn't an RCS
3569            keyword after all.  */
3570         if (*s == ':')
3571         {
3572             for (; s < send; s++)
3573                 if (*s == '$' || *s == '\n')
3574                     break;
3575             if (s == send || *s != '$')
3576                 continue;
3577         }
3578
3579         /* At this point we must replace the string from SRCH to S
3580            with the expansion of the keyword KW.  */
3581
3582         /* Get the value to use.  */
3583         free_value = 0;
3584         if (expand == KFLAG_K)
3585             value = NULL;
3586         else
3587         {
3588             switch (kw)
3589             {
3590             default:
3591                 abort ();
3592
3593             case KEYWORD_AUTHOR:
3594                 value = ver->author;
3595                 break;
3596
3597             case KEYWORD_DATE:
3598                 value = printable_date (ver->date);
3599                 free_value = 1;
3600                 break;
3601
3602             case KEYWORD_CVSHEADER:
3603             case KEYWORD_HEADER:
3604             case KEYWORD_ID:
3605             case KEYWORD_LOCALID:
3606                 {
3607                     const char *path;
3608                     int free_path;
3609                     char *date;
3610                     char *old_path;
3611
3612                     old_path = NULL;
3613                     if (kw == KEYWORD_HEADER ||
3614                             (kw == KEYWORD_LOCALID &&
3615                              keyword_local == KEYWORD_HEADER))
3616                         path = rcs->path;
3617                     else if (kw == KEYWORD_CVSHEADER ||
3618                              (kw == KEYWORD_LOCALID &&
3619                               keyword_local == KEYWORD_CVSHEADER))
3620                         path = getfullCVSname(rcs->path, &old_path);
3621                     else
3622                         path = last_component (rcs->path);
3623                     path = escape_keyword_value (path, &free_path);
3624                     date = printable_date (ver->date);
3625                     value = xmalloc (strlen (path)
3626                                      + strlen (ver->version)
3627                                      + strlen (date)
3628                                      + strlen (ver->author)
3629                                      + strlen (ver->state)
3630                                      + (locker == NULL ? 0 : strlen (locker))
3631                                      + 20);
3632
3633                     sprintf (value, "%s %s %s %s %s%s%s",
3634                              path, ver->version, date, ver->author,
3635                              ver->state,
3636                              locker != NULL ? " " : "",
3637                              locker != NULL ? locker : "");
3638                     if (free_path)
3639                         /* If free_path is set then we know we allocated path
3640                          * and we can discard the const.
3641                          */
3642                         free ((char *)path);
3643                     if (old_path)
3644                         free (old_path);
3645                     free (date);
3646                     free_value = 1;
3647                 }
3648                 break;
3649
3650             case KEYWORD_LOCKER:
3651                 value = locker;
3652                 break;
3653
3654             case KEYWORD_LOG:
3655             case KEYWORD_RCSFILE:
3656                 value = escape_keyword_value (last_component (rcs->path),
3657                                               &free_value);
3658                 break;
3659
3660             case KEYWORD_NAME:
3661                 if (name != NULL && ! isdigit ((unsigned char) *name))
3662                     value = (char *) name;
3663                 else
3664                     value = NULL;
3665                 break;
3666
3667             case KEYWORD_REVISION:
3668                 value = ver->version;
3669                 break;
3670
3671             case KEYWORD_SOURCE:
3672                 value = escape_keyword_value (rcs->path, &free_value);
3673                 break;
3674
3675             case KEYWORD_STATE:
3676                 value = ver->state;
3677                 break;
3678             }
3679         }
3680
3681         sub = xmalloc (keyword->len
3682                        + (value == NULL ? 0 : strlen (value))
3683                        + 10);
3684         if (expand == KFLAG_V)
3685         {
3686             /* Decrement SRCH and increment S to remove the $
3687                characters.  */
3688             --srch;
3689             ++srch_len;
3690             ++s;
3691             sublen = 0;
3692         }
3693         else
3694         {
3695             strcpy (sub, keyword->string);
3696             sublen = strlen (keyword->string);
3697             if (expand != KFLAG_K)
3698             {
3699                 sub[sublen] = ':';
3700                 sub[sublen + 1] = ' ';
3701                 sublen += 2;
3702             }
3703         }
3704         if (value != NULL)
3705         {
3706             strcpy (sub + sublen, value);
3707             sublen += strlen (value);
3708         }
3709         if (expand != KFLAG_V && expand != KFLAG_K)
3710         {
3711             sub[sublen] = ' ';
3712             ++sublen;
3713             sub[sublen] = '\0';
3714         }
3715
3716         if (free_value)
3717             free (value);
3718
3719         /* The Log keyword requires special handling.  This behaviour
3720            is taken from RCS 5.7.  The special log message is what RCS
3721            uses for ci -k.  */
3722         if (kw == KEYWORD_LOG
3723             && (sizeof "checked in with -k by " <= loglen
3724                 || log == NULL
3725                 || strncmp (log, "checked in with -k by ",
3726                             sizeof "checked in with -k by " - 1) != 0))
3727         {
3728             char *start;
3729             char *leader;
3730             size_t leader_len, leader_sp_len;
3731             const char *logend;
3732             const char *snl;
3733             int cnl;
3734             char *date;
3735             const char *sl;
3736
3737             /* We are going to insert the trailing $ ourselves, before
3738                the log message, so we must remove it from S, if we
3739                haven't done so already.  */
3740             if (expand != KFLAG_V)
3741                 ++s;
3742
3743             /* CVS never has empty log messages, but old RCS files might.  */
3744             if (log == NULL)
3745                 log = "";
3746
3747             /* Find the start of the line.  */
3748             start = srch;
3749             while (start > buf && start[-1] != '\n')
3750                 --start;
3751
3752             /* Copy the start of the line to use as a comment leader.  */
3753             leader_len = srch - start;
3754             if (expand != KFLAG_V)
3755                 --leader_len;
3756             leader = xmalloc (leader_len);
3757             memcpy (leader, start, leader_len);
3758             leader_sp_len = leader_len;
3759             while (leader_sp_len > 0 && leader[leader_sp_len - 1] == ' ')
3760                 --leader_sp_len;
3761
3762             /* RCS does some checking for an old style of Log here,
3763                but we don't bother.  RCS issues a warning if it
3764                changes anything.  */
3765
3766             /* Count the number of newlines in the log message so that
3767                we know how many copies of the leader we will need.  */
3768             cnl = 0;
3769             logend = log + loglen;
3770             for (snl = log; snl < logend; snl++)
3771                 if (*snl == '\n')
3772                     ++cnl;
3773
3774             date = printable_date (ver->date);
3775             sub = xrealloc (sub,
3776                             (sublen
3777                              + sizeof "Revision"
3778                              + strlen (ver->version)
3779                              + strlen (date)
3780                              + strlen (ver->author)
3781                              + loglen
3782                              + (cnl + 2) * leader_len
3783                              + 20));
3784             if (expand != KFLAG_V)
3785             {
3786                 sub[sublen] = '$';
3787                 ++sublen;
3788             }
3789             sub[sublen] = '\n';
3790             ++sublen;
3791             memcpy (sub + sublen, leader, leader_len);
3792             sublen += leader_len;
3793             sprintf (sub + sublen, "Revision %s  %s  %s\n",
3794                      ver->version, date, ver->author);
3795             sublen += strlen (sub + sublen);
3796             free (date);
3797
3798             sl = log;
3799             while (sl < logend)
3800             {
3801                 if (*sl == '\n')
3802                 {
3803                     memcpy (sub + sublen, leader, leader_sp_len);
3804                     sublen += leader_sp_len;
3805                     sub[sublen] = '\n';
3806                     ++sublen;
3807                     ++sl;
3808                 }
3809                 else
3810                 {
3811                     const char *slnl;
3812
3813                     memcpy (sub + sublen, leader, leader_len);
3814                     sublen += leader_len;
3815                     for (slnl = sl; slnl < logend && *slnl != '\n'; ++slnl)
3816                         ;
3817                     if (slnl < logend)
3818                         ++slnl;
3819                     memcpy (sub + sublen, sl, slnl - sl);
3820                     sublen += slnl - sl;
3821                     sl = slnl;
3822                 }
3823             }
3824
3825             memcpy (sub + sublen, leader, leader_sp_len);
3826             sublen += leader_sp_len;
3827
3828             free (leader);
3829         }
3830
3831         /* Now SUB contains a string which is to replace the string
3832            from SRCH to S.  SUBLEN is the length of SUB.  */
3833
3834         if (srch + sublen == s)
3835         {
3836             memcpy (srch, sub, sublen);
3837             free (sub);
3838         }
3839         else
3840         {
3841             struct expand_buffer *ebuf;
3842
3843             /* We need to change the size of the buffer.  We build a
3844                list of expand_buffer structures.  Each expand_buffer
3845                structure represents a portion of the final output.  We
3846                concatenate them back into a single buffer when we are
3847                done.  This minimizes the number of potentially large
3848                buffer copies we must do.  */
3849
3850             if (ebufs == NULL)
3851             {
3852                 ebufs = (struct expand_buffer *) xmalloc (sizeof *ebuf);
3853                 ebufs->next = NULL;
3854                 ebufs->data = buf;
3855                 ebufs->free_data = 0;
3856                 ebuf_len = srch - buf;
3857                 ebufs->len = ebuf_len;
3858                 ebuf_last = ebufs;
3859             }
3860             else
3861             {
3862                 assert (srch >= ebuf_last->data);
3863                 assert (srch <= ebuf_last->data + ebuf_last->len);
3864                 ebuf_len -= ebuf_last->len - (srch - ebuf_last->data);
3865                 ebuf_last->len = srch - ebuf_last->data;
3866             }
3867
3868             ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf);
3869             ebuf->data = sub;
3870             ebuf->len = sublen;
3871             ebuf->free_data = 1;
3872             ebuf->next = NULL;
3873             ebuf_last->next = ebuf;
3874             ebuf_last = ebuf;
3875             ebuf_len += sublen;
3876
3877             ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf);
3878             ebuf->data = s;
3879             ebuf->len = srch_len - (s - srch);
3880             ebuf->free_data = 0;
3881             ebuf->next = NULL;
3882             ebuf_last->next = ebuf;
3883             ebuf_last = ebuf;
3884             ebuf_len += srch_len - (s - srch);
3885         }
3886
3887         srch_len -= (s - srch);
3888         srch = s;
3889     }
3890
3891     if (locker != NULL)
3892         free (locker);
3893
3894     if (ebufs == NULL)
3895     {
3896         *retbuf = buf;
3897         *retlen = len;
3898     }
3899     else
3900     {
3901         char *ret;
3902
3903         ret = xmalloc (ebuf_len);
3904         *retbuf = ret;
3905         *retlen = ebuf_len;
3906         while (ebufs != NULL)
3907         {
3908             struct expand_buffer *next;
3909
3910             memcpy (ret, ebufs->data, ebufs->len);
3911             ret += ebufs->len;
3912             if (ebufs->free_data)
3913                 free (ebufs->data);
3914             next = ebufs->next;
3915             free (ebufs);
3916             ebufs = next;
3917         }
3918     }
3919 }
3920
3921
3922
3923 /* Check out a revision from an RCS file.
3924
3925    If PFN is not NULL, then ignore WORKFILE and SOUT.  Call PFN zero
3926    or more times with the contents of the file.  CALLERDAT is passed,
3927    uninterpreted, to PFN.  (The current code will always call PFN
3928    exactly once for a non empty file; however, the current code
3929    assumes that it can hold the entire file contents in memory, which
3930    is not a good assumption, and might change in the future).
3931
3932    Otherwise, if WORKFILE is not NULL, check out the revision to
3933    WORKFILE.  However, if WORKFILE is not NULL, and noexec is set,
3934    then don't do anything.
3935
3936    Otherwise, if WORKFILE is NULL, check out the revision to SOUT.  If
3937    SOUT is RUN_TTY, then write the contents of the revision to
3938    standard output.  When using SOUT, the output is generally a
3939    temporary file; don't bother to get the file modes correct.
3940
3941    REV is the numeric revision to check out.  It may be NULL, which
3942    means to check out the head of the default branch.
3943
3944    If NAMETAG is not NULL, and is not a numeric revision, then it is
3945    the tag that should be used when expanding the RCS Name keyword.
3946
3947    OPTIONS is a string such as "-kb" or "-kv" for keyword expansion
3948    options.  It may be NULL to use the default expansion mode of the
3949    file, typically "-kkv".
3950
3951    On an error which prevented checking out the file, either print a
3952    nonfatal error and return 1, or give a fatal error.  On success,
3953    return 0.  */
3954
3955 /* This function mimics the behavior of `rcs co' almost exactly.  The
3956    chief difference is in its support for preserving file ownership,
3957    permissions, and special files across checkin and checkout -- see
3958    comments in RCS_checkin for some issues about this. -twp */
3959
3960 int
3961 RCS_checkout (RCSNode *rcs, const char *workfile, const char *rev,
3962               const char *nametag, const char *options, const char *sout,
3963               RCSCHECKOUTPROC pfn, void *callerdat)
3964 {
3965     int free_rev = 0;
3966     enum kflag expand;
3967     FILE *fp, *ofp;
3968     struct stat sb;
3969     struct rcsbuffer rcsbuf;
3970     char *key;
3971     char *value;
3972     size_t len;
3973     int free_value = 0;
3974     char *log = NULL;
3975     size_t loglen;
3976     Node *vp = NULL;
3977 #ifdef PRESERVE_PERMISSIONS_SUPPORT
3978     uid_t rcs_owner = (uid_t) -1;
3979     gid_t rcs_group = (gid_t) -1;
3980     mode_t rcs_mode;
3981     int change_rcs_owner_or_group = 0;
3982     int change_rcs_mode = 0;
3983     int special_file = 0;
3984     unsigned long devnum_long;
3985     dev_t devnum = 0;
3986 #endif
3987
3988     TRACE ( 1, "RCS_checkout (%s, %s, %s, %s, %s)",
3989             rcs->path,
3990             rev != NULL ? rev : "",
3991             nametag != NULL ? nametag : "",
3992             options != NULL ? options : "",
3993             (pfn != NULL ? "(function)"
3994               : (workfile != NULL ? workfile
3995                   : (sout != RUN_TTY ? sout
3996                       : "(stdout)" ) ) ) );
3997
3998     assert (rev == NULL || isdigit ((unsigned char) *rev));
3999
4000     if (noexec && workfile != NULL)
4001         return 0;
4002
4003     assert (sout == RUN_TTY || workfile == NULL);
4004     assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL));
4005
4006     /* Some callers, such as Checkin or remove_file, will pass us a
4007        branch.  */
4008     if (rev != NULL && (numdots (rev) & 1) == 0)
4009     {
4010         rev = RCS_getbranch (rcs, rev, 1);
4011         if (rev == NULL)
4012             error (1, 0, "internal error: bad branch tag in checkout");
4013         free_rev = 1;
4014     }
4015
4016     if (rev == NULL || STREQ (rev, rcs->head))
4017     {
4018         int gothead;
4019
4020         /* We want the head revision.  Try to read it directly.  */
4021
4022         if (rcs->flags & PARTIAL)
4023             RCS_reparsercsfile (rcs, &fp, &rcsbuf);
4024         else
4025             rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf);
4026
4027         gothead = 0;
4028         if (! rcsbuf_getrevnum (&rcsbuf, &key))
4029             error (1, 0, "unexpected EOF reading %s", rcs->path);
4030         while (rcsbuf_getkey (&rcsbuf, &key, &value))
4031         {
4032             if (STREQ (key, "log"))
4033                 log = rcsbuf_valcopy (&rcsbuf, value, 0, &loglen);
4034             else if (STREQ (key, "text"))
4035             {
4036                 gothead = 1;
4037                 break;
4038             }
4039         }
4040
4041         if (! gothead)
4042         {
4043             error (0, 0, "internal error: cannot find head text");
4044             if (free_rev)
4045                 /* It's okay to discard the const when free_rev is set, because
4046                  * we know we allocated it in this function.
4047                  */
4048                 free ((char *)rev);
4049             return 1;
4050         }
4051
4052         rcsbuf_valpolish (&rcsbuf, value, 0, &len);
4053
4054         if (fstat (fileno (fp), &sb) < 0)
4055             error (1, errno, "cannot fstat %s", rcs->path);
4056
4057         rcsbuf_cache (rcs, &rcsbuf);
4058     }
4059     else
4060     {
4061         struct rcsbuffer *rcsbufp;
4062
4063         /* It isn't the head revision of the trunk.  We'll need to
4064            walk through the deltas.  */
4065
4066         fp = NULL;
4067         if (rcs->flags & PARTIAL)
4068             RCS_reparsercsfile (rcs, &fp, &rcsbuf);
4069
4070         if (fp == NULL)
4071         {
4072             /* If RCS_deltas didn't close the file, we could use fstat
4073                here too.  Probably should change it thusly....  */
4074             if( CVS_STAT( rcs->path, &sb ) < 0 )
4075                 error (1, errno, "cannot stat %s", rcs->path);
4076             rcsbufp = NULL;
4077         }
4078         else
4079         {
4080             if (fstat (fileno (fp), &sb) < 0)
4081                 error (1, errno, "cannot fstat %s", rcs->path);
4082             rcsbufp = &rcsbuf;
4083         }
4084
4085         RCS_deltas (rcs, fp, rcsbufp, rev, RCS_FETCH, &value, &len,
4086                     &log, &loglen);
4087         free_value = 1;
4088     }
4089
4090     /* If OPTIONS is NULL or the empty string, then the old code would
4091        invoke the RCS co program with no -k option, which means that
4092        co would use the string we have stored in rcs->expand.  */
4093     if ((options == NULL || options[0] == '\0') && rcs->expand == NULL)
4094         expand = KFLAG_KV;
4095     else
4096     {
4097         const char *ouroptions;
4098         const char * const *cpp;
4099
4100         if (options != NULL && options[0] != '\0')
4101         {
4102             assert (options[0] == '-' && options[1] == 'k');
4103             ouroptions = options + 2;
4104         }
4105         else
4106             ouroptions = rcs->expand;
4107
4108         for (cpp = kflags; *cpp != NULL; cpp++)
4109             if (STREQ (*cpp, ouroptions))
4110                 break;
4111
4112         if (*cpp != NULL)
4113             expand = (enum kflag) (cpp - kflags);
4114         else
4115         {
4116             error (0, 0,
4117                    "internal error: unsupported substitution string -k%s",
4118                    ouroptions);
4119             expand = KFLAG_KV;
4120         }
4121     }
4122
4123 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4124     /* Handle special files and permissions, if that is desired. */
4125     if (preserve_perms)
4126     {
4127         RCSVers *vers;
4128         Node *info;
4129
4130         vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
4131         if (vp == NULL)
4132             error (1, 0, "internal error: no revision information for %s",
4133                    rev == NULL ? rcs->head : rev);
4134         vers = vp->data;
4135
4136         /* First we look for symlinks, which are simplest to handle. */
4137         info = findnode (vers->other_delta, "symlink");
4138         if (info != NULL)
4139         {
4140             char *dest;
4141
4142             if (pfn != NULL || (workfile == NULL && sout == RUN_TTY))
4143                 error (1, 0, "symbolic link %s:%s cannot be piped",
4144                        rcs->path, vers->version);
4145             if (workfile == NULL)
4146                 dest = sout;
4147             else
4148                 dest = workfile;
4149
4150             /* Remove `dest', just in case.  It's okay to get ENOENT here,
4151                since we just want the file not to be there.  (TODO: decide
4152                whether it should be considered an error for `dest' to exist
4153                at this point.  If so, the unlink call should be removed and
4154                `symlink' should signal the error. -twp) */
4155             if (CVS_UNLINK (dest) < 0 && !existence_error (errno))
4156                 error (1, errno, "cannot remove %s", dest);
4157             if (symlink (info->data, dest) < 0)
4158                 error (1, errno, "cannot create symbolic link from %s to %s",
4159                        dest, (char *)info->data);
4160             if (free_value)
4161                 free (value);
4162             if (free_rev)
4163                 /* It's okay to discard the const when free_rev is set, because
4164                  * we know we allocated it in this function.
4165                  */
4166                 free ((char *)rev);
4167             return 0;
4168         }
4169
4170         /* Next, we look at this file's hardlinks field, and see whether
4171            it is linked to any other file that has been checked out.
4172            If so, we don't do anything else -- just link it to that file.
4173
4174            If we are checking out a file to a pipe or temporary storage,
4175            none of this should matter.  Hence the `workfile != NULL'
4176            wrapper around the whole thing. -twp */
4177
4178         if (workfile != NULL)
4179         {
4180             List *links = vers->hardlinks;
4181             if (links != NULL)
4182             {
4183                 Node *uptodate_link;
4184
4185                 /* For each file in the hardlinks field, check to see
4186                    if it exists, and if so, if it has been checked out
4187                    this iteration.  When walklist returns, uptodate_link
4188                    should point to a hardlist node representing a file
4189                    in `links' which has recently been checked out, or
4190                    NULL if no file in `links' has yet been checked out. */
4191
4192                 uptodate_link = NULL;
4193                 (void) walklist (links, find_checkedout_proc, &uptodate_link);
4194                 dellist (&links);
4195
4196                 /* If we've found a file that `workfile' is supposed to be
4197                    linked to, and it has been checked out since CVS was
4198                    invoked, then simply link workfile to that file and return.
4199
4200                    If one of these conditions is not met, then
4201                    workfile is the first one in its hardlink group to
4202                    be checked out, and we must continue with a full
4203                    checkout. */
4204
4205                 if (uptodate_link != NULL)
4206                 {
4207                     struct hardlink_info *hlinfo = uptodate_link->data;
4208
4209                     if (link (uptodate_link->key, workfile) < 0)
4210                         error (1, errno, "cannot link %s to %s",
4211                                workfile, uptodate_link->key);
4212                     hlinfo->checked_out = 1;    /* probably unnecessary */
4213                     if (free_value)
4214                         free (value);
4215                     if (free_rev)
4216                         /* It's okay to discard the const when free_rev is set,
4217                          * because we know we allocated it in this function.
4218          &n