diff options
| author | jtc <jtc@NetBSD.org> | 1993-07-08 20:14:18 +0000 |
|---|---|---|
| committer | jtc <jtc@NetBSD.org> | 1993-07-08 20:14:18 +0000 |
| commit | f365b1ca2f1a540460315de59428ee31bd985be7 (patch) | |
| tree | c46cbff816fcdffbc5cb16ac8f442b3973e22d83 /gnu/usr.bin/diff3 | |
| parent | 06622400d9890111a0af8f7e7b26c5b34efd96c2 (diff) | |
Update to GNU diff3 2.3
Diffstat (limited to 'gnu/usr.bin/diff3')
| -rw-r--r-- | gnu/usr.bin/diff3/COPYING | 354 | ||||
| -rw-r--r-- | gnu/usr.bin/diff3/Makefile | 14 | ||||
| -rw-r--r-- | gnu/usr.bin/diff3/diff3.c | 1166 |
3 files changed, 816 insertions, 718 deletions
diff --git a/gnu/usr.bin/diff3/COPYING b/gnu/usr.bin/diff3/COPYING index 9a170375811..a43ea2126fb 100644 --- a/gnu/usr.bin/diff3/COPYING +++ b/gnu/usr.bin/diff3/COPYING @@ -1,38 +1,40 @@ - GNU GENERAL PUBLIC LICENSE - Version 1, February 1989 + Version 2, June 1991 - Copyright (C) 1989 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + 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 license agreements of most software companies try to keep users -at the mercy of those companies. By contrast, our General Public + 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. The -General Public License applies to the Free Software Foundation's -software and to any other program whose authors commit to using it. -You can use it for your programs, too. +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. Specifically, the General Public License is designed to make -sure that you have the freedom to give away or sell copies of free -software, 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. +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 a such a program, whether + 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 tell them their rights. +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, @@ -45,120 +47,207 @@ 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 Agreement 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 work containing the -Program or a portion of it, either verbatim or with modifications. Each -licensee is addressed as "you". - - 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 -General Public License and to the absence of any warranty; and give any -other recipients of the Program a copy of this General Public License -along with the Program. You may charge a fee for the physical act of -transferring a copy. - - 2. You may modify your copy or copies of the Program or any portion of -it, and copy and distribute such modifications under the terms of Paragraph -1 above, provided that you also do the following: - - a) cause the modified files to carry prominent notices stating that - you changed the files and the date of any change; and - - b) cause the whole of any work that you distribute or publish, that - in whole or in part contains the Program or any part thereof, either - with or without modifications, to be licensed at no charge to all - third parties under the terms of this General Public License (except - that you may choose to grant warranty protection to some or all - third parties, at your option). - - c) If the modified program normally reads commands interactively when - run, you must cause it, when started running for such interactive use - in the simplest and most usual 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 General - Public License. - - d) 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. - -Mere aggregation of another independent work with the Program (or its -derivative) on a volume of a storage or distribution medium does not bring -the other work under the scope of these terms. + 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.) - 3. You may copy and distribute the Program (or a portion or derivative of -it, under Paragraph 2) in object code or executable form under the terms of -Paragraphs 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 - Paragraphs 1 and 2 above; or, - - b) accompany it with a written offer, valid for at least three - years, to give any third party free (except for a nominal charge - for the cost of distribution) a complete machine-readable copy of the - corresponding source code, to be distributed under the terms of - Paragraphs 1 and 2 above; or, - - c) accompany it with the information you received as to where the - corresponding source code may be obtained. (This alternative is +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 alone.) - -Source code for a work means the preferred form of the work for making -modifications to it. For an executable file, complete source code means -all the source code for all modules it contains; but, as a special -exception, it need not include source code for modules which are standard -libraries that accompany the operating system on which the executable -file runs, or for standard header files or definitions files that -accompany that operating system. - - 4. You may not copy, modify, sublicense, distribute or transfer the -Program except as expressly provided under this General Public License. -Any attempt otherwise to copy, modify, sublicense, distribute or transfer -the Program is void, and will automatically terminate your rights to use -the Program under this License. However, parties who have received -copies, or rights to use copies, from you under this General Public -License will not have their licenses terminated so long as such parties -remain in full compliance. - - 5. By copying, distributing or modifying 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. + 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. +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. - 7. The Free Software Foundation may publish revised and/or new versions + 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 the license which applies to it and "any +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 -the license, you may choose any version ever published by the Free Software +this License, you may choose any version ever published by the Free Software Foundation. - 8. If you wish to incorporate parts of the Program into other free + 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 @@ -168,7 +257,7 @@ of promoting the sharing and reuse of software generally. NO WARRANTY - 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS 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 @@ -178,7 +267,7 @@ 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. - 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + 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 @@ -193,22 +282,21 @@ POSSIBILITY OF SUCH DAMAGES. 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 humanity, the best way to achieve this is to make it -free software which everyone can redistribute and change under these -terms. +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. + 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 1, or (at your option) - any later version. + 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 @@ -224,26 +312,28 @@ 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) 19xx name of author + 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. +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 a sample; alter the names: +necessary. Here is a sample; alter the names: - Yoyodyne, Inc., hereby disclaims all copyright interest in the - program `Gnomovision' (a program to direct compilers to make passes - at assemblers) written by James Hacker. + 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 -That's all there is to it! +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/gnu/usr.bin/diff3/Makefile b/gnu/usr.bin/diff3/Makefile index b5cc6ed6baa..db54aa58f8e 100644 --- a/gnu/usr.bin/diff3/Makefile +++ b/gnu/usr.bin/diff3/Makefile @@ -1,7 +1,11 @@ - -PROG= diff3 -SRCS= diff3.c -NOMAN=noman -CFLAGS+= -DDIFF_PROGRAM=\"/usr/bin/diff\" +PROG= diff3 +SRCS= diff3.c getopt.c getopt1.c version.c +CFLAGS+= -I$(.CURDIR)/../diff\ + -DDIRENT=1 -DHAVE_UNISTD_H=1 -DHAVE_DUP2=1 -DHAVE_MEMCHR=1\ + -DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_FCNTL_H=1\ + -DHAVE_STRING_H=1 -DHAVE_SYS_WAIT_H=1 -DHAVE_TIME_H=1\ + -DHAVE_ST_BLKSIZE=1 -DDIFF_PROGRAM=\"/usr/bin/diff\" +NOMAN= noman .include <bsd.prog.mk> +.PATH: $(.CURDIR)/../diff diff --git a/gnu/usr.bin/diff3/diff3.c b/gnu/usr.bin/diff3/diff3.c index 6bf193019a2..b9952fc0a04 100644 --- a/gnu/usr.bin/diff3/diff3.c +++ b/gnu/usr.bin/diff3/diff3.c @@ -1,9 +1,9 @@ -/* Three-way file comparison program (diff3) for Project GNU - Copyright (C) 1988, 1989 Free Software Foundation, Inc. +/* Three way file comparison program (diff3) for Project GNU. + Copyright (C) 1988, 1989, 1992 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) + 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, @@ -14,72 +14,42 @@ 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. */ - /* Written by Randy Smith */ -#ifdef __STDC__ +#if __STDC__ #define VOID void #else #define VOID char #endif -/* - * Include files. - */ #include <stdio.h> #include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> - -#ifdef USG -#include <fcntl.h> - -/* Define needed BSD functions in terms of sysV library. */ - -#define bcmp(s1,s2,n) memcmp((s1),(s2),(n)) -#define bzero(s,n) memset((s),0,(n)) - -#ifndef XENIX -#define dup2(f,t) (close(t),fcntl((f),F_DUPFD,(t))) -#endif - -#define vfork fork - -#else /* not USG */ -#include <sys/wait.h> -#endif /* not USG */ - -#ifndef WEXITSTATUS -#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) -#undef WIFEXITED /* Avoid 4.3BSD incompatibility with Posix. */ -#endif -#ifndef WIFEXITED -#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) -#endif - -#ifdef sparc -/* vfork clobbers registers on the Sparc, so don't use it. */ -#define vfork fork -#endif +#include "getopt.h" +#include "system.h" /* * Internal data structures and macros for the diff3 program; includes * data structures for both diff3 diffs and normal diffs. */ -/* - * Different files within a diff - */ +/* Different files within a three way diff. */ #define FILE0 0 #define FILE1 1 #define FILE2 2 /* - * Three way diffs are build out of two two-way diffs; the file which + * A three way diff is built from two two-way diffs; the file which * the two two-way diffs share is: */ -#define FILEC FILE0 +#define FILEC FILE2 + +/* + * Different files within a two way diff. + * FC is the common file, FO the other file. + */ +#define FO 0 +#define FC 1 /* The ranges are indexed by */ #define START 0 @@ -96,19 +66,19 @@ enum diff_type { DIFF_3RD /* Only the third */ }; -/* Two-way diff */ +/* Two way diff */ struct diff_block { - int ranges[2][2]; /* Ranges are inclusive */ + int ranges[2][2]; /* Ranges are inclusive */ char **lines[2]; /* The actual lines (may contain nulls) */ int *lengths[2]; /* Line lengths (including newlines, if any) */ struct diff_block *next; }; -/* Three-way diff */ +/* Three way diff */ struct diff3_block { enum diff_type correspond; /* Type of diff */ - int ranges[3][2]; /* Ranges are inclusive */ + int ranges[3][2]; /* Ranges are inclusive */ char **lines[3]; /* The actual lines (may contain nulls) */ int *lengths[3]; /* Line lengths (including newlines, if any) */ struct diff3_block *next; @@ -122,7 +92,7 @@ struct diff3_block { #define D_HIGHLINE(diff, filenum) \ ((diff)->ranges[filenum][END]) #define D_NUMLINES(diff, filenum) \ - (D_HIGHLINE((diff), (filenum)) - D_LOWLINE((diff), (filenum)) + 1) + (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1) /* * Access the line numbers in a file in a diff by relative line @@ -130,9 +100,9 @@ struct diff3_block { * are lvalues and can be used for assignment. */ #define D_RELNUM(diff, filenum, linenum) \ - (*((diff)->lines[filenum] + linenum)) + ((diff)->lines[filenum][linenum]) #define D_RELLEN(diff, filenum, linenum) \ - (*((diff)->lengths[filenum] + linenum)) + ((diff)->lengths[filenum][linenum]) /* * And get at them directly, when that should be necessary. @@ -172,106 +142,130 @@ struct diff3_block { #define ALLOCATE(number, type) \ (type *) xmalloc ((number) * sizeof (type)) -/* - * Options variables for flags set on command line. - * - * ALWAYS_TEXT: Treat all files as text files; never treat as binary. - * - * EDSCRIPT: Write out an ed script instead of the standard diff3 format. - * - * FLAGGING: Indicates that in the case of overlapping diffs (type - * DIFF_ALL), the lines which would normally be deleted from file 1 - * should be preserved with a special flagging mechanism. - * - * DONT_WRITE_OVERLAP: 1 if information for overlapping diffs should - * not be output. - * - * DONT_WRITE_SIMPLE: 1 if information for non-overlapping diffs - * should not be output. - * - * FINALWRITE: 1 if a :wq should be included at the end of the script - * to write out the file being edited. - * - * MERGE: output a merged file. - */ -int always_text; -int edscript; -int flagging; -int dont_write_overlap; -int dont_write_simple; -int finalwrite; -int merge; +/* Options variables for flags set on command line. */ -extern int optind; +/* If nonzero, treat all files as text files, never as binary. */ +static int always_text; -char *argv0; +/* If nonzero, write out an ed script instead of the standard diff3 format. */ +static int edscript; -/* - * Forward function declarations. - */ -struct diff_block *process_diff (); -struct diff3_block *make_3way_diff (); -void output_diff3 (); -int output_diff3_edscript (); -int output_diff3_merge (); -void usage (); +/* If nonzero, in the case of overlapping diffs (type DIFF_ALL), + preserve the lines which would normally be deleted from + file 1 with a special flagging mechanism. */ +static int flagging; + +/* Number of lines to keep in identical prefix and suffix. */ +static int horizon_lines = 10; + +/* If nonzero, do not output information for overlapping diffs. */ +static int simple_only; + +/* If nonzero, do not output information for non-overlapping diffs. */ +static int overlap_only; + +/* If nonzero, show information for DIFF_2ND diffs. */ +static int show_2nd; + +/* If nonzero, include `:wq' at the end of the script + to write out the file being edited. */ +static int finalwrite; -struct diff3_block *using_to_diff3_block (); -int copy_stringlist (); -struct diff3_block *create_diff3_block (); -int compare_line_list (); +/* If nonzero, output a merged file. */ +static int merge; -char *read_diff (); -enum diff_type process_diff_control (); -char *scan_diff_line (); +static char *argv0; -struct diff3_block *reverse_diff3_blocklist (); +/* + * Forward function declarations. + */ +static int myread (); +static void fatal (); +static void perror_with_exit (); +static struct diff_block *process_diff (); +static struct diff3_block *make_3way_diff (); +static void output_diff3 (); +static int output_diff3_edscript (); +static int output_diff3_merge (); +static void usage (); + +static struct diff3_block *using_to_diff3_block (); +static int copy_stringlist (); +static struct diff3_block *create_diff3_block (); +static int compare_line_list (); + +static char *read_diff (); +static enum diff_type process_diff_control (); +static char *scan_diff_line (); + +static struct diff3_block *reverse_diff3_blocklist (); VOID *xmalloc (); -VOID *xrealloc (); +static VOID *xrealloc (); -char diff_program[] = DIFF_PROGRAM; +static char diff_program[] = DIFF_PROGRAM; + +static struct option longopts[] = +{ + {"text", 0, NULL, 'a'}, + {"show-all", 0, NULL, 'A'}, + {"ed", 0, NULL, 'e'}, + {"show-overlap", 0, NULL, 'E'}, + {"label", 1, NULL, 'L'}, + {"merge", 0, NULL, 'm'}, + {"overlap-only", 0, NULL, 'x'}, + {"easy-only", 0, NULL, '3'}, + {"version", 0, NULL, 'v'}, + {0, 0, 0, 0} +}; /* * Main program. Calls diff twice on two pairs of input files, * combines the two diffs, and outputs them. */ +int main (argc, argv) int argc; char **argv; { + extern char *version_string; int c, i; int mapping[3]; int rev_mapping[3]; int incompat; - int overlaps_found; - struct diff_block *thread1, *thread2; - struct diff3_block *diff; + int conflicts_found; + struct diff_block *thread0, *thread1, *last_block; + struct diff3_block *diff3; int tag_count = 0; - /* Element 0 is for file 0, element 1 is for file 2. */ - char *tag_strings[2]; + char *tag_strings[3]; extern char *optarg; char *commonname; + char **file; struct stat statb; incompat = 0; - tag_strings[0] = tag_strings[1] = 0; argv0 = argv[0]; - - while ((c = getopt (argc, argv, "aeimx3EXL:")) != EOF) + + while ((c = getopt_long (argc, argv, "aeimvx3AEXL:", longopts, (int *) 0)) + != EOF) { switch (c) { case 'a': always_text = 1; break; + case 'A': + show_2nd = 1; + flagging = 1; + incompat++; + break; case 'x': - dont_write_simple = 1; + overlap_only = 1; incompat++; break; case '3': - dont_write_overlap = 1; + simple_only = 1; incompat++; break; case 'i': @@ -281,7 +275,7 @@ main (argc, argv) merge = 1; break; case 'X': - dont_write_simple = 1; + overlap_only = 1; /* Falls through */ case 'E': flagging = 1; @@ -289,48 +283,55 @@ main (argc, argv) case 'e': incompat++; break; + case 'v': + fprintf (stderr, "GNU diff3 version %s\n", version_string); + break; case 'L': - /* Handle one or two -L arguments. */ - if (tag_count < 2) + /* Handle up to three -L options. */ + if (tag_count < 3) { tag_strings[tag_count++] = optarg; break; } /* Falls through */ - case '?': default: usage (); /* NOTREACHED */ } } - edscript = incompat & ~merge; /* -eExX3 without -m implies ed script. */ - flagging |= ~incompat & merge; /* -m without -eExX3 implies -E. */ + edscript = incompat & ~merge; /* -AeExX3 without -m implies ed script. */ + show_2nd |= ~incompat & merge; /* -m without -AeExX3 implies -A. */ + flagging |= ~incompat & merge; - if (incompat > 1 /* Ensure at most one of -eExX3. */ - || finalwrite & (~incompat | merge) - /* -i needs one of -eExX3; -i -m would rewrite input file. */ - || tag_count && ! flagging /* -L requires one of -EX. */ + if (incompat > 1 /* Ensure at most one of -AeExX3. */ + || finalwrite & merge /* -i -m would rewrite input file. */ + || (tag_count && ! flagging) /* -L requires one of -AEX. */ || argc - optind != 3) usage (); - if (tag_strings[0] == 0) - tag_strings[0] = argv[optind]; - if (tag_strings[1] == 0) - tag_strings[1] = argv[optind + 2]; + file = &argv[optind]; - if (*argv[optind] == '-' && *(argv[optind] + 1) == '\0') + for (i = tag_count; i < 3; i++) + tag_strings[i] = file[i]; + + /* Always compare file1 to file2, even if file2 is "-". + This is needed for -mAeExX3. Using the file0 as + the common file would produce wrong results, because if the + file0-file1 diffs didn't line up with the file0-file2 diffs + (which is entirely possible since we don't use diff's -n option), + diff3 might report phantom changes from file1 to file2. */ + + if (strcmp (file[2], "-") == 0) { - /* Sigh. We've got standard input as the first arg. We can't */ - /* call diff twice on stdin */ - if (! strcmp (argv[optind + 1], "-") || ! strcmp (argv[optind + 2], "-")) + /* Sigh. We've got standard input as the last arg. We can't + call diff twice on stdin. Use the middle arg as the common + file instead. */ + if (strcmp (file[0], "-") == 0 || strcmp (file[1], "-") == 0) fatal ("`-' specified for more than one input file"); - mapping[0] = 1; + mapping[0] = 0; mapping[1] = 2; - mapping[2] = 0; - rev_mapping[1] = 0; - rev_mapping[2] = 1; - rev_mapping[0] = 2; + mapping[2] = 1; } else { @@ -338,61 +339,71 @@ main (argc, argv) mapping[0] = 0; mapping[1] = 1; mapping[2] = 2; - rev_mapping[0] = 0; - rev_mapping[1] = 1; - rev_mapping[2] = 2; } for (i = 0; i < 3; i++) - if (argv[optind + i][0] != '-' || argv[optind + i][1] != '\0') - if (stat (argv[optind + i], &statb) < 0) - perror_with_exit (argv[optind + i]); - else if ((statb.st_mode & S_IFMT) == S_IFDIR) + rev_mapping[mapping[i]] = i; + + for (i = 0; i < 3; i++) + if (strcmp (file[i], "-") != 0) + if (stat (file[i], &statb) < 0) + perror_with_exit (file[i]); + else if (S_ISDIR(statb.st_mode)) { - fprintf (stderr, "%s: %s: Is a directory\n", argv0, - argv[optind + i]); + fprintf (stderr, "%s: %s: Is a directory\n", argv0, file[i]); exit (2); } - - commonname = argv[optind + rev_mapping[0]]; - thread1 = process_diff (commonname, argv[optind + rev_mapping[1]]); - thread2 = process_diff (commonname, argv[optind + rev_mapping[2]]); - diff = make_3way_diff (thread1, thread2); + + commonname = file[rev_mapping[FILEC]]; + thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block); + if (thread1) + for (i = 0; i < 2; i++) + { + horizon_lines = max (horizon_lines, D_NUMLINES (thread1, i)); + horizon_lines = max (horizon_lines, D_NUMLINES (last_block, i)); + } + thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block); + diff3 = make_3way_diff (thread0, thread1); if (edscript) - overlaps_found - = output_diff3_edscript (stdout, diff, mapping, rev_mapping, - tag_strings[0], argv[optind+1], tag_strings[1]); + conflicts_found + = output_diff3_edscript (stdout, diff3, mapping, rev_mapping, + tag_strings[0], tag_strings[1], tag_strings[2]); else if (merge) { - if (! freopen (commonname, "r", stdin)) - perror_with_exit (commonname); - overlaps_found - = output_diff3_merge (stdin, stdout, diff, mapping, rev_mapping, - tag_strings[0], argv[optind+1], tag_strings[1]); + if (! freopen (file[rev_mapping[FILE0]], "r", stdin)) + perror_with_exit (file[rev_mapping[FILE0]]); + conflicts_found + = output_diff3_merge (stdin, stdout, diff3, mapping, rev_mapping, + tag_strings[0], tag_strings[1], tag_strings[2]); if (ferror (stdin)) fatal ("read error"); } else { - output_diff3 (stdout, diff, mapping, rev_mapping); - overlaps_found = 0; + output_diff3 (stdout, diff3, mapping, rev_mapping); + conflicts_found = 0; } - if (ferror (stdout) || fflush (stdout) != 0) + if (ferror (stdout) || fclose (stdout) != 0) fatal ("write error"); - exit (overlaps_found); + exit (conflicts_found); + return conflicts_found; } - + /* * Explain, patiently and kindly, how to use this program. Then exit. */ -void +static void usage () { - fprintf (stderr, "Usage:\t%s [-exEX3 [-i | -m] [-L label1 -L label3]] file1 file2 file3\n", - argv0); - fprintf (stderr, "\tOnly one of [exEX3] allowed\n"); + fprintf (stderr, "\ +Usage: %s [options] my-file older-file your-file\n\ +Options:\n\ + [-exAEX3v] [-i|-m] [-L label1 [-L label2 [-L label3]]] [--text] [--ed]\n\ + [--merge] [--show-all] [--show-overlap] [--overlap-only] [--easy-only]\n\ + [--label=label1 [--label=label2 [--label=label3]]] [--version]\n\ + Only one of [exAEX3] is allowed\n", argv0); exit (2); } @@ -400,79 +411,79 @@ usage () * Routines that combine the two diffs together into one. The * algorithm used follows: * - * File0 is shared in common between the two diffs. - * Diff01 is the diff between 0 and 1. + * File2 is shared in common between the two diffs. * Diff02 is the diff between 0 and 2. + * Diff12 is the diff between 1 and 2. * - * 1) Find the range for the first block in File0. - * a) Take the lowest of the two ranges (in File0) in the two - * current blocks (one from each diff) as being the low - * water mark. Assign the upper end of this block as - * being the high water mark and move the current block up - * one. Mark the block just moved over as to be used. + * 1) Find the range for the first block in File2. + * a) Take the lowest of the two ranges (in File2) in the two + * current blocks (one from each diff) as being the low + * water mark. Assign the upper end of this block as + * being the high water mark and move the current block up + * one. Mark the block just moved over as to be used. * b) Check the next block in the diff that the high water - * mark is *not* from. - * + * mark is *not* from. + * * *If* the high water mark is above - * the low end of the range in that block, - * - * mark that block as to be used and move the current - * block up. Set the high water mark to the max of - * the high end of this block and the current. Repeat b. - * - * 2) Find the corresponding ranges in Files1 (from the blocks - * in diff01; line per line outside of diffs) and in File2. - * Create a diff3_block, reserving space as indicated by the ranges. - * - * 3) Copy all of the pointers for file0 in. At least for now, - * do bcmp's between corresponding strings in the two diffs. - * - * 4) Copy all of the pointers for file1 and 2 in. Get what you - * need from file0 (when there isn't a diff block, it's - * identical to file0 within the range between diff blocks). - * + * the low end of the range in that block, + * + * mark that block as to be used and move the current + * block up. Set the high water mark to the max of + * the high end of this block and the current. Repeat b. + * + * 2) Find the corresponding ranges in File0 (from the blocks + * in diff02; line per line outside of diffs) and in File1. + * Create a diff3_block, reserving space as indicated by the ranges. + * + * 3) Copy all of the pointers for file2 in. At least for now, + * do bcmp's between corresponding strings in the two diffs. + * + * 4) Copy all of the pointers for file0 and 1 in. Get what you + * need from file2 (when there isn't a diff block, it's + * identical to file2 within the range between diff blocks). + * * 5) If the diff blocks you used came from only one of the two - * strings of diffs, then that file (i.e. the one other than - * file 0 in that diff) is the odd person out. If you used - * diff blocks from both sets, check to see if files 1 and 2 match: - * - * Same number of lines? If so, do a set of bcmp's (if a - * bcmp matches; copy the pointer over; it'll be easier later - * if you have to do any compares). If they match, 1 & 2 are - * the same. If not, all three different. - * - * Then you do it again, until you run out of blocks. - * + * strings of diffs, then that file (i.e. the one other than + * the common file in that diff) is the odd person out. If you used + * diff blocks from both sets, check to see if files 0 and 1 match: + * + * Same number of lines? If so, do a set of bcmp's (if a + * bcmp matches; copy the pointer over; it'll be easier later + * if you have to do any compares). If they match, 0 & 1 are + * the same. If not, all three different. + * + * Then you do it again, until you run out of blocks. + * */ -/* +/* * This routine makes a three way diff (chain of diff3_block's) from two * two way diffs (chains of diff_block's). It is assumed that each of - * the two diffs passed are off of the same file (i.e. that each of the - * diffs were made "from" the same file). The three way diff pointer - * returned will have numbering 0--the common file, 1--the other file - * in diff1, and 2--the other file in diff2. + * the two diffs passed are onto the same file (i.e. that each of the + * diffs were made "to" the same file). The three way diff pointer + * returned will have numbering FILE0--the other file in diff02, + * FILE1--the other file in diff12, and FILEC--the common file. */ -struct diff3_block * -make_3way_diff (thread1, thread2) - struct diff_block *thread1, *thread2; +static struct diff3_block * +make_3way_diff (thread0, thread1) + struct diff_block *thread0, *thread1; { /* * This routine works on the two diffs passed to it as threads. - * Thread number 0 is diff1, thread number 1 is diff2. The USING + * Thread number 0 is diff02, thread number 1 is diff12. The USING * array is set to the base of the list of blocks to be used to * construct each block of the three way diff; if no blocks from a * particular thread are to be used, that element of the using array * is set to 0. The elements LAST_USING array are set to the last * elements on each of the using lists. * - * The HIGH_WATER_MARK is set to the highest line number in File 0 + * The HIGH_WATER_MARK is set to the highest line number in the common file * described in any of the diffs in either of the USING lists. The * HIGH_WATER_THREAD names the thread. Similarly the BASE_WATER_MARK - * and BASE_WATER_THREAD describe the lowest line number in File 0 + * and BASE_WATER_THREAD describe the lowest line number in the common file * described in any of the diffs in either of the USING lists. The * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was - * taken. + * taken. * * The HIGH_WATER_DIFF should always be equal to LAST_USING * [HIGH_WATER_THREAD]. The OTHER_DIFF is the next diff to check for @@ -507,10 +518,10 @@ make_3way_diff (thread1, thread2) struct diff3_block *result, *tmpblock, - *result_last, - *last_diff; + **result_end, + *last_diff3; - static struct diff3_block zero_diff = { + static struct diff3_block zero_diff3 = { ERROR, { {0, 0}, {0, 0}, {0, 0} }, { (char **) 0, (char **) 0, (char **) 0 }, @@ -519,9 +530,10 @@ make_3way_diff (thread1, thread2) }; /* Initialization */ - result = result_last = (struct diff3_block *) 0; - current[0] = thread1; current[1] = thread2; - last_diff = &zero_diff; + result = 0; + result_end = &result; + current[0] = thread0; current[1] = thread1; + last_diff3 = &zero_diff3; /* Sniff up the threads until we reach the end */ @@ -537,18 +549,18 @@ make_3way_diff (thread1, thread2) base_water_thread = 0; else base_water_thread = - (D_LOWLINE (current[0], FILE0) > D_LOWLINE (current[1], FILE0)); + (D_LOWLINE (current[0], FC) > D_LOWLINE (current[1], FC)); high_water_thread = base_water_thread; - + high_water_diff = current[high_water_thread]; - + #if 0 /* low and high waters start off same diff */ - base_water_mark = D_LOWLINE (high_water_diff, FILE0); + base_water_mark = D_LOWLINE (high_water_diff, FC); #endif - high_water_mark = D_HIGHLINE (high_water_diff, FILE0); + high_water_mark = D_HIGHLINE (high_water_diff, FC); /* Make the diff you just got info from into the using class */ using[high_water_thread] @@ -563,9 +575,9 @@ make_3way_diff (thread1, thread2) other_diff = current[other_thread]; /* Shuffle up the ladder, checking the other diff to see if it - needs to be incorporated */ + needs to be incorporated. */ while (other_diff - && D_LOWLINE (other_diff, FILE0) <= high_water_mark + 1) + && D_LOWLINE (other_diff, FC) <= high_water_mark + 1) { /* Incorporate this diff into the using list. Note that @@ -588,13 +600,13 @@ make_3way_diff (thread1, thread2) If this comparison is equal, then this is the last pass through this loop; since diff blocks within a given thread cannot overlap, the high_water_mark will be - *below* the range_start of either of the next diffs. */ + *below* the range_start of either of the next diffs. */ - if (high_water_mark < D_HIGHLINE (other_diff, FILE0)) + if (high_water_mark < D_HIGHLINE (other_diff, FC)) { high_water_thread ^= 1; high_water_diff = other_diff; - high_water_mark = D_HIGHLINE (other_diff, FILE0); + high_water_mark = D_HIGHLINE (other_diff, FC); } /* Set the other diff */ @@ -603,24 +615,21 @@ make_3way_diff (thread1, thread2) } /* The using lists contain a list of all of the blocks to be - included in this diff3_block. Create it. */ + included in this diff3_block. Create it. */ tmpblock = using_to_diff3_block (using, last_using, base_water_thread, high_water_thread, - last_diff); + last_diff3); if (!tmpblock) - fatal ("internal: screwup in format of diff blocks"); + fatal ("internal error: screwup in format of diff blocks"); - /* Put it on the list */ - if (result) - result_last->next = tmpblock; - else - result = tmpblock; - result_last = tmpblock; + /* Put it on the list. */ + *result_end = tmpblock; + result_end = &tmpblock->next; - /* Setup corresponding lines correctly */ - last_diff = tmpblock; + /* Set up corresponding lines correctly. */ + last_diff3 = tmpblock; } return result; } @@ -637,7 +646,7 @@ make_3way_diff (thread1, thread2) * structure. * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest * and highest line numbers for File0. - * last_diff contains the last diff produced in the calling routine. + * last_diff3 contains the last diff produced in the calling routine. * This is used for lines mappings which would still be identical to * the state that diff ended in. * @@ -645,188 +654,120 @@ make_3way_diff (thread1, thread2) * that are part of a normal two diff block, and the three diffs that * are part of a diff3_block. */ -struct diff3_block * -using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff) +static struct diff3_block * +using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff3) struct diff_block *using[2], *last_using[2]; int low_thread, high_thread; - struct diff3_block *last_diff; + struct diff3_block *last_diff3; { - int lowc, highc, low1, high1, low2, high2; + int low[2], high[2]; struct diff3_block *result; struct diff_block *ptr; - int i; - int current0line; - - /* Find the range in file0 */ - lowc = using[low_thread]->ranges[0][START]; - highc = last_using[high_thread]->ranges[0][END]; + int d, i; - /* Find the ranges in the other files. - If using[x] is null, that means that the file to which that diff - refers is equivalent to file 0 over this range */ - - if (using[0]) - { - low1 = D_LOW_MAPLINE (using[0], FILE0, FILE1, lowc); - high1 = D_HIGH_MAPLINE (last_using[0], FILE0, FILE1, highc); - } - else - { - low1 = D_HIGH_MAPLINE (last_diff, FILEC, FILE1, lowc); - high1 = D_HIGH_MAPLINE (last_diff, FILEC, FILE1, highc); - } + /* Find the range in the common file. */ + int lowc = D_LOWLINE (using[low_thread], FC); + int highc = D_HIGHLINE (last_using[high_thread], FC); - /* - * Note that in the following, we use file 1 relative to the diff, - * and file 2 relative to the corresponding lines struct. - */ - if (using[1]) - { - low2 = D_LOW_MAPLINE (using[1], FILE0, FILE1, lowc); - high2 = D_HIGH_MAPLINE (last_using[1], FILE0, FILE1, highc); - } - else - { - low2 = D_HIGH_MAPLINE (last_diff, FILEC, FILE2, lowc); - high2 = D_HIGH_MAPLINE (last_diff, FILEC, FILE2, highc); - } + /* Find the ranges in the other files. + If using[d] is null, that means that the file to which that diff + refers is equivalent to the common file over this range. */ + + for (d = 0; d < 2; d++) + if (using[d]) + { + low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc); + high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc); + } + else + { + low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc); + high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc); + } /* Create a block with the appropriate sizes */ - result = create_diff3_block (lowc, highc, low1, high1, low2, high2); + result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc); - /* Copy over all of the information for File 0. Return with a zero - if any of the compares failed. */ - for (ptr = using[0]; ptr; ptr = D_NEXT (ptr)) - { - int result_offset = D_LOWLINE (ptr, FILE0) - lowc; - int copy_size - = D_HIGHLINE (ptr, FILE0) - D_LOWLINE (ptr, FILE0) + 1; - - if (!copy_stringlist (D_LINEARRAY (ptr, FILE0), - D_LENARRAY (ptr, FILE0), - D_LINEARRAY (result, FILEC) + result_offset, - D_LENARRAY (result, FILEC) + result_offset, - copy_size)) - return 0; - } + /* Copy information for the common file. + Return with a zero if any of the compares failed. */ - for (ptr = using[1]; ptr; ptr = D_NEXT (ptr)) - { - int result_offset = D_LOWLINE (ptr, FILEC) - lowc; - int copy_size - = D_HIGHLINE (ptr, FILEC) - D_LOWLINE (ptr, FILEC) + 1; - - if (!copy_stringlist (D_LINEARRAY (ptr, FILE0), - D_LENARRAY (ptr, FILE0), - D_LINEARRAY (result, FILEC) + result_offset, - D_LENARRAY (result, FILEC) + result_offset, - copy_size)) - return 0; - } + for (d = 0; d < 2; d++) + for (ptr = using[d]; ptr; ptr = D_NEXT (ptr)) + { + int result_offset = D_LOWLINE (ptr, FC) - lowc; - /* Copy stuff for file 1. First deal with anything that might be - before the first diff. */ + if (!copy_stringlist (D_LINEARRAY (ptr, FC), + D_LENARRAY (ptr, FC), + D_LINEARRAY (result, FILEC) + result_offset, + D_LENARRAY (result, FILEC) + result_offset, + D_NUMLINES (ptr, FC))) + return 0; + } - for (i = 0; - i + low1 < (using[0] ? D_LOWLINE (using[0], FILE1) : high1 + 1); - i++) - { - D_RELNUM (result, FILE1, i) = D_RELNUM (result, FILEC, i); - D_RELLEN (result, FILE1, i) = D_RELLEN (result, FILEC, i); - } - - for (ptr = using[0]; ptr; ptr = D_NEXT (ptr)) + /* Copy information for file d. First deal with anything that might be + before the first diff. */ + + for (d = 0; d < 2; d++) { - int result_offset = D_LOWLINE (ptr, FILE1) - low1; - int copy_size - = D_HIGHLINE (ptr, FILE1) - D_LOWLINE (ptr, FILE1) + 1; - - if (!copy_stringlist (D_LINEARRAY (ptr, FILE1), - D_LENARRAY (ptr, FILE1), - D_LINEARRAY (result, FILE1) + result_offset, - D_LENARRAY (result, FILE1) + result_offset, - copy_size)) - return 0; - - /* Catch the lines between here and the next diff */ - current0line = D_HIGHLINE (ptr, FILE0) + 1 - lowc; - for (i = D_HIGHLINE (ptr, FILE1) + 1 - low1; - i < (D_NEXT (ptr) ? - D_LOWLINE (D_NEXT (ptr), FILE1) : - high1 + 1) - low1; + struct diff_block *u = using[d]; + int lo = low[d], hi = high[d]; + + for (i = 0; + i + lo < (u ? D_LOWLINE (u, FO) : hi + 1); i++) { - D_RELNUM (result, FILE1, i) - = D_RELNUM (result, FILEC, current0line); - D_RELLEN (result, FILE1, i) - = D_RELLEN (result, FILEC, current0line++); + D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i); + D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i); } - } - /* Copy stuff for file 2. First deal with anything that might be - before the first diff. */ - - for (i = 0; - i + low2 < (using[1] ? D_LOWLINE (using[1], FILE1) : high2 + 1); - i++) - { - D_RELNUM (result, FILE2, i) = D_RELNUM (result, FILEC, i); - D_RELLEN (result, FILE2, i) = D_RELLEN (result, FILEC, i); - } - - for (ptr = using[1]; ptr; ptr = D_NEXT (ptr)) - { - int result_offset = D_LOWLINE (ptr, FILE1) - low2; - int copy_size - = D_HIGHLINE (ptr, FILE1) - D_LOWLINE (ptr, FILE1) + 1; - - if (!copy_stringlist (D_LINEARRAY (ptr, FILE1), - D_LENARRAY (ptr, FILE1), - D_LINEARRAY (result, FILE2) + result_offset, - D_LENARRAY (result, FILE2) + result_offset, - copy_size)) - return 0; - - /* Catch the lines between here and the next diff */ - current0line = D_HIGHLINE (ptr, FILE0) + 1 - lowc; - for (i = D_HIGHLINE (ptr, FILE1) + 1 - low2; - i < (D_NEXT (ptr) ? - D_LOWLINE (D_NEXT (ptr), FILE1) : - high2 + 1) - low2; - i++) + for (ptr = u; ptr; ptr = D_NEXT (ptr)) { - D_RELNUM (result, FILE2, i) - = D_RELNUM (result, FILEC, current0line); - D_RELLEN (result, FILE2, i) - = D_RELLEN (result, FILEC, current0line++); + int result_offset = D_LOWLINE (ptr, FO) - lo; + int linec; + + if (!copy_stringlist (D_LINEARRAY (ptr, FO), + D_LENARRAY (ptr, FO), + D_LINEARRAY (result, FILE0 + d) + result_offset, + D_LENARRAY (result, FILE0 + d) + result_offset, + D_NUMLINES (ptr, FO))) + return 0; + + /* Catch the lines between here and the next diff */ + linec = D_HIGHLINE (ptr, FC) + 1 - lowc; + for (i = D_HIGHLINE (ptr, FO) + 1 - lo; + i < (D_NEXT (ptr) ? D_LOWLINE (D_NEXT (ptr), FO) : hi + 1) - lo; + i++) + { + D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec); + D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec); + linec++; + } } } /* Set correspond */ if (!using[0]) - D3_TYPE (result) = DIFF_3RD; - else if (!using[1]) D3_TYPE (result) = DIFF_2ND; + else if (!using[1]) + D3_TYPE (result) = DIFF_1ST; else { - int nl1 - = D_HIGHLINE (result, FILE1) - D_LOWLINE (result, FILE1) + 1; - int nl2 - = D_HIGHLINE (result, FILE2) - D_LOWLINE (result, FILE2) + 1; + int nl0 = D_NUMLINES (result, FILE0); + int nl1 = D_NUMLINES (result, FILE1); - if (nl1 != nl2 - || !compare_line_list (D_LINEARRAY (result, FILE1), + if (nl0 != nl1 + || !compare_line_list (D_LINEARRAY (result, FILE0), + D_LENARRAY (result, FILE0), + D_LINEARRAY (result, FILE1), D_LENARRAY (result, FILE1), - D_LINEARRAY (result, FILE2), - D_LENARRAY (result, FILE2), - nl1)) + nl0)) D3_TYPE (result) = DIFF_ALL; else - D3_TYPE (result) = DIFF_1ST; + D3_TYPE (result) = DIFF_3RD; } - + return result; } @@ -837,7 +778,7 @@ using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff) * returns 0, the copy incomplete. * Upon successful completion of the copy, it returns 1. */ -int +static int copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum) char *fromptrs[], *toptrs[]; int *fromlengths, *tolengths; @@ -849,7 +790,7 @@ copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum) register int *fl = fromlengths, *tl = tolengths; - + while (copynum--) { if (*t) @@ -867,7 +808,7 @@ copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum) * Allocate the arrays for the various pointers (and zero them) based * on the arguments passed. Return the block as a result. */ -struct diff3_block * +static struct diff3_block * create_diff3_block (low0, high0, low1, high1, low2, high2) register int low0, high0, low1, high1, low2, high2; { @@ -936,7 +877,7 @@ create_diff3_block (low0, high0, low1, high1, low2, high2) * Compare two lists of lines of text. * Return 1 if they are equivalent, 0 if not. */ -int +static int compare_line_list (list1, lengths1, list2, lengths2, nl) char *list1[], *list2[]; int *lengths1, *lengths2; @@ -948,7 +889,7 @@ compare_line_list (list1, lengths1, list2, lengths2, nl) int *lgths1 = lengths1, *lgths2 = lengths2; - + while (nl--) if (!*l1 || !*l2 || *lgths1 != *lgths2++ || bcmp (*l1++, *l2++, *lgths1++)) @@ -956,7 +897,7 @@ compare_line_list (list1, lengths1, list2, lengths2, nl) return 1; } -/* +/* * Routines to input and parse two way diffs. */ @@ -964,28 +905,28 @@ extern char **environ; #define DIFF_CHUNK_SIZE 10000 -struct diff_block * -process_diff (filea, fileb) +static struct diff_block * +process_diff (filea, fileb, last_block) char *filea, *fileb; + struct diff_block **last_block; { char *diff_contents; char *diff_limit; char *scan_diff; enum diff_type dt; int i; - struct diff_block *block_list, *block_list_end, *bptr; + struct diff_block *block_list, **block_list_end, *bptr; diff_limit = read_diff (filea, fileb, &diff_contents); scan_diff = diff_contents; - bptr = block_list_end = block_list = (struct diff_block *) 0; + block_list_end = &block_list; while (scan_diff < diff_limit) { bptr = ALLOCATE (1, struct diff_block); - bptr->next = 0; bptr->lines[0] = bptr->lines[1] = (char **) 0; bptr->lengths[0] = bptr->lengths[1] = (int *) 0; - + dt = process_diff_control (&scan_diff, bptr); if (dt == ERROR || *scan_diff != '\n') { @@ -998,7 +939,7 @@ process_diff (filea, fileb) exit (2); } scan_diff++; - + /* Force appropriate ranges to be null, if necessary */ switch (dt) { @@ -1011,66 +952,55 @@ process_diff (filea, fileb) case CHANGE: break; default: - fatal ("internal: Bad diff type in process_diff"); + fatal ("internal error: invalid diff type in process_diff"); break; } - + /* Allocate space for the pointers for the lines from filea, and parcel them out among these pointers */ if (dt != ADD) { - bptr->lines[0] = ALLOCATE ((bptr->ranges[0][END] - - bptr->ranges[0][START] + 1), - char *); - bptr->lengths[0] = ALLOCATE ((bptr->ranges[0][END] - - bptr->ranges[0][START] + 1), - int); - for (i = 0; i <= (bptr->ranges[0][END] - - bptr->ranges[0][START]); i++) + int numlines = D_NUMLINES (bptr, 0); + bptr->lines[0] = ALLOCATE (numlines, char *); + bptr->lengths[0] = ALLOCATE (numlines, int); + for (i = 0; i < numlines; i++) scan_diff = scan_diff_line (scan_diff, &(bptr->lines[0][i]), &(bptr->lengths[0][i]), diff_limit, '<'); } - + /* Get past the separator for changes */ if (dt == CHANGE) { if (strncmp (scan_diff, "---\n", 4)) - fatal ("Bad diff format: bad change separator"); + fatal ("invalid diff format; invalid change separator"); scan_diff += 4; } - + /* Allocate space for the pointers for the lines from fileb, and parcel them out among these pointers */ if (dt != DELETE) { - bptr->lines[1] = ALLOCATE ((bptr->ranges[1][END] - - bptr->ranges[1][START] + 1), - char *); - bptr->lengths[1] = ALLOCATE ((bptr->ranges[1][END] - - bptr->ranges[1][START] + 1), - int); - for (i = 0; i <= (bptr->ranges[1][END] - - bptr->ranges[1][START]); i++) + int numlines = D_NUMLINES (bptr, 1); + bptr->lines[1] = ALLOCATE (numlines, char *); + bptr->lengths[1] = ALLOCATE (numlines, int); + for (i = 0; i < numlines; i++) scan_diff = scan_diff_line (scan_diff, &(bptr->lines[1][i]), &(bptr->lengths[1][i]), diff_limit, '>'); } - - /* Place this block on the blocklist */ - if (block_list_end) - block_list_end->next = bptr; - else - block_list = bptr; - - block_list_end = bptr; - + + /* Place this block on the blocklist. */ + *block_list_end = bptr; + block_list_end = &bptr->next; } + *block_list_end = 0; + *last_block = bptr; return block_list; } @@ -1087,10 +1017,10 @@ process_diff (filea, fileb) * number, then both corresponding numbers in the diff block are set * to that number. In general these numbers are interpetted as ranges * inclusive, unless being used by the ADD or DELETE commands. It is - * assumed that these will be special cased in a superior routine. + * assumed that these will be special cased in a superior routine. */ -enum diff_type +static enum diff_type process_diff_control (string, db) char **string; struct diff_block *db; @@ -1117,7 +1047,7 @@ process_diff_control (string, db) READNUM (s, db->ranges[0][START]); /* Was that the only digit? */ - SKIPWHITE(s); + SKIPWHITE (s); if (*s == ',') { /* Get the next digit */ @@ -1144,13 +1074,13 @@ process_diff_control (string, db) return ERROR; /* Bad format */ } s++; /* Past letter */ - + /* Read second set of digits */ SKIPWHITE (s); READNUM (s, db->ranges[1][START]); /* Was that the only digit? */ - SKIPWHITE(s); + SKIPWHITE (s); if (*s == ',') { /* Get the next digit */ @@ -1165,12 +1095,13 @@ process_diff_control (string, db) return type; } -char * +static char * read_diff (filea, fileb, output_placement) char *filea, *fileb; char **output_placement; { - char *argv[6]; + char *argv[7]; + char horizon_arg[256]; char **ap; int fds[2]; char *diff_result; @@ -1184,13 +1115,15 @@ read_diff (filea, fileb, output_placement) *ap++ = diff_program; if (always_text) *ap++ = "-a"; + sprintf (horizon_arg, "--horizon-lines=%d", horizon_lines); + *ap++ = horizon_arg; *ap++ = "--"; *ap++ = filea; *ap++ = fileb; *ap = (char *) 0; if (pipe (fds) < 0) - perror_with_exit ("Pipe failed"); + perror_with_exit ("pipe failed"); pid = vfork (); if (pid == 0) @@ -1203,14 +1136,14 @@ read_diff (filea, fileb, output_placement) close (fds[1]); } execve (diff_program, argv, environ); - /* Avoid stdio, because the parent process's buffers are inherited. */ + /* Avoid stdio, because the parent process's buffers are inherited. */ write (fileno (stderr), diff_program, strlen (diff_program)); write (fileno (stderr), ": not found\n", 12); _exit (2); } if (pid == -1) - perror_with_exit ("Fork failed"); + perror_with_exit ("fork failed"); close (fds[1]); /* Prevent erroneous lack of EOF */ current_chunk_size = DIFF_CHUNK_SIZE; @@ -1226,17 +1159,17 @@ read_diff (filea, fileb, output_placement) } while (bytes); if (total != 0 && diff_result[total-1] != '\n') - fatal ("bad diff format; incomplete last line"); + fatal ("invalid diff format; incomplete last line"); *output_placement = diff_result; do if ((w = wait (&wstatus)) == -1) - perror_with_exit ("Wait failed"); + perror_with_exit ("wait failed"); while (w != pid); if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2)) - fatal ("Subsidiary diff failed"); + fatal ("subsidiary diff failed"); return diff_result + total; } @@ -1249,7 +1182,7 @@ read_diff (filea, fileb, output_placement) * This next routine began life as a macro and many parameters in it * are used as call-by-reference values. */ -char * +static char * scan_diff_line (scan_ptr, set_start, set_length, limit, firstchar) char *scan_ptr, **set_start; int *set_length; @@ -1260,7 +1193,7 @@ scan_diff_line (scan_ptr, set_start, set_length, limit, firstchar) if (!(scan_ptr[0] == (firstchar) && scan_ptr[1] == ' ')) - fatal ("Bad diff format; incorrect leading line chars"); + fatal ("invalid diff format; incorrect leading line chars"); *set_start = line_ptr = scan_ptr + 2; while (*line_ptr++ != '\n') @@ -1297,11 +1230,11 @@ scan_diff_line (scan_ptr, set_start, set_length, limit, firstchar) * argument list) and contains the internal file number (from the * diff passed). This is important because the user expects his * outputs in terms of the argument list number, and the diff passed - * may have been done slightly differently (if the first argument in - * the argument list was the standard input, for example). + * may have been done slightly differently (if the last argument + * was "-", for example). * REV_MAPPING is the inverse of MAPPING. */ -void +static void output_diff3 (outputfile, diff, mapping, rev_mapping) FILE *outputfile; struct diff3_block *diff; @@ -1331,17 +1264,17 @@ output_diff3 (outputfile, diff, mapping, rev_mapping) case DIFF_2ND: case DIFF_3RD: oddoneout = rev_mapping[(int) ptr->correspond - (int) DIFF_1ST]; - + x[0] = oddoneout + '1'; x[1] = '\0'; dontprint = oddoneout==0; break; default: - fatal ("internal: Bad diff type passed to output"); + fatal ("internal error: invalid diff type passed to output"); } fprintf (outputfile, "====%s\n", x); - /* Go 0, 2, 1 if the first and third outputs are equivalent. */ + /* Go 0, 2, 1 if the first and third outputs are equivalent. */ for (i = 0; i < 3; i = (oddoneout == 1 ? skew_increment[i] : i + 1)) { @@ -1349,7 +1282,7 @@ output_diff3 (outputfile, diff, mapping, rev_mapping) int lowt = D_LOWLINE (ptr, realfile), hight = D_HIGHLINE (ptr, realfile); - + fprintf (outputfile, "%d:", i + 1); switch (lowt - hight) { @@ -1379,6 +1312,55 @@ output_diff3 (outputfile, diff, mapping, rev_mapping) } } + +/* + * Output to OUTPUTFILE the lines of B taken from FILENUM. + * Double any initial '.'s; yield nonzero if any initial '.'s were doubled. + */ +static int +dotlines (outputfile, b, filenum) + FILE *outputfile; + struct diff3_block *b; + int filenum; +{ + int i; + int leading_dot = 0; + + for (i = 0; + i < D_NUMLINES (b, filenum); + i++) + { + char *line = D_RELNUM (b, filenum, i); + if (line[0] == '.') + { + leading_dot = 1; + fprintf (outputfile, "."); + } + fwrite (line, sizeof (char), + D_RELLEN (b, filenum, i), outputfile); + } + + return leading_dot; +} + +/* + * Output to OUTPUTFILE a '.' line. If LEADING_DOT is nonzero, + * also output a command that removes initial '.'s + * starting with line START and continuing for NUM lines. + */ +static void +undotlines (outputfile, leading_dot, start, num) + FILE *outputfile; + int leading_dot, start, num; +{ + fprintf (outputfile, ".\n"); + if (leading_dot) + if (num == 1) + fprintf (outputfile, "%ds/^\\.//\n", start); + else + fprintf (outputfile, "%d,%ds/^\\.//\n", start, start + num - 1); +} + /* * This routine outputs a diff3 set of blocks as an ed script. This * script applies the changes between file's 2 & 3 to file 1. It @@ -1398,10 +1380,10 @@ output_diff3 (outputfile, diff, mapping, rev_mapping) * as the names of the three files. These may be the actual names, * or may be the arguments specified with -L. * - * Returns 1 if overlaps were found. + * Returns 1 if conflicts were found. */ -int +static int output_diff3_edscript (outputfile, diff, mapping, rev_mapping, file0, file1, file2) FILE *outputfile; @@ -1409,124 +1391,115 @@ output_diff3_edscript (outputfile, diff, mapping, rev_mapping, int mapping[3], rev_mapping[3]; char *file0, *file1, *file2; { - int i; int leading_dot; - int overlaps_found = 0; - struct diff3_block *newblock, *thisblock; - - leading_dot = 0; - - newblock = reverse_diff3_blocklist (diff); + int conflicts_found = 0, conflict; + struct diff3_block *b; - for (thisblock = newblock; thisblock; thisblock = thisblock->next) + for (b = reverse_diff3_blocklist (diff); b; b = b->next) { /* Must do mapping correctly. */ enum diff_type type - = ((thisblock->correspond == DIFF_ALL) ? + = ((b->correspond == DIFF_ALL) ? DIFF_ALL : ((enum diff_type) (((int) DIFF_1ST) - + rev_mapping[(int) thisblock->correspond - (int) DIFF_1ST]))); + + rev_mapping[(int) b->correspond - (int) DIFF_1ST]))); - /* If we aren't supposed to do this output block, skip it */ - if (type == DIFF_2ND || type == DIFF_1ST - || (type == DIFF_3RD && dont_write_simple) - || (type == DIFF_ALL && dont_write_overlap)) - continue; + /* If we aren't supposed to do this output block, skip it. */ + switch (type) + { + default: continue; + case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break; + case DIFF_3RD: if (overlap_only) continue; conflict = 0; break; + case DIFF_ALL: if (simple_only) continue; conflict = flagging; break; + } - if (flagging && type == DIFF_ALL) - /* Do special flagging */ + if (conflict) { + conflicts_found = 1; - /* Put in lines from FILE2 with bracket */ - fprintf (outputfile, "%da\n", - D_HIGHLINE (thisblock, mapping[FILE0])); - fprintf (outputfile, "=======\n"); - for (i = 0; - i < D_NUMLINES (thisblock, mapping[FILE2]); - i++) + + /* Mark end of conflict. */ + + fprintf (outputfile, "%da\n", D_HIGHLINE (b, mapping[FILE0])); + leading_dot = 0; + if (type == DIFF_ALL) { - if (D_RELNUM (thisblock, mapping[FILE2], i)[0] == '.') - { leading_dot = 1; fprintf(outputfile, "."); } - fwrite (D_RELNUM (thisblock, mapping[FILE2], i), sizeof (char), - D_RELLEN (thisblock, mapping[FILE2], i), outputfile); + if (show_2nd) + { + /* Append lines from FILE1. */ + fprintf (outputfile, "||||||| %s\n", file1); + leading_dot = dotlines (outputfile, b, mapping[FILE1]); + } + /* Append lines from FILE2. */ + fprintf (outputfile, "=======\n"); + leading_dot |= dotlines (outputfile, b, mapping[FILE2]); } - fprintf (outputfile, ">>>>>>> %s\n.\n", file2); - overlaps_found = 1; + fprintf (outputfile, ">>>>>>> %s\n", file2); + undotlines (outputfile, leading_dot, + D_HIGHLINE (b, mapping[FILE0]) + 2, + (D_NUMLINES (b, mapping[FILE1]) + + D_NUMLINES (b, mapping[FILE2]) + 1)); + - /* Add in code to take care of leading dots, if necessary. */ - if (leading_dot) + /* Mark start of conflict. */ + + fprintf (outputfile, "%da\n<<<<<<< %s\n", + D_LOWLINE (b, mapping[FILE0]) - 1, + type == DIFF_ALL ? file0 : file1); + leading_dot = 0; + if (type == DIFF_2ND) { - fprintf (outputfile, "%d,%ds/^\\.\\./\\./\n", - D_HIGHLINE (thisblock, mapping[FILE0]) + 1, - (D_HIGHLINE (thisblock, mapping[FILE0]) - + D_NUMLINES (thisblock, mapping[FILE2]))); - leading_dot = 0; + /* Prepend lines from FILE1. */ + leading_dot = dotlines (outputfile, b, mapping[FILE1]); + fprintf (outputfile, "=======\n"); } - - /* Put in code to do initial bracket of lines from FILE0 */ - fprintf (outputfile, "%da\n<<<<<<< %s\n.\n", - D_LOWLINE (thisblock, mapping[FILE0]) - 1, - file0); + undotlines (outputfile, leading_dot, + D_LOWLINE (b, mapping[FILE0]) + 1, + D_NUMLINES (b, mapping[FILE1])); } - else if (D_NUMLINES (thisblock, mapping[FILE2]) == 0) + else if (D_NUMLINES (b, mapping[FILE2]) == 0) /* Write out a delete */ { - if (D_NUMLINES (thisblock, mapping[FILE0]) == 1) + if (D_NUMLINES (b, mapping[FILE0]) == 1) fprintf (outputfile, "%dd\n", - D_LOWLINE (thisblock, mapping[FILE0])); + D_LOWLINE (b, mapping[FILE0])); else fprintf (outputfile, "%d,%dd\n", - D_LOWLINE (thisblock, mapping[FILE0]), - D_HIGHLINE (thisblock, mapping[FILE0])); + D_LOWLINE (b, mapping[FILE0]), + D_HIGHLINE (b, mapping[FILE0])); } else /* Write out an add or change */ { - switch (D_NUMLINES (thisblock, mapping[FILE0])) + switch (D_NUMLINES (b, mapping[FILE0])) { case 0: fprintf (outputfile, "%da\n", - D_HIGHLINE (thisblock, mapping[FILE0])); + D_HIGHLINE (b, mapping[FILE0])); break; case 1: fprintf (outputfile, "%dc\n", - D_HIGHLINE (thisblock, mapping[FILE0])); + D_HIGHLINE (b, mapping[FILE0])); break; default: fprintf (outputfile, "%d,%dc\n", - D_LOWLINE (thisblock, mapping[FILE0]), - D_HIGHLINE (thisblock, mapping[FILE0])); + D_LOWLINE (b, mapping[FILE0]), + D_HIGHLINE (b, mapping[FILE0])); break; } - for (i = 0; - i < D_NUMLINES (thisblock, mapping[FILE2]); - i++) - { - if (D_RELNUM (thisblock, mapping[FILE2], i)[0] == '.') - { leading_dot = 1; fprintf (outputfile, "."); } - fwrite (D_RELNUM (thisblock, mapping[FILE2], i), sizeof (char), - D_RELLEN (thisblock, mapping[FILE2], i), outputfile); - } - fprintf (outputfile, ".\n"); - - /* Add in code to take care of leading dots, if necessary. */ - if (leading_dot) - { - fprintf (outputfile, "%d,%ds/^\\.\\./\\./\n", - D_HIGHLINE (thisblock, mapping[FILE0]) + 1, - (D_HIGHLINE (thisblock, mapping[FILE0]) - + D_NUMLINES (thisblock, mapping[FILE2]))); - leading_dot = 0; - } + + undotlines (outputfile, dotlines (outputfile, b, mapping[FILE2]), + D_LOWLINE (b, mapping[FILE0]), + D_NUMLINES (b, mapping[FILE2])); } } if (finalwrite) fprintf (outputfile, "w\nq\n"); - return overlaps_found; + return conflicts_found; } /* - * Read from COMMONFILE and output to OUTPUTFILE a set of diff3_ blocks DIFF + * Read from INFILE and output to OUTPUTFILE a set of diff3_ blocks DIFF * as a merged file. This acts like 'ed file0 <[output_diff3_edscript]', * except that it works even for binary data or incomplete lines. * @@ -1534,64 +1507,87 @@ output_diff3_edscript (outputfile, diff, mapping, rev_mapping, * REV_MAPPING is its inverse, * and FILE0, FILE1, and FILE2 are the names of the files. * - * Returns 1 if overlaps were found. + * Returns 1 if conflicts were found. */ -int -output_diff3_merge (commonfile, outputfile, diff, mapping, rev_mapping, +static int +output_diff3_merge (infile, outputfile, diff, mapping, rev_mapping, file0, file1, file2) - FILE *commonfile, *outputfile; + FILE *infile, *outputfile; struct diff3_block *diff; int mapping[3], rev_mapping[3]; char *file0, *file1, *file2; { int c, i; - int overlaps_found = 0; + int conflicts_found = 0, conflict; struct diff3_block *b; int linesread = 0; for (b = diff; b; b = b->next) { - /* Must do mapping correctly */ + /* Must do mapping correctly. */ enum diff_type type = ((b->correspond == DIFF_ALL) ? DIFF_ALL : ((enum diff_type) (((int) DIFF_1ST) + rev_mapping[(int) b->correspond - (int) DIFF_1ST]))); + char *format_2nd = "<<<<<<< %s\n"; /* If we aren't supposed to do this output block, skip it. */ - if (type == DIFF_2ND || type == DIFF_1ST - || (type == DIFF_3RD && dont_write_simple) - || (type == DIFF_ALL && dont_write_overlap)) - continue; + switch (type) + { + default: continue; + case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break; + case DIFF_3RD: if (overlap_only) continue; conflict = 0; break; + case DIFF_ALL: if (simple_only) continue; conflict = flagging; + format_2nd = "||||||| %s\n"; + break; + } - /* Copy I lines from common file. */ + /* Copy I lines from file 0. */ i = D_LOWLINE (b, FILE0) - linesread - 1; linesread += i; while (0 <= --i) + do + { + c = getc (infile); + if (c == EOF) + if (ferror (infile)) + perror_with_exit ("input file"); + else if (feof (infile)) + fatal ("input file shrank"); + putc (c, outputfile); + } + while (c != '\n'); + + if (conflict) { - while ((c = getc(commonfile)) != '\n') + conflicts_found = 1; + + if (type == DIFF_ALL) { - if (c == EOF) - fatal ("input file shrank"); - putc (c, outputfile); + /* Put in lines from FILE0 with bracket. */ + fprintf (outputfile, "<<<<<<< %s\n", file0); + for (i = 0; + i < D_NUMLINES (b, mapping[FILE0]); + i++) + fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char), + D_RELLEN (b, mapping[FILE0], i), outputfile); + } + + if (show_2nd) + { + /* Put in lines from FILE1 with bracket. */ + fprintf (outputfile, format_2nd, file1); + for (i = 0; + i < D_NUMLINES (b, mapping[FILE1]); + i++) + fwrite (D_RELNUM (b, mapping[FILE1], i), sizeof (char), + D_RELLEN (b, mapping[FILE1], i), outputfile); } - putc (c, outputfile); - } - if (flagging && type == DIFF_ALL) - /* Do special flagging. */ - { - /* Put in lines from FILE0 with bracket. */ - fprintf (outputfile, "<<<<<<< %s\n", file0); - for (i = 0; - i < D_NUMLINES (b, mapping[FILE0]); - i++) - fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char), - D_RELLEN (b, mapping[FILE0], i), outputfile); fprintf (outputfile, "=======\n"); - overlaps_found = 1; } /* Put in lines from FILE2. */ @@ -1601,31 +1597,34 @@ output_diff3_merge (commonfile, outputfile, diff, mapping, rev_mapping, fwrite (D_RELNUM (b, mapping[FILE2], i), sizeof (char), D_RELLEN (b, mapping[FILE2], i), outputfile); - if (flagging && type == DIFF_ALL) + if (conflict) fprintf (outputfile, ">>>>>>> %s\n", file2); - /* Skip I lines in common file. */ + /* Skip I lines in file 0. */ i = D_NUMLINES (b, FILE0); linesread += i; while (0 <= --i) - while ((c = getc(commonfile)) != '\n') + while ((c = getc (infile)) != '\n') if (c == EOF) - { - if (i || b->next) - fatal ("input file shrank"); - return overlaps_found; - } + if (ferror (infile)) + perror_with_exit ("input file"); + else if (feof (infile)) + { + if (i || b->next) + fatal ("input file shrank"); + return conflicts_found; + } } /* Copy rest of common file. */ - while ((c = getc (commonfile)) != EOF) + while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile))) putc (c, outputfile); - return overlaps_found; + return conflicts_found; } /* * Reverse the order of the list of diff3 blocks. */ -struct diff3_block * +static struct diff3_block * reverse_diff3_blocklist (diff) struct diff3_block *diff; { @@ -1638,42 +1637,43 @@ reverse_diff3_blocklist (diff) tmp->next = prev; prev = tmp; } - + return prev; } -int +static int myread (fd, ptr, size) int fd, size; char *ptr; { int result = read (fd, ptr, size); if (result < 0) - perror_with_exit ("Read failed"); + perror_with_exit ("read failed"); return result; } VOID * xmalloc (size) - int size; + unsigned size; { VOID *result = (VOID *) malloc (size ? size : 1); if (!result) - fatal ("Malloc failed"); + fatal ("virtual memory exhausted"); return result; } -VOID * +static VOID * xrealloc (ptr, size) VOID *ptr; - int size; + unsigned size; { VOID *result = (VOID *) realloc (ptr, size ? size : 1); if (!result) - fatal ("Malloc failed"); + fatal ("virtual memory exhausted"); return result; } +static void fatal (string) char *string; { @@ -1681,9 +1681,13 @@ fatal (string) exit (2); } +static void perror_with_exit (string) char *string; { + int e = errno; + fprintf (stderr, "%s: ", argv0); + errno = e; perror (string); exit (2); } |
