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
;
69 if (outinfo
&& outinfo
->line_offsets
.len
> 0) {
70 unsigned int idx
= outinfo
->line_offsets
.len
- 1;
71 outoff
= outinfo
->line_offsets
.head
[idx
];
74 foreach_diff_atom(atom
, start_atom
, count
) {
77 unsigned int len
= atom
->len
;
78 unsigned char buf
[DIFF_OUTPUT_BUF_SIZE
+ 1 /* '\n' */];
81 n
= strlcpy(buf
, prefix
, sizeof(buf
));
82 if (n
>= DIFF_OUTPUT_BUF_SIZE
) /* leave room for '\n' */
87 rc
= get_atom_byte(&ch
, atom
, len
- 1);
93 rc
= get_atom_byte(&ch
, atom
, len
- 1);
101 for (i
= 0; i
< len
; i
++) {
102 rc
= get_atom_byte(&ch
, atom
, i
);
105 if (nbuf
>= DIFF_OUTPUT_BUF_SIZE
) {
106 rc
= fwrite(buf
, 1, nbuf
, dest
);
115 rc
= fwrite(buf
, 1, nbuf
, dest
);
120 ARRAYLIST_ADD(offp
, outinfo
->line_offsets
);
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
;
211 if (chunk_type
== CHUNK_MINUS
|| chunk_type
== CHUNK_SAME
) {
212 start_atom
= c
->left_start
;
213 atom_count
= c
->left_count
;
214 } else if (chunk_type
== CHUNK_PLUS
) {
215 start_atom
= c
->right_start
;
216 atom_count
= c
->right_count
;
220 /* Locate the last atom. */
223 atom
= &start_atom
[atom_count
- 1];
225 rc
= get_atom_byte(&ch
, atom
, atom
->len
- 1);
226 if (rc
!= DIFF_RC_OK
)
230 if (outinfo
&& outinfo
->line_offsets
.len
> 0) {
231 unsigned int idx
= outinfo
->line_offsets
.len
- 1;
232 outoff
= outinfo
->line_offsets
.head
[idx
];
234 rc
= fprintf(dest
, "\\ No newline at end of file\n");
238 ARRAYLIST_ADD(offp
, outinfo
->line_offsets
);
250 is_function_prototype(unsigned char ch
)
252 return (isalpha(ch
) || ch
== '_' || ch
== '$');
255 #define begins_with(s, pre) (strncmp(s, pre, sizeof(pre)-1) == 0)
258 diff_output_match_function_prototype(char *prototype
, size_t prototype_size
,
259 int *last_prototype_idx
, const struct diff_result
*result
,
260 const struct diff_chunk_context
*cc
)
262 struct diff_atom
*start_atom
, *atom
;
263 const struct diff_data
*data
;
264 unsigned char buf
[DIFF_FUNCTION_CONTEXT_SIZE
];
265 const char *state
= NULL
;
268 if (result
->left
->atoms
.len
> 0 && cc
->left
.start
> 0) {
270 start_atom
= &data
->atoms
.head
[cc
->left
.start
- 1];
274 diff_data_foreach_atom_backwards_from(start_atom
, atom
, data
) {
275 int atom_idx
= diff_atom_root_idx(data
, atom
);
276 if (atom_idx
< *last_prototype_idx
)
278 rc
= get_atom_byte(&ch
, atom
, 0);
281 buf
[0] = (unsigned char)ch
;
282 if (!is_function_prototype(buf
[0]))
284 for (i
= 1; i
< atom
->len
&& i
< sizeof(buf
) - 1; i
++) {
285 rc
= get_atom_byte(&ch
, atom
, i
);
290 buf
[i
] = (unsigned char)ch
;
293 if (begins_with(buf
, "private:")) {
295 state
= " (private)";
296 } else if (begins_with(buf
, "protected:")) {
298 state
= " (protected)";
299 } else if (begins_with(buf
, "public:")) {
303 if (state
) /* don't care about truncation */
304 strlcat(buf
, state
, sizeof(buf
));
305 strlcpy(prototype
, buf
, prototype_size
);
310 *last_prototype_idx
= diff_atom_root_idx(data
, start_atom
);
314 struct diff_output_info
*
315 diff_output_info_alloc(void)
317 struct diff_output_info
*output_info
;
320 output_info
= malloc(sizeof(*output_info
));
321 if (output_info
!= NULL
) {
322 ARRAYLIST_INIT(output_info
->line_offsets
, 128);
323 ARRAYLIST_ADD(offp
, output_info
->line_offsets
);
325 diff_output_info_free(output_info
);
334 diff_output_info_free(struct diff_output_info
*output_info
)
336 ARRAYLIST_FREE(output_info
->line_offsets
);
341 diff_output_get_label_left(const struct diff_input_info
*info
)
343 if (info
->flags
& DIFF_INPUT_LEFT_NONEXISTENT
)
346 return info
->left_path
? : "a";
350 diff_output_get_label_right(const struct diff_input_info
*info
)
352 if (info
->flags
& DIFF_INPUT_RIGHT_NONEXISTENT
)
355 return info
->right_path
? : "b";