Line Flow Count Block(s) Source
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 "common.h"
9 -
10 - #include "diff.h"
11 - #include "diff_file.h"
12 - #include "patch_generate.h"
13 - #include "futils.h"
14 - #include "zstream.h"
15 - #include "blob.h"
16 - #include "delta.h"
17 - #include "git2/sys/diff.h"
18 -
19 - typedef struct {
20 - git_diff_format_t format;
21 - git_diff_line_cb print_cb;
22 - void *payload;
23 -
24 - git_buf *buf;
25 - git_diff_line line;
26 -
27 - const char *old_prefix;
28 - const char *new_prefix;
29 - uint32_t flags;
30 - int id_strlen;
31 -
32 - int (*strcomp)(const char *, const char *);
33 - } diff_print_info;
34 -
35 234 2 static int diff_print_info_init__common(
36 - diff_print_info *pi,
37 - git_buf *out,
38 - git_repository *repo,
39 - git_diff_format_t format,
40 - git_diff_line_cb cb,
41 - void *payload)
42 - {
43 234 2 pi->format = format;
44 234 2 pi->print_cb = cb;
45 234 2 pi->payload = payload;
46 234 2 pi->buf = out;
47 -
48 234 2 if (!pi->id_strlen) {
49 208 3 if (!repo)
50 99 4 pi->id_strlen = GIT_ABBREV_DEFAULT;
51 109 5,6 else if (git_repository__configmap_lookup(&pi->id_strlen, repo, GIT_CONFIGMAP_ABBREV) < 0)
52 ##### 7 return -1;
53 - }
54 -
55 234 8 if (pi->id_strlen > GIT_OID_HEXSZ)
56 ##### 9 pi->id_strlen = GIT_OID_HEXSZ;
57 -
58 234 10 memset(&pi->line, 0, sizeof(pi->line));
59 234 10 pi->line.old_lineno = -1;
60 234 10 pi->line.new_lineno = -1;
61 234 10 pi->line.num_lines = 1;
62 -
63 234 10 return 0;
64 - }
65 -
66 50 2 static int diff_print_info_init_fromdiff(
67 - diff_print_info *pi,
68 - git_buf *out,
69 - git_diff *diff,
70 - git_diff_format_t format,
71 - git_diff_line_cb cb,
72 - void *payload)
73 - {
74 50 2-4 git_repository *repo = diff ? diff->repo : NULL;
75 -
76 50 5 memset(pi, 0, sizeof(diff_print_info));
77 -
78 50 5 if (diff) {
79 50 6 pi->flags = diff->opts.flags;
80 50 6 pi->id_strlen = diff->opts.id_abbrev;
81 50 6 pi->old_prefix = diff->opts.old_prefix;
82 50 6 pi->new_prefix = diff->opts.new_prefix;
83 -
84 50 6 pi->strcomp = diff->strcomp;
85 - }
86 -
87 50 7 return diff_print_info_init__common(pi, out, repo, format, cb, payload);
88 - }
89 -
90 184 2 static int diff_print_info_init_frompatch(
91 - diff_print_info *pi,
92 - git_buf *out,
93 - git_patch *patch,
94 - git_diff_format_t format,
95 - git_diff_line_cb cb,
96 - void *payload)
97 - {
98 184 2,3 assert(patch);
99 -
100 184 4 memset(pi, 0, sizeof(diff_print_info));
101 -
102 184 4 pi->flags = patch->diff_opts.flags;
103 184 4 pi->id_strlen = patch->diff_opts.id_abbrev;
104 184 4 pi->old_prefix = patch->diff_opts.old_prefix;
105 184 4 pi->new_prefix = patch->diff_opts.new_prefix;
106 -
107 184 4 return diff_print_info_init__common(pi, out, patch->repo, format, cb, payload);
108 - }
109 -
110 ##### 2 static char diff_pick_suffix(int mode)
111 - {
112 ##### 2 if (S_ISDIR(mode))
113 ##### 3 return '/';
114 ##### 4 else if (GIT_PERMS_IS_EXEC(mode)) /* -V536 */
115 - /* in git, modes are very regular, so we must have 0100755 mode */
116 ##### 5 return '*';
117 - else
118 ##### 6 return ' ';
119 - }
120 -
121 8 2 char git_diff_status_char(git_delta_t status)
122 - {
123 - char code;
124 -
125 8 2 switch (status) {
126 1 3 case GIT_DELTA_ADDED: code = 'A'; break;
127 1 4 case GIT_DELTA_DELETED: code = 'D'; break;
128 2 5 case GIT_DELTA_MODIFIED: code = 'M'; break;
129 3 6 case GIT_DELTA_RENAMED: code = 'R'; break;
130 ##### 7 case GIT_DELTA_COPIED: code = 'C'; break;
131 ##### 8 case GIT_DELTA_IGNORED: code = 'I'; break;
132 ##### 9 case GIT_DELTA_UNTRACKED: code = '?'; break;
133 1 10 case GIT_DELTA_TYPECHANGE: code = 'T'; break;
134 ##### 11 case GIT_DELTA_UNREADABLE: code = 'X'; break;
135 ##### 12 default: code = ' '; break;
136 - }
137 -
138 8 13 return code;
139 - }
140 -
141 ##### 2 static int diff_print_one_name_only(
142 - const git_diff_delta *delta, float progress, void *data)
143 - {
144 ##### 2 diff_print_info *pi = data;
145 ##### 2 git_buf *out = pi->buf;
146 -
147 - GIT_UNUSED(progress);
148 -
149 ##### 2,3 if ((pi->flags & GIT_DIFF_SHOW_UNMODIFIED) == 0 &&
150 ##### 3 delta->status == GIT_DELTA_UNMODIFIED)
151 ##### 4 return 0;
152 -
153 ##### 5 git_buf_clear(out);
154 ##### 6 git_buf_puts(out, delta->new_file.path);
155 ##### 7 git_buf_putc(out, '\n');
156 ##### 8,9 if (git_buf_oom(out))
157 ##### 10 return -1;
158 -
159 ##### 11 pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
160 ##### 11 pi->line.content = git_buf_cstr(out);
161 ##### 12 pi->line.content_len = git_buf_len(out);
162 -
163 ##### 13 return pi->print_cb(delta, NULL, &pi->line, pi->payload);
164 - }
165 -
166 ##### 2 static int diff_print_one_name_status(
167 - const git_diff_delta *delta, float progress, void *data)
168 - {
169 ##### 2 diff_print_info *pi = data;
170 ##### 2 git_buf *out = pi->buf;
171 ##### 2 char old_suffix, new_suffix, code = git_diff_status_char(delta->status);
172 ##### 3,6 int(*strcomp)(const char *, const char *) = pi->strcomp ?
173 ##### 3-5 pi->strcomp : git__strcmp;
174 -
175 - GIT_UNUSED(progress);
176 -
177 ##### 6,7 if ((pi->flags & GIT_DIFF_SHOW_UNMODIFIED) == 0 && code == ' ')
178 ##### 8 return 0;
179 -
180 ##### 9 old_suffix = diff_pick_suffix(delta->old_file.mode);
181 ##### 10 new_suffix = diff_pick_suffix(delta->new_file.mode);
182 -
183 ##### 11 git_buf_clear(out);
184 -
185 ##### 12,14 if (delta->old_file.path != delta->new_file.path &&
186 ##### 13 strcomp(delta->old_file.path,delta->new_file.path) != 0)
187 ##### 15 git_buf_printf(out, "%c\t%s%c %s%c\n", code,
188 - delta->old_file.path, old_suffix, delta->new_file.path, new_suffix);
189 ##### 16,17 else if (delta->old_file.mode != delta->new_file.mode &&
190 ##### 17,18 delta->old_file.mode != 0 && delta->new_file.mode != 0)
191 ##### 19 git_buf_printf(out, "%c\t%s%c %s%c\n", code,
192 - delta->old_file.path, old_suffix, delta->new_file.path, new_suffix);
193 ##### 20 else if (old_suffix != ' ')
194 ##### 21 git_buf_printf(out, "%c\t%s%c\n", code, delta->old_file.path, old_suffix);
195 - else
196 ##### 22 git_buf_printf(out, "%c\t%s\n", code, delta->old_file.path);
197 ##### 23,24 if (git_buf_oom(out))
198 ##### 25 return -1;
199 -
200 ##### 26 pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
201 ##### 26 pi->line.content = git_buf_cstr(out);
202 ##### 27 pi->line.content_len = git_buf_len(out);
203 -
204 ##### 28 return pi->print_cb(delta, NULL, &pi->line, pi->payload);
205 - }
206 -
207 ##### 2 static int diff_print_one_raw(
208 - const git_diff_delta *delta, float progress, void *data)
209 - {
210 ##### 2 diff_print_info *pi = data;
211 ##### 2 git_buf *out = pi->buf;
212 - int id_abbrev;
213 ##### 2 char code = git_diff_status_char(delta->status);
214 - char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1];
215 -
216 - GIT_UNUSED(progress);
217 -
218 ##### 3,4 if ((pi->flags & GIT_DIFF_SHOW_UNMODIFIED) == 0 && code == ' ')
219 ##### 5 return 0;
220 -
221 ##### 6 git_buf_clear(out);
222 -
223 ##### 7-9 id_abbrev = delta->old_file.mode ? delta->old_file.id_abbrev :
224 ##### 9 delta->new_file.id_abbrev;
225 -
226 ##### 10 if (pi->id_strlen > id_abbrev) {
227 ##### 11 git_error_set(GIT_ERROR_PATCH,
228 - "the patch input contains %d id characters (cannot print %d)",
229 - id_abbrev, pi->id_strlen);
230 ##### 12 return -1;
231 - }
232 -
233 ##### 13 git_oid_tostr(start_oid, pi->id_strlen + 1, &delta->old_file.id);
234 ##### 14 git_oid_tostr(end_oid, pi->id_strlen + 1, &delta->new_file.id);
235 -
236 ##### 15,15,15,15-18 git_buf_printf(
237 ##### 15 out, (pi->id_strlen <= GIT_OID_HEXSZ) ?
238 - ":%06o %06o %s... %s... %c" : ":%06o %06o %s %s %c",
239 ##### 15,15 delta->old_file.mode, delta->new_file.mode, start_oid, end_oid, code);
240 -
241 ##### 19 if (delta->similarity > 0)
242 ##### 20 git_buf_printf(out, "%03u", delta->similarity);
243 -
244 ##### 21 if (delta->old_file.path != delta->new_file.path)
245 ##### 22 git_buf_printf(
246 - out, "\t%s %s\n", delta->old_file.path, delta->new_file.path);
247 - else
248 ##### 23-26 git_buf_printf(
249 ##### 23 out, "\t%s\n", delta->old_file.path ?
250 - delta->old_file.path : delta->new_file.path);
251 -
252 ##### 27,28 if (git_buf_oom(out))
253 ##### 29 return -1;
254 -
255 ##### 30 pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
256 ##### 30 pi->line.content = git_buf_cstr(out);
257 ##### 31 pi->line.content_len = git_buf_len(out);
258 -
259 ##### 32 return pi->print_cb(delta, NULL, &pi->line, pi->payload);
260 - }
261 -
262 8 2 static int diff_print_modes(
263 - git_buf *out, const git_diff_delta *delta)
264 - {
265 8 2 git_buf_printf(out, "old mode %o\n", delta->old_file.mode);
266 8 3 git_buf_printf(out, "new mode %o\n", delta->new_file.mode);
267 -
268 8 4 return git_buf_oom(out) ? -1 : 0;
269 - }
270 -
271 235 2 static int diff_print_oid_range(
272 - git_buf *out, const git_diff_delta *delta, int id_strlen,
273 - bool print_index)
274 - {
275 - char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1];
276 -
277 235 2,3 if (delta->old_file.mode &&
278 210 3 id_strlen > delta->old_file.id_abbrev) {
279 ##### 4 git_error_set(GIT_ERROR_PATCH,
280 - "the patch input contains %d id characters (cannot print %d)",
281 ##### 4 delta->old_file.id_abbrev, id_strlen);
282 ##### 5 return -1;
283 - }
284 -
285 235 6,7 if ((delta->new_file.mode &&
286 204 7 id_strlen > delta->new_file.id_abbrev)) {
287 ##### 8 git_error_set(GIT_ERROR_PATCH,
288 - "the patch input contains %d id characters (cannot print %d)",
289 ##### 8 delta->new_file.id_abbrev, id_strlen);
290 ##### 9 return -1;
291 - }
292 -
293 235 10 git_oid_tostr(start_oid, id_strlen + 1, &delta->old_file.id);
294 235 11 git_oid_tostr(end_oid, id_strlen + 1, &delta->new_file.id);
295 -
296 235 12 if (delta->old_file.mode == delta->new_file.mode) {
297 177 13 if (print_index)
298 177 14,15 git_buf_printf(out, "index %s..%s %o\n",
299 167 14 start_oid, end_oid, delta->old_file.mode);
300 - } else {
301 58 16 if (delta->old_file.mode == 0)
302 25 17 git_buf_printf(out, "new file mode %o\n", delta->new_file.mode);
303 33 18 else if (delta->new_file.mode == 0)
304 31 19 git_buf_printf(out, "deleted file mode %o\n", delta->old_file.mode);
305 - else
306 2 20 diff_print_modes(out, delta);
307 -
308 58 21 if (print_index)
309 52 22 git_buf_printf(out, "index %s..%s\n", start_oid, end_oid);
310 - }
311 -
312 235 23 return git_buf_oom(out) ? -1 : 0;
313 - }
314 -
315 530 2 static int diff_delta_format_path(
316 - git_buf *out, const char *prefix, const char *filename)
317 - {
318 530 2,3 if (git_buf_joinpath(out, prefix, filename) < 0)
319 ##### 4 return -1;
320 -
321 530 5 return git_buf_quote(out);
322 - }
323 -
324 214 2 static int diff_delta_format_with_paths(
325 - git_buf *out,
326 - const git_diff_delta *delta,
327 - const char *template,
328 - const char *oldpath,
329 - const char *newpath)
330 - {
331 214 2,3 if (git_oid_is_zero(&delta->old_file.id))
332 21 4 oldpath = "/dev/null";
333 -
334 214 5,6 if (git_oid_is_zero(&delta->new_file.id))
335 27 7 newpath = "/dev/null";
336 -
337 214 8 return git_buf_printf(out, template, oldpath, newpath);
338 - }
339 -
340 13 2 static int diff_delta_format_similarity_header(
341 - git_buf *out,
342 - const git_diff_delta *delta)
343 - {
344 13 2 git_buf old_path = GIT_BUF_INIT, new_path = GIT_BUF_INIT;
345 - const char *type;
346 13 2 int error = 0;
347 -
348 13 2 if (delta->similarity > 100) {
349 ##### 3 git_error_set(GIT_ERROR_PATCH, "invalid similarity %d", delta->similarity);
350 ##### 4 error = -1;
351 ##### 4 goto done;
352 - }
353 -
354 13 5-8 GIT_ASSERT(delta->status == GIT_DELTA_RENAMED || delta->status == GIT_DELTA_COPIED);
355 13 9 if (delta->status == GIT_DELTA_RENAMED)
356 11 10 type = "rename";
357 - else
358 2 11 type = "copy";
359 -
360 13 12-15 if ((error = git_buf_puts(&old_path, delta->old_file.path)) < 0 ||
361 13 14,16,17 (error = git_buf_puts(&new_path, delta->new_file.path)) < 0 ||
362 13 18,19 (error = git_buf_quote(&old_path)) < 0 ||
363 - (error = git_buf_quote(&new_path)) < 0)
364 - goto done;
365 -
366 13 20,20 git_buf_printf(out,
367 - "similarity index %d%%\n"
368 - "%s from %s\n"
369 - "%s to %s\n",
370 13 20 delta->similarity,
371 - type, old_path.ptr,
372 - type, new_path.ptr);
373 -
374 13 21,22 if (git_buf_oom(out))
375 ##### 23 error = -1;
376 -
377 - done:
378 13 24 git_buf_dispose(&old_path);
379 13 25 git_buf_dispose(&new_path);
380 -
381 13 26 return error;
382 - }
383 -
384 250 2 static bool delta_is_unchanged(const git_diff_delta *delta)
385 - {
386 250 2,3,5 if (git_oid_is_zero(&delta->old_file.id) &&
387 31 4 git_oid_is_zero(&delta->new_file.id))
388 6 6 return true;
389 -
390 244 7,8 if (delta->old_file.mode == GIT_FILEMODE_COMMIT ||
391 208 8 delta->new_file.mode == GIT_FILEMODE_COMMIT)
392 37 9 return false;
393 -
394 207 10,11 if (git_oid_equal(&delta->old_file.id, &delta->new_file.id))
395 9 12 return true;
396 -
397 198 13 return false;
398 - }
399 -
400 250 2 int git_diff_delta__format_file_header(
401 - git_buf *out,
402 - const git_diff_delta *delta,
403 - const char *oldpfx,
404 - const char *newpfx,
405 - int id_strlen,
406 - bool print_index)
407 - {
408 250 2 git_buf old_path = GIT_BUF_INIT, new_path = GIT_BUF_INIT;
409 250 2 bool unchanged = delta_is_unchanged(delta);
410 250 3 int error = 0;
411 -
412 250 3 if (!oldpfx)
413 2 4 oldpfx = DIFF_OLD_PREFIX_DEFAULT;
414 250 5 if (!newpfx)
415 2 6 newpfx = DIFF_NEW_PREFIX_DEFAULT;
416 250 7 if (!id_strlen)
417 2 8 id_strlen = GIT_ABBREV_DEFAULT;
418 -
419 250 9,10 if ((error = diff_delta_format_path(
420 250 11,12 &old_path, oldpfx, delta->old_file.path)) < 0 ||
421 250 11 (error = diff_delta_format_path(
422 - &new_path, newpfx, delta->new_file.path)) < 0)
423 - goto done;
424 -
425 250 13 git_buf_clear(out);
426 -
427 250 14 git_buf_printf(out, "diff --git %s %s\n",
428 - old_path.ptr, new_path.ptr);
429 -
430 250 15,16 if (unchanged && delta->old_file.mode != delta->new_file.mode)
431 6 17 diff_print_modes(out, delta);
432 -
433 250 18,19 if (delta->status == GIT_DELTA_RENAMED ||
434 239 19,20 (delta->status == GIT_DELTA_COPIED && unchanged)) {
435 13 21,22 if ((error = diff_delta_format_similarity_header(out, delta)) < 0)
436 ##### 23 goto done;
437 - }
438 -
439 250 24 if (!unchanged) {
440 235 25,26 if ((error = diff_print_oid_range(out, delta,
441 - id_strlen, print_index)) < 0)
442 ##### 27 goto done;
443 -
444 235 28 if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0)
445 199 29 diff_delta_format_with_paths(out, delta,
446 199 29 "--- %s\n+++ %s\n", old_path.ptr, new_path.ptr);
447 - }
448 -
449 250 30,31 if (git_buf_oom(out))
450 ##### 32 error = -1;
451 -
452 - done:
453 250 33 git_buf_dispose(&old_path);
454 250 34 git_buf_dispose(&new_path);
455 -
456 250 35 return error;
457 - }
458 -
459 42 2 static int format_binary(
460 - diff_print_info *pi,
461 - git_diff_binary_t type,
462 - const char *data,
463 - size_t datalen,
464 - size_t inflatedlen)
465 - {
466 42 5 const char *typename = type == GIT_DIFF_BINARY_DELTA ?
467 42 2-4 "delta" : "literal";
468 - const char *scan, *end;
469 -
470 42 5 git_buf_printf(pi->buf, "%s %" PRIuZ "\n", typename, inflatedlen);
471 42 6 pi->line.num_lines++;
472 -
473 96 6,18 for (scan = data, end = data + datalen; scan < end; ) {
474 54 7 size_t chunk_len = end - scan;
475 54 7 if (chunk_len > 52)
476 12 8 chunk_len = 52;
477 -
478 54 9 if (chunk_len <= 26)
479 31 10 git_buf_putc(pi->buf, (char)chunk_len + 'A' - 1);
480 - else
481 23 11 git_buf_putc(pi->buf, (char)chunk_len - 26 + 'a' - 1);
482 -
483 54 12 git_buf_encode_base85(pi->buf, scan, chunk_len);
484 54 13 git_buf_putc(pi->buf, '\n');
485 -
486 54 14,15 if (git_buf_oom(pi->buf))
487 ##### 16 return -1;
488 -
489 54 17 scan += chunk_len;
490 54 17 pi->line.num_lines++;
491 - }
492 42 19 git_buf_putc(pi->buf, '\n');
493 -
494 42 20,21 if (git_buf_oom(pi->buf))
495 ##### 22 return -1;
496 -
497 42 23 return 0;
498 - }
499 -
500 15 2 static int diff_print_patch_file_binary_noshow(
501 - diff_print_info *pi, git_diff_delta *delta,
502 - const char *old_pfx, const char *new_pfx)
503 - {
504 15 2 git_buf old_path = GIT_BUF_INIT, new_path = GIT_BUF_INIT;
505 - int error;
506 -
507 15 2-5 if ((error = diff_delta_format_path(&old_path, old_pfx, delta->old_file.path)) < 0 ||
508 15 4,6,7 (error = diff_delta_format_path(&new_path, new_pfx, delta->new_file.path)) < 0 ||
509 15 6 (error = diff_delta_format_with_paths(pi->buf, delta, "Binary files %s and %s differ\n",
510 15 6 old_path.ptr, new_path.ptr)) < 0)
511 - goto done;
512 -
513 15 8 pi->line.num_lines = 1;
514 -
515 - done:
516 15 9 git_buf_dispose(&old_path);
517 15 10 git_buf_dispose(&new_path);
518 15 11 return error;
519 - }
520 -
521 37 2 static int diff_print_patch_file_binary(
522 - diff_print_info *pi, git_diff_delta *delta,
523 - const char *old_pfx, const char *new_pfx,
524 - const git_diff_binary *binary)
525 - {
526 - size_t pre_binary_size;
527 - int error;
528 -
529 37 2 if (delta->status == GIT_DELTA_UNMODIFIED)
530 1 3 return 0;
531 -
532 36 4,5 if ((pi->flags & GIT_DIFF_SHOW_BINARY) == 0 || !binary->contains_data)
533 15 6 return diff_print_patch_file_binary_noshow(
534 - pi, delta, old_pfx, new_pfx);
535 -
536 21 7 pre_binary_size = pi->buf->size;
537 21 7 git_buf_printf(pi->buf, "GIT binary patch\n");
538 21 8 pi->line.num_lines++;
539 -
540 21 8,9 if ((error = format_binary(pi, binary->new_file.type, binary->new_file.data,
541 21 10,11 binary->new_file.datalen, binary->new_file.inflatedlen)) < 0 ||
542 21 10 (error = format_binary(pi, binary->old_file.type, binary->old_file.data,
543 - binary->old_file.datalen, binary->old_file.inflatedlen)) < 0) {
544 ##### 12 if (error == GIT_EBUFS) {
545 ##### 13 git_error_clear();
546 ##### 14 git_buf_truncate(pi->buf, pre_binary_size);
547 -
548 ##### 15 return diff_print_patch_file_binary_noshow(
549 - pi, delta, old_pfx, new_pfx);
550 - }
551 - }
552 -
553 21 16 pi->line.num_lines++;
554 21 16 return error;
555 - }
556 -
557 257 2 static int diff_print_patch_file(
558 - const git_diff_delta *delta, float progress, void *data)
559 - {
560 - int error;
561 257 2 diff_print_info *pi = data;
562 257 5 const char *oldpfx =
563 257 2-4 pi->old_prefix ? pi->old_prefix : DIFF_OLD_PREFIX_DEFAULT;
564 257 8 const char *newpfx =
565 257 5-7 pi->new_prefix ? pi->new_prefix : DIFF_NEW_PREFIX_DEFAULT;
566 -
567 257 8-11 bool binary = (delta->flags & GIT_DIFF_FLAG_BINARY) ||
568 220 9 (pi->flags & GIT_DIFF_FORCE_BINARY);
569 257 12 bool show_binary = !!(pi->flags & GIT_DIFF_SHOW_BINARY);
570 257 12 int id_strlen = pi->id_strlen;
571 257 12 bool print_index = (pi->format != GIT_DIFF_FORMAT_PATCH_ID);
572 -
573 257 12,13 if (binary && show_binary)
574 24 14-17 id_strlen = delta->old_file.id_abbrev ? delta->old_file.id_abbrev :
575 5 16 delta->new_file.id_abbrev;
576 -
577 - GIT_UNUSED(progress);
578 -
579 257 18,19 if (S_ISDIR(delta->new_file.mode) ||
580 257 19,20 delta->status == GIT_DELTA_UNMODIFIED ||
581 252 20,21 delta->status == GIT_DELTA_IGNORED ||
582 250 21,22 delta->status == GIT_DELTA_UNREADABLE ||
583 250 22,23 (delta->status == GIT_DELTA_UNTRACKED &&
584 2 23 (pi->flags & GIT_DIFF_SHOW_UNTRACKED_CONTENT) == 0))
585 9 24 return 0;
586 -
587 248 25,26 if ((error = git_diff_delta__format_file_header(pi->buf, delta, oldpfx, newpfx,
588 - id_strlen, print_index)) < 0)
589 ##### 27 return error;
590 -
591 248 28 pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
592 248 28 pi->line.content = git_buf_cstr(pi->buf);
593 248 29 pi->line.content_len = git_buf_len(pi->buf);
594 -
595 248 30 return pi->print_cb(delta, NULL, &pi->line, pi->payload);
596 - }
597 -
598 37 2 static int diff_print_patch_binary(
599 - const git_diff_delta *delta,
600 - const git_diff_binary *binary,
601 - void *data)
602 - {
603 37 2 diff_print_info *pi = data;
604 37 5 const char *old_pfx =
605 37 2-4 pi->old_prefix ? pi->old_prefix : DIFF_OLD_PREFIX_DEFAULT;
606 37 8 const char *new_pfx =
607 37 5-7 pi->new_prefix ? pi->new_prefix : DIFF_NEW_PREFIX_DEFAULT;
608 - int error;
609 -
610 37 8 git_buf_clear(pi->buf);
611 -
612 37 9,10 if ((error = diff_print_patch_file_binary(
613 - pi, (git_diff_delta *)delta, old_pfx, new_pfx, binary)) < 0)
614 ##### 11 return error;
615 -
616 37 12 pi->line.origin = GIT_DIFF_LINE_BINARY;
617 37 12 pi->line.content = git_buf_cstr(pi->buf);
618 37 13 pi->line.content_len = git_buf_len(pi->buf);
619 -
620 37 14 return pi->print_cb(delta, NULL, &pi->line, pi->payload);
621 - }
622 -
623 218 2 static int diff_print_patch_hunk(
624 - const git_diff_delta *d,
625 - const git_diff_hunk *h,
626 - void *data)
627 - {
628 218 2 diff_print_info *pi = data;
629 -
630 218 2 if (S_ISDIR(d->new_file.mode))
631 ##### 3 return 0;
632 -
633 218 4 pi->line.origin = GIT_DIFF_LINE_HUNK_HDR;
634 218 4 pi->line.content = h->header;
635 218 4 pi->line.content_len = h->header_len;
636 -
637 218 4 return pi->print_cb(d, h, &pi->line, pi->payload);
638 - }
639 -
640 1505 2 static int diff_print_patch_line(
641 - const git_diff_delta *delta,
642 - const git_diff_hunk *hunk,
643 - const git_diff_line *line,
644 - void *data)
645 - {
646 1505 2 diff_print_info *pi = data;
647 -
648 1505 2 if (S_ISDIR(delta->new_file.mode))
649 ##### 3 return 0;
650 -
651 1505 4 return pi->print_cb(delta, hunk, line, pi->payload);
652 - }
653 -
654 - /* print a git_diff to an output callback */
655 50 2 int git_diff_print(
656 - git_diff *diff,
657 - git_diff_format_t format,
658 - git_diff_line_cb print_cb,
659 - void *payload)
660 - {
661 - int error;
662 50 2 git_buf buf = GIT_BUF_INIT;
663 - diff_print_info pi;
664 50 2 git_diff_file_cb print_file = NULL;
665 50 2 git_diff_binary_cb print_binary = NULL;
666 50 2 git_diff_hunk_cb print_hunk = NULL;
667 50 2 git_diff_line_cb print_line = NULL;
668 -
669 50 2 switch (format) {
670 - case GIT_DIFF_FORMAT_PATCH:
671 35 3 print_file = diff_print_patch_file;
672 35 3 print_binary = diff_print_patch_binary;
673 35 3 print_hunk = diff_print_patch_hunk;
674 35 3 print_line = diff_print_patch_line;
675 35 3 break;
676 - case GIT_DIFF_FORMAT_PATCH_ID:
677 15 4 print_file = diff_print_patch_file;
678 15 4 print_binary = diff_print_patch_binary;
679 15 4 print_line = diff_print_patch_line;
680 15 4 break;
681 - case GIT_DIFF_FORMAT_PATCH_HEADER:
682 ##### 5 print_file = diff_print_patch_file;
683 ##### 5 break;
684 - case GIT_DIFF_FORMAT_RAW:
685 ##### 6 print_file = diff_print_one_raw;
686 ##### 6 break;
687 - case GIT_DIFF_FORMAT_NAME_ONLY:
688 ##### 7 print_file = diff_print_one_name_only;
689 ##### 7 break;
690 - case GIT_DIFF_FORMAT_NAME_STATUS:
691 ##### 8 print_file = diff_print_one_name_status;
692 ##### 8 break;
693 - default:
694 ##### 9 git_error_set(GIT_ERROR_INVALID, "unknown diff output format (%d)", format);
695 ##### 10 return -1;
696 - }
697 -
698 50 11,12 if ((error = diff_print_info_init_fromdiff(&pi, &buf, diff, format, print_cb, payload)) < 0)
699 ##### 13 goto out;
700 -
701 50 14,15 if ((error = git_diff_foreach(diff, print_file, print_binary, print_hunk, print_line, &pi)) != 0) {
702 2 16 git_error_set_after_callback_function(error, "git_diff_print");
703 2 17 goto out;
704 - }
705 -
706 - out:
707 50 18 git_buf_dispose(&buf);
708 50 19 return error;
709 - }
710 -
711 1995 2 int git_diff_print_callback__to_buf(
712 - const git_diff_delta *delta,
713 - const git_diff_hunk *hunk,
714 - const git_diff_line *line,
715 - void *payload)
716 - {
717 1995 2 git_buf *output = payload;
718 - GIT_UNUSED(delta); GIT_UNUSED(hunk);
719 -
720 1995 2 if (!output) {
721 ##### 3 git_error_set(GIT_ERROR_INVALID, "buffer pointer must be provided");
722 ##### 4 return -1;
723 - }
724 -
725 1995 5,6 if (line->origin == GIT_DIFF_LINE_ADDITION ||
726 1447 6,7 line->origin == GIT_DIFF_LINE_DELETION ||
727 987 7 line->origin == GIT_DIFF_LINE_CONTEXT)
728 1490 8 git_buf_putc(output, line->origin);
729 -
730 1995 9 return git_buf_put(output, line->content, line->content_len);
731 - }
732 -
733 ##### 2 int git_diff_print_callback__to_file_handle(
734 - const git_diff_delta *delta,
735 - const git_diff_hunk *hunk,
736 - const git_diff_line *line,
737 - void *payload)
738 - {
739 ##### 2-4 FILE *fp = payload ? payload : stdout;
740 - int error;
741 -
742 - GIT_UNUSED(delta);
743 - GIT_UNUSED(hunk);
744 -
745 ##### 5,6 if (line->origin == GIT_DIFF_LINE_CONTEXT ||
746 ##### 6,7 line->origin == GIT_DIFF_LINE_ADDITION ||
747 ##### 7 line->origin == GIT_DIFF_LINE_DELETION) {
748 ##### 8,10,11 while ((error = fputc(line->origin, fp)) == EINTR)
749 ##### 9 continue;
750 ##### 12 if (error) {
751 ##### 13 git_error_set(GIT_ERROR_OS, "could not write status");
752 ##### 14 return -1;
753 - }
754 - }
755 -
756 ##### 15,16 if (fwrite(line->content, line->content_len, 1, fp) != 1) {
757 ##### 17 git_error_set(GIT_ERROR_OS, "could not write line");
758 ##### 18 return -1;
759 - }
760 -
761 ##### 19 return 0;
762 - }
763 -
764 - /* print a git_diff to a git_buf */
765 21 2 int git_diff_to_buf(git_buf *out, git_diff *diff, git_diff_format_t format)
766 - {
767 21 2-4 assert(out && diff);
768 21 5 git_buf_sanitize(out);
769 21 6 return git_diff_print(diff, format, git_diff_print_callback__to_buf, out);
770 - }
771 -
772 - /* print a git_patch to an output callback */
773 184 2 int git_patch_print(
774 - git_patch *patch,
775 - git_diff_line_cb print_cb,
776 - void *payload)
777 - {
778 184 2 git_buf temp = GIT_BUF_INIT;
779 - diff_print_info pi;
780 - int error;
781 -
782 184 2-4 assert(patch && print_cb);
783 -
784 184 5,6 if ((error = diff_print_info_init_frompatch(&pi, &temp, patch,
785 - GIT_DIFF_FORMAT_PATCH, print_cb, payload)) < 0)
786 ##### 7 goto out;
787 -
788 184 8,9 if ((error = git_patch__invoke_callbacks(patch, diff_print_patch_file, diff_print_patch_binary,
789 - diff_print_patch_hunk, diff_print_patch_line, &pi)) < 0) {
790 ##### 10 git_error_set_after_callback_function(error, "git_patch_print");
791 ##### 11 goto out;
792 - }
793 -
794 - out:
795 184 12 git_buf_dispose(&temp);
796 184 13 return error;
797 - }
798 -
799 - /* print a git_patch to a git_buf */
800 184 2 int git_patch_to_buf(git_buf *out, git_patch *patch)
801 - {
802 184 2-4 assert(out && patch);
803 184 5 git_buf_sanitize(out);
804 184 6 return git_patch_print(patch, git_diff_print_callback__to_buf, out);
805 - }