Blame src/ifdef.c

Packit Service fdd496
/* #ifdef-format output routines for GNU DIFF.
Packit Service fdd496
Packit Service fdd496
   Copyright (C) 1989, 1991-1994, 2001-2002, 2004, 2006, 2009-2013, 2015-2017
Packit Service fdd496
   Free 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 <xalloc.h>
Packit Service fdd496
Packit Service fdd496
struct group
Packit Service fdd496
{
Packit Service fdd496
  struct file_data const *file;
Packit Service fdd496
  lin from, upto; /* start and limit lines for this group of lines */
Packit Service fdd496
};
Packit Service fdd496
Packit Service fdd496
static char const *format_group (FILE *, char const *, char,
Packit Service fdd496
				 struct group const *);
Packit Service fdd496
static char const *do_printf_spec (FILE *, char const *,
Packit Service fdd496
				   struct file_data const *, lin,
Packit Service fdd496
				   struct group const *);
Packit Service fdd496
static char const *scan_char_literal (char const *, char *);
Packit Service fdd496
static lin groups_letter_value (struct group const *, char);
Packit Service fdd496
static void format_ifdef (char const *, lin, lin, lin, lin);
Packit Service fdd496
static void print_ifdef_hunk (struct change *);
Packit Service fdd496
static void print_ifdef_lines (FILE *, char const *, struct group const *);
Packit Service fdd496
Packit Service fdd496
static lin next_line0;
Packit Service fdd496
static lin next_line1;
Packit Service fdd496
Packit Service fdd496
/* Print the edit-script SCRIPT as a merged #ifdef file.  */
Packit Service fdd496
Packit Service fdd496
void
Packit Service fdd496
print_ifdef_script (struct change *script)
Packit Service fdd496
{
Packit Service fdd496
  next_line0 = next_line1 = - files[0].prefix_lines;
Packit Service fdd496
  print_script (script, find_change, print_ifdef_hunk);
Packit Service fdd496
  if (next_line0 < files[0].valid_lines
Packit Service fdd496
      || next_line1 < files[1].valid_lines)
Packit Service fdd496
    {
Packit Service fdd496
      begin_output ();
Packit Service fdd496
      format_ifdef (group_format[UNCHANGED],
Packit Service fdd496
		    next_line0, files[0].valid_lines,
Packit Service fdd496
		    next_line1, files[1].valid_lines);
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Print a hunk of an ifdef 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_ifdef_hunk (struct change *hunk)
Packit Service fdd496
{
Packit Service fdd496
  lin first0, last0, first1, last1;
Packit Service fdd496
Packit Service fdd496
  /* Determine range of line numbers involved in each file.  */
Packit Service fdd496
  enum changes changes = analyze_hunk (hunk, &first0, &last0, &first1, &last1);
Packit Service fdd496
  if (!changes)
Packit Service fdd496
    return;
Packit Service fdd496
Packit Service fdd496
  begin_output ();
Packit Service fdd496
Packit Service fdd496
  /* Print lines up to this change.  */
Packit Service fdd496
  if (next_line0 < first0 || next_line1 < first1)
Packit Service fdd496
    format_ifdef (group_format[UNCHANGED],
Packit Service fdd496
		  next_line0, first0,
Packit Service fdd496
		  next_line1, first1);
Packit Service fdd496
Packit Service fdd496
  /* Print this change.  */
Packit Service fdd496
  next_line0 = last0 + 1;
Packit Service fdd496
  next_line1 = last1 + 1;
Packit Service fdd496
  format_ifdef (group_format[changes],
Packit Service fdd496
		first0, next_line0,
Packit Service fdd496
		first1, next_line1);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Print a set of lines according to FORMAT.
Packit Service fdd496
   Lines BEG0 up to END0 are from the first file;
Packit Service fdd496
   lines BEG1 up to END1 are from the second file.  */
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
format_ifdef (char const *format, lin beg0, lin end0, lin beg1, lin end1)
Packit Service fdd496
{
Packit Service fdd496
  struct group groups[2];
Packit Service fdd496
Packit Service fdd496
  groups[0].file = &files[0];
Packit Service fdd496
  groups[0].from = beg0;
Packit Service fdd496
  groups[0].upto = end0;
Packit Service fdd496
  groups[1].file = &files[1];
Packit Service fdd496
  groups[1].from = beg1;
Packit Service fdd496
  groups[1].upto = end1;
Packit Service fdd496
  format_group (outfile, format, 0, groups);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Print to file OUT a set of lines according to FORMAT.
Packit Service fdd496
   The format ends at the first free instance of ENDCHAR.
Packit Service fdd496
   Yield the address of the terminating character.
Packit Service fdd496
   GROUPS specifies which lines to print.
Packit Service fdd496
   If OUT is zero, do not actually print anything; just scan the format.  */
Packit Service fdd496
Packit Service fdd496
static char const *
Packit Service fdd496
format_group (register FILE *out, char const *format, char endchar,
Packit Service fdd496
	      struct group const *groups)
Packit Service fdd496
{
Packit Service fdd496
  register char c;
Packit Service fdd496
  register char const *f = format;
Packit Service fdd496
Packit Service fdd496
  while ((c = *f) != endchar && c != 0)
Packit Service fdd496
    {
Packit Service fdd496
      char const *f1 = ++f;
Packit Service fdd496
      if (c == '%')
Packit Service fdd496
	switch ((c = *f++))
Packit Service fdd496
	  {
Packit Service fdd496
	  case '%':
Packit Service fdd496
	    break;
Packit Service fdd496
Packit Service fdd496
	  case '(':
Packit Service fdd496
	    /* Print if-then-else format e.g. '%(n=1?thenpart:elsepart)'.  */
Packit Service fdd496
	    {
Packit Service fdd496
	      int i;
Packit Service fdd496
	      uintmax_t value[2];
Packit Service fdd496
	      FILE *thenout, *elseout;
Packit Service fdd496
Packit Service fdd496
	      for (i = 0; i < 2; i++)
Packit Service fdd496
		{
Packit Service fdd496
		  if (ISDIGIT (*f))
Packit Service fdd496
		    {
Packit Service fdd496
		      char *fend;
Packit Service fdd496
		      errno = 0;
Packit Service fdd496
		      value[i] = strtoumax (f, &fend, 10);
Packit Service fdd496
		      if (errno)
Packit Service fdd496
			goto bad_format;
Packit Service fdd496
		      f = fend;
Packit Service fdd496
		    }
Packit Service fdd496
		  else
Packit Service fdd496
		    {
Packit Service fdd496
		      value[i] = groups_letter_value (groups, *f);
Packit Service fdd496
		      if (value[i] == -1)
Packit Service fdd496
			goto bad_format;
Packit Service fdd496
		      f++;
Packit Service fdd496
		    }
Packit Service fdd496
		  if (*f++ != "=?"[i])
Packit Service fdd496
		    goto bad_format;
Packit Service fdd496
		}
Packit Service fdd496
	      if (value[0] == value[1])
Packit Service fdd496
		thenout = out, elseout = 0;
Packit Service fdd496
	      else
Packit Service fdd496
		thenout = 0, elseout = out;
Packit Service fdd496
	      f = format_group (thenout, f, ':', groups);
Packit Service fdd496
	      if (*f)
Packit Service fdd496
		{
Packit Service fdd496
		  f = format_group (elseout, f + 1, ')', groups);
Packit Service fdd496
		  if (*f)
Packit Service fdd496
		    f++;
Packit Service fdd496
		}
Packit Service fdd496
	    }
Packit Service fdd496
	    continue;
Packit Service fdd496
Packit Service fdd496
	  case '<':
Packit Service fdd496
	    /* Print lines deleted from first file.  */
Packit Service fdd496
	    print_ifdef_lines (out, line_format[OLD], &groups[0]);
Packit Service fdd496
	    continue;
Packit Service fdd496
Packit Service fdd496
	  case '=':
Packit Service fdd496
	    /* Print common lines.  */
Packit Service fdd496
	    print_ifdef_lines (out, line_format[UNCHANGED], &groups[0]);
Packit Service fdd496
	    continue;
Packit Service fdd496
Packit Service fdd496
	  case '>':
Packit Service fdd496
	    /* Print lines inserted from second file.  */
Packit Service fdd496
	    print_ifdef_lines (out, line_format[NEW], &groups[1]);
Packit Service fdd496
	    continue;
Packit Service fdd496
Packit Service fdd496
	  default:
Packit Service fdd496
	    f = do_printf_spec (out, f - 2, 0, 0, groups);
Packit Service fdd496
	    if (f)
Packit Service fdd496
	      continue;
Packit Service fdd496
	    /* Fall through. */
Packit Service fdd496
	  bad_format:
Packit Service fdd496
	    c = '%';
Packit Service fdd496
	    f = f1;
Packit Service fdd496
	    break;
Packit Service fdd496
	  }
Packit Service fdd496
Packit Service fdd496
      if (out)
Packit Service fdd496
	putc (c, out);
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  return f;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* For the line group pair G, return the number corresponding to LETTER.
Packit Service fdd496
   Return -1 if LETTER is not a group format letter.  */
Packit Service fdd496
static lin
Packit Service fdd496
groups_letter_value (struct group const *g, char letter)
Packit Service fdd496
{
Packit Service fdd496
  switch (letter)
Packit Service fdd496
    {
Packit Service fdd496
    case 'E': letter = 'e'; g++; break;
Packit Service fdd496
    case 'F': letter = 'f'; g++; break;
Packit Service fdd496
    case 'L': letter = 'l'; g++; break;
Packit Service fdd496
    case 'M': letter = 'm'; g++; break;
Packit Service fdd496
    case 'N': letter = 'n'; g++; break;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  switch (letter)
Packit Service fdd496
    {
Packit Service fdd496
      case 'e': return translate_line_number (g->file, g->from) - 1;
Packit Service fdd496
      case 'f': return translate_line_number (g->file, g->from);
Packit Service fdd496
      case 'l': return translate_line_number (g->file, g->upto) - 1;
Packit Service fdd496
      case 'm': return translate_line_number (g->file, g->upto);
Packit Service fdd496
      case 'n': return g->upto - g->from;
Packit Service fdd496
      default: return -1;
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Print to file OUT, using FORMAT to print the line group GROUP.
Packit Service fdd496
   But do nothing if OUT is zero.  */
Packit Service fdd496
static void
Packit Service fdd496
print_ifdef_lines (register FILE *out, char const *format,
Packit Service fdd496
		   struct group const *group)
Packit Service fdd496
{
Packit Service fdd496
  struct file_data const *file = group->file;
Packit Service fdd496
  char const * const *linbuf = file->linbuf;
Packit Service fdd496
  lin from = group->from, upto = group->upto;
Packit Service fdd496
Packit Service fdd496
  if (!out)
Packit Service fdd496
    return;
Packit Service fdd496
Packit Service fdd496
  /* If possible, use a single fwrite; it's faster.  */
Packit Service fdd496
  if (!expand_tabs && format[0] == '%')
Packit Service fdd496
    {
Packit Service fdd496
      if (format[1] == 'l' && format[2] == '\n' && !format[3] && from < upto)
Packit Service fdd496
	{
Packit Service fdd496
	  fwrite (linbuf[from], sizeof (char),
Packit Service fdd496
		  linbuf[upto] + (linbuf[upto][-1] != '\n') -  linbuf[from],
Packit Service fdd496
		  out);
Packit Service fdd496
	  return;
Packit Service fdd496
	}
Packit Service fdd496
      if (format[1] == 'L' && !format[2])
Packit Service fdd496
	{
Packit Service fdd496
	  fwrite (linbuf[from], sizeof (char),
Packit Service fdd496
		  linbuf[upto] -  linbuf[from], out);
Packit Service fdd496
	  return;
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  for (;  from < upto;  from++)
Packit Service fdd496
    {
Packit Service fdd496
      register char c;
Packit Service fdd496
      register char const *f = format;
Packit Service fdd496
Packit Service fdd496
      while ((c = *f++) != 0)
Packit Service fdd496
	{
Packit Service fdd496
	  char const *f1 = f;
Packit Service fdd496
	  if (c == '%')
Packit Service fdd496
	    switch ((c = *f++))
Packit Service fdd496
	      {
Packit Service fdd496
	      case '%':
Packit Service fdd496
		break;
Packit Service fdd496
Packit Service fdd496
	      case 'l':
Packit Service fdd496
		output_1_line (linbuf[from],
Packit Service fdd496
			       (linbuf[from + 1]
Packit Service fdd496
				- (linbuf[from + 1][-1] == '\n')),
Packit Service fdd496
			       0, 0);
Packit Service fdd496
		continue;
Packit Service fdd496
Packit Service fdd496
	      case 'L':
Packit Service fdd496
		output_1_line (linbuf[from], linbuf[from + 1], 0, 0);
Packit Service fdd496
		continue;
Packit Service fdd496
Packit Service fdd496
	      default:
Packit Service fdd496
		f = do_printf_spec (out, f - 2, file, from, 0);
Packit Service fdd496
		if (f)
Packit Service fdd496
		  continue;
Packit Service fdd496
		c = '%';
Packit Service fdd496
		f = f1;
Packit Service fdd496
		break;
Packit Service fdd496
	      }
Packit Service fdd496
Packit Service fdd496
	  putc (c, out);
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static char const *
Packit Service fdd496
do_printf_spec (FILE *out, char const *spec,
Packit Service fdd496
		struct file_data const *file, lin n,
Packit Service fdd496
		struct group const *groups)
Packit Service fdd496
{
Packit Service fdd496
  char const *f = spec;
Packit Service fdd496
  char c;
Packit Service fdd496
  char c1;
Packit Service fdd496
Packit Service fdd496
  /* Scan printf-style SPEC of the form %[-'0]*[0-9]*(.[0-9]*)?[cdoxX].  */
Packit Service fdd496
  /* assert (*f == '%'); */
Packit Service fdd496
  f++;
Packit Service fdd496
  while ((c = *f++) == '-' || c == '\'' || c == '0')
Packit Service fdd496
    continue;
Packit Service fdd496
  while (ISDIGIT (c))
Packit Service fdd496
    c = *f++;
Packit Service fdd496
  if (c == '.')
Packit Service fdd496
    while (ISDIGIT (c = *f++))
Packit Service fdd496
      continue;
Packit Service fdd496
  c1 = *f++;
Packit Service fdd496
Packit Service fdd496
  switch (c)
Packit Service fdd496
    {
Packit Service fdd496
    case 'c':
Packit Service fdd496
      if (c1 != '\'')
Packit Service fdd496
	return 0;
Packit Service fdd496
      else
Packit Service fdd496
	{
Packit Service fdd496
	  char value IF_LINT (= 0);
Packit Service fdd496
	  f = scan_char_literal (f, &value);
Packit Service fdd496
	  if (!f)
Packit Service fdd496
	    return 0;
Packit Service fdd496
	  if (out)
Packit Service fdd496
	    putc (value, out);
Packit Service fdd496
	}
Packit Service fdd496
      break;
Packit Service fdd496
Packit Service fdd496
    case 'd': case 'o': case 'x': case 'X':
Packit Service fdd496
      {
Packit Service fdd496
	lin value;
Packit Service fdd496
Packit Service fdd496
	if (file)
Packit Service fdd496
	  {
Packit Service fdd496
	    if (c1 != 'n')
Packit Service fdd496
	      return 0;
Packit Service fdd496
	    value = translate_line_number (file, n);
Packit Service fdd496
	  }
Packit Service fdd496
	else
Packit Service fdd496
	  {
Packit Service fdd496
	    value = groups_letter_value (groups, c1);
Packit Service fdd496
	    if (value < 0)
Packit Service fdd496
	      return 0;
Packit Service fdd496
	  }
Packit Service fdd496
Packit Service fdd496
	if (out)
Packit Service fdd496
	  {
Packit Service fdd496
	    /* For example, if the spec is "%3xn" and pI is "l", use the printf
Packit Service fdd496
	       format spec "%3lx".  Here the spec prefix is "%3".  */
Packit Service fdd496
	    printint print_value = value;
Packit Service fdd496
	    size_t spec_prefix_len = f - spec - 2;
Packit Service fdd496
	    size_t pI_len = sizeof pI - 1;
Packit Service fdd496
	    char *format = xmalloc (spec_prefix_len + pI_len + 2);
Packit Service fdd496
	    char *p = format + spec_prefix_len + pI_len;
Packit Service fdd496
	    memcpy (format, spec, spec_prefix_len);
Packit Service fdd496
	    memcpy (format + spec_prefix_len, pI, pI_len);
Packit Service fdd496
	    *p++ = c;
Packit Service fdd496
	    *p = '\0';
Packit Service fdd496
	    fprintf (out, format, print_value);
Packit Service fdd496
	    free (format);
Packit Service fdd496
	  }
Packit Service fdd496
      }
Packit Service fdd496
      break;
Packit Service fdd496
Packit Service fdd496
    default:
Packit Service fdd496
      return 0;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  return f;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Scan the character literal represented in the string LIT; LIT points just
Packit Service fdd496
   after the initial apostrophe.  Put the literal's value into *VALPTR.
Packit Service fdd496
   Yield the address of the first character after the closing apostrophe,
Packit Service fdd496
   or a null pointer if the literal is ill-formed.  */
Packit Service fdd496
static char const *
Packit Service fdd496
scan_char_literal (char const *lit, char *valptr)
Packit Service fdd496
{
Packit Service fdd496
  register char const *p = lit;
Packit Service fdd496
  char value;
Packit Service fdd496
  ptrdiff_t digits;
Packit Service fdd496
  char c = *p++;
Packit Service fdd496
Packit Service fdd496
  switch (c)
Packit Service fdd496
    {
Packit Service fdd496
      case 0:
Packit Service fdd496
      case '\'':
Packit Service fdd496
	return NULL;
Packit Service fdd496
Packit Service fdd496
      case '\\':
Packit Service fdd496
	value = 0;
Packit Service fdd496
	while ((c = *p++) != '\'')
Packit Service fdd496
	  {
Packit Service fdd496
	    unsigned int digit = c - '0';
Packit Service fdd496
	    if (8 <= digit)
Packit Service fdd496
	      return NULL;
Packit Service fdd496
	    value = 8 * value + digit;
Packit Service fdd496
	  }
Packit Service fdd496
	digits = p - lit - 2;
Packit Service fdd496
	if (! (1 <= digits && digits <= 3))
Packit Service fdd496
	  return NULL;
Packit Service fdd496
	break;
Packit Service fdd496
Packit Service fdd496
      default:
Packit Service fdd496
	value = c;
Packit Service fdd496
	if (*p++ != '\'')
Packit Service fdd496
	  return NULL;
Packit Service fdd496
	break;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  *valptr = value;
Packit Service fdd496
  return p;
Packit Service fdd496
}