11#include "git-compat-util.h"
22#include "line-range.h"
3+ #include "xdiff-interface.h"
4+ #include "strbuf.h"
5+ #include "userdiff.h"
36
47/*
58 * Parse one item in the -L option
@@ -84,9 +87,137 @@ static const char *parse_loc(const char *spec, nth_line_fn_t nth_line,
8487 }
8588}
8689
90+ static int match_funcname (xdemitconf_t * xecfg , const char * bol , const char * eol )
91+ {
92+ if (xecfg ) {
93+ char buf [1 ];
94+ return xecfg -> find_func (bol , eol - bol , buf , 1 ,
95+ xecfg -> find_func_priv ) >= 0 ;
96+ }
97+
98+ if (bol == eol )
99+ return 0 ;
100+ if (isalpha (* bol ) || * bol == '_' || * bol == '$' )
101+ return 1 ;
102+ return 0 ;
103+ }
104+
105+ static const char * find_funcname_matching_regexp (xdemitconf_t * xecfg , const char * start ,
106+ regex_t * regexp )
107+ {
108+ int reg_error ;
109+ regmatch_t match [1 ];
110+ while (1 ) {
111+ const char * bol , * eol ;
112+ reg_error = regexec (regexp , start , 1 , match , 0 );
113+ if (reg_error == REG_NOMATCH )
114+ return NULL ;
115+ else if (reg_error ) {
116+ char errbuf [1024 ];
117+ regerror (reg_error , regexp , errbuf , 1024 );
118+ die ("-L parameter: regexec() failed: %s" , errbuf );
119+ }
120+ /* determine extent of line matched */
121+ bol = start + match [0 ].rm_so ;
122+ eol = start + match [0 ].rm_eo ;
123+ while (bol > start && * bol != '\n' )
124+ bol -- ;
125+ if (* bol == '\n' )
126+ bol ++ ;
127+ while (* eol && * eol != '\n' )
128+ eol ++ ;
129+ if (* eol == '\n' )
130+ eol ++ ;
131+ /* is it a funcname line? */
132+ if (match_funcname (xecfg , (char * ) bol , (char * ) eol ))
133+ return bol ;
134+ start = eol ;
135+ }
136+ }
137+
138+ static const char * parse_range_funcname (const char * arg , nth_line_fn_t nth_line_cb ,
139+ void * cb_data , long lines , long * begin , long * end ,
140+ const char * path )
141+ {
142+ char * pattern ;
143+ const char * term ;
144+ struct userdiff_driver * drv ;
145+ xdemitconf_t * xecfg = NULL ;
146+ const char * start ;
147+ const char * p ;
148+ int reg_error ;
149+ regex_t regexp ;
150+
151+ assert (* arg == ':' );
152+ term = arg + 1 ;
153+ while (* term && * term != ':' ) {
154+ if (* term == '\\' && * (term + 1 ))
155+ term ++ ;
156+ term ++ ;
157+ }
158+ if (term == arg + 1 )
159+ return NULL ;
160+ if (!begin ) /* skip_range_arg case */
161+ return term ;
162+
163+ pattern = xstrndup (arg + 1 , term - (arg + 1 ));
164+
165+ start = nth_line_cb (cb_data , 0 );
166+
167+ drv = userdiff_find_by_path (path );
168+ if (drv && drv -> funcname .pattern ) {
169+ const struct userdiff_funcname * pe = & drv -> funcname ;
170+ xecfg = xcalloc (1 , sizeof (* xecfg ));
171+ xdiff_set_find_func (xecfg , pe -> pattern , pe -> cflags );
172+ }
173+
174+ reg_error = regcomp (& regexp , pattern , REG_NEWLINE );
175+ if (reg_error ) {
176+ char errbuf [1024 ];
177+ regerror (reg_error , & regexp , errbuf , 1024 );
178+ die ("-L parameter '%s': %s" , pattern , errbuf );
179+ }
180+
181+ p = find_funcname_matching_regexp (xecfg , (char * ) start , & regexp );
182+ if (!p )
183+ die ("-L parameter '%s': no match" , pattern );
184+ * begin = 0 ;
185+ while (p > nth_line_cb (cb_data , * begin ))
186+ (* begin )++ ;
187+
188+ if (* begin >= lines )
189+ die ("-L parameter '%s' matches at EOF" , pattern );
190+
191+ * end = * begin + 1 ;
192+ while (* end < lines ) {
193+ const char * bol = nth_line_cb (cb_data , * end );
194+ const char * eol = nth_line_cb (cb_data , * end + 1 );
195+ if (match_funcname (xecfg , bol , eol ))
196+ break ;
197+ (* end )++ ;
198+ }
199+
200+ regfree (& regexp );
201+ free (xecfg );
202+ free (pattern );
203+
204+ /* compensate for 1-based numbering */
205+ (* begin )++ ;
206+
207+ return term ;
208+ }
209+
87210int parse_range_arg (const char * arg , nth_line_fn_t nth_line_cb ,
88- void * cb_data , long lines , long * begin , long * end )
211+ void * cb_data , long lines , long * begin , long * end ,
212+ const char * path )
89213{
214+ if (* arg == ':' ) {
215+ arg = parse_range_funcname (arg , nth_line_cb , cb_data , lines , begin , end , path );
216+ if (!arg || * arg )
217+ return -1 ;
218+ return 0 ;
219+ }
220+
90221 arg = parse_loc (arg , nth_line_cb , cb_data , lines , 1 , begin );
91222
92223 if (* arg == ',' )
@@ -100,6 +231,9 @@ int parse_range_arg(const char *arg, nth_line_fn_t nth_line_cb,
100231
101232const char * skip_range_arg (const char * arg )
102233{
234+ if (* arg == ':' )
235+ return parse_range_funcname (arg , NULL , NULL , 0 , NULL , NULL , NULL );
236+
103237 arg = parse_loc (arg , NULL , NULL , 0 , -1 , NULL );
104238
105239 if (* arg == ',' )
0 commit comments