ref-filter: introduce ref_formatting_state and ref_formatting_stack
[gitweb.git] / ref-filter.c
index e53c77e86b99929a3e8efee9ddebf5cc2c547ed1..432cea0265062b2a1f34bc9d85487bb6b6e68ecd 100644 (file)
@@ -55,6 +55,18 @@ static struct {
        { "color" },
 };
 
+#define REF_FORMATTING_STATE_INIT  { 0, NULL }
+
+struct ref_formatting_stack {
+       struct ref_formatting_stack *prev;
+       struct strbuf output;
+};
+
+struct ref_formatting_state {
+       int quote_style;
+       struct ref_formatting_stack *stack;
+};
+
 struct atom_value {
        const char *s;
        unsigned long ul; /* used for sorting when not FIELD_STR */
@@ -129,6 +141,27 @@ int parse_ref_filter_atom(const char *atom, const char *ep)
        return at;
 }
 
+static void push_stack_element(struct ref_formatting_stack **stack)
+{
+       struct ref_formatting_stack *s = xcalloc(1, sizeof(struct ref_formatting_stack));
+
+       strbuf_init(&s->output, 0);
+       s->prev = *stack;
+       *stack = s;
+}
+
+static void pop_stack_element(struct ref_formatting_stack **stack)
+{
+       struct ref_formatting_stack *current = *stack;
+       struct ref_formatting_stack *prev = current->prev;
+
+       if (prev)
+               strbuf_addbuf(&prev->output, &current->output);
+       strbuf_release(&current->output);
+       free(current);
+       *stack = prev;
+}
+
 /*
  * In a format string, find the next occurrence of %(atom).
  */
@@ -1195,30 +1228,27 @@ void ref_array_sort(struct ref_sorting *sorting, struct ref_array *array)
        qsort(array->items, array->nr, sizeof(struct ref_array_item *), compare_refs);
 }
 
-static void print_value(struct atom_value *v, int quote_style)
+static void append_atom(struct atom_value *v, struct ref_formatting_state *state)
 {
-       struct strbuf sb = STRBUF_INIT;
-       switch (quote_style) {
+       struct strbuf *s = &state->stack->output;
+
+       switch (state->quote_style) {
        case QUOTE_NONE:
-               fputs(v->s, stdout);
+               strbuf_addstr(s, v->s);
                break;
        case QUOTE_SHELL:
-               sq_quote_buf(&sb, v->s);
+               sq_quote_buf(s, v->s);
                break;
        case QUOTE_PERL:
-               perl_quote_buf(&sb, v->s);
+               perl_quote_buf(s, v->s);
                break;
        case QUOTE_PYTHON:
-               python_quote_buf(&sb, v->s);
+               python_quote_buf(s, v->s);
                break;
        case QUOTE_TCL:
-               tcl_quote_buf(&sb, v->s);
+               tcl_quote_buf(s, v->s);
                break;
        }
-       if (quote_style != QUOTE_NONE) {
-               fputs(sb.buf, stdout);
-               strbuf_release(&sb);
-       }
 }
 
 static int hex1(char ch)
@@ -1239,8 +1269,10 @@ static int hex2(const char *cp)
                return -1;
 }
 
-static void emit(const char *cp, const char *ep)
+static void append_literal(const char *cp, const char *ep, struct ref_formatting_state *state)
 {
+       struct strbuf *s = &state->stack->output;
+
        while (*cp && (!ep || cp < ep)) {
                if (*cp == '%') {
                        if (cp[1] == '%')
@@ -1248,13 +1280,13 @@ static void emit(const char *cp, const char *ep)
                        else {
                                int ch = hex2(cp + 1);
                                if (0 <= ch) {
-                                       putchar(ch);
+                                       strbuf_addch(s, ch);
                                        cp += 3;
                                        continue;
                                }
                        }
                }
-               putchar(*cp);
+               strbuf_addch(s, *cp);
                cp++;
        }
 }
@@ -1262,19 +1294,24 @@ static void emit(const char *cp, const char *ep)
 void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style)
 {
        const char *cp, *sp, *ep;
+       struct strbuf *final_buf;
+       struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
+
+       state.quote_style = quote_style;
+       push_stack_element(&state.stack);
 
        for (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) {
                struct atom_value *atomv;
 
                ep = strchr(sp, ')');
                if (cp < sp)
-                       emit(cp, sp);
+                       append_literal(cp, sp, &state);
                get_ref_atom_value(info, parse_ref_filter_atom(sp + 2, ep), &atomv);
-               print_value(atomv, quote_style);
+               append_atom(atomv, &state);
        }
        if (*cp) {
                sp = cp + strlen(cp);
-               emit(cp, sp);
+               append_literal(cp, sp, &state);
        }
        if (need_color_reset_at_eol) {
                struct atom_value resetv;
@@ -1283,8 +1320,11 @@ void show_ref_array_item(struct ref_array_item *info, const char *format, int qu
                if (color_parse("reset", color) < 0)
                        die("BUG: couldn't parse 'reset' as a color");
                resetv.s = color;
-               print_value(&resetv, quote_style);
+               append_atom(&resetv, &state);
        }
+       final_buf = &state.stack->output;
+       fwrite(final_buf->buf, 1, final_buf->len, stdout);
+       pop_stack_element(&state.stack);
        putchar('\n');
 }