color: add support for 12-bit RGB colors
[git/gitster.git] / reftable / refname.c
blobbbfde15754a227c9bd418572b778d77827a59db4
1 /*
2 Copyright 2020 Google LLC
4 Use of this source code is governed by a BSD-style
5 license that can be found in the LICENSE file or at
6 https://developers.google.com/open-source/licenses/bsd
7 */
9 #include "system.h"
10 #include "reftable-error.h"
11 #include "basics.h"
12 #include "refname.h"
13 #include "reftable-iterator.h"
15 struct refname_needle_lesseq_args {
16 char **haystack;
17 const char *needle;
20 static int refname_needle_lesseq(size_t k, void *_args)
22 struct refname_needle_lesseq_args *args = _args;
23 return strcmp(args->needle, args->haystack[k]) <= 0;
26 static int modification_has_ref(struct modification *mod, const char *name)
28 struct reftable_ref_record ref = { NULL };
29 int err = 0;
31 if (mod->add_len > 0) {
32 struct refname_needle_lesseq_args args = {
33 .haystack = mod->add,
34 .needle = name,
36 size_t idx = binsearch(mod->add_len, refname_needle_lesseq, &args);
37 if (idx < mod->add_len && !strcmp(mod->add[idx], name))
38 return 0;
41 if (mod->del_len > 0) {
42 struct refname_needle_lesseq_args args = {
43 .haystack = mod->del,
44 .needle = name,
46 size_t idx = binsearch(mod->del_len, refname_needle_lesseq, &args);
47 if (idx < mod->del_len && !strcmp(mod->del[idx], name))
48 return 1;
51 err = reftable_table_read_ref(&mod->tab, name, &ref);
52 reftable_ref_record_release(&ref);
53 return err;
56 static void modification_release(struct modification *mod)
58 /* don't delete the strings themselves; they're owned by ref records.
60 FREE_AND_NULL(mod->add);
61 FREE_AND_NULL(mod->del);
62 mod->add_len = 0;
63 mod->del_len = 0;
66 static int modification_has_ref_with_prefix(struct modification *mod,
67 const char *prefix)
69 struct reftable_iterator it = { NULL };
70 struct reftable_ref_record ref = { NULL };
71 int err = 0;
73 if (mod->add_len > 0) {
74 struct refname_needle_lesseq_args args = {
75 .haystack = mod->add,
76 .needle = prefix,
78 size_t idx = binsearch(mod->add_len, refname_needle_lesseq, &args);
79 if (idx < mod->add_len &&
80 !strncmp(prefix, mod->add[idx], strlen(prefix)))
81 goto done;
83 err = reftable_table_seek_ref(&mod->tab, &it, prefix);
84 if (err)
85 goto done;
87 while (1) {
88 err = reftable_iterator_next_ref(&it, &ref);
89 if (err)
90 goto done;
92 if (mod->del_len > 0) {
93 struct refname_needle_lesseq_args args = {
94 .haystack = mod->del,
95 .needle = ref.refname,
97 size_t idx = binsearch(mod->del_len, refname_needle_lesseq, &args);
98 if (idx < mod->del_len &&
99 !strcmp(ref.refname, mod->del[idx]))
100 continue;
103 if (strncmp(ref.refname, prefix, strlen(prefix))) {
104 err = 1;
105 goto done;
107 err = 0;
108 goto done;
111 done:
112 reftable_ref_record_release(&ref);
113 reftable_iterator_destroy(&it);
114 return err;
117 static int validate_refname(const char *name)
119 while (1) {
120 char *next = strchr(name, '/');
121 if (!*name) {
122 return REFTABLE_REFNAME_ERROR;
124 if (!next) {
125 return 0;
127 if (next - name == 0 || (next - name == 1 && *name == '.') ||
128 (next - name == 2 && name[0] == '.' && name[1] == '.'))
129 return REFTABLE_REFNAME_ERROR;
130 name = next + 1;
132 return 0;
135 int validate_ref_record_addition(struct reftable_table tab,
136 struct reftable_ref_record *recs, size_t sz)
138 struct modification mod = {
139 .tab = tab,
140 .add = reftable_calloc(sz, sizeof(*mod.add)),
141 .del = reftable_calloc(sz, sizeof(*mod.del)),
143 int i = 0;
144 int err = 0;
145 for (; i < sz; i++) {
146 if (reftable_ref_record_is_deletion(&recs[i])) {
147 mod.del[mod.del_len++] = recs[i].refname;
148 } else {
149 mod.add[mod.add_len++] = recs[i].refname;
153 err = modification_validate(&mod);
154 modification_release(&mod);
155 return err;
158 static void strbuf_trim_component(struct strbuf *sl)
160 while (sl->len > 0) {
161 int is_slash = (sl->buf[sl->len - 1] == '/');
162 strbuf_setlen(sl, sl->len - 1);
163 if (is_slash)
164 break;
168 int modification_validate(struct modification *mod)
170 struct strbuf slashed = STRBUF_INIT;
171 int err = 0;
172 int i = 0;
173 for (; i < mod->add_len; i++) {
174 err = validate_refname(mod->add[i]);
175 if (err)
176 goto done;
177 strbuf_reset(&slashed);
178 strbuf_addstr(&slashed, mod->add[i]);
179 strbuf_addstr(&slashed, "/");
181 err = modification_has_ref_with_prefix(mod, slashed.buf);
182 if (err == 0) {
183 err = REFTABLE_NAME_CONFLICT;
184 goto done;
186 if (err < 0)
187 goto done;
189 strbuf_reset(&slashed);
190 strbuf_addstr(&slashed, mod->add[i]);
191 while (slashed.len) {
192 strbuf_trim_component(&slashed);
193 err = modification_has_ref(mod, slashed.buf);
194 if (err == 0) {
195 err = REFTABLE_NAME_CONFLICT;
196 goto done;
198 if (err < 0)
199 goto done;
202 err = 0;
203 done:
204 strbuf_release(&slashed);
205 return err;