xref: /openbsd-src/gnu/usr.bin/cvs/diff/side.c (revision 0971b67f68eabe84e58ba202abe73d50c878d1ac)
12286d8edStholo /* sdiff-format output routines for GNU DIFF.
2b2346922Stholo    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
print_sdiff_script(script)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
tab_from_to(from,to)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       {
58b2346922Stholo 	write_output ("\t", 1);
592286d8edStholo 	from = tab;
602286d8edStholo       }
612286d8edStholo   while (from++ < to)
62b2346922Stholo     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
print_half_line(line,indent,out_bound)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++;
84b2346922Stholo       /* We use CC to avoid taking the address of the register
85b2346922Stholo          variable C.  */
86b2346922Stholo       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++)
101b2346922Stholo 		      write_output (" ", 1);
1022286d8edStholo 		  }
1032286d8edStholo 		else
1042286d8edStholo 		  if (tabstop < out_bound)
1052286d8edStholo 		    {
1062286d8edStholo 		      out_position = tabstop;
107b2346922Stholo 		      cc = c;
108b2346922Stholo 		      write_output (&cc, 1);
1092286d8edStholo 		    }
1102286d8edStholo 	      }
1112286d8edStholo 	    in_position += spaces;
1122286d8edStholo 	  }
1132286d8edStholo 	  break;
1142286d8edStholo 
1152286d8edStholo 	case '\r':
1162286d8edStholo 	  {
117b2346922Stholo 	    cc = c;
118b2346922Stholo 	    write_output (&cc, 1);
1192286d8edStholo 	    tab_from_to (0, indent);
1202286d8edStholo 	    in_position = out_position = 0;
1212286d8edStholo 	  }
1222286d8edStholo 	  break;
1232286d8edStholo 
1242286d8edStholo 	case '\b':
125*0971b67fStb 	  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++)
129b2346922Stholo 		write_output (" ", 1);
1302286d8edStholo 	    else
1312286d8edStholo 	      {
1322286d8edStholo 		out_position = in_position;
133b2346922Stholo 		cc = c;
134b2346922Stholo 		write_output (&cc, 1);
1352286d8edStholo 	      }
136*0971b67fStb 	  }
1372286d8edStholo 	  break;
1382286d8edStholo 
1392286d8edStholo 	case '\f':
1402286d8edStholo 	case '\v':
1412286d8edStholo 	control_char:
1422286d8edStholo 	  if (in_position < out_bound)
143b2346922Stholo 	    {
144b2346922Stholo 	      cc = c;
145b2346922Stholo 	      write_output (&cc, 1);
146b2346922Stholo 	    }
1472286d8edStholo 	  break;
1482286d8edStholo 
1492286d8edStholo 	default:
1502286d8edStholo 	  if (! ISPRINT (c))
1512286d8edStholo 	    goto control_char;
1522286d8edStholo 	  /* falls through */
1532286d8edStholo 	case ' ':
1542286d8edStholo 	  if (in_position++ < out_bound)
1552286d8edStholo 	    {
1562286d8edStholo 	      out_position = in_position;
157b2346922Stholo 	      cc = c;
158b2346922Stholo 	      write_output (&cc, 1);
1592286d8edStholo 	    }
1602286d8edStholo 	  break;
1612286d8edStholo 
1622286d8edStholo 	case '\n':
1632286d8edStholo 	  return out_position;
1642286d8edStholo 	}
1652286d8edStholo     }
1662286d8edStholo 
1672286d8edStholo   return out_position;
1682286d8edStholo }
1692286d8edStholo 
1702286d8edStholo /*
1712286d8edStholo  * Print side by side lines with a separator in the middle.
1722286d8edStholo  * 0 parameters are taken to indicate white space text.
1732286d8edStholo  * Blank lines that can easily be caught are reduced to a single newline.
1742286d8edStholo  */
1752286d8edStholo 
1762286d8edStholo static void
print_1sdiff_line(left,sep,right)1772286d8edStholo print_1sdiff_line (left, sep, right)
1782286d8edStholo      char const * const *left;
1792286d8edStholo      int sep;
1802286d8edStholo      char const * const *right;
1812286d8edStholo {
1822286d8edStholo   unsigned hw = sdiff_half_width, c2o = sdiff_column2_offset;
1832286d8edStholo   unsigned col = 0;
1842286d8edStholo   int put_newline = 0;
1852286d8edStholo 
1862286d8edStholo   if (left)
1872286d8edStholo     {
1882286d8edStholo       if (left[1][-1] == '\n')
1892286d8edStholo 	put_newline = 1;
1902286d8edStholo       col = print_half_line (left, 0, hw);
1912286d8edStholo     }
1922286d8edStholo 
1932286d8edStholo   if (sep != ' ')
1942286d8edStholo     {
195b2346922Stholo       char cc;
196b2346922Stholo 
1972286d8edStholo       col = tab_from_to (col, (hw + c2o - 1) / 2) + 1;
1982286d8edStholo       if (sep == '|' && put_newline != (right[1][-1] == '\n'))
1992286d8edStholo 	sep = put_newline ? '/' : '\\';
200b2346922Stholo       cc = sep;
201b2346922Stholo       write_output (&cc, 1);
2022286d8edStholo     }
2032286d8edStholo 
2042286d8edStholo   if (right)
2052286d8edStholo     {
2062286d8edStholo       if (right[1][-1] == '\n')
2072286d8edStholo 	put_newline = 1;
2082286d8edStholo       if (**right != '\n')
2092286d8edStholo 	{
2102286d8edStholo 	  col = tab_from_to (col, c2o);
2112286d8edStholo 	  print_half_line (right, col, hw);
2122286d8edStholo 	}
2132286d8edStholo     }
2142286d8edStholo 
2152286d8edStholo   if (put_newline)
216b2346922Stholo     write_output ("\n", 1);
2172286d8edStholo }
2182286d8edStholo 
2192286d8edStholo /* Print lines common to both files in side-by-side format.  */
2202286d8edStholo static void
print_sdiff_common_lines(limit0,limit1)2212286d8edStholo print_sdiff_common_lines (limit0, limit1)
2222286d8edStholo      int limit0, limit1;
2232286d8edStholo {
2242286d8edStholo   int i0 = next0, i1 = next1;
2252286d8edStholo 
2262286d8edStholo   if (! sdiff_skip_common_lines  &&  (i0 != limit0 || i1 != limit1))
2272286d8edStholo     {
2282286d8edStholo       if (sdiff_help_sdiff)
229b2346922Stholo 	printf_output ("i%d,%d\n", limit0 - i0, limit1 - i1);
2302286d8edStholo 
2312286d8edStholo       if (! sdiff_left_only)
2322286d8edStholo 	{
2332286d8edStholo 	  while (i0 != limit0 && i1 != limit1)
2342286d8edStholo 	    print_1sdiff_line (&files[0].linbuf[i0++], ' ', &files[1].linbuf[i1++]);
2352286d8edStholo 	  while (i1 != limit1)
2362286d8edStholo 	    print_1sdiff_line (0, ')', &files[1].linbuf[i1++]);
2372286d8edStholo 	}
2382286d8edStholo       while (i0 != limit0)
2392286d8edStholo 	print_1sdiff_line (&files[0].linbuf[i0++], '(', 0);
2402286d8edStholo     }
2412286d8edStholo 
2422286d8edStholo   next0 = limit0;
2432286d8edStholo   next1 = limit1;
2442286d8edStholo }
2452286d8edStholo 
2462286d8edStholo /* Print a hunk of an sdiff diff.
2472286d8edStholo    This is a contiguous portion of a complete edit script,
2482286d8edStholo    describing changes in consecutive lines.  */
2492286d8edStholo 
2502286d8edStholo static void
print_sdiff_hunk(hunk)2512286d8edStholo print_sdiff_hunk (hunk)
2522286d8edStholo      struct change *hunk;
2532286d8edStholo {
2542286d8edStholo   int first0, last0, first1, last1, deletes, inserts;
2552286d8edStholo   register int i, j;
2562286d8edStholo 
2572286d8edStholo   /* Determine range of line numbers involved in each file.  */
2582286d8edStholo   analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
2592286d8edStholo   if (!deletes && !inserts)
2602286d8edStholo     return;
2612286d8edStholo 
2622286d8edStholo   /* Print out lines up to this change.  */
2632286d8edStholo   print_sdiff_common_lines (first0, first1);
2642286d8edStholo 
2652286d8edStholo   if (sdiff_help_sdiff)
266b2346922Stholo     printf_output ("c%d,%d\n", last0 - first0 + 1, last1 - first1 + 1);
2672286d8edStholo 
2682286d8edStholo   /* Print ``xxx  |  xxx '' lines */
2692286d8edStholo   if (inserts && deletes)
2702286d8edStholo     {
2712286d8edStholo       for (i = first0, j = first1;  i <= last0 && j <= last1; ++i, ++j)
2722286d8edStholo 	print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]);
2732286d8edStholo       deletes = i <= last0;
2742286d8edStholo       inserts = j <= last1;
2752286d8edStholo       next0 = first0 = i;
2762286d8edStholo       next1 = first1 = j;
2772286d8edStholo     }
2782286d8edStholo 
2792286d8edStholo 
2802286d8edStholo   /* Print ``     >  xxx '' lines */
2812286d8edStholo   if (inserts)
2822286d8edStholo     {
2832286d8edStholo       for (j = first1; j <= last1; ++j)
2842286d8edStholo 	print_1sdiff_line (0, '>', &files[1].linbuf[j]);
2852286d8edStholo       next1 = j;
2862286d8edStholo     }
2872286d8edStholo 
2882286d8edStholo   /* Print ``xxx  <     '' lines */
2892286d8edStholo   if (deletes)
2902286d8edStholo     {
2912286d8edStholo       for (i = first0; i <= last0; ++i)
2922286d8edStholo 	print_1sdiff_line (&files[0].linbuf[i], '<', 0);
2932286d8edStholo       next0 = i;
2942286d8edStholo     }
2952286d8edStholo }
296