aboutsummaryrefslogtreecommitdiff
path: root/ref-filter.c
diff options
context:
space:
mode:
Diffstat (limited to 'ref-filter.c')
-rw-r--r--ref-filter.c78
1 files changed, 59 insertions, 19 deletions
diff --git a/ref-filter.c b/ref-filter.c
index e53c77e86..432cea026 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -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');
}