On 13 March 2018 at 11:16, Olga Telezhnaya <olyatelezhnaya@xxxxxxxxx> wrote: > Continue removing any printing from ref-filter formatting logic, > so that it could be more general. > > Change the signature of parse_ref_filter_atom() by changing return value, > adding previous return value to function parameter and also adding > strbuf parameter for error message. I think the current return value is always non-negative. Maybe it would be easier to leave the return value as-is, except return negative on error? Unless I am missing something? > > Signed-off-by: Olga Telezhnaia <olyatelezhnaya@xxxxxxxxx> > --- > ref-filter.c | 45 ++++++++++++++++++++++++++++++++------------- > 1 file changed, 32 insertions(+), 13 deletions(-) > > diff --git a/ref-filter.c b/ref-filter.c > index 07bedc636398c..e146215bf1e64 100644 > --- a/ref-filter.c > +++ b/ref-filter.c > @@ -397,7 +397,8 @@ struct atom_value { > * Used to parse format string and sort specifiers > */ > static int parse_ref_filter_atom(const struct ref_format *format, > - const char *atom, const char *ep) > + const char *atom, const char *ep, int *res, > + struct strbuf *err) > { > const char *sp; > const char *arg; > @@ -406,14 +407,18 @@ static int parse_ref_filter_atom(const struct ref_format *format, > sp = atom; > if (*sp == '*' && sp < ep) > sp++; /* deref */ > - if (ep <= sp) > - die(_("malformed field name: %.*s"), (int)(ep-atom), atom); > + if (ep <= sp) { > + strbuf_addf(err, _("malformed field name: %.*s"), (int)(ep-atom), atom); > + return -1; > + } > > /* Do we have the atom already used elsewhere? */ > for (i = 0; i < used_atom_cnt; i++) { > int len = strlen(used_atom[i].name); > - if (len == ep - atom && !memcmp(used_atom[i].name, atom, len)) > - return i; > + if (len == ep - atom && !memcmp(used_atom[i].name, atom, len)) { > + *res = i; > + return 0; > + } > } If you did so, this hunk above would not need to be changed ... > @@ -458,7 +465,8 @@ static int parse_ref_filter_atom(const struct ref_format *format, > need_tagged = 1; > if (!strcmp(valid_atom[i].name, "symref")) > need_symref = 1; > - return at; > + *res = at; > + return 0; > } ... nor this one above ... > if (!ep) > return error(_("malformed format string %s"), sp); > /* sp points at "%(" and ep points at the closing ")" */ > - at = parse_ref_filter_atom(format, sp + 2, ep); > + if (parse_ref_filter_atom(format, sp + 2, ep, &at, &err)) > + die("%s", err.buf); And this would be more like "if (at < 0) die(...)". > for (cp = format->format; *cp && (sp = find_next(cp)); cp = ep + 1) { > struct atom_value *atomv; > + struct strbuf err = STRBUF_INIT; > + int pos; > > ep = strchr(sp, ')'); > if (cp < sp) > append_literal(cp, sp, &state); > - get_ref_atom_value(info, > - parse_ref_filter_atom(format, sp + 2, ep), > - &atomv); > + if (parse_ref_filter_atom(format, sp + 2, ep, &pos, &err)) > + return -1; > + get_ref_atom_value(info, pos, &atomv); > if (atomv->handler(atomv, &state, error_buf)) > return -1; > + strbuf_release(&err); This looks leaky: if we get an error, we've got something in the buffer but we do not release it because we return early. Stepping back a bit, I wonder why we do not do anything at all with "err". Stepping back a bit more :-) I wonder if you could get rid of "err" and pass "error_buf" to parse_ref_filter_atom() instead. Our caller would like to have access to the error string? This ties back to my comment on the first patch -- "return negative if and only if you add some error string to the buffer" might be a useful rule? Martin