@@ -653,7 +653,45 @@ static int get_base_var(struct strbuf *name)
653653 }
654654}
655655
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 )
657695{
658696 int comment = 0 ;
659697 int baselen = 0 ;
@@ -664,8 +702,15 @@ static int git_parse_source(config_fn_t fn, void *data)
664702 /* U+FEFF Byte Order Mark in UTF8 */
665703 const char * bomptr = utf8_bom ;
666704
705+ /* For the parser event callback */
706+ struct parse_event_data event_data = {
707+ CONFIG_EVENT_EOF , 0 , opts
708+ };
709+
667710 for (;;) {
668- int c = get_next_char ();
711+ int c ;
712+
713+ c = get_next_char ();
669714 if (bomptr && * bomptr ) {
670715 /* We are at the file beginning; skip UTF8-encoded BOM
671716 * 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)
682727 }
683728 }
684729 if (c == '\n' ) {
685- if (cf -> eof )
730+ if (cf -> eof ) {
731+ if (do_event (CONFIG_EVENT_EOF , & event_data ) < 0 )
732+ return -1 ;
686733 return 0 ;
734+ }
735+ if (do_event (CONFIG_EVENT_WHITESPACE , & event_data ) < 0 )
736+ return -1 ;
687737 comment = 0 ;
688738 continue ;
689739 }
690- if (comment || isspace ( c ) )
740+ if (comment )
691741 continue ;
742+ if (isspace (c )) {
743+ if (do_event (CONFIG_EVENT_WHITESPACE , & event_data ) < 0 )
744+ return -1 ;
745+ continue ;
746+ }
692747 if (c == '#' || c == ';' ) {
748+ if (do_event (CONFIG_EVENT_COMMENT , & event_data ) < 0 )
749+ return -1 ;
693750 comment = 1 ;
694751 continue ;
695752 }
696753 if (c == '[' ) {
754+ if (do_event (CONFIG_EVENT_SECTION , & event_data ) < 0 )
755+ return -1 ;
756+
697757 /* Reset prior to determining a new stem */
698758 strbuf_reset (var );
699759 if (get_base_var (var ) < 0 || var -> len < 1 )
@@ -704,6 +764,10 @@ static int git_parse_source(config_fn_t fn, void *data)
704764 }
705765 if (!isalpha (c ))
706766 break ;
767+
768+ if (do_event (CONFIG_EVENT_ENTRY , & event_data ) < 0 )
769+ return -1 ;
770+
707771 /*
708772 * Truncate the var name back to the section header
709773 * 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)
715779 break ;
716780 }
717781
782+ if (do_event (CONFIG_EVENT_ERROR , & event_data ) < 0 )
783+ return -1 ;
784+
718785 switch (cf -> origin_type ) {
719786 case CONFIG_ORIGIN_BLOB :
720787 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)
13901457 * fgetc, ungetc, ftell of top need to be initialized before calling
13911458 * this function.
13921459 */
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 )
13941462{
13951463 int ret ;
13961464
@@ -1402,7 +1470,7 @@ static int do_config_from(struct config_source *top, config_fn_t fn, void *data)
14021470 strbuf_init (& top -> var , 1024 );
14031471 cf = top ;
14041472
1405- ret = git_parse_source (fn , data );
1473+ ret = git_parse_source (fn , data , opts );
14061474
14071475 /* pop config-file parsing state stack */
14081476 strbuf_release (& top -> value );
@@ -1415,7 +1483,7 @@ static int do_config_from(struct config_source *top, config_fn_t fn, void *data)
14151483static int do_config_from_file (config_fn_t fn ,
14161484 const enum config_origin_type origin_type ,
14171485 const char * name , const char * path , FILE * f ,
1418- void * data )
1486+ void * data , const struct config_options * opts )
14191487{
14201488 struct config_source top ;
14211489
@@ -1428,29 +1496,38 @@ static int do_config_from_file(config_fn_t fn,
14281496 top .do_ungetc = config_file_ungetc ;
14291497 top .do_ftell = config_file_ftell ;
14301498
1431- return do_config_from (& top , fn , data );
1499+ return do_config_from (& top , fn , data , opts );
14321500}
14331501
14341502static int git_config_from_stdin (config_fn_t fn , void * data )
14351503{
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 );
14371506}
14381507
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 )
14401511{
14411512 int ret = -1 ;
14421513 FILE * f ;
14431514
14441515 f = fopen_or_warn (filename , "r" );
14451516 if (f ) {
14461517 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 );
14481520 funlockfile (f );
14491521 fclose (f );
14501522 }
14511523 return ret ;
14521524}
14531525
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+
14541531int git_config_from_mem (config_fn_t fn , const enum config_origin_type origin_type ,
14551532 const char * name , const char * buf , size_t len , void * data )
14561533{
@@ -1467,7 +1544,7 @@ int git_config_from_mem(config_fn_t fn, const enum config_origin_type origin_typ
14671544 top .do_ungetc = config_buf_ungetc ;
14681545 top .do_ftell = config_buf_ftell ;
14691546
1470- return do_config_from (& top , fn , data );
1547+ return do_config_from (& top , fn , data , NULL );
14711548}
14721549
14731550int git_config_from_blob_oid (config_fn_t fn ,
0 commit comments