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