am: refactor read_author_script()

By splitting the part that reads from a file and the part that parses the variable definitions from the contents, make the latter can be more reusable in the future. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Aug 30, 2016 at 12:36 UTC a77598ef44c45800983448489ab87f9519e341af
1 file changed +45 -58
builtin/am.c
+45 -58
@@ -28,6 +28,7 @@
28 #include "rerere.h"
29 #include "prompt.h"
30 #include "mailinfo.h"
31 +#include "string-list.h"
32
33 /**
34 * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -258,38 +259,29 @@ static int read_state_file(struct strbuf *sb, const struct am_state *state,
259 }
260
261 /**
261 - * Reads a KEY=VALUE shell variable assignment from `fp`, returning the VALUE
262 - * as a newly-allocated string. VALUE must be a quoted string, and the KEY must
263 - * match `key`. Returns NULL on failure.
264 - *
265 - * This is used by read_author_script() to read the GIT_AUTHOR_* variables from
266 - * the author-script.
262 + * Take a series of KEY='VALUE' lines where VALUE part is
263 + * sq-quoted, and append <KEY, VALUE> at the end of the string list
264 */
268 -static char *read_shell_var(FILE *fp, const char *key)
265 +static int parse_key_value_squoted(char *buf, struct string_list *list)
266 {
270 - struct strbuf sb = STRBUF_INIT;
271 - const char *str;
272 -
273 - if (strbuf_getline_lf(&sb, fp))
274 - goto fail;
275 -
276 - if (!skip_prefix(sb.buf, key, &str))
277 - goto fail;
278 -
279 - if (!skip_prefix(str, "=", &str))
280 - goto fail;
281 -
282 - strbuf_remove(&sb, 0, str - sb.buf);
283 -
284 - str = sq_dequote(sb.buf);
285 - if (!str)
286 - goto fail;
287 -
288 - return strbuf_detach(&sb, NULL);
289 -
290 -fail:
291 - strbuf_release(&sb);
292 - return NULL;
267 + while (*buf) {
268 + struct string_list_item *item;
269 + char *np;
270 + char *cp = strchr(buf, '=');
271 + if (!cp)
272 + return -1;
273 + np = strchrnul(cp, '\n');
274 + *cp++ = '\0';
275 + item = string_list_append(list, buf);
276 +
277 + buf = np + (*np == '\n');
278 + *np = '\0';
279 + cp = sq_dequote(cp);
280 + if (!cp)
281 + return -1;
282 + item->util = xstrdup(cp);
283 + }
284 + return 0;
285 }
286
287 /**
@@ -311,44 +303,39 @@ fail:
303 static int read_author_script(struct am_state *state)
304 {
305 const char *filename = am_path(state, "author-script");
314 - FILE *fp;
306 + struct strbuf buf = STRBUF_INIT;
307 + struct string_list kv = STRING_LIST_INIT_DUP;
308 + int retval = -1; /* assume failure */
309 + int fd;
310
311 assert(!state->author_name);
312 assert(!state->author_email);
313 assert(!state->author_date);
314
320 - fp = fopen(filename, "r");
321 - if (!fp) {
315 + fd = open(filename, O_RDONLY);
316 + if (fd < 0) {
317 if (errno == ENOENT)
318 return 0;
319 die_errno(_("could not open '%s' for reading"), filename);
320 }
321 + strbuf_read(&buf, fd, 0);
322 + close(fd);
323 + if (parse_key_value_squoted(buf.buf, &kv))
324 + goto finish;
325
327 - state->author_name = read_shell_var(fp, "GIT_AUTHOR_NAME");
328 - if (!state->author_name) {
329 - fclose(fp);
330 - return -1;
331 - }
332 -
333 - state->author_email = read_shell_var(fp, "GIT_AUTHOR_EMAIL");
334 - if (!state->author_email) {
335 - fclose(fp);
336 - return -1;
337 - }
338 -
339 - state->author_date = read_shell_var(fp, "GIT_AUTHOR_DATE");
340 - if (!state->author_date) {
341 - fclose(fp);
342 - return -1;
343 - }
344 -
345 - if (fgetc(fp) != EOF) {
346 - fclose(fp);
347 - return -1;
348 - }
349 -
350 - fclose(fp);
351 - return 0;
326 + if (kv.nr != 3 ||
327 + strcmp(kv.items[0].string, "GIT_AUTHOR_NAME") ||
328 + strcmp(kv.items[1].string, "GIT_AUTHOR_EMAIL") ||
329 + strcmp(kv.items[2].string, "GIT_AUTHOR_DATE"))
330 + goto finish;
331 + state->author_name = kv.items[0].util;
332 + state->author_email = kv.items[1].util;
333 + state->author_date = kv.items[2].util;
334 + retval = 0;
335 +finish:
336 + string_list_clear(&kv, !!retval);
337 + strbuf_release(&buf);
338 + return retval;
339 }
340
341 /**