Merge from vendor branch OPENSSH:
[dragonfly.git] / contrib / cvs-1.12 / 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 /* The RCS -k options, and a set of enums that must match the array.
37    These come first so that we can use enum kflag in function
38    prototypes.  */
39 static const char *const kflags[] =
40   {"kv", "kvl", "k", "v", "o", "b", NULL};
41 enum kflag { KFLAG_KV = 0, KFLAG_KVL, KFLAG_K, KFLAG_V, KFLAG_O, KFLAG_B };
42
43 /* A structure we use to buffer the contents of an RCS file.  The
44    various fields are only referenced directly by the rcsbuf_*
45    functions.  We declare the struct here so that we can allocate it
46    on the stack, rather than in memory.  */
47
48 struct rcsbuffer
49 {
50     /* Points to the current position in the buffer.  */
51     char *ptr;
52     /* Points just after the last valid character in the buffer.  */
53     char *ptrend;
54     /* The file.  */
55     FILE *fp;
56     /* The name of the file, used for error messages.  */
57     const char *filename;
58     /* The starting file position of the data in the buffer.  */
59     unsigned long pos;
60     /* The length of the value.  */
61     size_t vlen;
62     /* Whether the value contains an '@' string.  If so, we can not
63        compress whitespace characters.  */
64     int at_string;
65     /* The number of embedded '@' characters in an '@' string.  If
66        this is non-zero, we must search the string for pairs of '@'
67        and convert them to a single '@'.  */
68     int embedded_at;
69 };
70
71 static RCSNode *RCS_parsercsfile_i (FILE * fp, const char *rcsfile);
72 static char *RCS_getdatebranch (RCSNode * rcs, const char *date,
73                                 const char *branch);
74 static void rcsbuf_open (struct rcsbuffer *, FILE *fp,
75                          const char *filename, unsigned long pos);
76 static void rcsbuf_close (struct rcsbuffer *);
77 static int rcsbuf_getkey (struct rcsbuffer *, char **keyp, char **valp);
78 static int rcsbuf_getrevnum (struct rcsbuffer *, char **revp);
79 static char *rcsbuf_fill (struct rcsbuffer *, char *ptr, char **keyp,
80                           char **valp);
81 static int rcsbuf_valcmp (struct rcsbuffer *);
82 static char *rcsbuf_valcopy (struct rcsbuffer *, char *val, int polish,
83                              size_t *lenp);
84 static void rcsbuf_valpolish (struct rcsbuffer *, char *val, int polish,
85                               size_t *lenp);
86 static void rcsbuf_valpolish_internal (struct rcsbuffer *, char *to,
87                                        const char *from, size_t *lenp);
88 static off_t rcsbuf_ftello (struct rcsbuffer *);
89 static void rcsbuf_get_buffered (struct rcsbuffer *, char **datap,
90                                  size_t *lenp);
91 static void rcsbuf_cache (RCSNode *, struct rcsbuffer *);
92 static void rcsbuf_cache_close (void);
93 static void rcsbuf_cache_open (RCSNode *, off_t, FILE **, struct rcsbuffer *);
94 static int checkmagic_proc (Node *p, void *closure);
95 static void do_branches (List * list, char *val);
96 static void do_symbols (List * list, char *val);
97 static void do_locks (List * list, char *val);
98 static void free_rcsnode_contents (RCSNode *);
99 static void free_rcsvers_contents (RCSVers *);
100 static void rcsvers_delproc (Node * p);
101 static char *translate_symtag (RCSNode *, const char *);
102 static char *RCS_addbranch (RCSNode *, const char *);
103 static char *truncate_revnum_in_place (char *);
104 static char *truncate_revnum (const char *);
105 static char *printable_date (const char *);
106 static char *escape_keyword_value (const char *, int *);
107 static void expand_keywords (RCSNode *, RCSVers *, const char *,
108                              const char *, size_t, enum kflag, char *,
109                              size_t, char **, size_t *);
110 static void cmp_file_buffer (void *, const char *, size_t);
111
112 /* Routines for reading, parsing and writing RCS files. */
113 static RCSVers *getdelta (struct rcsbuffer *, char *, char **, char **);
114 static Deltatext *RCS_getdeltatext (RCSNode *, FILE *, struct rcsbuffer *);
115 static void freedeltatext (Deltatext *);
116
117 static void RCS_putadmin (RCSNode *, FILE *);
118 static void RCS_putdtree (RCSNode *, char *, FILE *);
119 static void RCS_putdesc (RCSNode *, FILE *);
120 static void putdelta (RCSVers *, FILE *);
121 static int putrcsfield_proc (Node *, void *);
122 static int putsymbol_proc (Node *, void *);
123 static void RCS_copydeltas (RCSNode *, FILE *, struct rcsbuffer *, FILE *,
124                             Deltatext *, char *);
125 static int count_delta_actions (Node *, void *);
126 static void putdeltatext (FILE *, Deltatext *);
127
128 static FILE *rcs_internal_lockfile (char *);
129 static void rcs_internal_unlockfile (FILE *, char *);
130 static char *rcs_lockfilename (const char *);
131
132 /* The RCS file reading functions are called a lot, and they do some
133    string comparisons.  This macro speeds things up a bit by skipping
134    the function call when the first characters are different.  It
135    evaluates its arguments multiple times.  */
136 #define STREQ(a, b) (*(char *)(a) == *(char *)(b) && strcmp ((a), (b)) == 0)
137
138 static char * getfullCVSname (char *, char **);
139
140 /*
141  * We don't want to use isspace() from the C library because:
142  *
143  * 1. The definition of "whitespace" in RCS files includes ASCII
144  *    backspace, but the C locale doesn't.
145  * 2. isspace is an very expensive function call in some implementations
146  *    due to the addition of wide character support.
147  */
148 static const char spacetab[] = {
149         0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x00 - 0x0f */
150         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */
151         1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */
152         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */
153         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
154         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
155         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x8f */
156         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */
157         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */
158         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */
159         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */
160         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */
161         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
162         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
163         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
164         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  /* 0xf0 - 0xff */
165 };
166
167 #define whitespace(c)   (spacetab[(unsigned char)c] != 0)
168
169 static char *rcs_lockfile = NULL;
170 static int rcs_lockfd = -1;
171
172
173
174 /*
175  * char *
176  * locate_rcs ( const char* file, const char *repository , int *inattic )
177  *
178  * Find an RCS file in the repository, case insensitively when the cased name
179  * doesn't exist, we are running as the server, and a client has asked us to
180  * ignore case.
181  *
182  * Most parts of CVS will want to rely instead on RCS_parse which calls this
183  * function and is called by recurse.c which then puts the result in useful
184  * places like the rcs field of struct file_info.
185  *
186  * INPUTS
187  *
188  *  repository          the repository (including the directory)
189  *  file                the filename within that directory (without RCSEXT).
190  *  inattic             NULL or a pointer to the output boolean
191  *
192  * OUTPUTS
193  *
194  *  inattic             If this input was non-null, the destination will be
195  *                      set to true if the file was found in the attic or
196  *                      false if not.  If no RCS file is found, this value
197  *                      is undefined.
198  *
199  * RETURNS
200  *
201  *  a newly-malloc'd array containing the absolute pathname of the RCS
202  *  file that was found or NULL when none was found.
203  *
204  * ERRORS
205  *
206  *  errno can be set by the return value of the final call to
207  *  locate_file_in_dir().  This should resolve to the system's existence error
208  *  value (sometime ENOENT) if the Attic directory did not exist and ENOENT if
209  *  the Attic was found but no matching files were found in the Attic or its
210  *  parent.
211  */
212 static char *
213 locate_rcs (const char *repository, const char *file, int *inattic)
214 {
215     char *retval;
216
217     /* First, try to find the file as cased. */
218     retval = xmalloc (strlen (repository)
219                       + sizeof (CVSATTIC)
220                       + strlen (file)
221                       + sizeof (RCSEXT)
222                       + 3);
223     sprintf (retval, "%s/%s%s", repository, file, RCSEXT);
224     if (isreadable (retval))
225     {
226         if (inattic)
227             *inattic = 0;
228         return retval;
229     }
230     sprintf (retval, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT);
231     if (isreadable (retval))
232     {
233         if (inattic)
234             *inattic = 1;
235         return retval;
236     }
237     free (retval);
238
239     return NULL;
240 }
241
242
243
244 /* A few generic thoughts on error handling, in particular the
245    printing of unexpected characters that we find in the RCS file
246    (that is, why we use '\x%x' rather than %c or some such).
247
248    * Avoiding %c means we don't have to worry about what is printable
249    and other such stuff.  In error handling, often better to keep it
250    simple.
251
252    * Hex rather than decimal or octal because character set standards
253    tend to use hex.
254
255    * Saying "character 0x%x" might make it sound like we are printing
256    a file offset.  So we use '\x%x'.
257
258    * Would be nice to print the offset within the file, but I can
259    imagine various portability hassles (in particular, whether
260    unsigned long is always big enough to hold file offsets).  */
261
262 /* Parse an rcsfile given a user file name and a repository.  If there is
263    an error, we print an error message and return NULL.  If the file
264    does not exist, we return NULL without printing anything (I'm not
265    sure this allows the caller to do anything reasonable, but it is
266    the current behavior).  */
267 RCSNode *
268 RCS_parse (const char *file, const char *repos)
269 {
270     RCSNode *rcs;
271     FILE *fp;
272     RCSNode *retval = NULL;
273     char *rcsfile;
274     int inattic;
275
276     /* We're creating a new RCSNode, so there is no hope of finding it
277        in the cache.  */
278     rcsbuf_cache_close ();
279
280     if (!(rcsfile = locate_rcs (repos, file, &inattic)))
281     {
282         /* Handle the error cases */
283     }
284     else if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ))) 
285     {
286         rcs = RCS_parsercsfile_i (fp, rcsfile);
287         if (rcs)
288         {       
289             rcs->flags |= VALID;
290             if (inattic)
291                 rcs->flags |= INATTIC;
292         }
293
294         free (rcsfile);
295         retval = rcs;
296     }
297     else if (!existence_error (errno))
298     {
299         error (0, errno, "cannot open `%s'", rcsfile);
300         free (rcsfile);
301     }
302
303     return retval;
304 }
305
306
307
308 /*
309  * Parse a specific rcsfile.
310  */
311 RCSNode *
312 RCS_parsercsfile (const char *rcsfile)
313 {
314     FILE *fp;
315     RCSNode *rcs;
316
317     /* We're creating a new RCSNode, so there is no hope of finding it
318        in the cache.  */
319     rcsbuf_cache_close ();
320
321     /* open the rcsfile */
322     if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) == NULL)
323     {
324         error (0, errno, "Couldn't open rcs file `%s'", rcsfile);
325         return NULL;
326     }
327
328     rcs = RCS_parsercsfile_i (fp, rcsfile);
329
330     return rcs;
331 }
332
333
334
335 /*
336  */ 
337 static RCSNode *
338 RCS_parsercsfile_i (FILE *fp, const char *rcsfile)
339 {
340     RCSNode *rdata;
341     struct rcsbuffer rcsbuf;
342     char *key, *value;
343
344     /* make a node */
345     rdata = xmalloc (sizeof (RCSNode));
346     memset (rdata, 0, sizeof (RCSNode));
347     rdata->refcount = 1;
348     rdata->path = xstrdup (rcsfile);
349     rdata->print_path = xstrdup (primary_root_inverse_translate (rcsfile));
350
351     /* Process HEAD, BRANCH, and EXPAND keywords from the RCS header.
352
353        Most cvs operations on the main branch don't need any more
354        information.  Those that do call RCS_reparsercsfile to parse
355        the rest of the header and the deltas.  */
356
357     rcsbuf_open (&rcsbuf, fp, rcsfile, 0);
358
359     if (! rcsbuf_getkey (&rcsbuf, &key, &value))
360         goto l_error;
361     if (STREQ (key, RCSDESC))
362         goto l_error;
363
364     if (STREQ (RCSHEAD, key) && value != NULL)
365         rdata->head = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
366
367     if (! rcsbuf_getkey (&rcsbuf, &key, &value))
368         goto l_error;
369     if (STREQ (key, RCSDESC))
370         goto l_error;
371
372     if (STREQ (RCSBRANCH, key) && value != NULL)
373     {
374         char *cp;
375
376         rdata->branch = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
377         if ((numdots (rdata->branch) & 1) != 0)
378         {
379             /* turn it into a branch if it's a revision */
380             cp = strrchr (rdata->branch, '.');
381             *cp = '\0';
382         }
383     }
384
385     /* Look ahead for expand, stopping when we see desc or a revision
386        number.  */
387     while (1)
388     {
389         char *cp;
390
391         if (STREQ (RCSEXPAND, key))
392         {
393             rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
394             break;
395         }
396
397         for (cp = key;
398              (isdigit ((unsigned char)*cp) || *cp == '.') && *cp != '\0';
399              cp++)
400             /* do nothing */ ;
401         if (*cp == '\0')
402             break;
403
404         if (STREQ (RCSDESC, key))
405             break;
406
407         if (! rcsbuf_getkey (&rcsbuf, &key, &value))
408             break;
409     }
410
411     rdata->flags |= PARTIAL;
412
413     rcsbuf_cache (rdata, &rcsbuf);
414
415     return rdata;
416
417 l_error:
418     error (0, 0, "`%s' does not appear to be a valid rcs file",
419            rcsfile);
420     rcsbuf_close (&rcsbuf);
421     freercsnode (&rdata);
422     fclose (fp);
423     return NULL;
424 }
425
426
427
428 /* Do the real work of parsing an RCS file.
429
430    On error, die with a fatal error; if it returns at all it was successful.
431
432    If PFP is NULL, close the file when done.  Otherwise, leave it open
433    and store the FILE * in *PFP.  */
434 void
435 RCS_reparsercsfile (RCSNode *rdata, FILE **pfp, struct rcsbuffer *rcsbufp)
436 {
437     FILE *fp;
438     char *rcsfile;
439     struct rcsbuffer rcsbuf;
440     Node *q, *kv;
441     RCSVers *vnode;
442     int gotkey;
443     char *cp;
444     char *key, *value;
445
446     assert (rdata != NULL);
447     rcsfile = rdata->path;
448
449     rcsbuf_cache_open (rdata, 0, &fp, &rcsbuf);
450
451     /* make a node */
452     /* This probably shouldn't be done until later: if a file has an
453        empty revision tree (which is permissible), rdata->versions
454        should be NULL. -twp */
455     rdata->versions = getlist ();
456
457     /*
458      * process all the special header information, break out when we get to
459      * the first revision delta
460      */
461     gotkey = 0;
462     for (;;)
463     {
464         /* get the next key/value pair */
465         if (!gotkey)
466         {
467             if (! rcsbuf_getkey (&rcsbuf, &key, &value))
468             {
469                 error (1, 0, "`%s' does not appear to be a valid rcs file",
470                        rcsfile);
471             }
472         }
473
474         gotkey = 0;
475
476         /* Skip head, branch and expand tags; we already have them. */
477         if (STREQ (key, RCSHEAD)
478             || STREQ (key, RCSBRANCH)
479             || STREQ (key, RCSEXPAND))
480         {
481             continue;
482         }
483
484         if (STREQ (key, "access"))
485         {
486             if (value != NULL)
487             {
488                 /* We pass the POLISH parameter as 1 because
489                    RCS_addaccess expects nothing but spaces.  FIXME:
490                    It would be easy and more efficient to change
491                    RCS_addaccess.  */
492                 if (rdata->access)
493                 {
494                     error (0, 0,
495                            "Duplicate `access' keyword found in RCS file.");
496                     free (rdata->access);
497                 }
498                 rdata->access = rcsbuf_valcopy (&rcsbuf, value, 1, NULL);
499             }
500             continue;
501         }
502
503         /* We always save lock information, so that we can handle
504            -kkvl correctly when checking out a file. */
505         if (STREQ (key, "locks"))
506         {
507             if (value != NULL)
508             {
509                 if (rdata->locks_data)
510                 {
511                     error (0, 0,
512                            "Duplicate `locks' keyword found in RCS file.");
513                     free (rdata->locks_data);
514                 }
515                 rdata->locks_data = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
516             }
517             if (! rcsbuf_getkey (&rcsbuf, &key, &value))
518             {
519                 error (1, 0, "premature end of file reading %s", rcsfile);
520             }
521             if (STREQ (key, "strict") && value == NULL)
522             {
523                 rdata->strict_locks = 1;
524             }
525             else
526                 gotkey = 1;
527             continue;
528         }
529
530         if (STREQ (RCSSYMBOLS, key))
531         {
532             if (value != NULL)
533             {
534                 if (rdata->symbols_data)
535                 {
536                     error (0, 0,
537                            "Duplicate `%s' keyword found in RCS file.",
538                            RCSSYMBOLS);
539                     free (rdata->symbols_data);
540                 }
541                 rdata->symbols_data = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
542             }
543             continue;
544         }
545
546         /*
547          * check key for '.''s and digits (probably a rev) if it is a
548          * revision or `desc', we are done with the headers and are down to the
549          * revision deltas, so we break out of the loop
550          */
551         for (cp = key;
552              (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
553              cp++)
554              /* do nothing */ ;
555         /* Note that when comparing with RCSDATE, we are not massaging
556            VALUE from the string found in the RCS file.  This is OK
557            since we know exactly what to expect.  */
558         if (*cp == '\0' && strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) == 0)
559             break;
560
561         if (STREQ (key, RCSDESC))
562             break;
563
564         if (STREQ (key, "comment"))
565         {
566             if (rdata->comment)
567             {
568                 error (0, 0,
569                        "warning: duplicate key `%s' in RCS file `%s'",
570                        key, rcsfile);
571                 free (rdata->comment);
572             }
573             rdata->comment = rcsbuf_valcopy (&rcsbuf, value, 0, NULL);
574             continue;
575         }
576         if (rdata->other == NULL)
577             rdata->other = getlist ();
578         kv = getnode ();
579         kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
580         kv->key = xstrdup (key);
581         kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD, NULL);
582         if (addnode (rdata->other, kv) != 0)
583         {
584             error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
585                    key, rcsfile);
586             freenode (kv);
587         }
588
589         /* if we haven't grabbed it yet, we didn't want it */
590     }
591
592     /* We got out of the loop, so we have the first part of the first
593        revision delta in KEY (the revision) and VALUE (the date key
594        and its value).  This is what getdelta expects to receive.  */
595
596     while ((vnode = getdelta (&rcsbuf, rcsfile, &key, &value)) != NULL)
597     {
598         /* get the node */
599         q = getnode ();
600         q->type = RCSVERS;
601         q->delproc = rcsvers_delproc;
602         q->data = vnode;
603         q->key = vnode->version;
604
605         /* add the nodes to the list */
606         if (addnode (rdata->versions, q) != 0)
607         {
608 #if 0
609                 purify_printf("WARNING: Adding duplicate version: %s (%s)\n",
610                          q->key, rcsfile);
611                 freenode (q);
612 #endif
613         }
614     }
615
616     /* Here KEY and VALUE are whatever caused getdelta to return NULL.  */
617
618     if (STREQ (key, RCSDESC))
619     {
620         if (rdata->desc != NULL)
621         {
622             error (0, 0,
623                    "warning: duplicate key `%s' in RCS file `%s'",
624                    key, rcsfile);
625             free (rdata->desc);
626         }
627         rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 1, NULL);
628     }
629
630     rdata->delta_pos = rcsbuf_ftello (&rcsbuf);
631
632     if (pfp == NULL)
633         rcsbuf_cache (rdata, &rcsbuf);
634     else
635     {
636         *pfp = fp;
637         *rcsbufp = rcsbuf;
638     }
639     rdata->flags &= ~PARTIAL;
640 }
641
642
643
644 /* Move RCS into or out of the Attic, depending on TOATTIC.  If the
645    file is already in the desired place, return without doing
646    anything.  At some point may want to think about how this relates
647    to RCS_rewrite but that is a bit hairy (if one wants renames to be
648    atomic, or that kind of thing).  If there is an error, print a message
649    and return 1.  On success, return 0.  */
650 int
651 RCS_setattic (RCSNode *rcs, int toattic)
652 {
653     char *newpath;
654     const char *p;
655     char *q;
656
657     /* Some systems aren't going to let us rename an open file.  */
658     rcsbuf_cache_close ();
659
660     /* Could make the pathname computations in this file, and probably
661        in other parts of rcs.c too, easier if the REPOS and FILE
662        arguments to RCS_parse got stashed in the RCSNode.  */
663
664     if (toattic)
665     {
666         mode_t omask;
667
668         if (rcs->flags & INATTIC)
669             return 0;
670
671         /* Example: rcs->path is "/foo/bar/baz,v".  */
672         newpath = xmalloc (strlen (rcs->path) + sizeof CVSATTIC + 5);
673         p = last_component (rcs->path);
674         strncpy (newpath, rcs->path, p - rcs->path);
675         strcpy (newpath + (p - rcs->path), CVSATTIC);
676
677         /* Create the Attic directory if it doesn't exist.  */
678         omask = umask (cvsumask);
679         if (CVS_MKDIR (newpath, 0777) < 0 && errno != EEXIST)
680             error (0, errno, "cannot make directory %s", newpath);
681         (void) umask (omask);
682
683         strcat (newpath, "/");
684         strcat (newpath, p);
685
686         if (CVS_RENAME (rcs->path, newpath) < 0)
687         {
688             int save_errno = errno;
689
690             /* The checks for isreadable look awfully fishy, but
691                I'm going to leave them here for now until I
692                can think harder about whether they take care of
693                some cases which should be handled somehow.  */
694
695             if (isreadable (rcs->path) || !isreadable (newpath))
696             {
697                 error (0, save_errno, "cannot rename %s to %s",
698                        rcs->path, newpath);
699                 free (newpath);
700                 return 1;
701             }
702         }
703     }
704     else
705     {
706         if (!(rcs->flags & INATTIC))
707             return 0;
708
709         newpath = xmalloc (strlen (rcs->path));
710
711         /* Example: rcs->path is "/foo/bar/Attic/baz,v".  */
712         p = last_component (rcs->path);
713         strncpy (newpath, rcs->path, p - rcs->path - 1);
714         newpath[p - rcs->path - 1] = '\0';
715         q = newpath + (p - rcs->path - 1) - (sizeof CVSATTIC - 1);
716         assert (strncmp (q, CVSATTIC, sizeof CVSATTIC - 1) == 0);
717         strcpy (q, p);
718
719         if (CVS_RENAME (rcs->path, newpath) < 0)
720         {
721             error (0, errno, "failed to move `%s' out of the attic",
722                    rcs->path);
723             free (newpath);
724             return 1;
725         }
726     }
727
728     free (rcs->path);
729     rcs->path = newpath;
730
731     return 0;
732 }
733
734
735
736 /*
737  * Fully parse the RCS file.  Store all keyword/value pairs, fetch the
738  * log messages for each revision, and fetch add and delete counts for
739  * each revision (we could fetch the entire text for each revision,
740  * but the only caller, log_fileproc, doesn't need that information,
741  * so we don't waste the memory required to store it).  The add and
742  * delete counts are stored on the OTHER field of the RCSVERSNODE
743  * structure, under the names ";add" and ";delete", so that we don't
744  * waste the memory space of extra fields in RCSVERSNODE for code
745  * which doesn't need this information.
746  */
747 void
748 RCS_fully_parse (RCSNode *rcs)
749 {
750     FILE *fp;
751     struct rcsbuffer rcsbuf;
752
753     RCS_reparsercsfile (rcs, &fp, &rcsbuf);
754
755     while (1)
756     {
757         char *key, *value;
758         Node *vers;
759         RCSVers *vnode;
760
761         /* Rather than try to keep track of how much information we
762            have read, just read to the end of the file.  */
763         if (!rcsbuf_getrevnum (&rcsbuf, &key))
764             break;
765
766         vers = findnode (rcs->versions, key);
767         if (vers == NULL)
768             error (1, 0,
769                    "mismatch in rcs file %s between deltas and deltatexts (%s)",
770                    rcs->print_path, key);
771
772         vnode = vers->data;
773
774         while (rcsbuf_getkey (&rcsbuf, &key, &value))
775         {
776             if (!STREQ (key, "text"))
777             {
778                 Node *kv;
779
780                 if (vnode->other == NULL)
781                     vnode->other = getlist ();
782                 kv = getnode ();
783                 kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
784                 kv->key = xstrdup (key);
785                 kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
786                                            NULL);
787                 if (addnode (vnode->other, kv) != 0)
788                 {
789                     error (0, 0,
790                            "\
791 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
792                            key, vnode->version, rcs->print_path);
793                     freenode (kv);
794                 }
795
796                 continue;
797             }
798
799             if (!STREQ (vnode->version, rcs->head))
800             {
801                 unsigned long add, del;
802                 char buf[50];
803                 Node *kv;
804
805                 /* This is a change text.  Store the add and delete
806                    counts.  */
807                 add = 0;
808                 del = 0;
809                 if (value != NULL)
810                 {
811                     size_t vallen;
812                     const char *cp;
813
814                     rcsbuf_valpolish (&rcsbuf, value, 0, &vallen);
815                     cp = value;
816                     while (cp < value + vallen)
817                     {
818                         char op;
819                         unsigned long count;
820
821                         op = *cp++;
822                         if (op != 'a' && op  != 'd')
823                             error (1, 0, "\
824 unrecognized operation '\\x%x' in %s",
825                                    op, rcs->print_path);
826                         (void) strtoul (cp, (char **) &cp, 10);
827                         if (*cp++ != ' ')
828                             error (1, 0, "space expected in %s revision %s",
829                                    rcs->print_path, vnode->version);
830                         count = strtoul (cp, (char **) &cp, 10);
831                         if (*cp++ != '\012')
832                             error (1, 0, "linefeed expected in %s revision %s",
833                                    rcs->print_path, vnode->version);
834
835                         if (op == 'd')
836                             del += count;
837                         else
838                         {
839                             add += count;
840                             while (count != 0)
841                             {
842                                 if (*cp == '\012')
843                                     --count;
844                                 else if (cp == value + vallen)
845                                 {
846                                     if (count != 1)
847                                         error (1, 0, "\
848 premature end of value in %s revision %s",
849                                                rcs->print_path, vnode->version);
850                                     else
851                                         break;
852                                 }
853                                 ++cp;
854                             }
855                         }
856                     }
857                 }
858
859                 sprintf (buf, "%lu", add);
860                 kv = getnode ();
861                 kv->type = RCSFIELD;
862                 kv->key = xstrdup (";add");
863                 kv->data = xstrdup (buf);
864                 if (addnode (vnode->other, kv) != 0)
865                 {
866                     error (0, 0,
867                            "\
868 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
869                            key, vnode->version, rcs->print_path);
870                     freenode (kv);
871                 }
872
873                 sprintf (buf, "%lu", del);
874                 kv = getnode ();
875                 kv->type = RCSFIELD;
876                 kv->key = xstrdup (";delete");
877                 kv->data = xstrdup (buf);
878                 if (addnode (vnode->other, kv) != 0)
879                 {
880                     error (0, 0,
881                            "\
882 warning: duplicate key `%s' in version `%s' of RCS file `%s'",
883                            key, vnode->version, rcs->print_path);
884                     freenode (kv);
885                 }
886             }
887
888             /* We have found the "text" key which ends the data for
889                this revision.  Break out of the loop and go on to the
890                next revision.  */
891             break;
892         }
893     }
894
895     rcsbuf_cache (rcs, &rcsbuf);
896 }
897
898
899
900 /*
901  * freercsnode - free up the info for an RCSNode
902  */
903 void
904 freercsnode (RCSNode **rnodep)
905 {
906     if (rnodep == NULL || *rnodep == NULL)
907         return;
908
909     ((*rnodep)->refcount)--;
910     if ((*rnodep)->refcount != 0)
911     {
912         *rnodep = NULL;
913         return;
914     }
915     free ((*rnodep)->path);
916     free ((*rnodep)->print_path);
917     if ((*rnodep)->head != NULL)
918         free ((*rnodep)->head);
919     if ((*rnodep)->branch != NULL)
920         free ((*rnodep)->branch);
921     free_rcsnode_contents (*rnodep);
922     free (*rnodep);
923     *rnodep = NULL;
924 }
925
926
927
928 /*
929  * free_rcsnode_contents - free up the contents of an RCSNode without
930  * freeing the node itself, or the file name, or the head, or the
931  * path.  This returns the RCSNode to the state it is in immediately
932  * after a call to RCS_parse.
933  */
934 static void
935 free_rcsnode_contents (RCSNode *rnode)
936 {
937     dellist (&rnode->versions);
938     if (rnode->symbols != NULL)
939         dellist (&rnode->symbols);
940     if (rnode->symbols_data != NULL)
941         free (rnode->symbols_data);
942     if (rnode->expand != NULL)
943         free (rnode->expand);
944     if (rnode->other != NULL)
945         dellist (&rnode->other);
946     if (rnode->access != NULL)
947         free (rnode->access);
948     if (rnode->locks_data != NULL)
949         free (rnode->locks_data);
950     if (rnode->locks != NULL)
951         dellist (&rnode->locks);
952     if (rnode->comment != NULL)
953         free (rnode->comment);
954     if (rnode->desc != NULL)
955         free (rnode->desc);
956 }
957
958
959
960 /* free_rcsvers_contents -- free up the contents of an RCSVers node,
961    but also free the pointer to the node itself. */
962 /* Note: The `hardlinks' list is *not* freed, since it is merely a
963    pointer into the `hardlist' structure (defined in hardlink.c), and
964    that structure is freed elsewhere in the program. */
965 static void
966 free_rcsvers_contents (RCSVers *rnode)
967 {
968     if (rnode->branches != NULL)
969         dellist (&rnode->branches);
970     if (rnode->date != NULL)
971         free (rnode->date);
972     if (rnode->next != NULL)
973         free (rnode->next);
974     if (rnode->author != NULL)
975         free (rnode->author);
976     if (rnode->state != NULL)
977         free (rnode->state);
978     if (rnode->other != NULL)
979         dellist (&rnode->other);
980     if (rnode->other_delta != NULL)
981         dellist (&rnode->other_delta);
982     if (rnode->text != NULL)
983         freedeltatext (rnode->text);
984     free (rnode);
985 }
986
987
988
989 /*
990  * rcsvers_delproc - free up an RCSVers type node
991  */
992 static void
993 rcsvers_delproc (Node *p)
994 {
995     free_rcsvers_contents (p->data);
996 }
997
998
999
1000 /* These functions retrieve keys and values from an RCS file using a
1001    buffer.  We use this somewhat complex approach because it turns out
1002    that for many common operations, CVS spends most of its time
1003    reading keys, so it's worth doing some fairly hairy optimization.  */
1004
1005 /* The number of bytes we try to read each time we need more data.  */
1006
1007 #define RCSBUF_BUFSIZE (8192)
1008
1009 /* The buffer we use to store data.  This grows as needed.  */
1010
1011 static char *rcsbuf_buffer = NULL;
1012 static size_t rcsbuf_buffer_size = 0;
1013
1014 /* Whether rcsbuf_buffer is in use.  This is used as a sanity check.  */
1015
1016 static int rcsbuf_inuse;
1017
1018 /* Set up to start gathering keys and values from an RCS file.  This
1019    initializes RCSBUF.  */
1020
1021 static void
1022 rcsbuf_open (struct rcsbuffer *rcsbuf, FILE *fp, const char *filename,
1023              long unsigned int pos)
1024 {
1025     if (rcsbuf_inuse)
1026         error (1, 0, "rcsbuf_open: internal error");
1027     rcsbuf_inuse = 1;
1028
1029 #ifdef HAVE_MMAP
1030     {
1031         /* When we have mmap, it is much more efficient to let the system do the
1032          * buffering and caching for us
1033          */
1034         struct stat fs;
1035         size_t mmap_off = 0;
1036
1037         if ( fstat (fileno(fp), &fs) < 0 )
1038             error ( 1, errno, "Could not stat RCS archive %s for mapping", filename );
1039
1040         if (pos)
1041         {
1042             size_t ps = getpagesize ();
1043             mmap_off = ( pos / ps ) * ps;
1044         }
1045
1046         /* Map private here since this particular buffer is read only */
1047         rcsbuf_buffer = mmap ( NULL, fs.st_size - mmap_off,
1048                                 PROT_READ | PROT_WRITE,
1049                                 MAP_PRIVATE, fileno(fp), mmap_off );
1050         if ( rcsbuf_buffer == NULL || rcsbuf_buffer == MAP_FAILED )
1051             error ( 1, errno, "Could not map memory to RCS archive %s", filename );
1052
1053         rcsbuf_buffer_size = fs.st_size - mmap_off;
1054         rcsbuf->ptr = rcsbuf_buffer + pos - mmap_off;
1055         rcsbuf->ptrend = rcsbuf_buffer + fs.st_size - mmap_off;
1056         rcsbuf->pos = mmap_off;
1057     }
1058 #else /* !HAVE_MMAP */
1059     if (rcsbuf_buffer_size < RCSBUF_BUFSIZE)
1060         expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, RCSBUF_BUFSIZE);
1061
1062     rcsbuf->ptr = rcsbuf_buffer;
1063     rcsbuf->ptrend = rcsbuf_buffer;
1064     rcsbuf->pos = pos;
1065 #endif /* HAVE_MMAP */
1066     rcsbuf->fp = fp;
1067     rcsbuf->filename = filename;
1068     rcsbuf->vlen = 0;
1069     rcsbuf->at_string = 0;
1070     rcsbuf->embedded_at = 0;
1071 }
1072
1073
1074
1075 /* Stop gathering keys from an RCS file.  */
1076 static void
1077 rcsbuf_close (struct rcsbuffer *rcsbuf)
1078 {
1079     if (! rcsbuf_inuse)
1080         error (1, 0, "rcsbuf_close: internal error");
1081 #ifdef HAVE_MMAP
1082     munmap ( rcsbuf_buffer, rcsbuf_buffer_size );
1083 #endif
1084     rcsbuf_inuse = 0;
1085 }
1086
1087
1088
1089 /* Read a key/value pair from an RCS file.  This sets *KEYP to point
1090    to the key, and *VALUEP to point to the value.  A missing or empty
1091    value is indicated by setting *VALUEP to NULL.
1092
1093    This function returns 1 on success, or 0 on EOF.  If there is an
1094    error reading the file, or an EOF in an unexpected location, it
1095    gives a fatal error.
1096
1097    This sets *KEYP and *VALUEP to point to storage managed by
1098    rcsbuf_getkey.  Moreover, *VALUEP has not been massaged from the
1099    RCS format: it may contain embedded whitespace and embedded '@'
1100    characters.  Call rcsbuf_valcopy or rcsbuf_valpolish to do
1101    appropriate massaging.  */
1102
1103 /* Note that the extreme hair in rcsbuf_getkey is because profiling
1104    statistics show that it was worth it. */
1105 static int
1106 rcsbuf_getkey (struct rcsbuffer *rcsbuf, char **keyp, char **valp)
1107 {
1108     register const char * const my_spacetab = spacetab;
1109     register char *ptr, *ptrend;
1110     char c;
1111
1112 #define my_whitespace(c)        (my_spacetab[(unsigned char)c] != 0)
1113
1114     rcsbuf->vlen = 0;
1115     rcsbuf->at_string = 0;
1116     rcsbuf->embedded_at = 0;
1117
1118     ptr = rcsbuf->ptr;
1119     ptrend = rcsbuf->ptrend;
1120
1121     /* Sanity check.  */
1122     assert (ptr >= rcsbuf_buffer && ptr <= rcsbuf_buffer + rcsbuf_buffer_size);
1123     assert (ptrend >= rcsbuf_buffer && ptrend <= rcsbuf_buffer + rcsbuf_buffer_size);
1124
1125 #ifndef HAVE_MMAP
1126     /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
1127        buffer, move back to the start of the buffer.  This keeps the
1128        buffer from growing indefinitely.  */
1129     if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
1130     {
1131         int len;
1132
1133         len = ptrend - ptr;
1134
1135         /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
1136            at a time, so we can't have more bytes than that past PTR.  */
1137         assert (len <= RCSBUF_BUFSIZE);
1138
1139         /* Update the POS field, which holds the file offset of the
1140            first byte in the RCSBUF_BUFFER buffer.  */
1141         rcsbuf->pos += ptr - rcsbuf_buffer;
1142
1143         memcpy (rcsbuf_buffer, ptr, len);
1144         ptr = rcsbuf_buffer;
1145         ptrend = ptr + len;
1146         rcsbuf->ptrend = ptrend;
1147     }
1148 #endif /* HAVE_MMAP */
1149
1150     /* Skip leading whitespace.  */
1151
1152     while (1)
1153     {
1154         if (ptr >= ptrend)
1155         {
1156             ptr = rcsbuf_fill (rcsbuf, ptr, NULL, NULL);
1157             if (ptr == NULL)
1158                 return 0;
1159             ptrend = rcsbuf->ptrend;
1160         }
1161
1162         c = *ptr;
1163         if (! my_whitespace (c))
1164             break;
1165
1166         ++ptr;
1167     }
1168
1169     /* We've found the start of the key.  */
1170
1171     *keyp = ptr;
1172
1173     if (c != ';')
1174     {
1175         while (1)
1176         {
1177             ++ptr;
1178             if (ptr >= ptrend)
1179             {
1180                 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, NULL);
1181                 if (ptr == NULL)
1182                     error (1, 0, "EOF in key in RCS file %s",
1183                            primary_root_inverse_translate (rcsbuf->filename));
1184                 ptrend = rcsbuf->ptrend;
1185             }
1186             c = *ptr;
1187             if (c == ';' || my_whitespace (c))
1188                 break;
1189         }
1190     }
1191
1192     /* Here *KEYP points to the key in the buffer, C is the character
1193        we found at the of the key, and PTR points to the location in
1194        the buffer where we found C.  We must set *PTR to \0 in order
1195        to terminate the key.  If the key ended with ';', then there is
1196        no value.  */
1197
1198     *ptr = '\0';
1199     ++ptr;
1200
1201     if (c == ';')
1202     {
1203         *valp = NULL;
1204         rcsbuf->ptr = ptr;
1205         return 1;
1206     }
1207
1208     /* C must be whitespace.  Skip whitespace between the key and the
1209        value.  If we find ';' now, there is no value.  */
1210
1211     while (1)
1212     {
1213         if (ptr >= ptrend)
1214         {
1215             ptr = rcsbuf_fill (rcsbuf, ptr, keyp, NULL);
1216             if (ptr == NULL)
1217                 error (1, 0, "EOF while looking for value in RCS file %s",
1218                        primary_root_inverse_translate (rcsbuf->filename));
1219             ptrend = rcsbuf->ptrend;
1220         }
1221         c = *ptr;
1222         if (c == ';')
1223         {
1224             *valp = NULL;
1225             rcsbuf->ptr = ptr + 1;
1226             return 1;
1227         }
1228         if (! my_whitespace (c))
1229             break;
1230         ++ptr;
1231     }
1232
1233     /* Now PTR points to the start of the value, and C is the first
1234        character of the value.  */
1235
1236     if (c != '@')
1237         *valp = ptr;
1238     else
1239     {
1240         char *pat;
1241         size_t vlen;
1242
1243         /* Optimize the common case of a value composed of a single
1244            '@' string.  */
1245
1246         rcsbuf->at_string = 1;
1247
1248         ++ptr;
1249
1250         *valp = ptr;
1251
1252         while (1)
1253         {
1254             while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1255             {
1256                 /* Note that we pass PTREND as the PTR value to
1257                    rcsbuf_fill, so that we will wind up setting PTR to
1258                    the location corresponding to the old PTREND, so
1259                    that we don't search the same bytes again.  */
1260                 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1261                 if (ptr == NULL)
1262                     error (1, 0,
1263                            "EOF while looking for end of string in RCS file %s",
1264                            primary_root_inverse_translate (rcsbuf->filename));
1265                 ptrend = rcsbuf->ptrend;
1266             }
1267
1268             /* Handle the special case of an '@' right at the end of
1269                the known bytes.  */
1270             if (pat + 1 >= ptrend)
1271             {
1272                 /* Note that we pass PAT, not PTR, here.  */
1273                 pat = rcsbuf_fill (rcsbuf, pat, keyp, valp);
1274                 if (pat == NULL)
1275                 {
1276                     /* EOF here is OK; it just means that the last
1277                        character of the file was an '@' terminating a
1278                        value for a key type which does not require a
1279                        trailing ';'.  */
1280                     pat = rcsbuf->ptrend - 1;
1281
1282                 }
1283                 ptrend = rcsbuf->ptrend;
1284
1285                 /* Note that the value of PTR is bogus here.  This is
1286                    OK, because we don't use it.  */
1287             }
1288
1289             if (pat + 1 >= ptrend || pat[1] != '@')
1290                 break;
1291
1292             /* We found an '@' pair in the string.  Keep looking.  */
1293             ++rcsbuf->embedded_at;
1294             ptr = pat + 2;
1295         }
1296
1297         /* Here PAT points to the final '@' in the string.  */
1298
1299         *pat = '\0';
1300
1301         vlen = pat - *valp;
1302         if (vlen == 0)
1303             *valp = NULL;
1304         rcsbuf->vlen = vlen;
1305
1306         ptr = pat + 1;
1307     }
1308
1309     /* Certain keywords only have a '@' string.  If there is no '@'
1310        string, then the old getrcskey function assumed that they had
1311        no value, and we do the same.  */
1312
1313     {
1314         char *k;
1315
1316         k = *keyp;
1317         if (STREQ (k, RCSDESC)
1318             || STREQ (k, "text")
1319             || STREQ (k, "log"))
1320         {
1321             if (c != '@')
1322                 *valp = NULL;
1323             rcsbuf->ptr = ptr;
1324             return 1;
1325         }
1326     }
1327
1328     /* If we've already gathered a '@' string, try to skip whitespace
1329        and find a ';'.  */
1330     if (c == '@')
1331     {
1332         while (1)
1333         {
1334             char n;
1335
1336             if (ptr >= ptrend)
1337             {
1338                 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1339                 if (ptr == NULL)
1340                     error (1, 0, "EOF in value in RCS file %s",
1341                            primary_root_inverse_translate (rcsbuf->filename));
1342                 ptrend = rcsbuf->ptrend;
1343             }
1344             n = *ptr;
1345             if (n == ';')
1346             {
1347                 /* We're done.  We already set everything up for this
1348                    case above.  */
1349                 rcsbuf->ptr = ptr + 1;
1350                 return 1;
1351             }
1352             if (! my_whitespace (n))
1353                 break;
1354             ++ptr;
1355         }
1356
1357         /* The value extends past the '@' string.  We need to undo the
1358            '@' stripping done in the default case above.  This
1359            case never happens in a plain RCS file, but it can happen
1360            if user defined phrases are used.  */
1361         ((*valp)--)[rcsbuf->vlen++] = '@';
1362     }
1363
1364     /* Here we have a value which is not a simple '@' string.  We need
1365        to gather up everything until the next ';', including any '@'
1366        strings.  *VALP points to the start of the value.  If
1367        RCSBUF->VLEN is not zero, then we have already read an '@'
1368        string, and PTR points to the data following the '@' string.
1369        Otherwise, PTR points to the start of the value.  */
1370
1371     while (1)
1372     {
1373         char *start, *psemi, *pat;
1374
1375         /* Find the ';' which must end the value.  */
1376         start = ptr;
1377         while ((psemi = memchr (ptr, ';', ptrend - ptr)) == NULL)
1378         {
1379             int slen;
1380
1381             /* Note that we pass PTREND as the PTR value to
1382                rcsbuf_fill, so that we will wind up setting PTR to the
1383                location corresponding to the old PTREND, so that we
1384                don't search the same bytes again.  */
1385             slen = start - *valp;
1386             ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1387             if (ptr == NULL)
1388                 error (1, 0, "EOF in value in RCS file %s",
1389                        primary_root_inverse_translate (rcsbuf->filename));
1390             start = *valp + slen;
1391             ptrend = rcsbuf->ptrend;
1392         }
1393
1394         /* See if there are any '@' strings in the value.  */
1395         pat = memchr (start, '@', psemi - start);
1396
1397         if (pat == NULL)
1398         {
1399             size_t vlen;
1400
1401             /* We're done with the value.  Trim any trailing
1402                whitespace.  */
1403
1404             rcsbuf->ptr = psemi + 1;
1405
1406             start = *valp;
1407             while (psemi > start && my_whitespace (psemi[-1]))
1408                 --psemi;
1409             *psemi = '\0';
1410
1411             vlen = psemi - start;
1412             if (vlen == 0)
1413                 *valp = NULL;
1414             rcsbuf->vlen = vlen;
1415
1416             return 1;
1417         }
1418
1419         /* We found an '@' string in the value.  We set RCSBUF->AT_STRING
1420            and RCSBUF->EMBEDDED_AT to indicate that we won't be able to
1421            compress whitespace correctly for this type of value.
1422            Since this type of value never arises in a normal RCS file,
1423            this should not be a big deal.  It means that if anybody
1424            adds a phrase which can have both an '@' string and regular
1425            text, they will have to handle whitespace compression
1426            themselves.  */
1427
1428         rcsbuf->at_string = 1;
1429         rcsbuf->embedded_at = -1;
1430
1431         ptr = pat + 1;
1432
1433         while (1)
1434         {
1435             while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
1436             {
1437                 /* Note that we pass PTREND as the PTR value to
1438                    rcsbuff_fill, so that we will wind up setting PTR
1439                    to the location corresponding to the old PTREND, so
1440                    that we don't search the same bytes again.  */
1441                 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
1442                 if (ptr == NULL)
1443                     error (1, 0,
1444                            "EOF while looking for end of string in RCS file %s",
1445                            primary_root_inverse_translate (rcsbuf->filename));
1446                 ptrend = rcsbuf->ptrend;
1447             }
1448
1449             /* Handle the special case of an '@' right at the end of
1450                the known bytes.  */
1451             if (pat + 1 >= ptrend)
1452             {
1453                 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
1454                 if (ptr == NULL)
1455                     error (1, 0, "EOF in value in RCS file %s",
1456                            primary_root_inverse_translate (rcsbuf->filename));
1457                 ptrend = rcsbuf->ptrend;
1458             }
1459
1460             if (pat[1] != '@')
1461                 break;
1462
1463             /* We found an '@' pair in the string.  Keep looking.  */
1464             ptr = pat + 2;
1465         }
1466
1467         /* Here PAT points to the final '@' in the string.  */
1468         ptr = pat + 1;
1469     }
1470
1471 #undef my_whitespace
1472 }
1473
1474
1475
1476 /* Read an RCS revision number from an RCS file.  This sets *REVP to
1477    point to the revision number; it will point to space that is
1478    managed by the rcsbuf functions, and is only good until the next
1479    call to rcsbuf_getkey or rcsbuf_getrevnum.
1480
1481    This function returns 1 on success, or 0 on EOF.  If there is an
1482    error reading the file, or an EOF in an unexpected location, it
1483    gives a fatal error.  */
1484 static int
1485 rcsbuf_getrevnum (struct rcsbuffer *rcsbuf, char **revp)
1486 {
1487     char *ptr, *ptrend;
1488     char c;
1489
1490     ptr = rcsbuf->ptr;
1491     ptrend = rcsbuf->ptrend;
1492
1493     *revp = NULL;
1494
1495     /* Skip leading whitespace.  */
1496
1497     while (1)
1498     {
1499         if (ptr >= ptrend)
1500         {
1501             ptr = rcsbuf_fill (rcsbuf, ptr, NULL, NULL);
1502             if (ptr == NULL)
1503                 return 0;
1504             ptrend = rcsbuf->ptrend;
1505         }
1506
1507         c = *ptr;
1508         if (! whitespace (c))
1509             break;
1510
1511         ++ptr;
1512     }
1513
1514     if (! isdigit ((unsigned char) c) && c != '.')
1515         error (1, 0,
1516                "\
1517 unexpected '\\x%x' reading revision number in RCS file %s",
1518                c, primary_root_inverse_translate (rcsbuf->filename));
1519
1520     *revp = ptr;
1521
1522     do
1523     {
1524         ++ptr;
1525         if (ptr >= ptrend)
1526         {
1527             ptr = rcsbuf_fill (rcsbuf, ptr, revp, NULL);
1528             if (ptr == NULL)
1529                 error (1, 0,
1530                        "unexpected EOF reading revision number in RCS file %s",
1531                        primary_root_inverse_translate (rcsbuf->filename));
1532             ptrend = rcsbuf->ptrend;
1533         }
1534
1535         c = *ptr;
1536     }
1537     while (isdigit ((unsigned char) c) || c == '.');
1538
1539     if (! whitespace (c))
1540         error (1, 0, "\
1541 unexpected '\\x%x' reading revision number in RCS file %s",
1542                c, primary_root_inverse_translate (rcsbuf->filename));
1543
1544     *ptr = '\0';
1545
1546     rcsbuf->ptr = ptr + 1;
1547
1548     return 1;
1549 }
1550
1551
1552
1553 /* Fill RCSBUF_BUFFER with bytes from the file associated with RCSBUF,
1554    updating PTR and the PTREND field.  If KEYP and *KEYP are not NULL,
1555    then *KEYP points into the buffer, and must be adjusted if the
1556    buffer is changed.  Likewise for VALP.  Returns the new value of
1557    PTR, or NULL on error.  */
1558 static char *
1559 rcsbuf_fill (struct rcsbuffer *rcsbuf, char *ptr, char **keyp, char **valp)
1560 {
1561 #ifdef HAVE_MMAP
1562     return NULL;
1563 #else /* HAVE_MMAP */
1564     int got;
1565
1566     if (rcsbuf->ptrend - rcsbuf_buffer + RCSBUF_BUFSIZE > rcsbuf_buffer_size)
1567     {
1568         int poff, peoff, koff, voff;
1569
1570         poff = ptr - rcsbuf_buffer;
1571         peoff = rcsbuf->ptrend - rcsbuf_buffer;
1572         koff = keyp == NULL ? 0 : *keyp - rcsbuf_buffer;
1573         voff = valp == NULL ? 0 : *valp - rcsbuf_buffer;
1574
1575         expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size,
1576                        rcsbuf_buffer_size + RCSBUF_BUFSIZE);
1577
1578         ptr = rcsbuf_buffer + poff;
1579         rcsbuf->ptrend = rcsbuf_buffer + peoff;
1580         if (keyp != NULL)
1581             *keyp = rcsbuf_buffer + koff;
1582         if (valp != NULL)
1583             *valp = rcsbuf_buffer + voff;
1584     }
1585
1586     got = fread (rcsbuf->ptrend, 1, RCSBUF_BUFSIZE, rcsbuf->fp);
1587     if (got == 0)
1588     {
1589         if (ferror (rcsbuf->fp))
1590             error (1, errno, "cannot read %s", rcsbuf->filename);
1591         return NULL;
1592     }
1593
1594     rcsbuf->ptrend += got;
1595
1596     return ptr;
1597 #endif /* HAVE_MMAP */
1598 }
1599
1600
1601
1602 /* Test whether the last value returned by rcsbuf_getkey is a composite
1603    value or not. */
1604 static int
1605 rcsbuf_valcmp (struct rcsbuffer *rcsbuf)
1606 {
1607     return rcsbuf->at_string && rcsbuf->embedded_at < 0;
1608 }
1609
1610
1611
1612 /* Copy the value VAL returned by rcsbuf_getkey into a memory buffer,
1613    returning the memory buffer.  Polish the value like
1614    rcsbuf_valpolish, q.v.  */
1615 static char *
1616 rcsbuf_valcopy (struct rcsbuffer *rcsbuf, char *val, int polish, size_t *lenp)
1617 {
1618     size_t vlen;
1619     int embedded_at;
1620     char *ret;
1621
1622     if (val == NULL)
1623     {
1624         if (lenp != NULL)
1625             *lenp = 0;
1626         return NULL;
1627     }
1628
1629     vlen = rcsbuf->vlen;
1630     embedded_at = rcsbuf->embedded_at < 0 ? 0 : rcsbuf->embedded_at;
1631
1632     ret = xmalloc (vlen - embedded_at + 1);
1633
1634     if (rcsbuf->at_string ? embedded_at == 0 : ! polish)
1635     {
1636         /* No special action to take.  */
1637         memcpy (ret, val, vlen + 1);
1638         if (lenp != NULL)
1639             *lenp = vlen;
1640         return ret;
1641     }
1642
1643     rcsbuf_valpolish_internal (rcsbuf, ret, val, lenp);
1644     return ret;
1645 }
1646
1647
1648
1649 /* Polish the value VAL returned by rcsbuf_getkey.  The POLISH
1650    parameter is non-zero if multiple embedded whitespace characters
1651    should be compressed into a single whitespace character.  Note that
1652    leading and trailing whitespace was already removed by
1653    rcsbuf_getkey.  Within an '@' string, pairs of '@' characters are
1654    compressed into a single '@' character regardless of the value of
1655    POLISH.  If LENP is not NULL, set *LENP to the length of the value.  */
1656 static void
1657 rcsbuf_valpolish (struct rcsbuffer *rcsbuf, char *val, int polish,
1658                   size_t *lenp)
1659 {
1660     if (val == NULL)
1661     {
1662         if (lenp != NULL)
1663             *lenp= 0;
1664         return;
1665     }
1666
1667     if (rcsbuf->at_string ? rcsbuf->embedded_at == 0 : ! polish)
1668     {
1669         /* No special action to take.  */
1670         if (lenp != NULL)
1671             *lenp = rcsbuf->vlen;
1672         return;
1673     }
1674
1675     rcsbuf_valpolish_internal (rcsbuf, val, val, lenp);
1676 }
1677
1678
1679
1680 /* Internal polishing routine, called from rcsbuf_valcopy and
1681    rcsbuf_valpolish.  */
1682 static void
1683 rcsbuf_valpolish_internal (struct rcsbuffer *rcsbuf, char *to,
1684                            const char *from, size_t *lenp)
1685 {
1686     size_t len;
1687
1688     len = rcsbuf->vlen;
1689
1690     if (! rcsbuf->at_string)
1691     {
1692         char *orig_to;
1693         size_t clen;
1694
1695         orig_to = to;
1696
1697         for (clen = len; clen > 0; ++from, --clen)
1698         {
1699             char c;
1700
1701             c = *from;
1702             if (whitespace (c))
1703             {
1704                 /* Note that we know that clen can not drop to zero
1705                    while we have whitespace, because we know there is
1706                    no trailing whitespace.  */
1707                 while (whitespace (from[1]))
1708                 {
1709                     ++from;
1710                     --clen;
1711                 }
1712                 c = ' ';
1713             }
1714             *to++ = c;
1715         }
1716
1717         *to = '\0';
1718
1719         if (lenp != NULL)
1720             *lenp = to - orig_to;
1721     }
1722     else
1723     {
1724         const char *orig_from;
1725         char *orig_to;
1726         int embedded_at;
1727         size_t clen;
1728
1729         orig_from = from;
1730         orig_to = to;
1731
1732         embedded_at = rcsbuf->embedded_at;
1733         assert (embedded_at > 0);
1734
1735         if (lenp != NULL)
1736             *lenp = len - embedded_at;
1737
1738         for (clen = len; clen > 0; ++from, --clen)
1739         {
1740             char c;
1741
1742             c = *from;
1743             *to++ = c;
1744             if (c == '@')
1745             {
1746                 ++from;
1747
1748                 /* Sanity check.
1749                  *
1750                  * FIXME: I restored this to an abort from an assert based on
1751                  * advice from Larry Jones that asserts should not be used to
1752                  * confirm the validity of an RCS file...  This leaves two
1753                  * issues here: 1) I am uncertain that the fact that we will
1754                  * only find double '@'s hasn't already been confirmed; and:
1755                  * 2) If this is the proper place to spot the error in the RCS
1756                  * file, then we should print a much clearer error here for the
1757                  * user!!!!!!!
1758                  *
1759                  *      - DRP
1760                  */
1761                 if (*from != '@' || clen == 0)
1762                     abort ();
1763
1764                 --clen;
1765
1766                 --embedded_at;
1767                 if (embedded_at == 0)
1768                 {
1769                     /* We've found all the embedded '@' characters.
1770                        We can just memcpy the rest of the buffer after
1771                        this '@' character.  */
1772                     if (orig_to != orig_from)
1773                         memcpy (to, from + 1, clen - 1);
1774                     else
1775                         memmove (to, from + 1, clen - 1);
1776                     from += clen;
1777                     to += clen - 1;
1778                     break;
1779                 }
1780             }
1781         }
1782
1783         /* Sanity check.  */
1784         assert (from == orig_from + len
1785             && to == orig_to + (len - rcsbuf->embedded_at));
1786
1787         *to = '\0';
1788     }
1789 }
1790
1791
1792
1793 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1794
1795 /* Copy the next word from the value VALP returned by rcsbuf_getkey into a
1796    memory buffer, updating VALP and returning the memory buffer.  Return
1797    NULL when there are no more words. */
1798
1799 static char *
1800 rcsbuf_valword (struct rcsbuffer *rcsbuf, char **valp)
1801 {
1802     register const char * const my_spacetab = spacetab;
1803     register char *ptr, *pat;
1804     char c;
1805
1806 # define my_whitespace(c)       (my_spacetab[(unsigned char)c] != 0)
1807
1808     if (*valp == NULL)
1809         return NULL;
1810
1811     for (ptr = *valp; my_whitespace (*ptr); ++ptr) ;
1812     if (*ptr == '\0')
1813     {
1814         assert (ptr - *valp == rcsbuf->vlen);
1815         *valp = NULL;
1816         rcsbuf->vlen = 0;
1817         return NULL;
1818     }
1819
1820     /* PTR now points to the start of a value.  Find out whether it is
1821        a num, an id, a string or a colon. */
1822     c = *ptr;
1823     if (c == ':')
1824     {
1825         rcsbuf->vlen -= ++ptr - *valp;
1826         *valp = ptr;
1827         return xstrdup (":");
1828     }
1829
1830     if (c == '@')
1831     {
1832         int embedded_at = 0;
1833         size_t vlen;
1834
1835         pat = ++ptr;
1836         while ((pat = strchr (pat, '@')) != NULL)
1837         {
1838             if (pat[1] != '@')
1839                 break;
1840             ++embedded_at;
1841             pat += 2;
1842         }
1843
1844         /* Here PAT points to the final '@' in the string.  */
1845         *pat++ = '\0';
1846         assert (rcsbuf->at_string);
1847         vlen = rcsbuf->vlen - (pat - *valp);
1848         rcsbuf->vlen = pat - ptr - 1;
1849         rcsbuf->embedded_at = embedded_at;
1850         ptr = rcsbuf_valcopy (rcsbuf, ptr, 0, NULL);
1851         *valp = pat;
1852         rcsbuf->vlen = vlen;
1853         if (strchr (pat, '@') == NULL)
1854             rcsbuf->at_string = 0;
1855         else
1856             rcsbuf->embedded_at = -1;
1857         return ptr;
1858     }
1859
1860     /* *PTR is neither `:', `;' nor `@', so it should be the start of a num
1861        or an id.  Make sure it is not another special character. */
1862     if (c == '$' || c == '.' || c == ',')
1863         error (1, 0, "invalid special character in RCS field in %s",
1864                primary_root_inverse_translate (rcsbuf->filename));
1865
1866     pat = ptr;
1867     while (1)
1868     {
1869         /* Legitimate ID characters are digits, dots and any `graphic
1870            printing character that is not a special.' This test ought
1871            to do the trick. */
1872         c = *++pat;
1873         if (!isprint ((unsigned char) c) ||
1874             c == ';' || c == '$' || c == ',' || c == '@' || c == ':')
1875             break;
1876     }
1877
1878     /* PAT points to the last non-id character in this word, and C is
1879        the character in its memory cell.  Check to make sure that it
1880        is a legitimate word delimiter -- whitespace or end. */
1881     if (c != '\0' && !my_whitespace (c))
1882         error (1, 0, "invalid special character in RCS field in %s",
1883                primary_root_inverse_translate (rcsbuf->filename));
1884
1885     *pat = '\0';
1886     rcsbuf->vlen -= pat - *valp;
1887     *valp = pat;
1888     return xstrdup (ptr);
1889
1890 # undef my_whitespace
1891 }
1892
1893 #endif /* PRESERVE_PERMISSIONS_SUPPORT */
1894
1895
1896
1897 /* Return the current position of an rcsbuf.  */
1898 static off_t
1899 rcsbuf_ftello (struct rcsbuffer *rcsbuf)
1900 {
1901     return rcsbuf->pos + rcsbuf->ptr - rcsbuf_buffer;
1902 }
1903
1904
1905
1906 /* Return a pointer to any data buffered for RCSBUF, along with the
1907    length.  */
1908 static void
1909 rcsbuf_get_buffered (struct rcsbuffer *rcsbuf, char **datap, size_t *lenp)
1910 {
1911     *datap = rcsbuf->ptr;
1912     *lenp = rcsbuf->ptrend - rcsbuf->ptr;
1913 }
1914
1915
1916
1917 /* CVS optimizes by quickly reading some header information from a
1918    file.  If it decides it needs to do more with the file, it reopens
1919    it.  We speed that up here by maintaining a cache of a single open
1920    file, to save the time it takes to reopen the file in the common
1921    case.  */
1922 static RCSNode *cached_rcs;
1923 static struct rcsbuffer cached_rcsbuf;
1924
1925 /* Cache RCS and RCSBUF.  This takes responsibility for closing
1926    RCSBUF->FP.  */
1927 static void
1928 rcsbuf_cache (RCSNode *rcs, struct rcsbuffer *rcsbuf)
1929 {
1930     if (cached_rcs != NULL)
1931         rcsbuf_cache_close ();
1932     cached_rcs = rcs;
1933     ++rcs->refcount;
1934     cached_rcsbuf = *rcsbuf;
1935 }
1936
1937
1938
1939 /* If there is anything in the cache, close it.  */
1940 static void
1941 rcsbuf_cache_close (void)
1942 {
1943     if (cached_rcs != NULL)
1944     {
1945         rcsbuf_close (&cached_rcsbuf);
1946         if (fclose (cached_rcsbuf.fp) != 0)
1947             error (0, errno, "cannot close %s", cached_rcsbuf.filename);
1948         freercsnode (&cached_rcs);
1949         cached_rcs = NULL;
1950     }
1951 }
1952
1953
1954
1955 /* Open an rcsbuffer for RCS, getting it from the cache if possible.
1956    Set *FPP to the file, and *RCSBUFP to the rcsbuf.  The file should
1957    be put at position POS.  */
1958 static void
1959 rcsbuf_cache_open (RCSNode *rcs, off_t pos, FILE **pfp,
1960                    struct rcsbuffer *prcsbuf)
1961 {
1962 #ifndef HAVE_MMAP
1963     if (cached_rcs == rcs)
1964     {
1965         if (rcsbuf_ftello (&cached_rcsbuf) != pos)
1966         {
1967             if (fseeko (cached_rcsbuf.fp, pos, SEEK_SET) != 0)
1968                 error (1, 0, "cannot fseeko RCS file %s",
1969                        cached_rcsbuf.filename);
1970             cached_rcsbuf.ptr = rcsbuf_buffer;
1971             cached_rcsbuf.ptrend = rcsbuf_buffer;
1972             cached_rcsbuf.pos = pos;
1973         }
1974         *pfp = cached_rcsbuf.fp;
1975
1976         /* When RCS_parse opens a file using fopen_case, it frees the
1977            filename which we cached in CACHED_RCSBUF and stores a new
1978            file name in RCS->PATH.  We avoid problems here by always
1979            copying the filename over.  FIXME: This is hackish.  */
1980         cached_rcsbuf.filename = rcs->path;
1981
1982         *prcsbuf = cached_rcsbuf;
1983
1984         cached_rcs = NULL;
1985
1986         /* Removing RCS from the cache removes a reference to it.  */
1987         --rcs->refcount;
1988         if (rcs->refcount <= 0)
1989             error (1, 0, "rcsbuf_cache_open: internal error");
1990     }
1991     else
1992     {
1993 #endif /* ifndef HAVE_MMAP */
1994         /* FIXME:  If these routines can be rewritten to not write to the
1995          * rcs file buffer, there would be a considerably larger memory savings
1996          * from using mmap since the shared file would never need be copied to
1997          * process memory.
1998          *
1999          * If this happens, cached mmapped buffers would be usable, but don't
2000          * forget to make sure rcs->pos < pos here...
2001          */
2002         if (cached_rcs != NULL)
2003             rcsbuf_cache_close ();
2004
2005         *pfp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ);
2006         if (*pfp == NULL)
2007             error (1, 0, "unable to reopen `%s'", rcs->path);
2008 #ifndef HAVE_MMAP
2009         if (pos != 0)
2010         {
2011             if (fseeko (*pfp, pos, SEEK_SET) != 0)
2012                 error (1, 0, "cannot fseeko RCS file %s", rcs->path);
2013         }
2014 #endif /* ifndef HAVE_MMAP */
2015         rcsbuf_open (prcsbuf, *pfp, rcs->path, pos);
2016 #ifndef HAVE_MMAP
2017     }
2018 #endif /* ifndef HAVE_MMAP */
2019 }
2020
2021
2022
2023 /*
2024  * process the symbols list of the rcs file
2025  */
2026 static void
2027 do_symbols (List *list, char *val)
2028 {
2029     Node *p;
2030     char *cp = val;
2031     char *tag, *rev;
2032
2033     assert (cp);
2034
2035     for (;;)
2036     {
2037         /* skip leading whitespace */
2038         while (whitespace (*cp))
2039             cp++;
2040
2041         /* if we got to the end, we are done */
2042         if (*cp == '\0')
2043             break;
2044
2045         /* split it up into tag and rev */
2046         tag = cp;
2047         cp = strchr (cp, ':');
2048         *cp++ = '\0';
2049         rev = cp;
2050         while (!whitespace (*cp) && *cp != '\0')
2051             cp++;
2052         if (*cp != '\0')
2053             *cp++ = '\0';
2054
2055         /* make a new node and add it to the list */
2056         p = getnode ();
2057         p->key = xstrdup (tag);
2058         p->data = xstrdup (rev);
2059         (void) addnode (list, p);
2060     }
2061 }
2062
2063
2064
2065 /*
2066  * process the locks list of the rcs file
2067  * Like do_symbols, but hash entries are keyed backwards: i.e.
2068  * an entry like `user:rev' is keyed on REV rather than on USER.
2069  */
2070 static void
2071 do_locks (List *list, char *val)
2072 {
2073     Node *p;
2074     char *cp = val;
2075     char *user, *rev;
2076
2077     assert (cp);
2078
2079     for (;;)
2080     {
2081         /* skip leading whitespace */
2082         while (whitespace (*cp))
2083             cp++;
2084
2085         /* if we got to the end, we are done */
2086         if (*cp == '\0')
2087             break;
2088
2089         /* split it up into user and rev */
2090         user = cp;
2091         cp = strchr (cp, ':');
2092         *cp++ = '\0';
2093         rev = cp;
2094         while (!whitespace (*cp) && *cp != '\0')
2095             cp++;
2096         if (*cp != '\0')
2097             *cp++ = '\0';
2098
2099         /* make a new node and add it to the list */
2100         p = getnode ();
2101         p->key = xstrdup (rev);
2102         p->data = xstrdup (user);
2103         (void) addnode (list, p);
2104     }
2105 }
2106
2107
2108
2109 /*
2110  * process the branches list of a revision delta
2111  */
2112 static void
2113 do_branches (List *list, char *val)
2114 {
2115     Node *p;
2116     char *cp = val;
2117     char *branch;
2118
2119     for (;;)
2120     {
2121         /* skip leading whitespace */
2122         while (whitespace (*cp))
2123             cp++;
2124
2125         /* if we got to the end, we are done */
2126         if (*cp == '\0')
2127             break;
2128
2129         /* find the end of this branch */
2130         branch = cp;
2131         while (!whitespace (*cp) && *cp != '\0')
2132             cp++;
2133         if (*cp != '\0')
2134             *cp++ = '\0';
2135
2136         /* make a new node and add it to the list */
2137         p = getnode ();
2138         p->key = xstrdup (branch);
2139         (void) addnode (list, p);
2140     }
2141 }
2142
2143
2144
2145 /*
2146  * Version Number
2147  * 
2148  * Returns the requested version number of the RCS file, satisfying tags and/or
2149  * dates, and walking branches, if necessary.
2150  * 
2151  * The result is returned; null-string if error.
2152  */
2153 char *
2154 RCS_getversion (RCSNode *rcs, const char *tag, const char *date,
2155                 int force_tag_match, int *simple_tag)
2156 {
2157     if (simple_tag != NULL)
2158         *simple_tag = 0;
2159
2160     /* make sure we have something to look at... */
2161     assert (rcs != NULL);
2162
2163     if (tag && date)
2164     {
2165         char *branch, *rev;
2166
2167         if (! RCS_nodeisbranch (rcs, tag))
2168         {
2169             /* We can't get a particular date if the tag is not a
2170                branch.  */
2171             return NULL;
2172         }
2173
2174         /* Work out the branch.  */
2175         if (! isdigit ((unsigned char) tag[0]))
2176             branch = RCS_whatbranch (rcs, tag);
2177         else
2178             branch = xstrdup (tag);
2179
2180         /* Fetch the revision of branch as of date.  */
2181         rev = RCS_getdatebranch (rcs, date, branch);
2182         free (branch);
2183         return rev;
2184     }
2185     else if (tag)
2186         return RCS_gettag (rcs, tag, force_tag_match, simple_tag);
2187     else if (date)
2188         return RCS_getdate (rcs, date, force_tag_match);
2189     else
2190         return RCS_head (rcs);
2191
2192 }
2193
2194
2195
2196 /*
2197  * Get existing revision number corresponding to tag or revision.
2198  * Similar to RCS_gettag but less interpretation imposed.
2199  * For example:
2200  * -- If tag designates a magic branch, RCS_tag2rev
2201  *    returns the magic branch number.
2202  * -- If tag is a branch tag, returns the branch number, not
2203  *    the revision of the head of the branch.
2204  * If tag or revision is not valid or does not exist in file,
2205  * return NULL.
2206  */
2207 char *
2208 RCS_tag2rev (RCSNode *rcs, char *tag)
2209 {
2210     char *rev, *pa, *pb;
2211     int i;
2212
2213     assert (rcs != NULL);
2214
2215     if (rcs->flags & PARTIAL)
2216         RCS_reparsercsfile (rcs, NULL, NULL);
2217
2218     /* If a valid revision, try to look it up */
2219     if ( RCS_valid_rev (tag) )
2220     {
2221         /* Make a copy so we can scribble on it */
2222         rev =  xstrdup (tag);
2223
2224         /* If revision exists, return the copy */
2225         if (RCS_exist_rev (rcs, tag))
2226             return rev;
2227
2228         /* Nope, none such. If tag is not a branch we're done. */ 
2229         i = numdots (rev);
2230         if ((i & 1) == 1 )
2231         {
2232             pa = strrchr (rev, '.');
2233             if (i == 1 || *(pa-1) != RCS_MAGIC_BRANCH || *(pa-2) != '.')
2234             {
2235                 free (rev);
2236                 error (1, 0, "revision `%s' does not exist", tag);
2237             }
2238         }
2239
2240         /* Try for a real (that is, exists in the RCS deltas) branch
2241            (RCS_exist_rev just checks for real revisions and revisions
2242            which have tags pointing to them).  */
2243         pa = RCS_getbranch (rcs, rev, 1);
2244         if (pa != NULL)
2245         {
2246             free (pa);
2247             return rev;
2248         }
2249
2250        /* Tag is branch, but does not exist, try corresponding 
2251         * magic branch tag.
2252         *
2253         * FIXME: assumes all magic branches are of       
2254         * form "n.n.n ... .0.n".  I'll fix if somebody can
2255         * send me a method to get a magic branch tag with
2256         * the 0 in some other position -- <dan@gasboy.com>
2257         */ 
2258         pa = strrchr (rev, '.');
2259         if (!pa)
2260             /* This might happen, for instance, if an RCS file only contained
2261              * revisions 2.x and higher, and REV == "1".
2262              */
2263             error (1, 0, "revision `%s' does not exist", tag);
2264
2265         *pa++ = 0;
2266         pb = Xasprintf ("%s.%d.%s", rev, RCS_MAGIC_BRANCH, pa);
2267         free (rev);
2268         rev = pb;
2269         if (RCS_exist_rev (rcs, rev))
2270             return rev;
2271         error (1, 0, "revision `%s' does not exist", tag);
2272     }
2273
2274
2275     RCS_check_tag (tag); /* exit if not a valid tag */
2276
2277     /* If tag is "HEAD", special case to get head RCS revision */
2278     if (tag && STREQ (tag, TAG_HEAD))
2279         return RCS_head (rcs);
2280
2281     /* If valid tag let translate_symtag say yea or nay. */
2282     rev = translate_symtag (rcs, tag);
2283
2284     if (rev)
2285         return rev;
2286
2287     /* Trust the caller to print warnings. */
2288     return NULL;
2289 }
2290
2291
2292
2293 /*
2294  * Find the revision for a specific tag.
2295  * If force_tag_match is set, return NULL if an exact match is not
2296  * possible otherwise return RCS_head ().  We are careful to look for
2297  * and handle "magic" revisions specially.
2298  * 
2299  * If the matched tag is a branch tag, find the head of the branch.
2300  * 
2301  * Returns pointer to newly malloc'd string, or NULL.
2302  */
2303 char *
2304 RCS_gettag (RCSNode *rcs, const char *symtag, int force_tag_match,
2305             int *simple_tag)
2306 {
2307     char *tag;
2308
2309     if (simple_tag != NULL)
2310         *simple_tag = 0;
2311
2312     /* make sure we have something to look at... */
2313     assert (rcs != NULL);
2314
2315     /* XXX this is probably not necessary, --jtc */
2316     if (rcs->flags & PARTIAL) 
2317         RCS_reparsercsfile (rcs, NULL, NULL);
2318
2319     /* If symtag is "HEAD", special case to get head RCS revision */
2320     if (symtag && STREQ (symtag, TAG_HEAD))
2321 #if 0 /* This #if 0 is only in the Cygnus code.  Why?  Death support?  */
2322         if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
2323             return NULL;        /* head request for removed file */
2324         else
2325 #endif
2326             return RCS_head (rcs);
2327
2328     if (!isdigit ((unsigned char) symtag[0]))
2329     {
2330         char *version;
2331
2332         /* If we got a symbolic tag, resolve it to a numeric */
2333         version = translate_symtag (rcs, symtag);
2334         if (version != NULL)
2335         {
2336             int dots;
2337             char *magic, *branch, *cp;
2338
2339             tag = version;
2340
2341             /*
2342              * If this is a magic revision, we turn it into either its
2343              * physical branch equivalent (if one exists) or into
2344              * its base revision, which we assume exists.
2345              */
2346             dots = numdots (tag);
2347             if (dots > 2 && (dots & 1) != 0)
2348             {
2349                 branch = strrchr (tag, '.');
2350                 cp = branch++ - 1;
2351                 while (*cp != '.')
2352                     cp--;
2353
2354                 /* see if we have .magic-branch. (".0.") */
2355                 magic = xmalloc (strlen (tag) + 1);
2356                 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2357                 if (strncmp (magic, cp, strlen (magic)) == 0)
2358                 {
2359                     /* it's magic.  See if the branch exists */
2360                     *cp = '\0';         /* turn it into a revision */
2361                     (void) sprintf (magic, "%s.%s", tag, branch);
2362                     branch = RCS_getbranch (rcs, magic, 1);
2363                     free (magic);
2364                     if (branch != NULL)
2365                     {
2366                         free (tag);
2367                         return branch;
2368                     }
2369                     return tag;
2370                 }
2371                 free (magic);
2372             }
2373         }
2374         else
2375         {
2376             /* The tag wasn't there, so return the head or NULL */
2377             if (force_tag_match)
2378                 return NULL;
2379             else
2380                 return RCS_head (rcs);
2381         }
2382     }
2383     else
2384         tag = xstrdup (symtag);
2385
2386     /* tag is always allocated and numeric now.  */
2387
2388     /*
2389      * numeric tag processing:
2390      *          1) revision number - just return it
2391      *          2) branch number   - find head of branch
2392      */
2393
2394     /* strip trailing dots */
2395     while (tag[strlen (tag) - 1] == '.')
2396         tag[strlen (tag) - 1] = '\0';
2397
2398     if ((numdots (tag) & 1) == 0)
2399     {
2400         char *branch;
2401
2402         /* we have a branch tag, so we need to walk the branch */
2403         branch = RCS_getbranch (rcs, tag, force_tag_match);
2404         free (tag);
2405         return branch;
2406     }
2407     else
2408     {
2409         Node *p;
2410
2411         /* we have a revision tag, so make sure it exists */
2412         p = findnode (rcs->versions, tag);
2413         if (p != NULL)
2414         {
2415             /* We have found a numeric revision for the revision tag.
2416                To support expanding the RCS keyword Name, if
2417                SIMPLE_TAG is not NULL, tell the the caller that this
2418                is a simple tag which co will recognize.  FIXME: Are
2419                there other cases in which we should set this?  In
2420                particular, what if we expand RCS keywords internally
2421                without calling co?  */
2422             if (simple_tag != NULL)
2423                 *simple_tag = 1;
2424             return tag;
2425         }
2426         else
2427         {
2428             /* The revision wasn't there, so return the head or NULL */
2429             free (tag);
2430             if (force_tag_match)
2431                 return NULL;
2432             else
2433                 return RCS_head (rcs);
2434         }
2435     }
2436 }
2437
2438
2439
2440 /*
2441  * Return a "magic" revision as a virtual branch off of REV for the RCS file.
2442  * A "magic" revision is one which is unique in the RCS file.  By unique, I
2443  * mean we return a revision which:
2444  *      - has a branch of 0 (see rcs.h RCS_MAGIC_BRANCH)
2445  *      - has a revision component which is not an existing branch off REV
2446  *      - has a revision component which is not an existing magic revision
2447  *      - is an even-numbered revision, to avoid conflicts with vendor branches
2448  * The first point is what makes it "magic".
2449  *
2450  * As an example, if we pass in 1.37 as REV, we will look for an existing
2451  * branch called 1.37.2.  If it did not exist, we would look for an
2452  * existing symbolic tag with a numeric part equal to 1.37.0.2.  If that
2453  * didn't exist, then we know that the 1.37.2 branch can be reserved by
2454  * creating a symbolic tag with 1.37.0.2 as the numeric part.
2455  *
2456  * This allows us to fork development with very little overhead -- just a
2457  * symbolic tag is used in the RCS file.  When a commit is done, a physical
2458  * branch is dynamically created to hold the new revision.
2459  *
2460  * Note: We assume that REV is an RCS revision and not a branch number.
2461  */
2462 static char *check_rev;
2463 char *
2464 RCS_magicrev (RCSNode *rcs, char *rev)
2465 {
2466     int rev_num;
2467     char *xrev, *test_branch, *local_branch_num;
2468
2469     xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */
2470     check_rev = xrev;
2471
2472     local_branch_num = getenv("CVS_LOCAL_BRANCH_NUM");
2473     if (local_branch_num)
2474     {
2475       rev_num = atoi(local_branch_num);
2476       if (rev_num < 2)
2477         rev_num = 2;
2478       else
2479         rev_num &= ~1;
2480     }
2481     else
2482       rev_num = 2;
2483
2484     /* only look at even numbered branches */
2485     for ( ; ; rev_num += 2)
2486     {
2487         /* see if the physical branch exists */
2488         (void) sprintf (xrev, "%s.%d", rev, rev_num);
2489         test_branch = RCS_getbranch (rcs, xrev, 1);
2490         if (test_branch != NULL)        /* it did, so keep looking */
2491         {
2492             free (test_branch);
2493             continue;
2494         }
2495
2496         /* now, create a "magic" revision */
2497         (void) sprintf (xrev, "%s.%d.%d", rev, RCS_MAGIC_BRANCH, rev_num);
2498
2499         /* walk the symbols list to see if a magic one already exists */
2500         if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0)
2501             continue;
2502
2503         /* we found a free magic branch.  Claim it as ours */
2504         return xrev;
2505     }
2506 }
2507
2508
2509
2510 /*
2511  * walklist proc to look for a match in the symbols list.
2512  * Returns 0 if the symbol does not match, 1 if it does.
2513  */
2514 static int
2515 checkmagic_proc (Node *p, void *closure)
2516 {
2517     if (STREQ (check_rev, p->data))
2518         return 1;
2519     else
2520         return 0;
2521 }
2522
2523
2524
2525 /*
2526  * Given an RCSNode, returns non-zero if the specified revision number 
2527  * or symbolic tag resolves to a "branch" within the rcs file.
2528  *
2529  * FIXME: this is the same as RCS_nodeisbranch except for the special 
2530  *        case for handling a null rcsnode.
2531  */
2532 int
2533 RCS_isbranch (RCSNode *rcs, const char *rev)
2534 {
2535     /* numeric revisions are easy -- even number of dots is a branch */
2536     if (isdigit ((unsigned char) *rev))
2537         return (numdots (rev) & 1) == 0;
2538
2539     /* assume a revision if you can't find the RCS info */
2540     if (rcs == NULL)
2541         return 0;
2542
2543     /* now, look for a match in the symbols list */
2544     return RCS_nodeisbranch (rcs, rev);
2545 }
2546
2547
2548
2549 /*
2550  * Given an RCSNode, returns non-zero if the specified revision number
2551  * or symbolic tag resolves to a "branch" within the rcs file.  We do
2552  * take into account any magic branches as well.
2553  */
2554 int
2555 RCS_nodeisbranch (RCSNode *rcs, const char *rev)
2556 {
2557     int dots;
2558     char *version;
2559
2560     assert (rcs != NULL);
2561
2562     /* numeric revisions are easy -- even number of dots is a branch */
2563     if (isdigit ((unsigned char) *rev))
2564         return (numdots (rev) & 1) == 0;
2565
2566     version = translate_symtag (rcs, rev);
2567     if (version == NULL)
2568         return 0;
2569     dots = numdots (version);
2570     if ((dots & 1) == 0)
2571     {
2572         free (version);
2573         return 1;
2574     }
2575
2576     /* got a symbolic tag match, but it's not a branch; see if it's magic */
2577     if (dots > 2)
2578     {
2579         char *magic;
2580         char *branch = strrchr (version, '.');
2581         char *cp = branch - 1;
2582         while (*cp != '.')
2583             cp--;
2584
2585         /* see if we have .magic-branch. (".0.") */
2586         magic = Xasprintf (".%d.", RCS_MAGIC_BRANCH);
2587         if (strncmp (magic, cp, strlen (magic)) == 0)
2588         {
2589             free (magic);
2590             free (version);
2591             return 1;
2592         }
2593         free (magic);
2594     }
2595     free (version);
2596     return 0;
2597 }
2598
2599
2600
2601 /*
2602  * Returns a pointer to malloc'ed memory which contains the branch
2603  * for the specified *symbolic* tag.  Magic branches are handled correctly.
2604  */
2605 char *
2606 RCS_whatbranch (RCSNode *rcs, const char *rev)
2607 {
2608     char *version;
2609     int dots;
2610
2611     /* assume no branch if you can't find the RCS info */
2612     if (rcs == NULL)
2613         return NULL;
2614
2615     /* now, look for a match in the symbols list */
2616     version = translate_symtag (rcs, rev);
2617     if (version == NULL)
2618         return NULL;
2619     dots = numdots (version);
2620     if ((dots & 1) == 0)
2621         return version;
2622
2623     /* got a symbolic tag match, but it's not a branch; see if it's magic */
2624     if (dots > 2)
2625     {
2626         char *magic;
2627         char *branch = strrchr (version, '.');
2628         char *cp = branch++ - 1;
2629         while (*cp != '.')
2630             cp--;
2631
2632         /* see if we have .magic-branch. (".0.") */
2633         magic = xmalloc (strlen (version) + 1);
2634         (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH);
2635         if (strncmp (magic, cp, strlen (magic)) == 0)
2636         {
2637             /* yep.  it's magic.  now, construct the real branch */
2638             *cp = '\0';                 /* turn it into a revision */
2639             (void) sprintf (magic, "%s.%s", version, branch);
2640             free (version);
2641             return magic;
2642         }
2643         free (magic);
2644     }
2645     free (version);
2646     return NULL;
2647 }
2648
2649
2650
2651 /*
2652  * Get the head of the specified branch.  If the branch does not exist,
2653  * return NULL or RCS_head depending on force_tag_match.
2654  * Returns NULL or a newly malloc'd string.
2655  */
2656 char *
2657 RCS_getbranch (RCSNode *rcs, const char *tag, int force_tag_match)
2658 {
2659     Node *p, *head;
2660     RCSVers *vn;
2661     char *xtag;
2662     char *nextvers;
2663     char *cp;
2664
2665     /* make sure we have something to look at... */
2666     assert (rcs != NULL);
2667
2668     if (rcs->flags & PARTIAL)
2669         RCS_reparsercsfile (rcs, NULL, NULL);
2670
2671     /* find out if the tag contains a dot, or is on the trunk */
2672     cp = strrchr (tag, '.');
2673
2674     /* trunk processing is the special case */
2675     if (cp == NULL)
2676     {
2677         xtag = Xasprintf ("%s.", tag);
2678         for (cp = rcs->head; cp != NULL;)
2679         {
2680             if (strncmp (xtag, cp, strlen (xtag)) == 0)
2681                 break;
2682             p = findnode (rcs->versions, cp);
2683             if (p == NULL)
2684             {
2685                 free (xtag);
2686                 if (force_tag_match)
2687                     return NULL;
2688                 else
2689                     return RCS_head (rcs);
2690             }
2691             vn = p->data;
2692             cp = vn->next;
2693         }
2694         free (xtag);
2695         if (cp == NULL)
2696         {
2697             if (force_tag_match)
2698                 return NULL;
2699             else
2700                 return RCS_head (rcs);
2701         }
2702         return xstrdup (cp);
2703     }
2704
2705     /* if it had a `.', terminate the string so we have the base revision */
2706     *cp = '\0';
2707
2708     /* look up the revision this branch is based on */
2709     p = findnode (rcs->versions, tag);
2710
2711     /* put the . back so we have the branch again */
2712     *cp = '.';
2713
2714     if (p == NULL)
2715     {
2716         /* if the base revision didn't exist, return head or NULL */
2717         if (force_tag_match)
2718             return NULL;
2719         else
2720             return RCS_head (rcs);
2721     }
2722
2723     /* find the first element of the branch we are looking for */
2724     vn = p->data;
2725     if (vn->branches == NULL)
2726         return NULL;
2727     xtag = Xasprintf ("%s.", tag);
2728     head = vn->branches->list;
2729     for (p = head->next; p != head; p = p->next)
2730         if (strncmp (p->key, xtag, strlen (xtag)) == 0)
2731             break;
2732     free (xtag);
2733
2734     if (p == head)
2735     {
2736         /* we didn't find a match so return head or NULL */
2737         if (force_tag_match)
2738             return NULL;
2739         else
2740             return RCS_head (rcs);
2741     }
2742
2743     /* now walk the next pointers of the branch */
2744     nextvers = p->key;
2745     do
2746     {
2747         p = findnode (rcs->versions, nextvers);
2748         if (p == NULL)
2749         {
2750             /* a link in the chain is missing - return head or NULL */
2751             if (force_tag_match)
2752                 return NULL;
2753             else
2754                 return RCS_head (rcs);
2755         }
2756         vn = p->data;
2757         nextvers = vn->next;
2758     } while (nextvers != NULL);
2759
2760     /* we have the version in our hand, so go for it */
2761     return xstrdup (vn->version);
2762 }
2763
2764
2765
2766 /* Returns the head of the branch which REV is on.  REV can be a
2767    branch tag or non-branch tag; symbolic or numeric.
2768
2769    Returns a newly malloc'd string.  Returns NULL if a symbolic name
2770    isn't found.  */
2771 char *
2772 RCS_branch_head (RCSNode *rcs, char *rev)
2773 {
2774     char *num;
2775     char *br;
2776     char *retval;
2777
2778     assert (rcs != NULL);
2779
2780     if (RCS_nodeisbranch (rcs, rev))
2781         return RCS_getbranch (rcs, rev, 1);
2782
2783     if (isdigit ((unsigned char) *rev))
2784         num = xstrdup (rev);
2785     else
2786     {
2787         num = translate_symtag (rcs, rev);
2788         if (num == NULL)
2789             return NULL;
2790     }
2791     br = truncate_revnum (num);
2792     retval = RCS_getbranch (rcs, br, 1);
2793     free (br);
2794     free (num);
2795     return retval;
2796 }
2797
2798
2799
2800 /* Get the branch point for a particular branch, that is the first
2801    revision on that branch.  For example, RCS_getbranchpoint (rcs,
2802    "1.3.2") will normally return "1.3.2.1".  TARGET may be either a
2803    branch number or a revision number; if a revnum, find the
2804    branchpoint of the branch to which TARGET belongs.
2805
2806    Return RCS_head if TARGET is on the trunk or if the root node could
2807    not be found (this is sort of backwards from our behavior on a branch;
2808    the rationale is that the return value is a revision from which you
2809    can start walking the next fields and end up at TARGET).
2810    Return NULL on error.  */
2811 static char *
2812 RCS_getbranchpoint (RCSNode *rcs, char *target)
2813 {
2814     char *branch, *bp;
2815     Node *vp;
2816     RCSVers *rev;
2817     int dots, isrevnum, brlen;
2818
2819     dots = numdots (target);
2820     isrevnum = dots & 1;
2821
2822     if (dots == 1)
2823         /* TARGET is a trunk revision; return rcs->head. */
2824         return RCS_head (rcs);
2825
2826     /* Get the revision number of the node at which TARGET's branch is
2827        rooted.  If TARGET is a branch number, lop off the last field;
2828        if it's a revision number, lop off the last *two* fields. */
2829     branch = xstrdup (target);
2830     bp = strrchr (branch, '.');
2831     if (bp == NULL)
2832         error (1, 0, "%s: confused revision number %s",
2833                rcs->print_path, target);
2834     if (isrevnum)
2835         while (*--bp != '.')
2836             ;
2837     *bp = '\0';
2838
2839     vp = findnode (rcs->versions, branch);
2840     if (vp == NULL)
2841     {   
2842         error (0, 0, "%s: can't find branch point %s", rcs->print_path, target);
2843         free (branch);
2844         return NULL;
2845     }
2846     rev = vp->data;
2847
2848     *bp++ = '.';
2849     while (*bp && *bp != '.')
2850         ++bp;
2851     brlen = bp - branch;
2852
2853     vp = rev->branches->list->next;
2854     while (vp != rev->branches->list)
2855     {
2856         /* BRANCH may be a genuine branch number, e.g. `1.1.3', or
2857            maybe a full revision number, e.g. `1.1.3.6'.  We have
2858            found our branch point if the first BRANCHLEN characters
2859            of the revision number match, *and* if the following
2860            character is a dot. */
2861         if (strncmp (vp->key, branch, brlen) == 0 && vp->key[brlen] == '.')
2862             break;
2863         vp = vp->next;
2864     }
2865
2866     free (branch);
2867     if (vp == rev->branches->list)
2868     {
2869         error (0, 0, "%s: can't find branch point %s", rcs->print_path, target);
2870         return NULL;
2871     }
2872     else
2873         return xstrdup (vp->key);
2874 }
2875
2876
2877
2878 /*
2879  * Get the head of the RCS file.  If branch is set, this is the head of the
2880  * branch, otherwise the real head.
2881  *
2882  * INPUTS
2883  *   rcs        The parsed rcs node information.
2884  *
2885  * RETURNS
2886  *   NULL when rcs->branch exists and cannot be found.
2887  *   A newly malloc'd string, otherwise.
2888  */
2889 char *
2890 RCS_head (RCSNode *rcs)
2891 {
2892     /* make sure we have something to look at... */
2893     assert (rcs);
2894
2895     /*
2896      * NOTE: we call getbranch with force_tag_match set to avoid any
2897      * possibility of recursion
2898      */
2899     if (rcs->branch)
2900         return RCS_getbranch (rcs, rcs->branch, 1);
2901     else
2902         return xstrdup (rcs->head);
2903 }
2904
2905
2906
2907 /*
2908  * Get the most recent revision, based on the supplied date, but use some
2909  * funky stuff and follow the vendor branch maybe
2910  */
2911 char *
2912 RCS_getdate (RCSNode *rcs, const char *date, int force_tag_match)
2913 {
2914     char *cur_rev = NULL;
2915     char *retval = NULL;
2916     Node *p;
2917     RCSVers *vers = NULL;
2918
2919     /* make sure we have something to look at... */
2920     assert (rcs != NULL);
2921
2922     if (rcs->flags & PARTIAL)
2923         RCS_reparsercsfile (rcs, NULL, NULL);
2924
2925     /* if the head is on a branch, try the branch first */
2926     if (rcs->branch != NULL)
2927     {
2928         retval = RCS_getdatebranch (rcs, date, rcs->branch);
2929         if (retval != NULL)
2930             return retval;
2931     }
2932
2933     /* otherwise if we have a trunk, try it */
2934     if (rcs->head)
2935     {
2936         p = findnode (rcs->versions, rcs->head);
2937         if (p == NULL)
2938         {
2939             error (0, 0, "%s: head revision %s doesn't exist", rcs->print_path,
2940                    rcs->head);
2941         }
2942         while (p != NULL)
2943         {
2944             /* if the date of this one is before date, take it */
2945             vers = p->data;
2946             if (RCS_datecmp (vers->date, date) <= 0)
2947             {
2948                 cur_rev = vers->version;
2949                 break;
2950             }
2951
2952             /* if there is a next version, find the node */
2953             if (vers->next != NULL)
2954                 p = findnode (rcs->versions, vers->next);
2955             else
2956                 p = NULL;
2957         }
2958     }
2959     else
2960         error (0, 0, "%s: no head revision", rcs->print_path);
2961
2962     /*
2963      * at this point, either we have the revision we want, or we have the
2964      * first revision on the trunk (1.1?) in our hands, or we've come up
2965      * completely empty
2966      */
2967
2968     /* if we found what we're looking for, and it's not 1.1 return it */
2969     if (cur_rev != NULL)
2970     {
2971         if (! STREQ (cur_rev, "1.1"))
2972             return xstrdup (cur_rev);
2973
2974         /* This is 1.1;  if the date of 1.1 is not the same as that for the
2975            1.1.1.1 version, then return 1.1.  This happens when the first
2976            version of a file is created by a regular cvs add and commit,
2977            and there is a subsequent cvs import of the same file.  */
2978         p = findnode (rcs->versions, "1.1.1.1");
2979         if (p)
2980         {
2981             char *date_1_1 = vers->date;
2982
2983             vers = p->data;
2984             if (RCS_datecmp (vers->date, date_1_1) != 0)
2985                 return xstrdup ("1.1");
2986         }
2987     }
2988
2989     /* look on the vendor branch */
2990     retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
2991
2992     /*
2993      * if we found a match, return it; otherwise, we return the first
2994      * revision on the trunk or NULL depending on force_tag_match and the
2995      * date of the first rev
2996      */
2997     if (retval != NULL)
2998         return retval;
2999
3000     if (vers && (!force_tag_match || RCS_datecmp (vers->date, date) <= 0))
3001         return xstrdup (vers->version);
3002     else
3003         return NULL;
3004 }
3005
3006
3007
3008 /*
3009  * Look up the last element on a branch that was put in before or on
3010  * the specified date and time (return the rev or NULL)
3011  */
3012 static char *
3013 RCS_getdatebranch (RCSNode *rcs, const char *date, const char *branch)
3014 {
3015     char *cur_rev = NULL;
3016     char *cp;
3017     char *xbranch, *xrev;
3018     Node *p;
3019     RCSVers *vers;
3020
3021     /* look up the first revision on the branch */
3022     xrev = xstrdup (branch);
3023     cp = strrchr (xrev, '.');
3024     if (cp == NULL)
3025     {
3026         free (xrev);
3027         return NULL;
3028     }
3029     *cp = '\0';                         /* turn it into a revision */
3030
3031     assert (rcs != NULL);
3032
3033     if (rcs->flags & PARTIAL)
3034         RCS_reparsercsfile (rcs, NULL, NULL);
3035
3036     p = findnode (rcs->versions, xrev);
3037     free (xrev);
3038     if (p == NULL)
3039         return NULL;
3040     vers = p->data;
3041
3042     /* Tentatively use this revision, if it is early enough.  */
3043     if (RCS_datecmp (vers->date, date) <= 0)
3044         cur_rev = vers->version;
3045
3046     /* If no branches list, return now.  This is what happens if the branch
3047        is a (magic) branch with no revisions yet.  */
3048     if (vers->branches == NULL)
3049         return xstrdup (cur_rev);
3050
3051     /* walk the branches list looking for the branch number */
3052     xbranch = Xasprintf ("%s.", branch);
3053     for (p = vers->branches->list->next; p != vers->branches->list; p = p->next)
3054         if (strncmp (p->key, xbranch, strlen (xbranch)) == 0)
3055             break;
3056     free (xbranch);
3057     if (p == vers->branches->list)
3058     {
3059         /* This is what happens if the branch is a (magic) branch with
3060            no revisions yet.  Similar to the case where vers->branches ==
3061            NULL, except here there was a another branch off the same
3062            branchpoint.  */
3063         return xstrdup (cur_rev);
3064     }
3065
3066     p = findnode (rcs->versions, p->key);
3067
3068     /* walk the next pointers until you find the end, or the date is too late */
3069     while (p != NULL)
3070     {
3071         vers = p->data;
3072         if (RCS_datecmp (vers->date, date) <= 0)
3073             cur_rev = vers->version;
3074         else
3075             break;
3076
3077         /* if there is a next version, find the node */
3078         if (vers->next != NULL)
3079             p = findnode (rcs->versions, vers->next);
3080         else
3081             p = NULL;
3082     }
3083
3084     /* Return whatever we found, which may be NULL.  */
3085     return xstrdup (cur_rev);
3086 }
3087
3088
3089
3090 /*
3091  * Compare two dates in RCS format. Beware the change in format on January 1,
3092  * 2000, when years go from 2-digit to full format.
3093  */
3094 int
3095 RCS_datecmp (const char *date1, const char *date2)
3096 {
3097     int length_diff = strlen (date1) - strlen (date2);
3098
3099     return length_diff ? length_diff : strcmp (date1, date2);
3100 }
3101
3102
3103
3104 /* Look up revision REV in RCS and return the date specified for the
3105    revision minus FUDGE seconds (FUDGE will generally be one, so that the
3106    logically previous revision will be found later, or zero, if we want
3107    the exact date).
3108
3109    The return value is the date being returned as a time_t, or (time_t)-1
3110    on error (previously was documented as zero on error; I haven't checked
3111    the callers to make sure that they really check for (time_t)-1, but
3112    the latter is what this function really returns).  If DATE is non-NULL,
3113    then it must point to MAXDATELEN characters, and we store the same
3114    return value there in DATEFORM format.  */
3115 time_t
3116 RCS_getrevtime (RCSNode *rcs, const char *rev, char *date, int fudge)
3117 {
3118     char *tdate;
3119     struct tm xtm, *ftm;
3120     struct timespec revdate;
3121     Node *p;
3122     RCSVers *vers;
3123
3124     /* make sure we have something to look at... */
3125     assert (rcs != NULL);
3126
3127     if (rcs->flags & PARTIAL)
3128         RCS_reparsercsfile (rcs, NULL, NULL);
3129
3130     /* look up the revision */
3131     p = findnode (rcs->versions, rev);
3132     if (p == NULL)
3133         return -1;
3134     vers = p->data;
3135
3136     /* split up the date */
3137     if (sscanf (vers->date, SDATEFORM, &xtm.tm_year, &xtm.tm_mon,
3138                 &xtm.tm_mday, &xtm.tm_hour, &xtm.tm_min, &xtm.tm_sec) != 6)
3139         error (1, 0, "%s: invalid date for revision %s (%s)", rcs->print_path,
3140                rev, vers->date);
3141
3142     /* If the year is from 1900 to 1999, RCS files contain only two
3143        digits, and sscanf gives us a year from 0-99.  If the year is
3144        2000+, RCS files contain all four digits and we subtract 1900,
3145        because the tm_year field should contain years since 1900.  */
3146
3147     if (xtm.tm_year >= 100 && xtm.tm_year < 2000)
3148         error (0, 0, "%s: non-standard date format for revision %s (%s)",
3149                rcs->print_path, rev, vers->date);
3150     if (xtm.tm_year >= 1900)
3151         xtm.tm_year -= 1900;
3152
3153     /* put the date in a form getdate can grok */
3154     tdate = Xasprintf ("%d-%d-%d %d:%d:%d -0000",
3155                        xtm.tm_year + 1900, xtm.tm_mon, xtm.tm_mday,
3156                        xtm.tm_hour, xtm.tm_min, xtm.tm_sec);
3157
3158     /* Turn it into seconds since the epoch.
3159      *
3160      * We use a struct timespec since that is what getdate requires, then
3161      * truncate the nanoseconds.
3162      */
3163     if (!get_date (&revdate, tdate, NULL))
3164     {
3165         free (tdate);
3166         return (time_t)-1;
3167     }
3168     free (tdate);
3169
3170     revdate.tv_sec -= fudge;    /* remove "fudge" seconds */
3171     if (date)
3172     {
3173         /* Put an appropriate string into `date', if we were given one. */
3174         ftm = gmtime (&revdate.tv_sec);
3175         (void) sprintf (date, DATEFORM,
3176                         ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
3177                         ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
3178                         ftm->tm_min, ftm->tm_sec);
3179     }
3180
3181     return revdate.tv_sec;
3182 }
3183
3184
3185
3186 List *
3187 RCS_getlocks (RCSNode *rcs)
3188 {
3189     assert(rcs != NULL);
3190
3191     if (rcs->flags & PARTIAL)
3192         RCS_reparsercsfile (rcs, NULL, NULL);
3193
3194     if (rcs->locks_data) {
3195         rcs->locks = getlist ();
3196         do_locks (rcs->locks, rcs->locks_data);
3197         free(rcs->locks_data);
3198         rcs->locks_data = NULL;
3199     }
3200
3201     return rcs->locks;
3202 }
3203
3204
3205
3206 List *
3207 RCS_symbols(RCSNode *rcs)
3208 {
3209     assert(rcs != NULL);
3210
3211     if (rcs->flags & PARTIAL)
3212         RCS_reparsercsfile (rcs, NULL, NULL);
3213
3214     if (rcs->symbols_data) {
3215         rcs->symbols = getlist ();
3216         do_symbols (rcs->symbols, rcs->symbols_data);
3217         free(rcs->symbols_data);
3218         rcs->symbols_data = NULL;
3219     }
3220
3221     return rcs->symbols;
3222 }
3223
3224
3225
3226 /*
3227  * Return the version associated with a particular symbolic tag.
3228  * Returns NULL or a newly malloc'd string.
3229  */
3230 static char *
3231 translate_symtag (RCSNode *rcs, const char *tag)
3232 {
3233     if (rcs->flags & PARTIAL)
3234         RCS_reparsercsfile (rcs, NULL, NULL);
3235
3236     if (rcs->symbols != NULL)
3237     {
3238         Node *p;
3239
3240         /* The symbols have already been converted into a list.  */
3241         p = findnode (rcs->symbols, tag);
3242         if (p == NULL)
3243             return NULL;
3244
3245         return xstrdup (p->data);
3246     }
3247
3248     if (rcs->symbols_data != NULL)
3249     {
3250         size_t len;
3251         char *cp, *last;
3252
3253         /* Look through the RCS symbols information.  This is like
3254            do_symbols, but we don't add the information to a list.  In
3255            most cases, we will only be called once for this file, so
3256            generating the list is unnecessary overhead.  */
3257
3258         len = strlen (tag);
3259         cp = rcs->symbols_data;
3260         /* Keeping track of LAST below isn't strictly necessary, now that tags
3261          * should be parsed for validity before they are accepted, but tags
3262          * with spaces used to cause the code below to loop indefintely, so
3263          * I have corrected for that.  Now, in the event that I missed
3264          * something, the server cannot be hung.  -DRP
3265          */
3266         last = NULL;
3267         while ((cp = strchr (cp, tag[0])) != NULL)
3268         {
3269             if (cp == last) break;
3270             if ((cp == rcs->symbols_data || whitespace (cp[-1]))
3271                 && strncmp (cp, tag, len) == 0
3272                 && cp[len] == ':')
3273             {
3274                 char *v, *r;
3275
3276                 /* We found the tag.  Return the version number.  */
3277
3278                 cp += len + 1;
3279                 v = cp;
3280                 while (! whitespace (*cp) && *cp != '\0')
3281                     ++cp;
3282                 r = xmalloc (cp - v + 1);
3283                 strncpy (r, v, cp - v);
3284                 r[cp - v] = '\0';
3285                 return r;
3286             }
3287
3288             while (! whitespace (*cp) && *cp != '\0')
3289                 ++cp;
3290             if (*cp == '\0')
3291                 break;
3292             last = cp;
3293         }
3294     }
3295
3296     return NULL;
3297 }
3298
3299
3300
3301 /*
3302  * The argument ARG is the getopt remainder of the -k option specified on the
3303  * command line.  This function returns malloc'ed space that can be used
3304  * directly in calls to RCS V5, with the -k flag munged correctly.
3305  */
3306 char *
3307 RCS_check_kflag (const char *arg)
3308 {
3309     static const char *const  keyword_usage[] =
3310     {
3311       "%s %s: invalid RCS keyword expansion mode\n",
3312       "Valid expansion modes include:\n",
3313       "   -kkv\tGenerate keywords using the default form.\n",
3314       "   -kkvl\tLike -kkv, except locker's name inserted.\n",
3315       "   -kk\tGenerate only keyword names in keyword strings.\n",
3316       "   -kv\tGenerate only keyword values in keyword strings.\n",
3317       "   -ko\tGenerate the old keyword string (no changes from checked in file).\n",
3318       "   -kb\tGenerate binary file unmodified (merges not allowed) (RCS 5.7).\n",
3319       "(Specify the --help global option for a list of other help options)\n",
3320       NULL,
3321     };
3322     char const *const *cpp = NULL;
3323
3324     if (arg)
3325     {
3326         for (cpp = kflags; *cpp != NULL; cpp++)
3327         {
3328             if (STREQ (arg, *cpp))
3329                 break;
3330         }
3331     }
3332
3333     if (arg == NULL || *cpp == NULL)
3334     {
3335         usage (keyword_usage);
3336     }
3337
3338     return Xasprintf ("-k%s", *cpp);
3339 }
3340
3341
3342
3343 /*
3344  * Do some consistency checks on the symbolic tag... These should equate
3345  * pretty close to what RCS checks, though I don't know for certain.
3346  */
3347 void
3348 RCS_check_tag (const char *tag)
3349 {
3350     char *invalid = "$,.:;@";           /* invalid RCS tag characters */
3351     const char *cp;
3352
3353     /*
3354      * The first character must be an alphabetic letter. The remaining
3355      * characters cannot be non-visible graphic characters, and must not be
3356      * in the set of "invalid" RCS identifier characters.
3357      */
3358     if (isalpha ((unsigned char) *tag))
3359     {
3360         for (cp = tag; *cp; cp++)
3361         {
3362             if (!isgraph ((unsigned char) *cp))
3363                 error (1, 0, "tag `%s' has non-visible graphic characters",
3364                        tag);
3365             if (strchr (invalid, *cp))
3366                 error (1, 0, "tag `%s' must not contain the characters `%s'",
3367                        tag, invalid);
3368         }
3369     }
3370     else
3371         error (1, 0, "tag `%s' must start with a letter", tag);
3372 }
3373
3374
3375
3376 /*
3377  * TRUE if argument has valid syntax for an RCS revision or 
3378  * branch number.  All characters must be digits or dots, first 
3379  * and last characters must be digits, and no two consecutive 
3380  * characters may be dots.
3381  *
3382  * Intended for classifying things, so this function doesn't 
3383  * call error.
3384  */
3385 int 
3386 RCS_valid_rev (const char *rev)
3387 {
3388    char last, c;
3389    last = *rev++;
3390    if (!isdigit ((unsigned char) last))
3391        return 0;
3392    while ((c = *rev++))   /* Extra parens placate -Wall gcc option */
3393    {
3394        if (c == '.')
3395        {
3396            if (last == '.')
3397                return 0;
3398            continue;
3399        }
3400        last = c;
3401        if (!isdigit ((unsigned char) c))
3402            return 0;
3403    }
3404    if (!isdigit ((unsigned char) last))
3405        return 0;
3406    return 1;
3407 }
3408
3409
3410
3411 /*
3412  * Return true if RCS revision with TAG is a dead revision.
3413  */
3414 int
3415 RCS_isdead (RCSNode *rcs, const char *tag)
3416 {
3417     Node *p;
3418     RCSVers *version;
3419
3420     if (rcs->flags & PARTIAL)
3421         RCS_reparsercsfile (rcs, NULL, NULL);
3422
3423     p = findnode (rcs->versions, tag);
3424     if (p == NULL)
3425         return 0;
3426
3427     version = p->data;
3428     return version->dead;
3429 }
3430
3431
3432
3433 /* Return the RCS keyword expansion mode.  For example "b" for binary.
3434    Returns a pointer into storage which is allocated and freed along with
3435    the rest of the RCS information; the caller should not modify this
3436    storage.  Returns NULL if the RCS file does not specify a keyword
3437    expansion mode; for all other errors, die with a fatal error.  */
3438 char *
3439 RCS_getexpand (RCSNode *rcs)
3440 {
3441     /* Since RCS_parsercsfile_i now reads expand, don't need to worry
3442        about RCS_reparsercsfile.  */
3443     assert (rcs != NULL);
3444     return rcs->expand;
3445 }
3446
3447
3448
3449 /* Set keyword expansion mode to EXPAND.  For example "b" for binary.  */
3450 void
3451 RCS_setexpand (RCSNode *rcs, const char *expand)
3452 {
3453     /* Since RCS_parsercsfile_i now reads expand, don't need to worry
3454        about RCS_reparsercsfile.  */
3455     assert (rcs != NULL);
3456     if (rcs->expand != NULL)
3457         free (rcs->expand);
3458     rcs->expand = xstrdup (expand);
3459 }
3460
3461
3462
3463 /* RCS keywords, and a matching enum.  */
3464 enum keyword
3465 {
3466     KEYWORD_AUTHOR = 0,
3467     KEYWORD_DATE,
3468     KEYWORD_CVSHEADER,
3469     KEYWORD_HEADER,
3470     KEYWORD_ID,
3471     KEYWORD_LOCKER,
3472     KEYWORD_LOG,
3473     KEYWORD_NAME,
3474     KEYWORD_RCSFILE,
3475     KEYWORD_REVISION,
3476     KEYWORD_SOURCE,
3477     KEYWORD_STATE,
3478     KEYWORD_LOCALID
3479 };
3480 struct rcs_keyword
3481 {
3482     const char *string;
3483     size_t len;
3484     enum keyword expandto;
3485     bool expandit;
3486 };
3487
3488
3489
3490 static inline struct rcs_keyword *
3491 new_keywords (void)
3492 {
3493     struct rcs_keyword *new;
3494     new = xcalloc (KEYWORD_LOCALID + 2, sizeof (struct rcs_keyword));
3495
3496 #define KEYWORD_INIT(k, i, s) \
3497         k[i].string = s; \
3498         k[i].len = sizeof s - 1; \
3499         k[i].expandto = i; \
3500         k[i].expandit = true
3501
3502     KEYWORD_INIT (new, KEYWORD_AUTHOR, "Author");
3503     KEYWORD_INIT (new, KEYWORD_DATE, "Date");
3504     KEYWORD_INIT (new, KEYWORD_CVSHEADER, "CVSHeader");
3505     KEYWORD_INIT (new, KEYWORD_HEADER, "Header");
3506     KEYWORD_INIT (new, KEYWORD_ID, "Id");
3507     KEYWORD_INIT (new, KEYWORD_LOCKER, "Locker");
3508     KEYWORD_INIT (new, KEYWORD_LOG, "Log");
3509     KEYWORD_INIT (new, KEYWORD_NAME, "Name");
3510     KEYWORD_INIT (new, KEYWORD_RCSFILE, "RCSfile");
3511     KEYWORD_INIT (new, KEYWORD_REVISION, "Revision");
3512     KEYWORD_INIT (new, KEYWORD_SOURCE, "Source");
3513     KEYWORD_INIT (new, KEYWORD_STATE, "State");
3514
3515     return new;
3516 }
3517
3518
3519
3520 void
3521 free_keywords (void *keywords)
3522 {
3523     free (keywords);
3524 }
3525
3526
3527
3528 /* Convert an RCS date string into a readable string.  This is like
3529    the RCS date2str function.  */
3530 static char *
3531 printable_date (const char *rcs_date)
3532 {
3533     int year, mon, mday, hour, min, sec;
3534     char buf[100];
3535
3536     (void) sscanf (rcs_date, SDATEFORM, &year, &mon, &mday, &hour, &min,
3537                    &sec);
3538     if (year < 1900)
3539         year += 1900;
3540     sprintf (buf, "%04d/%02d/%02d %02d:%02d:%02d", year, mon, mday,
3541              hour, min, sec);
3542     return xstrdup (buf);
3543 }
3544
3545
3546
3547 /* Escape the characters in a string so that it can be included in an
3548    RCS value.  */
3549 static char *
3550 escape_keyword_value (const char *value, int *free_value)
3551 {
3552     char *ret, *t;
3553     const char *s;
3554
3555     for (s = value; *s != '\0'; s++)
3556     {
3557         char c;
3558
3559         c = *s;
3560         if (c == '\t'
3561             || c == '\n'
3562             || c == '\\'
3563             || c == ' '
3564             || c == '$')
3565         {
3566             break;
3567         }
3568     }
3569
3570     if (*s == '\0')
3571     {
3572         *free_value = 0;
3573         return (char *) value;
3574     }
3575
3576     ret = xmalloc (strlen (value) * 4 + 1);
3577     *free_value = 1;
3578
3579     for (s = value, t = ret; *s != '\0'; s++, t++)
3580     {
3581         switch (*s)
3582         {
3583         default:
3584             *t = *s;
3585             break;
3586         case '\t':
3587             *t++ = '\\';
3588             *t = 't';
3589             break;
3590         case '\n':
3591             *t++ = '\\';
3592             *t = 'n';
3593             break;
3594         case '\\':
3595             *t++ = '\\';
3596             *t = '\\';
3597             break;
3598         case ' ':
3599             *t++ = '\\';
3600             *t++ = '0';
3601             *t++ = '4';
3602             *t = '0';
3603             break;
3604         case '$':
3605             *t++ = '\\';
3606             *t++ = '0';
3607             *t++ = '4';
3608             *t = '4';
3609             break;
3610         }
3611     }
3612
3613     *t = '\0';
3614
3615     return ret;
3616 }
3617
3618
3619
3620 /* Expand RCS keywords in the memory buffer BUF of length LEN.  This
3621    applies to file RCS and version VERS.  If NAME is not NULL, and is
3622    not a numeric revision, then it is the symbolic tag used for the
3623    checkout.  EXPAND indicates how to expand the keywords.  This
3624    function sets *RETBUF and *RETLEN to the new buffer and length.
3625    This function may modify the buffer BUF.  If BUF != *RETBUF, then
3626    RETBUF is a newly allocated buffer.  */
3627 static void
3628 expand_keywords (RCSNode *rcs, RCSVers *ver, const char *name, const char *log,
3629                  size_t loglen, enum kflag expand, char *buf, size_t len,
3630                  char **retbuf, size_t *retlen)
3631 {
3632     struct expand_buffer
3633     {
3634         struct expand_buffer *next;
3635         char *data;
3636         size_t len;
3637         int free_data;
3638     } *ebufs = NULL;
3639     struct expand_buffer *ebuf_last = NULL;
3640     size_t ebuf_len = 0;
3641     char *locker;
3642     char *srch, *srch_next;
3643     size_t srch_len;
3644     const struct rcs_keyword *keywords;
3645
3646     if (!config /* For `cvs init', config may not be set.  */
3647         ||expand == KFLAG_O || expand == KFLAG_B)
3648     {
3649         *retbuf = buf;
3650         *retlen = len;
3651         return;
3652     }
3653
3654     if (!config->keywords) config->keywords = new_keywords ();
3655     keywords = config->keywords;
3656
3657     /* If we are using -kkvl, dig out the locker information if any.  */
3658     locker = NULL;
3659     if (expand == KFLAG_KVL)
3660     {
3661         Node *lock;
3662         lock = findnode (RCS_getlocks(rcs), ver->version);
3663         if (lock != NULL)
3664             locker = xstrdup (lock->data);
3665     }
3666
3667     /* RCS keywords look like $STRING$ or $STRING: VALUE$.  */
3668     srch = buf;
3669     srch_len = len;
3670     while ((srch_next = memchr (srch, '$', srch_len)) != NULL)
3671     {
3672         char *s, *send;
3673         size_t slen;
3674         const struct rcs_keyword *keyword;
3675         char *value;
3676         int free_value;
3677         char *sub;
3678         size_t sublen;
3679
3680         srch_len -= (srch_next + 1) - srch;
3681         srch = srch_next + 1;
3682
3683         /* Look for the first non alphabetic character after the '$'.  */
3684         send = srch + srch_len;
3685         for (s = srch; s < send; s++)
3686             if (! isalpha ((unsigned char) *s))
3687                 break;
3688
3689         /* If the first non alphabetic character is not '$' or ':',
3690            then this is not an RCS keyword.  */
3691         if (s == send || (*s != '$' && *s != ':'))
3692             continue;
3693
3694         /* See if this is one of the keywords.  */
3695         slen = s - srch;
3696         for (keyword = keywords; keyword->string != NULL; keyword++)
3697         {
3698             if (keyword->expandit
3699                 && keyword->len == slen
3700                 && strncmp (keyword->string, srch, slen) == 0)
3701             {
3702                 break;
3703             }
3704         }
3705         if (keyword->string == NULL)
3706             continue;
3707
3708         /* If the keyword ends with a ':', then the old value consists
3709            of the characters up to the next '$'.  If there is no '$'
3710            before the end of the line, though, then this wasn't an RCS
3711            keyword after all.  */
3712         if (*s == ':')
3713         {
3714             for (; s < send; s++)
3715                 if (*s == '$' || *s == '\n')
3716                     break;
3717             if (s == send || *s != '$')
3718                 continue;
3719         }
3720
3721         /* At this point we must replace the string from SRCH to S
3722            with the expansion of the keyword KW.  */
3723
3724         /* Get the value to use.  */
3725         free_value = 0;
3726         if (expand == KFLAG_K)
3727             value = NULL;
3728         else
3729         {
3730             switch (keyword->expandto)
3731             {
3732             default:
3733                 assert (!"unreached");
3734
3735             case KEYWORD_AUTHOR:
3736                 value = ver->author;
3737                 break;
3738
3739             case KEYWORD_DATE:
3740                 value = printable_date (ver->date);
3741                 free_value = 1;
3742                 break;
3743
3744             case KEYWORD_CVSHEADER:
3745             case KEYWORD_HEADER:
3746             case KEYWORD_ID:
3747             case KEYWORD_LOCALID:
3748                 {
3749                     const char *path;
3750                     int free_path;
3751                     char *date;
3752                     char *old_path;
3753
3754                     old_path = NULL;
3755                     if (keyword->expandto == KEYWORD_HEADER)
3756                         path = rcs->print_path;
3757                     else if (keyword->expandto == KEYWORD_CVSHEADER)
3758                         path = getfullCVSname (rcs->print_path, &old_path);
3759                     else
3760                         path = last_component (rcs->print_path);
3761                     path = escape_keyword_value (path, &free_path);
3762                     date = printable_date (ver->date);
3763                     value = Xasprintf ("%s %s %s %s %s%s%s",
3764                                        path, ver->version, date, ver->author,
3765                                        ver->state,
3766                                        locker != NULL ? " " : "",
3767                                        locker != NULL ? locker : "");
3768                     if (free_path)
3769                         /* If free_path is set then we know we allocated path
3770                          * and we can discard the const.
3771                          */
3772                         free ((char *)path);
3773                     if (old_path)
3774                         free (old_path);
3775                     free (date);
3776                     free_value = 1;
3777                 }
3778                 break;
3779
3780             case KEYWORD_LOCKER:
3781                 value = locker;
3782                 break;
3783
3784             case KEYWORD_LOG:
3785             case KEYWORD_RCSFILE:
3786                 value = escape_keyword_value (last_component (rcs->print_path),
3787                                               &free_value);
3788                 break;
3789
3790             case KEYWORD_NAME:
3791                 if (name != NULL && ! isdigit ((unsigned char) *name))
3792                     value = (char *) name;
3793                 else
3794                     value = NULL;
3795                 break;
3796
3797             case KEYWORD_REVISION:
3798                 value = ver->version;
3799                 break;
3800
3801             case KEYWORD_SOURCE:
3802                 value = escape_keyword_value (rcs->print_path, &free_value);
3803                 break;
3804
3805             case KEYWORD_STATE:
3806                 value = ver->state;
3807                 break;
3808             }
3809         }
3810
3811         sub = xmalloc (keyword->len
3812                        + (value == NULL ? 0 : strlen (value))
3813                        + 10);
3814         if (expand == KFLAG_V)
3815         {
3816             /* Decrement SRCH and increment S to remove the $
3817                characters.  */
3818             --srch;
3819             ++srch_len;
3820             ++s;
3821             sublen = 0;
3822         }
3823         else
3824         {
3825             strcpy (sub, keyword->string);
3826             sublen = strlen (keyword->string);
3827             if (expand != KFLAG_K)
3828             {
3829                 sub[sublen] = ':';
3830                 sub[sublen + 1] = ' ';
3831                 sublen += 2;
3832             }
3833         }
3834         if (value != NULL)
3835         {
3836             strcpy (sub + sublen, value);
3837             sublen += strlen (value);
3838         }
3839         if (expand != KFLAG_V && expand != KFLAG_K)
3840         {
3841             sub[sublen] = ' ';
3842             ++sublen;
3843             sub[sublen] = '\0';
3844         }
3845
3846         if (free_value)
3847             free (value);
3848
3849         /* The Log keyword requires special handling.  This behaviour
3850            is taken from RCS 5.7.  The special log message is what RCS
3851            uses for ci -k.  */
3852         if (keyword->expandto == KEYWORD_LOG
3853             && (sizeof "checked in with -k by " <= loglen
3854                 || log == NULL
3855                 || strncmp (log, "checked in with -k by ",
3856                             sizeof "checked in with -k by " - 1) != 0))
3857         {
3858             char *start;
3859             char *leader;
3860             size_t leader_len, leader_sp_len;
3861             const char *logend;
3862             const char *snl;
3863             int cnl;
3864             char *date;
3865             const char *sl;
3866
3867             /* We are going to insert the trailing $ ourselves, before
3868                the log message, so we must remove it from S, if we
3869                haven't done so already.  */
3870             if (expand != KFLAG_V)
3871                 ++s;
3872
3873             /* CVS never has empty log messages, but old RCS files might.  */
3874             if (log == NULL)
3875                 log = "";
3876
3877             /* Find the start of the line.  */
3878             start = srch;
3879             leader_len = 0;
3880             while (start > buf && start[-1] != '\n'
3881                    && leader_len <= xsum (config->MaxCommentLeaderLength,
3882                                           expand != KFLAG_V ? 1 : 0))
3883             {
3884                 --start;
3885                 ++leader_len;
3886             }
3887
3888             if (expand != KFLAG_V)
3889                 /* When automagically determined and !KFLAG_V, we wish to avoid
3890                  * including the leading `$' of the Log keyword in our leader.
3891                  */
3892                 --leader_len;
3893
3894             /* If the automagically determined leader exceeds the limit set in
3895              * CVSROOT/config, try to use a fallback.
3896              */
3897             if (leader_len > config->MaxCommentLeaderLength)
3898             {
3899                 if (config->UseArchiveCommentLeader && rcs->comment)
3900                 {
3901                     leader = xstrdup (rcs->comment);
3902                     leader_len = strlen (rcs->comment);
3903                 }
3904                 else
3905                 {
3906                     error (0, 0,
3907 "Skipping `$" "Log$' keyword due to excessive comment leader.");
3908                     continue;
3909                 }
3910             }
3911             else /* leader_len <= config->MaxCommentLeaderLength */
3912             {
3913                 /* Copy the start of the line to use as a comment leader.  */
3914                 leader = xmalloc (leader_len);
3915                 memcpy (leader, start, leader_len);
3916             }
3917
3918             leader_sp_len = leader_len;
3919             while (leader_sp_len > 0 && isspace (leader[leader_sp_len - 1]))
3920                 --leader_sp_len;
3921
3922             /* RCS does some checking for an old style of Log here,
3923                but we don't bother.  RCS issues a warning if it
3924                changes anything.  */
3925
3926             /* Count the number of newlines in the log message so that
3927                we know how many copies of the leader we will need.  */
3928             cnl = 0;
3929             logend = log + loglen;
3930             for (snl = log; snl < logend; snl++)
3931                 if (*snl == '\n')
3932                     ++cnl;
3933
3934             /* If the log message did not end in a newline, increment
3935              * the newline count so we have space for the extra leader.
3936              * Failure to do so results in a buffer overrun.
3937              */
3938             if (loglen && snl[-1] != '\n')
3939                 ++cnl;
3940
3941             date = printable_date (ver->date);
3942             sub = xrealloc (sub,
3943                             (sublen
3944                              + sizeof "Revision"
3945                              + strlen (ver->version)
3946                              + strlen (date)
3947                              + strlen (ver->author)
3948                              + loglen
3949                                /* Use CNL + 2 below:  One leader for each log
3950                                 * line, plus the Revision/Author/Date line,
3951                                 * plus a trailing blank line.
3952                                 */
3953                              + (cnl + 2) * leader_len
3954                              + 20));
3955             if (expand != KFLAG_V)
3956             {
3957                 sub[sublen] = '$';
3958                 ++sublen;
3959             }
3960             sub[sublen] = '\n';
3961             ++sublen;
3962             memcpy (sub + sublen, leader, leader_len);
3963             sublen += leader_len;
3964             sprintf (sub + sublen, "Revision %s  %s  %s\n",
3965                      ver->version, date, ver->author);
3966             sublen += strlen (sub + sublen);
3967             free (date);
3968
3969             sl = log;
3970             while (sl < logend)
3971             {
3972                 if (*sl == '\n')
3973                 {
3974                     memcpy (sub + sublen, leader, leader_sp_len);
3975                     sublen += leader_sp_len;
3976                     sub[sublen] = '\n';
3977                     ++sublen;
3978                     ++sl;
3979                 }
3980                 else
3981                 {
3982                     const char *slnl;
3983
3984                     memcpy (sub + sublen, leader, leader_len);
3985                     sublen += leader_len;
3986                     for (slnl = sl; slnl < logend && *slnl != '\n'; ++slnl)
3987                         ;
3988                     if (slnl < logend)
3989                         ++slnl;
3990                     memcpy (sub + sublen, sl, slnl - sl);
3991                     sublen += slnl - sl;
3992                     if (slnl == logend && slnl[-1] != '\n')
3993                     {
3994                         /* There was no EOL at the end of the log message.  Add
3995                          * one.
3996                          */
3997                         sub[sublen] = '\n';
3998                         ++sublen;
3999                     }
4000                     sl = slnl;
4001                 }
4002             }
4003
4004             memcpy (sub + sublen, leader, leader_sp_len);
4005             sublen += leader_sp_len;
4006
4007             free (leader);
4008         }
4009
4010         /* Now SUB contains a string which is to replace the string
4011            from SRCH to S.  SUBLEN is the length of SUB.  */
4012
4013         if (srch + sublen == s)
4014         {
4015             memcpy (srch, sub, sublen);
4016             free (sub);
4017         }
4018         else
4019         {
4020             struct expand_buffer *ebuf;
4021
4022             /* We need to change the size of the buffer.  We build a
4023                list of expand_buffer structures.  Each expand_buffer
4024                structure represents a portion of the final output.  We
4025                concatenate them back into a single buffer when we are
4026                done.  This minimizes the number of potentially large
4027                buffer copies we must do.  */
4028
4029             if (ebufs == NULL)
4030             {
4031                 ebufs = xmalloc (sizeof *ebuf);
4032                 ebufs->next = NULL;
4033                 ebufs->data = buf;
4034                 ebufs->free_data = 0;
4035                 ebuf_len = srch - buf;
4036                 ebufs->len = ebuf_len;
4037                 ebuf_last = ebufs;
4038             }
4039             else
4040             {
4041                 assert (srch >= ebuf_last->data);
4042                 assert (srch <= ebuf_last->data + ebuf_last->len);
4043                 ebuf_len -= ebuf_last->len - (srch - ebuf_last->data);
4044                 ebuf_last->len = srch - ebuf_last->data;
4045             }
4046
4047             ebuf = xmalloc (sizeof *ebuf);
4048             ebuf->data = sub;
4049             ebuf->len = sublen;
4050             ebuf->free_data = 1;
4051             ebuf->next = NULL;
4052             ebuf_last->next = ebuf;
4053             ebuf_last = ebuf;
4054             ebuf_len += sublen;
4055
4056             ebuf = xmalloc (sizeof *ebuf);
4057             ebuf->data = s;
4058             ebuf->len = srch_len - (s - srch);
4059             ebuf->free_data = 0;
4060             ebuf->next = NULL;
4061             ebuf_last->next = ebuf;
4062             ebuf_last = ebuf;
4063             ebuf_len += srch_len - (s - srch);
4064         }
4065
4066         srch_len -= (s - srch);
4067         srch = s;
4068     }
4069
4070     if (locker != NULL)
4071         free (locker);
4072
4073     if (ebufs == NULL)
4074     {
4075         *retbuf = buf;
4076         *retlen = len;
4077     }
4078     else
4079     {
4080         char *ret;
4081
4082         ret = xmalloc (ebuf_len);
4083         *retbuf = ret;
4084         *retlen = ebuf_len;
4085         while (ebufs != NULL)
4086         {
4087             struct expand_buffer *next;
4088
4089             memcpy (ret, ebufs->data, ebufs->len);
4090             ret += ebufs->len;
4091             if (ebufs->free_data)
4092                 free (ebufs->data);
4093             next = ebufs->next;
4094             free (ebufs);
4095             ebufs = next;
4096         }
4097     }
4098 }
4099
4100
4101
4102 /* Check out a revision from an RCS file.
4103
4104    If PFN is not NULL, then ignore WORKFILE and SOUT.  Call PFN zero
4105    or more times with the contents of the file.  CALLERDAT is passed,
4106    uninterpreted, to PFN.  (The current code will always call PFN
4107    exactly once for a non empty file; however, the current code
4108    assumes that it can hold the entire file contents in memory, which
4109    is not a good assumption, and might change in the future).
4110
4111    Otherwise, if WORKFILE is not NULL, check out the revision to
4112    WORKFILE.  However, if WORKFILE is not NULL, and noexec is set,
4113    then don't do anything.
4114
4115    Otherwise, if WORKFILE is NULL, check out the revision to SOUT.  If
4116    SOUT is RUN_TTY, then write the contents of the revision to
4117    standard output.  When using SOUT, the output is generally a
4118    temporary file; don't bother to get the file modes correct.  When
4119    NOEXEC is set, WORKFILEs are not written but SOUTs are.
4120
4121    REV is the numeric revision to check out.  It may be NULL, which
4122    means to check out the head of the default branch.
4123
4124    If NAMETAG is not NULL, and is not a numeric revision, then it is
4125    the tag that should be used when expanding the RCS Name keyword.
4126
4127    OPTIONS is a string such as "-kb" or "-kv" for keyword expansion
4128    options.  It may be NULL to use the default expansion mode of the
4129    file, typically "-kkv".
4130
4131    On an error which prevented checking out the file, either print a
4132    nonfatal error and return 1, or give a fatal error.  On success,
4133    return 0.  */
4134
4135 /* This function mimics the behavior of `rcs co' almost exactly.  The
4136    chief difference is in its support for preserving file ownership,
4137    permissions, and special files across checkin and checkout -- see
4138    comments in RCS_checkin for some issues about this. -twp */
4139 int
4140 RCS_checkout (RCSNode *rcs, const char *workfile, const char *rev,
4141               const char *nametag, const char *options, const char *sout,
4142               RCSCHECKOUTPROC pfn, void *callerdat)
4143 {
4144     int free_rev = 0;
4145     enum kflag expand;
4146     FILE *fp,
4147          *ofp = NULL; /* Initialize since -Wall doesn't understand that
4148                        * error (1, ...) does not return.
4149                        */
4150     struct stat sb;
4151     struct rcsbuffer rcsbuf;
4152     char *key;
4153     char *value;
4154     size_t len;
4155     int free_value = 0;
4156     char *log = NULL;
4157     size_t loglen = 0;
4158     Node *vp = NULL;
4159 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4160     uid_t rcs_owner = (uid_t) -1;
4161     gid_t rcs_group = (gid_t) -1;
4162     mode_t rcs_mode;
4163     int change_rcs_owner_or_group = 0;
4164     int change_rcs_mode = 0;
4165     int special_file = 0;
4166     unsigned long devnum_long;
4167     dev_t devnum = 0;
4168 #endif
4169
4170     TRACE (TRACE_FUNCTION, "RCS_checkout (%s, %s, %s, %s, %s)",
4171            rcs->path,
4172            rev != NULL ? rev : "",
4173            nametag != NULL ? nametag : "",
4174            options != NULL ? options : "",
4175            (pfn != NULL ? "(function)"
4176             : (workfile != NULL ? workfile
4177                : (sout != RUN_TTY ? sout
4178                   : "(stdout)"))));
4179
4180     assert (rev == NULL || isdigit ((unsigned char) *rev));
4181
4182     if (noexec && !server_active && workfile != NULL)
4183         return 0;
4184
4185     assert (sout == RUN_TTY || workfile == NULL);
4186     assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL));
4187
4188     /* Some callers, such as Checkin or remove_file, will pass us a
4189        branch.  */
4190     if (rev != NULL && (numdots (rev) & 1) == 0)
4191     {
4192         rev = RCS_getbranch (rcs, rev, 1);
4193         if (rev == NULL)
4194             error (1, 0, "internal error: bad branch tag in checkout");
4195         free_rev = 1;
4196     }
4197
4198     if (rev == NULL || STREQ (rev, rcs->head))
4199     {
4200         int gothead;
4201
4202         /* We want the head revision.  Try to read it directly.  */
4203
4204         if (rcs->flags & PARTIAL)
4205             RCS_reparsercsfile (rcs, &fp, &rcsbuf);
4206         else
4207             rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf);
4208
4209         gothead = 0;
4210         if (! rcsbuf_getrevnum (&rcsbuf, &key))
4211             error (1, 0, "unexpected EOF reading %s", rcs->print_path);
4212         while (rcsbuf_getkey (&rcsbuf, &key, &value))
4213         {
4214             if (STREQ (key, "log"))
4215             {
4216                 if (log)
4217                 {
4218                     error (0, 0,
4219 "Duplicate log keyword found for head revision in RCS file.");
4220                     free (log);
4221                 }
4222                 log = rcsbuf_valcopy (&rcsbuf, value, 0, &loglen);
4223             }
4224             else if (STREQ (key, "text"))
4225             {
4226                 gothead = 1;
4227                 break;
4228             }
4229         }
4230
4231         if (! gothead)
4232         {
4233             error (0, 0, "internal error: cannot find head text");
4234             if (free_rev)
4235                 /* It's okay to discard the const when free_rev is set, because
4236                  * we know we allocated it in this function.
4237                  */
4238                 free ((char *)rev);
4239             return 1;
4240         }
4241
4242         rcsbuf_valpolish (&rcsbuf, value, 0, &len);
4243
4244         if (fstat (fileno (fp), &sb) < 0)
4245             error (1, errno, "cannot fstat %s", rcs->path);
4246
4247         rcsbuf_cache (rcs, &rcsbuf);
4248     }
4249     else
4250     {
4251         struct rcsbuffer *rcsbufp;
4252
4253         /* It isn't the head revision of the trunk.  We'll need to
4254            walk through the deltas.  */
4255
4256         fp = NULL;
4257         if (rcs->flags & PARTIAL)
4258             RCS_reparsercsfile (rcs, &fp, &rcsbuf);
4259
4260         if (fp == NULL)
4261         {
4262             /* If RCS_deltas didn't close the file, we could use fstat
4263                here too.  Probably should change it thusly....  */
4264             if (stat (rcs->path, &sb) < 0)
4265                 error (1, errno, "cannot stat %s", rcs->path);
4266             rcsbufp = NULL;
4267         }
4268         else
4269         {
4270             if (fstat (fileno (fp), &sb) < 0)
4271                 error (1, errno, "cannot fstat %s", rcs->path);
4272             rcsbufp = &rcsbuf;
4273         }
4274
4275         RCS_deltas (rcs, fp, rcsbufp, rev, RCS_FETCH, &value, &len,
4276                     &log, &loglen);
4277         free_value = 1;
4278     }
4279
4280     /* If OPTIONS is NULL or the empty string, then the old code would
4281        invoke the RCS co program with no -k option, which means that
4282        co would use the string we have stored in rcs->expand.  */
4283     if ((options == NULL || options[0] == '\0') && rcs->expand == NULL)
4284         expand = KFLAG_KV;
4285     else
4286     {
4287         const char *ouroptions;
4288         const char * const *cpp;
4289
4290         if (options != NULL && options[0] != '\0')
4291         {
4292             assert (options[0] == '-' && options[1] == 'k');
4293             ouroptions = options + 2;
4294         }
4295         else
4296             ouroptions = rcs->expand;
4297
4298         for (cpp = kflags; *cpp != NULL; cpp++)
4299             if (STREQ (*cpp, ouroptions))
4300                 break;
4301
4302         if (*cpp != NULL)
4303             expand = (enum kflag) (cpp - kflags);
4304         else
4305         {
4306             error (0, 0,
4307                    "internal error: unsupported substitution string -k%s",
4308                    ouroptions);
4309             expand = KFLAG_KV;
4310         }
4311     }
4312
4313 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4314     /* Handle special files and permissions, if that is desired. */
4315     if (preserve_perms)
4316     {
4317         RCSVers *vers;
4318         Node *info;
4319
4320         vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
4321         if (vp == NULL)
4322             error (1, 0, "internal error: no revision information for %s",
4323                    rev == NULL ? rcs->head : rev);
4324         vers = vp->data;
4325
4326         /* First we look for symlinks, which are simplest to handle. */
4327         info = findnode (vers->other_delta, "symlink");
4328         if (info != NULL)
4329         {
4330             char *dest;
4331
4332             if (pfn != NULL || (workfile == NULL && sout == RUN_TTY))
4333                 error (1, 0, "symbolic link %s:%s cannot be piped",
4334                        rcs->path, vers->version);
4335             if (workfile == NULL)
4336                 dest = sout;
4337             else
4338                 dest = workfile;
4339
4340             /* Remove `dest', just in case.  It's okay to get ENOENT here,
4341                since we just want the file not to be there.  (TODO: decide
4342                whether it should be considered an error for `dest' to exist
4343                at this point.  If so, the unlink call should be removed and
4344                `symlink' should signal the error. -twp) */
4345             if (CVS_UNLINK (dest) < 0 && !existence_error (errno))
4346                 error (1, errno, "cannot remove %s", dest);
4347             if (symlink (info->data, dest) < 0)
4348                 error (1, errno, "cannot create symbolic link from %s to %s",
4349                        dest, (char *)info->data);
4350             if (free_value)
4351                 free (value);
4352             if (free_rev)
4353                 /* It's okay to discard the const when free_rev is set, because
4354                  * we know we allocated it in this function.
4355                  */
4356                 free ((char *)rev);
4357             return 0;
4358         }
4359
4360         /* Next, we look at this file's hardlinks field, and see whether
4361            it is linked to any other file that has been checked out.
4362            If so, we don't do anything else -- just link it to that file.
4363
4364            If we are checking out a file to a pipe or temporary storage,
4365            none of this should matter.  Hence the `workfile != NULL'
4366            wrapper around the whole thing. -twp */
4367
4368         if (workfile != NULL)
4369         {
4370             List *links = vers->hardlinks;
4371             if (links != NULL)
4372             {
4373                 Node *uptodate_link;
4374
4375                 /* For each file in the hardlinks field, check to see
4376                    if it exists, and if so, if it has been checked out
4377                    this iteration.  When walklist returns, uptodate_link
4378                    should point to a hardlist node representing a file
4379                    in `links' which has recently been checked out, or
4380                    NULL if no file in `links' has yet been checked out. */
4381
4382                 uptodate_link = NULL;
4383                 (void) walklist (links, find_checkedout_proc, &uptodate_link);
4384                 dellist (&links);
4385
4386                 /* If we've found a file that `workfile' is supposed to be
4387                    linked to, and it has been checked out since CVS was
4388                    invoked, then simply link workfile to that file and return.
4389
4390                    If one of these conditions is not met, then
4391                    workfile is the first one in its hardlink group to
4392                    be checked out, and we must continue with a full
4393                    checkout. */
4394
4395                 if (uptodate_link != NULL)
4396                 {
4397                     struct hardlink_info *hlinfo = uptodate_link->data;
4398
4399                     if (link (uptodate_link->key, workfile) < 0)
4400                         error (1, errno, "cannot link %s to %s",
4401                                workfile, uptodate_link->key);
4402                     hlinfo->checked_out = 1;    /* probably unnecessary */
4403                     if (free_value)
4404                         free (value);
4405                     if (free_rev)
4406                         /* It's okay to discard the const when free_rev is set,
4407                          * because we know we allocated it in this function.
4408                          */
4409                         free ((char *)rev);
4410                     return 0;
4411                 }
4412             }
4413         }
4414
4415         info = findnode (vers->other_delta, "owner");
4416         if (info != NULL)
4417         {
4418             change_rcs_owner_or_group = 1;
4419             rcs_owner = (uid_t) strtoul (info->data, NULL, 10);
4420         }
4421         info = findnode (vers->other_delta, "group");
4422         if (info != NULL)
4423         {
4424             change_rcs_owner_or_group = 1;
4425             rcs_group = (gid_t) strtoul (info->data, NULL, 10);
4426         }
4427         info = findnode (vers->other_delta, "permissions");
4428         if (info != NULL)
4429         {
4430             change_rcs_mode = 1;
4431             rcs_mode = (mode_t) strtoul (info->data, NULL, 8);
4432         }
4433         info = findnode (vers->other_delta, "special");
4434         if (info != NULL)
4435         {
4436             /* If the size of `devtype' changes, fix the sscanf call also */
4437             char devtype[16];
4438
4439             if (sscanf (info->data, "%15s %lu",
4440                         devtype, &devnum_long) < 2)
4441                 error (1, 0, "%s:%s has bad `special' newphrase %s",
4442                        workfile, vers->version, (char *)info->data);
4443             devnum = devnum_long;
4444             if (STREQ (devtype, "character"))
4445                 special_file = S_IFCHR;
4446             else if (STREQ (devtype, "block"))
4447                 special_file = S_IFBLK;
4448             else
4449                 error (0, 0, "%s is a special file of unsupported type `%s'",
4450                        workfile, (char *)info->data);
4451         }
4452     }
4453 #endif /* PRESERVE_PERMISSIONS_SUPPORT */
4454
4455     if (expand != KFLAG_O && expand != KFLAG_B)
4456     {
4457         char *newvalue;
4458
4459         /* Don't fetch the delta node again if we already have it. */
4460         if (vp == NULL)
4461         {
4462             vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
4463             if (vp == NULL)
4464                 error (1, 0, "internal error: no revision information for %s",
4465                        rev == NULL ? rcs->head : rev);
4466         }
4467
4468         expand_keywords (rcs, vp->data, nametag, log, loglen,
4469                          expand, value, len, &newvalue, &len);
4470
4471         if (newvalue != value)
4472         {
4473             if (free_value)
4474                 free (value);
4475             value = newvalue;
4476             free_value = 1;
4477         }
4478     }
4479
4480     if (free_rev)
4481         /* It's okay to discard the const when free_rev is set, because
4482          * we know we allocated it in this function.
4483          */
4484         free ((char *)rev);
4485
4486     if (log != NULL)
4487     {
4488         free (log);
4489         log = NULL;
4490     }
4491
4492     if (pfn != NULL)
4493     {
4494 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4495         if (special_file)
4496             error (1, 0, "special file %s cannot be piped to anything",
4497                    rcs->path);
4498 #endif
4499         /* The PFN interface is very simple to implement right now, as
4500            we always have the entire file in memory.  */
4501         if (len != 0)
4502             pfn (callerdat, value, len);
4503     }
4504 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4505     else if (special_file)
4506     {
4507 # ifdef HAVE_MKNOD
4508         char *dest;
4509
4510         /* Can send either to WORKFILE or to SOUT, as long as SOUT is
4511            not RUN_TTY. */
4512         dest = workfile;
4513         if (dest == NULL)
4514         {
4515             if (sout == RUN_TTY)
4516                 error (1, 0, "special file %s cannot be written to stdout",
4517                        rcs->path);
4518             dest = sout;
4519         }
4520
4521         /* Unlink `dest', just in case.  It's okay if this provokes a
4522            ENOENT error. */
4523         if (CVS_UNLINK (dest) < 0 && existence_error (errno))
4524             error (1, errno, "cannot remove %s", dest);
4525         if (mknod (dest, special_file, devnum) < 0)
4526             error (1, errno, "could not create special file %s",
4527                    dest);
4528 # else
4529         error (1, 0,
4530 "cannot create %s: unable to create special files on this system",
4531 workfile);
4532 # endif
4533     }
4534 #endif
4535     else
4536     {
4537         /* Not a special file: write to WORKFILE or SOUT. */
4538         if (workfile == NULL)
4539         {
4540             if (sout == RUN_TTY)
4541                 ofp = stdout;
4542             else
4543             {
4544                 /* Symbolic links should be removed before replacement, so that
4545                    `fopen' doesn't follow the link and open the wrong file. */
4546                 if (islink (sout))
4547                     if (unlink_file (sout) < 0)
4548                         error (1, errno, "cannot remove %s", sout);
4549                 ofp = CVS_FOPEN (sout, expand == KFLAG_B ? "wb" : "w");
4550                 if (ofp == NULL)
4551                     error (1, errno, "cannot open %s", sout);
4552             }
4553         }
4554         else
4555         {
4556             /* Output is supposed to go to WORKFILE, so we should open that
4557                file.  Symbolic links should be removed first (see above). */
4558             if (islink (workfile))
4559                 if (unlink_file (workfile) < 0)
4560                     error (1, errno, "cannot remove %s", workfile);
4561
4562             ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
4563
4564             /* If the open failed because the existing workfile was not
4565                writable, try to chmod the file and retry the open.  */
4566             if (ofp == NULL && errno == EACCES
4567                 && isfile (workfile) && !iswritable (workfile))
4568             {
4569                 xchmod (workfile, 1);
4570                 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
4571             }
4572
4573             if (ofp == NULL)
4574             {
4575                 error (0, errno, "cannot open %s", workfile);
4576                 if (free_value)
4577                     free (value);
4578                 return 1;
4579             }
4580         }
4581
4582         if (workfile == NULL && sout == RUN_TTY)
4583         {
4584             if (expand == KFLAG_B)
4585                 cvs_output_binary (value, len);
4586             else
4587             {
4588                 /* cvs_output requires the caller to check for zero
4589                    length.  */
4590                 if (len > 0)
4591                     cvs_output (value, len);
4592             }
4593         }
4594         else
4595         {
4596             /* NT 4.0 is said to have trouble writing 2099999 bytes
4597                (for example) in a single fwrite.  So break it down
4598                (there is no need to be writing that much at once
4599                anyway; it is possible that LARGEST_FWRITE should be
4600                somewhat larger for good performance, but for testing I
4601                want to start with a small value until/unless a bigger
4602                one proves useful).  */
4603 #define LARGEST_FWRITE 8192
4604             size_t nleft = len;
4605             size_t nstep = (len < LARGEST_FWRITE ? len : LARGEST_FWRITE);
4606             char *p = value;
4607
4608             while (nleft > 0)
4609             {
4610                 if (fwrite (p, 1, nstep, ofp) != nstep)
4611                 {
4612                     error (0, errno, "cannot write %s",
4613                            (workfile != NULL
4614                             ? workfile
4615                             : (sout != RUN_TTY ? sout : "stdout")));
4616                     if (free_value)
4617                         free (value);
4618                     return 1;
4619                 }
4620                 p += nstep;
4621                 nleft -= nstep;
4622                 if (nleft < nstep)
4623                     nstep = nleft;
4624             }
4625         }
4626     }
4627
4628     if (free_value)
4629         free (value);
4630
4631     if (workfile != NULL)
4632     {
4633         int ret;
4634
4635 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4636         if (!special_file && fclose (ofp) < 0)
4637         {
4638             error (0, errno, "cannot close %s", workfile);
4639             return 1;
4640         }
4641
4642         if (change_rcs_owner_or_group)
4643         {
4644             if (chown (workfile, rcs_owner, rcs_group) < 0)
4645                 error (0, errno, "could not change owner or group of %s",
4646                        workfile);
4647         }
4648
4649         ret = chmod (workfile,
4650                      change_rcs_mode
4651                      ? rcs_mode
4652                      : sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
4653 #else
4654         if (fclose (ofp) < 0)
4655         {
4656             error (0, errno, "cannot close %s", workfile);
4657             return 1;
4658         }
4659
4660         ret = chmod (workfile,
4661                      sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
4662 #endif
4663         if (ret < 0)
4664         {
4665             error (0, errno, "cannot change mode of file %s",
4666                    workfile);
4667         }
4668     }
4669     else if (sout != RUN_TTY)
4670     {
4671         if (
4672 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4673             !special_file &&
4674 #endif
4675             fclose (ofp) < 0)
4676         {
4677             error (0, errno, "cannot close %s", sout);
4678             return 1;
4679         }
4680     }
4681
4682 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4683     /* If we are in the business of preserving hardlinks, then
4684        mark this file as having been checked out. */
4685     if (preserve_perms && workfile != NULL)
4686         update_hardlink_info (workfile);
4687 #endif
4688
4689     return 0;
4690 }
4691
4692
4693
4694 /* Find the delta currently locked by the user.  From the `ci' man page:
4695
4696         "If rev is omitted, ci tries to  derive  the  new  revision
4697          number  from  the  caller's  last lock.  If the caller has
4698          locked the tip revision of a branch, the new  revision  is
4699          appended  to  that  branch.   The  new  revision number is
4700          obtained by incrementing the tip revision number.  If  the
4701          caller  locked a non-tip revision, a new branch is started
4702          at that revision by incrementing the highest branch number
4703          at  that  revision.   The default initial branch and level
4704          numbers are 1.
4705
4706          If rev is omitted and the caller has no lock, but owns the
4707          file  and  locking is not set to strict, then the revision
4708          is appended to the default branch (normally the trunk; see
4709          the -b option of rcs(1))."
4710
4711    RCS_findlock_or_tip finds the unique revision locked by the caller
4712    and returns its delta node.  If the caller has not locked any
4713    revisions (and is permitted to commit to an unlocked delta, as
4714    described above), return the tip of the default branch. */
4715 static RCSVers *
4716 RCS_findlock_or_tip (RCSNode *rcs)
4717 {
4718     char *user = getcaller();
4719     Node *lock, *p;
4720     List *locklist;
4721
4722     /* Find unique delta locked by caller. This code is very similar
4723        to the code in RCS_unlock -- perhaps it could be abstracted
4724        into a RCS_findlock function. */
4725     locklist = RCS_getlocks (rcs);
4726     lock = NULL;
4727     for (p = locklist->list->next; p != locklist->list; p = p->next)
4728     {
4729         if (STREQ (p->data, user))
4730         {
4731             if (lock != NULL)
4732             {
4733                 error (0, 0, "\
4734 %s: multiple revisions locked by %s; please specify one", rcs->print_path, user);
4735                 return NULL;
4736             }
4737             lock = p;
4738         }
4739     }
4740
4741     if (lock != NULL)
4742     {
4743         /* Found an old lock, but check that the revision still exists. */
4744         p = findnode (rcs->versions, lock->key);
4745         if (p == NULL)
4746         {
4747             error (0, 0, "%s: can't unlock nonexistent revision %s",
4748                    rcs->print_path,
4749                    lock->key);
4750             return NULL;
4751         }
4752         return p->data;
4753     }
4754
4755     /* No existing lock.  The RCS rule is that this is an error unless
4756        locking is nonstrict AND the file is owned by the current
4757        user.  Trying to determine the latter is a portability nightmare
4758        in the face of NT, VMS, AFS, and other systems with non-unix-like
4759        ideas of users and owners.  In the case of CVS, we should never get
4760        here (as long as the traditional behavior of making sure to call
4761        RCS_lock persists).  Anyway, we skip the RCS error checks
4762        and just return the default branch or head.  The reasoning is that
4763        those error checks are to make users lock before a checkin, and we do
4764        that in other ways if at all anyway (e.g. rcslock.pl).  */
4765
4766     p = findnode (rcs->versions, RCS_getbranch (rcs, rcs->branch, 0));
4767     if (!p)
4768     {
4769         error (0, 0, "RCS file `%s' does not contain its default revision.",
4770                rcs->path);
4771         return NULL;
4772     }
4773
4774     return p->data;
4775 }
4776
4777
4778
4779 /* Revision number string, R, must contain a `.'.
4780    Return a newly-malloc'd copy of the prefix of R up
4781    to but not including the final `.'.  */
4782 static char *
4783 truncate_revnum (const char *r)
4784 {
4785     size_t len;
4786     char *new_r;
4787     char *dot = strrchr (r, '.');
4788
4789     assert (dot);
4790     len = dot - r;
4791     new_r = xmalloc (len + 1);
4792     memcpy (new_r, r, len);
4793     *(new_r + len) = '\0';
4794     return new_r;
4795 }
4796
4797
4798
4799 /* Revision number string, R, must contain a `.'.
4800    R must be writable.  Replace the rightmost `.' in R with
4801    the NUL byte and return a pointer to that NUL byte.  */
4802 static char *
4803 truncate_revnum_in_place (char *r)
4804 {
4805     char *dot = strrchr (r, '.');
4806     assert (dot);
4807     *dot = '\0';
4808     return dot;
4809 }
4810
4811
4812
4813 /* Revision number strings, R and S, must each contain a `.'.
4814    R and S must be writable and must have the same number of dots.
4815    Truncate R and S for the comparison, then restored them to their
4816    original state.
4817    Return the result (see compare_revnums) of comparing R and S
4818    ignoring differences in any component after the rightmost `.'.  */
4819 static int
4820 compare_truncated_revnums (char *r, char *s)
4821 {
4822     char *r_dot = truncate_revnum_in_place (r);
4823     char *s_dot = truncate_revnum_in_place (s);
4824     int cmp;
4825
4826     assert (numdots (r) == numdots (s));
4827
4828     cmp = compare_revnums (r, s);
4829
4830     *r_dot = '.';
4831     *s_dot = '.';
4832
4833     return cmp;
4834 }
4835
4836
4837
4838 /* Return a malloc'd copy of the string representing the highest branch
4839    number on BRANCHNODE.  If there are no branches on BRANCHNODE, return NULL.
4840    FIXME: isn't the max rev always the last one?
4841    If so, we don't even need a loop.  */
4842 static char *
4843 max_rev (const RCSVers *branchnode)
4844 {
4845     Node *head;
4846     Node *bp;
4847     char *max;
4848
4849     if (branchnode->branches == NULL)
4850     {
4851         return NULL;
4852     }
4853
4854     max = NULL;
4855     head = branchnode->branches->list;
4856     for (bp = head->next; bp != head; bp = bp->next)
4857     {
4858         if (max == NULL || compare_truncated_revnums (max, bp->key) < 0)
4859         {
4860             max = bp->key;
4861         }
4862     }
4863     assert (max);
4864
4865     return truncate_revnum (max);
4866 }
4867
4868
4869
4870 /* Create BRANCH in RCS's delta tree.  BRANCH may be either a branch
4871    number or a revision number.  In the former case, create the branch
4872    with the specified number; in the latter case, create a new branch
4873    rooted at node BRANCH with a higher branch number than any others.
4874    Return the number of the tip node on the new branch. */
4875 static char *
4876 RCS_addbranch (RCSNode *rcs, const char *branch)
4877 {
4878     char *branchpoint, *newrevnum;
4879     Node *nodep, *bp;
4880     Node *marker;
4881     RCSVers *branchnode;
4882
4883     assert (branch);
4884
4885     /* Append to end by default.  */
4886     marker = NULL;
4887
4888     branchpoint = xstrdup (branch);
4889     if ((numdots (branchpoint) & 1) == 0)
4890     {
4891         truncate_revnum_in_place (branchpoint);
4892     }
4893
4894     /* Find the branch rooted at BRANCHPOINT. */
4895     nodep = findnode (rcs->versions, branchpoint);
4896     if (nodep == NULL)
4897     {
4898         error (0, 0, "%s: can't find branch point %s", rcs->print_path, branchpoint);
4899         free (branchpoint);
4900         return NULL;
4901     }
4902     free (branchpoint);
4903     branchnode = nodep->data;
4904
4905     /* If BRANCH was a full branch number, make sure it is higher than MAX. */
4906     if ((numdots (branch) & 1) == 1)
4907     {
4908         if (branchnode->branches == NULL)
4909         {
4910             /* We have to create the first branch on this node, which means
4911                appending ".2" to the revision number. */
4912             newrevnum = Xasprintf ("%s.2", branch);
4913         }
4914         else
4915         {
4916             char *max = max_rev (branchnode);
4917             assert (max);
4918             newrevnum = increment_revnum (max);
4919             free (max);
4920         }
4921     }
4922     else
4923     {
4924         newrevnum = xstrdup (branch);
4925
4926         if (branchnode->branches != NULL)
4927         {
4928             Node *head;
4929             Node *bp;
4930
4931             /* Find the position of this new branch in the sorted list
4932                of branches.  */
4933             head = branchnode->branches->list;
4934             for (bp = head->next; bp != head; bp = bp->next)
4935             {
4936                 char *dot;
4937                 int found_pos;
4938
4939                 /* The existing list must be sorted on increasing revnum.  */
4940                 assert (bp->next == head
4941                         || compare_truncated_revnums (bp->key,
4942                                                       bp->next->key) < 0);
4943                 dot = truncate_revnum_in_place (bp->key);
4944                 found_pos = (compare_revnums (branch, bp->key) < 0);
4945                 *dot = '.';
4946
4947                 if (found_pos)
4948                 {
4949                     break;
4950                 }
4951             }
4952             marker = bp;
4953         }
4954     }
4955
4956     newrevnum = xrealloc (newrevnum, strlen (newrevnum) + 3);
4957     strcat (newrevnum, ".1");
4958
4959     /* Add this new revision number to BRANCHPOINT's branches list. */
4960     if (branchnode->branches == NULL)
4961         branchnode->branches = getlist();
4962     bp = getnode();
4963     bp->key = xstrdup (newrevnum);
4964
4965     /* Append to the end of the list by default, that is, just before
4966        the header node, `list'.  */
4967     if (marker == NULL)
4968         marker = branchnode->branches->list;
4969
4970     {
4971         int fail;
4972         fail = insert_before (branchnode->branches, marker, bp);
4973         assert (!fail);
4974     }
4975
4976     return newrevnum;
4977 }
4978
4979
4980
4981 /* Check in to RCSFILE with revision REV (which must be greater than
4982    the largest revision) and message MESSAGE (which is checked for
4983    validity).  If FLAGS & RCS_FLAGS_DEAD, check in a dead revision.
4984    If FLAGS & RCS_FLAGS_QUIET, tell ci to be quiet.  If FLAGS &
4985    RCS_FLAGS_MODTIME, use the working file's modification time for the
4986    checkin time.  WORKFILE is the working file to check in from, or
4987    NULL to use the usual RCS rules for deriving it from the RCSFILE.
4988    If FLAGS & RCS_FLAGS_KEEPFILE, don't unlink the working file;
4989    unlinking the working file is standard RCS behavior, but is rarely
4990    appropriate for CVS.
4991
4992    UPDATE_DIR is used to print the path for the file.  This argument is
4993    unnecessary when FLAGS & RCS_FLAGS_QUIET since the path won't be printed
4994    anyhow.
4995
4996    This function should almost exactly mimic the behavior of `rcs ci'.  The
4997    principal point of difference is the support here for preserving file
4998    ownership and permissions in the delta nodes.  This is not a clean
4999    solution -- precisely because it diverges from RCS's behavior -- but
5000    it doesn't seem feasible to do this anywhere else in the code. [-twp]
5001    
5002    Return value is -1 for error (and errno is set to indicate the
5003    error), positive for error (and an error message has been printed),
5004    or zero for success.  */
5005 int
5006 RCS_checkin (RCSNode *rcs, const char *update_dir, const char *workfile_in,
5007              const char *message, const char *rev, time_t citime, int flags)
5008 {
5009     RCSVers *delta, *commitpt;
5010     Deltatext *dtext;
5011     Node *nodep;
5012     char *tmpfile, *changefile;
5013     int dargc = 0;
5014     size_t darg_allocated = 0;
5015     char **dargv = NULL;
5016     size_t bufsize;
5017     int status, checkin_quiet;
5018     struct tm *ftm;
5019     time_t modtime;
5020     int adding_branch = 0;
5021     char *workfile = xstrdup (workfile_in);
5022 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5023     struct stat sb;
5024 #endif
5025     Node *np;
5026
5027     commitpt = NULL;
5028
5029     if (rcs->flags & PARTIAL)
5030         RCS_reparsercsfile (rcs, NULL, NULL);
5031
5032     /* Get basename of working file.  Is there a library function to
5033        do this?  I couldn't find one. -twp */
5034     if (workfile == NULL)
5035     {
5036         char *p;
5037         int extlen = strlen (RCSEXT);
5038         assert (rcs->path);
5039         workfile = xstrdup (last_component (rcs->path));
5040         p = workfile + (strlen (workfile) - extlen);
5041         assert (strncmp (p, RCSEXT, extlen) == 0);
5042         *p = '\0';
5043     }
5044
5045     /* If the filename is a symbolic link, follow it and replace it
5046        with the destination of the link.  We need to do this before
5047        calling rcs_internal_lockfile, or else we won't put the lock in
5048        the right place. */
5049     resolve_symlink (&(rcs->path));
5050
5051     checkin_quiet = flags & RCS_FLAGS_QUIET;
5052     if (!(checkin_quiet || really_quiet))
5053     {
5054         cvs_output (rcs->path, 0);
5055         cvs_output ("  <--  ", 7);
5056         if (update_dir && strlen (update_dir))
5057         {
5058             cvs_output (update_dir, 0);
5059             cvs_output ("/", 1);
5060         }
5061         cvs_output (workfile, 0);
5062         cvs_output ("\n", 1);
5063     }
5064
5065     /* Create new delta node. */
5066     delta = xmalloc (sizeof (RCSVers));
5067     memset (delta, 0, sizeof (RCSVers));
5068     delta->author = xstrdup (getcaller ());
5069     if (flags & RCS_FLAGS_MODTIME)
5070     {
5071         struct stat ws;
5072         if (stat (workfile, &ws) < 0)
5073         {
5074             error (1, errno, "cannot stat %s", workfile);
5075         }
5076         modtime = ws.st_mtime;
5077     }
5078     else if (flags & RCS_FLAGS_USETIME)
5079         modtime = citime;
5080     else
5081         (void) time (&modtime);
5082     ftm = gmtime (&modtime);
5083     delta->date = Xasprintf (DATEFORM,
5084                              ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
5085                              ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
5086                              ftm->tm_min, ftm->tm_sec);
5087     if (flags & RCS_FLAGS_DEAD)
5088     {
5089         delta->state = xstrdup (RCSDEAD);
5090         delta->dead = 1;
5091     }
5092     else
5093         delta->state = xstrdup ("Exp");
5094
5095     delta->other_delta = getlist();
5096
5097     /* save the commit ID */
5098     np = getnode();
5099     np->type = RCSFIELD;
5100     np->key = xstrdup ("commitid");
5101     np->data = xstrdup(global_session_id);
5102     addnode (delta->other_delta, np);
5103
5104
5105 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5106     /* If permissions should be preserved on this project, then
5107        save the permission info. */
5108     if (preserve_perms)
5109     {
5110         Node *np;
5111         char buf[64];   /* static buffer should be safe: see usage. -twp */
5112
5113         delta->other_delta = getlist();
5114
5115         if (lstat (workfile, &sb) < 0)
5116             error (1, errno, "cannot lstat %s", workfile);
5117
5118         if (S_ISLNK (sb.st_mode))
5119         {
5120             np = getnode();
5121             np->type = RCSFIELD;
5122             np->key = xstrdup ("symlink");
5123             np->data = Xreadlink (workfile, sb.st_size);
5124             addnode (delta->other_delta, np);
5125         }
5126         else
5127         {
5128             (void) sprintf (buf, "%u", sb.st_uid);
5129             np = getnode();
5130             np->type = RCSFIELD;
5131             np->key = xstrdup ("owner");
5132             np->data = xstrdup (buf);
5133             addnode (delta->other_delta, np);
5134
5135             (void) sprintf (buf, "%u", sb.st_gid);
5136             np = getnode();
5137             np->type = RCSFIELD;
5138             np->key = xstrdup ("group");
5139             np->data = xstrdup (buf);
5140             addnode (delta->other_delta, np);
5141             
5142             (void) sprintf (buf, "%o", sb.st_mode & 07777);
5143             np = getnode();
5144             np->type = RCSFIELD;
5145             np->key = xstrdup ("permissions");
5146             np->data = xstrdup (buf);
5147             addnode (delta->other_delta, np);
5148
5149             /* Save device number. */
5150             switch (sb.st_mode & S_IFMT)
5151             {
5152                 case S_IFREG: break;
5153                 case S_IFCHR:
5154                 case S_IFBLK:
5155 # ifdef HAVE_STRUCT_STAT_ST_RDEV
5156                     np = getnode();
5157                     np->type = RCSFIELD;
5158                     np->key = xstrdup ("special");
5159                     sprintf (buf, "%s %lu",
5160                              ((sb.st_mode & S_IFMT) == S_IFCHR
5161                               ? "character" : "block"),
5162                              (unsigned long) sb.st_rdev);
5163                     np->data = xstrdup (buf);
5164                     addnode (delta->other_delta, np);
5165 # else
5166                     error (0, 0,
5167 "can't preserve %s: unable to save device files on this system",
5168 workfile);
5169 # endif
5170                     break;
5171
5172                 default:
5173                     error (0, 0, "special file %s has unknown type", workfile);
5174             }
5175
5176             /* Save hardlinks. */
5177             delta->hardlinks = list_linked_files_on_disk (workfile);
5178         }
5179     }
5180 #endif
5181
5182     /* Create a new deltatext node. */
5183     dtext = xmalloc (sizeof (Deltatext));
5184     memset (dtext, 0, sizeof (Deltatext));
5185
5186     dtext->log = make_message_rcsvalid (message);
5187
5188     /* If the delta tree is empty, then there's nothing to link the
5189        new delta into.  So make a new delta tree, snarf the working
5190        file contents, and just write the new RCS file. */
5191     if (rcs->head == NULL)
5192     {
5193         char *newrev;
5194         FILE *fout;
5195
5196         /* Figure out what the first revision number should be. */
5197         if (rev == NULL || *rev == '\0')
5198             newrev = xstrdup ("1.1");
5199         else if (numdots (rev) == 0)
5200         {
5201             newrev = Xasprintf ("%s.1", rev);
5202         }
5203         else
5204             newrev = xstrdup (rev);
5205
5206         /* Don't need to xstrdup NEWREV because it's already dynamic, and
5207            not used for anything else.  (Don't need to free it, either.) */
5208         rcs->head = newrev;
5209         delta->version = xstrdup (newrev);
5210         nodep = getnode();
5211         nodep->type = RCSVERS;
5212         nodep->delproc = rcsvers_delproc;
5213         nodep->data = delta;
5214         nodep->key = delta->version;
5215         (void) addnode (rcs->versions, nodep);
5216
5217         dtext->version = xstrdup (newrev);
5218         bufsize = 0;
5219 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5220         if (preserve_perms && !S_ISREG (sb.st_mode))
5221             /* Pretend file is empty.  */
5222             bufsize = 0;
5223         else
5224 #endif
5225         get_file (workfile, workfile,
5226                   rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5227                   &dtext->text, &bufsize, &dtext->len);
5228
5229         if (!(checkin_quiet || really_quiet))
5230         {
5231             cvs_output ("initial revision: ", 0);
5232             cvs_output (rcs->head, 0);
5233             cvs_output ("\n", 1);
5234         }
5235
5236         /* We are probably about to invalidate any cached file.  */
5237         rcsbuf_cache_close ();
5238
5239         fout = rcs_internal_lockfile (rcs->path);
5240         RCS_putadmin (rcs, fout);
5241         RCS_putdtree (rcs, rcs->head, fout);
5242         RCS_putdesc (rcs, fout);
5243         rcs->delta_pos = ftello (fout);
5244         if (rcs->delta_pos == -1)
5245             error (1, errno, "cannot ftello for %s", rcs->path);
5246         putdeltatext (fout, dtext);
5247         rcs_internal_unlockfile (fout, rcs->path);
5248
5249         if ((flags & RCS_FLAGS_KEEPFILE) == 0)
5250         {
5251             if (unlink_file (workfile) < 0)
5252                 /* FIXME-update-dir: message does not include update_dir.  */
5253                 error (0, errno, "cannot remove %s", workfile);
5254         }
5255
5256         status = 0;
5257         goto checkin_done;
5258     }
5259
5260     /* Derive a new revision number.  From the `ci' man page:
5261
5262          "If rev  is  a revision number, it must be higher than the
5263          latest one on the branch to which  rev  belongs,  or  must
5264          start a new branch.
5265
5266          If  rev is a branch rather than a revision number, the new
5267          revision is appended to that branch.  The level number  is
5268          obtained  by  incrementing the tip revision number of that
5269          branch.  If rev  indicates  a  non-existing  branch,  that
5270          branch  is  created  with  the  initial  revision numbered
5271          rev.1."
5272
5273        RCS_findlock_or_tip handles the case where REV is omitted.
5274        RCS 5.7 also permits REV to be "$" or to begin with a dot, but
5275        we do not address those cases -- every routine that calls
5276        RCS_checkin passes it a numeric revision. */
5277
5278     if (rev == NULL || *rev == '\0')
5279     {
5280         /* Figure out where the commit point is by looking for locks.
5281            If the commit point is at the tip of a branch (or is the
5282            head of the delta tree), then increment its revision number
5283            to obtain the new revnum.  Otherwise, start a new
5284            branch. */
5285         commitpt = RCS_findlock_or_tip (rcs);
5286         if (commitpt == NULL)
5287         {
5288             status = 1;
5289             goto checkin_done;
5290         }
5291         else if (commitpt->next == NULL
5292                  || STREQ (commitpt->version, rcs->head))
5293             delta->version = increment_revnum (commitpt->version);
5294         else
5295             delta->version = RCS_addbranch (rcs, commitpt->version);
5296     }
5297     else
5298     {
5299         /* REV is either a revision number or a branch number.  Find the
5300            tip of the target branch. */
5301         char *branch, *tip, *newrev, *p;
5302         int dots, isrevnum;
5303
5304         assert (isdigit ((unsigned char) *rev));
5305
5306         newrev = xstrdup (rev);
5307         dots = numdots (newrev);
5308         isrevnum = dots & 1;
5309
5310         branch = xstrdup (rev);
5311         if (isrevnum)
5312         {
5313             p = strrchr (branch, '.');
5314             *p = '\0';
5315         }
5316
5317         /* Find the tip of the target branch.  If we got a one- or two-digit
5318            revision number, this will be the head of the tree.  Exception:
5319            if rev is a single-field revision equal to the branch number of
5320            the trunk (usually "1") then we want to treat it like an ordinary
5321            branch revision. */
5322         if (dots == 0)
5323         {
5324             tip = xstrdup (rcs->head);
5325             if (atoi (tip) != atoi (branch))
5326             {
5327                 newrev = xrealloc (newrev, strlen (newrev) + 3);
5328                 strcat (newrev, ".1");
5329                 dots = isrevnum = 1;
5330             }
5331         }
5332         else if (dots == 1)
5333             tip = xstrdup (rcs->head);
5334         else
5335             tip = RCS_getbranch (rcs, branch, 1);
5336
5337         /* If the branch does not exist, and we were supplied an exact
5338            revision number, signal an error.  Otherwise, if we were
5339            given only a branch number, create it and set COMMITPT to
5340            the branch point. */
5341         if (tip == NULL)
5342         {
5343             if (isrevnum)
5344             {
5345                 error (0, 0, "%s: can't find branch point %s",
5346                        rcs->print_path, branch);
5347                 free (branch);
5348                 free (newrev);
5349                 status = 1;
5350                 goto checkin_done;
5351             }
5352             delta->version = RCS_addbranch (rcs, branch);
5353             if (!delta->version)
5354             {
5355                 free (branch);
5356                 free (newrev);
5357                 status = 1;
5358                 goto checkin_done;
5359             }
5360             adding_branch = 1;
5361             p = strrchr (branch, '.');
5362             *p = '\0';
5363             tip = xstrdup (branch);
5364         }
5365         else
5366         {
5367             if (isrevnum)
5368             {
5369                 /* NEWREV must be higher than TIP. */
5370                 if (compare_revnums (tip, newrev) >= 0)
5371                 {
5372                     error (0, 0,
5373                            "%s: revision %s too low; must be higher than %s",
5374                            rcs->print_path,
5375                            newrev, tip);
5376                     free (branch);
5377                     free (newrev);
5378                     free (tip);
5379                     status = 1;
5380                     goto checkin_done;
5381                 }
5382                 delta->version = xstrdup (newrev);
5383             }
5384             else
5385                 /* Just increment the tip number to get the new revision. */
5386                 delta->version = increment_revnum (tip);
5387         }
5388
5389         nodep = findnode (rcs->versions, tip);
5390         commitpt = nodep->data;
5391
5392         free (branch);
5393         free (newrev);
5394         free (tip);
5395     }
5396
5397     assert (delta->version != NULL);
5398
5399     /* If COMMITPT is locked by us, break the lock.  If it's locked
5400        by someone else, signal an error. */
5401     nodep = findnode (RCS_getlocks (rcs), commitpt->version);
5402     if (nodep != NULL)
5403     {
5404         if (! STREQ (nodep->data, delta->author))
5405         {
5406             /* If we are adding a branch, then leave the old lock around.
5407                That is sensible in the sense that when adding a branch,
5408                we don't need to use the lock to tell us where to check
5409                in.  It is fishy in the sense that if it is our own lock,
5410                we break it.  However, this is the RCS 5.7 behavior (at
5411                the end of addbranch in ci.c in RCS 5.7, it calls
5412                removelock only if it is our own lock, not someone
5413                else's).  */
5414
5415             if (!adding_branch)
5416             {
5417                 error (0, 0, "%s: revision %s locked by %s",
5418                        rcs->print_path,
5419                        nodep->key, (char *)nodep->data);
5420                 status = 1;
5421                 goto checkin_done;
5422             }
5423         }
5424         else
5425             delnode (nodep);
5426     }
5427
5428     dtext->version = xstrdup (delta->version);
5429
5430     /* Obtain the change text for the new delta.  If DELTA is to be the
5431        new head of the tree, then its change text should be the contents
5432        of the working file, and LEAFNODE's change text should be a diff.
5433        Else, DELTA's change text should be a diff between LEAFNODE and
5434        the working file. */
5435
5436     tmpfile = cvs_temp_name();
5437     status = RCS_checkout (rcs, NULL, commitpt->version, NULL,
5438                            ((rcs->expand != NULL
5439                              && STREQ (rcs->expand, "b"))
5440                             ? "-kb"
5441                             : "-ko"),
5442                            tmpfile,
5443                            NULL, NULL);
5444     if (status != 0)
5445         error (1, 0,
5446                "could not check out revision %s of `%s'",
5447                commitpt->version, rcs->print_path);
5448
5449     bufsize = 0;
5450     changefile = cvs_temp_name();
5451
5452     /* Diff options should include --binary if the RCS file has -kb set
5453        in its `expand' field. */
5454     run_add_arg_p (&dargc, &darg_allocated, &dargv, "-a");
5455     run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n");
5456     if (rcs->expand != NULL && STREQ (rcs->expand, "b"))
5457         run_add_arg_p (&dargc, &darg_allocated, &dargv, "--binary");
5458
5459     if (STREQ (commitpt->version, rcs->head) &&
5460         numdots (delta->version) == 1)
5461     {
5462         /* If this revision is being inserted on the trunk, the change text
5463            for the new delta should be the contents of the working file ... */
5464         bufsize = 0;
5465 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5466         if (preserve_perms && !S_ISREG (sb.st_mode))
5467             /* Pretend file is empty.  */
5468             ;
5469         else
5470 #endif
5471         get_file (workfile, workfile,
5472                   rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5473                   &dtext->text, &bufsize, &dtext->len);
5474
5475         /* ... and the change text for the old delta should be a diff. */
5476         commitpt->text = xmalloc (sizeof (Deltatext));
5477         memset (commitpt->text, 0, sizeof (Deltatext));
5478
5479         bufsize = 0;
5480         switch (diff_exec (workfile, tmpfile, NULL, NULL,
5481                            dargc, dargv, changefile))
5482         {
5483             case 0:
5484             case 1:
5485                 break;
5486             case -1:
5487                 /* FIXME-update-dir: message does not include update_dir.  */
5488                 error (1, errno, "error diffing %s", workfile);
5489                 break;
5490             default:
5491                 /* FIXME-update-dir: message does not include update_dir.  */
5492                 error (1, 0, "error diffing %s", workfile);
5493                 break;
5494         }
5495
5496         /* OK, the text file case here is really dumb.  Logically
5497            speaking we want diff to read the files in text mode,
5498            convert them to the canonical form found in RCS files
5499            (which, we hope at least, is independent of OS--always
5500            bare linefeeds), and then work with change texts in that
5501            format.  However, diff_exec both generates change
5502            texts and produces output for user purposes (e.g. patch.c),
5503            and there is no way to distinguish between the two cases.
5504            So we actually implement the text file case by writing the
5505            change text as a text file, then reading it as a text file.
5506            This should cause no harm, but doesn't strike me as
5507            immensely clean.  */
5508         get_file (changefile, changefile,
5509                   rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5510                   &commitpt->text->text, &bufsize, &commitpt->text->len);
5511
5512         /* If COMMITPT->TEXT->TEXT is NULL, it means that CHANGEFILE
5513            was empty and that there are no differences between revisions.
5514            In that event, we want to force RCS_rewrite to write an empty
5515            string for COMMITPT's change text.  Leaving the change text
5516            field set NULL won't work, since that means "preserve the original
5517            change text for this delta." */
5518         if (commitpt->text->text == NULL)
5519         {
5520             commitpt->text->text = xstrdup ("");
5521             commitpt->text->len = 0;
5522         }
5523     }
5524     else
5525     {
5526         /* This file is not being inserted at the head, but on a side
5527            branch somewhere.  Make a diff from the previous revision
5528            to the working file. */
5529         switch (diff_exec (tmpfile, workfile, NULL, NULL,
5530                            dargc, dargv, changefile))
5531         {
5532             case 0:
5533             case 1:
5534                 break;
5535             case -1:
5536                 /* FIXME-update-dir: message does not include update_dir.  */
5537                 error (1, errno, "error diffing %s", workfile);
5538                 break;
5539             default:
5540                 /* FIXME-update-dir: message does not include update_dir.  */
5541                 error (1, 0, "error diffing %s", workfile);
5542                 break;
5543         }
5544         /* See the comment above, at the other get_file invocation,
5545            regarding binary vs. text.  */
5546         get_file (changefile, changefile, 
5547                   rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5548                   &dtext->text, &bufsize,
5549                   &dtext->len);
5550         if (dtext->text == NULL)
5551         {
5552             dtext->text = xstrdup ("");
5553             dtext->len = 0;
5554         }
5555     }
5556
5557     run_arg_free_p (dargc, dargv);
5558     free (dargv);
5559
5560     /* Update DELTA linkage.  It is important not to do this before
5561        the very end of RCS_checkin; if an error arises that forces
5562        us to abort checking in, we must not have malformed deltas
5563        partially linked into the tree.
5564
5565        If DELTA and COMMITPT are on different branches, do nothing --
5566        DELTA is linked to the tree through COMMITPT->BRANCHES, and we
5567        don't want to change `next' pointers.
5568
5569        Otherwise, if the nodes are both on the trunk, link DELTA to
5570        COMMITPT; otherwise, link COMMITPT to DELTA. */
5571
5572     if (numdots (commitpt->version) == numdots (delta->version))
5573     {
5574         if (STREQ (commitpt->version, rcs->head))
5575         {
5576             delta->next = rcs->head;
5577             rcs->head = xstrdup (delta->version);
5578         }
5579         else
5580             commitpt->next = xstrdup (delta->version);
5581     }
5582
5583     /* Add DELTA to RCS->VERSIONS. */
5584     if (rcs->versions == NULL)
5585         rcs->versions = getlist();
5586     nodep = getnode();
5587     nodep->type = RCSVERS;
5588     nodep->delproc = rcsvers_delproc;
5589     nodep->data = delta;
5590     nodep->key = delta->version;
5591     (void) addnode (rcs->versions, nodep);
5592         
5593     /* Write the new RCS file, inserting the new delta at COMMITPT. */
5594     if (!(checkin_quiet || really_quiet))
5595     {
5596         cvs_output ("new revision: ", 14);
5597         cvs_output (delta->version, 0);
5598         cvs_output ("; previous revision: ", 21);
5599         cvs_output (commitpt->version, 0);
5600         cvs_output ("\n", 1);
5601     }
5602
5603     RCS_rewrite (rcs, dtext, commitpt->version);
5604
5605     if ((flags & RCS_FLAGS_KEEPFILE) == 0)
5606     {
5607         if (unlink_file (workfile) < 0)
5608             /* FIXME-update-dir: message does not include update_dir.  */
5609             error (1, errno, "cannot remove %s", workfile);
5610     }
5611     if (unlink_file (tmpfile) < 0)
5612         error (0, errno, "cannot remove %s", tmpfile);
5613     free (tmpfile);
5614     if (unlink_file (changefile) < 0)
5615         error (0, errno, "cannot remove %s", changefile);
5616     free (changefile);
5617
5618  checkin_done:
5619     free (workfile);
5620
5621     if (commitpt != NULL && commitpt->text != NULL)
5622     {
5623         freedeltatext (commitpt->text);
5624         commitpt->text = NULL;
5625     }
5626
5627     freedeltatext (dtext);
5628     if (status != 0)
5629     {
5630         /* If delta has not been added to a List, then freeing the Node key
5631          * won't free delta->version.
5632          */
5633         if (delta->version) free (delta->version);
5634         free_rcsvers_contents (delta);
5635     }
5636
5637     return status;
5638 }
5639
5640
5641
5642 /* This structure is passed between RCS_cmp_file and cmp_file_buffer.  */
5643 struct cmp_file_data
5644 {
5645     const char *filename;
5646     FILE *fp;
5647     int different;
5648 };
5649
5650 /* Compare the contents of revision REV1 of RCS file RCS with the
5651    contents of REV2 if given, otherwise, compare with the contents of
5652    the file FILENAME.  OPTIONS is a string for the keyword
5653    expansion options.  Return 0 if the contents of the revision are
5654    the same as the contents of the file, 1 if they are different.  */
5655 int
5656 RCS_cmp_file (RCSNode *rcs, const char *rev1, char **rev1_cache,
5657               const char *rev2, const char *options, const char *filename)
5658 {
5659     int binary;
5660
5661     TRACE (TRACE_FUNCTION, "RCS_cmp_file( %s, %s, %s, %s, %s )",
5662            rcs->path ? rcs->path : "(null)",
5663            rev1 ? rev1 : "(null)", rev2 ? rev2 : "(null)",
5664            options ? options : "(null)", filename ? filename : "(null)");
5665
5666     if (options != NULL && options[0] != '\0')
5667         binary = STREQ (options, "-kb");
5668     else
5669     {
5670         char *expand;
5671
5672         expand = RCS_getexpand (rcs);
5673         if (expand != NULL && STREQ (expand, "b"))
5674             binary = 1;
5675         else
5676             binary = 0;
5677     }
5678
5679 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5680     /* If CVS is to deal properly with special files (when
5681        PreservePermissions is on), the best way is to check out the
5682        revision to a temporary file and call `xcmp' on the two disk
5683        files.  xcmp needs to handle non-regular files properly anyway,
5684        so calling it simplifies RCS_cmp_file.  We *could* just yank
5685        the delta node out of the version tree and look for device
5686        numbers, but writing to disk and calling xcmp is a better
5687        abstraction (therefore probably more robust). -twp */
5688
5689     if (preserve_perms)
5690     {
5691         char *tmp;
5692         int retcode;
5693
5694         tmp = cvs_temp_name();
5695         retcode = RCS_checkout(rcs, NULL, rev, NULL, options, tmp, NULL, NULL);
5696         if (retcode != 0)
5697             return 1;
5698
5699         retcode = xcmp (tmp, filename);
5700         if (CVS_UNLINK (tmp) < 0)
5701             error (0, errno, "cannot remove %s", tmp);
5702         free (tmp);
5703         return retcode;
5704     }
5705     else
5706 #endif
5707     {
5708         FILE *fp;
5709         struct cmp_file_data data;
5710         const char *use_file1;
5711         char *tmpfile = NULL;
5712
5713         if (rev2 != NULL)
5714         {
5715             /* Open & cache rev1 */
5716             tmpfile = cvs_temp_name();
5717             if (RCS_checkout (rcs, NULL, rev1, NULL, options, tmpfile,
5718                               NULL, NULL))
5719                 error (1, errno,
5720                        "cannot check out revision %s of %s",
5721                        rev1, rcs->print_path);
5722             use_file1 = tmpfile;
5723             if (rev1_cache != NULL)
5724                 *rev1_cache = tmpfile;
5725         }
5726         else
5727             use_file1 = filename;
5728
5729         fp = CVS_FOPEN (use_file1, binary ? FOPEN_BINARY_READ : "r");
5730         if (fp == NULL)
5731             /* FIXME-update-dir: should include update_dir in message.  */
5732             error (1, errno, "cannot open file %s for comparing", use_file1);
5733         
5734         data.filename = use_file1;
5735         data.fp = fp;
5736         data.different = 0;
5737         
5738         if (RCS_checkout (rcs, NULL, rev2 ? rev2 : rev1, NULL, options,
5739                           RUN_TTY, cmp_file_buffer, &data ))
5740                 error (1, errno,
5741                        "cannot check out revision %s of %s",
5742                        rev2 ? rev2 : rev1, rcs->print_path);
5743
5744         /* If we have not yet found a difference, make sure that we are at
5745            the end of the file.  */
5746         if (!data.different)
5747         {
5748             if (getc (fp) != EOF)
5749                 data.different = 1;
5750         }
5751         
5752         fclose (fp);
5753         if (rev1_cache == NULL && tmpfile)
5754         {
5755             if (CVS_UNLINK (tmpfile ) < 0)
5756                 error (0, errno, "cannot remove %s", tmpfile);
5757             free (tmpfile);
5758         }
5759
5760         return data.different;
5761     }
5762 }
5763
5764
5765
5766 /* This is a subroutine of RCS_cmp_file.  It is passed to
5767    RCS_checkout.  */
5768 #define CMP_BUF_SIZE (8 * 1024)
5769
5770 static void
5771 cmp_file_buffer (void *callerdat, const char *buffer, size_t len)
5772 {
5773     struct cmp_file_data *data = callerdat;
5774     char *filebuf;
5775
5776     /* If we've already found a difference, we don't need to check
5777        further.  */
5778     if (data->different)
5779         return;
5780
5781     filebuf = xmalloc (len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len);
5782
5783     while (len > 0)
5784     {
5785         size_t checklen;
5786
5787         checklen = len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len;
5788         if (fread (filebuf, 1, checklen, data->fp) != checklen)
5789         {
5790             if (ferror (data->fp))
5791                 error (1, errno, "cannot read file %s for comparing",
5792                        data->filename);
5793             data->different = 1;
5794             free (filebuf);
5795             return;
5796         }
5797
5798         if (memcmp (filebuf, buffer, checklen) != 0)
5799         {
5800             data->different = 1;
5801             free (filebuf);
5802             return;
5803         }
5804
5805         buffer += checklen;
5806         len -= checklen;
5807     }
5808
5809     free (filebuf);
5810 }
5811
5812
5813
5814 /* For RCS file RCS, make symbolic tag TAG point to revision REV.
5815    This validates that TAG is OK for a user to use.  Return value is
5816    -1 for error (and errno is set to indicate the error), positive for
5817    error (and an error message has been printed), or zero for success.  */
5818 int
5819 RCS_settag (RCSNode *rcs, const char *tag, const char *rev)
5820 {
5821     List *symbols;
5822     Node *node;
5823
5824     if (rcs->flags & PARTIAL)
5825         RCS_reparsercsfile (rcs, NULL, NULL);
5826
5827     /* FIXME: This check should be moved to RCS_check_tag.  There is no
5828        reason for it to be here.  */
5829     if (STREQ (tag, TAG_BASE)
5830         || STREQ (tag, TAG_HEAD))
5831     {
5832         /* Print the name of the tag might be considered redundant
5833            with the caller, which also prints it.  Perhaps this helps
5834            clarify why the tag name is considered reserved, I don't
5835            know.  */
5836         error (0, 0, "Attempt to add reserved tag name %s", tag);
5837         return 1;
5838     }
5839
5840     /* A revision number of NULL means use the head or default branch.
5841        If rev is not NULL, it may be a symbolic tag or branch number;
5842        expand it to the correct numeric revision or branch head. */
5843     if (rev == NULL)
5844         rev = rcs->branch ? rcs->branch : rcs->head;
5845
5846     /* At this point rcs->symbol_data may not have been parsed.
5847        Calling RCS_symbols will force it to be parsed into a list
5848        which we can easily manipulate.  */
5849     symbols = RCS_symbols (rcs);
5850     if (symbols == NULL)
5851     {
5852         symbols = getlist ();
5853         rcs->symbols = symbols;
5854     }
5855     node = findnode (symbols, tag);
5856     if (node != NULL)
5857     {
5858         free (node->data);
5859         node->data = xstrdup (rev);
5860     }
5861     else
5862     {
5863         node = getnode ();
5864         node->key = xstrdup (tag);
5865         node->data = xstrdup (rev);
5866         (void)addnode_at_front (symbols, node);
5867     }
5868
5869     return 0;
5870 }
5871
5872
5873
5874 /* Delete the symbolic tag TAG from the RCS file RCS.  Return 0 if
5875    the tag was found (and removed), or 1 if it was not present.  (In
5876    either case, the tag will no longer be in RCS->SYMBOLS.) */
5877 int
5878 RCS_deltag (RCSNode *rcs, const char *tag)
5879 {
5880     List *symbols;
5881     Node *node;
5882     if (rcs->flags & PARTIAL)
5883         RCS_reparsercsfile (rcs, NULL, NULL);
5884
5885     symbols = RCS_symbols (rcs);
5886     if (symbols == NULL)
5887         return 1;
5888
5889     node = findnode (symbols, tag);
5890     if (node == NULL)
5891         return 1;
5892
5893     delnode (node);
5894
5895     return 0;
5896 }
5897
5898
5899
5900 /* Set the default branch of RCS to REV.  */
5901 int
5902 RCS_setbranch (RCSNode *rcs, const char *rev)
5903 {
5904     if (rcs->flags & PARTIAL)
5905         RCS_reparsercsfile (rcs, NULL, NULL);
5906
5907     if (rev && ! *rev)
5908         rev = NULL;
5909
5910     if (rev == NULL && rcs->branch == NULL)
5911         return 0;
5912     if (rev != NULL && rcs->branch != NULL && STREQ (rev, rcs->branch))
5913         return 0;
5914
5915     if (rcs->branch != NULL)
5916         free (rcs->branch);
5917     rcs->branch = xstrdup (rev);
5918
5919     return 0;
5920 }
5921
5922
5923
5924 /* Lock revision REV.  LOCK_QUIET is 1 to suppress output.  FIXME:
5925    Most of the callers only call us because RCS_checkin still tends to
5926    like a lock (a relic of old behavior inherited from the RCS ci
5927    program).  If we clean this up, only "cvs admin -l" will still need
5928    to call RCS_lock.  */
5929
5930 /* FIXME-twp: if a lock owned by someone else is broken, should this
5931    send mail to the lock owner?  Prompt user?  It seems like such an
5932    obscure situation for CVS as almost not worth worrying much
5933    about. */
5934 int
5935 RCS_lock (RCSNode *rcs, const char *rev, int lock_quiet)
5936 {
5937     List *locks;
5938     Node *p;
5939     char *user;
5940     char *xrev = NULL;
5941
5942     if (rcs->flags & PARTIAL)
5943         RCS_reparsercsfile (rcs, NULL, NULL);
5944
5945     locks = RCS_getlocks (rcs);
5946     if (locks == NULL)
5947         locks = rcs->locks = getlist();
5948     user = getcaller();
5949
5950     /* A revision number of NULL means lock the head or default branch. */
5951     if (rev == NULL)
5952         xrev = RCS_head (rcs);
5953     else
5954         xrev = RCS_gettag (rcs, rev, 1, NULL);
5955
5956     /* Make sure that the desired revision exists.  Technically,
5957        we can update the locks list without even checking this,
5958        but RCS 5.7 did this.  And it can't hurt. */
5959     if (xrev == NULL || findnode (rcs->versions, xrev) == NULL)
5960     {
5961         if (!lock_quiet)
5962             error (0, 0, "%s: revision %s absent", rcs->print_path, rev);
5963         free (xrev);
5964         return 1;
5965     }
5966
5967     /* Is this rev already locked? */
5968     p = findnode (locks, xrev);
5969     if (p != NULL)
5970     {
5971         if (STREQ (p->data, user))
5972         {
5973             /* We already own the lock on this revision, so do nothing. */
5974             free (xrev);
5975             return 0;
5976         }
5977
5978 #if 0
5979         /* Well, first of all, "rev" below should be "xrev" to avoid
5980            core dumps.  But more importantly, should we really be
5981            breaking the lock unconditionally?  What CVS 1.9 does (via
5982            RCS) is to prompt "Revision 1.1 is already locked by fred.
5983            Do you want to break the lock? [ny](n): ".  Well, we don't
5984            want to interact with the user (certainly not at the
5985            server/protocol level, and probably not in the command-line
5986            client), but isn't it more sensible to give an error and
5987            let the user run "cvs admin -u" if they want to break the
5988            lock?  */
5989
5990         /* Break the lock. */       
5991         if (!lock_quiet)
5992         {
5993             cvs_output (rev, 0);
5994             cvs_output (" unlocked\n", 0);
5995         }
5996         delnode (p);
5997 #else
5998         error (1, 0, "Revision %s is already locked by %s",
5999                xrev, (char *)p->data);
6000 #endif
6001     }
6002
6003     /* Create a new lock. */
6004     p = getnode();
6005     p->key = xrev;      /* already xstrdupped */
6006     p->data = xstrdup (getcaller());
6007     (void)addnode_at_front (locks, p);
6008
6009     if (!lock_quiet)
6010     {
6011         cvs_output (xrev, 0);
6012         cvs_output (" locked\n", 0);
6013     }
6014
6015     return 0;
6016 }
6017
6018
6019
6020 /* Unlock revision REV.  UNLOCK_QUIET is 1 to suppress output.  FIXME:
6021    Like RCS_lock, this can become a no-op if we do the checkin
6022    ourselves.
6023
6024    If REV is not null and is locked by someone else, break their
6025    lock and notify them.  It is an open issue whether RCS_unlock
6026    queries the user about whether or not to break the lock. */
6027 int
6028 RCS_unlock (RCSNode *rcs, char *rev, int unlock_quiet)
6029 {
6030     Node *lock;
6031     List *locks;
6032     char *user;
6033     char *xrev = NULL;
6034
6035     user = getcaller();
6036     if (rcs->flags & PARTIAL)
6037         RCS_reparsercsfile (rcs, NULL, NULL);
6038
6039     /* If rev is NULL, unlock the revision held by the caller; if more
6040        than one, make the user specify the revision explicitly.  This
6041        differs from RCS which unlocks the latest revision (first in
6042        rcs->locks) held by the caller. */
6043     if (rev == NULL)
6044     {
6045         Node *p;
6046
6047         /* No-ops: attempts to unlock an empty tree or an unlocked file. */
6048         if (rcs->head == NULL)
6049         {
6050             if (!unlock_quiet)
6051                 cvs_outerr ("can't unlock an empty tree\n", 0);
6052             return 0;
6053         }
6054
6055         locks = RCS_getlocks (rcs);
6056         if (locks == NULL)
6057         {
6058             if (!unlock_quiet)
6059                 cvs_outerr ("No locks are set.\n", 0);
6060             return 0;
6061         }
6062
6063         lock = NULL;
6064         for (p = locks->list->next; p != locks->list; p = p->next)
6065         {
6066             if (STREQ (p->data, user))
6067             {
6068                 if (lock != NULL)
6069                 {
6070                     if (!unlock_quiet)
6071                         error (0, 0, "\
6072 %s: multiple revisions locked by %s; please specify one", rcs->print_path, user);
6073                     return 1;
6074                 }
6075                 lock = p;
6076             }
6077         }
6078         if (lock == NULL)
6079         {
6080             if (!unlock_quiet)
6081                 error (0, 0, "No locks are set for %s.\n", user);
6082             return 0;   /* no lock found, ergo nothing to do */
6083         }
6084         xrev = xstrdup (lock->key);
6085     }
6086     else
6087     {
6088         xrev = RCS_gettag (rcs, rev, 1, NULL);
6089         if (xrev == NULL)
6090         {
6091             error (0, 0, "%s: revision %s absent", rcs->print_path, rev);
6092             return 1;
6093         }
6094     }
6095
6096     lock = findnode (RCS_getlocks (rcs), xrev);
6097     if (lock == NULL)
6098     {
6099         /* This revision isn't locked. */
6100         free (xrev);
6101         return 0;
6102     }
6103
6104     if (! STREQ (lock->data, user))
6105     {
6106         /* If the revision is locked by someone else, notify
6107            them.  Note that this shouldn't ever happen if RCS_unlock
6108            is called with a NULL revision, since that means "whatever
6109            revision is currently locked by the caller." */
6110         char *repos, *workfile;
6111         if (!unlock_quiet)
6112             error (0, 0, "\
6113 %s: revision %s locked by %s; breaking lock", rcs->print_path, xrev,
6114                    (char *)lock->data);
6115         repos = xstrdup (rcs->path);
6116         workfile = strrchr (repos, '/');
6117         *workfile++ = '\0';
6118         notify_do ('C', workfile, NULL, user, NULL, NULL, repos);
6119         free (repos);
6120     }
6121
6122     delnode (lock);
6123     if (!unlock_quiet)
6124     {
6125         cvs_output (xrev, 0);
6126         cvs_output (" unlocked\n", 0);
6127     }
6128
6129     free (xrev);
6130     return 0;
6131 }
6132
6133
6134
6135 /* Add USER to the access list of RCS.  Do nothing if already present.
6136    FIXME-twp: check syntax of USER to make sure it's a valid id. */
6137
6138 void
6139 RCS_addaccess (RCSNode *rcs, char *user)
6140 {
6141     char *access, *a;
6142
6143     if (rcs->flags & PARTIAL)
6144         RCS_reparsercsfile (rcs, NULL, NULL);
6145
6146     if (rcs->access == NULL)
6147         rcs->access = xstrdup (user);
6148     else
6149     {
6150         access = xstrdup (rcs->access);
6151         for (a = strtok (access, " "); a != NULL; a = strtok (NULL, " "))
6152         {
6153             if (STREQ (a, user))
6154             {
6155                 free (access);
6156                 return;
6157             }
6158         }
6159         free (access);
6160         rcs->access = xrealloc (rcs->access,
6161                                 strlen (rcs->access) + strlen (user) + 2);
6162         strcat (rcs->access, " ");
6163         strcat (rcs->access, user);
6164     }
6165 }
6166
6167
6168
6169 /* Remove USER from the access list of RCS. */
6170 void
6171 RCS_delaccess (RCSNode *rcs, char *user)
6172 {
6173     char *p, *s;
6174     int ulen;
6175
6176     if (rcs->flags & PARTIAL)
6177         RCS_reparsercsfile (rcs, NULL, NULL);
6178
6179     if (rcs->access == NULL)
6180         return;
6181
6182     if (user == NULL)
6183     {
6184         free (rcs->access);
6185         rcs->access = NULL;
6186         return;
6187     }
6188
6189     p = rcs->access;
6190     ulen = strlen (user);
6191     while (p != NULL)
6192     {
6193         if (strncmp (p, user, ulen) == 0 && (p[ulen] == '\0' || p[ulen] == ' '))
6194             break;
6195         p = strchr (p, ' ');
6196         if (p != NULL)
6197             ++p;
6198     }
6199
6200     if (p == NULL)
6201         return;
6202
6203     s = p + ulen;
6204     while (*s != '\0')
6205         *p++ = *s++;
6206     *p = '\0';
6207 }
6208
6209
6210
6211 char *
6212 RCS_getaccess (RCSNode *rcs)
6213 {
6214     if (rcs->flags & PARTIAL)
6215         RCS_reparsercsfile (rcs, NULL, NULL);
6216
6217     return rcs->access;
6218 }
6219
6220
6221
6222 /* Return a nonzero value if the revision specified by ARG is found.  */
6223 static int
6224 findtag (Node *node, void *arg)
6225 {
6226     char *rev = arg;
6227
6228     if (STREQ (node->data, rev))
6229         return 1;
6230     else
6231         return 0;
6232 }
6233
6234
6235
6236 /* Delete revisions between REV1 and REV2.  The changes between the two
6237    revisions must be collapsed, and the result stored in the revision
6238    immediately preceding the lower one.  Return 0 for successful completion,
6239    1 otherwise.
6240
6241    Solution: check out the revision preceding REV1 and the revision
6242    following REV2.  Use call_diff to find aggregate diffs between
6243    these two revisions, and replace the delta text for the latter one
6244    with the new aggregate diff.  Alternatively, we could write a
6245    function that takes two change texts and combines them to produce a
6246    new change text, without checking out any revs or calling diff.  It
6247    would be hairy, but so, so cool.
6248
6249    If INCLUSIVE is set, then TAG1 and TAG2, if non-NULL, tell us to
6250    delete that revision as well (cvs admin -o tag1:tag2).  If clear,
6251    delete up to but not including that revision (cvs admin -o tag1::tag2).
6252    This does not affect TAG1 or TAG2 being NULL; the meaning of the start
6253    point in ::tag2 and :tag2 is the same and likewise for end points.  */
6254 int
6255 RCS_delete_revs (RCSNode *rcs, char *tag1, char *tag2, int inclusive)
6256 {
6257     char *next;
6258     Node *nodep;
6259     RCSVers *revp = NULL;
6260     RCSVers *beforep;
6261     int status, found;
6262     int save_noexec;
6263
6264     char *branchpoint = NULL;
6265     char *rev1 = NULL;
6266     char *rev2 = NULL;
6267     int rev1_inclusive = inclusive;
6268     int rev2_inclusive = inclusive;
6269     char *before = NULL;
6270     char *after = NULL;
6271     char *beforefile = NULL;
6272     char *afterfile = NULL;
6273     char *outfile = NULL;
6274
6275     if (tag1 == NULL && tag2 == NULL)
6276         return 0;
6277
6278     /* Assume error status until everything is finished. */
6279     status = 1;
6280
6281     /* Make sure both revisions exist. */
6282     if (tag1 != NULL)
6283     {
6284         rev1 = RCS_gettag (rcs, tag1, 1, NULL);
6285         if (rev1 == NULL || (nodep = findnode (rcs->versions, rev1)) == NULL)
6286         {
6287             error (0, 0, "%s: Revision %s doesn't exist.", rcs->print_path, tag1);
6288             goto delrev_done;
6289         }
6290     }
6291     if (tag2 != NULL)
6292     {
6293         rev2 = RCS_gettag (rcs, tag2, 1, NULL);
6294         if (rev2 == NULL || (nodep = findnode (rcs->versions, rev2)) == NULL)
6295         {
6296             error (0, 0, "%s: Revision %s doesn't exist.", rcs->print_path, tag2);
6297             goto delrev_done;
6298         }
6299     }
6300
6301     /* If rev1 is on the trunk and rev2 is NULL, rev2 should be
6302        RCS->HEAD.  (*Not* RCS_head(rcs), which may return rcs->branch
6303        instead.)  We need to check this special case early, in order
6304        to make sure that rev1 and rev2 get ordered correctly. */
6305     if (rev2 == NULL && numdots (rev1) == 1)
6306     {
6307         rev2 = xstrdup (rcs->head);
6308         rev2_inclusive = 1;
6309     }
6310
6311     if (rev2 == NULL)
6312         rev2_inclusive = 1;
6313
6314     if (rev1 != NULL && rev2 != NULL)
6315     {
6316         /* A range consisting of a branch number means the latest revision
6317            on that branch. */
6318         if (RCS_isbranch (rcs, rev1) && STREQ (rev1, rev2))
6319         {
6320             char *tmp = RCS_getbranch (rcs, rev1, 0);
6321             free (rev1);
6322             free (rev2);
6323             rev1 = rev2 = tmp;
6324         }
6325         else
6326         {
6327             /* Make sure REV1 and REV2 are ordered correctly (in the
6328                same order as the next field).  For revisions on the
6329                trunk, REV1 should be higher than REV2; for branches,
6330                REV1 should be lower.  */
6331             /* Shouldn't we just be giving an error in the case where
6332                the user specifies the revisions in the wrong order
6333                (that is, always swap on the trunk, never swap on a
6334                branch, in the non-error cases)?  It is not at all
6335                clear to me that users who specify -o 1.4:1.2 really
6336                meant to type -o 1.2:1.4, and the out of order usage
6337                has never been documented, either by cvs.texinfo or
6338                rcs(1).  */
6339             char *temp;
6340             int temp_inclusive;
6341             if (numdots (rev1) == 1)
6342             {
6343                 if (compare_revnums (rev1, rev2) <= 0)
6344                 {
6345                     temp = rev2;
6346                     rev2 = rev1;
6347                     rev1 = temp;
6348
6349                     temp_inclusive = rev2_inclusive;
6350                     rev2_inclusive = rev1_inclusive;
6351                     rev1_inclusive = temp_inclusive;
6352                 }
6353             }
6354             else if (compare_revnums (rev1, rev2) > 0)
6355             {
6356                 temp = rev2;
6357                 rev2 = rev1;
6358                 rev1 = temp;
6359
6360                 temp_inclusive = rev2_inclusive;
6361                 rev2_inclusive = rev1_inclusive;
6362                 rev1_inclusive = temp_inclusive;
6363             }
6364         }
6365     }
6366
6367     /* Basically the same thing; make sure that the ordering is what we
6368        need.  */
6369     if (rev1 == NULL)
6370     {
6371         assert (rev2 != NULL);
6372         if (numdots (rev2) == 1)
6373         {
6374             /* Swap rev1 and rev2.  */
6375             int temp_inclusive;
6376
6377             rev1 = rev2;
6378             rev2 = NULL;
6379
6380             temp_inclusive = rev2_inclusive;
6381             rev2_inclusive = rev1_inclusive;
6382             rev1_inclusive = temp_inclusive;
6383         }
6384     }
6385
6386     /* Put the revision number preceding the first one to delete into
6387        BEFORE (where "preceding" means according to the next field).
6388        If the first revision to delete is the first revision on its
6389        branch (e.g. 1.3.2.1), BEFORE should be the node on the trunk
6390        at which the branch is rooted.  If the first revision to delete
6391        is the head revision of the trunk, set BEFORE to NULL.
6392
6393        Note that because BEFORE may not be on the same branch as REV1,
6394        it is not very handy for navigating the revision tree.  It's
6395        most useful just for checking out the revision preceding REV1. */
6396     before = NULL;
6397     branchpoint = RCS_getbranchpoint (rcs, rev1 != NULL ? rev1 : rev2);
6398     if (rev1 == NULL)
6399     {
6400         rev1 = xstrdup (branchpoint);
6401         if (numdots (branchpoint) > 1)
6402         {
6403             char *bp;
6404             bp = strrchr (branchpoint, '.');
6405             while (*--bp != '.')
6406                 ;
6407             *bp = '\0';
6408             /* Note that this is exclusive, always, because the inclusive
6409                flag doesn't affect the meaning when rev1 == NULL.  */
6410             before = xstrdup (branchpoint);
6411             *bp = '.';
6412         }
6413     }
6414     else if (! STREQ (rev1, branchpoint))
6415     {
6416         /* Walk deltas from BRANCHPOINT on, looking for REV1. */
6417         nodep = findnode (rcs->versions, branchpoint);
6418         revp = nodep->data;
6419         while (revp->next != NULL && ! STREQ (revp->next, rev1))
6420         {
6421             revp = nodep->data;
6422             nodep = findnode (rcs->versions, revp->next);
6423         }
6424         if (revp->next == NULL)
6425         {
6426             error (0, 0, "%s: Revision %s doesn't exist.", rcs->print_path, rev1);
6427             goto delrev_done;
6428         }
6429         if (rev1_inclusive)
6430             before = xstrdup (revp->version);
6431         else
6432         {
6433             before = rev1;
6434             nodep = findnode (rcs->versions, before);
6435             rev1 = xstrdup (((RCSVers *)nodep->data)->next);
6436         }
6437     }
6438     else if (!rev1_inclusive)
6439     {
6440         before = rev1;
6441         nodep = findnode (rcs->versions, before);
6442         rev1 = xstrdup (((RCSVers *)nodep->data)->next);
6443     }
6444     else if (numdots (branchpoint) > 1)
6445     {
6446         /* Example: rev1 is "1.3.2.1", branchpoint is "1.3.2.1".
6447            Set before to "1.3".  */
6448         char *bp;
6449         bp = strrchr (branchpoint, '.');
6450         while (*--bp != '.')
6451             ;
6452         *bp = '\0';
6453         before = xstrdup (branchpoint);
6454         *bp = '.';
6455     }
6456
6457     /* If any revision between REV1 and REV2 is locked or is a branch point,
6458        we can't delete that revision and must abort. */
6459     after = NULL;
6460     next = rev1;
6461     found = 0;
6462     while (!found && next != NULL)
6463     {
6464         nodep = findnode (rcs->versions, next);
6465         revp = nodep->data;
6466
6467         if (rev2 != NULL)
6468             found = STREQ (revp->version, rev2);
6469         next = revp->next;
6470
6471         if ((!found && next != NULL) || rev2_inclusive || rev2 == NULL)
6472         {
6473             if (findnode (RCS_getlocks (rcs), revp->version))
6474             {
6475                 error (0, 0, "%s: can't remove locked revision %s",
6476                        rcs->print_path,
6477                        revp->version);
6478                 goto delrev_done;
6479             }
6480             if (revp->branches != NULL)
6481             {
6482                 error (0, 0, "%s: can't remove branch point %s",
6483                        rcs->print_path,
6484                        revp->version);
6485                 goto delrev_done;
6486             }
6487
6488             /* Doing this only for the :: syntax is for compatibility.
6489                See cvs.texinfo for somewhat more discussion.  */
6490             if (!inclusive
6491                 && walklist (RCS_symbols (rcs), findtag, revp->version))
6492             {
6493                 /* We don't print which file this happens to on the theory
6494                    that the caller will print the name of the file in a
6495                    more useful fashion (fullname not rcs->path).  */
6496                 error (0, 0, "cannot remove revision %s because it has tags",
6497                        revp->version);
6498                 goto delrev_done;
6499             }
6500
6501             /* It's misleading to print the `deleting revision' output
6502                here, since we may not actually delete these revisions.
6503                But that's how RCS does it.  Bleah.  Someday this should be
6504                moved to the point where the revs are actually marked for
6505                deletion. -twp */
6506             cvs_output ("deleting revision ", 0);
6507             cvs_output (revp->version, 0);
6508             cvs_output ("\n", 1);
6509         }
6510     }
6511
6512     if (rev2 == NULL)
6513         ;
6514     else if (found)
6515     {
6516         if (rev2_inclusive)
6517             after = xstrdup (next);
6518         else
6519             after = xstrdup (revp->version);
6520     }
6521     else if (!inclusive)
6522     {
6523         /* In the case of an empty range, for example 1.2::1.2 or
6524            1.2::1.3, we want to just do nothing.  */
6525         status = 0;
6526         goto delrev_done;
6527     }
6528     else
6529     {
6530         /* This looks fishy in the cases where tag1 == NULL or tag2 == NULL.
6531            Are those cases really impossible?  */
6532         assert (tag1 != NULL);
6533         assert (tag2 != NULL);
6534
6535         error (0, 0, "%s: invalid revision range %s:%s", rcs->print_path,
6536                tag1, tag2);
6537         goto delrev_done;
6538     }
6539
6540     if (after == NULL && before == NULL)
6541     {
6542         /* The user is trying to delete all revisions.  While an
6543            RCS file without revisions makes sense to RCS (e.g. the
6544            state after "rcs -i"), CVS has never been able to cope with
6545            it.  So at least for now we just make this an error.
6546
6547            We don't include rcs->path in the message since "cvs admin"
6548            already printed "RCS file:" and the name.  */
6549         error (1, 0, "attempt to delete all revisions");
6550     }
6551
6552     /* The conditionals at this point get really hairy.  Here is the
6553        general idea:
6554
6555        IF before != NULL and after == NULL
6556          THEN don't check out any revisions, just delete them
6557        IF before == NULL and after != NULL
6558          THEN only check out after's revision, and use it for the new deltatext
6559        ELSE
6560          check out both revisions and diff -n them.  This could use
6561          RCS_exec_rcsdiff with some changes, like being able
6562          to suppress diagnostic messages and to direct output. */
6563
6564     if (after != NULL)
6565     {
6566         char *diffbuf;
6567         size_t bufsize, len;
6568
6569 #if defined (WOE32) && !defined (__CYGWIN32__)
6570         /* FIXME: This is an awful kludge, but at least until I have
6571            time to work on it a little more and test it, I'd rather
6572            give a fatal error than corrupt the file.  I think that we
6573            need to use "-kb" and "--binary" and "rb" to get_file
6574            (probably can do it always, not just for binary files, if
6575            we are consistent between the RCS_checkout and the diff).  */
6576         {
6577             char *expand = RCS_getexpand (rcs);
6578             if (expand != NULL && STREQ (expand, "b"))
6579                 error (1, 0,
6580                    "admin -o not implemented yet for binary on this system");
6581         }
6582 #endif /* WOE32 */
6583
6584         afterfile = cvs_temp_name();
6585         status = RCS_checkout (rcs, NULL, after, NULL, "-ko", afterfile,
6586                                NULL, NULL);
6587         if (status > 0)
6588             goto delrev_done;
6589
6590         if (before == NULL)
6591         {
6592             /* We are deleting revisions from the head of the tree,
6593                so must create a new head. */
6594             diffbuf = NULL;
6595             bufsize = 0;
6596             get_file (afterfile, afterfile, "r", &diffbuf, &bufsize, &len);
6597
6598             save_noexec = noexec;
6599             noexec = 0;
6600             if (unlink_file (afterfile) < 0)
6601                 error (0, errno, "cannot remove %s", afterfile);
6602             noexec = save_noexec;
6603
6604             free (afterfile);
6605             afterfile = NULL;
6606
6607             free (rcs->head);
6608             rcs->head = xstrdup (after);
6609         }
6610         else
6611         {
6612             int dargc = 0;
6613             size_t darg_allocated = 0;
6614             char **dargv = NULL;
6615
6616             beforefile = cvs_temp_name();
6617             status = RCS_checkout (rcs, NULL, before, NULL, "-ko", beforefile,
6618                                    NULL, NULL);
6619             if (status > 0)
6620                 goto delrev_done;
6621
6622             outfile = cvs_temp_name();
6623             run_add_arg_p (&dargc, &darg_allocated, &dargv, "-a");
6624             run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n");
6625             status = diff_exec (beforefile, afterfile, NULL, NULL,
6626                                 dargc, dargv, outfile);
6627             run_arg_free_p (dargc, dargv);
6628             free (dargv);
6629
6630             if (status == 2)
6631             {
6632                 /* Not sure we need this message; will diff_exec already
6633                    have printed an error?  */
6634                 error (0, 0, "%s: could not diff", rcs->print_path);
6635                 status = 1;
6636                 goto delrev_done;
6637             }
6638
6639             diffbuf = NULL;
6640             bufsize = 0;
6641             get_file (outfile, outfile, "r", &diffbuf, &bufsize, &len);
6642         }
6643
6644         /* Save the new change text in after's delta node. */
6645         nodep = findnode (rcs->versions, after);
6646         revp = nodep->data;
6647
6648         assert (revp->text == NULL);
6649
6650         revp->text = xmalloc (sizeof (Deltatext));
6651         memset (revp->text, 0, sizeof (Deltatext));
6652         revp->text->version = xstrdup (revp->version);
6653         revp->text->text = diffbuf;
6654         revp->text->len = len;
6655
6656         /* If DIFFBUF is NULL, it means that OUTFILE is empty and that
6657            there are no differences between the two revisions.  In that
6658            case, we want to force RCS_copydeltas to write an empty string
6659            for the new change text (leaving the text field set NULL
6660            means "preserve the original change text for this delta," so
6661            we don't want that). */
6662         if (revp->text->text == NULL)
6663             revp->text->text = xstrdup ("");
6664     }
6665
6666     /* Walk through the revisions (again) to mark each one as
6667        outdated.  (FIXME: would it be safe to use the `dead' field for
6668        this?  Doubtful.) */
6669     for (next = rev1;
6670          next != NULL && (after == NULL || ! STREQ (next, after));
6671          next = revp->next)
6672     {
6673         nodep = findnode (rcs->versions, next);
6674         revp = nodep->data;
6675         revp->outdated = 1;
6676     }
6677
6678     /* Update delta links.  If BEFORE == NULL, we're changing the
6679        head of the tree and don't need to update any `next' links. */
6680     if (before != NULL)
6681     {
6682         /* If REV1 is the first node on its branch, then BEFORE is its
6683            root node (on the trunk) and we have to update its branches
6684            list.  Otherwise, BEFORE is on the same branch as AFTER, and
6685            we can just change BEFORE's `next' field to point to AFTER.
6686            (This should be safe: since findnode manages its lists via
6687            the `hashnext' and `hashprev' fields, rather than `next' and
6688            `prev', mucking with `next' and `prev' should not corrupt the
6689            delta tree's internal structure.  Much. -twp) */
6690
6691         if (rev1 == NULL)
6692             /* beforep's ->next field already should be equal to after,
6693                which I think is always NULL in this case.  */
6694             ;
6695         else if (STREQ (rev1, branchpoint))
6696         {
6697             nodep = findnode (rcs->versions, before);
6698             revp = nodep->data;
6699             nodep = revp->branches->list->next;
6700             while (nodep != revp->branches->list &&
6701                    ! STREQ (nodep->key, rev1))
6702                 nodep = nodep->next;
6703             assert (nodep != revp->branches->list);
6704             if (after == NULL)
6705                 delnode (nodep);
6706             else
6707             {
6708                 free (nodep->key);
6709                 nodep->key = xstrdup (after);
6710             }
6711         }
6712         else
6713         {
6714             nodep = findnode (rcs->versions, before);
6715             beforep = nodep->data;
6716             free (beforep->next);
6717             beforep->next = xstrdup (after);
6718         }
6719     }
6720
6721     status = 0;
6722
6723  delrev_done:
6724     if (rev1 != NULL)
6725         free (rev1);
6726     if (rev2 && rev2 != rev1)
6727         free (rev2);
6728     if (branchpoint != NULL)
6729         free (branchpoint);
6730     if (before != NULL)
6731         free (before);
6732     if (after != NULL)
6733         free (after);
6734
6735     save_noexec = noexec;
6736     noexec = 0;
6737     if (beforefile != NULL)
6738     {
6739         if (unlink_file (beforefile) < 0)
6740             error (0, errno, "cannot remove %s", beforefile);
6741         free (beforefile);
6742     }
6743     if (afterfile != NULL)
6744     {
6745         if (unlink_file (afterfile) < 0)
6746             error (0, errno, "cannot remove %s", afterfile);
6747         free (afterfile);
6748     }
6749     if (outfile != NULL)
6750     {
6751         if (unlink_file (outfile) < 0)
6752             error (0, errno, "cannot remove %s", outfile);
6753         free (outfile);
6754     }
6755     noexec = save_noexec;
6756
6757     return status;
6758 }
6759
6760
6761
6762 /*
6763  * TRUE if there exists a symbolic tag "tag" in file.
6764  */
6765 int 
6766 RCS_exist_tag (RCSNode *rcs, char *tag)
6767 {
6768
6769     assert (rcs != NULL);
6770
6771     if (findnode (RCS_symbols (rcs), tag))
6772     return 1;
6773     return 0;
6774
6775 }
6776
6777
6778
6779 /*
6780  * TRUE if RCS revision number "rev" exists.
6781  * This includes magic branch revisions, not found in rcs->versions, 
6782  * but only in rcs->symbols, requiring a list walk to find them.
6783  * Take advantage of list walk callback function already used by 
6784  * RCS_delete_revs, above.
6785  */
6786 int
6787 RCS_exist_rev (RCSNode *rcs, char *rev)
6788 {
6789
6790     assert (rcs != NULL);
6791
6792     if (rcs->flags & PARTIAL)
6793         RCS_reparsercsfile (rcs, NULL, NULL);
6794
6795     if (findnode(rcs->versions, rev) != 0)
6796         return 1;
6797
6798     if (walklist (RCS_symbols(rcs), findtag, rev) != 0)
6799         return 1;
6800
6801     return 0;
6802
6803 }
6804
6805
6806
6807
6808 /* RCS_deltas and friends.  Processing of the deltas in RCS files.  */
6809 struct line
6810 {
6811     /* Text of this line.  Part of the same malloc'd block as the struct
6812        line itself (we probably should use the "struct hack" (char text[1])
6813        and save ourselves sizeof (char *) bytes).  Does not include \n;
6814        instead has_newline indicates the presence or absence of \n.  */
6815     char *text;
6816     /* Length of this line, not counting \n if has_newline is true.  */
6817     size_t len;
6818     /* Version in which it was introduced.  */
6819     RCSVers *vers;
6820     /* Nonzero if this line ends with \n.  This will always be true
6821        except possibly for the last line.  */
6822     int has_newline;
6823     /* Number of pointers to this struct line.  */
6824     int refcount;
6825 };
6826
6827 struct linevector
6828 {
6829     /* How many lines in use for this linevector?  */
6830     unsigned int nlines;
6831     /* How many lines allocated for this linevector?  */
6832     unsigned int lines_alloced;
6833     /* Pointer to array containing a pointer to each line.  */
6834     struct line **vector;
6835 };
6836
6837
6838
6839 /* Initialize *VEC to be a linevector with no lines.  */
6840 static void
6841 linevector_init (struct linevector *vec)
6842 {
6843     vec->lines_alloced = 0;
6844     vec->nlines = 0;
6845     vec->vector = NULL;
6846 }
6847
6848
6849
6850 /* Given some text TEXT, add each of its lines to VEC before line POS
6851    (where line 0 is the first line).  The last line in TEXT may or may
6852    not be \n terminated.
6853    Set the version for each of the new lines to VERS.  This
6854    function returns non-zero for success.  It returns zero if the line
6855    number is out of range.
6856
6857    Each of the lines in TEXT are copied to space which is managed with
6858    the linevector (and freed by linevector_free).  So the caller doesn't
6859    need to keep TEXT around after the call to this function.  */
6860 static int
6861 linevector_add (struct linevector *vec, const char *text, size_t len,
6862                 RCSVers *vers, unsigned int pos)
6863 {
6864     const char *textend;
6865     unsigned int i;
6866     unsigned int nnew;
6867     const char *p;
6868     const char *nextline_text;
6869     size_t nextline_len;
6870     int nextline_newline;
6871     struct line *q;
6872
6873     if (len == 0)
6874         return 1;
6875
6876     textend = text + len;
6877
6878     /* Count the number of lines we will need to add.  */
6879     nnew = 1;
6880     for (p = text; p < textend; ++p)
6881         if (*p == '\n' && p + 1 < textend)
6882             ++nnew;
6883
6884     /* Expand VEC->VECTOR if needed.  */
6885     if (vec->nlines + nnew >= vec->lines_alloced)
6886     {
6887         if (vec->lines_alloced == 0)
6888             vec->lines_alloced = 10;
6889         while (vec->nlines + nnew >= vec->lines_alloced)
6890             vec->lines_alloced *= 2;
6891         vec->vector = xnrealloc (vec->vector,
6892                                  vec->lines_alloced, sizeof (*vec->vector));
6893     }
6894
6895     /* Make room for the new lines in VEC->VECTOR.  */
6896     for (i = vec->nlines + nnew - 1; i >= pos + nnew; --i)
6897         vec->vector[i] = vec->vector[i - nnew];
6898
6899     if (pos > vec->nlines)
6900         return 0;
6901
6902     /* Actually add the lines, to VEC->VECTOR.  */
6903     i = pos;
6904     nextline_text = text;
6905     nextline_newline = 0;
6906     for (p = text; p < textend; ++p)
6907         if (*p == '\n')
6908         {
6909             nextline_newline = 1;
6910             if (p + 1 == textend)
6911                 /* If there are no characters beyond the last newline, we
6912                    don't consider it another line.  */
6913                 break;
6914             nextline_len = p - nextline_text;
6915             q = xmalloc (sizeof (struct line) + nextline_len);
6916             q->vers = vers;
6917             q->text = (char *)q + sizeof (struct line);
6918             q->len = nextline_len;
6919             q->has_newline = nextline_newline;
6920             q->refcount = 1;
6921             memcpy (q->text, nextline_text, nextline_len);
6922             vec->vector[i++] = q;
6923
6924             nextline_text = (char *)p + 1;
6925             nextline_newline = 0;
6926         }
6927     nextline_len = p - nextline_text;
6928     q = xmalloc (sizeof (struct line) + nextline_len);
6929     q->vers = vers;
6930     q->text = (char *)q + sizeof (struct line);
6931     q->len = nextline_len;
6932     q->has_newline = nextline_newline;
6933     q->refcount = 1;
6934     memcpy (q->text, nextline_text, nextline_len);
6935     vec->vector[i] = q;
6936
6937     vec->nlines += nnew;
6938
6939     return 1;
6940 }
6941
6942
6943
6944 /* Remove NLINES lines from VEC at position POS (where line 0 is the
6945    first line).  */
6946 static void
6947 linevector_delete (struct linevector *vec, unsigned int pos,
6948                    unsigned int nlines)
6949 {
6950     unsigned int i;
6951     unsigned int last;
6952
6953     last = vec->nlines - nlines;
6954     for (i = pos; i < pos + nlines; ++i)
6955     {
6956         if (--vec->vector[i]->refcount == 0)
6957             free (vec->vector[i]);
6958     }
6959     for (i = pos; i < last; ++i)
6960         vec->vector[i] = vec->vector[i + nlines];
6961     vec->nlines -= nlines;
6962 }
6963
6964
6965
6966 /* Copy FROM to TO, copying the vectors but not the lines pointed to.  */
6967 static void
6968 linevector_copy (struct linevector *to, struct linevector *from)
6969 {
6970     unsigned int ln;
6971
6972     for (ln = 0; ln < to->nlines; ++ln)
6973     {
6974         if (--to->vector[ln]->refcount == 0)
6975             free (to->vector[ln]);
6976     }
6977     if (from->nlines > to->lines_alloced)
6978     {
6979         if (to->lines_alloced == 0)
6980             to->lines_alloced = 10;
6981         while (from->nlines > to->lines_alloced)
6982             to->lines_alloced *= 2;
6983         to->vector = xnrealloc (to->vector,
6984                                 to->lines_alloced,
6985                                 sizeof (*to->vector));
6986     }
6987     memcpy (to->vector, from->vector,
6988             xtimes (from->nlines, sizeof (*to->vector)));
6989     to->nlines = from->nlines;
6990     for (ln = 0; ln < to->nlines; ++ln)
6991         ++to->vector[ln]->refcount;
6992 }
6993
6994
6995
6996 /* Free storage associated with linevector.  */
6997 static void
6998 linevector_free (struct linevector *vec)
6999 {
7000     unsigned int ln;
7001
7002     if (vec->vector != NULL)
7003     {
7004         for (ln = 0; ln < vec->nlines; ++ln)
7005             if (--vec->vector[ln]->refcount == 0)
7006                 free (vec->vector[ln]);
7007
7008         free (vec->vector);
7009     }
7010 }
7011
7012
7013
7014 /* Given a textual string giving the month (1-12), terminated with any
7015    character not recognized by atoi, return the 3 character name to
7016    print it with.  I do not think it is a good idea to change these
7017    strings based on the locale; they are standard abbreviations (for
7018    example in rfc822 mail messages) which should be widely understood.
7019    Returns a pointer into static readonly storage.  */
7020 static const char *
7021 month_printname (const char *month)
7022 {
7023     static const char *const months[] =
7024       {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
7025          "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
7026     int mnum;
7027
7028     mnum = atoi (month);
7029     if (mnum < 1 || mnum > 12)
7030         return "???";
7031     return months[mnum - 1];
7032 }
7033
7034
7035
7036 /* Apply changes to the line vector LINES.  DIFFBUF is a buffer of
7037    length DIFFLEN holding the change text from an RCS file (the output
7038    of diff -n).  NAME is used in error messages.  The VERS field of
7039    any line added is set to ADDVERS.  The VERS field of any line
7040    deleted is set to DELVERS, unless DELVERS is NULL, in which case
7041    the VERS field of deleted lines is unchanged.  The function returns
7042    non-zero if the change text is applied successfully.  It returns
7043    zero if the change text does not appear to apply to LINES (e.g., a
7044    line number is invalid).  If the change text is improperly
7045    formatted (e.g., it is not the output of diff -n), the function
7046    calls error with a status of 1, causing the program to exit.  */
7047 static int
7048 apply_rcs_changes (struct linevector *lines, const char *diffbuf,
7049                    size_t difflen, const char *name, RCSVers *addvers,
7050                    RCSVers *delvers)
7051 {
7052     const char *p;
7053     const char *q;
7054     int op;
7055     /* The RCS format throws us for a loop in that the deltafrags (if
7056        we define a deltafrag as an add or a delete) need to be applied
7057        in reverse order.  So we stick them into a linked list.  */
7058     struct deltafrag {
7059         enum {FRAG_ADD, FRAG_DELETE} type;
7060         unsigned long pos;
7061         unsigned long nlines;
7062         const char *new_lines;
7063         size_t len;
7064         struct deltafrag *next;
7065     };
7066     struct deltafrag *dfhead;
7067     struct deltafrag *df;
7068     int err;
7069
7070     dfhead = NULL;
7071     for (p = diffbuf; p != NULL && p < diffbuf + difflen; )
7072     {
7073         op = *p++;
7074         if (op != 'a' && op != 'd')
7075             /* Can't just skip over the deltafrag, because the value
7076                of op determines the syntax.  */
7077             error (1, 0, "unrecognized operation '\\x%x' in %s",
7078                    op, name);
7079         df = xmalloc (sizeof (struct deltafrag));
7080         df->next = dfhead;
7081         dfhead = df;
7082         df->pos = strtoul (p, (char **) &q, 10);
7083
7084         if (p == q)
7085             error (1, 0, "number expected in %s", name);
7086         p = q;
7087         if (*p++ != ' ')
7088             error (1, 0, "space expected in %s", name);
7089         df->nlines = strtoul (p, (char **) &q, 10);
7090         if (p == q)
7091             error (1, 0, "number expected in %s", name);
7092         p = q;
7093         if (*p++ != '\012')
7094             error (1, 0, "linefeed expected in %s", name);
7095
7096         if (op == 'a')
7097         {
7098             unsigned int i;
7099
7100             df->type = FRAG_ADD;
7101             i = df->nlines;
7102             /* The text we want is the number of lines specified, or
7103                until the end of the value, whichever comes first (it
7104                will be the former except in the case where we are
7105                adding a line which does not end in newline).  */
7106             for (q = p; i != 0; ++q)
7107                 if (*q == '\n')
7108                     --i;
7109                 else if (q == diffbuf + difflen)
7110                 {
7111                     if (i != 1)
7112                         error (1, 0, "premature end of change in %s", name);
7113                     else
7114                         break;
7115                 }
7116
7117             /* Stash away a pointer to the text we are adding.  */
7118             df->new_lines = p;
7119             df->len = q - p;
7120
7121             p = q;
7122         }
7123         else
7124         {
7125             /* Correct for the fact that line numbers in RCS files
7126                start with 1.  */
7127             --df->pos;
7128
7129             assert (op == 'd');
7130             df->type = FRAG_DELETE;
7131         }
7132     }
7133
7134     err = 0;
7135     for (df = dfhead; df != NULL;)
7136     {
7137         unsigned int ln;
7138
7139         /* Once an error is encountered, just free the rest of the list and
7140          * return.
7141          */
7142         if (!err)
7143             switch (df->type)
7144             {
7145             case FRAG_ADD:
7146                 if (! linevector_add (lines, df->new_lines, df->len, addvers,
7147                                       df->pos))
7148                     err = 1;
7149                 break;
7150             case FRAG_DELETE:
7151                 if (df->pos > lines->nlines
7152                     || df->pos + df->nlines > lines->nlines)
7153                     return 0;
7154                 if (delvers != NULL)
7155                     for (ln = df->pos; ln < df->pos + df->nlines; ++ln)
7156                         lines->vector[ln]->vers = delvers;
7157                 linevector_delete (lines, df->pos, df->nlines);
7158                 break;
7159             }
7160
7161         df = df->next;
7162         free (dfhead);
7163         dfhead = df;
7164     }
7165
7166     return !err;
7167 }
7168
7169
7170
7171 /* Apply an RCS change text to a buffer.  The function name starts
7172    with rcs rather than RCS because this does not take an RCSNode
7173    argument.  NAME is used in error messages.  TEXTBUF is the text
7174    buffer to change, and TEXTLEN is the size.  DIFFBUF and DIFFLEN are
7175    the change buffer and size.  The new buffer is returned in *RETBUF
7176    and *RETLEN.  The new buffer is allocated by xmalloc.
7177
7178    Return 1 for success.  On failure, call error and return 0.  */
7179 int
7180 rcs_change_text (const char *name, char *textbuf, size_t textlen,
7181                  const char *diffbuf, size_t difflen, char **retbuf,
7182                  size_t *retlen)
7183 {
7184     struct linevector lines;
7185     int ret;
7186
7187     *retbuf = NULL;
7188     *retlen = 0;
7189
7190     linevector_init (&lines);
7191
7192     if (! linevector_add (&lines, textbuf, textlen, NULL, 0))
7193         error (1, 0, "cannot initialize line vector");
7194
7195     if (! apply_rcs_changes (&lines, diffbuf, difflen, name, NULL, NULL))
7196     {
7197         error (0, 0, "invalid change text in %s", name);
7198         ret = 0;
7199     }
7200     else
7201     {
7202         char *p;
7203         size_t n;
7204         unsigned int ln;
7205
7206         n = 0;
7207         for (ln = 0; ln < lines.nlines; ++ln)
7208             /* 1 for \n */
7209             n += lines.vector[ln]->len + 1;
7210
7211         p = xmalloc (n);
7212         *retbuf = p;
7213
7214         for (ln = 0; ln < lines.nlines; ++ln)
7215         {
7216             memcpy (p, lines.vector[ln]->text, lines.vector[ln]->len);
7217             p += lines.vector[ln]->len;
7218             if (lines.vector[ln]->has_newline)
7219                 *p++ = '\n';
7220         }
7221
7222         *retlen = p - *retbuf;
7223         assert (*retlen <= n);
7224
7225         ret = 1;
7226     }
7227
7228     linevector_free (&lines);
7229
7230     return ret;
7231 }
7232
7233
7234
7235 /* Walk the deltas in RCS to get to revision VERSION.
7236
7237    If OP is RCS_ANNOTATE, then write annotations using cvs_output.
7238
7239    If OP is RCS_FETCH, then put the contents of VERSION into a
7240    newly-malloc'd array and put a pointer to it in *TEXT.  Each line
7241    is \n terminated; the caller is responsible for converting text
7242    files if desired.  The total length is put in *LEN.
7243
7244    If FP is non-NULL, it should be a file descriptor open to the file
7245    RCS with file position pointing to the deltas.  We close the file
7246    when we are done.
7247
7248    If LOG is non-NULL, then *LOG is set to the log message of VERSION,
7249    and *LOGLEN is set to the length of the log message.
7250
7251    On error, give a fatal error.  */
7252 void
7253 RCS_deltas (RCSNode *rcs, FILE *fp, struct rcsbuffer *rcsbuf,
7254             const char *version, enum rcs_delta_op op, char **text,
7255             size_t *len, char **log, size_t *loglen)
7256 {
7257     struct rcsbuffer rcsbuf_local;
7258     char *branchversion;
7259     char *cpversion;
7260     char *key;
7261     char *value;
7262     size_t vallen;
7263     RCSVers *vers;
7264     RCSVers *prev_vers;
7265     RCSVers *trunk_vers;
7266     char *next;
7267     int ishead, isnext, isversion, onbranch;
7268     Node *node;
7269     struct linevector headlines;
7270     struct linevector curlines;
7271     struct linevector trunklines;
7272     int foundhead;
7273
7274     assert (version);
7275
7276     if (fp == NULL)
7277     {
7278         rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf_local);
7279         rcsbuf = &rcsbuf_local;
7280     }
7281
7282    if (log) *log = NULL;
7283
7284     ishead = 1;
7285     vers = NULL;
7286     prev_vers = NULL;
7287     trunk_vers = NULL;
7288     next = NULL;
7289     onbranch = 0;
7290     foundhead = 0;
7291
7292     linevector_init (&curlines);
7293     linevector_init (&headlines);
7294     linevector_init (&trunklines);
7295
7296     /* We set BRANCHVERSION to the version we are currently looking
7297        for.  Initially, this is the version on the trunk from which
7298        VERSION branches off.  If VERSION is not a branch, then
7299        BRANCHVERSION is just VERSION.  */
7300     branchversion = xstrdup (version);
7301     cpversion = strchr (branchversion, '.');
7302     if (cpversion != NULL)
7303         cpversion = strchr (cpversion + 1, '.');
7304     if (cpversion != NULL)
7305         *cpversion = '\0';
7306
7307     do {
7308         if (! rcsbuf_getrevnum (rcsbuf, &key))
7309             error (1, 0, "unexpected EOF reading RCS file %s", rcs->print_path);
7310
7311         if (next != NULL && ! STREQ (next, key))
7312         {
7313             /* This is not the next version we need.  It is a branch
7314                version which we want to ignore.  */
7315             isnext = 0;
7316             isversion = 0;
7317         }
7318         else
7319         {
7320             isnext = 1;
7321
7322             /* look up the revision */
7323             node = findnode (rcs->versions, key);
7324             if (node == NULL)
7325                 error (1, 0,
7326                        "mismatch in rcs file %s between deltas and deltatexts (%s)",
7327                        rcs->print_path, key);
7328
7329             /* Stash the previous version.  */
7330             prev_vers = vers;
7331
7332             vers = node->data;
7333             next = vers->next;
7334
7335             /* Compare key and trunkversion now, because key points to
7336                storage controlled by rcsbuf_getkey.  */
7337             if (STREQ (branchversion, key))
7338                 isversion = 1;
7339             else
7340                 isversion = 0;
7341         }
7342
7343         while (1)
7344         {
7345             if (! rcsbuf_getkey (rcsbuf, &key, &value))
7346                 error (1, 0, "%s does not appear to be a valid rcs file",
7347                        rcs->print_path);
7348
7349             if (log != NULL
7350                 && isversion
7351                 && STREQ (key, "log")
7352                 && STREQ (branchversion, version))
7353             {
7354                 if (*log != NULL)
7355                 {
7356                     error (0, 0, "Duplicate `log' keyword in RCS file (`%s').",
7357                            rcs->print_path);
7358                     free (*log);
7359                 }
7360                 *log = rcsbuf_valcopy (rcsbuf, value, 0, loglen);
7361             }
7362
7363             if (STREQ (key, "text"))
7364             {
7365                 rcsbuf_valpolish (rcsbuf, value, 0, &vallen);
7366                 if (ishead)
7367                 {
7368                     if (! linevector_add (&curlines, value, vallen, NULL, 0))
7369                         error (1, 0, "invalid rcs file %s", rcs->print_path);
7370
7371                     ishead = 0;
7372                 }
7373                 else if (isnext)
7374                 {
7375                     if (! apply_rcs_changes (&curlines, value, vallen,
7376                                              rcs->path,
7377                                              onbranch ? vers : NULL,
7378                                              onbranch ? NULL : prev_vers))
7379                         error (1, 0, "invalid change text in %s", rcs->print_path);
7380                 }
7381                 break;
7382             }
7383         }
7384
7385         if (isversion)
7386         {
7387             /* This is either the version we want, or it is the
7388                branchpoint to the version we want.  */
7389             if (STREQ (branchversion, version))
7390             {
7391                 /* This is the version we want.  */
7392                 linevector_copy (&headlines, &curlines);
7393                 foundhead = 1;
7394                 if (onbranch)
7395                 {
7396                     /* We have found this version by tracking up a
7397                        branch.  Restore back to the lines we saved
7398                        when we left the trunk, and continue tracking
7399                        down the trunk.  */
7400                     onbranch = 0;
7401                     vers = trunk_vers;
7402                     next = vers->next;
7403                     linevector_copy (&curlines, &trunklines);
7404                 }
7405             }
7406             else
7407             {
7408                 Node *p;
7409
7410                 /* We need to look up the branch.  */
7411                 onbranch = 1;
7412
7413                 if (numdots (branchversion) < 2)
7414                 {
7415                     unsigned int ln;
7416
7417                     /* We are leaving the trunk; save the current
7418                        lines so that we can restore them when we
7419                        continue tracking down the trunk.  */
7420                     trunk_vers = vers;
7421                     linevector_copy (&trunklines, &curlines);
7422
7423                     /* Reset the version information we have
7424                        accumulated so far.  It only applies to the
7425                        changes from the head to this version.  */
7426                     for (ln = 0; ln < curlines.nlines; ++ln)
7427                         curlines.vector[ln]->vers = NULL;
7428                 }
7429
7430                 /* The next version we want is the entry on
7431                    VERS->branches which matches this branch.  For
7432                    example, suppose VERSION is 1.21.4.3 and
7433                    BRANCHVERSION was 1.21.  Then we look for an entry
7434                    starting with "1.21.4" and we'll put it (probably
7435                    1.21.4.1) in NEXT.  We'll advance BRANCHVERSION by
7436                    two dots (in this example, to 1.21.4.3).  */
7437
7438                 if (vers->branches == NULL)
7439                     error (1, 0, "missing expected branches in %s",
7440                            rcs->print_path);
7441                 if (!cpversion)
7442                     error (1, 0, "Invalid revision number in `%s'.",
7443                            rcs->print_path);
7444                 *cpversion = '.';
7445                 ++cpversion;
7446                 cpversion = strchr (cpversion, '.');
7447                 if (cpversion == NULL)
7448                     error (1, 0, "version number confusion in %s",
7449                            rcs->print_path);
7450                 for (p = vers->branches->list->next;
7451                      p != vers->branches->list;
7452                      p = p->next)
7453                     if (strncmp (p->key, branchversion,
7454                                  cpversion - branchversion) == 0)
7455                         break;
7456                 if (p == vers->branches->list)
7457                     error (1, 0, "missing expected branch in %s",
7458                            rcs->print_path);
7459
7460                 next = p->key;
7461
7462                 cpversion = strchr (cpversion + 1, '.');
7463                 if (cpversion != NULL)
7464                     *cpversion = '\0';
7465             }
7466         }
7467         if (op == RCS_FETCH && foundhead)
7468             break;
7469     } while (next != NULL);
7470
7471     free (branchversion);
7472
7473     rcsbuf_cache (rcs, rcsbuf);
7474
7475     if (! foundhead)
7476         error (1, 0, "could not find desired version %s in %s",
7477                version, rcs->print_path);
7478
7479     /* Now print out or return the data we have just computed.  */
7480     switch (op)
7481     {
7482         case RCS_ANNOTATE:
7483             {
7484                 unsigned int ln;
7485
7486                 for (ln = 0; ln < headlines.nlines; ++ln)
7487                 {
7488                     char *buf;
7489                     /* Period which separates year from month in date.  */
7490                     char *ym;
7491                     /* Period which separates month from day in date.  */
7492                     char *md;
7493                     RCSVers *prvers;
7494
7495                     prvers = headlines.vector[ln]->vers;
7496                     if (prvers == NULL)
7497                         prvers = vers;
7498
7499                     buf = xmalloc (strlen (prvers->version) + 24);
7500                     sprintf (buf, "%-12s (%-8.8s ",
7501                              prvers->version,
7502                              prvers->author);
7503                     cvs_output (buf, 0);
7504                     free (buf);
7505
7506                     /* Now output the date.  */
7507                     ym = strchr (prvers->date, '.');
7508                     if (ym == NULL)
7509                     {
7510                         cvs_output ("??", 0);
7511                         cvs_output ("-???", 0);
7512                         cvs_output ("-??", 0);
7513                     }
7514                     else
7515                     {
7516                         md = strchr (ym + 1, '.');
7517                         if (md == NULL)
7518                             cvs_output ("??", 0);
7519                         else
7520                             cvs_output (md + 1, 2);
7521
7522                         cvs_output ("-", 1);
7523                         cvs_output (month_printname (ym + 1), 0);
7524                         cvs_output ("-", 1);
7525                         /* Only output the last two digits of the year.  Our output
7526                            lines are long enough as it is without printing the
7527                            century.  */
7528                         cvs_output (ym - 2, 2);
7529                     }
7530                     cvs_output ("): ", 0);
7531                     if (headlines.vector[ln]->len != 0)
7532                         cvs_output (headlines.vector[ln]->text,
7533                                     headlines.vector[ln]->len);
7534                     cvs_output ("\n", 1);
7535                 }
7536             }
7537             break;
7538         case RCS_FETCH:
7539             {
7540                 char *p;
7541                 size_t n;
7542                 unsigned int ln;
7543
7544                 assert (text != NULL);
7545                 assert (len != NULL);
7546
7547                 n = 0;
7548                 for (ln = 0; ln < headlines.nlines; ++ln)
7549                     /* 1 for \n */
7550                     n += headlines.vector[ln]->len + 1;
7551                 p = xmalloc (n);
7552                 *text = p;
7553                 for (ln = 0; ln < headlines.nlines; ++ln)
7554                 {
7555                     memcpy (p, headlines.vector[ln]->text,
7556                             headlines.vector[ln]->len);
7557                     p += headlines.vector[ln]->len;
7558                     if (headlines.vector[ln]->has_newline)
7559                         *p++ = '\n';
7560                 }
7561                 *len = p - *text;
7562                 assert (*len <= n);
7563             }
7564             break;
7565     }
7566
7567     linevector_free (&curlines);
7568     linevector_free (&headlines);
7569     linevector_free (&trunklines);
7570
7571     return;
7572 }
7573
7574
7575
7576 /* Read the information for a single delta from the RCS buffer RCSBUF,
7577    whose name is RCSFILE.  *KEYP and *VALP are either NULL, or the
7578    first key/value pair to read, as set by rcsbuf_getkey. Return NULL
7579    if there are no more deltas.  Store the key/value pair which
7580    terminated the read in *KEYP and *VALP.  */
7581 static RCSVers *
7582 getdelta (struct rcsbuffer *rcsbuf, char *rcsfile, char **keyp, char **valp)
7583 {
7584     RCSVers *vnode;
7585     char *key, *value, *cp;
7586     Node *kv;
7587
7588     /* Get revision number if it wasn't passed in. This uses
7589        rcsbuf_getkey because it doesn't croak when encountering
7590        unexpected input.  As a result, we have to play unholy games
7591        with `key' and `value'. */
7592     if (*keyp != NULL)
7593     {
7594         key = *keyp;
7595         value = *valp;
7596     }
7597     else
7598     {
7599         if (! rcsbuf_getkey (rcsbuf, &key, &value))
7600             error (1, 0, "%s: unexpected EOF", rcsfile);
7601     }
7602
7603     /* Make sure that it is a revision number and not a cabbage 
7604        or something. */
7605     for (cp = key;
7606          (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
7607          cp++)
7608         /* do nothing */ ;
7609     /* Note that when comparing with RCSDATE, we are not massaging
7610        VALUE from the string found in the RCS file.  This is OK since
7611        we know exactly what to expect.  */
7612     if (*cp != '\0' || strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) != 0)
7613     {
7614         *keyp = key;
7615         *valp = value;
7616         return NULL;
7617     }
7618
7619     vnode = xmalloc (sizeof (RCSVers));
7620     memset (vnode, 0, sizeof (RCSVers));
7621
7622     vnode->version = xstrdup (key);
7623
7624     /* Grab the value of the date from value.  Note that we are not
7625        massaging VALUE from the string found in the RCS file.  */
7626     cp = value + (sizeof RCSDATE) - 1;  /* skip the "date" keyword */
7627     while (whitespace (*cp))            /* take space off front of value */
7628         cp++;
7629
7630     vnode->date = xstrdup (cp);
7631
7632     /* Get author field.  */
7633     if (! rcsbuf_getkey (rcsbuf, &key, &value))
7634     {
7635         error (1, 0, "unexpected end of file reading %s", rcsfile);
7636     }
7637     if (! STREQ (key, "author"))
7638         error (1, 0, "\
7639 unable to parse %s; `author' not in the expected place", rcsfile);
7640     vnode->author = rcsbuf_valcopy (rcsbuf, value, 0, NULL);
7641
7642     /* Get state field.  */
7643     if (! rcsbuf_getkey (rcsbuf, &key, &value))
7644     {
7645         error (1, 0, "unexpected end of file reading %s", rcsfile);
7646     }
7647     if (! STREQ (key, "state"))
7648         error (1, 0, "\
7649 unable to parse %s; `state' not in the expected place", rcsfile);
7650     vnode->state = rcsbuf_valcopy (rcsbuf, value, 0, NULL);
7651     /* The value is optional, according to rcsfile(5).  */
7652     if (value != NULL && STREQ (value, RCSDEAD))
7653     {
7654         vnode->dead = 1;
7655     }
7656
7657     /* Note that "branches" and "next" are in fact mandatory, according
7658        to doc/RCSFILES.  */
7659
7660     /* fill in the branch list (if any branches exist) */
7661     if (! rcsbuf_getkey (rcsbuf, &key, &value))
7662     {
7663         error (1, 0, "unexpected end of file reading %s", rcsfile);
7664     }
7665     if (STREQ (key, RCSDESC))
7666     {
7667         *keyp = key;
7668         *valp = value;
7669         /* Probably could/should be a fatal error.  */
7670         error (0, 0, "warning: 'branches' keyword missing from %s", rcsfile);
7671         return vnode;
7672     }
7673     if (value != NULL)
7674     {
7675         vnode->branches = getlist ();
7676         /* Note that we are not massaging VALUE from the string found
7677            in the RCS file.  */
7678         do_branches (vnode->branches, value);
7679     }
7680
7681     /* fill in the next field if there is a next revision */
7682     if (! rcsbuf_getkey (rcsbuf, &key, &value))
7683     {
7684         error (1, 0, "unexpected end of file reading %s", rcsfile);
7685     }
7686     if (STREQ (key, RCSDESC))
7687     {
7688         *keyp = key;
7689         *valp = value;
7690         /* Probably could/should be a fatal error.  */
7691         error (0, 0, "warning: 'next' keyword missing from %s", rcsfile);
7692         return vnode;
7693     }
7694     if (value != NULL)
7695         vnode->next = rcsbuf_valcopy (rcsbuf, value, 0, NULL);
7696
7697     /*
7698      * XXX - this is where we put the symbolic link stuff???
7699      * (into newphrases in the deltas).
7700      */
7701     while (1)
7702     {
7703         if (! rcsbuf_getkey (rcsbuf, &key, &value))
7704             error (1, 0, "unexpected end of file reading %s", rcsfile);
7705
7706         /* The `desc' keyword is the end of the deltas. */
7707         if (strcmp (key, RCSDESC) == 0)
7708             break;
7709
7710 #ifdef PRESERVE_PERMISSIONS_SUPPORT
7711
7712         /* The `hardlinks' value is a group of words, which must
7713            be parsed separately and added as a list to vnode->hardlinks. */
7714         if (strcmp (key, "hardlinks") == 0)
7715         {
7716             char *word;
7717
7718             vnode->hardlinks = getlist();
7719             while ((word = rcsbuf_valword (rcsbuf, &value)) != NULL)
7720             {
7721                 Node *n = getnode();
7722                 n->key = word;
7723                 addnode (vnode->hardlinks, n);
7724             }
7725             continue;
7726         }
7727 #endif
7728
7729         /* Enable use of repositories created by certain obsolete
7730            versions of CVS.  This code should remain indefinately;
7731            there is no procedure for converting old repositories, and
7732            checking for it is harmless.  */
7733         if (STREQ (key, RCSDEAD))
7734         {
7735             vnode->dead = 1;
7736             if (vnode->state != NULL)
7737                 free (vnode->state);
7738             vnode->state = xstrdup (RCSDEAD);
7739             continue;
7740         }
7741         /* if we have a new revision number, we're done with this delta */
7742         for (cp = key;
7743              (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
7744              cp++)
7745             /* do nothing */ ;
7746         /* Note that when comparing with RCSDATE, we are not massaging
7747            VALUE from the string found in the RCS file.  This is OK
7748            since we know exactly what to expect.  */
7749         if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0)
7750             break;
7751
7752         /* At this point, key and value represent a user-defined field
7753            in the delta node. */
7754         if (vnode->other_delta == NULL)
7755             vnode->other_delta = getlist ();
7756         kv = getnode ();
7757         kv->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
7758         kv->key = xstrdup (key);
7759         kv->data = rcsbuf_valcopy (rcsbuf, value, kv->type == RCSFIELD, NULL);
7760         if (addnode (vnode->other_delta, kv) != 0)
7761         {
7762             /* Complaining about duplicate keys in newphrases seems
7763                questionable, in that we don't know what they mean and
7764                doc/RCSFILES has no prohibition on several newphrases
7765                with the same key.  But we can't store more than one as
7766                long as we store them in a List *.  */
7767             error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
7768                    key, rcsfile);
7769             freenode (kv);
7770         }
7771     }
7772
7773     /* Return the key which caused us to fail back to the caller.  */
7774     *keyp = key;
7775     *valp = value;
7776
7777     return vnode;
7778 }
7779
7780
7781
7782 static void
7783 freedeltatext (Deltatext *d)
7784 {
7785     if (d->version != NULL)
7786         free (d->version);
7787     if (d->log != NULL)
7788         free (d->log);
7789     if (d->text != NULL)
7790         free (d->text);
7791     if (d->other != NULL)
7792         dellist (&d->other);
7793     free (d);
7794 }
7795
7796 static Deltatext *
7797 RCS_getdeltatext (RCSNode *rcs, FILE *fp, struct rcsbuffer *rcsbuf)
7798 {
7799     char *num;
7800     char *key, *value;
7801     Node *p;
7802     Deltatext *d;
7803
7804     /* Get the revision number. */
7805     if (! rcsbuf_getrevnum (rcsbuf, &num))
7806     {
7807         /* If num == NULL, it means we reached EOF naturally.  That's
7808            fine. */
7809         if (num == NULL)
7810             return NULL;
7811         else
7812             error (1, 0, "%s: unexpected EOF", rcs->print_path);
7813     }
7814
7815     p = findnode (rcs->versions, num);
7816     if (p == NULL)
7817         error (1, 0, "mismatch in rcs file %s between deltas and deltatexts (%s)",
7818                rcs->print_path, num);
7819
7820     d = xmalloc (sizeof (Deltatext));
7821     d->version = xstrdup (num);
7822
7823     /* Get the log message. */
7824     if (! rcsbuf_getkey (rcsbuf, &key, &value))
7825         error (1, 0, "%s, delta %s: unexpected EOF", rcs->print_path, num);
7826     if (! STREQ (key, "log"))
7827         error (1, 0, "%s, delta %s: expected `log', got `%s'",
7828                rcs->print_path, num, key);
7829     d->log = rcsbuf_valcopy (rcsbuf, value, 0, NULL);
7830
7831     /* Get random newphrases. */
7832     d->other = getlist();
7833     while (1)
7834     {
7835         if (! rcsbuf_getkey (rcsbuf, &key, &value))
7836             error (1, 0, "%s, delta %s: unexpected EOF", rcs->print_path, num);
7837
7838         if (STREQ (key, "text"))
7839             break;
7840
7841         p = getnode();
7842         p->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
7843         p->key = xstrdup (key);
7844         p->data = rcsbuf_valcopy (rcsbuf, value, p->type == RCSFIELD, NULL);
7845         if (addnode (d->other, p) < 0)
7846         {
7847             error (0, 0, "warning: %s, delta %s: duplicate field `%s'",
7848                    rcs->print_path, num, key);
7849         }
7850     }
7851
7852     /* Get the change text. We already know that this key is `text'. */
7853     d->text = rcsbuf_valcopy (rcsbuf, value, 0, &d->len);
7854
7855     return d;
7856 }
7857
7858
7859
7860 /* RCS output functions, for writing RCS format files from RCSNode
7861    structures.
7862
7863    For most of this work, RCS 5.7 uses an `aprintf' function which aborts
7864    program upon error.  Instead, these functions check the output status
7865    of the stream right before closing it, and aborts if an error condition
7866    is found.  The RCS solution is probably the better one: it produces
7867    more overhead, but will produce a clearer diagnostic in the case of
7868    catastrophic error.  In either case, however, the repository will probably
7869    not get corrupted. */
7870 static int
7871 putsymbol_proc (Node *symnode, void *fparg)
7872 {
7873     FILE *fp = fparg;
7874
7875     /* A fiddly optimization: this code used to just call fprintf, but
7876        in an old repository with hundreds of tags this can get called
7877        hundreds of thousands of times when doing a cvs tag.  Since
7878        tagging is a relatively common operation, and using putc and
7879        fputs is just as comprehensible, the change is worthwhile.  */
7880     putc ('\n', fp);
7881     putc ('\t', fp);
7882     fputs (symnode->key, fp);
7883     putc (':', fp);
7884     fputs (symnode->data, fp);
7885     return 0;
7886 }
7887
7888
7889
7890 /* putlock_proc is like putsymbol_proc, but key and data are reversed. */
7891 static int
7892 putlock_proc (Node *symnode, void *fp)
7893 {
7894     return fprintf (fp, "\n\t%s:%s", (char *)symnode->data, symnode->key);
7895 }
7896
7897
7898
7899 static int
7900 putrcsfield_proc (Node *node, void *vfp)
7901 {
7902     FILE *fp = vfp;
7903
7904     /* Some magic keys used internally by CVS start with `;'. Skip them. */
7905     if (node->key[0] == ';')
7906         return 0;
7907
7908     fprintf (fp, "\n%s\t", node->key);
7909     if (node->data != NULL)
7910     {
7911         /* If the field's value contains evil characters,
7912            it must be stringified. */
7913         /* FIXME: This does not quite get it right.  "7jk8f" is not a valid
7914            value for a value in a newpharse, according to doc/RCSFILES,
7915            because digits are not valid in an "id".  We might do OK by
7916            always writing strings (enclosed in @@).  Would be nice to
7917            explicitly mention this one way or another in doc/RCSFILES.
7918            A case where we are wrong in a much more clear-cut way is that
7919            we let through non-graphic characters such as whitespace and
7920            control characters.  */
7921
7922         if (node->type == RCSCMPFLD || strpbrk (node->data, "$,.:;@") == NULL)
7923             fputs (node->data, fp);
7924         else
7925         {
7926             putc ('@', fp);
7927             expand_at_signs (node->data, (off_t) strlen (node->data), fp);
7928             putc ('@', fp);
7929         }
7930     }
7931
7932     /* desc, log and text fields should not be terminated with semicolon;
7933        all other fields should be. */
7934     if (! STREQ (node->key, "desc") &&
7935         ! STREQ (node->key, "log") &&
7936         ! STREQ (node->key, "text"))
7937     {
7938         putc (';', fp);
7939     }
7940     return 0;
7941 }
7942
7943
7944
7945 #ifdef PRESERVE_PERMISSIONS_SUPPORT
7946
7947 /* Save a filename in a `hardlinks' RCS field.  NODE->KEY will contain
7948    a full pathname, but currently only basenames are stored in the RCS
7949    node.  Assume that the filename includes nasty characters and
7950    @-escape it. */
7951
7952 static int
7953 puthardlink_proc (node, vfp)
7954     Node *node;
7955     void *vfp;
7956 {
7957     FILE *fp = vfp;
7958     char *basename = strrchr (node->key, '/');
7959
7960     if (basename == NULL)
7961         basename = node->key;
7962     else
7963         ++basename;
7964
7965     putc ('\t', fp);
7966     putc ('@', fp);
7967     (void) expand_at_signs (basename, strlen (basename), fp);
7968     putc ('@', fp);
7969
7970     return 0;
7971 }
7972
7973 #endif /* PRESERVE_PERMISSIONS_SUPPORT */
7974
7975
7976
7977 /* Output the admin node for RCS into stream FP. */
7978 static void
7979 RCS_putadmin (RCSNode *rcs, FILE *fp)
7980 {
7981     fprintf (fp, "%s\t%s;\n", RCSHEAD, rcs->head ? rcs->head : "");
7982     if (rcs->branch)
7983         fprintf (fp, "%s\t%s;\n", RCSBRANCH, rcs->branch);
7984
7985     fputs ("access", fp);
7986     if (rcs->access)
7987     {
7988         char *p, *s;
7989         s = xstrdup (rcs->access);
7990         for (p = strtok (s, " \n\t"); p != NULL; p = strtok (NULL, " \n\t"))
7991             fprintf (fp, "\n\t%s", p);
7992         free (s);
7993     }
7994     fputs (";\n", fp);
7995
7996     fputs (RCSSYMBOLS, fp);
7997     /* If we haven't had to convert the symbols to a list yet, don't
7998        force a conversion now; just write out the string.  */
7999     if (rcs->symbols == NULL && rcs->symbols_data != NULL)
8000     {
8001         fputs ("\n\t", fp);
8002         fputs (rcs->symbols_data, fp);
8003     }
8004     else
8005         walklist (RCS_symbols (rcs), putsymbol_proc, fp);
8006     fputs (";\n", fp);
8007
8008     fputs ("locks", fp);
8009     if (rcs->locks_data)
8010         fprintf (fp, "\t%s", rcs->locks_data);
8011     else if (rcs->locks)
8012         walklist (rcs->locks, putlock_proc, fp);
8013     if (rcs->strict_locks)
8014         fprintf (fp, "; strict");
8015     fputs (";\n", fp);
8016
8017     if (rcs->comment)
8018     {
8019         fprintf (fp, "comment\t@");
8020         expand_at_signs (rcs->comment, (off_t) strlen (rcs->comment), fp);
8021         fputs ("@;\n", fp);
8022     }
8023     if (rcs->expand && ! STREQ (rcs->expand, "kv"))
8024         fprintf (fp, "%s\t@%s@;\n", RCSEXPAND, rcs->expand);
8025
8026     walklist (rcs->other, putrcsfield_proc, fp);
8027
8028     putc ('\n', fp);
8029 }
8030
8031
8032
8033 static void
8034 putdelta (RCSVers *vers, FILE *fp)
8035 {
8036     Node *bp, *start;
8037
8038     /* Skip if no revision was supplied, or if it is outdated (cvs admin -o) */
8039     if (vers == NULL || vers->outdated)
8040         return;
8041
8042     fprintf (fp, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches",
8043              vers->version,
8044              RCSDATE, vers->date,
8045              "author", vers->author,
8046              "state", vers->state ? vers->state : "");
8047
8048     if (vers->branches != NULL)
8049     {
8050         start = vers->branches->list;
8051         for (bp = start->next; bp != start; bp = bp->next)
8052             fprintf (fp, "\n\t%s", bp->key);
8053     }
8054
8055     fprintf (fp, ";\nnext\t%s;", vers->next ? vers->next : "");
8056
8057     walklist (vers->other_delta, putrcsfield_proc, fp);
8058
8059 #ifdef PRESERVE_PERMISSIONS_SUPPORT
8060     if (vers->hardlinks)
8061     {
8062         fprintf (fp, "\nhardlinks");
8063         walklist (vers->hardlinks, puthardlink_proc, fp);
8064         putc (';', fp);
8065     }
8066 #endif
8067     putc ('\n', fp);
8068 }
8069
8070
8071
8072 static void
8073 RCS_putdtree (RCSNode *rcs, char *rev, FILE *fp)
8074 {
8075     RCSVers *versp;
8076     Node *p, *branch;
8077
8078     /* Previously, this function used a recursive implementation, but
8079        if the trunk has a huge number of revisions and the program
8080        stack is not big, a stack overflow could occur, so this
8081        nonrecursive version was developed to be more safe. */
8082     Node *branchlist, *onebranch;
8083     List *branches;
8084     List *onebranchlist;
8085
8086     if (rev == NULL)
8087         return;
8088
8089     branches = getlist();
8090
8091     for (; rev != NULL;)
8092     {
8093         /* Find the delta node for this revision. */
8094         p = findnode (rcs->versions, rev);
8095         if (p == NULL)
8096         {
8097             error (1, 0,
8098                    "error parsing repository file %s, file may be corrupt.", 
8099                    rcs->path);
8100         }
8101  
8102         versp = p->data;
8103
8104         /* Print the delta node and go for its `next' node.  This
8105            prints the trunk. If there are any branches printed on this
8106            revision, mark we have some. */
8107         putdelta (versp, fp);
8108         /* Store branch information into branch list so to write its
8109            trunk afterwards */
8110         if (versp->branches != NULL)
8111         {
8112             branch = getnode();
8113             branch->data = versp->branches;
8114
8115             addnode(branches, branch);
8116         }
8117
8118         rev = versp->next;
8119     }
8120
8121     /* If there are any branches printed on this revision,
8122        print those trunks as well. */
8123     branchlist = branches->list;
8124     for (branch = branchlist->next;
8125          branch != branchlist;
8126          branch = branch->next)
8127     {
8128         onebranchlist = (List *)(branch->data);
8129         onebranch = onebranchlist->list;
8130         for (p = onebranch->next; p != onebranch; p = p->next)
8131             RCS_putdtree (rcs, p->key, fp);
8132
8133         branch->data = NULL; /* so to prevent its freeing on dellist */
8134     }
8135
8136     dellist(&branches);
8137 }
8138
8139
8140
8141 static void
8142 RCS_putdesc (RCSNode *rcs, FILE *fp)
8143 {
8144     fprintf (fp, "\n\n%s\n@", RCSDESC);
8145     if (rcs->desc != NULL)
8146     {
8147         off_t len = (off_t) strlen (rcs->desc);
8148         if (len > 0)
8149         {
8150             expand_at_signs (rcs->desc, len, fp);
8151             if (rcs->desc[len-1] != '\n')
8152                 putc ('\n', fp);
8153         }
8154     }
8155     fputs ("@\n", fp);
8156 }
8157
8158
8159
8160 static void
8161 putdeltatext (FILE *fp, Deltatext *d)
8162 {
8163     fprintf (fp, "\n\n%s\nlog\n@", d->version);
8164     if (d->log != NULL)
8165     {
8166         int loglen = strlen (d->log);
8167         expand_at_signs (d->log, (off_t) loglen, fp);
8168         if (d->log[loglen-1] != '\n')
8169             putc ('\n', fp);
8170     }
8171     putc ('@', fp);
8172
8173     walklist (d->other, putrcsfield_proc, fp);
8174
8175     fputs ("\ntext\n@", fp);
8176     if (d->text != NULL)
8177         expand_at_signs (d->text, (off_t) d->len, fp);
8178     fputs ("@\n", fp);
8179 }
8180
8181
8182
8183 /* TODO: the whole mechanism for updating deltas is kludgey... more
8184    sensible would be to supply all the necessary info in a `newdeltatext'
8185    field for RCSVers nodes. -twp */
8186
8187 /* Copy delta text nodes from FIN to FOUT.  If NEWDTEXT is non-NULL, it
8188    is a new delta text node, and should be added to the tree at the
8189    node whose revision number is INSERTPT.  (Note that trunk nodes are
8190    written in decreasing order, and branch nodes are written in
8191    increasing order.) */
8192 static void
8193 RCS_copydeltas (RCSNode *rcs, FILE *fin, struct rcsbuffer *rcsbufin,
8194                 FILE *fout, Deltatext *newdtext, char *insertpt)
8195 {
8196     int actions;
8197     RCSVers *dadmin;
8198     Node *np;
8199     int insertbefore, found;
8200     char *bufrest;
8201     int nls;
8202     size_t buflen;
8203 #ifndef HAVE_MMAP
8204     char buf[8192];
8205     int got;
8206 #endif
8207
8208     /* Count the number of versions for which we have to do some
8209        special operation.  */
8210     actions = walklist (rcs->versions, count_delta_actions, NULL);
8211
8212     /* Make a note of whether NEWDTEXT should be inserted
8213        before or after its INSERTPT. */
8214     insertbefore = (newdtext != NULL && numdots (newdtext->version) == 1);
8215
8216     while (actions != 0 || newdtext != NULL)
8217     {
8218         Deltatext *dtext;
8219
8220         dtext = RCS_getdeltatext (rcs, fin, rcsbufin);
8221
8222         /* We shouldn't hit EOF here, because that would imply that
8223            some action was not taken, or that we could not insert
8224            NEWDTEXT.  */
8225         if (dtext == NULL)
8226             error (1, 0, "internal error: EOF too early in RCS_copydeltas");
8227
8228         found = (insertpt != NULL && STREQ (dtext->version, insertpt));
8229         if (found && insertbefore)
8230         {
8231             putdeltatext (fout, newdtext);
8232             newdtext = NULL;
8233             insertpt = NULL;
8234         }
8235
8236         np = findnode (rcs->versions, dtext->version);
8237         dadmin = np->data;
8238
8239         /* If this revision has been outdated, just skip it. */
8240         if (dadmin->outdated)
8241         {
8242             freedeltatext (dtext);
8243             --actions;
8244             continue;
8245         }
8246            
8247         /* Update the change text for this delta.  New change text
8248            data may come from cvs admin -m, cvs admin -o, or cvs ci. */
8249         if (dadmin->text != NULL)
8250         {
8251             if (dadmin->text->log != NULL || dadmin->text->text != NULL)
8252                 --actions;
8253             if (dadmin->text->log != NULL)
8254             {
8255                 free (dtext->log);
8256                 dtext->log = dadmin->text->log;
8257                 dadmin->text->log = NULL;
8258             }
8259             if (dadmin->text->text != NULL)
8260             {
8261                 free (dtext->text);
8262                 dtext->text = dadmin->text->text;
8263                 dtext->len = dadmin->text->len;
8264                 dadmin->text->text = NULL;
8265             }
8266         }
8267         putdeltatext (fout, dtext);
8268         freedeltatext (dtext);
8269
8270         if (found && !insertbefore)
8271         {
8272             putdeltatext (fout, newdtext);
8273             newdtext = NULL;
8274             insertpt = NULL;
8275         }
8276     }
8277
8278     /* Copy the rest of the file directly, without bothering to
8279        interpret it.  The caller will handle error checking by calling
8280        ferror.
8281
8282        We just wrote a newline to the file, either in putdeltatext or
8283        in the caller.  However, we may not have read the corresponding
8284        newline from the file, because rcsbuf_getkey returns as soon as
8285        it finds the end of the '@' string for the desc or text key.
8286        Therefore, we may read three newlines when we should really
8287        only write two, and we check for that case here.  This is not
8288        an semantically important issue; we only do it to make our RCS
8289        files look traditional.  */
8290
8291     nls = 3;
8292
8293     rcsbuf_get_buffered (rcsbufin, &bufrest, &buflen);
8294     if (buflen > 0)
8295     {
8296         if (bufrest[0] != '\n'
8297             || strncmp (bufrest, "\n\n\n", buflen < 3 ? buflen : 3) != 0)
8298         {
8299             nls = 0;
8300         }
8301         else
8302         {
8303             if (buflen < 3)
8304                 nls -= buflen;
8305             else
8306             {
8307                 ++bufrest;
8308                 --buflen;
8309                 nls = 0;
8310             }
8311         }
8312
8313         fwrite (bufrest, 1, buflen, fout);
8314     }
8315 #ifndef HAVE_MMAP
8316     /* This bit isn't necessary when using mmap since the entire file
8317      * will already be available via the RCS buffer.  Besides, the
8318      * mmap code doesn't always keep the file pointer up to date, so
8319      * this adds some data twice.
8320      */
8321     while ((got = fread (buf, 1, sizeof buf, fin)) != 0)
8322     {
8323         if (nls > 0
8324             && got >= nls
8325             && buf[0] == '\n'
8326             && strncmp (buf, "\n\n\n", nls) == 0)
8327         {
8328             fwrite (buf + 1, 1, got - 1, fout);
8329         }
8330         else
8331         {
8332             fwrite (buf, 1, got, fout);
8333         }
8334
8335         nls = 0;
8336     }
8337 #endif /* HAVE_MMAP */
8338 }
8339
8340
8341
8342 /* A helper procedure for RCS_copydeltas.  This is called via walklist
8343    to count the number of RCS revisions for which some special action
8344    is required.  */
8345 static int
8346 count_delta_actions (Node *np, void *ignore)
8347 {
8348     RCSVers *dadmin = np->data;
8349
8350     if (dadmin->outdated)
8351         return 1;
8352
8353     if (dadmin->text != NULL
8354         && (dadmin->text->log != NULL || dadmin->text->text != NULL))
8355     {
8356         return 1;
8357     }
8358
8359     return 0;
8360 }
8361
8362
8363
8364 /*
8365  * Clean up temporary files.
8366  *
8367  * NOTES
8368  *   This function needs to be reentrant since a call to exit() can cause a
8369  *   call to this function, which can then be interrupted by a signal, which
8370  *   can cause a second call to this function.
8371  *
8372  * RETURNS
8373  *   Nothing.
8374  */
8375 static void
8376 rcs_cleanup (void)
8377 {
8378     TRACE (TRACE_FUNCTION, "rcs_cleanup()");
8379
8380     /* FIXME: Do not perform buffered I/O from an interrupt handler like
8381      * this (via error).  However, I'm leaving the error-calling code there
8382      * in the hope that on the rare occasion the error call is actually made
8383      * (e.g., a fluky I/O error or permissions problem prevents the deletion
8384      * of a just-created file) reentrancy won't be an issue.
8385      */
8386
8387     /* We don't want to be interrupted during calls which set globals to NULL,
8388      * but we know that by the time we reach this function, interrupts have
8389      * already been blocked.
8390      */
8391     if (rcs_lockfile != NULL)
8392     {
8393         /* Use a tmp var since any of these functions could call exit, causing
8394          * us to be called a second time.
8395          */
8396         char *tmp = rcs_lockfile;
8397         rcs_lockfile = NULL;
8398         if (rcs_lockfd >= 0)
8399         {
8400             if (close (rcs_lockfd) != 0)
8401                 error (0, errno, "error closing lock file %s", tmp);
8402             rcs_lockfd = -1;
8403         }
8404
8405         /* Note that the checks for existence_error are because we can be
8406          * called from a signal handler, so we don't know whether the
8407          * files got created.
8408          */
8409         if (unlink_file (tmp) < 0
8410             && !existence_error (errno))
8411             error (0, errno, "cannot remove %s", tmp);
8412     }
8413 }
8414
8415
8416
8417 /* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style
8418    locking on the specified RCSFILE: for a file called `foo,v', open
8419    for writing a file called `,foo,'.
8420
8421    Note that we what do here is quite different from what RCS does.
8422    RCS creates the ,foo, file before it reads the RCS file (if it
8423    knows that it will be writing later), so that it actually serves as
8424    a lock.  We don't; instead we rely on CVS writelocks.  This means
8425    that if someone is running RCS on the file at the same time they
8426    are running CVS on it, they might lose (we read the file,
8427    then RCS writes it, then we write it, clobbering the
8428    changes made by RCS).  I believe the current sentiment about this
8429    is "well, don't do that".
8430
8431    A concern has been expressed about whether adopting the RCS
8432    strategy would slow us down.  I don't think so, since we need to
8433    write the ,foo, file anyway (unless perhaps if O_EXCL is slower or
8434    something).
8435
8436    These do not perform quite the same function as the RCS -l option
8437    for locking files: they are intended to prevent competing RCS
8438    processes from stomping all over each other's laundry.  Hence,
8439    they are `internal' locking functions.
8440
8441    If there is an error, give a fatal error; if we return we always
8442    return a non-NULL value.  */
8443 static FILE *
8444 rcs_internal_lockfile (char *rcsfile)
8445 {
8446     struct stat rstat;
8447     FILE *fp;
8448     static int first_call = 1;
8449
8450     if (first_call)
8451     {
8452         first_call = 0;
8453         /* Clean up if we get a signal or exit.  */
8454         cleanup_register (rcs_cleanup);
8455     }
8456
8457     /* Get the lock file name: `,file,' for RCS file `file,v'. */
8458     assert (rcs_lockfile == NULL);
8459     assert (rcs_lockfd < 0);
8460     rcs_lockfile = rcs_lockfilename (rcsfile);
8461
8462     /* Use the existing RCS file mode, or read-only if this is a new
8463        file.  (Really, this is a lie -- if this is a new file,
8464        RCS_checkin uses the permissions from the working copy.  For
8465        actually creating the file, we use 0444 as a safe default mode.) */
8466     if (stat (rcsfile, &rstat) < 0)
8467     {
8468         if (existence_error (errno))
8469             rstat.st_mode = S_IRUSR | S_IRGRP | S_IROTH;
8470         else
8471             error (1, errno, "cannot stat %s", rcsfile);
8472     }
8473
8474     /* Try to open exclusively.  POSIX.1 guarantees that O_EXCL|O_CREAT
8475        guarantees an exclusive open.  According to the RCS source, with
8476        NFS v2 we must also throw in O_TRUNC and use an open mask that makes
8477        the file unwriteable.  For extensive justification, see the comments for
8478        rcswriteopen() in rcsedit.c, in RCS 5.7.  This is kind of pointless
8479        in the CVS case; see comment at the start of this file concerning
8480        general ,foo, file strategy.
8481
8482        There is some sentiment that with NFSv3 and such, that one can
8483        rely on O_EXCL these days.  This might be true for unix (I
8484        don't really know), but I am still pretty skeptical in the case
8485        of the non-unix systems.  */
8486     rcs_lockfd = open (rcs_lockfile,
8487                        OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
8488                        S_IRUSR | S_IRGRP | S_IROTH);
8489
8490     if (rcs_lockfd < 0)
8491     {
8492         error (1, errno, "could not open lock file `%s'", rcs_lockfile);
8493     }
8494
8495     /* Force the file permissions, and return a stream object. */
8496     /* Because we change the modes later, we don't worry about
8497        this in the non-HAVE_FCHMOD case.  */
8498 #ifdef HAVE_FCHMOD
8499     if (fchmod (rcs_lockfd, rstat.st_mode) < 0)
8500         error (1, errno, "cannot change mode for %s", rcs_lockfile);
8501 #endif
8502     fp = fdopen (rcs_lockfd, FOPEN_BINARY_WRITE);
8503     if (fp == NULL)
8504         error (1, errno, "cannot fdopen %s", rcs_lockfile);
8505
8506     return fp;
8507 }
8508
8509
8510
8511 static void
8512 rcs_internal_unlockfile (FILE *fp, char *rcsfile)
8513 {
8514     assert (rcs_lockfile != NULL);
8515     assert (rcs_lockfd >= 0);
8516
8517     /* Abort if we could not write everything successfully to LOCKFILE.
8518        This is not a great error-handling mechanism, but should prevent
8519        corrupting the repository. */
8520
8521     if (ferror (fp))
8522         /* Using errno here may well be misleanding since the most recent
8523            call that set errno may not have anything whatsoever to do with
8524            the error that set the flag, but it's better than nothing.  The
8525            real solution is to check each call to fprintf rather than waiting
8526            until the end like this.  */
8527         error (1, errno, "error writing to lock file %s", rcs_lockfile);
8528
8529     /* Flush and sync the file, or the user may be told the commit completed,
8530      * while a server crash/power failure could still cause the data to be
8531      * lost.
8532      *
8533      * Invoking rename(",<file>," , "<file>,v") on Linux and almost all UNIXs
8534      * only flushes the inode for the target file to disk, it does not
8535      * guarantee flush of the kernel buffers allocated for the ,<file>,.
8536      * Depending upon the load on the machine, the Linux kernel's flush daemon
8537      * process may not flush for a while.  In the meantime the CVS transaction
8538      * could have been declared committed to the end CVS user (CVS process has
8539      * returned the final "OK").  If the machine crashes prior to syncing the
8540      * changes to disk, the committed transaction can be lost.
8541      */
8542     if (fflush (fp) != 0)
8543         error (1, errno, "error flushing file `%s' to kernel buffers",
8544                rcs_lockfile);
8545 #ifdef HAVE_FSYNC
8546     if (fsync (rcs_lockfd) < 0)
8547         error (1, errno, "error fsyncing file `%s'", rcs_lockfile);
8548 #endif
8549
8550     if (fclose (fp) == EOF)
8551         error (1, errno, "error closing lock file %s", rcs_lockfile);
8552     rcs_lockfd = -1;
8553
8554     rename_file (rcs_lockfile, rcsfile);
8555
8556     {
8557         /* Use a temporary to make sure there's no interval
8558            (after rcs_lockfile has been freed but before it's set to NULL)
8559            during which the signal handler's use of rcs_lockfile would
8560            reference freed memory.  */
8561         char *tmp = rcs_lockfile;
8562         rcs_lockfile = NULL;
8563         free (tmp);
8564     }
8565 }
8566
8567
8568
8569 static char *
8570 rcs_lockfilename (const char *rcsfile)
8571 {
8572     char *lockfile, *lockp;
8573     const char *rcsbase, *rcsp, *rcsend;
8574     int rcslen;
8575
8576     /* Create the lockfile name. */
8577     rcslen = strlen (rcsfile);
8578     lockfile = xmalloc (rcslen + 10);
8579     rcsbase = last_component (rcsfile);
8580     rcsend = rcsfile + rcslen - sizeof(RCSEXT);
8581     for (lockp = lockfile, rcsp = rcsfile; rcsp < rcsbase; ++rcsp)
8582         *lockp++ = *rcsp;
8583     *lockp++ = ',';
8584     while (rcsp <= rcsend)
8585         *lockp++ = *rcsp++;
8586     *lockp++ = ',';
8587     *lockp = '\0';
8588
8589     return lockfile;
8590 }
8591
8592
8593
8594 /* Rewrite an RCS file.  The basic idea here is that the caller should
8595    first call RCS_reparsercsfile, then munge the data structures as
8596    desired (via RCS_delete_revs, RCS_settag, &c), then call RCS_rewrite.  */
8597 void
8598 RCS_rewrite (RCSNode *rcs, Deltatext *newdtext, char *insertpt)
8599 {
8600     FILE *fin, *fout;
8601     struct rcsbuffer rcsbufin;
8602
8603     if (noexec)
8604         return;
8605
8606     /* Make sure we're operating on an actual file and not a symlink.  */
8607     resolve_symlink (&(rcs->path));
8608
8609     fout = rcs_internal_lockfile (rcs->path);
8610
8611     RCS_putadmin (rcs, fout);
8612     RCS_putdtree (rcs, rcs->head, fout);
8613     RCS_putdesc (rcs, fout);
8614
8615     /* Open the original RCS file and seek to the first delta text. */
8616     rcsbuf_cache_open (rcs, rcs->delta_pos, &fin, &rcsbufin);
8617
8618     /* Update delta_pos to the current position in the output file.
8619        Do NOT move these statements: they must be done after fin has
8620        been positioned at the old delta_pos, but before any delta
8621        texts have been written to fout.
8622      */
8623     rcs->delta_pos = ftello (fout);
8624     if (rcs->delta_pos == -1)
8625         error (1, errno, "cannot ftello in RCS file %s", rcs->path);
8626
8627     RCS_copydeltas (rcs, fin, &rcsbufin, fout, newdtext, insertpt);
8628
8629     /* We don't want to call rcsbuf_cache here, since we're about to
8630        delete the file.  */
8631     rcsbuf_close (&rcsbufin);
8632     if (ferror (fin))
8633         /* The only case in which using errno here would be meaningful
8634            is if we happen to have left errno unmolested since the call
8635            which produced the error (e.g. fread).  That is pretty
8636            fragile even if it happens to sometimes be true.  The real
8637            solution is to make sure that all the code which reads
8638            from fin checks for errors itself (some does, some doesn't).  */
8639         error (0, 0, "warning: ferror set while rewriting RCS file `%s'", rcs->path);
8640     if (fclose (fin) < 0)
8641         error (0, errno, "warning: closing RCS file `%s'", rcs->path);
8642
8643     rcs_internal_unlockfile (fout, rcs->path);
8644 }
8645
8646
8647
8648 /* Abandon changes to an RCS file. */
8649 void
8650 RCS_abandon (RCSNode *rcs)
8651 {
8652     free_rcsnode_contents (rcs);
8653     rcs->symbols_data = NULL;
8654     rcs->expand = NULL;
8655     rcs->access = NULL;
8656     rcs->locks_data = NULL;
8657     rcs->comment = NULL;
8658     rcs->desc = NULL;
8659     rcs->flags |= PARTIAL;
8660 }
8661
8662
8663
8664 /*
8665  * For a given file with full pathname PATH and revision number REV,
8666  * produce a file label suitable for passing to diff.  The default
8667  * file label as used by RCS 5.7 looks like this:
8668  *
8669  *      FILENAME <tab> YYYY/MM/DD <sp> HH:MM:SS <tab> REVNUM
8670  *
8671  * The date and time used are the revision's last checkin date and time.
8672  * If REV is NULL, use the working copy's mtime instead.
8673  *
8674  * /dev/null is not statted but assumed to have been created on the Epoch.
8675  * At least using the POSIX.2 definition of patch, this should cause creation
8676  * of files on platforms such as Windoze where the null IO device isn't named
8677  * /dev/null to be parsed by patch properly.
8678  */
8679 char *
8680 make_file_label (const char *path, const char *rev, RCSNode *rcs)
8681 {
8682     char datebuf[MAXDATELEN + 1];
8683     char *label;
8684
8685     if (rev)
8686     {
8687         char date[MAXDATELEN + 1];
8688         /* revs cannot be attached to /dev/null ... duh. */
8689         assert (strcmp(DEVNULL, path));
8690         RCS_getrevtime (rcs, rev, datebuf, 0);
8691         (void) date_to_internet (date, datebuf);
8692         label = Xasprintf ("-L%s\t%s\t%s", path, date, rev);
8693     }
8694     else
8695     {
8696         struct stat sb;
8697         struct tm *wm;
8698
8699         if (strcmp(DEVNULL, path))
8700         {
8701             const char *file = last_component (path);
8702             if (stat (file, &sb) < 0)
8703                 /* Assume that if the stat fails,then the later read for the
8704                  * diff will too.
8705                  */
8706                 error (1, errno, "could not get info for `%s'", path);
8707             wm = gmtime (&sb.st_mtime);
8708         }
8709         else
8710         {
8711             time_t t = 0;
8712             wm = gmtime(&t);
8713         }
8714
8715         (void) tm_to_internet (datebuf, wm);
8716         label = Xasprintf ("-L%s\t%s", path, datebuf);
8717     }
8718     return label;
8719 }
8720
8721
8722
8723 /*
8724  * Set up a local/custom RCS keyword for expansion.
8725  *
8726  * INPUTS
8727  *   infopath           Path to file being parsed, for error messages.
8728  *   ln                 Line number of INFOPATH being processed, for error
8729  *                      messages.
8730  *   keywords_in
8731  *   arg
8732  *
8733  * OUTPUTS
8734  *   keywords_in
8735  */
8736 void
8737 RCS_setlocalid (const char *infopath, unsigned int ln,
8738                 void **keywords_in, const char *arg)
8739 {
8740     char *copy, *next, *key, *s;
8741     struct rcs_keyword *keywords;
8742     enum keyword save_expandto;
8743
8744     if (!*keywords_in)
8745         *keywords_in = new_keywords ();
8746     keywords = *keywords_in;
8747
8748     copy = xstrdup (arg);
8749     next = copy;
8750     key = strtok (next, "=");
8751
8752     /*
8753      * Validate key
8754      */
8755     for (s = key; *s != '\0'; s++)
8756     {
8757         if (! isalpha ((unsigned char) *s))
8758         {
8759             if (!parse_error (infopath, ln))
8760                     error (0, 0,
8761 "%s [%u]: LocalKeyword ignored: Bad character `%c' in key `%s'",
8762                            primary_root_inverse_translate (infopath),
8763                            ln, *s, key);
8764             free (copy);
8765             return;
8766         }
8767     }
8768
8769     save_expandto = keywords[KEYWORD_LOCALID].expandto;
8770
8771     /* options? */
8772     while ((key = strtok (NULL, ",")) != NULL) {
8773         if (!strcmp(key, keywords[KEYWORD_ID].string))
8774             keywords[KEYWORD_LOCALID].expandto = KEYWORD_ID;
8775         else if (!strcmp(key, keywords[KEYWORD_HEADER].string))
8776             keywords[KEYWORD_LOCALID].expandto = KEYWORD_HEADER;
8777         else if (!strcmp(key, keywords[KEYWORD_CVSHEADER].string))
8778             keywords[KEYWORD_LOCALID].expandto = KEYWORD_CVSHEADER;
8779         else
8780         {
8781             keywords[KEYWORD_LOCALID].expandto = save_expandto;
8782             if (!parse_error (infopath, ln))
8783                 error (0, 0,
8784 "%s [%u]: LocalKeyword ignored: Unknown LocalId mode: `%s'",
8785                        primary_root_inverse_translate (infopath),
8786                        ln, key);
8787             free (copy);
8788             return;
8789         }
8790     }
8791
8792     keywords[KEYWORD_LOCALID].string = xstrdup (next);
8793     keywords[KEYWORD_LOCALID].len = strlen (next);
8794     keywords[KEYWORD_LOCALID].expandit = 1;
8795
8796     free (copy);
8797 }
8798
8799
8800
8801 void
8802 RCS_setincexc (void **keywords_in, const char *arg)
8803 {
8804     char *key;
8805     char *copy, *next;
8806     bool include = false;
8807     struct rcs_keyword *keyword;
8808     struct rcs_keyword *keywords;
8809
8810     if (!*keywords_in)
8811         *keywords_in = new_keywords ();
8812     keywords = *keywords_in;
8813
8814     copy = xstrdup(arg);
8815     next = copy;
8816     switch (*next++) {
8817         case 'e':
8818             include = false;
8819             break;
8820         case 'i':
8821             include = true;
8822             break;
8823         default:
8824             free(copy);
8825             return;
8826     }
8827
8828     if (include)
8829         for (keyword = keywords; keyword->string != NULL; keyword++)
8830         {
8831             keyword->expandit = false;
8832         }
8833
8834     key = strtok(next, ",");
8835     while (key) {
8836         for (keyword = keywords; keyword->string != NULL; keyword++) {
8837             if (strcmp (keyword->string, key) == 0)
8838                 keyword->expandit = include;
8839         }
8840         key = strtok(NULL, ",");
8841     }
8842     free(copy);
8843     return;
8844 }
8845
8846
8847
8848 #define ATTIC "/" CVSATTIC
8849 static char *
8850 getfullCVSname(char *CVSname, char **pathstore)
8851 {
8852     if (current_parsed_root->directory) {
8853         int rootlen;
8854         char *c = NULL;
8855         int alen = sizeof(ATTIC) - 1;
8856
8857         *pathstore = xstrdup(CVSname);
8858         if ((c = strrchr(*pathstore, '/')) != NULL) {
8859             if (c - *pathstore >= alen) {
8860                 if (!strncmp(c - alen, ATTIC, alen)) {
8861                     while (*c != '\0') {
8862                         *(c - alen) = *c;
8863                         c++;
8864                     }
8865                     *(c - alen) = '\0';
8866                 }
8867             }
8868         }
8869
8870         rootlen = strlen(current_parsed_root->directory);
8871         if (!strncmp(*pathstore, current_parsed_root->directory, rootlen) &&
8872             (*pathstore)[rootlen] == '/')
8873             CVSname = (*pathstore + rootlen + 1);
8874         else
8875             CVSname = (*pathstore);
8876     }
8877     return CVSname;
8878 }