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