File: | got/../lib/diff_output.c |
Warning: | line 270, column 10 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Common parts for printing diff output */ | |||
2 | /* | |||
3 | * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de> | |||
4 | * | |||
5 | * Permission to use, copy, modify, and distribute this software for any | |||
6 | * purpose with or without fee is hereby granted, provided that the above | |||
7 | * copyright notice and this permission notice appear in all copies. | |||
8 | * | |||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
16 | */ | |||
17 | ||||
18 | #include <ctype.h> | |||
19 | #include <errno(*__errno()).h> | |||
20 | #include <stdbool.h> | |||
21 | #include <stdint.h> | |||
22 | #include <stdio.h> | |||
23 | #include <stdlib.h> | |||
24 | #include <string.h> | |||
25 | #include <unistd.h> | |||
26 | ||||
27 | #include <arraylist.h> | |||
28 | #include <diff_main.h> | |||
29 | #include <diff_output.h> | |||
30 | ||||
31 | #include "diff_internal.h" | |||
32 | ||||
33 | static int | |||
34 | get_atom_byte(int *ch, struct diff_atom *atom, off_t off) | |||
35 | { | |||
36 | off_t cur; | |||
37 | ||||
38 | if (atom->at != NULL((void *)0)) { | |||
39 | *ch = atom->at[off]; | |||
40 | return 0; | |||
41 | } | |||
42 | ||||
43 | cur = ftello(atom->root->f); | |||
44 | if (cur == -1) | |||
45 | return errno(*__errno()); | |||
46 | ||||
47 | if (cur != atom->pos + off && | |||
48 | fseeko(atom->root->f, atom->pos + off, SEEK_SET0) == -1) | |||
49 | return errno(*__errno()); | |||
50 | ||||
51 | *ch = fgetc(atom->root->f); | |||
52 | if (*ch == EOF(-1) && ferror(atom->root->f)(!__isthreaded ? (((atom->root->f)->_flags & 0x0040 ) != 0) : (ferror)(atom->root->f))) | |||
53 | return errno(*__errno()); | |||
54 | ||||
55 | return 0; | |||
56 | } | |||
57 | ||||
58 | int | |||
59 | diff_output_lines(struct diff_output_info *outinfo, FILE *dest, | |||
60 | const char *prefix, struct diff_atom *start_atom, | |||
61 | unsigned int count) | |||
62 | { | |||
63 | struct diff_atom *atom; | |||
64 | off_t outoff = 0, *offp; | |||
65 | int rc; | |||
66 | ||||
67 | if (outinfo && outinfo->line_offsets.len > 0) { | |||
68 | unsigned int idx = outinfo->line_offsets.len - 1; | |||
69 | outoff = outinfo->line_offsets.head[idx]; | |||
70 | } | |||
71 | ||||
72 | foreach_diff_atom(atom, start_atom, count)for ((atom) = (start_atom); (atom) && ((atom) >= ( start_atom)) && ((atom) - (start_atom) < (count)); (atom)++) { | |||
73 | off_t outlen = 0; | |||
74 | int i, ch; | |||
75 | unsigned int len = atom->len; | |||
76 | rc = fprintf(dest, "%s", prefix); | |||
77 | if (rc < 0) | |||
78 | return errno(*__errno()); | |||
79 | outlen += rc; | |||
80 | if (len) { | |||
81 | rc = get_atom_byte(&ch, atom, len - 1); | |||
82 | if (rc) | |||
83 | return rc; | |||
84 | if (ch == '\n') | |||
85 | len--; | |||
86 | if (len) { | |||
87 | rc = get_atom_byte(&ch, atom, len - 1); | |||
88 | if (rc) | |||
89 | return rc; | |||
90 | if (ch == '\r') | |||
91 | len--; | |||
92 | } | |||
93 | } | |||
94 | ||||
95 | for (i = 0; i < len; i++) { | |||
96 | rc = get_atom_byte(&ch, atom, i); | |||
97 | if (rc) | |||
98 | return rc; | |||
99 | rc = fprintf(dest, "%c", (unsigned char)ch); | |||
100 | if (rc < 0) | |||
101 | return errno(*__errno()); | |||
102 | outlen += rc; | |||
103 | } | |||
104 | rc = fprintf(dest, "\n"); | |||
105 | if (rc < 0) | |||
106 | return errno(*__errno()); | |||
107 | outlen += rc; | |||
108 | if (outinfo) { | |||
109 | ARRAYLIST_ADD(offp, outinfo->line_offsets)do { if ((outinfo->line_offsets).len && !(outinfo-> line_offsets).allocated) { offp = ((void *)0); break; } if (( outinfo->line_offsets).head == ((void *)0) || (outinfo-> line_offsets).allocated < (outinfo->line_offsets).len + 1) { (outinfo->line_offsets).p = recallocarray((outinfo-> line_offsets).head, (outinfo->line_offsets).len, (outinfo-> line_offsets).allocated + ((outinfo->line_offsets).alloc_blocksize ? : 8), sizeof(*(outinfo->line_offsets).head)); if ((outinfo ->line_offsets).p == ((void *)0)) { offp = ((void *)0); break ; } (outinfo->line_offsets).allocated += (outinfo->line_offsets ).alloc_blocksize ? : 8; (outinfo->line_offsets).head = (outinfo ->line_offsets).p; (outinfo->line_offsets).p = ((void * )0); }; if ((outinfo->line_offsets).head == ((void *)0) || (outinfo->line_offsets).allocated < (outinfo->line_offsets ).len + 1) { offp = ((void *)0); break; } (offp) = &(outinfo ->line_offsets).head[(outinfo->line_offsets).len]; (outinfo ->line_offsets).len++; } while (0); | |||
110 | if (offp == NULL((void *)0)) | |||
111 | return ENOMEM12; | |||
112 | outoff += outlen; | |||
113 | *offp = outoff; | |||
114 | } | |||
115 | } | |||
116 | ||||
117 | return DIFF_RC_OK0; | |||
118 | } | |||
119 | ||||
120 | int | |||
121 | diff_output_chunk_left_version(struct diff_output_info **output_info, | |||
122 | FILE *dest, | |||
123 | const struct diff_input_info *info, | |||
124 | const struct diff_result *result, | |||
125 | const struct diff_chunk_context *cc) | |||
126 | { | |||
127 | int rc, c_idx; | |||
128 | struct diff_output_info *outinfo = NULL((void *)0); | |||
129 | ||||
130 | if (diff_range_empty(&cc->left)) | |||
131 | return DIFF_RC_OK0; | |||
132 | ||||
133 | if (output_info) { | |||
134 | *output_info = diff_output_info_alloc(); | |||
135 | if (*output_info == NULL((void *)0)) | |||
136 | return ENOMEM12; | |||
137 | outinfo = *output_info; | |||
138 | } | |||
139 | ||||
140 | /* Write out all chunks on the left side. */ | |||
141 | for (c_idx = cc->chunk.start; c_idx < cc->chunk.end; c_idx++) { | |||
142 | const struct diff_chunk *c = &result->chunks.head[c_idx]; | |||
143 | ||||
144 | if (c->left_count) { | |||
145 | rc = diff_output_lines(outinfo, dest, "", | |||
146 | c->left_start, c->left_count); | |||
147 | if (rc) | |||
148 | return rc; | |||
149 | } | |||
150 | } | |||
151 | ||||
152 | return DIFF_RC_OK0; | |||
153 | } | |||
154 | ||||
155 | int | |||
156 | diff_output_chunk_right_version(struct diff_output_info **output_info, | |||
157 | FILE *dest, | |||
158 | const struct diff_input_info *info, | |||
159 | const struct diff_result *result, | |||
160 | const struct diff_chunk_context *cc) | |||
161 | { | |||
162 | int rc, c_idx; | |||
163 | struct diff_output_info *outinfo = NULL((void *)0); | |||
164 | ||||
165 | if (diff_range_empty(&cc->right)) | |||
166 | return DIFF_RC_OK0; | |||
167 | ||||
168 | if (output_info) { | |||
169 | *output_info = diff_output_info_alloc(); | |||
170 | if (*output_info == NULL((void *)0)) | |||
171 | return ENOMEM12; | |||
172 | outinfo = *output_info; | |||
173 | } | |||
174 | ||||
175 | /* Write out all chunks on the right side. */ | |||
176 | for (c_idx = cc->chunk.start; c_idx < cc->chunk.end; c_idx++) { | |||
177 | const struct diff_chunk *c = &result->chunks.head[c_idx]; | |||
178 | ||||
179 | if (c->right_count) { | |||
180 | rc = diff_output_lines(outinfo, dest, "", c->right_start, | |||
181 | c->right_count); | |||
182 | if (rc) | |||
183 | return rc; | |||
184 | } | |||
185 | } | |||
186 | ||||
187 | return DIFF_RC_OK0; | |||
188 | } | |||
189 | ||||
190 | int | |||
191 | diff_output_trailing_newline_msg(struct diff_output_info *outinfo, FILE *dest, | |||
192 | const struct diff_chunk *c) | |||
193 | { | |||
194 | enum diff_chunk_type chunk_type = diff_chunk_type(c); | |||
195 | struct diff_atom *atom, *start_atom; | |||
196 | unsigned int atom_count; | |||
197 | int rc, ch; | |||
198 | off_t outoff = 0, *offp; | |||
199 | ||||
200 | if (chunk_type == CHUNK_MINUS || chunk_type == CHUNK_SAME) { | |||
201 | start_atom = c->left_start; | |||
202 | atom_count = c->left_count; | |||
203 | } else if (chunk_type == CHUNK_PLUS) { | |||
204 | start_atom = c->right_start; | |||
205 | atom_count = c->right_count; | |||
206 | } else | |||
207 | return EINVAL22; | |||
208 | ||||
209 | /* Locate the last atom. */ | |||
210 | if (atom_count == 0) | |||
211 | return EINVAL22; | |||
212 | atom = &start_atom[atom_count - 1]; | |||
213 | ||||
214 | rc = get_atom_byte(&ch, atom, atom->len - 1); | |||
215 | if (rc != DIFF_RC_OK0) | |||
216 | return rc; | |||
217 | ||||
218 | if (ch != '\n') { | |||
219 | if (outinfo && outinfo->line_offsets.len > 0) { | |||
220 | unsigned int idx = outinfo->line_offsets.len - 1; | |||
221 | outoff = outinfo->line_offsets.head[idx]; | |||
222 | } | |||
223 | rc = fprintf(dest, "\\ No newline at end of file\n"); | |||
224 | if (rc < 0) | |||
225 | return errno(*__errno()); | |||
226 | if (outinfo) { | |||
227 | ARRAYLIST_ADD(offp, outinfo->line_offsets)do { if ((outinfo->line_offsets).len && !(outinfo-> line_offsets).allocated) { offp = ((void *)0); break; } if (( outinfo->line_offsets).head == ((void *)0) || (outinfo-> line_offsets).allocated < (outinfo->line_offsets).len + 1) { (outinfo->line_offsets).p = recallocarray((outinfo-> line_offsets).head, (outinfo->line_offsets).len, (outinfo-> line_offsets).allocated + ((outinfo->line_offsets).alloc_blocksize ? : 8), sizeof(*(outinfo->line_offsets).head)); if ((outinfo ->line_offsets).p == ((void *)0)) { offp = ((void *)0); break ; } (outinfo->line_offsets).allocated += (outinfo->line_offsets ).alloc_blocksize ? : 8; (outinfo->line_offsets).head = (outinfo ->line_offsets).p; (outinfo->line_offsets).p = ((void * )0); }; if ((outinfo->line_offsets).head == ((void *)0) || (outinfo->line_offsets).allocated < (outinfo->line_offsets ).len + 1) { offp = ((void *)0); break; } (offp) = &(outinfo ->line_offsets).head[(outinfo->line_offsets).len]; (outinfo ->line_offsets).len++; } while (0); | |||
228 | if (offp == NULL((void *)0)) | |||
229 | return ENOMEM12; | |||
230 | outoff += rc; | |||
231 | *offp = outoff; | |||
232 | } | |||
233 | } | |||
234 | ||||
235 | return DIFF_RC_OK0; | |||
236 | } | |||
237 | ||||
238 | static bool_Bool | |||
239 | is_function_prototype(unsigned char ch) | |||
240 | { | |||
241 | return (isalpha(ch) || ch == '_' || ch == '$'); | |||
242 | } | |||
243 | ||||
244 | #define begins_with(s, pre)(strncmp(s, pre, sizeof(pre)-1) == 0) (strncmp(s, pre, sizeof(pre)-1) == 0) | |||
245 | ||||
246 | int | |||
247 | diff_output_match_function_prototype(char *prototype, size_t prototype_size, | |||
248 | int *last_prototype_idx, const struct diff_result *result, | |||
249 | const struct diff_chunk_context *cc) | |||
250 | { | |||
251 | struct diff_atom *start_atom, *atom; | |||
252 | const struct diff_data *data; | |||
253 | unsigned char buf[DIFF_FUNCTION_CONTEXT_SIZE55]; | |||
254 | char *state = NULL((void *)0); | |||
255 | int rc, i, ch; | |||
| ||||
256 | ||||
257 | if (result->left->atoms.len > 0 && cc->left.start > 0) { | |||
258 | data = result->left; | |||
259 | start_atom = &data->atoms.head[cc->left.start - 1]; | |||
260 | } else | |||
261 | return DIFF_RC_OK0; | |||
262 | ||||
263 | diff_data_foreach_atom_backwards_from(start_atom, atom, data)for ((atom) = (start_atom); (atom) && ((atom) >= ( data)->atoms.head) && ((atom) - (data)->atoms.head >= 0); (atom)--) { | |||
264 | int atom_idx = diff_atom_root_idx(data, atom)((atom) && ((atom) >= (data)->root->atoms.head ) ? (unsigned int)((atom) - ((data)->root->atoms.head)) : (data)->root->atoms.len); | |||
265 | if (atom_idx < *last_prototype_idx) | |||
266 | break; | |||
267 | rc = get_atom_byte(&ch, atom, 0); | |||
268 | if (rc) | |||
269 | return rc; | |||
270 | buf[0] = (unsigned char)ch; | |||
| ||||
271 | if (!is_function_prototype(buf[0])) | |||
272 | continue; | |||
273 | for (i = 1; i < atom->len && i < sizeof(buf) - 1; i++) { | |||
274 | rc = get_atom_byte(&ch, atom, i); | |||
275 | if (rc) | |||
276 | return rc; | |||
277 | if (ch == '\n') | |||
278 | break; | |||
279 | buf[i] = (unsigned char)ch; | |||
280 | } | |||
281 | buf[i] = '\0'; | |||
282 | if (begins_with(buf, "private:")(strncmp(buf, "private:", sizeof("private:")-1) == 0)) { | |||
283 | if (!state) | |||
284 | state = " (private)"; | |||
285 | } else if (begins_with(buf, "protected:")(strncmp(buf, "protected:", sizeof("protected:")-1) == 0)) { | |||
286 | if (!state) | |||
287 | state = " (protected)"; | |||
288 | } else if (begins_with(buf, "public:")(strncmp(buf, "public:", sizeof("public:")-1) == 0)) { | |||
289 | if (!state) | |||
290 | state = " (public)"; | |||
291 | } else { | |||
292 | if (state) /* don't care about truncation */ | |||
293 | strlcat(buf, state, sizeof(buf)); | |||
294 | strlcpy(prototype, buf, prototype_size); | |||
295 | break; | |||
296 | } | |||
297 | } | |||
298 | ||||
299 | *last_prototype_idx = diff_atom_root_idx(data, start_atom)((start_atom) && ((start_atom) >= (data)->root-> atoms.head) ? (unsigned int)((start_atom) - ((data)->root-> atoms.head)) : (data)->root->atoms.len); | |||
300 | return DIFF_RC_OK0; | |||
301 | } | |||
302 | ||||
303 | struct diff_output_info * | |||
304 | diff_output_info_alloc(void) | |||
305 | { | |||
306 | struct diff_output_info *output_info; | |||
307 | off_t *offp; | |||
308 | ||||
309 | output_info = malloc(sizeof(*output_info)); | |||
310 | if (output_info != NULL((void *)0)) { | |||
311 | ARRAYLIST_INIT(output_info->line_offsets, 128)do { (output_info->line_offsets).head = ((void *)0); (output_info ->line_offsets).len = 0; (output_info->line_offsets).allocated = 0; (output_info->line_offsets).alloc_blocksize = 128; } while(0); | |||
312 | ARRAYLIST_ADD(offp, output_info->line_offsets)do { if ((output_info->line_offsets).len && !(output_info ->line_offsets).allocated) { offp = ((void *)0); break; } if ((output_info->line_offsets).head == ((void *)0) || (output_info ->line_offsets).allocated < (output_info->line_offsets ).len + 1) { (output_info->line_offsets).p = recallocarray ((output_info->line_offsets).head, (output_info->line_offsets ).len, (output_info->line_offsets).allocated + ((output_info ->line_offsets).alloc_blocksize ? : 8), sizeof(*(output_info ->line_offsets).head)); if ((output_info->line_offsets) .p == ((void *)0)) { offp = ((void *)0); break; } (output_info ->line_offsets).allocated += (output_info->line_offsets ).alloc_blocksize ? : 8; (output_info->line_offsets).head = (output_info->line_offsets).p; (output_info->line_offsets ).p = ((void *)0); }; if ((output_info->line_offsets).head == ((void *)0) || (output_info->line_offsets).allocated < (output_info->line_offsets).len + 1) { offp = ((void *)0) ; break; } (offp) = &(output_info->line_offsets).head[ (output_info->line_offsets).len]; (output_info->line_offsets ).len++; } while (0); | |||
313 | if (offp == NULL((void *)0)) { | |||
314 | diff_output_info_free(output_info); | |||
315 | return NULL((void *)0); | |||
316 | } | |||
317 | *offp = 0; | |||
318 | } | |||
319 | return output_info; | |||
320 | } | |||
321 | ||||
322 | void | |||
323 | diff_output_info_free(struct diff_output_info *output_info) | |||
324 | { | |||
325 | ARRAYLIST_FREE(output_info->line_offsets)do { if ((output_info->line_offsets).head && (output_info ->line_offsets).allocated) free((output_info->line_offsets ).head); do { (output_info->line_offsets).head = ((void *) 0); (output_info->line_offsets).len = 0; (output_info-> line_offsets).allocated = 0; (output_info->line_offsets).alloc_blocksize = (output_info->line_offsets).alloc_blocksize; } while(0) ; } while(0); | |||
326 | free(output_info); | |||
327 | } | |||
328 | ||||
329 | const char * | |||
330 | diff_output_get_label_left(const struct diff_input_info *info) | |||
331 | { | |||
332 | if (info->flags & DIFF_INPUT_LEFT_NONEXISTENT0x00000001) | |||
333 | return "/dev/null"; | |||
334 | ||||
335 | return info->left_path ? : "a"; | |||
336 | } | |||
337 | ||||
338 | const char * | |||
339 | diff_output_get_label_right(const struct diff_input_info *info) | |||
340 | { | |||
341 | if (info->flags & DIFF_INPUT_RIGHT_NONEXISTENT0x00000002) | |||
342 | return "/dev/null"; | |||
343 | ||||
344 | return info->right_path ? : "b"; | |||
345 | } |