xref: /netbsd-src/external/gpl2/xcvs/dist/src/rcs.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
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 			count = 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     new[KEYWORD_LOCALID].string = NULL;
3515     new[KEYWORD_LOCALID].len = 0;
3516     new[KEYWORD_LOCALID].expandto = KEYWORD_LOCALID;
3517     new[KEYWORD_LOCALID].expandit = false;
3518 
3519     return new;
3520 }
3521 
3522 
3523 
3524 void
3525 free_keywords (void *keywords)
3526 {
3527     free (keywords);
3528 }
3529 
3530 
3531 
3532 /* Convert an RCS date string into a readable string.  This is like
3533    the RCS date2str function.  */
3534 static char *
3535 printable_date (const char *rcs_date)
3536 {
3537     int year, mon, mday, hour, min, sec;
3538     char buf[100];
3539 
3540     (void) sscanf (rcs_date, SDATEFORM, &year, &mon, &mday, &hour, &min,
3541 		   &sec);
3542     if (year < 1900)
3543 	year += 1900;
3544     sprintf (buf, "%04d/%02d/%02d %02d:%02d:%02d", year, mon, mday,
3545 	     hour, min, sec);
3546     return xstrdup (buf);
3547 }
3548 
3549 
3550 
3551 /* Escape the characters in a string so that it can be included in an
3552    RCS value.  */
3553 static char *
3554 escape_keyword_value (const char *value, int *free_value)
3555 {
3556     char *ret, *t;
3557     const char *s;
3558 
3559     for (s = value; *s != '\0'; s++)
3560     {
3561 	char c;
3562 
3563 	c = *s;
3564 	if (c == '\t'
3565 	    || c == '\n'
3566 	    || c == '\\'
3567 	    || c == ' '
3568 	    || c == '$')
3569 	{
3570 	    break;
3571 	}
3572     }
3573 
3574     if (*s == '\0')
3575     {
3576 	*free_value = 0;
3577 	return (char *) value;
3578     }
3579 
3580     ret = xmalloc (strlen (value) * 4 + 1);
3581     *free_value = 1;
3582 
3583     for (s = value, t = ret; *s != '\0'; s++, t++)
3584     {
3585 	switch (*s)
3586 	{
3587 	default:
3588 	    *t = *s;
3589 	    break;
3590 	case '\t':
3591 	    *t++ = '\\';
3592 	    *t = 't';
3593 	    break;
3594 	case '\n':
3595 	    *t++ = '\\';
3596 	    *t = 'n';
3597 	    break;
3598 	case '\\':
3599 	    *t++ = '\\';
3600 	    *t = '\\';
3601 	    break;
3602 	case ' ':
3603 	    *t++ = '\\';
3604 	    *t++ = '0';
3605 	    *t++ = '4';
3606 	    *t = '0';
3607 	    break;
3608 	case '$':
3609 	    *t++ = '\\';
3610 	    *t++ = '0';
3611 	    *t++ = '4';
3612 	    *t = '4';
3613 	    break;
3614 	}
3615     }
3616 
3617     *t = '\0';
3618 
3619     return ret;
3620 }
3621 
3622 
3623 
3624 /* Expand RCS keywords in the memory buffer BUF of length LEN.  This
3625    applies to file RCS and version VERS.  If NAME is not NULL, and is
3626    not a numeric revision, then it is the symbolic tag used for the
3627    checkout.  EXPAND indicates how to expand the keywords.  This
3628    function sets *RETBUF and *RETLEN to the new buffer and length.
3629    This function may modify the buffer BUF.  If BUF != *RETBUF, then
3630    RETBUF is a newly allocated buffer.  */
3631 static void
3632 expand_keywords (RCSNode *rcs, RCSVers *ver, const char *name, const char *log,
3633 		 size_t loglen, enum kflag expand, char *buf, size_t len,
3634 		 char **retbuf, size_t *retlen)
3635 {
3636     struct expand_buffer
3637     {
3638 	struct expand_buffer *next;
3639 	char *data;
3640 	size_t len;
3641 	int free_data;
3642     } *ebufs = NULL;
3643     struct expand_buffer *ebuf_last = NULL;
3644     size_t ebuf_len = 0;
3645     char *locker;
3646     char *srch, *srch_next;
3647     size_t srch_len;
3648     const struct rcs_keyword *keywords;
3649 
3650     if (!config /* For `cvs init', config may not be set.  */
3651 	||expand == KFLAG_O || expand == KFLAG_B)
3652     {
3653 	*retbuf = buf;
3654 	*retlen = len;
3655 	return;
3656     }
3657 
3658     if (!config->keywords) config->keywords = new_keywords ();
3659     keywords = config->keywords;
3660 
3661     /* If we are using -kkvl, dig out the locker information if any.  */
3662     locker = NULL;
3663     if (expand == KFLAG_KVL)
3664     {
3665 	Node *lock;
3666 	lock = findnode (RCS_getlocks(rcs), ver->version);
3667 	if (lock != NULL)
3668 	    locker = xstrdup (lock->data);
3669     }
3670 
3671     /* RCS keywords look like $STRING$ or $STRING: VALUE$.  */
3672     srch = buf;
3673     srch_len = len;
3674     while ((srch_next = memchr (srch, '$', srch_len)) != NULL)
3675     {
3676 	char *s, *send;
3677 	size_t slen;
3678 	const struct rcs_keyword *keyword;
3679 	char *value;
3680 	int free_value;
3681 	char *sub;
3682 	size_t sublen;
3683 
3684 	srch_len -= (srch_next + 1) - srch;
3685 	srch = srch_next + 1;
3686 
3687 	/* Look for the first non alphabetic character after the '$'.  */
3688 	send = srch + srch_len;
3689 	for (s = srch; s < send; s++)
3690 	    if (! isalpha ((unsigned char) *s))
3691 		break;
3692 
3693 	/* If the first non alphabetic character is not '$' or ':',
3694            then this is not an RCS keyword.  */
3695 	if (s == send || (*s != '$' && *s != ':'))
3696 	    continue;
3697 
3698 	/* See if this is one of the keywords.  */
3699 	slen = s - srch;
3700 	for (keyword = keywords; keyword->string != NULL; keyword++)
3701 	{
3702 	    if (keyword->expandit
3703 		&& keyword->len == slen
3704 		&& strncmp (keyword->string, srch, slen) == 0)
3705 	    {
3706 		break;
3707 	    }
3708 	}
3709 	if (keyword->string == NULL)
3710 	    continue;
3711 
3712 	/* If the keyword ends with a ':', then the old value consists
3713            of the characters up to the next '$'.  If there is no '$'
3714            before the end of the line, though, then this wasn't an RCS
3715            keyword after all.  */
3716 	if (*s == ':')
3717 	{
3718 	    for (; s < send; s++)
3719 		if (*s == '$' || *s == '\n')
3720 		    break;
3721 	    if (s == send || *s != '$')
3722 		continue;
3723 	}
3724 
3725 	/* At this point we must replace the string from SRCH to S
3726            with the expansion of the keyword KW.  */
3727 
3728 	/* Get the value to use.  */
3729 	free_value = 0;
3730 	if (expand == KFLAG_K)
3731 	    value = NULL;
3732 	else
3733 	{
3734 	    switch (keyword->expandto)
3735 	    {
3736 	    default:
3737 		assert (!"unreached");
3738 
3739 	    case KEYWORD_AUTHOR:
3740 		value = ver->author;
3741 		break;
3742 
3743 	    case KEYWORD_DATE:
3744 		value = printable_date (ver->date);
3745 		free_value = 1;
3746 		break;
3747 
3748 	    case KEYWORD_CVSHEADER:
3749 	    case KEYWORD_HEADER:
3750 	    case KEYWORD_ID:
3751 	    case KEYWORD_LOCALID:
3752 		{
3753 		    const char *path;
3754 		    int free_path;
3755 		    char *date;
3756 		    char *old_path;
3757 
3758 		    old_path = NULL;
3759 		    if (keyword->expandto == KEYWORD_HEADER)
3760 			path = rcs->print_path;
3761 		    else if (keyword->expandto == KEYWORD_CVSHEADER)
3762 			path = getfullCVSname (rcs->print_path, &old_path);
3763 		    else
3764 			path = last_component (rcs->print_path);
3765 		    path = escape_keyword_value (path, &free_path);
3766 		    date = printable_date (ver->date);
3767 		    value = Xasprintf ("%s %s %s %s %s%s%s",
3768 				       path, ver->version, date, ver->author,
3769 				       ver->state,
3770 				       locker != NULL ? " " : "",
3771 				       locker != NULL ? locker : "");
3772 		    if (free_path)
3773 			/* If free_path is set then we know we allocated path
3774 			 * and we can discard the const.
3775 			 */
3776 			free ((char *)path);
3777 		    if (old_path)
3778 			free (old_path);
3779 		    free (date);
3780 		    free_value = 1;
3781 		}
3782 		break;
3783 
3784 	    case KEYWORD_LOCKER:
3785 		value = locker;
3786 		break;
3787 
3788 	    case KEYWORD_LOG:
3789 	    case KEYWORD_RCSFILE:
3790 		value = escape_keyword_value (last_component (rcs->print_path),
3791 					      &free_value);
3792 		break;
3793 
3794 	    case KEYWORD_NAME:
3795 		if (name != NULL && ! isdigit ((unsigned char) *name))
3796 		    value = (char *) name;
3797 		else
3798 		    value = NULL;
3799 		break;
3800 
3801 	    case KEYWORD_REVISION:
3802 		value = ver->version;
3803 		break;
3804 
3805 	    case KEYWORD_SOURCE:
3806 		value = escape_keyword_value (rcs->print_path, &free_value);
3807 		break;
3808 
3809 	    case KEYWORD_STATE:
3810 		value = ver->state;
3811 		break;
3812 	    }
3813 	}
3814 
3815 	sub = xmalloc (keyword->len
3816 		       + (value == NULL ? 0 : strlen (value))
3817 		       + 10);
3818 	if (expand == KFLAG_V)
3819 	{
3820 	    /* Decrement SRCH and increment S to remove the $
3821                characters.  */
3822 	    --srch;
3823 	    ++srch_len;
3824 	    ++s;
3825 	    sublen = 0;
3826 	}
3827 	else
3828 	{
3829 	    strcpy (sub, keyword->string);
3830 	    sublen = strlen (keyword->string);
3831 	    if (expand != KFLAG_K)
3832 	    {
3833 		sub[sublen] = ':';
3834 		sub[sublen + 1] = ' ';
3835 		sublen += 2;
3836 	    }
3837 	}
3838 	if (value != NULL)
3839 	{
3840 	    strcpy (sub + sublen, value);
3841 	    sublen += strlen (value);
3842 	}
3843 	if (expand != KFLAG_V && expand != KFLAG_K)
3844 	{
3845 	    sub[sublen] = ' ';
3846 	    ++sublen;
3847 	    sub[sublen] = '\0';
3848 	}
3849 
3850 	if (free_value)
3851 	    free (value);
3852 
3853 	/* The Log keyword requires special handling.  This behaviour
3854            is taken from RCS 5.7.  The special log message is what RCS
3855            uses for ci -k.  */
3856 	if (keyword->expandto == KEYWORD_LOG
3857 	    && (sizeof "checked in with -k by " <= loglen
3858 		|| log == NULL
3859 		|| strncmp (log, "checked in with -k by ",
3860 			    sizeof "checked in with -k by " - 1) != 0))
3861 	{
3862 	    char *start;
3863 	    char *leader;
3864 	    size_t leader_len, leader_sp_len;
3865 	    const char *logend;
3866 	    const char *snl;
3867 	    int cnl;
3868 	    char *date;
3869 	    const char *sl;
3870 
3871 	    /* We are going to insert the trailing $ ourselves, before
3872                the log message, so we must remove it from S, if we
3873                haven't done so already.  */
3874 	    if (expand != KFLAG_V)
3875 		++s;
3876 
3877 	    /* CVS never has empty log messages, but old RCS files might.  */
3878 	    if (log == NULL)
3879 		log = "";
3880 
3881 	    /* Find the start of the line.  */
3882 	    start = srch;
3883 	    leader_len = 0;
3884 	    while (start > buf && start[-1] != '\n'
3885 		   && leader_len <= xsum (config->MaxCommentLeaderLength,
3886 					  expand != KFLAG_V ? 1 : 0))
3887 	    {
3888 		--start;
3889 		++leader_len;
3890 	    }
3891 
3892 	    if (expand != KFLAG_V)
3893 		/* When automagically determined and !KFLAG_V, we wish to avoid
3894 		 * including the leading `$' of the Log keyword in our leader.
3895 		 */
3896 		--leader_len;
3897 
3898 	    /* If the automagically determined leader exceeds the limit set in
3899 	     * CVSROOT/config, try to use a fallback.
3900 	     */
3901 	    if (leader_len > config->MaxCommentLeaderLength)
3902 	    {
3903 		if (config->UseArchiveCommentLeader && rcs->comment)
3904 		{
3905 		    leader = xstrdup (rcs->comment);
3906 		    leader_len = strlen (rcs->comment);
3907 		}
3908 		else
3909 		{
3910 		    error (0, 0,
3911 "Skipping `$" "Log$' keyword due to excessive comment leader.");
3912 		    continue;
3913 		}
3914 	    }
3915 	    else /* leader_len <= config->MaxCommentLeaderLength */
3916 	    {
3917 		/* Copy the start of the line to use as a comment leader.  */
3918 		leader = xmalloc (leader_len);
3919 		memcpy (leader, start, leader_len);
3920 	    }
3921 
3922 	    leader_sp_len = leader_len;
3923 	    while (leader_sp_len > 0 && isspace (leader[leader_sp_len - 1]))
3924 		--leader_sp_len;
3925 
3926 	    /* RCS does some checking for an old style of Log here,
3927 	       but we don't bother.  RCS issues a warning if it
3928 	       changes anything.  */
3929 
3930 	    /* Count the number of newlines in the log message so that
3931 	       we know how many copies of the leader we will need.  */
3932 	    cnl = 0;
3933 	    logend = log + loglen;
3934 	    for (snl = log; snl < logend; snl++)
3935 		if (*snl == '\n')
3936 		    ++cnl;
3937 
3938 	    /* If the log message did not end in a newline, increment
3939 	     * the newline count so we have space for the extra leader.
3940 	     * Failure to do so results in a buffer overrun.
3941 	     */
3942 	    if (loglen && snl[-1] != '\n')
3943 		++cnl;
3944 
3945 	    date = printable_date (ver->date);
3946 	    sub = xrealloc (sub,
3947 			    (sublen
3948 			     + sizeof "Revision"
3949 			     + strlen (ver->version)
3950 			     + strlen (date)
3951 			     + strlen (ver->author)
3952 			     + loglen
3953 			       /* Use CNL + 2 below:  One leader for each log
3954 				* line, plus the Revision/Author/Date line,
3955 				* plus a trailing blank line.
3956 				*/
3957 			     + (cnl + 2) * leader_len
3958 			     + 20));
3959 	    if (expand != KFLAG_V)
3960 	    {
3961 		sub[sublen] = '$';
3962 		++sublen;
3963 	    }
3964 	    sub[sublen] = '\n';
3965 	    ++sublen;
3966 	    memcpy (sub + sublen, leader, leader_len);
3967 	    sublen += leader_len;
3968 	    sprintf (sub + sublen, "Revision %s  %s  %s\n",
3969 		     ver->version, date, ver->author);
3970 	    sublen += strlen (sub + sublen);
3971 	    free (date);
3972 
3973 	    sl = log;
3974 	    while (sl < logend)
3975 	    {
3976 		if (*sl == '\n')
3977 		{
3978 		    memcpy (sub + sublen, leader, leader_sp_len);
3979 		    sublen += leader_sp_len;
3980 		    sub[sublen] = '\n';
3981 		    ++sublen;
3982 		    ++sl;
3983 		}
3984 		else
3985 		{
3986 		    const char *slnl;
3987 
3988 		    memcpy (sub + sublen, leader, leader_len);
3989 		    sublen += leader_len;
3990 		    for (slnl = sl; slnl < logend && *slnl != '\n'; ++slnl)
3991 			;
3992 		    if (slnl < logend)
3993 			++slnl;
3994 		    memcpy (sub + sublen, sl, slnl - sl);
3995 		    sublen += slnl - sl;
3996 		    if (slnl == logend && slnl[-1] != '\n')
3997 		    {
3998 			/* There was no EOL at the end of the log message.  Add
3999 			 * one.
4000 			 */
4001 			sub[sublen] = '\n';
4002 			++sublen;
4003 		    }
4004 		    sl = slnl;
4005 		}
4006 	    }
4007 
4008 	    memcpy (sub + sublen, leader, leader_sp_len);
4009 	    sublen += leader_sp_len;
4010 
4011 	    free (leader);
4012 	}
4013 
4014 	/* Now SUB contains a string which is to replace the string
4015 	   from SRCH to S.  SUBLEN is the length of SUB.  */
4016 
4017 	if (srch + sublen == s)
4018 	{
4019 	    memcpy (srch, sub, sublen);
4020 	    free (sub);
4021 	}
4022 	else
4023 	{
4024 	    struct expand_buffer *ebuf;
4025 
4026 	    /* We need to change the size of the buffer.  We build a
4027                list of expand_buffer structures.  Each expand_buffer
4028                structure represents a portion of the final output.  We
4029                concatenate them back into a single buffer when we are
4030                done.  This minimizes the number of potentially large
4031                buffer copies we must do.  */
4032 
4033 	    if (ebufs == NULL)
4034 	    {
4035 		ebufs = xmalloc (sizeof *ebuf);
4036 		ebufs->next = NULL;
4037 		ebufs->data = buf;
4038 		ebufs->free_data = 0;
4039 		ebuf_len = srch - buf;
4040 		ebufs->len = ebuf_len;
4041 		ebuf_last = ebufs;
4042 	    }
4043 	    else
4044 	    {
4045 		assert (srch >= ebuf_last->data);
4046 		assert (srch <= ebuf_last->data + ebuf_last->len);
4047 		ebuf_len -= ebuf_last->len - (srch - ebuf_last->data);
4048 		ebuf_last->len = srch - ebuf_last->data;
4049 	    }
4050 
4051 	    ebuf = xmalloc (sizeof *ebuf);
4052 	    ebuf->data = sub;
4053 	    ebuf->len = sublen;
4054 	    ebuf->free_data = 1;
4055 	    ebuf->next = NULL;
4056 	    ebuf_last->next = ebuf;
4057 	    ebuf_last = ebuf;
4058 	    ebuf_len += sublen;
4059 
4060 	    ebuf = xmalloc (sizeof *ebuf);
4061 	    ebuf->data = s;
4062 	    ebuf->len = srch_len - (s - srch);
4063 	    ebuf->free_data = 0;
4064 	    ebuf->next = NULL;
4065 	    ebuf_last->next = ebuf;
4066 	    ebuf_last = ebuf;
4067 	    ebuf_len += srch_len - (s - srch);
4068 	}
4069 
4070 	srch_len -= (s - srch);
4071 	srch = s;
4072     }
4073 
4074     if (locker != NULL)
4075 	free (locker);
4076 
4077     if (ebufs == NULL)
4078     {
4079 	*retbuf = buf;
4080 	*retlen = len;
4081     }
4082     else
4083     {
4084 	char *ret;
4085 
4086 	ret = xmalloc (ebuf_len);
4087 	*retbuf = ret;
4088 	*retlen = ebuf_len;
4089 	while (ebufs != NULL)
4090 	{
4091 	    struct expand_buffer *next;
4092 
4093 	    memcpy (ret, ebufs->data, ebufs->len);
4094 	    ret += ebufs->len;
4095 	    if (ebufs->free_data)
4096 		free (ebufs->data);
4097 	    next = ebufs->next;
4098 	    free (ebufs);
4099 	    ebufs = next;
4100 	}
4101     }
4102 }
4103 
4104 
4105 
4106 /* Check out a revision from an RCS file.
4107 
4108    If PFN is not NULL, then ignore WORKFILE and SOUT.  Call PFN zero
4109    or more times with the contents of the file.  CALLERDAT is passed,
4110    uninterpreted, to PFN.  (The current code will always call PFN
4111    exactly once for a non empty file; however, the current code
4112    assumes that it can hold the entire file contents in memory, which
4113    is not a good assumption, and might change in the future).
4114 
4115    Otherwise, if WORKFILE is not NULL, check out the revision to
4116    WORKFILE.  However, if WORKFILE is not NULL, and noexec is set,
4117    then don't do anything.
4118 
4119    Otherwise, if WORKFILE is NULL, check out the revision to SOUT.  If
4120    SOUT is RUN_TTY, then write the contents of the revision to
4121    standard output.  When using SOUT, the output is generally a
4122    temporary file; don't bother to get the file modes correct.  When
4123    NOEXEC is set, WORKFILEs are not written but SOUTs are.
4124 
4125    REV is the numeric revision to check out.  It may be NULL, which
4126    means to check out the head of the default branch.
4127 
4128    If NAMETAG is not NULL, and is not a numeric revision, then it is
4129    the tag that should be used when expanding the RCS Name keyword.
4130 
4131    OPTIONS is a string such as "-kb" or "-kv" for keyword expansion
4132    options.  It may be NULL to use the default expansion mode of the
4133    file, typically "-kkv".
4134 
4135    On an error which prevented checking out the file, either print a
4136    nonfatal error and return 1, or give a fatal error.  On success,
4137    return 0.  */
4138 
4139 /* This function mimics the behavior of `rcs co' almost exactly.  The
4140    chief difference is in its support for preserving file ownership,
4141    permissions, and special files across checkin and checkout -- see
4142    comments in RCS_checkin for some issues about this. -twp */
4143 int
4144 RCS_checkout (RCSNode *rcs, const char *workfile, const char *rev,
4145               const char *nametag, const char *options, const char *sout,
4146               RCSCHECKOUTPROC pfn, void *callerdat)
4147 {
4148     int free_rev = 0;
4149     enum kflag expand;
4150     FILE *fp,
4151 	 *ofp = NULL; /* Initialize since -Wall doesn't understand that
4152 		       * error (1, ...) does not return.
4153 		       */
4154     struct stat sb;
4155     struct rcsbuffer rcsbuf;
4156     char *key;
4157     char *value;
4158     size_t len;
4159     int free_value = 0;
4160     char *log = NULL;
4161     size_t loglen = 0;
4162     Node *vp = NULL;
4163 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4164     uid_t rcs_owner = (uid_t) -1;
4165     gid_t rcs_group = (gid_t) -1;
4166     mode_t rcs_mode;
4167     int change_rcs_owner_or_group = 0;
4168     int change_rcs_mode = 0;
4169     int special_file = 0;
4170     unsigned long devnum_long;
4171     dev_t devnum = 0;
4172 #endif
4173 
4174     TRACE (TRACE_FUNCTION, "RCS_checkout (%s, %s, %s, %s, %s)",
4175 	   rcs->path,
4176 	   rev != NULL ? rev : "",
4177 	   nametag != NULL ? nametag : "",
4178 	   options != NULL ? options : "",
4179 	   (pfn != NULL ? "(function)"
4180 	    : (workfile != NULL ? workfile
4181 	       : (sout != RUN_TTY ? sout
4182 		  : "(stdout)"))));
4183 
4184     assert (rev == NULL || isdigit ((unsigned char) *rev));
4185 
4186     if (noexec && !server_active && workfile != NULL)
4187 	return 0;
4188 
4189     assert (sout == RUN_TTY || workfile == NULL);
4190     assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL));
4191 
4192     /* Some callers, such as Checkin or remove_file, will pass us a
4193        branch.  */
4194     if (rev != NULL && (numdots (rev) & 1) == 0)
4195     {
4196 	rev = RCS_getbranch (rcs, rev, 1);
4197 	if (rev == NULL)
4198 	    error (1, 0, "internal error: bad branch tag in checkout");
4199 	free_rev = 1;
4200     }
4201 
4202     if (rev == NULL || STREQ (rev, rcs->head))
4203     {
4204 	int gothead;
4205 
4206 	/* We want the head revision.  Try to read it directly.  */
4207 
4208 	if (rcs->flags & PARTIAL)
4209 	    RCS_reparsercsfile (rcs, &fp, &rcsbuf);
4210 	else
4211 	    rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf);
4212 
4213 	gothead = 0;
4214 	if (! rcsbuf_getrevnum (&rcsbuf, &key))
4215 	    error (1, 0, "unexpected EOF reading %s", rcs->print_path);
4216 	while (rcsbuf_getkey (&rcsbuf, &key, &value))
4217 	{
4218 	    if (STREQ (key, "log"))
4219 	    {
4220 		if (log)
4221 		{
4222 		    error (0, 0,
4223 "Duplicate log keyword found for head revision in RCS file.");
4224 		    free (log);
4225 		}
4226 		log = rcsbuf_valcopy (&rcsbuf, value, 0, &loglen);
4227 	    }
4228 	    else if (STREQ (key, "text"))
4229 	    {
4230 		gothead = 1;
4231 		break;
4232 	    }
4233 	}
4234 
4235 	if (! gothead)
4236 	{
4237 	    error (0, 0, "internal error: cannot find head text");
4238 	    if (free_rev)
4239 		/* It's okay to discard the const when free_rev is set, because
4240 		 * we know we allocated it in this function.
4241 		 */
4242 		free ((char *)rev);
4243 	    return 1;
4244 	}
4245 
4246 	rcsbuf_valpolish (&rcsbuf, value, 0, &len);
4247 
4248 	if (fstat (fileno (fp), &sb) < 0)
4249 	    error (1, errno, "cannot fstat %s", rcs->path);
4250 
4251 	rcsbuf_cache (rcs, &rcsbuf);
4252     }
4253     else
4254     {
4255 	struct rcsbuffer *rcsbufp;
4256 
4257 	/* It isn't the head revision of the trunk.  We'll need to
4258 	   walk through the deltas.  */
4259 
4260 	fp = NULL;
4261 	if (rcs->flags & PARTIAL)
4262 	    RCS_reparsercsfile (rcs, &fp, &rcsbuf);
4263 
4264 	if (fp == NULL)
4265 	{
4266 	    /* If RCS_deltas didn't close the file, we could use fstat
4267 	       here too.  Probably should change it thusly....  */
4268 	    if (stat (rcs->path, &sb) < 0)
4269 		error (1, errno, "cannot stat %s", rcs->path);
4270 	    rcsbufp = NULL;
4271 	}
4272 	else
4273 	{
4274 	    if (fstat (fileno (fp), &sb) < 0)
4275 		error (1, errno, "cannot fstat %s", rcs->path);
4276 	    rcsbufp = &rcsbuf;
4277 	}
4278 
4279 	RCS_deltas (rcs, fp, rcsbufp, rev, RCS_FETCH, &value, &len,
4280 		    &log, &loglen);
4281 	free_value = 1;
4282     }
4283 
4284     /* If OPTIONS is NULL or the empty string, then the old code would
4285        invoke the RCS co program with no -k option, which means that
4286        co would use the string we have stored in rcs->expand.  */
4287     if ((options == NULL || options[0] == '\0') && rcs->expand == NULL)
4288 	expand = KFLAG_KV;
4289     else
4290     {
4291 	const char *ouroptions;
4292 	const char * const *cpp;
4293 
4294 	if (options != NULL && options[0] != '\0')
4295 	{
4296 	    assert (options[0] == '-' && options[1] == 'k');
4297 	    ouroptions = options + 2;
4298 	}
4299 	else
4300 	    ouroptions = rcs->expand;
4301 
4302 	for (cpp = kflags; *cpp != NULL; cpp++)
4303 	    if (STREQ (*cpp, ouroptions))
4304 		break;
4305 
4306 	if (*cpp != NULL)
4307 	    expand = (enum kflag) (cpp - kflags);
4308 	else
4309 	{
4310 	    error (0, 0,
4311 		   "internal error: unsupported substitution string -k%s",
4312 		   ouroptions);
4313 	    expand = KFLAG_KV;
4314 	}
4315     }
4316 
4317 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4318     /* Handle special files and permissions, if that is desired. */
4319     if (preserve_perms)
4320     {
4321 	RCSVers *vers;
4322 	Node *info;
4323 
4324 	vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
4325 	if (vp == NULL)
4326 	    error (1, 0, "internal error: no revision information for %s",
4327 		   rev == NULL ? rcs->head : rev);
4328 	vers = vp->data;
4329 
4330 	/* First we look for symlinks, which are simplest to handle. */
4331 	info = findnode (vers->other_delta, "symlink");
4332 	if (info != NULL)
4333 	{
4334 	    char *dest;
4335 
4336 	    if (pfn != NULL || (workfile == NULL && sout == RUN_TTY))
4337 		error (1, 0, "symbolic link %s:%s cannot be piped",
4338 		       rcs->path, vers->version);
4339 	    if (workfile == NULL)
4340 		dest = sout;
4341 	    else
4342 		dest = workfile;
4343 
4344 	    /* Remove `dest', just in case.  It's okay to get ENOENT here,
4345 	       since we just want the file not to be there.  (TODO: decide
4346 	       whether it should be considered an error for `dest' to exist
4347 	       at this point.  If so, the unlink call should be removed and
4348 	       `symlink' should signal the error. -twp) */
4349 	    if (CVS_UNLINK (dest) < 0 && !existence_error (errno))
4350 		error (1, errno, "cannot remove %s", dest);
4351 	    if (symlink (info->data, dest) < 0)
4352 		error (1, errno, "cannot create symbolic link from %s to %s",
4353 		       dest, (char *)info->data);
4354 	    if (free_value)
4355 		free (value);
4356 	    if (free_rev)
4357 		/* It's okay to discard the const when free_rev is set, because
4358 		 * we know we allocated it in this function.
4359 		 */
4360 		free ((char *)rev);
4361 	    return 0;
4362 	}
4363 
4364 	/* Next, we look at this file's hardlinks field, and see whether
4365 	   it is linked to any other file that has been checked out.
4366 	   If so, we don't do anything else -- just link it to that file.
4367 
4368 	   If we are checking out a file to a pipe or temporary storage,
4369 	   none of this should matter.  Hence the `workfile != NULL'
4370 	   wrapper around the whole thing. -twp */
4371 
4372 	if (workfile != NULL)
4373 	{
4374 	    List *links = vers->hardlinks;
4375 	    if (links != NULL)
4376 	    {
4377 		Node *uptodate_link;
4378 
4379 		/* For each file in the hardlinks field, check to see
4380 		   if it exists, and if so, if it has been checked out
4381 		   this iteration.  When walklist returns, uptodate_link
4382 		   should point to a hardlist node representing a file
4383 		   in `links' which has recently been checked out, or
4384 		   NULL if no file in `links' has yet been checked out. */
4385 
4386 		uptodate_link = NULL;
4387 		(void) walklist (links, find_checkedout_proc, &uptodate_link);
4388 		dellist (&links);
4389 
4390 		/* If we've found a file that `workfile' is supposed to be
4391 		   linked to, and it has been checked out since CVS was
4392 		   invoked, then simply link workfile to that file and return.
4393 
4394 		   If one of these conditions is not met, then
4395 		   workfile is the first one in its hardlink group to
4396 		   be checked out, and we must continue with a full
4397 		   checkout. */
4398 
4399 		if (uptodate_link != NULL)
4400 		{
4401 		    struct hardlink_info *hlinfo = uptodate_link->data;
4402 
4403 		    if (link (uptodate_link->key, workfile) < 0)
4404 			error (1, errno, "cannot link %s to %s",
4405 			       workfile, uptodate_link->key);
4406 		    hlinfo->checked_out = 1;	/* probably unnecessary */
4407 		    if (free_value)
4408 			free (value);
4409 		    if (free_rev)
4410 			/* It's okay to discard the const when free_rev is set,
4411 			 * because we know we allocated it in this function.
4412 			 */
4413 			free ((char *)rev);
4414 		    return 0;
4415 		}
4416 	    }
4417 	}
4418 
4419 	info = findnode (vers->other_delta, "owner");
4420 	if (info != NULL)
4421 	{
4422 	    change_rcs_owner_or_group = 1;
4423 	    rcs_owner = (uid_t) strtoul (info->data, NULL, 10);
4424 	}
4425 	info = findnode (vers->other_delta, "group");
4426 	if (info != NULL)
4427 	{
4428 	    change_rcs_owner_or_group = 1;
4429 	    rcs_group = (gid_t) strtoul (info->data, NULL, 10);
4430 	}
4431 	info = findnode (vers->other_delta, "permissions");
4432 	if (info != NULL)
4433 	{
4434 	    change_rcs_mode = 1;
4435 	    rcs_mode = (mode_t) strtoul (info->data, NULL, 8);
4436 	}
4437 	info = findnode (vers->other_delta, "special");
4438 	if (info != NULL)
4439 	{
4440 	    /* If the size of `devtype' changes, fix the sscanf call also */
4441 	    char devtype[16];
4442 
4443 	    if (sscanf (info->data, "%15s %lu",
4444 			devtype, &devnum_long) < 2)
4445 		error (1, 0, "%s:%s has bad `special' newphrase %s",
4446 		       workfile, vers->version, (char *)info->data);
4447 	    devnum = devnum_long;
4448 	    if (STREQ (devtype, "character"))
4449 		special_file = S_IFCHR;
4450 	    else if (STREQ (devtype, "block"))
4451 		special_file = S_IFBLK;
4452 	    else
4453 		error (0, 0, "%s is a special file of unsupported type `%s'",
4454 		       workfile, (char *)info->data);
4455 	}
4456     }
4457 #endif /* PRESERVE_PERMISSIONS_SUPPORT */
4458 
4459     if (expand != KFLAG_O && expand != KFLAG_B)
4460     {
4461 	char *newvalue;
4462 
4463 	/* Don't fetch the delta node again if we already have it. */
4464 	if (vp == NULL)
4465 	{
4466 	    vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
4467 	    if (vp == NULL)
4468 		error (1, 0, "internal error: no revision information for %s",
4469 		       rev == NULL ? rcs->head : rev);
4470 	}
4471 
4472 	expand_keywords (rcs, vp->data, nametag, log, loglen,
4473 			 expand, value, len, &newvalue, &len);
4474 
4475 	if (newvalue != value)
4476 	{
4477 	    if (free_value)
4478 		free (value);
4479 	    value = newvalue;
4480 	    free_value = 1;
4481 	}
4482     }
4483 
4484     if (free_rev)
4485 	/* It's okay to discard the const when free_rev is set, because
4486 	 * we know we allocated it in this function.
4487 	 */
4488 	free ((char *)rev);
4489 
4490     if (log != NULL)
4491     {
4492 	free (log);
4493 	log = NULL;
4494     }
4495 
4496     if (pfn != NULL)
4497     {
4498 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4499 	if (special_file)
4500 	    error (1, 0, "special file %s cannot be piped to anything",
4501 		   rcs->path);
4502 #endif
4503 	/* The PFN interface is very simple to implement right now, as
4504            we always have the entire file in memory.  */
4505 	if (len != 0)
4506 	    pfn (callerdat, value, len);
4507     }
4508 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4509     else if (special_file)
4510     {
4511 # ifdef HAVE_MKNOD
4512 	char *dest;
4513 
4514 	/* Can send either to WORKFILE or to SOUT, as long as SOUT is
4515 	   not RUN_TTY. */
4516 	dest = workfile;
4517 	if (dest == NULL)
4518 	{
4519 	    if (sout == RUN_TTY)
4520 		error (1, 0, "special file %s cannot be written to stdout",
4521 		       rcs->path);
4522 	    dest = sout;
4523 	}
4524 
4525 	/* Unlink `dest', just in case.  It's okay if this provokes a
4526 	   ENOENT error. */
4527 	if (CVS_UNLINK (dest) < 0 && existence_error (errno))
4528 	    error (1, errno, "cannot remove %s", dest);
4529 	if (mknod (dest, special_file, devnum) < 0)
4530 	    error (1, errno, "could not create special file %s",
4531 		   dest);
4532 # else
4533 	error (1, 0,
4534 "cannot create %s: unable to create special files on this system",
4535 workfile);
4536 # endif
4537     }
4538 #endif
4539     else
4540     {
4541 	/* Not a special file: write to WORKFILE or SOUT. */
4542 	if (workfile == NULL)
4543 	{
4544 	    if (sout == RUN_TTY)
4545 		ofp = stdout;
4546 	    else
4547 	    {
4548 		/* Symbolic links should be removed before replacement, so that
4549 		   `fopen' doesn't follow the link and open the wrong file. */
4550 		if (islink (sout))
4551 		    if (unlink_file (sout) < 0)
4552 			error (1, errno, "cannot remove %s", sout);
4553 		ofp = CVS_FOPEN (sout, expand == KFLAG_B ? "wb" : "w");
4554 		if (ofp == NULL)
4555 		    error (1, errno, "cannot open %s", sout);
4556 	    }
4557 	}
4558 	else
4559 	{
4560 	    /* Output is supposed to go to WORKFILE, so we should open that
4561 	       file.  Symbolic links should be removed first (see above). */
4562 	    if (islink (workfile))
4563 		if (unlink_file (workfile) < 0)
4564 		    error (1, errno, "cannot remove %s", workfile);
4565 
4566 	    ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
4567 
4568 	    /* If the open failed because the existing workfile was not
4569 	       writable, try to chmod the file and retry the open.  */
4570 	    if (ofp == NULL && errno == EACCES
4571 		&& isfile (workfile) && !iswritable (workfile))
4572 	    {
4573 		xchmod (workfile, 1);
4574 		ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
4575 	    }
4576 
4577 	    if (ofp == NULL)
4578 	    {
4579 		error (0, errno, "cannot open %s", workfile);
4580 		if (free_value)
4581 		    free (value);
4582 		return 1;
4583 	    }
4584 	}
4585 
4586 	if (workfile == NULL && sout == RUN_TTY)
4587 	{
4588 	    if (expand == KFLAG_B)
4589 		cvs_output_binary (value, len);
4590 	    else
4591 	    {
4592 		/* cvs_output requires the caller to check for zero
4593 		   length.  */
4594 		if (len > 0)
4595 		    cvs_output (value, len);
4596 	    }
4597 	}
4598 	else
4599 	{
4600 	    /* NT 4.0 is said to have trouble writing 2099999 bytes
4601 	       (for example) in a single fwrite.  So break it down
4602 	       (there is no need to be writing that much at once
4603 	       anyway; it is possible that LARGEST_FWRITE should be
4604 	       somewhat larger for good performance, but for testing I
4605 	       want to start with a small value until/unless a bigger
4606 	       one proves useful).  */
4607 #define LARGEST_FWRITE 8192
4608 	    size_t nleft = len;
4609 	    size_t nstep = (len < LARGEST_FWRITE ? len : LARGEST_FWRITE);
4610 	    char *p = value;
4611 
4612 	    while (nleft > 0)
4613 	    {
4614 		if (fwrite (p, 1, nstep, ofp) != nstep)
4615 		{
4616 		    error (0, errno, "cannot write %s",
4617 			   (workfile != NULL
4618 			    ? workfile
4619 			    : (sout != RUN_TTY ? sout : "stdout")));
4620 		    if (free_value)
4621 			free (value);
4622 		    return 1;
4623 		}
4624 		p += nstep;
4625 		nleft -= nstep;
4626 		if (nleft < nstep)
4627 		    nstep = nleft;
4628 	    }
4629 	}
4630     }
4631 
4632     if (free_value)
4633 	free (value);
4634 
4635     if (workfile != NULL)
4636     {
4637 	int ret;
4638 
4639 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4640 	if (!special_file && fclose (ofp) < 0)
4641 	{
4642 	    error (0, errno, "cannot close %s", workfile);
4643 	    return 1;
4644 	}
4645 
4646 	if (change_rcs_owner_or_group)
4647 	{
4648 	    if (chown (workfile, rcs_owner, rcs_group) < 0)
4649 		error (0, errno, "could not change owner or group of %s",
4650 		       workfile);
4651 	}
4652 
4653 	ret = chmod (workfile,
4654 		     change_rcs_mode
4655 		     ? rcs_mode
4656 		     : sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
4657 #else
4658 	if (fclose (ofp) < 0)
4659 	{
4660 	    error (0, errno, "cannot close %s", workfile);
4661 	    return 1;
4662 	}
4663 
4664 	ret = chmod (workfile,
4665 		     sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
4666 #endif
4667 	if (ret < 0)
4668 	{
4669 	    error (0, errno, "cannot change mode of file %s",
4670 		   workfile);
4671 	}
4672     }
4673     else if (sout != RUN_TTY)
4674     {
4675 	if (
4676 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4677 	    !special_file &&
4678 #endif
4679 	    fclose (ofp) < 0)
4680 	{
4681 	    error (0, errno, "cannot close %s", sout);
4682 	    return 1;
4683 	}
4684     }
4685 
4686 #ifdef PRESERVE_PERMISSIONS_SUPPORT
4687     /* If we are in the business of preserving hardlinks, then
4688        mark this file as having been checked out. */
4689     if (preserve_perms && workfile != NULL)
4690 	update_hardlink_info (workfile);
4691 #endif
4692 
4693     return 0;
4694 }
4695 
4696 
4697 
4698 /* Find the delta currently locked by the user.  From the `ci' man page:
4699 
4700 	"If rev is omitted, ci tries to  derive  the  new  revision
4701 	 number  from  the  caller's  last lock.  If the caller has
4702 	 locked the tip revision of a branch, the new  revision  is
4703 	 appended  to  that  branch.   The  new  revision number is
4704 	 obtained by incrementing the tip revision number.  If  the
4705 	 caller  locked a non-tip revision, a new branch is started
4706 	 at that revision by incrementing the highest branch number
4707 	 at  that  revision.   The default initial branch and level
4708 	 numbers are 1.
4709 
4710 	 If rev is omitted and the caller has no lock, but owns the
4711 	 file  and  locking is not set to strict, then the revision
4712 	 is appended to the default branch (normally the trunk; see
4713 	 the -b option of rcs(1))."
4714 
4715    RCS_findlock_or_tip finds the unique revision locked by the caller
4716    and returns its delta node.  If the caller has not locked any
4717    revisions (and is permitted to commit to an unlocked delta, as
4718    described above), return the tip of the default branch. */
4719 static RCSVers *
4720 RCS_findlock_or_tip (RCSNode *rcs)
4721 {
4722     char *user = getcaller();
4723     Node *lock, *p;
4724     List *locklist;
4725 
4726     /* Find unique delta locked by caller. This code is very similar
4727        to the code in RCS_unlock -- perhaps it could be abstracted
4728        into a RCS_findlock function. */
4729     locklist = RCS_getlocks (rcs);
4730     lock = NULL;
4731     for (p = locklist->list->next; p != locklist->list; p = p->next)
4732     {
4733 	if (STREQ (p->data, user))
4734 	{
4735 	    if (lock != NULL)
4736 	    {
4737 		error (0, 0, "\
4738 %s: multiple revisions locked by %s; please specify one", rcs->print_path, user);
4739 		return NULL;
4740 	    }
4741 	    lock = p;
4742 	}
4743     }
4744 
4745     if (lock != NULL)
4746     {
4747 	/* Found an old lock, but check that the revision still exists. */
4748 	p = findnode (rcs->versions, lock->key);
4749 	if (p == NULL)
4750 	{
4751 	    error (0, 0, "%s: can't unlock nonexistent revision %s",
4752 		   rcs->print_path,
4753 		   lock->key);
4754 	    return NULL;
4755 	}
4756 	return p->data;
4757     }
4758 
4759     /* No existing lock.  The RCS rule is that this is an error unless
4760        locking is nonstrict AND the file is owned by the current
4761        user.  Trying to determine the latter is a portability nightmare
4762        in the face of NT, VMS, AFS, and other systems with non-unix-like
4763        ideas of users and owners.  In the case of CVS, we should never get
4764        here (as long as the traditional behavior of making sure to call
4765        RCS_lock persists).  Anyway, we skip the RCS error checks
4766        and just return the default branch or head.  The reasoning is that
4767        those error checks are to make users lock before a checkin, and we do
4768        that in other ways if at all anyway (e.g. rcslock.pl).  */
4769 
4770     p = findnode (rcs->versions, RCS_getbranch (rcs, rcs->branch, 0));
4771     if (!p)
4772     {
4773 	error (0, 0, "RCS file `%s' does not contain its default revision.",
4774 	       rcs->path);
4775 	return NULL;
4776     }
4777 
4778     return p->data;
4779 }
4780 
4781 
4782 
4783 /* Revision number string, R, must contain a `.'.
4784    Return a newly-malloc'd copy of the prefix of R up
4785    to but not including the final `.'.  */
4786 static char *
4787 truncate_revnum (const char *r)
4788 {
4789     size_t len;
4790     char *new_r;
4791     char *dot = strrchr (r, '.');
4792 
4793     assert (dot);
4794     len = dot - r;
4795     new_r = xmalloc (len + 1);
4796     memcpy (new_r, r, len);
4797     *(new_r + len) = '\0';
4798     return new_r;
4799 }
4800 
4801 
4802 
4803 /* Revision number string, R, must contain a `.'.
4804    R must be writable.  Replace the rightmost `.' in R with
4805    the NUL byte and return a pointer to that NUL byte.  */
4806 static char *
4807 truncate_revnum_in_place (char *r)
4808 {
4809     char *dot = strrchr (r, '.');
4810     assert (dot);
4811     *dot = '\0';
4812     return dot;
4813 }
4814 
4815 
4816 
4817 /* Revision number strings, R and S, must each contain a `.'.
4818    R and S must be writable and must have the same number of dots.
4819    Truncate R and S for the comparison, then restored them to their
4820    original state.
4821    Return the result (see compare_revnums) of comparing R and S
4822    ignoring differences in any component after the rightmost `.'.  */
4823 static int
4824 compare_truncated_revnums (char *r, char *s)
4825 {
4826     char *r_dot = truncate_revnum_in_place (r);
4827     char *s_dot = truncate_revnum_in_place (s);
4828     int cmp;
4829 
4830     assert (numdots (r) == numdots (s));
4831 
4832     cmp = compare_revnums (r, s);
4833 
4834     *r_dot = '.';
4835     *s_dot = '.';
4836 
4837     return cmp;
4838 }
4839 
4840 
4841 
4842 /* Return a malloc'd copy of the string representing the highest branch
4843    number on BRANCHNODE.  If there are no branches on BRANCHNODE, return NULL.
4844    FIXME: isn't the max rev always the last one?
4845    If so, we don't even need a loop.  */
4846 static char *
4847 max_rev (const RCSVers *branchnode)
4848 {
4849     Node *head;
4850     Node *bp;
4851     char *max;
4852 
4853     if (branchnode->branches == NULL)
4854     {
4855         return NULL;
4856     }
4857 
4858     max = NULL;
4859     head = branchnode->branches->list;
4860     for (bp = head->next; bp != head; bp = bp->next)
4861     {
4862 	if (max == NULL || compare_truncated_revnums (max, bp->key) < 0)
4863 	{
4864 	    max = bp->key;
4865 	}
4866     }
4867     assert (max);
4868 
4869     return truncate_revnum (max);
4870 }
4871 
4872 
4873 
4874 /* Create BRANCH in RCS's delta tree.  BRANCH may be either a branch
4875    number or a revision number.  In the former case, create the branch
4876    with the specified number; in the latter case, create a new branch
4877    rooted at node BRANCH with a higher branch number than any others.
4878    Return the number of the tip node on the new branch. */
4879 static char *
4880 RCS_addbranch (RCSNode *rcs, const char *branch)
4881 {
4882     char *branchpoint, *newrevnum;
4883     Node *nodep, *bp;
4884     Node *marker;
4885     RCSVers *branchnode;
4886 
4887     assert (branch);
4888 
4889     /* Append to end by default.  */
4890     marker = NULL;
4891 
4892     branchpoint = xstrdup (branch);
4893     if ((numdots (branchpoint) & 1) == 0)
4894     {
4895 	truncate_revnum_in_place (branchpoint);
4896     }
4897 
4898     /* Find the branch rooted at BRANCHPOINT. */
4899     nodep = findnode (rcs->versions, branchpoint);
4900     if (nodep == NULL)
4901     {
4902 	error (0, 0, "%s: can't find branch point %s", rcs->print_path, branchpoint);
4903 	free (branchpoint);
4904 	return NULL;
4905     }
4906     free (branchpoint);
4907     branchnode = nodep->data;
4908 
4909     /* If BRANCH was a full branch number, make sure it is higher than MAX. */
4910     if ((numdots (branch) & 1) == 1)
4911     {
4912 	if (branchnode->branches == NULL)
4913 	{
4914 	    /* We have to create the first branch on this node, which means
4915 	       appending ".2" to the revision number. */
4916 	    newrevnum = Xasprintf ("%s.2", branch);
4917 	}
4918 	else
4919 	{
4920 	    char *max = max_rev (branchnode);
4921 	    assert (max);
4922 	    newrevnum = increment_revnum (max);
4923 	    free (max);
4924 	}
4925     }
4926     else
4927     {
4928 	newrevnum = xstrdup (branch);
4929 
4930 	if (branchnode->branches != NULL)
4931 	{
4932 	    Node *head;
4933 	    Node *bp;
4934 
4935 	    /* Find the position of this new branch in the sorted list
4936 	       of branches.  */
4937 	    head = branchnode->branches->list;
4938 	    for (bp = head->next; bp != head; bp = bp->next)
4939 	    {
4940 		char *dot;
4941 		int found_pos;
4942 
4943 		/* The existing list must be sorted on increasing revnum.  */
4944 		assert (bp->next == head
4945 			|| compare_truncated_revnums (bp->key,
4946 						      bp->next->key) < 0);
4947 		dot = truncate_revnum_in_place (bp->key);
4948 		found_pos = (compare_revnums (branch, bp->key) < 0);
4949 		*dot = '.';
4950 
4951 		if (found_pos)
4952 		{
4953 		    break;
4954 		}
4955 	    }
4956 	    marker = bp;
4957 	}
4958     }
4959 
4960     newrevnum = xrealloc (newrevnum, strlen (newrevnum) + 3);
4961     strcat (newrevnum, ".1");
4962 
4963     /* Add this new revision number to BRANCHPOINT's branches list. */
4964     if (branchnode->branches == NULL)
4965 	branchnode->branches = getlist();
4966     bp = getnode();
4967     bp->key = xstrdup (newrevnum);
4968 
4969     /* Append to the end of the list by default, that is, just before
4970        the header node, `list'.  */
4971     if (marker == NULL)
4972 	marker = branchnode->branches->list;
4973 
4974     {
4975 	int fail;
4976 	fail = insert_before (branchnode->branches, marker, bp);
4977 	assert (!fail);
4978     }
4979 
4980     return newrevnum;
4981 }
4982 
4983 
4984 
4985 /* Check in to RCSFILE with revision REV (which must be greater than
4986    the largest revision) and message MESSAGE (which is checked for
4987    validity).  If FLAGS & RCS_FLAGS_DEAD, check in a dead revision.
4988    If FLAGS & RCS_FLAGS_QUIET, tell ci to be quiet.  If FLAGS &
4989    RCS_FLAGS_MODTIME, use the working file's modification time for the
4990    checkin time.  WORKFILE is the working file to check in from, or
4991    NULL to use the usual RCS rules for deriving it from the RCSFILE.
4992    If FLAGS & RCS_FLAGS_KEEPFILE, don't unlink the working file;
4993    unlinking the working file is standard RCS behavior, but is rarely
4994    appropriate for CVS.
4995 
4996    UPDATE_DIR is used to print the path for the file.  This argument is
4997    unnecessary when FLAGS & RCS_FLAGS_QUIET since the path won't be printed
4998    anyhow.
4999 
5000    This function should almost exactly mimic the behavior of `rcs ci'.  The
5001    principal point of difference is the support here for preserving file
5002    ownership and permissions in the delta nodes.  This is not a clean
5003    solution -- precisely because it diverges from RCS's behavior -- but
5004    it doesn't seem feasible to do this anywhere else in the code. [-twp]
5005 
5006    Return value is -1 for error (and errno is set to indicate the
5007    error), positive for error (and an error message has been printed),
5008    or zero for success.  */
5009 int
5010 RCS_checkin (RCSNode *rcs, const char *update_dir, const char *workfile_in,
5011 	     const char *message, const char *rev, time_t citime, int flags)
5012 {
5013     RCSVers *delta, *commitpt;
5014     Deltatext *dtext;
5015     Node *nodep;
5016     char *tmpfile, *changefile;
5017     int dargc = 0;
5018     size_t darg_allocated = 0;
5019     char **dargv = NULL;
5020     size_t bufsize;
5021     int status, checkin_quiet;
5022     struct tm *ftm;
5023     time_t modtime;
5024     int adding_branch = 0;
5025     char *workfile = xstrdup (workfile_in);
5026 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5027     struct stat sb;
5028 #endif
5029     Node *np;
5030 
5031     commitpt = NULL;
5032 
5033     if (rcs->flags & PARTIAL)
5034 	RCS_reparsercsfile (rcs, NULL, NULL);
5035 
5036     /* Get basename of working file.  Is there a library function to
5037        do this?  I couldn't find one. -twp */
5038     if (workfile == NULL)
5039     {
5040 	char *p;
5041 	int extlen = strlen (RCSEXT);
5042 	assert (rcs->path);
5043 	workfile = xstrdup (last_component (rcs->path));
5044 	p = workfile + (strlen (workfile) - extlen);
5045 	assert (strncmp (p, RCSEXT, extlen) == 0);
5046 	*p = '\0';
5047     }
5048 
5049     /* If the filename is a symbolic link, follow it and replace it
5050        with the destination of the link.  We need to do this before
5051        calling rcs_internal_lockfile, or else we won't put the lock in
5052        the right place. */
5053     resolve_symlink (&(rcs->path));
5054 
5055     checkin_quiet = flags & RCS_FLAGS_QUIET;
5056     if (!(checkin_quiet || really_quiet))
5057     {
5058 	cvs_output (rcs->path, 0);
5059 	cvs_output ("  <--  ", 7);
5060 	if (update_dir && strlen (update_dir))
5061 	{
5062 	    cvs_output (update_dir, 0);
5063 	    cvs_output ("/", 1);
5064 	}
5065 	cvs_output (workfile, 0);
5066 	cvs_output ("\n", 1);
5067     }
5068 
5069     /* Create new delta node. */
5070     delta = xmalloc (sizeof (RCSVers));
5071     memset (delta, 0, sizeof (RCSVers));
5072     delta->author = xstrdup (getcaller ());
5073     if (flags & RCS_FLAGS_MODTIME)
5074     {
5075 	struct stat ws;
5076 	if (stat (workfile, &ws) < 0)
5077 	{
5078 	    error (1, errno, "cannot stat %s", workfile);
5079 	}
5080 	modtime = ws.st_mtime;
5081     }
5082     else if (flags & RCS_FLAGS_USETIME)
5083 	modtime = citime;
5084     else
5085 	(void) time (&modtime);
5086     ftm = gmtime (&modtime);
5087     delta->date = Xasprintf (DATEFORM,
5088 			     ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
5089 			     ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
5090 			     ftm->tm_min, ftm->tm_sec);
5091     if (flags & RCS_FLAGS_DEAD)
5092     {
5093 	delta->state = xstrdup (RCSDEAD);
5094 	delta->dead = 1;
5095     }
5096     else
5097 	delta->state = xstrdup ("Exp");
5098 
5099     delta->other_delta = getlist();
5100 
5101     /* save the commit ID */
5102     np = getnode();
5103     np->type = RCSFIELD;
5104     np->key = xstrdup ("commitid");
5105     np->data = xstrdup(global_session_id);
5106     addnode (delta->other_delta, np);
5107 
5108 
5109 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5110     /* If permissions should be preserved on this project, then
5111        save the permission info. */
5112     if (preserve_perms)
5113     {
5114 	Node *np;
5115 	char buf[64];	/* static buffer should be safe: see usage. -twp */
5116 
5117 	delta->other_delta = getlist();
5118 
5119 	if (lstat (workfile, &sb) < 0)
5120 	    error (1, errno, "cannot lstat %s", workfile);
5121 
5122 	if (S_ISLNK (sb.st_mode))
5123 	{
5124 	    np = getnode();
5125 	    np->type = RCSFIELD;
5126 	    np->key = xstrdup ("symlink");
5127 	    np->data = Xreadlink (workfile, sb.st_size);
5128 	    addnode (delta->other_delta, np);
5129 	}
5130 	else
5131 	{
5132 	    (void) sprintf (buf, "%u", sb.st_uid);
5133 	    np = getnode();
5134 	    np->type = RCSFIELD;
5135 	    np->key = xstrdup ("owner");
5136 	    np->data = xstrdup (buf);
5137 	    addnode (delta->other_delta, np);
5138 
5139 	    (void) sprintf (buf, "%u", sb.st_gid);
5140 	    np = getnode();
5141 	    np->type = RCSFIELD;
5142 	    np->key = xstrdup ("group");
5143 	    np->data = xstrdup (buf);
5144 	    addnode (delta->other_delta, np);
5145 
5146 	    (void) sprintf (buf, "%o", sb.st_mode & 07777);
5147 	    np = getnode();
5148 	    np->type = RCSFIELD;
5149 	    np->key = xstrdup ("permissions");
5150 	    np->data = xstrdup (buf);
5151 	    addnode (delta->other_delta, np);
5152 
5153 	    /* Save device number. */
5154 	    switch (sb.st_mode & S_IFMT)
5155 	    {
5156 		case S_IFREG: break;
5157 		case S_IFCHR:
5158 		case S_IFBLK:
5159 # ifdef HAVE_STRUCT_STAT_ST_RDEV
5160 		    np = getnode();
5161 		    np->type = RCSFIELD;
5162 		    np->key = xstrdup ("special");
5163 		    sprintf (buf, "%s %lu",
5164 			     ((sb.st_mode & S_IFMT) == S_IFCHR
5165 			      ? "character" : "block"),
5166 			     (unsigned long) sb.st_rdev);
5167 		    np->data = xstrdup (buf);
5168 		    addnode (delta->other_delta, np);
5169 # else
5170 		    error (0, 0,
5171 "can't preserve %s: unable to save device files on this system",
5172 workfile);
5173 # endif
5174 		    break;
5175 
5176 		default:
5177 		    error (0, 0, "special file %s has unknown type", workfile);
5178 	    }
5179 
5180 	    /* Save hardlinks. */
5181 	    delta->hardlinks = list_linked_files_on_disk (workfile);
5182 	}
5183     }
5184 #endif
5185 
5186     /* Create a new deltatext node. */
5187     dtext = xmalloc (sizeof (Deltatext));
5188     memset (dtext, 0, sizeof (Deltatext));
5189 
5190     dtext->log = make_message_rcsvalid (message);
5191 
5192     /* If the delta tree is empty, then there's nothing to link the
5193        new delta into.  So make a new delta tree, snarf the working
5194        file contents, and just write the new RCS file. */
5195     if (rcs->head == NULL)
5196     {
5197 	char *newrev;
5198 	FILE *fout;
5199 
5200 	/* Figure out what the first revision number should be. */
5201 	if (rev == NULL || *rev == '\0')
5202 	    newrev = xstrdup ("1.1");
5203 	else if (numdots (rev) == 0)
5204 	{
5205 	    newrev = Xasprintf ("%s.1", rev);
5206 	}
5207 	else
5208 	    newrev = xstrdup (rev);
5209 
5210 	/* Don't need to xstrdup NEWREV because it's already dynamic, and
5211 	   not used for anything else.  (Don't need to free it, either.) */
5212 	rcs->head = newrev;
5213 	delta->version = xstrdup (newrev);
5214 	nodep = getnode();
5215 	nodep->type = RCSVERS;
5216 	nodep->delproc = rcsvers_delproc;
5217 	nodep->data = delta;
5218 	nodep->key = delta->version;
5219 	(void) addnode (rcs->versions, nodep);
5220 
5221 	dtext->version = xstrdup (newrev);
5222 	bufsize = 0;
5223 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5224 	if (preserve_perms && !S_ISREG (sb.st_mode))
5225 	    /* Pretend file is empty.  */
5226 	    bufsize = 0;
5227 	else
5228 #endif
5229 	get_file (workfile, workfile,
5230 		  rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5231 		  &dtext->text, &bufsize, &dtext->len);
5232 
5233 	if (!(checkin_quiet || really_quiet))
5234 	{
5235 	    cvs_output ("initial revision: ", 0);
5236 	    cvs_output (rcs->head, 0);
5237 	    cvs_output ("\n", 1);
5238 	}
5239 
5240 	/* We are probably about to invalidate any cached file.  */
5241 	rcsbuf_cache_close ();
5242 
5243 	fout = rcs_internal_lockfile (rcs->path);
5244 	RCS_putadmin (rcs, fout);
5245 	RCS_putdtree (rcs, rcs->head, fout);
5246 	RCS_putdesc (rcs, fout);
5247 	rcs->delta_pos = ftello (fout);
5248 	if (rcs->delta_pos == -1)
5249 	    error (1, errno, "cannot ftello for %s", rcs->path);
5250 	putdeltatext (fout, dtext);
5251 	rcs_internal_unlockfile (fout, rcs->path);
5252 
5253 	if ((flags & RCS_FLAGS_KEEPFILE) == 0)
5254 	{
5255 	    if (unlink_file (workfile) < 0)
5256 		/* FIXME-update-dir: message does not include update_dir.  */
5257 		error (0, errno, "cannot remove %s", workfile);
5258 	}
5259 
5260 	status = 0;
5261 	goto checkin_done;
5262     }
5263 
5264     /* Derive a new revision number.  From the `ci' man page:
5265 
5266 	 "If rev  is  a revision number, it must be higher than the
5267 	 latest one on the branch to which  rev  belongs,  or  must
5268 	 start a new branch.
5269 
5270 	 If  rev is a branch rather than a revision number, the new
5271 	 revision is appended to that branch.  The level number  is
5272 	 obtained  by  incrementing the tip revision number of that
5273 	 branch.  If rev  indicates  a  non-existing  branch,  that
5274 	 branch  is  created  with  the  initial  revision numbered
5275 	 rev.1."
5276 
5277        RCS_findlock_or_tip handles the case where REV is omitted.
5278        RCS 5.7 also permits REV to be "$" or to begin with a dot, but
5279        we do not address those cases -- every routine that calls
5280        RCS_checkin passes it a numeric revision. */
5281 
5282     if (rev == NULL || *rev == '\0')
5283     {
5284 	/* Figure out where the commit point is by looking for locks.
5285 	   If the commit point is at the tip of a branch (or is the
5286 	   head of the delta tree), then increment its revision number
5287 	   to obtain the new revnum.  Otherwise, start a new
5288 	   branch. */
5289 	commitpt = RCS_findlock_or_tip (rcs);
5290 	if (commitpt == NULL)
5291 	{
5292 	    status = 1;
5293 	    goto checkin_done;
5294 	}
5295 	else if (commitpt->next == NULL
5296 		 || STREQ (commitpt->version, rcs->head))
5297 	    delta->version = increment_revnum (commitpt->version);
5298 	else
5299 	    delta->version = RCS_addbranch (rcs, commitpt->version);
5300     }
5301     else
5302     {
5303 	/* REV is either a revision number or a branch number.  Find the
5304 	   tip of the target branch. */
5305 	char *branch, *tip, *newrev, *p;
5306 	int dots, isrevnum;
5307 
5308 	assert (isdigit ((unsigned char) *rev));
5309 
5310 	newrev = xstrdup (rev);
5311 	dots = numdots (newrev);
5312 	isrevnum = dots & 1;
5313 
5314 	branch = xstrdup (rev);
5315 	if (isrevnum)
5316 	{
5317 	    p = strrchr (branch, '.');
5318 	    *p = '\0';
5319 	}
5320 
5321 	/* Find the tip of the target branch.  If we got a one- or two-digit
5322 	   revision number, this will be the head of the tree.  Exception:
5323 	   if rev is a single-field revision equal to the branch number of
5324 	   the trunk (usually "1") then we want to treat it like an ordinary
5325 	   branch revision. */
5326 	if (dots == 0)
5327 	{
5328 	    tip = xstrdup (rcs->head);
5329 	    if (atoi (tip) != atoi (branch))
5330 	    {
5331 		newrev = xrealloc (newrev, strlen (newrev) + 3);
5332 		strcat (newrev, ".1");
5333 		dots = isrevnum = 1;
5334 	    }
5335 	}
5336 	else if (dots == 1)
5337 	    tip = xstrdup (rcs->head);
5338 	else
5339 	    tip = RCS_getbranch (rcs, branch, 1);
5340 
5341 	/* If the branch does not exist, and we were supplied an exact
5342 	   revision number, signal an error.  Otherwise, if we were
5343 	   given only a branch number, create it and set COMMITPT to
5344 	   the branch point. */
5345 	if (tip == NULL)
5346 	{
5347 	    if (isrevnum)
5348 	    {
5349 		error (0, 0, "%s: can't find branch point %s",
5350 		       rcs->print_path, branch);
5351 		free (branch);
5352 		free (newrev);
5353 		status = 1;
5354 		goto checkin_done;
5355 	    }
5356 	    delta->version = RCS_addbranch (rcs, branch);
5357 	    if (!delta->version)
5358 	    {
5359 		free (branch);
5360 		free (newrev);
5361 		status = 1;
5362 		goto checkin_done;
5363 	    }
5364 	    adding_branch = 1;
5365 	    p = strrchr (branch, '.');
5366 	    *p = '\0';
5367 	    tip = xstrdup (branch);
5368 	}
5369 	else
5370 	{
5371 	    if (isrevnum)
5372 	    {
5373 		/* NEWREV must be higher than TIP. */
5374 		if (compare_revnums (tip, newrev) >= 0)
5375 		{
5376 		    error (0, 0,
5377 			   "%s: revision %s too low; must be higher than %s",
5378 			   rcs->print_path,
5379 			   newrev, tip);
5380 		    free (branch);
5381 		    free (newrev);
5382 		    free (tip);
5383 		    status = 1;
5384 		    goto checkin_done;
5385 		}
5386 		delta->version = xstrdup (newrev);
5387 	    }
5388 	    else
5389 		/* Just increment the tip number to get the new revision. */
5390 		delta->version = increment_revnum (tip);
5391 	}
5392 
5393 	nodep = findnode (rcs->versions, tip);
5394 	commitpt = nodep->data;
5395 
5396 	free (branch);
5397 	free (newrev);
5398 	free (tip);
5399     }
5400 
5401     assert (delta->version != NULL);
5402 
5403     /* If COMMITPT is locked by us, break the lock.  If it's locked
5404        by someone else, signal an error. */
5405     nodep = findnode (RCS_getlocks (rcs), commitpt->version);
5406     if (nodep != NULL)
5407     {
5408 	if (! STREQ (nodep->data, delta->author))
5409 	{
5410 	    /* If we are adding a branch, then leave the old lock around.
5411 	       That is sensible in the sense that when adding a branch,
5412 	       we don't need to use the lock to tell us where to check
5413 	       in.  It is fishy in the sense that if it is our own lock,
5414 	       we break it.  However, this is the RCS 5.7 behavior (at
5415 	       the end of addbranch in ci.c in RCS 5.7, it calls
5416 	       removelock only if it is our own lock, not someone
5417 	       else's).  */
5418 
5419 	    if (!adding_branch)
5420 	    {
5421 		error (0, 0, "%s: revision %s locked by %s",
5422 		       rcs->print_path,
5423 		       nodep->key, (char *)nodep->data);
5424 		status = 1;
5425 		goto checkin_done;
5426 	    }
5427 	}
5428 	else
5429 	    delnode (nodep);
5430     }
5431 
5432     dtext->version = xstrdup (delta->version);
5433 
5434     /* Obtain the change text for the new delta.  If DELTA is to be the
5435        new head of the tree, then its change text should be the contents
5436        of the working file, and LEAFNODE's change text should be a diff.
5437        Else, DELTA's change text should be a diff between LEAFNODE and
5438        the working file. */
5439 
5440     tmpfile = cvs_temp_name();
5441     status = RCS_checkout (rcs, NULL, commitpt->version, NULL,
5442 			   ((rcs->expand != NULL
5443 			     && STREQ (rcs->expand, "b"))
5444 			    ? "-kb"
5445 			    : "-ko"),
5446 			   tmpfile,
5447 			   NULL, NULL);
5448     if (status != 0)
5449 	error (1, 0,
5450 	       "could not check out revision %s of `%s'",
5451 	       commitpt->version, rcs->print_path);
5452 
5453     bufsize = 0;
5454     changefile = cvs_temp_name();
5455 
5456     /* Diff options should include --binary if the RCS file has -kb set
5457        in its `expand' field. */
5458     run_add_arg_p (&dargc, &darg_allocated, &dargv, "-a");
5459     run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n");
5460     if (rcs->expand != NULL && STREQ (rcs->expand, "b"))
5461 	run_add_arg_p (&dargc, &darg_allocated, &dargv, "--binary");
5462 
5463     if (STREQ (commitpt->version, rcs->head) &&
5464 	numdots (delta->version) == 1)
5465     {
5466 	/* If this revision is being inserted on the trunk, the change text
5467 	   for the new delta should be the contents of the working file ... */
5468 	bufsize = 0;
5469 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5470 	if (preserve_perms && !S_ISREG (sb.st_mode))
5471 	    /* Pretend file is empty.  */
5472 	    ;
5473 	else
5474 #endif
5475 	get_file (workfile, workfile,
5476 		  rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5477 		  &dtext->text, &bufsize, &dtext->len);
5478 
5479 	/* ... and the change text for the old delta should be a diff. */
5480 	commitpt->text = xmalloc (sizeof (Deltatext));
5481 	memset (commitpt->text, 0, sizeof (Deltatext));
5482 
5483 	bufsize = 0;
5484 	switch (diff_exec (workfile, tmpfile, NULL, NULL,
5485 			   dargc, dargv, changefile))
5486 	{
5487 	    case 0:
5488 	    case 1:
5489 		break;
5490 	    case -1:
5491 		/* FIXME-update-dir: message does not include update_dir.  */
5492 		error (1, errno, "error diffing %s", workfile);
5493 		break;
5494 	    default:
5495 		/* FIXME-update-dir: message does not include update_dir.  */
5496 		error (1, 0, "error diffing %s", workfile);
5497 		break;
5498 	}
5499 
5500 	/* OK, the text file case here is really dumb.  Logically
5501 	   speaking we want diff to read the files in text mode,
5502 	   convert them to the canonical form found in RCS files
5503 	   (which, we hope at least, is independent of OS--always
5504 	   bare linefeeds), and then work with change texts in that
5505 	   format.  However, diff_exec both generates change
5506 	   texts and produces output for user purposes (e.g. patch.c),
5507 	   and there is no way to distinguish between the two cases.
5508 	   So we actually implement the text file case by writing the
5509 	   change text as a text file, then reading it as a text file.
5510 	   This should cause no harm, but doesn't strike me as
5511 	   immensely clean.  */
5512 	get_file (changefile, changefile,
5513 		  rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5514 		  &commitpt->text->text, &bufsize, &commitpt->text->len);
5515 
5516 	/* If COMMITPT->TEXT->TEXT is NULL, it means that CHANGEFILE
5517 	   was empty and that there are no differences between revisions.
5518 	   In that event, we want to force RCS_rewrite to write an empty
5519 	   string for COMMITPT's change text.  Leaving the change text
5520 	   field set NULL won't work, since that means "preserve the original
5521 	   change text for this delta." */
5522 	if (commitpt->text->text == NULL)
5523 	{
5524 	    commitpt->text->text = xstrdup ("");
5525 	    commitpt->text->len = 0;
5526 	}
5527     }
5528     else
5529     {
5530 	/* This file is not being inserted at the head, but on a side
5531 	   branch somewhere.  Make a diff from the previous revision
5532 	   to the working file. */
5533 	switch (diff_exec (tmpfile, workfile, NULL, NULL,
5534 			   dargc, dargv, changefile))
5535 	{
5536 	    case 0:
5537 	    case 1:
5538 		break;
5539 	    case -1:
5540 		/* FIXME-update-dir: message does not include update_dir.  */
5541 		error (1, errno, "error diffing %s", workfile);
5542 		break;
5543 	    default:
5544 		/* FIXME-update-dir: message does not include update_dir.  */
5545 		error (1, 0, "error diffing %s", workfile);
5546 		break;
5547 	}
5548 	/* See the comment above, at the other get_file invocation,
5549 	   regarding binary vs. text.  */
5550 	get_file (changefile, changefile,
5551 		  rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
5552 		  &dtext->text, &bufsize,
5553 		  &dtext->len);
5554 	if (dtext->text == NULL)
5555 	{
5556 	    dtext->text = xstrdup ("");
5557 	    dtext->len = 0;
5558 	}
5559     }
5560 
5561     run_arg_free_p (dargc, dargv);
5562     free (dargv);
5563 
5564     /* Update DELTA linkage.  It is important not to do this before
5565        the very end of RCS_checkin; if an error arises that forces
5566        us to abort checking in, we must not have malformed deltas
5567        partially linked into the tree.
5568 
5569        If DELTA and COMMITPT are on different branches, do nothing --
5570        DELTA is linked to the tree through COMMITPT->BRANCHES, and we
5571        don't want to change `next' pointers.
5572 
5573        Otherwise, if the nodes are both on the trunk, link DELTA to
5574        COMMITPT; otherwise, link COMMITPT to DELTA. */
5575 
5576     if (numdots (commitpt->version) == numdots (delta->version))
5577     {
5578 	if (STREQ (commitpt->version, rcs->head))
5579 	{
5580 	    delta->next = rcs->head;
5581 	    rcs->head = xstrdup (delta->version);
5582 	}
5583 	else
5584 	    commitpt->next = xstrdup (delta->version);
5585     }
5586 
5587     /* Add DELTA to RCS->VERSIONS. */
5588     if (rcs->versions == NULL)
5589 	rcs->versions = getlist();
5590     nodep = getnode();
5591     nodep->type = RCSVERS;
5592     nodep->delproc = rcsvers_delproc;
5593     nodep->data = delta;
5594     nodep->key = delta->version;
5595     (void) addnode (rcs->versions, nodep);
5596 
5597     /* Write the new RCS file, inserting the new delta at COMMITPT. */
5598     if (!(checkin_quiet || really_quiet))
5599     {
5600 	cvs_output ("new revision: ", 14);
5601 	cvs_output (delta->version, 0);
5602 	cvs_output ("; previous revision: ", 21);
5603 	cvs_output (commitpt->version, 0);
5604 	cvs_output ("\n", 1);
5605     }
5606 
5607     RCS_rewrite (rcs, dtext, commitpt->version);
5608 
5609     if ((flags & RCS_FLAGS_KEEPFILE) == 0)
5610     {
5611 	if (unlink_file (workfile) < 0)
5612 	    /* FIXME-update-dir: message does not include update_dir.  */
5613 	    error (1, errno, "cannot remove %s", workfile);
5614     }
5615     if (unlink_file (tmpfile) < 0)
5616 	error (0, errno, "cannot remove %s", tmpfile);
5617     free (tmpfile);
5618     if (unlink_file (changefile) < 0)
5619 	error (0, errno, "cannot remove %s", changefile);
5620     free (changefile);
5621 
5622  checkin_done:
5623     free (workfile);
5624 
5625     if (commitpt != NULL && commitpt->text != NULL)
5626     {
5627 	freedeltatext (commitpt->text);
5628 	commitpt->text = NULL;
5629     }
5630 
5631     freedeltatext (dtext);
5632     if (status != 0)
5633     {
5634 	/* If delta has not been added to a List, then freeing the Node key
5635 	 * won't free delta->version.
5636 	 */
5637 	if (delta->version) free (delta->version);
5638 	free_rcsvers_contents (delta);
5639     }
5640 
5641     return status;
5642 }
5643 
5644 
5645 
5646 /* This structure is passed between RCS_cmp_file and cmp_file_buffer.  */
5647 struct cmp_file_data
5648 {
5649     const char *filename;
5650     FILE *fp;
5651     int different;
5652 };
5653 
5654 /* Compare the contents of revision REV1 of RCS file RCS with the
5655    contents of REV2 if given, otherwise, compare with the contents of
5656    the file FILENAME.  OPTIONS is a string for the keyword
5657    expansion options.  Return 0 if the contents of the revision are
5658    the same as the contents of the file, 1 if they are different.  */
5659 int
5660 RCS_cmp_file (RCSNode *rcs, const char *rev1, char **rev1_cache,
5661               const char *rev2, const char *options, const char *filename)
5662 {
5663     int binary;
5664 
5665     TRACE (TRACE_FUNCTION, "RCS_cmp_file( %s, %s, %s, %s, %s )",
5666            rcs->path ? rcs->path : "(null)",
5667 	   rev1 ? rev1 : "(null)", rev2 ? rev2 : "(null)",
5668 	   options ? options : "(null)", filename ? filename : "(null)");
5669 
5670     if (options != NULL && options[0] != '\0')
5671 	binary = STREQ (options, "-kb");
5672     else
5673     {
5674 	char *expand;
5675 
5676 	expand = RCS_getexpand (rcs);
5677 	if (expand != NULL && STREQ (expand, "b"))
5678 	    binary = 1;
5679 	else
5680 	    binary = 0;
5681     }
5682 
5683 #ifdef PRESERVE_PERMISSIONS_SUPPORT
5684     /* If CVS is to deal properly with special files (when
5685        PreservePermissions is on), the best way is to check out the
5686        revision to a temporary file and call `xcmp' on the two disk
5687        files.  xcmp needs to handle non-regular files properly anyway,
5688        so calling it simplifies RCS_cmp_file.  We *could* just yank
5689        the delta node out of the version tree and look for device
5690        numbers, but writing to disk and calling xcmp is a better
5691        abstraction (therefore probably more robust). -twp */
5692 
5693     if (preserve_perms)
5694     {
5695 	char *tmp;
5696 	int retcode;
5697 
5698 	tmp = cvs_temp_name();
5699 	retcode = RCS_checkout(rcs, NULL, rev, NULL, options, tmp, NULL, NULL);
5700 	if (retcode != 0)
5701 	    return 1;
5702 
5703 	retcode = xcmp (tmp, filename);
5704 	if (CVS_UNLINK (tmp) < 0)
5705 	    error (0, errno, "cannot remove %s", tmp);
5706 	free (tmp);
5707 	return retcode;
5708     }
5709     else
5710 #endif
5711     {
5712 	FILE *fp;
5713 	struct cmp_file_data data;
5714 	const char *use_file1;
5715 	char *tmpfile = NULL;
5716 
5717 	if (rev2 != NULL)
5718 	{
5719 	    /* Open & cache rev1 */
5720 	    tmpfile = cvs_temp_name();
5721 	    if (RCS_checkout (rcs, NULL, rev1, NULL, options, tmpfile,
5722 	                      NULL, NULL))
5723 		error (1, errno,
5724 		       "cannot check out revision %s of %s",
5725 		       rev1, rcs->print_path);
5726 	    use_file1 = tmpfile;
5727 	    if (rev1_cache != NULL)
5728 		*rev1_cache = tmpfile;
5729 	}
5730 	else
5731 	    use_file1 = filename;
5732 
5733         fp = CVS_FOPEN (use_file1, binary ? FOPEN_BINARY_READ : "r");
5734 	if (fp == NULL)
5735 	    /* FIXME-update-dir: should include update_dir in message.  */
5736 	    error (1, errno, "cannot open file %s for comparing", use_file1);
5737 
5738         data.filename = use_file1;
5739         data.fp = fp;
5740         data.different = 0;
5741 
5742         if (RCS_checkout (rcs, NULL, rev2 ? rev2 : rev1, NULL, options,
5743                           RUN_TTY, cmp_file_buffer, &data ))
5744 		error (1, errno,
5745 		       "cannot check out revision %s of %s",
5746 		       rev2 ? rev2 : rev1, rcs->print_path);
5747 
5748         /* If we have not yet found a difference, make sure that we are at
5749            the end of the file.  */
5750         if (!data.different)
5751         {
5752 	    if (getc (fp) != EOF)
5753 		data.different = 1;
5754         }
5755 
5756         fclose (fp);
5757 	if (rev1_cache == NULL && tmpfile)
5758 	{
5759 	    if (CVS_UNLINK (tmpfile ) < 0)
5760 		error (0, errno, "cannot remove %s", tmpfile);
5761 	    free (tmpfile);
5762 	}
5763 
5764         return data.different;
5765     }
5766 }
5767 
5768 
5769 
5770 /* This is a subroutine of RCS_cmp_file.  It is passed to
5771    RCS_checkout.  */
5772 #define CMP_BUF_SIZE (8 * 1024)
5773 
5774 static void
5775 cmp_file_buffer (void *callerdat, const char *buffer, size_t len)
5776 {
5777     struct cmp_file_data *data = callerdat;
5778     char *filebuf;
5779 
5780     /* If we've already found a difference, we don't need to check
5781        further.  */
5782     if (data->different)
5783 	return;
5784 
5785     filebuf = xmalloc (len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len);
5786 
5787     while (len > 0)
5788     {
5789 	size_t checklen;
5790 
5791 	checklen = len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len;
5792 	if (fread (filebuf, 1, checklen, data->fp) != checklen)
5793 	{
5794 	    if (ferror (data->fp))
5795 		error (1, errno, "cannot read file %s for comparing",
5796 		       data->filename);
5797 	    data->different = 1;
5798 	    free (filebuf);
5799 	    return;
5800 	}
5801 
5802 	if (memcmp (filebuf, buffer, checklen) != 0)
5803 	{
5804 	    data->different = 1;
5805 	    free (filebuf);
5806 	    return;
5807 	}
5808 
5809 	buffer += checklen;
5810 	len -= checklen;
5811     }
5812 
5813     free (filebuf);
5814 }
5815 
5816 
5817 
5818 /* For RCS file RCS, make symbolic tag TAG point to revision REV.
5819    This validates that TAG is OK for a user to use.  Return value is
5820    -1 for error (and errno is set to indicate the error), positive for
5821    error (and an error message has been printed), or zero for success.  */
5822 int
5823 RCS_settag (RCSNode *rcs, const char *tag, const char *rev)
5824 {
5825     List *symbols;
5826     Node *node;
5827 
5828     if (rcs->flags & PARTIAL)
5829 	RCS_reparsercsfile (rcs, NULL, NULL);
5830 
5831     /* FIXME: This check should be moved to RCS_check_tag.  There is no
5832        reason for it to be here.  */
5833     if (STREQ (tag, TAG_BASE)
5834 	|| STREQ (tag, TAG_HEAD))
5835     {
5836 	/* Print the name of the tag might be considered redundant
5837 	   with the caller, which also prints it.  Perhaps this helps
5838 	   clarify why the tag name is considered reserved, I don't
5839 	   know.  */
5840 	error (0, 0, "Attempt to add reserved tag name %s", tag);
5841 	return 1;
5842     }
5843 
5844     /* A revision number of NULL means use the head or default branch.
5845        If rev is not NULL, it may be a symbolic tag or branch number;
5846        expand it to the correct numeric revision or branch head. */
5847     if (rev == NULL)
5848 	rev = rcs->branch ? rcs->branch : rcs->head;
5849 
5850     /* At this point rcs->symbol_data may not have been parsed.
5851        Calling RCS_symbols will force it to be parsed into a list
5852        which we can easily manipulate.  */
5853     symbols = RCS_symbols (rcs);
5854     if (symbols == NULL)
5855     {
5856 	symbols = getlist ();
5857 	rcs->symbols = symbols;
5858     }
5859     node = findnode (symbols, tag);
5860     if (node != NULL)
5861     {
5862 	free (node->data);
5863 	node->data = xstrdup (rev);
5864     }
5865     else
5866     {
5867 	node = getnode ();
5868 	node->key = xstrdup (tag);
5869 	node->data = xstrdup (rev);
5870 	(void)addnode_at_front (symbols, node);
5871     }
5872 
5873     return 0;
5874 }
5875 
5876 
5877 
5878 /* Delete the symbolic tag TAG from the RCS file RCS.  Return 0 if
5879    the tag was found (and removed), or 1 if it was not present.  (In
5880    either case, the tag will no longer be in RCS->SYMBOLS.) */
5881 int
5882 RCS_deltag (RCSNode *rcs, const char *tag)
5883 {
5884     List *symbols;
5885     Node *node;
5886     if (rcs->flags & PARTIAL)
5887 	RCS_reparsercsfile (rcs, NULL, NULL);
5888 
5889     symbols = RCS_symbols (rcs);
5890     if (symbols == NULL)
5891 	return 1;
5892 
5893     node = findnode (symbols, tag);
5894     if (node == NULL)
5895 	return 1;
5896 
5897     delnode (node);
5898 
5899     return 0;
5900 }
5901 
5902 
5903 
5904 /* Set the default branch of RCS to REV.  */
5905 int
5906 RCS_setbranch (RCSNode *rcs, const char *rev)
5907 {
5908     if (rcs->flags & PARTIAL)
5909 	RCS_reparsercsfile (rcs, NULL, NULL);
5910 
5911     if (rev && ! *rev)
5912 	rev = NULL;
5913 
5914     if (rev == NULL && rcs->branch == NULL)
5915 	return 0;
5916     if (rev != NULL && rcs->branch != NULL && STREQ (rev, rcs->branch))
5917 	return 0;
5918 
5919     if (rcs->branch != NULL)
5920 	free (rcs->branch);
5921     rcs->branch = xstrdup (rev);
5922 
5923     return 0;
5924 }
5925 
5926 
5927 
5928 /* Lock revision REV.  LOCK_QUIET is 1 to suppress output.  FIXME:
5929    Most of the callers only call us because RCS_checkin still tends to
5930    like a lock (a relic of old behavior inherited from the RCS ci
5931    program).  If we clean this up, only "cvs admin -l" will still need
5932    to call RCS_lock.  */
5933 
5934 /* FIXME-twp: if a lock owned by someone else is broken, should this
5935    send mail to the lock owner?  Prompt user?  It seems like such an
5936    obscure situation for CVS as almost not worth worrying much
5937    about. */
5938 int
5939 RCS_lock (RCSNode *rcs, const char *rev, int lock_quiet)
5940 {
5941     List *locks;
5942     Node *p;
5943     char *user;
5944     char *xrev = NULL;
5945 
5946     if (rcs->flags & PARTIAL)
5947 	RCS_reparsercsfile (rcs, NULL, NULL);
5948 
5949     locks = RCS_getlocks (rcs);
5950     if (locks == NULL)
5951 	locks = rcs->locks = getlist();
5952     user = getcaller();
5953 
5954     /* A revision number of NULL means lock the head or default branch. */
5955     if (rev == NULL)
5956 	xrev = RCS_head (rcs);
5957     else
5958 	xrev = RCS_gettag (rcs, rev, 1, NULL);
5959 
5960     /* Make sure that the desired revision exists.  Technically,
5961        we can update the locks list without even checking this,
5962        but RCS 5.7 did this.  And it can't hurt. */
5963     if (xrev == NULL || findnode (rcs->versions, xrev) == NULL)
5964     {
5965 	if (!lock_quiet)
5966 	    error (0, 0, "%s: revision %s absent", rcs->print_path, rev);
5967 	free (xrev);
5968 	return 1;
5969     }
5970 
5971     /* Is this rev already locked? */
5972     p = findnode (locks, xrev);
5973     if (p != NULL)
5974     {
5975 	if (STREQ (p->data, user))
5976 	{
5977 	    /* We already own the lock on this revision, so do nothing. */
5978 	    free (xrev);
5979 	    return 0;
5980 	}
5981 
5982 #if 0
5983 	/* Well, first of all, "rev" below should be "xrev" to avoid
5984 	   core dumps.  But more importantly, should we really be
5985 	   breaking the lock unconditionally?  What CVS 1.9 does (via
5986 	   RCS) is to prompt "Revision 1.1 is already locked by fred.
5987 	   Do you want to break the lock? [ny](n): ".  Well, we don't
5988 	   want to interact with the user (certainly not at the
5989 	   server/protocol level, and probably not in the command-line
5990 	   client), but isn't it more sensible to give an error and
5991 	   let the user run "cvs admin -u" if they want to break the
5992 	   lock?  */
5993 
5994 	/* Break the lock. */
5995 	if (!lock_quiet)
5996 	{
5997 	    cvs_output (rev, 0);
5998 	    cvs_output (" unlocked\n", 0);
5999 	}
6000 	delnode (p);
6001 #else
6002 	error (1, 0, "Revision %s is already locked by %s",
6003                xrev, (char *)p->data);
6004 #endif
6005     }
6006 
6007     /* Create a new lock. */
6008     p = getnode();
6009     p->key = xrev;	/* already xstrdupped */
6010     p->data = xstrdup (getcaller());
6011     (void)addnode_at_front (locks, p);
6012 
6013     if (!lock_quiet)
6014     {
6015 	cvs_output (xrev, 0);
6016 	cvs_output (" locked\n", 0);
6017     }
6018 
6019     return 0;
6020 }
6021 
6022 
6023 
6024 /* Unlock revision REV.  UNLOCK_QUIET is 1 to suppress output.  FIXME:
6025    Like RCS_lock, this can become a no-op if we do the checkin
6026    ourselves.
6027 
6028    If REV is not null and is locked by someone else, break their
6029    lock and notify them.  It is an open issue whether RCS_unlock
6030    queries the user about whether or not to break the lock. */
6031 int
6032 RCS_unlock (RCSNode *rcs, char *rev, int unlock_quiet)
6033 {
6034     Node *lock;
6035     List *locks;
6036     char *user;
6037     char *xrev = NULL;
6038 
6039     user = getcaller();
6040     if (rcs->flags & PARTIAL)
6041 	RCS_reparsercsfile (rcs, NULL, NULL);
6042 
6043     /* If rev is NULL, unlock the revision held by the caller; if more
6044        than one, make the user specify the revision explicitly.  This
6045        differs from RCS which unlocks the latest revision (first in
6046        rcs->locks) held by the caller. */
6047     if (rev == NULL)
6048     {
6049 	Node *p;
6050 
6051 	/* No-ops: attempts to unlock an empty tree or an unlocked file. */
6052 	if (rcs->head == NULL)
6053 	{
6054 	    if (!unlock_quiet)
6055 		cvs_outerr ("can't unlock an empty tree\n", 0);
6056 	    return 0;
6057 	}
6058 
6059 	locks = RCS_getlocks (rcs);
6060 	if (locks == NULL)
6061 	{
6062 	    if (!unlock_quiet)
6063 		cvs_outerr ("No locks are set.\n", 0);
6064 	    return 0;
6065 	}
6066 
6067 	lock = NULL;
6068 	for (p = locks->list->next; p != locks->list; p = p->next)
6069 	{
6070 	    if (STREQ (p->data, user))
6071 	    {
6072 		if (lock != NULL)
6073 		{
6074 		    if (!unlock_quiet)
6075 			error (0, 0, "\
6076 %s: multiple revisions locked by %s; please specify one", rcs->print_path, user);
6077 		    return 1;
6078 		}
6079 		lock = p;
6080 	    }
6081 	}
6082 	if (lock == NULL)
6083 	{
6084 	    if (!unlock_quiet)
6085 		error (0, 0, "No locks are set for %s.\n", user);
6086 	    return 0;	/* no lock found, ergo nothing to do */
6087 	}
6088 	xrev = xstrdup (lock->key);
6089     }
6090     else
6091     {
6092 	xrev = RCS_gettag (rcs, rev, 1, NULL);
6093 	if (xrev == NULL)
6094 	{
6095 	    error (0, 0, "%s: revision %s absent", rcs->print_path, rev);
6096 	    return 1;
6097 	}
6098     }
6099 
6100     lock = findnode (RCS_getlocks (rcs), xrev);
6101     if (lock == NULL)
6102     {
6103 	/* This revision isn't locked. */
6104 	free (xrev);
6105 	return 0;
6106     }
6107 
6108     if (! STREQ (lock->data, user))
6109     {
6110         /* If the revision is locked by someone else, notify
6111 	   them.  Note that this shouldn't ever happen if RCS_unlock
6112 	   is called with a NULL revision, since that means "whatever
6113 	   revision is currently locked by the caller." */
6114 	char *repos, *workfile;
6115 	if (!unlock_quiet)
6116 	    error (0, 0, "\
6117 %s: revision %s locked by %s; breaking lock", rcs->print_path, xrev,
6118 		   (char *)lock->data);
6119 	repos = xstrdup (rcs->path);
6120 	workfile = strrchr (repos, '/');
6121 	*workfile++ = '\0';
6122 	notify_do ('C', workfile, NULL, user, NULL, NULL, repos);
6123 	free (repos);
6124     }
6125 
6126     delnode (lock);
6127     if (!unlock_quiet)
6128     {
6129 	cvs_output (xrev, 0);
6130 	cvs_output (" unlocked\n", 0);
6131     }
6132 
6133     free (xrev);
6134     return 0;
6135 }
6136 
6137 
6138 
6139 /* Add USER to the access list of RCS.  Do nothing if already present.
6140    FIXME-twp: check syntax of USER to make sure it's a valid id. */
6141 
6142 void
6143 RCS_addaccess (RCSNode *rcs, char *user)
6144 {
6145     char *access, *a;
6146 
6147     if (rcs->flags & PARTIAL)
6148 	RCS_reparsercsfile (rcs, NULL, NULL);
6149 
6150     if (rcs->access == NULL)
6151 	rcs->access = xstrdup (user);
6152     else
6153     {
6154 	access = xstrdup (rcs->access);
6155 	for (a = strtok (access, " "); a != NULL; a = strtok (NULL, " "))
6156 	{
6157 	    if (STREQ (a, user))
6158 	    {
6159 		free (access);
6160 		return;
6161 	    }
6162 	}
6163 	free (access);
6164 	rcs->access = xrealloc (rcs->access,
6165 				strlen (rcs->access) + strlen (user) + 2);
6166 	strcat (rcs->access, " ");
6167 	strcat (rcs->access, user);
6168     }
6169 }
6170 
6171 
6172 
6173 /* Remove USER from the access list of RCS. */
6174 void
6175 RCS_delaccess (RCSNode *rcs, char *user)
6176 {
6177     char *p, *s;
6178     int ulen;
6179 
6180     if (rcs->flags & PARTIAL)
6181 	RCS_reparsercsfile (rcs, NULL, NULL);
6182 
6183     if (rcs->access == NULL)
6184 	return;
6185 
6186     if (user == NULL)
6187     {
6188         free (rcs->access);
6189         rcs->access = NULL;
6190         return;
6191     }
6192 
6193     p = rcs->access;
6194     ulen = strlen (user);
6195     while (p != NULL)
6196     {
6197 	if (strncmp (p, user, ulen) == 0 && (p[ulen] == '\0' || p[ulen] == ' '))
6198 	    break;
6199 	p = strchr (p, ' ');
6200 	if (p != NULL)
6201 	    ++p;
6202     }
6203 
6204     if (p == NULL)
6205 	return;
6206 
6207     s = p + ulen;
6208     while (*s != '\0')
6209 	*p++ = *s++;
6210     *p = '\0';
6211 }
6212 
6213 
6214 
6215 char *
6216 RCS_getaccess (RCSNode *rcs)
6217 {
6218     if (rcs->flags & PARTIAL)
6219 	RCS_reparsercsfile (rcs, NULL, NULL);
6220 
6221     return rcs->access;
6222 }
6223 
6224 
6225 
6226 /* Return a nonzero value if the revision specified by ARG is found.  */
6227 static int
6228 findtag (Node *node, void *arg)
6229 {
6230     char *rev = arg;
6231 
6232     if (STREQ (node->data, rev))
6233 	return 1;
6234     else
6235 	return 0;
6236 }
6237 
6238 
6239 
6240 /* Delete revisions between REV1 and REV2.  The changes between the two
6241    revisions must be collapsed, and the result stored in the revision
6242    immediately preceding the lower one.  Return 0 for successful completion,
6243    1 otherwise.
6244 
6245    Solution: check out the revision preceding REV1 and the revision
6246    following REV2.  Use call_diff to find aggregate diffs between
6247    these two revisions, and replace the delta text for the latter one
6248    with the new aggregate diff.  Alternatively, we could write a
6249    function that takes two change texts and combines them to produce a
6250    new change text, without checking out any revs or calling diff.  It
6251    would be hairy, but so, so cool.
6252 
6253    If INCLUSIVE is set, then TAG1 and TAG2, if non-NULL, tell us to
6254    delete that revision as well (cvs admin -o tag1:tag2).  If clear,
6255    delete up to but not including that revision (cvs admin -o tag1::tag2).
6256    This does not affect TAG1 or TAG2 being NULL; the meaning of the start
6257    point in ::tag2 and :tag2 is the same and likewise for end points.  */
6258 int
6259 RCS_delete_revs (RCSNode *rcs, char *tag1, char *tag2, int inclusive)
6260 {
6261     char *next;
6262     Node *nodep;
6263     RCSVers *revp = NULL;
6264     RCSVers *beforep;
6265     int status, found;
6266     int save_noexec;
6267 
6268     char *branchpoint = NULL;
6269     char *rev1 = NULL;
6270     char *rev2 = NULL;
6271     int rev1_inclusive = inclusive;
6272     int rev2_inclusive = inclusive;
6273     char *before = NULL;
6274     char *after = NULL;
6275     char *beforefile = NULL;
6276     char *afterfile = NULL;
6277     char *outfile = NULL;
6278 
6279     if (tag1 == NULL && tag2 == NULL)
6280 	return 0;
6281 
6282     /* Assume error status until everything is finished. */
6283     status = 1;
6284 
6285     /* Make sure both revisions exist. */
6286     if (tag1 != NULL)
6287     {
6288 	rev1 = RCS_gettag (rcs, tag1, 1, NULL);
6289 	if (rev1 == NULL || (nodep = findnode (rcs->versions, rev1)) == NULL)
6290 	{
6291 	    error (0, 0, "%s: Revision %s doesn't exist.", rcs->print_path, tag1);
6292 	    goto delrev_done;
6293 	}
6294     }
6295     if (tag2 != NULL)
6296     {
6297 	rev2 = RCS_gettag (rcs, tag2, 1, NULL);
6298 	if (rev2 == NULL || (nodep = findnode (rcs->versions, rev2)) == NULL)
6299 	{
6300 	    error (0, 0, "%s: Revision %s doesn't exist.", rcs->print_path, tag2);
6301 	    goto delrev_done;
6302 	}
6303     }
6304 
6305     /* If rev1 is on the trunk and rev2 is NULL, rev2 should be
6306        RCS->HEAD.  (*Not* RCS_head(rcs), which may return rcs->branch
6307        instead.)  We need to check this special case early, in order
6308        to make sure that rev1 and rev2 get ordered correctly. */
6309     if (rev2 == NULL && numdots (rev1) == 1)
6310     {
6311 	rev2 = xstrdup (rcs->head);
6312 	rev2_inclusive = 1;
6313     }
6314 
6315     if (rev2 == NULL)
6316 	rev2_inclusive = 1;
6317 
6318     if (rev1 != NULL && rev2 != NULL)
6319     {
6320 	/* A range consisting of a branch number means the latest revision
6321 	   on that branch. */
6322 	if (RCS_isbranch (rcs, rev1) && STREQ (rev1, rev2))
6323 	{
6324 	    char *tmp = RCS_getbranch (rcs, rev1, 0);
6325 	    free (rev1);
6326 	    free (rev2);
6327 	    rev1 = rev2 = tmp;
6328 	}
6329 	else
6330 	{
6331 	    /* Make sure REV1 and REV2 are ordered correctly (in the
6332 	       same order as the next field).  For revisions on the
6333 	       trunk, REV1 should be higher than REV2; for branches,
6334 	       REV1 should be lower.  */
6335 	    /* Shouldn't we just be giving an error in the case where
6336 	       the user specifies the revisions in the wrong order
6337 	       (that is, always swap on the trunk, never swap on a
6338 	       branch, in the non-error cases)?  It is not at all
6339 	       clear to me that users who specify -o 1.4:1.2 really
6340 	       meant to type -o 1.2:1.4, and the out of order usage
6341 	       has never been documented, either by cvs.texinfo or
6342 	       rcs(1).  */
6343 	    char *temp;
6344 	    int temp_inclusive;
6345 	    if (numdots (rev1) == 1)
6346 	    {
6347 		if (compare_revnums (rev1, rev2) <= 0)
6348 		{
6349 		    temp = rev2;
6350 		    rev2 = rev1;
6351 		    rev1 = temp;
6352 
6353 		    temp_inclusive = rev2_inclusive;
6354 		    rev2_inclusive = rev1_inclusive;
6355 		    rev1_inclusive = temp_inclusive;
6356 		}
6357 	    }
6358 	    else if (compare_revnums (rev1, rev2) > 0)
6359 	    {
6360 		temp = rev2;
6361 		rev2 = rev1;
6362 		rev1 = temp;
6363 
6364 		temp_inclusive = rev2_inclusive;
6365 		rev2_inclusive = rev1_inclusive;
6366 		rev1_inclusive = temp_inclusive;
6367 	    }
6368 	}
6369     }
6370 
6371     /* Basically the same thing; make sure that the ordering is what we
6372        need.  */
6373     if (rev1 == NULL)
6374     {
6375 	assert (rev2 != NULL);
6376 	if (numdots (rev2) == 1)
6377 	{
6378 	    /* Swap rev1 and rev2.  */
6379 	    int temp_inclusive;
6380 
6381 	    rev1 = rev2;
6382 	    rev2 = NULL;
6383 
6384 	    temp_inclusive = rev2_inclusive;
6385 	    rev2_inclusive = rev1_inclusive;
6386 	    rev1_inclusive = temp_inclusive;
6387 	}
6388     }
6389 
6390     /* Put the revision number preceding the first one to delete into
6391        BEFORE (where "preceding" means according to the next field).
6392        If the first revision to delete is the first revision on its
6393        branch (e.g. 1.3.2.1), BEFORE should be the node on the trunk
6394        at which the branch is rooted.  If the first revision to delete
6395        is the head revision of the trunk, set BEFORE to NULL.
6396 
6397        Note that because BEFORE may not be on the same branch as REV1,
6398        it is not very handy for navigating the revision tree.  It's
6399        most useful just for checking out the revision preceding REV1. */
6400     before = NULL;
6401     branchpoint = RCS_getbranchpoint (rcs, rev1 != NULL ? rev1 : rev2);
6402     if (rev1 == NULL)
6403     {
6404 	rev1 = xstrdup (branchpoint);
6405 	if (numdots (branchpoint) > 1)
6406 	{
6407 	    char *bp;
6408 	    bp = strrchr (branchpoint, '.');
6409 	    while (*--bp != '.')
6410 		;
6411 	    *bp = '\0';
6412 	    /* Note that this is exclusive, always, because the inclusive
6413 	       flag doesn't affect the meaning when rev1 == NULL.  */
6414 	    before = xstrdup (branchpoint);
6415 	    *bp = '.';
6416 	}
6417     }
6418     else if (! STREQ (rev1, branchpoint))
6419     {
6420 	/* Walk deltas from BRANCHPOINT on, looking for REV1. */
6421 	nodep = findnode (rcs->versions, branchpoint);
6422 	revp = nodep->data;
6423 	while (revp->next != NULL && ! STREQ (revp->next, rev1))
6424 	{
6425 	    revp = nodep->data;
6426 	    nodep = findnode (rcs->versions, revp->next);
6427 	}
6428 	if (revp->next == NULL)
6429 	{
6430 	    error (0, 0, "%s: Revision %s doesn't exist.", rcs->print_path, rev1);
6431 	    goto delrev_done;
6432 	}
6433 	if (rev1_inclusive)
6434 	    before = xstrdup (revp->version);
6435 	else
6436 	{
6437 	    before = rev1;
6438 	    nodep = findnode (rcs->versions, before);
6439 	    rev1 = xstrdup (((RCSVers *)nodep->data)->next);
6440 	}
6441     }
6442     else if (!rev1_inclusive)
6443     {
6444 	before = rev1;
6445 	nodep = findnode (rcs->versions, before);
6446 	rev1 = xstrdup (((RCSVers *)nodep->data)->next);
6447     }
6448     else if (numdots (branchpoint) > 1)
6449     {
6450 	/* Example: rev1 is "1.3.2.1", branchpoint is "1.3.2.1".
6451 	   Set before to "1.3".  */
6452 	char *bp;
6453 	bp = strrchr (branchpoint, '.');
6454 	while (*--bp != '.')
6455 	    ;
6456 	*bp = '\0';
6457 	before = xstrdup (branchpoint);
6458 	*bp = '.';
6459     }
6460 
6461     /* If any revision between REV1 and REV2 is locked or is a branch point,
6462        we can't delete that revision and must abort. */
6463     after = NULL;
6464     next = rev1;
6465     found = 0;
6466     while (!found && next != NULL)
6467     {
6468 	nodep = findnode (rcs->versions, next);
6469 	revp = nodep->data;
6470 
6471 	if (rev2 != NULL)
6472 	    found = STREQ (revp->version, rev2);
6473 	next = revp->next;
6474 
6475 	if ((!found && next != NULL) || rev2_inclusive || rev2 == NULL)
6476 	{
6477 	    if (findnode (RCS_getlocks (rcs), revp->version))
6478 	    {
6479 		error (0, 0, "%s: can't remove locked revision %s",
6480 		       rcs->print_path,
6481 		       revp->version);
6482 		goto delrev_done;
6483 	    }
6484 	    if (revp->branches != NULL)
6485 	    {
6486 		error (0, 0, "%s: can't remove branch point %s",
6487 		       rcs->print_path,
6488 		       revp->version);
6489 		goto delrev_done;
6490 	    }
6491 
6492 	    /* Doing this only for the :: syntax is for compatibility.
6493 	       See cvs.texinfo for somewhat more discussion.  */
6494 	    if (!inclusive
6495 		&& walklist (RCS_symbols (rcs), findtag, revp->version))
6496 	    {
6497 		/* We don't print which file this happens to on the theory
6498 		   that the caller will print the name of the file in a
6499 		   more useful fashion (fullname not rcs->path).  */
6500 		error (0, 0, "cannot remove revision %s because it has tags",
6501 		       revp->version);
6502 		goto delrev_done;
6503 	    }
6504 
6505 	    /* It's misleading to print the `deleting revision' output
6506 	       here, since we may not actually delete these revisions.
6507 	       But that's how RCS does it.  Bleah.  Someday this should be
6508 	       moved to the point where the revs are actually marked for
6509 	       deletion. -twp */
6510 	    cvs_output ("deleting revision ", 0);
6511 	    cvs_output (revp->version, 0);
6512 	    cvs_output ("\n", 1);
6513 	}
6514     }
6515 
6516     if (rev2 == NULL)
6517 	;
6518     else if (found)
6519     {
6520 	if (rev2_inclusive)
6521 	    after = xstrdup (next);
6522 	else
6523 	    after = xstrdup (revp->version);
6524     }
6525     else if (!inclusive)
6526     {
6527 	/* In the case of an empty range, for example 1.2::1.2 or
6528 	   1.2::1.3, we want to just do nothing.  */
6529 	status = 0;
6530 	goto delrev_done;
6531     }
6532     else
6533     {
6534 	/* This looks fishy in the cases where tag1 == NULL or tag2 == NULL.
6535 	   Are those cases really impossible?  */
6536 	assert (tag1 != NULL);
6537 	assert (tag2 != NULL);
6538 
6539 	error (0, 0, "%s: invalid revision range %s:%s", rcs->print_path,
6540 	       tag1, tag2);
6541 	goto delrev_done;
6542     }
6543 
6544     if (after == NULL && before == NULL)
6545     {
6546 	/* The user is trying to delete all revisions.  While an
6547 	   RCS file without revisions makes sense to RCS (e.g. the
6548 	   state after "rcs -i"), CVS has never been able to cope with
6549 	   it.  So at least for now we just make this an error.
6550 
6551 	   We don't include rcs->path in the message since "cvs admin"
6552 	   already printed "RCS file:" and the name.  */
6553 	error (1, 0, "attempt to delete all revisions");
6554     }
6555 
6556     /* The conditionals at this point get really hairy.  Here is the
6557        general idea:
6558 
6559        IF before != NULL and after == NULL
6560          THEN don't check out any revisions, just delete them
6561        IF before == NULL and after != NULL
6562          THEN only check out after's revision, and use it for the new deltatext
6563        ELSE
6564          check out both revisions and diff -n them.  This could use
6565 	 RCS_exec_rcsdiff with some changes, like being able
6566 	 to suppress diagnostic messages and to direct output. */
6567 
6568     if (after != NULL)
6569     {
6570 	char *diffbuf;
6571 	size_t bufsize, len;
6572 
6573 #if defined (WOE32) && !defined (__CYGWIN32__)
6574 	/* FIXME: This is an awful kludge, but at least until I have
6575 	   time to work on it a little more and test it, I'd rather
6576 	   give a fatal error than corrupt the file.  I think that we
6577 	   need to use "-kb" and "--binary" and "rb" to get_file
6578 	   (probably can do it always, not just for binary files, if
6579 	   we are consistent between the RCS_checkout and the diff).  */
6580 	{
6581 	    char *expand = RCS_getexpand (rcs);
6582 	    if (expand != NULL && STREQ (expand, "b"))
6583 		error (1, 0,
6584 		   "admin -o not implemented yet for binary on this system");
6585 	}
6586 #endif /* WOE32 */
6587 
6588 	afterfile = cvs_temp_name();
6589 	status = RCS_checkout (rcs, NULL, after, NULL, "-ko", afterfile,
6590 			       NULL, NULL);
6591 	if (status > 0)
6592 	    goto delrev_done;
6593 
6594 	if (before == NULL)
6595 	{
6596 	    /* We are deleting revisions from the head of the tree,
6597 	       so must create a new head. */
6598 	    diffbuf = NULL;
6599 	    bufsize = 0;
6600 	    get_file (afterfile, afterfile, "r", &diffbuf, &bufsize, &len);
6601 
6602 	    save_noexec = noexec;
6603 	    noexec = 0;
6604 	    if (unlink_file (afterfile) < 0)
6605 		error (0, errno, "cannot remove %s", afterfile);
6606 	    noexec = save_noexec;
6607 
6608 	    free (afterfile);
6609 	    afterfile = NULL;
6610 
6611 	    free (rcs->head);
6612 	    rcs->head = xstrdup (after);
6613 	}
6614 	else
6615 	{
6616 	    int dargc = 0;
6617 	    size_t darg_allocated = 0;
6618 	    char **dargv = NULL;
6619 
6620 	    beforefile = cvs_temp_name();
6621 	    status = RCS_checkout (rcs, NULL, before, NULL, "-ko", beforefile,
6622 				   NULL, NULL);
6623 	    if (status > 0)
6624 		goto delrev_done;
6625 
6626 	    outfile = cvs_temp_name();
6627 	    run_add_arg_p (&dargc, &darg_allocated, &dargv, "-a");
6628 	    run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n");
6629 	    status = diff_exec (beforefile, afterfile, NULL, NULL,
6630 				dargc, dargv, outfile);
6631 	    run_arg_free_p (dargc, dargv);
6632 	    free (dargv);
6633 
6634 	    if (status == 2)
6635 	    {
6636 		/* Not sure we need this message; will diff_exec already
6637 		   have printed an error?  */
6638 		error (0, 0, "%s: could not diff", rcs->print_path);
6639 		status = 1;
6640 		goto delrev_done;
6641 	    }
6642 
6643 	    diffbuf = NULL;
6644 	    bufsize = 0;
6645 	    get_file (outfile, outfile, "r", &diffbuf, &bufsize, &len);
6646 	}
6647 
6648 	/* Save the new change text in after's delta node. */
6649 	nodep = findnode (rcs->versions, after);
6650 	revp = nodep->data;
6651 
6652 	assert (revp->text == NULL);
6653 
6654 	revp->text = xmalloc (sizeof (Deltatext));
6655 	memset (revp->text, 0, sizeof (Deltatext));
6656 	revp->text->version = xstrdup (revp->version);
6657 	revp->text->text = diffbuf;
6658 	revp->text->len = len;
6659 
6660 	/* If DIFFBUF is NULL, it means that OUTFILE is empty and that
6661 	   there are no differences between the two revisions.  In that
6662 	   case, we want to force RCS_copydeltas to write an empty string
6663 	   for the new change text (leaving the text field set NULL
6664 	   means "preserve the original change text for this delta," so
6665 	   we don't want that). */
6666 	if (revp->text->text == NULL)
6667 	    revp->text->text = xstrdup ("");
6668     }
6669 
6670     /* Walk through the revisions (again) to mark each one as
6671        outdated.  (FIXME: would it be safe to use the `dead' field for
6672        this?  Doubtful.) */
6673     for (next = rev1;
6674 	 next != NULL && (after == NULL || ! STREQ (next, after));
6675 	 next = revp->next)
6676     {
6677 	nodep = findnode (rcs->versions, next);
6678 	revp = nodep->data;
6679 	revp->outdated = 1;
6680     }
6681 
6682     /* Update delta links.  If BEFORE == NULL, we're changing the
6683        head of the tree and don't need to update any `next' links. */
6684     if (before != NULL)
6685     {
6686 	/* If REV1 is the first node on its branch, then BEFORE is its
6687 	   root node (on the trunk) and we have to update its branches
6688 	   list.  Otherwise, BEFORE is on the same branch as AFTER, and
6689 	   we can just change BEFORE's `next' field to point to AFTER.
6690 	   (This should be safe: since findnode manages its lists via
6691 	   the `hashnext' and `hashprev' fields, rather than `next' and
6692 	   `prev', mucking with `next' and `prev' should not corrupt the
6693 	   delta tree's internal structure.  Much. -twp) */
6694 
6695 	if (rev1 == NULL)
6696 	    /* beforep's ->next field already should be equal to after,
6697 	       which I think is always NULL in this case.  */
6698 	    ;
6699 	else if (STREQ (rev1, branchpoint))
6700 	{
6701 	    nodep = findnode (rcs->versions, before);
6702 	    revp = nodep->data;
6703 	    nodep = revp->branches->list->next;
6704 	    while (nodep != revp->branches->list &&
6705 		   ! STREQ (nodep->key, rev1))
6706 		nodep = nodep->next;
6707 	    assert (nodep != revp->branches->list);
6708 	    if (after == NULL)
6709 		delnode (nodep);
6710 	    else
6711 	    {
6712 		free (nodep->key);
6713 		nodep->key = xstrdup (after);
6714 	    }
6715 	}
6716 	else
6717 	{
6718 	    nodep = findnode (rcs->versions, before);
6719 	    beforep = nodep->data;
6720 	    free (beforep->next);
6721 	    beforep->next = xstrdup (after);
6722 	}
6723     }
6724 
6725     status = 0;
6726 
6727  delrev_done:
6728     if (rev1 != NULL)
6729 	free (rev1);
6730     if (rev2 && rev2 != rev1)
6731 	free (rev2);
6732     if (branchpoint != NULL)
6733 	free (branchpoint);
6734     if (before != NULL)
6735 	free (before);
6736     if (after != NULL)
6737 	free (after);
6738 
6739     save_noexec = noexec;
6740     noexec = 0;
6741     if (beforefile != NULL)
6742     {
6743 	if (unlink_file (beforefile) < 0)
6744 	    error (0, errno, "cannot remove %s", beforefile);
6745 	free (beforefile);
6746     }
6747     if (afterfile != NULL)
6748     {
6749 	if (unlink_file (afterfile) < 0)
6750 	    error (0, errno, "cannot remove %s", afterfile);
6751 	free (afterfile);
6752     }
6753     if (outfile != NULL)
6754     {
6755 	if (unlink_file (outfile) < 0)
6756 	    error (0, errno, "cannot remove %s", outfile);
6757 	free (outfile);
6758     }
6759     noexec = save_noexec;
6760 
6761     return status;
6762 }
6763 
6764 
6765 
6766 /*
6767  * TRUE if there exists a symbolic tag "tag" in file.
6768  */
6769 int
6770 RCS_exist_tag (RCSNode *rcs, char *tag)
6771 {
6772 
6773     assert (rcs != NULL);
6774 
6775     if (findnode (RCS_symbols (rcs), tag))
6776     return 1;
6777     return 0;
6778 
6779 }
6780 
6781 
6782 
6783 /*
6784  * TRUE if RCS revision number "rev" exists.
6785  * This includes magic branch revisions, not found in rcs->versions,
6786  * but only in rcs->symbols, requiring a list walk to find them.
6787  * Take advantage of list walk callback function already used by
6788  * RCS_delete_revs, above.
6789  */
6790 int
6791 RCS_exist_rev (RCSNode *rcs, char *rev)
6792 {
6793 
6794     assert (rcs != NULL);
6795 
6796     if (rcs->flags & PARTIAL)
6797 	RCS_reparsercsfile (rcs, NULL, NULL);
6798 
6799     if (findnode(rcs->versions, rev) != 0)
6800 	return 1;
6801 
6802     if (walklist (RCS_symbols(rcs), findtag, rev) != 0)
6803 	return 1;
6804 
6805     return 0;
6806 
6807 }
6808 
6809 
6810 
6811 
6812 /* RCS_deltas and friends.  Processing of the deltas in RCS files.  */
6813 struct line
6814 {
6815     /* Text of this line.  Part of the same malloc'd block as the struct
6816        line itself (we probably should use the "struct hack" (char text[1])
6817        and save ourselves sizeof (char *) bytes).  Does not include \n;
6818        instead has_newline indicates the presence or absence of \n.  */
6819     char *text;
6820     /* Length of this line, not counting \n if has_newline is true.  */
6821     size_t len;
6822     /* Version in which it was introduced.  */
6823     RCSVers *vers;
6824     /* Nonzero if this line ends with \n.  This will always be true
6825        except possibly for the last line.  */
6826     int has_newline;
6827     /* Number of pointers to this struct line.  */
6828     int refcount;
6829 };
6830 
6831 struct linevector
6832 {
6833     /* How many lines in use for this linevector?  */
6834     unsigned int nlines;
6835     /* How many lines allocated for this linevector?  */
6836     unsigned int lines_alloced;
6837     /* Pointer to array containing a pointer to each line.  */
6838     struct line **vector;
6839 };
6840 
6841 
6842 
6843 /* Initialize *VEC to be a linevector with no lines.  */
6844 static void
6845 linevector_init (struct linevector *vec)
6846 {
6847     vec->lines_alloced = 0;
6848     vec->nlines = 0;
6849     vec->vector = NULL;
6850 }
6851 
6852 
6853 
6854 /* Given some text TEXT, add each of its lines to VEC before line POS
6855    (where line 0 is the first line).  The last line in TEXT may or may
6856    not be \n terminated.
6857    Set the version for each of the new lines to VERS.  This
6858    function returns non-zero for success.  It returns zero if the line
6859    number is out of range.
6860 
6861    Each of the lines in TEXT are copied to space which is managed with
6862    the linevector (and freed by linevector_free).  So the caller doesn't
6863    need to keep TEXT around after the call to this function.  */
6864 static int
6865 linevector_add (struct linevector *vec, const char *text, size_t len,
6866 		RCSVers *vers, unsigned int pos)
6867 {
6868     const char *textend;
6869     unsigned int i;
6870     unsigned int nnew;
6871     const char *p;
6872     const char *nextline_text;
6873     size_t nextline_len;
6874     int nextline_newline;
6875     struct line *q;
6876 
6877     if (len == 0)
6878 	return 1;
6879 
6880     textend = text + len;
6881 
6882     /* Count the number of lines we will need to add.  */
6883     nnew = 1;
6884     for (p = text; p < textend; ++p)
6885 	if (*p == '\n' && p + 1 < textend)
6886 	    ++nnew;
6887 
6888     /* Expand VEC->VECTOR if needed.  */
6889     if (vec->nlines + nnew >= vec->lines_alloced)
6890     {
6891 	if (vec->lines_alloced == 0)
6892 	    vec->lines_alloced = 10;
6893 	while (vec->nlines + nnew >= vec->lines_alloced)
6894 	    vec->lines_alloced *= 2;
6895 	vec->vector = xnrealloc (vec->vector,
6896 				 vec->lines_alloced, sizeof (*vec->vector));
6897     }
6898 
6899     /* Make room for the new lines in VEC->VECTOR.  */
6900     for (i = vec->nlines + nnew - 1; i >= pos + nnew; --i)
6901 	vec->vector[i] = vec->vector[i - nnew];
6902 
6903     if (pos > vec->nlines)
6904 	return 0;
6905 
6906     /* Actually add the lines, to VEC->VECTOR.  */
6907     i = pos;
6908     nextline_text = text;
6909     nextline_newline = 0;
6910     for (p = text; p < textend; ++p)
6911 	if (*p == '\n')
6912 	{
6913 	    nextline_newline = 1;
6914 	    if (p + 1 == textend)
6915 		/* If there are no characters beyond the last newline, we
6916 		   don't consider it another line.  */
6917 		break;
6918 	    nextline_len = p - nextline_text;
6919 	    q = xmalloc (sizeof (struct line) + nextline_len);
6920 	    q->vers = vers;
6921 	    q->text = (char *)q + sizeof (struct line);
6922 	    q->len = nextline_len;
6923 	    q->has_newline = nextline_newline;
6924 	    q->refcount = 1;
6925 	    memcpy (q->text, nextline_text, nextline_len);
6926 	    vec->vector[i++] = q;
6927 
6928 	    nextline_text = (char *)p + 1;
6929 	    nextline_newline = 0;
6930 	}
6931     nextline_len = p - nextline_text;
6932     q = xmalloc (sizeof (struct line) + nextline_len);
6933     q->vers = vers;
6934     q->text = (char *)q + sizeof (struct line);
6935     q->len = nextline_len;
6936     q->has_newline = nextline_newline;
6937     q->refcount = 1;
6938     memcpy (q->text, nextline_text, nextline_len);
6939     vec->vector[i] = q;
6940 
6941     vec->nlines += nnew;
6942 
6943     return 1;
6944 }
6945 
6946 
6947 
6948 /* Remove NLINES lines from VEC at position POS (where line 0 is the
6949    first line).  */
6950 static void
6951 linevector_delete (struct linevector *vec, unsigned int pos,
6952 		   unsigned int nlines)
6953 {
6954     unsigned int i;
6955     unsigned int last;
6956 
6957     last = vec->nlines - nlines;
6958     for (i = pos; i < pos + nlines; ++i)
6959     {
6960 	if (--vec->vector[i]->refcount == 0)
6961 	    free (vec->vector[i]);
6962     }
6963     for (i = pos; i < last; ++i)
6964 	vec->vector[i] = vec->vector[i + nlines];
6965     vec->nlines -= nlines;
6966 }
6967 
6968 
6969 
6970 /* Copy FROM to TO, copying the vectors but not the lines pointed to.  */
6971 static void
6972 linevector_copy (struct linevector *to, struct linevector *from)
6973 {
6974     unsigned int ln;
6975 
6976     for (ln = 0; ln < to->nlines; ++ln)
6977     {
6978 	if (--to->vector[ln]->refcount == 0)
6979 	    free (to->vector[ln]);
6980     }
6981     if (from->nlines > to->lines_alloced)
6982     {
6983 	if (to->lines_alloced == 0)
6984 	    to->lines_alloced = 10;
6985 	while (from->nlines > to->lines_alloced)
6986 	    to->lines_alloced *= 2;
6987 	to->vector = xnrealloc (to->vector,
6988 				to->lines_alloced,
6989 				sizeof (*to->vector));
6990     }
6991     memcpy (to->vector, from->vector,
6992 	    /* XXX: wrong int cast to avoid gcc warning */
6993 	    xtimes ((int)from->nlines, sizeof (*to->vector)));
6994     to->nlines = from->nlines;
6995     for (ln = 0; ln < to->nlines; ++ln)
6996 	++to->vector[ln]->refcount;
6997 }
6998 
6999 
7000 
7001 /* Free storage associated with linevector.  */
7002 static void
7003 linevector_free (struct linevector *vec)
7004 {
7005     unsigned int ln;
7006 
7007     if (vec->vector != NULL)
7008     {
7009 	for (ln = 0; ln < vec->nlines; ++ln)
7010 	    if (--vec->vector[ln]->refcount == 0)
7011 		free (vec->vector[ln]);
7012 
7013 	free (vec->vector);
7014     }
7015 }
7016 
7017 
7018 
7019 /* Given a textual string giving the month (1-12), terminated with any
7020    character not recognized by atoi, return the 3 character name to
7021    print it with.  I do not think it is a good idea to change these
7022    strings based on the locale; they are standard abbreviations (for
7023    example in rfc822 mail messages) which should be widely understood.
7024    Returns a pointer into static readonly storage.  */
7025 static const char *
7026 month_printname (const char *month)
7027 {
7028     static const char *const months[] =
7029       {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
7030 	 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
7031     int mnum;
7032 
7033     mnum = atoi (month);
7034     if (mnum < 1 || mnum > 12)
7035 	return "???";
7036     return months[mnum - 1];
7037 }
7038 
7039 
7040 
7041 /* Apply changes to the line vector LINES.  DIFFBUF is a buffer of
7042    length DIFFLEN holding the change text from an RCS file (the output
7043    of diff -n).  NAME is used in error messages.  The VERS field of
7044    any line added is set to ADDVERS.  The VERS field of any line
7045    deleted is set to DELVERS, unless DELVERS is NULL, in which case
7046    the VERS field of deleted lines is unchanged.  The function returns
7047    non-zero if the change text is applied successfully.  It returns
7048    zero if the change text does not appear to apply to LINES (e.g., a
7049    line number is invalid).  If the change text is improperly
7050    formatted (e.g., it is not the output of diff -n), the function
7051    calls error with a status of 1, causing the program to exit.  */
7052 static int
7053 apply_rcs_changes (struct linevector *lines, const char *diffbuf,
7054 		   size_t difflen, const char *name, RCSVers *addvers,
7055 		   RCSVers *delvers)
7056 {
7057     const char *p;
7058     const char *q;
7059     int op;
7060     /* The RCS format throws us for a loop in that the deltafrags (if
7061        we define a deltafrag as an add or a delete) need to be applied
7062        in reverse order.  So we stick them into a linked list.  */
7063     struct deltafrag {
7064 	enum {FRAG_ADD, FRAG_DELETE} type;
7065 	unsigned long pos;
7066 	unsigned long nlines;
7067 	const char *new_lines;
7068 	size_t len;
7069 	struct deltafrag *next;
7070     };
7071     struct deltafrag *dfhead;
7072     struct deltafrag *df;
7073     int err;
7074 
7075     dfhead = NULL;
7076     for (p = diffbuf; p != NULL && p < diffbuf + difflen; )
7077     {
7078 	op = *p++;
7079 	if (op != 'a' && op != 'd')
7080 	    /* Can't just skip over the deltafrag, because the value
7081 	       of op determines the syntax.  */
7082 	    error (1, 0, "unrecognized operation '\\x%x' in %s",
7083 		   op, name);
7084 	df = xmalloc (sizeof (struct deltafrag));
7085 	df->next = dfhead;
7086 	dfhead = df;
7087 	df->pos = strtoul (p, (char **) &q, 10);
7088 
7089 	if (p == q)
7090 	    error (1, 0, "number expected in %s", name);
7091 	p = q;
7092 	if (*p++ != ' ')
7093 	    error (1, 0, "space expected in %s", name);
7094 	df->nlines = strtoul (p, (char **) &q, 10);
7095 	if (p == q)
7096 	    error (1, 0, "number expected in %s", name);
7097 	p = q;
7098 	if (*p++ != '\012')
7099 	    error (1, 0, "linefeed expected in %s", name);
7100 
7101 	if (op == 'a')
7102 	{
7103 	    unsigned int i;
7104 
7105 	    df->type = FRAG_ADD;
7106 	    i = df->nlines;
7107 	    /* The text we want is the number of lines specified, or
7108 	       until the end of the value, whichever comes first (it
7109 	       will be the former except in the case where we are
7110 	       adding a line which does not end in newline).  */
7111 	    for (q = p; i != 0; ++q)
7112 		if (*q == '\n')
7113 		    --i;
7114 		else if (q == diffbuf + difflen)
7115 		{
7116 		    if (i != 1)
7117 			error (1, 0, "premature end of change in %s", name);
7118 		    else
7119 			break;
7120 		}
7121 
7122 	    /* Stash away a pointer to the text we are adding.  */
7123 	    df->new_lines = p;
7124 	    df->len = q - p;
7125 
7126 	    p = q;
7127 	}
7128 	else
7129 	{
7130 	    /* Correct for the fact that line numbers in RCS files
7131 	       start with 1.  */
7132 	    --df->pos;
7133 
7134 	    assert (op == 'd');
7135 	    df->type = FRAG_DELETE;
7136 	}
7137     }
7138 
7139     err = 0;
7140     for (df = dfhead; df != NULL;)
7141     {
7142 	unsigned int ln;
7143 
7144 	/* Once an error is encountered, just free the rest of the list and
7145 	 * return.
7146 	 */
7147 	if (!err)
7148 	    switch (df->type)
7149 	    {
7150 	    case FRAG_ADD:
7151 		if (! linevector_add (lines, df->new_lines, df->len, addvers,
7152 				      df->pos))
7153 		    err = 1;
7154 		break;
7155 	    case FRAG_DELETE:
7156 		if (df->pos > lines->nlines
7157 		    || df->pos + df->nlines > lines->nlines)
7158 		    return 0;
7159 		if (delvers != NULL)
7160 		    for (ln = df->pos; ln < df->pos + df->nlines; ++ln)
7161 			lines->vector[ln]->vers = delvers;
7162 		linevector_delete (lines, df->pos, df->nlines);
7163 		break;
7164 	    }
7165 
7166 	df = df->next;
7167 	free (dfhead);
7168 	dfhead = df;
7169     }
7170 
7171     return !err;
7172 }
7173 
7174 
7175 
7176 /* Apply an RCS change text to a buffer.  The function name starts
7177    with rcs rather than RCS because this does not take an RCSNode
7178    argument.  NAME is used in error messages.  TEXTBUF is the text
7179    buffer to change, and TEXTLEN is the size.  DIFFBUF and DIFFLEN are
7180    the change buffer and size.  The new buffer is returned in *RETBUF
7181    and *RETLEN.  The new buffer is allocated by xmalloc.
7182 
7183    Return 1 for success.  On failure, call error and return 0.  */
7184 int
7185 rcs_change_text (const char *name, char *textbuf, size_t textlen,
7186 		 const char *diffbuf, size_t difflen, char **retbuf,
7187 		 size_t *retlen)
7188 {
7189     struct linevector lines;
7190     int ret;
7191 
7192     *retbuf = NULL;
7193     *retlen = 0;
7194 
7195     linevector_init (&lines);
7196 
7197     if (! linevector_add (&lines, textbuf, textlen, NULL, 0))
7198 	error (1, 0, "cannot initialize line vector");
7199 
7200     if (! apply_rcs_changes (&lines, diffbuf, difflen, name, NULL, NULL))
7201     {
7202 	error (0, 0, "invalid change text in %s", name);
7203 	ret = 0;
7204     }
7205     else
7206     {
7207 	char *p;
7208 	size_t n;
7209 	unsigned int ln;
7210 
7211 	n = 0;
7212 	for (ln = 0; ln < lines.nlines; ++ln)
7213 	    /* 1 for \n */
7214 	    n += lines.vector[ln]->len + 1;
7215 
7216 	p = xmalloc (n);
7217 	*retbuf = p;
7218 
7219 	for (ln = 0; ln < lines.nlines; ++ln)
7220 	{
7221 	    memcpy (p, lines.vector[ln]->text, lines.vector[ln]->len);
7222 	    p += lines.vector[ln]->len;
7223 	    if (lines.vector[ln]->has_newline)
7224 		*p++ = '\n';
7225 	}
7226 
7227 	*retlen = p - *retbuf;
7228 	assert (*retlen <= n);
7229 
7230 	ret = 1;
7231     }
7232 
7233     linevector_free (&lines);
7234 
7235     return ret;
7236 }
7237 
7238 
7239 
7240 /* Walk the deltas in RCS to get to revision VERSION.
7241 
7242    If OP is RCS_ANNOTATE, then write annotations using cvs_output.
7243 
7244    If OP is RCS_FETCH, then put the contents of VERSION into a
7245    newly-malloc'd array and put a pointer to it in *TEXT.  Each line
7246    is \n terminated; the caller is responsible for converting text
7247    files if desired.  The total length is put in *LEN.
7248 
7249    If FP is non-NULL, it should be a file descriptor open to the file
7250    RCS with file position pointing to the deltas.  We close the file
7251    when we are done.
7252 
7253    If LOG is non-NULL, then *LOG is set to the log message of VERSION,
7254    and *LOGLEN is set to the length of the log message.
7255 
7256    On error, give a fatal error.  */
7257 void
7258 RCS_deltas (RCSNode *rcs, FILE *fp, struct rcsbuffer *rcsbuf,
7259             const char *version, enum rcs_delta_op op, char **text,
7260             size_t *len, char **log, size_t *loglen)
7261 {
7262     struct rcsbuffer rcsbuf_local;
7263     char *branchversion;
7264     char *cpversion;
7265     char *key;
7266     char *value;
7267     size_t vallen;
7268     RCSVers *vers;
7269     RCSVers *prev_vers;
7270     RCSVers *trunk_vers;
7271     char *next;
7272     int ishead, isnext, isversion, onbranch;
7273     Node *node;
7274     struct linevector headlines;
7275     struct linevector curlines;
7276     struct linevector trunklines;
7277     int foundhead;
7278 
7279     assert (version);
7280 
7281     if (fp == NULL)
7282     {
7283 	rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf_local);
7284 	rcsbuf = &rcsbuf_local;
7285     }
7286 
7287    if (log) *log = NULL;
7288 
7289     ishead = 1;
7290     vers = NULL;
7291     prev_vers = NULL;
7292     trunk_vers = NULL;
7293     next = NULL;
7294     onbranch = 0;
7295     foundhead = 0;
7296 
7297     linevector_init (&curlines);
7298     linevector_init (&headlines);
7299     linevector_init (&trunklines);
7300 
7301     /* We set BRANCHVERSION to the version we are currently looking
7302        for.  Initially, this is the version on the trunk from which
7303        VERSION branches off.  If VERSION is not a branch, then
7304        BRANCHVERSION is just VERSION.  */
7305     branchversion = xstrdup (version);
7306     cpversion = strchr (branchversion, '.');
7307     if (cpversion != NULL)
7308         cpversion = strchr (cpversion + 1, '.');
7309     if (cpversion != NULL)
7310         *cpversion = '\0';
7311 
7312     do {
7313 	if (! rcsbuf_getrevnum (rcsbuf, &key))
7314 	    error (1, 0, "unexpected EOF reading RCS file %s", rcs->print_path);
7315 
7316 	if (next != NULL && ! STREQ (next, key))
7317 	{
7318 	    /* This is not the next version we need.  It is a branch
7319                version which we want to ignore.  */
7320 	    isnext = 0;
7321 	    isversion = 0;
7322 	}
7323 	else
7324 	{
7325 	    isnext = 1;
7326 
7327 	    /* look up the revision */
7328 	    node = findnode (rcs->versions, key);
7329 	    if (node == NULL)
7330 	        error (1, 0,
7331 		       "mismatch in rcs file %s between deltas and deltatexts (%s)",
7332 		       rcs->print_path, key);
7333 
7334 	    /* Stash the previous version.  */
7335 	    prev_vers = vers;
7336 
7337 	    vers = node->data;
7338 	    next = vers->next;
7339 
7340 	    /* Compare key and trunkversion now, because key points to
7341 	       storage controlled by rcsbuf_getkey.  */
7342 	    if (STREQ (branchversion, key))
7343 	        isversion = 1;
7344 	    else
7345 	        isversion = 0;
7346 	}
7347 
7348 	while (1)
7349 	{
7350 	    if (! rcsbuf_getkey (rcsbuf, &key, &value))
7351 		error (1, 0, "%s does not appear to be a valid rcs file",
7352 		       rcs->print_path);
7353 
7354 	    if (log != NULL
7355 		&& isversion
7356 		&& STREQ (key, "log")
7357 		&& STREQ (branchversion, version))
7358 	    {
7359 		if (*log != NULL)
7360 		{
7361 		    error (0, 0, "Duplicate `log' keyword in RCS file (`%s').",
7362 		           rcs->print_path);
7363 		    free (*log);
7364 		}
7365 		*log = rcsbuf_valcopy (rcsbuf, value, 0, loglen);
7366 	    }
7367 
7368 	    if (STREQ (key, "text"))
7369 	    {
7370 		rcsbuf_valpolish (rcsbuf, value, 0, &vallen);
7371 		if (ishead)
7372 		{
7373 		    if (! linevector_add (&curlines, value, vallen, NULL, 0))
7374 			error (1, 0, "invalid rcs file %s", rcs->print_path);
7375 
7376 		    ishead = 0;
7377 		}
7378 		else if (isnext)
7379 		{
7380 		    if (! apply_rcs_changes (&curlines, value, vallen,
7381 					     rcs->path,
7382 					     onbranch ? vers : NULL,
7383 					     onbranch ? NULL : prev_vers))
7384 			error (1, 0, "invalid change text in %s", rcs->print_path);
7385 		}
7386 		break;
7387 	    }
7388 	}
7389 
7390 	if (isversion)
7391 	{
7392 	    /* This is either the version we want, or it is the
7393                branchpoint to the version we want.  */
7394 	    if (STREQ (branchversion, version))
7395 	    {
7396 	        /* This is the version we want.  */
7397 		linevector_copy (&headlines, &curlines);
7398 		foundhead = 1;
7399 		if (onbranch)
7400 		{
7401 		    /* We have found this version by tracking up a
7402                        branch.  Restore back to the lines we saved
7403                        when we left the trunk, and continue tracking
7404                        down the trunk.  */
7405 		    onbranch = 0;
7406 		    vers = trunk_vers;
7407 		    next = vers->next;
7408 		    linevector_copy (&curlines, &trunklines);
7409 		}
7410 	    }
7411 	    else
7412 	    {
7413 	        Node *p;
7414 
7415 	        /* We need to look up the branch.  */
7416 	        onbranch = 1;
7417 
7418 		if (numdots (branchversion) < 2)
7419 		{
7420 		    unsigned int ln;
7421 
7422 		    /* We are leaving the trunk; save the current
7423                        lines so that we can restore them when we
7424                        continue tracking down the trunk.  */
7425 		    trunk_vers = vers;
7426 		    linevector_copy (&trunklines, &curlines);
7427 
7428 		    /* Reset the version information we have
7429                        accumulated so far.  It only applies to the
7430                        changes from the head to this version.  */
7431 		    for (ln = 0; ln < curlines.nlines; ++ln)
7432 		        curlines.vector[ln]->vers = NULL;
7433 		}
7434 
7435 		/* The next version we want is the entry on
7436                    VERS->branches which matches this branch.  For
7437                    example, suppose VERSION is 1.21.4.3 and
7438                    BRANCHVERSION was 1.21.  Then we look for an entry
7439                    starting with "1.21.4" and we'll put it (probably
7440                    1.21.4.1) in NEXT.  We'll advance BRANCHVERSION by
7441                    two dots (in this example, to 1.21.4.3).  */
7442 
7443 		if (vers->branches == NULL)
7444 		    error (1, 0, "missing expected branches in %s",
7445 			   rcs->print_path);
7446 		if (!cpversion)
7447 		    error (1, 0, "Invalid revision number in `%s'.",
7448 		           rcs->print_path);
7449 		*cpversion = '.';
7450 		++cpversion;
7451 		cpversion = strchr (cpversion, '.');
7452 		if (cpversion == NULL)
7453 		    error (1, 0, "version number confusion in %s",
7454 			   rcs->print_path);
7455 		for (p = vers->branches->list->next;
7456 		     p != vers->branches->list;
7457 		     p = p->next)
7458 		    if (strncmp (p->key, branchversion,
7459 				 cpversion - branchversion) == 0)
7460 			break;
7461 		if (p == vers->branches->list)
7462 		    error (1, 0, "missing expected branch in %s",
7463 			   rcs->print_path);
7464 
7465 		next = p->key;
7466 
7467 		cpversion = strchr (cpversion + 1, '.');
7468 		if (cpversion != NULL)
7469 		    *cpversion = '\0';
7470 	    }
7471 	}
7472 	if (op == RCS_FETCH && foundhead)
7473 	    break;
7474     } while (next != NULL);
7475 
7476     free (branchversion);
7477 
7478     rcsbuf_cache (rcs, rcsbuf);
7479 
7480     if (! foundhead)
7481         error (1, 0, "could not find desired version %s in %s",
7482 	       version, rcs->print_path);
7483 
7484     /* Now print out or return the data we have just computed.  */
7485     switch (op)
7486     {
7487 	case RCS_ANNOTATE:
7488 	    {
7489 		unsigned int ln;
7490 
7491 		for (ln = 0; ln < headlines.nlines; ++ln)
7492 		{
7493 		    char *buf;
7494 		    /* Period which separates year from month in date.  */
7495 		    char *ym;
7496 		    /* Period which separates month from day in date.  */
7497 		    char *md;
7498 		    RCSVers *prvers;
7499 
7500 		    prvers = headlines.vector[ln]->vers;
7501 		    if (prvers == NULL)
7502 			prvers = vers;
7503 
7504 		    buf = xmalloc (strlen (prvers->version) + 24);
7505 		    sprintf (buf, "%-12s (%-8.8s ",
7506 			     prvers->version,
7507 			     prvers->author);
7508 		    cvs_output (buf, 0);
7509 		    free (buf);
7510 
7511 		    /* Now output the date.  */
7512 		    ym = strchr (prvers->date, '.');
7513 		    if (ym == NULL)
7514 		    {
7515 			cvs_output ("??", 0);
7516 			cvs_output ("-???", 0);
7517 			cvs_output ("-??", 0);
7518 		    }
7519 		    else
7520 		    {
7521 			md = strchr (ym + 1, '.');
7522 			if (md == NULL)
7523 			    cvs_output ("??", 0);
7524 			else
7525 			    cvs_output (md + 1, 2);
7526 
7527 			cvs_output ("-", 1);
7528 			cvs_output (month_printname (ym + 1), 0);
7529 			cvs_output ("-", 1);
7530 			/* Only output the last two digits of the year.  Our output
7531 			   lines are long enough as it is without printing the
7532 			   century.  */
7533 			cvs_output (ym - 2, 2);
7534 		    }
7535 		    cvs_output ("): ", 0);
7536 		    if (headlines.vector[ln]->len != 0)
7537 			cvs_output (headlines.vector[ln]->text,
7538 				    headlines.vector[ln]->len);
7539 		    cvs_output ("\n", 1);
7540 		}
7541 	    }
7542 	    break;
7543 	case RCS_FETCH:
7544 	    {
7545 		char *p;
7546 		size_t n;
7547 		unsigned int ln;
7548 
7549 		assert (text != NULL);
7550 		assert (len != NULL);
7551 
7552 		n = 0;
7553 		for (ln = 0; ln < headlines.nlines; ++ln)
7554 		    /* 1 for \n */
7555 		    n += headlines.vector[ln]->len + 1;
7556 		p = xmalloc (n);
7557 		*text = p;
7558 		for (ln = 0; ln < headlines.nlines; ++ln)
7559 		{
7560 		    memcpy (p, headlines.vector[ln]->text,
7561 			    headlines.vector[ln]->len);
7562 		    p += headlines.vector[ln]->len;
7563 		    if (headlines.vector[ln]->has_newline)
7564 			*p++ = '\n';
7565 		}
7566 		*len = p - *text;
7567 		assert (*len <= n);
7568 	    }
7569 	    break;
7570     }
7571 
7572     linevector_free (&curlines);
7573     linevector_free (&headlines);
7574     linevector_free (&trunklines);
7575 
7576     return;
7577 }
7578 
7579 
7580 
7581 /* Read the information for a single delta from the RCS buffer RCSBUF,
7582    whose name is RCSFILE.  *KEYP and *VALP are either NULL, or the
7583    first key/value pair to read, as set by rcsbuf_getkey. Return NULL
7584    if there are no more deltas.  Store the key/value pair which
7585    terminated the read in *KEYP and *VALP.  */
7586 static RCSVers *
7587 getdelta (struct rcsbuffer *rcsbuf, char *rcsfile, char **keyp, char **valp)
7588 {
7589     RCSVers *vnode;
7590     char *key, *value, *cp;
7591     Node *kv;
7592 
7593     /* Get revision number if it wasn't passed in. This uses
7594        rcsbuf_getkey because it doesn't croak when encountering
7595        unexpected input.  As a result, we have to play unholy games
7596        with `key' and `value'. */
7597     if (*keyp != NULL)
7598     {
7599 	key = *keyp;
7600 	value = *valp;
7601     }
7602     else
7603     {
7604 	if (! rcsbuf_getkey (rcsbuf, &key, &value))
7605 	    error (1, 0, "%s: unexpected EOF", rcsfile);
7606     }
7607 
7608     /* Make sure that it is a revision number and not a cabbage
7609        or something. */
7610     for (cp = key;
7611 	 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
7612 	 cp++)
7613 	/* do nothing */ ;
7614     /* Note that when comparing with RCSDATE, we are not massaging
7615        VALUE from the string found in the RCS file.  This is OK since
7616        we know exactly what to expect.  */
7617     if (*cp != '\0' || strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) != 0)
7618     {
7619 	*keyp = key;
7620 	*valp = value;
7621 	return NULL;
7622     }
7623 
7624     vnode = xmalloc (sizeof (RCSVers));
7625     memset (vnode, 0, sizeof (RCSVers));
7626 
7627     vnode->version = xstrdup (key);
7628 
7629     /* Grab the value of the date from value.  Note that we are not
7630        massaging VALUE from the string found in the RCS file.  */
7631     cp = value + (sizeof RCSDATE) - 1;	/* skip the "date" keyword */
7632     while (whitespace (*cp))		/* take space off front of value */
7633 	cp++;
7634 
7635     vnode->date = xstrdup (cp);
7636 
7637     /* Get author field.  */
7638     if (! rcsbuf_getkey (rcsbuf, &key, &value))
7639     {
7640 	error (1, 0, "unexpected end of file reading %s", rcsfile);
7641     }
7642     if (! STREQ (key, "author"))
7643 	error (1, 0, "\
7644 unable to parse %s; `author' not in the expected place", rcsfile);
7645     vnode->author = rcsbuf_valcopy (rcsbuf, value, 0, NULL);
7646 
7647     /* Get state field.  */
7648     if (! rcsbuf_getkey (rcsbuf, &key, &value))
7649     {
7650 	error (1, 0, "unexpected end of file reading %s", rcsfile);
7651     }
7652     if (! STREQ (key, "state"))
7653 	error (1, 0, "\
7654 unable to parse %s; `state' not in the expected place", rcsfile);
7655     vnode->state = rcsbuf_valcopy (rcsbuf, value, 0, NULL);
7656     /* The value is optional, according to rcsfile(5).  */
7657     if (value != NULL && STREQ (value, RCSDEAD))
7658     {
7659 	vnode->dead = 1;
7660     }
7661 
7662     /* Note that "branches" and "next" are in fact mandatory, according
7663        to doc/RCSFILES.  */
7664 
7665     /* fill in the branch list (if any branches exist) */
7666     if (! rcsbuf_getkey (rcsbuf, &key, &value))
7667     {
7668 	error (1, 0, "unexpected end of file reading %s", rcsfile);
7669     }
7670     if (STREQ (key, RCSDESC))
7671     {
7672 	*keyp = key;
7673 	*valp = value;
7674 	/* Probably could/should be a fatal error.  */
7675 	error (0, 0, "warning: 'branches' keyword missing from %s", rcsfile);
7676 	return vnode;
7677     }
7678     if (value != NULL)
7679     {
7680 	vnode->branches = getlist ();
7681 	/* Note that we are not massaging VALUE from the string found
7682            in the RCS file.  */
7683 	do_branches (vnode->branches, value);
7684     }
7685 
7686     /* fill in the next field if there is a next revision */
7687     if (! rcsbuf_getkey (rcsbuf, &key, &value))
7688     {
7689 	error (1, 0, "unexpected end of file reading %s", rcsfile);
7690     }
7691     if (STREQ (key, RCSDESC))
7692     {
7693 	*keyp = key;
7694 	*valp = value;
7695 	/* Probably could/should be a fatal error.  */
7696 	error (0, 0, "warning: 'next' keyword missing from %s", rcsfile);
7697 	return vnode;
7698     }
7699     if (value != NULL)
7700 	vnode->next = rcsbuf_valcopy (rcsbuf, value, 0, NULL);
7701 
7702     /*
7703      * XXX - this is where we put the symbolic link stuff???
7704      * (into newphrases in the deltas).
7705      */
7706     while (1)
7707     {
7708 	if (! rcsbuf_getkey (rcsbuf, &key, &value))
7709 	    error (1, 0, "unexpected end of file reading %s", rcsfile);
7710 
7711 	/* The `desc' keyword is the end of the deltas. */
7712 	if (strcmp (key, RCSDESC) == 0)
7713 	    break;
7714 
7715 #ifdef PRESERVE_PERMISSIONS_SUPPORT
7716 
7717 	/* The `hardlinks' value is a group of words, which must
7718 	   be parsed separately and added as a list to vnode->hardlinks. */
7719 	if (strcmp (key, "hardlinks") == 0)
7720 	{
7721 	    char *word;
7722 
7723 	    vnode->hardlinks = getlist();
7724 	    while ((word = rcsbuf_valword (rcsbuf, &value)) != NULL)
7725 	    {
7726 		Node *n = getnode();
7727 		n->key = word;
7728 		addnode (vnode->hardlinks, n);
7729 	    }
7730 	    continue;
7731 	}
7732 #endif
7733 
7734 	/* Enable use of repositories created by certain obsolete
7735 	   versions of CVS.  This code should remain indefinately;
7736 	   there is no procedure for converting old repositories, and
7737 	   checking for it is harmless.  */
7738 	if (STREQ (key, RCSDEAD))
7739 	{
7740 	    vnode->dead = 1;
7741 	    if (vnode->state != NULL)
7742 		free (vnode->state);
7743 	    vnode->state = xstrdup (RCSDEAD);
7744 	    continue;
7745 	}
7746 	/* if we have a new revision number, we're done with this delta */
7747 	for (cp = key;
7748 	     (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
7749 	     cp++)
7750 	    /* do nothing */ ;
7751 	/* Note that when comparing with RCSDATE, we are not massaging
7752 	   VALUE from the string found in the RCS file.  This is OK
7753 	   since we know exactly what to expect.  */
7754 	if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0)
7755 	    break;
7756 
7757 	/* At this point, key and value represent a user-defined field
7758 	   in the delta node. */
7759 	if (vnode->other_delta == NULL)
7760 	    vnode->other_delta = getlist ();
7761 	kv = getnode ();
7762 	kv->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
7763 	kv->key = xstrdup (key);
7764 	kv->data = rcsbuf_valcopy (rcsbuf, value, kv->type == RCSFIELD, NULL);
7765 	if (addnode (vnode->other_delta, kv) != 0)
7766 	{
7767 	    /* Complaining about duplicate keys in newphrases seems
7768 	       questionable, in that we don't know what they mean and
7769 	       doc/RCSFILES has no prohibition on several newphrases
7770 	       with the same key.  But we can't store more than one as
7771 	       long as we store them in a List *.  */
7772 	    error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
7773 		   key, rcsfile);
7774 	    freenode (kv);
7775 	}
7776     }
7777 
7778     /* Return the key which caused us to fail back to the caller.  */
7779     *keyp = key;
7780     *valp = value;
7781 
7782     return vnode;
7783 }
7784 
7785 
7786 
7787 static void
7788 freedeltatext (Deltatext *d)
7789 {
7790     if (d->version != NULL)
7791 	free (d->version);
7792     if (d->log != NULL)
7793 	free (d->log);
7794     if (d->text != NULL)
7795 	free (d->text);
7796     if (d->other != NULL)
7797 	dellist (&d->other);
7798     free (d);
7799 }
7800 
7801 static Deltatext *
7802 RCS_getdeltatext (RCSNode *rcs, FILE *fp, struct rcsbuffer *rcsbuf)
7803 {
7804     char *num;
7805     char *key, *value;
7806     Node *p;
7807     Deltatext *d;
7808 
7809     /* Get the revision number. */
7810     if (! rcsbuf_getrevnum (rcsbuf, &num))
7811     {
7812 	/* If num == NULL, it means we reached EOF naturally.  That's
7813 	   fine. */
7814 	if (num == NULL)
7815 	    return NULL;
7816 	else
7817 	    error (1, 0, "%s: unexpected EOF", rcs->print_path);
7818     }
7819 
7820     p = findnode (rcs->versions, num);
7821     if (p == NULL)
7822 	error (1, 0, "mismatch in rcs file %s between deltas and deltatexts (%s)",
7823 	       rcs->print_path, num);
7824 
7825     d = xmalloc (sizeof (Deltatext));
7826     d->version = xstrdup (num);
7827 
7828     /* Get the log message. */
7829     if (! rcsbuf_getkey (rcsbuf, &key, &value))
7830 	error (1, 0, "%s, delta %s: unexpected EOF", rcs->print_path, num);
7831     if (! STREQ (key, "log"))
7832 	error (1, 0, "%s, delta %s: expected `log', got `%s'",
7833 	       rcs->print_path, num, key);
7834     d->log = rcsbuf_valcopy (rcsbuf, value, 0, NULL);
7835 
7836     /* Get random newphrases. */
7837     d->other = getlist();
7838     while (1)
7839     {
7840 	if (! rcsbuf_getkey (rcsbuf, &key, &value))
7841 	    error (1, 0, "%s, delta %s: unexpected EOF", rcs->print_path, num);
7842 
7843 	if (STREQ (key, "text"))
7844 	    break;
7845 
7846 	p = getnode();
7847 	p->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
7848 	p->key = xstrdup (key);
7849 	p->data = rcsbuf_valcopy (rcsbuf, value, p->type == RCSFIELD, NULL);
7850 	if (addnode (d->other, p) < 0)
7851 	{
7852 	    error (0, 0, "warning: %s, delta %s: duplicate field `%s'",
7853 		   rcs->print_path, num, key);
7854 	}
7855     }
7856 
7857     /* Get the change text. We already know that this key is `text'. */
7858     d->text = rcsbuf_valcopy (rcsbuf, value, 0, &d->len);
7859 
7860     return d;
7861 }
7862 
7863 
7864 
7865 /* RCS output functions, for writing RCS format files from RCSNode
7866    structures.
7867 
7868    For most of this work, RCS 5.7 uses an `aprintf' function which aborts
7869    program upon error.  Instead, these functions check the output status
7870    of the stream right before closing it, and aborts if an error condition
7871    is found.  The RCS solution is probably the better one: it produces
7872    more overhead, but will produce a clearer diagnostic in the case of
7873    catastrophic error.  In either case, however, the repository will probably
7874    not get corrupted. */
7875 static int
7876 putsymbol_proc (Node *symnode, void *fparg)
7877 {
7878     FILE *fp = fparg;
7879 
7880     /* A fiddly optimization: this code used to just call fprintf, but
7881        in an old repository with hundreds of tags this can get called
7882        hundreds of thousands of times when doing a cvs tag.  Since
7883        tagging is a relatively common operation, and using putc and
7884        fputs is just as comprehensible, the change is worthwhile.  */
7885     putc ('\n', fp);
7886     putc ('\t', fp);
7887     fputs (symnode->key, fp);
7888     putc (':', fp);
7889     fputs (symnode->data, fp);
7890     return 0;
7891 }
7892 
7893 
7894 
7895 /* putlock_proc is like putsymbol_proc, but key and data are reversed. */
7896 static int
7897 putlock_proc (Node *symnode, void *fp)
7898 {
7899     return fprintf (fp, "\n\t%s:%s", (char *)symnode->data, symnode->key);
7900 }
7901 
7902 
7903 
7904 static int
7905 putrcsfield_proc (Node *node, void *vfp)
7906 {
7907     FILE *fp = vfp;
7908 
7909     /* Some magic keys used internally by CVS start with `;'. Skip them. */
7910     if (node->key[0] == ';')
7911 	return 0;
7912 
7913     fprintf (fp, "\n%s\t", node->key);
7914     if (node->data != NULL)
7915     {
7916 	/* If the field's value contains evil characters,
7917 	   it must be stringified. */
7918 	/* FIXME: This does not quite get it right.  "7jk8f" is not a valid
7919 	   value for a value in a newpharse, according to doc/RCSFILES,
7920 	   because digits are not valid in an "id".  We might do OK by
7921 	   always writing strings (enclosed in @@).  Would be nice to
7922 	   explicitly mention this one way or another in doc/RCSFILES.
7923 	   A case where we are wrong in a much more clear-cut way is that
7924 	   we let through non-graphic characters such as whitespace and
7925 	   control characters.  */
7926 
7927 	if (node->type == RCSCMPFLD || strpbrk (node->data, "$,.:;@") == NULL)
7928 	    fputs (node->data, fp);
7929 	else
7930 	{
7931 	    putc ('@', fp);
7932 	    expand_at_signs (node->data, (off_t) strlen (node->data), fp);
7933 	    putc ('@', fp);
7934 	}
7935     }
7936 
7937     /* desc, log and text fields should not be terminated with semicolon;
7938        all other fields should be. */
7939     if (! STREQ (node->key, "desc") &&
7940 	! STREQ (node->key, "log") &&
7941 	! STREQ (node->key, "text"))
7942     {
7943 	putc (';', fp);
7944     }
7945     return 0;
7946 }
7947 
7948 
7949 
7950 #ifdef PRESERVE_PERMISSIONS_SUPPORT
7951 
7952 /* Save a filename in a `hardlinks' RCS field.  NODE->KEY will contain
7953    a full pathname, but currently only basenames are stored in the RCS
7954    node.  Assume that the filename includes nasty characters and
7955    @-escape it. */
7956 
7957 static int
7958 puthardlink_proc (node, vfp)
7959     Node *node;
7960     void *vfp;
7961 {
7962     FILE *fp = vfp;
7963     char *basename = strrchr (node->key, '/');
7964 
7965     if (basename == NULL)
7966 	basename = node->key;
7967     else
7968 	++basename;
7969 
7970     putc ('\t', fp);
7971     putc ('@', fp);
7972     (void) expand_at_signs (basename, strlen (basename), fp);
7973     putc ('@', fp);
7974 
7975     return 0;
7976 }
7977 
7978 #endif /* PRESERVE_PERMISSIONS_SUPPORT */
7979 
7980 
7981 
7982 /* Output the admin node for RCS into stream FP. */
7983 static void
7984 RCS_putadmin (RCSNode *rcs, FILE *fp)
7985 {
7986     fprintf (fp, "%s\t%s;\n", RCSHEAD, rcs->head ? rcs->head : "");
7987     if (rcs->branch)
7988 	fprintf (fp, "%s\t%s;\n", RCSBRANCH, rcs->branch);
7989 
7990     fputs ("access", fp);
7991     if (rcs->access)
7992     {
7993 	char *p, *s;
7994 	s = xstrdup (rcs->access);
7995 	for (p = strtok (s, " \n\t"); p != NULL; p = strtok (NULL, " \n\t"))
7996 	    fprintf (fp, "\n\t%s", p);
7997 	free (s);
7998     }
7999     fputs (";\n", fp);
8000 
8001     fputs (RCSSYMBOLS, fp);
8002     /* If we haven't had to convert the symbols to a list yet, don't
8003        force a conversion now; just write out the string.  */
8004     if (rcs->symbols == NULL && rcs->symbols_data != NULL)
8005     {
8006 	fputs ("\n\t", fp);
8007 	fputs (rcs->symbols_data, fp);
8008     }
8009     else
8010 	walklist (RCS_symbols (rcs), putsymbol_proc, fp);
8011     fputs (";\n", fp);
8012 
8013     fputs ("locks", fp);
8014     if (rcs->locks_data)
8015 	fprintf (fp, "\t%s", rcs->locks_data);
8016     else if (rcs->locks)
8017 	walklist (rcs->locks, putlock_proc, fp);
8018     if (rcs->strict_locks)
8019 	fprintf (fp, "; strict");
8020     fputs (";\n", fp);
8021 
8022     if (rcs->comment)
8023     {
8024 	fprintf (fp, "comment\t@");
8025 	expand_at_signs (rcs->comment, (off_t) strlen (rcs->comment), fp);
8026 	fputs ("@;\n", fp);
8027     }
8028     if (rcs->expand && ! STREQ (rcs->expand, "kv"))
8029 	fprintf (fp, "%s\t@%s@;\n", RCSEXPAND, rcs->expand);
8030 
8031     walklist (rcs->other, putrcsfield_proc, fp);
8032 
8033     putc ('\n', fp);
8034 }
8035 
8036 
8037 
8038 static void
8039 putdelta (RCSVers *vers, FILE *fp)
8040 {
8041     Node *bp, *start;
8042 
8043     /* Skip if no revision was supplied, or if it is outdated (cvs admin -o) */
8044     if (vers == NULL || vers->outdated)
8045 	return;
8046 
8047     fprintf (fp, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches",
8048 	     vers->version,
8049 	     RCSDATE, vers->date,
8050 	     "author", vers->author,
8051 	     "state", vers->state ? vers->state : "");
8052 
8053     if (vers->branches != NULL)
8054     {
8055 	start = vers->branches->list;
8056 	for (bp = start->next; bp != start; bp = bp->next)
8057 	    fprintf (fp, "\n\t%s", bp->key);
8058     }
8059 
8060     fprintf (fp, ";\nnext\t%s;", vers->next ? vers->next : "");
8061 
8062     walklist (vers->other_delta, putrcsfield_proc, fp);
8063 
8064 #ifdef PRESERVE_PERMISSIONS_SUPPORT
8065     if (vers->hardlinks)
8066     {
8067 	fprintf (fp, "\nhardlinks");
8068 	walklist (vers->hardlinks, puthardlink_proc, fp);
8069 	putc (';', fp);
8070     }
8071 #endif
8072     putc ('\n', fp);
8073 }
8074 
8075 
8076 
8077 static void
8078 RCS_putdtree (RCSNode *rcs, char *rev, FILE *fp)
8079 {
8080     RCSVers *versp;
8081     Node *p, *branch;
8082 
8083     /* Previously, this function used a recursive implementation, but
8084        if the trunk has a huge number of revisions and the program
8085        stack is not big, a stack overflow could occur, so this
8086        nonrecursive version was developed to be more safe. */
8087     Node *branchlist, *onebranch;
8088     List *branches;
8089     List *onebranchlist;
8090 
8091     if (rev == NULL)
8092 	return;
8093 
8094     branches = getlist();
8095 
8096     for (; rev != NULL;)
8097     {
8098 	/* Find the delta node for this revision. */
8099 	p = findnode (rcs->versions, rev);
8100 	if (p == NULL)
8101 	{
8102 	    error (1, 0,
8103 		   "error parsing repository file %s, file may be corrupt.",
8104 		   rcs->path);
8105 	}
8106 
8107 	versp = p->data;
8108 
8109 	/* Print the delta node and go for its `next' node.  This
8110 	   prints the trunk. If there are any branches printed on this
8111 	   revision, mark we have some. */
8112 	putdelta (versp, fp);
8113 	/* Store branch information into branch list so to write its
8114 	   trunk afterwards */
8115 	if (versp->branches != NULL)
8116 	{
8117 	    branch = getnode();
8118 	    branch->data = versp->branches;
8119 
8120 	    addnode(branches, branch);
8121 	}
8122 
8123 	rev = versp->next;
8124     }
8125 
8126     /* If there are any branches printed on this revision,
8127        print those trunks as well. */
8128     branchlist = branches->list;
8129     for (branch = branchlist->next;
8130 	 branch != branchlist;
8131 	 branch = branch->next)
8132     {
8133 	onebranchlist = (List *)(branch->data);
8134 	onebranch = onebranchlist->list;
8135 	for (p = onebranch->next; p != onebranch; p = p->next)
8136 	    RCS_putdtree (rcs, p->key, fp);
8137 
8138 	branch->data = NULL; /* so to prevent its freeing on dellist */
8139     }
8140 
8141     dellist(&branches);
8142 }
8143 
8144 
8145 
8146 static void
8147 RCS_putdesc (RCSNode *rcs, FILE *fp)
8148 {
8149     fprintf (fp, "\n\n%s\n@", RCSDESC);
8150     if (rcs->desc != NULL)
8151     {
8152 	off_t len = (off_t) strlen (rcs->desc);
8153 	if (len > 0)
8154 	{
8155 	    expand_at_signs (rcs->desc, len, fp);
8156 	    if (rcs->desc[len-1] != '\n')
8157 		putc ('\n', fp);
8158 	}
8159     }
8160     fputs ("@\n", fp);
8161 }
8162 
8163 
8164 
8165 static void
8166 putdeltatext (FILE *fp, Deltatext *d)
8167 {
8168     fprintf (fp, "\n\n%s\nlog\n@", d->version);
8169     if (d->log != NULL)
8170     {
8171 	int loglen = strlen (d->log);
8172 	expand_at_signs (d->log, (off_t) loglen, fp);
8173 	if (d->log[loglen-1] != '\n')
8174 	    putc ('\n', fp);
8175     }
8176     putc ('@', fp);
8177 
8178     walklist (d->other, putrcsfield_proc, fp);
8179 
8180     fputs ("\ntext\n@", fp);
8181     if (d->text != NULL)
8182 	expand_at_signs (d->text, (off_t) d->len, fp);
8183     fputs ("@\n", fp);
8184 }
8185 
8186 
8187 
8188 /* TODO: the whole mechanism for updating deltas is kludgey... more
8189    sensible would be to supply all the necessary info in a `newdeltatext'
8190    field for RCSVers nodes. -twp */
8191 
8192 /* Copy delta text nodes from FIN to FOUT.  If NEWDTEXT is non-NULL, it
8193    is a new delta text node, and should be added to the tree at the
8194    node whose revision number is INSERTPT.  (Note that trunk nodes are
8195    written in decreasing order, and branch nodes are written in
8196    increasing order.) */
8197 static void
8198 RCS_copydeltas (RCSNode *rcs, FILE *fin, struct rcsbuffer *rcsbufin,
8199 		FILE *fout, Deltatext *newdtext, char *insertpt)
8200 {
8201     int actions;
8202     RCSVers *dadmin;
8203     Node *np;
8204     int insertbefore, found;
8205     char *bufrest;
8206     int nls;
8207     size_t buflen;
8208 #ifndef HAVE_MMAP
8209     char buf[8192];
8210     int got;
8211 #endif
8212 
8213     /* Count the number of versions for which we have to do some
8214        special operation.  */
8215     actions = walklist (rcs->versions, count_delta_actions, NULL);
8216 
8217     /* Make a note of whether NEWDTEXT should be inserted
8218        before or after its INSERTPT. */
8219     insertbefore = (newdtext != NULL && numdots (newdtext->version) == 1);
8220 
8221     while (actions != 0 || newdtext != NULL)
8222     {
8223 	Deltatext *dtext;
8224 
8225 	dtext = RCS_getdeltatext (rcs, fin, rcsbufin);
8226 
8227 	/* We shouldn't hit EOF here, because that would imply that
8228            some action was not taken, or that we could not insert
8229            NEWDTEXT.  */
8230 	if (dtext == NULL)
8231 	    error (1, 0, "internal error: EOF too early in RCS_copydeltas");
8232 
8233 	found = (insertpt != NULL && STREQ (dtext->version, insertpt));
8234 	if (found && insertbefore)
8235 	{
8236 	    putdeltatext (fout, newdtext);
8237 	    newdtext = NULL;
8238 	    insertpt = NULL;
8239 	}
8240 
8241 	np = findnode (rcs->versions, dtext->version);
8242 	dadmin = np->data;
8243 
8244 	/* If this revision has been outdated, just skip it. */
8245 	if (dadmin->outdated)
8246 	{
8247 	    freedeltatext (dtext);
8248 	    --actions;
8249 	    continue;
8250 	}
8251 
8252 	/* Update the change text for this delta.  New change text
8253 	   data may come from cvs admin -m, cvs admin -o, or cvs ci. */
8254 	if (dadmin->text != NULL)
8255 	{
8256 	    if (dadmin->text->log != NULL || dadmin->text->text != NULL)
8257 		--actions;
8258 	    if (dadmin->text->log != NULL)
8259 	    {
8260 		free (dtext->log);
8261 		dtext->log = dadmin->text->log;
8262 		dadmin->text->log = NULL;
8263 	    }
8264 	    if (dadmin->text->text != NULL)
8265 	    {
8266 		free (dtext->text);
8267 		dtext->text = dadmin->text->text;
8268 		dtext->len = dadmin->text->len;
8269 		dadmin->text->text = NULL;
8270 	    }
8271 	}
8272 	putdeltatext (fout, dtext);
8273 	freedeltatext (dtext);
8274 
8275 	if (found && !insertbefore)
8276 	{
8277 	    putdeltatext (fout, newdtext);
8278 	    newdtext = NULL;
8279 	    insertpt = NULL;
8280 	}
8281     }
8282 
8283     /* Copy the rest of the file directly, without bothering to
8284        interpret it.  The caller will handle error checking by calling
8285        ferror.
8286 
8287        We just wrote a newline to the file, either in putdeltatext or
8288        in the caller.  However, we may not have read the corresponding
8289        newline from the file, because rcsbuf_getkey returns as soon as
8290        it finds the end of the '@' string for the desc or text key.
8291        Therefore, we may read three newlines when we should really
8292        only write two, and we check for that case here.  This is not
8293        an semantically important issue; we only do it to make our RCS
8294        files look traditional.  */
8295 
8296     nls = 3;
8297 
8298     rcsbuf_get_buffered (rcsbufin, &bufrest, &buflen);
8299     if (buflen > 0)
8300     {
8301 	if (bufrest[0] != '\n'
8302 	    || strncmp (bufrest, "\n\n\n", buflen < 3 ? buflen : 3) != 0)
8303 	{
8304 	    nls = 0;
8305 	}
8306 	else
8307 	{
8308 	    if (buflen < 3)
8309 		nls -= buflen;
8310 	    else
8311 	    {
8312 		++bufrest;
8313 		--buflen;
8314 		nls = 0;
8315 	    }
8316 	}
8317 
8318 	fwrite (bufrest, 1, buflen, fout);
8319     }
8320 #ifndef HAVE_MMAP
8321     /* This bit isn't necessary when using mmap since the entire file
8322      * will already be available via the RCS buffer.  Besides, the
8323      * mmap code doesn't always keep the file pointer up to date, so
8324      * this adds some data twice.
8325      */
8326     while ((got = fread (buf, 1, sizeof buf, fin)) != 0)
8327     {
8328 	if (nls > 0
8329 	    && got >= nls
8330 	    && buf[0] == '\n'
8331 	    && strncmp (buf, "\n\n\n", nls) == 0)
8332 	{
8333 	    fwrite (buf + 1, 1, got - 1, fout);
8334 	}
8335 	else
8336 	{
8337 	    fwrite (buf, 1, got, fout);
8338 	}
8339 
8340 	nls = 0;
8341     }
8342 #endif /* HAVE_MMAP */
8343 }
8344 
8345 
8346 
8347 /* A helper procedure for RCS_copydeltas.  This is called via walklist
8348    to count the number of RCS revisions for which some special action
8349    is required.  */
8350 static int
8351 count_delta_actions (Node *np, void *ignore)
8352 {
8353     RCSVers *dadmin = np->data;
8354 
8355     if (dadmin->outdated)
8356 	return 1;
8357 
8358     if (dadmin->text != NULL
8359 	&& (dadmin->text->log != NULL || dadmin->text->text != NULL))
8360     {
8361 	return 1;
8362     }
8363 
8364     return 0;
8365 }
8366 
8367 
8368 
8369 /*
8370  * Clean up temporary files.
8371  *
8372  * NOTES
8373  *   This function needs to be reentrant since a call to exit() can cause a
8374  *   call to this function, which can then be interrupted by a signal, which
8375  *   can cause a second call to this function.
8376  *
8377  * RETURNS
8378  *   Nothing.
8379  */
8380 static void
8381 rcs_cleanup (void)
8382 {
8383     static int reenter = 0;
8384 
8385     if (reenter++)
8386 	_exit(1);
8387 
8388     TRACE (TRACE_FUNCTION, "rcs_cleanup()");
8389 
8390     /* FIXME: Do not perform buffered I/O from an interrupt handler like
8391      * this (via error).  However, I'm leaving the error-calling code there
8392      * in the hope that on the rare occasion the error call is actually made
8393      * (e.g., a fluky I/O error or permissions problem prevents the deletion
8394      * of a just-created file) reentrancy won't be an issue.
8395      */
8396 
8397     /* We don't want to be interrupted during calls which set globals to NULL,
8398      * but we know that by the time we reach this function, interrupts have
8399      * already been blocked.
8400      */
8401     if (rcs_lockfile != NULL)
8402     {
8403 	/* Use a tmp var since any of these functions could call exit, causing
8404 	 * us to be called a second time.
8405 	 */
8406 	char *tmp = rcs_lockfile;
8407 	rcs_lockfile = NULL;
8408 	if (rcs_lockfd >= 0)
8409 	{
8410 	    if (close (rcs_lockfd) != 0)
8411 		error (0, errno, "error closing lock file %s", tmp);
8412 	    rcs_lockfd = -1;
8413 	}
8414 
8415 	/* Note that the checks for existence_error are because we can be
8416 	 * called from a signal handler, so we don't know whether the
8417 	 * files got created.
8418 	 */
8419 	if (unlink_file (tmp) < 0
8420 	    && !existence_error (errno))
8421 	    error (0, errno, "cannot remove %s", tmp);
8422     }
8423 }
8424 
8425 
8426 
8427 /* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style
8428    locking on the specified RCSFILE: for a file called `foo,v', open
8429    for writing a file called `,foo,'.
8430 
8431    Note that we what do here is quite different from what RCS does.
8432    RCS creates the ,foo, file before it reads the RCS file (if it
8433    knows that it will be writing later), so that it actually serves as
8434    a lock.  We don't; instead we rely on CVS writelocks.  This means
8435    that if someone is running RCS on the file at the same time they
8436    are running CVS on it, they might lose (we read the file,
8437    then RCS writes it, then we write it, clobbering the
8438    changes made by RCS).  I believe the current sentiment about this
8439    is "well, don't do that".
8440 
8441    A concern has been expressed about whether adopting the RCS
8442    strategy would slow us down.  I don't think so, since we need to
8443    write the ,foo, file anyway (unless perhaps if O_EXCL is slower or
8444    something).
8445 
8446    These do not perform quite the same function as the RCS -l option
8447    for locking files: they are intended to prevent competing RCS
8448    processes from stomping all over each other's laundry.  Hence,
8449    they are `internal' locking functions.
8450 
8451    If there is an error, give a fatal error; if we return we always
8452    return a non-NULL value.  */
8453 static FILE *
8454 rcs_internal_lockfile (char *rcsfile)
8455 {
8456     struct stat rstat;
8457     FILE *fp;
8458     static int first_call = 1;
8459 
8460     if (first_call)
8461     {
8462 	first_call = 0;
8463 	/* Clean up if we get a signal or exit.  */
8464 	cleanup_register (rcs_cleanup);
8465     }
8466 
8467     /* Get the lock file name: `,file,' for RCS file `file,v'. */
8468     assert (rcs_lockfile == NULL);
8469     assert (rcs_lockfd < 0);
8470     rcs_lockfile = rcs_lockfilename (rcsfile);
8471 
8472     /* Use the existing RCS file mode, or read-only if this is a new
8473        file.  (Really, this is a lie -- if this is a new file,
8474        RCS_checkin uses the permissions from the working copy.  For
8475        actually creating the file, we use 0444 as a safe default mode.) */
8476     if (stat (rcsfile, &rstat) < 0)
8477     {
8478 	if (existence_error (errno))
8479 	    rstat.st_mode = S_IRUSR | S_IRGRP | S_IROTH;
8480 	else
8481 	    error (1, errno, "cannot stat %s", rcsfile);
8482     }
8483 
8484     /* Try to open exclusively.  POSIX.1 guarantees that O_EXCL|O_CREAT
8485        guarantees an exclusive open.  According to the RCS source, with
8486        NFS v2 we must also throw in O_TRUNC and use an open mask that makes
8487        the file unwriteable.  For extensive justification, see the comments for
8488        rcswriteopen() in rcsedit.c, in RCS 5.7.  This is kind of pointless
8489        in the CVS case; see comment at the start of this file concerning
8490        general ,foo, file strategy.
8491 
8492        There is some sentiment that with NFSv3 and such, that one can
8493        rely on O_EXCL these days.  This might be true for unix (I
8494        don't really know), but I am still pretty skeptical in the case
8495        of the non-unix systems.  */
8496     rcs_lockfd = open (rcs_lockfile,
8497 		       OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
8498 		       S_IRUSR | S_IRGRP | S_IROTH);
8499 
8500     if (rcs_lockfd < 0)
8501     {
8502 	error (1, errno, "could not open lock file `%s'", rcs_lockfile);
8503     }
8504 
8505     /* Force the file permissions, and return a stream object. */
8506     /* Because we change the modes later, we don't worry about
8507        this in the non-HAVE_FCHMOD case.  */
8508 #ifdef HAVE_FCHMOD
8509     if (fchmod (rcs_lockfd, rstat.st_mode) < 0)
8510 	error (1, errno, "cannot change mode for %s", rcs_lockfile);
8511 #endif
8512     fp = fdopen (rcs_lockfd, FOPEN_BINARY_WRITE);
8513     if (fp == NULL)
8514 	error (1, errno, "cannot fdopen %s", rcs_lockfile);
8515 
8516     return fp;
8517 }
8518 
8519 
8520 
8521 static void
8522 rcs_internal_unlockfile (FILE *fp, char *rcsfile)
8523 {
8524     assert (rcs_lockfile != NULL);
8525     assert (rcs_lockfd >= 0);
8526 
8527     /* Abort if we could not write everything successfully to LOCKFILE.
8528        This is not a great error-handling mechanism, but should prevent
8529        corrupting the repository. */
8530 
8531     if (ferror (fp))
8532 	/* Using errno here may well be misleanding since the most recent
8533 	   call that set errno may not have anything whatsoever to do with
8534 	   the error that set the flag, but it's better than nothing.  The
8535 	   real solution is to check each call to fprintf rather than waiting
8536 	   until the end like this.  */
8537 	error (1, errno, "error writing to lock file %s", rcs_lockfile);
8538 
8539     /* Flush and sync the file, or the user may be told the commit completed,
8540      * while a server crash/power failure could still cause the data to be
8541      * lost.
8542      *
8543      * Invoking rename(",<file>," , "<file>,v") on Linux and almost all UNIXs
8544      * only flushes the inode for the target file to disk, it does not
8545      * guarantee flush of the kernel buffers allocated for the ,<file>,.
8546      * Depending upon the load on the machine, the Linux kernel's flush daemon
8547      * process may not flush for a while.  In the meantime the CVS transaction
8548      * could have been declared committed to the end CVS user (CVS process has
8549      * returned the final "OK").  If the machine crashes prior to syncing the
8550      * changes to disk, the committed transaction can be lost.
8551      */
8552     if (fflush (fp) != 0)
8553 	error (1, errno, "error flushing file `%s' to kernel buffers",
8554 	       rcs_lockfile);
8555 #ifdef HAVE_FSYNC
8556     if (fsync (rcs_lockfd) < 0)
8557 	error (1, errno, "error fsyncing file `%s'", rcs_lockfile);
8558 #endif
8559 
8560     if (fclose (fp) == EOF)
8561 	error (1, errno, "error closing lock file %s", rcs_lockfile);
8562     rcs_lockfd = -1;
8563 
8564     rename_file (rcs_lockfile, rcsfile);
8565 
8566     {
8567 	/* Use a temporary to make sure there's no interval
8568 	   (after rcs_lockfile has been freed but before it's set to NULL)
8569 	   during which the signal handler's use of rcs_lockfile would
8570 	   reference freed memory.  */
8571 	char *tmp = rcs_lockfile;
8572 	rcs_lockfile = NULL;
8573 	free (tmp);
8574     }
8575 }
8576 
8577 
8578 
8579 static char *
8580 rcs_lockfilename (const char *rcsfile)
8581 {
8582     char *lockfile, *lockp;
8583     const char *rcsbase, *rcsp, *rcsend;
8584     int rcslen;
8585 
8586     /* Create the lockfile name. */
8587     rcslen = strlen (rcsfile);
8588     lockfile = xmalloc (rcslen + 10);
8589     rcsbase = last_component (rcsfile);
8590     rcsend = rcsfile + rcslen - sizeof(RCSEXT);
8591     for (lockp = lockfile, rcsp = rcsfile; rcsp < rcsbase; ++rcsp)
8592 	*lockp++ = *rcsp;
8593     *lockp++ = ',';
8594     while (rcsp <= rcsend)
8595 	*lockp++ = *rcsp++;
8596     *lockp++ = ',';
8597     *lockp = '\0';
8598 
8599     return lockfile;
8600 }
8601 
8602 
8603 
8604 /* Rewrite an RCS file.  The basic idea here is that the caller should
8605    first call RCS_reparsercsfile, then munge the data structures as
8606    desired (via RCS_delete_revs, RCS_settag, &c), then call RCS_rewrite.  */
8607 void
8608 RCS_rewrite (RCSNode *rcs, Deltatext *newdtext, char *insertpt)
8609 {
8610     FILE *fin, *fout;
8611     struct rcsbuffer rcsbufin;
8612 
8613     if (noexec)
8614 	return;
8615 
8616     /* Make sure we're operating on an actual file and not a symlink.  */
8617     resolve_symlink (&(rcs->path));
8618 
8619     fout = rcs_internal_lockfile (rcs->path);
8620 
8621     RCS_putadmin (rcs, fout);
8622     RCS_putdtree (rcs, rcs->head, fout);
8623     RCS_putdesc (rcs, fout);
8624 
8625     /* Open the original RCS file and seek to the first delta text. */
8626     rcsbuf_cache_open (rcs, rcs->delta_pos, &fin, &rcsbufin);
8627 
8628     /* Update delta_pos to the current position in the output file.
8629        Do NOT move these statements: they must be done after fin has
8630        been positioned at the old delta_pos, but before any delta
8631        texts have been written to fout.
8632      */
8633     rcs->delta_pos = ftello (fout);
8634     if (rcs->delta_pos == -1)
8635 	error (1, errno, "cannot ftello in RCS file %s", rcs->path);
8636 
8637     RCS_copydeltas (rcs, fin, &rcsbufin, fout, newdtext, insertpt);
8638 
8639     /* We don't want to call rcsbuf_cache here, since we're about to
8640        delete the file.  */
8641     rcsbuf_close (&rcsbufin);
8642     if (ferror (fin))
8643 	/* The only case in which using errno here would be meaningful
8644 	   is if we happen to have left errno unmolested since the call
8645 	   which produced the error (e.g. fread).  That is pretty
8646 	   fragile even if it happens to sometimes be true.  The real
8647 	   solution is to make sure that all the code which reads
8648 	   from fin checks for errors itself (some does, some doesn't).  */
8649 	error (0, 0, "warning: ferror set while rewriting RCS file `%s'", rcs->path);
8650     if (fclose (fin) < 0)
8651 	error (0, errno, "warning: closing RCS file `%s'", rcs->path);
8652 
8653     rcs_internal_unlockfile (fout, rcs->path);
8654 }
8655 
8656 
8657 
8658 /* Abandon changes to an RCS file. */
8659 void
8660 RCS_abandon (RCSNode *rcs)
8661 {
8662     free_rcsnode_contents (rcs);
8663     rcs->symbols_data = NULL;
8664     rcs->expand = NULL;
8665     rcs->access = NULL;
8666     rcs->locks_data = NULL;
8667     rcs->comment = NULL;
8668     rcs->desc = NULL;
8669     rcs->flags |= PARTIAL;
8670 }
8671 
8672 
8673 
8674 /*
8675  * For a given file with full pathname PATH and revision number REV,
8676  * produce a file label suitable for passing to diff.  The default
8677  * file label as used by RCS 5.7 looks like this:
8678  *
8679  *	FILENAME <tab> YYYY/MM/DD <sp> HH:MM:SS <tab> REVNUM
8680  *
8681  * The date and time used are the revision's last checkin date and time.
8682  * If REV is NULL, use the working copy's mtime instead.
8683  *
8684  * /dev/null is not statted but assumed to have been created on the Epoch.
8685  * At least using the POSIX.2 definition of patch, this should cause creation
8686  * of files on platforms such as Windoze where the null IO device isn't named
8687  * /dev/null to be parsed by patch properly.
8688  */
8689 char *
8690 make_file_label (const char *path, const char *rev, RCSNode *rcs)
8691 {
8692     char datebuf[MAXDATELEN + 1];
8693     char *label;
8694 
8695     if (rev)
8696     {
8697 	char date[MAXDATELEN + 1];
8698 	/* revs cannot be attached to /dev/null ... duh. */
8699 	assert (strcmp(DEVNULL, path));
8700 	RCS_getrevtime (rcs, rev, datebuf, 0);
8701 	(void) date_to_internet (date, datebuf);
8702 	label = Xasprintf ("-L%s\t%s\t%s", path, date, rev);
8703     }
8704     else
8705     {
8706 	struct stat sb;
8707 	struct tm *wm;
8708 
8709 	if (strcmp(DEVNULL, path))
8710 	{
8711 	    const char *file = last_component (path);
8712 	    if (stat (file, &sb) < 0)
8713 		/* Assume that if the stat fails,then the later read for the
8714 		 * diff will too.
8715 		 */
8716 		error (1, errno, "could not get info for `%s'", path);
8717 	    wm = gmtime (&sb.st_mtime);
8718 	}
8719 	else
8720 	{
8721 	    time_t t = 0;
8722 	    wm = gmtime(&t);
8723 	}
8724 
8725 	(void) tm_to_internet (datebuf, wm);
8726 	label = Xasprintf ("-L%s\t%s", path, datebuf);
8727     }
8728     return label;
8729 }
8730 
8731 
8732 
8733 /*
8734  * Set up a local/custom RCS keyword for expansion.
8735  *
8736  * INPUTS
8737  *   infopath		Path to file being parsed, for error messages.
8738  *   ln			Line number of INFOPATH being processed, for error
8739  *			messages.
8740  *   keywords_in
8741  *   arg
8742  *
8743  * OUTPUTS
8744  *   keywords_in
8745  */
8746 void
8747 RCS_setlocalid (const char *infopath, unsigned int ln,
8748 		void **keywords_in, const char *arg)
8749 {
8750     char *copy, *next, *key, *s;
8751     struct rcs_keyword *keywords;
8752     enum keyword save_expandto;
8753 
8754     if (!*keywords_in)
8755 	*keywords_in = new_keywords ();
8756     keywords = *keywords_in;
8757 
8758     copy = xstrdup (arg);
8759     next = copy;
8760     key = strtok (next, "=");
8761 
8762     /*
8763      * Validate key
8764      */
8765     for (s = key; *s != '\0'; s++)
8766     {
8767 	if (! isalpha ((unsigned char) *s))
8768 	{
8769 	    if (!parse_error (infopath, ln))
8770 		    error (0, 0,
8771 "%s [%u]: LocalKeyword ignored: Bad character `%c' in key `%s'",
8772 			   primary_root_inverse_translate (infopath),
8773 			   ln, *s, key);
8774 	    free (copy);
8775 	    return;
8776 	}
8777     }
8778 
8779     save_expandto = keywords[KEYWORD_LOCALID].expandto;
8780 
8781     /* options? */
8782     while ((key = strtok (NULL, ",")) != NULL) {
8783 	if (!strcmp(key, keywords[KEYWORD_ID].string))
8784 	    keywords[KEYWORD_LOCALID].expandto = KEYWORD_ID;
8785 	else if (!strcmp(key, keywords[KEYWORD_HEADER].string))
8786 	    keywords[KEYWORD_LOCALID].expandto = KEYWORD_HEADER;
8787 	else if (!strcmp(key, keywords[KEYWORD_CVSHEADER].string))
8788 	    keywords[KEYWORD_LOCALID].expandto = KEYWORD_CVSHEADER;
8789 	else
8790 	{
8791 	    keywords[KEYWORD_LOCALID].expandto = save_expandto;
8792 	    if (!parse_error (infopath, ln))
8793 		error (0, 0,
8794 "%s [%u]: LocalKeyword ignored: Unknown LocalId mode: `%s'",
8795 		       primary_root_inverse_translate (infopath),
8796 		       ln, key);
8797 	    free (copy);
8798 	    return;
8799 	}
8800     }
8801 
8802     keywords[KEYWORD_LOCALID].string = xstrdup (next);
8803     keywords[KEYWORD_LOCALID].len = strlen (next);
8804     keywords[KEYWORD_LOCALID].expandit = 1;
8805 
8806     free (copy);
8807 }
8808 
8809 
8810 
8811 void
8812 RCS_setincexc (void **keywords_in, const char *arg)
8813 {
8814     char *key;
8815     char *copy, *next;
8816     bool include = false;
8817     struct rcs_keyword *keyword;
8818     struct rcs_keyword *keywords;
8819 
8820     if (!*keywords_in)
8821 	*keywords_in = new_keywords ();
8822     keywords = *keywords_in;
8823 
8824     copy = xstrdup(arg);
8825     next = copy;
8826     switch (*next++) {
8827 	case 'e':
8828 	    include = false;
8829 	    break;
8830 	case 'i':
8831 	    include = true;
8832 	    break;
8833 	default:
8834 	    free(copy);
8835 	    return;
8836     }
8837 
8838     if (include)
8839 	for (keyword = keywords; keyword->string != NULL; keyword++)
8840 	{
8841 	    keyword->expandit = false;
8842 	}
8843 
8844     key = strtok(next, ",");
8845     while (key) {
8846 	for (keyword = keywords; keyword->string != NULL; keyword++) {
8847 	    if (strcmp (keyword->string, key) == 0)
8848 		keyword->expandit = include;
8849 	}
8850 	key = strtok(NULL, ",");
8851     }
8852     free(copy);
8853     return;
8854 }
8855 
8856 
8857 
8858 #define ATTIC "/" CVSATTIC
8859 static char *
8860 getfullCVSname(char *CVSname, char **pathstore)
8861 {
8862     if (current_parsed_root->directory) {
8863 	int rootlen;
8864 	char *c = NULL;
8865 	int alen = sizeof(ATTIC) - 1;
8866 
8867 	*pathstore = xstrdup(CVSname);
8868 	if ((c = strrchr(*pathstore, '/')) != NULL) {
8869 	    if (c - *pathstore >= alen) {
8870 		if (!strncmp(c - alen, ATTIC, alen)) {
8871 		    while (*c != '\0') {
8872 			*(c - alen) = *c;
8873 			c++;
8874 		    }
8875 		    *(c - alen) = '\0';
8876 		}
8877 	    }
8878 	}
8879 
8880 	rootlen = strlen(current_parsed_root->directory);
8881 	if (!strncmp(*pathstore, current_parsed_root->directory, rootlen) &&
8882 	    (*pathstore)[rootlen] == '/')
8883 	    CVSname = (*pathstore + rootlen + 1);
8884 	else
8885 	    CVSname = (*pathstore);
8886     }
8887     return CVSname;
8888 }
8889