12286d8edStholo /* sdiff-format output routines for GNU DIFF. 2*b2346922Stholo 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 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 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 { 58*b2346922Stholo write_output ("\t", 1); 592286d8edStholo from = tab; 602286d8edStholo } 612286d8edStholo while (from++ < to) 62*b2346922Stholo 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 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++; 84*b2346922Stholo /* We use CC to avoid taking the address of the register 85*b2346922Stholo variable C. */ 86*b2346922Stholo 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++) 101*b2346922Stholo write_output (" ", 1); 1022286d8edStholo } 1032286d8edStholo else 1042286d8edStholo if (tabstop < out_bound) 1052286d8edStholo { 1062286d8edStholo out_position = tabstop; 107*b2346922Stholo cc = c; 108*b2346922Stholo write_output (&cc, 1); 1092286d8edStholo } 1102286d8edStholo } 1112286d8edStholo in_position += spaces; 1122286d8edStholo } 1132286d8edStholo break; 1142286d8edStholo 1152286d8edStholo case '\r': 1162286d8edStholo { 117*b2346922Stholo cc = c; 118*b2346922Stholo write_output (&cc, 1); 1192286d8edStholo tab_from_to (0, indent); 1202286d8edStholo in_position = out_position = 0; 1212286d8edStholo } 1222286d8edStholo break; 1232286d8edStholo 1242286d8edStholo case '\b': 1252286d8edStholo 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++) 129*b2346922Stholo write_output (" ", 1); 1302286d8edStholo else 1312286d8edStholo { 1322286d8edStholo out_position = in_position; 133*b2346922Stholo cc = c; 134*b2346922Stholo write_output (&cc, 1); 1352286d8edStholo } 1362286d8edStholo break; 1372286d8edStholo 1382286d8edStholo case '\f': 1392286d8edStholo case '\v': 1402286d8edStholo control_char: 1412286d8edStholo if (in_position < out_bound) 142*b2346922Stholo { 143*b2346922Stholo cc = c; 144*b2346922Stholo write_output (&cc, 1); 145*b2346922Stholo } 1462286d8edStholo break; 1472286d8edStholo 1482286d8edStholo default: 1492286d8edStholo if (! ISPRINT (c)) 1502286d8edStholo goto control_char; 1512286d8edStholo /* falls through */ 1522286d8edStholo case ' ': 1532286d8edStholo if (in_position++ < out_bound) 1542286d8edStholo { 1552286d8edStholo out_position = in_position; 156*b2346922Stholo cc = c; 157*b2346922Stholo write_output (&cc, 1); 1582286d8edStholo } 1592286d8edStholo break; 1602286d8edStholo 1612286d8edStholo case '\n': 1622286d8edStholo return out_position; 1632286d8edStholo } 1642286d8edStholo } 1652286d8edStholo 1662286d8edStholo return out_position; 1672286d8edStholo } 1682286d8edStholo 1692286d8edStholo /* 1702286d8edStholo * Print side by side lines with a separator in the middle. 1712286d8edStholo * 0 parameters are taken to indicate white space text. 1722286d8edStholo * Blank lines that can easily be caught are reduced to a single newline. 1732286d8edStholo */ 1742286d8edStholo 1752286d8edStholo static void 1762286d8edStholo print_1sdiff_line (left, sep, right) 1772286d8edStholo char const * const *left; 1782286d8edStholo int sep; 1792286d8edStholo char const * const *right; 1802286d8edStholo { 1812286d8edStholo unsigned hw = sdiff_half_width, c2o = sdiff_column2_offset; 1822286d8edStholo unsigned col = 0; 1832286d8edStholo int put_newline = 0; 1842286d8edStholo 1852286d8edStholo if (left) 1862286d8edStholo { 1872286d8edStholo if (left[1][-1] == '\n') 1882286d8edStholo put_newline = 1; 1892286d8edStholo col = print_half_line (left, 0, hw); 1902286d8edStholo } 1912286d8edStholo 1922286d8edStholo if (sep != ' ') 1932286d8edStholo { 194*b2346922Stholo char cc; 195*b2346922Stholo 1962286d8edStholo col = tab_from_to (col, (hw + c2o - 1) / 2) + 1; 1972286d8edStholo if (sep == '|' && put_newline != (right[1][-1] == '\n')) 1982286d8edStholo sep = put_newline ? '/' : '\\'; 199*b2346922Stholo cc = sep; 200*b2346922Stholo write_output (&cc, 1); 2012286d8edStholo } 2022286d8edStholo 2032286d8edStholo if (right) 2042286d8edStholo { 2052286d8edStholo if (right[1][-1] == '\n') 2062286d8edStholo put_newline = 1; 2072286d8edStholo if (**right != '\n') 2082286d8edStholo { 2092286d8edStholo col = tab_from_to (col, c2o); 2102286d8edStholo print_half_line (right, col, hw); 2112286d8edStholo } 2122286d8edStholo } 2132286d8edStholo 2142286d8edStholo if (put_newline) 215*b2346922Stholo write_output ("\n", 1); 2162286d8edStholo } 2172286d8edStholo 2182286d8edStholo /* Print lines common to both files in side-by-side format. */ 2192286d8edStholo static void 2202286d8edStholo print_sdiff_common_lines (limit0, limit1) 2212286d8edStholo int limit0, limit1; 2222286d8edStholo { 2232286d8edStholo int i0 = next0, i1 = next1; 2242286d8edStholo 2252286d8edStholo if (! sdiff_skip_common_lines && (i0 != limit0 || i1 != limit1)) 2262286d8edStholo { 2272286d8edStholo if (sdiff_help_sdiff) 228*b2346922Stholo printf_output ("i%d,%d\n", limit0 - i0, limit1 - i1); 2292286d8edStholo 2302286d8edStholo if (! sdiff_left_only) 2312286d8edStholo { 2322286d8edStholo while (i0 != limit0 && i1 != limit1) 2332286d8edStholo print_1sdiff_line (&files[0].linbuf[i0++], ' ', &files[1].linbuf[i1++]); 2342286d8edStholo while (i1 != limit1) 2352286d8edStholo print_1sdiff_line (0, ')', &files[1].linbuf[i1++]); 2362286d8edStholo } 2372286d8edStholo while (i0 != limit0) 2382286d8edStholo print_1sdiff_line (&files[0].linbuf[i0++], '(', 0); 2392286d8edStholo } 2402286d8edStholo 2412286d8edStholo next0 = limit0; 2422286d8edStholo next1 = limit1; 2432286d8edStholo } 2442286d8edStholo 2452286d8edStholo /* Print a hunk of an sdiff diff. 2462286d8edStholo This is a contiguous portion of a complete edit script, 2472286d8edStholo describing changes in consecutive lines. */ 2482286d8edStholo 2492286d8edStholo static void 2502286d8edStholo print_sdiff_hunk (hunk) 2512286d8edStholo struct change *hunk; 2522286d8edStholo { 2532286d8edStholo int first0, last0, first1, last1, deletes, inserts; 2542286d8edStholo register int i, j; 2552286d8edStholo 2562286d8edStholo /* Determine range of line numbers involved in each file. */ 2572286d8edStholo analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts); 2582286d8edStholo if (!deletes && !inserts) 2592286d8edStholo return; 2602286d8edStholo 2612286d8edStholo /* Print out lines up to this change. */ 2622286d8edStholo print_sdiff_common_lines (first0, first1); 2632286d8edStholo 2642286d8edStholo if (sdiff_help_sdiff) 265*b2346922Stholo printf_output ("c%d,%d\n", last0 - first0 + 1, last1 - first1 + 1); 2662286d8edStholo 2672286d8edStholo /* Print ``xxx | xxx '' lines */ 2682286d8edStholo if (inserts && deletes) 2692286d8edStholo { 2702286d8edStholo for (i = first0, j = first1; i <= last0 && j <= last1; ++i, ++j) 2712286d8edStholo print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]); 2722286d8edStholo deletes = i <= last0; 2732286d8edStholo inserts = j <= last1; 2742286d8edStholo next0 = first0 = i; 2752286d8edStholo next1 = first1 = j; 2762286d8edStholo } 2772286d8edStholo 2782286d8edStholo 2792286d8edStholo /* Print `` > xxx '' lines */ 2802286d8edStholo if (inserts) 2812286d8edStholo { 2822286d8edStholo for (j = first1; j <= last1; ++j) 2832286d8edStholo print_1sdiff_line (0, '>', &files[1].linbuf[j]); 2842286d8edStholo next1 = j; 2852286d8edStholo } 2862286d8edStholo 2872286d8edStholo /* Print ``xxx < '' lines */ 2882286d8edStholo if (deletes) 2892286d8edStholo { 2902286d8edStholo for (i = first0; i <= last0; ++i) 2912286d8edStholo print_1sdiff_line (&files[0].linbuf[i], '<', 0); 2922286d8edStholo next0 = i; 2932286d8edStholo } 2942286d8edStholo } 295