]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/diff/side.c
A version of SGR disabling stuff that is believed to be safe.
[FreeBSD/FreeBSD.git] / contrib / diff / side.c
1 /* sdiff-format output routines for GNU DIFF.
2    Copyright (C) 1991, 1992, 1993 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   FILE *out = outfile;
54   unsigned tab;
55
56   if (! tab_expand_flag)
57     for (tab = from + TAB_WIDTH - from % TAB_WIDTH;  tab <= to;  tab += TAB_WIDTH)
58       {
59         putc ('\t', out);
60         from = tab;
61       }
62   while (from++ < to)
63     putc (' ', out);
64   return to;
65 }
66
67 /*
68  * Print the text for half an sdiff line.  This means truncate to width
69  * observing tabs, and trim a trailing newline.  Returns the last column
70  * written (not the number of chars).
71  */
72 static unsigned
73 print_half_line (line, indent, out_bound)
74      char const * const *line;
75      unsigned indent, out_bound;
76 {
77   FILE *out = outfile;
78   register unsigned in_position = 0, out_position = 0;
79   register char const
80         *text_pointer = line[0],
81         *text_limit = line[1];
82
83   while (text_pointer < text_limit)
84     {
85       register unsigned char c = *text_pointer++;
86
87       switch (c)
88         {
89         case '\t':
90           {
91             unsigned spaces = TAB_WIDTH - in_position % TAB_WIDTH;
92             if (in_position == out_position)
93               {
94                 unsigned tabstop = out_position + spaces;
95                 if (tab_expand_flag)
96                   {
97                     if (out_bound < tabstop)
98                       tabstop = out_bound;
99                     for (;  out_position < tabstop;  out_position++)
100                       putc (' ', out);
101                   }
102                 else
103                   if (tabstop < out_bound)
104                     {
105                       out_position = tabstop;
106                       putc (c, out);
107                     }
108               }
109             in_position += spaces;
110           }
111           break;
112
113         case '\r':
114           {
115             putc (c, out);
116             tab_from_to (0, indent);
117             in_position = out_position = 0;
118           }
119           break;
120
121         case '\b':
122           if (in_position != 0 && --in_position < out_bound)
123             if (out_position <= in_position)
124               /* Add spaces to make up for suppressed tab past out_bound.  */
125               for (;  out_position < in_position;  out_position++)
126                 putc (' ', out);
127             else
128               {
129                 out_position = in_position;
130                 putc (c, out);
131               }
132           break;
133
134         case '\f':
135         case '\v':
136         control_char:
137           if (in_position < out_bound)
138             putc (c, out);
139           break;
140
141         default:
142           if (! ISPRINT (c))
143             goto control_char;
144           /* falls through */
145         case ' ':
146           if (in_position++ < out_bound)
147             {
148               out_position = in_position;
149               putc (c, out);
150             }
151           break;
152
153         case '\n':
154           return out_position;
155         }
156     }
157
158   return out_position;
159 }
160
161 /*
162  * Print side by side lines with a separator in the middle.
163  * 0 parameters are taken to indicate white space text.
164  * Blank lines that can easily be caught are reduced to a single newline.
165  */
166
167 static void
168 print_1sdiff_line (left, sep, right)
169      char const * const *left;
170      int sep;
171      char const * const *right;
172 {
173   FILE *out = outfile;
174   unsigned hw = sdiff_half_width, c2o = sdiff_column2_offset;
175   unsigned col = 0;
176   int put_newline = 0;
177
178   if (left)
179     {
180       if (left[1][-1] == '\n')
181         put_newline = 1;
182       col = print_half_line (left, 0, hw);
183     }
184
185   if (sep != ' ')
186     {
187       col = tab_from_to (col, (hw + c2o - 1) / 2) + 1;
188       if (sep == '|' && put_newline != (right[1][-1] == '\n'))
189         sep = put_newline ? '/' : '\\';
190       putc (sep, out);
191     }
192
193   if (right)
194     {
195       if (right[1][-1] == '\n')
196         put_newline = 1;
197       if (**right != '\n')
198         {
199           col = tab_from_to (col, c2o);
200           print_half_line (right, col, hw);
201         }
202     }
203
204   if (put_newline)
205     putc ('\n', out);
206 }
207
208 /* Print lines common to both files in side-by-side format.  */
209 static void
210 print_sdiff_common_lines (limit0, limit1)
211      int limit0, limit1;
212 {
213   int i0 = next0, i1 = next1;
214
215   if (! sdiff_skip_common_lines  &&  (i0 != limit0 || i1 != limit1))
216     {
217       if (sdiff_help_sdiff)
218         fprintf (outfile, "i%d,%d\n", limit0 - i0, limit1 - i1);
219
220       if (! sdiff_left_only)
221         {
222           while (i0 != limit0 && i1 != limit1)
223             print_1sdiff_line (&files[0].linbuf[i0++], ' ', &files[1].linbuf[i1++]);
224           while (i1 != limit1)
225             print_1sdiff_line (0, ')', &files[1].linbuf[i1++]);
226         }
227       while (i0 != limit0)
228         print_1sdiff_line (&files[0].linbuf[i0++], '(', 0);
229     }
230
231   next0 = limit0;
232   next1 = limit1;
233 }
234
235 /* Print a hunk of an sdiff diff.
236    This is a contiguous portion of a complete edit script,
237    describing changes in consecutive lines.  */
238
239 static void
240 print_sdiff_hunk (hunk)
241      struct change *hunk;
242 {
243   int first0, last0, first1, last1, deletes, inserts;
244   register int i, j;
245
246   /* Determine range of line numbers involved in each file.  */
247   analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
248   if (!deletes && !inserts)
249     return;
250
251   /* Print out lines up to this change.  */
252   print_sdiff_common_lines (first0, first1);
253
254   if (sdiff_help_sdiff)
255     fprintf (outfile, "c%d,%d\n", last0 - first0 + 1, last1 - first1 + 1);
256
257   /* Print ``xxx  |  xxx '' lines */
258   if (inserts && deletes)
259     {
260       for (i = first0, j = first1;  i <= last0 && j <= last1; ++i, ++j)
261         print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]);
262       deletes = i <= last0;
263       inserts = j <= last1;
264       next0 = first0 = i;
265       next1 = first1 = j;
266     }
267
268
269   /* Print ``     >  xxx '' lines */
270   if (inserts)
271     {
272       for (j = first1; j <= last1; ++j)
273         print_1sdiff_line (0, '>', &files[1].linbuf[j]);
274       next1 = j;
275     }
276
277   /* Print ``xxx  <     '' lines */
278   if (deletes)
279     {
280       for (i = first0; i <= last0; ++i)
281         print_1sdiff_line (&files[0].linbuf[i], '<', 0);
282       next0 = i;
283     }
284 }