Merge branch 'mh/attr'

* mh/attr:
  Unroll the loop over passes
  Change while loop into for loop
  Determine the start of the states outside of the pass loop
  Change parse_attr() to take a pointer to struct attr_state
  Increment num_attr in parse_attr_line(), not parse_attr()
  Document struct match_attr
  Add a file comment
maint
Junio C Hamano 2011-08-28 21:19:12 -07:00
commit e5cfcb04e0
1 changed files with 63 additions and 50 deletions

81
attr.c
View File

@ -1,3 +1,12 @@
/*
* Handle git attributes. See gitattributes(5) for a description of
* the file syntax, and Documentation/technical/api-gitattributes.txt
* for a description of the API.
*
* One basic design decision here is that we are not going to support
* an insanely large number of attributes.
*/

#define NO_THE_INDEX_COMPATIBILITY_MACROS #define NO_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h" #include "cache.h"
#include "exec_cmd.h" #include "exec_cmd.h"
@ -13,12 +22,7 @@ static const char git_attr__unknown[] = "(builtin)unknown";


static const char *attributes_file; static const char *attributes_file;


/* /* This is a randomly chosen prime. */
* The basic design decision here is that we are not going to have
* insanely large number of attributes.
*
* This is a randomly chosen prime.
*/
#define HASHSIZE 257 #define HASHSIZE 257


#ifndef DEBUG_ATTR #ifndef DEBUG_ATTR
@ -106,22 +110,26 @@ struct git_attr *git_attr(const char *name)
return git_attr_internal(name, strlen(name)); return git_attr_internal(name, strlen(name));
} }


/*
* .gitattributes file is one line per record, each of which is
*
* (1) glob pattern.
* (2) whitespace
* (3) whitespace separated list of attribute names, each of which
* could be prefixed with '-' to mean "set to false", '!' to mean
* "unset".
*/

/* What does a matched pattern decide? */ /* What does a matched pattern decide? */
struct attr_state { struct attr_state {
struct git_attr *attr; struct git_attr *attr;
const char *setto; const char *setto;
}; };


/*
* One rule, as from a .gitattributes file.
*
* If is_macro is true, then u.attr is a pointer to the git_attr being
* defined.
*
* If is_macro is false, then u.pattern points at the filename pattern
* to which the rule applies. (The memory pointed to is part of the
* memory block allocated for the match_attr instance.)
*
* In either case, num_attr is the number of attributes affected by
* this rule, and state is an array listing them. The attributes are
* listed as they appear in the file (macros unexpanded).
*/
struct match_attr { struct match_attr {
union { union {
char *pattern; char *pattern;
@ -134,8 +142,15 @@ struct match_attr {


static const char blank[] = " \t\r\n"; static const char blank[] = " \t\r\n";


/*
* Parse a whitespace-delimited attribute state (i.e., "attr",
* "-attr", "!attr", or "attr=value") from the string starting at src.
* If e is not NULL, write the results to *e. Return a pointer to the
* remainder of the string (with leading whitespace removed), or NULL
* if there was an error.
*/
static const char *parse_attr(const char *src, int lineno, const char *cp, static const char *parse_attr(const char *src, int lineno, const char *cp,
int *num_attr, struct match_attr *res) struct attr_state *e)
{ {
const char *ep, *equals; const char *ep, *equals;
int len; int len;
@ -148,7 +163,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
len = equals - cp; len = equals - cp;
else else
len = ep - cp; len = ep - cp;
if (!res) { if (!e) {
if (*cp == '-' || *cp == '!') { if (*cp == '-' || *cp == '!') {
cp++; cp++;
len--; len--;
@ -160,9 +175,6 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
return NULL; return NULL;
} }
} else { } else {
struct attr_state *e;

e = &(res->state[*num_attr]);
if (*cp == '-' || *cp == '!') { if (*cp == '-' || *cp == '!') {
e->setto = (*cp == '-') ? ATTR__FALSE : ATTR__UNSET; e->setto = (*cp == '-') ? ATTR__FALSE : ATTR__UNSET;
cp++; cp++;
@ -175,7 +187,6 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
} }
e->attr = git_attr_internal(cp, len); e->attr = git_attr_internal(cp, len);
} }
(*num_attr)++;
return ep + strspn(ep, blank); return ep + strspn(ep, blank);
} }


@ -183,10 +194,9 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
int lineno, int macro_ok) int lineno, int macro_ok)
{ {
int namelen; int namelen;
int num_attr; int num_attr, i;
const char *cp, *name; const char *cp, *name, *states;
struct match_attr *res = NULL; struct match_attr *res = NULL;
int pass;
int is_macro; int is_macro;


cp = line + strspn(line, blank); cp = line + strspn(line, blank);
@ -215,18 +225,16 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
else else
is_macro = 0; is_macro = 0;


for (pass = 0; pass < 2; pass++) { states = name + namelen;
/* pass 0 counts and allocates, pass 1 fills */ states += strspn(states, blank);
num_attr = 0;
cp = name + namelen; /* First pass to count the attr_states */
cp = cp + strspn(cp, blank); for (cp = states, num_attr = 0; *cp; num_attr++) {
while (*cp) { cp = parse_attr(src, lineno, cp, NULL);
cp = parse_attr(src, lineno, cp, &num_attr, res);
if (!cp) if (!cp)
return NULL; return NULL;
} }
if (pass)
break;
res = xcalloc(1, res = xcalloc(1,
sizeof(*res) + sizeof(*res) +
sizeof(struct attr_state) * num_attr + sizeof(struct attr_state) * num_attr +
@ -240,7 +248,12 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
} }
res->is_macro = is_macro; res->is_macro = is_macro;
res->num_attr = num_attr; res->num_attr = num_attr;

/* Second pass to fill the attr_states */
for (cp = states, i = 0; *cp; i++) {
cp = parse_attr(src, lineno, cp, &(res->state[i]));
} }

return res; return res;
} }