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