xref: /openbsd-src/gnu/usr.bin/cvs/diff/side.c (revision b2346922a76a50a89e33beab4ebbc0950de8a8df)
12286d8edStholo /* sdiff-format output routines for GNU DIFF.
2*b2346922Stholo    Copyright (C) 1991, 1992, 1993, 1998 Free Software Foundation, Inc.
32286d8edStholo 
42286d8edStholo This file is part of GNU DIFF.
52286d8edStholo 
62286d8edStholo GNU DIFF is distributed in the hope that it will be useful,
72286d8edStholo but WITHOUT ANY WARRANTY.  No author or distributor
82286d8edStholo accepts responsibility to anyone for the consequences of using it
92286d8edStholo or for whether it serves any particular purpose or works at all,
102286d8edStholo unless he says so in writing.  Refer to the GNU DIFF General Public
112286d8edStholo License for full details.
122286d8edStholo 
132286d8edStholo Everyone is granted permission to copy, modify and redistribute
142286d8edStholo GNU DIFF, but only under the conditions described in the
152286d8edStholo GNU DIFF General Public License.   A copy of this license is
162286d8edStholo supposed to have been given to you along with GNU DIFF so you
172286d8edStholo can know your rights and responsibilities.  It should be in a
182286d8edStholo file named COPYING.  Among other things, the copyright notice
192286d8edStholo and this notice must be preserved on all copies.  */
202286d8edStholo 
212286d8edStholo 
222286d8edStholo #include "diff.h"
232286d8edStholo 
242286d8edStholo static unsigned print_half_line PARAMS((char const * const *, unsigned, unsigned));
252286d8edStholo static unsigned tab_from_to PARAMS((unsigned, unsigned));
262286d8edStholo static void print_1sdiff_line PARAMS((char const * const *, int, char const * const *));
272286d8edStholo static void print_sdiff_common_lines PARAMS((int, int));
282286d8edStholo static void print_sdiff_hunk PARAMS((struct change *));
292286d8edStholo 
302286d8edStholo /* Next line number to be printed in the two input files.  */
312286d8edStholo static int next0, next1;
322286d8edStholo 
332286d8edStholo /* Print the edit-script SCRIPT as a sdiff style output.  */
342286d8edStholo 
352286d8edStholo void
362286d8edStholo print_sdiff_script (script)
372286d8edStholo      struct change *script;
382286d8edStholo {
392286d8edStholo   begin_output ();
402286d8edStholo 
412286d8edStholo   next0 = next1 = - files[0].prefix_lines;
422286d8edStholo   print_script (script, find_change, print_sdiff_hunk);
432286d8edStholo 
442286d8edStholo   print_sdiff_common_lines (files[0].valid_lines, files[1].valid_lines);
452286d8edStholo }
462286d8edStholo 
472286d8edStholo /* Tab from column FROM to column TO, where FROM <= TO.  Yield TO.  */
482286d8edStholo 
492286d8edStholo static unsigned
502286d8edStholo tab_from_to (from, to)
512286d8edStholo      unsigned from, to;
522286d8edStholo {
532286d8edStholo   unsigned tab;
542286d8edStholo 
552286d8edStholo   if (! tab_expand_flag)
562286d8edStholo     for (tab = from + TAB_WIDTH - from % TAB_WIDTH;  tab <= to;  tab += TAB_WIDTH)
572286d8edStholo       {
58*b2346922Stholo 	write_output ("\t", 1);
592286d8edStholo 	from = tab;
602286d8edStholo       }
612286d8edStholo   while (from++ < to)
62*b2346922Stholo     write_output (" ", 1);
632286d8edStholo   return to;
642286d8edStholo }
652286d8edStholo 
662286d8edStholo /*
672286d8edStholo  * Print the text for half an sdiff line.  This means truncate to width
682286d8edStholo  * observing tabs, and trim a trailing newline.  Returns the last column
692286d8edStholo  * written (not the number of chars).
702286d8edStholo  */
712286d8edStholo static unsigned
722286d8edStholo print_half_line (line, indent, out_bound)
732286d8edStholo      char const * const *line;
742286d8edStholo      unsigned indent, out_bound;
752286d8edStholo {
762286d8edStholo   register unsigned in_position = 0, out_position = 0;
772286d8edStholo   register char const
782286d8edStholo 	*text_pointer = line[0],
792286d8edStholo 	*text_limit = line[1];
802286d8edStholo 
812286d8edStholo   while (text_pointer < text_limit)
822286d8edStholo     {
832286d8edStholo       register unsigned char c = *text_pointer++;
84*b2346922Stholo       /* We use CC to avoid taking the address of the register
85*b2346922Stholo          variable C.  */
86*b2346922Stholo       char cc;
872286d8edStholo 
882286d8edStholo       switch (c)
892286d8edStholo 	{
902286d8edStholo 	case '\t':
912286d8edStholo 	  {
922286d8edStholo 	    unsigned spaces = TAB_WIDTH - in_position % TAB_WIDTH;
932286d8edStholo 	    if (in_position == out_position)
942286d8edStholo 	      {
952286d8edStholo 		unsigned tabstop = out_position + spaces;
962286d8edStholo 		if (tab_expand_flag)
972286d8edStholo 		  {
982286d8edStholo 		    if (out_bound < tabstop)
992286d8edStholo 		      tabstop = out_bound;
1002286d8edStholo 		    for (;  out_position < tabstop;  out_position++)
101*b2346922Stholo 		      write_output (" ", 1);
1022286d8edStholo 		  }
1032286d8edStholo 		else
1042286d8edStholo 		  if (tabstop < out_bound)
1052286d8edStholo 		    {
1062286d8edStholo 		      out_position = tabstop;
107*b2346922Stholo 		      cc = c;
108*b2346922Stholo 		      write_output (&cc, 1);
1092286d8edStholo 		    }
1102286d8edStholo 	      }
1112286d8edStholo 	    in_position += spaces;
1122286d8edStholo 	  }
1132286d8edStholo 	  break;
1142286d8edStholo 
1152286d8edStholo 	case '\r':
1162286d8edStholo 	  {
117*b2346922Stholo 	    cc = c;
118*b2346922Stholo 	    write_output (&cc, 1);
1192286d8edStholo 	    tab_from_to (0, indent);
1202286d8edStholo 	    in_position = out_position = 0;
1212286d8edStholo 	  }
1222286d8edStholo 	  break;
1232286d8edStholo 
1242286d8edStholo 	case '\b':
1252286d8edStholo 	  if (in_position != 0 && --in_position < out_bound)
1262286d8edStholo 	    if (out_position <= in_position)
1272286d8edStholo 	      /* Add spaces to make up for suppressed tab past out_bound.  */
1282286d8edStholo 	      for (;  out_position < in_position;  out_position++)
129*b2346922Stholo 		write_output (" ", 1);
1302286d8edStholo 	    else
1312286d8edStholo 	      {
1322286d8edStholo 		out_position = in_position;
133*b2346922Stholo 		cc = c;
134*b2346922Stholo 		write_output (&cc, 1);
1352286d8edStholo 	      }
1362286d8edStholo 	  break;
1372286d8edStholo 
1382286d8edStholo 	case '\f':
1392286d8edStholo 	case '\v':
1402286d8edStholo 	control_char:
1412286d8edStholo 	  if (in_position < out_bound)
142*b2346922Stholo 	    {
143*b2346922Stholo 	      cc = c;
144*b2346922Stholo 	      write_output (&cc, 1);
145*b2346922Stholo 	    }
1462286d8edStholo 	  break;
1472286d8edStholo 
1482286d8edStholo 	default:
1492286d8edStholo 	  if (! ISPRINT (c))
1502286d8edStholo 	    goto control_char;
1512286d8edStholo 	  /* falls through */
1522286d8edStholo 	case ' ':
1532286d8edStholo 	  if (in_position++ < out_bound)
1542286d8edStholo 	    {
1552286d8edStholo 	      out_position = in_position;
156*b2346922Stholo 	      cc = c;
157*b2346922Stholo 	      write_output (&cc, 1);
1582286d8edStholo 	    }
1592286d8edStholo 	  break;
1602286d8edStholo 
1612286d8edStholo 	case '\n':
1622286d8edStholo 	  return out_position;
1632286d8edStholo 	}
1642286d8edStholo     }
1652286d8edStholo 
1662286d8edStholo   return out_position;
1672286d8edStholo }
1682286d8edStholo 
1692286d8edStholo /*
1702286d8edStholo  * Print side by side lines with a separator in the middle.
1712286d8edStholo  * 0 parameters are taken to indicate white space text.
1722286d8edStholo  * Blank lines that can easily be caught are reduced to a single newline.
1732286d8edStholo  */
1742286d8edStholo 
1752286d8edStholo static void
1762286d8edStholo print_1sdiff_line (left, sep, right)
1772286d8edStholo      char const * const *left;
1782286d8edStholo      int sep;
1792286d8edStholo      char const * const *right;
1802286d8edStholo {
1812286d8edStholo   unsigned hw = sdiff_half_width, c2o = sdiff_column2_offset;
1822286d8edStholo   unsigned col = 0;
1832286d8edStholo   int put_newline = 0;
1842286d8edStholo 
1852286d8edStholo   if (left)
1862286d8edStholo     {
1872286d8edStholo       if (left[1][-1] == '\n')
1882286d8edStholo 	put_newline = 1;
1892286d8edStholo       col = print_half_line (left, 0, hw);
1902286d8edStholo     }
1912286d8edStholo 
1922286d8edStholo   if (sep != ' ')
1932286d8edStholo     {
194*b2346922Stholo       char cc;
195*b2346922Stholo 
1962286d8edStholo       col = tab_from_to (col, (hw + c2o - 1) / 2) + 1;
1972286d8edStholo       if (sep == '|' && put_newline != (right[1][-1] == '\n'))
1982286d8edStholo 	sep = put_newline ? '/' : '\\';
199*b2346922Stholo       cc = sep;
200*b2346922Stholo       write_output (&cc, 1);
2012286d8edStholo     }
2022286d8edStholo 
2032286d8edStholo   if (right)
2042286d8edStholo     {
2052286d8edStholo       if (right[1][-1] == '\n')
2062286d8edStholo 	put_newline = 1;
2072286d8edStholo       if (**right != '\n')
2082286d8edStholo 	{
2092286d8edStholo 	  col = tab_from_to (col, c2o);
2102286d8edStholo 	  print_half_line (right, col, hw);
2112286d8edStholo 	}
2122286d8edStholo     }
2132286d8edStholo 
2142286d8edStholo   if (put_newline)
215*b2346922Stholo     write_output ("\n", 1);
2162286d8edStholo }
2172286d8edStholo 
2182286d8edStholo /* Print lines common to both files in side-by-side format.  */
2192286d8edStholo static void
2202286d8edStholo print_sdiff_common_lines (limit0, limit1)
2212286d8edStholo      int limit0, limit1;
2222286d8edStholo {
2232286d8edStholo   int i0 = next0, i1 = next1;
2242286d8edStholo 
2252286d8edStholo   if (! sdiff_skip_common_lines  &&  (i0 != limit0 || i1 != limit1))
2262286d8edStholo     {
2272286d8edStholo       if (sdiff_help_sdiff)
228*b2346922Stholo 	printf_output ("i%d,%d\n", limit0 - i0, limit1 - i1);
2292286d8edStholo 
2302286d8edStholo       if (! sdiff_left_only)
2312286d8edStholo 	{
2322286d8edStholo 	  while (i0 != limit0 && i1 != limit1)
2332286d8edStholo 	    print_1sdiff_line (&files[0].linbuf[i0++], ' ', &files[1].linbuf[i1++]);
2342286d8edStholo 	  while (i1 != limit1)
2352286d8edStholo 	    print_1sdiff_line (0, ')', &files[1].linbuf[i1++]);
2362286d8edStholo 	}
2372286d8edStholo       while (i0 != limit0)
2382286d8edStholo 	print_1sdiff_line (&files[0].linbuf[i0++], '(', 0);
2392286d8edStholo     }
2402286d8edStholo 
2412286d8edStholo   next0 = limit0;
2422286d8edStholo   next1 = limit1;
2432286d8edStholo }
2442286d8edStholo 
2452286d8edStholo /* Print a hunk of an sdiff diff.
2462286d8edStholo    This is a contiguous portion of a complete edit script,
2472286d8edStholo    describing changes in consecutive lines.  */
2482286d8edStholo 
2492286d8edStholo static void
2502286d8edStholo print_sdiff_hunk (hunk)
2512286d8edStholo      struct change *hunk;
2522286d8edStholo {
2532286d8edStholo   int first0, last0, first1, last1, deletes, inserts;
2542286d8edStholo   register int i, j;
2552286d8edStholo 
2562286d8edStholo   /* Determine range of line numbers involved in each file.  */
2572286d8edStholo   analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
2582286d8edStholo   if (!deletes && !inserts)
2592286d8edStholo     return;
2602286d8edStholo 
2612286d8edStholo   /* Print out lines up to this change.  */
2622286d8edStholo   print_sdiff_common_lines (first0, first1);
2632286d8edStholo 
2642286d8edStholo   if (sdiff_help_sdiff)
265*b2346922Stholo     printf_output ("c%d,%d\n", last0 - first0 + 1, last1 - first1 + 1);
2662286d8edStholo 
2672286d8edStholo   /* Print ``xxx  |  xxx '' lines */
2682286d8edStholo   if (inserts && deletes)
2692286d8edStholo     {
2702286d8edStholo       for (i = first0, j = first1;  i <= last0 && j <= last1; ++i, ++j)
2712286d8edStholo 	print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]);
2722286d8edStholo       deletes = i <= last0;
2732286d8edStholo       inserts = j <= last1;
2742286d8edStholo       next0 = first0 = i;
2752286d8edStholo       next1 = first1 = j;
2762286d8edStholo     }
2772286d8edStholo 
2782286d8edStholo 
2792286d8edStholo   /* Print ``     >  xxx '' lines */
2802286d8edStholo   if (inserts)
2812286d8edStholo     {
2822286d8edStholo       for (j = first1; j <= last1; ++j)
2832286d8edStholo 	print_1sdiff_line (0, '>', &files[1].linbuf[j]);
2842286d8edStholo       next1 = j;
2852286d8edStholo     }
2862286d8edStholo 
2872286d8edStholo   /* Print ``xxx  <     '' lines */
2882286d8edStholo   if (deletes)
2892286d8edStholo     {
2902286d8edStholo       for (i = first0; i <= last0; ++i)
2912286d8edStholo 	print_1sdiff_line (&files[0].linbuf[i], '<', 0);
2922286d8edStholo       next0 = i;
2932286d8edStholo     }
2942286d8edStholo }
295