# gitattributes API

gitattributes mechanism gives a uniform way to associate various attributes to set of paths.

## Data Structure

`struct git_attr`

  An attribute is an opaque object that is identified by its name. Pass the name to `git_attr()` function to obtain the object of this type. The internal representation of this structure is of no interest to the calling programs. The name of the attribute can be retrieved by calling `git_attr_name()`.

`struct attr_check_item`

  This structure represents one attribute and its value.

`struct attr_check`

  This structure represents a collection of `attr_check_item`. It is passed to `git_check_attr()` function, specifying the attributes to check, and receives their values.

## Attribute Values

An attribute for a path can be in one of four states: Set, Unset, Unspecified or set to a string, and `.value` member of `struct attr_check_item` records it. There are three macros to check these:

`ATTR_TRUE()`

  Returns true if the attribute is Set for the path.

`ATTR_FALSE()`

  Returns true if the attribute is Unset for the path.

`ATTR_UNSET()`

  Returns true if the attribute is Unspecified for the path.

If none of the above returns true, `.value` member points at a string value of the attribute for the path.

## Querying Specific Attributes

- Prepare `struct attr_check` using attr_check_initl() function, enumerating the names of attributes whose values you are interested in, terminated with a NULL pointer. Alternatively, an empty `struct attr_check` can be prepared by calling `attr_check_alloc()` function and then attributes you want to ask about can be added to it with `attr_check_append()` function.

- Call `git_check_attr()` to check the attributes for the path.

- Inspect `attr_check` structure to see how each of the attribute in the array is defined for the path.

## Example

To see how attributes "crlf" and "ident" are set for different paths.

1. Prepare a `struct attr_check` with two elements (because we are checking two attributes):

    static struct attr_check *check;
    static void setup_check(void)
    {
    	if (check)
    		return; /* already done */
    	check = attr_check_initl("crlf", "ident", NULL);
    }

1. Call `git_check_attr()` with the prepared `struct attr_check`:

    	const char *path;

    	setup_check();
    	git_check_attr(path, check);

1. Act on `.value` member of the result, left in `check->items[]`:

    	const char *value = check->items[0].value;

    	if (ATTR_TRUE(value)) {
    		The attribute is Set, by listing only the name of the
    		attribute in the gitattributes file for the path.
    	} else if (ATTR_FALSE(value)) {
    		The attribute is Unset, by listing the name of the
    		attribute prefixed with a dash - for the path.
    	} else if (ATTR_UNSET(value)) {
    		The attribute is neither set nor unset for the path.
    	} else if (!strcmp(value, "input")) {
    		If none of ATTR_TRUE(), ATTR_FALSE(), or ATTR_UNSET() is
    		true, the value is a string set in the gitattributes
    		file for the path by saying "attr=value".
    	} else if (... other check using value as string ...) {
    		...
    	}

To see how attributes in argv[] are set for different paths, only the first step in the above would be different.

    static struct attr_check *check;
    static void setup_check(const char **argv)
    {
    	check = attr_check_alloc();
    	while (*argv) {
    		struct git_attr *attr = git_attr(*argv);
    		attr_check_append(check, attr);
    		argv++;
    	}
    }

## Querying All Attributes

To get the values of all attributes associated with a file:

- Prepare an empty `attr_check` structure by calling `attr_check_alloc()`.

- Call `git_all_attrs()`, which populates the `attr_check` with the attributes attached to the path.

- Iterate over the `attr_check.items[]` array to examine the attribute names and values. The name of the attribute described by an `attr_check.items[]` object can be retrieved via `git_attr_name(check->items[i].attr)`. (Please note that no items will be returned for unset attributes, so `ATTR_UNSET()` will return false for all returned `attr_check.items[]` objects.)

- Free the `attr_check` struct by calling `attr_check_free()`.