The core logic of this function is factored out to provide more
information when the refname is invalid: what part that is and exact
what is wrong with it. This will be useful for a coming function that
has to turn a string into a valid refname component.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
---
 refs.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 62 insertions(+), 16 deletions(-)

diff --git a/refs.c b/refs.c
index 142888a40a..70c55ea1b6 100644
--- a/refs.c
+++ b/refs.c
@@ -57,10 +57,21 @@ static unsigned char refname_disposition[256] = {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4
 };
 
+enum refname_check_code {
+        refname_ok = 0,
+        refname_contains_dotdot,
+        refname_contains_atopen,
+        refname_has_badchar,
+        refname_contains_wildcard,
+        refname_starts_with_dot,
+        refname_ends_with_dotlock,
+        refname_component_has_zero_length
+};
+
 /*
  * Try to read one refname component from the front of refname.
- * Return the length of the component found, or -1 if the component is
- * not legal.  It is legal if it is something reasonable to have under
+ * If the component is legal, return the end of the component in cp_out.
+ * It is legal if it is something reasonable to have under
  * ".git/refs/"; We do not like it if:
  *
  * - any path component of it begins with ".", or
@@ -71,11 +82,15 @@ static unsigned char refname_disposition[256] = {
  * - it ends with a "/", or
  * - it ends with ".lock", or
  * - it contains a "@{" portion
+ *
+ * in which case cp_out points to the beginning of the illegal part.
  */
-static int check_refname_component(const char *refname, int *flags)
+static enum refname_check_code do_check_refname_component(
+       const char *refname, int *flags, const char **cp_out)
 {
        const char *cp;
        char last = '\0';
+       enum refname_check_code ret = refname_ok;
 
        for (cp = refname; ; cp++) {
                int ch = *cp & 255;
@@ -84,18 +99,28 @@ static int check_refname_component(const char *refname, int 
*flags)
                case 1:
                        goto out;
                case 2:
-                       if (last == '.')
-                               return -1; /* Refname contains "..". */
+                       if (last == '.') {
+                               cp--;
+                               ret = refname_contains_dotdot;
+                               goto done;
+                       }
                        break;
                case 3:
-                       if (last == '@')
-                               return -1; /* Refname contains "@{". */
+                       if (last == '@') {
+                               cp--;
+                               ret = refname_contains_atopen; /* @{ */
+                               goto done;
+                       }
                        break;
                case 4:
-                       return -1;
+                       ret = refname_has_badchar;
+                       goto done;
                case 5:
-                       if (!(*flags & REFNAME_REFSPEC_PATTERN))
-                               return -1; /* refspec can't be a pattern */
+                       if (!(*flags & REFNAME_REFSPEC_PATTERN)) {
+                               /* refspec can't be a pattern */
+                               ret = refname_contains_wildcard;
+                               goto done;
+                       }
 
                        /*
                         * Unset the pattern flag so that we only accept
@@ -107,13 +132,34 @@ static int check_refname_component(const char *refname, 
int *flags)
                last = ch;
        }
 out:
-       if (cp == refname)
-               return 0; /* Component has zero length. */
-       if (refname[0] == '.')
-               return -1; /* Component starts with '.'. */
+       if (cp == refname) {
+               ret = refname_component_has_zero_length;
+               goto done;
+       }
+       if (refname[0] == '.') {
+               cp = refname;
+               ret = refname_starts_with_dot;
+               goto done;
+       }
        if (cp - refname >= LOCK_SUFFIX_LEN &&
-           !memcmp(cp - LOCK_SUFFIX_LEN, LOCK_SUFFIX, LOCK_SUFFIX_LEN))
-               return -1; /* Refname ends with ".lock". */
+           !memcmp(cp - LOCK_SUFFIX_LEN, LOCK_SUFFIX, LOCK_SUFFIX_LEN)) {
+               cp -= LOCK_SUFFIX_LEN;
+               ret = refname_ends_with_dotlock;
+       }
+done:
+       *cp_out = cp;
+       return ret;
+}
+
+/* Return the length of the component if it's legal otherwise -1 */
+static int check_refname_component(const char *refname, int *flags)
+{
+       const char *cp;
+       enum refname_check_code ret;
+
+       ret = do_check_refname_component(refname, flags, &cp);
+       if (ret)
+               return -1;
        return cp - refname;
 }
 
-- 
2.21.0.rc1.337.gdf7f8d0522

Reply via email to