@@ -144,6 +144,7 @@ enum atom_type {
144
144
ATOM_BODY ,
145
145
ATOM_TRAILERS ,
146
146
ATOM_CONTENTS ,
147
+ ATOM_RAW ,
147
148
ATOM_UPSTREAM ,
148
149
ATOM_PUSH ,
149
150
ATOM_SYMREF ,
@@ -189,6 +190,9 @@ static struct used_atom {
189
190
struct process_trailer_options trailer_opts ;
190
191
unsigned int nlines ;
191
192
} contents ;
193
+ struct {
194
+ enum { RAW_BARE , RAW_LENGTH } option ;
195
+ } raw_data ;
192
196
struct {
193
197
cmp_status cmp_status ;
194
198
const char * str ;
@@ -426,6 +430,18 @@ static int contents_atom_parser(const struct ref_format *format, struct used_ato
426
430
return 0 ;
427
431
}
428
432
433
+ static int raw_atom_parser (const struct ref_format * format , struct used_atom * atom ,
434
+ const char * arg , struct strbuf * err )
435
+ {
436
+ if (!arg )
437
+ atom -> u .raw_data .option = RAW_BARE ;
438
+ else if (!strcmp (arg , "size" ))
439
+ atom -> u .raw_data .option = RAW_LENGTH ;
440
+ else
441
+ return strbuf_addf_ret (err , -1 , _ ("unrecognized %%(raw) argument: %s" ), arg );
442
+ return 0 ;
443
+ }
444
+
429
445
static int oid_atom_parser (const struct ref_format * format , struct used_atom * atom ,
430
446
const char * arg , struct strbuf * err )
431
447
{
@@ -586,6 +602,7 @@ static struct {
586
602
[ATOM_BODY ] = { "body" , SOURCE_OBJ , FIELD_STR , body_atom_parser },
587
603
[ATOM_TRAILERS ] = { "trailers" , SOURCE_OBJ , FIELD_STR , trailers_atom_parser },
588
604
[ATOM_CONTENTS ] = { "contents" , SOURCE_OBJ , FIELD_STR , contents_atom_parser },
605
+ [ATOM_RAW ] = { "raw" , SOURCE_OBJ , FIELD_STR , raw_atom_parser },
589
606
[ATOM_UPSTREAM ] = { "upstream" , SOURCE_NONE , FIELD_STR , remote_ref_atom_parser },
590
607
[ATOM_PUSH ] = { "push" , SOURCE_NONE , FIELD_STR , remote_ref_atom_parser },
591
608
[ATOM_SYMREF ] = { "symref" , SOURCE_NONE , FIELD_STR , refname_atom_parser },
@@ -620,12 +637,19 @@ struct ref_formatting_state {
620
637
621
638
struct atom_value {
622
639
const char * s ;
640
+ ssize_t s_size ;
623
641
int (* handler )(struct atom_value * atomv , struct ref_formatting_state * state ,
624
642
struct strbuf * err );
625
643
uintmax_t value ; /* used for sorting when not FIELD_STR */
626
644
struct used_atom * atom ;
627
645
};
628
646
647
+ #define ATOM_SIZE_UNSPECIFIED (-1)
648
+
649
+ #define ATOM_VALUE_INIT { \
650
+ .s_size = ATOM_SIZE_UNSPECIFIED \
651
+ }
652
+
629
653
/*
630
654
* Used to parse format string and sort specifiers
631
655
*/
@@ -644,13 +668,6 @@ static int parse_ref_filter_atom(const struct ref_format *format,
644
668
return strbuf_addf_ret (err , -1 , _ ("malformed field name: %.*s" ),
645
669
(int )(ep - atom ), atom );
646
670
647
- /* Do we have the atom already used elsewhere? */
648
- for (i = 0 ; i < used_atom_cnt ; i ++ ) {
649
- int len = strlen (used_atom [i ].name );
650
- if (len == ep - atom && !memcmp (used_atom [i ].name , atom , len ))
651
- return i ;
652
- }
653
-
654
671
/*
655
672
* If the atom name has a colon, strip it and everything after
656
673
* it off - it specifies the format for this entry, and
@@ -660,6 +677,13 @@ static int parse_ref_filter_atom(const struct ref_format *format,
660
677
arg = memchr (sp , ':' , ep - sp );
661
678
atom_len = (arg ? arg : ep ) - sp ;
662
679
680
+ /* Do we have the atom already used elsewhere? */
681
+ for (i = 0 ; i < used_atom_cnt ; i ++ ) {
682
+ int len = strlen (used_atom [i ].name );
683
+ if (len == ep - atom && !memcmp (used_atom [i ].name , atom , len ))
684
+ return i ;
685
+ }
686
+
663
687
/* Is the atom a valid one? */
664
688
for (i = 0 ; i < ARRAY_SIZE (valid_atom ); i ++ ) {
665
689
int len = strlen (valid_atom [i ].name );
@@ -709,11 +733,14 @@ static int parse_ref_filter_atom(const struct ref_format *format,
709
733
return at ;
710
734
}
711
735
712
- static void quote_formatting (struct strbuf * s , const char * str , int quote_style )
736
+ static void quote_formatting (struct strbuf * s , const char * str , ssize_t len , int quote_style )
713
737
{
714
738
switch (quote_style ) {
715
739
case QUOTE_NONE :
716
- strbuf_addstr (s , str );
740
+ if (len < 0 )
741
+ strbuf_addstr (s , str );
742
+ else
743
+ strbuf_add (s , str , len );
717
744
break ;
718
745
case QUOTE_SHELL :
719
746
sq_quote_buf (s , str );
@@ -740,9 +767,11 @@ static int append_atom(struct atom_value *v, struct ref_formatting_state *state,
740
767
* encountered.
741
768
*/
742
769
if (!state -> stack -> prev )
743
- quote_formatting (& state -> stack -> output , v -> s , state -> quote_style );
744
- else
770
+ quote_formatting (& state -> stack -> output , v -> s , v -> s_size , state -> quote_style );
771
+ else if ( v -> s_size < 0 )
745
772
strbuf_addstr (& state -> stack -> output , v -> s );
773
+ else
774
+ strbuf_add (& state -> stack -> output , v -> s , v -> s_size );
746
775
return 0 ;
747
776
}
748
777
@@ -842,21 +871,23 @@ static int if_atom_handler(struct atom_value *atomv, struct ref_formatting_state
842
871
return 0 ;
843
872
}
844
873
845
- static int is_empty (const char * s )
874
+ static int is_empty (struct strbuf * buf )
846
875
{
847
- while (* s != '\0' ) {
848
- if (!isspace (* s ))
849
- return 0 ;
850
- s ++ ;
851
- }
852
- return 1 ;
853
- }
876
+ const char * cur = buf -> buf ;
877
+ const char * end = buf -> buf + buf -> len ;
878
+
879
+ while (cur != end && (isspace (* cur )))
880
+ cur ++ ;
881
+
882
+ return cur == end ;
883
+ }
854
884
855
885
static int then_atom_handler (struct atom_value * atomv , struct ref_formatting_state * state ,
856
886
struct strbuf * err )
857
887
{
858
888
struct ref_formatting_stack * cur = state -> stack ;
859
889
struct if_then_else * if_then_else = NULL ;
890
+ size_t str_len = 0 ;
860
891
861
892
if (cur -> at_end == if_then_else_handler )
862
893
if_then_else = (struct if_then_else * )cur -> at_end_data ;
@@ -867,18 +898,22 @@ static int then_atom_handler(struct atom_value *atomv, struct ref_formatting_sta
867
898
if (if_then_else -> else_atom_seen )
868
899
return strbuf_addf_ret (err , -1 , _ ("format: %%(then) atom used after %%(else)" ));
869
900
if_then_else -> then_atom_seen = 1 ;
901
+ if (if_then_else -> str )
902
+ str_len = strlen (if_then_else -> str );
870
903
/*
871
904
* If the 'equals' or 'notequals' attribute is used then
872
905
* perform the required comparison. If not, only non-empty
873
906
* strings satisfy the 'if' condition.
874
907
*/
875
908
if (if_then_else -> cmp_status == COMPARE_EQUAL ) {
876
- if (!strcmp (if_then_else -> str , cur -> output .buf ))
909
+ if (str_len == cur -> output .len &&
910
+ !memcmp (if_then_else -> str , cur -> output .buf , cur -> output .len ))
877
911
if_then_else -> condition_satisfied = 1 ;
878
912
} else if (if_then_else -> cmp_status == COMPARE_UNEQUAL ) {
879
- if (strcmp (if_then_else -> str , cur -> output .buf ))
913
+ if (str_len != cur -> output .len ||
914
+ memcmp (if_then_else -> str , cur -> output .buf , cur -> output .len ))
880
915
if_then_else -> condition_satisfied = 1 ;
881
- } else if (cur -> output .len && !is_empty (cur -> output . buf ))
916
+ } else if (cur -> output .len && !is_empty (& cur -> output ))
882
917
if_then_else -> condition_satisfied = 1 ;
883
918
strbuf_reset (& cur -> output );
884
919
return 0 ;
@@ -924,7 +959,7 @@ static int end_atom_handler(struct atom_value *atomv, struct ref_formatting_stat
924
959
* only on the topmost supporting atom.
925
960
*/
926
961
if (!current -> prev -> prev ) {
927
- quote_formatting (& s , current -> output .buf , state -> quote_style );
962
+ quote_formatting (& s , current -> output .buf , current -> output . len , state -> quote_style );
928
963
strbuf_swap (& current -> output , & s );
929
964
}
930
965
strbuf_release (& s );
@@ -974,6 +1009,10 @@ int verify_ref_format(struct ref_format *format)
974
1009
at = parse_ref_filter_atom (format , sp + 2 , ep , & err );
975
1010
if (at < 0 )
976
1011
die ("%s" , err .buf );
1012
+ if (format -> quote_style && used_atom [at ].atom_type == ATOM_RAW &&
1013
+ used_atom [at ].u .raw_data .option == RAW_BARE )
1014
+ die (_ ("--format=%.*s cannot be used with"
1015
+ "--python, --shell, --tcl, --perl" ), (int )(ep - sp - 2 ), sp + 2 );
977
1016
cp = ep + 1 ;
978
1017
979
1018
if (skip_prefix (used_atom [at ].name , "color:" , & color ))
@@ -1367,12 +1406,25 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct exp
1367
1406
struct used_atom * atom = & used_atom [i ];
1368
1407
const char * name = atom -> name ;
1369
1408
struct atom_value * v = & val [i ];
1409
+ enum atom_type atom_type = atom -> atom_type ;
1370
1410
1371
1411
if (!!deref != (* name == '*' ))
1372
1412
continue ;
1373
1413
if (deref )
1374
1414
name ++ ;
1375
1415
1416
+ if (atom_type == ATOM_RAW ) {
1417
+ unsigned long buf_size = data -> size ;
1418
+
1419
+ if (atom -> u .raw_data .option == RAW_BARE ) {
1420
+ v -> s = xmemdupz (buf , buf_size );
1421
+ v -> s_size = buf_size ;
1422
+ } else if (atom -> u .raw_data .option == RAW_LENGTH ) {
1423
+ v -> s = xstrfmt ("%" PRIuMAX , (uintmax_t )buf_size );
1424
+ }
1425
+ continue ;
1426
+ }
1427
+
1376
1428
if ((data -> type != OBJ_TAG &&
1377
1429
data -> type != OBJ_COMMIT ) ||
1378
1430
(strcmp (name , "body" ) &&
@@ -1460,9 +1512,11 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, s
1460
1512
break ;
1461
1513
case OBJ_TREE :
1462
1514
/* grab_tree_values(val, deref, obj, buf, sz); */
1515
+ grab_sub_body_contents (val , deref , data );
1463
1516
break ;
1464
1517
case OBJ_BLOB :
1465
1518
/* grab_blob_values(val, deref, obj, buf, sz); */
1519
+ grab_sub_body_contents (val , deref , data );
1466
1520
break ;
1467
1521
default :
1468
1522
die ("Eh? Object of type %d?" , obj -> type );
@@ -1766,6 +1820,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
1766
1820
const char * refname ;
1767
1821
struct branch * branch = NULL ;
1768
1822
1823
+ v -> s_size = ATOM_SIZE_UNSPECIFIED ;
1769
1824
v -> handler = append_atom ;
1770
1825
v -> atom = atom ;
1771
1826
@@ -2369,6 +2424,19 @@ static int compare_detached_head(struct ref_array_item *a, struct ref_array_item
2369
2424
return 0 ;
2370
2425
}
2371
2426
2427
+ static int memcasecmp (const void * vs1 , const void * vs2 , size_t n )
2428
+ {
2429
+ const char * s1 = vs1 , * s2 = vs2 ;
2430
+ const char * end = s1 + n ;
2431
+
2432
+ for (; s1 < end ; s1 ++ , s2 ++ ) {
2433
+ int diff = tolower (* s1 ) - tolower (* s2 );
2434
+ if (diff )
2435
+ return diff ;
2436
+ }
2437
+ return 0 ;
2438
+ }
2439
+
2372
2440
static int cmp_ref_sorting (struct ref_sorting * s , struct ref_array_item * a , struct ref_array_item * b )
2373
2441
{
2374
2442
struct atom_value * va , * vb ;
@@ -2389,10 +2457,29 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru
2389
2457
} else if (s -> sort_flags & REF_SORTING_VERSION ) {
2390
2458
cmp = versioncmp (va -> s , vb -> s );
2391
2459
} else if (cmp_type == FIELD_STR ) {
2392
- int (* cmp_fn )(const char * , const char * );
2393
- cmp_fn = s -> sort_flags & REF_SORTING_ICASE
2394
- ? strcasecmp : strcmp ;
2395
- cmp = cmp_fn (va -> s , vb -> s );
2460
+ if (va -> s_size < 0 && vb -> s_size < 0 ) {
2461
+ int (* cmp_fn )(const char * , const char * );
2462
+ cmp_fn = s -> sort_flags & REF_SORTING_ICASE
2463
+ ? strcasecmp : strcmp ;
2464
+ cmp = cmp_fn (va -> s , vb -> s );
2465
+ } else {
2466
+ size_t a_size = va -> s_size < 0 ?
2467
+ strlen (va -> s ) : va -> s_size ;
2468
+ size_t b_size = vb -> s_size < 0 ?
2469
+ strlen (vb -> s ) : vb -> s_size ;
2470
+ int (* cmp_fn )(const void * , const void * , size_t );
2471
+ cmp_fn = s -> sort_flags & REF_SORTING_ICASE
2472
+ ? memcasecmp : memcmp ;
2473
+
2474
+ cmp = cmp_fn (va -> s , vb -> s , b_size > a_size ?
2475
+ a_size : b_size );
2476
+ if (!cmp ) {
2477
+ if (a_size > b_size )
2478
+ cmp = 1 ;
2479
+ else if (a_size < b_size )
2480
+ cmp = -1 ;
2481
+ }
2482
+ }
2396
2483
} else {
2397
2484
if (va -> value < vb -> value )
2398
2485
cmp = -1 ;
@@ -2491,7 +2578,7 @@ int format_ref_array_item(struct ref_array_item *info,
2491
2578
append_literal (cp , sp , & state );
2492
2579
}
2493
2580
if (format -> need_color_reset_at_eol ) {
2494
- struct atom_value resetv ;
2581
+ struct atom_value resetv = ATOM_VALUE_INIT ;
2495
2582
resetv .s = GIT_COLOR_RESET ;
2496
2583
if (append_atom (& resetv , & state , error_buf )) {
2497
2584
pop_stack_element (& state .stack );
0 commit comments