xref: /netbsd-src/external/gpl2/diffutils/dist/src/side.c (revision 75f6d617e282811cb173c2ccfbf5df0dd71f7045)
1 /*	$NetBSD: side.c,v 1.1.1.1 2016/01/13 03:15:30 christos Exp $	*/
2 
3 /* sdiff-format output routines for GNU DIFF.
4 
5    Copyright (C) 1991, 1992, 1993, 1998, 2001, 2002 Free Software
6    Foundation, Inc.
7 
8    This file is part of GNU DIFF.
9 
10    GNU DIFF is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY.  No author or distributor
12    accepts responsibility to anyone for the consequences of using it
13    or for whether it serves any particular purpose or works at all,
14    unless he says so in writing.  Refer to the GNU DIFF General Public
15    License for full details.
16 
17    Everyone is granted permission to copy, modify and redistribute
18    GNU DIFF, but only under the conditions described in the
19    GNU DIFF General Public License.   A copy of this license is
20    supposed to have been given to you along with GNU DIFF so you
21    can know your rights and responsibilities.  It should be in a
22    file named COPYING.  Among other things, the copyright notice
23    and this notice must be preserved on all copies.  */
24 
25 #include "diff.h"
26 
27 static void print_sdiff_common_lines (lin, lin);
28 static void print_sdiff_hunk (struct change *);
29 
30 /* Next line number to be printed in the two input files.  */
31 static lin next0, next1;
32 
33 /* Print the edit-script SCRIPT as a sdiff style output.  */
34 
35 void
print_sdiff_script(struct change * script)36 print_sdiff_script (struct change *script)
37 {
38   begin_output ();
39 
40   next0 = next1 = - files[0].prefix_lines;
41   print_script (script, find_change, print_sdiff_hunk);
42 
43   print_sdiff_common_lines (files[0].valid_lines, files[1].valid_lines);
44 }
45 
46 /* Tab from column FROM to column TO, where FROM <= TO.  Yield TO.  */
47 
48 static unsigned int
tab_from_to(unsigned int from,unsigned int to)49 tab_from_to (unsigned int from, unsigned int to)
50 {
51   FILE *out = outfile;
52   unsigned int tab;
53 
54   if (!expand_tabs)
55     for (tab = from + TAB_WIDTH - from % TAB_WIDTH;  tab <= to;  tab += TAB_WIDTH)
56       {
57 	putc ('\t', out);
58 	from = tab;
59       }
60   while (from++ < to)
61     putc (' ', out);
62   return to;
63 }
64 
65 /*
66  * Print the text for half an sdiff line.  This means truncate to width
67  * observing tabs, and trim a trailing newline.  Returns the last column
68  * written (not the number of chars).
69  */
70 static unsigned int
print_half_line(char const * const * line,unsigned int indent,unsigned int out_bound)71 print_half_line (char const *const *line, unsigned int indent,
72 		 unsigned int out_bound)
73 {
74   FILE *out = outfile;
75   register unsigned int in_position = 0;
76   register unsigned int out_position = 0;
77   register char const *text_pointer = line[0];
78   register char const *text_limit = line[1];
79 
80   while (text_pointer < text_limit)
81     {
82       register unsigned char c = *text_pointer++;
83 
84       switch (c)
85 	{
86 	case '\t':
87 	  {
88 	    unsigned int spaces = TAB_WIDTH - in_position % TAB_WIDTH;
89 	    if (in_position == out_position)
90 	      {
91 		unsigned int tabstop = out_position + spaces;
92 		if (expand_tabs)
93 		  {
94 		    if (out_bound < tabstop)
95 		      tabstop = out_bound;
96 		    for (;  out_position < tabstop;  out_position++)
97 		      putc (' ', out);
98 		  }
99 		else
100 		  if (tabstop < out_bound)
101 		    {
102 		      out_position = tabstop;
103 		      putc (c, out);
104 		    }
105 	      }
106 	    in_position += spaces;
107 	  }
108 	  break;
109 
110 	case '\r':
111 	  {
112 	    putc (c, out);
113 	    tab_from_to (0, indent);
114 	    in_position = out_position = 0;
115 	  }
116 	  break;
117 
118 	case '\b':
119 	  if (in_position != 0 && --in_position < out_bound)
120 	    {
121 	      if (out_position <= in_position)
122 		/* Add spaces to make up for suppressed tab past out_bound.  */
123 		for (;  out_position < in_position;  out_position++)
124 		  putc (' ', out);
125 	      else
126 		{
127 		  out_position = in_position;
128 		  putc (c, out);
129 		}
130 	    }
131 	  break;
132 
133 	case '\f':
134 	case '\v':
135 	control_char:
136 	  if (in_position < out_bound)
137 	    putc (c, out);
138 	  break;
139 
140 	default:
141 	  if (! ISPRINT (c))
142 	    goto control_char;
143 	  /* falls through */
144 	case ' ':
145 	  if (in_position++ < out_bound)
146 	    {
147 	      out_position = in_position;
148 	      putc (c, out);
149 	    }
150 	  break;
151 
152 	case '\n':
153 	  return out_position;
154 	}
155     }
156 
157   return out_position;
158 }
159 
160 /*
161  * Print side by side lines with a separator in the middle.
162  * 0 parameters are taken to indicate white space text.
163  * Blank lines that can easily be caught are reduced to a single newline.
164  */
165 
166 static void
print_1sdiff_line(char const * const * left,char sep,char const * const * right)167 print_1sdiff_line (char const *const *left, char sep,
168 		   char const *const *right)
169 {
170   FILE *out = outfile;
171   unsigned int hw = sdiff_half_width, c2o = sdiff_column2_offset;
172   unsigned int col = 0;
173   bool put_newline = 0;
174 
175   if (left)
176     {
177       put_newline |= left[1][-1] == '\n';
178       col = print_half_line (left, 0, hw);
179     }
180 
181   if (sep != ' ')
182     {
183       col = tab_from_to (col, (hw + c2o - 1) / 2) + 1;
184       if (sep == '|' && put_newline != (right[1][-1] == '\n'))
185 	sep = put_newline ? '/' : '\\';
186       putc (sep, out);
187     }
188 
189   if (right)
190     {
191       put_newline |= right[1][-1] == '\n';
192       if (**right != '\n')
193 	{
194 	  col = tab_from_to (col, c2o);
195 	  print_half_line (right, col, hw);
196 	}
197     }
198 
199   if (put_newline)
200     putc ('\n', out);
201 }
202 
203 /* Print lines common to both files in side-by-side format.  */
204 static void
print_sdiff_common_lines(lin limit0,lin limit1)205 print_sdiff_common_lines (lin limit0, lin limit1)
206 {
207   lin i0 = next0, i1 = next1;
208 
209   if (!suppress_common_lines && (i0 != limit0 || i1 != limit1))
210     {
211       if (sdiff_merge_assist)
212 	{
213 	  long len0 = limit0 - i0;
214 	  long len1 = limit1 - i1;
215 	  fprintf (outfile, "i%ld,%ld\n", len0, len1);
216 	}
217 
218       if (!left_column)
219 	{
220 	  while (i0 != limit0 && i1 != limit1)
221 	    print_1sdiff_line (&files[0].linbuf[i0++], ' ',
222 			       &files[1].linbuf[i1++]);
223 	  while (i1 != limit1)
224 	    print_1sdiff_line (0, ')', &files[1].linbuf[i1++]);
225 	}
226       while (i0 != limit0)
227 	print_1sdiff_line (&files[0].linbuf[i0++], '(', 0);
228     }
229 
230   next0 = limit0;
231   next1 = limit1;
232 }
233 
234 /* Print a hunk of an sdiff diff.
235    This is a contiguous portion of a complete edit script,
236    describing changes in consecutive lines.  */
237 
238 static void
print_sdiff_hunk(struct change * hunk)239 print_sdiff_hunk (struct change *hunk)
240 {
241   lin first0, last0, first1, last1;
242   register lin i, j;
243 
244   /* Determine range of line numbers involved in each file.  */
245   enum changes changes =
246     analyze_hunk (hunk, &first0, &last0, &first1, &last1);
247   if (!changes)
248     return;
249 
250   /* Print out lines up to this change.  */
251   print_sdiff_common_lines (first0, first1);
252 
253   if (sdiff_merge_assist)
254     {
255       long len0 = last0 - first0 + 1;
256       long len1 = last1 - first1 + 1;
257       fprintf (outfile, "c%ld,%ld\n", len0, len1);
258     }
259 
260   /* Print ``xxx  |  xxx '' lines */
261   if (changes == CHANGED)
262     {
263       for (i = first0, j = first1;  i <= last0 && j <= last1;  i++, j++)
264 	print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]);
265       changes = (i <= last0 ? OLD : 0) + (j <= last1 ? NEW : 0);
266       next0 = first0 = i;
267       next1 = first1 = j;
268     }
269 
270   /* Print ``     >  xxx '' lines */
271   if (changes & NEW)
272     {
273       for (j = first1; j <= last1; ++j)
274 	print_1sdiff_line (0, '>', &files[1].linbuf[j]);
275       next1 = j;
276     }
277 
278   /* Print ``xxx  <     '' lines */
279   if (changes & OLD)
280     {
281       for (i = first0; i <= last0; ++i)
282 	print_1sdiff_line (&files[0].linbuf[i], '<', 0);
283       next0 = i;
284     }
285 }
286