12286d8edStholo /* Three way file comparison program (diff3) for Project GNU. 2b2346922Stholo Copyright (C) 1988, 1989, 1992, 1993, 1994, 1997, 1998 Free Software Foundation, Inc. 32286d8edStholo 42286d8edStholo This program is free software; you can redistribute it and/or modify 52286d8edStholo it under the terms of the GNU General Public License as published by 62286d8edStholo the Free Software Foundation; either version 2, or (at your option) 72286d8edStholo any later version. 82286d8edStholo 92286d8edStholo This program is distributed in the hope that it will be useful, 102286d8edStholo but WITHOUT ANY WARRANTY; without even the implied warranty of 112286d8edStholo MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 122286d8edStholo GNU General Public License for more details. 132286d8edStholo 14c71bc7e2Stholo */ 152286d8edStholo 162286d8edStholo /* Written by Randy Smith */ 172286d8edStholo /* Librarification by Tim Pierce */ 182286d8edStholo 192286d8edStholo #include "system.h" 202286d8edStholo #include <stdio.h> 212286d8edStholo #include <setjmp.h> 222286d8edStholo #include "getopt.h" 23b2346922Stholo #include "diffrun.h" 242286d8edStholo 252286d8edStholo /* diff3.c has a real initialize_main function. */ 262286d8edStholo #ifdef initialize_main 272286d8edStholo #undef initialize_main 282286d8edStholo #endif 292286d8edStholo 302286d8edStholo extern char const diff_version_string[]; 312286d8edStholo 32b2346922Stholo extern FILE *outfile; 33b2346922Stholo 34b2346922Stholo extern const struct diff_callbacks *callbacks; 35b2346922Stholo 36b2346922Stholo void write_output PARAMS((char const *, size_t)); 37b2346922Stholo void printf_output PARAMS((char const *, ...)) 38b2346922Stholo #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 6) 39b2346922Stholo __attribute__ ((__format__ (__printf__, 1, 2))) 40b2346922Stholo #endif 41b2346922Stholo ; 42b2346922Stholo void flush_output PARAMS((void)); 43b2346922Stholo 442286d8edStholo /* 452286d8edStholo * Internal data structures and macros for the diff3 program; includes 462286d8edStholo * data structures for both diff3 diffs and normal diffs. 472286d8edStholo */ 482286d8edStholo 492286d8edStholo /* Different files within a three way diff. */ 502286d8edStholo #define FILE0 0 512286d8edStholo #define FILE1 1 522286d8edStholo #define FILE2 2 532286d8edStholo 542286d8edStholo /* 552286d8edStholo * A three way diff is built from two two-way diffs; the file which 562286d8edStholo * the two two-way diffs share is: 572286d8edStholo */ 582286d8edStholo #define FILEC FILE2 592286d8edStholo 602286d8edStholo /* 612286d8edStholo * Different files within a two way diff. 622286d8edStholo * FC is the common file, FO the other file. 632286d8edStholo */ 642286d8edStholo #define FO 0 652286d8edStholo #define FC 1 662286d8edStholo 672286d8edStholo /* The ranges are indexed by */ 682286d8edStholo #define START 0 692286d8edStholo #define END 1 702286d8edStholo 712286d8edStholo enum diff_type { 722286d8edStholo ERROR, /* Should not be used */ 732286d8edStholo ADD, /* Two way diff add */ 742286d8edStholo CHANGE, /* Two way diff change */ 752286d8edStholo DELETE, /* Two way diff delete */ 762286d8edStholo DIFF_ALL, /* All three are different */ 772286d8edStholo DIFF_1ST, /* Only the first is different */ 782286d8edStholo DIFF_2ND, /* Only the second */ 792286d8edStholo DIFF_3RD /* Only the third */ 802286d8edStholo }; 812286d8edStholo 822286d8edStholo /* Two way diff */ 832286d8edStholo struct diff_block { 842286d8edStholo int ranges[2][2]; /* Ranges are inclusive */ 852286d8edStholo char **lines[2]; /* The actual lines (may contain nulls) */ 862286d8edStholo size_t *lengths[2]; /* Line lengths (including newlines, if any) */ 872286d8edStholo struct diff_block *next; 882286d8edStholo }; 892286d8edStholo 902286d8edStholo /* Three way diff */ 912286d8edStholo 922286d8edStholo struct diff3_block { 932286d8edStholo enum diff_type correspond; /* Type of diff */ 942286d8edStholo int ranges[3][2]; /* Ranges are inclusive */ 952286d8edStholo char **lines[3]; /* The actual lines (may contain nulls) */ 962286d8edStholo size_t *lengths[3]; /* Line lengths (including newlines, if any) */ 972286d8edStholo struct diff3_block *next; 982286d8edStholo }; 992286d8edStholo 1002286d8edStholo /* 1012286d8edStholo * Access the ranges on a diff block. 1022286d8edStholo */ 1032286d8edStholo #define D_LOWLINE(diff, filenum) \ 1042286d8edStholo ((diff)->ranges[filenum][START]) 1052286d8edStholo #define D_HIGHLINE(diff, filenum) \ 1062286d8edStholo ((diff)->ranges[filenum][END]) 1072286d8edStholo #define D_NUMLINES(diff, filenum) \ 1082286d8edStholo (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1) 1092286d8edStholo 1102286d8edStholo /* 1112286d8edStholo * Access the line numbers in a file in a diff by relative line 1122286d8edStholo * numbers (i.e. line number within the diff itself). Note that these 1132286d8edStholo * are lvalues and can be used for assignment. 1142286d8edStholo */ 1152286d8edStholo #define D_RELNUM(diff, filenum, linenum) \ 1162286d8edStholo ((diff)->lines[filenum][linenum]) 1172286d8edStholo #define D_RELLEN(diff, filenum, linenum) \ 1182286d8edStholo ((diff)->lengths[filenum][linenum]) 1192286d8edStholo 1202286d8edStholo /* 1212286d8edStholo * And get at them directly, when that should be necessary. 1222286d8edStholo */ 1232286d8edStholo #define D_LINEARRAY(diff, filenum) \ 1242286d8edStholo ((diff)->lines[filenum]) 1252286d8edStholo #define D_LENARRAY(diff, filenum) \ 1262286d8edStholo ((diff)->lengths[filenum]) 1272286d8edStholo 1282286d8edStholo /* 1292286d8edStholo * Next block. 1302286d8edStholo */ 1312286d8edStholo #define D_NEXT(diff) ((diff)->next) 1322286d8edStholo 1332286d8edStholo /* 1342286d8edStholo * Access the type of a diff3 block. 1352286d8edStholo */ 1362286d8edStholo #define D3_TYPE(diff) ((diff)->correspond) 1372286d8edStholo 1382286d8edStholo /* 1392286d8edStholo * Line mappings based on diffs. The first maps off the top of the 1402286d8edStholo * diff, the second off of the bottom. 1412286d8edStholo */ 1422286d8edStholo #define D_HIGH_MAPLINE(diff, fromfile, tofile, lineno) \ 1432286d8edStholo ((lineno) \ 1442286d8edStholo - D_HIGHLINE ((diff), (fromfile)) \ 1452286d8edStholo + D_HIGHLINE ((diff), (tofile))) 1462286d8edStholo 1472286d8edStholo #define D_LOW_MAPLINE(diff, fromfile, tofile, lineno) \ 1482286d8edStholo ((lineno) \ 1492286d8edStholo - D_LOWLINE ((diff), (fromfile)) \ 1502286d8edStholo + D_LOWLINE ((diff), (tofile))) 1512286d8edStholo 1522286d8edStholo /* 1532286d8edStholo * General memory allocation function. 1542286d8edStholo */ 1552286d8edStholo #define ALLOCATE(number, type) \ 1562286d8edStholo (type *) xmalloc ((number) * sizeof (type)) 1572286d8edStholo 1582286d8edStholo /* Options variables for flags set on command line. */ 1592286d8edStholo 1602286d8edStholo /* If nonzero, treat all files as text files, never as binary. */ 1612286d8edStholo static int always_text; 1622286d8edStholo 1632286d8edStholo /* If nonzero, write out an ed script instead of the standard diff3 format. */ 1642286d8edStholo static int edscript; 1652286d8edStholo 1662286d8edStholo /* If nonzero, in the case of overlapping diffs (type DIFF_ALL), 1672286d8edStholo preserve the lines which would normally be deleted from 1682286d8edStholo file 1 with a special flagging mechanism. */ 1692286d8edStholo static int flagging; 1702286d8edStholo 1712286d8edStholo /* Number of lines to keep in identical prefix and suffix. */ 1722286d8edStholo static int horizon_lines = 10; 1732286d8edStholo 1742286d8edStholo /* Use a tab to align output lines (-T). */ 1752286d8edStholo static int tab_align_flag; 1762286d8edStholo 1772286d8edStholo /* If nonzero, do not output information for overlapping diffs. */ 1782286d8edStholo static int simple_only; 1792286d8edStholo 1802286d8edStholo /* If nonzero, do not output information for non-overlapping diffs. */ 1812286d8edStholo static int overlap_only; 1822286d8edStholo 1832286d8edStholo /* If nonzero, show information for DIFF_2ND diffs. */ 1842286d8edStholo static int show_2nd; 1852286d8edStholo 1862286d8edStholo /* If nonzero, include `:wq' at the end of the script 1872286d8edStholo to write out the file being edited. */ 1882286d8edStholo static int finalwrite; 1892286d8edStholo 1902286d8edStholo /* If nonzero, output a merged file. */ 1912286d8edStholo static int merge; 1922286d8edStholo 1932286d8edStholo extern char *diff_program_name; 1942286d8edStholo 1952286d8edStholo static char *read_diff PARAMS((char const *, char const *, char **)); 1962286d8edStholo static char *scan_diff_line PARAMS((char *, char **, size_t *, char *, int)); 1972286d8edStholo static enum diff_type process_diff_control PARAMS((char **, struct diff_block *)); 1982286d8edStholo static int compare_line_list PARAMS((char * const[], size_t const[], char * const[], size_t const[], int)); 1992286d8edStholo static int copy_stringlist PARAMS((char * const[], size_t const[], char *[], size_t[], int)); 200b2346922Stholo static int dotlines PARAMS((struct diff3_block *, int)); 201b2346922Stholo static int output_diff3_edscript PARAMS((struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *)); 202b2346922Stholo static int output_diff3_merge PARAMS((FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *)); 2032286d8edStholo static size_t myread PARAMS((int, char *, size_t)); 2042286d8edStholo static struct diff3_block *create_diff3_block PARAMS((int, int, int, int, int, int)); 2052286d8edStholo static struct diff3_block *make_3way_diff PARAMS((struct diff_block *, struct diff_block *)); 2062286d8edStholo static struct diff3_block *reverse_diff3_blocklist PARAMS((struct diff3_block *)); 2072286d8edStholo static struct diff3_block *using_to_diff3_block PARAMS((struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *)); 2082286d8edStholo static struct diff_block *process_diff PARAMS((char const *, char const *, struct diff_block **, char **)); 2092286d8edStholo static void check_output PARAMS((FILE *)); 2102286d8edStholo static void diff3_fatal PARAMS((char const *)); 211b2346922Stholo static void output_diff3 PARAMS((struct diff3_block *, int const[3], int const[3])); 2122286d8edStholo static void diff3_perror_with_exit PARAMS((char const *)); 2132286d8edStholo static int try_help PARAMS((char const *)); 214b2346922Stholo static void undotlines PARAMS((int, int, int)); 2152286d8edStholo static void usage PARAMS((void)); 2162286d8edStholo static void initialize_main PARAMS((int *, char ***)); 2172286d8edStholo static void free_diff_blocks PARAMS((struct diff_block *)); 2182286d8edStholo static void free_diff3_blocks PARAMS((struct diff3_block *)); 2192286d8edStholo 2202286d8edStholo /* Functions provided in libdiff.a or other external sources. */ 2212286d8edStholo VOID *xmalloc PARAMS((size_t)); 2222286d8edStholo VOID *xrealloc PARAMS((VOID *, size_t)); 2232286d8edStholo void perror_with_name PARAMS((char const *)); 2242286d8edStholo void diff_error PARAMS((char const *, char const *, char const *)); 2252286d8edStholo 2262286d8edStholo /* Permit non-local exits from diff3. */ 2272286d8edStholo static jmp_buf diff3_abort_buf; 2282286d8edStholo #define DIFF3_ABORT(retval) longjmp(diff3_abort_buf, retval) 2292286d8edStholo 2302286d8edStholo static struct option const longopts[] = 2312286d8edStholo { 2322286d8edStholo {"text", 0, 0, 'a'}, 2332286d8edStholo {"show-all", 0, 0, 'A'}, 2342286d8edStholo {"ed", 0, 0, 'e'}, 2352286d8edStholo {"show-overlap", 0, 0, 'E'}, 2362286d8edStholo {"label", 1, 0, 'L'}, 2372286d8edStholo {"merge", 0, 0, 'm'}, 2382286d8edStholo {"initial-tab", 0, 0, 'T'}, 2392286d8edStholo {"overlap-only", 0, 0, 'x'}, 2402286d8edStholo {"easy-only", 0, 0, '3'}, 2412286d8edStholo {"version", 0, 0, 'v'}, 2422286d8edStholo {"help", 0, 0, 129}, 2432286d8edStholo {0, 0, 0, 0} 2442286d8edStholo }; 2452286d8edStholo 2462286d8edStholo /* 2472286d8edStholo * Main program. Calls diff twice on two pairs of input files, 2482286d8edStholo * combines the two diffs, and outputs them. 2492286d8edStholo */ 2502286d8edStholo int 251b2346922Stholo diff3_run (argc, argv, out, callbacks_arg) 2522286d8edStholo int argc; 2532286d8edStholo char **argv; 254b2346922Stholo char *out; 255b2346922Stholo const struct diff_callbacks *callbacks_arg; 2562286d8edStholo { 2572286d8edStholo int c, i; 2582286d8edStholo int mapping[3]; 2592286d8edStholo int rev_mapping[3]; 2602286d8edStholo int incompat = 0; 2612286d8edStholo int conflicts_found; 2622286d8edStholo int status; 2632286d8edStholo struct diff_block *thread0, *thread1, *last_block; 2642286d8edStholo char *content0, *content1; 2652286d8edStholo struct diff3_block *diff3; 2662286d8edStholo int tag_count = 0; 2672286d8edStholo char *tag_strings[3]; 2682286d8edStholo char *commonname; 2692286d8edStholo char **file; 2702286d8edStholo struct stat statb; 2712286d8edStholo int optind_old; 272b2346922Stholo int opened_file = 0; 273b2346922Stholo 274b2346922Stholo callbacks = callbacks_arg; 2752286d8edStholo 2762286d8edStholo initialize_main (&argc, &argv); 2772286d8edStholo 2782286d8edStholo optind_old = optind; 2792286d8edStholo optind = 0; 2802286d8edStholo while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != EOF) 2812286d8edStholo { 2822286d8edStholo switch (c) 2832286d8edStholo { 2842286d8edStholo case 'a': 2852286d8edStholo always_text = 1; 2862286d8edStholo break; 2872286d8edStholo case 'A': 2882286d8edStholo show_2nd = 1; 2892286d8edStholo flagging = 1; 2902286d8edStholo incompat++; 2912286d8edStholo break; 2922286d8edStholo case 'x': 2932286d8edStholo overlap_only = 1; 2942286d8edStholo incompat++; 2952286d8edStholo break; 2962286d8edStholo case '3': 2972286d8edStholo simple_only = 1; 2982286d8edStholo incompat++; 2992286d8edStholo break; 3002286d8edStholo case 'i': 3012286d8edStholo finalwrite = 1; 3022286d8edStholo break; 3032286d8edStholo case 'm': 3042286d8edStholo merge = 1; 3052286d8edStholo break; 3062286d8edStholo case 'X': 3072286d8edStholo overlap_only = 1; 3082286d8edStholo /* Falls through */ 3092286d8edStholo case 'E': 3102286d8edStholo flagging = 1; 3112286d8edStholo /* Falls through */ 3122286d8edStholo case 'e': 3132286d8edStholo incompat++; 3142286d8edStholo break; 3152286d8edStholo case 'T': 3162286d8edStholo tab_align_flag = 1; 3172286d8edStholo break; 3182286d8edStholo case 'v': 319b2346922Stholo if (callbacks && callbacks->write_stdout) 320b2346922Stholo { 321b2346922Stholo (*callbacks->write_stdout) ("diff3 - GNU diffutils version "); 322b2346922Stholo (*callbacks->write_stdout) (diff_version_string); 323b2346922Stholo (*callbacks->write_stdout) ("\n"); 324b2346922Stholo } 325b2346922Stholo else 3262286d8edStholo printf ("diff3 - GNU diffutils version %s\n", diff_version_string); 3272286d8edStholo return 0; 3282286d8edStholo case 129: 3292286d8edStholo usage (); 330b2346922Stholo if (! callbacks || ! callbacks->write_stdout) 3312286d8edStholo check_output (stdout); 3322286d8edStholo return 0; 3332286d8edStholo case 'L': 3342286d8edStholo /* Handle up to three -L options. */ 3352286d8edStholo if (tag_count < 3) 3362286d8edStholo { 3372286d8edStholo tag_strings[tag_count++] = optarg; 3382286d8edStholo break; 3392286d8edStholo } 3402286d8edStholo return try_help ("Too many labels were given. The limit is 3."); 3412286d8edStholo default: 3422286d8edStholo return try_help (0); 3432286d8edStholo } 3442286d8edStholo } 3452286d8edStholo 3462286d8edStholo edscript = incompat & ~merge; /* -AeExX3 without -m implies ed script. */ 3472286d8edStholo show_2nd |= ~incompat & merge; /* -m without -AeExX3 implies -A. */ 3482286d8edStholo flagging |= ~incompat & merge; 3492286d8edStholo 3502286d8edStholo if (incompat > 1 /* Ensure at most one of -AeExX3. */ 3512286d8edStholo || finalwrite & merge /* -i -m would rewrite input file. */ 3522286d8edStholo || (tag_count && ! flagging)) /* -L requires one of -AEX. */ 3532286d8edStholo return try_help ("incompatible options"); 3542286d8edStholo 3552286d8edStholo if (argc - optind != 3) 3562286d8edStholo return try_help (argc - optind < 3 ? "missing operand" : "extra operand"); 3572286d8edStholo 3582286d8edStholo file = &argv[optind]; 3592286d8edStholo 3602286d8edStholo optind = optind_old; 3612286d8edStholo 3622286d8edStholo for (i = tag_count; i < 3; i++) 3632286d8edStholo tag_strings[i] = file[i]; 3642286d8edStholo 3652286d8edStholo /* Always compare file1 to file2, even if file2 is "-". 3662286d8edStholo This is needed for -mAeExX3. Using the file0 as 3672286d8edStholo the common file would produce wrong results, because if the 3682286d8edStholo file0-file1 diffs didn't line up with the file0-file2 diffs 3692286d8edStholo (which is entirely possible since we don't use diff's -n option), 3702286d8edStholo diff3 might report phantom changes from file1 to file2. */ 3712286d8edStholo 3722286d8edStholo if (strcmp (file[2], "-") == 0) 3732286d8edStholo { 3742286d8edStholo /* Sigh. We've got standard input as the last arg. We can't 3752286d8edStholo call diff twice on stdin. Use the middle arg as the common 3762286d8edStholo file instead. */ 3772286d8edStholo if (strcmp (file[0], "-") == 0 || strcmp (file[1], "-") == 0) 3782286d8edStholo { 3792286d8edStholo diff_error ("%s", "`-' specified for more than one input file", 0); 3802286d8edStholo return 2; 3812286d8edStholo } 3822286d8edStholo mapping[0] = 0; 3832286d8edStholo mapping[1] = 2; 3842286d8edStholo mapping[2] = 1; 3852286d8edStholo } 3862286d8edStholo else 3872286d8edStholo { 3882286d8edStholo /* Normal, what you'd expect */ 3892286d8edStholo mapping[0] = 0; 3902286d8edStholo mapping[1] = 1; 3912286d8edStholo mapping[2] = 2; 3922286d8edStholo } 3932286d8edStholo 3942286d8edStholo for (i = 0; i < 3; i++) 3952286d8edStholo rev_mapping[mapping[i]] = i; 3962286d8edStholo 3972286d8edStholo for (i = 0; i < 3; i++) 3982286d8edStholo if (strcmp (file[i], "-") != 0) 3992286d8edStholo { 4002286d8edStholo if (stat (file[i], &statb) < 0) 4012286d8edStholo { 4022286d8edStholo perror_with_name (file[i]); 4032286d8edStholo return 2; 4042286d8edStholo } 4052286d8edStholo else if (S_ISDIR(statb.st_mode)) 4062286d8edStholo { 407b2346922Stholo diff_error ("%s: Is a directory", file[i], 0); 4082286d8edStholo return 2; 4092286d8edStholo } 4102286d8edStholo } 4112286d8edStholo 412b2346922Stholo if (callbacks && callbacks->write_output) 413b2346922Stholo { 414b2346922Stholo if (out != NULL) 415b2346922Stholo { 416b2346922Stholo diff_error ("write callback with output file", 0, 0); 417b2346922Stholo return 2; 418b2346922Stholo } 419b2346922Stholo } 4202286d8edStholo else 4212286d8edStholo { 422b2346922Stholo if (out == NULL) 423b2346922Stholo outfile = stdout; 424b2346922Stholo else 425b2346922Stholo { 426b2346922Stholo outfile = fopen (out, "w"); 427b2346922Stholo if (outfile == NULL) 4282286d8edStholo { 4292286d8edStholo perror_with_name ("could not open output file"); 4302286d8edStholo return 2; 4312286d8edStholo } 432b2346922Stholo opened_file = 1; 433b2346922Stholo } 4342286d8edStholo } 4352286d8edStholo 4362286d8edStholo /* Set the jump buffer, so that diff may abort execution without 4372286d8edStholo terminating the process. */ 4382286d8edStholo status = setjmp (diff3_abort_buf); 4392286d8edStholo if (status != 0) 4402286d8edStholo return status; 4412286d8edStholo 4422286d8edStholo commonname = file[rev_mapping[FILEC]]; 4432286d8edStholo thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block, 4442286d8edStholo &content1); 4452286d8edStholo if (thread1) 4462286d8edStholo for (i = 0; i < 2; i++) 4472286d8edStholo { 4482286d8edStholo horizon_lines = max (horizon_lines, D_NUMLINES (thread1, i)); 4492286d8edStholo horizon_lines = max (horizon_lines, D_NUMLINES (last_block, i)); 4502286d8edStholo } 4512286d8edStholo thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block, 4522286d8edStholo &content0); 4532286d8edStholo diff3 = make_3way_diff (thread0, thread1); 4542286d8edStholo if (edscript) 4552286d8edStholo conflicts_found 456b2346922Stholo = output_diff3_edscript (diff3, mapping, rev_mapping, 4572286d8edStholo tag_strings[0], tag_strings[1], tag_strings[2]); 4582286d8edStholo else if (merge) 4592286d8edStholo { 460*892c0aadStholo FILE *mfp = fopen (file[rev_mapping[FILE0]], "r"); 461*892c0aadStholo if (! mfp) 4622286d8edStholo diff3_perror_with_exit (file[rev_mapping[FILE0]]); 463*892c0aadStholo conflicts_found = output_diff3_merge (mfp, diff3, mapping, rev_mapping, 4642286d8edStholo tag_strings[0], tag_strings[1], tag_strings[2]); 465*892c0aadStholo if (ferror (mfp)) 4662286d8edStholo diff3_fatal ("read error"); 467*892c0aadStholo if (fclose(mfp) != 0) 468*892c0aadStholo perror_with_name (file[rev_mapping[FILE0]]); 4692286d8edStholo } 4702286d8edStholo else 4712286d8edStholo { 472b2346922Stholo output_diff3 (diff3, mapping, rev_mapping); 4732286d8edStholo conflicts_found = 0; 4742286d8edStholo } 4752286d8edStholo 4762286d8edStholo free(content0); 4772286d8edStholo free(content1); 4782286d8edStholo free_diff_blocks(thread0); 4792286d8edStholo free_diff_blocks(thread1); 4802286d8edStholo free_diff3_blocks(diff3); 4812286d8edStholo 482b2346922Stholo if (! callbacks || ! callbacks->write_output) 483b2346922Stholo check_output (outfile); 484b2346922Stholo 485b2346922Stholo if (opened_file) 486b2346922Stholo if (fclose (outfile) != 0) 487b2346922Stholo perror_with_name ("close error on output file"); 488b2346922Stholo 4892286d8edStholo return conflicts_found; 4902286d8edStholo } 4912286d8edStholo 4922286d8edStholo static int 4932286d8edStholo try_help (reason) 4942286d8edStholo char const *reason; 4952286d8edStholo { 4962286d8edStholo if (reason) 497b2346922Stholo diff_error ("%s", reason, 0); 498b2346922Stholo diff_error ("Try `%s --help' for more information.", diff_program_name, 0); 4992286d8edStholo return 2; 5002286d8edStholo } 5012286d8edStholo 5022286d8edStholo static void 5032286d8edStholo check_output (stream) 5042286d8edStholo FILE *stream; 5052286d8edStholo { 5062286d8edStholo if (ferror (stream) || fflush (stream) != 0) 5072286d8edStholo diff3_fatal ("write error"); 5082286d8edStholo } 5092286d8edStholo 5102286d8edStholo /* 5112286d8edStholo * Explain, patiently and kindly, how to use this program. 5122286d8edStholo */ 5132286d8edStholo static void 5142286d8edStholo usage () 5152286d8edStholo { 516b2346922Stholo if (callbacks && callbacks->write_stdout) 517b2346922Stholo { 518b2346922Stholo (*callbacks->write_stdout) ("Usage: "); 519b2346922Stholo (*callbacks->write_stdout) (diff_program_name); 520b2346922Stholo (*callbacks->write_stdout) (" [OPTION]... MYFILE OLDFILE YOURFILE\n\n"); 521b2346922Stholo 522b2346922Stholo (*callbacks->write_stdout) ("\ 523b2346922Stholo -e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE.\n\ 524b2346922Stholo -E --show-overlap Output unmerged changes, bracketing conflicts.\n\ 525b2346922Stholo -A --show-all Output all changes, bracketing conflicts.\n\ 526b2346922Stholo -x --overlap-only Output overlapping changes.\n\ 527b2346922Stholo -X Output overlapping changes, bracketing them.\n\ 528b2346922Stholo -3 --easy-only Output unmerged nonoverlapping changes.\n\n"); 529b2346922Stholo (*callbacks->write_stdout) ("\ 530b2346922Stholo -m --merge Output merged file instead of ed script (default -A).\n\ 531b2346922Stholo -L LABEL --label=LABEL Use LABEL instead of file name.\n\ 532b2346922Stholo -i Append `w' and `q' commands to ed scripts.\n\ 533b2346922Stholo -a --text Treat all files as text.\n\ 534b2346922Stholo -T --initial-tab Make tabs line up by prepending a tab.\n\n"); 535b2346922Stholo (*callbacks->write_stdout) ("\ 536b2346922Stholo -v --version Output version info.\n\ 537b2346922Stholo --help Output this help.\n\n"); 538b2346922Stholo (*callbacks->write_stdout) ("If a FILE is `-', read standard input.\n"); 539b2346922Stholo } 540b2346922Stholo else 541b2346922Stholo { 5422286d8edStholo printf ("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n\n", diff_program_name); 5432286d8edStholo 5442286d8edStholo printf ("%s", "\ 5452286d8edStholo -e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE.\n\ 5462286d8edStholo -E --show-overlap Output unmerged changes, bracketing conflicts.\n\ 5472286d8edStholo -A --show-all Output all changes, bracketing conflicts.\n\ 5482286d8edStholo -x --overlap-only Output overlapping changes.\n\ 5492286d8edStholo -X Output overlapping changes, bracketing them.\n\ 5502286d8edStholo -3 --easy-only Output unmerged nonoverlapping changes.\n\n"); 5512286d8edStholo printf ("%s", "\ 5522286d8edStholo -m --merge Output merged file instead of ed script (default -A).\n\ 5532286d8edStholo -L LABEL --label=LABEL Use LABEL instead of file name.\n\ 5542286d8edStholo -i Append `w' and `q' commands to ed scripts.\n\ 5552286d8edStholo -a --text Treat all files as text.\n\ 5562286d8edStholo -T --initial-tab Make tabs line up by prepending a tab.\n\n"); 5572286d8edStholo printf ("%s", "\ 5582286d8edStholo -v --version Output version info.\n\ 5592286d8edStholo --help Output this help.\n\n"); 5602286d8edStholo printf ("If a FILE is `-', read standard input.\n"); 5612286d8edStholo } 562b2346922Stholo } 5632286d8edStholo 5642286d8edStholo /* 5652286d8edStholo * Routines that combine the two diffs together into one. The 5662286d8edStholo * algorithm used follows: 5672286d8edStholo * 5682286d8edStholo * File2 is shared in common between the two diffs. 5692286d8edStholo * Diff02 is the diff between 0 and 2. 5702286d8edStholo * Diff12 is the diff between 1 and 2. 5712286d8edStholo * 5722286d8edStholo * 1) Find the range for the first block in File2. 5732286d8edStholo * a) Take the lowest of the two ranges (in File2) in the two 5742286d8edStholo * current blocks (one from each diff) as being the low 5752286d8edStholo * water mark. Assign the upper end of this block as 5762286d8edStholo * being the high water mark and move the current block up 5772286d8edStholo * one. Mark the block just moved over as to be used. 5782286d8edStholo * b) Check the next block in the diff that the high water 5792286d8edStholo * mark is *not* from. 5802286d8edStholo * 5812286d8edStholo * *If* the high water mark is above 5822286d8edStholo * the low end of the range in that block, 5832286d8edStholo * 5842286d8edStholo * mark that block as to be used and move the current 5852286d8edStholo * block up. Set the high water mark to the max of 5862286d8edStholo * the high end of this block and the current. Repeat b. 5872286d8edStholo * 5882286d8edStholo * 2) Find the corresponding ranges in File0 (from the blocks 5892286d8edStholo * in diff02; line per line outside of diffs) and in File1. 5902286d8edStholo * Create a diff3_block, reserving space as indicated by the ranges. 5912286d8edStholo * 5922286d8edStholo * 3) Copy all of the pointers for file2 in. At least for now, 5932286d8edStholo * do memcmp's between corresponding strings in the two diffs. 5942286d8edStholo * 5952286d8edStholo * 4) Copy all of the pointers for file0 and 1 in. Get what you 5962286d8edStholo * need from file2 (when there isn't a diff block, it's 5972286d8edStholo * identical to file2 within the range between diff blocks). 5982286d8edStholo * 5992286d8edStholo * 5) If the diff blocks you used came from only one of the two 6002286d8edStholo * strings of diffs, then that file (i.e. the one other than 6012286d8edStholo * the common file in that diff) is the odd person out. If you used 6022286d8edStholo * diff blocks from both sets, check to see if files 0 and 1 match: 6032286d8edStholo * 6042286d8edStholo * Same number of lines? If so, do a set of memcmp's (if a 6052286d8edStholo * memcmp matches; copy the pointer over; it'll be easier later 6062286d8edStholo * if you have to do any compares). If they match, 0 & 1 are 6072286d8edStholo * the same. If not, all three different. 6082286d8edStholo * 6092286d8edStholo * Then you do it again, until you run out of blocks. 6102286d8edStholo * 6112286d8edStholo */ 6122286d8edStholo 6132286d8edStholo /* 6142286d8edStholo * This routine makes a three way diff (chain of diff3_block's) from two 6152286d8edStholo * two way diffs (chains of diff_block's). It is assumed that each of 6162286d8edStholo * the two diffs passed are onto the same file (i.e. that each of the 6172286d8edStholo * diffs were made "to" the same file). The three way diff pointer 6182286d8edStholo * returned will have numbering FILE0--the other file in diff02, 6192286d8edStholo * FILE1--the other file in diff12, and FILEC--the common file. 6202286d8edStholo */ 6212286d8edStholo static struct diff3_block * 6222286d8edStholo make_3way_diff (thread0, thread1) 6232286d8edStholo struct diff_block *thread0, *thread1; 6242286d8edStholo { 6252286d8edStholo /* 6262286d8edStholo * This routine works on the two diffs passed to it as threads. 6272286d8edStholo * Thread number 0 is diff02, thread number 1 is diff12. The USING 6282286d8edStholo * array is set to the base of the list of blocks to be used to 6292286d8edStholo * construct each block of the three way diff; if no blocks from a 6302286d8edStholo * particular thread are to be used, that element of the using array 6312286d8edStholo * is set to 0. The elements LAST_USING array are set to the last 6322286d8edStholo * elements on each of the using lists. 6332286d8edStholo * 6342286d8edStholo * The HIGH_WATER_MARK is set to the highest line number in the common file 6352286d8edStholo * described in any of the diffs in either of the USING lists. The 6362286d8edStholo * HIGH_WATER_THREAD names the thread. Similarly the BASE_WATER_MARK 6372286d8edStholo * and BASE_WATER_THREAD describe the lowest line number in the common file 6382286d8edStholo * described in any of the diffs in either of the USING lists. The 6392286d8edStholo * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was 6402286d8edStholo * taken. 6412286d8edStholo * 6422286d8edStholo * The HIGH_WATER_DIFF should always be equal to LAST_USING 6432286d8edStholo * [HIGH_WATER_THREAD]. The OTHER_DIFF is the next diff to check for 6442286d8edStholo * higher water, and should always be equal to 6452286d8edStholo * CURRENT[HIGH_WATER_THREAD ^ 0x1]. The OTHER_THREAD is the thread 6462286d8edStholo * in which the OTHER_DIFF is, and hence should always be equal to 6472286d8edStholo * HIGH_WATER_THREAD ^ 0x1. 6482286d8edStholo * 6492286d8edStholo * The variable LAST_DIFF is kept set to the last diff block produced 6502286d8edStholo * by this routine, for line correspondence purposes between that diff 6512286d8edStholo * and the one currently being worked on. It is initialized to 6522286d8edStholo * ZERO_DIFF before any blocks have been created. 6532286d8edStholo */ 6542286d8edStholo 6552286d8edStholo struct diff_block 6562286d8edStholo *using[2], 6572286d8edStholo *last_using[2], 6582286d8edStholo *current[2]; 6592286d8edStholo 6602286d8edStholo int 6612286d8edStholo high_water_mark; 6622286d8edStholo 6632286d8edStholo int 6642286d8edStholo high_water_thread, 6652286d8edStholo base_water_thread, 6662286d8edStholo other_thread; 6672286d8edStholo 6682286d8edStholo struct diff_block 6692286d8edStholo *high_water_diff, 6702286d8edStholo *other_diff; 6712286d8edStholo 6722286d8edStholo struct diff3_block 6732286d8edStholo *result, 6742286d8edStholo *tmpblock, 6752286d8edStholo **result_end; 6762286d8edStholo 6772286d8edStholo struct diff3_block const *last_diff3; 6782286d8edStholo 6792286d8edStholo static struct diff3_block const zero_diff3; 6802286d8edStholo 6812286d8edStholo /* Initialization */ 6822286d8edStholo result = 0; 6832286d8edStholo result_end = &result; 6842286d8edStholo current[0] = thread0; current[1] = thread1; 6852286d8edStholo last_diff3 = &zero_diff3; 6862286d8edStholo 6872286d8edStholo /* Sniff up the threads until we reach the end */ 6882286d8edStholo 6892286d8edStholo while (current[0] || current[1]) 6902286d8edStholo { 6912286d8edStholo using[0] = using[1] = last_using[0] = last_using[1] = 0; 6922286d8edStholo 6932286d8edStholo /* Setup low and high water threads, diffs, and marks. */ 6942286d8edStholo if (!current[0]) 6952286d8edStholo base_water_thread = 1; 6962286d8edStholo else if (!current[1]) 6972286d8edStholo base_water_thread = 0; 6982286d8edStholo else 6992286d8edStholo base_water_thread = 7002286d8edStholo (D_LOWLINE (current[0], FC) > D_LOWLINE (current[1], FC)); 7012286d8edStholo 7022286d8edStholo high_water_thread = base_water_thread; 7032286d8edStholo 7042286d8edStholo high_water_diff = current[high_water_thread]; 7052286d8edStholo 7062286d8edStholo #if 0 7072286d8edStholo /* low and high waters start off same diff */ 7082286d8edStholo base_water_mark = D_LOWLINE (high_water_diff, FC); 7092286d8edStholo #endif 7102286d8edStholo 7112286d8edStholo high_water_mark = D_HIGHLINE (high_water_diff, FC); 7122286d8edStholo 7132286d8edStholo /* Make the diff you just got info from into the using class */ 7142286d8edStholo using[high_water_thread] 7152286d8edStholo = last_using[high_water_thread] 7162286d8edStholo = high_water_diff; 7172286d8edStholo current[high_water_thread] = high_water_diff->next; 7182286d8edStholo last_using[high_water_thread]->next = 0; 7192286d8edStholo 7202286d8edStholo /* And mark the other diff */ 7212286d8edStholo other_thread = high_water_thread ^ 0x1; 7222286d8edStholo other_diff = current[other_thread]; 7232286d8edStholo 7242286d8edStholo /* Shuffle up the ladder, checking the other diff to see if it 7252286d8edStholo needs to be incorporated. */ 7262286d8edStholo while (other_diff 7272286d8edStholo && D_LOWLINE (other_diff, FC) <= high_water_mark + 1) 7282286d8edStholo { 7292286d8edStholo 7302286d8edStholo /* Incorporate this diff into the using list. Note that 7312286d8edStholo this doesn't take it off the current list */ 7322286d8edStholo if (using[other_thread]) 7332286d8edStholo last_using[other_thread]->next = other_diff; 7342286d8edStholo else 7352286d8edStholo using[other_thread] = other_diff; 7362286d8edStholo last_using[other_thread] = other_diff; 7372286d8edStholo 7382286d8edStholo /* Take it off the current list. Note that this following 7392286d8edStholo code assumes that other_diff enters it equal to 7402286d8edStholo current[high_water_thread ^ 0x1] */ 7412286d8edStholo current[other_thread] = current[other_thread]->next; 7422286d8edStholo other_diff->next = 0; 7432286d8edStholo 7442286d8edStholo /* Set the high_water stuff 7452286d8edStholo If this comparison is equal, then this is the last pass 7462286d8edStholo through this loop; since diff blocks within a given 7472286d8edStholo thread cannot overlap, the high_water_mark will be 7482286d8edStholo *below* the range_start of either of the next diffs. */ 7492286d8edStholo 7502286d8edStholo if (high_water_mark < D_HIGHLINE (other_diff, FC)) 7512286d8edStholo { 7522286d8edStholo high_water_thread ^= 1; 7532286d8edStholo high_water_diff = other_diff; 7542286d8edStholo high_water_mark = D_HIGHLINE (other_diff, FC); 7552286d8edStholo } 7562286d8edStholo 7572286d8edStholo /* Set the other diff */ 7582286d8edStholo other_thread = high_water_thread ^ 0x1; 7592286d8edStholo other_diff = current[other_thread]; 7602286d8edStholo } 7612286d8edStholo 7622286d8edStholo /* The using lists contain a list of all of the blocks to be 7632286d8edStholo included in this diff3_block. Create it. */ 7642286d8edStholo 7652286d8edStholo tmpblock = using_to_diff3_block (using, last_using, 7662286d8edStholo base_water_thread, high_water_thread, 7672286d8edStholo last_diff3); 7682286d8edStholo 7692286d8edStholo if (!tmpblock) 7702286d8edStholo diff3_fatal ("internal error: screwup in format of diff blocks"); 7712286d8edStholo 7722286d8edStholo /* Put it on the list. */ 7732286d8edStholo *result_end = tmpblock; 7742286d8edStholo result_end = &tmpblock->next; 7752286d8edStholo 7762286d8edStholo /* Set up corresponding lines correctly. */ 7772286d8edStholo last_diff3 = tmpblock; 7782286d8edStholo } 7792286d8edStholo return result; 7802286d8edStholo } 7812286d8edStholo 7822286d8edStholo /* 7832286d8edStholo * using_to_diff3_block: 7842286d8edStholo * This routine takes two lists of blocks (from two separate diff 7852286d8edStholo * threads) and puts them together into one diff3 block. 7862286d8edStholo * It then returns a pointer to this diff3 block or 0 for failure. 7872286d8edStholo * 7882286d8edStholo * All arguments besides using are for the convenience of the routine; 7892286d8edStholo * they could be derived from the using array. 7902286d8edStholo * LAST_USING is a pair of pointers to the last blocks in the using 7912286d8edStholo * structure. 7922286d8edStholo * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest 7932286d8edStholo * and highest line numbers for File0. 7942286d8edStholo * last_diff3 contains the last diff produced in the calling routine. 7952286d8edStholo * This is used for lines mappings which would still be identical to 7962286d8edStholo * the state that diff ended in. 7972286d8edStholo * 7982286d8edStholo * A distinction should be made in this routine between the two diffs 7992286d8edStholo * that are part of a normal two diff block, and the three diffs that 8002286d8edStholo * are part of a diff3_block. 8012286d8edStholo */ 8022286d8edStholo static struct diff3_block * 8032286d8edStholo using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff3) 8042286d8edStholo struct diff_block 8052286d8edStholo *using[2], 8062286d8edStholo *last_using[2]; 8072286d8edStholo int low_thread, high_thread; 8082286d8edStholo struct diff3_block const *last_diff3; 8092286d8edStholo { 8102286d8edStholo int low[2], high[2]; 8112286d8edStholo struct diff3_block *result; 8122286d8edStholo struct diff_block *ptr; 8132286d8edStholo int d, i; 8142286d8edStholo 8152286d8edStholo /* Find the range in the common file. */ 8162286d8edStholo int lowc = D_LOWLINE (using[low_thread], FC); 8172286d8edStholo int highc = D_HIGHLINE (last_using[high_thread], FC); 8182286d8edStholo 8192286d8edStholo /* Find the ranges in the other files. 8202286d8edStholo If using[d] is null, that means that the file to which that diff 8212286d8edStholo refers is equivalent to the common file over this range. */ 8222286d8edStholo 8232286d8edStholo for (d = 0; d < 2; d++) 8242286d8edStholo if (using[d]) 8252286d8edStholo { 8262286d8edStholo low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc); 8272286d8edStholo high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc); 8282286d8edStholo } 8292286d8edStholo else 8302286d8edStholo { 8312286d8edStholo low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc); 8322286d8edStholo high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc); 8332286d8edStholo } 8342286d8edStholo 8352286d8edStholo /* Create a block with the appropriate sizes */ 8362286d8edStholo result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc); 8372286d8edStholo 8382286d8edStholo /* Copy information for the common file. 8392286d8edStholo Return with a zero if any of the compares failed. */ 8402286d8edStholo 8412286d8edStholo for (d = 0; d < 2; d++) 8422286d8edStholo for (ptr = using[d]; ptr; ptr = D_NEXT (ptr)) 8432286d8edStholo { 8442286d8edStholo int result_offset = D_LOWLINE (ptr, FC) - lowc; 8452286d8edStholo 8462286d8edStholo if (!copy_stringlist (D_LINEARRAY (ptr, FC), 8472286d8edStholo D_LENARRAY (ptr, FC), 8482286d8edStholo D_LINEARRAY (result, FILEC) + result_offset, 8492286d8edStholo D_LENARRAY (result, FILEC) + result_offset, 8502286d8edStholo D_NUMLINES (ptr, FC))) 8512286d8edStholo return 0; 8522286d8edStholo } 8532286d8edStholo 8542286d8edStholo /* Copy information for file d. First deal with anything that might be 8552286d8edStholo before the first diff. */ 8562286d8edStholo 8572286d8edStholo for (d = 0; d < 2; d++) 8582286d8edStholo { 8592286d8edStholo struct diff_block *u = using[d]; 8602286d8edStholo int lo = low[d], hi = high[d]; 8612286d8edStholo 8622286d8edStholo for (i = 0; 8632286d8edStholo i + lo < (u ? D_LOWLINE (u, FO) : hi + 1); 8642286d8edStholo i++) 8652286d8edStholo { 8662286d8edStholo D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i); 8672286d8edStholo D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i); 8682286d8edStholo } 8692286d8edStholo 8702286d8edStholo for (ptr = u; ptr; ptr = D_NEXT (ptr)) 8712286d8edStholo { 8722286d8edStholo int result_offset = D_LOWLINE (ptr, FO) - lo; 8732286d8edStholo int linec; 8742286d8edStholo 8752286d8edStholo if (!copy_stringlist (D_LINEARRAY (ptr, FO), 8762286d8edStholo D_LENARRAY (ptr, FO), 8772286d8edStholo D_LINEARRAY (result, FILE0 + d) + result_offset, 8782286d8edStholo D_LENARRAY (result, FILE0 + d) + result_offset, 8792286d8edStholo D_NUMLINES (ptr, FO))) 8802286d8edStholo return 0; 8812286d8edStholo 8822286d8edStholo /* Catch the lines between here and the next diff */ 8832286d8edStholo linec = D_HIGHLINE (ptr, FC) + 1 - lowc; 8842286d8edStholo for (i = D_HIGHLINE (ptr, FO) + 1 - lo; 8852286d8edStholo i < (D_NEXT (ptr) ? D_LOWLINE (D_NEXT (ptr), FO) : hi + 1) - lo; 8862286d8edStholo i++) 8872286d8edStholo { 8882286d8edStholo D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec); 8892286d8edStholo D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec); 8902286d8edStholo linec++; 8912286d8edStholo } 8922286d8edStholo } 8932286d8edStholo } 8942286d8edStholo 8952286d8edStholo /* Set correspond */ 8962286d8edStholo if (!using[0]) 8972286d8edStholo D3_TYPE (result) = DIFF_2ND; 8982286d8edStholo else if (!using[1]) 8992286d8edStholo D3_TYPE (result) = DIFF_1ST; 9002286d8edStholo else 9012286d8edStholo { 9022286d8edStholo int nl0 = D_NUMLINES (result, FILE0); 9032286d8edStholo int nl1 = D_NUMLINES (result, FILE1); 9042286d8edStholo 9052286d8edStholo if (nl0 != nl1 9062286d8edStholo || !compare_line_list (D_LINEARRAY (result, FILE0), 9072286d8edStholo D_LENARRAY (result, FILE0), 9082286d8edStholo D_LINEARRAY (result, FILE1), 9092286d8edStholo D_LENARRAY (result, FILE1), 9102286d8edStholo nl0)) 9112286d8edStholo D3_TYPE (result) = DIFF_ALL; 9122286d8edStholo else 9132286d8edStholo D3_TYPE (result) = DIFF_3RD; 9142286d8edStholo } 9152286d8edStholo 9162286d8edStholo return result; 9172286d8edStholo } 9182286d8edStholo 9192286d8edStholo /* 9202286d8edStholo * This routine copies pointers from a list of strings to a different list 9212286d8edStholo * of strings. If a spot in the second list is already filled, it 9222286d8edStholo * makes sure that it is filled with the same string; if not it 9232286d8edStholo * returns 0, the copy incomplete. 9242286d8edStholo * Upon successful completion of the copy, it returns 1. 9252286d8edStholo */ 9262286d8edStholo static int 9272286d8edStholo copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum) 9282286d8edStholo char * const fromptrs[]; 9292286d8edStholo char *toptrs[]; 9302286d8edStholo size_t const fromlengths[]; 9312286d8edStholo size_t tolengths[]; 9322286d8edStholo int copynum; 9332286d8edStholo { 9342286d8edStholo register char * const *f = fromptrs; 9352286d8edStholo register char **t = toptrs; 9362286d8edStholo register size_t const *fl = fromlengths; 9372286d8edStholo register size_t *tl = tolengths; 9382286d8edStholo 9392286d8edStholo while (copynum--) 9402286d8edStholo { 9412286d8edStholo if (*t) 9422286d8edStholo { if (*fl != *tl || memcmp (*f, *t, *fl)) return 0; } 9432286d8edStholo else 9442286d8edStholo { *t = *f ; *tl = *fl; } 9452286d8edStholo 9462286d8edStholo t++; f++; tl++; fl++; 9472286d8edStholo } 9482286d8edStholo return 1; 9492286d8edStholo } 9502286d8edStholo 9512286d8edStholo /* 9522286d8edStholo * Create a diff3_block, with ranges as specified in the arguments. 9532286d8edStholo * Allocate the arrays for the various pointers (and zero them) based 9542286d8edStholo * on the arguments passed. Return the block as a result. 9552286d8edStholo */ 9562286d8edStholo static struct diff3_block * 9572286d8edStholo create_diff3_block (low0, high0, low1, high1, low2, high2) 9582286d8edStholo register int low0, high0, low1, high1, low2, high2; 9592286d8edStholo { 9602286d8edStholo struct diff3_block *result = ALLOCATE (1, struct diff3_block); 9612286d8edStholo int numlines; 9622286d8edStholo 9632286d8edStholo D3_TYPE (result) = ERROR; 9642286d8edStholo D_NEXT (result) = 0; 9652286d8edStholo 9662286d8edStholo /* Assign ranges */ 9672286d8edStholo D_LOWLINE (result, FILE0) = low0; 9682286d8edStholo D_HIGHLINE (result, FILE0) = high0; 9692286d8edStholo D_LOWLINE (result, FILE1) = low1; 9702286d8edStholo D_HIGHLINE (result, FILE1) = high1; 9712286d8edStholo D_LOWLINE (result, FILE2) = low2; 9722286d8edStholo D_HIGHLINE (result, FILE2) = high2; 9732286d8edStholo 9742286d8edStholo /* Allocate and zero space */ 9752286d8edStholo numlines = D_NUMLINES (result, FILE0); 9762286d8edStholo if (numlines) 9772286d8edStholo { 9782286d8edStholo D_LINEARRAY (result, FILE0) = ALLOCATE (numlines, char *); 9792286d8edStholo D_LENARRAY (result, FILE0) = ALLOCATE (numlines, size_t); 9802286d8edStholo bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *))); 9812286d8edStholo bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (size_t))); 9822286d8edStholo } 9832286d8edStholo else 9842286d8edStholo { 9852286d8edStholo D_LINEARRAY (result, FILE0) = 0; 9862286d8edStholo D_LENARRAY (result, FILE0) = 0; 9872286d8edStholo } 9882286d8edStholo 9892286d8edStholo numlines = D_NUMLINES (result, FILE1); 9902286d8edStholo if (numlines) 9912286d8edStholo { 9922286d8edStholo D_LINEARRAY (result, FILE1) = ALLOCATE (numlines, char *); 9932286d8edStholo D_LENARRAY (result, FILE1) = ALLOCATE (numlines, size_t); 9942286d8edStholo bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *))); 9952286d8edStholo bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (size_t))); 9962286d8edStholo } 9972286d8edStholo else 9982286d8edStholo { 9992286d8edStholo D_LINEARRAY (result, FILE1) = 0; 10002286d8edStholo D_LENARRAY (result, FILE1) = 0; 10012286d8edStholo } 10022286d8edStholo 10032286d8edStholo numlines = D_NUMLINES (result, FILE2); 10042286d8edStholo if (numlines) 10052286d8edStholo { 10062286d8edStholo D_LINEARRAY (result, FILE2) = ALLOCATE (numlines, char *); 10072286d8edStholo D_LENARRAY (result, FILE2) = ALLOCATE (numlines, size_t); 10082286d8edStholo bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *))); 10092286d8edStholo bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (size_t))); 10102286d8edStholo } 10112286d8edStholo else 10122286d8edStholo { 10132286d8edStholo D_LINEARRAY (result, FILE2) = 0; 10142286d8edStholo D_LENARRAY (result, FILE2) = 0; 10152286d8edStholo } 10162286d8edStholo 10172286d8edStholo /* Return */ 10182286d8edStholo return result; 10192286d8edStholo } 10202286d8edStholo 10212286d8edStholo /* 10222286d8edStholo * Compare two lists of lines of text. 10232286d8edStholo * Return 1 if they are equivalent, 0 if not. 10242286d8edStholo */ 10252286d8edStholo static int 10262286d8edStholo compare_line_list (list1, lengths1, list2, lengths2, nl) 10272286d8edStholo char * const list1[], * const list2[]; 10282286d8edStholo size_t const lengths1[], lengths2[]; 10292286d8edStholo int nl; 10302286d8edStholo { 10312286d8edStholo char 10322286d8edStholo * const *l1 = list1, 10332286d8edStholo * const *l2 = list2; 10342286d8edStholo size_t const 10352286d8edStholo *lgths1 = lengths1, 10362286d8edStholo *lgths2 = lengths2; 10372286d8edStholo 10382286d8edStholo while (nl--) 10392286d8edStholo if (!*l1 || !*l2 || *lgths1 != *lgths2++ 10402286d8edStholo || memcmp (*l1++, *l2++, *lgths1++)) 10412286d8edStholo return 0; 10422286d8edStholo return 1; 10432286d8edStholo } 10442286d8edStholo 10452286d8edStholo /* 10462286d8edStholo * Routines to input and parse two way diffs. 10472286d8edStholo */ 10482286d8edStholo 10492286d8edStholo extern char **environ; 10502286d8edStholo 10512286d8edStholo static struct diff_block * 10522286d8edStholo process_diff (filea, fileb, last_block, diff_contents) 10532286d8edStholo char const *filea, *fileb; 10542286d8edStholo struct diff_block **last_block; 10552286d8edStholo char **diff_contents; 10562286d8edStholo { 10572286d8edStholo char *diff_limit; 10582286d8edStholo char *scan_diff; 10592286d8edStholo enum diff_type dt; 10602286d8edStholo int i; 10612286d8edStholo struct diff_block *block_list, **block_list_end, *bptr; 10622286d8edStholo 10632286d8edStholo diff_limit = read_diff (filea, fileb, diff_contents); 10642286d8edStholo scan_diff = *diff_contents; 10652286d8edStholo block_list_end = &block_list; 10662286d8edStholo bptr = 0; /* Pacify `gcc -W'. */ 10672286d8edStholo 10682286d8edStholo while (scan_diff < diff_limit) 10692286d8edStholo { 10702286d8edStholo bptr = ALLOCATE (1, struct diff_block); 10712286d8edStholo bptr->lines[0] = bptr->lines[1] = 0; 10722286d8edStholo bptr->lengths[0] = bptr->lengths[1] = 0; 10732286d8edStholo 10742286d8edStholo dt = process_diff_control (&scan_diff, bptr); 10752286d8edStholo if (dt == ERROR || *scan_diff != '\n') 10762286d8edStholo { 1077b2346922Stholo char *serr; 1078b2346922Stholo 1079b2346922Stholo for (serr = scan_diff; *serr != '\n'; serr++) 1080b2346922Stholo ; 1081b2346922Stholo *serr = '\0'; 1082b2346922Stholo diff_error ("diff error: %s", scan_diff, 0); 1083b2346922Stholo *serr = '\n'; 10842286d8edStholo DIFF3_ABORT (2); 10852286d8edStholo } 10862286d8edStholo scan_diff++; 10872286d8edStholo 10882286d8edStholo /* Force appropriate ranges to be null, if necessary */ 10892286d8edStholo switch (dt) 10902286d8edStholo { 10912286d8edStholo case ADD: 10922286d8edStholo bptr->ranges[0][0]++; 10932286d8edStholo break; 10942286d8edStholo case DELETE: 10952286d8edStholo bptr->ranges[1][0]++; 10962286d8edStholo break; 10972286d8edStholo case CHANGE: 10982286d8edStholo break; 10992286d8edStholo default: 11002286d8edStholo diff3_fatal ("internal error: invalid diff type in process_diff"); 11012286d8edStholo break; 11022286d8edStholo } 11032286d8edStholo 11042286d8edStholo /* Allocate space for the pointers for the lines from filea, and 11052286d8edStholo parcel them out among these pointers */ 11062286d8edStholo if (dt != ADD) 11072286d8edStholo { 11082286d8edStholo int numlines = D_NUMLINES (bptr, 0); 11092286d8edStholo bptr->lines[0] = ALLOCATE (numlines, char *); 11102286d8edStholo bptr->lengths[0] = ALLOCATE (numlines, size_t); 11112286d8edStholo for (i = 0; i < numlines; i++) 11122286d8edStholo scan_diff = scan_diff_line (scan_diff, 11132286d8edStholo &(bptr->lines[0][i]), 11142286d8edStholo &(bptr->lengths[0][i]), 11152286d8edStholo diff_limit, 11162286d8edStholo '<'); 11172286d8edStholo } 11182286d8edStholo 11192286d8edStholo /* Get past the separator for changes */ 11202286d8edStholo if (dt == CHANGE) 11212286d8edStholo { 11222286d8edStholo if (strncmp (scan_diff, "---\n", 4)) 11232286d8edStholo diff3_fatal ("invalid diff format; invalid change separator"); 11242286d8edStholo scan_diff += 4; 11252286d8edStholo } 11262286d8edStholo 11272286d8edStholo /* Allocate space for the pointers for the lines from fileb, and 11282286d8edStholo parcel them out among these pointers */ 11292286d8edStholo if (dt != DELETE) 11302286d8edStholo { 11312286d8edStholo int numlines = D_NUMLINES (bptr, 1); 11322286d8edStholo bptr->lines[1] = ALLOCATE (numlines, char *); 11332286d8edStholo bptr->lengths[1] = ALLOCATE (numlines, size_t); 11342286d8edStholo for (i = 0; i < numlines; i++) 11352286d8edStholo scan_diff = scan_diff_line (scan_diff, 11362286d8edStholo &(bptr->lines[1][i]), 11372286d8edStholo &(bptr->lengths[1][i]), 11382286d8edStholo diff_limit, 11392286d8edStholo '>'); 11402286d8edStholo } 11412286d8edStholo 11422286d8edStholo /* Place this block on the blocklist. */ 11432286d8edStholo *block_list_end = bptr; 11442286d8edStholo block_list_end = &bptr->next; 11452286d8edStholo } 11462286d8edStholo 11472286d8edStholo *block_list_end = 0; 11482286d8edStholo *last_block = bptr; 11492286d8edStholo return block_list; 11502286d8edStholo } 11512286d8edStholo 11522286d8edStholo /* 11532286d8edStholo * This routine will parse a normal format diff control string. It 11542286d8edStholo * returns the type of the diff (ERROR if the format is bad). All of 11552286d8edStholo * the other important information is filled into to the structure 11562286d8edStholo * pointed to by db, and the string pointer (whose location is passed 11572286d8edStholo * to this routine) is updated to point beyond the end of the string 11582286d8edStholo * parsed. Note that only the ranges in the diff_block will be set by 11592286d8edStholo * this routine. 11602286d8edStholo * 11612286d8edStholo * If some specific pair of numbers has been reduced to a single 11622286d8edStholo * number, then both corresponding numbers in the diff block are set 11632286d8edStholo * to that number. In general these numbers are interpetted as ranges 11642286d8edStholo * inclusive, unless being used by the ADD or DELETE commands. It is 11652286d8edStholo * assumed that these will be special cased in a superior routine. 11662286d8edStholo */ 11672286d8edStholo 11682286d8edStholo static enum diff_type 11692286d8edStholo process_diff_control (string, db) 11702286d8edStholo char **string; 11712286d8edStholo struct diff_block *db; 11722286d8edStholo { 11732286d8edStholo char *s = *string; 11742286d8edStholo int holdnum; 11752286d8edStholo enum diff_type type; 11762286d8edStholo 11772286d8edStholo /* These macros are defined here because they can use variables 11782286d8edStholo defined in this function. Don't try this at home kids, we're 11792286d8edStholo trained professionals! 11802286d8edStholo 11812286d8edStholo Also note that SKIPWHITE only recognizes tabs and spaces, and 11822286d8edStholo that READNUM can only read positive, integral numbers */ 11832286d8edStholo 11842286d8edStholo #define SKIPWHITE(s) { while (*s == ' ' || *s == '\t') s++; } 11852286d8edStholo #define READNUM(s, num) \ 11862286d8edStholo { unsigned char c = *s; if (!ISDIGIT (c)) return ERROR; holdnum = 0; \ 11872286d8edStholo do { holdnum = (c - '0' + holdnum * 10); } \ 11882286d8edStholo while (ISDIGIT (c = *++s)); (num) = holdnum; } 11892286d8edStholo 11902286d8edStholo /* Read first set of digits */ 11912286d8edStholo SKIPWHITE (s); 11922286d8edStholo READNUM (s, db->ranges[0][START]); 11932286d8edStholo 11942286d8edStholo /* Was that the only digit? */ 11952286d8edStholo SKIPWHITE (s); 11962286d8edStholo if (*s == ',') 11972286d8edStholo { 11982286d8edStholo /* Get the next digit */ 11992286d8edStholo s++; 12002286d8edStholo READNUM (s, db->ranges[0][END]); 12012286d8edStholo } 12022286d8edStholo else 12032286d8edStholo db->ranges[0][END] = db->ranges[0][START]; 12042286d8edStholo 12052286d8edStholo /* Get the letter */ 12062286d8edStholo SKIPWHITE (s); 12072286d8edStholo switch (*s) 12082286d8edStholo { 12092286d8edStholo case 'a': 12102286d8edStholo type = ADD; 12112286d8edStholo break; 12122286d8edStholo case 'c': 12132286d8edStholo type = CHANGE; 12142286d8edStholo break; 12152286d8edStholo case 'd': 12162286d8edStholo type = DELETE; 12172286d8edStholo break; 12182286d8edStholo default: 12192286d8edStholo return ERROR; /* Bad format */ 12202286d8edStholo } 12212286d8edStholo s++; /* Past letter */ 12222286d8edStholo 12232286d8edStholo /* Read second set of digits */ 12242286d8edStholo SKIPWHITE (s); 12252286d8edStholo READNUM (s, db->ranges[1][START]); 12262286d8edStholo 12272286d8edStholo /* Was that the only digit? */ 12282286d8edStholo SKIPWHITE (s); 12292286d8edStholo if (*s == ',') 12302286d8edStholo { 12312286d8edStholo /* Get the next digit */ 12322286d8edStholo s++; 12332286d8edStholo READNUM (s, db->ranges[1][END]); 12342286d8edStholo SKIPWHITE (s); /* To move to end */ 12352286d8edStholo } 12362286d8edStholo else 12372286d8edStholo db->ranges[1][END] = db->ranges[1][START]; 12382286d8edStholo 12392286d8edStholo *string = s; 12402286d8edStholo return type; 12412286d8edStholo } 12422286d8edStholo 12432286d8edStholo static char * 12442286d8edStholo read_diff (filea, fileb, output_placement) 12452286d8edStholo char const *filea, *fileb; 12462286d8edStholo char **output_placement; 12472286d8edStholo { 12482286d8edStholo char *diff_result; 12492286d8edStholo size_t bytes, current_chunk_size, total; 12502286d8edStholo int fd, wstatus; 12512286d8edStholo struct stat pipestat; 1252b2346922Stholo FILE *outfile_hold; 1253b2346922Stholo const struct diff_callbacks *callbacks_hold; 1254b2346922Stholo struct diff_callbacks my_callbacks; 1255b2346922Stholo struct diff_callbacks *my_callbacks_arg; 12562286d8edStholo 12572286d8edStholo /* 302 / 1000 is log10(2.0) rounded up. Subtract 1 for the sign bit; 12582286d8edStholo add 1 for integer division truncation; add 1 more for a minus sign. */ 12592286d8edStholo #define INT_STRLEN_BOUND(type) ((sizeof(type)*CHAR_BIT - 1) * 302 / 1000 + 2) 12602286d8edStholo 12612286d8edStholo char const *argv[7]; 12622286d8edStholo char horizon_arg[17 + INT_STRLEN_BOUND (int)]; 12632286d8edStholo char const **ap; 12642286d8edStholo char *diffout; 12652286d8edStholo 12662286d8edStholo ap = argv; 12672286d8edStholo *ap++ = "diff"; 12682286d8edStholo if (always_text) 12692286d8edStholo *ap++ = "-a"; 12702286d8edStholo sprintf (horizon_arg, "--horizon-lines=%d", horizon_lines); 12712286d8edStholo *ap++ = horizon_arg; 12722286d8edStholo *ap++ = "--"; 12732286d8edStholo *ap++ = filea; 12742286d8edStholo *ap++ = fileb; 12752286d8edStholo *ap = 0; 12762286d8edStholo 12772286d8edStholo diffout = tmpnam(NULL); 1278b2346922Stholo 1279b2346922Stholo outfile_hold = outfile; 1280b2346922Stholo callbacks_hold = callbacks; 1281b2346922Stholo 1282b2346922Stholo /* We want to call diff_run preserving any stdout and stderr 1283b2346922Stholo callbacks, but discarding any callbacks to handle file output, 1284b2346922Stholo since we want the file output to go to our temporary file. 1285b2346922Stholo FIXME: We should use callbacks to just read it into a memory 1286b2346922Stholo buffer; that's we do with the temporary file just below anyhow. */ 1287b2346922Stholo if (callbacks == NULL) 1288b2346922Stholo my_callbacks_arg = NULL; 1289b2346922Stholo else 1290b2346922Stholo { 1291b2346922Stholo my_callbacks = *callbacks; 1292b2346922Stholo my_callbacks.write_output = NULL; 1293b2346922Stholo my_callbacks.flush_output = NULL; 1294b2346922Stholo my_callbacks_arg = &my_callbacks; 1295b2346922Stholo } 1296b2346922Stholo 1297b2346922Stholo wstatus = diff_run (ap - argv, (char **) argv, diffout, my_callbacks_arg); 1298b2346922Stholo 1299b2346922Stholo outfile = outfile_hold; 1300b2346922Stholo callbacks = callbacks_hold; 1301b2346922Stholo 13022286d8edStholo if (wstatus == 2) 13032286d8edStholo diff3_fatal ("subsidiary diff failed"); 13042286d8edStholo 13052286d8edStholo if (-1 == (fd = open (diffout, O_RDONLY))) 13062286d8edStholo diff3_fatal ("could not open temporary diff file"); 13072286d8edStholo 13082286d8edStholo current_chunk_size = 8 * 1024; 13092286d8edStholo if (fstat (fd, &pipestat) == 0) 13102286d8edStholo current_chunk_size = max (current_chunk_size, STAT_BLOCKSIZE (pipestat)); 13112286d8edStholo 13122286d8edStholo diff_result = xmalloc (current_chunk_size); 13132286d8edStholo total = 0; 13142286d8edStholo do { 13152286d8edStholo bytes = myread (fd, 13162286d8edStholo diff_result + total, 13172286d8edStholo current_chunk_size - total); 13182286d8edStholo total += bytes; 13192286d8edStholo if (total == current_chunk_size) 13202286d8edStholo { 13212286d8edStholo if (current_chunk_size < 2 * current_chunk_size) 13222286d8edStholo current_chunk_size = 2 * current_chunk_size; 13232286d8edStholo else if (current_chunk_size < (size_t) -1) 13242286d8edStholo current_chunk_size = (size_t) -1; 13252286d8edStholo else 13262286d8edStholo diff3_fatal ("files are too large to fit into memory"); 13272286d8edStholo diff_result = xrealloc (diff_result, (current_chunk_size *= 2)); 13282286d8edStholo } 13292286d8edStholo } while (bytes); 13302286d8edStholo 13312286d8edStholo if (total != 0 && diff_result[total-1] != '\n') 13322286d8edStholo diff3_fatal ("invalid diff format; incomplete last line"); 13332286d8edStholo 13342286d8edStholo *output_placement = diff_result; 13352286d8edStholo 13362286d8edStholo if (close (fd) != 0) 13372286d8edStholo diff3_perror_with_exit ("pipe close"); 13382286d8edStholo unlink (diffout); 13392286d8edStholo 13402286d8edStholo return diff_result + total; 13412286d8edStholo } 13422286d8edStholo 13432286d8edStholo 13442286d8edStholo /* 13452286d8edStholo * Scan a regular diff line (consisting of > or <, followed by a 13462286d8edStholo * space, followed by text (including nulls) up to a newline. 13472286d8edStholo * 13482286d8edStholo * This next routine began life as a macro and many parameters in it 13492286d8edStholo * are used as call-by-reference values. 13502286d8edStholo */ 13512286d8edStholo static char * 13522286d8edStholo scan_diff_line (scan_ptr, set_start, set_length, limit, leadingchar) 13532286d8edStholo char *scan_ptr, **set_start; 13542286d8edStholo size_t *set_length; 13552286d8edStholo char *limit; 13562286d8edStholo int leadingchar; 13572286d8edStholo { 13582286d8edStholo char *line_ptr; 13592286d8edStholo 13602286d8edStholo if (!(scan_ptr[0] == leadingchar 13612286d8edStholo && scan_ptr[1] == ' ')) 13622286d8edStholo diff3_fatal ("invalid diff format; incorrect leading line chars"); 13632286d8edStholo 13642286d8edStholo *set_start = line_ptr = scan_ptr + 2; 13652286d8edStholo while (*line_ptr++ != '\n') 13662286d8edStholo ; 13672286d8edStholo 13682286d8edStholo /* Include newline if the original line ended in a newline, 13692286d8edStholo or if an edit script is being generated. 13702286d8edStholo Copy any missing newline message to stderr if an edit script is being 13712286d8edStholo generated, because edit scripts cannot handle missing newlines. 13722286d8edStholo Return the beginning of the next line. */ 13732286d8edStholo *set_length = line_ptr - *set_start; 13742286d8edStholo if (line_ptr < limit && *line_ptr == '\\') 13752286d8edStholo { 1376b2346922Stholo if (! edscript) 1377b2346922Stholo { 13782286d8edStholo --*set_length; 13792286d8edStholo line_ptr++; 1380b2346922Stholo while (*line_ptr++ != '\n') 1381b2346922Stholo ; 13822286d8edStholo } 1383b2346922Stholo else 1384b2346922Stholo { 1385b2346922Stholo char *serr; 1386b2346922Stholo 1387b2346922Stholo line_ptr++; 1388b2346922Stholo serr = line_ptr; 1389b2346922Stholo while (*line_ptr++ != '\n') 1390b2346922Stholo ; 1391b2346922Stholo line_ptr[-1] = '\0'; 1392b2346922Stholo diff_error ("%s", serr, 0); 1393b2346922Stholo line_ptr[-1] = '\n'; 1394b2346922Stholo } 13952286d8edStholo } 13962286d8edStholo 13972286d8edStholo return line_ptr; 13982286d8edStholo } 13992286d8edStholo 14002286d8edStholo /* 14012286d8edStholo * This routine outputs a three way diff passed as a list of 14022286d8edStholo * diff3_block's. 14032286d8edStholo * The argument MAPPING is indexed by external file number (in the 14042286d8edStholo * argument list) and contains the internal file number (from the 14052286d8edStholo * diff passed). This is important because the user expects his 14062286d8edStholo * outputs in terms of the argument list number, and the diff passed 14072286d8edStholo * may have been done slightly differently (if the last argument 14082286d8edStholo * was "-", for example). 14092286d8edStholo * REV_MAPPING is the inverse of MAPPING. 14102286d8edStholo */ 14112286d8edStholo static void 1412b2346922Stholo output_diff3 (diff, mapping, rev_mapping) 14132286d8edStholo struct diff3_block *diff; 14142286d8edStholo int const mapping[3], rev_mapping[3]; 14152286d8edStholo { 14162286d8edStholo int i; 14172286d8edStholo int oddoneout; 14182286d8edStholo char *cp; 14192286d8edStholo struct diff3_block *ptr; 14202286d8edStholo int line; 14212286d8edStholo size_t length; 14222286d8edStholo int dontprint; 14232286d8edStholo static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */ 14242286d8edStholo char const *line_prefix = tab_align_flag ? "\t" : " "; 14252286d8edStholo 14262286d8edStholo for (ptr = diff; ptr; ptr = D_NEXT (ptr)) 14272286d8edStholo { 14282286d8edStholo char x[2]; 14292286d8edStholo 14302286d8edStholo switch (ptr->correspond) 14312286d8edStholo { 14322286d8edStholo case DIFF_ALL: 14332286d8edStholo x[0] = '\0'; 14342286d8edStholo dontprint = 3; /* Print them all */ 14352286d8edStholo oddoneout = 3; /* Nobody's odder than anyone else */ 14362286d8edStholo break; 14372286d8edStholo case DIFF_1ST: 14382286d8edStholo case DIFF_2ND: 14392286d8edStholo case DIFF_3RD: 14402286d8edStholo oddoneout = rev_mapping[(int) ptr->correspond - (int) DIFF_1ST]; 14412286d8edStholo 14422286d8edStholo x[0] = oddoneout + '1'; 14432286d8edStholo x[1] = '\0'; 14442286d8edStholo dontprint = oddoneout==0; 14452286d8edStholo break; 14462286d8edStholo default: 14472286d8edStholo diff3_fatal ("internal error: invalid diff type passed to output"); 14482286d8edStholo } 1449b2346922Stholo printf_output ("====%s\n", x); 14502286d8edStholo 14512286d8edStholo /* Go 0, 2, 1 if the first and third outputs are equivalent. */ 14522286d8edStholo for (i = 0; i < 3; 14532286d8edStholo i = (oddoneout == 1 ? skew_increment[i] : i + 1)) 14542286d8edStholo { 14552286d8edStholo int realfile = mapping[i]; 14562286d8edStholo int 14572286d8edStholo lowt = D_LOWLINE (ptr, realfile), 14582286d8edStholo hight = D_HIGHLINE (ptr, realfile); 14592286d8edStholo 1460b2346922Stholo printf_output ("%d:", i + 1); 14612286d8edStholo switch (lowt - hight) 14622286d8edStholo { 14632286d8edStholo case 1: 1464b2346922Stholo printf_output ("%da\n", lowt - 1); 14652286d8edStholo break; 14662286d8edStholo case 0: 1467b2346922Stholo printf_output ("%dc\n", lowt); 14682286d8edStholo break; 14692286d8edStholo default: 1470b2346922Stholo printf_output ("%d,%dc\n", lowt, hight); 14712286d8edStholo break; 14722286d8edStholo } 14732286d8edStholo 14742286d8edStholo if (i == dontprint) continue; 14752286d8edStholo 14762286d8edStholo if (lowt <= hight) 14772286d8edStholo { 14782286d8edStholo line = 0; 14792286d8edStholo do 14802286d8edStholo { 1481b2346922Stholo printf_output (line_prefix); 14822286d8edStholo cp = D_RELNUM (ptr, realfile, line); 14832286d8edStholo length = D_RELLEN (ptr, realfile, line); 1484b2346922Stholo write_output (cp, length); 14852286d8edStholo } 14862286d8edStholo while (++line < hight - lowt + 1); 14872286d8edStholo if (cp[length - 1] != '\n') 1488b2346922Stholo printf_output ("\n\\ No newline at end of file\n"); 14892286d8edStholo } 14902286d8edStholo } 14912286d8edStholo } 14922286d8edStholo } 14932286d8edStholo 14942286d8edStholo 14952286d8edStholo /* 1496b2346922Stholo * Output the lines of B taken from FILENUM. 14972286d8edStholo * Double any initial '.'s; yield nonzero if any initial '.'s were doubled. 14982286d8edStholo */ 14992286d8edStholo static int 1500b2346922Stholo dotlines (b, filenum) 15012286d8edStholo struct diff3_block *b; 15022286d8edStholo int filenum; 15032286d8edStholo { 15042286d8edStholo int i; 15052286d8edStholo int leading_dot = 0; 15062286d8edStholo 15072286d8edStholo for (i = 0; 15082286d8edStholo i < D_NUMLINES (b, filenum); 15092286d8edStholo i++) 15102286d8edStholo { 15112286d8edStholo char *line = D_RELNUM (b, filenum, i); 15122286d8edStholo if (line[0] == '.') 15132286d8edStholo { 15142286d8edStholo leading_dot = 1; 1515b2346922Stholo write_output (".", 1); 15162286d8edStholo } 1517b2346922Stholo write_output (line, D_RELLEN (b, filenum, i)); 15182286d8edStholo } 15192286d8edStholo 15202286d8edStholo return leading_dot; 15212286d8edStholo } 15222286d8edStholo 15232286d8edStholo /* 15242286d8edStholo * Output to OUTPUTFILE a '.' line. If LEADING_DOT is nonzero, 15252286d8edStholo * also output a command that removes initial '.'s 15262286d8edStholo * starting with line START and continuing for NUM lines. 15272286d8edStholo */ 15282286d8edStholo static void 1529b2346922Stholo undotlines (leading_dot, start, num) 15302286d8edStholo int leading_dot, start, num; 15312286d8edStholo { 1532b2346922Stholo write_output (".\n", 2); 15332286d8edStholo if (leading_dot) 15342286d8edStholo if (num == 1) 1535b2346922Stholo printf_output ("%ds/^\\.//\n", start); 15362286d8edStholo else 1537b2346922Stholo printf_output ("%d,%ds/^\\.//\n", start, start + num - 1); 15382286d8edStholo } 15392286d8edStholo 15402286d8edStholo /* 15412286d8edStholo * This routine outputs a diff3 set of blocks as an ed script. This 15422286d8edStholo * script applies the changes between file's 2 & 3 to file 1. It 15432286d8edStholo * takes the precise format of the ed script to be output from global 15442286d8edStholo * variables set during options processing. Note that it does 15452286d8edStholo * destructive things to the set of diff3 blocks it is passed; it 15462286d8edStholo * reverses their order (this gets around the problems involved with 15472286d8edStholo * changing line numbers in an ed script). 15482286d8edStholo * 15492286d8edStholo * Note that this routine has the same problem of mapping as the last 15502286d8edStholo * one did; the variable MAPPING maps from file number according to 15512286d8edStholo * the argument list to file number according to the diff passed. All 15522286d8edStholo * files listed below are in terms of the argument list. 15532286d8edStholo * REV_MAPPING is the inverse of MAPPING. 15542286d8edStholo * 15552286d8edStholo * The arguments FILE0, FILE1 and FILE2 are the strings to print 15562286d8edStholo * as the names of the three files. These may be the actual names, 15572286d8edStholo * or may be the arguments specified with -L. 15582286d8edStholo * 15592286d8edStholo * Returns 1 if conflicts were found. 15602286d8edStholo */ 15612286d8edStholo 15622286d8edStholo static int 1563b2346922Stholo output_diff3_edscript (diff, mapping, rev_mapping, file0, file1, file2) 15642286d8edStholo struct diff3_block *diff; 15652286d8edStholo int const mapping[3], rev_mapping[3]; 15662286d8edStholo char const *file0, *file1, *file2; 15672286d8edStholo { 15682286d8edStholo int leading_dot; 15692286d8edStholo int conflicts_found = 0, conflict; 15702286d8edStholo struct diff3_block *b; 15712286d8edStholo 15722286d8edStholo for (b = reverse_diff3_blocklist (diff); b; b = b->next) 15732286d8edStholo { 15742286d8edStholo /* Must do mapping correctly. */ 15752286d8edStholo enum diff_type type 15762286d8edStholo = ((b->correspond == DIFF_ALL) ? 15772286d8edStholo DIFF_ALL : 15782286d8edStholo ((enum diff_type) 15792286d8edStholo (((int) DIFF_1ST) 15802286d8edStholo + rev_mapping[(int) b->correspond - (int) DIFF_1ST]))); 15812286d8edStholo 15822286d8edStholo /* If we aren't supposed to do this output block, skip it. */ 15832286d8edStholo switch (type) 15842286d8edStholo { 15852286d8edStholo default: continue; 15862286d8edStholo case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break; 15872286d8edStholo case DIFF_3RD: if (overlap_only) continue; conflict = 0; break; 15882286d8edStholo case DIFF_ALL: if (simple_only) continue; conflict = flagging; break; 15892286d8edStholo } 15902286d8edStholo 15912286d8edStholo if (conflict) 15922286d8edStholo { 15932286d8edStholo conflicts_found = 1; 15942286d8edStholo 15952286d8edStholo 15962286d8edStholo /* Mark end of conflict. */ 15972286d8edStholo 1598b2346922Stholo printf_output ("%da\n", D_HIGHLINE (b, mapping[FILE0])); 15992286d8edStholo leading_dot = 0; 16002286d8edStholo if (type == DIFF_ALL) 16012286d8edStholo { 16022286d8edStholo if (show_2nd) 16032286d8edStholo { 16042286d8edStholo /* Append lines from FILE1. */ 1605b2346922Stholo printf_output ("||||||| %s\n", file1); 1606b2346922Stholo leading_dot = dotlines (b, mapping[FILE1]); 16072286d8edStholo } 16082286d8edStholo /* Append lines from FILE2. */ 1609b2346922Stholo printf_output ("=======\n"); 1610b2346922Stholo leading_dot |= dotlines (b, mapping[FILE2]); 16112286d8edStholo } 1612b2346922Stholo printf_output (">>>>>>> %s\n", file2); 1613b2346922Stholo undotlines (leading_dot, 16142286d8edStholo D_HIGHLINE (b, mapping[FILE0]) + 2, 16152286d8edStholo (D_NUMLINES (b, mapping[FILE1]) 16162286d8edStholo + D_NUMLINES (b, mapping[FILE2]) + 1)); 16172286d8edStholo 16182286d8edStholo 16192286d8edStholo /* Mark start of conflict. */ 16202286d8edStholo 1621b2346922Stholo printf_output ("%da\n<<<<<<< %s\n", 16222286d8edStholo D_LOWLINE (b, mapping[FILE0]) - 1, 16232286d8edStholo type == DIFF_ALL ? file0 : file1); 16242286d8edStholo leading_dot = 0; 16252286d8edStholo if (type == DIFF_2ND) 16262286d8edStholo { 16272286d8edStholo /* Prepend lines from FILE1. */ 1628b2346922Stholo leading_dot = dotlines (b, mapping[FILE1]); 1629b2346922Stholo printf_output ("=======\n"); 16302286d8edStholo } 1631b2346922Stholo undotlines (leading_dot, 16322286d8edStholo D_LOWLINE (b, mapping[FILE0]) + 1, 16332286d8edStholo D_NUMLINES (b, mapping[FILE1])); 16342286d8edStholo } 16352286d8edStholo else if (D_NUMLINES (b, mapping[FILE2]) == 0) 16362286d8edStholo /* Write out a delete */ 16372286d8edStholo { 16382286d8edStholo if (D_NUMLINES (b, mapping[FILE0]) == 1) 1639b2346922Stholo printf_output ("%dd\n", D_LOWLINE (b, mapping[FILE0])); 16402286d8edStholo else 1641b2346922Stholo printf_output ("%d,%dd\n", 16422286d8edStholo D_LOWLINE (b, mapping[FILE0]), 16432286d8edStholo D_HIGHLINE (b, mapping[FILE0])); 16442286d8edStholo } 16452286d8edStholo else 16462286d8edStholo /* Write out an add or change */ 16472286d8edStholo { 16482286d8edStholo switch (D_NUMLINES (b, mapping[FILE0])) 16492286d8edStholo { 16502286d8edStholo case 0: 1651b2346922Stholo printf_output ("%da\n", D_HIGHLINE (b, mapping[FILE0])); 16522286d8edStholo break; 16532286d8edStholo case 1: 1654b2346922Stholo printf_output ("%dc\n", D_HIGHLINE (b, mapping[FILE0])); 16552286d8edStholo break; 16562286d8edStholo default: 1657b2346922Stholo printf_output ("%d,%dc\n", 16582286d8edStholo D_LOWLINE (b, mapping[FILE0]), 16592286d8edStholo D_HIGHLINE (b, mapping[FILE0])); 16602286d8edStholo break; 16612286d8edStholo } 16622286d8edStholo 1663b2346922Stholo undotlines (dotlines (b, mapping[FILE2]), 16642286d8edStholo D_LOWLINE (b, mapping[FILE0]), 16652286d8edStholo D_NUMLINES (b, mapping[FILE2])); 16662286d8edStholo } 16672286d8edStholo } 1668b2346922Stholo if (finalwrite) printf_output ("w\nq\n"); 16692286d8edStholo return conflicts_found; 16702286d8edStholo } 16712286d8edStholo 16722286d8edStholo /* 1673b2346922Stholo * Read from INFILE and output to the standard output file a set of 1674b2346922Stholo * diff3_ blocks DIFF as a merged file. This acts like 'ed file0 1675b2346922Stholo * <[output_diff3_edscript]', except that it works even for binary 1676b2346922Stholo * data or incomplete lines. 16772286d8edStholo * 16782286d8edStholo * As before, MAPPING maps from arg list file number to diff file number, 16792286d8edStholo * REV_MAPPING is its inverse, 16802286d8edStholo * and FILE0, FILE1, and FILE2 are the names of the files. 16812286d8edStholo * 16822286d8edStholo * Returns 1 if conflicts were found. 16832286d8edStholo */ 16842286d8edStholo 16852286d8edStholo static int 1686b2346922Stholo output_diff3_merge (infile, diff, mapping, rev_mapping, 16872286d8edStholo file0, file1, file2) 1688b2346922Stholo FILE *infile; 16892286d8edStholo struct diff3_block *diff; 16902286d8edStholo int const mapping[3], rev_mapping[3]; 16912286d8edStholo char const *file0, *file1, *file2; 16922286d8edStholo { 16932286d8edStholo int c, i; 1694b2346922Stholo char cc; 16952286d8edStholo int conflicts_found = 0, conflict; 16962286d8edStholo struct diff3_block *b; 16972286d8edStholo int linesread = 0; 16982286d8edStholo 16992286d8edStholo for (b = diff; b; b = b->next) 17002286d8edStholo { 17012286d8edStholo /* Must do mapping correctly. */ 17022286d8edStholo enum diff_type type 17032286d8edStholo = ((b->correspond == DIFF_ALL) ? 17042286d8edStholo DIFF_ALL : 17052286d8edStholo ((enum diff_type) 17062286d8edStholo (((int) DIFF_1ST) 17072286d8edStholo + rev_mapping[(int) b->correspond - (int) DIFF_1ST]))); 17082286d8edStholo char const *format_2nd = "<<<<<<< %s\n"; 17092286d8edStholo 17102286d8edStholo /* If we aren't supposed to do this output block, skip it. */ 17112286d8edStholo switch (type) 17122286d8edStholo { 17132286d8edStholo default: continue; 17142286d8edStholo case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break; 17152286d8edStholo case DIFF_3RD: if (overlap_only) continue; conflict = 0; break; 17162286d8edStholo case DIFF_ALL: if (simple_only) continue; conflict = flagging; 17172286d8edStholo format_2nd = "||||||| %s\n"; 17182286d8edStholo break; 17192286d8edStholo } 17202286d8edStholo 17212286d8edStholo /* Copy I lines from file 0. */ 17222286d8edStholo i = D_LOWLINE (b, FILE0) - linesread - 1; 17232286d8edStholo linesread += i; 17242286d8edStholo while (0 <= --i) 17252286d8edStholo do 17262286d8edStholo { 17272286d8edStholo c = getc (infile); 17282286d8edStholo if (c == EOF) 17292286d8edStholo if (ferror (infile)) 17302286d8edStholo diff3_perror_with_exit ("input file"); 17312286d8edStholo else if (feof (infile)) 17322286d8edStholo diff3_fatal ("input file shrank"); 1733b2346922Stholo cc = c; 1734b2346922Stholo write_output (&cc, 1); 17352286d8edStholo } 17362286d8edStholo while (c != '\n'); 17372286d8edStholo 17382286d8edStholo if (conflict) 17392286d8edStholo { 17402286d8edStholo conflicts_found = 1; 17412286d8edStholo 17422286d8edStholo if (type == DIFF_ALL) 17432286d8edStholo { 17442286d8edStholo /* Put in lines from FILE0 with bracket. */ 1745b2346922Stholo printf_output ("<<<<<<< %s\n", file0); 17462286d8edStholo for (i = 0; 17472286d8edStholo i < D_NUMLINES (b, mapping[FILE0]); 17482286d8edStholo i++) 1749b2346922Stholo write_output (D_RELNUM (b, mapping[FILE0], i), 1750b2346922Stholo D_RELLEN (b, mapping[FILE0], i)); 17512286d8edStholo } 17522286d8edStholo 17532286d8edStholo if (show_2nd) 17542286d8edStholo { 17552286d8edStholo /* Put in lines from FILE1 with bracket. */ 1756b2346922Stholo printf_output (format_2nd, file1); 17572286d8edStholo for (i = 0; 17582286d8edStholo i < D_NUMLINES (b, mapping[FILE1]); 17592286d8edStholo i++) 1760b2346922Stholo write_output (D_RELNUM (b, mapping[FILE1], i), 1761b2346922Stholo D_RELLEN (b, mapping[FILE1], i)); 17622286d8edStholo } 17632286d8edStholo 1764b2346922Stholo printf_output ("=======\n"); 17652286d8edStholo } 17662286d8edStholo 17672286d8edStholo /* Put in lines from FILE2. */ 17682286d8edStholo for (i = 0; 17692286d8edStholo i < D_NUMLINES (b, mapping[FILE2]); 17702286d8edStholo i++) 1771b2346922Stholo write_output (D_RELNUM (b, mapping[FILE2], i), 1772b2346922Stholo D_RELLEN (b, mapping[FILE2], i)); 17732286d8edStholo 17742286d8edStholo if (conflict) 1775b2346922Stholo printf_output (">>>>>>> %s\n", file2); 17762286d8edStholo 17772286d8edStholo /* Skip I lines in file 0. */ 17782286d8edStholo i = D_NUMLINES (b, FILE0); 17792286d8edStholo linesread += i; 17802286d8edStholo while (0 <= --i) 17812286d8edStholo while ((c = getc (infile)) != '\n') 17822286d8edStholo if (c == EOF) 17832286d8edStholo if (ferror (infile)) 17842286d8edStholo diff3_perror_with_exit ("input file"); 17852286d8edStholo else if (feof (infile)) 17862286d8edStholo { 17872286d8edStholo if (i || b->next) 17882286d8edStholo diff3_fatal ("input file shrank"); 17892286d8edStholo return conflicts_found; 17902286d8edStholo } 17912286d8edStholo } 17922286d8edStholo /* Copy rest of common file. */ 17932286d8edStholo while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile))) 1794b2346922Stholo { 1795b2346922Stholo cc = c; 1796b2346922Stholo write_output (&cc, 1); 1797b2346922Stholo } 17982286d8edStholo return conflicts_found; 17992286d8edStholo } 18002286d8edStholo 18012286d8edStholo /* 18022286d8edStholo * Reverse the order of the list of diff3 blocks. 18032286d8edStholo */ 18042286d8edStholo static struct diff3_block * 18052286d8edStholo reverse_diff3_blocklist (diff) 18062286d8edStholo struct diff3_block *diff; 18072286d8edStholo { 18082286d8edStholo register struct diff3_block *tmp, *next, *prev; 18092286d8edStholo 18102286d8edStholo for (tmp = diff, prev = 0; tmp; tmp = next) 18112286d8edStholo { 18122286d8edStholo next = tmp->next; 18132286d8edStholo tmp->next = prev; 18142286d8edStholo prev = tmp; 18152286d8edStholo } 18162286d8edStholo 18172286d8edStholo return prev; 18182286d8edStholo } 18192286d8edStholo 18202286d8edStholo static size_t 18212286d8edStholo myread (fd, ptr, size) 18222286d8edStholo int fd; 18232286d8edStholo char *ptr; 18242286d8edStholo size_t size; 18252286d8edStholo { 18262286d8edStholo size_t result = read (fd, ptr, size); 18272286d8edStholo if (result == -1) 18282286d8edStholo diff3_perror_with_exit ("read failed"); 18292286d8edStholo return result; 18302286d8edStholo } 18312286d8edStholo 18322286d8edStholo static void 18332286d8edStholo diff3_fatal (string) 18342286d8edStholo char const *string; 18352286d8edStholo { 1836b2346922Stholo diff_error ("%s", string, 0); 18372286d8edStholo DIFF3_ABORT (2); 18382286d8edStholo } 18392286d8edStholo 18402286d8edStholo static void 18412286d8edStholo diff3_perror_with_exit (string) 18422286d8edStholo char const *string; 18432286d8edStholo { 1844b2346922Stholo perror_with_name (string); 18452286d8edStholo DIFF3_ABORT (2); 18462286d8edStholo } 18472286d8edStholo 18482286d8edStholo static void 18492286d8edStholo initialize_main (argcp, argvp) 18502286d8edStholo int *argcp; 18512286d8edStholo char ***argvp; 18522286d8edStholo { 18532286d8edStholo always_text = 0; 18542286d8edStholo edscript = 0; 18552286d8edStholo flagging = 0; 18562286d8edStholo horizon_lines = 10; 18572286d8edStholo tab_align_flag = 0; 18582286d8edStholo simple_only = 0; 18592286d8edStholo overlap_only = 0; 18602286d8edStholo show_2nd = 0; 18612286d8edStholo finalwrite = 0; 18622286d8edStholo merge = 0; 18632286d8edStholo diff_program_name = (*argvp)[0]; 1864b2346922Stholo outfile = NULL; 18652286d8edStholo } 18662286d8edStholo 18672286d8edStholo static void 18682286d8edStholo free_diff_blocks(p) 18692286d8edStholo struct diff_block *p; 18702286d8edStholo { 18712286d8edStholo register struct diff_block *next; 18722286d8edStholo 18732286d8edStholo while (p) 18742286d8edStholo { 18752286d8edStholo next = p->next; 18762286d8edStholo if (p->lines[0]) free(p->lines[0]); 18772286d8edStholo if (p->lines[1]) free(p->lines[1]); 18782286d8edStholo if (p->lengths[0]) free(p->lengths[0]); 18792286d8edStholo if (p->lengths[1]) free(p->lengths[1]); 18802286d8edStholo free(p); 18812286d8edStholo p = next; 18822286d8edStholo } 18832286d8edStholo } 18842286d8edStholo 18852286d8edStholo static void 18862286d8edStholo free_diff3_blocks(p) 18872286d8edStholo struct diff3_block *p; 18882286d8edStholo { 18892286d8edStholo register struct diff3_block *next; 18902286d8edStholo 18912286d8edStholo while (p) 18922286d8edStholo { 18932286d8edStholo next = p->next; 18942286d8edStholo if (p->lines[0]) free(p->lines[0]); 18952286d8edStholo if (p->lines[1]) free(p->lines[1]); 18962286d8edStholo if (p->lines[2]) free(p->lines[2]); 18972286d8edStholo if (p->lengths[0]) free(p->lengths[0]); 18982286d8edStholo if (p->lengths[1]) free(p->lengths[1]); 18992286d8edStholo if (p->lengths[2]) free(p->lengths[2]); 19002286d8edStholo free(p); 19012286d8edStholo p = next; 19022286d8edStholo } 19032286d8edStholo } 1904