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