refspec: remove the deprecated functions
[git] / refspec.c
1 #include "cache.h"
2 #include "refs.h"
3 #include "refspec.h"
4
5 static struct refspec_item s_tag_refspec = {
6         0,
7         1,
8         0,
9         0,
10         "refs/tags/*",
11         "refs/tags/*"
12 };
13
14 /* See TAG_REFSPEC for the string version */
15 const struct refspec_item *tag_refspec = &s_tag_refspec;
16
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 {
23         size_t llen;
24         int is_glob;
25         const char *lhs, *rhs;
26         int flags;
27
28         is_glob = 0;
29
30         lhs = refspec;
31         if (*lhs == '+') {
32                 item->force = 1;
33                 lhs++;
34         }
35
36         rhs = strrchr(lhs, ':');
37
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                 /*
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 (!*item->src)
96                         ; /* empty is ok */
97                 else if (is_glob) {
98                         if (check_refname_format(item->src, flags))
99                                 return 0;
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 (!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
121         return 1;
122 }
123
124 void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
125 {
126         memset(item, 0, sizeof(*item));
127
128         if (!parse_refspec(item, refspec, fetch))
129                 die("Invalid refspec '%s'", refspec);
130 }
131
132 void refspec_item_clear(struct refspec_item *item)
133 {
134         FREE_AND_NULL(item->src);
135         FREE_AND_NULL(item->dst);
136         item->force = 0;
137         item->pattern = 0;
138         item->matching = 0;
139         item->exact_sha1 = 0;
140 }
141
142 void refspec_init(struct refspec *rs, int fetch)
143 {
144         memset(rs, 0, sizeof(*rs));
145         rs->fetch = fetch;
146 }
147
148 void refspec_append(struct refspec *rs, const char *refspec)
149 {
150         struct refspec_item item;
151
152         refspec_item_init(&item, refspec, rs->fetch);
153
154         ALLOC_GROW(rs->items, rs->nr + 1, rs->alloc);
155         rs->items[rs->nr++] = item;
156
157         ALLOC_GROW(rs->raw, rs->raw_nr + 1, rs->raw_alloc);
158         rs->raw[rs->raw_nr++] = xstrdup(refspec);
159 }
160
161 void refspec_appendn(struct refspec *rs, const char **refspecs, int nr)
162 {
163         int i;
164         for (i = 0; i < nr; i++)
165                 refspec_append(rs, refspecs[i]);
166 }
167
168 void refspec_clear(struct refspec *rs)
169 {
170         int i;
171
172         for (i = 0; i < rs->nr; i++)
173                 refspec_item_clear(&rs->items[i]);
174
175         FREE_AND_NULL(rs->items);
176         rs->alloc = 0;
177         rs->nr = 0;
178
179         for (i = 0; i < rs->raw_nr; i++)
180                 free((char *)rs->raw[i]);
181         FREE_AND_NULL(rs->raw);
182         rs->raw_alloc = 0;
183         rs->raw_nr = 0;
184
185         rs->fetch = 0;
186 }
187
188 int valid_fetch_refspec(const char *fetch_refspec_str)
189 {
190         struct refspec_item refspec;
191         int ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
192         refspec_item_clear(&refspec);
193         return ret;
194 }