Initial import
This commit is contained in:
commit
f5e00e241f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/diff/dist/; revision=30839
339
contrib/diff/COPYING
Normal file
339
contrib/diff/COPYING
Normal file
@ -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.
|
||||
|
||||
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.)
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
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.
|
1766
contrib/diff/ChangeLog
Normal file
1766
contrib/diff/ChangeLog
Normal file
File diff suppressed because it is too large
Load Diff
198
contrib/diff/Makefile.in
Normal file
198
contrib/diff/Makefile.in
Normal file
@ -0,0 +1,198 @@
|
||||
# Makefile for GNU DIFF
|
||||
# Copyright (C) 1988,1989,1991,1992,1993,1994 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.
|
||||
|
||||
#### Start of system configuration section. ####
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
CC = @CC@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
MAKEINFO = makeinfo
|
||||
TEXI2DVI = texi2dvi
|
||||
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
DEFS = @DEFS@
|
||||
CFLAGS = @CFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
|
||||
# Some System V machines do not come with libPW.
|
||||
# If this is true for you, use the GNU alloca.o here.
|
||||
ALLOCA = @ALLOCA@
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
edit_program_name = sed '@program_transform_name@'
|
||||
|
||||
bindir = $(exec_prefix)/bin
|
||||
|
||||
infodir = $(prefix)/info
|
||||
|
||||
DEFAULT_EDITOR_PROGRAM = ed
|
||||
DIFF_PROGRAM = $(bindir)/`echo diff | $(edit_program_name)`
|
||||
NULL_DEVICE = /dev/null
|
||||
PR_PROGRAM = /bin/pr
|
||||
|
||||
#### End of system configuration section. ####
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
# The source files for all of the programs.
|
||||
srcs=diff.c analyze.c cmpbuf.c cmpbuf.h io.c context.c ed.c normal.c ifdef.c \
|
||||
util.c dir.c memchr.c waitpid.c \
|
||||
version.c diff.h regex.c regex.h side.c system.h \
|
||||
diff3.c sdiff.c cmp.c error.c xmalloc.c getopt.c getopt1.c getopt.h \
|
||||
fnmatch.c fnmatch.h alloca.c
|
||||
distfiles = $(srcs) README INSTALL NEWS diagmeet.note Makefile.in \
|
||||
stamp-h.in config.hin configure configure.in COPYING ChangeLog \
|
||||
diff.texi diff.info* texinfo.tex \
|
||||
install-sh mkinstalldirs
|
||||
|
||||
PROGRAMS = cmp diff diff3 sdiff
|
||||
|
||||
all: $(PROGRAMS) info
|
||||
|
||||
COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) -I. -I$(srcdir) $(CFLAGS)
|
||||
|
||||
.c.o:
|
||||
$(COMPILE) $<
|
||||
|
||||
diff_o = diff.o analyze.o cmpbuf.o dir.o io.o util.o \
|
||||
context.o ed.o ifdef.o normal.o side.o \
|
||||
fnmatch.o getopt.o getopt1.o regex.o version.o $(ALLOCA) $(LIBOBJS)
|
||||
diff: $(diff_o)
|
||||
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(diff_o) $(LIBS)
|
||||
|
||||
diff3_o = diff3.o getopt.o getopt1.o version.o $(LIBOBJS)
|
||||
diff3: $(diff3_o)
|
||||
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(diff3_o) $(LIBS)
|
||||
|
||||
sdiff_o = sdiff.o getopt.o getopt1.o version.o $(LIBOBJS)
|
||||
sdiff: $(sdiff_o)
|
||||
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(sdiff_o) $(LIBS)
|
||||
|
||||
cmp_o = cmp.o cmpbuf.o error.o getopt.o getopt1.o xmalloc.o version.o $(LIBOBJS)
|
||||
cmp: $(cmp_o)
|
||||
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(cmp_o) $(LIBS)
|
||||
|
||||
info: diff.info
|
||||
diff.info: diff.texi
|
||||
$(MAKEINFO) $(srcdir)/diff.texi --output=$@
|
||||
|
||||
dvi: diff.dvi
|
||||
diff.dvi: diff.texi
|
||||
$(TEXI2DVI) $(srcdir)/diff.texi
|
||||
|
||||
$(diff_o): diff.h system.h
|
||||
cmp.o diff3.o sdiff.o: system.h
|
||||
context.o diff.o regex.o: regex.h
|
||||
cmp.o diff.o diff3.o sdiff.o getopt.o getopt1.o: getopt.h
|
||||
diff.o fnmatch.o: fnmatch.h
|
||||
analyze.o cmpbuf.o cmp.o: cmpbuf.h
|
||||
|
||||
cmp.o: cmp.c
|
||||
$(COMPILE) -DNULL_DEVICE=\"$(NULL_DEVICE)\" $(srcdir)/cmp.c
|
||||
|
||||
diff3.o: diff3.c
|
||||
$(COMPILE) -DDIFF_PROGRAM=\"$(DIFF_PROGRAM)\" $(srcdir)/diff3.c
|
||||
|
||||
sdiff.o: sdiff.c
|
||||
$(COMPILE) -DDEFAULT_EDITOR_PROGRAM=\"$(DEFAULT_EDITOR_PROGRAM)\" \
|
||||
-DDIFF_PROGRAM=\"$(DIFF_PROGRAM)\" $(srcdir)/sdiff.c
|
||||
|
||||
util.o: util.c
|
||||
$(COMPILE) -DPR_PROGRAM=\"$(PR_PROGRAM)\" $(srcdir)/util.c
|
||||
|
||||
TAGS: $(srcs)
|
||||
etags $(srcs)
|
||||
|
||||
clean:
|
||||
rm -f *.o $(PROGRAMS) core
|
||||
rm -f *.aux *.cp *.cps *.dvi *.fn *.fns *.ky *.kys *.log
|
||||
rm -f *.pg *.pgs *.toc *.tp *.tps *.vr *.vrs
|
||||
|
||||
mostlyclean: clean
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile config.cache config.h config.log config.status stamp-h
|
||||
|
||||
realclean: distclean
|
||||
rm -f TAGS *.info*
|
||||
|
||||
install: all installdirs
|
||||
for p in $(PROGRAMS); do \
|
||||
$(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p | $(edit_program_name)`; \
|
||||
done
|
||||
{ test -f diff.info || cd $(srcdir); } && \
|
||||
for f in diff.info*; do \
|
||||
$(INSTALL_DATA) $$f $(infodir)/$$f; \
|
||||
done
|
||||
|
||||
installdirs:
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(bindir) $(infodir)
|
||||
|
||||
# We need more tests.
|
||||
check:
|
||||
./cmp cmp cmp
|
||||
./diff diff diff
|
||||
./diff3 diff3 diff3 diff3
|
||||
./sdiff sdiff sdiff
|
||||
|
||||
uninstall:
|
||||
for p in $(PROGRAMS); do \
|
||||
rm -f $(bindir)/`echo $$p | $(edit_program_name)`; \
|
||||
done
|
||||
rm -f $(infodir)/diff.info*
|
||||
|
||||
configure: configure.in
|
||||
cd $(srcdir) && autoconf
|
||||
|
||||
# autoheader might not change config.hin.
|
||||
config.hin: stamp-h.in
|
||||
stamp-h.in: configure.in
|
||||
cd $(srcdir) && autoheader
|
||||
date > $(srcdir)/stamp-h.in
|
||||
|
||||
config.status: configure
|
||||
./config.status --recheck
|
||||
|
||||
# config.status might not change config.h, but it changes stamp-h.
|
||||
config.h: stamp-h
|
||||
stamp-h: config.hin config.status
|
||||
./config.status
|
||||
Makefile: Makefile.in config.status
|
||||
./config.status
|
||||
|
||||
dist: $(distfiles)
|
||||
echo diffutils-`sed -e '/version_string/!d' -e 's/[^0-9]*\([0-9a-z.]*\).*/\1/' -e q version.c` > .fname
|
||||
rm -rf `cat .fname`
|
||||
mkdir `cat .fname`
|
||||
-ln $(distfiles) `cat .fname`
|
||||
for file in $(distfiles); do \
|
||||
[ -r `cat .fname`/$$file ] || cp -p $$file `cat .fname` || exit; \
|
||||
done
|
||||
tar -chf - `cat .fname` | gzip >`cat .fname`.tar.gz
|
||||
rm -rf `cat .fname` .fname
|
||||
|
||||
# Prevent GNU make v3 from overflowing arg limit on SysV.
|
||||
.NOEXPORT:
|
126
contrib/diff/NEWS
Normal file
126
contrib/diff/NEWS
Normal file
@ -0,0 +1,126 @@
|
||||
User-visible changes in version 2.7:
|
||||
|
||||
* New diff option: --binary (useful only on non-Posix hosts)
|
||||
* diff -b and -w now ignore line incompleteness; -B no longer does this.
|
||||
* cmp -c now uses locale to decide which output characters to quote.
|
||||
* Help and version messages are reorganized.
|
||||
|
||||
|
||||
User-visible changes in version 2.6:
|
||||
|
||||
* New cmp, diff, diff3, sdiff option: --help
|
||||
* A new heuristic for diff greatly reduces the time needed to compare
|
||||
large input files that contain many differences.
|
||||
* Partly as a result, GNU diff's output is not exactly the same as before.
|
||||
Usually it is a bit smaller, but sometimes it is a bit larger.
|
||||
|
||||
|
||||
User-visible changes in version 2.5:
|
||||
|
||||
* New cmp option: -v --version
|
||||
|
||||
|
||||
User-visible changes in version 2.4:
|
||||
|
||||
* New cmp option: --ignore-initial=BYTES
|
||||
* New diff3 option: -T --initial-tab
|
||||
* New diff option: --line-format=FORMAT
|
||||
* New diff group format specifications:
|
||||
<PRINTF_SPEC>[eflmnEFLMN]
|
||||
A printf spec followed by one of the following letters
|
||||
causes the integer corresponding to that letter to be
|
||||
printed according to the printf specification.
|
||||
E.g. `%5df' prints the number of the first line in the
|
||||
group in the old file using the "%5d" format.
|
||||
e: line number just before the group in old file; equals f - 1
|
||||
f: first line number in group in the old file
|
||||
l: last line number in group in the old file
|
||||
m: line number just after the group in old file; equals l + 1
|
||||
n: number of lines in group in the old file; equals l - f + 1
|
||||
E, F, L, M, N: likewise, for lines in the new file
|
||||
%(A=B?T:E)
|
||||
If A equals B then T else E. A and B are each either a decimal
|
||||
constant or a single letter interpreted as above. T and E are
|
||||
arbitrary format strings. This format spec is equivalent to T if
|
||||
A's value equals B's; otherwise it is equivalent to E. For
|
||||
example, `%(N=0?no:%dN) line%(N=1?:s)' is equivalent to `no lines'
|
||||
if N (the number of lines in the group in the the new file) is 0,
|
||||
to `1 line' if N is 1, and to `%dN lines' otherwise.
|
||||
%c'C'
|
||||
where C is a single character, stands for the character C. C may not
|
||||
be a backslash or an apostrophe. E.g. %c':' stands for a colon.
|
||||
%c'\O'
|
||||
where O is a string of 1, 2, or 3 octal digits, stands for the
|
||||
character with octal code O. E.g. %c'\0' stands for a null character.
|
||||
* New diff line format specifications:
|
||||
<PRINTF_SPEC>n
|
||||
The line number, printed with <PRINTF_SPEC>.
|
||||
E.g. `%5dn' prints the line number with a "%5d" format.
|
||||
%c'C'
|
||||
%c'\O'
|
||||
The character C, or with octal code O, as above.
|
||||
* Supported <PRINTF_SPEC>s have the same meaning as with printf, but must
|
||||
match the extended regular expression %-*[0-9]*(\.[0-9]*)?[doxX].
|
||||
* The format spec %0 introduced in version 2.1 has been removed, since it
|
||||
is incompatible with printf specs like %02d. To represent a null char,
|
||||
use %c'\0' instead.
|
||||
* cmp and diff now conform to Posix.2 (ISO/IEC 9945-2:1993)
|
||||
if the underlying system conforms to Posix:
|
||||
- Some messages' wordings are changed in minor ways.
|
||||
- ``White space'' is now whatever C's `isspace' says it is.
|
||||
- When comparing directories, if `diff' finds a file that is not a regular
|
||||
file or a directory, it reports the file's type instead of diffing it.
|
||||
(As usual, it follows symbolic links first.)
|
||||
- When signaled, sdiff exits with the signal's status, not with status 2.
|
||||
* Now portable to hosts where int, long, pointer, etc. are not all the same
|
||||
size.
|
||||
* `cmp - -' now works like `diff - -'.
|
||||
|
||||
|
||||
User-visible changes in version 2.3:
|
||||
|
||||
* New diff option: --horizon-lines=lines
|
||||
|
||||
|
||||
User-visible changes in version 2.1:
|
||||
|
||||
* New diff options:
|
||||
--{old,new,unchanged}-line-format='format'
|
||||
--{old,new,unchanged,changed}-group-format='format'
|
||||
-U
|
||||
* New diff3 option:
|
||||
-A --show-all
|
||||
* diff3 -m now defaults to -A, not -E.
|
||||
* diff3 now takes up to three -L or --label options, not just two.
|
||||
If just two options are given, they refer to the first two input files,
|
||||
not the first and third input files.
|
||||
* sdiff and diff -y handle incomplete lines.
|
||||
|
||||
|
||||
User-visible changes in version 2.0:
|
||||
|
||||
* Add sdiff and cmp programs.
|
||||
* Add Texinfo documentation.
|
||||
* Add configure script.
|
||||
* Improve diff performance.
|
||||
* New diff options:
|
||||
-x --exclude
|
||||
-X --exclude-from
|
||||
-P --unidirectional-new-file
|
||||
-W --width
|
||||
-y --side-by-side
|
||||
--left-column
|
||||
--sdiff-merge-assist
|
||||
--suppress-common-lines
|
||||
* diff options renamed:
|
||||
--label renamed from --file-label
|
||||
--forward-ed renamed from --reversed-ed
|
||||
--paginate renamed from --print
|
||||
--entire-new-file renamed from --entire-new-files
|
||||
--new-file renamed from --new-files
|
||||
--all-text removed
|
||||
* New diff3 options:
|
||||
-v --version
|
||||
* Add long-named equivalents for other diff3 options.
|
||||
* diff options -F (--show-function-line) and -I (--ignore-matching-lines)
|
||||
can now be given more than once.
|
9
contrib/diff/README
Normal file
9
contrib/diff/README
Normal file
@ -0,0 +1,9 @@
|
||||
This directory contains the GNU diff, diff3, sdiff, and cmp utilities.
|
||||
Their features are a superset of the Unix features and they are
|
||||
significantly faster. cmp has been moved here from the GNU textutils.
|
||||
|
||||
See the file COPYING for copying conditions.
|
||||
See the file diff.texi (or diff.info*) for documentation.
|
||||
See the file INSTALL for compilation and installation instructions.
|
||||
|
||||
Report bugs to bug-gnu-utils@prep.ai.mit.edu
|
1084
contrib/diff/analyze.c
Normal file
1084
contrib/diff/analyze.c
Normal file
File diff suppressed because it is too large
Load Diff
40
contrib/diff/cmpbuf.c
Normal file
40
contrib/diff/cmpbuf.c
Normal file
@ -0,0 +1,40 @@
|
||||
/* Buffer primitives for comparison operations.
|
||||
Copyright (C) 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "system.h"
|
||||
#include "cmpbuf.h"
|
||||
|
||||
/* Least common multiple of two buffer sizes A and B. */
|
||||
|
||||
size_t
|
||||
buffer_lcm (a, b)
|
||||
size_t a, b;
|
||||
{
|
||||
size_t m, n, r;
|
||||
|
||||
/* Yield reasonable values if buffer sizes are zero. */
|
||||
if (!a)
|
||||
return b ? b : 8 * 1024;
|
||||
if (!b)
|
||||
return a;
|
||||
|
||||
/* n = gcd (a, b) */
|
||||
for (m = a, n = b; (r = m % n) != 0; m = n, n = r)
|
||||
continue;
|
||||
|
||||
return a/n * b;
|
||||
}
|
20
contrib/diff/cmpbuf.h
Normal file
20
contrib/diff/cmpbuf.h
Normal file
@ -0,0 +1,20 @@
|
||||
/* Buffer primitives for comparison operations.
|
||||
Copyright (C) 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. */
|
||||
|
||||
size_t buffer_lcm PARAMS((size_t, size_t));
|
117
contrib/diff/config.hin
Normal file
117
contrib/diff/config.hin
Normal file
@ -0,0 +1,117 @@
|
||||
/* config.hin. Generated automatically from configure.in by autoheader. */
|
||||
|
||||
/* Define if using alloca.c. */
|
||||
#undef C_ALLOCA
|
||||
|
||||
/* Define if the closedir function returns void instead of int. */
|
||||
#undef CLOSEDIR_VOID
|
||||
|
||||
/* Define to empty if the keyword does not work. */
|
||||
#undef const
|
||||
|
||||
/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
|
||||
This function is required for alloca.c support on those systems. */
|
||||
#undef CRAY_STACKSEG_END
|
||||
|
||||
/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
|
||||
#undef HAVE_ALLOCA_H
|
||||
|
||||
/* Define if you don't have vprintf but do have _doprnt. */
|
||||
#undef HAVE_DOPRNT
|
||||
|
||||
/* Define if your struct stat has st_blksize. */
|
||||
#undef HAVE_ST_BLKSIZE
|
||||
|
||||
/* Define if you have <vfork.h>. */
|
||||
#undef HAVE_VFORK_H
|
||||
|
||||
/* Define if you have the vprintf function. */
|
||||
#undef HAVE_VPRINTF
|
||||
|
||||
/* Define if on MINIX. */
|
||||
#undef _MINIX
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef pid_t
|
||||
|
||||
/* Define if the system does not provide POSIX.1 features except
|
||||
with this defined. */
|
||||
#undef _POSIX_1_SOURCE
|
||||
|
||||
/* Define if you need to in order for stat and other things to work. */
|
||||
#undef _POSIX_SOURCE
|
||||
|
||||
/* Define as the return type of signal handlers (int or void). */
|
||||
#undef RETSIGTYPE
|
||||
|
||||
/* If using the C implementation of alloca, define if you know the
|
||||
direction of stack growth for your system; otherwise it will be
|
||||
automatically deduced at run-time.
|
||||
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||
STACK_DIRECTION = 0 => direction of growth unknown
|
||||
*/
|
||||
#undef STACK_DIRECTION
|
||||
|
||||
/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
|
||||
#undef STAT_MACROS_BROKEN
|
||||
|
||||
/* Define if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define if <sys/wait.h> is compatible with Posix applications. */
|
||||
#undef HAVE_SYS_WAIT_H
|
||||
|
||||
/* Define vfork as fork if vfork does not work. */
|
||||
#undef vfork
|
||||
|
||||
/* Define if you have the dup2 function. */
|
||||
#undef HAVE_DUP2
|
||||
|
||||
/* Define if you have the memchr function. */
|
||||
#undef HAVE_MEMCHR
|
||||
|
||||
/* Define if you have the sigaction function. */
|
||||
#undef HAVE_SIGACTION
|
||||
|
||||
/* Define if you have the strchr function. */
|
||||
#undef HAVE_STRCHR
|
||||
|
||||
/* Define if you have the strerror function. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/* Define if you have the tmpnam function. */
|
||||
#undef HAVE_TMPNAM
|
||||
|
||||
/* Define if you have the <dirent.h> header file. */
|
||||
#undef HAVE_DIRENT_H
|
||||
|
||||
/* Define if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define if you have the <limits.h> header file. */
|
||||
#undef HAVE_LIMITS_H
|
||||
|
||||
/* Define if you have the <ndir.h> header file. */
|
||||
#undef HAVE_NDIR_H
|
||||
|
||||
/* Define if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define if you have the <sys/dir.h> header file. */
|
||||
#undef HAVE_SYS_DIR_H
|
||||
|
||||
/* Define if you have the <sys/file.h> header file. */
|
||||
#undef HAVE_SYS_FILE_H
|
||||
|
||||
/* Define if you have the <sys/ndir.h> header file. */
|
||||
#undef HAVE_SYS_NDIR_H
|
||||
|
||||
/* Define if you have the <time.h> header file. */
|
||||
#undef HAVE_TIME_H
|
||||
|
||||
/* Define if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
2149
contrib/diff/configure
vendored
Executable file
2149
contrib/diff/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
26
contrib/diff/configure.in
Normal file
26
contrib/diff/configure.in
Normal file
@ -0,0 +1,26 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(diff.h)
|
||||
AC_CONFIG_HEADER(config.h:config.hin)
|
||||
AC_ARG_PROGRAM
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_INSTALL
|
||||
AC_ISC_POSIX
|
||||
AC_MINIX
|
||||
AC_C_CONST
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS(unistd.h fcntl.h limits.h stdlib.h string.h sys/file.h time.h)
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_STAT
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIGNAL
|
||||
AC_CHECK_FUNCS(dup2 memchr sigaction strchr strerror tmpnam)
|
||||
AC_REPLACE_FUNCS(memchr waitpid)
|
||||
AC_FUNC_ALLOCA
|
||||
AC_FUNC_CLOSEDIR_VOID
|
||||
dnl No need for AC_FUNC_MEMCMP, since memcmp is used only to test for equality.
|
||||
AC_FUNC_VFORK
|
||||
AC_FUNC_VPRINTF
|
||||
AC_STRUCT_ST_BLKSIZE
|
||||
AC_OUTPUT(Makefile, [date > stamp-h])
|
468
contrib/diff/context.c
Normal file
468
contrib/diff/context.c
Normal file
@ -0,0 +1,468 @@
|
||||
/* Context-format output routines for GNU DIFF.
|
||||
Copyright (C) 1988,1989,1991,1992,1993,1994 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 "diff.h"
|
||||
|
||||
static struct change *find_hunk PARAMS((struct change *));
|
||||
static void find_function PARAMS((struct file_data const *, int, char const **, size_t *));
|
||||
static void mark_ignorable PARAMS((struct change *));
|
||||
static void pr_context_hunk PARAMS((struct change *));
|
||||
static void pr_unidiff_hunk PARAMS((struct change *));
|
||||
static void print_context_label PARAMS ((char const *, struct file_data *, char const *));
|
||||
static void print_context_number_range PARAMS((struct file_data const *, int, int));
|
||||
static void print_unidiff_number_range PARAMS((struct file_data const *, int, int));
|
||||
|
||||
/* Last place find_function started searching from. */
|
||||
static int find_function_last_search;
|
||||
|
||||
/* The value find_function returned when it started searching there. */
|
||||
static int find_function_last_match;
|
||||
|
||||
/* Print a label for a context diff, with a file name and date or a label. */
|
||||
|
||||
static void
|
||||
print_context_label (mark, inf, label)
|
||||
char const *mark;
|
||||
struct file_data *inf;
|
||||
char const *label;
|
||||
{
|
||||
if (label)
|
||||
fprintf (outfile, "%s %s\n", mark, label);
|
||||
else
|
||||
{
|
||||
char const *ct = ctime (&inf->stat.st_mtime);
|
||||
if (!ct)
|
||||
ct = "?\n";
|
||||
/* See Posix.2 section 4.17.6.1.4 for this format. */
|
||||
fprintf (outfile, "%s %s\t%s", mark, inf->name, ct);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print a header for a context diff, with the file names and dates. */
|
||||
|
||||
void
|
||||
print_context_header (inf, unidiff_flag)
|
||||
struct file_data inf[];
|
||||
int unidiff_flag;
|
||||
{
|
||||
if (unidiff_flag)
|
||||
{
|
||||
print_context_label ("---", &inf[0], file_label[0]);
|
||||
print_context_label ("+++", &inf[1], file_label[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
print_context_label ("***", &inf[0], file_label[0]);
|
||||
print_context_label ("---", &inf[1], file_label[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print an edit script in context format. */
|
||||
|
||||
void
|
||||
print_context_script (script, unidiff_flag)
|
||||
struct change *script;
|
||||
int unidiff_flag;
|
||||
{
|
||||
if (ignore_blank_lines_flag || ignore_regexp_list)
|
||||
mark_ignorable (script);
|
||||
else
|
||||
{
|
||||
struct change *e;
|
||||
for (e = script; e; e = e->link)
|
||||
e->ignore = 0;
|
||||
}
|
||||
|
||||
find_function_last_search = - files[0].prefix_lines;
|
||||
find_function_last_match = find_function_last_search - 1;
|
||||
|
||||
if (unidiff_flag)
|
||||
print_script (script, find_hunk, pr_unidiff_hunk);
|
||||
else
|
||||
print_script (script, find_hunk, pr_context_hunk);
|
||||
}
|
||||
|
||||
/* Print a pair of line numbers with a comma, translated for file FILE.
|
||||
If the second number is not greater, use the first in place of it.
|
||||
|
||||
Args A and B are internal line numbers.
|
||||
We print the translated (real) line numbers. */
|
||||
|
||||
static void
|
||||
print_context_number_range (file, a, b)
|
||||
struct file_data const *file;
|
||||
int a, b;
|
||||
{
|
||||
int trans_a, trans_b;
|
||||
translate_range (file, a, b, &trans_a, &trans_b);
|
||||
|
||||
/* Note: we can have B < A in the case of a range of no lines.
|
||||
In this case, we should print the line number before the range,
|
||||
which is B. */
|
||||
if (trans_b > trans_a)
|
||||
fprintf (outfile, "%d,%d", trans_a, trans_b);
|
||||
else
|
||||
fprintf (outfile, "%d", trans_b);
|
||||
}
|
||||
|
||||
/* Print a portion of an edit script in context format.
|
||||
HUNK is the beginning of the portion to be printed.
|
||||
The end is marked by a `link' that has been nulled out.
|
||||
|
||||
Prints out lines from both files, and precedes each
|
||||
line with the appropriate flag-character. */
|
||||
|
||||
static void
|
||||
pr_context_hunk (hunk)
|
||||
struct change *hunk;
|
||||
{
|
||||
int first0, last0, first1, last1, show_from, show_to, i;
|
||||
struct change *next;
|
||||
char const *prefix;
|
||||
char const *function;
|
||||
size_t function_length;
|
||||
FILE *out;
|
||||
|
||||
/* Determine range of line numbers involved in each file. */
|
||||
|
||||
analyze_hunk (hunk, &first0, &last0, &first1, &last1, &show_from, &show_to);
|
||||
|
||||
if (!show_from && !show_to)
|
||||
return;
|
||||
|
||||
/* Include a context's width before and after. */
|
||||
|
||||
i = - files[0].prefix_lines;
|
||||
first0 = max (first0 - context, i);
|
||||
first1 = max (first1 - context, i);
|
||||
last0 = min (last0 + context, files[0].valid_lines - 1);
|
||||
last1 = min (last1 + context, files[1].valid_lines - 1);
|
||||
|
||||
/* If desired, find the preceding function definition line in file 0. */
|
||||
function = 0;
|
||||
if (function_regexp_list)
|
||||
find_function (&files[0], first0, &function, &function_length);
|
||||
|
||||
begin_output ();
|
||||
out = outfile;
|
||||
|
||||
/* If we looked for and found a function this is part of,
|
||||
include its name in the header of the diff section. */
|
||||
fprintf (out, "***************");
|
||||
|
||||
if (function)
|
||||
{
|
||||
fprintf (out, " ");
|
||||
fwrite (function, 1, min (function_length - 1, 40), out);
|
||||
}
|
||||
|
||||
fprintf (out, "\n*** ");
|
||||
print_context_number_range (&files[0], first0, last0);
|
||||
fprintf (out, " ****\n");
|
||||
|
||||
if (show_from)
|
||||
{
|
||||
next = hunk;
|
||||
|
||||
for (i = first0; i <= last0; i++)
|
||||
{
|
||||
/* Skip past changes that apply (in file 0)
|
||||
only to lines before line I. */
|
||||
|
||||
while (next && next->line0 + next->deleted <= i)
|
||||
next = next->link;
|
||||
|
||||
/* Compute the marking for line I. */
|
||||
|
||||
prefix = " ";
|
||||
if (next && next->line0 <= i)
|
||||
/* The change NEXT covers this line.
|
||||
If lines were inserted here in file 1, this is "changed".
|
||||
Otherwise it is "deleted". */
|
||||
prefix = (next->inserted > 0 ? "!" : "-");
|
||||
|
||||
print_1_line (prefix, &files[0].linbuf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf (out, "--- ");
|
||||
print_context_number_range (&files[1], first1, last1);
|
||||
fprintf (out, " ----\n");
|
||||
|
||||
if (show_to)
|
||||
{
|
||||
next = hunk;
|
||||
|
||||
for (i = first1; i <= last1; i++)
|
||||
{
|
||||
/* Skip past changes that apply (in file 1)
|
||||
only to lines before line I. */
|
||||
|
||||
while (next && next->line1 + next->inserted <= i)
|
||||
next = next->link;
|
||||
|
||||
/* Compute the marking for line I. */
|
||||
|
||||
prefix = " ";
|
||||
if (next && next->line1 <= i)
|
||||
/* The change NEXT covers this line.
|
||||
If lines were deleted here in file 0, this is "changed".
|
||||
Otherwise it is "inserted". */
|
||||
prefix = (next->deleted > 0 ? "!" : "+");
|
||||
|
||||
print_1_line (prefix, &files[1].linbuf[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Print a pair of line numbers with a comma, translated for file FILE.
|
||||
If the second number is smaller, use the first in place of it.
|
||||
If the numbers are equal, print just one number.
|
||||
|
||||
Args A and B are internal line numbers.
|
||||
We print the translated (real) line numbers. */
|
||||
|
||||
static void
|
||||
print_unidiff_number_range (file, a, b)
|
||||
struct file_data const *file;
|
||||
int a, b;
|
||||
{
|
||||
int trans_a, trans_b;
|
||||
translate_range (file, a, b, &trans_a, &trans_b);
|
||||
|
||||
/* Note: we can have B < A in the case of a range of no lines.
|
||||
In this case, we should print the line number before the range,
|
||||
which is B. */
|
||||
if (trans_b <= trans_a)
|
||||
fprintf (outfile, trans_b == trans_a ? "%d" : "%d,0", trans_b);
|
||||
else
|
||||
fprintf (outfile, "%d,%d", trans_a, trans_b - trans_a + 1);
|
||||
}
|
||||
|
||||
/* Print a portion of an edit script in unidiff format.
|
||||
HUNK is the beginning of the portion to be printed.
|
||||
The end is marked by a `link' that has been nulled out.
|
||||
|
||||
Prints out lines from both files, and precedes each
|
||||
line with the appropriate flag-character. */
|
||||
|
||||
static void
|
||||
pr_unidiff_hunk (hunk)
|
||||
struct change *hunk;
|
||||
{
|
||||
int first0, last0, first1, last1, show_from, show_to, i, j, k;
|
||||
struct change *next;
|
||||
char const *function;
|
||||
size_t function_length;
|
||||
FILE *out;
|
||||
|
||||
/* Determine range of line numbers involved in each file. */
|
||||
|
||||
analyze_hunk (hunk, &first0, &last0, &first1, &last1, &show_from, &show_to);
|
||||
|
||||
if (!show_from && !show_to)
|
||||
return;
|
||||
|
||||
/* Include a context's width before and after. */
|
||||
|
||||
i = - files[0].prefix_lines;
|
||||
first0 = max (first0 - context, i);
|
||||
first1 = max (first1 - context, i);
|
||||
last0 = min (last0 + context, files[0].valid_lines - 1);
|
||||
last1 = min (last1 + context, files[1].valid_lines - 1);
|
||||
|
||||
/* If desired, find the preceding function definition line in file 0. */
|
||||
function = 0;
|
||||
if (function_regexp_list)
|
||||
find_function (&files[0], first0, &function, &function_length);
|
||||
|
||||
begin_output ();
|
||||
out = outfile;
|
||||
|
||||
fprintf (out, "@@ -");
|
||||
print_unidiff_number_range (&files[0], first0, last0);
|
||||
fprintf (out, " +");
|
||||
print_unidiff_number_range (&files[1], first1, last1);
|
||||
fprintf (out, " @@");
|
||||
|
||||
/* If we looked for and found a function this is part of,
|
||||
include its name in the header of the diff section. */
|
||||
|
||||
if (function)
|
||||
{
|
||||
putc (' ', out);
|
||||
fwrite (function, 1, min (function_length - 1, 40), out);
|
||||
}
|
||||
putc ('\n', out);
|
||||
|
||||
next = hunk;
|
||||
i = first0;
|
||||
j = first1;
|
||||
|
||||
while (i <= last0 || j <= last1)
|
||||
{
|
||||
|
||||
/* If the line isn't a difference, output the context from file 0. */
|
||||
|
||||
if (!next || i < next->line0)
|
||||
{
|
||||
putc (tab_align_flag ? '\t' : ' ', out);
|
||||
print_1_line (0, &files[0].linbuf[i++]);
|
||||
j++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For each difference, first output the deleted part. */
|
||||
|
||||
k = next->deleted;
|
||||
while (k--)
|
||||
{
|
||||
putc ('-', out);
|
||||
if (tab_align_flag)
|
||||
putc ('\t', out);
|
||||
print_1_line (0, &files[0].linbuf[i++]);
|
||||
}
|
||||
|
||||
/* Then output the inserted part. */
|
||||
|
||||
k = next->inserted;
|
||||
while (k--)
|
||||
{
|
||||
putc ('+', out);
|
||||
if (tab_align_flag)
|
||||
putc ('\t', out);
|
||||
print_1_line (0, &files[1].linbuf[j++]);
|
||||
}
|
||||
|
||||
/* We're done with this hunk, so on to the next! */
|
||||
|
||||
next = next->link;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan a (forward-ordered) edit script for the first place that more than
|
||||
2*CONTEXT unchanged lines appear, and return a pointer
|
||||
to the `struct change' for the last change before those lines. */
|
||||
|
||||
static struct change *
|
||||
find_hunk (start)
|
||||
struct change *start;
|
||||
{
|
||||
struct change *prev;
|
||||
int top0, top1;
|
||||
int thresh;
|
||||
|
||||
do
|
||||
{
|
||||
/* Compute number of first line in each file beyond this changed. */
|
||||
top0 = start->line0 + start->deleted;
|
||||
top1 = start->line1 + start->inserted;
|
||||
prev = start;
|
||||
start = start->link;
|
||||
/* Threshold distance is 2*CONTEXT between two non-ignorable changes,
|
||||
but only CONTEXT if one is ignorable. */
|
||||
thresh = ((prev->ignore || (start && start->ignore))
|
||||
? context
|
||||
: 2 * context + 1);
|
||||
/* It is not supposed to matter which file we check in the end-test.
|
||||
If it would matter, crash. */
|
||||
if (start && start->line0 - top0 != start->line1 - top1)
|
||||
abort ();
|
||||
} while (start
|
||||
/* Keep going if less than THRESH lines
|
||||
elapse before the affected line. */
|
||||
&& start->line0 < top0 + thresh);
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
/* Set the `ignore' flag properly in each change in SCRIPT.
|
||||
It should be 1 if all the lines inserted or deleted in that change
|
||||
are ignorable lines. */
|
||||
|
||||
static void
|
||||
mark_ignorable (script)
|
||||
struct change *script;
|
||||
{
|
||||
while (script)
|
||||
{
|
||||
struct change *next = script->link;
|
||||
int first0, last0, first1, last1, deletes, inserts;
|
||||
|
||||
/* Turn this change into a hunk: detach it from the others. */
|
||||
script->link = 0;
|
||||
|
||||
/* Determine whether this change is ignorable. */
|
||||
analyze_hunk (script, &first0, &last0, &first1, &last1, &deletes, &inserts);
|
||||
/* Reconnect the chain as before. */
|
||||
script->link = next;
|
||||
|
||||
/* If the change is ignorable, mark it. */
|
||||
script->ignore = (!deletes && !inserts);
|
||||
|
||||
/* Advance to the following change. */
|
||||
script = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the last function-header line in FILE prior to line number LINENUM.
|
||||
This is a line containing a match for the regexp in `function_regexp'.
|
||||
Store the address of the line text into LINEP and the length of the
|
||||
line into LENP.
|
||||
Do not store anything if no function-header is found. */
|
||||
|
||||
static void
|
||||
find_function (file, linenum, linep, lenp)
|
||||
struct file_data const *file;
|
||||
int linenum;
|
||||
char const **linep;
|
||||
size_t *lenp;
|
||||
{
|
||||
int i = linenum;
|
||||
int last = find_function_last_search;
|
||||
find_function_last_search = i;
|
||||
|
||||
while (--i >= last)
|
||||
{
|
||||
/* See if this line is what we want. */
|
||||
struct regexp_list *r;
|
||||
char const *line = file->linbuf[i];
|
||||
size_t len = file->linbuf[i + 1] - line;
|
||||
|
||||
for (r = function_regexp_list; r; r = r->next)
|
||||
if (0 <= re_search (&r->buf, line, len, 0, len, 0))
|
||||
{
|
||||
*linep = line;
|
||||
*lenp = len;
|
||||
find_function_last_match = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* If we search back to where we started searching the previous time,
|
||||
find the line we found last time. */
|
||||
if (find_function_last_match >= - file->prefix_lines)
|
||||
{
|
||||
i = find_function_last_match;
|
||||
*linep = file->linbuf[i];
|
||||
*lenp = file->linbuf[i + 1] - *linep;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
71
contrib/diff/diagmeet.note
Normal file
71
contrib/diff/diagmeet.note
Normal file
@ -0,0 +1,71 @@
|
||||
Here is a comparison matrix which shows a case in which
|
||||
it is possible for the forward and backward scan in `diag'
|
||||
to meet along a nonzero length of diagonal simultaneous
|
||||
(so that bdiag[d] and fdiag[d] are not equal)
|
||||
even though there is no snake on that diagonal at the meeting point.
|
||||
|
||||
|
||||
85 1 1 1 159 1 1 17
|
||||
1 2 3 4
|
||||
60
|
||||
1 2
|
||||
1
|
||||
2 2 3 4
|
||||
71
|
||||
3 3 4 5
|
||||
85
|
||||
4 3 4 5
|
||||
17
|
||||
5 4 5
|
||||
1
|
||||
6 4 5 6
|
||||
183
|
||||
7 5 6 7
|
||||
10
|
||||
8 6 7
|
||||
1
|
||||
9 6 7 8
|
||||
12
|
||||
7 8 9 10
|
||||
13
|
||||
10 8 9 10
|
||||
14
|
||||
10 9 10
|
||||
17
|
||||
10 10
|
||||
1
|
||||
10 9 10
|
||||
1
|
||||
8 10 10 10
|
||||
183
|
||||
8 7 9 9 9
|
||||
10
|
||||
7 6 8 9 8 8
|
||||
1
|
||||
6 5 7 7
|
||||
1
|
||||
5 6 6
|
||||
1
|
||||
5 5 5
|
||||
50
|
||||
5 4 4 4
|
||||
1
|
||||
4 3 3
|
||||
85
|
||||
5 4 3 2 2
|
||||
1
|
||||
2 1
|
||||
17
|
||||
5 4 3 2 1 1
|
||||
1
|
||||
1 0
|
||||
85 1 1 1 159 1 1 17
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
1106
contrib/diff/diff.c
Normal file
1106
contrib/diff/diff.c
Normal file
File diff suppressed because it is too large
Load Diff
340
contrib/diff/diff.h
Normal file
340
contrib/diff/diff.h
Normal file
@ -0,0 +1,340 @@
|
||||
/* Shared definitions for GNU DIFF
|
||||
Copyright (C) 1988, 89, 91, 92, 93 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 "system.h"
|
||||
#include <stdio.h>
|
||||
#include "regex.h"
|
||||
|
||||
#define TAB_WIDTH 8
|
||||
|
||||
/* Variables for command line options */
|
||||
|
||||
#ifndef GDIFF_MAIN
|
||||
#define EXTERN extern
|
||||
#else
|
||||
#define EXTERN
|
||||
#endif
|
||||
|
||||
enum output_style {
|
||||
/* Default output style. */
|
||||
OUTPUT_NORMAL,
|
||||
/* Output the differences with lines of context before and after (-c). */
|
||||
OUTPUT_CONTEXT,
|
||||
/* Output the differences in a unified context diff format (-u). */
|
||||
OUTPUT_UNIFIED,
|
||||
/* Output the differences as commands suitable for `ed' (-e). */
|
||||
OUTPUT_ED,
|
||||
/* Output the diff as a forward ed script (-f). */
|
||||
OUTPUT_FORWARD_ED,
|
||||
/* Like -f, but output a count of changed lines in each "command" (-n). */
|
||||
OUTPUT_RCS,
|
||||
/* Output merged #ifdef'd file (-D). */
|
||||
OUTPUT_IFDEF,
|
||||
/* Output sdiff style (-y). */
|
||||
OUTPUT_SDIFF
|
||||
};
|
||||
|
||||
/* True for output styles that are robust,
|
||||
i.e. can handle a file that ends in a non-newline. */
|
||||
#define ROBUST_OUTPUT_STYLE(S) ((S) != OUTPUT_ED && (S) != OUTPUT_FORWARD_ED)
|
||||
|
||||
EXTERN enum output_style output_style;
|
||||
|
||||
/* Nonzero if output cannot be generated for identical files. */
|
||||
EXTERN int no_diff_means_no_output;
|
||||
|
||||
/* Number of lines of context to show in each set of diffs.
|
||||
This is zero when context is not to be shown. */
|
||||
EXTERN int context;
|
||||
|
||||
/* Consider all files as text files (-a).
|
||||
Don't interpret codes over 0177 as implying a "binary file". */
|
||||
EXTERN int always_text_flag;
|
||||
|
||||
/* Number of lines to keep in identical prefix and suffix. */
|
||||
EXTERN int horizon_lines;
|
||||
|
||||
/* Ignore changes in horizontal white space (-b). */
|
||||
EXTERN int ignore_space_change_flag;
|
||||
|
||||
/* Ignore all horizontal white space (-w). */
|
||||
EXTERN int ignore_all_space_flag;
|
||||
|
||||
/* Ignore changes that affect only blank lines (-B). */
|
||||
EXTERN int ignore_blank_lines_flag;
|
||||
|
||||
/* 1 if lines may match even if their contents do not match exactly.
|
||||
This depends on various options. */
|
||||
EXTERN int ignore_some_line_changes;
|
||||
|
||||
/* 1 if files may match even if their contents are not byte-for-byte identical.
|
||||
This depends on various options. */
|
||||
EXTERN int ignore_some_changes;
|
||||
|
||||
/* Ignore differences in case of letters (-i). */
|
||||
EXTERN int ignore_case_flag;
|
||||
|
||||
/* File labels for `-c' output headers (-L). */
|
||||
EXTERN char *file_label[2];
|
||||
|
||||
struct regexp_list
|
||||
{
|
||||
struct re_pattern_buffer buf;
|
||||
struct regexp_list *next;
|
||||
};
|
||||
|
||||
/* Regexp to identify function-header lines (-F). */
|
||||
EXTERN struct regexp_list *function_regexp_list;
|
||||
|
||||
/* Ignore changes that affect only lines matching this regexp (-I). */
|
||||
EXTERN struct regexp_list *ignore_regexp_list;
|
||||
|
||||
/* Say only whether files differ, not how (-q). */
|
||||
EXTERN int no_details_flag;
|
||||
|
||||
/* Report files compared that match (-s).
|
||||
Normally nothing is output when that happens. */
|
||||
EXTERN int print_file_same_flag;
|
||||
|
||||
/* Output the differences with exactly 8 columns added to each line
|
||||
so that any tabs in the text line up properly (-T). */
|
||||
EXTERN int tab_align_flag;
|
||||
|
||||
/* Expand tabs in the output so the text lines up properly
|
||||
despite the characters added to the front of each line (-t). */
|
||||
EXTERN int tab_expand_flag;
|
||||
|
||||
/* In directory comparison, specify file to start with (-S).
|
||||
All file names less than this name are ignored. */
|
||||
EXTERN char *dir_start_file;
|
||||
|
||||
/* If a file is new (appears in only one dir)
|
||||
include its entire contents (-N).
|
||||
Then `patch' would create the file with appropriate contents. */
|
||||
EXTERN int entire_new_file_flag;
|
||||
|
||||
/* If a file is new (appears in only the second dir)
|
||||
include its entire contents (-P).
|
||||
Then `patch' would create the file with appropriate contents. */
|
||||
EXTERN int unidirectional_new_file_flag;
|
||||
|
||||
/* Pipe each file's output through pr (-l). */
|
||||
EXTERN int paginate_flag;
|
||||
|
||||
enum line_class {
|
||||
/* Lines taken from just the first file. */
|
||||
OLD,
|
||||
/* Lines taken from just the second file. */
|
||||
NEW,
|
||||
/* Lines common to both files. */
|
||||
UNCHANGED,
|
||||
/* A hunk containing both old and new lines (line groups only). */
|
||||
CHANGED
|
||||
};
|
||||
|
||||
/* Line group formats for old, new, unchanged, and changed groups. */
|
||||
EXTERN char *group_format[CHANGED + 1];
|
||||
|
||||
/* Line formats for old, new, and unchanged lines. */
|
||||
EXTERN char *line_format[UNCHANGED + 1];
|
||||
|
||||
/* If using OUTPUT_SDIFF print extra information to help the sdiff filter. */
|
||||
EXTERN int sdiff_help_sdiff;
|
||||
|
||||
/* Tell OUTPUT_SDIFF to show only the left version of common lines. */
|
||||
EXTERN int sdiff_left_only;
|
||||
|
||||
/* Tell OUTPUT_SDIFF to not show common lines. */
|
||||
EXTERN int sdiff_skip_common_lines;
|
||||
|
||||
/* The half line width and column 2 offset for OUTPUT_SDIFF. */
|
||||
EXTERN unsigned sdiff_half_width;
|
||||
EXTERN unsigned sdiff_column2_offset;
|
||||
|
||||
/* String containing all the command options diff received,
|
||||
with spaces between and at the beginning but none at the end.
|
||||
If there were no options given, this string is empty. */
|
||||
EXTERN char * switch_string;
|
||||
|
||||
/* Nonzero means use heuristics for better speed. */
|
||||
EXTERN int heuristic;
|
||||
|
||||
/* Name of program the user invoked (for error messages). */
|
||||
EXTERN char *program_name;
|
||||
|
||||
/* The result of comparison is an "edit script": a chain of `struct change'.
|
||||
Each `struct change' represents one place where some lines are deleted
|
||||
and some are inserted.
|
||||
|
||||
LINE0 and LINE1 are the first affected lines in the two files (origin 0).
|
||||
DELETED is the number of lines deleted here from file 0.
|
||||
INSERTED is the number of lines inserted here in file 1.
|
||||
|
||||
If DELETED is 0 then LINE0 is the number of the line before
|
||||
which the insertion was done; vice versa for INSERTED and LINE1. */
|
||||
|
||||
struct change
|
||||
{
|
||||
struct change *link; /* Previous or next edit command */
|
||||
int inserted; /* # lines of file 1 changed here. */
|
||||
int deleted; /* # lines of file 0 changed here. */
|
||||
int line0; /* Line number of 1st deleted line. */
|
||||
int line1; /* Line number of 1st inserted line. */
|
||||
char ignore; /* Flag used in context.c */
|
||||
};
|
||||
|
||||
/* Structures that describe the input files. */
|
||||
|
||||
/* Data on one input file being compared. */
|
||||
|
||||
struct file_data {
|
||||
int desc; /* File descriptor */
|
||||
char const *name; /* File name */
|
||||
struct stat stat; /* File status from fstat() */
|
||||
int dir_p; /* nonzero if file is a directory */
|
||||
|
||||
/* Buffer in which text of file is read. */
|
||||
char * buffer;
|
||||
/* Allocated size of buffer. */
|
||||
size_t bufsize;
|
||||
/* Number of valid characters now in the buffer. */
|
||||
size_t buffered_chars;
|
||||
|
||||
/* Array of pointers to lines in the file. */
|
||||
char const **linbuf;
|
||||
|
||||
/* linbuf_base <= buffered_lines <= valid_lines <= alloc_lines.
|
||||
linebuf[linbuf_base ... buffered_lines - 1] are possibly differing.
|
||||
linebuf[linbuf_base ... valid_lines - 1] contain valid data.
|
||||
linebuf[linbuf_base ... alloc_lines - 1] are allocated. */
|
||||
int linbuf_base, buffered_lines, valid_lines, alloc_lines;
|
||||
|
||||
/* Pointer to end of prefix of this file to ignore when hashing. */
|
||||
char const *prefix_end;
|
||||
|
||||
/* Count of lines in the prefix.
|
||||
There are this many lines in the file before linbuf[0]. */
|
||||
int prefix_lines;
|
||||
|
||||
/* Pointer to start of suffix of this file to ignore when hashing. */
|
||||
char const *suffix_begin;
|
||||
|
||||
/* Vector, indexed by line number, containing an equivalence code for
|
||||
each line. It is this vector that is actually compared with that
|
||||
of another file to generate differences. */
|
||||
int *equivs;
|
||||
|
||||
/* Vector, like the previous one except that
|
||||
the elements for discarded lines have been squeezed out. */
|
||||
int *undiscarded;
|
||||
|
||||
/* Vector mapping virtual line numbers (not counting discarded lines)
|
||||
to real ones (counting those lines). Both are origin-0. */
|
||||
int *realindexes;
|
||||
|
||||
/* Total number of nondiscarded lines. */
|
||||
int nondiscarded_lines;
|
||||
|
||||
/* Vector, indexed by real origin-0 line number,
|
||||
containing 1 for a line that is an insertion or a deletion.
|
||||
The results of comparison are stored here. */
|
||||
char *changed_flag;
|
||||
|
||||
/* 1 if file ends in a line with no final newline. */
|
||||
int missing_newline;
|
||||
|
||||
/* 1 more than the maximum equivalence value used for this or its
|
||||
sibling file. */
|
||||
int equiv_max;
|
||||
};
|
||||
|
||||
/* Describe the two files currently being compared. */
|
||||
|
||||
EXTERN struct file_data files[2];
|
||||
|
||||
/* Stdio stream to output diffs to. */
|
||||
|
||||
EXTERN FILE *outfile;
|
||||
|
||||
/* Declare various functions. */
|
||||
|
||||
/* analyze.c */
|
||||
int diff_2_files PARAMS((struct file_data[], int));
|
||||
|
||||
/* context.c */
|
||||
void print_context_header PARAMS((struct file_data[], int));
|
||||
void print_context_script PARAMS((struct change *, int));
|
||||
|
||||
/* diff.c */
|
||||
int excluded_filename PARAMS((char const *));
|
||||
|
||||
/* dir.c */
|
||||
int diff_dirs PARAMS((struct file_data const[], int (*) PARAMS((char const *, char const *, char const *, char const *, int)), int));
|
||||
|
||||
/* ed.c */
|
||||
void print_ed_script PARAMS((struct change *));
|
||||
void pr_forward_ed_script PARAMS((struct change *));
|
||||
|
||||
/* ifdef.c */
|
||||
void print_ifdef_script PARAMS((struct change *));
|
||||
|
||||
/* io.c */
|
||||
int read_files PARAMS((struct file_data[], int));
|
||||
int sip PARAMS((struct file_data *, int));
|
||||
void slurp PARAMS((struct file_data *));
|
||||
|
||||
/* normal.c */
|
||||
void print_normal_script PARAMS((struct change *));
|
||||
|
||||
/* rcs.c */
|
||||
void print_rcs_script PARAMS((struct change *));
|
||||
|
||||
/* side.c */
|
||||
void print_sdiff_script PARAMS((struct change *));
|
||||
|
||||
/* util.c */
|
||||
VOID *xmalloc PARAMS((size_t));
|
||||
VOID *xrealloc PARAMS((VOID *, size_t));
|
||||
char *concat PARAMS((char const *, char const *, char const *));
|
||||
char *dir_file_pathname PARAMS((char const *, char const *));
|
||||
int change_letter PARAMS((int, int));
|
||||
int line_cmp PARAMS((char const *, char const *));
|
||||
int translate_line_number PARAMS((struct file_data const *, int));
|
||||
struct change *find_change PARAMS((struct change *));
|
||||
struct change *find_reverse_change PARAMS((struct change *));
|
||||
void analyze_hunk PARAMS((struct change *, int *, int *, int *, int *, int *, int *));
|
||||
void begin_output PARAMS((void));
|
||||
void debug_script PARAMS((struct change *));
|
||||
void error PARAMS((char const *, char const *, char const *));
|
||||
void fatal PARAMS((char const *));
|
||||
void finish_output PARAMS((void));
|
||||
void message PARAMS((char const *, char const *, char const *));
|
||||
void message5 PARAMS((char const *, char const *, char const *, char const *, char const *));
|
||||
void output_1_line PARAMS((char const *, char const *, char const *, char const *));
|
||||
void perror_with_name PARAMS((char const *));
|
||||
void pfatal_with_name PARAMS((char const *));
|
||||
void print_1_line PARAMS((char const *, char const * const *));
|
||||
void print_message_queue PARAMS((void));
|
||||
void print_number_range PARAMS((int, struct file_data *, int, int));
|
||||
void print_script PARAMS((struct change *, struct change * (*) PARAMS((struct change *)), void (*) PARAMS((struct change *))));
|
||||
void setup_output PARAMS((char const *, char const *, int));
|
||||
void translate_range PARAMS((struct file_data const *, int, int, int *, int *));
|
||||
|
||||
/* version.c */
|
||||
extern char const version_string[];
|
3916
contrib/diff/diff.texi
Normal file
3916
contrib/diff/diff.texi
Normal file
File diff suppressed because it is too large
Load Diff
1778
contrib/diff/diff3.c
Normal file
1778
contrib/diff/diff3.c
Normal file
File diff suppressed because it is too large
Load Diff
216
contrib/diff/dir.c
Normal file
216
contrib/diff/dir.c
Normal file
@ -0,0 +1,216 @@
|
||||
/* Read, sort and compare two directories. Used for GNU DIFF.
|
||||
Copyright (C) 1988, 1989, 1992, 1993, 1994 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 "diff.h"
|
||||
|
||||
/* Read the directory named by DIR and store into DIRDATA a sorted vector
|
||||
of filenames for its contents. DIR->desc == -1 means this directory is
|
||||
known to be nonexistent, so set DIRDATA to an empty vector.
|
||||
Return -1 (setting errno) if error, 0 otherwise. */
|
||||
|
||||
struct dirdata
|
||||
{
|
||||
char const **names; /* Sorted names of files in dir, 0-terminated. */
|
||||
char *data; /* Allocated storage for file names. */
|
||||
};
|
||||
|
||||
static int compare_names PARAMS((void const *, void const *));
|
||||
static int dir_sort PARAMS((struct file_data const *, struct dirdata *));
|
||||
|
||||
static int
|
||||
dir_sort (dir, dirdata)
|
||||
struct file_data const *dir;
|
||||
struct dirdata *dirdata;
|
||||
{
|
||||
register struct dirent *next;
|
||||
register int i;
|
||||
|
||||
/* Address of block containing the files that are described. */
|
||||
char const **names;
|
||||
|
||||
/* Number of files in directory. */
|
||||
size_t nnames;
|
||||
|
||||
/* Allocated and used storage for file name data. */
|
||||
char *data;
|
||||
size_t data_alloc, data_used;
|
||||
|
||||
dirdata->names = 0;
|
||||
dirdata->data = 0;
|
||||
nnames = 0;
|
||||
data = 0;
|
||||
|
||||
if (dir->desc != -1)
|
||||
{
|
||||
/* Open the directory and check for errors. */
|
||||
register DIR *reading = opendir (dir->name);
|
||||
if (!reading)
|
||||
return -1;
|
||||
|
||||
/* Initialize the table of filenames. */
|
||||
|
||||
data_alloc = max (1, (size_t) dir->stat.st_size);
|
||||
data_used = 0;
|
||||
dirdata->data = data = xmalloc (data_alloc);
|
||||
|
||||
/* Read the directory entries, and insert the subfiles
|
||||
into the `data' table. */
|
||||
|
||||
while ((errno = 0, (next = readdir (reading)) != 0))
|
||||
{
|
||||
char *d_name = next->d_name;
|
||||
size_t d_size = NAMLEN (next) + 1;
|
||||
|
||||
/* Ignore the files `.' and `..' */
|
||||
if (d_name[0] == '.'
|
||||
&& (d_name[1] == 0 || (d_name[1] == '.' && d_name[2] == 0)))
|
||||
continue;
|
||||
|
||||
if (excluded_filename (d_name))
|
||||
continue;
|
||||
|
||||
while (data_alloc < data_used + d_size)
|
||||
dirdata->data = data = xrealloc (data, data_alloc *= 2);
|
||||
memcpy (data + data_used, d_name, d_size);
|
||||
data_used += d_size;
|
||||
nnames++;
|
||||
}
|
||||
if (errno)
|
||||
{
|
||||
int e = errno;
|
||||
closedir (reading);
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
#if CLOSEDIR_VOID
|
||||
closedir (reading);
|
||||
#else
|
||||
if (closedir (reading) != 0)
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Create the `names' table from the `data' table. */
|
||||
dirdata->names = names = (char const **) xmalloc (sizeof (char *)
|
||||
* (nnames + 1));
|
||||
for (i = 0; i < nnames; i++)
|
||||
{
|
||||
names[i] = data;
|
||||
data += strlen (data) + 1;
|
||||
}
|
||||
names[nnames] = 0;
|
||||
|
||||
/* Sort the table. */
|
||||
qsort (names, nnames, sizeof (char *), compare_names);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sort the files now in the table. */
|
||||
|
||||
static int
|
||||
compare_names (file1, file2)
|
||||
void const *file1, *file2;
|
||||
{
|
||||
return filename_cmp (* (char const *const *) file1,
|
||||
* (char const *const *) file2);
|
||||
}
|
||||
|
||||
/* Compare the contents of two directories named in FILEVEC[0] and FILEVEC[1].
|
||||
This is a top-level routine; it does everything necessary for diff
|
||||
on two directories.
|
||||
|
||||
FILEVEC[0].desc == -1 says directory FILEVEC[0] doesn't exist,
|
||||
but pretend it is empty. Likewise for FILEVEC[1].
|
||||
|
||||
HANDLE_FILE is a caller-provided subroutine called to handle each file.
|
||||
It gets five operands: dir and name (rel to original working dir) of file
|
||||
in dir 0, dir and name pathname of file in dir 1, and the recursion depth.
|
||||
|
||||
For a file that appears in only one of the dirs, one of the name-args
|
||||
to HANDLE_FILE is zero.
|
||||
|
||||
DEPTH is the current depth in recursion, used for skipping top-level
|
||||
files by the -S option.
|
||||
|
||||
Returns the maximum of all the values returned by HANDLE_FILE,
|
||||
or 2 if trouble is encountered in opening files. */
|
||||
|
||||
int
|
||||
diff_dirs (filevec, handle_file, depth)
|
||||
struct file_data const filevec[];
|
||||
int (*handle_file) PARAMS((char const *, char const *, char const *, char const *, int));
|
||||
int depth;
|
||||
{
|
||||
struct dirdata dirdata[2];
|
||||
int val = 0; /* Return value. */
|
||||
int i;
|
||||
|
||||
/* Get sorted contents of both dirs. */
|
||||
for (i = 0; i < 2; i++)
|
||||
if (dir_sort (&filevec[i], &dirdata[i]) != 0)
|
||||
{
|
||||
perror_with_name (filevec[i].name);
|
||||
val = 2;
|
||||
}
|
||||
|
||||
if (val == 0)
|
||||
{
|
||||
register char const * const *names0 = dirdata[0].names;
|
||||
register char const * const *names1 = dirdata[1].names;
|
||||
char const *name0 = filevec[0].name;
|
||||
char const *name1 = filevec[1].name;
|
||||
|
||||
/* If `-S name' was given, and this is the topmost level of comparison,
|
||||
ignore all file names less than the specified starting name. */
|
||||
|
||||
if (dir_start_file && depth == 0)
|
||||
{
|
||||
while (*names0 && filename_cmp (*names0, dir_start_file) < 0)
|
||||
names0++;
|
||||
while (*names1 && filename_cmp (*names1, dir_start_file) < 0)
|
||||
names1++;
|
||||
}
|
||||
|
||||
/* Loop while files remain in one or both dirs. */
|
||||
while (*names0 || *names1)
|
||||
{
|
||||
/* Compare next name in dir 0 with next name in dir 1.
|
||||
At the end of a dir,
|
||||
pretend the "next name" in that dir is very large. */
|
||||
int nameorder = (!*names0 ? 1 : !*names1 ? -1
|
||||
: filename_cmp (*names0, *names1));
|
||||
int v1 = (*handle_file) (name0, 0 < nameorder ? 0 : *names0++,
|
||||
name1, nameorder < 0 ? 0 : *names1++,
|
||||
depth + 1);
|
||||
if (v1 > val)
|
||||
val = v1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
if (dirdata[i].names)
|
||||
free (dirdata[i].names);
|
||||
if (dirdata[i].data)
|
||||
free (dirdata[i].data);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
200
contrib/diff/ed.c
Normal file
200
contrib/diff/ed.c
Normal file
@ -0,0 +1,200 @@
|
||||
/* Output routines for ed-script format.
|
||||
Copyright (C) 1988, 89, 91, 92, 93 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 "diff.h"
|
||||
|
||||
static void print_ed_hunk PARAMS((struct change *));
|
||||
static void print_rcs_hunk PARAMS((struct change *));
|
||||
static void pr_forward_ed_hunk PARAMS((struct change *));
|
||||
|
||||
/* Print our script as ed commands. */
|
||||
|
||||
void
|
||||
print_ed_script (script)
|
||||
struct change *script;
|
||||
{
|
||||
print_script (script, find_reverse_change, print_ed_hunk);
|
||||
}
|
||||
|
||||
/* Print a hunk of an ed diff */
|
||||
|
||||
static void
|
||||
print_ed_hunk (hunk)
|
||||
struct change *hunk;
|
||||
{
|
||||
int f0, l0, f1, l1;
|
||||
int deletes, inserts;
|
||||
|
||||
#if 0
|
||||
hunk = flip_script (hunk);
|
||||
#endif
|
||||
#ifdef DEBUG
|
||||
debug_script (hunk);
|
||||
#endif
|
||||
|
||||
/* Determine range of line numbers involved in each file. */
|
||||
analyze_hunk (hunk, &f0, &l0, &f1, &l1, &deletes, &inserts);
|
||||
if (!deletes && !inserts)
|
||||
return;
|
||||
|
||||
begin_output ();
|
||||
|
||||
/* Print out the line number header for this hunk */
|
||||
print_number_range (',', &files[0], f0, l0);
|
||||
fprintf (outfile, "%c\n", change_letter (inserts, deletes));
|
||||
|
||||
/* Print new/changed lines from second file, if needed */
|
||||
if (inserts)
|
||||
{
|
||||
int i;
|
||||
int inserting = 1;
|
||||
for (i = f1; i <= l1; i++)
|
||||
{
|
||||
/* Resume the insert, if we stopped. */
|
||||
if (! inserting)
|
||||
fprintf (outfile, "%da\n",
|
||||
i - f1 + translate_line_number (&files[0], f0) - 1);
|
||||
inserting = 1;
|
||||
|
||||
/* If the file's line is just a dot, it would confuse `ed'.
|
||||
So output it with a double dot, and set the flag LEADING_DOT
|
||||
so that we will output another ed-command later
|
||||
to change the double dot into a single dot. */
|
||||
|
||||
if (files[1].linbuf[i][0] == '.'
|
||||
&& files[1].linbuf[i][1] == '\n')
|
||||
{
|
||||
fprintf (outfile, "..\n");
|
||||
fprintf (outfile, ".\n");
|
||||
/* Now change that double dot to the desired single dot. */
|
||||
fprintf (outfile, "%ds/^\\.\\././\n",
|
||||
i - f1 + translate_line_number (&files[0], f0));
|
||||
inserting = 0;
|
||||
}
|
||||
else
|
||||
/* Line is not `.', so output it unmodified. */
|
||||
print_1_line ("", &files[1].linbuf[i]);
|
||||
}
|
||||
|
||||
/* End insert mode, if we are still in it. */
|
||||
if (inserting)
|
||||
fprintf (outfile, ".\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Print change script in the style of ed commands,
|
||||
but print the changes in the order they appear in the input files,
|
||||
which means that the commands are not truly useful with ed. */
|
||||
|
||||
void
|
||||
pr_forward_ed_script (script)
|
||||
struct change *script;
|
||||
{
|
||||
print_script (script, find_change, pr_forward_ed_hunk);
|
||||
}
|
||||
|
||||
static void
|
||||
pr_forward_ed_hunk (hunk)
|
||||
struct change *hunk;
|
||||
{
|
||||
int i;
|
||||
int f0, l0, f1, l1;
|
||||
int deletes, inserts;
|
||||
|
||||
/* Determine range of line numbers involved in each file. */
|
||||
analyze_hunk (hunk, &f0, &l0, &f1, &l1, &deletes, &inserts);
|
||||
if (!deletes && !inserts)
|
||||
return;
|
||||
|
||||
begin_output ();
|
||||
|
||||
fprintf (outfile, "%c", change_letter (inserts, deletes));
|
||||
print_number_range (' ', files, f0, l0);
|
||||
fprintf (outfile, "\n");
|
||||
|
||||
/* If deletion only, print just the number range. */
|
||||
|
||||
if (!inserts)
|
||||
return;
|
||||
|
||||
/* For insertion (with or without deletion), print the number range
|
||||
and the lines from file 2. */
|
||||
|
||||
for (i = f1; i <= l1; i++)
|
||||
print_1_line ("", &files[1].linbuf[i]);
|
||||
|
||||
fprintf (outfile, ".\n");
|
||||
}
|
||||
|
||||
/* Print in a format somewhat like ed commands
|
||||
except that each insert command states the number of lines it inserts.
|
||||
This format is used for RCS. */
|
||||
|
||||
void
|
||||
print_rcs_script (script)
|
||||
struct change *script;
|
||||
{
|
||||
print_script (script, find_change, print_rcs_hunk);
|
||||
}
|
||||
|
||||
/* Print a hunk of an RCS diff */
|
||||
|
||||
static void
|
||||
print_rcs_hunk (hunk)
|
||||
struct change *hunk;
|
||||
{
|
||||
int i;
|
||||
int f0, l0, f1, l1;
|
||||
int deletes, inserts;
|
||||
int tf0, tl0, tf1, tl1;
|
||||
|
||||
/* Determine range of line numbers involved in each file. */
|
||||
analyze_hunk (hunk, &f0, &l0, &f1, &l1, &deletes, &inserts);
|
||||
if (!deletes && !inserts)
|
||||
return;
|
||||
|
||||
begin_output ();
|
||||
|
||||
translate_range (&files[0], f0, l0, &tf0, &tl0);
|
||||
|
||||
if (deletes)
|
||||
{
|
||||
fprintf (outfile, "d");
|
||||
/* For deletion, print just the starting line number from file 0
|
||||
and the number of lines deleted. */
|
||||
fprintf (outfile, "%d %d\n",
|
||||
tf0,
|
||||
(tl0 >= tf0 ? tl0 - tf0 + 1 : 1));
|
||||
}
|
||||
|
||||
if (inserts)
|
||||
{
|
||||
fprintf (outfile, "a");
|
||||
|
||||
/* Take last-line-number from file 0 and # lines from file 1. */
|
||||
translate_range (&files[1], f1, l1, &tf1, &tl1);
|
||||
fprintf (outfile, "%d %d\n",
|
||||
tl0,
|
||||
(tl1 >= tf1 ? tl1 - tf1 + 1 : 1));
|
||||
|
||||
/* Print the inserted lines. */
|
||||
for (i = f1; i <= l1; i++)
|
||||
print_1_line ("", &files[1].linbuf[i]);
|
||||
}
|
||||
}
|
748
contrib/diff/getopt.c
Normal file
748
contrib/diff/getopt.c
Normal file
@ -0,0 +1,748 @@
|
||||
/* 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, 93, 94
|
||||
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. */
|
||||
|
||||
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
|
||||
Ditto for AIX 3.2 and <stdlib.h>. */
|
||||
#ifndef _NO_PROTO
|
||||
#define _NO_PROTO
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifndef __STDC__
|
||||
/* This is a separate conditional since some stdc systems
|
||||
reject `defined (const)'. */
|
||||
#ifndef const
|
||||
#define const
|
||||
#endif
|
||||
#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__
|
||||
/* Don't include stdlib.h for non-GNU C libraries because some of them
|
||||
contain conflicting prototypes for getopt. */
|
||||
#include <stdlib.h>
|
||||
#endif /* GNU C library. */
|
||||
|
||||
/* 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 = NULL;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Value of POSIXLY_CORRECT environment variable. */
|
||||
static char *posixly_correct;
|
||||
|
||||
#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
|
||||
#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;
|
||||
}
|
||||
|
||||
/* If using GCC, we can safely declare strlen this way.
|
||||
If not using GCC, it is ok not to declare it. */
|
||||
#ifdef __GNUC__
|
||||
/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
|
||||
That was relevant to code that was here before. */
|
||||
#ifndef __STDC__
|
||||
/* gcc with -traditional declares the built-in strlen to return int,
|
||||
and has done so at least since version 2.4.5. -- rms. */
|
||||
extern int strlen (const char *);
|
||||
#endif /* not __STDC__ */
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
#endif /* not __GNU_LIBRARY__ */
|
||||
|
||||
/* 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 bottom = first_nonopt;
|
||||
int middle = last_nonopt;
|
||||
int top = optind;
|
||||
char *tem;
|
||||
|
||||
/* Exchange the shorter segment with the far end of the longer segment.
|
||||
That puts the shorter segment into the right place.
|
||||
It leaves the longer segment in the right place overall,
|
||||
but it consists of two parts that need to be swapped next. */
|
||||
|
||||
while (top > middle && middle > bottom)
|
||||
{
|
||||
if (top - middle > middle - bottom)
|
||||
{
|
||||
/* Bottom segment is the short one. */
|
||||
int len = middle - bottom;
|
||||
register int i;
|
||||
|
||||
/* Swap it with the top part of the top segment. */
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tem = argv[bottom + i];
|
||||
argv[bottom + i] = argv[top - (middle - bottom) + i];
|
||||
argv[top - (middle - bottom) + i] = tem;
|
||||
}
|
||||
/* Exclude the moved bottom segment from further swapping. */
|
||||
top -= len;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Top segment is the short one. */
|
||||
int len = top - middle;
|
||||
register int i;
|
||||
|
||||
/* Swap it with the bottom part of the bottom segment. */
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tem = argv[bottom + i];
|
||||
argv[bottom + i] = argv[middle + i];
|
||||
argv[middle + i] = tem;
|
||||
}
|
||||
/* Exclude the moved top segment from further swapping. */
|
||||
bottom += len;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update records for the slots the non-options now occupy. */
|
||||
|
||||
first_nonopt += (optind - last_nonopt);
|
||||
last_nonopt = optind;
|
||||
}
|
||||
|
||||
/* Initialize the internal data when the first call is made. */
|
||||
|
||||
static const char *
|
||||
_getopt_initialize (optstring)
|
||||
const char *optstring;
|
||||
{
|
||||
/* 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. */
|
||||
|
||||
first_nonopt = last_nonopt = optind = 1;
|
||||
|
||||
nextchar = NULL;
|
||||
|
||||
posixly_correct = getenv ("POSIXLY_CORRECT");
|
||||
|
||||
/* 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 (posixly_correct != NULL)
|
||||
ordering = REQUIRE_ORDER;
|
||||
else
|
||||
ordering = PERMUTE;
|
||||
|
||||
return optstring;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
{
|
||||
optarg = NULL;
|
||||
|
||||
if (optind == 0)
|
||||
optstring = _getopt_initialize (optstring);
|
||||
|
||||
if (nextchar == NULL || *nextchar == '\0')
|
||||
{
|
||||
/* Advance to the next ARGV-element. */
|
||||
|
||||
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;
|
||||
|
||||
/* Skip any additional non-options
|
||||
and extend the range of non-options previously skipped. */
|
||||
|
||||
while (optind < argc
|
||||
&& (argv[optind][0] != '-' || argv[optind][1] == '\0'))
|
||||
optind++;
|
||||
last_nonopt = optind;
|
||||
}
|
||||
|
||||
/* The 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'))
|
||||
{
|
||||
if (ordering == REQUIRE_ORDER)
|
||||
return EOF;
|
||||
optarg = argv[optind++];
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We have found another option-ARGV-element.
|
||||
Skip the initial punctuation. */
|
||||
|
||||
nextchar = (argv[optind] + 1
|
||||
+ (longopts != NULL && argv[optind][1] == '-'));
|
||||
}
|
||||
|
||||
/* Decode the current option-ARGV-element. */
|
||||
|
||||
/* Check whether the ARGV-element is a long option.
|
||||
|
||||
If long_only and the ARGV-element has the form "-f", where f is
|
||||
a valid short option, don't consider it an abbreviated form of
|
||||
a long option that starts with f. Otherwise there would be no
|
||||
way to give the -f short option.
|
||||
|
||||
On the other hand, if there's a long option "fubar" and
|
||||
the ARGV-element is "-fu", do consider that an abbreviation of
|
||||
the long option, just like "--fu", and not "-f" with arg "u".
|
||||
|
||||
This distinction seems to be the most useful approach. */
|
||||
|
||||
if (longopts != NULL
|
||||
&& (argv[optind][1] == '-'
|
||||
|| (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
|
||||
{
|
||||
char *nameend;
|
||||
const struct option *p;
|
||||
const struct option *pfound = NULL;
|
||||
int exact = 0;
|
||||
int ambig = 0;
|
||||
int indfound;
|
||||
int option_index;
|
||||
|
||||
for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
|
||||
/* Do nothing. */ ;
|
||||
|
||||
/* Test all long options for either exact match
|
||||
or abbreviated matches. */
|
||||
for (p = longopts, option_index = 0; p->name; p++, option_index++)
|
||||
if (!strncmp (p->name, nextchar, nameend - nextchar))
|
||||
{
|
||||
if (nameend - 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 or later 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 (*nameend)
|
||||
{
|
||||
/* Don't test has_arg with >, because some C compilers don't
|
||||
allow it to be used on enums. */
|
||||
if (pfound->has_arg)
|
||||
optarg = nameend + 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] == '-'
|
||||
|| 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 short 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 (posixly_correct)
|
||||
/* 1003.2 specifies the format of this message. */
|
||||
fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
|
||||
else
|
||||
fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c);
|
||||
}
|
||||
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 = NULL;
|
||||
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)
|
||||
{
|
||||
/* 1003.2 specifies the format of this message. */
|
||||
fprintf (stderr, "%s: option requires an argument -- %c\n",
|
||||
argv[0], c);
|
||||
}
|
||||
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__. */
|
||||
|
||||
#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 */
|
129
contrib/diff/getopt.h
Normal file
129
contrib/diff/getopt.h
Normal file
@ -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 */
|
180
contrib/diff/getopt1.c
Normal file
180
contrib/diff/getopt1.c
Normal file
@ -0,0 +1,180 @@
|
||||
/* 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. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
#ifndef __STDC__
|
||||
/* This is a separate conditional since some stdc systems
|
||||
reject `defined (const)'. */
|
||||
#ifndef const
|
||||
#define const
|
||||
#endif
|
||||
#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__. */
|
||||
|
||||
#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 */
|
428
contrib/diff/ifdef.c
Normal file
428
contrib/diff/ifdef.c
Normal file
@ -0,0 +1,428 @@
|
||||
/* #ifdef-format output routines for GNU DIFF.
|
||||
Copyright (C) 1989, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU DIFF.
|
||||
|
||||
GNU DIFF is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY. No author or distributor
|
||||
accepts responsibility to anyone for the consequences of using it
|
||||
or for whether it serves any particular purpose or works at all,
|
||||
unless he says so in writing. Refer to the GNU DIFF General Public
|
||||
License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute
|
||||
GNU DIFF, but only under the conditions described in the
|
||||
GNU DIFF General Public License. A copy of this license is
|
||||
supposed to have been given to you along with GNU DIFF so you
|
||||
can know your rights and responsibilities. It should be in a
|
||||
file named COPYING. Among other things, the copyright notice
|
||||
and this notice must be preserved on all copies. */
|
||||
|
||||
|
||||
#include "diff.h"
|
||||
|
||||
struct group
|
||||
{
|
||||
struct file_data const *file;
|
||||
int from, upto; /* start and limit lines for this group of lines */
|
||||
};
|
||||
|
||||
static char *format_group PARAMS((FILE *, char *, int, struct group const *));
|
||||
static char *scan_char_literal PARAMS((char *, int *));
|
||||
static char *scan_printf_spec PARAMS((char *));
|
||||
static int groups_letter_value PARAMS((struct group const *, int));
|
||||
static void format_ifdef PARAMS((char *, int, int, int, int));
|
||||
static void print_ifdef_hunk PARAMS((struct change *));
|
||||
static void print_ifdef_lines PARAMS((FILE *, char *, struct group const *));
|
||||
|
||||
static int next_line;
|
||||
|
||||
/* Print the edit-script SCRIPT as a merged #ifdef file. */
|
||||
|
||||
void
|
||||
print_ifdef_script (script)
|
||||
struct change *script;
|
||||
{
|
||||
next_line = - files[0].prefix_lines;
|
||||
print_script (script, find_change, print_ifdef_hunk);
|
||||
if (next_line < files[0].valid_lines)
|
||||
{
|
||||
begin_output ();
|
||||
format_ifdef (group_format[UNCHANGED], next_line, files[0].valid_lines,
|
||||
next_line - files[0].valid_lines + files[1].valid_lines,
|
||||
files[1].valid_lines);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print a hunk of an ifdef diff.
|
||||
This is a contiguous portion of a complete edit script,
|
||||
describing changes in consecutive lines. */
|
||||
|
||||
static void
|
||||
print_ifdef_hunk (hunk)
|
||||
struct change *hunk;
|
||||
{
|
||||
int first0, last0, first1, last1, deletes, inserts;
|
||||
char *format;
|
||||
|
||||
/* Determine range of line numbers involved in each file. */
|
||||
analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
|
||||
if (inserts)
|
||||
format = deletes ? group_format[CHANGED] : group_format[NEW];
|
||||
else if (deletes)
|
||||
format = group_format[OLD];
|
||||
else
|
||||
return;
|
||||
|
||||
begin_output ();
|
||||
|
||||
/* Print lines up to this change. */
|
||||
if (next_line < first0)
|
||||
format_ifdef (group_format[UNCHANGED], next_line, first0,
|
||||
next_line - first0 + first1, first1);
|
||||
|
||||
/* Print this change. */
|
||||
next_line = last0 + 1;
|
||||
format_ifdef (format, first0, next_line, first1, last1 + 1);
|
||||
}
|
||||
|
||||
/* Print a set of lines according to FORMAT.
|
||||
Lines BEG0 up to END0 are from the first file;
|
||||
lines BEG1 up to END1 are from the second file. */
|
||||
|
||||
static void
|
||||
format_ifdef (format, beg0, end0, beg1, end1)
|
||||
char *format;
|
||||
int beg0, end0, beg1, end1;
|
||||
{
|
||||
struct group groups[2];
|
||||
|
||||
groups[0].file = &files[0];
|
||||
groups[0].from = beg0;
|
||||
groups[0].upto = end0;
|
||||
groups[1].file = &files[1];
|
||||
groups[1].from = beg1;
|
||||
groups[1].upto = end1;
|
||||
format_group (outfile, format, '\0', groups);
|
||||
}
|
||||
|
||||
/* Print to file OUT a set of lines according to FORMAT.
|
||||
The format ends at the first free instance of ENDCHAR.
|
||||
Yield the address of the terminating character.
|
||||
GROUPS specifies which lines to print.
|
||||
If OUT is zero, do not actually print anything; just scan the format. */
|
||||
|
||||
static char *
|
||||
format_group (out, format, endchar, groups)
|
||||
register FILE *out;
|
||||
char *format;
|
||||
int endchar;
|
||||
struct group const *groups;
|
||||
{
|
||||
register char c;
|
||||
register char *f = format;
|
||||
|
||||
while ((c = *f) != endchar && c != 0)
|
||||
{
|
||||
f++;
|
||||
if (c == '%')
|
||||
{
|
||||
char *spec = f;
|
||||
switch ((c = *f++))
|
||||
{
|
||||
case '%':
|
||||
break;
|
||||
|
||||
case '(':
|
||||
/* Print if-then-else format e.g. `%(n=1?thenpart:elsepart)'. */
|
||||
{
|
||||
int i, value[2];
|
||||
FILE *thenout, *elseout;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
unsigned char f0 = f[0];
|
||||
if (ISDIGIT (f0))
|
||||
{
|
||||
value[i] = atoi (f);
|
||||
while (ISDIGIT ((unsigned char) *++f))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
value[i] = groups_letter_value (groups, f0);
|
||||
if (value[i] < 0)
|
||||
goto bad_format;
|
||||
f++;
|
||||
}
|
||||
if (*f++ != "=?"[i])
|
||||
goto bad_format;
|
||||
}
|
||||
if (value[0] == value[1])
|
||||
thenout = out, elseout = 0;
|
||||
else
|
||||
thenout = 0, elseout = out;
|
||||
f = format_group (thenout, f, ':', groups);
|
||||
if (*f)
|
||||
{
|
||||
f = format_group (elseout, f + 1, ')', groups);
|
||||
if (*f)
|
||||
f++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
case '<':
|
||||
/* Print lines deleted from first file. */
|
||||
print_ifdef_lines (out, line_format[OLD], &groups[0]);
|
||||
continue;
|
||||
|
||||
case '=':
|
||||
/* Print common lines. */
|
||||
print_ifdef_lines (out, line_format[UNCHANGED], &groups[0]);
|
||||
continue;
|
||||
|
||||
case '>':
|
||||
/* Print lines inserted from second file. */
|
||||
print_ifdef_lines (out, line_format[NEW], &groups[1]);
|
||||
continue;
|
||||
|
||||
default:
|
||||
{
|
||||
int value;
|
||||
char *speclim;
|
||||
|
||||
f = scan_printf_spec (spec);
|
||||
if (!f)
|
||||
goto bad_format;
|
||||
speclim = f;
|
||||
c = *f++;
|
||||
switch (c)
|
||||
{
|
||||
case '\'':
|
||||
f = scan_char_literal (f, &value);
|
||||
if (!f)
|
||||
goto bad_format;
|
||||
break;
|
||||
|
||||
default:
|
||||
value = groups_letter_value (groups, c);
|
||||
if (value < 0)
|
||||
goto bad_format;
|
||||
break;
|
||||
}
|
||||
if (out)
|
||||
{
|
||||
/* Temporarily replace e.g. "%3dnx" with "%3d\0x". */
|
||||
*speclim = 0;
|
||||
fprintf (out, spec - 1, value);
|
||||
/* Undo the temporary replacement. */
|
||||
*speclim = c;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
bad_format:
|
||||
c = '%';
|
||||
f = spec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (out)
|
||||
putc (c, out);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
/* For the line group pair G, return the number corresponding to LETTER.
|
||||
Return -1 if LETTER is not a group format letter. */
|
||||
static int
|
||||
groups_letter_value (g, letter)
|
||||
struct group const *g;
|
||||
int letter;
|
||||
{
|
||||
if (ISUPPER (letter))
|
||||
{
|
||||
g++;
|
||||
letter = tolower (letter);
|
||||
}
|
||||
switch (letter)
|
||||
{
|
||||
case 'e': return translate_line_number (g->file, g->from) - 1;
|
||||
case 'f': return translate_line_number (g->file, g->from);
|
||||
case 'l': return translate_line_number (g->file, g->upto) - 1;
|
||||
case 'm': return translate_line_number (g->file, g->upto);
|
||||
case 'n': return g->upto - g->from;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print to file OUT, using FORMAT to print the line group GROUP.
|
||||
But do nothing if OUT is zero. */
|
||||
static void
|
||||
print_ifdef_lines (out, format, group)
|
||||
register FILE *out;
|
||||
char *format;
|
||||
struct group const *group;
|
||||
{
|
||||
struct file_data const *file = group->file;
|
||||
char const * const *linbuf = file->linbuf;
|
||||
int from = group->from, upto = group->upto;
|
||||
|
||||
if (!out)
|
||||
return;
|
||||
|
||||
/* If possible, use a single fwrite; it's faster. */
|
||||
if (!tab_expand_flag && format[0] == '%')
|
||||
{
|
||||
if (format[1] == 'l' && format[2] == '\n' && !format[3])
|
||||
{
|
||||
fwrite (linbuf[from], sizeof (char),
|
||||
linbuf[upto] + (linbuf[upto][-1] != '\n') - linbuf[from],
|
||||
out);
|
||||
return;
|
||||
}
|
||||
if (format[1] == 'L' && !format[2])
|
||||
{
|
||||
fwrite (linbuf[from], sizeof (char),
|
||||
linbuf[upto] - linbuf[from], out);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (; from < upto; from++)
|
||||
{
|
||||
register char c;
|
||||
register char *f = format;
|
||||
|
||||
while ((c = *f++) != 0)
|
||||
{
|
||||
if (c == '%')
|
||||
{
|
||||
char *spec = f;
|
||||
switch ((c = *f++))
|
||||
{
|
||||
case '%':
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
output_1_line (linbuf[from],
|
||||
linbuf[from + 1]
|
||||
- (linbuf[from + 1][-1] == '\n'), 0, 0);
|
||||
continue;
|
||||
|
||||
case 'L':
|
||||
output_1_line (linbuf[from], linbuf[from + 1], 0, 0);
|
||||
continue;
|
||||
|
||||
default:
|
||||
{
|
||||
int value;
|
||||
char *speclim;
|
||||
|
||||
f = scan_printf_spec (spec);
|
||||
if (!f)
|
||||
goto bad_format;
|
||||
speclim = f;
|
||||
c = *f++;
|
||||
switch (c)
|
||||
{
|
||||
case '\'':
|
||||
f = scan_char_literal (f, &value);
|
||||
if (!f)
|
||||
goto bad_format;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
value = translate_line_number (file, from);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto bad_format;
|
||||
}
|
||||
/* Temporarily replace e.g. "%3dnx" with "%3d\0x". */
|
||||
*speclim = 0;
|
||||
fprintf (out, spec - 1, value);
|
||||
/* Undo the temporary replacement. */
|
||||
*speclim = c;
|
||||
}
|
||||
continue;
|
||||
|
||||
bad_format:
|
||||
c = '%';
|
||||
f = spec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
putc (c, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan the character literal represented in the string LIT; LIT points just
|
||||
after the initial apostrophe. Put the literal's value into *INTPTR.
|
||||
Yield the address of the first character after the closing apostrophe,
|
||||
or zero if the literal is ill-formed. */
|
||||
static char *
|
||||
scan_char_literal (lit, intptr)
|
||||
char *lit;
|
||||
int *intptr;
|
||||
{
|
||||
register char *p = lit;
|
||||
int value, digits;
|
||||
char c = *p++;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 0:
|
||||
case '\'':
|
||||
return 0;
|
||||
|
||||
case '\\':
|
||||
value = 0;
|
||||
while ((c = *p++) != '\'')
|
||||
{
|
||||
unsigned digit = c - '0';
|
||||
if (8 <= digit)
|
||||
return 0;
|
||||
value = 8 * value + digit;
|
||||
}
|
||||
digits = p - lit - 2;
|
||||
if (! (1 <= digits && digits <= 3))
|
||||
return 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
value = c;
|
||||
if (*p++ != '\'')
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
*intptr = value;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Scan optional printf-style SPEC of the form `-*[0-9]*(.[0-9]*)?[cdoxX]'.
|
||||
Return the address of the character following SPEC, or zero if failure. */
|
||||
static char *
|
||||
scan_printf_spec (spec)
|
||||
register char *spec;
|
||||
{
|
||||
register unsigned char c;
|
||||
|
||||
while ((c = *spec++) == '-')
|
||||
continue;
|
||||
while (ISDIGIT (c))
|
||||
c = *spec++;
|
||||
if (c == '.')
|
||||
while (ISDIGIT (c = *spec++))
|
||||
continue;
|
||||
switch (c)
|
||||
{
|
||||
case 'c': case 'd': case 'o': case 'x': case 'X':
|
||||
return spec;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
714
contrib/diff/io.c
Normal file
714
contrib/diff/io.c
Normal file
@ -0,0 +1,714 @@
|
||||
/* File I/O for GNU DIFF.
|
||||
Copyright (C) 1988, 1989, 1992, 1993, 1994 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 "diff.h"
|
||||
|
||||
/* Rotate a value n bits to the left. */
|
||||
#define UINT_BIT (sizeof (unsigned) * CHAR_BIT)
|
||||
#define ROL(v, n) ((v) << (n) | (v) >> (UINT_BIT - (n)))
|
||||
|
||||
/* Given a hash value and a new character, return a new hash value. */
|
||||
#define HASH(h, c) ((c) + ROL (h, 7))
|
||||
|
||||
/* Guess remaining number of lines from number N of lines so far,
|
||||
size S so far, and total size T. */
|
||||
#define GUESS_LINES(n,s,t) (((t) - (s)) / ((n) < 10 ? 32 : (s) / ((n)-1)) + 5)
|
||||
|
||||
/* Type used for fast prefix comparison in find_identical_ends. */
|
||||
#ifndef word
|
||||
#define word int
|
||||
#endif
|
||||
|
||||
/* Lines are put into equivalence classes (of lines that match in line_cmp).
|
||||
Each equivalence class is represented by one of these structures,
|
||||
but only while the classes are being computed.
|
||||
Afterward, each class is represented by a number. */
|
||||
struct equivclass
|
||||
{
|
||||
int next; /* Next item in this bucket. */
|
||||
unsigned hash; /* Hash of lines in this class. */
|
||||
char const *line; /* A line that fits this class. */
|
||||
size_t length; /* That line's length, not counting its newline. */
|
||||
};
|
||||
|
||||
/* Hash-table: array of buckets, each being a chain of equivalence classes.
|
||||
buckets[-1] is reserved for incomplete lines. */
|
||||
static int *buckets;
|
||||
|
||||
/* Number of buckets in the hash table array, not counting buckets[-1]. */
|
||||
static int nbuckets;
|
||||
|
||||
/* Array in which the equivalence classes are allocated.
|
||||
The bucket-chains go through the elements in this array.
|
||||
The number of an equivalence class is its index in this array. */
|
||||
static struct equivclass *equivs;
|
||||
|
||||
/* Index of first free element in the array `equivs'. */
|
||||
static int equivs_index;
|
||||
|
||||
/* Number of elements allocated in the array `equivs'. */
|
||||
static int equivs_alloc;
|
||||
|
||||
static void find_and_hash_each_line PARAMS((struct file_data *));
|
||||
static void find_identical_ends PARAMS((struct file_data[]));
|
||||
static void prepare_text_end PARAMS((struct file_data *));
|
||||
|
||||
/* Check for binary files and compare them for exact identity. */
|
||||
|
||||
/* Return 1 if BUF contains a non text character.
|
||||
SIZE is the number of characters in BUF. */
|
||||
|
||||
#define binary_file_p(buf, size) (memchr (buf, '\0', size) != 0)
|
||||
|
||||
/* Get ready to read the current file.
|
||||
Return nonzero if SKIP_TEST is zero,
|
||||
and if it appears to be a binary file. */
|
||||
|
||||
int
|
||||
sip (current, skip_test)
|
||||
struct file_data *current;
|
||||
int skip_test;
|
||||
{
|
||||
/* If we have a nonexistent file at this stage, treat it as empty. */
|
||||
if (current->desc < 0)
|
||||
{
|
||||
/* Leave room for a sentinel. */
|
||||
current->bufsize = sizeof (word);
|
||||
current->buffer = xmalloc (current->bufsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
current->bufsize = STAT_BLOCKSIZE (current->stat);
|
||||
current->buffer = xmalloc (current->bufsize);
|
||||
|
||||
if (! skip_test)
|
||||
{
|
||||
/* Check first part of file to see if it's a binary file. */
|
||||
#if HAVE_SETMODE
|
||||
int oldmode = setmode (current->desc, O_BINARY);
|
||||
#endif
|
||||
size_t n = read (current->desc, current->buffer, current->bufsize);
|
||||
if (n == -1)
|
||||
pfatal_with_name (current->name);
|
||||
current->buffered_chars = n;
|
||||
#if HAVE_SETMODE
|
||||
if (oldmode != O_BINARY)
|
||||
{
|
||||
if (lseek (current->desc, - (off_t) n, SEEK_CUR) == -1)
|
||||
pfatal_with_name (current->name);
|
||||
setmode (current->desc, oldmode);
|
||||
current->buffered_chars = 0;
|
||||
}
|
||||
#endif
|
||||
return binary_file_p (current->buffer, n);
|
||||
}
|
||||
}
|
||||
|
||||
current->buffered_chars = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Slurp the rest of the current file completely into memory. */
|
||||
|
||||
void
|
||||
slurp (current)
|
||||
struct file_data *current;
|
||||
{
|
||||
size_t cc;
|
||||
|
||||
if (current->desc < 0)
|
||||
/* The file is nonexistent. */
|
||||
;
|
||||
else if (S_ISREG (current->stat.st_mode))
|
||||
{
|
||||
/* It's a regular file; slurp in the rest all at once. */
|
||||
|
||||
/* Get the size out of the stat block.
|
||||
Allocate enough room for appended newline and sentinel. */
|
||||
cc = current->stat.st_size + 1 + sizeof (word);
|
||||
if (current->bufsize < cc)
|
||||
{
|
||||
current->bufsize = cc;
|
||||
current->buffer = xrealloc (current->buffer, cc);
|
||||
}
|
||||
|
||||
if (current->buffered_chars < current->stat.st_size)
|
||||
{
|
||||
cc = read (current->desc,
|
||||
current->buffer + current->buffered_chars,
|
||||
current->stat.st_size - current->buffered_chars);
|
||||
if (cc == -1)
|
||||
pfatal_with_name (current->name);
|
||||
current->buffered_chars += cc;
|
||||
}
|
||||
}
|
||||
/* It's not a regular file; read it, growing the buffer as needed. */
|
||||
else if (always_text_flag || current->buffered_chars != 0)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (current->buffered_chars == current->bufsize)
|
||||
{
|
||||
current->bufsize = current->bufsize * 2;
|
||||
current->buffer = xrealloc (current->buffer, current->bufsize);
|
||||
}
|
||||
cc = read (current->desc,
|
||||
current->buffer + current->buffered_chars,
|
||||
current->bufsize - current->buffered_chars);
|
||||
if (cc == 0)
|
||||
break;
|
||||
if (cc == -1)
|
||||
pfatal_with_name (current->name);
|
||||
current->buffered_chars += cc;
|
||||
}
|
||||
/* Allocate just enough room for appended newline and sentinel. */
|
||||
current->bufsize = current->buffered_chars + 1 + sizeof (word);
|
||||
current->buffer = xrealloc (current->buffer, current->bufsize);
|
||||
}
|
||||
}
|
||||
|
||||
/* Split the file into lines, simultaneously computing the equivalence class for
|
||||
each line. */
|
||||
|
||||
static void
|
||||
find_and_hash_each_line (current)
|
||||
struct file_data *current;
|
||||
{
|
||||
unsigned h;
|
||||
unsigned char const *p = (unsigned char const *) current->prefix_end;
|
||||
unsigned char c;
|
||||
int i, *bucket;
|
||||
size_t length;
|
||||
|
||||
/* Cache often-used quantities in local variables to help the compiler. */
|
||||
char const **linbuf = current->linbuf;
|
||||
int alloc_lines = current->alloc_lines;
|
||||
int line = 0;
|
||||
int linbuf_base = current->linbuf_base;
|
||||
int *cureqs = (int *) xmalloc (alloc_lines * sizeof (int));
|
||||
struct equivclass *eqs = equivs;
|
||||
int eqs_index = equivs_index;
|
||||
int eqs_alloc = equivs_alloc;
|
||||
char const *suffix_begin = current->suffix_begin;
|
||||
char const *bufend = current->buffer + current->buffered_chars;
|
||||
int use_line_cmp = ignore_some_line_changes;
|
||||
|
||||
while ((char const *) p < suffix_begin)
|
||||
{
|
||||
char const *ip = (char const *) p;
|
||||
|
||||
/* Compute the equivalence class for this line. */
|
||||
|
||||
h = 0;
|
||||
|
||||
/* Hash this line until we find a newline. */
|
||||
if (ignore_case_flag)
|
||||
{
|
||||
if (ignore_all_space_flag)
|
||||
while ((c = *p++) != '\n')
|
||||
{
|
||||
if (! ISSPACE (c))
|
||||
h = HASH (h, ISUPPER (c) ? tolower (c) : c);
|
||||
}
|
||||
else if (ignore_space_change_flag)
|
||||
while ((c = *p++) != '\n')
|
||||
{
|
||||
if (ISSPACE (c))
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
c = *p++;
|
||||
if (!ISSPACE (c))
|
||||
break;
|
||||
if (c == '\n')
|
||||
goto hashing_done;
|
||||
}
|
||||
h = HASH (h, ' ');
|
||||
}
|
||||
/* C is now the first non-space. */
|
||||
h = HASH (h, ISUPPER (c) ? tolower (c) : c);
|
||||
}
|
||||
else
|
||||
while ((c = *p++) != '\n')
|
||||
h = HASH (h, ISUPPER (c) ? tolower (c) : c);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ignore_all_space_flag)
|
||||
while ((c = *p++) != '\n')
|
||||
{
|
||||
if (! ISSPACE (c))
|
||||
h = HASH (h, c);
|
||||
}
|
||||
else if (ignore_space_change_flag)
|
||||
while ((c = *p++) != '\n')
|
||||
{
|
||||
if (ISSPACE (c))
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
c = *p++;
|
||||
if (!ISSPACE (c))
|
||||
break;
|
||||
if (c == '\n')
|
||||
goto hashing_done;
|
||||
}
|
||||
h = HASH (h, ' ');
|
||||
}
|
||||
/* C is now the first non-space. */
|
||||
h = HASH (h, c);
|
||||
}
|
||||
else
|
||||
while ((c = *p++) != '\n')
|
||||
h = HASH (h, c);
|
||||
}
|
||||
hashing_done:;
|
||||
|
||||
bucket = &buckets[h % nbuckets];
|
||||
length = (char const *) p - ip - 1;
|
||||
|
||||
if ((char const *) p == bufend
|
||||
&& current->missing_newline
|
||||
&& ROBUST_OUTPUT_STYLE (output_style))
|
||||
{
|
||||
/* This line is incomplete. If this is significant,
|
||||
put the line into bucket[-1]. */
|
||||
if (! (ignore_space_change_flag | ignore_all_space_flag))
|
||||
bucket = &buckets[-1];
|
||||
|
||||
/* Omit the inserted newline when computing linbuf later. */
|
||||
p--;
|
||||
bufend = suffix_begin = (char const *) p;
|
||||
}
|
||||
|
||||
for (i = *bucket; ; i = eqs[i].next)
|
||||
if (!i)
|
||||
{
|
||||
/* Create a new equivalence class in this bucket. */
|
||||
i = eqs_index++;
|
||||
if (i == eqs_alloc)
|
||||
eqs = (struct equivclass *)
|
||||
xrealloc (eqs, (eqs_alloc*=2) * sizeof(*eqs));
|
||||
eqs[i].next = *bucket;
|
||||
eqs[i].hash = h;
|
||||
eqs[i].line = ip;
|
||||
eqs[i].length = length;
|
||||
*bucket = i;
|
||||
break;
|
||||
}
|
||||
else if (eqs[i].hash == h)
|
||||
{
|
||||
char const *eqline = eqs[i].line;
|
||||
|
||||
/* Reuse existing equivalence class if the lines are identical.
|
||||
This detects the common case of exact identity
|
||||
faster than complete comparison would. */
|
||||
if (eqs[i].length == length && memcmp (eqline, ip, length) == 0)
|
||||
break;
|
||||
|
||||
/* Reuse existing class if line_cmp reports the lines equal. */
|
||||
if (use_line_cmp && line_cmp (eqline, ip) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Maybe increase the size of the line table. */
|
||||
if (line == alloc_lines)
|
||||
{
|
||||
/* Double (alloc_lines - linbuf_base) by adding to alloc_lines. */
|
||||
alloc_lines = 2 * alloc_lines - linbuf_base;
|
||||
cureqs = (int *) xrealloc (cureqs, alloc_lines * sizeof (*cureqs));
|
||||
linbuf = (char const **) xrealloc (linbuf + linbuf_base,
|
||||
(alloc_lines - linbuf_base)
|
||||
* sizeof (*linbuf))
|
||||
- linbuf_base;
|
||||
}
|
||||
linbuf[line] = ip;
|
||||
cureqs[line] = i;
|
||||
++line;
|
||||
}
|
||||
|
||||
current->buffered_lines = line;
|
||||
|
||||
for (i = 0; ; i++)
|
||||
{
|
||||
/* Record the line start for lines in the suffix that we care about.
|
||||
Record one more line start than lines,
|
||||
so that we can compute the length of any buffered line. */
|
||||
if (line == alloc_lines)
|
||||
{
|
||||
/* Double (alloc_lines - linbuf_base) by adding to alloc_lines. */
|
||||
alloc_lines = 2 * alloc_lines - linbuf_base;
|
||||
linbuf = (char const **) xrealloc (linbuf + linbuf_base,
|
||||
(alloc_lines - linbuf_base)
|
||||
* sizeof (*linbuf))
|
||||
- linbuf_base;
|
||||
}
|
||||
linbuf[line] = (char const *) p;
|
||||
|
||||
if ((char const *) p == bufend)
|
||||
break;
|
||||
|
||||
if (context <= i && no_diff_means_no_output)
|
||||
break;
|
||||
|
||||
line++;
|
||||
|
||||
while (*p++ != '\n')
|
||||
;
|
||||
}
|
||||
|
||||
/* Done with cache in local variables. */
|
||||
current->linbuf = linbuf;
|
||||
current->valid_lines = line;
|
||||
current->alloc_lines = alloc_lines;
|
||||
current->equivs = cureqs;
|
||||
equivs = eqs;
|
||||
equivs_alloc = eqs_alloc;
|
||||
equivs_index = eqs_index;
|
||||
}
|
||||
|
||||
/* Prepare the end of the text. Make sure it's initialized.
|
||||
Make sure text ends in a newline,
|
||||
but remember that we had to add one. */
|
||||
|
||||
static void
|
||||
prepare_text_end (current)
|
||||
struct file_data *current;
|
||||
{
|
||||
size_t buffered_chars = current->buffered_chars;
|
||||
char *p = current->buffer;
|
||||
|
||||
if (buffered_chars == 0 || p[buffered_chars - 1] == '\n')
|
||||
current->missing_newline = 0;
|
||||
else
|
||||
{
|
||||
p[buffered_chars++] = '\n';
|
||||
current->buffered_chars = buffered_chars;
|
||||
current->missing_newline = 1;
|
||||
}
|
||||
|
||||
/* Don't use uninitialized storage when planting or using sentinels. */
|
||||
if (p)
|
||||
bzero (p + buffered_chars, sizeof (word));
|
||||
}
|
||||
|
||||
/* Given a vector of two file_data objects, find the identical
|
||||
prefixes and suffixes of each object. */
|
||||
|
||||
static void
|
||||
find_identical_ends (filevec)
|
||||
struct file_data filevec[];
|
||||
{
|
||||
word *w0, *w1;
|
||||
char *p0, *p1, *buffer0, *buffer1;
|
||||
char const *end0, *beg0;
|
||||
char const **linbuf0, **linbuf1;
|
||||
int i, lines;
|
||||
size_t n0, n1, tem;
|
||||
int alloc_lines0, alloc_lines1;
|
||||
int buffered_prefix, prefix_count, prefix_mask;
|
||||
|
||||
slurp (&filevec[0]);
|
||||
if (filevec[0].desc != filevec[1].desc)
|
||||
slurp (&filevec[1]);
|
||||
else
|
||||
{
|
||||
filevec[1].buffer = filevec[0].buffer;
|
||||
filevec[1].bufsize = filevec[0].bufsize;
|
||||
filevec[1].buffered_chars = filevec[0].buffered_chars;
|
||||
}
|
||||
for (i = 0; i < 2; i++)
|
||||
prepare_text_end (&filevec[i]);
|
||||
|
||||
/* Find identical prefix. */
|
||||
|
||||
p0 = buffer0 = filevec[0].buffer;
|
||||
p1 = buffer1 = filevec[1].buffer;
|
||||
|
||||
n0 = filevec[0].buffered_chars;
|
||||
n1 = filevec[1].buffered_chars;
|
||||
|
||||
if (p0 == p1)
|
||||
/* The buffers are the same; sentinels won't work. */
|
||||
p0 = p1 += n1;
|
||||
else
|
||||
{
|
||||
/* Insert end sentinels, in this case characters that are guaranteed
|
||||
to make the equality test false, and thus terminate the loop. */
|
||||
|
||||
if (n0 < n1)
|
||||
p0[n0] = ~p1[n0];
|
||||
else
|
||||
p1[n1] = ~p0[n1];
|
||||
|
||||
/* Loop until first mismatch, or to the sentinel characters. */
|
||||
|
||||
/* Compare a word at a time for speed. */
|
||||
w0 = (word *) p0;
|
||||
w1 = (word *) p1;
|
||||
while (*w0++ == *w1++)
|
||||
;
|
||||
--w0, --w1;
|
||||
|
||||
/* Do the last few bytes of comparison a byte at a time. */
|
||||
p0 = (char *) w0;
|
||||
p1 = (char *) w1;
|
||||
while (*p0++ == *p1++)
|
||||
;
|
||||
--p0, --p1;
|
||||
|
||||
/* Don't mistakenly count missing newline as part of prefix. */
|
||||
if (ROBUST_OUTPUT_STYLE (output_style)
|
||||
&& (buffer0 + n0 - filevec[0].missing_newline < p0)
|
||||
!=
|
||||
(buffer1 + n1 - filevec[1].missing_newline < p1))
|
||||
--p0, --p1;
|
||||
}
|
||||
|
||||
/* Now P0 and P1 point at the first nonmatching characters. */
|
||||
|
||||
/* Skip back to last line-beginning in the prefix,
|
||||
and then discard up to HORIZON_LINES lines from the prefix. */
|
||||
i = horizon_lines;
|
||||
while (p0 != buffer0 && (p0[-1] != '\n' || i--))
|
||||
--p0, --p1;
|
||||
|
||||
/* Record the prefix. */
|
||||
filevec[0].prefix_end = p0;
|
||||
filevec[1].prefix_end = p1;
|
||||
|
||||
/* Find identical suffix. */
|
||||
|
||||
/* P0 and P1 point beyond the last chars not yet compared. */
|
||||
p0 = buffer0 + n0;
|
||||
p1 = buffer1 + n1;
|
||||
|
||||
if (! ROBUST_OUTPUT_STYLE (output_style)
|
||||
|| filevec[0].missing_newline == filevec[1].missing_newline)
|
||||
{
|
||||
end0 = p0; /* Addr of last char in file 0. */
|
||||
|
||||
/* Get value of P0 at which we should stop scanning backward:
|
||||
this is when either P0 or P1 points just past the last char
|
||||
of the identical prefix. */
|
||||
beg0 = filevec[0].prefix_end + (n0 < n1 ? 0 : n0 - n1);
|
||||
|
||||
/* Scan back until chars don't match or we reach that point. */
|
||||
while (p0 != beg0)
|
||||
if (*--p0 != *--p1)
|
||||
{
|
||||
/* Point at the first char of the matching suffix. */
|
||||
++p0, ++p1;
|
||||
beg0 = p0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Are we at a line-beginning in both files? If not, add the rest of
|
||||
this line to the main body. Discard up to HORIZON_LINES lines from
|
||||
the identical suffix. Also, discard one extra line,
|
||||
because shift_boundaries may need it. */
|
||||
i = horizon_lines + !((buffer0 == p0 || p0[-1] == '\n')
|
||||
&&
|
||||
(buffer1 == p1 || p1[-1] == '\n'));
|
||||
while (i-- && p0 != end0)
|
||||
while (*p0++ != '\n')
|
||||
;
|
||||
|
||||
p1 += p0 - beg0;
|
||||
}
|
||||
|
||||
/* Record the suffix. */
|
||||
filevec[0].suffix_begin = p0;
|
||||
filevec[1].suffix_begin = p1;
|
||||
|
||||
/* Calculate number of lines of prefix to save.
|
||||
|
||||
prefix_count == 0 means save the whole prefix;
|
||||
we need this with for options like -D that output the whole file.
|
||||
We also need it for options like -F that output some preceding line;
|
||||
at least we will need to find the last few lines,
|
||||
but since we don't know how many, it's easiest to find them all.
|
||||
|
||||
Otherwise, prefix_count != 0. Save just prefix_count lines at start
|
||||
of the line buffer; they'll be moved to the proper location later.
|
||||
Handle 1 more line than the context says (because we count 1 too many),
|
||||
rounded up to the next power of 2 to speed index computation. */
|
||||
|
||||
if (no_diff_means_no_output && ! function_regexp_list)
|
||||
{
|
||||
for (prefix_count = 1; prefix_count < context + 1; prefix_count *= 2)
|
||||
;
|
||||
prefix_mask = prefix_count - 1;
|
||||
alloc_lines0
|
||||
= prefix_count
|
||||
+ GUESS_LINES (0, 0, p0 - filevec[0].prefix_end)
|
||||
+ context;
|
||||
}
|
||||
else
|
||||
{
|
||||
prefix_count = 0;
|
||||
prefix_mask = ~0;
|
||||
alloc_lines0 = GUESS_LINES (0, 0, n0);
|
||||
}
|
||||
|
||||
lines = 0;
|
||||
linbuf0 = (char const **) xmalloc (alloc_lines0 * sizeof (*linbuf0));
|
||||
|
||||
/* If the prefix is needed, find the prefix lines. */
|
||||
if (! (no_diff_means_no_output
|
||||
&& filevec[0].prefix_end == p0
|
||||
&& filevec[1].prefix_end == p1))
|
||||
{
|
||||
p0 = buffer0;
|
||||
end0 = filevec[0].prefix_end;
|
||||
while (p0 != end0)
|
||||
{
|
||||
int l = lines++ & prefix_mask;
|
||||
if (l == alloc_lines0)
|
||||
linbuf0 = (char const **) xrealloc (linbuf0, (alloc_lines0 *= 2)
|
||||
* sizeof(*linbuf0));
|
||||
linbuf0[l] = p0;
|
||||
while (*p0++ != '\n')
|
||||
;
|
||||
}
|
||||
}
|
||||
buffered_prefix = prefix_count && context < lines ? context : lines;
|
||||
|
||||
/* Allocate line buffer 1. */
|
||||
tem = prefix_count ? filevec[1].suffix_begin - buffer1 : n1;
|
||||
|
||||
alloc_lines1
|
||||
= (buffered_prefix
|
||||
+ GUESS_LINES (lines, filevec[1].prefix_end - buffer1, tem)
|
||||
+ context);
|
||||
linbuf1 = (char const **) xmalloc (alloc_lines1 * sizeof (*linbuf1));
|
||||
|
||||
if (buffered_prefix != lines)
|
||||
{
|
||||
/* Rotate prefix lines to proper location. */
|
||||
for (i = 0; i < buffered_prefix; i++)
|
||||
linbuf1[i] = linbuf0[(lines - context + i) & prefix_mask];
|
||||
for (i = 0; i < buffered_prefix; i++)
|
||||
linbuf0[i] = linbuf1[i];
|
||||
}
|
||||
|
||||
/* Initialize line buffer 1 from line buffer 0. */
|
||||
for (i = 0; i < buffered_prefix; i++)
|
||||
linbuf1[i] = linbuf0[i] - buffer0 + buffer1;
|
||||
|
||||
/* Record the line buffer, adjusted so that
|
||||
linbuf*[0] points at the first differing line. */
|
||||
filevec[0].linbuf = linbuf0 + buffered_prefix;
|
||||
filevec[1].linbuf = linbuf1 + buffered_prefix;
|
||||
filevec[0].linbuf_base = filevec[1].linbuf_base = - buffered_prefix;
|
||||
filevec[0].alloc_lines = alloc_lines0 - buffered_prefix;
|
||||
filevec[1].alloc_lines = alloc_lines1 - buffered_prefix;
|
||||
filevec[0].prefix_lines = filevec[1].prefix_lines = lines;
|
||||
}
|
||||
|
||||
/* Largest primes less than some power of two, for nbuckets. Values range
|
||||
from useful to preposterous. If one of these numbers isn't prime
|
||||
after all, don't blame it on me, blame it on primes (6) . . . */
|
||||
static int const primes[] =
|
||||
{
|
||||
509,
|
||||
1021,
|
||||
2039,
|
||||
4093,
|
||||
8191,
|
||||
16381,
|
||||
32749,
|
||||
#if 32767 < INT_MAX
|
||||
65521,
|
||||
131071,
|
||||
262139,
|
||||
524287,
|
||||
1048573,
|
||||
2097143,
|
||||
4194301,
|
||||
8388593,
|
||||
16777213,
|
||||
33554393,
|
||||
67108859, /* Preposterously large . . . */
|
||||
134217689,
|
||||
268435399,
|
||||
536870909,
|
||||
1073741789,
|
||||
2147483647,
|
||||
#endif
|
||||
0
|
||||
};
|
||||
|
||||
/* Given a vector of two file_data objects, read the file associated
|
||||
with each one, and build the table of equivalence classes.
|
||||
Return 1 if either file appears to be a binary file.
|
||||
If PRETEND_BINARY is nonzero, pretend they are binary regardless. */
|
||||
|
||||
int
|
||||
read_files (filevec, pretend_binary)
|
||||
struct file_data filevec[];
|
||||
int pretend_binary;
|
||||
{
|
||||
int i;
|
||||
int skip_test = always_text_flag | pretend_binary;
|
||||
int appears_binary = pretend_binary | sip (&filevec[0], skip_test);
|
||||
|
||||
if (filevec[0].desc != filevec[1].desc)
|
||||
appears_binary |= sip (&filevec[1], skip_test | appears_binary);
|
||||
else
|
||||
{
|
||||
filevec[1].buffer = filevec[0].buffer;
|
||||
filevec[1].bufsize = filevec[0].bufsize;
|
||||
filevec[1].buffered_chars = filevec[0].buffered_chars;
|
||||
}
|
||||
if (appears_binary)
|
||||
{
|
||||
#if HAVE_SETMODE
|
||||
setmode (filevec[0].desc, O_BINARY);
|
||||
setmode (filevec[1].desc, O_BINARY);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
find_identical_ends (filevec);
|
||||
|
||||
equivs_alloc = filevec[0].alloc_lines + filevec[1].alloc_lines + 1;
|
||||
equivs = (struct equivclass *) xmalloc (equivs_alloc * sizeof (struct equivclass));
|
||||
/* Equivalence class 0 is permanently safe for lines that were not
|
||||
hashed. Real equivalence classes start at 1. */
|
||||
equivs_index = 1;
|
||||
|
||||
for (i = 0; primes[i] < equivs_alloc / 3; i++)
|
||||
if (! primes[i])
|
||||
abort ();
|
||||
nbuckets = primes[i];
|
||||
|
||||
buckets = (int *) xmalloc ((nbuckets + 1) * sizeof (*buckets));
|
||||
bzero (buckets++, (nbuckets + 1) * sizeof (*buckets));
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
find_and_hash_each_line (&filevec[i]);
|
||||
|
||||
filevec[0].equiv_max = filevec[1].equiv_max = equivs_index;
|
||||
|
||||
free (equivs);
|
||||
free (buckets - 1);
|
||||
|
||||
return 0;
|
||||
}
|
71
contrib/diff/normal.c
Normal file
71
contrib/diff/normal.c
Normal file
@ -0,0 +1,71 @@
|
||||
/* Normal-format output routines for GNU DIFF.
|
||||
Copyright (C) 1988, 1989, 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 "diff.h"
|
||||
|
||||
static void print_normal_hunk PARAMS((struct change *));
|
||||
|
||||
/* Print the edit-script SCRIPT as a normal diff.
|
||||
INF points to an array of descriptions of the two files. */
|
||||
|
||||
void
|
||||
print_normal_script (script)
|
||||
struct change *script;
|
||||
{
|
||||
print_script (script, find_change, print_normal_hunk);
|
||||
}
|
||||
|
||||
/* Print a hunk of a normal diff.
|
||||
This is a contiguous portion of a complete edit script,
|
||||
describing changes in consecutive lines. */
|
||||
|
||||
static void
|
||||
print_normal_hunk (hunk)
|
||||
struct change *hunk;
|
||||
{
|
||||
int first0, last0, first1, last1, deletes, inserts;
|
||||
register int i;
|
||||
|
||||
/* Determine range of line numbers involved in each file. */
|
||||
analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
|
||||
if (!deletes && !inserts)
|
||||
return;
|
||||
|
||||
begin_output ();
|
||||
|
||||
/* Print out the line number header for this hunk */
|
||||
print_number_range (',', &files[0], first0, last0);
|
||||
fprintf (outfile, "%c", change_letter (inserts, deletes));
|
||||
print_number_range (',', &files[1], first1, last1);
|
||||
fprintf (outfile, "\n");
|
||||
|
||||
/* Print the lines that the first file has. */
|
||||
if (deletes)
|
||||
for (i = first0; i <= last0; i++)
|
||||
print_1_line ("<", &files[0].linbuf[i]);
|
||||
|
||||
if (inserts && deletes)
|
||||
fprintf (outfile, "---\n");
|
||||
|
||||
/* Print the lines that the second file has. */
|
||||
if (inserts)
|
||||
for (i = first1; i <= last1; i++)
|
||||
print_1_line (">", &files[1].linbuf[i]);
|
||||
}
|
1180
contrib/diff/sdiff.c
Normal file
1180
contrib/diff/sdiff.c
Normal file
File diff suppressed because it is too large
Load Diff
284
contrib/diff/side.c
Normal file
284
contrib/diff/side.c
Normal file
@ -0,0 +1,284 @@
|
||||
/* sdiff-format output routines for GNU DIFF.
|
||||
Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU DIFF.
|
||||
|
||||
GNU DIFF is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY. No author or distributor
|
||||
accepts responsibility to anyone for the consequences of using it
|
||||
or for whether it serves any particular purpose or works at all,
|
||||
unless he says so in writing. Refer to the GNU DIFF General Public
|
||||
License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute
|
||||
GNU DIFF, but only under the conditions described in the
|
||||
GNU DIFF General Public License. A copy of this license is
|
||||
supposed to have been given to you along with GNU DIFF so you
|
||||
can know your rights and responsibilities. It should be in a
|
||||
file named COPYING. Among other things, the copyright notice
|
||||
and this notice must be preserved on all copies. */
|
||||
|
||||
|
||||
#include "diff.h"
|
||||
|
||||
static unsigned print_half_line PARAMS((char const * const *, unsigned, unsigned));
|
||||
static unsigned tab_from_to PARAMS((unsigned, unsigned));
|
||||
static void print_1sdiff_line PARAMS((char const * const *, int, char const * const *));
|
||||
static void print_sdiff_common_lines PARAMS((int, int));
|
||||
static void print_sdiff_hunk PARAMS((struct change *));
|
||||
|
||||
/* Next line number to be printed in the two input files. */
|
||||
static int next0, next1;
|
||||
|
||||
/* Print the edit-script SCRIPT as a sdiff style output. */
|
||||
|
||||
void
|
||||
print_sdiff_script (script)
|
||||
struct change *script;
|
||||
{
|
||||
begin_output ();
|
||||
|
||||
next0 = next1 = - files[0].prefix_lines;
|
||||
print_script (script, find_change, print_sdiff_hunk);
|
||||
|
||||
print_sdiff_common_lines (files[0].valid_lines, files[1].valid_lines);
|
||||
}
|
||||
|
||||
/* Tab from column FROM to column TO, where FROM <= TO. Yield TO. */
|
||||
|
||||
static unsigned
|
||||
tab_from_to (from, to)
|
||||
unsigned from, to;
|
||||
{
|
||||
FILE *out = outfile;
|
||||
unsigned tab;
|
||||
|
||||
if (! tab_expand_flag)
|
||||
for (tab = from + TAB_WIDTH - from % TAB_WIDTH; tab <= to; tab += TAB_WIDTH)
|
||||
{
|
||||
putc ('\t', out);
|
||||
from = tab;
|
||||
}
|
||||
while (from++ < to)
|
||||
putc (' ', out);
|
||||
return to;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the text for half an sdiff line. This means truncate to width
|
||||
* observing tabs, and trim a trailing newline. Returns the last column
|
||||
* written (not the number of chars).
|
||||
*/
|
||||
static unsigned
|
||||
print_half_line (line, indent, out_bound)
|
||||
char const * const *line;
|
||||
unsigned indent, out_bound;
|
||||
{
|
||||
FILE *out = outfile;
|
||||
register unsigned in_position = 0, out_position = 0;
|
||||
register char const
|
||||
*text_pointer = line[0],
|
||||
*text_limit = line[1];
|
||||
|
||||
while (text_pointer < text_limit)
|
||||
{
|
||||
register unsigned char c = *text_pointer++;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\t':
|
||||
{
|
||||
unsigned spaces = TAB_WIDTH - in_position % TAB_WIDTH;
|
||||
if (in_position == out_position)
|
||||
{
|
||||
unsigned tabstop = out_position + spaces;
|
||||
if (tab_expand_flag)
|
||||
{
|
||||
if (out_bound < tabstop)
|
||||
tabstop = out_bound;
|
||||
for (; out_position < tabstop; out_position++)
|
||||
putc (' ', out);
|
||||
}
|
||||
else
|
||||
if (tabstop < out_bound)
|
||||
{
|
||||
out_position = tabstop;
|
||||
putc (c, out);
|
||||
}
|
||||
}
|
||||
in_position += spaces;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
{
|
||||
putc (c, out);
|
||||
tab_from_to (0, indent);
|
||||
in_position = out_position = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\b':
|
||||
if (in_position != 0 && --in_position < out_bound)
|
||||
if (out_position <= in_position)
|
||||
/* Add spaces to make up for suppressed tab past out_bound. */
|
||||
for (; out_position < in_position; out_position++)
|
||||
putc (' ', out);
|
||||
else
|
||||
{
|
||||
out_position = in_position;
|
||||
putc (c, out);
|
||||
}
|
||||
break;
|
||||
|
||||
case '\f':
|
||||
case '\v':
|
||||
control_char:
|
||||
if (in_position < out_bound)
|
||||
putc (c, out);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (! ISPRINT (c))
|
||||
goto control_char;
|
||||
/* falls through */
|
||||
case ' ':
|
||||
if (in_position++ < out_bound)
|
||||
{
|
||||
out_position = in_position;
|
||||
putc (c, out);
|
||||
}
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
return out_position;
|
||||
}
|
||||
}
|
||||
|
||||
return out_position;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print side by side lines with a separator in the middle.
|
||||
* 0 parameters are taken to indicate white space text.
|
||||
* Blank lines that can easily be caught are reduced to a single newline.
|
||||
*/
|
||||
|
||||
static void
|
||||
print_1sdiff_line (left, sep, right)
|
||||
char const * const *left;
|
||||
int sep;
|
||||
char const * const *right;
|
||||
{
|
||||
FILE *out = outfile;
|
||||
unsigned hw = sdiff_half_width, c2o = sdiff_column2_offset;
|
||||
unsigned col = 0;
|
||||
int put_newline = 0;
|
||||
|
||||
if (left)
|
||||
{
|
||||
if (left[1][-1] == '\n')
|
||||
put_newline = 1;
|
||||
col = print_half_line (left, 0, hw);
|
||||
}
|
||||
|
||||
if (sep != ' ')
|
||||
{
|
||||
col = tab_from_to (col, (hw + c2o - 1) / 2) + 1;
|
||||
if (sep == '|' && put_newline != (right[1][-1] == '\n'))
|
||||
sep = put_newline ? '/' : '\\';
|
||||
putc (sep, out);
|
||||
}
|
||||
|
||||
if (right)
|
||||
{
|
||||
if (right[1][-1] == '\n')
|
||||
put_newline = 1;
|
||||
if (**right != '\n')
|
||||
{
|
||||
col = tab_from_to (col, c2o);
|
||||
print_half_line (right, col, hw);
|
||||
}
|
||||
}
|
||||
|
||||
if (put_newline)
|
||||
putc ('\n', out);
|
||||
}
|
||||
|
||||
/* Print lines common to both files in side-by-side format. */
|
||||
static void
|
||||
print_sdiff_common_lines (limit0, limit1)
|
||||
int limit0, limit1;
|
||||
{
|
||||
int i0 = next0, i1 = next1;
|
||||
|
||||
if (! sdiff_skip_common_lines && (i0 != limit0 || i1 != limit1))
|
||||
{
|
||||
if (sdiff_help_sdiff)
|
||||
fprintf (outfile, "i%d,%d\n", limit0 - i0, limit1 - i1);
|
||||
|
||||
if (! sdiff_left_only)
|
||||
{
|
||||
while (i0 != limit0 && i1 != limit1)
|
||||
print_1sdiff_line (&files[0].linbuf[i0++], ' ', &files[1].linbuf[i1++]);
|
||||
while (i1 != limit1)
|
||||
print_1sdiff_line (0, ')', &files[1].linbuf[i1++]);
|
||||
}
|
||||
while (i0 != limit0)
|
||||
print_1sdiff_line (&files[0].linbuf[i0++], '(', 0);
|
||||
}
|
||||
|
||||
next0 = limit0;
|
||||
next1 = limit1;
|
||||
}
|
||||
|
||||
/* Print a hunk of an sdiff diff.
|
||||
This is a contiguous portion of a complete edit script,
|
||||
describing changes in consecutive lines. */
|
||||
|
||||
static void
|
||||
print_sdiff_hunk (hunk)
|
||||
struct change *hunk;
|
||||
{
|
||||
int first0, last0, first1, last1, deletes, inserts;
|
||||
register int i, j;
|
||||
|
||||
/* Determine range of line numbers involved in each file. */
|
||||
analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
|
||||
if (!deletes && !inserts)
|
||||
return;
|
||||
|
||||
/* Print out lines up to this change. */
|
||||
print_sdiff_common_lines (first0, first1);
|
||||
|
||||
if (sdiff_help_sdiff)
|
||||
fprintf (outfile, "c%d,%d\n", last0 - first0 + 1, last1 - first1 + 1);
|
||||
|
||||
/* Print ``xxx | xxx '' lines */
|
||||
if (inserts && deletes)
|
||||
{
|
||||
for (i = first0, j = first1; i <= last0 && j <= last1; ++i, ++j)
|
||||
print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]);
|
||||
deletes = i <= last0;
|
||||
inserts = j <= last1;
|
||||
next0 = first0 = i;
|
||||
next1 = first1 = j;
|
||||
}
|
||||
|
||||
|
||||
/* Print `` > xxx '' lines */
|
||||
if (inserts)
|
||||
{
|
||||
for (j = first1; j <= last1; ++j)
|
||||
print_1sdiff_line (0, '>', &files[1].linbuf[j]);
|
||||
next1 = j;
|
||||
}
|
||||
|
||||
/* Print ``xxx < '' lines */
|
||||
if (deletes)
|
||||
{
|
||||
for (i = first0; i <= last0; ++i)
|
||||
print_1sdiff_line (&files[0].linbuf[i], '<', 0);
|
||||
next0 = i;
|
||||
}
|
||||
}
|
1
contrib/diff/stamp-h.in
Normal file
1
contrib/diff/stamp-h.in
Normal file
@ -0,0 +1 @@
|
||||
Fri Sep 30 22:22:28 PDT 1994
|
267
contrib/diff/system.h
Normal file
267
contrib/diff/system.h
Normal file
@ -0,0 +1,267 @@
|
||||
/* System dependent declarations.
|
||||
Copyright (C) 1988, 1989, 1992, 1993, 1994 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. */
|
||||
|
||||
/* We must define `volatile' and `const' first (the latter inside config.h),
|
||||
so that they're used consistently in all system includes. */
|
||||
#if !__STDC__
|
||||
#ifndef volatile
|
||||
#define volatile
|
||||
#endif
|
||||
#endif
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if __STDC__
|
||||
#define PARAMS(args) args
|
||||
#define VOID void
|
||||
#else
|
||||
#define PARAMS(args) ()
|
||||
#define VOID char
|
||||
#endif
|
||||
|
||||
#if STAT_MACROS_BROKEN
|
||||
#undef S_ISBLK
|
||||
#undef S_ISCHR
|
||||
#undef S_ISDIR
|
||||
#undef S_ISFIFO
|
||||
#undef S_ISREG
|
||||
#undef S_ISSOCK
|
||||
#endif
|
||||
#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 !defined(S_ISBLK) && defined(S_IFBLK)
|
||||
#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
|
||||
#endif
|
||||
#if !defined(S_ISCHR) && defined(S_IFCHR)
|
||||
#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
|
||||
#endif
|
||||
#if !defined(S_ISFIFO) && defined(S_IFFIFO)
|
||||
#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO)
|
||||
#endif
|
||||
#if !defined(S_ISSOCK) && defined(S_IFSOCK)
|
||||
#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
|
||||
#endif
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_SET
|
||||
#define SEEK_SET 0
|
||||
#endif
|
||||
#ifndef SEEK_CUR
|
||||
#define SEEK_CUR 1
|
||||
#endif
|
||||
|
||||
#ifndef STDIN_FILENO
|
||||
#define STDIN_FILENO 0
|
||||
#endif
|
||||
#ifndef STDOUT_FILENO
|
||||
#define STDOUT_FILENO 1
|
||||
#endif
|
||||
#ifndef STDERR_FILENO
|
||||
#define STDERR_FILENO 2
|
||||
#endif
|
||||
|
||||
#if HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#else
|
||||
#if HAVE_SYS_FILE_H
|
||||
#include <sys/file.h>
|
||||
#endif
|
||||
#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
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
#ifndef WEXITSTATUS
|
||||
#define WEXITSTATUS(stat_val) ((unsigned) (stat_val) >> 8)
|
||||
#endif
|
||||
#ifndef WIFEXITED
|
||||
#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
|
||||
#endif
|
||||
|
||||
#ifndef STAT_BLOCKSIZE
|
||||
#if HAVE_ST_BLKSIZE
|
||||
#define STAT_BLOCKSIZE(s) (s).st_blksize
|
||||
#else
|
||||
#define STAT_BLOCKSIZE(s) (8 * 1024)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAVE_DIRENT_H
|
||||
# include <dirent.h>
|
||||
# define NAMLEN(dirent) strlen((dirent)->d_name)
|
||||
#else
|
||||
# define dirent direct
|
||||
# define NAMLEN(dirent) ((dirent)->d_namlen)
|
||||
# if HAVE_SYS_NDIR_H
|
||||
# include <sys/ndir.h>
|
||||
# endif
|
||||
# if HAVE_SYS_DIR_H
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# if HAVE_NDIR_H
|
||||
# include <ndir.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if HAVE_VFORK_H
|
||||
#include <vfork.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
VOID *malloc ();
|
||||
VOID *realloc ();
|
||||
#endif
|
||||
#ifndef getenv
|
||||
char *getenv ();
|
||||
#endif
|
||||
|
||||
#if HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#ifndef INT_MAX
|
||||
#define INT_MAX 2147483647
|
||||
#endif
|
||||
#ifndef CHAR_BIT
|
||||
#define CHAR_BIT 8
|
||||
#endif
|
||||
|
||||
#if STDC_HEADERS || HAVE_STRING_H
|
||||
# include <string.h>
|
||||
# ifndef bzero
|
||||
# define bzero(s, n) memset (s, 0, n)
|
||||
# endif
|
||||
#else
|
||||
# if !HAVE_STRCHR
|
||||
# define strchr index
|
||||
# define strrchr rindex
|
||||
# endif
|
||||
char *strchr (), *strrchr ();
|
||||
# if !HAVE_MEMCHR
|
||||
# define memcmp(s1, s2, n) bcmp (s1, s2, n)
|
||||
# define memcpy(d, s, n) bcopy (s, d, n)
|
||||
void *memchr ();
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
/* CTYPE_DOMAIN (C) is nonzero if the unsigned char C can safely be given
|
||||
as an argument to <ctype.h> macros like `isspace'. */
|
||||
#if STDC_HEADERS
|
||||
#define CTYPE_DOMAIN(c) 1
|
||||
#else
|
||||
#define CTYPE_DOMAIN(c) ((unsigned) (c) <= 0177)
|
||||
#endif
|
||||
#ifndef ISPRINT
|
||||
#define ISPRINT(c) (CTYPE_DOMAIN (c) && isprint (c))
|
||||
#endif
|
||||
#ifndef ISSPACE
|
||||
#define ISSPACE(c) (CTYPE_DOMAIN (c) && isspace (c))
|
||||
#endif
|
||||
#ifndef ISUPPER
|
||||
#define ISUPPER(c) (CTYPE_DOMAIN (c) && isupper (c))
|
||||
#endif
|
||||
|
||||
#ifndef ISDIGIT
|
||||
#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#if !STDC_HEADERS
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
#define min(a,b) ((a) <= (b) ? (a) : (b))
|
||||
#define max(a,b) ((a) >= (b) ? (a) : (b))
|
||||
|
||||
/* This section contains Posix-compliant defaults for macros
|
||||
that are meant to be overridden by hand in config.h as needed. */
|
||||
|
||||
#ifndef filename_cmp
|
||||
#define filename_cmp(a, b) strcmp (a, b)
|
||||
#endif
|
||||
|
||||
#ifndef filename_lastdirchar
|
||||
#define filename_lastdirchar(filename) strrchr (filename, '/')
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FORK
|
||||
#define HAVE_FORK 1
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SETMODE
|
||||
#define HAVE_SETMODE 0
|
||||
#endif
|
||||
|
||||
#ifndef initialize_main
|
||||
#define initialize_main(argcp, argvp)
|
||||
#endif
|
||||
|
||||
/* Do struct stat *S, *T describe the same file? Answer -1 if unknown. */
|
||||
#ifndef same_file
|
||||
#define same_file(s,t) ((s)->st_ino==(t)->st_ino && (s)->st_dev==(t)->st_dev)
|
||||
#endif
|
||||
|
||||
/* Place into Q a quoted version of A suitable for `popen' or `system',
|
||||
incrementing Q and junking A.
|
||||
Do not increment Q by more than 4 * strlen (A) + 2. */
|
||||
#ifndef SYSTEM_QUOTE_ARG
|
||||
#define SYSTEM_QUOTE_ARG(q, a) \
|
||||
{ \
|
||||
*(q)++ = '\''; \
|
||||
for (; *(a); *(q)++ = *(a)++) \
|
||||
if (*(a) == '\'') \
|
||||
{ \
|
||||
*(q)++ = '\''; \
|
||||
*(q)++ = '\\'; \
|
||||
*(q)++ = '\''; \
|
||||
} \
|
||||
*(q)++ = '\''; \
|
||||
}
|
||||
#endif
|
754
contrib/diff/util.c
Normal file
754
contrib/diff/util.c
Normal file
@ -0,0 +1,754 @@
|
||||
/* Support routines for GNU DIFF.
|
||||
Copyright (C) 1988, 1989, 1992, 1993, 1994 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 "diff.h"
|
||||
|
||||
#ifndef PR_PROGRAM
|
||||
#define PR_PROGRAM "/bin/pr"
|
||||
#endif
|
||||
|
||||
/* Queue up one-line messages to be printed at the end,
|
||||
when -l is specified. Each message is recorded with a `struct msg'. */
|
||||
|
||||
struct msg
|
||||
{
|
||||
struct msg *next;
|
||||
char const *format;
|
||||
char const *arg1;
|
||||
char const *arg2;
|
||||
char const *arg3;
|
||||
char const *arg4;
|
||||
};
|
||||
|
||||
/* Head of the chain of queues messages. */
|
||||
|
||||
static struct msg *msg_chain;
|
||||
|
||||
/* Tail of the chain of queues messages. */
|
||||
|
||||
static struct msg **msg_chain_end = &msg_chain;
|
||||
|
||||
/* Use when a system call returns non-zero status.
|
||||
TEXT should normally be the file name. */
|
||||
|
||||
void
|
||||
perror_with_name (text)
|
||||
char const *text;
|
||||
{
|
||||
int e = errno;
|
||||
fprintf (stderr, "%s: ", program_name);
|
||||
errno = e;
|
||||
perror (text);
|
||||
}
|
||||
|
||||
/* Use when a system call returns non-zero status and that is fatal. */
|
||||
|
||||
void
|
||||
pfatal_with_name (text)
|
||||
char const *text;
|
||||
{
|
||||
int e = errno;
|
||||
print_message_queue ();
|
||||
fprintf (stderr, "%s: ", program_name);
|
||||
errno = e;
|
||||
perror (text);
|
||||
exit (2);
|
||||
}
|
||||
|
||||
/* Print an error message from the format-string FORMAT
|
||||
with args ARG1 and ARG2. */
|
||||
|
||||
void
|
||||
error (format, arg, arg1)
|
||||
char const *format, *arg, *arg1;
|
||||
{
|
||||
fprintf (stderr, "%s: ", program_name);
|
||||
fprintf (stderr, format, arg, arg1);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
/* Print an error message containing the string TEXT, then exit. */
|
||||
|
||||
void
|
||||
fatal (m)
|
||||
char const *m;
|
||||
{
|
||||
print_message_queue ();
|
||||
error ("%s", m, 0);
|
||||
exit (2);
|
||||
}
|
||||
|
||||
/* Like printf, except if -l in effect then save the message and print later.
|
||||
This is used for things like "binary files differ" and "Only in ...". */
|
||||
|
||||
void
|
||||
message (format, arg1, arg2)
|
||||
char const *format, *arg1, *arg2;
|
||||
{
|
||||
message5 (format, arg1, arg2, 0, 0);
|
||||
}
|
||||
|
||||
void
|
||||
message5 (format, arg1, arg2, arg3, arg4)
|
||||
char const *format, *arg1, *arg2, *arg3, *arg4;
|
||||
{
|
||||
if (paginate_flag)
|
||||
{
|
||||
struct msg *new = (struct msg *) xmalloc (sizeof (struct msg));
|
||||
new->format = format;
|
||||
new->arg1 = concat (arg1, "", "");
|
||||
new->arg2 = concat (arg2, "", "");
|
||||
new->arg3 = arg3 ? concat (arg3, "", "") : 0;
|
||||
new->arg4 = arg4 ? concat (arg4, "", "") : 0;
|
||||
new->next = 0;
|
||||
*msg_chain_end = new;
|
||||
msg_chain_end = &new->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sdiff_help_sdiff)
|
||||
putchar (' ');
|
||||
printf (format, arg1, arg2, arg3, arg4);
|
||||
}
|
||||
}
|
||||
|
||||
/* Output all the messages that were saved up by calls to `message'. */
|
||||
|
||||
void
|
||||
print_message_queue ()
|
||||
{
|
||||
struct msg *m;
|
||||
|
||||
for (m = msg_chain; m; m = m->next)
|
||||
printf (m->format, m->arg1, m->arg2, m->arg3, m->arg4);
|
||||
}
|
||||
|
||||
/* Call before outputting the results of comparing files NAME0 and NAME1
|
||||
to set up OUTFILE, the stdio stream for the output to go to.
|
||||
|
||||
Usually, OUTFILE is just stdout. But when -l was specified
|
||||
we fork off a `pr' and make OUTFILE a pipe to it.
|
||||
`pr' then outputs to our stdout. */
|
||||
|
||||
static char const *current_name0;
|
||||
static char const *current_name1;
|
||||
static int current_depth;
|
||||
|
||||
void
|
||||
setup_output (name0, name1, depth)
|
||||
char const *name0, *name1;
|
||||
int depth;
|
||||
{
|
||||
current_name0 = name0;
|
||||
current_name1 = name1;
|
||||
current_depth = depth;
|
||||
outfile = 0;
|
||||
}
|
||||
|
||||
#if HAVE_FORK
|
||||
static pid_t pr_pid;
|
||||
#endif
|
||||
|
||||
void
|
||||
begin_output ()
|
||||
{
|
||||
char *name;
|
||||
|
||||
if (outfile != 0)
|
||||
return;
|
||||
|
||||
/* Construct the header of this piece of diff. */
|
||||
name = xmalloc (strlen (current_name0) + strlen (current_name1)
|
||||
+ strlen (switch_string) + 7);
|
||||
/* Posix.2 section 4.17.6.1.1 specifies this format. But there is a
|
||||
bug in the first printing (IEEE Std 1003.2-1992 p 251 l 3304):
|
||||
it says that we must print only the last component of the pathnames.
|
||||
This requirement is silly and does not match historical practice. */
|
||||
sprintf (name, "diff%s %s %s", switch_string, current_name0, current_name1);
|
||||
|
||||
if (paginate_flag)
|
||||
{
|
||||
/* Make OUTFILE a pipe to a subsidiary `pr'. */
|
||||
|
||||
#if HAVE_FORK
|
||||
int pipes[2];
|
||||
|
||||
if (pipe (pipes) != 0)
|
||||
pfatal_with_name ("pipe");
|
||||
|
||||
fflush (stdout);
|
||||
|
||||
pr_pid = vfork ();
|
||||
if (pr_pid < 0)
|
||||
pfatal_with_name ("vfork");
|
||||
|
||||
if (pr_pid == 0)
|
||||
{
|
||||
close (pipes[1]);
|
||||
if (pipes[0] != STDIN_FILENO)
|
||||
{
|
||||
if (dup2 (pipes[0], STDIN_FILENO) < 0)
|
||||
pfatal_with_name ("dup2");
|
||||
close (pipes[0]);
|
||||
}
|
||||
|
||||
execl (PR_PROGRAM, PR_PROGRAM, "-f", "-h", name, 0);
|
||||
pfatal_with_name (PR_PROGRAM);
|
||||
}
|
||||
else
|
||||
{
|
||||
close (pipes[0]);
|
||||
outfile = fdopen (pipes[1], "w");
|
||||
if (!outfile)
|
||||
pfatal_with_name ("fdopen");
|
||||
}
|
||||
#else /* ! HAVE_FORK */
|
||||
char *command = xmalloc (4 * strlen (name) + strlen (PR_PROGRAM) + 10);
|
||||
char *p;
|
||||
char const *a = name;
|
||||
sprintf (command, "%s -f -h ", PR_PROGRAM);
|
||||
p = command + strlen (command);
|
||||
SYSTEM_QUOTE_ARG (p, a);
|
||||
*p = 0;
|
||||
outfile = popen (command, "w");
|
||||
if (!outfile)
|
||||
pfatal_with_name (command);
|
||||
free (command);
|
||||
#endif /* ! HAVE_FORK */
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* If -l was not specified, output the diff straight to `stdout'. */
|
||||
|
||||
outfile = stdout;
|
||||
|
||||
/* If handling multiple files (because scanning a directory),
|
||||
print which files the following output is about. */
|
||||
if (current_depth > 0)
|
||||
printf ("%s\n", name);
|
||||
}
|
||||
|
||||
free (name);
|
||||
|
||||
/* A special header is needed at the beginning of context output. */
|
||||
switch (output_style)
|
||||
{
|
||||
case OUTPUT_CONTEXT:
|
||||
print_context_header (files, 0);
|
||||
break;
|
||||
|
||||
case OUTPUT_UNIFIED:
|
||||
print_context_header (files, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call after the end of output of diffs for one file.
|
||||
Close OUTFILE and get rid of the `pr' subfork. */
|
||||
|
||||
void
|
||||
finish_output ()
|
||||
{
|
||||
if (outfile != 0 && outfile != stdout)
|
||||
{
|
||||
int wstatus;
|
||||
if (ferror (outfile))
|
||||
fatal ("write error");
|
||||
#if ! HAVE_FORK
|
||||
wstatus = pclose (outfile);
|
||||
#else /* HAVE_FORK */
|
||||
if (fclose (outfile) != 0)
|
||||
pfatal_with_name ("write error");
|
||||
if (waitpid (pr_pid, &wstatus, 0) < 0)
|
||||
pfatal_with_name ("waitpid");
|
||||
#endif /* HAVE_FORK */
|
||||
if (wstatus != 0)
|
||||
fatal ("subsidiary pr failed");
|
||||
}
|
||||
|
||||
outfile = 0;
|
||||
}
|
||||
|
||||
/* Compare two lines (typically one from each input file)
|
||||
according to the command line options.
|
||||
For efficiency, this is invoked only when the lines do not match exactly
|
||||
but an option like -i might cause us to ignore the difference.
|
||||
Return nonzero if the lines differ. */
|
||||
|
||||
int
|
||||
line_cmp (s1, s2)
|
||||
char const *s1, *s2;
|
||||
{
|
||||
register unsigned char const *t1 = (unsigned char const *) s1;
|
||||
register unsigned char const *t2 = (unsigned char const *) s2;
|
||||
|
||||
while (1)
|
||||
{
|
||||
register unsigned char c1 = *t1++;
|
||||
register unsigned char c2 = *t2++;
|
||||
|
||||
/* Test for exact char equality first, since it's a common case. */
|
||||
if (c1 != c2)
|
||||
{
|
||||
/* Ignore horizontal white space if -b or -w is specified. */
|
||||
|
||||
if (ignore_all_space_flag)
|
||||
{
|
||||
/* For -w, just skip past any white space. */
|
||||
while (ISSPACE (c1) && c1 != '\n') c1 = *t1++;
|
||||
while (ISSPACE (c2) && c2 != '\n') c2 = *t2++;
|
||||
}
|
||||
else if (ignore_space_change_flag)
|
||||
{
|
||||
/* For -b, advance past any sequence of white space in line 1
|
||||
and consider it just one Space, or nothing at all
|
||||
if it is at the end of the line. */
|
||||
if (ISSPACE (c1))
|
||||
{
|
||||
while (c1 != '\n')
|
||||
{
|
||||
c1 = *t1++;
|
||||
if (! ISSPACE (c1))
|
||||
{
|
||||
--t1;
|
||||
c1 = ' ';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Likewise for line 2. */
|
||||
if (ISSPACE (c2))
|
||||
{
|
||||
while (c2 != '\n')
|
||||
{
|
||||
c2 = *t2++;
|
||||
if (! ISSPACE (c2))
|
||||
{
|
||||
--t2;
|
||||
c2 = ' ';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (c1 != c2)
|
||||
{
|
||||
/* If we went too far when doing the simple test
|
||||
for equality, go back to the first non-white-space
|
||||
character in both sides and try again. */
|
||||
if (c2 == ' ' && c1 != '\n'
|
||||
&& (unsigned char const *) s1 + 1 < t1
|
||||
&& ISSPACE(t1[-2]))
|
||||
{
|
||||
--t1;
|
||||
continue;
|
||||
}
|
||||
if (c1 == ' ' && c2 != '\n'
|
||||
&& (unsigned char const *) s2 + 1 < t2
|
||||
&& ISSPACE(t2[-2]))
|
||||
{
|
||||
--t2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Lowercase all letters if -i is specified. */
|
||||
|
||||
if (ignore_case_flag)
|
||||
{
|
||||
if (ISUPPER (c1))
|
||||
c1 = tolower (c1);
|
||||
if (ISUPPER (c2))
|
||||
c2 = tolower (c2);
|
||||
}
|
||||
|
||||
if (c1 != c2)
|
||||
break;
|
||||
}
|
||||
if (c1 == '\n')
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Find the consecutive changes at the start of the script START.
|
||||
Return the last link before the first gap. */
|
||||
|
||||
struct change *
|
||||
find_change (start)
|
||||
struct change *start;
|
||||
{
|
||||
return start;
|
||||
}
|
||||
|
||||
struct change *
|
||||
find_reverse_change (start)
|
||||
struct change *start;
|
||||
{
|
||||
return start;
|
||||
}
|
||||
|
||||
/* Divide SCRIPT into pieces by calling HUNKFUN and
|
||||
print each piece with PRINTFUN.
|
||||
Both functions take one arg, an edit script.
|
||||
|
||||
HUNKFUN is called with the tail of the script
|
||||
and returns the last link that belongs together with the start
|
||||
of the tail.
|
||||
|
||||
PRINTFUN takes a subscript which belongs together (with a null
|
||||
link at the end) and prints it. */
|
||||
|
||||
void
|
||||
print_script (script, hunkfun, printfun)
|
||||
struct change *script;
|
||||
struct change * (*hunkfun) PARAMS((struct change *));
|
||||
void (*printfun) PARAMS((struct change *));
|
||||
{
|
||||
struct change *next = script;
|
||||
|
||||
while (next)
|
||||
{
|
||||
struct change *this, *end;
|
||||
|
||||
/* Find a set of changes that belong together. */
|
||||
this = next;
|
||||
end = (*hunkfun) (next);
|
||||
|
||||
/* Disconnect them from the rest of the changes,
|
||||
making them a hunk, and remember the rest for next iteration. */
|
||||
next = end->link;
|
||||
end->link = 0;
|
||||
#ifdef DEBUG
|
||||
debug_script (this);
|
||||
#endif
|
||||
|
||||
/* Print this hunk. */
|
||||
(*printfun) (this);
|
||||
|
||||
/* Reconnect the script so it will all be freed properly. */
|
||||
end->link = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the text of a single line LINE,
|
||||
flagging it with the characters in LINE_FLAG (which say whether
|
||||
the line is inserted, deleted, changed, etc.). */
|
||||
|
||||
void
|
||||
print_1_line (line_flag, line)
|
||||
char const *line_flag;
|
||||
char const * const *line;
|
||||
{
|
||||
char const *text = line[0], *limit = line[1]; /* Help the compiler. */
|
||||
FILE *out = outfile; /* Help the compiler some more. */
|
||||
char const *flag_format = 0;
|
||||
|
||||
/* If -T was specified, use a Tab between the line-flag and the text.
|
||||
Otherwise use a Space (as Unix diff does).
|
||||
Print neither space nor tab if line-flags are empty. */
|
||||
|
||||
if (line_flag && *line_flag)
|
||||
{
|
||||
flag_format = tab_align_flag ? "%s\t" : "%s ";
|
||||
fprintf (out, flag_format, line_flag);
|
||||
}
|
||||
|
||||
output_1_line (text, limit, flag_format, line_flag);
|
||||
|
||||
if ((!line_flag || line_flag[0]) && limit[-1] != '\n')
|
||||
fprintf (out, "\n\\ No newline at end of file\n");
|
||||
}
|
||||
|
||||
/* Output a line from TEXT up to LIMIT. Without -t, output verbatim.
|
||||
With -t, expand white space characters to spaces, and if FLAG_FORMAT
|
||||
is nonzero, output it with argument LINE_FLAG after every
|
||||
internal carriage return, so that tab stops continue to line up. */
|
||||
|
||||
void
|
||||
output_1_line (text, limit, flag_format, line_flag)
|
||||
char const *text, *limit, *flag_format, *line_flag;
|
||||
{
|
||||
if (!tab_expand_flag)
|
||||
fwrite (text, sizeof (char), limit - text, outfile);
|
||||
else
|
||||
{
|
||||
register FILE *out = outfile;
|
||||
register unsigned char c;
|
||||
register char const *t = text;
|
||||
register unsigned column = 0;
|
||||
|
||||
while (t < limit)
|
||||
switch ((c = *t++))
|
||||
{
|
||||
case '\t':
|
||||
{
|
||||
unsigned spaces = TAB_WIDTH - column % TAB_WIDTH;
|
||||
column += spaces;
|
||||
do
|
||||
putc (' ', out);
|
||||
while (--spaces);
|
||||
}
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
putc (c, out);
|
||||
if (flag_format && t < limit && *t != '\n')
|
||||
fprintf (out, flag_format, line_flag);
|
||||
column = 0;
|
||||
break;
|
||||
|
||||
case '\b':
|
||||
if (column == 0)
|
||||
continue;
|
||||
column--;
|
||||
putc (c, out);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ISPRINT (c))
|
||||
column++;
|
||||
putc (c, out);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
change_letter (inserts, deletes)
|
||||
int inserts, deletes;
|
||||
{
|
||||
if (!inserts)
|
||||
return 'd';
|
||||
else if (!deletes)
|
||||
return 'a';
|
||||
else
|
||||
return 'c';
|
||||
}
|
||||
|
||||
/* Translate an internal line number (an index into diff's table of lines)
|
||||
into an actual line number in the input file.
|
||||
The internal line number is LNUM. FILE points to the data on the file.
|
||||
|
||||
Internal line numbers count from 0 starting after the prefix.
|
||||
Actual line numbers count from 1 within the entire file. */
|
||||
|
||||
int
|
||||
translate_line_number (file, lnum)
|
||||
struct file_data const *file;
|
||||
int lnum;
|
||||
{
|
||||
return lnum + file->prefix_lines + 1;
|
||||
}
|
||||
|
||||
void
|
||||
translate_range (file, a, b, aptr, bptr)
|
||||
struct file_data const *file;
|
||||
int a, b;
|
||||
int *aptr, *bptr;
|
||||
{
|
||||
*aptr = translate_line_number (file, a - 1) + 1;
|
||||
*bptr = translate_line_number (file, b + 1) - 1;
|
||||
}
|
||||
|
||||
/* Print a pair of line numbers with SEPCHAR, translated for file FILE.
|
||||
If the two numbers are identical, print just one number.
|
||||
|
||||
Args A and B are internal line numbers.
|
||||
We print the translated (real) line numbers. */
|
||||
|
||||
void
|
||||
print_number_range (sepchar, file, a, b)
|
||||
int sepchar;
|
||||
struct file_data *file;
|
||||
int a, b;
|
||||
{
|
||||
int trans_a, trans_b;
|
||||
translate_range (file, a, b, &trans_a, &trans_b);
|
||||
|
||||
/* Note: we can have B < A in the case of a range of no lines.
|
||||
In this case, we should print the line number before the range,
|
||||
which is B. */
|
||||
if (trans_b > trans_a)
|
||||
fprintf (outfile, "%d%c%d", trans_a, sepchar, trans_b);
|
||||
else
|
||||
fprintf (outfile, "%d", trans_b);
|
||||
}
|
||||
|
||||
/* Look at a hunk of edit script and report the range of lines in each file
|
||||
that it applies to. HUNK is the start of the hunk, which is a chain
|
||||
of `struct change'. The first and last line numbers of file 0 are stored in
|
||||
*FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1.
|
||||
Note that these are internal line numbers that count from 0.
|
||||
|
||||
If no lines from file 0 are deleted, then FIRST0 is LAST0+1.
|
||||
|
||||
Also set *DELETES nonzero if any lines of file 0 are deleted
|
||||
and set *INSERTS nonzero if any lines of file 1 are inserted.
|
||||
If only ignorable lines are inserted or deleted, both are
|
||||
set to 0. */
|
||||
|
||||
void
|
||||
analyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts)
|
||||
struct change *hunk;
|
||||
int *first0, *last0, *first1, *last1;
|
||||
int *deletes, *inserts;
|
||||
{
|
||||
int l0, l1, show_from, show_to;
|
||||
int i;
|
||||
int trivial = ignore_blank_lines_flag || ignore_regexp_list;
|
||||
struct change *next;
|
||||
|
||||
show_from = show_to = 0;
|
||||
|
||||
*first0 = hunk->line0;
|
||||
*first1 = hunk->line1;
|
||||
|
||||
next = hunk;
|
||||
do
|
||||
{
|
||||
l0 = next->line0 + next->deleted - 1;
|
||||
l1 = next->line1 + next->inserted - 1;
|
||||
show_from += next->deleted;
|
||||
show_to += next->inserted;
|
||||
|
||||
for (i = next->line0; i <= l0 && trivial; i++)
|
||||
if (!ignore_blank_lines_flag || files[0].linbuf[i][0] != '\n')
|
||||
{
|
||||
struct regexp_list *r;
|
||||
char const *line = files[0].linbuf[i];
|
||||
int len = files[0].linbuf[i + 1] - line;
|
||||
|
||||
for (r = ignore_regexp_list; r; r = r->next)
|
||||
if (0 <= re_search (&r->buf, line, len, 0, len, 0))
|
||||
break; /* Found a match. Ignore this line. */
|
||||
/* If we got all the way through the regexp list without
|
||||
finding a match, then it's nontrivial. */
|
||||
if (!r)
|
||||
trivial = 0;
|
||||
}
|
||||
|
||||
for (i = next->line1; i <= l1 && trivial; i++)
|
||||
if (!ignore_blank_lines_flag || files[1].linbuf[i][0] != '\n')
|
||||
{
|
||||
struct regexp_list *r;
|
||||
char const *line = files[1].linbuf[i];
|
||||
int len = files[1].linbuf[i + 1] - line;
|
||||
|
||||
for (r = ignore_regexp_list; r; r = r->next)
|
||||
if (0 <= re_search (&r->buf, line, len, 0, len, 0))
|
||||
break; /* Found a match. Ignore this line. */
|
||||
/* If we got all the way through the regexp list without
|
||||
finding a match, then it's nontrivial. */
|
||||
if (!r)
|
||||
trivial = 0;
|
||||
}
|
||||
}
|
||||
while ((next = next->link) != 0);
|
||||
|
||||
*last0 = l0;
|
||||
*last1 = l1;
|
||||
|
||||
/* If all inserted or deleted lines are ignorable,
|
||||
tell the caller to ignore this hunk. */
|
||||
|
||||
if (trivial)
|
||||
show_from = show_to = 0;
|
||||
|
||||
*deletes = show_from;
|
||||
*inserts = show_to;
|
||||
}
|
||||
|
||||
/* malloc a block of memory, with fatal error message if we can't do it. */
|
||||
|
||||
VOID *
|
||||
xmalloc (size)
|
||||
size_t size;
|
||||
{
|
||||
register VOID *value;
|
||||
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
|
||||
value = (VOID *) malloc (size);
|
||||
|
||||
if (!value)
|
||||
fatal ("memory exhausted");
|
||||
return value;
|
||||
}
|
||||
|
||||
/* realloc a block of memory, with fatal error message if we can't do it. */
|
||||
|
||||
VOID *
|
||||
xrealloc (old, size)
|
||||
VOID *old;
|
||||
size_t size;
|
||||
{
|
||||
register VOID *value;
|
||||
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
|
||||
value = (VOID *) realloc (old, size);
|
||||
|
||||
if (!value)
|
||||
fatal ("memory exhausted");
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Concatenate three strings, returning a newly malloc'd string. */
|
||||
|
||||
char *
|
||||
concat (s1, s2, s3)
|
||||
char const *s1, *s2, *s3;
|
||||
{
|
||||
size_t len = strlen (s1) + strlen (s2) + strlen (s3);
|
||||
char *new = xmalloc (len + 1);
|
||||
sprintf (new, "%s%s%s", s1, s2, s3);
|
||||
return new;
|
||||
}
|
||||
|
||||
/* Yield the newly malloc'd pathname
|
||||
of the file in DIR whose filename is FILE. */
|
||||
|
||||
char *
|
||||
dir_file_pathname (dir, file)
|
||||
char const *dir, *file;
|
||||
{
|
||||
char const *p = filename_lastdirchar (dir);
|
||||
return concat (dir, "/" + (p && !p[1]), file);
|
||||
}
|
||||
|
||||
void
|
||||
debug_script (sp)
|
||||
struct change *sp;
|
||||
{
|
||||
fflush (stdout);
|
||||
for (; sp; sp = sp->link)
|
||||
fprintf (stderr, "%3d %3d delete %d insert %d\n",
|
||||
sp->line0, sp->line1, sp->deleted, sp->inserted);
|
||||
fflush (stderr);
|
||||
}
|
5
contrib/diff/version.c
Normal file
5
contrib/diff/version.c
Normal file
@ -0,0 +1,5 @@
|
||||
/* Version number of GNU diff. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
char const version_string[] = "2.7";
|
81
contrib/diff/xmalloc.c
Normal file
81
contrib/diff/xmalloc.c
Normal file
@ -0,0 +1,81 @@
|
||||
/* xmalloc.c -- malloc with out of memory checking
|
||||
Copyright (C) 1990, 1991, 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#if __STDC__
|
||||
#define VOID void
|
||||
#else
|
||||
#define VOID char
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#if STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
VOID *malloc ();
|
||||
VOID *realloc ();
|
||||
void free ();
|
||||
#endif
|
||||
|
||||
#if __STDC__ && defined (HAVE_VPRINTF)
|
||||
void error (int, int, char const *, ...);
|
||||
#else
|
||||
void error ();
|
||||
#endif
|
||||
|
||||
/* Allocate N bytes of memory dynamically, with error checking. */
|
||||
|
||||
VOID *
|
||||
xmalloc (n)
|
||||
size_t n;
|
||||
{
|
||||
VOID *p;
|
||||
|
||||
p = malloc (n);
|
||||
if (p == 0)
|
||||
/* Must exit with 2 for `cmp'. */
|
||||
error (2, 0, "memory exhausted");
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Change the size of an allocated block of memory P to N bytes,
|
||||
with error checking.
|
||||
If P is NULL, run xmalloc.
|
||||
If N is 0, run free and return NULL. */
|
||||
|
||||
VOID *
|
||||
xrealloc (p, n)
|
||||
VOID *p;
|
||||
size_t n;
|
||||
{
|
||||
if (p == 0)
|
||||
return xmalloc (n);
|
||||
if (n == 0)
|
||||
{
|
||||
free (p);
|
||||
return 0;
|
||||
}
|
||||
p = realloc (p, n);
|
||||
if (p == 0)
|
||||
/* Must exit with 2 for `cmp'. */
|
||||
error (2, 0, "memory exhausted");
|
||||
return p;
|
||||
}
|
Loading…
Reference in New Issue
Block a user