dwdiff-2.0.9/0000770000175000017500000000000012262313361012627 5ustar gertjangertjandwdiff-2.0.9/COPYING0000640000175000017500000010451312262313361013665 0ustar gertjangertjan GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. 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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. 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. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS 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 state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program 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, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU 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 Lesser General Public License instead of this License. But first, please read . dwdiff-2.0.9/Changelog0000660000175000017500000001702412262313361014446 0ustar gertjangertjanVersion 2.0.9: Fix typo in configure script which prevents it from running. Version 2.0.8: Bug fixes: - Fix build against glibc 2.16 and newer. Miscelaneous changes: - Added correct breaking for Unicode Regional Indicators. Version 2.0.7: Fix incorrect release of 2.0.6, which omitted changes from the 2.0.5 release. Version 2.0.6 Bug fixes: - Fix incorrect line numbering caused by optimized printing of differences preceeded in both files by whitespace containing newlines. Version 2.0.5: Bug fixes: - fix a bug in the handling of context, which caused incorrect diffs to be printed. In some cases text was reported both as removed and as common. Version 2.0.4: Bug fixes: - fix a memory allocation bug, which would be triggered by large values for the -m option. Version 2.0.3: Updated translations for German (incomplete), French (incomplete) and Spanish. Version 2.0.2: Bug fixes: - add support for DESTDIR in the Makefile install target. - fix build error on --without-unicode compiles. Version 2.0.1: Bug fixes: - escape parsing for unknown escapes (like for example \;) would result in incorrect strings. - when the space character is not considered whitespace, dwdiff will no longer use it to make changes more readable. Internal changes: - the token file no longer uses a newline character as separator, but a nul character, making reparsing easier and the whole of dwdiff more robust. Version 2.0: New features: - dwdiff is no longer a front-end for the diff program, but includes its own diff-algorithm implementation (taken from GNU diff). This makes dwdiff much faster, and ensures that results are the same across all platforms. Bug fixes: - when two additions are made with a single common token in between, dwdiff incorrectly reported the common token as replaced by the two additions and the common token. - when using the --diff-input option, in some cases dwdiff would report changes spanning multiple diff sections. Version 1.9: New features: - an option for reading the output of diff (in Unified Diff) format was added (--diff-input) which can be used to reformat diffs for enhanced readability. Version 1.8.2: New features: - when parsing options, \e is understood to mean the escape character Bug fixes: - the -p and -l options did not correctly handle UTF-8 characters. Version 1.8.1: New features: - the context matching now decreases the matched context size exponentially, instead of immediately using the context-less mode if the changes found with context need refining. This results in more intuitive output when increasing the matching context size. Version 1.8: New features: - added an option to repeat the begin and end markers at the start and end of line if a change crosses a newline Bug fixes: - newline characters in the delimiter set where handled incorrectly in UTF-8 mode Version 1.7: New features: - added dwfilter program which reformats the old text such that it matches the new text to allow other programs such as visual diff tools to show the differences better. dwfilter can also be used to generate regular diffs to patch the old text by reformating the new text as the old text before executing diff [with caveats]. Bug fixes: - \u and \U escapes were parsed incorrectly - dwdiff crashed when generating statistics for empty files Version 1.6.1: Bug fixes: - the line clearing implemented for better background color handling caused (parts of) lines to disappear in the output with cr/nl line endings - the new paragraph separators were not handled correctly with the context matching feature, causing crashes Version 1.6: New features: - the output for deleted text was changed such that the whitespace following the deletion is now the whitespace that followed the deleted text, rather than the whitespace that is now before the next word in the new file - the output for changed text was changed in the case that the whitespace before the old text contains a newline. In this case, depending on whether the whitespace before the new text contains a newline, the new file's whitespace is replaced by a single space or the new text is printed first - the --wdiff-output option was added to revert to the old output mode - the color specification now also allows specification of the background color and custom escape sequences - a new option to add markers for deleted or inserted blocks of lines containing only whitespace (paragraph separators) Bug fixes: - octal escapes are now properly parsed - icu-config was called directly rather than through $ICU_CONFIG in the configure script, which prevented proper operation of the --icu-config option - compilation on systems without nl_langinfo was fixed Version 1.5.2 New features: - better option parsing, which allows short options to be grouped. For example -iPc instead of -i -P -c Bug fixes: - compatibility fixes to configure script Version 1.5.1: Bug fixes: - Statistics are now printed to stderr instead of stdout such that the only thing printed on stdout is the text - Repaired code for diff programs that do not support -a option - Fixed Makefile to pass settings for diff program to C compiler Version 1.5: New features: - added match context which ensures better results for large edits with frequently occuring words Version 1.4: New features: - an option to use all punctuation characters as delimiters - Unicode (UTF-8) support including formatting insensitive comparison - case-insensitive comparison when the underlying diff program does not support it Version 1.3: New features: - an option to print the line numbers at which the text appears in the old and new file respectively - an option to print only a user specified number of context lines surrounding lines with changes Bug fixes: - added printing of color mark-up codes at the start of every new line to improve viewing the output with less - the check for overlap between the delimiter and the whitespace sets was incomplete and incorrect - an inverted condition caused incorrect output if the newline character was not part of the whitespace set Version 1.2.1: Bug fixes: - fixed a bug in color mode where the resetting of a color would cause extra characters to be printed Version 1.2: New features: - color mode, enabled by -c - internationalisation. dwdiff can now use gettext and includes translated manual pages. Languages included in the distribution are: en (default) and nl. Version 1.1: Bug fixes: - fixes bug in \x-escape expansion of whitespace and delimiter lists New features: - will work on POSIX compatible diff, i.e. diff without -a and -i options - handles empty whitespace specification - allows nul character in whitespace and delimiter specification - \-escape expansion of start/stop-delete/insert markers - a single dash (-) can be specified as a file to read from standard input - a double dash (--) will stop dwdiff from interpreting arguments starting with a dash as options - allows the user to specify further options to the diff program to allow minimal diffs, half-hearted algorithms etc. dwdiff-2.0.9/install.sh0000750000175000017500000000570712262313361014643 0ustar gertjangertjan#!/bin/sh # Copyright (C) 2009-2010 G.P. Halkes # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # Set zsh to emulate sh (otherwise all kinds of eval's wont work) [ -n "${ZSH_VERSION}" ] && emulate sh unset directory sources dest mode owner group # Provide an alternative to ! not() { if "$@" ; then false else true fi } # Default mode for install is rwxr-xr-x mode="0755" while [ $# -gt 0 ] do case "$1" in -d) directory="1" ;; -m) mode="$2" shift ;; -m*) mode=`echo "$1" | sed 's/^-m//'` ;; -o) owner="$2" shift ;; -o*) owner=`echo "$1" | sed 's/^-o//'` ;; -g) group="$2" shift ;; -g*) group=`echo "$1" | sed 's/^-g//'` ;; *) break ;; esac shift done if [ "1" = "${directory}" ] ; then if [ $# -eq 0 ] ; then echo "No directory names supplied" >&2 exit 1 fi # Create directories while [ $# -gt 0 ] do if [ ! -d "$1" ] ; then # Find name of dir to apply chown/chgrp -R to, i.e., the first part # of the path that does not yet exist. firstDir="$1" testDir=`dirname "$1"` while [ ! -d "${testDir}" ] ; do firstDir="${testDir}" testDir=`dirname "${firstDir}"` done # Make the directory if not mkdir -p "$1" ; then exit 1 fi if not chmod -R "${mode}" "${firstDir}" ; then exit 1 fi # Set owner and group, if specified if [ -n "${owner}" ] ; then if not chown -R "${owner}" "${firstDir}" ; then exit 1 fi fi if [ -n "${group}" ] ; then if not chgrp -R "${group}" "${firstDir}" ; then exit 1 fi fi fi shift done exit fi if [ $# -lt 2 ] ; then echo "No destination and/or source(s) supplied" >&2 exit 1 fi install_file() { if [ -d "$2" ] ; then echo "Cannot install $2: directory in the way" >&2 exit 1 fi # Copy file if not cp "$1" "$2" ; then exit 1 fi # Set attributes if [ -n "${mode}" ] ; then if not chmod "${mode}" "$2" ; then exit 1 fi fi if [ -n "${owner}" ] ; then if not chown "${owner}" "$2" ; then exit 1 fi fi if [ -n "${group}" ] ; then if not chgrp "${group}" "$2" ; then exit 1 fi fi } eval dest="\"\${$#}\"" if [ -d "${dest}" ] ; then # Loop over all sources, but do not process destination as source while [ $# -gt 1 ] do install_file "$1" "${dest}/`basename \"$1\"`" shift done elif [ $# -eq 2 ] ; then install_file "$1" "${dest}" else echo "Multiple sources specified, but destination is not a directory" >&2 exit 1 fi dwdiff-2.0.9/config.pkg0000660000175000017500000001747412262313361014615 0ustar gertjangertjan# Copyright (C) 2006-2011 G.P. Halkes # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . SWITCHES="+gettext +unicode +dwfilter" OPTIONS="localedir icu-config" COMPILERULE='$(CC) $(CFLAGS) $(GETTEXTFLAGS) $(ICUFLAGS) -c -o $@ $<' LINKRULE='$(CC) $(CFLAGS) $(LDFLAGS) -o .config .config.o $(LDLIBS) $(GETTEXTLIBS) $(ICULIBS)' USERRULES='.SUFFIXES: .mo .po .po.mo: msgfmt -o $@ $< ' TEST_INSTALL="install $PWD/install.sh" DEFAULT_LINGUAS=" de es fr nl" [ -f config.pkg.langpack ] && . config.pkg.langpack USER_HELP=" --without-gettext Disable gettext translations --without-unicode Disable Unicode support --icu-config= Path to icu-config script --localedir= Installation directory for locales [prefix/share/locale] Environment variables: LINGUAS List of languages to install. Available languages are: ${DEFAULT_LINGUAS}" checkfunction() { clean .config.o CHECKFOR="$1" CODE="$2" shift 2 { for INCLUDE do echo "#include ${INCLUDE}" done cat < .config.c clean .config.o test_link "${CHECKFOR}" } config() { # Test for all required functionality cat > .config.c < #include #include #include #include int main(int argc, char *argv[]) { int fd; char buffer[10]; fd = mkstemp("fooXXXXXX"); fd = open("foo", O_RDONLY); read(fd, buffer, 10); lseek(fd, 0, SEEK_SET); write(fd, buffer, 10); close(fd); umask(~S_IRWXU); snprintf(buffer, 10, "%s", "foo"); return 0; } EOF clean .config.o test_link "required functions" || { check_message_result "Testing required functions seperatly for debugging purposes" checkfunction "mkstemp" 'int fd; fd = mkstemp("fooXXXXXX");' "" checkfunction "open" 'int fd; fd = open("foo", O_RDONLY);' "" "" checkfunction "read" 'int fd; char buffer[10]; read(fd, buffer, 10);' "" checkfunction "lseek" "int fd; lseek(fd, 0, SEEK_SET);" "" checkfunction "write" "int fd; char buffer[10]; write(fd, buffer, 10);" "" checkfunction "close" 'int fd; close(fd);' "" checkfunction "umask" 'umask(~S_IRWXU);' "" checkfunction "snprintf" 'char buffer[10]; snprintf(buffer, 10, "%s", "foo");' "" check_message_result "!! A required function is not available." exit 1 } if [ "yes" = "${with_dwfilter}" ] ; then cat > .config.c < #include int main(int argc, char *argv[]) { pid_t pid = fork(); execvp("test", NULL); } EOF clean .config.o test_link "required functions for dwfilter" || { checkfunction "fork" 'pid_t pid = fork();' "" "" checkfunction "execvp" 'execvp("test", NULL);' "" check_message_result "!! A required function for dwfilter is not availabe. Try configuring with --without-dwfilter" exit 1 } DWFILTER="DWFILTER=yes" else DWFILTER="DWFILTER=" fi checkfunction "strdup" "strdup(\"foo\");" "" || CFLAGS="${CFLAGS} -DNO_STRDUP" if [ "yes" = "${with_gettext}" ] || [ "yes" = "${with_unicode}" ] ; then checkfunction "setlocale" "setlocale(LC_ALL, \"\");" "" || { check_message_result "!! Gettext and Unicode support unavailable. Try configuring with --without-gettext --without-unicode" exit 1 } fi unset GETTEXTFLAGS GETTEXTLIBS linguas LOCALEDIR # Check for gettext functionality if [ "yes" = "${with_gettext}" ] ; then cat > .config.c < #include int main(int argc, char *argv[]) { setlocale(LC_ALL, ""); bindtextdomain("dwdiff", "/usr/share/locale"); textdomain("dwdiff"); gettext("dwdiff"); return 0; } EOF { test_compile "gettext and related functions" && { test_link "gettext in standard library" || { test_link "gettext in -lintl" GETTEXTLIBS=-lintl && GETTEXTLIBS=-lintl ; } || { test_link "gettext in -lintl -liconv" "GETTEXTLIBS=-lintl -liconv" && GETTEXTLIBS="-lintl -liconv" ; } } && { clean .config.po .config.mo cat > .config.po <> config.log 2>&1 ; then check_message_result "yes" true else check_message_result "no" false fi } } || { clean .config.po .config.mo check_message_result "!! Could not compile with gettext. Try configuring with --without-gettext." exit 1 } GETTEXTFLAGS="-DUSE_GETTEXT" clean .config.po .config.mo unset linguas if [ -n "${LINGUAS+set}" ] ; then check_message "Checking for available selected translations... " for lingua in ${LINGUAS} do if [ -f "po/${lingua}.po" ] && echo "${linguas}" | not grep "^\\(.* \\)*${lingua}\\( .*\\)*$" > /dev/null ; then linguas="${linguas}${linguas:+ }${lingua}" fi done check_message_result "done [${linguas}]" else linguas="${DEFAULT_LINGUAS}" fi fi if [ "yes" = "${with_unicode}" ] ; then ICU_CONFIG="${option_icu_config:-icu-config}" { { check_message "Checking for icu-config... " echo "Running which ${ICU_CONFIG} >/dev/null" >> config.log if not which "${ICU_CONFIG}" >/dev/null ; then check_message_result "no" check_message_result "!! Could not find icu-config. Ensure that you have installed the development files for libicu, or try configuring with --without-unicode" exit 1 fi echo "Running ${ICU_CONFIG} --cppflags --ldflags" >> config.log if "${ICU_CONFIG}" --cppflags --ldflags 2>&1 > /dev/null ; then check_message_result "yes" true else check_message_result "no" false fi } && { check_message "Checking ICU version >= 3.4... " echo "Running ${ICU_CONFIG} --version" >> config.log ICUVERSION="`\"${ICU_CONFIG}\" --version`" ICUMAJOR="`echo \"${ICUVERSION}\" | sed 's/\..*//'`" ICUMINOR="`echo \"${ICUVERSION}\" | sed -e 's/^[^.]*\.//' -e 's/[^0-9]*$//'`" if expr 3 \< "${ICUMAJOR}" \| \( 3 = "${ICUMAJOR}" \& 4 \<= "${ICUMINOR}" \) >/dev/null ; then check_message_result "yes (${ICUVERSION})" true else check_message_result "no (${ICUVERSION})" false fi } && { cat > .config.c < #include #include int main(int argc, char *argv[]) { UChar32 c; UChar *a, *b; UErrorCode error = U_ZERO_ERROR; u_isUWhiteSpace(c); U_GET_GC_MASK(c); u_strFoldCase(a, 10, b, 10, U_FOLD_CASE_DEFAULT, &error); unorm_normalize(a, 10, UNORM_NFKD, 0, b, 10, &error); u_getIntPropertyValue(c, UCHAR_GRAPHEME_CLUSTER_BREAK); return 0; } EOF clean .config.o test_link "functions in libicu" ICUFLAGS="\`\"${ICU_CONFIG}\" --cppflags\`" ICULIBS="\`\"${ICU_CONFIG}\" --ldflags\`" } } || { check_message_result "!! Could not compile with Unicode support. Try configuring with --without-unicode." exit 1 } ICUFLAGS="-DUSE_UNICODE \`\"${ICU_CONFIG}\" --cppflags\`" ICULIBS="\`\"${ICU_CONFIG}\" --ldflags\`" if checkfunction "nl_langinfo" "nl_langinfo(CODESET);" "" ; then ICUFLAGS="${ICUFLAGS} -DUSE_NL_LANGINFO" fi fi create_makefile "GETTEXTFLAGS=${GETTEXTFLAGS}" "GETTEXTLIBS=${GETTEXTLIBS}" \ "LINGUAS=${linguas}" ${option_localedir:+"LOCALEDIR=${option_localedir}"} \ "ICUFLAGS=${ICUFLAGS}" "ICULIBS=${ICULIBS}" $DWFILTER } sed_lines() { add_replace_settings "$@" } dwdiff-2.0.9/src/0000770000175000017500000000000012262313361013416 5ustar gertjangertjandwdiff-2.0.9/src/unicode.h0000640000175000017500000000453012262313361015216 0ustar gertjangertjan/* Copyright (C) 2008-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #ifndef UNICODE_H #define UNICODE_H #ifdef USE_UNICODE #include "definitions.h" #define UEOF -1 #define UEOVERLONG -2 #define UEINVALID -3 #define UETOOLARGE -4 /* Officially there should be no break between CR and LF. However, on the command line one would commonly write \n to match a line end. On Unix systems it is customary to simply use LF as the line break, so not allowing a break between CR and LF would break expected behaviour if the user were to write \r\n on the command line. Conversely, if the user writes \n on the command line, and the text contains CRLF, the user would expect the \n to match the line feed. The problem here is that there is hardly a good solution, that will satisfy all cases in an intuitive manner. Therefore, I'm going to stick with the Unix EOL convention instead of using the official Unicode way. Users can run dos2unix to convert their documents if need be. */ /* WARNING: changing this to 1 will break the code. DO NOT change!. Places which will definately break if this is changed to 1 will have a static assert on this value being 0. */ #define CRLF_GRAPHEME_CLUSTER_BREAK 0 #include #include typedef VECTOR(UChar, UTF16Buffer); typedef VECTOR(UTF16Buffer, CharList); bool getCluster(Stream *stream, UTF16Buffer *buffer); bool getBackspaceCluster(Stream *stream, UTF16Buffer *buffer); int convertToUTF8(UChar32 c, char *buffer); int filteredConvertToUTF8(UChar32 c, char *buffer, UChar32 *highSurrogate); int putuc(Stream *stream, UChar32 c); void decomposeChar(CharData *c); void casefoldChar(CharData *c); int compareUTF16Buffer(const UTF16Buffer *a, const UTF16Buffer *b); bool isUTF16Punct(UTF16Buffer *buffer); bool isUTF16Whitespace(UTF16Buffer *buffer); #endif #endif dwdiff-2.0.9/src/option.h0000640000175000017500000000326712262313361015106 0ustar gertjangertjan/* Copyright (C) 2008-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #ifndef OPTION_H #define OPTION_H #define DEFAULT_LINENUMBER_WIDTH 4 #define BITMASK_SIZE (UCHAR_MAX+7)/8 struct { InputFile oldFile, newFile; const char *delStart, *delStop, *addStart, *addStop; char *delColor, *addColor; size_t delStartLen, delStopLen, addStartLen, addStopLen, delColorLen, addColorLen; /* Bitmaps for single byte checking. */ char delimiters[BITMASK_SIZE], whitespace[BITMASK_SIZE]; /* Lists for UTF8 mode. */ #ifdef USE_UNICODE CharList delimiterList; CharList whitespaceList; uint32_t punctuationMask; UNormalizationMode decomposition; #endif bool whitespaceSet; bool printDeleted, printAdded, printCommon, needMarkers, needStartStop; bool printer, less, statistics, ignoreCase, colorMode; int lineNumbers; bool context; int contextLines; unsigned matchContext; bool aggregateChanges; bool paraDelim; const char *paraDelimMarker; size_t paraDelimMarkerLength; bool wdiffOutput; FILE *output; bool dwfilterMode; bool repeatMarkers; bool diffInput; } option; void parseCmdLine(int argc, char *argv[]); #endif dwdiff-2.0.9/src/util.c0000640000175000017500000000364612262313361014547 0ustar gertjangertjan/* Copyright (C) 2008-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #include #include #include #include #include #include "definitions.h" /** Alert the user of a fatal error and quit. @param fmt The format string for the message. See fprintf(3) for details. @param ... The arguments for printing. */ void fatal(const char *fmt, ...) { va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); exit(2); } /** Print an out of memory message and exit. */ void outOfMemory(void) { fatal("%s", _("Out of memory")); } /** Perform tolower for the ASCII character set. */ int ASCIItolower(int c) { return (c >= 0x41 && c <= 0x5A) ? c | 0x20 : c; } #ifdef NO_STRDUP char *strdupA(const char *orig) { char *result; if ((result = malloc(strlen(orig) * sizeof(char))) == NULL) return NULL; return strcpy(result, orig); } #endif char *safe_strdup(const char *orig) { char *result = strdupA(orig); if (result == NULL) outOfMemory(); return result; } void *safe_malloc(size_t size) { void *result = malloc(size); if (result == NULL) outOfMemory(); return result; } void *safe_calloc(size_t size) { void *result = calloc(1, size); if (result == NULL) outOfMemory(); return result; } void *safe_realloc(void *ptr, size_t size) { if ((ptr = realloc(ptr, size)) == NULL) outOfMemory(); return ptr; } dwdiff-2.0.9/src/unicode.c0000640000175000017500000004050512262313361015213 0ustar gertjangertjan/* Copyright (C) 2008-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #ifdef USE_UNICODE #include #include #include #include #include "definitions.h" #include "unicode.h" #include "static_assert.h" #include "option.h" /***************************************************************************** Input and output of UTF-8 streams *****************************************************************************/ /** Read in one UTF-8 character. @param stream The @a Stream to read. @retval The first UCS4 character found in the file or an error code. This function does not try to decode sequences that should not occur in valid UTF-8. Because it is more likely that the input is non-UTF-8 than that some program created invalid UTF-8 this is the more sane option. */ static UChar32 getuc(Stream *stream) { int c, bytesLeft; UChar32 retval, least; if ((c = stream->vtable->getChar(stream)) == EOF) return EOF; switch (c) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: case 64: case 65: case 66: case 67: case 68: case 69: case 70: case 71: case 72: case 73: case 74: case 75: case 76: case 77: case 78: case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88: case 89: case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97: case 98: case 99: case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: case 108: case 109: case 110: case 111: case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: case 123: case 124: case 125: case 126: case 127: return c; case 128: case 129: case 130: case 131: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143: case 144: case 145: case 146: case 147: case 148: case 149: case 150: case 151: case 152: case 153: case 154: case 155: case 156: case 157: case 158: case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 169: case 170: case 171: case 172: case 173: case 174: case 175: case 176: case 177: case 178: case 179: case 180: case 181: case 182: case 183: case 184: case 185: case 186: case 187: case 188: case 189: case 190: case 191: return UEINVALID; case 192: case 193: return UEOVERLONG; case 194: case 195: case 196: case 197: case 198: case 199: case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207: case 208: case 209: case 210: case 211: case 212: case 213: case 214: case 215: case 216: case 217: case 218: case 219: case 220: case 221: case 222: case 223: least = 0x80; bytesLeft = 1; retval = c & 0x1F; break; case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 237: case 238: case 239: least = 0x800; bytesLeft = 2; retval = c & 0x0F; break; case 240: case 241: case 242: case 243: case 244: least = 0x10000L; bytesLeft = 3; retval = c & 0x07; break; case 245: case 246: case 247: case 248: case 249: case 250: case 251: case 252: case 253: case 254: case 255: return UETOOLARGE; default: PANIC(); } for (; bytesLeft > 0; bytesLeft--) { if ((c = stream->vtable->getChar(stream)) == EOF) return UEINVALID; if ((c & 0xC0) != 0x80) { stream->vtable->ungetChar(stream, c); return UEINVALID; } retval = (retval << 6) | (c & 0x3F); } if (retval < least) return UEOVERLONG; if (retval > 0x10FFFFL) return UETOOLARGE; return retval; } #define REPLACEMENT_CHARACTER 0xFFFD; /** Get a character from a @a Stream, converting strange characters to REPLACEMENT CHARACTER. @param stream The @a Stream to read from. @return a UCS-4 character or EOF on end-of-file or error. */ UChar32 getucFiltered(Stream *stream) { UChar32 c; if (stream->nextChar >= 0) { c = stream->nextChar; stream->nextChar = -1; } else { c = getuc(stream); } if (c < 0) { return c == EOF ? EOF : REPLACEMENT_CHARACTER; } else if ((c & 0xF800L) == 0xD800L) { UChar32 clow; /* If we just encountered a low surrogate, just replace. */ if ((c & 0xDC00) == 0xDC00) return REPLACEMENT_CHARACTER; clow = getuc(stream); if ((clow & 0xFC00) != 0xDC00) { /* Buffer last read char so we can return next time. Return replacement for high surrogate encountered earlier. */ stream->nextChar = clow; return REPLACEMENT_CHARACTER; } c = clow + (c << 10) + 0x10000 - (0xD800 << 10) - 0xDC00; } return c; } /** Convert one UCS-4 character to UTF-8. @param c The character to convert. @param buffer The buffer to write the result. @return the number of @a char's written to @a buffer. This function does not check for high/low surrogates. */ int convertToUTF8(UChar32 c, char *buffer) { int bytes, i; if (c > 0x10000L) bytes = 4; else if (c > 0x800) bytes = 3; else if (c > 0x80) bytes = 2; else { buffer[0] = c; return 1; } for (i = bytes - 1; i >= 0; i--) { buffer[i] = (c & 0x3F) | 0x80; c >>= 6; } buffer[0] |= 0xF0 << (4 - bytes); return bytes; } /** Convert one UCS-4 character to UTF-8, filtering surrogates. @param c The character to convert. @param buffer The buffer to write the result. @param highSurrogate The location where highSurrogates are stored for this conversion. @return the number of @a char's written to @a buffer. This function also translates high/low surrogate pairs to a single UCS-4 character. Therefore it can also be used to convert UTF-16 to UTF-8. Note that the characters written are supposed to form a valid UTF-16 string, so every high surrogate has to be followed by a low surrogate, and every low surrogate has to be preceeded by a high surrogate. */ int filteredConvertToUTF8(UChar32 c, char *buffer, UChar32 *highSurrogate) { if ((c & 0xFC00) == 0xD800) { *highSurrogate = c; return 0; } if ((c & 0xFC00) == 0xDC00) { ASSERT(*highSurrogate != 0); c = c + ((*highSurrogate) << 10) + 0x10000 - (0xD800 << 10) - 0xDC00; *highSurrogate = 0; } return convertToUTF8(c, buffer); } /** Write out one UCS-4 character as UTF-8. @param stream The @a Stream to write. @param c The character to write. @return 0 for succes, EOF for failure. See @a filteredConvertToUTF8 for more details on the conversion. */ int putuc(Stream *stream, UChar32 c) { char encoded[4]; int bytes = filteredConvertToUTF8(c, encoded, &stream->highSurrogate); if (bytes == 0) return 0; return fileWrite(stream->data.file, encoded, bytes) < bytes ? EOF : 0; } #define MAX_GCB_CLASS 13 /* This will warn us if we compile against a new library with more cluster break classes. */ #ifdef DEBUG static_assert(U_GCB_COUNT <= MAX_GCB_CLASS); #endif /* Latest version of the algorithm, with all its classes, can be found at http://www.unicode.org/reports/tr29/ */ /* The values of the constants _should_ not change from version to version, but better safe than sorry. */ static_assert(U_GCB_OTHER == 0); static_assert(U_GCB_CONTROL == 1); static_assert(U_GCB_CR == 2); static_assert(U_GCB_EXTEND == 3); static_assert(U_GCB_L == 4); static_assert(U_GCB_LF == 5); static_assert(U_GCB_LV == 6); static_assert(U_GCB_LVT == 7); static_assert(U_GCB_T == 8); static_assert(U_GCB_V == 9); #if ICU_VERSION_MAJOR_NUM > 3 static_assert(U_GCB_SPACING_MARK == 10); static_assert(U_GCB_PREPEND == 11); #if ICU_VERSION_MAJOR_NUM > 4 static_assert(U_GCB_REGIONAL_INDICATOR == 12); #endif #endif /** Table used for determining wheter a grapheme break exists between two characters. */ static char clusterContinuationTable[MAX_GCB_CLASS][MAX_GCB_CLASS] = { {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, CRLF_GRAPHEME_CLUSTER_BREAK, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1}, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1} }; /** Table used for determining wheter a break exists between two characters when using backspace to overstrike characters. */ static char backspaceContinuationTable[MAX_GCB_CLASS][MAX_GCB_CLASS] = { {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; static void addUCS4ToUTF16Buffer(UTF16Buffer *buffer, UChar32 c); /** Retrieve the Grapheme cluster break category for a character. This ensures that cluster categories above the compiled-in maximum are folded to the "other" category. Should a newer version of the ICU library return values higher than the expected value, this will not pose significant problems. */ static int getClusterCategory(UChar32 c) { int category = u_getIntPropertyValue(c, UCHAR_GRAPHEME_CLUSTER_BREAK); return category >= MAX_GCB_CLASS ? U_GCB_OTHER : category; } /** Get the next Cluster from a stream. @param stream The @a Stream to read. @param buffer The @a UTF16Buffer to store the Cluster. @param continuationTable The table to use for looking up continuations. @return a boolean indicating whether the reading was successful. */ static bool getClusterInternal(Stream *stream, UTF16Buffer *buffer, char continuationTable[MAX_GCB_CLASS][MAX_GCB_CLASS]) { int32_t newClusterCategory; /* Empty buffer. */ buffer->used = 0; /* Check if we have already read a character on a previous occasion. */ if (stream->bufferedChar < 0) { if ((stream->bufferedChar = getucFiltered(stream)) < 0) return false; newClusterCategory = getClusterCategory(stream->bufferedChar); } else { newClusterCategory = stream->lastClusterCategory; } /* Append characters as long as the cluster categories dictate. */ do { stream->lastClusterCategory = newClusterCategory; addUCS4ToUTF16Buffer(buffer, stream->bufferedChar); if ((stream->bufferedChar = getucFiltered(stream)) < 0) { if (isFileStream(stream)) fileClearEof(stream->data.file); newClusterCategory = 0; break; } newClusterCategory = getClusterCategory(stream->bufferedChar); } while (continuationTable[stream->lastClusterCategory][newClusterCategory]); /* Save grapheme category for next call. */ stream->lastClusterCategory = newClusterCategory; return true; } /** Get the next Grapheme Cluster from a stream. @param stream The @a Stream to read. @param buffer The @a UTF16Buffer to store the Grapheme Cluster. @return a boolean indicating whether the reading was successful. */ bool getCluster(Stream *stream, UTF16Buffer *buffer) { return getClusterInternal(stream, buffer, clusterContinuationTable); } /** Get the next Backspace Cluster from a stream. @param stream The @a Stream to read. @param buffer The @a UTF16Buffer to store the Backspace Cluster. @return a boolean indicating whether the reading was successful. */ bool getBackspaceCluster(Stream *stream, UTF16Buffer *buffer) { return getClusterInternal(stream, buffer, backspaceContinuationTable); } /***************************************************************************** UTF16Buffer operations *****************************************************************************/ /** Append a 24 bit UCS-4 character to a UTF-16 encoded buffer. @param buffer The UTF16Buffer structure to append to. @param c The character to append. */ static void addUCS4ToUTF16Buffer(UTF16Buffer *buffer, UChar32 c) { if (c > 0x10000) { VECTOR_APPEND(*buffer, 0xD800 - (0x10000 >> 10) + (c >> 10)); VECTOR_APPEND(*buffer, 0xDC00 | (c & 0x3FF)); } else { VECTOR_APPEND(*buffer, (UChar) c); } } /** Decompose a Grapheme Cluster according to the standard decomposition. @param c The Grapheme Cluster to decompose. */ void decomposeChar(CharData *c) { UErrorCode error = U_ZERO_ERROR; size_t requiredLength; requiredLength = unorm_normalize(c->UTF8Char.original.data, c->UTF8Char.original.used, option.decomposition, 0, c->UTF8Char.converted.data, c->UTF8Char.converted.allocated, &error); if (requiredLength > c->UTF8Char.converted.allocated) { ASSERT(error == U_BUFFER_OVERFLOW_ERROR); error = U_ZERO_ERROR; VECTOR_ALLOCATE(c->UTF8Char.converted, requiredLength * sizeof(UChar)); requiredLength = unorm_normalize(c->UTF8Char.original.data, c->UTF8Char.original.used, option.decomposition, 0, c->UTF8Char.converted.data, c->UTF8Char.converted.allocated, &error); } ASSERT(U_SUCCESS(error)); c->UTF8Char.converted.used = requiredLength; } /** Fold the case of a Grapheme Cluster. @param c The Grapheme Cluster to case-fold. */ void casefoldChar(CharData *c) { UErrorCode error = U_ZERO_ERROR; size_t requiredLength; requiredLength = u_strFoldCase(c->UTF8Char.casefolded.data, c->UTF8Char.casefolded.allocated, c->UTF8Char.converted.data, c->UTF8Char.converted.used, U_FOLD_CASE_DEFAULT, &error); if (requiredLength > c->UTF8Char.casefolded.allocated) { ASSERT(error == U_BUFFER_OVERFLOW_ERROR); error = U_ZERO_ERROR; c->UTF8Char.casefolded.data = realloc(c->UTF8Char.casefolded.data, requiredLength * sizeof(UChar)); c->UTF8Char.casefolded.allocated = requiredLength; requiredLength = u_strFoldCase(c->UTF8Char.casefolded.data, c->UTF8Char.casefolded.allocated, c->UTF8Char.converted.data, c->UTF8Char.converted.used, U_FOLD_CASE_DEFAULT, &error); } ASSERT(U_SUCCESS(error)); c->UTF8Char.casefolded.used = requiredLength; } /* An initial size of 4 will provide sufficient space for most graphmes. There may be some cases in which this is not enough, but the buffer will be grown if this is the case. The reason for the ifndef is that for testing of the code to grow the buffers, we need to be able to set the size to 1. */ #ifndef UTF16BUFFER_INITIAL_SIZE #define UTF16BUFFER_INITIAL_SIZE 4 #endif /** Compare two UTF16Buffer's for sorting purposes */ int compareUTF16Buffer(const UTF16Buffer *a, const UTF16Buffer *b) { size_t minlen = a->used < b->used ? a->used : b->used; int result; result = memcmp(a->data, b->data, minlen * sizeof(UChar)); if (result) return result; if (b->used > minlen) return -1; if (a->used > minlen) return 1; return 0; } #define UTF16CharCondition(name, condition) bool isUTF16##name(UTF16Buffer *buffer) { \ UChar32 c; size_t i; \ for (i = 0; i < buffer->used; i++) { \ \ if ((buffer->data[i] & 0xFC00) == 0xD800) { \ ASSERT(i + 1 < buffer->used); \ c = ((((UChar32) buffer->data[i]) & 0x3FF) << 10) + 0x10000 + (buffer->data[i + 1] & 0x3FF); \ i++; \ } else { \ c = buffer->data[i]; \ } \ if (!(condition)) \ return false; \ } \ return true; \ } \ /** Check if a @a UTF16Buffer contains a punctuation character. */ UTF16CharCondition(Punct, U_GET_GC_MASK(c) & option.punctuationMask) /** Check if a @a UTF16Buffer contains a punctuation character. */ UTF16CharCondition(Whitespace, u_isUWhiteSpace(c)) #endif dwdiff-2.0.9/src/static_assert.h0000640000175000017500000000254512262313361016444 0ustar gertjangertjan/* Copyright (C) 2008 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #ifndef STATIC_ASSERT #define STATIC_ASSERT /* The static_assert is achieved by creating a struct definition which contains an array of negative size if the condition is false. To prevent multiple static assertions to define the same struct, the line number on which the assertion name of the struct is made is appended to the name of the struct. However, to do this we need another layer of indirection because the arguments of ## are not expanded before pasting. */ #define __static_assert(_condition, _line) struct __static_assert_##_line { int static_assert_failed[_condition ? 1 : -1]; } #define _static_assert(_condition, _line) __static_assert(_condition, _line) #define static_assert(_condition) _static_assert(_condition, __LINE__) #endif dwdiff-2.0.9/src/tempfile.h0000640000175000017500000000166512262313361015403 0ustar gertjangertjan/* Copyright (C) 2008-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #ifndef TEMPFILE_H #define TEMPFILE_H #include "stream.h" #define TEMPLATE "/tmp/dwdiffXXXXXXXX" #define TEMPLATE_LENGTH sizeof(TEMPLATE) typedef struct { Stream *stream; char name[TEMPLATE_LENGTH]; bool closed; } TempFile; TempFile *tempFile(void); void closeTempFile(TempFile *file); void resetTempFiles(void); #endif dwdiff-2.0.9/src/tempfile.c0000640000175000017500000000474712262313361015402 0ustar gertjangertjan/* Copyright (C) 2006-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #include #include #include #include #include "definitions.h" #include "stream.h" static TempFile files[6]; static unsigned openIndex = 0; #ifndef LEAVE_FILES static bool inited; #endif /** Create a temporary file. */ TempFile *tempFile(void) { #ifndef LEAVE_FILES int fd; #endif ASSERT(openIndex < sizeof(files) / sizeof(files[0])); #ifdef LEAVE_FILES strcpy(files[openIndex].name, "dwdiffTemp"); sprintf(files[openIndex].name + strlen(files[openIndex].name), "%d", openIndex); if ((files[openIndex].stream = newFileStream(fileOpen(files[openIndex].name, FILE_WRITE))) == NULL) return NULL; #else /* Create temporary file. */ if (!inited) { /* Make sure the umask is set so that we don't introduce a security risk. */ umask(~S_IRWXU); /* Make sure we will remove temporary files on exit. */ atexit(resetTempFiles); inited = true; } strcpy(files[openIndex].name, TEMPLATE); if ((fd = mkstemp(files[openIndex].name)) < 0) return NULL; if ((files[openIndex].stream = newFileStream(fileWrapFD(fd, FILE_WRITE))) == NULL) return NULL; #endif return files + openIndex++; } /** Closes a temporary file by closing its stream. @param file The ::TempFile to close. This function will close the stream, but it does not remove the temporary file. This will be done by the ::cleanup function at exit. It is permissible to call this function with the same argument more than once. */ void closeTempFile(TempFile *file) { if (!file->closed) { sfclose(file->stream); file->closed = true; } } /** Remove all the created temporary files and reset the data structures. */ void resetTempFiles(void) { unsigned i; for (i = 0; i < openIndex; i++) { closeTempFile(&files[i]); remove(files[i].name); files[i].closed = false; files[i].stream = NULL; memset(files[i].name, 0, sizeof(files[i].name)); } openIndex = 0; } dwdiff-2.0.9/src/hashtable.c0000640000175000017500000000764312262313361015526 0ustar gertjangertjan/* Copyright (C) 2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #include #include #include #include "definitions.h" #include "hashtable.h" #define MEMBLOCK_SIZE 32768 #define ALIGNOF(type) offsetof(struct { char c; type member; }, member) #define ROUNDUP(x, to) (((x + (to - 1)) / to) * to) typedef struct MemBlock { struct MemBlock *next; size_t size; size_t idx; } MemBlock; static MemBlock *head; #define HASHTABLE_SIZE 8091 typedef struct Tuple { ValueType value; size_t stringLength; struct Tuple *next; char string[1]; } Tuple; static Tuple *hashtable[HASHTABLE_SIZE]; static ValueType nextValue; ValueType baseHashMax; static Tuple *allocFromBlock(size_t size) { Tuple *result; size = ROUNDUP(size, ALIGNOF(Tuple)); if (head == NULL || size > head->size - head->idx) { MemBlock *newBlock; if (size > 2048) { newBlock = safe_malloc(size + sizeof(MemBlock)); newBlock->size = size + sizeof(MemBlock); } else { newBlock = safe_malloc(MEMBLOCK_SIZE); newBlock->size = MEMBLOCK_SIZE; } newBlock->idx = ROUNDUP(sizeof(MemBlock), ALIGNOF(Tuple)); newBlock->next = head; head = newBlock; } result = (Tuple *)(((char *) head) + head->idx); head->idx += size; return result; } static void freeBlocks(void) { MemBlock *ptr; while (head != NULL) { ptr = head; head = head->next; free(ptr); } } #ifdef PROFILE_HASH static int collisions; static int hits; void printHashStatistics(void) { fprintf(stderr, "Hash statistics: unique words: %d, collisions %d (%.2f%%), hits %d\n", (int) nextValue, collisions, (double) collisions * 100.0 / nextValue, hits); collisions = 0; hits = 0; } #endif /** Calculate a hash value for a string. @param key The string to hash. @return The hash value associated with the string. This function uses the djb2 hash function. */ static unsigned int hash(void *data, size_t size) { const unsigned char *ptr; size_t i; unsigned int hashValue = 5381; ptr = data; for (i = 0; i < size; i++) hashValue = (hashValue << 5) + hashValue + (unsigned int) *ptr++; return hashValue; } /** Get the value associated with a word. @param word The word to get the value for. This function gets the value associated with a word. If the word has not been seen before a new value will be given. */ ValueType getValueFromContext(CharBuffer *word) { return getValue(word->data, word->used); } ValueType getValue(void *data, size_t size) { Tuple *tuple; unsigned int hashValue = hash(data, size) % HASHTABLE_SIZE; tuple = hashtable[hashValue]; /* Search the singly linked list. */ while (tuple != NULL && !(size == tuple->stringLength && memcmp(data, tuple->string, size) == 0)) tuple = tuple->next; if (tuple == NULL) { ASSERT(nextValue != VALUE_MAX); #ifdef PROFILE_HASH if (hashtable[hashValue] != NULL) collisions++; #endif tuple = allocFromBlock(sizeof(Tuple) - 1 + size); tuple->value = nextValue++; tuple->stringLength = size; memcpy(tuple->string, data, size); tuple->next = hashtable[hashValue]; hashtable[hashValue] = tuple; } #ifdef PROFILE_HASH else hits++; #endif return tuple->value; } ValueType getHashMax(void) { ValueType hashMax = nextValue; int i; #ifdef PROFILE_HASH printHashStatistics(); #endif /* Reset the hashtable for the next iteration. */ for (i = 0; i < HASHTABLE_SIZE; i++) hashtable[i] = NULL; freeBlocks(); nextValue = 0; return hashMax; } dwdiff-2.0.9/src/dispatch.h0000640000175000017500000000446212262313361015373 0ustar gertjangertjan/* Copyright (C) 2008 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #ifndef DISPATH_H #define DISPATH_H #include "definitions.h" #define CHARLIST SWITCH_UNICODE(CharList, void) /* The FPTR macro serves only as a placeholder to allow easy generation of the code in dispatch_autogen.h. */ #define FPTR typedef struct { /** Get the next character from the input. @param file The file to read. @return True if the end of the file has not been reached. */ FPTR bool (*getNextCharDT)(Stream *file); /** Test if a character is a whitespace character. */ FPTR bool (*isWhitespaceDT)(void); /** Test if a character is a delimiter character. */ FPTR bool (*isDelimiterDT)(void); /** Write a character to a token file. @param file The file to write to. */ FPTR void (*writeTokenCharDT)(InputFile *file); /** Write a character to a token file. @param file The file to write to. */ FPTR void (*writeWhitespaceCharDT)(InputFile *file); /** Write a delimiter to the whitespace file. @param file The file to write to. */ FPTR void (*writeWhitespaceDelimiterDT)(InputFile *file); /** Add all characters to the specified list or bitmap. @param chars The string with characters to add to the list or bitmap. @param list The list to add to. @param bitmap. The bitmap to add to. If in UTF-8 mode, the characters will be added to the list. Otherwise to the bitmap. */ FPTR void (*addCharactersDT)(const char *chars, size_t length, CHARLIST *list, char bitmap[BITMASK_SIZE]); /** Check for overlap in whitespace and delimiter sets. */ FPTR void (*checkOverlapDT)(void); FPTR void (*setPunctuationDT)(void); FPTR void (*initOptionsDT)(void); FPTR void (*postProcessOptionsDT)(void); } DispatchTable; extern DispatchTable *dispatch; #include "dispatch_autogen.h" #endif dwdiff-2.0.9/src/dwfilter.c0000640000175000017500000001357612262313361015415 0ustar gertjangertjan/* Copyright (C) 2010-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #include #include #include #include #include #include #include #include "definitions.h" #include "util.h" #include "optionMacros.h" #define DWFILTER_COMPILE #include "optionDescriptions.h" #define TEMPLATE "/tmp/dwdiffXXXXXXXX" #define TEMPLATE_LENGTH sizeof(TEMPLATE) #ifndef DWDIFF # define DWDIFF "dwdiff" #endif struct { int oldFile, newFile; bool reverse; int postProcessorStart; } option; static PARSE_FUNCTION(parseCmdLine) int noOptionCount = 0; bool discard; /* Initialise options to correct values */ memset(&option, 0, sizeof(option)); OPTIONS OPTION('d', "delimiters", REQUIRED_ARG) END_OPTION OPTION('P', "punctuation", NO_ARG) END_OPTION OPTION('W', "white-space", REQUIRED_ARG) END_OPTION OPTION('h', "help", NO_ARG) int i = 0; printf(_("Usage: dwfilter [OPTIONS] [POST PROCESSOR OPTIONS]\n")); while (descriptions[i] != NULL) fputs(_(descriptions[i++]), stdout); exit(EXIT_SUCCESS); END_OPTION OPTION('v', "version", NO_ARG) fputs("dwfilter " VERSION_STRING "\n", stdout); fputs( /* TRANSLATORS: - If the (C) symbol (that is the c in a circle) is not available, leave as it as is. (Unicode code point 0x00A9) - G.P. Halkes is name and should be left as is. */ _("Copyright (C) 2006-2011 G.P. Halkes\nLicensed under the GNU General Public License version 3\n"), stdout); exit(EXIT_SUCCESS); END_OPTION OPTION('i', "ignore-case", NO_ARG) END_OPTION OPTION('I', "ignore-formatting", NO_ARG) END_OPTION SINGLE_DASH switch (noOptionCount++) { case 0: option.oldFile = optargind; break; case 1: option.newFile = optargind; break; default: option.postProcessorStart = optargind; STOP_OPTION_PROCESSING; break; } END_OPTION DOUBLE_DASH NO_MORE_OPTIONS; END_OPTION OPTION('C', "context", REQUIRED_ARG) END_OPTION OPTION('m', "match-context", REQUIRED_ARG) END_OPTION BOOLEAN_LONG_OPTION("aggregate-changes", discard) OPTION('A', "algorithm", REQUIRED_ARG) END_OPTION BOOLEAN_LONG_OPTION("wdiff-output", discard) /* FIXME: make this work again, after fixing dwdiff */ /* OPTION('S', "paragraph-separator", OPTIONAL_ARG) END_OPTION */ BOOLEAN_OPTION('r', "reverse", option.reverse) fatal(_("Option %.*s does not exist\n"), OPTPRARG); NO_OPTION switch (noOptionCount++) { case 0: option.oldFile = optargind; break; case 1: option.newFile = optargind; break; default: option.postProcessorStart = optargind; STOP_OPTION_PROCESSING; break; } END_OPTIONS /* Check that we have something to work with. */ if (noOptionCount < 2) fatal(_("Need two files to compare\n")); if (noOptionCount < 3) fatal(_("No post processor specified\n")); END_FUNCTION static char tempfile[TEMPLATE_LENGTH]; static void cleanup(void) { unlink(tempfile); } static void createTempfile(void) { int fd; /* Create temporary file. */ /* Make sure the umask is set so that we don't introduce a security risk. */ umask(~S_IRWXU); /* Make sure we will remove temporary files on exit. */ atexit(cleanup); strcpy(tempfile, TEMPLATE); if ((fd = mkstemp(tempfile)) < 0) fatal(_("Could not create temporary file: %s\n"), strerror(errno)); close(fd); } static int execute(char * const args[]) { pid_t pid; int status; if ((pid = fork()) == 0) { execvp(args[0], args); exit(127); } else if (pid < 0) { fatal(_("Could not execute %s: %s\n"), args[0], strerror(errno)); } pid = wait(&status); if (pid < 0) fatal(_("Error waiting for child process to terminate: %s\n"), strerror(errno)); return WEXITSTATUS(status); } #define OUTPUT_OPTION "--dwfilter=" int main(int argc, char *argv[]) { char **cmdArgs; char *outputArg; int i, j; #if defined(USE_GETTEXT) || defined(USE_UNICODE) setlocale(LC_ALL, ""); #endif #ifdef USE_GETTEXT bindtextdomain("dwdiff", LOCALEDIR); textdomain("dwdiff"); #endif parseCmdLine(argc, argv); createTempfile(); cmdArgs = safe_malloc(sizeof(char *) * (option.postProcessorStart + 7)); outputArg = safe_malloc(sizeof(char) * (strlen(tempfile) + sizeof(OUTPUT_OPTION))); cmdArgs[0] = safe_strdup(DWDIFF); /* argument has been allocated to correct size above, so we can safely use sprintf */ sprintf(outputArg, OUTPUT_OPTION "%s", tempfile); cmdArgs[1] = outputArg; for (i = 1, j = 2; i < option.postProcessorStart; i++) if (i != option.oldFile && i != option.newFile) cmdArgs[j++] = argv[i]; cmdArgs[j++] = safe_strdup("-w"); cmdArgs[j++] = safe_strdup(""); cmdArgs[j++] = safe_strdup("-x"); cmdArgs[j++] = safe_strdup(""); cmdArgs[j++] = safe_strdup("-2"); cmdArgs[j++] = argv[option.reverse ? option.newFile : option.oldFile]; cmdArgs[j++] = argv[option.reverse ? option.oldFile : option.newFile]; cmdArgs[j++] = NULL; if (execute(cmdArgs) > 2) fatal(_("dwdiff returned an error\n")); free(outputArg); free(cmdArgs); cmdArgs = safe_malloc(sizeof(char *) * (argc - option.postProcessorStart + 3)); for (i = option.postProcessorStart, j = 0; i < argc; i++, j++) cmdArgs[j] = argv[i]; cmdArgs[j++] = option.reverse ? argv[option.oldFile] : tempfile; cmdArgs[j++] = option.reverse ? tempfile : argv[option.newFile]; cmdArgs[j++] = NULL; return execute(cmdArgs); } dwdiff-2.0.9/src/hashtable.h0000640000175000017500000000156312262313361015526 0ustar gertjangertjan/* Copyright (C) 2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #ifndef HASHTABLE_H #define HASHTABLE_H #include #include "definitions.h" #include "buffer.h" ValueType getValueFromContext(CharBuffer *word); ValueType getValue(void *data, size_t size); ValueType getHashMax(void); extern ValueType baseHashMax; #endif dwdiff-2.0.9/src/option.c0000640000175000017500000005352412262313361015102 0ustar gertjangertjan/* Copyright (C) 2006-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #include #include #include "definitions.h" #include "stream.h" #include "unicode.h" #include "optionMacros.h" #include "option.h" #include "util.h" #include "buffer.h" #include "dispatch.h" #define DWDIFF_COMPILE #include "optionDescriptions.h" typedef struct { const char *name; const char *description; const char *sequence; const char *backgroundSequence; } Color; Color colors[] = { { "black", N_("Black"), "30", "40" }, { "red", N_("Red"), "31", "41" }, { "green", N_("Green"), "32", "42" }, { "brown", N_("Brown"), "33", "43" }, { "blue", N_("Blue"), "34", "44" }, { "magenta", N_("Magenta"), "35", "45" }, { "cyan", N_("Cyan"), "36", "46" }, { "gray", N_("Gray"), "37", "47" }, { "dgray", N_("Dark gray"), "30;1", NULL }, { "bred", N_("Bright red"), "31;1", NULL }, { "bgreen", N_("Bright green"), "32;1", NULL }, { "yellow", N_("Yellow"), "33;1", NULL }, { "bblue", N_("Bright blue"), "34;1", NULL }, { "bmagenta", N_("Bright magenta"), "35;1", NULL }, { "bcyan", N_("Bright cyan"), "36;1", NULL }, { "white", N_("White"), "37;1", NULL }, { NULL, NULL, NULL, NULL } }; /** Compare two strings, ignoring case. @param a The first string to compare. @param b The first string to compare. @return an integer smaller, equal, or larger than zero to indicate that @a a sorts before, the same, or after @a b. */ int strCaseCmp(const char *a, const char *b) { int ca, cb; while ((ca = tolower(*a++)) == (cb = tolower(*b++)) && ca != 0) {} return ca == cb ? 0 : (ca < cb ? -1 : 1); } /** Convert a string from the input format to an internally usable string. @param string A @a Token with the string to be converted. @param descr A description of the string to be included in error messages. @return The length of the resulting string. The use of this function processes escape characters. The converted characters are written in the original string. */ static size_t parseEscapes(char *string, const char *descr) { size_t maxReadPosition = strlen(string); size_t readPosition = 0, writePosition = 0; size_t i; while (readPosition < maxReadPosition) { if (string[readPosition] == '\\') { readPosition++; if (readPosition == maxReadPosition) { fatal(_("Single backslash at end of %s argument\n"), descr); } switch(string[readPosition++]) { case 'n': string[writePosition++] = '\n'; break; case 'r': string[writePosition++] = '\r'; break; case '\'': string[writePosition++] = '\''; break; case '\\': string[writePosition++] = '\\'; break; case 't': string[writePosition++] = '\t'; break; case 'b': string[writePosition++] = '\b'; break; case 'f': string[writePosition++] = '\f'; break; case 'a': string[writePosition++] = '\a'; break; case 'v': string[writePosition++] = '\v'; break; case '?': string[writePosition++] = '\?'; break; case '"': string[writePosition++] = '"'; break; case 'e': string[writePosition++] = '\033'; break; case 'x': { /* Hexadecimal escapes */ unsigned int value = 0; /* Read at most two characters, or as many as are valid. */ for (i = 0; i < 2 && (readPosition + i) < maxReadPosition && isxdigit(string[readPosition + i]); i++) { value <<= 4; if (isdigit(string[readPosition + i])) value += (int) (string[readPosition + i] - '0'); else value += (int) (tolower(string[readPosition + i]) - 'a') + 10; if (value > UCHAR_MAX) /* TRANSLATORS: The %s argument is a long option name without preceding dashes. */ fatal(_("Invalid hexadecimal escape sequence in %s argument\n"), descr); } readPosition += i; if (i == 0) /* TRANSLATORS: The %s argument is a long option name without preceding dashes. */ fatal(_("Invalid hexadecimal escape sequence in %s argument\n"), descr); string[writePosition++] = (char) value; break; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { /* Octal escapes */ int value = (int)(string[readPosition - 1] - '0'); size_t maxIdx = string[readPosition - 1] < '4' ? 2 : 1; for (i = 0; i < maxIdx && readPosition + i < maxReadPosition && string[readPosition + i] >= '0' && string[readPosition + i] <= '7'; i++) value = value * 8 + (int)(string[readPosition + i] - '0'); readPosition += i; string[writePosition++] = (char) value; break; } #ifdef USE_UNICODE case 'u': case 'U': { UChar32 value = 0; size_t chars = string[readPosition - 1] == 'U' ? 8 : 4; if (maxReadPosition < readPosition + chars) /* TRANSLATORS: The %c argument will be either 'u' or 'U'. The %s argument is a long option name without preceding dashes. */ fatal(_("Too short \\%c escape in %s argument\n"), string[readPosition - 1], descr); for (i = 0; i < chars; i++) { if (!isxdigit(string[readPosition + i])) /* TRANSLATORS: The %c argument will be either 'u' or 'U'. The %s argument is a long option name without preceding dashes. */ fatal(_("Too short \\%c escape in %s argument\n"), string[readPosition - 1], descr); value <<= 4; if (isdigit(string[readPosition + i])) value += (int) (string[readPosition + i] - '0'); else value += (int) (tolower(string[readPosition + i]) - 'a') + 10; } if (value > 0x10FFFFL) /* TRANSLATORS: The %s argument is a long option name without preceding dashes. */ fatal(_("\\U escape out of range in %s argument\n"), descr); if ((value & 0xF800L) == 0xD800L) /* TRANSLATORS: The %s argument is a long option name without preceding dashes. */ fatal(_("\\%c escapes for surrogate codepoints are not allowed in %s argument\n"), string[readPosition - 1], descr); /* The conversion won't overwrite subsequent characters because \uxxxx is already the as long as the max utf-8 length */ writePosition += convertToUTF8(value, string + writePosition); readPosition += chars; break; } #endif default: string[writePosition++] = string[readPosition - 1]; break; } } else { string[writePosition++] = string[readPosition++]; } } /* Terminate string. */ string[writePosition] = 0; return writePosition; } static void noDefaultMarkers(void) { /* Note: then lenghts are 0 by default. */ if (option.addStart == NULL) option.addStart = ""; if (option.addStop == NULL) option.addStop = ""; if (option.delStart == NULL) option.delStart = ""; if (option.delStop == NULL) option.delStop = ""; } /*===============================================================*/ /* Single character (SC) versions of the addCharacters and checkOverlap routines. Descriptions can be found in the definition of the DispatchTable struct. */ /** Add all characters to the specified list or bitmap. @param chars The string with characters to add to the list or bitmap. @param list The list to add to. @param bitmap. The bitmap to add to. If in UTF-8 mode, the characters will be added to the list. Otherwise to the bitmap. */ void addCharactersSC(const char *chars, size_t length, CHARLIST *list, char bitmap[BITMASK_SIZE]) { size_t i; /* Suppress unused parameter warning in semi-portable way. */ (void) list; for (i = 0; i < length; i++) { SET_BIT(bitmap, chars[i]); } } /** Check for overlap in whitespace and delimiter sets. */ void checkOverlapSC(void) { int i; if (!option.whitespaceSet) return; for (i = 0; i <= UCHAR_MAX; i++) { if (!TEST_BIT(option.delimiters, i)) continue; if (TEST_BIT(option.whitespace, i)) fatal(_("Whitespace and delimiter sets overlap\n")); } } void setPunctuationSC(void) { int i; for (i = 0; i <= UCHAR_MAX; i++) { if (!ispunct(i)) continue; SET_BIT(option.delimiters, i); } } void initOptionsSC(void) {} void postProcessOptionsSC(void) { if (!option.whitespaceSet) { int i; for (i = 0; i <= UCHAR_MAX; i++) { if (!TEST_BIT(option.delimiters, i) && isspace(i)) SET_BIT(option.whitespace, i); } } if (!TEST_BIT(option.whitespace, ' ')) option.wdiffOutput = true; } #ifdef USE_UNICODE /*===============================================================*/ /* UTF-8 versions of the addCharacters and checkOverlap routines. Descriptions can be found in the definition of the DispatchTable struct. */ /** Add all characters to the specified list. @param chars The string with characters to add to the list or bitmap. @param list The list to add to. @param bitmap. The bitmap to add to (unused). */ void addCharactersUTF8(const char *chars, size_t length, CHARLIST *list, char bitmap[BITMASK_SIZE]) { Stream *charStream; CharData cluster; /* Suppress unused parameter warning in semi-portable way. */ (void) bitmap; VECTOR_INIT_ALLOCATED(cluster.UTF8Char.original); VECTOR_INIT_ALLOCATED(cluster.UTF8Char.converted); charStream = newStringStream(chars, length); while (getCluster(charStream, &cluster.UTF8Char.original)) { UTF16Buffer tmp; size_t i; decomposeChar(&cluster); /* Check for duplicates */ for (i = 0; i < list->used; i++) if (compareUTF16Buffer(&cluster.UTF8Char.converted, &list->data[i]) == 0) break; /* continue won't work because we're in a for-loop */ if (i != list->used) continue; tmp.used = cluster.UTF8Char.converted.used; tmp.data = safe_malloc(cluster.UTF8Char.converted.used * sizeof(UChar)); tmp.allocated = cluster.UTF8Char.converted.used; memcpy(tmp.data, cluster.UTF8Char.converted.data, cluster.UTF8Char.converted.used * sizeof(UChar)); VECTOR_APPEND(*list, tmp); } VECTOR_FREE(cluster.UTF8Char.original); VECTOR_FREE(cluster.UTF8Char.converted); free(charStream); } /** Check for overlap in whitespace and delimiter sets. */ void checkOverlapUTF8(void) { size_t i, j; if (!option.whitespaceSet) return; /* Check for overlap can be done in O(N) because the lists have already been sorted in postProcessOptionsUTF8. */ for (i = 0, j = 0; i < option.delimiterList.used; i++) { for (; j < option.whitespaceList.used && compareUTF16Buffer(&option.delimiterList.data[i], &option.whitespaceList.data[j]) > 0; j++) /* NO-OP */; if (j == option.whitespaceList.used) break; if (compareUTF16Buffer(&option.delimiterList.data[i], &option.whitespaceList.data[j]) == 0) fatal(_("Whitespace and delimiter sets overlap\n")); } if (option.punctuationMask == 0) return; for (i = 0; i < option.whitespaceList.used; i++) { if (isUTF16Punct(&option.whitespaceList.data[i])) fatal(_("Whitespace and delimiter sets overlap\n")); } return; } void setPunctuationUTF8(void) { option.punctuationMask = U_GC_P_MASK | U_GC_S_MASK; } void initOptionsUTF8(void) { VECTOR_INIT_ALLOCATED(option.whitespaceList); VECTOR_INIT_ALLOCATED(option.delimiterList); } void postProcessOptionsUTF8(void) { static_assert(CRLF_GRAPHEME_CLUSTER_BREAK == 0); qsort(option.delimiterList.data, option.delimiterList.used, sizeof(UTF16Buffer), (int (*)(const void *, const void *)) compareUTF16Buffer); qsort(option.whitespaceList.data, option.whitespaceList.used, sizeof(UTF16Buffer), (int (*)(const void *, const void *)) compareUTF16Buffer); VECTOR_APPEND(charData.UTF8Char.converted, ' '); if (classifyChar() != CAT_WHITESPACE) option.wdiffOutput = true; charData.UTF8Char.converted.used = 0; } /*===============================================================*/ #endif #define SEQUENCE_BUFFER_LEN 20 static char *parseColor(const char *_color) { char sequenceBuffer[SEQUENCE_BUFFER_LEN]; char *colon, *color; int i, fg = -1, bg = -1; color = strdupA(_color); if (strncmp("e:", color, 2) == 0) { /* Custom color string */ parseEscapes(color + 2, "color"); memmove(color, color + 2, strlen(color) + 1); return color; } colon = strchr(color, ':'); if (colon != NULL && strrchr(color, ':') != colon) fatal(_("Invalid color specification %s\n"), color); if (colon != NULL) *colon++ = 0; if (*color != 0) { for (i = 0; colors[i].name != NULL; i++) { if (strCaseCmp(color, colors[i].name) == 0) { fg = i; break; } } if (colors[i].name == NULL) fatal(_("Invalid color %s\n"), color); } if (colon != NULL) { if (*colon != 0) { for (i = 0; colors[i].backgroundSequence != NULL; i++) { if (strCaseCmp(colon, colors[i].name) == 0) { bg = i; break; } } if (colors[i].backgroundSequence == NULL) fatal(_("Invalid background color %s\n"), colon); } } if (fg >= 0) { if (bg >= 0) snprintf(sequenceBuffer, SEQUENCE_BUFFER_LEN, "\033[0;%s;%sm", colors[fg].sequence, colors[bg].backgroundSequence); else snprintf(sequenceBuffer, SEQUENCE_BUFFER_LEN, "\033[0;%sm", colors[fg].sequence); } else { if (bg >= 0) snprintf(sequenceBuffer, SEQUENCE_BUFFER_LEN, "\033[0%sm", colors[bg].backgroundSequence); } free(color); return strdupA(sequenceBuffer); } PARSE_FUNCTION(parseCmdLine) char *comma; int noOptionCount = 0; /* Initialise options to correct values */ memset(&option, 0, sizeof(option)); option.printDeleted = option.printAdded = option.printCommon = true; option.matchContext = 2; option.output = stdout; initOptions(); ONLY_UNICODE(option.decomposition = UNORM_NFD;) option.needStartStop = true; option.paraDelimMarker = "<-->"; option.paraDelimMarkerLength = strlen(option.paraDelimMarker); OPTIONS OPTION('d', "delimiters", REQUIRED_ARG) size_t length = parseEscapes(optArg, "delimiters"); addCharacters(optArg, length, SWITCH_UNICODE(&option.delimiterList, NULL), option.delimiters); END_OPTION OPTION('P', "punctuation", NO_ARG) setPunctuation(); END_OPTION OPTION('W', "white-space", REQUIRED_ARG) size_t length = parseEscapes(optArg, "whitespace"); option.whitespaceSet = true; addCharacters(optArg, length, SWITCH_UNICODE(&option.whitespaceList, NULL), option.whitespace); END_OPTION OPTION('h', "help", NO_ARG) int i = 0; printf(_("Usage: dwdiff [OPTIONS] \n")); while (descriptions[i] != NULL) fputs(_(descriptions[i++]), stdout); exit(EXIT_SUCCESS); END_OPTION OPTION('v', "version", NO_ARG) fputs("dwdiff " VERSION_STRING "\n", stdout); fputs( /* TRANSLATORS: - If the (C) symbol (that is the c in a circle) is not available, leave as it as is. (Unicode code point 0x00A9) - G.P. Halkes is name and should be left as is. */ _("Copyright (C) 2006-2011 G.P. Halkes and others\nLicensed under the GNU General Public License version 3\n"), stdout); exit(EXIT_SUCCESS); END_OPTION OPTION('1', "no-deleted", NO_ARG) option.printDeleted = false; if (!option.printAdded) option.needMarkers = true; if (!option.printCommon || !option.printAdded) option.needStartStop = false; END_OPTION OPTION('2', "no-inserted", NO_ARG) option.printAdded = false; if (!option.printDeleted) option.needMarkers = true; if (!option.printCommon || !option.printDeleted) option.needStartStop = false; END_OPTION OPTION('3', "no-common", NO_ARG) option.printCommon = false; option.needMarkers = true; END_OPTION OPTION('i', "ignore-case", NO_ARG) option.ignoreCase = true; END_OPTION #ifdef USE_UNICODE OPTION('I', "ignore-formatting", NO_ARG) if (UTF8Mode) option.decomposition = UNORM_NFKD; else fatal(_("Option %.*s is only supported for UTF-8 mode\n"), OPTPRARG); #else OPTION('I', "ignore-formatting", NO_ARG) fatal(_("Support for option %.*s is not compiled into this version of dwdiff\n"), OPTPRARG); #endif END_OPTION OPTION('s', "statistics", NO_ARG) option.statistics = true; END_OPTION OPTION('a', "autopager", NO_ARG) fatal(_("Option %.*s is not supported\n"), OPTPRARG); END_OPTION OPTION('p', "printer", NO_ARG) option.printer = true; noDefaultMarkers(); END_OPTION OPTION('l', "less", NO_ARG) option.less = true; noDefaultMarkers(); END_OPTION OPTION('t', "terminal", NO_ARG) fatal(_("Option %.*s is not supported\n"), OPTPRARG); END_OPTION OPTION('w', "start-delete", REQUIRED_ARG) option.delStartLen = parseEscapes(optArg, "start-delete"); option.delStart = optArg; END_OPTION OPTION('x', "stop-delete", REQUIRED_ARG) option.delStopLen = parseEscapes(optArg, "stop-delete"); option.delStop = optArg; END_OPTION OPTION('y', "start-insert", REQUIRED_ARG) option.addStartLen = parseEscapes(optArg, "start-insert"); option.addStart = optArg; END_OPTION OPTION('z', "stop-insert", REQUIRED_ARG) option.addStopLen = parseEscapes(optArg, "stop-insert"); option.addStop = optArg; END_OPTION OPTION('n', "avoid-wraps", NO_ARG) fatal(_("Option %.*s is not supported\n"), OPTPRARG); END_OPTION SINGLE_DASH switch (noOptionCount++) { case 0: option.oldFile.input = newFileStream(fileWrapFD(STDIN_FILENO, FILE_READ)); break; case 1: if (option.oldFile.name == NULL) fatal(_("Can't read both files from standard input\n")); option.newFile.input = newFileStream(fileWrapFD(STDIN_FILENO, FILE_READ)); break; default: fatal(_("Too many files to compare\n")); } END_OPTION DOUBLE_DASH NO_MORE_OPTIONS; END_OPTION OPTION('c', "color", OPTIONAL_ARG) option.colorMode = true; if (optArg != NULL) { int i; if (strCaseCmp(optArg, "list") == 0) { fputs( /* TRANSLATORS: "Name" and "Description" are table headings for the color name list. Make sure you keep the alignment of the headings over the text. */ _("Name Description\n"), stdout); fputs("-- --\n", stdout); for (i = 0; colors[i].name != NULL; i++) printf("%-15s %s\n", colors[i].name, _(colors[i].description)); fputc('\n', stdout); fputs(_("The colors black through gray are also usable as background color\n"), stdout); exit(EXIT_SUCCESS); } comma = strchr(optArg, ','); if (comma != NULL && strrchr(optArg, ',') != comma) fatal(_("Invalid color specification %s\n"), optArg); if (comma != NULL) *comma++ = 0; option.delColor = parseColor(optArg[0] == 0 ? "bred" : optArg); option.addColor = parseColor(comma == NULL ? "bgreen" : comma); } else { option.delColor = parseColor("bred"); option.addColor = parseColor("bgreen"); } option.delColorLen = strlen(option.delColor); option.addColorLen = strlen(option.addColor); noDefaultMarkers(); END_OPTION OPTION('L', "line-numbers", OPTIONAL_ARG) if (optArg != NULL) PARSE_INT(option.lineNumbers, 1, INT_MAX); else option.lineNumbers = DEFAULT_LINENUMBER_WIDTH; END_OPTION OPTION('C', "context", REQUIRED_ARG) PARSE_INT(option.contextLines, 0, INT_MAX); option.context = true; initContextBuffers(); END_OPTION OPTION('m', "match-context", REQUIRED_ARG) PARSE_INT(option.matchContext, 0, (INT_MAX - 1) / 2); option.matchContext *= 2; END_OPTION BOOLEAN_LONG_OPTION("aggregate-changes", option.aggregateChanges) OPTION('S', "paragraph-separator", OPTIONAL_ARG) option.paraDelim = true; if (optArg != NULL) { option.paraDelimMarker = optArg; option.paraDelimMarkerLength = parseEscapes(optArg, "paragraph-separator"); } END_OPTION BOOLEAN_LONG_OPTION("wdiff-output", option.wdiffOutput) LONG_OPTION("dwfilter", REQUIRED_ARG) option.dwfilterMode = true; if ((option.output = fopen(optArg, "r+")) == NULL) fatal(_("Error opening temporary output file: %s\n"), strerror(errno)); END_OPTION OPTION('r', "reverse", NO_ARG) if (!option.dwfilterMode) fatal(_("Option %.*s does not exist\n"), OPTPRARG); END_OPTION OPTION('R', "repeat-markers", NO_ARG) option.repeatMarkers = true; END_OPTION LONG_OPTION("diff-input", NO_ARG) option.diffInput = true; END_OPTION OPTION('A', "algorithm", REQUIRED_ARG) if (strcmp(optArg, "best") == 0) { minimal = true; speed_large_files = false; } else if (strcmp(optArg, "normal") == 0) { minimal = false; speed_large_files = false; } else if (strcmp(optArg, "fast") == 0) { minimal = false; speed_large_files = true; } else { fatal(_("Invalid algorithm name\n")); } END_OPTION fatal(_("Option %.*s does not exist\n"), OPTPRARG); NO_OPTION switch (noOptionCount++) { case 0: option.oldFile.name = optcurrent; break; case 1: option.newFile.name = optcurrent; break; default: fatal(_("Too many files to compare\n")); } END_OPTIONS /* Check that we have something to work with. */ if (option.diffInput) { if (noOptionCount > 1) fatal(_("Only one input file accepted with --diff-input\n")); if (noOptionCount == 0) option.oldFile.input = newFileStream(fileWrapFD(STDIN_FILENO, FILE_READ)); } else { if (noOptionCount != 2) fatal(_("Need two files to compare\n")); } /* Check and set some values */ if (option.delStart == NULL) { option.delStart = "[-"; option.delStartLen = 2; } if (option.delStop == NULL) { option.delStop = "-]"; option.delStopLen = 2; } if (option.addStart == NULL) { option.addStart = "{+"; option.addStartLen = 2; } if (option.addStop == NULL) { option.addStop = "+}"; option.addStopLen = 2; } if (!option.printCommon && !option.printAdded && !option.printDeleted) option.needMarkers = false; if ((!option.printAdded + !option.printDeleted + !option.printCommon) == 2) option.needStartStop = false; postProcessOptions(); checkOverlap(); END_FUNCTION dwdiff-2.0.9/src/file.c0000640000175000017500000001416312262313361014505 0ustar gertjangertjan/* Copyright (C) 2008-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #include #include #include #include #include #include "definitions.h" #include "file.h" #include "util.h" #include "option.h" static int filePutcReal(File *file, int c); static int fileWriteReal(File *file, const char *buffer, int bytes); static int fileFlushReal(File *file); static FileVtable vtableReal = { fileWriteReal, filePutcReal, fileFlushReal }; /** Wrap a file descriptor in a @a File struct. */ File *fileWrapFD(int fd, FileMode mode) { File *retval = malloc(sizeof(File)); if (retval == NULL) return NULL; retval->fd = fd; retval->errNo = 0; retval->bufferFill = 0; retval->bufferIndex = 0; retval->eof = EOF_NO; retval->mode = mode; retval->vtable = &vtableReal; return retval; } /** Open a file. @param name The name of the file to open. @param mode The mode of the file to open. @a mode must be one of @a FILE_READ or @a FILE_WRITE. @a FILE_WRITE can only be used if compiled with LEAVE_FILES. */ File *fileOpen(const char *name, FileMode mode) { int fd, openMode; switch (mode) { case FILE_READ: openMode = O_RDONLY; break; #ifdef LEAVE_FILES case FILE_WRITE: openMode = O_RDWR | O_CREAT | O_TRUNC; break; #endif default: PANIC(); } if ((fd = open(name, openMode, 0600)) < 0) return NULL; return fileWrapFD(fd, mode); } /** Get the next character from a @a File. */ int fileGetc(File *file) { ASSERT(file->mode == FILE_READ); if (file->errNo != 0) return EOF; if (file->bufferIndex >= file->bufferFill) { ssize_t bytesRead = 0; if (file->eof != EOF_NO) { file->eof = EOF_HIT; return EOF; } /* Use while loop to allow interrupted reads */ while (1) { ssize_t retval = read(file->fd, file->buffer + bytesRead, FILE_BUFFER_SIZE - bytesRead); if (retval == 0) { file->eof = EOF_COMING; break; } else if (retval < 0) { if (errno == EINTR) continue; file->errNo = errno; break; } else { bytesRead += retval; if (bytesRead == FILE_BUFFER_SIZE) break; } } if (file->errNo != 0) return EOF; if (bytesRead == 0) { file->eof = EOF_HIT; return EOF; } file->bufferFill = bytesRead; file->bufferIndex = 0; } return (unsigned char) file->buffer[file->bufferIndex++]; } /** Push a character back into the buffer for a @a File. */ int fileUngetc(File *file, int c) { ASSERT(file->mode == FILE_READ); if (file->errNo != 0) return EOF; ASSERT(file->bufferIndex > 0); return file->buffer[--file->bufferIndex] = (unsigned char) c; } /** Flush the buffer associated with a @a File to disk. */ static int flushBuffer(File *file) { ssize_t bytesWritten = 0; if (file->mode == FILE_READ) return 0; if (file->errNo != 0) return EOF; if (file->bufferFill == 0) return 0; /* Use while loop to allow interrupted reads */ while (1) { ssize_t retval = write(file->fd, file->buffer + bytesWritten, file->bufferFill - bytesWritten); if (retval == 0) { PANIC(); } else if (retval < 0) { if (errno == EINTR) continue; file->errNo = errno; return EOF; } else { bytesWritten += retval; if (bytesWritten == file->bufferFill) break; } } file->bufferFill = 0; return bytesWritten; } /** Close a @a File. */ int fileClose(File *file) { int retval = flushBuffer(file); if (close(file->fd) < 0 && retval == 0) { retval = errno; } else { retval = 0; } free(file); return retval; } static int fileFlushReal(File *file) { return flushBuffer(file) == EOF ? -1 : 0; /* The code below also fsync's the data to disk. However, this should not be necessary to allow another program to read the entire file. It does however slow the program down, so we skip it. */ /* if (flushBuffer(file) == EOF) return -1; fsync(file->fd); return 0; */ } /** Write a character to a @a File. */ static int filePutcReal(File *file, int c) { ASSERT(file->mode == FILE_WRITE); if (file->errNo != 0) return EOF; if (file->bufferFill >= FILE_BUFFER_SIZE) { if (flushBuffer(file) == EOF) return EOF; } file->buffer[file->bufferFill++] = (unsigned char) c; return 0; } /** Write a buffer to a @a File. */ static int fileWriteReal(File *file, const char *buffer, int bytes) { ASSERT(file->mode == FILE_WRITE); if (file->errNo != 0) return EOF; while (1) { size_t minLength = FILE_BUFFER_SIZE - file->bufferFill < bytes ? FILE_BUFFER_SIZE - file->bufferFill : bytes; memcpy(file->buffer + file->bufferFill, buffer, minLength); file->bufferFill += minLength; bytes -= minLength; if (bytes == 0) return 0; if (flushBuffer(file) == EOF) return EOF; buffer += minLength; } } /** Write a string to a @a File. */ int filePuts(File *file, const char *string) { size_t length; ASSERT(file->mode == FILE_WRITE); if (file->errNo != 0) return EOF; length = strlen(string); return fileWrite(file, string, length); } /** Rewind a @a File, changing its mode. */ int fileRewind(File *file, FileMode mode) { ASSERT(mode == FILE_READ || (file->mode == FILE_WRITE && mode == FILE_WRITE)); if (flushBuffer(file) != 0) return -1; if (lseek(file->fd, 0, SEEK_SET) < 0) { file->errNo = errno; return -1; } file->eof = EOF_NO; file->mode = mode; return 0; } /** Return if a @a File is in error state. */ int fileError(File *file) { return file->errNo != 0; } /** Return if a @a File is at the end of file. */ int fileEof(File *file) { return file->eof == EOF_HIT; } /** Get the errno for the failing action on a @a File. */ int fileGetErrno(File *file) { return file->errNo; } void fileClearEof(File *file) { file->eof = EOF_COMING; } dwdiff-2.0.9/src/buffer.h0000640000175000017500000000170712262313361015044 0ustar gertjangertjan/* Copyright (C) 2008-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #ifndef BUFFER_H #define BUFFER_H #include "vector.h" typedef VECTOR(char, CharBuffer); void initContextBuffers(void); void addchar(char c, bool common); void printLineNumbers(int oldLineNumber, int newLineNumber); void writeString(const char *string, size_t bytes); #define INITIAL_BUFFER_SIZE 80 #define INITIAL_WORD_BUFFER_SIZE 32 #endif dwdiff-2.0.9/src/SciTEDirectory.properties0000640000175000017500000000110612262313361020365 0ustar gertjangertjan# C/C++ overrides make.command=LANG= make -C $(SciteDirectoryHome) --no-print-directory -j`egrep -c '^processor[[:space:]]+:' /proc/cpuinfo` openpath.*=$(SciteDirectoryHome) command.compile.$(file.patterns.c)=$(cc) command.build.$(file.patterns.c)=$(make.command) command.go.$(file.patterns.c)=$(FileName) # To make the Go command both compile (if needed) and execute, use this setting: #command.go.needs.*.c=g++ $(FileNameExt) -o $(FileName) command.name.9.$(file.patterns.c)=Make clean command.9.$(file.patterns.c)=$(make.command) clean keywords5.$(file.patterns.cpp)=USE_UNICODEdwdiff-2.0.9/src/buffer.c0000640000175000017500000001631612262313361015041 0ustar gertjangertjan/* Copyright (C) 2007-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #include #include #include #include #include "definitions.h" #include "util.h" #include "option.h" #include "buffer.h" typedef enum { PRINTING_CHANGED, PRINTING_AFTER_CONTEXT, PRE_BUFFERING, BUFFERING, /* The initial states are only used at the start of printing, to prevent printing of the separator string (--) before the first block of output. */ PRE_BUFFERING_INITIAL, BUFFERING_INITIAL } PrintState; static CharBuffer *contextBuffers; static PrintState state = PRE_BUFFERING_INITIAL; static int bufferIndex; static int afterContextLines; /** Initialize the context buffers. */ void initContextBuffers(void) { int i; errno = 0; contextBuffers = (CharBuffer *) safe_malloc((option.contextLines + 1) * sizeof(CharBuffer)); for (i = 0; i <= option.contextLines; i++) VECTOR_INIT(contextBuffers[i]); } /** Write a character, buffering if necessary. @param c The character to write. @param common Boolean to indicate whether the character belongs to both the old and the new file. */ void addchar(char c, bool common) { /* Using ignore variable to shut up gcc about the warn_unused_result attribute set on fwrite. */ int i, ignore; if (!option.context) { putc(c, option.output); return; } /* Check whether we have buffered output that we need to print because of encountering a non-common character. */ if (!common) { switch (state) { case PRINTING_CHANGED: case PRINTING_AFTER_CONTEXT: break; /* If we have entered a regular buffering state, all buffers are in use. However, the set of buffers is used as a ring buffer so first print all buffers after the current one, then print all buffers before the current. */ case BUFFERING: ignore = fwrite("--\n", 1, 3, option.output); case BUFFERING_INITIAL: for (i = bufferIndex + 1; i <= option.contextLines; i++) ignore = fwrite(contextBuffers[i].data, 1, contextBuffers[i].used, option.output); /* FALLTHROUGH */ /* In pre-buffering state, only the first buffers are used. Once we start wrapping around, we change state to a regular buffering state. */ case PRE_BUFFERING: case PRE_BUFFERING_INITIAL: for (i = 0; i <= bufferIndex; i++) ignore = fwrite(contextBuffers[i].data, 1, contextBuffers[i].used, option.output); break; default: PANIC(); } state = PRINTING_CHANGED; } /* Decided whether to buffer or print the character. */ switch (state) { case BUFFERING: case PRE_BUFFERING: case BUFFERING_INITIAL: case PRE_BUFFERING_INITIAL: VECTOR_APPEND(contextBuffers[bufferIndex], c); break; case PRINTING_AFTER_CONTEXT: case PRINTING_CHANGED: putc(c, option.output); break; default: PANIC(); } if (c == '\n') { switch (state) { case PRINTING_CHANGED: if (option.contextLines == 0) { state = PRE_BUFFERING; break; } state = PRINTING_AFTER_CONTEXT; afterContextLines = 0; break; case PRINTING_AFTER_CONTEXT: afterContextLines++; if (afterContextLines == option.contextLines) { state = PRE_BUFFERING; bufferIndex = 0; } break; case PRE_BUFFERING_INITIAL: case PRE_BUFFERING: bufferIndex++; /* Once we have filled all buffers, we change to a regular buffering state. */ if (bufferIndex > option.contextLines) { state = state == PRE_BUFFERING ? BUFFERING : BUFFERING_INITIAL; bufferIndex = 0; } break; case BUFFERING_INITIAL: case BUFFERING: bufferIndex++; if (bufferIndex > option.contextLines) bufferIndex = 0; break; default: PANIC(); } /* We just saw a newline, so we have either entered a buffering state, or already were in one, and finished filling the old buffer. The new buffer must be filled from the start. */ contextBuffers[bufferIndex].used = 0; } } /* Macro to ensure we use the same format and arguments for printing the line number information in all print statements. */ #define LINENUMBERS_FMT_ARGS "%*d:%-*d ", option.lineNumbers, oldLineNumber, option.lineNumbers, newLineNumber /** Print line number information, buffering if necessary. @param oldLineNumber The line number in the old file. @param newLineNumber The line number in the new file. */ void printLineNumbers(int oldLineNumber, int newLineNumber) { int printed, allowed; if (!option.context) { printf(LINENUMBERS_FMT_ARGS); return; } switch (state) { case BUFFERING: case PRE_BUFFERING: case BUFFERING_INITIAL: case PRE_BUFFERING_INITIAL: allowed = contextBuffers[bufferIndex].allocated - contextBuffers[bufferIndex].used; /* SUSv2 specification of snprintf does not handle zero sized buffers nicely :-( Therefore, we have to ensure that there is at least room for one byte, but as we will be printing 2 numbers and a colon and a space, we might as well ask for 4 bytes. */ VECTOR_ALLOCATE(contextBuffers[bufferIndex], 4); printed = snprintf(contextBuffers[bufferIndex].data + contextBuffers[bufferIndex].used, allowed, LINENUMBERS_FMT_ARGS); /* If there was not enough room to hold all the bytes for the line numbers, resize the buffer and try again. */ if (printed > allowed) { VECTOR_ALLOCATE(contextBuffers[bufferIndex], printed); allowed = contextBuffers[bufferIndex].allocated - contextBuffers[bufferIndex].used; printed = snprintf(contextBuffers[bufferIndex].data + contextBuffers[bufferIndex].used, allowed, LINENUMBERS_FMT_ARGS); } /* Sanity check: the number of characters printed should be at least 2 [probably 4, but I don't know all possible number systems]. */ ASSERT(printed >= 2); contextBuffers[bufferIndex].used += printed; break; case PRINTING_AFTER_CONTEXT: case PRINTING_CHANGED: printf(LINENUMBERS_FMT_ARGS); break; default: PANIC(); } } /** Print a string, buffering if necessary. @param string The string to print. @param bytes The length of the string. The string should not contain newline characters. */ void writeString(const char *string, size_t bytes) { /* Using ignore variable to shut up gcc about the warn_unused_result attribute set on fwrite. */ int ignore; if (!option.context) { ignore = fwrite(string, 1, bytes, option.output); return; } switch (state) { case BUFFERING: case PRE_BUFFERING: case BUFFERING_INITIAL: case PRE_BUFFERING_INITIAL: VECTOR_ALLOCATE(contextBuffers[bufferIndex], bytes); memcpy(contextBuffers[bufferIndex].data + contextBuffers[bufferIndex].used, string, bytes); contextBuffers[bufferIndex].used += bytes; break; case PRINTING_AFTER_CONTEXT: case PRINTING_CHANGED: ignore = fwrite(string, 1, bytes, option.output); break; default: PANIC(); } } dwdiff-2.0.9/src/util.h0000640000175000017500000000242412262313361014545 0ustar gertjangertjan/* Copyright (C) 2008-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #ifndef UTIL_H #define UTIL_H #ifdef __GNUC__ void fatal(const char *fmt, ...) __attribute__((format (printf, 1, 2))) __attribute__((noreturn)); #else /*@noreturn@*/ void fatal(const char *fmt, ...); #endif int ASCIItolower(int c); #ifdef DEBUG #define PANIC() do { fprintf(stderr, _("Program-logic error at %s:%d\n"), __FILE__, __LINE__); abort(); } while (0) #else #define PANIC() fatal(_("Program-logic error at %s:%d\n"), __FILE__, __LINE__) #endif #define ASSERT(_condition) do { if (!(_condition)) PANIC(); } while(0) char *safe_strdup(const char *orig); void *safe_malloc(size_t size); void *safe_calloc(size_t size); void *safe_realloc(void *ptr, size_t size); #endif dwdiff-2.0.9/src/file.h0000640000175000017500000000460512262313361014512 0ustar gertjangertjan/* Copyright (C) 2008-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #ifndef FILE_H #define FILE_H #include "buffer.h" /* Note: files opened for write can also be read. However, not vice versa. */ typedef enum { FILE_READ, FILE_WRITE } FileMode; typedef enum { EOF_NO, EOF_COMING, EOF_HIT } EOFState; #ifdef PAGE_SIZE #define FILE_BUFFER_SIZE PAGE_SIZE #else #define FILE_BUFFER_SIZE 4096 #endif struct FileVtable; typedef struct File { /* FD this struct is buffering */ int fd; /* 0, or the error code of the failed operation. Further operations will fail immediately. */ int errNo; /* Current mode associated with the File. */ FileMode mode; /* Buffer containing data from the file. */ char buffer[FILE_BUFFER_SIZE]; int bufferFill; /* Current index in the buffer. */ int bufferIndex; /* Flag to indicate whether filling the buffer hit end of file. */ EOFState eof; struct FileVtable *vtable; } File; typedef struct FileVtable { /* Functions to call for fileWrite and filePutc. Different implementations are provided such that diffing with context can be easily done. */ int (*fileWrite)(struct File *file, const char *buffer, int bytes); int (*filePutc)(struct File *file, int c); int (*fileFlush)(struct File *file); } FileVtable; #define fileFlush(file) ((file)->vtable->fileFlush(file)) #define filePutc(file, c) ((file)->vtable->filePutc((file), (c))) #define fileWrite(file, buffer, bytes) ((file)->vtable->fileWrite((file), (buffer), (bytes))) File *fileWrapFD(int fd, FileMode mode); File *fileOpen(const char *name, FileMode mode); int fileGetc(File *file); int fileUngetc(File *file, int c); int fileClose(File *file); int filePuts(File *file, const char *string); int fileRewind(File *file, FileMode mode); int fileError(File *file); int fileGetErrno(File *file); int fileEof(File *file); void fileClearEof(File *file); #endif dwdiff-2.0.9/src/optionMacros.h0000640000175000017500000002412512262313361016247 0ustar gertjangertjan/* Copyright (C) 2006-2010 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #ifndef OPTIONMACROS_H #define OPTIONMACROS_H #include #include #include #include /* INSTRUCTIONS: - A fatal routine should be provided. - If gettext is required, define the _ macro. Otherwise, the empty definition here will be used. However, if the macro USE_GETTEXT is defined, the automatic definition in this file will not be used to make sure a wrong order of definitions is detected. - Option parsing may change the argument vector. If this should not happen, define the macro OPTION_STRDUP such that it allocates a copy of the string passed to it. - Printing options should be done by using the "%.*s" format and "(int) optlength, optcurrent" arguments or even better, the OPTFMT format macor and OPTPRARG arg. A simple example argument parser is shown below: PARSE_FUNCTION(parse_options) OPTIONS OPTION('f', "long-f", REQUIRED_ARG) END_OPTION DOUBLE_DASH NO_MORE_OPTIONS; END_OPTION printf("Unknown option " OPTFMT "\n", OPTPRARG); NO_OPTION printf("Non-option argument: " OPTFMT "\n", OPTPRARG); END_OPTIONS END_FUNCTION */ /* Definitions to make the macro's work regardless of configuration. */ #if !defined _ && !defined USE_GETTEXT #define _(_x) (_x) #endif #ifndef OPTION_STRDUP #define OPTION_STRDUP(_x) (_x) #define OPTION_FREE(_x) (void) 0 #else #define OPTION_FREE(_x) free(_x) #endif /** Format string for printing options. */ #define OPTFMT "%.*s" /** Arguments for printf style functions, to be used in combination with @a OPTFMT. */ #define OPTPRARG (int) optlength, optcurrent /** Define an option parsing function. @param name The name of the function to define. */ #define PARSE_FUNCTION(name) void name(int argc, char **argv) {\ char *optArg; \ int optargind; \ int optnomore = 0; /** Declare a chile option parsing function. @param name The name of the function to define. */ #define CHILD_PARSE_FUNCTION_DECL(name) int name(int argc, char **argv, char *optcurrent, char *optArg, size_t optlength, ArgType opttype, int _optargind); /** Define a chile option parsing function. @param name The name of the function to define. */ #define CHILD_PARSE_FUNCTION(name) int name(int argc, char **argv, char *optcurrent, char *optArg, size_t optlength, ArgType opttype, int _optargind) { \ int optargind = _optargind, optcontrol = 0; /** Signal the end of a child option parsing function. */ #define END_CHILD_FUNCTION return -1; check_next: if (optargind != _optargind) return 4; return optcontrol; } /** Call a child option parsing function. @param name The name of the function to call. */ #define CALL_CHILD(name) do { int retval = name(argc, argv, optcurrent, optArg, optlength, opttype, optargind); \ if (retval == -1) break; \ else if (retval == 4) optargind++; \ else if (retval == 1) optcontrol++; \ goto check_next; } while (0) /** Indicate the start of option processing. This is separte from @a PARSE_FUNCTION so that local variables can be defined. */ #define OPTIONS \ for (optargind = 1; optargind < argc; optargind++) { \ char optcontrol = 0; \ char *optcurrent, *optptr; \ optcurrent = argv[optargind]; \ if (optcurrent[0] == '-' && !optnomore) { \ size_t optlength; \ ArgType opttype; \ \ if (optcurrent[1] == '-') { \ if ((optArg = strchr(optcurrent, '=')) == NULL) { \ optlength = strlen(optcurrent); \ } else { \ optlength = optArg - optcurrent; \ optArg++; \ } \ opttype = LONG; \ } else { \ optlength = 2; \ if (optcurrent[1] != 0 && optcurrent[2] != 0) \ optArg = optcurrent + 2; \ else \ optArg = NULL; \ opttype = SHORT; \ } \ if (optlength > INT_MAX) optlength = INT_MAX; \ next_opt: /* The last line above is to make sure the cast to int in error messages does not overflow. */ /** Signal the start of non-switch option processing. */ #define NO_OPTION } else { /** Signal the end of option processing. */ #define END_OPTIONS check_next: if (optcontrol == 1 || optcontrol == 3) { \ if (optcontrol == 1) { \ optptr = optcurrent = OPTION_STRDUP(optcurrent); \ } \ optcontrol = 2; \ optcurrent++; \ optcurrent[0] = '-'; \ optArg = optcurrent[2] != 0 ? optcurrent + 2 : NULL; \ goto next_opt; \ } else if (optcontrol == 2) { \ OPTION_FREE(optptr); \ } }} goto stop_opt_parse; stop_opt_parse:; /** Signal the end of the option processing function. */ #define END_FUNCTION } /** Internal macro to check whether the requirements regarding option arguments have been met. */ #define CHECK_ARG(argReq) \ switch(argReq) { \ case NO_ARG: \ if (optArg != NULL) { \ if (opttype == SHORT) { \ optcontrol++; \ optArg = NULL; \ } else { \ fatal(_("Option %.*s does not take an argument\n"), OPTPRARG); \ } \ } \ break; \ case REQUIRED_ARG: \ if (optArg == NULL && (optargind+1 >= argc)) { \ fatal(_("Option %.*s requires an argument\n"), OPTPRARG); \ } \ if (optArg == NULL) optArg = argv[++optargind]; \ break; \ default: \ break; \ } /** Check for a short style (-o) option. @param shortName The name of the short style option. @param argReq Whether or not an argument is required/allowed. One of NO_ARG, OPTIONAL_ARG or REQUIRED_ARG. */ #define SHORT_OPTION(shortName, argReq) if (opttype == SHORT && optcurrent[1] == shortName) { CHECK_ARG(argReq) { /** Check for a single dash as option. This is usually used to signal standard input/output. */ #define SINGLE_DASH SHORT_OPTION('\0', NO_ARG) /** Check for a double dash as option. This is usually used to signal the end of options. */ #define DOUBLE_DASH LONG_OPTION("", NO_ARG) /** Check for a short style (-o) or long style (--option) option. @param shortName The name of the short style option. @param longName The name of the long style option. @param argReq Whether or not an argument is required/allowed. One of NO_ARG, OPTIONAL_ARG or REQUIRED_ARG. */ #define OPTION(shortName, longName, argReq) if ((opttype == SHORT && optcurrent[1] == shortName) || (opttype == LONG && strlen(longName) == optlength - 2 && strncmp(optcurrent + 2, longName, optlength - 2) == 0)) { CHECK_ARG(argReq) { /** Check for a long style (--option) option. @param longName The name of the long style option. @param argReq Whether or not an argument is required/allowed. One of NO_ARG, OPTIONAL_ARG or REQUIRED_ARG. */ #define LONG_OPTION(longName, argReq) if (opttype == LONG && strlen(longName) == optlength - 2 && strncmp(optcurrent + 2, longName, optlength - 2) == 0) { CHECK_ARG(argReq) { /** Signal the end of processing for the previous (SHORT_|LONG_)OPTION. */ #define END_OPTION } goto check_next; } /** Check for presence of a short style (-o) option and set the variable if so. @param shortName The name of the short style option. @param var The variable to set. */ #define BOOLEAN_SHORT_OPTION(shortName, var) SHORT_OPTION(shortName, NO_ARG) var = 1; END_OPTION /** Check for presence of a long style (--option) option and set the variable if so. @param longName The name of the long style option. @param var The variable to set. */ #define BOOLEAN_LONG_OPTION(longName, var) LONG_OPTION(longName, NO_ARG) var = 1; END_OPTION /** Check for presence of a short style (-o) or long style (--option) option and set the variable if so. @param shortName The name of the short style option. @param longName The name of the long style option. @param var The variable to set. */ #define BOOLEAN_OPTION(shortName, longName, var) OPTION(shortName, longName, NO_ARG) var = 1; END_OPTION /** Tell option processor that all further arguments are non-option arguments. */ #define NO_MORE_OPTIONS do { optnomore = 1; } while(0) /** Tell option processor to jump out of option processing. */ #define STOP_OPTION_PROCESSING do { goto stop_opt_parse; } while(0) /** Check an option argument for an integer value. @param var The variable to store the result in. @param min The minimum allowable value. @param max The maximum allowable value. */ #define PARSE_INT(var, min, max) do {\ char *endptr; \ long value; \ errno = 0; \ \ value = strtol(optArg, &endptr, 10); \ if (*endptr != 0) { \ fatal(_("Garbage after value for %.*s option\n"), OPTPRARG); \ } \ if (errno != 0 || value < min || value > max) { \ fatal(_("Value for %.*s option (%ld) is out of range\n"), OPTPRARG, value); \ } \ var = (int) value; } while(0) /** Check an option argument for a double value. @param var The variable to store the result in. @param min The minimum allowable value. @param max The maximum allowable value. */ /* #define PARSE_DOUBLE(var, min, max) do {\ char *endptr; \ double value; \ errno = 0; \ \ value = strtod(optArg, &endptr); \ if (*endptr != 0) { \ fatal(_("Garbage after value for %.*s option\n"), OPTPRARG); \ } \ if (errno != 0 || value < min || value > max) { \ fatal(_("Value for %.*s option (%f) is out of range\n"), OPTPRARG, value); \ } \ var = value; } while(0) */ /** Check an option argument for a boolean value. @param var The variable to store the result in. */ #define PARSE_BOOLEAN(var) do {\ if (optArg == NULL || strcmp(optArg, "true") == 0 || strcmp(optArg, "t") == 0 || strcmp(optArg, "yes") == 0 || \ strcmp(optArg, "y") == 0 || strcmp(optArg, "1") == 0) \ (var) = 1; \ else if (strcmp(optArg, "false") == 0 || strcmp(optArg, "f") == 0 || strcmp(optArg, "no") == 0 || \ strcmp(optArg, "n") == 0 || strcmp(optArg, "0") == 0) \ (var) = 0; \ else \ fatal(_("Value for %.*s option (%s) is not a valid boolean value\n"), OPTPRARG, optArg); \ } while (0) typedef enum { SHORT, LONG } ArgType; enum { NO_ARG, OPTIONAL_ARG, REQUIRED_ARG }; #endif dwdiff-2.0.9/src/stream.c0000640000175000017500000000545212262313361015062 0ustar gertjangertjan/* Copyright (C) 2008-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #include #include "stream.h" /** Initialise the shared parts of a @a Stream structure. @param stream The @a Stream to initialise. */ static void initStreamDefault(Stream *stream) { (void) stream; #ifdef USE_UNICODE stream->bufferedChar = -1; stream->highSurrogate = 0; stream->lastClusterCategory = 0; stream->nextChar = -1; #endif } /** @a getChar for @a FILE based streams. */ static int getCharFile(Stream *stream) { return fileGetc(stream->data.file); } /** @a ungetChar for @a FILE based streams. */ static int ungetCharFile(Stream *stream, int c) { return fileUngetc(stream->data.file, c); } static StreamVtable fileVtable = { getCharFile, ungetCharFile }; /** Create a new @a File based stream. @param file The @a File to wrap. @return a new @a Stream wrapping the supplied @a File object. */ Stream *newFileStream(File *file) { Stream *retval; if (file == NULL) return NULL; retval = safe_malloc(sizeof(Stream)); retval->vtable = &fileVtable; retval->data.file = file; initStreamDefault(retval); return retval; } /** @a getChar for string based streams. */ static int getCharString(Stream *stream) { return stream->data.string.index >= stream->data.string.length ? EOF : (unsigned char) stream->data.string.string[stream->data.string.index++]; } /** @a ungetChar for string based streams. */ static int ungetCharString(Stream *stream, int c) { if (stream->data.string.index > 0) { ASSERT(stream->data.string.string[--stream->data.string.index] == c); return c; } else { return EOF; } } static StreamVtable stringVtable = { getCharString, ungetCharString }; /** Create a new string based stream. @param string The string to wrap. @return a new @a Stream wrapping the supplied string. */ Stream *newStringStream(const char *string, size_t length) { Stream *retval; retval = safe_malloc(sizeof(Stream)); retval->vtable = &stringVtable; retval->data.string.string = string; retval->data.string.index = 0; retval->data.string.length = length; initStreamDefault(retval); return retval; } bool isFileStream(const Stream *stream) { return stream->vtable == &fileVtable; } void sfclose(Stream *stream) { fileClose(stream->data.file); free(stream); } dwdiff-2.0.9/src/stream.h0000640000175000017500000000374712262313361015074 0ustar gertjangertjan/* Copyright (C) 2008-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #ifndef STREAM_H #define STREAM_H typedef struct Stream Stream; #include "definitions.h" #include "file.h" #include "util.h" #include "unicode.h" typedef struct StreamVtable { int (*getChar)(struct Stream *); int (*ungetChar)(struct Stream *, int c); } StreamVtable; struct Stream { StreamVtable *vtable; union { File *file; struct { const char *string; size_t length; size_t index; } string; } data; #ifdef USE_UNICODE /* Buffered character for grapheme cluster breaking. */ UChar32 bufferedChar; int32_t lastClusterCategory; /* High surrogate buffer for converting from UTF-16 to UTF-8. */ UChar32 highSurrogate; /* Character already read when checking for low surrogate. */ UChar32 nextChar; #endif }; Stream *newFileStream(File *file); Stream *newStringStream(const char *string, size_t length); bool isFileStream(const Stream *stream); #define sferror(s) (fileError((s)->data.file)) #define sfflush(s) (fileFlush((s)->data.file)) #define srewind(s) (fileRewind((s)->data.file, FILE_READ)) #define sfeof(s) (fileEof((s)->data.file)) // Note: this gets a single byte character, rather than a UTF-8 character #define sgetc(s) (fileGetc((s)->data.file)) #define sputc(s, c) (filePutc((s)->data.file, c)) #define swrite(s, buf, bytes) (fileWrite((s)->data.file, buf, bytes)) #define sgeterrno(s) (fileGetErrno((s)->data.file)) void sfclose(Stream *stream); #endif dwdiff-2.0.9/src/doDiff.c0000660000175000017500000005541612262313361014771 0ustar gertjangertjan/* Copyright (C) 2006-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #include #include #include #include #include "definitions.h" #include "option.h" #include "util.h" #include "stream.h" #include "buffer.h" #include "unicode.h" #include "diff/diff.h" #include "hashtable.h" static const char resetColor[] = "\033[0m"; static const char eraseLine[] = "\033[K"; static unsigned int oldLineNumber = 1, newLineNumber = 1; static bool lastWasLinefeed = true, lastWasDelete = false, lastWasCarriageReturn = false; /** Check whether the last-read character equals a certain value. This only works correctly if @p c is a character which will always be put into its own grapheme cluster, like control characters. */ static bool charDataEquals(int c) { #ifdef USE_UNICODE if (UTF8Mode) return charData.UTF8Char.original.data[0] == c; #endif return charData.singleChar == c; } static bool readNextChar(Stream *stream) { #ifdef USE_UNICODE if (UTF8Mode) return getBackspaceCluster(stream, &charData.UTF8Char.original); #endif charData.singleChar = stream->vtable->getChar(stream); return charData.singleChar != EOF; } static void addCharData(bool common) { #ifdef USE_UNICODE if (UTF8Mode) { size_t i; char encoded[4]; int bytes, j; UChar32 highSurrogate = 0; for (i = 0; i < charData.UTF8Char.original.used; i++) { bytes = filteredConvertToUTF8(charData.UTF8Char.original.data[i], encoded, &highSurrogate); for (j = 0; j < bytes; j++) addchar(encoded[j], common); } return; } #endif addchar(charData.singleChar, common); } /* Note: ADD should be 0, OLD_COMMON should be DEL + COMMON. */ typedef enum {ADD, DEL, COMMON, OLD_COMMON} Mode; /** If the last character printed was a newline, do some special handling. @param mode What kind of output is generated next. */ static void doPostLinefeed(Mode mode) { if (lastWasLinefeed) { if (mode & COMMON) mode = COMMON; lastWasLinefeed = false; if (option.lineNumbers) { if (option.colorMode && mode != COMMON) writeString(resetColor, sizeof(resetColor) - 1); printLineNumbers(oldLineNumber, newLineNumber); } if (option.needStartStop && mode != COMMON) { if (option.colorMode) { if (mode == ADD) writeString(option.addColor, option.addColorLen); else writeString(option.delColor, option.delColorLen); } if (option.repeatMarkers) { if (mode == ADD) writeString(option.addStart, option.addStartLen); else writeString(option.delStart, option.delStartLen); } } } } /** Handle a single whitespace character. @param print Skip or print. @param mode What type of output to generate. */ static void handleWhitespaceChar(bool print, Mode mode) { if (print) { doPostLinefeed(mode); /* Less mode also over-strikes whitespace */ if (option.less && !charDataEquals('\n') && !charDataEquals('\r') && mode == DEL) { addchar('_', mode & COMMON); addchar('\010', mode & COMMON); } else if (option.needStartStop && (mode & COMMON) != COMMON && (charDataEquals('\r') || (!lastWasCarriageReturn && charDataEquals('\n')))) { if (option.repeatMarkers) { if (mode == ADD) writeString(option.addStop, option.addStopLen); else writeString(option.delStop, option.delStopLen); } if (option.colorMode) /* Erase rest of line so it will use the correct background color */ writeString(eraseLine, sizeof(eraseLine) - 1); } addCharData(mode & COMMON); if (charDataEquals('\n')) lastWasLinefeed = true; lastWasCarriageReturn = charDataEquals('\r'); } if (charDataEquals('\n')) { switch (mode) { case COMMON: case ADD: newLineNumber++; break; case OLD_COMMON: case DEL: oldLineNumber++; break; default: PANIC(); } } } /** Skip or print the next bit of whitespace from @a file. @param file The file with whitespace. @param print Skip or print. @param mode What type of output to generate. */ static void handleNextWhitespace(InputFile *file, bool print, Mode mode) { if (file->whitespaceBufferUsed) { Stream *stream = newStringStream(file->whitespaceBuffer.data, file->whitespaceBuffer.used); while (readNextChar(stream)) handleWhitespaceChar(print, mode); free(stream); file->whitespaceBuffer.used = 0; file->whitespaceBufferUsed = false; } else { while (readNextChar(file->whitespace->stream)) { if (charDataEquals(0)) return; if (charDataEquals(1)) { if (!readNextChar(file->whitespace->stream)) fatal(_("Error reading back input\n")); } handleWhitespaceChar(print, mode); } } } /** Skip or print the next bit of whitespace from the new or old file, keeping the other file synchronized as far as line numbers are concerned. @param printNew Use the new file for printing instead of the old file. This is only for printing common text, and will skip over the old whitespace. */ static void handleSynchronizedNextWhitespace(bool printNew) { #ifdef USE_UNICODE static_assert(CRLF_GRAPHEME_CLUSTER_BREAK == 0); #endif bool BValid = true; unsigned int *lineNumberA, *lineNumberB; Stream *whitespaceA, *whitespaceB; Stream *oldFileWhitespaceStream = option.oldFile.whitespaceBufferUsed ? newStringStream(option.oldFile.whitespaceBuffer.data, option.oldFile.whitespaceBuffer.used) : option.oldFile.whitespace->stream; Stream *newFileWhitespaceStream = option.newFile.whitespaceBufferUsed ? newStringStream(option.newFile.whitespaceBuffer.data, option.newFile.whitespaceBuffer.used) : option.newFile.whitespace->stream; if (printNew) { whitespaceA = newFileWhitespaceStream; whitespaceB = oldFileWhitespaceStream; lineNumberA = &newLineNumber; lineNumberB = &oldLineNumber; } else { whitespaceA = oldFileWhitespaceStream; whitespaceB = newFileWhitespaceStream; lineNumberA = &oldLineNumber; lineNumberB = &newLineNumber; } while (readNextChar(whitespaceA)) { if (charDataEquals(0)) break; if (charDataEquals(1)) { if (!readNextChar(whitespaceA)) fatal(_("Error reading back input\n")); } if (option.printCommon) { doPostLinefeed(COMMON); /* Note that we don't have to check less mode here as we only print common whitespace. */ addCharData(true); if (charDataEquals('\n')) lastWasLinefeed = true; lastWasCarriageReturn = charDataEquals('\r'); } /* If a newline was found, see if the B file also has a newline. */ if (charDataEquals('\n')) { (*lineNumberA)++; /* Only process the B file if it has not reached then end of the token yet. */ if (BValid) { bool result; while ((result = readNextChar(whitespaceB))) { if (charDataEquals(0)) break; if (charDataEquals(1)) { if (!readNextChar(whitespaceB)) fatal(_("Error reading back input\n")); } if (charDataEquals('\n')) { (*lineNumberB)++; break; } } if (charDataEquals(0) || !result) BValid = false; } } } /* Process any remaining whitespace from the BS file. */ if (BValid) { while (readNextChar(whitespaceB)) { if (charDataEquals(0)) break; if (charDataEquals(1)) { if (!readNextChar(whitespaceB)) fatal(_("Error reading back input\n")); } if (charDataEquals('\n')) (*lineNumberB)++; } } if (option.oldFile.whitespaceBufferUsed) free(oldFileWhitespaceStream); if (option.newFile.whitespaceBufferUsed) free(newFileWhitespaceStream); } /** Wrapper for addchar which takes printer and less mode into account @param mode What type of output to generate. */ void addTokenChar(Mode mode) { /* Printer mode and less mode do special stuff, per character. */ if ((option.printer || option.less) && !charDataEquals('\n') && !charDataEquals('\r')) { if (mode == DEL) { addchar('_', mode & COMMON); addchar('\010', mode & COMMON); } else if (mode == ADD) { addCharData(mode & COMMON); addchar('\010', mode & COMMON); } } addCharData(mode & COMMON); } /** Skip or print the next token from @a file. @param file The file with tokens. @param print Skip or print. @param mode What type of output to generate. */ static void handleNextToken(TempFile *file, bool print, Mode mode) { bool empty = true; while (readNextChar(file->stream)) { if (charDataEquals(0)) { /* Check for option.paraDelim _should_ be superfluous, unless there is a bug elsewhere. */ if (option.paraDelim && print && empty && mode != COMMON) { Stream *stream = newStringStream(option.paraDelimMarker, option.paraDelimMarkerLength); while (readNextChar(stream)) { /* doPostLinefeed only does something if the last character was a line feed. However, the paragraph delimiter may contain line feeds as well, so call doPostLinefeed every time a character was printed. */ doPostLinefeed(mode); addCharData(mode); } free(stream); } return; } empty = false; /* Unescape the characters, if necessary. */ if (charDataEquals(1)) { if (!readNextChar(file->stream)) fatal(_("Error reading back input\n")); } if (print) { doPostLinefeed(mode); if (option.needStartStop && (mode & COMMON) != COMMON && (charDataEquals('\r') || (!lastWasCarriageReturn && charDataEquals('\n')))) { if (option.repeatMarkers) { if (mode == ADD) writeString(option.addStop, option.addStopLen); else writeString(option.delStop, option.delStopLen); } if (option.colorMode) /* Erase rest of line so it will use the correct background color */ writeString(eraseLine, sizeof(eraseLine) - 1); } addTokenChar(mode); if (charDataEquals('\n')) lastWasLinefeed = true; lastWasCarriageReturn = charDataEquals('\r'); } if (charDataEquals('\n')) { switch (mode) { /* When the newline is a word character rather than a whitespace character, we can safely count old and new lines together for common words. This will keep the line numbers in synch for these cases. Note that this also means that for OLD_COMMON the line counter is not incremented. */ case COMMON: oldLineNumber++; case ADD: newLineNumber++; break; case DEL: oldLineNumber++; break; case OLD_COMMON: break; default: PANIC(); } } } } /** Skip or print the next whitespace and tokens from @a file. @param file The @a InputFile to use. @param idx The last word to print or skip. @param print Skip or print. @param mode What type of output to generate. */ static void handleWord(InputFile *file, int idx, bool print, Mode mode) { while (file->lastPrinted < idx) { handleNextWhitespace(file, print, mode); handleNextToken(file->tokens, print, mode); file->lastPrinted++; } } /** Print (or skip if the user doesn't want to see) the common words. @param idx The last word to print (or skip). */ void printToCommonWord(int idx) { while (option.newFile.lastPrinted < idx) { handleSynchronizedNextWhitespace(!lastWasDelete); lastWasDelete = false; handleNextToken(option.newFile.tokens, option.printCommon, COMMON); handleNextToken(option.oldFile.tokens, false, OLD_COMMON); option.newFile.lastPrinted++; option.oldFile.lastPrinted++; } } /** Print (or skip if the user doesn't want to see) words from @a file. @param range The range of words to print (or skip). @param file The @a InputFile to print from. @param mode Either ADD or DEL, used for printing of start/stop markers. */ static void printWords(lin start, lin count, InputFile *file, bool print, Mode mode) { ASSERT(file->lastPrinted == start); /* Print the first word. As we need to add the markers AFTER the first bit of white space, we can't just use handleWord */ /* Print preceding whitespace. Should not be overstriken, so print as common */ handleNextWhitespace(file, print, mode + COMMON); /* Ensure that the the line numbers etc. get printed before the markers */ if (print) doPostLinefeed(COMMON); /* Print start marker */ if (print && option.needStartStop) { if (mode == ADD) { if (option.colorMode) writeString(option.addColor, option.addColorLen); writeString(option.addStart, option.addStartLen); } else { if (option.colorMode) writeString(option.delColor, option.delColorLen); writeString(option.delStart, option.delStartLen); } } /* Print first word */ handleNextToken(file->tokens, print, mode); file->lastPrinted++; /* Print following words */ handleWord(file, start + count, print, mode); if (print) doPostLinefeed(mode); /* Print stop marker */ if (print && option.needStartStop) { if (mode == ADD) writeString(option.addStop, option.addStopLen); else writeString(option.delStop, option.delStopLen); if (option.colorMode) writeString(resetColor, sizeof(resetColor) - 1); } } /** Print (or skip if the user doesn't want to see) deleted words. @param range The range of words to print (or skip). */ void printDeletedWords(struct change *script) { printWords(script->line0, script->deleted, &option.oldFile, option.printDeleted, DEL); } /** Print (or skip if the user doesn't want to see) inserted words. @param range The range of words to print (or skip). */ void printAddedWords(struct change *script) { printWords(script->line1, script->inserted, &option.newFile, option.printAdded, ADD); } /** Print (or skip if the user doesn't want to see) the last (common) words of both files. */ void printEnd(void) { if (!option.printCommon) return; while(!sfeof(option.newFile.tokens->stream)) { handleSynchronizedNextWhitespace(!lastWasDelete); lastWasDelete = false; handleNextToken(option.newFile.tokens, true, COMMON); handleNextToken(option.oldFile.tokens, false, OLD_COMMON); } } /** Load a piece of whitespace from file. @param file The @a InputFile to read from and store the result. @return a boolean indicating whether a newline was found within the whitespace. */ static bool loadNextWhitespace(InputFile *file) { bool newlineFound = false; file->whitespaceBufferUsed = true; file->whitespaceBuffer.used = 0; while (readNextChar(file->whitespace->stream)) { if (charDataEquals(0)) return newlineFound; if (charDataEquals(1)) { if (!readNextChar(file->whitespace->stream)) fatal(_("Error reading back input\n")); } if (charDataEquals('\n')) newlineFound = true; #ifdef USE_UNICODE if (UTF8Mode) { size_t i; char encoded[4]; int bytes, j; UChar32 highSurrogate = 0; for (i = 0; i < charData.UTF8Char.original.used; i++) { bytes = filteredConvertToUTF8(charData.UTF8Char.original.data[i], encoded, &highSurrogate); for (j = 0; j < bytes; j++) VECTOR_APPEND(file->whitespaceBuffer, encoded[j]); } } else #endif { VECTOR_APPEND(file->whitespaceBuffer, charData.singleChar); } } return newlineFound; } /** Create an array of integers to represent the aggregation of several tokens to a token with context. @param diffTokens The array of integers representing the words in the input. @param range An array of two integers representing the start and length in @p diffTokens (or @c NULL for complete array). @param context The number of context tokens to use (half on either side). @param file The ::file_data struct to fill. */ static ValueType *initializeContextDiffTokens(ValueTypeVector *diffTokens, lin *range, unsigned context, struct file_data *file) { ValueType *contextDiffTokens, *dataBase; size_t dataRange; size_t i, idx = 0; ValueType edgeArray[context + 1]; if (range == NULL) dataRange = diffTokens->used; else dataRange = range[1]; contextDiffTokens = safe_malloc((dataRange + context) * sizeof(ValueType)); dataBase = diffTokens->data; if (range != NULL) dataBase += range[0]; memcpy(edgeArray + 1, dataBase, context * sizeof(ValueType)); edgeArray[0] = -1; for (i = 1; i <= context; i++) contextDiffTokens[idx++] = getValue(edgeArray, (i + 1) * sizeof(ValueType)); for (i = 0; i < dataRange - context; i++) contextDiffTokens[idx++] = getValue(dataBase + i, (context + 1) * sizeof(ValueType)); memcpy(edgeArray, dataBase + dataRange - context, context * sizeof(ValueType)); edgeArray[context] = -1; for (i = 0; i < context; i++) contextDiffTokens[idx++] = getValue(edgeArray + i, (context - i + 1) * sizeof(ValueType)); ASSERT(idx == dataRange + context); file->equivs = contextDiffTokens; file->buffered_lines = dataRange + context; return contextDiffTokens; } /** Read the output of the diff command, and call the appropriate print routines. @param baseRange The range associated with the diff-token files, or NULL if the whole file. @param context The size of the context used. */ static void doDiffInternal(lin *baseRange, unsigned context) { enum { C_ADD, C_DEL, C_CHANGE } command; bool reverseDeleteAdd = false; struct change *script = NULL, *ptr; struct comparison cmp; if (context == 0) { if (baseRange == NULL) { cmp.file[0].equivs = option.oldFile.diffTokens.data; cmp.file[0].buffered_lines = option.oldFile.diffTokens.used; cmp.file[1].equivs = option.newFile.diffTokens.data; cmp.file[1].buffered_lines = option.newFile.diffTokens.used; } else { cmp.file[0].equivs = option.oldFile.diffTokens.data + baseRange[0]; cmp.file[0].buffered_lines = baseRange[1]; cmp.file[1].equivs = option.newFile.diffTokens.data + baseRange[2]; cmp.file[1].buffered_lines = baseRange[3]; } cmp.file[0].equiv_max = cmp.file[1].equiv_max = baseHashMax; script = diff_2_files(&cmp); } else { ValueType *oldDiffTokens, *newDiffTokens; /* Because we don't actually produce the empty tokens at the start and end of the file or range, we can't produce a set of context tokens when the context is larger than the range we try to cover. Therefore we trim the context to the smallest range. This may move some changes forward a little. */ if (baseRange != 0) { if ((lin) context > baseRange[1]) context = baseRange[1]; if ((lin) context > baseRange[3]) context = baseRange[3]; } else { if (context > option.oldFile.diffTokens.used) context = option.oldFile.diffTokens.used; if (context > option.newFile.diffTokens.used) context = option.newFile.diffTokens.used; } /* Make sure the context is a multiple of 2. */ context &= ~1; if (context == 0) { doDiffInternal(baseRange, context); return; } oldDiffTokens = initializeContextDiffTokens(&option.oldFile.diffTokens, baseRange, context, cmp.file); newDiffTokens = initializeContextDiffTokens(&option.newFile.diffTokens, baseRange == NULL ? NULL : baseRange + 2, context, cmp.file + 1); cmp.file[0].equiv_max = getHashMax(); script = diff_2_files(&cmp); free(oldDiffTokens); free(newDiffTokens); } if (option.needMarkers && baseRange == NULL) puts("======================================================================"); while (script != NULL) { if (baseRange != NULL) { script->line0 += baseRange[0]; script->line1 += baseRange[2]; } command = script->inserted == 0 ? C_DEL : (script->deleted == 0 ? C_ADD : C_CHANGE); differences = 1; if (option.matchContext && context != 0) { /* If the match-context option was specified, the diff output will generally be too long. Here we trim the ranges to the minimum range required to show the diff. However, the ranges are only too long when the difference is a change, not when it is an add or delete. */ if (command == C_CHANGE) { if (script->deleted <= (lin) context || script->inserted <= (lin) context) { ASSERT(script->deleted != script->inserted); if (script->deleted < script->inserted) { script->inserted -= script->deleted; command = C_ADD; } else if (script->inserted < script->deleted) { script->deleted -= script->inserted; command = C_DEL; } } else if (!option.aggregateChanges) { /* Result must be multiple of two, so divide by 4 first, and then multiply by 2. */ unsigned newContext = (context / 4) * 2; lin range[4] = { script->line0, script->deleted - context, script->line1, script->inserted - context }; doDiffInternal(range, newContext); goto nextDiff; } else { script->deleted -= context; script->inserted -= context; } } } /* Print common words. */ printToCommonWord(script->line1); /* Load whitespace for both files and analyse (same func). If old ws does not contain a newline, don't bother with loading the new because we need regular printing. Otherwise, determine if we need reverse printing or need to change the new ws into a single space */ if (command == C_CHANGE && !option.wdiffOutput) { if (loadNextWhitespace(&option.oldFile)) { if (loadNextWhitespace(&option.newFile)) { /* Because of the line feeds in both pieces of whitespace, we need to print the pieces synchronized to keep the line counters correct. We then empty the old whitespace buffer because that has already been printed, and we set the new whitespace buffer to a space such that the old and the new word are at least separated by a single space. */ handleSynchronizedNextWhitespace(!lastWasDelete); option.newFile.whitespaceBuffer.data[0] = ' '; option.newFile.whitespaceBuffer.used = 1; option.oldFile.whitespaceBuffer.used = 0; } else { reverseDeleteAdd = true; } } } if (reverseDeleteAdd) { /* This only happens for change commands, so we don't have to check the command anymore. */ printAddedWords(script); printDeletedWords(script); reverseDeleteAdd = false; } else { if (command != C_ADD) printDeletedWords(script); if (command != C_DEL) printAddedWords(script); } if (option.needMarkers) { puts("\n======================================================================"); lastWasLinefeed = true; } if (command == C_DEL && option.printDeleted && !option.wdiffOutput) lastWasDelete = true; /* Update statistics */ switch (command) { case C_ADD: statistics.added += script->inserted; break; case C_DEL: statistics.deleted += script->deleted; break; case C_CHANGE: statistics.newChanged += script->inserted; statistics.oldChanged += script->deleted; break; default: PANIC(); } nextDiff: ptr = script; script = script->link; free(ptr); } } /** Do the difference action. */ void doDiff(void) { VECTOR_INIT_ALLOCATED(option.oldFile.whitespaceBuffer); VECTOR_INIT_ALLOCATED(option.newFile.whitespaceBuffer); option.oldFile.lastPrinted = 0; option.newFile.lastPrinted = 0; doDiffInternal(NULL, option.matchContext); printEnd(); } dwdiff-2.0.9/src/dwdiff.c0000660000175000017500000004337612262313361015043 0ustar gertjangertjan/* Copyright (C) 2006-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #include #include #include #include #include #include #include "definitions.h" #include "option.h" #include "util.h" #include "stream.h" #include "unicode.h" #include "dispatch.h" #include "buffer.h" #include "hashtable.h" typedef enum { NONE, WHITESPACE, WORD } MatchState; int differences = 0; Statistics statistics; bool UTF8Mode; /** Contains the (partial) word currently being read in. We only need one copy of this for all files, because all files are read sequentially. */ static CharBuffer currentWord; CharBuffer whitespaceBuffer; bool tokenWritten; /** Contains the last read character. This is a global variable, because many routines use the same data and would require constant passing of either @a charData or a pointer to @a charData. Using a global-variable makes more sense in this case. */ CharData charData; static void writeEndOfToken(InputFile *file) { ValueType wordValue; sputc(file->tokens->stream, 0); wordValue = getValueFromContext(¤tWord); tokenWritten = true; VECTOR_APPEND(file->diffTokens, wordValue); /* Reset current word */ currentWord.used = 0; } /*===============================================================*/ /* Single character (SC) versions of the classification and storage routines. Descriptions can be found in the definition of the DispatchTable struct. */ bool getNextCharSC(Stream *file) { return (charData.singleChar = sgetc(file)) != EOF; } bool isWhitespaceSC(void) { return TEST_BIT(option.whitespace, charData.singleChar); } bool isDelimiterSC(void) { return TEST_BIT(option.delimiters, charData.singleChar); } void writeTokenCharSC(InputFile *file) { int diffChar = option.ignoreCase ? tolower(charData.singleChar) : charData.singleChar; VECTOR_APPEND(currentWord, diffChar); if (charData.singleChar == 0 || charData.singleChar == 1) filePutc(file->tokens->stream->data.file, 1); filePutc(file->tokens->stream->data.file, charData.singleChar); } void writeWhitespaceCharSC(InputFile *file) { /* Don't want to change interface (yet), so prevent warning. */ (void) file; if (charData.singleChar == 0 || charData.singleChar == 1) VECTOR_APPEND(whitespaceBuffer, 1); VECTOR_APPEND(whitespaceBuffer, charData.singleChar); } void writeWhitespaceDelimiterSC(InputFile *file) { sputc(file->whitespace->stream, 0); } #ifdef USE_UNICODE /*===============================================================*/ /* UTF-8 versions of the classification and storage routines. Descriptions can be found in the definition of the DispatchTable struct. */ bool getNextCharUTF8(Stream *file) { bool retval = getCluster(file, &charData.UTF8Char.original); if (retval) decomposeChar(&charData); return retval; } bool isWhitespaceUTF8(void) { if (option.whitespaceSet) return bsearch(&charData.UTF8Char.converted, option.whitespaceList.data, option.whitespaceList.used, sizeof(UTF16Buffer), (int (*)(const void *, const void *)) compareUTF16Buffer) != NULL; else return isUTF16Whitespace(&charData.UTF8Char.converted); return false; } bool isDelimiterUTF8(void) { return bsearch(&charData.UTF8Char.converted, option.delimiterList.data, option.delimiterList.used, sizeof(UTF16Buffer), (int (*)(const void *, const void *)) compareUTF16Buffer) != NULL || (option.punctuationMask && isUTF16Punct(&charData.UTF8Char.converted)); } void writeTokenCharUTF8(InputFile *file) { UChar32 highSurrogate = 0; UTF16Buffer *writeBuffer; size_t i; if (option.ignoreCase) { casefoldChar(&charData); writeBuffer = &charData.UTF8Char.casefolded; } else { writeBuffer = &charData.UTF8Char.converted; } for (i = 0; i < writeBuffer->used; i++) { char utf8char[4]; size_t bytes; if ((bytes = filteredConvertToUTF8(writeBuffer->data[i], utf8char, &highSurrogate)) == 0) continue; VECTOR_ALLOCATE(currentWord, bytes); memcpy(currentWord.data + currentWord.used, &utf8char, bytes); currentWord.used += bytes; } /* Write the "original" characters. Note that high and low surrogates and other invalid characters have been converted to REPLACEMENT CHARACTER. */ if (charData.UTF8Char.original.data[0] == 0 || charData.UTF8Char.original.data[0] == 1) { sputc(file->tokens->stream, 1); sputc(file->tokens->stream, charData.UTF8Char.original.data[0]); } else { for (i = 0; i < charData.UTF8Char.original.used; i++) putuc(file->tokens->stream, charData.UTF8Char.original.data[i]); } } void writeWhitespaceCharUTF8(InputFile *file) { UChar32 highSurrogate = 0; size_t i; /* Don't want to change interface (yet), so prevent warning. */ (void) file; /* 0 and 1 are always considered to be a grapheme cluster on their own, and are therefore always the only thing in the charData buffer if we encouter them. Furthermore, we use 0 as line end, and 1 as escape character in the temporary file. So we handle them separately here. */ if (charData.UTF8Char.original.data[0] == 0 || charData.UTF8Char.original.data[0] == 1) { VECTOR_APPEND(whitespaceBuffer, 1); VECTOR_APPEND(whitespaceBuffer, charData.UTF8Char.original.data[0]); return; } for (i = 0; i < charData.UTF8Char.original.used; i++) { char utf8char[4]; size_t bytes; if ((bytes = filteredConvertToUTF8(charData.UTF8Char.original.data[i], utf8char, &highSurrogate)) == 0) continue; VECTOR_ALLOCATE(whitespaceBuffer, bytes); memcpy(whitespaceBuffer.data + whitespaceBuffer.used, utf8char, bytes); whitespaceBuffer.used += bytes; } } void writeWhitespaceDelimiterUTF8(InputFile *file) { putuc(file->whitespace->stream, 0); } /*===============================================================*/ #endif DEF_TABLE(SC) ONLY_UNICODE(DEF_TABLE(UTF8)) DispatchTable *dispatch = &SCDispatch; /** Handle the end of a whitespace sequence. @param file The @a InputFile from which the whitespace came. If the paragraph delimiter mode is selected, this will check whether such a delimiter should be written and break up the whitespace if necessary. */ void handleWhitespaceEnd(InputFile *file) { if (option.paraDelim) { size_t i, firstNewline = 0; bool firstNewlineFound = false; for (i = 0; i < whitespaceBuffer.used; i++) { if (whitespaceBuffer.data[i] != '\n') continue; if (!firstNewlineFound) { firstNewlineFound = true; firstNewline = i; continue; } break; } /* The whitespace preceeding any text must be treated differently, as a newline there results in an empty line. This is different from other whitespace where two newlines are required for an empty line. */ if (firstNewlineFound && !tokenWritten) { /* Write everything upto but excluding the first newline */ swrite(file->whitespace->stream, whitespaceBuffer.data, firstNewline); writeWhitespaceDelimiter(file); swrite(file->whitespace->stream, whitespaceBuffer.data + firstNewline, whitespaceBuffer.used - firstNewline); writeWhitespaceDelimiter(file); writeEndOfToken(file); whitespaceBuffer.used = 0; return; } if (i != whitespaceBuffer.used) { /* Write everything upto and including the first newline */ swrite(file->whitespace->stream, whitespaceBuffer.data, firstNewline + 1); writeWhitespaceDelimiter(file); swrite(file->whitespace->stream, whitespaceBuffer.data + firstNewline + 1, whitespaceBuffer.used - (firstNewline + 1)); writeWhitespaceDelimiter(file); writeEndOfToken(file); whitespaceBuffer.used = 0; return; } /* Fall through to default case */ } swrite(file->whitespace->stream, whitespaceBuffer.data, whitespaceBuffer.used); writeWhitespaceDelimiter(file); whitespaceBuffer.used = 0; } /** Classify the character read in ::charData. */ int classifyChar(void) { /* Need to make sure we test delimiters first, because in UTF8Mode we can't simply remove any overlapping delimiters from the whitespace list. */ return isDelimiter() ? CAT_DELIMITER : (isWhitespace() ? CAT_WHITESPACE : CAT_OTHER); } /** Read a file and separate whitespace from the rest. @param file The @a InputFile to read. @return The number of "words" in @a file. The separated parts of @a file are put into temporary files. The temporary files' information is stored in the @a InputFile structure. For runs in which the newline character is not included in the whitespace list, the newline character is transliterated into the first character of the whitespace list. Just before writing the output the characters are again transliterated to restore the original text. */ static int readFile(InputFile *file) { MatchState state = NONE; int wordCount = 0; int category; if (file->name != NULL && (file->input = newFileStream(fileOpen(file->name, FILE_READ))) == NULL) fatal(_("Can't open file %s: %s\n"), file->name, strerror(errno)); if ((file->tokens = tempFile()) == NULL) fatal(_("Could not create temporary file: %s\n"), strerror(errno)); VECTOR_INIT(file->diffTokens); if ((file->whitespace = tempFile()) == NULL) fatal(_("Could not create temporary file: %s\n"), strerror(errno)); tokenWritten = false; while (getNextChar(file->input)) { category = classifyChar(); switch (state) { case NONE: if (category == CAT_WHITESPACE) { writeWhitespaceChar(file); state = WHITESPACE; break; } handleWhitespaceEnd(file); writeTokenChar(file); if (category == CAT_DELIMITER) { writeEndOfToken(file); state = WHITESPACE; } else { state = WORD; } break; case WORD: if (category == CAT_WHITESPACE) { /* Found the end of a "word". Go to whitespace mode. */ wordCount++; writeEndOfToken(file); writeWhitespaceChar(file); state = WHITESPACE; } else if (category == CAT_DELIMITER) { /* Found a delimiter. Finish the current word, add a zero length whitespace to the whitespace file, add the delimiter as a word, and go into whitespace mode. */ wordCount += 2; writeEndOfToken(file); writeTokenChar(file); writeEndOfToken(file); handleWhitespaceEnd(file); state = WHITESPACE; } else { writeTokenChar(file); } break; case WHITESPACE: if (category == CAT_WHITESPACE) { writeWhitespaceChar(file); } else if (category == CAT_DELIMITER) { /* Found a delimiter. Finish the current whitespace, and add the delimiter as a word. Then start new whitespace. */ wordCount++; writeTokenChar(file); writeEndOfToken(file); handleWhitespaceEnd(file); } else { /* Found the start of a word. Finish the whitespace, and go into word mode. */ handleWhitespaceEnd(file); writeTokenChar(file); state = WORD; } break; default: PANIC(); } } if (sferror(file->input)) fatal(_("Error reading file %s: %s\n"), file->name, strerror(sgeterrno(file->input))); /* Make sure there is whitespace to end the output with. This may be zero-length. */ handleWhitespaceEnd(file); /* Make sure the word is terminated, or otherwise diff will add extra output. */ if (state == WORD) { wordCount++; writeEndOfToken(file); } /* Close the input, and make sure the output is in the filesystem. Then rewind so we can start reading from the start. */ sfclose(file->input); sfflush(file->whitespace->stream); if (sferror(file->whitespace->stream)) fatal(_("Error writing to temporary file %s: %s\n"), file->name, strerror(sgeterrno(file->whitespace->stream))); srewind(file->whitespace->stream); sfflush(file->tokens->stream); if (sferror(file->tokens->stream)) fatal(_("Error writing to temporary file %s: %s\n"), file->name, strerror(sgeterrno(file->tokens->stream))); srewind(file->tokens->stream); return wordCount; } /** Read the input files and perform the diff. */ static void prepareAndExecuteDiff(void) { statistics.oldTotal = readFile(&option.oldFile); statistics.newTotal = readFile(&option.newFile); baseHashMax = getHashMax(); /* Whitespace buffer and currentWord won't be used after this. */ VECTOR_FREE(currentWord); VECTOR_FREE(whitespaceBuffer); doDiff(); } typedef enum { FIRST_HEADER, FIRST, OLD, NEW, COMMON, HEADER, LINE_COUNTS } DiffInputMode; /** Split the input, if it is the output from diff -u or similar. */ void splitDiffInput(void) { Stream *input; TempFile *oldFile, *newFile; DiffInputMode mode = FIRST_HEADER; if (option.oldFile.name == NULL) { input = option.oldFile.input; } else { if ((input = newFileStream(fileOpen(option.oldFile.name, FILE_READ))) == NULL) fatal(_("Can't open file %s: %s\n"), option.oldFile.name, strerror(errno)); } oldFile = tempFile(); newFile = tempFile(); while (getNextCharSC(input)) { switch (mode) { case FIRST_HEADER: putchar(charData.singleChar); mode = charData.singleChar != '@' ? HEADER : LINE_COUNTS; break; case FIRST: if (charData.singleChar == '+') { sputc(newFile->stream, ' '); mode = NEW; } else if (charData.singleChar == '-') { sputc(oldFile->stream, ' '); mode = OLD; } else if (charData.singleChar == ' ') { sputc(oldFile->stream, ' '); sputc(newFile->stream, ' '); mode = COMMON; } else { closeTempFile(oldFile); closeTempFile(newFile); option.oldFile.name = oldFile->name; option.newFile.name = newFile->name; prepareAndExecuteDiff(); resetTempFiles(); oldFile = tempFile(); newFile = tempFile(); putchar(charData.singleChar); mode = charData.singleChar == '@' ? LINE_COUNTS : HEADER; } break; case OLD: sputc(oldFile->stream, charData.singleChar); if (charData.singleChar == '\n') mode = FIRST; break; case NEW: sputc(newFile->stream, charData.singleChar); if (charData.singleChar == '\n') mode = FIRST; break; case COMMON: sputc(oldFile->stream, charData.singleChar); sputc(newFile->stream, charData.singleChar); if (charData.singleChar == '\n') mode = FIRST; break; case HEADER: putchar(charData.singleChar); if (charData.singleChar == '\n') mode = FIRST_HEADER; break; case LINE_COUNTS: putchar(charData.singleChar); if (charData.singleChar == '\n') mode = FIRST; break; default: PANIC(); } } closeTempFile(oldFile); closeTempFile(newFile); option.oldFile.name = oldFile->name; option.newFile.name = newFile->name; prepareAndExecuteDiff(); } /** Main. */ int main(int argc, char *argv[]) { #if defined(USE_GETTEXT) || defined(USE_UNICODE) setlocale(LC_ALL, ""); #endif #ifdef USE_GETTEXT bindtextdomain("dwdiff", LOCALEDIR); textdomain("dwdiff"); #endif #ifdef USE_UNICODE /* Check whether the input is UTF-8 encoded. */ #ifdef USE_NL_LANGINFO if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) UTF8Mode = true; #else { char *lc_ctype, *location; int i; if ((lc_ctype = setlocale(LC_CTYPE, NULL)) == NULL) goto end_utf8_check; lc_ctype = safe_strdup(lc_ctype); /* Use ASCII specific tolower function here, because it is not certain that using tolower with the user locale will give correct results. */ for (i = strlen(lc_ctype) - 1; i >= 0; i--) lc_ctype[i] = ASCIItolower(lc_ctype[i]); if ((location = strstr(lc_ctype, ".utf8")) != NULL) { if (location[5] == 0 || location[5] == '@') UTF8Mode = true; } else if ((location = strstr(lc_ctype, ".utf-8")) != NULL) { if (location[6] == 0 || location[6] == '@') UTF8Mode = true; } } end_utf8_check: #endif // USE_NL_LANGINFO #endif // USE_UNICODE #ifdef USE_UNICODE if (UTF8Mode) { VECTOR_INIT_ALLOCATED(charData.UTF8Char.original); VECTOR_INIT_ALLOCATED(charData.UTF8Char.converted); VECTOR_INIT_ALLOCATED(charData.UTF8Char.casefolded); dispatch = &UTF8Dispatch; } #endif VECTOR_INIT(currentWord); parseCmdLine(argc, argv); VECTOR_INIT(whitespaceBuffer); /* If we are reading the output from diff -u, then we need to first split the input into two separate files. After that, we can use our normal algorithm for determining the difference between two files. */ if (option.diffInput) splitDiffInput(); else prepareAndExecuteDiff(); fflush(option.output); if (option.statistics) { int common = statistics.oldTotal - statistics.deleted - statistics.oldChanged; if (statistics.oldTotal == 0) { fprintf(stderr, _("old: 0 words\n")); } else { fprintf(stderr, _("old: %d words %d %d%% common %d %d%% deleted %d %d%% changed\n"), statistics.oldTotal, common, (common * 100)/statistics.oldTotal, statistics.deleted, (statistics.deleted * 100) / statistics.oldTotal, statistics.oldChanged, (statistics.oldChanged * 100) / statistics.oldTotal); } common = statistics.newTotal - statistics.added - statistics.newChanged; if (statistics.newTotal == 0) { fprintf(stderr, _("new: 0 words\n")); } else { fprintf(stderr, _("new: %d words %d %d%% common %d %d%% inserted %d %d%% changed\n"), statistics.newTotal, common, (common * 100)/statistics.newTotal, statistics.added, (statistics.added * 100) / statistics.newTotal, statistics.newChanged, (statistics.newChanged * 100) / statistics.newTotal); } } #ifdef DEBUG_MEMORY free(option.oldFile.diffTokens.data); free(option.newFile.diffTokens.data); free(charData.UTF8Char.original.data); free(charData.UTF8Char.converted.data); free(charData.UTF8Char.casefolded.data); free(option.delColor); free(option.addColor); #endif return differences; } dwdiff-2.0.9/src/definitions.h0000640000175000017500000000566012262313361016110 0ustar gertjangertjan/* Copyright (C) 2006-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #ifndef DEFINITIONS_H #define DEFINITIONS_H #include #include #if defined(USE_GETTEXT) || defined(USE_UNICODE) # include #endif #if defined(USE_UNICODE) && defined(USE_NL_LANGINFO) # include #endif #ifdef USE_GETTEXT # include # define _(String) gettext(String) #else # define _(String) (String) #endif #define N_(String) String #ifdef USE_UNICODE #define ONLY_UNICODE(_x) _x #define SWITCH_UNICODE(a, b) a #else #define ONLY_UNICODE(_x) #define SWITCH_UNICODE(a, b) b #endif /*==== Misc definitions ====*/ /* Define a bool type if not already defined (C++ and C99 do)*/ #if !(defined(__cplusplus) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 19990601L)) /*@-incondefs@*/ typedef enum {false, true} bool; /*@+incondefs@*/ #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 19990601L #include #endif /*==== Configuration definitions ====*/ #ifndef NO_STRDUP #define strdupA strdup #endif #define VERSION_STRING "2.0.9" typedef struct CharData CharData; #include "vector.h" #include "stream.h" #include "tempfile.h" #include "unicode.h" #include "buffer.h" #include "diff/diff.h" typedef lin ValueType; #define VALUE_MAX LIN_MAX typedef VECTOR(ValueType, ValueTypeVector); typedef struct { const char *name; Stream *input; ValueTypeVector diffTokens; TempFile *tokens; TempFile *whitespace; int lastPrinted; CharBuffer whitespaceBuffer; bool whitespaceBufferUsed; } InputFile; typedef struct { int added, deleted, oldChanged, newChanged, oldTotal, newTotal; } Statistics; extern Statistics statistics; extern int differences; #define SET_BIT(x, b) do { (x)[(b)>>3] |= 1 << ((b) & 0x7); } while (0); #define RESET_BIT(x, b) do { (x)[(b)>>3] &= ~(1 << ((b) & 0x7)); } while (0); #define TEST_BIT(x, b) ((x)[(b)>>3] & (1 << ((b) & 0x7))) struct CharData { int singleChar; #ifdef USE_UNICODE struct { UTF16Buffer original; /* UTF-16 encoded original input after clean-up */ UTF16Buffer converted; /* UTF-16 encoded string for comparison purposes. */ UTF16Buffer casefolded; /* UTF-16 encoded string for comparison purposes, case folded version. */ } UTF8Char; #endif }; #ifdef USE_UNICODE extern bool UTF8Mode; #endif extern CharData charData; void doDiff(void); enum { CAT_OTHER, CAT_DELIMITER, CAT_WHITESPACE }; int classifyChar(void); #endif dwdiff-2.0.9/src/optionDescriptions.h0000640000175000017500000000764012262313361017474 0ustar gertjangertjan/* Copyright (C) 2010-2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #ifndef OPTIONDESCRIPTIONS_H #define OPTIONDESCRIPTIONS_H const char *descriptions[] = { /* Options showing info about the program */ N_("-h, --help Print this help message\n"), N_("-v, --version Print version and copyright information\n"), /* Options changing what is considered (non-)whitespace */ N_("-d , --delimiters= Specifiy delimiters\n"), N_("-P, --punctuation Use punctuation characters as delimiters\n"), N_("-W , --white-space= Specify whitespace characters\n"), #ifdef DWDIFF_COMPILE N_("--diff-input Read the input as the output from diff\n"), N_("-S[], --paragraph-separator[=] Show inserted or deleted blocks\n" " of empty lines, optionally overriding the marker\n"), /* Options changing what is output */ N_("-1, --no-deleted Do not print deleted words\n"), N_("-2, --no-inserted Do not print inserted words\n"), N_("-3, --no-common Do not print common words\n"), N_("-L[], --line-numbers[] Prepend line numbers\n"), N_("-C, --context= Show lines of context\n"), N_("-s, --statistics Print statistics when done\n"), #endif N_("--wdiff-output Produce wdiff compatible output\n"), /* Options changing the matching */ N_("-i, --ignore-case Ignore differences in case\n"), N_("-I, --ignore-formatting Ignore formatting differences\n"), /* TRANSLATORS: The context meant here are words preceeding and succeeding each word in the text. By using these extra context words when applying the diff program, frequently occuring words will be more likely to be matched to the correct corresponding word in the other text, thus giving a better result. */ N_("-m , --match-context= Use words of context for matching\n"), /* TRANSLATORS: The use of context words for matching is more expensive, because after the first pass of diff the changes reported need refining. However, if the user can live with multiple changes that are within (2 * match-context + 1) words from eachother being reported as a single change, they can use this option. */ N_("--aggregate-changes Allow close changes to aggregate\n"), N_("-A , --algorithm= Choose algorithm: best, normal, fast\n"), #ifdef DWDIFF_COMPILE /* Options changing the appearance of the output */ N_("-c[], --color[=] Color mode\n"), N_("-l, --less-mode As -p but also overstrike whitespace\n"), N_("-p, --printer Use overstriking and bold text\n"), N_("-w , --start-delete= String to mark begin of deleted text\n"), N_("-x , --stop-delete= String to mark end of deleted text\n"), N_("-y , --start-insert= String to mark begin of inserted text\n"), N_("-z , --stop-insert= String to mark end of inserted text\n"), N_("-R, --repeat-markers Repeat markers at newlines\n"), #endif #ifdef DWFILTER_COMPILE N_("-r, --reverse Format new as old\n"), #endif NULL}; #endif dwdiff-2.0.9/src/dispatch_autogen.sh0000750000175000017500000000212312262313361017272 0ustar gertjangertjan#!/bin/sh { echo "/* WARNING: THIS FILE IS AUTOGENERATED. DO NOT EDIT! */" echo "#ifndef DISPATCH_AUTOGEN_H" echo "#define DISPATCH_AUTOGEN_H" echo echo "/* Definition of the DEF_TABLE macro which allows easy creation of dispatch table */" echo "#define DEF_TABLE(suffix) DispatchTable suffix##Dispatch = { \\" grep '^[[:space:]]*FPTR' dispatch.h | sed 's/^[[:space:]]*FPTR[[:space:]][[:space:]]*\([^(]*\)(\*\([^)]*\)DT)\(([^)]*)\).*/ \2##suffix, \\/' | sed '$s/,//' echo "};" echo echo "/* Definitions to allow acces without prepending dispatch-> to all calls. */" grep '^[[:space:]]*FPTR' dispatch.h | sed 's/^[[:space:]]*FPTR[[:space:]][[:space:]]*\([^(]*\)(\*\([^)]*\)DT)\(([^)]*)\).*/#define \2 (dispatch->\2DT)/' echo echo "/* Definitions of all external functions. */" grep '^[[:space:]]*FPTR' dispatch.h | sed 's/^[[:space:]]*FPTR[[:space:]][[:space:]]*\([^(]*\)(\*\([^)]*\)DT)\(([^)]*)\).*/\1 \2SC\3;/' grep '^[[:space:]]*FPTR' dispatch.h | sed 's/^[[:space:]]*FPTR[[:space:]][[:space:]]*\([^(]*\)(\*\([^)]*\)DT)\(([^)]*)\).*/\1 \2UTF8\3;/' echo "#endif" } > dispatch_autogen.h dwdiff-2.0.9/src/vector.h0000640000175000017500000000347012262313361015074 0ustar gertjangertjan/* Copyright (C) 2011 G.P. Halkes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. 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, see . */ #ifndef VECTOR_H #define VECTOR_H #define VECTOR_INITIAL_SIZE 32 #define VECTOR(type, name) struct { type *data; size_t allocated, used; } name #define VECTOR_INIT(name) do { (name).data = NULL; (name).allocated = 0; (name).used = 0; } while (0) #define VECTOR_INIT_ALLOCATED(name) do { \ (name).allocated = VECTOR_INITIAL_SIZE; \ (name).data = safe_malloc((name).allocated * sizeof((name).data[0])); \ (name).used = 0; \ } while (0) #define VECTOR_APPEND(name, value) do { \ if ((name).allocated <= (name).used) { \ (name).allocated = (name).allocated == 0 ? VECTOR_INITIAL_SIZE : (name).allocated * 2; \ (name).data = safe_realloc((name).data, (name).allocated * sizeof((name).data[0])); \ } \ (name).data[(name).used++] = value; \ } while (0) #define VECTOR_ALLOCATE(name, value) do { \ if ((name).allocated > (name).used + (value)) break; \ if ((name).allocated == 0) (name).allocated = VECTOR_INITIAL_SIZE; \ while ((name).allocated <= (name).used + (value)) (name).allocated *= 2; \ (name).data = safe_realloc((name).data, (name).allocated * sizeof((name).data[0])); \ } while (0) #define VECTOR_FREE(name) do { free((name).data); (name).data = NULL; (name).used = 0; (name).allocated = 0; } while (0) #endif dwdiff-2.0.9/src/diff/0000770000175000017500000000000012262313361014326 5ustar gertjangertjandwdiff-2.0.9/src/diff/analyze.c0000640000175000017500000003314412262313361016141 0ustar gertjangertjan/* Analyze file differences for GNU DIFF. Copyright (C) 1988-1989, 1992-1995, 1998, 2001-2002, 2004, 2006-2007, 2009-2011 Free Software Foundation, Inc. This file is part of GNU DIFF. 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, version 3 of the License. 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, see . */ /* This file has been heavily stripped and slightly modified by G.P. Halkes, 2011. */ /* G.P. Halkes: Additions: */ #include "diff.h" static struct file_data files[2]; bool minimal; bool speed_large_files; /* /Additions. */ /* The core of the Diff algorithm. */ #define ELEMENT lin #define EQUAL(x,y) ((x) == (y)) #define OFFSET lin #define EXTRA_CONTEXT_FIELDS /* none */ #define NOTE_DELETE(c, xoff) (files[0].changed[files[0].realindexes[xoff]] = 1) #define NOTE_INSERT(c, yoff) (files[1].changed[files[1].realindexes[yoff]] = 1) #define USE_HEURISTIC 1 #define lint #include "diffseq.h" /* Discard lines from one file that have no matches in the other file. A line which is discarded will not be considered by the actual comparison algorithm; it will be as if that line were not in the file. The file's `realindexes' table maps virtual line numbers (which don't count the discarded lines) into real line numbers; this is how the actual comparison algorithm produces results that are comprehensible when the discarded lines are counted. When we discard a line, we also mark it as a deletion or insertion so that it will be printed in the output. */ static void discard_confusing_lines (struct file_data filevec[]) { int f; lin i; char *discarded[2]; lin *equiv_count[2]; lin *p; /* Allocate our results. */ p = xmalloc ((filevec[0].buffered_lines + filevec[1].buffered_lines) * (2 * sizeof *p)); for (f = 0; f < 2; f++) { filevec[f].undiscarded = p; p += filevec[f].buffered_lines; filevec[f].realindexes = p; p += filevec[f].buffered_lines; } /* Set up equiv_count[F][I] as the number of lines in file F that fall in equivalence class I. */ p = zalloc (filevec[0].equiv_max * (2 * sizeof *p)); equiv_count[0] = p; equiv_count[1] = p + filevec[0].equiv_max; for (i = 0; i < filevec[0].buffered_lines; ++i) ++equiv_count[0][filevec[0].equivs[i]]; for (i = 0; i < filevec[1].buffered_lines; ++i) ++equiv_count[1][filevec[1].equivs[i]]; /* Set up tables of which lines are going to be discarded. */ discarded[0] = zalloc (filevec[0].buffered_lines + filevec[1].buffered_lines); discarded[1] = discarded[0] + filevec[0].buffered_lines; /* Mark to be discarded each line that matches no line of the other file. If a line matches many lines, mark it as provisionally discardable. */ for (f = 0; f < 2; f++) { size_t end = filevec[f].buffered_lines; char *discards = discarded[f]; lin *counts = equiv_count[1 - f]; const lin *equivs = filevec[f].equivs; size_t many = 5; size_t tem = end / 64; /* Multiply MANY by approximate square root of number of lines. That is the threshold for provisionally discardable lines. */ while ((tem = tem >> 2) > 0) many *= 2; for (i = 0; i < (lin) end; i++) { size_t nmatch; if (equivs[i] == 0) continue; nmatch = counts[equivs[i]]; if (nmatch == 0) discards[i] = 1; else if (nmatch > many) discards[i] = 2; } } /* Don't really discard the provisional lines except when they occur in a run of discardables, with nonprovisionals at the beginning and end. */ for (f = 0; f < 2; f++) { lin end = filevec[f].buffered_lines; register char *discards = discarded[f]; for (i = 0; i < end; i++) { /* Cancel provisional discards not in middle of run of discards. */ if (discards[i] == 2) discards[i] = 0; else if (discards[i] != 0) { /* We have found a nonprovisional discard. */ register lin j; lin length; lin provisional = 0; /* Find end of this run of discardable lines. Count how many are provisionally discardable. */ for (j = i; j < end; j++) { if (discards[j] == 0) break; if (discards[j] == 2) ++provisional; } /* Cancel provisional discards at end, and shrink the run. */ while (j > i && discards[j - 1] == 2) discards[--j] = 0, --provisional; /* Now we have the length of a run of discardable lines whose first and last are not provisional. */ length = j - i; /* If 1/4 of the lines in the run are provisional, cancel discarding of all provisional lines in the run. */ if (provisional * 4 > length) { while (j > i) if (discards[--j] == 2) discards[j] = 0; } else { register lin consec; lin minimum = 1; lin tem = length >> 2; /* MINIMUM is approximate square root of LENGTH/4. A subrun of two or more provisionals can stand when LENGTH is at least 16. A subrun of 4 or more can stand when LENGTH >= 64. */ while (0 < (tem >>= 2)) minimum <<= 1; minimum++; /* Cancel any subrun of MINIMUM or more provisionals within the larger run. */ for (j = 0, consec = 0; j < length; j++) if (discards[i + j] != 2) consec = 0; else if (minimum == ++consec) /* Back up to start of subrun, to cancel it all. */ j -= consec; else if (minimum < consec) discards[i + j] = 0; /* Scan from beginning of run until we find 3 or more nonprovisionals in a row or until the first nonprovisional at least 8 lines in. Until that point, cancel any provisionals. */ for (j = 0, consec = 0; j < length; j++) { if (j >= 8 && discards[i + j] == 1) break; if (discards[i + j] == 2) consec = 0, discards[i + j] = 0; else if (discards[i + j] == 0) consec = 0; else consec++; if (consec == 3) break; } /* I advances to the last line of the run. */ i += length - 1; /* Same thing, from end. */ for (j = 0, consec = 0; j < length; j++) { if (j >= 8 && discards[i - j] == 1) break; if (discards[i - j] == 2) consec = 0, discards[i - j] = 0; else if (discards[i - j] == 0) consec = 0; else consec++; if (consec == 3) break; } } } } } /* Actually discard the lines. */ for (f = 0; f < 2; f++) { char *discards = discarded[f]; lin end = filevec[f].buffered_lines; lin j = 0; for (i = 0; i < end; ++i) if (minimal || discards[i] == 0) { filevec[f].undiscarded[j] = filevec[f].equivs[i]; filevec[f].realindexes[j++] = i; } else filevec[f].changed[i] = 1; filevec[f].nondiscarded_lines = j; } free (discarded[0]); free (equiv_count[0]); } /* Adjust inserts/deletes of identical lines to join changes as much as possible. We do something when a run of changed lines include a line at one end and have an excluded, identical line at the other. We are free to choose which identical line is included. `compareseq' usually chooses the one at the beginning, but usually it is cleaner to consider the following identical line to be the "change". */ static void shift_boundaries (struct file_data filevec[]) { int f; for (f = 0; f < 2; f++) { char *changed = filevec[f].changed; char *other_changed = filevec[1 - f].changed; lin const *equivs = filevec[f].equivs; lin i = 0; lin j = 0; lin i_end = filevec[f].buffered_lines; while (1) { lin runlength, start, corresponding; /* Scan forwards to find beginning of another run of changes. Also keep track of the corresponding point in the other file. */ while (i < i_end && !changed[i]) { while (other_changed[j++]) continue; i++; } if (i == i_end) break; start = i; /* Find the end of this run of changes. */ while (changed[++i]) continue; while (other_changed[j]) j++; do { /* Record the length of this run of changes, so that we can later determine whether the run has grown. */ runlength = i - start; /* Move the changed region back, so long as the previous unchanged line matches the last changed one. This merges with previous changed regions. */ while (start && equivs[start - 1] == equivs[i - 1]) { changed[--start] = 1; changed[--i] = 0; while (changed[start - 1]) start--; while (other_changed[--j]) continue; } /* Set CORRESPONDING to the end of the changed run, at the last point where it corresponds to a changed run in the other file. CORRESPONDING == I_END means no such point has been found. */ corresponding = other_changed[j - 1] ? i : i_end; /* Move the changed region forward, so long as the first changed line matches the following unchanged one. This merges with following changed regions. Do this second, so that if there are no merges, the changed region is moved forward as far as possible. */ while (i != i_end && equivs[start] == equivs[i]) { changed[start++] = 0; changed[i++] = 1; while (changed[i]) i++; while (other_changed[++j]) corresponding = i; } } while (runlength != i - start); /* If possible, move the fully-merged run of changes back to a corresponding run in the other file. */ while (corresponding < i) { changed[--start] = 1; changed[--i] = 0; while (other_changed[--j]) continue; } } } } /* Cons an additional entry onto the front of an edit script OLD. 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. */ static struct change * add_change (lin line0, lin line1, lin deleted, lin inserted, struct change *old) { struct change *new = xmalloc (sizeof *new); new->line0 = line0; new->line1 = line1; new->inserted = inserted; new->deleted = deleted; new->link = old; return new; } /* Scan the tables of which lines are inserted and deleted, producing an edit script in forward order. */ static struct change * build_script (struct file_data const filevec[]) { struct change *script = 0; char *changed0 = filevec[0].changed; char *changed1 = filevec[1].changed; lin i0 = filevec[0].buffered_lines, i1 = filevec[1].buffered_lines; /* Note that changedN[-1] does exist, and is 0. */ while (i0 >= 0 || i1 >= 0) { if (changed0[i0 - 1] | changed1[i1 - 1]) { lin line0 = i0, line1 = i1; /* Find # lines changed here in each file. */ while (changed0[i0 - 1]) --i0; while (changed1[i1 - 1]) --i1; /* Record this change. */ script = add_change (i0, i1, line0 - i0, line1 - i1, script); } /* We have reached lines in the two files that match each other. */ i0--, i1--; } return script; } /* Report the differences of two files. */ struct change *diff_2_files (struct comparison *cmp) { struct change *script; struct context ctxt; lin diags; lin too_expensive; /* Allocate vectors for the results of comparison: a flag for each line of each file, saying whether that line is an insertion or deletion. Allocate an extra element, always 0, at each end of each vector. */ size_t s = cmp->file[0].buffered_lines + cmp->file[1].buffered_lines + 4; char *flag_space = zalloc (s); cmp->file[0].changed = flag_space + 1; cmp->file[1].changed = flag_space + cmp->file[0].buffered_lines + 3; /* Some lines are obviously insertions or deletions because they don't match anything. Detect them now, and avoid even thinking about them in the main comparison algorithm. */ discard_confusing_lines (cmp->file); /* Now do the main comparison algorithm, considering just the undiscarded lines. */ ctxt.xvec = cmp->file[0].undiscarded; ctxt.yvec = cmp->file[1].undiscarded; diags = (cmp->file[0].nondiscarded_lines + cmp->file[1].nondiscarded_lines + 3); ctxt.fdiag = xmalloc (diags * (2 * sizeof *ctxt.fdiag)); ctxt.bdiag = ctxt.fdiag + diags; ctxt.fdiag += cmp->file[1].nondiscarded_lines + 1; ctxt.bdiag += cmp->file[1].nondiscarded_lines + 1; ctxt.heuristic = speed_large_files; /* Set TOO_EXPENSIVE to be approximate square root of input size, bounded below by 256. */ too_expensive = 1; for (; diags != 0; diags >>= 2) too_expensive <<= 1; ctxt.too_expensive = MAX (256, too_expensive); files[0] = cmp->file[0]; files[1] = cmp->file[1]; compareseq (0, cmp->file[0].nondiscarded_lines, 0, cmp->file[1].nondiscarded_lines, minimal, &ctxt); free (ctxt.fdiag - (cmp->file[1].nondiscarded_lines + 1)); /* Modify the results slightly to make them prettier in cases where that can validly be done. */ shift_boundaries (cmp->file); /* Get the results of comparison in the form of a chain of `struct change's -- an edit script. */ script = build_script (cmp->file); free (cmp->file[0].undiscarded); free (flag_space); return script; } dwdiff-2.0.9/src/diff/diffseq.h0000640000175000017500000004152512262313361016126 0ustar gertjangertjan/* Analyze differences between two vectors. Copyright (C) 1988-1989, 1992-1995, 2001-2004, 2006-2011 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; version 3 of the License. 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, see . */ /* Minor modifications done to prevent compiler warnings by G.P. Halkes, 2011 */ /* The basic idea is to consider two vectors as similar if, when transforming the first vector into the second vector through a sequence of edits (inserts and deletes of one element each), this sequence is short - or equivalently, if the ordered list of elements that are untouched by these edits is long. For a good introduction to the subject, read about the "Levenshtein distance" in Wikipedia. The basic algorithm is described in: "An O(ND) Difference Algorithm and its Variations", Eugene Myers, Algorithmica Vol. 1 No. 2, 1986, pp. 251-266; see especially section 4.2, which describes the variation used below. The basic algorithm was independently discovered as described in: "Algorithms for Approximate String Matching", E. Ukkonen, Information and Control Vol. 64, 1985, pp. 100-118. Unless the 'find_minimal' flag is set, this code uses the TOO_EXPENSIVE heuristic, by Paul Eggert, to limit the cost to O(N**1.5 log N) at the price of producing suboptimal output for large inputs with many differences. */ /* Before including this file, you need to define: ELEMENT The element type of the vectors being compared. EQUAL A two-argument macro that tests two elements for equality. OFFSET A signed integer type sufficient to hold the difference between two indices. Usually something like ssize_t. EXTRA_CONTEXT_FIELDS Declarations of fields for 'struct context'. NOTE_DELETE(ctxt, xoff) Record the removal of the object xvec[xoff]. NOTE_INSERT(ctxt, yoff) Record the insertion of the object yvec[yoff]. EARLY_ABORT(ctxt) (Optional) A boolean expression that triggers an early abort of the computation. USE_HEURISTIC (Optional) Define if you want to support the heuristic for large vectors. It is also possible to use this file with abstract arrays. In this case, xvec and yvec are not represented in memory. They only exist conceptually. In this case, the list of defines above is amended as follows: ELEMENT Undefined. EQUAL Undefined. XVECREF_YVECREF_EQUAL(ctxt, xoff, yoff) A three-argument macro: References xvec[xoff] and yvec[yoff] and tests these elements for equality. Before including this file, you also need to include: #include #include #include "minmax.h" */ /* Maximum value of type OFFSET. */ #define OFFSET_MAX \ ((((OFFSET)1 << (sizeof (OFFSET) * CHAR_BIT - 2)) - 1) * 2 + 1) /* Default to no early abort. */ #ifndef EARLY_ABORT # define EARLY_ABORT(ctxt) false #endif /* Use this to suppress gcc's `...may be used before initialized' warnings. Beware: The Code argument must not contain commas. */ #ifndef IF_LINT # ifdef lint # define IF_LINT(Code) Code # else # define IF_LINT(Code) /* empty */ # endif #endif /* As above, but when Code must contain one comma. */ #ifndef IF_LINT2 # ifdef lint # define IF_LINT2(Code1, Code2) Code1, Code2 # else # define IF_LINT2(Code1, Code2) /* empty */ # endif #endif /* * Context of comparison operation. */ struct context { #ifdef ELEMENT /* Vectors being compared. */ ELEMENT const *xvec; ELEMENT const *yvec; #endif /* Extra fields. */ EXTRA_CONTEXT_FIELDS /* Vector, indexed by diagonal, containing 1 + the X coordinate of the point furthest along the given diagonal in the forward search of the edit matrix. */ OFFSET *fdiag; /* Vector, indexed by diagonal, containing the X coordinate of the point furthest along the given diagonal in the backward search of the edit matrix. */ OFFSET *bdiag; #ifdef USE_HEURISTIC /* This corresponds to the diff -H flag. With this heuristic, for vectors with a constant small density of changes, the algorithm is linear in the vectors size. */ bool heuristic; #endif /* Edit scripts longer than this are too expensive to compute. */ OFFSET too_expensive; /* Snakes bigger than this are considered `big'. */ #define SNAKE_LIMIT 20 }; struct partition { /* Midpoints of this partition. */ OFFSET xmid; OFFSET ymid; /* True if low half will be analyzed minimally. */ bool lo_minimal; /* Likewise for high half. */ bool hi_minimal; }; /* Find the midpoint of the shortest edit script for a specified portion of the two vectors. Scan from the beginnings of the vectors, and simultaneously from the ends, doing a breadth-first search through the space of edit-sequence. When the two searches meet, we have found the midpoint of the shortest edit sequence. If FIND_MINIMAL is true, find the minimal edit script regardless of expense. Otherwise, if the search is too expensive, use heuristics to stop the search and report a suboptimal answer. Set PART->(xmid,ymid) to the midpoint (XMID,YMID). The diagonal number XMID - YMID equals the number of inserted elements minus the number of deleted elements (counting only elements before the midpoint). Set PART->lo_minimal to true iff the minimal edit script for the left half of the partition is known; similarly for PART->hi_minimal. This function assumes that the first elements of the specified portions of the two vectors do not match, and likewise that the last elements do not match. The caller must trim matching elements from the beginning and end of the portions it is going to specify. If we return the "wrong" partitions, the worst this can do is cause suboptimal diff output. It cannot cause incorrect diff output. */ static void diag (OFFSET xoff, OFFSET xlim, OFFSET yoff, OFFSET ylim, bool find_minimal, struct partition *part, struct context *ctxt) { OFFSET *const fd = ctxt->fdiag; /* Give the compiler a chance. */ OFFSET *const bd = ctxt->bdiag; /* Additional help for the compiler. */ #ifdef ELEMENT ELEMENT const *const xv = ctxt->xvec; /* Still more help for the compiler. */ ELEMENT const *const yv = ctxt->yvec; /* And more and more . . . */ #define XREF_YREF_EQUAL(x,y) EQUAL (xv[x], yv[y]) #else #define XREF_YREF_EQUAL(x,y) XVECREF_YVECREF_EQUAL (ctxt, x, y) #endif const OFFSET dmin = xoff - ylim; /* Minimum valid diagonal. */ const OFFSET dmax = xlim - yoff; /* Maximum valid diagonal. */ const OFFSET fmid = xoff - yoff; /* Center diagonal of top-down search. */ const OFFSET bmid = xlim - ylim; /* Center diagonal of bottom-up search. */ OFFSET fmin = fmid; OFFSET fmax = fmid; /* Limits of top-down search. */ OFFSET bmin = bmid; OFFSET bmax = bmid; /* Limits of bottom-up search. */ OFFSET c; /* Cost. */ bool odd = (fmid - bmid) & 1; /* True if southeast corner is on an odd diagonal with respect to the northwest. */ fd[fmid] = xoff; bd[bmid] = xlim; for (c = 1;; ++c) { OFFSET d; /* Active diagonal. */ bool big_snake = false; /* Extend the top-down search by an edit step in each diagonal. */ if (fmin > dmin) fd[--fmin - 1] = -1; else ++fmin; if (fmax < dmax) fd[++fmax + 1] = -1; else --fmax; for (d = fmax; d >= fmin; d -= 2) { OFFSET x; OFFSET y; OFFSET tlo = fd[d - 1]; OFFSET thi = fd[d + 1]; OFFSET x0 = tlo < thi ? thi : tlo + 1; for (x = x0, y = x0 - d; x < xlim && y < ylim && XREF_YREF_EQUAL (x, y); x++, y++) continue; if (x - x0 > SNAKE_LIMIT) big_snake = true; fd[d] = x; if (odd && bmin <= d && d <= bmax && bd[d] <= x) { part->xmid = x; part->ymid = y; part->lo_minimal = part->hi_minimal = true; return; } } /* Similarly extend the bottom-up search. */ if (bmin > dmin) bd[--bmin - 1] = OFFSET_MAX; else ++bmin; if (bmax < dmax) bd[++bmax + 1] = OFFSET_MAX; else --bmax; for (d = bmax; d >= bmin; d -= 2) { OFFSET x; OFFSET y; OFFSET tlo = bd[d - 1]; OFFSET thi = bd[d + 1]; OFFSET x0 = tlo < thi ? tlo : thi - 1; for (x = x0, y = x0 - d; xoff < x && yoff < y && XREF_YREF_EQUAL (x - 1, y - 1); x--, y--) continue; if (x0 - x > SNAKE_LIMIT) big_snake = true; bd[d] = x; if (!odd && fmin <= d && d <= fmax && x <= fd[d]) { part->xmid = x; part->ymid = y; part->lo_minimal = part->hi_minimal = true; return; } } if (find_minimal) continue; #ifdef USE_HEURISTIC /* Heuristic: check occasionally for a diagonal that has made lots of progress compared with the edit distance. If we have any such, find the one that has made the most progress and return it as if it had succeeded. With this heuristic, for vectors with a constant small density of changes, the algorithm is linear in the vector size. */ if (200 < c && big_snake && ctxt->heuristic) { { OFFSET best = 0; for (d = fmax; d >= fmin; d -= 2) { OFFSET dd = d - fmid; OFFSET x = fd[d]; OFFSET y = x - d; OFFSET v = (x - xoff) * 2 - dd; if (v > 12 * (c + (dd < 0 ? -dd : dd))) { if (v > best && xoff + SNAKE_LIMIT <= x && x < xlim && yoff + SNAKE_LIMIT <= y && y < ylim) { /* We have a good enough best diagonal; now insist that it end with a significant snake. */ int k; for (k = 1; XREF_YREF_EQUAL (x - k, y - k); k++) if (k == SNAKE_LIMIT) { best = v; part->xmid = x; part->ymid = y; break; } } } } if (best > 0) { part->lo_minimal = true; part->hi_minimal = false; return; } } { OFFSET best = 0; for (d = bmax; d >= bmin; d -= 2) { OFFSET dd = d - bmid; OFFSET x = bd[d]; OFFSET y = x - d; OFFSET v = (xlim - x) * 2 + dd; if (v > 12 * (c + (dd < 0 ? -dd : dd))) { if (v > best && xoff < x && x <= xlim - SNAKE_LIMIT && yoff < y && y <= ylim - SNAKE_LIMIT) { /* We have a good enough best diagonal; now insist that it end with a significant snake. */ int k; for (k = 0; XREF_YREF_EQUAL (x + k, y + k); k++) if (k == SNAKE_LIMIT - 1) { best = v; part->xmid = x; part->ymid = y; break; } } } } if (best > 0) { part->lo_minimal = false; part->hi_minimal = true; return; } } } #endif /* USE_HEURISTIC */ /* Heuristic: if we've gone well beyond the call of duty, give up and report halfway between our best results so far. */ if (c >= ctxt->too_expensive) { OFFSET fxybest; OFFSET fxbest IF_LINT (= 0); OFFSET bxybest; OFFSET bxbest IF_LINT (= 0); /* Find forward diagonal that maximizes X + Y. */ fxybest = -1; for (d = fmax; d >= fmin; d -= 2) { OFFSET x = MIN (fd[d], xlim); OFFSET y = x - d; if (ylim < y) { x = ylim + d; y = ylim; } if (fxybest < x + y) { fxybest = x + y; fxbest = x; } } /* Find backward diagonal that minimizes X + Y. */ bxybest = OFFSET_MAX; for (d = bmax; d >= bmin; d -= 2) { OFFSET x = MAX (xoff, bd[d]); OFFSET y = x - d; if (y < yoff) { x = yoff + d; y = yoff; } if (x + y < bxybest) { bxybest = x + y; bxbest = x; } } /* Use the better of the two diagonals. */ if ((xlim + ylim) - bxybest < fxybest - (xoff + yoff)) { part->xmid = fxbest; part->ymid = fxybest - fxbest; part->lo_minimal = true; part->hi_minimal = false; } else { part->xmid = bxbest; part->ymid = bxybest - bxbest; part->lo_minimal = false; part->hi_minimal = true; } return; } } #undef XREF_YREF_EQUAL } /* Compare in detail contiguous subsequences of the two vectors which are known, as a whole, to match each other. The subsequence of vector 0 is [XOFF, XLIM) and likewise for vector 1. Note that XLIM, YLIM are exclusive bounds. All indices into the vectors are origin-0. If FIND_MINIMAL, find a minimal difference no matter how expensive it is. The results are recorded by invoking NOTE_DELETE and NOTE_INSERT. Return false if terminated normally, or true if terminated through early abort. */ static bool compareseq (OFFSET xoff, OFFSET xlim, OFFSET yoff, OFFSET ylim, bool find_minimal, struct context *ctxt) { #ifdef ELEMENT ELEMENT const *xv = ctxt->xvec; /* Help the compiler. */ ELEMENT const *yv = ctxt->yvec; #define XREF_YREF_EQUAL(x,y) EQUAL (xv[x], yv[y]) #else #define XREF_YREF_EQUAL(x,y) XVECREF_YVECREF_EQUAL (ctxt, x, y) #endif /* Slide down the bottom initial diagonal. */ while (xoff < xlim && yoff < ylim && XREF_YREF_EQUAL (xoff, yoff)) { xoff++; yoff++; } /* Slide up the top initial diagonal. */ while (xoff < xlim && yoff < ylim && XREF_YREF_EQUAL (xlim - 1, ylim - 1)) { xlim--; ylim--; } /* Handle simple cases. */ if (xoff == xlim) while (yoff < ylim) { NOTE_INSERT (ctxt, yoff); if (EARLY_ABORT (ctxt)) return true; yoff++; } else if (yoff == ylim) while (xoff < xlim) { NOTE_DELETE (ctxt, xoff); if (EARLY_ABORT (ctxt)) return true; xoff++; } else { struct partition part IF_LINT2 (= { .xmid = 0, .ymid = 0 }); /* Find a point of correspondence in the middle of the vectors. */ diag (xoff, xlim, yoff, ylim, find_minimal, &part, ctxt); /* Use the partitions to split this problem into subproblems. */ if (compareseq (xoff, part.xmid, yoff, part.ymid, part.lo_minimal, ctxt)) return true; if (compareseq (part.xmid, xlim, part.ymid, ylim, part.hi_minimal, ctxt)) return true; } return false; #undef XREF_YREF_EQUAL } #undef ELEMENT #undef EQUAL #undef OFFSET #undef EXTRA_CONTEXT_FIELDS #undef NOTE_DELETE #undef NOTE_INSERT #undef EARLY_ABORT #undef USE_HEURISTIC #undef XVECREF_YVECREF_EQUAL #undef OFFSET_MAX dwdiff-2.0.9/src/diff/diff.h0000640000175000017500000001025312262313361015407 0ustar gertjangertjan/* Shared definitions for GNU DIFF Copyright (C) 1988-1989, 1991-1995, 1998, 2001-2002, 2004, 2009-2011 Free Software Foundation, Inc. This file is part of GNU DIFF. 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, version 3 of the License. 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, see . */ /* This file has been heavily stripped and slightly modified by G.P. Halkes, 2011. Definitions regarding the lin type and the MIN and MAX macros were taken from diffutils-3.2/src/system.h, which is distributed under the same license as this file. */ #ifndef DIFF_H #define DIFF_H #include #include #include #include #include "static_assert.h" typedef ptrdiff_t lin; #define LIN_MAX PTRDIFF_MAX static_assert((lin) -1 < 0); static_assert(sizeof (ptrdiff_t) <= sizeof (lin)); static_assert(sizeof (lin) <= sizeof (long int)); #include "definitions.h" #include "util.h" #define MIN(a, b) ((a) <= (b) ? (a) : (b)) #define MAX(a, b) ((a) >= (b) ? (a) : (b)) #define xmalloc safe_malloc #define zalloc safe_calloc /* Use heuristics for better speed with large files with a small density of changes. */ extern bool speed_large_files; /* Don't discard lines. This makes things slower (sometimes much slower) but will find a guaranteed minimal set of changes. */ extern bool minimal; /* 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 */ lin inserted; /* # lines of file 1 changed here. */ lin deleted; /* # lines of file 0 changed here. */ lin line0; /* Line number of 1st deleted line. */ lin line1; /* Line number of 1st inserted line. */ bool ignore; /* Flag used in context.c. */ }; /* Structures that describe the input files. */ /* Data on one input file being compared. */ struct file_data { /* 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. */ lin buffered_lines; /* 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. */ const lin *equivs; /* Vector, like the previous one except that the elements for discarded lines have been squeezed out. */ lin *undiscarded; /* Vector mapping virtual line numbers (not counting discarded lines) to real ones (counting those lines). Both are origin-0. */ lin *realindexes; /* Total number of nondiscarded lines. */ lin 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; /* 1 more than the maximum equivalence value used for this or its sibling file. */ lin equiv_max; }; /* Data on two input files being compared. */ struct comparison { struct file_data file[2]; struct comparison const *parent; /* parent, if a recursive comparison */ }; struct change *diff_2_files(struct comparison *cmp); #endif dwdiff-2.0.9/src/dispatch_autogen.h0000660000175000017500000000422112262313361017110 0ustar gertjangertjan/* WARNING: THIS FILE IS AUTOGENERATED. DO NOT EDIT! */ #ifndef DISPATCH_AUTOGEN_H #define DISPATCH_AUTOGEN_H /* Definition of the DEF_TABLE macro which allows easy creation of dispatch table */ #define DEF_TABLE(suffix) DispatchTable suffix##Dispatch = { \ getNextChar##suffix, \ isWhitespace##suffix, \ isDelimiter##suffix, \ writeTokenChar##suffix, \ writeWhitespaceChar##suffix, \ writeWhitespaceDelimiter##suffix, \ addCharacters##suffix, \ checkOverlap##suffix, \ setPunctuation##suffix, \ initOptions##suffix, \ postProcessOptions##suffix \ }; /* Definitions to allow acces without prepending dispatch-> to all calls. */ #define getNextChar (dispatch->getNextCharDT) #define isWhitespace (dispatch->isWhitespaceDT) #define isDelimiter (dispatch->isDelimiterDT) #define writeTokenChar (dispatch->writeTokenCharDT) #define writeWhitespaceChar (dispatch->writeWhitespaceCharDT) #define writeWhitespaceDelimiter (dispatch->writeWhitespaceDelimiterDT) #define addCharacters (dispatch->addCharactersDT) #define checkOverlap (dispatch->checkOverlapDT) #define setPunctuation (dispatch->setPunctuationDT) #define initOptions (dispatch->initOptionsDT) #define postProcessOptions (dispatch->postProcessOptionsDT) /* Definitions of all external functions. */ bool getNextCharSC(Stream *file); bool isWhitespaceSC(void); bool isDelimiterSC(void); void writeTokenCharSC(InputFile *file); void writeWhitespaceCharSC(InputFile *file); void writeWhitespaceDelimiterSC(InputFile *file); void addCharactersSC(const char *chars, size_t length, CHARLIST *list, char bitmap[BITMASK_SIZE]); void checkOverlapSC(void); void setPunctuationSC(void); void initOptionsSC(void); void postProcessOptionsSC(void); bool getNextCharUTF8(Stream *file); bool isWhitespaceUTF8(void); bool isDelimiterUTF8(void); void writeTokenCharUTF8(InputFile *file); void writeWhitespaceCharUTF8(InputFile *file); void writeWhitespaceDelimiterUTF8(InputFile *file); void addCharactersUTF8(const char *chars, size_t length, CHARLIST *list, char bitmap[BITMASK_SIZE]); void checkOverlapUTF8(void); void setPunctuationUTF8(void); void initOptionsUTF8(void); void postProcessOptionsUTF8(void); #endif dwdiff-2.0.9/Makefile.in0000660000175000017500000000765612262313361014713 0ustar gertjangertjan# Copyright (C) 2006-2010 G.P. Halkes # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . .POSIX: # C-compiler flags # If strdup is not provided by the library, add -DNO_STRDUP. CFLAGS=-O2 # Installation prefix prefix=/usr/local # Gettext configuration # GETTEXTFLAGS should contain -DUSE_GETTEXT to enable gettext translations # GETTEXTLIBS should contain all link flags to allow linking with gettext, if # it has been enabled. The GNU libc already contains the gettext library, so # there is no need to add any flags. Otherwise, -lintl is usually required, and # sometimes -liconv as well. GETTEXTFLAGS= GETTEXTLIBS= # Gettext related # LOCALEDIR: the directory where the locale dependant files should be installed. # LINGUAS: translations to be installed. Look in po directory for available # translations. LOCALEDIR=$(prefix)/share/locale LINGUAS= # Unicode/ICU config # If unicode support is to be enabled, the following flags should be set # ICUFLAGS: should at least be set to -DUSE_UNICODE. If the nl_langinfo # function is available it should also include -DUSE_NL_LANGINFO. Furthermore # it should include any C preprocessor flags that are required for building. # Usually this can be `icu-config --cppflags`. # ICULIBS: Flags to link to ICU, usually `icu-config --ldflags` ICUFLAGS= ICULIBS= # Install program to use (should provide -m and -d options) INSTALL=install # dwfilter on/off. To disable the compilation of dwfilter, comment the next # line or set DWFILTER to empty DWFILTER=yes # Miscelaneous install paths bindir=$(prefix)/bin docdir=$(prefix)/share/doc/dwdiff-2.0.9 mandir=$(prefix)/share/man all: dwdiff $(DWFILTER:yes=dwfilter) linguas .PHONY: all clean dist-clean install dwdiff-install lingua-install linguas CSOURCES_DWDIFF=src/buffer.c src/diff/analyze.c src/doDiff.c src/dwdiff.c src/file.c src/hashtable.c src/option.c src/stream.c src/tempfile.c src/unicode.c src/util.c OBJECTS_DWDIFF=$(CSOURCES_DWDIFF:.c=.o) CSOURCES_DWFILTER=src/dwfilter.c src/util.c OBJECTS_DWFILTER=$(CSOURCES_DWFILTER:.c=.o) clean: rm -rf src/*.o po/*.mo dist-clean: clean rm -rf dwdiff config.log Makefile .c.o: $(CC) $(CFLAGS) -Isrc $(GETTEXTFLAGS) -DLOCALEDIR=\"$(LOCALEDIR)\" $(ICUFLAGS) -c -o $@ $< dwdiff: $(OBJECTS_DWDIFF) $(CC) $(CFLAGS) $(LDFLAGS) -o dwdiff $(OBJECTS_DWDIFF) $(LDLIBS) $(ICULIBS) $(GETTEXTLIBS) dwfilter: $(OBJECTS_DWFILTER) $(CC) $(CFLAGS) $(LDFLAGS) -o dwfilter $(OBJECTS_DWFILTER) $(LDLIBS) $(ICULIBS) $(GETTEXTLIBS) linguas: cd po && $(MAKE) "LINGUAS=$(LINGUAS)" linguas # Macros to make DESTDIR support more readable _bindir=$(DESTDIR)$(bindir) _docdir=$(DESTDIR)$(docdir) _mandir=$(DESTDIR)$(mandir) install: dwdiff-install lingua-install dwdiff-install: dwdiff $(DWFILTER:yes=dwfilter) $(INSTALL) -d "$(_bindir)" $(INSTALL) dwdiff "$(_bindir)" if [ -n "$(DWFILTER)" ] ; then $(INSTALL) dwfilter "$(_bindir)" ; fi $(INSTALL) -d "$(_mandir)/man1" $(INSTALL) -m 644 "man/dwdiff.1" "$(_mandir)/man1" if [ -n "$(DWFILTER)" ] ; then $(INSTALL) -m 644 "man/dwfilter.1" "$(_mandir)/man1" ; fi $(INSTALL) -d "$(_docdir)" $(INSTALL) -m 644 README COPYING Changelog "$(_docdir)" # Work around empty LINGUAS list. Some shells don't like empty lists in for-loops lingua-install: if [ -n "$(LINGUAS)" ] ; then \ mandir="$(_mandir)" LINGUAS="$(LINGUAS)" INSTALL="$(INSTALL)" ./install-manpages $(DWFILTER) ;\ cd po && $(MAKE) "LOCALEDIR=$(DESTDIR)$(LOCALEDIR)" "INSTALL=$(INSTALL)" "LINGUAS=$(LINGUAS)" lingua-install ;\ fi dwdiff-2.0.9/configure0000750000175000017500000001636012262313361014542 0ustar gertjangertjan#!/bin/sh # Copyright (C) 2006-2007,2009 G.P. Halkes # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . # Set zsh to emulate sh (otherwise all kinds of eval's wont work) [ -n "${ZSH_VERSION}" ] && emulate sh #============================== # Functions #============================== error() { echo "$@" exit 1 } not() { if "$@" ; then false else true fi } check() { if not "$@" ; then error "Error executing $@. Aborting." fi } check_message() { printf "$@" echo "----------------------------------">> config.log echo "$@" >> config.log } check_message_result() { echo "$@" echo "$@" >> config.log } clean() { rm -rf "$@" >/dev/null 2>&1 } test_make() { echo "Running '${MAKE} -f .Makefile $@'" >> config.log "${MAKE}" -f .Makefile "$@" } test_compile() { clean .config.o check_message "Checking for $1... " shift if test_make "$@" .config.o >> config.log 2>&1 ; then check_message_result "yes" true else check_message_result "no" false fi } test_link() { clean .config check_message "Checking for $1... " shift if test_make "$@" .config >> config.log 2>&1 ; then check_message_result "yes" true else check_message_result "no" false fi } test_install() { clean .foo check_message "Checking for working install '$@'... " if test_make "INSTALL=$@" "install" >> config.log 2>&1 ; then check_message_result "yes" true else check_message_result "no" false fi } add_replace_settings() { for SETTING do NAME=`echo "${SETTING}" | sed 's/=.*/=/'` if grep "^${NAME}" Makefile.in > /dev/null ; then ESCAPED_SETTING=`echo "${SETTING}" | sed 's/\//\\\\\//g'` echo "s/^${NAME}.*/${ESCAPED_SETTING}/g" else echo "/^\\.POSIX:/a\\ ${SETTING}" fi done } replace_default() { if [ -n "$2" ] ; then ESCAPED=`echo "$2" | sed 's/\//\\\\\//g'` echo "s/^$1=.*/$1=${ESCAPED}/g" fi } insert() { [ -n "$2" ] && echo "/^\\.POSIX:/a\\ $1=$2" } create_makefile() { if [ -n "${TEST_INSTALL}" ] ; then [ -n "${INSTALL}" ] && TEST_INSTALL="${INSTALL}" unset INSTALL for _INSTALL in ${TEST_INSTALL} do # Don't test the sun install program, because it is dangerous. if [ "`uname`" = "SunOS" ] && [ "$_INSTALL" = "install" ] ; then continue fi test_install "${_INSTALL}" && INSTALL="${_INSTALL}" && break done if [ -z "${INSTALL}" ] ; then check_message_result "!! No working install program found. The install target will not work." fi fi echo "----------------------------------">> config.log check_message_result "Creating Makefile" { replace_default prefix "${PREFIX}" replace_default mandir "${MANDIR}" replace_default CFLAGS "${CFLAGS}" [ -n "${TEST_INSTALL}" ] && replace_default INSTALL "${INSTALL}" echo '/^\.POSIX:/a\ # Inserted settings' insert CC "${CC}" insert LDFLAGS "${LDFLAGS}" insert LDLIBS "${LDLIBS}" sed_lines "$@" } > .sedscript cat Makefile.in | sed -f .sedscript > Makefile clean .sedscript .config.c .config.o .config .Makefile .foo exit 0 } #============================== # Setup #============================== unset LINKRULE COMPILERULE USERRULES TEST_INSTALL . ./config.pkg for _switch in ${SWITCHES} do _name=`echo "${_switch}" | sed -e 's/^[+-]//' -e 's/-/_/g'` _pm=`echo "${_switch}" | sed 's/[^+-].*//'` if [ "${_pm}" = "+" ] ; then eval with_${_name}="yes" else eval with_${_name}="no" fi done _SWITCHES=`echo " ${SWITCHES}" | sed 's/ [+-]/ /g'` for PARAM do case "${PARAM}" in -h|--help) cat <] [=] --prefix= Prefix for installation [/usr/local] --mandir= Set manual page directory [prefix/share/man] Environment variables that tune build: MAKE Make program to use [make] CC C-compiler to use (default determined by make) CFLAGS C-compiler flags to use [-O2] LDFLAGS Linker flags to use (default determined by make) LDLIBS Extra libraries to link PREFIX See --prefix= EOF [ -n "${TEST_INSTALL}" ] && echo " INSTALL The install program to use" [ -n "${USER_HELP}" ] && { echo ; echo "Package specific settings" ; echo "${USER_HELP}" ; } cat < config.log echo "-- configure called with $0 $@" >> config.log [ -z "${LINKRULE}" ] && LINKRULE='$(CC) $(CFLAGS) $(LDFLAGS) -o .config .config.o $(LDLIBS) $(TESTLIBS)' [ -z "${COMPILERULE}" ] && COMPILERULE='$(CC) $(CFLAGS) $(TESTFLAGS) -c -o .config.o .config.c' unset SETTINGS [ -z "${LDLIBS}" ] || SETTINGS="LDLIBS=${LDLIBS} ${SETTINGS}" [ -z "${LDFLAGS}" ] || SETTINGS="LDFLAGS=${LDFLAGS} ${SETTINGS}" [ -z "${CFLAGS}" ] || SETTINGS="CFLAGS=${CFLAGS} ${SETTINGS}" [ -z "${CC}" ] || SETTINGS="CC=${CC} ${SETTINGS}" [ -n "${SETTINGS}" ] && check_message_result "Using settings ${SETTINGS}" clean .config .config.o .config.c config.log .Makefile .sedscript { echo ".POSIX:" [ -z "${CC}" ] || echo "CC=${CC}" [ -z "${LDFLAGS}" ] || echo "LDFLAGS=${LDFLAGS}" [ -z "${LDLIBS}" ] || echo "LDLIBS=${LDLIBS}" if [ -n "${CFLAGS}" ] ; then echo "CFLAGS=${CFLAGS}" else echo "CFLAGS=-O2" fi echo "${USERRULES}" if [ -n "${TEST_INSTALL}" ] ; then cat < .Makefile if [ -z "${MAKE}" ] ; then MAKE=make fi cat > .config.c < Language files were contributed by the authors named in them. dwdiff-2.0.9/man/0000770000175000017500000000000012262313361013402 5ustar gertjangertjandwdiff-2.0.9/man/nl/0000770000175000017500000000000012262313361014013 5ustar gertjangertjandwdiff-2.0.9/man/nl/dwdiff.10000660000175000017500000002255212262313361015347 0ustar gertjangertjan.\" Generated by manscript from nl/dwdiff.1.txt .TH "DWDIFF" "1" "2013/03/10" "Versie 2.0.9" "dwdiff afgebakend woord verschil programma" .hw /usr/share/doc/dwdiff-2.0.9 http://os.ghalkes.nl/dwdiff.html .SH NAAM dwdiff \- afgebakend woord verschil programma .SH OVERZICHT \fBdwdiff\fR [\fIOPTIES\fR] \fIOUD BESTAND\fR \fINIEUW BESTAND\fR .br \fBdwdiff\fR [\fIOPTIES\fR] \fB\-\-diff\-input\fR [\fIDIFF BESTAND\fR] .SH BESCHRIJVING \fBdwdiff\fR is een programma dat het verschil tussen twee bestanden bepaalt in woorden, in plaats van in regels. Het verschilt van \fBwdiff\fR in dat het de gebruiker toestaat om te specificeren wat witruimte is, en in dat het een optionele lijst van afbakeningskarakters kan gebruiken. Afbakeningskarakters worden behandeld als of ze afzonderlijke woorden zijn, zelfs als er geen witruimte is gelaten tussen het karakter en het voorafgaande of volgende woord. \fBdwdiff\fR is grotendeels commando-regel compatibel met \fBwdiff\fR. Slechts the \-\-autopager, \-\-terminal en \-\-avoid\-wraps opties worden niet ondersteund. .PP De standaard uitvoer van \fBdwdiff\fR is de nieuwe tekst, met daarin gemarkeerde verwijderde en ingevoegde stukken. Er zijn commando-regel opties beschikbaar om de uitvoer te veranderen. .SH OPTIES \fBdwdiff\fR accepteert de volgende opties (In alle karaktersequenties worden eerst de \\-escapecodes verwerkt. Alle standaard codes worden ondersteund, evenals de \\u en \\U Unicode escapecodes): .PP .TP \fB\-h\fR, \fB\-\-help\fR Toon een kort help bericht. .TP \fB\-v\fR, \fB\-\-version\fR Toon versie en auteursrecht informatie. .TP \fB\-d\fR \fIdelimiters\fR, \fB\-\-delimiters\fR=\fIdelimiters\fR Specificeer de lijst van afbakeningskarakters. .TP \fB\-P\fR, \fB\-\-punctuation\fR Gebruik alle leestekens als afbakeningskarakters. De set van leestekens is locale-afhankelijk. .TP \fB\-W\fR \fIwhitespace\fR, \fB\-\-whitespace\fR=\fIwhitespace\fR Specificeer de lijst van witruimte karakters. .TP \fB\-\-diff\-input\fR Interpreteer de invoer als de uitvoer van \fBdiff\fR in het Unified Diff formaat (meestal geproduceerd door \fBdiff \-u\fR). In dit geval is er maar één invoerbestand toegestaan. Deze optie maakt het mogelijk om de diff uitvoer te herformateren met \fBdwdiff\fR, en is bijvoorbeeld nuttig om de uitvoer van \fBsvn diff\fR na te bewerken. .TP \fB\-1\fR, \fB\-\-no\-deleted\fR Toon de woorden die verwijderd zijn uit het eerste bestand niet. .TP \fB\-2\fR, \fB\-\-no\-inserted\fR Toon de woorden die ingevoegd zijn in het tweede bestand niet. .TP \fB\-3\fR, \fB\-\-no\-common\fR Toon de woorden die in beide bestanden voorkomen niet. .TP \fB\-L\fR[\fIwidth\fR], \fB\-\-line\-numbers\fR[=\fIwidth\fR] Toon regelnummers aan het begin van iedere regel. De getoonde regelnummers zijn respectievelijk het regelnummer in het oude bestand en het regelnummer in het nieuwe bestand. Het optionele \fIwidth\fR argument is het minimum aantal posities per regelnummer. .TP \fB\-C\fR\fInum\fR, \fB\-\-context\fR=\fInum\fR Toon \fInum\fR regels context voor en na veranderingen. Voegt een regel met alleen \-\- toe tussen ieder blok veranderingen. .TP \fB\-s\fR, \fB\-\-statistics\fR Toon statistieken bij het afsluiten van het programma. De getoonde getallen zijn de aantallen woorden in beide bestanden, het aantal verwijderde woorden, het aantal ingevoegde woorden, en het aantal veranderde woorden. Het aantal veranderde woorden wordt geteld als het aantal woorden dat is verwijderd in het eerste bestand, en als het aantal vervangende woorden uit het tweede bestand. Al deze getallen worden ook uitgedrukt als een percentage van het totaal aantal woorden van het bestand waaruit ze afkomstig waren. .TP \fB\-i\fR, \fB\-\-ignore\-case\fR Negeer het verschil tussen hoofdletters en kleine letters bij het vergelijken van woorden. Deze optie is alleen beschikbaar als het onderliggende \fBdiff\fR programma deze optie biedt. .TP \fB\-I\fR, \fB\-\-ignore\-formatting\fR Negeer verschillen in opmaak van karakters. Deze optie schakelt naar het gebruik van de Unicode compatibiliteitsdecompositie van karakters in plaats van de canonieke decompositie. De compatibiliteitsdecompositie gooit opmaak informatie weg. Bijvoorbeeld, de ligatuur fi wordt vertaald naar twee losse letters voor de vergelijking. Echter, ook super- en subscript worden ook als gelijk gezien, evenals verschillende rotaties van hetzelfde karakter. .TP \fB\-c\fR[\fIspec\fR], \fB\-\-color\fR[=\fIspec\fR] Kleurenmodus. De optionele specificatie \fIspec\fR kan gebruikt worden om de gebruikte kleuren aan te passen. \fIspec\fR bestaat uit [\fIverwijderd\fR],[\fItoegevoegd\fR]. Als een van beide ontbreekt wordt zijn standaard kleur gebruikt (respectievelijk helder rood en helder groen). Beide delen van \fIspec\fR bestaan uit [\fIvoorgrond\fR][:\fIachtergrond\fR]. Een lijst met toelaatbare kleurnamen kan worden verkregen door het woord ``list'' te gebruiken op de plaats van \fIspec\fR. Alternatief kan een willekeurige escapecode om attributen te zetten worden gebruikt als kleur door er \fIe:\fR voor te zetten. .IP De standaard markeringen voor het begin en het einde van verwijderde en toegevoegde tekst worden onderdrukt, maar markeringen die op de commando-regel zijn gespecificeerd zullen worden afgedrukt. .TP \fB\-l\fR, \fB\-\-less\-mode\fR Als \-p, maar voer het doorhalen ook uit op verwijderde witruimte karakters. .TP \fB\-p\fR, \fB\-\-printer\fR Gebruik doorhalen met een liggend streepje en dik gedrukte tekst om veranderingen te benadrukken. Dit is geïmplementeerd door eerst een liggend streepje of een duplicaat van het karakter af te drukken, gevolgd door een backspace karakter, gevolgd door het karakter zelf. Op de meeste terminals heeft dit geen effect. Het \fBless\fR(1) programma zal echter doorgehaalde en dik gedrukte tekst laten zien. .IP De standaard markeringen voor het begin en het einde van verwijderde en toegevoegde tekst worden onderdrukt, maar markeringen die op de commando-regel zijn gespecificeerd zullen worden afgedrukt. .TP \fB\-m\fR[\fInum\fR], \fB\-\-match\-context\fR[=\fInum\fR] Gebruik \fInum\fR woorden context voor en na ieder woord voor vergelijking. Woorden in de oude tekst komen dan alleen overeen met woorden in de nieuwe tekst als de woorden er omheen eveneens overeenkomen. Dit verbeterd de uitvoer van \fBdwdiff\fR voor grote aanpassingen met veel voorkomende woorden. Echter, het gebruik van context vergroot de benodigde schijfruimte en vergt meer rekentijd. De standaard waarde voor deze optie is 1. Zet deze optie op 0 om het gedrag van versies voor 1.5 te gebruiken. .TP \fB\-\-aggregate\-changes\fR Laat nabije veranderingen versmelten tot één verandering, als context woorden gebruikt worden (zie \fB\-\-match\-context\fR). Deze optie verminderd de benodigde rekentijd door de veranderingen die het \fBdiff\fR programma rapporteerd niet nader te verfijnen. .TP \fB\-A\fR \fIalgorithm\fR, \fB\-\-algorithm\fR=\fIalgorithm\fR Kies het algoritme dat gebruikt wordt om de verschillen te bepalen. Er zijn drie mogelijke waarden voor \fIalgorithm\fR: \fIbest\fR, welke een minimaal aantal verschillen probeert te vinden, \fInormal\fR, welke enige optimaliteit uitruilt voor snelheid, en \fIfast\fR, welke er van uit gaat dat er slechts enkele wijzigingen zijn op een lange tekst. Standaard wordt het \fInormal\fR algoritme gebruikt. .TP \fB\-S\fR[\fImarker\fR], \fB\-\-paragraph\-separator\fR[=\fImarker\fR] Toon toegevoegde of verwijderde blokken van regels met alleen maar witruimte karakters. Een speciale markering wordt aan de uitvoer toegevoegd om deze blokken aan te geven. De standaard markering is \-\-. .TP \fB\-\-wdiff\-output\fR Maak uitvoer die overeenkomt met die van het \fBwdiff\fR programma. \fBdwdiff\fR maakt gebruik van een ander uitvoer algoritme, welke een meer intuïtieve uitvoer produceert. .TP \fB\-w\fR \fIstring\fR, \fB\-\-start\-delete\fR=\fIstring\fR Tekenreeks om het begin van verwijderde tekst te markeren. .TP \fB\-x\fR \fIstring\fR, \fB\-\-stop\-delete\fR=\fIstring\fR Tekenreeks om het einde van verwijderde tekst te markeren. .TP \fB\-y\fR \fIstring\fR, \fB\-\-start\-insert\fR=\fIstring\fR Tekenreeks om het begin van toegevoegde tekst te markeren. .TP \fB\-z\fR \fIstring\fR, \fB\-\-stop\-insert\fR=\fIstring\fR Tekenreeks om het einde van toegevoegde tekst te markeren. .TP \fB\-R\fR, \fB\-\-repeat\-markers\fR Herhaal de begin en eind markeringen aan het begin en het eind van een regel als de verandering over een regeleinde loopt. .PP Een enkel minteken (\-) als bestandsnaam kan worden gebruikt om aan te geven dat de tekst van de standaard invoer moet worden gelezen. Slechts één bestand kan van standaard invoer worden gelezen. Om te voorkomen dat \fBdwdiff\fR een bestandsnaam die begint met een minteken interpreteert als een optie kan een dubbel minteken (\-\-) opgegeven worden, waarna \fBdwdiff\fR alle volgende argumenten als bestandsnamen zal interpreteren. .SH BUGS Als u denkt een bug gevonden te hebben, controleer dan dat u de nieuwste versie van \fBdwdiff\fR gebruikt. Als u een bug wil rapporteren, voeg dan een minimaal voorbeeld dat het probleem demonstreert toe aan uw melding. .SH AUTEUR G.P. Halkes .SH COPYRIGHT Copyright \(co 2006\-2011 G.P. Halkes and others .br \fBdwdiff\fR is gelicenseerd onder de GNU General Public License version 3. .br Voor meer informatie over de licentie, zie het bestand COPYING in de documentatie map. Op Un*x systemen is dit meestal /usr/share/doc/dwdiff-2.0.9. .SH ZIE\ OOK \fBdwfilter\fR(1), \fBwdiff\fR(1), \fBdiff\fR(1) dwdiff-2.0.9/man/nl/dwfilter.10000660000175000017500000000546212262313361015725 0ustar gertjangertjan.\" Generated by manscript from nl/dwfilter.1.txt .TH "DWFILTER" "1" "2013/03/10" "Version 2.0.9" "reformat text for processing" .hw /usr/share/doc/dwdiff-2.0.9 http://os.ghalkes.nl/dwdiff.html .SH NAAM dwfilter \- herformateer tekst met dwdiff voor verdere verwerking .SH OVERZICHT \fBdwfilter\fR [\fIOPTIES\fR] \fIOUD BESTAND\fR \fINIEUW BESTAND\fR \fINABEWERKER\fR [\fINABEWERKER OPTIES\fR] .SH BESCHRIJVING \fBdwfilter\fR herformateert de tekst in het oude bestand volgens de inhoud van het nieuwe bestand (of vice versa) en geeft vervolgens het geherformateerde oude bestand en het nieuwe bestand aan een volgend filter. De belangrijkste functie is het mogelijk maken om programma's als \fBmeld\fR and \fBkdiff3\fR te gebruiken, zelfs als een bestand geherformateerd is na bewerking. Een verdere functie is het maken van kleine verschil bestanden zelfs als het nieuwe bestand geherformateerd is. .SH OPTIES .TP \fB\-r\fR, \fB\-\-reverse\fR Herformateer het nieuwe bestand volgens de inhoud van het oude bestand in plaats van de standaard operatie waarbij het oude bestand wordt geherformateerd volgens de inhoud van het nieuwe bestand. .PP \fBdwfilter\fR accepteerd de volgende \fBdwdiff\fR opties: .PP .RS \fB\-d\fR \fIdelimiters\fR, \fB\-\-delimiters\fR=\fIdelimiters\fR .br \fB\-P\fR, \fB\-\-punctuation\fR .br \fB\-W\fR \fIwhitespace\fR, \fB\-\-whitespace\fR=\fIwhitespace\fR .br \fB\-i\fR, \fB\-\-ignore\-case\fR .br \fB\-I\fR, \fB\-\-ignore\-formatting\fR .br \fB\-D\fR \fIoption\fR, \fB\-\-diff\-option\fR=\fIoption\fR .br \fB\-C\fR\fInum\fR, \fB\-\-context\fR=\fInum\fR .br \fB\-m\fR\fInum\fR, \fB\-\-match\-context\fR=\fInum\fR .br \fB\-\-aggregate\-changes\fR .br \fB\-\-wdiff\-output\fR .RE .PP Zie de \fBdwdiff\fR handleiding voor de betekenis. .PP Een enkel minteken (\-) als bestandsnaam kan worden gebruikt om aan te geven dat de tekst van de standaard invoer moet worden gelezen. Slechts één bestand kan van standaard invoer worden gelezen. Om te voorkomen dat \fBdwfilter\fR een bestandsnaam die begint met een minteken interpreteert als een optie kan een dubbel minteken (\-\-) opgegeven worden, waarna \fBdwfilter\fR alle volgende argumenten als bestandsnamen zal interpreteren. .SH BUGS Als u denkt een bug gevonden te hebben, controleer dan dat u de nieuwste versie van \fBdwdiff\fR gebruikt. Als u een bug wil rapporteren, voeg dan een minimaal voorbeeld dat het probleem demonstreert toe aan uw melding. .SH AUTEUR G.P. Halkes .SH COPYRIGHT Copyright \(co 2006\-2010 G.P. Halkes .br dwdiff is gelicenseerd onder de GNU General Public License version 3. .br Voor meer informatie over de licentie, zie het bestand COPYING in de documentatie map. Op Un*x systemen is dit meestal /usr/share/doc/dwdiff-2.0.9. .SH ZIE\ OOK \fBdwdiff\fR(1), \fBdiff\fR(1), \fBmeld\fR(1), \fBkdiff3\fR(1) dwdiff-2.0.9/man/dwdiff.10000660000175000017500000002066312262313361014737 0ustar gertjangertjan.\" Generated by manscript from dwdiff.1.txt .TH "DWDIFF" "1" "2013/03/10" "2.0.9" "Delimited word diff program" .hw /usr/share/doc/dwdiff-2.0.9 http://os.ghalkes.nl/dwdiff.html .SH NAME dwdiff \- a delimited word diff program .SH SYNOPSIS \fBdwdiff\fR [\fIOPTIONS\fR] \fIOLD FILE\fR \fINEW FILE\fR .br \fBdwdiff\fR [\fIOPTIONS\fR] \fB\-\-diff\-input\fR [\fIDIFF FILE\fR] .SH DESCRIPTION \fBdwdiff\fR is a \fBdiff\fR program that operates at the word level instead of the line level. It is different from \fBwdiff\fR in that it allows the user to specify what should be considered whitespace, and in that it takes an optional list of characters that should be considered delimiters. Delimiters are single characters that are treated as if they are words, even when there is no whitespace separating them from preceding words or delimiters. \fBdwdiff\fR is mostly command-line compatible with \fBwdiff\fR. Only the \-\-autopager, \-\-terminal and \-\-avoid\-wraps options are not supported. .PP The default output from \fBdwdiff\fR is the new text, with the deleted and inserted parts annotated with markers. Command line options are available to change both what is printed, and the markers. .SH OPTIONS \fBdwdiff\fR accepts the following options (Note that all strings will first be escape expanded. All standard \\-escapes are supported, as well as \\u and \\U Unicode escapes): .PP .TP \fB\-h\fR, \fB\-\-help\fR Display a short help message. .TP \fB\-v\fR, \fB\-\-version\fR Print version and copyright information. .TP \fB\-d\fR \fIdelimiters\fR, \fB\-\-delimiters\fR=\fIdelimiters\fR Specify a list of characters to be used as delimiters. .TP \fB\-P\fR, \fB\-\-punctuation\fR Use punctuation characters as delimiters. The exact set of punctuation characters depends on the current locale. .TP \fB\-W\fR \fIwhitespace\fR, \fB\-\-whitespace\fR=\fIwhitespace\fR Specify a list of characters to be used as whitespace. .TP \fB\-\-diff\-input\fR Interpret the input as the output from \fBdiff\fR in the Unified Diff format (usually produced by \fBdiff \-u\fR). In this case only one input file is allowed. This option allows reformating diff output with \fBdwdiff\fR, and is useful for example to post-process the output of \fBsvn diff\fR. .TP \fB\-1\fR, \fB\-\-no\-deleted\fR Suppress printing of words deleted from the first file. .TP \fB\-2\fR, \fB\-\-no\-inserted\fR Suppress printing of words inserted in the second file. .TP \fB\-3\fR, \fB\-\-no\-common\fR Suppress printing of words common to both files. .TP \fB\-L\fR[\fIwidth\fR], \fB\-\-line\-numbers\fR[=\fIwidth\fR] Show line numbers at the start of each line. The line numbers displayed are the line number in the old file and the line number in the new file respectively. The optional \fIwidth\fR argument is the minimum number of positions per line number. .TP \fB\-C\fR\fInum\fR, \fB\-\-context\fR=\fInum\fR Show \fInum\fR lines of context before and after each changes. A line with only \-\- is printed between blocks of changes. .TP \fB\-s\fR, \fB\-\-statistics\fR Print statistics when done. The numbers printed include the number of words from in both files, the number of deleted words, the number of inserted words, and the number of changed words. The number of changed words is counted as the number of words that are removed from the first file, and the number of words that replace them from the second file. All of these numbers are also expressed as a percentage of the total number of words in the file the words came from. .TP \fB\-i\fR, \fB\-\-ignore\-case\fR Ignore differences in case when comparing words. This option is only available if the diff program that is called provides it. .TP \fB\-I\fR, \fB\-\-ignore\-formatting\fR Ignore differences in formatting of characters. This option switches to using the Unicode compatibility decomposition instead of the canonical decomposition. The compatibility decomposition discards formatting information. For example, the ligature fi will be decomposed into two separate characters for the purposes of comparison. However, also super- and subscript will be regarded equal as well as different rotations of the same character. .TP \fB\-c\fR[\fIspec\fR], \fB\-\-color\fR[=\fIspec\fR] Color mode. The optional \fIspec\fR can be used to customize the colors. \fIspec\fR consists of [\fIdelete\fR],[\fIinsert\fR]. If either is omited it will be set to its default color (bright red or bright green respectively). Both parts of the \fIspec\fR consist of [\fIforeground\fR][:\fIbackground\fR]. To obtain a list of permissible color names, use the word ``list'' as \fIspec\fR. Alternatively, you can specify any escape sequence to set attributes as a color by prepending \fIe:\fR. .IP The standard markers for the begin and end of deleted and inserted text are suppressed, but any markers specified on the command line will still be printed. .TP \fB\-l\fR, \fB\-\-less\-mode\fR As \-p but also overstrike deleted whitespace. .TP \fB\-p\fR, \fB\-\-printer\fR Use overstriking with an underscore and bold text to emphasize changes. This is implemented by first printing the underscore or a duplicate of the character to be printed, followed by a backspace, followed by the character. On regular terminals you won't see any effect. The \fBless\fR(1) command will however show underlined and bold text. .IP The standard markers for the begin and end of deleted and inserted text are suppressed, but any markers specified on the command line will still be printed. .TP \fB\-m\fR\fInum\fR, \fB\-\-match\-context\fR=\fInum\fR Use \fInum\fR words of context before and after words for matching. Words in the old text will then only match words in the new text if words surrounding them are also equal. This improves the output for \fBdwdiff\fR for large changes with frequently occuring words. However, using context requires more disk space and more processing time. The default value is 1. Set this option to 0 to revert to the pre 1.5 behavior. .TP \fB\-\-aggregate\-changes\fR Allow multiple close changes to be treated as one change, if context words are used (see \fB\-\-match\-context\fR). This option reduces the processing time as the changes reported by the \fBdiff\fR program are not post-processed to give more precise results. .TP \fB\-A\fR \fIalgorithm\fR, \fB\-\-algorithm\fR=\fIalgorithm\fR Select the algorithm to be used for determining differences. There are three possible values for \fIalgorithm\fR: \fIbest\fR, which tries to find the minimal set of changes, \fInormal\fR, which trades some optimality for speed, and \fIfast\fR, which assumes that the input is large and contains few changes. By default the \fInormal\fR algorithm is used. .TP \fB\-S\fR[\fImarker\fR], \fB\-\-paragraph\-separator\fR[=\fImarker\fR] Show insertion or deletion of blocks of lines with only whitespace characters. A special marker is inserted into the output to indicate these blocks. The default marker is \-\-. .TP \fB\-\-wdiff\-output\fR Create \fBwdiff\fR compatible output. The \fBdwdiff\fR program uses a different output algorithm, which provides a more intuitive output. .TP \fB\-w\fR \fIstring\fR, \fB\-\-start\-delete\fR=\fIstring\fR Specify a string to mark begin of deleted text. .TP \fB\-x\fR \fIstring\fR, \fB\-\-stop\-delete\fR=\fIstring\fR Specify a string to mark end of deleted text. .TP \fB\-y\fR \fIstring\fR, \fB\-\-start\-insert\fR=\fIstring\fR Specify a string to mark begin of inserted text. .TP \fB\-z\fR \fIstring\fR, \fB\-\-stop\-insert\fR=\fIstring\fR Specify a string to mark end of inserted text. .TP \fB\-R\fR, \fB\-\-repeat\-markers\fR Repeat the begin and end markers at the start and end of line if a change crosses a newline. .PP A single dash (\-) as a file can be used to denote standard input. Only one file can be read from standard input. To stop \fBdwdiff\fR from interpreting file names that start with a dash as options, one can specify a double dash (\-\-) after which \fBdwdiff\fR will interpret any following arguments as files to read. .SH BUGS If you think you have found a bug, please check that you are using the latest version of \fBdwdiff\fR . When reporting bugs, please include a minimal example that demonstrates the problem. .SH AUTHOR G.P. Halkes .SH COPYRIGHT Copyright \(co 2006\-2011 G.P. Halkes and others .br \fBdwdiff\fR is licensed under the GNU General Public License version 3. .br For more details on the license, see the file COPYING in the documentation directory. On Un*x systems this is usually /usr/share/doc/dwdiff-2.0.9. .SH SEE\ ALSO \fBdwfilter\fR(1), \fBwdiff\fR(1), \fBdiff\fR(1) dwdiff-2.0.9/man/dwfilter.10000660000175000017500000000517012262313361015310 0ustar gertjangertjan.\" Generated by manscript from dwfilter.1.txt .TH "DWFILTER" "1" "2013/03/10" "Version 2.0.9" "reformat text for processing" .hw /usr/share/doc/dwdiff-2.0.9 http://os.ghalkes.nl/dwdiff.html .SH NAME dwfilter \- reformat text with dwdiff for further processing .SH SYNOPSIS \fBdwfilter\fR [\fIOPTIONS\fR] \fIOLD FILE\fR \fINEW FILE\fR \fIPOST PROCESSOR\fR [\fIPOST PROCESSOR OPTIONS\fR] .SH DESCRIPTION \fBdwfilter\fR reformats the text in the old file according to the contents of the new file (or vice versa) and subsequently passes the reformated old file and the new file through a secondary filter. It's main use is to allow visual diff programs such as \fBmeld\fR and \fBkdiff3\fR to be used, eventhough a text file has been reformated after editing. A further use is to allow the creation of small patches even when the new text has been reformated. \fBdwfilter\fR uses \fBdwdiff\fR for reformatting. .SH OPTIONS .TP \fB\-r\fR, \fB\-\-reverse\fR Reformat the new file based on the contents of the old file instead of the default where the old file is reformated based on the contents of the new file. .PP \fBdwfilter\fR accepts the following \fBdwdiff\fR options: .PP .RS \fB\-d\fR \fIdelimiters\fR, \fB\-\-delimiters\fR=\fIdelimiters\fR .br \fB\-P\fR, \fB\-\-punctuation\fR .br \fB\-W\fR \fIwhitespace\fR, \fB\-\-whitespace\fR=\fIwhitespace\fR .br \fB\-i\fR, \fB\-\-ignore\-case\fR .br \fB\-I\fR, \fB\-\-ignore\-formatting\fR .br \fB\-D\fR \fIoption\fR, \fB\-\-diff\-option\fR=\fIoption\fR .br \fB\-C\fR\fInum\fR, \fB\-\-context\fR=\fInum\fR .br \fB\-m\fR\fInum\fR, \fB\-\-match\-context\fR=\fInum\fR .br \fB\-\-aggregate\-changes\fR .br \fB\-\-wdiff\-output\fR .RE .PP See the \fBdwdiff\fR manual page for the meaning. .PP A single dash (\-) as a file can be used to denote standard input. Only one file can be read from standard input. To stop \fBdwfilter\fR from interpreting file names that start with a dash as options, one can specify a double dash (\-\-) after which \fBdwfilter\fR will interpret any following arguments as files to read. .SH BUGS If you think you have found a bug, please check that you are using the latest version of \fBdwdiff\fR . When reporting bugs, please include a minimal example that demonstrates the problem. .SH AUTHOR G.P. Halkes .SH COPYRIGHT Copyright \(co 2006\-2010 G.P. Halkes .br dwdiff is licensed under the GNU General Public License version 3. .br For more details on the license, see the file COPYING in the documentation directory. On Un*x systems this is usually /usr/share/doc/dwdiff-2.0.9. .SH SEE\ ALSO \fBdwdiff\fR(1), \fBdiff\fR(1), \fBmeld\fR(1), \fBkdiff3\fR(1) dwdiff-2.0.9/po/0000770000175000017500000000000012262313361013245 5ustar gertjangertjandwdiff-2.0.9/po/es.po0000660000175000017500000003546412262313361014231 0ustar gertjangertjan# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Jesús Franco , 2011. msgid "" msgstr "" "Project-Id-Version: dwdiff\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2011-01-31 20:18+0100\n" "PO-Revision-Date: 2011-06-05 06:12+0000\n" "Last-Translator: Jesús Franco \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: util.h:28 util.h:30 #, c-format msgid "Program-logic error at %s:%d\n" msgstr "Error lógico del programa en %s:%d\n" #: doDiff.c:209 doDiff.c:246 doDiff.c:274 doDiff.c:296 doDiff.c:350 #: doDiff.c:360 doDiff.c:533 msgid "Error reading back input\n" msgstr "Error al leer de nuevo la entrada\n\n" #: doDiff.c:584 doDiff.c:586 dwdiff.c:277 dwdiff.c:280 dwdiff.c:289 #: dwfilter.c:147 #, c-format msgid "Could not create temporary file: %s\n" msgstr "No se pudo crear el archivo temporal: %s\n" #: dwdiff.c:274 dwdiff.c:418 #, c-format msgid "Can't open file %s: %s\n" msgstr "No se puede abrir archivo %s: %s\n" #: dwdiff.c:359 #, c-format msgid "Error reading file %s: %s\n" msgstr "Error al leer el archivo %s: %s\n" #: dwdiff.c:378 dwdiff.c:383 dwdiff.c:388 #, c-format msgid "Error writing to temporary file %s: %s\n" msgstr "Error al escribir en archivo temporal %s: %s\n" #: dwdiff.c:562 #, c-format msgid "old: 0 words\n" msgstr "Precedente: 0 palabras\n" #: dwdiff.c:564 #, c-format msgid "old: %d words %d %d%% common %d %d%% deleted %d %d%% changed\n" msgstr "Precedente: %d words %d %d%% en común %d %d%% suprimidas %d %d%% cambiaron\n\n" #: dwdiff.c:571 #, c-format msgid "new: 0 words\n" msgstr "Nuevo: 0 palabras\n" #: dwdiff.c:573 #, c-format msgid "new: %d words %d %d%% common %d %d%% inserted %d %d%% changed\n" msgstr "Nuevo: %d palabras %d %d%% en común %d %d%% añadidas %d %d%% cambiaron\n" #: dwfilter.c:58 #, c-format msgid "" "Usage: dwfilter [OPTIONS] [POST " "PROCESSOR OPTIONS]\n" msgstr "Modo de uso: dwfilter [OPCIONES] [OPCIONES DE POSTPROCESO]\n" #. TRANSLATORS: #. - If the (C) symbol (that is the c in a circle) is not available, #. leave as it as is. (Unicode code point 0x00A9) #. - G.P. Halkes is name and should be left as is. #: dwfilter.c:70 option.c:535 msgid "" "Copyright (C) 2006-2011 G.P. Halkes\n" "Licensed under the GNU General Public License version 3\n" msgstr "Copyright (C) 2006-2011 G.P. Halkes\nLiberado bajo los términos de la Licencia Pública General de GNU Versión 3\n" #. TRANSLATORS: #. - If the (C) symbol (that is the c in a circle) is not available, #. leave as it as is. (Unicode code point 0x00A9) #. - G.P. Halkes is name and should be left as is. #: dwfilter.c:70 option.c:535 msgid "" "Copyright (C) 2006-2011 G.P. Halkes and others\n" "Licensed under the GNU General Public License version 3\n" msgstr "Copyright (C) 2006-2011 G.P. Halkes y otros\nLiberado bajo los términos de la Licencia Pública General de GNU Versión 3\n" #: dwfilter.c:108 option.c:693 option.c:702 #, c-format msgid "Option %.*s does not exist\n" msgstr "La opción %.*s no existe\n" #: dwfilter.c:125 option.c:723 msgid "Need two files to compare\n" msgstr "Se necesitan dos archivos para comparar\n" #: dwfilter.c:127 msgid "No post processor specified\n" msgstr "No se especificó un postprocesador\n" #: dwfilter.c:159 #, c-format msgid "Could not execute %s: %s\n" msgstr "No se puede ejecutar %s: %s\n" #: dwfilter.c:163 #, c-format msgid "Error waiting for child process to terminate: %s\n" msgstr "Ocurrió un error esperando que terminara el proceso hijo: %s\n" #: dwfilter.c:210 msgid "dwdiff returned an error\n" msgstr "dwdiff devolvió un error\n" #: optionMacros.h:168 #, c-format msgid "Option %.*s does not take an argument\n" msgstr "La opción %.*s no admite argumentos\n" #: optionMacros.h:174 #, c-format msgid "Option %.*s requires an argument\n" msgstr "La opción %.*s requiere un argumento\n" #: optionMacros.h:258 #, c-format msgid "Garbage after value for %.*s option\n" msgstr "Basura después de valor para la opción %.*s\n" #: optionMacros.h:261 #, c-format msgid "Value for %.*s option (%ld) is out of range\n" msgstr "El valor para la opción %.*s (%ld) está fuera de rango\n" #: optionMacros.h:295 #, c-format msgid "Value for %.*s option (%s) is not a valid boolean value\n" msgstr "El valor para la opción %.*s (%s) no es un valor booleano válido\n" #: optionDescriptions.h:20 msgid "-h, --help Print this help message\n" msgstr "-h, --help Muestra este mensaje de ayuda\n" #: optionDescriptions.h:21 msgid "" "-v, --version Print version and copyright " "information\n" msgstr "-v, --version Muestra versión e información de Copyright\n" #: optionDescriptions.h:24 msgid "-d , --delimiters= Specifiy delimiters\n" msgstr "-d , --delimiters= Especifica delimitadores\n" #: optionDescriptions.h:25 msgid "" "-P, --punctuation Use punctuation characters as " "delimiters\n" msgstr "-P, --punctuation Usa caracteres de puntuación como delimitadores\n" #: optionDescriptions.h:26 msgid "-W , --white-space= Specify whitespace characters\n" msgstr "-W , --white-space= Especifica caracteres a tomar como espacios en blanco\n" #: optionDescriptions.h:28 msgid "" "--diff-input Read the input as the output from " "diff\n" msgstr "--diff-input Lee tanto entrada como salida desde diff\n" #: optionDescriptions.h:29 msgid "" "-S[], --paragraph-separator[=] Show inserted or deleted blocks\n" " of empty lines, optionally overriding the marker\n" msgstr "-S[], --paragraph-separator[=] Muestra bloques añadidos o suprimidos\n de líneas vacías, opcionalmente ignorando el marcador\n" #: optionDescriptions.h:33 msgid "-1, --no-deleted Do not print deleted words\n" msgstr "-1, --no-deleted No mostrar palabras suprimidas\n" #: optionDescriptions.h:34 msgid "-2, --no-inserted Do not print inserted words\n" msgstr "-2, --no-inserted No mostrar palabras añadidas\n" #: optionDescriptions.h:35 msgid "-3, --no-common Do not print common words\n" msgstr "-3, --no-common No muestra palabras comunes\n" #: optionDescriptions.h:36 msgid "-L[], --line-numbers[] Prepend line numbers\n" msgstr "-L[], --line-numbers[] Muestra números de línea al inicio\n" #: optionDescriptions.h:37 msgid "-C, --context= Show lines of context\n" msgstr "-C, --context= Muestra líneas de contexto\n" #: optionDescriptions.h:38 msgid "-s, --statistics Print statistics when done\n" msgstr "-s, --statistics Muestra estadísticas al terminar\n" #: optionDescriptions.h:40 msgid "--wdiff-output Produce wdiff compatible output\n" msgstr "--wdiff-output Produce salida compatible con wdiff\n" #: optionDescriptions.h:43 msgid "-i, --ignore-case Ignore differences in case\n" msgstr "-i, --ignore-case Ignorar diferencias en mayúsculas/minúsculas\n" #: optionDescriptions.h:44 msgid "-I, --ignore-formatting Ignore formatting differences\n" msgstr "-I, --ignore-formatting Ignorar diferencias de presentación\n" #. TRANSLATORS: #. The context meant here are words preceeding and succeeding each word in #. the text. By using these extra context words when applying the diff #. program, #. frequently occuring words will be more likely to be matched to the #. correct corresponding word in the other text, thus giving a better result. #: optionDescriptions.h:51 msgid "" "-m , --match-context= Use words of context for " "matching\n" msgstr "-m , --match-context= Utiliza de palabras de contexto para cotejo\n" #. TRANSLATORS: #. The use of context words for matching is more expensive, because after the #. first pass of diff the changes reported need refining. However, if the user #. can live with multiple changes that are within (2 * match-context + 1) #. words #. from eachother being reported as a single change, they can use this option. #: optionDescriptions.h:57 msgid "" "--aggregate-changes Allow close changes to aggregate\n" msgstr "--aggregate-changes Permitir agregar cambios cercanos\n" #: optionDescriptions.h:61 msgid "-c[], --color[=] Color mode\n" msgstr "-c[], --color[=] Modo a color\n" #: optionDescriptions.h:62 msgid "" "-l, --less-mode As -p but also overstrike " "whitespace\n" msgstr "-l, --less-mode Como -p pero también tacha el espacio en blanco\n" #: optionDescriptions.h:63 msgid "-p, --printer Use overstriking and bold text\n" msgstr "-p, --printer Tacha y/o resalta el texto\n" #: optionDescriptions.h:64 msgid "" "-w , --start-delete= String to mark begin of deleted " "text\n" msgstr "-w , --start-delete= Cadena para marcar el inicio de texto suprimido\n" #: optionDescriptions.h:65 msgid "" "-x , --stop-delete= String to mark end of deleted text\n" msgstr "-x , --stop-delete= Cadena para mostrar al final de texto suprimido\n" #: optionDescriptions.h:66 msgid "" "-y , --start-insert= String to mark begin of inserted " "text\n" msgstr "-y , --start-insert= Cadena para mostrar al inicio de texto añadido\n" #: optionDescriptions.h:67 msgid "" "-z , --stop-insert= String to mark end of inserted text\n" msgstr "-z , --stop-insert= Cadena para marcar el final de texto añadido\n" #: optionDescriptions.h:68 msgid "-R, --repeat-markers Repeat markers at newlines\n" msgstr "-R, --repeat-markers Repite marcadores en retornos de carro\n" #: optionDescriptions.h:72 msgid "-r, --reverse Format new as old\n" msgstr "-r, --reverse Presentar texto nuevo como precedente\n" #: optionDescriptions.h:57 msgid "-A , --algorithm= Choose algorithm: best, normal, fast\n" msgstr "" #: option.c:38 msgid "Black" msgstr "Negro" #: option.c:39 msgid "Red" msgstr "Rojo" #: option.c:40 msgid "Green" msgstr "Verde" #: option.c:41 msgid "Brown" msgstr "Brown" #: option.c:42 msgid "Blue" msgstr "Azul" #: option.c:43 msgid "Magenta" msgstr "Magenta" #: option.c:44 msgid "Cyan" msgstr "Cian" #: option.c:45 msgid "Gray" msgstr "Gris" #: option.c:46 msgid "Dark gray" msgstr "Gris oscuro" #: option.c:47 msgid "Bright red" msgstr "Rojo brillante" #: option.c:48 msgid "Bright green" msgstr "Verde brillante" #: option.c:49 msgid "Yellow" msgstr "Amarillo" #: option.c:50 msgid "Bright blue" msgstr "Azul brillante" #: option.c:51 msgid "Bright magenta" msgstr "Magenta brillante" #: option.c:52 msgid "Bright cyan" msgstr "Cian brillante" #: option.c:53 msgid "White" msgstr "Blanco" #: option.c:88 #, c-format msgid "Single backslash at end of %s argument\n" msgstr "Barra invertida al final del argumento %s\n" #. TRANSLATORS: #. The %s argument is a long option name without preceding dashes. #: option.c:140 option.c:147 #, c-format msgid "Invalid hexadecimal escape sequence in %s argument\n" msgstr "Secuencia de escape hexadecimal no válida en el argumento %s\n" #. TRANSLATORS: #. The %c argument will be either 'u' or 'U'. The %s argument is a long #. option name without preceding dashes. #: option.c:181 option.c:187 #, c-format msgid "Too short \\%c escape in %s argument\n" msgstr "Escape \\%c demasiado corto en %s argumento\n" #. TRANSLATORS: #. The %s argument is a long option name without preceding dashes. #: option.c:198 #, c-format msgid "\\U escape out of range in %s argument\n" msgstr "escape \\U escape fuera de rango en %s argumento\n" #. TRANSLATORS: #. The %s argument is a long option name without preceding dashes. #: option.c:203 #, c-format msgid "\\%c escapes for surrogate codepoints are not allowed in %s argument\n" msgstr "" #: option.c:273 option.c:373 option.c:381 msgid "Whitespace and delimiter sets overlap\n" msgstr "Se solapan conjuntos de espacios en blanco y delimitadores\n" #: option.c:445 option.c:647 #, c-format msgid "Invalid color specification %s\n" msgstr "Color especificado no válido %s\n" #: option.c:458 option.c:470 #, c-format msgid "Invalid color %s\n" msgstr "Color inválido %s\n" #: option.c:445 #, c-format msgid "Invalid background color %s\n" msgstr "Color de fondo inválido %s\n" #: option.c:523 #, c-format msgid "Usage: dwdiff [OPTIONS] \n" msgstr "Modo de uso: dwdiff [OPCIONES] \n" #: option.c:564 #, c-format msgid "Option %.*s is only supported for UTF-8 mode\n" msgstr "La opción %.*s solo es soportada en modo UTF-8\n" #: option.c:567 #, c-format msgid "Support for option %.*s is not compiled into this version of dwdiff\n" msgstr "El soporte a la opción %.*s no se compiló para la presente versión de dwdiff\n" #: option.c:574 option.c:585 option.c:604 #, c-format msgid "Option %.*s is not supported\n" msgstr "La opción %.*s no tiene soporte\n" #: option.c:613 msgid "Can't read both files from standard input\n" msgstr "No se puede leer ambos archivos desde la entrada estándar\n" #: option.c:617 option.c:712 msgid "Too many files to compare\n" msgstr "Demasiados archivos a comparar\n" #. TRANSLATORS: #. "Name" and "Description" are table headings for the color name list. #. Make sure you keep the alignment of the headings over the text. #: option.c:636 msgid "Name Description\n" msgstr "Nombre Descripción\n" #: option.c:641 msgid "The colors black through gray are also usable as background color\n" msgstr "Los colores negro a gris pueden usarse también como color de fondo\n" #: option.c:689 #, c-format msgid "Error opening temporary output file: %s\n" msgstr "Error al abrir el archivo de salida temporal: %s\n" #: option.c:718 msgid "Only one input file accepted with --diff-input\n" msgstr "Sólo se admite archivo de entrada aceptó con --diff-input\n" #: util.c:38 msgid "Out of memory" msgstr "Fuera de memora" #: option.c:681 msgid "Invalid algorithm name\n" msgstr "" dwdiff-2.0.9/po/messages.pot0000660000175000017500000002432112262313361015603 0ustar gertjangertjan# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-01-05 18:31+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: util.h:26 util.h:28 #, c-format msgid "Program-logic error at %s:%d\n" msgstr "" #: doDiff.c:178 doDiff.c:226 doDiff.c:254 doDiff.c:276 doDiff.c:335 #: doDiff.c:506 msgid "Error reading back input\n" msgstr "" #: dwdiff.c:292 dwdiff.c:430 #, c-format msgid "Can't open file %s: %s\n" msgstr "" #: dwdiff.c:295 dwdiff.c:300 dwfilter.c:148 #, c-format msgid "Could not create temporary file: %s\n" msgstr "" #: dwdiff.c:367 #, c-format msgid "Error reading file %s: %s\n" msgstr "" #: dwdiff.c:386 dwdiff.c:391 #, c-format msgid "Error writing to temporary file %s: %s\n" msgstr "" #: dwdiff.c:580 #, c-format msgid "old: 0 words\n" msgstr "" #: dwdiff.c:582 #, c-format msgid "old: %d words %d %d%% common %d %d%% deleted %d %d%% changed\n" msgstr "" #: dwdiff.c:589 #, c-format msgid "new: 0 words\n" msgstr "" #: dwdiff.c:591 #, c-format msgid "new: %d words %d %d%% common %d %d%% inserted %d %d%% changed\n" msgstr "" #: dwfilter.c:59 #, c-format msgid "" "Usage: dwfilter [OPTIONS] [POST " "PROCESSOR OPTIONS]\n" msgstr "" #. TRANSLATORS: #. - If the (C) symbol (that is the c in a circle) is not available, #. leave as it as is. (Unicode code point 0x00A9) #. - G.P. Halkes is name and should be left as is. #: dwfilter.c:71 msgid "" "Copyright (C) 2006-2011 G.P. Halkes\n" "Licensed under the GNU General Public License version 3\n" msgstr "" #: dwfilter.c:109 option.c:662 option.c:685 #, c-format msgid "Option %.*s does not exist\n" msgstr "" #: dwfilter.c:126 option.c:706 msgid "Need two files to compare\n" msgstr "" #: dwfilter.c:128 msgid "No post processor specified\n" msgstr "" #: dwfilter.c:160 #, c-format msgid "Could not execute %s: %s\n" msgstr "" #: dwfilter.c:164 #, c-format msgid "Error waiting for child process to terminate: %s\n" msgstr "" #: dwfilter.c:209 msgid "dwdiff returned an error\n" msgstr "" #: optionMacros.h:168 #, c-format msgid "Option %.*s does not take an argument\n" msgstr "" #: optionMacros.h:174 #, c-format msgid "Option %.*s requires an argument\n" msgstr "" #: optionMacros.h:258 #, c-format msgid "Garbage after value for %.*s option\n" msgstr "" #: optionMacros.h:261 #, c-format msgid "Value for %.*s option (%ld) is out of range\n" msgstr "" #: optionMacros.h:295 #, c-format msgid "Value for %.*s option (%s) is not a valid boolean value\n" msgstr "" #: optionDescriptions.h:20 msgid "-h, --help Print this help message\n" msgstr "" #: optionDescriptions.h:21 msgid "" "-v, --version Print version and copyright " "information\n" msgstr "" #: optionDescriptions.h:24 msgid "-d , --delimiters= Specifiy delimiters\n" msgstr "" #: optionDescriptions.h:25 msgid "" "-P, --punctuation Use punctuation characters as " "delimiters\n" msgstr "" #: optionDescriptions.h:26 msgid "-W , --white-space= Specify whitespace characters\n" msgstr "" #: optionDescriptions.h:28 msgid "" "--diff-input Read the input as the output from " "diff\n" msgstr "" #: optionDescriptions.h:29 msgid "" "-S[], --paragraph-separator[=] Show inserted or deleted " "blocks\n" " of empty lines, optionally overriding the " "marker\n" msgstr "" #: optionDescriptions.h:33 msgid "-1, --no-deleted Do not print deleted words\n" msgstr "" #: optionDescriptions.h:34 msgid "-2, --no-inserted Do not print inserted words\n" msgstr "" #: optionDescriptions.h:35 msgid "-3, --no-common Do not print common words\n" msgstr "" #: optionDescriptions.h:36 msgid "-L[], --line-numbers[] Prepend line numbers\n" msgstr "" #: optionDescriptions.h:37 msgid "-C, --context= Show lines of context\n" msgstr "" #: optionDescriptions.h:38 msgid "-s, --statistics Print statistics when done\n" msgstr "" #: optionDescriptions.h:40 msgid "" "--wdiff-output Produce wdiff compatible output\n" msgstr "" #: optionDescriptions.h:43 msgid "-i, --ignore-case Ignore differences in case\n" msgstr "" #: optionDescriptions.h:44 msgid "-I, --ignore-formatting Ignore formatting differences\n" msgstr "" #. TRANSLATORS: #. The context meant here are words preceeding and succeeding each word in #. the text. By using these extra context words when applying the diff program, #. frequently occuring words will be more likely to be matched to the #. correct corresponding word in the other text, thus giving a better result. #: optionDescriptions.h:50 msgid "" "-m , --match-context= Use words of context for " "matching\n" msgstr "" #. TRANSLATORS: #. The use of context words for matching is more expensive, because after the #. first pass of diff the changes reported need refining. However, if the user #. can live with multiple changes that are within (2 * match-context + 1) words #. from eachother being reported as a single change, they can use this option. #: optionDescriptions.h:56 msgid "" "--aggregate-changes Allow close changes to aggregate\n" msgstr "" #: optionDescriptions.h:57 msgid "" "-A , --algorithm= Choose algorithm: best, normal, fast\n" msgstr "" #: optionDescriptions.h:61 msgid "-c[], --color[=] Color mode\n" msgstr "" #: optionDescriptions.h:62 msgid "" "-l, --less-mode As -p but also overstrike whitespace\n" msgstr "" #: optionDescriptions.h:63 msgid "-p, --printer Use overstriking and bold text\n" msgstr "" #: optionDescriptions.h:64 msgid "" "-w , --start-delete= String to mark begin of deleted text\n" msgstr "" #: optionDescriptions.h:65 msgid "" "-x , --stop-delete= String to mark end of deleted text\n" msgstr "" #: optionDescriptions.h:66 msgid "" "-y , --start-insert= String to mark begin of inserted " "text\n" msgstr "" #: optionDescriptions.h:67 msgid "" "-z , --stop-insert= String to mark end of inserted text\n" msgstr "" #: optionDescriptions.h:68 msgid "-R, --repeat-markers Repeat markers at newlines\n" msgstr "" #: optionDescriptions.h:72 msgid "-r, --reverse Format new as old\n" msgstr "" #: option.c:38 msgid "Black" msgstr "" #: option.c:39 msgid "Red" msgstr "" #: option.c:40 msgid "Green" msgstr "" #: option.c:41 msgid "Brown" msgstr "" #: option.c:42 msgid "Blue" msgstr "" #: option.c:43 msgid "Magenta" msgstr "" #: option.c:44 msgid "Cyan" msgstr "" #: option.c:45 msgid "Gray" msgstr "" #: option.c:46 msgid "Dark gray" msgstr "" #: option.c:47 msgid "Bright red" msgstr "" #: option.c:48 msgid "Bright green" msgstr "" #: option.c:49 msgid "Yellow" msgstr "" #: option.c:50 msgid "Bright blue" msgstr "" #: option.c:51 msgid "Bright magenta" msgstr "" #: option.c:52 msgid "Bright cyan" msgstr "" #: option.c:53 msgid "White" msgstr "" #: option.c:88 #, c-format msgid "Single backslash at end of %s argument\n" msgstr "" #. TRANSLATORS: #. The %s argument is a long option name without preceding dashes. #: option.c:140 option.c:147 #, c-format msgid "Invalid hexadecimal escape sequence in %s argument\n" msgstr "" #. TRANSLATORS: #. The %c argument will be either 'u' or 'U'. The %s argument is a long #. option name without preceding dashes. #: option.c:181 option.c:187 #, c-format msgid "Too short \\%c escape in %s argument\n" msgstr "" #. TRANSLATORS: #. The %s argument is a long option name without preceding dashes. #: option.c:198 #, c-format msgid "\\U escape out of range in %s argument\n" msgstr "" #. TRANSLATORS: #. The %s argument is a long option name without preceding dashes. #: option.c:203 #, c-format msgid "\\%c escapes for surrogate codepoints are not allowed in %s argument\n" msgstr "" #: option.c:273 option.c:362 option.c:370 msgid "Whitespace and delimiter sets overlap\n" msgstr "" #: option.c:420 option.c:616 #, c-format msgid "Invalid color specification %s\n" msgstr "" #: option.c:433 #, c-format msgid "Invalid color %s\n" msgstr "" #: option.c:445 #, c-format msgid "Invalid background color %s\n" msgstr "" #: option.c:495 #, c-format msgid "Usage: dwdiff [OPTIONS] \n" msgstr "" #. TRANSLATORS: #. - If the (C) symbol (that is the c in a circle) is not available, #. leave as it as is. (Unicode code point 0x00A9) #. - G.P. Halkes is name and should be left as is. #: option.c:507 msgid "" "Copyright (C) 2006-2011 G.P. Halkes and others\n" "Licensed under the GNU General Public License version 3\n" msgstr "" #: option.c:536 #, c-format msgid "Option %.*s is only supported for UTF-8 mode\n" msgstr "" #: option.c:539 #, c-format msgid "Support for option %.*s is not compiled into this version of dwdiff\n" msgstr "" #: option.c:546 option.c:557 option.c:576 #, c-format msgid "Option %.*s is not supported\n" msgstr "" #: option.c:585 msgid "Can't read both files from standard input\n" msgstr "" #: option.c:589 option.c:695 msgid "Too many files to compare\n" msgstr "" #. TRANSLATORS: #. "Name" and "Description" are table headings for the color name list. #. Make sure you keep the alignment of the headings over the text. #: option.c:605 msgid "Name Description\n" msgstr "" #: option.c:610 msgid "The colors black through gray are also usable as background color\n" msgstr "" #: option.c:658 #, c-format msgid "Error opening temporary output file: %s\n" msgstr "" #: option.c:681 msgid "Invalid algorithm name\n" msgstr "" #: option.c:701 msgid "Only one input file accepted with --diff-input\n" msgstr "" #: util.c:38 msgid "Out of memory" msgstr "" dwdiff-2.0.9/po/nl.po0000660000175000017500000003562612262313361014233 0ustar gertjangertjan# Copyright (C) 2011 G.P. Halkes # This file is distributed under the same license as the dwdiff package. # G.P. Halkes , 2011. # msgid "" msgstr "" "Project-Id-Version: dwdiff\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2011-01-31 20:18+0100\n" "PO-Revision-Date: 2011-01-31 19:40+0000\n" "Last-Translator: gphalkes \n" "Language-Team: Dutch <>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: nl\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: util.h:28 util.h:30 #, c-format msgid "Program-logic error at %s:%d\n" msgstr "Programmalogica fout op %s:%d\n" #: doDiff.c:209 doDiff.c:246 doDiff.c:274 doDiff.c:296 doDiff.c:350 #: doDiff.c:360 doDiff.c:533 msgid "Error reading back input\n" msgstr "Fout tijdens het teruglezen van de invoer\n" #, c-format msgid "Could not create temporary file: %s\n" msgstr "Kon tijdelijk bestand niet aanmaken: %s\n" #: doDiff.c:603 doDiff.c:615 doDiff.c:623 doDiff.c:631 doDiff.c:641 #: doDiff.c:647 doDiff.c:658 doDiff.c:663 doDiff.c:712 doDiff.c:717 #: doDiff.c:722 doDiff.c:727 doDiff.c:730 doDiff.c:851 #: dwdiff.c:274 dwdiff.c:418 #, c-format msgid "Can't open file %s: %s\n" msgstr "Kan bestand %s niet openen: %s\n" #: dwdiff.c:359 #, c-format msgid "Error reading file %s: %s\n" msgstr "Fout bij het lezen van bestand %s: %s\n" #: dwdiff.c:378 dwdiff.c:383 dwdiff.c:388 #, c-format msgid "Error writing to temporary file %s: %s\n" msgstr "Fout bij het schrijven naar tijdelijk bestand %s: %s\n" #: dwdiff.c:562 #, c-format msgid "old: 0 words\n" msgstr "oud: 0 woorden\n" #: dwdiff.c:564 #, c-format msgid "old: %d words %d %d%% common %d %d%% deleted %d %d%% changed\n" msgstr "oud: %d woorden %d %d%% gelijk %d %d%% verwijderd %d %d%% veranderd\n" #: dwdiff.c:571 #, c-format msgid "new: 0 words\n" msgstr "nieuw: 0 woorden\n" #: dwdiff.c:573 #, c-format msgid "new: %d words %d %d%% common %d %d%% inserted %d %d%% changed\n" msgstr "nieuw: %d woorden %d %d%% gelijk %d %d%% ingevoegd %d %d%% veranderd\n" #: dwfilter.c:58 #, c-format msgid "Usage: dwfilter [OPTIONS] [POST PROCESSOR OPTIONS]\n" msgstr "Gebruik: dwfilter [OPTIES] [NABEWERKER OPTIES]\n" #. TRANSLATORS: #. - If the (C) symbol (that is the c in a circle) is not available, #. leave as it as is. (Unicode code point 0x00A9) #. - G.P. Halkes is name and should be left as is. #: dwfilter.c:70 option.c:535 msgid "" "Copyright (C) 2006-2011 G.P. Halkes\n" "Licensed under the GNU General Public License version 3\n" msgstr "" "Copyright © 2006-2011 G.P. Halkes\n" "Gelicenseerd onder de GNU General Public License version 3\n" #. TRANSLATORS: #. - If the (C) symbol (that is the c in a circle) is not available, #. leave as it as is. (Unicode code point 0x00A9) #. - G.P. Halkes is name and should be left as is. #: option.c:519 msgid "" "Copyright (C) 2006-2011 G.P. Halkes and others\n" "Licensed under the GNU General Public License version 3\n" msgstr "" "Copyright © 2006-2011 G.P. Halkes en anderen\n" "Gelicenseerd onder de GNU General Public License version 3\n" #: dwfilter.c:108 option.c:693 option.c:702 #, c-format msgid "Option %.*s does not exist\n" msgstr "Optie %.*s bestaat niet\n" #: dwfilter.c:125 option.c:723 msgid "Need two files to compare\n" msgstr "Er zijn twee bestanden nodig om te vergelijken\n" #: dwfilter.c:127 msgid "No post processor specified\n" msgstr "Geen nabewerker gespecificeerd\n" #: dwfilter.c:159 #, c-format msgid "Could not execute %s: %s\n" msgstr "Kon %s niet uitvoeren: %s\n" #: dwfilter.c:163 #, c-format msgid "Error waiting for child process to terminate: %s\n" msgstr "Fout tijdens het wachten op afsluiten van kind proces: %s\n" #: dwfilter.c:210 msgid "dwdiff returned an error\n" msgstr "dwdiff gaf een fout terug\n" #: optionMacros.h:168 #, c-format msgid "Option %.*s does not take an argument\n" msgstr "Optie %.*s heeft geen argument\n" #: optionMacros.h:174 #, c-format msgid "Option %.*s requires an argument\n" msgstr "Optie %.*s heeft een argument nodig\n" #: optionMacros.h:258 #, c-format msgid "Garbage after value for %.*s option\n" msgstr "Rommel na waarde voor %.*s optie\n" #: optionMacros.h:261 #, c-format msgid "Value for %.*s option (%ld) is out of range\n" msgstr "Waarde voor %.*s option (%ld) is buiten toegestaan bereik\n" #: optionMacros.h:295 #, c-format msgid "Value for %.*s option (%s) is not a valid boolean value\n" msgstr "Waarde voor %.*s optie (%s) is geen geldige booleaanse waarde\n" #: optionDescriptions.h:20 msgid "-h, --help Print this help message\n" msgstr "-h, --help Toon dit help bericht\n" #: optionDescriptions.h:21 msgid "-v, --version Print version and copyright information\n" msgstr "-v, --version Toon versie en auteursrecht informatie\n" #: optionDescriptions.h:24 msgid "-d , --delimiters= Specifiy delimiters\n" msgstr "-d , --delimiters= Specificeer afbakeningskarakters\n" #: optionDescriptions.h:25 msgid "-P, --punctuation Use punctuation characters as delimiters\n" msgstr "-P, --punctuation Neem leestekens als afbakeningskarakters\n" #: optionDescriptions.h:26 msgid "-W , --white-space= Specify whitespace characters\n" msgstr "-W , --white-space= Specificeer witruimte karakters\n" #: optionDescriptions.h:28 msgid "--diff-input Read the input as the output from diff\n" msgstr "--diff-input Lees de invoer als de uitvoer van diff\n" #: optionDescriptions.h:29 msgid "" "-S[], --paragraph-separator[=] Show inserted or deleted blocks\n" " of empty lines, optionally overriding the marker\n" msgstr "" "-S[], --paragraph-separator[=] Toon toegevoegde of verwijderde\n" " blokken van lege regels, optioneel met niet standaard markering\n" #: optionDescriptions.h:33 msgid "-1, --no-deleted Do not print deleted words\n" msgstr "-1, --no-deleted Toon verwijderde woorden niet\n" #: optionDescriptions.h:34 msgid "-2, --no-inserted Do not print inserted words\n" msgstr "-2, --no-inserted Toon ingevoegde woorden niet\n" #: optionDescriptions.h:35 msgid "-3, --no-common Do not print common words\n" msgstr "-3, --no-common Toon gelijke woorden niet\n" #: optionDescriptions.h:36 msgid "-L[], --line-numbers[] Prepend line numbers\n" msgstr "-L[], --line-numbers[] Toon regelnummers\n" #: optionDescriptions.h:37 msgid "-C, --context= Show lines of context\n" msgstr "-C, --context= Toon regels context\n" #: optionDescriptions.h:38 msgid "-s, --statistics Print statistics when done\n" msgstr "-s, --statistics Toon statistieken\n" #: optionDescriptions.h:40 msgid "--wdiff-output Produce wdiff compatible output\n" msgstr "--wdiff-output Maak wdiff gelijkende uitvoer\n" #: optionDescriptions.h:43 msgid "-i, --ignore-case Ignore differences in case\n" msgstr "-i, --ignore-case Negeer hoofd/kleine letter verschil\n" #: optionDescriptions.h:44 msgid "-I, --ignore-formatting Ignore formatting differences\n" msgstr "-I, --ignore-formatting Negeer verschillen in opmaak\n" #. TRANSLATORS: #. The context meant here are words preceeding and succeeding each word in #. the text. By using these extra context words when applying the diff #. program, #. frequently occuring words will be more likely to be matched to the #. correct corresponding word in the other text, thus giving a better result. #: optionDescriptions.h:51 msgid "-m , --match-context= Use words of context for matching\n" msgstr "-m , --match-context= Gebruik woorden context voor vergelijking\n" #. TRANSLATORS: #. The use of context words for matching is more expensive, because after the #. first pass of diff the changes reported need refining. However, if the user #. can live with multiple changes that are within (2 * match-context + 1) #. words #. from eachother being reported as a single change, they can use this option. #: optionDescriptions.h:57 msgid "--aggregate-changes Allow close changes to aggregate\n" msgstr "--aggregate-changes Laat nabije veranderingen versmelten\n" #: optionDescriptions.h:61 msgid "-c[], --color[=] Color mode\n" msgstr "-c[], --color[=] Kleurenmodus\n" #: optionDescriptions.h:62 msgid "-l, --less-mode As -p but also overstrike whitespace\n" msgstr "-l, --less-mode Als -p met doorhalen van witruimte\n" #: optionDescriptions.h:63 msgid "-p, --printer Use overstriking and bold text\n" msgstr "-p, --printer Gebruik doorhalen en dikgedrukte tekst\n" #: optionDescriptions.h:64 msgid "-w , --start-delete= String to mark begin of deleted text\n" msgstr "" "-w , --start-delete= Tekenreeks om het begin van verwijderde\n" " tekst te markeren\n" #: optionDescriptions.h:65 msgid "-x , --stop-delete= String to mark end of deleted text\n" msgstr "" "-x , --stop-delete= Tekenreeks om het einde van verwijderde\n" " tekst te markeren\n" #: optionDescriptions.h:66 msgid "-y , --start-insert= String to mark begin of inserted text\n" msgstr "" "-y , --start-insert= Tekenreeks om het begin van toegevoegde\n" " tekst te markeren\n" #: optionDescriptions.h:67 msgid "-z , --stop-insert= String to mark end of inserted text\n" msgstr "" "-z , --stop-insert= Tekenreeks om het einde van toegevoegde\n" " tekst te markeren\n" #: optionDescriptions.h:68 msgid "-R, --repeat-markers Repeat markers at newlines\n" msgstr "-R, --repeat-markers Herhaal markeringen bij regeleindes\n" #: optionDescriptions.h:72 msgid "-r, --reverse Format new as old\n" msgstr "-r, --reverse Formateer nieuw als oud\n" #: option.c:38 msgid "Black" msgstr "Zwart" #: option.c:39 msgid "Red" msgstr "Rood" #: option.c:40 msgid "Green" msgstr "Groen" #: option.c:41 msgid "Brown" msgstr "Bruin" #: option.c:42 msgid "Blue" msgstr "Blauw" #: option.c:43 msgid "Magenta" msgstr "Magenta" #: option.c:44 msgid "Cyan" msgstr "Cyaan" #: option.c:45 msgid "Gray" msgstr "Grijs" #: option.c:46 msgid "Dark gray" msgstr "Donker grijs" #: option.c:47 msgid "Bright red" msgstr "Helder rood" #: option.c:48 msgid "Bright green" msgstr "Helder groen" #: option.c:49 msgid "Yellow" msgstr "Geel" #: option.c:50 msgid "Bright blue" msgstr "Helder blauw" #: option.c:51 msgid "Bright magenta" msgstr "Helder magenta" #: option.c:52 msgid "Bright cyan" msgstr "Helder cyaan" #: option.c:53 msgid "White" msgstr "Wit" #: option.c:88 #, c-format msgid "Single backslash at end of %s argument\n" msgstr "Losse backslash aan het einde van de %s argument\n" #. TRANSLATORS: #. The %s argument is a long option name without preceding dashes. #: option.c:140 option.c:147 #, c-format msgid "Invalid hexadecimal escape sequence in %s argument\n" msgstr "Ongeldige hexadecimale escapecode in de %s argument\n" #. TRANSLATORS: #. The %c argument will be either 'u' or 'U'. The %s argument is a long #. option name without preceding dashes. #: option.c:181 option.c:187 #, c-format msgid "Too short \\%c escape in %s argument\n" msgstr "Te korte \\%c escapecode in %s argument\n" #. TRANSLATORS: #. The %s argument is a long option name without preceding dashes. #: option.c:198 #, c-format msgid "\\U escape out of range in %s argument\n" msgstr "\\U escapecode buiten geldig bereik in %s argument\n" #. TRANSLATORS: #. The %s argument is a long option name without preceding dashes. #: option.c:203 #, c-format msgid "\\%c escapes for surrogate codepoints are not allowed in %s argument\n" msgstr "\\%c escapecodes voor surrogaat codepoints zijn niet toegestaan in %s argument\n" #: option.c:273 option.c:373 option.c:381 msgid "Whitespace and delimiter sets overlap\n" msgstr "Witruimte en afbakeningskarakters verzamelingen overlappen\n" #: option.c:445 option.c:647 #, c-format msgid "Invalid color specification %s\n" msgstr "Ongeldige kleur specificatie %s\n" #: option.c:458 #, c-format msgid "Invalid color %s\n" msgstr "Ongeldige kleur %s\n" #: option.c:470 #, c-format msgid "Invalid background color %s\n" msgstr "Ongeldige achtergrond kleur %s\n" #: option.c:523 #, c-format msgid "Usage: dwdiff [OPTIONS] \n" msgstr "Gebruik: dwdiff [OPTIES] \n" #: option.c:564 #, c-format msgid "Option %.*s is only supported for UTF-8 mode\n" msgstr "De optie %.*s wordt alleen ondersteund in UTF-8 mode\n" #: option.c:567 #, c-format msgid "Support for option %.*s is not compiled into this version of dwdiff\n" msgstr "Ondersteuning voor de optie %.*s is niet in deze versie van dwdiff meegecompileerd\n" #: option.c:574 option.c:585 option.c:604 #, c-format msgid "Option %.*s is not supported\n" msgstr "Optie %.*s is niet ondersteund\n" #: option.c:613 msgid "Can't read both files from standard input\n" msgstr "Kan niet beide bestanden lezen uit de standard invoer\n" #: option.c:617 option.c:712 msgid "Too many files to compare\n" msgstr "Te veel bestanden om te vergelijken\n" #. TRANSLATORS: #. "Name" and "Description" are table headings for the color name list. #. Make sure you keep the alignment of the headings over the text. #: option.c:636 msgid "Name Description\n" msgstr "Naam Omschrijving\n" #: option.c:641 msgid "The colors black through gray are also usable as background color\n" msgstr "De kleuren zwart tot en met grijs zijn ook bruikbaar als achtergrondkleur\n" #: option.c:689 #, c-format msgid "Error opening temporary output file: %s\n" msgstr "Fout bij het openen van het tijdelijke uitvoerbestand: %s\n" #: option.c:718 msgid "Only one input file accepted with --diff-input\n" msgstr "Slechts één invoerbestand toegestaan met --diff-input\n" #: util.c:38 msgid "Out of memory" msgstr "Onvoldoende geheugen beschikbaar" #: optionDescriptions.h:57 msgid "" "-A , --algorithm= Choose algorithm: best, normal, fast\n" msgstr "" "-A , --algorithm= Kies het algoritme: best, normal, fast\n" #: option.c:693 msgid "Invalid algorithm name\n" msgstr "Ongeldige algorithme naam\n" dwdiff-2.0.9/po/de.po0000660000175000017500000003356012262313361014205 0ustar gertjangertjan# German translations for dwdiff package. # Copyright (C) 2007-2010 G.P. Halkes # This file is distributed under the same license as the dwdiff package. # G.P. Halkes , 2007. # msgid "" msgstr "" "Project-Id-Version: dwdiff 1.2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-02-12 17:23+0100\n" "PO-Revision-Date: 2006-09-27 11:53+0200\n" "Last-Translator: Dr. D. Steuer \n" "Language-Team: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: util.h:28 util.h:30 #, c-format msgid "Program-logic error at %s:%d\n" msgstr "Programmlogikfehler bei %s:%d\n" #: doDiff.c:153 doDiff.c:192 doDiff.c:224 doDiff.c:247 doDiff.c:307 #: doDiff.c:471 msgid "Error reading back input\n" msgstr "Fehler beim zurücklesen der Eingabe\n" #: doDiff.c:495 doDiff.c:497 dwdiff.c:278 dwdiff.c:281 dwdiff.c:290 #: dwfilter.c:133 #, c-format msgid "Could not create temporary file: %s\n" msgstr "Konnte temporäre Datei nicht anlegen: %s\n" #: dwdiff.c:275 #, c-format msgid "Can't open file %s: %s\n" msgstr "Kann Datei %s nicht öffnen: %s\n" #: dwdiff.c:360 #, c-format msgid "Error reading file %s: %s\n" msgstr "Fehler bei Lesen der Datei %s: %s\n" #: dwdiff.c:379 dwdiff.c:384 dwdiff.c:389 #, c-format msgid "Error writing to temporary file %s: %s\n" msgstr "Fehler beim Schreiben in temporäre Datei %s: %s\n" #: dwdiff.c:466 #, c-format msgid "old: 0 words\n" msgstr "alt: 0 Wörter\n" #: dwdiff.c:468 #, c-format msgid "old: %d words %d %d%% common %d %d%% deleted %d %d%% changed\n" msgstr "alt: %d Wörter %d %d%% gemeinsam %d %d%% gelöscht %d %d%% geändert\n" #: dwdiff.c:475 #, c-format msgid "new: 0 words\n" msgstr "neu: 0 Wörter\n" #: dwdiff.c:477 #, c-format msgid "new: %d words %d %d%% common %d %d%% inserted %d %d%% changed\n" msgstr "neu: %d Wörter %d %d%% gleich %d %d%% eingefügt %d %d%% geändert\n" #: dwfilter.c:44 #, c-format msgid "Usage: dwfilter [OPTIONS] [POST PROCESSOR OPTIONS]\n" msgstr "" #. TRANSLATORS: #. - If the (C) symbol (that is the c in a circle) is not available, #. leave as it as is. (Unicode code point 0x00A9) #. - G.P. Halkes is name and should be left as is. #: dwfilter.c:56 option.c:524 msgid "" "Copyright (C) 2006-2011 G.P. Halkes\n" "Licensed under the GNU General Public License version 3\n" msgstr "" "Copyright © 2006-2011 G.P. Halkes\n" "Lizensiert unter der GNU General Public License version 3\n" #: dwfilter.c:94 option.c:683 option.c:686 #, c-format msgid "Option %.*s does not exist\n" msgstr "Option %.*s gibt es nicht\n" #: dwfilter.c:111 option.c:701 msgid "Need two files to compare\n" msgstr "Benötige zwei Dateien, um zu vergleichen\n" #: dwfilter.c:113 msgid "No post processor specified\n" msgstr "" #: dwfilter.c:149 #, c-format msgid "Error waiting for child process to terminate: %s\n" msgstr "" #: dwfilter.c:196 msgid "dwdiff returned an error\n" msgstr "" #: optionMacros.h:168 #, c-format msgid "Option %.*s does not take an argument\n" msgstr "Option %.*s hat kein Argument\n" #: optionMacros.h:174 #, c-format msgid "Option %.*s requires an argument\n" msgstr "Option %.*s benötigt ein Argument\n" #: optionMacros.h:258 #, c-format msgid "Garbage after value for %.*s option\n" msgstr "Müll nach dem Wert für die %.*s Option\n" #: optionMacros.h:261 #, c-format msgid "Value for %.*s option (%ld) is out of range\n" msgstr "Wert für die %*s Option (%ld) ist außerhalb des zulässigen Bereichs\n" #: optionMacros.h:295 #, c-format msgid "Value for %.*s option (%s) is not a valid boolean value\n" msgstr "" #: optionDescriptions.h:6 msgid "-h, --help Print this help message\n" msgstr "-h, --help Diese Hilfeseite ausgeben\n" #: optionDescriptions.h:7 msgid "-v, --version Print version and copyright information\n" msgstr "" "-v, --version Versions- und Copyrightinformationen\n" " ausgeben\n" #: optionDescriptions.h:10 msgid "-d , --delimiters= Specifiy delimiters\n" msgstr "-d , --delimiters= Begrenzer spezifizieren\n" #: optionDescriptions.h:11 msgid "-P, --punctuation Use punctuation characters as delimiters\n" msgstr "-P, --punctuation Nutze Zeichensetzungszeichen alsBegrenzer\n" #: optionDescriptions.h:12 msgid "-W , --white-space= Specify whitespace characters\n" msgstr "-W , --white-space= Character für Whitespace spezifizieren\n" #: optionDescriptions.h:14 msgid "" "-S[], --paragraph-separator[=] Show inserted or deleted blocks\n" " of empty lines, optionally overriding the marker\n" msgstr "" #: optionDescriptions.h:18 msgid "-1, --no-deleted Do not print deleted words\n" msgstr "-1, --no-deleted Gelöschte Wörter nicht ausgeben\n" #: optionDescriptions.h:19 msgid "-2, --no-inserted Do not print inserted words\n" msgstr "-2, --no-inserted Eingefügte Wörter nicht ausgeben\n" #: optionDescriptions.h:20 msgid "-3, --no-common Do not print common words\n" msgstr "-3, --no-common Gemeinsame Wörter nicht ausgeben\n" #: optionDescriptions.h:21 msgid "-L[], --line-numbers[] Prepend line numbers\n" msgstr "-L[], --line-numbers[] Voranstellen von Zeilennummern\n" #: optionDescriptions.h:22 msgid "-C, --context= Show lines of context\n" msgstr "-C, --context= Zeige Zeilen Kontext\n" #: optionDescriptions.h:23 msgid "-s, --statistics Print statistics when done\n" msgstr "-s, --statistics Statistiken ausgeben\n" #: optionDescriptions.h:25 msgid "--wdiff-output Produce wdiff compatible output\n" msgstr "" #: optionDescriptions.h:28 msgid "-i, --ignore-case Ignore differences in case\n" msgstr "-i, --ignore-case Groß- und Kleinschreibung ignorieren\n" #: optionDescriptions.h:29 msgid "-I, --ignore-formatting Ignore formatting differences\n" msgstr "-I, --ignore-formatting Ignoriere Formatierungsunterschiede\n" #. TRANSLATORS: #. The context meant here are words preceeding and succeeding each word in #. the text. By using these extra context words when applying the diff #. program, #. frequently occuring words will be more likely to be matched to the #. correct corresponding word in the other text, thus giving a better result. #: optionDescriptions.h:36 msgid "-m , --match-context= Use words of context for matching\n" msgstr "-m , --match-context= Benutze Wörter im Kontext für das Matching\n" #. TRANSLATORS: #. The use of context words for matching is more expensive, because after the #. first pass of diff the changes reported need refining. However, if the user #. can live with multiple changes that are within (2 * match-context + 1) #. words #. from eachother being reported as a single change, they can use this option. #: optionDescriptions.h:42 msgid "--aggregate-changes Allow close changes to aggregate\n" msgstr "--aggregate-changes Erlaube Zusammenfassung benachbarter Veränderungen\n" #: optionDescriptions.h:46 msgid "-c[], --color[=] Color mode\n" msgstr "-c[], --color[=] Farbmodus\n" #: optionDescriptions.h:47 msgid "-l, --less-mode As -p but also overstrike whitespace\n" msgstr "-l, --less-mode Wie -p, mit durchgestrichenen Whitespace\n" #: optionDescriptions.h:48 msgid "-p, --printer Use overstriking and bold text\n" msgstr "-p, --printer Gestrichenen und fetten Text nutzen\n" #: optionDescriptions.h:49 msgid "-w , --start-delete= String to mark begin of deleted text\n" msgstr "" "-w , --start-delete= Zeichenkette um den Beginn von gelöschtem\n" " Text zu markieren\n" #: optionDescriptions.h:50 msgid "-x , --stop-delete= String to mark end of deleted text\n" msgstr "" "-x , --stop-delete= Zeichenkette um das Ende von gelöschtem\n" " Text zu markieren\n" #: optionDescriptions.h:51 msgid "-y , --start-insert= String to mark begin of inserted text\n" msgstr "" "-y , --start-insert= Zeichenkette um den Beginn von eigefügtem\n" " Text zu markieren\n" #: optionDescriptions.h:52 msgid "-z , --stop-insert= String to mark end of inserted text\n" msgstr "" "-z , --stop-insert= Zeichenkette um das Ende von eigefügtem\n" " Text zu markieren\n" #: optionDescriptions.h:56 msgid "-r, --reverse Format new as old\n" msgstr "" #: option.c:38 msgid "Black" msgstr "Schwarz" #: option.c:39 msgid "Red" msgstr "Rot" #: option.c:40 msgid "Green" msgstr "Grün" #: option.c:41 msgid "Brown" msgstr "Braun" #: option.c:42 msgid "Blue" msgstr "Blau" #: option.c:43 msgid "Magenta" msgstr "Magenta" #: option.c:44 msgid "Cyan" msgstr "Cyan" #: option.c:45 msgid "Gray" msgstr "Grau" #: option.c:46 msgid "Dark gray" msgstr "Dunkelgrau" #: option.c:47 msgid "Bright red" msgstr "Hellrot" #: option.c:48 msgid "Bright green" msgstr "Hellgrün" #: option.c:49 msgid "Yellow" msgstr "Gelb" #: option.c:50 msgid "Bright blue" msgstr "Hellblau" #: option.c:51 msgid "Bright magenta" msgstr "Hellmagenta" #: option.c:52 msgid "Bright cyan" msgstr "Hellcyan" #: option.c:53 msgid "White" msgstr "Weiß" #: option.c:88 #, c-format msgid "Single backslash at end of %s argument\n" msgstr "Einfacher backslash am Ende des %s Argumentes\n" #. TRANSLATORS: #. The %s argument is a long option name without preceding dashes. #: option.c:137 option.c:144 #, c-format msgid "Invalid hexadecimal escape sequence in %s argument\n" msgstr "Ungültige hexadezimale Escape-Sequenz im %s Argument\n" #. TRANSLATORS: #. The %c argument will be either 'u' or 'U'. The %s argument is a long #. option name without preceding dashes. #: option.c:178 option.c:184 #, c-format msgid "Too short \\%c escape in %s argument\n" msgstr "Zu kurze \\%c Escapesequenz im Argument %s\n" #. TRANSLATORS: #. The %s argument is a long option name without preceding dashes. #: option.c:195 #, c-format msgid "\\U escape out of range in %s argument\n" msgstr "\\U Escapesequenz ist außerhalb des zulässigen Bereichs im Argument %s\n" #. TRANSLATORS: #. The %s argument is a long option name without preceding dashes. #: option.c:200 #, c-format msgid "\\%c escapes for surrogate codepoints are not allowed in %s argument\n" msgstr "\\%c Escapes für Surrogatkodepunkte sind im %s Argument nicht erlaubt\n" #: option.c:270 option.c:369 option.c:377 msgid "Whitespace and delimiter sets overlap\n" msgstr "Whitespace und Begrenzerspezifikation überlappen\n" #: option.c:435 option.c:637 #, c-format msgid "Invalid color specification %s\n" msgstr "Ungültige Farbspezifikation %s\n" #: option.c:448 option.c:460 #, c-format msgid "Invalid color %s\n" msgstr "Ungültige Farbe %s\n" #: option.c:445 #, c-format msgid "Invalid background color %s\n" msgstr "" #: option.c:512 #, c-format msgid "Usage: dwdiff [OPTIONS] \n" msgstr "Gebrauch: dwdiff [OPTIONEN] \n" #: option.c:553 #, c-format msgid "Option %.*s is only supported for UTF-8 mode\n" msgstr "Option %.*s ist nur für den UTF-8 Modus unterstützt\n" #: option.c:556 #, c-format msgid "Support for option %.*s is not compiled into this version of dwdiff\n" msgstr "Unterstützung für die Option %.*s ist in diese Version von dwdiff nicht integriert\n" #: option.c:563 option.c:574 option.c:593 #, c-format msgid "Option %.*s is not supported\n" msgstr "Option %.*s wird nicht unterstützt\n" #: option.c:602 msgid "Can't read both files from standard input\n" msgstr "Kann nicht beide Dateien von der Standardeingabe lesen\n" #: option.c:606 option.c:696 msgid "Too many files to compare\n" msgstr "Zu viele Dateien zu vergleichen\n" #. TRANSLATORS: #. "Name" and "Description" are table headings for the color name list. #. Make sure you keep the alignment of the headings over the text. #: option.c:626 msgid "Name Description\n" msgstr "Name Beschreibung\n" #: option.c:631 msgid "The colors black through gray are also usable as background color\n" msgstr "" #: option.c:679 #, c-format msgid "Error opening temporary output file: %s\n" msgstr "" #: util.c:38 msgid "Out of memory" msgstr "Hauptspeicher erschöpft" #~ msgid "Option %.*s has zero length argument\n" #~ msgstr "Option %.*s hat ein Argument der Länge Null\n" #: dwfilter.c:159 #, c-format msgid "Could not execute %s: %s\n" msgstr "" #: optionDescriptions.h:28 msgid "" "--diff-input Read the input as the output from " "diff\n" msgstr "" #: optionDescriptions.h:57 msgid "" "-A , --algorithm= Choose algorithm: best, normal, fast\n" msgstr "" #: optionDescriptions.h:68 msgid "-R, --repeat-markers Repeat markers at newlines\n" msgstr "" #. TRANSLATORS: #. - If the (C) symbol (that is the c in a circle) is not available, #. leave as it as is. (Unicode code point 0x00A9) #. - G.P. Halkes is name and should be left as is. #: option.c:507 msgid "" "Copyright (C) 2006-2011 G.P. Halkes and others\n" "Licensed under the GNU General Public License version 3\n" msgstr "" #: option.c:681 msgid "Invalid algorithm name\n" msgstr "" #: option.c:701 msgid "Only one input file accepted with --diff-input\n" msgstr "" dwdiff-2.0.9/po/fr.po0000660000175000017500000003404412262313361014222 0ustar gertjangertjan# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Emmanuel Trillaud , 2011. msgid "" msgstr "" "Project-Id-Version: dwdiff\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2011-01-31 20:18+0100\n" "PO-Revision-Date: 2011-09-24 16:07+0000\n" "Last-Translator: Emmanuel Trillaud \n" "Language-Team: French (http://www.transifex.net/projects/p/dwdiff/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1)\n" #: util.h:28 util.h:30 #, c-format msgid "Program-logic error at %s:%d\n" msgstr "Erreur de programmation à %s : %d\n" #: doDiff.c:209 doDiff.c:246 doDiff.c:274 doDiff.c:296 doDiff.c:350 #: doDiff.c:360 doDiff.c:533 msgid "Error reading back input\n" msgstr "Erreur lors de la lecture de l'entrée\n" #: doDiff.c:584 doDiff.c:586 dwdiff.c:277 dwdiff.c:280 dwdiff.c:289 #: dwfilter.c:147 #, c-format msgid "Could not create temporary file: %s\n" msgstr "Impossible de créer un fichier temporaire : %s\n" #: dwdiff.c:274 dwdiff.c:418 #, c-format msgid "Can't open file %s: %s\n" msgstr "Impossible d'ouvrir le fichier %s : %s\n" #: dwdiff.c:359 #, c-format msgid "Error reading file %s: %s\n" msgstr "Erreur lors de la lecture du fichier %s : %s\n" #: dwdiff.c:378 dwdiff.c:383 dwdiff.c:388 #, c-format msgid "Error writing to temporary file %s: %s\n" msgstr "Erreur lors de l'écriture du fichier temporaire %s : %s\n" #: dwdiff.c:562 #, c-format msgid "old: 0 words\n" msgstr "ancien : 0 mot\n" #: dwdiff.c:564 #, c-format msgid "old: %d words %d %d%% common %d %d%% deleted %d %d%% changed\n" msgstr "ancien : %d mots %d %d%% commun %d %d%% supprimé %d %d%% modifié\n" #: dwdiff.c:571 #, c-format msgid "new: 0 words\n" msgstr "nouveau : 0 mot\n" #: dwdiff.c:573 #, c-format msgid "new: %d words %d %d%% common %d %d%% inserted %d %d%% changed\n" msgstr "nouveau : %d mots %d %d%% commun %d %d%% inséré %d %d%% modifié\n" #: dwfilter.c:58 #, c-format msgid "" "Usage: dwfilter [OPTIONS] [POST " "PROCESSOR OPTIONS]\n" msgstr "" #. TRANSLATORS: #. - If the (C) symbol (that is the c in a circle) is not available, #. leave as it as is. (Unicode code point 0x00A9) #. - G.P. Halkes is name and should be left as is. #: dwfilter.c:70 option.c:535 msgid "" "Copyright (C) 2006-2011 G.P. Halkes\n" "Licensed under the GNU General Public License version 3\n" msgstr "Copyright (C) 2006-2011 G.P. Halkes\nSoumis à la GNU General Public License version 3\n" #. TRANSLATORS: #. - If the (C) symbol (that is the c in a circle) is not available, #. leave as it as is. (Unicode code point 0x00A9) #. - G.P. Halkes is name and should be left as is. #: option.c:507 msgid "" "Copyright (C) 2006-2011 G.P. Halkes and others\n" "Licensed under the GNU General Public License version 3\n" msgstr "Copyright (C) 2006-2011 G.P. Halkes et autres\nSoumis à la GNU General Public License version 3\n" #: dwfilter.c:108 option.c:693 option.c:702 #, c-format msgid "Option %.*s does not exist\n" msgstr "L'option %.*s n'existe pas\n" #: dwfilter.c:125 option.c:723 msgid "Need two files to compare\n" msgstr "Deux fichiers sont nécessaire à la comparaison\n" #: dwfilter.c:127 msgid "No post processor specified\n" msgstr "Aucun post-processeur précisé\n" #: dwfilter.c:159 #, c-format msgid "Could not execute %s: %s\n" msgstr "Impossible d'exécuter %s : %s\n" #: dwfilter.c:163 #, c-format msgid "Error waiting for child process to terminate: %s\n" msgstr "Erreur lors de l'attente de la fin du processus fils : %s\n" #: dwfilter.c:210 msgid "dwdiff returned an error\n" msgstr "dwdiff a renvoyé une erreur\n" #: optionMacros.h:168 #, c-format msgid "Option %.*s does not take an argument\n" msgstr "L'option %.*s n'accepte pas d'argument\n" #: optionMacros.h:174 #, c-format msgid "Option %.*s requires an argument\n" msgstr "L'option %.*s requiert un argument\n" #: optionMacros.h:258 #, c-format msgid "Garbage after value for %.*s option\n" msgstr "" #: optionMacros.h:261 #, c-format msgid "Value for %.*s option (%ld) is out of range\n" msgstr "Valeur (%3$ld) de l'option %2$.*1$s est hors limite\n" #: optionMacros.h:295 #, c-format msgid "Value for %.*s option (%s) is not a valid boolean value\n" msgstr "La valeur de l'option %.*s (%s) n'est pas une valeur booléenne valide\n" #: optionDescriptions.h:20 msgid "-h, --help Print this help message\n" msgstr "-h, --help Affiche ce message d'aide\n" #: optionDescriptions.h:21 msgid "" "-v, --version Print version and copyright " "information\n" msgstr "-v, --version Affiche les informations de version et de copyright\n" #: optionDescriptions.h:24 msgid "-d , --delimiters= Specifiy delimiters\n" msgstr "-d , --delimiters= Spécifie les séparateurs\n" #: optionDescriptions.h:25 msgid "" "-P, --punctuation Use punctuation characters as " "delimiters\n" msgstr "-P, --punctuation Utilise les caractères de ponctuation comme séparateur\n" #: optionDescriptions.h:26 msgid "-W , --white-space= Specify whitespace characters\n" msgstr "-W , --white-space= Spécifie les caractères blancs\n" #: optionDescriptions.h:28 msgid "" "--diff-input Read the input as the output from " "diff\n" msgstr "--diff-input lire l'entrée en tant que sortie de diff\n" #: optionDescriptions.h:29 msgid "" "-S[], --paragraph-separator[=] Show inserted or deleted blocks\n" " of empty lines, optionally overriding the marker\n" msgstr "-S[], --paragraph-separator[=] Montrer les blocs ajoutés ou supprimés\n de ligne vide, surcharge optionnellement le marqueur\n" #: optionDescriptions.h:33 msgid "-1, --no-deleted Do not print deleted words\n" msgstr "-1, --no-deleted Ne pas afficher les mots supprimés\n" #: optionDescriptions.h:34 msgid "-2, --no-inserted Do not print inserted words\n" msgstr "-2, --no-inserted Ne pas afficher les mots insérés\n" #: optionDescriptions.h:35 msgid "-3, --no-common Do not print common words\n" msgstr "-3, --no-common Ne pas afficher les mots communs\n" #: optionDescriptions.h:36 msgid "-L[], --line-numbers[] Prepend line numbers\n" msgstr "-L[], --line-numbers[] Ajoute les numéro de ligne\n" #: optionDescriptions.h:37 msgid "-C, --context= Show lines of context\n" msgstr "-C, --context= Montrer lignes de contexte\n" #: optionDescriptions.h:38 msgid "-s, --statistics Print statistics when done\n" msgstr "-s, --statistics Affiche les statistiques après l'exécution\n" #: optionDescriptions.h:40 msgid "--wdiff-output Produce wdiff compatible output\n" msgstr "--wdiff-output Génère sortie compatible avec wdiff\n" #: optionDescriptions.h:43 msgid "-i, --ignore-case Ignore differences in case\n" msgstr "-i, --ignore-case Ignore les différences de casse\n" #: optionDescriptions.h:44 msgid "-I, --ignore-formatting Ignore formatting differences\n" msgstr "-I, --ignore-formatting Ignore les différences de format\n" #. TRANSLATORS: #. The context meant here are words preceeding and succeeding each word in #. the text. By using these extra context words when applying the diff #. program, #. frequently occuring words will be more likely to be matched to the #. correct corresponding word in the other text, thus giving a better result. #: optionDescriptions.h:51 msgid "" "-m , --match-context= Use words of context for " "matching\n" msgstr "-m , --match-context= Utilise mot de contexte pour chercher les similarités\n" #. TRANSLATORS: #. The use of context words for matching is more expensive, because after the #. first pass of diff the changes reported need refining. However, if the user #. can live with multiple changes that are within (2 * match-context + 1) #. words #. from eachother being reported as a single change, they can use this option. #: optionDescriptions.h:57 msgid "" "--aggregate-changes Allow close changes to aggregate\n" msgstr "" #: optionDescriptions.h:61 msgid "-c[], --color[=] Color mode\n" msgstr "-c[], --color[=] Mode couleur\n" #: optionDescriptions.h:62 msgid "" "-l, --less-mode As -p but also overstrike whitespace\n" msgstr "" #: optionDescriptions.h:63 msgid "-p, --printer Use overstriking and bold text\n" msgstr "" #: optionDescriptions.h:64 msgid "" "-w , --start-delete= String to mark begin of deleted " "text\n" msgstr "-w , --start-delete= Chaîne marquant le début d'un texte supprimé\n" #: optionDescriptions.h:65 msgid "" "-x , --stop-delete= String to mark end of deleted text\n" msgstr "-w , --start-delete= Chaîne marquant la fin d'un texte supprimé\n" #: optionDescriptions.h:66 msgid "" "-y , --start-insert= String to mark begin of inserted " "text\n" msgstr "-y , --start-insert= Chaîne marquant le début d'un texte inséré\n" #: optionDescriptions.h:67 msgid "" "-z , --stop-insert= String to mark end of inserted text\n" msgstr "-y , --start-insert= Chaîne marquant la fin d'un texte inséré\n" #: optionDescriptions.h:68 msgid "-R, --repeat-markers Repeat markers at newlines\n" msgstr "-R, --repeat-markers Répéter les marqueurs au début de nouvelle ligne\n" #: optionDescriptions.h:72 msgid "-r, --reverse Format new as old\n" msgstr "" #: optionDescriptions.h:57 msgid "" "-A , --algorithm= Choose algorithm: best, normal, fast\n" msgstr "" #: option.c:38 msgid "Black" msgstr "Noir" #: option.c:39 msgid "Red" msgstr "Rouge" #: option.c:40 msgid "Green" msgstr "Vert" #: option.c:41 msgid "Brown" msgstr "Marron" #: option.c:42 msgid "Blue" msgstr "Bleu" #: option.c:43 msgid "Magenta" msgstr "Magenta" #: option.c:44 msgid "Cyan" msgstr "Cyan" #: option.c:45 msgid "Gray" msgstr "Gris" #: option.c:46 msgid "Dark gray" msgstr "Gris sombre" #: option.c:47 msgid "Bright red" msgstr "Rouge lumineux" #: option.c:48 msgid "Bright green" msgstr "Vert lumineux" #: option.c:49 msgid "Yellow" msgstr "Jaune" #: option.c:50 msgid "Bright blue" msgstr "Bleu lumineux" #: option.c:51 msgid "Bright magenta" msgstr "Magenta lumineux" #: option.c:52 msgid "Bright cyan" msgstr "Cyan lumineux" #: option.c:53 msgid "White" msgstr "Blanc" #: option.c:88 #, c-format msgid "Single backslash at end of %s argument\n" msgstr "Anti-slash simple à la fin de l'argument %s\n" #. TRANSLATORS: #. The %s argument is a long option name without preceding dashes. #: option.c:140 option.c:147 #, c-format msgid "Invalid hexadecimal escape sequence in %s argument\n" msgstr "Séquence d'echapement héxadécimal invalide dans l'argument %s\n" #. TRANSLATORS: #. The %c argument will be either 'u' or 'U'. The %s argument is a long #. option name without preceding dashes. #: option.c:181 option.c:187 #, c-format msgid "Too short \\%c escape in %s argument\n" msgstr "" #. TRANSLATORS: #. The %s argument is a long option name without preceding dashes. #: option.c:198 #, c-format msgid "\\U escape out of range in %s argument\n" msgstr "" #. TRANSLATORS: #. The %s argument is a long option name without preceding dashes. #: option.c:203 #, c-format msgid "\\%c escapes for surrogate codepoints are not allowed in %s argument\n" msgstr "" #: option.c:273 option.c:373 option.c:381 msgid "Whitespace and delimiter sets overlap\n" msgstr "" #: option.c:445 option.c:647 #, c-format msgid "Invalid color specification %s\n" msgstr "" #: option.c:458 option.c:470 #, c-format msgid "Invalid color %s\n" msgstr "Couleur %s invalide\n" #: option.c:445 #, c-format msgid "Invalid background color %s\n" msgstr "" #: option.c:523 #, c-format msgid "Usage: dwdiff [OPTIONS] \n" msgstr "Usage: dwdiff [OPTIONS] \n" #: option.c:564 #, c-format msgid "Option %.*s is only supported for UTF-8 mode\n" msgstr "L'option %.*s est supportée uniquement en mode UTF-8\n" #: option.c:567 #, c-format msgid "Support for option %.*s is not compiled into this version of dwdiff\n" msgstr "" #: option.c:574 option.c:585 option.c:604 #, c-format msgid "Option %.*s is not supported\n" msgstr "L'option %.*s n'est pas supportée\n" #: option.c:613 msgid "Can't read both files from standard input\n" msgstr "Impossible de lire les deux fichier depuis l'entrée standard\n" #: option.c:617 option.c:712 msgid "Too many files to compare\n" msgstr "Trop de fichier à comparer\n" #. TRANSLATORS: #. "Name" and "Description" are table headings for the color name list. #. Make sure you keep the alignment of the headings over the text. #: option.c:636 msgid "Name Description\n" msgstr "Nom Description\n" #: option.c:641 msgid "The colors black through gray are also usable as background color\n" msgstr "Les couleurs du noir au gris sont utilisable comme couleur d'arrière plan\n" #: option.c:689 #, c-format msgid "Error opening temporary output file: %s\n" msgstr "Erreur à l'ouverture du fichier temporaire de sortie : %s\n" #: option.c:718 msgid "Only one input file accepted with --diff-input\n" msgstr "Un seul fichier accepté en entrée avec --diff-input\n" #: util.c:38 msgid "Out of memory" msgstr "Plus de mémoire disponible" #: option.c:681 msgid "Invalid algorithm name\n" msgstr "" dwdiff-2.0.9/po/Makefile0000640000175000017500000000200112262313361014675 0ustar gertjangertjan# Copyright (C) 2006-2010 G.P. Halkes # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # 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, see . .POSIX: .PHONY: linguas lingua-install .SUFFIXES: .mo .po LINGUAOBJECTS=$(LINGUAS:=.mo) linguas: $(LINGUAOBJECTS) .po.mo: msgfmt -o $@ $< lingua-install: $(LINGUAOBJECTS) for lingua in $(LINGUAS) ; do \ if [ ! -f "$${lingua}.mo" ] ; then continue ; fi ;\ $(INSTALL) -d "$(LOCALEDIR)/$${lingua}/LC_MESSAGES" ;\ $(INSTALL) -m 644 "$${lingua}.mo" "$(LOCALEDIR)/$${lingua}/LC_MESSAGES/dwdiff.mo" ;\ done