update-ref --stdin: read the whole input at once

Read the whole input into a strbuf at once, and then parse it from there. This might also be a tad faster, but that is not the point. The point is to decouple the parsing code from the input source (the old parsing code had to read new data even in the middle of commands). Add docstrings for the parsing functions. 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:47 UTC e23d84350a3f4a3bfb86037eb1e6c4b28240324e
1 file changed +108 -62
builtin/update-ref.c
+108 -62
@@ -85,44 +85,70 @@ static const char *parse_arg(const char *next, struct strbuf *arg)
85 return next;
86 }
87
88 -static const char *parse_first_arg(const char *next, struct strbuf *arg)
88 +/*
89 + * Parse the argument immediately after "command SP". If not -z, then
90 + * handle C-quoting. Write the argument to arg. Set *next to point
91 + * at the character that terminates the argument. Die if C-quoting is
92 + * malformed.
93 + */
94 +static void parse_first_arg(struct strbuf *input, const char **next,
95 + struct strbuf *arg)
96 {
90 - /* Parse argument immediately after "command SP" */
97 strbuf_reset(arg);
98 if (line_termination) {
99 /* Without -z, use the next argument */
94 - next = parse_arg(next, arg);
100 + *next = parse_arg(*next, arg);
101 } else {
96 - /* With -z, use rest of first NUL-terminated line */
97 - strbuf_addstr(arg, next);
98 - next = next + arg->len;
102 + /* With -z, use everything up to the next NUL */
103 + strbuf_addstr(arg, *next);
104 + *next += arg->len;
105 }
100 - return next;
106 }
107
103 -static const char *parse_next_arg(const char *next, struct strbuf *arg)
108 +/*
109 + * Parse a SP/NUL separator followed by the next SP- or NUL-terminated
110 + * argument, if any. If there is an argument, write it to arg, set
111 + * *next to point at the character terminating the argument, and
112 + * return 0. If there is no argument at all (not even the empty
113 + * string), return a non-zero result and leave *next unchanged.
114 + */
115 +static int parse_next_arg(struct strbuf *input, const char **next,
116 + struct strbuf *arg)
117 {
105 - /* Parse next SP-terminated or NUL-terminated argument, if any */
118 strbuf_reset(arg);
119 if (line_termination) {
120 /* Without -z, consume SP and use next argument */
109 - if (!*next)
110 - return NULL;
111 - if (*next != ' ')
112 - die("expected SP but got: %s", next);
113 - next = parse_arg(next + 1, arg);
121 + if (!**next || **next == line_termination)
122 + return -1;
123 + if (**next != ' ')
124 + die("expected SP but got: %s", *next);
125 + (*next)++;
126 + *next = parse_arg(*next, arg);
127 } else {
128 /* With -z, read the next NUL-terminated line */
116 - if (*next)
117 - die("expected NUL but got: %s", next);
118 - if (strbuf_getline(arg, stdin, '\0') == EOF)
119 - return NULL;
120 - next = arg->buf + arg->len;
129 + if (**next)
130 + die("expected NUL but got: %s", *next);
131 + (*next)++;
132 + if (*next == input->buf + input->len)
133 + return -1;
134 + strbuf_addstr(arg, *next);
135 + *next += arg->len;
136 }
122 - return next;
137 + return 0;
138 }
139
125 -static void parse_cmd_update(const char *next)
140 +
141 +/*
142 + * The following five parse_cmd_*() functions parse the corresponding
143 + * command. In each case, next points at the character following the
144 + * command name and the following space. They each return a pointer
145 + * to the character terminating the command, and die with an
146 + * explanatory message if there are any parsing problems. All of
147 + * these functions handle either text or binary format input,
148 + * depending on how line_termination is set.
149 + */
150 +
151 +static const char *parse_cmd_update(struct strbuf *input, const char *next)
152 {
153 struct strbuf ref = STRBUF_INIT;
154 struct strbuf newvalue = STRBUF_INIT;
@@ -131,26 +157,28 @@ static void parse_cmd_update(const char *next)
157
158 update = update_alloc();
159
134 - if ((next = parse_first_arg(next, &ref)) != NULL && ref.buf[0])
160 + parse_first_arg(input, &next, &ref);
161 + if (ref.buf[0])
162 update_store_ref_name(update, ref.buf);
163 else
164 die("update line missing <ref>");
165
139 - if ((next = parse_next_arg(next, &newvalue)) != NULL)
166 + if (!parse_next_arg(input, &next, &newvalue))
167 update_store_new_sha1(update, newvalue.buf);
168 else
169 die("update %s missing <newvalue>", ref.buf);
170
144 - if ((next = parse_next_arg(next, &oldvalue)) != NULL)
171 + if (!parse_next_arg(input, &next, &oldvalue)) {
172 update_store_old_sha1(update, oldvalue.buf);
146 - else if(!line_termination)
173 + if (*next != line_termination)
174 + die("update %s has extra input: %s", ref.buf, next);
175 + } else if (!line_termination)
176 die("update %s missing [<oldvalue>] NUL", ref.buf);
177
149 - if (next && *next)
150 - die("update %s has extra input: %s", ref.buf, next);
178 + return next;
179 }
180
153 -static void parse_cmd_create(const char *next)
181 +static const char *parse_cmd_create(struct strbuf *input, const char *next)
182 {
183 struct strbuf ref = STRBUF_INIT;
184 struct strbuf newvalue = STRBUF_INIT;
@@ -158,23 +186,27 @@ static void parse_cmd_create(const char *next)
186
187 update = update_alloc();
188
161 - if ((next = parse_first_arg(next, &ref)) != NULL && ref.buf[0])
189 + parse_first_arg(input, &next, &ref);
190 + if (ref.buf[0])
191 update_store_ref_name(update, ref.buf);
192 else
193 die("create line missing <ref>");
194
166 - if ((next = parse_next_arg(next, &newvalue)) != NULL)
195 + if (!parse_next_arg(input, &next, &newvalue))
196 update_store_new_sha1(update, newvalue.buf);
197 else
198 die("create %s missing <newvalue>", ref.buf);
199 +
200 if (is_null_sha1(update->new_sha1))
201 die("create %s given zero new value", ref.buf);
202
173 - if (next && *next)
203 + if (*next != line_termination)
204 die("create %s has extra input: %s", ref.buf, next);
205 +
206 + return next;
207 }
208
177 -static void parse_cmd_delete(const char *next)
209 +static const char *parse_cmd_delete(struct strbuf *input, const char *next)
210 {
211 struct strbuf ref = STRBUF_INIT;
212 struct strbuf oldvalue = STRBUF_INIT;
@@ -182,23 +214,26 @@ static void parse_cmd_delete(const char *next)
214
215 update = update_alloc();
216
185 - if ((next = parse_first_arg(next, &ref)) != NULL && ref.buf[0])
217 + parse_first_arg(input, &next, &ref);
218 + if (ref.buf[0])
219 update_store_ref_name(update, ref.buf);
220 else
221 die("delete line missing <ref>");
222
190 - if ((next = parse_next_arg(next, &oldvalue)) != NULL)
223 + if (!parse_next_arg(input, &next, &oldvalue)) {
224 update_store_old_sha1(update, oldvalue.buf);
192 - else if(!line_termination)
225 + if (update->have_old && is_null_sha1(update->old_sha1))
226 + die("delete %s given zero old value", ref.buf);
227 + } else if (!line_termination)
228 die("delete %s missing [<oldvalue>] NUL", ref.buf);
194 - if (update->have_old && is_null_sha1(update->old_sha1))
195 - die("delete %s given zero old value", ref.buf);
229
197 - if (next && *next)
230 + if (*next != line_termination)
231 die("delete %s has extra input: %s", ref.buf, next);
232 +
233 + return next;
234 }
235
201 -static void parse_cmd_verify(const char *next)
236 +static const char *parse_cmd_verify(struct strbuf *input, const char *next)
237 {
238 struct strbuf ref = STRBUF_INIT;
239 struct strbuf value = STRBUF_INIT;
@@ -206,53 +241,64 @@ static void parse_cmd_verify(const char *next)
241
242 update = update_alloc();
243
209 - if ((next = parse_first_arg(next, &ref)) != NULL && ref.buf[0])
244 + parse_first_arg(input, &next, &ref);
245 + if (ref.buf[0])
246 update_store_ref_name(update, ref.buf);
247 else
248 die("verify line missing <ref>");
249
214 - if ((next = parse_next_arg(next, &value)) != NULL) {
250 + if (!parse_next_arg(input, &next, &value)) {
251 update_store_old_sha1(update, value.buf);
252 update_store_new_sha1(update, value.buf);
217 - } else if(!line_termination)
253 + } else if (!line_termination)
254 die("verify %s missing [<oldvalue>] NUL", ref.buf);
255
220 - if (next && *next)
256 + if (*next != line_termination)
257 die("verify %s has extra input: %s", ref.buf, next);
258 +
259 + return next;
260 }
261
224 -static void parse_cmd_option(const char *next)
262 +static const char *parse_cmd_option(struct strbuf *input, const char *next)
263 {
226 - if (!strcmp(next, "no-deref"))
264 + if (!strncmp(next, "no-deref", 8) && next[8] == line_termination)
265 update_flags |= REF_NODEREF;
266 else
267 die("option unknown: %s", next);
268 + return next + 8;
269 }
270
271 static void update_refs_stdin(void)
272 {
234 - struct strbuf cmd = STRBUF_INIT;
273 + struct strbuf input = STRBUF_INIT;
274 + const char *next;
275
276 + if (strbuf_read(&input, 0, 1000) < 0)
277 + die_errno("could not read from stdin");
278 + next = input.buf;
279 /* Read each line dispatch its command */
237 - while (strbuf_getline(&cmd, stdin, line_termination) != EOF)
238 - if (!cmd.buf[0])
280 + while (next < input.buf + input.len) {
281 + if (*next == line_termination)
282 die("empty command in input");
240 - else if (isspace(*cmd.buf))
241 - die("whitespace before command: %s", cmd.buf);
242 - else if (starts_with(cmd.buf, "update "))
243 - parse_cmd_update(cmd.buf + 7);
244 - else if (starts_with(cmd.buf, "create "))
245 - parse_cmd_create(cmd.buf + 7);
246 - else if (starts_with(cmd.buf, "delete "))
247 - parse_cmd_delete(cmd.buf + 7);
248 - else if (starts_with(cmd.buf, "verify "))
249 - parse_cmd_verify(cmd.buf + 7);
250 - else if (starts_with(cmd.buf, "option "))
251 - parse_cmd_option(cmd.buf + 7);
283 + else if (isspace(*next))
284 + die("whitespace before command: %s", next);
285 + else if (starts_with(next, "update "))
286 + next = parse_cmd_update(&input, next + 7);
287 + else if (starts_with(next, "create "))
288 + next = parse_cmd_create(&input, next + 7);
289 + else if (starts_with(next, "delete "))
290 + next = parse_cmd_delete(&input, next + 7);
291 + else if (starts_with(next, "verify "))
292 + next = parse_cmd_verify(&input, next + 7);
293 + else if (starts_with(next, "option "))
294 + next = parse_cmd_option(&input, next + 7);
295 else
253 - die("unknown command: %s", cmd.buf);
296 + die("unknown command: %s", next);
297 +
298 + next++;
299 + }
300
255 - strbuf_release(&cmd);
301 + strbuf_release(&input);
302 }
303
304 int cmd_update_ref(int argc, const char **argv, const char *prefix)