Phillip Wood <phillip.wood@xxxxxxxxxxxx> writes: > From: Phillip Wood <phillip.wood@xxxxxxxxxxxxx> > > If there are errors in a user edited author-script there was no > indication of what was wrong. This commit adds some specific error messages > depending on the problem. It also relaxes the requirement that the > variables appear in a specific order in the file to match the behavior > of 'rebase --interactive'. That relaxing is sensible; there is no reason to insist that the file we are reading was written by exactly the same writer as we have. > diff --git a/builtin/am.c b/builtin/am.c > index b68578bc3f..d42b725273 100644 > --- a/builtin/am.c > +++ b/builtin/am.c > @@ -270,8 +270,11 @@ static int parse_key_value_squoted(char *buf, struct string_list *list) > struct string_list_item *item; > char *np; > char *cp = strchr(buf, '='); > - if (!cp) > - return -1; > + if (!cp) { > + np = strchrnul(buf, '\n'); > + return error(_("unable to parse '%.*s'"), > + (int) (np - buf), buf); > + } We are unable to parse because it is not of KEY='VALUE' form. Is that something worth reporting, e.g. "no key present in '%.*s'"? > @@ -280,7 +283,8 @@ static int parse_key_value_squoted(char *buf, struct string_list *list) > *np = '\0'; > cp = sq_dequote(cp); > if (!cp) > - return -1; > + return error(_("unable to dequote value of '%s'"), > + item->string); At this point, item->string is what we earlier found on the left hand side of the '=', i.e. the key. The message makes sense. > @@ -308,6 +312,7 @@ static int read_author_script(struct am_state *state) > struct strbuf buf = STRBUF_INIT; > struct string_list kv = STRING_LIST_INIT_DUP; > int retval = -1; /* assume failure */ > + int i, name_i = -2, email_i = -2, date_i = -2, err = 0; That -2 is somewhat cute. If we find a dup, then it will become -1 so later check for missing field would not trigger. > @@ -326,14 +331,38 @@ static int read_author_script(struct am_state *state) > 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")) > + for (i = 0; i < kv.nr; i++) { > + if (!strcmp(kv.items[i].string, "GIT_AUTHOR_NAME")) { > + if (name_i >= 0) > + name_i = error(_("'GIT_AUTHOR_NAME' already given")); > + else > + name_i = i; However, if you have three instances of GIT_AUTHOR_NAME, then - the first one makes name_i point at it - the second one triggers an error and name_i becomes -1 - the third one makes name_i point at it again And name_i is not -2 so we won't give "missing" error, which is OK, but we end up having a usable name even though we said we detected duplicate! You can probably compare name_i with -2 when detecting the dup to fix it, i.e. if (name_i != -2) name_i = error("found dup"); else name_i = i; > + } else if (!strcmp(kv.items[i].string, "GIT_AUTHOR_EMAIL")) { > + if (email_i >= 0) > + email_i = error(_("'GIT_AUTHOR_EMAIL' already given")); > + else > + email_i = i; > + } else if (!strcmp(kv.items[i].string, "GIT_AUTHOR_DATE")) { > + if (date_i >= 0) > + date_i = error(_("'GIT_AUTHOR_DATE' already given")); > + else > + date_i = i; > + } else { > + err = error(_("unknown variable '%s'"), > + kv.items[i].string); > + } > + } > + if (name_i == -2) > + error(_("missing 'GIT_AUTHOR_NAME'")); > + if (email_i == -2) > + error(_("missing 'GIT_AUTHOR_EMAIL'")); > + if (date_i == -2) > + error(_("missing 'GIT_AUTHOR_DATE'")); > + if (date_i < 0 || email_i < 0 || date_i < 0 || err) > goto finish; > - state->author_name = kv.items[0].util; > - state->author_email = kv.items[1].util; > - state->author_date = kv.items[2].util; > + state->author_name = kv.items[name_i].util; > + state->author_email = kv.items[email_i].util; > + state->author_date = kv.items[date_i].util; > retval = 0; > finish: > string_list_clear(&kv, !!retval);