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