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