bug-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Feature request/ideas


From: Frank Hemer
Subject: Re: Feature request/ideas
Date: Wed, 2 Mar 2005 03:11:59 +0100
User-agent: KMail/1.5.1

> Note that when the final flag to tag_check_valid() is true,
> tag_check_valid() skips step 2 (the recursive repository check) and
> jumps to adding the tag to val-tags.

Is this a security issue, meaning to reduce server load if lots of invalid tags 
are requested?

However, I have implemented it that way, also adding tag_check_valid(...,true)
to import.c and commit.c


Tags now can be combined of several subexpressions, each separated by a dot.

Tags that must be at the begining of the tag:
1. '.commitid' (backwd. compatible as '@') followed by the id
2. '.trunk' may be used as a TRUNK branch

Extensions that might follow such a tag (or a numeric/symbolic tag):
1. '.prev' - meaning the previous revision on the current branch or trunk
2. '.next' - meaning the next revision on the current branch or trunk
3. '.root' - meaning the first revision on the current branch or trunk
4. '.origin' - meaning the revision a branch-revision or branch is based on: 
1.4.2.5.origin  => 1.4

All extensions can be appended several times. No rule without an exception, the 
'.root' extension
cannot be appended to itself, it needs a different extension in between.

Example 1.4.2.5.root.prev == 1.4.2.5.origin == 1.4.prev.next == 1.4

sanity.sh runs ok, but I would like to receive some feedback ...

Here's the patch agains the current repo version:

Index: src/commit.c
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/commit.c,v
retrieving revision 1.1.1.2
retrieving revision 1.4
diff -u -r1.1.1.2 -r1.4
--- src/commit.c        2 Mar 2005 01:36:28 -0000       1.1.1.2
+++ src/commit.c        2 Mar 2005 01:40:09 -0000       1.4
@@ -698,6 +698,10 @@
     Lock_Cleanup ();
     dellist (&mulist);
 
+    char *commitid = Xasprintf ("@%s", global_session_id);
+    tag_check_valid (commitid, argc, argv, local, aflag, "", true);
+    free (commitid);
+
     /* see if we need to sleep before returning to avoid time-stamp races */
     if (
 #ifdef SERVER_SUPPORT
@@ -884,13 +888,16 @@
                           finfo->fullname);
                    goto out;
                }
-               if (status == T_MODIFIED && vers->tag &&
-                   !RCS_isbranch (finfo->rcs, vers->tag))
+               if (status == T_MODIFIED && vers->tag)
                {
-                   error (0, 0,
-                          "sticky tag `%s' for file `%s' is not a branch",
-                          vers->tag, finfo->fullname);
-                   goto out;
+                  if ( (*(vers->tag) != '.' || strcmp (vers->tag+1, TAG_TRUNK))
+                        && !RCS_isbranch (finfo->rcs, vers->tag) )
+                  {
+                     error (0, 0,
+                           "sticky tag `%s' for file `%s' is not a branch",
+                           vers->tag, finfo->fullname);
+                     goto out;
+                  }
                }
            }
            if (status == T_MODIFIED && !force_ci && vers->ts_conflict)
Index: src/cvs.h
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/cvs.h,v
retrieving revision 1.1.1.1
retrieving revision 1.5
diff -u -r1.1.1.1 -r1.5
--- src/cvs.h   27 Feb 2005 15:02:24 -0000      1.1.1.1
+++ src/cvs.h   1 Mar 2005 20:30:05 -0000       1.5
@@ -242,6 +242,12 @@
  */
 #define        TAG_HEAD        "HEAD"
 #define        TAG_BASE        "BASE"
+#define TAG_COMMITID    "commitid"
+#define TAG_PREVIOUS    "prev"
+#define TAG_TRUNK       "trunk"
+#define TAG_ORIGIN      "origin"
+#define TAG_ROOT        "root"
+#define TAG_NEXT        "next"
 
 /* Environment variable used by CVS */
 #define        CVSREAD_ENV     "CVSREAD"       /* make files read-only */
Index: src/import.c
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/import.c,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -r1.1.1.1 -r1.3
--- src/import.c        27 Feb 2005 15:02:24 -0000      1.1.1.1
+++ src/import.c        1 Mar 2005 12:41:18 -0000       1.3
@@ -440,6 +440,10 @@
        error (0, errno, "cannot remove %s", tmpfile);
     free (tmpfile);
 
+    char *commitid = Xasprintf ("@%s", global_session_id);
+    tag_check_valid (commitid, 0, NULL, 0, 1, NULL, true);
+    free (commitid);
+
     if (message)
        free (message);
     free (repository);
Index: src/rcs.c
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/rcs.c,v
retrieving revision 1.1.1.2
retrieving revision 1.14
diff -u -r1.1.1.2 -r1.14
--- src/rcs.c   28 Feb 2005 21:55:36 -0000      1.1.1.2
+++ src/rcs.c   2 Mar 2005 01:27:01 -0000       1.14
@@ -65,6 +65,8 @@
 };
 
 static RCSNode *RCS_parsercsfile_i (FILE * fp, const char *rcsfile);
+static char *RCS_getdatetrunk (RCSNode * rcs, const char *date,
+                               int force_tag_match);
 static char *RCS_getdatebranch (RCSNode * rcs, const char *date,
                                 const char *branch);
 static void rcsbuf_open (struct rcsbuffer *, FILE *fp,
@@ -94,6 +96,12 @@
 static void free_rcsnode_contents (RCSNode *);
 static void free_rcsvers_contents (RCSVers *);
 static void rcsvers_delproc (Node * p);
+static char *RCS_getroot (RCSNode *, const char *);
+static char *RCS_getprevious (RCSNode *, const char *);
+static char *RCS_getnext (RCSNode *, const char *);
+static char *RCS_getorigin (RCSNode *, const char *);
+static char *RCS_getcommitid (RCSNode *, const char *, bool);
+static char *translate_tag (RCSNode *, const char *);
 static char *translate_symtag (RCSNode *, const char *);
 static char *RCS_addbranch (RCSNode *, const char *);
 static char *truncate_revnum_in_place (char *);
@@ -2126,23 +2134,30 @@
     {
        char *branch, *rev;
 
-       if (! RCS_nodeisbranch (rcs, tag))
+       if (*tag == '.' && !strcmp (tag+1, TAG_TRUNK))
        {
-           /* We can't get a particular date if the tag is not a
-               branch.  */
-           return NULL;
+           return RCS_getdatetrunk (rcs, date, force_tag_match);
        }
-
-       /* Work out the branch.  */
-       if (! isdigit ((unsigned char) tag[0]))
-           branch = RCS_whatbranch (rcs, tag);
        else
-           branch = xstrdup (tag);
+       {
+           if (! RCS_nodeisbranch (rcs, tag))
+           {
+               /* We can't get a particular date if the tag is not a
+                  branch.  */
+               return NULL;
+           }
 
-       /* Fetch the revision of branch as of date.  */
-       rev = RCS_getdatebranch (rcs, date, branch);
-       free (branch);
-       return rev;
+           /* Work out the branch.  */
+           if (! isdigit ((unsigned char) tag[0]))
+               branch = RCS_whatbranch (rcs, tag);
+           else
+               branch = xstrdup (tag);
+
+           /* Fetch the revision of branch as of date.  */
+           rev = RCS_getdatebranch (rcs, date, branch);
+           free (branch);
+           return rev;
+       }
     }
     else if (tag)
        return RCS_gettag (rcs, tag, force_tag_match, simple_tag);
@@ -2163,6 +2178,8 @@
  *    returns the magic branch number.
  * -- If tag is a branch tag, returns the branch number, not
  *    the revision of the head of the branch.
+ * -- An exception is made for '.trunk' as it returns the
+ *    head revision of the trunk
  * If tag or revision is not valid or does not exist in file,
  * return NULL.
  */
@@ -2228,15 +2245,15 @@
        error (1, 0, "revision `%s' does not exist", tag);
     }
 
-
-    RCS_check_tag (tag); /* exit if not a valid tag */
-
     /* If tag is "HEAD", special case to get head RCS revision */
     if (tag && STREQ (tag, TAG_HEAD))
         return RCS_head (rcs);
 
-    /* If valid tag let translate_symtag say yea or nay. */
-    rev = translate_symtag (rcs, tag);
+    /* If valid tag let translate_tag say yea or nay. */
+    char *tmp = RCS_extract_tag (tag);
+    if (tmp)
+        free (tmp);
+    rev = translate_tag (rcs, tag);
 
     if (rev)
         return rev;
@@ -2282,12 +2299,12 @@
 #endif
            return RCS_head (rcs);
 
-    if (!isdigit ((unsigned char) symtag[0]))
+    if (!isrevnumonly (symtag))
     {
        char *version;
 
        /* If we got a symbolic tag, resolve it to a numeric */
-       version = translate_symtag (rcs, symtag);
+       version = translate_tag (rcs, symtag);
        if (version != NULL)
        {
            int dots;
@@ -2517,10 +2534,10 @@
     assert (rcs != NULL);
 
     /* numeric revisions are easy -- even number of dots is a branch */
-    if (isdigit ((unsigned char) *rev))
-       return (numdots (rev) & 1) == 0;
+    if (isrevnumonly (rev))
+        return (numdots (rev) & 1) == 0;
 
-    version = translate_symtag (rcs, rev);
+    version = translate_tag (rcs, rev);
     if (version == NULL)
        return 0;
     dots = numdots (version);
@@ -2571,7 +2588,7 @@
        return NULL;
 
     /* now, look for a match in the symbols list */
-    version = translate_symtag (rcs, rev);
+    version = translate_tag (rcs, rev);
     if (version == NULL)
        return NULL;
     dots = numdots (version);
@@ -2742,11 +2759,11 @@
     if (RCS_nodeisbranch (rcs, rev))
        return RCS_getbranch (rcs, rev, 1);
 
-    if (isdigit ((unsigned char) *rev))
+    if (isrevnumonly (rev))
        num = xstrdup (rev);
     else
     {
-       num = translate_symtag (rcs, rev);
+       num = translate_tag (rcs, rev);
        if (num == NULL)
            return NULL;
     }
@@ -2885,7 +2902,26 @@
            return retval;
     }
 
-    /* otherwise if we have a trunk, try it */
+    /* otherwise if we have a trunk, use it */
+    return RCS_getdatetrunk (rcs, date, force_tag_match);
+}
+
+
+
+/*
+ * Look up the last element on the trunk that was put in before or on
+ * the specified date and time (return the rev or NULL)
+ * Follow the vendor branch if not found on the trunk
+ */
+static char *
+RCS_getdatetrunk (RCSNode *rcs, const char *date, int force_tag_match)
+{
+    Node *p = NULL;
+    RCSVers *vers = NULL;
+    char *retval = NULL;
+
+    assert(rcs);
+
     if (rcs->head)
     {
        p = findnode (rcs->versions, rcs->head);
@@ -2900,8 +2936,8 @@
            vers = p->data;
            if (RCS_datecmp (vers->date, date) <= 0)
            {
-               cur_rev = vers->version;
-               break;
+                retval = vers->version;
+                break;
            }
 
            /* if there is a next version, find the node */
@@ -2921,10 +2957,10 @@
      */
 
     /* if we found what we're looking for, and it's not 1.1 return it */
-    if (cur_rev != NULL)
+    if (retval != NULL)
     {
-       if (! STREQ (cur_rev, "1.1"))
-           return xstrdup (cur_rev);
+       if (! STREQ (retval, "1.1"))
+           return xstrdup (retval);
 
        /* This is 1.1;  if the date of 1.1 is not the same as that for the
           1.1.1.1 version, then return 1.1.  This happens when the first
@@ -2941,7 +2977,6 @@
        }
     }
 
-    /* look on the vendor branch */
     retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
 
     /*
@@ -3178,15 +3213,334 @@
 
 
 /*
- * Return the version associated with a particular symbolic tag.
+ * Find the previous revision
+ *
+ * RETURN
+ *     Branch: return the HEAD-1 revision or NULL
+ *     Revision: return the previous revision or NULL
+ */
+static char *
+RCS_getprevious (RCSNode *rcs, const char *rev)
+{
+   char *retval = xstrdup (rev);
+
+   /* remove ev. magic branch num */
+   int dots = numdots (rev);
+   if (dots > 2 && (dots & 1))
+   {
+       int i;
+       const char *p = rev;
+       for (i = 1; i < dots; ++i)
+          p = strchr (p+1, '.');
+       assert (p);
+       if (!strncmp (p, ".0.", 3))
+       {
+          strcpy (retval + (p - rev), p + 2);
+          --dots;
+       }
+   }
+   if (!(dots & 1))
+   {
+       char *p = retval;
+       retval = RCS_branch_head (rcs, p);
+       free (p);
+   }
+
+   char *p = retval;
+   retval = previous_rev (rcs, p);
+   free (p);
+   
+   return retval;
+}
+
+
+
+/*
+ * Find the next revision
+ *
+ * RETURN
+ *     Branch: NULL (There cannot be a revision)
+ *     Revision: returns the next revision or NULL
+ */
+static char *
+RCS_getnext (RCSNode *rcs, const char *rev)
+{
+    Node *p = NULL;
+    RCSVers *vers = NULL;
+    if (numdots (rev) > 1)
+    {
+       bool stop = false;
+        p = findnode (rcs->versions, rev);
+       while (p != NULL)
+       {
+           vers = p->data;
+
+           /* if there is a next version, find the node */
+           if (!stop && vers->next != NULL)
+           {
+               p = findnode (rcs->versions, vers->next);
+               stop = true;
+           }
+           else
+               break;
+       }
+    }
+    else if (rcs->head)
+    {
+       p = findnode (rcs->versions, rcs->head);
+       if (p)
+       {
+           RCSVers *next = NULL;
+           while (p != NULL)
+           {
+               vers = next;
+               next = p->data;
+               if (next && STREQ (next->version, rev))
+                   break;
+                  
+               /* if there is a next version, find the node */
+               if (next->next != NULL)
+                   p = findnode (rcs->versions, next->next);
+               else
+                   break;
+           }
+       }
+    }
+    if (p && vers)
+       return xstrdup (vers->version);
+
+    return NULL;
+}
+
+
+
+/*
+ * Find the root revision, which is the first revision
+ * on either the trunk or the branch that rev lives on.
+ */
+static char *
+RCS_getroot (RCSNode *rcs, const char * rev)
+{
+    char *retval = NULL;
+    int dots = numdots (rev);
+
+    if (dots > 1)
+    {
+        int i;
+        const char *p = rev;
+       for (i = 1; i < dots; ++i)
+            p = strchr (p+1, '.');
+       assert (p);
+       if (!strncmp (p, ".0.", 3))
+       {
+           char *tmp = xstrdup (rev);
+           strcpy (tmp + (p - rev), p + 2);
+           retval = RCS_getbranchpoint (rcs, (char *)tmp);
+           free (tmp);
+       }
+       else
+       {
+           retval = RCS_getbranchpoint (rcs, (char *)rev);
+       }
+    }
+    else if (rcs->head)
+    {
+        Node *p;
+       RCSVers *vers;
+
+       p = findnode (rcs->versions, rcs->head);
+       while (p)
+       {
+           vers = p->data;
+
+           /* if there is a next version, find the node */
+           if (vers->next != NULL)
+               p = findnode (rcs->versions, vers->next);
+           else
+           {
+               retval = xstrdup (vers->version);
+               break;
+           }
+       }
+    }
+
+    return retval;
+}
+
+
+
+/*
+ * Find the branchpoint, no matter if rev points
+ * to a branch or a revision
+ */
+static char *
+RCS_getorigin (RCSNode *rcs, const char *rev)
+{
+    char *retval = NULL;
+    int dots = numdots (rev);
+    
+    if (dots > 1)
+    {
+        retval = xstrdup (rev);
+        if (dots & 1)
+       {
+           int i;
+           char *p = retval;
+           for (i = 1; i < dots; ++i)
+               p = strchr (p+1, '.');
+           *p = '\0';
+       }
+       else
+       {
+           char *p = strrchr (retval, '.');
+           *p = '\0';
+       }
+    }
+
+    return retval;
+}
+
+
+
+/*
+ * Find the commitid, if prev is true return the
+ * previous revision 
+ */
+static char *
+RCS_getcommitid (RCSNode *rcs, const char *commitid, bool prev)
+{
+    Node *p;
+    RCSVers *oldvers = NULL;
+
+    Node *head = rcs->versions->list;
+    for (p = head->next; p != head; p = p->next)
+    {
+        RCSVers *vers = (RCSVers *)p->data;
+
+       Node *info = findnode (vers->other_delta, "commitid");
+       if (info != NULL)
+           if (!strcmp (info->data, commitid))
+           {
+               RCSVers *newvers = NULL;
+               if (!prev)
+                   return xstrdup (vers->version);
+               if (p->next)
+                   newvers = (RCSVers *)p->next->data;
+               else
+                   newvers = NULL;
+               if (numdots (vers->version)==1)
+                   return newvers ? xstrdup (newvers->version) : NULL;
+               else
+                   return oldvers ? xstrdup (oldvers->version) : NULL;
+           }
+       oldvers = vers;
+    }
+
+    return NULL;
+}
+
+
+
+/* Translate special/symbolic tags into their revision
+ * If tag is numeric, rely on its formating.
+ * If tag is symbolic, resolv it. Then check for
+ * tag extensions. If an extension is found, resolv it.
  * Returns NULL or a newly malloc'd string.
  */
 static char *
-translate_symtag (RCSNode *rcs, const char *tag)
+translate_tag (RCSNode *rcs, const char *tag)
 {
+    char c;
+    char *tmp = NULL;
+    char *retval = NULL;
+    char *tmpval = NULL;
+    bool dotstart = false;
+
     if (rcs->flags & PARTIAL)
        RCS_reparsercsfile (rcs, NULL, NULL);
 
+    if (tag[0] == '@')
+    {
+        /* handle cvsnt compatibility stuff */
+        if ( tag[1] == '<')
+           return RCS_getcommitid (rcs, tag+2, true);
+       else
+           return RCS_getcommitid (rcs, tag+1, false);
+    }
+
+    tmpval = xstrdup (tag);
+    if (isdigit ((unsigned char) *tmpval)) {
+        /* extract initial revision num */
+        char * p = tmpval;
+        do
+           ++p;
+       while (isdigit ((unsigned char) *p) || *p == '.');
+       tmp = p;
+       *(--p) = '\0';
+       retval = xstrdup (tmpval);
+    }
+    else
+        tmp = tmpval;
+
+    char *token = strtok(tmp,".");
+    if (token)
+    {
+        bool force;
+       do
+       {
+           force = false;
+           if (!retval)
+           {
+               if (token == tmp)
+                   retval = translate_symtag (rcs, token);
+               else if (STREQ (token, TAG_TRUNK))
+                   retval = RCS_head (rcs);
+               else if (STREQ (token, TAG_COMMITID))
+               {
+                   char *commitid = commitid = strtok (NULL,".");
+                   if (token = strtok (NULL,"."))
+                       force = true;
+                   if (commitid)
+                   {
+                      bool previous = (token && STREQ (token, TAG_PREVIOUS));
+                      retval = RCS_getcommitid (rcs, commitid, previous);
+                   }
+               }
+               else
+                   error (1, 0, "Tag '%s': invalid head: '%s'", token, tag);
+           }
+           else
+           {
+               char *p = retval;
+               if (STREQ (token, TAG_PREVIOUS))
+                   retval = RCS_getprevious (rcs, p);
+               else if (STREQ (token, TAG_ORIGIN))
+                   retval = RCS_getorigin (rcs, p);
+               else if (STREQ (token, TAG_ROOT))
+                   retval = RCS_getroot (rcs, p);
+               else if (STREQ (token, TAG_NEXT))
+                   retval = RCS_getnext (rcs, p);
+               else
+                   error (1, 0, "Tag '%s': invalid extension: '%s'", token, 
tag);
+               free (p);
+           }
+       }
+       while (force || (retval && (token = strtok (NULL, "."))) );
+    }
+    free (tmpval);
+
+    return retval;
+}
+
+
+
+/*
+ * Return the version associated with a particular symbolic tag.
+ * Returns NULL or a newly malloc'd string.
+ */
+static char *
+translate_symtag (RCSNode *rcs, const char *tag)
+{
     if (rcs->symbols != NULL)
     {
        Node *p;
@@ -3331,6 +3685,142 @@
 
 
 /*
+ * Do some consistency checks ...
+ * If a symbolic tag is found, return a newly allocated string
+ * Allow only:
+ * SYMTAG | SYMTAG[.prev]* | .trunk[.prev]* | HEAD | BASE | x.x.x[.prev]*
+ *
+ * ERRORS
+ *   fatal errors are generated for illegal syntax
+ */
+char *
+RCS_extract_tag (const char *tag)
+{
+    char *retval = NULL;
+    const char *p = tag;
+    bool first = true;
+
+    assert(p);
+
+    if (*p == '@')
+    {
+        if (*(p+1) == '<')
+       {
+           retval = xstrdup (p+1);
+           *retval = '@';
+       }
+       else
+           retval = xstrdup (p);
+       return retval;
+    }
+    else
+        p = tag;
+
+    if (strstr (p,".."))
+        error (1, 0, "\
+Numeric tag %s invalid.  Numeric tags should be of the form X[.X]...", tag);
+
+    bool dot = false;
+    while (p)
+    {
+        if (*p == '.')
+           dot = true;
+        else if (!isdigit ((unsigned char) *p))
+           break;
+       else if (dot && first)
+           error (1, 0, "\
+Numeric tag '%s' invalid. Numeric tags should be of the form X[.X]...", tag);
+       else
+       {
+           dot = false;
+           first = false;
+       }
+       ++p;
+    }
+
+    if ( (*p && !first && !dot) || tag[strlen (tag)-1] == '.')
+        error (1, 0, "\
+Tag '%s' is invalid. Combined tags should be of the form X[.X]...", tag);
+
+    /* handle HEAD and BASE */
+    if (first
+         && (STREQ (tag, TAG_HEAD)
+               || (STREQ (tag, TAG_BASE)) ))
+       return NULL;
+
+    bool root = false;
+    char *tmp = xstrdup (p);
+    char *token = strtok(tmp,".");
+    if (token)
+    {
+       
+       do
+       {
+           if (first)
+           {
+               if (!dot)
+               {
+                   if (!STREQ (token, TAG_TRUNK)
+                       && !STREQ (token, TAG_COMMITID)
+                       && !STREQ (token, TAG_PREVIOUS)
+                       && !STREQ (token, TAG_NEXT)
+                       && !STREQ (token, TAG_ORIGIN))
+                   {
+                      RCS_check_tag (token);
+                      retval = xstrdup (token);
+                      first = false;
+                   }
+                   else
+                       error (1, 0,"\
+Tag '%s' invalid. Reserved expression without leading dot: '%s'", tag, token);
+               }
+               else if (STREQ (token, TAG_TRUNK))
+                   first = false;
+               else if (STREQ (token, TAG_COMMITID))
+               {
+                   token = strtok (NULL,".");
+                   if (token)
+                   {
+                       retval = Xasprintf ("@%s",token);
+                       first = false;
+                   }
+               }
+               else if (isdigit ((unsigned char) *token))
+                   error (1, 0, "\
+Tag '%s' invalid: Numeric tags must be placed at the begining: '.%s'", tag, 
token);
+               else
+                   error (1, 0,"\
+Tag '%s' invalid. Cannot resolve head: '.%s'", tag, token);
+           }
+           else
+           {
+               if (!root && STREQ (token, TAG_ROOT))
+               {
+                   root = true;
+                   first = false;
+               }
+               else if ((STREQ (token, TAG_PREVIOUS))
+                        || (STREQ (token, TAG_NEXT))
+                        || (STREQ (token, TAG_ORIGIN)))
+               {
+                   root = false;
+                   first = false;
+               }
+               else
+                   error (1, 0,"\
+Tag '%s' invalid. Cannot resolve extension: '%s'", tag, token);
+           }
+       }
+       while (!first && (token = strtok (NULL, ".")) );
+    }
+    free (tmp);
+
+    return retval;
+}
+
+
+
+/*
  * TRUE if argument has valid syntax for an RCS revision or 
  * branch number.  All characters must be digits or dots, first 
  * and last characters must be digits, and no two consecutive 
Index: src/rcs.h
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/rcs.h,v
retrieving revision 1.1.1.1
retrieving revision 1.4
diff -u -r1.1.1.1 -r1.4
--- src/rcs.h   27 Feb 2005 15:02:24 -0000      1.1.1.1
+++ src/rcs.h   28 Feb 2005 03:24:21 -0000      1.4
@@ -215,6 +215,7 @@
 time_t RCS_getrevtime (RCSNode * rcs, const char *rev, char *date, int fudge);
 List *RCS_symbols (RCSNode *rcs);
 void RCS_check_tag (const char *tag);
+char *RCS_extract_tag (const char *tag);
 int RCS_valid_rev (const char *rev);
 List *RCS_getlocks (RCSNode *rcs);
 void freercsnode (RCSNode ** rnodep);
Index: src/sanity.sh
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/sanity.sh,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- src/sanity.sh       27 Feb 2005 15:02:24 -0000      1.1.1.1
+++ src/sanity.sh       2 Mar 2005 02:04:22 -0000       1.2
@@ -26139,7 +26139,7 @@
          #
          dotest_fail admin-28-4 "${testcvs} admin -ntagnine:1.a.2 file2"  \
 "RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
-${SPROG} \[admin aborted\]: tag .1\.a\.2. must start with a letter"
+${SPROG} \[admin aborted\]: Tag .1\.a\.2. invalid. Cannot resolve extension: 
'a'"
 
          # Confirm that a missing tag is not a fatal error.
          dotest admin-28-5.1 "${testcvs} -Q tag BO+GUS file1" ''
Index: src/subr.c
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/subr.c,v
retrieving revision 1.1.1.2
retrieving revision 1.4
diff -u -r1.1.1.2 -r1.4
--- src/subr.c  2 Mar 2005 01:36:28 -0000       1.1.1.2
+++ src/subr.c  2 Mar 2005 01:40:09 -0000       1.4
@@ -217,6 +217,32 @@
 
 
 
+/*
+ * Returns 1 if this is a plain revision number without extensions
+ * A plain rev num never has a dot followed by an alpha 
+ */
+int
+isrevnumonly (const char *s)
+{
+    if (!isdigit ((unsigned char) *s))
+    {
+        return 0;
+    }
+    else
+    {
+        const char * c = s+1;
+       while (c = strchr (c,'.'))
+        {
+           ++c;
+           if (*c && isalpha ((unsigned char) *c))
+               return 0;
+       }
+    }
+    return 1;
+}
+
+
+
 /* Compare revision numbers REV1 and REV2 by consecutive fields.
    Return negative, zero, or positive in the manner of strcmp.  The
    two revision numbers must have the same number of fields, or else
Index: src/subr.h
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/subr.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- src/subr.h  27 Feb 2005 15:02:24 -0000      1.1.1.1
+++ src/subr.h  27 Feb 2005 15:10:03 -0000      1.2
@@ -26,6 +26,7 @@
 void free_names (int *pargc, char *argv[]);
 void line2argv (int *pargc, char ***argv, char *line, char *sepchars);
 int numdots (const char *s);
+int isrevnumonly (const char *s);
 int compare_revnums (const char *, const char *);
 char *increment_revnum (const char *);
 char *getcaller (void);
Index: src/tag.c
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/tag.c,v
retrieving revision 1.1.1.1
retrieving revision 1.5
diff -u -r1.1.1.1 -r1.5
--- src/tag.c   27 Feb 2005 15:02:24 -0000      1.1.1.1
+++ src/tag.c   1 Mar 2005 12:41:19 -0000       1.5
@@ -1442,11 +1442,12 @@
  *   Nothing.
  */
 void
-tag_check_valid (const char *name, int argc, char **argv, int local, int aflag,
+tag_check_valid (const char *oriname, int argc, char **argv, int local, int 
aflag,
                  char *repository, bool valid)
 {
     DBM *db;
     char *valtags_filename;
+    char *name;
     int nowrite = 0;
     datum mytag, val;
     struct val_args the_val_args;
@@ -1457,43 +1458,25 @@
     TRACE (TRACE_FUNCTION,
           "tag_check_valid (name=%s, argc=%d, argv=%p, local=%d,\n"
       "                      aflag=%d, repository=%s, valid=%s)",
-          name ? name : "(name)", argc, (void *)argv, local, aflag,
+          oriname ? oriname : "(name)", argc, (void *)argv, local, aflag,
           repository ? repository : "(null)",
           valid ? "true" : "false");
 #else
     TRACE (TRACE_FUNCTION,
           "tag_check_valid (name=%s, argc=%d, argv=%lx, local=%d,\n"
       "                      aflag=%d, repository=%s, valid=%s)",
-          name ? name : "(name)", argc, (unsigned long)argv, local, aflag,
+          oriname ? oriname : "(name)", argc, (unsigned long)argv, local, 
aflag,
           repository ? repository : "(null)",
           valid ? "true" : "false");
 #endif
 
-    /* Numeric tags require only a syntactic check.  */
-    if (isdigit ((unsigned char) name[0]))
+    /* validate tag and return symbolic tag if any */
+    if (!(name = RCS_extract_tag (oriname)))
     {
-       /* insert is not possible for numeric revisions */
-       assert (!valid);
-       if (RCS_valid_rev (name)) return;
-       else
-           error (1, 0, "\
-Numeric tag %s invalid.  Numeric tags should be of the form X[.X]...", name);
-    }
-
-    /* Special tags are always valid.  */
-    if (strcmp (name, TAG_BASE) == 0
-       || strcmp (name, TAG_HEAD) == 0)
-    {
-       /* insert is not possible for numeric revisions */
        assert (!valid);
        return;
     }
 
-    /* Verify that the tag is valid syntactically.  Some later code once made
-     * assumptions about this.
-     */
-    RCS_check_tag (name);
-
     /* FIXME: This routine doesn't seem to do any locking whatsoever
        (and it is called from places which don't have locks in place).
        If two processes try to write val-tags at the same time, it would
@@ -1530,6 +1513,7 @@
             */
            dbm_close (db);
            free (valtags_filename);
+           free (name);
            return;
        }
        /* FIXME: should check errors somehow (add dbm_error to myndbm.c?).  */
@@ -1579,6 +1563,7 @@
        if (db != NULL)
            dbm_close (db);
        free (valtags_filename);
+       free (name);
        return;
     }
 
@@ -1593,6 +1578,7 @@
        {
            error (0, errno, "warning: cannot create %s", valtags_filename);
            free (valtags_filename);
+           free (name);
            return;
        }
     }
@@ -1604,4 +1590,5 @@
     dbm_close (db);
     free (mytag.dptr);
     free (valtags_filename);
+    free (name);
 }

Have fun
Frank
-- 
- The LinCVS Team -
http:/www.lincvs.com





reply via email to

[Prev in Thread] Current Thread [Next in Thread]