in src/refs.c [979:1104]
int git_reference__normalize_name(
git_buf *buf,
const char *name,
unsigned int flags)
{
const char *current;
int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC;
unsigned int process_flags;
bool normalize = (buf != NULL);
bool validate = (flags & GIT_REFERENCE_FORMAT__VALIDATION_DISABLE) == 0;
#ifdef GIT_USE_ICONV
git_path_iconv_t ic = GIT_PATH_ICONV_INIT;
#endif
assert(name);
process_flags = flags;
current = (char *)name;
if (validate && *current == '/')
goto cleanup;
if (normalize)
git_buf_clear(buf);
#ifdef GIT_USE_ICONV
if ((flags & GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE) != 0) {
size_t namelen = strlen(current);
if ((error = git_path_iconv_init_precompose(&ic)) < 0 ||
(error = git_path_iconv(&ic, ¤t, &namelen)) < 0)
goto cleanup;
error = GIT_EINVALIDSPEC;
}
#endif
if (!validate) {
git_buf_sets(buf, current);
error = git_buf_oom(buf) ? -1 : 0;
goto cleanup;
}
while (true) {
char may_contain_glob = process_flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN;
segment_len = ensure_segment_validity(current, may_contain_glob);
if (segment_len < 0)
goto cleanup;
if (segment_len > 0) {
/*
* There may only be one glob in a pattern, thus we reset
* the pattern-flag in case the current segment has one.
*/
if (memchr(current, '*', segment_len))
process_flags &= ~GIT_REFERENCE_FORMAT_REFSPEC_PATTERN;
if (normalize) {
size_t cur_len = git_buf_len(buf);
git_buf_joinpath(buf, git_buf_cstr(buf), current);
git_buf_truncate(buf,
cur_len + segment_len + (segments_count ? 1 : 0));
if (git_buf_oom(buf)) {
error = -1;
goto cleanup;
}
}
segments_count++;
}
/* No empty segment is allowed when not normalizing */
if (segment_len == 0 && !normalize)
goto cleanup;
if (current[segment_len] == '\0')
break;
current += segment_len + 1;
}
/* A refname can not be empty */
if (segment_len == 0 && segments_count == 0)
goto cleanup;
/* A refname can not end with "." */
if (current[segment_len - 1] == '.')
goto cleanup;
/* A refname can not end with "/" */
if (current[segment_len - 1] == '/')
goto cleanup;
if ((segments_count == 1 ) && !(flags & GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL))
goto cleanup;
if ((segments_count == 1 ) &&
!(flags & GIT_REFERENCE_FORMAT_REFSPEC_SHORTHAND) &&
!(is_all_caps_and_underscore(name, (size_t)segment_len) ||
((flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN) && !strcmp("*", name))))
goto cleanup;
if ((segments_count > 1)
&& (is_all_caps_and_underscore(name, strchr(name, '/') - name)))
goto cleanup;
error = 0;
cleanup:
if (error == GIT_EINVALIDSPEC)
git_error_set(
GIT_ERROR_REFERENCE,
"the given reference name '%s' is not valid", name);
if (error && normalize)
git_buf_dispose(buf);
#ifdef GIT_USE_ICONV
git_path_iconv_clear(&ic);
#endif
return error;
}