22
unsigned int width;
23
};
24
25
+struct if_then_else {
26
+ unsigned int then_atom_seen : 1,
27
+ else_atom_seen : 1,
28
+ condition_satisfied : 1;
29
+};
30
+
31
/*
32
* An atom is a valid field atom listed below, possibly prefixed with
33
* a "*" to denote deref_tag().
220
{ "color", FIELD_STR, color_atom_parser },
221
{ "align", FIELD_STR, align_atom_parser },
222
{ "end" },
223
+ { "if" },
224
+ { "then" },
225
+ { "else" },
226
};
227
228
#define REF_FORMATTING_STATE_INIT { 0, NULL }
230
struct ref_formatting_stack {
231
struct ref_formatting_stack *prev;
232
struct strbuf output;
224
- void (*at_end)(struct ref_formatting_stack *stack);
233
+ void (*at_end)(struct ref_formatting_stack **stack);
234
void *at_end_data;
235
};
236
363
*stack = prev;
364
}
365
357
-static void end_align_handler(struct ref_formatting_stack *stack)
366
+static void end_align_handler(struct ref_formatting_stack **stack)
367
{
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;
370
struct strbuf s = STRBUF_INIT;
371
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);
374
strbuf_release(&s);
375
}
376
384
new->at_end_data = &atomv->u.align;
385
}
386
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
+
485
static void end_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
486
{
487
struct ref_formatting_stack *current = state->stack;
489
490
if (!current->at_end)
491
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;
496
497
/*
498
* Perform quote formatting when the stack element is that of
499
* a supporting atom. If nested then perform quote formatting
500
* only on the topmost supporting atom.
501
*/
391
- if (!state->stack->prev->prev) {
502
+ if (!current->prev->prev) {
503
quote_formatting(&s, current->output.buf, state->quote_style);
504
strbuf_swap(¤t->output, &s);
505
}
1160
} else if (!strcmp(name, "end")) {
1161
v->handler = end_atom_handler;
1162
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;
1172
} else
1173
continue;
1174