| 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.h" | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | #include "git2/version.h" | 
| 11 |  |  |  |  |  |  | #include "diff_generate.h" | 
| 12 |  |  |  |  |  |  | #include "patch.h" | 
| 13 |  |  |  |  |  |  | #include "commit.h" | 
| 14 |  |  |  |  |  |  | #include "index.h" | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | struct patch_id_args { | 
| 17 |  |  |  |  |  |  | git_hash_ctx ctx; | 
| 18 |  |  |  |  |  |  | git_oid result; | 
| 19 |  |  |  |  |  |  | int first_file; | 
| 20 |  |  |  |  |  |  | }; | 
| 21 |  |  |  |  |  |  |  | 
| 22 | 46 |  |  |  |  |  | GIT_INLINE(const char *) diff_delta__path(const git_diff_delta *delta) | 
| 23 |  |  |  |  |  |  | { | 
| 24 | 46 |  |  |  |  |  | const char *str = delta->old_file.path; | 
| 25 |  |  |  |  |  |  |  | 
| 26 | 46 | 50 |  |  |  |  | if (!str || | 
|  |  | 50 |  |  |  |  |  | 
| 27 | 46 | 100 |  |  |  |  | delta->status == GIT_DELTA_ADDED || | 
| 28 | 42 | 50 |  |  |  |  | delta->status == GIT_DELTA_RENAMED || | 
| 29 | 42 |  |  |  |  |  | delta->status == GIT_DELTA_COPIED) | 
| 30 | 4 |  |  |  |  |  | str = delta->new_file.path; | 
| 31 |  |  |  |  |  |  |  | 
| 32 | 46 |  |  |  |  |  | return str; | 
| 33 |  |  |  |  |  |  | } | 
| 34 |  |  |  |  |  |  |  | 
| 35 | 23 |  |  |  |  |  | int git_diff_delta__cmp(const void *a, const void *b) | 
| 36 |  |  |  |  |  |  | { | 
| 37 | 23 |  |  |  |  |  | const git_diff_delta *da = a, *db = b; | 
| 38 | 23 |  |  |  |  |  | int val = strcmp(diff_delta__path(da), diff_delta__path(db)); | 
| 39 | 23 | 50 |  |  |  |  | return val ? val : ((int)da->status - (int)db->status); | 
| 40 |  |  |  |  |  |  | } | 
| 41 |  |  |  |  |  |  |  | 
| 42 | 0 |  |  |  |  |  | int git_diff_delta__casecmp(const void *a, const void *b) | 
| 43 |  |  |  |  |  |  | { | 
| 44 | 0 |  |  |  |  |  | const git_diff_delta *da = a, *db = b; | 
| 45 | 0 |  |  |  |  |  | int val = strcasecmp(diff_delta__path(da), diff_delta__path(db)); | 
| 46 | 0 | 0 |  |  |  |  | return val ? val : ((int)da->status - (int)db->status); | 
| 47 |  |  |  |  |  |  | } | 
| 48 |  |  |  |  |  |  |  | 
| 49 | 826 |  |  |  |  |  | int git_diff__entry_cmp(const void *a, const void *b) | 
| 50 |  |  |  |  |  |  | { | 
| 51 | 826 |  |  |  |  |  | const git_index_entry *entry_a = a; | 
| 52 | 826 |  |  |  |  |  | const git_index_entry *entry_b = b; | 
| 53 |  |  |  |  |  |  |  | 
| 54 | 826 |  |  |  |  |  | return strcmp(entry_a->path, entry_b->path); | 
| 55 |  |  |  |  |  |  | } | 
| 56 |  |  |  |  |  |  |  | 
| 57 | 0 |  |  |  |  |  | int git_diff__entry_icmp(const void *a, const void *b) | 
| 58 |  |  |  |  |  |  | { | 
| 59 | 0 |  |  |  |  |  | const git_index_entry *entry_a = a; | 
| 60 | 0 |  |  |  |  |  | const git_index_entry *entry_b = b; | 
| 61 |  |  |  |  |  |  |  | 
| 62 | 0 |  |  |  |  |  | return strcasecmp(entry_a->path, entry_b->path); | 
| 63 |  |  |  |  |  |  | } | 
| 64 |  |  |  |  |  |  |  | 
| 65 | 664 |  |  |  |  |  | void git_diff_free(git_diff *diff) | 
| 66 |  |  |  |  |  |  | { | 
| 67 | 664 | 100 |  |  |  |  | if (!diff) | 
| 68 | 307 |  |  |  |  |  | return; | 
| 69 |  |  |  |  |  |  |  | 
| 70 | 357 | 100 |  |  |  |  | GIT_REFCOUNT_DEC(diff, diff->free_fn); | 
|  |  | 50 |  |  |  |  |  | 
| 71 |  |  |  |  |  |  | } | 
| 72 |  |  |  |  |  |  |  | 
| 73 | 49 |  |  |  |  |  | void git_diff_addref(git_diff *diff) | 
| 74 |  |  |  |  |  |  | { | 
| 75 | 49 |  |  |  |  |  | GIT_REFCOUNT_INC(diff); | 
| 76 | 49 |  |  |  |  |  | } | 
| 77 |  |  |  |  |  |  |  | 
| 78 | 59 |  |  |  |  |  | size_t git_diff_num_deltas(const git_diff *diff) | 
| 79 |  |  |  |  |  |  | { | 
| 80 | 59 | 50 |  |  |  |  | assert(diff); | 
| 81 | 59 |  |  |  |  |  | return diff->deltas.length; | 
| 82 |  |  |  |  |  |  | } | 
| 83 |  |  |  |  |  |  |  | 
| 84 | 0 |  |  |  |  |  | size_t git_diff_num_deltas_of_type(const git_diff *diff, git_delta_t type) | 
| 85 |  |  |  |  |  |  | { | 
| 86 | 0 |  |  |  |  |  | size_t i, count = 0; | 
| 87 |  |  |  |  |  |  | const git_diff_delta *delta; | 
| 88 |  |  |  |  |  |  |  | 
| 89 | 0 | 0 |  |  |  |  | assert(diff); | 
| 90 |  |  |  |  |  |  |  | 
| 91 | 0 | 0 |  |  |  |  | git_vector_foreach(&diff->deltas, i, delta) { | 
| 92 | 0 |  |  |  |  |  | count += (delta->status == type); | 
| 93 |  |  |  |  |  |  | } | 
| 94 |  |  |  |  |  |  |  | 
| 95 | 0 |  |  |  |  |  | return count; | 
| 96 |  |  |  |  |  |  | } | 
| 97 |  |  |  |  |  |  |  | 
| 98 | 61 |  |  |  |  |  | const git_diff_delta *git_diff_get_delta(const git_diff *diff, size_t idx) | 
| 99 |  |  |  |  |  |  | { | 
| 100 | 61 | 50 |  |  |  |  | assert(diff); | 
| 101 | 61 |  |  |  |  |  | return git_vector_get(&diff->deltas, idx); | 
| 102 |  |  |  |  |  |  | } | 
| 103 |  |  |  |  |  |  |  | 
| 104 | 83 |  |  |  |  |  | int git_diff_is_sorted_icase(const git_diff *diff) | 
| 105 |  |  |  |  |  |  | { | 
| 106 | 83 |  |  |  |  |  | return (diff->opts.flags & GIT_DIFF_IGNORE_CASE) != 0; | 
| 107 |  |  |  |  |  |  | } | 
| 108 |  |  |  |  |  |  |  | 
| 109 | 0 |  |  |  |  |  | int git_diff_get_perfdata(git_diff_perfdata *out, const git_diff *diff) | 
| 110 |  |  |  |  |  |  | { | 
| 111 | 0 | 0 |  |  |  |  | assert(out); | 
| 112 | 0 | 0 |  |  |  |  | GIT_ERROR_CHECK_VERSION(out, GIT_DIFF_PERFDATA_VERSION, "git_diff_perfdata"); | 
| 113 | 0 |  |  |  |  |  | out->stat_calls = diff->perf.stat_calls; | 
| 114 | 0 |  |  |  |  |  | out->oid_calculations = diff->perf.oid_calculations; | 
| 115 | 0 |  |  |  |  |  | return 0; | 
| 116 |  |  |  |  |  |  | } | 
| 117 |  |  |  |  |  |  |  | 
| 118 | 22 |  |  |  |  |  | int git_diff_foreach( | 
| 119 |  |  |  |  |  |  | git_diff *diff, | 
| 120 |  |  |  |  |  |  | git_diff_file_cb file_cb, | 
| 121 |  |  |  |  |  |  | git_diff_binary_cb binary_cb, | 
| 122 |  |  |  |  |  |  | git_diff_hunk_cb hunk_cb, | 
| 123 |  |  |  |  |  |  | git_diff_line_cb data_cb, | 
| 124 |  |  |  |  |  |  | void *payload) | 
| 125 |  |  |  |  |  |  | { | 
| 126 | 22 |  |  |  |  |  | int error = 0; | 
| 127 |  |  |  |  |  |  | git_diff_delta *delta; | 
| 128 |  |  |  |  |  |  | size_t idx; | 
| 129 |  |  |  |  |  |  |  | 
| 130 | 22 | 50 |  |  |  |  | assert(diff); | 
| 131 |  |  |  |  |  |  |  | 
| 132 | 53 | 100 |  |  |  |  | git_vector_foreach(&diff->deltas, idx, delta) { | 
| 133 |  |  |  |  |  |  | git_patch *patch; | 
| 134 |  |  |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | /* check flags against patch status */ | 
| 136 | 32 | 50 |  |  |  |  | if (git_diff_delta__should_skip(&diff->opts, delta)) | 
| 137 | 0 |  |  |  |  |  | continue; | 
| 138 |  |  |  |  |  |  |  | 
| 139 | 32 | 50 |  |  |  |  | if ((error = git_patch_from_diff(&patch, diff, idx)) != 0) | 
| 140 | 1 |  |  |  |  |  | break; | 
| 141 |  |  |  |  |  |  |  | 
| 142 | 32 |  |  |  |  |  | error = git_patch__invoke_callbacks(patch, file_cb, binary_cb, | 
| 143 |  |  |  |  |  |  | hunk_cb, data_cb, payload); | 
| 144 | 32 |  |  |  |  |  | git_patch_free(patch); | 
| 145 |  |  |  |  |  |  |  | 
| 146 | 32 | 100 |  |  |  |  | if (error) | 
| 147 | 32 |  |  |  |  |  | break; | 
| 148 |  |  |  |  |  |  | } | 
| 149 |  |  |  |  |  |  |  | 
| 150 | 22 |  |  |  |  |  | return error; | 
| 151 |  |  |  |  |  |  | } | 
| 152 |  |  |  |  |  |  |  | 
| 153 | 3 |  |  |  |  |  | static int diff_format_email_append_header_tobuf( | 
| 154 |  |  |  |  |  |  | git_buf *out, | 
| 155 |  |  |  |  |  |  | const git_oid *id, | 
| 156 |  |  |  |  |  |  | const git_signature *author, | 
| 157 |  |  |  |  |  |  | const char *summary, | 
| 158 |  |  |  |  |  |  | const char *body, | 
| 159 |  |  |  |  |  |  | size_t patch_no, | 
| 160 |  |  |  |  |  |  | size_t total_patches, | 
| 161 |  |  |  |  |  |  | bool exclude_patchno_marker) | 
| 162 |  |  |  |  |  |  | { | 
| 163 |  |  |  |  |  |  | char idstr[GIT_OID_HEXSZ + 1]; | 
| 164 |  |  |  |  |  |  | char date_str[GIT_DATE_RFC2822_SZ]; | 
| 165 | 3 |  |  |  |  |  | int error = 0; | 
| 166 |  |  |  |  |  |  |  | 
| 167 | 3 |  |  |  |  |  | git_oid_fmt(idstr, id); | 
| 168 | 3 |  |  |  |  |  | idstr[GIT_OID_HEXSZ] = '\0'; | 
| 169 |  |  |  |  |  |  |  | 
| 170 | 3 | 50 |  |  |  |  | if ((error = git__date_rfc2822_fmt(date_str, sizeof(date_str), | 
| 171 |  |  |  |  |  |  | &author->when)) < 0) | 
| 172 | 0 |  |  |  |  |  | return error; | 
| 173 |  |  |  |  |  |  |  | 
| 174 | 3 |  |  |  |  |  | error = git_buf_printf(out, | 
| 175 |  |  |  |  |  |  | "From %s Mon Sep 17 00:00:00 2001\n" \ | 
| 176 |  |  |  |  |  |  | "From: %s <%s>\n" \ | 
| 177 |  |  |  |  |  |  | "Date: %s\n" \ | 
| 178 |  |  |  |  |  |  | "Subject: ", | 
| 179 |  |  |  |  |  |  | idstr, | 
| 180 |  |  |  |  |  |  | author->name, author->email, | 
| 181 |  |  |  |  |  |  | date_str); | 
| 182 |  |  |  |  |  |  |  | 
| 183 | 3 | 50 |  |  |  |  | if (error < 0) | 
| 184 | 0 |  |  |  |  |  | return error; | 
| 185 |  |  |  |  |  |  |  | 
| 186 | 3 | 100 |  |  |  |  | if (!exclude_patchno_marker) { | 
| 187 | 2 | 100 |  |  |  |  | if (total_patches == 1) { | 
| 188 | 1 |  |  |  |  |  | error = git_buf_puts(out, "[PATCH] "); | 
| 189 |  |  |  |  |  |  | } else { | 
| 190 | 1 |  |  |  |  |  | error = git_buf_printf(out, "[PATCH %"PRIuZ"/%"PRIuZ"] ", | 
| 191 |  |  |  |  |  |  | patch_no, total_patches); | 
| 192 |  |  |  |  |  |  | } | 
| 193 |  |  |  |  |  |  |  | 
| 194 | 2 | 50 |  |  |  |  | if (error < 0) | 
| 195 | 0 |  |  |  |  |  | return error; | 
| 196 |  |  |  |  |  |  | } | 
| 197 |  |  |  |  |  |  |  | 
| 198 | 3 |  |  |  |  |  | error = git_buf_printf(out, "%s\n\n", summary); | 
| 199 |  |  |  |  |  |  |  | 
| 200 | 3 | 50 |  |  |  |  | if (body) { | 
| 201 | 0 |  |  |  |  |  | git_buf_puts(out, body); | 
| 202 |  |  |  |  |  |  |  | 
| 203 | 0 | 0 |  |  |  |  | if (out->ptr[out->size - 1] != '\n') | 
| 204 | 0 |  |  |  |  |  | git_buf_putc(out, '\n'); | 
| 205 |  |  |  |  |  |  | } | 
| 206 |  |  |  |  |  |  |  | 
| 207 | 3 |  |  |  |  |  | return error; | 
| 208 |  |  |  |  |  |  | } | 
| 209 |  |  |  |  |  |  |  | 
| 210 | 3 |  |  |  |  |  | static int diff_format_email_append_patches_tobuf( | 
| 211 |  |  |  |  |  |  | git_buf *out, | 
| 212 |  |  |  |  |  |  | git_diff *diff) | 
| 213 |  |  |  |  |  |  | { | 
| 214 |  |  |  |  |  |  | size_t i, deltas; | 
| 215 | 3 |  |  |  |  |  | int error = 0; | 
| 216 |  |  |  |  |  |  |  | 
| 217 | 3 |  |  |  |  |  | deltas = git_diff_num_deltas(diff); | 
| 218 |  |  |  |  |  |  |  | 
| 219 | 6 | 100 |  |  |  |  | for (i = 0; i < deltas; ++i) { | 
| 220 | 3 |  |  |  |  |  | git_patch *patch = NULL; | 
| 221 |  |  |  |  |  |  |  | 
| 222 | 3 | 50 |  |  |  |  | if ((error = git_patch_from_diff(&patch, diff, i)) >= 0) | 
| 223 | 3 |  |  |  |  |  | error = git_patch_to_buf(out, patch); | 
| 224 |  |  |  |  |  |  |  | 
| 225 | 3 |  |  |  |  |  | git_patch_free(patch); | 
| 226 |  |  |  |  |  |  |  | 
| 227 | 3 | 50 |  |  |  |  | if (error < 0) | 
| 228 | 0 |  |  |  |  |  | break; | 
| 229 |  |  |  |  |  |  | } | 
| 230 |  |  |  |  |  |  |  | 
| 231 | 3 |  |  |  |  |  | return error; | 
| 232 |  |  |  |  |  |  | } | 
| 233 |  |  |  |  |  |  |  | 
| 234 | 3 |  |  |  |  |  | int git_diff_format_email( | 
| 235 |  |  |  |  |  |  | git_buf *out, | 
| 236 |  |  |  |  |  |  | git_diff *diff, | 
| 237 |  |  |  |  |  |  | const git_diff_format_email_options *opts) | 
| 238 |  |  |  |  |  |  | { | 
| 239 | 3 |  |  |  |  |  | git_diff_stats *stats = NULL; | 
| 240 | 3 |  |  |  |  |  | char *summary = NULL, *loc = NULL; | 
| 241 |  |  |  |  |  |  | bool ignore_marker; | 
| 242 | 3 |  |  |  |  |  | unsigned int format_flags = 0; | 
| 243 |  |  |  |  |  |  | size_t allocsize; | 
| 244 |  |  |  |  |  |  | int error; | 
| 245 |  |  |  |  |  |  |  | 
| 246 | 3 | 50 |  |  |  |  | assert(out && diff && opts); | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 247 | 3 | 50 |  |  |  |  | assert(opts->summary && opts->id && opts->author); | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 248 |  |  |  |  |  |  |  | 
| 249 | 3 | 50 |  |  |  |  | GIT_ERROR_CHECK_VERSION(opts, | 
| 250 |  |  |  |  |  |  | GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION, | 
| 251 |  |  |  |  |  |  | "git_format_email_options"); | 
| 252 |  |  |  |  |  |  |  | 
| 253 | 3 |  |  |  |  |  | ignore_marker = (opts->flags & | 
| 254 |  |  |  |  |  |  | GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER) != 0; | 
| 255 |  |  |  |  |  |  |  | 
| 256 | 3 | 100 |  |  |  |  | if (!ignore_marker) { | 
| 257 | 2 | 50 |  |  |  |  | if (opts->patch_no > opts->total_patches) { | 
| 258 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_INVALID, | 
| 259 |  |  |  |  |  |  | "patch %"PRIuZ" out of range. max %"PRIuZ, | 
| 260 |  |  |  |  |  |  | opts->patch_no, opts->total_patches); | 
| 261 | 0 |  |  |  |  |  | return -1; | 
| 262 |  |  |  |  |  |  | } | 
| 263 |  |  |  |  |  |  |  | 
| 264 | 2 | 50 |  |  |  |  | if (opts->patch_no == 0) { | 
| 265 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_INVALID, | 
| 266 |  |  |  |  |  |  | "invalid patch no %"PRIuZ". should be >0", opts->patch_no); | 
| 267 | 0 |  |  |  |  |  | return -1; | 
| 268 |  |  |  |  |  |  | } | 
| 269 |  |  |  |  |  |  | } | 
| 270 |  |  |  |  |  |  |  | 
| 271 |  |  |  |  |  |  | /* the summary we receive may not be clean. | 
| 272 |  |  |  |  |  |  | * it could potentially contain new line characters | 
| 273 |  |  |  |  |  |  | * or not be set, sanitize, */ | 
| 274 | 3 | 50 |  |  |  |  | if ((loc = strpbrk(opts->summary, "\r\n")) != NULL) { | 
| 275 | 0 |  |  |  |  |  | size_t offset = 0; | 
| 276 |  |  |  |  |  |  |  | 
| 277 | 0 | 0 |  |  |  |  | if ((offset = (loc - opts->summary)) == 0) { | 
| 278 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_INVALID, "summary is empty"); | 
| 279 | 0 |  |  |  |  |  | error = -1; | 
| 280 | 0 |  |  |  |  |  | goto on_error; | 
| 281 |  |  |  |  |  |  | } | 
| 282 |  |  |  |  |  |  |  | 
| 283 | 0 | 0 |  |  |  |  | GIT_ERROR_CHECK_ALLOC_ADD(&allocsize, offset, 1); | 
|  |  | 0 |  |  |  |  |  | 
| 284 | 0 |  |  |  |  |  | summary = git__calloc(allocsize, sizeof(char)); | 
| 285 | 0 | 0 |  |  |  |  | GIT_ERROR_CHECK_ALLOC(summary); | 
| 286 |  |  |  |  |  |  |  | 
| 287 | 0 |  |  |  |  |  | strncpy(summary, opts->summary, offset); | 
| 288 |  |  |  |  |  |  | } | 
| 289 |  |  |  |  |  |  |  | 
| 290 | 3 | 50 |  |  |  |  | error = diff_format_email_append_header_tobuf(out, | 
| 291 |  |  |  |  |  |  | opts->id, opts->author, summary == NULL ? opts->summary : summary, | 
| 292 |  |  |  |  |  |  | opts->body, opts->patch_no, opts->total_patches, ignore_marker); | 
| 293 |  |  |  |  |  |  |  | 
| 294 | 3 | 50 |  |  |  |  | if (error < 0) | 
| 295 | 0 |  |  |  |  |  | goto on_error; | 
| 296 |  |  |  |  |  |  |  | 
| 297 | 3 |  |  |  |  |  | format_flags = GIT_DIFF_STATS_FULL | GIT_DIFF_STATS_INCLUDE_SUMMARY; | 
| 298 |  |  |  |  |  |  |  | 
| 299 | 3 | 50 |  |  |  |  | if ((error = git_buf_puts(out, "---\n")) < 0 || | 
|  |  | 50 |  |  |  |  |  | 
| 300 | 3 | 50 |  |  |  |  | (error = git_diff_get_stats(&stats, diff)) < 0 || | 
| 301 | 3 | 50 |  |  |  |  | (error = git_diff_stats_to_buf(out, stats, format_flags, 0)) < 0 || | 
| 302 | 3 | 50 |  |  |  |  | (error = git_buf_putc(out, '\n')) < 0 || | 
| 303 |  |  |  |  |  |  | (error = diff_format_email_append_patches_tobuf(out, diff)) < 0) | 
| 304 |  |  |  |  |  |  | goto on_error; | 
| 305 |  |  |  |  |  |  |  | 
| 306 | 3 |  |  |  |  |  | error = git_buf_puts(out, "--\nlibgit2 " LIBGIT2_VERSION "\n\n"); | 
| 307 |  |  |  |  |  |  |  | 
| 308 |  |  |  |  |  |  | on_error: | 
| 309 | 3 |  |  |  |  |  | git__free(summary); | 
| 310 | 3 |  |  |  |  |  | git_diff_stats_free(stats); | 
| 311 |  |  |  |  |  |  |  | 
| 312 | 3 |  |  |  |  |  | return error; | 
| 313 |  |  |  |  |  |  | } | 
| 314 |  |  |  |  |  |  |  | 
| 315 | 3 |  |  |  |  |  | int git_diff_commit_as_email( | 
| 316 |  |  |  |  |  |  | git_buf *out, | 
| 317 |  |  |  |  |  |  | git_repository *repo, | 
| 318 |  |  |  |  |  |  | git_commit *commit, | 
| 319 |  |  |  |  |  |  | size_t patch_no, | 
| 320 |  |  |  |  |  |  | size_t total_patches, | 
| 321 |  |  |  |  |  |  | uint32_t flags, | 
| 322 |  |  |  |  |  |  | const git_diff_options *diff_opts) | 
| 323 |  |  |  |  |  |  | { | 
| 324 | 3 |  |  |  |  |  | git_diff *diff = NULL; | 
| 325 | 3 |  |  |  |  |  | git_diff_format_email_options opts = | 
| 326 |  |  |  |  |  |  | GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; | 
| 327 |  |  |  |  |  |  | int error; | 
| 328 |  |  |  |  |  |  |  | 
| 329 | 3 | 50 |  |  |  |  | assert (out && repo && commit); | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 330 |  |  |  |  |  |  |  | 
| 331 | 3 |  |  |  |  |  | opts.flags = flags; | 
| 332 | 3 |  |  |  |  |  | opts.patch_no = patch_no; | 
| 333 | 3 |  |  |  |  |  | opts.total_patches = total_patches; | 
| 334 | 3 |  |  |  |  |  | opts.id = git_commit_id(commit); | 
| 335 | 3 |  |  |  |  |  | opts.summary = git_commit_summary(commit); | 
| 336 | 3 |  |  |  |  |  | opts.body = git_commit_body(commit); | 
| 337 | 3 |  |  |  |  |  | opts.author = git_commit_author(commit); | 
| 338 |  |  |  |  |  |  |  | 
| 339 | 3 | 50 |  |  |  |  | if ((error = git_diff__commit(&diff, repo, commit, diff_opts)) < 0) | 
| 340 | 0 |  |  |  |  |  | return error; | 
| 341 |  |  |  |  |  |  |  | 
| 342 | 3 |  |  |  |  |  | error = git_diff_format_email(out, diff, &opts); | 
| 343 |  |  |  |  |  |  |  | 
| 344 | 3 |  |  |  |  |  | git_diff_free(diff); | 
| 345 | 3 |  |  |  |  |  | return error; | 
| 346 |  |  |  |  |  |  | } | 
| 347 |  |  |  |  |  |  |  | 
| 348 | 1 |  |  |  |  |  | int git_diff_options_init(git_diff_options *opts, unsigned int version) | 
| 349 |  |  |  |  |  |  | { | 
| 350 | 1 | 50 |  |  |  |  | GIT_INIT_STRUCTURE_FROM_TEMPLATE( | 
| 351 |  |  |  |  |  |  | opts, version, git_diff_options, GIT_DIFF_OPTIONS_INIT); | 
| 352 | 1 |  |  |  |  |  | return 0; | 
| 353 |  |  |  |  |  |  | } | 
| 354 |  |  |  |  |  |  |  | 
| 355 |  |  |  |  |  |  | #ifndef GIT_DEPRECATE_HARD | 
| 356 | 0 |  |  |  |  |  | int git_diff_init_options(git_diff_options *opts, unsigned int version) | 
| 357 |  |  |  |  |  |  | { | 
| 358 | 0 |  |  |  |  |  | return git_diff_options_init(opts, version); | 
| 359 |  |  |  |  |  |  | } | 
| 360 |  |  |  |  |  |  | #endif | 
| 361 |  |  |  |  |  |  |  | 
| 362 | 0 |  |  |  |  |  | int git_diff_find_options_init( | 
| 363 |  |  |  |  |  |  | git_diff_find_options *opts, unsigned int version) | 
| 364 |  |  |  |  |  |  | { | 
| 365 | 0 | 0 |  |  |  |  | GIT_INIT_STRUCTURE_FROM_TEMPLATE( | 
| 366 |  |  |  |  |  |  | opts, version, git_diff_find_options, GIT_DIFF_FIND_OPTIONS_INIT); | 
| 367 | 0 |  |  |  |  |  | return 0; | 
| 368 |  |  |  |  |  |  | } | 
| 369 |  |  |  |  |  |  |  | 
| 370 |  |  |  |  |  |  | #ifndef GIT_DEPRECATE_HARD | 
| 371 | 0 |  |  |  |  |  | int git_diff_find_init_options( | 
| 372 |  |  |  |  |  |  | git_diff_find_options *opts, unsigned int version) | 
| 373 |  |  |  |  |  |  | { | 
| 374 | 0 |  |  |  |  |  | return git_diff_find_options_init(opts, version); | 
| 375 |  |  |  |  |  |  | } | 
| 376 |  |  |  |  |  |  | #endif | 
| 377 |  |  |  |  |  |  |  | 
| 378 | 0 |  |  |  |  |  | int git_diff_format_email_options_init( | 
| 379 |  |  |  |  |  |  | git_diff_format_email_options *opts, unsigned int version) | 
| 380 |  |  |  |  |  |  | { | 
| 381 | 0 | 0 |  |  |  |  | GIT_INIT_STRUCTURE_FROM_TEMPLATE( | 
| 382 |  |  |  |  |  |  | opts, version, git_diff_format_email_options, | 
| 383 |  |  |  |  |  |  | GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT); | 
| 384 | 0 |  |  |  |  |  | return 0; | 
| 385 |  |  |  |  |  |  | } | 
| 386 |  |  |  |  |  |  |  | 
| 387 |  |  |  |  |  |  | #ifndef GIT_DEPRECATE_HARD | 
| 388 | 0 |  |  |  |  |  | int git_diff_format_email_init_options( | 
| 389 |  |  |  |  |  |  | git_diff_format_email_options *opts, unsigned int version) | 
| 390 |  |  |  |  |  |  | { | 
| 391 | 0 |  |  |  |  |  | return git_diff_format_email_options_init(opts, version); | 
| 392 |  |  |  |  |  |  | } | 
| 393 |  |  |  |  |  |  | #endif | 
| 394 |  |  |  |  |  |  |  | 
| 395 | 2 |  |  |  |  |  | static int flush_hunk(git_oid *result, git_hash_ctx *ctx) | 
| 396 |  |  |  |  |  |  | { | 
| 397 |  |  |  |  |  |  | git_oid hash; | 
| 398 | 2 |  |  |  |  |  | unsigned short carry = 0; | 
| 399 |  |  |  |  |  |  | int error, i; | 
| 400 |  |  |  |  |  |  |  | 
| 401 | 2 | 50 |  |  |  |  | if ((error = git_hash_final(&hash, ctx)) < 0 || | 
|  |  | 50 |  |  |  |  |  | 
| 402 |  |  |  |  |  |  | (error = git_hash_init(ctx)) < 0) | 
| 403 | 0 |  |  |  |  |  | return error; | 
| 404 |  |  |  |  |  |  |  | 
| 405 | 42 | 100 |  |  |  |  | for (i = 0; i < GIT_OID_RAWSZ; i++) { | 
| 406 | 40 |  |  |  |  |  | carry += result->id[i] + hash.id[i]; | 
| 407 | 40 |  |  |  |  |  | result->id[i] = (unsigned char)carry; | 
| 408 | 40 |  |  |  |  |  | carry >>= 8; | 
| 409 |  |  |  |  |  |  | } | 
| 410 |  |  |  |  |  |  |  | 
| 411 | 2 |  |  |  |  |  | return 0; | 
| 412 |  |  |  |  |  |  | } | 
| 413 |  |  |  |  |  |  |  | 
| 414 | 5 |  |  |  |  |  | static void strip_spaces(git_buf *buf) | 
| 415 |  |  |  |  |  |  | { | 
| 416 | 5 |  |  |  |  |  | char *src = buf->ptr, *dst = buf->ptr; | 
| 417 |  |  |  |  |  |  | char c; | 
| 418 | 5 |  |  |  |  |  | size_t len = 0; | 
| 419 |  |  |  |  |  |  |  | 
| 420 | 139 | 100 |  |  |  |  | while ((c = *src++) != '\0') { | 
| 421 | 134 | 100 |  |  |  |  | if (!git__isspace(c)) { | 
| 422 | 110 |  |  |  |  |  | *dst++ = c; | 
| 423 | 110 |  |  |  |  |  | len++; | 
| 424 |  |  |  |  |  |  | } | 
| 425 |  |  |  |  |  |  | } | 
| 426 |  |  |  |  |  |  |  | 
| 427 | 5 |  |  |  |  |  | git_buf_truncate(buf, len); | 
| 428 | 5 |  |  |  |  |  | } | 
| 429 |  |  |  |  |  |  |  | 
| 430 | 5 |  |  |  |  |  | static int diff_patchid_print_callback_to_buf( | 
| 431 |  |  |  |  |  |  | const git_diff_delta *delta, | 
| 432 |  |  |  |  |  |  | const git_diff_hunk *hunk, | 
| 433 |  |  |  |  |  |  | const git_diff_line *line, | 
| 434 |  |  |  |  |  |  | void *payload) | 
| 435 |  |  |  |  |  |  | { | 
| 436 | 5 |  |  |  |  |  | struct patch_id_args *args = (struct patch_id_args *) payload; | 
| 437 | 5 |  |  |  |  |  | git_buf buf = GIT_BUF_INIT; | 
| 438 | 5 |  |  |  |  |  | int error = 0; | 
| 439 |  |  |  |  |  |  |  | 
| 440 | 5 | 50 |  |  |  |  | if (line->origin == GIT_DIFF_LINE_CONTEXT_EOFNL || | 
|  |  | 50 |  |  |  |  |  | 
| 441 | 5 | 50 |  |  |  |  | line->origin == GIT_DIFF_LINE_ADD_EOFNL || | 
| 442 | 5 |  |  |  |  |  | line->origin == GIT_DIFF_LINE_DEL_EOFNL) | 
| 443 |  |  |  |  |  |  | goto out; | 
| 444 |  |  |  |  |  |  |  | 
| 445 | 5 | 50 |  |  |  |  | if ((error = git_diff_print_callback__to_buf(delta, hunk, | 
| 446 |  |  |  |  |  |  | line, &buf)) < 0) | 
| 447 | 0 |  |  |  |  |  | goto out; | 
| 448 |  |  |  |  |  |  |  | 
| 449 | 5 |  |  |  |  |  | strip_spaces(&buf); | 
| 450 |  |  |  |  |  |  |  | 
| 451 | 5 | 100 |  |  |  |  | if (line->origin == GIT_DIFF_LINE_FILE_HDR && | 
|  |  | 100 |  |  |  |  |  | 
| 452 | 1 | 50 |  |  |  |  | !args->first_file && | 
| 453 | 1 |  |  |  |  |  | (error = flush_hunk(&args->result, &args->ctx) < 0)) | 
| 454 | 0 |  |  |  |  |  | goto out; | 
| 455 |  |  |  |  |  |  |  | 
| 456 | 5 | 50 |  |  |  |  | if ((error = git_hash_update(&args->ctx, buf.ptr, buf.size)) < 0) | 
| 457 | 0 |  |  |  |  |  | goto out; | 
| 458 |  |  |  |  |  |  |  | 
| 459 | 5 | 100 |  |  |  |  | if (line->origin == GIT_DIFF_LINE_FILE_HDR && args->first_file) | 
|  |  | 100 |  |  |  |  |  | 
| 460 | 1 |  |  |  |  |  | args->first_file = 0; | 
| 461 |  |  |  |  |  |  |  | 
| 462 |  |  |  |  |  |  | out: | 
| 463 | 5 |  |  |  |  |  | git_buf_dispose(&buf); | 
| 464 | 5 |  |  |  |  |  | return error; | 
| 465 |  |  |  |  |  |  | } | 
| 466 |  |  |  |  |  |  |  | 
| 467 | 0 |  |  |  |  |  | int git_diff_patchid_options_init(git_diff_patchid_options *opts, unsigned int version) | 
| 468 |  |  |  |  |  |  | { | 
| 469 | 0 | 0 |  |  |  |  | GIT_INIT_STRUCTURE_FROM_TEMPLATE( | 
| 470 |  |  |  |  |  |  | opts, version, git_diff_patchid_options, GIT_DIFF_PATCHID_OPTIONS_INIT); | 
| 471 | 0 |  |  |  |  |  | return 0; | 
| 472 |  |  |  |  |  |  | } | 
| 473 |  |  |  |  |  |  |  | 
| 474 | 1 |  |  |  |  |  | int git_diff_patchid(git_oid *out, git_diff *diff, git_diff_patchid_options *opts) | 
| 475 |  |  |  |  |  |  | { | 
| 476 |  |  |  |  |  |  | struct patch_id_args args; | 
| 477 |  |  |  |  |  |  | int error; | 
| 478 |  |  |  |  |  |  |  | 
| 479 | 1 | 50 |  |  |  |  | GIT_ERROR_CHECK_VERSION( | 
| 480 |  |  |  |  |  |  | opts, GIT_DIFF_PATCHID_OPTIONS_VERSION, "git_diff_patchid_options"); | 
| 481 |  |  |  |  |  |  |  | 
| 482 | 1 |  |  |  |  |  | memset(&args, 0, sizeof(args)); | 
| 483 | 1 |  |  |  |  |  | args.first_file = 1; | 
| 484 | 1 | 50 |  |  |  |  | if ((error = git_hash_ctx_init(&args.ctx)) < 0) | 
| 485 | 0 |  |  |  |  |  | goto out; | 
| 486 |  |  |  |  |  |  |  | 
| 487 | 1 | 50 |  |  |  |  | if ((error = git_diff_print(diff, | 
| 488 |  |  |  |  |  |  | GIT_DIFF_FORMAT_PATCH_ID, | 
| 489 |  |  |  |  |  |  | diff_patchid_print_callback_to_buf, | 
| 490 |  |  |  |  |  |  | &args)) < 0) | 
| 491 | 0 |  |  |  |  |  | goto out; | 
| 492 |  |  |  |  |  |  |  | 
| 493 | 1 | 50 |  |  |  |  | if ((error = (flush_hunk(&args.result, &args.ctx))) < 0) | 
| 494 | 0 |  |  |  |  |  | goto out; | 
| 495 |  |  |  |  |  |  |  | 
| 496 | 1 |  |  |  |  |  | git_oid_cpy(out, &args.result); | 
| 497 |  |  |  |  |  |  |  | 
| 498 |  |  |  |  |  |  | out: | 
| 499 | 1 |  |  |  |  |  | git_hash_ctx_cleanup(&args.ctx); | 
| 500 | 1 |  |  |  |  |  | return error; | 
| 501 |  |  |  |  |  |  | } |