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