1170754Sdelphij/* sdiff-format output routines for GNU DIFF. 2170754Sdelphij 3170754Sdelphij Copyright (C) 1991, 1992, 1993, 1998, 2001, 2002, 2004 Free 4170754Sdelphij Software Foundation, Inc. 5170754Sdelphij 6170754Sdelphij This file is part of GNU DIFF. 7170754Sdelphij 8170754Sdelphij GNU DIFF is distributed in the hope that it will be useful, 9170754Sdelphij but WITHOUT ANY WARRANTY. No author or distributor 10170754Sdelphij accepts responsibility to anyone for the consequences of using it 11170754Sdelphij or for whether it serves any particular purpose or works at all, 12170754Sdelphij unless he says so in writing. Refer to the GNU DIFF General Public 13170754Sdelphij License for full details. 14170754Sdelphij 15170754Sdelphij Everyone is granted permission to copy, modify and redistribute 16170754Sdelphij GNU DIFF, but only under the conditions described in the 17170754Sdelphij GNU DIFF General Public License. A copy of this license is 18170754Sdelphij supposed to have been given to you along with GNU DIFF so you 19170754Sdelphij can know your rights and responsibilities. It should be in a 20170754Sdelphij file named COPYING. Among other things, the copyright notice 21170754Sdelphij and this notice must be preserved on all copies. */ 22170754Sdelphij 23170754Sdelphij#include "diff.h" 24170754Sdelphij 25170754Sdelphijstatic void print_sdiff_common_lines (lin, lin); 26170754Sdelphijstatic void print_sdiff_hunk (struct change *); 27170754Sdelphij 28170754Sdelphij/* Next line number to be printed in the two input files. */ 29170754Sdelphijstatic lin next0, next1; 30170754Sdelphij 31170754Sdelphij/* Print the edit-script SCRIPT as a sdiff style output. */ 32170754Sdelphij 33170754Sdelphijvoid 34170754Sdelphijprint_sdiff_script (struct change *script) 35170754Sdelphij{ 36170754Sdelphij begin_output (); 37170754Sdelphij 38170754Sdelphij next0 = next1 = - files[0].prefix_lines; 39170754Sdelphij print_script (script, find_change, print_sdiff_hunk); 40170754Sdelphij 41170754Sdelphij print_sdiff_common_lines (files[0].valid_lines, files[1].valid_lines); 42170754Sdelphij} 43170754Sdelphij 44170754Sdelphij/* Tab from column FROM to column TO, where FROM <= TO. Yield TO. */ 45170754Sdelphij 46170754Sdelphijstatic size_t 47170754Sdelphijtab_from_to (size_t from, size_t to) 48170754Sdelphij{ 49170754Sdelphij FILE *out = outfile; 50170754Sdelphij size_t tab; 51170754Sdelphij size_t tab_size = tabsize; 52170754Sdelphij 53170754Sdelphij if (!expand_tabs) 54170754Sdelphij for (tab = from + tab_size - from % tab_size; tab <= to; tab += tab_size) 55170754Sdelphij { 56170754Sdelphij putc ('\t', out); 57170754Sdelphij from = tab; 58170754Sdelphij } 59170754Sdelphij while (from++ < to) 60170754Sdelphij putc (' ', out); 61170754Sdelphij return to; 62170754Sdelphij} 63170754Sdelphij 64170754Sdelphij/* Print the text for half an sdiff line. This means truncate to 65170754Sdelphij width observing tabs, and trim a trailing newline. Return the 66170754Sdelphij last column written (not the number of chars). */ 67170754Sdelphij 68170754Sdelphijstatic size_t 69170754Sdelphijprint_half_line (char const *const *line, size_t indent, size_t out_bound) 70170754Sdelphij{ 71170754Sdelphij FILE *out = outfile; 72170754Sdelphij register size_t in_position = 0; 73170754Sdelphij register size_t out_position = 0; 74170754Sdelphij register char const *text_pointer = line[0]; 75170754Sdelphij register char const *text_limit = line[1]; 76170754Sdelphij 77170754Sdelphij while (text_pointer < text_limit) 78170754Sdelphij { 79170754Sdelphij register unsigned char c = *text_pointer++; 80170754Sdelphij 81170754Sdelphij switch (c) 82170754Sdelphij { 83170754Sdelphij case '\t': 84170754Sdelphij { 85170754Sdelphij size_t spaces = tabsize - in_position % tabsize; 86170754Sdelphij if (in_position == out_position) 87170754Sdelphij { 88170754Sdelphij size_t tabstop = out_position + spaces; 89170754Sdelphij if (expand_tabs) 90170754Sdelphij { 91170754Sdelphij if (out_bound < tabstop) 92170754Sdelphij tabstop = out_bound; 93170754Sdelphij for (; out_position < tabstop; out_position++) 94170754Sdelphij putc (' ', out); 95170754Sdelphij } 96170754Sdelphij else 97170754Sdelphij if (tabstop < out_bound) 98170754Sdelphij { 99170754Sdelphij out_position = tabstop; 100170754Sdelphij putc (c, out); 101170754Sdelphij } 102170754Sdelphij } 103170754Sdelphij in_position += spaces; 104170754Sdelphij } 105170754Sdelphij break; 106170754Sdelphij 107170754Sdelphij case '\r': 108170754Sdelphij { 109170754Sdelphij putc (c, out); 110170754Sdelphij tab_from_to (0, indent); 111170754Sdelphij in_position = out_position = 0; 112170754Sdelphij } 113170754Sdelphij break; 114170754Sdelphij 115170754Sdelphij case '\b': 116170754Sdelphij if (in_position != 0 && --in_position < out_bound) 117170754Sdelphij { 118170754Sdelphij if (out_position <= in_position) 119170754Sdelphij /* Add spaces to make up for suppressed tab past out_bound. */ 120170754Sdelphij for (; out_position < in_position; out_position++) 121170754Sdelphij putc (' ', out); 122170754Sdelphij else 123170754Sdelphij { 124170754Sdelphij out_position = in_position; 125170754Sdelphij putc (c, out); 126170754Sdelphij } 127170754Sdelphij } 128170754Sdelphij break; 129170754Sdelphij 130170754Sdelphij case '\f': 131170754Sdelphij case '\v': 132170754Sdelphij control_char: 133170754Sdelphij if (in_position < out_bound) 134170754Sdelphij putc (c, out); 135170754Sdelphij break; 136170754Sdelphij 137170754Sdelphij default: 138170754Sdelphij if (! isprint (c)) 139170754Sdelphij goto control_char; 140170754Sdelphij /* falls through */ 141170754Sdelphij case ' ': 142170754Sdelphij if (in_position++ < out_bound) 143170754Sdelphij { 144170754Sdelphij out_position = in_position; 145170754Sdelphij putc (c, out); 146170754Sdelphij } 147170754Sdelphij break; 148170754Sdelphij 149170754Sdelphij case '\n': 150170754Sdelphij return out_position; 151170754Sdelphij } 152170754Sdelphij } 153170754Sdelphij 154170754Sdelphij return out_position; 155170754Sdelphij} 156170754Sdelphij 157170754Sdelphij/* Print side by side lines with a separator in the middle. 158170754Sdelphij 0 parameters are taken to indicate white space text. 159170754Sdelphij Blank lines that can easily be caught are reduced to a single newline. */ 160170754Sdelphij 161170754Sdelphijstatic void 162170754Sdelphijprint_1sdiff_line (char const *const *left, char sep, 163170754Sdelphij char const *const *right) 164170754Sdelphij{ 165170754Sdelphij FILE *out = outfile; 166170754Sdelphij size_t hw = sdiff_half_width; 167170754Sdelphij size_t c2o = sdiff_column2_offset; 168170754Sdelphij size_t col = 0; 169170754Sdelphij bool put_newline = false; 170170754Sdelphij 171170754Sdelphij if (left) 172170754Sdelphij { 173170754Sdelphij put_newline |= left[1][-1] == '\n'; 174170754Sdelphij col = print_half_line (left, 0, hw); 175170754Sdelphij } 176170754Sdelphij 177170754Sdelphij if (sep != ' ') 178170754Sdelphij { 179170754Sdelphij col = tab_from_to (col, (hw + c2o - 1) / 2) + 1; 180170754Sdelphij if (sep == '|' && put_newline != (right[1][-1] == '\n')) 181170754Sdelphij sep = put_newline ? '/' : '\\'; 182170754Sdelphij putc (sep, out); 183170754Sdelphij } 184170754Sdelphij 185170754Sdelphij if (right) 186170754Sdelphij { 187170754Sdelphij put_newline |= right[1][-1] == '\n'; 188170754Sdelphij if (**right != '\n') 189170754Sdelphij { 190170754Sdelphij col = tab_from_to (col, c2o); 191170754Sdelphij print_half_line (right, col, hw); 192170754Sdelphij } 193170754Sdelphij } 194170754Sdelphij 195170754Sdelphij if (put_newline) 196170754Sdelphij putc ('\n', out); 197170754Sdelphij} 198170754Sdelphij 199170754Sdelphij/* Print lines common to both files in side-by-side format. */ 200170754Sdelphijstatic void 201170754Sdelphijprint_sdiff_common_lines (lin limit0, lin limit1) 202170754Sdelphij{ 203170754Sdelphij lin i0 = next0, i1 = next1; 204170754Sdelphij 205170754Sdelphij if (!suppress_common_lines && (i0 != limit0 || i1 != limit1)) 206170754Sdelphij { 207170754Sdelphij if (sdiff_merge_assist) 208170754Sdelphij { 209170754Sdelphij long int len0 = limit0 - i0; 210170754Sdelphij long int len1 = limit1 - i1; 211170754Sdelphij fprintf (outfile, "i%ld,%ld\n", len0, len1); 212170754Sdelphij } 213170754Sdelphij 214170754Sdelphij if (!left_column) 215170754Sdelphij { 216170754Sdelphij while (i0 != limit0 && i1 != limit1) 217170754Sdelphij print_1sdiff_line (&files[0].linbuf[i0++], ' ', 218170754Sdelphij &files[1].linbuf[i1++]); 219170754Sdelphij while (i1 != limit1) 220170754Sdelphij print_1sdiff_line (0, ')', &files[1].linbuf[i1++]); 221170754Sdelphij } 222170754Sdelphij while (i0 != limit0) 223170754Sdelphij print_1sdiff_line (&files[0].linbuf[i0++], '(', 0); 224170754Sdelphij } 225170754Sdelphij 226170754Sdelphij next0 = limit0; 227170754Sdelphij next1 = limit1; 228170754Sdelphij} 229170754Sdelphij 230170754Sdelphij/* Print a hunk of an sdiff diff. 231170754Sdelphij This is a contiguous portion of a complete edit script, 232170754Sdelphij describing changes in consecutive lines. */ 233170754Sdelphij 234170754Sdelphijstatic void 235170754Sdelphijprint_sdiff_hunk (struct change *hunk) 236170754Sdelphij{ 237170754Sdelphij lin first0, last0, first1, last1; 238170754Sdelphij register lin i, j; 239170754Sdelphij 240170754Sdelphij /* Determine range of line numbers involved in each file. */ 241170754Sdelphij enum changes changes = 242170754Sdelphij analyze_hunk (hunk, &first0, &last0, &first1, &last1); 243170754Sdelphij if (!changes) 244170754Sdelphij return; 245170754Sdelphij 246170754Sdelphij /* Print out lines up to this change. */ 247170754Sdelphij print_sdiff_common_lines (first0, first1); 248170754Sdelphij 249170754Sdelphij if (sdiff_merge_assist) 250170754Sdelphij { 251170754Sdelphij long int len0 = last0 - first0 + 1; 252170754Sdelphij long int len1 = last1 - first1 + 1; 253170754Sdelphij fprintf (outfile, "c%ld,%ld\n", len0, len1); 254170754Sdelphij } 255170754Sdelphij 256170754Sdelphij /* Print ``xxx | xxx '' lines */ 257170754Sdelphij if (changes == CHANGED) 258170754Sdelphij { 259170754Sdelphij for (i = first0, j = first1; i <= last0 && j <= last1; i++, j++) 260170754Sdelphij print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]); 261170754Sdelphij changes = (i <= last0 ? OLD : 0) + (j <= last1 ? NEW : 0); 262170754Sdelphij next0 = first0 = i; 263170754Sdelphij next1 = first1 = j; 264170754Sdelphij } 265170754Sdelphij 266170754Sdelphij /* Print `` > xxx '' lines */ 267170754Sdelphij if (changes & NEW) 268170754Sdelphij { 269170754Sdelphij for (j = first1; j <= last1; ++j) 270170754Sdelphij print_1sdiff_line (0, '>', &files[1].linbuf[j]); 271170754Sdelphij next1 = j; 272170754Sdelphij } 273170754Sdelphij 274170754Sdelphij /* Print ``xxx < '' lines */ 275170754Sdelphij if (changes & OLD) 276170754Sdelphij { 277170754Sdelphij for (i = first0; i <= last0; ++i) 278170754Sdelphij print_1sdiff_line (&files[0].linbuf[i], '<', 0); 279170754Sdelphij next0 = i; 280170754Sdelphij } 281170754Sdelphij} 282