1 /* Common parts for printing diff output */
3 * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de>
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.
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.
27 #include <arraylist.h>
28 #include <diff_main.h>
29 #include <diff_output.h>
31 #include "diff_internal.h"
34 get_atom_byte(int *ch
, struct diff_atom
*atom
, off_t off
)
38 if (atom
->at
!= NULL
) {
43 cur
= ftello(atom
->root
->f
);
47 if (cur
!= atom
->pos
+ off
&&
48 fseeko(atom
->root
->f
, atom
->pos
+ off
, SEEK_SET
) == -1)
51 *ch
= fgetc(atom
->root
->f
);
52 if (*ch
== EOF
&& ferror(atom
->root
->f
))
58 #define DIFF_OUTPUT_BUF_SIZE 512
61 diff_output_lines(struct diff_output_info
*outinfo
, FILE *dest
,
62 const char *prefix
, struct diff_atom
*start_atom
,
65 struct diff_atom
*atom
;
66 off_t outoff
= 0, *offp
;
70 if (outinfo
&& outinfo
->line_offsets
.len
> 0) {
71 unsigned int idx
= outinfo
->line_offsets
.len
- 1;
72 outoff
= outinfo
->line_offsets
.head
[idx
];
75 foreach_diff_atom(atom
, start_atom
, count
) {
78 unsigned int len
= atom
->len
;
79 unsigned char buf
[DIFF_OUTPUT_BUF_SIZE
+ 1 /* '\n' */];
82 n
= strlcpy(buf
, prefix
, sizeof(buf
));
83 if (n
>= DIFF_OUTPUT_BUF_SIZE
) /* leave room for '\n' */
88 rc
= get_atom_byte(&ch
, atom
, len
- 1);
95 for (i
= 0; i
< len
; i
++) {
96 rc
= get_atom_byte(&ch
, atom
, i
);
99 if (nbuf
>= DIFF_OUTPUT_BUF_SIZE
) {
100 rc
= fwrite(buf
, 1, nbuf
, dest
);
109 rc
= fwrite(buf
, 1, nbuf
, dest
);
114 ARRAYLIST_ADD(offp
, outinfo
->line_offsets
);
119 ARRAYLIST_ADD(typep
, outinfo
->line_types
);
122 *typep
= *prefix
== ' ' ? DIFF_LINE_CONTEXT
:
123 *prefix
== '-' ? DIFF_LINE_MINUS
:
124 *prefix
== '+' ? DIFF_LINE_PLUS
: DIFF_LINE_NONE
;
132 diff_output_chunk_left_version(struct diff_output_info
**output_info
,
134 const struct diff_input_info
*info
,
135 const struct diff_result
*result
,
136 const struct diff_chunk_context
*cc
)
139 struct diff_output_info
*outinfo
= NULL
;
141 if (diff_range_empty(&cc
->left
))
145 *output_info
= diff_output_info_alloc();
146 if (*output_info
== NULL
)
148 outinfo
= *output_info
;
151 /* Write out all chunks on the left side. */
152 for (c_idx
= cc
->chunk
.start
; c_idx
< cc
->chunk
.end
; c_idx
++) {
153 const struct diff_chunk
*c
= &result
->chunks
.head
[c_idx
];
156 rc
= diff_output_lines(outinfo
, dest
, "",
157 c
->left_start
, c
->left_count
);
167 diff_output_chunk_right_version(struct diff_output_info
**output_info
,
169 const struct diff_input_info
*info
,
170 const struct diff_result
*result
,
171 const struct diff_chunk_context
*cc
)
174 struct diff_output_info
*outinfo
= NULL
;
176 if (diff_range_empty(&cc
->right
))
180 *output_info
= diff_output_info_alloc();
181 if (*output_info
== NULL
)
183 outinfo
= *output_info
;
186 /* Write out all chunks on the right side. */
187 for (c_idx
= cc
->chunk
.start
; c_idx
< cc
->chunk
.end
; c_idx
++) {
188 const struct diff_chunk
*c
= &result
->chunks
.head
[c_idx
];
190 if (c
->right_count
) {
191 rc
= diff_output_lines(outinfo
, dest
, "", c
->right_start
,
202 diff_output_trailing_newline_msg(struct diff_output_info
*outinfo
, FILE *dest
,
203 const struct diff_chunk
*c
)
205 enum diff_chunk_type chunk_type
= diff_chunk_type(c
);
206 struct diff_atom
*atom
, *start_atom
;
207 unsigned int atom_count
;
209 off_t outoff
= 0, *offp
;
213 if (chunk_type
== CHUNK_MINUS
|| chunk_type
== CHUNK_SAME
) {
214 start_atom
= c
->left_start
;
215 atom_count
= c
->left_count
;
216 } else if (chunk_type
== CHUNK_PLUS
) {
217 start_atom
= c
->right_start
;
218 atom_count
= c
->right_count
;
222 /* Locate the last atom. */
225 atom
= &start_atom
[atom_count
- 1];
227 rc
= get_atom_byte(&ch
, atom
, atom
->len
- 1);
228 if (rc
!= DIFF_RC_OK
)
232 if (outinfo
&& outinfo
->line_offsets
.len
> 0) {
233 unsigned int idx
= outinfo
->line_offsets
.len
- 1;
234 outoff
= outinfo
->line_offsets
.head
[idx
];
236 rc
= fprintf(dest
, "\\ No newline at end of file\n");
240 ARRAYLIST_ADD(offp
, outinfo
->line_offsets
);
245 ARRAYLIST_ADD(typep
, outinfo
->line_types
);
248 *typep
= DIFF_LINE_NONE
;
256 is_function_prototype(unsigned char ch
)
258 return (isalpha((unsigned char)ch
) || ch
== '_' || ch
== '$');
261 #define begins_with(s, pre) (strncmp(s, pre, sizeof(pre)-1) == 0)
264 diff_output_match_function_prototype(char *prototype
, size_t prototype_size
,
265 int *last_prototype_idx
, const struct diff_result
*result
,
266 const struct diff_chunk_context
*cc
)
268 struct diff_atom
*start_atom
, *atom
;
269 const struct diff_data
*data
;
270 unsigned char buf
[DIFF_FUNCTION_CONTEXT_SIZE
];
271 const char *state
= NULL
;
274 if (result
->left
->atoms
.len
> 0 && cc
->left
.start
> 0) {
276 start_atom
= &data
->atoms
.head
[cc
->left
.start
- 1];
280 diff_data_foreach_atom_backwards_from(start_atom
, atom
, data
) {
281 int atom_idx
= diff_atom_root_idx(data
, atom
);
282 if (atom_idx
< *last_prototype_idx
)
284 rc
= get_atom_byte(&ch
, atom
, 0);
287 buf
[0] = (unsigned char)ch
;
288 if (!is_function_prototype(buf
[0]))
290 for (i
= 1; i
< atom
->len
&& i
< sizeof(buf
) - 1; i
++) {
291 rc
= get_atom_byte(&ch
, atom
, i
);
296 buf
[i
] = (unsigned char)ch
;
299 if (begins_with(buf
, "private:")) {
301 state
= " (private)";
302 } else if (begins_with(buf
, "protected:")) {
304 state
= " (protected)";
305 } else if (begins_with(buf
, "public:")) {
309 if (state
) /* don't care about truncation */
310 strlcat(buf
, state
, sizeof(buf
));
311 strlcpy(prototype
, buf
, prototype_size
);
316 *last_prototype_idx
= diff_atom_root_idx(data
, start_atom
);
320 struct diff_output_info
*
321 diff_output_info_alloc(void)
323 struct diff_output_info
*output_info
;
327 output_info
= malloc(sizeof(*output_info
));
328 if (output_info
!= NULL
) {
329 ARRAYLIST_INIT(output_info
->line_offsets
, 128);
330 ARRAYLIST_ADD(offp
, output_info
->line_offsets
);
332 diff_output_info_free(output_info
);
336 ARRAYLIST_INIT(output_info
->line_types
, 128);
337 ARRAYLIST_ADD(typep
, output_info
->line_types
);
339 diff_output_info_free(output_info
);
342 *typep
= DIFF_LINE_NONE
;
348 diff_output_info_free(struct diff_output_info
*output_info
)
350 ARRAYLIST_FREE(output_info
->line_offsets
);
351 ARRAYLIST_FREE(output_info
->line_types
);
356 diff_output_get_label_left(const struct diff_input_info
*info
)
358 if (info
->flags
& DIFF_INPUT_LEFT_NONEXISTENT
)
361 return info
->left_path
? info
->left_path
: "a";
365 diff_output_get_label_right(const struct diff_input_info
*info
)
367 if (info
->flags
& DIFF_INPUT_RIGHT_NONEXISTENT
)
370 return info
->right_path
? info
->right_path
: "b";