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 commentmaint
commit
e5cfcb04e0
81
attr.c
81
attr.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue