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