xref: /freebsd/contrib/diff/src/side.c (revision 18fd37a72c3a7549d2d4f6c6ea00bdcd2bdaca01)
118fd37a7SXin LI /* sdiff-format output routines for GNU DIFF.
218fd37a7SXin LI 
318fd37a7SXin LI    Copyright (C) 1991, 1992, 1993, 1998, 2001, 2002, 2004 Free
418fd37a7SXin LI    Software Foundation, Inc.
518fd37a7SXin LI 
618fd37a7SXin LI    This file is part of GNU DIFF.
718fd37a7SXin LI 
818fd37a7SXin LI    GNU DIFF is distributed in the hope that it will be useful,
918fd37a7SXin LI    but WITHOUT ANY WARRANTY.  No author or distributor
1018fd37a7SXin LI    accepts responsibility to anyone for the consequences of using it
1118fd37a7SXin LI    or for whether it serves any particular purpose or works at all,
1218fd37a7SXin LI    unless he says so in writing.  Refer to the GNU DIFF General Public
1318fd37a7SXin LI    License for full details.
1418fd37a7SXin LI 
1518fd37a7SXin LI    Everyone is granted permission to copy, modify and redistribute
1618fd37a7SXin LI    GNU DIFF, but only under the conditions described in the
1718fd37a7SXin LI    GNU DIFF General Public License.   A copy of this license is
1818fd37a7SXin LI    supposed to have been given to you along with GNU DIFF so you
1918fd37a7SXin LI    can know your rights and responsibilities.  It should be in a
2018fd37a7SXin LI    file named COPYING.  Among other things, the copyright notice
2118fd37a7SXin LI    and this notice must be preserved on all copies.  */
2218fd37a7SXin LI 
2318fd37a7SXin LI #include "diff.h"
2418fd37a7SXin LI 
2518fd37a7SXin LI static void print_sdiff_common_lines (lin, lin);
2618fd37a7SXin LI static void print_sdiff_hunk (struct change *);
2718fd37a7SXin LI 
2818fd37a7SXin LI /* Next line number to be printed in the two input files.  */
2918fd37a7SXin LI static lin next0, next1;
3018fd37a7SXin LI 
3118fd37a7SXin LI /* Print the edit-script SCRIPT as a sdiff style output.  */
3218fd37a7SXin LI 
3318fd37a7SXin LI void
print_sdiff_script(struct change * script)3418fd37a7SXin LI print_sdiff_script (struct change *script)
3518fd37a7SXin LI {
3618fd37a7SXin LI   begin_output ();
3718fd37a7SXin LI 
3818fd37a7SXin LI   next0 = next1 = - files[0].prefix_lines;
3918fd37a7SXin LI   print_script (script, find_change, print_sdiff_hunk);
4018fd37a7SXin LI 
4118fd37a7SXin LI   print_sdiff_common_lines (files[0].valid_lines, files[1].valid_lines);
4218fd37a7SXin LI }
4318fd37a7SXin LI 
4418fd37a7SXin LI /* Tab from column FROM to column TO, where FROM <= TO.  Yield TO.  */
4518fd37a7SXin LI 
4618fd37a7SXin LI static size_t
tab_from_to(size_t from,size_t to)4718fd37a7SXin LI tab_from_to (size_t from, size_t to)
4818fd37a7SXin LI {
4918fd37a7SXin LI   FILE *out = outfile;
5018fd37a7SXin LI   size_t tab;
5118fd37a7SXin LI   size_t tab_size = tabsize;
5218fd37a7SXin LI 
5318fd37a7SXin LI   if (!expand_tabs)
5418fd37a7SXin LI     for (tab = from + tab_size - from % tab_size;  tab <= to;  tab += tab_size)
5518fd37a7SXin LI       {
5618fd37a7SXin LI 	putc ('\t', out);
5718fd37a7SXin LI 	from = tab;
5818fd37a7SXin LI       }
5918fd37a7SXin LI   while (from++ < to)
6018fd37a7SXin LI     putc (' ', out);
6118fd37a7SXin LI   return to;
6218fd37a7SXin LI }
6318fd37a7SXin LI 
6418fd37a7SXin LI /* Print the text for half an sdiff line.  This means truncate to
6518fd37a7SXin LI    width observing tabs, and trim a trailing newline.  Return the
6618fd37a7SXin LI    last column written (not the number of chars).  */
6718fd37a7SXin LI 
6818fd37a7SXin LI static size_t
print_half_line(char const * const * line,size_t indent,size_t out_bound)6918fd37a7SXin LI print_half_line (char const *const *line, size_t indent, size_t out_bound)
7018fd37a7SXin LI {
7118fd37a7SXin LI   FILE *out = outfile;
7218fd37a7SXin LI   register size_t in_position = 0;
7318fd37a7SXin LI   register size_t out_position = 0;
7418fd37a7SXin LI   register char const *text_pointer = line[0];
7518fd37a7SXin LI   register char const *text_limit = line[1];
7618fd37a7SXin LI 
7718fd37a7SXin LI   while (text_pointer < text_limit)
7818fd37a7SXin LI     {
7918fd37a7SXin LI       register unsigned char c = *text_pointer++;
8018fd37a7SXin LI 
8118fd37a7SXin LI       switch (c)
8218fd37a7SXin LI 	{
8318fd37a7SXin LI 	case '\t':
8418fd37a7SXin LI 	  {
8518fd37a7SXin LI 	    size_t spaces = tabsize - in_position % tabsize;
8618fd37a7SXin LI 	    if (in_position == out_position)
8718fd37a7SXin LI 	      {
8818fd37a7SXin LI 		size_t tabstop = out_position + spaces;
8918fd37a7SXin LI 		if (expand_tabs)
9018fd37a7SXin LI 		  {
9118fd37a7SXin LI 		    if (out_bound < tabstop)
9218fd37a7SXin LI 		      tabstop = out_bound;
9318fd37a7SXin LI 		    for (;  out_position < tabstop;  out_position++)
9418fd37a7SXin LI 		      putc (' ', out);
9518fd37a7SXin LI 		  }
9618fd37a7SXin LI 		else
9718fd37a7SXin LI 		  if (tabstop < out_bound)
9818fd37a7SXin LI 		    {
9918fd37a7SXin LI 		      out_position = tabstop;
10018fd37a7SXin LI 		      putc (c, out);
10118fd37a7SXin LI 		    }
10218fd37a7SXin LI 	      }
10318fd37a7SXin LI 	    in_position += spaces;
10418fd37a7SXin LI 	  }
10518fd37a7SXin LI 	  break;
10618fd37a7SXin LI 
10718fd37a7SXin LI 	case '\r':
10818fd37a7SXin LI 	  {
10918fd37a7SXin LI 	    putc (c, out);
11018fd37a7SXin LI 	    tab_from_to (0, indent);
11118fd37a7SXin LI 	    in_position = out_position = 0;
11218fd37a7SXin LI 	  }
11318fd37a7SXin LI 	  break;
11418fd37a7SXin LI 
11518fd37a7SXin LI 	case '\b':
11618fd37a7SXin LI 	  if (in_position != 0 && --in_position < out_bound)
11718fd37a7SXin LI 	    {
11818fd37a7SXin LI 	      if (out_position <= in_position)
11918fd37a7SXin LI 		/* Add spaces to make up for suppressed tab past out_bound.  */
12018fd37a7SXin LI 		for (;  out_position < in_position;  out_position++)
12118fd37a7SXin LI 		  putc (' ', out);
12218fd37a7SXin LI 	      else
12318fd37a7SXin LI 		{
12418fd37a7SXin LI 		  out_position = in_position;
12518fd37a7SXin LI 		  putc (c, out);
12618fd37a7SXin LI 		}
12718fd37a7SXin LI 	    }
12818fd37a7SXin LI 	  break;
12918fd37a7SXin LI 
13018fd37a7SXin LI 	case '\f':
13118fd37a7SXin LI 	case '\v':
13218fd37a7SXin LI 	control_char:
13318fd37a7SXin LI 	  if (in_position < out_bound)
13418fd37a7SXin LI 	    putc (c, out);
13518fd37a7SXin LI 	  break;
13618fd37a7SXin LI 
13718fd37a7SXin LI 	default:
13818fd37a7SXin LI 	  if (! isprint (c))
13918fd37a7SXin LI 	    goto control_char;
14018fd37a7SXin LI 	  /* falls through */
14118fd37a7SXin LI 	case ' ':
14218fd37a7SXin LI 	  if (in_position++ < out_bound)
14318fd37a7SXin LI 	    {
14418fd37a7SXin LI 	      out_position = in_position;
14518fd37a7SXin LI 	      putc (c, out);
14618fd37a7SXin LI 	    }
14718fd37a7SXin LI 	  break;
14818fd37a7SXin LI 
14918fd37a7SXin LI 	case '\n':
15018fd37a7SXin LI 	  return out_position;
15118fd37a7SXin LI 	}
15218fd37a7SXin LI     }
15318fd37a7SXin LI 
15418fd37a7SXin LI   return out_position;
15518fd37a7SXin LI }
15618fd37a7SXin LI 
15718fd37a7SXin LI /* Print side by side lines with a separator in the middle.
15818fd37a7SXin LI    0 parameters are taken to indicate white space text.
15918fd37a7SXin LI    Blank lines that can easily be caught are reduced to a single newline.  */
16018fd37a7SXin LI 
16118fd37a7SXin LI static void
print_1sdiff_line(char const * const * left,char sep,char const * const * right)16218fd37a7SXin LI print_1sdiff_line (char const *const *left, char sep,
16318fd37a7SXin LI 		   char const *const *right)
16418fd37a7SXin LI {
16518fd37a7SXin LI   FILE *out = outfile;
16618fd37a7SXin LI   size_t hw = sdiff_half_width;
16718fd37a7SXin LI   size_t c2o = sdiff_column2_offset;
16818fd37a7SXin LI   size_t col = 0;
16918fd37a7SXin LI   bool put_newline = false;
17018fd37a7SXin LI 
17118fd37a7SXin LI   if (left)
17218fd37a7SXin LI     {
17318fd37a7SXin LI       put_newline |= left[1][-1] == '\n';
17418fd37a7SXin LI       col = print_half_line (left, 0, hw);
17518fd37a7SXin LI     }
17618fd37a7SXin LI 
17718fd37a7SXin LI   if (sep != ' ')
17818fd37a7SXin LI     {
17918fd37a7SXin LI       col = tab_from_to (col, (hw + c2o - 1) / 2) + 1;
18018fd37a7SXin LI       if (sep == '|' && put_newline != (right[1][-1] == '\n'))
18118fd37a7SXin LI 	sep = put_newline ? '/' : '\\';
18218fd37a7SXin LI       putc (sep, out);
18318fd37a7SXin LI     }
18418fd37a7SXin LI 
18518fd37a7SXin LI   if (right)
18618fd37a7SXin LI     {
18718fd37a7SXin LI       put_newline |= right[1][-1] == '\n';
18818fd37a7SXin LI       if (**right != '\n')
18918fd37a7SXin LI 	{
19018fd37a7SXin LI 	  col = tab_from_to (col, c2o);
19118fd37a7SXin LI 	  print_half_line (right, col, hw);
19218fd37a7SXin LI 	}
19318fd37a7SXin LI     }
19418fd37a7SXin LI 
19518fd37a7SXin LI   if (put_newline)
19618fd37a7SXin LI     putc ('\n', out);
19718fd37a7SXin LI }
19818fd37a7SXin LI 
19918fd37a7SXin LI /* Print lines common to both files in side-by-side format.  */
20018fd37a7SXin LI static void
print_sdiff_common_lines(lin limit0,lin limit1)20118fd37a7SXin LI print_sdiff_common_lines (lin limit0, lin limit1)
20218fd37a7SXin LI {
20318fd37a7SXin LI   lin i0 = next0, i1 = next1;
20418fd37a7SXin LI 
20518fd37a7SXin LI   if (!suppress_common_lines && (i0 != limit0 || i1 != limit1))
20618fd37a7SXin LI     {
20718fd37a7SXin LI       if (sdiff_merge_assist)
20818fd37a7SXin LI 	{
20918fd37a7SXin LI 	  long int len0 = limit0 - i0;
21018fd37a7SXin LI 	  long int len1 = limit1 - i1;
21118fd37a7SXin LI 	  fprintf (outfile, "i%ld,%ld\n", len0, len1);
21218fd37a7SXin LI 	}
21318fd37a7SXin LI 
21418fd37a7SXin LI       if (!left_column)
21518fd37a7SXin LI 	{
21618fd37a7SXin LI 	  while (i0 != limit0 && i1 != limit1)
21718fd37a7SXin LI 	    print_1sdiff_line (&files[0].linbuf[i0++], ' ',
21818fd37a7SXin LI 			       &files[1].linbuf[i1++]);
21918fd37a7SXin LI 	  while (i1 != limit1)
22018fd37a7SXin LI 	    print_1sdiff_line (0, ')', &files[1].linbuf[i1++]);
22118fd37a7SXin LI 	}
22218fd37a7SXin LI       while (i0 != limit0)
22318fd37a7SXin LI 	print_1sdiff_line (&files[0].linbuf[i0++], '(', 0);
22418fd37a7SXin LI     }
22518fd37a7SXin LI 
22618fd37a7SXin LI   next0 = limit0;
22718fd37a7SXin LI   next1 = limit1;
22818fd37a7SXin LI }
22918fd37a7SXin LI 
23018fd37a7SXin LI /* Print a hunk of an sdiff diff.
23118fd37a7SXin LI    This is a contiguous portion of a complete edit script,
23218fd37a7SXin LI    describing changes in consecutive lines.  */
23318fd37a7SXin LI 
23418fd37a7SXin LI static void
print_sdiff_hunk(struct change * hunk)23518fd37a7SXin LI print_sdiff_hunk (struct change *hunk)
23618fd37a7SXin LI {
23718fd37a7SXin LI   lin first0, last0, first1, last1;
23818fd37a7SXin LI   register lin i, j;
23918fd37a7SXin LI 
24018fd37a7SXin LI   /* Determine range of line numbers involved in each file.  */
24118fd37a7SXin LI   enum changes changes =
24218fd37a7SXin LI     analyze_hunk (hunk, &first0, &last0, &first1, &last1);
24318fd37a7SXin LI   if (!changes)
24418fd37a7SXin LI     return;
24518fd37a7SXin LI 
24618fd37a7SXin LI   /* Print out lines up to this change.  */
24718fd37a7SXin LI   print_sdiff_common_lines (first0, first1);
24818fd37a7SXin LI 
24918fd37a7SXin LI   if (sdiff_merge_assist)
25018fd37a7SXin LI     {
25118fd37a7SXin LI       long int len0 = last0 - first0 + 1;
25218fd37a7SXin LI       long int len1 = last1 - first1 + 1;
25318fd37a7SXin LI       fprintf (outfile, "c%ld,%ld\n", len0, len1);
25418fd37a7SXin LI     }
25518fd37a7SXin LI 
25618fd37a7SXin LI   /* Print ``xxx  |  xxx '' lines */
25718fd37a7SXin LI   if (changes == CHANGED)
25818fd37a7SXin LI     {
25918fd37a7SXin LI       for (i = first0, j = first1;  i <= last0 && j <= last1;  i++, j++)
26018fd37a7SXin LI 	print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]);
26118fd37a7SXin LI       changes = (i <= last0 ? OLD : 0) + (j <= last1 ? NEW : 0);
26218fd37a7SXin LI       next0 = first0 = i;
26318fd37a7SXin LI       next1 = first1 = j;
26418fd37a7SXin LI     }
26518fd37a7SXin LI 
26618fd37a7SXin LI   /* Print ``     >  xxx '' lines */
26718fd37a7SXin LI   if (changes & NEW)
26818fd37a7SXin LI     {
26918fd37a7SXin LI       for (j = first1; j <= last1; ++j)
27018fd37a7SXin LI 	print_1sdiff_line (0, '>', &files[1].linbuf[j]);
27118fd37a7SXin LI       next1 = j;
27218fd37a7SXin LI     }
27318fd37a7SXin LI 
27418fd37a7SXin LI   /* Print ``xxx  <     '' lines */
27518fd37a7SXin LI   if (changes & OLD)
27618fd37a7SXin LI     {
27718fd37a7SXin LI       for (i = first0; i <= last0; ++i)
27818fd37a7SXin LI 	print_1sdiff_line (&files[0].linbuf[i], '<', 0);
27918fd37a7SXin LI       next0 = i;
28018fd37a7SXin LI     }
28118fd37a7SXin LI }
282