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