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