update-ref.c: extract a new function, parse_next_sha1()

Replace three functions, update_store_new_sha1(), update_store_old_sha1(), and parse_next_arg(), with a single function, parse_next_sha1(). The new function takes care of a whole argument, including checking whether it is there, converting it to an SHA-1, and emitting errors on EOF or for invalid values. The return value indicates whether the argument was present or absent, which requires a bit of intelligence because absent values are represented differently depending on whether "-z" was used. The new interface means that the calling functions, parse_cmd_*(), don't have to interpret the result differently based on the line_termination mode that is in effect. It also means that parse_cmd_create() can distinguish unambiguously between an empty new value and a zeros new value, which fixes a failure in t1400. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Haggerty committed Apr 7, 2014 at 15:48 UTC 3afcc4637452100c68b469de7757dd2b45b4d29c
2 files changed +99 -63
builtin/update-ref.c
+98 -62
@@ -35,27 +35,6 @@ static struct ref_update *update_alloc(void)
35 return update;
36 }
37
38 -static void update_store_new_sha1(const char *command,
39 - struct ref_update *update,
40 - const char *newvalue)
41 -{
42 - if (*newvalue && get_sha1(newvalue, update->new_sha1))
43 - die("%s %s: invalid <newvalue>: %s",
44 - command, update->ref_name, newvalue);
45 -}
46 -
47 -static void update_store_old_sha1(const char *command,
48 - struct ref_update *update,
49 - const char *oldvalue)
50 -{
51 - if (*oldvalue && get_sha1(oldvalue, update->old_sha1))
52 - die("%s %s: invalid <oldvalue>: %s",
53 - command, update->ref_name, oldvalue);
54 -
55 - /* We have an old value if non-empty, or if empty without -z */
56 - update->have_old = *oldvalue || line_termination;
57 -}
58 -
38 /*
39 * Parse one whitespace- or NUL-terminated, possibly C-quoted argument
40 * and append the result to arg. Return a pointer to the terminator.
@@ -112,35 +91,94 @@ static char *parse_refname(struct strbuf *input, const char **next)
91 }
92
93 /*
115 - * Parse a SP/NUL separator followed by the next SP- or NUL-terminated
116 - * argument, if any. If there is an argument, write it to arg, set
117 - * *next to point at the character terminating the argument, and
94 + * The value being parsed is <oldvalue> (as opposed to <newvalue>; the
95 + * difference affects which error messages are generated):
96 + */
97 +#define PARSE_SHA1_OLD 0x01
98 +
99 +/*
100 + * For backwards compatibility, accept an empty string for update's
101 + * <newvalue> in binary mode to be equivalent to specifying zeros.
102 + */
103 +#define PARSE_SHA1_ALLOW_EMPTY 0x02
104 +
105 +/*
106 + * Parse an argument separator followed by the next argument, if any.
107 + * If there is an argument, convert it to a SHA-1, write it to sha1,
108 + * set *next to point at the character terminating the argument, and
109 * return 0. If there is no argument at all (not even the empty
119 - * string), return a non-zero result and leave *next unchanged.
110 + * string), return 1 and leave *next unchanged. If the value is
111 + * provided but cannot be converted to a SHA-1, die. flags can
112 + * include PARSE_SHA1_OLD and/or PARSE_SHA1_ALLOW_EMPTY.
113 */
121 -static int parse_next_arg(struct strbuf *input, const char **next,
122 - struct strbuf *arg)
114 +static int parse_next_sha1(struct strbuf *input, const char **next,
115 + unsigned char *sha1,
116 + const char *command, const char *refname,
117 + int flags)
118 {
124 - strbuf_reset(arg);
119 + struct strbuf arg = STRBUF_INIT;
120 + int ret = 0;
121 +
122 + if (*next == input->buf + input->len)
123 + goto eof;
124 +
125 if (line_termination) {
126 /* Without -z, consume SP and use next argument */
127 if (!**next || **next == line_termination)
128 - return -1;
128 + return 1;
129 if (**next != ' ')
130 - die("expected SP but got: %s", *next);
130 + die("%s %s: expected SP but got: %s",
131 + command, refname, *next);
132 (*next)++;
132 - *next = parse_arg(*next, arg);
133 + *next = parse_arg(*next, &arg);
134 + if (arg.len) {
135 + if (get_sha1(arg.buf, sha1))
136 + goto invalid;
137 + } else {
138 + /* Without -z, an empty value means all zeros: */
139 + hashclr(sha1);
140 + }
141 } else {
142 /* With -z, read the next NUL-terminated line */
143 if (**next)
136 - die("expected NUL but got: %s", *next);
144 + die("%s %s: expected NUL but got: %s",
145 + command, refname, *next);
146 (*next)++;
147 if (*next == input->buf + input->len)
139 - return -1;
140 - strbuf_addstr(arg, *next);
141 - *next += arg->len;
148 + goto eof;
149 + strbuf_addstr(&arg, *next);
150 + *next += arg.len;
151 +
152 + if (arg.len) {
153 + if (get_sha1(arg.buf, sha1))
154 + goto invalid;
155 + } else if (flags & PARSE_SHA1_ALLOW_EMPTY) {
156 + /* With -z, treat an empty value as all zeros: */
157 + hashclr(sha1);
158 + } else {
159 + /*
160 + * With -z, an empty non-required value means
161 + * unspecified:
162 + */
163 + ret = 1;
164 + }
165 }
143 - return 0;
166 +
167 + strbuf_release(&arg);
168 +
169 + return ret;
170 +
171 + invalid:
172 + die(flags & PARSE_SHA1_OLD ?
173 + "%s %s: invalid <oldvalue>: %s" :
174 + "%s %s: invalid <newvalue>: %s",
175 + command, refname, arg.buf);
176 +
177 + eof:
178 + die(flags & PARSE_SHA1_OLD ?
179 + "%s %s missing <oldvalue>" :
180 + "%s %s missing <newvalue>",
181 + command, refname);
182 }
183
184
@@ -156,8 +194,6 @@ static int parse_next_arg(struct strbuf *input, const char **next,
194
195 static const char *parse_cmd_update(struct strbuf *input, const char *next)
196 {
159 - struct strbuf newvalue = STRBUF_INIT;
160 - struct strbuf oldvalue = STRBUF_INIT;
197 struct ref_update *update;
198
199 update = update_alloc();
@@ -166,24 +202,23 @@ static const char *parse_cmd_update(struct strbuf *input, const char *next)
202 if (!update->ref_name)
203 die("update line missing <ref>");
204
169 - if (!parse_next_arg(input, &next, &newvalue))
170 - update_store_new_sha1("update", update, newvalue.buf);
171 - else
205 + if (parse_next_sha1(input, &next, update->new_sha1,
206 + "update", update->ref_name,
207 + PARSE_SHA1_ALLOW_EMPTY))
208 die("update %s missing <newvalue>", update->ref_name);
209
174 - if (!parse_next_arg(input, &next, &oldvalue)) {
175 - update_store_old_sha1("update", update, oldvalue.buf);
176 - if (*next != line_termination)
177 - die("update %s has extra input: %s", update->ref_name, next);
178 - } else if (!line_termination)
179 - die("update %s missing <oldvalue>", update->ref_name);
210 + update->have_old = !parse_next_sha1(input, &next, update->old_sha1,
211 + "update", update->ref_name,
212 + PARSE_SHA1_OLD);
213 +
214 + if (*next != line_termination)
215 + die("update %s has extra input: %s", update->ref_name, next);
216
217 return next;
218 }
219
220 static const char *parse_cmd_create(struct strbuf *input, const char *next)
221 {
186 - struct strbuf newvalue = STRBUF_INIT;
222 struct ref_update *update;
223
224 update = update_alloc();
@@ -192,9 +227,8 @@ static const char *parse_cmd_create(struct strbuf *input, const char *next)
227 if (!update->ref_name)
228 die("create line missing <ref>");
229
195 - if (!parse_next_arg(input, &next, &newvalue))
196 - update_store_new_sha1("create", update, newvalue.buf);
197 - else
230 + if (parse_next_sha1(input, &next, update->new_sha1,
231 + "create", update->ref_name, 0))
232 die("create %s missing <newvalue>", update->ref_name);
233
234 if (is_null_sha1(update->new_sha1))
@@ -208,7 +242,6 @@ static const char *parse_cmd_create(struct strbuf *input, const char *next)
242
243 static const char *parse_cmd_delete(struct strbuf *input, const char *next)
244 {
211 - struct strbuf oldvalue = STRBUF_INIT;
245 struct ref_update *update;
246
247 update = update_alloc();
@@ -217,12 +250,14 @@ static const char *parse_cmd_delete(struct strbuf *input, const char *next)
250 if (!update->ref_name)
251 die("delete line missing <ref>");
252
220 - if (!parse_next_arg(input, &next, &oldvalue)) {
221 - update_store_old_sha1("delete", update, oldvalue.buf);
222 - if (update->have_old && is_null_sha1(update->old_sha1))
253 + if (parse_next_sha1(input, &next, update->old_sha1,
254 + "delete", update->ref_name, PARSE_SHA1_OLD)) {
255 + update->have_old = 0;
256 + } else {
257 + if (is_null_sha1(update->old_sha1))
258 die("delete %s given zero <oldvalue>", update->ref_name);
224 - } else if (!line_termination)
225 - die("delete %s missing <oldvalue>", update->ref_name);
259 + update->have_old = 1;
260 + }
261
262 if (*next != line_termination)
263 die("delete %s has extra input: %s", update->ref_name, next);
@@ -232,7 +267,6 @@ static const char *parse_cmd_delete(struct strbuf *input, const char *next)
267
268 static const char *parse_cmd_verify(struct strbuf *input, const char *next)
269 {
235 - struct strbuf value = STRBUF_INIT;
270 struct ref_update *update;
271
272 update = update_alloc();
@@ -241,11 +275,13 @@ static const char *parse_cmd_verify(struct strbuf *input, const char *next)
275 if (!update->ref_name)
276 die("verify line missing <ref>");
277
244 - if (!parse_next_arg(input, &next, &value)) {
245 - update_store_old_sha1("verify", update, value.buf);
278 + if (parse_next_sha1(input, &next, update->old_sha1,
279 + "verify", update->ref_name, PARSE_SHA1_OLD)) {
280 + update->have_old = 0;
281 + } else {
282 hashcpy(update->new_sha1, update->old_sha1);
247 - } else if (!line_termination)
248 - die("verify %s missing <oldvalue>", update->ref_name);
283 + update->have_old = 1;
284 + }
285
286 if (*next != line_termination)
287 die("verify %s has extra input: %s", update->ref_name, next);
t/t1400-update-ref.sh
+1 -1
@@ -858,7 +858,7 @@ test_expect_success 'stdin -z create ref fails with bad new value' '
858 test_must_fail git rev-parse --verify -q $c
859 '
860
861 -test_expect_failure 'stdin -z create ref fails with empty new value' '
861 +test_expect_success 'stdin -z create ref fails with empty new value' '
862 printf $F "create $c" "" >stdin &&
863 test_must_fail git update-ref -z --stdin <stdin 2>err &&
864 grep "fatal: create $c missing <newvalue>" err &&