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
/**