12286d8edStholo /* sdiff-format output routines for GNU DIFF.
2b2346922Stholo Copyright (C) 1991, 1992, 1993, 1998 Free Software Foundation, Inc.
32286d8edStholo
42286d8edStholo This file is part of GNU DIFF.
52286d8edStholo
62286d8edStholo GNU DIFF is distributed in the hope that it will be useful,
72286d8edStholo but WITHOUT ANY WARRANTY. No author or distributor
82286d8edStholo accepts responsibility to anyone for the consequences of using it
92286d8edStholo or for whether it serves any particular purpose or works at all,
102286d8edStholo unless he says so in writing. Refer to the GNU DIFF General Public
112286d8edStholo License for full details.
122286d8edStholo
132286d8edStholo Everyone is granted permission to copy, modify and redistribute
142286d8edStholo GNU DIFF, but only under the conditions described in the
152286d8edStholo GNU DIFF General Public License. A copy of this license is
162286d8edStholo supposed to have been given to you along with GNU DIFF so you
172286d8edStholo can know your rights and responsibilities. It should be in a
182286d8edStholo file named COPYING. Among other things, the copyright notice
192286d8edStholo and this notice must be preserved on all copies. */
202286d8edStholo
212286d8edStholo
222286d8edStholo #include "diff.h"
232286d8edStholo
242286d8edStholo static unsigned print_half_line PARAMS((char const * const *, unsigned, unsigned));
252286d8edStholo static unsigned tab_from_to PARAMS((unsigned, unsigned));
262286d8edStholo static void print_1sdiff_line PARAMS((char const * const *, int, char const * const *));
272286d8edStholo static void print_sdiff_common_lines PARAMS((int, int));
282286d8edStholo static void print_sdiff_hunk PARAMS((struct change *));
292286d8edStholo
302286d8edStholo /* Next line number to be printed in the two input files. */
312286d8edStholo static int next0, next1;
322286d8edStholo
332286d8edStholo /* Print the edit-script SCRIPT as a sdiff style output. */
342286d8edStholo
352286d8edStholo void
print_sdiff_script(script)362286d8edStholo print_sdiff_script (script)
372286d8edStholo struct change *script;
382286d8edStholo {
392286d8edStholo begin_output ();
402286d8edStholo
412286d8edStholo next0 = next1 = - files[0].prefix_lines;
422286d8edStholo print_script (script, find_change, print_sdiff_hunk);
432286d8edStholo
442286d8edStholo print_sdiff_common_lines (files[0].valid_lines, files[1].valid_lines);
452286d8edStholo }
462286d8edStholo
472286d8edStholo /* Tab from column FROM to column TO, where FROM <= TO. Yield TO. */
482286d8edStholo
492286d8edStholo static unsigned
tab_from_to(from,to)502286d8edStholo tab_from_to (from, to)
512286d8edStholo unsigned from, to;
522286d8edStholo {
532286d8edStholo unsigned tab;
542286d8edStholo
552286d8edStholo if (! tab_expand_flag)
562286d8edStholo for (tab = from + TAB_WIDTH - from % TAB_WIDTH; tab <= to; tab += TAB_WIDTH)
572286d8edStholo {
58b2346922Stholo write_output ("\t", 1);
592286d8edStholo from = tab;
602286d8edStholo }
612286d8edStholo while (from++ < to)
62b2346922Stholo write_output (" ", 1);
632286d8edStholo return to;
642286d8edStholo }
652286d8edStholo
662286d8edStholo /*
672286d8edStholo * Print the text for half an sdiff line. This means truncate to width
682286d8edStholo * observing tabs, and trim a trailing newline. Returns the last column
692286d8edStholo * written (not the number of chars).
702286d8edStholo */
712286d8edStholo static unsigned
print_half_line(line,indent,out_bound)722286d8edStholo print_half_line (line, indent, out_bound)
732286d8edStholo char const * const *line;
742286d8edStholo unsigned indent, out_bound;
752286d8edStholo {
762286d8edStholo register unsigned in_position = 0, out_position = 0;
772286d8edStholo register char const
782286d8edStholo *text_pointer = line[0],
792286d8edStholo *text_limit = line[1];
802286d8edStholo
812286d8edStholo while (text_pointer < text_limit)
822286d8edStholo {
832286d8edStholo register unsigned char c = *text_pointer++;
84b2346922Stholo /* We use CC to avoid taking the address of the register
85b2346922Stholo variable C. */
86b2346922Stholo char cc;
872286d8edStholo
882286d8edStholo switch (c)
892286d8edStholo {
902286d8edStholo case '\t':
912286d8edStholo {
922286d8edStholo unsigned spaces = TAB_WIDTH - in_position % TAB_WIDTH;
932286d8edStholo if (in_position == out_position)
942286d8edStholo {
952286d8edStholo unsigned tabstop = out_position + spaces;
962286d8edStholo if (tab_expand_flag)
972286d8edStholo {
982286d8edStholo if (out_bound < tabstop)
992286d8edStholo tabstop = out_bound;
1002286d8edStholo for (; out_position < tabstop; out_position++)
101b2346922Stholo write_output (" ", 1);
1022286d8edStholo }
1032286d8edStholo else
1042286d8edStholo if (tabstop < out_bound)
1052286d8edStholo {
1062286d8edStholo out_position = tabstop;
107b2346922Stholo cc = c;
108b2346922Stholo write_output (&cc, 1);
1092286d8edStholo }
1102286d8edStholo }
1112286d8edStholo in_position += spaces;
1122286d8edStholo }
1132286d8edStholo break;
1142286d8edStholo
1152286d8edStholo case '\r':
1162286d8edStholo {
117b2346922Stholo cc = c;
118b2346922Stholo write_output (&cc, 1);
1192286d8edStholo tab_from_to (0, indent);
1202286d8edStholo in_position = out_position = 0;
1212286d8edStholo }
1222286d8edStholo break;
1232286d8edStholo
1242286d8edStholo case '\b':
125*0971b67fStb if (in_position != 0 && --in_position < out_bound) {
1262286d8edStholo if (out_position <= in_position)
1272286d8edStholo /* Add spaces to make up for suppressed tab past out_bound. */
1282286d8edStholo for (; out_position < in_position; out_position++)
129b2346922Stholo write_output (" ", 1);
1302286d8edStholo else
1312286d8edStholo {
1322286d8edStholo out_position = in_position;
133b2346922Stholo cc = c;
134b2346922Stholo write_output (&cc, 1);
1352286d8edStholo }
136*0971b67fStb }
1372286d8edStholo break;
1382286d8edStholo
1392286d8edStholo case '\f':
1402286d8edStholo case '\v':
1412286d8edStholo control_char:
1422286d8edStholo if (in_position < out_bound)
143b2346922Stholo {
144b2346922Stholo cc = c;
145b2346922Stholo write_output (&cc, 1);
146b2346922Stholo }
1472286d8edStholo break;
1482286d8edStholo
1492286d8edStholo default:
1502286d8edStholo if (! ISPRINT (c))
1512286d8edStholo goto control_char;
1522286d8edStholo /* falls through */
1532286d8edStholo case ' ':
1542286d8edStholo if (in_position++ < out_bound)
1552286d8edStholo {
1562286d8edStholo out_position = in_position;
157b2346922Stholo cc = c;
158b2346922Stholo write_output (&cc, 1);
1592286d8edStholo }
1602286d8edStholo break;
1612286d8edStholo
1622286d8edStholo case '\n':
1632286d8edStholo return out_position;
1642286d8edStholo }
1652286d8edStholo }
1662286d8edStholo
1672286d8edStholo return out_position;
1682286d8edStholo }
1692286d8edStholo
1702286d8edStholo /*
1712286d8edStholo * Print side by side lines with a separator in the middle.
1722286d8edStholo * 0 parameters are taken to indicate white space text.
1732286d8edStholo * Blank lines that can easily be caught are reduced to a single newline.
1742286d8edStholo */
1752286d8edStholo
1762286d8edStholo static void
print_1sdiff_line(left,sep,right)1772286d8edStholo print_1sdiff_line (left, sep, right)
1782286d8edStholo char const * const *left;
1792286d8edStholo int sep;
1802286d8edStholo char const * const *right;
1812286d8edStholo {
1822286d8edStholo unsigned hw = sdiff_half_width, c2o = sdiff_column2_offset;
1832286d8edStholo unsigned col = 0;
1842286d8edStholo int put_newline = 0;
1852286d8edStholo
1862286d8edStholo if (left)
1872286d8edStholo {
1882286d8edStholo if (left[1][-1] == '\n')
1892286d8edStholo put_newline = 1;
1902286d8edStholo col = print_half_line (left, 0, hw);
1912286d8edStholo }
1922286d8edStholo
1932286d8edStholo if (sep != ' ')
1942286d8edStholo {
195b2346922Stholo char cc;
196b2346922Stholo
1972286d8edStholo col = tab_from_to (col, (hw + c2o - 1) / 2) + 1;
1982286d8edStholo if (sep == '|' && put_newline != (right[1][-1] == '\n'))
1992286d8edStholo sep = put_newline ? '/' : '\\';
200b2346922Stholo cc = sep;
201b2346922Stholo write_output (&cc, 1);
2022286d8edStholo }
2032286d8edStholo
2042286d8edStholo if (right)
2052286d8edStholo {
2062286d8edStholo if (right[1][-1] == '\n')
2072286d8edStholo put_newline = 1;
2082286d8edStholo if (**right != '\n')
2092286d8edStholo {
2102286d8edStholo col = tab_from_to (col, c2o);
2112286d8edStholo print_half_line (right, col, hw);
2122286d8edStholo }
2132286d8edStholo }
2142286d8edStholo
2152286d8edStholo if (put_newline)
216b2346922Stholo write_output ("\n", 1);
2172286d8edStholo }
2182286d8edStholo
2192286d8edStholo /* Print lines common to both files in side-by-side format. */
2202286d8edStholo static void
print_sdiff_common_lines(limit0,limit1)2212286d8edStholo print_sdiff_common_lines (limit0, limit1)
2222286d8edStholo int limit0, limit1;
2232286d8edStholo {
2242286d8edStholo int i0 = next0, i1 = next1;
2252286d8edStholo
2262286d8edStholo if (! sdiff_skip_common_lines && (i0 != limit0 || i1 != limit1))
2272286d8edStholo {
2282286d8edStholo if (sdiff_help_sdiff)
229b2346922Stholo printf_output ("i%d,%d\n", limit0 - i0, limit1 - i1);
2302286d8edStholo
2312286d8edStholo if (! sdiff_left_only)
2322286d8edStholo {
2332286d8edStholo while (i0 != limit0 && i1 != limit1)
2342286d8edStholo print_1sdiff_line (&files[0].linbuf[i0++], ' ', &files[1].linbuf[i1++]);
2352286d8edStholo while (i1 != limit1)
2362286d8edStholo print_1sdiff_line (0, ')', &files[1].linbuf[i1++]);
2372286d8edStholo }
2382286d8edStholo while (i0 != limit0)
2392286d8edStholo print_1sdiff_line (&files[0].linbuf[i0++], '(', 0);
2402286d8edStholo }
2412286d8edStholo
2422286d8edStholo next0 = limit0;
2432286d8edStholo next1 = limit1;
2442286d8edStholo }
2452286d8edStholo
2462286d8edStholo /* Print a hunk of an sdiff diff.
2472286d8edStholo This is a contiguous portion of a complete edit script,
2482286d8edStholo describing changes in consecutive lines. */
2492286d8edStholo
2502286d8edStholo static void
print_sdiff_hunk(hunk)2512286d8edStholo print_sdiff_hunk (hunk)
2522286d8edStholo struct change *hunk;
2532286d8edStholo {
2542286d8edStholo int first0, last0, first1, last1, deletes, inserts;
2552286d8edStholo register int i, j;
2562286d8edStholo
2572286d8edStholo /* Determine range of line numbers involved in each file. */
2582286d8edStholo analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
2592286d8edStholo if (!deletes && !inserts)
2602286d8edStholo return;
2612286d8edStholo
2622286d8edStholo /* Print out lines up to this change. */
2632286d8edStholo print_sdiff_common_lines (first0, first1);
2642286d8edStholo
2652286d8edStholo if (sdiff_help_sdiff)
266b2346922Stholo printf_output ("c%d,%d\n", last0 - first0 + 1, last1 - first1 + 1);
2672286d8edStholo
2682286d8edStholo /* Print ``xxx | xxx '' lines */
2692286d8edStholo if (inserts && deletes)
2702286d8edStholo {
2712286d8edStholo for (i = first0, j = first1; i <= last0 && j <= last1; ++i, ++j)
2722286d8edStholo print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]);
2732286d8edStholo deletes = i <= last0;
2742286d8edStholo inserts = j <= last1;
2752286d8edStholo next0 = first0 = i;
2762286d8edStholo next1 = first1 = j;
2772286d8edStholo }
2782286d8edStholo
2792286d8edStholo
2802286d8edStholo /* Print `` > xxx '' lines */
2812286d8edStholo if (inserts)
2822286d8edStholo {
2832286d8edStholo for (j = first1; j <= last1; ++j)
2842286d8edStholo print_1sdiff_line (0, '>', &files[1].linbuf[j]);
2852286d8edStholo next1 = j;
2862286d8edStholo }
2872286d8edStholo
2882286d8edStholo /* Print ``xxx < '' lines */
2892286d8edStholo if (deletes)
2902286d8edStholo {
2912286d8edStholo for (i = first0; i <= last0; ++i)
2922286d8edStholo print_1sdiff_line (&files[0].linbuf[i], '<', 0);
2932286d8edStholo next0 = i;
2942286d8edStholo }
2952286d8edStholo }
296