| File: | tog/../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 | } |