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