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