Commit | Line | Data |
---|---|---|
30944a03 WJ |
1 | /* Three-way file comparison program (diff3) for Project GNU |
2 | Copyright (C) 1988, 1989 Free Software Foundation, Inc. | |
3 | ||
4 | This program is free software; you can redistribute it and/or modify | |
5 | it under the terms of the GNU General Public License as published by | |
6 | the Free Software Foundation; either version 1, or (at your option) | |
7 | any later version. | |
8 | ||
9 | This program is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | GNU General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU General Public License | |
15 | along with this program; if not, write to the Free Software | |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
17 | ||
18 | \f | |
19 | /* Written by Randy Smith */ | |
20 | ||
21 | #ifdef __STDC__ | |
22 | #define VOID void | |
23 | #else | |
24 | #define VOID char | |
25 | #endif | |
26 | ||
27 | /* | |
28 | * Include files. | |
29 | */ | |
30 | #include <stdio.h> | |
31 | #include <ctype.h> | |
32 | #include <sys/types.h> | |
33 | #include <sys/stat.h> | |
34 | ||
35 | #ifdef USG | |
36 | #include <fcntl.h> | |
37 | ||
38 | /* Define needed BSD functions in terms of sysV library. */ | |
39 | ||
40 | #define bcmp(s1,s2,n) memcmp((s1),(s2),(n)) | |
41 | #define bzero(s,n) memset((s),0,(n)) | |
42 | ||
43 | #ifndef XENIX | |
44 | #define dup2(f,t) (close(t),fcntl((f),F_DUPFD,(t))) | |
45 | #endif | |
46 | ||
47 | #define vfork fork | |
48 | ||
49 | #else /* not USG */ | |
50 | #include <sys/wait.h> | |
51 | #endif /* not USG */ | |
52 | ||
53 | #ifndef WEXITSTATUS | |
54 | #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) | |
55 | #undef WIFEXITED /* Avoid 4.3BSD incompatibility with Posix. */ | |
56 | #endif | |
57 | #ifndef WIFEXITED | |
58 | #define WIFEXITED(stat_val) (((stat_val) & 255) == 0) | |
59 | #endif | |
60 | ||
61 | #ifdef sparc | |
62 | /* vfork clobbers registers on the Sparc, so don't use it. */ | |
63 | #define vfork fork | |
64 | #endif | |
65 | ||
66 | /* | |
67 | * Internal data structures and macros for the diff3 program; includes | |
68 | * data structures for both diff3 diffs and normal diffs. | |
69 | */ | |
70 | ||
71 | /* | |
72 | * Different files within a diff | |
73 | */ | |
74 | #define FILE0 0 | |
75 | #define FILE1 1 | |
76 | #define FILE2 2 | |
77 | ||
78 | /* | |
79 | * Three way diffs are build out of two two-way diffs; the file which | |
80 | * the two two-way diffs share is: | |
81 | */ | |
82 | #define FILEC FILE0 | |
83 | ||
84 | /* The ranges are indexed by */ | |
85 | #define START 0 | |
86 | #define END 1 | |
87 | ||
88 | enum diff_type { | |
89 | ERROR, /* Should not be used */ | |
90 | ADD, /* Two way diff add */ | |
91 | CHANGE, /* Two way diff change */ | |
92 | DELETE, /* Two way diff delete */ | |
93 | DIFF_ALL, /* All three are different */ | |
94 | DIFF_1ST, /* Only the first is different */ | |
95 | DIFF_2ND, /* Only the second */ | |
96 | DIFF_3RD /* Only the third */ | |
97 | }; | |
98 | ||
99 | /* Two-way diff */ | |
100 | struct diff_block { | |
101 | int ranges[2][2]; /* Ranges are inclusive */ | |
102 | char **lines[2]; /* The actual lines (may contain nulls) */ | |
103 | int *lengths[2]; /* Line lengths (including newlines, if any) */ | |
104 | struct diff_block *next; | |
105 | }; | |
106 | ||
107 | /* Three-way diff */ | |
108 | ||
109 | struct diff3_block { | |
110 | enum diff_type correspond; /* Type of diff */ | |
111 | int ranges[3][2]; /* Ranges are inclusive */ | |
112 | char **lines[3]; /* The actual lines (may contain nulls) */ | |
113 | int *lengths[3]; /* Line lengths (including newlines, if any) */ | |
114 | struct diff3_block *next; | |
115 | }; | |
116 | ||
117 | /* | |
118 | * Access the ranges on a diff block. | |
119 | */ | |
120 | #define D_LOWLINE(diff, filenum) \ | |
121 | ((diff)->ranges[filenum][START]) | |
122 | #define D_HIGHLINE(diff, filenum) \ | |
123 | ((diff)->ranges[filenum][END]) | |
124 | #define D_NUMLINES(diff, filenum) \ | |
125 | (D_HIGHLINE((diff), (filenum)) - D_LOWLINE((diff), (filenum)) + 1) | |
126 | ||
127 | /* | |
128 | * Access the line numbers in a file in a diff by relative line | |
129 | * numbers (i.e. line number within the diff itself). Note that these | |
130 | * are lvalues and can be used for assignment. | |
131 | */ | |
132 | #define D_RELNUM(diff, filenum, linenum) \ | |
133 | (*((diff)->lines[filenum] + linenum)) | |
134 | #define D_RELLEN(diff, filenum, linenum) \ | |
135 | (*((diff)->lengths[filenum] + linenum)) | |
136 | ||
137 | /* | |
138 | * And get at them directly, when that should be necessary. | |
139 | */ | |
140 | #define D_LINEARRAY(diff, filenum) \ | |
141 | ((diff)->lines[filenum]) | |
142 | #define D_LENARRAY(diff, filenum) \ | |
143 | ((diff)->lengths[filenum]) | |
144 | ||
145 | /* | |
146 | * Next block. | |
147 | */ | |
148 | #define D_NEXT(diff) ((diff)->next) | |
149 | ||
150 | /* | |
151 | * Access the type of a diff3 block. | |
152 | */ | |
153 | #define D3_TYPE(diff) ((diff)->correspond) | |
154 | ||
155 | /* | |
156 | * Line mappings based on diffs. The first maps off the top of the | |
157 | * diff, the second off of the bottom. | |
158 | */ | |
159 | #define D_HIGH_MAPLINE(diff, fromfile, tofile, lineno) \ | |
160 | ((lineno) \ | |
161 | - D_HIGHLINE ((diff), (fromfile)) \ | |
162 | + D_HIGHLINE ((diff), (tofile))) | |
163 | ||
164 | #define D_LOW_MAPLINE(diff, fromfile, tofile, lineno) \ | |
165 | ((lineno) \ | |
166 | - D_LOWLINE ((diff), (fromfile)) \ | |
167 | + D_LOWLINE ((diff), (tofile))) | |
168 | ||
169 | /* | |
170 | * General memory allocation function. | |
171 | */ | |
172 | #define ALLOCATE(number, type) \ | |
173 | (type *) xmalloc ((number) * sizeof (type)) | |
174 | \f | |
175 | /* | |
176 | * Options variables for flags set on command line. | |
177 | * | |
178 | * ALWAYS_TEXT: Treat all files as text files; never treat as binary. | |
179 | * | |
180 | * EDSCRIPT: Write out an ed script instead of the standard diff3 format. | |
181 | * | |
182 | * FLAGGING: Indicates that in the case of overlapping diffs (type | |
183 | * DIFF_ALL), the lines which would normally be deleted from file 1 | |
184 | * should be preserved with a special flagging mechanism. | |
185 | * | |
186 | * DONT_WRITE_OVERLAP: 1 if information for overlapping diffs should | |
187 | * not be output. | |
188 | * | |
189 | * DONT_WRITE_SIMPLE: 1 if information for non-overlapping diffs | |
190 | * should not be output. | |
191 | * | |
192 | * FINALWRITE: 1 if a :wq should be included at the end of the script | |
193 | * to write out the file being edited. | |
194 | * | |
195 | * MERGE: output a merged file. | |
196 | */ | |
197 | int always_text; | |
198 | int edscript; | |
199 | int flagging; | |
200 | int dont_write_overlap; | |
201 | int dont_write_simple; | |
202 | int finalwrite; | |
203 | int merge; | |
204 | ||
205 | extern int optind; | |
206 | ||
207 | char *argv0; | |
208 | ||
209 | /* | |
210 | * Forward function declarations. | |
211 | */ | |
212 | struct diff_block *process_diff (); | |
213 | struct diff3_block *make_3way_diff (); | |
214 | void output_diff3 (); | |
215 | int output_diff3_edscript (); | |
216 | int output_diff3_merge (); | |
217 | void usage (); | |
218 | ||
219 | struct diff3_block *using_to_diff3_block (); | |
220 | int copy_stringlist (); | |
221 | struct diff3_block *create_diff3_block (); | |
222 | int compare_line_list (); | |
223 | ||
224 | char *read_diff (); | |
225 | enum diff_type process_diff_control (); | |
226 | char *scan_diff_line (); | |
227 | ||
228 | struct diff3_block *reverse_diff3_blocklist (); | |
229 | ||
230 | VOID *xmalloc (); | |
231 | VOID *xrealloc (); | |
232 | ||
233 | char diff_program[] = DIFF_PROGRAM; | |
234 | ||
235 | /* | |
236 | * Main program. Calls diff twice on two pairs of input files, | |
237 | * combines the two diffs, and outputs them. | |
238 | */ | |
239 | main (argc, argv) | |
240 | int argc; | |
241 | char **argv; | |
242 | { | |
243 | int c, i; | |
244 | int mapping[3]; | |
245 | int rev_mapping[3]; | |
246 | int incompat; | |
247 | int overlaps_found; | |
248 | struct diff_block *thread1, *thread2; | |
249 | struct diff3_block *diff; | |
250 | int tag_count = 0; | |
251 | /* Element 0 is for file 0, element 1 is for file 2. */ | |
252 | char *tag_strings[2]; | |
253 | extern char *optarg; | |
254 | char *commonname; | |
255 | struct stat statb; | |
256 | ||
257 | incompat = 0; | |
258 | tag_strings[0] = tag_strings[1] = 0; | |
259 | ||
260 | argv0 = argv[0]; | |
261 | ||
262 | while ((c = getopt (argc, argv, "aeimx3EXL:")) != EOF) | |
263 | { | |
264 | switch (c) | |
265 | { | |
266 | case 'a': | |
267 | always_text = 1; | |
268 | break; | |
269 | case 'x': | |
270 | dont_write_simple = 1; | |
271 | incompat++; | |
272 | break; | |
273 | case '3': | |
274 | dont_write_overlap = 1; | |
275 | incompat++; | |
276 | break; | |
277 | case 'i': | |
278 | finalwrite = 1; | |
279 | break; | |
280 | case 'm': | |
281 | merge = 1; | |
282 | break; | |
283 | case 'X': | |
284 | dont_write_simple = 1; | |
285 | /* Falls through */ | |
286 | case 'E': | |
287 | flagging = 1; | |
288 | /* Falls through */ | |
289 | case 'e': | |
290 | incompat++; | |
291 | break; | |
292 | case 'L': | |
293 | /* Handle one or two -L arguments. */ | |
294 | if (tag_count < 2) | |
295 | { | |
296 | tag_strings[tag_count++] = optarg; | |
297 | break; | |
298 | } | |
299 | /* Falls through */ | |
300 | case '?': | |
301 | default: | |
302 | usage (); | |
303 | /* NOTREACHED */ | |
304 | } | |
305 | } | |
306 | ||
307 | edscript = incompat & ~merge; /* -eExX3 without -m implies ed script. */ | |
308 | flagging |= ~incompat & merge; /* -m without -eExX3 implies -E. */ | |
309 | ||
310 | if (incompat > 1 /* Ensure at most one of -eExX3. */ | |
311 | || finalwrite & (~incompat | merge) | |
312 | /* -i needs one of -eExX3; -i -m would rewrite input file. */ | |
313 | || tag_count && ! flagging /* -L requires one of -EX. */ | |
314 | || argc - optind != 3) | |
315 | usage (); | |
316 | ||
317 | if (tag_strings[0] == 0) | |
318 | tag_strings[0] = argv[optind]; | |
319 | if (tag_strings[1] == 0) | |
320 | tag_strings[1] = argv[optind + 2]; | |
321 | ||
322 | if (*argv[optind] == '-' && *(argv[optind] + 1) == '\0') | |
323 | { | |
324 | /* Sigh. We've got standard input as the first arg. We can't */ | |
325 | /* call diff twice on stdin */ | |
326 | if (! strcmp (argv[optind + 1], "-") || ! strcmp (argv[optind + 2], "-")) | |
327 | fatal ("`-' specified for more than one input file"); | |
328 | mapping[0] = 1; | |
329 | mapping[1] = 2; | |
330 | mapping[2] = 0; | |
331 | rev_mapping[1] = 0; | |
332 | rev_mapping[2] = 1; | |
333 | rev_mapping[0] = 2; | |
334 | } | |
335 | else | |
336 | { | |
337 | /* Normal, what you'd expect */ | |
338 | mapping[0] = 0; | |
339 | mapping[1] = 1; | |
340 | mapping[2] = 2; | |
341 | rev_mapping[0] = 0; | |
342 | rev_mapping[1] = 1; | |
343 | rev_mapping[2] = 2; | |
344 | } | |
345 | ||
346 | for (i = 0; i < 3; i++) | |
347 | if (argv[optind + i][0] != '-' || argv[optind + i][1] != '\0') | |
348 | if (stat (argv[optind + i], &statb) < 0) | |
349 | perror_with_exit (argv[optind + i]); | |
350 | else if ((statb.st_mode & S_IFMT) == S_IFDIR) | |
351 | { | |
352 | fprintf (stderr, "%s: %s: Is a directory\n", argv0, | |
353 | argv[optind + i]); | |
354 | exit (2); | |
355 | } | |
356 | ||
357 | ||
358 | commonname = argv[optind + rev_mapping[0]]; | |
359 | thread1 = process_diff (commonname, argv[optind + rev_mapping[1]]); | |
360 | thread2 = process_diff (commonname, argv[optind + rev_mapping[2]]); | |
361 | diff = make_3way_diff (thread1, thread2); | |
362 | if (edscript) | |
363 | overlaps_found | |
364 | = output_diff3_edscript (stdout, diff, mapping, rev_mapping, | |
365 | tag_strings[0], argv[optind+1], tag_strings[1]); | |
366 | else if (merge) | |
367 | { | |
368 | if (! freopen (commonname, "r", stdin)) | |
369 | perror_with_exit (commonname); | |
370 | overlaps_found | |
371 | = output_diff3_merge (stdin, stdout, diff, mapping, rev_mapping, | |
372 | tag_strings[0], argv[optind+1], tag_strings[1]); | |
373 | if (ferror (stdin)) | |
374 | fatal ("read error"); | |
375 | } | |
376 | else | |
377 | { | |
378 | output_diff3 (stdout, diff, mapping, rev_mapping); | |
379 | overlaps_found = 0; | |
380 | } | |
381 | ||
382 | if (ferror (stdout) || fflush (stdout) != 0) | |
383 | fatal ("write error"); | |
384 | exit (overlaps_found); | |
385 | } | |
386 | ||
387 | /* | |
388 | * Explain, patiently and kindly, how to use this program. Then exit. | |
389 | */ | |
390 | void | |
391 | usage () | |
392 | { | |
393 | fprintf (stderr, "Usage:\t%s [-exEX3 [-i | -m] [-L label1 -L label3]] file1 file2 file3\n", | |
394 | argv0); | |
395 | fprintf (stderr, "\tOnly one of [exEX3] allowed\n"); | |
396 | exit (2); | |
397 | } | |
398 | \f | |
399 | /* | |
400 | * Routines that combine the two diffs together into one. The | |
401 | * algorithm used follows: | |
402 | * | |
403 | * File0 is shared in common between the two diffs. | |
404 | * Diff01 is the diff between 0 and 1. | |
405 | * Diff02 is the diff between 0 and 2. | |
406 | * | |
407 | * 1) Find the range for the first block in File0. | |
408 | * a) Take the lowest of the two ranges (in File0) in the two | |
409 | * current blocks (one from each diff) as being the low | |
410 | * water mark. Assign the upper end of this block as | |
411 | * being the high water mark and move the current block up | |
412 | * one. Mark the block just moved over as to be used. | |
413 | * b) Check the next block in the diff that the high water | |
414 | * mark is *not* from. | |
415 | * | |
416 | * *If* the high water mark is above | |
417 | * the low end of the range in that block, | |
418 | * | |
419 | * mark that block as to be used and move the current | |
420 | * block up. Set the high water mark to the max of | |
421 | * the high end of this block and the current. Repeat b. | |
422 | * | |
423 | * 2) Find the corresponding ranges in Files1 (from the blocks | |
424 | * in diff01; line per line outside of diffs) and in File2. | |
425 | * Create a diff3_block, reserving space as indicated by the ranges. | |
426 | * | |
427 | * 3) Copy all of the pointers for file0 in. At least for now, | |
428 | * do bcmp's between corresponding strings in the two diffs. | |
429 | * | |
430 | * 4) Copy all of the pointers for file1 and 2 in. Get what you | |
431 | * need from file0 (when there isn't a diff block, it's | |
432 | * identical to file0 within the range between diff blocks). | |
433 | * | |
434 | * 5) If the diff blocks you used came from only one of the two | |
435 | * strings of diffs, then that file (i.e. the one other than | |
436 | * file 0 in that diff) is the odd person out. If you used | |
437 | * diff blocks from both sets, check to see if files 1 and 2 match: | |
438 | * | |
439 | * Same number of lines? If so, do a set of bcmp's (if a | |
440 | * bcmp matches; copy the pointer over; it'll be easier later | |
441 | * if you have to do any compares). If they match, 1 & 2 are | |
442 | * the same. If not, all three different. | |
443 | * | |
444 | * Then you do it again, until you run out of blocks. | |
445 | * | |
446 | */ | |
447 | ||
448 | /* | |
449 | * This routine makes a three way diff (chain of diff3_block's) from two | |
450 | * two way diffs (chains of diff_block's). It is assumed that each of | |
451 | * the two diffs passed are off of the same file (i.e. that each of the | |
452 | * diffs were made "from" the same file). The three way diff pointer | |
453 | * returned will have numbering 0--the common file, 1--the other file | |
454 | * in diff1, and 2--the other file in diff2. | |
455 | */ | |
456 | struct diff3_block * | |
457 | make_3way_diff (thread1, thread2) | |
458 | struct diff_block *thread1, *thread2; | |
459 | { | |
460 | /* | |
461 | * This routine works on the two diffs passed to it as threads. | |
462 | * Thread number 0 is diff1, thread number 1 is diff2. The USING | |
463 | * array is set to the base of the list of blocks to be used to | |
464 | * construct each block of the three way diff; if no blocks from a | |
465 | * particular thread are to be used, that element of the using array | |
466 | * is set to 0. The elements LAST_USING array are set to the last | |
467 | * elements on each of the using lists. | |
468 | * | |
469 | * The HIGH_WATER_MARK is set to the highest line number in File 0 | |
470 | * described in any of the diffs in either of the USING lists. The | |
471 | * HIGH_WATER_THREAD names the thread. Similarly the BASE_WATER_MARK | |
472 | * and BASE_WATER_THREAD describe the lowest line number in File 0 | |
473 | * described in any of the diffs in either of the USING lists. The | |
474 | * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was | |
475 | * taken. | |
476 | * | |
477 | * The HIGH_WATER_DIFF should always be equal to LAST_USING | |
478 | * [HIGH_WATER_THREAD]. The OTHER_DIFF is the next diff to check for | |
479 | * higher water, and should always be equal to | |
480 | * CURRENT[HIGH_WATER_THREAD ^ 0x1]. The OTHER_THREAD is the thread | |
481 | * in which the OTHER_DIFF is, and hence should always be equal to | |
482 | * HIGH_WATER_THREAD ^ 0x1. | |
483 | * | |
484 | * The variable LAST_DIFF is kept set to the last diff block produced | |
485 | * by this routine, for line correspondence purposes between that diff | |
486 | * and the one currently being worked on. It is initialized to | |
487 | * ZERO_DIFF before any blocks have been created. | |
488 | */ | |
489 | ||
490 | struct diff_block | |
491 | *using[2], | |
492 | *last_using[2], | |
493 | *current[2]; | |
494 | ||
495 | int | |
496 | high_water_mark; | |
497 | ||
498 | int | |
499 | high_water_thread, | |
500 | base_water_thread, | |
501 | other_thread; | |
502 | ||
503 | struct diff_block | |
504 | *high_water_diff, | |
505 | *other_diff; | |
506 | ||
507 | struct diff3_block | |
508 | *result, | |
509 | *tmpblock, | |
510 | *result_last, | |
511 | *last_diff; | |
512 | ||
513 | static struct diff3_block zero_diff = { | |
514 | ERROR, | |
515 | { {0, 0}, {0, 0}, {0, 0} }, | |
516 | { (char **) 0, (char **) 0, (char **) 0 }, | |
517 | { (int *) 0, (int *) 0, (int *) 0 }, | |
518 | (struct diff3_block *) 0 | |
519 | }; | |
520 | ||
521 | /* Initialization */ | |
522 | result = result_last = (struct diff3_block *) 0; | |
523 | current[0] = thread1; current[1] = thread2; | |
524 | last_diff = &zero_diff; | |
525 | ||
526 | /* Sniff up the threads until we reach the end */ | |
527 | ||
528 | while (current[0] || current[1]) | |
529 | { | |
530 | using[0] = using[1] = last_using[0] = last_using[1] = | |
531 | (struct diff_block *) 0; | |
532 | ||
533 | /* Setup low and high water threads, diffs, and marks. */ | |
534 | if (!current[0]) | |
535 | base_water_thread = 1; | |
536 | else if (!current[1]) | |
537 | base_water_thread = 0; | |
538 | else | |
539 | base_water_thread = | |
540 | (D_LOWLINE (current[0], FILE0) > D_LOWLINE (current[1], FILE0)); | |
541 | ||
542 | high_water_thread = base_water_thread; | |
543 | ||
544 | high_water_diff = current[high_water_thread]; | |
545 | ||
546 | #if 0 | |
547 | /* low and high waters start off same diff */ | |
548 | base_water_mark = D_LOWLINE (high_water_diff, FILE0); | |
549 | #endif | |
550 | ||
551 | high_water_mark = D_HIGHLINE (high_water_diff, FILE0); | |
552 | ||
553 | /* Make the diff you just got info from into the using class */ | |
554 | using[high_water_thread] | |
555 | = last_using[high_water_thread] | |
556 | = high_water_diff; | |
557 | current[high_water_thread] = high_water_diff->next; | |
558 | last_using[high_water_thread]->next | |
559 | = (struct diff_block *) 0; | |
560 | ||
561 | /* And mark the other diff */ | |
562 | other_thread = high_water_thread ^ 0x1; | |
563 | other_diff = current[other_thread]; | |
564 | ||
565 | /* Shuffle up the ladder, checking the other diff to see if it | |
566 | needs to be incorporated */ | |
567 | while (other_diff | |
568 | && D_LOWLINE (other_diff, FILE0) <= high_water_mark + 1) | |
569 | { | |
570 | ||
571 | /* Incorporate this diff into the using list. Note that | |
572 | this doesn't take it off the current list */ | |
573 | if (using[other_thread]) | |
574 | last_using[other_thread]->next = other_diff; | |
575 | else | |
576 | using[other_thread] = other_diff; | |
577 | last_using[other_thread] = other_diff; | |
578 | ||
579 | /* Take it off the current list. Note that this following | |
580 | code assumes that other_diff enters it equal to | |
581 | current[high_water_thread ^ 0x1] */ | |
582 | current[other_thread] | |
583 | = current[other_thread]->next; | |
584 | other_diff->next | |
585 | = (struct diff_block *) 0; | |
586 | ||
587 | /* Set the high_water stuff | |
588 | If this comparison is equal, then this is the last pass | |
589 | through this loop; since diff blocks within a given | |
590 | thread cannot overlap, the high_water_mark will be | |
591 | *below* the range_start of either of the next diffs. */ | |
592 | ||
593 | if (high_water_mark < D_HIGHLINE (other_diff, FILE0)) | |
594 | { | |
595 | high_water_thread ^= 1; | |
596 | high_water_diff = other_diff; | |
597 | high_water_mark = D_HIGHLINE (other_diff, FILE0); | |
598 | } | |
599 | ||
600 | /* Set the other diff */ | |
601 | other_thread = high_water_thread ^ 0x1; | |
602 | other_diff = current[other_thread]; | |
603 | } | |
604 | ||
605 | /* The using lists contain a list of all of the blocks to be | |
606 | included in this diff3_block. Create it. */ | |
607 | ||
608 | tmpblock = using_to_diff3_block (using, last_using, | |
609 | base_water_thread, high_water_thread, | |
610 | last_diff); | |
611 | ||
612 | if (!tmpblock) | |
613 | fatal ("internal: screwup in format of diff blocks"); | |
614 | ||
615 | /* Put it on the list */ | |
616 | if (result) | |
617 | result_last->next = tmpblock; | |
618 | else | |
619 | result = tmpblock; | |
620 | result_last = tmpblock; | |
621 | ||
622 | /* Setup corresponding lines correctly */ | |
623 | last_diff = tmpblock; | |
624 | } | |
625 | return result; | |
626 | } | |
627 | ||
628 | /* | |
629 | * using_to_diff3_block: | |
630 | * This routine takes two lists of blocks (from two separate diff | |
631 | * threads) and puts them together into one diff3 block. | |
632 | * It then returns a pointer to this diff3 block or 0 for failure. | |
633 | * | |
634 | * All arguments besides using are for the convenience of the routine; | |
635 | * they could be derived from the using array. | |
636 | * LAST_USING is a pair of pointers to the last blocks in the using | |
637 | * structure. | |
638 | * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest | |
639 | * and highest line numbers for File0. | |
640 | * last_diff contains the last diff produced in the calling routine. | |
641 | * This is used for lines mappings which would still be identical to | |
642 | * the state that diff ended in. | |
643 | * | |
644 | * A distinction should be made in this routine between the two diffs | |
645 | * that are part of a normal two diff block, and the three diffs that | |
646 | * are part of a diff3_block. | |
647 | */ | |
648 | struct diff3_block * | |
649 | using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff) | |
650 | struct diff_block | |
651 | *using[2], | |
652 | *last_using[2]; | |
653 | int low_thread, high_thread; | |
654 | struct diff3_block *last_diff; | |
655 | { | |
656 | int lowc, highc, low1, high1, low2, high2; | |
657 | struct diff3_block *result; | |
658 | struct diff_block *ptr; | |
659 | int i; | |
660 | int current0line; | |
661 | ||
662 | /* Find the range in file0 */ | |
663 | lowc = using[low_thread]->ranges[0][START]; | |
664 | highc = last_using[high_thread]->ranges[0][END]; | |
665 | ||
666 | /* Find the ranges in the other files. | |
667 | If using[x] is null, that means that the file to which that diff | |
668 | refers is equivalent to file 0 over this range */ | |
669 | ||
670 | if (using[0]) | |
671 | { | |
672 | low1 = D_LOW_MAPLINE (using[0], FILE0, FILE1, lowc); | |
673 | high1 = D_HIGH_MAPLINE (last_using[0], FILE0, FILE1, highc); | |
674 | } | |
675 | else | |
676 | { | |
677 | low1 = D_HIGH_MAPLINE (last_diff, FILEC, FILE1, lowc); | |
678 | high1 = D_HIGH_MAPLINE (last_diff, FILEC, FILE1, highc); | |
679 | } | |
680 | ||
681 | /* | |
682 | * Note that in the following, we use file 1 relative to the diff, | |
683 | * and file 2 relative to the corresponding lines struct. | |
684 | */ | |
685 | if (using[1]) | |
686 | { | |
687 | low2 = D_LOW_MAPLINE (using[1], FILE0, FILE1, lowc); | |
688 | high2 = D_HIGH_MAPLINE (last_using[1], FILE0, FILE1, highc); | |
689 | } | |
690 | else | |
691 | { | |
692 | low2 = D_HIGH_MAPLINE (last_diff, FILEC, FILE2, lowc); | |
693 | high2 = D_HIGH_MAPLINE (last_diff, FILEC, FILE2, highc); | |
694 | } | |
695 | ||
696 | /* Create a block with the appropriate sizes */ | |
697 | result = create_diff3_block (lowc, highc, low1, high1, low2, high2); | |
698 | ||
699 | /* Copy over all of the information for File 0. Return with a zero | |
700 | if any of the compares failed. */ | |
701 | for (ptr = using[0]; ptr; ptr = D_NEXT (ptr)) | |
702 | { | |
703 | int result_offset = D_LOWLINE (ptr, FILE0) - lowc; | |
704 | int copy_size | |
705 | = D_HIGHLINE (ptr, FILE0) - D_LOWLINE (ptr, FILE0) + 1; | |
706 | ||
707 | if (!copy_stringlist (D_LINEARRAY (ptr, FILE0), | |
708 | D_LENARRAY (ptr, FILE0), | |
709 | D_LINEARRAY (result, FILEC) + result_offset, | |
710 | D_LENARRAY (result, FILEC) + result_offset, | |
711 | copy_size)) | |
712 | return 0; | |
713 | } | |
714 | ||
715 | for (ptr = using[1]; ptr; ptr = D_NEXT (ptr)) | |
716 | { | |
717 | int result_offset = D_LOWLINE (ptr, FILEC) - lowc; | |
718 | int copy_size | |
719 | = D_HIGHLINE (ptr, FILEC) - D_LOWLINE (ptr, FILEC) + 1; | |
720 | ||
721 | if (!copy_stringlist (D_LINEARRAY (ptr, FILE0), | |
722 | D_LENARRAY (ptr, FILE0), | |
723 | D_LINEARRAY (result, FILEC) + result_offset, | |
724 | D_LENARRAY (result, FILEC) + result_offset, | |
725 | copy_size)) | |
726 | return 0; | |
727 | } | |
728 | ||
729 | /* Copy stuff for file 1. First deal with anything that might be | |
730 | before the first diff. */ | |
731 | ||
732 | for (i = 0; | |
733 | i + low1 < (using[0] ? D_LOWLINE (using[0], FILE1) : high1 + 1); | |
734 | i++) | |
735 | { | |
736 | D_RELNUM (result, FILE1, i) = D_RELNUM (result, FILEC, i); | |
737 | D_RELLEN (result, FILE1, i) = D_RELLEN (result, FILEC, i); | |
738 | } | |
739 | ||
740 | for (ptr = using[0]; ptr; ptr = D_NEXT (ptr)) | |
741 | { | |
742 | int result_offset = D_LOWLINE (ptr, FILE1) - low1; | |
743 | int copy_size | |
744 | = D_HIGHLINE (ptr, FILE1) - D_LOWLINE (ptr, FILE1) + 1; | |
745 | ||
746 | if (!copy_stringlist (D_LINEARRAY (ptr, FILE1), | |
747 | D_LENARRAY (ptr, FILE1), | |
748 | D_LINEARRAY (result, FILE1) + result_offset, | |
749 | D_LENARRAY (result, FILE1) + result_offset, | |
750 | copy_size)) | |
751 | return 0; | |
752 | ||
753 | /* Catch the lines between here and the next diff */ | |
754 | current0line = D_HIGHLINE (ptr, FILE0) + 1 - lowc; | |
755 | for (i = D_HIGHLINE (ptr, FILE1) + 1 - low1; | |
756 | i < (D_NEXT (ptr) ? | |
757 | D_LOWLINE (D_NEXT (ptr), FILE1) : | |
758 | high1 + 1) - low1; | |
759 | i++) | |
760 | { | |
761 | D_RELNUM (result, FILE1, i) | |
762 | = D_RELNUM (result, FILEC, current0line); | |
763 | D_RELLEN (result, FILE1, i) | |
764 | = D_RELLEN (result, FILEC, current0line++); | |
765 | } | |
766 | } | |
767 | ||
768 | /* Copy stuff for file 2. First deal with anything that might be | |
769 | before the first diff. */ | |
770 | ||
771 | for (i = 0; | |
772 | i + low2 < (using[1] ? D_LOWLINE (using[1], FILE1) : high2 + 1); | |
773 | i++) | |
774 | { | |
775 | D_RELNUM (result, FILE2, i) = D_RELNUM (result, FILEC, i); | |
776 | D_RELLEN (result, FILE2, i) = D_RELLEN (result, FILEC, i); | |
777 | } | |
778 | ||
779 | for (ptr = using[1]; ptr; ptr = D_NEXT (ptr)) | |
780 | { | |
781 | int result_offset = D_LOWLINE (ptr, FILE1) - low2; | |
782 | int copy_size | |
783 | = D_HIGHLINE (ptr, FILE1) - D_LOWLINE (ptr, FILE1) + 1; | |
784 | ||
785 | if (!copy_stringlist (D_LINEARRAY (ptr, FILE1), | |
786 | D_LENARRAY (ptr, FILE1), | |
787 | D_LINEARRAY (result, FILE2) + result_offset, | |
788 | D_LENARRAY (result, FILE2) + result_offset, | |
789 | copy_size)) | |
790 | return 0; | |
791 | ||
792 | /* Catch the lines between here and the next diff */ | |
793 | current0line = D_HIGHLINE (ptr, FILE0) + 1 - lowc; | |
794 | for (i = D_HIGHLINE (ptr, FILE1) + 1 - low2; | |
795 | i < (D_NEXT (ptr) ? | |
796 | D_LOWLINE (D_NEXT (ptr), FILE1) : | |
797 | high2 + 1) - low2; | |
798 | i++) | |
799 | { | |
800 | D_RELNUM (result, FILE2, i) | |
801 | = D_RELNUM (result, FILEC, current0line); | |
802 | D_RELLEN (result, FILE2, i) | |
803 | = D_RELLEN (result, FILEC, current0line++); | |
804 | } | |
805 | } | |
806 | ||
807 | /* Set correspond */ | |
808 | if (!using[0]) | |
809 | D3_TYPE (result) = DIFF_3RD; | |
810 | else if (!using[1]) | |
811 | D3_TYPE (result) = DIFF_2ND; | |
812 | else | |
813 | { | |
814 | int nl1 | |
815 | = D_HIGHLINE (result, FILE1) - D_LOWLINE (result, FILE1) + 1; | |
816 | int nl2 | |
817 | = D_HIGHLINE (result, FILE2) - D_LOWLINE (result, FILE2) + 1; | |
818 | ||
819 | if (nl1 != nl2 | |
820 | || !compare_line_list (D_LINEARRAY (result, FILE1), | |
821 | D_LENARRAY (result, FILE1), | |
822 | D_LINEARRAY (result, FILE2), | |
823 | D_LENARRAY (result, FILE2), | |
824 | nl1)) | |
825 | D3_TYPE (result) = DIFF_ALL; | |
826 | else | |
827 | D3_TYPE (result) = DIFF_1ST; | |
828 | } | |
829 | ||
830 | return result; | |
831 | } | |
832 | ||
833 | /* | |
834 | * This routine copies pointers from a list of strings to a different list | |
835 | * of strings. If a spot in the second list is already filled, it | |
836 | * makes sure that it is filled with the same string; if not it | |
837 | * returns 0, the copy incomplete. | |
838 | * Upon successful completion of the copy, it returns 1. | |
839 | */ | |
840 | int | |
841 | copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum) | |
842 | char *fromptrs[], *toptrs[]; | |
843 | int *fromlengths, *tolengths; | |
844 | int copynum; | |
845 | { | |
846 | register char | |
847 | **f = fromptrs, | |
848 | **t = toptrs; | |
849 | register int | |
850 | *fl = fromlengths, | |
851 | *tl = tolengths; | |
852 | ||
853 | while (copynum--) | |
854 | { | |
855 | if (*t) | |
856 | { if (*fl != *tl || bcmp (*f, *t, *fl)) return 0; } | |
857 | else | |
858 | { *t = *f ; *tl = *fl; } | |
859 | ||
860 | t++; f++; tl++; fl++; | |
861 | } | |
862 | return 1; | |
863 | } | |
864 | ||
865 | /* | |
866 | * Create a diff3_block, with ranges as specified in the arguments. | |
867 | * Allocate the arrays for the various pointers (and zero them) based | |
868 | * on the arguments passed. Return the block as a result. | |
869 | */ | |
870 | struct diff3_block * | |
871 | create_diff3_block (low0, high0, low1, high1, low2, high2) | |
872 | register int low0, high0, low1, high1, low2, high2; | |
873 | { | |
874 | struct diff3_block *result = ALLOCATE (1, struct diff3_block); | |
875 | int numlines; | |
876 | ||
877 | D3_TYPE (result) = ERROR; | |
878 | D_NEXT (result) = 0; | |
879 | ||
880 | /* Assign ranges */ | |
881 | D_LOWLINE (result, FILE0) = low0; | |
882 | D_HIGHLINE (result, FILE0) = high0; | |
883 | D_LOWLINE (result, FILE1) = low1; | |
884 | D_HIGHLINE (result, FILE1) = high1; | |
885 | D_LOWLINE (result, FILE2) = low2; | |
886 | D_HIGHLINE (result, FILE2) = high2; | |
887 | ||
888 | /* Allocate and zero space */ | |
889 | numlines = D_NUMLINES (result, FILE0); | |
890 | if (numlines) | |
891 | { | |
892 | D_LINEARRAY (result, FILE0) = ALLOCATE (numlines, char *); | |
893 | D_LENARRAY (result, FILE0) = ALLOCATE (numlines, int); | |
894 | bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *))); | |
895 | bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (int))); | |
896 | } | |
897 | else | |
898 | { | |
899 | D_LINEARRAY (result, FILE0) = (char **) 0; | |
900 | D_LENARRAY (result, FILE0) = (int *) 0; | |
901 | } | |
902 | ||
903 | numlines = D_NUMLINES (result, FILE1); | |
904 | if (numlines) | |
905 | { | |
906 | D_LINEARRAY (result, FILE1) = ALLOCATE (numlines, char *); | |
907 | D_LENARRAY (result, FILE1) = ALLOCATE (numlines, int); | |
908 | bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *))); | |
909 | bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (int))); | |
910 | } | |
911 | else | |
912 | { | |
913 | D_LINEARRAY (result, FILE1) = (char **) 0; | |
914 | D_LENARRAY (result, FILE1) = (int *) 0; | |
915 | } | |
916 | ||
917 | numlines = D_NUMLINES (result, FILE2); | |
918 | if (numlines) | |
919 | { | |
920 | D_LINEARRAY (result, FILE2) = ALLOCATE (numlines, char *); | |
921 | D_LENARRAY (result, FILE2) = ALLOCATE (numlines, int); | |
922 | bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *))); | |
923 | bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (int))); | |
924 | } | |
925 | else | |
926 | { | |
927 | D_LINEARRAY (result, FILE2) = (char **) 0; | |
928 | D_LENARRAY (result, FILE2) = (int *) 0; | |
929 | } | |
930 | ||
931 | /* Return */ | |
932 | return result; | |
933 | } | |
934 | ||
935 | /* | |
936 | * Compare two lists of lines of text. | |
937 | * Return 1 if they are equivalent, 0 if not. | |
938 | */ | |
939 | int | |
940 | compare_line_list (list1, lengths1, list2, lengths2, nl) | |
941 | char *list1[], *list2[]; | |
942 | int *lengths1, *lengths2; | |
943 | int nl; | |
944 | { | |
945 | char | |
946 | **l1 = list1, | |
947 | **l2 = list2; | |
948 | int | |
949 | *lgths1 = lengths1, | |
950 | *lgths2 = lengths2; | |
951 | ||
952 | while (nl--) | |
953 | if (!*l1 || !*l2 || *lgths1 != *lgths2++ | |
954 | || bcmp (*l1++, *l2++, *lgths1++)) | |
955 | return 0; | |
956 | return 1; | |
957 | } | |
958 | \f | |
959 | /* | |
960 | * Routines to input and parse two way diffs. | |
961 | */ | |
962 | ||
963 | extern char **environ; | |
964 | ||
965 | #define DIFF_CHUNK_SIZE 10000 | |
966 | ||
967 | struct diff_block * | |
968 | process_diff (filea, fileb) | |
969 | char *filea, *fileb; | |
970 | { | |
971 | char *diff_contents; | |
972 | char *diff_limit; | |
973 | char *scan_diff; | |
974 | enum diff_type dt; | |
975 | int i; | |
976 | struct diff_block *block_list, *block_list_end, *bptr; | |
977 | ||
978 | diff_limit = read_diff (filea, fileb, &diff_contents); | |
979 | scan_diff = diff_contents; | |
980 | bptr = block_list_end = block_list = (struct diff_block *) 0; | |
981 | ||
982 | while (scan_diff < diff_limit) | |
983 | { | |
984 | bptr = ALLOCATE (1, struct diff_block); | |
985 | bptr->next = 0; | |
986 | bptr->lines[0] = bptr->lines[1] = (char **) 0; | |
987 | bptr->lengths[0] = bptr->lengths[1] = (int *) 0; | |
988 | ||
989 | dt = process_diff_control (&scan_diff, bptr); | |
990 | if (dt == ERROR || *scan_diff != '\n') | |
991 | { | |
992 | fprintf (stderr, "%s: diff error: ", argv0); | |
993 | do | |
994 | { | |
995 | putc (*scan_diff, stderr); | |
996 | } | |
997 | while (*scan_diff++ != '\n'); | |
998 | exit (2); | |
999 | } | |
1000 | scan_diff++; | |
1001 | ||
1002 | /* Force appropriate ranges to be null, if necessary */ | |
1003 | switch (dt) | |
1004 | { | |
1005 | case ADD: | |
1006 | bptr->ranges[0][0]++; | |
1007 | break; | |
1008 | case DELETE: | |
1009 | bptr->ranges[1][0]++; | |
1010 | break; | |
1011 | case CHANGE: | |
1012 | break; | |
1013 | default: | |
1014 | fatal ("internal: Bad diff type in process_diff"); | |
1015 | break; | |
1016 | } | |
1017 | ||
1018 | /* Allocate space for the pointers for the lines from filea, and | |
1019 | parcel them out among these pointers */ | |
1020 | if (dt != ADD) | |
1021 | { | |
1022 | bptr->lines[0] = ALLOCATE ((bptr->ranges[0][END] | |
1023 | - bptr->ranges[0][START] + 1), | |
1024 | char *); | |
1025 | bptr->lengths[0] = ALLOCATE ((bptr->ranges[0][END] | |
1026 | - bptr->ranges[0][START] + 1), | |
1027 | int); | |
1028 | for (i = 0; i <= (bptr->ranges[0][END] | |
1029 | - bptr->ranges[0][START]); i++) | |
1030 | scan_diff = scan_diff_line (scan_diff, | |
1031 | &(bptr->lines[0][i]), | |
1032 | &(bptr->lengths[0][i]), | |
1033 | diff_limit, | |
1034 | '<'); | |
1035 | } | |
1036 | ||
1037 | /* Get past the separator for changes */ | |
1038 | if (dt == CHANGE) | |
1039 | { | |
1040 | if (strncmp (scan_diff, "---\n", 4)) | |
1041 | fatal ("Bad diff format: bad change separator"); | |
1042 | scan_diff += 4; | |
1043 | } | |
1044 | ||
1045 | /* Allocate space for the pointers for the lines from fileb, and | |
1046 | parcel them out among these pointers */ | |
1047 | if (dt != DELETE) | |
1048 | { | |
1049 | bptr->lines[1] = ALLOCATE ((bptr->ranges[1][END] | |
1050 | - bptr->ranges[1][START] + 1), | |
1051 | char *); | |
1052 | bptr->lengths[1] = ALLOCATE ((bptr->ranges[1][END] | |
1053 | - bptr->ranges[1][START] + 1), | |
1054 | int); | |
1055 | for (i = 0; i <= (bptr->ranges[1][END] | |
1056 | - bptr->ranges[1][START]); i++) | |
1057 | scan_diff = scan_diff_line (scan_diff, | |
1058 | &(bptr->lines[1][i]), | |
1059 | &(bptr->lengths[1][i]), | |
1060 | diff_limit, | |
1061 | '>'); | |
1062 | } | |
1063 | ||
1064 | /* Place this block on the blocklist */ | |
1065 | if (block_list_end) | |
1066 | block_list_end->next = bptr; | |
1067 | else | |
1068 | block_list = bptr; | |
1069 | ||
1070 | block_list_end = bptr; | |
1071 | ||
1072 | } | |
1073 | ||
1074 | return block_list; | |
1075 | } | |
1076 | ||
1077 | /* | |
1078 | * This routine will parse a normal format diff control string. It | |
1079 | * returns the type of the diff (ERROR if the format is bad). All of | |
1080 | * the other important information is filled into to the structure | |
1081 | * pointed to by db, and the string pointer (whose location is passed | |
1082 | * to this routine) is updated to point beyond the end of the string | |
1083 | * parsed. Note that only the ranges in the diff_block will be set by | |
1084 | * this routine. | |
1085 | * | |
1086 | * If some specific pair of numbers has been reduced to a single | |
1087 | * number, then both corresponding numbers in the diff block are set | |
1088 | * to that number. In general these numbers are interpetted as ranges | |
1089 | * inclusive, unless being used by the ADD or DELETE commands. It is | |
1090 | * assumed that these will be special cased in a superior routine. | |
1091 | */ | |
1092 | ||
1093 | enum diff_type | |
1094 | process_diff_control (string, db) | |
1095 | char **string; | |
1096 | struct diff_block *db; | |
1097 | { | |
1098 | char *s = *string; | |
1099 | int holdnum; | |
1100 | enum diff_type type; | |
1101 | ||
1102 | /* These macros are defined here because they can use variables | |
1103 | defined in this function. Don't try this at home kids, we're | |
1104 | trained professionals! | |
1105 | ||
1106 | Also note that SKIPWHITE only recognizes tabs and spaces, and | |
1107 | that READNUM can only read positive, integral numbers */ | |
1108 | ||
1109 | #define SKIPWHITE(s) { while (*s == ' ' || *s == '\t') s++; } | |
1110 | #define READNUM(s, num) \ | |
1111 | { if (!isdigit (*s)) return ERROR; holdnum = 0; \ | |
1112 | do { holdnum = (*s++ - '0' + holdnum * 10); } \ | |
1113 | while (isdigit (*s)); (num) = holdnum; } | |
1114 | ||
1115 | /* Read first set of digits */ | |
1116 | SKIPWHITE (s); | |
1117 | READNUM (s, db->ranges[0][START]); | |
1118 | ||
1119 | /* Was that the only digit? */ | |
1120 | SKIPWHITE(s); | |
1121 | if (*s == ',') | |
1122 | { | |
1123 | /* Get the next digit */ | |
1124 | s++; | |
1125 | READNUM (s, db->ranges[0][END]); | |
1126 | } | |
1127 | else | |
1128 | db->ranges[0][END] = db->ranges[0][START]; | |
1129 | ||
1130 | /* Get the letter */ | |
1131 | SKIPWHITE (s); | |
1132 | switch (*s) | |
1133 | { | |
1134 | case 'a': | |
1135 | type = ADD; | |
1136 | break; | |
1137 | case 'c': | |
1138 | type = CHANGE; | |
1139 | break; | |
1140 | case 'd': | |
1141 | type = DELETE; | |
1142 | break; | |
1143 | default: | |
1144 | return ERROR; /* Bad format */ | |
1145 | } | |
1146 | s++; /* Past letter */ | |
1147 | ||
1148 | /* Read second set of digits */ | |
1149 | SKIPWHITE (s); | |
1150 | READNUM (s, db->ranges[1][START]); | |
1151 | ||
1152 | /* Was that the only digit? */ | |
1153 | SKIPWHITE(s); | |
1154 | if (*s == ',') | |
1155 | { | |
1156 | /* Get the next digit */ | |
1157 | s++; | |
1158 | READNUM (s, db->ranges[1][END]); | |
1159 | SKIPWHITE (s); /* To move to end */ | |
1160 | } | |
1161 | else | |
1162 | db->ranges[1][END] = db->ranges[1][START]; | |
1163 | ||
1164 | *string = s; | |
1165 | return type; | |
1166 | } | |
1167 | ||
1168 | char * | |
1169 | read_diff (filea, fileb, output_placement) | |
1170 | char *filea, *fileb; | |
1171 | char **output_placement; | |
1172 | { | |
1173 | char *argv[6]; | |
1174 | char **ap; | |
1175 | int fds[2]; | |
1176 | char *diff_result; | |
1177 | int current_chunk_size; | |
1178 | int bytes; | |
1179 | int total; | |
1180 | int pid, w; | |
1181 | int wstatus; | |
1182 | ||
1183 | ap = argv; | |
1184 | *ap++ = diff_program; | |
1185 | if (always_text) | |
1186 | *ap++ = "-a"; | |
1187 | *ap++ = "--"; | |
1188 | *ap++ = filea; | |
1189 | *ap++ = fileb; | |
1190 | *ap = (char *) 0; | |
1191 | ||
1192 | if (pipe (fds) < 0) | |
1193 | perror_with_exit ("Pipe failed"); | |
1194 | ||
1195 | pid = vfork (); | |
1196 | if (pid == 0) | |
1197 | { | |
1198 | /* Child */ | |
1199 | close (fds[0]); | |
1200 | if (fds[1] != fileno (stdout)) | |
1201 | { | |
1202 | dup2 (fds[1], fileno (stdout)); | |
1203 | close (fds[1]); | |
1204 | } | |
1205 | execve (diff_program, argv, environ); | |
1206 | /* Avoid stdio, because the parent process's buffers are inherited. */ | |
1207 | write (fileno (stderr), diff_program, strlen (diff_program)); | |
1208 | write (fileno (stderr), ": not found\n", 12); | |
1209 | _exit (2); | |
1210 | } | |
1211 | ||
1212 | if (pid == -1) | |
1213 | perror_with_exit ("Fork failed"); | |
1214 | ||
1215 | close (fds[1]); /* Prevent erroneous lack of EOF */ | |
1216 | current_chunk_size = DIFF_CHUNK_SIZE; | |
1217 | diff_result = (char *) xmalloc (current_chunk_size); | |
1218 | total = 0; | |
1219 | do { | |
1220 | bytes = myread (fds[0], | |
1221 | diff_result + total, | |
1222 | current_chunk_size - total); | |
1223 | total += bytes; | |
1224 | if (total == current_chunk_size) | |
1225 | diff_result = (char *) xrealloc (diff_result, (current_chunk_size *= 2)); | |
1226 | } while (bytes); | |
1227 | ||
1228 | if (total != 0 && diff_result[total-1] != '\n') | |
1229 | fatal ("bad diff format; incomplete last line"); | |
1230 | ||
1231 | *output_placement = diff_result; | |
1232 | ||
1233 | do | |
1234 | if ((w = wait (&wstatus)) == -1) | |
1235 | perror_with_exit ("Wait failed"); | |
1236 | while (w != pid); | |
1237 | ||
1238 | if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2)) | |
1239 | fatal ("Subsidiary diff failed"); | |
1240 | ||
1241 | return diff_result + total; | |
1242 | } | |
1243 | ||
1244 | ||
1245 | /* | |
1246 | * Scan a regular diff line (consisting of > or <, followed by a | |
1247 | * space, followed by text (including nulls) up to a newline. | |
1248 | * | |
1249 | * This next routine began life as a macro and many parameters in it | |
1250 | * are used as call-by-reference values. | |
1251 | */ | |
1252 | char * | |
1253 | scan_diff_line (scan_ptr, set_start, set_length, limit, firstchar) | |
1254 | char *scan_ptr, **set_start; | |
1255 | int *set_length; | |
1256 | char *limit; | |
1257 | char firstchar; | |
1258 | { | |
1259 | char *line_ptr; | |
1260 | ||
1261 | if (!(scan_ptr[0] == (firstchar) | |
1262 | && scan_ptr[1] == ' ')) | |
1263 | fatal ("Bad diff format; incorrect leading line chars"); | |
1264 | ||
1265 | *set_start = line_ptr = scan_ptr + 2; | |
1266 | while (*line_ptr++ != '\n') | |
1267 | ; | |
1268 | ||
1269 | /* Include newline if the original line ended in a newline, | |
1270 | or if an edit script is being generated. | |
1271 | Copy any missing newline message to stderr if an edit script is being | |
1272 | generated, because edit scripts cannot handle missing newlines. | |
1273 | Return the beginning of the next line. */ | |
1274 | *set_length = line_ptr - *set_start; | |
1275 | if (line_ptr < limit && *line_ptr == '\\') | |
1276 | { | |
1277 | if (edscript) | |
1278 | fprintf (stderr, "%s:", argv0); | |
1279 | else | |
1280 | --*set_length; | |
1281 | line_ptr++; | |
1282 | do | |
1283 | { | |
1284 | if (edscript) | |
1285 | putc (*line_ptr, stderr); | |
1286 | } | |
1287 | while (*line_ptr++ != '\n'); | |
1288 | } | |
1289 | ||
1290 | return line_ptr; | |
1291 | } | |
1292 | ||
1293 | /* | |
1294 | * This routine outputs a three way diff passed as a list of | |
1295 | * diff3_block's. | |
1296 | * The argument MAPPING is indexed by external file number (in the | |
1297 | * argument list) and contains the internal file number (from the | |
1298 | * diff passed). This is important because the user expects his | |
1299 | * outputs in terms of the argument list number, and the diff passed | |
1300 | * may have been done slightly differently (if the first argument in | |
1301 | * the argument list was the standard input, for example). | |
1302 | * REV_MAPPING is the inverse of MAPPING. | |
1303 | */ | |
1304 | void | |
1305 | output_diff3 (outputfile, diff, mapping, rev_mapping) | |
1306 | FILE *outputfile; | |
1307 | struct diff3_block *diff; | |
1308 | int mapping[3], rev_mapping[3]; | |
1309 | { | |
1310 | int i; | |
1311 | int oddoneout; | |
1312 | char *cp; | |
1313 | struct diff3_block *ptr; | |
1314 | int line; | |
1315 | int length; | |
1316 | int dontprint; | |
1317 | static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */ | |
1318 | ||
1319 | for (ptr = diff; ptr; ptr = D_NEXT (ptr)) | |
1320 | { | |
1321 | char x[2]; | |
1322 | ||
1323 | switch (ptr->correspond) | |
1324 | { | |
1325 | case DIFF_ALL: | |
1326 | x[0] = '\0'; | |
1327 | dontprint = 3; /* Print them all */ | |
1328 | oddoneout = 3; /* Nobody's odder than anyone else */ | |
1329 | break; | |
1330 | case DIFF_1ST: | |
1331 | case DIFF_2ND: | |
1332 | case DIFF_3RD: | |
1333 | oddoneout = rev_mapping[(int) ptr->correspond - (int) DIFF_1ST]; | |
1334 | ||
1335 | x[0] = oddoneout + '1'; | |
1336 | x[1] = '\0'; | |
1337 | dontprint = oddoneout==0; | |
1338 | break; | |
1339 | default: | |
1340 | fatal ("internal: Bad diff type passed to output"); | |
1341 | } | |
1342 | fprintf (outputfile, "====%s\n", x); | |
1343 | ||
1344 | /* Go 0, 2, 1 if the first and third outputs are equivalent. */ | |
1345 | for (i = 0; i < 3; | |
1346 | i = (oddoneout == 1 ? skew_increment[i] : i + 1)) | |
1347 | { | |
1348 | int realfile = mapping[i]; | |
1349 | int | |
1350 | lowt = D_LOWLINE (ptr, realfile), | |
1351 | hight = D_HIGHLINE (ptr, realfile); | |
1352 | ||
1353 | fprintf (outputfile, "%d:", i + 1); | |
1354 | switch (lowt - hight) | |
1355 | { | |
1356 | case 1: | |
1357 | fprintf (outputfile, "%da\n", lowt - 1); | |
1358 | break; | |
1359 | case 0: | |
1360 | fprintf (outputfile, "%dc\n", lowt); | |
1361 | break; | |
1362 | default: | |
1363 | fprintf (outputfile, "%d,%dc\n", lowt, hight); | |
1364 | break; | |
1365 | } | |
1366 | ||
1367 | if (i == dontprint) continue; | |
1368 | ||
1369 | for (line = 0; line < hight - lowt + 1; line++) | |
1370 | { | |
1371 | fprintf (outputfile, " "); | |
1372 | cp = D_RELNUM (ptr, realfile, line); | |
1373 | length = D_RELLEN (ptr, realfile, line); | |
1374 | fwrite (cp, sizeof (char), length, outputfile); | |
1375 | } | |
1376 | if (line != 0 && cp[length - 1] != '\n') | |
1377 | fprintf (outputfile, "\n\\ No newline at end of file\n"); | |
1378 | } | |
1379 | } | |
1380 | } | |
1381 | ||
1382 | /* | |
1383 | * This routine outputs a diff3 set of blocks as an ed script. This | |
1384 | * script applies the changes between file's 2 & 3 to file 1. It | |
1385 | * takes the precise format of the ed script to be output from global | |
1386 | * variables set during options processing. Note that it does | |
1387 | * destructive things to the set of diff3 blocks it is passed; it | |
1388 | * reverses their order (this gets around the problems involved with | |
1389 | * changing line numbers in an ed script). | |
1390 | * | |
1391 | * Note that this routine has the same problem of mapping as the last | |
1392 | * one did; the variable MAPPING maps from file number according to | |
1393 | * the argument list to file number according to the diff passed. All | |
1394 | * files listed below are in terms of the argument list. | |
1395 | * REV_MAPPING is the inverse of MAPPING. | |
1396 | * | |
1397 | * The arguments FILE0, FILE1 and FILE2 are the strings to print | |
1398 | * as the names of the three files. These may be the actual names, | |
1399 | * or may be the arguments specified with -L. | |
1400 | * | |
1401 | * Returns 1 if overlaps were found. | |
1402 | */ | |
1403 | ||
1404 | int | |
1405 | output_diff3_edscript (outputfile, diff, mapping, rev_mapping, | |
1406 | file0, file1, file2) | |
1407 | FILE *outputfile; | |
1408 | struct diff3_block *diff; | |
1409 | int mapping[3], rev_mapping[3]; | |
1410 | char *file0, *file1, *file2; | |
1411 | { | |
1412 | int i; | |
1413 | int leading_dot; | |
1414 | int overlaps_found = 0; | |
1415 | struct diff3_block *newblock, *thisblock; | |
1416 | ||
1417 | leading_dot = 0; | |
1418 | ||
1419 | newblock = reverse_diff3_blocklist (diff); | |
1420 | ||
1421 | for (thisblock = newblock; thisblock; thisblock = thisblock->next) | |
1422 | { | |
1423 | /* Must do mapping correctly. */ | |
1424 | enum diff_type type | |
1425 | = ((thisblock->correspond == DIFF_ALL) ? | |
1426 | DIFF_ALL : | |
1427 | ((enum diff_type) | |
1428 | (((int) DIFF_1ST) | |
1429 | + rev_mapping[(int) thisblock->correspond - (int) DIFF_1ST]))); | |
1430 | ||
1431 | /* If we aren't supposed to do this output block, skip it */ | |
1432 | if (type == DIFF_2ND || type == DIFF_1ST | |
1433 | || (type == DIFF_3RD && dont_write_simple) | |
1434 | || (type == DIFF_ALL && dont_write_overlap)) | |
1435 | continue; | |
1436 | ||
1437 | if (flagging && type == DIFF_ALL) | |
1438 | /* Do special flagging */ | |
1439 | { | |
1440 | ||
1441 | /* Put in lines from FILE2 with bracket */ | |
1442 | fprintf (outputfile, "%da\n", | |
1443 | D_HIGHLINE (thisblock, mapping[FILE0])); | |
1444 | fprintf (outputfile, "=======\n"); | |
1445 | for (i = 0; | |
1446 | i < D_NUMLINES (thisblock, mapping[FILE2]); | |
1447 | i++) | |
1448 | { | |
1449 | if (D_RELNUM (thisblock, mapping[FILE2], i)[0] == '.') | |
1450 | { leading_dot = 1; fprintf(outputfile, "."); } | |
1451 | fwrite (D_RELNUM (thisblock, mapping[FILE2], i), sizeof (char), | |
1452 | D_RELLEN (thisblock, mapping[FILE2], i), outputfile); | |
1453 | } | |
1454 | fprintf (outputfile, ">>>>>>> %s\n.\n", file2); | |
1455 | overlaps_found = 1; | |
1456 | ||
1457 | /* Add in code to take care of leading dots, if necessary. */ | |
1458 | if (leading_dot) | |
1459 | { | |
1460 | fprintf (outputfile, "%d,%ds/^\\.\\./\\./\n", | |
1461 | D_HIGHLINE (thisblock, mapping[FILE0]) + 1, | |
1462 | (D_HIGHLINE (thisblock, mapping[FILE0]) | |
1463 | + D_NUMLINES (thisblock, mapping[FILE2]))); | |
1464 | leading_dot = 0; | |
1465 | } | |
1466 | ||
1467 | /* Put in code to do initial bracket of lines from FILE0 */ | |
1468 | fprintf (outputfile, "%da\n<<<<<<< %s\n.\n", | |
1469 | D_LOWLINE (thisblock, mapping[FILE0]) - 1, | |
1470 | file0); | |
1471 | } | |
1472 | else if (D_NUMLINES (thisblock, mapping[FILE2]) == 0) | |
1473 | /* Write out a delete */ | |
1474 | { | |
1475 | if (D_NUMLINES (thisblock, mapping[FILE0]) == 1) | |
1476 | fprintf (outputfile, "%dd\n", | |
1477 | D_LOWLINE (thisblock, mapping[FILE0])); | |
1478 | else | |
1479 | fprintf (outputfile, "%d,%dd\n", | |
1480 | D_LOWLINE (thisblock, mapping[FILE0]), | |
1481 | D_HIGHLINE (thisblock, mapping[FILE0])); | |
1482 | } | |
1483 | else | |
1484 | /* Write out an add or change */ | |
1485 | { | |
1486 | switch (D_NUMLINES (thisblock, mapping[FILE0])) | |
1487 | { | |
1488 | case 0: | |
1489 | fprintf (outputfile, "%da\n", | |
1490 | D_HIGHLINE (thisblock, mapping[FILE0])); | |
1491 | break; | |
1492 | case 1: | |
1493 | fprintf (outputfile, "%dc\n", | |
1494 | D_HIGHLINE (thisblock, mapping[FILE0])); | |
1495 | break; | |
1496 | default: | |
1497 | fprintf (outputfile, "%d,%dc\n", | |
1498 | D_LOWLINE (thisblock, mapping[FILE0]), | |
1499 | D_HIGHLINE (thisblock, mapping[FILE0])); | |
1500 | break; | |
1501 | } | |
1502 | for (i = 0; | |
1503 | i < D_NUMLINES (thisblock, mapping[FILE2]); | |
1504 | i++) | |
1505 | { | |
1506 | if (D_RELNUM (thisblock, mapping[FILE2], i)[0] == '.') | |
1507 | { leading_dot = 1; fprintf (outputfile, "."); } | |
1508 | fwrite (D_RELNUM (thisblock, mapping[FILE2], i), sizeof (char), | |
1509 | D_RELLEN (thisblock, mapping[FILE2], i), outputfile); | |
1510 | } | |
1511 | fprintf (outputfile, ".\n"); | |
1512 | ||
1513 | /* Add in code to take care of leading dots, if necessary. */ | |
1514 | if (leading_dot) | |
1515 | { | |
1516 | fprintf (outputfile, "%d,%ds/^\\.\\./\\./\n", | |
1517 | D_HIGHLINE (thisblock, mapping[FILE0]) + 1, | |
1518 | (D_HIGHLINE (thisblock, mapping[FILE0]) | |
1519 | + D_NUMLINES (thisblock, mapping[FILE2]))); | |
1520 | leading_dot = 0; | |
1521 | } | |
1522 | } | |
1523 | } | |
1524 | if (finalwrite) fprintf (outputfile, "w\nq\n"); | |
1525 | return overlaps_found; | |
1526 | } | |
1527 | ||
1528 | /* | |
1529 | * Read from COMMONFILE and output to OUTPUTFILE a set of diff3_ blocks DIFF | |
1530 | * as a merged file. This acts like 'ed file0 <[output_diff3_edscript]', | |
1531 | * except that it works even for binary data or incomplete lines. | |
1532 | * | |
1533 | * As before, MAPPING maps from arg list file number to diff file number, | |
1534 | * REV_MAPPING is its inverse, | |
1535 | * and FILE0, FILE1, and FILE2 are the names of the files. | |
1536 | * | |
1537 | * Returns 1 if overlaps were found. | |
1538 | */ | |
1539 | ||
1540 | int | |
1541 | output_diff3_merge (commonfile, outputfile, diff, mapping, rev_mapping, | |
1542 | file0, file1, file2) | |
1543 | FILE *commonfile, *outputfile; | |
1544 | struct diff3_block *diff; | |
1545 | int mapping[3], rev_mapping[3]; | |
1546 | char *file0, *file1, *file2; | |
1547 | { | |
1548 | int c, i; | |
1549 | int overlaps_found = 0; | |
1550 | struct diff3_block *b; | |
1551 | int linesread = 0; | |
1552 | ||
1553 | for (b = diff; b; b = b->next) | |
1554 | { | |
1555 | /* Must do mapping correctly */ | |
1556 | enum diff_type type | |
1557 | = ((b->correspond == DIFF_ALL) ? | |
1558 | DIFF_ALL : | |
1559 | ((enum diff_type) | |
1560 | (((int) DIFF_1ST) | |
1561 | + rev_mapping[(int) b->correspond - (int) DIFF_1ST]))); | |
1562 | ||
1563 | /* If we aren't supposed to do this output block, skip it. */ | |
1564 | if (type == DIFF_2ND || type == DIFF_1ST | |
1565 | || (type == DIFF_3RD && dont_write_simple) | |
1566 | || (type == DIFF_ALL && dont_write_overlap)) | |
1567 | continue; | |
1568 | ||
1569 | /* Copy I lines from common file. */ | |
1570 | i = D_LOWLINE (b, FILE0) - linesread - 1; | |
1571 | linesread += i; | |
1572 | while (0 <= --i) | |
1573 | { | |
1574 | while ((c = getc(commonfile)) != '\n') | |
1575 | { | |
1576 | if (c == EOF) | |
1577 | fatal ("input file shrank"); | |
1578 | putc (c, outputfile); | |
1579 | } | |
1580 | putc (c, outputfile); | |
1581 | } | |
1582 | ||
1583 | if (flagging && type == DIFF_ALL) | |
1584 | /* Do special flagging. */ | |
1585 | { | |
1586 | /* Put in lines from FILE0 with bracket. */ | |
1587 | fprintf (outputfile, "<<<<<<< %s\n", file0); | |
1588 | for (i = 0; | |
1589 | i < D_NUMLINES (b, mapping[FILE0]); | |
1590 | i++) | |
1591 | fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char), | |
1592 | D_RELLEN (b, mapping[FILE0], i), outputfile); | |
1593 | fprintf (outputfile, "=======\n"); | |
1594 | overlaps_found = 1; | |
1595 | } | |
1596 | ||
1597 | /* Put in lines from FILE2. */ | |
1598 | for (i = 0; | |
1599 | i < D_NUMLINES (b, mapping[FILE2]); | |
1600 | i++) | |
1601 | fwrite (D_RELNUM (b, mapping[FILE2], i), sizeof (char), | |
1602 | D_RELLEN (b, mapping[FILE2], i), outputfile); | |
1603 | ||
1604 | if (flagging && type == DIFF_ALL) | |
1605 | fprintf (outputfile, ">>>>>>> %s\n", file2); | |
1606 | ||
1607 | /* Skip I lines in common file. */ | |
1608 | i = D_NUMLINES (b, FILE0); | |
1609 | linesread += i; | |
1610 | while (0 <= --i) | |
1611 | while ((c = getc(commonfile)) != '\n') | |
1612 | if (c == EOF) | |
1613 | { | |
1614 | if (i || b->next) | |
1615 | fatal ("input file shrank"); | |
1616 | return overlaps_found; | |
1617 | } | |
1618 | } | |
1619 | /* Copy rest of common file. */ | |
1620 | while ((c = getc (commonfile)) != EOF) | |
1621 | putc (c, outputfile); | |
1622 | return overlaps_found; | |
1623 | } | |
1624 | ||
1625 | /* | |
1626 | * Reverse the order of the list of diff3 blocks. | |
1627 | */ | |
1628 | struct diff3_block * | |
1629 | reverse_diff3_blocklist (diff) | |
1630 | struct diff3_block *diff; | |
1631 | { | |
1632 | register struct diff3_block *tmp, *next, *prev; | |
1633 | ||
1634 | for (tmp = diff, prev = (struct diff3_block *) 0; | |
1635 | tmp; tmp = next) | |
1636 | { | |
1637 | next = tmp->next; | |
1638 | tmp->next = prev; | |
1639 | prev = tmp; | |
1640 | } | |
1641 | ||
1642 | return prev; | |
1643 | } | |
1644 | \f | |
1645 | int | |
1646 | myread (fd, ptr, size) | |
1647 | int fd, size; | |
1648 | char *ptr; | |
1649 | { | |
1650 | int result = read (fd, ptr, size); | |
1651 | if (result < 0) | |
1652 | perror_with_exit ("Read failed"); | |
1653 | return result; | |
1654 | } | |
1655 | \f | |
1656 | VOID * | |
1657 | xmalloc (size) | |
1658 | int size; | |
1659 | { | |
1660 | VOID *result = (VOID *) malloc (size ? size : 1); | |
1661 | if (!result) | |
1662 | fatal ("Malloc failed"); | |
1663 | return result; | |
1664 | } | |
1665 | ||
1666 | VOID * | |
1667 | xrealloc (ptr, size) | |
1668 | VOID *ptr; | |
1669 | int size; | |
1670 | { | |
1671 | VOID *result = (VOID *) realloc (ptr, size ? size : 1); | |
1672 | if (!result) | |
1673 | fatal ("Malloc failed"); | |
1674 | return result; | |
1675 | } | |
1676 | \f | |
1677 | fatal (string) | |
1678 | char *string; | |
1679 | { | |
1680 | fprintf (stderr, "%s: %s\n", argv0, string); | |
1681 | exit (2); | |
1682 | } | |
1683 | ||
1684 | perror_with_exit (string) | |
1685 | char *string; | |
1686 | { | |
1687 | perror (string); | |
1688 | exit (2); | |
1689 | } |