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