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