@@ -653,7 +653,45 @@ static int get_base_var(struct strbuf *name)
653
653
}
654
654
}
655
655
656
- static int git_parse_source (config_fn_t fn , void * data )
656
+ struct parse_event_data {
657
+ enum config_event_t previous_type ;
658
+ size_t previous_offset ;
659
+ const struct config_options * opts ;
660
+ };
661
+
662
+ static int do_event (enum config_event_t type , struct parse_event_data * data )
663
+ {
664
+ size_t offset ;
665
+
666
+ if (!data -> opts || !data -> opts -> event_fn )
667
+ return 0 ;
668
+
669
+ if (type == CONFIG_EVENT_WHITESPACE &&
670
+ data -> previous_type == type )
671
+ return 0 ;
672
+
673
+ offset = cf -> do_ftell (cf );
674
+ /*
675
+ * At EOF, the parser always "inserts" an extra '\n', therefore
676
+ * the end offset of the event is the current file position, otherwise
677
+ * we will already have advanced to the next event.
678
+ */
679
+ if (type != CONFIG_EVENT_EOF )
680
+ offset -- ;
681
+
682
+ if (data -> previous_type != CONFIG_EVENT_EOF &&
683
+ data -> opts -> event_fn (data -> previous_type , data -> previous_offset ,
684
+ offset , data -> opts -> event_fn_data ) < 0 )
685
+ return -1 ;
686
+
687
+ data -> previous_type = type ;
688
+ data -> previous_offset = offset ;
689
+
690
+ return 0 ;
691
+ }
692
+
693
+ static int git_parse_source (config_fn_t fn , void * data ,
694
+ const struct config_options * opts )
657
695
{
658
696
int comment = 0 ;
659
697
int baselen = 0 ;
@@ -664,8 +702,15 @@ static int git_parse_source(config_fn_t fn, void *data)
664
702
/* U+FEFF Byte Order Mark in UTF8 */
665
703
const char * bomptr = utf8_bom ;
666
704
705
+ /* For the parser event callback */
706
+ struct parse_event_data event_data = {
707
+ CONFIG_EVENT_EOF , 0 , opts
708
+ };
709
+
667
710
for (;;) {
668
- int c = get_next_char ();
711
+ int c ;
712
+
713
+ c = get_next_char ();
669
714
if (bomptr && * bomptr ) {
670
715
/* We are at the file beginning; skip UTF8-encoded BOM
671
716
* if present. Sane editors won't put this in on their
@@ -682,18 +727,33 @@ static int git_parse_source(config_fn_t fn, void *data)
682
727
}
683
728
}
684
729
if (c == '\n' ) {
685
- if (cf -> eof )
730
+ if (cf -> eof ) {
731
+ if (do_event (CONFIG_EVENT_EOF , & event_data ) < 0 )
732
+ return -1 ;
686
733
return 0 ;
734
+ }
735
+ if (do_event (CONFIG_EVENT_WHITESPACE , & event_data ) < 0 )
736
+ return -1 ;
687
737
comment = 0 ;
688
738
continue ;
689
739
}
690
- if (comment || isspace ( c ) )
740
+ if (comment )
691
741
continue ;
742
+ if (isspace (c )) {
743
+ if (do_event (CONFIG_EVENT_WHITESPACE , & event_data ) < 0 )
744
+ return -1 ;
745
+ continue ;
746
+ }
692
747
if (c == '#' || c == ';' ) {
748
+ if (do_event (CONFIG_EVENT_COMMENT , & event_data ) < 0 )
749
+ return -1 ;
693
750
comment = 1 ;
694
751
continue ;
695
752
}
696
753
if (c == '[' ) {
754
+ if (do_event (CONFIG_EVENT_SECTION , & event_data ) < 0 )
755
+ return -1 ;
756
+
697
757
/* Reset prior to determining a new stem */
698
758
strbuf_reset (var );
699
759
if (get_base_var (var ) < 0 || var -> len < 1 )
@@ -704,6 +764,10 @@ static int git_parse_source(config_fn_t fn, void *data)
704
764
}
705
765
if (!isalpha (c ))
706
766
break ;
767
+
768
+ if (do_event (CONFIG_EVENT_ENTRY , & event_data ) < 0 )
769
+ return -1 ;
770
+
707
771
/*
708
772
* Truncate the var name back to the section header
709
773
* stem prior to grabbing the suffix part of the name
@@ -715,6 +779,9 @@ static int git_parse_source(config_fn_t fn, void *data)
715
779
break ;
716
780
}
717
781
782
+ if (do_event (CONFIG_EVENT_ERROR , & event_data ) < 0 )
783
+ return -1 ;
784
+
718
785
switch (cf -> origin_type ) {
719
786
case CONFIG_ORIGIN_BLOB :
720
787
error_msg = xstrfmt (_ ("bad config line %d in blob %s" ),
@@ -1390,7 +1457,8 @@ int git_default_config(const char *var, const char *value, void *dummy)
1390
1457
* fgetc, ungetc, ftell of top need to be initialized before calling
1391
1458
* this function.
1392
1459
*/
1393
- static int do_config_from (struct config_source * top , config_fn_t fn , void * data )
1460
+ static int do_config_from (struct config_source * top , config_fn_t fn , void * data ,
1461
+ const struct config_options * opts )
1394
1462
{
1395
1463
int ret ;
1396
1464
@@ -1402,7 +1470,7 @@ static int do_config_from(struct config_source *top, config_fn_t fn, void *data)
1402
1470
strbuf_init (& top -> var , 1024 );
1403
1471
cf = top ;
1404
1472
1405
- ret = git_parse_source (fn , data );
1473
+ ret = git_parse_source (fn , data , opts );
1406
1474
1407
1475
/* pop config-file parsing state stack */
1408
1476
strbuf_release (& top -> value );
@@ -1415,7 +1483,7 @@ static int do_config_from(struct config_source *top, config_fn_t fn, void *data)
1415
1483
static int do_config_from_file (config_fn_t fn ,
1416
1484
const enum config_origin_type origin_type ,
1417
1485
const char * name , const char * path , FILE * f ,
1418
- void * data )
1486
+ void * data , const struct config_options * opts )
1419
1487
{
1420
1488
struct config_source top ;
1421
1489
@@ -1428,29 +1496,38 @@ static int do_config_from_file(config_fn_t fn,
1428
1496
top .do_ungetc = config_file_ungetc ;
1429
1497
top .do_ftell = config_file_ftell ;
1430
1498
1431
- return do_config_from (& top , fn , data );
1499
+ return do_config_from (& top , fn , data , opts );
1432
1500
}
1433
1501
1434
1502
static int git_config_from_stdin (config_fn_t fn , void * data )
1435
1503
{
1436
- return do_config_from_file (fn , CONFIG_ORIGIN_STDIN , "" , NULL , stdin , data );
1504
+ return do_config_from_file (fn , CONFIG_ORIGIN_STDIN , "" , NULL , stdin ,
1505
+ data , NULL );
1437
1506
}
1438
1507
1439
- int git_config_from_file (config_fn_t fn , const char * filename , void * data )
1508
+ int git_config_from_file_with_options (config_fn_t fn , const char * filename ,
1509
+ void * data ,
1510
+ const struct config_options * opts )
1440
1511
{
1441
1512
int ret = -1 ;
1442
1513
FILE * f ;
1443
1514
1444
1515
f = fopen_or_warn (filename , "r" );
1445
1516
if (f ) {
1446
1517
flockfile (f );
1447
- ret = do_config_from_file (fn , CONFIG_ORIGIN_FILE , filename , filename , f , data );
1518
+ ret = do_config_from_file (fn , CONFIG_ORIGIN_FILE , filename ,
1519
+ filename , f , data , opts );
1448
1520
funlockfile (f );
1449
1521
fclose (f );
1450
1522
}
1451
1523
return ret ;
1452
1524
}
1453
1525
1526
+ int git_config_from_file (config_fn_t fn , const char * filename , void * data )
1527
+ {
1528
+ return git_config_from_file_with_options (fn , filename , data , NULL );
1529
+ }
1530
+
1454
1531
int git_config_from_mem (config_fn_t fn , const enum config_origin_type origin_type ,
1455
1532
const char * name , const char * buf , size_t len , void * data )
1456
1533
{
@@ -1467,7 +1544,7 @@ int git_config_from_mem(config_fn_t fn, const enum config_origin_type origin_typ
1467
1544
top .do_ungetc = config_buf_ungetc ;
1468
1545
top .do_ftell = config_buf_ftell ;
1469
1546
1470
- return do_config_from (& top , fn , data );
1547
+ return do_config_from (& top , fn , data , NULL );
1471
1548
}
1472
1549
1473
1550
int git_config_from_blob_oid (config_fn_t fn ,
0 commit comments