rcs.c (eea99451) rcs.c (9fe7c2c3)
1/*
2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 *
4 * You may distribute under the terms of the GNU General Public License as
5 * specified in the README file that comes with the CVS source distribution.
6 *
7 * The routines contained in this file do all the rcs file parsing and
8 * manipulation

--- 139 unchanged lines hidden (view full) ---

148 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
149 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
151 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0 - 0xff */
152};
153
154#define whitespace(c) (spacetab[(unsigned char)c] != 0)
155
1/*
2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 *
4 * You may distribute under the terms of the GNU General Public License as
5 * specified in the README file that comes with the CVS source distribution.
6 *
7 * The routines contained in this file do all the rcs file parsing and
8 * manipulation

--- 139 unchanged lines hidden (view full) ---

148 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
149 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
151 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0 - 0xff */
152};
153
154#define whitespace(c) (spacetab[(unsigned char)c] != 0)
155
156/* A few generic thoughts on error handling, in particular the
157 printing of unexpected characters that we find in the RCS file
158 (that is, why we use '\x%x' rather than %c or some such).
159
160 * Avoiding %c means we don't have to worry about what is printable
161 and other such stuff. In error handling, often better to keep it
162 simple.
163
164 * Hex rather than decimal or octal because character set standards
165 tend to use hex.
166
167 * Saying "character 0x%x" might make it sound like we are printing
168 a file offset. So we use '\x%x'.
169
170 * Would be nice to print the offset within the file, but I can
171 imagine various portability hassles (in particular, whether
172 unsigned long is always big enough to hold file offsets). */
173
156/* Parse an rcsfile given a user file name and a repository. If there is
157 an error, we print an error message and return NULL. If the file
158 does not exist, we return NULL without printing anything (I'm not
159 sure this allows the caller to do anything reasonable, but it is
160 the current behavior). */
161RCSNode *
162RCS_parse (file, repos)
163 const char *file;

--- 195 unchanged lines hidden (view full) ---

359
360 if (STREQ (RCSEXPAND, key))
361 {
362 rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0,
363 (size_t *) NULL);
364 break;
365 }
366
174/* Parse an rcsfile given a user file name and a repository. If there is
175 an error, we print an error message and return NULL. If the file
176 does not exist, we return NULL without printing anything (I'm not
177 sure this allows the caller to do anything reasonable, but it is
178 the current behavior). */
179RCSNode *
180RCS_parse (file, repos)
181 const char *file;

--- 195 unchanged lines hidden (view full) ---

377
378 if (STREQ (RCSEXPAND, key))
379 {
380 rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0,
381 (size_t *) NULL);
382 break;
383 }
384
367 for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
385 for (cp = key;
386 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
387 cp++)
368 /* do nothing */ ;
369 if (*cp == '\0')
370 break;
371
372 if (STREQ (RCSDESC, key))
373 break;
374
375 if (! rcsbuf_getkey (&rcsbuf, &key, &value))

--- 117 unchanged lines hidden (view full) ---

493 continue;
494 }
495
496 /*
497 * check key for '.''s and digits (probably a rev) if it is a
498 * revision or `desc', we are done with the headers and are down to the
499 * revision deltas, so we break out of the loop
500 */
388 /* do nothing */ ;
389 if (*cp == '\0')
390 break;
391
392 if (STREQ (RCSDESC, key))
393 break;
394
395 if (! rcsbuf_getkey (&rcsbuf, &key, &value))

--- 117 unchanged lines hidden (view full) ---

513 continue;
514 }
515
516 /*
517 * check key for '.''s and digits (probably a rev) if it is a
518 * revision or `desc', we are done with the headers and are down to the
519 * revision deltas, so we break out of the loop
520 */
501 for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
521 for (cp = key;
522 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
523 cp++)
502 /* do nothing */ ;
503 /* Note that when comparing with RCSDATE, we are not massaging
504 VALUE from the string found in the RCS file. This is OK
505 since we know exactly what to expect. */
506 if (*cp == '\0' && strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) == 0)
507 break;
508
509 if (STREQ (key, RCSDESC))

--- 68 unchanged lines hidden (view full) ---

578 else
579 {
580 *pfp = fp;
581 *rcsbufp = rcsbuf;
582 }
583 rdata->flags &= ~PARTIAL;
584}
585
524 /* do nothing */ ;
525 /* Note that when comparing with RCSDATE, we are not massaging
526 VALUE from the string found in the RCS file. This is OK
527 since we know exactly what to expect. */
528 if (*cp == '\0' && strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) == 0)
529 break;
530
531 if (STREQ (key, RCSDESC))

--- 68 unchanged lines hidden (view full) ---

600 else
601 {
602 *pfp = fp;
603 *rcsbufp = rcsbuf;
604 }
605 rdata->flags &= ~PARTIAL;
606}
607
608/* Move RCS into or out of the Attic, depending on TOATTIC. If the
609 file is already in the desired place, return without doing
610 anything. At some point may want to think about how this relates
611 to RCS_rewrite but that is a bit hairy (if one wants renames to be
612 atomic, or that kind of thing). If there is an error, print a message
613 and return 1. On success, return 0. */
614int
615RCS_setattic (rcs, toattic)
616 RCSNode *rcs;
617 int toattic;
618{
619 char *newpath;
620 char *p;
621 char *q;
622
623 /* Some systems aren't going to let us rename an open file. */
624 rcsbuf_cache_close ();
625
626 /* Could make the pathname computations in this file, and probably
627 in other parts of rcs.c too, easier if the REPOS and FILE
628 arguments to RCS_parse got stashed in the RCSNode. */
629
630 if (toattic)
631 {
632 mode_t omask;
633
634 if (rcs->flags & INATTIC)
635 return 0;
636
637 /* Example: rcs->path is "/foo/bar/baz,v". */
638 newpath = xmalloc (strlen (rcs->path) + sizeof CVSATTIC + 5);
639 p = last_component (rcs->path);
640 strncpy (newpath, rcs->path, p - rcs->path);
641 strcpy (newpath + (p - rcs->path), CVSATTIC);
642
643 /* Create the Attic directory if it doesn't exist. */
644 omask = umask (cvsumask);
645 if (CVS_MKDIR (newpath, 0777) < 0 && errno != EEXIST)
646 error (0, errno, "cannot make directory %s", newpath);
647 (void) umask (omask);
648
649 strcat (newpath, "/");
650 strcat (newpath, p);
651
652 if (CVS_RENAME (rcs->path, newpath) < 0)
653 {
654 int save_errno = errno;
655
656 /* The checks for isreadable look awfully fishy, but
657 I'm going to leave them here for now until I
658 can think harder about whether they take care of
659 some cases which should be handled somehow. */
660
661 if (isreadable (rcs->path) || !isreadable (newpath))
662 {
663 error (0, save_errno, "cannot rename %s to %s",
664 rcs->path, newpath);
665 free (newpath);
666 return 1;
667 }
668 }
669 }
670 else
671 {
672 if (!(rcs->flags & INATTIC))
673 return 0;
674
675 newpath = xmalloc (strlen (rcs->path));
676
677 /* Example: rcs->path is "/foo/bar/Attic/baz,v". */
678 p = last_component (rcs->path);
679 strncpy (newpath, rcs->path, p - rcs->path - 1);
680 newpath[p - rcs->path - 1] = '\0';
681 q = newpath + (p - rcs->path - 1) - (sizeof CVSATTIC - 1);
682 assert (strncmp (q, CVSATTIC, sizeof CVSATTIC - 1) == 0);
683 strcpy (q, p);
684
685 if (CVS_RENAME (rcs->path, newpath) < 0)
686 {
687 error (0, errno, "failed to move `%s' out of the attic",
688 rcs->path);
689 free (newpath);
690 return 1;
691 }
692 }
693
694 free (rcs->path);
695 rcs->path = newpath;
696
697 return 0;
698}
699
586/*
587 * Fully parse the RCS file. Store all keyword/value pairs, fetch the
588 * log messages for each revision, and fetch add and delete counts for
589 * each revision (we could fetch the entire text for each revision,
590 * but the only caller, log_fileproc, doesn't need that information,
591 * so we don't waste the memory required to store it). The add and
592 * delete counts are stored on the OTHER field of the RCSVERSNODE
593 * structure, under the names ";add" and ";delete", so that we don't

--- 72 unchanged lines hidden (view full) ---

666 cp = value;
667 while (cp < value + vallen)
668 {
669 char op;
670 unsigned long count;
671
672 op = *cp++;
673 if (op != 'a' && op != 'd')
700/*
701 * Fully parse the RCS file. Store all keyword/value pairs, fetch the
702 * log messages for each revision, and fetch add and delete counts for
703 * each revision (we could fetch the entire text for each revision,
704 * but the only caller, log_fileproc, doesn't need that information,
705 * so we don't waste the memory required to store it). The add and
706 * delete counts are stored on the OTHER field of the RCSVERSNODE
707 * structure, under the names ";add" and ";delete", so that we don't

--- 72 unchanged lines hidden (view full) ---

780 cp = value;
781 while (cp < value + vallen)
782 {
783 char op;
784 unsigned long count;
785
786 op = *cp++;
787 if (op != 'a' && op != 'd')
674 error (1, 0, "unrecognized operation '%c' in %s",
788 error (1, 0, "\
789unrecognized operation '\\x%x' in %s",
675 op, rcs->path);
676 (void) strtoul (cp, (char **) &cp, 10);
677 if (*cp++ != ' ')
678 error (1, 0, "space expected in %s",
679 rcs->path);
680 count = strtoul (cp, (char **) &cp, 10);
681 if (*cp++ != '\012')
682 error (1, 0, "linefeed expected in %s",

--- 791 unchanged lines hidden (view full) ---

1474 if (! my_whitespace (c))
1475 break;
1476
1477 ++ptr;
1478 }
1479
1480 /* PTR should now point to the start of a string. */
1481 if (c != '@')
790 op, rcs->path);
791 (void) strtoul (cp, (char **) &cp, 10);
792 if (*cp++ != ' ')
793 error (1, 0, "space expected in %s",
794 rcs->path);
795 count = strtoul (cp, (char **) &cp, 10);
796 if (*cp++ != '\012')
797 error (1, 0, "linefeed expected in %s",

--- 791 unchanged lines hidden (view full) ---

1589 if (! my_whitespace (c))
1590 break;
1591
1592 ++ptr;
1593 }
1594
1595 /* PTR should now point to the start of a string. */
1596 if (c != '@')
1482 error (1, 0, "expected @-string at `%c' in %s", c, rcsbuf->filename);
1597 error (1, 0, "expected @-string at '\\x%x' in %s",
1598 c, rcsbuf->filename);
1483
1484 /* Optimize the common case of a value composed of a single
1485 '@' string. */
1486
1487 rcsbuf->at_string = 1;
1488
1489 ++ptr;
1490

--- 240 unchanged lines hidden (view full) ---

1731 rcsbuf->filename);
1732 ptrend = rcsbuf->ptrend;
1733 }
1734
1735 /* Legitimate ID characters are digits, dots and any `graphic
1736 printing character that is not a special.' This test ought
1737 to do the trick. */
1738 c = *ptr;
1599
1600 /* Optimize the common case of a value composed of a single
1601 '@' string. */
1602
1603 rcsbuf->at_string = 1;
1604
1605 ++ptr;
1606

--- 240 unchanged lines hidden (view full) ---

1847 rcsbuf->filename);
1848 ptrend = rcsbuf->ptrend;
1849 }
1850
1851 /* Legitimate ID characters are digits, dots and any `graphic
1852 printing character that is not a special.' This test ought
1853 to do the trick. */
1854 c = *ptr;
1739 if (isprint (c) &&
1855 if (isprint ((unsigned char) c) &&
1740 c != ';' && c != '$' && c != ',' && c != '@' && c != ':')
1741 {
1742 ++ptr;
1743 continue;
1744 }
1745 break;
1746 }
1747

--- 51 unchanged lines hidden (view full) ---

1799
1800 c = *ptr;
1801 if (! whitespace (c))
1802 break;
1803
1804 ++ptr;
1805 }
1806
1856 c != ';' && c != '$' && c != ',' && c != '@' && c != ':')
1857 {
1858 ++ptr;
1859 continue;
1860 }
1861 break;
1862 }
1863

--- 51 unchanged lines hidden (view full) ---

1915
1916 c = *ptr;
1917 if (! whitespace (c))
1918 break;
1919
1920 ++ptr;
1921 }
1922
1807 if (! isdigit (c) && c != '.')
1923 if (! isdigit ((unsigned char) c) && c != '.')
1808 error (1, 0,
1924 error (1, 0,
1809 "unexpected `%c' reading revision number in RCS file %s",
1925 "\
1926unexpected '\\x%x' reading revision number in RCS file %s",
1810 c, rcsbuf->filename);
1811
1812 *revp = ptr;
1813
1814 do
1815 {
1816 ++ptr;
1817 if (ptr >= ptrend)
1818 {
1819 ptr = rcsbuf_fill (rcsbuf, ptr, revp, (char **) NULL);
1820 if (ptr == NULL)
1821 error (1, 0,
1822 "unexpected EOF reading revision number in RCS file %s",
1823 rcsbuf->filename);
1824 ptrend = rcsbuf->ptrend;
1825 }
1826
1827 c = *ptr;
1828 }
1927 c, rcsbuf->filename);
1928
1929 *revp = ptr;
1930
1931 do
1932 {
1933 ++ptr;
1934 if (ptr >= ptrend)
1935 {
1936 ptr = rcsbuf_fill (rcsbuf, ptr, revp, (char **) NULL);
1937 if (ptr == NULL)
1938 error (1, 0,
1939 "unexpected EOF reading revision number in RCS file %s",
1940 rcsbuf->filename);
1941 ptrend = rcsbuf->ptrend;
1942 }
1943
1944 c = *ptr;
1945 }
1829 while (isdigit (c) || c == '.');
1946 while (isdigit ((unsigned char) c) || c == '.');
1830
1831 if (! whitespace (c))
1947
1948 if (! whitespace (c))
1832 error (1, 0, "unexpected `%c' reading revision number in RCS file %s",
1949 error (1, 0, "\
1950unexpected '\\x%x' reading revision number in RCS file %s",
1833 c, rcsbuf->filename);
1834
1835 *ptr = '\0';
1836
1837 rcsbuf->ptr = ptr + 1;
1838
1839 return 1;
1840}

--- 491 unchanged lines hidden (view full) ---

2332 if (! RCS_nodeisbranch (rcs, tag))
2333 {
2334 /* We can't get a particular date if the tag is not a
2335 branch. */
2336 return NULL;
2337 }
2338
2339 /* Work out the branch. */
1951 c, rcsbuf->filename);
1952
1953 *ptr = '\0';
1954
1955 rcsbuf->ptr = ptr + 1;
1956
1957 return 1;
1958}

--- 491 unchanged lines hidden (view full) ---

2450 if (! RCS_nodeisbranch (rcs, tag))
2451 {
2452 /* We can't get a particular date if the tag is not a
2453 branch. */
2454 return NULL;
2455 }
2456
2457 /* Work out the branch. */
2340 if (! isdigit (tag[0]))
2458 if (! isdigit ((unsigned char) tag[0]))
2341 branch = RCS_whatbranch (rcs, tag);
2342 else
2343 branch = xstrdup (tag);
2344
2345 /* Fetch the revision of branch as of date. */
2346 rev = RCS_getdatebranch (rcs, date, branch);
2347 free (branch);
2348 return (rev);

--- 124 unchanged lines hidden (view full) ---

2473 if (tag && (STREQ (tag, TAG_HEAD) || *tag == '\0'))
2474#if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */
2475 if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
2476 return ((char *) NULL); /* head request for removed file */
2477 else
2478#endif
2479 return (RCS_head (rcs));
2480
2459 branch = RCS_whatbranch (rcs, tag);
2460 else
2461 branch = xstrdup (tag);
2462
2463 /* Fetch the revision of branch as of date. */
2464 rev = RCS_getdatebranch (rcs, date, branch);
2465 free (branch);
2466 return (rev);

--- 124 unchanged lines hidden (view full) ---

2591 if (tag && (STREQ (tag, TAG_HEAD) || *tag == '\0'))
2592#if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */
2593 if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
2594 return ((char *) NULL); /* head request for removed file */
2595 else
2596#endif
2597 return (RCS_head (rcs));
2598
2481 if (!isdigit (tag[0]))
2599 if (!isdigit ((unsigned char) tag[0]))
2482 {
2483 char *version;
2484
2485 /* If we got a symbolic tag, resolve it to a numeric */
2486 version = translate_symtag (rcs, tag);
2487 if (version != NULL)
2488 {
2489 int dots;

--- 180 unchanged lines hidden (view full) ---

2670 * case for handling a null rcsnode.
2671 */
2672int
2673RCS_isbranch (rcs, rev)
2674 RCSNode *rcs;
2675 const char *rev;
2676{
2677 /* numeric revisions are easy -- even number of dots is a branch */
2600 {
2601 char *version;
2602
2603 /* If we got a symbolic tag, resolve it to a numeric */
2604 version = translate_symtag (rcs, tag);
2605 if (version != NULL)
2606 {
2607 int dots;

--- 180 unchanged lines hidden (view full) ---

2788 * case for handling a null rcsnode.
2789 */
2790int
2791RCS_isbranch (rcs, rev)
2792 RCSNode *rcs;
2793 const char *rev;
2794{
2795 /* numeric revisions are easy -- even number of dots is a branch */
2678 if (isdigit (*rev))
2796 if (isdigit ((unsigned char) *rev))
2679 return ((numdots (rev) & 1) == 0);
2680
2681 /* assume a revision if you can't find the RCS info */
2682 if (rcs == NULL)
2683 return (0);
2684
2685 /* now, look for a match in the symbols list */
2686 return (RCS_nodeisbranch (rcs, rev));

--- 10 unchanged lines hidden (view full) ---

2697 const char *rev;
2698{
2699 int dots;
2700 char *version;
2701
2702 assert (rcs != NULL);
2703
2704 /* numeric revisions are easy -- even number of dots is a branch */
2797 return ((numdots (rev) & 1) == 0);
2798
2799 /* assume a revision if you can't find the RCS info */
2800 if (rcs == NULL)
2801 return (0);
2802
2803 /* now, look for a match in the symbols list */
2804 return (RCS_nodeisbranch (rcs, rev));

--- 10 unchanged lines hidden (view full) ---

2815 const char *rev;
2816{
2817 int dots;
2818 char *version;
2819
2820 assert (rcs != NULL);
2821
2822 /* numeric revisions are easy -- even number of dots is a branch */
2705 if (isdigit (*rev))
2823 if (isdigit ((unsigned char) *rev))
2706 return ((numdots (rev) & 1) == 0);
2707
2708 version = translate_symtag (rcs, rev);
2709 if (version == NULL)
2710 return (0);
2711 dots = numdots (version);
2712 if ((dots & 1) == 0)
2713 {

--- 210 unchanged lines hidden (view full) ---

2924 char *br;
2925 char *retval;
2926
2927 assert (rcs != NULL);
2928
2929 if (RCS_nodeisbranch (rcs, rev))
2930 return RCS_getbranch (rcs, rev, 1);
2931
2824 return ((numdots (rev) & 1) == 0);
2825
2826 version = translate_symtag (rcs, rev);
2827 if (version == NULL)
2828 return (0);
2829 dots = numdots (version);
2830 if ((dots & 1) == 0)
2831 {

--- 210 unchanged lines hidden (view full) ---

3042 char *br;
3043 char *retval;
3044
3045 assert (rcs != NULL);
3046
3047 if (RCS_nodeisbranch (rcs, rev))
3048 return RCS_getbranch (rcs, rev, 1);
3049
2932 if (isdigit (*rev))
3050 if (isdigit ((unsigned char) *rev))
2933 num = xstrdup (rev);
2934 else
2935 {
2936 num = translate_symtag (rcs, rev);
2937 if (num == NULL)
2938 return NULL;
2939 }
2940 br = truncate_revnum (num);

--- 155 unchanged lines hidden (view full) ---

3096 }
3097
3098 /*
3099 * at this point, either we have the revision we want, or we have the
3100 * first revision on the trunk (1.1?) in our hands
3101 */
3102
3103 /* if we found what we're looking for, and it's not 1.1 return it */
3051 num = xstrdup (rev);
3052 else
3053 {
3054 num = translate_symtag (rcs, rev);
3055 if (num == NULL)
3056 return NULL;
3057 }
3058 br = truncate_revnum (num);

--- 155 unchanged lines hidden (view full) ---

3214 }
3215
3216 /*
3217 * at this point, either we have the revision we want, or we have the
3218 * first revision on the trunk (1.1?) in our hands
3219 */
3220
3221 /* if we found what we're looking for, and it's not 1.1 return it */
3104 if (cur_rev != NULL && ! STREQ (cur_rev, "1.1"))
3105 return (xstrdup (cur_rev));
3222 if (cur_rev != NULL)
3223 {
3224 if (! STREQ (cur_rev, "1.1"))
3225 return (xstrdup (cur_rev));
3106
3226
3227 /* This is 1.1; if the date of 1.1 is not the same as that for the
3228 1.1.1.1 version, then return 1.1. This happens when the first
3229 version of a file is created by a regular cvs add and commit,
3230 and there is a subsequent cvs import of the same file. */
3231 p = findnode (rcs->versions, "1.1.1.1");
3232 if (p)
3233 {
3234 vers = (RCSVers *) p->data;
3235 if (RCS_datecmp (vers->date, date) != 0)
3236 return xstrdup ("1.1");
3237 }
3238 }
3239
3107 /* look on the vendor branch */
3108 retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
3109
3110 /*
3111 * if we found a match, return it; otherwise, we return the first
3112 * revision on the trunk or NULL depending on force_tag_match and the
3113 * date of the first rev
3114 */

--- 334 unchanged lines hidden (view full) ---

3449 char *invalid = "$,.:;@"; /* invalid RCS tag characters */
3450 const char *cp;
3451
3452 /*
3453 * The first character must be an alphabetic letter. The remaining
3454 * characters cannot be non-visible graphic characters, and must not be
3455 * in the set of "invalid" RCS identifier characters.
3456 */
3240 /* look on the vendor branch */
3241 retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
3242
3243 /*
3244 * if we found a match, return it; otherwise, we return the first
3245 * revision on the trunk or NULL depending on force_tag_match and the
3246 * date of the first rev
3247 */

--- 334 unchanged lines hidden (view full) ---

3582 char *invalid = "$,.:;@"; /* invalid RCS tag characters */
3583 const char *cp;
3584
3585 /*
3586 * The first character must be an alphabetic letter. The remaining
3587 * characters cannot be non-visible graphic characters, and must not be
3588 * in the set of "invalid" RCS identifier characters.
3589 */
3457 if (isalpha (*tag))
3590 if (isalpha ((unsigned char) *tag))
3458 {
3459 for (cp = tag; *cp; cp++)
3460 {
3591 {
3592 for (cp = tag; *cp; cp++)
3593 {
3461 if (!isgraph (*cp))
3594 if (!isgraph ((unsigned char) *cp))
3462 error (1, 0, "tag `%s' has non-visible graphic characters",
3463 tag);
3464 if (strchr (invalid, *cp))
3465 error (1, 0, "tag `%s' must not contain the characters `%s'",
3466 tag, invalid);
3467 }
3468 }
3469 else

--- 10 unchanged lines hidden (view full) ---

3480 * call error.
3481 */
3482int
3483RCS_valid_rev (rev)
3484 char *rev;
3485{
3486 char last, c;
3487 last = *rev++;
3595 error (1, 0, "tag `%s' has non-visible graphic characters",
3596 tag);
3597 if (strchr (invalid, *cp))
3598 error (1, 0, "tag `%s' must not contain the characters `%s'",
3599 tag, invalid);
3600 }
3601 }
3602 else

--- 10 unchanged lines hidden (view full) ---

3613 * call error.
3614 */
3615int
3616RCS_valid_rev (rev)
3617 char *rev;
3618{
3619 char last, c;
3620 last = *rev++;
3488 if (!isdigit (last))
3621 if (!isdigit ((unsigned char) last))
3489 return 0;
3490 while ((c = *rev++)) /* Extra parens placate -Wall gcc option */
3491 {
3492 if (c == '.')
3493 {
3494 if (last == '.')
3495 return 0;
3496 continue;
3497 }
3498 last = c;
3622 return 0;
3623 while ((c = *rev++)) /* Extra parens placate -Wall gcc option */
3624 {
3625 if (c == '.')
3626 {
3627 if (last == '.')
3628 return 0;
3629 continue;
3630 }
3631 last = c;
3499 if (!isdigit (c))
3632 if (!isdigit ((unsigned char) c))
3500 return 0;
3501 }
3633 return 0;
3634 }
3502 if (!isdigit (last))
3635 if (!isdigit ((unsigned char) last))
3503 return 0;
3504 return 1;
3505}
3506
3507/*
3508 * Return true if RCS revision with TAG is a dead revision.
3509 */
3510int

--- 19 unchanged lines hidden (view full) ---

3530 Returns a pointer into storage which is allocated and freed along with
3531 the rest of the RCS information; the caller should not modify this
3532 storage. Returns NULL if the RCS file does not specify a keyword
3533 expansion mode; for all other errors, die with a fatal error. */
3534char *
3535RCS_getexpand (rcs)
3536 RCSNode *rcs;
3537{
3636 return 0;
3637 return 1;
3638}
3639
3640/*
3641 * Return true if RCS revision with TAG is a dead revision.
3642 */
3643int

--- 19 unchanged lines hidden (view full) ---

3663 Returns a pointer into storage which is allocated and freed along with
3664 the rest of the RCS information; the caller should not modify this
3665 storage. Returns NULL if the RCS file does not specify a keyword
3666 expansion mode; for all other errors, die with a fatal error. */
3667char *
3668RCS_getexpand (rcs)
3669 RCSNode *rcs;
3670{
3671 /* Since RCS_parsercsfile_i now reads expand, don't need to worry
3672 about RCS_reparsercsfile. */
3538 assert (rcs != NULL);
3539 return rcs->expand;
3540}
3541
3673 assert (rcs != NULL);
3674 return rcs->expand;
3675}
3676
3677/* Set keyword expansion mode to EXPAND. For example "b" for binary. */
3678void
3679RCS_setexpand (rcs, expand)
3680 RCSNode *rcs;
3681 char *expand;
3682{
3683 /* Since RCS_parsercsfile_i now reads expand, don't need to worry
3684 about RCS_reparsercsfile. */
3685 assert (rcs != NULL);
3686 if (rcs->expand != NULL)
3687 free (rcs->expand);
3688 rcs->expand = xstrdup (expand);
3689}
3690
3542/* RCS keywords, and a matching enum. */
3543struct rcs_keyword
3544{
3545 const char *string;
3546 size_t len;
3547};
3548#define KEYWORD_INIT(s) (s), sizeof (s) - 1
3549static struct rcs_keyword keywords[] =

--- 192 unchanged lines hidden (view full) ---

3742 size_t sublen;
3743
3744 srch_len -= (srch_next + 1) - srch;
3745 srch = srch_next + 1;
3746
3747 /* Look for the first non alphabetic character after the '$'. */
3748 send = srch + srch_len;
3749 for (s = srch; s < send; s++)
3691/* RCS keywords, and a matching enum. */
3692struct rcs_keyword
3693{
3694 const char *string;
3695 size_t len;
3696};
3697#define KEYWORD_INIT(s) (s), sizeof (s) - 1
3698static struct rcs_keyword keywords[] =

--- 192 unchanged lines hidden (view full) ---

3891 size_t sublen;
3892
3893 srch_len -= (srch_next + 1) - srch;
3894 srch = srch_next + 1;
3895
3896 /* Look for the first non alphabetic character after the '$'. */
3897 send = srch + srch_len;
3898 for (s = srch; s < send; s++)
3750 if (! isalpha (*s))
3899 if (! isalpha ((unsigned char) *s))
3751 break;
3752
3753 /* If the first non alphabetic character is not '$' or ':',
3754 then this is not an RCS keyword. */
3755 if (s == send || (*s != '$' && *s != ':'))
3756 continue;
3757
3758 /* See if this is one of the keywords. */

--- 87 unchanged lines hidden (view full) ---

3846
3847 case KEYWORD_LOG:
3848 case KEYWORD_RCSFILE:
3849 value = escape_keyword_value (last_component (rcs->path),
3850 &free_value);
3851 break;
3852
3853 case KEYWORD_NAME:
3900 break;
3901
3902 /* If the first non alphabetic character is not '$' or ':',
3903 then this is not an RCS keyword. */
3904 if (s == send || (*s != '$' && *s != ':'))
3905 continue;
3906
3907 /* See if this is one of the keywords. */

--- 87 unchanged lines hidden (view full) ---

3995
3996 case KEYWORD_LOG:
3997 case KEYWORD_RCSFILE:
3998 value = escape_keyword_value (last_component (rcs->path),
3999 &free_value);
4000 break;
4001
4002 case KEYWORD_NAME:
3854 if (name != NULL && ! isdigit (*name))
4003 if (name != NULL && ! isdigit ((unsigned char) *name))
3855 value = (char *) name;
3856 else
3857 value = NULL;
3858 break;
3859
3860 case KEYWORD_REVISION:
3861 value = ver->version;
3862 break;

--- 326 unchanged lines hidden (view full) ---

4189 rev != NULL ? rev : "",
4190 options != NULL ? options : "",
4191 (pfn != NULL ? "(function)"
4192 : (workfile != NULL
4193 ? workfile
4194 : (sout != RUN_TTY ? sout : "(stdout)"))));
4195 }
4196
4004 value = (char *) name;
4005 else
4006 value = NULL;
4007 break;
4008
4009 case KEYWORD_REVISION:
4010 value = ver->version;
4011 break;

--- 326 unchanged lines hidden (view full) ---

4338 rev != NULL ? rev : "",
4339 options != NULL ? options : "",
4340 (pfn != NULL ? "(function)"
4341 : (workfile != NULL
4342 ? workfile
4343 : (sout != RUN_TTY ? sout : "(stdout)"))));
4344 }
4345
4197 assert (rev == NULL || isdigit (*rev));
4346 assert (rev == NULL || isdigit ((unsigned char) *rev));
4198
4199 if (noexec && workfile != NULL)
4200 return 0;
4201
4202 assert (sout == RUN_TTY || workfile == NULL);
4203 assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL));
4204
4205 /* Some callers, such as Checkin or remove_file, will pass us a

--- 817 unchanged lines hidden (view full) ---

5023 assert (strncmp (p, RCSEXT, extlen) == 0);
5024 *p = '\0';
5025 allocated_workfile = 1;
5026 }
5027
5028 /* Is the backend file a symbolic link? Follow it and replace the
5029 filename with the destination of the link. */
5030
4347
4348 if (noexec && workfile != NULL)
4349 return 0;
4350
4351 assert (sout == RUN_TTY || workfile == NULL);
4352 assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL));
4353
4354 /* Some callers, such as Checkin or remove_file, will pass us a

--- 817 unchanged lines hidden (view full) ---

5172 assert (strncmp (p, RCSEXT, extlen) == 0);
5173 *p = '\0';
5174 allocated_workfile = 1;
5175 }
5176
5177 /* Is the backend file a symbolic link? Follow it and replace the
5178 filename with the destination of the link. */
5179
5031 while (islink (rcs->path))
5032 {
5033 char *newname;
5034#ifdef HAVE_READLINK
5035 /* The clean thing to do is probably to have each filesubr.c
5036 implement this (with an error if not supported by the
5037 platform, in which case islink would presumably return 0).
5038 But that would require editing each filesubr.c and so the
5039 expedient hack seems to be looking at HAVE_READLINK. */
5040 newname = xreadlink (rcs->path);
5041#else
5042 error (1, 0, "internal error: islink doesn't like readlink");
5043#endif
5044
5045 if (isabsolute (newname))
5046 {
5047 free (rcs->path);
5048 rcs->path = newname;
5049 }
5050 else
5051 {
5052 char *oldname = last_component (rcs->path);
5053 int dirlen = oldname - rcs->path;
5054 char *fullnewname = xmalloc (dirlen + strlen (newname) + 1);
5055 strncpy (fullnewname, rcs->path, dirlen);
5056 strcpy (fullnewname + dirlen, newname);
5057 free (newname);
5058 free (rcs->path);
5059 rcs->path = fullnewname;
5060 }
5061 }
5180 /* If the filename is a symbolic link, follow it and replace it
5181 with the destination of the link. We need to do this before
5182 calling rcs_internal_lockfile, or else we won't put the lock in
5183 the right place. */
5184 resolve_symlink (&(rcs->path));
5062
5063 checkin_quiet = flags & RCS_FLAGS_QUIET;
5064 if (!checkin_quiet)
5065 {
5066 cvs_output (rcs->path, 0);
5067 cvs_output (" <-- ", 7);
5068 cvs_output (workfile, 0);
5069 cvs_output ("\n", 1);

--- 210 unchanged lines hidden (view full) ---

5280 }
5281 else
5282 {
5283 /* REV is either a revision number or a branch number. Find the
5284 tip of the target branch. */
5285 char *branch, *tip, *newrev, *p;
5286 int dots, isrevnum;
5287
5185
5186 checkin_quiet = flags & RCS_FLAGS_QUIET;
5187 if (!checkin_quiet)
5188 {
5189 cvs_output (rcs->path, 0);
5190 cvs_output (" <-- ", 7);
5191 cvs_output (workfile, 0);
5192 cvs_output ("\n", 1);

--- 210 unchanged lines hidden (view full) ---

5403 }
5404 else
5405 {
5406 /* REV is either a revision number or a branch number. Find the
5407 tip of the target branch. */
5408 char *branch, *tip, *newrev, *p;
5409 int dots, isrevnum;
5410
5288 assert (isdigit(*rev));
5411 assert (isdigit ((unsigned char) *rev));
5289
5290 newrev = xstrdup (rev);
5291 dots = numdots (newrev);
5292 isrevnum = dots & 1;
5293
5294 branch = xstrdup (rev);
5295 if (isrevnum)
5296 {

--- 1247 unchanged lines hidden (view full) ---

6544 {
6545 beforefile = cvs_temp_name();
6546 status = RCS_checkout (rcs, NULL, before, NULL, NULL, beforefile,
6547 (RCSCHECKOUTPROC)0, NULL);
6548 if (status > 0)
6549 goto delrev_done;
6550
6551 outfile = cvs_temp_name();
5412
5413 newrev = xstrdup (rev);
5414 dots = numdots (newrev);
5415 isrevnum = dots & 1;
5416
5417 branch = xstrdup (rev);
5418 if (isrevnum)
5419 {

--- 1247 unchanged lines hidden (view full) ---

6667 {
6668 beforefile = cvs_temp_name();
6669 status = RCS_checkout (rcs, NULL, before, NULL, NULL, beforefile,
6670 (RCSCHECKOUTPROC)0, NULL);
6671 if (status > 0)
6672 goto delrev_done;
6673
6674 outfile = cvs_temp_name();
6552 status = diff_exec (beforefile, afterfile, "-n", outfile);
6675 status = diff_exec (beforefile, afterfile, "-an", outfile);
6553
6554 if (status == 2)
6555 {
6556 /* Not sure we need this message; will diff_exec already
6557 have printed an error? */
6558 error (0, 0, "%s: could not diff", rcs->path);
6559 status = 1;
6560 goto delrev_done;

--- 450 unchanged lines hidden (view full) ---

7011
7012 dfhead = NULL;
7013 for (p = diffbuf; p != NULL && p < diffbuf + difflen; )
7014 {
7015 op = *p++;
7016 if (op != 'a' && op != 'd')
7017 /* Can't just skip over the deltafrag, because the value
7018 of op determines the syntax. */
6676
6677 if (status == 2)
6678 {
6679 /* Not sure we need this message; will diff_exec already
6680 have printed an error? */
6681 error (0, 0, "%s: could not diff", rcs->path);
6682 status = 1;
6683 goto delrev_done;

--- 450 unchanged lines hidden (view full) ---

7134
7135 dfhead = NULL;
7136 for (p = diffbuf; p != NULL && p < diffbuf + difflen; )
7137 {
7138 op = *p++;
7139 if (op != 'a' && op != 'd')
7140 /* Can't just skip over the deltafrag, because the value
7141 of op determines the syntax. */
7019 error (1, 0, "unrecognized operation '%c' in %s", op, name);
7142 error (1, 0, "unrecognized operation '\\x%x' in %s",
7143 op, name);
7020 df = (struct deltafrag *) xmalloc (sizeof (struct deltafrag));
7021 df->next = dfhead;
7022 dfhead = df;
7023 df->pos = strtoul (p, (char **) &q, 10);
7024
7025 if (p == q)
7026 error (1, 0, "number expected in %s", name);
7027 p = q;

--- 509 unchanged lines hidden (view full) ---

7537 else
7538 {
7539 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7540 error (1, 0, "%s: unexpected EOF", rcsfile);
7541 }
7542
7543 /* Make sure that it is a revision number and not a cabbage
7544 or something. */
7144 df = (struct deltafrag *) xmalloc (sizeof (struct deltafrag));
7145 df->next = dfhead;
7146 dfhead = df;
7147 df->pos = strtoul (p, (char **) &q, 10);
7148
7149 if (p == q)
7150 error (1, 0, "number expected in %s", name);
7151 p = q;

--- 509 unchanged lines hidden (view full) ---

7661 else
7662 {
7663 if (! rcsbuf_getkey (rcsbuf, &key, &value))
7664 error (1, 0, "%s: unexpected EOF", rcsfile);
7665 }
7666
7667 /* Make sure that it is a revision number and not a cabbage
7668 or something. */
7545 for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
7669 for (cp = key;
7670 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
7671 cp++)
7546 /* do nothing */ ;
7547 /* Note that when comparing with RCSDATE, we are not massaging
7548 VALUE from the string found in the RCS file. This is OK since
7549 we know exactly what to expect. */
7550 if (*cp != '\0' || strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) != 0)
7551 {
7552 *keyp = key;
7553 *valp = value;

--- 167 unchanged lines hidden (view full) ---

7721 {
7722 vnode->dead = 1;
7723 if (vnode->state != NULL)
7724 free (vnode->state);
7725 vnode->state = xstrdup ("dead");
7726 continue;
7727 }
7728 /* if we have a new revision number, we're done with this delta */
7672 /* do nothing */ ;
7673 /* Note that when comparing with RCSDATE, we are not massaging
7674 VALUE from the string found in the RCS file. This is OK since
7675 we know exactly what to expect. */
7676 if (*cp != '\0' || strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) != 0)
7677 {
7678 *keyp = key;
7679 *valp = value;

--- 167 unchanged lines hidden (view full) ---

7847 {
7848 vnode->dead = 1;
7849 if (vnode->state != NULL)
7850 free (vnode->state);
7851 vnode->state = xstrdup ("dead");
7852 continue;
7853 }
7854 /* if we have a new revision number, we're done with this delta */
7729 for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
7855 for (cp = key;
7856 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
7857 cp++)
7730 /* do nothing */ ;
7731 /* Note that when comparing with RCSDATE, we are not massaging
7732 VALUE from the string found in the RCS file. This is OK
7733 since we know exactly what to expect. */
7734 if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0)
7735 break;
7736
7737 /* At this point, key and value represent a user-defined field

--- 725 unchanged lines hidden (view full) ---

8463 char *insertpt;
8464{
8465 FILE *fin, *fout;
8466 struct rcsbuffer rcsbufin;
8467
8468 if (noexec)
8469 return;
8470
7858 /* do nothing */ ;
7859 /* Note that when comparing with RCSDATE, we are not massaging
7860 VALUE from the string found in the RCS file. This is OK
7861 since we know exactly what to expect. */
7862 if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0)
7863 break;
7864
7865 /* At this point, key and value represent a user-defined field

--- 725 unchanged lines hidden (view full) ---

8591 char *insertpt;
8592{
8593 FILE *fin, *fout;
8594 struct rcsbuffer rcsbufin;
8595
8596 if (noexec)
8597 return;
8598
8599 /* Make sure we're operating on an actual file and not a symlink. */
8600 resolve_symlink (&(rcs->path));
8601
8471 fout = rcs_internal_lockfile (rcs->path);
8472
8473 RCS_putadmin (rcs, fout);
8474 RCS_putdtree (rcs, rcs->head, fout);
8475 RCS_putdesc (rcs, fout);
8476
8477 /* Open the original RCS file and seek to the first delta text. */
8478 rcsbuf_cache_open (rcs, rcs->delta_pos, &fin, &rcsbufin);

--- 136 unchanged lines hidden (view full) ---

8615
8616 if (local)
8617 send_arg ("-l");
8618 if (!force_tag_match)
8619 send_arg ("-f");
8620 option_with_arg ("-r", tag);
8621 if (date)
8622 client_senddate (date);
8602 fout = rcs_internal_lockfile (rcs->path);
8603
8604 RCS_putadmin (rcs, fout);
8605 RCS_putdtree (rcs, rcs->head, fout);
8606 RCS_putdesc (rcs, fout);
8607
8608 /* Open the original RCS file and seek to the first delta text. */
8609 rcsbuf_cache_open (rcs, rcs->delta_pos, &fin, &rcsbufin);

--- 136 unchanged lines hidden (view full) ---

8746
8747 if (local)
8748 send_arg ("-l");
8749 if (!force_tag_match)
8750 send_arg ("-f");
8751 option_with_arg ("-r", tag);
8752 if (date)
8753 client_senddate (date);
8623 send_file_names (argc, argv, SEND_EXPAND_WILD);
8624 send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
8754 send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
8755 send_file_names (argc, argv, SEND_EXPAND_WILD);
8625 send_to_server ("annotate\012", 0);
8626 return get_responses_and_close ();
8627 }
8628#endif /* CLIENT_SUPPORT */
8629
8630 if (tag != NULL)
8631 tag_check_valid (tag, argc, argv, local, 0, "");
8632

--- 19 unchanged lines hidden (view full) ---

8652 char *rev;
8653 RCSNode *rcs;
8654{
8655 char datebuf[MAXDATELEN];
8656 char *label;
8657 char *file;
8658
8659 file = last_component (path);
8756 send_to_server ("annotate\012", 0);
8757 return get_responses_and_close ();
8758 }
8759#endif /* CLIENT_SUPPORT */
8760
8761 if (tag != NULL)
8762 tag_check_valid (tag, argc, argv, local, 0, "");
8763

--- 19 unchanged lines hidden (view full) ---

8783 char *rev;
8784 RCSNode *rcs;
8785{
8786 char datebuf[MAXDATELEN];
8787 char *label;
8788 char *file;
8789
8790 file = last_component (path);
8660 label = (char *) xmalloc (strlen (file)
8791 label = (char *) xmalloc (strlen (path)
8661 + (rev == NULL ? 0 : strlen (rev))
8662 + 50);
8663
8664 if (rev)
8665 {
8666 char *date;
8667 RCS_getrevtime (rcs, rev, datebuf, 0);
8668 date = printable_date (datebuf);
8792 + (rev == NULL ? 0 : strlen (rev))
8793 + 50);
8794
8795 if (rev)
8796 {
8797 char *date;
8798 RCS_getrevtime (rcs, rev, datebuf, 0);
8799 date = printable_date (datebuf);
8669 (void) sprintf (label, "-L%s\t%s\t%s", file, date, rev);
8800 (void) sprintf (label, "-L%s\t%s\t%s", path, date, rev);
8670 free (date);
8671 }
8672 else
8673 {
8674 struct stat sb;
8675 struct tm *wm;
8676
8677 if (CVS_STAT (file, &sb) < 0)
8678 error (0, 1, "could not get info for `%s'", path);
8679 else
8680 {
8681 wm = gmtime (&sb.st_mtime);
8682 (void) sprintf (datebuf, "%04d/%02d/%02d %02d:%02d:%02d",
8683 wm->tm_year + 1900, wm->tm_mon + 1,
8684 wm->tm_mday, wm->tm_hour,
8685 wm->tm_min, wm->tm_sec);
8801 free (date);
8802 }
8803 else
8804 {
8805 struct stat sb;
8806 struct tm *wm;
8807
8808 if (CVS_STAT (file, &sb) < 0)
8809 error (0, 1, "could not get info for `%s'", path);
8810 else
8811 {
8812 wm = gmtime (&sb.st_mtime);
8813 (void) sprintf (datebuf, "%04d/%02d/%02d %02d:%02d:%02d",
8814 wm->tm_year + 1900, wm->tm_mon + 1,
8815 wm->tm_mday, wm->tm_hour,
8816 wm->tm_min, wm->tm_sec);
8686 (void) sprintf (label, "-L%s\t%s", file, datebuf);
8817 (void) sprintf (label, "-L%s\t%s", path, datebuf);
8687 }
8688 }
8689 return label;
8690}
8818 }
8819 }
8820 return label;
8821}
8691