Blame src/side.c

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