File: | src/usr.bin/rcs/diff3.c |
Warning: | line 623, 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.45 2021/04/13 14:20:24 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 <err.h> | |||
69 | #include <stdio.h> | |||
70 | #include <stdlib.h> | |||
71 | #include <string.h> | |||
72 | #include <time.h> | |||
73 | #include <unistd.h> | |||
74 | ||||
75 | #include "diff.h" | |||
76 | #include "rcsprog.h" | |||
77 | ||||
78 | /* diff3 - 3-way differential file comparison */ | |||
79 | ||||
80 | /* diff3 [-ex3EX] d13 d23 f1 f2 f3 [m1 m3] | |||
81 | * | |||
82 | * d13 = diff report on f1 vs f3 | |||
83 | * d23 = diff report on f2 vs f3 | |||
84 | * f1, f2, f3 the 3 files | |||
85 | * if changes in f1 overlap with changes in f3, m1 and m3 are used | |||
86 | * to mark the overlaps; otherwise, the file names f1 and f3 are used | |||
87 | * (only for options E and X). | |||
88 | */ | |||
89 | ||||
90 | /* | |||
91 | * "from" is first in range of changed lines; "to" is last+1 | |||
92 | * from=to=line after point of insertion for added lines. | |||
93 | */ | |||
94 | struct range { | |||
95 | int from; | |||
96 | int to; | |||
97 | }; | |||
98 | ||||
99 | struct diff { | |||
100 | struct range old; | |||
101 | struct range new; | |||
102 | }; | |||
103 | ||||
104 | static size_t szchanges; | |||
105 | ||||
106 | static struct diff *d13; | |||
107 | static struct diff *d23; | |||
108 | ||||
109 | /* | |||
110 | * "de" is used to gather editing scripts. These are later spewed out in | |||
111 | * reverse order. Its first element must be all zero, the "new" component | |||
112 | * of "de" contains line positions or byte positions depending on when you | |||
113 | * look (!?). Array overlap indicates which sections in "de" correspond to | |||
114 | * lines that are different in all three files. | |||
115 | */ | |||
116 | static struct diff *de; | |||
117 | static char *overlap; | |||
118 | static int overlapcnt = 0; | |||
119 | static FILE *fp[3]; | |||
120 | static int cline[3]; /* # of the last-read line in each file (0-2) */ | |||
121 | ||||
122 | /* | |||
123 | * the latest known correspondence between line numbers of the 3 files | |||
124 | * is stored in last[1-3]; | |||
125 | */ | |||
126 | static int last[4]; | |||
127 | static int eflag = 3; /* default -E for compatibility with former RCS */ | |||
128 | static int oflag = 1; /* default -E for compatibility with former RCS */ | |||
129 | static int debug = 0; | |||
130 | static char f1mark[PATH_MAX1024], f3mark[PATH_MAX1024]; /* markers for -E and -X */ | |||
131 | ||||
132 | static int duplicate(struct range *, struct range *); | |||
133 | static int edit(struct diff *, int, int); | |||
134 | static char *getchange(FILE *); | |||
135 | static char *get_line(FILE *, size_t *); | |||
136 | static int number(char **); | |||
137 | static ssize_t readin(char *, struct diff **); | |||
138 | static int skip(int, int, char *); | |||
139 | static int edscript(int); | |||
140 | static int merge(size_t, size_t); | |||
141 | static void change(int, struct range *, int); | |||
142 | static void keep(int, struct range *); | |||
143 | static void prange(struct range *); | |||
144 | static void repos(int); | |||
145 | static void separate(const char *); | |||
146 | static void increase(void); | |||
147 | static int diff3_internal(int, char **, const char *, const char *); | |||
148 | ||||
149 | int diff3_conflicts = 0; | |||
150 | ||||
151 | /* | |||
152 | * For merge(1). | |||
153 | */ | |||
154 | BUF * | |||
155 | merge_diff3(char **av, int flags) | |||
156 | { | |||
157 | int argc; | |||
158 | char *argv[5], *dp13, *dp23, *path1, *path2, *path3; | |||
159 | BUF *b1, *b2, *b3, *d1, *d2, *diffb; | |||
160 | u_char *data, *patch; | |||
161 | size_t dlen, plen; | |||
162 | ||||
163 | b1 = b2 = b3 = d1 = d2 = diffb = NULL((void *)0); | |||
164 | dp13 = dp23 = path1 = path2 = path3 = NULL((void *)0); | |||
165 | data = patch = NULL((void *)0); | |||
166 | ||||
167 | if ((flags & MERGE_EFLAG(1<<16)) && !(flags & MERGE_OFLAG(1<<17))) | |||
168 | oflag = 0; | |||
169 | ||||
170 | if ((b1 = buf_load(av[0])) == NULL((void *)0)) | |||
171 | goto out; | |||
172 | if ((b2 = buf_load(av[1])) == NULL((void *)0)) | |||
173 | goto out; | |||
174 | if ((b3 = buf_load(av[2])) == NULL((void *)0)) | |||
175 | goto out; | |||
176 | ||||
177 | d1 = buf_alloc(128); | |||
178 | d2 = buf_alloc(128); | |||
179 | diffb = buf_alloc(128); | |||
180 | ||||
181 | (void)xasprintf(&path1, "%s/diff1.XXXXXXXXXX", rcs_tmpdir); | |||
182 | (void)xasprintf(&path2, "%s/diff2.XXXXXXXXXX", rcs_tmpdir); | |||
183 | (void)xasprintf(&path3, "%s/diff3.XXXXXXXXXX", rcs_tmpdir); | |||
184 | ||||
185 | buf_write_stmp(b1, path1); | |||
186 | buf_write_stmp(b2, path2); | |||
187 | buf_write_stmp(b3, path3); | |||
188 | ||||
189 | buf_free(b2); | |||
190 | b2 = NULL((void *)0); | |||
191 | ||||
192 | if ((diffreg(path1, path3, d1, D_FORCEASCII0x01) == D_ERROR2) || | |||
193 | (diffreg(path2, path3, d2, D_FORCEASCII0x01) == D_ERROR2)) { | |||
194 | buf_free(diffb); | |||
195 | diffb = NULL((void *)0); | |||
196 | goto out; | |||
197 | } | |||
198 | ||||
199 | (void)xasprintf(&dp13, "%s/d13.XXXXXXXXXX", rcs_tmpdir); | |||
200 | buf_write_stmp(d1, dp13); | |||
201 | ||||
202 | buf_free(d1); | |||
203 | d1 = NULL((void *)0); | |||
204 | ||||
205 | (void)xasprintf(&dp23, "%s/d23.XXXXXXXXXX", rcs_tmpdir); | |||
206 | buf_write_stmp(d2, dp23); | |||
207 | ||||
208 | buf_free(d2); | |||
209 | d2 = NULL((void *)0); | |||
210 | ||||
211 | argc = 0; | |||
212 | diffbuf = diffb; | |||
213 | argv[argc++] = dp13; | |||
214 | argv[argc++] = dp23; | |||
215 | argv[argc++] = path1; | |||
216 | argv[argc++] = path2; | |||
217 | argv[argc++] = path3; | |||
218 | ||||
219 | diff3_conflicts = diff3_internal(argc, argv, av[0], av[2]); | |||
220 | if (diff3_conflicts < 0) { | |||
221 | buf_free(diffb); | |||
222 | diffb = NULL((void *)0); | |||
223 | goto out; | |||
224 | } | |||
225 | ||||
226 | plen = buf_len(diffb); | |||
227 | patch = buf_release(diffb); | |||
228 | dlen = buf_len(b1); | |||
229 | data = buf_release(b1); | |||
230 | ||||
231 | if ((diffb = rcs_patchfile(data, dlen, patch, plen, ed_patch_lines)) == NULL((void *)0)) | |||
232 | goto out; | |||
233 | ||||
234 | if (!(flags & QUIET(1<<24)) && diff3_conflicts != 0) | |||
235 | warnx("warning: overlaps or other problems during merge"); | |||
236 | ||||
237 | out: | |||
238 | buf_free(b2); | |||
239 | buf_free(b3); | |||
240 | buf_free(d1); | |||
241 | buf_free(d2); | |||
242 | ||||
243 | (void)unlink(path1); | |||
244 | (void)unlink(path2); | |||
245 | (void)unlink(path3); | |||
246 | (void)unlink(dp13); | |||
247 | (void)unlink(dp23); | |||
248 | ||||
249 | free(path1); | |||
250 | free(path2); | |||
251 | free(path3); | |||
252 | free(dp13); | |||
253 | free(dp23); | |||
254 | free(data); | |||
255 | free(patch); | |||
256 | ||||
257 | return (diffb); | |||
258 | } | |||
259 | ||||
260 | BUF * | |||
261 | rcs_diff3(RCSFILE *rf, char *workfile, RCSNUM *rev1, RCSNUM *rev2, int flags) | |||
262 | { | |||
263 | int argc; | |||
264 | char *argv[5], r1[RCS_REV_BUFSZ64], r2[RCS_REV_BUFSZ64]; | |||
265 | char *dp13, *dp23, *path1, *path2, *path3; | |||
266 | BUF *b1, *b2, *b3, *d1, *d2, *diffb; | |||
267 | size_t dlen, plen; | |||
268 | u_char *data, *patch; | |||
269 | ||||
270 | b1 = b2 = b3 = d1 = d2 = diffb = NULL((void *)0); | |||
271 | dp13 = dp23 = path1 = path2 = path3 = NULL((void *)0); | |||
272 | data = patch = NULL((void *)0); | |||
273 | ||||
274 | if ((flags & MERGE_EFLAG(1<<16)) && !(flags & MERGE_OFLAG(1<<17))) | |||
| ||||
275 | oflag = 0; | |||
276 | ||||
277 | rcsnum_tostr(rev1, r1, sizeof(r1)); | |||
278 | rcsnum_tostr(rev2, r2, sizeof(r2)); | |||
279 | ||||
280 | if ((b1 = buf_load(workfile)) == NULL((void *)0)) | |||
281 | goto out; | |||
282 | ||||
283 | if (!(flags & QUIET(1<<24))) | |||
284 | (void)fprintf(stderr(&__sF[2]), "retrieving revision %s\n", r1); | |||
285 | if ((b2 = rcs_getrev(rf, rev1)) == NULL((void *)0)) | |||
286 | goto out; | |||
287 | ||||
288 | if (!(flags & QUIET(1<<24))) | |||
289 | (void)fprintf(stderr(&__sF[2]), "retrieving revision %s\n", r2); | |||
290 | if ((b3 = rcs_getrev(rf, rev2)) == NULL((void *)0)) | |||
291 | goto out; | |||
292 | ||||
293 | d1 = buf_alloc(128); | |||
294 | d2 = buf_alloc(128); | |||
295 | diffb = buf_alloc(128); | |||
296 | ||||
297 | (void)xasprintf(&path1, "%s/diff1.XXXXXXXXXX", rcs_tmpdir); | |||
298 | (void)xasprintf(&path2, "%s/diff2.XXXXXXXXXX", rcs_tmpdir); | |||
299 | (void)xasprintf(&path3, "%s/diff3.XXXXXXXXXX", rcs_tmpdir); | |||
300 | ||||
301 | buf_write_stmp(b1, path1); | |||
302 | buf_write_stmp(b2, path2); | |||
303 | buf_write_stmp(b3, path3); | |||
304 | ||||
305 | buf_free(b2); | |||
306 | b2 = NULL((void *)0); | |||
307 | ||||
308 | if ((diffreg(path1, path3, d1, D_FORCEASCII0x01) == D_ERROR2) || | |||
309 | (diffreg(path2, path3, d2, D_FORCEASCII0x01) == D_ERROR2)) { | |||
310 | buf_free(diffb); | |||
311 | diffb = NULL((void *)0); | |||
312 | goto out; | |||
313 | } | |||
314 | ||||
315 | (void)xasprintf(&dp13, "%s/d13.XXXXXXXXXX", rcs_tmpdir); | |||
316 | buf_write_stmp(d1, dp13); | |||
317 | ||||
318 | buf_free(d1); | |||
319 | d1 = NULL((void *)0); | |||
320 | ||||
321 | (void)xasprintf(&dp23, "%s/d23.XXXXXXXXXX", rcs_tmpdir); | |||
322 | buf_write_stmp(d2, dp23); | |||
323 | ||||
324 | buf_free(d2); | |||
325 | d2 = NULL((void *)0); | |||
326 | ||||
327 | argc = 0; | |||
328 | diffbuf = diffb; | |||
329 | argv[argc++] = dp13; | |||
330 | argv[argc++] = dp23; | |||
331 | argv[argc++] = path1; | |||
332 | argv[argc++] = path2; | |||
333 | argv[argc++] = path3; | |||
334 | ||||
335 | diff3_conflicts = diff3_internal(argc, argv, workfile, r2); | |||
336 | if (diff3_conflicts < 0) { | |||
337 | buf_free(diffb); | |||
338 | diffb = NULL((void *)0); | |||
339 | goto out; | |||
340 | } | |||
341 | ||||
342 | plen = buf_len(diffb); | |||
343 | patch = buf_release(diffb); | |||
344 | dlen = buf_len(b1); | |||
345 | data = buf_release(b1); | |||
346 | ||||
347 | if ((diffb = rcs_patchfile(data, dlen, patch, plen, ed_patch_lines)) == NULL((void *)0)) | |||
348 | goto out; | |||
349 | ||||
350 | if (!(flags & QUIET(1<<24)) && diff3_conflicts != 0) | |||
351 | warnx("warning: overlaps or other problems during merge"); | |||
352 | ||||
353 | out: | |||
354 | buf_free(b2); | |||
355 | buf_free(b3); | |||
356 | buf_free(d1); | |||
357 | buf_free(d2); | |||
358 | ||||
359 | (void)unlink(path1); | |||
360 | (void)unlink(path2); | |||
361 | (void)unlink(path3); | |||
362 | (void)unlink(dp13); | |||
363 | (void)unlink(dp23); | |||
364 | ||||
365 | free(path1); | |||
366 | free(path2); | |||
367 | free(path3); | |||
368 | free(dp13); | |||
369 | free(dp23); | |||
370 | free(data); | |||
371 | free(patch); | |||
372 | ||||
373 | return (diffb); | |||
374 | } | |||
375 | ||||
376 | static int | |||
377 | diff3_internal(int argc, char **argv, const char *fmark, const char *rmark) | |||
378 | { | |||
379 | ssize_t m, n; | |||
380 | int i; | |||
381 | ||||
382 | if (argc
| |||
383 | return (-1); | |||
384 | ||||
385 | if (oflag) { | |||
386 | i = snprintf(f1mark, sizeof(f1mark), "<<<<<<< %s", fmark); | |||
387 | if (i < 0 || i >= (int)sizeof(f1mark)) | |||
388 | errx(1, "diff3_internal: string truncated"); | |||
389 | ||||
390 | i = snprintf(f3mark, sizeof(f3mark), ">>>>>>> %s", rmark); | |||
391 | if (i < 0 || i >= (int)sizeof(f3mark)) | |||
392 | errx(1, "diff3_internal: string truncated"); | |||
393 | } | |||
394 | ||||
395 | increase(); | |||
396 | if ((m = readin(argv[0], &d13)) < 0) { | |||
397 | warn("%s", argv[0]); | |||
398 | return (-1); | |||
399 | } | |||
400 | if ((n = readin(argv[1], &d23)) < 0) { | |||
401 | warn("%s", argv[1]); | |||
402 | return (-1); | |||
403 | } | |||
404 | ||||
405 | for (i = 0; i <= 2; i++) | |||
406 | if ((fp[i] = fopen(argv[i + 2], "r")) == NULL((void *)0)) { | |||
407 | warn("%s", argv[i + 2]); | |||
408 | return (-1); | |||
409 | } | |||
410 | ||||
411 | return (merge(m, n)); | |||
412 | } | |||
413 | ||||
414 | int | |||
415 | ed_patch_lines(struct rcs_lines *dlines, struct rcs_lines *plines) | |||
416 | { | |||
417 | char op, *ep; | |||
418 | struct rcs_line *sort, *lp, *dlp, *ndlp, *insert_after; | |||
419 | int start, end, i, lineno; | |||
420 | u_char tmp; | |||
421 | ||||
422 | dlp = TAILQ_FIRST(&(dlines->l_lines))((&(dlines->l_lines))->tqh_first); | |||
423 | lp = TAILQ_FIRST(&(plines->l_lines))((&(plines->l_lines))->tqh_first); | |||
424 | ||||
425 | end = 0; | |||
426 | for (lp = TAILQ_NEXT(lp, l_list)((lp)->l_list.tqe_next); lp != NULL((void *)0); | |||
427 | lp = TAILQ_NEXT(lp, l_list)((lp)->l_list.tqe_next)) { | |||
428 | /* Skip blank lines */ | |||
429 | if (lp->l_len < 2) | |||
430 | continue; | |||
431 | ||||
432 | /* NUL-terminate line buffer for strtol() safety. */ | |||
433 | tmp = lp->l_line[lp->l_len - 1]; | |||
434 | lp->l_line[lp->l_len - 1] = '\0'; | |||
435 | ||||
436 | /* len - 1 is NUL terminator so we use len - 2 for 'op' */ | |||
437 | op = lp->l_line[lp->l_len - 2]; | |||
438 | start = (int)strtol(lp->l_line, &ep, 10); | |||
439 | ||||
440 | /* Restore the last byte of the buffer */ | |||
441 | lp->l_line[lp->l_len - 1] = tmp; | |||
442 | ||||
443 | if (op == 'a') { | |||
444 | if (start > dlines->l_nblines || | |||
445 | start < 0 || *ep != 'a') | |||
446 | errx(1, "ed_patch_lines"); | |||
447 | } else if (op == 'c') { | |||
448 | if (start > dlines->l_nblines || | |||
449 | start < 0 || (*ep != ',' && *ep != 'c')) | |||
450 | errx(1, "ed_patch_lines"); | |||
451 | ||||
452 | if (*ep == ',') { | |||
453 | ep++; | |||
454 | end = (int)strtol(ep, &ep, 10); | |||
455 | if (end < 0 || *ep != 'c') | |||
456 | errx(1, "ed_patch_lines"); | |||
457 | } else { | |||
458 | end = start; | |||
459 | } | |||
460 | } | |||
461 | ||||
462 | ||||
463 | for (;;) { | |||
464 | if (dlp == NULL((void *)0)) | |||
465 | break; | |||
466 | if (dlp->l_lineno == start) | |||
467 | break; | |||
468 | if (dlp->l_lineno > start) { | |||
469 | dlp = TAILQ_PREV(dlp, tqh, l_list)(*(((struct tqh *)((dlp)->l_list.tqe_prev))->tqh_last)); | |||
470 | } else if (dlp->l_lineno < start) { | |||
471 | ndlp = TAILQ_NEXT(dlp, l_list)((dlp)->l_list.tqe_next); | |||
472 | if (ndlp->l_lineno > start) | |||
473 | break; | |||
474 | dlp = ndlp; | |||
475 | } | |||
476 | } | |||
477 | ||||
478 | if (dlp == NULL((void *)0)) | |||
479 | errx(1, "ed_patch_lines"); | |||
480 | ||||
481 | ||||
482 | if (op == 'c') { | |||
483 | insert_after = TAILQ_PREV(dlp, tqh, l_list)(*(((struct tqh *)((dlp)->l_list.tqe_prev))->tqh_last)); | |||
484 | for (i = 0; i <= (end - start); i++) { | |||
485 | ndlp = TAILQ_NEXT(dlp, l_list)((dlp)->l_list.tqe_next); | |||
486 | 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); | |||
487 | dlp = ndlp; | |||
488 | } | |||
489 | dlp = insert_after; | |||
490 | } | |||
491 | ||||
492 | if (op == 'a' || op == 'c') { | |||
493 | for (;;) { | |||
494 | ndlp = lp; | |||
495 | lp = TAILQ_NEXT(lp, l_list)((lp)->l_list.tqe_next); | |||
496 | if (lp == NULL((void *)0)) | |||
497 | errx(1, "ed_patch_lines"); | |||
498 | ||||
499 | if (lp->l_len == 2 && | |||
500 | lp->l_line[0] == '.' && | |||
501 | lp->l_line[1] == '\n') | |||
502 | break; | |||
503 | ||||
504 | 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); | |||
505 | 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) | |||
506 | 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); | |||
507 | dlp = lp; | |||
508 | ||||
509 | lp->l_lineno = start; | |||
510 | lp = ndlp; | |||
511 | } | |||
512 | } | |||
513 | ||||
514 | /* | |||
515 | * always resort lines as the markers might be put at the | |||
516 | * same line as we first started editing. | |||
517 | */ | |||
518 | lineno = 0; | |||
519 | TAILQ_FOREACH(sort, &(dlines->l_lines), l_list)for((sort) = ((&(dlines->l_lines))->tqh_first); (sort ) != ((void *)0); (sort) = ((sort)->l_list.tqe_next)) | |||
520 | sort->l_lineno = lineno++; | |||
521 | dlines->l_nblines = lineno - 1; | |||
522 | } | |||
523 | ||||
524 | return (0); | |||
525 | } | |||
526 | ||||
527 | /* | |||
528 | * Pick up the line numbers of all changes from one change file. | |||
529 | * (This puts the numbers in a vector, which is not strictly necessary, | |||
530 | * since the vector is processed in one sequential pass. | |||
531 | * The vector could be optimized out of existence) | |||
532 | */ | |||
533 | static ssize_t | |||
534 | readin(char *name, struct diff **dd) | |||
535 | { | |||
536 | int a, b, c, d; | |||
537 | char kind, *p; | |||
538 | size_t i; | |||
539 | ||||
540 | fp[0] = fopen(name, "r"); | |||
541 | if (fp[0] == NULL((void *)0)) | |||
542 | return (-1); | |||
543 | for (i = 0; (p = getchange(fp[0])); i++) { | |||
544 | if (i >= szchanges - 1) | |||
545 | increase(); | |||
546 | a = b = number(&p); | |||
547 | if (*p == ',') { | |||
548 | p++; | |||
549 | b = number(&p); | |||
550 | } | |||
551 | kind = *p++; | |||
552 | c = d = number(&p); | |||
553 | if (*p==',') { | |||
554 | p++; | |||
555 | d = number(&p); | |||
556 | } | |||
557 | if (kind == 'a') | |||
558 | a++; | |||
559 | if (kind == 'd') | |||
560 | c++; | |||
561 | b++; | |||
562 | d++; | |||
563 | (*dd)[i].old.from = a; | |||
564 | (*dd)[i].old.to = b; | |||
565 | (*dd)[i].new.from = c; | |||
566 | (*dd)[i].new.to = d; | |||
567 | } | |||
568 | ||||
569 | if (i) { | |||
570 | (*dd)[i].old.from = (*dd)[i-1].old.to; | |||
571 | (*dd)[i].new.from = (*dd)[i-1].new.to; | |||
572 | } | |||
573 | ||||
574 | (void)fclose(fp[0]); | |||
575 | ||||
576 | return (i); | |||
577 | } | |||
578 | ||||
579 | static int | |||
580 | number(char **lc) | |||
581 | { | |||
582 | int nn; | |||
583 | ||||
584 | nn = 0; | |||
585 | while (isdigit((unsigned char)(**lc))) | |||
586 | nn = nn*10 + *(*lc)++ - '0'; | |||
587 | ||||
588 | return (nn); | |||
589 | } | |||
590 | ||||
591 | static char * | |||
592 | getchange(FILE *b) | |||
593 | { | |||
594 | char *line; | |||
595 | ||||
596 | while ((line = get_line(b, NULL((void *)0)))) { | |||
597 | if (isdigit((unsigned char)line[0])) | |||
598 | return (line); | |||
599 | } | |||
600 | ||||
601 | return (NULL((void *)0)); | |||
602 | } | |||
603 | ||||
604 | static char * | |||
605 | get_line(FILE *b, size_t *n) | |||
606 | { | |||
607 | char *cp; | |||
608 | size_t len; | |||
609 | static char *buf; | |||
610 | static size_t bufsize; | |||
611 | ||||
612 | if ((cp = fgetln(b, &len)) == NULL((void *)0)) | |||
613 | return (NULL((void *)0)); | |||
614 | ||||
615 | if (cp[len - 1] != '\n') | |||
616 | len++; | |||
617 | if (len + 1 > bufsize) { | |||
618 | do { | |||
619 | bufsize += 1024; | |||
620 | } while (len + 1 > bufsize); | |||
621 | buf = xreallocarray(buf, 1, bufsize); | |||
622 | } | |||
623 | memcpy(buf, cp, len - 1); | |||
| ||||
624 | buf[len - 1] = '\n'; | |||
625 | buf[len] = '\0'; | |||
626 | if (n != NULL((void *)0)) | |||
627 | *n = len; | |||
628 | ||||
629 | return (buf); | |||
630 | } | |||
631 | ||||
632 | static int | |||
633 | merge(size_t m1, size_t m2) | |||
634 | { | |||
635 | struct diff *d1, *d2, *d3; | |||
636 | int dpl, j, t1, t2; | |||
637 | ||||
638 | d1 = d13; | |||
639 | d2 = d23; | |||
640 | j = 0; | |||
641 | for (;;) { | |||
642 | t1 = (d1 < d13 + m1); | |||
643 | t2 = (d2 < d23 + m2); | |||
644 | if (!t1 && !t2) | |||
645 | break; | |||
646 | ||||
647 | if (debug) { | |||
648 | printf("%d,%d=%d,%d %d,%d=%d,%d\n", | |||
649 | d1->old.from, d1->old.to, | |||
650 | d1->new.from, d1->new.to, | |||
651 | d2->old.from, d2->old.to, | |||
652 | d2->new.from, d2->new.to); | |||
653 | } | |||
654 | ||||
655 | /* first file is different from others */ | |||
656 | if (!t2 || (t1 && d1->new.to < d2->new.from)) { | |||
657 | /* stuff peculiar to 1st file */ | |||
658 | if (eflag==0) { | |||
659 | separate("1"); | |||
660 | change(1, &d1->old, 0); | |||
661 | keep(2, &d1->new); | |||
662 | change(3, &d1->new, 0); | |||
663 | } | |||
664 | d1++; | |||
665 | continue; | |||
666 | } | |||
667 | ||||
668 | /* second file is different from others */ | |||
669 | if (!t1 || (t2 && d2->new.to < d1->new.from)) { | |||
670 | if (eflag==0) { | |||
671 | separate("2"); | |||
672 | keep(1, &d2->new); | |||
673 | change(2, &d2->old, 0); | |||
674 | change(3, &d2->new, 0); | |||
675 | } | |||
676 | d2++; | |||
677 | continue; | |||
678 | } | |||
679 | ||||
680 | /* | |||
681 | * Merge overlapping changes in first file | |||
682 | * this happens after extension (see below). | |||
683 | */ | |||
684 | if (d1 + 1 < d13 + m1 && d1->new.to >= d1[1].new.from) { | |||
685 | d1[1].old.from = d1->old.from; | |||
686 | d1[1].new.from = d1->new.from; | |||
687 | d1++; | |||
688 | continue; | |||
689 | } | |||
690 | ||||
691 | /* merge overlapping changes in second */ | |||
692 | if (d2 + 1 < d23 + m2 && d2->new.to >= d2[1].new.from) { | |||
693 | d2[1].old.from = d2->old.from; | |||
694 | d2[1].new.from = d2->new.from; | |||
695 | d2++; | |||
696 | continue; | |||
697 | } | |||
698 | /* stuff peculiar to third file or different in all */ | |||
699 | if (d1->new.from == d2->new.from && d1->new.to == d2->new.to) { | |||
700 | dpl = duplicate(&d1->old,&d2->old); | |||
701 | if (dpl == -1) | |||
702 | return (-1); | |||
703 | ||||
704 | /* | |||
705 | * dpl = 0 means all files differ | |||
706 | * dpl = 1 means files 1 and 2 identical | |||
707 | */ | |||
708 | if (eflag==0) { | |||
709 | separate(dpl ? "3" : ""); | |||
710 | change(1, &d1->old, dpl); | |||
711 | change(2, &d2->old, 0); | |||
712 | d3 = d1->old.to > d1->old.from ? d1 : d2; | |||
713 | change(3, &d3->new, 0); | |||
714 | } else | |||
715 | j = edit(d1, dpl, j); | |||
716 | d1++; | |||
717 | d2++; | |||
718 | continue; | |||
719 | } | |||
720 | ||||
721 | /* | |||
722 | * Overlapping changes from file 1 and 2; extend changes | |||
723 | * appropriately to make them coincide. | |||
724 | */ | |||
725 | if (d1->new.from < d2->new.from) { | |||
726 | d2->old.from -= d2->new.from-d1->new.from; | |||
727 | d2->new.from = d1->new.from; | |||
728 | } else if (d2->new.from < d1->new.from) { | |||
729 | d1->old.from -= d1->new.from-d2->new.from; | |||
730 | d1->new.from = d2->new.from; | |||
731 | } | |||
732 | if (d1->new.to > d2->new.to) { | |||
733 | d2->old.to += d1->new.to - d2->new.to; | |||
734 | d2->new.to = d1->new.to; | |||
735 | } else if (d2->new.to > d1->new.to) { | |||
736 | d1->old.to += d2->new.to - d1->new.to; | |||
737 | d1->new.to = d2->new.to; | |||
738 | } | |||
739 | } | |||
740 | ||||
741 | return (edscript(j)); | |||
742 | } | |||
743 | ||||
744 | static void | |||
745 | separate(const char *s) | |||
746 | { | |||
747 | diff_output("====%s\n", s); | |||
748 | } | |||
749 | ||||
750 | /* | |||
751 | * The range of lines rold.from thru rold.to in file i is to be changed. | |||
752 | * It is to be printed only if it does not duplicate something to be | |||
753 | * printed later. | |||
754 | */ | |||
755 | static void | |||
756 | change(int i, struct range *rold, int fdup) | |||
757 | { | |||
758 | diff_output("%d:", i); | |||
759 | last[i] = rold->to; | |||
760 | prange(rold); | |||
761 | if (fdup || debug) | |||
762 | return; | |||
763 | i--; | |||
764 | (void)skip(i, rold->from, NULL((void *)0)); | |||
765 | (void)skip(i, rold->to, " "); | |||
766 | } | |||
767 | ||||
768 | /* | |||
769 | * print the range of line numbers, rold.from thru rold.to, as n1,n2 or n1 | |||
770 | */ | |||
771 | static void | |||
772 | prange(struct range *rold) | |||
773 | { | |||
774 | if (rold->to <= rold->from) | |||
775 | diff_output("%da\n", rold->from - 1); | |||
776 | else { | |||
777 | diff_output("%d", rold->from); | |||
778 | if (rold->to > rold->from+1) | |||
779 | diff_output(",%d", rold->to - 1); | |||
780 | diff_output("c\n"); | |||
781 | } | |||
782 | } | |||
783 | ||||
784 | /* | |||
785 | * No difference was reported by diff between file 1 (or 2) and file 3, | |||
786 | * and an artificial dummy difference (trange) must be ginned up to | |||
787 | * correspond to the change reported in the other file. | |||
788 | */ | |||
789 | static void | |||
790 | keep(int i, struct range *rnew) | |||
791 | { | |||
792 | int delta; | |||
793 | struct range trange; | |||
794 | ||||
795 | delta = last[3] - last[i]; | |||
796 | trange.from = rnew->from - delta; | |||
797 | trange.to = rnew->to - delta; | |||
798 | change(i, &trange, 1); | |||
799 | } | |||
800 | ||||
801 | /* | |||
802 | * skip to just before line number from in file "i". If "pr" is non-NULL, | |||
803 | * print all skipped stuff with string pr as a prefix. | |||
804 | */ | |||
805 | static int | |||
806 | skip(int i, int from, char *pr) | |||
807 | { | |||
808 | size_t j, n; | |||
809 | char *line; | |||
810 | ||||
811 | for (n = 0; cline[i] < from - 1; n += j) { | |||
812 | if ((line = get_line(fp[i], &j)) == NULL((void *)0)) | |||
813 | return (-1); | |||
814 | if (pr != NULL((void *)0)) | |||
815 | diff_output("%s%s", pr, line); | |||
816 | cline[i]++; | |||
817 | } | |||
818 | return ((int) n); | |||
819 | } | |||
820 | ||||
821 | /* | |||
822 | * Return 1 or 0 according as the old range (in file 1) contains exactly | |||
823 | * the same data as the new range (in file 2). | |||
824 | */ | |||
825 | static int | |||
826 | duplicate(struct range *r1, struct range *r2) | |||
827 | { | |||
828 | int c,d; | |||
829 | int nchar; | |||
830 | int nline; | |||
831 | ||||
832 | if (r1->to-r1->from != r2->to-r2->from) | |||
833 | return (0); | |||
834 | (void)skip(0, r1->from, NULL((void *)0)); | |||
835 | (void)skip(1, r2->from, NULL((void *)0)); | |||
836 | nchar = 0; | |||
837 | for (nline=0; nline < r1->to - r1->from; nline++) { | |||
838 | do { | |||
839 | c = getc(fp[0])(!__isthreaded ? (--(fp[0])->_r < 0 ? __srget(fp[0]) : ( int)(*(fp[0])->_p++)) : (getc)(fp[0])); | |||
840 | d = getc(fp[1])(!__isthreaded ? (--(fp[1])->_r < 0 ? __srget(fp[1]) : ( int)(*(fp[1])->_p++)) : (getc)(fp[1])); | |||
841 | if (c == -1 && d == -1) | |||
842 | break; | |||
843 | if (c == -1 || d== -1) | |||
844 | return (-1); | |||
845 | nchar++; | |||
846 | if (c != d) { | |||
847 | repos(nchar); | |||
848 | return (0); | |||
849 | } | |||
850 | } while (c != '\n'); | |||
851 | } | |||
852 | repos(nchar); | |||
853 | return (1); | |||
854 | } | |||
855 | ||||
856 | static void | |||
857 | repos(int nchar) | |||
858 | { | |||
859 | int i; | |||
860 | ||||
861 | for (i = 0; i < 2; i++) | |||
862 | (void)fseek(fp[i], (long)-nchar, SEEK_CUR1); | |||
863 | } | |||
864 | ||||
865 | /* | |||
866 | * collect an editing script for later regurgitation | |||
867 | */ | |||
868 | static int | |||
869 | edit(struct diff *diff, int fdup, int j) | |||
870 | { | |||
871 | if (((fdup + 1) & eflag) == 0) | |||
872 | return (j); | |||
873 | j++; | |||
874 | overlap[j] = !fdup; | |||
875 | if (!fdup) | |||
876 | overlapcnt++; | |||
877 | de[j].old.from = diff->old.from; | |||
878 | de[j].old.to = diff->old.to; | |||
879 | de[j].new.from = de[j-1].new.to + skip(2, diff->new.from, NULL((void *)0)); | |||
880 | de[j].new.to = de[j].new.from + skip(2, diff->new.to, NULL((void *)0)); | |||
881 | return (j); | |||
882 | } | |||
883 | ||||
884 | /* regurgitate */ | |||
885 | static int | |||
886 | edscript(int n) | |||
887 | { | |||
888 | int j, k; | |||
889 | char block[BUFSIZ1024+1]; | |||
890 | ||||
891 | for (; n > 0; n--) { | |||
892 | if (!oflag || !overlap[n]) | |||
893 | prange(&de[n].old); | |||
894 | else | |||
895 | diff_output("%da\n=======\n", de[n].old.to -1); | |||
896 | (void)fseek(fp[2], (long)de[n].new.from, SEEK_SET0); | |||
897 | for (k = de[n].new.to-de[n].new.from; k > 0; k-= j) { | |||
898 | size_t r; | |||
899 | j = k > BUFSIZ1024 ? BUFSIZ1024 : k; | |||
900 | r = fread(block, 1, j, fp[2]); | |||
901 | if (r == 0) { | |||
902 | if (feof(fp[2])(!__isthreaded ? (((fp[2])->_flags & 0x0020) != 0) : ( feof)(fp[2]))) | |||
903 | break; | |||
904 | return -1; | |||
905 | } | |||
906 | if (r != (size_t)j) | |||
907 | j = r; | |||
908 | block[j] = '\0'; | |||
909 | diff_output("%s", block); | |||
910 | } | |||
911 | ||||
912 | if (!oflag || !overlap[n]) | |||
913 | diff_output(".\n"); | |||
914 | else { | |||
915 | diff_output("%s\n.\n", f3mark); | |||
916 | diff_output("%da\n%s\n.\n", de[n].old.from - 1, f1mark); | |||
917 | } | |||
918 | } | |||
919 | ||||
920 | return (overlapcnt); | |||
921 | } | |||
922 | ||||
923 | static void | |||
924 | increase(void) | |||
925 | { | |||
926 | size_t newsz, incr; | |||
927 | ||||
928 | /* are the memset(3) calls needed? */ | |||
929 | newsz = szchanges == 0 ? 64 : 2 * szchanges; | |||
930 | incr = newsz - szchanges; | |||
931 | ||||
932 | d13 = xreallocarray(d13, newsz, sizeof(*d13)); | |||
933 | memset(d13 + szchanges, 0, incr * sizeof(*d13)); | |||
934 | d23 = xreallocarray(d23, newsz, sizeof(*d23)); | |||
935 | memset(d23 + szchanges, 0, incr * sizeof(*d23)); | |||
936 | de = xreallocarray(de, newsz, sizeof(*de)); | |||
937 | memset(de + szchanges, 0, incr * sizeof(*de)); | |||
938 | overlap = xreallocarray(overlap, newsz, sizeof(*overlap)); | |||
939 | memset(overlap + szchanges, 0, incr * sizeof(*overlap)); | |||
940 | szchanges = newsz; | |||
941 | } |