| 191 | } |
| 192 | |
| 193 | static void parse_pathspec_attr_match(struct pathspec_item *item, const char *value) |
| 194 | { |
| 195 | struct string_list_item *si; |
| 196 | struct string_list list = STRING_LIST_INIT_DUP; |
| 197 | |
| 198 | if (item->attr_check || item->attr_match) |
| 199 | die(_("Only one 'attr:' specification is allowed.")); |
| 200 | |
| 201 | if (!value || !*value) |
| 202 | die(_("attr spec must not be empty")); |
| 203 | |
| 204 | string_list_split_f(&list, value, " ", -1, STRING_LIST_SPLIT_NONEMPTY); |
| 205 | |
| 206 | item->attr_check = attr_check_alloc(); |
| 207 | CALLOC_ARRAY(item->attr_match, list.nr); |
| 208 | |
| 209 | for_each_string_list_item(si, &list) { |
| 210 | size_t attr_len; |
| 211 | char *attr_name; |
| 212 | const struct git_attr *a; |
| 213 | |
| 214 | int j = item->attr_match_nr++; |
| 215 | const char *attr = si->string; |
| 216 | struct attr_match *am = &item->attr_match[j]; |
| 217 | |
| 218 | switch (*attr) { |
| 219 | case '!': |
| 220 | am->match_mode = MATCH_UNSPECIFIED; |
| 221 | attr++; |
| 222 | attr_len = strlen(attr); |
| 223 | break; |
| 224 | case '-': |
| 225 | am->match_mode = MATCH_UNSET; |
| 226 | attr++; |
| 227 | attr_len = strlen(attr); |
| 228 | break; |
| 229 | default: |
| 230 | attr_len = strcspn(attr, "="); |
| 231 | if (attr[attr_len] != '=') |
| 232 | am->match_mode = MATCH_SET; |
| 233 | else { |
| 234 | const char *v = &attr[attr_len + 1]; |
| 235 | am->match_mode = MATCH_VALUE; |
| 236 | am->value = attr_value_unescape(v); |
| 237 | } |
| 238 | break; |
| 239 | } |
| 240 | |
| 241 | attr_name = xmemdupz(attr, attr_len); |
| 242 | a = git_attr(attr_name); |
| 243 | if (!a) |
| 244 | die(_("invalid attribute name %s"), attr_name); |
| 245 | |
| 246 | attr_check_append(item->attr_check, a); |
| 247 | |
| 248 | free(attr_name); |
| 249 | } |
| 250 |
no test coverage detected