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