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