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