@@ -22,6 +22,12 @@ struct align {
22
22
unsigned int width ;
23
23
};
24
24
25
+ struct if_then_else {
26
+ unsigned int then_atom_seen : 1 ,
27
+ else_atom_seen : 1 ,
28
+ condition_satisfied : 1 ;
29
+ };
30
+
25
31
/*
26
32
* An atom is a valid field atom listed below, possibly prefixed with
27
33
* a "*" to denote deref_tag().
@@ -214,14 +220,17 @@ static struct {
214
220
{ "color" , FIELD_STR , color_atom_parser },
215
221
{ "align" , FIELD_STR , align_atom_parser },
216
222
{ "end" },
223
+ { "if" },
224
+ { "then" },
225
+ { "else" },
217
226
};
218
227
219
228
#define REF_FORMATTING_STATE_INIT { 0, NULL }
220
229
221
230
struct ref_formatting_stack {
222
231
struct ref_formatting_stack * prev ;
223
232
struct strbuf output ;
224
- void (* at_end )(struct ref_formatting_stack * stack );
233
+ void (* at_end )(struct ref_formatting_stack * * stack );
225
234
void * at_end_data ;
226
235
};
227
236
@@ -354,13 +363,14 @@ static void pop_stack_element(struct ref_formatting_stack **stack)
354
363
* stack = prev ;
355
364
}
356
365
357
- static void end_align_handler (struct ref_formatting_stack * stack )
366
+ static void end_align_handler (struct ref_formatting_stack * * stack )
358
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 ;
360
370
struct strbuf s = STRBUF_INIT ;
361
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 );
364
374
strbuf_release (& s );
365
375
}
366
376
@@ -374,21 +384,122 @@ static void align_atom_handler(struct atom_value *atomv, struct ref_formatting_s
374
384
new -> at_end_data = & atomv -> u .align ;
375
385
}
376
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
+
377
485
static void end_atom_handler (struct atom_value * atomv , struct ref_formatting_state * state )
378
486
{
379
487
struct ref_formatting_stack * current = state -> stack ;
380
488
struct strbuf s = STRBUF_INIT ;
381
489
382
490
if (!current -> at_end )
383
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 ;
385
496
386
497
/*
387
498
* Perform quote formatting when the stack element is that of
388
499
* a supporting atom. If nested then perform quote formatting
389
500
* only on the topmost supporting atom.
390
501
*/
391
- if (!state -> stack -> prev -> prev ) {
502
+ if (!current -> prev -> prev ) {
392
503
quote_formatting (& s , current -> output .buf , state -> quote_style );
393
504
strbuf_swap (& current -> output , & s );
394
505
}
@@ -1049,6 +1160,15 @@ static void populate_value(struct ref_array_item *ref)
1049
1160
} else if (!strcmp (name , "end" )) {
1050
1161
v -> handler = end_atom_handler ;
1051
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 ;
1052
1172
} else
1053
1173
continue ;
1054
1174
0 commit comments