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: Mon, 28 Feb 2005 23:09:48 +0100
User-agent: KMail/1.5.1

> |> Also, commitids should be cached at commit time as well as when
> |> they are found in RCS files.  CVS started doing this on tag
> |> creation for other branches and tags a few releases back  It's
> |> silly to wait for the first update to insert them into val-tags -
> |> it only triggers an unneeded recursive search.


A cannot find any call to tag_check_valid() with the final (valid) flag set to 
true?

> | I saw tag.c::tag_check_valid(). Are there other locations where
> | val-tags entries are added/accessed?
>
> No, that is the only location.  The trick is that you need a call like
> `tag_check_valid ("@commitid", 0, NULL, 0, 0, NULL, true);' in
> commit.c after you are certain that the commitid has been added to at
> least one file.  Should only call it once per commitid too, if possible.


I'll leave this for later ... now it's added like '@xxxx'.

Features:

'.trunk' works like a TRUNK branch

'.prev' can be appended to '.trunk', numeric rev. numbers, symbolic tags and 
commitid's except for 'HEAD' and 'BASE'.
It can be appended several times ...

The '.prev' extension is not possible with 'x.x.x:date' because it would turn 
any branch into a specific revision.
The formating might not stick to the cvs-rulses on some places? If so, I'll fix 
it later.

Here's the patch, I hope I have successfully disabled the linewrapping ...
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


Index: src/cvs.h
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/cvs.h,v
retrieving revision 1.1.1.1
retrieving revision 1.4
diff -u -r1.1.1.1 -r1.4
--- src/cvs.h   27 Feb 2005 15:02:24 -0000      1.1.1.1
+++ src/cvs.h   28 Feb 2005 16:55:03 -0000      1.4
@@ -242,6 +242,9 @@
  */
 #define        TAG_HEAD        "HEAD"
 #define        TAG_BASE        "BASE"
+#define TAG_COMMITID    "commitid"
+#define TAG_PREVIOUS    "prev"
+#define TAG_TRUNK       "trunk"
 
 /* Environment variable used by CVS */
 #define        CVSREAD_ENV     "CVSREAD"       /* make files read-only */
Index: src/rcs.c
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/rcs.c,v
retrieving revision 1.1.1.2
retrieving revision 1.10
diff -u -r1.1.1.2 -r1.10
--- src/rcs.c   28 Feb 2005 21:55:36 -0000      1.1.1.2
+++ src/rcs.c   28 Feb 2005 21:57:57 -0000      1.10
@@ -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,8 @@
 static void free_rcsnode_contents (RCSNode *);
 static void free_rcsvers_contents (RCSVers *);
 static void rcsvers_delproc (Node * p);
+static char *RCS_findcommitid (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 +2130,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);
@@ -2235,8 +2246,8 @@
     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. */
+    rev = translate_tag (rcs, tag);
 
     if (rev)
         return rev;
@@ -2282,12 +2293,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 +2528,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 +2582,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 +2753,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 +2896,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 +2930,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 +2951,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 +2971,6 @@
        }
     }
 
-    /* look on the vendor branch */
     retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
 
     /*
@@ -3178,15 +3207,160 @@
 
 
 /*
- * Return the version associated with a particular symbolic tag.
+ * Find the commitid, if prev is true return the
+ * previous revision 
+ */
+static char *
+RCS_findcommitid (RCSNode *rcs, const char *commitid, bool prev)
+{
+    RCSVers *vers, *oldvers;
+    Node *head, *p, *info;
+
+    head = rcs->versions->list;
+    oldvers = NULL;
+    for (p = head->next; p != head; p = p->next)
+    {
+        vers = (RCSVers *) p->data;
+
+       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;
+    bool dotstart = false;
+    char * retval = NULL;
+    char * tmpval = NULL;
+    char * tmp = NULL;
+
     if (rcs->flags & PARTIAL)
        RCS_reparsercsfile (rcs, NULL, NULL);
 
+    if (tag[0] == '@')
+    {
+        /* handle cvsnt compatibility stuff */
+        if ( tag[1] == '<')
+       {
+           return RCS_findcommitid(rcs, tag+2, true);
+       }
+       else
+       {
+           return RCS_findcommitid(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 * commitid = NULL;
+    char * token = strtok(tmp,".");
+    if (!strcmp (token, TAG_COMMITID))
+    {
+       commitid = strtok (NULL,".");
+       token = strtok (NULL,".");
+    }
+    if (token)
+    {
+       do
+       {
+           if (!strcmp (token, TAG_PREVIOUS))
+           {
+               if (commitid)
+               {
+                   char * p = retval;
+                   retval = RCS_findcommitid(rcs, commitid, true);
+                   free (p);
+                   commitid = NULL;
+               }
+               else if (retval)
+               {
+                   char * p = retval;
+                   retval = previous_rev( rcs, p);
+                   free (p);
+               }
+               else
+                   error (1, 0, "invalid tag extension: '%s'",tag);
+           }
+           else if (!strcmp (token, TAG_TRUNK))
+           {
+               if (retval || tmp == token)
+                   error (1, 0, "invalid tag extension: '%s'",tag);
+               retval = RCS_head(rcs);
+           }
+           else if (isdigit ((unsigned char) *token))
+           {
+               error (1, 0, "invalid tag extension: '%s'",tag);
+           }
+           else
+           {
+               if (retval)
+                   error (1, 0, "invalid tag extension: '%s'",tag);
+               else
+               {
+                   retval = translate_symtag (rcs, token);
+               }
+           }
+       }
+       while (token = strtok (NULL, "."));
+    }
+    if (commitid)
+        retval = RCS_findcommitid(rcs, commitid, false);
+
+    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 +3505,134 @@
 
 
 /*
+ * 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)
+{
+    const char *p = tag;
+    char * retval = NULL;
+    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
+       {
+           dot = false;
+           first = false;
+       }
+       ++p;
+    }
+
+    if ( (*p && !first && !dot) || tag[strlen (tag)-1] == '.')
+        error (1, 0, "\
+tag substring '%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 * tmp = xstrdup (p);
+    char * token = strtok (tmp,".");
+    if (first && dot && token)
+    {
+        /* handle tags that must be at the begining */
+        if (STREQ(token,TAG_COMMITID))
+       {
+           token = strtok (NULL,".");
+           if (token)
+           {
+               retval = xmalloc (strlen (token) + 2);
+               *retval = '@';
+               strcpy(retval+1,token);
+               first = false;
+               token = strtok (NULL,".");
+           }
+       }
+       else if (STREQ(token, TAG_TRUNK))
+       {
+           token = strtok (NULL, ".");
+           first = false;
+       }
+    }
+
+    while (token)
+    {
+        if (first)
+       {
+           if ( !dot
+                 && !STREQ (token, TAG_PREVIOUS)
+                 && !STREQ (token, TAG_HEAD)
+                 && !STREQ (token, TAG_BASE)
+                 && !STREQ (token, TAG_TRUNK)
+                 && !STREQ (token, TAG_COMMITID))
+           {
+               if (isdigit ((unsigned char) *token))
+                   error (1, 0, "\
+Numeric tags: '%s' must be placed at the begining: '%s'", token,tag);
+           
+               RCS_check_tag (token);
+               retval = xstrdup (token);
+               first = false;
+               token = strtok (NULL, ".");
+               continue;
+           }
+       }
+       else if (STREQ(token, TAG_PREVIOUS))
+       {
+           token = strtok (NULL, ".");
+           continue;
+       }
+       else
+       {
+           error (1, 0, "\
+too many tags: '%s'", tag);
+       }
+       error (1, 0, "\
+tag combination not allowed: '%s'", tag);
+    }
+
+    free (tmp);
+/*     if (retval) printf("retval: '%s'\n",retval); else printf("retval: 
(null)\n"); */
+    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/subr.c
===================================================================
RCS file: /home/frank/CVS_ROOT/ccvs/src/subr.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- src/subr.c  27 Feb 2005 15:02:24 -0000      1.1.1.1
+++ src/subr.c  27 Feb 2005 15:10:03 -0000      1.2
@@ -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[0]))
+    {
+        return 0;
+    }
+    else
+    {
+        const char * c = s+1;
+       while (c = strchr(c,'.'))
+        {
+           ++c;
+           if (*c && isalpha ((unsigned char) c[0]))
+               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.4
diff -u -r1.1.1.1 -r1.4
--- src/tag.c   27 Feb 2005 15:02:24 -0000      1.1.1.1
+++ src/tag.c   28 Feb 2005 03:24:21 -0000      1.4
@@ -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, *p;
     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);
 }


Regards - and enjoy
Frank

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





reply via email to

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