@@ -32,9 +32,12 @@ struct git_attr {
3232 struct git_attr * next ;
3333 unsigned h ;
3434 int attr_nr ;
35+ int maybe_macro ;
36+ int maybe_real ;
3537 char name [FLEX_ARRAY ];
3638};
3739static int attr_nr ;
40+ static int cannot_trust_maybe_real ;
3841
3942static struct git_attr_check * check_all_attr ;
4043static struct git_attr * (git_attr_hash [HASHSIZE ]);
@@ -95,6 +98,8 @@ static struct git_attr *git_attr_internal(const char *name, int len)
9598 a -> h = hval ;
9699 a -> next = git_attr_hash [pos ];
97100 a -> attr_nr = attr_nr ++ ;
101+ a -> maybe_macro = 0 ;
102+ a -> maybe_real = 0 ;
98103 git_attr_hash [pos ] = a ;
99104
100105 REALLOC_ARRAY (check_all_attr , attr_nr );
@@ -244,9 +249,10 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
244249 sizeof (* res ) +
245250 sizeof (struct attr_state ) * num_attr +
246251 (is_macro ? 0 : namelen + 1 ));
247- if (is_macro )
252+ if (is_macro ) {
248253 res -> u .attr = git_attr_internal (name , namelen );
249- else {
254+ res -> u .attr -> maybe_macro = 1 ;
255+ } else {
250256 char * p = (char * )& (res -> state [num_attr ]);
251257 memcpy (p , name , namelen );
252258 res -> u .pat .pattern = p ;
@@ -266,6 +272,10 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
266272 /* Second pass to fill the attr_states */
267273 for (cp = states , i = 0 ; * cp ; i ++ ) {
268274 cp = parse_attr (src , lineno , cp , & (res -> state [i ]));
275+ if (!is_macro )
276+ res -> state [i ].attr -> maybe_real = 1 ;
277+ if (res -> state [i ].attr -> maybe_macro )
278+ cannot_trust_maybe_real = 1 ;
269279 }
270280
271281 return res ;
@@ -681,21 +691,22 @@ static int fill(const char *path, int pathlen, int basename_offset,
681691 return rem ;
682692}
683693
684- static int macroexpand_one (int attr_nr , int rem )
694+ static int macroexpand_one (int nr , int rem )
685695{
686696 struct attr_stack * stk ;
687697 struct match_attr * a = NULL ;
688698 int i ;
689699
690- if (check_all_attr [attr_nr ].value != ATTR__TRUE )
700+ if (check_all_attr [nr ].value != ATTR__TRUE ||
701+ !check_all_attr [nr ].attr -> maybe_macro )
691702 return rem ;
692703
693704 for (stk = attr_stack ; !a && stk ; stk = stk -> prev )
694705 for (i = stk -> num_matches - 1 ; !a && 0 <= i ; i -- ) {
695706 struct match_attr * ma = stk -> attrs [i ];
696707 if (!ma -> is_macro )
697708 continue ;
698- if (ma -> u .attr -> attr_nr == attr_nr )
709+ if (ma -> u .attr -> attr_nr == nr )
699710 a = ma ;
700711 }
701712
@@ -706,10 +717,13 @@ static int macroexpand_one(int attr_nr, int rem)
706717}
707718
708719/*
709- * Collect all attributes for path into the array pointed to by
710- * check_all_attr.
720+ * Collect attributes for path into the array pointed to by
721+ * check_all_attr. If num is non-zero, only attributes in check[] are
722+ * collected. Otherwise all attributes are collected.
711723 */
712- static void collect_all_attrs (const char * path )
724+ static void collect_some_attrs (const char * path , int num ,
725+ struct git_attr_check * check )
726+
713727{
714728 struct attr_stack * stk ;
715729 int i , pathlen , rem , dirlen ;
@@ -732,6 +746,19 @@ static void collect_all_attrs(const char *path)
732746 prepare_attr_stack (path , dirlen );
733747 for (i = 0 ; i < attr_nr ; i ++ )
734748 check_all_attr [i ].value = ATTR__UNKNOWN ;
749+ if (num && !cannot_trust_maybe_real ) {
750+ rem = 0 ;
751+ for (i = 0 ; i < num ; i ++ ) {
752+ if (!check [i ].attr -> maybe_real ) {
753+ struct git_attr_check * c ;
754+ c = check_all_attr + check [i ].attr -> attr_nr ;
755+ c -> value = ATTR__UNSET ;
756+ rem ++ ;
757+ }
758+ }
759+ if (rem == num )
760+ return ;
761+ }
735762
736763 rem = attr_nr ;
737764 for (stk = attr_stack ; 0 < rem && stk ; stk = stk -> prev )
@@ -742,7 +769,7 @@ int git_check_attr(const char *path, int num, struct git_attr_check *check)
742769{
743770 int i ;
744771
745- collect_all_attrs (path );
772+ collect_some_attrs (path , num , check );
746773
747774 for (i = 0 ; i < num ; i ++ ) {
748775 const char * value = check_all_attr [check [i ].attr -> attr_nr ].value ;
@@ -758,7 +785,7 @@ int git_all_attrs(const char *path, int *num, struct git_attr_check **check)
758785{
759786 int i , count , j ;
760787
761- collect_all_attrs (path );
788+ collect_some_attrs (path , 0 , NULL );
762789
763790 /* Count the number of attributes that are set. */
764791 count = 0 ;
0 commit comments