v24i018: GNU Diff, version 1.15, Part03/08

Rich Salz rsalz at uunet.uu.net
Tue Feb 26 08:14:14 AEST 1991


Submitted-by: Paul Eggert <eggert at twinsun.com>
Posting-number: Volume 24, Issue 18
Archive-name: gnudiff1.15/part03

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 8)."
# Contents:  diff.c getopt.c util.c
# Wrapped by eggert at ata on Mon Jan  7 11:25:29 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'diff.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'diff.c'\"
else
echo shar: Extracting \"'diff.c'\" \(17901 characters\)
sed "s/^X//" >'diff.c' <<'END_OF_FILE'
X/* GNU DIFF main routine.
X   Copyright (C) 1988, 1989 Free Software Foundation, Inc.
X
XThis file is part of GNU DIFF.
X
XGNU DIFF is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation; either version 1, or (at your option)
Xany later version.
X
XGNU DIFF is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with GNU DIFF; see the file COPYING.  If not, write to
Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
X
X/* GNU DIFF was written by Mike Haertel, David Hayes,
X   Richard Stallman and Len Tower.  */
X
X#define GDIFF_MAIN
X#include "regex.h"
X#include "diff.h"
X#include "getopt.h"
X
X
X/* Nonzero for -r: if comparing two directories,
X   compare their common subdirectories recursively.  */
X
Xint recursive;
X
X/* For debugging: don't do discard_confusing_lines.  */
X
Xint no_discards;
X
X/* Return a string containing the command options with which diff was invoked.
X   Spaces appear between what were separate ARGV-elements.
X   There is a space at the beginning but none at the end.
X   If there were no options, the result is an empty string.
X
X   Arguments: OPTIONVEC, a vector containing separate ARGV-elements, and COUNT,
X   the length of that vector.  */
X
Xstatic char *
Xoption_list (optionvec, count)
X     char **optionvec;  /* Was `vector', but that collides on Alliant.  */
X     int count;
X{
X  int i;
X  int length = 0;
X  char *result;
X
X  for (i = 0; i < count; i++)
X    length += strlen (optionvec[i]) + 1;
X
X  result = (char *) xmalloc (length + 1);
X  result[0] = 0;
X
X  for (i = 0; i < count; i++)
X    {
X      strcat (result, " ");
X      strcat (result, optionvec[i]);
X    }
X
X  return result;
X}
X
X/* The numbers 129 and 130 that appear in the fourth element
X   for the context and unidiff entries are used as a way of
X   telling the big switch in `main' how to process those options.  */
X
Xstatic struct option longopts[] =
X{
X  {"ignore-blank-lines", 0, 0, 'B'},
X  {"context", 2, 0, 129},
X  {"ifdef", 1, 0, 'D'},
X  {"show-function-line", 1, 0, 'F'},
X  {"speed-large-files", 0, 0, 'H'},
X  {"ignore-matching-lines", 1, 0, 'I'},
X  {"file-label", 1, 0, 'L'},
X  {"entire-new-files", 0, 0, 'N'},
X  {"new-files", 0, 0, 'N'},
X  {"starting-file", 1, 0, 'S'},
X  {"initial-tab", 0, 0, 'T'},
X  {"text", 0, 0, 'a'},
X  {"all-text", 0, 0, 'a'},
X  {"ascii", 0, 0, 'a'},
X  {"ignore-space-change", 0, 0, 'b'},
X  {"minimal", 0, 0, 'd'},
X  {"ed", 0, 0, 'e'},
X  {"reversed-ed", 0, 0, 'f'},
X  {"ignore-case", 0, 0, 'i'},
X  {"print", 0, 0, 'l'},
X  {"rcs", 0, 0, 'n'},
X  {"show-c-function", 0, 0, 'p'},
X  {"binary", 0, 0, 'q'},
X  {"brief", 0, 0, 'q'},
X  {"recursive", 0, 0, 'r'},
X  {"report-identical-files", 0, 0, 's'},
X  {"expand-tabs", 0, 0, 't'},
X  {"ignore-all-space", 0, 0, 'w'},
X  {"unified", 2, 0, 130},
X  {"version", 0, 0, 'v'},
X  {0, 0, 0, 0}
X};
X
Xmain (argc, argv)
X     int argc;
X     char *argv[];
X{
X  int val;
X  int c;
X  int prev = -1;
X  int longind;
X  extern char *version_string;
X
X  program = argv[0];
X
X  /* Do our initializations. */
X  output_style = OUTPUT_NORMAL;
X  always_text_flag = FALSE;
X  ignore_space_change_flag = FALSE;
X  ignore_all_space_flag = FALSE;
X  length_varies = FALSE;
X  ignore_case_flag = FALSE;
X  ignore_blank_lines_flag = FALSE;
X  ignore_regexp = 0;
X  function_regexp = 0;
X  print_file_same_flag = FALSE;
X  entire_new_file_flag = FALSE;
X  no_details_flag = FALSE;
X  context = -1;
X  line_end_char = '\n';
X  tab_align_flag = FALSE;
X  tab_expand_flag = FALSE;
X  recursive = FALSE;
X  paginate_flag = FALSE;
X  ifdef_string = NULL;
X  heuristic = FALSE;
X  dir_start_file = NULL;
X  msg_chain = NULL;
X  msg_chain_end = NULL;
X  no_discards = 0;
X
X  /* Decode the options.  */
X
X  while ((c = getopt_long (argc, argv,
X			   "0123456789abBcC:dD:efF:hHiI:lL:nNpqrsS:tTuvw",
X			   longopts, &longind)) != EOF)
X    {
X      if (c == 0)		/* Long option. */
X	c = longopts[longind].val;
X      switch (c)
X	{
X	  /* All digits combine in decimal to specify the context-size.  */
X	case '1':
X	case '2':
X	case '3':
X	case '4':
X	case '5':
X	case '6':
X	case '7':
X	case '8':
X	case '9':
X	case '0':
X	  if (context == -1)
X	    context = 0;
X	  /* If a context length has already been specified,
X	     more digits allowed only if they follow right after the others.
X	     Reject two separate runs of digits, or digits after -C.  */
X	  else if (prev < '0' || prev > '9')
X	    fatal ("context length specified twice");
X
X	  context = context * 10 + c - '0';
X	  break;
X
X	case 'a':
X	  /* Treat all files as text files; never treat as binary.  */
X	  always_text_flag = 1;
X	  break;
X
X	case 'b':
X	  /* Ignore changes in amount of whitespace.  */
X	  ignore_space_change_flag = 1;
X	  length_varies = 1;
X	  break;
X
X	case 'B':
X	  /* Ignore changes affecting only blank lines.  */
X	  ignore_blank_lines_flag = 1;
X	  break;
X
X	case 'C':
X	case 129:		/* +context[=lines] */
X	case 130:		/* +unified[=lines] */
X	  if (optarg)
X	    {
X	      if (context >= 0)
X		fatal ("context length specified twice");
X	      {
X		char *p;
X		for (p = optarg; *p; p++)
X		  if (*p < '0' || *p > '9')
X		    fatal ("invalid context length argument");
X	      }
X	      context = atoi (optarg);
X	    }
X
X	  /* Falls through.  */
X	case 'c':
X	  /* Make context-style output.  */
X	  specify_style (c == 130 ? OUTPUT_UNIFIED : OUTPUT_CONTEXT);
X	  break;
X
X	case 'd':
X	  /* Don't discard lines.  This makes things slower (sometimes much
X	     slower) but will find a guaranteed minimal set of changes.  */
X	  no_discards = 1;
X	  break;
X
X	case 'D':
X	  /* Make merged #ifdef output.  */
X	  specify_style (OUTPUT_IFDEF);
X	  ifdef_string = optarg;
X	  break;
X
X	case 'e':
X	  /* Make output that is a valid `ed' script.  */
X	  specify_style (OUTPUT_ED);
X	  break;
X
X	case 'f':
X	  /* Make output that looks vaguely like an `ed' script
X	     but has changes in the order they appear in the file.  */
X	  specify_style (OUTPUT_FORWARD_ED);
X	  break;
X
X	case 'F':
X	  /* Show, for each set of changes, the previous line that
X	     matches the specified regexp.  Currently affects only
X	     context-style output.  */
X	  function_regexp = optarg;
X	  break;
X
X	case 'h':
X	  /* Split the files into chunks of around 1500 lines
X	     for faster processing.  Usually does not change the result.
X
X	     This currently has no effect.  */
X	  break;
X
X	case 'H':
X	  /* Turn on heuristics that speed processing of large files
X	     with a small density of changes.  */
X	  heuristic = 1;
X	  break;
X
X	case 'i':
X	  /* Ignore changes in case.  */
X	  ignore_case_flag = 1;
X	  break;
X
X	case 'I':
X	  /* Ignore changes affecting only lines that match the
X	     specified regexp.  */
X	  ignore_regexp = optarg;
X	  break;
X
X	case 'l':
X	  /* Pass the output through `pr' to paginate it.  */
X	  paginate_flag = 1;
X	  break;
X
X	case 'L':
X	  /* Specify file labels for `-c' output headers.  */
X	  if (!file_label[0])
X	    file_label[0] = optarg;
X	  else if (!file_label[1])
X	    file_label[1] = optarg;
X	  else
X	    fatal ("too many file label options");
X	  break;
X
X	case 'n':
X	  /* Output RCS-style diffs, like `-f' except that each command
X	     specifies the number of lines affected.  */
X	  specify_style (OUTPUT_RCS);
X	  break;
X
X	case 'N':
X	  /* When comparing directories, if a file appears only in one
X	     directory, treat it as present but empty in the other.  */
X	  entire_new_file_flag = 1;
X	  break;
X
X	case 'p':
X	  /* Make context-style output and show name of last C function.  */
X	  specify_style (OUTPUT_CONTEXT);
X	  function_regexp = "^[_a-zA-Z]";
X	  break;
X
X	case 'q':
X	  no_details_flag = 1;
X	  break;
X
X	case 'r':
X	  /* When comparing directories, 
X	     recursively compare any subdirectories found.  */
X	  recursive = 1;
X	  break;
X
X	case 's':
X	  /* Print a message if the files are the same.  */
X	  print_file_same_flag = 1;
X	  break;
X
X	case 'S':
X	  /* When comparing directories, start with the specified
X	     file name.  This is used for resuming an aborted comparison.  */
X	  dir_start_file = optarg;
X	  break;
X
X	case 't':
X	  /* Expand tabs to spaces in the output so that it preserves
X	     the alignment of the input files.  */
X	  tab_expand_flag = 1;
X	  break;
X
X	case 'T':
X	  /* Use a tab in the output, rather than a space, before the
X	     text of an input line, so as to keep the proper alignment
X	     in the input line without changing the characters in it.  */
X	  tab_align_flag = 1;
X	  break;
X
X	case 'v':
X	  printf ("GNU diff version %s\n", version_string);
X	  break;
X
X	case 'u':
X	  /* Output the context diff in unidiff format.  */
X	  specify_style (OUTPUT_UNIFIED);
X	  break;
X
X	case 'w':
X	  /* Ignore horizontal whitespace when comparing lines.  */
X	  ignore_all_space_flag = 1;
X	  length_varies = 1;
X	  break;
X
X	default:
X	  usage ();
X	}
X      prev = c;
X    }
X
X  if (optind != argc - 2)
X    usage ();
X
X  if (ignore_regexp)
X    {
X      char *val;
X      bzero (&ignore_regexp_compiled, sizeof ignore_regexp_compiled);
X      val = re_compile_pattern (ignore_regexp, strlen (ignore_regexp),
X				&ignore_regexp_compiled);
X      if (val != 0)
X	error ("%s: %s", ignore_regexp, val);
X      ignore_regexp_compiled.fastmap = (char *) xmalloc (256);
X    }
X
X  if (function_regexp)
X    {
X      char *val;
X      bzero (&function_regexp_compiled, sizeof function_regexp_compiled);
X      val = re_compile_pattern (function_regexp, strlen (function_regexp),
X				&function_regexp_compiled);
X      if (val != 0)
X	error ("%s: %s", function_regexp, val);
X      function_regexp_compiled.fastmap = (char *) xmalloc (256);
X    }
X
X  if (output_style != OUTPUT_CONTEXT && output_style != OUTPUT_UNIFIED)
X    context = 0;
X  else if (context == -1)
X    /* Default amount of context for -c.  */
X    context = 3;
X
X  switch_string = option_list (argv + 1, optind - 1);
X
X  val = compare_files (0, argv[optind], 0, argv[optind + 1], 0);
X
X  /* Print any messages that were saved up for last.  */
X  print_message_queue ();
X
X  if (ferror (stdout) || fclose (stdout) != 0)
X    fatal ("write error");
X  exit (val);
X}
X
Xusage ()
X{
X  fprintf (stderr, "\
XUsage: diff [-#] [-abBcdefhHilnNprstTuvw] [-C lines] [-F regexp] [-I regexp]\n\
X       [-L label [-L label]] [-S file] [-D symbol] [+ignore-blank-lines]\n\
X       [+context[=lines]] [+unified[=lines]] [+ifdef=symbol]\n\
X       [+show-function-line=regexp]\n");
X  fprintf (stderr, "\
X       [+speed-large-files] [+ignore-matching-lines=regexp] [+new-file]\n\
X       [+initial-tab] [+starting-file=file] [+text] [+all-text] [+ascii]\n\
X       [+minimal] [+ignore-space-change] [+ed] [+reversed-ed] [+ignore-case]\n");
X  fprintf (stderr, "\
X       [+print] [+rcs] [+show-c-function] [+binary] [+brief] [+recursive]\n\
X       [+report-identical-files] [+expand-tabs] [+ignore-all-space]\n\
X       [+file-label=label [+file-label=label]] [+version] path1 path2\n");
X  exit (2);
X} 
X
Xspecify_style (style)
X     enum output_style style;
X{
X  if (output_style != OUTPUT_NORMAL
X      && output_style != style)
X    error ("conflicting specifications of output style");
X  output_style = style;
X}
X
X/* Compare two files (or dirs) with specified names
X   DIR0/NAME0 and DIR1/NAME1, at level DEPTH in directory recursion.
X   (if DIR0 is 0, then the name is just NAME0, etc.)
X   This is self-contained; it opens the files and closes them.
X
X   Value is 0 if files are identical, 1 if different,
X   2 if there is a problem opening them.  */
X
Xint
Xcompare_files (dir0, name0, dir1, name1, depth)
X     char *dir0, *dir1;
X     char *name0, *name1;
X     int depth;
X{
X  static char Standard_Input[] = "Standard Input";
X  struct file_data inf[2];
X  register int i;
X  int val;
X  int errorcount = 0;
X  int stat_result[2];
X
X  /* If this is directory comparison, perhaps we have a file
X     that exists only in one of the directories.
X     If so, just print a message to that effect.  */
X
X  if (! entire_new_file_flag && (name0 == 0 || name1 == 0))
X    {
X      char *name = name0 == 0 ? name1 : name0;
X      char *dir = name0 == 0 ? dir1 : dir0;
X      message ("Only in %s: %s\n", dir, name);
X      /* Return 1 so that diff_dirs will return 1 ("some files differ").  */
X      return 1;
X    }
X
X  /* Mark any nonexistent file with -1 in the desc field.  */
X  /* Mark unopened files (i.e. directories) with -2. */
X
X  inf[0].desc = name0 == 0 ? -1 : -2;
X  inf[1].desc = name1 == 0 ? -1 : -2;
X
X  /* Now record the full name of each file, including nonexistent ones.  */
X
X  if (name0 == 0)
X    name0 = name1;
X  if (name1 == 0)
X    name1 = name0;
X
X  inf[0].name = dir0 == 0 ? name0 : concat (dir0, "/", name0);
X  inf[1].name = dir1 == 0 ? name1 : concat (dir1, "/", name1);
X
X  /* Stat the files.  Record whether they are directories.
X     Record in stat_result whether stat fails.  */
X
X  for (i = 0; i <= 1; i++)
X    {
X      bzero (&inf[i].stat, sizeof(struct stat));
X      inf[i].dir_p = 0;
X      stat_result[i] = 0;
X
X      if (inf[i].desc != -1)
X	{
X	  char *filename = inf[i].name;
X
X	  stat_result[i] = 
X	    strcmp (filename, "-")
X	      ? stat (filename, &inf[i].stat)
X	      : fstat (0, &inf[i].stat);
X		  
X	  if (stat_result[i] < 0)
X	    {
X	      perror_with_name (filename);
X	      errorcount = 1;
X	    }
X	  else
X	    inf[i].dir_p = 
X	      S_IFDIR == (inf[i].stat.st_mode & S_IFMT)
X	      && strcmp (filename, "-");
X	}
X    }
X
X  /* See if the two named files are actually the same physical file.
X     If so, we know they are identical without actually reading them.  */
X
X  if (output_style != OUTPUT_IFDEF
X      && inf[0].stat.st_ino == inf[1].stat.st_ino
X      && inf[0].stat.st_dev == inf[1].stat.st_dev
X      && stat_result[0] == 0
X      && stat_result[1] == 0)
X    {
X      val = 0;
X      goto done;
X    }
X
X  if (name0 == 0)
X    inf[0].dir_p = inf[1].dir_p;
X  if (name1 == 0)
X    inf[1].dir_p = inf[0].dir_p;
X
X  /* Open the files and record their descriptors.  */
X
X  for (i = 0; i <= 1; i++)
X    {
X      if (inf[i].desc == -1)
X	;
X      else if (!strcmp (inf[i].name, "-"))
X	{
X	  inf[i].desc = 0;
X	  inf[i].name = Standard_Input;
X	}
X      /* Don't bother opening if stat already failed.  */
X      else if (stat_result[i] == 0 && ! inf[i].dir_p)
X	{
X	  char *filename = inf[i].name;
X
X	  inf[i].desc = open (filename, O_RDONLY, 0);
X	  if (0 > inf[i].desc)
X	    {
X	      perror_with_name (filename);
X	      errorcount = 1;
X	    }
X	}
X    }
X
X  if (errorcount)
X    {
X
X      /* If either file should exist but fails to be opened, return 2.  */
X
X      val = 2;
X
X    }
X  else if (inf[0].dir_p && inf[1].dir_p)
X    {
X      if (output_style == OUTPUT_IFDEF)
X	fatal ("-D option not supported with directories");
X
X      /* If both are directories, compare the files in them.  */
X
X      if (depth > 0 && !recursive)
X	{
X	  /* But don't compare dir contents one level down
X	     unless -r was specified.  */
X	  message ("Common subdirectories: %s and %s\n",
X		   inf[0].name, inf[1].name);
X	  val = 0;
X	}
X      else
X	{
X	  val = diff_dirs (inf[0].name, inf[1].name, 
X			   compare_files, depth, 0, 0);
X	}
X
X    }
X  else if (depth == 0 && (inf[0].dir_p || inf[1].dir_p))
X    {
X
X      /* If only one is a directory, and it was specified in the command line,
X	 use the file in that dir whose basename matches the other file.  */
X
X      int dir_arg = (inf[0].dir_p ? 0 : 1);
X      int fnm_arg = (inf[0].dir_p ? 1 : 0);
X      char *p = rindex (inf[fnm_arg].name, '/');
X      char *filename = concat (inf[dir_arg].name,  "/",
X			       (p ? p+1 : inf[fnm_arg].name));
X
X      if (inf[fnm_arg].name == Standard_Input)
X	fatal ("can't compare - to a directory");
X
X      inf[dir_arg].desc = open (filename, O_RDONLY, 0);
X
X      if (0 > inf[dir_arg].desc)
X	{
X	  perror_with_name (filename);
X	  val = 2;
X	}
X      else
X	{
X	  /* JF: patch from the net to check and make sure we can really free
X	     this.  If it's from argv[], freeing it is a *really* bad idea */
X	  if (0 != (dir_arg ? dir1 : dir0))
X	    free (inf[dir_arg].name);
X	  inf[dir_arg].name = filename;
X	  if (fstat (inf[dir_arg].desc, &inf[dir_arg].stat) < 0)
X	    pfatal_with_name (inf[dir_arg].name);
X
X	  inf[dir_arg].dir_p
X	    = (S_IFDIR == (inf[dir_arg].stat.st_mode & S_IFMT));
X	  if (inf[dir_arg].dir_p)
X	    {
X	      error ("%s is a directory but %s is not",
X		     inf[dir_arg].name, inf[fnm_arg].name);
X	      val = 1;
X	    }
X	  else
X	    val = diff_2_files (inf, depth);
X	}
X
X    }
X  else if (depth > 0 && (inf[0].dir_p || inf[1].dir_p))
X    {
X      /* Perhaps we have a subdirectory that exists only in one directory.
X	 If so, just print a message to that effect.  */
X
X      if (inf[0].desc == -1 || inf[1].desc == -1)
X	{
X	  if (entire_new_file_flag && recursive)
X	    val = diff_dirs (inf[0].name, inf[1].name, compare_files, depth,
X			     inf[0].desc == -1, inf[1].desc == -1);
X	  else
X	    {
X	      char *dir = (inf[0].desc == -1) ? dir1 : dir0;
X	      message ("Only in %s: %s\n", dir, name0);
X	      val = 1;
X	    }
X	}
X      else
X	{
X	  /* We have a subdirectory in one directory
X	     and a file in the other.  */
X
X	  if (inf[0].dir_p)
X	    message ("%s is a directory but %s is not\n",
X		     inf[0].name, inf[1].name);
X	  else
X	    message ("%s is a directory but %s is not\n",
X		     inf[1].name, inf[0].name);
X	  /* This is a difference.  */
X	  val = 1;
X	}
X    }
X  else
X    {
X
X      /* Both exist and both are ordinary files.  */
X
X      val = diff_2_files (inf, depth);
X
X    }
X
X  /* Now the comparison has been done, if no error prevented it,
X     and VAL is the value this function will return.  */
X
X  if (inf[0].desc >= 0)
X    close (inf[0].desc);
X  if (inf[1].desc >= 0)
X    close (inf[1].desc);
X
X done:
X  if (val == 0 && !inf[0].dir_p)
X    {
X      if (print_file_same_flag)
X	message ("Files %s and %s are identical\n",
X		 inf[0].name, inf[1].name);
X    }
X  else
X    fflush (stdout);
X
X  if (dir0 != 0)
X    free (inf[0].name);
X  if (dir1 != 0)
X    free (inf[1].name);
X
X  return val;
X}
END_OF_FILE
if test 17901 -ne `wc -c <'diff.c'`; then
    echo shar: \"'diff.c'\" unpacked with wrong size!
fi
# end of 'diff.c'
fi
if test -f 'getopt.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'getopt.c'\"
else
echo shar: Extracting \"'getopt.c'\" \(16740 characters\)
sed "s/^X//" >'getopt.c' <<'END_OF_FILE'
X/* Getopt for GNU.
X   Copyright (C) 1987, 1989, 1990 Free Software Foundation, Inc.
X
X   This program is free software; you can redistribute it and/or modify
X   it under the terms of the GNU General Public License as published by
X   the Free Software Foundation; either version 1, or (at your option)
X   any later version.
X
X   This program is distributed in the hope that it will be useful,
X   but WITHOUT ANY WARRANTY; without even the implied warranty of
X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X   GNU General Public License for more details.
X
X   You should have received a copy of the GNU General Public License
X   along with this program; if not, write to the Free Software
X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
X
X#ifdef __STDC__
X#define CONST const
X#else
X#define CONST
X#endif
X
X/* This version of `getopt' appears to the caller like standard Unix `getopt'
X   but it behaves differently for the user, since it allows the user
X   to intersperse the options with the other arguments.
X
X   As `getopt' works, it permutes the elements of `argv' so that,
X   when it is done, all the options precede everything else.  Thus
X   all application programs are extended to handle flexible argument order.
X
X   Setting the environment variable _POSIX_OPTION_ORDER disables permutation.
X   Then the behavior is completely standard.
X
X   GNU application programs can use a third alternative mode in which
X   they can distinguish the relative order of options and other arguments.  */
X
X#include <stdio.h>
X
X/* If compiled with GNU C, use the built-in alloca */
X#ifdef __GNUC__
X#define alloca __builtin_alloca
X#else /* not __GNUC__ */
X#ifdef sparc
X#include <alloca.h>
X#else
Xchar *alloca ();
X#endif
X#endif /* not __GNUC__ */
X
X#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__)
X#include <stdlib.h>
X#include <string.h>
X#define bcopy(s, d, n) memcpy ((d), (s), (n))
X#define index strchr
X#else
X
X#ifdef USG
X#include <string.h>
X#define bcopy(s, d, n) memcpy ((d), (s), (n))
X#define index strchr
X#else
X#ifdef VMS
X#include <string.h>
X#else
X#include <strings.h>
X#endif
Xvoid bcopy ();
X#endif
X
Xchar *getenv ();
Xchar *malloc ();
X#endif
X
X/* For communication from `getopt' to the caller.
X   When `getopt' finds an option that takes an argument,
X   the argument value is returned here.
X   Also, when `ordering' is RETURN_IN_ORDER,
X   each non-option ARGV-element is returned here.  */
X
Xchar *optarg = 0;
X
X/* Index in ARGV of the next element to be scanned.
X   This is used for communication to and from the caller
X   and for communication between successive calls to `getopt'.
X
X   On entry to `getopt', zero means this is the first call; initialize.
X
X   When `getopt' returns EOF, this is the index of the first of the
X   non-option elements that the caller should itself scan.
X
X   Otherwise, `optind' communicates from one call to the next
X   how much of ARGV has been scanned so far.  */
X
Xint optind = 0;
X
X/* The next char to be scanned in the option-element
X   in which the last option character we returned was found.
X   This allows us to pick up the scan where we left off.
X
X   If this is zero, or a null string, it means resume the scan
X   by advancing to the next ARGV-element.  */
X
Xstatic char *nextchar;
X
X/* Callers store zero here to inhibit the error message
X   for unrecognized options.  */
X
Xint opterr = 1;
X
X/* Describe how to deal with options that follow non-option ARGV-elements.
X
X   If the caller did not specify anything,
X   the default is REQUIRE_ORDER if the environment variable
X   _POSIX_OPTION_ORDER is defined, PERMUTE otherwise.
X
X   REQUIRE_ORDER means don't recognize them as options;
X   stop option processing when the first non-option is seen.
X   This is what Unix does.
X   This mode of operation is selected by either setting the environment
X   variable _POSIX_OPTION_ORDER, or using `+' as the first character
X   of the list of option characters.
X
X   PERMUTE is the default.  We permute the contents of ARGV as we scan,
X   so that eventually all the non-options are at the end.  This allows options
X   to be given in any order, even with programs that were not written to
X   expect this.
X
X   RETURN_IN_ORDER is an option available to programs that were written
X   to expect options and other ARGV-elements in any order and that care about
X   the ordering of the two.  We describe each non-option ARGV-element
X   as if it were the argument of an option with character code 1.
X   Using `-' as the first character of the list of option characters
X   selects this mode of operation.
X
X   The special argument `--' forces an end of option-scanning regardless
X   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
X   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
X
Xstatic enum
X{
X  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
X} ordering;
X
X/* Describe the long-named options requested by the application.
X   _GETOPT_LONG_OPTIONS is a vector of `struct option' terminated by an
X   element containing a name which is zero.
X   The field `has_arg' is 1 if the option takes an argument,
X   2 if it takes an optional argument.  */
X
Xstruct option
X{
X  char *name;
X  int has_arg;
X  int *flag;
X  int val;
X};
X
XCONST struct option *_getopt_long_options;
X
Xint _getopt_long_only = 0;
X
X/* Index in _GETOPT_LONG_OPTIONS of the long-named option actually found.
X   Only valid when a long-named option was found. */
X
Xint option_index;
X
X/* Handle permutation of arguments.  */
X
X/* Describe the part of ARGV that contains non-options that have
X   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
X   `last_nonopt' is the index after the last of them.  */
X
Xstatic int first_nonopt;
Xstatic int last_nonopt;
X
X/* Exchange two adjacent subsequences of ARGV.
X   One subsequence is elements [first_nonopt,last_nonopt)
X    which contains all the non-options that have been skipped so far.
X   The other is elements [last_nonopt,optind), which contains all
X    the options processed since those non-options were skipped.
X
X   `first_nonopt' and `last_nonopt' are relocated so that they describe
X    the new indices of the non-options in ARGV after they are moved.  */
X
Xstatic void
Xexchange (argv)
X     char **argv;
X{
X  int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
X  char **temp = (char **) alloca (nonopts_size);
X
X  /* Interchange the two blocks of data in ARGV.  */
X
X  bcopy (&argv[first_nonopt], temp, nonopts_size);
X  bcopy (&argv[last_nonopt], &argv[first_nonopt],
X	 (optind - last_nonopt) * sizeof (char *));
X  bcopy (temp, &argv[first_nonopt + optind - last_nonopt], nonopts_size);
X
X  /* Update records for the slots the non-options now occupy.  */
X
X  first_nonopt += (optind - last_nonopt);
X  last_nonopt = optind;
X}
X
X/* Scan elements of ARGV (whose length is ARGC) for option characters
X   given in OPTSTRING.
X
X   If an element of ARGV starts with '-', and is not exactly "-" or "--",
X   then it is an option element.  The characters of this element
X   (aside from the initial '-') are option characters.  If `getopt'
X   is called repeatedly, it returns successively each of the option characters
X   from each of the option elements.
X
X   If `getopt' finds another option character, it returns that character,
X   updating `optind' and `nextchar' so that the next call to `getopt' can
X   resume the scan with the following option character or ARGV-element.
X
X   If there are no more option characters, `getopt' returns `EOF'.
X   Then `optind' is the index in ARGV of the first ARGV-element
X   that is not an option.  (The ARGV-elements have been permuted
X   so that those that are not options now come last.)
X
X   OPTSTRING is a string containing the legitimate option characters.
X   If an option character is seen that is not listed in OPTSTRING,
X   return '?' after printing an error message.  If you set `opterr' to
X   zero, the error message is suppressed but we still return '?'.
X
X   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
X   so the following text in the same ARGV-element, or the text of the following
X   ARGV-element, is returned in `optarg'.  Two colons mean an option that
X   wants an optional arg; if there is text in the current ARGV-element,
X   it is returned in `optarg', otherwise `optarg' is set to zero.
X
X   If OPTSTRING starts with `-' or `+', it requests different methods of
X   handling the non-option ARGV-elements.
X   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
X
X   Long-named options begin with `+' instead of `-'.
X   Their names may be abbreviated as long as the abbreviation is unique
X   or is an exact match for some defined option.  If they have an
X   argument, it follows the option name in the same ARGV-element, separated
X   from the option name by a `=', or else the in next ARGV-element.
X   When `getopt' finds a long-named option, it returns 0 if that option's
X   `flag' field is nonzero, the value of the option's `val' field
X   otherwise.  */
X
Xint
Xgetopt (argc, argv, optstring)
X     int argc;
X     char **argv;
X     CONST char *optstring;
X{
X  optarg = 0;
X
X  /* Initialize the internal data when the first call is made.
X     Start processing options with ARGV-element 1 (since ARGV-element 0
X     is the program name); the sequence of previously skipped
X     non-option ARGV-elements is empty.  */
X
X  if (optind == 0)
X    {
X      first_nonopt = last_nonopt = optind = 1;
X
X      nextchar = 0;
X
X      /* Determine how to handle the ordering of options and nonoptions.  */
X
X      if (optstring[0] == '-')
X	{
X	  ordering = RETURN_IN_ORDER;
X	  ++optstring;
X	}
X      else if (optstring[0] == '+')
X	{
X	  ordering = REQUIRE_ORDER;
X	  ++optstring;
X	}
X      else if (getenv ("_POSIX_OPTION_ORDER") != 0)
X	ordering = REQUIRE_ORDER;
X      else
X	ordering = PERMUTE;
X    }
X
X  if (nextchar == 0 || *nextchar == 0)
X    {
X      if (ordering == PERMUTE)
X	{
X	  /* If we have just processed some options following some non-options,
X	     exchange them so that the options come first.  */
X
X	  if (first_nonopt != last_nonopt && last_nonopt != optind)
X	    exchange (argv);
X	  else if (last_nonopt != optind)
X	    first_nonopt = optind;
X
X	  /* Now skip any additional non-options
X	     and extend the range of non-options previously skipped.  */
X
X	  while (optind < argc
X		 && (argv[optind][0] != '-'
X		     || argv[optind][1] == 0)
X		 && (_getopt_long_options == 0
X		     || argv[optind][0] != '+'
X		     || argv[optind][1] == 0))
X	    optind++;
X	  last_nonopt = optind;
X	}
X
X      /* Special ARGV-element `--' means premature end of options.
X	 Skip it like a null option,
X	 then exchange with previous non-options as if it were an option,
X	 then skip everything else like a non-option.  */
X
X      if (optind != argc && !strcmp (argv[optind], "--"))
X	{
X	  optind++;
X
X	  if (first_nonopt != last_nonopt && last_nonopt != optind)
X	    exchange (argv);
X	  else if (first_nonopt == last_nonopt)
X	    first_nonopt = optind;
X	  last_nonopt = argc;
X
X	  optind = argc;
X	}
X
X      /* If we have done all the ARGV-elements, stop the scan
X	 and back over any non-options that we skipped and permuted.  */
X
X      if (optind == argc)
X	{
X	  /* Set the next-arg-index to point at the non-options
X	     that we previously skipped, so the caller will digest them.  */
X	  if (first_nonopt != last_nonopt)
X	    optind = first_nonopt;
X	  return EOF;
X	}
X
X      /* If we have come to a non-option and did not permute it,
X	 either stop the scan or describe it to the caller and pass it by.  */
X
X      if ((argv[optind][0] != '-' || argv[optind][1] == 0)
X	  && (_getopt_long_options == 0
X	      || argv[optind][0] != '+' || argv[optind][1] == 0))
X	{
X	  if (ordering == REQUIRE_ORDER)
X	    return EOF;
X	  optarg = argv[optind++];
X	  return 1;
X	}
X
X      /* We have found another option-ARGV-element.
X	 Start decoding its characters.  */
X
X      nextchar = argv[optind] + 1;
X    }
X
X  if (_getopt_long_options != 0
X      && (argv[optind][0] == '+'
X	  || (_getopt_long_only && argv[optind][0] == '-'))
X    )
X    {
X      CONST struct option *p;
X      char *s = nextchar;
X      int exact = 0;
X      int ambig = 0;
X      CONST struct option *pfound = 0;
X      int indfound;
X
X      while (*s && *s != '=')
X	s++;
X
X      /* Test all options for either exact match or abbreviated matches.  */
X      for (p = _getopt_long_options, option_index = 0; p->name;
X	   p++, option_index++)
X	if (!strncmp (p->name, nextchar, s - nextchar))
X	  {
X	    if (s - nextchar == strlen (p->name))
X	      {
X		/* Exact match found.  */
X		pfound = p;
X		indfound = option_index;
X		exact = 1;
X		break;
X	      }
X	    else if (pfound == 0)
X	      {
X		/* First nonexact match found.  */
X		pfound = p;
X		indfound = option_index;
X	      }
X	    else
X	      /* Second nonexact match found.  */
X	      ambig = 1;
X	  }
X
X      if (ambig && !exact)
X	{
X	  fprintf (stderr, "%s: option `%s' is ambiguous\n",
X		   argv[0], argv[optind]);
X	  nextchar += strlen (nextchar);
X	  optind++;
X	  return '?';
X	}
X
X      if (pfound != 0)
X	{
X	  option_index = indfound;
X	  optind++;
X	  if (*s)
X	    {
X	      if (pfound->has_arg > 0)
X		optarg = s + 1;
X	      else
X		{
X		  fprintf (stderr,
X			   "%s: option `%c%s' doesn't allow an argument\n",
X			   argv[0], argv[optind - 1][0], pfound->name);
X		  nextchar += strlen (nextchar);
X		  return '?';
X		}
X	    }
X	  else if (pfound->has_arg == 1)
X	    {
X	      if (optind < argc)
X		optarg = argv[optind++];
X	      else
X		{
X		  fprintf (stderr, "%s: option `%s' requires an argument\n",
X			   argv[0], argv[optind - 1]);
X		  nextchar += strlen (nextchar);
X		  return '?';
X		}
X	    }
X	  nextchar += strlen (nextchar);
X	  if (pfound->flag)
X	    {
X	      *(pfound->flag) = pfound->val;
X	      return 0;
X	    }
X	  return pfound->val;
X	}
X      /* Can't find it as a long option.  If this is getopt_long_only,
X	 and the option starts with '-' and is a valid short
X	 option, then interpret it as a short option.  Otherwise it's
X	 an error.  */
X      if (_getopt_long_only == 0 || argv[optind][0] == '+' ||
X	  index (optstring, *nextchar) == 0)
X	{
X	  if (opterr != 0)
X	    fprintf (stderr, "%s: unrecognized option `%c%s'\n",
X		     argv[0], argv[optind][0], nextchar);
X	  nextchar += strlen (nextchar);
X	  optind++;
X	  return '?';
X	}
X    }
X
X  /* Look at and handle the next option-character.  */
X
X  {
X    char c = *nextchar++;
X    char *temp = index (optstring, c);
X
X    /* Increment `optind' when we start to process its last character.  */
X    if (*nextchar == 0)
X      optind++;
X
X    if (temp == 0 || c == ':')
X      {
X	if (opterr != 0)
X	  {
X	    if (c < 040 || c >= 0177)
X	      fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
X		       argv[0], c);
X	    else
X	      fprintf (stderr, "%s: unrecognized option `-%c'\n",
X		       argv[0], c);
X	  }
X	return '?';
X      }
X    if (temp[1] == ':')
X      {
X	if (temp[2] == ':')
X	  {
X	    /* This is an option that accepts an argument optionally.  */
X	    if (*nextchar != 0)
X	      {
X		optarg = nextchar;
X		optind++;
X	      }
X	    else
X	      optarg = 0;
X	    nextchar = 0;
X	  }
X	else
X	  {
X	    /* This is an option that requires an argument.  */
X	    if (*nextchar != 0)
X	      {
X		optarg = nextchar;
X		/* If we end this ARGV-element by taking the rest as an arg,
X		   we must advance to the next element now.  */
X		optind++;
X	      }
X	    else if (optind == argc)
X	      {
X		if (opterr != 0)
X		  fprintf (stderr, "%s: option `-%c' requires an argument\n",
X			   argv[0], c);
X		c = '?';
X	      }
X	    else
X	      /* We already incremented `optind' once;
X		 increment it again when taking next ARGV-elt as argument.  */
X	      optarg = argv[optind++];
X	    nextchar = 0;
X	  }
X      }
X    return c;
X  }
X}
X
X#ifdef TEST
X
X/* Compile with -DTEST to make an executable for use in testing
X   the above definition of `getopt'.  */
X
Xint
Xmain (argc, argv)
X     int argc;
X     char **argv;
X{
X  int c;
X  int digit_optind = 0;
X
X  while (1)
X    {
X      int this_option_optind = optind ? optind : 1;
X
X      c = getopt (argc, argv, "abc:d:0123456789");
X      if (c == EOF)
X	break;
X
X      switch (c)
X	{
X	case '0':
X	case '1':
X	case '2':
X	case '3':
X	case '4':
X	case '5':
X	case '6':
X	case '7':
X	case '8':
X	case '9':
X	  if (digit_optind != 0 && digit_optind != this_option_optind)
X	    printf ("digits occur in two different argv-elements.\n");
X	  digit_optind = this_option_optind;
X	  printf ("option %c\n", c);
X	  break;
X
X	case 'a':
X	  printf ("option a\n");
X	  break;
X
X	case 'b':
X	  printf ("option b\n");
X	  break;
X
X	case 'c':
X	  printf ("option c with value `%s'\n", optarg);
X	  break;
X
X	case '?':
X	  break;
X
X	default:
X	  printf ("?? getopt returned character code 0%o ??\n", c);
X	}
X    }
X
X  if (optind < argc)
X    {
X      printf ("non-option ARGV-elements: ");
X      while (optind < argc)
X	printf ("%s ", argv[optind++]);
X      printf ("\n");
X    }
X
X  exit (0);
X}
X
X#endif /* TEST */
END_OF_FILE
if test 16740 -ne `wc -c <'getopt.c'`; then
    echo shar: \"'getopt.c'\" unpacked with wrong size!
fi
# end of 'getopt.c'
fi
if test -f 'util.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'util.c'\"
else
echo shar: Extracting \"'util.c'\" \(14888 characters\)
sed "s/^X//" >'util.c' <<'END_OF_FILE'
X/* Support routines for GNU DIFF.
X   Copyright (C) 1988, 1989 Free Software Foundation, Inc.
X
XThis file is part of GNU DIFF.
X
XGNU DIFF is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation; either version 1, or (at your option)
Xany later version.
X
XGNU DIFF is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with GNU DIFF; see the file COPYING.  If not, write to
Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
X
X#include "diff.h"
X
X/* Use when a system call returns non-zero status.
X   TEXT should normally be the file name.  */
X
Xvoid
Xperror_with_name (text)
X     char *text;
X{
X  fprintf (stderr, "%s: ", program);
X  perror (text);
X}
X
X/* Use when a system call returns non-zero status and that is fatal.  */
X
Xvoid
Xpfatal_with_name (text)
X     char *text;
X{
X  print_message_queue ();
X  fprintf (stderr, "%s: ", program);
X  perror (text);
X  exit (2);
X}
X
X/* Print an error message from the format-string FORMAT
X   with args ARG1 and ARG2.  */
X
Xvoid
Xerror (format, arg, arg1)
X     char *format;
X     char *arg;
X     char *arg1;
X{
X  fprintf (stderr, "%s: ", program);
X  fprintf (stderr, format, arg, arg1);
X  fprintf (stderr, "\n");
X}
X
X/* Print an error message containing the string TEXT, then exit.  */
X
Xvoid
Xfatal (message)
X     char *message;
X{
X  print_message_queue ();
X  error (message, "");
X  exit (2);
X}
X
X/* Like printf, except if -l in effect then save the message and print later.
X   This is used for things like "binary files differ" and "Only in ...".  */
X
Xvoid
Xmessage (format, arg1, arg2)
X     char *format, *arg1, *arg2;
X{
X  if (paginate_flag)
X    {
X      struct msg *new = (struct msg *) xmalloc (sizeof (struct msg));
X      if (msg_chain_end == 0)
X	msg_chain = msg_chain_end = new;
X      else
X	{
X	  msg_chain_end->next = new;
X	  msg_chain_end = new;
X	}
X      new->format = format;
X      new->arg1 = concat (arg1, "", "");
X      new->arg2 = concat (arg2, "", "");
X      new->next = 0;
X    }
X  else
X    printf (format, arg1, arg2);
X}
X
X/* Output all the messages that were saved up by calls to `message'.  */
X
Xvoid
Xprint_message_queue ()
X{
X  struct msg *m;
X
X  for (m = msg_chain; m; m = m->next)
X    printf (m->format, m->arg1, m->arg2);
X}
X
X/* Call before outputting the results of comparing files NAME0 and NAME1
X   to set up OUTFILE, the stdio stream for the output to go to.
X
X   Usually, OUTFILE is just stdout.  But when -l was specified
X   we fork off a `pr' and make OUTFILE a pipe to it.
X   `pr' then outputs to our stdout.  */
X
Xvoid
Xsetup_output (name0, name1, depth)
X     char *name0, *name1;
X     int depth;
X{
X  char *name;
X
X  /* Construct the header of this piece of diff.  */
X  name = (char *) xmalloc (strlen (name0) + strlen (name1)
X			   + strlen (switch_string) + 15);
X
X  strcpy (name, "diff");
X  strcat (name, switch_string);
X  strcat (name, " ");
X  strcat (name, name0);
X  strcat (name, " ");
X  strcat (name, name1);
X
X  if (paginate_flag)
X    {
X      int pipes[2];
X      int desc;
X
X      /* For a `pr' and make OUTFILE a pipe to it.  */
X      if (pipe (pipes) < 0)
X	pfatal_with_name ("pipe");
X
X      fflush (stdout);
X
X      desc = vfork ();
X      if (desc < 0)
X	pfatal_with_name ("vfork");
X
X      if (desc == 0)
X	{
X	  close (pipes[1]);
X	  if (pipes[0] != fileno (stdin))
X	    {
X	      if (dup2 (pipes[0], fileno (stdin)) < 0)
X		pfatal_with_name ("dup2");
X	      close (pipes[0]);
X	    }
X
X	  if (execl (PR_FILE_NAME, PR_FILE_NAME, "-f", "-h", name, 0) < 0)
X	    pfatal_with_name (PR_FILE_NAME);
X	}
X      else
X	{
X	  close (pipes[0]);
X	  outfile = fdopen (pipes[1], "w");
X	} 
X    }
X  else
X    {
X
X      /* If -l was not specified, output the diff straight to `stdout'.  */
X
X      outfile = stdout;
X
X      /* If handling multiple files (because scanning a directory),
X	 print which files the following output is about.  */
X      if (depth > 0)
X	printf ("%s\n", name);
X    }
X
X  free (name);
X}
X
X/* Call after the end of output of diffs for one file.
X   Close OUTFILE and get rid of the `pr' subfork.  */
X
Xvoid
Xfinish_output ()
X{
X  if (outfile != stdout)
X    {
X      fclose (outfile);
X      wait (0);
X    }
X}
X
X/* Compare two lines (typically one from each input file)
X   according to the command line options.
X   Each line is described by a `struct line_def'.
X   Return 1 if the lines differ, like `bcmp'.  */
X
Xint
Xline_cmp (s1, s2)
X     struct line_def *s1, *s2;
X{
X  register char *t1, *t2;
X  register char end_char = line_end_char;
X  int savechar;
X
X  /* Check first for exact identity.
X     If that is true, return 0 immediately.
X     This detects the common case of exact identity
X     faster than complete comparison would.  */
X
X  t1 = s1->text;
X  t2 = s2->text;
X
X  /* Alter the character following line 2 so it doesn't
X     match that following line 1.
X     (We used to alter the character after line 1,
X     but that caused trouble if line 2 directly follows line 1.)  */
X  savechar = s2->text[s2->length];
X  s2->text[s2->length] = s1->text[s1->length] + 1;
X
X  /* Now find the first mismatch; this won't go past the
X     character we just changed.  */
X  while (*t1++ == *t2++);
X
X  /* Undo the alteration.  */
X  s2->text[s2->length] = savechar;
X
X  /* If the comparison stopped at the alteration,
X     the two lines are identical.  */
X  if (t2 == s2->text + s2->length + 1)
X    return 0;
X
X  /* Not exactly identical, but perhaps they match anyway
X     when case or whitespace is ignored.  */
X
X  if (ignore_case_flag || ignore_space_change_flag || ignore_all_space_flag)
X    {
X      t1 = s1->text;
X      t2 = s2->text;
X
X      while (1)
X	{
X	  register char c1 = *t1++;
X	  register char c2 = *t2++;
X
X	  /* Ignore horizontal whitespace if -b or -w is specified.  */
X
X	  if (ignore_all_space_flag)
X	    {
X	      /* For -w, just skip past any spaces or tabs.  */
X	      while (c1 == ' ' || c1 == '\t') c1 = *t1++;
X	      while (c2 == ' ' || c2 == '\t') c2 = *t2++;
X	    }
X	  else if (ignore_space_change_flag)
X	    {
X	      /* For -b, advance past any sequence of whitespace in line 1
X		 and consider it just one Space, or nothing at all
X		 if it is at the end of the line.  */
X	      if (c1 == ' ' || c1 == '\t')
X		{
X		  while (1)
X		    {
X		      c1 = *t1++;
X		      if (c1 == end_char)
X			break;
X		      if (c1 != ' ' && c1 != '\t')
X			{
X			  --t1;
X			  c1 = ' ';
X			  break;
X			}
X		    }
X		}
X
X	      /* Likewise for line 2.  */
X	      if (c2 == ' ' || c2 == '\t')
X		{
X		  while (1)
X		    {
X		      c2 = *t2++;
X		      if (c2 == end_char)
X			break;
X		      if (c2 != ' ' && c2 != '\t')
X			{
X			  --t2;
X			  c2 = ' ';
X			  break;
X			}
X		    }
X		}
X	    }
X
X	  /* Upcase all letters if -i is specified.  */
X
X	  if (ignore_case_flag)
X	    {
X	      if (islower (c1))
X		c1 = toupper (c1);
X	      if (islower (c2))
X		c2 = toupper (c2);
X	    }
X
X	  if (c1 != c2)
X	    break;
X	  if (c1 == end_char)
X	    return 0;
X	}
X    }
X
X  return (1);
X}
X
X/* Find the consecutive changes at the start of the script START.
X   Return the last link before the first gap.  */
X
Xstruct change *
Xfind_change (start)
X     struct change *start;
X{
X  return start;
X}
X
Xstruct change *
Xfind_reverse_change (start)
X     struct change *start;
X{
X  return start;
X}
X
X/* Divide SCRIPT into pieces by calling HUNKFUN and
X   print each piece with PRINTFUN.
X   Both functions take one arg, an edit script.
X
X   HUNKFUN is called with the tail of the script
X   and returns the last link that belongs together with the start
X   of the tail.
X
X   PRINTFUN takes a subscript which belongs together (with a null
X   link at the end) and prints it.  */
X
Xvoid
Xprint_script (script, hunkfun, printfun)
X     struct change *script;
X     struct change * (*hunkfun) ();
X     void (*printfun) ();
X{
X  struct change *next = script;
X
X  while (next)
X    {
X      struct change *this, *end;
X
X      /* Find a set of changes that belong together.  */
X      this = next;
X      end = (*hunkfun) (next);
X
X      /* Disconnect them from the rest of the changes,
X	 making them a hunk, and remember the rest for next iteration.  */
X      next = end->link;
X      end->link = NULL;
X#ifdef DEBUG
X      debug_script (this);
X#endif
X
X      /* Print this hunk.  */
X      (*printfun) (this);
X
X      /* Reconnect the script so it will all be freed properly.  */
X      end->link = next;
X    }
X}
X
X/* Print the text of a single line LINE,
X   flagging it with the characters in LINE_FLAG (which say whether
X   the line is inserted, deleted, changed, etc.).  */
X
Xvoid
Xprint_1_line (line_flag, line)
X     char *line_flag;
X     struct line_def *line;
X{
X  int length = line->length; /* must be nonzero */
X  const char *text = line->text; /* Help the compiler.  */
X  FILE *out = outfile; /* Help the compiler some more.  */
X
X  /* If -T was specified, use a Tab between the line-flag and the text.
X     Otherwise use a Space (as Unix diff does).
X     Print neither space nor tab if line-flags are empty.  */
X
X  if (line_flag != NULL && line_flag[0] != 0)
X    fprintf (out, tab_align_flag ? "%s\t" : "%s ", line_flag);
X
X  /* Now output the contents of the line.
X     If -t was specified, expand tabs to spaces.
X     Otherwise output verbatim.  */
X
X  if (tab_expand_flag)
X    {
X      register int column = 0;
X      register int i;
X      for (i = 0; i < line->length; i++)
X	{
X	  register char c = line->text[i];
X	  switch (c)
X	    {
X	    case '\t':
X	      column++;
X	      while (column & 7)
X		{
X		  putc (' ', out);
X		  column++;
X		}
X	      c = ' ';
X	      break;
X	    case '\b':
X	      column--;
X	      break;
X	    default:
X	      column++;
X	      break;
X	    }
X	  putc (c, out);
X	}
X    }
X  else
X    fwrite (text, sizeof (char), length, out);
X  if ((line_flag == NULL || line_flag[0] != 0) && text[length - 1] != '\n'
X      && line_end_char == '\n')
X    fprintf (out, "\n\\ No newline at end of file\n");
X}
X
Xchange_letter (inserts, deletes)
X     int inserts, deletes;
X{
X  if (!inserts)
X    return 'd';
X  else if (!deletes)
X    return 'a';
X  else
X    return 'c';
X}
X
X/* Translate an internal line number (an index into diff's table of lines)
X   into an actual line number in the input file.
X   The internal line number is LNUM.  FILE points to the data on the file.
X
X   Internal line numbers count from 0 within the current chunk.
X   Actual line numbers count from 1 within the entire file;
X   in addition, they include lines ignored for comparison purposes.
X
X   The `ltran' feature is no longer in use.  */
X
Xint
Xtranslate_line_number (file, lnum)
X     struct file_data *file;
X     int lnum;
X{
X  return lnum + 1;
X}
X
Xvoid
Xtranslate_range (file, a, b, aptr, bptr)
X     struct file_data *file;
X     int a, b;
X     int *aptr, *bptr;
X{
X  *aptr = translate_line_number (file, a - 1) + 1;
X  *bptr = translate_line_number (file, b + 1) - 1;
X}
X
X/* Print a pair of line numbers with SEPCHAR, translated for file FILE.
X   If the two numbers are identical, print just one number.
X
X   Args A and B are internal line numbers.
X   We print the translated (real) line numbers.  */
X
Xvoid
Xprint_number_range (sepchar, file, a, b)
X     char sepchar;
X     struct file_data *file;
X     int a, b;
X{
X  int trans_a, trans_b;
X  translate_range (file, a, b, &trans_a, &trans_b);
X
X  /* Note: we can have B < A in the case of a range of no lines.
X     In this case, we should print the line number before the range,
X     which is B.  */
X  if (trans_b > trans_a)
X    fprintf (outfile, "%d%c%d", trans_a, sepchar, trans_b);
X  else
X    fprintf (outfile, "%d", trans_b);
X}
X
X/* Look at a hunk of edit script and report the range of lines in each file
X   that it applies to.  HUNK is the start of the hunk, which is a chain
X   of `struct change'.  The first and last line numbers of file 0 are stored in
X   *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1. 
X   Note that these are internal line numbers that count from 0.
X
X   If no lines from file 0 are deleted, then FIRST0 is LAST0+1.
X
X   Also set *DELETES nonzero if any lines of file 0 are deleted
X   and set *INSERTS nonzero if any lines of file 1 are inserted.
X   If only ignorable lines are inserted or deleted, both are
X   set to 0.  */
X
Xvoid
Xanalyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts)
X     struct change *hunk;
X     int *first0, *last0, *first1, *last1;
X     int *deletes, *inserts;
X{
X  int f0, l0, f1, l1, show_from, show_to;
X  int i;
X  int nontrivial = !(ignore_blank_lines_flag || ignore_regexp);
X  struct change *next;
X
X  show_from = show_to = 0;
X
X  f0 = hunk->line0;
X  f1 = hunk->line1;
X
X  for (next = hunk; next; next = next->link)
X    {
X      l0 = next->line0 + next->deleted - 1;
X      l1 = next->line1 + next->inserted - 1;
X      show_from += next->deleted;
X      show_to += next->inserted;
X
X      for (i = next->line0; i <= l0 && ! nontrivial; i++)
X	if ((!ignore_blank_lines_flag || files[0].linbuf[i].length > 1)
X	    && (!ignore_regexp
X		|| 0 > re_search (&ignore_regexp_compiled,
X				  files[0].linbuf[i].text,
X				  files[0].linbuf[i].length, 0,
X				  files[0].linbuf[i].length, 0)))
X	  nontrivial = 1;
X
X      for (i = next->line1; i <= l1 && ! nontrivial; i++)
X	if ((!ignore_blank_lines_flag || files[1].linbuf[i].length > 1)
X	    && (!ignore_regexp
X		|| 0 > re_search (&ignore_regexp_compiled,
X				  files[1].linbuf[i].text,
X				  files[1].linbuf[i].length, 0,
X				  files[1].linbuf[i].length, 0)))
X	  nontrivial = 1;
X    }
X
X  *first0 = f0;
X  *last0 = l0;
X  *first1 = f1;
X  *last1 = l1;
X
X  /* If all inserted or deleted lines are ignorable,
X     tell the caller to ignore this hunk.  */
X
X  if (!nontrivial)
X    show_from = show_to = 0;
X
X  *deletes = show_from;
X  *inserts = show_to;
X}
X
X/* malloc a block of memory, with fatal error message if we can't do it. */
X
XVOID *
Xxmalloc (size)
X     unsigned size;
X{
X  register VOID *value;
X
X  if (size == 0)
X    size = 1;
X
X  value = (VOID *) malloc (size);
X
X  if (!value)
X    fatal ("virtual memory exhausted");
X  return value;
X}
X
X/* realloc a block of memory, with fatal error message if we can't do it. */
X
XVOID *
Xxrealloc (old, size)
X     VOID *old;
X     unsigned int size;
X{
X  register VOID *value;
X
X  if (size == 0)
X    size = 1;
X
X  value = (VOID *) realloc (old, size);
X
X  if (!value)
X    fatal ("virtual memory exhausted");
X  return value;
X}
X
X/* Concatenate three strings, returning a newly malloc'd string.  */
X
Xchar *
Xconcat (s1, s2, s3)
X     char *s1, *s2, *s3;
X{
X  int len = strlen (s1) + strlen (s2) + strlen (s3);
X  char *new = (char *) xmalloc (len + 1);
X  strcpy (new, s1);
X  strcat (new, s2);
X  strcat (new, s3);
X  return new;
X}
X
Xdebug_script (sp)
X     struct change *sp;
X{
X  fflush (stdout);
X  for (; sp; sp = sp->link)
X    fprintf (stderr, "%3d %3d delete %d insert %d\n",
X	     sp->line0, sp->line1, sp->deleted, sp->inserted);
X  fflush (stderr);
X}
END_OF_FILE
if test 14888 -ne `wc -c <'util.c'`; then
    echo shar: \"'util.c'\" unpacked with wrong size!
fi
# end of 'util.c'
fi
echo shar: End of archive 3 \(of 8\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 8 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.



More information about the Comp.sources.unix mailing list