Make 'traverse_tree()' use linked structure rather than 'const char *base'
This makes the calling convention a bit less obvious, but a lot more flexible. Instead of allocating and extending a new 'base' string, we just link the top-most name into a linked list of the 'info' structure when traversing a subdirectory, and we can generate the basename by following the list. Perhaps even more importantly, the linked list of info structures also gives us a place to naturally save off other information than just the directory name. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Linus Torvalds committed
Mar 5, 2008 at 18:59 UTC
40d934df72eaf244c826d5c26da0896ce7185cb6
3 files changed
+78
-28
merge-tree.c
+27
-24
@@ -168,7 +168,13 @@ static struct merge_list *create_entry(unsigned stage, unsigned mode, const unsi
168
return res;
169
}
170
171
-static void resolve(const char *base, struct name_entry *branch1, struct name_entry *result)
171
+static char *traverse_path(const struct traverse_info *info, const struct name_entry *n)
172
+{
173
+ char *path = xmalloc(traverse_path_len(info, n) + 1);
174
+ return make_traverse_path(path, info, n);
175
+}
176
+
177
+static void resolve(const struct traverse_info *info, struct name_entry *branch1, struct name_entry *result)
178
{
179
struct merge_list *orig, *final;
180
const char *path;
@@ -177,7 +183,7 @@ static void resolve(const char *base, struct name_entry *branch1, struct name_en
183
if (!branch1)
184
return;
185
180
- path = xstrdup(mkpath("%s%s", base, result->path));
186
+ path = traverse_path(info, result);
187
orig = create_entry(2, branch1->mode, branch1->sha1, path);
188
final = create_entry(0, result->mode, result->sha1, path);
189
@@ -186,9 +192,8 @@ static void resolve(const char *base, struct name_entry *branch1, struct name_en
192
add_merge_entry(final);
193
}
194
189
-static int unresolved_directory(const char *base, struct name_entry n[3])
195
+static int unresolved_directory(const struct traverse_info *info, struct name_entry n[3])
196
{
191
- int baselen, pathlen;
197
char *newbase;
198
struct name_entry *p;
199
struct tree_desc t[3];
@@ -204,13 +209,7 @@ static int unresolved_directory(const char *base, struct name_entry n[3])
209
}
210
if (!S_ISDIR(p->mode))
211
return 0;
207
- baselen = strlen(base);
208
- pathlen = tree_entry_len(p->path, p->sha1);
209
- newbase = xmalloc(baselen + pathlen + 2);
210
- memcpy(newbase, base, baselen);
211
- memcpy(newbase + baselen, p->path, pathlen);
212
- memcpy(newbase + baselen + pathlen, "/", 2);
213
-
212
+ newbase = traverse_path(info, p);
213
buf0 = fill_tree_descriptor(t+0, n[0].sha1);
214
buf1 = fill_tree_descriptor(t+1, n[1].sha1);
215
buf2 = fill_tree_descriptor(t+2, n[2].sha1);
@@ -224,7 +223,7 @@ static int unresolved_directory(const char *base, struct name_entry n[3])
223
}
224
225
227
-static struct merge_list *link_entry(unsigned stage, const char *base, struct name_entry *n, struct merge_list *entry)
226
+static struct merge_list *link_entry(unsigned stage, const struct traverse_info *info, struct name_entry *n, struct merge_list *entry)
227
{
228
const char *path;
229
struct merge_list *link;
@@ -234,17 +233,17 @@ static struct merge_list *link_entry(unsigned stage, const char *base, struct na
233
if (entry)
234
path = entry->path;
235
else
237
- path = xstrdup(mkpath("%s%s", base, n->path));
236
+ path = traverse_path(info, n);
237
link = create_entry(stage, n->mode, n->sha1, path);
238
link->link = entry;
239
return link;
240
}
241
243
-static void unresolved(const char *base, struct name_entry n[3])
242
+static void unresolved(const struct traverse_info *info, struct name_entry n[3])
243
{
244
struct merge_list *entry = NULL;
245
247
- if (unresolved_directory(base, n))
246
+ if (unresolved_directory(info, n))
247
return;
248
249
/*
@@ -252,9 +251,9 @@ static void unresolved(const char *base, struct name_entry n[3])
251
* list has the stages in order - link_entry adds new
252
* links at the front.
253
*/
255
- entry = link_entry(3, base, n + 2, entry);
256
- entry = link_entry(2, base, n + 1, entry);
257
- entry = link_entry(1, base, n + 0, entry);
254
+ entry = link_entry(3, info, n + 2, entry);
255
+ entry = link_entry(2, info, n + 1, entry);
256
+ entry = link_entry(1, info, n + 0, entry);
257
258
add_merge_entry(entry);
259
}
@@ -288,36 +287,40 @@ static void unresolved(const char *base, struct name_entry n[3])
287
* The successful merge rules are the same as for the three-way merge
288
* in git-read-tree.
289
*/
291
-static void threeway_callback(int n, unsigned long mask, struct name_entry *entry, const char *base)
290
+static void threeway_callback(int n, unsigned long mask, struct name_entry *entry, struct traverse_info *info)
291
{
292
/* Same in both? */
293
if (same_entry(entry+1, entry+2)) {
294
if (entry[0].sha1) {
296
- resolve(base, NULL, entry+1);
295
+ resolve(info, NULL, entry+1);
296
return;
297
}
298
}
299
300
if (same_entry(entry+0, entry+1)) {
301
if (entry[2].sha1 && !S_ISDIR(entry[2].mode)) {
303
- resolve(base, entry+1, entry+2);
302
+ resolve(info, entry+1, entry+2);
303
return;
304
}
305
}
306
307
if (same_entry(entry+0, entry+2)) {
308
if (entry[1].sha1 && !S_ISDIR(entry[1].mode)) {
310
- resolve(base, NULL, entry+1);
309
+ resolve(info, NULL, entry+1);
310
return;
311
}
312
}
313
315
- unresolved(base, entry);
314
+ unresolved(info, entry);
315
}
316
317
static void merge_trees(struct tree_desc t[3], const char *base)
318
{
320
- traverse_trees(3, t, base, threeway_callback);
319
+ struct traverse_info info;
320
+
321
+ setup_traverse_info(&info, base);
322
+ info.fn = threeway_callback;
323
+ traverse_trees(3, t, &info);
324
}
325
326
static void *get_tree_descriptor(struct tree_desc *desc, const char *rev)
tree-walk.c
+33
-2
@@ -104,7 +104,38 @@ int tree_entry(struct tree_desc *desc, struct name_entry *entry)
104
return 1;
105
}
106
107
-void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callback_t callback)
107
+void setup_traverse_info(struct traverse_info *info, const char *base)
108
+{
109
+ int pathlen = strlen(base);
110
+
111
+ memset(info, 0, sizeof(*info));
112
+ if (pathlen && base[pathlen-1] == '/')
113
+ pathlen--;
114
+ info->pathlen = pathlen ? pathlen + 1 : 0;
115
+ info->name.path = base;
116
+ info->name.sha1 = (void *)(base + pathlen + 1);
117
+}
118
+
119
+char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n)
120
+{
121
+ int len = tree_entry_len(n->path, n->sha1);
122
+ int pathlen = info->pathlen;
123
+
124
+ path[pathlen + len] = 0;
125
+ for (;;) {
126
+ memcpy(path + pathlen, n->path, len);
127
+ if (!pathlen)
128
+ break;
129
+ path[--pathlen] = '/';
130
+ n = &info->name;
131
+ len = tree_entry_len(n->path, n->sha1);
132
+ info = info->prev;
133
+ pathlen -= len;
134
+ }
135
+ return path;
136
+}
137
+
138
+void traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
139
{
140
struct name_entry *entry = xmalloc(n*sizeof(*entry));
141
@@ -150,7 +181,7 @@ void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callb
181
}
182
entry_clear(entry + i);
183
}
153
- callback(n, mask, entry, base);
184
+ info->fn(n, mask, entry, info);
185
}
186
free(entry);
187
}
tree-walk.h
+18
-2
@@ -33,10 +33,26 @@ int tree_entry(struct tree_desc *, struct name_entry *);
33
34
void *fill_tree_descriptor(struct tree_desc *desc, const unsigned char *sha1);
35
36
-typedef void (*traverse_callback_t)(int n, unsigned long mask, struct name_entry *entry, const char *base);
36
+struct traverse_info;
37
+typedef void (*traverse_callback_t)(int n, unsigned long mask, struct name_entry *entry, struct traverse_info *);
38
+void traverse_trees(int n, struct tree_desc *t, struct traverse_info *info);
39
38
-void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callback_t callback);
40
+struct traverse_info {
41
+ struct traverse_info *prev;
42
+ struct name_entry name;
43
+ int pathlen;
44
+
45
+ traverse_callback_t fn;
46
+ void *data;
47
+};
48
49
int get_tree_entry(const unsigned char *, const char *, unsigned char *, unsigned *);
50
+extern char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n);
51
+extern void setup_traverse_info(struct traverse_info *info, const char *base);
52
+
53
+static inline int traverse_path_len(const struct traverse_info *info, const struct name_entry *n)
54
+{
55
+ return info->pathlen + tree_entry_len(n->path, n->sha1);
56
+}
57
58
#endif