Bring cvs-1.12.9 into the CVS repository
[dragonfly.git] / contrib / cvs-1.12.9 / 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           break;
137
138         case '\f':
139         case '\v':
140         control_char:
141           if (in_position < out_bound)
142             {
143               cc = c;
144               write_output (&cc, 1);
145             }
146           break;
147
148         default:
149           if (! ISPRINT (c))
150             goto control_char;
151           /* falls through */
152         case ' ':
153           if (in_position++ < out_bound)
154             {
155               out_position = in_position;
156               cc = c;
157               write_output (&cc, 1);
158             }
159           break;
160
161         case '\n':
162           return out_position;
163         }
164     }
165
166   return out_position;
167 }
168
169 /*
170  * Print side by side lines with a separator in the middle.
171  * 0 parameters are taken to indicate white space text.
172  * Blank lines that can easily be caught are reduced to a single newline.
173  */
174
175 static void
176 print_1sdiff_line (left, sep, right)
177      char const * const *left;
178      int sep;
179      char const * const *right;
180 {
181   unsigned hw = sdiff_half_width, c2o = sdiff_column2_offset;
182   unsigned col = 0;
183   int put_newline = 0;
184
185   if (left)
186     {
187       if (left[1][-1] == '\n')
188         put_newline = 1;
189       col = print_half_line (left, 0, hw);
190     }
191
192   if (sep != ' ')
193     {
194       char cc;
195
196       col = tab_from_to (col, (hw + c2o - 1) / 2) + 1;
197       if (sep == '|' && put_newline != (right[1][-1] == '\n'))
198         sep = put_newline ? '/' : '\\';
199       cc = sep;
200       write_output (&cc, 1);
201     }
202
203   if (right)
204     {
205       if (right[1][-1] == '\n')
206         put_newline = 1;
207       if (**right != '\n')
208         {
209           col = tab_from_to (col, c2o);
210           print_half_line (right, col, hw);
211         }
212     }
213
214   if (put_newline)
215     write_output ("\n", 1);
216 }
217
218 /* Print lines common to both files in side-by-side format.  */
219 static void
220 print_sdiff_common_lines (limit0, limit1)
221      int limit0, limit1;
222 {
223   int i0 = next0, i1 = next1;
224
225   if (! sdiff_skip_common_lines  &&  (i0 != limit0 || i1 != limit1))
226     {
227       if (sdiff_help_sdiff)
228         printf_output ("i%d,%d\n", limit0 - i0, limit1 - i1);
229
230       if (! sdiff_left_only)
231         {
232           while (i0 != limit0 && i1 != limit1)
233             print_1sdiff_line (&files[0].linbuf[i0++], ' ', &files[1].linbuf[i1++]);
234           while (i1 != limit1)
235             print_1sdiff_line (0, ')', &files[1].linbuf[i1++]);
236         }
237       while (i0 != limit0)
238         print_1sdiff_line (&files[0].linbuf[i0++], '(', 0);
239     }
240
241   next0 = limit0;
242   next1 = limit1;
243 }
244
245 /* Print a hunk of an sdiff diff.
246    This is a contiguous portion of a complete edit script,
247    describing changes in consecutive lines.  */
248
249 static void
250 print_sdiff_hunk (hunk)
251      struct change *hunk;
252 {
253   int first0, last0, first1, last1, deletes, inserts;
254   register int i, j;
255
256   /* Determine range of line numbers involved in each file.  */
257   analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
258   if (!deletes && !inserts)
259     return;
260
261   /* Print out lines up to this change.  */
262   print_sdiff_common_lines (first0, first1);
263
264   if (sdiff_help_sdiff)
265     printf_output ("c%d,%d\n", last0 - first0 + 1, last1 - first1 + 1);
266
267   /* Print ``xxx  |  xxx '' lines */
268   if (inserts && deletes)
269     {
270       for (i = first0, j = first1;  i <= last0 && j <= last1; ++i, ++j)
271         print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]);
272       deletes = i <= last0;
273       inserts = j <= last1;
274       next0 = first0 = i;
275       next1 = first1 = j;
276     }
277
278
279   /* Print ``     >  xxx '' lines */
280   if (inserts)
281     {
282       for (j = first1; j <= last1; ++j)
283         print_1sdiff_line (0, '>', &files[1].linbuf[j]);
284       next1 = j;
285     }
286
287   /* Print ``xxx  <     '' lines */
288   if (deletes)
289     {
290       for (i = first0; i <= last0; ++i)
291         print_1sdiff_line (&files[0].linbuf[i], '<', 0);
292       next0 = i;
293     }
294 }