return 0;
}
- void add_object_array(struct object *obj, const char *name, struct object_array *array)
- {
- add_object_array_with_mode(obj, name, array, S_IFINVALID);
- }
-
-static void add_object_array_with_mode_context(struct object *obj, const char *name, struct object_array *array, unsigned mode, struct object_context *context)
+/*
+ * A zero-length string to which object_array_entry::name can be
+ * initialized without requiring a malloc/free.
+ */
+static char object_array_slopbuf[1];
+
- void add_object_array_with_mode(struct object *obj, const char *name, struct object_array *array, unsigned mode)
++static void add_object_array_with_mode_context(struct object *obj, const char *name,
++ struct object_array *array,
++ unsigned mode,
++ struct object_context *context)
{
unsigned nr = array->nr;
unsigned alloc = array->alloc;
array->alloc = alloc;
array->objects = objects;
}
- objects[nr].item = obj;
- objects[nr].name = name;
- objects[nr].mode = mode;
- objects[nr].context = context;
+ entry = &objects[nr];
+ entry->item = obj;
+ if (!name)
+ entry->name = NULL;
+ else if (!*name)
+ /* Use our own empty string instead of allocating one: */
+ entry->name = object_array_slopbuf;
+ else
+ entry->name = xstrdup(name);
+ entry->mode = mode;
++ entry->context = context;
array->nr = ++nr;
}
-void object_array_remove_duplicates(struct object_array *array)
+ void add_object_array(struct object *obj, const char *name, struct object_array *array)
+ {
+ add_object_array_with_mode(obj, name, array, S_IFINVALID);
+ }
+
+ void add_object_array_with_mode(struct object *obj, const char *name, struct object_array *array, unsigned mode)
+ {
+ add_object_array_with_mode_context(obj, name, array, mode, NULL);
+ }
+
+ void add_object_array_with_context(struct object *obj, const char *name, struct object_array *array, struct object_context *context)
+ {
+ if (context)
+ add_object_array_with_mode_context(obj, name, array, context->mode, context);
+ else
+ add_object_array_with_mode_context(obj, name, array, S_IFINVALID, context);
+ }
+
+void object_array_filter(struct object_array *array,
+ object_array_each_func_t want, void *cb_data)
{
- unsigned int ref, src, dst;
+ unsigned nr = array->nr, src, dst;
struct object_array_entry *objects = array->objects;
- for (ref = 0; ref + 1 < array->nr; ref++) {
- for (src = ref + 1, dst = src;
- src < array->nr;
- src++) {
- if (!strcmp(objects[ref].name, objects[src].name))
- continue;
+ for (src = dst = 0; src < nr; src++) {
+ if (want(&objects[src], cb_data)) {
if (src != dst)
objects[dst] = objects[src];
dst++;
unsigned int alloc;
struct object_array_entry {
struct object *item;
- const char *name;
+ /*
+ * name or NULL. If non-NULL, the memory pointed to
+ * is owned by this object *except* if it points at
+ * object_array_slopbuf, which is a static copy of the
+ * empty string.
+ */
+ char *name;
unsigned mode;
+ struct object_context *context;
} *objects;
};
/* Object array handling .. */
void add_object_array(struct object *obj, const char *name, struct object_array *array);
void add_object_array_with_mode(struct object *obj, const char *name, struct object_array *array, unsigned mode);
-void object_array_remove_duplicates(struct object_array *);
+ void add_object_array_with_context(struct object *obj, const char *name, struct object_array *array, struct object_context *context);
+
+typedef int (*object_array_each_func_t)(struct object_array_entry *, void *);
+
+/*
+ * Apply want to each entry in array, retaining only the entries for
+ * which the function returns true. Preserve the order of the entries
+ * that are retained.
+ */
+void object_array_filter(struct object_array *array,
+ object_array_each_func_t want, void *cb_data);
+
+/*
+ * Remove from array all but the first entry with a given name.
+ * Warning: this function uses an O(N^2) algorithm.
+ */
+void object_array_remove_duplicates(struct object_array *array);
void clear_object_flags(unsigned flags);
test_cmp expected result
'
-test_expect_success SYMLINKS 'cat-file without --textconv (symlink)' '
+test_expect_success 'cat-file without --textconv (symlink)' '
+ printf "%s" "one.bin" >expected &&
git cat-file blob :symlink.bin >result &&
- printf "%s" "one.bin" >expected
test_cmp expected result
'
-test_expect_success SYMLINKS 'cat-file --textconv on index (symlink)' '
+test_expect_success 'cat-file --textconv on index (symlink)' '
- ! git cat-file --textconv :symlink.bin 2>result &&
- cat >expected <<\EOF &&
- fatal: git cat-file --textconv: unable to run textconv on :symlink.bin
- EOF
+ git cat-file --textconv :symlink.bin >result &&
test_cmp expected result
'
-test_expect_success SYMLINKS 'cat-file --textconv on HEAD (symlink)' '
+test_expect_success 'cat-file --textconv on HEAD (symlink)' '
- ! git cat-file --textconv HEAD:symlink.bin 2>result &&
- cat >expected <<EOF &&
- fatal: git cat-file --textconv: unable to run textconv on HEAD:symlink.bin
- EOF
+ git cat-file --textconv HEAD:symlink.bin >result &&
test_cmp expected result
'