Merge branch 'jc/am-read-author-file' into maint
authorJunio C Hamano <gitster@pobox.com>
Tue, 29 Nov 2016 21:27:53 +0000 (13:27 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 29 Nov 2016 21:27:53 +0000 (13:27 -0800)
Extract a small helper out of the function that reads the authors
script file "git am" internally uses.
This by itself is not useful until a second caller appears in the
future for "rebase -i" helper.

* jc/am-read-author-file:
am: refactor read_author_script()

1  2 
builtin/am.c
diff --combined builtin/am.c
index 9e2ae5cba40ece7fa8c489a18ba610ab2f4f6e2f,b36d1f047d8124e3aeab5fabb24dd2bb2a003fdf..9daeb27225c04c28e33adc7b8e9071d825a490de
@@@ -28,6 -28,7 +28,7 @@@
  #include "rerere.h"
  #include "prompt.h"
  #include "mailinfo.h"
+ #include "string-list.h"
  
  /**
   * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@@ -258,38 -259,29 +259,29 @@@ static int read_state_file(struct strbu
  }
  
  /**
-  * Reads a KEY=VALUE shell variable assignment from `fp`, returning the VALUE
-  * as a newly-allocated string. VALUE must be a quoted string, and the KEY must
-  * match `key`. Returns NULL on failure.
-  *
-  * This is used by read_author_script() to read the GIT_AUTHOR_* variables from
-  * the author-script.
+  * Take a series of KEY='VALUE' lines where VALUE part is
+  * sq-quoted, and append <KEY, VALUE> at the end of the string list
   */
- static char *read_shell_var(FILE *fp, const char *key)
+ static int parse_key_value_squoted(char *buf, struct string_list *list)
  {
-       struct strbuf sb = STRBUF_INIT;
-       const char *str;
-       if (strbuf_getline_lf(&sb, fp))
-               goto fail;
-       if (!skip_prefix(sb.buf, key, &str))
-               goto fail;
-       if (!skip_prefix(str, "=", &str))
-               goto fail;
-       strbuf_remove(&sb, 0, str - sb.buf);
-       str = sq_dequote(sb.buf);
-       if (!str)
-               goto fail;
-       return strbuf_detach(&sb, NULL);
- fail:
-       strbuf_release(&sb);
-       return NULL;
+       while (*buf) {
+               struct string_list_item *item;
+               char *np;
+               char *cp = strchr(buf, '=');
+               if (!cp)
+                       return -1;
+               np = strchrnul(cp, '\n');
+               *cp++ = '\0';
+               item = string_list_append(list, buf);
+               buf = np + (*np == '\n');
+               *np = '\0';
+               cp = sq_dequote(cp);
+               if (!cp)
+                       return -1;
+               item->util = xstrdup(cp);
+       }
+       return 0;
  }
  
  /**
  static int read_author_script(struct am_state *state)
  {
        const char *filename = am_path(state, "author-script");
-       FILE *fp;
+       struct strbuf buf = STRBUF_INIT;
+       struct string_list kv = STRING_LIST_INIT_DUP;
+       int retval = -1; /* assume failure */
+       int fd;
  
        assert(!state->author_name);
        assert(!state->author_email);
        assert(!state->author_date);
  
-       fp = fopen(filename, "r");
-       if (!fp) {
+       fd = open(filename, O_RDONLY);
+       if (fd < 0) {
                if (errno == ENOENT)
                        return 0;
                die_errno(_("could not open '%s' for reading"), filename);
        }
-       state->author_name = read_shell_var(fp, "GIT_AUTHOR_NAME");
-       if (!state->author_name) {
-               fclose(fp);
-               return -1;
-       }
-       state->author_email = read_shell_var(fp, "GIT_AUTHOR_EMAIL");
-       if (!state->author_email) {
-               fclose(fp);
-               return -1;
-       }
-       state->author_date = read_shell_var(fp, "GIT_AUTHOR_DATE");
-       if (!state->author_date) {
-               fclose(fp);
-               return -1;
-       }
-       if (fgetc(fp) != EOF) {
-               fclose(fp);
-               return -1;
-       }
-       fclose(fp);
-       return 0;
+       strbuf_read(&buf, fd, 0);
+       close(fd);
+       if (parse_key_value_squoted(buf.buf, &kv))
+               goto finish;
+       if (kv.nr != 3 ||
+           strcmp(kv.items[0].string, "GIT_AUTHOR_NAME") ||
+           strcmp(kv.items[1].string, "GIT_AUTHOR_EMAIL") ||
+           strcmp(kv.items[2].string, "GIT_AUTHOR_DATE"))
+               goto finish;
+       state->author_name = kv.items[0].util;
+       state->author_email = kv.items[1].util;
+       state->author_date = kv.items[2].util;
+       retval = 0;
+ finish:
+       string_list_clear(&kv, !!retval);
+       strbuf_release(&buf);
+       return retval;
  }
  
  /**
@@@ -2222,7 -2209,7 +2209,7 @@@ int cmd_am(int argc, const char **argv
        int in_progress;
  
        const char * const usage[] = {
 -              N_("git am [<options>] [(<mbox>|<Maildir>)...]"),
 +              N_("git am [<options>] [(<mbox> | <Maildir>)...]"),
                N_("git am [<options>] (--continue | --skip | --abort)"),
                NULL
        };