| File: | src/usr.bin/cvs/diff3.c |
| Warning: | line 528, column 2 Null pointer passed as 1st argument to memory copy function |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: diff3.c,v 1.65 2021/04/13 14:20:23 stsp Exp $ */ | |||
| 2 | ||||
| 3 | /* | |||
| 4 | * Copyright (C) Caldera International Inc. 2001-2002. | |||
| 5 | * All rights reserved. | |||
| 6 | * | |||
| 7 | * Redistribution and use in source and binary forms, with or without | |||
| 8 | * modification, are permitted provided that the following conditions | |||
| 9 | * are met: | |||
| 10 | * 1. Redistributions of source code and documentation must retain the above | |||
| 11 | * copyright notice, this list of conditions and the following disclaimer. | |||
| 12 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 13 | * notice, this list of conditions and the following disclaimer in the | |||
| 14 | * documentation and/or other materials provided with the distribution. | |||
| 15 | * 3. All advertising materials mentioning features or use of this software | |||
| 16 | * must display the following acknowledgement: | |||
| 17 | * This product includes software developed or owned by Caldera | |||
| 18 | * International, Inc. | |||
| 19 | * 4. Neither the name of Caldera International, Inc. nor the names of other | |||
| 20 | * contributors may be used to endorse or promote products derived from | |||
| 21 | * this software without specific prior written permission. | |||
| 22 | * | |||
| 23 | * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA | |||
| 24 | * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR | |||
| 25 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| 26 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
| 27 | * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, | |||
| 28 | * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
| 29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |||
| 30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |||
| 32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |||
| 33 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
| 34 | * POSSIBILITY OF SUCH DAMAGE. | |||
| 35 | */ | |||
| 36 | /*- | |||
| 37 | * Copyright (c) 1991, 1993 | |||
| 38 | * The Regents of the University of California. All rights reserved. | |||
| 39 | * | |||
| 40 | * Redistribution and use in source and binary forms, with or without | |||
| 41 | * modification, are permitted provided that the following conditions | |||
| 42 | * are met: | |||
| 43 | * 1. Redistributions of source code must retain the above copyright | |||
| 44 | * notice, this list of conditions and the following disclaimer. | |||
| 45 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 46 | * notice, this list of conditions and the following disclaimer in the | |||
| 47 | * documentation and/or other materials provided with the distribution. | |||
| 48 | * 3. Neither the name of the University nor the names of its contributors | |||
| 49 | * may be used to endorse or promote products derived from this software | |||
| 50 | * without specific prior written permission. | |||
| 51 | * | |||
| 52 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
| 53 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
| 54 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
| 55 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
| 56 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
| 57 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
| 58 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| 59 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
| 60 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
| 61 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| 62 | * SUCH DAMAGE. | |||
| 63 | * | |||
| 64 | * @(#)diff3.c 8.1 (Berkeley) 6/6/93 | |||
| 65 | */ | |||
| 66 | ||||
| 67 | #include <ctype.h> | |||
| 68 | #include <errno(*__errno()).h> | |||
| 69 | #include <fcntl.h> | |||
| 70 | #include <stdio.h> | |||
| 71 | #include <stdlib.h> | |||
| 72 | #include <string.h> | |||
| 73 | #include <unistd.h> | |||
| 74 | ||||
| 75 | #include "atomicio.h" | |||
| 76 | #include "cvs.h" | |||
| 77 | #include "diff.h" | |||
| 78 | ||||
| 79 | /* diff3 - 3-way differential file comparison */ | |||
| 80 | ||||
| 81 | /* diff3 [-ex3EX] d13 d23 f1 f2 f3 [m1 m3] | |||
| 82 | * | |||
| 83 | * d13 = diff report on f1 vs f3 | |||
| 84 | * d23 = diff report on f2 vs f3 | |||
| 85 | * f1, f2, f3 the 3 files | |||
| 86 | * if changes in f1 overlap with changes in f3, m1 and m3 are used | |||
| 87 | * to mark the overlaps; otherwise, the file names f1 and f3 are used | |||
| 88 | * (only for options E and X). | |||
| 89 | */ | |||
| 90 | ||||
| 91 | /* | |||
| 92 | * "from" is first in range of changed lines; "to" is last+1 | |||
| 93 | * from=to=line after point of insertion for added lines. | |||
| 94 | */ | |||
| 95 | struct range { | |||
| 96 | int from; | |||
| 97 | int to; | |||
| 98 | }; | |||
| 99 | ||||
| 100 | struct diff { | |||
| 101 | struct range old; | |||
| 102 | struct range new; | |||
| 103 | }; | |||
| 104 | ||||
| 105 | static size_t szchanges; | |||
| 106 | ||||
| 107 | static struct diff *d13; | |||
| 108 | static struct diff *d23; | |||
| 109 | ||||
| 110 | /* | |||
| 111 | * "de" is used to gather editing scripts. These are later spewed out in | |||
| 112 | * reverse order. Its first element must be all zero, the "new" component | |||
| 113 | * of "de" contains line positions or byte positions depending on when you | |||
| 114 | * look (!?). Array overlap indicates which sections in "de" correspond to | |||
| 115 | * lines that are different in all three files. | |||
| 116 | */ | |||
| 117 | static struct diff *de; | |||
| 118 | static char *overlap; | |||
| 119 | static int overlapcnt = 0; | |||
| 120 | static FILE *fp[3]; | |||
| 121 | static int cline[3]; /* # of the last-read line in each file (0-2) */ | |||
| 122 | ||||
| 123 | /* | |||
| 124 | * the latest known correspondence between line numbers of the 3 files | |||
| 125 | * is stored in last[1-3]; | |||
| 126 | */ | |||
| 127 | static int last[4]; | |||
| 128 | static int eflag; | |||
| 129 | static int oflag; /* indicates whether to mark overlaps (-E or -X)*/ | |||
| 130 | static int debug = 0; | |||
| 131 | static char f1mark[PATH_MAX1024], f3mark[PATH_MAX1024]; /* markers for -E and -X */ | |||
| 132 | ||||
| 133 | static int duplicate(struct range *, struct range *); | |||
| 134 | static int edit(struct diff *, int, int); | |||
| 135 | static char *getchange(FILE *); | |||
| 136 | static char *get_line(FILE *, size_t *); | |||
| 137 | static int number(char **); | |||
| 138 | static size_t readin(int, struct diff **); | |||
| 139 | static int skip(int, int, char *); | |||
| 140 | static int edscript(int); | |||
| 141 | static int merge(size_t, size_t); | |||
| 142 | static void change(int, struct range *, int); | |||
| 143 | static void keep(int, struct range *); | |||
| 144 | static void prange(struct range *); | |||
| 145 | static void repos(int); | |||
| 146 | static void separate(const char *); | |||
| 147 | static void increase(void); | |||
| 148 | static int diff3_internal(int, char **, const char *, const char *); | |||
| 149 | ||||
| 150 | int diff3_conflicts = 0; | |||
| 151 | RCSNUM *d3rev1 = NULL((void *)0); | |||
| 152 | RCSNUM *d3rev2 = NULL((void *)0); | |||
| 153 | ||||
| 154 | static int fds[5]; | |||
| 155 | ||||
| 156 | void | |||
| 157 | cvs_merge_file(struct cvs_file *cf, int verbose) | |||
| 158 | { | |||
| 159 | int i, argc; | |||
| 160 | char *data, *patch; | |||
| 161 | char *argv[5], r1[CVS_REV_BUFSZ32], r2[CVS_REV_BUFSZ32]; | |||
| 162 | char *dp13, *dp23, *path1, *path2, *path3; | |||
| 163 | BUF *b1, *d1, *d2, *diffb; | |||
| 164 | size_t dlen, plen; | |||
| 165 | struct rcs_line *lp; | |||
| 166 | struct rcs_lines *dlines, *plines; | |||
| 167 | ||||
| 168 | overlapcnt = 0; | |||
| 169 | b1 = d1 = d2 = diffb = NULL((void *)0); | |||
| 170 | ||||
| 171 | rcsnum_tostr(d3rev1, r1, sizeof(r1)); | |||
| 172 | rcsnum_tostr(d3rev2, r2, sizeof(r2)); | |||
| 173 | ||||
| 174 | b1 = buf_load_fd(cf->fd); | |||
| 175 | d1 = buf_alloc(128); | |||
| 176 | d2 = buf_alloc(128); | |||
| 177 | diffb = buf_alloc(128); | |||
| 178 | ||||
| 179 | (void)xasprintf(&path1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); | |||
| 180 | (void)xasprintf(&path2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); | |||
| 181 | (void)xasprintf(&path3, "%s/diff3.XXXXXXXXXX", cvs_tmpdir); | |||
| 182 | ||||
| 183 | fds[2] = buf_write_stmp(b1, path1, NULL((void *)0)); | |||
| 184 | if (verbose == 1) | |||
| ||||
| 185 | cvs_printf("Retrieving revision %s\n", r1); | |||
| 186 | fds[3] = rcs_rev_write_stmp(cf->file_rcs, d3rev1, path2, 0); | |||
| 187 | if (verbose
| |||
| 188 | cvs_printf("Retrieving revision %s\n", r2); | |||
| 189 | fds[4] = rcs_rev_write_stmp(cf->file_rcs, d3rev2, path3, 0); | |||
| 190 | ||||
| 191 | diffreg(path1, path3, fds[2], fds[4], d1, D_FORCEASCII0x01); | |||
| 192 | diffreg(path2, path3, fds[3], fds[4], d2, D_FORCEASCII0x01); | |||
| 193 | ||||
| 194 | (void)xasprintf(&dp13, "%s/d13.XXXXXXXXXX", cvs_tmpdir); | |||
| 195 | fds[0] = buf_write_stmp(d1, dp13, NULL((void *)0)); | |||
| 196 | buf_free(d1); | |||
| 197 | ||||
| 198 | (void)xasprintf(&dp23, "%s/d23.XXXXXXXXXX", cvs_tmpdir); | |||
| 199 | fds[1] = buf_write_stmp(d2, dp23, NULL((void *)0)); | |||
| 200 | buf_free(d2); | |||
| 201 | ||||
| 202 | argc = 0; | |||
| 203 | diffbuf = diffb; | |||
| 204 | argv[argc++] = dp13; | |||
| 205 | argv[argc++] = dp23; | |||
| 206 | argv[argc++] = path1; | |||
| 207 | argv[argc++] = path2; | |||
| 208 | argv[argc++] = path3; | |||
| 209 | ||||
| 210 | if (lseek(fds[2], 0, SEEK_SET0) == -1) | |||
| 211 | fatal("cvs_merge_file: lseek fds[2]: %s", strerror(errno(*__errno()))); | |||
| 212 | if (lseek(fds[3], 0, SEEK_SET0) == -1) | |||
| 213 | fatal("cvs_merge_file: lseek fds[3]: %s", strerror(errno(*__errno()))); | |||
| 214 | if (lseek(fds[4], 0, SEEK_SET0) == -1) | |||
| 215 | fatal("cvs_merge_file: lseek fds[4]: %s", strerror(errno(*__errno()))); | |||
| 216 | ||||
| 217 | diff3_conflicts = diff3_internal(argc, argv, cf->file_path, r2); | |||
| 218 | if (diff3_conflicts < 0) | |||
| 219 | fatal("cvs_merge_file: merging failed for an unknown reason"); | |||
| 220 | ||||
| 221 | plen = buf_len(diffb); | |||
| 222 | patch = buf_release(diffb); | |||
| 223 | dlen = buf_len(b1); | |||
| 224 | data = buf_release(b1); | |||
| 225 | ||||
| 226 | if (verbose == 1) | |||
| 227 | cvs_printf("Merging differences between %s and %s into `%s'\n", | |||
| 228 | r1, r2, cf->file_path); | |||
| 229 | ||||
| 230 | dlines = cvs_splitlines(data, dlen); | |||
| 231 | plines = cvs_splitlines(patch, plen); | |||
| 232 | ||||
| 233 | ed_patch_lines(dlines, plines); | |||
| 234 | cvs_freelines(plines); | |||
| 235 | ||||
| 236 | if (verbose == 1 && diff3_conflicts != 0) { | |||
| 237 | cvs_log(LP_ERR1, "%d conflict%s found during merge, " | |||
| 238 | "please correct.", diff3_conflicts, | |||
| 239 | (diff3_conflicts > 1) ? "s" : ""); | |||
| 240 | } | |||
| 241 | ||||
| 242 | (void)close(cf->fd); | |||
| 243 | cf->fd = open(cf->file_path, O_CREAT0x0200 | O_RDWR0x0002 | O_TRUNC0x0400, 0644); | |||
| 244 | if (cf->fd == -1) { | |||
| 245 | fatal("cvs_merge_file: failed to reopen fd for writing: %s", | |||
| 246 | strerror(errno(*__errno()))); | |||
| 247 | } | |||
| 248 | ||||
| 249 | TAILQ_FOREACH(lp, &(dlines->l_lines), l_list)for((lp) = ((&(dlines->l_lines))->tqh_first); (lp) != ((void *)0); (lp) = ((lp)->l_list.tqe_next)) { | |||
| 250 | if (lp->l_line == NULL((void *)0)) | |||
| 251 | continue; | |||
| 252 | ||||
| 253 | if (atomicio(vwrite(ssize_t (*)(int, void *, size_t))write, cf->fd, lp->l_line, lp->l_len) != | |||
| 254 | lp->l_len) | |||
| 255 | fatal("cvs_merge_file: %s", strerror(errno(*__errno()))); | |||
| 256 | } | |||
| 257 | ||||
| 258 | cvs_freelines(dlines); | |||
| 259 | ||||
| 260 | free(data); | |||
| 261 | free(patch); | |||
| 262 | ||||
| 263 | for (i = 0; i < 3; i++) | |||
| 264 | fclose(fp[i]); | |||
| 265 | ||||
| 266 | worklist_run(&temp_files, worklist_unlink); | |||
| 267 | ||||
| 268 | free(path1); | |||
| 269 | free(path2); | |||
| 270 | free(path3); | |||
| 271 | free(dp13); | |||
| 272 | free(dp23); | |||
| 273 | } | |||
| 274 | ||||
| 275 | static int | |||
| 276 | diff3_internal(int argc, char **argv, const char *fmark, const char *rmark) | |||
| 277 | { | |||
| 278 | size_t m, n; | |||
| 279 | int i; | |||
| 280 | ||||
| 281 | eflag = 3; | |||
| 282 | oflag = 1; | |||
| 283 | ||||
| 284 | if (argc
| |||
| 285 | return (-1); | |||
| 286 | ||||
| 287 | (void)xsnprintf(f1mark, sizeof(f1mark), "<<<<<<< %s", fmark); | |||
| 288 | (void)xsnprintf(f3mark, sizeof(f3mark), ">>>>>>> %s", rmark); | |||
| 289 | ||||
| 290 | szchanges = 0; | |||
| 291 | memset(last, 0, sizeof(last)); | |||
| 292 | memset(cline, 0, sizeof(cline)); | |||
| 293 | free(d13); | |||
| 294 | free(d23); | |||
| 295 | free(overlap); | |||
| 296 | free(de); | |||
| 297 | ||||
| 298 | de = d13 = d23 = NULL((void *)0); | |||
| 299 | overlap = NULL((void *)0); | |||
| 300 | ||||
| 301 | increase(); | |||
| 302 | ||||
| 303 | /* fds[0] and fds[1] are closed in readin() */ | |||
| 304 | m = readin(fds[0], &d13); | |||
| 305 | n = readin(fds[1], &d23); | |||
| 306 | ||||
| 307 | for (i = 0; i <= 2; i++) { | |||
| 308 | if ((fp[i] = fdopen(fds[i + 2], "r")) == NULL((void *)0)) { | |||
| 309 | cvs_log(LP_ERR1, "%s", argv[i + 2]); | |||
| 310 | return (-1); | |||
| 311 | } | |||
| 312 | } | |||
| 313 | ||||
| 314 | return (merge(m, n)); | |||
| 315 | } | |||
| 316 | ||||
| 317 | int | |||
| 318 | ed_patch_lines(struct rcs_lines *dlines, struct rcs_lines *plines) | |||
| 319 | { | |||
| 320 | char op, *ep; | |||
| 321 | struct rcs_line *sort, *lp, *dlp, *ndlp, *insert_after; | |||
| 322 | int start, end, i, lineno; | |||
| 323 | u_char tmp; | |||
| 324 | ||||
| 325 | dlp = TAILQ_FIRST(&(dlines->l_lines))((&(dlines->l_lines))->tqh_first); | |||
| 326 | lp = TAILQ_FIRST(&(plines->l_lines))((&(plines->l_lines))->tqh_first); | |||
| 327 | ||||
| 328 | end = 0; | |||
| 329 | for (lp = TAILQ_NEXT(lp, l_list)((lp)->l_list.tqe_next); lp != NULL((void *)0); | |||
| 330 | lp = TAILQ_NEXT(lp, l_list)((lp)->l_list.tqe_next)) { | |||
| 331 | /* Skip blank lines */ | |||
| 332 | if (lp->l_len < 2) | |||
| 333 | continue; | |||
| 334 | ||||
| 335 | /* NUL-terminate line buffer for strtol() safety. */ | |||
| 336 | tmp = lp->l_line[lp->l_len - 1]; | |||
| 337 | lp->l_line[lp->l_len - 1] = '\0'; | |||
| 338 | ||||
| 339 | op = lp->l_line[strlen(lp->l_line) - 1]; | |||
| 340 | start = (int)strtol(lp->l_line, &ep, 10); | |||
| 341 | ||||
| 342 | /* Restore the last byte of the buffer */ | |||
| 343 | lp->l_line[lp->l_len - 1] = tmp; | |||
| 344 | ||||
| 345 | if (op == 'a') { | |||
| 346 | if (start > dlines->l_nblines || | |||
| 347 | start < 0 || *ep != 'a') | |||
| 348 | fatal("ed_patch_lines %d", start); | |||
| 349 | } else if (op == 'c') { | |||
| 350 | if (start > dlines->l_nblines || | |||
| 351 | start < 0 || (*ep != ',' && *ep != 'c')) | |||
| 352 | fatal("ed_patch_lines"); | |||
| 353 | ||||
| 354 | if (*ep == ',') { | |||
| 355 | ep++; | |||
| 356 | end = (int)strtol(ep, &ep, 10); | |||
| 357 | if (end < 0 || *ep != 'c') | |||
| 358 | fatal("ed_patch_lines"); | |||
| 359 | } else { | |||
| 360 | end = start; | |||
| 361 | } | |||
| 362 | } else { | |||
| 363 | fatal("invalid op %c found while merging", op); | |||
| 364 | } | |||
| 365 | ||||
| 366 | ||||
| 367 | for (;;) { | |||
| 368 | if (dlp == NULL((void *)0)) | |||
| 369 | break; | |||
| 370 | if (dlp->l_lineno == start) | |||
| 371 | break; | |||
| 372 | if (dlp->l_lineno > start) { | |||
| 373 | dlp = TAILQ_PREV(dlp, tqh, l_list)(*(((struct tqh *)((dlp)->l_list.tqe_prev))->tqh_last)); | |||
| 374 | } else if (dlp->l_lineno < start) { | |||
| 375 | ndlp = TAILQ_NEXT(dlp, l_list)((dlp)->l_list.tqe_next); | |||
| 376 | if (ndlp->l_lineno > start) | |||
| 377 | break; | |||
| 378 | dlp = ndlp; | |||
| 379 | } | |||
| 380 | } | |||
| 381 | ||||
| 382 | if (dlp == NULL((void *)0)) | |||
| 383 | fatal("ed_patch_lines"); | |||
| 384 | ||||
| 385 | ||||
| 386 | if (op == 'c') { | |||
| 387 | insert_after = TAILQ_PREV(dlp, tqh, l_list)(*(((struct tqh *)((dlp)->l_list.tqe_prev))->tqh_last)); | |||
| 388 | for (i = 0; i <= (end - start); i++) { | |||
| 389 | ndlp = TAILQ_NEXT(dlp, l_list)((dlp)->l_list.tqe_next); | |||
| 390 | TAILQ_REMOVE(&(dlines->l_lines), dlp, l_list)do { if (((dlp)->l_list.tqe_next) != ((void *)0)) (dlp)-> l_list.tqe_next->l_list.tqe_prev = (dlp)->l_list.tqe_prev ; else (&(dlines->l_lines))->tqh_last = (dlp)->l_list .tqe_prev; *(dlp)->l_list.tqe_prev = (dlp)->l_list.tqe_next ; ; ; } while (0); | |||
| 391 | dlp = ndlp; | |||
| 392 | } | |||
| 393 | dlp = insert_after; | |||
| 394 | } | |||
| 395 | ||||
| 396 | if (op == 'a' || op == 'c') { | |||
| 397 | for (;;) { | |||
| 398 | ndlp = lp; | |||
| 399 | lp = TAILQ_NEXT(lp, l_list)((lp)->l_list.tqe_next); | |||
| 400 | if (lp == NULL((void *)0)) | |||
| 401 | fatal("ed_patch_lines"); | |||
| 402 | ||||
| 403 | if (lp->l_len == 2 && | |||
| 404 | lp->l_line[0] == '.' && | |||
| 405 | lp->l_line[1] == '\n') | |||
| 406 | break; | |||
| 407 | ||||
| 408 | TAILQ_REMOVE(&(plines->l_lines), lp, l_list)do { if (((lp)->l_list.tqe_next) != ((void *)0)) (lp)-> l_list.tqe_next->l_list.tqe_prev = (lp)->l_list.tqe_prev ; else (&(plines->l_lines))->tqh_last = (lp)->l_list .tqe_prev; *(lp)->l_list.tqe_prev = (lp)->l_list.tqe_next ; ; ; } while (0); | |||
| 409 | TAILQ_INSERT_AFTER(&(dlines->l_lines), dlp,do { if (((lp)->l_list.tqe_next = (dlp)->l_list.tqe_next ) != ((void *)0)) (lp)->l_list.tqe_next->l_list.tqe_prev = &(lp)->l_list.tqe_next; else (&(dlines->l_lines ))->tqh_last = &(lp)->l_list.tqe_next; (dlp)->l_list .tqe_next = (lp); (lp)->l_list.tqe_prev = &(dlp)->l_list .tqe_next; } while (0) | |||
| 410 | lp, l_list)do { if (((lp)->l_list.tqe_next = (dlp)->l_list.tqe_next ) != ((void *)0)) (lp)->l_list.tqe_next->l_list.tqe_prev = &(lp)->l_list.tqe_next; else (&(dlines->l_lines ))->tqh_last = &(lp)->l_list.tqe_next; (dlp)->l_list .tqe_next = (lp); (lp)->l_list.tqe_prev = &(dlp)->l_list .tqe_next; } while (0); | |||
| 411 | dlp = lp; | |||
| 412 | ||||
| 413 | lp->l_lineno = start; | |||
| 414 | lp = ndlp; | |||
| 415 | } | |||
| 416 | } | |||
| 417 | ||||
| 418 | /* | |||
| 419 | * always resort lines as the markers might be put at the | |||
| 420 | * same line as we first started editing. | |||
| 421 | */ | |||
| 422 | lineno = 0; | |||
| 423 | TAILQ_FOREACH(sort, &(dlines->l_lines), l_list)for((sort) = ((&(dlines->l_lines))->tqh_first); (sort ) != ((void *)0); (sort) = ((sort)->l_list.tqe_next)) | |||
| 424 | sort->l_lineno = lineno++; | |||
| 425 | dlines->l_nblines = lineno - 1; | |||
| 426 | } | |||
| 427 | ||||
| 428 | return (0); | |||
| 429 | } | |||
| 430 | ||||
| 431 | /* | |||
| 432 | * Pick up the line numbers of all changes from one change file. | |||
| 433 | * (This puts the numbers in a vector, which is not strictly necessary, | |||
| 434 | * since the vector is processed in one sequential pass. | |||
| 435 | * The vector could be optimized out of existence) | |||
| 436 | */ | |||
| 437 | static size_t | |||
| 438 | readin(int fd, struct diff **dd) | |||
| 439 | { | |||
| 440 | int a, b, c, d; | |||
| 441 | char kind, *p; | |||
| 442 | size_t i; | |||
| 443 | ||||
| 444 | fp[0] = fdopen(fd, "r"); | |||
| 445 | if (fp[0] == NULL((void *)0)) | |||
| 446 | fatal("readin: fdopen: %s", strerror(errno(*__errno()))); | |||
| 447 | ||||
| 448 | for (i = 0; (p = getchange(fp[0])); i++) { | |||
| 449 | if (i >= szchanges - 1) | |||
| 450 | increase(); | |||
| 451 | a = b = number(&p); | |||
| 452 | if (*p == ',') { | |||
| 453 | p++; | |||
| 454 | b = number(&p); | |||
| 455 | } | |||
| 456 | kind = *p++; | |||
| 457 | c = d = number(&p); | |||
| 458 | if (*p==',') { | |||
| 459 | p++; | |||
| 460 | d = number(&p); | |||
| 461 | } | |||
| 462 | if (kind == 'a') | |||
| 463 | a++; | |||
| 464 | if (kind == 'd') | |||
| 465 | c++; | |||
| 466 | b++; | |||
| 467 | d++; | |||
| 468 | (*dd)[i].old.from = a; | |||
| 469 | (*dd)[i].old.to = b; | |||
| 470 | (*dd)[i].new.from = c; | |||
| 471 | (*dd)[i].new.to = d; | |||
| 472 | } | |||
| 473 | ||||
| 474 | if (i) { | |||
| 475 | (*dd)[i].old.from = (*dd)[i-1].old.to; | |||
| 476 | (*dd)[i].new.from = (*dd)[i-1].new.to; | |||
| 477 | } | |||
| 478 | ||||
| 479 | (void)fclose(fp[0]); | |||
| 480 | ||||
| 481 | return (i); | |||
| 482 | } | |||
| 483 | ||||
| 484 | static int | |||
| 485 | number(char **lc) | |||
| 486 | { | |||
| 487 | int nn; | |||
| 488 | ||||
| 489 | nn = 0; | |||
| 490 | while (isdigit((unsigned char)(**lc))) | |||
| 491 | nn = nn*10 + *(*lc)++ - '0'; | |||
| 492 | ||||
| 493 | return (nn); | |||
| 494 | } | |||
| 495 | ||||
| 496 | static char * | |||
| 497 | getchange(FILE *b) | |||
| 498 | { | |||
| 499 | char *line; | |||
| 500 | ||||
| 501 | while ((line = get_line(b, NULL((void *)0)))) { | |||
| 502 | if (isdigit((unsigned char)line[0])) | |||
| 503 | return (line); | |||
| 504 | } | |||
| 505 | ||||
| 506 | return (NULL((void *)0)); | |||
| 507 | } | |||
| 508 | ||||
| 509 | static char * | |||
| 510 | get_line(FILE *b, size_t *n) | |||
| 511 | { | |||
| 512 | char *cp; | |||
| 513 | size_t len; | |||
| 514 | static char *buf; | |||
| 515 | static size_t bufsize; | |||
| 516 | ||||
| 517 | if ((cp = fgetln(b, &len)) == NULL((void *)0)) | |||
| 518 | return (NULL((void *)0)); | |||
| 519 | ||||
| 520 | if (cp[len - 1] != '\n') | |||
| 521 | len++; | |||
| 522 | if (len + 1 > bufsize) { | |||
| 523 | do { | |||
| 524 | bufsize += 1024; | |||
| 525 | } while (len + 1 > bufsize); | |||
| 526 | buf = xreallocarray(buf, 1, bufsize); | |||
| 527 | } | |||
| 528 | memcpy(buf, cp, len - 1); | |||
| ||||
| 529 | buf[len - 1] = '\n'; | |||
| 530 | buf[len] = '\0'; | |||
| 531 | if (n != NULL((void *)0)) | |||
| 532 | *n = len; | |||
| 533 | ||||
| 534 | return (buf); | |||
| 535 | } | |||
| 536 | ||||
| 537 | static int | |||
| 538 | merge(size_t m1, size_t m2) | |||
| 539 | { | |||
| 540 | struct diff *d1, *d2, *d3; | |||
| 541 | int dpl, j, t1, t2; | |||
| 542 | ||||
| 543 | d1 = d13; | |||
| 544 | d2 = d23; | |||
| 545 | j = 0; | |||
| 546 | for (;;) { | |||
| 547 | t1 = (d1 < d13 + m1); | |||
| 548 | t2 = (d2 < d23 + m2); | |||
| 549 | if (!t1 && !t2) | |||
| 550 | break; | |||
| 551 | ||||
| 552 | if (debug) { | |||
| 553 | printf("%d,%d=%d,%d %d,%d=%d,%d\n", | |||
| 554 | d1->old.from, d1->old.to, | |||
| 555 | d1->new.from, d1->new.to, | |||
| 556 | d2->old.from, d2->old.to, | |||
| 557 | d2->new.from, d2->new.to); | |||
| 558 | } | |||
| 559 | ||||
| 560 | /* first file is different from others */ | |||
| 561 | if (!t2 || (t1 && d1->new.to < d2->new.from)) { | |||
| 562 | /* stuff peculiar to 1st file */ | |||
| 563 | if (eflag==0) { | |||
| 564 | separate("1"); | |||
| 565 | change(1, &d1->old, 0); | |||
| 566 | keep(2, &d1->new); | |||
| 567 | change(3, &d1->new, 0); | |||
| 568 | } | |||
| 569 | d1++; | |||
| 570 | continue; | |||
| 571 | } | |||
| 572 | ||||
| 573 | /* second file is different from others */ | |||
| 574 | if (!t1 || (t2 && d2->new.to < d1->new.from)) { | |||
| 575 | if (eflag==0) { | |||
| 576 | separate("2"); | |||
| 577 | keep(1, &d2->new); | |||
| 578 | change(2, &d2->old, 0); | |||
| 579 | change(3, &d2->new, 0); | |||
| 580 | } | |||
| 581 | d2++; | |||
| 582 | continue; | |||
| 583 | } | |||
| 584 | ||||
| 585 | /* | |||
| 586 | * Merge overlapping changes in first file | |||
| 587 | * this happens after extension (see below). | |||
| 588 | */ | |||
| 589 | if (d1 + 1 < d13 + m1 && d1->new.to >= d1[1].new.from) { | |||
| 590 | d1[1].old.from = d1->old.from; | |||
| 591 | d1[1].new.from = d1->new.from; | |||
| 592 | d1++; | |||
| 593 | continue; | |||
| 594 | } | |||
| 595 | ||||
| 596 | /* merge overlapping changes in second */ | |||
| 597 | if (d2 + 1 < d23 + m2 && d2->new.to >= d2[1].new.from) { | |||
| 598 | d2[1].old.from = d2->old.from; | |||
| 599 | d2[1].new.from = d2->new.from; | |||
| 600 | d2++; | |||
| 601 | continue; | |||
| 602 | } | |||
| 603 | /* stuff peculiar to third file or different in all */ | |||
| 604 | if (d1->new.from == d2->new.from && d1->new.to == d2->new.to) { | |||
| 605 | dpl = duplicate(&d1->old,&d2->old); | |||
| 606 | if (dpl == -1) | |||
| 607 | return (-1); | |||
| 608 | ||||
| 609 | /* | |||
| 610 | * dpl = 0 means all files differ | |||
| 611 | * dpl = 1 means files 1 and 2 identical | |||
| 612 | */ | |||
| 613 | if (eflag==0) { | |||
| 614 | separate(dpl ? "3" : ""); | |||
| 615 | change(1, &d1->old, dpl); | |||
| 616 | change(2, &d2->old, 0); | |||
| 617 | d3 = d1->old.to > d1->old.from ? d1 : d2; | |||
| 618 | change(3, &d3->new, 0); | |||
| 619 | } else | |||
| 620 | j = edit(d1, dpl, j); | |||
| 621 | d1++; | |||
| 622 | d2++; | |||
| 623 | continue; | |||
| 624 | } | |||
| 625 | ||||
| 626 | /* | |||
| 627 | * Overlapping changes from file 1 and 2; extend changes | |||
| 628 | * appropriately to make them coincide. | |||
| 629 | */ | |||
| 630 | if (d1->new.from < d2->new.from) { | |||
| 631 | d2->old.from -= d2->new.from-d1->new.from; | |||
| 632 | d2->new.from = d1->new.from; | |||
| 633 | } else if (d2->new.from < d1->new.from) { | |||
| 634 | d1->old.from -= d1->new.from-d2->new.from; | |||
| 635 | d1->new.from = d2->new.from; | |||
| 636 | } | |||
| 637 | if (d1->new.to > d2->new.to) { | |||
| 638 | d2->old.to += d1->new.to - d2->new.to; | |||
| 639 | d2->new.to = d1->new.to; | |||
| 640 | } else if (d2->new.to > d1->new.to) { | |||
| 641 | d1->old.to += d2->new.to - d1->new.to; | |||
| 642 | d1->new.to = d2->new.to; | |||
| 643 | } | |||
| 644 | } | |||
| 645 | ||||
| 646 | return (edscript(j)); | |||
| 647 | } | |||
| 648 | ||||
| 649 | static void | |||
| 650 | separate(const char *s) | |||
| 651 | { | |||
| 652 | diff_output("====%s\n", s); | |||
| 653 | } | |||
| 654 | ||||
| 655 | /* | |||
| 656 | * The range of lines rold.from thru rold.to in file i is to be changed. | |||
| 657 | * It is to be printed only if it does not duplicate something to be | |||
| 658 | * printed later. | |||
| 659 | */ | |||
| 660 | static void | |||
| 661 | change(int i, struct range *rold, int fdup) | |||
| 662 | { | |||
| 663 | diff_output("%d:", i); | |||
| 664 | last[i] = rold->to; | |||
| 665 | prange(rold); | |||
| 666 | if (fdup || debug) | |||
| 667 | return; | |||
| 668 | i--; | |||
| 669 | (void)skip(i, rold->from, NULL((void *)0)); | |||
| 670 | (void)skip(i, rold->to, " "); | |||
| 671 | } | |||
| 672 | ||||
| 673 | /* | |||
| 674 | * print the range of line numbers, rold.from thru rold.to, as n1,n2 or n1 | |||
| 675 | */ | |||
| 676 | static void | |||
| 677 | prange(struct range *rold) | |||
| 678 | { | |||
| 679 | if (rold->to <= rold->from) | |||
| 680 | diff_output("%da\n", rold->from - 1); | |||
| 681 | else { | |||
| 682 | diff_output("%d", rold->from); | |||
| 683 | if (rold->to > rold->from+1) | |||
| 684 | diff_output(",%d", rold->to - 1); | |||
| 685 | diff_output("c\n"); | |||
| 686 | } | |||
| 687 | } | |||
| 688 | ||||
| 689 | /* | |||
| 690 | * No difference was reported by diff between file 1 (or 2) and file 3, | |||
| 691 | * and an artificial dummy difference (trange) must be ginned up to | |||
| 692 | * correspond to the change reported in the other file. | |||
| 693 | */ | |||
| 694 | static void | |||
| 695 | keep(int i, struct range *rnew) | |||
| 696 | { | |||
| 697 | int delta; | |||
| 698 | struct range trange; | |||
| 699 | ||||
| 700 | delta = last[3] - last[i]; | |||
| 701 | trange.from = rnew->from - delta; | |||
| 702 | trange.to = rnew->to - delta; | |||
| 703 | change(i, &trange, 1); | |||
| 704 | } | |||
| 705 | ||||
| 706 | /* | |||
| 707 | * skip to just before line number from in file "i". If "pr" is non-NULL, | |||
| 708 | * print all skipped stuff with string pr as a prefix. | |||
| 709 | */ | |||
| 710 | static int | |||
| 711 | skip(int i, int from, char *pr) | |||
| 712 | { | |||
| 713 | size_t j, n; | |||
| 714 | char *line; | |||
| 715 | ||||
| 716 | for (n = 0; cline[i] < from - 1; n += j) { | |||
| 717 | if ((line = get_line(fp[i], &j)) == NULL((void *)0)) | |||
| 718 | return (-1); | |||
| 719 | if (pr != NULL((void *)0)) | |||
| 720 | diff_output("%s%s", pr, line); | |||
| 721 | cline[i]++; | |||
| 722 | } | |||
| 723 | return ((int) n); | |||
| 724 | } | |||
| 725 | ||||
| 726 | /* | |||
| 727 | * Return 1 or 0 according as the old range (in file 1) contains exactly | |||
| 728 | * the same data as the new range (in file 2). | |||
| 729 | */ | |||
| 730 | static int | |||
| 731 | duplicate(struct range *r1, struct range *r2) | |||
| 732 | { | |||
| 733 | int c,d; | |||
| 734 | int nchar; | |||
| 735 | int nline; | |||
| 736 | ||||
| 737 | if (r1->to-r1->from != r2->to-r2->from) | |||
| 738 | return (0); | |||
| 739 | (void)skip(0, r1->from, NULL((void *)0)); | |||
| 740 | (void)skip(1, r2->from, NULL((void *)0)); | |||
| 741 | nchar = 0; | |||
| 742 | for (nline=0; nline < r1->to - r1->from; nline++) { | |||
| 743 | do { | |||
| 744 | c = getc(fp[0])(!__isthreaded ? (--(fp[0])->_r < 0 ? __srget(fp[0]) : ( int)(*(fp[0])->_p++)) : (getc)(fp[0])); | |||
| 745 | d = getc(fp[1])(!__isthreaded ? (--(fp[1])->_r < 0 ? __srget(fp[1]) : ( int)(*(fp[1])->_p++)) : (getc)(fp[1])); | |||
| 746 | if (c == -1 && d == -1) | |||
| 747 | break; | |||
| 748 | if (c == -1 || d== -1) | |||
| 749 | return (-1); | |||
| 750 | nchar++; | |||
| 751 | if (c != d) { | |||
| 752 | repos(nchar); | |||
| 753 | return (0); | |||
| 754 | } | |||
| 755 | } while (c != '\n'); | |||
| 756 | } | |||
| 757 | repos(nchar); | |||
| 758 | return (1); | |||
| 759 | } | |||
| 760 | ||||
| 761 | static void | |||
| 762 | repos(int nchar) | |||
| 763 | { | |||
| 764 | int i; | |||
| 765 | ||||
| 766 | for (i = 0; i < 2; i++) | |||
| 767 | (void)fseek(fp[i], (long)-nchar, SEEK_CUR1); | |||
| 768 | } | |||
| 769 | ||||
| 770 | /* | |||
| 771 | * collect an editing script for later regurgitation | |||
| 772 | */ | |||
| 773 | static int | |||
| 774 | edit(struct diff *diff, int fdup, int j) | |||
| 775 | { | |||
| 776 | if (((fdup + 1) & eflag) == 0) | |||
| 777 | return (j); | |||
| 778 | j++; | |||
| 779 | overlap[j] = !fdup; | |||
| 780 | if (!fdup) | |||
| 781 | overlapcnt++; | |||
| 782 | de[j].old.from = diff->old.from; | |||
| 783 | de[j].old.to = diff->old.to; | |||
| 784 | de[j].new.from = de[j-1].new.to + skip(2, diff->new.from, NULL((void *)0)); | |||
| 785 | de[j].new.to = de[j].new.from + skip(2, diff->new.to, NULL((void *)0)); | |||
| 786 | return (j); | |||
| 787 | } | |||
| 788 | ||||
| 789 | /* regurgitate */ | |||
| 790 | static int | |||
| 791 | edscript(int n) | |||
| 792 | { | |||
| 793 | int j, k; | |||
| 794 | char block[BUFSIZ1024+1]; | |||
| 795 | ||||
| 796 | for (; n > 0; n--) { | |||
| 797 | if (!oflag || !overlap[n]) | |||
| 798 | prange(&de[n].old); | |||
| 799 | else | |||
| 800 | diff_output("%da\n=======\n", de[n].old.to -1); | |||
| 801 | (void)fseek(fp[2], (long)de[n].new.from, SEEK_SET0); | |||
| 802 | for (k = de[n].new.to-de[n].new.from; k > 0; k-= j) { | |||
| 803 | size_t r; | |||
| 804 | j = k > BUFSIZ1024 ? BUFSIZ1024 : k; | |||
| 805 | r = fread(block, 1, j, fp[2]); | |||
| 806 | if (r == 0) { | |||
| 807 | if (feof(fp[2])(!__isthreaded ? (((fp[2])->_flags & 0x0020) != 0) : ( feof)(fp[2]))) | |||
| 808 | break; | |||
| 809 | return (-1); | |||
| 810 | } | |||
| 811 | if (r != (size_t)j) | |||
| 812 | j = r; | |||
| 813 | block[j] = '\0'; | |||
| 814 | diff_output("%s", block); | |||
| 815 | } | |||
| 816 | ||||
| 817 | if (!oflag || !overlap[n]) | |||
| 818 | diff_output(".\n"); | |||
| 819 | else { | |||
| 820 | diff_output("%s\n.\n", f3mark); | |||
| 821 | diff_output("%da\n%s\n.\n", de[n].old.from - 1, f1mark); | |||
| 822 | } | |||
| 823 | } | |||
| 824 | ||||
| 825 | return (overlapcnt); | |||
| 826 | } | |||
| 827 | ||||
| 828 | static void | |||
| 829 | increase(void) | |||
| 830 | { | |||
| 831 | size_t newsz, incr; | |||
| 832 | ||||
| 833 | /* are the memset(3) calls needed? */ | |||
| 834 | newsz = szchanges == 0 ? 64 : 2 * szchanges; | |||
| 835 | incr = newsz - szchanges; | |||
| 836 | ||||
| 837 | d13 = xreallocarray(d13, newsz, sizeof(*d13)); | |||
| 838 | memset(d13 + szchanges, 0, incr * sizeof(*d13)); | |||
| 839 | d23 = xreallocarray(d23, newsz, sizeof(*d23)); | |||
| 840 | memset(d23 + szchanges, 0, incr * sizeof(*d23)); | |||
| 841 | de = xreallocarray(de, newsz, sizeof(*de)); | |||
| 842 | memset(de + szchanges, 0, incr * sizeof(*de)); | |||
| 843 | overlap = xreallocarray(overlap, newsz, sizeof(*overlap)); | |||
| 844 | memset(overlap + szchanges, 0, incr * sizeof(*overlap)); | |||
| 845 | szchanges = newsz; | |||
| 846 | } |