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