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