118fd37a7SXin LI /* sdiff-format output routines for GNU DIFF.
218fd37a7SXin LI
318fd37a7SXin LI Copyright (C) 1991, 1992, 1993, 1998, 2001, 2002, 2004 Free
418fd37a7SXin LI Software Foundation, Inc.
518fd37a7SXin LI
618fd37a7SXin LI This file is part of GNU DIFF.
718fd37a7SXin LI
818fd37a7SXin LI GNU DIFF is distributed in the hope that it will be useful,
918fd37a7SXin LI but WITHOUT ANY WARRANTY. No author or distributor
1018fd37a7SXin LI accepts responsibility to anyone for the consequences of using it
1118fd37a7SXin LI or for whether it serves any particular purpose or works at all,
1218fd37a7SXin LI unless he says so in writing. Refer to the GNU DIFF General Public
1318fd37a7SXin LI License for full details.
1418fd37a7SXin LI
1518fd37a7SXin LI Everyone is granted permission to copy, modify and redistribute
1618fd37a7SXin LI GNU DIFF, but only under the conditions described in the
1718fd37a7SXin LI GNU DIFF General Public License. A copy of this license is
1818fd37a7SXin LI supposed to have been given to you along with GNU DIFF so you
1918fd37a7SXin LI can know your rights and responsibilities. It should be in a
2018fd37a7SXin LI file named COPYING. Among other things, the copyright notice
2118fd37a7SXin LI and this notice must be preserved on all copies. */
2218fd37a7SXin LI
2318fd37a7SXin LI #include "diff.h"
2418fd37a7SXin LI
2518fd37a7SXin LI static void print_sdiff_common_lines (lin, lin);
2618fd37a7SXin LI static void print_sdiff_hunk (struct change *);
2718fd37a7SXin LI
2818fd37a7SXin LI /* Next line number to be printed in the two input files. */
2918fd37a7SXin LI static lin next0, next1;
3018fd37a7SXin LI
3118fd37a7SXin LI /* Print the edit-script SCRIPT as a sdiff style output. */
3218fd37a7SXin LI
3318fd37a7SXin LI void
print_sdiff_script(struct change * script)3418fd37a7SXin LI print_sdiff_script (struct change *script)
3518fd37a7SXin LI {
3618fd37a7SXin LI begin_output ();
3718fd37a7SXin LI
3818fd37a7SXin LI next0 = next1 = - files[0].prefix_lines;
3918fd37a7SXin LI print_script (script, find_change, print_sdiff_hunk);
4018fd37a7SXin LI
4118fd37a7SXin LI print_sdiff_common_lines (files[0].valid_lines, files[1].valid_lines);
4218fd37a7SXin LI }
4318fd37a7SXin LI
4418fd37a7SXin LI /* Tab from column FROM to column TO, where FROM <= TO. Yield TO. */
4518fd37a7SXin LI
4618fd37a7SXin LI static size_t
tab_from_to(size_t from,size_t to)4718fd37a7SXin LI tab_from_to (size_t from, size_t to)
4818fd37a7SXin LI {
4918fd37a7SXin LI FILE *out = outfile;
5018fd37a7SXin LI size_t tab;
5118fd37a7SXin LI size_t tab_size = tabsize;
5218fd37a7SXin LI
5318fd37a7SXin LI if (!expand_tabs)
5418fd37a7SXin LI for (tab = from + tab_size - from % tab_size; tab <= to; tab += tab_size)
5518fd37a7SXin LI {
5618fd37a7SXin LI putc ('\t', out);
5718fd37a7SXin LI from = tab;
5818fd37a7SXin LI }
5918fd37a7SXin LI while (from++ < to)
6018fd37a7SXin LI putc (' ', out);
6118fd37a7SXin LI return to;
6218fd37a7SXin LI }
6318fd37a7SXin LI
6418fd37a7SXin LI /* Print the text for half an sdiff line. This means truncate to
6518fd37a7SXin LI width observing tabs, and trim a trailing newline. Return the
6618fd37a7SXin LI last column written (not the number of chars). */
6718fd37a7SXin LI
6818fd37a7SXin LI static size_t
print_half_line(char const * const * line,size_t indent,size_t out_bound)6918fd37a7SXin LI print_half_line (char const *const *line, size_t indent, size_t out_bound)
7018fd37a7SXin LI {
7118fd37a7SXin LI FILE *out = outfile;
7218fd37a7SXin LI register size_t in_position = 0;
7318fd37a7SXin LI register size_t out_position = 0;
7418fd37a7SXin LI register char const *text_pointer = line[0];
7518fd37a7SXin LI register char const *text_limit = line[1];
7618fd37a7SXin LI
7718fd37a7SXin LI while (text_pointer < text_limit)
7818fd37a7SXin LI {
7918fd37a7SXin LI register unsigned char c = *text_pointer++;
8018fd37a7SXin LI
8118fd37a7SXin LI switch (c)
8218fd37a7SXin LI {
8318fd37a7SXin LI case '\t':
8418fd37a7SXin LI {
8518fd37a7SXin LI size_t spaces = tabsize - in_position % tabsize;
8618fd37a7SXin LI if (in_position == out_position)
8718fd37a7SXin LI {
8818fd37a7SXin LI size_t tabstop = out_position + spaces;
8918fd37a7SXin LI if (expand_tabs)
9018fd37a7SXin LI {
9118fd37a7SXin LI if (out_bound < tabstop)
9218fd37a7SXin LI tabstop = out_bound;
9318fd37a7SXin LI for (; out_position < tabstop; out_position++)
9418fd37a7SXin LI putc (' ', out);
9518fd37a7SXin LI }
9618fd37a7SXin LI else
9718fd37a7SXin LI if (tabstop < out_bound)
9818fd37a7SXin LI {
9918fd37a7SXin LI out_position = tabstop;
10018fd37a7SXin LI putc (c, out);
10118fd37a7SXin LI }
10218fd37a7SXin LI }
10318fd37a7SXin LI in_position += spaces;
10418fd37a7SXin LI }
10518fd37a7SXin LI break;
10618fd37a7SXin LI
10718fd37a7SXin LI case '\r':
10818fd37a7SXin LI {
10918fd37a7SXin LI putc (c, out);
11018fd37a7SXin LI tab_from_to (0, indent);
11118fd37a7SXin LI in_position = out_position = 0;
11218fd37a7SXin LI }
11318fd37a7SXin LI break;
11418fd37a7SXin LI
11518fd37a7SXin LI case '\b':
11618fd37a7SXin LI if (in_position != 0 && --in_position < out_bound)
11718fd37a7SXin LI {
11818fd37a7SXin LI if (out_position <= in_position)
11918fd37a7SXin LI /* Add spaces to make up for suppressed tab past out_bound. */
12018fd37a7SXin LI for (; out_position < in_position; out_position++)
12118fd37a7SXin LI putc (' ', out);
12218fd37a7SXin LI else
12318fd37a7SXin LI {
12418fd37a7SXin LI out_position = in_position;
12518fd37a7SXin LI putc (c, out);
12618fd37a7SXin LI }
12718fd37a7SXin LI }
12818fd37a7SXin LI break;
12918fd37a7SXin LI
13018fd37a7SXin LI case '\f':
13118fd37a7SXin LI case '\v':
13218fd37a7SXin LI control_char:
13318fd37a7SXin LI if (in_position < out_bound)
13418fd37a7SXin LI putc (c, out);
13518fd37a7SXin LI break;
13618fd37a7SXin LI
13718fd37a7SXin LI default:
13818fd37a7SXin LI if (! isprint (c))
13918fd37a7SXin LI goto control_char;
14018fd37a7SXin LI /* falls through */
14118fd37a7SXin LI case ' ':
14218fd37a7SXin LI if (in_position++ < out_bound)
14318fd37a7SXin LI {
14418fd37a7SXin LI out_position = in_position;
14518fd37a7SXin LI putc (c, out);
14618fd37a7SXin LI }
14718fd37a7SXin LI break;
14818fd37a7SXin LI
14918fd37a7SXin LI case '\n':
15018fd37a7SXin LI return out_position;
15118fd37a7SXin LI }
15218fd37a7SXin LI }
15318fd37a7SXin LI
15418fd37a7SXin LI return out_position;
15518fd37a7SXin LI }
15618fd37a7SXin LI
15718fd37a7SXin LI /* Print side by side lines with a separator in the middle.
15818fd37a7SXin LI 0 parameters are taken to indicate white space text.
15918fd37a7SXin LI Blank lines that can easily be caught are reduced to a single newline. */
16018fd37a7SXin LI
16118fd37a7SXin LI static void
print_1sdiff_line(char const * const * left,char sep,char const * const * right)16218fd37a7SXin LI print_1sdiff_line (char const *const *left, char sep,
16318fd37a7SXin LI char const *const *right)
16418fd37a7SXin LI {
16518fd37a7SXin LI FILE *out = outfile;
16618fd37a7SXin LI size_t hw = sdiff_half_width;
16718fd37a7SXin LI size_t c2o = sdiff_column2_offset;
16818fd37a7SXin LI size_t col = 0;
16918fd37a7SXin LI bool put_newline = false;
17018fd37a7SXin LI
17118fd37a7SXin LI if (left)
17218fd37a7SXin LI {
17318fd37a7SXin LI put_newline |= left[1][-1] == '\n';
17418fd37a7SXin LI col = print_half_line (left, 0, hw);
17518fd37a7SXin LI }
17618fd37a7SXin LI
17718fd37a7SXin LI if (sep != ' ')
17818fd37a7SXin LI {
17918fd37a7SXin LI col = tab_from_to (col, (hw + c2o - 1) / 2) + 1;
18018fd37a7SXin LI if (sep == '|' && put_newline != (right[1][-1] == '\n'))
18118fd37a7SXin LI sep = put_newline ? '/' : '\\';
18218fd37a7SXin LI putc (sep, out);
18318fd37a7SXin LI }
18418fd37a7SXin LI
18518fd37a7SXin LI if (right)
18618fd37a7SXin LI {
18718fd37a7SXin LI put_newline |= right[1][-1] == '\n';
18818fd37a7SXin LI if (**right != '\n')
18918fd37a7SXin LI {
19018fd37a7SXin LI col = tab_from_to (col, c2o);
19118fd37a7SXin LI print_half_line (right, col, hw);
19218fd37a7SXin LI }
19318fd37a7SXin LI }
19418fd37a7SXin LI
19518fd37a7SXin LI if (put_newline)
19618fd37a7SXin LI putc ('\n', out);
19718fd37a7SXin LI }
19818fd37a7SXin LI
19918fd37a7SXin LI /* Print lines common to both files in side-by-side format. */
20018fd37a7SXin LI static void
print_sdiff_common_lines(lin limit0,lin limit1)20118fd37a7SXin LI print_sdiff_common_lines (lin limit0, lin limit1)
20218fd37a7SXin LI {
20318fd37a7SXin LI lin i0 = next0, i1 = next1;
20418fd37a7SXin LI
20518fd37a7SXin LI if (!suppress_common_lines && (i0 != limit0 || i1 != limit1))
20618fd37a7SXin LI {
20718fd37a7SXin LI if (sdiff_merge_assist)
20818fd37a7SXin LI {
20918fd37a7SXin LI long int len0 = limit0 - i0;
21018fd37a7SXin LI long int len1 = limit1 - i1;
21118fd37a7SXin LI fprintf (outfile, "i%ld,%ld\n", len0, len1);
21218fd37a7SXin LI }
21318fd37a7SXin LI
21418fd37a7SXin LI if (!left_column)
21518fd37a7SXin LI {
21618fd37a7SXin LI while (i0 != limit0 && i1 != limit1)
21718fd37a7SXin LI print_1sdiff_line (&files[0].linbuf[i0++], ' ',
21818fd37a7SXin LI &files[1].linbuf[i1++]);
21918fd37a7SXin LI while (i1 != limit1)
22018fd37a7SXin LI print_1sdiff_line (0, ')', &files[1].linbuf[i1++]);
22118fd37a7SXin LI }
22218fd37a7SXin LI while (i0 != limit0)
22318fd37a7SXin LI print_1sdiff_line (&files[0].linbuf[i0++], '(', 0);
22418fd37a7SXin LI }
22518fd37a7SXin LI
22618fd37a7SXin LI next0 = limit0;
22718fd37a7SXin LI next1 = limit1;
22818fd37a7SXin LI }
22918fd37a7SXin LI
23018fd37a7SXin LI /* Print a hunk of an sdiff diff.
23118fd37a7SXin LI This is a contiguous portion of a complete edit script,
23218fd37a7SXin LI describing changes in consecutive lines. */
23318fd37a7SXin LI
23418fd37a7SXin LI static void
print_sdiff_hunk(struct change * hunk)23518fd37a7SXin LI print_sdiff_hunk (struct change *hunk)
23618fd37a7SXin LI {
23718fd37a7SXin LI lin first0, last0, first1, last1;
23818fd37a7SXin LI register lin i, j;
23918fd37a7SXin LI
24018fd37a7SXin LI /* Determine range of line numbers involved in each file. */
24118fd37a7SXin LI enum changes changes =
24218fd37a7SXin LI analyze_hunk (hunk, &first0, &last0, &first1, &last1);
24318fd37a7SXin LI if (!changes)
24418fd37a7SXin LI return;
24518fd37a7SXin LI
24618fd37a7SXin LI /* Print out lines up to this change. */
24718fd37a7SXin LI print_sdiff_common_lines (first0, first1);
24818fd37a7SXin LI
24918fd37a7SXin LI if (sdiff_merge_assist)
25018fd37a7SXin LI {
25118fd37a7SXin LI long int len0 = last0 - first0 + 1;
25218fd37a7SXin LI long int len1 = last1 - first1 + 1;
25318fd37a7SXin LI fprintf (outfile, "c%ld,%ld\n", len0, len1);
25418fd37a7SXin LI }
25518fd37a7SXin LI
25618fd37a7SXin LI /* Print ``xxx | xxx '' lines */
25718fd37a7SXin LI if (changes == CHANGED)
25818fd37a7SXin LI {
25918fd37a7SXin LI for (i = first0, j = first1; i <= last0 && j <= last1; i++, j++)
26018fd37a7SXin LI print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]);
26118fd37a7SXin LI changes = (i <= last0 ? OLD : 0) + (j <= last1 ? NEW : 0);
26218fd37a7SXin LI next0 = first0 = i;
26318fd37a7SXin LI next1 = first1 = j;
26418fd37a7SXin LI }
26518fd37a7SXin LI
26618fd37a7SXin LI /* Print `` > xxx '' lines */
26718fd37a7SXin LI if (changes & NEW)
26818fd37a7SXin LI {
26918fd37a7SXin LI for (j = first1; j <= last1; ++j)
27018fd37a7SXin LI print_1sdiff_line (0, '>', &files[1].linbuf[j]);
27118fd37a7SXin LI next1 = j;
27218fd37a7SXin LI }
27318fd37a7SXin LI
27418fd37a7SXin LI /* Print ``xxx < '' lines */
27518fd37a7SXin LI if (changes & OLD)
27618fd37a7SXin LI {
27718fd37a7SXin LI for (i = first0; i <= last0; ++i)
27818fd37a7SXin LI print_1sdiff_line (&files[0].linbuf[i], '<', 0);
27918fd37a7SXin LI next0 = i;
28018fd37a7SXin LI }
28118fd37a7SXin LI }
282