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: Fri, 11 Mar 2005 03:29:43 +0100
User-agent: KMail/1.5.1

On Thursday 10 March 2005 19:56, Derek Price wrote:
> Frank Hemer wrote:
> | Hold on ... it seems I have found a workaround for this:
> |
> | /* If a file was added on the trunk, and it is added on * a branch
> | in a second step, the '1.1.2.1' revision is * dead, and timestamp
> | of 1.1 and 1.1.2.1 are equal. * Prevent returning this as root! */
>
> Hrm.  Yes, I think you have it, in about as backwards compatible a
> manner as possible (this will cause .root to work consistently for any
> branch if a is file added to a branch with a server with this
> change).  It won't retroactively fix old branches to work with .root,
> but that's not possible to automate since the information just plain
> isn't available in the archive files.
>
> The only other potential insertion that might work that I can think
> of, would be to try and insert a dead 1.0 revision for all files and
> branch off that, but that would require more research to see how many
> assumptions were violated in the CVS source.  Of course, I can think
> of no additional advantages of this solution, even if it turned out to
> work, other than allowing a standard "base" revision for files added
> on branches, which I only see as useful to humans gleaning info by
> perusing status messages and logs.  I see little reason to prefer it.

Well, I think it would be a good idea to add the same behavoir (as adding
on an existing branch) to the import feature. If vendor importing on several
vendor branches (1.1.1, 1.1.2, 1.1.3), there is no dead revision introduced.
However I think this is sth. thats very rarely used -

> So anyway, I think I would be happy with the solution you suggest,
> without further research.

:-)
Patch follows

> | The revision numbers do not necessarily have to be those in the
> | above example:-)
> |
> | Btw. the problem of .commitid.next and alike is already solved ...
>
> I was simply wondering because you specified that .prev and .next
> could only be applied to one file at a time.

That was a misunderstanding;-)
I had limited it to _several_ files, because initialy there were problems with
the dirtag. This is set before vers_ts.c comes into action, so I was trying to
prevent interference of the already changed dirtag when calculating the
absolute revisions.

However, I have changed this and hopefully this works now as expected.
The '.root' returns a dead revision when first added on a branch. And I tried
it with several variants of vendor tags at a time, still there are so many
different ways I will not be able to try them all ...

> Also, .commitid.next as currently defined should be nonsense in almost
> all cases.  Only .commitid & .commitid.prev are meaningful.

Thats right. However it would require extra code to prevent this, and I don't
really think this will cause problems. I assume a user who is willing to type
such a number probably knows what he's doing?;-)

As an extension to my doc:
If no files are specified (recursive calls or calls on a flat dir),
all combined tags need to be absolute. '.base.next' is invalid here, because
it depends on the specific file's rev number and subconsequently cannot
serve as a dirtag (on commands like update ...). '.trunk.prev' would be ok here.
So if applied on directories, a tag needs to start with either a numeric rev. 
num,
'.trunk', '.commitid' or a symbolic tag.

Now the patch, I'll care for doc and stuff next week - no more time right now.
Still it would be good if someone else would try out my hack -

>>>>>>>>>>>>>>>>>>>> patch >>>>>>>>>>>>>>>>>>>>

Index: src/admin.c
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/admin.c,v
retrieving revision 1.1.1.3
retrieving revision 1.2
diff -b -B -u -r1.1.1.3 -r1.2
--- src/admin.c 8 Mar 2005 01:18:17 -0000       1.1.1.3
+++ src/admin.c 8 Mar 2005 19:37:41 -0000       1.2
@@ -655,6 +655,10 @@
        char *branch = &admin_data->branch[2];
        if (*branch != '\0' && ! isdigit ((unsigned char) *branch))
        {
+           if (*branch == '.' && !strcmp (branch+1, TAG_TRUNK))
+               branch = NULL;
+           else
+           {
            branch = RCS_whatbranch (rcs, admin_data->branch + 2);
            if (branch == NULL)
            {
@@ -663,6 +667,7 @@
                status = 1;
            }
        }
+       }
        if (status == 0)
            RCS_setbranch (rcs, branch);
        if (branch != NULL && branch != &admin_data->branch[2])
Index: src/commit.c
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/commit.c,v
retrieving revision 1.1.1.4
retrieving revision 1.8
diff -b -B -u -r1.1.1.4 -r1.8
--- src/commit.c        11 Mar 2005 02:22:47 -0000      1.1.1.4
+++ src/commit.c        11 Mar 2005 02:24:16 -0000      1.8
@@ -700,6 +700,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
@@ -886,8 +890,10 @@
                           finfo->fullname);
                    goto out;
                }
-               if (status == T_MODIFIED && vers->tag &&
-                   !RCS_isbranch (finfo->rcs, vers->tag))
+               if (status == T_MODIFIED && vers->tag)
+               {
+                  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",
@@ -895,6 +901,7 @@
                    goto out;
                }
            }
+           }
            if (status == T_MODIFIED && !force_ci && vers->ts_conflict)
            {
                /*
@@ -1350,6 +1357,7 @@
     {
        char *rev = RCS_getversion (finfo->rcs, write_dirtag, NULL, 1, NULL);
        if (rev != NULL
+           && !(*write_dirtag == '.' && !strcmp (write_dirtag+1, TAG_TRUNK))
            && !RCS_nodeisbranch (finfo->rcs, write_dirtag))
            write_dirnonbranch = 1;
        if (rev != NULL)
@@ -1407,6 +1415,16 @@
     }
     else if (ci->status == T_ADDED)
     {
+
+        /* prevent adding files to a branch named TAG_TRUNK as this
+        * is a synonym for the trunk itself
+        */
+        if (ci->tag && *ci->tag == '.' && !strcmp (ci->tag + 1, TAG_TRUNK))
+       {
+           free (ci->tag);
+           ci->tag = NULL;
+       }
+
        if (checkaddfile (finfo->file, finfo->repository, ci->tag, ci->options,
                          &finfo->rcs) != 0)
        {
Index: src/cvs.h
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/cvs.h,v
retrieving revision 1.1.1.1
retrieving revision 1.6
diff -b -B -u -r1.1.1.1 -r1.6
--- src/cvs.h   27 Feb 2005 15:02:24 -0000      1.1.1.1
+++ src/cvs.h   8 Mar 2005 01:14:59 -0000       1.6
@@ -242,6 +242,14 @@
  */
 #define        TAG_HEAD        "HEAD"
 #define        TAG_BASE        "BASE"
+#define TAG_DOTHEAD     "head"
+#define TAG_DOTBASE     "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.3
retrieving revision 1.6
diff -b -B -u -r1.1.1.3 -r1.6
--- src/import.c        11 Mar 2005 02:22:48 -0000      1.1.1.3
+++ src/import.c        11 Mar 2005 02:24:16 -0000      1.6
@@ -441,6 +441,10 @@
        error (0, errno, "cannot remove %s", tmpfile);
     free (tmpfile);
 
+    char *commitid = Xasprintf ("@%s", global_session_id);
+    tag_check_valid (commitid, argc, argv, 0, 1, "", 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.5
retrieving revision 1.31
diff -b -B -u -r1.1.1.5 -r1.31
--- src/rcs.c   10 Mar 2005 12:14:01 -0000      1.1.1.5
+++ src/rcs.c   11 Mar 2005 01:31:10 -0000      1.31
@@ -69,6 +69,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,
@@ -98,6 +100,13 @@
 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 *RCS_gethead (RCSNode *, const char *);
+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 *);
@@ -2153,6 +2162,12 @@
     {
        char *branch, *rev;
 
+       if (*tag == '.' && !strcmp (tag+1, TAG_TRUNK))
+       {
+           return RCS_getdatetrunk (rcs, date, force_tag_match);
+       }
+       else
+       {
        if (! RCS_nodeisbranch (rcs, tag))
        {
            /* We can't get a particular date if the tag is not a
@@ -2171,6 +2186,7 @@
        free (branch);
        return rev;
     }
+    }
     else if (tag)
        return RCS_gettag (rcs, tag, force_tag_match, simple_tag);
     else if (date)
@@ -2190,6 +2206,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.
  */
@@ -2255,15 +2273,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, true);
+    if (tmp)
+        free (tmp);
+    rev = translate_tag (rcs, tag);
 
     if (rev)
         return rev;
@@ -2309,12 +2327,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;
@@ -2544,10 +2562,10 @@
     assert (rcs != NULL);
 
     /* numeric revisions are easy -- even number of dots is a branch */
-    if (isdigit ((unsigned char) *rev))
+    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);
@@ -2598,7 +2616,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);
@@ -2769,11 +2787,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;
     }
@@ -2913,7 +2931,29 @@
            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->flags & PARTIAL)
+        RCS_reparsercsfile (rcs, NULL, NULL);
+
     if (rcs->head)
     {
        p = findnode (rcs->versions, rcs->head);
@@ -2928,7 +2968,7 @@
            vers = p->data;
            if (RCS_datecmp (vers->date, date) <= 0)
            {
-               cur_rev = vers->version;
+                retval = vers->version;
                break;
            }
 
@@ -2949,10 +2989,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
@@ -2969,7 +3009,6 @@
        }
     }
 
-    /* look on the vendor branch */
     retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
 
     /*
@@ -3206,15 +3245,680 @@
 
 
 /*
- * 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 = NULL;
+    int dots = numdots (rev);
+
+    if (!dots)
+        return NULL;
+
+    char *tmp = xstrdup (rev);
+    char *trev = NULL;
+
+    /* remove ev. magic branch num */
+    if (dots > 2 && (dots & 1))
+    {
+        int i;
+        const char *p = rev;
+        for (i = 1; i < dots; ++i)
+            p = strchr (p+1, '.');
+        if (!strncmp (p, ".0.", 3))
+        {
+            strcpy (tmp + (p - rev), p + 2);
+           --dots;
+        }
+    }
+
+    if (!(dots & 1)) /* branch handling => turn into a head revision */
+    {
+        char *p = RCS_branch_head (rcs, tmp);
+       if (p)
+           trev = p;
+       else
+       {
+           /* branch tag without any revisions ... */
+           trev = xstrdup (tmp);
+           *strrchr (trev, '.') = '\0';
+       }
+       dots = numdots (trev);
+    }
+    else
+        trev = xstrdup (tmp);
+
+    if (dots > 1) /* revision on a branch */
+    {
+        if (rcs->flags & PARTIAL)
+           RCS_reparsercsfile (rcs, NULL, NULL);
+
+        /* find the root revision */
+        *strrchr (trev, '.') = '\0';
+       int len = strlen (trev);
+        *strrchr (trev, '.') = '\0';
+
+        RCSVers *vers = NULL;
+        Node *node = findnode (rcs->versions, trev);
+        if (node && (vers = node->data) && vers->branches)
+       {
+          char *rootdate = vers->date;
+           Node *head = vers->branches->list;
+           Node *br;
+           for (br = head->next; br != head; br = br->next)
+           {
+               if (node = findnode (rcs->versions, br->key))
+               {
+                   if (strncmp (((RCSVers *)node->data)->version, tmp, len))
+                       continue;
+                      
+                   ++len;
+                   char *p = NULL;
+                   while (node != NULL)
+                   {
+                       vers = node->data;
+                       if (STREQ (vers->version + len, tmp + len))
+                       {
+                           if (p)
+                               retval = xstrdup (p);
+                           else if (RCS_datecmp (vers->date, rootdate))
+                               retval = xstrdup (trev);
+                           break;
+                       }
+
+                       /* if there is a next version, find the node */
+                       if (vers->next != NULL)
+                       {
+                           p = vers->version;
+                           node = findnode (rcs->versions, vers->next);
+                       }
+                       else
+                           node = NULL;
+                   }
+               }
+           }
+       }
+    }
+    else /* revision on trunk */
+    {
+        char *prev = NULL;
+       char *curdate = NULL;
+
+       assert (dots == 1);
+
+       if (rcs->flags & PARTIAL)
+           RCS_reparsercsfile (rcs, NULL, NULL);
+
+        if (!STREQ (trev, "1.1"))
+       {
+            Node *node = findnode (rcs->versions, trev);
+           if (node)
+           {
+               RCSVers *v = node->data;
+               curdate = v->date;
+               if (v->next && (node = findnode (rcs->versions, v->next)))
+               {
+                   free (trev);
+                   prev = ((RCSVers *)node->data)->version;
+                   trev = xstrdup (prev);
+               }
+           }
+        }
+
+        if (prev && STREQ (trev, "1.1"))
+        {
+            /* This is 1.1;  if the date of 1.1 is the same as that for
+            * the VENDOR.1 version, then return the VENDOR version with
+            * a timestamp before the 1.2 timestamp (point of merge). The
+            * date of 1.1. and VENDOR.1 differs if the first version of
+            * a file is created by a regular cvs add and commit, and there
+            * is a subsequent cvs import of the same file ==> return 1.1.
+            * If 1.1 is dead, the file was initially added on a branch
+            * ==> return NULL.
+            */
+           Node *rootnode = findnode (rcs->versions, trev);
+           if (rootnode)
+           {
+               RCSVers *vers = rootnode->data;
+               if (!vers->dead && vers->branches)
+               {
+                   char *date_1_1 = vers->date;//vers 1.1
+
+                   Node *head = vers->branches->list;
+                   Node *br;
+                   for (br = head->next; br != head; br = br->next)
+                   {
+                       Node *node = NULL;
+                       if (node = findnode (rcs->versions, br->key))
+                       {
+                           vers = node->data;
+                           if (!RCS_datecmp (vers->date, date_1_1))
+                           {
+                               /* get head of branch */
+                               retval = vers->version;
+                               while (vers->next)
+                               {
+                                   node = findnode (rcs->versions, vers->next);
+                                   if (node)
+                                   {
+                                       vers = node->data;
+                                       if (RCS_datecmp (curdate, vers->date) > 
0)
+                                       {
+                                           vers = node->data;
+                                           retval = vers->version;
+                                           continue;
+                                       }
+                                   }
+                                   break;
+                               }
+                               retval = xstrdup (retval);
+                           }
+                       }
+                   }
+               }
+           }
+        }
+       if (!retval && prev)
+           retval = xstrdup (prev);
+    }
+    free (tmp);
+    free (trev);
+
+    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 *node = NULL;
+    RCSVers *vers = NULL;
+    char *retval = NULL;
+    const char *cmp = rev;
+    int dots = numdots (rev);
+
+    if (rcs->flags & PARTIAL)
+       RCS_reparsercsfile (rcs, NULL, NULL);
+
+    if (dots > 1)
+    {
+        node = findnode (rcs->versions, rev);
+       if (!node)
+           return NULL;
+
+       vers = node->data;
+
+       /* if there is a next version, find the node */
+       if (vers->next != NULL)
+       {
+           node = findnode (rcs->versions, vers->next);
+           if (node)
+               return xstrdup (((RCSVers *)node->data)->version);
+       }
+    }
+    else if (rcs->head)
+    {
+       node = findnode (rcs->versions, rcs->head);
+       if (node)
+       {
+           RCSVers *next = NULL;
+           vers = NULL;
+           while (node != NULL)
+           {
+               vers = next;
+               next = node->data;
+               if (next && STREQ (next->version, cmp))
+               {
+                   if (vers)
+                       retval = xstrdup (vers->version);
+                   break;
+               }
+                  
+               /* if there is a next version, find the node */
+               if (next->next != NULL)
+                   node = findnode (rcs->versions, next->next);
+               else
+                   node = NULL;
+           }
+       }
+    }
+
+    return retval;
+}
+
+
+
+/*
+ * Find the origin revision, which is the first revision
+ * on either the trunk or a branch if added there.
+ */
+static char *
+RCS_getorigin (RCSNode *rcs, const char * rev)
+{
+    char *workrev = xstrdup (rev);
+
+    if (RCS_exist_rev (rcs, workrev))
+    {
+       Node *rootnode = NULL;
+        int dots = numdots (workrev);
+
+       if (dots > 2)
+       {
+           int i;
+           char *p = workrev;
+           for (i = 1; i < dots; ++i)
+               p = strchr (p+1, '.');
+           if (!strncmp (p, ".0.", 3))
+           {
+               memmove (p, p+2, strlen (p+2) + 1);
+               --dots;
+           }
+       }
+       
+       while (dots > 1)
+       {
+          int len;
+          char *tmp = workrev;
+          workrev = xstrdup (tmp);
+
+          if (dots & 1)
+          {
+              *strrchr (workrev, '.') = '\0';
+              len = strlen (workrev);
+              *strrchr (workrev, '.') = '\0';
+          }
+          else
+          {
+              len = strlen (workrev);
+              *strrchr (workrev, '.') = '\0';
+          }
+
+          /* If a file was added on the trunk, and it is added on
+           * a branch in a second step, the '1.1.2.1' revision is
+           * dead, and timestamp of 1.1 and 1.1.2.1 are equal.
+           * Prevent returning this as root!
+           */
+          bool found = false;
+          rootnode = findnode(rcs->versions, workrev);
+          if (rootnode)
+          {
+              RCSVers *vers = rootnode->data;
+              if (vers->branches)
+              {
+                  Node *head = vers->branches->list;
+                  Node *br;
+                  for (br = head->next; br != head; br = br->next)
+                  {
+                     /* check if br->key is on branch rev */
+                     if (!strncmp (tmp, br->key, len))
+                     {
+                         Node *bn = NULL;
+                         if (bn = findnode (rcs->versions, br->key))
+                         {
+                             RCSVers *cv = bn->data;
+                             if (cv->dead)
+                             {
+                                if (cv->next)
+                                {
+                                    free (workrev);
+                                    if (STREQ (cv->version, rev))
+                                        workrev = xstrdup (rev);
+                                    else
+                                    {
+                                        bn = findnode (rcs->versions, 
cv->next);
+                                        cv = bn->data;
+                                        workrev = xstrdup (cv->version);
+                                    }
+                                    found = true;
+                                }
+                                else
+                                {
+                                    free (workrev);
+                                    workrev = NULL;
+                                }
+                             }
+                             else if (vers->dead)
+                             {
+                                /* root dead => stay on branch */
+                                free (workrev);
+                                workrev = xstrdup (cv->version);
+                                found = true;
+                             }
+                         }
+                     }
+                  }
+              }
+          }
+          if (found || !workrev)
+              return workrev;
+          else
+              dots = numdots (workrev);
+          free (tmp);
+       }
+
+       RCSVers *vers;
+       char *prev = NULL;
+
+       if (!rootnode)
+           rootnode = findnode (rcs->versions, workrev);
+       free (workrev);
+
+       while (rootnode)
+       {
+           vers = rootnode->data;
+
+           /* if there is a next version, find the node */
+           if (vers->next != NULL)
+           {
+               prev = vers->version;
+               rootnode = findnode (rcs->versions, vers->next);
+           }
+           else if (vers->dead)
+               return xstrdup (prev);
+           else
+               return xstrdup (vers->version);
+       }
+    }
+    free (workrev);
+    return NULL;
+}
+
+
+
+/*
+ * Find the branchpoint, no matter if rev points
+ * to a branch or a revision
+ */
+static char *
+RCS_getroot (RCSNode *rcs, const char *rev)
+{
+    char *retval = NULL;
+    RCSVers *vers = NULL;
+    int dots = numdots (rev);
+    
+    if (dots > 1)
+    {
+        int len;
+        char *tmp = xstrdup (rev);
+
+       /* remove ev. magic branch num */
+       if (dots > 2 && (dots & 1))
+       {
+           int i;
+           const char *p = rev;
+           for (i = 1; i < dots; ++i)
+               p = strchr (p+1, '.');
+           if (!strncmp (p, ".0.", 3))
+           {
+               strcpy (tmp + (p - rev), p + 2);
+               --dots;
+           }
+       }
+       retval = xstrdup (tmp);
+
+        if (dots & 1)
+       {
+           *strrchr (retval, '.') = '\0';
+           len = strlen (retval);
+           *strrchr (retval, '.') = '\0';
+       }
+       else
+       {
+           len = strlen (retval);
+           *strrchr (retval, '.') = '\0';
+       }
+
+       /* If a file was added on the trunk, and it is added on
+        * a branch in a second step, the '1.1.2.1' revision is
+        * dead, and timestamp of 1.1 and 1.1.2.1 are equal.
+        * Return 1.1.2.1 in this case!
+        */
+       if (rcs->flags & PARTIAL)
+           RCS_reparsercsfile (rcs, NULL, NULL);
+
+       Node *node = findnode(rcs->versions, retval);
+       if (node)
+       {
+           vers = node->data;
+           if (vers->branches)
+           {
+               char *rootdate = vers->date;
+               Node *head = vers->branches->list;
+               Node *br;
+               for (br = head->next; br != head; br = br->next)
+               {
+                  //check if br->key is on branch rev
+                  if (!strncmp (tmp, br->key, len))
+                  {
+                      if (node = findnode (rcs->versions, br->key))
+                      {
+                          vers = node->data;
+                          if (vers->dead && !RCS_datecmp (rootdate, 
vers->date))
+                          {
+                              free (retval);
+                              free (tmp);
+                              if (STREQ (vers->version, rev))
+                                  return NULL;
+                              else
+                                  return xstrdup (vers->version);
+                          }
+                      }
+                      free (tmp);
+                      return retval;
+                  }
+               }
+           }
+       }
+       free (tmp);
+       free (retval);
+    }
+    return NULL;
+}
+
+
+
+/*
+ * 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;
+
+    if (rcs->flags & PARTIAL)
+        RCS_reparsercsfile (rcs, NULL, 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;
+}
+
+
+
+/*
+ * Find the head of branch of current revision
+ */
+static char *
+RCS_gethead (RCSNode *rcs, const char *rev)
+{
+    char *retval = NULL;
+    int dots = numdots (rev);
+    if (!dots)
+        return NULL;
+
+    char *tmp = xstrdup (rev);
+
+    /* remove ev. magic branch num */
+    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 (tmp + (p - rev), p + 2);
+           --dots;
+        }
+    }
+
+    if (dots > 1)
+    {
+        if (dots & 1)
+           *(strrchr (tmp, '.')) = '\0';
+       retval = RCS_branch_head (rcs, tmp);
+    }
+    else
+        retval = xstrdup (rcs->head);
+    free (tmp);
+
+    return retval;
+}
+
+
+
+/* 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 = strtok (NULL,".");
+                   if (token = strtok (NULL,"."))
+                      force = true;
+                   if (commitid)
+                   {
+                      bool previous = (token && STREQ (token, TAG_PREVIOUS));
+                      retval = RCS_getcommitid (rcs, commitid, previous);
+                      if (previous || !retval)
+                          force = false;
+                   }
+               }
+               else
+                   error (1, 0, "Tag '%s': invalid head: '%s'", token, tag);
+           }
+           else
+           {
+               char *p = retval;
+               if (STREQ (token, TAG_DOTHEAD))
+                   retval = RCS_gethead (rcs, p);
+               else 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;
@@ -3359,6 +4063,156 @@
 
 
 /*
+ * 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, bool files)
+{
+    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;
+
+    char *prev = NULL;
+    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_DOTHEAD)
+                       && !STREQ (token, TAG_DOTBASE)
+                       && !STREQ (token, TAG_ORIGIN)
+                       && !STREQ (token, TAG_ROOT))
+                   {
+                      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 (!files)
+                   error (1, 0,"\
+Tag '%s' invalid. Tag must not be relative: '.%s'", tag, token);
+               else if (STREQ (token, TAG_ORIGIN)
+                        || STREQ (token, TAG_DOTHEAD))
+               {
+                  first = false;
+                  prev = token;
+               }
+               else if (STREQ (token, TAG_PREVIOUS)
+                        || STREQ (token, TAG_NEXT)
+                        || STREQ (token, TAG_DOTBASE)
+                        || STREQ (token, TAG_ROOT))
+               {
+                  first = false;
+               }
+               else
+                   error (1, 0,"\
+Tag '%s' invalid. Cannot resolve head: '.%s'", tag, token);
+           }
+           else if (STREQ (token, TAG_ORIGIN)
+                    || STREQ (token, TAG_DOTHEAD))
+           {
+               if (!prev || !STREQ (prev, token))
+                   prev = token;
+               else
+                   error (1, 0,"\
+Tag '%s' invalid. Duplicate extension: '%s'", tag, token);
+
+           }
+           else if ((!STREQ (token, TAG_PREVIOUS))
+                     && (!STREQ (token, TAG_NEXT))
+                     && (!STREQ (token, TAG_ROOT)))
+               error (1, 0,"\
+Tag '%s' invalid. Cannot resolve extension: '%s'", tag, token);
+           else
+               prev = NULL;
+       }
+       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.5
diff -b -B -u -r1.1.1.1 -r1.5
--- src/rcs.h   27 Feb 2005 15:02:24 -0000      1.1.1.1
+++ src/rcs.h   8 Mar 2005 01:15:00 -0000       1.5
@@ -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, bool files);
 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.2
retrieving revision 1.3
diff -b -B -u -r1.1.1.2 -r1.3
--- src/sanity.sh       4 Mar 2005 22:35:02 -0000       1.1.1.2
+++ src/sanity.sh       4 Mar 2005 22:36:19 -0000       1.3
@@ -26166,7 +26166,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 -b -B -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 -b -B -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.7
diff -b -B -u -r1.1.1.1 -r1.7
--- src/tag.c   27 Feb 2005 15:02:24 -0000      1.1.1.1
+++ src/tag.c   8 Mar 2005 13:13:28 -0000       1.7
@@ -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,33 @@
     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 */
+    bool files = (argc > 0);
+    int i;
+    for (i=0; i<argc; ++i)
+       if (isdir (argv[i]))
     {
-       /* 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);
+          files = false;
+          break;
     }
-
-    /* Special tags are always valid.  */
-    if (strcmp (name, TAG_BASE) == 0
-       || strcmp (name, TAG_HEAD) == 0)
+    if (!(name = RCS_extract_tag (oriname, files)))
     {
-       /* 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 +1521,7 @@
             */
            dbm_close (db);
            free (valtags_filename);
+           free (name);
            return;
        }
        /* FIXME: should check errors somehow (add dbm_error to myndbm.c?).  */
@@ -1579,6 +1571,7 @@
        if (db != NULL)
            dbm_close (db);
        free (valtags_filename);
+       free (name);
        return;
     }
 
@@ -1593,6 +1586,7 @@
        {
            error (0, errno, "warning: cannot create %s", valtags_filename);
            free (valtags_filename);
+           free (name);
            return;
        }
     }
@@ -1604,4 +1598,5 @@
     dbm_close (db);
     free (mytag.dptr);
     free (valtags_filename);
+    free (name);
 }
Index: src/update.c
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/update.c,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -b -B -u -r1.1.1.2 -r1.2
--- src/update.c        28 Feb 2005 21:55:36 -0000      1.1.1.2
+++ src/update.c        9 Mar 2005 23:13:51 -0000       1.2
@@ -614,6 +614,7 @@
     {
        char *rev = RCS_getversion (finfo->rcs, tag, NULL, 1, NULL);
        if (rev != NULL
+           && !(*tag == '.' && !strcmp (tag+1, TAG_TRUNK))
            && nonbranch != (nb = !RCS_nodeisbranch (finfo->rcs, tag)))
        {
            if (nonbranch >= 0 && !warned && !quiet)
Index: src/vers_ts.c
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/vers_ts.c,v
retrieving revision 1.1.1.1
retrieving revision 1.6
diff -b -B -u -r1.1.1.1 -r1.6
--- src/vers_ts.c       27 Feb 2005 15:02:24 -0000      1.1.1.1
+++ src/vers_ts.c       10 Mar 2005 01:28:40 -0000      1.6
@@ -46,6 +46,7 @@
     struct stickydirtag *sdtp;
     Entnode *entdata;
     char *rcsexpand = NULL;
+    bool setstickynumtag = false;
 
     /* get a new Vers_TS struct */
     vers_ts = xmalloc (sizeof (Vers_TS));
@@ -159,9 +160,121 @@
      */
     if (tag || date)
     {
+        if (tag)
+       {
+           /* If a relative tag extension is used,
+            * prepend the local revision number, and set setstickynumtag
+            * so the sticky tag gets set to the numeric revision number
+            */
+           int position = 0;
+           bool head = false;
+           bool base = false;
+           bool root = false;
+           bool origin = false;
+           bool relative = true;
+           bool prepversion = false;
+           bool dot = false;
+
+           if (*tag == '.')
+              dot = true;
+
+           char *tmp = xstrdup (tag);
+           char *token = strtok (tmp, ".");
+           while (token)
+           {
+               if (position == 0)
+               {
+                   if (dot)
+                   {
+                       if (!strcmp (token, TAG_ROOT))
+                           root = true;
+                       else if (!strcmp (token, TAG_ORIGIN))
+                           origin = true;
+                       else if (!strcmp (token, TAG_DOTHEAD))
+                           head = true;
+                       else if (!strcmp (token, TAG_DOTBASE))
+                       {
+                           base = true;
+                           relative = false;
+                       }
+                       else if (strcmp (token, TAG_TRUNK)
+                                && strcmp (token, TAG_COMMITID))
+                       {
+                           prepversion = true;
+                           setstickynumtag = true;
+                           break;
+                       }
+                       else
+                           relative = false;
+                   }
+                   else
+                       relative = false;
+               }
+               else if (!isdigit ((unsigned char) *token))
+               {
+                   if (!strcmp (token, TAG_DOTHEAD))
+                       setstickynumtag = false;
+                   else if (!strcmp (token, TAG_PREVIOUS)
+                            || !strcmp (token, TAG_NEXT))
+                       setstickynumtag = true;
+               }
+               token = strtok (NULL, ".");
+               ++position;
+           }
+           free (tmp);
+
+           char *preptag = NULL;
+           if (prepversion)
+               preptag = vers_ts->vn_user;
+           else if (head || root || origin)
+           {
+               if (vers_ts->entdata && vers_ts->entdata->tag)
+                   preptag = vers_ts->entdata->tag;
+               else if (sdtp && !sdtp->aflag && !isdigit (*sdtp->tag))
+                   preptag = sdtp->tag;
+               else
+                   preptag = vers_ts->vn_user;
+           }
+
+           if (preptag)
+           {
+               char *p = NULL;
+           if (origin
+               && (p = strrchr (preptag, '.'))
+               && !strcmp (p+1, TAG_ORIGIN))
+           {
+               tmp = xstrdup (preptag);
+               tmp[p-preptag] = '\0';
+               vers_ts->tag = Xasprintf ("%s%s", tmp, tag);
+               free (tmp);
+           }
+           else if (head
+               && (p = strrchr (preptag, '.'))
+               && !strcmp (p+1, TAG_DOTHEAD))
+           {
+               tmp = xstrdup (preptag);
+               tmp[p-preptag] = '\0';
+               vers_ts->tag = Xasprintf ("%s%s", tmp, tag);
+               free (tmp);
+           }
+           else
+               vers_ts->tag = Xasprintf ("%s%s", preptag, tag);
+           }
+           else if (base && position > 1)
+           {
+               const char *p = strchr (tag+1, '.');
+               vers_ts->tag = Xasprintf ("%s%s", vers_ts->vn_user, p);
+           }
+           else if (relative)
+               vers_ts->tag = Xasprintf (".%s%s", TAG_TRUNK, tag);
+           else
        vers_ts->tag = xstrdup (tag);
+       }
+       if (date)
+       {
        vers_ts->date = xstrdup (date);
     }
+    }
     else if (!vers_ts->entdata && (sdtp && sdtp->aflag == 0))
     {
        if (!vers_ts->tag)
@@ -189,7 +302,10 @@
        /* squirrel away the rcsdata pointer for others */
        vers_ts->srcfile = rcsdata;
 
-       if (vers_ts->tag && strcmp (vers_ts->tag, TAG_BASE) == 0)
+       if (vers_ts->tag
+           && (!strcmp (vers_ts->tag, TAG_BASE)
+               || (*(vers_ts->tag) == '.'
+                   && !strcmp (vers_ts->tag+1, TAG_DOTBASE)) ) )
        {
            vers_ts->vn_rcs = xstrdup (vers_ts->vn_user);
            vers_ts->vn_tag = xstrdup (vers_ts->vn_user);
@@ -207,6 +323,15 @@
                vers_ts->vn_tag = xstrdup (vers_ts->tag);
            else
                vers_ts->vn_tag = xstrdup (vers_ts->vn_rcs);
+
+           if (vers_ts->vn_rcs && setstickynumtag)
+           {
+               /* for some relative tags, the sticky tag
+                * needs to be set to its numeric equivalent
+                */
+               free (vers_ts->tag);
+               vers_ts->tag = xstrdup (vers_ts->vn_rcs);
+           }
        }
 
        /*


<<<<<<<<<<<<<<<<<<<< patch <<<<<<<<<<<<<<<<<<<<

Regards
Frank

-- 
- The LinCVS Team -
http://www.lincvs.com





reply via email to

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