Blame src/side.c

Packit 33f14e
/* sdiff-format output routines for GNU DIFF.
Packit 33f14e
Packit 33f14e
   Copyright (C) 1991-1993, 1998, 2001-2002, 2004, 2009-2013, 2015-2017 Free
Packit 33f14e
   Software Foundation, Inc.
Packit 33f14e
Packit 33f14e
   This file is part of GNU DIFF.
Packit 33f14e
Packit 33f14e
   GNU DIFF is distributed in the hope that it will be useful,
Packit 33f14e
   but WITHOUT ANY WARRANTY.  No author or distributor
Packit 33f14e
   accepts responsibility to anyone for the consequences of using it
Packit 33f14e
   or for whether it serves any particular purpose or works at all,
Packit 33f14e
   unless he says so in writing.  Refer to the GNU General Public
Packit 33f14e
   License for full details.
Packit 33f14e
Packit 33f14e
   Everyone is granted permission to copy, modify and redistribute
Packit 33f14e
   GNU DIFF, but only under the conditions described in the
Packit 33f14e
   GNU General Public License.   A copy of this license is
Packit 33f14e
   supposed to have been given to you along with GNU DIFF so you
Packit 33f14e
   can know your rights and responsibilities.  It should be in a
Packit 33f14e
   file named COPYING.  Among other things, the copyright notice
Packit 33f14e
   and this notice must be preserved on all copies.  */
Packit 33f14e
Packit 33f14e
#include "diff.h"
Packit 33f14e
Packit 33f14e
#include <wchar.h>
Packit 33f14e
Packit 33f14e
static void print_sdiff_common_lines (lin, lin);
Packit 33f14e
static void print_sdiff_hunk (struct change *);
Packit 33f14e
Packit 33f14e
/* Next line number to be printed in the two input files.  */
Packit 33f14e
static lin next0, next1;
Packit 33f14e
Packit 33f14e
/* Print the edit-script SCRIPT as a sdiff style output.  */
Packit 33f14e
Packit 33f14e
void
Packit 33f14e
print_sdiff_script (struct change *script)
Packit 33f14e
{
Packit 33f14e
  begin_output ();
Packit 33f14e
Packit 33f14e
  next0 = next1 = - files[0].prefix_lines;
Packit 33f14e
  print_script (script, find_change, print_sdiff_hunk);
Packit 33f14e
Packit 33f14e
  print_sdiff_common_lines (files[0].valid_lines, files[1].valid_lines);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Tab from column FROM to column TO, where FROM <= TO.  Yield TO.  */
Packit 33f14e
Packit 33f14e
static size_t
Packit 33f14e
tab_from_to (size_t from, size_t to)
Packit 33f14e
{
Packit 33f14e
  FILE *out = outfile;
Packit 33f14e
  size_t tab;
Packit 33f14e
  size_t tab_size = tabsize;
Packit 33f14e
Packit 33f14e
  if (!expand_tabs)
Packit 33f14e
    for (tab = from + tab_size - from % tab_size;  tab <= to;  tab += tab_size)
Packit 33f14e
      {
Packit 33f14e
	putc ('\t', out);
Packit 33f14e
	from = tab;
Packit 33f14e
      }
Packit 33f14e
  while (from++ < to)
Packit 33f14e
    putc (' ', out);
Packit 33f14e
  return to;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Print the text for half an sdiff line.  This means truncate to
Packit 33f14e
   width observing tabs, and trim a trailing newline.  Return the
Packit 33f14e
   last column written (not the number of chars).  */
Packit 33f14e
Packit 33f14e
static size_t
Packit 33f14e
print_half_line (char const *const *line, size_t indent, size_t out_bound)
Packit 33f14e
{
Packit 33f14e
  FILE *out = outfile;
Packit 33f14e
  register size_t in_position = 0;
Packit 33f14e
  register size_t out_position = 0;
Packit 33f14e
  register char const *text_pointer = line[0];
Packit 33f14e
  register char const *text_limit = line[1];
Packit 33f14e
  mbstate_t mbstate = { 0 };
Packit 33f14e
Packit 33f14e
  while (text_pointer < text_limit)
Packit 33f14e
    {
Packit 33f14e
      char const *tp0 = text_pointer;
Packit 33f14e
      register char c = *text_pointer++;
Packit 33f14e
Packit 33f14e
      switch (c)
Packit 33f14e
	{
Packit 33f14e
	case '\t':
Packit 33f14e
	  {
Packit 33f14e
	    size_t spaces = tabsize - in_position % tabsize;
Packit 33f14e
	    if (in_position == out_position)
Packit 33f14e
	      {
Packit 33f14e
		size_t tabstop = out_position + spaces;
Packit 33f14e
		if (expand_tabs)
Packit 33f14e
		  {
Packit 33f14e
		    if (out_bound < tabstop)
Packit 33f14e
		      tabstop = out_bound;
Packit 33f14e
		    for (;  out_position < tabstop;  out_position++)
Packit 33f14e
		      putc (' ', out);
Packit 33f14e
		  }
Packit 33f14e
		else
Packit 33f14e
		  if (tabstop < out_bound)
Packit 33f14e
		    {
Packit 33f14e
		      out_position = tabstop;
Packit 33f14e
		      putc (c, out);
Packit 33f14e
		    }
Packit 33f14e
	      }
Packit 33f14e
	    in_position += spaces;
Packit 33f14e
	  }
Packit 33f14e
	  break;
Packit 33f14e
Packit 33f14e
	case '\r':
Packit 33f14e
	  {
Packit 33f14e
	    putc (c, out);
Packit 33f14e
	    tab_from_to (0, indent);
Packit 33f14e
	    in_position = out_position = 0;
Packit 33f14e
	  }
Packit 33f14e
	  break;
Packit 33f14e
Packit 33f14e
	case '\b':
Packit 33f14e
	  if (in_position != 0 && --in_position < out_bound)
Packit 33f14e
	    {
Packit 33f14e
	      if (out_position <= in_position)
Packit 33f14e
		/* Add spaces to make up for suppressed tab past out_bound.  */
Packit 33f14e
		for (;  out_position < in_position;  out_position++)
Packit 33f14e
		  putc (' ', out);
Packit 33f14e
	      else
Packit 33f14e
		{
Packit 33f14e
		  out_position = in_position;
Packit 33f14e
		  putc (c, out);
Packit 33f14e
		}
Packit 33f14e
	    }
Packit 33f14e
	  break;
Packit 33f14e
Packit 33f14e
	default:
Packit 33f14e
	  {
Packit 33f14e
	    wchar_t wc;
Packit 33f14e
	    size_t bytes = mbrtowc (&wc, tp0, text_limit - tp0, &mbstate);
Packit 33f14e
Packit 33f14e
	    if (0 < bytes && bytes < (size_t) -2)
Packit 33f14e
	      {
Packit 33f14e
		int width = wcwidth (wc);
Packit 33f14e
		if (0 < width)
Packit 33f14e
		  in_position += width;
Packit 33f14e
		if (in_position <= out_bound)
Packit 33f14e
		  {
Packit 33f14e
		    out_position = in_position;
Packit 33f14e
		    fwrite (tp0, 1, bytes, stdout);
Packit 33f14e
		  }
Packit 33f14e
		text_pointer = tp0 + bytes;
Packit 33f14e
		break;
Packit 33f14e
	      }
Packit 33f14e
	  }
Packit 33f14e
	  FALLTHROUGH;
Packit 33f14e
	case '\f':
Packit 33f14e
	case '\v':
Packit 33f14e
	  if (in_position < out_bound)
Packit 33f14e
	    putc (c, out);
Packit 33f14e
	  break;
Packit 33f14e
Packit 33f14e
	case ' ': case '!': case '"': case '#': case '%':
Packit 33f14e
	case '&': case '\'': case '(': case ')': case '*':
Packit 33f14e
	case '+': case ',': case '-': case '.': case '/':
Packit 33f14e
	case '0': case '1': case '2': case '3': case '4':
Packit 33f14e
	case '5': case '6': case '7': case '8': case '9':
Packit 33f14e
	case ':': case ';': case '<': case '=': case '>':
Packit 33f14e
	case '?':
Packit 33f14e
	case 'A': case 'B': case 'C': case 'D': case 'E':
Packit 33f14e
	case 'F': case 'G': case 'H': case 'I': case 'J':
Packit 33f14e
	case 'K': case 'L': case 'M': case 'N': case 'O':
Packit 33f14e
	case 'P': case 'Q': case 'R': case 'S': case 'T':
Packit 33f14e
	case 'U': case 'V': case 'W': case 'X': case 'Y':
Packit 33f14e
	case 'Z':
Packit 33f14e
	case '[': case '\\': case ']': case '^': case '_':
Packit 33f14e
	case 'a': case 'b': case 'c': case 'd': case 'e':
Packit 33f14e
	case 'f': case 'g': case 'h': case 'i': case 'j':
Packit 33f14e
	case 'k': case 'l': case 'm': case 'n': case 'o':
Packit 33f14e
	case 'p': case 'q': case 'r': case 's': case 't':
Packit 33f14e
	case 'u': case 'v': case 'w': case 'x': case 'y':
Packit 33f14e
	case 'z': case '{': case '|': case '}': case '~':
Packit 33f14e
	  /* These characters are printable ASCII characters.  */
Packit 33f14e
	  if (in_position++ < out_bound)
Packit 33f14e
	    {
Packit 33f14e
	      out_position = in_position;
Packit 33f14e
	      putc (c, out);
Packit 33f14e
	    }
Packit 33f14e
	  break;
Packit 33f14e
Packit 33f14e
	case '\n':
Packit 33f14e
	  return out_position;
Packit 33f14e
	}
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  return out_position;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Print side by side lines with a separator in the middle.
Packit 33f14e
   0 parameters are taken to indicate white space text.
Packit 33f14e
   Blank lines that can easily be caught are reduced to a single newline.  */
Packit 33f14e
Packit 33f14e
static void
Packit 33f14e
print_1sdiff_line (char const *const *left, char sep,
Packit 33f14e
		   char const *const *right)
Packit 33f14e
{
Packit 33f14e
  FILE *out = outfile;
Packit 33f14e
  size_t hw = sdiff_half_width;
Packit 33f14e
  size_t c2o = sdiff_column2_offset;
Packit 33f14e
  size_t col = 0;
Packit 33f14e
  bool put_newline = false;
Packit 33f14e
  bool color_to_reset = false;
Packit 33f14e
Packit 33f14e
  if (sep == '<')
Packit 33f14e
    {
Packit 33f14e
      set_color_context (DELETE_CONTEXT);
Packit 33f14e
      color_to_reset = true;
Packit 33f14e
    }
Packit 33f14e
  else if (sep == '>')
Packit 33f14e
    {
Packit 33f14e
      set_color_context (ADD_CONTEXT);
Packit 33f14e
      color_to_reset = true;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  if (left)
Packit 33f14e
    {
Packit 33f14e
      put_newline |= left[1][-1] == '\n';
Packit 33f14e
      col = print_half_line (left, 0, hw);
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  if (sep != ' ')
Packit 33f14e
    {
Packit 33f14e
      col = tab_from_to (col, (hw + c2o - 1) / 2) + 1;
Packit 33f14e
      if (sep == '|' && put_newline != (right[1][-1] == '\n'))
Packit 33f14e
	sep = put_newline ? '/' : '\\';
Packit 33f14e
      putc (sep, out);
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  if (right)
Packit 33f14e
    {
Packit 33f14e
      put_newline |= right[1][-1] == '\n';
Packit 33f14e
      if (**right != '\n')
Packit 33f14e
	{
Packit 33f14e
	  col = tab_from_to (col, c2o);
Packit 33f14e
	  print_half_line (right, col, hw);
Packit 33f14e
	}
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  if (put_newline)
Packit 33f14e
    putc ('\n', out);
Packit 33f14e
Packit 33f14e
  if (color_to_reset)
Packit 33f14e
    set_color_context (RESET_CONTEXT);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Print lines common to both files in side-by-side format.  */
Packit 33f14e
static void
Packit 33f14e
print_sdiff_common_lines (lin limit0, lin limit1)
Packit 33f14e
{
Packit 33f14e
  lin i0 = next0, i1 = next1;
Packit 33f14e
Packit 33f14e
  if (!suppress_common_lines && (i0 != limit0 || i1 != limit1))
Packit 33f14e
    {
Packit 33f14e
      if (sdiff_merge_assist)
Packit 33f14e
	{
Packit 33f14e
	  printint len0 = limit0 - i0;
Packit 33f14e
	  printint len1 = limit1 - i1;
Packit 33f14e
	  fprintf (outfile, "i%"pI"d,%"pI"d\n", len0, len1);
Packit 33f14e
	}
Packit 33f14e
Packit 33f14e
      if (!left_column)
Packit 33f14e
	{
Packit 33f14e
	  while (i0 != limit0 && i1 != limit1)
Packit 33f14e
	    print_1sdiff_line (&files[0].linbuf[i0++], ' ',
Packit 33f14e
			       &files[1].linbuf[i1++]);
Packit 33f14e
	  while (i1 != limit1)
Packit 33f14e
	    print_1sdiff_line (0, ')', &files[1].linbuf[i1++]);
Packit 33f14e
	}
Packit 33f14e
      while (i0 != limit0)
Packit 33f14e
	print_1sdiff_line (&files[0].linbuf[i0++], '(', 0);
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  next0 = limit0;
Packit 33f14e
  next1 = limit1;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Print a hunk of an sdiff diff.
Packit 33f14e
   This is a contiguous portion of a complete edit script,
Packit 33f14e
   describing changes in consecutive lines.  */
Packit 33f14e
Packit 33f14e
static void
Packit 33f14e
print_sdiff_hunk (struct change *hunk)
Packit 33f14e
{
Packit 33f14e
  lin first0, last0, first1, last1;
Packit 33f14e
  register lin i, j;
Packit 33f14e
Packit 33f14e
  /* Determine range of line numbers involved in each file.  */
Packit 33f14e
  enum changes changes =
Packit 33f14e
    analyze_hunk (hunk, &first0, &last0, &first1, &last1);
Packit 33f14e
  if (!changes)
Packit 33f14e
    return;
Packit 33f14e
Packit 33f14e
  /* Print out lines up to this change.  */
Packit 33f14e
  print_sdiff_common_lines (first0, first1);
Packit 33f14e
Packit 33f14e
  if (sdiff_merge_assist)
Packit 33f14e
    {
Packit 33f14e
      printint len0 = last0 - first0 + 1;
Packit 33f14e
      printint len1 = last1 - first1 + 1;
Packit 33f14e
      fprintf (outfile, "c%"pI"d,%"pI"d\n", len0, len1);
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* Print "xxx  |  xxx " lines.  */
Packit 33f14e
  if (changes == CHANGED)
Packit 33f14e
    {
Packit 33f14e
      for (i = first0, j = first1;  i <= last0 && j <= last1;  i++, j++)
Packit 33f14e
	print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]);
Packit 33f14e
      changes = (i <= last0 ? OLD : 0) + (j <= last1 ? NEW : 0);
Packit 33f14e
      next0 = first0 = i;
Packit 33f14e
      next1 = first1 = j;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* Print "     >  xxx " lines.  */
Packit 33f14e
  if (changes & NEW)
Packit 33f14e
    {
Packit 33f14e
      for (j = first1; j <= last1; ++j)
Packit 33f14e
	print_1sdiff_line (0, '>', &files[1].linbuf[j]);
Packit 33f14e
      next1 = j;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* Print "xxx  <     " lines.  */
Packit 33f14e
  if (changes & OLD)
Packit 33f14e
    {
Packit 33f14e
      for (i = first0; i <= last0; ++i)
Packit 33f14e
	print_1sdiff_line (&files[0].linbuf[i], '<', 0);
Packit 33f14e
      next0 = i;
Packit 33f14e
    }
Packit 33f14e
}