git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[RFC 02/13] parse_refname_prefix(): new function

From
mhagger@alum.mit.edu <mhagger@alum.mit.edu>
Date
Oct 19, 2011, 20:55 UTC
Message-ID
<1319057716-28094-3-git-send-email-mhagger@alum.mit.edu>
In-Reply-To
<1319057716-28094-1-git-send-email-mhagger@alum.mit.edu>
From: Michael Haggerty <mhagger@alum.mit.edu>

Add a function parse_refname_prefix() that can read a possible refname from the front of a string. This is like check_refname_format(), except:

* It accepts (string, len) parameters and can therefore handle
  non-NUL-terminated strings.
* It returns the length of the part of the string that was parsed,
  allowing it to be used for refnames that are followed by additional
  characters.
Re-implement check_refname_format() using the new function.

Rename function check_refname_component() to parse_refname_component() for consistency.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
 refs.c |   64 ++++++++++++++++++++++++++++++++++++++++++++--------------------
 1 files changed, 44 insertions(+), 20 deletions(-)
diff --git a/refs.c b/refs.c
index 3b41252..387da83 100644
--- a/refs.c
+++ b/refs.c
@@ -907,24 +907,30 @@ static inline int bad_ref_char(int ch)
 
 /*
  * Try to read one refname component from the front of ref.  Return
- * the length of the component found, or -1 if the component is not
- * legal.
+ * the length of the component found, or -1 if the start of the string
+ * cannot be interpreted as a component of a legal refname.
  */
-static int check_refname_component(const char *ref, int flags)
+static int parse_refname_component(const char *ref, int len, int flags)
 {
-	int i, len = strlen(ref);
+	int i;
 	char last = '\0';
 
 	for (i = 0; i < len; i++) {
 		char ch = ref[i];
-		if (ch == '\0' || ch == '/')
-			break;
+		if (ch == '/')
+			break; /* Component terminated by "..". */
 		if (bad_ref_char(ch))
-			return -1; /* Illegal character in refname. */
-		if (last == '.' && ch == '.')
-			return -1; /* Refname contains "..". */
-		if (last == '@' && ch == '{')
-			return -1; /* Refname contains "@{". */
+			break; /* Component terminated by illegal character. */
+		if (last == '.' && ch == '.') {
+			/* Component terminated by "..". */
+			i--;
+			break;
+		}
+		if (last == '@' && ch == '{') {
+			/* Component terminated by "@{". */
+			i--;
+			break;
+		}
 		last = ch;
 	}
 	if (i == 0)
@@ -944,17 +950,26 @@ static int check_refname_component(const char *ref, int flags)
 	return i;
 }
 
-int check_refname_format(const char *ref, int flags)
+/*
+ * Try to interpret the beginning of a string as a refname.  Return
+ * the length of the part of the string that could constitute a valid
+ * refname, or -1 if the start of the string cannot possibly be
+ * interpreted as a refname.  flags has the same interpretation as for
+ * check_refname_format().
+ */
+static int parse_refname_prefix(const char *ref, int len, int flags)
 {
 	int component_len, component_count = 0;
+	const char *p = ref;
+	int valid_len;
 
 	while (1) {
-		/* We are at the start of a path component. */
-		component_len = check_refname_component(ref, flags);
+		/* p is at the start of a path component. */
+		component_len = parse_refname_component(p, len, flags);
 		if (component_len < 0) {
 			if ((flags & REFNAME_REFSPEC_PATTERN) &&
-					ref[0] == '*' &&
-					(ref[1] == '\0' || ref[1] == '/')) {
+					len && p[0] == '*' &&
+					(len == 1 || p[1] == '/')) {
 				/* Accept one wildcard as a full refname component. */
 				flags &= ~REFNAME_REFSPEC_PATTERN;
 				component_len = 1;
@@ -963,17 +978,26 @@ int check_refname_format(const char *ref, int flags)
 			}
 		}
 		component_count++;
-		if (ref[component_len] == '\0')
+		if (component_len == len || p[component_len] != '/')
 			break;
 		/* Skip to next component. */
-		ref += component_len + 1;
+		p += component_len + 1;
+		len -= component_len + 1;
 	}
 
-	if (ref[component_len - 1] == '.')
+	valid_len = p + component_len - ref;
+
+	if (ref[valid_len - 1] == '.')
 		return -1; /* Refname ends with '.'. */
 	if (!(flags & REFNAME_ALLOW_ONELEVEL) && component_count < 2)
 		return -1; /* Refname has only one component. */
-	return 0;
+	return valid_len;
+}
+
+int check_refname_format(const char *ref, int flags)
+{
+	int len = strlen(ref);
+	return parse_refname_prefix(ref, len, flags) == len ? 0 : -1;
 }
 
 const char *prettify_refname(const char *name)
-- 
1.7.7
Previous: mhagger@alum.mit.eduNext: mhagger@alum.mit.edu
Message 3 of 17 in “[RFC 00/13] Checking full vs. partial refnames”
  1. mhagger@alum.mit.eduOct 19, 2011
  2. 01/13 check_refname_component(): iterate via index rather than via pointermhagger@alum.mit.edu, Oct 19, 2011
  3. 02/13 parse_refname_prefix(): new functionmhagger@alum.mit.edu, Oct 19, 2011
  4. 03/13 Teach check_refname_format() to check full refnamesmhagger@alum.mit.edu, Oct 19, 2011
  5. 04/13 add_ref(): move the call of check_refname_format() to callersmhagger@alum.mit.edu, Oct 19, 2011
  6. Junio C HamanoOct 19, 2011
  7. Michael HaggertyOct 19, 2011
  8. 05/13 receive-pack::update(): use check_refname_format(..., REFNAME_FULL)mhagger@alum.mit.edu, Oct 19, 2011
  9. 06/13 strbuf_check_branch_ref(): use check_refname_format(..., REFNAME_FULL)mhagger@alum.mit.edu, Oct 19, 2011
  10. 07/13 one_local_ref(): use check_refname_format(..., REFNAME_FULL)mhagger@alum.mit.edu, Oct 19, 2011
  11. 08/13 expand_namespace(): the refname is full, so use REFNAME_FULL optionmhagger@alum.mit.edu, Oct 19, 2011
  12. 09/13 new_branch(): verify that new branch name is a valid full refnamemhagger@alum.mit.edu, Oct 19, 2011
  13. Junio C HamanoOct 19, 2011
  14. 10/13 strbuf_check_tag_ref(): the refname is full, so use REFNAME_FULL optionmhagger@alum.mit.edu, Oct 19, 2011
  15. 11/13 replace_object(): the refname is full, so use REFNAME_FULL optionmhagger@alum.mit.edu, Oct 19, 2011
  16. 12/13 resolve_ref: use check_refname_format(..., REFNAME_FULL)mhagger@alum.mit.edu, Oct 19, 2011
  17. 13/13 filter_refs(): the refname is full, so use REFNAME_FULL optionmhagger@alum.mit.edu, Oct 19, 2011

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.