refspec: factor out parsing a single refspec

Factor out the logic which parses a single refspec into its own function. This makes it easier to reuse this logic in a future patch. Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Brandon Williams committed May 16, 2018 at 15:57 UTC 3eec3700fdc4d5b0a33729d45e7fb9735ed7e0f5
1 file changed +104 -91
refspec.c
+104 -91
@@ -14,110 +14,123 @@ static struct refspec_item s_tag_refspec = {
14 /* See TAG_REFSPEC for the string version */
15 const struct refspec_item *tag_refspec = &s_tag_refspec;
16
17 -static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
17 +/*
18 + * Parses the provided refspec 'refspec' and populates the refspec_item 'item'.
19 + * Returns 1 if successful and 0 if the refspec is invalid.
20 + */
21 +static int parse_refspec(struct refspec_item *item, const char *refspec, int fetch)
22 {
19 - int i;
20 - struct refspec_item *rs = xcalloc(nr_refspec, sizeof(*rs));
23 + size_t llen;
24 + int is_glob;
25 + const char *lhs, *rhs;
26 + int flags;
27
22 - for (i = 0; i < nr_refspec; i++) {
23 - size_t llen;
24 - int is_glob;
25 - const char *lhs, *rhs;
26 - int flags;
28 + is_glob = 0;
29
28 - is_glob = 0;
30 + lhs = refspec;
31 + if (*lhs == '+') {
32 + item->force = 1;
33 + lhs++;
34 + }
35
30 - lhs = refspec[i];
31 - if (*lhs == '+') {
32 - rs[i].force = 1;
33 - lhs++;
34 - }
36 + rhs = strrchr(lhs, ':');
37
36 - rhs = strrchr(lhs, ':');
38 + /*
39 + * Before going on, special case ":" (or "+:") as a refspec
40 + * for pushing matching refs.
41 + */
42 + if (!fetch && rhs == lhs && rhs[1] == '\0') {
43 + item->matching = 1;
44 + return 1;
45 + }
46
47 + if (rhs) {
48 + size_t rlen = strlen(++rhs);
49 + is_glob = (1 <= rlen && strchr(rhs, '*'));
50 + item->dst = xstrndup(rhs, rlen);
51 + }
52 +
53 + llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
54 + if (1 <= llen && memchr(lhs, '*', llen)) {
55 + if ((rhs && !is_glob) || (!rhs && fetch))
56 + return 0;
57 + is_glob = 1;
58 + } else if (rhs && is_glob) {
59 + return 0;
60 + }
61 +
62 + item->pattern = is_glob;
63 + item->src = xstrndup(lhs, llen);
64 + flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
65 +
66 + if (fetch) {
67 + struct object_id unused;
68 +
69 + /* LHS */
70 + if (!*item->src)
71 + ; /* empty is ok; it means "HEAD" */
72 + else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(item->src, &unused))
73 + item->exact_sha1 = 1; /* ok */
74 + else if (!check_refname_format(item->src, flags))
75 + ; /* valid looking ref is ok */
76 + else
77 + return 0;
78 + /* RHS */
79 + if (!item->dst)
80 + ; /* missing is ok; it is the same as empty */
81 + else if (!*item->dst)
82 + ; /* empty is ok; it means "do not store" */
83 + else if (!check_refname_format(item->dst, flags))
84 + ; /* valid looking ref is ok */
85 + else
86 + return 0;
87 + } else {
88 /*
39 - * Before going on, special case ":" (or "+:") as a refspec
40 - * for pushing matching refs.
89 + * LHS
90 + * - empty is allowed; it means delete.
91 + * - when wildcarded, it must be a valid looking ref.
92 + * - otherwise, it must be an extended SHA-1, but
93 + * there is no existing way to validate this.
94 */
42 - if (!fetch && rhs == lhs && rhs[1] == '\0') {
43 - rs[i].matching = 1;
44 - continue;
95 + if (!*item->src)
96 + ; /* empty is ok */
97 + else if (is_glob) {
98 + if (check_refname_format(item->src, flags))
99 + return 0;
100 }
46 -
47 - if (rhs) {
48 - size_t rlen = strlen(++rhs);
49 - is_glob = (1 <= rlen && strchr(rhs, '*'));
50 - rs[i].dst = xstrndup(rhs, rlen);
101 + else
102 + ; /* anything goes, for now */
103 + /*
104 + * RHS
105 + * - missing is allowed, but LHS then must be a
106 + * valid looking ref.
107 + * - empty is not allowed.
108 + * - otherwise it must be a valid looking ref.
109 + */
110 + if (!item->dst) {
111 + if (check_refname_format(item->src, flags))
112 + return 0;
113 + } else if (!*item->dst) {
114 + return 0;
115 + } else {
116 + if (check_refname_format(item->dst, flags))
117 + return 0;
118 }
119 + }
120
53 - llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
54 - if (1 <= llen && memchr(lhs, '*', llen)) {
55 - if ((rhs && !is_glob) || (!rhs && fetch))
56 - goto invalid;
57 - is_glob = 1;
58 - } else if (rhs && is_glob) {
59 - goto invalid;
60 - }
121 + return 1;
122 +}
123
62 - rs[i].pattern = is_glob;
63 - rs[i].src = xstrndup(lhs, llen);
64 - flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
65 -
66 - if (fetch) {
67 - struct object_id unused;
68 -
69 - /* LHS */
70 - if (!*rs[i].src)
71 - ; /* empty is ok; it means "HEAD" */
72 - else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused))
73 - rs[i].exact_sha1 = 1; /* ok */
74 - else if (!check_refname_format(rs[i].src, flags))
75 - ; /* valid looking ref is ok */
76 - else
77 - goto invalid;
78 - /* RHS */
79 - if (!rs[i].dst)
80 - ; /* missing is ok; it is the same as empty */
81 - else if (!*rs[i].dst)
82 - ; /* empty is ok; it means "do not store" */
83 - else if (!check_refname_format(rs[i].dst, flags))
84 - ; /* valid looking ref is ok */
85 - else
86 - goto invalid;
87 - } else {
88 - /*
89 - * LHS
90 - * - empty is allowed; it means delete.
91 - * - when wildcarded, it must be a valid looking ref.
92 - * - otherwise, it must be an extended SHA-1, but
93 - * there is no existing way to validate this.
94 - */
95 - if (!*rs[i].src)
96 - ; /* empty is ok */
97 - else if (is_glob) {
98 - if (check_refname_format(rs[i].src, flags))
99 - goto invalid;
100 - }
101 - else
102 - ; /* anything goes, for now */
103 - /*
104 - * RHS
105 - * - missing is allowed, but LHS then must be a
106 - * valid looking ref.
107 - * - empty is not allowed.
108 - * - otherwise it must be a valid looking ref.
109 - */
110 - if (!rs[i].dst) {
111 - if (check_refname_format(rs[i].src, flags))
112 - goto invalid;
113 - } else if (!*rs[i].dst) {
114 - goto invalid;
115 - } else {
116 - if (check_refname_format(rs[i].dst, flags))
117 - goto invalid;
118 - }
119 - }
124 +static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
125 +{
126 + int i;
127 + struct refspec_item *rs = xcalloc(nr_refspec, sizeof(*rs));
128 +
129 + for (i = 0; i < nr_refspec; i++) {
130 + if (!parse_refspec(&rs[i], refspec[i], fetch))
131 + goto invalid;
132 }
133 +
134 return rs;
135
136 invalid: