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