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