Skip to content

Commit e5cfcb0

Browse files
committed
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
2 parents 0dc691a + d68e1c1 commit e5cfcb0

File tree

1 file changed

+63
-50
lines changed

1 file changed

+63
-50
lines changed

attr.c

Lines changed: 63 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
/*
2+
* Handle git attributes. See gitattributes(5) for a description of
3+
* the file syntax, and Documentation/technical/api-gitattributes.txt
4+
* for a description of the API.
5+
*
6+
* One basic design decision here is that we are not going to support
7+
* an insanely large number of attributes.
8+
*/
9+
110
#define NO_THE_INDEX_COMPATIBILITY_MACROS
211
#include "cache.h"
312
#include "exec_cmd.h"
@@ -13,12 +22,7 @@ static const char git_attr__unknown[] = "(builtin)unknown";
1322

1423
static const char *attributes_file;
1524

16-
/*
17-
* The basic design decision here is that we are not going to have
18-
* insanely large number of attributes.
19-
*
20-
* This is a randomly chosen prime.
21-
*/
25+
/* This is a randomly chosen prime. */
2226
#define HASHSIZE 257
2327

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

109-
/*
110-
* .gitattributes file is one line per record, each of which is
111-
*
112-
* (1) glob pattern.
113-
* (2) whitespace
114-
* (3) whitespace separated list of attribute names, each of which
115-
* could be prefixed with '-' to mean "set to false", '!' to mean
116-
* "unset".
117-
*/
118-
119113
/* What does a matched pattern decide? */
120114
struct attr_state {
121115
struct git_attr *attr;
122116
const char *setto;
123117
};
124118

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

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

145+
/*
146+
* Parse a whitespace-delimited attribute state (i.e., "attr",
147+
* "-attr", "!attr", or "attr=value") from the string starting at src.
148+
* If e is not NULL, write the results to *e. Return a pointer to the
149+
* remainder of the string (with leading whitespace removed), or NULL
150+
* if there was an error.
151+
*/
137152
static const char *parse_attr(const char *src, int lineno, const char *cp,
138-
int *num_attr, struct match_attr *res)
153+
struct attr_state *e)
139154
{
140155
const char *ep, *equals;
141156
int len;
@@ -148,7 +163,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
148163
len = equals - cp;
149164
else
150165
len = ep - cp;
151-
if (!res) {
166+
if (!e) {
152167
if (*cp == '-' || *cp == '!') {
153168
cp++;
154169
len--;
@@ -160,9 +175,6 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
160175
return NULL;
161176
}
162177
} else {
163-
struct attr_state *e;
164-
165-
e = &(res->state[*num_attr]);
166178
if (*cp == '-' || *cp == '!') {
167179
e->setto = (*cp == '-') ? ATTR__FALSE : ATTR__UNSET;
168180
cp++;
@@ -175,18 +187,16 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
175187
}
176188
e->attr = git_attr_internal(cp, len);
177189
}
178-
(*num_attr)++;
179190
return ep + strspn(ep, blank);
180191
}
181192

182193
static struct match_attr *parse_attr_line(const char *line, const char *src,
183194
int lineno, int macro_ok)
184195
{
185196
int namelen;
186-
int num_attr;
187-
const char *cp, *name;
197+
int num_attr, i;
198+
const char *cp, *name, *states;
188199
struct match_attr *res = NULL;
189-
int pass;
190200
int is_macro;
191201

192202
cp = line + strspn(line, blank);
@@ -215,32 +225,35 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
215225
else
216226
is_macro = 0;
217227

218-
for (pass = 0; pass < 2; pass++) {
219-
/* pass 0 counts and allocates, pass 1 fills */
220-
num_attr = 0;
221-
cp = name + namelen;
222-
cp = cp + strspn(cp, blank);
223-
while (*cp) {
224-
cp = parse_attr(src, lineno, cp, &num_attr, res);
225-
if (!cp)
226-
return NULL;
227-
}
228-
if (pass)
229-
break;
230-
res = xcalloc(1,
231-
sizeof(*res) +
232-
sizeof(struct attr_state) * num_attr +
233-
(is_macro ? 0 : namelen + 1));
234-
if (is_macro)
235-
res->u.attr = git_attr_internal(name, namelen);
236-
else {
237-
res->u.pattern = (char *)&(res->state[num_attr]);
238-
memcpy(res->u.pattern, name, namelen);
239-
res->u.pattern[namelen] = 0;
240-
}
241-
res->is_macro = is_macro;
242-
res->num_attr = num_attr;
228+
states = name + namelen;
229+
states += strspn(states, blank);
230+
231+
/* First pass to count the attr_states */
232+
for (cp = states, num_attr = 0; *cp; num_attr++) {
233+
cp = parse_attr(src, lineno, cp, NULL);
234+
if (!cp)
235+
return NULL;
236+
}
237+
238+
res = xcalloc(1,
239+
sizeof(*res) +
240+
sizeof(struct attr_state) * num_attr +
241+
(is_macro ? 0 : namelen + 1));
242+
if (is_macro)
243+
res->u.attr = git_attr_internal(name, namelen);
244+
else {
245+
res->u.pattern = (char *)&(res->state[num_attr]);
246+
memcpy(res->u.pattern, name, namelen);
247+
res->u.pattern[namelen] = 0;
243248
}
249+
res->is_macro = is_macro;
250+
res->num_attr = num_attr;
251+
252+
/* Second pass to fill the attr_states */
253+
for (cp = states, i = 0; *cp; i++) {
254+
cp = parse_attr(src, lineno, cp, &(res->state[i]));
255+
}
256+
244257
return res;
245258
}
246259

0 commit comments

Comments
 (0)