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)