@@ -22,6 +22,12 @@ struct align {
2222 unsigned int width ;
2323};
2424
25+ struct if_then_else {
26+ unsigned int then_atom_seen : 1 ,
27+ else_atom_seen : 1 ,
28+ condition_satisfied : 1 ;
29+ };
30+
2531/*
2632 * An atom is a valid field atom listed below, possibly prefixed with
2733 * a "*" to denote deref_tag().
@@ -214,14 +220,17 @@ static struct {
214220 { "color" , FIELD_STR , color_atom_parser },
215221 { "align" , FIELD_STR , align_atom_parser },
216222 { "end" },
223+ { "if" },
224+ { "then" },
225+ { "else" },
217226};
218227
219228#define REF_FORMATTING_STATE_INIT { 0, NULL }
220229
221230struct ref_formatting_stack {
222231 struct ref_formatting_stack * prev ;
223232 struct strbuf output ;
224- void (* at_end )(struct ref_formatting_stack * stack );
233+ void (* at_end )(struct ref_formatting_stack * * stack );
225234 void * at_end_data ;
226235};
227236
@@ -354,13 +363,14 @@ static void pop_stack_element(struct ref_formatting_stack **stack)
354363 * stack = prev ;
355364}
356365
357- static void end_align_handler (struct ref_formatting_stack * stack )
366+ static void end_align_handler (struct ref_formatting_stack * * stack )
358367{
359- struct align * align = (struct align * )stack -> at_end_data ;
368+ struct ref_formatting_stack * cur = * stack ;
369+ struct align * align = (struct align * )cur -> at_end_data ;
360370 struct strbuf s = STRBUF_INIT ;
361371
362- strbuf_utf8_align (& s , align -> position , align -> width , stack -> output .buf );
363- strbuf_swap (& stack -> output , & s );
372+ strbuf_utf8_align (& s , align -> position , align -> width , cur -> output .buf );
373+ strbuf_swap (& cur -> output , & s );
364374 strbuf_release (& s );
365375}
366376
@@ -374,21 +384,122 @@ static void align_atom_handler(struct atom_value *atomv, struct ref_formatting_s
374384 new -> at_end_data = & atomv -> u .align ;
375385}
376386
387+ static void if_then_else_handler (struct ref_formatting_stack * * stack )
388+ {
389+ struct ref_formatting_stack * cur = * stack ;
390+ struct ref_formatting_stack * prev = cur -> prev ;
391+ struct if_then_else * if_then_else = (struct if_then_else * )cur -> at_end_data ;
392+
393+ if (!if_then_else -> then_atom_seen )
394+ die (_ ("format: %%(if) atom used without a %%(then) atom" ));
395+
396+ if (if_then_else -> else_atom_seen ) {
397+ /*
398+ * There is an %(else) atom: we need to drop one state from the
399+ * stack, either the %(else) branch if the condition is satisfied, or
400+ * the %(then) branch if it isn't.
401+ */
402+ if (if_then_else -> condition_satisfied ) {
403+ strbuf_reset (& cur -> output );
404+ pop_stack_element (& cur );
405+ } else {
406+ strbuf_swap (& cur -> output , & prev -> output );
407+ strbuf_reset (& cur -> output );
408+ pop_stack_element (& cur );
409+ }
410+ } else if (!if_then_else -> condition_satisfied ) {
411+ /*
412+ * No %(else) atom: just drop the %(then) branch if the
413+ * condition is not satisfied.
414+ */
415+ strbuf_reset (& cur -> output );
416+ }
417+
418+ * stack = cur ;
419+ free (if_then_else );
420+ }
421+
422+ static void if_atom_handler (struct atom_value * atomv , struct ref_formatting_state * state )
423+ {
424+ struct ref_formatting_stack * new ;
425+ struct if_then_else * if_then_else = xcalloc (sizeof (struct if_then_else ), 1 );
426+
427+ push_stack_element (& state -> stack );
428+ new = state -> stack ;
429+ new -> at_end = if_then_else_handler ;
430+ new -> at_end_data = if_then_else ;
431+ }
432+
433+ static int is_empty (const char * s )
434+ {
435+ while (* s != '\0' ) {
436+ if (!isspace (* s ))
437+ return 0 ;
438+ s ++ ;
439+ }
440+ return 1 ;
441+ }
442+
443+ static void then_atom_handler (struct atom_value * atomv , struct ref_formatting_state * state )
444+ {
445+ struct ref_formatting_stack * cur = state -> stack ;
446+ struct if_then_else * if_then_else = NULL ;
447+
448+ if (cur -> at_end == if_then_else_handler )
449+ if_then_else = (struct if_then_else * )cur -> at_end_data ;
450+ if (!if_then_else )
451+ die (_ ("format: %%(then) atom used without an %%(if) atom" ));
452+ if (if_then_else -> then_atom_seen )
453+ die (_ ("format: %%(then) atom used more than once" ));
454+ if (if_then_else -> else_atom_seen )
455+ die (_ ("format: %%(then) atom used after %%(else)" ));
456+ if_then_else -> then_atom_seen = 1 ;
457+ /*
458+ * If there exists non-empty string between the 'if' and
459+ * 'then' atom then the 'if' condition is satisfied.
460+ */
461+ if (cur -> output .len && !is_empty (cur -> output .buf ))
462+ if_then_else -> condition_satisfied = 1 ;
463+ strbuf_reset (& cur -> output );
464+ }
465+
466+ static void else_atom_handler (struct atom_value * atomv , struct ref_formatting_state * state )
467+ {
468+ struct ref_formatting_stack * prev = state -> stack ;
469+ struct if_then_else * if_then_else = NULL ;
470+
471+ if (prev -> at_end == if_then_else_handler )
472+ if_then_else = (struct if_then_else * )prev -> at_end_data ;
473+ if (!if_then_else )
474+ die (_ ("format: %%(else) atom used without an %%(if) atom" ));
475+ if (!if_then_else -> then_atom_seen )
476+ die (_ ("format: %%(else) atom used without a %%(then) atom" ));
477+ if (if_then_else -> else_atom_seen )
478+ die (_ ("format: %%(else) atom used more than once" ));
479+ if_then_else -> else_atom_seen = 1 ;
480+ push_stack_element (& state -> stack );
481+ state -> stack -> at_end_data = prev -> at_end_data ;
482+ state -> stack -> at_end = prev -> at_end ;
483+ }
484+
377485static void end_atom_handler (struct atom_value * atomv , struct ref_formatting_state * state )
378486{
379487 struct ref_formatting_stack * current = state -> stack ;
380488 struct strbuf s = STRBUF_INIT ;
381489
382490 if (!current -> at_end )
383491 die (_ ("format: %%(end) atom used without corresponding atom" ));
384- current -> at_end (current );
492+ current -> at_end (& state -> stack );
493+
494+ /* Stack may have been popped within at_end(), hence reset the current pointer */
495+ current = state -> stack ;
385496
386497 /*
387498 * Perform quote formatting when the stack element is that of
388499 * a supporting atom. If nested then perform quote formatting
389500 * only on the topmost supporting atom.
390501 */
391- if (!state -> stack -> prev -> prev ) {
502+ if (!current -> prev -> prev ) {
392503 quote_formatting (& s , current -> output .buf , state -> quote_style );
393504 strbuf_swap (& current -> output , & s );
394505 }
@@ -1049,6 +1160,15 @@ static void populate_value(struct ref_array_item *ref)
10491160 } else if (!strcmp (name , "end" )) {
10501161 v -> handler = end_atom_handler ;
10511162 continue ;
1163+ } else if (!strcmp (name , "if" )) {
1164+ v -> handler = if_atom_handler ;
1165+ continue ;
1166+ } else if (!strcmp (name , "then" )) {
1167+ v -> handler = then_atom_handler ;
1168+ continue ;
1169+ } else if (!strcmp (name , "else" )) {
1170+ v -> handler = else_atom_handler ;
1171+ continue ;
10521172 } else
10531173 continue ;
10541174
0 commit comments