/*
* 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
#include "cache.h"
#include "config.h"
#include "exec-cmd.h"
#include "attr.h"
#include "dir.h"
#include "utf8.h"
#include "quote.h"
#include "thread-utils.h"
const char git_attr__true[] = "(builtin)true";
const char git_attr__false[] = "\0(builtin)false";
static const char git_attr__unknown[] = "(builtin)unknown";
#define ATTR__TRUE git_attr__true
#define ATTR__FALSE git_attr__false
#define ATTR__UNSET NULL
#define ATTR__UNKNOWN git_attr__unknown
#ifndef DEBUG_ATTR
#define DEBUG_ATTR 0
#endif
struct git_attr {
int attr_nr; /* unique attribute number */
char name[FLEX_ARRAY]; /* attribute name */
};
const char *git_attr_name(const struct git_attr *attr)
{
return attr->name;
}
struct attr_hashmap {
struct hashmap map;
#ifndef NO_PTHREADS
pthread_mutex_t mutex;
#endif
};
static inline void hashmap_lock(struct attr_hashmap *map)
{
#ifndef NO_PTHREADS
pthread_mutex_lock(&map->mutex);
#endif
}
static inline void hashmap_unlock(struct attr_hashmap *map)
{
#ifndef NO_PTHREADS
pthread_mutex_unlock(&map->mutex);
#endif
}
/*
* The global dictionary of all interned attributes. This
* is a singleton object which is shared between threads.
* Access to this dictionary must be surrounded with a mutex.
*/
static struct attr_hashmap g_attr_hashmap;
/* The container for objects stored in "struct attr_hashmap" */
struct attr_hash_entry {
struct hashmap_entry ent; /* must be the first member! */
const char *key; /* the key; memory should be owned by value */
size_t keylen; /* length of the key */
void *value; /* the stored value */
};
/* attr_hashmap comparison function */
static int attr_hash_entry_cmp(const void *unused_cmp_data,
const void *entry,
const void *entry_or_key,
const void *unused_keydata)
{
const struct attr_hash_entry *a = entry;
const struct attr_hash_entry *b = entry_or_key;
return (a->keylen != b->keylen) || strncmp(a->key, b->key, a->keylen);
}
/* Initialize an 'attr_hashmap' object */
static void attr_hashmap_init(struct attr_hashmap *map)
{
hashmap_init(&map->map, attr_hash_entry_cmp, NULL, 0);
}
/*
* Retrieve the 'value' stored in a hashmap given the provided 'key'.
* If there is no matching entry, return NULL.
*/
static void *attr_hashmap_get(struct attr_hashmap *map,
const char *key, size_t keylen)
{
struct attr_hash_entry k;
struct attr_hash_entry *e;
if (!map->map.tablesize)
attr_hashmap_init(map);
hashmap_entry_init(&k, memhash(key, keylen));
k.key = key;
k.keylen = keylen;
e = hashmap_get(&map->map, &k, NULL);
return e ? e->value : NULL;
}
/* Add 'value' to a hashmap based on the provided 'key'. */
static void attr_hashmap_add(struct attr_hashmap *map,
const char *key, size_t keylen,
void *value)
{
struct attr_hash_entry *e;
if (!map->map.tablesize)
attr_hashmap_init(map);
e = xmalloc(sizeof(struct attr_hash_entry));
hashmap_entry_init(e, memhash(key, keylen));
e->key = key;
e->keylen = keylen;
e->value = value;
hashmap_add(&map->map, e);
}
struct all_attrs_item {
const struct git_attr *attr;
const char *value;
/*
* If 'macro' is non-NULL, indicates that 'attr' is a macro based on
* the current attribute stack and contains a pointer to the match_attr
* definition of the macro
*/
const struct match_attr *macro;
};
/*
* Reallocate and reinitialize the array of all attributes (which is used in
* the attribute collection process) in 'check' based on the global dictionary
* of attributes.
*/
static void all_attrs_init(struct attr_hashmap *map, struct attr_check *check)
{
int i;
unsigned int size;
hashmap_lock(map);
size = hashmap_get_size(&map->map);
if (size < check->all_attrs_nr)
BUG("interned attributes shouldn't be deleted");
/*
* If the number of attributes in the global dictionary has increased
* (or this attr_check instance doesn't have an initialized all_attrs
* field), reallocate the provided attr_check instance's all_attrs
|