1--- test019.left.txt 2+++ test019.right.txt 3@@ -40,8 +40,23 @@ 4 #include "got_lib_object.h" 5 6 static const struct got_error * 7-diff_blobs(struct got_diffreg_result **resultp, 8-struct got_blob_object *blob1, struct got_blob_object *blob2, 9+add_line_offset(off_t **line_offsets, size_t *nlines, off_t off) 10+{ 11+ off_t *p; 12+ 13+ p = reallocarray(*line_offsets, *nlines + 1, sizeof(off_t)); 14+ if (p == NULL) 15+ return got_error_from_errno("reallocarray"); 16+ *line_offsets = p; 17+ (*line_offsets)[*nlines] = off; 18+ (*nlines)++; 19+ return NULL; 20+} 21+ 22+static const struct got_error * 23+diff_blobs(off_t **line_offsets, size_t *nlines, 24+ struct got_diffreg_result **resultp, struct got_blob_object *blob1, 25+ struct got_blob_object *blob2, 26 const char *label1, const char *label2, mode_t mode1, mode_t mode2, 27 int diff_context, int ignore_whitespace, FILE *outfile) 28 { 29@@ -52,7 +67,12 @@ 30 char *idstr1 = NULL, *idstr2 = NULL; 31 size_t size1, size2; 32 struct got_diffreg_result *result; 33+ off_t outoff = 0; 34+ int n; 35 36+ if (line_offsets && *line_offsets && *nlines > 0) 37+ outoff = (*line_offsets)[*nlines - 1]; 38+ 39 if (resultp) 40 *resultp = NULL; 41 42@@ -116,10 +136,32 @@ 43 goto done; 44 } 45 } 46- fprintf(outfile, "blob - %s%s\n", idstr1, 47+ n = fprintf(outfile, "blob - %s%s\n", idstr1, 48 modestr1 ? modestr1 : ""); 49- fprintf(outfile, "blob + %s%s\n", idstr2, 50+ if (n < 0) { 51+ err = got_error_from_errno("fprintf"); 52+ goto done; 53+ } 54+ outoff += n; 55+ if (line_offsets) { 56+ err = add_line_offset(line_offsets, nlines, outoff); 57+ if (err) 58+ goto done; 59+ } 60+ 61+ n = fprintf(outfile, "blob + %s%s\n", idstr2, 62 modestr2 ? modestr2 : ""); 63+ if (n < 0) { 64+ err = got_error_from_errno("fprintf"); 65+ goto done; 66+ } 67+ outoff += n; 68+ if (line_offsets) { 69+ err = add_line_offset(line_offsets, nlines, outoff); 70+ if (err) 71+ goto done; 72+ } 73+ 74 free(modestr1); 75 free(modestr2); 76 } 77@@ -129,7 +171,7 @@ 78 goto done; 79 80 if (outfile) { 81- err = got_diffreg_output(NULL, NULL, result, f1, f2, 82+ err = got_diffreg_output(line_offsets, nlines, result, f1, f2, 83 label1 ? label1 : idstr1, 84 label2 ? label2 : idstr2, 85 GOT_DIFF_OUTPUT_UNIDIFF, diff_context, outfile); 86@@ -158,21 +200,21 @@ 87 struct got_object_id *id2, const char *label1, const char *label2, 88 mode_t mode1, mode_t mode2, struct got_repository *repo) 89 { 90- const struct got_error *err; 91 struct got_diff_blob_output_unidiff_arg *a = arg; 92 93- err = diff_blobs(NULL, blob1, blob2, label1, label2, mode1, mode2, 94- a->diff_context, a->ignore_whitespace, a->outfile); 95- return err; 96+ return diff_blobs(&a->line_offsets, &a->nlines, NULL, 97+ blob1, blob2, label1, label2, mode1, mode2, a->diff_context, 98+ a->ignore_whitespace, a->outfile); 99 } 100 101 const struct got_error * 102-got_diff_blob(struct got_blob_object *blob1, struct got_blob_object *blob2, 103+got_diff_blob(off_t **line_offsets, size_t *nlines, 104+ struct got_blob_object *blob1, struct got_blob_object *blob2, 105 const char *label1, const char *label2, int diff_context, 106 int ignore_whitespace, FILE *outfile) 107 { 108- return diff_blobs(NULL, blob1, blob2, label1, label2, 0, 0, diff_context, 109- ignore_whitespace, outfile); 110+ return diff_blobs(line_offsets, nlines, NULL, blob1, blob2, 111+ label1, label2, 0, 0, diff_context, ignore_whitespace, outfile); 112 } 113 114 static const struct got_error * 115@@ -259,7 +301,8 @@ 116 { 117 const struct got_error *err = NULL; 118 119- err = diff_blobs(result, blob1, blob2, NULL, NULL, 0, 0, 3, 0, NULL); 120+ err = diff_blobs(NULL, NULL, result, blob1, blob2, 121+ NULL, NULL, 0, 0, 3, 0, NULL); 122 if (err) { 123 got_diffreg_result_free(*result); 124 *result = NULL; 125@@ -702,7 +745,8 @@ 126 } 127 128 const struct got_error * 129-got_diff_objects_as_blobs(struct got_object_id *id1, struct got_object_id *id2, 130+got_diff_objects_as_blobs(off_t **line_offsets, size_t *nlines, 131+ struct got_object_id *id1, struct got_object_id *id2, 132 const char *label1, const char *label2, int diff_context, 133 int ignore_whitespace, struct got_repository *repo, FILE *outfile) 134 { 135@@ -722,8 +766,8 @@ 136 if (err) 137 goto done; 138 } 139- err = got_diff_blob(blob1, blob2, label1, label2, diff_context, 140- ignore_whitespace, outfile); 141+ err = got_diff_blob(line_offsets, nlines, blob1, blob2, 142+ label1, label2, diff_context, ignore_whitespace, outfile); 143 done: 144 if (blob1) 145 got_object_blob_close(blob1); 146@@ -733,13 +777,15 @@ 147 } 148 149 const struct got_error * 150-got_diff_objects_as_trees(struct got_object_id *id1, struct got_object_id *id2, 151+got_diff_objects_as_trees(off_t **line_offsets, size_t *nlines, 152+ struct got_object_id *id1, struct got_object_id *id2, 153 char *label1, char *label2, int diff_context, int ignore_whitespace, 154 struct got_repository *repo, FILE *outfile) 155 { 156 const struct got_error *err; 157 struct got_tree_object *tree1 = NULL, *tree2 = NULL; 158 struct got_diff_blob_output_unidiff_arg arg; 159+ int want_lineoffsets = (line_offsets != NULL && *line_offsets != NULL); 160 161 if (id1 == NULL && id2 == NULL) 162 return got_error(GOT_ERR_NO_OBJ); 163@@ -757,8 +803,20 @@ 164 arg.diff_context = diff_context; 165 arg.ignore_whitespace = ignore_whitespace; 166 arg.outfile = outfile; 167+ if (want_lineoffsets) { 168+ arg.line_offsets = *line_offsets; 169+ arg.nlines = *nlines; 170+ } else { 171+ arg.line_offsets = NULL; 172+ arg.nlines = 0; 173+ } 174 err = got_diff_tree(tree1, tree2, label1, label2, repo, 175 got_diff_blob_output_unidiff, &arg, 1); 176+ 177+ if (want_lineoffsets) { 178+ *line_offsets = arg.line_offsets; /* was likely re-allocated */ 179+ *nlines = arg.nlines; 180+ } 181 done: 182 if (tree1) 183 got_object_tree_close(tree1); 184@@ -768,8 +826,9 @@ 185 } 186 187 const struct got_error * 188-got_diff_objects_as_commits(struct got_object_id *id1, 189- struct got_object_id *id2, int diff_context, int ignore_whitespace, 190+got_diff_objects_as_commits(off_t **line_offsets, size_t *nlines, 191+ struct got_object_id *id1, struct got_object_id *id2, 192+ int diff_context, int ignore_whitespace, 193 struct got_repository *repo, FILE *outfile) 194 { 195 const struct got_error *err; 196@@ -788,7 +847,7 @@ 197 if (err) 198 goto done; 199 200- err = got_diff_objects_as_trees( 201+ err = got_diff_objects_as_trees(line_offsets, nlines, 202 commit1 ? got_object_commit_get_tree_id(commit1) : NULL, 203 got_object_commit_get_tree_id(commit2), "", "", diff_context, 204 ignore_whitespace, repo, outfile); 205