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