| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | /* | 
| 2 |  |  |  |  |  |  | * Copyright (C) the libgit2 contributors. All rights reserved. | 
| 3 |  |  |  |  |  |  | * | 
| 4 |  |  |  |  |  |  | * This file is part of libgit2, distributed under the GNU GPL v2 with | 
| 5 |  |  |  |  |  |  | * a Linking Exception. For full terms see the included COPYING file. | 
| 6 |  |  |  |  |  |  | */ | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | #include "diff_driver.h" | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | #include "git2/attr.h" | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | #include "common.h" | 
| 13 |  |  |  |  |  |  | #include "diff.h" | 
| 14 |  |  |  |  |  |  | #include "strmap.h" | 
| 15 |  |  |  |  |  |  | #include "map.h" | 
| 16 |  |  |  |  |  |  | #include "config.h" | 
| 17 |  |  |  |  |  |  | #include "regexp.h" | 
| 18 |  |  |  |  |  |  | #include "repository.h" | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | typedef enum { | 
| 21 |  |  |  |  |  |  | DIFF_DRIVER_AUTO = 0, | 
| 22 |  |  |  |  |  |  | DIFF_DRIVER_BINARY = 1, | 
| 23 |  |  |  |  |  |  | DIFF_DRIVER_TEXT = 2, | 
| 24 |  |  |  |  |  |  | DIFF_DRIVER_PATTERNLIST = 3 | 
| 25 |  |  |  |  |  |  | } git_diff_driver_t; | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | typedef struct { | 
| 28 |  |  |  |  |  |  | git_regexp re; | 
| 29 |  |  |  |  |  |  | int flags; | 
| 30 |  |  |  |  |  |  | } git_diff_driver_pattern; | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | enum { | 
| 33 |  |  |  |  |  |  | REG_NEGATE = (1 << 15) /* get out of the way of existing flags */ | 
| 34 |  |  |  |  |  |  | }; | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | /* data for finding function context for a given file type */ | 
| 37 |  |  |  |  |  |  | struct git_diff_driver { | 
| 38 |  |  |  |  |  |  | git_diff_driver_t type; | 
| 39 |  |  |  |  |  |  | uint32_t binary_flags; | 
| 40 |  |  |  |  |  |  | uint32_t other_flags; | 
| 41 |  |  |  |  |  |  | git_array_t(git_diff_driver_pattern) fn_patterns; | 
| 42 |  |  |  |  |  |  | git_regexp  word_pattern; | 
| 43 |  |  |  |  |  |  | char name[GIT_FLEX_ARRAY]; | 
| 44 |  |  |  |  |  |  | }; | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | #include "userdiff.h" | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  | struct git_diff_driver_registry { | 
| 49 |  |  |  |  |  |  | git_strmap *drivers; | 
| 50 |  |  |  |  |  |  | }; | 
| 51 |  |  |  |  |  |  |  | 
| 52 |  |  |  |  |  |  | #define FORCE_DIFFABLE (GIT_DIFF_FORCE_TEXT | GIT_DIFF_FORCE_BINARY) | 
| 53 |  |  |  |  |  |  |  | 
| 54 |  |  |  |  |  |  | static git_diff_driver diff_driver_auto =   { DIFF_DRIVER_AUTO,   0, 0 }; | 
| 55 |  |  |  |  |  |  | static git_diff_driver diff_driver_binary = { DIFF_DRIVER_BINARY, GIT_DIFF_FORCE_BINARY, 0 }; | 
| 56 |  |  |  |  |  |  | static git_diff_driver diff_driver_text =   { DIFF_DRIVER_TEXT,   GIT_DIFF_FORCE_TEXT, 0 }; | 
| 57 |  |  |  |  |  |  |  | 
| 58 | 0 |  |  |  |  |  | git_diff_driver_registry *git_diff_driver_registry_new(void) | 
| 59 |  |  |  |  |  |  | { | 
| 60 | 0 |  |  |  |  |  | git_diff_driver_registry *reg = | 
| 61 | 0 |  |  |  |  |  | git__calloc(1, sizeof(git_diff_driver_registry)); | 
| 62 | 0 | 0 |  |  |  |  | if (!reg) | 
| 63 | 0 |  |  |  |  |  | return NULL; | 
| 64 |  |  |  |  |  |  |  | 
| 65 | 0 | 0 |  |  |  |  | if (git_strmap_new(®->drivers) < 0) { | 
| 66 | 0 |  |  |  |  |  | git_diff_driver_registry_free(reg); | 
| 67 | 0 |  |  |  |  |  | return NULL; | 
| 68 |  |  |  |  |  |  | } | 
| 69 |  |  |  |  |  |  |  | 
| 70 | 0 |  |  |  |  |  | return reg; | 
| 71 |  |  |  |  |  |  | } | 
| 72 |  |  |  |  |  |  |  | 
| 73 | 63 |  |  |  |  |  | void git_diff_driver_registry_free(git_diff_driver_registry *reg) | 
| 74 |  |  |  |  |  |  | { | 
| 75 |  |  |  |  |  |  | git_diff_driver *drv; | 
| 76 |  |  |  |  |  |  |  | 
| 77 | 63 | 50 |  |  |  |  | if (!reg) | 
| 78 | 63 |  |  |  |  |  | return; | 
| 79 |  |  |  |  |  |  |  | 
| 80 | 0 | 0 |  |  |  |  | git_strmap_foreach_value(reg->drivers, drv, git_diff_driver_free(drv)); | 
| 81 | 0 |  |  |  |  |  | git_strmap_free(reg->drivers); | 
| 82 | 0 |  |  |  |  |  | git__free(reg); | 
| 83 |  |  |  |  |  |  | } | 
| 84 |  |  |  |  |  |  |  | 
| 85 | 0 |  |  |  |  |  | static int diff_driver_add_patterns( | 
| 86 |  |  |  |  |  |  | git_diff_driver *drv, const char *regex_str, int regex_flags) | 
| 87 |  |  |  |  |  |  | { | 
| 88 | 0 |  |  |  |  |  | int error = 0; | 
| 89 |  |  |  |  |  |  | const char *scan, *end; | 
| 90 | 0 |  |  |  |  |  | git_diff_driver_pattern *pat = NULL; | 
| 91 | 0 |  |  |  |  |  | git_str buf = GIT_STR_INIT; | 
| 92 |  |  |  |  |  |  |  | 
| 93 | 0 | 0 |  |  |  |  | for (scan = regex_str; scan; scan = end) { | 
| 94 |  |  |  |  |  |  | /* get pattern to fill in */ | 
| 95 | 0 | 0 |  |  |  |  | if ((pat = git_array_alloc(drv->fn_patterns)) == NULL) { | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 96 | 0 |  |  |  |  |  | return -1; | 
| 97 |  |  |  |  |  |  | } | 
| 98 |  |  |  |  |  |  |  | 
| 99 | 0 |  |  |  |  |  | pat->flags = regex_flags; | 
| 100 | 0 | 0 |  |  |  |  | if (*scan == '!') { | 
| 101 | 0 |  |  |  |  |  | pat->flags |= REG_NEGATE; | 
| 102 | 0 |  |  |  |  |  | ++scan; | 
| 103 |  |  |  |  |  |  | } | 
| 104 |  |  |  |  |  |  |  | 
| 105 | 0 | 0 |  |  |  |  | if ((end = strchr(scan, '\n')) != NULL) { | 
| 106 | 0 |  |  |  |  |  | error = git_str_set(&buf, scan, end - scan); | 
| 107 | 0 |  |  |  |  |  | end++; | 
| 108 |  |  |  |  |  |  | } else { | 
| 109 | 0 |  |  |  |  |  | error = git_str_sets(&buf, scan); | 
| 110 |  |  |  |  |  |  | } | 
| 111 | 0 | 0 |  |  |  |  | if (error < 0) | 
| 112 | 0 |  |  |  |  |  | break; | 
| 113 |  |  |  |  |  |  |  | 
| 114 | 0 |  |  |  |  |  | if ((error = git_regexp_compile(&pat->re, buf.ptr, regex_flags)) != 0) { | 
| 115 |  |  |  |  |  |  | /* | 
| 116 |  |  |  |  |  |  | * TODO: issue a warning | 
| 117 |  |  |  |  |  |  | */ | 
| 118 |  |  |  |  |  |  | } | 
| 119 |  |  |  |  |  |  | } | 
| 120 |  |  |  |  |  |  |  | 
| 121 | 0 | 0 |  |  |  |  | if (error && pat != NULL) | 
|  |  | 0 |  |  |  |  |  | 
| 122 | 0 | 0 |  |  |  |  | (void)git_array_pop(drv->fn_patterns); /* release last item */ | 
| 123 | 0 |  |  |  |  |  | git_str_dispose(&buf); | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | /* We want to ignore bad patterns, so return success regardless */ | 
| 126 | 0 |  |  |  |  |  | return 0; | 
| 127 |  |  |  |  |  |  | } | 
| 128 |  |  |  |  |  |  |  | 
| 129 | 0 |  |  |  |  |  | static int diff_driver_xfuncname(const git_config_entry *entry, void *payload) | 
| 130 |  |  |  |  |  |  | { | 
| 131 | 0 |  |  |  |  |  | return diff_driver_add_patterns(payload, entry->value, 0); | 
| 132 |  |  |  |  |  |  | } | 
| 133 |  |  |  |  |  |  |  | 
| 134 | 0 |  |  |  |  |  | static int diff_driver_funcname(const git_config_entry *entry, void *payload) | 
| 135 |  |  |  |  |  |  | { | 
| 136 | 0 |  |  |  |  |  | return diff_driver_add_patterns(payload, entry->value, 0); | 
| 137 |  |  |  |  |  |  | } | 
| 138 |  |  |  |  |  |  |  | 
| 139 | 0 |  |  |  |  |  | static git_diff_driver_registry *git_repository_driver_registry( | 
| 140 |  |  |  |  |  |  | git_repository *repo) | 
| 141 |  |  |  |  |  |  | { | 
| 142 | 0 |  |  |  |  |  | git_diff_driver_registry *reg = git_atomic_load(repo->diff_drivers), *newreg; | 
| 143 | 0 | 0 |  |  |  |  | if (reg) | 
| 144 | 0 |  |  |  |  |  | return reg; | 
| 145 |  |  |  |  |  |  |  | 
| 146 | 0 |  |  |  |  |  | newreg = git_diff_driver_registry_new(); | 
| 147 | 0 | 0 |  |  |  |  | if (!newreg) { | 
| 148 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_REPOSITORY, "unable to create diff driver registry"); | 
| 149 | 0 |  |  |  |  |  | return newreg; | 
| 150 |  |  |  |  |  |  | } | 
| 151 | 0 |  |  |  |  |  | reg = git_atomic_compare_and_swap(&repo->diff_drivers, NULL, newreg); | 
| 152 | 0 | 0 |  |  |  |  | if (!reg) { | 
| 153 | 0 |  |  |  |  |  | reg = newreg; | 
| 154 |  |  |  |  |  |  | } else { | 
| 155 |  |  |  |  |  |  | /* if we race, free losing allocation */ | 
| 156 | 0 |  |  |  |  |  | git_diff_driver_registry_free(newreg); | 
| 157 |  |  |  |  |  |  | } | 
| 158 | 0 |  |  |  |  |  | return reg; | 
| 159 |  |  |  |  |  |  | } | 
| 160 |  |  |  |  |  |  |  | 
| 161 | 0 |  |  |  |  |  | static int diff_driver_alloc( | 
| 162 |  |  |  |  |  |  | git_diff_driver **out, size_t *namelen_out, const char *name) | 
| 163 |  |  |  |  |  |  | { | 
| 164 |  |  |  |  |  |  | git_diff_driver *driver; | 
| 165 | 0 |  |  |  |  |  | size_t driverlen = sizeof(git_diff_driver), | 
| 166 | 0 |  |  |  |  |  | namelen = strlen(name), | 
| 167 |  |  |  |  |  |  | alloclen; | 
| 168 |  |  |  |  |  |  |  | 
| 169 | 0 | 0 |  |  |  |  | GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, driverlen, namelen); | 
|  |  | 0 |  |  |  |  |  | 
| 170 | 0 | 0 |  |  |  |  | GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1); | 
|  |  | 0 |  |  |  |  |  | 
| 171 |  |  |  |  |  |  |  | 
| 172 | 0 |  |  |  |  |  | driver = git__calloc(1, alloclen); | 
| 173 | 0 | 0 |  |  |  |  | GIT_ERROR_CHECK_ALLOC(driver); | 
| 174 |  |  |  |  |  |  |  | 
| 175 | 0 |  |  |  |  |  | memcpy(driver->name, name, namelen); | 
| 176 |  |  |  |  |  |  |  | 
| 177 | 0 |  |  |  |  |  | *out = driver; | 
| 178 |  |  |  |  |  |  |  | 
| 179 | 0 | 0 |  |  |  |  | if (namelen_out) | 
| 180 | 0 |  |  |  |  |  | *namelen_out = namelen; | 
| 181 |  |  |  |  |  |  |  | 
| 182 | 0 |  |  |  |  |  | return 0; | 
| 183 |  |  |  |  |  |  | } | 
| 184 |  |  |  |  |  |  |  | 
| 185 | 0 |  |  |  |  |  | static int git_diff_driver_builtin( | 
| 186 |  |  |  |  |  |  | git_diff_driver **out, | 
| 187 |  |  |  |  |  |  | git_diff_driver_registry *reg, | 
| 188 |  |  |  |  |  |  | const char *driver_name) | 
| 189 |  |  |  |  |  |  | { | 
| 190 | 0 |  |  |  |  |  | git_diff_driver_definition *ddef = NULL; | 
| 191 | 0 |  |  |  |  |  | git_diff_driver *drv = NULL; | 
| 192 | 0 |  |  |  |  |  | int error = 0; | 
| 193 |  |  |  |  |  |  | size_t idx; | 
| 194 |  |  |  |  |  |  |  | 
| 195 | 0 | 0 |  |  |  |  | for (idx = 0; idx < ARRAY_SIZE(builtin_defs); ++idx) { | 
| 196 | 0 | 0 |  |  |  |  | if (!strcasecmp(driver_name, builtin_defs[idx].name)) { | 
| 197 | 0 |  |  |  |  |  | ddef = &builtin_defs[idx]; | 
| 198 | 0 |  |  |  |  |  | break; | 
| 199 |  |  |  |  |  |  | } | 
| 200 |  |  |  |  |  |  | } | 
| 201 | 0 | 0 |  |  |  |  | if (!ddef) | 
| 202 | 0 |  |  |  |  |  | goto done; | 
| 203 |  |  |  |  |  |  |  | 
| 204 | 0 | 0 |  |  |  |  | if ((error = diff_driver_alloc(&drv, NULL, ddef->name)) < 0) | 
| 205 | 0 |  |  |  |  |  | goto done; | 
| 206 |  |  |  |  |  |  |  | 
| 207 | 0 |  |  |  |  |  | drv->type = DIFF_DRIVER_PATTERNLIST; | 
| 208 |  |  |  |  |  |  |  | 
| 209 | 0 | 0 |  |  |  |  | if (ddef->fns && | 
|  |  | 0 |  |  |  |  |  | 
| 210 | 0 |  |  |  |  |  | (error = diff_driver_add_patterns( | 
| 211 |  |  |  |  |  |  | drv, ddef->fns, ddef->flags)) < 0) | 
| 212 | 0 |  |  |  |  |  | goto done; | 
| 213 |  |  |  |  |  |  |  | 
| 214 | 0 | 0 |  |  |  |  | if (ddef->words && | 
|  |  | 0 |  |  |  |  |  | 
| 215 | 0 |  |  |  |  |  | (error = git_regexp_compile(&drv->word_pattern, ddef->words, ddef->flags)) < 0) | 
| 216 | 0 |  |  |  |  |  | goto done; | 
| 217 |  |  |  |  |  |  |  | 
| 218 | 0 | 0 |  |  |  |  | if ((error = git_strmap_set(reg->drivers, drv->name, drv)) < 0) | 
| 219 | 0 |  |  |  |  |  | goto done; | 
| 220 |  |  |  |  |  |  |  | 
| 221 |  |  |  |  |  |  | done: | 
| 222 | 0 | 0 |  |  |  |  | if (error && drv) | 
|  |  | 0 |  |  |  |  |  | 
| 223 | 0 |  |  |  |  |  | git_diff_driver_free(drv); | 
| 224 |  |  |  |  |  |  | else | 
| 225 | 0 |  |  |  |  |  | *out = drv; | 
| 226 |  |  |  |  |  |  |  | 
| 227 | 0 |  |  |  |  |  | return error; | 
| 228 |  |  |  |  |  |  | } | 
| 229 |  |  |  |  |  |  |  | 
| 230 | 0 |  |  |  |  |  | static int git_diff_driver_load( | 
| 231 |  |  |  |  |  |  | git_diff_driver **out, git_repository *repo, const char *driver_name) | 
| 232 |  |  |  |  |  |  | { | 
| 233 | 0 |  |  |  |  |  | int error = 0; | 
| 234 |  |  |  |  |  |  | git_diff_driver_registry *reg; | 
| 235 |  |  |  |  |  |  | git_diff_driver *drv; | 
| 236 |  |  |  |  |  |  | size_t namelen; | 
| 237 | 0 |  |  |  |  |  | git_config *cfg = NULL; | 
| 238 | 0 |  |  |  |  |  | git_str name = GIT_STR_INIT; | 
| 239 | 0 |  |  |  |  |  | git_config_entry *ce = NULL; | 
| 240 | 0 |  |  |  |  |  | bool found_driver = false; | 
| 241 |  |  |  |  |  |  |  | 
| 242 | 0 | 0 |  |  |  |  | if ((reg = git_repository_driver_registry(repo)) == NULL) | 
| 243 | 0 |  |  |  |  |  | return -1; | 
| 244 |  |  |  |  |  |  |  | 
| 245 | 0 | 0 |  |  |  |  | if ((drv = git_strmap_get(reg->drivers, driver_name)) != NULL) { | 
| 246 | 0 |  |  |  |  |  | *out = drv; | 
| 247 | 0 |  |  |  |  |  | return 0; | 
| 248 |  |  |  |  |  |  | } | 
| 249 |  |  |  |  |  |  |  | 
| 250 | 0 | 0 |  |  |  |  | if ((error = diff_driver_alloc(&drv, &namelen, driver_name)) < 0) | 
| 251 | 0 |  |  |  |  |  | goto done; | 
| 252 |  |  |  |  |  |  |  | 
| 253 | 0 |  |  |  |  |  | drv->type = DIFF_DRIVER_AUTO; | 
| 254 |  |  |  |  |  |  |  | 
| 255 |  |  |  |  |  |  | /* if you can't read config for repo, just use default driver */ | 
| 256 | 0 | 0 |  |  |  |  | if (git_repository_config_snapshot(&cfg, repo) < 0) { | 
| 257 | 0 |  |  |  |  |  | git_error_clear(); | 
| 258 | 0 |  |  |  |  |  | goto done; | 
| 259 |  |  |  |  |  |  | } | 
| 260 |  |  |  |  |  |  |  | 
| 261 | 0 | 0 |  |  |  |  | if ((error = git_str_printf(&name, "diff.%s.binary", driver_name)) < 0) | 
| 262 | 0 |  |  |  |  |  | goto done; | 
| 263 |  |  |  |  |  |  |  | 
| 264 | 0 |  |  |  |  |  | switch (git_config__get_bool_force(cfg, name.ptr, -1)) { | 
| 265 |  |  |  |  |  |  | case true: | 
| 266 |  |  |  |  |  |  | /* if diff..binary is true, just return the binary driver */ | 
| 267 | 0 |  |  |  |  |  | *out = &diff_driver_binary; | 
| 268 | 0 |  |  |  |  |  | goto done; | 
| 269 |  |  |  |  |  |  | case false: | 
| 270 |  |  |  |  |  |  | /* if diff..binary is false, force binary checks off */ | 
| 271 |  |  |  |  |  |  | /* but still may have custom function context patterns, etc. */ | 
| 272 | 0 |  |  |  |  |  | drv->binary_flags = GIT_DIFF_FORCE_TEXT; | 
| 273 | 0 |  |  |  |  |  | found_driver = true; | 
| 274 | 0 |  |  |  |  |  | break; | 
| 275 |  |  |  |  |  |  | default: | 
| 276 |  |  |  |  |  |  | /* diff..binary unspecified or "auto", so just continue */ | 
| 277 | 0 |  |  |  |  |  | break; | 
| 278 |  |  |  |  |  |  | } | 
| 279 |  |  |  |  |  |  |  | 
| 280 |  |  |  |  |  |  | /* TODO: warn if diff..command or diff..textconv are set */ | 
| 281 |  |  |  |  |  |  |  | 
| 282 | 0 |  |  |  |  |  | git_str_truncate(&name, namelen + strlen("diff..")); | 
| 283 | 0 | 0 |  |  |  |  | if ((error = git_str_PUTS(&name, "xfuncname")) < 0) | 
| 284 | 0 |  |  |  |  |  | goto done; | 
| 285 |  |  |  |  |  |  |  | 
| 286 | 0 | 0 |  |  |  |  | if ((error = git_config_get_multivar_foreach( | 
| 287 | 0 |  |  |  |  |  | cfg, name.ptr, NULL, diff_driver_xfuncname, drv)) < 0) { | 
| 288 | 0 | 0 |  |  |  |  | if (error != GIT_ENOTFOUND) | 
| 289 | 0 |  |  |  |  |  | goto done; | 
| 290 | 0 |  |  |  |  |  | git_error_clear(); /* no diff..xfuncname, so just continue */ | 
| 291 |  |  |  |  |  |  | } | 
| 292 |  |  |  |  |  |  |  | 
| 293 | 0 |  |  |  |  |  | git_str_truncate(&name, namelen + strlen("diff..")); | 
| 294 | 0 | 0 |  |  |  |  | if ((error = git_str_PUTS(&name, "funcname")) < 0) | 
| 295 | 0 |  |  |  |  |  | goto done; | 
| 296 |  |  |  |  |  |  |  | 
| 297 | 0 | 0 |  |  |  |  | if ((error = git_config_get_multivar_foreach( | 
| 298 | 0 |  |  |  |  |  | cfg, name.ptr, NULL, diff_driver_funcname, drv)) < 0) { | 
| 299 | 0 | 0 |  |  |  |  | if (error != GIT_ENOTFOUND) | 
| 300 | 0 |  |  |  |  |  | goto done; | 
| 301 | 0 |  |  |  |  |  | git_error_clear(); /* no diff..funcname, so just continue */ | 
| 302 |  |  |  |  |  |  | } | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | /* if we found any patterns, set driver type to use correct callback */ | 
| 305 | 0 | 0 |  |  |  |  | if (git_array_size(drv->fn_patterns) > 0) { | 
| 306 | 0 |  |  |  |  |  | drv->type = DIFF_DRIVER_PATTERNLIST; | 
| 307 | 0 |  |  |  |  |  | found_driver = true; | 
| 308 |  |  |  |  |  |  | } | 
| 309 |  |  |  |  |  |  |  | 
| 310 | 0 |  |  |  |  |  | git_str_truncate(&name, namelen + strlen("diff..")); | 
| 311 | 0 | 0 |  |  |  |  | if ((error = git_str_PUTS(&name, "wordregex")) < 0) | 
| 312 | 0 |  |  |  |  |  | goto done; | 
| 313 |  |  |  |  |  |  |  | 
| 314 | 0 | 0 |  |  |  |  | if ((error = git_config__lookup_entry(&ce, cfg, name.ptr, false)) < 0) | 
| 315 | 0 |  |  |  |  |  | goto done; | 
| 316 | 0 | 0 |  |  |  |  | if (!ce || !ce->value) | 
|  |  | 0 |  |  |  |  |  | 
| 317 |  |  |  |  |  |  | /* no diff..wordregex, so just continue */; | 
| 318 | 0 | 0 |  |  |  |  | else if (!(error = git_regexp_compile(&drv->word_pattern, ce->value, 0))) | 
| 319 | 0 |  |  |  |  |  | found_driver = true; | 
| 320 |  |  |  |  |  |  | else { | 
| 321 |  |  |  |  |  |  | /* TODO: warn about bad regex instead of failure */ | 
| 322 | 0 |  |  |  |  |  | goto done; | 
| 323 |  |  |  |  |  |  | } | 
| 324 |  |  |  |  |  |  |  | 
| 325 |  |  |  |  |  |  | /* TODO: look up diff..algorithm to turn on minimal / patience | 
| 326 |  |  |  |  |  |  | * diff in drv->other_flags | 
| 327 |  |  |  |  |  |  | */ | 
| 328 |  |  |  |  |  |  |  | 
| 329 |  |  |  |  |  |  | /* if no driver config found at all, fall back on AUTO driver */ | 
| 330 | 0 | 0 |  |  |  |  | if (!found_driver) | 
| 331 | 0 |  |  |  |  |  | goto done; | 
| 332 |  |  |  |  |  |  |  | 
| 333 |  |  |  |  |  |  | /* store driver in registry */ | 
| 334 | 0 | 0 |  |  |  |  | if ((error = git_strmap_set(reg->drivers, drv->name, drv)) < 0) | 
| 335 | 0 |  |  |  |  |  | goto done; | 
| 336 |  |  |  |  |  |  |  | 
| 337 | 0 |  |  |  |  |  | *out = drv; | 
| 338 |  |  |  |  |  |  |  | 
| 339 |  |  |  |  |  |  | done: | 
| 340 | 0 |  |  |  |  |  | git_config_entry_free(ce); | 
| 341 | 0 |  |  |  |  |  | git_str_dispose(&name); | 
| 342 | 0 |  |  |  |  |  | git_config_free(cfg); | 
| 343 |  |  |  |  |  |  |  | 
| 344 | 0 | 0 |  |  |  |  | if (!*out) { | 
| 345 | 0 |  |  |  |  |  | int error2 = git_diff_driver_builtin(out, reg, driver_name); | 
| 346 | 0 | 0 |  |  |  |  | if (!error) | 
| 347 | 0 |  |  |  |  |  | error = error2; | 
| 348 |  |  |  |  |  |  | } | 
| 349 |  |  |  |  |  |  |  | 
| 350 | 0 | 0 |  |  |  |  | if (drv && drv != *out) | 
|  |  | 0 |  |  |  |  |  | 
| 351 | 0 |  |  |  |  |  | git_diff_driver_free(drv); | 
| 352 |  |  |  |  |  |  |  | 
| 353 | 0 |  |  |  |  |  | return error; | 
| 354 |  |  |  |  |  |  | } | 
| 355 |  |  |  |  |  |  |  | 
| 356 | 100 |  |  |  |  |  | int git_diff_driver_lookup( | 
| 357 |  |  |  |  |  |  | git_diff_driver **out, git_repository *repo, | 
| 358 |  |  |  |  |  |  | git_attr_session *attrsession, const char *path) | 
| 359 |  |  |  |  |  |  | { | 
| 360 | 100 |  |  |  |  |  | int error = 0; | 
| 361 | 100 |  |  |  |  |  | const char *values[1], *attrs[] = { "diff" }; | 
| 362 |  |  |  |  |  |  |  | 
| 363 | 100 | 50 |  |  |  |  | GIT_ASSERT_ARG(out); | 
| 364 | 100 |  |  |  |  |  | *out = NULL; | 
| 365 |  |  |  |  |  |  |  | 
| 366 | 100 | 50 |  |  |  |  | if (!repo || !path || !strlen(path)) | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 367 |  |  |  |  |  |  | /* just use the auto value */; | 
| 368 | 100 | 50 |  |  |  |  | else if ((error = git_attr_get_many_with_session(values, repo, | 
| 369 |  |  |  |  |  |  | attrsession, 0, path, 1, attrs)) < 0) | 
| 370 |  |  |  |  |  |  | /* return error below */; | 
| 371 |  |  |  |  |  |  |  | 
| 372 | 100 | 50 |  |  |  |  | else if (GIT_ATTR_IS_UNSPECIFIED(values[0])) | 
| 373 |  |  |  |  |  |  | /* just use the auto value */; | 
| 374 | 0 | 0 |  |  |  |  | else if (GIT_ATTR_IS_FALSE(values[0])) | 
| 375 | 0 |  |  |  |  |  | *out = &diff_driver_binary; | 
| 376 | 0 | 0 |  |  |  |  | else if (GIT_ATTR_IS_TRUE(values[0])) | 
| 377 | 0 |  |  |  |  |  | *out = &diff_driver_text; | 
| 378 |  |  |  |  |  |  |  | 
| 379 |  |  |  |  |  |  | /* otherwise look for driver information in config and build driver */ | 
| 380 | 0 | 0 |  |  |  |  | else if ((error = git_diff_driver_load(out, repo, values[0])) < 0) { | 
| 381 | 0 | 0 |  |  |  |  | if (error == GIT_ENOTFOUND) { | 
| 382 | 0 |  |  |  |  |  | error = 0; | 
| 383 | 0 |  |  |  |  |  | git_error_clear(); | 
| 384 |  |  |  |  |  |  | } | 
| 385 |  |  |  |  |  |  | } | 
| 386 |  |  |  |  |  |  |  | 
| 387 | 100 | 50 |  |  |  |  | if (!*out) | 
| 388 | 100 |  |  |  |  |  | *out = &diff_driver_auto; | 
| 389 |  |  |  |  |  |  |  | 
| 390 | 100 |  |  |  |  |  | return error; | 
| 391 |  |  |  |  |  |  | } | 
| 392 |  |  |  |  |  |  |  | 
| 393 | 0 |  |  |  |  |  | void git_diff_driver_free(git_diff_driver *driver) | 
| 394 |  |  |  |  |  |  | { | 
| 395 |  |  |  |  |  |  | git_diff_driver_pattern *pat; | 
| 396 |  |  |  |  |  |  |  | 
| 397 | 0 | 0 |  |  |  |  | if (!driver) | 
| 398 | 0 |  |  |  |  |  | return; | 
| 399 |  |  |  |  |  |  |  | 
| 400 | 0 | 0 |  |  |  |  | while ((pat = git_array_pop(driver->fn_patterns)) != NULL) | 
|  |  | 0 |  |  |  |  |  | 
| 401 | 0 |  |  |  |  |  | git_regexp_dispose(&pat->re); | 
| 402 | 0 |  |  |  |  |  | git_array_clear(driver->fn_patterns); | 
| 403 |  |  |  |  |  |  |  | 
| 404 | 0 |  |  |  |  |  | git_regexp_dispose(&driver->word_pattern); | 
| 405 |  |  |  |  |  |  |  | 
| 406 | 0 |  |  |  |  |  | git__free(driver); | 
| 407 |  |  |  |  |  |  | } | 
| 408 |  |  |  |  |  |  |  | 
| 409 | 100 |  |  |  |  |  | void git_diff_driver_update_options( | 
| 410 |  |  |  |  |  |  | uint32_t *option_flags, git_diff_driver *driver) | 
| 411 |  |  |  |  |  |  | { | 
| 412 | 100 | 100 |  |  |  |  | if ((*option_flags & FORCE_DIFFABLE) == 0) | 
| 413 | 96 |  |  |  |  |  | *option_flags |= driver->binary_flags; | 
| 414 |  |  |  |  |  |  |  | 
| 415 | 100 |  |  |  |  |  | *option_flags |= driver->other_flags; | 
| 416 | 100 |  |  |  |  |  | } | 
| 417 |  |  |  |  |  |  |  | 
| 418 | 60 |  |  |  |  |  | int git_diff_driver_content_is_binary( | 
| 419 |  |  |  |  |  |  | git_diff_driver *driver, const char *content, size_t content_len) | 
| 420 |  |  |  |  |  |  | { | 
| 421 | 60 |  |  |  |  |  | git_str search = GIT_STR_INIT; | 
| 422 |  |  |  |  |  |  |  | 
| 423 | 60 |  |  |  |  |  | GIT_UNUSED(driver); | 
| 424 |  |  |  |  |  |  |  | 
| 425 | 60 |  |  |  |  |  | git_str_attach_notowned(&search, content, | 
| 426 |  |  |  |  |  |  | min(content_len, GIT_FILTER_BYTES_TO_CHECK_NUL)); | 
| 427 |  |  |  |  |  |  |  | 
| 428 |  |  |  |  |  |  | /* TODO: provide encoding / binary detection callbacks that can | 
| 429 |  |  |  |  |  |  | * be UTF-8 aware, etc.  For now, instead of trying to be smart, | 
| 430 |  |  |  |  |  |  | * let's just use the simple NUL-byte detection that core git uses. | 
| 431 |  |  |  |  |  |  | */ | 
| 432 |  |  |  |  |  |  |  | 
| 433 |  |  |  |  |  |  | /* previously was: if (git_str_is_binary(&search)) */ | 
| 434 | 60 | 50 |  |  |  |  | if (git_str_contains_nul(&search)) | 
| 435 | 0 |  |  |  |  |  | return 1; | 
| 436 |  |  |  |  |  |  |  | 
| 437 | 60 |  |  |  |  |  | return 0; | 
| 438 |  |  |  |  |  |  | } | 
| 439 |  |  |  |  |  |  |  | 
| 440 | 0 |  |  |  |  |  | static int diff_context_line__simple( | 
| 441 |  |  |  |  |  |  | git_diff_driver *driver, git_str *line) | 
| 442 |  |  |  |  |  |  | { | 
| 443 | 0 |  |  |  |  |  | char firstch = line->ptr[0]; | 
| 444 | 0 |  |  |  |  |  | GIT_UNUSED(driver); | 
| 445 | 0 | 0 |  |  |  |  | return (git__isalpha(firstch) || firstch == '_' || firstch == '$'); | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 446 |  |  |  |  |  |  | } | 
| 447 |  |  |  |  |  |  |  | 
| 448 | 0 |  |  |  |  |  | static int diff_context_line__pattern_match( | 
| 449 |  |  |  |  |  |  | git_diff_driver *driver, git_str *line) | 
| 450 |  |  |  |  |  |  | { | 
| 451 | 0 |  |  |  |  |  | size_t i, maxi = git_array_size(driver->fn_patterns); | 
| 452 |  |  |  |  |  |  | git_regmatch pmatch[2]; | 
| 453 |  |  |  |  |  |  |  | 
| 454 | 0 | 0 |  |  |  |  | for (i = 0; i < maxi; ++i) { | 
| 455 | 0 | 0 |  |  |  |  | git_diff_driver_pattern *pat = git_array_get(driver->fn_patterns, i); | 
| 456 |  |  |  |  |  |  |  | 
| 457 | 0 | 0 |  |  |  |  | if (!git_regexp_search(&pat->re, line->ptr, 2, pmatch)) { | 
| 458 | 0 | 0 |  |  |  |  | if (pat->flags & REG_NEGATE) | 
| 459 | 0 |  |  |  |  |  | return false; | 
| 460 |  |  |  |  |  |  |  | 
| 461 |  |  |  |  |  |  | /* use pmatch data to trim line data */ | 
| 462 | 0 |  |  |  |  |  | i = (pmatch[1].start >= 0) ? 1 : 0; | 
| 463 | 0 |  |  |  |  |  | git_str_consume(line, git_str_cstr(line) + pmatch[i].start); | 
| 464 | 0 |  |  |  |  |  | git_str_truncate(line, pmatch[i].end - pmatch[i].start); | 
| 465 | 0 |  |  |  |  |  | git_str_rtrim(line); | 
| 466 |  |  |  |  |  |  |  | 
| 467 | 0 |  |  |  |  |  | return true; | 
| 468 |  |  |  |  |  |  | } | 
| 469 |  |  |  |  |  |  | } | 
| 470 |  |  |  |  |  |  |  | 
| 471 | 0 |  |  |  |  |  | return false; | 
| 472 |  |  |  |  |  |  | } | 
| 473 |  |  |  |  |  |  |  | 
| 474 | 0 |  |  |  |  |  | static long diff_context_find( | 
| 475 |  |  |  |  |  |  | const char *line, | 
| 476 |  |  |  |  |  |  | long line_len, | 
| 477 |  |  |  |  |  |  | char *out, | 
| 478 |  |  |  |  |  |  | long out_size, | 
| 479 |  |  |  |  |  |  | void *payload) | 
| 480 |  |  |  |  |  |  | { | 
| 481 | 0 |  |  |  |  |  | git_diff_find_context_payload *ctxt = payload; | 
| 482 |  |  |  |  |  |  |  | 
| 483 | 0 | 0 |  |  |  |  | if (git_str_set(&ctxt->line, line, (size_t)line_len) < 0) | 
| 484 | 0 |  |  |  |  |  | return -1; | 
| 485 | 0 |  |  |  |  |  | git_str_rtrim(&ctxt->line); | 
| 486 |  |  |  |  |  |  |  | 
| 487 | 0 | 0 |  |  |  |  | if (!ctxt->line.size) | 
| 488 | 0 |  |  |  |  |  | return -1; | 
| 489 |  |  |  |  |  |  |  | 
| 490 | 0 | 0 |  |  |  |  | if (!ctxt->match_line || !ctxt->match_line(ctxt->driver, &ctxt->line)) | 
|  |  | 0 |  |  |  |  |  | 
| 491 | 0 |  |  |  |  |  | return -1; | 
| 492 |  |  |  |  |  |  |  | 
| 493 | 0 | 0 |  |  |  |  | if (out_size > (long)ctxt->line.size) | 
| 494 | 0 |  |  |  |  |  | out_size = (long)ctxt->line.size; | 
| 495 | 0 |  |  |  |  |  | memcpy(out, ctxt->line.ptr, (size_t)out_size); | 
| 496 |  |  |  |  |  |  |  | 
| 497 | 0 |  |  |  |  |  | return out_size; | 
| 498 |  |  |  |  |  |  | } | 
| 499 |  |  |  |  |  |  |  | 
| 500 | 38 |  |  |  |  |  | void git_diff_find_context_init( | 
| 501 |  |  |  |  |  |  | git_diff_find_context_fn *findfn_out, | 
| 502 |  |  |  |  |  |  | git_diff_find_context_payload *payload_out, | 
| 503 |  |  |  |  |  |  | git_diff_driver *driver) | 
| 504 |  |  |  |  |  |  | { | 
| 505 | 38 | 50 |  |  |  |  | *findfn_out = driver ? diff_context_find : NULL; | 
| 506 |  |  |  |  |  |  |  | 
| 507 | 38 |  |  |  |  |  | memset(payload_out, 0, sizeof(*payload_out)); | 
| 508 | 38 | 50 |  |  |  |  | if (driver) { | 
| 509 | 38 |  |  |  |  |  | payload_out->driver = driver; | 
| 510 | 76 |  |  |  |  |  | payload_out->match_line = (driver->type == DIFF_DRIVER_PATTERNLIST) ? | 
| 511 | 38 | 50 |  |  |  |  | diff_context_line__pattern_match : diff_context_line__simple; | 
| 512 | 38 |  |  |  |  |  | git_str_init(&payload_out->line, 0); | 
| 513 |  |  |  |  |  |  | } | 
| 514 | 38 |  |  |  |  |  | } | 
| 515 |  |  |  |  |  |  |  | 
| 516 | 38 |  |  |  |  |  | void git_diff_find_context_clear(git_diff_find_context_payload *payload) | 
| 517 |  |  |  |  |  |  | { | 
| 518 | 38 | 50 |  |  |  |  | if (payload) { | 
| 519 | 38 |  |  |  |  |  | git_str_dispose(&payload->line); | 
| 520 | 38 |  |  |  |  |  | payload->driver = NULL; | 
| 521 |  |  |  |  |  |  | } | 
| 522 | 38 |  |  |  |  |  | } |