GNU3 Diff 2.3
authorNate Willams <nate@FreeBSD.org>
Tue, 29 Jun 1993 08:19:28 +0000 (08:19 +0000)
committerNate Willams <nate@FreeBSD.org>
Tue, 29 Jun 1993 08:19:28 +0000 (08:19 +0000)
gnu/usr.bin/diff3/COPYING [new file with mode: 0644]
gnu/usr.bin/diff3/Makefile [new file with mode: 0644]
gnu/usr.bin/diff3/diff3.c [new file with mode: 0644]
gnu/usr.bin/diff3/getopt.c [new file with mode: 0644]
gnu/usr.bin/diff3/getopt.h [new file with mode: 0644]
gnu/usr.bin/diff3/getopt1.c [new file with mode: 0644]
gnu/usr.bin/diff3/system.h [new file with mode: 0644]
gnu/usr.bin/diff3/version.c [new file with mode: 0644]

diff --git a/gnu/usr.bin/diff3/COPYING b/gnu/usr.bin/diff3/COPYING
new file mode 100644 (file)
index 0000000..a43ea21
--- /dev/null
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/diff3/Makefile b/gnu/usr.bin/diff3/Makefile
new file mode 100644 (file)
index 0000000..7510536
--- /dev/null
@@ -0,0 +1,9 @@
+PROG=  diff3
+SRCS=  diff3.c getopt.c getopt1.c version.c
+CFLAGS+=-DDIRENT=1 -DHAVE_UNISTD_H=1 -DHAVE_DUP2=1 -DHAVE_MEMCHR=1 \
+       -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_FCNTL_H=1 \
+       -DHAVE_STRING_H=1 -DHAVE_SYS_WAIT_H=1 -DHAVE_TIME_H=1 \
+       -DHAVE_ST_BLKSIZE=1 -DDIFF_PROGRAM=\"/usr/bin/diff\"
+NOMAN=noman
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/diff3/diff3.c b/gnu/usr.bin/diff3/diff3.c
new file mode 100644 (file)
index 0000000..b9952fc
--- /dev/null
@@ -0,0 +1,1693 @@
+/* Three way file comparison program (diff3) for Project GNU.
+   Copyright (C) 1988, 1989, 1992 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+/* Written by Randy Smith */
+
+#if __STDC__
+#define VOID void
+#else
+#define VOID char
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include "getopt.h"
+#include "system.h"
+
+/*
+ * Internal data structures and macros for the diff3 program; includes
+ * data structures for both diff3 diffs and normal diffs.
+ */
+
+/* Different files within a three way diff.  */
+#define        FILE0   0
+#define        FILE1   1
+#define        FILE2   2
+
+/*
+ * A three way diff is built from two two-way diffs; the file which
+ * the two two-way diffs share is:
+ */
+#define        FILEC   FILE2
+
+/*
+ * Different files within a two way diff.
+ * FC is the common file, FO the other file.
+ */
+#define FO 0
+#define FC 1
+
+/* The ranges are indexed by */
+#define        START   0
+#define        END     1
+
+enum diff_type {
+  ERROR,                       /* Should not be used */
+  ADD,                         /* Two way diff add */
+  CHANGE,                      /* Two way diff change */
+  DELETE,                      /* Two way diff delete */
+  DIFF_ALL,                    /* All three are different */
+  DIFF_1ST,                    /* Only the first is different */
+  DIFF_2ND,                    /* Only the second */
+  DIFF_3RD                     /* Only the third */
+};
+
+/* Two way diff */
+struct diff_block {
+  int ranges[2][2];            /* Ranges are inclusive */
+  char **lines[2];             /* The actual lines (may contain nulls) */
+  int *lengths[2];             /* Line lengths (including newlines, if any) */
+  struct diff_block *next;
+};
+
+/* Three way diff */
+
+struct diff3_block {
+  enum diff_type correspond;   /* Type of diff */
+  int ranges[3][2];            /* Ranges are inclusive */
+  char **lines[3];             /* The actual lines (may contain nulls) */
+  int *lengths[3];             /* Line lengths (including newlines, if any) */
+  struct diff3_block *next;
+};
+
+/*
+ * Access the ranges on a diff block.
+ */
+#define        D_LOWLINE(diff, filenum)        \
+  ((diff)->ranges[filenum][START])
+#define        D_HIGHLINE(diff, filenum)       \
+  ((diff)->ranges[filenum][END])
+#define        D_NUMLINES(diff, filenum)       \
+  (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1)
+
+/*
+ * Access the line numbers in a file in a diff by relative line
+ * numbers (i.e. line number within the diff itself).  Note that these
+ * are lvalues and can be used for assignment.
+ */
+#define        D_RELNUM(diff, filenum, linenum)        \
+  ((diff)->lines[filenum][linenum])
+#define        D_RELLEN(diff, filenum, linenum)        \
+  ((diff)->lengths[filenum][linenum])
+
+/*
+ * And get at them directly, when that should be necessary.
+ */
+#define        D_LINEARRAY(diff, filenum)      \
+  ((diff)->lines[filenum])
+#define        D_LENARRAY(diff, filenum)       \
+  ((diff)->lengths[filenum])
+
+/*
+ * Next block.
+ */
+#define        D_NEXT(diff)    ((diff)->next)
+
+/*
+ * Access the type of a diff3 block.
+ */
+#define        D3_TYPE(diff)   ((diff)->correspond)
+
+/*
+ * Line mappings based on diffs.  The first maps off the top of the
+ * diff, the second off of the bottom.
+ */
+#define        D_HIGH_MAPLINE(diff, fromfile, tofile, lineno)  \
+  ((lineno)                                            \
+   - D_HIGHLINE ((diff), (fromfile))                   \
+   + D_HIGHLINE ((diff), (tofile)))
+
+#define        D_LOW_MAPLINE(diff, fromfile, tofile, lineno)   \
+  ((lineno)                                            \
+   - D_LOWLINE ((diff), (fromfile))                    \
+   + D_LOWLINE ((diff), (tofile)))
+
+/*
+ * General memory allocation function.
+ */
+#define        ALLOCATE(number, type)  \
+  (type *) xmalloc ((number) * sizeof (type))
+\f
+/* Options variables for flags set on command line.  */
+
+/* If nonzero, treat all files as text files, never as binary.  */
+static int always_text;
+
+/* If nonzero, write out an ed script instead of the standard diff3 format.  */
+static int edscript;
+
+/* If nonzero, in the case of overlapping diffs (type DIFF_ALL),
+   preserve the lines which would normally be deleted from
+   file 1 with a special flagging mechanism.  */
+static int flagging;
+
+/* Number of lines to keep in identical prefix and suffix.  */
+static int horizon_lines = 10;
+
+/* If nonzero, do not output information for overlapping diffs.  */
+static int simple_only;
+
+/* If nonzero, do not output information for non-overlapping diffs.  */
+static int overlap_only;
+
+/* If nonzero, show information for DIFF_2ND diffs.  */
+static int show_2nd;
+
+/* If nonzero, include `:wq' at the end of the script
+   to write out the file being edited.   */
+static int finalwrite;
+
+/* If nonzero, output a merged file.  */
+static int merge;
+
+static char *argv0;
+
+/*
+ * Forward function declarations.
+ */
+static int myread ();
+static void fatal ();
+static void perror_with_exit ();
+static struct diff_block *process_diff ();
+static struct diff3_block *make_3way_diff ();
+static void output_diff3 ();
+static int output_diff3_edscript ();
+static int output_diff3_merge ();
+static void usage ();
+
+static struct diff3_block *using_to_diff3_block ();
+static int copy_stringlist ();
+static struct diff3_block *create_diff3_block ();
+static int compare_line_list ();
+
+static char *read_diff ();
+static enum diff_type process_diff_control ();
+static char *scan_diff_line ();
+
+static struct diff3_block *reverse_diff3_blocklist ();
+
+VOID *xmalloc ();
+static VOID *xrealloc ();
+
+static char diff_program[] = DIFF_PROGRAM;
+
+static struct option longopts[] =
+{
+  {"text", 0, NULL, 'a'},
+  {"show-all", 0, NULL, 'A'},
+  {"ed", 0, NULL, 'e'},
+  {"show-overlap", 0, NULL, 'E'},
+  {"label", 1, NULL, 'L'},
+  {"merge", 0, NULL, 'm'},
+  {"overlap-only", 0, NULL, 'x'},
+  {"easy-only", 0, NULL, '3'},
+  {"version", 0, NULL, 'v'},
+  {0, 0, 0, 0}
+};
+
+/*
+ * Main program.  Calls diff twice on two pairs of input files,
+ * combines the two diffs, and outputs them.
+ */
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  extern char *version_string;
+  int c, i;
+  int mapping[3];
+  int rev_mapping[3];
+  int incompat;
+  int conflicts_found;
+  struct diff_block *thread0, *thread1, *last_block;
+  struct diff3_block *diff3;
+  int tag_count = 0;
+  char *tag_strings[3];
+  extern char *optarg;
+  char *commonname;
+  char **file;
+  struct stat statb;
+
+  incompat = 0;
+
+  argv0 = argv[0];
+
+  while ((c = getopt_long (argc, argv, "aeimvx3AEXL:", longopts, (int *) 0))
+        != EOF)
+    {
+      switch (c)
+       {
+       case 'a':
+         always_text = 1;
+         break;
+       case 'A':
+         show_2nd = 1;
+         flagging = 1;
+         incompat++;
+         break;
+       case 'x':
+         overlap_only = 1;
+         incompat++;
+         break;
+       case '3':
+         simple_only = 1;
+         incompat++;
+         break;
+       case 'i':
+         finalwrite = 1;
+         break;
+       case 'm':
+         merge = 1;
+         break;
+       case 'X':
+         overlap_only = 1;
+         /* Falls through */
+       case 'E':
+         flagging = 1;
+         /* Falls through */
+       case 'e':
+         incompat++;
+         break;
+       case 'v':
+         fprintf (stderr, "GNU diff3 version %s\n", version_string);
+         break;
+       case 'L':
+         /* Handle up to three -L options.  */
+         if (tag_count < 3)
+           {
+             tag_strings[tag_count++] = optarg;
+             break;
+           }
+         /* Falls through */
+       default:
+         usage ();
+         /* NOTREACHED */
+       }
+    }
+
+  edscript = incompat & ~merge;  /* -AeExX3 without -m implies ed script.  */
+  show_2nd |= ~incompat & merge;  /* -m without -AeExX3 implies -A.  */
+  flagging |= ~incompat & merge;
+
+  if (incompat > 1  /* Ensure at most one of -AeExX3.  */
+      || finalwrite & merge /* -i -m would rewrite input file.  */
+      || (tag_count && ! flagging) /* -L requires one of -AEX.  */
+      || argc - optind != 3)
+    usage ();
+
+  file = &argv[optind];
+
+  for (i = tag_count; i < 3; i++)
+    tag_strings[i] = file[i];
+
+  /* Always compare file1 to file2, even if file2 is "-".
+     This is needed for -mAeExX3.  Using the file0 as
+     the common file would produce wrong results, because if the
+     file0-file1 diffs didn't line up with the file0-file2 diffs
+     (which is entirely possible since we don't use diff's -n option),
+     diff3 might report phantom changes from file1 to file2.  */
+
+  if (strcmp (file[2], "-") == 0)
+    {
+      /* Sigh.  We've got standard input as the last arg.  We can't
+        call diff twice on stdin.  Use the middle arg as the common
+        file instead.  */
+      if (strcmp (file[0], "-") == 0 || strcmp (file[1], "-") == 0)
+       fatal ("`-' specified for more than one input file");
+      mapping[0] = 0;
+      mapping[1] = 2;
+      mapping[2] = 1;
+    }
+  else
+    {
+      /* Normal, what you'd expect */
+      mapping[0] = 0;
+      mapping[1] = 1;
+      mapping[2] = 2;
+    }
+
+  for (i = 0; i < 3; i++)
+    rev_mapping[mapping[i]] = i;
+
+  for (i = 0; i < 3; i++)
+    if (strcmp (file[i], "-") != 0)
+      if (stat (file[i], &statb) < 0)
+       perror_with_exit (file[i]);
+      else if (S_ISDIR(statb.st_mode))
+       {
+         fprintf (stderr, "%s: %s: Is a directory\n", argv0, file[i]);
+         exit (2);
+       }
+
+
+  commonname = file[rev_mapping[FILEC]];
+  thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block);
+  if (thread1)
+    for (i = 0; i < 2; i++)
+      {
+       horizon_lines = max (horizon_lines, D_NUMLINES (thread1, i));
+       horizon_lines = max (horizon_lines, D_NUMLINES (last_block, i));
+      }
+  thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block);
+  diff3 = make_3way_diff (thread0, thread1);
+  if (edscript)
+    conflicts_found
+      = output_diff3_edscript (stdout, diff3, mapping, rev_mapping,
+                              tag_strings[0], tag_strings[1], tag_strings[2]);
+  else if (merge)
+    {
+      if (! freopen (file[rev_mapping[FILE0]], "r", stdin))
+       perror_with_exit (file[rev_mapping[FILE0]]);
+      conflicts_found
+       = output_diff3_merge (stdin, stdout, diff3, mapping, rev_mapping,
+                             tag_strings[0], tag_strings[1], tag_strings[2]);
+      if (ferror (stdin))
+       fatal ("read error");
+    }
+  else
+    {
+      output_diff3 (stdout, diff3, mapping, rev_mapping);
+      conflicts_found = 0;
+    }
+
+  if (ferror (stdout) || fclose (stdout) != 0)
+    fatal ("write error");
+  exit (conflicts_found);
+  return conflicts_found;
+}
+
+/*
+ * Explain, patiently and kindly, how to use this program.  Then exit.
+ */
+static void
+usage ()
+{
+  fprintf (stderr, "\
+Usage: %s [options] my-file older-file your-file\n\
+Options:\n\
+       [-exAEX3v] [-i|-m] [-L label1 [-L label2 [-L label3]]] [--text] [--ed]\n\
+       [--merge] [--show-all] [--show-overlap] [--overlap-only] [--easy-only]\n\
+       [--label=label1 [--label=label2 [--label=label3]]] [--version]\n\
+       Only one of [exAEX3] is allowed\n", argv0);
+  exit (2);
+}
+\f
+/*
+ * Routines that combine the two diffs together into one.  The
+ * algorithm used follows:
+ *
+ *   File2 is shared in common between the two diffs.
+ *   Diff02 is the diff between 0 and 2.
+ *   Diff12 is the diff between 1 and 2.
+ *
+ *     1) Find the range for the first block in File2.
+ *         a) Take the lowest of the two ranges (in File2) in the two
+ *            current blocks (one from each diff) as being the low
+ *            water mark.  Assign the upper end of this block as
+ *            being the high water mark and move the current block up
+ *            one.  Mark the block just moved over as to be used.
+ *         b) Check the next block in the diff that the high water
+ *            mark is *not* from.
+ *
+ *            *If* the high water mark is above
+ *            the low end of the range in that block,
+ *
+ *                mark that block as to be used and move the current
+ *                block up.  Set the high water mark to the max of
+ *                the high end of this block and the current.  Repeat b.
+ *
+ *      2) Find the corresponding ranges in File0 (from the blocks
+ *         in diff02; line per line outside of diffs) and in File1.
+ *         Create a diff3_block, reserving space as indicated by the ranges.
+ *
+ *      3) Copy all of the pointers for file2 in.  At least for now,
+ *         do bcmp's between corresponding strings in the two diffs.
+ *
+ *      4) Copy all of the pointers for file0 and 1 in.  Get what you
+ *         need from file2 (when there isn't a diff block, it's
+ *         identical to file2 within the range between diff blocks).
+ *
+ *      5) If the diff blocks you used came from only one of the two
+ *         strings of diffs, then that file (i.e. the one other than
+ *         the common file in that diff) is the odd person out.  If you used
+ *         diff blocks from both sets, check to see if files 0 and 1 match:
+ *
+ *             Same number of lines?  If so, do a set of bcmp's (if a
+ *         bcmp matches; copy the pointer over; it'll be easier later
+ *         if you have to do any compares).  If they match, 0 & 1 are
+ *         the same.  If not, all three different.
+ *
+ *   Then you do it again, until you run out of blocks.
+ *
+ */
+
+/*
+ * This routine makes a three way diff (chain of diff3_block's) from two
+ * two way diffs (chains of diff_block's).  It is assumed that each of
+ * the two diffs passed are onto the same file (i.e. that each of the
+ * diffs were made "to" the same file).  The three way diff pointer
+ * returned will have numbering FILE0--the other file in diff02,
+ * FILE1--the other file in diff12, and FILEC--the common file.
+ */
+static struct diff3_block *
+make_3way_diff (thread0, thread1)
+     struct diff_block *thread0, *thread1;
+{
+/*
+ * This routine works on the two diffs passed to it as threads.
+ * Thread number 0 is diff02, thread number 1 is diff12.  The USING
+ * array is set to the base of the list of blocks to be used to
+ * construct each block of the three way diff; if no blocks from a
+ * particular thread are to be used, that element of the using array
+ * is set to 0.  The elements LAST_USING array are set to the last
+ * elements on each of the using lists.
+ *
+ * The HIGH_WATER_MARK is set to the highest line number in the common file
+ * described in any of the diffs in either of the USING lists.  The
+ * HIGH_WATER_THREAD names the thread.  Similarly the BASE_WATER_MARK
+ * and BASE_WATER_THREAD describe the lowest line number in the common file
+ * described in any of the diffs in either of the USING lists.  The
+ * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was
+ * taken.
+ *
+ * The HIGH_WATER_DIFF should always be equal to LAST_USING
+ * [HIGH_WATER_THREAD].  The OTHER_DIFF is the next diff to check for
+ * higher water, and should always be equal to
+ * CURRENT[HIGH_WATER_THREAD ^ 0x1].  The OTHER_THREAD is the thread
+ * in which the OTHER_DIFF is, and hence should always be equal to
+ * HIGH_WATER_THREAD ^ 0x1.
+ *
+ * The variable LAST_DIFF is kept set to the last diff block produced
+ * by this routine, for line correspondence purposes between that diff
+ * and the one currently being worked on.  It is initialized to
+ * ZERO_DIFF before any blocks have been created.
+ */
+
+  struct diff_block
+    *using[2],
+    *last_using[2],
+    *current[2];
+
+  int
+    high_water_mark;
+
+  int
+    high_water_thread,
+    base_water_thread,
+    other_thread;
+
+  struct diff_block
+    *high_water_diff,
+    *other_diff;
+
+  struct diff3_block
+    *result,
+    *tmpblock,
+    **result_end,
+    *last_diff3;
+
+  static struct diff3_block zero_diff3 = {
+      ERROR,
+      { {0, 0}, {0, 0}, {0, 0} },
+      { (char **) 0, (char **) 0, (char **) 0 },
+      { (int *) 0, (int *) 0, (int *) 0 },
+      (struct diff3_block *) 0
+      };
+
+  /* Initialization */
+  result = 0;
+  result_end = &result;
+  current[0] = thread0; current[1] = thread1;
+  last_diff3 = &zero_diff3;
+
+  /* Sniff up the threads until we reach the end */
+
+  while (current[0] || current[1])
+    {
+      using[0] = using[1] = last_using[0] = last_using[1] =
+       (struct diff_block *) 0;
+
+      /* Setup low and high water threads, diffs, and marks.  */
+      if (!current[0])
+       base_water_thread = 1;
+      else if (!current[1])
+       base_water_thread = 0;
+      else
+       base_water_thread =
+         (D_LOWLINE (current[0], FC) > D_LOWLINE (current[1], FC));
+
+      high_water_thread = base_water_thread;
+
+      high_water_diff = current[high_water_thread];
+
+#if 0
+      /* low and high waters start off same diff */
+      base_water_mark = D_LOWLINE (high_water_diff, FC);
+#endif
+
+      high_water_mark = D_HIGHLINE (high_water_diff, FC);
+
+      /* Make the diff you just got info from into the using class */
+      using[high_water_thread]
+       = last_using[high_water_thread]
+       = high_water_diff;
+      current[high_water_thread] = high_water_diff->next;
+      last_using[high_water_thread]->next
+       = (struct diff_block *) 0;
+
+      /* And mark the other diff */
+      other_thread = high_water_thread ^ 0x1;
+      other_diff = current[other_thread];
+
+      /* Shuffle up the ladder, checking the other diff to see if it
+        needs to be incorporated.  */
+      while (other_diff
+            && D_LOWLINE (other_diff, FC) <= high_water_mark + 1)
+       {
+
+         /* Incorporate this diff into the using list.  Note that
+            this doesn't take it off the current list */
+         if (using[other_thread])
+           last_using[other_thread]->next = other_diff;
+         else
+           using[other_thread] = other_diff;
+         last_using[other_thread] = other_diff;
+
+         /* Take it off the current list.  Note that this following
+            code assumes that other_diff enters it equal to
+            current[high_water_thread ^ 0x1] */
+         current[other_thread]
+           = current[other_thread]->next;
+         other_diff->next
+           = (struct diff_block *) 0;
+
+         /* Set the high_water stuff
+            If this comparison is equal, then this is the last pass
+            through this loop; since diff blocks within a given
+            thread cannot overlap, the high_water_mark will be
+            *below* the range_start of either of the next diffs.  */
+
+         if (high_water_mark < D_HIGHLINE (other_diff, FC))
+           {
+             high_water_thread ^= 1;
+             high_water_diff = other_diff;
+             high_water_mark = D_HIGHLINE (other_diff, FC);
+           }
+
+         /* Set the other diff */
+         other_thread = high_water_thread ^ 0x1;
+         other_diff = current[other_thread];
+       }
+
+      /* The using lists contain a list of all of the blocks to be
+        included in this diff3_block.  Create it.  */
+
+      tmpblock = using_to_diff3_block (using, last_using,
+                                      base_water_thread, high_water_thread,
+                                      last_diff3);
+
+      if (!tmpblock)
+       fatal ("internal error: screwup in format of diff blocks");
+
+      /* Put it on the list.  */
+      *result_end = tmpblock;
+      result_end = &tmpblock->next;
+
+      /* Set up corresponding lines correctly.  */
+      last_diff3 = tmpblock;
+    }
+  return result;
+}
+
+/*
+ * using_to_diff3_block:
+ *   This routine takes two lists of blocks (from two separate diff
+ * threads) and puts them together into one diff3 block.
+ * It then returns a pointer to this diff3 block or 0 for failure.
+ *
+ * All arguments besides using are for the convenience of the routine;
+ * they could be derived from the using array.
+ * LAST_USING is a pair of pointers to the last blocks in the using
+ * structure.
+ * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest
+ * and highest line numbers for File0.
+ * last_diff3 contains the last diff produced in the calling routine.
+ * This is used for lines mappings which would still be identical to
+ * the state that diff ended in.
+ *
+ * A distinction should be made in this routine between the two diffs
+ * that are part of a normal two diff block, and the three diffs that
+ * are part of a diff3_block.
+ */
+static struct diff3_block *
+using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff3)
+     struct diff_block
+       *using[2],
+       *last_using[2];
+     int low_thread, high_thread;
+     struct diff3_block *last_diff3;
+{
+  int low[2], high[2];
+  struct diff3_block *result;
+  struct diff_block *ptr;
+  int d, i;
+
+  /* Find the range in the common file.  */
+  int lowc = D_LOWLINE (using[low_thread], FC);
+  int highc = D_HIGHLINE (last_using[high_thread], FC);
+
+  /* Find the ranges in the other files.
+     If using[d] is null, that means that the file to which that diff
+     refers is equivalent to the common file over this range.  */
+
+  for (d = 0; d < 2; d++)
+    if (using[d])
+      {
+       low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc);
+       high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc);
+      }
+    else
+      {
+       low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc);
+       high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc);
+      }
+
+  /* Create a block with the appropriate sizes */
+  result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc);
+
+  /* Copy information for the common file.
+     Return with a zero if any of the compares failed.  */
+
+  for (d = 0; d < 2; d++)
+    for (ptr = using[d]; ptr; ptr = D_NEXT (ptr))
+      {
+       int result_offset = D_LOWLINE (ptr, FC) - lowc;
+
+       if (!copy_stringlist (D_LINEARRAY (ptr, FC),
+                             D_LENARRAY (ptr, FC),
+                             D_LINEARRAY (result, FILEC) + result_offset,
+                             D_LENARRAY (result, FILEC) + result_offset,
+                             D_NUMLINES (ptr, FC)))
+         return 0;
+      }
+
+  /* Copy information for file d.  First deal with anything that might be
+     before the first diff.  */
+
+  for (d = 0; d < 2; d++)
+    {
+      struct diff_block *u = using[d];
+      int lo = low[d], hi = high[d];
+
+      for (i = 0;
+          i + lo < (u ? D_LOWLINE (u, FO) : hi + 1);
+          i++)
+       {
+         D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i);
+         D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i);
+       }
+
+      for (ptr = u; ptr; ptr = D_NEXT (ptr))
+       {
+         int result_offset = D_LOWLINE (ptr, FO) - lo;
+         int linec;
+
+         if (!copy_stringlist (D_LINEARRAY (ptr, FO),
+                               D_LENARRAY (ptr, FO),
+                               D_LINEARRAY (result, FILE0 + d) + result_offset,
+                               D_LENARRAY (result, FILE0 + d) + result_offset,
+                               D_NUMLINES (ptr, FO)))
+           return 0;
+
+         /* Catch the lines between here and the next diff */
+         linec = D_HIGHLINE (ptr, FC) + 1 - lowc;
+         for (i = D_HIGHLINE (ptr, FO) + 1 - lo;
+              i < (D_NEXT (ptr) ? D_LOWLINE (D_NEXT (ptr), FO) : hi + 1) - lo;
+              i++)
+           {
+             D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec);
+             D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec);
+             linec++;
+           }
+       }
+    }
+
+  /* Set correspond */
+  if (!using[0])
+    D3_TYPE (result) = DIFF_2ND;
+  else if (!using[1])
+    D3_TYPE (result) = DIFF_1ST;
+  else
+    {
+      int nl0 = D_NUMLINES (result, FILE0);
+      int nl1 = D_NUMLINES (result, FILE1);
+
+      if (nl0 != nl1
+         || !compare_line_list (D_LINEARRAY (result, FILE0),
+                                D_LENARRAY (result, FILE0),
+                                D_LINEARRAY (result, FILE1),
+                                D_LENARRAY (result, FILE1),
+                                nl0))
+       D3_TYPE (result) = DIFF_ALL;
+      else
+       D3_TYPE (result) = DIFF_3RD;
+    }
+
+  return result;
+}
+
+/*
+ * This routine copies pointers from a list of strings to a different list
+ * of strings.  If a spot in the second list is already filled, it
+ * makes sure that it is filled with the same string; if not it
+ * returns 0, the copy incomplete.
+ * Upon successful completion of the copy, it returns 1.
+ */
+static int
+copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum)
+     char *fromptrs[], *toptrs[];
+     int *fromlengths, *tolengths;
+     int copynum;
+{
+  register char
+    **f = fromptrs,
+    **t = toptrs;
+  register int
+    *fl = fromlengths,
+    *tl = tolengths;
+
+  while (copynum--)
+    {
+      if (*t)
+       { if (*fl != *tl || bcmp (*f, *t, *fl)) return 0; }
+      else
+       { *t = *f ; *tl = *fl; }
+
+      t++; f++; tl++; fl++;
+    }
+  return 1;
+}
+
+/*
+ * Create a diff3_block, with ranges as specified in the arguments.
+ * Allocate the arrays for the various pointers (and zero them) based
+ * on the arguments passed.  Return the block as a result.
+ */
+static struct diff3_block *
+create_diff3_block (low0, high0, low1, high1, low2, high2)
+     register int low0, high0, low1, high1, low2, high2;
+{
+  struct diff3_block *result = ALLOCATE (1, struct diff3_block);
+  int numlines;
+
+  D3_TYPE (result) = ERROR;
+  D_NEXT (result) = 0;
+
+  /* Assign ranges */
+  D_LOWLINE (result, FILE0) = low0;
+  D_HIGHLINE (result, FILE0) = high0;
+  D_LOWLINE (result, FILE1) = low1;
+  D_HIGHLINE (result, FILE1) = high1;
+  D_LOWLINE (result, FILE2) = low2;
+  D_HIGHLINE (result, FILE2) = high2;
+
+  /* Allocate and zero space */
+  numlines = D_NUMLINES (result, FILE0);
+  if (numlines)
+    {
+      D_LINEARRAY (result, FILE0) = ALLOCATE (numlines, char *);
+      D_LENARRAY (result, FILE0) = ALLOCATE (numlines, int);
+      bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *)));
+      bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (int)));
+    }
+  else
+    {
+      D_LINEARRAY (result, FILE0) = (char **) 0;
+      D_LENARRAY (result, FILE0) = (int *) 0;
+    }
+
+  numlines = D_NUMLINES (result, FILE1);
+  if (numlines)
+    {
+      D_LINEARRAY (result, FILE1) = ALLOCATE (numlines, char *);
+      D_LENARRAY (result, FILE1) = ALLOCATE (numlines, int);
+      bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *)));
+      bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (int)));
+    }
+  else
+    {
+      D_LINEARRAY (result, FILE1) = (char **) 0;
+      D_LENARRAY (result, FILE1) = (int *) 0;
+    }
+
+  numlines = D_NUMLINES (result, FILE2);
+  if (numlines)
+    {
+      D_LINEARRAY (result, FILE2) = ALLOCATE (numlines, char *);
+      D_LENARRAY (result, FILE2) = ALLOCATE (numlines, int);
+      bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *)));
+      bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (int)));
+    }
+  else
+    {
+      D_LINEARRAY (result, FILE2) = (char **) 0;
+      D_LENARRAY (result, FILE2) = (int *) 0;
+    }
+
+  /* Return */
+  return result;
+}
+
+/*
+ * Compare two lists of lines of text.
+ * Return 1 if they are equivalent, 0 if not.
+ */
+static int
+compare_line_list (list1, lengths1, list2, lengths2, nl)
+     char *list1[], *list2[];
+     int *lengths1, *lengths2;
+     int nl;
+{
+  char
+    **l1 = list1,
+    **l2 = list2;
+  int
+    *lgths1 = lengths1,
+    *lgths2 = lengths2;
+
+  while (nl--)
+    if (!*l1 || !*l2 || *lgths1 != *lgths2++
+       || bcmp (*l1++, *l2++, *lgths1++))
+      return 0;
+  return 1;
+}
+\f
+/*
+ * Routines to input and parse two way diffs.
+ */
+
+extern char **environ;
+
+#define        DIFF_CHUNK_SIZE 10000
+
+static struct diff_block *
+process_diff (filea, fileb, last_block)
+     char *filea, *fileb;
+     struct diff_block **last_block;
+{
+  char *diff_contents;
+  char *diff_limit;
+  char *scan_diff;
+  enum diff_type dt;
+  int i;
+  struct diff_block *block_list, **block_list_end, *bptr;
+
+  diff_limit = read_diff (filea, fileb, &diff_contents);
+  scan_diff = diff_contents;
+  block_list_end = &block_list;
+
+  while (scan_diff < diff_limit)
+    {
+      bptr = ALLOCATE (1, struct diff_block);
+      bptr->lines[0] = bptr->lines[1] = (char **) 0;
+      bptr->lengths[0] = bptr->lengths[1] = (int *) 0;
+
+      dt = process_diff_control (&scan_diff, bptr);
+      if (dt == ERROR || *scan_diff != '\n')
+       {
+         fprintf (stderr, "%s: diff error: ", argv0);
+         do
+           {
+             putc (*scan_diff, stderr);
+           }
+         while (*scan_diff++ != '\n');
+         exit (2);
+       }
+      scan_diff++;
+
+      /* Force appropriate ranges to be null, if necessary */
+      switch (dt)
+       {
+       case ADD:
+         bptr->ranges[0][0]++;
+         break;
+       case DELETE:
+         bptr->ranges[1][0]++;
+         break;
+       case CHANGE:
+         break;
+       default:
+         fatal ("internal error: invalid diff type in process_diff");
+         break;
+       }
+
+      /* Allocate space for the pointers for the lines from filea, and
+        parcel them out among these pointers */
+      if (dt != ADD)
+       {
+         int numlines = D_NUMLINES (bptr, 0);
+         bptr->lines[0] = ALLOCATE (numlines, char *);
+         bptr->lengths[0] = ALLOCATE (numlines, int);
+         for (i = 0; i < numlines; i++)
+           scan_diff = scan_diff_line (scan_diff,
+                                       &(bptr->lines[0][i]),
+                                       &(bptr->lengths[0][i]),
+                                       diff_limit,
+                                       '<');
+       }
+
+      /* Get past the separator for changes */
+      if (dt == CHANGE)
+       {
+         if (strncmp (scan_diff, "---\n", 4))
+           fatal ("invalid diff format; invalid change separator");
+         scan_diff += 4;
+       }
+
+      /* Allocate space for the pointers for the lines from fileb, and
+        parcel them out among these pointers */
+      if (dt != DELETE)
+       {
+         int numlines = D_NUMLINES (bptr, 1);
+         bptr->lines[1] = ALLOCATE (numlines, char *);
+         bptr->lengths[1] = ALLOCATE (numlines, int);
+         for (i = 0; i < numlines; i++)
+           scan_diff = scan_diff_line (scan_diff,
+                                       &(bptr->lines[1][i]),
+                                       &(bptr->lengths[1][i]),
+                                       diff_limit,
+                                       '>');
+       }
+
+      /* Place this block on the blocklist.  */
+      *block_list_end = bptr;
+      block_list_end = &bptr->next;
+    }
+
+  *block_list_end = 0;
+  *last_block = bptr;
+  return block_list;
+}
+
+/*
+ * This routine will parse a normal format diff control string.  It
+ * returns the type of the diff (ERROR if the format is bad).  All of
+ * the other important information is filled into to the structure
+ * pointed to by db, and the string pointer (whose location is passed
+ * to this routine) is updated to point beyond the end of the string
+ * parsed.  Note that only the ranges in the diff_block will be set by
+ * this routine.
+ *
+ * If some specific pair of numbers has been reduced to a single
+ * number, then both corresponding numbers in the diff block are set
+ * to that number.  In general these numbers are interpetted as ranges
+ * inclusive, unless being used by the ADD or DELETE commands.  It is
+ * assumed that these will be special cased in a superior routine.
+ */
+
+static enum diff_type
+process_diff_control (string, db)
+     char **string;
+     struct diff_block *db;
+{
+  char *s = *string;
+  int holdnum;
+  enum diff_type type;
+
+/* These macros are defined here because they can use variables
+   defined in this function.  Don't try this at home kids, we're
+   trained professionals!
+
+   Also note that SKIPWHITE only recognizes tabs and spaces, and
+   that READNUM can only read positive, integral numbers */
+
+#define        SKIPWHITE(s)    { while (*s == ' ' || *s == '\t') s++; }
+#define        READNUM(s, num) \
+       { if (!isdigit (*s)) return ERROR; holdnum = 0; \
+         do { holdnum = (*s++ - '0' + holdnum * 10); } \
+         while (isdigit (*s)); (num) = holdnum; }
+
+  /* Read first set of digits */
+  SKIPWHITE (s);
+  READNUM (s, db->ranges[0][START]);
+
+  /* Was that the only digit? */
+  SKIPWHITE (s);
+  if (*s == ',')
+    {
+      /* Get the next digit */
+      s++;
+      READNUM (s, db->ranges[0][END]);
+    }
+  else
+    db->ranges[0][END] = db->ranges[0][START];
+
+  /* Get the letter */
+  SKIPWHITE (s);
+  switch (*s)
+    {
+    case 'a':
+      type = ADD;
+      break;
+    case 'c':
+      type = CHANGE;
+      break;
+    case 'd':
+      type = DELETE;
+      break;
+    default:
+      return ERROR;                    /* Bad format */
+    }
+  s++;                         /* Past letter */
+
+  /* Read second set of digits */
+  SKIPWHITE (s);
+  READNUM (s, db->ranges[1][START]);
+
+  /* Was that the only digit? */
+  SKIPWHITE (s);
+  if (*s == ',')
+    {
+      /* Get the next digit */
+      s++;
+      READNUM (s, db->ranges[1][END]);
+      SKIPWHITE (s);           /* To move to end */
+    }
+  else
+    db->ranges[1][END] = db->ranges[1][START];
+
+  *string = s;
+  return type;
+}
+
+static char *
+read_diff (filea, fileb, output_placement)
+     char *filea, *fileb;
+     char **output_placement;
+{
+  char *argv[7];
+  char horizon_arg[256];
+  char **ap;
+  int fds[2];
+  char *diff_result;
+  int current_chunk_size;
+  int bytes;
+  int total;
+  int pid, w;
+  int wstatus;
+
+  ap = argv;
+  *ap++ = diff_program;
+  if (always_text)
+    *ap++ = "-a";
+  sprintf (horizon_arg, "--horizon-lines=%d", horizon_lines);
+  *ap++ = horizon_arg;
+  *ap++ = "--";
+  *ap++ = filea;
+  *ap++ = fileb;
+  *ap = (char *) 0;
+
+  if (pipe (fds) < 0)
+    perror_with_exit ("pipe failed");
+
+  pid = vfork ();
+  if (pid == 0)
+    {
+      /* Child */
+      close (fds[0]);
+      if (fds[1] != fileno (stdout))
+       {
+         dup2 (fds[1], fileno (stdout));
+         close (fds[1]);
+       }
+      execve (diff_program, argv, environ);
+      /* Avoid stdio, because the parent process's buffers are inherited.  */
+      write (fileno (stderr), diff_program, strlen (diff_program));
+      write (fileno (stderr), ": not found\n", 12);
+      _exit (2);
+    }
+
+  if (pid == -1)
+    perror_with_exit ("fork failed");
+
+  close (fds[1]);              /* Prevent erroneous lack of EOF */
+  current_chunk_size = DIFF_CHUNK_SIZE;
+  diff_result = (char *) xmalloc (current_chunk_size);
+  total = 0;
+  do {
+    bytes = myread (fds[0],
+                   diff_result + total,
+                   current_chunk_size - total);
+    total += bytes;
+    if (total == current_chunk_size)
+      diff_result = (char *) xrealloc (diff_result, (current_chunk_size *= 2));
+  } while (bytes);
+
+  if (total != 0 && diff_result[total-1] != '\n')
+    fatal ("invalid diff format; incomplete last line");
+
+  *output_placement = diff_result;
+
+  do
+    if ((w = wait (&wstatus)) == -1)
+      perror_with_exit ("wait failed");
+  while (w != pid);
+
+  if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2))
+    fatal ("subsidiary diff failed");
+
+  return diff_result + total;
+}
+
+
+/*
+ * Scan a regular diff line (consisting of > or <, followed by a
+ * space, followed by text (including nulls) up to a newline.
+ *
+ * This next routine began life as a macro and many parameters in it
+ * are used as call-by-reference values.
+ */
+static char *
+scan_diff_line (scan_ptr, set_start, set_length, limit, firstchar)
+     char *scan_ptr, **set_start;
+     int *set_length;
+     char *limit;
+     char firstchar;
+{
+  char *line_ptr;
+
+  if (!(scan_ptr[0] == (firstchar)
+       && scan_ptr[1] == ' '))
+    fatal ("invalid diff format; incorrect leading line chars");
+
+  *set_start = line_ptr = scan_ptr + 2;
+  while (*line_ptr++ != '\n')
+    ;
+
+  /* Include newline if the original line ended in a newline,
+     or if an edit script is being generated.
+     Copy any missing newline message to stderr if an edit script is being
+     generated, because edit scripts cannot handle missing newlines.
+     Return the beginning of the next line.  */
+  *set_length = line_ptr - *set_start;
+  if (line_ptr < limit && *line_ptr == '\\')
+    {
+      if (edscript)
+       fprintf (stderr, "%s:", argv0);
+      else
+       --*set_length;
+      line_ptr++;
+      do
+       {
+         if (edscript)
+           putc (*line_ptr, stderr);
+       }
+      while (*line_ptr++ != '\n');
+    }
+
+  return line_ptr;
+}
+
+/*
+ * This routine outputs a three way diff passed as a list of
+ * diff3_block's.
+ * The argument MAPPING is indexed by external file number (in the
+ * argument list) and contains the internal file number (from the
+ * diff passed).  This is important because the user expects his
+ * outputs in terms of the argument list number, and the diff passed
+ * may have been done slightly differently (if the last argument
+ * was "-", for example).
+ * REV_MAPPING is the inverse of MAPPING.
+ */
+static void
+output_diff3 (outputfile, diff, mapping, rev_mapping)
+     FILE *outputfile;
+     struct diff3_block *diff;
+     int mapping[3], rev_mapping[3];
+{
+  int i;
+  int oddoneout;
+  char *cp;
+  struct diff3_block *ptr;
+  int line;
+  int length;
+  int dontprint;
+  static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
+
+  for (ptr = diff; ptr; ptr = D_NEXT (ptr))
+    {
+      char x[2];
+
+      switch (ptr->correspond)
+       {
+       case DIFF_ALL:
+         x[0] = '\0';
+         dontprint = 3;        /* Print them all */
+         oddoneout = 3;        /* Nobody's odder than anyone else */
+         break;
+       case DIFF_1ST:
+       case DIFF_2ND:
+       case DIFF_3RD:
+         oddoneout = rev_mapping[(int) ptr->correspond - (int) DIFF_1ST];
+
+         x[0] = oddoneout + '1';
+         x[1] = '\0';
+         dontprint = oddoneout==0;
+         break;
+       default:
+         fatal ("internal error: invalid diff type passed to output");
+       }
+      fprintf (outputfile, "====%s\n", x);
+
+      /* Go 0, 2, 1 if the first and third outputs are equivalent.  */
+      for (i = 0; i < 3;
+          i = (oddoneout == 1 ? skew_increment[i] : i + 1))
+       {
+         int realfile = mapping[i];
+         int
+           lowt = D_LOWLINE (ptr, realfile),
+           hight = D_HIGHLINE (ptr, realfile);
+
+         fprintf (outputfile, "%d:", i + 1);
+         switch (lowt - hight)
+           {
+           case 1:
+             fprintf (outputfile, "%da\n", lowt - 1);
+             break;
+           case 0:
+             fprintf (outputfile, "%dc\n", lowt);
+             break;
+           default:
+             fprintf (outputfile, "%d,%dc\n", lowt, hight);
+             break;
+           }
+
+         if (i == dontprint) continue;
+
+         for (line = 0; line < hight - lowt + 1; line++)
+           {
+             fprintf (outputfile, "  ");
+             cp = D_RELNUM (ptr, realfile, line);
+             length = D_RELLEN (ptr, realfile, line);
+             fwrite (cp, sizeof (char), length, outputfile);
+           }
+         if (line != 0 && cp[length - 1] != '\n')
+           fprintf (outputfile, "\n\\ No newline at end of file\n");
+       }
+    }
+}
+
+
+/*
+ * Output to OUTPUTFILE the lines of B taken from FILENUM.
+ * Double any initial '.'s; yield nonzero if any initial '.'s were doubled.
+ */
+static int
+dotlines (outputfile, b, filenum)
+     FILE *outputfile;
+     struct diff3_block *b;
+     int filenum;
+{
+  int i;
+  int leading_dot = 0;
+
+  for (i = 0;
+       i < D_NUMLINES (b, filenum);
+       i++)
+    {
+      char *line = D_RELNUM (b, filenum, i);
+      if (line[0] == '.')
+       {
+         leading_dot = 1;
+         fprintf (outputfile, ".");
+       }
+      fwrite (line, sizeof (char),
+             D_RELLEN (b, filenum, i), outputfile);
+    }
+
+  return leading_dot;
+}
+
+/*
+ * Output to OUTPUTFILE a '.' line.  If LEADING_DOT is nonzero,
+ * also output a command that removes initial '.'s
+ * starting with line START and continuing for NUM lines.
+ */
+static void
+undotlines (outputfile, leading_dot, start, num)
+     FILE *outputfile;
+     int leading_dot, start, num;
+{
+  fprintf (outputfile, ".\n");
+  if (leading_dot)
+    if (num == 1)
+      fprintf (outputfile, "%ds/^\\.//\n", start);
+    else
+      fprintf (outputfile, "%d,%ds/^\\.//\n", start, start + num - 1);
+}
+
+/*
+ * This routine outputs a diff3 set of blocks as an ed script.  This
+ * script applies the changes between file's 2 & 3 to file 1.  It
+ * takes the precise format of the ed script to be output from global
+ * variables set during options processing.  Note that it does
+ * destructive things to the set of diff3 blocks it is passed; it
+ * reverses their order (this gets around the problems involved with
+ * changing line numbers in an ed script).
+ *
+ * Note that this routine has the same problem of mapping as the last
+ * one did; the variable MAPPING maps from file number according to
+ * the argument list to file number according to the diff passed.  All
+ * files listed below are in terms of the argument list.
+ * REV_MAPPING is the inverse of MAPPING.
+ *
+ * The arguments FILE0, FILE1 and FILE2 are the strings to print
+ * as the names of the three files.  These may be the actual names,
+ * or may be the arguments specified with -L.
+ *
+ * Returns 1 if conflicts were found.
+ */
+
+static int
+output_diff3_edscript (outputfile, diff, mapping, rev_mapping,
+                      file0, file1, file2)
+     FILE *outputfile;
+     struct diff3_block *diff;
+     int mapping[3], rev_mapping[3];
+     char *file0, *file1, *file2;
+{
+  int leading_dot;
+  int conflicts_found = 0, conflict;
+  struct diff3_block *b;
+
+  for (b = reverse_diff3_blocklist (diff); b; b = b->next)
+    {
+      /* Must do mapping correctly.  */
+      enum diff_type type
+       = ((b->correspond == DIFF_ALL) ?
+          DIFF_ALL :
+          ((enum diff_type)
+           (((int) DIFF_1ST)
+            + rev_mapping[(int) b->correspond - (int) DIFF_1ST])));
+
+      /* If we aren't supposed to do this output block, skip it.  */
+      switch (type)
+       {
+       default: continue;
+       case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break;
+       case DIFF_3RD: if (overlap_only) continue; conflict = 0; break;
+       case DIFF_ALL: if (simple_only) continue; conflict = flagging; break;
+       }
+
+      if (conflict)
+       {
+         conflicts_found = 1;
+
+
+         /* Mark end of conflict.  */
+
+         fprintf (outputfile, "%da\n", D_HIGHLINE (b, mapping[FILE0]));
+         leading_dot = 0;
+         if (type == DIFF_ALL)
+           {
+             if (show_2nd)
+               {
+                 /* Append lines from FILE1.  */
+                 fprintf (outputfile, "||||||| %s\n", file1);
+                 leading_dot = dotlines (outputfile, b, mapping[FILE1]);
+               }
+             /* Append lines from FILE2.  */
+             fprintf (outputfile, "=======\n");
+             leading_dot |= dotlines (outputfile, b, mapping[FILE2]);
+           }
+         fprintf (outputfile, ">>>>>>> %s\n", file2);
+         undotlines (outputfile, leading_dot,
+                     D_HIGHLINE (b, mapping[FILE0]) + 2,
+                     (D_NUMLINES (b, mapping[FILE1])
+                      + D_NUMLINES (b, mapping[FILE2]) + 1));
+
+
+         /* Mark start of conflict.  */
+
+         fprintf (outputfile, "%da\n<<<<<<< %s\n",
+                  D_LOWLINE (b, mapping[FILE0]) - 1,
+                  type == DIFF_ALL ? file0 : file1);
+         leading_dot = 0;
+         if (type == DIFF_2ND)
+           {
+             /* Prepend lines from FILE1.  */
+             leading_dot = dotlines (outputfile, b, mapping[FILE1]);
+             fprintf (outputfile, "=======\n");
+           }
+         undotlines (outputfile, leading_dot,
+                     D_LOWLINE (b, mapping[FILE0]) + 1,
+                     D_NUMLINES (b, mapping[FILE1]));
+       }
+      else if (D_NUMLINES (b, mapping[FILE2]) == 0)
+       /* Write out a delete */
+       {
+         if (D_NUMLINES (b, mapping[FILE0]) == 1)
+           fprintf (outputfile, "%dd\n",
+                    D_LOWLINE (b, mapping[FILE0]));
+         else
+           fprintf (outputfile, "%d,%dd\n",
+                    D_LOWLINE (b, mapping[FILE0]),
+                    D_HIGHLINE (b, mapping[FILE0]));
+       }
+      else
+       /* Write out an add or change */
+       {
+         switch (D_NUMLINES (b, mapping[FILE0]))
+           {
+           case 0:
+             fprintf (outputfile, "%da\n",
+                      D_HIGHLINE (b, mapping[FILE0]));
+             break;
+           case 1:
+             fprintf (outputfile, "%dc\n",
+                      D_HIGHLINE (b, mapping[FILE0]));
+             break;
+           default:
+             fprintf (outputfile, "%d,%dc\n",
+                      D_LOWLINE (b, mapping[FILE0]),
+                      D_HIGHLINE (b, mapping[FILE0]));
+             break;
+           }
+
+         undotlines (outputfile, dotlines (outputfile, b, mapping[FILE2]),
+                     D_LOWLINE (b, mapping[FILE0]),
+                     D_NUMLINES (b, mapping[FILE2]));
+       }
+    }
+  if (finalwrite) fprintf (outputfile, "w\nq\n");
+  return conflicts_found;
+}
+
+/*
+ * Read from INFILE and output to OUTPUTFILE a set of diff3_ blocks DIFF
+ * as a merged file.  This acts like 'ed file0 <[output_diff3_edscript]',
+ * except that it works even for binary data or incomplete lines.
+ *
+ * As before, MAPPING maps from arg list file number to diff file number,
+ * REV_MAPPING is its inverse,
+ * and FILE0, FILE1, and FILE2 are the names of the files.
+ *
+ * Returns 1 if conflicts were found.
+ */
+
+static int
+output_diff3_merge (infile, outputfile, diff, mapping, rev_mapping,
+                   file0, file1, file2)
+     FILE *infile, *outputfile;
+     struct diff3_block *diff;
+     int mapping[3], rev_mapping[3];
+     char *file0, *file1, *file2;
+{
+  int c, i;
+  int conflicts_found = 0, conflict;
+  struct diff3_block *b;
+  int linesread = 0;
+
+  for (b = diff; b; b = b->next)
+    {
+      /* Must do mapping correctly.  */
+      enum diff_type type
+       = ((b->correspond == DIFF_ALL) ?
+          DIFF_ALL :
+          ((enum diff_type)
+           (((int) DIFF_1ST)
+            + rev_mapping[(int) b->correspond - (int) DIFF_1ST])));
+      char *format_2nd = "<<<<<<< %s\n";
+
+      /* If we aren't supposed to do this output block, skip it.  */
+      switch (type)
+       {
+       default: continue;
+       case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break;
+       case DIFF_3RD: if (overlap_only) continue; conflict = 0; break;
+       case DIFF_ALL: if (simple_only) continue; conflict = flagging;
+         format_2nd = "||||||| %s\n";
+         break;
+       }
+
+      /* Copy I lines from file 0.  */
+      i = D_LOWLINE (b, FILE0) - linesread - 1;
+      linesread += i;
+      while (0 <= --i)
+       do
+         {
+           c = getc (infile);
+           if (c == EOF)
+             if (ferror (infile))
+               perror_with_exit ("input file");
+             else if (feof (infile))
+               fatal ("input file shrank");
+           putc (c, outputfile);
+         }
+       while (c != '\n');
+
+      if (conflict)
+       {
+         conflicts_found = 1;
+
+         if (type == DIFF_ALL)
+           {
+             /* Put in lines from FILE0 with bracket.  */
+             fprintf (outputfile, "<<<<<<< %s\n", file0);
+             for (i = 0;
+                  i < D_NUMLINES (b, mapping[FILE0]);
+                  i++)
+               fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char),
+                       D_RELLEN (b, mapping[FILE0], i), outputfile);
+           }
+
+         if (show_2nd)
+           {
+             /* Put in lines from FILE1 with bracket.  */
+             fprintf (outputfile, format_2nd, file1);
+             for (i = 0;
+                  i < D_NUMLINES (b, mapping[FILE1]);
+                  i++)
+               fwrite (D_RELNUM (b, mapping[FILE1], i), sizeof (char),
+                       D_RELLEN (b, mapping[FILE1], i), outputfile);
+           }
+
+         fprintf (outputfile, "=======\n");
+       }
+
+      /* Put in lines from FILE2.  */
+      for (i = 0;
+          i < D_NUMLINES (b, mapping[FILE2]);
+          i++)
+       fwrite (D_RELNUM (b, mapping[FILE2], i), sizeof (char),
+               D_RELLEN (b, mapping[FILE2], i), outputfile);
+
+      if (conflict)
+       fprintf (outputfile, ">>>>>>> %s\n", file2);
+
+      /* Skip I lines in file 0.  */
+      i = D_NUMLINES (b, FILE0);
+      linesread += i;
+      while (0 <= --i)
+       while ((c = getc (infile)) != '\n')
+         if (c == EOF)
+           if (ferror (infile))
+             perror_with_exit ("input file");
+           else if (feof (infile))
+             {
+               if (i || b->next)
+                 fatal ("input file shrank");
+               return conflicts_found;
+             }
+    }
+  /* Copy rest of common file.  */
+  while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile)))
+    putc (c, outputfile);
+  return conflicts_found;
+}
+
+/*
+ * Reverse the order of the list of diff3 blocks.
+ */
+static struct diff3_block *
+reverse_diff3_blocklist (diff)
+     struct diff3_block *diff;
+{
+  register struct diff3_block *tmp, *next, *prev;
+
+  for (tmp = diff, prev = (struct diff3_block *) 0;
+       tmp; tmp = next)
+    {
+      next = tmp->next;
+      tmp->next = prev;
+      prev = tmp;
+    }
+
+  return prev;
+}
+\f
+static int
+myread (fd, ptr, size)
+     int fd, size;
+     char *ptr;
+{
+  int result = read (fd, ptr, size);
+  if (result < 0)
+    perror_with_exit ("read failed");
+  return result;
+}
+\f
+VOID *
+xmalloc (size)
+     unsigned size;
+{
+  VOID *result = (VOID *) malloc (size ? size : 1);
+  if (!result)
+    fatal ("virtual memory exhausted");
+  return result;
+}
+
+static VOID *
+xrealloc (ptr, size)
+     VOID *ptr;
+     unsigned size;
+{
+  VOID *result = (VOID *) realloc (ptr, size ? size : 1);
+  if (!result)
+    fatal ("virtual memory exhausted");
+  return result;
+}
+\f
+static void
+fatal (string)
+     char *string;
+{
+  fprintf (stderr, "%s: %s\n", argv0, string);
+  exit (2);
+}
+
+static void
+perror_with_exit (string)
+     char *string;
+{
+  int e = errno;
+  fprintf (stderr, "%s: ", argv0);
+  errno = e;
+  perror (string);
+  exit (2);
+}
diff --git a/gnu/usr.bin/diff3/getopt.c b/gnu/usr.bin/diff3/getopt.c
new file mode 100644 (file)
index 0000000..a59a013
--- /dev/null
@@ -0,0 +1,731 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+       Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+/* NOTE!!!  AIX requires this to be the first thing in the file.
+   Do not put ANYTHING before it!  */
+#if !defined (__GNUC__) && defined (_AIX)
+ #pragma alloca
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
+#include <alloca.h>
+#else
+#ifndef _AIX
+char *alloca ();
+#endif
+#endif /* alloca.h */
+#endif /* not __GNUC__ */
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#undef alloca
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#else  /* Not GNU C library.  */
+#define        __alloca        alloca
+#endif /* GNU C library.  */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+   long-named option.  Because this is not POSIX.2 compliant, it is
+   being phased out.  */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* XXX 1003.2 says this must be 1 before any call.  */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+\f
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#include <string.h>
+#define        my_index        strchr
+#define        my_bcopy(src, dst, n)   memcpy ((dst), (src), (n))
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+       return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+static void
+my_bcopy (from, to, size)
+     const char *from;
+     char *to;
+     int size;
+{
+  int i;
+  for (i = 0; i < size; i++)
+    to[i] = from[i];
+}
+#endif                         /* GNU C library.  */
+\f
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
+  char **temp = (char **) __alloca (nonopts_size);
+
+  /* Interchange the two blocks of data in ARGV.  */
+
+  my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
+  my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
+           (optind - last_nonopt) * sizeof (char *));
+  my_bcopy ((char *) temp,
+           (char *) &argv[first_nonopt + optind - last_nonopt],
+           nonopts_size);
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+\f
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns `EOF'.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  int option_index;
+
+  optarg = 0;
+
+  /* Initialize the internal data when the first call is made.
+     Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  if (optind == 0)
+    {
+      first_nonopt = last_nonopt = optind = 1;
+
+      nextchar = NULL;
+
+      /* Determine how to handle the ordering of options and nonoptions.  */
+
+      if (optstring[0] == '-')
+       {
+         ordering = RETURN_IN_ORDER;
+         ++optstring;
+       }
+      else if (optstring[0] == '+')
+       {
+         ordering = REQUIRE_ORDER;
+         ++optstring;
+       }
+      else if (getenv ("POSIXLY_CORRECT") != NULL)
+       ordering = REQUIRE_ORDER;
+      else
+       ordering = PERMUTE;
+    }
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      if (ordering == PERMUTE)
+       {
+         /* If we have just processed some options following some non-options,
+            exchange them so that the options come first.  */
+
+         if (first_nonopt != last_nonopt && last_nonopt != optind)
+           exchange ((char **) argv);
+         else if (last_nonopt != optind)
+           first_nonopt = optind;
+
+         /* Now skip any additional non-options
+            and extend the range of non-options previously skipped.  */
+
+         while (optind < argc
+                && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+                && (longopts == NULL
+                    || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif                         /* GETOPT_COMPAT */
+                )
+           optind++;
+         last_nonopt = optind;
+       }
+
+      /* Special ARGV-element `--' means premature end of options.
+        Skip it like a null option,
+        then exchange with previous non-options as if it were an option,
+        then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+       {
+         optind++;
+
+         if (first_nonopt != last_nonopt && last_nonopt != optind)
+           exchange ((char **) argv);
+         else if (first_nonopt == last_nonopt)
+           first_nonopt = optind;
+         last_nonopt = argc;
+
+         optind = argc;
+       }
+
+      /* If we have done all the ARGV-elements, stop the scan
+        and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+       {
+         /* Set the next-arg-index to point at the non-options
+            that we previously skipped, so the caller will digest them.  */
+         if (first_nonopt != last_nonopt)
+           optind = first_nonopt;
+         return EOF;
+       }
+
+      /* If we have come to a non-option and did not permute it,
+        either stop the scan or describe it to the caller and pass it by.  */
+
+      if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+         && (longopts == NULL
+             || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif                         /* GETOPT_COMPAT */
+         )
+       {
+         if (ordering == REQUIRE_ORDER)
+           return EOF;
+         optarg = argv[optind++];
+         return 1;
+       }
+
+      /* We have found another option-ARGV-element.
+        Start decoding its characters.  */
+
+      nextchar = (argv[optind] + 1
+                 + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  if (longopts != NULL
+      && ((argv[optind][0] == '-'
+          && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+         || argv[optind][0] == '+'
+#endif                         /* GETOPT_COMPAT */
+         ))
+    {
+      const struct option *p;
+      char *s = nextchar;
+      int exact = 0;
+      int ambig = 0;
+      const struct option *pfound = NULL;
+      int indfound;
+
+      while (*s && *s != '=')
+       s++;
+
+      /* Test all options for either exact match or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name;
+          p++, option_index++)
+       if (!strncmp (p->name, nextchar, s - nextchar))
+         {
+           if (s - nextchar == strlen (p->name))
+             {
+               /* Exact match found.  */
+               pfound = p;
+               indfound = option_index;
+               exact = 1;
+               break;
+             }
+           else if (pfound == NULL)
+             {
+               /* First nonexact match found.  */
+               pfound = p;
+               indfound = option_index;
+             }
+           else
+             /* Second nonexact match found.  */
+             ambig = 1;
+         }
+
+      if (ambig && !exact)
+       {
+         if (opterr)
+           fprintf (stderr, "%s: option `%s' is ambiguous\n",
+                    argv[0], argv[optind]);
+         nextchar += strlen (nextchar);
+         optind++;
+         return '?';
+       }
+
+      if (pfound != NULL)
+       {
+         option_index = indfound;
+         optind++;
+         if (*s)
+           {
+             /* Don't test has_arg with >, because some C compilers don't
+                allow it to be used on enums.  */
+             if (pfound->has_arg)
+               optarg = s + 1;
+             else
+               {
+                 if (opterr)
+                   {
+                     if (argv[optind - 1][1] == '-')
+                       /* --option */
+                       fprintf (stderr,
+                                "%s: option `--%s' doesn't allow an argument\n",
+                                argv[0], pfound->name);
+                     else
+                       /* +option or -option */
+                       fprintf (stderr,
+                            "%s: option `%c%s' doesn't allow an argument\n",
+                            argv[0], argv[optind - 1][0], pfound->name);
+                   }
+                 nextchar += strlen (nextchar);
+                 return '?';
+               }
+           }
+         else if (pfound->has_arg == 1)
+           {
+             if (optind < argc)
+               optarg = argv[optind++];
+             else
+               {
+                 if (opterr)
+                   fprintf (stderr, "%s: option `%s' requires an argument\n",
+                            argv[0], argv[optind - 1]);
+                 nextchar += strlen (nextchar);
+                 return optstring[0] == ':' ? ':' : '?';
+               }
+           }
+         nextchar += strlen (nextchar);
+         if (longind != NULL)
+           *longind = option_index;
+         if (pfound->flag)
+           {
+             *(pfound->flag) = pfound->val;
+             return 0;
+           }
+         return pfound->val;
+       }
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+        or the option starts with '--' or is not a valid short
+        option, then it's an error.
+        Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+         || argv[optind][0] == '+'
+#endif                         /* GETOPT_COMPAT */
+         || my_index (optstring, *nextchar) == NULL)
+       {
+         if (opterr)
+           {
+             if (argv[optind][1] == '-')
+               /* --option */
+               fprintf (stderr, "%s: unrecognized option `--%s'\n",
+                        argv[0], nextchar);
+             else
+               /* +option or -option */
+               fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+                        argv[0], argv[optind][0], nextchar);
+           }
+         nextchar = (char *) "";
+         optind++;
+         return '?';
+       }
+    }
+
+  /* Look at and handle the next option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+       if (opterr)
+         {
+#if 0
+           if (c < 040 || c >= 0177)
+             fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+                      argv[0], c);
+           else
+             fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+           /* 1003.2 specifies the format of this message.  */
+           fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+         }
+       optopt = c;
+       return '?';
+      }
+    if (temp[1] == ':')
+      {
+       if (temp[2] == ':')
+         {
+           /* This is an option that accepts an argument optionally.  */
+           if (*nextchar != '\0')
+             {
+               optarg = nextchar;
+               optind++;
+             }
+           else
+             optarg = 0;
+           nextchar = NULL;
+         }
+       else
+         {
+           /* This is an option that requires an argument.  */
+           if (*nextchar != '\0')
+             {
+               optarg = nextchar;
+               /* If we end this ARGV-element by taking the rest as an arg,
+                  we must advance to the next element now.  */
+               optind++;
+             }
+           else if (optind == argc)
+             {
+               if (opterr)
+                 {
+#if 0
+                   fprintf (stderr, "%s: option `-%c' requires an argument\n",
+                            argv[0], c);
+#else
+                   /* 1003.2 specifies the format of this message.  */
+                   fprintf (stderr, "%s: option requires an argument -- %c\n",
+                            argv[0], c);
+#endif
+                 }
+               optopt = c;
+               if (optstring[0] == ':')
+                 c = ':';
+               else
+                 c = '?';
+             }
+           else
+             /* We already incremented `optind' once;
+                increment it again when taking next ARGV-elt as argument.  */
+             optarg = argv[optind++];
+           nextchar = NULL;
+         }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+                          (const struct option *) 0,
+                          (int *) 0,
+                          0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
+\f
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == EOF)
+       break;
+
+      switch (c)
+       {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+       printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/diff3/getopt.h b/gnu/usr.bin/diff3/getopt.h
new file mode 100644 (file)
index 0000000..45541f5
--- /dev/null
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument         (or 0) if the option does not take an argument,
+   required_argument   (or 1) if the option requires an argument,
+   optional_argument   (or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+struct option
+{
+#if    __STDC__
+  const char *name;
+#else
+  char *name;
+#endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define        no_argument             0
+#define required_argument      1
+#define optional_argument      2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+                       const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int _getopt_internal (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct option *longopts, int *longind,
+                            int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/gnu/usr.bin/diff3/getopt1.c b/gnu/usr.bin/diff3/getopt1.c
new file mode 100644 (file)
index 0000000..a32615c
--- /dev/null
@@ -0,0 +1,176 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+       Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "getopt.h"
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef        NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
+\f
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+      int option_index = 0;
+      static struct option long_options[] =
+      {
+       {"add", 1, 0, 0},
+       {"append", 0, 0, 0},
+       {"delete", 1, 0, 0},
+       {"verbose", 0, 0, 0},
+       {"create", 0, 0, 0},
+       {"file", 1, 0, 0},
+       {0, 0, 0, 0}
+      };
+
+      c = getopt_long (argc, argv, "abc:d:0123456789",
+                      long_options, &option_index);
+      if (c == EOF)
+       break;
+
+      switch (c)
+       {
+       case 0:
+         printf ("option %s", long_options[option_index].name);
+         if (optarg)
+           printf (" with arg %s", optarg);
+         printf ("\n");
+         break;
+
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", optarg);
+         break;
+
+       case 'd':
+         printf ("option d with value `%s'\n", optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+       printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/diff3/system.h b/gnu/usr.bin/diff3/system.h
new file mode 100644 (file)
index 0000000..b17d39a
--- /dev/null
@@ -0,0 +1,159 @@
+/* System dependent declarations.
+   Copyright (C) 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GNU DIFF.
+
+GNU DIFF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU DIFF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU DIFF; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef S_ISDIR
+#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+#ifndef S_ISREG
+#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if HAVE_TIME_H
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#include <sys/file.h>
+#endif
+
+#if !HAVE_DUP2
+#define dup2(f,t)      (close (t),  fcntl (f,F_DUPFD,t))
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#endif
+
+#if HAVE_SYS_WAIT_H
+#ifndef _POSIX_VERSION
+/* Prevent the NeXT prototype using union wait from causing problems.  */
+#define wait system_wait
+#endif
+#include <sys/wait.h>
+#ifndef _POSIX_VERSION
+#undef wait
+#endif
+#endif /* HAVE_SYS_WAIT_H */
+
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#undef WIFEXITED               /* Avoid 4.3BSD incompatibility with Posix.  */
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+#if HAVE_ST_BLKSIZE
+#define STAT_BLOCKSIZE(s) (s).st_blksize
+#else
+#define STAT_BLOCKSIZE(s) (S_ISREG ((s).st_mode) ? 8192 : 4096)
+#endif
+
+#if DIRENT || defined (_POSIX_VERSION)
+#include <dirent.h>
+#ifdef direct
+#undef direct
+#endif
+#define direct dirent
+#else /* ! (DIRENT || defined (_POSIX_VERSION)) */
+#if SYSNDIR
+#include <sys/ndir.h>
+#else
+#if SYSDIR
+#include <sys/dir.h>
+#else
+#include <ndir.h>
+#endif
+#endif
+#endif /* ! (DIRENT || defined (_POSIX_VERSION)) */
+
+#if HAVE_VFORK_H
+#include <vfork.h>
+#endif
+
+#if HAVE_STRING_H || STDC_HEADERS
+#include <string.h>
+#ifndef index
+#define index  strchr
+#endif
+#ifndef rindex
+#define rindex strrchr
+#endif
+#ifndef bcopy
+#define bcopy(s,d,n)   memcpy (d,s,n)
+#endif
+#ifndef bcmp
+#define bcmp(s1,s2,n)  memcmp (s1,s2,n)
+#endif
+#ifndef bzero
+#define bzero(s,n)     memset (s,0,n)
+#endif
+#else
+#include <strings.h>
+#endif
+#if !HAVE_MEMCHR && !STDC_HEADERS
+char *memchr ();
+#endif
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <limits.h>
+#else
+char *getenv ();
+char *malloc ();
+char *realloc ();
+#if __STDC__ || __GNUC__
+#include "limits.h"
+#else
+#define INT_MAX 2147483647
+#define CHAR_BIT 8
+#endif
+#endif
+
+#include <errno.h>
+#if !STDC_HEADERS
+extern int errno;
+#endif
+
+#ifdef TRUE
+#undef TRUE
+#endif
+#ifdef FALSE
+#undef FALSE
+#endif
+#define TRUE           1
+#define        FALSE           0
+
+#if !__STDC__
+#define volatile
+#endif
+
+#define min(a,b) ((a) <= (b) ? (a) : (b))
+#define max(a,b) ((a) >= (b) ? (a) : (b))
diff --git a/gnu/usr.bin/diff3/version.c b/gnu/usr.bin/diff3/version.c
new file mode 100644 (file)
index 0000000..cb9d3b9
--- /dev/null
@@ -0,0 +1,3 @@
+/* Version number of GNU diff.  */
+
+char *version_string = "2.3";