22#include "cache.h"
33#include "color.h"
44#include "parse-options.h"
5+ #include "urlmatch.h"
56
67static const char * const builtin_config_usage [] = {
78 N_ ("git config [options]" ),
@@ -42,6 +43,7 @@ static int respect_includes = -1;
4243#define ACTION_SET_ALL (1<<12)
4344#define ACTION_GET_COLOR (1<<13)
4445#define ACTION_GET_COLORBOOL (1<<14)
46+ #define ACTION_GET_URLMATCH (1<<15)
4547
4648#define TYPE_BOOL (1<<0)
4749#define TYPE_INT (1<<1)
@@ -59,6 +61,7 @@ static struct option builtin_config_options[] = {
5961 OPT_BIT (0 , "get" , & actions , N_ ("get value: name [value-regex]" ), ACTION_GET ),
6062 OPT_BIT (0 , "get-all" , & actions , N_ ("get all values: key [value-regex]" ), ACTION_GET_ALL ),
6163 OPT_BIT (0 , "get-regexp" , & actions , N_ ("get values for regexp: name-regex [value-regex]" ), ACTION_GET_REGEXP ),
64+ OPT_BIT (0 , "get-urlmatch" , & actions , N_ ("get value specific for the URL: section[.var] URL" ), ACTION_GET_URLMATCH ),
6265 OPT_BIT (0 , "replace-all" , & actions , N_ ("replace all matching variables: name value [value_regex]" ), ACTION_REPLACE_ALL ),
6366 OPT_BIT (0 , "add" , & actions , N_ ("add a new variable: name value" ), ACTION_ADD ),
6467 OPT_BIT (0 , "unset" , & actions , N_ ("remove a variable: name [value-regex]" ), ACTION_UNSET ),
@@ -102,33 +105,21 @@ struct strbuf_list {
102105 int alloc ;
103106};
104107
105- static int collect_config ( const char * key_ , const char * value_ , void * cb )
108+ static int format_config ( struct strbuf * buf , const char * key_ , const char * value_ )
106109{
107- struct strbuf_list * values = cb ;
108- struct strbuf * buf ;
109- char value [256 ];
110- const char * vptr = value ;
111110 int must_free_vptr = 0 ;
112111 int must_print_delim = 0 ;
112+ char value [256 ];
113+ const char * vptr = value ;
113114
114- if (!use_key_regexp && strcmp (key_ , key ))
115- return 0 ;
116- if (use_key_regexp && regexec (key_regexp , key_ , 0 , NULL , 0 ))
117- return 0 ;
118- if (regexp != NULL &&
119- (do_not_match ^ !!regexec (regexp , (value_ ?value_ :"" ), 0 , NULL , 0 )))
120- return 0 ;
121-
122- ALLOC_GROW (values -> items , values -> nr + 1 , values -> alloc );
123- buf = & values -> items [values -> nr ++ ];
124115 strbuf_init (buf , 0 );
125116
126117 if (show_keys ) {
127118 strbuf_addstr (buf , key_ );
128119 must_print_delim = 1 ;
129120 }
130121 if (types == TYPE_INT )
131- sprintf (value , "%d" , git_config_int (key_ , value_ ? value_ : "" ));
122+ sprintf (value , "%d" , git_config_int (key_ , value_ ? value_ : "" ));
132123 else if (types == TYPE_BOOL )
133124 vptr = git_config_bool (key_ , value_ ) ? "true" : "false" ;
134125 else if (types == TYPE_BOOL_OR_INT ) {
@@ -156,15 +147,27 @@ static int collect_config(const char *key_, const char *value_, void *cb)
156147 strbuf_addch (buf , term );
157148
158149 if (must_free_vptr )
159- /* If vptr must be freed, it's a pointer to a
160- * dynamically allocated buffer, it's safe to cast to
161- * const.
162- */
163150 free ((char * )vptr );
164-
165151 return 0 ;
166152}
167153
154+ static int collect_config (const char * key_ , const char * value_ , void * cb )
155+ {
156+ struct strbuf_list * values = cb ;
157+
158+ if (!use_key_regexp && strcmp (key_ , key ))
159+ return 0 ;
160+ if (use_key_regexp && regexec (key_regexp , key_ , 0 , NULL , 0 ))
161+ return 0 ;
162+ if (regexp != NULL &&
163+ (do_not_match ^ !!regexec (regexp , (value_ ?value_ :"" ), 0 , NULL , 0 )))
164+ return 0 ;
165+
166+ ALLOC_GROW (values -> items , values -> nr + 1 , values -> alloc );
167+
168+ return format_config (& values -> items [values -> nr ++ ], key_ , value_ );
169+ }
170+
168171static int get_value (const char * key_ , const char * regex_ )
169172{
170173 int ret = CONFIG_GENERIC_ERROR ;
@@ -364,6 +367,97 @@ static void check_blob_write(void)
364367 die ("writing config blobs is not supported" );
365368}
366369
370+ struct urlmatch_current_candidate_value {
371+ char value_is_null ;
372+ struct strbuf value ;
373+ };
374+
375+ static int urlmatch_collect_fn (const char * var , const char * value , void * cb )
376+ {
377+ struct string_list * values = cb ;
378+ struct string_list_item * item = string_list_insert (values , var );
379+ struct urlmatch_current_candidate_value * matched = item -> util ;
380+
381+ if (!matched ) {
382+ matched = xmalloc (sizeof (* matched ));
383+ strbuf_init (& matched -> value , 0 );
384+ item -> util = matched ;
385+ } else {
386+ strbuf_reset (& matched -> value );
387+ }
388+
389+ if (value ) {
390+ strbuf_addstr (& matched -> value , value );
391+ matched -> value_is_null = 0 ;
392+ } else {
393+ matched -> value_is_null = 1 ;
394+ }
395+ return 0 ;
396+ }
397+
398+ static char * dup_downcase (const char * string )
399+ {
400+ char * result ;
401+ size_t len , i ;
402+
403+ len = strlen (string );
404+ result = xmalloc (len + 1 );
405+ for (i = 0 ; i < len ; i ++ )
406+ result [i ] = tolower (string [i ]);
407+ result [i ] = '\0' ;
408+ return result ;
409+ }
410+
411+ static int get_urlmatch (const char * var , const char * url )
412+ {
413+ char * section_tail ;
414+ struct string_list_item * item ;
415+ struct urlmatch_config config = { STRING_LIST_INIT_DUP };
416+ struct string_list values = STRING_LIST_INIT_DUP ;
417+
418+ config .collect_fn = urlmatch_collect_fn ;
419+ config .cascade_fn = NULL ;
420+ config .cb = & values ;
421+
422+ if (!url_normalize (url , & config .url ))
423+ die ("%s" , config .url .err );
424+
425+ config .section = dup_downcase (var );
426+ section_tail = strchr (config .section , '.' );
427+ if (section_tail ) {
428+ * section_tail = '\0' ;
429+ config .key = section_tail + 1 ;
430+ show_keys = 0 ;
431+ } else {
432+ config .key = NULL ;
433+ show_keys = 1 ;
434+ }
435+
436+ git_config_with_options (urlmatch_config_entry , & config ,
437+ given_config_file , NULL , respect_includes );
438+
439+ for_each_string_list_item (item , & values ) {
440+ struct urlmatch_current_candidate_value * matched = item -> util ;
441+ struct strbuf key = STRBUF_INIT ;
442+ struct strbuf buf = STRBUF_INIT ;
443+
444+ strbuf_addstr (& key , item -> string );
445+ format_config (& buf , key .buf ,
446+ matched -> value_is_null ? NULL : matched -> value .buf );
447+ fwrite (buf .buf , 1 , buf .len , stdout );
448+ strbuf_release (& key );
449+ strbuf_release (& buf );
450+
451+ strbuf_release (& matched -> value );
452+ }
453+ string_list_clear (& config .vars , 1 );
454+ string_list_clear (& values , 1 );
455+ free (config .url .url );
456+
457+ free ((void * )config .section );
458+ return 0 ;
459+ }
460+
367461int cmd_config (int argc , const char * * argv , const char * prefix )
368462{
369463 int nongit = !startup_info -> have_repository ;
@@ -523,6 +617,10 @@ int cmd_config(int argc, const char **argv, const char *prefix)
523617 check_argc (argc , 1 , 2 );
524618 return get_value (argv [0 ], argv [1 ]);
525619 }
620+ else if (actions == ACTION_GET_URLMATCH ) {
621+ check_argc (argc , 2 , 2 );
622+ return get_urlmatch (argv [0 ], argv [1 ]);
623+ }
526624 else if (actions == ACTION_UNSET ) {
527625 check_blob_write ();
528626 check_argc (argc , 1 , 2 );
0 commit comments