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