132785Speter/* sdiff-format output routines for GNU DIFF. 244852Speter Copyright (C) 1991, 1992, 1993, 1998 Free Software Foundation, Inc. 332785Speter 432785SpeterThis file is part of GNU DIFF. 532785Speter 632785SpeterGNU DIFF is distributed in the hope that it will be useful, 732785Speterbut WITHOUT ANY WARRANTY. No author or distributor 832785Speteraccepts responsibility to anyone for the consequences of using it 932785Speteror for whether it serves any particular purpose or works at all, 1032785Speterunless he says so in writing. Refer to the GNU DIFF General Public 1132785SpeterLicense for full details. 1232785Speter 1332785SpeterEveryone is granted permission to copy, modify and redistribute 1432785SpeterGNU DIFF, but only under the conditions described in the 1532785SpeterGNU DIFF General Public License. A copy of this license is 1632785Spetersupposed to have been given to you along with GNU DIFF so you 1732785Spetercan know your rights and responsibilities. It should be in a 1832785Speterfile named COPYING. Among other things, the copyright notice 1932785Speterand this notice must be preserved on all copies. */ 2032785Speter 2132785Speter 2232785Speter#include "diff.h" 2332785Speter 2432785Speterstatic unsigned print_half_line PARAMS((char const * const *, unsigned, unsigned)); 2532785Speterstatic unsigned tab_from_to PARAMS((unsigned, unsigned)); 2632785Speterstatic void print_1sdiff_line PARAMS((char const * const *, int, char const * const *)); 2732785Speterstatic void print_sdiff_common_lines PARAMS((int, int)); 2832785Speterstatic void print_sdiff_hunk PARAMS((struct change *)); 2932785Speter 3032785Speter/* Next line number to be printed in the two input files. */ 3132785Speterstatic int next0, next1; 3232785Speter 3332785Speter/* Print the edit-script SCRIPT as a sdiff style output. */ 3432785Speter 3532785Spetervoid 3632785Speterprint_sdiff_script (script) 3732785Speter struct change *script; 3832785Speter{ 3932785Speter begin_output (); 4032785Speter 4132785Speter next0 = next1 = - files[0].prefix_lines; 4232785Speter print_script (script, find_change, print_sdiff_hunk); 4332785Speter 4432785Speter print_sdiff_common_lines (files[0].valid_lines, files[1].valid_lines); 4532785Speter} 4632785Speter 4732785Speter/* Tab from column FROM to column TO, where FROM <= TO. Yield TO. */ 4832785Speter 4932785Speterstatic unsigned 5032785Spetertab_from_to (from, to) 5132785Speter unsigned from, to; 5232785Speter{ 5332785Speter unsigned tab; 5432785Speter 5532785Speter if (! tab_expand_flag) 5632785Speter for (tab = from + TAB_WIDTH - from % TAB_WIDTH; tab <= to; tab += TAB_WIDTH) 5732785Speter { 5844852Speter write_output ("\t", 1); 5932785Speter from = tab; 6032785Speter } 6132785Speter while (from++ < to) 6244852Speter write_output (" ", 1); 6332785Speter return to; 6432785Speter} 6532785Speter 6632785Speter/* 6732785Speter * Print the text for half an sdiff line. This means truncate to width 6832785Speter * observing tabs, and trim a trailing newline. Returns the last column 6932785Speter * written (not the number of chars). 7032785Speter */ 7132785Speterstatic unsigned 7232785Speterprint_half_line (line, indent, out_bound) 7332785Speter char const * const *line; 7432785Speter unsigned indent, out_bound; 7532785Speter{ 7632785Speter register unsigned in_position = 0, out_position = 0; 7732785Speter register char const 7832785Speter *text_pointer = line[0], 7932785Speter *text_limit = line[1]; 8032785Speter 8132785Speter while (text_pointer < text_limit) 8232785Speter { 8332785Speter register unsigned char c = *text_pointer++; 8444852Speter /* We use CC to avoid taking the address of the register 8544852Speter variable C. */ 8644852Speter char cc; 8732785Speter 8832785Speter switch (c) 8932785Speter { 9032785Speter case '\t': 9132785Speter { 9232785Speter unsigned spaces = TAB_WIDTH - in_position % TAB_WIDTH; 9332785Speter if (in_position == out_position) 9432785Speter { 9532785Speter unsigned tabstop = out_position + spaces; 9632785Speter if (tab_expand_flag) 9732785Speter { 9832785Speter if (out_bound < tabstop) 9932785Speter tabstop = out_bound; 10032785Speter for (; out_position < tabstop; out_position++) 10144852Speter write_output (" ", 1); 10232785Speter } 10332785Speter else 10432785Speter if (tabstop < out_bound) 10532785Speter { 10632785Speter out_position = tabstop; 10744852Speter cc = c; 10844852Speter write_output (&cc, 1); 10932785Speter } 11032785Speter } 11132785Speter in_position += spaces; 11232785Speter } 11332785Speter break; 11432785Speter 11532785Speter case '\r': 11632785Speter { 11744852Speter cc = c; 11844852Speter write_output (&cc, 1); 11932785Speter tab_from_to (0, indent); 12032785Speter in_position = out_position = 0; 12132785Speter } 12232785Speter break; 12332785Speter 12432785Speter case '\b': 12532785Speter if (in_position != 0 && --in_position < out_bound) 12632785Speter if (out_position <= in_position) 12732785Speter /* Add spaces to make up for suppressed tab past out_bound. */ 12832785Speter for (; out_position < in_position; out_position++) 12944852Speter write_output (" ", 1); 13032785Speter else 13132785Speter { 13232785Speter out_position = in_position; 13344852Speter cc = c; 13444852Speter write_output (&cc, 1); 13532785Speter } 13632785Speter break; 13732785Speter 13832785Speter case '\f': 13932785Speter case '\v': 14032785Speter control_char: 14132785Speter if (in_position < out_bound) 14244852Speter { 14344852Speter cc = c; 14444852Speter write_output (&cc, 1); 14544852Speter } 14632785Speter break; 14732785Speter 14832785Speter default: 14932785Speter if (! ISPRINT (c)) 15032785Speter goto control_char; 15132785Speter /* falls through */ 15232785Speter case ' ': 15332785Speter if (in_position++ < out_bound) 15432785Speter { 15532785Speter out_position = in_position; 15644852Speter cc = c; 15744852Speter write_output (&cc, 1); 15832785Speter } 15932785Speter break; 16032785Speter 16132785Speter case '\n': 16232785Speter return out_position; 16332785Speter } 16432785Speter } 16532785Speter 16632785Speter return out_position; 16732785Speter} 16832785Speter 16932785Speter/* 17032785Speter * Print side by side lines with a separator in the middle. 17132785Speter * 0 parameters are taken to indicate white space text. 17232785Speter * Blank lines that can easily be caught are reduced to a single newline. 17332785Speter */ 17432785Speter 17532785Speterstatic void 17632785Speterprint_1sdiff_line (left, sep, right) 17732785Speter char const * const *left; 17832785Speter int sep; 17932785Speter char const * const *right; 18032785Speter{ 18132785Speter unsigned hw = sdiff_half_width, c2o = sdiff_column2_offset; 18232785Speter unsigned col = 0; 18332785Speter int put_newline = 0; 18432785Speter 18532785Speter if (left) 18632785Speter { 18732785Speter if (left[1][-1] == '\n') 18832785Speter put_newline = 1; 18932785Speter col = print_half_line (left, 0, hw); 19032785Speter } 19132785Speter 19232785Speter if (sep != ' ') 19332785Speter { 19444852Speter char cc; 19544852Speter 19632785Speter col = tab_from_to (col, (hw + c2o - 1) / 2) + 1; 19732785Speter if (sep == '|' && put_newline != (right[1][-1] == '\n')) 19832785Speter sep = put_newline ? '/' : '\\'; 19944852Speter cc = sep; 20044852Speter write_output (&cc, 1); 20132785Speter } 20232785Speter 20332785Speter if (right) 20432785Speter { 20532785Speter if (right[1][-1] == '\n') 20632785Speter put_newline = 1; 20732785Speter if (**right != '\n') 20832785Speter { 20932785Speter col = tab_from_to (col, c2o); 21032785Speter print_half_line (right, col, hw); 21132785Speter } 21232785Speter } 21332785Speter 21432785Speter if (put_newline) 21544852Speter write_output ("\n", 1); 21632785Speter} 21732785Speter 21832785Speter/* Print lines common to both files in side-by-side format. */ 21932785Speterstatic void 22032785Speterprint_sdiff_common_lines (limit0, limit1) 22132785Speter int limit0, limit1; 22232785Speter{ 22332785Speter int i0 = next0, i1 = next1; 22432785Speter 22532785Speter if (! sdiff_skip_common_lines && (i0 != limit0 || i1 != limit1)) 22632785Speter { 22732785Speter if (sdiff_help_sdiff) 22844852Speter printf_output ("i%d,%d\n", limit0 - i0, limit1 - i1); 22932785Speter 23032785Speter if (! sdiff_left_only) 23132785Speter { 23232785Speter while (i0 != limit0 && i1 != limit1) 23332785Speter print_1sdiff_line (&files[0].linbuf[i0++], ' ', &files[1].linbuf[i1++]); 23432785Speter while (i1 != limit1) 23532785Speter print_1sdiff_line (0, ')', &files[1].linbuf[i1++]); 23632785Speter } 23732785Speter while (i0 != limit0) 23832785Speter print_1sdiff_line (&files[0].linbuf[i0++], '(', 0); 23932785Speter } 24032785Speter 24132785Speter next0 = limit0; 24232785Speter next1 = limit1; 24332785Speter} 24432785Speter 24532785Speter/* Print a hunk of an sdiff diff. 24632785Speter This is a contiguous portion of a complete edit script, 24732785Speter describing changes in consecutive lines. */ 24832785Speter 24932785Speterstatic void 25032785Speterprint_sdiff_hunk (hunk) 25132785Speter struct change *hunk; 25232785Speter{ 25332785Speter int first0, last0, first1, last1, deletes, inserts; 25432785Speter register int i, j; 25532785Speter 25632785Speter /* Determine range of line numbers involved in each file. */ 25732785Speter analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts); 25832785Speter if (!deletes && !inserts) 25932785Speter return; 26032785Speter 26132785Speter /* Print out lines up to this change. */ 26232785Speter print_sdiff_common_lines (first0, first1); 26332785Speter 26432785Speter if (sdiff_help_sdiff) 26544852Speter printf_output ("c%d,%d\n", last0 - first0 + 1, last1 - first1 + 1); 26632785Speter 26732785Speter /* Print ``xxx | xxx '' lines */ 26832785Speter if (inserts && deletes) 26932785Speter { 27032785Speter for (i = first0, j = first1; i <= last0 && j <= last1; ++i, ++j) 27132785Speter print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]); 27232785Speter deletes = i <= last0; 27332785Speter inserts = j <= last1; 27432785Speter next0 = first0 = i; 27532785Speter next1 = first1 = j; 27632785Speter } 27732785Speter 27832785Speter 27932785Speter /* Print `` > xxx '' lines */ 28032785Speter if (inserts) 28132785Speter { 28232785Speter for (j = first1; j <= last1; ++j) 28332785Speter print_1sdiff_line (0, '>', &files[1].linbuf[j]); 28432785Speter next1 = j; 28532785Speter } 28632785Speter 28732785Speter /* Print ``xxx < '' lines */ 28832785Speter if (deletes) 28932785Speter { 29032785Speter for (i = first0; i <= last0; ++i) 29132785Speter print_1sdiff_line (&files[0].linbuf[i], '<', 0); 29232785Speter next0 = i; 29332785Speter } 29432785Speter} 295