From 9481d43bd52d85112a97c3b7fb60921c55ce9da3 Mon Sep 17 00:00:00 2001 From: tilmann Date: Mon, 15 Aug 2016 22:55:38 +0200 Subject: [PATCH] Prepare 1.2.0 release --- Makefile | 2 +- latexdiff | 6 +- latexdiff-1.0.1/COPYING | 623 --- latexdiff-1.0.1/README | 105 - latexdiff-1.0.1/doc/example-diff.tex | 89 - latexdiff-1.0.1/doc/latexdiff-man.tex | 355 -- latexdiff-1.0.1/example/example-draft.tex | 59 - latexdiff-1.0.1/example/example-rev.tex | 60 - latexdiff-1.0.1/latexdiff | 3392 -------------- latexdiff-1.0.1/latexdiff-fast | 3953 ----------------- latexdiff-1.0.1/latexdiff-so | 3849 ---------------- latexdiff-1.0.1/latexdiff-vc | 485 -- latexdiff-1.0.1/latexdiff-vc.1 | 246 -- latexdiff-1.0.1/latexdiff.1 | 751 ---- latexdiff-1.0.1/latexrevise | 527 --- latexdiff-1.0.1/latexrevise.1 | 235 - latexdiff-1.0.2/COPYING | 623 --- latexdiff-1.0.2/README | 107 - latexdiff-1.0.2/contrib/README.latexchanges | 13 - latexdiff-1.0.2/contrib/latexchanges.py | 67 - latexdiff-1.0.2/contrib/latexdiff-wrap | 192 - latexdiff-1.0.2/contrib/latexdiff.spec | 58 - latexdiff-1.0.2/doc/example-diff.tex | 89 - latexdiff-1.0.2/doc/latexdiff-man.tex | 355 -- latexdiff-1.0.2/example/example-draft.tex | 59 - latexdiff-1.0.2/example/example-rev.tex | 60 - latexdiff-1.0.2/latexdiff | 3400 -------------- latexdiff-1.0.2/latexdiff-fast | 3961 ----------------- latexdiff-1.0.2/latexdiff-so | 3857 ---------------- latexdiff-1.0.2/latexdiff-vc | 490 --- latexdiff-1.0.2/latexdiff-vc.1 | 246 -- latexdiff-1.0.2/latexdiff.1 | 758 ---- latexdiff-1.0.2/latexrevise | 539 --- latexdiff-1.0.2/latexrevise.1 | 235 - latexdiff-1.0.3/COPYING | 623 --- latexdiff-1.0.3/README | 107 - latexdiff-1.0.3/doc/example-diff.tex | 89 - latexdiff-1.0.3/doc/latexdiff-man.tex | 355 -- latexdiff-1.0.3/example/example-draft.tex | 59 - latexdiff-1.0.3/example/example-rev.tex | 60 - latexdiff-1.0.3/latexdiff | 3415 --------------- latexdiff-1.0.3/latexdiff-fast | 3976 ----------------- latexdiff-1.0.3/latexdiff-so | 3872 ---------------- latexdiff-1.0.3/latexdiff-vc | 493 --- latexdiff-1.0.3/latexdiff-vc.1 | 246 -- latexdiff-1.0.3/latexdiff.1 | 758 ---- latexdiff-1.0.3/latexrevise | 539 --- latexdiff-1.0.3/latexrevise.1 | 235 - latexdiff-1.0.4/COPYING | 623 --- latexdiff-1.0.4/Makefile | 64 - latexdiff-1.0.4/README | 108 - latexdiff-1.0.4/contrib/README.latexchanges | 13 - latexdiff-1.0.4/contrib/latexchanges.py | 67 - latexdiff-1.0.4/contrib/latexdiff-wrap | 192 - latexdiff-1.0.4/contrib/latexdiff.spec | 58 - latexdiff-1.0.4/doc/example-diff.tex | 89 - latexdiff-1.0.4/doc/latexdiff-man.pdf | Bin 261188 -> 0 bytes latexdiff-1.0.4/doc/latexdiff-man.tex | 355 -- latexdiff-1.0.4/example/example-draft.tex | 59 - latexdiff-1.0.4/example/example-rev.tex | 60 - latexdiff-1.0.4/latexdiff | 3540 --------------- latexdiff-1.0.4/latexdiff-fast | 4101 ----------------- latexdiff-1.0.4/latexdiff-so | 3997 ----------------- latexdiff-1.0.4/latexdiff-vc | 507 --- latexdiff-1.0.4/latexdiff-vc.1 | 252 -- latexdiff-1.0.4/latexdiff.1 | 751 ---- latexdiff-1.0.4/latexrevise | 538 --- latexdiff-1.0.4/latexrevise.1 | 243 - latexdiff-1.1.0/COPYING | 623 --- latexdiff-1.1.0/Makefile | 64 - latexdiff-1.1.0/README | 108 - latexdiff-1.1.0/contrib/README.latexchanges | 13 - latexdiff-1.1.0/contrib/latexchanges.py | 67 - latexdiff-1.1.0/contrib/latexdiff-wrap | 192 - latexdiff-1.1.0/contrib/latexdiff.spec | 58 - latexdiff-1.1.0/doc/latexdiff-man.pdf | Bin 289524 -> 0 bytes latexdiff-1.1.0/doc/latexdiff-man.tex | 355 -- latexdiff-1.1.0/example/example-draft.tex | 59 - latexdiff-1.1.0/example/example-rev.tex | 60 - latexdiff-1.1.0/latexdiff | 3824 ---------------- latexdiff-1.1.0/latexdiff-fast | 4385 ------------------- latexdiff-1.1.0/latexdiff-so | 4281 ------------------ latexdiff-1.1.0/latexdiff-vc | 649 --- latexdiff-1.1.0/latexdiff-vc.1 | 256 -- latexdiff-1.1.0/latexdiff.1 | 808 ---- latexdiff-1.1.0/latexrevise | 538 --- latexdiff-1.1.0/latexrevise.1 | 234 - latexdiff-vc | 4 +- testsuite/verify | 2 +- 89 files changed, 7 insertions(+), 76863 deletions(-) delete mode 100644 latexdiff-1.0.1/COPYING delete mode 100644 latexdiff-1.0.1/README delete mode 100644 latexdiff-1.0.1/doc/example-diff.tex delete mode 100644 latexdiff-1.0.1/doc/latexdiff-man.tex delete mode 100644 latexdiff-1.0.1/example/example-draft.tex delete mode 100644 latexdiff-1.0.1/example/example-rev.tex delete mode 100755 latexdiff-1.0.1/latexdiff delete mode 100755 latexdiff-1.0.1/latexdiff-fast delete mode 100755 latexdiff-1.0.1/latexdiff-so delete mode 100755 latexdiff-1.0.1/latexdiff-vc delete mode 100644 latexdiff-1.0.1/latexdiff-vc.1 delete mode 100644 latexdiff-1.0.1/latexdiff.1 delete mode 100755 latexdiff-1.0.1/latexrevise delete mode 100644 latexdiff-1.0.1/latexrevise.1 delete mode 100644 latexdiff-1.0.2/COPYING delete mode 100644 latexdiff-1.0.2/README delete mode 100644 latexdiff-1.0.2/contrib/README.latexchanges delete mode 100644 latexdiff-1.0.2/contrib/latexchanges.py delete mode 100755 latexdiff-1.0.2/contrib/latexdiff-wrap delete mode 100644 latexdiff-1.0.2/contrib/latexdiff.spec delete mode 100644 latexdiff-1.0.2/doc/example-diff.tex delete mode 100644 latexdiff-1.0.2/doc/latexdiff-man.tex delete mode 100644 latexdiff-1.0.2/example/example-draft.tex delete mode 100644 latexdiff-1.0.2/example/example-rev.tex delete mode 100755 latexdiff-1.0.2/latexdiff delete mode 100755 latexdiff-1.0.2/latexdiff-fast delete mode 100755 latexdiff-1.0.2/latexdiff-so delete mode 100755 latexdiff-1.0.2/latexdiff-vc delete mode 100644 latexdiff-1.0.2/latexdiff-vc.1 delete mode 100644 latexdiff-1.0.2/latexdiff.1 delete mode 100755 latexdiff-1.0.2/latexrevise delete mode 100644 latexdiff-1.0.2/latexrevise.1 delete mode 100644 latexdiff-1.0.3/COPYING delete mode 100644 latexdiff-1.0.3/README delete mode 100644 latexdiff-1.0.3/doc/example-diff.tex delete mode 100644 latexdiff-1.0.3/doc/latexdiff-man.tex delete mode 100644 latexdiff-1.0.3/example/example-draft.tex delete mode 100644 latexdiff-1.0.3/example/example-rev.tex delete mode 100755 latexdiff-1.0.3/latexdiff delete mode 100755 latexdiff-1.0.3/latexdiff-fast delete mode 100755 latexdiff-1.0.3/latexdiff-so delete mode 100755 latexdiff-1.0.3/latexdiff-vc delete mode 100644 latexdiff-1.0.3/latexdiff-vc.1 delete mode 100644 latexdiff-1.0.3/latexdiff.1 delete mode 100755 latexdiff-1.0.3/latexrevise delete mode 100644 latexdiff-1.0.3/latexrevise.1 delete mode 100644 latexdiff-1.0.4/COPYING delete mode 100644 latexdiff-1.0.4/Makefile delete mode 100644 latexdiff-1.0.4/README delete mode 100644 latexdiff-1.0.4/contrib/README.latexchanges delete mode 100644 latexdiff-1.0.4/contrib/latexchanges.py delete mode 100755 latexdiff-1.0.4/contrib/latexdiff-wrap delete mode 100644 latexdiff-1.0.4/contrib/latexdiff.spec delete mode 100644 latexdiff-1.0.4/doc/example-diff.tex delete mode 100644 latexdiff-1.0.4/doc/latexdiff-man.pdf delete mode 100644 latexdiff-1.0.4/doc/latexdiff-man.tex delete mode 100644 latexdiff-1.0.4/example/example-draft.tex delete mode 100644 latexdiff-1.0.4/example/example-rev.tex delete mode 100755 latexdiff-1.0.4/latexdiff delete mode 100755 latexdiff-1.0.4/latexdiff-fast delete mode 100755 latexdiff-1.0.4/latexdiff-so delete mode 100755 latexdiff-1.0.4/latexdiff-vc delete mode 100644 latexdiff-1.0.4/latexdiff-vc.1 delete mode 100644 latexdiff-1.0.4/latexdiff.1 delete mode 100755 latexdiff-1.0.4/latexrevise delete mode 100644 latexdiff-1.0.4/latexrevise.1 delete mode 100644 latexdiff-1.1.0/COPYING delete mode 100644 latexdiff-1.1.0/Makefile delete mode 100644 latexdiff-1.1.0/README delete mode 100644 latexdiff-1.1.0/contrib/README.latexchanges delete mode 100644 latexdiff-1.1.0/contrib/latexchanges.py delete mode 100755 latexdiff-1.1.0/contrib/latexdiff-wrap delete mode 100644 latexdiff-1.1.0/contrib/latexdiff.spec delete mode 100644 latexdiff-1.1.0/doc/latexdiff-man.pdf delete mode 100644 latexdiff-1.1.0/doc/latexdiff-man.tex delete mode 100644 latexdiff-1.1.0/example/example-draft.tex delete mode 100644 latexdiff-1.1.0/example/example-rev.tex delete mode 100755 latexdiff-1.1.0/latexdiff delete mode 100755 latexdiff-1.1.0/latexdiff-fast delete mode 100755 latexdiff-1.1.0/latexdiff-so delete mode 100755 latexdiff-1.1.0/latexdiff-vc delete mode 100644 latexdiff-1.1.0/latexdiff-vc.1 delete mode 100644 latexdiff-1.1.0/latexdiff.1 delete mode 100755 latexdiff-1.1.0/latexrevise delete mode 100644 latexdiff-1.1.0/latexrevise.1 diff --git a/Makefile b/Makefile index eaf5505..8a236dd 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # Makefile for preparing files for distribution -VERSION=1.1.1 +VERSION=1.2.0 .PHONY: distribution release test mkdirs clean cleanall cleantest webmanual diff --git a/latexdiff b/latexdiff index 45720e2..f234566 100755 --- a/latexdiff +++ b/latexdiff @@ -30,7 +30,7 @@ ### - --flatten option only expands first including command per line if there is more than one ### - move --show-options so that they are also capable of showing preamble (and commands) after all modificationsbased on source file packages # -# Version 1.2.0alpha: +# Version 1.2.0: # - highlight new and deleted figures # - bug fix in title mark-up. Previously deleted commands in title (such as \title, \author or \date) were marked up erroneously # - (minor) bug fixes in new 1.1.1 features: disabled label was commented out twice, additional spaces were introduced before list environment begin and end commands @@ -147,7 +147,7 @@ my ($algodiffversion)=split(/ /,$Algorithm::Diff::VERSION); my ($versionstring)=< requires the I command to be present. =head1 AUTHOR -Version 1.1.1 +Version 1.2.0 Copyright (C) 2004-2015 Frederik Tilmann This program is free software; you can redistribute it and/or modify diff --git a/latexdiff-1.0.1/COPYING b/latexdiff-1.0.1/COPYING deleted file mode 100644 index d6fa915..0000000 --- a/latexdiff-1.0.1/COPYING +++ /dev/null @@ -1,623 +0,0 @@ - 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 - - diff --git a/latexdiff-1.0.1/README b/latexdiff-1.0.1/README deleted file mode 100644 index 2b218ba..0000000 --- a/latexdiff-1.0.1/README +++ /dev/null @@ -1,105 +0,0 @@ - -INTRODUCTION - -latexdiff is a Perl script, which compares two latex files and marks -up significant differences between them (i.e. a diff for latex files). - Various options are available for visual markup using standard latex -packages such as "color.sty". Changes not directly affecting visible -text, for example in formatting commands, are still marked in -the latex source. - -A rudimentary revision facilility is provided by another Perl script, -latexrevise, which accepts or rejects all changes. Manual -editing of the difference file can be used to override this default -behaviour and accept or reject selected changes only. - -The author is F Tilmann (ftilmann@users.berlios.de) - -Project webpage: http://latexdiff.berlios.de/ -CTAN page: http://www.ctan.org/tex-archive/support/latexdiff - - -REQUIREMENTS - -Perl 5.8 or higher must be installed. - The latexdiff script makes use of the Perl package Algorithm::Diff (available -from www.cpan.org, current version 1.19). You can either install this package, or -use the standalone version of latexdiff, latexdiff-so, which has version 1.15 of -this package inlined and does not require external installation of -the package. Because latexdiff uses internal functions of Algorithm:Diff whose -calling format or availability can change without notice, the preferred method is -now to use the standalone version. - -As an alternative, latexdiff-fast has a modified version of Algorithm::Diff inlined, -which internally uses the UNIX diff command. This version is much faster but is dependent -on an external "diff" command. Subtle differences in the algorithm of Algorithm::Diff and -UNIX-diff mean that the resulting set of differences will generally not be the same as -for the standard latexdiff. In most practical cases, these differences are minor, though. - -INSTALLATION UNIX/LINUX - -The basic installation procedure is almost trivial: - -1. Copy latexdiff, latexrevise and latexdiff-vc into a directory which - is in the search path and make them executable. If the Algorithm::Diff - package is not installed, use latexdiff-so instead of latexdiff. - -2. Copy latexdiff.1 and latexrevise.1 into the correct man directory - -3. Optionally create soft links latexdiff-cvs latexdiff-rcs, and - latexdiff-svn for latexdiff-vc. - -The attached Makefile contains example commands to carry out above -steps as root for a typical UNIX installation. Type - - make install (for the stand alone version) -or - make install-ext (for the version using the external Algorithm::Diff) -or - make install-fast (for the version using the UNIX 'diff' function for fast differencing) - -to get it rolling. You can type - - make test -or - make test-ext -or - make test-fast - -to test the respective versions on a brief example before installation - - -DOCUMENTATION: - -Usage instructions are in the manual latexdiff-man.pdf as well as the -man pages. - -CHANGELOGS: - -Check out the comment lines at the beginning of the perl scripts (latexdiff, latexdiff-vc, latexrevise) - -CONTRIBUTIONS - -The directory contrib contains code written by others relating to latexdiff. -Currently this directory contains: - -latexdiff-wrap (Author: V. Kuhlmann) An alternative wrapper script which can be used - instead of latexdiff-vc. Its main use is as a template for customised wrapper scripts. - -latexdiff.spec (Author: T. Doerges) spec file for RPM generation - -The following contributions were incorporated into the latexdiff code, or inspired me to -extend latexdiff in a similar way: J. Paisley, N. Becker, K. Huebner - -LICENSE (also see file COPYING) - -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 (file LICENSE in the -distribution). - diff --git a/latexdiff-1.0.1/doc/example-diff.tex b/latexdiff-1.0.1/doc/example-diff.tex deleted file mode 100644 index 4193ecc..0000000 --- a/latexdiff-1.0.1/doc/example-diff.tex +++ /dev/null @@ -1,89 +0,0 @@ -\documentclass[12pt,a4paper]{article} -%DIF LATEXDIFF DIFFERENCE FILE -%DIF DEL example-draft.tex Tue Nov 13 00:43:28 2012 -%DIF ADD example-rev.tex Tue Nov 13 00:43:28 2012 - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -%DIF 7c7 -%DIF < \setlength{\textwidth}{6.5in} -%DIF ------- -\setlength{\textwidth}{6in} %DIF > -%DIF ------- - -\title{latexdiff Example - \DIFdelbegin \DIFdel{Draft }\DIFdelend \DIFaddbegin \DIFadd{Revised }\DIFaddend version} -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even %DIF > -% if some preamble might eventually end up as visible text.) %DIF > -%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF -%DIF UNDERLINE PREAMBLE %DIF PREAMBLE -\RequirePackage[normalem]{ulem} %DIF PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} %DIF PREAMBLE -\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}} %DIF PREAMBLE -\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}} %DIF PREAMBLE -%DIF SAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddbegin}{} %DIF PREAMBLE -\providecommand{\DIFaddend}{} %DIF PREAMBLE -\providecommand{\DIFdelbegin}{} %DIF PREAMBLE -\providecommand{\DIFdelend}{} %DIF PREAMBLE -%DIF FLOATSAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} %DIF PREAMBLE -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} %DIF PREAMBLE -\providecommand{\DIFaddbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFaddendFL}{} %DIF PREAMBLE -\providecommand{\DIFdelbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFdelendFL}{} %DIF PREAMBLE -%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of \DIFaddbegin \DIFadd{the }\DIFaddend latexdiff features. -Type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -or -\begin{verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{verbatim} -to display the markup. - -\section*{\DIFdelbegin \DIFdel{Another }\DIFdelend \DIFaddbegin \DIFadd{Yet another }\DIFaddend section title} - - \DIFdelbegin \DIFdel{A paragraph with a line only in the draft document. }\DIFdelend More things could be said were it not for the constraints of time and space. - -\DIFaddbegin \DIFadd{A paragraph with a line only in the revised document. }\DIFaddend More things could be -said were it not for the constraints of time and space. - -And here is a \DIFdelbegin \DIFdel{tipo}\DIFdelend \DIFaddbegin \DIFadd{typo}\DIFaddend . - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & \DIFdelbegin \DIFdel{Grey }\DIFdelend \DIFaddbegin \DIFadd{White }\DIFaddend \\ -Saruman & \DIFdelbegin \DIFdel{White -}\DIFdelend \DIFaddbegin \DIFadd{Evil -}\DIFaddend \end{tabular} - -And \DIFdelbegin \DIFdel{sometimes a whole paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}\DIFdelend \DIFaddbegin \DIFadd{now for something completely different, with not a paragraph in sight}\DIFaddend . -No change, -no markup! -\end{document} - - diff --git a/latexdiff-1.0.1/doc/latexdiff-man.tex b/latexdiff-1.0.1/doc/latexdiff-man.tex deleted file mode 100644 index 2adffcc..0000000 --- a/latexdiff-1.0.1/doc/latexdiff-man.tex +++ /dev/null @@ -1,355 +0,0 @@ -\documentclass[a4]{article} -\usepackage{graphicx} -%\def\C++{{\rm C\kern-.05em\raise.3ex\hbox{\footnotesize ++}}} -%\def\underscore{\leavevmode\kern.04em\vbox{\hrule width 0.4em height 0.3pt}} -\setlength{\parindent}{0pt} -%\setlength{\textwidth}{6.5in} -%\setlength{\oddsidemargin}{0.0in} -\title{Marking up differences between latex files with {\em latexdiff}} -\author{F.J. Tilmann\thanks{tilmann@gfz-potsdam.de}} -\date{\today} - -\begin{document} -\maketitle - -\section*{Preamble} - -{\em latexdiff} is a Perl script, which compares two -latex files and marks up significant differences between them. Various options are available for visual markup using standard -latex packages such as {\em color.sty}. Changes not directly affecting visible -text, for example in formatting commands, are still marked in the -latex source. - -A rudimentary revision facilility is provided by another Perl script, -{\em latexrevise}, which accepts or rejects all changes. Manual editing -of the difference file can be used to override this default behaviour -and accept or reject selected changes only. - -There is no explicit support for annotations as these are trivial to implement. -For example, I include the following command definition in the preamble -\begin{verbatim} -\newcommand{\remark}[1]{{ \bf [ \footnotesize #1 ]}} -\end{verbatim} -and mark up annotations as follows -\begin{verbatim} -... The roadrunner is the fastest running bird \remark{Check this -again with a zoologist!}. The most famous roadrunner ... -\end{verbatim} -Alternatively, instead of a command like \verb#\remark# in the example just given, an -equivalent annotation environment could be defined. -{\em latexrevise} can remove such comments or -environments from the text body. - -%It is planned that the revision capabilities of this system will be -%further expanded, dependent on the amount of feedback received. - -On the following pages you find the {\em man} pages for {\em - latexdiff} and {\em latexrevise} and a simple example. - -\include{latexdiff} -\setcounter{section}{0} - -\include{latexrevise} -\setcounter{section}{0} - -\include{latexdiff-vc} -\setcounter{section}{0} - -\section*{A simple example} - -We start with a draft text, \verb|example-draft.tex|, listed here in -full but also included in the distribution (except that the ``verbatim'' environment had -to be renamed to ``Verbatim'' for the listing). - -{\scriptsize -\begin{verbatim} -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6.5in} - -\title{latexdiff Example - Draft version} -\author{F Tilmann} - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of latexdiff features. -Type -\begin{Verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{Verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{Verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{Verbatim} -or -\begin{Verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{Verbatim} -to display the markup. Of course, instead of \verb|xpdf| you can use -\verb|okular, evince, acroread| or any other pdf or postscript viewer. - -\section*{Another section title} - -A paragraph with a line only in the draft document. More things -could be said were it not for the constraints of time and space. - -More things could be said were it not for the constraints of time and space. - -And here is a tipo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & Grey \\ -Saruman & White -\end{tabular} - -And sometimes a whole paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical. -No change, no markup! -\end{document} -\end{verbatim} -} - -We can now edit -this text as we would do with any other latex file to create -a new revision of the text, \verb|example-rev.tex|. We should run -\begin{verbatim} -latex example-rev.tex -\end{verbatim} -and look at the resulting \verb|.dvi| file to make sure that all -changes are valid. An example revision is listed here: - -{\scriptsize -\begin{verbatim} -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6in} - -\title{latexdiff Example - Revised version} -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even -% if some preamble might eventually end up as visible text.) - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of the latexdiff features. -Type -\begin{Verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{Verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{Verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{Verbatim} -or -\begin{Verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{Verbatim} -to display the markup. - -\section*{Yet another section title} - - More things could be said were it not for the constraints of time and space. - -A paragraph with a line only in the revised document. -More things could be said were it not for the constraints of time and space. - -And here is a typo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & White \\ -Saruman & Evil -\end{tabular} - -And now for something completely different, with not a paragraph in sight. -No change, -no markup! -\end{document} -\end{verbatim} -} - -To compare both revisions, type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -This results in the following difference file (a few newlines have been -added in this listing for legibility reasosn): -{\scriptsize -\begin{verbatim} -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -%DIF 7c7 -%DIF < \setlength{\textwidth}{6.5in} -%DIF ------- -\setlength{\textwidth}{6in} %DIF > -%DIF ------- - -%DIF 9c9 -%DIF < \title{latexdiff Example - Draft version} -%DIF ------- -\title{latexdiff Example - Revised version} %DIF > -%DIF ------- -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even %DIF > -% if some preamble might eventually end up as visible text.) %DIF > -%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF -%DIF UNDERLINE PREAMBLE %DIF PREAMBLE -\RequirePackage[normalem]{ulem} %DIF PREAMBLE -\RequirePackage{color} %DIF PREAMBLE -\providecommand{\DIFadd}[1]{{\color{blue}\uline{#1}}} %DIF PREAMBLE -\providecommand{\DIFdel}[1]{{\color{red}\sout{#1}}} %DIF PREAMBLE -%DIF SAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddbegin}{} %DIF PREAMBLE -\providecommand{\DIFaddend}{} %DIF PREAMBLE -\providecommand{\DIFdelbegin}{} %DIF PREAMBLE -\providecommand{\DIFdelend}{} %DIF PREAMBLE -%DIF FLOATSAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} %DIF PREAMBLE -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} %DIF PREAMBLE -\providecommand{\DIFaddbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFaddendFL}{} %DIF PREAMBLE -\providecommand{\DIFdelbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFdelendFL}{} %DIF PREAMBLE -%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of latexdiff features. -Type -\begin{Verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{Verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{Verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{Verbatim} -or -\begin{Verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{Verbatim} -to display the markup. - -\section*{\DIFaddbegin \DIFadd{Yet another }\DIFaddend \DIFdelbegin -\DIFdel{Another }\DIFdelend section title} - - \DIFdelbegin \DIFdel{A paragraph with a line only in the draft - document. }\DIFdelend More things could - be said were it not for the constraints of time and space. - -\DIFaddbegin \DIFadd{A paragraph with a line only in the revised - document. }\DIFaddend More things could be said -were it not for the constraints of time and space. - -And here is a \DIFaddbegin \DIFadd{typo}\DIFaddend \DIFdelbegin -\DIFdel{tipo}\DIFdelend . - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & \DIFaddbegin \DIFadd{White }\DIFaddend \DIFdelbegin -\DIFdel{Grey }\DIFdelend \\ -Saruman & \DIFaddbegin \DIFadd{Evil -}\DIFaddend \DIFdelbegin \DIFdel{White -}\DIFdelend \end{tabular} - -And \DIFaddbegin \DIFadd{now for something completely different, with not - a paragraph in sight}\DIFaddend \DIFdelbegin \DIFdel{sometimes a whole - paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}\DIFdelend . -No change, -no markup! -\end{document} -\end{verbatim} -} -Type -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -to make the markup visible. This is what it looks like: - -\vspace{1cm} -\framebox[\textwidth]{\includegraphics[width=\textwidth]{example-diff}} -\vspace{1cm} - -If you approve of all the changes in the revision, just continue with -\verb|example-rev.tex| for the next revision. If you like to adopt -most but not all changes you can use \verb|latexrevise| in the -following manner. Simply remove the \verb|\DIFdelbegin| and -\verb|\DIFdelend| tags around the text you would like to keep and -simply remove the text between \verb|\DIFaddbegin| and -\verb|\DIFaddend| tags, if you do not wish to keep them. Say you are happy with all proposed changes for the -example above except in -the last paragraph where you prefer the original draft. You have -to change - -{\scriptsize -\begin{verbatim} -... -And \DIFaddbegin \DIFadd{now for something completely different, with not - a paragraph in sight}\DIFaddend \DIFdelbegin \DIFdel{sometimes a whole - paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}\DIFdelend . -... -\end{verbatim} -} -into -{\scriptsize -\begin{verbatim} -... -And \DIFdel{sometimes a whole - paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}. -... -\end{verbatim} -} -and run -\begin{verbatim} -latexrevise -a example-rev.tex > example-final.tex -\end{verbatim} -\verb|example-final.tex| is then almost identical to -\verb|example-rev.tex| except for the last paragraph. -\end{document} diff --git a/latexdiff-1.0.1/example/example-draft.tex b/latexdiff-1.0.1/example/example-draft.tex deleted file mode 100644 index 593a170..0000000 --- a/latexdiff-1.0.1/example/example-draft.tex +++ /dev/null @@ -1,59 +0,0 @@ -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6.5in} - -\title{latexdiff Example - Draft version} -\author{F Tilmann} - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of latexdiff features. -Type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -or -\begin{verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{verbatim} -to display the markup. - -\section*{Another section title} - -A paragraph with a line only in the draft document. More things could be said -were it not for the constraints of time and space. - -More things could be said were it not for the constraints of time and space. - -And here is a tipo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & Grey \\ -Saruman & White -\end{tabular} - -And sometimes a whole paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical. -No change, no markup! -\end{document} - - diff --git a/latexdiff-1.0.1/example/example-rev.tex b/latexdiff-1.0.1/example/example-rev.tex deleted file mode 100644 index 4bcaf15..0000000 --- a/latexdiff-1.0.1/example/example-rev.tex +++ /dev/null @@ -1,60 +0,0 @@ -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6in} - -\title{latexdiff Example - Revised version} -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even -% if some preamble might eventually end up as visible text.) - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of the latexdiff features. -Type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -or -\begin{verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{verbatim} -to display the markup. - -\section*{Yet another section title} - - More things could be said were it not for the constraints of time and space. - -A paragraph with a line only in the revised document. More things could be -said were it not for the constraints of time and space. - -And here is a typo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & White \\ -Saruman & Evil -\end{tabular} - -And now for something completely different, with not a paragraph in sight. -No change, -no markup! -\end{document} - - diff --git a/latexdiff-1.0.1/latexdiff b/latexdiff-1.0.1/latexdiff deleted file mode 100755 index 4f34c1a..0000000 --- a/latexdiff-1.0.1/latexdiff +++ /dev/null @@ -1,3392 +0,0 @@ -#!/usr/bin/env perl -##!/usr/bin/perl -w -# latexdiff - differences two latex files on the word level -# and produces a latex file with the differences marked up. -# -# Copyright (C) 2004-12 F J Tilmann (tilmann@gfz-potsdam.de, ftilmann@users.berlios.de) -# -# Project webpages: http://latexdiff.berlios.de/ -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# -# Version 1.0.1 - treat \big,\bigg etc. equivalently to \left and -# \right - include starred version in MATHENV - apply -# - flatten recursively and --flatten expansion is now -# aware of comments (thanks to Tim Connors for patch) -# - Change to post-processing for more reliability for -# deleted math environments -# - On linux systems, recognise and remove DOS style newlines -# - Provide markup for some special preamble commands (\title, -# \author,\date, -# - configurable by setting context2cmd -# - for styles using ulem package, remove \emph and \text.. from list of -# safe commands in order to allow linebreaks within the -# highlighted sections. -# - for ulem style, now show citations by enclosing them in \mbox commands. -# This unfortunately implies linebreaks within citations no longer function, -# so this functionality can be turned off (Option --disable-citation-markup). -# With --enable-citation-markup, the mbox markup is forced for other styles) -# - new substyle COLOR. This is particularly useful for marking up citations -# and some special post-processing is implemented to retain cite -# commands in deleted blocks. -# - four different levels of math-markup -# - Option --driver for choosing driver for modes employing changebar package -# - accept \\* as valid command (and other commands of form \.*). Also accept -# \ (backslashed newline) -# - some typo fixes, include commands defined in preamble as safe commands -# (Sebastian Gouezel) -# - include compared filenames as comments as line 2 and 3 of -# the preamble (can be modified with option --label, and suppressed with -# --no-label), option --visible-label to show files in generated pdf or dvi -# at the beginning of main document -# -# Version 0.5 A number of minor improvements based on feedback -# Deleted blocks are now shown before added blocks -# Package specific processing -# -# Version 0.43 unreleased typo in list of styles at the end -# Add protect to all \cbstart, \cbend commands -# More robust substitution of deleted math commands -# -# Version 0.42 November 06 Bug fixes only -# -# Version 0.4 March 06 option for fast differencing using UNIX diff command, several minor bug fixes (\par bug, improved highlighting of textcmds) -# -# Version 0.3 August 05 improved parsing of displayed math, --allow-spaces -# option, several minor bug fixes -# -# Version 0.25 October 04 Fix bug with deleted equations, add math mode commands to safecmd, add | to allowed interpunctuation signs -# Version 0.2 September 04 extension to utf-8 and variable encodings -# Version 0.1 August 04 First public release - -use Algorithm::Diff qw(traverse_sequences); - -use Getopt::Long ; -use strict ; -use warnings; -use utf8 ; - -my ($algodiffversion)=split(/ /,$Algorithm::Diff::VERSION); - - -my ($versionstring)=< 0, - WHOLE => 1, - COARSE => 2, - FINE => 3 -}; - - -my (@configlist,@labels, - @appendsafelist,@excludesafelist, - @appendtextlist,@excludetextlist, - @appendcontext1list,@appendcontext2list, - @packagelist); -my ($assign,@config); -# Hash where keys corresponds to the names of all included packages (including the documentclass as another package -# the optional arguments to the package are the values of the hash elements -my ($pkg,%packages); -# Defaults -$type='UNDERLINE'; -$subtype='SAFE'; -$floattype='FLOATSAFE'; -$mathmarkup=COARSE; - -$verbose=0; -# output debug and intermediate files, set to 0 in final distribution -$debug=0; -# define character properties -sub IsNonAsciiPunct { return <<'END' # Unicode punctuation but excluding ASCII punctuation -+utf8::IsPunct --utf8::IsASCII -END -} -sub IsNonAsciiS { return <<'END' # Unicode symbol but excluding ASCII -+utf8::IsS --utf8::IsASCII -END -} - - -my %verbhash; - -Getopt::Long::Configure('bundling'); -GetOptions('type|t=s' => \$type, - 'subtype|s=s' => \$subtype, - 'floattype|f=s' => \$floattype, - 'config|c=s' => \@configlist, - 'preamble|p=s' => \$preamblefile, - 'encoding|e=s' => \$encoding, - 'label|L=s' => \@labels, - 'no-label' => \$nolabel, - 'visible-label' => \$visiblelabel, - 'exclude-safecmd|A=s' => \@excludesafelist, - 'replace-safecmd=s' => \$replacesafe, - 'append-safecmd|a=s' => \@appendsafelist, - 'exclude-textcmd|X=s' => \@excludetextlist, - 'replace-textcmd=s' => \$replacetext, - 'append-textcmd|x=s' => \@appendtextlist, - 'replace-context1cmd=s' => \$replacecontext1, - 'append-context1cmd=s' => \@appendcontext1list, - 'replace-context2cmd=s' => \$replacecontext2, - 'append-context2cmd=s' => \@appendcontext2list, - 'show-preamble' => \$showpreamble, - 'show-safecmd' => \$showsafe, - 'show-textcmd' => \$showtext, - 'show-config' => \$showconfig, - 'show-all' => \$showall, - 'packages=s' => \@packagelist, - 'allow-spaces' => \$allowspaces, - 'math-markup=s' => \$mathmarkup, - 'enable-citation-markup' => \$enablecitmark, - 'disable-citation-markup' => \$disablecitmark, - 'verbose|V' => \$verbose, - 'ignore-warnings' => \$ignorewarnings, - 'driver=s'=> \$driver, - 'flatten' => \$flatten, - 'version' => \$version, - 'help|h|H' => \$help); - -if ( $help ) { - usage() ; -} - - -if ( $version ) { - die $versionstring ; -} - -print STDERR $versionstring if $verbose; - -if (defined($showall)){ - $showpreamble=$showsafe=$showtext=$showconfig=1; -} - -if (defined($mathmarkup)) { - $mathmarkup=~tr/a-z/A-Z/; - if ( $mathmarkup eq 'OFF' ){ - $mathmarkup=OFF; - } elsif ( $mathmarkup eq 'WHOLE' ){ - $mathmarkup=WHOLE; - } elsif ( $mathmarkup eq 'COARSE' ){ - $mathmarkup=COARSE; - } elsif ( $mathmarkup eq 'FINE' ){ - $mathmarkup=FINE; - } elsif ( $mathmarkup !~ m/^[0123]$/ ) { - die "Illegal value: ($mathmarkup) for option--math-markup. Possible values: OFF,WHOLE,COARSE,FINE,0- "; - } - # else use numerical value -} - -# setting extra preamble commands -if (defined($preamblefile)) { - $latexdiffpreamble=join "\n",(extrapream($preamblefile),""); -} else { - $latexdiffpreamble=join "\n",(extrapream($type,$subtype,$floattype),""); -} - -if ( defined($driver) ) { - # for changebar only - $latexdiffpreamble=~s/\[dvips\]/[$driver]/sg; -} -# setting up @SAFECMDLIST and @SAFECMDEXCL -if (defined($replacesafe)) { - init_regex_arr_ext(\@SAFECMDLIST,$replacesafe); -} else { - init_regex_arr_data(\@SAFECMDLIST, "SAFE COMMANDS"); -} -foreach $appendsafe ( @appendsafelist ) { - init_regex_arr_ext(\@SAFECMDLIST, $appendsafe); -} -foreach $excludesafe ( @excludesafelist ) { - init_regex_arr_ext(\@SAFECMDEXCL, $excludesafe); -} - -# Special: treat all cite commands as safe except in UNDERLINE and FONTSTRIKE mode -# (there is a conflict between citation and ulem package, see -# package documentation) -# Use post-processing - -if ( uc($type) ne "UNDERLINE" && uc($type) ne "FONTSTRIKE" && uc($type) ne "CULINECHBAR" ) { - push (@SAFECMDLIST, qr/^cite.*$/); -} else { - ### Experimental: disable text and emph commands - push (@SAFECMDLIST, qr/^cite.*$/) unless $disablecitmark; - push(@SAFECMDEXCL, qr/^emph$/, qr/^text..$/); - # replace \cite{..} by \mbox{\cite{..}} in added or deleted blocks in post-processing - if ( uc($subtype) eq "COLOR" or uc($subtype) eq "DVIPSCOL" ) { - # remove \cite command again from list of safe commands - pop @SAFECMDLIST; - # deleted cite commands - $CITE2CMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite-type commands which should be reinstated in deleted blocks - } else { - $CITECMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite commands which need to be protected within an mbox in UNDERLINE and other modes using ulem - } -} -$CITECMD='(?:cite\w*|nocite)' if $enablecitmark ; # as above for explicit selection - -# setting up @TEXTCMDLIST and @TEXTCMDEXCL -if (defined($replacetext)) { - init_regex_arr_ext(\@TEXTCMDLIST,$replacetext); -} else { - init_regex_arr_data(\@TEXTCMDLIST, "TEXT COMMANDS"); -} -foreach $appendtext ( @appendtextlist ) { - init_regex_arr_ext(\@TEXTCMDLIST, $appendtext); -} -foreach $excludetext ( @excludetextlist ) { - init_regex_arr_ext(\@TEXTCMDEXCL, $excludetext); -} - - -# setting up @CONTEXT1CMDLIST ( @CONTEXT1CMDEXCL exist but is always empty ) -if (defined($replacecontext1)) { - init_regex_arr_ext(\@CONTEXT1CMDLIST,$replacecontext1); -} else { - init_regex_arr_data(\@CONTEXT1CMDLIST, "CONTEXT1 COMMANDS"); -} -foreach $appendcontext1 ( @appendcontext1list ) { - init_regex_arr_ext(\@CONTEXT1CMDLIST, $appendcontext1); -} - - -# setting up @CONTEXT2CMDLIST ( @CONTEXT2CMDEXCL exist but is always empty ) -if (defined($replacecontext2)) { - init_regex_arr_ext(\@CONTEXT2CMDLIST,$replacecontext2); -} else { - init_regex_arr_data(\@CONTEXT2CMDLIST, "CONTEXT2 COMMANDS"); -} -foreach $appendcontext2 ( @appendcontext2list ) { - init_regex_arr_ext(\@CONTEXT2CMDLIST, $appendcontext2); -} - -# setting configuration variables -@config=(); -foreach $config ( @configlist ) { - if (-f $config ) { - open(FILE,$config) or die ("Couldn't open configuration file $config: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@config,$_); - } - close(FILE); - } - else { -# foreach ( split(",",$config) ) { -# push @config,$_; -# } - push @config,split(",",$config) - } -} -foreach $assign ( @config ) { - $assign=~ m/\s*(\w*)\s*=\s*(\S*)\s*$/ or die "Illegal assignment $assign in configuration list (must be variable=value)"; - if ( $1 eq "MINWORDSBLOCK" ) { $MINWORDSBLOCK = $2; } - elsif ( $1 eq "FLOATENV" ) { $FLOATENV = $2 ; } - elsif ( $1 eq "PICTUREENV" ) { $PICTUREENV = $2 ; } - elsif ( $1 eq "MATHENV" ) { $MATHENV = $2 ; } - elsif ( $1 eq "MATHREPL" ) { $MATHREPL = $2 ; } - elsif ( $1 eq "MATHARRENV" ) { $MATHARRENV = $2 ; } - elsif ( $1 eq "MATHARRREPL" ) { $MATHARRREPL = $2 ; } - elsif ( $1 eq "ARRENV" ) { $ARRENV = $2 ; } - elsif ( $1 eq "COUNTERCMD" ) { $COUNTERCMD = $2 ; } - else { die "Unknown variable $1 in assignment.";} -} - -if ( $mathmarkup == COARSE || $mathmarkup == WHOLE ) { - push(@MATHTEXTCMDLIST,qr/^MATHBLOCK(?:$MATHENV|$MATHARRENV|SQUAREBRACKET)$/); -} - - - -foreach $pkg ( @packagelist ) { - map { $packages{$_}="" } split(/,/,$pkg) ; -} - -if ($showpreamble) { - print "\nPreamble commands:\n"; - print $latexdiffpreamble ; -} - -if ($showsafe) { - print "\nCommands safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE (unless excluded):\n"; - print_regex_arr(@SAFECMDLIST); - print "\nCommands not safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE :\n"; - print_regex_arr(@SAFECMDEXCL); -} - -if ($showtext) { - print "\nCommands with last argument textual (unless excluded) and safe in every context:\n"; - print_regex_arr(@TEXTCMDLIST); - print "\nContext1 commands (last argument textual, command will be disabled in deleted passages, last argument will be shown as plain text):\n"; - print_regex_arr(@CONTEXT1CMDLIST); - print "\nContext2 commands (last argument textual, command and its argument will be disabled in deleted passages):\n"; - print_regex_arr(@CONTEXT2CMDLIST); - print "\nExclude list of Commands with last argument not textual (overrides patterns above):\n"; - print_regex_arr(@TEXTCMDEXCL); -} - - -if ($showconfig) { - print "Configuration variables:\n"; - print "MINWORDSBLOCK=$MINWORDSBLOCK\n"; - print "FLOATENV=$FLOATENV\n"; - print "PICTUREENV=$PICTUREENV\n"; - print "MATHENV=$MATHENV\n"; - print "MATHREPL=$MATHREPL\n"; - print "MATHARRENV=$MATHARRENV\n"; - print "MATHARRREPL=$MATHARRREPL\n"; - print "ARRENV=$ARRENV\n"; - print "COUNTERCMD=$COUNTERCMD\n"; -} -if ($showconfig || $showtext || $showsafe || $showpreamble) { - exit 0; } -if ( @ARGV != 2 ) { - print STDERR "2 and only 2 non-option arguments required. Write latexdiff -h to get help\n"; - exit(2); -} - -# Are extra spaces between command arguments permissible? -my $extraspace; -if ($allowspaces) { - $extraspace='\s*'; -} else { - $extraspace=''; -} - -# append context lists to text lists (as text property is implied) -push @TEXTCMDLIST, @CONTEXT1CMDLIST; -push @TEXTCMDLIST, @CONTEXT2CMDLIST; - -push @TEXTCMDLIST, @MATHTEXTCMDLIST if $mathmarkup==COARSE; - -# internal additions to SAFECMDLIST -push(@SAFECMDLIST, qr/^QLEFTBRACE$/, qr/^QRIGHTBRACE$/); - - -# Patterns. These are used by some of the subroutines, too -# I can only define them down here because value of extraspace depends on an option - my $pat0 = '(?:[^{}])*'; - my $pat1 = '(?:[^{}]|\{'.$pat0.'\})*'; - my $pat2 = '(?:[^{}]|\{'.$pat1.'\})*'; - my $pat3 = '(?:[^{}]|\{'.$pat2.'\})*'; - my $pat4 = '(?:[^{}]|\{'.$pat3.'\})*'; - my $pat5 = '(?:[^{}]|\{'.$pat4.'\})*'; - my $pat6 = '(?:[^{}]|\{'.$pat5.'\})*'; - my $brat0 = '(?:[^\[\]]|\\\[|\\\])*'; - - my $quotemarks = '(?:\'\')|(?:\`\`)'; - my $punct='[0.,\/\'\`:;\"\?\(\)\[\]!~\p{IsNonAsciiPunct}\p{IsNonAsciiS}]'; - my $number='-?\d*\.\d*'; - my $mathpunct='[+=<>\-\|]'; - my $and = '&'; - my $coords= '[\-.,\s\d]*'; -# word: sequence of letters or accents followed by letter - my $word='(?:[-\w\d*]|\\\\[\"\'\`~^][A-Za-z\*])+'; - my $cmdleftright='\\\\(?:left|right|[Bb]igg?[lrm]?|middle)\s*(?:[()\[\]|]|\\\\(?:[|{}]|\w+))'; - - my $cmdoptseq='\\\\[\w\d\*]+'.$extraspace.'(?:(?:\['.$brat0.'\]|\{'. $pat6 . '\}|\(' . $coords .'\))'.$extraspace.')*'; - my $backslashnl='\\\\\n'; - my $oneletcmd='\\\\.\*?(?:\['.$brat0.'\]|\{'. $pat6 . '\})*'; - my $math='\$(?:[^$]|\\\$)*?\$|\\\\[(].*?\\\\[)]'; -## the current maths command cannot cope with newline within the math expression - - my $comment='%.*?\n'; - my $pat=qr/(?:\A\s*)?(?:${and}|${quotemarks}|${number}|${word}|$cmdleftright|${cmdoptseq}|${math}|${backslashnl}|${oneletcmd}|${comment}|${punct}|${mathpunct}|\{|\})\s*/ ; - - - -# now we are done setting up and can start working -my ($oldfile, $newfile) = @ARGV; -# check for existence of input files -if ( ! -e $oldfile ) { - die "Input file $oldfile does not exist."; -} -if ( ! -e $newfile ) { - die "Input file $newfile does not exist."; -} - - -# set the labels to be included into the file -my ($oldtime,$newtime,$oldlabel,$newlabel); -if (defined($labels[0])) { - $oldlabel=$labels[0] ; -} else { - $oldtime=localtime((stat($oldfile))[9]); - $oldlabel="$oldfile " . " "x(length($newfile)-length($oldfile)) . $oldtime; -} -if (defined($labels[1])) { - $newlabel=$labels[1] ; -} else { - $newtime=localtime((stat($newfile))[9]); - $newlabel="$newfile " . " "x(length($oldfile)-length($newfile)) . $newtime; -} - -$encoding=guess_encoding($newfile) unless defined($encoding); - -$encoding = "utf8" if $encoding =~ m/^utf8/i ; -if (lc($encoding) eq "utf8" ) { - binmode(STDOUT, ":utf8"); - binmode(STDERR, ":utf8"); -} - -$old=read_file_with_encoding($oldfile,$encoding); -$new=read_file_with_encoding($newfile,$encoding); - - - - -# reset time -exetime(1); -($oldpreamble,$oldbody,$oldpost)=splitdoc($old,'\\\\begin\{document\}','\\\\end\{document\}'); - - -($newpreamble,$newbody,$newpost)=splitdoc($new,'\\\\begin\{document\}','\\\\end\{document\}'); - - -if ($flatten) { - $oldbody=flatten($oldbody,$oldpreamble,$oldfile,$encoding); - $newbody=flatten($newbody,$newpreamble,$newfile,$encoding); -} - -my @auxlines; -if ( length $oldpreamble && length $newpreamble ) { - # pre-process preamble by looking for commands used in \maketitle (title, author, date etc commands) - # and marking up content with latexdiff markup - @auxlines=preprocess_preamble($oldpreamble,$newpreamble); - - @oldpreamble = split /\n/, $oldpreamble; - @newpreamble = split /\n/, $newpreamble; - - # If a command is defined in the preamble of the new file, and only uses safe commands, then it can be considered to be safe) (contribution S. Gouezel) - # Base this assessment on the new preamble - add_safe_commands($newpreamble); - - %packages=list_packages(@newpreamble) unless %packages; - if (defined $packages{"hyperref"} ) { - print STDERR "hyperref package detected.\n" if $verbose ; - $latexdiffpreamble =~ s/\{\\DIFadd\}/{\\DIFaddtex}/g; - $latexdiffpreamble =~ s/\{\\DIFdel\}/{\\DIFdeltex}/g; - $latexdiffpreamble .= join "\n",(extrapream("HYPERREF"),""); - } - print STDERR "Differencing preamble.\n" if $verbose; - - # insert dummy first line such that line count begins with line 1 (rather than perl's line 0) - just so that line numbers inserted by linediff are correct - unshift @newpreamble,''; - unshift @oldpreamble,''; - @diffpreamble = linediff(\@oldpreamble, \@newpreamble); - # remove dummy line again - shift @diffpreamble; - # add filenames, modification time and latexdiff mark - defined($nolabel) or splice @diffpreamble,1,0, - "%DIF LATEXDIFF DIFFERENCE FILE", - ,"%DIF DEL $oldlabel", - "%DIF ADD $newlabel"; - if ( @auxlines ) { - push @diffpreamble,"%DIF DELETED TITLE COMMANDS FOR MARKUP"; - push @diffpreamble,join("\n",@auxlines); - } - push @diffpreamble,$latexdiffpreamble; - push @diffpreamble,'\begin{document}'; -} -elsif ( !length $oldpreamble && !length $newpreamble ) { - @diffpreamble=(); -} else { - print STDERR "Either both texts must have preamble or neither text must have the preamble.\n"; - exit(2); -} - -if (defined $packages{"amsmath"} or defined $packages{"amsart"} or defined $packages{"amsbook"} ) { - print STDERR "amsmath package detected.\n" if $verbose ; - $MATHARRREPL='align*'; -} - -print STDERR "Preprocessing body. " if $verbose; -my ($oldleadin,$newleadin)=preprocess($oldbody,$newbody); - - -# run difference algorithm -@diffbody=bodydiff($oldbody, $newbody); -$diffbo=join("",@diffbody); -if ( $debug ) { - open(RAWDIFF,">","latexdiff.debug.bodydiff"); - print RAWDIFF $diffbo; - close(RAWDIFF); -} -print STDERR "(",exetime()," s)\n","Postprocessing body. \n " if $verbose; -postprocess($diffbo); -$diffall =join("\n",@diffpreamble) ; -# add visible labels -if (defined($visiblelabel)) { - # Give information right after \begin{document} (or at the beginning of the text for files without preamble - ### if \date command is used, add information to \date argument, otherwise give right after \begin{document} - ### $diffall=~s/(\\date$extraspace(?:\[$brat0\])?$extraspace)\{($pat6)\}/$1\{$2 \\ LATEXDIFF comparison \\ Old: $oldlabel \\ New: $newlabel \}/ or - $diffbo = "\\begin{verbatim}LATEXDIFF comparison\nOld: $oldlabel\nNew: $newlabel\\end{verbatim}\n$diffbo" ; -} - -$diffall .= "$newleadin$diffbo" ; -$diffall .= "\\end{document}$newpost" if length $newpreamble ; -if ( lc($encoding) ne "utf8" && lc($encoding) ne "ascii" ) { - print STDERR "Encoding output file to $encoding\n" if $verbose; - $diffall=Encode::encode($encoding,$diffall); - binmode STDOUT; -} -print $diffall; - - -print STDERR "(",exetime()," s)\n","Done.\n" if $verbose; - - - -## guess_encoding(filename) -## reads the first 20 lines of filename and looks for call of inputenc package -## if found, return the option of this package (encoding), otherwise return ascii -sub guess_encoding { - my ($filename)=@_; - my ($i,$enc); - open (FH, $filename) or die("Couldn't open $filename: $!"); - $i=0; - while () { - next if /^\s*%/; # skip comment lines - if (m/\\usepackage\[(\w*?)\]\{inputenc\}/) { - close(FH); - return($1); - } - last if (++$i > 20 ); # scan at most 20 non-comment lines - } - close(FH); - return("ascii"); -} - - -sub read_file_with_encoding { - my ($output); - my ($filename, $encoding) = @_; - - if (lc($encoding) eq "utf8" ) { - open (FILE, "<:utf8",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } elsif ( lc($encoding) eq "ascii") { - open (FILE, $filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } else { - require Encode; - open (FILE, "<",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - print STDERR "Converting $filename from $encoding to utf8\n" if $verbose; - $output=Encode::decode($encoding,$output); - } - close FILE; - if ($^O eq "linux" ) { - $output =~ s/\r\n/\n/g ; - } - return $output; -} - -# %packages=list_packages(@preamble) -# scans the arguments for \documentclass and \usepackage statements and constructs a hash -# whose keys are the included packages, and whose values are the associated optional arguments -sub list_packages { - my (@preamble)=@_; - my %packages=(); - foreach $line ( @preamble ) { - # get rid of comments - $line=~s/(?catfile($dirname,$fname), "\n" if $debug; - # content of file becomes replacement value (use recursion), add \newpage if the command was include - ###$replacement=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - $replacement=flatten(read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding), $preamble,$filename,$encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - # \include always starts a new page; use explicit \newpage command to simulate this - $begline=(defined($1)? $1 : "") ; - $newpage=(defined($3)? " \\newpage " : "") ; - "$begline$newpage$replacement$newpage"; - }/exgm; - - return($text); -} - - -# print_regex_arr(@arr) -# prints regex array without x-ism expansion put in by pearl to stdout -sub print_regex_arr { - my $dumstring; - $dumstring = join(" ",@_); # PERL generates string (?-xism:^ref$) for quoted refex ^ref$ - $dumstring =~ s/\(\?-xism:\^(.*?)\$\)/$1/g; # remove string and ^,$ marks before output - print $dumstring,"\n"; -} - - -# @lines=extrapream($type) -# reads line from appendix (end of file after __END__ token) -sub extrapream { - my $type; - my @retval=("%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - my ($copy); - - while (@_) { - $copy=0; - $type=shift ; - if ( -f $type ) { - open (FILE,$type) or die "Cannot open preamble file $type: $!"; - print STDERR "Reading preamble file $type\n" if $verbose ; - while () { - chomp ; - if ( $_ =~ m/%DIF PREAMBLE/ ) { - push (@retval,"$_"); - } else { - push (@retval,"$_ %DIF PREAMBLE"); - } - } - } - else { # not (-f $type) - $type=uc($type); # upcase argument - print STDERR "Preamble Internal Type $type\n" if $verbose; - while () { - if ( m/^%DIF $type/ ) { - $copy=1; } - elsif ( m/^%DIF END $type/ ) { - last; } - chomp; - push (@retval,"$_ %DIF PREAMBLE") if $copy; - } - if ( $copy == 0 ) { - print STDERR "\nPreamble style $type not implemented.\n"; - print STDERR "Write latexdiff -h to get help with available styles\n"; - exit(2); - } - seek DATA,0,0; # rewind DATA handle to file begin - } - } - push (@retval,"%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - return @retval; -} - - -# ($part1,$part2,$part3)=splitdoc($text,$word1,$word2) -# splits $text into 3 parts at $word1 and $word2. -# if neither $word1 nor $word2 exist, $part1 and $part3 are empty, $part2 is $text -# If only $word1 or $word2 exist but not the other, output an error message. - -# NB this version avoids $` and $' for performance reason although it only makes a tiny difference -# (in one test gain a tenth of a second for a 30s run) -sub splitdoc { - my ($text,$word1,$word2)=@_; - my ($part1,$part2,$part3)=("","",""); - my ($rest,$pos); - - if ( $text =~ m/(^[^%]*)($word1)/mg ) { - $pos=pos $text; - $part1=substr($text,0,$pos-length($2)); - $rest=substr($text,$pos); - if ( $rest =~ m/(^[^%]*)($word2)/mg ) { - $pos=pos $rest; - $part2=substr($rest,0,$pos-length($2)); - $part3=substr($rest,$pos); - } - else { - die "$word1 and $word2 not in the correct order or not present as a pair." ; - } - } else { - $part2=$text; - die "$word2 present but not $word1." if ( $text =~ m/(^[^%]*)$word2/ms ); - } - return ($part1,$part2,$part3); -} - - - - - -# bodydiff($old,$new) -sub bodydiff { - my ($oldwords, $newwords) = @_; - my @retwords; - - print STDERR "(",exetime()," s)\n","Splitting into latex tokens \n" if $verbose; - print STDERR "Parsing $oldfile \n" if $verbose; - my @oldwords = splitlatex($oldwords); - print STDERR "Parsing $newfile \n" if $verbose; - my @newwords = splitlatex($newwords); - - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - print STDERR "(",exetime()," s)\n","Pass 1: Expanding text commands and merging isolated identities with changed blocks " if $verbose; - pass1(\@oldwords, \@newwords); - - - print STDERR "(",exetime()," s)\n","Pass 2: inserting DIF tokens and mark up. " if $verbose; - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold2.tex"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew2.tex"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - @retwords=pass2(\@oldwords, \@newwords); - - return(@retwords); -} - - - - -# @words=splitlatex($string) -# split string according to latex rules -# Each element of words is either -# a word (including trailing spaces and punctuation) -# a latex command -sub splitlatex { - my ($string) = @_ ; - # if input is empty, return empty list - length($string)>0 or return (); - - my @retval=($string =~ m/$pat/osg); - - if (length($string) != length(join("",@retval))) { - print STDERR "\nWARNING: Inconsistency in length of input string and parsed string:\n This often indicates faulty or non-standard latex code.\n In many cases you can ignore this and the following warning messages.\n Note that character numbers in the following are counted beginning after \\begin{document} and are only approximate." unless $ignorewarnings; - print STDERR "DEBUG Original length ",length($string)," Parsed length ",length(join("",@retval)),"\n" if $debug; - print STDERR "DEBUG Input string: |$string|\n" if (length($string)<500) && $debug; - print STDERR "DEBUG Token parsing: |",join("+",@retval),"|\n" if (length($string)<500) && $debug ; - @retval=(); - # slow way only do this if other m//sg method fails - my $last = 0; - while ( $string =~ m/$pat/osg ) { - my $match=$&; - if ($last + length $& != pos $string ) { - my $pos=pos($string); - my $offset=30<$last ? 30 : $last; - my $dum=substr($string,$last-$offset,$pos-$last+2*$offset); - my $dum1=$dum; - my $cnt=$#retval; - my $i; - $dum1 =~ s/\n/ /g; - unless ($ignorewarnings) { - print STDERR "\n$dum1\n"; - print STDERR " " x 30,"^" x ($pos-$last)," " x 30,"\n"; - print STDERR "Missing characters near word " . (scalar @retval) . " character index: " . $last . "-" . pos($string) . " Length: " . length($match) . " Match: |$match| (expected match marked above).\n"; - } - # put in missing characters `by hand' - push (@retval, substr($dum,$offset,$pos-$last-length($match))); -# Note: there seems to be a bug in substr with utf8 that made the following line output substr which were too long, -# using dum instead appears to work -# push (@retval, substr($string,$last, pos($string)-$last-length($match))); - } - push (@retval, $match); - $last=pos $string; - } - - } - return @retval; -} - - -# pass1( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Where an common-subsequence block is flanked by deleted or appended blocks, -# and is shorter than $MINWORDSBLOCK words it is appended -# to the last deleted or appended word. If the block contains tokens other than words -# or punctuation it is not merged. -# Deleted or appended block consisting of words and safe commands only are -# also merged, to prevent break-up in pass2 (after previous isolated words have been removed) -# If there are commands with textual arguments (e.g. \caption) both in corresponding -# appended and deleted blocks split them such that the command and opening bracket -# are one token, then the rest is split up following standard rules, and the closing -# bracket is a separate token, ie. turn -# "\caption{This is a textual argument}" into -# ("\caption{","This ","is ","a ","textual ","argument","}") -# No return value. Destructively changes sequences -sub pass1 { - my $seq1 = shift ; - my $seq2 = shift ; - - my $len1 = scalar @$seq1; - my $len2 = scalar @$seq2; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - - my ($last1,$last2)=(-1,-1) ; - my $cnt=0; - my $block=[]; - my $addblock=[]; - my $delblock=[]; - my $todo=[]; - my $instruction=[]; - my $i; - my (@delmid,@addmid,@dummy); - - my ($addcmds,$delcmds,$matchindex); - my ($addtextblocks,$deltextblocks); - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $adddiscard = sub { - if ($cnt > 0 ) { - $matblkcnt++; - # just after an unchanged block -# print STDERR "Unchanged block $cnt, $last1,$last2 \n"; - if ($cnt < $MINWORDSBLOCK - && $cnt==scalar ( - grep { /^$wpat/ || ( /^\\([\w\d\*]+)((?:\[$brat0\]|\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && scalar(@dummy=split(" ",$2))<3 ) } - @$block) ) { - # merge identical blocks shorter than $MINWORDSBLOCK - # and only containing ordinary words - # with preceding different word - # We cannot carry out this merging immediately as this - # would change the index numbers of seq1 and seq2 and confuse - # the algorithm, instead we store in @$todo where we have to merge - push(@$todo, [ $last1,$last2,$cnt,@$block ]); - } - $block = []; - $cnt=0; $last1=-1; $last2=-1; - } - }; - my $discard=sub { $deltokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$delblock,[ $seq1->[$_[0]],$_[0] ]); - $last1=$_[0] }; - - my $add = sub { $addtokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$addblock,[ $seq2->[$_[1]],$_[1] ]); - $last2=$_[1] }; - - my $match = sub { $mattokcnt++; - if ($cnt==0) { # first word of matching sequence after changed sequence or at beginning of word sequence - $deltextblocks = extracttextblocks($delblock); - $delblkcnt++ if scalar @$delblock; - $addtextblocks = extracttextblocks($addblock); - $addblkcnt++ if scalar @$addblock; - - $delcmds = extractcommands($delblock); - $addcmds = extractcommands($addblock); - # keygen(third argument of _longestCommonSubsequence) implies to sort on command (0th elements of $addcmd elements) - # the calling format for longestCommonSubsequence has changed between versions of - # Algorithm::Diff so we need to check which one we are using - if ( $algodiffversion > 1.15 ) { - ### Algorithm::Diff 1.19 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, 0, sub { $_[0]->[0] } ); - } else { - ### Algorithm::Diff 1.15 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, sub { $_[0]->[0] } ); - } - - for ($i=0 ; $i<=$#$matchindex ; $i++) { - if (defined($matchindex->[$i])){ - $j=$matchindex->[$i]; - @delmid=splitlatex($delcmds->[$i][3]); - @addmid=splitlatex($addcmds->[$j][3]); - while (scalar(@$deltextblocks) && $deltextblocks->[0][0]<$delcmds->[$i][1]) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) }; - push(@$todo, [$index,-1,$cnt,@$block]); - } - push(@$todo, [ $delcmds->[$i][1],-1,-1,$delcmds->[$i][2],@delmid,$delcmds->[$i][4]]); - - while (scalar(@$addtextblocks) && $addtextblocks->[0][0]<$addcmds->[$j][1]) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - push(@$todo, [ -1,$addcmds->[$j][1],-1,$addcmds->[$j][2],@addmid,$addcmds->[$j][4]]); - } - } - # mop up remaining textblocks - while (scalar(@$deltextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) } ; - push(@$todo, [$index,-1,$cnt,@$block]); - } - while (scalar(@$addtextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - - $addblock=[]; - $delblock=[]; - } - push(@$block,$seq2->[$_[1]]); - $cnt++ }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - - - # now carry out the merging/splitting. Refer to elements relative from - # the end (with negative indices) as these offsets don't change before the instruction is executed - # cnt>0: merged small unchanged groups with previous changed blocks - # cnt==-1: split textual commands into components - foreach $instruction ( @$todo) { - ($last1,$last2,$cnt,@$block)=@$instruction ; - if ($cnt>=0) { - splice(@$seq1,$last1-$len1,1+$cnt,join("",$seq1->[$last1-$len1],@$block)) if $last1>=0; - splice(@$seq2,$last2-$len2,1+$cnt,join("",$seq2->[$last2-$len2],@$block)) if $last2>=0; - } else { - splice(@$seq1,$last1-$len1,1,@$block) if $last1>=0; - splice(@$seq2,$last2-$len2,1,@$block) if $last2>=0; - } - } - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens in $matblkcnt blocks.\n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } -} - - -# extracttextblocks(\@blockindex) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [[ $index, $textblock, $cnt ], .. -# where $index index of block to be merged -# $textblock contains all the words to be merged with the word at $index (but does not contain this word) -# $cnt is length of block -# -# requires: iscmd -# -sub extracttextblocks { - my $block=shift; - my ($i,$token,$index); - my $textblock=[]; - my $last=-1; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # store pure text blocks - if ($token =~ /$wpat/ || ( $token =~/^\\([\w\d\*]+)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && !iscmd($1,\@TEXTCMDLIST,\@TEXTCMDEXCL))) { - # we have text or a command which can be treated as text - if ($last<0) { - # new pure-text block - $last=$index; - } else { - # add to pure-text block - push(@$textblock, $token); - } - } else { - # it is not text - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - $textblock=[]; - $last=-1; - } - } - # finish processing a possibly unfinished block before returning - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - return($retval) -} - - - -# extractcommands( \@blockindex ) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [ [ "\cmd1", index, "\cmd1[optarg]{arg1}{", "arg2" ,"} " ],.. -# where index is just taken from input array -# command must have a textual argument as last argument -# -# requires: iscmd -# -sub extractcommands { - my $block=shift; - my ($i,$token,$index,$cmd,$open,$mid,$closing); - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: \cmd - # $3: last argument - # $4: } + trailing spaces - if ( ( $token =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL) ) { - # push(@$retval,[ $2,$index,$1,$3,$4 ]); - ($cmd,$open,$mid,$closing) = ($2,$1,$3,$4) ; - $closing =~ s/\}/\\RIGHTBRACE/ ; - push(@$retval,[ $cmd,$index,$open,$mid,$closing ]); - } - } - return $retval; -} - -# iscmd($cmd,\@regexarray,\@regexexcl) checks -# return 1 if $cmd matches any of the patterns in the -# array $@regexarray, and none of the patterns in \@regexexcl, otherwise return 0 -sub iscmd { - my ($cmd,$regexar,$regexexcl)=@_; - my ($ret)=0; - foreach $pat ( @$regexar ) { - if ( $cmd =~ m/^${pat}$/ ) { - $ret=1 ; - last; - } - } - return 0 unless $ret; - foreach $pat ( @$regexexcl ) { - return 0 if ( $cmd =~ m/^${pat}$/ ); - } - return 1; -} - - -# pass2( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Mark begin and end of deleted and appended sequences with tags $DELOPEN and $DELCLOSE -# and $ADDOPEN and $ADDCLOSE, respectively, however exclude { } & and all comands, unless -# they match an element of the whitelist (SAFECMD) -# For words in TEXTCMD but not in SAFECMD, enclose interior with $ADDOPEN and $ADDCLOSE brackets -# Deleted comment lines are marked with %DIF < -# Added comment lines are marked with %DIF > -sub pass2 { - my $seq1 = shift ; - my $seq2 = shift ; - - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $retval = []; - my $delhunk = []; - my $addhunk = []; - - my $discard = sub { $deltokcnt++; - push ( @$delhunk, $seq1->[$_[0]]) }; - - my $add = sub { $addtokcnt++; - push ( @$addhunk, $seq2->[$_[1]]) }; - - my $match = sub { $mattokcnt++; - if ( scalar @$delhunk ) { - $delblkcnt++; - # mark up changes, but comment out commands - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk); - $delhunk = []; - } - if ( scalar @$addhunk ) { - $addblkcnt++; - # we mark up changes, but simply quote commands - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk); - $addhunk = []; - } - push(@$retval,$seq2->[$_[1]]) }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - # clear up unprocessed hunks - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk) if scalar @$delhunk; - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk) if scalar @$addhunk; - - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens. \n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } - - return(@$retval); -} - -# marktags($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,\@block) -# returns ($openmark,$open,$block,$close,$closemark) if @block only contains no commands (except white-listed ones), -# braces, ampersands, or comments -# mark comments with $comment -# exclude all other exceptions from scope of open, close like this -# ($openmark, $open,...,$close, $opencmd,command, command,$closecmd, $open, ..., $close, $closemark) -# If $opencmd begins with "%" marktags assumes it is operating on a deleted block, otherwise on an added block -sub marktags { - my ($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,$block)=@_; - my $word; - my (@argtext); - my $retval=[]; - my $noncomment=0; - my $cmd=-1; # -1 at beginning 0: last token written is a ordinary word - # 1: last token written is a command - # for keeping track whether we are just in a command sequence or in a word sequence - my $cmdcomment= ($opencmd =~ m/^%/); # Flag to indicate whether opencmd is a comment (i.e. if we intend to simply comment out changed commands) - my ($command,$commandword,$closingbracket) ; # temporary variables needed below to remember sub-pattern matches - -# split this block to flatten out sequences joined in pass1 - @$block=splitlatex(join "",@$block); - foreach (@$block) { - $word=$_; - if ( $word =~ s/^%/%$comment/ ) { - # a comment - if ($cmd==1) { - push (@$retval,$closecmd) ; - $cmd=-1; - } - push (@$retval,$word); - next; - } - if (! $noncomment) { - push (@$retval,$openmark); - $noncomment=1; - } - # negative lookahead pattern (?!) in second clause is put in to avoid mathcing \( .. \) patterns - # also note that second pattern will match \\ - # Note: the second pattern should really be $word =~ /^\\(?!\()(\\|[\w*@]+)/, ie * replaced by + - # and then all commands \" \' etc declared safe. But as I don't have a complete list of one letter - # commands, and nobody has complained so far, I will eave this as is - if ( $word =~ /^[&{}\[\]]/ || ( $word =~ /^\\(?!\()(\\|[\w*@]*)/ && !iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL)) ) { - # word is a command or other significant token (not in SAFECMDLIST) - ## same conditions as in subroutine extractcommand: - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: cmd - # $3: last argument - # $4: } + trailing spaces - ### pre-0.3 if ( ( $token =~ m/^(\\([\w\d\*]+)(?:\[$brat0\]|\{$pat6\})*\{)($pat6)(\}\s*)$/so ) - if ( ( $word =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && (iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL)|| iscmd($2,\@MATHTEXTCMDLIST,\@MATHTEXTCMDEXCL)) - && ( !$cmdcomment || !iscmd($2,\@CONTEXT2CMDLIST, \@CONTEXT2CMDEXCL) ) ) { - # Condition 1: word is a command? - if yes, $1,$2,.. will be set as above - # Condition 2: word is a text command - we mark up the interior of the word. There is a separate check for MATHTEXTCMDLIST - # because for $mathmarkup=WHOLE, the commands should not be split in pass1 (ie. math mode commands are not in - # TEXTCMDLIST, but the interior of MATHTEXT commands should be highlighted in both deleted and added blocks - # Condition 3: But if we are in a deleted block ($cmdcomment=1) and - # $2 (the command) is in context2, just treat it as an ordinary command (i.e. comment it open with $opencmd) - # Because we do not want to disable this command - # here we do not use $opencmd and $closecmd($opencmd is empty) - if ($cmd==1) { - push (@$retval,$closecmd) ; - } elsif ($cmd==0) { - push (@$retval,$close) ; - } - $command=$1; $commandword=$2; $closingbracket=$4; - @argtext=splitlatex($3); # split textual argument into tokens - # and mark it up (but we do not need openmark and closemark) - # insert command with initial arguments, marked-up final argument, and closing bracket - if ( $cmdcomment && iscmd($commandword,\@CONTEXT1CMDLIST, \@CONTEXT1CMDEXCL) ) { - # context1cmd in a deleted environment; delete command itself but keep last argument, marked up - push (@$retval,$opencmd); - $command =~ s/\n/\n${opencmd}/sg ; # repeat opencmd at the beginning of each line - # argument, note that the additional comment character is included - # to suppress linebreak after opening parentheses, which is important - # for latexrevise - push (@$retval,$command,"%\n{$AUXCMD\n",marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } elsif ( iscmd($commandword,,\@MATHTEXTCMDLIST, \@MATHTEXTCMDEXCL) ) { - # MATHBLOCK pseudo command: consider all commands safe, except & and \\ - # Keep these commands even in deleted blocks, hence set $opencmd and $closecmd (5th and 6th argument of marktags) to - # "" - local @SAFECMDLIST=(".*"); - local @SAFECMDEXCL=('\\','\\\\'); - push(@$retval,$command,marktags("","",$open,$close,"","",$comment,\@argtext)#@argtext - ,$closingbracket); - } else { - # normal textcmd or context1cmd in an added block - push (@$retval,$command,marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } - push (@$retval,$AUXCMD,"\n") if $cmdcomment ; - $cmd=-1 ; - } else { - # ordinary command - push (@$retval,$opencmd) if $cmd==-1 ; - push (@$retval,$close,$opencmd) if $cmd==0 ; - $word =~ s/\n/\n${opencmd}/sg if $cmdcomment ; # if opencmd is a comment, repeat this at the beginning of every line - push (@$retval,$word); - $cmd=1; - } - } else { - # just an ordinary word or word in SAFECMD - push (@$retval,$open) if $cmd==-1 ; - push (@$retval,$closecmd,$open) if $cmd==1 ; - push (@$retval,$word); - $cmd=0; - } - } - push (@$retval,$close) if $cmd==0; - push (@$retval,$closecmd) if $cmd==1; - - push (@$retval,$closemark) if ($noncomment); - return @$retval; -} - -# preprocess($string, ..) -# carry out the following pre-processing steps for all arguments: -# 1. Remove leading white-space -# Change \{ to \LEFTBRACE and \} to \RIGHTBRACE -# #. change begin and end commands within comments to BEGINDIF, ENDDIF -# so they don't disturb the pattern matching (if there are several \begin or \end in one line -# 2. mark all first empty line (in block of several) with \PAR tokens -# 3. Convert all '\%' into '\PERCENTAGE ' to make parsing regular expressions easier -# 4. Convert all \verb|some verbatim text| commands (where | can be an arbitrary character) -# into \verb{hash} -# 5. Convert \begin{verbatim} some verbatim text \end{verbatim} into \verbatim{hash} -# 6. Convert _n into \SUBSCRIPTNB{n} and _{nnn} into \SUBSCRIPT{nn} -# 7. Convert ^n into \SUPERSCRIPTNB{n} and ^{nnn} into \SUPERSCRIPT{nn} -# 8. a. Convert $$ $$ into \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} -# b. Convert \[ \] into \begin{SQUAREBRACKET} \end{SQUAREBRACKET} -# 9. Convert all picture environmentent (\begin{PICTUREENV} .. \end{PICTUREENV} \PICTUREBLOCKenv -# For --block-math-markup option -convert all \begin{MATH} .. \end{MATH} -# into \MATHBLOCKmath{...} commands, where MATH/math is any valid math environment - -# 10. Add final token STOP to the very end. This is put in because the algorithm works better if the last token is identical. This is removed again in postprocessing. -# -# NB: step 6 and 7 is likely to convert some "_" inappropriately, e.g. in file -# names or labels but it does not matter because they are converted back in the postprocessing step -# Returns: leading white space removed in step 1 -sub preprocess { - my @leadin=() ; - for (@_) { - s/^(\s*)//s; - push(@leadin,$1); - # Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE - s/(?{$hstr}) && $string ne $hash->{$hstr}) { - warn "Repeated hash value for verbatim mode in spite of different content."; - $hstr="-$hstr"; - } - $hash->{$hstr}=$string; - return($hstr); -} - -#string=fromhash(\%hash,$fromstring) -# restores string value stored in hash -#string=fromhash(\%hash,$fromstring,$prependstring) -# additionally begins each line with prependstring -sub fromhash { - my ($hash,$hstr)=($_[0],$_[1]); - my $retstr=$hash->{$hstr}; - if ( $#_ >= 2) { - $retstr =~ s/^/$_[2]/mg; - } - return $retstr; -} - - -# postprocess($string, ..) -# carry out the following post-processing steps for all arguments: -# * Remove STOP token from the end -# * Replace \RIGHTBRACE by } -# * change citation commands within comments to protect from processing (using marker CITEDIF) -# 1. Check all deleted blocks: -# a.where a deleted block contains a matching \begin and -# \end environment (these will be disabled by a %DIFDELCMD statements), for selected environments enable -# these commands again (such that for example displayed math in a deleted equation -# is properly within math mode. For math mode environments replace numbered equation -# environments with their display only variety (so that equation numbers in new file and -# diff file are identical). Where the correct type of math environment cannot be determined -# use a place holder MATHMODE -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file -# Replace all MATHMODE environment commands by the correct environment to achieve matching -# pairs -# c. Convert MATHBLOCKmath commands to their uncounted numbers (e.g. convert equation -> displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL -# d. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# For added blocks: -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# 2. If --block-math-markup option set: Convert \MATHBLOCKmath{..} commands back to environments -# -# Convert all PICTUREblock{..} commands back to the appropriate environments -# 3. Convert DIFadd, DIFdel, DIFFaddbegin , ... into FL varieties -# within floats (currently recognised float environments: plate,table,figure -# plus starred varieties). -# 4. Remove empty %DIFDELCMD < lines -# 4. Convert \begin{SQUAREBRACKET} \end{SQUAREBRACKET} into \[ \] -# Convert \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} into $$ $$ -# 5. Convert \SUPERSCRIPTNB{n} into ^n and \SUPERSCRIPT{nn} into ^{nnn} -# 6. Convert \SUBSCRIPTNB{n} into _n and \SUBCRIPT{nn} into _{nnn} -# 7. Expand hashes of verb and verbatim environments -# 8. Convert '\PERCENTAGE ' back into '\%' -# 9.. remove all \PAR tokens -# 10. package specific processing: endfloat: make sure \begin{figure} and \end{figure} are always -# on a line by themselves, similarly for table environment -# 4, undo renaming of the \begin and \end in comments -# Change \QLEFTBRACE, \QRIGHTBRACE to \{,\} -# -# Note have to manually synchronize substitution commands below and -# DIF.. command names in the header -sub postprocess { - my ($begin,$len,$cnt,$float,$delblock,$addblock); - # second level blocks - my ($begin2,$cnt2,$len2,$eqarrayblock,$mathblock); - - for (@_) { - - # change $'s in comments to something harmless - 1 while s/(%.*)\$/$1DOLLARDIF/mg ; - - # Remove final STOP token - s/ STOP$//; - # Replace \RIGHTBRACE by } - s/\\RIGHTBRACE/}/g; - - # change citation commands within comments to protect from processing - if ($CITECMD){ - 1 while s/(%.*)\\($CITECMD)/$1\\CITEDIF$2/m ; - } - # Check all deleted blocks: where a deleted block contains a matching \begin and - # \end environment (these will be disabled by a %DIFDELCMD statements), enable - # these commands again (such that for example displayed math in a deleted equation - # is properly within math mode. For math mode environments replace numbered equation - # environments with their display only variety (so that equation numbers in new file and - # diff file are identical - while ( m/\\DIFdelbegin.*?\\DIFdelend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $delblock=$&; - - - ### (.*?[^\n]?)\n? construct is necessary to avoid empty lines in math mode, which result in - ### an error - # displayed math environments - if ($mathmarkup == FINE ) { - $delblock=~ s/(\%DIFDELCMD < \s*\\begin\{((?:$MATHENV)|SQUAREBRACKET)\}.*?(?:$DELCMDCLOSE|\n))(.*?[^\n]?)\n?(\%DIFDELCMD < \s*\\end\{\2\})/\\begin{$MATHREPL}$AUXCMD\n$1$3\n\\end{$MATHREPL}$AUXCMD\n$4/sg; - # also transform the opposite pair \end{displaymath} .. \begin{displaymath} but we have to be careful not to interfere with the results of the transformation in the line directly above - ### pre-0.42 obsolete version which did not work on eqnarray test $delblock=~ s/(? displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL - $delblock=~ s/\\MATHBLOCK($MATHENV)\{($pat6)\}/\\MATHBLOCK$MATHREPL\{$2\}/sg; - $delblock=~ s/\\MATHBLOCK($MATHARRENV)\{($pat6)\}/\\MATHBLOCK$MATHARRREPL\{$2\}/sg; - } - - -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file - $delblock=~ s/\\($COUNTERCMD)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*\s*${AUXCMD}\n)/\\$1$2\\addtocounter{$1}{-1}${AUXCMD}\n/sg ; - - -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es - while ( $delblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($delblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($delblock,$begin2,$len2)=$mathblock; - pos($delblock) = $begin2 + length($mathblock); - } - if ($CITE2CMD) { - $delblock=~s/($DELCMDOPEN\s*\\($CITE2CMD)(.*)$DELCMDCLOSE)/ - # Replacement code - {my ($aux,$all); - $aux=$all=$1; - $aux=~s#\n?($DELCMDOPEN|$DELCMDCLOSE)##g; - $all."$aux$AUXCMD\n";}/sge; - } - # or protect \cite commands with \mbox - if ($CITECMD) { - $delblock=~s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat6\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified delblock - substr($_,$begin,$len)=$delblock; - pos = $begin + length($delblock); - } - # make the array modification in added blocks - while ( m/\\DIFaddbegin.*?\\DIFaddend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $addblock=$&; - while ( $addblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($addblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($addblock,$begin2,$len2)=$mathblock; - pos($addblock) = $begin2 + length($mathblock); - } - if ($CITECMD) { - my $addblockbefore=$addblock; - $addblock=~ s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat2\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified addblock - substr($_,$begin,$len)=$addblock; - pos = $begin + length($addblock); - } - - - ### old place for BEGINDIF, ENDDIF replacement - # change begin and end commands within comments such that they - # don't disturb the pattern matching (if there are several \begin or \end in one line - # this substitution is insufficient but that appears unlikely) - # This needs to be repeated here to also get rid of DIFdelcmd-protected environments - s/(%.*)\\begin\{(.*)$/$1\\BEGINDIF\{$2/mg ; - s/(%.*)\\end\{(.*)$/$1\\ENDDIF\{$2/mg ; - - # Replace MATHMODE environments from step 1a above by the correct Math environment - - # The next line is complicated. The negative look-ahead insertion makes sure that no \end{$MATHENV} (or other mathematical - # environments) are between the \begin{$MATHENV} and \end{MATHMODE} commands. This is necessary as the minimal matching - # is not globally minimal but only 'locally' (matching is beginning from the left side of the string) - if ( $mathmarkup == FINE ) { - 1 while s/\\begin{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}((?:.(?!(?:\\end{(?:(?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}|\\begin{MATHMODE})))*?)\\end{MATHMODE}/\\begin{$1}$2\\end{$1}/s; - 1 while s/\\begin{MATHMODE}((?:.(?!\\end{MATHMODE}))*?)\\end{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}/\\begin{$2}$1\\end{$2}/s; - # convert remaining \begin{MATHMODE} \end{MATHMODE} (and not containing & or \\ )into MATHREPL environments - s/\\begin{MATHMODE}((?:(.(?!(?[1])) { - $optargnew=$newhash{$cmd}->[1]; - } else { - $optargnew=""; - } - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - } else { - $optargold=""; - } - - if ( defined($oldhash{$cmd}) ) { - $argold=$oldhash{$cmd}->[2]; - } else { - $argold=""; - } - $argnew=$newhash{$cmd}->[2]; - $argdiff="{" . join("",bodydiff($argold,$argnew)) ."}"; - if ( length $optargnew ) { - $optargdiff="[".join("",bodydiff($optargold,$optargnew))."]" ; - $optargdiff =~ s/\\DIFaddbegin /\\DIFaddbeginFL /g; - $optargdiff =~ s/\\DIFaddend /\\DIFaddendFL /g; - $optargdiff =~ s/\\DIFadd\{/\\DIFaddFL{/g; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - ### print STDERR "DEBUG s/\\Q$newhash{$cmd}->[0]\\E/\\$cmd$optargdiff$argdiff/s\n"; - # Note: \Q and \E force literal interpretation of what it between them but allow - # variable interpolation, such that e.g. \title matches just that and not TAB-itle - $$newpreambleref=~s/\Q$newhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s; - # replace this in old preamble if necessary - if ( defined($oldhash{$cmd}->[0])) { - $$oldpreambleref=~s/\Q$oldhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s ; - } - ### print STDERR "DEBUG NEW PRE ".$$newpreambleref."\n"; - } - - foreach $cmd ( keys %oldhash ) { - # if this has already been dealt with above can just skip - next if defined($newhash{$cmd}) ; - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - $optargdiff="[".join("",bodydiff($optargold,""))."]" ; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - $argdiff="{" . join("",bodydiff($argold,"")) ."}"; - $auxline = "\\$cmd$optargdiff$argdiff"; - $auxline =~s/$/$AUXCMD/sg; - push @auxlines,$auxline; - } - # add auxcmd comment to highlight added lines - return(@auxlines); -} - - - -# @diffs=linediff(\@seq1, \@seq2) -# mark up lines like this -#%DIF mm-mmdnn -#%< old deleted line(s) -#%DIF ------- -#%DIF mmann-nn -#new appended line %< -#%DIF ------- -# Future extension: mark change explicitly -# Assumes: traverse_sequence traverses deletions before insertions in changed sequences -# all line numbers relative to line 0 (first line of real file) -sub linediff { - my $seq1 = shift ; - my $seq2 = shift ; - - my $block = []; - my $retseq = []; - my @begin=('','',''); # dummy initialisation - my $instring ; - - my $discard = sub { @begin=('d',$_[0],$_[1]) unless scalar @$block ; - push(@$block, "%DIF < " . $seq1->[$_[0]]) }; - my $add = sub { if (! scalar @$block) { - @begin=('a',$_[0],$_[1]) ;} - elsif ( $begin[0] eq 'd' ) { - $begin[0]='c'; $begin[2]=$_[1]; - push(@$block, "%DIF -------") } - push(@$block, $seq2->[$_[1]] . " %DIF > " ) }; - my $match = sub { if ( scalar @$block ) { - if ( $begin[0] eq 'd' && $begin[1]!=$_[0]-1) { - $instring = sprintf "%%DIF %d-%dd%d",$begin[1],$_[0]-1,$begin[2]; } - elsif ( $begin[0] eq 'a' && $begin[2]!=$_[1]-1) { - $instring = sprintf "%%DIF %da%d-%d",$begin[1],$begin[2],$_[1]-1; } - elsif ( $begin[0] eq 'c' ) { - $instring = sprintf "%%DIF %sc%s", - ($begin[1]==$_[0]-1) ? "$begin[1]" : $begin[1]."-".($_[0]-1) , - ($begin[2]==$_[1]-1) ? "$begin[2]" : $begin[2]."-".($_[1]-1) ; } - else { - $instring = sprintf "%%DIF %d%s%d",$begin[1],$begin[0],$begin[2]; } - push @$retseq, $instring,@$block, "%DIF -------" ; - $block = []; - } - push @$retseq, $seq2->[$_[1]] - }; - # key function: remove multiple spaces (such that insertion or deletion of redundant white space is not reported) - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - push @$retseq, @$block if scalar @$block; - - return wantarray ? @$retseq : $retseq ; -} - - - -# init_regex_arr_data(\@array,"TOKEN INIT") -# scans DATA file handel for line "%% TOKEN INIT" line -# then appends each line not beginning with % into array (as a quoted regex) -sub init_regex_arr_data { - my ($arr,$token)=@_; - my ($copy); - while () { - if ( m/^%%BEGIN $token\s*$/ ) { - $copy=1; } - elsif ( m/^%%END $token\s*/ ) { - last; } - chomp; - push (@$arr,qr/^$_$/) if ( $copy && !/^%/ ) ; - } - seek DATA,0,0; # rewind DATA handle to file begin -} - - -# init_regex_arr_ext(\@array,$arg) -# fills array with regular expressions. -# if arg is a file name, then read in list of regular expressions from that file -# (one expression per line) -# Otherwise treat arg as a comma separated list of regular expressions -sub init_regex_arr_ext { - my ($arr,$arg)=@_; - my $regex; - if ( -f $ arg ) { - open(FILE,"$arg") or die ("Couldn't open $arg: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@$arr,qr/^$_$/); - } - close(FILE); - } - else { - # assume it is a comma-separated list of reg-ex - foreach $regex (split(qr/(?=1) { - $reset=shift; - } - if ($reset) { - $lasttime=times(); - } - else { - $retval=times()-$lasttime; - $lasttime=$lasttime+$retval; - return($retval); - } -} - - -sub usage { - die <<"EOF"; -Usage: $0 [options] old.tex new.tex > diff.tex - -Compares two latex files and writes tex code to stdout, which has the same -format as new.tex but has all changes relative to old.tex marked up or commented. - ---type=markupstyle --t markupstyle Add code to preamble for selected markup style - Available styles: UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE - CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR - [ Default: UNDERLINE ] - ---subtype=markstyle --s markstyle Add code to preamble for selected style for bracketing - commands (e.g. to mark changes in margin) - Available styles: SAFE MARGINAL DVIPSCOL COLOR - [ Default: SAFE ] - ---floattype=markstyle --f markstyle Add code to preamble for selected style which - replace standard marking and markup commands within floats - (e.g., marginal remarks cause an error within floats - so marginal marking can be disabled thus) - Available styles: FLOATSAFE IDENTICAL - [ Default: FLOATSAFE ] - ---encoding=enc --e enc Specify encoding of old.tex and new.tex. Typical encodings are - ascii, utf8, latin1, latin9. A list of available encodings can be - obtained by executing - perl -MEncode -e 'print join ("\\n",Encode->encodings( ":all" )) ;' - [Default encoding is utf8 unless the first few lines of the preamble contain - an invocation "\\usepackage[..]{inputenc} in which case the - encoding chosen by this command is asssumed. Note that ASCII (standard - latex) is a subset of utf8] - ---preamble=file --p file Insert file at end of preamble instead of auto-generating - preamble. The preamble must define the following commands - \\DIFaddbegin,\\DIFaddend,\\DIFadd{..}, - \\DIFdelbegin,\\DIFdelend,\\DIFdel{..}, - and varieties for use within floats - \\DIFaddbeginFL,\\DIFaddendFL,\\DIFaddFL{..}, - \\DIFdelbeginFL,\\DIFdelendFL,\\DIFdelFL{..} - (If this option is set -t, -s, and -f options - are ignored.) - ---exclude-safecmd=exclude-file ---exclude-safecmd="cmd1,cmd2,..." --A exclude-file ---replace-safecmd=replace-file ---append-safecmd=append-file ---append-safecmd="cmd1,cmd2,..." --a append-file Exclude from, replace or append to the list of regex - matching commands which are safe to use within the - scope of a \\DIFadd or \\DIFdel command. The file must contain - one Perl-RegEx per line (Comment lines beginning with # or % are - ignored). A literal comma within the comma-separated list must be - escaped thus "\\,", Note that the RegEx needs to match the whole of - the token, i.e., /^regex\$/ is implied and that the initial - "\\" of the command is not included. The --exclude-safecmd - and --append-safecmd options can be combined with the --replace-safecmd - option and can be used repeatedly to add cumulatively to the lists. - ---exclude-textcmd=exclude-file ---exclude-textcmd="cmd1,cmd2,..." --X exclude-file ---replace-textcmd=replace-file ---append-textcmd=append-file ---append-textcmd="cmd1,cmd2,..." --x append-file Exclude from, replace or append to the list of regex - matching commands whose last argument is text. See - entry for --exclude-safecmd directly above for further details. - ---replace-context1cmd=replace-file ---append-context1cmd=append-file ---append-context1cmd="cmd1,cmd2,..." - Replace or append to the list of regex matching commands - whose last argument is text but which require a particular - context to work, e.g. \\caption will only work within a figure - or table. These commands behave like text commands, except when - they occur in a deleted section, when they are disabled, but their - argument is shown as deleted text. - ---replace-context2cmd=replace-file ---append-context2cmd=append-file ---append-context2cmd="cmd1,cmd2,..." - As corresponding commands for context1. The only difference is that - context2 commands are completely disabled in deleted sections, including - their arguments. - - ---config var1=val1,var2=val2,... --c var1=val1,.. Set configuration variables. --c configfile Available variables: - MINWORDSBLOCK (integer) - FLOATENV (RegEx) - PICTUREENV (RegEx) - MATHENV (RegEx) - MATHREPL (String) - MATHARRENV (RegEx) - MATHARRREPL (String) - ARRENV (RegEx) - COUNTERCMD (RegEx) - This option can be repeated. - - ---packages=pkg1,pkg2,.. - Tell latexdiff that .tex file is processed with the packages in list - loaded. This is normally not necessary if the .tex file includes the - preamble, as the preamble is automatically scanned for \\usepackage commands. - Use of the --packages option disables automatic scanning, so if for any - reason package specific parsing needs to be switched off, use --packages=none. - The following packages trigger special behaviour: - endfloat hyperref amsmath - [ Default: scan the preamble for \\usepackage commands to determine - loaded packages.] - ---show-preamble Print generated or included preamble commands to stdout. - ---show-safecmd Print list of regex matching and excluding safe commands. - ---show-textcmd Print list of regex matching and excluding commands with text argument. - ---show-config Show values of configuration variables - ---show-all Show all of the above - - NB For all --show commands, no old.tex or new.tex file needs to be given, and no - differencing takes place. - -Other configuration options: - ---allow-spaces Allow spaces between bracketed or braced arguments to commands - [Default requires arguments to directly follow each other without - intervening spaces] - ---math-markup=level Determine granularity of markup in displayed math environments: - Possible values for level are (both numerical and text labels are acceptable): - off or 0: suppress markup for math environments. Deleted equations will not - appear in diff file. This mode can be used if all the other modes - cause invalid latex code. - whole or 1: Differencing on the level of whole equations. Even trivial changes - to equations cause the whole equation to be marked changed. This - mode can be used if processing in coarse or fine mode results in - invalid latex code. - coarse or 2: Detect changes within equations marked up with a coarse - granularity; changes in equation type (e.g.displaymath to equation) - appear as a change to the complete equation. This mode is recommended - for situations where the content and order of some equations are still - being changed. [Default] - fine or 3: Detect small change in equations and mark up and fine granularity. - This mode is most suitable, if only minor changes to equations are - expected, e.g. correction of typos. - ---disable-citation-markup Suppress citation markup in styles using ulem (UNDERLINE, - FONTSTRIKE, CULINECHBAR) ---enable-citation-markup Protect citation commands in changed sections with \\mbox command - [i.e. use default behaviour for ulem package for other packages] - - -Miscelleneous options - ---label=label --L label Sets the labels used to describe the old and new files. The first use - of this option sets the label describing the old file and the second - use of the option sets the label for the new file. - [Default: use the filename and modification dates for the label] - ---no-label Suppress inclusion of old and new file names as comment in output file - ---visble-label Include old and new filenames (or labels set with --label option) as - visible output - ---flatten Replace \\input and \\include commands within body by the content - of the files in their argument. If \\includeonly is present in the - preamble, only those files are expanded into the document. However, - no recursion is done, i.e. \\input and \\include commands within - included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, - respectively, making it possible to organise files into old and new directories. - --flatten is applied recursively, so inputted files can contain further - \\input statements. - ---help --h Show this help text. - ---ignore-warnings Suppress warnings about inconsistencies in length between input - and parsed strings and missing characters. - ---verbose --V Output various status information to stderr during processing. - Default is to work silently. - ---version Show version number. - -EOF -} - -=head1 NAME - -latexdiff - determine and markup differences between two latex files - -=head1 SYNOPSIS - -B [ B ] F F > F - -=head1 DESCRIPTION - -Briefly, I is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called C and C, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. - -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "S>>" is appended to each added line, i.e. a -line present in C but not in C. Discarded lines - are deactivated by prepending "S>>". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file C will be similar to -C. At the end of the preamble, the definitions for I markup commands are inserted. -In differencing the main body of the text, I attempts to -satisfy the following guidelines (in order of priority): - -=over 3 - -=item 1 - -If both C and C are valid LaTeX, then the resulting -C should also be valid LateX. (NB If a few plain TeX commands -are used within C or C then C is not -guaranteed to work but usually will). - -=item 2 - -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -C. - -=item 3 - -If a changed passage contains text or text-producing commands, then -running C through LateX should produce output where added -and discarded passages are highlighted. - -=item 4 - -Where there are insignificant differences, e.g. in the positioning of -line breaks, C should follow the formatting of C - -=back - -For differencing the same algorithm as I is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, C<\caption> and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write - - \section{\textem{This is an emphasized section title}} - -and not - - \section {\textem{This is an emphasized section title}} - -or - - \section\textem{This is an emphasized section title} - -even though all varieties are the same to LaTeX (but see -B<--allow-spaces> option which allows the second variety). - -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the PICTUREENV configuration variable, set by -default to C and C environments; see B<--config> -option). The latter environment (C) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by C<\begin{DIFnomarkup}> and C<\end{DIFnomarkup}>. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, - -C<\newenvironment{DIFnomarkup}{}{}> - -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. - -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. - -All markup commands inserted by I begin with "C<\DIF>". Added -blocks containing words, commands or comments which are in C -but not in C are marked by C<\DIFaddbegin> and C<\DIFaddend>. -Discarded blocks are marked by C<\DIFdelbegin> and C<\DIFdelend>. -Within added blocks all text is highlighted with C<\DIFadd> like this: -C<\DIFadd{Added text block}> -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces "{" and "}" are never put within -the scope of C<\DIFadd>. Added comments are marked by prepending -"S >>". - -Within deleted blocks text is highlighted with C<\DIFdel>. Deleted -comments are marked by prepending "S >>". Non-safe command -and curly braces within deleted blocks are commented out with -"S >>". - - - -=head1 OPTIONS - -=head2 Preamble - -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. - -=over 4 - -=item B<--type=markupstyle> or -B<-t markupstyle> - -Add code to preamble for selected markup style. This option defines -C<\DIFadd> and C<\DIFdel> commands. -Available styles: - -C - -[ Default: C ] - -=item B<--subtype=markstyle> or -B<-s markstyle> - -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -C<\DIFaddbegin>, C<\DIFaddend>, C<\DIFdelbegin> and C<\DIFdelend> commands. -Available styles: C - -[ Default: C ] - -=item B<--floattype=markstyle> or -B<-f markstyle> - -Add code to preamble for selected style which -replace standard marking and markup commands within floats -(e.g., marginal remarks cause an error within floats -so marginal marking can be disabled thus). This option defines all -C<\DIF...FL> commands. -Available styles: C - -[ Default: C ] - -=item B<--encoding=enc> or -B<-e enc> - -Specify encoding of old.tex and new.tex. Typical encodings are -C, C, C, C. A list of available encodings can be -obtained by executing - -Cencodings( ":all" )) ;' > - -[Default encoding is utf8 unless the first few lines of the preamble contain -an invocation C<\usepackage[..]{inputenc}> in which case the -encoding chosen by this command is asssumed. Note that ASCII (standard -latex) is a subset of utf8] - -=item B<--preamble=file> or -B<-p file> - -Insert file at end of preamble instead of generating -preamble. The preamble must define the following commands -C<\DIFaddbegin, \DIFaddend, \DIFadd{..}, -\DIFdelbegin,\DIFdelend,\DIFdel{..},> -and varieties for use within floats -C<\DIFaddbeginFL, \DIFaddendFL, \DIFaddFL{..}, -\DIFdelbeginFL, \DIFdelendFL, \DIFdelFL{..}> -(If this option is set B<-t>, B<-s>, and B<-f> options -are ignored.) - -=item B<--packages=pkg1,pkg2,..> - -Tell latexdiff that .tex file is processed with the packages in list -loaded. This is normally not necessary if the .tex file includes the -preamble, as the preamble is automatically scanned for C<\usepackage> commands. -Use of the B<--packages> option disables automatic scanning, so if for any -reason package specific parsing needs to be switched off, use B<--packages=none>. -The following packages trigger special behaviour: - -=over 8 - -=item C - -Configuration variable amsmath is set to C (Default: C) - -=item C - -Ensure that C<\begin{figure}> and C<\end{figure}> always appear by themselves on a line. - -=item C - -Change name of C<\DIFadd> and C<\DIFdel> commands to C<\DIFaddtex> and C<\DIFdeltex> and -define new C<\DIFadd> and C<\DIFdel> commands, which provide a wrapper for these commands, -using them for the text but not for the link defining command (where any markup would cause -errors). - -=back - -[ Default: scan the preamble for C<\\usepackage> commands to determine - loaded packages.] - - - -=item B<--show-preamble> - -Print generated or included preamble commands to stdout. - -=back - -=head2 Configuration - -=over 4 - -=item B<--exclude-safecmd=exclude-file> or -B<-A exclude-file> or B<--exclude-safecmd="cmd1,cmd2,..."> - -=item B<--replace-safecmd=replace-file> - -=item B<--append-safecmd=append-file> or -B<-a append-file> or B<--append-safecmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions (RegEx) -matching commands which are safe to use within the -scope of a C<\DIFadd> or C<\DIFdel> command. The file must contain -one Perl-RegEx per line (Comment lines beginning with # or % are -ignored). Note that the RegEx needs to match the whole of -the token, i.e., /^regex$/ is implied and that the initial -"\" of the command is not included. -The B<--exclude-safecmd> and B<--append-safecmd> options can be combined with the -B<--replace-safecmd> -option and can be used repeatedly to add cumulatively to the lists. - B<--exclude-safecmd> -and B<--append-safecmd> can also take a comma separated list as input. If a -comma for one of the regex is required, escape it thus "\,". In most cases it -will be necessary to protect the comma-separated list from the shell by putting -it in quotation marks. - -=item B<--exclude-textcmd=exclude-file> or -B<-X exclude-file> or B<--exclude-textcmd="cmd1,cmd2,..."> - -=item B<--replace-textcmd=replace-file> - -=item B<--append-textcmd=append-file> or -B<-x append-file> or B<--append-textcmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions -matching commands whose last argument is text. See -entry for B<--exclude-safecmd> directly above for further details. - - -=item B<--replace-context1cmd=replace-file> - -=item B<--append-context1cmd=append-file> or -=item B<--append-context1cmd="cmd1,cmd2,..."> - -Replace or append to the list of regex matching commands -whose last argument is text but which require a particular -context to work, e.g. \caption will only work within a figure -or table. These commands behave like text commands, except when -they occur in a deleted section, when they are disabled, but their -argument is shown as deleted text. - -=item B<--replace-context2cmd=replace-file> - -=item B<--append-context2cmd=append-file> or -=item B<--append-context2cmd="cmd1,cmd2,..."> -As corresponding commands for context1. The only difference is that -context2 commands are completely disabled in deleted sections, including -their arguments. - - - -=item B<--config var1=val1,var2=val2,...> or B<-c var1=val1,..> - -=item B<-c configfile> - -Set configuration variables. The option can be repeated to set different -variables (as an alternative to the comma-separated list). -Available variables (see below for further explanations): - -C (integer) - -C (RegEx) - -C (RegEx) - -C (RegEx) - -C (String) - -C (RegEx) - -C (String) - -C (RegEx) - -C (RegEx) - -=item B<--show-safecmd> - -Print list of RegEx matching and excluding safe commands. - -=item B<--show-textcmd> - -Print list of RegEx matching and excluding commands with text argument. - -=item B<--show-config> - -Show values of configuration variables. - -=item B<--show-all> - -Combine all --show commands. - -NB For all --show commands, no C or C file needs to be specified, and no -differencing takes place. - -=back - -=head2 Other configuration options: - -=over 4 - -=item B<--allow-spaces> - -Allow spaces between bracketed or braced arguments to commands. Note -that this option might have undesirable side effects (unrelated scope -might get lumpeded with preceding commands) so should only be used if the -default produces erroneous results. (Default requires arguments to -directly follow each other without intervening spaces). - -=item B<--math-markup=level> - -Determine granularity of markup in displayed math environments: -Possible values for level are (both numerical and text labels are acceptable): - -C or C<0>: suppress markup for math environments. Deleted equations will not -appear in diff file. This mode can be used if all the other modes -cause invalid latex code. - -C or C<1>: Differencing on the level of whole equations. Even trivial changes -to equations cause the whole equation to be marked changed. This -mode can be used if processing in coarse or fine mode results in -invalid latex code. - -C or C<2>: Detect changes within equations marked up with a coarse -granularity; changes in equation type (e.g.displaymath to equation) -appear as a change to the complete equation. This mode is recommended -for situations where the content and order of some equations are still -being changed. [Default] -C or C<3>: Detect small change in equations and mark up and fine granularity. -This mode is most suitable, if only minor changes to equations are -expected, e.g. correction of typos. - -=item B<--disable-citation-markup> - -Suppress citation markup in styles using ulem (UNDERLINE, -FONTSTRIKE, CULINECHBAR) - -=item B<--enable-citation-markup> - -Protect citation commands in changed sections with \\mbox command [i.e. use default behaviour for ulem package for other packages] - -=back - -=head2 Miscellaneous - -=over 4 -=item B<--verbose> or B<-V> - -Output various status information to stderr during processing. -Default is to work silently. - -=item B<--driver=type> - -Choose driver for changebar package (only relevant for styles using - changebar: CCHANGEBAR CFONTCHBAR CULINECHBAR CHANGEBAR). Possible -drivers are listed in changebar manual, e.g. pdftex,dvips,dvitops - [Default: dvips] - -=item B<--ignore-warnings> - -Suppress warnings about inconsistencies in length between input and -parsed strings and missing characters. These warning messages are -often related to non-standard latex or latex constructions with a -syntax unknown to C but the resulting difference argument -is often fully functional anyway, particularly if the non-standard -latex only occurs in parts of the text which have not changed. - -=item B<--label=label> or -B<-L label> - -Sets the labels used to describe the old and new files. The first use -of this option sets the label describing the old file and the second -use of the option sets the label for the new file, i.e. set both -labels like this C<-L labelold -L labelnew>. -[Default: use the filename and modification dates for the label] - -=item B<--no-label> - -Suppress inclusion of old and new file names as comment in output file - -=item B<--visble-label> - -Include old and new filenames (or labels set with --label option) as -visible output. - -=item B<--flatten> - -Replace C<\input> and C<\include> commands within body by the content -of the files in their argument. If C<\includeonly> is present in the -preamble, only those files are expanded into the document. However, -no recursion is done, i.e. C<\input> and C<\include> commands within -included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, -respectively, making it possible to organise files into old and new directories. ---flatten is applied recursively, so inputted files can contain further -C<\input> statements. - -Use of this option might result in prohibitive processing times for -larger documents, and the resulting difference document -no longer reflects the structure of the input documents. - -=item B<--help> or -B<-h> - -Show help text - -=item B<--version> - -Show version number - -=back - - - -=head2 Predefined styles - -=head2 Major types - -The major type determine the markup of plain text and some selected latex commands outside floats by defining the markup commands C<\DIFadd{...}> and C<\DIFdel{...}> . - -=over 10 - -=item C - -Added text is wavy-underlined and blue, discarded text is struck out and red -(Requires color and ulem packages). Overstriking does not work in displayed math equations such that deleted parts of equation are underlined, not struck out (this is a shortcoming inherent to the ulem package). - -=item C - -Added text is blue and set in sans-serif, and a red footnote is created for each discarded -piece of text. (Requires color package) - -=item C - -Like C but without the use of color. - -=item C - -Added text is blue and set in sans-serif, and discarded text is red and very small size. - -=item C - -Added tex is set in sans-serif, discarded text small and struck out - -=item C - -Added text is blue, and discarded text is red. Additionally, the changed text is marked with a bar in the margin (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color, ulem and changebar packages). - -=item C - -No mark up of text, but mark margins with changebars (Requires changebar package). - -=item C - -No visible markup (but generic markup commands will still be inserted. - -=back - -=head2 Subtypes - -The subtype defines the commands that are inserted at the begin and end of added or discarded blocks, irrespectively of whether these blocks contain text or commands (Defined commands: C<\DIFaddbegin, \DIFaddend, \DIFdelbegin, \DIFdelend>) - -=over 10 - -=item C - -No additional markup (Recommended choice) - -=item C - -Mark beginning and end of changed blocks with symbols in the margin nearby (using -the standard C<\marginpar> command - note that this sometimes moves somewhat -from the intended position. - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. -(It is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete, for example -with citation commands). - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. Note -that C only works with the dvips converter, e.g. not pdflatex. -(it is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete). - -=back - -=head2 Float Types - -Some of the markup used in the main text might cause problems when used within -floats (e.g. figures or tables). For this reason alternative versions of all -markup commands are used within floats. The float type defines these alternative commands. - -=over 10 - -=item C - -Use identical markup for text as in the main body, but set all commands marking the begin and end of changed blocks to null-commands. You have to choose this float type if your subtype is C as C<\marginpar> does not work properly within floats. - -=item C - -Mark additions the same way as in the main text. Deleted environments are marked by angular brackets \[ and \] and the deleted text is set in scriptscript size. This float type should always be used with the C and C markup types as the \footnote command does not work properly in floating environments. - -=item C - -Make no difference between the main text and floats. - -=back - - -=head2 Configuration Variables - -=over 10 - -=item C - -Minimum number of tokens required to form an independent block. This value is -used in the algorithm to detect changes of complete blocks by merging identical text parts of less than C to the preceding added and discarded parts. - -[ Default: 3 ] - -=item C - -Environments whose name matches the regular expression in C are -considered floats. Within these environments, the I markup commands -are replaced by their FL variaties. - -[ Default: S >] - -=item C - -Within environments whose name matches the regular expression in C -all latexdiff markup is removed (in pathologic cases this might lead to - inconsistent markup but this situation should be rare). - -[ Default: S >] - -=item C,C - -If both \begin and \end for a math environment (environment name matching C -or \[ and \]) -are within the same deleted block, they are replaced by a \begin and \end commands for C -rather than being commented out. - -[ Default: C=S >, C=S >] - -=item C,C - -as C,C but for equation arrays - -[ Default: C=S >, C=S >] - -=item C - -If a match to C is found within an inline math environment within a deleted or added block, then the inlined math -is surrounded by C<\mbox{>...C<}>. This is necessary as underlining does not work within inlined array environments. - -[ Default: C=S > - -=item C - -If a command in a deleted block which is also in the textcmd list matches C then an -additional command C<\addtocounter{>FC<}{-1}>, where F is the matching command, is appended in the diff file such that the numbering in the diff file remains synchronized with the -numbering in the new file. - -[ Default: C=C<(?:footnote|part|section|subsection> ... - -C<|subsubsection|paragraph|subparagraph)> ] - -=back - -=head1 COMMON PROBLEMS - -=over 10 - -=item Citations result in overfull boxes - -There is an incompatibility between the C package, which C uses for underlining and striking out in the UNDERLINE style, -the default style. In order to be able to mark up citations properly, they are placed with an C<\mbox> command in post-processing. As mboxes -cannot be broken across lines, this procedure frequently results in overfull boxes, possibly obscuring the content as it extends beyond the right margin. If this is a problem, you have two possibilities: - -1. Use C or C subtype markup (option C<-s COLOR>): If this markup is chosen, then changed citations are no longer marked up -with the wavy line (additions) or struck out (deletions), but are still highlighted in the appropriate color. - -2. Choose option C<--disable-citation-markup> which turns off the marking up of citations: deleted citations are no longer shown, and -added ctations are shown without markup. (This was the default behaviour of latexdiff at versions 0.6 and older - -=back - -=head1 BUGS - -Option allow-spaces not implemented entirely consistently. It breaks -the rules that number and type of white space does not matter, as -different numbers of inter-argument spaces are treated as significant. - -Please send bug reports -to I or submit on latexdiff project page I. Include the serial number of I -(from comments at the top of the source or use B<--version>). If you come across latex -files that are error-free and conform to the specifications set out -above, and whose differencing still does not result in error-free -latex, please send me those files, ideally edited to only contain the -offending passage as long as that still reproduces the problem. If your -file relies on non-standard class files, you must include those. I will not -look at examples where I have trouble to latex the original files. - -=head1 SEE ALSO - -L, L - -=head1 PORTABILITY - -I does not make use of external commands and thus should run -on any platform supporting Perl 5.6 or higher. If files with encodings -other than ASCII or UTF-8 are processed, Perl 5.8 or higher is required. - -The standard version of I requires installation of the Perl package -C (available from I - -I) but a stand-alone -version, I, which has this package inlined, is available, too. -I requires the I command to be present. - -=head1 AUTHOR - -Copyright (C) 2004-2012 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 - -Contributors of fixes and additions: V. Kuhlmann, J. Paisley, N. Becker, T. Doerges, K. Huebner, -T. Connors, Sebastian Gouezel and many others. -Thanks to the many people who send in bug reports, feature suggestions, and other feedback. - -=cut - -__END__ -%%BEGIN SAFE COMMANDS -% Regex matching commands which can safely be in the -% argument of a \DIFadd or \DIFdel command (leave out the \) -arabic -dashbox -emph -fbox -framebox -hspace -math.* -makebox -mbox -pageref -ref -symbol -raisebox -rule -text.* -shortstack -usebox -dag -ddag -copyright -pounds -S -P -oe -OE -ae -AE -aa -AA -o -O -l -L -frac -ss -sqrt -ldots -cdots -vdots -ddots -alpha -beta -gamma -delta -epsilon -varepsilon -zeta -eta -theta -vartheta -iota -kappa -lambda -mu -nu -xi -pi -varpi -rho -varrho -sigma -varsigma -tau -upsilon -phi -varphi -chi -psi -omega -Gamma -Delta -Theta -Lambda -Xi -Pi -Sigma -Upsilon -Phi -Psi -Omega -ps -mp -times -div -ast -star -circ -bullet -cdot -cap -cup -uplus -sqcap -vee -wedge -setminus -wr -diamond -(?:big)?triangle.* -lhd -rhd -unlhd -unrhd -oplus -ominus -otimes -oslash -odot -bigcirc -d?dagger -amalg -leq -prec -preceq -ll -(?:sq)?su[bp]set(?:eq)? -in -vdash -geq -succ(?:eq)? -gg -ni -dashv -equiv -sim(?:eq)? -asymp -approx -cong -neq -doteq -propto -models -perp -mid -parallel -bowtie -Join -smile -frown -.*arrow -(?:long)?mapsto -.*harpoon.* -leadsto -aleph -hbar -imath -jmath -ell -wp -Re -Im -mho -prime -emptyset -nabla -surd -top -bot -angle -forall -exists -neg -flat -natural -sharp -backslash -partial -infty -Box -Diamond -triangle -clubsuit -diamondsuit -heartsuit -spadesuit -sum -prod -coprod -int -oint -big(?:sq)?c[au]p -bigvee -bigwedge -bigodot -bigotimes -bigoplus -biguplus -(?:arc)?(?:cos|sin|tan|cot)h? -csc -arg -deg -det -dim -exp -gcd -hom -inf -ker -lg -lim -liminf -limsup -ln -log -max -min -Pr -sec -sup -(SUPER|SUB)SCRIPTNB -(SUPER|SUB)SCRIPT -%%END SAFE COMMANDS - -%%BEGIN TEXT COMMANDS -% Regex matching commands with a text argument (leave out the \) -addcontents.* -cc -closing -chapter -dashbox -emph -encl -fbox -framebox -footnote -footnotetext -framebox -part -(sub){0,2}section\*? -(sub)?paragraph\*? -makebox -mbox -opening -parbox -raisebox -savebox -sbox -shortstack -signature -text.* -value -underline -sqrt -(SUPER|SUB)SCRIPT -%%END TEXT COMMANDS - -%%BEGIN CONTEXT1 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -caption -%%END CONTEXT1 COMMANDS - -%%BEGIN CONTEXT2 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -title -author -date -institute -%%END CONTEXT2 COMMANDS - - -%% TYPES (Commands for highlighting changed blocks) - -%DIF UNDERLINE PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}} -\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}} -%DIF END UNDERLINE PREAMBLE - -%DIF CTRADITIONAL PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} [..\footnote{removed: #1} ]}} -%DIF END CTRADITIONAL PREAMBLE - -%DIF TRADITIONAL PREAMBLE -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{[..\footnote{removed: #1} ]}} -%DIF END TRADITIONAL PREAMBLE - -%DIF CFONT PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} \scriptsize #1}} -%DIF END CFONT PREAMBLE - -%DIF FONTSTRIKE PREAMBLE -\RequirePackage[normalem]{ulem} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{\footnotesize \sout{#1}}} -%DIF END FONTSTRIKE PREAMBLE - -%DIF CCHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}#1}\protect\cbdelete} -%DIF END CCHANGEBAR PREAMBLE - -%DIF CFONTCHBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\sf #1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\scriptsize #1}\protect\cbdelete} -%DIF END CFONTCHBAR PREAMBLE - -%DIF CULINECHBAR PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage[dvips]{changebar} -\RequirePackage{color} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\uwave{#1}}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\sout{#1}}\protect\cbdelete} -%DIF END CULINECHBAR PREAMBLE - -%DIF CHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\providecommand{\DIFadd}[1]{\protect\cbstart{#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete} -%DIF END CHANGEBAR PREAMBLE - -%DIF INVISIBLE PREAMBLE -\providecommand{\DIFadd}[1]{#1} -\providecommand{\DIFdel}[1]{} -%DIF END INVISIBLE PREAMBLE - - -%% SUBTYPES (Markers for beginning and end of changed blocks) - -%DIF SAFE PREAMBLE -\providecommand{\DIFaddbegin}{} -\providecommand{\DIFaddend}{} -\providecommand{\DIFdelbegin}{} -\providecommand{\DIFdelend}{} -%DIF END SAFE PREAMBLE - -%DIF MARGIN PREAMBLE -\providecommand{\DIFaddbegin}{\protect\marginpar{a[}} -\providecommand{\DIFaddend}{\protect\marginpar{]}} -\providecommand{\DIFdelbegin}{\protect\marginpar{d[}} -\providecommand{\DIFdelend}{\protect\marginpar{]}} -%DIF END BRACKET PREAMBLE - -%DIF DVIPSCOL PREAMBLE -%Note: only works with dvips converter -\RequirePackage{color} -\RequirePackage{dvipscol} -\providecommand{\DIFaddbegin}{\protect\nogroupcolor{blue}} -\providecommand{\DIFaddend}{\protect\nogroupcolor{black}} -\providecommand{\DIFdelbegin}{\protect\nogroupcolor{red}} -\providecommand{\DIFdelend}{\protect\nogroupcolor{black}} -%DIF END DVIPSCOL PREAMBLE - -%DIF COLOR PREAMBLE -\RequirePackage{color} -\providecommand{\DIFaddbegin}{\protect\color{blue}} -\providecommand{\DIFaddend}{\protect\color{black}} -\providecommand{\DIFdelbegin}{\protect\color{red}} -\providecommand{\DIFdelend}{\protect\color{black}} -%DIF END COLOR PREAMBLE - - -%% FLOAT TYPES - -%DIF FLOATSAFE PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%DIF IDENTICAL PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{\DIFaddbegin} -\providecommand{\DIFaddendFL}{\DIFaddend} -\providecommand{\DIFdelbeginFL}{\DIFdelbegin} -\providecommand{\DIFdelendFL}{\DIFdelend} -%DIF END IDENTICAL PREAMBLE - -%DIF TRADITIONALSAFE PREAMBLE -% procidecommand color to make this work for TRADITIONAL and CTRADITIONAL -\providecommand{\color}[1]{} -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdel}[1]{{\protect\color{red}[..{\scriptsize {removed: #1}} ]}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%% SPECIAL PACKAGE PREAMBLE COMMANDS - -% Standard \DIFadd and \DIFdel are redefined as \DIFaddtex and \DIFdeltex -% when hyperref package is included. -%DIF HYPERREF PREAMBLE -\providecommand{\DIFadd}[1]{\texorpdfstring{\DIFaddtex{#1}}{#1}} -\providecommand{\DIFdel}[1]{\texorpdfstring{\DIFdeltex{#1}}{}} -%DIF END HYPERREF PACKAGE diff --git a/latexdiff-1.0.1/latexdiff-fast b/latexdiff-1.0.1/latexdiff-fast deleted file mode 100755 index 46de52d..0000000 --- a/latexdiff-1.0.1/latexdiff-fast +++ /dev/null @@ -1,3953 +0,0 @@ -#!/usr/bin/env perl -##!/usr/bin/perl -w -# latexdiff - differences two latex files on the word level -# and produces a latex file with the differences marked up. -# -# Copyright (C) 2004-12 F J Tilmann (tilmann@gfz-potsdam.de, ftilmann@users.berlios.de) -# -# Project webpages: http://latexdiff.berlios.de/ -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# -# Version 1.0.1 - treat \big,\bigg etc. equivalently to \left and -# \right - include starred version in MATHENV - apply -# - flatten recursively and --flatten expansion is now -# aware of comments (thanks to Tim Connors for patch) -# - Change to post-processing for more reliability for -# deleted math environments -# - On linux systems, recognise and remove DOS style newlines -# - Provide markup for some special preamble commands (\title, -# \author,\date, -# - configurable by setting context2cmd -# - for styles using ulem package, remove \emph and \text.. from list of -# safe commands in order to allow linebreaks within the -# highlighted sections. -# - for ulem style, now show citations by enclosing them in \mbox commands. -# This unfortunately implies linebreaks within citations no longer function, -# so this functionality can be turned off (Option --disable-citation-markup). -# With --enable-citation-markup, the mbox markup is forced for other styles) -# - new substyle COLOR. This is particularly useful for marking up citations -# and some special post-processing is implemented to retain cite -# commands in deleted blocks. -# - four different levels of math-markup -# - Option --driver for choosing driver for modes employing changebar package -# - accept \\* as valid command (and other commands of form \.*). Also accept -# \ (backslashed newline) -# - some typo fixes, include commands defined in preamble as safe commands -# (Sebastian Gouezel) -# - include compared filenames as comments as line 2 and 3 of -# the preamble (can be modified with option --label, and suppressed with -# --no-label), option --visible-label to show files in generated pdf or dvi -# at the beginning of main document -# -# Version 0.5 A number of minor improvements based on feedback -# Deleted blocks are now shown before added blocks -# Package specific processing -# -# Version 0.43 unreleased typo in list of styles at the end -# Add protect to all \cbstart, \cbend commands -# More robust substitution of deleted math commands -# -# Version 0.42 November 06 Bug fixes only -# -# Version 0.4 March 06 option for fast differencing using UNIX diff command, several minor bug fixes (\par bug, improved highlighting of textcmds) -# -# Version 0.3 August 05 improved parsing of displayed math, --allow-spaces -# option, several minor bug fixes -# -# Version 0.25 October 04 Fix bug with deleted equations, add math mode commands to safecmd, add | to allowed interpunctuation signs -# Version 0.2 September 04 extension to utf-8 and variable encodings -# Version 0.1 August 04 First public release - -# Inserted block for differenceing -# use Algorithm::Diff qw(traverse_sequences); -# in standard version -# The following BEGIN block contains a verbatim copy of -# Ned Konz' Algorithm::Diff package version 1.15 except -# that subroutine _longestCommonSubsequence has been replace by -# a routine which internally uses the UNIX diff command for -# the differencing rather than the Perl routines if the -# length of the sequences exceeds some threshold. -# Also, all POD documentation has been stripped out. -# -# (the distribution on which this modification is based is available -# from http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15 -# the most recent version can be found via http://search.cpan.org/search?module=Algorithm::Diff ) -# Please note that the LICENCSE for Algorithm::Diff : -# "Copyright (c) 2000-2002 Ned Konz. All rights reserved. -# This program is free software; -# you can redistribute it and/or modify it under the same terms -# as Perl itself." -# The fast-differencing version of latexdiff is provided as a convenience -# for latex users under Unix-like systems which have a 'diff' command. -# If you believe -# the inlining of Algorithm::Diff violates its license please contact -# me and I will modify the latexdiff distribution accordingly. -# Frederik Tilmann (tilmann@esc.cam.ac.uk) -# Jonathan Paisley is acknowledged for the idea of using the system diff -# command to achieve shorter running times -BEGIN { -package Algorithm::Diff; -use strict; -use vars qw($VERSION @EXPORT_OK @ISA @EXPORT); -use integer; # see below in _replaceNextLargerWith() for mod to make - # if you don't use this -require Exporter; -@ISA = qw(Exporter); -@EXPORT = qw(); -@EXPORT_OK = qw(LCS diff traverse_sequences traverse_balanced sdiff); -$VERSION = sprintf('%d.%02d fast', (q$Revision: 1.15 $ =~ /\d+/g)); - -# Global parameters - -use File::Temp qw/tempfile/; -# if larger number of elements in longestCommonSubsequence smaller than -# this number, then use internal algorithm, otherwise use UNIX diff -use constant THRESHOLD => 100 ; -# Detect whether diff --minimal option is available -# if yes we use it -use constant MINIMAL => ( system('diff','--minimal','/dev/null','/dev/null') >> 8 ==0 ? "--minimal" : "" ) ; - - - -# McIlroy-Hunt diff algorithm -# Adapted from the Smalltalk code of Mario I. Wolczko, -# by Ned Konz, perl@bike-nomad.com - - -# Create a hash that maps each element of $aCollection to the set of positions -# it occupies in $aCollection, restricted to the elements within the range of -# indexes specified by $start and $end. -# The fourth parameter is a subroutine reference that will be called to -# generate a string to use as a key. -# Additional parameters, if any, will be passed to this subroutine. -# -# my $hashRef = _withPositionsOfInInterval( \@array, $start, $end, $keyGen ); - -sub _withPositionsOfInInterval -{ - my $aCollection = shift; # array ref - my $start = shift; - my $end = shift; - my $keyGen = shift; - my %d; - my $index; - for ( $index = $start ; $index <= $end ; $index++ ) - { - my $element = $aCollection->[$index]; - my $key = &$keyGen( $element, @_ ); - if ( exists( $d{$key} ) ) - { - unshift ( @{ $d{$key} }, $index ); - } - else - { - $d{$key} = [$index]; - } - } - return wantarray ? %d : \%d; -} - -# Find the place at which aValue would normally be inserted into the array. If -# that place is already occupied by aValue, do nothing, and return undef. If -# the place does not exist (i.e., it is off the end of the array), add it to -# the end, otherwise replace the element at that point with aValue. -# It is assumed that the array's values are numeric. -# This is where the bulk (75%) of the time is spent in this module, so try to -# make it fast! - -sub _replaceNextLargerWith -{ - my ( $array, $aValue, $high ) = @_; - $high ||= $#$array; - - # off the end? - if ( $high == -1 || $aValue > $array->[-1] ) - { - push ( @$array, $aValue ); - return $high + 1; - } - - # binary search for insertion point... - my $low = 0; - my $index; - my $found; - while ( $low <= $high ) - { - $index = ( $high + $low ) / 2; - - # $index = int(( $high + $low ) / 2); # without 'use integer' - $found = $array->[$index]; - - if ( $aValue == $found ) - { - return undef; - } - elsif ( $aValue > $found ) - { - $low = $index + 1; - } - else - { - $high = $index - 1; - } - } - - # now insertion point is in $low. - $array->[$low] = $aValue; # overwrite next larger - return $low; -} - -# This method computes the longest common subsequence in $a and $b. - -# Result is array or ref, whose contents is such that -# $a->[ $i ] == $b->[ $result[ $i ] ] -# foreach $i in ( 0 .. $#result ) if $result[ $i ] is defined. - -# An additional argument may be passed; this is a hash or key generating -# function that should return a string that uniquely identifies the given -# element. It should be the case that if the key is the same, the elements -# will compare the same. If this parameter is undef or missing, the key -# will be the element as a string. - -# By default, comparisons will use "eq" and elements will be turned into keys -# using the default stringizing operator '""'. - -# Additional parameters, if any, will be passed to the key generation routine. - -sub _longestCommonSubsequence -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $keyGen = shift; # code ref - my $compare; # code ref - - # set up code refs - # Note that these are optimized. - if ( !defined($keyGen) ) # optimize for strings - { - $keyGen = sub { $_[0] }; - $compare = sub { my ( $a, $b ) = @_; $a eq $b }; - } - else - { - $compare = sub { - my $a = shift; - my $b = shift; - &$keyGen( $a, @_ ) eq &$keyGen( $b, @_ ); - }; - } - - my ( $aStart, $aFinish, $bStart, $bFinish, $matchVector ) = - ( 0, $#$a, 0, $#$b, [] ); - - # Check whether to use internal routine (small number of elements) - # or use it as a wrapper for UNIX diff - if ( ( $#$a > $#$b ? $#$a : $#$b) < THRESHOLD ) { - ### print STDERR "DEBUG: regular longestCommonSubsequence\n"; - # First we prune off any common elements at the beginning - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aStart], $b->[$bStart], @_ ) ) - { - $matchVector->[ $aStart++ ] = $bStart++; - } - - # now the end - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aFinish], $b->[$bFinish], @_ ) ) - { - $matchVector->[ $aFinish-- ] = $bFinish--; - } - - # Now compute the equivalence classes of positions of elements - my $bMatches = - _withPositionsOfInInterval( $b, $bStart, $bFinish, $keyGen, @_ ); - my $thresh = []; - my $links = []; - - my ( $i, $ai, $j, $k ); - for ( $i = $aStart ; $i <= $aFinish ; $i++ ) - { - $ai = &$keyGen( $a->[$i], @_ ); - if ( exists( $bMatches->{$ai} ) ) - { - $k = 0; - for $j ( @{ $bMatches->{$ai} } ) - { - - # optimization: most of the time this will be true - if ( $k and $thresh->[$k] > $j and $thresh->[ $k - 1 ] < $j ) - { - $thresh->[$k] = $j; - } - else - { - $k = _replaceNextLargerWith( $thresh, $j, $k ); - } - - # oddly, it's faster to always test this (CPU cache?). - if ( defined($k) ) - { - $links->[$k] = - [ ( $k ? $links->[ $k - 1 ] : undef ), $i, $j ]; - } - } - } - } - - if (@$thresh) - { - for ( my $link = $links->[$#$thresh] ; $link ; $link = $link->[0] ) - { - $matchVector->[ $link->[1] ] = $link->[2]; - } - } - } - else { - my ($fha,$fhb,$fna,$fnb,$ele,$key); - my ($alines,$blines,$alb,$alf,$blb,$blf); - my ($minimal)=MINIMAL; - # large number of elements, use system diff - ### print STDERR "DEBUG: fast (diff) longestCommonSubsequence\n"; - - ($fha,$fna)=tempfile("DiffA-XXXX") or die "_longestCommonSubsequence: Cannot open tempfile for sequence A"; - ($fhb,$fnb)=tempfile("DiffB-XXXX") or die "_longestCommonSubsequence: Cannot open tempfile for sequence B"; - # prepare sequence A - foreach $ele ( @$a ) { - $key=&$keyGen( $ele, @_ ); - $key =~ s/\\/\\\\/g ; - $key =~ s/\n/\\n/sg ; - print $fha "$key\n" ; - } - close($fha); - # prepare sequence B - foreach $ele ( @$b ) { - $key=&$keyGen( $ele, @_ ); - $key =~ s/\\/\\\\/g ; - $key =~ s/\n/\\n/sg ; - print $fhb "$key\n" ; - } - close($fhb); - - open(DIFFPIPE, "diff $minimal $fna $fnb |") or die "_longestCommonSubsequence: Cannot launch diff process. $!" ; - # The diff line numbering begins with 1, but Perl subscripts start with 0 - # We follow the diff numbering but substract 1 when assigning to matchVector - $aStart++; $bStart++ ; $aFinish++ ; $bFinish++ ; - while( ) { - if ( ($alines,$blines) = ( m/^(\d*(?:,\d*)?)?c(\d*(?:,\d*)?)?$/ ) ) { - ($alb,$alf)=split(/,/,$alines); - ($blb,$blf)=split(/,/,$blines); - $alf=$alb unless defined($alf); - $blf=$blb unless defined($blf); - while($aStart < $alb ) { - $matchVector->[ -1 + $aStart++ ] = -1 + $bStart++ ; - } - # check for consistency - $bStart==$blb or die "_longestCommonSubsequence: Fatal error in interpreting diff output: Inconsistency in changed sequence"; - $aStart=$alf+1; - $bStart=$blf+1; - } - elsif ( ($alb,$blines) = ( m/^(\d*)a(\d*(?:,\d*)?)$/ ) ) { - ($blb,$blf)=split(/,/,$blines); - $blf=$blb unless defined($blf); - while ( $bStart < $blb ) { - $matchVector->[ -1 + $aStart++ ] = -1 + $bStart++ ; - } - $aStart==$alb+1 or die "_longestCommonSubsequence: Fatal error in interpreting diff output: Inconsistency in appended sequence near elements $aStart and $bStart"; - $bStart=$blf+1; - } - elsif ( ($alines,$blb) = ( m/^(\d*(?:,\d*)?)d(\d*)$/ ) ) { - ($alb,$alf)=split(/,/,$alines); - $alf=$alb unless defined($alf); - while ( $aStart < $alb ) { - $matchVector->[ -1 + $aStart++ ] = -1 + $bStart++ ; - } - $bStart==$blb+1 or die "_longestCommonSubsequence: Fatal error in interpreting diff output: Inconsistency in deleted sequence near elements $aStart and $bStart"; - $aStart=$alf+1; - } - elsif ( m/^Binary files/ ) { - # if diff reports it is a binary file force --text mode. I do not like - # to always use this option because it is probably only available in GNU diff - open(DIFFPIPE, "diff --text $fna $fnb |") or die "Cannot launch diff process. $!" ; - } - # Default: just skip line - } - while ($aStart <= $aFinish ) { - $matchVector->[ -1 + $aStart++ ] = -1 + $bStart++ ; - } - $bStart==$bFinish+1 or die "_longestCommonSubsequence: Fatal error in interpreting diff output: Inconsistency at end"; - close DIFFPIPE; - # check whether a system error has occurred or return status is greater than or equal to 5 - if ( $! || ($? >> 8) > 5) { - print STDERR "diff process failed with exit code ", ($? >> 8), " $!\n"; - die; - } - unlink $fna,$fnb ; - } - return wantarray ? @$matchVector : $matchVector; -} - -sub traverse_sequences -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $finishedACallback = $callbacks->{'A_FINISHED'}; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $finishedBCallback = $callbacks->{'B_FINISHED'}; - my $matchVector = _longestCommonSubsequence( $a, $b, $keyGen, @_ ); - - # Process all the lines in @$matchVector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai; - - for ( $ai = 0 ; $ai <= $#$matchVector ; $ai++ ) - { - my $bLine = $matchVector->[$ai]; - if ( defined($bLine) ) # matched - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi < $bLine; - &$matchCallback( $ai, $bi++, @_ ); - } - else - { - &$discardACallback( $ai, $bi, @_ ); - } - } - - # The last entry (if any) processed was a match. - # $ai and $bi point just past the last matching lines in their sequences. - - while ( $ai <= $lastA or $bi <= $lastB ) - { - - # last A? - if ( $ai == $lastA + 1 and $bi <= $lastB ) - { - if ( defined($finishedACallback) ) - { - &$finishedACallback( $lastA, @_ ); - $finishedACallback = undef; - } - else - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi <= $lastB; - } - } - - # last B? - if ( $bi == $lastB + 1 and $ai <= $lastA ) - { - if ( defined($finishedBCallback) ) - { - &$finishedBCallback( $lastB, @_ ); - $finishedBCallback = undef; - } - else - { - &$discardACallback( $ai++, $bi, @_ ) while $ai <= $lastA; - } - } - - &$discardACallback( $ai++, $bi, @_ ) if $ai <= $lastA; - &$discardBCallback( $ai, $bi++, @_ ) if $bi <= $lastB; - } - - return 1; -} - -sub traverse_balanced -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $changeCallback = $callbacks->{'CHANGE'}; - my $matchVector = _longestCommonSubsequence( $a, $b, $keyGen, @_ ); - - # Process all the lines in match vector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai = 0; - my $ma = -1; - my $mb; - - while (1) - { - - # Find next match indices $ma and $mb - do { $ma++ } while ( $ma <= $#$matchVector && !defined $matchVector->[$ma] ); - - last if $ma > $#$matchVector; # end of matchVector? - $mb = $matchVector->[$ma]; - - # Proceed with discard a/b or change events until - # next match - while ( $ai < $ma || $bi < $mb ) - { - - if ( $ai < $ma && $bi < $mb ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai < $ma ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi < $mb - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - # Match - &$matchCallback( $ai++, $bi++, @_ ); - } - - while ( $ai <= $lastA || $bi <= $lastB ) - { - if ( $ai <= $lastA && $bi <= $lastB ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai <= $lastA ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi <= $lastB - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - return 1; -} - -sub LCS -{ - my $a = shift; # array ref - my $matchVector = _longestCommonSubsequence( $a, @_ ); - my @retval; - my $i; - for ( $i = 0 ; $i <= $#$matchVector ; $i++ ) - { - if ( defined( $matchVector->[$i] ) ) - { - push ( @retval, $a->[$i] ); - } - } - return wantarray ? @retval : \@retval; -} - -sub diff -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $hunk = []; - my $discard = sub { push ( @$hunk, [ '-', $_[0], $a->[ $_[0] ] ] ) }; - my $add = sub { push ( @$hunk, [ '+', $_[1], $b->[ $_[1] ] ] ) }; - my $match = sub { push ( @$retval, $hunk ) if scalar(@$hunk); $hunk = [] }; - traverse_sequences( $a, $b, - { MATCH => $match, DISCARD_A => $discard, DISCARD_B => $add }, @_ ); - &$match(); - return wantarray ? @$retval : $retval; -} - -sub sdiff -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $discard = sub { push ( @$retval, [ '-', $a->[ $_[0] ], "" ] ) }; - my $add = sub { push ( @$retval, [ '+', "", $b->[ $_[1] ] ] ) }; - my $change = sub { - push ( @$retval, [ 'c', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - my $match = sub { - push ( @$retval, [ 'u', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - traverse_balanced( - $a, - $b, - { - MATCH => $match, - DISCARD_A => $discard, - DISCARD_B => $add, - CHANGE => $change, - }, - @_ - ); - return wantarray ? @$retval : $retval; -} - -1; -} -import Algorithm::Diff qw(traverse_sequences); -# End of inserted block for stand-alone version - - -use Getopt::Long ; -use strict ; -use warnings; -use utf8 ; - -my ($algodiffversion)=split(/ /,$Algorithm::Diff::VERSION); - - -my ($versionstring)=< 0, - WHOLE => 1, - COARSE => 2, - FINE => 3 -}; - - -my (@configlist,@labels, - @appendsafelist,@excludesafelist, - @appendtextlist,@excludetextlist, - @appendcontext1list,@appendcontext2list, - @packagelist); -my ($assign,@config); -# Hash where keys corresponds to the names of all included packages (including the documentclass as another package -# the optional arguments to the package are the values of the hash elements -my ($pkg,%packages); -# Defaults -$type='UNDERLINE'; -$subtype='SAFE'; -$floattype='FLOATSAFE'; -$mathmarkup=COARSE; - -$verbose=0; -# output debug and intermediate files, set to 0 in final distribution -$debug=0; -# define character properties -sub IsNonAsciiPunct { return <<'END' # Unicode punctuation but excluding ASCII punctuation -+utf8::IsPunct --utf8::IsASCII -END -} -sub IsNonAsciiS { return <<'END' # Unicode symbol but excluding ASCII -+utf8::IsS --utf8::IsASCII -END -} - - -my %verbhash; - -Getopt::Long::Configure('bundling'); -GetOptions('type|t=s' => \$type, - 'subtype|s=s' => \$subtype, - 'floattype|f=s' => \$floattype, - 'config|c=s' => \@configlist, - 'preamble|p=s' => \$preamblefile, - 'encoding|e=s' => \$encoding, - 'label|L=s' => \@labels, - 'no-label' => \$nolabel, - 'visible-label' => \$visiblelabel, - 'exclude-safecmd|A=s' => \@excludesafelist, - 'replace-safecmd=s' => \$replacesafe, - 'append-safecmd|a=s' => \@appendsafelist, - 'exclude-textcmd|X=s' => \@excludetextlist, - 'replace-textcmd=s' => \$replacetext, - 'append-textcmd|x=s' => \@appendtextlist, - 'replace-context1cmd=s' => \$replacecontext1, - 'append-context1cmd=s' => \@appendcontext1list, - 'replace-context2cmd=s' => \$replacecontext2, - 'append-context2cmd=s' => \@appendcontext2list, - 'show-preamble' => \$showpreamble, - 'show-safecmd' => \$showsafe, - 'show-textcmd' => \$showtext, - 'show-config' => \$showconfig, - 'show-all' => \$showall, - 'packages=s' => \@packagelist, - 'allow-spaces' => \$allowspaces, - 'math-markup=s' => \$mathmarkup, - 'enable-citation-markup' => \$enablecitmark, - 'disable-citation-markup' => \$disablecitmark, - 'verbose|V' => \$verbose, - 'ignore-warnings' => \$ignorewarnings, - 'driver=s'=> \$driver, - 'flatten' => \$flatten, - 'version' => \$version, - 'help|h|H' => \$help); - -if ( $help ) { - usage() ; -} - - -if ( $version ) { - die $versionstring ; -} - -print STDERR $versionstring if $verbose; - -if (defined($showall)){ - $showpreamble=$showsafe=$showtext=$showconfig=1; -} - -if (defined($mathmarkup)) { - $mathmarkup=~tr/a-z/A-Z/; - if ( $mathmarkup eq 'OFF' ){ - $mathmarkup=OFF; - } elsif ( $mathmarkup eq 'WHOLE' ){ - $mathmarkup=WHOLE; - } elsif ( $mathmarkup eq 'COARSE' ){ - $mathmarkup=COARSE; - } elsif ( $mathmarkup eq 'FINE' ){ - $mathmarkup=FINE; - } elsif ( $mathmarkup !~ m/^[0123]$/ ) { - die "Illegal value: ($mathmarkup) for option--math-markup. Possible values: OFF,WHOLE,COARSE,FINE,0- "; - } - # else use numerical value -} - -# setting extra preamble commands -if (defined($preamblefile)) { - $latexdiffpreamble=join "\n",(extrapream($preamblefile),""); -} else { - $latexdiffpreamble=join "\n",(extrapream($type,$subtype,$floattype),""); -} - -if ( defined($driver) ) { - # for changebar only - $latexdiffpreamble=~s/\[dvips\]/[$driver]/sg; -} -# setting up @SAFECMDLIST and @SAFECMDEXCL -if (defined($replacesafe)) { - init_regex_arr_ext(\@SAFECMDLIST,$replacesafe); -} else { - init_regex_arr_data(\@SAFECMDLIST, "SAFE COMMANDS"); -} -foreach $appendsafe ( @appendsafelist ) { - init_regex_arr_ext(\@SAFECMDLIST, $appendsafe); -} -foreach $excludesafe ( @excludesafelist ) { - init_regex_arr_ext(\@SAFECMDEXCL, $excludesafe); -} - -# Special: treat all cite commands as safe except in UNDERLINE and FONTSTRIKE mode -# (there is a conflict between citation and ulem package, see -# package documentation) -# Use post-processing - -if ( uc($type) ne "UNDERLINE" && uc($type) ne "FONTSTRIKE" && uc($type) ne "CULINECHBAR" ) { - push (@SAFECMDLIST, qr/^cite.*$/); -} else { - ### Experimental: disable text and emph commands - push (@SAFECMDLIST, qr/^cite.*$/) unless $disablecitmark; - push(@SAFECMDEXCL, qr/^emph$/, qr/^text..$/); - # replace \cite{..} by \mbox{\cite{..}} in added or deleted blocks in post-processing - if ( uc($subtype) eq "COLOR" or uc($subtype) eq "DVIPSCOL" ) { - # remove \cite command again from list of safe commands - pop @SAFECMDLIST; - # deleted cite commands - $CITE2CMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite-type commands which should be reinstated in deleted blocks - } else { - $CITECMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite commands which need to be protected within an mbox in UNDERLINE and other modes using ulem - } -} -$CITECMD='(?:cite\w*|nocite)' if $enablecitmark ; # as above for explicit selection - -# setting up @TEXTCMDLIST and @TEXTCMDEXCL -if (defined($replacetext)) { - init_regex_arr_ext(\@TEXTCMDLIST,$replacetext); -} else { - init_regex_arr_data(\@TEXTCMDLIST, "TEXT COMMANDS"); -} -foreach $appendtext ( @appendtextlist ) { - init_regex_arr_ext(\@TEXTCMDLIST, $appendtext); -} -foreach $excludetext ( @excludetextlist ) { - init_regex_arr_ext(\@TEXTCMDEXCL, $excludetext); -} - - -# setting up @CONTEXT1CMDLIST ( @CONTEXT1CMDEXCL exist but is always empty ) -if (defined($replacecontext1)) { - init_regex_arr_ext(\@CONTEXT1CMDLIST,$replacecontext1); -} else { - init_regex_arr_data(\@CONTEXT1CMDLIST, "CONTEXT1 COMMANDS"); -} -foreach $appendcontext1 ( @appendcontext1list ) { - init_regex_arr_ext(\@CONTEXT1CMDLIST, $appendcontext1); -} - - -# setting up @CONTEXT2CMDLIST ( @CONTEXT2CMDEXCL exist but is always empty ) -if (defined($replacecontext2)) { - init_regex_arr_ext(\@CONTEXT2CMDLIST,$replacecontext2); -} else { - init_regex_arr_data(\@CONTEXT2CMDLIST, "CONTEXT2 COMMANDS"); -} -foreach $appendcontext2 ( @appendcontext2list ) { - init_regex_arr_ext(\@CONTEXT2CMDLIST, $appendcontext2); -} - -# setting configuration variables -@config=(); -foreach $config ( @configlist ) { - if (-f $config ) { - open(FILE,$config) or die ("Couldn't open configuration file $config: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@config,$_); - } - close(FILE); - } - else { -# foreach ( split(",",$config) ) { -# push @config,$_; -# } - push @config,split(",",$config) - } -} -foreach $assign ( @config ) { - $assign=~ m/\s*(\w*)\s*=\s*(\S*)\s*$/ or die "Illegal assignment $assign in configuration list (must be variable=value)"; - if ( $1 eq "MINWORDSBLOCK" ) { $MINWORDSBLOCK = $2; } - elsif ( $1 eq "FLOATENV" ) { $FLOATENV = $2 ; } - elsif ( $1 eq "PICTUREENV" ) { $PICTUREENV = $2 ; } - elsif ( $1 eq "MATHENV" ) { $MATHENV = $2 ; } - elsif ( $1 eq "MATHREPL" ) { $MATHREPL = $2 ; } - elsif ( $1 eq "MATHARRENV" ) { $MATHARRENV = $2 ; } - elsif ( $1 eq "MATHARRREPL" ) { $MATHARRREPL = $2 ; } - elsif ( $1 eq "ARRENV" ) { $ARRENV = $2 ; } - elsif ( $1 eq "COUNTERCMD" ) { $COUNTERCMD = $2 ; } - else { die "Unknown variable $1 in assignment.";} -} - -if ( $mathmarkup == COARSE || $mathmarkup == WHOLE ) { - push(@MATHTEXTCMDLIST,qr/^MATHBLOCK(?:$MATHENV|$MATHARRENV|SQUAREBRACKET)$/); -} - - - -foreach $pkg ( @packagelist ) { - map { $packages{$_}="" } split(/,/,$pkg) ; -} - -if ($showpreamble) { - print "\nPreamble commands:\n"; - print $latexdiffpreamble ; -} - -if ($showsafe) { - print "\nCommands safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE (unless excluded):\n"; - print_regex_arr(@SAFECMDLIST); - print "\nCommands not safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE :\n"; - print_regex_arr(@SAFECMDEXCL); -} - -if ($showtext) { - print "\nCommands with last argument textual (unless excluded) and safe in every context:\n"; - print_regex_arr(@TEXTCMDLIST); - print "\nContext1 commands (last argument textual, command will be disabled in deleted passages, last argument will be shown as plain text):\n"; - print_regex_arr(@CONTEXT1CMDLIST); - print "\nContext2 commands (last argument textual, command and its argument will be disabled in deleted passages):\n"; - print_regex_arr(@CONTEXT2CMDLIST); - print "\nExclude list of Commands with last argument not textual (overrides patterns above):\n"; - print_regex_arr(@TEXTCMDEXCL); -} - - -if ($showconfig) { - print "Configuration variables:\n"; - print "MINWORDSBLOCK=$MINWORDSBLOCK\n"; - print "FLOATENV=$FLOATENV\n"; - print "PICTUREENV=$PICTUREENV\n"; - print "MATHENV=$MATHENV\n"; - print "MATHREPL=$MATHREPL\n"; - print "MATHARRENV=$MATHARRENV\n"; - print "MATHARRREPL=$MATHARRREPL\n"; - print "ARRENV=$ARRENV\n"; - print "COUNTERCMD=$COUNTERCMD\n"; -} -if ($showconfig || $showtext || $showsafe || $showpreamble) { - exit 0; } -if ( @ARGV != 2 ) { - print STDERR "2 and only 2 non-option arguments required. Write latexdiff -h to get help\n"; - exit(2); -} - -# Are extra spaces between command arguments permissible? -my $extraspace; -if ($allowspaces) { - $extraspace='\s*'; -} else { - $extraspace=''; -} - -# append context lists to text lists (as text property is implied) -push @TEXTCMDLIST, @CONTEXT1CMDLIST; -push @TEXTCMDLIST, @CONTEXT2CMDLIST; - -push @TEXTCMDLIST, @MATHTEXTCMDLIST if $mathmarkup==COARSE; - -# internal additions to SAFECMDLIST -push(@SAFECMDLIST, qr/^QLEFTBRACE$/, qr/^QRIGHTBRACE$/); - - -# Patterns. These are used by some of the subroutines, too -# I can only define them down here because value of extraspace depends on an option - my $pat0 = '(?:[^{}])*'; - my $pat1 = '(?:[^{}]|\{'.$pat0.'\})*'; - my $pat2 = '(?:[^{}]|\{'.$pat1.'\})*'; - my $pat3 = '(?:[^{}]|\{'.$pat2.'\})*'; - my $pat4 = '(?:[^{}]|\{'.$pat3.'\})*'; - my $pat5 = '(?:[^{}]|\{'.$pat4.'\})*'; - my $pat6 = '(?:[^{}]|\{'.$pat5.'\})*'; - my $brat0 = '(?:[^\[\]]|\\\[|\\\])*'; - - my $quotemarks = '(?:\'\')|(?:\`\`)'; - my $punct='[0.,\/\'\`:;\"\?\(\)\[\]!~\p{IsNonAsciiPunct}\p{IsNonAsciiS}]'; - my $number='-?\d*\.\d*'; - my $mathpunct='[+=<>\-\|]'; - my $and = '&'; - my $coords= '[\-.,\s\d]*'; -# word: sequence of letters or accents followed by letter - my $word='(?:[-\w\d*]|\\\\[\"\'\`~^][A-Za-z\*])+'; - my $cmdleftright='\\\\(?:left|right|[Bb]igg?[lrm]?|middle)\s*(?:[()\[\]|]|\\\\(?:[|{}]|\w+))'; - - my $cmdoptseq='\\\\[\w\d\*]+'.$extraspace.'(?:(?:\['.$brat0.'\]|\{'. $pat6 . '\}|\(' . $coords .'\))'.$extraspace.')*'; - my $backslashnl='\\\\\n'; - my $oneletcmd='\\\\.\*?(?:\['.$brat0.'\]|\{'. $pat6 . '\})*'; - my $math='\$(?:[^$]|\\\$)*?\$|\\\\[(].*?\\\\[)]'; -## the current maths command cannot cope with newline within the math expression - - my $comment='%.*?\n'; - my $pat=qr/(?:\A\s*)?(?:${and}|${quotemarks}|${number}|${word}|$cmdleftright|${cmdoptseq}|${math}|${backslashnl}|${oneletcmd}|${comment}|${punct}|${mathpunct}|\{|\})\s*/ ; - - - -# now we are done setting up and can start working -my ($oldfile, $newfile) = @ARGV; -# check for existence of input files -if ( ! -e $oldfile ) { - die "Input file $oldfile does not exist."; -} -if ( ! -e $newfile ) { - die "Input file $newfile does not exist."; -} - - -# set the labels to be included into the file -my ($oldtime,$newtime,$oldlabel,$newlabel); -if (defined($labels[0])) { - $oldlabel=$labels[0] ; -} else { - $oldtime=localtime((stat($oldfile))[9]); - $oldlabel="$oldfile " . " "x(length($newfile)-length($oldfile)) . $oldtime; -} -if (defined($labels[1])) { - $newlabel=$labels[1] ; -} else { - $newtime=localtime((stat($newfile))[9]); - $newlabel="$newfile " . " "x(length($oldfile)-length($newfile)) . $newtime; -} - -$encoding=guess_encoding($newfile) unless defined($encoding); - -$encoding = "utf8" if $encoding =~ m/^utf8/i ; -if (lc($encoding) eq "utf8" ) { - binmode(STDOUT, ":utf8"); - binmode(STDERR, ":utf8"); -} - -$old=read_file_with_encoding($oldfile,$encoding); -$new=read_file_with_encoding($newfile,$encoding); - - - - -# reset time -exetime(1); -($oldpreamble,$oldbody,$oldpost)=splitdoc($old,'\\\\begin\{document\}','\\\\end\{document\}'); - - -($newpreamble,$newbody,$newpost)=splitdoc($new,'\\\\begin\{document\}','\\\\end\{document\}'); - - -if ($flatten) { - $oldbody=flatten($oldbody,$oldpreamble,$oldfile,$encoding); - $newbody=flatten($newbody,$newpreamble,$newfile,$encoding); -} - -my @auxlines; -if ( length $oldpreamble && length $newpreamble ) { - # pre-process preamble by looking for commands used in \maketitle (title, author, date etc commands) - # and marking up content with latexdiff markup - @auxlines=preprocess_preamble($oldpreamble,$newpreamble); - - @oldpreamble = split /\n/, $oldpreamble; - @newpreamble = split /\n/, $newpreamble; - - # If a command is defined in the preamble of the new file, and only uses safe commands, then it can be considered to be safe) (contribution S. Gouezel) - # Base this assessment on the new preamble - add_safe_commands($newpreamble); - - %packages=list_packages(@newpreamble) unless %packages; - if (defined $packages{"hyperref"} ) { - print STDERR "hyperref package detected.\n" if $verbose ; - $latexdiffpreamble =~ s/\{\\DIFadd\}/{\\DIFaddtex}/g; - $latexdiffpreamble =~ s/\{\\DIFdel\}/{\\DIFdeltex}/g; - $latexdiffpreamble .= join "\n",(extrapream("HYPERREF"),""); - } - print STDERR "Differencing preamble.\n" if $verbose; - - # insert dummy first line such that line count begins with line 1 (rather than perl's line 0) - just so that line numbers inserted by linediff are correct - unshift @newpreamble,''; - unshift @oldpreamble,''; - @diffpreamble = linediff(\@oldpreamble, \@newpreamble); - # remove dummy line again - shift @diffpreamble; - # add filenames, modification time and latexdiff mark - defined($nolabel) or splice @diffpreamble,1,0, - "%DIF LATEXDIFF DIFFERENCE FILE", - ,"%DIF DEL $oldlabel", - "%DIF ADD $newlabel"; - if ( @auxlines ) { - push @diffpreamble,"%DIF DELETED TITLE COMMANDS FOR MARKUP"; - push @diffpreamble,join("\n",@auxlines); - } - push @diffpreamble,$latexdiffpreamble; - push @diffpreamble,'\begin{document}'; -} -elsif ( !length $oldpreamble && !length $newpreamble ) { - @diffpreamble=(); -} else { - print STDERR "Either both texts must have preamble or neither text must have the preamble.\n"; - exit(2); -} - -if (defined $packages{"amsmath"} or defined $packages{"amsart"} or defined $packages{"amsbook"} ) { - print STDERR "amsmath package detected.\n" if $verbose ; - $MATHARRREPL='align*'; -} - -print STDERR "Preprocessing body. " if $verbose; -my ($oldleadin,$newleadin)=preprocess($oldbody,$newbody); - - -# run difference algorithm -@diffbody=bodydiff($oldbody, $newbody); -$diffbo=join("",@diffbody); -if ( $debug ) { - open(RAWDIFF,">","latexdiff.debug.bodydiff"); - print RAWDIFF $diffbo; - close(RAWDIFF); -} -print STDERR "(",exetime()," s)\n","Postprocessing body. \n " if $verbose; -postprocess($diffbo); -$diffall =join("\n",@diffpreamble) ; -# add visible labels -if (defined($visiblelabel)) { - # Give information right after \begin{document} (or at the beginning of the text for files without preamble - ### if \date command is used, add information to \date argument, otherwise give right after \begin{document} - ### $diffall=~s/(\\date$extraspace(?:\[$brat0\])?$extraspace)\{($pat6)\}/$1\{$2 \\ LATEXDIFF comparison \\ Old: $oldlabel \\ New: $newlabel \}/ or - $diffbo = "\\begin{verbatim}LATEXDIFF comparison\nOld: $oldlabel\nNew: $newlabel\\end{verbatim}\n$diffbo" ; -} - -$diffall .= "$newleadin$diffbo" ; -$diffall .= "\\end{document}$newpost" if length $newpreamble ; -if ( lc($encoding) ne "utf8" && lc($encoding) ne "ascii" ) { - print STDERR "Encoding output file to $encoding\n" if $verbose; - $diffall=Encode::encode($encoding,$diffall); - binmode STDOUT; -} -print $diffall; - - -print STDERR "(",exetime()," s)\n","Done.\n" if $verbose; - - - -## guess_encoding(filename) -## reads the first 20 lines of filename and looks for call of inputenc package -## if found, return the option of this package (encoding), otherwise return ascii -sub guess_encoding { - my ($filename)=@_; - my ($i,$enc); - open (FH, $filename) or die("Couldn't open $filename: $!"); - $i=0; - while () { - next if /^\s*%/; # skip comment lines - if (m/\\usepackage\[(\w*?)\]\{inputenc\}/) { - close(FH); - return($1); - } - last if (++$i > 20 ); # scan at most 20 non-comment lines - } - close(FH); - return("ascii"); -} - - -sub read_file_with_encoding { - my ($output); - my ($filename, $encoding) = @_; - - if (lc($encoding) eq "utf8" ) { - open (FILE, "<:utf8",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } elsif ( lc($encoding) eq "ascii") { - open (FILE, $filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } else { - require Encode; - open (FILE, "<",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - print STDERR "Converting $filename from $encoding to utf8\n" if $verbose; - $output=Encode::decode($encoding,$output); - } - close FILE; - if ($^O eq "linux" ) { - $output =~ s/\r\n/\n/g ; - } - return $output; -} - -# %packages=list_packages(@preamble) -# scans the arguments for \documentclass and \usepackage statements and constructs a hash -# whose keys are the included packages, and whose values are the associated optional arguments -sub list_packages { - my (@preamble)=@_; - my %packages=(); - foreach $line ( @preamble ) { - # get rid of comments - $line=~s/(?catfile($dirname,$fname), "\n" if $debug; - # content of file becomes replacement value (use recursion), add \newpage if the command was include - ###$replacement=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - $replacement=flatten(read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding), $preamble,$filename,$encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - # \include always starts a new page; use explicit \newpage command to simulate this - $begline=(defined($1)? $1 : "") ; - $newpage=(defined($3)? " \\newpage " : "") ; - "$begline$newpage$replacement$newpage"; - }/exgm; - - return($text); -} - - -# print_regex_arr(@arr) -# prints regex array without x-ism expansion put in by pearl to stdout -sub print_regex_arr { - my $dumstring; - $dumstring = join(" ",@_); # PERL generates string (?-xism:^ref$) for quoted refex ^ref$ - $dumstring =~ s/\(\?-xism:\^(.*?)\$\)/$1/g; # remove string and ^,$ marks before output - print $dumstring,"\n"; -} - - -# @lines=extrapream($type) -# reads line from appendix (end of file after __END__ token) -sub extrapream { - my $type; - my @retval=("%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - my ($copy); - - while (@_) { - $copy=0; - $type=shift ; - if ( -f $type ) { - open (FILE,$type) or die "Cannot open preamble file $type: $!"; - print STDERR "Reading preamble file $type\n" if $verbose ; - while () { - chomp ; - if ( $_ =~ m/%DIF PREAMBLE/ ) { - push (@retval,"$_"); - } else { - push (@retval,"$_ %DIF PREAMBLE"); - } - } - } - else { # not (-f $type) - $type=uc($type); # upcase argument - print STDERR "Preamble Internal Type $type\n" if $verbose; - while () { - if ( m/^%DIF $type/ ) { - $copy=1; } - elsif ( m/^%DIF END $type/ ) { - last; } - chomp; - push (@retval,"$_ %DIF PREAMBLE") if $copy; - } - if ( $copy == 0 ) { - print STDERR "\nPreamble style $type not implemented.\n"; - print STDERR "Write latexdiff -h to get help with available styles\n"; - exit(2); - } - seek DATA,0,0; # rewind DATA handle to file begin - } - } - push (@retval,"%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - return @retval; -} - - -# ($part1,$part2,$part3)=splitdoc($text,$word1,$word2) -# splits $text into 3 parts at $word1 and $word2. -# if neither $word1 nor $word2 exist, $part1 and $part3 are empty, $part2 is $text -# If only $word1 or $word2 exist but not the other, output an error message. - -# NB this version avoids $` and $' for performance reason although it only makes a tiny difference -# (in one test gain a tenth of a second for a 30s run) -sub splitdoc { - my ($text,$word1,$word2)=@_; - my ($part1,$part2,$part3)=("","",""); - my ($rest,$pos); - - if ( $text =~ m/(^[^%]*)($word1)/mg ) { - $pos=pos $text; - $part1=substr($text,0,$pos-length($2)); - $rest=substr($text,$pos); - if ( $rest =~ m/(^[^%]*)($word2)/mg ) { - $pos=pos $rest; - $part2=substr($rest,0,$pos-length($2)); - $part3=substr($rest,$pos); - } - else { - die "$word1 and $word2 not in the correct order or not present as a pair." ; - } - } else { - $part2=$text; - die "$word2 present but not $word1." if ( $text =~ m/(^[^%]*)$word2/ms ); - } - return ($part1,$part2,$part3); -} - - - - - -# bodydiff($old,$new) -sub bodydiff { - my ($oldwords, $newwords) = @_; - my @retwords; - - print STDERR "(",exetime()," s)\n","Splitting into latex tokens \n" if $verbose; - print STDERR "Parsing $oldfile \n" if $verbose; - my @oldwords = splitlatex($oldwords); - print STDERR "Parsing $newfile \n" if $verbose; - my @newwords = splitlatex($newwords); - - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - print STDERR "(",exetime()," s)\n","Pass 1: Expanding text commands and merging isolated identities with changed blocks " if $verbose; - pass1(\@oldwords, \@newwords); - - - print STDERR "(",exetime()," s)\n","Pass 2: inserting DIF tokens and mark up. " if $verbose; - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold2.tex"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew2.tex"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - @retwords=pass2(\@oldwords, \@newwords); - - return(@retwords); -} - - - - -# @words=splitlatex($string) -# split string according to latex rules -# Each element of words is either -# a word (including trailing spaces and punctuation) -# a latex command -sub splitlatex { - my ($string) = @_ ; - # if input is empty, return empty list - length($string)>0 or return (); - - my @retval=($string =~ m/$pat/osg); - - if (length($string) != length(join("",@retval))) { - print STDERR "\nWARNING: Inconsistency in length of input string and parsed string:\n This often indicates faulty or non-standard latex code.\n In many cases you can ignore this and the following warning messages.\n Note that character numbers in the following are counted beginning after \\begin{document} and are only approximate." unless $ignorewarnings; - print STDERR "DEBUG Original length ",length($string)," Parsed length ",length(join("",@retval)),"\n" if $debug; - print STDERR "DEBUG Input string: |$string|\n" if (length($string)<500) && $debug; - print STDERR "DEBUG Token parsing: |",join("+",@retval),"|\n" if (length($string)<500) && $debug ; - @retval=(); - # slow way only do this if other m//sg method fails - my $last = 0; - while ( $string =~ m/$pat/osg ) { - my $match=$&; - if ($last + length $& != pos $string ) { - my $pos=pos($string); - my $offset=30<$last ? 30 : $last; - my $dum=substr($string,$last-$offset,$pos-$last+2*$offset); - my $dum1=$dum; - my $cnt=$#retval; - my $i; - $dum1 =~ s/\n/ /g; - unless ($ignorewarnings) { - print STDERR "\n$dum1\n"; - print STDERR " " x 30,"^" x ($pos-$last)," " x 30,"\n"; - print STDERR "Missing characters near word " . (scalar @retval) . " character index: " . $last . "-" . pos($string) . " Length: " . length($match) . " Match: |$match| (expected match marked above).\n"; - } - # put in missing characters `by hand' - push (@retval, substr($dum,$offset,$pos-$last-length($match))); -# Note: there seems to be a bug in substr with utf8 that made the following line output substr which were too long, -# using dum instead appears to work -# push (@retval, substr($string,$last, pos($string)-$last-length($match))); - } - push (@retval, $match); - $last=pos $string; - } - - } - return @retval; -} - - -# pass1( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Where an common-subsequence block is flanked by deleted or appended blocks, -# and is shorter than $MINWORDSBLOCK words it is appended -# to the last deleted or appended word. If the block contains tokens other than words -# or punctuation it is not merged. -# Deleted or appended block consisting of words and safe commands only are -# also merged, to prevent break-up in pass2 (after previous isolated words have been removed) -# If there are commands with textual arguments (e.g. \caption) both in corresponding -# appended and deleted blocks split them such that the command and opening bracket -# are one token, then the rest is split up following standard rules, and the closing -# bracket is a separate token, ie. turn -# "\caption{This is a textual argument}" into -# ("\caption{","This ","is ","a ","textual ","argument","}") -# No return value. Destructively changes sequences -sub pass1 { - my $seq1 = shift ; - my $seq2 = shift ; - - my $len1 = scalar @$seq1; - my $len2 = scalar @$seq2; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - - my ($last1,$last2)=(-1,-1) ; - my $cnt=0; - my $block=[]; - my $addblock=[]; - my $delblock=[]; - my $todo=[]; - my $instruction=[]; - my $i; - my (@delmid,@addmid,@dummy); - - my ($addcmds,$delcmds,$matchindex); - my ($addtextblocks,$deltextblocks); - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $adddiscard = sub { - if ($cnt > 0 ) { - $matblkcnt++; - # just after an unchanged block -# print STDERR "Unchanged block $cnt, $last1,$last2 \n"; - if ($cnt < $MINWORDSBLOCK - && $cnt==scalar ( - grep { /^$wpat/ || ( /^\\([\w\d\*]+)((?:\[$brat0\]|\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && scalar(@dummy=split(" ",$2))<3 ) } - @$block) ) { - # merge identical blocks shorter than $MINWORDSBLOCK - # and only containing ordinary words - # with preceding different word - # We cannot carry out this merging immediately as this - # would change the index numbers of seq1 and seq2 and confuse - # the algorithm, instead we store in @$todo where we have to merge - push(@$todo, [ $last1,$last2,$cnt,@$block ]); - } - $block = []; - $cnt=0; $last1=-1; $last2=-1; - } - }; - my $discard=sub { $deltokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$delblock,[ $seq1->[$_[0]],$_[0] ]); - $last1=$_[0] }; - - my $add = sub { $addtokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$addblock,[ $seq2->[$_[1]],$_[1] ]); - $last2=$_[1] }; - - my $match = sub { $mattokcnt++; - if ($cnt==0) { # first word of matching sequence after changed sequence or at beginning of word sequence - $deltextblocks = extracttextblocks($delblock); - $delblkcnt++ if scalar @$delblock; - $addtextblocks = extracttextblocks($addblock); - $addblkcnt++ if scalar @$addblock; - - $delcmds = extractcommands($delblock); - $addcmds = extractcommands($addblock); - # keygen(third argument of _longestCommonSubsequence) implies to sort on command (0th elements of $addcmd elements) - # the calling format for longestCommonSubsequence has changed between versions of - # Algorithm::Diff so we need to check which one we are using - if ( $algodiffversion > 1.15 ) { - ### Algorithm::Diff 1.19 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, 0, sub { $_[0]->[0] } ); - } else { - ### Algorithm::Diff 1.15 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, sub { $_[0]->[0] } ); - } - - for ($i=0 ; $i<=$#$matchindex ; $i++) { - if (defined($matchindex->[$i])){ - $j=$matchindex->[$i]; - @delmid=splitlatex($delcmds->[$i][3]); - @addmid=splitlatex($addcmds->[$j][3]); - while (scalar(@$deltextblocks) && $deltextblocks->[0][0]<$delcmds->[$i][1]) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) }; - push(@$todo, [$index,-1,$cnt,@$block]); - } - push(@$todo, [ $delcmds->[$i][1],-1,-1,$delcmds->[$i][2],@delmid,$delcmds->[$i][4]]); - - while (scalar(@$addtextblocks) && $addtextblocks->[0][0]<$addcmds->[$j][1]) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - push(@$todo, [ -1,$addcmds->[$j][1],-1,$addcmds->[$j][2],@addmid,$addcmds->[$j][4]]); - } - } - # mop up remaining textblocks - while (scalar(@$deltextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) } ; - push(@$todo, [$index,-1,$cnt,@$block]); - } - while (scalar(@$addtextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - - $addblock=[]; - $delblock=[]; - } - push(@$block,$seq2->[$_[1]]); - $cnt++ }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - - - # now carry out the merging/splitting. Refer to elements relative from - # the end (with negative indices) as these offsets don't change before the instruction is executed - # cnt>0: merged small unchanged groups with previous changed blocks - # cnt==-1: split textual commands into components - foreach $instruction ( @$todo) { - ($last1,$last2,$cnt,@$block)=@$instruction ; - if ($cnt>=0) { - splice(@$seq1,$last1-$len1,1+$cnt,join("",$seq1->[$last1-$len1],@$block)) if $last1>=0; - splice(@$seq2,$last2-$len2,1+$cnt,join("",$seq2->[$last2-$len2],@$block)) if $last2>=0; - } else { - splice(@$seq1,$last1-$len1,1,@$block) if $last1>=0; - splice(@$seq2,$last2-$len2,1,@$block) if $last2>=0; - } - } - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens in $matblkcnt blocks.\n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } -} - - -# extracttextblocks(\@blockindex) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [[ $index, $textblock, $cnt ], .. -# where $index index of block to be merged -# $textblock contains all the words to be merged with the word at $index (but does not contain this word) -# $cnt is length of block -# -# requires: iscmd -# -sub extracttextblocks { - my $block=shift; - my ($i,$token,$index); - my $textblock=[]; - my $last=-1; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # store pure text blocks - if ($token =~ /$wpat/ || ( $token =~/^\\([\w\d\*]+)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && !iscmd($1,\@TEXTCMDLIST,\@TEXTCMDEXCL))) { - # we have text or a command which can be treated as text - if ($last<0) { - # new pure-text block - $last=$index; - } else { - # add to pure-text block - push(@$textblock, $token); - } - } else { - # it is not text - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - $textblock=[]; - $last=-1; - } - } - # finish processing a possibly unfinished block before returning - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - return($retval) -} - - - -# extractcommands( \@blockindex ) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [ [ "\cmd1", index, "\cmd1[optarg]{arg1}{", "arg2" ,"} " ],.. -# where index is just taken from input array -# command must have a textual argument as last argument -# -# requires: iscmd -# -sub extractcommands { - my $block=shift; - my ($i,$token,$index,$cmd,$open,$mid,$closing); - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: \cmd - # $3: last argument - # $4: } + trailing spaces - if ( ( $token =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL) ) { - # push(@$retval,[ $2,$index,$1,$3,$4 ]); - ($cmd,$open,$mid,$closing) = ($2,$1,$3,$4) ; - $closing =~ s/\}/\\RIGHTBRACE/ ; - push(@$retval,[ $cmd,$index,$open,$mid,$closing ]); - } - } - return $retval; -} - -# iscmd($cmd,\@regexarray,\@regexexcl) checks -# return 1 if $cmd matches any of the patterns in the -# array $@regexarray, and none of the patterns in \@regexexcl, otherwise return 0 -sub iscmd { - my ($cmd,$regexar,$regexexcl)=@_; - my ($ret)=0; - foreach $pat ( @$regexar ) { - if ( $cmd =~ m/^${pat}$/ ) { - $ret=1 ; - last; - } - } - return 0 unless $ret; - foreach $pat ( @$regexexcl ) { - return 0 if ( $cmd =~ m/^${pat}$/ ); - } - return 1; -} - - -# pass2( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Mark begin and end of deleted and appended sequences with tags $DELOPEN and $DELCLOSE -# and $ADDOPEN and $ADDCLOSE, respectively, however exclude { } & and all comands, unless -# they match an element of the whitelist (SAFECMD) -# For words in TEXTCMD but not in SAFECMD, enclose interior with $ADDOPEN and $ADDCLOSE brackets -# Deleted comment lines are marked with %DIF < -# Added comment lines are marked with %DIF > -sub pass2 { - my $seq1 = shift ; - my $seq2 = shift ; - - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $retval = []; - my $delhunk = []; - my $addhunk = []; - - my $discard = sub { $deltokcnt++; - push ( @$delhunk, $seq1->[$_[0]]) }; - - my $add = sub { $addtokcnt++; - push ( @$addhunk, $seq2->[$_[1]]) }; - - my $match = sub { $mattokcnt++; - if ( scalar @$delhunk ) { - $delblkcnt++; - # mark up changes, but comment out commands - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk); - $delhunk = []; - } - if ( scalar @$addhunk ) { - $addblkcnt++; - # we mark up changes, but simply quote commands - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk); - $addhunk = []; - } - push(@$retval,$seq2->[$_[1]]) }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - # clear up unprocessed hunks - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk) if scalar @$delhunk; - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk) if scalar @$addhunk; - - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens. \n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } - - return(@$retval); -} - -# marktags($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,\@block) -# returns ($openmark,$open,$block,$close,$closemark) if @block only contains no commands (except white-listed ones), -# braces, ampersands, or comments -# mark comments with $comment -# exclude all other exceptions from scope of open, close like this -# ($openmark, $open,...,$close, $opencmd,command, command,$closecmd, $open, ..., $close, $closemark) -# If $opencmd begins with "%" marktags assumes it is operating on a deleted block, otherwise on an added block -sub marktags { - my ($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,$block)=@_; - my $word; - my (@argtext); - my $retval=[]; - my $noncomment=0; - my $cmd=-1; # -1 at beginning 0: last token written is a ordinary word - # 1: last token written is a command - # for keeping track whether we are just in a command sequence or in a word sequence - my $cmdcomment= ($opencmd =~ m/^%/); # Flag to indicate whether opencmd is a comment (i.e. if we intend to simply comment out changed commands) - my ($command,$commandword,$closingbracket) ; # temporary variables needed below to remember sub-pattern matches - -# split this block to flatten out sequences joined in pass1 - @$block=splitlatex(join "",@$block); - foreach (@$block) { - $word=$_; - if ( $word =~ s/^%/%$comment/ ) { - # a comment - if ($cmd==1) { - push (@$retval,$closecmd) ; - $cmd=-1; - } - push (@$retval,$word); - next; - } - if (! $noncomment) { - push (@$retval,$openmark); - $noncomment=1; - } - # negative lookahead pattern (?!) in second clause is put in to avoid mathcing \( .. \) patterns - # also note that second pattern will match \\ - # Note: the second pattern should really be $word =~ /^\\(?!\()(\\|[\w*@]+)/, ie * replaced by + - # and then all commands \" \' etc declared safe. But as I don't have a complete list of one letter - # commands, and nobody has complained so far, I will eave this as is - if ( $word =~ /^[&{}\[\]]/ || ( $word =~ /^\\(?!\()(\\|[\w*@]*)/ && !iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL)) ) { - # word is a command or other significant token (not in SAFECMDLIST) - ## same conditions as in subroutine extractcommand: - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: cmd - # $3: last argument - # $4: } + trailing spaces - ### pre-0.3 if ( ( $token =~ m/^(\\([\w\d\*]+)(?:\[$brat0\]|\{$pat6\})*\{)($pat6)(\}\s*)$/so ) - if ( ( $word =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && (iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL)|| iscmd($2,\@MATHTEXTCMDLIST,\@MATHTEXTCMDEXCL)) - && ( !$cmdcomment || !iscmd($2,\@CONTEXT2CMDLIST, \@CONTEXT2CMDEXCL) ) ) { - # Condition 1: word is a command? - if yes, $1,$2,.. will be set as above - # Condition 2: word is a text command - we mark up the interior of the word. There is a separate check for MATHTEXTCMDLIST - # because for $mathmarkup=WHOLE, the commands should not be split in pass1 (ie. math mode commands are not in - # TEXTCMDLIST, but the interior of MATHTEXT commands should be highlighted in both deleted and added blocks - # Condition 3: But if we are in a deleted block ($cmdcomment=1) and - # $2 (the command) is in context2, just treat it as an ordinary command (i.e. comment it open with $opencmd) - # Because we do not want to disable this command - # here we do not use $opencmd and $closecmd($opencmd is empty) - if ($cmd==1) { - push (@$retval,$closecmd) ; - } elsif ($cmd==0) { - push (@$retval,$close) ; - } - $command=$1; $commandword=$2; $closingbracket=$4; - @argtext=splitlatex($3); # split textual argument into tokens - # and mark it up (but we do not need openmark and closemark) - # insert command with initial arguments, marked-up final argument, and closing bracket - if ( $cmdcomment && iscmd($commandword,\@CONTEXT1CMDLIST, \@CONTEXT1CMDEXCL) ) { - # context1cmd in a deleted environment; delete command itself but keep last argument, marked up - push (@$retval,$opencmd); - $command =~ s/\n/\n${opencmd}/sg ; # repeat opencmd at the beginning of each line - # argument, note that the additional comment character is included - # to suppress linebreak after opening parentheses, which is important - # for latexrevise - push (@$retval,$command,"%\n{$AUXCMD\n",marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } elsif ( iscmd($commandword,,\@MATHTEXTCMDLIST, \@MATHTEXTCMDEXCL) ) { - # MATHBLOCK pseudo command: consider all commands safe, except & and \\ - # Keep these commands even in deleted blocks, hence set $opencmd and $closecmd (5th and 6th argument of marktags) to - # "" - local @SAFECMDLIST=(".*"); - local @SAFECMDEXCL=('\\','\\\\'); - push(@$retval,$command,marktags("","",$open,$close,"","",$comment,\@argtext)#@argtext - ,$closingbracket); - } else { - # normal textcmd or context1cmd in an added block - push (@$retval,$command,marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } - push (@$retval,$AUXCMD,"\n") if $cmdcomment ; - $cmd=-1 ; - } else { - # ordinary command - push (@$retval,$opencmd) if $cmd==-1 ; - push (@$retval,$close,$opencmd) if $cmd==0 ; - $word =~ s/\n/\n${opencmd}/sg if $cmdcomment ; # if opencmd is a comment, repeat this at the beginning of every line - push (@$retval,$word); - $cmd=1; - } - } else { - # just an ordinary word or word in SAFECMD - push (@$retval,$open) if $cmd==-1 ; - push (@$retval,$closecmd,$open) if $cmd==1 ; - push (@$retval,$word); - $cmd=0; - } - } - push (@$retval,$close) if $cmd==0; - push (@$retval,$closecmd) if $cmd==1; - - push (@$retval,$closemark) if ($noncomment); - return @$retval; -} - -# preprocess($string, ..) -# carry out the following pre-processing steps for all arguments: -# 1. Remove leading white-space -# Change \{ to \LEFTBRACE and \} to \RIGHTBRACE -# #. change begin and end commands within comments to BEGINDIF, ENDDIF -# so they don't disturb the pattern matching (if there are several \begin or \end in one line -# 2. mark all first empty line (in block of several) with \PAR tokens -# 3. Convert all '\%' into '\PERCENTAGE ' to make parsing regular expressions easier -# 4. Convert all \verb|some verbatim text| commands (where | can be an arbitrary character) -# into \verb{hash} -# 5. Convert \begin{verbatim} some verbatim text \end{verbatim} into \verbatim{hash} -# 6. Convert _n into \SUBSCRIPTNB{n} and _{nnn} into \SUBSCRIPT{nn} -# 7. Convert ^n into \SUPERSCRIPTNB{n} and ^{nnn} into \SUPERSCRIPT{nn} -# 8. a. Convert $$ $$ into \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} -# b. Convert \[ \] into \begin{SQUAREBRACKET} \end{SQUAREBRACKET} -# 9. Convert all picture environmentent (\begin{PICTUREENV} .. \end{PICTUREENV} \PICTUREBLOCKenv -# For --block-math-markup option -convert all \begin{MATH} .. \end{MATH} -# into \MATHBLOCKmath{...} commands, where MATH/math is any valid math environment - -# 10. Add final token STOP to the very end. This is put in because the algorithm works better if the last token is identical. This is removed again in postprocessing. -# -# NB: step 6 and 7 is likely to convert some "_" inappropriately, e.g. in file -# names or labels but it does not matter because they are converted back in the postprocessing step -# Returns: leading white space removed in step 1 -sub preprocess { - my @leadin=() ; - for (@_) { - s/^(\s*)//s; - push(@leadin,$1); - # Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE - s/(?{$hstr}) && $string ne $hash->{$hstr}) { - warn "Repeated hash value for verbatim mode in spite of different content."; - $hstr="-$hstr"; - } - $hash->{$hstr}=$string; - return($hstr); -} - -#string=fromhash(\%hash,$fromstring) -# restores string value stored in hash -#string=fromhash(\%hash,$fromstring,$prependstring) -# additionally begins each line with prependstring -sub fromhash { - my ($hash,$hstr)=($_[0],$_[1]); - my $retstr=$hash->{$hstr}; - if ( $#_ >= 2) { - $retstr =~ s/^/$_[2]/mg; - } - return $retstr; -} - - -# postprocess($string, ..) -# carry out the following post-processing steps for all arguments: -# * Remove STOP token from the end -# * Replace \RIGHTBRACE by } -# * change citation commands within comments to protect from processing (using marker CITEDIF) -# 1. Check all deleted blocks: -# a.where a deleted block contains a matching \begin and -# \end environment (these will be disabled by a %DIFDELCMD statements), for selected environments enable -# these commands again (such that for example displayed math in a deleted equation -# is properly within math mode. For math mode environments replace numbered equation -# environments with their display only variety (so that equation numbers in new file and -# diff file are identical). Where the correct type of math environment cannot be determined -# use a place holder MATHMODE -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file -# Replace all MATHMODE environment commands by the correct environment to achieve matching -# pairs -# c. Convert MATHBLOCKmath commands to their uncounted numbers (e.g. convert equation -> displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL -# d. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# For added blocks: -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# 2. If --block-math-markup option set: Convert \MATHBLOCKmath{..} commands back to environments -# -# Convert all PICTUREblock{..} commands back to the appropriate environments -# 3. Convert DIFadd, DIFdel, DIFFaddbegin , ... into FL varieties -# within floats (currently recognised float environments: plate,table,figure -# plus starred varieties). -# 4. Remove empty %DIFDELCMD < lines -# 4. Convert \begin{SQUAREBRACKET} \end{SQUAREBRACKET} into \[ \] -# Convert \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} into $$ $$ -# 5. Convert \SUPERSCRIPTNB{n} into ^n and \SUPERSCRIPT{nn} into ^{nnn} -# 6. Convert \SUBSCRIPTNB{n} into _n and \SUBCRIPT{nn} into _{nnn} -# 7. Expand hashes of verb and verbatim environments -# 8. Convert '\PERCENTAGE ' back into '\%' -# 9.. remove all \PAR tokens -# 10. package specific processing: endfloat: make sure \begin{figure} and \end{figure} are always -# on a line by themselves, similarly for table environment -# 4, undo renaming of the \begin and \end in comments -# Change \QLEFTBRACE, \QRIGHTBRACE to \{,\} -# -# Note have to manually synchronize substitution commands below and -# DIF.. command names in the header -sub postprocess { - my ($begin,$len,$cnt,$float,$delblock,$addblock); - # second level blocks - my ($begin2,$cnt2,$len2,$eqarrayblock,$mathblock); - - for (@_) { - - # change $'s in comments to something harmless - 1 while s/(%.*)\$/$1DOLLARDIF/mg ; - - # Remove final STOP token - s/ STOP$//; - # Replace \RIGHTBRACE by } - s/\\RIGHTBRACE/}/g; - - # change citation commands within comments to protect from processing - if ($CITECMD){ - 1 while s/(%.*)\\($CITECMD)/$1\\CITEDIF$2/m ; - } - # Check all deleted blocks: where a deleted block contains a matching \begin and - # \end environment (these will be disabled by a %DIFDELCMD statements), enable - # these commands again (such that for example displayed math in a deleted equation - # is properly within math mode. For math mode environments replace numbered equation - # environments with their display only variety (so that equation numbers in new file and - # diff file are identical - while ( m/\\DIFdelbegin.*?\\DIFdelend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $delblock=$&; - - - ### (.*?[^\n]?)\n? construct is necessary to avoid empty lines in math mode, which result in - ### an error - # displayed math environments - if ($mathmarkup == FINE ) { - $delblock=~ s/(\%DIFDELCMD < \s*\\begin\{((?:$MATHENV)|SQUAREBRACKET)\}.*?(?:$DELCMDCLOSE|\n))(.*?[^\n]?)\n?(\%DIFDELCMD < \s*\\end\{\2\})/\\begin{$MATHREPL}$AUXCMD\n$1$3\n\\end{$MATHREPL}$AUXCMD\n$4/sg; - # also transform the opposite pair \end{displaymath} .. \begin{displaymath} but we have to be careful not to interfere with the results of the transformation in the line directly above - ### pre-0.42 obsolete version which did not work on eqnarray test $delblock=~ s/(? displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL - $delblock=~ s/\\MATHBLOCK($MATHENV)\{($pat6)\}/\\MATHBLOCK$MATHREPL\{$2\}/sg; - $delblock=~ s/\\MATHBLOCK($MATHARRENV)\{($pat6)\}/\\MATHBLOCK$MATHARRREPL\{$2\}/sg; - } - - -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file - $delblock=~ s/\\($COUNTERCMD)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*\s*${AUXCMD}\n)/\\$1$2\\addtocounter{$1}{-1}${AUXCMD}\n/sg ; - - -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es - while ( $delblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($delblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($delblock,$begin2,$len2)=$mathblock; - pos($delblock) = $begin2 + length($mathblock); - } - if ($CITE2CMD) { - $delblock=~s/($DELCMDOPEN\s*\\($CITE2CMD)(.*)$DELCMDCLOSE)/ - # Replacement code - {my ($aux,$all); - $aux=$all=$1; - $aux=~s#\n?($DELCMDOPEN|$DELCMDCLOSE)##g; - $all."$aux$AUXCMD\n";}/sge; - } - # or protect \cite commands with \mbox - if ($CITECMD) { - $delblock=~s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat6\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified delblock - substr($_,$begin,$len)=$delblock; - pos = $begin + length($delblock); - } - # make the array modification in added blocks - while ( m/\\DIFaddbegin.*?\\DIFaddend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $addblock=$&; - while ( $addblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($addblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($addblock,$begin2,$len2)=$mathblock; - pos($addblock) = $begin2 + length($mathblock); - } - if ($CITECMD) { - my $addblockbefore=$addblock; - $addblock=~ s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat2\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified addblock - substr($_,$begin,$len)=$addblock; - pos = $begin + length($addblock); - } - - - ### old place for BEGINDIF, ENDDIF replacement - # change begin and end commands within comments such that they - # don't disturb the pattern matching (if there are several \begin or \end in one line - # this substitution is insufficient but that appears unlikely) - # This needs to be repeated here to also get rid of DIFdelcmd-protected environments - s/(%.*)\\begin\{(.*)$/$1\\BEGINDIF\{$2/mg ; - s/(%.*)\\end\{(.*)$/$1\\ENDDIF\{$2/mg ; - - # Replace MATHMODE environments from step 1a above by the correct Math environment - - # The next line is complicated. The negative look-ahead insertion makes sure that no \end{$MATHENV} (or other mathematical - # environments) are between the \begin{$MATHENV} and \end{MATHMODE} commands. This is necessary as the minimal matching - # is not globally minimal but only 'locally' (matching is beginning from the left side of the string) - if ( $mathmarkup == FINE ) { - 1 while s/\\begin{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}((?:.(?!(?:\\end{(?:(?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}|\\begin{MATHMODE})))*?)\\end{MATHMODE}/\\begin{$1}$2\\end{$1}/s; - 1 while s/\\begin{MATHMODE}((?:.(?!\\end{MATHMODE}))*?)\\end{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}/\\begin{$2}$1\\end{$2}/s; - # convert remaining \begin{MATHMODE} \end{MATHMODE} (and not containing & or \\ )into MATHREPL environments - s/\\begin{MATHMODE}((?:(.(?!(?[1])) { - $optargnew=$newhash{$cmd}->[1]; - } else { - $optargnew=""; - } - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - } else { - $optargold=""; - } - - if ( defined($oldhash{$cmd}) ) { - $argold=$oldhash{$cmd}->[2]; - } else { - $argold=""; - } - $argnew=$newhash{$cmd}->[2]; - $argdiff="{" . join("",bodydiff($argold,$argnew)) ."}"; - if ( length $optargnew ) { - $optargdiff="[".join("",bodydiff($optargold,$optargnew))."]" ; - $optargdiff =~ s/\\DIFaddbegin /\\DIFaddbeginFL /g; - $optargdiff =~ s/\\DIFaddend /\\DIFaddendFL /g; - $optargdiff =~ s/\\DIFadd\{/\\DIFaddFL{/g; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - ### print STDERR "DEBUG s/\\Q$newhash{$cmd}->[0]\\E/\\$cmd$optargdiff$argdiff/s\n"; - # Note: \Q and \E force literal interpretation of what it between them but allow - # variable interpolation, such that e.g. \title matches just that and not TAB-itle - $$newpreambleref=~s/\Q$newhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s; - # replace this in old preamble if necessary - if ( defined($oldhash{$cmd}->[0])) { - $$oldpreambleref=~s/\Q$oldhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s ; - } - ### print STDERR "DEBUG NEW PRE ".$$newpreambleref."\n"; - } - - foreach $cmd ( keys %oldhash ) { - # if this has already been dealt with above can just skip - next if defined($newhash{$cmd}) ; - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - $optargdiff="[".join("",bodydiff($optargold,""))."]" ; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - $argdiff="{" . join("",bodydiff($argold,"")) ."}"; - $auxline = "\\$cmd$optargdiff$argdiff"; - $auxline =~s/$/$AUXCMD/sg; - push @auxlines,$auxline; - } - # add auxcmd comment to highlight added lines - return(@auxlines); -} - - - -# @diffs=linediff(\@seq1, \@seq2) -# mark up lines like this -#%DIF mm-mmdnn -#%< old deleted line(s) -#%DIF ------- -#%DIF mmann-nn -#new appended line %< -#%DIF ------- -# Future extension: mark change explicitly -# Assumes: traverse_sequence traverses deletions before insertions in changed sequences -# all line numbers relative to line 0 (first line of real file) -sub linediff { - my $seq1 = shift ; - my $seq2 = shift ; - - my $block = []; - my $retseq = []; - my @begin=('','',''); # dummy initialisation - my $instring ; - - my $discard = sub { @begin=('d',$_[0],$_[1]) unless scalar @$block ; - push(@$block, "%DIF < " . $seq1->[$_[0]]) }; - my $add = sub { if (! scalar @$block) { - @begin=('a',$_[0],$_[1]) ;} - elsif ( $begin[0] eq 'd' ) { - $begin[0]='c'; $begin[2]=$_[1]; - push(@$block, "%DIF -------") } - push(@$block, $seq2->[$_[1]] . " %DIF > " ) }; - my $match = sub { if ( scalar @$block ) { - if ( $begin[0] eq 'd' && $begin[1]!=$_[0]-1) { - $instring = sprintf "%%DIF %d-%dd%d",$begin[1],$_[0]-1,$begin[2]; } - elsif ( $begin[0] eq 'a' && $begin[2]!=$_[1]-1) { - $instring = sprintf "%%DIF %da%d-%d",$begin[1],$begin[2],$_[1]-1; } - elsif ( $begin[0] eq 'c' ) { - $instring = sprintf "%%DIF %sc%s", - ($begin[1]==$_[0]-1) ? "$begin[1]" : $begin[1]."-".($_[0]-1) , - ($begin[2]==$_[1]-1) ? "$begin[2]" : $begin[2]."-".($_[1]-1) ; } - else { - $instring = sprintf "%%DIF %d%s%d",$begin[1],$begin[0],$begin[2]; } - push @$retseq, $instring,@$block, "%DIF -------" ; - $block = []; - } - push @$retseq, $seq2->[$_[1]] - }; - # key function: remove multiple spaces (such that insertion or deletion of redundant white space is not reported) - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - push @$retseq, @$block if scalar @$block; - - return wantarray ? @$retseq : $retseq ; -} - - - -# init_regex_arr_data(\@array,"TOKEN INIT") -# scans DATA file handel for line "%% TOKEN INIT" line -# then appends each line not beginning with % into array (as a quoted regex) -sub init_regex_arr_data { - my ($arr,$token)=@_; - my ($copy); - while () { - if ( m/^%%BEGIN $token\s*$/ ) { - $copy=1; } - elsif ( m/^%%END $token\s*/ ) { - last; } - chomp; - push (@$arr,qr/^$_$/) if ( $copy && !/^%/ ) ; - } - seek DATA,0,0; # rewind DATA handle to file begin -} - - -# init_regex_arr_ext(\@array,$arg) -# fills array with regular expressions. -# if arg is a file name, then read in list of regular expressions from that file -# (one expression per line) -# Otherwise treat arg as a comma separated list of regular expressions -sub init_regex_arr_ext { - my ($arr,$arg)=@_; - my $regex; - if ( -f $ arg ) { - open(FILE,"$arg") or die ("Couldn't open $arg: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@$arr,qr/^$_$/); - } - close(FILE); - } - else { - # assume it is a comma-separated list of reg-ex - foreach $regex (split(qr/(?=1) { - $reset=shift; - } - if ($reset) { - $lasttime=times(); - } - else { - $retval=times()-$lasttime; - $lasttime=$lasttime+$retval; - return($retval); - } -} - - -sub usage { - die <<"EOF"; -Usage: $0 [options] old.tex new.tex > diff.tex - -Compares two latex files and writes tex code to stdout, which has the same -format as new.tex but has all changes relative to old.tex marked up or commented. - ---type=markupstyle --t markupstyle Add code to preamble for selected markup style - Available styles: UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE - CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR - [ Default: UNDERLINE ] - ---subtype=markstyle --s markstyle Add code to preamble for selected style for bracketing - commands (e.g. to mark changes in margin) - Available styles: SAFE MARGINAL DVIPSCOL COLOR - [ Default: SAFE ] - ---floattype=markstyle --f markstyle Add code to preamble for selected style which - replace standard marking and markup commands within floats - (e.g., marginal remarks cause an error within floats - so marginal marking can be disabled thus) - Available styles: FLOATSAFE IDENTICAL - [ Default: FLOATSAFE ] - ---encoding=enc --e enc Specify encoding of old.tex and new.tex. Typical encodings are - ascii, utf8, latin1, latin9. A list of available encodings can be - obtained by executing - perl -MEncode -e 'print join ("\\n",Encode->encodings( ":all" )) ;' - [Default encoding is utf8 unless the first few lines of the preamble contain - an invocation "\\usepackage[..]{inputenc} in which case the - encoding chosen by this command is asssumed. Note that ASCII (standard - latex) is a subset of utf8] - ---preamble=file --p file Insert file at end of preamble instead of auto-generating - preamble. The preamble must define the following commands - \\DIFaddbegin,\\DIFaddend,\\DIFadd{..}, - \\DIFdelbegin,\\DIFdelend,\\DIFdel{..}, - and varieties for use within floats - \\DIFaddbeginFL,\\DIFaddendFL,\\DIFaddFL{..}, - \\DIFdelbeginFL,\\DIFdelendFL,\\DIFdelFL{..} - (If this option is set -t, -s, and -f options - are ignored.) - ---exclude-safecmd=exclude-file ---exclude-safecmd="cmd1,cmd2,..." --A exclude-file ---replace-safecmd=replace-file ---append-safecmd=append-file ---append-safecmd="cmd1,cmd2,..." --a append-file Exclude from, replace or append to the list of regex - matching commands which are safe to use within the - scope of a \\DIFadd or \\DIFdel command. The file must contain - one Perl-RegEx per line (Comment lines beginning with # or % are - ignored). A literal comma within the comma-separated list must be - escaped thus "\\,", Note that the RegEx needs to match the whole of - the token, i.e., /^regex\$/ is implied and that the initial - "\\" of the command is not included. The --exclude-safecmd - and --append-safecmd options can be combined with the --replace-safecmd - option and can be used repeatedly to add cumulatively to the lists. - ---exclude-textcmd=exclude-file ---exclude-textcmd="cmd1,cmd2,..." --X exclude-file ---replace-textcmd=replace-file ---append-textcmd=append-file ---append-textcmd="cmd1,cmd2,..." --x append-file Exclude from, replace or append to the list of regex - matching commands whose last argument is text. See - entry for --exclude-safecmd directly above for further details. - ---replace-context1cmd=replace-file ---append-context1cmd=append-file ---append-context1cmd="cmd1,cmd2,..." - Replace or append to the list of regex matching commands - whose last argument is text but which require a particular - context to work, e.g. \\caption will only work within a figure - or table. These commands behave like text commands, except when - they occur in a deleted section, when they are disabled, but their - argument is shown as deleted text. - ---replace-context2cmd=replace-file ---append-context2cmd=append-file ---append-context2cmd="cmd1,cmd2,..." - As corresponding commands for context1. The only difference is that - context2 commands are completely disabled in deleted sections, including - their arguments. - - ---config var1=val1,var2=val2,... --c var1=val1,.. Set configuration variables. --c configfile Available variables: - MINWORDSBLOCK (integer) - FLOATENV (RegEx) - PICTUREENV (RegEx) - MATHENV (RegEx) - MATHREPL (String) - MATHARRENV (RegEx) - MATHARRREPL (String) - ARRENV (RegEx) - COUNTERCMD (RegEx) - This option can be repeated. - - ---packages=pkg1,pkg2,.. - Tell latexdiff that .tex file is processed with the packages in list - loaded. This is normally not necessary if the .tex file includes the - preamble, as the preamble is automatically scanned for \\usepackage commands. - Use of the --packages option disables automatic scanning, so if for any - reason package specific parsing needs to be switched off, use --packages=none. - The following packages trigger special behaviour: - endfloat hyperref amsmath - [ Default: scan the preamble for \\usepackage commands to determine - loaded packages.] - ---show-preamble Print generated or included preamble commands to stdout. - ---show-safecmd Print list of regex matching and excluding safe commands. - ---show-textcmd Print list of regex matching and excluding commands with text argument. - ---show-config Show values of configuration variables - ---show-all Show all of the above - - NB For all --show commands, no old.tex or new.tex file needs to be given, and no - differencing takes place. - -Other configuration options: - ---allow-spaces Allow spaces between bracketed or braced arguments to commands - [Default requires arguments to directly follow each other without - intervening spaces] - ---math-markup=level Determine granularity of markup in displayed math environments: - Possible values for level are (both numerical and text labels are acceptable): - off or 0: suppress markup for math environments. Deleted equations will not - appear in diff file. This mode can be used if all the other modes - cause invalid latex code. - whole or 1: Differencing on the level of whole equations. Even trivial changes - to equations cause the whole equation to be marked changed. This - mode can be used if processing in coarse or fine mode results in - invalid latex code. - coarse or 2: Detect changes within equations marked up with a coarse - granularity; changes in equation type (e.g.displaymath to equation) - appear as a change to the complete equation. This mode is recommended - for situations where the content and order of some equations are still - being changed. [Default] - fine or 3: Detect small change in equations and mark up and fine granularity. - This mode is most suitable, if only minor changes to equations are - expected, e.g. correction of typos. - ---disable-citation-markup Suppress citation markup in styles using ulem (UNDERLINE, - FONTSTRIKE, CULINECHBAR) ---enable-citation-markup Protect citation commands in changed sections with \\mbox command - [i.e. use default behaviour for ulem package for other packages] - - -Miscelleneous options - ---label=label --L label Sets the labels used to describe the old and new files. The first use - of this option sets the label describing the old file and the second - use of the option sets the label for the new file. - [Default: use the filename and modification dates for the label] - ---no-label Suppress inclusion of old and new file names as comment in output file - ---visble-label Include old and new filenames (or labels set with --label option) as - visible output - ---flatten Replace \\input and \\include commands within body by the content - of the files in their argument. If \\includeonly is present in the - preamble, only those files are expanded into the document. However, - no recursion is done, i.e. \\input and \\include commands within - included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, - respectively, making it possible to organise files into old and new directories. - --flatten is applied recursively, so inputted files can contain further - \\input statements. - ---help --h Show this help text. - ---ignore-warnings Suppress warnings about inconsistencies in length between input - and parsed strings and missing characters. - ---verbose --V Output various status information to stderr during processing. - Default is to work silently. - ---version Show version number. - -EOF -} - -=head1 NAME - -latexdiff - determine and markup differences between two latex files - -=head1 SYNOPSIS - -B [ B ] F F > F - -=head1 DESCRIPTION - -Briefly, I is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called C and C, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. - -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "S>>" is appended to each added line, i.e. a -line present in C but not in C. Discarded lines - are deactivated by prepending "S>>". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file C will be similar to -C. At the end of the preamble, the definitions for I markup commands are inserted. -In differencing the main body of the text, I attempts to -satisfy the following guidelines (in order of priority): - -=over 3 - -=item 1 - -If both C and C are valid LaTeX, then the resulting -C should also be valid LateX. (NB If a few plain TeX commands -are used within C or C then C is not -guaranteed to work but usually will). - -=item 2 - -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -C. - -=item 3 - -If a changed passage contains text or text-producing commands, then -running C through LateX should produce output where added -and discarded passages are highlighted. - -=item 4 - -Where there are insignificant differences, e.g. in the positioning of -line breaks, C should follow the formatting of C - -=back - -For differencing the same algorithm as I is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, C<\caption> and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write - - \section{\textem{This is an emphasized section title}} - -and not - - \section {\textem{This is an emphasized section title}} - -or - - \section\textem{This is an emphasized section title} - -even though all varieties are the same to LaTeX (but see -B<--allow-spaces> option which allows the second variety). - -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the PICTUREENV configuration variable, set by -default to C and C environments; see B<--config> -option). The latter environment (C) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by C<\begin{DIFnomarkup}> and C<\end{DIFnomarkup}>. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, - -C<\newenvironment{DIFnomarkup}{}{}> - -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. - -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. - -All markup commands inserted by I begin with "C<\DIF>". Added -blocks containing words, commands or comments which are in C -but not in C are marked by C<\DIFaddbegin> and C<\DIFaddend>. -Discarded blocks are marked by C<\DIFdelbegin> and C<\DIFdelend>. -Within added blocks all text is highlighted with C<\DIFadd> like this: -C<\DIFadd{Added text block}> -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces "{" and "}" are never put within -the scope of C<\DIFadd>. Added comments are marked by prepending -"S >>". - -Within deleted blocks text is highlighted with C<\DIFdel>. Deleted -comments are marked by prepending "S >>". Non-safe command -and curly braces within deleted blocks are commented out with -"S >>". - - - -=head1 OPTIONS - -=head2 Preamble - -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. - -=over 4 - -=item B<--type=markupstyle> or -B<-t markupstyle> - -Add code to preamble for selected markup style. This option defines -C<\DIFadd> and C<\DIFdel> commands. -Available styles: - -C - -[ Default: C ] - -=item B<--subtype=markstyle> or -B<-s markstyle> - -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -C<\DIFaddbegin>, C<\DIFaddend>, C<\DIFdelbegin> and C<\DIFdelend> commands. -Available styles: C - -[ Default: C ] - -=item B<--floattype=markstyle> or -B<-f markstyle> - -Add code to preamble for selected style which -replace standard marking and markup commands within floats -(e.g., marginal remarks cause an error within floats -so marginal marking can be disabled thus). This option defines all -C<\DIF...FL> commands. -Available styles: C - -[ Default: C ] - -=item B<--encoding=enc> or -B<-e enc> - -Specify encoding of old.tex and new.tex. Typical encodings are -C, C, C, C. A list of available encodings can be -obtained by executing - -Cencodings( ":all" )) ;' > - -[Default encoding is utf8 unless the first few lines of the preamble contain -an invocation C<\usepackage[..]{inputenc}> in which case the -encoding chosen by this command is asssumed. Note that ASCII (standard -latex) is a subset of utf8] - -=item B<--preamble=file> or -B<-p file> - -Insert file at end of preamble instead of generating -preamble. The preamble must define the following commands -C<\DIFaddbegin, \DIFaddend, \DIFadd{..}, -\DIFdelbegin,\DIFdelend,\DIFdel{..},> -and varieties for use within floats -C<\DIFaddbeginFL, \DIFaddendFL, \DIFaddFL{..}, -\DIFdelbeginFL, \DIFdelendFL, \DIFdelFL{..}> -(If this option is set B<-t>, B<-s>, and B<-f> options -are ignored.) - -=item B<--packages=pkg1,pkg2,..> - -Tell latexdiff that .tex file is processed with the packages in list -loaded. This is normally not necessary if the .tex file includes the -preamble, as the preamble is automatically scanned for C<\usepackage> commands. -Use of the B<--packages> option disables automatic scanning, so if for any -reason package specific parsing needs to be switched off, use B<--packages=none>. -The following packages trigger special behaviour: - -=over 8 - -=item C - -Configuration variable amsmath is set to C (Default: C) - -=item C - -Ensure that C<\begin{figure}> and C<\end{figure}> always appear by themselves on a line. - -=item C - -Change name of C<\DIFadd> and C<\DIFdel> commands to C<\DIFaddtex> and C<\DIFdeltex> and -define new C<\DIFadd> and C<\DIFdel> commands, which provide a wrapper for these commands, -using them for the text but not for the link defining command (where any markup would cause -errors). - -=back - -[ Default: scan the preamble for C<\\usepackage> commands to determine - loaded packages.] - - - -=item B<--show-preamble> - -Print generated or included preamble commands to stdout. - -=back - -=head2 Configuration - -=over 4 - -=item B<--exclude-safecmd=exclude-file> or -B<-A exclude-file> or B<--exclude-safecmd="cmd1,cmd2,..."> - -=item B<--replace-safecmd=replace-file> - -=item B<--append-safecmd=append-file> or -B<-a append-file> or B<--append-safecmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions (RegEx) -matching commands which are safe to use within the -scope of a C<\DIFadd> or C<\DIFdel> command. The file must contain -one Perl-RegEx per line (Comment lines beginning with # or % are -ignored). Note that the RegEx needs to match the whole of -the token, i.e., /^regex$/ is implied and that the initial -"\" of the command is not included. -The B<--exclude-safecmd> and B<--append-safecmd> options can be combined with the -B<--replace-safecmd> -option and can be used repeatedly to add cumulatively to the lists. - B<--exclude-safecmd> -and B<--append-safecmd> can also take a comma separated list as input. If a -comma for one of the regex is required, escape it thus "\,". In most cases it -will be necessary to protect the comma-separated list from the shell by putting -it in quotation marks. - -=item B<--exclude-textcmd=exclude-file> or -B<-X exclude-file> or B<--exclude-textcmd="cmd1,cmd2,..."> - -=item B<--replace-textcmd=replace-file> - -=item B<--append-textcmd=append-file> or -B<-x append-file> or B<--append-textcmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions -matching commands whose last argument is text. See -entry for B<--exclude-safecmd> directly above for further details. - - -=item B<--replace-context1cmd=replace-file> - -=item B<--append-context1cmd=append-file> or -=item B<--append-context1cmd="cmd1,cmd2,..."> - -Replace or append to the list of regex matching commands -whose last argument is text but which require a particular -context to work, e.g. \caption will only work within a figure -or table. These commands behave like text commands, except when -they occur in a deleted section, when they are disabled, but their -argument is shown as deleted text. - -=item B<--replace-context2cmd=replace-file> - -=item B<--append-context2cmd=append-file> or -=item B<--append-context2cmd="cmd1,cmd2,..."> -As corresponding commands for context1. The only difference is that -context2 commands are completely disabled in deleted sections, including -their arguments. - - - -=item B<--config var1=val1,var2=val2,...> or B<-c var1=val1,..> - -=item B<-c configfile> - -Set configuration variables. The option can be repeated to set different -variables (as an alternative to the comma-separated list). -Available variables (see below for further explanations): - -C (integer) - -C (RegEx) - -C (RegEx) - -C (RegEx) - -C (String) - -C (RegEx) - -C (String) - -C (RegEx) - -C (RegEx) - -=item B<--show-safecmd> - -Print list of RegEx matching and excluding safe commands. - -=item B<--show-textcmd> - -Print list of RegEx matching and excluding commands with text argument. - -=item B<--show-config> - -Show values of configuration variables. - -=item B<--show-all> - -Combine all --show commands. - -NB For all --show commands, no C or C file needs to be specified, and no -differencing takes place. - -=back - -=head2 Other configuration options: - -=over 4 - -=item B<--allow-spaces> - -Allow spaces between bracketed or braced arguments to commands. Note -that this option might have undesirable side effects (unrelated scope -might get lumpeded with preceding commands) so should only be used if the -default produces erroneous results. (Default requires arguments to -directly follow each other without intervening spaces). - -=item B<--math-markup=level> - -Determine granularity of markup in displayed math environments: -Possible values for level are (both numerical and text labels are acceptable): - -C or C<0>: suppress markup for math environments. Deleted equations will not -appear in diff file. This mode can be used if all the other modes -cause invalid latex code. - -C or C<1>: Differencing on the level of whole equations. Even trivial changes -to equations cause the whole equation to be marked changed. This -mode can be used if processing in coarse or fine mode results in -invalid latex code. - -C or C<2>: Detect changes within equations marked up with a coarse -granularity; changes in equation type (e.g.displaymath to equation) -appear as a change to the complete equation. This mode is recommended -for situations where the content and order of some equations are still -being changed. [Default] -C or C<3>: Detect small change in equations and mark up and fine granularity. -This mode is most suitable, if only minor changes to equations are -expected, e.g. correction of typos. - -=item B<--disable-citation-markup> - -Suppress citation markup in styles using ulem (UNDERLINE, -FONTSTRIKE, CULINECHBAR) - -=item B<--enable-citation-markup> - -Protect citation commands in changed sections with \\mbox command [i.e. use default behaviour for ulem package for other packages] - -=back - -=head2 Miscellaneous - -=over 4 -=item B<--verbose> or B<-V> - -Output various status information to stderr during processing. -Default is to work silently. - -=item B<--driver=type> - -Choose driver for changebar package (only relevant for styles using - changebar: CCHANGEBAR CFONTCHBAR CULINECHBAR CHANGEBAR). Possible -drivers are listed in changebar manual, e.g. pdftex,dvips,dvitops - [Default: dvips] - -=item B<--ignore-warnings> - -Suppress warnings about inconsistencies in length between input and -parsed strings and missing characters. These warning messages are -often related to non-standard latex or latex constructions with a -syntax unknown to C but the resulting difference argument -is often fully functional anyway, particularly if the non-standard -latex only occurs in parts of the text which have not changed. - -=item B<--label=label> or -B<-L label> - -Sets the labels used to describe the old and new files. The first use -of this option sets the label describing the old file and the second -use of the option sets the label for the new file, i.e. set both -labels like this C<-L labelold -L labelnew>. -[Default: use the filename and modification dates for the label] - -=item B<--no-label> - -Suppress inclusion of old and new file names as comment in output file - -=item B<--visble-label> - -Include old and new filenames (or labels set with --label option) as -visible output. - -=item B<--flatten> - -Replace C<\input> and C<\include> commands within body by the content -of the files in their argument. If C<\includeonly> is present in the -preamble, only those files are expanded into the document. However, -no recursion is done, i.e. C<\input> and C<\include> commands within -included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, -respectively, making it possible to organise files into old and new directories. ---flatten is applied recursively, so inputted files can contain further -C<\input> statements. - -Use of this option might result in prohibitive processing times for -larger documents, and the resulting difference document -no longer reflects the structure of the input documents. - -=item B<--help> or -B<-h> - -Show help text - -=item B<--version> - -Show version number - -=back - - - -=head2 Predefined styles - -=head2 Major types - -The major type determine the markup of plain text and some selected latex commands outside floats by defining the markup commands C<\DIFadd{...}> and C<\DIFdel{...}> . - -=over 10 - -=item C - -Added text is wavy-underlined and blue, discarded text is struck out and red -(Requires color and ulem packages). Overstriking does not work in displayed math equations such that deleted parts of equation are underlined, not struck out (this is a shortcoming inherent to the ulem package). - -=item C - -Added text is blue and set in sans-serif, and a red footnote is created for each discarded -piece of text. (Requires color package) - -=item C - -Like C but without the use of color. - -=item C - -Added text is blue and set in sans-serif, and discarded text is red and very small size. - -=item C - -Added tex is set in sans-serif, discarded text small and struck out - -=item C - -Added text is blue, and discarded text is red. Additionally, the changed text is marked with a bar in the margin (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color, ulem and changebar packages). - -=item C - -No mark up of text, but mark margins with changebars (Requires changebar package). - -=item C - -No visible markup (but generic markup commands will still be inserted. - -=back - -=head2 Subtypes - -The subtype defines the commands that are inserted at the begin and end of added or discarded blocks, irrespectively of whether these blocks contain text or commands (Defined commands: C<\DIFaddbegin, \DIFaddend, \DIFdelbegin, \DIFdelend>) - -=over 10 - -=item C - -No additional markup (Recommended choice) - -=item C - -Mark beginning and end of changed blocks with symbols in the margin nearby (using -the standard C<\marginpar> command - note that this sometimes moves somewhat -from the intended position. - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. -(It is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete, for example -with citation commands). - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. Note -that C only works with the dvips converter, e.g. not pdflatex. -(it is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete). - -=back - -=head2 Float Types - -Some of the markup used in the main text might cause problems when used within -floats (e.g. figures or tables). For this reason alternative versions of all -markup commands are used within floats. The float type defines these alternative commands. - -=over 10 - -=item C - -Use identical markup for text as in the main body, but set all commands marking the begin and end of changed blocks to null-commands. You have to choose this float type if your subtype is C as C<\marginpar> does not work properly within floats. - -=item C - -Mark additions the same way as in the main text. Deleted environments are marked by angular brackets \[ and \] and the deleted text is set in scriptscript size. This float type should always be used with the C and C markup types as the \footnote command does not work properly in floating environments. - -=item C - -Make no difference between the main text and floats. - -=back - - -=head2 Configuration Variables - -=over 10 - -=item C - -Minimum number of tokens required to form an independent block. This value is -used in the algorithm to detect changes of complete blocks by merging identical text parts of less than C to the preceding added and discarded parts. - -[ Default: 3 ] - -=item C - -Environments whose name matches the regular expression in C are -considered floats. Within these environments, the I markup commands -are replaced by their FL variaties. - -[ Default: S >] - -=item C - -Within environments whose name matches the regular expression in C -all latexdiff markup is removed (in pathologic cases this might lead to - inconsistent markup but this situation should be rare). - -[ Default: S >] - -=item C,C - -If both \begin and \end for a math environment (environment name matching C -or \[ and \]) -are within the same deleted block, they are replaced by a \begin and \end commands for C -rather than being commented out. - -[ Default: C=S >, C=S >] - -=item C,C - -as C,C but for equation arrays - -[ Default: C=S >, C=S >] - -=item C - -If a match to C is found within an inline math environment within a deleted or added block, then the inlined math -is surrounded by C<\mbox{>...C<}>. This is necessary as underlining does not work within inlined array environments. - -[ Default: C=S > - -=item C - -If a command in a deleted block which is also in the textcmd list matches C then an -additional command C<\addtocounter{>FC<}{-1}>, where F is the matching command, is appended in the diff file such that the numbering in the diff file remains synchronized with the -numbering in the new file. - -[ Default: C=C<(?:footnote|part|section|subsection> ... - -C<|subsubsection|paragraph|subparagraph)> ] - -=back - -=head1 COMMON PROBLEMS - -=over 10 - -=item Citations result in overfull boxes - -There is an incompatibility between the C package, which C uses for underlining and striking out in the UNDERLINE style, -the default style. In order to be able to mark up citations properly, they are placed with an C<\mbox> command in post-processing. As mboxes -cannot be broken across lines, this procedure frequently results in overfull boxes, possibly obscuring the content as it extends beyond the right margin. If this is a problem, you have two possibilities: - -1. Use C or C subtype markup (option C<-s COLOR>): If this markup is chosen, then changed citations are no longer marked up -with the wavy line (additions) or struck out (deletions), but are still highlighted in the appropriate color. - -2. Choose option C<--disable-citation-markup> which turns off the marking up of citations: deleted citations are no longer shown, and -added ctations are shown without markup. (This was the default behaviour of latexdiff at versions 0.6 and older - -=back - -=head1 BUGS - -Option allow-spaces not implemented entirely consistently. It breaks -the rules that number and type of white space does not matter, as -different numbers of inter-argument spaces are treated as significant. - -Please send bug reports -to I or submit on latexdiff project page I. Include the serial number of I -(from comments at the top of the source or use B<--version>). If you come across latex -files that are error-free and conform to the specifications set out -above, and whose differencing still does not result in error-free -latex, please send me those files, ideally edited to only contain the -offending passage as long as that still reproduces the problem. If your -file relies on non-standard class files, you must include those. I will not -look at examples where I have trouble to latex the original files. - -=head1 SEE ALSO - -L, L - -=head1 PORTABILITY - -I does not make use of external commands and thus should run -on any platform supporting Perl 5.6 or higher. If files with encodings -other than ASCII or UTF-8 are processed, Perl 5.8 or higher is required. - -The standard version of I requires installation of the Perl package -C (available from I - -I) but a stand-alone -version, I, which has this package inlined, is available, too. -I requires the I command to be present. - -=head1 AUTHOR - -Copyright (C) 2004-2012 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 - -Contributors of fixes and additions: V. Kuhlmann, J. Paisley, N. Becker, T. Doerges, K. Huebner, -T. Connors, Sebastian Gouezel and many others. -Thanks to the many people who send in bug reports, feature suggestions, and other feedback. - -=cut - -__END__ -%%BEGIN SAFE COMMANDS -% Regex matching commands which can safely be in the -% argument of a \DIFadd or \DIFdel command (leave out the \) -arabic -dashbox -emph -fbox -framebox -hspace -math.* -makebox -mbox -pageref -ref -symbol -raisebox -rule -text.* -shortstack -usebox -dag -ddag -copyright -pounds -S -P -oe -OE -ae -AE -aa -AA -o -O -l -L -frac -ss -sqrt -ldots -cdots -vdots -ddots -alpha -beta -gamma -delta -epsilon -varepsilon -zeta -eta -theta -vartheta -iota -kappa -lambda -mu -nu -xi -pi -varpi -rho -varrho -sigma -varsigma -tau -upsilon -phi -varphi -chi -psi -omega -Gamma -Delta -Theta -Lambda -Xi -Pi -Sigma -Upsilon -Phi -Psi -Omega -ps -mp -times -div -ast -star -circ -bullet -cdot -cap -cup -uplus -sqcap -vee -wedge -setminus -wr -diamond -(?:big)?triangle.* -lhd -rhd -unlhd -unrhd -oplus -ominus -otimes -oslash -odot -bigcirc -d?dagger -amalg -leq -prec -preceq -ll -(?:sq)?su[bp]set(?:eq)? -in -vdash -geq -succ(?:eq)? -gg -ni -dashv -equiv -sim(?:eq)? -asymp -approx -cong -neq -doteq -propto -models -perp -mid -parallel -bowtie -Join -smile -frown -.*arrow -(?:long)?mapsto -.*harpoon.* -leadsto -aleph -hbar -imath -jmath -ell -wp -Re -Im -mho -prime -emptyset -nabla -surd -top -bot -angle -forall -exists -neg -flat -natural -sharp -backslash -partial -infty -Box -Diamond -triangle -clubsuit -diamondsuit -heartsuit -spadesuit -sum -prod -coprod -int -oint -big(?:sq)?c[au]p -bigvee -bigwedge -bigodot -bigotimes -bigoplus -biguplus -(?:arc)?(?:cos|sin|tan|cot)h? -csc -arg -deg -det -dim -exp -gcd -hom -inf -ker -lg -lim -liminf -limsup -ln -log -max -min -Pr -sec -sup -(SUPER|SUB)SCRIPTNB -(SUPER|SUB)SCRIPT -%%END SAFE COMMANDS - -%%BEGIN TEXT COMMANDS -% Regex matching commands with a text argument (leave out the \) -addcontents.* -cc -closing -chapter -dashbox -emph -encl -fbox -framebox -footnote -footnotetext -framebox -part -(sub){0,2}section\*? -(sub)?paragraph\*? -makebox -mbox -opening -parbox -raisebox -savebox -sbox -shortstack -signature -text.* -value -underline -sqrt -(SUPER|SUB)SCRIPT -%%END TEXT COMMANDS - -%%BEGIN CONTEXT1 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -caption -%%END CONTEXT1 COMMANDS - -%%BEGIN CONTEXT2 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -title -author -date -institute -%%END CONTEXT2 COMMANDS - - -%% TYPES (Commands for highlighting changed blocks) - -%DIF UNDERLINE PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}} -\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}} -%DIF END UNDERLINE PREAMBLE - -%DIF CTRADITIONAL PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} [..\footnote{removed: #1} ]}} -%DIF END CTRADITIONAL PREAMBLE - -%DIF TRADITIONAL PREAMBLE -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{[..\footnote{removed: #1} ]}} -%DIF END TRADITIONAL PREAMBLE - -%DIF CFONT PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} \scriptsize #1}} -%DIF END CFONT PREAMBLE - -%DIF FONTSTRIKE PREAMBLE -\RequirePackage[normalem]{ulem} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{\footnotesize \sout{#1}}} -%DIF END FONTSTRIKE PREAMBLE - -%DIF CCHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}#1}\protect\cbdelete} -%DIF END CCHANGEBAR PREAMBLE - -%DIF CFONTCHBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\sf #1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\scriptsize #1}\protect\cbdelete} -%DIF END CFONTCHBAR PREAMBLE - -%DIF CULINECHBAR PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage[dvips]{changebar} -\RequirePackage{color} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\uwave{#1}}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\sout{#1}}\protect\cbdelete} -%DIF END CULINECHBAR PREAMBLE - -%DIF CHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\providecommand{\DIFadd}[1]{\protect\cbstart{#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete} -%DIF END CHANGEBAR PREAMBLE - -%DIF INVISIBLE PREAMBLE -\providecommand{\DIFadd}[1]{#1} -\providecommand{\DIFdel}[1]{} -%DIF END INVISIBLE PREAMBLE - - -%% SUBTYPES (Markers for beginning and end of changed blocks) - -%DIF SAFE PREAMBLE -\providecommand{\DIFaddbegin}{} -\providecommand{\DIFaddend}{} -\providecommand{\DIFdelbegin}{} -\providecommand{\DIFdelend}{} -%DIF END SAFE PREAMBLE - -%DIF MARGIN PREAMBLE -\providecommand{\DIFaddbegin}{\protect\marginpar{a[}} -\providecommand{\DIFaddend}{\protect\marginpar{]}} -\providecommand{\DIFdelbegin}{\protect\marginpar{d[}} -\providecommand{\DIFdelend}{\protect\marginpar{]}} -%DIF END BRACKET PREAMBLE - -%DIF DVIPSCOL PREAMBLE -%Note: only works with dvips converter -\RequirePackage{color} -\RequirePackage{dvipscol} -\providecommand{\DIFaddbegin}{\protect\nogroupcolor{blue}} -\providecommand{\DIFaddend}{\protect\nogroupcolor{black}} -\providecommand{\DIFdelbegin}{\protect\nogroupcolor{red}} -\providecommand{\DIFdelend}{\protect\nogroupcolor{black}} -%DIF END DVIPSCOL PREAMBLE - -%DIF COLOR PREAMBLE -\RequirePackage{color} -\providecommand{\DIFaddbegin}{\protect\color{blue}} -\providecommand{\DIFaddend}{\protect\color{black}} -\providecommand{\DIFdelbegin}{\protect\color{red}} -\providecommand{\DIFdelend}{\protect\color{black}} -%DIF END COLOR PREAMBLE - - -%% FLOAT TYPES - -%DIF FLOATSAFE PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%DIF IDENTICAL PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{\DIFaddbegin} -\providecommand{\DIFaddendFL}{\DIFaddend} -\providecommand{\DIFdelbeginFL}{\DIFdelbegin} -\providecommand{\DIFdelendFL}{\DIFdelend} -%DIF END IDENTICAL PREAMBLE - -%DIF TRADITIONALSAFE PREAMBLE -% procidecommand color to make this work for TRADITIONAL and CTRADITIONAL -\providecommand{\color}[1]{} -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdel}[1]{{\protect\color{red}[..{\scriptsize {removed: #1}} ]}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%% SPECIAL PACKAGE PREAMBLE COMMANDS - -% Standard \DIFadd and \DIFdel are redefined as \DIFaddtex and \DIFdeltex -% when hyperref package is included. -%DIF HYPERREF PREAMBLE -\providecommand{\DIFadd}[1]{\texorpdfstring{\DIFaddtex{#1}}{#1}} -\providecommand{\DIFdel}[1]{\texorpdfstring{\DIFdeltex{#1}}{}} -%DIF END HYPERREF PACKAGE diff --git a/latexdiff-1.0.1/latexdiff-so b/latexdiff-1.0.1/latexdiff-so deleted file mode 100755 index 0ded5a8..0000000 --- a/latexdiff-1.0.1/latexdiff-so +++ /dev/null @@ -1,3849 +0,0 @@ -#!/usr/bin/env perl -##!/usr/bin/perl -w -# latexdiff - differences two latex files on the word level -# and produces a latex file with the differences marked up. -# -# Copyright (C) 2004-12 F J Tilmann (tilmann@gfz-potsdam.de, ftilmann@users.berlios.de) -# -# Project webpages: http://latexdiff.berlios.de/ -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# -# Version 1.0.1 - treat \big,\bigg etc. equivalently to \left and -# \right - include starred version in MATHENV - apply -# - flatten recursively and --flatten expansion is now -# aware of comments (thanks to Tim Connors for patch) -# - Change to post-processing for more reliability for -# deleted math environments -# - On linux systems, recognise and remove DOS style newlines -# - Provide markup for some special preamble commands (\title, -# \author,\date, -# - configurable by setting context2cmd -# - for styles using ulem package, remove \emph and \text.. from list of -# safe commands in order to allow linebreaks within the -# highlighted sections. -# - for ulem style, now show citations by enclosing them in \mbox commands. -# This unfortunately implies linebreaks within citations no longer function, -# so this functionality can be turned off (Option --disable-citation-markup). -# With --enable-citation-markup, the mbox markup is forced for other styles) -# - new substyle COLOR. This is particularly useful for marking up citations -# and some special post-processing is implemented to retain cite -# commands in deleted blocks. -# - four different levels of math-markup -# - Option --driver for choosing driver for modes employing changebar package -# - accept \\* as valid command (and other commands of form \.*). Also accept -# \ (backslashed newline) -# - some typo fixes, include commands defined in preamble as safe commands -# (Sebastian Gouezel) -# - include compared filenames as comments as line 2 and 3 of -# the preamble (can be modified with option --label, and suppressed with -# --no-label), option --visible-label to show files in generated pdf or dvi -# at the beginning of main document -# -# Version 0.5 A number of minor improvements based on feedback -# Deleted blocks are now shown before added blocks -# Package specific processing -# -# Version 0.43 unreleased typo in list of styles at the end -# Add protect to all \cbstart, \cbend commands -# More robust substitution of deleted math commands -# -# Version 0.42 November 06 Bug fixes only -# -# Version 0.4 March 06 option for fast differencing using UNIX diff command, several minor bug fixes (\par bug, improved highlighting of textcmds) -# -# Version 0.3 August 05 improved parsing of displayed math, --allow-spaces -# option, several minor bug fixes -# -# Version 0.25 October 04 Fix bug with deleted equations, add math mode commands to safecmd, add | to allowed interpunctuation signs -# Version 0.2 September 04 extension to utf-8 and variable encodings -# Version 0.1 August 04 First public release - -# Inserted block for stand-alone version replaces -# use Algorithm::Diff qw(traverse_sequences); -# in standard version -# The following BEGIN block contains a verbatim copy of -# Ned Konz' Algorithm::Diff package version 1.15 except -# that all POD documentation has been stripped out. -# I encourage you to download and install the Algorithm::Diff -# package and use the standard latexdiff version instead -# (current distribution available from http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15 -# the most recent version can be found via http://search.cpan.org/search?module=Algorithm::Diff ) -# Please note that the LICENCSE for Algorithm::Diff : -# "Copyright (c) 2000-2002 Ned Konz. All rights reserved. -# This program is free software; -# you can redistribute it and/or modify it under the same terms -# as Perl itself." -# The stand-alone version of latexdiff is provided as a convenience -# for latex users with no knowledge of PERL who do not wish to install -# additional packages to be able to use latexdiff. If you believe -# the inlining of Algorithm::Diff violates its license please contact -# me and I will modify the latexdiff distribution accordingly. -# Frederik Tilmann (tilmann@esc.cam.ac.uk) -BEGIN { -package Algorithm::Diff; -use strict; -use vars qw($VERSION @EXPORT_OK @ISA @EXPORT); -use integer; # see below in _replaceNextLargerWith() for mod to make - # if you don't use this -require Exporter; -@ISA = qw(Exporter); -@EXPORT = qw(); -@EXPORT_OK = qw(LCS diff traverse_sequences traverse_balanced sdiff); -$VERSION = sprintf('%d.%02d so', (q$Revision: 1.15 $ =~ /\d+/g)); - -# McIlroy-Hunt diff algorithm -# Adapted from the Smalltalk code of Mario I. Wolczko, -# by Ned Konz, perl@bike-nomad.com - - -# Create a hash that maps each element of $aCollection to the set of positions -# it occupies in $aCollection, restricted to the elements within the range of -# indexes specified by $start and $end. -# The fourth parameter is a subroutine reference that will be called to -# generate a string to use as a key. -# Additional parameters, if any, will be passed to this subroutine. -# -# my $hashRef = _withPositionsOfInInterval( \@array, $start, $end, $keyGen ); - -sub _withPositionsOfInInterval -{ - my $aCollection = shift; # array ref - my $start = shift; - my $end = shift; - my $keyGen = shift; - my %d; - my $index; - for ( $index = $start ; $index <= $end ; $index++ ) - { - my $element = $aCollection->[$index]; - my $key = &$keyGen( $element, @_ ); - if ( exists( $d{$key} ) ) - { - unshift ( @{ $d{$key} }, $index ); - } - else - { - $d{$key} = [$index]; - } - } - return wantarray ? %d : \%d; -} - -# Find the place at which aValue would normally be inserted into the array. If -# that place is already occupied by aValue, do nothing, and return undef. If -# the place does not exist (i.e., it is off the end of the array), add it to -# the end, otherwise replace the element at that point with aValue. -# It is assumed that the array's values are numeric. -# This is where the bulk (75%) of the time is spent in this module, so try to -# make it fast! - -sub _replaceNextLargerWith -{ - my ( $array, $aValue, $high ) = @_; - $high ||= $#$array; - - # off the end? - if ( $high == -1 || $aValue > $array->[-1] ) - { - push ( @$array, $aValue ); - return $high + 1; - } - - # binary search for insertion point... - my $low = 0; - my $index; - my $found; - while ( $low <= $high ) - { - $index = ( $high + $low ) / 2; - - # $index = int(( $high + $low ) / 2); # without 'use integer' - $found = $array->[$index]; - - if ( $aValue == $found ) - { - return undef; - } - elsif ( $aValue > $found ) - { - $low = $index + 1; - } - else - { - $high = $index - 1; - } - } - - # now insertion point is in $low. - $array->[$low] = $aValue; # overwrite next larger - return $low; -} - -# This method computes the longest common subsequence in $a and $b. - -# Result is array or ref, whose contents is such that -# $a->[ $i ] == $b->[ $result[ $i ] ] -# foreach $i in ( 0 .. $#result ) if $result[ $i ] is defined. - -# An additional argument may be passed; this is a hash or key generating -# function that should return a string that uniquely identifies the given -# element. It should be the case that if the key is the same, the elements -# will compare the same. If this parameter is undef or missing, the key -# will be the element as a string. - -# By default, comparisons will use "eq" and elements will be turned into keys -# using the default stringizing operator '""'. - -# Additional parameters, if any, will be passed to the key generation routine. - -sub _longestCommonSubsequence -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $keyGen = shift; # code ref - my $compare; # code ref - - # set up code refs - # Note that these are optimized. - if ( !defined($keyGen) ) # optimize for strings - { - $keyGen = sub { $_[0] }; - $compare = sub { my ( $a, $b ) = @_; $a eq $b }; - } - else - { - $compare = sub { - my $a = shift; - my $b = shift; - &$keyGen( $a, @_ ) eq &$keyGen( $b, @_ ); - }; - } - - my ( $aStart, $aFinish, $bStart, $bFinish, $matchVector ) = - ( 0, $#$a, 0, $#$b, [] ); - - # First we prune off any common elements at the beginning - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aStart], $b->[$bStart], @_ ) ) - { - $matchVector->[ $aStart++ ] = $bStart++; - } - - # now the end - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aFinish], $b->[$bFinish], @_ ) ) - { - $matchVector->[ $aFinish-- ] = $bFinish--; - } - - # Now compute the equivalence classes of positions of elements - my $bMatches = - _withPositionsOfInInterval( $b, $bStart, $bFinish, $keyGen, @_ ); - my $thresh = []; - my $links = []; - - my ( $i, $ai, $j, $k ); - for ( $i = $aStart ; $i <= $aFinish ; $i++ ) - { - $ai = &$keyGen( $a->[$i], @_ ); - if ( exists( $bMatches->{$ai} ) ) - { - $k = 0; - for $j ( @{ $bMatches->{$ai} } ) - { - - # optimization: most of the time this will be true - if ( $k and $thresh->[$k] > $j and $thresh->[ $k - 1 ] < $j ) - { - $thresh->[$k] = $j; - } - else - { - $k = _replaceNextLargerWith( $thresh, $j, $k ); - } - - # oddly, it's faster to always test this (CPU cache?). - if ( defined($k) ) - { - $links->[$k] = - [ ( $k ? $links->[ $k - 1 ] : undef ), $i, $j ]; - } - } - } - } - - if (@$thresh) - { - for ( my $link = $links->[$#$thresh] ; $link ; $link = $link->[0] ) - { - $matchVector->[ $link->[1] ] = $link->[2]; - } - } - - return wantarray ? @$matchVector : $matchVector; -} - -sub traverse_sequences -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $finishedACallback = $callbacks->{'A_FINISHED'}; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $finishedBCallback = $callbacks->{'B_FINISHED'}; - my $matchVector = _longestCommonSubsequence( $a, $b, $keyGen, @_ ); - - # Process all the lines in @$matchVector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai; - - for ( $ai = 0 ; $ai <= $#$matchVector ; $ai++ ) - { - my $bLine = $matchVector->[$ai]; - if ( defined($bLine) ) # matched - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi < $bLine; - &$matchCallback( $ai, $bi++, @_ ); - } - else - { - &$discardACallback( $ai, $bi, @_ ); - } - } - - # The last entry (if any) processed was a match. - # $ai and $bi point just past the last matching lines in their sequences. - - while ( $ai <= $lastA or $bi <= $lastB ) - { - - # last A? - if ( $ai == $lastA + 1 and $bi <= $lastB ) - { - if ( defined($finishedACallback) ) - { - &$finishedACallback( $lastA, @_ ); - $finishedACallback = undef; - } - else - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi <= $lastB; - } - } - - # last B? - if ( $bi == $lastB + 1 and $ai <= $lastA ) - { - if ( defined($finishedBCallback) ) - { - &$finishedBCallback( $lastB, @_ ); - $finishedBCallback = undef; - } - else - { - &$discardACallback( $ai++, $bi, @_ ) while $ai <= $lastA; - } - } - - &$discardACallback( $ai++, $bi, @_ ) if $ai <= $lastA; - &$discardBCallback( $ai, $bi++, @_ ) if $bi <= $lastB; - } - - return 1; -} - -sub traverse_balanced -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $changeCallback = $callbacks->{'CHANGE'}; - my $matchVector = _longestCommonSubsequence( $a, $b, $keyGen, @_ ); - - # Process all the lines in match vector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai = 0; - my $ma = -1; - my $mb; - - while (1) - { - - # Find next match indices $ma and $mb - do { $ma++ } while ( $ma <= $#$matchVector && !defined $matchVector->[$ma] ); - - last if $ma > $#$matchVector; # end of matchVector? - $mb = $matchVector->[$ma]; - - # Proceed with discard a/b or change events until - # next match - while ( $ai < $ma || $bi < $mb ) - { - - if ( $ai < $ma && $bi < $mb ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai < $ma ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi < $mb - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - # Match - &$matchCallback( $ai++, $bi++, @_ ); - } - - while ( $ai <= $lastA || $bi <= $lastB ) - { - if ( $ai <= $lastA && $bi <= $lastB ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai <= $lastA ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi <= $lastB - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - return 1; -} - -sub LCS -{ - my $a = shift; # array ref - my $matchVector = _longestCommonSubsequence( $a, @_ ); - my @retval; - my $i; - for ( $i = 0 ; $i <= $#$matchVector ; $i++ ) - { - if ( defined( $matchVector->[$i] ) ) - { - push ( @retval, $a->[$i] ); - } - } - return wantarray ? @retval : \@retval; -} - -sub diff -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $hunk = []; - my $discard = sub { push ( @$hunk, [ '-', $_[0], $a->[ $_[0] ] ] ) }; - my $add = sub { push ( @$hunk, [ '+', $_[1], $b->[ $_[1] ] ] ) }; - my $match = sub { push ( @$retval, $hunk ) if scalar(@$hunk); $hunk = [] }; - traverse_sequences( $a, $b, - { MATCH => $match, DISCARD_A => $discard, DISCARD_B => $add }, @_ ); - &$match(); - return wantarray ? @$retval : $retval; -} - -sub sdiff -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $discard = sub { push ( @$retval, [ '-', $a->[ $_[0] ], "" ] ) }; - my $add = sub { push ( @$retval, [ '+', "", $b->[ $_[1] ] ] ) }; - my $change = sub { - push ( @$retval, [ 'c', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - my $match = sub { - push ( @$retval, [ 'u', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - traverse_balanced( - $a, - $b, - { - MATCH => $match, - DISCARD_A => $discard, - DISCARD_B => $add, - CHANGE => $change, - }, - @_ - ); - return wantarray ? @$retval : $retval; -} - -1; -} -import Algorithm::Diff qw(traverse_sequences); -# End of inserted block for stand-alone version - -use Getopt::Long ; -use strict ; -use warnings; -use utf8 ; - -my ($algodiffversion)=split(/ /,$Algorithm::Diff::VERSION); - - -my ($versionstring)=< 0, - WHOLE => 1, - COARSE => 2, - FINE => 3 -}; - - -my (@configlist,@labels, - @appendsafelist,@excludesafelist, - @appendtextlist,@excludetextlist, - @appendcontext1list,@appendcontext2list, - @packagelist); -my ($assign,@config); -# Hash where keys corresponds to the names of all included packages (including the documentclass as another package -# the optional arguments to the package are the values of the hash elements -my ($pkg,%packages); -# Defaults -$type='UNDERLINE'; -$subtype='SAFE'; -$floattype='FLOATSAFE'; -$mathmarkup=COARSE; - -$verbose=0; -# output debug and intermediate files, set to 0 in final distribution -$debug=0; -# define character properties -sub IsNonAsciiPunct { return <<'END' # Unicode punctuation but excluding ASCII punctuation -+utf8::IsPunct --utf8::IsASCII -END -} -sub IsNonAsciiS { return <<'END' # Unicode symbol but excluding ASCII -+utf8::IsS --utf8::IsASCII -END -} - - -my %verbhash; - -Getopt::Long::Configure('bundling'); -GetOptions('type|t=s' => \$type, - 'subtype|s=s' => \$subtype, - 'floattype|f=s' => \$floattype, - 'config|c=s' => \@configlist, - 'preamble|p=s' => \$preamblefile, - 'encoding|e=s' => \$encoding, - 'label|L=s' => \@labels, - 'no-label' => \$nolabel, - 'visible-label' => \$visiblelabel, - 'exclude-safecmd|A=s' => \@excludesafelist, - 'replace-safecmd=s' => \$replacesafe, - 'append-safecmd|a=s' => \@appendsafelist, - 'exclude-textcmd|X=s' => \@excludetextlist, - 'replace-textcmd=s' => \$replacetext, - 'append-textcmd|x=s' => \@appendtextlist, - 'replace-context1cmd=s' => \$replacecontext1, - 'append-context1cmd=s' => \@appendcontext1list, - 'replace-context2cmd=s' => \$replacecontext2, - 'append-context2cmd=s' => \@appendcontext2list, - 'show-preamble' => \$showpreamble, - 'show-safecmd' => \$showsafe, - 'show-textcmd' => \$showtext, - 'show-config' => \$showconfig, - 'show-all' => \$showall, - 'packages=s' => \@packagelist, - 'allow-spaces' => \$allowspaces, - 'math-markup=s' => \$mathmarkup, - 'enable-citation-markup' => \$enablecitmark, - 'disable-citation-markup' => \$disablecitmark, - 'verbose|V' => \$verbose, - 'ignore-warnings' => \$ignorewarnings, - 'driver=s'=> \$driver, - 'flatten' => \$flatten, - 'version' => \$version, - 'help|h|H' => \$help); - -if ( $help ) { - usage() ; -} - - -if ( $version ) { - die $versionstring ; -} - -print STDERR $versionstring if $verbose; - -if (defined($showall)){ - $showpreamble=$showsafe=$showtext=$showconfig=1; -} - -if (defined($mathmarkup)) { - $mathmarkup=~tr/a-z/A-Z/; - if ( $mathmarkup eq 'OFF' ){ - $mathmarkup=OFF; - } elsif ( $mathmarkup eq 'WHOLE' ){ - $mathmarkup=WHOLE; - } elsif ( $mathmarkup eq 'COARSE' ){ - $mathmarkup=COARSE; - } elsif ( $mathmarkup eq 'FINE' ){ - $mathmarkup=FINE; - } elsif ( $mathmarkup !~ m/^[0123]$/ ) { - die "Illegal value: ($mathmarkup) for option--math-markup. Possible values: OFF,WHOLE,COARSE,FINE,0- "; - } - # else use numerical value -} - -# setting extra preamble commands -if (defined($preamblefile)) { - $latexdiffpreamble=join "\n",(extrapream($preamblefile),""); -} else { - $latexdiffpreamble=join "\n",(extrapream($type,$subtype,$floattype),""); -} - -if ( defined($driver) ) { - # for changebar only - $latexdiffpreamble=~s/\[dvips\]/[$driver]/sg; -} -# setting up @SAFECMDLIST and @SAFECMDEXCL -if (defined($replacesafe)) { - init_regex_arr_ext(\@SAFECMDLIST,$replacesafe); -} else { - init_regex_arr_data(\@SAFECMDLIST, "SAFE COMMANDS"); -} -foreach $appendsafe ( @appendsafelist ) { - init_regex_arr_ext(\@SAFECMDLIST, $appendsafe); -} -foreach $excludesafe ( @excludesafelist ) { - init_regex_arr_ext(\@SAFECMDEXCL, $excludesafe); -} - -# Special: treat all cite commands as safe except in UNDERLINE and FONTSTRIKE mode -# (there is a conflict between citation and ulem package, see -# package documentation) -# Use post-processing - -if ( uc($type) ne "UNDERLINE" && uc($type) ne "FONTSTRIKE" && uc($type) ne "CULINECHBAR" ) { - push (@SAFECMDLIST, qr/^cite.*$/); -} else { - ### Experimental: disable text and emph commands - push (@SAFECMDLIST, qr/^cite.*$/) unless $disablecitmark; - push(@SAFECMDEXCL, qr/^emph$/, qr/^text..$/); - # replace \cite{..} by \mbox{\cite{..}} in added or deleted blocks in post-processing - if ( uc($subtype) eq "COLOR" or uc($subtype) eq "DVIPSCOL" ) { - # remove \cite command again from list of safe commands - pop @SAFECMDLIST; - # deleted cite commands - $CITE2CMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite-type commands which should be reinstated in deleted blocks - } else { - $CITECMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite commands which need to be protected within an mbox in UNDERLINE and other modes using ulem - } -} -$CITECMD='(?:cite\w*|nocite)' if $enablecitmark ; # as above for explicit selection - -# setting up @TEXTCMDLIST and @TEXTCMDEXCL -if (defined($replacetext)) { - init_regex_arr_ext(\@TEXTCMDLIST,$replacetext); -} else { - init_regex_arr_data(\@TEXTCMDLIST, "TEXT COMMANDS"); -} -foreach $appendtext ( @appendtextlist ) { - init_regex_arr_ext(\@TEXTCMDLIST, $appendtext); -} -foreach $excludetext ( @excludetextlist ) { - init_regex_arr_ext(\@TEXTCMDEXCL, $excludetext); -} - - -# setting up @CONTEXT1CMDLIST ( @CONTEXT1CMDEXCL exist but is always empty ) -if (defined($replacecontext1)) { - init_regex_arr_ext(\@CONTEXT1CMDLIST,$replacecontext1); -} else { - init_regex_arr_data(\@CONTEXT1CMDLIST, "CONTEXT1 COMMANDS"); -} -foreach $appendcontext1 ( @appendcontext1list ) { - init_regex_arr_ext(\@CONTEXT1CMDLIST, $appendcontext1); -} - - -# setting up @CONTEXT2CMDLIST ( @CONTEXT2CMDEXCL exist but is always empty ) -if (defined($replacecontext2)) { - init_regex_arr_ext(\@CONTEXT2CMDLIST,$replacecontext2); -} else { - init_regex_arr_data(\@CONTEXT2CMDLIST, "CONTEXT2 COMMANDS"); -} -foreach $appendcontext2 ( @appendcontext2list ) { - init_regex_arr_ext(\@CONTEXT2CMDLIST, $appendcontext2); -} - -# setting configuration variables -@config=(); -foreach $config ( @configlist ) { - if (-f $config ) { - open(FILE,$config) or die ("Couldn't open configuration file $config: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@config,$_); - } - close(FILE); - } - else { -# foreach ( split(",",$config) ) { -# push @config,$_; -# } - push @config,split(",",$config) - } -} -foreach $assign ( @config ) { - $assign=~ m/\s*(\w*)\s*=\s*(\S*)\s*$/ or die "Illegal assignment $assign in configuration list (must be variable=value)"; - if ( $1 eq "MINWORDSBLOCK" ) { $MINWORDSBLOCK = $2; } - elsif ( $1 eq "FLOATENV" ) { $FLOATENV = $2 ; } - elsif ( $1 eq "PICTUREENV" ) { $PICTUREENV = $2 ; } - elsif ( $1 eq "MATHENV" ) { $MATHENV = $2 ; } - elsif ( $1 eq "MATHREPL" ) { $MATHREPL = $2 ; } - elsif ( $1 eq "MATHARRENV" ) { $MATHARRENV = $2 ; } - elsif ( $1 eq "MATHARRREPL" ) { $MATHARRREPL = $2 ; } - elsif ( $1 eq "ARRENV" ) { $ARRENV = $2 ; } - elsif ( $1 eq "COUNTERCMD" ) { $COUNTERCMD = $2 ; } - else { die "Unknown variable $1 in assignment.";} -} - -if ( $mathmarkup == COARSE || $mathmarkup == WHOLE ) { - push(@MATHTEXTCMDLIST,qr/^MATHBLOCK(?:$MATHENV|$MATHARRENV|SQUAREBRACKET)$/); -} - - - -foreach $pkg ( @packagelist ) { - map { $packages{$_}="" } split(/,/,$pkg) ; -} - -if ($showpreamble) { - print "\nPreamble commands:\n"; - print $latexdiffpreamble ; -} - -if ($showsafe) { - print "\nCommands safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE (unless excluded):\n"; - print_regex_arr(@SAFECMDLIST); - print "\nCommands not safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE :\n"; - print_regex_arr(@SAFECMDEXCL); -} - -if ($showtext) { - print "\nCommands with last argument textual (unless excluded) and safe in every context:\n"; - print_regex_arr(@TEXTCMDLIST); - print "\nContext1 commands (last argument textual, command will be disabled in deleted passages, last argument will be shown as plain text):\n"; - print_regex_arr(@CONTEXT1CMDLIST); - print "\nContext2 commands (last argument textual, command and its argument will be disabled in deleted passages):\n"; - print_regex_arr(@CONTEXT2CMDLIST); - print "\nExclude list of Commands with last argument not textual (overrides patterns above):\n"; - print_regex_arr(@TEXTCMDEXCL); -} - - -if ($showconfig) { - print "Configuration variables:\n"; - print "MINWORDSBLOCK=$MINWORDSBLOCK\n"; - print "FLOATENV=$FLOATENV\n"; - print "PICTUREENV=$PICTUREENV\n"; - print "MATHENV=$MATHENV\n"; - print "MATHREPL=$MATHREPL\n"; - print "MATHARRENV=$MATHARRENV\n"; - print "MATHARRREPL=$MATHARRREPL\n"; - print "ARRENV=$ARRENV\n"; - print "COUNTERCMD=$COUNTERCMD\n"; -} -if ($showconfig || $showtext || $showsafe || $showpreamble) { - exit 0; } -if ( @ARGV != 2 ) { - print STDERR "2 and only 2 non-option arguments required. Write latexdiff -h to get help\n"; - exit(2); -} - -# Are extra spaces between command arguments permissible? -my $extraspace; -if ($allowspaces) { - $extraspace='\s*'; -} else { - $extraspace=''; -} - -# append context lists to text lists (as text property is implied) -push @TEXTCMDLIST, @CONTEXT1CMDLIST; -push @TEXTCMDLIST, @CONTEXT2CMDLIST; - -push @TEXTCMDLIST, @MATHTEXTCMDLIST if $mathmarkup==COARSE; - -# internal additions to SAFECMDLIST -push(@SAFECMDLIST, qr/^QLEFTBRACE$/, qr/^QRIGHTBRACE$/); - - -# Patterns. These are used by some of the subroutines, too -# I can only define them down here because value of extraspace depends on an option - my $pat0 = '(?:[^{}])*'; - my $pat1 = '(?:[^{}]|\{'.$pat0.'\})*'; - my $pat2 = '(?:[^{}]|\{'.$pat1.'\})*'; - my $pat3 = '(?:[^{}]|\{'.$pat2.'\})*'; - my $pat4 = '(?:[^{}]|\{'.$pat3.'\})*'; - my $pat5 = '(?:[^{}]|\{'.$pat4.'\})*'; - my $pat6 = '(?:[^{}]|\{'.$pat5.'\})*'; - my $brat0 = '(?:[^\[\]]|\\\[|\\\])*'; - - my $quotemarks = '(?:\'\')|(?:\`\`)'; - my $punct='[0.,\/\'\`:;\"\?\(\)\[\]!~\p{IsNonAsciiPunct}\p{IsNonAsciiS}]'; - my $number='-?\d*\.\d*'; - my $mathpunct='[+=<>\-\|]'; - my $and = '&'; - my $coords= '[\-.,\s\d]*'; -# word: sequence of letters or accents followed by letter - my $word='(?:[-\w\d*]|\\\\[\"\'\`~^][A-Za-z\*])+'; - my $cmdleftright='\\\\(?:left|right|[Bb]igg?[lrm]?|middle)\s*(?:[()\[\]|]|\\\\(?:[|{}]|\w+))'; - - my $cmdoptseq='\\\\[\w\d\*]+'.$extraspace.'(?:(?:\['.$brat0.'\]|\{'. $pat6 . '\}|\(' . $coords .'\))'.$extraspace.')*'; - my $backslashnl='\\\\\n'; - my $oneletcmd='\\\\.\*?(?:\['.$brat0.'\]|\{'. $pat6 . '\})*'; - my $math='\$(?:[^$]|\\\$)*?\$|\\\\[(].*?\\\\[)]'; -## the current maths command cannot cope with newline within the math expression - - my $comment='%.*?\n'; - my $pat=qr/(?:\A\s*)?(?:${and}|${quotemarks}|${number}|${word}|$cmdleftright|${cmdoptseq}|${math}|${backslashnl}|${oneletcmd}|${comment}|${punct}|${mathpunct}|\{|\})\s*/ ; - - - -# now we are done setting up and can start working -my ($oldfile, $newfile) = @ARGV; -# check for existence of input files -if ( ! -e $oldfile ) { - die "Input file $oldfile does not exist."; -} -if ( ! -e $newfile ) { - die "Input file $newfile does not exist."; -} - - -# set the labels to be included into the file -my ($oldtime,$newtime,$oldlabel,$newlabel); -if (defined($labels[0])) { - $oldlabel=$labels[0] ; -} else { - $oldtime=localtime((stat($oldfile))[9]); - $oldlabel="$oldfile " . " "x(length($newfile)-length($oldfile)) . $oldtime; -} -if (defined($labels[1])) { - $newlabel=$labels[1] ; -} else { - $newtime=localtime((stat($newfile))[9]); - $newlabel="$newfile " . " "x(length($oldfile)-length($newfile)) . $newtime; -} - -$encoding=guess_encoding($newfile) unless defined($encoding); - -$encoding = "utf8" if $encoding =~ m/^utf8/i ; -if (lc($encoding) eq "utf8" ) { - binmode(STDOUT, ":utf8"); - binmode(STDERR, ":utf8"); -} - -$old=read_file_with_encoding($oldfile,$encoding); -$new=read_file_with_encoding($newfile,$encoding); - - - - -# reset time -exetime(1); -($oldpreamble,$oldbody,$oldpost)=splitdoc($old,'\\\\begin\{document\}','\\\\end\{document\}'); - - -($newpreamble,$newbody,$newpost)=splitdoc($new,'\\\\begin\{document\}','\\\\end\{document\}'); - - -if ($flatten) { - $oldbody=flatten($oldbody,$oldpreamble,$oldfile,$encoding); - $newbody=flatten($newbody,$newpreamble,$newfile,$encoding); -} - -my @auxlines; -if ( length $oldpreamble && length $newpreamble ) { - # pre-process preamble by looking for commands used in \maketitle (title, author, date etc commands) - # and marking up content with latexdiff markup - @auxlines=preprocess_preamble($oldpreamble,$newpreamble); - - @oldpreamble = split /\n/, $oldpreamble; - @newpreamble = split /\n/, $newpreamble; - - # If a command is defined in the preamble of the new file, and only uses safe commands, then it can be considered to be safe) (contribution S. Gouezel) - # Base this assessment on the new preamble - add_safe_commands($newpreamble); - - %packages=list_packages(@newpreamble) unless %packages; - if (defined $packages{"hyperref"} ) { - print STDERR "hyperref package detected.\n" if $verbose ; - $latexdiffpreamble =~ s/\{\\DIFadd\}/{\\DIFaddtex}/g; - $latexdiffpreamble =~ s/\{\\DIFdel\}/{\\DIFdeltex}/g; - $latexdiffpreamble .= join "\n",(extrapream("HYPERREF"),""); - } - print STDERR "Differencing preamble.\n" if $verbose; - - # insert dummy first line such that line count begins with line 1 (rather than perl's line 0) - just so that line numbers inserted by linediff are correct - unshift @newpreamble,''; - unshift @oldpreamble,''; - @diffpreamble = linediff(\@oldpreamble, \@newpreamble); - # remove dummy line again - shift @diffpreamble; - # add filenames, modification time and latexdiff mark - defined($nolabel) or splice @diffpreamble,1,0, - "%DIF LATEXDIFF DIFFERENCE FILE", - ,"%DIF DEL $oldlabel", - "%DIF ADD $newlabel"; - if ( @auxlines ) { - push @diffpreamble,"%DIF DELETED TITLE COMMANDS FOR MARKUP"; - push @diffpreamble,join("\n",@auxlines); - } - push @diffpreamble,$latexdiffpreamble; - push @diffpreamble,'\begin{document}'; -} -elsif ( !length $oldpreamble && !length $newpreamble ) { - @diffpreamble=(); -} else { - print STDERR "Either both texts must have preamble or neither text must have the preamble.\n"; - exit(2); -} - -if (defined $packages{"amsmath"} or defined $packages{"amsart"} or defined $packages{"amsbook"} ) { - print STDERR "amsmath package detected.\n" if $verbose ; - $MATHARRREPL='align*'; -} - -print STDERR "Preprocessing body. " if $verbose; -my ($oldleadin,$newleadin)=preprocess($oldbody,$newbody); - - -# run difference algorithm -@diffbody=bodydiff($oldbody, $newbody); -$diffbo=join("",@diffbody); -if ( $debug ) { - open(RAWDIFF,">","latexdiff.debug.bodydiff"); - print RAWDIFF $diffbo; - close(RAWDIFF); -} -print STDERR "(",exetime()," s)\n","Postprocessing body. \n " if $verbose; -postprocess($diffbo); -$diffall =join("\n",@diffpreamble) ; -# add visible labels -if (defined($visiblelabel)) { - # Give information right after \begin{document} (or at the beginning of the text for files without preamble - ### if \date command is used, add information to \date argument, otherwise give right after \begin{document} - ### $diffall=~s/(\\date$extraspace(?:\[$brat0\])?$extraspace)\{($pat6)\}/$1\{$2 \\ LATEXDIFF comparison \\ Old: $oldlabel \\ New: $newlabel \}/ or - $diffbo = "\\begin{verbatim}LATEXDIFF comparison\nOld: $oldlabel\nNew: $newlabel\\end{verbatim}\n$diffbo" ; -} - -$diffall .= "$newleadin$diffbo" ; -$diffall .= "\\end{document}$newpost" if length $newpreamble ; -if ( lc($encoding) ne "utf8" && lc($encoding) ne "ascii" ) { - print STDERR "Encoding output file to $encoding\n" if $verbose; - $diffall=Encode::encode($encoding,$diffall); - binmode STDOUT; -} -print $diffall; - - -print STDERR "(",exetime()," s)\n","Done.\n" if $verbose; - - - -## guess_encoding(filename) -## reads the first 20 lines of filename and looks for call of inputenc package -## if found, return the option of this package (encoding), otherwise return ascii -sub guess_encoding { - my ($filename)=@_; - my ($i,$enc); - open (FH, $filename) or die("Couldn't open $filename: $!"); - $i=0; - while () { - next if /^\s*%/; # skip comment lines - if (m/\\usepackage\[(\w*?)\]\{inputenc\}/) { - close(FH); - return($1); - } - last if (++$i > 20 ); # scan at most 20 non-comment lines - } - close(FH); - return("ascii"); -} - - -sub read_file_with_encoding { - my ($output); - my ($filename, $encoding) = @_; - - if (lc($encoding) eq "utf8" ) { - open (FILE, "<:utf8",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } elsif ( lc($encoding) eq "ascii") { - open (FILE, $filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } else { - require Encode; - open (FILE, "<",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - print STDERR "Converting $filename from $encoding to utf8\n" if $verbose; - $output=Encode::decode($encoding,$output); - } - close FILE; - if ($^O eq "linux" ) { - $output =~ s/\r\n/\n/g ; - } - return $output; -} - -# %packages=list_packages(@preamble) -# scans the arguments for \documentclass and \usepackage statements and constructs a hash -# whose keys are the included packages, and whose values are the associated optional arguments -sub list_packages { - my (@preamble)=@_; - my %packages=(); - foreach $line ( @preamble ) { - # get rid of comments - $line=~s/(?catfile($dirname,$fname), "\n" if $debug; - # content of file becomes replacement value (use recursion), add \newpage if the command was include - ###$replacement=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - $replacement=flatten(read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding), $preamble,$filename,$encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - # \include always starts a new page; use explicit \newpage command to simulate this - $begline=(defined($1)? $1 : "") ; - $newpage=(defined($3)? " \\newpage " : "") ; - "$begline$newpage$replacement$newpage"; - }/exgm; - - return($text); -} - - -# print_regex_arr(@arr) -# prints regex array without x-ism expansion put in by pearl to stdout -sub print_regex_arr { - my $dumstring; - $dumstring = join(" ",@_); # PERL generates string (?-xism:^ref$) for quoted refex ^ref$ - $dumstring =~ s/\(\?-xism:\^(.*?)\$\)/$1/g; # remove string and ^,$ marks before output - print $dumstring,"\n"; -} - - -# @lines=extrapream($type) -# reads line from appendix (end of file after __END__ token) -sub extrapream { - my $type; - my @retval=("%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - my ($copy); - - while (@_) { - $copy=0; - $type=shift ; - if ( -f $type ) { - open (FILE,$type) or die "Cannot open preamble file $type: $!"; - print STDERR "Reading preamble file $type\n" if $verbose ; - while () { - chomp ; - if ( $_ =~ m/%DIF PREAMBLE/ ) { - push (@retval,"$_"); - } else { - push (@retval,"$_ %DIF PREAMBLE"); - } - } - } - else { # not (-f $type) - $type=uc($type); # upcase argument - print STDERR "Preamble Internal Type $type\n" if $verbose; - while () { - if ( m/^%DIF $type/ ) { - $copy=1; } - elsif ( m/^%DIF END $type/ ) { - last; } - chomp; - push (@retval,"$_ %DIF PREAMBLE") if $copy; - } - if ( $copy == 0 ) { - print STDERR "\nPreamble style $type not implemented.\n"; - print STDERR "Write latexdiff -h to get help with available styles\n"; - exit(2); - } - seek DATA,0,0; # rewind DATA handle to file begin - } - } - push (@retval,"%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - return @retval; -} - - -# ($part1,$part2,$part3)=splitdoc($text,$word1,$word2) -# splits $text into 3 parts at $word1 and $word2. -# if neither $word1 nor $word2 exist, $part1 and $part3 are empty, $part2 is $text -# If only $word1 or $word2 exist but not the other, output an error message. - -# NB this version avoids $` and $' for performance reason although it only makes a tiny difference -# (in one test gain a tenth of a second for a 30s run) -sub splitdoc { - my ($text,$word1,$word2)=@_; - my ($part1,$part2,$part3)=("","",""); - my ($rest,$pos); - - if ( $text =~ m/(^[^%]*)($word1)/mg ) { - $pos=pos $text; - $part1=substr($text,0,$pos-length($2)); - $rest=substr($text,$pos); - if ( $rest =~ m/(^[^%]*)($word2)/mg ) { - $pos=pos $rest; - $part2=substr($rest,0,$pos-length($2)); - $part3=substr($rest,$pos); - } - else { - die "$word1 and $word2 not in the correct order or not present as a pair." ; - } - } else { - $part2=$text; - die "$word2 present but not $word1." if ( $text =~ m/(^[^%]*)$word2/ms ); - } - return ($part1,$part2,$part3); -} - - - - - -# bodydiff($old,$new) -sub bodydiff { - my ($oldwords, $newwords) = @_; - my @retwords; - - print STDERR "(",exetime()," s)\n","Splitting into latex tokens \n" if $verbose; - print STDERR "Parsing $oldfile \n" if $verbose; - my @oldwords = splitlatex($oldwords); - print STDERR "Parsing $newfile \n" if $verbose; - my @newwords = splitlatex($newwords); - - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - print STDERR "(",exetime()," s)\n","Pass 1: Expanding text commands and merging isolated identities with changed blocks " if $verbose; - pass1(\@oldwords, \@newwords); - - - print STDERR "(",exetime()," s)\n","Pass 2: inserting DIF tokens and mark up. " if $verbose; - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold2.tex"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew2.tex"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - @retwords=pass2(\@oldwords, \@newwords); - - return(@retwords); -} - - - - -# @words=splitlatex($string) -# split string according to latex rules -# Each element of words is either -# a word (including trailing spaces and punctuation) -# a latex command -sub splitlatex { - my ($string) = @_ ; - # if input is empty, return empty list - length($string)>0 or return (); - - my @retval=($string =~ m/$pat/osg); - - if (length($string) != length(join("",@retval))) { - print STDERR "\nWARNING: Inconsistency in length of input string and parsed string:\n This often indicates faulty or non-standard latex code.\n In many cases you can ignore this and the following warning messages.\n Note that character numbers in the following are counted beginning after \\begin{document} and are only approximate." unless $ignorewarnings; - print STDERR "DEBUG Original length ",length($string)," Parsed length ",length(join("",@retval)),"\n" if $debug; - print STDERR "DEBUG Input string: |$string|\n" if (length($string)<500) && $debug; - print STDERR "DEBUG Token parsing: |",join("+",@retval),"|\n" if (length($string)<500) && $debug ; - @retval=(); - # slow way only do this if other m//sg method fails - my $last = 0; - while ( $string =~ m/$pat/osg ) { - my $match=$&; - if ($last + length $& != pos $string ) { - my $pos=pos($string); - my $offset=30<$last ? 30 : $last; - my $dum=substr($string,$last-$offset,$pos-$last+2*$offset); - my $dum1=$dum; - my $cnt=$#retval; - my $i; - $dum1 =~ s/\n/ /g; - unless ($ignorewarnings) { - print STDERR "\n$dum1\n"; - print STDERR " " x 30,"^" x ($pos-$last)," " x 30,"\n"; - print STDERR "Missing characters near word " . (scalar @retval) . " character index: " . $last . "-" . pos($string) . " Length: " . length($match) . " Match: |$match| (expected match marked above).\n"; - } - # put in missing characters `by hand' - push (@retval, substr($dum,$offset,$pos-$last-length($match))); -# Note: there seems to be a bug in substr with utf8 that made the following line output substr which were too long, -# using dum instead appears to work -# push (@retval, substr($string,$last, pos($string)-$last-length($match))); - } - push (@retval, $match); - $last=pos $string; - } - - } - return @retval; -} - - -# pass1( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Where an common-subsequence block is flanked by deleted or appended blocks, -# and is shorter than $MINWORDSBLOCK words it is appended -# to the last deleted or appended word. If the block contains tokens other than words -# or punctuation it is not merged. -# Deleted or appended block consisting of words and safe commands only are -# also merged, to prevent break-up in pass2 (after previous isolated words have been removed) -# If there are commands with textual arguments (e.g. \caption) both in corresponding -# appended and deleted blocks split them such that the command and opening bracket -# are one token, then the rest is split up following standard rules, and the closing -# bracket is a separate token, ie. turn -# "\caption{This is a textual argument}" into -# ("\caption{","This ","is ","a ","textual ","argument","}") -# No return value. Destructively changes sequences -sub pass1 { - my $seq1 = shift ; - my $seq2 = shift ; - - my $len1 = scalar @$seq1; - my $len2 = scalar @$seq2; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - - my ($last1,$last2)=(-1,-1) ; - my $cnt=0; - my $block=[]; - my $addblock=[]; - my $delblock=[]; - my $todo=[]; - my $instruction=[]; - my $i; - my (@delmid,@addmid,@dummy); - - my ($addcmds,$delcmds,$matchindex); - my ($addtextblocks,$deltextblocks); - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $adddiscard = sub { - if ($cnt > 0 ) { - $matblkcnt++; - # just after an unchanged block -# print STDERR "Unchanged block $cnt, $last1,$last2 \n"; - if ($cnt < $MINWORDSBLOCK - && $cnt==scalar ( - grep { /^$wpat/ || ( /^\\([\w\d\*]+)((?:\[$brat0\]|\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && scalar(@dummy=split(" ",$2))<3 ) } - @$block) ) { - # merge identical blocks shorter than $MINWORDSBLOCK - # and only containing ordinary words - # with preceding different word - # We cannot carry out this merging immediately as this - # would change the index numbers of seq1 and seq2 and confuse - # the algorithm, instead we store in @$todo where we have to merge - push(@$todo, [ $last1,$last2,$cnt,@$block ]); - } - $block = []; - $cnt=0; $last1=-1; $last2=-1; - } - }; - my $discard=sub { $deltokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$delblock,[ $seq1->[$_[0]],$_[0] ]); - $last1=$_[0] }; - - my $add = sub { $addtokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$addblock,[ $seq2->[$_[1]],$_[1] ]); - $last2=$_[1] }; - - my $match = sub { $mattokcnt++; - if ($cnt==0) { # first word of matching sequence after changed sequence or at beginning of word sequence - $deltextblocks = extracttextblocks($delblock); - $delblkcnt++ if scalar @$delblock; - $addtextblocks = extracttextblocks($addblock); - $addblkcnt++ if scalar @$addblock; - - $delcmds = extractcommands($delblock); - $addcmds = extractcommands($addblock); - # keygen(third argument of _longestCommonSubsequence) implies to sort on command (0th elements of $addcmd elements) - # the calling format for longestCommonSubsequence has changed between versions of - # Algorithm::Diff so we need to check which one we are using - if ( $algodiffversion > 1.15 ) { - ### Algorithm::Diff 1.19 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, 0, sub { $_[0]->[0] } ); - } else { - ### Algorithm::Diff 1.15 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, sub { $_[0]->[0] } ); - } - - for ($i=0 ; $i<=$#$matchindex ; $i++) { - if (defined($matchindex->[$i])){ - $j=$matchindex->[$i]; - @delmid=splitlatex($delcmds->[$i][3]); - @addmid=splitlatex($addcmds->[$j][3]); - while (scalar(@$deltextblocks) && $deltextblocks->[0][0]<$delcmds->[$i][1]) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) }; - push(@$todo, [$index,-1,$cnt,@$block]); - } - push(@$todo, [ $delcmds->[$i][1],-1,-1,$delcmds->[$i][2],@delmid,$delcmds->[$i][4]]); - - while (scalar(@$addtextblocks) && $addtextblocks->[0][0]<$addcmds->[$j][1]) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - push(@$todo, [ -1,$addcmds->[$j][1],-1,$addcmds->[$j][2],@addmid,$addcmds->[$j][4]]); - } - } - # mop up remaining textblocks - while (scalar(@$deltextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) } ; - push(@$todo, [$index,-1,$cnt,@$block]); - } - while (scalar(@$addtextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - - $addblock=[]; - $delblock=[]; - } - push(@$block,$seq2->[$_[1]]); - $cnt++ }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - - - # now carry out the merging/splitting. Refer to elements relative from - # the end (with negative indices) as these offsets don't change before the instruction is executed - # cnt>0: merged small unchanged groups with previous changed blocks - # cnt==-1: split textual commands into components - foreach $instruction ( @$todo) { - ($last1,$last2,$cnt,@$block)=@$instruction ; - if ($cnt>=0) { - splice(@$seq1,$last1-$len1,1+$cnt,join("",$seq1->[$last1-$len1],@$block)) if $last1>=0; - splice(@$seq2,$last2-$len2,1+$cnt,join("",$seq2->[$last2-$len2],@$block)) if $last2>=0; - } else { - splice(@$seq1,$last1-$len1,1,@$block) if $last1>=0; - splice(@$seq2,$last2-$len2,1,@$block) if $last2>=0; - } - } - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens in $matblkcnt blocks.\n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } -} - - -# extracttextblocks(\@blockindex) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [[ $index, $textblock, $cnt ], .. -# where $index index of block to be merged -# $textblock contains all the words to be merged with the word at $index (but does not contain this word) -# $cnt is length of block -# -# requires: iscmd -# -sub extracttextblocks { - my $block=shift; - my ($i,$token,$index); - my $textblock=[]; - my $last=-1; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # store pure text blocks - if ($token =~ /$wpat/ || ( $token =~/^\\([\w\d\*]+)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && !iscmd($1,\@TEXTCMDLIST,\@TEXTCMDEXCL))) { - # we have text or a command which can be treated as text - if ($last<0) { - # new pure-text block - $last=$index; - } else { - # add to pure-text block - push(@$textblock, $token); - } - } else { - # it is not text - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - $textblock=[]; - $last=-1; - } - } - # finish processing a possibly unfinished block before returning - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - return($retval) -} - - - -# extractcommands( \@blockindex ) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [ [ "\cmd1", index, "\cmd1[optarg]{arg1}{", "arg2" ,"} " ],.. -# where index is just taken from input array -# command must have a textual argument as last argument -# -# requires: iscmd -# -sub extractcommands { - my $block=shift; - my ($i,$token,$index,$cmd,$open,$mid,$closing); - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: \cmd - # $3: last argument - # $4: } + trailing spaces - if ( ( $token =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL) ) { - # push(@$retval,[ $2,$index,$1,$3,$4 ]); - ($cmd,$open,$mid,$closing) = ($2,$1,$3,$4) ; - $closing =~ s/\}/\\RIGHTBRACE/ ; - push(@$retval,[ $cmd,$index,$open,$mid,$closing ]); - } - } - return $retval; -} - -# iscmd($cmd,\@regexarray,\@regexexcl) checks -# return 1 if $cmd matches any of the patterns in the -# array $@regexarray, and none of the patterns in \@regexexcl, otherwise return 0 -sub iscmd { - my ($cmd,$regexar,$regexexcl)=@_; - my ($ret)=0; - foreach $pat ( @$regexar ) { - if ( $cmd =~ m/^${pat}$/ ) { - $ret=1 ; - last; - } - } - return 0 unless $ret; - foreach $pat ( @$regexexcl ) { - return 0 if ( $cmd =~ m/^${pat}$/ ); - } - return 1; -} - - -# pass2( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Mark begin and end of deleted and appended sequences with tags $DELOPEN and $DELCLOSE -# and $ADDOPEN and $ADDCLOSE, respectively, however exclude { } & and all comands, unless -# they match an element of the whitelist (SAFECMD) -# For words in TEXTCMD but not in SAFECMD, enclose interior with $ADDOPEN and $ADDCLOSE brackets -# Deleted comment lines are marked with %DIF < -# Added comment lines are marked with %DIF > -sub pass2 { - my $seq1 = shift ; - my $seq2 = shift ; - - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $retval = []; - my $delhunk = []; - my $addhunk = []; - - my $discard = sub { $deltokcnt++; - push ( @$delhunk, $seq1->[$_[0]]) }; - - my $add = sub { $addtokcnt++; - push ( @$addhunk, $seq2->[$_[1]]) }; - - my $match = sub { $mattokcnt++; - if ( scalar @$delhunk ) { - $delblkcnt++; - # mark up changes, but comment out commands - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk); - $delhunk = []; - } - if ( scalar @$addhunk ) { - $addblkcnt++; - # we mark up changes, but simply quote commands - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk); - $addhunk = []; - } - push(@$retval,$seq2->[$_[1]]) }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - # clear up unprocessed hunks - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk) if scalar @$delhunk; - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk) if scalar @$addhunk; - - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens. \n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } - - return(@$retval); -} - -# marktags($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,\@block) -# returns ($openmark,$open,$block,$close,$closemark) if @block only contains no commands (except white-listed ones), -# braces, ampersands, or comments -# mark comments with $comment -# exclude all other exceptions from scope of open, close like this -# ($openmark, $open,...,$close, $opencmd,command, command,$closecmd, $open, ..., $close, $closemark) -# If $opencmd begins with "%" marktags assumes it is operating on a deleted block, otherwise on an added block -sub marktags { - my ($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,$block)=@_; - my $word; - my (@argtext); - my $retval=[]; - my $noncomment=0; - my $cmd=-1; # -1 at beginning 0: last token written is a ordinary word - # 1: last token written is a command - # for keeping track whether we are just in a command sequence or in a word sequence - my $cmdcomment= ($opencmd =~ m/^%/); # Flag to indicate whether opencmd is a comment (i.e. if we intend to simply comment out changed commands) - my ($command,$commandword,$closingbracket) ; # temporary variables needed below to remember sub-pattern matches - -# split this block to flatten out sequences joined in pass1 - @$block=splitlatex(join "",@$block); - foreach (@$block) { - $word=$_; - if ( $word =~ s/^%/%$comment/ ) { - # a comment - if ($cmd==1) { - push (@$retval,$closecmd) ; - $cmd=-1; - } - push (@$retval,$word); - next; - } - if (! $noncomment) { - push (@$retval,$openmark); - $noncomment=1; - } - # negative lookahead pattern (?!) in second clause is put in to avoid mathcing \( .. \) patterns - # also note that second pattern will match \\ - # Note: the second pattern should really be $word =~ /^\\(?!\()(\\|[\w*@]+)/, ie * replaced by + - # and then all commands \" \' etc declared safe. But as I don't have a complete list of one letter - # commands, and nobody has complained so far, I will eave this as is - if ( $word =~ /^[&{}\[\]]/ || ( $word =~ /^\\(?!\()(\\|[\w*@]*)/ && !iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL)) ) { - # word is a command or other significant token (not in SAFECMDLIST) - ## same conditions as in subroutine extractcommand: - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: cmd - # $3: last argument - # $4: } + trailing spaces - ### pre-0.3 if ( ( $token =~ m/^(\\([\w\d\*]+)(?:\[$brat0\]|\{$pat6\})*\{)($pat6)(\}\s*)$/so ) - if ( ( $word =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && (iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL)|| iscmd($2,\@MATHTEXTCMDLIST,\@MATHTEXTCMDEXCL)) - && ( !$cmdcomment || !iscmd($2,\@CONTEXT2CMDLIST, \@CONTEXT2CMDEXCL) ) ) { - # Condition 1: word is a command? - if yes, $1,$2,.. will be set as above - # Condition 2: word is a text command - we mark up the interior of the word. There is a separate check for MATHTEXTCMDLIST - # because for $mathmarkup=WHOLE, the commands should not be split in pass1 (ie. math mode commands are not in - # TEXTCMDLIST, but the interior of MATHTEXT commands should be highlighted in both deleted and added blocks - # Condition 3: But if we are in a deleted block ($cmdcomment=1) and - # $2 (the command) is in context2, just treat it as an ordinary command (i.e. comment it open with $opencmd) - # Because we do not want to disable this command - # here we do not use $opencmd and $closecmd($opencmd is empty) - if ($cmd==1) { - push (@$retval,$closecmd) ; - } elsif ($cmd==0) { - push (@$retval,$close) ; - } - $command=$1; $commandword=$2; $closingbracket=$4; - @argtext=splitlatex($3); # split textual argument into tokens - # and mark it up (but we do not need openmark and closemark) - # insert command with initial arguments, marked-up final argument, and closing bracket - if ( $cmdcomment && iscmd($commandword,\@CONTEXT1CMDLIST, \@CONTEXT1CMDEXCL) ) { - # context1cmd in a deleted environment; delete command itself but keep last argument, marked up - push (@$retval,$opencmd); - $command =~ s/\n/\n${opencmd}/sg ; # repeat opencmd at the beginning of each line - # argument, note that the additional comment character is included - # to suppress linebreak after opening parentheses, which is important - # for latexrevise - push (@$retval,$command,"%\n{$AUXCMD\n",marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } elsif ( iscmd($commandword,,\@MATHTEXTCMDLIST, \@MATHTEXTCMDEXCL) ) { - # MATHBLOCK pseudo command: consider all commands safe, except & and \\ - # Keep these commands even in deleted blocks, hence set $opencmd and $closecmd (5th and 6th argument of marktags) to - # "" - local @SAFECMDLIST=(".*"); - local @SAFECMDEXCL=('\\','\\\\'); - push(@$retval,$command,marktags("","",$open,$close,"","",$comment,\@argtext)#@argtext - ,$closingbracket); - } else { - # normal textcmd or context1cmd in an added block - push (@$retval,$command,marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } - push (@$retval,$AUXCMD,"\n") if $cmdcomment ; - $cmd=-1 ; - } else { - # ordinary command - push (@$retval,$opencmd) if $cmd==-1 ; - push (@$retval,$close,$opencmd) if $cmd==0 ; - $word =~ s/\n/\n${opencmd}/sg if $cmdcomment ; # if opencmd is a comment, repeat this at the beginning of every line - push (@$retval,$word); - $cmd=1; - } - } else { - # just an ordinary word or word in SAFECMD - push (@$retval,$open) if $cmd==-1 ; - push (@$retval,$closecmd,$open) if $cmd==1 ; - push (@$retval,$word); - $cmd=0; - } - } - push (@$retval,$close) if $cmd==0; - push (@$retval,$closecmd) if $cmd==1; - - push (@$retval,$closemark) if ($noncomment); - return @$retval; -} - -# preprocess($string, ..) -# carry out the following pre-processing steps for all arguments: -# 1. Remove leading white-space -# Change \{ to \LEFTBRACE and \} to \RIGHTBRACE -# #. change begin and end commands within comments to BEGINDIF, ENDDIF -# so they don't disturb the pattern matching (if there are several \begin or \end in one line -# 2. mark all first empty line (in block of several) with \PAR tokens -# 3. Convert all '\%' into '\PERCENTAGE ' to make parsing regular expressions easier -# 4. Convert all \verb|some verbatim text| commands (where | can be an arbitrary character) -# into \verb{hash} -# 5. Convert \begin{verbatim} some verbatim text \end{verbatim} into \verbatim{hash} -# 6. Convert _n into \SUBSCRIPTNB{n} and _{nnn} into \SUBSCRIPT{nn} -# 7. Convert ^n into \SUPERSCRIPTNB{n} and ^{nnn} into \SUPERSCRIPT{nn} -# 8. a. Convert $$ $$ into \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} -# b. Convert \[ \] into \begin{SQUAREBRACKET} \end{SQUAREBRACKET} -# 9. Convert all picture environmentent (\begin{PICTUREENV} .. \end{PICTUREENV} \PICTUREBLOCKenv -# For --block-math-markup option -convert all \begin{MATH} .. \end{MATH} -# into \MATHBLOCKmath{...} commands, where MATH/math is any valid math environment - -# 10. Add final token STOP to the very end. This is put in because the algorithm works better if the last token is identical. This is removed again in postprocessing. -# -# NB: step 6 and 7 is likely to convert some "_" inappropriately, e.g. in file -# names or labels but it does not matter because they are converted back in the postprocessing step -# Returns: leading white space removed in step 1 -sub preprocess { - my @leadin=() ; - for (@_) { - s/^(\s*)//s; - push(@leadin,$1); - # Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE - s/(?{$hstr}) && $string ne $hash->{$hstr}) { - warn "Repeated hash value for verbatim mode in spite of different content."; - $hstr="-$hstr"; - } - $hash->{$hstr}=$string; - return($hstr); -} - -#string=fromhash(\%hash,$fromstring) -# restores string value stored in hash -#string=fromhash(\%hash,$fromstring,$prependstring) -# additionally begins each line with prependstring -sub fromhash { - my ($hash,$hstr)=($_[0],$_[1]); - my $retstr=$hash->{$hstr}; - if ( $#_ >= 2) { - $retstr =~ s/^/$_[2]/mg; - } - return $retstr; -} - - -# postprocess($string, ..) -# carry out the following post-processing steps for all arguments: -# * Remove STOP token from the end -# * Replace \RIGHTBRACE by } -# * change citation commands within comments to protect from processing (using marker CITEDIF) -# 1. Check all deleted blocks: -# a.where a deleted block contains a matching \begin and -# \end environment (these will be disabled by a %DIFDELCMD statements), for selected environments enable -# these commands again (such that for example displayed math in a deleted equation -# is properly within math mode. For math mode environments replace numbered equation -# environments with their display only variety (so that equation numbers in new file and -# diff file are identical). Where the correct type of math environment cannot be determined -# use a place holder MATHMODE -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file -# Replace all MATHMODE environment commands by the correct environment to achieve matching -# pairs -# c. Convert MATHBLOCKmath commands to their uncounted numbers (e.g. convert equation -> displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL -# d. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# For added blocks: -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# 2. If --block-math-markup option set: Convert \MATHBLOCKmath{..} commands back to environments -# -# Convert all PICTUREblock{..} commands back to the appropriate environments -# 3. Convert DIFadd, DIFdel, DIFFaddbegin , ... into FL varieties -# within floats (currently recognised float environments: plate,table,figure -# plus starred varieties). -# 4. Remove empty %DIFDELCMD < lines -# 4. Convert \begin{SQUAREBRACKET} \end{SQUAREBRACKET} into \[ \] -# Convert \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} into $$ $$ -# 5. Convert \SUPERSCRIPTNB{n} into ^n and \SUPERSCRIPT{nn} into ^{nnn} -# 6. Convert \SUBSCRIPTNB{n} into _n and \SUBCRIPT{nn} into _{nnn} -# 7. Expand hashes of verb and verbatim environments -# 8. Convert '\PERCENTAGE ' back into '\%' -# 9.. remove all \PAR tokens -# 10. package specific processing: endfloat: make sure \begin{figure} and \end{figure} are always -# on a line by themselves, similarly for table environment -# 4, undo renaming of the \begin and \end in comments -# Change \QLEFTBRACE, \QRIGHTBRACE to \{,\} -# -# Note have to manually synchronize substitution commands below and -# DIF.. command names in the header -sub postprocess { - my ($begin,$len,$cnt,$float,$delblock,$addblock); - # second level blocks - my ($begin2,$cnt2,$len2,$eqarrayblock,$mathblock); - - for (@_) { - - # change $'s in comments to something harmless - 1 while s/(%.*)\$/$1DOLLARDIF/mg ; - - # Remove final STOP token - s/ STOP$//; - # Replace \RIGHTBRACE by } - s/\\RIGHTBRACE/}/g; - - # change citation commands within comments to protect from processing - if ($CITECMD){ - 1 while s/(%.*)\\($CITECMD)/$1\\CITEDIF$2/m ; - } - # Check all deleted blocks: where a deleted block contains a matching \begin and - # \end environment (these will be disabled by a %DIFDELCMD statements), enable - # these commands again (such that for example displayed math in a deleted equation - # is properly within math mode. For math mode environments replace numbered equation - # environments with their display only variety (so that equation numbers in new file and - # diff file are identical - while ( m/\\DIFdelbegin.*?\\DIFdelend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $delblock=$&; - - - ### (.*?[^\n]?)\n? construct is necessary to avoid empty lines in math mode, which result in - ### an error - # displayed math environments - if ($mathmarkup == FINE ) { - $delblock=~ s/(\%DIFDELCMD < \s*\\begin\{((?:$MATHENV)|SQUAREBRACKET)\}.*?(?:$DELCMDCLOSE|\n))(.*?[^\n]?)\n?(\%DIFDELCMD < \s*\\end\{\2\})/\\begin{$MATHREPL}$AUXCMD\n$1$3\n\\end{$MATHREPL}$AUXCMD\n$4/sg; - # also transform the opposite pair \end{displaymath} .. \begin{displaymath} but we have to be careful not to interfere with the results of the transformation in the line directly above - ### pre-0.42 obsolete version which did not work on eqnarray test $delblock=~ s/(? displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL - $delblock=~ s/\\MATHBLOCK($MATHENV)\{($pat6)\}/\\MATHBLOCK$MATHREPL\{$2\}/sg; - $delblock=~ s/\\MATHBLOCK($MATHARRENV)\{($pat6)\}/\\MATHBLOCK$MATHARRREPL\{$2\}/sg; - } - - -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file - $delblock=~ s/\\($COUNTERCMD)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*\s*${AUXCMD}\n)/\\$1$2\\addtocounter{$1}{-1}${AUXCMD}\n/sg ; - - -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es - while ( $delblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($delblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($delblock,$begin2,$len2)=$mathblock; - pos($delblock) = $begin2 + length($mathblock); - } - if ($CITE2CMD) { - $delblock=~s/($DELCMDOPEN\s*\\($CITE2CMD)(.*)$DELCMDCLOSE)/ - # Replacement code - {my ($aux,$all); - $aux=$all=$1; - $aux=~s#\n?($DELCMDOPEN|$DELCMDCLOSE)##g; - $all."$aux$AUXCMD\n";}/sge; - } - # or protect \cite commands with \mbox - if ($CITECMD) { - $delblock=~s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat6\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified delblock - substr($_,$begin,$len)=$delblock; - pos = $begin + length($delblock); - } - # make the array modification in added blocks - while ( m/\\DIFaddbegin.*?\\DIFaddend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $addblock=$&; - while ( $addblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($addblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($addblock,$begin2,$len2)=$mathblock; - pos($addblock) = $begin2 + length($mathblock); - } - if ($CITECMD) { - my $addblockbefore=$addblock; - $addblock=~ s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat2\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified addblock - substr($_,$begin,$len)=$addblock; - pos = $begin + length($addblock); - } - - - ### old place for BEGINDIF, ENDDIF replacement - # change begin and end commands within comments such that they - # don't disturb the pattern matching (if there are several \begin or \end in one line - # this substitution is insufficient but that appears unlikely) - # This needs to be repeated here to also get rid of DIFdelcmd-protected environments - s/(%.*)\\begin\{(.*)$/$1\\BEGINDIF\{$2/mg ; - s/(%.*)\\end\{(.*)$/$1\\ENDDIF\{$2/mg ; - - # Replace MATHMODE environments from step 1a above by the correct Math environment - - # The next line is complicated. The negative look-ahead insertion makes sure that no \end{$MATHENV} (or other mathematical - # environments) are between the \begin{$MATHENV} and \end{MATHMODE} commands. This is necessary as the minimal matching - # is not globally minimal but only 'locally' (matching is beginning from the left side of the string) - if ( $mathmarkup == FINE ) { - 1 while s/\\begin{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}((?:.(?!(?:\\end{(?:(?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}|\\begin{MATHMODE})))*?)\\end{MATHMODE}/\\begin{$1}$2\\end{$1}/s; - 1 while s/\\begin{MATHMODE}((?:.(?!\\end{MATHMODE}))*?)\\end{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}/\\begin{$2}$1\\end{$2}/s; - # convert remaining \begin{MATHMODE} \end{MATHMODE} (and not containing & or \\ )into MATHREPL environments - s/\\begin{MATHMODE}((?:(.(?!(?[1])) { - $optargnew=$newhash{$cmd}->[1]; - } else { - $optargnew=""; - } - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - } else { - $optargold=""; - } - - if ( defined($oldhash{$cmd}) ) { - $argold=$oldhash{$cmd}->[2]; - } else { - $argold=""; - } - $argnew=$newhash{$cmd}->[2]; - $argdiff="{" . join("",bodydiff($argold,$argnew)) ."}"; - if ( length $optargnew ) { - $optargdiff="[".join("",bodydiff($optargold,$optargnew))."]" ; - $optargdiff =~ s/\\DIFaddbegin /\\DIFaddbeginFL /g; - $optargdiff =~ s/\\DIFaddend /\\DIFaddendFL /g; - $optargdiff =~ s/\\DIFadd\{/\\DIFaddFL{/g; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - ### print STDERR "DEBUG s/\\Q$newhash{$cmd}->[0]\\E/\\$cmd$optargdiff$argdiff/s\n"; - # Note: \Q and \E force literal interpretation of what it between them but allow - # variable interpolation, such that e.g. \title matches just that and not TAB-itle - $$newpreambleref=~s/\Q$newhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s; - # replace this in old preamble if necessary - if ( defined($oldhash{$cmd}->[0])) { - $$oldpreambleref=~s/\Q$oldhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s ; - } - ### print STDERR "DEBUG NEW PRE ".$$newpreambleref."\n"; - } - - foreach $cmd ( keys %oldhash ) { - # if this has already been dealt with above can just skip - next if defined($newhash{$cmd}) ; - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - $optargdiff="[".join("",bodydiff($optargold,""))."]" ; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - $argdiff="{" . join("",bodydiff($argold,"")) ."}"; - $auxline = "\\$cmd$optargdiff$argdiff"; - $auxline =~s/$/$AUXCMD/sg; - push @auxlines,$auxline; - } - # add auxcmd comment to highlight added lines - return(@auxlines); -} - - - -# @diffs=linediff(\@seq1, \@seq2) -# mark up lines like this -#%DIF mm-mmdnn -#%< old deleted line(s) -#%DIF ------- -#%DIF mmann-nn -#new appended line %< -#%DIF ------- -# Future extension: mark change explicitly -# Assumes: traverse_sequence traverses deletions before insertions in changed sequences -# all line numbers relative to line 0 (first line of real file) -sub linediff { - my $seq1 = shift ; - my $seq2 = shift ; - - my $block = []; - my $retseq = []; - my @begin=('','',''); # dummy initialisation - my $instring ; - - my $discard = sub { @begin=('d',$_[0],$_[1]) unless scalar @$block ; - push(@$block, "%DIF < " . $seq1->[$_[0]]) }; - my $add = sub { if (! scalar @$block) { - @begin=('a',$_[0],$_[1]) ;} - elsif ( $begin[0] eq 'd' ) { - $begin[0]='c'; $begin[2]=$_[1]; - push(@$block, "%DIF -------") } - push(@$block, $seq2->[$_[1]] . " %DIF > " ) }; - my $match = sub { if ( scalar @$block ) { - if ( $begin[0] eq 'd' && $begin[1]!=$_[0]-1) { - $instring = sprintf "%%DIF %d-%dd%d",$begin[1],$_[0]-1,$begin[2]; } - elsif ( $begin[0] eq 'a' && $begin[2]!=$_[1]-1) { - $instring = sprintf "%%DIF %da%d-%d",$begin[1],$begin[2],$_[1]-1; } - elsif ( $begin[0] eq 'c' ) { - $instring = sprintf "%%DIF %sc%s", - ($begin[1]==$_[0]-1) ? "$begin[1]" : $begin[1]."-".($_[0]-1) , - ($begin[2]==$_[1]-1) ? "$begin[2]" : $begin[2]."-".($_[1]-1) ; } - else { - $instring = sprintf "%%DIF %d%s%d",$begin[1],$begin[0],$begin[2]; } - push @$retseq, $instring,@$block, "%DIF -------" ; - $block = []; - } - push @$retseq, $seq2->[$_[1]] - }; - # key function: remove multiple spaces (such that insertion or deletion of redundant white space is not reported) - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - push @$retseq, @$block if scalar @$block; - - return wantarray ? @$retseq : $retseq ; -} - - - -# init_regex_arr_data(\@array,"TOKEN INIT") -# scans DATA file handel for line "%% TOKEN INIT" line -# then appends each line not beginning with % into array (as a quoted regex) -sub init_regex_arr_data { - my ($arr,$token)=@_; - my ($copy); - while () { - if ( m/^%%BEGIN $token\s*$/ ) { - $copy=1; } - elsif ( m/^%%END $token\s*/ ) { - last; } - chomp; - push (@$arr,qr/^$_$/) if ( $copy && !/^%/ ) ; - } - seek DATA,0,0; # rewind DATA handle to file begin -} - - -# init_regex_arr_ext(\@array,$arg) -# fills array with regular expressions. -# if arg is a file name, then read in list of regular expressions from that file -# (one expression per line) -# Otherwise treat arg as a comma separated list of regular expressions -sub init_regex_arr_ext { - my ($arr,$arg)=@_; - my $regex; - if ( -f $ arg ) { - open(FILE,"$arg") or die ("Couldn't open $arg: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@$arr,qr/^$_$/); - } - close(FILE); - } - else { - # assume it is a comma-separated list of reg-ex - foreach $regex (split(qr/(?=1) { - $reset=shift; - } - if ($reset) { - $lasttime=times(); - } - else { - $retval=times()-$lasttime; - $lasttime=$lasttime+$retval; - return($retval); - } -} - - -sub usage { - die <<"EOF"; -Usage: $0 [options] old.tex new.tex > diff.tex - -Compares two latex files and writes tex code to stdout, which has the same -format as new.tex but has all changes relative to old.tex marked up or commented. - ---type=markupstyle --t markupstyle Add code to preamble for selected markup style - Available styles: UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE - CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR - [ Default: UNDERLINE ] - ---subtype=markstyle --s markstyle Add code to preamble for selected style for bracketing - commands (e.g. to mark changes in margin) - Available styles: SAFE MARGINAL DVIPSCOL COLOR - [ Default: SAFE ] - ---floattype=markstyle --f markstyle Add code to preamble for selected style which - replace standard marking and markup commands within floats - (e.g., marginal remarks cause an error within floats - so marginal marking can be disabled thus) - Available styles: FLOATSAFE IDENTICAL - [ Default: FLOATSAFE ] - ---encoding=enc --e enc Specify encoding of old.tex and new.tex. Typical encodings are - ascii, utf8, latin1, latin9. A list of available encodings can be - obtained by executing - perl -MEncode -e 'print join ("\\n",Encode->encodings( ":all" )) ;' - [Default encoding is utf8 unless the first few lines of the preamble contain - an invocation "\\usepackage[..]{inputenc} in which case the - encoding chosen by this command is asssumed. Note that ASCII (standard - latex) is a subset of utf8] - ---preamble=file --p file Insert file at end of preamble instead of auto-generating - preamble. The preamble must define the following commands - \\DIFaddbegin,\\DIFaddend,\\DIFadd{..}, - \\DIFdelbegin,\\DIFdelend,\\DIFdel{..}, - and varieties for use within floats - \\DIFaddbeginFL,\\DIFaddendFL,\\DIFaddFL{..}, - \\DIFdelbeginFL,\\DIFdelendFL,\\DIFdelFL{..} - (If this option is set -t, -s, and -f options - are ignored.) - ---exclude-safecmd=exclude-file ---exclude-safecmd="cmd1,cmd2,..." --A exclude-file ---replace-safecmd=replace-file ---append-safecmd=append-file ---append-safecmd="cmd1,cmd2,..." --a append-file Exclude from, replace or append to the list of regex - matching commands which are safe to use within the - scope of a \\DIFadd or \\DIFdel command. The file must contain - one Perl-RegEx per line (Comment lines beginning with # or % are - ignored). A literal comma within the comma-separated list must be - escaped thus "\\,", Note that the RegEx needs to match the whole of - the token, i.e., /^regex\$/ is implied and that the initial - "\\" of the command is not included. The --exclude-safecmd - and --append-safecmd options can be combined with the --replace-safecmd - option and can be used repeatedly to add cumulatively to the lists. - ---exclude-textcmd=exclude-file ---exclude-textcmd="cmd1,cmd2,..." --X exclude-file ---replace-textcmd=replace-file ---append-textcmd=append-file ---append-textcmd="cmd1,cmd2,..." --x append-file Exclude from, replace or append to the list of regex - matching commands whose last argument is text. See - entry for --exclude-safecmd directly above for further details. - ---replace-context1cmd=replace-file ---append-context1cmd=append-file ---append-context1cmd="cmd1,cmd2,..." - Replace or append to the list of regex matching commands - whose last argument is text but which require a particular - context to work, e.g. \\caption will only work within a figure - or table. These commands behave like text commands, except when - they occur in a deleted section, when they are disabled, but their - argument is shown as deleted text. - ---replace-context2cmd=replace-file ---append-context2cmd=append-file ---append-context2cmd="cmd1,cmd2,..." - As corresponding commands for context1. The only difference is that - context2 commands are completely disabled in deleted sections, including - their arguments. - - ---config var1=val1,var2=val2,... --c var1=val1,.. Set configuration variables. --c configfile Available variables: - MINWORDSBLOCK (integer) - FLOATENV (RegEx) - PICTUREENV (RegEx) - MATHENV (RegEx) - MATHREPL (String) - MATHARRENV (RegEx) - MATHARRREPL (String) - ARRENV (RegEx) - COUNTERCMD (RegEx) - This option can be repeated. - - ---packages=pkg1,pkg2,.. - Tell latexdiff that .tex file is processed with the packages in list - loaded. This is normally not necessary if the .tex file includes the - preamble, as the preamble is automatically scanned for \\usepackage commands. - Use of the --packages option disables automatic scanning, so if for any - reason package specific parsing needs to be switched off, use --packages=none. - The following packages trigger special behaviour: - endfloat hyperref amsmath - [ Default: scan the preamble for \\usepackage commands to determine - loaded packages.] - ---show-preamble Print generated or included preamble commands to stdout. - ---show-safecmd Print list of regex matching and excluding safe commands. - ---show-textcmd Print list of regex matching and excluding commands with text argument. - ---show-config Show values of configuration variables - ---show-all Show all of the above - - NB For all --show commands, no old.tex or new.tex file needs to be given, and no - differencing takes place. - -Other configuration options: - ---allow-spaces Allow spaces between bracketed or braced arguments to commands - [Default requires arguments to directly follow each other without - intervening spaces] - ---math-markup=level Determine granularity of markup in displayed math environments: - Possible values for level are (both numerical and text labels are acceptable): - off or 0: suppress markup for math environments. Deleted equations will not - appear in diff file. This mode can be used if all the other modes - cause invalid latex code. - whole or 1: Differencing on the level of whole equations. Even trivial changes - to equations cause the whole equation to be marked changed. This - mode can be used if processing in coarse or fine mode results in - invalid latex code. - coarse or 2: Detect changes within equations marked up with a coarse - granularity; changes in equation type (e.g.displaymath to equation) - appear as a change to the complete equation. This mode is recommended - for situations where the content and order of some equations are still - being changed. [Default] - fine or 3: Detect small change in equations and mark up and fine granularity. - This mode is most suitable, if only minor changes to equations are - expected, e.g. correction of typos. - ---disable-citation-markup Suppress citation markup in styles using ulem (UNDERLINE, - FONTSTRIKE, CULINECHBAR) ---enable-citation-markup Protect citation commands in changed sections with \\mbox command - [i.e. use default behaviour for ulem package for other packages] - - -Miscelleneous options - ---label=label --L label Sets the labels used to describe the old and new files. The first use - of this option sets the label describing the old file and the second - use of the option sets the label for the new file. - [Default: use the filename and modification dates for the label] - ---no-label Suppress inclusion of old and new file names as comment in output file - ---visble-label Include old and new filenames (or labels set with --label option) as - visible output - ---flatten Replace \\input and \\include commands within body by the content - of the files in their argument. If \\includeonly is present in the - preamble, only those files are expanded into the document. However, - no recursion is done, i.e. \\input and \\include commands within - included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, - respectively, making it possible to organise files into old and new directories. - --flatten is applied recursively, so inputted files can contain further - \\input statements. - ---help --h Show this help text. - ---ignore-warnings Suppress warnings about inconsistencies in length between input - and parsed strings and missing characters. - ---verbose --V Output various status information to stderr during processing. - Default is to work silently. - ---version Show version number. - -EOF -} - -=head1 NAME - -latexdiff - determine and markup differences between two latex files - -=head1 SYNOPSIS - -B [ B ] F F > F - -=head1 DESCRIPTION - -Briefly, I is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called C and C, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. - -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "S>>" is appended to each added line, i.e. a -line present in C but not in C. Discarded lines - are deactivated by prepending "S>>". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file C will be similar to -C. At the end of the preamble, the definitions for I markup commands are inserted. -In differencing the main body of the text, I attempts to -satisfy the following guidelines (in order of priority): - -=over 3 - -=item 1 - -If both C and C are valid LaTeX, then the resulting -C should also be valid LateX. (NB If a few plain TeX commands -are used within C or C then C is not -guaranteed to work but usually will). - -=item 2 - -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -C. - -=item 3 - -If a changed passage contains text or text-producing commands, then -running C through LateX should produce output where added -and discarded passages are highlighted. - -=item 4 - -Where there are insignificant differences, e.g. in the positioning of -line breaks, C should follow the formatting of C - -=back - -For differencing the same algorithm as I is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, C<\caption> and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write - - \section{\textem{This is an emphasized section title}} - -and not - - \section {\textem{This is an emphasized section title}} - -or - - \section\textem{This is an emphasized section title} - -even though all varieties are the same to LaTeX (but see -B<--allow-spaces> option which allows the second variety). - -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the PICTUREENV configuration variable, set by -default to C and C environments; see B<--config> -option). The latter environment (C) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by C<\begin{DIFnomarkup}> and C<\end{DIFnomarkup}>. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, - -C<\newenvironment{DIFnomarkup}{}{}> - -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. - -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. - -All markup commands inserted by I begin with "C<\DIF>". Added -blocks containing words, commands or comments which are in C -but not in C are marked by C<\DIFaddbegin> and C<\DIFaddend>. -Discarded blocks are marked by C<\DIFdelbegin> and C<\DIFdelend>. -Within added blocks all text is highlighted with C<\DIFadd> like this: -C<\DIFadd{Added text block}> -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces "{" and "}" are never put within -the scope of C<\DIFadd>. Added comments are marked by prepending -"S >>". - -Within deleted blocks text is highlighted with C<\DIFdel>. Deleted -comments are marked by prepending "S >>". Non-safe command -and curly braces within deleted blocks are commented out with -"S >>". - - - -=head1 OPTIONS - -=head2 Preamble - -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. - -=over 4 - -=item B<--type=markupstyle> or -B<-t markupstyle> - -Add code to preamble for selected markup style. This option defines -C<\DIFadd> and C<\DIFdel> commands. -Available styles: - -C - -[ Default: C ] - -=item B<--subtype=markstyle> or -B<-s markstyle> - -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -C<\DIFaddbegin>, C<\DIFaddend>, C<\DIFdelbegin> and C<\DIFdelend> commands. -Available styles: C - -[ Default: C ] - -=item B<--floattype=markstyle> or -B<-f markstyle> - -Add code to preamble for selected style which -replace standard marking and markup commands within floats -(e.g., marginal remarks cause an error within floats -so marginal marking can be disabled thus). This option defines all -C<\DIF...FL> commands. -Available styles: C - -[ Default: C ] - -=item B<--encoding=enc> or -B<-e enc> - -Specify encoding of old.tex and new.tex. Typical encodings are -C, C, C, C. A list of available encodings can be -obtained by executing - -Cencodings( ":all" )) ;' > - -[Default encoding is utf8 unless the first few lines of the preamble contain -an invocation C<\usepackage[..]{inputenc}> in which case the -encoding chosen by this command is asssumed. Note that ASCII (standard -latex) is a subset of utf8] - -=item B<--preamble=file> or -B<-p file> - -Insert file at end of preamble instead of generating -preamble. The preamble must define the following commands -C<\DIFaddbegin, \DIFaddend, \DIFadd{..}, -\DIFdelbegin,\DIFdelend,\DIFdel{..},> -and varieties for use within floats -C<\DIFaddbeginFL, \DIFaddendFL, \DIFaddFL{..}, -\DIFdelbeginFL, \DIFdelendFL, \DIFdelFL{..}> -(If this option is set B<-t>, B<-s>, and B<-f> options -are ignored.) - -=item B<--packages=pkg1,pkg2,..> - -Tell latexdiff that .tex file is processed with the packages in list -loaded. This is normally not necessary if the .tex file includes the -preamble, as the preamble is automatically scanned for C<\usepackage> commands. -Use of the B<--packages> option disables automatic scanning, so if for any -reason package specific parsing needs to be switched off, use B<--packages=none>. -The following packages trigger special behaviour: - -=over 8 - -=item C - -Configuration variable amsmath is set to C (Default: C) - -=item C - -Ensure that C<\begin{figure}> and C<\end{figure}> always appear by themselves on a line. - -=item C - -Change name of C<\DIFadd> and C<\DIFdel> commands to C<\DIFaddtex> and C<\DIFdeltex> and -define new C<\DIFadd> and C<\DIFdel> commands, which provide a wrapper for these commands, -using them for the text but not for the link defining command (where any markup would cause -errors). - -=back - -[ Default: scan the preamble for C<\\usepackage> commands to determine - loaded packages.] - - - -=item B<--show-preamble> - -Print generated or included preamble commands to stdout. - -=back - -=head2 Configuration - -=over 4 - -=item B<--exclude-safecmd=exclude-file> or -B<-A exclude-file> or B<--exclude-safecmd="cmd1,cmd2,..."> - -=item B<--replace-safecmd=replace-file> - -=item B<--append-safecmd=append-file> or -B<-a append-file> or B<--append-safecmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions (RegEx) -matching commands which are safe to use within the -scope of a C<\DIFadd> or C<\DIFdel> command. The file must contain -one Perl-RegEx per line (Comment lines beginning with # or % are -ignored). Note that the RegEx needs to match the whole of -the token, i.e., /^regex$/ is implied and that the initial -"\" of the command is not included. -The B<--exclude-safecmd> and B<--append-safecmd> options can be combined with the -B<--replace-safecmd> -option and can be used repeatedly to add cumulatively to the lists. - B<--exclude-safecmd> -and B<--append-safecmd> can also take a comma separated list as input. If a -comma for one of the regex is required, escape it thus "\,". In most cases it -will be necessary to protect the comma-separated list from the shell by putting -it in quotation marks. - -=item B<--exclude-textcmd=exclude-file> or -B<-X exclude-file> or B<--exclude-textcmd="cmd1,cmd2,..."> - -=item B<--replace-textcmd=replace-file> - -=item B<--append-textcmd=append-file> or -B<-x append-file> or B<--append-textcmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions -matching commands whose last argument is text. See -entry for B<--exclude-safecmd> directly above for further details. - - -=item B<--replace-context1cmd=replace-file> - -=item B<--append-context1cmd=append-file> or -=item B<--append-context1cmd="cmd1,cmd2,..."> - -Replace or append to the list of regex matching commands -whose last argument is text but which require a particular -context to work, e.g. \caption will only work within a figure -or table. These commands behave like text commands, except when -they occur in a deleted section, when they are disabled, but their -argument is shown as deleted text. - -=item B<--replace-context2cmd=replace-file> - -=item B<--append-context2cmd=append-file> or -=item B<--append-context2cmd="cmd1,cmd2,..."> -As corresponding commands for context1. The only difference is that -context2 commands are completely disabled in deleted sections, including -their arguments. - - - -=item B<--config var1=val1,var2=val2,...> or B<-c var1=val1,..> - -=item B<-c configfile> - -Set configuration variables. The option can be repeated to set different -variables (as an alternative to the comma-separated list). -Available variables (see below for further explanations): - -C (integer) - -C (RegEx) - -C (RegEx) - -C (RegEx) - -C (String) - -C (RegEx) - -C (String) - -C (RegEx) - -C (RegEx) - -=item B<--show-safecmd> - -Print list of RegEx matching and excluding safe commands. - -=item B<--show-textcmd> - -Print list of RegEx matching and excluding commands with text argument. - -=item B<--show-config> - -Show values of configuration variables. - -=item B<--show-all> - -Combine all --show commands. - -NB For all --show commands, no C or C file needs to be specified, and no -differencing takes place. - -=back - -=head2 Other configuration options: - -=over 4 - -=item B<--allow-spaces> - -Allow spaces between bracketed or braced arguments to commands. Note -that this option might have undesirable side effects (unrelated scope -might get lumpeded with preceding commands) so should only be used if the -default produces erroneous results. (Default requires arguments to -directly follow each other without intervening spaces). - -=item B<--math-markup=level> - -Determine granularity of markup in displayed math environments: -Possible values for level are (both numerical and text labels are acceptable): - -C or C<0>: suppress markup for math environments. Deleted equations will not -appear in diff file. This mode can be used if all the other modes -cause invalid latex code. - -C or C<1>: Differencing on the level of whole equations. Even trivial changes -to equations cause the whole equation to be marked changed. This -mode can be used if processing in coarse or fine mode results in -invalid latex code. - -C or C<2>: Detect changes within equations marked up with a coarse -granularity; changes in equation type (e.g.displaymath to equation) -appear as a change to the complete equation. This mode is recommended -for situations where the content and order of some equations are still -being changed. [Default] -C or C<3>: Detect small change in equations and mark up and fine granularity. -This mode is most suitable, if only minor changes to equations are -expected, e.g. correction of typos. - -=item B<--disable-citation-markup> - -Suppress citation markup in styles using ulem (UNDERLINE, -FONTSTRIKE, CULINECHBAR) - -=item B<--enable-citation-markup> - -Protect citation commands in changed sections with \\mbox command [i.e. use default behaviour for ulem package for other packages] - -=back - -=head2 Miscellaneous - -=over 4 -=item B<--verbose> or B<-V> - -Output various status information to stderr during processing. -Default is to work silently. - -=item B<--driver=type> - -Choose driver for changebar package (only relevant for styles using - changebar: CCHANGEBAR CFONTCHBAR CULINECHBAR CHANGEBAR). Possible -drivers are listed in changebar manual, e.g. pdftex,dvips,dvitops - [Default: dvips] - -=item B<--ignore-warnings> - -Suppress warnings about inconsistencies in length between input and -parsed strings and missing characters. These warning messages are -often related to non-standard latex or latex constructions with a -syntax unknown to C but the resulting difference argument -is often fully functional anyway, particularly if the non-standard -latex only occurs in parts of the text which have not changed. - -=item B<--label=label> or -B<-L label> - -Sets the labels used to describe the old and new files. The first use -of this option sets the label describing the old file and the second -use of the option sets the label for the new file, i.e. set both -labels like this C<-L labelold -L labelnew>. -[Default: use the filename and modification dates for the label] - -=item B<--no-label> - -Suppress inclusion of old and new file names as comment in output file - -=item B<--visble-label> - -Include old and new filenames (or labels set with --label option) as -visible output. - -=item B<--flatten> - -Replace C<\input> and C<\include> commands within body by the content -of the files in their argument. If C<\includeonly> is present in the -preamble, only those files are expanded into the document. However, -no recursion is done, i.e. C<\input> and C<\include> commands within -included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, -respectively, making it possible to organise files into old and new directories. ---flatten is applied recursively, so inputted files can contain further -C<\input> statements. - -Use of this option might result in prohibitive processing times for -larger documents, and the resulting difference document -no longer reflects the structure of the input documents. - -=item B<--help> or -B<-h> - -Show help text - -=item B<--version> - -Show version number - -=back - - - -=head2 Predefined styles - -=head2 Major types - -The major type determine the markup of plain text and some selected latex commands outside floats by defining the markup commands C<\DIFadd{...}> and C<\DIFdel{...}> . - -=over 10 - -=item C - -Added text is wavy-underlined and blue, discarded text is struck out and red -(Requires color and ulem packages). Overstriking does not work in displayed math equations such that deleted parts of equation are underlined, not struck out (this is a shortcoming inherent to the ulem package). - -=item C - -Added text is blue and set in sans-serif, and a red footnote is created for each discarded -piece of text. (Requires color package) - -=item C - -Like C but without the use of color. - -=item C - -Added text is blue and set in sans-serif, and discarded text is red and very small size. - -=item C - -Added tex is set in sans-serif, discarded text small and struck out - -=item C - -Added text is blue, and discarded text is red. Additionally, the changed text is marked with a bar in the margin (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color, ulem and changebar packages). - -=item C - -No mark up of text, but mark margins with changebars (Requires changebar package). - -=item C - -No visible markup (but generic markup commands will still be inserted. - -=back - -=head2 Subtypes - -The subtype defines the commands that are inserted at the begin and end of added or discarded blocks, irrespectively of whether these blocks contain text or commands (Defined commands: C<\DIFaddbegin, \DIFaddend, \DIFdelbegin, \DIFdelend>) - -=over 10 - -=item C - -No additional markup (Recommended choice) - -=item C - -Mark beginning and end of changed blocks with symbols in the margin nearby (using -the standard C<\marginpar> command - note that this sometimes moves somewhat -from the intended position. - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. -(It is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete, for example -with citation commands). - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. Note -that C only works with the dvips converter, e.g. not pdflatex. -(it is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete). - -=back - -=head2 Float Types - -Some of the markup used in the main text might cause problems when used within -floats (e.g. figures or tables). For this reason alternative versions of all -markup commands are used within floats. The float type defines these alternative commands. - -=over 10 - -=item C - -Use identical markup for text as in the main body, but set all commands marking the begin and end of changed blocks to null-commands. You have to choose this float type if your subtype is C as C<\marginpar> does not work properly within floats. - -=item C - -Mark additions the same way as in the main text. Deleted environments are marked by angular brackets \[ and \] and the deleted text is set in scriptscript size. This float type should always be used with the C and C markup types as the \footnote command does not work properly in floating environments. - -=item C - -Make no difference between the main text and floats. - -=back - - -=head2 Configuration Variables - -=over 10 - -=item C - -Minimum number of tokens required to form an independent block. This value is -used in the algorithm to detect changes of complete blocks by merging identical text parts of less than C to the preceding added and discarded parts. - -[ Default: 3 ] - -=item C - -Environments whose name matches the regular expression in C are -considered floats. Within these environments, the I markup commands -are replaced by their FL variaties. - -[ Default: S >] - -=item C - -Within environments whose name matches the regular expression in C -all latexdiff markup is removed (in pathologic cases this might lead to - inconsistent markup but this situation should be rare). - -[ Default: S >] - -=item C,C - -If both \begin and \end for a math environment (environment name matching C -or \[ and \]) -are within the same deleted block, they are replaced by a \begin and \end commands for C -rather than being commented out. - -[ Default: C=S >, C=S >] - -=item C,C - -as C,C but for equation arrays - -[ Default: C=S >, C=S >] - -=item C - -If a match to C is found within an inline math environment within a deleted or added block, then the inlined math -is surrounded by C<\mbox{>...C<}>. This is necessary as underlining does not work within inlined array environments. - -[ Default: C=S > - -=item C - -If a command in a deleted block which is also in the textcmd list matches C then an -additional command C<\addtocounter{>FC<}{-1}>, where F is the matching command, is appended in the diff file such that the numbering in the diff file remains synchronized with the -numbering in the new file. - -[ Default: C=C<(?:footnote|part|section|subsection> ... - -C<|subsubsection|paragraph|subparagraph)> ] - -=back - -=head1 COMMON PROBLEMS - -=over 10 - -=item Citations result in overfull boxes - -There is an incompatibility between the C package, which C uses for underlining and striking out in the UNDERLINE style, -the default style. In order to be able to mark up citations properly, they are placed with an C<\mbox> command in post-processing. As mboxes -cannot be broken across lines, this procedure frequently results in overfull boxes, possibly obscuring the content as it extends beyond the right margin. If this is a problem, you have two possibilities: - -1. Use C or C subtype markup (option C<-s COLOR>): If this markup is chosen, then changed citations are no longer marked up -with the wavy line (additions) or struck out (deletions), but are still highlighted in the appropriate color. - -2. Choose option C<--disable-citation-markup> which turns off the marking up of citations: deleted citations are no longer shown, and -added ctations are shown without markup. (This was the default behaviour of latexdiff at versions 0.6 and older - -=back - -=head1 BUGS - -Option allow-spaces not implemented entirely consistently. It breaks -the rules that number and type of white space does not matter, as -different numbers of inter-argument spaces are treated as significant. - -Please send bug reports -to I or submit on latexdiff project page I. Include the serial number of I -(from comments at the top of the source or use B<--version>). If you come across latex -files that are error-free and conform to the specifications set out -above, and whose differencing still does not result in error-free -latex, please send me those files, ideally edited to only contain the -offending passage as long as that still reproduces the problem. If your -file relies on non-standard class files, you must include those. I will not -look at examples where I have trouble to latex the original files. - -=head1 SEE ALSO - -L, L - -=head1 PORTABILITY - -I does not make use of external commands and thus should run -on any platform supporting Perl 5.6 or higher. If files with encodings -other than ASCII or UTF-8 are processed, Perl 5.8 or higher is required. - -The standard version of I requires installation of the Perl package -C (available from I - -I) but a stand-alone -version, I, which has this package inlined, is available, too. -I requires the I command to be present. - -=head1 AUTHOR - -Copyright (C) 2004-2012 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 - -Contributors of fixes and additions: V. Kuhlmann, J. Paisley, N. Becker, T. Doerges, K. Huebner, -T. Connors, Sebastian Gouezel and many others. -Thanks to the many people who send in bug reports, feature suggestions, and other feedback. - -=cut - -__END__ -%%BEGIN SAFE COMMANDS -% Regex matching commands which can safely be in the -% argument of a \DIFadd or \DIFdel command (leave out the \) -arabic -dashbox -emph -fbox -framebox -hspace -math.* -makebox -mbox -pageref -ref -symbol -raisebox -rule -text.* -shortstack -usebox -dag -ddag -copyright -pounds -S -P -oe -OE -ae -AE -aa -AA -o -O -l -L -frac -ss -sqrt -ldots -cdots -vdots -ddots -alpha -beta -gamma -delta -epsilon -varepsilon -zeta -eta -theta -vartheta -iota -kappa -lambda -mu -nu -xi -pi -varpi -rho -varrho -sigma -varsigma -tau -upsilon -phi -varphi -chi -psi -omega -Gamma -Delta -Theta -Lambda -Xi -Pi -Sigma -Upsilon -Phi -Psi -Omega -ps -mp -times -div -ast -star -circ -bullet -cdot -cap -cup -uplus -sqcap -vee -wedge -setminus -wr -diamond -(?:big)?triangle.* -lhd -rhd -unlhd -unrhd -oplus -ominus -otimes -oslash -odot -bigcirc -d?dagger -amalg -leq -prec -preceq -ll -(?:sq)?su[bp]set(?:eq)? -in -vdash -geq -succ(?:eq)? -gg -ni -dashv -equiv -sim(?:eq)? -asymp -approx -cong -neq -doteq -propto -models -perp -mid -parallel -bowtie -Join -smile -frown -.*arrow -(?:long)?mapsto -.*harpoon.* -leadsto -aleph -hbar -imath -jmath -ell -wp -Re -Im -mho -prime -emptyset -nabla -surd -top -bot -angle -forall -exists -neg -flat -natural -sharp -backslash -partial -infty -Box -Diamond -triangle -clubsuit -diamondsuit -heartsuit -spadesuit -sum -prod -coprod -int -oint -big(?:sq)?c[au]p -bigvee -bigwedge -bigodot -bigotimes -bigoplus -biguplus -(?:arc)?(?:cos|sin|tan|cot)h? -csc -arg -deg -det -dim -exp -gcd -hom -inf -ker -lg -lim -liminf -limsup -ln -log -max -min -Pr -sec -sup -(SUPER|SUB)SCRIPTNB -(SUPER|SUB)SCRIPT -%%END SAFE COMMANDS - -%%BEGIN TEXT COMMANDS -% Regex matching commands with a text argument (leave out the \) -addcontents.* -cc -closing -chapter -dashbox -emph -encl -fbox -framebox -footnote -footnotetext -framebox -part -(sub){0,2}section\*? -(sub)?paragraph\*? -makebox -mbox -opening -parbox -raisebox -savebox -sbox -shortstack -signature -text.* -value -underline -sqrt -(SUPER|SUB)SCRIPT -%%END TEXT COMMANDS - -%%BEGIN CONTEXT1 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -caption -%%END CONTEXT1 COMMANDS - -%%BEGIN CONTEXT2 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -title -author -date -institute -%%END CONTEXT2 COMMANDS - - -%% TYPES (Commands for highlighting changed blocks) - -%DIF UNDERLINE PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}} -\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}} -%DIF END UNDERLINE PREAMBLE - -%DIF CTRADITIONAL PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} [..\footnote{removed: #1} ]}} -%DIF END CTRADITIONAL PREAMBLE - -%DIF TRADITIONAL PREAMBLE -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{[..\footnote{removed: #1} ]}} -%DIF END TRADITIONAL PREAMBLE - -%DIF CFONT PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} \scriptsize #1}} -%DIF END CFONT PREAMBLE - -%DIF FONTSTRIKE PREAMBLE -\RequirePackage[normalem]{ulem} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{\footnotesize \sout{#1}}} -%DIF END FONTSTRIKE PREAMBLE - -%DIF CCHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}#1}\protect\cbdelete} -%DIF END CCHANGEBAR PREAMBLE - -%DIF CFONTCHBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\sf #1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\scriptsize #1}\protect\cbdelete} -%DIF END CFONTCHBAR PREAMBLE - -%DIF CULINECHBAR PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage[dvips]{changebar} -\RequirePackage{color} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\uwave{#1}}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\sout{#1}}\protect\cbdelete} -%DIF END CULINECHBAR PREAMBLE - -%DIF CHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\providecommand{\DIFadd}[1]{\protect\cbstart{#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete} -%DIF END CHANGEBAR PREAMBLE - -%DIF INVISIBLE PREAMBLE -\providecommand{\DIFadd}[1]{#1} -\providecommand{\DIFdel}[1]{} -%DIF END INVISIBLE PREAMBLE - - -%% SUBTYPES (Markers for beginning and end of changed blocks) - -%DIF SAFE PREAMBLE -\providecommand{\DIFaddbegin}{} -\providecommand{\DIFaddend}{} -\providecommand{\DIFdelbegin}{} -\providecommand{\DIFdelend}{} -%DIF END SAFE PREAMBLE - -%DIF MARGIN PREAMBLE -\providecommand{\DIFaddbegin}{\protect\marginpar{a[}} -\providecommand{\DIFaddend}{\protect\marginpar{]}} -\providecommand{\DIFdelbegin}{\protect\marginpar{d[}} -\providecommand{\DIFdelend}{\protect\marginpar{]}} -%DIF END BRACKET PREAMBLE - -%DIF DVIPSCOL PREAMBLE -%Note: only works with dvips converter -\RequirePackage{color} -\RequirePackage{dvipscol} -\providecommand{\DIFaddbegin}{\protect\nogroupcolor{blue}} -\providecommand{\DIFaddend}{\protect\nogroupcolor{black}} -\providecommand{\DIFdelbegin}{\protect\nogroupcolor{red}} -\providecommand{\DIFdelend}{\protect\nogroupcolor{black}} -%DIF END DVIPSCOL PREAMBLE - -%DIF COLOR PREAMBLE -\RequirePackage{color} -\providecommand{\DIFaddbegin}{\protect\color{blue}} -\providecommand{\DIFaddend}{\protect\color{black}} -\providecommand{\DIFdelbegin}{\protect\color{red}} -\providecommand{\DIFdelend}{\protect\color{black}} -%DIF END COLOR PREAMBLE - - -%% FLOAT TYPES - -%DIF FLOATSAFE PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%DIF IDENTICAL PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{\DIFaddbegin} -\providecommand{\DIFaddendFL}{\DIFaddend} -\providecommand{\DIFdelbeginFL}{\DIFdelbegin} -\providecommand{\DIFdelendFL}{\DIFdelend} -%DIF END IDENTICAL PREAMBLE - -%DIF TRADITIONALSAFE PREAMBLE -% procidecommand color to make this work for TRADITIONAL and CTRADITIONAL -\providecommand{\color}[1]{} -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdel}[1]{{\protect\color{red}[..{\scriptsize {removed: #1}} ]}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%% SPECIAL PACKAGE PREAMBLE COMMANDS - -% Standard \DIFadd and \DIFdel are redefined as \DIFaddtex and \DIFdeltex -% when hyperref package is included. -%DIF HYPERREF PREAMBLE -\providecommand{\DIFadd}[1]{\texorpdfstring{\DIFaddtex{#1}}{#1}} -\providecommand{\DIFdel}[1]{\texorpdfstring{\DIFdeltex{#1}}{}} -%DIF END HYPERREF PACKAGE diff --git a/latexdiff-1.0.1/latexdiff-vc b/latexdiff-1.0.1/latexdiff-vc deleted file mode 100755 index 45d52cd..0000000 --- a/latexdiff-1.0.1/latexdiff-vc +++ /dev/null @@ -1,485 +0,0 @@ -#!/usr/bin/env perl -# Place the following 2 lines at beginning to make script independent of location of perl -#eval 'exec perl -w -S $0 ${1+"$@"}' -# if 0; # not running under some shell -# -# latexdiff-vc - wrapper script for applying latexdiff to rcs managed files -# and for automatised creation of postscript or pdf from difference file -# -# Copyright (C) 2005-12 F J Tilmann (tilmann@gfz-potsdam.de, ftilmann@users.berlios.de) -# -# Project webpages: http://latexdiff.berlios.de/ -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# -# Contributors: S Utcke, H Bruyninckx -# -# 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 . -# -# Detailed usage information at the end of the file -# -# version 1.0.1 (change version numbering to match that of latexdiff) -# - Option --fast to use latexdiff-fast -# - git support (thanks to Bjørn Magnus Mathisen, Santi Béjar, Pietro Battiston and Stefan Alfredson for patches) - UNTESTED -# version 0.25: -# - bbl is allowed as alternative extension (instead of .tex) -# version 0.26a -# - Bug fix: it copes now correctly with the possibility that there are no changes between current -# and archived version -use Getopt::Long ; -use Pod::Usage qw/pod2usage/ ; -use File::Temp qw/tempdir/ ; -use File::Basename qw/dirname/; -use strict ; -use warnings ; - -my $versionstring=< 1); -# Variables -my ($file1,$file2,$diff,$diffbase,$answer,$options,$infile,$append,$dirname,$cwd); -my (@files,@ldoptions,@tmpfiles,@ptmpfiles,@difffiles); # , - -Getopt::Long::Configure('pass_through','bundling'); - -GetOptions('revision|r:s' => \@revs, - 'cvs' => \$cvs, - 'rcs' => \$rcs, - 'svn' => \$svn, - 'git' => \$git, - 'dir|d:s' => \$dir, - 'fast' => \$fast, - 'postscript|ps' => \$postscript, - 'pdf' => \$pdf, - 'force' => \$force, - 'version' => \$version, - 'help|h' => \$help); - -if ( $help ) { - pod2usage(1) ; -} - -if ( $version ) { - die $versionstring ; -} - -if ( $fast ) { - $latexdiff='latexdiff-fast'; -} - -if ( $cvs ) { - $vc="CVS"; -} -if ( $rcs ) { - die "Cannot specify more than one of --cvs, --rcs --svn or --git." if ($vc); - $vc="RCS"; -} -if ( $svn ) { - die "Cannot specify more than one of --cvs, --rcs --svn or --git." if ($vc); - $vc="SVN"; -} -if ( $git ) { - die "Cannot specify more than one of --cvs, --rcs, --svn or --git." if ($vc); - $vc="GIT"; -} - - -# check whether the first file name got misinterpreted as an option to an empty -r option -if ( @revs && -f $revs[$#revs] ) { - unshift @ARGV,$revs[$#revs]; - $revs[$#revs]=""; -} -# check whether the first file name got misinterpreted as an option to an empty -d option -if ( defined($dir) && -f $dir ) { - unshift @ARGV,$dir; - $dir=""; -} - -$file2=pop @ARGV; -( defined($file2) && $file2 =~ /\.(tex|bbl)$/ ) or pod2usage("Must specify at least one tex or bbl file"); - -if (! $vc && scalar(@revs)>0 ) { - # have to guess $vc - # check whether we have a special name - if ( $0 =~ /-cvs$/ ) { - $vc="CVS"; - } elsif ( $0 =~ /-rcs$/ ) { - $vc="RCS"; - } elsif ( $0 =~ /-svn$/ ) { - $vc="SVN"; - } elsif ( $0 =~ /-git$/ ) { - $vc="GIT"; - } elsif ( -e "CVSROOT" || defined($ENV{"CVSROOT"}) ) { - print STDERR "Guess you are using CVS ...\n"; - $vc="CVS"; - } elsif ( -e "$file2,v" ) { - print STDERR "Guess you are using RCS ...\n"; - $vc="RCS"; - } elsif ( -d ".svn" ) { - print STDERR "Guess you are using SVN ...\n"; - $vc="SVN"; - } elsif ( -d ".git" ) { - print STDERR "Guess you are using GIT ...\n"; - $vc="GIT"; - } else { - print STDERR "Cannot figure out version control system, so I default to CVS\n"; - $vc="CVS"; - } -} - -if (defined($dir) && $dir=~/^\.\/?/ ) { - print STDERR "You wrote -dir=. but you do not really like to do that, do you ?\n"; - exit 10 -} - -if ( scalar(@revs)>0 ) { - if ( $vc eq "CVS" ) { - $diffcmd = "cvs diff -u -r"; - $patchcmd = "patch -R -p0"; - } elsif ( $vc eq "RCS" ) { - $diffcmd = "rcsdiff -u -r"; - $patchcmd = "patch -R -p0"; - } elsif ( $vc eq "SVN" ) { - $diffcmd = "svn diff -r "; - $patchcmd = "patch -R -p0"; - } elsif ( $vc eq "GIT" ) { - $diffcmd = "git diff -r --relative --no-prefix "; - $patchcmd = "patch -R -p0"; - # alternatively: - # $diffcmd = "git diff "; - # $patchcmd = "patch -R -p1"; - } else { - print STDERR "Unknown versioning system $vc \n"; - exit 10; - } -} - - -# make file list (last arguments), initial arguments have to be passed to latexdiff -# We assume an argument is a valid file rather than a latexdiff argument -# if it has extension .tex or .bbl - -@files=($file2); -while( $file1=pop @ARGV ) { - if ( $file1 =~ /\.(tex|bbl)$/ ) { - # $file1 looks like a valid file name and is prepended to file list - unshift @files, $file1 ; - } else { - # $file1 looks like an option for latexdiff, push it back to argument stack - unshift @ldoptions, $file1 ; - } -} - -if ( scalar(@revs) == 0 ) { - pod2usage("When -r option is not used, two .tex files (old and new) must be given on the command line") unless @files==2; - # compare two files - $file1=shift @files ; -} - -if ( scalar(@revs) == 2 ) { - $append = "-diff$revs[0]-$revs[1]"; -} elsif ( scalar(@revs) == 1 || $revs[0] ) { - $append = "-diff$revs[0]"; -} else { - $append = "-diff"; -} - -if ( defined ($dir) && ! $dir ) { - # bare -d option => choose directory name - ($dir=$append) =~ s/^-//; -} - -if ( ($vc eq "SVN" || $vc eq "CVS") && scalar(@revs)) { - length($revs[$#revs]) > 0 or $revs[$#revs]="HEAD"; - length($revs[0]) > 0 or $revs[0]="HEAD"; -} - -#exit ; - - -# cycle through all files - -@difffiles=(); -while ( $infile=$file2=shift @files ) { - print STDERR "Working on $infile \n"; - if ( scalar(@revs) == 1 ) { - ($file1=$infile) =~ s/\.(tex|bbl)/-oldtmp-$$.$1/ ; - push @tmpfiles,$file1; - # compare file with previous version ($revs[0]="") or specified version - ### system("$diffcmd$revs[0] $infile| $patchcmd -o$file1") ; - if (system("$diffcmd$revs[0] $infile | $patchcmd -o$file1")==0 and -z $file1 ) { - # no differences detected, i.e. file is equal to current version - system("\cp $infile $file1"); - } - } elsif ( scalar(@revs) == 2 ) { - ($file1=$infile) =~ s/\.(tex|bbl)/-oldtmp-$$.$1/ ; - $file2 =~ s/\.(tex|bbl)/-newtmp-$$.$1/ ; - push @tmpfiles,$file2; - ; - if (system("$diffcmd$revs[1] $infile | $patchcmd -o$file2")==0 and -z $file2 ) { - system("\cp $infile $file2"); - } - if (system("$diffcmd$revs[0] $infile | $patchcmd -o$file1")==0 and -z $file1 ) { - system("\cp $infile $file1"); - }; - } - - if ( -z $file1 || -z $file2) { - print STDERR "One or both of the files to compare are empty. Possibly something went wrong in the retrieval of older versions. Aborting ...\n" ; - exit(10); - } - - # Get name of difference file - if ( defined($dir) ) { - $diff="$dir/$infile" ; - } else { - ($diff=$infile) =~ s/\.(tex|bbl)$/$append.$1/ ; - } - # make directories if needed - $dirname=dirname($diff) ; - system("mkdir -p $dirname") unless ( -e $dirname ); - - # Remaining options are passed to latexdiff - $options = join(" ",@ldoptions); - - if ( -e $diff && ! $force ) { - print STDERR "OK to overwrite existing file $diff (y/n)? "; - $answer = ; - unless ($answer =~ /^y/i ) { - unlink @tmpfiles; - die "Abort ... " ; - } - } - print "Running $latexdiff\n"; - unless ( system("$latexdiff $options $file1 $file2 > $diff") == 0 ) { - print STDERR "Something went wrong in $latexdiff. Deleting $diff and abort\n" ; unlink $diff ; exit(5) - }; - print "Generated difference file $diff\n"; - - if ( ( $postscript or $pdf ) and !( scalar(@revs) && greptex( qr/\\document(?:class|style)/ , $diff ) ) ) { - # save filename for later processing if postscript or pdf conversion is requested and either two-file mode was used (scalar(@revs)==0) or the diff file contains documentclass statement (ie. is a root document) - push @difffiles, $diff ; - } - - unlink @tmpfiles; -} - -foreach $diff ( @difffiles ) { - chomp($cwd=(`pwd`)); - if (defined($dir)) { - ( $diff =~ s/$dir\/?// ) ; - chdir $dir ; - } - @ptmpfiles=(); - ( $diffbase=$diff) =~ s/\.(tex)$// ; - - # adapt magically changebar styles to [pdftex] display driver if pdf output was selected - if ( $pdf ) { - system("sed \"s/Package\\[dvips\\]/Package[pdftex]/\" $diff > $diff.tmp$$ ; \\mv $diff.tmp$$ $diff"); - } - print STDERR "PDF: $pdf Postscript: $postscript cwd $cwd\n"; - - if ( system("grep -q \'^[^%]*\\\\bibliography\' $diff") == 0 ) { - if ( $postscript) { - system("latex --interaction=batchmode $diff; bibtex $diffbase"); - push @ptmpfiles, "$diffbase.bbl","$diffbase.bbl" ; - } elsif ( $pdf ) { - system("pdflatex --interaction=batchmode $diff; bibtex $diffbase"); - push @ptmpfiles, "$diffbase.bbl","$diffbase.bbl" ; - } - } - - if ( $postscript ) { - my $dvi="$diffbase.dvi"; - my $ps="$diffbase.ps"; - - system("latex --interaction=batchmode $diff; latex $diff; dvips -o $ps $dvi"); - push @ptmpfiles, "$diffbase.aux","$diffbase.log",$dvi ; - print "Generated postscript file $ps\n"; - } - elsif ( $pdf ) { - system("pdflatex --interaction=batchmode $diff; pdflatex $diff"); - push @ptmpfiles, "$diffbase.aux","$diffbase.log"; - } - unlink @ptmpfiles; - chdir $cwd; -} - -# greptex returns 1 if regex is not matched in filename -# 0 if there is a match -sub greptex { - my ($regex,$filename)=@_; - my ($i)=0; - open (FH, $filename) or die("Couldn't open $filename: $!"); - while () { - next if /^\s*%/; # skip comment lines - if ( m/$regex/ ) { - close(FH); - return(0); - } - # only scan 25 lines - $i++; - last if $i>25 ; - } - close(FH); - return(1); -} - - -=head1 NAME - -latexdiff-vc - wrapper script that calls latexdiff for different versions of a file under version management (CVS, RCS or SVN) - -=head1 SYNOPSIS - -B [ F ] [ F ] B<-r> [F] [B<-r> F] F [ F ...] - - or - -B [ F ] [ F ][ B<--postscript> | B<--pdf> ] F F - -=head1 DESCRIPTION - -I is a wrapper script that applies I to a -file, or multiple files under version control (CVS, RCS or SVN), and optionally runs the -sequence of C and C or C commands necessary to -produce pdf or postscript output of the difference tex file(s). It can -also be applied to a pair of files to automatise the generation of difference -file in postscript or pdf format. - -=head1 OPTIONS - -=over 4 - -=item B<--rcs>, B<--svn>, B<--cvs>, or B<--git> - -Set the version system. -If no version system is specified, latexdiff-vc will venture a guess. - -latexdiff-cvs and latexdiff-rcs are variants of latexdiff-vc which default to -the respective versioning system. However, this default can still be overridden using the options above. - -=item B<-r>, B<-r> F or B<--revision>, B<--revision=>F - -Choose revision (under RCS, CVS, SVN or GIT). One or two B<-r> options can be -specified, and they result in different behaviour: - -=over 4 - -=item B -r F ... - -compares F with the most recent version checked into RCS. - -=item B -r F F ... - -compares F with revision F. - -=item B -r F -r F F ... - -compares revisions F and F of F. - -Multiple files can be specified for all of the above options. All files must have the -extension C<.tex>, though. - -=item B F F - -compares two files. - -=back - -The name of the difference file is generated automatically and -reported to stdout. - -=item B<-d> or B<--dir> B<-d> F or B<--dir=>F - -Rather than appending the string C and optionally the version -numbers given to the output-file, this will prepend a directory name C -to the -original filename, creating the directory and subdirectories should they not exist already. This is particularly useful in order to clone a -complete directory hierarchy. Optionally, a pathname F can be specified, which is prepended instead of C. - -=item B<--fast> - -Use C instead of C - -=item B<--ps> or B<--postscript> - -Generate postscript output from difference file. This will run the -sequence C on the difference file (do not use -this option in the rare cases, where three C commands are -required if you care about correct referencing). If the difference -file contains a C<\bibliography> tag, run the sequence C. - -=item B<--pdf> - -Generate pdf output from difference file using C. This will -run the sequence C on the difference file, or -C for files requiring bibtex. - -=item B<--force> - -Overwrite existing diff files without asking for confirmation. Default -behaviour is to ask for confirmation before overwriting an existing difference -file. - -=item B<--help> or -B<-h> - -Show help text - -=item B<--version> - -Show version number - -=back - -All other options are passed on to C. - -=head1 SEE ALSO - -L - -=head1 PORTABILITY - -I uses external commands and is therefore -limited to Unix-like systems. It also requires the RCS version control -system and latex to be installed on the system. Modules from Perl 5.8 -or higher are required. - -=head1 BUG REPORTING - - Please submit bug reports through -the latexdiff project page I or send -to I. Include the serial number of I -(option C<--version>) -. -=head1 AUTHOR - -Copyright (C) 2005,2012 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 -Contributors: S Utcke, H Bruyninckx - -=cut - diff --git a/latexdiff-1.0.1/latexdiff-vc.1 b/latexdiff-1.0.1/latexdiff-vc.1 deleted file mode 100644 index 6cb393f..0000000 --- a/latexdiff-1.0.1/latexdiff-vc.1 +++ /dev/null @@ -1,246 +0,0 @@ -.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` "" -. ds C' "" -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.ie \nF \{\ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. nr % 0 -. rr F -.\} -.el \{\ -. de IX -.. -.\} -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "LATEXDIFF-VC 1" -.TH LATEXDIFF-VC 1 "2012-11-13" "perl v5.14.2" " " -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -latexdiff\-vc \- wrapper script that calls latexdiff for different versions of a file under version management (CVS, RCS or SVN) -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBlatexdiff-vc\fR [ \fIlatexdiff-options\fR ] [ \fIlatexdiff-vc-options\fR ] \fB\-r\fR [\fIrev1\fR] [\fB\-r\fR \fIrev2\fR] \fIfile1.tex\fR [ \fIfile2.tex\fR ...] -.PP -.Vb 1 -\& or -.Ve -.PP -\&\fBlatexdiff-vc\fR [ \fIlatexdiff-options\fR ] [ \fIlatexdiff-vc-options\fR ][ \fB\-\-postscript\fR | \fB\-\-pdf\fR ] \fIold.tex\fR \fInew.tex\fR -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -\&\fIlatexdiff-vc\fR is a wrapper script that applies \fIlatexdiff\fR to a -file, or multiple files under version control (\s-1CVS\s0, \s-1RCS\s0 or \s-1SVN\s0), and optionally runs the -sequence of \f(CW\*(C`latex\*(C'\fR and \f(CW\*(C`dvips\*(C'\fR or \f(CW\*(C`pdflatex\*(C'\fR commands necessary to -produce pdf or postscript output of the difference tex file(s). It can -also be applied to a pair of files to automatise the generation of difference -file in postscript or pdf format. -.SH "OPTIONS" -.IX Header "OPTIONS" -.IP "\fB\-\-rcs\fR, \fB\-\-svn\fR, \fB\-\-cvs\fR, or \fB\-\-git\fR" 4 -.IX Item "--rcs, --svn, --cvs, or --git" -Set the version system. -If no version system is specified, latexdiff-vc will venture a guess. -.Sp -latexdiff-cvs and latexdiff-rcs are variants of latexdiff-vc which default to -the respective versioning system. However, this default can still be overridden using the options above. -.IP "\fB\-r\fR, \fB\-r\fR \fIrev\fR or \fB\-\-revision\fR, \fB\-\-revision=\fR\fIrev\fR" 4 -.IX Item "-r, -r rev or --revision, --revision=rev" -Choose revision (under \s-1RCS\s0, \s-1CVS\s0, \s-1SVN\s0 or \s-1GIT\s0). One or two \fB\-r\fR options can be -specified, and they result in different behaviour: -.RS 4 -.IP "\fBlatexdiff-vc\fR \-r \fIfile.tex\fR ..." 4 -.IX Item "latexdiff-vc -r file.tex ..." -compares \fIfile.tex\fR with the most recent version checked into \s-1RCS\s0. -.IP "\fBlatexdiff-vc\fR \-r \fIrev1\fR \fIfile.tex\fR ..." 4 -.IX Item "latexdiff-vc -r rev1 file.tex ..." -compares \fIfile.tex\fR with revision \fIrev1\fR. -.IP "\fBlatexdiff-vc\fR \-r \fIrev1\fR \-r \fIrev2\fR \fIfile.tex\fR ..." 4 -.IX Item "latexdiff-vc -r rev1 -r rev2 file.tex ..." -compares revisions \fIrev1\fR and \fIrev2\fR of \fIfile.tex\fR. -.Sp -Multiple files can be specified for all of the above options. All files must have the -extension \f(CW\*(C`.tex\*(C'\fR, though. -.IP "\fBlatexdiff-vc\fR \fIold.tex\fR \fInew.tex\fR" 4 -.IX Item "latexdiff-vc old.tex new.tex" -compares two files. -.RE -.RS 4 -.Sp -The name of the difference file is generated automatically and -reported to stdout. -.RE -.IP "\fB\-d\fR or \fB\-\-dir\fR \fB\-d\fR \fIpath\fR or \fB\-\-dir=\fR\fIpath\fR" 4 -.IX Item "-d or --dir -d path or --dir=path" -Rather than appending the string \f(CW\*(C`diff\*(C'\fR and optionally the version -numbers given to the output-file, this will prepend a directory name \f(CW\*(C`diff\*(C'\fR -to the -original filename, creating the directory and subdirectories should they not exist already. This is particularly useful in order to clone a -complete directory hierarchy. Optionally, a pathname \fIpath\fR can be specified, which is prepended instead of \f(CW\*(C`diff\*(C'\fR. -.IP "\fB\-\-fast\fR" 4 -.IX Item "--fast" -Use \f(CW\*(C`latexdiff\-fast\*(C'\fR instead of \f(CW\*(C`latexdiff\*(C'\fR -.IP "\fB\-\-ps\fR or \fB\-\-postscript\fR" 4 -.IX Item "--ps or --postscript" -Generate postscript output from difference file. This will run the -sequence \f(CW\*(C`latex; latex; dvips\*(C'\fR on the difference file (do not use -this option in the rare cases, where three \f(CW\*(C`latex\*(C'\fR commands are -required if you care about correct referencing). If the difference -file contains a \f(CW\*(C`\ebibliography\*(C'\fR tag, run the sequence \f(CW\*(C`latex; -bibtex; latex; latex; dvips\*(C'\fR. -.IP "\fB\-\-pdf\fR" 4 -.IX Item "--pdf" -Generate pdf output from difference file using \f(CW\*(C`pdflatex\*(C'\fR. This will -run the sequence \f(CW\*(C`pdflatex; pdflatex\*(C'\fR on the difference file, or -\&\f(CW\*(C`pdflatex; bibtex; pdflatex; pdflatex\*(C'\fR for files requiring bibtex. -.IP "\fB\-\-force\fR" 4 -.IX Item "--force" -Overwrite existing diff files without asking for confirmation. Default -behaviour is to ask for confirmation before overwriting an existing difference -file. -.IP "\fB\-\-help\fR or \fB\-h\fR" 4 -.IX Item "--help or -h" -Show help text -.IP "\fB\-\-version\fR" 4 -.IX Item "--version" -Show version number -.PP -All other options are passed on to \f(CW\*(C`latexdiff\*(C'\fR. -.SH "SEE ALSO" -.IX Header "SEE ALSO" -latexdiff -.SH "PORTABILITY" -.IX Header "PORTABILITY" -\&\fIlatexdiff-vc\fR uses external commands and is therefore -limited to Unix-like systems. It also requires the \s-1RCS\s0 version control -system and latex to be installed on the system. Modules from Perl 5.8 -or higher are required. -.SH "BUG REPORTING" -.IX Header "BUG REPORTING" -.Vb 6 -\& Please submit bug reports through -\&the latexdiff project page I or send -\&to I. Include the serial number of I -\&(option C<\-\-version>) -\&. -\&=head1 AUTHOR -.Ve -.PP -Copyright (C) 2005,2012 Frederik Tilmann -.PP -This program is free software; you can redistribute it and/or modify -it under the terms of the \s-1GNU\s0 General Public License Version 3 -Contributors: S Utcke, H Bruyninckx diff --git a/latexdiff-1.0.1/latexdiff.1 b/latexdiff-1.0.1/latexdiff.1 deleted file mode 100644 index 7073b62..0000000 --- a/latexdiff-1.0.1/latexdiff.1 +++ /dev/null @@ -1,751 +0,0 @@ -.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` "" -. ds C' "" -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.ie \nF \{\ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. nr % 0 -. rr F -.\} -.el \{\ -. de IX -.. -.\} -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "LATEXDIFF 1" -.TH LATEXDIFF 1 "2012-11-13" "perl v5.14.2" " " -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -latexdiff \- determine and markup differences between two latex files -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBlatexdiff\fR [ \fB\s-1OPTIONS\s0\fR ] \fIold.tex\fR \fInew.tex\fR > \fIdiff.tex\fR -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -Briefly, \fIlatexdiff\fR is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called \f(CW\*(C`old.tex\*(C'\fR and \f(CW\*(C`new.tex\*(C'\fR, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. -.PP -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "\f(CW\*(C`%DIF\ >\*(C'\fR" is appended to each added line, i.e. a -line present in \f(CW\*(C`new.tex\*(C'\fR but not in \f(CW\*(C`old.tex\*(C'\fR. Discarded lines - are deactivated by prepending "\f(CW\*(C`%DIF\ <\*(C'\fR". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file \f(CW\*(C`diff.tex\*(C'\fR will be similar to -\&\f(CW\*(C`new.tex\*(C'\fR. At the end of the preamble, the definitions for \fIlatexdiff\fR markup commands are inserted. -In differencing the main body of the text, \fIlatexdiff\fR attempts to -satisfy the following guidelines (in order of priority): -.IP "1." 3 -If both \f(CW\*(C`old.tex\*(C'\fR and \f(CW\*(C`new.tex\*(C'\fR are valid LaTeX, then the resulting -\&\f(CW\*(C`diff.tex\*(C'\fR should also be valid LateX. (\s-1NB\s0 If a few plain TeX commands -are used within \f(CW\*(C`old.tex\*(C'\fR or \f(CW\*(C`new.tex\*(C'\fR then \f(CW\*(C`diff.tex\*(C'\fR is not -guaranteed to work but usually will). -.IP "2." 3 -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -\&\f(CW\*(C`diff.tex\*(C'\fR. -.IP "3." 3 -If a changed passage contains text or text-producing commands, then -running \f(CW\*(C`diff.tex\*(C'\fR through LateX should produce output where added -and discarded passages are highlighted. -.IP "4." 3 -Where there are insignificant differences, e.g. in the positioning of -line breaks, \f(CW\*(C`diff.tex\*(C'\fR should follow the formatting of \f(CW\*(C`new.tex\*(C'\fR -.PP -For differencing the same algorithm as \fIdiff\fR is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, \f(CW\*(C`\ecaption\*(C'\fR and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write -.PP -.Vb 1 -\& \esection{\etextem{This is an emphasized section title}} -.Ve -.PP -and not -.PP -.Vb 1 -\& \esection {\etextem{This is an emphasized section title}} -.Ve -.PP -or -.PP -.Vb 1 -\& \esection\etextem{This is an emphasized section title} -.Ve -.PP -even though all varieties are the same to LaTeX (but see -\&\fB\-\-allow\-spaces\fR option which allows the second variety). -.PP -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the \s-1PICTUREENV\s0 configuration variable, set by -default to \f(CW\*(C`picture\*(C'\fR and \f(CW\*(C`DIFnomarkup\*(C'\fR environments; see \fB\-\-config\fR -option). The latter environment (\f(CW\*(C`DIFnomarkup\*(C'\fR) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by \f(CW\*(C`\ebegin{DIFnomarkup}\*(C'\fR and \f(CW\*(C`\eend{DIFnomarkup}\*(C'\fR. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, -.PP -\&\f(CW\*(C`\enewenvironment{DIFnomarkup}{}{}\*(C'\fR -.PP -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. -.PP -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. -.PP -All markup commands inserted by \fIlatexdiff\fR begin with "\f(CW\*(C`\eDIF\*(C'\fR". Added -blocks containing words, commands or comments which are in \f(CW\*(C`new.tex\*(C'\fR -but not in \f(CW\*(C`old.tex\*(C'\fR are marked by \f(CW\*(C`\eDIFaddbegin\*(C'\fR and \f(CW\*(C`\eDIFaddend\*(C'\fR. -Discarded blocks are marked by \f(CW\*(C`\eDIFdelbegin\*(C'\fR and \f(CW\*(C`\eDIFdelend\*(C'\fR. -Within added blocks all text is highlighted with \f(CW\*(C`\eDIFadd\*(C'\fR like this: -\&\f(CW\*(C`\eDIFadd{Added text block}\*(C'\fR -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces \*(L"{\*(R" and \*(L"}\*(R" are never put within -the scope of \f(CW\*(C`\eDIFadd\*(C'\fR. Added comments are marked by prepending -"\f(CW\*(C`%DIF\ >\ \*(C'\fR". -.PP -Within deleted blocks text is highlighted with \f(CW\*(C`\eDIFdel\*(C'\fR. Deleted -comments are marked by prepending "\f(CW\*(C`%DIF\ <\ \*(C'\fR\*(L". Non-safe command -and curly braces within deleted blocks are commented out with -\&\*(R"\f(CW\*(C`%DIFDELCMD\ <\ \*(C'\fR". -.SH "OPTIONS" -.IX Header "OPTIONS" -.SS "Preamble" -.IX Subsection "Preamble" -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. -.IP "\fB\-\-type=markupstyle\fR or \fB\-t markupstyle\fR" 4 -.IX Item "--type=markupstyle or -t markupstyle" -Add code to preamble for selected markup style. This option defines -\&\f(CW\*(C`\eDIFadd\*(C'\fR and \f(CW\*(C`\eDIFdel\*(C'\fR commands. -Available styles: -.Sp -\&\f(CW\*(C`UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE -CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR\*(C'\fR -.Sp -[ Default: \f(CW\*(C`UNDERLINE\*(C'\fR ] -.IP "\fB\-\-subtype=markstyle\fR or \fB\-s markstyle\fR" 4 -.IX Item "--subtype=markstyle or -s markstyle" -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -\&\f(CW\*(C`\eDIFaddbegin\*(C'\fR, \f(CW\*(C`\eDIFaddend\*(C'\fR, \f(CW\*(C`\eDIFdelbegin\*(C'\fR and \f(CW\*(C`\eDIFdelend\*(C'\fR commands. -Available styles: \f(CW\*(C`SAFE MARGINAL COLOR DVIPSCOL\*(C'\fR -.Sp -[ Default: \f(CW\*(C`SAFE\*(C'\fR ] -.IP "\fB\-\-floattype=markstyle\fR or \fB\-f markstyle\fR" 4 -.IX Item "--floattype=markstyle or -f markstyle" -Add code to preamble for selected style which -replace standard marking and markup commands within floats -(e.g., marginal remarks cause an error within floats -so marginal marking can be disabled thus). This option defines all -\&\f(CW\*(C`\eDIF...FL\*(C'\fR commands. -Available styles: \f(CW\*(C`FLOATSAFE TRADITIONALSAFE IDENTICAL\*(C'\fR -.Sp -[ Default: \f(CW\*(C`FLOATSAFE\*(C'\fR ] -.IP "\fB\-\-encoding=enc\fR or \fB\-e enc\fR" 4 -.IX Item "--encoding=enc or -e enc" -Specify encoding of old.tex and new.tex. Typical encodings are -\&\f(CW\*(C`ascii\*(C'\fR, \f(CW\*(C`utf8\*(C'\fR, \f(CW\*(C`latin1\*(C'\fR, \f(CW\*(C`latin9\*(C'\fR. A list of available encodings can be -obtained by executing -.Sp -\&\f(CW\*(C`perl \-MEncode \-e \*(Aqprint join ("\en",Encode\-\*(C'\fRencodings( \*(L":all\*(R" )) ;' > -.Sp -[Default encoding is utf8 unless the first few lines of the preamble contain -an invocation \f(CW\*(C`\eusepackage[..]{inputenc}\*(C'\fR in which case the -encoding chosen by this command is asssumed. Note that \s-1ASCII\s0 (standard -latex) is a subset of utf8] -.IP "\fB\-\-preamble=file\fR or \fB\-p file\fR" 4 -.IX Item "--preamble=file or -p file" -Insert file at end of preamble instead of generating -preamble. The preamble must define the following commands -\&\f(CW\*(C`\eDIFaddbegin, \eDIFaddend, \eDIFadd{..}, -\&\eDIFdelbegin,\eDIFdelend,\eDIFdel{..},\*(C'\fR -and varieties for use within floats -\&\f(CW\*(C`\eDIFaddbeginFL, \eDIFaddendFL, \eDIFaddFL{..}, -\&\eDIFdelbeginFL, \eDIFdelendFL, \eDIFdelFL{..}\*(C'\fR -(If this option is set \fB\-t\fR, \fB\-s\fR, and \fB\-f\fR options -are ignored.) -.IP "\fB\-\-packages=pkg1,pkg2,..\fR" 4 -.IX Item "--packages=pkg1,pkg2,.." -Tell latexdiff that .tex file is processed with the packages in list -loaded. This is normally not necessary if the .tex file includes the -preamble, as the preamble is automatically scanned for \f(CW\*(C`\eusepackage\*(C'\fR commands. -Use of the \fB\-\-packages\fR option disables automatic scanning, so if for any -reason package specific parsing needs to be switched off, use \fB\-\-packages=none\fR. -The following packages trigger special behaviour: -.RS 4 -.ie n .IP """amsmath""" 8 -.el .IP "\f(CWamsmath\fR" 8 -.IX Item "amsmath" -Configuration variable amsmath is set to \f(CW\*(C`align*\*(C'\fR (Default: \f(CW\*(C`eqnarray*\*(C'\fR) -.ie n .IP """endfloat""" 8 -.el .IP "\f(CWendfloat\fR" 8 -.IX Item "endfloat" -Ensure that \f(CW\*(C`\ebegin{figure}\*(C'\fR and \f(CW\*(C`\eend{figure}\*(C'\fR always appear by themselves on a line. -.ie n .IP """hyperref""" 8 -.el .IP "\f(CWhyperref\fR" 8 -.IX Item "hyperref" -Change name of \f(CW\*(C`\eDIFadd\*(C'\fR and \f(CW\*(C`\eDIFdel\*(C'\fR commands to \f(CW\*(C`\eDIFaddtex\*(C'\fR and \f(CW\*(C`\eDIFdeltex\*(C'\fR and -define new \f(CW\*(C`\eDIFadd\*(C'\fR and \f(CW\*(C`\eDIFdel\*(C'\fR commands, which provide a wrapper for these commands, -using them for the text but not for the link defining command (where any markup would cause -errors). -.RE -.RS 4 -.Sp -[ Default: scan the preamble for \f(CW\*(C`\e\eusepackage\*(C'\fR commands to determine - loaded packages.] -.RE -.IP "\fB\-\-show\-preamble\fR" 4 -.IX Item "--show-preamble" -Print generated or included preamble commands to stdout. -.SS "Configuration" -.IX Subsection "Configuration" -.ie n .IP "\fB\-\-exclude\-safecmd=exclude\-file\fR or \fB\-A exclude-file\fR or \fB\-\-exclude\-safecmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-exclude\-safecmd=exclude\-file\fR or \fB\-A exclude-file\fR or \fB\-\-exclude\-safecmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--exclude-safecmd=exclude-file or -A exclude-file or --exclude-safecmd=cmd1,cmd2,..." -.PD 0 -.IP "\fB\-\-replace\-safecmd=replace\-file\fR" 4 -.IX Item "--replace-safecmd=replace-file" -.ie n .IP "\fB\-\-append\-safecmd=append\-file\fR or \fB\-a append-file\fR or \fB\-\-append\-safecmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-append\-safecmd=append\-file\fR or \fB\-a append-file\fR or \fB\-\-append\-safecmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--append-safecmd=append-file or -a append-file or --append-safecmd=cmd1,cmd2,..." -.PD -Exclude from, replace or append to the list of regular expressions (RegEx) -matching commands which are safe to use within the -scope of a \f(CW\*(C`\eDIFadd\*(C'\fR or \f(CW\*(C`\eDIFdel\*(C'\fR command. The file must contain -one Perl-RegEx per line (Comment lines beginning with # or % are -ignored). Note that the RegEx needs to match the whole of -the token, i.e., /^regex$/ is implied and that the initial -\&\*(L"\e\*(R" of the command is not included. -The \fB\-\-exclude\-safecmd\fR and \fB\-\-append\-safecmd\fR options can be combined with the \-\fB\-\-replace\-safecmd\fR -option and can be used repeatedly to add cumulatively to the lists. - \fB\-\-exclude\-safecmd\fR -and \fB\-\-append\-safecmd\fR can also take a comma separated list as input. If a -comma for one of the regex is required, escape it thus \*(L"\e,\*(R". In most cases it -will be necessary to protect the comma-separated list from the shell by putting -it in quotation marks. -.ie n .IP "\fB\-\-exclude\-textcmd=exclude\-file\fR or \fB\-X exclude-file\fR or \fB\-\-exclude\-textcmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-exclude\-textcmd=exclude\-file\fR or \fB\-X exclude-file\fR or \fB\-\-exclude\-textcmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--exclude-textcmd=exclude-file or -X exclude-file or --exclude-textcmd=cmd1,cmd2,..." -.PD 0 -.IP "\fB\-\-replace\-textcmd=replace\-file\fR" 4 -.IX Item "--replace-textcmd=replace-file" -.ie n .IP "\fB\-\-append\-textcmd=append\-file\fR or \fB\-x append-file\fR or \fB\-\-append\-textcmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-append\-textcmd=append\-file\fR or \fB\-x append-file\fR or \fB\-\-append\-textcmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--append-textcmd=append-file or -x append-file or --append-textcmd=cmd1,cmd2,..." -.PD -Exclude from, replace or append to the list of regular expressions -matching commands whose last argument is text. See -entry for \fB\-\-exclude\-safecmd\fR directly above for further details. -.IP "\fB\-\-replace\-context1cmd=replace\-file\fR" 4 -.IX Item "--replace-context1cmd=replace-file" -.PD 0 -.ie n .IP "\fB\-\-append\-context1cmd=append\-file\fR or =item \fB\-\-append\-context1cmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-append\-context1cmd=append\-file\fR or =item \fB\-\-append\-context1cmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--append-context1cmd=append-file or =item --append-context1cmd=cmd1,cmd2,..." -.PD -Replace or append to the list of regex matching commands -whose last argument is text but which require a particular -context to work, e.g. \ecaption will only work within a figure -or table. These commands behave like text commands, except when -they occur in a deleted section, when they are disabled, but their -argument is shown as deleted text. -.IP "\fB\-\-replace\-context2cmd=replace\-file\fR" 4 -.IX Item "--replace-context2cmd=replace-file" -.PD 0 -.ie n .IP "\fB\-\-append\-context2cmd=append\-file\fR or =item \fB\-\-append\-context2cmd=""cmd1,cmd2,...""\fR As corresponding commands for context1. The only difference is that context2 commands are completely disabled in deleted sections, including their arguments." 4 -.el .IP "\fB\-\-append\-context2cmd=append\-file\fR or =item \fB\-\-append\-context2cmd=``cmd1,cmd2,...''\fR As corresponding commands for context1. The only difference is that context2 commands are completely disabled in deleted sections, including their arguments." 4 -.IX Item "--append-context2cmd=append-file or =item --append-context2cmd=cmd1,cmd2,... As corresponding commands for context1. The only difference is that context2 commands are completely disabled in deleted sections, including their arguments." -.IP "\fB\-\-config var1=val1,var2=val2,...\fR or \fB\-c var1=val1,..\fR" 4 -.IX Item "--config var1=val1,var2=val2,... or -c var1=val1,.." -.IP "\fB\-c configfile\fR" 4 -.IX Item "-c configfile" -.PD -Set configuration variables. The option can be repeated to set different -variables (as an alternative to the comma-separated list). -Available variables (see below for further explanations): -.Sp -\&\f(CW\*(C`MINWORDSBLOCK\*(C'\fR (integer) -.Sp -\&\f(CW\*(C`FLOATENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`PICTUREENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`MATHENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`MATHREPL\*(C'\fR (String) -.Sp -\&\f(CW\*(C`MATHARRENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`MATHARRREPL\*(C'\fR (String) -.Sp -\&\f(CW\*(C`ARRENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`COUNTERCMD\*(C'\fR (RegEx) -.IP "\fB\-\-show\-safecmd\fR" 4 -.IX Item "--show-safecmd" -Print list of RegEx matching and excluding safe commands. -.IP "\fB\-\-show\-textcmd\fR" 4 -.IX Item "--show-textcmd" -Print list of RegEx matching and excluding commands with text argument. -.IP "\fB\-\-show\-config\fR" 4 -.IX Item "--show-config" -Show values of configuration variables. -.IP "\fB\-\-show\-all\fR" 4 -.IX Item "--show-all" -Combine all \-\-show commands. -.Sp -\&\s-1NB\s0 For all \-\-show commands, no \f(CW\*(C`old.tex\*(C'\fR or \f(CW\*(C`new.tex\*(C'\fR file needs to be specified, and no -differencing takes place. -.SS "Other configuration options:" -.IX Subsection "Other configuration options:" -.IP "\fB\-\-allow\-spaces\fR" 4 -.IX Item "--allow-spaces" -Allow spaces between bracketed or braced arguments to commands. Note -that this option might have undesirable side effects (unrelated scope -might get lumpeded with preceding commands) so should only be used if the -default produces erroneous results. (Default requires arguments to -directly follow each other without intervening spaces). -.IP "\fB\-\-math\-markup=level\fR" 4 -.IX Item "--math-markup=level" -Determine granularity of markup in displayed math environments: -Possible values for level are (both numerical and text labels are acceptable): -.Sp -\&\f(CW\*(C`off\*(C'\fR or \f(CW0\fR: suppress markup for math environments. Deleted equations will not -appear in diff file. This mode can be used if all the other modes -cause invalid latex code. -.Sp -\&\f(CW\*(C`whole\*(C'\fR or \f(CW1\fR: Differencing on the level of whole equations. Even trivial changes -to equations cause the whole equation to be marked changed. This -mode can be used if processing in coarse or fine mode results in -invalid latex code. -.Sp -\&\f(CW\*(C`coarse\*(C'\fR or \f(CW2\fR: Detect changes within equations marked up with a coarse -granularity; changes in equation type (e.g.displaymath to equation) -appear as a change to the complete equation. This mode is recommended -for situations where the content and order of some equations are still -being changed. [Default] -\&\f(CW\*(C`fine\*(C'\fR or \f(CW3\fR: Detect small change in equations and mark up and fine granularity. -This mode is most suitable, if only minor changes to equations are -expected, e.g. correction of typos. -.IP "\fB\-\-disable\-citation\-markup\fR" 4 -.IX Item "--disable-citation-markup" -Suppress citation markup in styles using ulem (\s-1UNDERLINE\s0, -\&\s-1FONTSTRIKE\s0, \s-1CULINECHBAR\s0) -.IP "\fB\-\-enable\-citation\-markup\fR" 4 -.IX Item "--enable-citation-markup" -Protect citation commands in changed sections with \e\embox command [i.e. use default behaviour for ulem package for other packages] -.SS "Miscellaneous" -.IX Subsection "Miscellaneous" -.RS 4 -Output various status information to stderr during processing. -Default is to work silently. -.Sp -\&\fB\-\-driver=type\fR -.Sp -Choose driver for changebar package (only relevant for styles using - changebar: \s-1CCHANGEBAR\s0 \s-1CFONTCHBAR\s0 \s-1CULINECHBAR\s0 \s-1CHANGEBAR\s0). Possible -drivers are listed in changebar manual, e.g. pdftex,dvips,dvitops - [Default: dvips] -.Sp -\&\fB\-\-ignore\-warnings\fR -.Sp -Suppress warnings about inconsistencies in length between input and -parsed strings and missing characters. These warning messages are -often related to non-standard latex or latex constructions with a -syntax unknown to \f(CW\*(C`latexdiff\*(C'\fR but the resulting difference argument -is often fully functional anyway, particularly if the non-standard -latex only occurs in parts of the text which have not changed. -.Sp -\&\fB\-\-label=label\fR or -\&\fB\-L label\fR -.Sp -Sets the labels used to describe the old and new files. The first use -of this option sets the label describing the old file and the second -use of the option sets the label for the new file, i.e. set both -labels like this \f(CW\*(C`\-L labelold \-L labelnew\*(C'\fR. -[Default: use the filename and modification dates for the label] -.Sp -\&\fB\-\-no\-label\fR -.Sp -Suppress inclusion of old and new file names as comment in output file -.Sp -\&\fB\-\-visble\-label\fR -.Sp -Include old and new filenames (or labels set with \-\-label option) as -visible output. -.Sp -\&\fB\-\-flatten\fR -.Sp -Replace \f(CW\*(C`\einput\*(C'\fR and \f(CW\*(C`\einclude\*(C'\fR commands within body by the content -of the files in their argument. If \f(CW\*(C`\eincludeonly\*(C'\fR is present in the -preamble, only those files are expanded into the document. However, -no recursion is done, i.e. \f(CW\*(C`\einput\*(C'\fR and \f(CW\*(C`\einclude\*(C'\fR commands within -included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, -respectively, making it possible to organise files into old and new directories. -\&\-\-flatten is applied recursively, so inputted files can contain further -\&\f(CW\*(C`\einput\*(C'\fR statements. -.Sp -Use of this option might result in prohibitive processing times for -larger documents, and the resulting difference document -no longer reflects the structure of the input documents. -.Sp -\&\fB\-\-help\fR or -\&\fB\-h\fR -.Sp -Show help text -.Sp -\&\fB\-\-version\fR -.Sp -Show version number -.RE -.SS "Predefined styles" -.IX Subsection "Predefined styles" -.SS "Major types" -.IX Subsection "Major types" -The major type determine the markup of plain text and some selected latex commands outside floats by defining the markup commands \f(CW\*(C`\eDIFadd{...}\*(C'\fR and \f(CW\*(C`\eDIFdel{...}\*(C'\fR . -.ie n .IP """UNDERLINE""" 10 -.el .IP "\f(CWUNDERLINE\fR" 10 -.IX Item "UNDERLINE" -Added text is wavy-underlined and blue, discarded text is struck out and red -(Requires color and ulem packages). Overstriking does not work in displayed math equations such that deleted parts of equation are underlined, not struck out (this is a shortcoming inherent to the ulem package). -.ie n .IP """CTRADITIONAL""" 10 -.el .IP "\f(CWCTRADITIONAL\fR" 10 -.IX Item "CTRADITIONAL" -Added text is blue and set in sans-serif, and a red footnote is created for each discarded -piece of text. (Requires color package) -.ie n .IP """TRADITIONAL""" 10 -.el .IP "\f(CWTRADITIONAL\fR" 10 -.IX Item "TRADITIONAL" -Like \f(CW\*(C`CTRADITIONAL\*(C'\fR but without the use of color. -.ie n .IP """CFONT""" 10 -.el .IP "\f(CWCFONT\fR" 10 -.IX Item "CFONT" -Added text is blue and set in sans-serif, and discarded text is red and very small size. -.ie n .IP """FONTSTRIKE""" 10 -.el .IP "\f(CWFONTSTRIKE\fR" 10 -.IX Item "FONTSTRIKE" -Added tex is set in sans-serif, discarded text small and struck out -.ie n .IP """CCHANGEBAR""" 10 -.el .IP "\f(CWCCHANGEBAR\fR" 10 -.IX Item "CCHANGEBAR" -Added text is blue, and discarded text is red. Additionally, the changed text is marked with a bar in the margin (Requires color and changebar packages). -.ie n .IP """CFONTCHBAR""" 10 -.el .IP "\f(CWCFONTCHBAR\fR" 10 -.IX Item "CFONTCHBAR" -Like \f(CW\*(C`CFONT\*(C'\fR but with additional changebars (Requires color and changebar packages). -.ie n .IP """CULINECHBAR""" 10 -.el .IP "\f(CWCULINECHBAR\fR" 10 -.IX Item "CULINECHBAR" -Like \f(CW\*(C`UNDERLINE\*(C'\fR but with additional changebars (Requires color, ulem and changebar packages). -.ie n .IP """CHANGEBAR""" 10 -.el .IP "\f(CWCHANGEBAR\fR" 10 -.IX Item "CHANGEBAR" -No mark up of text, but mark margins with changebars (Requires changebar package). -.ie n .IP """INVISIBLE""" 10 -.el .IP "\f(CWINVISIBLE\fR" 10 -.IX Item "INVISIBLE" -No visible markup (but generic markup commands will still be inserted. -.SS "Subtypes" -.IX Subsection "Subtypes" -The subtype defines the commands that are inserted at the begin and end of added or discarded blocks, irrespectively of whether these blocks contain text or commands (Defined commands: \f(CW\*(C`\eDIFaddbegin, \eDIFaddend, \eDIFdelbegin, \eDIFdelend\*(C'\fR) -.ie n .IP """SAFE""" 10 -.el .IP "\f(CWSAFE\fR" 10 -.IX Item "SAFE" -No additional markup (Recommended choice) -.ie n .IP """MARGIN""" 10 -.el .IP "\f(CWMARGIN\fR" 10 -.IX Item "MARGIN" -Mark beginning and end of changed blocks with symbols in the margin nearby (using -the standard \f(CW\*(C`\emarginpar\*(C'\fR command \- note that this sometimes moves somewhat -from the intended position. -.ie n .IP """COLOR""" 10 -.el .IP "\f(CWCOLOR\fR" 10 -.IX Item "COLOR" -An alternative way of marking added passages in blue, and deleted ones in red. -(It is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete, for example -with citation commands). -.ie n .IP """DVIPSCOL""" 10 -.el .IP "\f(CWDVIPSCOL\fR" 10 -.IX Item "DVIPSCOL" -An alternative way of marking added passages in blue, and deleted ones in red. Note -that \f(CW\*(C`DVIPSCOL\*(C'\fR only works with the dvips converter, e.g. not pdflatex. -(it is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete). -.SS "Float Types" -.IX Subsection "Float Types" -Some of the markup used in the main text might cause problems when used within -floats (e.g. figures or tables). For this reason alternative versions of all -markup commands are used within floats. The float type defines these alternative commands. -.ie n .IP """FLOATSAFE""" 10 -.el .IP "\f(CWFLOATSAFE\fR" 10 -.IX Item "FLOATSAFE" -Use identical markup for text as in the main body, but set all commands marking the begin and end of changed blocks to null-commands. You have to choose this float type if your subtype is \f(CW\*(C`MARGIN\*(C'\fR as \f(CW\*(C`\emarginpar\*(C'\fR does not work properly within floats. -.ie n .IP """TRADITIONALSAFE""" 10 -.el .IP "\f(CWTRADITIONALSAFE\fR" 10 -.IX Item "TRADITIONALSAFE" -Mark additions the same way as in the main text. Deleted environments are marked by angular brackets \e[ and \e] and the deleted text is set in scriptscript size. This float type should always be used with the \f(CW\*(C`TRADITIONAL\*(C'\fR and \f(CW\*(C`CTRADITIONAL\*(C'\fR markup types as the \efootnote command does not work properly in floating environments. -.ie n .IP """IDENTICAL""" 10 -.el .IP "\f(CWIDENTICAL\fR" 10 -.IX Item "IDENTICAL" -Make no difference between the main text and floats. -.SS "Configuration Variables" -.IX Subsection "Configuration Variables" -.ie n .IP """MINWORDSBLOCK""" 10 -.el .IP "\f(CWMINWORDSBLOCK\fR" 10 -.IX Item "MINWORDSBLOCK" -Minimum number of tokens required to form an independent block. This value is -used in the algorithm to detect changes of complete blocks by merging identical text parts of less than \f(CW\*(C`MINWORDSBLOCK\*(C'\fR to the preceding added and discarded parts. -.Sp -[ Default: 3 ] -.ie n .IP """FLOATENV""" 10 -.el .IP "\f(CWFLOATENV\fR" 10 -.IX Item "FLOATENV" -Environments whose name matches the regular expression in \f(CW\*(C`FLOATENV\*(C'\fR are -considered floats. Within these environments, the \fIlatexdiff\fR markup commands -are replaced by their \s-1FL\s0 variaties. -.Sp -[ Default: \f(CW\*(C`(?:figure|table|plate)[\ew\ed*@]*\*(C'\fR\ ] -.ie n .IP """PICTUREENV""" 10 -.el .IP "\f(CWPICTUREENV\fR" 10 -.IX Item "PICTUREENV" -Within environments whose name matches the regular expression in \f(CW\*(C`PICTUREENV\*(C'\fR -all latexdiff markup is removed (in pathologic cases this might lead to - inconsistent markup but this situation should be rare). -.Sp -[ Default: \f(CW\*(C`(?:picture|DIFnomarkup)[\ew\ed*@]*\*(C'\fR\ ] -.ie n .IP """MATHENV"",""MATHREPL""" 10 -.el .IP "\f(CWMATHENV\fR,\f(CWMATHREPL\fR" 10 -.IX Item "MATHENV,MATHREPL" -If both \ebegin and \eend for a math environment (environment name matching \f(CW\*(C`MATHENV\*(C'\fR -or \e[ and \e]) -are within the same deleted block, they are replaced by a \ebegin and \eend commands for \f(CW\*(C`MATHREPL\*(C'\fR -rather than being commented out. -.Sp -[ Default: \f(CW\*(C`MATHENV\*(C'\fR=\f(CW\*(C`(?:displaymath|equation)\*(C'\fR\ , \f(CW\*(C`MATHREPL\*(C'\fR=\f(CW\*(C`displaymath\*(C'\fR\ ] -.ie n .IP """MATHARRENV"",""MATHARRREPL""" 10 -.el .IP "\f(CWMATHARRENV\fR,\f(CWMATHARRREPL\fR" 10 -.IX Item "MATHARRENV,MATHARRREPL" -as \f(CW\*(C`MATHENV\*(C'\fR,\f(CW\*(C`MATHREPL\*(C'\fR but for equation arrays -.Sp -[ Default: \f(CW\*(C`MATHARRENV\*(C'\fR=\f(CW\*(C`eqnarray\e*?\*(C'\fR\ , \f(CW\*(C`MATHREPL\*(C'\fR=\f(CW\*(C`eqnarray\*(C'\fR\ ] -.ie n .IP """ARRENV""" 10 -.el .IP "\f(CWARRENV\fR" 10 -.IX Item "ARRENV" -If a match to \f(CW\*(C`ARRENV\*(C'\fR is found within an inline math environment within a deleted or added block, then the inlined math -is surrounded by \f(CW\*(C`\embox{\*(C'\fR...\f(CW\*(C`}\*(C'\fR. This is necessary as underlining does not work within inlined array environments. -.Sp -[ Default: \f(CW\*(C`ARRENV\*(C'\fR=\f(CW\*(C`(?:array|[pbvBV]matrix)\*(C'\fR\ -.ie n .IP """COUNTERCMD""" 10 -.el .IP "\f(CWCOUNTERCMD\fR" 10 -.IX Item "COUNTERCMD" -If a command in a deleted block which is also in the textcmd list matches \f(CW\*(C`COUNTERCMD\*(C'\fR then an -additional command \f(CW\*(C`\eaddtocounter{\*(C'\fR\fIcntcmd\fR\f(CW\*(C`}{\-1}\*(C'\fR, where \fIcntcmd\fR is the matching command, is appended in the diff file such that the numbering in the diff file remains synchronized with the -numbering in the new file. -.Sp -[ Default: \f(CW\*(C`COUNTERCMD\*(C'\fR=\f(CW\*(C`(?:footnote|part|section|subsection\*(C'\fR ... -.Sp -\&\f(CW\*(C`|subsubsection|paragraph|subparagraph)\*(C'\fR ] -.SH "COMMON PROBLEMS" -.IX Header "COMMON PROBLEMS" -.IP "Citations result in overfull boxes" 10 -.IX Item "Citations result in overfull boxes" -There is an incompatibility between the \f(CW\*(C`ulem\*(C'\fR package, which \f(CW\*(C`latexdiff\*(C'\fR uses for underlining and striking out in the \s-1UNDERLINE\s0 style, -the default style. In order to be able to mark up citations properly, they are placed with an \f(CW\*(C`\embox\*(C'\fR command in post-processing. As mboxes -cannot be broken across lines, this procedure frequently results in overfull boxes, possibly obscuring the content as it extends beyond the right margin. If this is a problem, you have two possibilities: -.Sp -1. Use \f(CW\*(C`COLOR\*(C'\fR or \f(CW\*(C`DVIPSCOL\*(C'\fR subtype markup (option \f(CW\*(C`\-s COLOR\*(C'\fR): If this markup is chosen, then changed citations are no longer marked up -with the wavy line (additions) or struck out (deletions), but are still highlighted in the appropriate color. -.Sp -2. Choose option \f(CW\*(C`\-\-disable\-citation\-markup\*(C'\fR which turns off the marking up of citations: deleted citations are no longer shown, and -added ctations are shown without markup. (This was the default behaviour of latexdiff at versions 0.6 and older -.SH "BUGS" -.IX Header "BUGS" -Option allow-spaces not implemented entirely consistently. It breaks -the rules that number and type of white space does not matter, as -different numbers of inter-argument spaces are treated as significant. -.PP -Please send bug reports -to \fItilmann@gfz\-potsdam.de\fR or submit on latexdiff project page \fIhttp://developer.berlios.de/projects/latexdiff/\fR. Include the serial number of \fIlatexdiff\fR -(from comments at the top of the source or use \fB\-\-version\fR). If you come across latex -files that are error-free and conform to the specifications set out -above, and whose differencing still does not result in error-free -latex, please send me those files, ideally edited to only contain the -offending passage as long as that still reproduces the problem. If your -file relies on non-standard class files, you must include those. I will not -look at examples where I have trouble to latex the original files. -.SH "SEE ALSO" -.IX Header "SEE ALSO" -latexrevise, latexdiff-vc -.SH "PORTABILITY" -.IX Header "PORTABILITY" -\&\fIlatexdiff\fR does not make use of external commands and thus should run -on any platform supporting Perl 5.6 or higher. If files with encodings -other than \s-1ASCII\s0 or \s-1UTF\-8\s0 are processed, Perl 5.8 or higher is required. -.PP -The standard version of \fIlatexdiff\fR requires installation of the Perl package -\&\f(CW\*(C`Algorithm::Diff\*(C'\fR (available from \fIwww.cpan.org\fR \- -\&\fIhttp://search.cpan.org/~nedkonz/Algorithm\-Diff\-1.15\fR) but a stand-alone -version, \fIlatexdiff-so\fR, which has this package inlined, is available, too. -\&\fIlatexdiff-fast\fR requires the \fIdiff\fR command to be present. -.SH "AUTHOR" -.IX Header "AUTHOR" -Copyright (C) 2004\-2012 Frederik Tilmann -.PP -This program is free software; you can redistribute it and/or modify -it under the terms of the \s-1GNU\s0 General Public License Version 3 -.PP -Contributors of fixes and additions: V. Kuhlmann, J. Paisley, N. Becker, T. Doerges, K. Huebner, -T. Connors, Sebastian Gouezel and many others. -Thanks to the many people who send in bug reports, feature suggestions, and other feedback. -.SH "POD ERRORS" -.IX Header "POD ERRORS" -Hey! \fBThe above document had some coding errors, which are explained below:\fR -.IP "Around line 2941:" 4 -.IX Item "Around line 2941:" -=over should be: '=over' or '=over positive_number' -.Sp -You can't have =items (as at line 2947) unless the first thing after the =over is an =item diff --git a/latexdiff-1.0.1/latexrevise b/latexdiff-1.0.1/latexrevise deleted file mode 100755 index bf3ec83..0000000 --- a/latexdiff-1.0.1/latexrevise +++ /dev/null @@ -1,527 +0,0 @@ -#!/usr/bin/env/perl -# latexrevise - takes output file of latexdiff and removes either discarded -# or appended passages, then deletes all other latexdiff markup -# -# Copyright (C) 2004 F J Tilmann (tilmann@gfz-potsdam.de, ftilmann@users.berlios.de) -# -# Project webpages: http://latexdiff.berlios.de/ -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# Note: version number now keeping up with latexdiff -# Version 1.0.1 no changes to latexrevise -# Version 0.3 Updated for compatibility with latexdiff 0.3 output (DIFAUXCMD removal) -# Version 0.1 First public release - -use Getopt::Long ; -use strict; -use warnings; - -# Markup strings (make sure that this are set to the same value as in -# latexdiff) -# If at all possible, do not change these as parts of the program -# depend on the actual name. -# At the very least adapt subroutine postprocess to new tokens. - -# note: have to use three backslashes to mean one literal one (reason -# unknown -my $ADDMARKOPEN='\\\DIFaddbegin(?:FL)? '; # Token to mark begin of appended text -my $ADDMARKCLOSE='\\\DIFaddend(?:FL)?(?: |\z)'; # Token to mark end of appended text (|\z only deals with the case of \DIFaddend right before \end{document} -my $ADDOPEN='\\\DIFadd(?:FL)?{'; # To mark begin of added text passage -my $ADDCLOSE='}'; # To mark end of added text passage -my $ADDCOMMENT='DIF > '; # To mark added comment line -my $DELMARKOPEN='\\\DIFdelbegin(?:FL)? '; # Token to mark begin of deleted text -my $DELMARKCLOSE='\\\DIFdelend(?:FL)?(?: |\z)'; # Token to mark end of deleted text -my $DELOPEN='\\\DIFdel(?:FL)?{'; # To mark begin of deleted text passage -my $DELCLOSE='}'; # To mark end of deleted text passage -my $ALTEXT='FL'; # string which might be appended to above commands -my $DELCMDOPEN='%DIFDELCMD < '; # To mark begin of deleted commands (must begin with %, i.e., be a comment -my $DELCMDCLOSE="%%%\n"; # To mark end of deleted commands (must end with a new line) -my $AUXCMD='%DIFAUXCMD' ; # follows auxiliary commands put in by latexdiff to make difference file legal -my $DELCOMMENT='DIF < '; # To mark deleted comment line - -my $PREAMBLEXTBEG='^%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF$'; -my $PREAMBLEXTEND='^%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF$'; - - -my $pat0 = '(?:[^{}]|\\\{|\\\})*'; -my $pat1 = '(?:[^{}]|\\\{|\\\}|\{'.$pat0.'\})*'; -my $pat2 = '(?:[^{}]|\\\{|\\\}|\{'.$pat1.'\})*'; -my $pat3 = '(?:[^{}]|\\\{|\\\}|\{'.$pat2.'\})*'; -my $pat4 = '(?:[^{}]|\\\{|\\\}|\{'.$pat3.'\})*'; -my $brat0 = '(?:[^\[\]]|\\\[|\\\])*'; - - -my ($input,$preamble,$body,$post); -my (@matches); -my ($cnt,$prematch,$postmatch); -my ($help); -my ($verbose,$quiet,$accept,$decline,$simplify)=(0,0,0,0,0); -my ($comment,$comenv,$markup,$markenv); - -# A word unlikely ever to be used in a real latex file -my $someword='gobbledegooksygook'; - -Getopt::Long::Configure('bundling'); -GetOptions('accept|a' => \$accept, - 'decline|d'=> \$decline, - 'simplify|s' => \$simplify, - 'comment|c=s' => \$comment, - 'comment-environment|e=s' => \$comenv, - 'markup|m=s' => \$markup, - 'markup-environment|n=s' => \$markenv, - 'no-warnings|q' => \$verbose, - 'verbose|V' => \$verbose, - 'help|h|H' => \$help); - -if ( $help ) { - usage() ; -} - -if ( ($accept && $decline) || ($accept && $simplify) || ($decline && $simplify) ) { - die '-a,-d and -s options are mutually axclusive. Type latexrevise -h to get more help.'; -} - - - -print STDERR "ACCEPT mode\n" if $verbose && $accept; -print STDERR "DECLINE mode\n" if $verbose && $decline; -print STDERR "SIMPLIFY mode. WARNING: The output will not normally be valid latex,\n" if $verbose && $simplify; - -# Slurp old and new files -{ - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $input=<>; -} - -# split into parts -($preamble,$body,$post)=splitdoc($input,'\begin{document}','\end{document}'); - -if (length $preamble && ( $accept || $decline ) ) { - # - # WORK ON PREAMBLE - # - # (compare subroutine linediff in latexdiff to make sure correct strings are used) - - # remove extra commands added to preamble by latexdiff - $preamble =~ s/${PREAMBLEXTBEG}.*?${PREAMBLEXTEND}\n{0,1}//smg ; - - if ( $accept ) { - # delete mark up in appended lines - $preamble =~ s/^(.*) %DIF > $/$1/mg ; - } elsif ( $decline ) { - # delete appended lines - # $preamble =~ s/^(.*) %DIF > $//mg ; - $preamble =~ s/^(.*) %DIF > \n//mg ; - # delete markup in deleted lines - $preamble =~ s/^%DIF < //mg ; - } - # remove any remaining DIF markups - #$preamble =~ s/%DIF.*$//mg ; - $preamble =~ s/%DIF.*?\n//sg ; -} -#print $preamble ; - -# -# WORK ON BODY -# -if ($accept) { - # remove ADDMARKOPEN, ADDMARKCLOSE tokens - @matches= $body =~ m/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/sg; - checkpure(@matches); - $body =~ s/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/$1/sg; - # remove text flanked by DELMARKOPEN, DELMARKCLOSE tokens - @matches= $body =~ m/${DELMARKOPEN}(.*?)${DELMARKCLOSE}/sg; - checkpure(@matches); - $body =~ s/${DELMARKOPEN}(.*?)${DELMARKCLOSE}//sg; - # remove markup of added comments - $body =~ s/%${ADDCOMMENT}(.*?)$/%$1/mg ; - # remove deleted comments (full line) - $body =~ s/^%${DELCOMMENT}.*?\n//mg ; - # remove deleted comments (part of line) - $body =~ s/%${DELCOMMENT}.*?$//mg ; -} -elsif ( $decline) { - # remove DELMARKOPEN, DELMARKCLOSE tokens - @matches= $body =~ m/${DELMARKOPEN}(.*?)${DELMARKCLOSE}/sg; - checkpure(@matches); - $body =~ s/${DELMARKOPEN}(.*?)${DELMARKCLOSE}/$1/sg; - # remove text flanked by ADDMARKOPEN, ADDMARKCLOSE tokens - # as latexdiff algorithm keeps the formatting and white spaces - # of the new text, sometimes whitespace might be inserted or - # removed inappropriately. We try to guess whether this has - # happened - - # Mop up tokens. This must be done already now as otherwise - # detection of white-space problems does not work - $cnt = $body =~ s/${DELOPEN}($pat4)${DELCLOSE}/$1/sg; - # remove markup of deleted commands - $cnt += $body =~ s/${DELCMDOPEN}(.*?)${DELCMDCLOSE}/$1/sg ; - $cnt += $body =~ s/${DELCMDOPEN}//g ; - # remove aux commands - $cnt += $body =~ s/^.*${AUXCMD}$/${someword}/mg; $body =~ s/${someword}\n//g; - - while ( $body =~ m/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/s ) { - $prematch=$`; - $postmatch=$'; - checkpure($1); - if ( $prematch =~ /\w$/s && $postmatch =~ /^\w/ ) { - # apparently no white-space between word=>Insert white space - $body =~ s/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/ /s ; - } - elsif ( $prematch =~ /\s$/s && $postmatch =~ /^[.,;:]/ ) { - # space immediately before one of ".,:;" => remove this space - $body =~ s/\s${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}//s ; - } - else { - # do not insert or remove any extras - $body =~ s/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}//s; - } - } -# Alternative without special cases treatment -# @matches= $body =~ m/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/sg; -# checkpure(@matches); -# $body =~ s/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}//sg; - # remove markup of deleted comments - $body =~ s/%${DELCOMMENT}(.*?)$/%$1/mg ; - # remove added comments (full line) - $body =~ s/^%${ADDCOMMENT}.*?\n//mg ; - # remove added comments (part of line) - $body =~ s/%${ADDCOMMENT}.*?$//mg ; -} - -# remove any remaining tokens -if ( $accept || $decline || $simplify ) { - # first substitution command deals with special case of added paragraph - $cnt = $body =~ s/${ADDOPEN}($pat4)\n${ADDCLOSE}\n/$1\n/sg; - $cnt += $body =~ s/${ADDOPEN}($pat4)${ADDCLOSE}/$1/sg; - $cnt==0 || warn 'Remaining $ADDOPEN tokens in DECLINE mode\n' unless ( $quiet || $accept || $simplify ); -} -if ($accept || $simplify ) { - # Note: in decline mode these commands have already been removed above - $cnt = $body =~ s/${DELOPEN}($pat4)${DELCLOSE}/$1/sg; - #### remove markup of deleted commands - $cnt += $body =~ s/${DELCMDOPEN}(.*?)${DELCMDCLOSE}/$1/sg ; - $cnt += $body =~ s/${DELCMDOPEN}//g ; - # remove aux commands - # $cnt += - $body =~ s/^.*${AUXCMD}$/${someword}/mg; $body =~ s/${someword}\n//g; - - #### remove deleted comments - ###$cnt += $body =~ s/${DIFDELCMD}.*?$//mg ; - $cnt==0 || warn 'Remaining $DELOPEN or $DIFDELCMD tokens in ACCEPT mode\n' unless ( $quiet || $simplify ); -} - -# Remove comment commands -if (defined($comment)) { - print STDERR "Removing \\$comment\{..\} sequences ..." if $verbose; - # protect $comments in comments by making them look different - $body =~ s/(%.*)${comment}(.*)$/$1${someword}$2/mg ; - # carry out the substitution - $cnt = 0 + $body =~ s/\\${comment}(?:\[${brat0}\])?\{${pat4}\}//sg ; - print STDERR "$cnt matches found and removed.\n" if $verbose; - # and undo the protection substitution - $body =~ s/(%.*)${someword}(.*)$/$1${comment}$2/mg ; -} -if (defined($comenv)) { - print STDERR "Removing $comenv environments ..." if $verbose; - $body =~ s/(%.*)${comenv}/$1${someword}/mg ; -## $cnt = 0 + $body =~ s/\\begin(?:\[${brat0}\])?\{\$comenv\}.*?\\end\{\$comenv\}//sg ; - $cnt = 0 + $body =~ s/\\begin(?:\[${brat0}\])?\{${comenv}\}.*?\\end\{${comenv}\}\s*?\n//sg ; - print STDERR "$cnt matches found and removed.\n" if $verbose; - $body =~ s/(%.*)${someword}/$1${comenv}/mg ; -} - -if (defined($markup)) { - print STDERR "Removing \\$markup\{..\} cpmmands ..." if $verbose; - # protect $markups in comments by making them look different - $body =~ s/(%.*)${markup}(.*)$/$1${someword}$2/mg ; - # carry out the substitution - $cnt = 0 + $body =~ s/\\${markup}(?:\[${brat0}\])?\{(${pat4})\}/$1/sg ; - print STDERR "$cnt matches found and removed.\n" if $verbose; - # and undo the protection substitution - $body =~ s/(%.*)${someword}(.*)$/$1${markup}$2/mg ; -} -if (defined($markenv)) { - print STDERR "Removing $markenv environments ..." if $verbose; - $body =~ s/(%.*)${markenv}/$1${someword}/mg ; - $cnt = 0 + $body =~ s/\\begin(?:\[${brat0}\])?\{${markenv}\}\n?//sg; - $cnt += 0 + $body =~ s/\\end\{${markenv}\}\n?//sg; - print STDERR $cnt/2, " matches found and removed.\n" if $verbose; - $body =~ s/(%.*)${someword}/$1${markenv}/mg ; -} - - -if ( length $preamble ) { - print "$preamble\\begin{document}${body}\\end{document}$post"; -} else { - print $body; -} - -# checkpure(@matches) -# checks whether any of the strings in matches contains -# $ADDMARKOPEN, $ADDMARKCLOSE,$DELMARKOPEN, or $DELMARKCLOSE -# If so, die reporting nesting problems, otherwise return to caller -sub checkpure { - while (defined($_=shift)) { - if ( /$ADDMARKOPEN/ || /$ADDMARKCLOSE/ - || /$DELMARKOPEN/ || /$DELMARKCLOSE/ ) { - die <=0 && $j>$i ) { - $part1 = substr($text,0,$i) ; - $part2 = substr($text,$i+$l1,$j-$i-$l1); - $part3 = substr($text,$j+$l2) unless $j+$l2 >= length $text; - } else { - die "$word1 or $word2 not in the correct order or not present as a pair." - } - return ($part1,$part2,$part3); -} - - - -sub usage { - die <<"EOF"; -Usage: $0 [OPTIONS] [diff.tex] > revised.tex - -Read a file diff.tex (output of latexdiff), and remove its markup. -If no filename is given read from standard input. The command can be used -in ACCEPT, DECLINE, or SIMPLIFY mode, and be used to remove user-defined -latex commands from the input (see options -c, -e, -m, -n below). -In ACCEPT mode, all appended text fragments (or preamble lines) -are kept, and all discarded text fragments (or preamble lines) are -deleted. -In DECLINE mode, all discarded text fragments are kept, and all appended -text fragments are deleted. -If you wish to keep some changes, edit the diff.tex file in -advance, and manually remove those tokens which would otherwise be -deleted. Note that latexrevise only pays attention to the \\DIFaddbegin, -\\DIFaddend, \\DIFdelbegin, and \\DIFdelend tokens and corresponding FL -varieties. All \\DIFadd and \\DIFdel commands (but not their content) are -simply deleted. The commands added by latexdiff to the preamble are also -removed. -In SIMPLIFY mode all latexdiff markup is removed from the body of the text (after -\\begin{document}) except for \\DIFaddbegin, \\DIFaddend, \\DIFdelbegin, \\DIFdelend -tokens and the corresponding FL varieties of those commands. The result -will not in general be valid latex-code but might be easier to read and edit in -preparation for a subsequent run in ACCEPT or DECLINE mode. -In SIMPLIFY mode the preamble is left unmodified. - --a ---accept Run in ACCEPT mode (delete all blocks marked by \\DIFdelbegin - and \\DIFdelend). - --d ---decline Run in DECLINE mode (delete all blocks marked by \\DIFaddbegin - and \\DIFaddend). - --s ---simplify Run in SIMPLIFY mode (Keep all \\DIFaddbegin, \\DIFaddend, - \\DIFdelbegin, \\DIFdelend tokens, but remove all other latexdiff - markup from body. - -Note that the three mode options are mutually exclusive. If no mode option is given, -latexrevise simply removes user annotations and markup according to the following four -options. - - --c cmd ---comment=cmd Remove \\cmd{...}. cmd is supposed to mark some explicit - anotations which should be removed from the file before - release. - --e envir ---comment-environment=envir - Remove explicit annotation environments from the text, i.e. remove - \\begin{envir} - ... - \\end{envir} - blocks. - --m cmd ---markup=cmd Remove the markup command cmd but leave its argument, i.e. - turn \\cmd{abc} into abc. - --n envir ---markup-environment=envir - Similarly, remove \\begin{envir} and \\end{envir} commands, - but leave content of the environment in the text. - --q ---no-warnings Do not warn users about \\DIDadd{..} or \\DIFdel statements - which should not be there anymore - --V ---verbose Verbose output - -EOF -} - -=head1 NAME - -latexrevise - selectively remove markup and text from latexdiff output - -=head1 SYNOPSIS - -B [ B ] [ F ] > F - -=head1 DESCRIPTION - -I reads a file C (output of I), and remove the markup commands. -If no filename is given the input is read from standard input. The command can be used -in I, I, or I mode, or can be used to remove user-defined -latex commands from the input (see B<-c>, B<-e>, B<-m>, and B<-n> below). -In I mode, all appended text fragments (or preamble lines) -are kept, and all discarded text fragments (or preamble lines) are -deleted. -In I mode, all discarded text fragments are kept, and all appended -text fragments are deleted. -If you wish to keep some changes, edit the diff.tex file in -advance, and manually remove those tokens which would otherwise be -deleted. Note that I only pays attention to the C<\DIFaddbegin>, -C<\DIFaddend>, C<\DIFdelbegin>, and C<\DIFdelend> tokens and corresponding FL -varieties. All C<\DIFadd> and C<\DIFdel> commands (but not their contents) are -simply deleted. The commands added by latexdiff to the preamble are also -removed. -In I mode, C<\DIFaddbegin, \DIFaddend, \DIFdelbegin, \DIFdelend> -tokens and their corresponding C varieties are kept but all other markup (e.g. C and <\DIFdel>) is removed. The result -will not in general be valid latex-code but it will be easier to read and edit in -preparation for a subsequent run in I or I mode. -In I mode the preamble is left unmodified. - -=head1 OPTIONS - -=over 4 - -=item B<-a> or B<--accept> - -Run in I mode (delete all blocks marked by C<\DIFdelbegin> and C<\DIFdelend>). - -=item B<-d> or B<--decline> - -Run in I mode (delete all blocks marked by C<\DIFaddbegin> -and C<\DIFaddend>). - -=item B<-s> or B<--simplify> - -Run in I mode (Keep all C<\DIFaddbegin>, C<\DIFaddend>, -C<\DIFdelbegin>, C<\DIFdelend> tokens, but remove all other latexdiff -markup from body). - -=back - -Note that the three mode options are mutually exclusive. If no mode option is given, -I simply removes user annotations and markup according to the following four -options. - -=over 4 - -=item B<-c cmd> or B<--comment=cmd> - -Remove C<\cmd{...}> sequences. C is supposed to mark some explicit -anotations which should be removed from the file before -release. - -=item B<-e envir> or B<--comment-environment=envir> - -Remove explicit annotation environments from the text, i.e. remove - - \begin{envir} - ... - \end{envir} - -blocks. - -=item B<-m cmd> or B<--markup=cmd> - -Remove the markup command C<\cmd> but leave its argument, i.e. -turn C<\cmd{abc}> into C. - -=item B<-n envir> or B<--markup-environment=envir> - -Similarly, remove C<\begin{envir}> and C<\end{envir}> commands but -leave content of the environment in the text. - - -=item B<-V> or B<--verbose> - -Verbose output - -=item B<-q> or B<--no-warnings> - -Do not warn users about C<\DIDadd{..}> or C<\DIFdel{..}> statements -which should have been removed already. - -=back - -=head1 BUGS - -The current version is a beta version which has not yet been -extensively tested, but worked fine locally. Please submit bug reports through -the latexdiff project page I or send -to I. Include the serial number of I -(from comments at the top of the source). If you come across latexdiff -output which is not processed correctly by I please include the -problem file as well as the old and new files on which it is based, -ideally edited to only contain the offending passage as long as that still -reproduces the problem. - -Note that I gets confused by commented C<\begin{document}> or -C<\end{document}> statements - -=head1 SEE ALSO - -L - -=head1 PORTABILITY - -I does not make use of external commands and thus should run -on any platform supporting PERL v5 or higher. - -=head1 AUTHOR - -Copyright (C) 2004 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 - -=cut diff --git a/latexdiff-1.0.1/latexrevise.1 b/latexdiff-1.0.1/latexrevise.1 deleted file mode 100644 index b44a245..0000000 --- a/latexdiff-1.0.1/latexrevise.1 +++ /dev/null @@ -1,235 +0,0 @@ -.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` "" -. ds C' "" -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.ie \nF \{\ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. nr % 0 -. rr F -.\} -.el \{\ -. de IX -.. -.\} -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "LATEXREVISE 1" -.TH LATEXREVISE 1 "2012-11-13" "perl v5.14.2" " " -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -latexrevise \- selectively remove markup and text from latexdiff output -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBlatexrevise\fR [ \fB\s-1OPTIONS\s0\fR ] [ \fIdiff.tex\fR ] > \fIrevised.tex\fR -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -\&\fIlatexrevise\fR reads a file \f(CW\*(C`diff.tex\*(C'\fR (output of \fIlatexdiff\fR), and remove the markup commands. -If no filename is given the input is read from standard input. The command can be used -in \fI\s-1ACCEPT\s0\fR, \fI\s-1DECLINE\s0\fR, or \fI\s-1SIMPLIFY\s0\fR mode, or can be used to remove user-defined -latex commands from the input (see \fB\-c\fR, \fB\-e\fR, \fB\-m\fR, and \fB\-n\fR below). -In \fI\s-1ACCEPT\s0\fR mode, all appended text fragments (or preamble lines) -are kept, and all discarded text fragments (or preamble lines) are -deleted. -In \fI\s-1DECLINE\s0\fR mode, all discarded text fragments are kept, and all appended -text fragments are deleted. -If you wish to keep some changes, edit the diff.tex file in -advance, and manually remove those tokens which would otherwise be -deleted. Note that \fIlatexrevise\fR only pays attention to the \f(CW\*(C`\eDIFaddbegin\*(C'\fR, -\&\f(CW\*(C`\eDIFaddend\*(C'\fR, \f(CW\*(C`\eDIFdelbegin\*(C'\fR, and \f(CW\*(C`\eDIFdelend\*(C'\fR tokens and corresponding \s-1FL\s0 -varieties. All \f(CW\*(C`\eDIFadd\*(C'\fR and \f(CW\*(C`\eDIFdel\*(C'\fR commands (but not their contents) are -simply deleted. The commands added by latexdiff to the preamble are also -removed. -In \fI\s-1SIMPLIFY\s0\fR mode, \f(CW\*(C`\eDIFaddbegin, \eDIFaddend, \eDIFdelbegin, \eDIFdelend\*(C'\fR -tokens and their corresponding \f(CW\*(C`FL\*(C'\fR varieties are kept but all other markup (e.g. \f(CW\*(C`DIFadd\*(C'\fR and <\eDIFdel>) is removed. The result -will not in general be valid latex-code but it will be easier to read and edit in -preparation for a subsequent run in \fI\s-1ACCEPT\s0\fR or \fI\s-1DECLINE\s0\fR mode. -In \fI\s-1SIMPLIFY\s0\fR mode the preamble is left unmodified. -.SH "OPTIONS" -.IX Header "OPTIONS" -.IP "\fB\-a\fR or \fB\-\-accept\fR" 4 -.IX Item "-a or --accept" -Run in \fI\s-1ACCEPT\s0\fR mode (delete all blocks marked by \f(CW\*(C`\eDIFdelbegin\*(C'\fR and \f(CW\*(C`\eDIFdelend\*(C'\fR). -.IP "\fB\-d\fR or \fB\-\-decline\fR" 4 -.IX Item "-d or --decline" -Run in \fI\s-1DECLINE\s0\fR mode (delete all blocks marked by \f(CW\*(C`\eDIFaddbegin\*(C'\fR -and \f(CW\*(C`\eDIFaddend\*(C'\fR). -.IP "\fB\-s\fR or \fB\-\-simplify\fR" 4 -.IX Item "-s or --simplify" -Run in \fI\s-1SIMPLIFY\s0\fR mode (Keep all \f(CW\*(C`\eDIFaddbegin\*(C'\fR, \f(CW\*(C`\eDIFaddend\*(C'\fR, -\&\f(CW\*(C`\eDIFdelbegin\*(C'\fR, \f(CW\*(C`\eDIFdelend\*(C'\fR tokens, but remove all other latexdiff -markup from body). -.PP -Note that the three mode options are mutually exclusive. If no mode option is given, -\&\fIlatexrevise\fR simply removes user annotations and markup according to the following four -options. -.IP "\fB\-c cmd\fR or \fB\-\-comment=cmd\fR" 4 -.IX Item "-c cmd or --comment=cmd" -Remove \f(CW\*(C`\ecmd{...}\*(C'\fR sequences. \f(CW\*(C`cmd\*(C'\fR is supposed to mark some explicit -anotations which should be removed from the file before -release. -.IP "\fB\-e envir\fR or \fB\-\-comment\-environment=envir\fR" 4 -.IX Item "-e envir or --comment-environment=envir" -Remove explicit annotation environments from the text, i.e. remove -.Sp -.Vb 3 -\& \ebegin{envir} -\& ... -\& \eend{envir} -.Ve -.Sp -blocks. -.IP "\fB\-m cmd\fR or \fB\-\-markup=cmd\fR" 4 -.IX Item "-m cmd or --markup=cmd" -Remove the markup command \f(CW\*(C`\ecmd\*(C'\fR but leave its argument, i.e. -turn \f(CW\*(C`\ecmd{abc}\*(C'\fR into \f(CW\*(C`abc\*(C'\fR. -.IP "\fB\-n envir\fR or \fB\-\-markup\-environment=envir\fR" 4 -.IX Item "-n envir or --markup-environment=envir" -Similarly, remove \f(CW\*(C`\ebegin{envir}\*(C'\fR and \f(CW\*(C`\eend{envir}\*(C'\fR commands but -leave content of the environment in the text. -.IP "\fB\-V\fR or \fB\-\-verbose\fR" 4 -.IX Item "-V or --verbose" -Verbose output -.IP "\fB\-q\fR or \fB\-\-no\-warnings\fR" 4 -.IX Item "-q or --no-warnings" -Do not warn users about \f(CW\*(C`\eDIDadd{..}\*(C'\fR or \f(CW\*(C`\eDIFdel{..}\*(C'\fR statements -which should have been removed already. -.SH "BUGS" -.IX Header "BUGS" -The current version is a beta version which has not yet been -extensively tested, but worked fine locally. Please submit bug reports through -the latexdiff project page \fIhttp://developer.berlios.de/projects/latexdiff/\fR or send -to \fItilmann@gfz\-potsdam.de\fR. Include the serial number of \fIlatexrevise\fR -(from comments at the top of the source). If you come across latexdiff -output which is not processed correctly by \fIlatexrevise\fR please include the -problem file as well as the old and new files on which it is based, -ideally edited to only contain the offending passage as long as that still -reproduces the problem. -.PP -Note that \fIlatexrevise\fR gets confused by commented \f(CW\*(C`\ebegin{document}\*(C'\fR or -\&\f(CW\*(C`\eend{document}\*(C'\fR statements -.SH "SEE ALSO" -.IX Header "SEE ALSO" -latexdiff -.SH "PORTABILITY" -.IX Header "PORTABILITY" -\&\fIlatexrevise\fR does not make use of external commands and thus should run -on any platform supporting \s-1PERL\s0 v5 or higher. -.SH "AUTHOR" -.IX Header "AUTHOR" -Copyright (C) 2004 Frederik Tilmann -.PP -This program is free software; you can redistribute it and/or modify -it under the terms of the \s-1GNU\s0 General Public License Version 3 diff --git a/latexdiff-1.0.2/COPYING b/latexdiff-1.0.2/COPYING deleted file mode 100644 index d6fa915..0000000 --- a/latexdiff-1.0.2/COPYING +++ /dev/null @@ -1,623 +0,0 @@ - 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 - - diff --git a/latexdiff-1.0.2/README b/latexdiff-1.0.2/README deleted file mode 100644 index 7c7ff86..0000000 --- a/latexdiff-1.0.2/README +++ /dev/null @@ -1,107 +0,0 @@ -INTRODUCTION - -latexdiff is a Perl script, which compares two latex files and marks -up significant differences between them (i.e. a diff for latex files). - Various options are available for visual markup using standard latex -packages such as "color.sty". Changes not directly affecting visible -text, for example in formatting commands, are still marked in -the latex source. - -A rudimentary revision facilility is provided by another Perl script, -latexrevise, which accepts or rejects all changes. Manual -editing of the difference file can be used to override this default -behaviour and accept or reject selected changes only. - -The author is F Tilmann (ftilmann@users.berlios.de). - -Project webpage: http://latexdiff.berlios.de/ -CTAN page: http://www.ctan.org/tex-archive/support/latexdiff - - -REQUIREMENTS - -Perl 5.8 or higher must be installed. - The latexdiff script makes use of the Perl package Algorithm::Diff (available -from www.cpan.org, current version 1.19). You can either install this package, or -use the standalone version of latexdiff, latexdiff-so, which has version 1.15 of -this package inlined and does not require external installation of -the package. Because latexdiff uses internal functions of Algorithm:Diff whose -calling format or availability can change without notice, the preferred method is -now to use the standalone version. - -As an alternative, latexdiff-fast has a modified version of Algorithm::Diff inlined, -which internally uses the UNIX diff command. This version is much faster but is dependent -on an external "diff" command. Subtle differences in the algorithm of Algorithm::Diff and -UNIX-diff mean that the resulting set of differences will generally not be the same as -for the standard latexdiff. In most practical cases, these differences are minor, though. - -INSTALLATION UNIX/LINUX - -The basic installation procedure is almost trivial: - -1. Copy latexdiff, latexrevise and latexdiff-vc into a directory which - is in the search path and make them executable. If the Algorithm::Diff - package is not installed, use latexdiff-so instead of latexdiff. - -2. Copy latexdiff.1 and latexrevise.1 into the correct man directory - -3. Optionally create soft links latexdiff-cvs latexdiff-rcs, and - latexdiff-svn for latexdiff-vc. - -The attached Makefile contains example commands to carry out above -steps as root for a typical UNIX installation. Type - - make install (for the stand alone version) -or - make install-ext (for the version using the external Algorithm::Diff) -or - make install-fast (for the version using the UNIX 'diff' function for fast differencing) - -to get it rolling. You can type - - make test -or - make test-ext -or - make test-fast - -to test the respective versions on a brief example before installation - - -DOCUMENTATION: - -Usage instructions are in the manual latexdiff-man.pdf as well as the -man pages. - -CHANGELOGS: - -Check out the comment lines at the beginning of the perl scripts (latexdiff, latexdiff-vc, latexrevise) - -CONTRIBUTIONS - -The directory contrib contains code written by others relating to latexdiff. -Currently this directory contains: - -latexdiff-wrap (Author: V. Kuhlmann) An alternative wrapper script which can be used - instead of latexdiff-vc. Its main use is as a template for customised wrapper scripts. - -latexdiff.spec (Author: T. Doerges) spec file for RPM generation - -latexchanges (Author: Jan-Ake Larsson) Wrapper script for applying latexdiff with numbered documen version -(see contrib/README.latexchanges for a more detailed description) - -Cntributions by the following authors were incorporated into the latexdiff code, or inspired me to -extend latexdiff in a similar way: J. Paisley, N. Becker, K. Huebner - -LICENSE (also see file COPYING) - -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 (file LICENSE in the -distribution). - diff --git a/latexdiff-1.0.2/contrib/README.latexchanges b/latexdiff-1.0.2/contrib/README.latexchanges deleted file mode 100644 index 4a02765..0000000 --- a/latexdiff-1.0.2/contrib/README.latexchanges +++ /dev/null @@ -1,13 +0,0 @@ -latexchanges.py (Jan-Ake Larsson): -Here's a wrapper I wrote for latexdiff, intended as a drop-in -replacement for latex, when you have several numbered (or dated) -versions of a manuscript. My coauthors don't as a rule know what CVS or -SVN is, they simply use a number or date for the different versions. - -latexchanges replaces the current DVI with one that includes a -latexdiff to the last version. The last version is selected as the -TEX file in the same directory with the same prefix (up to a number -or a dot), that has an mtime immediately preceding the given TEX -file. - - diff --git a/latexdiff-1.0.2/contrib/latexchanges.py b/latexdiff-1.0.2/contrib/latexchanges.py deleted file mode 100644 index de7acbe..0000000 --- a/latexdiff-1.0.2/contrib/latexchanges.py +++ /dev/null @@ -1,67 +0,0 @@ -#! /bin/env python -# latexchanges -# -# Wrapper for latexdiff, intended as a drop-in replacement for latex, -# when you have several numbered (or dated) versions of a manuscript. -# My coauthors don't as a rule know what CVS or SVN is, they simply -# use a number or date for the different versions. -# -# latexchanges replaces the current DVI with one that includes a -# latexdiff to the last version. The last version is selected as the -# TEX file in the same directory with the same prefix (up to a number -# or a dot), that has an mtime immediately preceding the given TEX -# file. -# -# (I should probably add CVS version numbering too, at some point.) -# -# Copyright (C) 2009 by Jan-\AA{}ke Larsson -# Released under the terms of the GNU General Public License (GPL) -# Version 2. See http://www.gnu.org/ for details. -# -# Please do provide patches and bug reports, but remember: if it -# breaks, you get to keep the pieces. -# -# Jan-\AA{}ke Larsson -# Sept 16 2009 - -from os import listdir,system,stat -from sys import argv -from re import split - -name="" -newarg=[] - -# Find filename argument -for i in range(1,len(argv)): - if argv[i][-4:]==".tex": - basename=split('[0-9.]',argv[i])[0] - name=argv[i][:-4] - newarg.append(name+".changes.tex") - else: - newarg.append(argv[i]) - -if name: - print "Filename",name+".tex" - print "Prefix is",basename - # Find last archived version - mtime=stat(name+".tex").st_mtime - old_mtime=0 - ls=listdir(".") - for j in ls: - if j.startswith(basename) and j.endswith(".tex")\ - and not j.endswith(".changes.tex"): - tmptime=stat(j).st_mtime - if mtime>tmptime and old_mtime0: - print "Comparing with",oldname - system ("/bin/cp "+name+".aux "+name+".changes.aux") - system ("/bin/cp "+name+".bbl "+name+".changes.bbl") - system ("latexdiff "+oldname+" "+name+".tex > "+name+".changes.tex") - system ("latex "+" ".join(newarg)) - system ("cp "+name+".changes.dvi "+name+".dvi") - else: - system ("latex "+" ".join(argv[1:])) diff --git a/latexdiff-1.0.2/contrib/latexdiff-wrap b/latexdiff-1.0.2/contrib/latexdiff-wrap deleted file mode 100755 index 894b424..0000000 --- a/latexdiff-1.0.2/contrib/latexdiff-wrap +++ /dev/null @@ -1,192 +0,0 @@ -#!/bin/bash -# -# latexdiff-wrap -# -# Wrapper for latexdiff, to -# * provide support for documents consiting of more than 1 latex file -# * provide my common arguments -# -# Copyright (C) by Volker Kuhlmann -# Released under the terms of the GNU General Public License (GPL) Version 2. -# See http://www.gnu.org/ for details. -# -# Volker Kuhlmann -# 5, 6, 7, 12, 16, 17 Oct 2005 -# 31 Jan; 5, 7, 13, 15 Feb 2006 -# - -VERSION="0.6, 15 Feb 2006" -AUTHOR="Volker Kuhlmann " -COPYRIGHT="Copyright (C) 2005-2006" - - -#### -#### Constants and initialised variables -# -diffcmd="latexdiff" -diffrc="$HOME/texmf/latexdiff" -#diffargs="-e latin1 --ignore-warnings -p latexdiff-preamble.sty" -diffargs="-e latin1 --ignore-warnings" -diffargs="$diffargs --append-safecmd $diffrc/safe-cmds" -diffargs="$diffargs --append-textcmd $diffrc/text-cmds" -# Note: Can't use multiple --append-safecmd -# show current command lists: -#diffcmd="$diffcmd --show-safecmd --show-textcmd --show-config" - - -#### -#### Version, Usage, Help -# -show_version() { - echo "${0##*/} version $VERSION -$COPYRIGHT by $AUTHOR" -} - -show_usage() { - echo " -Usage: ${0##*/} OLDDIR NEWDIR DIFFDIR [DIFFARGS --] FILE.tex [...] - ${0##*/} --show [DIFFARGS] -Version $VERSION -$COPYRIGHT by $AUTHOR -" -} - -show_help() { - show_usage - echo "\ -For each FILE.tex, build a new file DIFFDIR/FILE.tex with markup of the changes -which were made from OLDDIR/FILE.tex to NEWDIR/FILE.tex. -Any path given with FILE.tex is stripped off. -Any DIFFARGS are added to the latexdiff call, if present (remember to follow -them with a double-hyphen on its own before the FILE arguments). - -With --show, shows the settings latexdiff would be running with, including the -changes applied by the user. -" -} - -# For scripts not using function library only: -Version() { show_version; exitwith ErrVersion; } -Usage() { show_help; exitwith ErrUsage; } -Help() { test "$1" && exitwith ErrHelp show_help; show_help; exitwith ErrOK; } - - -#### -#### Error/Exit codes -# -exitwith() { - exec 1>&2 # write stdout on stderr instead - case "$1" in - ErrOK) - exit 0;; - ErrVersion|ErrUsage|ErrHelp) - # Output generated by function (program) $2, if given - test -n "$2" && "$2" - exit 1;; - # more codes in here - # more codes in here - ErrBadoption) - echo "Bad option '$2'." - echo "Call with -h for help." - exit 9;; - ErrMissingParameter) - echo "A required parameter for option $2 is missing." - echo "Call with -h for help." - exit 9;; - *) - echo "Internal error: exitwith() called with illegal error code '$1'." - exit 19;; - esac -} - - -#### -#### Parse command line parameters -# - -# If the next arg starts with a "-", collect additional argument for latexdiff -# until "--". -scanextraargs() { - addargs=() - case "$1" in -*) - while [ $# -gt 0 -a "$1" != "--" ]; do - addargs=( "${addargs[@]}" "$1" ) - shift - done - test "$1" == "--" && shift - ;; esac - fileargs=( "$@" ) -} - -case "$1" in - --version) Version;; - --usage) Usage;; - --help|-h|-help) Help;; - --show) - shift - scanextraargs "$@" - (set -x - $diffcmd $diffargs "${addargs[@]}" \ - --show-safecmd --show-textcmd --show-config - ) | fmt - exit $? ;; -esac - -olddir="${1%/}" -newdir="${2%/}" -diffdir="${3%/}" - -if ! [ -d "$olddir" -a -d "$newdir" -a -d "$diffdir" ]; then - Help 1>&2 err -fi - -shift 3 - -scanextraargs "$@" -set -- "${fileargs[@]}" - - - -#### -#### Functions -# -#set -x -Log() { echo 1>&2 "+ $@"; "$@"; } - - -#### -#### Main -# - -# Create output directory, just in case. -(set -x -mkdir -p "$diffdir" -) -while [ $# -gt 0 ]; do - file="${1##*/}" - echo Examining: "$file" - # No point running latexdiff if both files are identical, - # but run latexdiff on top-level LaTeX file in any case. - if cmp --quiet "$olddir/$file" "$newdir/$file" \ - && ! grep -lq '\\begin.*{document}' "$newdir/$file"; then - (set -x - cp -p "$olddir/$file" "$diffdir" - ) - else - # Delete file, to make sure it's not clobbered by redirecting stdout - # in case it's a symlink to te original. - test -f "$diffdir/$file" && (set -x - rm "$diffdir/$file" - ) - # Run latexdiff if both input files are present. - run=1 - test -f "$olddir/$file" || { echo 1>&2 "No file: $olddir/$file"; run=; } - test -f "$newdir/$file" || { echo 1>&2 "No file: $newdir/$file"; run=; } - test -n "$run" && \ - (set -x - $diffcmd $diffargs "${addargs[@]}" \ - "$olddir/$file" "$newdir/$file" > "$diffdir/$file" - ) - fi - shift -done diff --git a/latexdiff-1.0.2/contrib/latexdiff.spec b/latexdiff-1.0.2/contrib/latexdiff.spec deleted file mode 100644 index 9255a69..0000000 --- a/latexdiff-1.0.2/contrib/latexdiff.spec +++ /dev/null @@ -1,58 +0,0 @@ -Summary: Diff for LaTeX files -Name: latexdiff -Version: 0.5 -Release: 1 -License: GPL -Group: Productivity/Publishing/TeX/Utilities -URL: http://www.tug.org/tex-archive/help/Catalogue/entries/latexdiff.html -Source0: %{name}.zip -BuildArch: noarch -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root -# only required for 'make install-ext' -# Requires: perl-Algorithm-Diff - - -%description -latexdiff is a Perl script, which compares two latex files and marks -up significant differences between them (i.e. a diff for latex files). - Various options are available for visual markup using standard latex -packages such as "color.sty". Changes not directly affecting visible -text, for example in formatting commands, are still marked in -the latex source. - -(C) 2004 Frederik Tilmann - - -%prep -%setup -n %{name} - - -%build -# quick had to adapt the Makefile -%{__mv} Makefile Makefile.old -%{__sed} \ - -e "s;INSTALLPATH = /usr/local;INSTALLPATH = \${DESTDIR}%{_prefix};" \ - -e "s;INSTALLMANPATH = \$(INSTALLPATH)/man;INSTALLMANPATH = \${DESTDIR}%{_mandir};" \ - Makefile.old > Makefile - - -%install -%{__mkdir_p} $RPM_BUILD_ROOT%{_bindir} -%{__mkdir_p} $RPM_BUILD_ROOT%{_mandir}/man1 - -%makeinstall - - -%clean -[ "${RPM_BUILD_ROOT}" != "/" ] && [ -d "${RPM_BUILD_ROOT}" ] && %{__rm} -rf "${RPM_BUILD_ROOT}" - - -%files -%defattr(-,root,root) -%doc example CHANGES LICENSE README -%{_bindir}/* -%{_mandir}/man*/* - -%changelog -* Thu Jan 4 2007 Till Dörges - 0.5-1 -- Initial build. diff --git a/latexdiff-1.0.2/doc/example-diff.tex b/latexdiff-1.0.2/doc/example-diff.tex deleted file mode 100644 index 149588d..0000000 --- a/latexdiff-1.0.2/doc/example-diff.tex +++ /dev/null @@ -1,89 +0,0 @@ -\documentclass[12pt,a4paper]{article} -%DIF LATEXDIFF DIFFERENCE FILE -%DIF DEL example-draft.tex Sat Nov 17 00:45:22 2012 -%DIF ADD example-rev.tex Sat Nov 17 00:45:22 2012 - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -%DIF 7c7 -%DIF < \setlength{\textwidth}{6.5in} -%DIF ------- -\setlength{\textwidth}{6in} %DIF > -%DIF ------- - -\title{latexdiff Example - \DIFdelbegin \DIFdel{Draft }\DIFdelend \DIFaddbegin \DIFadd{Revised }\DIFaddend version} -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even %DIF > -% if some preamble might eventually end up as visible text.) %DIF > -%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF -%DIF UNDERLINE PREAMBLE %DIF PREAMBLE -\RequirePackage[normalem]{ulem} %DIF PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} %DIF PREAMBLE -\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}} %DIF PREAMBLE -\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}} %DIF PREAMBLE -%DIF SAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddbegin}{} %DIF PREAMBLE -\providecommand{\DIFaddend}{} %DIF PREAMBLE -\providecommand{\DIFdelbegin}{} %DIF PREAMBLE -\providecommand{\DIFdelend}{} %DIF PREAMBLE -%DIF FLOATSAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} %DIF PREAMBLE -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} %DIF PREAMBLE -\providecommand{\DIFaddbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFaddendFL}{} %DIF PREAMBLE -\providecommand{\DIFdelbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFdelendFL}{} %DIF PREAMBLE -%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of \DIFaddbegin \DIFadd{the }\DIFaddend latexdiff features. -Type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -or -\begin{verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{verbatim} -to display the markup. - -\section*{\DIFdelbegin \DIFdel{Another }\DIFdelend \DIFaddbegin \DIFadd{Yet another }\DIFaddend section title} - - \DIFdelbegin \DIFdel{A paragraph with a line only in the draft document. }\DIFdelend More things could be said were it not for the constraints of time and space. - -\DIFaddbegin \DIFadd{A paragraph with a line only in the revised document. }\DIFaddend More things could be -said were it not for the constraints of time and space. - -And here is a \DIFdelbegin \DIFdel{tipo}\DIFdelend \DIFaddbegin \DIFadd{typo}\DIFaddend . - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & \DIFdelbegin \DIFdel{Grey }\DIFdelend \DIFaddbegin \DIFadd{White }\DIFaddend \\ -Saruman & \DIFdelbegin \DIFdel{White -}\DIFdelend \DIFaddbegin \DIFadd{Evil -}\DIFaddend \end{tabular} - -And \DIFdelbegin \DIFdel{sometimes a whole paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}\DIFdelend \DIFaddbegin \DIFadd{now for something completely different, with not a paragraph in sight}\DIFaddend . -No change, -no markup! -\end{document} - - diff --git a/latexdiff-1.0.2/doc/latexdiff-man.tex b/latexdiff-1.0.2/doc/latexdiff-man.tex deleted file mode 100644 index b6bb37e..0000000 --- a/latexdiff-1.0.2/doc/latexdiff-man.tex +++ /dev/null @@ -1,355 +0,0 @@ -\documentclass[a4]{article} -\usepackage{graphicx} -%\def\C++{{\rm C\kern-.05em\raise.3ex\hbox{\footnotesize ++}}} -%\def\underscore{\leavevmode\kern.04em\vbox{\hrule width 0.4em height 0.3pt}} -\setlength{\parindent}{0pt} -%\setlength{\textwidth}{6.5in} -%\setlength{\oddsidemargin}{0.0in} -\title{Marking up differences between latex files with {\em latexdiff}} -\author{F.J. Tilmann\thanks{tilmann@gfz-potsdam.de,ftilmann@users.berlios.de}} -\date{\today} - -\begin{document} -\maketitle - -\section*{Preamble} - -{\em latexdiff} is a Perl script, which compares two -latex files and marks up significant differences between them. Various options are available for visual markup using standard -latex packages such as {\em color.sty}. Changes not directly affecting visible -text, for example in formatting commands, are still marked in the -latex source. - -A rudimentary revision facilility is provided by another Perl script, -{\em latexrevise}, which accepts or rejects all changes. Manual editing -of the difference file can be used to override this default behaviour -and accept or reject selected changes only. - -There is no explicit support for annotations as these are trivial to implement. -For example, I include the following command definition in the preamble -\begin{verbatim} -\newcommand{\remark}[1]{{ \bf [ \footnotesize #1 ]}} -\end{verbatim} -and mark up annotations as follows -\begin{verbatim} -... The roadrunner is the fastest running bird \remark{Check this -again with a zoologist!}. The most famous roadrunner ... -\end{verbatim} -Alternatively, instead of a command like \verb#\remark# in the example just given, an -equivalent annotation environment could be defined. -{\em latexrevise} can remove such comments or -environments from the text body. - -%It is planned that the revision capabilities of this system will be -%further expanded, dependent on the amount of feedback received. - -On the following pages you find the {\em man} pages for {\em - latexdiff} and {\em latexrevise} and a simple example. - -\include{latexdiff} -\setcounter{section}{0} - -\include{latexrevise} -\setcounter{section}{0} - -\include{latexdiff-vc} -\setcounter{section}{0} - -\section*{A simple example} - -We start with a draft text, \verb|example-draft.tex|, listed here in -full but also included in the distribution (except that the ``verbatim'' environment had -to be renamed to ``Verbatim'' for the listing). - -{\scriptsize -\begin{verbatim} -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6.5in} - -\title{latexdiff Example - Draft version} -\author{F Tilmann} - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of latexdiff features. -Type -\begin{Verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{Verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{Verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{Verbatim} -or -\begin{Verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{Verbatim} -to display the markup. Of course, instead of \verb|xpdf| you can use -\verb|okular, evince, acroread| or any other pdf or postscript viewer. - -\section*{Another section title} - -A paragraph with a line only in the draft document. More things -could be said were it not for the constraints of time and space. - -More things could be said were it not for the constraints of time and space. - -And here is a tipo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & Grey \\ -Saruman & White -\end{tabular} - -And sometimes a whole paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical. -No change, no markup! -\end{document} -\end{verbatim} -} - -We can now edit -this text as we would do with any other latex file to create -a new revision of the text, \verb|example-rev.tex|. We should run -\begin{verbatim} -latex example-rev.tex -\end{verbatim} -and look at the resulting \verb|.dvi| file to make sure that all -changes are valid. An example revision is listed here: - -{\scriptsize -\begin{verbatim} -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6in} - -\title{latexdiff Example - Revised version} -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even -% if some preamble might eventually end up as visible text.) - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of the latexdiff features. -Type -\begin{Verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{Verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{Verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{Verbatim} -or -\begin{Verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{Verbatim} -to display the markup. - -\section*{Yet another section title} - - More things could be said were it not for the constraints of time and space. - -A paragraph with a line only in the revised document. -More things could be said were it not for the constraints of time and space. - -And here is a typo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & White \\ -Saruman & Evil -\end{tabular} - -And now for something completely different, with not a paragraph in sight. -No change, -no markup! -\end{document} -\end{verbatim} -} - -To compare both revisions, type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -This results in the following difference file (a few newlines have been -added in this listing for legibility reasosn): -{\scriptsize -\begin{verbatim} -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -%DIF 7c7 -%DIF < \setlength{\textwidth}{6.5in} -%DIF ------- -\setlength{\textwidth}{6in} %DIF > -%DIF ------- - -%DIF 9c9 -%DIF < \title{latexdiff Example - Draft version} -%DIF ------- -\title{latexdiff Example - Revised version} %DIF > -%DIF ------- -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even %DIF > -% if some preamble might eventually end up as visible text.) %DIF > -%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF -%DIF UNDERLINE PREAMBLE %DIF PREAMBLE -\RequirePackage[normalem]{ulem} %DIF PREAMBLE -\RequirePackage{color} %DIF PREAMBLE -\providecommand{\DIFadd}[1]{{\color{blue}\uline{#1}}} %DIF PREAMBLE -\providecommand{\DIFdel}[1]{{\color{red}\sout{#1}}} %DIF PREAMBLE -%DIF SAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddbegin}{} %DIF PREAMBLE -\providecommand{\DIFaddend}{} %DIF PREAMBLE -\providecommand{\DIFdelbegin}{} %DIF PREAMBLE -\providecommand{\DIFdelend}{} %DIF PREAMBLE -%DIF FLOATSAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} %DIF PREAMBLE -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} %DIF PREAMBLE -\providecommand{\DIFaddbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFaddendFL}{} %DIF PREAMBLE -\providecommand{\DIFdelbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFdelendFL}{} %DIF PREAMBLE -%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of latexdiff features. -Type -\begin{Verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{Verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{Verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{Verbatim} -or -\begin{Verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{Verbatim} -to display the markup. - -\section*{\DIFaddbegin \DIFadd{Yet another }\DIFaddend \DIFdelbegin -\DIFdel{Another }\DIFdelend section title} - - \DIFdelbegin \DIFdel{A paragraph with a line only in the draft - document. }\DIFdelend More things could - be said were it not for the constraints of time and space. - -\DIFaddbegin \DIFadd{A paragraph with a line only in the revised - document. }\DIFaddend More things could be said -were it not for the constraints of time and space. - -And here is a \DIFaddbegin \DIFadd{typo}\DIFaddend \DIFdelbegin -\DIFdel{tipo}\DIFdelend . - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & \DIFaddbegin \DIFadd{White }\DIFaddend \DIFdelbegin -\DIFdel{Grey }\DIFdelend \\ -Saruman & \DIFaddbegin \DIFadd{Evil -}\DIFaddend \DIFdelbegin \DIFdel{White -}\DIFdelend \end{tabular} - -And \DIFaddbegin \DIFadd{now for something completely different, with not - a paragraph in sight}\DIFaddend \DIFdelbegin \DIFdel{sometimes a whole - paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}\DIFdelend . -No change, -no markup! -\end{document} -\end{verbatim} -} -Type -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -to make the markup visible. This is what it looks like: - -\vspace{1cm} -\framebox[\textwidth]{\includegraphics[width=\textwidth]{example-diff}} -\vspace{1cm} - -If you approve of all the changes in the revision, just continue with -\verb|example-rev.tex| for the next revision. If you like to adopt -most but not all changes you can use \verb|latexrevise| in the -following manner. Simply remove the \verb|\DIFdelbegin| and -\verb|\DIFdelend| tags around the text you would like to keep and -simply remove the text between \verb|\DIFaddbegin| and -\verb|\DIFaddend| tags, if you do not wish to keep them. Say you are happy with all proposed changes for the -example above except in -the last paragraph where you prefer the original draft. You have -to change - -{\scriptsize -\begin{verbatim} -... -And \DIFaddbegin \DIFadd{now for something completely different, with not - a paragraph in sight}\DIFaddend \DIFdelbegin \DIFdel{sometimes a whole - paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}\DIFdelend . -... -\end{verbatim} -} -into -{\scriptsize -\begin{verbatim} -... -And \DIFdel{sometimes a whole - paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}. -... -\end{verbatim} -} -and run -\begin{verbatim} -latexrevise -a example-rev.tex > example-final.tex -\end{verbatim} -\verb|example-final.tex| is then almost identical to -\verb|example-rev.tex| except for the last paragraph. -\end{document} diff --git a/latexdiff-1.0.2/example/example-draft.tex b/latexdiff-1.0.2/example/example-draft.tex deleted file mode 100644 index 593a170..0000000 --- a/latexdiff-1.0.2/example/example-draft.tex +++ /dev/null @@ -1,59 +0,0 @@ -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6.5in} - -\title{latexdiff Example - Draft version} -\author{F Tilmann} - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of latexdiff features. -Type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -or -\begin{verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{verbatim} -to display the markup. - -\section*{Another section title} - -A paragraph with a line only in the draft document. More things could be said -were it not for the constraints of time and space. - -More things could be said were it not for the constraints of time and space. - -And here is a tipo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & Grey \\ -Saruman & White -\end{tabular} - -And sometimes a whole paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical. -No change, no markup! -\end{document} - - diff --git a/latexdiff-1.0.2/example/example-rev.tex b/latexdiff-1.0.2/example/example-rev.tex deleted file mode 100644 index 4bcaf15..0000000 --- a/latexdiff-1.0.2/example/example-rev.tex +++ /dev/null @@ -1,60 +0,0 @@ -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6in} - -\title{latexdiff Example - Revised version} -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even -% if some preamble might eventually end up as visible text.) - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of the latexdiff features. -Type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -or -\begin{verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{verbatim} -to display the markup. - -\section*{Yet another section title} - - More things could be said were it not for the constraints of time and space. - -A paragraph with a line only in the revised document. More things could be -said were it not for the constraints of time and space. - -And here is a typo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & White \\ -Saruman & Evil -\end{tabular} - -And now for something completely different, with not a paragraph in sight. -No change, -no markup! -\end{document} - - diff --git a/latexdiff-1.0.2/latexdiff b/latexdiff-1.0.2/latexdiff deleted file mode 100755 index 7075561..0000000 --- a/latexdiff-1.0.2/latexdiff +++ /dev/null @@ -1,3400 +0,0 @@ -#!/usr/bin/env perl -##!/usr/bin/perl -w -# latexdiff - differences two latex files on the word level -# and produces a latex file with the differences marked up. -# -# Copyright (C) 2004-12 F J Tilmann (tilmann@gfz-potsdam.de, ftilmann@users.berlios.de) -# -# Project webpages: http://latexdiff.berlios.de/ -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# -# Version 1.0.1 - treat \big,\bigg etc. equivalently to \left and -# \right - include starred version in MATHENV - apply -# - flatten recursively and --flatten expansion is now -# aware of comments (thanks to Tim Connors for patch) -# - Change to post-processing for more reliability for -# deleted math environments -# - On linux systems, recognise and remove DOS style newlines -# - Provide markup for some special preamble commands (\title, -# \author,\date, -# - configurable by setting context2cmd -# - for styles using ulem package, remove \emph and \text.. from list of -# safe commands in order to allow linebreaks within the -# highlighted sections. -# - for ulem style, now show citations by enclosing them in \mbox commands. -# This unfortunately implies linebreaks within citations no longer function, -# so this functionality can be turned off (Option --disable-citation-markup). -# With --enable-citation-markup, the mbox markup is forced for other styles) -# - new substyle COLOR. This is particularly useful for marking up citations -# and some special post-processing is implemented to retain cite -# commands in deleted blocks. -# - four different levels of math-markup -# - Option --driver for choosing driver for modes employing changebar package -# - accept \\* as valid command (and other commands of form \.*). Also accept -# \ (backslashed newline) -# - some typo fixes, include commands defined in preamble as safe commands -# (Sebastian Gouezel) -# - include compared filenames as comments as line 2 and 3 of -# the preamble (can be modified with option --label, and suppressed with -# --no-label), option --visible-label to show files in generated pdf or dvi -# at the beginning of main document -# -# Version 0.5 A number of minor improvements based on feedback -# Deleted blocks are now shown before added blocks -# Package specific processing -# -# Version 0.43 unreleased typo in list of styles at the end -# Add protect to all \cbstart, \cbend commands -# More robust substitution of deleted math commands -# -# Version 0.42 November 06 Bug fixes only -# -# Version 0.4 March 06 option for fast differencing using UNIX diff command, several minor bug fixes (\par bug, improved highlighting of textcmds) -# -# Version 0.3 August 05 improved parsing of displayed math, --allow-spaces -# option, several minor bug fixes -# -# Version 0.25 October 04 Fix bug with deleted equations, add math mode commands to safecmd, add | to allowed interpunctuation signs -# Version 0.2 September 04 extension to utf-8 and variable encodings -# Version 0.1 August 04 First public release - -use Algorithm::Diff qw(traverse_sequences); - -use Getopt::Long ; -use strict ; -use warnings; -use utf8 ; - -my ($algodiffversion)=split(/ /,$Algorithm::Diff::VERSION); - - -my ($versionstring)=< 0, - WHOLE => 1, - COARSE => 2, - FINE => 3 -}; - - -my (@configlist,@labels, - @appendsafelist,@excludesafelist, - @appendtextlist,@excludetextlist, - @appendcontext1list,@appendcontext2list, - @packagelist); -my ($assign,@config); -# Hash where keys corresponds to the names of all included packages (including the documentclass as another package -# the optional arguments to the package are the values of the hash elements -my ($pkg,%packages); -# Defaults -$type='UNDERLINE'; -$subtype='SAFE'; -$floattype='FLOATSAFE'; -$mathmarkup=COARSE; - -$verbose=0; -# output debug and intermediate files, set to 0 in final distribution -$debug=0; -# define character properties -sub IsNonAsciiPunct { return <<'END' # Unicode punctuation but excluding ASCII punctuation -+utf8::IsPunct --utf8::IsASCII -END -} -sub IsNonAsciiS { return <<'END' # Unicode symbol but excluding ASCII -+utf8::IsS --utf8::IsASCII -END -} - - -my %verbhash; - -Getopt::Long::Configure('bundling'); -GetOptions('type|t=s' => \$type, - 'subtype|s=s' => \$subtype, - 'floattype|f=s' => \$floattype, - 'config|c=s' => \@configlist, - 'preamble|p=s' => \$preamblefile, - 'encoding|e=s' => \$encoding, - 'label|L=s' => \@labels, - 'no-label' => \$nolabel, - 'visible-label' => \$visiblelabel, - 'exclude-safecmd|A=s' => \@excludesafelist, - 'replace-safecmd=s' => \$replacesafe, - 'append-safecmd|a=s' => \@appendsafelist, - 'exclude-textcmd|X=s' => \@excludetextlist, - 'replace-textcmd=s' => \$replacetext, - 'append-textcmd|x=s' => \@appendtextlist, - 'replace-context1cmd=s' => \$replacecontext1, - 'append-context1cmd=s' => \@appendcontext1list, - 'replace-context2cmd=s' => \$replacecontext2, - 'append-context2cmd=s' => \@appendcontext2list, - 'show-preamble' => \$showpreamble, - 'show-safecmd' => \$showsafe, - 'show-textcmd' => \$showtext, - 'show-config' => \$showconfig, - 'show-all' => \$showall, - 'packages=s' => \@packagelist, - 'allow-spaces' => \$allowspaces, - 'math-markup=s' => \$mathmarkup, - 'enable-citation-markup' => \$enablecitmark, - 'disable-citation-markup' => \$disablecitmark, - 'verbose|V' => \$verbose, - 'ignore-warnings' => \$ignorewarnings, - 'driver=s'=> \$driver, - 'flatten' => \$flatten, - 'version' => \$version, - 'help|h|H' => \$help); - -if ( $help ) { - usage() ; -} - - -if ( $version ) { - die $versionstring ; -} - -print STDERR $versionstring if $verbose; - -if (defined($showall)){ - $showpreamble=$showsafe=$showtext=$showconfig=1; -} - -if (defined($mathmarkup)) { - $mathmarkup=~tr/a-z/A-Z/; - if ( $mathmarkup eq 'OFF' ){ - $mathmarkup=OFF; - } elsif ( $mathmarkup eq 'WHOLE' ){ - $mathmarkup=WHOLE; - } elsif ( $mathmarkup eq 'COARSE' ){ - $mathmarkup=COARSE; - } elsif ( $mathmarkup eq 'FINE' ){ - $mathmarkup=FINE; - } elsif ( $mathmarkup !~ m/^[0123]$/ ) { - die "Illegal value: ($mathmarkup) for option--math-markup. Possible values: OFF,WHOLE,COARSE,FINE,0- "; - } - # else use numerical value -} - -# setting extra preamble commands -if (defined($preamblefile)) { - $latexdiffpreamble=join "\n",(extrapream($preamblefile),""); -} else { - $latexdiffpreamble=join "\n",(extrapream($type,$subtype,$floattype),""); -} - -if ( defined($driver) ) { - # for changebar only - $latexdiffpreamble=~s/\[dvips\]/[$driver]/sg; -} -# setting up @SAFECMDLIST and @SAFECMDEXCL -if (defined($replacesafe)) { - init_regex_arr_ext(\@SAFECMDLIST,$replacesafe); -} else { - init_regex_arr_data(\@SAFECMDLIST, "SAFE COMMANDS"); -} -foreach $appendsafe ( @appendsafelist ) { - init_regex_arr_ext(\@SAFECMDLIST, $appendsafe); -} -foreach $excludesafe ( @excludesafelist ) { - init_regex_arr_ext(\@SAFECMDEXCL, $excludesafe); -} - -# Special: treat all cite commands as safe except in UNDERLINE and FONTSTRIKE mode -# (there is a conflict between citation and ulem package, see -# package documentation) -# Use post-processing - -if ( uc($type) ne "UNDERLINE" && uc($type) ne "FONTSTRIKE" && uc($type) ne "CULINECHBAR" ) { - push (@SAFECMDLIST, qr/^cite.*$/); -} else { - ### Experimental: disable text and emph commands - push (@SAFECMDLIST, qr/^cite.*$/) unless $disablecitmark; - push(@SAFECMDEXCL, qr/^emph$/, qr/^text..$/); - # replace \cite{..} by \mbox{\cite{..}} in added or deleted blocks in post-processing - if ( uc($subtype) eq "COLOR" or uc($subtype) eq "DVIPSCOL" ) { - # remove \cite command again from list of safe commands - pop @SAFECMDLIST; - # deleted cite commands - $CITE2CMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite-type commands which should be reinstated in deleted blocks - } else { - $CITECMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite commands which need to be protected within an mbox in UNDERLINE and other modes using ulem - } -} -$CITECMD='(?:cite\w*|nocite)' if $enablecitmark ; # as above for explicit selection - -# setting up @TEXTCMDLIST and @TEXTCMDEXCL -if (defined($replacetext)) { - init_regex_arr_ext(\@TEXTCMDLIST,$replacetext); -} else { - init_regex_arr_data(\@TEXTCMDLIST, "TEXT COMMANDS"); -} -foreach $appendtext ( @appendtextlist ) { - init_regex_arr_ext(\@TEXTCMDLIST, $appendtext); -} -foreach $excludetext ( @excludetextlist ) { - init_regex_arr_ext(\@TEXTCMDEXCL, $excludetext); -} - - -# setting up @CONTEXT1CMDLIST ( @CONTEXT1CMDEXCL exist but is always empty ) -if (defined($replacecontext1)) { - init_regex_arr_ext(\@CONTEXT1CMDLIST,$replacecontext1); -} else { - init_regex_arr_data(\@CONTEXT1CMDLIST, "CONTEXT1 COMMANDS"); -} -foreach $appendcontext1 ( @appendcontext1list ) { - init_regex_arr_ext(\@CONTEXT1CMDLIST, $appendcontext1); -} - - -# setting up @CONTEXT2CMDLIST ( @CONTEXT2CMDEXCL exist but is always empty ) -if (defined($replacecontext2)) { - init_regex_arr_ext(\@CONTEXT2CMDLIST,$replacecontext2); -} else { - init_regex_arr_data(\@CONTEXT2CMDLIST, "CONTEXT2 COMMANDS"); -} -foreach $appendcontext2 ( @appendcontext2list ) { - init_regex_arr_ext(\@CONTEXT2CMDLIST, $appendcontext2); -} - -# setting configuration variables -@config=(); -foreach $config ( @configlist ) { - if (-f $config ) { - open(FILE,$config) or die ("Couldn't open configuration file $config: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@config,$_); - } - close(FILE); - } - else { -# foreach ( split(",",$config) ) { -# push @config,$_; -# } - push @config,split(",",$config) - } -} -foreach $assign ( @config ) { - $assign=~ m/\s*(\w*)\s*=\s*(\S*)\s*$/ or die "Illegal assignment $assign in configuration list (must be variable=value)"; - if ( $1 eq "MINWORDSBLOCK" ) { $MINWORDSBLOCK = $2; } - elsif ( $1 eq "FLOATENV" ) { $FLOATENV = $2 ; } - elsif ( $1 eq "PICTUREENV" ) { $PICTUREENV = $2 ; } - elsif ( $1 eq "MATHENV" ) { $MATHENV = $2 ; } - elsif ( $1 eq "MATHREPL" ) { $MATHREPL = $2 ; } - elsif ( $1 eq "MATHARRENV" ) { $MATHARRENV = $2 ; } - elsif ( $1 eq "MATHARRREPL" ) { $MATHARRREPL = $2 ; } - elsif ( $1 eq "ARRENV" ) { $ARRENV = $2 ; } - elsif ( $1 eq "COUNTERCMD" ) { $COUNTERCMD = $2 ; } - else { die "Unknown variable $1 in assignment.";} -} - -if ( $mathmarkup == COARSE || $mathmarkup == WHOLE ) { - push(@MATHTEXTCMDLIST,qr/^MATHBLOCK(?:$MATHENV|$MATHARRENV|SQUAREBRACKET)$/); -} - - - -foreach $pkg ( @packagelist ) { - map { $packages{$_}="" } split(/,/,$pkg) ; -} - -if ($showpreamble) { - print "\nPreamble commands:\n"; - print $latexdiffpreamble ; -} - -if ($showsafe) { - print "\nCommands safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE (unless excluded):\n"; - print_regex_arr(@SAFECMDLIST); - print "\nCommands not safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE :\n"; - print_regex_arr(@SAFECMDEXCL); -} - -if ($showtext) { - print "\nCommands with last argument textual (unless excluded) and safe in every context:\n"; - print_regex_arr(@TEXTCMDLIST); - print "\nContext1 commands (last argument textual, command will be disabled in deleted passages, last argument will be shown as plain text):\n"; - print_regex_arr(@CONTEXT1CMDLIST); - print "\nContext2 commands (last argument textual, command and its argument will be disabled in deleted passages):\n"; - print_regex_arr(@CONTEXT2CMDLIST); - print "\nExclude list of Commands with last argument not textual (overrides patterns above):\n"; - print_regex_arr(@TEXTCMDEXCL); -} - - -if ($showconfig) { - print "Configuration variables:\n"; - print "MINWORDSBLOCK=$MINWORDSBLOCK\n"; - print "FLOATENV=$FLOATENV\n"; - print "PICTUREENV=$PICTUREENV\n"; - print "MATHENV=$MATHENV\n"; - print "MATHREPL=$MATHREPL\n"; - print "MATHARRENV=$MATHARRENV\n"; - print "MATHARRREPL=$MATHARRREPL\n"; - print "ARRENV=$ARRENV\n"; - print "COUNTERCMD=$COUNTERCMD\n"; -} -if ($showconfig || $showtext || $showsafe || $showpreamble) { - exit 0; } -if ( @ARGV != 2 ) { - print STDERR "2 and only 2 non-option arguments required. Write latexdiff -h to get help\n"; - exit(2); -} - -# Are extra spaces between command arguments permissible? -my $extraspace; -if ($allowspaces) { - $extraspace='\s*'; -} else { - $extraspace=''; -} - -# append context lists to text lists (as text property is implied) -push @TEXTCMDLIST, @CONTEXT1CMDLIST; -push @TEXTCMDLIST, @CONTEXT2CMDLIST; - -push @TEXTCMDLIST, @MATHTEXTCMDLIST if $mathmarkup==COARSE; - -# internal additions to SAFECMDLIST -push(@SAFECMDLIST, qr/^QLEFTBRACE$/, qr/^QRIGHTBRACE$/); - - -# Patterns. These are used by some of the subroutines, too -# I can only define them down here because value of extraspace depends on an option - my $pat0 = '(?:[^{}])*'; - my $pat1 = '(?:[^{}]|\{'.$pat0.'\})*'; - my $pat2 = '(?:[^{}]|\{'.$pat1.'\})*'; - my $pat3 = '(?:[^{}]|\{'.$pat2.'\})*'; - my $pat4 = '(?:[^{}]|\{'.$pat3.'\})*'; - my $pat5 = '(?:[^{}]|\{'.$pat4.'\})*'; - my $pat6 = '(?:[^{}]|\{'.$pat5.'\})*'; - my $brat0 = '(?:[^\[\]]|\\\[|\\\])*'; - - my $quotemarks = '(?:\'\')|(?:\`\`)'; - my $punct='[0.,\/\'\`:;\"\?\(\)\[\]!~\p{IsNonAsciiPunct}\p{IsNonAsciiS}]'; - my $number='-?\d*\.\d*'; - my $mathpunct='[+=<>\-\|]'; - my $and = '&'; - my $coords= '[\-.,\s\d]*'; -# word: sequence of letters or accents followed by letter - my $word='(?:[-\w\d*]|\\\\[\"\'\`~^][A-Za-z\*])+'; - my $cmdleftright='\\\\(?:left|right|[Bb]igg?[lrm]?|middle)\s*(?:[()\[\]|]|\\\\(?:[|{}]|\w+))'; - - my $cmdoptseq='\\\\[\w\d\*]+'.$extraspace.'(?:(?:\['.$brat0.'\]|\{'. $pat6 . '\}|\(' . $coords .'\))'.$extraspace.')*'; - my $backslashnl='\\\\\n'; - my $oneletcmd='\\\\.\*?(?:\['.$brat0.'\]|\{'. $pat6 . '\})*'; - my $math='\$(?:[^$]|\\\$)*?\$|\\\\[(].*?\\\\[)]'; -## the current maths command cannot cope with newline within the math expression - - my $comment='%.*?\n'; - my $pat=qr/(?:\A\s*)?(?:${and}|${quotemarks}|${number}|${word}|$cmdleftright|${cmdoptseq}|${math}|${backslashnl}|${oneletcmd}|${comment}|${punct}|${mathpunct}|\{|\})\s*/ ; - - - -# now we are done setting up and can start working -my ($oldfile, $newfile) = @ARGV; -# check for existence of input files -if ( ! -e $oldfile ) { - die "Input file $oldfile does not exist."; -} -if ( ! -e $newfile ) { - die "Input file $newfile does not exist."; -} - - -# set the labels to be included into the file -my ($oldtime,$newtime,$oldlabel,$newlabel); -if (defined($labels[0])) { - $oldlabel=$labels[0] ; -} else { - $oldtime=localtime((stat($oldfile))[9]); - $oldlabel="$oldfile " . " "x(length($newfile)-length($oldfile)) . $oldtime; -} -if (defined($labels[1])) { - $newlabel=$labels[1] ; -} else { - $newtime=localtime((stat($newfile))[9]); - $newlabel="$newfile " . " "x(length($oldfile)-length($newfile)) . $newtime; -} - -$encoding=guess_encoding($newfile) unless defined($encoding); - -$encoding = "utf8" if $encoding =~ m/^utf8/i ; -if (lc($encoding) eq "utf8" ) { - binmode(STDOUT, ":utf8"); - binmode(STDERR, ":utf8"); -} - -$old=read_file_with_encoding($oldfile,$encoding); -$new=read_file_with_encoding($newfile,$encoding); - - - - -# reset time -exetime(1); -($oldpreamble,$oldbody,$oldpost)=splitdoc($old,'\\\\begin\{document\}','\\\\end\{document\}'); - - -($newpreamble,$newbody,$newpost)=splitdoc($new,'\\\\begin\{document\}','\\\\end\{document\}'); - - -if ($flatten) { - $oldbody=flatten($oldbody,$oldpreamble,$oldfile,$encoding); - $newbody=flatten($newbody,$newpreamble,$newfile,$encoding); -} - -my @auxlines; -if ( length $oldpreamble && length $newpreamble ) { - # pre-process preamble by looking for commands used in \maketitle (title, author, date etc commands) - # and marking up content with latexdiff markup - @auxlines=preprocess_preamble($oldpreamble,$newpreamble); - - @oldpreamble = split /\n/, $oldpreamble; - @newpreamble = split /\n/, $newpreamble; - - # If a command is defined in the preamble of the new file, and only uses safe commands, then it can be considered to be safe) (contribution S. Gouezel) - # Base this assessment on the new preamble - add_safe_commands($newpreamble); - - %packages=list_packages(@newpreamble) unless %packages; - if (defined $packages{"hyperref"} ) { - print STDERR "hyperref package detected.\n" if $verbose ; - $latexdiffpreamble =~ s/\{\\DIFadd\}/{\\DIFaddtex}/g; - $latexdiffpreamble =~ s/\{\\DIFdel\}/{\\DIFdeltex}/g; - $latexdiffpreamble .= join "\n",(extrapream("HYPERREF"),""); - } - print STDERR "Differencing preamble.\n" if $verbose; - - # insert dummy first line such that line count begins with line 1 (rather than perl's line 0) - just so that line numbers inserted by linediff are correct - unshift @newpreamble,''; - unshift @oldpreamble,''; - @diffpreamble = linediff(\@oldpreamble, \@newpreamble); - # remove dummy line again - shift @diffpreamble; - # add filenames, modification time and latexdiff mark - defined($nolabel) or splice @diffpreamble,1,0, - "%DIF LATEXDIFF DIFFERENCE FILE", - ,"%DIF DEL $oldlabel", - "%DIF ADD $newlabel"; - if ( @auxlines ) { - push @diffpreamble,"%DIF DELETED TITLE COMMANDS FOR MARKUP"; - push @diffpreamble,join("\n",@auxlines); - } - push @diffpreamble,$latexdiffpreamble; - push @diffpreamble,'\begin{document}'; -} -elsif ( !length $oldpreamble && !length $newpreamble ) { - @diffpreamble=(); -} else { - print STDERR "Either both texts must have preamble or neither text must have the preamble.\n"; - exit(2); -} - -if (defined $packages{"amsmath"} or defined $packages{"amsart"} or defined $packages{"amsbook"} ) { - print STDERR "amsmath package detected.\n" if $verbose ; - $MATHARRREPL='align*'; -} - -print STDERR "Preprocessing body. " if $verbose; -my ($oldleadin,$newleadin)=preprocess($oldbody,$newbody); - - -# run difference algorithm -@diffbody=bodydiff($oldbody, $newbody); -$diffbo=join("",@diffbody); -if ( $debug ) { - open(RAWDIFF,">","latexdiff.debug.bodydiff"); - print RAWDIFF $diffbo; - close(RAWDIFF); -} -print STDERR "(",exetime()," s)\n","Postprocessing body. \n " if $verbose; -postprocess($diffbo); -$diffall =join("\n",@diffpreamble) ; -# add visible labels -if (defined($visiblelabel)) { - # Give information right after \begin{document} (or at the beginning of the text for files without preamble - ### if \date command is used, add information to \date argument, otherwise give right after \begin{document} - ### $diffall=~s/(\\date$extraspace(?:\[$brat0\])?$extraspace)\{($pat6)\}/$1\{$2 \\ LATEXDIFF comparison \\ Old: $oldlabel \\ New: $newlabel \}/ or - $diffbo = "\\begin{verbatim}LATEXDIFF comparison\nOld: $oldlabel\nNew: $newlabel\\end{verbatim}\n$diffbo" ; -} - -$diffall .= "$newleadin$diffbo" ; -$diffall .= "\\end{document}$newpost" if length $newpreamble ; -if ( lc($encoding) ne "utf8" && lc($encoding) ne "ascii" ) { - print STDERR "Encoding output file to $encoding\n" if $verbose; - $diffall=Encode::encode($encoding,$diffall); - binmode STDOUT; -} -print $diffall; - - -print STDERR "(",exetime()," s)\n","Done.\n" if $verbose; - - - -## guess_encoding(filename) -## reads the first 20 lines of filename and looks for call of inputenc package -## if found, return the option of this package (encoding), otherwise return ascii -sub guess_encoding { - my ($filename)=@_; - my ($i,$enc); - open (FH, $filename) or die("Couldn't open $filename: $!"); - $i=0; - while () { - next if /^\s*%/; # skip comment lines - if (m/\\usepackage\[(\w*?)\]\{inputenc\}/) { - close(FH); - return($1); - } - last if (++$i > 20 ); # scan at most 20 non-comment lines - } - close(FH); - return("ascii"); -} - - -sub read_file_with_encoding { - my ($output); - my ($filename, $encoding) = @_; - - if (lc($encoding) eq "utf8" ) { - open (FILE, "<:utf8",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } elsif ( lc($encoding) eq "ascii") { - open (FILE, $filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } else { - require Encode; - open (FILE, "<",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - print STDERR "Converting $filename from $encoding to utf8\n" if $verbose; - $output=Encode::decode($encoding,$output); - } - close FILE; - if ($^O eq "linux" ) { - $output =~ s/\r\n/\n/g ; - } - return $output; -} - -# %packages=list_packages(@preamble) -# scans the arguments for \documentclass and \usepackage statements and constructs a hash -# whose keys are the included packages, and whose values are the associated optional arguments -sub list_packages { - my (@preamble)=@_; - my %packages=(); - foreach $line ( @preamble ) { - # get rid of comments - $line=~s/(?catfile($dirname,$fname), "\n" if $debug; - # content of file becomes replacement value (use recursion), add \newpage if the command was include - ###$replacement=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - $replacement=flatten(read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding), $preamble,$filename,$encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - # \include always starts a new page; use explicit \newpage command to simulate this - $begline=(defined($1)? $1 : "") ; - $newpage=(defined($3)? " \\newpage " : "") ; - "$begline$newpage$replacement$newpage"; - }/exgm; - - return($text); -} - - -# print_regex_arr(@arr) -# prints regex array without x-ism expansion put in by pearl to stdout -sub print_regex_arr { - my $dumstring; - $dumstring = join(" ",@_); # PERL generates string (?-xism:^ref$) for quoted refex ^ref$ - $dumstring =~ s/\(\?-xism:\^(.*?)\$\)/$1/g; # remove string and ^,$ marks before output - print $dumstring,"\n"; -} - - -# @lines=extrapream($type) -# reads line from appendix (end of file after __END__ token) -sub extrapream { - my $type; - my @retval=("%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - my ($copy); - - while (@_) { - $copy=0; - $type=shift ; - if ( -f $type ) { - open (FILE,$type) or die "Cannot open preamble file $type: $!"; - print STDERR "Reading preamble file $type\n" if $verbose ; - while () { - chomp ; - if ( $_ =~ m/%DIF PREAMBLE/ ) { - push (@retval,"$_"); - } else { - push (@retval,"$_ %DIF PREAMBLE"); - } - } - } - else { # not (-f $type) - $type=uc($type); # upcase argument - print STDERR "Preamble Internal Type $type\n" if $verbose; - while () { - if ( m/^%DIF $type/ ) { - $copy=1; } - elsif ( m/^%DIF END $type/ ) { - last; } - chomp; - push (@retval,"$_ %DIF PREAMBLE") if $copy; - } - if ( $copy == 0 ) { - print STDERR "\nPreamble style $type not implemented.\n"; - print STDERR "Write latexdiff -h to get help with available styles\n"; - exit(2); - } - seek DATA,0,0; # rewind DATA handle to file begin - } - } - push (@retval,"%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - return @retval; -} - - -# ($part1,$part2,$part3)=splitdoc($text,$word1,$word2) -# splits $text into 3 parts at $word1 and $word2. -# if neither $word1 nor $word2 exist, $part1 and $part3 are empty, $part2 is $text -# If only $word1 or $word2 exist but not the other, output an error message. - -# NB this version avoids $` and $' for performance reason although it only makes a tiny difference -# (in one test gain a tenth of a second for a 30s run) -sub splitdoc { - my ($text,$word1,$word2)=@_; - my ($part1,$part2,$part3)=("","",""); - my ($rest,$pos); - - if ( $text =~ m/(^[^%]*)($word1)/mg ) { - $pos=pos $text; - $part1=substr($text,0,$pos-length($2)); - $rest=substr($text,$pos); - if ( $rest =~ m/(^[^%]*)($word2)/mg ) { - $pos=pos $rest; - $part2=substr($rest,0,$pos-length($2)); - $part3=substr($rest,$pos); - } - else { - die "$word1 and $word2 not in the correct order or not present as a pair." ; - } - } else { - $part2=$text; - die "$word2 present but not $word1." if ( $text =~ m/(^[^%]*)$word2/ms ); - } - return ($part1,$part2,$part3); -} - - - - - -# bodydiff($old,$new) -sub bodydiff { - my ($oldwords, $newwords) = @_; - my @retwords; - - print STDERR "(",exetime()," s)\n","Splitting into latex tokens \n" if $verbose; - print STDERR "Parsing $oldfile \n" if $verbose; - my @oldwords = splitlatex($oldwords); - print STDERR "Parsing $newfile \n" if $verbose; - my @newwords = splitlatex($newwords); - - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - print STDERR "(",exetime()," s)\n","Pass 1: Expanding text commands and merging isolated identities with changed blocks " if $verbose; - pass1(\@oldwords, \@newwords); - - - print STDERR "(",exetime()," s)\n","Pass 2: inserting DIF tokens and mark up. " if $verbose; - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold2.tex"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew2.tex"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - @retwords=pass2(\@oldwords, \@newwords); - - return(@retwords); -} - - - - -# @words=splitlatex($string) -# split string according to latex rules -# Each element of words is either -# a word (including trailing spaces and punctuation) -# a latex command -sub splitlatex { - my ($string) = @_ ; - # if input is empty, return empty list - length($string)>0 or return (); - - my @retval=($string =~ m/$pat/osg); - - if (length($string) != length(join("",@retval))) { - print STDERR "\nWARNING: Inconsistency in length of input string and parsed string:\n This often indicates faulty or non-standard latex code.\n In many cases you can ignore this and the following warning messages.\n Note that character numbers in the following are counted beginning after \\begin{document} and are only approximate." unless $ignorewarnings; - print STDERR "DEBUG Original length ",length($string)," Parsed length ",length(join("",@retval)),"\n" if $debug; - print STDERR "DEBUG Input string: |$string|\n" if (length($string)<500) && $debug; - print STDERR "DEBUG Token parsing: |",join("+",@retval),"|\n" if (length($string)<500) && $debug ; - @retval=(); - # slow way only do this if other m//sg method fails - my $last = 0; - while ( $string =~ m/$pat/osg ) { - my $match=$&; - if ($last + length $& != pos $string ) { - my $pos=pos($string); - my $offset=30<$last ? 30 : $last; - my $dum=substr($string,$last-$offset,$pos-$last+2*$offset); - my $dum1=$dum; - my $cnt=$#retval; - my $i; - $dum1 =~ s/\n/ /g; - unless ($ignorewarnings) { - print STDERR "\n$dum1\n"; - print STDERR " " x 30,"^" x ($pos-$last)," " x 30,"\n"; - print STDERR "Missing characters near word " . (scalar @retval) . " character index: " . $last . "-" . pos($string) . " Length: " . length($match) . " Match: |$match| (expected match marked above).\n"; - } - # put in missing characters `by hand' - push (@retval, substr($dum,$offset,$pos-$last-length($match))); -# Note: there seems to be a bug in substr with utf8 that made the following line output substr which were too long, -# using dum instead appears to work -# push (@retval, substr($string,$last, pos($string)-$last-length($match))); - } - push (@retval, $match); - $last=pos $string; - } - - } - return @retval; -} - - -# pass1( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Where an common-subsequence block is flanked by deleted or appended blocks, -# and is shorter than $MINWORDSBLOCK words it is appended -# to the last deleted or appended word. If the block contains tokens other than words -# or punctuation it is not merged. -# Deleted or appended block consisting of words and safe commands only are -# also merged, to prevent break-up in pass2 (after previous isolated words have been removed) -# If there are commands with textual arguments (e.g. \caption) both in corresponding -# appended and deleted blocks split them such that the command and opening bracket -# are one token, then the rest is split up following standard rules, and the closing -# bracket is a separate token, ie. turn -# "\caption{This is a textual argument}" into -# ("\caption{","This ","is ","a ","textual ","argument","}") -# No return value. Destructively changes sequences -sub pass1 { - my $seq1 = shift ; - my $seq2 = shift ; - - my $len1 = scalar @$seq1; - my $len2 = scalar @$seq2; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - - my ($last1,$last2)=(-1,-1) ; - my $cnt=0; - my $block=[]; - my $addblock=[]; - my $delblock=[]; - my $todo=[]; - my $instruction=[]; - my $i; - my (@delmid,@addmid,@dummy); - - my ($addcmds,$delcmds,$matchindex); - my ($addtextblocks,$deltextblocks); - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $adddiscard = sub { - if ($cnt > 0 ) { - $matblkcnt++; - # just after an unchanged block -# print STDERR "Unchanged block $cnt, $last1,$last2 \n"; - if ($cnt < $MINWORDSBLOCK - && $cnt==scalar ( - grep { /^$wpat/ || ( /^\\([\w\d\*]+)((?:\[$brat0\]|\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && scalar(@dummy=split(" ",$2))<3 ) } - @$block) ) { - # merge identical blocks shorter than $MINWORDSBLOCK - # and only containing ordinary words - # with preceding different word - # We cannot carry out this merging immediately as this - # would change the index numbers of seq1 and seq2 and confuse - # the algorithm, instead we store in @$todo where we have to merge - push(@$todo, [ $last1,$last2,$cnt,@$block ]); - } - $block = []; - $cnt=0; $last1=-1; $last2=-1; - } - }; - my $discard=sub { $deltokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$delblock,[ $seq1->[$_[0]],$_[0] ]); - $last1=$_[0] }; - - my $add = sub { $addtokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$addblock,[ $seq2->[$_[1]],$_[1] ]); - $last2=$_[1] }; - - my $match = sub { $mattokcnt++; - if ($cnt==0) { # first word of matching sequence after changed sequence or at beginning of word sequence - $deltextblocks = extracttextblocks($delblock); - $delblkcnt++ if scalar @$delblock; - $addtextblocks = extracttextblocks($addblock); - $addblkcnt++ if scalar @$addblock; - - $delcmds = extractcommands($delblock); - $addcmds = extractcommands($addblock); - # keygen(third argument of _longestCommonSubsequence) implies to sort on command (0th elements of $addcmd elements) - # the calling format for longestCommonSubsequence has changed between versions of - # Algorithm::Diff so we need to check which one we are using - if ( $algodiffversion > 1.15 ) { - ### Algorithm::Diff 1.19 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, 0, sub { $_[0]->[0] } ); - } else { - ### Algorithm::Diff 1.15 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, sub { $_[0]->[0] } ); - } - - for ($i=0 ; $i<=$#$matchindex ; $i++) { - if (defined($matchindex->[$i])){ - $j=$matchindex->[$i]; - @delmid=splitlatex($delcmds->[$i][3]); - @addmid=splitlatex($addcmds->[$j][3]); - while (scalar(@$deltextblocks) && $deltextblocks->[0][0]<$delcmds->[$i][1]) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) }; - push(@$todo, [$index,-1,$cnt,@$block]); - } - push(@$todo, [ $delcmds->[$i][1],-1,-1,$delcmds->[$i][2],@delmid,$delcmds->[$i][4]]); - - while (scalar(@$addtextblocks) && $addtextblocks->[0][0]<$addcmds->[$j][1]) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - push(@$todo, [ -1,$addcmds->[$j][1],-1,$addcmds->[$j][2],@addmid,$addcmds->[$j][4]]); - } - } - # mop up remaining textblocks - while (scalar(@$deltextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) } ; - push(@$todo, [$index,-1,$cnt,@$block]); - } - while (scalar(@$addtextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - - $addblock=[]; - $delblock=[]; - } - push(@$block,$seq2->[$_[1]]); - $cnt++ }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - - - # now carry out the merging/splitting. Refer to elements relative from - # the end (with negative indices) as these offsets don't change before the instruction is executed - # cnt>0: merged small unchanged groups with previous changed blocks - # cnt==-1: split textual commands into components - foreach $instruction ( @$todo) { - ($last1,$last2,$cnt,@$block)=@$instruction ; - if ($cnt>=0) { - splice(@$seq1,$last1-$len1,1+$cnt,join("",$seq1->[$last1-$len1],@$block)) if $last1>=0; - splice(@$seq2,$last2-$len2,1+$cnt,join("",$seq2->[$last2-$len2],@$block)) if $last2>=0; - } else { - splice(@$seq1,$last1-$len1,1,@$block) if $last1>=0; - splice(@$seq2,$last2-$len2,1,@$block) if $last2>=0; - } - } - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens in $matblkcnt blocks.\n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } -} - - -# extracttextblocks(\@blockindex) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [[ $index, $textblock, $cnt ], .. -# where $index index of block to be merged -# $textblock contains all the words to be merged with the word at $index (but does not contain this word) -# $cnt is length of block -# -# requires: iscmd -# -sub extracttextblocks { - my $block=shift; - my ($i,$token,$index); - my $textblock=[]; - my $last=-1; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # store pure text blocks - if ($token =~ /$wpat/ || ( $token =~/^\\([\w\d\*]+)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && !iscmd($1,\@TEXTCMDLIST,\@TEXTCMDEXCL))) { - # we have text or a command which can be treated as text - if ($last<0) { - # new pure-text block - $last=$index; - } else { - # add to pure-text block - push(@$textblock, $token); - } - } else { - # it is not text - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - $textblock=[]; - $last=-1; - } - } - # finish processing a possibly unfinished block before returning - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - return($retval) -} - - - -# extractcommands( \@blockindex ) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [ [ "\cmd1", index, "\cmd1[optarg]{arg1}{", "arg2" ,"} " ],.. -# where index is just taken from input array -# command must have a textual argument as last argument -# -# requires: iscmd -# -sub extractcommands { - my $block=shift; - my ($i,$token,$index,$cmd,$open,$mid,$closing); - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: \cmd - # $3: last argument - # $4: } + trailing spaces - if ( ( $token =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL) ) { - # push(@$retval,[ $2,$index,$1,$3,$4 ]); - ($cmd,$open,$mid,$closing) = ($2,$1,$3,$4) ; - $closing =~ s/\}/\\RIGHTBRACE/ ; - push(@$retval,[ $cmd,$index,$open,$mid,$closing ]); - } - } - return $retval; -} - -# iscmd($cmd,\@regexarray,\@regexexcl) checks -# return 1 if $cmd matches any of the patterns in the -# array $@regexarray, and none of the patterns in \@regexexcl, otherwise return 0 -sub iscmd { - my ($cmd,$regexar,$regexexcl)=@_; - my ($ret)=0; - foreach $pat ( @$regexar ) { - if ( $cmd =~ m/^${pat}$/ ) { - $ret=1 ; - last; - } - } - return 0 unless $ret; - foreach $pat ( @$regexexcl ) { - return 0 if ( $cmd =~ m/^${pat}$/ ); - } - return 1; -} - - -# pass2( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Mark begin and end of deleted and appended sequences with tags $DELOPEN and $DELCLOSE -# and $ADDOPEN and $ADDCLOSE, respectively, however exclude { } & and all comands, unless -# they match an element of the whitelist (SAFECMD) -# For words in TEXTCMD but not in SAFECMD, enclose interior with $ADDOPEN and $ADDCLOSE brackets -# Deleted comment lines are marked with %DIF < -# Added comment lines are marked with %DIF > -sub pass2 { - my $seq1 = shift ; - my $seq2 = shift ; - - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $retval = []; - my $delhunk = []; - my $addhunk = []; - - my $discard = sub { $deltokcnt++; - push ( @$delhunk, $seq1->[$_[0]]) }; - - my $add = sub { $addtokcnt++; - push ( @$addhunk, $seq2->[$_[1]]) }; - - my $match = sub { $mattokcnt++; - if ( scalar @$delhunk ) { - $delblkcnt++; - # mark up changes, but comment out commands - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk); - $delhunk = []; - } - if ( scalar @$addhunk ) { - $addblkcnt++; - # we mark up changes, but simply quote commands - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk); - $addhunk = []; - } - push(@$retval,$seq2->[$_[1]]) }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - # clear up unprocessed hunks - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk) if scalar @$delhunk; - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk) if scalar @$addhunk; - - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens. \n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } - - return(@$retval); -} - -# marktags($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,\@block) -# returns ($openmark,$open,$block,$close,$closemark) if @block only contains no commands (except white-listed ones), -# braces, ampersands, or comments -# mark comments with $comment -# exclude all other exceptions from scope of open, close like this -# ($openmark, $open,...,$close, $opencmd,command, command,$closecmd, $open, ..., $close, $closemark) -# If $opencmd begins with "%" marktags assumes it is operating on a deleted block, otherwise on an added block -sub marktags { - my ($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,$block)=@_; - my $word; - my (@argtext); - my $retval=[]; - my $noncomment=0; - my $cmd=-1; # -1 at beginning 0: last token written is a ordinary word - # 1: last token written is a command - # for keeping track whether we are just in a command sequence or in a word sequence - my $cmdcomment= ($opencmd =~ m/^%/); # Flag to indicate whether opencmd is a comment (i.e. if we intend to simply comment out changed commands) - my ($command,$commandword,$closingbracket) ; # temporary variables needed below to remember sub-pattern matches - -# split this block to flatten out sequences joined in pass1 - @$block=splitlatex(join "",@$block); - foreach (@$block) { - $word=$_; - if ( $word =~ s/^%/%$comment/ ) { - # a comment - if ($cmd==1) { - push (@$retval,$closecmd) ; - $cmd=-1; - } - push (@$retval,$word); - next; - } - if (! $noncomment) { - push (@$retval,$openmark); - $noncomment=1; - } - # negative lookahead pattern (?!) in second clause is put in to avoid mathcing \( .. \) patterns - # also note that second pattern will match \\ - # Note: the second pattern should really be $word =~ /^\\(?!\()(\\|[\w*@]+)/, ie * replaced by + - # and then all commands \" \' etc declared safe. But as I don't have a complete list of one letter - # commands, and nobody has complained so far, I will eave this as is - if ( $word =~ /^[&{}\[\]]/ || ( $word =~ /^\\(?!\()(\\|[\w*@]*)/ && !iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL)) ) { - # word is a command or other significant token (not in SAFECMDLIST) - ## same conditions as in subroutine extractcommand: - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: cmd - # $3: last argument - # $4: } + trailing spaces - ### pre-0.3 if ( ( $token =~ m/^(\\([\w\d\*]+)(?:\[$brat0\]|\{$pat6\})*\{)($pat6)(\}\s*)$/so ) - if ( ( $word =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && (iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL)|| iscmd($2,\@MATHTEXTCMDLIST,\@MATHTEXTCMDEXCL)) - && ( !$cmdcomment || !iscmd($2,\@CONTEXT2CMDLIST, \@CONTEXT2CMDEXCL) ) ) { - # Condition 1: word is a command? - if yes, $1,$2,.. will be set as above - # Condition 2: word is a text command - we mark up the interior of the word. There is a separate check for MATHTEXTCMDLIST - # because for $mathmarkup=WHOLE, the commands should not be split in pass1 (ie. math mode commands are not in - # TEXTCMDLIST, but the interior of MATHTEXT commands should be highlighted in both deleted and added blocks - # Condition 3: But if we are in a deleted block ($cmdcomment=1) and - # $2 (the command) is in context2, just treat it as an ordinary command (i.e. comment it open with $opencmd) - # Because we do not want to disable this command - # here we do not use $opencmd and $closecmd($opencmd is empty) - if ($cmd==1) { - push (@$retval,$closecmd) ; - } elsif ($cmd==0) { - push (@$retval,$close) ; - } - $command=$1; $commandword=$2; $closingbracket=$4; - @argtext=splitlatex($3); # split textual argument into tokens - # and mark it up (but we do not need openmark and closemark) - # insert command with initial arguments, marked-up final argument, and closing bracket - if ( $cmdcomment && iscmd($commandword,\@CONTEXT1CMDLIST, \@CONTEXT1CMDEXCL) ) { - # context1cmd in a deleted environment; delete command itself but keep last argument, marked up - push (@$retval,$opencmd); - $command =~ s/\n/\n${opencmd}/sg ; # repeat opencmd at the beginning of each line - # argument, note that the additional comment character is included - # to suppress linebreak after opening parentheses, which is important - # for latexrevise - push (@$retval,$command,"%\n{$AUXCMD\n",marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } elsif ( iscmd($commandword,,\@MATHTEXTCMDLIST, \@MATHTEXTCMDEXCL) ) { - # MATHBLOCK pseudo command: consider all commands safe, except & and \\ - # Keep these commands even in deleted blocks, hence set $opencmd and $closecmd (5th and 6th argument of marktags) to - # "" - local @SAFECMDLIST=(".*"); - local @SAFECMDEXCL=('\\','\\\\'); - push(@$retval,$command,marktags("","",$open,$close,"","",$comment,\@argtext)#@argtext - ,$closingbracket); - } else { - # normal textcmd or context1cmd in an added block - push (@$retval,$command,marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } - push (@$retval,$AUXCMD,"\n") if $cmdcomment ; - $cmd=-1 ; - } else { - # ordinary command - push (@$retval,$opencmd) if $cmd==-1 ; - push (@$retval,$close,$opencmd) if $cmd==0 ; - $word =~ s/\n/\n${opencmd}/sg if $cmdcomment ; # if opencmd is a comment, repeat this at the beginning of every line - push (@$retval,$word); - $cmd=1; - } - } else { - # just an ordinary word or word in SAFECMD - push (@$retval,$open) if $cmd==-1 ; - push (@$retval,$closecmd,$open) if $cmd==1 ; - push (@$retval,$word); - $cmd=0; - } - } - push (@$retval,$close) if $cmd==0; - push (@$retval,$closecmd) if $cmd==1; - - push (@$retval,$closemark) if ($noncomment); - return @$retval; -} - -# preprocess($string, ..) -# carry out the following pre-processing steps for all arguments: -# 1. Remove leading white-space -# Change \{ to \LEFTBRACE and \} to \RIGHTBRACE -# #. change begin and end commands within comments to BEGINDIF, ENDDIF -# so they don't disturb the pattern matching (if there are several \begin or \end in one line -# 2. mark all first empty line (in block of several) with \PAR tokens -# 3. Convert all '\%' into '\PERCENTAGE ' to make parsing regular expressions easier -# 4. Convert all \verb|some verbatim text| commands (where | can be an arbitrary character) -# into \verb{hash} -# 5. Convert \begin{verbatim} some verbatim text \end{verbatim} into \verbatim{hash} -# 6. Convert _n into \SUBSCRIPTNB{n} and _{nnn} into \SUBSCRIPT{nn} -# 7. Convert ^n into \SUPERSCRIPTNB{n} and ^{nnn} into \SUPERSCRIPT{nn} -# 8. a. Convert $$ $$ into \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} -# b. Convert \[ \] into \begin{SQUAREBRACKET} \end{SQUAREBRACKET} -# 9. Convert all picture environmentent (\begin{PICTUREENV} .. \end{PICTUREENV} \PICTUREBLOCKenv -# For --block-math-markup option -convert all \begin{MATH} .. \end{MATH} -# into \MATHBLOCKmath{...} commands, where MATH/math is any valid math environment - -# 10. Add final token STOP to the very end. This is put in because the algorithm works better if the last token is identical. This is removed again in postprocessing. -# -# NB: step 6 and 7 is likely to convert some "_" inappropriately, e.g. in file -# names or labels but it does not matter because they are converted back in the postprocessing step -# Returns: leading white space removed in step 1 -sub preprocess { - my @leadin=() ; - for (@_) { - s/^(\s*)//s; - push(@leadin,$1); - # Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE - s/(?{$hstr}) && $string ne $hash->{$hstr}) { - warn "Repeated hash value for verbatim mode in spite of different content."; - $hstr="-$hstr"; - } - $hash->{$hstr}=$string; - return($hstr); -} - -#string=fromhash(\%hash,$fromstring) -# restores string value stored in hash -#string=fromhash(\%hash,$fromstring,$prependstring) -# additionally begins each line with prependstring -sub fromhash { - my ($hash,$hstr)=($_[0],$_[1]); - my $retstr=$hash->{$hstr}; - if ( $#_ >= 2) { - $retstr =~ s/^/$_[2]/mg; - } - return $retstr; -} - - -# postprocess($string, ..) -# carry out the following post-processing steps for all arguments: -# * Remove STOP token from the end -# * Replace \RIGHTBRACE by } -# * change citation commands within comments to protect from processing (using marker CITEDIF) -# 1. Check all deleted blocks: -# a.where a deleted block contains a matching \begin and -# \end environment (these will be disabled by a %DIFDELCMD statements), for selected environments enable -# these commands again (such that for example displayed math in a deleted equation -# is properly within math mode. For math mode environments replace numbered equation -# environments with their display only variety (so that equation numbers in new file and -# diff file are identical). Where the correct type of math environment cannot be determined -# use a place holder MATHMODE -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file -# Replace all MATHMODE environment commands by the correct environment to achieve matching -# pairs -# c. Convert MATHBLOCKmath commands to their uncounted numbers (e.g. convert equation -> displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL -# d. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# For added blocks: -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# 2. If --block-math-markup option set: Convert \MATHBLOCKmath{..} commands back to environments -# -# Convert all PICTUREblock{..} commands back to the appropriate environments -# 3. Convert DIFadd, DIFdel, DIFFaddbegin , ... into FL varieties -# within floats (currently recognised float environments: plate,table,figure -# plus starred varieties). -# 4. Remove empty %DIFDELCMD < lines -# 4. Convert \begin{SQUAREBRACKET} \end{SQUAREBRACKET} into \[ \] -# Convert \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} into $$ $$ -# 5. Convert \SUPERSCRIPTNB{n} into ^n and \SUPERSCRIPT{nn} into ^{nnn} -# 6. Convert \SUBSCRIPTNB{n} into _n and \SUBCRIPT{nn} into _{nnn} -# 7. Expand hashes of verb and verbatim environments -# 8. Convert '\PERCENTAGE ' back into '\%' -# 9.. remove all \PAR tokens -# 10. package specific processing: endfloat: make sure \begin{figure} and \end{figure} are always -# on a line by themselves, similarly for table environment -# 4, undo renaming of the \begin and \end in comments -# Change \QLEFTBRACE, \QRIGHTBRACE to \{,\} -# -# Note have to manually synchronize substitution commands below and -# DIF.. command names in the header -sub postprocess { - my ($begin,$len,$cnt,$float,$delblock,$addblock); - # second level blocks - my ($begin2,$cnt2,$len2,$eqarrayblock,$mathblock); - - for (@_) { - - # change $'s in comments to something harmless - 1 while s/(%.*)\$/$1DOLLARDIF/mg ; - - # Remove final STOP token - s/ STOP$//; - # Replace \RIGHTBRACE by } - s/\\RIGHTBRACE/}/g; - - # change citation commands within comments to protect from processing - if ($CITECMD){ - 1 while s/(%.*)\\($CITECMD)/$1\\CITEDIF$2/m ; - } - # Check all deleted blocks: where a deleted block contains a matching \begin and - # \end environment (these will be disabled by a %DIFDELCMD statements), enable - # these commands again (such that for example displayed math in a deleted equation - # is properly within math mode. For math mode environments replace numbered equation - # environments with their display only variety (so that equation numbers in new file and - # diff file are identical - while ( m/\\DIFdelbegin.*?\\DIFdelend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $delblock=$&; - - - ### (.*?[^\n]?)\n? construct is necessary to avoid empty lines in math mode, which result in - ### an error - # displayed math environments - if ($mathmarkup == FINE ) { - $delblock=~ s/(\%DIFDELCMD < \s*\\begin\{((?:$MATHENV)|SQUAREBRACKET)\}.*?(?:$DELCMDCLOSE|\n))(.*?[^\n]?)\n?(\%DIFDELCMD < \s*\\end\{\2\})/\\begin{$MATHREPL}$AUXCMD\n$1$3\n\\end{$MATHREPL}$AUXCMD\n$4/sg; - # also transform the opposite pair \end{displaymath} .. \begin{displaymath} but we have to be careful not to interfere with the results of the transformation in the line directly above - ### pre-0.42 obsolete version which did not work on eqnarray test $delblock=~ s/(? displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL - $delblock=~ s/\\MATHBLOCK($MATHENV)\{($pat6)\}/\\MATHBLOCK$MATHREPL\{$2\}/sg; - $delblock=~ s/\\MATHBLOCK($MATHARRENV)\{($pat6)\}/\\MATHBLOCK$MATHARRREPL\{$2\}/sg; - } - - -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file - $delblock=~ s/\\($COUNTERCMD)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*\s*${AUXCMD}\n)/\\$1$2\\addtocounter{$1}{-1}${AUXCMD}\n/sg ; - - -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es - while ( $delblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($delblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($delblock,$begin2,$len2)=$mathblock; - pos($delblock) = $begin2 + length($mathblock); - } - if ($CITE2CMD) { - $delblock=~s/($DELCMDOPEN\s*\\($CITE2CMD)(.*)$DELCMDCLOSE)/ - # Replacement code - {my ($aux,$all); - $aux=$all=$1; - $aux=~s#\n?($DELCMDOPEN|$DELCMDCLOSE)##g; - $all."$aux$AUXCMD\n";}/sge; - } - # or protect \cite commands with \mbox - if ($CITECMD) { - $delblock=~s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat6\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified delblock - substr($_,$begin,$len)=$delblock; - pos = $begin + length($delblock); - } - # make the array modification in added blocks - while ( m/\\DIFaddbegin.*?\\DIFaddend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $addblock=$&; - while ( $addblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($addblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($addblock,$begin2,$len2)=$mathblock; - pos($addblock) = $begin2 + length($mathblock); - } - if ($CITECMD) { - my $addblockbefore=$addblock; - $addblock=~ s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat2\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified addblock - substr($_,$begin,$len)=$addblock; - pos = $begin + length($addblock); - } - - - ### old place for BEGINDIF, ENDDIF replacement - # change begin and end commands within comments such that they - # don't disturb the pattern matching (if there are several \begin or \end in one line - # this substitution is insufficient but that appears unlikely) - # This needs to be repeated here to also get rid of DIFdelcmd-protected environments - s/(%.*)\\begin\{(.*)$/$1\\BEGINDIF\{$2/mg ; - s/(%.*)\\end\{(.*)$/$1\\ENDDIF\{$2/mg ; - - # Replace MATHMODE environments from step 1a above by the correct Math environment - - # The next line is complicated. The negative look-ahead insertion makes sure that no \end{$MATHENV} (or other mathematical - # environments) are between the \begin{$MATHENV} and \end{MATHMODE} commands. This is necessary as the minimal matching - # is not globally minimal but only 'locally' (matching is beginning from the left side of the string) - if ( $mathmarkup == FINE ) { - 1 while s/\\begin{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}((?:.(?!(?:\\end{(?:(?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}|\\begin{MATHMODE})))*?)\\end{MATHMODE}/\\begin{$1}$2\\end{$1}/s; - 1 while s/\\begin{MATHMODE}((?:.(?!\\end{MATHMODE}))*?)\\end{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}/\\begin{$2}$1\\end{$2}/s; - # convert remaining \begin{MATHMODE} \end{MATHMODE} (and not containing & or \\ )into MATHREPL environments - s/\\begin{MATHMODE}((?:(.(?!(?[1])) { - $optargnew=$newhash{$cmd}->[1]; - } else { - $optargnew=""; - } - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - } else { - $optargold=""; - } - - if ( defined($oldhash{$cmd}) ) { - $argold=$oldhash{$cmd}->[2]; - } else { - $argold=""; - } - $argnew=$newhash{$cmd}->[2]; - $argdiff="{" . join("",bodydiff($argold,$argnew)) ."}"; - if ( length $optargnew ) { - $optargdiff="[".join("",bodydiff($optargold,$optargnew))."]" ; - $optargdiff =~ s/\\DIFaddbegin /\\DIFaddbeginFL /g; - $optargdiff =~ s/\\DIFaddend /\\DIFaddendFL /g; - $optargdiff =~ s/\\DIFadd\{/\\DIFaddFL{/g; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - ### print STDERR "DEBUG s/\\Q$newhash{$cmd}->[0]\\E/\\$cmd$optargdiff$argdiff/s\n"; - # Note: \Q and \E force literal interpretation of what it between them but allow - # variable interpolation, such that e.g. \title matches just that and not TAB-itle - $$newpreambleref=~s/\Q$newhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s; - # replace this in old preamble if necessary - if ( defined($oldhash{$cmd}->[0])) { - $$oldpreambleref=~s/\Q$oldhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s ; - } - ### print STDERR "DEBUG NEW PRE ".$$newpreambleref."\n"; - } - - foreach $cmd ( keys %oldhash ) { - # if this has already been dealt with above can just skip - next if defined($newhash{$cmd}) ; - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - $optargdiff="[".join("",bodydiff($optargold,""))."]" ; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - $argdiff="{" . join("",bodydiff($argold,"")) ."}"; - $auxline = "\\$cmd$optargdiff$argdiff"; - $auxline =~s/$/$AUXCMD/sg; - push @auxlines,$auxline; - } - # add auxcmd comment to highlight added lines - return(@auxlines); -} - - - -# @diffs=linediff(\@seq1, \@seq2) -# mark up lines like this -#%DIF mm-mmdnn -#%< old deleted line(s) -#%DIF ------- -#%DIF mmann-nn -#new appended line %< -#%DIF ------- -# Future extension: mark change explicitly -# Assumes: traverse_sequence traverses deletions before insertions in changed sequences -# all line numbers relative to line 0 (first line of real file) -sub linediff { - my $seq1 = shift ; - my $seq2 = shift ; - - my $block = []; - my $retseq = []; - my @begin=('','',''); # dummy initialisation - my $instring ; - - my $discard = sub { @begin=('d',$_[0],$_[1]) unless scalar @$block ; - push(@$block, "%DIF < " . $seq1->[$_[0]]) }; - my $add = sub { if (! scalar @$block) { - @begin=('a',$_[0],$_[1]) ;} - elsif ( $begin[0] eq 'd' ) { - $begin[0]='c'; $begin[2]=$_[1]; - push(@$block, "%DIF -------") } - push(@$block, $seq2->[$_[1]] . " %DIF > " ) }; - my $match = sub { if ( scalar @$block ) { - if ( $begin[0] eq 'd' && $begin[1]!=$_[0]-1) { - $instring = sprintf "%%DIF %d-%dd%d",$begin[1],$_[0]-1,$begin[2]; } - elsif ( $begin[0] eq 'a' && $begin[2]!=$_[1]-1) { - $instring = sprintf "%%DIF %da%d-%d",$begin[1],$begin[2],$_[1]-1; } - elsif ( $begin[0] eq 'c' ) { - $instring = sprintf "%%DIF %sc%s", - ($begin[1]==$_[0]-1) ? "$begin[1]" : $begin[1]."-".($_[0]-1) , - ($begin[2]==$_[1]-1) ? "$begin[2]" : $begin[2]."-".($_[1]-1) ; } - else { - $instring = sprintf "%%DIF %d%s%d",$begin[1],$begin[0],$begin[2]; } - push @$retseq, $instring,@$block, "%DIF -------" ; - $block = []; - } - push @$retseq, $seq2->[$_[1]] - }; - # key function: remove multiple spaces (such that insertion or deletion of redundant white space is not reported) - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - push @$retseq, @$block if scalar @$block; - - return wantarray ? @$retseq : $retseq ; -} - - - -# init_regex_arr_data(\@array,"TOKEN INIT") -# scans DATA file handel for line "%% TOKEN INIT" line -# then appends each line not beginning with % into array (as a quoted regex) -sub init_regex_arr_data { - my ($arr,$token)=@_; - my ($copy); - while () { - if ( m/^%%BEGIN $token\s*$/ ) { - $copy=1; } - elsif ( m/^%%END $token\s*/ ) { - last; } - chomp; - push (@$arr,qr/^$_$/) if ( $copy && !/^%/ ) ; - } - seek DATA,0,0; # rewind DATA handle to file begin -} - - -# init_regex_arr_ext(\@array,$arg) -# fills array with regular expressions. -# if arg is a file name, then read in list of regular expressions from that file -# (one expression per line) -# Otherwise treat arg as a comma separated list of regular expressions -sub init_regex_arr_ext { - my ($arr,$arg)=@_; - my $regex; - if ( -f $ arg ) { - open(FILE,"$arg") or die ("Couldn't open $arg: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@$arr,qr/^$_$/); - } - close(FILE); - } - else { - # assume it is a comma-separated list of reg-ex - foreach $regex (split(qr/(?=1) { - $reset=shift; - } - if ($reset) { - $lasttime=times(); - } - else { - $retval=times()-$lasttime; - $lasttime=$lasttime+$retval; - return($retval); - } -} - - -sub usage { - die <<"EOF"; -Usage: $0 [options] old.tex new.tex > diff.tex - -Compares two latex files and writes tex code to stdout, which has the same -format as new.tex but has all changes relative to old.tex marked up or commented. - ---type=markupstyle --t markupstyle Add code to preamble for selected markup style - Available styles: UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE - CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR - [ Default: UNDERLINE ] - ---subtype=markstyle --s markstyle Add code to preamble for selected style for bracketing - commands (e.g. to mark changes in margin) - Available styles: SAFE MARGINAL DVIPSCOL COLOR - [ Default: SAFE ] - ---floattype=markstyle --f markstyle Add code to preamble for selected style which - replace standard marking and markup commands within floats - (e.g., marginal remarks cause an error within floats - so marginal marking can be disabled thus) - Available styles: FLOATSAFE IDENTICAL - [ Default: FLOATSAFE ] - ---encoding=enc --e enc Specify encoding of old.tex and new.tex. Typical encodings are - ascii, utf8, latin1, latin9. A list of available encodings can be - obtained by executing - perl -MEncode -e 'print join ("\\n",Encode->encodings( ":all" )) ;' - [Default encoding is utf8 unless the first few lines of the preamble contain - an invocation "\\usepackage[..]{inputenc} in which case the - encoding chosen by this command is asssumed. Note that ASCII (standard - latex) is a subset of utf8] - ---preamble=file --p file Insert file at end of preamble instead of auto-generating - preamble. The preamble must define the following commands - \\DIFaddbegin,\\DIFaddend,\\DIFadd{..}, - \\DIFdelbegin,\\DIFdelend,\\DIFdel{..}, - and varieties for use within floats - \\DIFaddbeginFL,\\DIFaddendFL,\\DIFaddFL{..}, - \\DIFdelbeginFL,\\DIFdelendFL,\\DIFdelFL{..} - (If this option is set -t, -s, and -f options - are ignored.) - ---exclude-safecmd=exclude-file ---exclude-safecmd="cmd1,cmd2,..." --A exclude-file ---replace-safecmd=replace-file ---append-safecmd=append-file ---append-safecmd="cmd1,cmd2,..." --a append-file Exclude from, replace or append to the list of regex - matching commands which are safe to use within the - scope of a \\DIFadd or \\DIFdel command. The file must contain - one Perl-RegEx per line (Comment lines beginning with # or % are - ignored). A literal comma within the comma-separated list must be - escaped thus "\\,", Note that the RegEx needs to match the whole of - the token, i.e., /^regex\$/ is implied and that the initial - "\\" of the command is not included. The --exclude-safecmd - and --append-safecmd options can be combined with the --replace-safecmd - option and can be used repeatedly to add cumulatively to the lists. - ---exclude-textcmd=exclude-file ---exclude-textcmd="cmd1,cmd2,..." --X exclude-file ---replace-textcmd=replace-file ---append-textcmd=append-file ---append-textcmd="cmd1,cmd2,..." --x append-file Exclude from, replace or append to the list of regex - matching commands whose last argument is text. See - entry for --exclude-safecmd directly above for further details. - ---replace-context1cmd=replace-file ---append-context1cmd=append-file ---append-context1cmd="cmd1,cmd2,..." - Replace or append to the list of regex matching commands - whose last argument is text but which require a particular - context to work, e.g. \\caption will only work within a figure - or table. These commands behave like text commands, except when - they occur in a deleted section, when they are disabled, but their - argument is shown as deleted text. - ---replace-context2cmd=replace-file ---append-context2cmd=append-file ---append-context2cmd="cmd1,cmd2,..." - As corresponding commands for context1. The only difference is that - context2 commands are completely disabled in deleted sections, including - their arguments. - - ---config var1=val1,var2=val2,... --c var1=val1,.. Set configuration variables. --c configfile Available variables: - MINWORDSBLOCK (integer) - FLOATENV (RegEx) - PICTUREENV (RegEx) - MATHENV (RegEx) - MATHREPL (String) - MATHARRENV (RegEx) - MATHARRREPL (String) - ARRENV (RegEx) - COUNTERCMD (RegEx) - This option can be repeated. - - ---packages=pkg1,pkg2,.. - Tell latexdiff that .tex file is processed with the packages in list - loaded. This is normally not necessary if the .tex file includes the - preamble, as the preamble is automatically scanned for \\usepackage commands. - Use of the --packages option disables automatic scanning, so if for any - reason package specific parsing needs to be switched off, use --packages=none. - The following packages trigger special behaviour: - endfloat hyperref amsmath - [ Default: scan the preamble for \\usepackage commands to determine - loaded packages.] - ---show-preamble Print generated or included preamble commands to stdout. - ---show-safecmd Print list of regex matching and excluding safe commands. - ---show-textcmd Print list of regex matching and excluding commands with text argument. - ---show-config Show values of configuration variables - ---show-all Show all of the above - - NB For all --show commands, no old.tex or new.tex file needs to be given, and no - differencing takes place. - -Other configuration options: - ---allow-spaces Allow spaces between bracketed or braced arguments to commands - [Default requires arguments to directly follow each other without - intervening spaces] - ---math-markup=level Determine granularity of markup in displayed math environments: - Possible values for level are (both numerical and text labels are acceptable): - off or 0: suppress markup for math environments. Deleted equations will not - appear in diff file. This mode can be used if all the other modes - cause invalid latex code. - whole or 1: Differencing on the level of whole equations. Even trivial changes - to equations cause the whole equation to be marked changed. This - mode can be used if processing in coarse or fine mode results in - invalid latex code. - coarse or 2: Detect changes within equations marked up with a coarse - granularity; changes in equation type (e.g.displaymath to equation) - appear as a change to the complete equation. This mode is recommended - for situations where the content and order of some equations are still - being changed. [Default] - fine or 3: Detect small change in equations and mark up and fine granularity. - This mode is most suitable, if only minor changes to equations are - expected, e.g. correction of typos. - ---disable-citation-markup Suppress citation markup in styles using ulem (UNDERLINE, - FONTSTRIKE, CULINECHBAR) ---enable-citation-markup Protect citation commands in changed sections with \\mbox command - [i.e. use default behaviour for ulem package for other packages] - -Miscelleneous options - ---label=label --L label Sets the labels used to describe the old and new files. The first use - of this option sets the label describing the old file and the second - use of the option sets the label for the new file. - [Default: use the filename and modification dates for the label] - ---no-label Suppress inclusion of old and new file names as comment in output file - ---visble-label Include old and new filenames (or labels set with --label option) as - visible output - ---flatten Replace \\input and \\include commands within body by the content - of the files in their argument. If \\includeonly is present in the - preamble, only those files are expanded into the document. However, - no recursion is done, i.e. \\input and \\include commands within - included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, - respectively, making it possible to organise files into old and new directories. - --flatten is applied recursively, so inputted files can contain further - \\input statements. - ---help --h Show this help text. - ---ignore-warnings Suppress warnings about inconsistencies in length between input - and parsed strings and missing characters. - ---verbose --V Output various status information to stderr during processing. - Default is to work silently. - ---version Show version number. - -For further information, consult http://latexdiff.berlios.de -EOF -} - -=head1 NAME - -latexdiff - determine and markup differences between two latex files - -=head1 SYNOPSIS - -B [ B ] F F > F - -=head1 DESCRIPTION - -Briefly, I is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called C and C, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. - -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "S>>" is appended to each added line, i.e. a -line present in C but not in C. Discarded lines - are deactivated by prepending "S>>". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file C will be similar to -C. At the end of the preamble, the definitions for I markup commands are inserted. -In differencing the main body of the text, I attempts to -satisfy the following guidelines (in order of priority): - -=over 3 - -=item 1 - -If both C and C are valid LaTeX, then the resulting -C should also be valid LateX. (NB If a few plain TeX commands -are used within C or C then C is not -guaranteed to work but usually will). - -=item 2 - -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -C. - -=item 3 - -If a changed passage contains text or text-producing commands, then -running C through LateX should produce output where added -and discarded passages are highlighted. - -=item 4 - -Where there are insignificant differences, e.g. in the positioning of -line breaks, C should follow the formatting of C - -=back - -For differencing the same algorithm as I is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, C<\caption> and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write - - \section{\textem{This is an emphasized section title}} - -and not - - \section {\textem{This is an emphasized section title}} - -or - - \section\textem{This is an emphasized section title} - -even though all varieties are the same to LaTeX (but see -B<--allow-spaces> option which allows the second variety). - -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the PICTUREENV configuration variable, set by -default to C and C environments; see B<--config> -option). The latter environment (C) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by C<\begin{DIFnomarkup}> and C<\end{DIFnomarkup}>. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, - -C<\newenvironment{DIFnomarkup}{}{}> - -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. - -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. - -All markup commands inserted by I begin with "C<\DIF>". Added -blocks containing words, commands or comments which are in C -but not in C are marked by C<\DIFaddbegin> and C<\DIFaddend>. -Discarded blocks are marked by C<\DIFdelbegin> and C<\DIFdelend>. -Within added blocks all text is highlighted with C<\DIFadd> like this: -C<\DIFadd{Added text block}> -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces "{" and "}" are never put within -the scope of C<\DIFadd>. Added comments are marked by prepending -"S >>". - -Within deleted blocks text is highlighted with C<\DIFdel>. Deleted -comments are marked by prepending "S >>". Non-safe command -and curly braces within deleted blocks are commented out with -"S >>". - - - -=head1 OPTIONS - -=head2 Preamble - -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. - -=over 4 - -=item B<--type=markupstyle> or -B<-t markupstyle> - -Add code to preamble for selected markup style. This option defines -C<\DIFadd> and C<\DIFdel> commands. -Available styles: - -C - -[ Default: C ] - -=item B<--subtype=markstyle> or -B<-s markstyle> - -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -C<\DIFaddbegin>, C<\DIFaddend>, C<\DIFdelbegin> and C<\DIFdelend> commands. -Available styles: C - -[ Default: C ] - -=item B<--floattype=markstyle> or -B<-f markstyle> - -Add code to preamble for selected style which -replace standard marking and markup commands within floats -(e.g., marginal remarks cause an error within floats -so marginal marking can be disabled thus). This option defines all -C<\DIF...FL> commands. -Available styles: C - -[ Default: C ] - -=item B<--encoding=enc> or -B<-e enc> - -Specify encoding of old.tex and new.tex. Typical encodings are -C, C, C, C. A list of available encodings can be -obtained by executing - -Cencodings( ":all" )) ;' > - -[Default encoding is utf8 unless the first few lines of the preamble contain -an invocation C<\usepackage[..]{inputenc}> in which case the -encoding chosen by this command is asssumed. Note that ASCII (standard -latex) is a subset of utf8] - -=item B<--preamble=file> or -B<-p file> - -Insert file at end of preamble instead of generating -preamble. The preamble must define the following commands -C<\DIFaddbegin, \DIFaddend, \DIFadd{..}, -\DIFdelbegin,\DIFdelend,\DIFdel{..},> -and varieties for use within floats -C<\DIFaddbeginFL, \DIFaddendFL, \DIFaddFL{..}, -\DIFdelbeginFL, \DIFdelendFL, \DIFdelFL{..}> -(If this option is set B<-t>, B<-s>, and B<-f> options -are ignored.) - -=item B<--packages=pkg1,pkg2,..> - -Tell latexdiff that .tex file is processed with the packages in list -loaded. This is normally not necessary if the .tex file includes the -preamble, as the preamble is automatically scanned for C<\usepackage> commands. -Use of the B<--packages> option disables automatic scanning, so if for any -reason package specific parsing needs to be switched off, use B<--packages=none>. -The following packages trigger special behaviour: - -=over 8 - -=item C - -Configuration variable amsmath is set to C (Default: C) - -=item C - -Ensure that C<\begin{figure}> and C<\end{figure}> always appear by themselves on a line. - -=item C - -Change name of C<\DIFadd> and C<\DIFdel> commands to C<\DIFaddtex> and C<\DIFdeltex> and -define new C<\DIFadd> and C<\DIFdel> commands, which provide a wrapper for these commands, -using them for the text but not for the link defining command (where any markup would cause -errors). - -=back - -[ Default: scan the preamble for C<\\usepackage> commands to determine - loaded packages.] - - - -=item B<--show-preamble> - -Print generated or included preamble commands to stdout. - -=back - -=head2 Configuration - -=over 4 - -=item B<--exclude-safecmd=exclude-file> or -B<-A exclude-file> or B<--exclude-safecmd="cmd1,cmd2,..."> - -=item B<--replace-safecmd=replace-file> - -=item B<--append-safecmd=append-file> or -B<-a append-file> or B<--append-safecmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions (RegEx) -matching commands which are safe to use within the -scope of a C<\DIFadd> or C<\DIFdel> command. The file must contain -one Perl-RegEx per line (Comment lines beginning with # or % are -ignored). Note that the RegEx needs to match the whole of -the token, i.e., /^regex$/ is implied and that the initial -"\" of the command is not included. -The B<--exclude-safecmd> and B<--append-safecmd> options can be combined with the -B<--replace-safecmd> -option and can be used repeatedly to add cumulatively to the lists. - B<--exclude-safecmd> -and B<--append-safecmd> can also take a comma separated list as input. If a -comma for one of the regex is required, escape it thus "\,". In most cases it -will be necessary to protect the comma-separated list from the shell by putting -it in quotation marks. - -=item B<--exclude-textcmd=exclude-file> or -B<-X exclude-file> or B<--exclude-textcmd="cmd1,cmd2,..."> - -=item B<--replace-textcmd=replace-file> - -=item B<--append-textcmd=append-file> or -B<-x append-file> or B<--append-textcmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions -matching commands whose last argument is text. See -entry for B<--exclude-safecmd> directly above for further details. - - -=item B<--replace-context1cmd=replace-file> - -=item B<--append-context1cmd=append-file> or -=item B<--append-context1cmd="cmd1,cmd2,..."> - -Replace or append to the list of regex matching commands -whose last argument is text but which require a particular -context to work, e.g. \caption will only work within a figure -or table. These commands behave like text commands, except when -they occur in a deleted section, when they are disabled, but their -argument is shown as deleted text. - -=item B<--replace-context2cmd=replace-file> - -=item B<--append-context2cmd=append-file> or -=item B<--append-context2cmd="cmd1,cmd2,..."> -As corresponding commands for context1. The only difference is that -context2 commands are completely disabled in deleted sections, including -their arguments. - - - -=item B<--config var1=val1,var2=val2,...> or B<-c var1=val1,..> - -=item B<-c configfile> - -Set configuration variables. The option can be repeated to set different -variables (as an alternative to the comma-separated list). -Available variables (see below for further explanations): - -C (integer) - -C (RegEx) - -C (RegEx) - -C (RegEx) - -C (String) - -C (RegEx) - -C (String) - -C (RegEx) - -C (RegEx) - -=item B<--show-safecmd> - -Print list of RegEx matching and excluding safe commands. - -=item B<--show-textcmd> - -Print list of RegEx matching and excluding commands with text argument. - -=item B<--show-config> - -Show values of configuration variables. - -=item B<--show-all> - -Combine all --show commands. - -NB For all --show commands, no C or C file needs to be specified, and no -differencing takes place. - -=back - -=head2 Other configuration options: - -=over 4 - -=item B<--allow-spaces> - -Allow spaces between bracketed or braced arguments to commands. Note -that this option might have undesirable side effects (unrelated scope -might get lumpeded with preceding commands) so should only be used if the -default produces erroneous results. (Default requires arguments to -directly follow each other without intervening spaces). - -=item B<--math-markup=level> - -Determine granularity of markup in displayed math environments: -Possible values for level are (both numerical and text labels are acceptable): - -C or C<0>: suppress markup for math environments. Deleted equations will not -appear in diff file. This mode can be used if all the other modes -cause invalid latex code. - -C or C<1>: Differencing on the level of whole equations. Even trivial changes -to equations cause the whole equation to be marked changed. This -mode can be used if processing in coarse or fine mode results in -invalid latex code. - -C or C<2>: Detect changes within equations marked up with a coarse -granularity; changes in equation type (e.g.displaymath to equation) -appear as a change to the complete equation. This mode is recommended -for situations where the content and order of some equations are still -being changed. [Default] - -C or C<3>: Detect small change in equations and mark up at fine granularity. -This mode is most suitable, if only minor changes to equations are -expected, e.g. correction of typos. - -=item B<--disable-citation-markup> - -Suppress citation markup in styles using ulem (UNDERLINE, -FONTSTRIKE, CULINECHBAR) - -=item B<--enable-citation-markup> - -Protect citation commands in changed sections with \\mbox command [i.e. use default behaviour for ulem package for other packages] - -=back - -=head2 Miscellaneous - -=over 4 -=item B<--verbose> or B<-V> - -Output various status information to stderr during processing. -Default is to work silently. - -=item B<--driver=type> - -Choose driver for changebar package (only relevant for styles using - changebar: CCHANGEBAR CFONTCHBAR CULINECHBAR CHANGEBAR). Possible -drivers are listed in changebar manual, e.g. pdftex,dvips,dvitops - [Default: dvips] - -=item B<--ignore-warnings> - -Suppress warnings about inconsistencies in length between input and -parsed strings and missing characters. These warning messages are -often related to non-standard latex or latex constructions with a -syntax unknown to C but the resulting difference argument -is often fully functional anyway, particularly if the non-standard -latex only occurs in parts of the text which have not changed. - -=item B<--label=label> or -B<-L label> - -Sets the labels used to describe the old and new files. The first use -of this option sets the label describing the old file and the second -use of the option sets the label for the new file, i.e. set both -labels like this C<-L labelold -L labelnew>. -[Default: use the filename and modification dates for the label] - -=item B<--no-label> - -Suppress inclusion of old and new file names as comment in output file - -=item B<--visble-label> - -Include old and new filenames (or labels set with --label option) as -visible output. - -=item B<--flatten> - -Replace C<\input> and C<\include> commands within body by the content -of the files in their argument. If C<\includeonly> is present in the -preamble, only those files are expanded into the document. However, -no recursion is done, i.e. C<\input> and C<\include> commands within -included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, -respectively, making it possible to organise files into old and new directories. ---flatten is applied recursively, so inputted files can contain further -C<\input> statements. - -Use of this option might result in prohibitive processing times for -larger documents, and the resulting difference document -no longer reflects the structure of the input documents. - -=item B<--help> or -B<-h> - -Show help text - -=item B<--version> - -Show version number - -=back - - - -=head2 Predefined styles - -=head2 Major types - -The major type determine the markup of plain text and some selected latex commands outside floats by defining the markup commands C<\DIFadd{...}> and C<\DIFdel{...}> . - -=over 10 - -=item C - -Added text is wavy-underlined and blue, discarded text is struck out and red -(Requires color and ulem packages). Overstriking does not work in displayed math equations such that deleted parts of equation are underlined, not struck out (this is a shortcoming inherent to the ulem package). - -=item C - -Added text is blue and set in sans-serif, and a red footnote is created for each discarded -piece of text. (Requires color package) - -=item C - -Like C but without the use of color. - -=item C - -Added text is blue and set in sans-serif, and discarded text is red and very small size. - -=item C - -Added tex is set in sans-serif, discarded text small and struck out - -=item C - -Added text is blue, and discarded text is red. Additionally, the changed text is marked with a bar in the margin (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color, ulem and changebar packages). - -=item C - -No mark up of text, but mark margins with changebars (Requires changebar package). - -=item C - -No visible markup (but generic markup commands will still be inserted. - -=back - -=head2 Subtypes - -The subtype defines the commands that are inserted at the begin and end of added or discarded blocks, irrespectively of whether these blocks contain text or commands (Defined commands: C<\DIFaddbegin, \DIFaddend, \DIFdelbegin, \DIFdelend>) - -=over 10 - -=item C - -No additional markup (Recommended choice) - -=item C - -Mark beginning and end of changed blocks with symbols in the margin nearby (using -the standard C<\marginpar> command - note that this sometimes moves somewhat -from the intended position. - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. -(It is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete, for example -with citation commands). - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. Note -that C only works with the dvips converter, e.g. not pdflatex. -(it is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete). - -=back - -=head2 Float Types - -Some of the markup used in the main text might cause problems when used within -floats (e.g. figures or tables). For this reason alternative versions of all -markup commands are used within floats. The float type defines these alternative commands. - -=over 10 - -=item C - -Use identical markup for text as in the main body, but set all commands marking the begin and end of changed blocks to null-commands. You have to choose this float type if your subtype is C as C<\marginpar> does not work properly within floats. - -=item C - -Mark additions the same way as in the main text. Deleted environments are marked by angular brackets \[ and \] and the deleted text is set in scriptscript size. This float type should always be used with the C and C markup types as the \footnote command does not work properly in floating environments. - -=item C - -Make no difference between the main text and floats. - -=back - - -=head2 Configuration Variables - -=over 10 - -=item C - -Minimum number of tokens required to form an independent block. This value is -used in the algorithm to detect changes of complete blocks by merging identical text parts of less than C to the preceding added and discarded parts. - -[ Default: 3 ] - -=item C - -Environments whose name matches the regular expression in C are -considered floats. Within these environments, the I markup commands -are replaced by their FL variaties. - -[ Default: S >] - -=item C - -Within environments whose name matches the regular expression in C -all latexdiff markup is removed (in pathologic cases this might lead to - inconsistent markup but this situation should be rare). - -[ Default: S >] - -=item C,C - -If both \begin and \end for a math environment (environment name matching C -or \[ and \]) -are within the same deleted block, they are replaced by a \begin and \end commands for C -rather than being commented out. - -[ Default: C=S >, C=S >] - -=item C,C - -as C,C but for equation arrays - -[ Default: C=S >, C=S >] - -=item C - -If a match to C is found within an inline math environment within a deleted or added block, then the inlined math -is surrounded by C<\mbox{>...C<}>. This is necessary as underlining does not work within inlined array environments. - -[ Default: C=S > - -=item C - -If a command in a deleted block which is also in the textcmd list matches C then an -additional command C<\addtocounter{>FC<}{-1}>, where F is the matching command, is appended in the diff file such that the numbering in the diff file remains synchronized with the -numbering in the new file. - -[ Default: C=C<(?:footnote|part|section|subsection> ... - -C<|subsubsection|paragraph|subparagraph)> ] - -=back - -=head1 COMMON PROBLEMS - -=over 10 - -=item Citations result in overfull boxes - -There is an incompatibility between the C package, which C uses for underlining and striking out in the UNDERLINE style, -the default style. In order to be able to mark up citations properly, they are placed with an C<\mbox> command in post-processing. As mboxes -cannot be broken across lines, this procedure frequently results in overfull boxes, possibly obscuring the content as it extends beyond the right margin. If this is a problem, you have two possibilities: - -1. Use C or C subtype markup (option C<-s COLOR>): If this markup is chosen, then changed citations are no longer marked up -with the wavy line (additions) or struck out (deletions), but are still highlighted in the appropriate color. - -2. Choose option C<--disable-citation-markup> which turns off the marking up of citations: deleted citations are no longer shown, and -added ctations are shown without markup. (This was the default behaviour of latexdiff at versions 0.6 and older) - -=item Changes in complicated mathematical equations result in latex processing errors - -Try options C<--math-markup=whole>. If even that fails, you can turn off mark up for equations with C<--math-markup=off>. - -=back - -=head1 BUGS - -Option allow-spaces not implemented entirely consistently. It breaks -the rules that number and type of white space does not matter, as -different numbers of inter-argument spaces are treated as significant. - -Please submit bug reports on the latexdiff project page I, -send them to user discussion list C (prior subscription -to list required, also on project webpage) -or send them to I. Include the serial number of I -(from comments at the top of the source or use B<--version>). If you come across latex -files that are error-free and conform to the specifications set out -above, and whose differencing still does not result in error-free -latex, please send me those files, ideally edited to only contain the -offending passage as long as that still reproduces the problem. If your -file relies on non-standard class files, you must include those. I will not -look at examples where I have trouble to latex the original files. - -=head1 SEE ALSO - -L, L - -=head1 PORTABILITY - -I does not make use of external commands and thus should run -on any platform supporting Perl 5.6 or higher. If files with encodings -other than ASCII or UTF-8 are processed, Perl 5.8 or higher is required. - -The standard version of I requires installation of the Perl package -C (available from I - -I) but a stand-alone -version, I, which has this package inlined, is available, too. -I requires the I command to be present. - -=head1 AUTHOR - -Version 1.0.2 -Copyright (C) 2004-2012 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 - -Contributors of fixes and additions: V. Kuhlmann, J. Paisley, N. Becker, T. Doerges, K. Huebner, -T. Connors, Sebastian Gouezel and many others. -Thanks to the many people who send in bug reports, feature suggestions, and other feedback. - -=cut - -__END__ -%%BEGIN SAFE COMMANDS -% Regex matching commands which can safely be in the -% argument of a \DIFadd or \DIFdel command (leave out the \) -arabic -dashbox -emph -fbox -framebox -hspace -math.* -makebox -mbox -pageref -ref -symbol -raisebox -rule -text.* -shortstack -usebox -dag -ddag -copyright -pounds -S -P -oe -OE -ae -AE -aa -AA -o -O -l -L -frac -ss -sqrt -ldots -cdots -vdots -ddots -alpha -beta -gamma -delta -epsilon -varepsilon -zeta -eta -theta -vartheta -iota -kappa -lambda -mu -nu -xi -pi -varpi -rho -varrho -sigma -varsigma -tau -upsilon -phi -varphi -chi -psi -omega -Gamma -Delta -Theta -Lambda -Xi -Pi -Sigma -Upsilon -Phi -Psi -Omega -ps -mp -times -div -ast -star -circ -bullet -cdot -cap -cup -uplus -sqcap -vee -wedge -setminus -wr -diamond -(?:big)?triangle.* -lhd -rhd -unlhd -unrhd -oplus -ominus -otimes -oslash -odot -bigcirc -d?dagger -amalg -leq -prec -preceq -ll -(?:sq)?su[bp]set(?:eq)? -in -vdash -geq -succ(?:eq)? -gg -ni -dashv -equiv -sim(?:eq)? -asymp -approx -cong -neq -doteq -propto -models -perp -mid -parallel -bowtie -Join -smile -frown -.*arrow -(?:long)?mapsto -.*harpoon.* -leadsto -aleph -hbar -imath -jmath -ell -wp -Re -Im -mho -prime -emptyset -nabla -surd -top -bot -angle -forall -exists -neg -flat -natural -sharp -backslash -partial -infty -Box -Diamond -triangle -clubsuit -diamondsuit -heartsuit -spadesuit -sum -prod -coprod -int -oint -big(?:sq)?c[au]p -bigvee -bigwedge -bigodot -bigotimes -bigoplus -biguplus -(?:arc)?(?:cos|sin|tan|cot)h? -csc -arg -deg -det -dim -exp -gcd -hom -inf -ker -lg -lim -liminf -limsup -ln -log -max -min -Pr -sec -sup -(SUPER|SUB)SCRIPTNB -(SUPER|SUB)SCRIPT -%%END SAFE COMMANDS - -%%BEGIN TEXT COMMANDS -% Regex matching commands with a text argument (leave out the \) -addcontents.* -cc -closing -chapter -dashbox -emph -encl -fbox -framebox -footnote -footnotetext -framebox -part -(sub){0,2}section\*? -(sub)?paragraph\*? -makebox -mbox -opening -parbox -raisebox -savebox -sbox -shortstack -signature -text.* -value -underline -sqrt -(SUPER|SUB)SCRIPT -%%END TEXT COMMANDS - -%%BEGIN CONTEXT1 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -caption -%%END CONTEXT1 COMMANDS - -%%BEGIN CONTEXT2 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -title -author -date -institute -%%END CONTEXT2 COMMANDS - - -%% TYPES (Commands for highlighting changed blocks) - -%DIF UNDERLINE PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}} -\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}} -%DIF END UNDERLINE PREAMBLE - -%DIF CTRADITIONAL PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} [..\footnote{removed: #1} ]}} -%DIF END CTRADITIONAL PREAMBLE - -%DIF TRADITIONAL PREAMBLE -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{[..\footnote{removed: #1} ]}} -%DIF END TRADITIONAL PREAMBLE - -%DIF CFONT PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} \scriptsize #1}} -%DIF END CFONT PREAMBLE - -%DIF FONTSTRIKE PREAMBLE -\RequirePackage[normalem]{ulem} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{\footnotesize \sout{#1}}} -%DIF END FONTSTRIKE PREAMBLE - -%DIF CCHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}#1}\protect\cbdelete} -%DIF END CCHANGEBAR PREAMBLE - -%DIF CFONTCHBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\sf #1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\scriptsize #1}\protect\cbdelete} -%DIF END CFONTCHBAR PREAMBLE - -%DIF CULINECHBAR PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage[dvips]{changebar} -\RequirePackage{color} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\uwave{#1}}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\sout{#1}}\protect\cbdelete} -%DIF END CULINECHBAR PREAMBLE - -%DIF CHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\providecommand{\DIFadd}[1]{\protect\cbstart{#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete} -%DIF END CHANGEBAR PREAMBLE - -%DIF INVISIBLE PREAMBLE -\providecommand{\DIFadd}[1]{#1} -\providecommand{\DIFdel}[1]{} -%DIF END INVISIBLE PREAMBLE - - -%% SUBTYPES (Markers for beginning and end of changed blocks) - -%DIF SAFE PREAMBLE -\providecommand{\DIFaddbegin}{} -\providecommand{\DIFaddend}{} -\providecommand{\DIFdelbegin}{} -\providecommand{\DIFdelend}{} -%DIF END SAFE PREAMBLE - -%DIF MARGIN PREAMBLE -\providecommand{\DIFaddbegin}{\protect\marginpar{a[}} -\providecommand{\DIFaddend}{\protect\marginpar{]}} -\providecommand{\DIFdelbegin}{\protect\marginpar{d[}} -\providecommand{\DIFdelend}{\protect\marginpar{]}} -%DIF END BRACKET PREAMBLE - -%DIF DVIPSCOL PREAMBLE -%Note: only works with dvips converter -\RequirePackage{color} -\RequirePackage{dvipscol} -\providecommand{\DIFaddbegin}{\protect\nogroupcolor{blue}} -\providecommand{\DIFaddend}{\protect\nogroupcolor{black}} -\providecommand{\DIFdelbegin}{\protect\nogroupcolor{red}} -\providecommand{\DIFdelend}{\protect\nogroupcolor{black}} -%DIF END DVIPSCOL PREAMBLE - -%DIF COLOR PREAMBLE -\RequirePackage{color} -\providecommand{\DIFaddbegin}{\protect\color{blue}} -\providecommand{\DIFaddend}{\protect\color{black}} -\providecommand{\DIFdelbegin}{\protect\color{red}} -\providecommand{\DIFdelend}{\protect\color{black}} -%DIF END COLOR PREAMBLE - - -%% FLOAT TYPES - -%DIF FLOATSAFE PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%DIF IDENTICAL PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{\DIFaddbegin} -\providecommand{\DIFaddendFL}{\DIFaddend} -\providecommand{\DIFdelbeginFL}{\DIFdelbegin} -\providecommand{\DIFdelendFL}{\DIFdelend} -%DIF END IDENTICAL PREAMBLE - -%DIF TRADITIONALSAFE PREAMBLE -% procidecommand color to make this work for TRADITIONAL and CTRADITIONAL -\providecommand{\color}[1]{} -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdel}[1]{{\protect\color{red}[..{\scriptsize {removed: #1}} ]}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%% SPECIAL PACKAGE PREAMBLE COMMANDS - -% Standard \DIFadd and \DIFdel are redefined as \DIFaddtex and \DIFdeltex -% when hyperref package is included. -%DIF HYPERREF PREAMBLE -\providecommand{\DIFadd}[1]{\texorpdfstring{\DIFaddtex{#1}}{#1}} -\providecommand{\DIFdel}[1]{\texorpdfstring{\DIFdeltex{#1}}{}} -%DIF END HYPERREF PACKAGE diff --git a/latexdiff-1.0.2/latexdiff-fast b/latexdiff-1.0.2/latexdiff-fast deleted file mode 100755 index 310ecc4..0000000 --- a/latexdiff-1.0.2/latexdiff-fast +++ /dev/null @@ -1,3961 +0,0 @@ -#!/usr/bin/env perl -##!/usr/bin/perl -w -# latexdiff - differences two latex files on the word level -# and produces a latex file with the differences marked up. -# -# Copyright (C) 2004-12 F J Tilmann (tilmann@gfz-potsdam.de, ftilmann@users.berlios.de) -# -# Project webpages: http://latexdiff.berlios.de/ -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# -# Version 1.0.1 - treat \big,\bigg etc. equivalently to \left and -# \right - include starred version in MATHENV - apply -# - flatten recursively and --flatten expansion is now -# aware of comments (thanks to Tim Connors for patch) -# - Change to post-processing for more reliability for -# deleted math environments -# - On linux systems, recognise and remove DOS style newlines -# - Provide markup for some special preamble commands (\title, -# \author,\date, -# - configurable by setting context2cmd -# - for styles using ulem package, remove \emph and \text.. from list of -# safe commands in order to allow linebreaks within the -# highlighted sections. -# - for ulem style, now show citations by enclosing them in \mbox commands. -# This unfortunately implies linebreaks within citations no longer function, -# so this functionality can be turned off (Option --disable-citation-markup). -# With --enable-citation-markup, the mbox markup is forced for other styles) -# - new substyle COLOR. This is particularly useful for marking up citations -# and some special post-processing is implemented to retain cite -# commands in deleted blocks. -# - four different levels of math-markup -# - Option --driver for choosing driver for modes employing changebar package -# - accept \\* as valid command (and other commands of form \.*). Also accept -# \ (backslashed newline) -# - some typo fixes, include commands defined in preamble as safe commands -# (Sebastian Gouezel) -# - include compared filenames as comments as line 2 and 3 of -# the preamble (can be modified with option --label, and suppressed with -# --no-label), option --visible-label to show files in generated pdf or dvi -# at the beginning of main document -# -# Version 0.5 A number of minor improvements based on feedback -# Deleted blocks are now shown before added blocks -# Package specific processing -# -# Version 0.43 unreleased typo in list of styles at the end -# Add protect to all \cbstart, \cbend commands -# More robust substitution of deleted math commands -# -# Version 0.42 November 06 Bug fixes only -# -# Version 0.4 March 06 option for fast differencing using UNIX diff command, several minor bug fixes (\par bug, improved highlighting of textcmds) -# -# Version 0.3 August 05 improved parsing of displayed math, --allow-spaces -# option, several minor bug fixes -# -# Version 0.25 October 04 Fix bug with deleted equations, add math mode commands to safecmd, add | to allowed interpunctuation signs -# Version 0.2 September 04 extension to utf-8 and variable encodings -# Version 0.1 August 04 First public release - -# Inserted block for differenceing -# use Algorithm::Diff qw(traverse_sequences); -# in standard version -# The following BEGIN block contains a verbatim copy of -# Ned Konz' Algorithm::Diff package version 1.15 except -# that subroutine _longestCommonSubsequence has been replace by -# a routine which internally uses the UNIX diff command for -# the differencing rather than the Perl routines if the -# length of the sequences exceeds some threshold. -# Also, all POD documentation has been stripped out. -# -# (the distribution on which this modification is based is available -# from http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15 -# the most recent version can be found via http://search.cpan.org/search?module=Algorithm::Diff ) -# Please note that the LICENCSE for Algorithm::Diff : -# "Copyright (c) 2000-2002 Ned Konz. All rights reserved. -# This program is free software; -# you can redistribute it and/or modify it under the same terms -# as Perl itself." -# The fast-differencing version of latexdiff is provided as a convenience -# for latex users under Unix-like systems which have a 'diff' command. -# If you believe -# the inlining of Algorithm::Diff violates its license please contact -# me and I will modify the latexdiff distribution accordingly. -# Frederik Tilmann (tilmann@esc.cam.ac.uk) -# Jonathan Paisley is acknowledged for the idea of using the system diff -# command to achieve shorter running times -BEGIN { -package Algorithm::Diff; -use strict; -use vars qw($VERSION @EXPORT_OK @ISA @EXPORT); -use integer; # see below in _replaceNextLargerWith() for mod to make - # if you don't use this -require Exporter; -@ISA = qw(Exporter); -@EXPORT = qw(); -@EXPORT_OK = qw(LCS diff traverse_sequences traverse_balanced sdiff); -$VERSION = sprintf('%d.%02d fast', (q$Revision: 1.15 $ =~ /\d+/g)); - -# Global parameters - -use File::Temp qw/tempfile/; -# if larger number of elements in longestCommonSubsequence smaller than -# this number, then use internal algorithm, otherwise use UNIX diff -use constant THRESHOLD => 100 ; -# Detect whether diff --minimal option is available -# if yes we use it -use constant MINIMAL => ( system('diff','--minimal','/dev/null','/dev/null') >> 8 ==0 ? "--minimal" : "" ) ; - - - -# McIlroy-Hunt diff algorithm -# Adapted from the Smalltalk code of Mario I. Wolczko, -# by Ned Konz, perl@bike-nomad.com - - -# Create a hash that maps each element of $aCollection to the set of positions -# it occupies in $aCollection, restricted to the elements within the range of -# indexes specified by $start and $end. -# The fourth parameter is a subroutine reference that will be called to -# generate a string to use as a key. -# Additional parameters, if any, will be passed to this subroutine. -# -# my $hashRef = _withPositionsOfInInterval( \@array, $start, $end, $keyGen ); - -sub _withPositionsOfInInterval -{ - my $aCollection = shift; # array ref - my $start = shift; - my $end = shift; - my $keyGen = shift; - my %d; - my $index; - for ( $index = $start ; $index <= $end ; $index++ ) - { - my $element = $aCollection->[$index]; - my $key = &$keyGen( $element, @_ ); - if ( exists( $d{$key} ) ) - { - unshift ( @{ $d{$key} }, $index ); - } - else - { - $d{$key} = [$index]; - } - } - return wantarray ? %d : \%d; -} - -# Find the place at which aValue would normally be inserted into the array. If -# that place is already occupied by aValue, do nothing, and return undef. If -# the place does not exist (i.e., it is off the end of the array), add it to -# the end, otherwise replace the element at that point with aValue. -# It is assumed that the array's values are numeric. -# This is where the bulk (75%) of the time is spent in this module, so try to -# make it fast! - -sub _replaceNextLargerWith -{ - my ( $array, $aValue, $high ) = @_; - $high ||= $#$array; - - # off the end? - if ( $high == -1 || $aValue > $array->[-1] ) - { - push ( @$array, $aValue ); - return $high + 1; - } - - # binary search for insertion point... - my $low = 0; - my $index; - my $found; - while ( $low <= $high ) - { - $index = ( $high + $low ) / 2; - - # $index = int(( $high + $low ) / 2); # without 'use integer' - $found = $array->[$index]; - - if ( $aValue == $found ) - { - return undef; - } - elsif ( $aValue > $found ) - { - $low = $index + 1; - } - else - { - $high = $index - 1; - } - } - - # now insertion point is in $low. - $array->[$low] = $aValue; # overwrite next larger - return $low; -} - -# This method computes the longest common subsequence in $a and $b. - -# Result is array or ref, whose contents is such that -# $a->[ $i ] == $b->[ $result[ $i ] ] -# foreach $i in ( 0 .. $#result ) if $result[ $i ] is defined. - -# An additional argument may be passed; this is a hash or key generating -# function that should return a string that uniquely identifies the given -# element. It should be the case that if the key is the same, the elements -# will compare the same. If this parameter is undef or missing, the key -# will be the element as a string. - -# By default, comparisons will use "eq" and elements will be turned into keys -# using the default stringizing operator '""'. - -# Additional parameters, if any, will be passed to the key generation routine. - -sub _longestCommonSubsequence -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $keyGen = shift; # code ref - my $compare; # code ref - - # set up code refs - # Note that these are optimized. - if ( !defined($keyGen) ) # optimize for strings - { - $keyGen = sub { $_[0] }; - $compare = sub { my ( $a, $b ) = @_; $a eq $b }; - } - else - { - $compare = sub { - my $a = shift; - my $b = shift; - &$keyGen( $a, @_ ) eq &$keyGen( $b, @_ ); - }; - } - - my ( $aStart, $aFinish, $bStart, $bFinish, $matchVector ) = - ( 0, $#$a, 0, $#$b, [] ); - - # Check whether to use internal routine (small number of elements) - # or use it as a wrapper for UNIX diff - if ( ( $#$a > $#$b ? $#$a : $#$b) < THRESHOLD ) { - ### print STDERR "DEBUG: regular longestCommonSubsequence\n"; - # First we prune off any common elements at the beginning - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aStart], $b->[$bStart], @_ ) ) - { - $matchVector->[ $aStart++ ] = $bStart++; - } - - # now the end - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aFinish], $b->[$bFinish], @_ ) ) - { - $matchVector->[ $aFinish-- ] = $bFinish--; - } - - # Now compute the equivalence classes of positions of elements - my $bMatches = - _withPositionsOfInInterval( $b, $bStart, $bFinish, $keyGen, @_ ); - my $thresh = []; - my $links = []; - - my ( $i, $ai, $j, $k ); - for ( $i = $aStart ; $i <= $aFinish ; $i++ ) - { - $ai = &$keyGen( $a->[$i], @_ ); - if ( exists( $bMatches->{$ai} ) ) - { - $k = 0; - for $j ( @{ $bMatches->{$ai} } ) - { - - # optimization: most of the time this will be true - if ( $k and $thresh->[$k] > $j and $thresh->[ $k - 1 ] < $j ) - { - $thresh->[$k] = $j; - } - else - { - $k = _replaceNextLargerWith( $thresh, $j, $k ); - } - - # oddly, it's faster to always test this (CPU cache?). - if ( defined($k) ) - { - $links->[$k] = - [ ( $k ? $links->[ $k - 1 ] : undef ), $i, $j ]; - } - } - } - } - - if (@$thresh) - { - for ( my $link = $links->[$#$thresh] ; $link ; $link = $link->[0] ) - { - $matchVector->[ $link->[1] ] = $link->[2]; - } - } - } - else { - my ($fha,$fhb,$fna,$fnb,$ele,$key); - my ($alines,$blines,$alb,$alf,$blb,$blf); - my ($minimal)=MINIMAL; - # large number of elements, use system diff - ### print STDERR "DEBUG: fast (diff) longestCommonSubsequence\n"; - - ($fha,$fna)=tempfile("DiffA-XXXX") or die "_longestCommonSubsequence: Cannot open tempfile for sequence A"; - ($fhb,$fnb)=tempfile("DiffB-XXXX") or die "_longestCommonSubsequence: Cannot open tempfile for sequence B"; - # prepare sequence A - foreach $ele ( @$a ) { - $key=&$keyGen( $ele, @_ ); - $key =~ s/\\/\\\\/g ; - $key =~ s/\n/\\n/sg ; - print $fha "$key\n" ; - } - close($fha); - # prepare sequence B - foreach $ele ( @$b ) { - $key=&$keyGen( $ele, @_ ); - $key =~ s/\\/\\\\/g ; - $key =~ s/\n/\\n/sg ; - print $fhb "$key\n" ; - } - close($fhb); - - open(DIFFPIPE, "diff $minimal $fna $fnb |") or die "_longestCommonSubsequence: Cannot launch diff process. $!" ; - # The diff line numbering begins with 1, but Perl subscripts start with 0 - # We follow the diff numbering but substract 1 when assigning to matchVector - $aStart++; $bStart++ ; $aFinish++ ; $bFinish++ ; - while( ) { - if ( ($alines,$blines) = ( m/^(\d*(?:,\d*)?)?c(\d*(?:,\d*)?)?$/ ) ) { - ($alb,$alf)=split(/,/,$alines); - ($blb,$blf)=split(/,/,$blines); - $alf=$alb unless defined($alf); - $blf=$blb unless defined($blf); - while($aStart < $alb ) { - $matchVector->[ -1 + $aStart++ ] = -1 + $bStart++ ; - } - # check for consistency - $bStart==$blb or die "_longestCommonSubsequence: Fatal error in interpreting diff output: Inconsistency in changed sequence"; - $aStart=$alf+1; - $bStart=$blf+1; - } - elsif ( ($alb,$blines) = ( m/^(\d*)a(\d*(?:,\d*)?)$/ ) ) { - ($blb,$blf)=split(/,/,$blines); - $blf=$blb unless defined($blf); - while ( $bStart < $blb ) { - $matchVector->[ -1 + $aStart++ ] = -1 + $bStart++ ; - } - $aStart==$alb+1 or die "_longestCommonSubsequence: Fatal error in interpreting diff output: Inconsistency in appended sequence near elements $aStart and $bStart"; - $bStart=$blf+1; - } - elsif ( ($alines,$blb) = ( m/^(\d*(?:,\d*)?)d(\d*)$/ ) ) { - ($alb,$alf)=split(/,/,$alines); - $alf=$alb unless defined($alf); - while ( $aStart < $alb ) { - $matchVector->[ -1 + $aStart++ ] = -1 + $bStart++ ; - } - $bStart==$blb+1 or die "_longestCommonSubsequence: Fatal error in interpreting diff output: Inconsistency in deleted sequence near elements $aStart and $bStart"; - $aStart=$alf+1; - } - elsif ( m/^Binary files/ ) { - # if diff reports it is a binary file force --text mode. I do not like - # to always use this option because it is probably only available in GNU diff - open(DIFFPIPE, "diff --text $fna $fnb |") or die "Cannot launch diff process. $!" ; - } - # Default: just skip line - } - while ($aStart <= $aFinish ) { - $matchVector->[ -1 + $aStart++ ] = -1 + $bStart++ ; - } - $bStart==$bFinish+1 or die "_longestCommonSubsequence: Fatal error in interpreting diff output: Inconsistency at end"; - close DIFFPIPE; - # check whether a system error has occurred or return status is greater than or equal to 5 - if ( $! || ($? >> 8) > 5) { - print STDERR "diff process failed with exit code ", ($? >> 8), " $!\n"; - die; - } - unlink $fna,$fnb ; - } - return wantarray ? @$matchVector : $matchVector; -} - -sub traverse_sequences -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $finishedACallback = $callbacks->{'A_FINISHED'}; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $finishedBCallback = $callbacks->{'B_FINISHED'}; - my $matchVector = _longestCommonSubsequence( $a, $b, $keyGen, @_ ); - - # Process all the lines in @$matchVector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai; - - for ( $ai = 0 ; $ai <= $#$matchVector ; $ai++ ) - { - my $bLine = $matchVector->[$ai]; - if ( defined($bLine) ) # matched - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi < $bLine; - &$matchCallback( $ai, $bi++, @_ ); - } - else - { - &$discardACallback( $ai, $bi, @_ ); - } - } - - # The last entry (if any) processed was a match. - # $ai and $bi point just past the last matching lines in their sequences. - - while ( $ai <= $lastA or $bi <= $lastB ) - { - - # last A? - if ( $ai == $lastA + 1 and $bi <= $lastB ) - { - if ( defined($finishedACallback) ) - { - &$finishedACallback( $lastA, @_ ); - $finishedACallback = undef; - } - else - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi <= $lastB; - } - } - - # last B? - if ( $bi == $lastB + 1 and $ai <= $lastA ) - { - if ( defined($finishedBCallback) ) - { - &$finishedBCallback( $lastB, @_ ); - $finishedBCallback = undef; - } - else - { - &$discardACallback( $ai++, $bi, @_ ) while $ai <= $lastA; - } - } - - &$discardACallback( $ai++, $bi, @_ ) if $ai <= $lastA; - &$discardBCallback( $ai, $bi++, @_ ) if $bi <= $lastB; - } - - return 1; -} - -sub traverse_balanced -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $changeCallback = $callbacks->{'CHANGE'}; - my $matchVector = _longestCommonSubsequence( $a, $b, $keyGen, @_ ); - - # Process all the lines in match vector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai = 0; - my $ma = -1; - my $mb; - - while (1) - { - - # Find next match indices $ma and $mb - do { $ma++ } while ( $ma <= $#$matchVector && !defined $matchVector->[$ma] ); - - last if $ma > $#$matchVector; # end of matchVector? - $mb = $matchVector->[$ma]; - - # Proceed with discard a/b or change events until - # next match - while ( $ai < $ma || $bi < $mb ) - { - - if ( $ai < $ma && $bi < $mb ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai < $ma ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi < $mb - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - # Match - &$matchCallback( $ai++, $bi++, @_ ); - } - - while ( $ai <= $lastA || $bi <= $lastB ) - { - if ( $ai <= $lastA && $bi <= $lastB ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai <= $lastA ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi <= $lastB - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - return 1; -} - -sub LCS -{ - my $a = shift; # array ref - my $matchVector = _longestCommonSubsequence( $a, @_ ); - my @retval; - my $i; - for ( $i = 0 ; $i <= $#$matchVector ; $i++ ) - { - if ( defined( $matchVector->[$i] ) ) - { - push ( @retval, $a->[$i] ); - } - } - return wantarray ? @retval : \@retval; -} - -sub diff -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $hunk = []; - my $discard = sub { push ( @$hunk, [ '-', $_[0], $a->[ $_[0] ] ] ) }; - my $add = sub { push ( @$hunk, [ '+', $_[1], $b->[ $_[1] ] ] ) }; - my $match = sub { push ( @$retval, $hunk ) if scalar(@$hunk); $hunk = [] }; - traverse_sequences( $a, $b, - { MATCH => $match, DISCARD_A => $discard, DISCARD_B => $add }, @_ ); - &$match(); - return wantarray ? @$retval : $retval; -} - -sub sdiff -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $discard = sub { push ( @$retval, [ '-', $a->[ $_[0] ], "" ] ) }; - my $add = sub { push ( @$retval, [ '+', "", $b->[ $_[1] ] ] ) }; - my $change = sub { - push ( @$retval, [ 'c', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - my $match = sub { - push ( @$retval, [ 'u', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - traverse_balanced( - $a, - $b, - { - MATCH => $match, - DISCARD_A => $discard, - DISCARD_B => $add, - CHANGE => $change, - }, - @_ - ); - return wantarray ? @$retval : $retval; -} - -1; -} -import Algorithm::Diff qw(traverse_sequences); -# End of inserted block for stand-alone version - - -use Getopt::Long ; -use strict ; -use warnings; -use utf8 ; - -my ($algodiffversion)=split(/ /,$Algorithm::Diff::VERSION); - - -my ($versionstring)=< 0, - WHOLE => 1, - COARSE => 2, - FINE => 3 -}; - - -my (@configlist,@labels, - @appendsafelist,@excludesafelist, - @appendtextlist,@excludetextlist, - @appendcontext1list,@appendcontext2list, - @packagelist); -my ($assign,@config); -# Hash where keys corresponds to the names of all included packages (including the documentclass as another package -# the optional arguments to the package are the values of the hash elements -my ($pkg,%packages); -# Defaults -$type='UNDERLINE'; -$subtype='SAFE'; -$floattype='FLOATSAFE'; -$mathmarkup=COARSE; - -$verbose=0; -# output debug and intermediate files, set to 0 in final distribution -$debug=0; -# define character properties -sub IsNonAsciiPunct { return <<'END' # Unicode punctuation but excluding ASCII punctuation -+utf8::IsPunct --utf8::IsASCII -END -} -sub IsNonAsciiS { return <<'END' # Unicode symbol but excluding ASCII -+utf8::IsS --utf8::IsASCII -END -} - - -my %verbhash; - -Getopt::Long::Configure('bundling'); -GetOptions('type|t=s' => \$type, - 'subtype|s=s' => \$subtype, - 'floattype|f=s' => \$floattype, - 'config|c=s' => \@configlist, - 'preamble|p=s' => \$preamblefile, - 'encoding|e=s' => \$encoding, - 'label|L=s' => \@labels, - 'no-label' => \$nolabel, - 'visible-label' => \$visiblelabel, - 'exclude-safecmd|A=s' => \@excludesafelist, - 'replace-safecmd=s' => \$replacesafe, - 'append-safecmd|a=s' => \@appendsafelist, - 'exclude-textcmd|X=s' => \@excludetextlist, - 'replace-textcmd=s' => \$replacetext, - 'append-textcmd|x=s' => \@appendtextlist, - 'replace-context1cmd=s' => \$replacecontext1, - 'append-context1cmd=s' => \@appendcontext1list, - 'replace-context2cmd=s' => \$replacecontext2, - 'append-context2cmd=s' => \@appendcontext2list, - 'show-preamble' => \$showpreamble, - 'show-safecmd' => \$showsafe, - 'show-textcmd' => \$showtext, - 'show-config' => \$showconfig, - 'show-all' => \$showall, - 'packages=s' => \@packagelist, - 'allow-spaces' => \$allowspaces, - 'math-markup=s' => \$mathmarkup, - 'enable-citation-markup' => \$enablecitmark, - 'disable-citation-markup' => \$disablecitmark, - 'verbose|V' => \$verbose, - 'ignore-warnings' => \$ignorewarnings, - 'driver=s'=> \$driver, - 'flatten' => \$flatten, - 'version' => \$version, - 'help|h|H' => \$help); - -if ( $help ) { - usage() ; -} - - -if ( $version ) { - die $versionstring ; -} - -print STDERR $versionstring if $verbose; - -if (defined($showall)){ - $showpreamble=$showsafe=$showtext=$showconfig=1; -} - -if (defined($mathmarkup)) { - $mathmarkup=~tr/a-z/A-Z/; - if ( $mathmarkup eq 'OFF' ){ - $mathmarkup=OFF; - } elsif ( $mathmarkup eq 'WHOLE' ){ - $mathmarkup=WHOLE; - } elsif ( $mathmarkup eq 'COARSE' ){ - $mathmarkup=COARSE; - } elsif ( $mathmarkup eq 'FINE' ){ - $mathmarkup=FINE; - } elsif ( $mathmarkup !~ m/^[0123]$/ ) { - die "Illegal value: ($mathmarkup) for option--math-markup. Possible values: OFF,WHOLE,COARSE,FINE,0- "; - } - # else use numerical value -} - -# setting extra preamble commands -if (defined($preamblefile)) { - $latexdiffpreamble=join "\n",(extrapream($preamblefile),""); -} else { - $latexdiffpreamble=join "\n",(extrapream($type,$subtype,$floattype),""); -} - -if ( defined($driver) ) { - # for changebar only - $latexdiffpreamble=~s/\[dvips\]/[$driver]/sg; -} -# setting up @SAFECMDLIST and @SAFECMDEXCL -if (defined($replacesafe)) { - init_regex_arr_ext(\@SAFECMDLIST,$replacesafe); -} else { - init_regex_arr_data(\@SAFECMDLIST, "SAFE COMMANDS"); -} -foreach $appendsafe ( @appendsafelist ) { - init_regex_arr_ext(\@SAFECMDLIST, $appendsafe); -} -foreach $excludesafe ( @excludesafelist ) { - init_regex_arr_ext(\@SAFECMDEXCL, $excludesafe); -} - -# Special: treat all cite commands as safe except in UNDERLINE and FONTSTRIKE mode -# (there is a conflict between citation and ulem package, see -# package documentation) -# Use post-processing - -if ( uc($type) ne "UNDERLINE" && uc($type) ne "FONTSTRIKE" && uc($type) ne "CULINECHBAR" ) { - push (@SAFECMDLIST, qr/^cite.*$/); -} else { - ### Experimental: disable text and emph commands - push (@SAFECMDLIST, qr/^cite.*$/) unless $disablecitmark; - push(@SAFECMDEXCL, qr/^emph$/, qr/^text..$/); - # replace \cite{..} by \mbox{\cite{..}} in added or deleted blocks in post-processing - if ( uc($subtype) eq "COLOR" or uc($subtype) eq "DVIPSCOL" ) { - # remove \cite command again from list of safe commands - pop @SAFECMDLIST; - # deleted cite commands - $CITE2CMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite-type commands which should be reinstated in deleted blocks - } else { - $CITECMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite commands which need to be protected within an mbox in UNDERLINE and other modes using ulem - } -} -$CITECMD='(?:cite\w*|nocite)' if $enablecitmark ; # as above for explicit selection - -# setting up @TEXTCMDLIST and @TEXTCMDEXCL -if (defined($replacetext)) { - init_regex_arr_ext(\@TEXTCMDLIST,$replacetext); -} else { - init_regex_arr_data(\@TEXTCMDLIST, "TEXT COMMANDS"); -} -foreach $appendtext ( @appendtextlist ) { - init_regex_arr_ext(\@TEXTCMDLIST, $appendtext); -} -foreach $excludetext ( @excludetextlist ) { - init_regex_arr_ext(\@TEXTCMDEXCL, $excludetext); -} - - -# setting up @CONTEXT1CMDLIST ( @CONTEXT1CMDEXCL exist but is always empty ) -if (defined($replacecontext1)) { - init_regex_arr_ext(\@CONTEXT1CMDLIST,$replacecontext1); -} else { - init_regex_arr_data(\@CONTEXT1CMDLIST, "CONTEXT1 COMMANDS"); -} -foreach $appendcontext1 ( @appendcontext1list ) { - init_regex_arr_ext(\@CONTEXT1CMDLIST, $appendcontext1); -} - - -# setting up @CONTEXT2CMDLIST ( @CONTEXT2CMDEXCL exist but is always empty ) -if (defined($replacecontext2)) { - init_regex_arr_ext(\@CONTEXT2CMDLIST,$replacecontext2); -} else { - init_regex_arr_data(\@CONTEXT2CMDLIST, "CONTEXT2 COMMANDS"); -} -foreach $appendcontext2 ( @appendcontext2list ) { - init_regex_arr_ext(\@CONTEXT2CMDLIST, $appendcontext2); -} - -# setting configuration variables -@config=(); -foreach $config ( @configlist ) { - if (-f $config ) { - open(FILE,$config) or die ("Couldn't open configuration file $config: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@config,$_); - } - close(FILE); - } - else { -# foreach ( split(",",$config) ) { -# push @config,$_; -# } - push @config,split(",",$config) - } -} -foreach $assign ( @config ) { - $assign=~ m/\s*(\w*)\s*=\s*(\S*)\s*$/ or die "Illegal assignment $assign in configuration list (must be variable=value)"; - if ( $1 eq "MINWORDSBLOCK" ) { $MINWORDSBLOCK = $2; } - elsif ( $1 eq "FLOATENV" ) { $FLOATENV = $2 ; } - elsif ( $1 eq "PICTUREENV" ) { $PICTUREENV = $2 ; } - elsif ( $1 eq "MATHENV" ) { $MATHENV = $2 ; } - elsif ( $1 eq "MATHREPL" ) { $MATHREPL = $2 ; } - elsif ( $1 eq "MATHARRENV" ) { $MATHARRENV = $2 ; } - elsif ( $1 eq "MATHARRREPL" ) { $MATHARRREPL = $2 ; } - elsif ( $1 eq "ARRENV" ) { $ARRENV = $2 ; } - elsif ( $1 eq "COUNTERCMD" ) { $COUNTERCMD = $2 ; } - else { die "Unknown variable $1 in assignment.";} -} - -if ( $mathmarkup == COARSE || $mathmarkup == WHOLE ) { - push(@MATHTEXTCMDLIST,qr/^MATHBLOCK(?:$MATHENV|$MATHARRENV|SQUAREBRACKET)$/); -} - - - -foreach $pkg ( @packagelist ) { - map { $packages{$_}="" } split(/,/,$pkg) ; -} - -if ($showpreamble) { - print "\nPreamble commands:\n"; - print $latexdiffpreamble ; -} - -if ($showsafe) { - print "\nCommands safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE (unless excluded):\n"; - print_regex_arr(@SAFECMDLIST); - print "\nCommands not safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE :\n"; - print_regex_arr(@SAFECMDEXCL); -} - -if ($showtext) { - print "\nCommands with last argument textual (unless excluded) and safe in every context:\n"; - print_regex_arr(@TEXTCMDLIST); - print "\nContext1 commands (last argument textual, command will be disabled in deleted passages, last argument will be shown as plain text):\n"; - print_regex_arr(@CONTEXT1CMDLIST); - print "\nContext2 commands (last argument textual, command and its argument will be disabled in deleted passages):\n"; - print_regex_arr(@CONTEXT2CMDLIST); - print "\nExclude list of Commands with last argument not textual (overrides patterns above):\n"; - print_regex_arr(@TEXTCMDEXCL); -} - - -if ($showconfig) { - print "Configuration variables:\n"; - print "MINWORDSBLOCK=$MINWORDSBLOCK\n"; - print "FLOATENV=$FLOATENV\n"; - print "PICTUREENV=$PICTUREENV\n"; - print "MATHENV=$MATHENV\n"; - print "MATHREPL=$MATHREPL\n"; - print "MATHARRENV=$MATHARRENV\n"; - print "MATHARRREPL=$MATHARRREPL\n"; - print "ARRENV=$ARRENV\n"; - print "COUNTERCMD=$COUNTERCMD\n"; -} -if ($showconfig || $showtext || $showsafe || $showpreamble) { - exit 0; } -if ( @ARGV != 2 ) { - print STDERR "2 and only 2 non-option arguments required. Write latexdiff -h to get help\n"; - exit(2); -} - -# Are extra spaces between command arguments permissible? -my $extraspace; -if ($allowspaces) { - $extraspace='\s*'; -} else { - $extraspace=''; -} - -# append context lists to text lists (as text property is implied) -push @TEXTCMDLIST, @CONTEXT1CMDLIST; -push @TEXTCMDLIST, @CONTEXT2CMDLIST; - -push @TEXTCMDLIST, @MATHTEXTCMDLIST if $mathmarkup==COARSE; - -# internal additions to SAFECMDLIST -push(@SAFECMDLIST, qr/^QLEFTBRACE$/, qr/^QRIGHTBRACE$/); - - -# Patterns. These are used by some of the subroutines, too -# I can only define them down here because value of extraspace depends on an option - my $pat0 = '(?:[^{}])*'; - my $pat1 = '(?:[^{}]|\{'.$pat0.'\})*'; - my $pat2 = '(?:[^{}]|\{'.$pat1.'\})*'; - my $pat3 = '(?:[^{}]|\{'.$pat2.'\})*'; - my $pat4 = '(?:[^{}]|\{'.$pat3.'\})*'; - my $pat5 = '(?:[^{}]|\{'.$pat4.'\})*'; - my $pat6 = '(?:[^{}]|\{'.$pat5.'\})*'; - my $brat0 = '(?:[^\[\]]|\\\[|\\\])*'; - - my $quotemarks = '(?:\'\')|(?:\`\`)'; - my $punct='[0.,\/\'\`:;\"\?\(\)\[\]!~\p{IsNonAsciiPunct}\p{IsNonAsciiS}]'; - my $number='-?\d*\.\d*'; - my $mathpunct='[+=<>\-\|]'; - my $and = '&'; - my $coords= '[\-.,\s\d]*'; -# word: sequence of letters or accents followed by letter - my $word='(?:[-\w\d*]|\\\\[\"\'\`~^][A-Za-z\*])+'; - my $cmdleftright='\\\\(?:left|right|[Bb]igg?[lrm]?|middle)\s*(?:[()\[\]|]|\\\\(?:[|{}]|\w+))'; - - my $cmdoptseq='\\\\[\w\d\*]+'.$extraspace.'(?:(?:\['.$brat0.'\]|\{'. $pat6 . '\}|\(' . $coords .'\))'.$extraspace.')*'; - my $backslashnl='\\\\\n'; - my $oneletcmd='\\\\.\*?(?:\['.$brat0.'\]|\{'. $pat6 . '\})*'; - my $math='\$(?:[^$]|\\\$)*?\$|\\\\[(].*?\\\\[)]'; -## the current maths command cannot cope with newline within the math expression - - my $comment='%.*?\n'; - my $pat=qr/(?:\A\s*)?(?:${and}|${quotemarks}|${number}|${word}|$cmdleftright|${cmdoptseq}|${math}|${backslashnl}|${oneletcmd}|${comment}|${punct}|${mathpunct}|\{|\})\s*/ ; - - - -# now we are done setting up and can start working -my ($oldfile, $newfile) = @ARGV; -# check for existence of input files -if ( ! -e $oldfile ) { - die "Input file $oldfile does not exist."; -} -if ( ! -e $newfile ) { - die "Input file $newfile does not exist."; -} - - -# set the labels to be included into the file -my ($oldtime,$newtime,$oldlabel,$newlabel); -if (defined($labels[0])) { - $oldlabel=$labels[0] ; -} else { - $oldtime=localtime((stat($oldfile))[9]); - $oldlabel="$oldfile " . " "x(length($newfile)-length($oldfile)) . $oldtime; -} -if (defined($labels[1])) { - $newlabel=$labels[1] ; -} else { - $newtime=localtime((stat($newfile))[9]); - $newlabel="$newfile " . " "x(length($oldfile)-length($newfile)) . $newtime; -} - -$encoding=guess_encoding($newfile) unless defined($encoding); - -$encoding = "utf8" if $encoding =~ m/^utf8/i ; -if (lc($encoding) eq "utf8" ) { - binmode(STDOUT, ":utf8"); - binmode(STDERR, ":utf8"); -} - -$old=read_file_with_encoding($oldfile,$encoding); -$new=read_file_with_encoding($newfile,$encoding); - - - - -# reset time -exetime(1); -($oldpreamble,$oldbody,$oldpost)=splitdoc($old,'\\\\begin\{document\}','\\\\end\{document\}'); - - -($newpreamble,$newbody,$newpost)=splitdoc($new,'\\\\begin\{document\}','\\\\end\{document\}'); - - -if ($flatten) { - $oldbody=flatten($oldbody,$oldpreamble,$oldfile,$encoding); - $newbody=flatten($newbody,$newpreamble,$newfile,$encoding); -} - -my @auxlines; -if ( length $oldpreamble && length $newpreamble ) { - # pre-process preamble by looking for commands used in \maketitle (title, author, date etc commands) - # and marking up content with latexdiff markup - @auxlines=preprocess_preamble($oldpreamble,$newpreamble); - - @oldpreamble = split /\n/, $oldpreamble; - @newpreamble = split /\n/, $newpreamble; - - # If a command is defined in the preamble of the new file, and only uses safe commands, then it can be considered to be safe) (contribution S. Gouezel) - # Base this assessment on the new preamble - add_safe_commands($newpreamble); - - %packages=list_packages(@newpreamble) unless %packages; - if (defined $packages{"hyperref"} ) { - print STDERR "hyperref package detected.\n" if $verbose ; - $latexdiffpreamble =~ s/\{\\DIFadd\}/{\\DIFaddtex}/g; - $latexdiffpreamble =~ s/\{\\DIFdel\}/{\\DIFdeltex}/g; - $latexdiffpreamble .= join "\n",(extrapream("HYPERREF"),""); - } - print STDERR "Differencing preamble.\n" if $verbose; - - # insert dummy first line such that line count begins with line 1 (rather than perl's line 0) - just so that line numbers inserted by linediff are correct - unshift @newpreamble,''; - unshift @oldpreamble,''; - @diffpreamble = linediff(\@oldpreamble, \@newpreamble); - # remove dummy line again - shift @diffpreamble; - # add filenames, modification time and latexdiff mark - defined($nolabel) or splice @diffpreamble,1,0, - "%DIF LATEXDIFF DIFFERENCE FILE", - ,"%DIF DEL $oldlabel", - "%DIF ADD $newlabel"; - if ( @auxlines ) { - push @diffpreamble,"%DIF DELETED TITLE COMMANDS FOR MARKUP"; - push @diffpreamble,join("\n",@auxlines); - } - push @diffpreamble,$latexdiffpreamble; - push @diffpreamble,'\begin{document}'; -} -elsif ( !length $oldpreamble && !length $newpreamble ) { - @diffpreamble=(); -} else { - print STDERR "Either both texts must have preamble or neither text must have the preamble.\n"; - exit(2); -} - -if (defined $packages{"amsmath"} or defined $packages{"amsart"} or defined $packages{"amsbook"} ) { - print STDERR "amsmath package detected.\n" if $verbose ; - $MATHARRREPL='align*'; -} - -print STDERR "Preprocessing body. " if $verbose; -my ($oldleadin,$newleadin)=preprocess($oldbody,$newbody); - - -# run difference algorithm -@diffbody=bodydiff($oldbody, $newbody); -$diffbo=join("",@diffbody); -if ( $debug ) { - open(RAWDIFF,">","latexdiff.debug.bodydiff"); - print RAWDIFF $diffbo; - close(RAWDIFF); -} -print STDERR "(",exetime()," s)\n","Postprocessing body. \n " if $verbose; -postprocess($diffbo); -$diffall =join("\n",@diffpreamble) ; -# add visible labels -if (defined($visiblelabel)) { - # Give information right after \begin{document} (or at the beginning of the text for files without preamble - ### if \date command is used, add information to \date argument, otherwise give right after \begin{document} - ### $diffall=~s/(\\date$extraspace(?:\[$brat0\])?$extraspace)\{($pat6)\}/$1\{$2 \\ LATEXDIFF comparison \\ Old: $oldlabel \\ New: $newlabel \}/ or - $diffbo = "\\begin{verbatim}LATEXDIFF comparison\nOld: $oldlabel\nNew: $newlabel\\end{verbatim}\n$diffbo" ; -} - -$diffall .= "$newleadin$diffbo" ; -$diffall .= "\\end{document}$newpost" if length $newpreamble ; -if ( lc($encoding) ne "utf8" && lc($encoding) ne "ascii" ) { - print STDERR "Encoding output file to $encoding\n" if $verbose; - $diffall=Encode::encode($encoding,$diffall); - binmode STDOUT; -} -print $diffall; - - -print STDERR "(",exetime()," s)\n","Done.\n" if $verbose; - - - -## guess_encoding(filename) -## reads the first 20 lines of filename and looks for call of inputenc package -## if found, return the option of this package (encoding), otherwise return ascii -sub guess_encoding { - my ($filename)=@_; - my ($i,$enc); - open (FH, $filename) or die("Couldn't open $filename: $!"); - $i=0; - while () { - next if /^\s*%/; # skip comment lines - if (m/\\usepackage\[(\w*?)\]\{inputenc\}/) { - close(FH); - return($1); - } - last if (++$i > 20 ); # scan at most 20 non-comment lines - } - close(FH); - return("ascii"); -} - - -sub read_file_with_encoding { - my ($output); - my ($filename, $encoding) = @_; - - if (lc($encoding) eq "utf8" ) { - open (FILE, "<:utf8",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } elsif ( lc($encoding) eq "ascii") { - open (FILE, $filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } else { - require Encode; - open (FILE, "<",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - print STDERR "Converting $filename from $encoding to utf8\n" if $verbose; - $output=Encode::decode($encoding,$output); - } - close FILE; - if ($^O eq "linux" ) { - $output =~ s/\r\n/\n/g ; - } - return $output; -} - -# %packages=list_packages(@preamble) -# scans the arguments for \documentclass and \usepackage statements and constructs a hash -# whose keys are the included packages, and whose values are the associated optional arguments -sub list_packages { - my (@preamble)=@_; - my %packages=(); - foreach $line ( @preamble ) { - # get rid of comments - $line=~s/(?catfile($dirname,$fname), "\n" if $debug; - # content of file becomes replacement value (use recursion), add \newpage if the command was include - ###$replacement=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - $replacement=flatten(read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding), $preamble,$filename,$encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - # \include always starts a new page; use explicit \newpage command to simulate this - $begline=(defined($1)? $1 : "") ; - $newpage=(defined($3)? " \\newpage " : "") ; - "$begline$newpage$replacement$newpage"; - }/exgm; - - return($text); -} - - -# print_regex_arr(@arr) -# prints regex array without x-ism expansion put in by pearl to stdout -sub print_regex_arr { - my $dumstring; - $dumstring = join(" ",@_); # PERL generates string (?-xism:^ref$) for quoted refex ^ref$ - $dumstring =~ s/\(\?-xism:\^(.*?)\$\)/$1/g; # remove string and ^,$ marks before output - print $dumstring,"\n"; -} - - -# @lines=extrapream($type) -# reads line from appendix (end of file after __END__ token) -sub extrapream { - my $type; - my @retval=("%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - my ($copy); - - while (@_) { - $copy=0; - $type=shift ; - if ( -f $type ) { - open (FILE,$type) or die "Cannot open preamble file $type: $!"; - print STDERR "Reading preamble file $type\n" if $verbose ; - while () { - chomp ; - if ( $_ =~ m/%DIF PREAMBLE/ ) { - push (@retval,"$_"); - } else { - push (@retval,"$_ %DIF PREAMBLE"); - } - } - } - else { # not (-f $type) - $type=uc($type); # upcase argument - print STDERR "Preamble Internal Type $type\n" if $verbose; - while () { - if ( m/^%DIF $type/ ) { - $copy=1; } - elsif ( m/^%DIF END $type/ ) { - last; } - chomp; - push (@retval,"$_ %DIF PREAMBLE") if $copy; - } - if ( $copy == 0 ) { - print STDERR "\nPreamble style $type not implemented.\n"; - print STDERR "Write latexdiff -h to get help with available styles\n"; - exit(2); - } - seek DATA,0,0; # rewind DATA handle to file begin - } - } - push (@retval,"%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - return @retval; -} - - -# ($part1,$part2,$part3)=splitdoc($text,$word1,$word2) -# splits $text into 3 parts at $word1 and $word2. -# if neither $word1 nor $word2 exist, $part1 and $part3 are empty, $part2 is $text -# If only $word1 or $word2 exist but not the other, output an error message. - -# NB this version avoids $` and $' for performance reason although it only makes a tiny difference -# (in one test gain a tenth of a second for a 30s run) -sub splitdoc { - my ($text,$word1,$word2)=@_; - my ($part1,$part2,$part3)=("","",""); - my ($rest,$pos); - - if ( $text =~ m/(^[^%]*)($word1)/mg ) { - $pos=pos $text; - $part1=substr($text,0,$pos-length($2)); - $rest=substr($text,$pos); - if ( $rest =~ m/(^[^%]*)($word2)/mg ) { - $pos=pos $rest; - $part2=substr($rest,0,$pos-length($2)); - $part3=substr($rest,$pos); - } - else { - die "$word1 and $word2 not in the correct order or not present as a pair." ; - } - } else { - $part2=$text; - die "$word2 present but not $word1." if ( $text =~ m/(^[^%]*)$word2/ms ); - } - return ($part1,$part2,$part3); -} - - - - - -# bodydiff($old,$new) -sub bodydiff { - my ($oldwords, $newwords) = @_; - my @retwords; - - print STDERR "(",exetime()," s)\n","Splitting into latex tokens \n" if $verbose; - print STDERR "Parsing $oldfile \n" if $verbose; - my @oldwords = splitlatex($oldwords); - print STDERR "Parsing $newfile \n" if $verbose; - my @newwords = splitlatex($newwords); - - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - print STDERR "(",exetime()," s)\n","Pass 1: Expanding text commands and merging isolated identities with changed blocks " if $verbose; - pass1(\@oldwords, \@newwords); - - - print STDERR "(",exetime()," s)\n","Pass 2: inserting DIF tokens and mark up. " if $verbose; - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold2.tex"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew2.tex"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - @retwords=pass2(\@oldwords, \@newwords); - - return(@retwords); -} - - - - -# @words=splitlatex($string) -# split string according to latex rules -# Each element of words is either -# a word (including trailing spaces and punctuation) -# a latex command -sub splitlatex { - my ($string) = @_ ; - # if input is empty, return empty list - length($string)>0 or return (); - - my @retval=($string =~ m/$pat/osg); - - if (length($string) != length(join("",@retval))) { - print STDERR "\nWARNING: Inconsistency in length of input string and parsed string:\n This often indicates faulty or non-standard latex code.\n In many cases you can ignore this and the following warning messages.\n Note that character numbers in the following are counted beginning after \\begin{document} and are only approximate." unless $ignorewarnings; - print STDERR "DEBUG Original length ",length($string)," Parsed length ",length(join("",@retval)),"\n" if $debug; - print STDERR "DEBUG Input string: |$string|\n" if (length($string)<500) && $debug; - print STDERR "DEBUG Token parsing: |",join("+",@retval),"|\n" if (length($string)<500) && $debug ; - @retval=(); - # slow way only do this if other m//sg method fails - my $last = 0; - while ( $string =~ m/$pat/osg ) { - my $match=$&; - if ($last + length $& != pos $string ) { - my $pos=pos($string); - my $offset=30<$last ? 30 : $last; - my $dum=substr($string,$last-$offset,$pos-$last+2*$offset); - my $dum1=$dum; - my $cnt=$#retval; - my $i; - $dum1 =~ s/\n/ /g; - unless ($ignorewarnings) { - print STDERR "\n$dum1\n"; - print STDERR " " x 30,"^" x ($pos-$last)," " x 30,"\n"; - print STDERR "Missing characters near word " . (scalar @retval) . " character index: " . $last . "-" . pos($string) . " Length: " . length($match) . " Match: |$match| (expected match marked above).\n"; - } - # put in missing characters `by hand' - push (@retval, substr($dum,$offset,$pos-$last-length($match))); -# Note: there seems to be a bug in substr with utf8 that made the following line output substr which were too long, -# using dum instead appears to work -# push (@retval, substr($string,$last, pos($string)-$last-length($match))); - } - push (@retval, $match); - $last=pos $string; - } - - } - return @retval; -} - - -# pass1( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Where an common-subsequence block is flanked by deleted or appended blocks, -# and is shorter than $MINWORDSBLOCK words it is appended -# to the last deleted or appended word. If the block contains tokens other than words -# or punctuation it is not merged. -# Deleted or appended block consisting of words and safe commands only are -# also merged, to prevent break-up in pass2 (after previous isolated words have been removed) -# If there are commands with textual arguments (e.g. \caption) both in corresponding -# appended and deleted blocks split them such that the command and opening bracket -# are one token, then the rest is split up following standard rules, and the closing -# bracket is a separate token, ie. turn -# "\caption{This is a textual argument}" into -# ("\caption{","This ","is ","a ","textual ","argument","}") -# No return value. Destructively changes sequences -sub pass1 { - my $seq1 = shift ; - my $seq2 = shift ; - - my $len1 = scalar @$seq1; - my $len2 = scalar @$seq2; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - - my ($last1,$last2)=(-1,-1) ; - my $cnt=0; - my $block=[]; - my $addblock=[]; - my $delblock=[]; - my $todo=[]; - my $instruction=[]; - my $i; - my (@delmid,@addmid,@dummy); - - my ($addcmds,$delcmds,$matchindex); - my ($addtextblocks,$deltextblocks); - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $adddiscard = sub { - if ($cnt > 0 ) { - $matblkcnt++; - # just after an unchanged block -# print STDERR "Unchanged block $cnt, $last1,$last2 \n"; - if ($cnt < $MINWORDSBLOCK - && $cnt==scalar ( - grep { /^$wpat/ || ( /^\\([\w\d\*]+)((?:\[$brat0\]|\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && scalar(@dummy=split(" ",$2))<3 ) } - @$block) ) { - # merge identical blocks shorter than $MINWORDSBLOCK - # and only containing ordinary words - # with preceding different word - # We cannot carry out this merging immediately as this - # would change the index numbers of seq1 and seq2 and confuse - # the algorithm, instead we store in @$todo where we have to merge - push(@$todo, [ $last1,$last2,$cnt,@$block ]); - } - $block = []; - $cnt=0; $last1=-1; $last2=-1; - } - }; - my $discard=sub { $deltokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$delblock,[ $seq1->[$_[0]],$_[0] ]); - $last1=$_[0] }; - - my $add = sub { $addtokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$addblock,[ $seq2->[$_[1]],$_[1] ]); - $last2=$_[1] }; - - my $match = sub { $mattokcnt++; - if ($cnt==0) { # first word of matching sequence after changed sequence or at beginning of word sequence - $deltextblocks = extracttextblocks($delblock); - $delblkcnt++ if scalar @$delblock; - $addtextblocks = extracttextblocks($addblock); - $addblkcnt++ if scalar @$addblock; - - $delcmds = extractcommands($delblock); - $addcmds = extractcommands($addblock); - # keygen(third argument of _longestCommonSubsequence) implies to sort on command (0th elements of $addcmd elements) - # the calling format for longestCommonSubsequence has changed between versions of - # Algorithm::Diff so we need to check which one we are using - if ( $algodiffversion > 1.15 ) { - ### Algorithm::Diff 1.19 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, 0, sub { $_[0]->[0] } ); - } else { - ### Algorithm::Diff 1.15 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, sub { $_[0]->[0] } ); - } - - for ($i=0 ; $i<=$#$matchindex ; $i++) { - if (defined($matchindex->[$i])){ - $j=$matchindex->[$i]; - @delmid=splitlatex($delcmds->[$i][3]); - @addmid=splitlatex($addcmds->[$j][3]); - while (scalar(@$deltextblocks) && $deltextblocks->[0][0]<$delcmds->[$i][1]) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) }; - push(@$todo, [$index,-1,$cnt,@$block]); - } - push(@$todo, [ $delcmds->[$i][1],-1,-1,$delcmds->[$i][2],@delmid,$delcmds->[$i][4]]); - - while (scalar(@$addtextblocks) && $addtextblocks->[0][0]<$addcmds->[$j][1]) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - push(@$todo, [ -1,$addcmds->[$j][1],-1,$addcmds->[$j][2],@addmid,$addcmds->[$j][4]]); - } - } - # mop up remaining textblocks - while (scalar(@$deltextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) } ; - push(@$todo, [$index,-1,$cnt,@$block]); - } - while (scalar(@$addtextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - - $addblock=[]; - $delblock=[]; - } - push(@$block,$seq2->[$_[1]]); - $cnt++ }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - - - # now carry out the merging/splitting. Refer to elements relative from - # the end (with negative indices) as these offsets don't change before the instruction is executed - # cnt>0: merged small unchanged groups with previous changed blocks - # cnt==-1: split textual commands into components - foreach $instruction ( @$todo) { - ($last1,$last2,$cnt,@$block)=@$instruction ; - if ($cnt>=0) { - splice(@$seq1,$last1-$len1,1+$cnt,join("",$seq1->[$last1-$len1],@$block)) if $last1>=0; - splice(@$seq2,$last2-$len2,1+$cnt,join("",$seq2->[$last2-$len2],@$block)) if $last2>=0; - } else { - splice(@$seq1,$last1-$len1,1,@$block) if $last1>=0; - splice(@$seq2,$last2-$len2,1,@$block) if $last2>=0; - } - } - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens in $matblkcnt blocks.\n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } -} - - -# extracttextblocks(\@blockindex) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [[ $index, $textblock, $cnt ], .. -# where $index index of block to be merged -# $textblock contains all the words to be merged with the word at $index (but does not contain this word) -# $cnt is length of block -# -# requires: iscmd -# -sub extracttextblocks { - my $block=shift; - my ($i,$token,$index); - my $textblock=[]; - my $last=-1; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # store pure text blocks - if ($token =~ /$wpat/ || ( $token =~/^\\([\w\d\*]+)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && !iscmd($1,\@TEXTCMDLIST,\@TEXTCMDEXCL))) { - # we have text or a command which can be treated as text - if ($last<0) { - # new pure-text block - $last=$index; - } else { - # add to pure-text block - push(@$textblock, $token); - } - } else { - # it is not text - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - $textblock=[]; - $last=-1; - } - } - # finish processing a possibly unfinished block before returning - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - return($retval) -} - - - -# extractcommands( \@blockindex ) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [ [ "\cmd1", index, "\cmd1[optarg]{arg1}{", "arg2" ,"} " ],.. -# where index is just taken from input array -# command must have a textual argument as last argument -# -# requires: iscmd -# -sub extractcommands { - my $block=shift; - my ($i,$token,$index,$cmd,$open,$mid,$closing); - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: \cmd - # $3: last argument - # $4: } + trailing spaces - if ( ( $token =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL) ) { - # push(@$retval,[ $2,$index,$1,$3,$4 ]); - ($cmd,$open,$mid,$closing) = ($2,$1,$3,$4) ; - $closing =~ s/\}/\\RIGHTBRACE/ ; - push(@$retval,[ $cmd,$index,$open,$mid,$closing ]); - } - } - return $retval; -} - -# iscmd($cmd,\@regexarray,\@regexexcl) checks -# return 1 if $cmd matches any of the patterns in the -# array $@regexarray, and none of the patterns in \@regexexcl, otherwise return 0 -sub iscmd { - my ($cmd,$regexar,$regexexcl)=@_; - my ($ret)=0; - foreach $pat ( @$regexar ) { - if ( $cmd =~ m/^${pat}$/ ) { - $ret=1 ; - last; - } - } - return 0 unless $ret; - foreach $pat ( @$regexexcl ) { - return 0 if ( $cmd =~ m/^${pat}$/ ); - } - return 1; -} - - -# pass2( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Mark begin and end of deleted and appended sequences with tags $DELOPEN and $DELCLOSE -# and $ADDOPEN and $ADDCLOSE, respectively, however exclude { } & and all comands, unless -# they match an element of the whitelist (SAFECMD) -# For words in TEXTCMD but not in SAFECMD, enclose interior with $ADDOPEN and $ADDCLOSE brackets -# Deleted comment lines are marked with %DIF < -# Added comment lines are marked with %DIF > -sub pass2 { - my $seq1 = shift ; - my $seq2 = shift ; - - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $retval = []; - my $delhunk = []; - my $addhunk = []; - - my $discard = sub { $deltokcnt++; - push ( @$delhunk, $seq1->[$_[0]]) }; - - my $add = sub { $addtokcnt++; - push ( @$addhunk, $seq2->[$_[1]]) }; - - my $match = sub { $mattokcnt++; - if ( scalar @$delhunk ) { - $delblkcnt++; - # mark up changes, but comment out commands - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk); - $delhunk = []; - } - if ( scalar @$addhunk ) { - $addblkcnt++; - # we mark up changes, but simply quote commands - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk); - $addhunk = []; - } - push(@$retval,$seq2->[$_[1]]) }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - # clear up unprocessed hunks - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk) if scalar @$delhunk; - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk) if scalar @$addhunk; - - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens. \n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } - - return(@$retval); -} - -# marktags($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,\@block) -# returns ($openmark,$open,$block,$close,$closemark) if @block only contains no commands (except white-listed ones), -# braces, ampersands, or comments -# mark comments with $comment -# exclude all other exceptions from scope of open, close like this -# ($openmark, $open,...,$close, $opencmd,command, command,$closecmd, $open, ..., $close, $closemark) -# If $opencmd begins with "%" marktags assumes it is operating on a deleted block, otherwise on an added block -sub marktags { - my ($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,$block)=@_; - my $word; - my (@argtext); - my $retval=[]; - my $noncomment=0; - my $cmd=-1; # -1 at beginning 0: last token written is a ordinary word - # 1: last token written is a command - # for keeping track whether we are just in a command sequence or in a word sequence - my $cmdcomment= ($opencmd =~ m/^%/); # Flag to indicate whether opencmd is a comment (i.e. if we intend to simply comment out changed commands) - my ($command,$commandword,$closingbracket) ; # temporary variables needed below to remember sub-pattern matches - -# split this block to flatten out sequences joined in pass1 - @$block=splitlatex(join "",@$block); - foreach (@$block) { - $word=$_; - if ( $word =~ s/^%/%$comment/ ) { - # a comment - if ($cmd==1) { - push (@$retval,$closecmd) ; - $cmd=-1; - } - push (@$retval,$word); - next; - } - if (! $noncomment) { - push (@$retval,$openmark); - $noncomment=1; - } - # negative lookahead pattern (?!) in second clause is put in to avoid mathcing \( .. \) patterns - # also note that second pattern will match \\ - # Note: the second pattern should really be $word =~ /^\\(?!\()(\\|[\w*@]+)/, ie * replaced by + - # and then all commands \" \' etc declared safe. But as I don't have a complete list of one letter - # commands, and nobody has complained so far, I will eave this as is - if ( $word =~ /^[&{}\[\]]/ || ( $word =~ /^\\(?!\()(\\|[\w*@]*)/ && !iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL)) ) { - # word is a command or other significant token (not in SAFECMDLIST) - ## same conditions as in subroutine extractcommand: - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: cmd - # $3: last argument - # $4: } + trailing spaces - ### pre-0.3 if ( ( $token =~ m/^(\\([\w\d\*]+)(?:\[$brat0\]|\{$pat6\})*\{)($pat6)(\}\s*)$/so ) - if ( ( $word =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && (iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL)|| iscmd($2,\@MATHTEXTCMDLIST,\@MATHTEXTCMDEXCL)) - && ( !$cmdcomment || !iscmd($2,\@CONTEXT2CMDLIST, \@CONTEXT2CMDEXCL) ) ) { - # Condition 1: word is a command? - if yes, $1,$2,.. will be set as above - # Condition 2: word is a text command - we mark up the interior of the word. There is a separate check for MATHTEXTCMDLIST - # because for $mathmarkup=WHOLE, the commands should not be split in pass1 (ie. math mode commands are not in - # TEXTCMDLIST, but the interior of MATHTEXT commands should be highlighted in both deleted and added blocks - # Condition 3: But if we are in a deleted block ($cmdcomment=1) and - # $2 (the command) is in context2, just treat it as an ordinary command (i.e. comment it open with $opencmd) - # Because we do not want to disable this command - # here we do not use $opencmd and $closecmd($opencmd is empty) - if ($cmd==1) { - push (@$retval,$closecmd) ; - } elsif ($cmd==0) { - push (@$retval,$close) ; - } - $command=$1; $commandword=$2; $closingbracket=$4; - @argtext=splitlatex($3); # split textual argument into tokens - # and mark it up (but we do not need openmark and closemark) - # insert command with initial arguments, marked-up final argument, and closing bracket - if ( $cmdcomment && iscmd($commandword,\@CONTEXT1CMDLIST, \@CONTEXT1CMDEXCL) ) { - # context1cmd in a deleted environment; delete command itself but keep last argument, marked up - push (@$retval,$opencmd); - $command =~ s/\n/\n${opencmd}/sg ; # repeat opencmd at the beginning of each line - # argument, note that the additional comment character is included - # to suppress linebreak after opening parentheses, which is important - # for latexrevise - push (@$retval,$command,"%\n{$AUXCMD\n",marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } elsif ( iscmd($commandword,,\@MATHTEXTCMDLIST, \@MATHTEXTCMDEXCL) ) { - # MATHBLOCK pseudo command: consider all commands safe, except & and \\ - # Keep these commands even in deleted blocks, hence set $opencmd and $closecmd (5th and 6th argument of marktags) to - # "" - local @SAFECMDLIST=(".*"); - local @SAFECMDEXCL=('\\','\\\\'); - push(@$retval,$command,marktags("","",$open,$close,"","",$comment,\@argtext)#@argtext - ,$closingbracket); - } else { - # normal textcmd or context1cmd in an added block - push (@$retval,$command,marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } - push (@$retval,$AUXCMD,"\n") if $cmdcomment ; - $cmd=-1 ; - } else { - # ordinary command - push (@$retval,$opencmd) if $cmd==-1 ; - push (@$retval,$close,$opencmd) if $cmd==0 ; - $word =~ s/\n/\n${opencmd}/sg if $cmdcomment ; # if opencmd is a comment, repeat this at the beginning of every line - push (@$retval,$word); - $cmd=1; - } - } else { - # just an ordinary word or word in SAFECMD - push (@$retval,$open) if $cmd==-1 ; - push (@$retval,$closecmd,$open) if $cmd==1 ; - push (@$retval,$word); - $cmd=0; - } - } - push (@$retval,$close) if $cmd==0; - push (@$retval,$closecmd) if $cmd==1; - - push (@$retval,$closemark) if ($noncomment); - return @$retval; -} - -# preprocess($string, ..) -# carry out the following pre-processing steps for all arguments: -# 1. Remove leading white-space -# Change \{ to \LEFTBRACE and \} to \RIGHTBRACE -# #. change begin and end commands within comments to BEGINDIF, ENDDIF -# so they don't disturb the pattern matching (if there are several \begin or \end in one line -# 2. mark all first empty line (in block of several) with \PAR tokens -# 3. Convert all '\%' into '\PERCENTAGE ' to make parsing regular expressions easier -# 4. Convert all \verb|some verbatim text| commands (where | can be an arbitrary character) -# into \verb{hash} -# 5. Convert \begin{verbatim} some verbatim text \end{verbatim} into \verbatim{hash} -# 6. Convert _n into \SUBSCRIPTNB{n} and _{nnn} into \SUBSCRIPT{nn} -# 7. Convert ^n into \SUPERSCRIPTNB{n} and ^{nnn} into \SUPERSCRIPT{nn} -# 8. a. Convert $$ $$ into \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} -# b. Convert \[ \] into \begin{SQUAREBRACKET} \end{SQUAREBRACKET} -# 9. Convert all picture environmentent (\begin{PICTUREENV} .. \end{PICTUREENV} \PICTUREBLOCKenv -# For --block-math-markup option -convert all \begin{MATH} .. \end{MATH} -# into \MATHBLOCKmath{...} commands, where MATH/math is any valid math environment - -# 10. Add final token STOP to the very end. This is put in because the algorithm works better if the last token is identical. This is removed again in postprocessing. -# -# NB: step 6 and 7 is likely to convert some "_" inappropriately, e.g. in file -# names or labels but it does not matter because they are converted back in the postprocessing step -# Returns: leading white space removed in step 1 -sub preprocess { - my @leadin=() ; - for (@_) { - s/^(\s*)//s; - push(@leadin,$1); - # Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE - s/(?{$hstr}) && $string ne $hash->{$hstr}) { - warn "Repeated hash value for verbatim mode in spite of different content."; - $hstr="-$hstr"; - } - $hash->{$hstr}=$string; - return($hstr); -} - -#string=fromhash(\%hash,$fromstring) -# restores string value stored in hash -#string=fromhash(\%hash,$fromstring,$prependstring) -# additionally begins each line with prependstring -sub fromhash { - my ($hash,$hstr)=($_[0],$_[1]); - my $retstr=$hash->{$hstr}; - if ( $#_ >= 2) { - $retstr =~ s/^/$_[2]/mg; - } - return $retstr; -} - - -# postprocess($string, ..) -# carry out the following post-processing steps for all arguments: -# * Remove STOP token from the end -# * Replace \RIGHTBRACE by } -# * change citation commands within comments to protect from processing (using marker CITEDIF) -# 1. Check all deleted blocks: -# a.where a deleted block contains a matching \begin and -# \end environment (these will be disabled by a %DIFDELCMD statements), for selected environments enable -# these commands again (such that for example displayed math in a deleted equation -# is properly within math mode. For math mode environments replace numbered equation -# environments with their display only variety (so that equation numbers in new file and -# diff file are identical). Where the correct type of math environment cannot be determined -# use a place holder MATHMODE -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file -# Replace all MATHMODE environment commands by the correct environment to achieve matching -# pairs -# c. Convert MATHBLOCKmath commands to their uncounted numbers (e.g. convert equation -> displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL -# d. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# For added blocks: -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# 2. If --block-math-markup option set: Convert \MATHBLOCKmath{..} commands back to environments -# -# Convert all PICTUREblock{..} commands back to the appropriate environments -# 3. Convert DIFadd, DIFdel, DIFFaddbegin , ... into FL varieties -# within floats (currently recognised float environments: plate,table,figure -# plus starred varieties). -# 4. Remove empty %DIFDELCMD < lines -# 4. Convert \begin{SQUAREBRACKET} \end{SQUAREBRACKET} into \[ \] -# Convert \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} into $$ $$ -# 5. Convert \SUPERSCRIPTNB{n} into ^n and \SUPERSCRIPT{nn} into ^{nnn} -# 6. Convert \SUBSCRIPTNB{n} into _n and \SUBCRIPT{nn} into _{nnn} -# 7. Expand hashes of verb and verbatim environments -# 8. Convert '\PERCENTAGE ' back into '\%' -# 9.. remove all \PAR tokens -# 10. package specific processing: endfloat: make sure \begin{figure} and \end{figure} are always -# on a line by themselves, similarly for table environment -# 4, undo renaming of the \begin and \end in comments -# Change \QLEFTBRACE, \QRIGHTBRACE to \{,\} -# -# Note have to manually synchronize substitution commands below and -# DIF.. command names in the header -sub postprocess { - my ($begin,$len,$cnt,$float,$delblock,$addblock); - # second level blocks - my ($begin2,$cnt2,$len2,$eqarrayblock,$mathblock); - - for (@_) { - - # change $'s in comments to something harmless - 1 while s/(%.*)\$/$1DOLLARDIF/mg ; - - # Remove final STOP token - s/ STOP$//; - # Replace \RIGHTBRACE by } - s/\\RIGHTBRACE/}/g; - - # change citation commands within comments to protect from processing - if ($CITECMD){ - 1 while s/(%.*)\\($CITECMD)/$1\\CITEDIF$2/m ; - } - # Check all deleted blocks: where a deleted block contains a matching \begin and - # \end environment (these will be disabled by a %DIFDELCMD statements), enable - # these commands again (such that for example displayed math in a deleted equation - # is properly within math mode. For math mode environments replace numbered equation - # environments with their display only variety (so that equation numbers in new file and - # diff file are identical - while ( m/\\DIFdelbegin.*?\\DIFdelend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $delblock=$&; - - - ### (.*?[^\n]?)\n? construct is necessary to avoid empty lines in math mode, which result in - ### an error - # displayed math environments - if ($mathmarkup == FINE ) { - $delblock=~ s/(\%DIFDELCMD < \s*\\begin\{((?:$MATHENV)|SQUAREBRACKET)\}.*?(?:$DELCMDCLOSE|\n))(.*?[^\n]?)\n?(\%DIFDELCMD < \s*\\end\{\2\})/\\begin{$MATHREPL}$AUXCMD\n$1$3\n\\end{$MATHREPL}$AUXCMD\n$4/sg; - # also transform the opposite pair \end{displaymath} .. \begin{displaymath} but we have to be careful not to interfere with the results of the transformation in the line directly above - ### pre-0.42 obsolete version which did not work on eqnarray test $delblock=~ s/(? displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL - $delblock=~ s/\\MATHBLOCK($MATHENV)\{($pat6)\}/\\MATHBLOCK$MATHREPL\{$2\}/sg; - $delblock=~ s/\\MATHBLOCK($MATHARRENV)\{($pat6)\}/\\MATHBLOCK$MATHARRREPL\{$2\}/sg; - } - - -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file - $delblock=~ s/\\($COUNTERCMD)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*\s*${AUXCMD}\n)/\\$1$2\\addtocounter{$1}{-1}${AUXCMD}\n/sg ; - - -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es - while ( $delblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($delblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($delblock,$begin2,$len2)=$mathblock; - pos($delblock) = $begin2 + length($mathblock); - } - if ($CITE2CMD) { - $delblock=~s/($DELCMDOPEN\s*\\($CITE2CMD)(.*)$DELCMDCLOSE)/ - # Replacement code - {my ($aux,$all); - $aux=$all=$1; - $aux=~s#\n?($DELCMDOPEN|$DELCMDCLOSE)##g; - $all."$aux$AUXCMD\n";}/sge; - } - # or protect \cite commands with \mbox - if ($CITECMD) { - $delblock=~s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat6\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified delblock - substr($_,$begin,$len)=$delblock; - pos = $begin + length($delblock); - } - # make the array modification in added blocks - while ( m/\\DIFaddbegin.*?\\DIFaddend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $addblock=$&; - while ( $addblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($addblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($addblock,$begin2,$len2)=$mathblock; - pos($addblock) = $begin2 + length($mathblock); - } - if ($CITECMD) { - my $addblockbefore=$addblock; - $addblock=~ s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat2\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified addblock - substr($_,$begin,$len)=$addblock; - pos = $begin + length($addblock); - } - - - ### old place for BEGINDIF, ENDDIF replacement - # change begin and end commands within comments such that they - # don't disturb the pattern matching (if there are several \begin or \end in one line - # this substitution is insufficient but that appears unlikely) - # This needs to be repeated here to also get rid of DIFdelcmd-protected environments - s/(%.*)\\begin\{(.*)$/$1\\BEGINDIF\{$2/mg ; - s/(%.*)\\end\{(.*)$/$1\\ENDDIF\{$2/mg ; - - # Replace MATHMODE environments from step 1a above by the correct Math environment - - # The next line is complicated. The negative look-ahead insertion makes sure that no \end{$MATHENV} (or other mathematical - # environments) are between the \begin{$MATHENV} and \end{MATHMODE} commands. This is necessary as the minimal matching - # is not globally minimal but only 'locally' (matching is beginning from the left side of the string) - if ( $mathmarkup == FINE ) { - 1 while s/\\begin{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}((?:.(?!(?:\\end{(?:(?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}|\\begin{MATHMODE})))*?)\\end{MATHMODE}/\\begin{$1}$2\\end{$1}/s; - 1 while s/\\begin{MATHMODE}((?:.(?!\\end{MATHMODE}))*?)\\end{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}/\\begin{$2}$1\\end{$2}/s; - # convert remaining \begin{MATHMODE} \end{MATHMODE} (and not containing & or \\ )into MATHREPL environments - s/\\begin{MATHMODE}((?:(.(?!(?[1])) { - $optargnew=$newhash{$cmd}->[1]; - } else { - $optargnew=""; - } - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - } else { - $optargold=""; - } - - if ( defined($oldhash{$cmd}) ) { - $argold=$oldhash{$cmd}->[2]; - } else { - $argold=""; - } - $argnew=$newhash{$cmd}->[2]; - $argdiff="{" . join("",bodydiff($argold,$argnew)) ."}"; - if ( length $optargnew ) { - $optargdiff="[".join("",bodydiff($optargold,$optargnew))."]" ; - $optargdiff =~ s/\\DIFaddbegin /\\DIFaddbeginFL /g; - $optargdiff =~ s/\\DIFaddend /\\DIFaddendFL /g; - $optargdiff =~ s/\\DIFadd\{/\\DIFaddFL{/g; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - ### print STDERR "DEBUG s/\\Q$newhash{$cmd}->[0]\\E/\\$cmd$optargdiff$argdiff/s\n"; - # Note: \Q and \E force literal interpretation of what it between them but allow - # variable interpolation, such that e.g. \title matches just that and not TAB-itle - $$newpreambleref=~s/\Q$newhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s; - # replace this in old preamble if necessary - if ( defined($oldhash{$cmd}->[0])) { - $$oldpreambleref=~s/\Q$oldhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s ; - } - ### print STDERR "DEBUG NEW PRE ".$$newpreambleref."\n"; - } - - foreach $cmd ( keys %oldhash ) { - # if this has already been dealt with above can just skip - next if defined($newhash{$cmd}) ; - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - $optargdiff="[".join("",bodydiff($optargold,""))."]" ; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - $argdiff="{" . join("",bodydiff($argold,"")) ."}"; - $auxline = "\\$cmd$optargdiff$argdiff"; - $auxline =~s/$/$AUXCMD/sg; - push @auxlines,$auxline; - } - # add auxcmd comment to highlight added lines - return(@auxlines); -} - - - -# @diffs=linediff(\@seq1, \@seq2) -# mark up lines like this -#%DIF mm-mmdnn -#%< old deleted line(s) -#%DIF ------- -#%DIF mmann-nn -#new appended line %< -#%DIF ------- -# Future extension: mark change explicitly -# Assumes: traverse_sequence traverses deletions before insertions in changed sequences -# all line numbers relative to line 0 (first line of real file) -sub linediff { - my $seq1 = shift ; - my $seq2 = shift ; - - my $block = []; - my $retseq = []; - my @begin=('','',''); # dummy initialisation - my $instring ; - - my $discard = sub { @begin=('d',$_[0],$_[1]) unless scalar @$block ; - push(@$block, "%DIF < " . $seq1->[$_[0]]) }; - my $add = sub { if (! scalar @$block) { - @begin=('a',$_[0],$_[1]) ;} - elsif ( $begin[0] eq 'd' ) { - $begin[0]='c'; $begin[2]=$_[1]; - push(@$block, "%DIF -------") } - push(@$block, $seq2->[$_[1]] . " %DIF > " ) }; - my $match = sub { if ( scalar @$block ) { - if ( $begin[0] eq 'd' && $begin[1]!=$_[0]-1) { - $instring = sprintf "%%DIF %d-%dd%d",$begin[1],$_[0]-1,$begin[2]; } - elsif ( $begin[0] eq 'a' && $begin[2]!=$_[1]-1) { - $instring = sprintf "%%DIF %da%d-%d",$begin[1],$begin[2],$_[1]-1; } - elsif ( $begin[0] eq 'c' ) { - $instring = sprintf "%%DIF %sc%s", - ($begin[1]==$_[0]-1) ? "$begin[1]" : $begin[1]."-".($_[0]-1) , - ($begin[2]==$_[1]-1) ? "$begin[2]" : $begin[2]."-".($_[1]-1) ; } - else { - $instring = sprintf "%%DIF %d%s%d",$begin[1],$begin[0],$begin[2]; } - push @$retseq, $instring,@$block, "%DIF -------" ; - $block = []; - } - push @$retseq, $seq2->[$_[1]] - }; - # key function: remove multiple spaces (such that insertion or deletion of redundant white space is not reported) - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - push @$retseq, @$block if scalar @$block; - - return wantarray ? @$retseq : $retseq ; -} - - - -# init_regex_arr_data(\@array,"TOKEN INIT") -# scans DATA file handel for line "%% TOKEN INIT" line -# then appends each line not beginning with % into array (as a quoted regex) -sub init_regex_arr_data { - my ($arr,$token)=@_; - my ($copy); - while () { - if ( m/^%%BEGIN $token\s*$/ ) { - $copy=1; } - elsif ( m/^%%END $token\s*/ ) { - last; } - chomp; - push (@$arr,qr/^$_$/) if ( $copy && !/^%/ ) ; - } - seek DATA,0,0; # rewind DATA handle to file begin -} - - -# init_regex_arr_ext(\@array,$arg) -# fills array with regular expressions. -# if arg is a file name, then read in list of regular expressions from that file -# (one expression per line) -# Otherwise treat arg as a comma separated list of regular expressions -sub init_regex_arr_ext { - my ($arr,$arg)=@_; - my $regex; - if ( -f $ arg ) { - open(FILE,"$arg") or die ("Couldn't open $arg: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@$arr,qr/^$_$/); - } - close(FILE); - } - else { - # assume it is a comma-separated list of reg-ex - foreach $regex (split(qr/(?=1) { - $reset=shift; - } - if ($reset) { - $lasttime=times(); - } - else { - $retval=times()-$lasttime; - $lasttime=$lasttime+$retval; - return($retval); - } -} - - -sub usage { - die <<"EOF"; -Usage: $0 [options] old.tex new.tex > diff.tex - -Compares two latex files and writes tex code to stdout, which has the same -format as new.tex but has all changes relative to old.tex marked up or commented. - ---type=markupstyle --t markupstyle Add code to preamble for selected markup style - Available styles: UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE - CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR - [ Default: UNDERLINE ] - ---subtype=markstyle --s markstyle Add code to preamble for selected style for bracketing - commands (e.g. to mark changes in margin) - Available styles: SAFE MARGINAL DVIPSCOL COLOR - [ Default: SAFE ] - ---floattype=markstyle --f markstyle Add code to preamble for selected style which - replace standard marking and markup commands within floats - (e.g., marginal remarks cause an error within floats - so marginal marking can be disabled thus) - Available styles: FLOATSAFE IDENTICAL - [ Default: FLOATSAFE ] - ---encoding=enc --e enc Specify encoding of old.tex and new.tex. Typical encodings are - ascii, utf8, latin1, latin9. A list of available encodings can be - obtained by executing - perl -MEncode -e 'print join ("\\n",Encode->encodings( ":all" )) ;' - [Default encoding is utf8 unless the first few lines of the preamble contain - an invocation "\\usepackage[..]{inputenc} in which case the - encoding chosen by this command is asssumed. Note that ASCII (standard - latex) is a subset of utf8] - ---preamble=file --p file Insert file at end of preamble instead of auto-generating - preamble. The preamble must define the following commands - \\DIFaddbegin,\\DIFaddend,\\DIFadd{..}, - \\DIFdelbegin,\\DIFdelend,\\DIFdel{..}, - and varieties for use within floats - \\DIFaddbeginFL,\\DIFaddendFL,\\DIFaddFL{..}, - \\DIFdelbeginFL,\\DIFdelendFL,\\DIFdelFL{..} - (If this option is set -t, -s, and -f options - are ignored.) - ---exclude-safecmd=exclude-file ---exclude-safecmd="cmd1,cmd2,..." --A exclude-file ---replace-safecmd=replace-file ---append-safecmd=append-file ---append-safecmd="cmd1,cmd2,..." --a append-file Exclude from, replace or append to the list of regex - matching commands which are safe to use within the - scope of a \\DIFadd or \\DIFdel command. The file must contain - one Perl-RegEx per line (Comment lines beginning with # or % are - ignored). A literal comma within the comma-separated list must be - escaped thus "\\,", Note that the RegEx needs to match the whole of - the token, i.e., /^regex\$/ is implied and that the initial - "\\" of the command is not included. The --exclude-safecmd - and --append-safecmd options can be combined with the --replace-safecmd - option and can be used repeatedly to add cumulatively to the lists. - ---exclude-textcmd=exclude-file ---exclude-textcmd="cmd1,cmd2,..." --X exclude-file ---replace-textcmd=replace-file ---append-textcmd=append-file ---append-textcmd="cmd1,cmd2,..." --x append-file Exclude from, replace or append to the list of regex - matching commands whose last argument is text. See - entry for --exclude-safecmd directly above for further details. - ---replace-context1cmd=replace-file ---append-context1cmd=append-file ---append-context1cmd="cmd1,cmd2,..." - Replace or append to the list of regex matching commands - whose last argument is text but which require a particular - context to work, e.g. \\caption will only work within a figure - or table. These commands behave like text commands, except when - they occur in a deleted section, when they are disabled, but their - argument is shown as deleted text. - ---replace-context2cmd=replace-file ---append-context2cmd=append-file ---append-context2cmd="cmd1,cmd2,..." - As corresponding commands for context1. The only difference is that - context2 commands are completely disabled in deleted sections, including - their arguments. - - ---config var1=val1,var2=val2,... --c var1=val1,.. Set configuration variables. --c configfile Available variables: - MINWORDSBLOCK (integer) - FLOATENV (RegEx) - PICTUREENV (RegEx) - MATHENV (RegEx) - MATHREPL (String) - MATHARRENV (RegEx) - MATHARRREPL (String) - ARRENV (RegEx) - COUNTERCMD (RegEx) - This option can be repeated. - - ---packages=pkg1,pkg2,.. - Tell latexdiff that .tex file is processed with the packages in list - loaded. This is normally not necessary if the .tex file includes the - preamble, as the preamble is automatically scanned for \\usepackage commands. - Use of the --packages option disables automatic scanning, so if for any - reason package specific parsing needs to be switched off, use --packages=none. - The following packages trigger special behaviour: - endfloat hyperref amsmath - [ Default: scan the preamble for \\usepackage commands to determine - loaded packages.] - ---show-preamble Print generated or included preamble commands to stdout. - ---show-safecmd Print list of regex matching and excluding safe commands. - ---show-textcmd Print list of regex matching and excluding commands with text argument. - ---show-config Show values of configuration variables - ---show-all Show all of the above - - NB For all --show commands, no old.tex or new.tex file needs to be given, and no - differencing takes place. - -Other configuration options: - ---allow-spaces Allow spaces between bracketed or braced arguments to commands - [Default requires arguments to directly follow each other without - intervening spaces] - ---math-markup=level Determine granularity of markup in displayed math environments: - Possible values for level are (both numerical and text labels are acceptable): - off or 0: suppress markup for math environments. Deleted equations will not - appear in diff file. This mode can be used if all the other modes - cause invalid latex code. - whole or 1: Differencing on the level of whole equations. Even trivial changes - to equations cause the whole equation to be marked changed. This - mode can be used if processing in coarse or fine mode results in - invalid latex code. - coarse or 2: Detect changes within equations marked up with a coarse - granularity; changes in equation type (e.g.displaymath to equation) - appear as a change to the complete equation. This mode is recommended - for situations where the content and order of some equations are still - being changed. [Default] - fine or 3: Detect small change in equations and mark up and fine granularity. - This mode is most suitable, if only minor changes to equations are - expected, e.g. correction of typos. - ---disable-citation-markup Suppress citation markup in styles using ulem (UNDERLINE, - FONTSTRIKE, CULINECHBAR) ---enable-citation-markup Protect citation commands in changed sections with \\mbox command - [i.e. use default behaviour for ulem package for other packages] - -Miscelleneous options - ---label=label --L label Sets the labels used to describe the old and new files. The first use - of this option sets the label describing the old file and the second - use of the option sets the label for the new file. - [Default: use the filename and modification dates for the label] - ---no-label Suppress inclusion of old and new file names as comment in output file - ---visble-label Include old and new filenames (or labels set with --label option) as - visible output - ---flatten Replace \\input and \\include commands within body by the content - of the files in their argument. If \\includeonly is present in the - preamble, only those files are expanded into the document. However, - no recursion is done, i.e. \\input and \\include commands within - included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, - respectively, making it possible to organise files into old and new directories. - --flatten is applied recursively, so inputted files can contain further - \\input statements. - ---help --h Show this help text. - ---ignore-warnings Suppress warnings about inconsistencies in length between input - and parsed strings and missing characters. - ---verbose --V Output various status information to stderr during processing. - Default is to work silently. - ---version Show version number. - -For further information, consult http://latexdiff.berlios.de -EOF -} - -=head1 NAME - -latexdiff - determine and markup differences between two latex files - -=head1 SYNOPSIS - -B [ B ] F F > F - -=head1 DESCRIPTION - -Briefly, I is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called C and C, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. - -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "S>>" is appended to each added line, i.e. a -line present in C but not in C. Discarded lines - are deactivated by prepending "S>>". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file C will be similar to -C. At the end of the preamble, the definitions for I markup commands are inserted. -In differencing the main body of the text, I attempts to -satisfy the following guidelines (in order of priority): - -=over 3 - -=item 1 - -If both C and C are valid LaTeX, then the resulting -C should also be valid LateX. (NB If a few plain TeX commands -are used within C or C then C is not -guaranteed to work but usually will). - -=item 2 - -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -C. - -=item 3 - -If a changed passage contains text or text-producing commands, then -running C through LateX should produce output where added -and discarded passages are highlighted. - -=item 4 - -Where there are insignificant differences, e.g. in the positioning of -line breaks, C should follow the formatting of C - -=back - -For differencing the same algorithm as I is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, C<\caption> and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write - - \section{\textem{This is an emphasized section title}} - -and not - - \section {\textem{This is an emphasized section title}} - -or - - \section\textem{This is an emphasized section title} - -even though all varieties are the same to LaTeX (but see -B<--allow-spaces> option which allows the second variety). - -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the PICTUREENV configuration variable, set by -default to C and C environments; see B<--config> -option). The latter environment (C) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by C<\begin{DIFnomarkup}> and C<\end{DIFnomarkup}>. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, - -C<\newenvironment{DIFnomarkup}{}{}> - -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. - -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. - -All markup commands inserted by I begin with "C<\DIF>". Added -blocks containing words, commands or comments which are in C -but not in C are marked by C<\DIFaddbegin> and C<\DIFaddend>. -Discarded blocks are marked by C<\DIFdelbegin> and C<\DIFdelend>. -Within added blocks all text is highlighted with C<\DIFadd> like this: -C<\DIFadd{Added text block}> -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces "{" and "}" are never put within -the scope of C<\DIFadd>. Added comments are marked by prepending -"S >>". - -Within deleted blocks text is highlighted with C<\DIFdel>. Deleted -comments are marked by prepending "S >>". Non-safe command -and curly braces within deleted blocks are commented out with -"S >>". - - - -=head1 OPTIONS - -=head2 Preamble - -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. - -=over 4 - -=item B<--type=markupstyle> or -B<-t markupstyle> - -Add code to preamble for selected markup style. This option defines -C<\DIFadd> and C<\DIFdel> commands. -Available styles: - -C - -[ Default: C ] - -=item B<--subtype=markstyle> or -B<-s markstyle> - -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -C<\DIFaddbegin>, C<\DIFaddend>, C<\DIFdelbegin> and C<\DIFdelend> commands. -Available styles: C - -[ Default: C ] - -=item B<--floattype=markstyle> or -B<-f markstyle> - -Add code to preamble for selected style which -replace standard marking and markup commands within floats -(e.g., marginal remarks cause an error within floats -so marginal marking can be disabled thus). This option defines all -C<\DIF...FL> commands. -Available styles: C - -[ Default: C ] - -=item B<--encoding=enc> or -B<-e enc> - -Specify encoding of old.tex and new.tex. Typical encodings are -C, C, C, C. A list of available encodings can be -obtained by executing - -Cencodings( ":all" )) ;' > - -[Default encoding is utf8 unless the first few lines of the preamble contain -an invocation C<\usepackage[..]{inputenc}> in which case the -encoding chosen by this command is asssumed. Note that ASCII (standard -latex) is a subset of utf8] - -=item B<--preamble=file> or -B<-p file> - -Insert file at end of preamble instead of generating -preamble. The preamble must define the following commands -C<\DIFaddbegin, \DIFaddend, \DIFadd{..}, -\DIFdelbegin,\DIFdelend,\DIFdel{..},> -and varieties for use within floats -C<\DIFaddbeginFL, \DIFaddendFL, \DIFaddFL{..}, -\DIFdelbeginFL, \DIFdelendFL, \DIFdelFL{..}> -(If this option is set B<-t>, B<-s>, and B<-f> options -are ignored.) - -=item B<--packages=pkg1,pkg2,..> - -Tell latexdiff that .tex file is processed with the packages in list -loaded. This is normally not necessary if the .tex file includes the -preamble, as the preamble is automatically scanned for C<\usepackage> commands. -Use of the B<--packages> option disables automatic scanning, so if for any -reason package specific parsing needs to be switched off, use B<--packages=none>. -The following packages trigger special behaviour: - -=over 8 - -=item C - -Configuration variable amsmath is set to C (Default: C) - -=item C - -Ensure that C<\begin{figure}> and C<\end{figure}> always appear by themselves on a line. - -=item C - -Change name of C<\DIFadd> and C<\DIFdel> commands to C<\DIFaddtex> and C<\DIFdeltex> and -define new C<\DIFadd> and C<\DIFdel> commands, which provide a wrapper for these commands, -using them for the text but not for the link defining command (where any markup would cause -errors). - -=back - -[ Default: scan the preamble for C<\\usepackage> commands to determine - loaded packages.] - - - -=item B<--show-preamble> - -Print generated or included preamble commands to stdout. - -=back - -=head2 Configuration - -=over 4 - -=item B<--exclude-safecmd=exclude-file> or -B<-A exclude-file> or B<--exclude-safecmd="cmd1,cmd2,..."> - -=item B<--replace-safecmd=replace-file> - -=item B<--append-safecmd=append-file> or -B<-a append-file> or B<--append-safecmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions (RegEx) -matching commands which are safe to use within the -scope of a C<\DIFadd> or C<\DIFdel> command. The file must contain -one Perl-RegEx per line (Comment lines beginning with # or % are -ignored). Note that the RegEx needs to match the whole of -the token, i.e., /^regex$/ is implied and that the initial -"\" of the command is not included. -The B<--exclude-safecmd> and B<--append-safecmd> options can be combined with the -B<--replace-safecmd> -option and can be used repeatedly to add cumulatively to the lists. - B<--exclude-safecmd> -and B<--append-safecmd> can also take a comma separated list as input. If a -comma for one of the regex is required, escape it thus "\,". In most cases it -will be necessary to protect the comma-separated list from the shell by putting -it in quotation marks. - -=item B<--exclude-textcmd=exclude-file> or -B<-X exclude-file> or B<--exclude-textcmd="cmd1,cmd2,..."> - -=item B<--replace-textcmd=replace-file> - -=item B<--append-textcmd=append-file> or -B<-x append-file> or B<--append-textcmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions -matching commands whose last argument is text. See -entry for B<--exclude-safecmd> directly above for further details. - - -=item B<--replace-context1cmd=replace-file> - -=item B<--append-context1cmd=append-file> or -=item B<--append-context1cmd="cmd1,cmd2,..."> - -Replace or append to the list of regex matching commands -whose last argument is text but which require a particular -context to work, e.g. \caption will only work within a figure -or table. These commands behave like text commands, except when -they occur in a deleted section, when they are disabled, but their -argument is shown as deleted text. - -=item B<--replace-context2cmd=replace-file> - -=item B<--append-context2cmd=append-file> or -=item B<--append-context2cmd="cmd1,cmd2,..."> -As corresponding commands for context1. The only difference is that -context2 commands are completely disabled in deleted sections, including -their arguments. - - - -=item B<--config var1=val1,var2=val2,...> or B<-c var1=val1,..> - -=item B<-c configfile> - -Set configuration variables. The option can be repeated to set different -variables (as an alternative to the comma-separated list). -Available variables (see below for further explanations): - -C (integer) - -C (RegEx) - -C (RegEx) - -C (RegEx) - -C (String) - -C (RegEx) - -C (String) - -C (RegEx) - -C (RegEx) - -=item B<--show-safecmd> - -Print list of RegEx matching and excluding safe commands. - -=item B<--show-textcmd> - -Print list of RegEx matching and excluding commands with text argument. - -=item B<--show-config> - -Show values of configuration variables. - -=item B<--show-all> - -Combine all --show commands. - -NB For all --show commands, no C or C file needs to be specified, and no -differencing takes place. - -=back - -=head2 Other configuration options: - -=over 4 - -=item B<--allow-spaces> - -Allow spaces between bracketed or braced arguments to commands. Note -that this option might have undesirable side effects (unrelated scope -might get lumpeded with preceding commands) so should only be used if the -default produces erroneous results. (Default requires arguments to -directly follow each other without intervening spaces). - -=item B<--math-markup=level> - -Determine granularity of markup in displayed math environments: -Possible values for level are (both numerical and text labels are acceptable): - -C or C<0>: suppress markup for math environments. Deleted equations will not -appear in diff file. This mode can be used if all the other modes -cause invalid latex code. - -C or C<1>: Differencing on the level of whole equations. Even trivial changes -to equations cause the whole equation to be marked changed. This -mode can be used if processing in coarse or fine mode results in -invalid latex code. - -C or C<2>: Detect changes within equations marked up with a coarse -granularity; changes in equation type (e.g.displaymath to equation) -appear as a change to the complete equation. This mode is recommended -for situations where the content and order of some equations are still -being changed. [Default] - -C or C<3>: Detect small change in equations and mark up at fine granularity. -This mode is most suitable, if only minor changes to equations are -expected, e.g. correction of typos. - -=item B<--disable-citation-markup> - -Suppress citation markup in styles using ulem (UNDERLINE, -FONTSTRIKE, CULINECHBAR) - -=item B<--enable-citation-markup> - -Protect citation commands in changed sections with \\mbox command [i.e. use default behaviour for ulem package for other packages] - -=back - -=head2 Miscellaneous - -=over 4 -=item B<--verbose> or B<-V> - -Output various status information to stderr during processing. -Default is to work silently. - -=item B<--driver=type> - -Choose driver for changebar package (only relevant for styles using - changebar: CCHANGEBAR CFONTCHBAR CULINECHBAR CHANGEBAR). Possible -drivers are listed in changebar manual, e.g. pdftex,dvips,dvitops - [Default: dvips] - -=item B<--ignore-warnings> - -Suppress warnings about inconsistencies in length between input and -parsed strings and missing characters. These warning messages are -often related to non-standard latex or latex constructions with a -syntax unknown to C but the resulting difference argument -is often fully functional anyway, particularly if the non-standard -latex only occurs in parts of the text which have not changed. - -=item B<--label=label> or -B<-L label> - -Sets the labels used to describe the old and new files. The first use -of this option sets the label describing the old file and the second -use of the option sets the label for the new file, i.e. set both -labels like this C<-L labelold -L labelnew>. -[Default: use the filename and modification dates for the label] - -=item B<--no-label> - -Suppress inclusion of old and new file names as comment in output file - -=item B<--visble-label> - -Include old and new filenames (or labels set with --label option) as -visible output. - -=item B<--flatten> - -Replace C<\input> and C<\include> commands within body by the content -of the files in their argument. If C<\includeonly> is present in the -preamble, only those files are expanded into the document. However, -no recursion is done, i.e. C<\input> and C<\include> commands within -included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, -respectively, making it possible to organise files into old and new directories. ---flatten is applied recursively, so inputted files can contain further -C<\input> statements. - -Use of this option might result in prohibitive processing times for -larger documents, and the resulting difference document -no longer reflects the structure of the input documents. - -=item B<--help> or -B<-h> - -Show help text - -=item B<--version> - -Show version number - -=back - - - -=head2 Predefined styles - -=head2 Major types - -The major type determine the markup of plain text and some selected latex commands outside floats by defining the markup commands C<\DIFadd{...}> and C<\DIFdel{...}> . - -=over 10 - -=item C - -Added text is wavy-underlined and blue, discarded text is struck out and red -(Requires color and ulem packages). Overstriking does not work in displayed math equations such that deleted parts of equation are underlined, not struck out (this is a shortcoming inherent to the ulem package). - -=item C - -Added text is blue and set in sans-serif, and a red footnote is created for each discarded -piece of text. (Requires color package) - -=item C - -Like C but without the use of color. - -=item C - -Added text is blue and set in sans-serif, and discarded text is red and very small size. - -=item C - -Added tex is set in sans-serif, discarded text small and struck out - -=item C - -Added text is blue, and discarded text is red. Additionally, the changed text is marked with a bar in the margin (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color, ulem and changebar packages). - -=item C - -No mark up of text, but mark margins with changebars (Requires changebar package). - -=item C - -No visible markup (but generic markup commands will still be inserted. - -=back - -=head2 Subtypes - -The subtype defines the commands that are inserted at the begin and end of added or discarded blocks, irrespectively of whether these blocks contain text or commands (Defined commands: C<\DIFaddbegin, \DIFaddend, \DIFdelbegin, \DIFdelend>) - -=over 10 - -=item C - -No additional markup (Recommended choice) - -=item C - -Mark beginning and end of changed blocks with symbols in the margin nearby (using -the standard C<\marginpar> command - note that this sometimes moves somewhat -from the intended position. - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. -(It is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete, for example -with citation commands). - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. Note -that C only works with the dvips converter, e.g. not pdflatex. -(it is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete). - -=back - -=head2 Float Types - -Some of the markup used in the main text might cause problems when used within -floats (e.g. figures or tables). For this reason alternative versions of all -markup commands are used within floats. The float type defines these alternative commands. - -=over 10 - -=item C - -Use identical markup for text as in the main body, but set all commands marking the begin and end of changed blocks to null-commands. You have to choose this float type if your subtype is C as C<\marginpar> does not work properly within floats. - -=item C - -Mark additions the same way as in the main text. Deleted environments are marked by angular brackets \[ and \] and the deleted text is set in scriptscript size. This float type should always be used with the C and C markup types as the \footnote command does not work properly in floating environments. - -=item C - -Make no difference between the main text and floats. - -=back - - -=head2 Configuration Variables - -=over 10 - -=item C - -Minimum number of tokens required to form an independent block. This value is -used in the algorithm to detect changes of complete blocks by merging identical text parts of less than C to the preceding added and discarded parts. - -[ Default: 3 ] - -=item C - -Environments whose name matches the regular expression in C are -considered floats. Within these environments, the I markup commands -are replaced by their FL variaties. - -[ Default: S >] - -=item C - -Within environments whose name matches the regular expression in C -all latexdiff markup is removed (in pathologic cases this might lead to - inconsistent markup but this situation should be rare). - -[ Default: S >] - -=item C,C - -If both \begin and \end for a math environment (environment name matching C -or \[ and \]) -are within the same deleted block, they are replaced by a \begin and \end commands for C -rather than being commented out. - -[ Default: C=S >, C=S >] - -=item C,C - -as C,C but for equation arrays - -[ Default: C=S >, C=S >] - -=item C - -If a match to C is found within an inline math environment within a deleted or added block, then the inlined math -is surrounded by C<\mbox{>...C<}>. This is necessary as underlining does not work within inlined array environments. - -[ Default: C=S > - -=item C - -If a command in a deleted block which is also in the textcmd list matches C then an -additional command C<\addtocounter{>FC<}{-1}>, where F is the matching command, is appended in the diff file such that the numbering in the diff file remains synchronized with the -numbering in the new file. - -[ Default: C=C<(?:footnote|part|section|subsection> ... - -C<|subsubsection|paragraph|subparagraph)> ] - -=back - -=head1 COMMON PROBLEMS - -=over 10 - -=item Citations result in overfull boxes - -There is an incompatibility between the C package, which C uses for underlining and striking out in the UNDERLINE style, -the default style. In order to be able to mark up citations properly, they are placed with an C<\mbox> command in post-processing. As mboxes -cannot be broken across lines, this procedure frequently results in overfull boxes, possibly obscuring the content as it extends beyond the right margin. If this is a problem, you have two possibilities: - -1. Use C or C subtype markup (option C<-s COLOR>): If this markup is chosen, then changed citations are no longer marked up -with the wavy line (additions) or struck out (deletions), but are still highlighted in the appropriate color. - -2. Choose option C<--disable-citation-markup> which turns off the marking up of citations: deleted citations are no longer shown, and -added ctations are shown without markup. (This was the default behaviour of latexdiff at versions 0.6 and older) - -=item Changes in complicated mathematical equations result in latex processing errors - -Try options C<--math-markup=whole>. If even that fails, you can turn off mark up for equations with C<--math-markup=off>. - -=back - -=head1 BUGS - -Option allow-spaces not implemented entirely consistently. It breaks -the rules that number and type of white space does not matter, as -different numbers of inter-argument spaces are treated as significant. - -Please submit bug reports on the latexdiff project page I, -send them to user discussion list C (prior subscription -to list required, also on project webpage) -or send them to I. Include the serial number of I -(from comments at the top of the source or use B<--version>). If you come across latex -files that are error-free and conform to the specifications set out -above, and whose differencing still does not result in error-free -latex, please send me those files, ideally edited to only contain the -offending passage as long as that still reproduces the problem. If your -file relies on non-standard class files, you must include those. I will not -look at examples where I have trouble to latex the original files. - -=head1 SEE ALSO - -L, L - -=head1 PORTABILITY - -I does not make use of external commands and thus should run -on any platform supporting Perl 5.6 or higher. If files with encodings -other than ASCII or UTF-8 are processed, Perl 5.8 or higher is required. - -The standard version of I requires installation of the Perl package -C (available from I - -I) but a stand-alone -version, I, which has this package inlined, is available, too. -I requires the I command to be present. - -=head1 AUTHOR - -Version 1.0.2 -Copyright (C) 2004-2012 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 - -Contributors of fixes and additions: V. Kuhlmann, J. Paisley, N. Becker, T. Doerges, K. Huebner, -T. Connors, Sebastian Gouezel and many others. -Thanks to the many people who send in bug reports, feature suggestions, and other feedback. - -=cut - -__END__ -%%BEGIN SAFE COMMANDS -% Regex matching commands which can safely be in the -% argument of a \DIFadd or \DIFdel command (leave out the \) -arabic -dashbox -emph -fbox -framebox -hspace -math.* -makebox -mbox -pageref -ref -symbol -raisebox -rule -text.* -shortstack -usebox -dag -ddag -copyright -pounds -S -P -oe -OE -ae -AE -aa -AA -o -O -l -L -frac -ss -sqrt -ldots -cdots -vdots -ddots -alpha -beta -gamma -delta -epsilon -varepsilon -zeta -eta -theta -vartheta -iota -kappa -lambda -mu -nu -xi -pi -varpi -rho -varrho -sigma -varsigma -tau -upsilon -phi -varphi -chi -psi -omega -Gamma -Delta -Theta -Lambda -Xi -Pi -Sigma -Upsilon -Phi -Psi -Omega -ps -mp -times -div -ast -star -circ -bullet -cdot -cap -cup -uplus -sqcap -vee -wedge -setminus -wr -diamond -(?:big)?triangle.* -lhd -rhd -unlhd -unrhd -oplus -ominus -otimes -oslash -odot -bigcirc -d?dagger -amalg -leq -prec -preceq -ll -(?:sq)?su[bp]set(?:eq)? -in -vdash -geq -succ(?:eq)? -gg -ni -dashv -equiv -sim(?:eq)? -asymp -approx -cong -neq -doteq -propto -models -perp -mid -parallel -bowtie -Join -smile -frown -.*arrow -(?:long)?mapsto -.*harpoon.* -leadsto -aleph -hbar -imath -jmath -ell -wp -Re -Im -mho -prime -emptyset -nabla -surd -top -bot -angle -forall -exists -neg -flat -natural -sharp -backslash -partial -infty -Box -Diamond -triangle -clubsuit -diamondsuit -heartsuit -spadesuit -sum -prod -coprod -int -oint -big(?:sq)?c[au]p -bigvee -bigwedge -bigodot -bigotimes -bigoplus -biguplus -(?:arc)?(?:cos|sin|tan|cot)h? -csc -arg -deg -det -dim -exp -gcd -hom -inf -ker -lg -lim -liminf -limsup -ln -log -max -min -Pr -sec -sup -(SUPER|SUB)SCRIPTNB -(SUPER|SUB)SCRIPT -%%END SAFE COMMANDS - -%%BEGIN TEXT COMMANDS -% Regex matching commands with a text argument (leave out the \) -addcontents.* -cc -closing -chapter -dashbox -emph -encl -fbox -framebox -footnote -footnotetext -framebox -part -(sub){0,2}section\*? -(sub)?paragraph\*? -makebox -mbox -opening -parbox -raisebox -savebox -sbox -shortstack -signature -text.* -value -underline -sqrt -(SUPER|SUB)SCRIPT -%%END TEXT COMMANDS - -%%BEGIN CONTEXT1 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -caption -%%END CONTEXT1 COMMANDS - -%%BEGIN CONTEXT2 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -title -author -date -institute -%%END CONTEXT2 COMMANDS - - -%% TYPES (Commands for highlighting changed blocks) - -%DIF UNDERLINE PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}} -\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}} -%DIF END UNDERLINE PREAMBLE - -%DIF CTRADITIONAL PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} [..\footnote{removed: #1} ]}} -%DIF END CTRADITIONAL PREAMBLE - -%DIF TRADITIONAL PREAMBLE -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{[..\footnote{removed: #1} ]}} -%DIF END TRADITIONAL PREAMBLE - -%DIF CFONT PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} \scriptsize #1}} -%DIF END CFONT PREAMBLE - -%DIF FONTSTRIKE PREAMBLE -\RequirePackage[normalem]{ulem} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{\footnotesize \sout{#1}}} -%DIF END FONTSTRIKE PREAMBLE - -%DIF CCHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}#1}\protect\cbdelete} -%DIF END CCHANGEBAR PREAMBLE - -%DIF CFONTCHBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\sf #1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\scriptsize #1}\protect\cbdelete} -%DIF END CFONTCHBAR PREAMBLE - -%DIF CULINECHBAR PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage[dvips]{changebar} -\RequirePackage{color} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\uwave{#1}}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\sout{#1}}\protect\cbdelete} -%DIF END CULINECHBAR PREAMBLE - -%DIF CHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\providecommand{\DIFadd}[1]{\protect\cbstart{#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete} -%DIF END CHANGEBAR PREAMBLE - -%DIF INVISIBLE PREAMBLE -\providecommand{\DIFadd}[1]{#1} -\providecommand{\DIFdel}[1]{} -%DIF END INVISIBLE PREAMBLE - - -%% SUBTYPES (Markers for beginning and end of changed blocks) - -%DIF SAFE PREAMBLE -\providecommand{\DIFaddbegin}{} -\providecommand{\DIFaddend}{} -\providecommand{\DIFdelbegin}{} -\providecommand{\DIFdelend}{} -%DIF END SAFE PREAMBLE - -%DIF MARGIN PREAMBLE -\providecommand{\DIFaddbegin}{\protect\marginpar{a[}} -\providecommand{\DIFaddend}{\protect\marginpar{]}} -\providecommand{\DIFdelbegin}{\protect\marginpar{d[}} -\providecommand{\DIFdelend}{\protect\marginpar{]}} -%DIF END BRACKET PREAMBLE - -%DIF DVIPSCOL PREAMBLE -%Note: only works with dvips converter -\RequirePackage{color} -\RequirePackage{dvipscol} -\providecommand{\DIFaddbegin}{\protect\nogroupcolor{blue}} -\providecommand{\DIFaddend}{\protect\nogroupcolor{black}} -\providecommand{\DIFdelbegin}{\protect\nogroupcolor{red}} -\providecommand{\DIFdelend}{\protect\nogroupcolor{black}} -%DIF END DVIPSCOL PREAMBLE - -%DIF COLOR PREAMBLE -\RequirePackage{color} -\providecommand{\DIFaddbegin}{\protect\color{blue}} -\providecommand{\DIFaddend}{\protect\color{black}} -\providecommand{\DIFdelbegin}{\protect\color{red}} -\providecommand{\DIFdelend}{\protect\color{black}} -%DIF END COLOR PREAMBLE - - -%% FLOAT TYPES - -%DIF FLOATSAFE PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%DIF IDENTICAL PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{\DIFaddbegin} -\providecommand{\DIFaddendFL}{\DIFaddend} -\providecommand{\DIFdelbeginFL}{\DIFdelbegin} -\providecommand{\DIFdelendFL}{\DIFdelend} -%DIF END IDENTICAL PREAMBLE - -%DIF TRADITIONALSAFE PREAMBLE -% procidecommand color to make this work for TRADITIONAL and CTRADITIONAL -\providecommand{\color}[1]{} -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdel}[1]{{\protect\color{red}[..{\scriptsize {removed: #1}} ]}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%% SPECIAL PACKAGE PREAMBLE COMMANDS - -% Standard \DIFadd and \DIFdel are redefined as \DIFaddtex and \DIFdeltex -% when hyperref package is included. -%DIF HYPERREF PREAMBLE -\providecommand{\DIFadd}[1]{\texorpdfstring{\DIFaddtex{#1}}{#1}} -\providecommand{\DIFdel}[1]{\texorpdfstring{\DIFdeltex{#1}}{}} -%DIF END HYPERREF PACKAGE diff --git a/latexdiff-1.0.2/latexdiff-so b/latexdiff-1.0.2/latexdiff-so deleted file mode 100755 index 865fc48..0000000 --- a/latexdiff-1.0.2/latexdiff-so +++ /dev/null @@ -1,3857 +0,0 @@ -#!/usr/bin/env perl -##!/usr/bin/perl -w -# latexdiff - differences two latex files on the word level -# and produces a latex file with the differences marked up. -# -# Copyright (C) 2004-12 F J Tilmann (tilmann@gfz-potsdam.de, ftilmann@users.berlios.de) -# -# Project webpages: http://latexdiff.berlios.de/ -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# -# Version 1.0.1 - treat \big,\bigg etc. equivalently to \left and -# \right - include starred version in MATHENV - apply -# - flatten recursively and --flatten expansion is now -# aware of comments (thanks to Tim Connors for patch) -# - Change to post-processing for more reliability for -# deleted math environments -# - On linux systems, recognise and remove DOS style newlines -# - Provide markup for some special preamble commands (\title, -# \author,\date, -# - configurable by setting context2cmd -# - for styles using ulem package, remove \emph and \text.. from list of -# safe commands in order to allow linebreaks within the -# highlighted sections. -# - for ulem style, now show citations by enclosing them in \mbox commands. -# This unfortunately implies linebreaks within citations no longer function, -# so this functionality can be turned off (Option --disable-citation-markup). -# With --enable-citation-markup, the mbox markup is forced for other styles) -# - new substyle COLOR. This is particularly useful for marking up citations -# and some special post-processing is implemented to retain cite -# commands in deleted blocks. -# - four different levels of math-markup -# - Option --driver for choosing driver for modes employing changebar package -# - accept \\* as valid command (and other commands of form \.*). Also accept -# \ (backslashed newline) -# - some typo fixes, include commands defined in preamble as safe commands -# (Sebastian Gouezel) -# - include compared filenames as comments as line 2 and 3 of -# the preamble (can be modified with option --label, and suppressed with -# --no-label), option --visible-label to show files in generated pdf or dvi -# at the beginning of main document -# -# Version 0.5 A number of minor improvements based on feedback -# Deleted blocks are now shown before added blocks -# Package specific processing -# -# Version 0.43 unreleased typo in list of styles at the end -# Add protect to all \cbstart, \cbend commands -# More robust substitution of deleted math commands -# -# Version 0.42 November 06 Bug fixes only -# -# Version 0.4 March 06 option for fast differencing using UNIX diff command, several minor bug fixes (\par bug, improved highlighting of textcmds) -# -# Version 0.3 August 05 improved parsing of displayed math, --allow-spaces -# option, several minor bug fixes -# -# Version 0.25 October 04 Fix bug with deleted equations, add math mode commands to safecmd, add | to allowed interpunctuation signs -# Version 0.2 September 04 extension to utf-8 and variable encodings -# Version 0.1 August 04 First public release - -# Inserted block for stand-alone version replaces -# use Algorithm::Diff qw(traverse_sequences); -# in standard version -# The following BEGIN block contains a verbatim copy of -# Ned Konz' Algorithm::Diff package version 1.15 except -# that all POD documentation has been stripped out. -# I encourage you to download and install the Algorithm::Diff -# package and use the standard latexdiff version instead -# (current distribution available from http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15 -# the most recent version can be found via http://search.cpan.org/search?module=Algorithm::Diff ) -# Please note that the LICENCSE for Algorithm::Diff : -# "Copyright (c) 2000-2002 Ned Konz. All rights reserved. -# This program is free software; -# you can redistribute it and/or modify it under the same terms -# as Perl itself." -# The stand-alone version of latexdiff is provided as a convenience -# for latex users with no knowledge of PERL who do not wish to install -# additional packages to be able to use latexdiff. If you believe -# the inlining of Algorithm::Diff violates its license please contact -# me and I will modify the latexdiff distribution accordingly. -# Frederik Tilmann (tilmann@esc.cam.ac.uk) -BEGIN { -package Algorithm::Diff; -use strict; -use vars qw($VERSION @EXPORT_OK @ISA @EXPORT); -use integer; # see below in _replaceNextLargerWith() for mod to make - # if you don't use this -require Exporter; -@ISA = qw(Exporter); -@EXPORT = qw(); -@EXPORT_OK = qw(LCS diff traverse_sequences traverse_balanced sdiff); -$VERSION = sprintf('%d.%02d so', (q$Revision: 1.15 $ =~ /\d+/g)); - -# McIlroy-Hunt diff algorithm -# Adapted from the Smalltalk code of Mario I. Wolczko, -# by Ned Konz, perl@bike-nomad.com - - -# Create a hash that maps each element of $aCollection to the set of positions -# it occupies in $aCollection, restricted to the elements within the range of -# indexes specified by $start and $end. -# The fourth parameter is a subroutine reference that will be called to -# generate a string to use as a key. -# Additional parameters, if any, will be passed to this subroutine. -# -# my $hashRef = _withPositionsOfInInterval( \@array, $start, $end, $keyGen ); - -sub _withPositionsOfInInterval -{ - my $aCollection = shift; # array ref - my $start = shift; - my $end = shift; - my $keyGen = shift; - my %d; - my $index; - for ( $index = $start ; $index <= $end ; $index++ ) - { - my $element = $aCollection->[$index]; - my $key = &$keyGen( $element, @_ ); - if ( exists( $d{$key} ) ) - { - unshift ( @{ $d{$key} }, $index ); - } - else - { - $d{$key} = [$index]; - } - } - return wantarray ? %d : \%d; -} - -# Find the place at which aValue would normally be inserted into the array. If -# that place is already occupied by aValue, do nothing, and return undef. If -# the place does not exist (i.e., it is off the end of the array), add it to -# the end, otherwise replace the element at that point with aValue. -# It is assumed that the array's values are numeric. -# This is where the bulk (75%) of the time is spent in this module, so try to -# make it fast! - -sub _replaceNextLargerWith -{ - my ( $array, $aValue, $high ) = @_; - $high ||= $#$array; - - # off the end? - if ( $high == -1 || $aValue > $array->[-1] ) - { - push ( @$array, $aValue ); - return $high + 1; - } - - # binary search for insertion point... - my $low = 0; - my $index; - my $found; - while ( $low <= $high ) - { - $index = ( $high + $low ) / 2; - - # $index = int(( $high + $low ) / 2); # without 'use integer' - $found = $array->[$index]; - - if ( $aValue == $found ) - { - return undef; - } - elsif ( $aValue > $found ) - { - $low = $index + 1; - } - else - { - $high = $index - 1; - } - } - - # now insertion point is in $low. - $array->[$low] = $aValue; # overwrite next larger - return $low; -} - -# This method computes the longest common subsequence in $a and $b. - -# Result is array or ref, whose contents is such that -# $a->[ $i ] == $b->[ $result[ $i ] ] -# foreach $i in ( 0 .. $#result ) if $result[ $i ] is defined. - -# An additional argument may be passed; this is a hash or key generating -# function that should return a string that uniquely identifies the given -# element. It should be the case that if the key is the same, the elements -# will compare the same. If this parameter is undef or missing, the key -# will be the element as a string. - -# By default, comparisons will use "eq" and elements will be turned into keys -# using the default stringizing operator '""'. - -# Additional parameters, if any, will be passed to the key generation routine. - -sub _longestCommonSubsequence -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $keyGen = shift; # code ref - my $compare; # code ref - - # set up code refs - # Note that these are optimized. - if ( !defined($keyGen) ) # optimize for strings - { - $keyGen = sub { $_[0] }; - $compare = sub { my ( $a, $b ) = @_; $a eq $b }; - } - else - { - $compare = sub { - my $a = shift; - my $b = shift; - &$keyGen( $a, @_ ) eq &$keyGen( $b, @_ ); - }; - } - - my ( $aStart, $aFinish, $bStart, $bFinish, $matchVector ) = - ( 0, $#$a, 0, $#$b, [] ); - - # First we prune off any common elements at the beginning - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aStart], $b->[$bStart], @_ ) ) - { - $matchVector->[ $aStart++ ] = $bStart++; - } - - # now the end - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aFinish], $b->[$bFinish], @_ ) ) - { - $matchVector->[ $aFinish-- ] = $bFinish--; - } - - # Now compute the equivalence classes of positions of elements - my $bMatches = - _withPositionsOfInInterval( $b, $bStart, $bFinish, $keyGen, @_ ); - my $thresh = []; - my $links = []; - - my ( $i, $ai, $j, $k ); - for ( $i = $aStart ; $i <= $aFinish ; $i++ ) - { - $ai = &$keyGen( $a->[$i], @_ ); - if ( exists( $bMatches->{$ai} ) ) - { - $k = 0; - for $j ( @{ $bMatches->{$ai} } ) - { - - # optimization: most of the time this will be true - if ( $k and $thresh->[$k] > $j and $thresh->[ $k - 1 ] < $j ) - { - $thresh->[$k] = $j; - } - else - { - $k = _replaceNextLargerWith( $thresh, $j, $k ); - } - - # oddly, it's faster to always test this (CPU cache?). - if ( defined($k) ) - { - $links->[$k] = - [ ( $k ? $links->[ $k - 1 ] : undef ), $i, $j ]; - } - } - } - } - - if (@$thresh) - { - for ( my $link = $links->[$#$thresh] ; $link ; $link = $link->[0] ) - { - $matchVector->[ $link->[1] ] = $link->[2]; - } - } - - return wantarray ? @$matchVector : $matchVector; -} - -sub traverse_sequences -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $finishedACallback = $callbacks->{'A_FINISHED'}; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $finishedBCallback = $callbacks->{'B_FINISHED'}; - my $matchVector = _longestCommonSubsequence( $a, $b, $keyGen, @_ ); - - # Process all the lines in @$matchVector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai; - - for ( $ai = 0 ; $ai <= $#$matchVector ; $ai++ ) - { - my $bLine = $matchVector->[$ai]; - if ( defined($bLine) ) # matched - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi < $bLine; - &$matchCallback( $ai, $bi++, @_ ); - } - else - { - &$discardACallback( $ai, $bi, @_ ); - } - } - - # The last entry (if any) processed was a match. - # $ai and $bi point just past the last matching lines in their sequences. - - while ( $ai <= $lastA or $bi <= $lastB ) - { - - # last A? - if ( $ai == $lastA + 1 and $bi <= $lastB ) - { - if ( defined($finishedACallback) ) - { - &$finishedACallback( $lastA, @_ ); - $finishedACallback = undef; - } - else - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi <= $lastB; - } - } - - # last B? - if ( $bi == $lastB + 1 and $ai <= $lastA ) - { - if ( defined($finishedBCallback) ) - { - &$finishedBCallback( $lastB, @_ ); - $finishedBCallback = undef; - } - else - { - &$discardACallback( $ai++, $bi, @_ ) while $ai <= $lastA; - } - } - - &$discardACallback( $ai++, $bi, @_ ) if $ai <= $lastA; - &$discardBCallback( $ai, $bi++, @_ ) if $bi <= $lastB; - } - - return 1; -} - -sub traverse_balanced -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $changeCallback = $callbacks->{'CHANGE'}; - my $matchVector = _longestCommonSubsequence( $a, $b, $keyGen, @_ ); - - # Process all the lines in match vector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai = 0; - my $ma = -1; - my $mb; - - while (1) - { - - # Find next match indices $ma and $mb - do { $ma++ } while ( $ma <= $#$matchVector && !defined $matchVector->[$ma] ); - - last if $ma > $#$matchVector; # end of matchVector? - $mb = $matchVector->[$ma]; - - # Proceed with discard a/b or change events until - # next match - while ( $ai < $ma || $bi < $mb ) - { - - if ( $ai < $ma && $bi < $mb ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai < $ma ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi < $mb - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - # Match - &$matchCallback( $ai++, $bi++, @_ ); - } - - while ( $ai <= $lastA || $bi <= $lastB ) - { - if ( $ai <= $lastA && $bi <= $lastB ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai <= $lastA ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi <= $lastB - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - return 1; -} - -sub LCS -{ - my $a = shift; # array ref - my $matchVector = _longestCommonSubsequence( $a, @_ ); - my @retval; - my $i; - for ( $i = 0 ; $i <= $#$matchVector ; $i++ ) - { - if ( defined( $matchVector->[$i] ) ) - { - push ( @retval, $a->[$i] ); - } - } - return wantarray ? @retval : \@retval; -} - -sub diff -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $hunk = []; - my $discard = sub { push ( @$hunk, [ '-', $_[0], $a->[ $_[0] ] ] ) }; - my $add = sub { push ( @$hunk, [ '+', $_[1], $b->[ $_[1] ] ] ) }; - my $match = sub { push ( @$retval, $hunk ) if scalar(@$hunk); $hunk = [] }; - traverse_sequences( $a, $b, - { MATCH => $match, DISCARD_A => $discard, DISCARD_B => $add }, @_ ); - &$match(); - return wantarray ? @$retval : $retval; -} - -sub sdiff -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $discard = sub { push ( @$retval, [ '-', $a->[ $_[0] ], "" ] ) }; - my $add = sub { push ( @$retval, [ '+', "", $b->[ $_[1] ] ] ) }; - my $change = sub { - push ( @$retval, [ 'c', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - my $match = sub { - push ( @$retval, [ 'u', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - traverse_balanced( - $a, - $b, - { - MATCH => $match, - DISCARD_A => $discard, - DISCARD_B => $add, - CHANGE => $change, - }, - @_ - ); - return wantarray ? @$retval : $retval; -} - -1; -} -import Algorithm::Diff qw(traverse_sequences); -# End of inserted block for stand-alone version - -use Getopt::Long ; -use strict ; -use warnings; -use utf8 ; - -my ($algodiffversion)=split(/ /,$Algorithm::Diff::VERSION); - - -my ($versionstring)=< 0, - WHOLE => 1, - COARSE => 2, - FINE => 3 -}; - - -my (@configlist,@labels, - @appendsafelist,@excludesafelist, - @appendtextlist,@excludetextlist, - @appendcontext1list,@appendcontext2list, - @packagelist); -my ($assign,@config); -# Hash where keys corresponds to the names of all included packages (including the documentclass as another package -# the optional arguments to the package are the values of the hash elements -my ($pkg,%packages); -# Defaults -$type='UNDERLINE'; -$subtype='SAFE'; -$floattype='FLOATSAFE'; -$mathmarkup=COARSE; - -$verbose=0; -# output debug and intermediate files, set to 0 in final distribution -$debug=0; -# define character properties -sub IsNonAsciiPunct { return <<'END' # Unicode punctuation but excluding ASCII punctuation -+utf8::IsPunct --utf8::IsASCII -END -} -sub IsNonAsciiS { return <<'END' # Unicode symbol but excluding ASCII -+utf8::IsS --utf8::IsASCII -END -} - - -my %verbhash; - -Getopt::Long::Configure('bundling'); -GetOptions('type|t=s' => \$type, - 'subtype|s=s' => \$subtype, - 'floattype|f=s' => \$floattype, - 'config|c=s' => \@configlist, - 'preamble|p=s' => \$preamblefile, - 'encoding|e=s' => \$encoding, - 'label|L=s' => \@labels, - 'no-label' => \$nolabel, - 'visible-label' => \$visiblelabel, - 'exclude-safecmd|A=s' => \@excludesafelist, - 'replace-safecmd=s' => \$replacesafe, - 'append-safecmd|a=s' => \@appendsafelist, - 'exclude-textcmd|X=s' => \@excludetextlist, - 'replace-textcmd=s' => \$replacetext, - 'append-textcmd|x=s' => \@appendtextlist, - 'replace-context1cmd=s' => \$replacecontext1, - 'append-context1cmd=s' => \@appendcontext1list, - 'replace-context2cmd=s' => \$replacecontext2, - 'append-context2cmd=s' => \@appendcontext2list, - 'show-preamble' => \$showpreamble, - 'show-safecmd' => \$showsafe, - 'show-textcmd' => \$showtext, - 'show-config' => \$showconfig, - 'show-all' => \$showall, - 'packages=s' => \@packagelist, - 'allow-spaces' => \$allowspaces, - 'math-markup=s' => \$mathmarkup, - 'enable-citation-markup' => \$enablecitmark, - 'disable-citation-markup' => \$disablecitmark, - 'verbose|V' => \$verbose, - 'ignore-warnings' => \$ignorewarnings, - 'driver=s'=> \$driver, - 'flatten' => \$flatten, - 'version' => \$version, - 'help|h|H' => \$help); - -if ( $help ) { - usage() ; -} - - -if ( $version ) { - die $versionstring ; -} - -print STDERR $versionstring if $verbose; - -if (defined($showall)){ - $showpreamble=$showsafe=$showtext=$showconfig=1; -} - -if (defined($mathmarkup)) { - $mathmarkup=~tr/a-z/A-Z/; - if ( $mathmarkup eq 'OFF' ){ - $mathmarkup=OFF; - } elsif ( $mathmarkup eq 'WHOLE' ){ - $mathmarkup=WHOLE; - } elsif ( $mathmarkup eq 'COARSE' ){ - $mathmarkup=COARSE; - } elsif ( $mathmarkup eq 'FINE' ){ - $mathmarkup=FINE; - } elsif ( $mathmarkup !~ m/^[0123]$/ ) { - die "Illegal value: ($mathmarkup) for option--math-markup. Possible values: OFF,WHOLE,COARSE,FINE,0- "; - } - # else use numerical value -} - -# setting extra preamble commands -if (defined($preamblefile)) { - $latexdiffpreamble=join "\n",(extrapream($preamblefile),""); -} else { - $latexdiffpreamble=join "\n",(extrapream($type,$subtype,$floattype),""); -} - -if ( defined($driver) ) { - # for changebar only - $latexdiffpreamble=~s/\[dvips\]/[$driver]/sg; -} -# setting up @SAFECMDLIST and @SAFECMDEXCL -if (defined($replacesafe)) { - init_regex_arr_ext(\@SAFECMDLIST,$replacesafe); -} else { - init_regex_arr_data(\@SAFECMDLIST, "SAFE COMMANDS"); -} -foreach $appendsafe ( @appendsafelist ) { - init_regex_arr_ext(\@SAFECMDLIST, $appendsafe); -} -foreach $excludesafe ( @excludesafelist ) { - init_regex_arr_ext(\@SAFECMDEXCL, $excludesafe); -} - -# Special: treat all cite commands as safe except in UNDERLINE and FONTSTRIKE mode -# (there is a conflict between citation and ulem package, see -# package documentation) -# Use post-processing - -if ( uc($type) ne "UNDERLINE" && uc($type) ne "FONTSTRIKE" && uc($type) ne "CULINECHBAR" ) { - push (@SAFECMDLIST, qr/^cite.*$/); -} else { - ### Experimental: disable text and emph commands - push (@SAFECMDLIST, qr/^cite.*$/) unless $disablecitmark; - push(@SAFECMDEXCL, qr/^emph$/, qr/^text..$/); - # replace \cite{..} by \mbox{\cite{..}} in added or deleted blocks in post-processing - if ( uc($subtype) eq "COLOR" or uc($subtype) eq "DVIPSCOL" ) { - # remove \cite command again from list of safe commands - pop @SAFECMDLIST; - # deleted cite commands - $CITE2CMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite-type commands which should be reinstated in deleted blocks - } else { - $CITECMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite commands which need to be protected within an mbox in UNDERLINE and other modes using ulem - } -} -$CITECMD='(?:cite\w*|nocite)' if $enablecitmark ; # as above for explicit selection - -# setting up @TEXTCMDLIST and @TEXTCMDEXCL -if (defined($replacetext)) { - init_regex_arr_ext(\@TEXTCMDLIST,$replacetext); -} else { - init_regex_arr_data(\@TEXTCMDLIST, "TEXT COMMANDS"); -} -foreach $appendtext ( @appendtextlist ) { - init_regex_arr_ext(\@TEXTCMDLIST, $appendtext); -} -foreach $excludetext ( @excludetextlist ) { - init_regex_arr_ext(\@TEXTCMDEXCL, $excludetext); -} - - -# setting up @CONTEXT1CMDLIST ( @CONTEXT1CMDEXCL exist but is always empty ) -if (defined($replacecontext1)) { - init_regex_arr_ext(\@CONTEXT1CMDLIST,$replacecontext1); -} else { - init_regex_arr_data(\@CONTEXT1CMDLIST, "CONTEXT1 COMMANDS"); -} -foreach $appendcontext1 ( @appendcontext1list ) { - init_regex_arr_ext(\@CONTEXT1CMDLIST, $appendcontext1); -} - - -# setting up @CONTEXT2CMDLIST ( @CONTEXT2CMDEXCL exist but is always empty ) -if (defined($replacecontext2)) { - init_regex_arr_ext(\@CONTEXT2CMDLIST,$replacecontext2); -} else { - init_regex_arr_data(\@CONTEXT2CMDLIST, "CONTEXT2 COMMANDS"); -} -foreach $appendcontext2 ( @appendcontext2list ) { - init_regex_arr_ext(\@CONTEXT2CMDLIST, $appendcontext2); -} - -# setting configuration variables -@config=(); -foreach $config ( @configlist ) { - if (-f $config ) { - open(FILE,$config) or die ("Couldn't open configuration file $config: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@config,$_); - } - close(FILE); - } - else { -# foreach ( split(",",$config) ) { -# push @config,$_; -# } - push @config,split(",",$config) - } -} -foreach $assign ( @config ) { - $assign=~ m/\s*(\w*)\s*=\s*(\S*)\s*$/ or die "Illegal assignment $assign in configuration list (must be variable=value)"; - if ( $1 eq "MINWORDSBLOCK" ) { $MINWORDSBLOCK = $2; } - elsif ( $1 eq "FLOATENV" ) { $FLOATENV = $2 ; } - elsif ( $1 eq "PICTUREENV" ) { $PICTUREENV = $2 ; } - elsif ( $1 eq "MATHENV" ) { $MATHENV = $2 ; } - elsif ( $1 eq "MATHREPL" ) { $MATHREPL = $2 ; } - elsif ( $1 eq "MATHARRENV" ) { $MATHARRENV = $2 ; } - elsif ( $1 eq "MATHARRREPL" ) { $MATHARRREPL = $2 ; } - elsif ( $1 eq "ARRENV" ) { $ARRENV = $2 ; } - elsif ( $1 eq "COUNTERCMD" ) { $COUNTERCMD = $2 ; } - else { die "Unknown variable $1 in assignment.";} -} - -if ( $mathmarkup == COARSE || $mathmarkup == WHOLE ) { - push(@MATHTEXTCMDLIST,qr/^MATHBLOCK(?:$MATHENV|$MATHARRENV|SQUAREBRACKET)$/); -} - - - -foreach $pkg ( @packagelist ) { - map { $packages{$_}="" } split(/,/,$pkg) ; -} - -if ($showpreamble) { - print "\nPreamble commands:\n"; - print $latexdiffpreamble ; -} - -if ($showsafe) { - print "\nCommands safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE (unless excluded):\n"; - print_regex_arr(@SAFECMDLIST); - print "\nCommands not safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE :\n"; - print_regex_arr(@SAFECMDEXCL); -} - -if ($showtext) { - print "\nCommands with last argument textual (unless excluded) and safe in every context:\n"; - print_regex_arr(@TEXTCMDLIST); - print "\nContext1 commands (last argument textual, command will be disabled in deleted passages, last argument will be shown as plain text):\n"; - print_regex_arr(@CONTEXT1CMDLIST); - print "\nContext2 commands (last argument textual, command and its argument will be disabled in deleted passages):\n"; - print_regex_arr(@CONTEXT2CMDLIST); - print "\nExclude list of Commands with last argument not textual (overrides patterns above):\n"; - print_regex_arr(@TEXTCMDEXCL); -} - - -if ($showconfig) { - print "Configuration variables:\n"; - print "MINWORDSBLOCK=$MINWORDSBLOCK\n"; - print "FLOATENV=$FLOATENV\n"; - print "PICTUREENV=$PICTUREENV\n"; - print "MATHENV=$MATHENV\n"; - print "MATHREPL=$MATHREPL\n"; - print "MATHARRENV=$MATHARRENV\n"; - print "MATHARRREPL=$MATHARRREPL\n"; - print "ARRENV=$ARRENV\n"; - print "COUNTERCMD=$COUNTERCMD\n"; -} -if ($showconfig || $showtext || $showsafe || $showpreamble) { - exit 0; } -if ( @ARGV != 2 ) { - print STDERR "2 and only 2 non-option arguments required. Write latexdiff -h to get help\n"; - exit(2); -} - -# Are extra spaces between command arguments permissible? -my $extraspace; -if ($allowspaces) { - $extraspace='\s*'; -} else { - $extraspace=''; -} - -# append context lists to text lists (as text property is implied) -push @TEXTCMDLIST, @CONTEXT1CMDLIST; -push @TEXTCMDLIST, @CONTEXT2CMDLIST; - -push @TEXTCMDLIST, @MATHTEXTCMDLIST if $mathmarkup==COARSE; - -# internal additions to SAFECMDLIST -push(@SAFECMDLIST, qr/^QLEFTBRACE$/, qr/^QRIGHTBRACE$/); - - -# Patterns. These are used by some of the subroutines, too -# I can only define them down here because value of extraspace depends on an option - my $pat0 = '(?:[^{}])*'; - my $pat1 = '(?:[^{}]|\{'.$pat0.'\})*'; - my $pat2 = '(?:[^{}]|\{'.$pat1.'\})*'; - my $pat3 = '(?:[^{}]|\{'.$pat2.'\})*'; - my $pat4 = '(?:[^{}]|\{'.$pat3.'\})*'; - my $pat5 = '(?:[^{}]|\{'.$pat4.'\})*'; - my $pat6 = '(?:[^{}]|\{'.$pat5.'\})*'; - my $brat0 = '(?:[^\[\]]|\\\[|\\\])*'; - - my $quotemarks = '(?:\'\')|(?:\`\`)'; - my $punct='[0.,\/\'\`:;\"\?\(\)\[\]!~\p{IsNonAsciiPunct}\p{IsNonAsciiS}]'; - my $number='-?\d*\.\d*'; - my $mathpunct='[+=<>\-\|]'; - my $and = '&'; - my $coords= '[\-.,\s\d]*'; -# word: sequence of letters or accents followed by letter - my $word='(?:[-\w\d*]|\\\\[\"\'\`~^][A-Za-z\*])+'; - my $cmdleftright='\\\\(?:left|right|[Bb]igg?[lrm]?|middle)\s*(?:[()\[\]|]|\\\\(?:[|{}]|\w+))'; - - my $cmdoptseq='\\\\[\w\d\*]+'.$extraspace.'(?:(?:\['.$brat0.'\]|\{'. $pat6 . '\}|\(' . $coords .'\))'.$extraspace.')*'; - my $backslashnl='\\\\\n'; - my $oneletcmd='\\\\.\*?(?:\['.$brat0.'\]|\{'. $pat6 . '\})*'; - my $math='\$(?:[^$]|\\\$)*?\$|\\\\[(].*?\\\\[)]'; -## the current maths command cannot cope with newline within the math expression - - my $comment='%.*?\n'; - my $pat=qr/(?:\A\s*)?(?:${and}|${quotemarks}|${number}|${word}|$cmdleftright|${cmdoptseq}|${math}|${backslashnl}|${oneletcmd}|${comment}|${punct}|${mathpunct}|\{|\})\s*/ ; - - - -# now we are done setting up and can start working -my ($oldfile, $newfile) = @ARGV; -# check for existence of input files -if ( ! -e $oldfile ) { - die "Input file $oldfile does not exist."; -} -if ( ! -e $newfile ) { - die "Input file $newfile does not exist."; -} - - -# set the labels to be included into the file -my ($oldtime,$newtime,$oldlabel,$newlabel); -if (defined($labels[0])) { - $oldlabel=$labels[0] ; -} else { - $oldtime=localtime((stat($oldfile))[9]); - $oldlabel="$oldfile " . " "x(length($newfile)-length($oldfile)) . $oldtime; -} -if (defined($labels[1])) { - $newlabel=$labels[1] ; -} else { - $newtime=localtime((stat($newfile))[9]); - $newlabel="$newfile " . " "x(length($oldfile)-length($newfile)) . $newtime; -} - -$encoding=guess_encoding($newfile) unless defined($encoding); - -$encoding = "utf8" if $encoding =~ m/^utf8/i ; -if (lc($encoding) eq "utf8" ) { - binmode(STDOUT, ":utf8"); - binmode(STDERR, ":utf8"); -} - -$old=read_file_with_encoding($oldfile,$encoding); -$new=read_file_with_encoding($newfile,$encoding); - - - - -# reset time -exetime(1); -($oldpreamble,$oldbody,$oldpost)=splitdoc($old,'\\\\begin\{document\}','\\\\end\{document\}'); - - -($newpreamble,$newbody,$newpost)=splitdoc($new,'\\\\begin\{document\}','\\\\end\{document\}'); - - -if ($flatten) { - $oldbody=flatten($oldbody,$oldpreamble,$oldfile,$encoding); - $newbody=flatten($newbody,$newpreamble,$newfile,$encoding); -} - -my @auxlines; -if ( length $oldpreamble && length $newpreamble ) { - # pre-process preamble by looking for commands used in \maketitle (title, author, date etc commands) - # and marking up content with latexdiff markup - @auxlines=preprocess_preamble($oldpreamble,$newpreamble); - - @oldpreamble = split /\n/, $oldpreamble; - @newpreamble = split /\n/, $newpreamble; - - # If a command is defined in the preamble of the new file, and only uses safe commands, then it can be considered to be safe) (contribution S. Gouezel) - # Base this assessment on the new preamble - add_safe_commands($newpreamble); - - %packages=list_packages(@newpreamble) unless %packages; - if (defined $packages{"hyperref"} ) { - print STDERR "hyperref package detected.\n" if $verbose ; - $latexdiffpreamble =~ s/\{\\DIFadd\}/{\\DIFaddtex}/g; - $latexdiffpreamble =~ s/\{\\DIFdel\}/{\\DIFdeltex}/g; - $latexdiffpreamble .= join "\n",(extrapream("HYPERREF"),""); - } - print STDERR "Differencing preamble.\n" if $verbose; - - # insert dummy first line such that line count begins with line 1 (rather than perl's line 0) - just so that line numbers inserted by linediff are correct - unshift @newpreamble,''; - unshift @oldpreamble,''; - @diffpreamble = linediff(\@oldpreamble, \@newpreamble); - # remove dummy line again - shift @diffpreamble; - # add filenames, modification time and latexdiff mark - defined($nolabel) or splice @diffpreamble,1,0, - "%DIF LATEXDIFF DIFFERENCE FILE", - ,"%DIF DEL $oldlabel", - "%DIF ADD $newlabel"; - if ( @auxlines ) { - push @diffpreamble,"%DIF DELETED TITLE COMMANDS FOR MARKUP"; - push @diffpreamble,join("\n",@auxlines); - } - push @diffpreamble,$latexdiffpreamble; - push @diffpreamble,'\begin{document}'; -} -elsif ( !length $oldpreamble && !length $newpreamble ) { - @diffpreamble=(); -} else { - print STDERR "Either both texts must have preamble or neither text must have the preamble.\n"; - exit(2); -} - -if (defined $packages{"amsmath"} or defined $packages{"amsart"} or defined $packages{"amsbook"} ) { - print STDERR "amsmath package detected.\n" if $verbose ; - $MATHARRREPL='align*'; -} - -print STDERR "Preprocessing body. " if $verbose; -my ($oldleadin,$newleadin)=preprocess($oldbody,$newbody); - - -# run difference algorithm -@diffbody=bodydiff($oldbody, $newbody); -$diffbo=join("",@diffbody); -if ( $debug ) { - open(RAWDIFF,">","latexdiff.debug.bodydiff"); - print RAWDIFF $diffbo; - close(RAWDIFF); -} -print STDERR "(",exetime()," s)\n","Postprocessing body. \n " if $verbose; -postprocess($diffbo); -$diffall =join("\n",@diffpreamble) ; -# add visible labels -if (defined($visiblelabel)) { - # Give information right after \begin{document} (or at the beginning of the text for files without preamble - ### if \date command is used, add information to \date argument, otherwise give right after \begin{document} - ### $diffall=~s/(\\date$extraspace(?:\[$brat0\])?$extraspace)\{($pat6)\}/$1\{$2 \\ LATEXDIFF comparison \\ Old: $oldlabel \\ New: $newlabel \}/ or - $diffbo = "\\begin{verbatim}LATEXDIFF comparison\nOld: $oldlabel\nNew: $newlabel\\end{verbatim}\n$diffbo" ; -} - -$diffall .= "$newleadin$diffbo" ; -$diffall .= "\\end{document}$newpost" if length $newpreamble ; -if ( lc($encoding) ne "utf8" && lc($encoding) ne "ascii" ) { - print STDERR "Encoding output file to $encoding\n" if $verbose; - $diffall=Encode::encode($encoding,$diffall); - binmode STDOUT; -} -print $diffall; - - -print STDERR "(",exetime()," s)\n","Done.\n" if $verbose; - - - -## guess_encoding(filename) -## reads the first 20 lines of filename and looks for call of inputenc package -## if found, return the option of this package (encoding), otherwise return ascii -sub guess_encoding { - my ($filename)=@_; - my ($i,$enc); - open (FH, $filename) or die("Couldn't open $filename: $!"); - $i=0; - while () { - next if /^\s*%/; # skip comment lines - if (m/\\usepackage\[(\w*?)\]\{inputenc\}/) { - close(FH); - return($1); - } - last if (++$i > 20 ); # scan at most 20 non-comment lines - } - close(FH); - return("ascii"); -} - - -sub read_file_with_encoding { - my ($output); - my ($filename, $encoding) = @_; - - if (lc($encoding) eq "utf8" ) { - open (FILE, "<:utf8",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } elsif ( lc($encoding) eq "ascii") { - open (FILE, $filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } else { - require Encode; - open (FILE, "<",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - print STDERR "Converting $filename from $encoding to utf8\n" if $verbose; - $output=Encode::decode($encoding,$output); - } - close FILE; - if ($^O eq "linux" ) { - $output =~ s/\r\n/\n/g ; - } - return $output; -} - -# %packages=list_packages(@preamble) -# scans the arguments for \documentclass and \usepackage statements and constructs a hash -# whose keys are the included packages, and whose values are the associated optional arguments -sub list_packages { - my (@preamble)=@_; - my %packages=(); - foreach $line ( @preamble ) { - # get rid of comments - $line=~s/(?catfile($dirname,$fname), "\n" if $debug; - # content of file becomes replacement value (use recursion), add \newpage if the command was include - ###$replacement=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - $replacement=flatten(read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding), $preamble,$filename,$encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - # \include always starts a new page; use explicit \newpage command to simulate this - $begline=(defined($1)? $1 : "") ; - $newpage=(defined($3)? " \\newpage " : "") ; - "$begline$newpage$replacement$newpage"; - }/exgm; - - return($text); -} - - -# print_regex_arr(@arr) -# prints regex array without x-ism expansion put in by pearl to stdout -sub print_regex_arr { - my $dumstring; - $dumstring = join(" ",@_); # PERL generates string (?-xism:^ref$) for quoted refex ^ref$ - $dumstring =~ s/\(\?-xism:\^(.*?)\$\)/$1/g; # remove string and ^,$ marks before output - print $dumstring,"\n"; -} - - -# @lines=extrapream($type) -# reads line from appendix (end of file after __END__ token) -sub extrapream { - my $type; - my @retval=("%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - my ($copy); - - while (@_) { - $copy=0; - $type=shift ; - if ( -f $type ) { - open (FILE,$type) or die "Cannot open preamble file $type: $!"; - print STDERR "Reading preamble file $type\n" if $verbose ; - while () { - chomp ; - if ( $_ =~ m/%DIF PREAMBLE/ ) { - push (@retval,"$_"); - } else { - push (@retval,"$_ %DIF PREAMBLE"); - } - } - } - else { # not (-f $type) - $type=uc($type); # upcase argument - print STDERR "Preamble Internal Type $type\n" if $verbose; - while () { - if ( m/^%DIF $type/ ) { - $copy=1; } - elsif ( m/^%DIF END $type/ ) { - last; } - chomp; - push (@retval,"$_ %DIF PREAMBLE") if $copy; - } - if ( $copy == 0 ) { - print STDERR "\nPreamble style $type not implemented.\n"; - print STDERR "Write latexdiff -h to get help with available styles\n"; - exit(2); - } - seek DATA,0,0; # rewind DATA handle to file begin - } - } - push (@retval,"%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - return @retval; -} - - -# ($part1,$part2,$part3)=splitdoc($text,$word1,$word2) -# splits $text into 3 parts at $word1 and $word2. -# if neither $word1 nor $word2 exist, $part1 and $part3 are empty, $part2 is $text -# If only $word1 or $word2 exist but not the other, output an error message. - -# NB this version avoids $` and $' for performance reason although it only makes a tiny difference -# (in one test gain a tenth of a second for a 30s run) -sub splitdoc { - my ($text,$word1,$word2)=@_; - my ($part1,$part2,$part3)=("","",""); - my ($rest,$pos); - - if ( $text =~ m/(^[^%]*)($word1)/mg ) { - $pos=pos $text; - $part1=substr($text,0,$pos-length($2)); - $rest=substr($text,$pos); - if ( $rest =~ m/(^[^%]*)($word2)/mg ) { - $pos=pos $rest; - $part2=substr($rest,0,$pos-length($2)); - $part3=substr($rest,$pos); - } - else { - die "$word1 and $word2 not in the correct order or not present as a pair." ; - } - } else { - $part2=$text; - die "$word2 present but not $word1." if ( $text =~ m/(^[^%]*)$word2/ms ); - } - return ($part1,$part2,$part3); -} - - - - - -# bodydiff($old,$new) -sub bodydiff { - my ($oldwords, $newwords) = @_; - my @retwords; - - print STDERR "(",exetime()," s)\n","Splitting into latex tokens \n" if $verbose; - print STDERR "Parsing $oldfile \n" if $verbose; - my @oldwords = splitlatex($oldwords); - print STDERR "Parsing $newfile \n" if $verbose; - my @newwords = splitlatex($newwords); - - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - print STDERR "(",exetime()," s)\n","Pass 1: Expanding text commands and merging isolated identities with changed blocks " if $verbose; - pass1(\@oldwords, \@newwords); - - - print STDERR "(",exetime()," s)\n","Pass 2: inserting DIF tokens and mark up. " if $verbose; - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold2.tex"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew2.tex"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - @retwords=pass2(\@oldwords, \@newwords); - - return(@retwords); -} - - - - -# @words=splitlatex($string) -# split string according to latex rules -# Each element of words is either -# a word (including trailing spaces and punctuation) -# a latex command -sub splitlatex { - my ($string) = @_ ; - # if input is empty, return empty list - length($string)>0 or return (); - - my @retval=($string =~ m/$pat/osg); - - if (length($string) != length(join("",@retval))) { - print STDERR "\nWARNING: Inconsistency in length of input string and parsed string:\n This often indicates faulty or non-standard latex code.\n In many cases you can ignore this and the following warning messages.\n Note that character numbers in the following are counted beginning after \\begin{document} and are only approximate." unless $ignorewarnings; - print STDERR "DEBUG Original length ",length($string)," Parsed length ",length(join("",@retval)),"\n" if $debug; - print STDERR "DEBUG Input string: |$string|\n" if (length($string)<500) && $debug; - print STDERR "DEBUG Token parsing: |",join("+",@retval),"|\n" if (length($string)<500) && $debug ; - @retval=(); - # slow way only do this if other m//sg method fails - my $last = 0; - while ( $string =~ m/$pat/osg ) { - my $match=$&; - if ($last + length $& != pos $string ) { - my $pos=pos($string); - my $offset=30<$last ? 30 : $last; - my $dum=substr($string,$last-$offset,$pos-$last+2*$offset); - my $dum1=$dum; - my $cnt=$#retval; - my $i; - $dum1 =~ s/\n/ /g; - unless ($ignorewarnings) { - print STDERR "\n$dum1\n"; - print STDERR " " x 30,"^" x ($pos-$last)," " x 30,"\n"; - print STDERR "Missing characters near word " . (scalar @retval) . " character index: " . $last . "-" . pos($string) . " Length: " . length($match) . " Match: |$match| (expected match marked above).\n"; - } - # put in missing characters `by hand' - push (@retval, substr($dum,$offset,$pos-$last-length($match))); -# Note: there seems to be a bug in substr with utf8 that made the following line output substr which were too long, -# using dum instead appears to work -# push (@retval, substr($string,$last, pos($string)-$last-length($match))); - } - push (@retval, $match); - $last=pos $string; - } - - } - return @retval; -} - - -# pass1( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Where an common-subsequence block is flanked by deleted or appended blocks, -# and is shorter than $MINWORDSBLOCK words it is appended -# to the last deleted or appended word. If the block contains tokens other than words -# or punctuation it is not merged. -# Deleted or appended block consisting of words and safe commands only are -# also merged, to prevent break-up in pass2 (after previous isolated words have been removed) -# If there are commands with textual arguments (e.g. \caption) both in corresponding -# appended and deleted blocks split them such that the command and opening bracket -# are one token, then the rest is split up following standard rules, and the closing -# bracket is a separate token, ie. turn -# "\caption{This is a textual argument}" into -# ("\caption{","This ","is ","a ","textual ","argument","}") -# No return value. Destructively changes sequences -sub pass1 { - my $seq1 = shift ; - my $seq2 = shift ; - - my $len1 = scalar @$seq1; - my $len2 = scalar @$seq2; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - - my ($last1,$last2)=(-1,-1) ; - my $cnt=0; - my $block=[]; - my $addblock=[]; - my $delblock=[]; - my $todo=[]; - my $instruction=[]; - my $i; - my (@delmid,@addmid,@dummy); - - my ($addcmds,$delcmds,$matchindex); - my ($addtextblocks,$deltextblocks); - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $adddiscard = sub { - if ($cnt > 0 ) { - $matblkcnt++; - # just after an unchanged block -# print STDERR "Unchanged block $cnt, $last1,$last2 \n"; - if ($cnt < $MINWORDSBLOCK - && $cnt==scalar ( - grep { /^$wpat/ || ( /^\\([\w\d\*]+)((?:\[$brat0\]|\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && scalar(@dummy=split(" ",$2))<3 ) } - @$block) ) { - # merge identical blocks shorter than $MINWORDSBLOCK - # and only containing ordinary words - # with preceding different word - # We cannot carry out this merging immediately as this - # would change the index numbers of seq1 and seq2 and confuse - # the algorithm, instead we store in @$todo where we have to merge - push(@$todo, [ $last1,$last2,$cnt,@$block ]); - } - $block = []; - $cnt=0; $last1=-1; $last2=-1; - } - }; - my $discard=sub { $deltokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$delblock,[ $seq1->[$_[0]],$_[0] ]); - $last1=$_[0] }; - - my $add = sub { $addtokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$addblock,[ $seq2->[$_[1]],$_[1] ]); - $last2=$_[1] }; - - my $match = sub { $mattokcnt++; - if ($cnt==0) { # first word of matching sequence after changed sequence or at beginning of word sequence - $deltextblocks = extracttextblocks($delblock); - $delblkcnt++ if scalar @$delblock; - $addtextblocks = extracttextblocks($addblock); - $addblkcnt++ if scalar @$addblock; - - $delcmds = extractcommands($delblock); - $addcmds = extractcommands($addblock); - # keygen(third argument of _longestCommonSubsequence) implies to sort on command (0th elements of $addcmd elements) - # the calling format for longestCommonSubsequence has changed between versions of - # Algorithm::Diff so we need to check which one we are using - if ( $algodiffversion > 1.15 ) { - ### Algorithm::Diff 1.19 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, 0, sub { $_[0]->[0] } ); - } else { - ### Algorithm::Diff 1.15 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, sub { $_[0]->[0] } ); - } - - for ($i=0 ; $i<=$#$matchindex ; $i++) { - if (defined($matchindex->[$i])){ - $j=$matchindex->[$i]; - @delmid=splitlatex($delcmds->[$i][3]); - @addmid=splitlatex($addcmds->[$j][3]); - while (scalar(@$deltextblocks) && $deltextblocks->[0][0]<$delcmds->[$i][1]) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) }; - push(@$todo, [$index,-1,$cnt,@$block]); - } - push(@$todo, [ $delcmds->[$i][1],-1,-1,$delcmds->[$i][2],@delmid,$delcmds->[$i][4]]); - - while (scalar(@$addtextblocks) && $addtextblocks->[0][0]<$addcmds->[$j][1]) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - push(@$todo, [ -1,$addcmds->[$j][1],-1,$addcmds->[$j][2],@addmid,$addcmds->[$j][4]]); - } - } - # mop up remaining textblocks - while (scalar(@$deltextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) } ; - push(@$todo, [$index,-1,$cnt,@$block]); - } - while (scalar(@$addtextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - - $addblock=[]; - $delblock=[]; - } - push(@$block,$seq2->[$_[1]]); - $cnt++ }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - - - # now carry out the merging/splitting. Refer to elements relative from - # the end (with negative indices) as these offsets don't change before the instruction is executed - # cnt>0: merged small unchanged groups with previous changed blocks - # cnt==-1: split textual commands into components - foreach $instruction ( @$todo) { - ($last1,$last2,$cnt,@$block)=@$instruction ; - if ($cnt>=0) { - splice(@$seq1,$last1-$len1,1+$cnt,join("",$seq1->[$last1-$len1],@$block)) if $last1>=0; - splice(@$seq2,$last2-$len2,1+$cnt,join("",$seq2->[$last2-$len2],@$block)) if $last2>=0; - } else { - splice(@$seq1,$last1-$len1,1,@$block) if $last1>=0; - splice(@$seq2,$last2-$len2,1,@$block) if $last2>=0; - } - } - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens in $matblkcnt blocks.\n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } -} - - -# extracttextblocks(\@blockindex) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [[ $index, $textblock, $cnt ], .. -# where $index index of block to be merged -# $textblock contains all the words to be merged with the word at $index (but does not contain this word) -# $cnt is length of block -# -# requires: iscmd -# -sub extracttextblocks { - my $block=shift; - my ($i,$token,$index); - my $textblock=[]; - my $last=-1; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # store pure text blocks - if ($token =~ /$wpat/ || ( $token =~/^\\([\w\d\*]+)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && !iscmd($1,\@TEXTCMDLIST,\@TEXTCMDEXCL))) { - # we have text or a command which can be treated as text - if ($last<0) { - # new pure-text block - $last=$index; - } else { - # add to pure-text block - push(@$textblock, $token); - } - } else { - # it is not text - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - $textblock=[]; - $last=-1; - } - } - # finish processing a possibly unfinished block before returning - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - return($retval) -} - - - -# extractcommands( \@blockindex ) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [ [ "\cmd1", index, "\cmd1[optarg]{arg1}{", "arg2" ,"} " ],.. -# where index is just taken from input array -# command must have a textual argument as last argument -# -# requires: iscmd -# -sub extractcommands { - my $block=shift; - my ($i,$token,$index,$cmd,$open,$mid,$closing); - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: \cmd - # $3: last argument - # $4: } + trailing spaces - if ( ( $token =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL) ) { - # push(@$retval,[ $2,$index,$1,$3,$4 ]); - ($cmd,$open,$mid,$closing) = ($2,$1,$3,$4) ; - $closing =~ s/\}/\\RIGHTBRACE/ ; - push(@$retval,[ $cmd,$index,$open,$mid,$closing ]); - } - } - return $retval; -} - -# iscmd($cmd,\@regexarray,\@regexexcl) checks -# return 1 if $cmd matches any of the patterns in the -# array $@regexarray, and none of the patterns in \@regexexcl, otherwise return 0 -sub iscmd { - my ($cmd,$regexar,$regexexcl)=@_; - my ($ret)=0; - foreach $pat ( @$regexar ) { - if ( $cmd =~ m/^${pat}$/ ) { - $ret=1 ; - last; - } - } - return 0 unless $ret; - foreach $pat ( @$regexexcl ) { - return 0 if ( $cmd =~ m/^${pat}$/ ); - } - return 1; -} - - -# pass2( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Mark begin and end of deleted and appended sequences with tags $DELOPEN and $DELCLOSE -# and $ADDOPEN and $ADDCLOSE, respectively, however exclude { } & and all comands, unless -# they match an element of the whitelist (SAFECMD) -# For words in TEXTCMD but not in SAFECMD, enclose interior with $ADDOPEN and $ADDCLOSE brackets -# Deleted comment lines are marked with %DIF < -# Added comment lines are marked with %DIF > -sub pass2 { - my $seq1 = shift ; - my $seq2 = shift ; - - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $retval = []; - my $delhunk = []; - my $addhunk = []; - - my $discard = sub { $deltokcnt++; - push ( @$delhunk, $seq1->[$_[0]]) }; - - my $add = sub { $addtokcnt++; - push ( @$addhunk, $seq2->[$_[1]]) }; - - my $match = sub { $mattokcnt++; - if ( scalar @$delhunk ) { - $delblkcnt++; - # mark up changes, but comment out commands - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk); - $delhunk = []; - } - if ( scalar @$addhunk ) { - $addblkcnt++; - # we mark up changes, but simply quote commands - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk); - $addhunk = []; - } - push(@$retval,$seq2->[$_[1]]) }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - # clear up unprocessed hunks - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk) if scalar @$delhunk; - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk) if scalar @$addhunk; - - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens. \n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } - - return(@$retval); -} - -# marktags($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,\@block) -# returns ($openmark,$open,$block,$close,$closemark) if @block only contains no commands (except white-listed ones), -# braces, ampersands, or comments -# mark comments with $comment -# exclude all other exceptions from scope of open, close like this -# ($openmark, $open,...,$close, $opencmd,command, command,$closecmd, $open, ..., $close, $closemark) -# If $opencmd begins with "%" marktags assumes it is operating on a deleted block, otherwise on an added block -sub marktags { - my ($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,$block)=@_; - my $word; - my (@argtext); - my $retval=[]; - my $noncomment=0; - my $cmd=-1; # -1 at beginning 0: last token written is a ordinary word - # 1: last token written is a command - # for keeping track whether we are just in a command sequence or in a word sequence - my $cmdcomment= ($opencmd =~ m/^%/); # Flag to indicate whether opencmd is a comment (i.e. if we intend to simply comment out changed commands) - my ($command,$commandword,$closingbracket) ; # temporary variables needed below to remember sub-pattern matches - -# split this block to flatten out sequences joined in pass1 - @$block=splitlatex(join "",@$block); - foreach (@$block) { - $word=$_; - if ( $word =~ s/^%/%$comment/ ) { - # a comment - if ($cmd==1) { - push (@$retval,$closecmd) ; - $cmd=-1; - } - push (@$retval,$word); - next; - } - if (! $noncomment) { - push (@$retval,$openmark); - $noncomment=1; - } - # negative lookahead pattern (?!) in second clause is put in to avoid mathcing \( .. \) patterns - # also note that second pattern will match \\ - # Note: the second pattern should really be $word =~ /^\\(?!\()(\\|[\w*@]+)/, ie * replaced by + - # and then all commands \" \' etc declared safe. But as I don't have a complete list of one letter - # commands, and nobody has complained so far, I will eave this as is - if ( $word =~ /^[&{}\[\]]/ || ( $word =~ /^\\(?!\()(\\|[\w*@]*)/ && !iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL)) ) { - # word is a command or other significant token (not in SAFECMDLIST) - ## same conditions as in subroutine extractcommand: - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: cmd - # $3: last argument - # $4: } + trailing spaces - ### pre-0.3 if ( ( $token =~ m/^(\\([\w\d\*]+)(?:\[$brat0\]|\{$pat6\})*\{)($pat6)(\}\s*)$/so ) - if ( ( $word =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && (iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL)|| iscmd($2,\@MATHTEXTCMDLIST,\@MATHTEXTCMDEXCL)) - && ( !$cmdcomment || !iscmd($2,\@CONTEXT2CMDLIST, \@CONTEXT2CMDEXCL) ) ) { - # Condition 1: word is a command? - if yes, $1,$2,.. will be set as above - # Condition 2: word is a text command - we mark up the interior of the word. There is a separate check for MATHTEXTCMDLIST - # because for $mathmarkup=WHOLE, the commands should not be split in pass1 (ie. math mode commands are not in - # TEXTCMDLIST, but the interior of MATHTEXT commands should be highlighted in both deleted and added blocks - # Condition 3: But if we are in a deleted block ($cmdcomment=1) and - # $2 (the command) is in context2, just treat it as an ordinary command (i.e. comment it open with $opencmd) - # Because we do not want to disable this command - # here we do not use $opencmd and $closecmd($opencmd is empty) - if ($cmd==1) { - push (@$retval,$closecmd) ; - } elsif ($cmd==0) { - push (@$retval,$close) ; - } - $command=$1; $commandword=$2; $closingbracket=$4; - @argtext=splitlatex($3); # split textual argument into tokens - # and mark it up (but we do not need openmark and closemark) - # insert command with initial arguments, marked-up final argument, and closing bracket - if ( $cmdcomment && iscmd($commandword,\@CONTEXT1CMDLIST, \@CONTEXT1CMDEXCL) ) { - # context1cmd in a deleted environment; delete command itself but keep last argument, marked up - push (@$retval,$opencmd); - $command =~ s/\n/\n${opencmd}/sg ; # repeat opencmd at the beginning of each line - # argument, note that the additional comment character is included - # to suppress linebreak after opening parentheses, which is important - # for latexrevise - push (@$retval,$command,"%\n{$AUXCMD\n",marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } elsif ( iscmd($commandword,,\@MATHTEXTCMDLIST, \@MATHTEXTCMDEXCL) ) { - # MATHBLOCK pseudo command: consider all commands safe, except & and \\ - # Keep these commands even in deleted blocks, hence set $opencmd and $closecmd (5th and 6th argument of marktags) to - # "" - local @SAFECMDLIST=(".*"); - local @SAFECMDEXCL=('\\','\\\\'); - push(@$retval,$command,marktags("","",$open,$close,"","",$comment,\@argtext)#@argtext - ,$closingbracket); - } else { - # normal textcmd or context1cmd in an added block - push (@$retval,$command,marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } - push (@$retval,$AUXCMD,"\n") if $cmdcomment ; - $cmd=-1 ; - } else { - # ordinary command - push (@$retval,$opencmd) if $cmd==-1 ; - push (@$retval,$close,$opencmd) if $cmd==0 ; - $word =~ s/\n/\n${opencmd}/sg if $cmdcomment ; # if opencmd is a comment, repeat this at the beginning of every line - push (@$retval,$word); - $cmd=1; - } - } else { - # just an ordinary word or word in SAFECMD - push (@$retval,$open) if $cmd==-1 ; - push (@$retval,$closecmd,$open) if $cmd==1 ; - push (@$retval,$word); - $cmd=0; - } - } - push (@$retval,$close) if $cmd==0; - push (@$retval,$closecmd) if $cmd==1; - - push (@$retval,$closemark) if ($noncomment); - return @$retval; -} - -# preprocess($string, ..) -# carry out the following pre-processing steps for all arguments: -# 1. Remove leading white-space -# Change \{ to \LEFTBRACE and \} to \RIGHTBRACE -# #. change begin and end commands within comments to BEGINDIF, ENDDIF -# so they don't disturb the pattern matching (if there are several \begin or \end in one line -# 2. mark all first empty line (in block of several) with \PAR tokens -# 3. Convert all '\%' into '\PERCENTAGE ' to make parsing regular expressions easier -# 4. Convert all \verb|some verbatim text| commands (where | can be an arbitrary character) -# into \verb{hash} -# 5. Convert \begin{verbatim} some verbatim text \end{verbatim} into \verbatim{hash} -# 6. Convert _n into \SUBSCRIPTNB{n} and _{nnn} into \SUBSCRIPT{nn} -# 7. Convert ^n into \SUPERSCRIPTNB{n} and ^{nnn} into \SUPERSCRIPT{nn} -# 8. a. Convert $$ $$ into \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} -# b. Convert \[ \] into \begin{SQUAREBRACKET} \end{SQUAREBRACKET} -# 9. Convert all picture environmentent (\begin{PICTUREENV} .. \end{PICTUREENV} \PICTUREBLOCKenv -# For --block-math-markup option -convert all \begin{MATH} .. \end{MATH} -# into \MATHBLOCKmath{...} commands, where MATH/math is any valid math environment - -# 10. Add final token STOP to the very end. This is put in because the algorithm works better if the last token is identical. This is removed again in postprocessing. -# -# NB: step 6 and 7 is likely to convert some "_" inappropriately, e.g. in file -# names or labels but it does not matter because they are converted back in the postprocessing step -# Returns: leading white space removed in step 1 -sub preprocess { - my @leadin=() ; - for (@_) { - s/^(\s*)//s; - push(@leadin,$1); - # Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE - s/(?{$hstr}) && $string ne $hash->{$hstr}) { - warn "Repeated hash value for verbatim mode in spite of different content."; - $hstr="-$hstr"; - } - $hash->{$hstr}=$string; - return($hstr); -} - -#string=fromhash(\%hash,$fromstring) -# restores string value stored in hash -#string=fromhash(\%hash,$fromstring,$prependstring) -# additionally begins each line with prependstring -sub fromhash { - my ($hash,$hstr)=($_[0],$_[1]); - my $retstr=$hash->{$hstr}; - if ( $#_ >= 2) { - $retstr =~ s/^/$_[2]/mg; - } - return $retstr; -} - - -# postprocess($string, ..) -# carry out the following post-processing steps for all arguments: -# * Remove STOP token from the end -# * Replace \RIGHTBRACE by } -# * change citation commands within comments to protect from processing (using marker CITEDIF) -# 1. Check all deleted blocks: -# a.where a deleted block contains a matching \begin and -# \end environment (these will be disabled by a %DIFDELCMD statements), for selected environments enable -# these commands again (such that for example displayed math in a deleted equation -# is properly within math mode. For math mode environments replace numbered equation -# environments with their display only variety (so that equation numbers in new file and -# diff file are identical). Where the correct type of math environment cannot be determined -# use a place holder MATHMODE -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file -# Replace all MATHMODE environment commands by the correct environment to achieve matching -# pairs -# c. Convert MATHBLOCKmath commands to their uncounted numbers (e.g. convert equation -> displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL -# d. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# For added blocks: -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# 2. If --block-math-markup option set: Convert \MATHBLOCKmath{..} commands back to environments -# -# Convert all PICTUREblock{..} commands back to the appropriate environments -# 3. Convert DIFadd, DIFdel, DIFFaddbegin , ... into FL varieties -# within floats (currently recognised float environments: plate,table,figure -# plus starred varieties). -# 4. Remove empty %DIFDELCMD < lines -# 4. Convert \begin{SQUAREBRACKET} \end{SQUAREBRACKET} into \[ \] -# Convert \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} into $$ $$ -# 5. Convert \SUPERSCRIPTNB{n} into ^n and \SUPERSCRIPT{nn} into ^{nnn} -# 6. Convert \SUBSCRIPTNB{n} into _n and \SUBCRIPT{nn} into _{nnn} -# 7. Expand hashes of verb and verbatim environments -# 8. Convert '\PERCENTAGE ' back into '\%' -# 9.. remove all \PAR tokens -# 10. package specific processing: endfloat: make sure \begin{figure} and \end{figure} are always -# on a line by themselves, similarly for table environment -# 4, undo renaming of the \begin and \end in comments -# Change \QLEFTBRACE, \QRIGHTBRACE to \{,\} -# -# Note have to manually synchronize substitution commands below and -# DIF.. command names in the header -sub postprocess { - my ($begin,$len,$cnt,$float,$delblock,$addblock); - # second level blocks - my ($begin2,$cnt2,$len2,$eqarrayblock,$mathblock); - - for (@_) { - - # change $'s in comments to something harmless - 1 while s/(%.*)\$/$1DOLLARDIF/mg ; - - # Remove final STOP token - s/ STOP$//; - # Replace \RIGHTBRACE by } - s/\\RIGHTBRACE/}/g; - - # change citation commands within comments to protect from processing - if ($CITECMD){ - 1 while s/(%.*)\\($CITECMD)/$1\\CITEDIF$2/m ; - } - # Check all deleted blocks: where a deleted block contains a matching \begin and - # \end environment (these will be disabled by a %DIFDELCMD statements), enable - # these commands again (such that for example displayed math in a deleted equation - # is properly within math mode. For math mode environments replace numbered equation - # environments with their display only variety (so that equation numbers in new file and - # diff file are identical - while ( m/\\DIFdelbegin.*?\\DIFdelend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $delblock=$&; - - - ### (.*?[^\n]?)\n? construct is necessary to avoid empty lines in math mode, which result in - ### an error - # displayed math environments - if ($mathmarkup == FINE ) { - $delblock=~ s/(\%DIFDELCMD < \s*\\begin\{((?:$MATHENV)|SQUAREBRACKET)\}.*?(?:$DELCMDCLOSE|\n))(.*?[^\n]?)\n?(\%DIFDELCMD < \s*\\end\{\2\})/\\begin{$MATHREPL}$AUXCMD\n$1$3\n\\end{$MATHREPL}$AUXCMD\n$4/sg; - # also transform the opposite pair \end{displaymath} .. \begin{displaymath} but we have to be careful not to interfere with the results of the transformation in the line directly above - ### pre-0.42 obsolete version which did not work on eqnarray test $delblock=~ s/(? displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL - $delblock=~ s/\\MATHBLOCK($MATHENV)\{($pat6)\}/\\MATHBLOCK$MATHREPL\{$2\}/sg; - $delblock=~ s/\\MATHBLOCK($MATHARRENV)\{($pat6)\}/\\MATHBLOCK$MATHARRREPL\{$2\}/sg; - } - - -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file - $delblock=~ s/\\($COUNTERCMD)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*\s*${AUXCMD}\n)/\\$1$2\\addtocounter{$1}{-1}${AUXCMD}\n/sg ; - - -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es - while ( $delblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($delblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($delblock,$begin2,$len2)=$mathblock; - pos($delblock) = $begin2 + length($mathblock); - } - if ($CITE2CMD) { - $delblock=~s/($DELCMDOPEN\s*\\($CITE2CMD)(.*)$DELCMDCLOSE)/ - # Replacement code - {my ($aux,$all); - $aux=$all=$1; - $aux=~s#\n?($DELCMDOPEN|$DELCMDCLOSE)##g; - $all."$aux$AUXCMD\n";}/sge; - } - # or protect \cite commands with \mbox - if ($CITECMD) { - $delblock=~s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat6\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified delblock - substr($_,$begin,$len)=$delblock; - pos = $begin + length($delblock); - } - # make the array modification in added blocks - while ( m/\\DIFaddbegin.*?\\DIFaddend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $addblock=$&; - while ( $addblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($addblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($addblock,$begin2,$len2)=$mathblock; - pos($addblock) = $begin2 + length($mathblock); - } - if ($CITECMD) { - my $addblockbefore=$addblock; - $addblock=~ s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat2\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified addblock - substr($_,$begin,$len)=$addblock; - pos = $begin + length($addblock); - } - - - ### old place for BEGINDIF, ENDDIF replacement - # change begin and end commands within comments such that they - # don't disturb the pattern matching (if there are several \begin or \end in one line - # this substitution is insufficient but that appears unlikely) - # This needs to be repeated here to also get rid of DIFdelcmd-protected environments - s/(%.*)\\begin\{(.*)$/$1\\BEGINDIF\{$2/mg ; - s/(%.*)\\end\{(.*)$/$1\\ENDDIF\{$2/mg ; - - # Replace MATHMODE environments from step 1a above by the correct Math environment - - # The next line is complicated. The negative look-ahead insertion makes sure that no \end{$MATHENV} (or other mathematical - # environments) are between the \begin{$MATHENV} and \end{MATHMODE} commands. This is necessary as the minimal matching - # is not globally minimal but only 'locally' (matching is beginning from the left side of the string) - if ( $mathmarkup == FINE ) { - 1 while s/\\begin{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}((?:.(?!(?:\\end{(?:(?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}|\\begin{MATHMODE})))*?)\\end{MATHMODE}/\\begin{$1}$2\\end{$1}/s; - 1 while s/\\begin{MATHMODE}((?:.(?!\\end{MATHMODE}))*?)\\end{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}/\\begin{$2}$1\\end{$2}/s; - # convert remaining \begin{MATHMODE} \end{MATHMODE} (and not containing & or \\ )into MATHREPL environments - s/\\begin{MATHMODE}((?:(.(?!(?[1])) { - $optargnew=$newhash{$cmd}->[1]; - } else { - $optargnew=""; - } - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - } else { - $optargold=""; - } - - if ( defined($oldhash{$cmd}) ) { - $argold=$oldhash{$cmd}->[2]; - } else { - $argold=""; - } - $argnew=$newhash{$cmd}->[2]; - $argdiff="{" . join("",bodydiff($argold,$argnew)) ."}"; - if ( length $optargnew ) { - $optargdiff="[".join("",bodydiff($optargold,$optargnew))."]" ; - $optargdiff =~ s/\\DIFaddbegin /\\DIFaddbeginFL /g; - $optargdiff =~ s/\\DIFaddend /\\DIFaddendFL /g; - $optargdiff =~ s/\\DIFadd\{/\\DIFaddFL{/g; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - ### print STDERR "DEBUG s/\\Q$newhash{$cmd}->[0]\\E/\\$cmd$optargdiff$argdiff/s\n"; - # Note: \Q and \E force literal interpretation of what it between them but allow - # variable interpolation, such that e.g. \title matches just that and not TAB-itle - $$newpreambleref=~s/\Q$newhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s; - # replace this in old preamble if necessary - if ( defined($oldhash{$cmd}->[0])) { - $$oldpreambleref=~s/\Q$oldhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s ; - } - ### print STDERR "DEBUG NEW PRE ".$$newpreambleref."\n"; - } - - foreach $cmd ( keys %oldhash ) { - # if this has already been dealt with above can just skip - next if defined($newhash{$cmd}) ; - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - $optargdiff="[".join("",bodydiff($optargold,""))."]" ; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - $argdiff="{" . join("",bodydiff($argold,"")) ."}"; - $auxline = "\\$cmd$optargdiff$argdiff"; - $auxline =~s/$/$AUXCMD/sg; - push @auxlines,$auxline; - } - # add auxcmd comment to highlight added lines - return(@auxlines); -} - - - -# @diffs=linediff(\@seq1, \@seq2) -# mark up lines like this -#%DIF mm-mmdnn -#%< old deleted line(s) -#%DIF ------- -#%DIF mmann-nn -#new appended line %< -#%DIF ------- -# Future extension: mark change explicitly -# Assumes: traverse_sequence traverses deletions before insertions in changed sequences -# all line numbers relative to line 0 (first line of real file) -sub linediff { - my $seq1 = shift ; - my $seq2 = shift ; - - my $block = []; - my $retseq = []; - my @begin=('','',''); # dummy initialisation - my $instring ; - - my $discard = sub { @begin=('d',$_[0],$_[1]) unless scalar @$block ; - push(@$block, "%DIF < " . $seq1->[$_[0]]) }; - my $add = sub { if (! scalar @$block) { - @begin=('a',$_[0],$_[1]) ;} - elsif ( $begin[0] eq 'd' ) { - $begin[0]='c'; $begin[2]=$_[1]; - push(@$block, "%DIF -------") } - push(@$block, $seq2->[$_[1]] . " %DIF > " ) }; - my $match = sub { if ( scalar @$block ) { - if ( $begin[0] eq 'd' && $begin[1]!=$_[0]-1) { - $instring = sprintf "%%DIF %d-%dd%d",$begin[1],$_[0]-1,$begin[2]; } - elsif ( $begin[0] eq 'a' && $begin[2]!=$_[1]-1) { - $instring = sprintf "%%DIF %da%d-%d",$begin[1],$begin[2],$_[1]-1; } - elsif ( $begin[0] eq 'c' ) { - $instring = sprintf "%%DIF %sc%s", - ($begin[1]==$_[0]-1) ? "$begin[1]" : $begin[1]."-".($_[0]-1) , - ($begin[2]==$_[1]-1) ? "$begin[2]" : $begin[2]."-".($_[1]-1) ; } - else { - $instring = sprintf "%%DIF %d%s%d",$begin[1],$begin[0],$begin[2]; } - push @$retseq, $instring,@$block, "%DIF -------" ; - $block = []; - } - push @$retseq, $seq2->[$_[1]] - }; - # key function: remove multiple spaces (such that insertion or deletion of redundant white space is not reported) - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - push @$retseq, @$block if scalar @$block; - - return wantarray ? @$retseq : $retseq ; -} - - - -# init_regex_arr_data(\@array,"TOKEN INIT") -# scans DATA file handel for line "%% TOKEN INIT" line -# then appends each line not beginning with % into array (as a quoted regex) -sub init_regex_arr_data { - my ($arr,$token)=@_; - my ($copy); - while () { - if ( m/^%%BEGIN $token\s*$/ ) { - $copy=1; } - elsif ( m/^%%END $token\s*/ ) { - last; } - chomp; - push (@$arr,qr/^$_$/) if ( $copy && !/^%/ ) ; - } - seek DATA,0,0; # rewind DATA handle to file begin -} - - -# init_regex_arr_ext(\@array,$arg) -# fills array with regular expressions. -# if arg is a file name, then read in list of regular expressions from that file -# (one expression per line) -# Otherwise treat arg as a comma separated list of regular expressions -sub init_regex_arr_ext { - my ($arr,$arg)=@_; - my $regex; - if ( -f $ arg ) { - open(FILE,"$arg") or die ("Couldn't open $arg: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@$arr,qr/^$_$/); - } - close(FILE); - } - else { - # assume it is a comma-separated list of reg-ex - foreach $regex (split(qr/(?=1) { - $reset=shift; - } - if ($reset) { - $lasttime=times(); - } - else { - $retval=times()-$lasttime; - $lasttime=$lasttime+$retval; - return($retval); - } -} - - -sub usage { - die <<"EOF"; -Usage: $0 [options] old.tex new.tex > diff.tex - -Compares two latex files and writes tex code to stdout, which has the same -format as new.tex but has all changes relative to old.tex marked up or commented. - ---type=markupstyle --t markupstyle Add code to preamble for selected markup style - Available styles: UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE - CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR - [ Default: UNDERLINE ] - ---subtype=markstyle --s markstyle Add code to preamble for selected style for bracketing - commands (e.g. to mark changes in margin) - Available styles: SAFE MARGINAL DVIPSCOL COLOR - [ Default: SAFE ] - ---floattype=markstyle --f markstyle Add code to preamble for selected style which - replace standard marking and markup commands within floats - (e.g., marginal remarks cause an error within floats - so marginal marking can be disabled thus) - Available styles: FLOATSAFE IDENTICAL - [ Default: FLOATSAFE ] - ---encoding=enc --e enc Specify encoding of old.tex and new.tex. Typical encodings are - ascii, utf8, latin1, latin9. A list of available encodings can be - obtained by executing - perl -MEncode -e 'print join ("\\n",Encode->encodings( ":all" )) ;' - [Default encoding is utf8 unless the first few lines of the preamble contain - an invocation "\\usepackage[..]{inputenc} in which case the - encoding chosen by this command is asssumed. Note that ASCII (standard - latex) is a subset of utf8] - ---preamble=file --p file Insert file at end of preamble instead of auto-generating - preamble. The preamble must define the following commands - \\DIFaddbegin,\\DIFaddend,\\DIFadd{..}, - \\DIFdelbegin,\\DIFdelend,\\DIFdel{..}, - and varieties for use within floats - \\DIFaddbeginFL,\\DIFaddendFL,\\DIFaddFL{..}, - \\DIFdelbeginFL,\\DIFdelendFL,\\DIFdelFL{..} - (If this option is set -t, -s, and -f options - are ignored.) - ---exclude-safecmd=exclude-file ---exclude-safecmd="cmd1,cmd2,..." --A exclude-file ---replace-safecmd=replace-file ---append-safecmd=append-file ---append-safecmd="cmd1,cmd2,..." --a append-file Exclude from, replace or append to the list of regex - matching commands which are safe to use within the - scope of a \\DIFadd or \\DIFdel command. The file must contain - one Perl-RegEx per line (Comment lines beginning with # or % are - ignored). A literal comma within the comma-separated list must be - escaped thus "\\,", Note that the RegEx needs to match the whole of - the token, i.e., /^regex\$/ is implied and that the initial - "\\" of the command is not included. The --exclude-safecmd - and --append-safecmd options can be combined with the --replace-safecmd - option and can be used repeatedly to add cumulatively to the lists. - ---exclude-textcmd=exclude-file ---exclude-textcmd="cmd1,cmd2,..." --X exclude-file ---replace-textcmd=replace-file ---append-textcmd=append-file ---append-textcmd="cmd1,cmd2,..." --x append-file Exclude from, replace or append to the list of regex - matching commands whose last argument is text. See - entry for --exclude-safecmd directly above for further details. - ---replace-context1cmd=replace-file ---append-context1cmd=append-file ---append-context1cmd="cmd1,cmd2,..." - Replace or append to the list of regex matching commands - whose last argument is text but which require a particular - context to work, e.g. \\caption will only work within a figure - or table. These commands behave like text commands, except when - they occur in a deleted section, when they are disabled, but their - argument is shown as deleted text. - ---replace-context2cmd=replace-file ---append-context2cmd=append-file ---append-context2cmd="cmd1,cmd2,..." - As corresponding commands for context1. The only difference is that - context2 commands are completely disabled in deleted sections, including - their arguments. - - ---config var1=val1,var2=val2,... --c var1=val1,.. Set configuration variables. --c configfile Available variables: - MINWORDSBLOCK (integer) - FLOATENV (RegEx) - PICTUREENV (RegEx) - MATHENV (RegEx) - MATHREPL (String) - MATHARRENV (RegEx) - MATHARRREPL (String) - ARRENV (RegEx) - COUNTERCMD (RegEx) - This option can be repeated. - - ---packages=pkg1,pkg2,.. - Tell latexdiff that .tex file is processed with the packages in list - loaded. This is normally not necessary if the .tex file includes the - preamble, as the preamble is automatically scanned for \\usepackage commands. - Use of the --packages option disables automatic scanning, so if for any - reason package specific parsing needs to be switched off, use --packages=none. - The following packages trigger special behaviour: - endfloat hyperref amsmath - [ Default: scan the preamble for \\usepackage commands to determine - loaded packages.] - ---show-preamble Print generated or included preamble commands to stdout. - ---show-safecmd Print list of regex matching and excluding safe commands. - ---show-textcmd Print list of regex matching and excluding commands with text argument. - ---show-config Show values of configuration variables - ---show-all Show all of the above - - NB For all --show commands, no old.tex or new.tex file needs to be given, and no - differencing takes place. - -Other configuration options: - ---allow-spaces Allow spaces between bracketed or braced arguments to commands - [Default requires arguments to directly follow each other without - intervening spaces] - ---math-markup=level Determine granularity of markup in displayed math environments: - Possible values for level are (both numerical and text labels are acceptable): - off or 0: suppress markup for math environments. Deleted equations will not - appear in diff file. This mode can be used if all the other modes - cause invalid latex code. - whole or 1: Differencing on the level of whole equations. Even trivial changes - to equations cause the whole equation to be marked changed. This - mode can be used if processing in coarse or fine mode results in - invalid latex code. - coarse or 2: Detect changes within equations marked up with a coarse - granularity; changes in equation type (e.g.displaymath to equation) - appear as a change to the complete equation. This mode is recommended - for situations where the content and order of some equations are still - being changed. [Default] - fine or 3: Detect small change in equations and mark up and fine granularity. - This mode is most suitable, if only minor changes to equations are - expected, e.g. correction of typos. - ---disable-citation-markup Suppress citation markup in styles using ulem (UNDERLINE, - FONTSTRIKE, CULINECHBAR) ---enable-citation-markup Protect citation commands in changed sections with \\mbox command - [i.e. use default behaviour for ulem package for other packages] - -Miscelleneous options - ---label=label --L label Sets the labels used to describe the old and new files. The first use - of this option sets the label describing the old file and the second - use of the option sets the label for the new file. - [Default: use the filename and modification dates for the label] - ---no-label Suppress inclusion of old and new file names as comment in output file - ---visble-label Include old and new filenames (or labels set with --label option) as - visible output - ---flatten Replace \\input and \\include commands within body by the content - of the files in their argument. If \\includeonly is present in the - preamble, only those files are expanded into the document. However, - no recursion is done, i.e. \\input and \\include commands within - included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, - respectively, making it possible to organise files into old and new directories. - --flatten is applied recursively, so inputted files can contain further - \\input statements. - ---help --h Show this help text. - ---ignore-warnings Suppress warnings about inconsistencies in length between input - and parsed strings and missing characters. - ---verbose --V Output various status information to stderr during processing. - Default is to work silently. - ---version Show version number. - -For further information, consult http://latexdiff.berlios.de -EOF -} - -=head1 NAME - -latexdiff - determine and markup differences between two latex files - -=head1 SYNOPSIS - -B [ B ] F F > F - -=head1 DESCRIPTION - -Briefly, I is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called C and C, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. - -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "S>>" is appended to each added line, i.e. a -line present in C but not in C. Discarded lines - are deactivated by prepending "S>>". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file C will be similar to -C. At the end of the preamble, the definitions for I markup commands are inserted. -In differencing the main body of the text, I attempts to -satisfy the following guidelines (in order of priority): - -=over 3 - -=item 1 - -If both C and C are valid LaTeX, then the resulting -C should also be valid LateX. (NB If a few plain TeX commands -are used within C or C then C is not -guaranteed to work but usually will). - -=item 2 - -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -C. - -=item 3 - -If a changed passage contains text or text-producing commands, then -running C through LateX should produce output where added -and discarded passages are highlighted. - -=item 4 - -Where there are insignificant differences, e.g. in the positioning of -line breaks, C should follow the formatting of C - -=back - -For differencing the same algorithm as I is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, C<\caption> and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write - - \section{\textem{This is an emphasized section title}} - -and not - - \section {\textem{This is an emphasized section title}} - -or - - \section\textem{This is an emphasized section title} - -even though all varieties are the same to LaTeX (but see -B<--allow-spaces> option which allows the second variety). - -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the PICTUREENV configuration variable, set by -default to C and C environments; see B<--config> -option). The latter environment (C) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by C<\begin{DIFnomarkup}> and C<\end{DIFnomarkup}>. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, - -C<\newenvironment{DIFnomarkup}{}{}> - -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. - -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. - -All markup commands inserted by I begin with "C<\DIF>". Added -blocks containing words, commands or comments which are in C -but not in C are marked by C<\DIFaddbegin> and C<\DIFaddend>. -Discarded blocks are marked by C<\DIFdelbegin> and C<\DIFdelend>. -Within added blocks all text is highlighted with C<\DIFadd> like this: -C<\DIFadd{Added text block}> -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces "{" and "}" are never put within -the scope of C<\DIFadd>. Added comments are marked by prepending -"S >>". - -Within deleted blocks text is highlighted with C<\DIFdel>. Deleted -comments are marked by prepending "S >>". Non-safe command -and curly braces within deleted blocks are commented out with -"S >>". - - - -=head1 OPTIONS - -=head2 Preamble - -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. - -=over 4 - -=item B<--type=markupstyle> or -B<-t markupstyle> - -Add code to preamble for selected markup style. This option defines -C<\DIFadd> and C<\DIFdel> commands. -Available styles: - -C - -[ Default: C ] - -=item B<--subtype=markstyle> or -B<-s markstyle> - -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -C<\DIFaddbegin>, C<\DIFaddend>, C<\DIFdelbegin> and C<\DIFdelend> commands. -Available styles: C - -[ Default: C ] - -=item B<--floattype=markstyle> or -B<-f markstyle> - -Add code to preamble for selected style which -replace standard marking and markup commands within floats -(e.g., marginal remarks cause an error within floats -so marginal marking can be disabled thus). This option defines all -C<\DIF...FL> commands. -Available styles: C - -[ Default: C ] - -=item B<--encoding=enc> or -B<-e enc> - -Specify encoding of old.tex and new.tex. Typical encodings are -C, C, C, C. A list of available encodings can be -obtained by executing - -Cencodings( ":all" )) ;' > - -[Default encoding is utf8 unless the first few lines of the preamble contain -an invocation C<\usepackage[..]{inputenc}> in which case the -encoding chosen by this command is asssumed. Note that ASCII (standard -latex) is a subset of utf8] - -=item B<--preamble=file> or -B<-p file> - -Insert file at end of preamble instead of generating -preamble. The preamble must define the following commands -C<\DIFaddbegin, \DIFaddend, \DIFadd{..}, -\DIFdelbegin,\DIFdelend,\DIFdel{..},> -and varieties for use within floats -C<\DIFaddbeginFL, \DIFaddendFL, \DIFaddFL{..}, -\DIFdelbeginFL, \DIFdelendFL, \DIFdelFL{..}> -(If this option is set B<-t>, B<-s>, and B<-f> options -are ignored.) - -=item B<--packages=pkg1,pkg2,..> - -Tell latexdiff that .tex file is processed with the packages in list -loaded. This is normally not necessary if the .tex file includes the -preamble, as the preamble is automatically scanned for C<\usepackage> commands. -Use of the B<--packages> option disables automatic scanning, so if for any -reason package specific parsing needs to be switched off, use B<--packages=none>. -The following packages trigger special behaviour: - -=over 8 - -=item C - -Configuration variable amsmath is set to C (Default: C) - -=item C - -Ensure that C<\begin{figure}> and C<\end{figure}> always appear by themselves on a line. - -=item C - -Change name of C<\DIFadd> and C<\DIFdel> commands to C<\DIFaddtex> and C<\DIFdeltex> and -define new C<\DIFadd> and C<\DIFdel> commands, which provide a wrapper for these commands, -using them for the text but not for the link defining command (where any markup would cause -errors). - -=back - -[ Default: scan the preamble for C<\\usepackage> commands to determine - loaded packages.] - - - -=item B<--show-preamble> - -Print generated or included preamble commands to stdout. - -=back - -=head2 Configuration - -=over 4 - -=item B<--exclude-safecmd=exclude-file> or -B<-A exclude-file> or B<--exclude-safecmd="cmd1,cmd2,..."> - -=item B<--replace-safecmd=replace-file> - -=item B<--append-safecmd=append-file> or -B<-a append-file> or B<--append-safecmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions (RegEx) -matching commands which are safe to use within the -scope of a C<\DIFadd> or C<\DIFdel> command. The file must contain -one Perl-RegEx per line (Comment lines beginning with # or % are -ignored). Note that the RegEx needs to match the whole of -the token, i.e., /^regex$/ is implied and that the initial -"\" of the command is not included. -The B<--exclude-safecmd> and B<--append-safecmd> options can be combined with the -B<--replace-safecmd> -option and can be used repeatedly to add cumulatively to the lists. - B<--exclude-safecmd> -and B<--append-safecmd> can also take a comma separated list as input. If a -comma for one of the regex is required, escape it thus "\,". In most cases it -will be necessary to protect the comma-separated list from the shell by putting -it in quotation marks. - -=item B<--exclude-textcmd=exclude-file> or -B<-X exclude-file> or B<--exclude-textcmd="cmd1,cmd2,..."> - -=item B<--replace-textcmd=replace-file> - -=item B<--append-textcmd=append-file> or -B<-x append-file> or B<--append-textcmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions -matching commands whose last argument is text. See -entry for B<--exclude-safecmd> directly above for further details. - - -=item B<--replace-context1cmd=replace-file> - -=item B<--append-context1cmd=append-file> or -=item B<--append-context1cmd="cmd1,cmd2,..."> - -Replace or append to the list of regex matching commands -whose last argument is text but which require a particular -context to work, e.g. \caption will only work within a figure -or table. These commands behave like text commands, except when -they occur in a deleted section, when they are disabled, but their -argument is shown as deleted text. - -=item B<--replace-context2cmd=replace-file> - -=item B<--append-context2cmd=append-file> or -=item B<--append-context2cmd="cmd1,cmd2,..."> -As corresponding commands for context1. The only difference is that -context2 commands are completely disabled in deleted sections, including -their arguments. - - - -=item B<--config var1=val1,var2=val2,...> or B<-c var1=val1,..> - -=item B<-c configfile> - -Set configuration variables. The option can be repeated to set different -variables (as an alternative to the comma-separated list). -Available variables (see below for further explanations): - -C (integer) - -C (RegEx) - -C (RegEx) - -C (RegEx) - -C (String) - -C (RegEx) - -C (String) - -C (RegEx) - -C (RegEx) - -=item B<--show-safecmd> - -Print list of RegEx matching and excluding safe commands. - -=item B<--show-textcmd> - -Print list of RegEx matching and excluding commands with text argument. - -=item B<--show-config> - -Show values of configuration variables. - -=item B<--show-all> - -Combine all --show commands. - -NB For all --show commands, no C or C file needs to be specified, and no -differencing takes place. - -=back - -=head2 Other configuration options: - -=over 4 - -=item B<--allow-spaces> - -Allow spaces between bracketed or braced arguments to commands. Note -that this option might have undesirable side effects (unrelated scope -might get lumpeded with preceding commands) so should only be used if the -default produces erroneous results. (Default requires arguments to -directly follow each other without intervening spaces). - -=item B<--math-markup=level> - -Determine granularity of markup in displayed math environments: -Possible values for level are (both numerical and text labels are acceptable): - -C or C<0>: suppress markup for math environments. Deleted equations will not -appear in diff file. This mode can be used if all the other modes -cause invalid latex code. - -C or C<1>: Differencing on the level of whole equations. Even trivial changes -to equations cause the whole equation to be marked changed. This -mode can be used if processing in coarse or fine mode results in -invalid latex code. - -C or C<2>: Detect changes within equations marked up with a coarse -granularity; changes in equation type (e.g.displaymath to equation) -appear as a change to the complete equation. This mode is recommended -for situations where the content and order of some equations are still -being changed. [Default] - -C or C<3>: Detect small change in equations and mark up at fine granularity. -This mode is most suitable, if only minor changes to equations are -expected, e.g. correction of typos. - -=item B<--disable-citation-markup> - -Suppress citation markup in styles using ulem (UNDERLINE, -FONTSTRIKE, CULINECHBAR) - -=item B<--enable-citation-markup> - -Protect citation commands in changed sections with \\mbox command [i.e. use default behaviour for ulem package for other packages] - -=back - -=head2 Miscellaneous - -=over 4 -=item B<--verbose> or B<-V> - -Output various status information to stderr during processing. -Default is to work silently. - -=item B<--driver=type> - -Choose driver for changebar package (only relevant for styles using - changebar: CCHANGEBAR CFONTCHBAR CULINECHBAR CHANGEBAR). Possible -drivers are listed in changebar manual, e.g. pdftex,dvips,dvitops - [Default: dvips] - -=item B<--ignore-warnings> - -Suppress warnings about inconsistencies in length between input and -parsed strings and missing characters. These warning messages are -often related to non-standard latex or latex constructions with a -syntax unknown to C but the resulting difference argument -is often fully functional anyway, particularly if the non-standard -latex only occurs in parts of the text which have not changed. - -=item B<--label=label> or -B<-L label> - -Sets the labels used to describe the old and new files. The first use -of this option sets the label describing the old file and the second -use of the option sets the label for the new file, i.e. set both -labels like this C<-L labelold -L labelnew>. -[Default: use the filename and modification dates for the label] - -=item B<--no-label> - -Suppress inclusion of old and new file names as comment in output file - -=item B<--visble-label> - -Include old and new filenames (or labels set with --label option) as -visible output. - -=item B<--flatten> - -Replace C<\input> and C<\include> commands within body by the content -of the files in their argument. If C<\includeonly> is present in the -preamble, only those files are expanded into the document. However, -no recursion is done, i.e. C<\input> and C<\include> commands within -included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, -respectively, making it possible to organise files into old and new directories. ---flatten is applied recursively, so inputted files can contain further -C<\input> statements. - -Use of this option might result in prohibitive processing times for -larger documents, and the resulting difference document -no longer reflects the structure of the input documents. - -=item B<--help> or -B<-h> - -Show help text - -=item B<--version> - -Show version number - -=back - - - -=head2 Predefined styles - -=head2 Major types - -The major type determine the markup of plain text and some selected latex commands outside floats by defining the markup commands C<\DIFadd{...}> and C<\DIFdel{...}> . - -=over 10 - -=item C - -Added text is wavy-underlined and blue, discarded text is struck out and red -(Requires color and ulem packages). Overstriking does not work in displayed math equations such that deleted parts of equation are underlined, not struck out (this is a shortcoming inherent to the ulem package). - -=item C - -Added text is blue and set in sans-serif, and a red footnote is created for each discarded -piece of text. (Requires color package) - -=item C - -Like C but without the use of color. - -=item C - -Added text is blue and set in sans-serif, and discarded text is red and very small size. - -=item C - -Added tex is set in sans-serif, discarded text small and struck out - -=item C - -Added text is blue, and discarded text is red. Additionally, the changed text is marked with a bar in the margin (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color, ulem and changebar packages). - -=item C - -No mark up of text, but mark margins with changebars (Requires changebar package). - -=item C - -No visible markup (but generic markup commands will still be inserted. - -=back - -=head2 Subtypes - -The subtype defines the commands that are inserted at the begin and end of added or discarded blocks, irrespectively of whether these blocks contain text or commands (Defined commands: C<\DIFaddbegin, \DIFaddend, \DIFdelbegin, \DIFdelend>) - -=over 10 - -=item C - -No additional markup (Recommended choice) - -=item C - -Mark beginning and end of changed blocks with symbols in the margin nearby (using -the standard C<\marginpar> command - note that this sometimes moves somewhat -from the intended position. - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. -(It is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete, for example -with citation commands). - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. Note -that C only works with the dvips converter, e.g. not pdflatex. -(it is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete). - -=back - -=head2 Float Types - -Some of the markup used in the main text might cause problems when used within -floats (e.g. figures or tables). For this reason alternative versions of all -markup commands are used within floats. The float type defines these alternative commands. - -=over 10 - -=item C - -Use identical markup for text as in the main body, but set all commands marking the begin and end of changed blocks to null-commands. You have to choose this float type if your subtype is C as C<\marginpar> does not work properly within floats. - -=item C - -Mark additions the same way as in the main text. Deleted environments are marked by angular brackets \[ and \] and the deleted text is set in scriptscript size. This float type should always be used with the C and C markup types as the \footnote command does not work properly in floating environments. - -=item C - -Make no difference between the main text and floats. - -=back - - -=head2 Configuration Variables - -=over 10 - -=item C - -Minimum number of tokens required to form an independent block. This value is -used in the algorithm to detect changes of complete blocks by merging identical text parts of less than C to the preceding added and discarded parts. - -[ Default: 3 ] - -=item C - -Environments whose name matches the regular expression in C are -considered floats. Within these environments, the I markup commands -are replaced by their FL variaties. - -[ Default: S >] - -=item C - -Within environments whose name matches the regular expression in C -all latexdiff markup is removed (in pathologic cases this might lead to - inconsistent markup but this situation should be rare). - -[ Default: S >] - -=item C,C - -If both \begin and \end for a math environment (environment name matching C -or \[ and \]) -are within the same deleted block, they are replaced by a \begin and \end commands for C -rather than being commented out. - -[ Default: C=S >, C=S >] - -=item C,C - -as C,C but for equation arrays - -[ Default: C=S >, C=S >] - -=item C - -If a match to C is found within an inline math environment within a deleted or added block, then the inlined math -is surrounded by C<\mbox{>...C<}>. This is necessary as underlining does not work within inlined array environments. - -[ Default: C=S > - -=item C - -If a command in a deleted block which is also in the textcmd list matches C then an -additional command C<\addtocounter{>FC<}{-1}>, where F is the matching command, is appended in the diff file such that the numbering in the diff file remains synchronized with the -numbering in the new file. - -[ Default: C=C<(?:footnote|part|section|subsection> ... - -C<|subsubsection|paragraph|subparagraph)> ] - -=back - -=head1 COMMON PROBLEMS - -=over 10 - -=item Citations result in overfull boxes - -There is an incompatibility between the C package, which C uses for underlining and striking out in the UNDERLINE style, -the default style. In order to be able to mark up citations properly, they are placed with an C<\mbox> command in post-processing. As mboxes -cannot be broken across lines, this procedure frequently results in overfull boxes, possibly obscuring the content as it extends beyond the right margin. If this is a problem, you have two possibilities: - -1. Use C or C subtype markup (option C<-s COLOR>): If this markup is chosen, then changed citations are no longer marked up -with the wavy line (additions) or struck out (deletions), but are still highlighted in the appropriate color. - -2. Choose option C<--disable-citation-markup> which turns off the marking up of citations: deleted citations are no longer shown, and -added ctations are shown without markup. (This was the default behaviour of latexdiff at versions 0.6 and older) - -=item Changes in complicated mathematical equations result in latex processing errors - -Try options C<--math-markup=whole>. If even that fails, you can turn off mark up for equations with C<--math-markup=off>. - -=back - -=head1 BUGS - -Option allow-spaces not implemented entirely consistently. It breaks -the rules that number and type of white space does not matter, as -different numbers of inter-argument spaces are treated as significant. - -Please submit bug reports on the latexdiff project page I, -send them to user discussion list C (prior subscription -to list required, also on project webpage) -or send them to I. Include the serial number of I -(from comments at the top of the source or use B<--version>). If you come across latex -files that are error-free and conform to the specifications set out -above, and whose differencing still does not result in error-free -latex, please send me those files, ideally edited to only contain the -offending passage as long as that still reproduces the problem. If your -file relies on non-standard class files, you must include those. I will not -look at examples where I have trouble to latex the original files. - -=head1 SEE ALSO - -L, L - -=head1 PORTABILITY - -I does not make use of external commands and thus should run -on any platform supporting Perl 5.6 or higher. If files with encodings -other than ASCII or UTF-8 are processed, Perl 5.8 or higher is required. - -The standard version of I requires installation of the Perl package -C (available from I - -I) but a stand-alone -version, I, which has this package inlined, is available, too. -I requires the I command to be present. - -=head1 AUTHOR - -Version 1.0.2 -Copyright (C) 2004-2012 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 - -Contributors of fixes and additions: V. Kuhlmann, J. Paisley, N. Becker, T. Doerges, K. Huebner, -T. Connors, Sebastian Gouezel and many others. -Thanks to the many people who send in bug reports, feature suggestions, and other feedback. - -=cut - -__END__ -%%BEGIN SAFE COMMANDS -% Regex matching commands which can safely be in the -% argument of a \DIFadd or \DIFdel command (leave out the \) -arabic -dashbox -emph -fbox -framebox -hspace -math.* -makebox -mbox -pageref -ref -symbol -raisebox -rule -text.* -shortstack -usebox -dag -ddag -copyright -pounds -S -P -oe -OE -ae -AE -aa -AA -o -O -l -L -frac -ss -sqrt -ldots -cdots -vdots -ddots -alpha -beta -gamma -delta -epsilon -varepsilon -zeta -eta -theta -vartheta -iota -kappa -lambda -mu -nu -xi -pi -varpi -rho -varrho -sigma -varsigma -tau -upsilon -phi -varphi -chi -psi -omega -Gamma -Delta -Theta -Lambda -Xi -Pi -Sigma -Upsilon -Phi -Psi -Omega -ps -mp -times -div -ast -star -circ -bullet -cdot -cap -cup -uplus -sqcap -vee -wedge -setminus -wr -diamond -(?:big)?triangle.* -lhd -rhd -unlhd -unrhd -oplus -ominus -otimes -oslash -odot -bigcirc -d?dagger -amalg -leq -prec -preceq -ll -(?:sq)?su[bp]set(?:eq)? -in -vdash -geq -succ(?:eq)? -gg -ni -dashv -equiv -sim(?:eq)? -asymp -approx -cong -neq -doteq -propto -models -perp -mid -parallel -bowtie -Join -smile -frown -.*arrow -(?:long)?mapsto -.*harpoon.* -leadsto -aleph -hbar -imath -jmath -ell -wp -Re -Im -mho -prime -emptyset -nabla -surd -top -bot -angle -forall -exists -neg -flat -natural -sharp -backslash -partial -infty -Box -Diamond -triangle -clubsuit -diamondsuit -heartsuit -spadesuit -sum -prod -coprod -int -oint -big(?:sq)?c[au]p -bigvee -bigwedge -bigodot -bigotimes -bigoplus -biguplus -(?:arc)?(?:cos|sin|tan|cot)h? -csc -arg -deg -det -dim -exp -gcd -hom -inf -ker -lg -lim -liminf -limsup -ln -log -max -min -Pr -sec -sup -(SUPER|SUB)SCRIPTNB -(SUPER|SUB)SCRIPT -%%END SAFE COMMANDS - -%%BEGIN TEXT COMMANDS -% Regex matching commands with a text argument (leave out the \) -addcontents.* -cc -closing -chapter -dashbox -emph -encl -fbox -framebox -footnote -footnotetext -framebox -part -(sub){0,2}section\*? -(sub)?paragraph\*? -makebox -mbox -opening -parbox -raisebox -savebox -sbox -shortstack -signature -text.* -value -underline -sqrt -(SUPER|SUB)SCRIPT -%%END TEXT COMMANDS - -%%BEGIN CONTEXT1 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -caption -%%END CONTEXT1 COMMANDS - -%%BEGIN CONTEXT2 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -title -author -date -institute -%%END CONTEXT2 COMMANDS - - -%% TYPES (Commands for highlighting changed blocks) - -%DIF UNDERLINE PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}} -\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}} -%DIF END UNDERLINE PREAMBLE - -%DIF CTRADITIONAL PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} [..\footnote{removed: #1} ]}} -%DIF END CTRADITIONAL PREAMBLE - -%DIF TRADITIONAL PREAMBLE -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{[..\footnote{removed: #1} ]}} -%DIF END TRADITIONAL PREAMBLE - -%DIF CFONT PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} \scriptsize #1}} -%DIF END CFONT PREAMBLE - -%DIF FONTSTRIKE PREAMBLE -\RequirePackage[normalem]{ulem} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{\footnotesize \sout{#1}}} -%DIF END FONTSTRIKE PREAMBLE - -%DIF CCHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}#1}\protect\cbdelete} -%DIF END CCHANGEBAR PREAMBLE - -%DIF CFONTCHBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\sf #1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\scriptsize #1}\protect\cbdelete} -%DIF END CFONTCHBAR PREAMBLE - -%DIF CULINECHBAR PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage[dvips]{changebar} -\RequirePackage{color} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\uwave{#1}}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\sout{#1}}\protect\cbdelete} -%DIF END CULINECHBAR PREAMBLE - -%DIF CHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\providecommand{\DIFadd}[1]{\protect\cbstart{#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete} -%DIF END CHANGEBAR PREAMBLE - -%DIF INVISIBLE PREAMBLE -\providecommand{\DIFadd}[1]{#1} -\providecommand{\DIFdel}[1]{} -%DIF END INVISIBLE PREAMBLE - - -%% SUBTYPES (Markers for beginning and end of changed blocks) - -%DIF SAFE PREAMBLE -\providecommand{\DIFaddbegin}{} -\providecommand{\DIFaddend}{} -\providecommand{\DIFdelbegin}{} -\providecommand{\DIFdelend}{} -%DIF END SAFE PREAMBLE - -%DIF MARGIN PREAMBLE -\providecommand{\DIFaddbegin}{\protect\marginpar{a[}} -\providecommand{\DIFaddend}{\protect\marginpar{]}} -\providecommand{\DIFdelbegin}{\protect\marginpar{d[}} -\providecommand{\DIFdelend}{\protect\marginpar{]}} -%DIF END BRACKET PREAMBLE - -%DIF DVIPSCOL PREAMBLE -%Note: only works with dvips converter -\RequirePackage{color} -\RequirePackage{dvipscol} -\providecommand{\DIFaddbegin}{\protect\nogroupcolor{blue}} -\providecommand{\DIFaddend}{\protect\nogroupcolor{black}} -\providecommand{\DIFdelbegin}{\protect\nogroupcolor{red}} -\providecommand{\DIFdelend}{\protect\nogroupcolor{black}} -%DIF END DVIPSCOL PREAMBLE - -%DIF COLOR PREAMBLE -\RequirePackage{color} -\providecommand{\DIFaddbegin}{\protect\color{blue}} -\providecommand{\DIFaddend}{\protect\color{black}} -\providecommand{\DIFdelbegin}{\protect\color{red}} -\providecommand{\DIFdelend}{\protect\color{black}} -%DIF END COLOR PREAMBLE - - -%% FLOAT TYPES - -%DIF FLOATSAFE PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%DIF IDENTICAL PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{\DIFaddbegin} -\providecommand{\DIFaddendFL}{\DIFaddend} -\providecommand{\DIFdelbeginFL}{\DIFdelbegin} -\providecommand{\DIFdelendFL}{\DIFdelend} -%DIF END IDENTICAL PREAMBLE - -%DIF TRADITIONALSAFE PREAMBLE -% procidecommand color to make this work for TRADITIONAL and CTRADITIONAL -\providecommand{\color}[1]{} -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdel}[1]{{\protect\color{red}[..{\scriptsize {removed: #1}} ]}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%% SPECIAL PACKAGE PREAMBLE COMMANDS - -% Standard \DIFadd and \DIFdel are redefined as \DIFaddtex and \DIFdeltex -% when hyperref package is included. -%DIF HYPERREF PREAMBLE -\providecommand{\DIFadd}[1]{\texorpdfstring{\DIFaddtex{#1}}{#1}} -\providecommand{\DIFdel}[1]{\texorpdfstring{\DIFdeltex{#1}}{}} -%DIF END HYPERREF PACKAGE diff --git a/latexdiff-1.0.2/latexdiff-vc b/latexdiff-1.0.2/latexdiff-vc deleted file mode 100755 index 16b0dea..0000000 --- a/latexdiff-1.0.2/latexdiff-vc +++ /dev/null @@ -1,490 +0,0 @@ -#!/usr/bin/env perl -# -# latexdiff-vc - wrapper script for applying latexdiff to rcs managed files -# and for automatised creation of postscript or pdf from difference file -# -# Copyright (C) 2005-12 F J Tilmann (tilmann@gfz-potsdam.de, ftilmann@users.berlios.de) -# -# Project webpages: http://latexdiff.berlios.de/ -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# -# Contributors: S Utcke, H Bruyninckx -# -# 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 . -# -# Detailed usage information at the end of the file -# -# version 1.0.2: - option --so to use latexdiff-so -# version 1.0.1 (change version numbering to match that of latexdiff) -# - Option --fast to use latexdiff-fast, -# - git support (thanks to Bjørn Magnus Mathisen, Santi Béjar, Pietro Battiston and Stefan Alfredson for patches) - UNTESTED -# version 0.25: -# - bbl is allowed as alternative extension (instead of .tex) -# version 0.26a -# - Bug fix: it copes now correctly with the possibility that there are no changes between current -# and archived version -use Getopt::Long ; -use Pod::Usage qw/pod2usage/ ; -use File::Temp qw/tempdir/ ; -use File::Basename qw/dirname/; -use strict ; -use warnings ; - -my $versionstring=< 1); -# Variables -my ($file1,$file2,$diff,$diffbase,$answer,$options,$infile,$append,$dirname,$cwd); -my (@files,@ldoptions,@tmpfiles,@ptmpfiles,@difffiles); # , - -Getopt::Long::Configure('pass_through','bundling'); - -GetOptions('revision|r:s' => \@revs, - 'cvs' => \$cvs, - 'rcs' => \$rcs, - 'svn' => \$svn, - 'git' => \$git, - 'dir|d:s' => \$dir, - 'fast' => \$fast, - 'so' => \$so, - 'postscript|ps' => \$postscript, - 'pdf' => \$pdf, - 'force' => \$force, - 'version' => \$version, - 'help|h' => \$help); - -if ( $help ) { - pod2usage(1) ; -} - -if ( $version ) { - die $versionstring ; -} - -if ( $so ) { - $latexdiff='latexdiff-so'; -} -if ( $fast ) { - die "Cannot specify more than one of --fast or --so " if ($so); - $latexdiff='latexdiff-fast'; -} - -if ( $cvs ) { - $vc="CVS"; -} -if ( $rcs ) { - die "Cannot specify more than one of --cvs, --rcs --svn or --git." if ($vc); - $vc="RCS"; -} -if ( $svn ) { - die "Cannot specify more than one of --cvs, --rcs --svn or --git." if ($vc); - $vc="SVN"; -} -if ( $git ) { - die "Cannot specify more than one of --cvs, --rcs, --svn or --git." if ($vc); - $vc="GIT"; -} - - -# check whether the first file name or first passed-through option for latexdiff got misinterpreted as an option to an empty -r option -if ( @revs && ( -f $revs[$#revs] || $revs[$#revs] =~ /^-/ ) ) { - unshift @ARGV,$revs[$#revs]; - $revs[$#revs]=""; -} -# check whether the first file name or first passed-through option for latexdiff got misinterpreted as an option to an empty -d option -if ( defined($dir) && ( -f $dir || $dir =~ /^-/ ) ) { - unshift @ARGV,$dir; - $dir=""; -} - -#print "DEBUG: latexdiff-vc command line: ", join(" ",@ARGV), "\n"; - -$file2=pop @ARGV; -( defined($file2) && $file2 =~ /\.(tex|bbl)$/ ) or pod2usage("Must specify at least one tex or bbl file"); - -if (! $vc && scalar(@revs)>0 ) { - # have to guess $vc - # check whether we have a special name - if ( $0 =~ /-cvs$/ ) { - $vc="CVS"; - } elsif ( $0 =~ /-rcs$/ ) { - $vc="RCS"; - } elsif ( $0 =~ /-svn$/ ) { - $vc="SVN"; - } elsif ( $0 =~ /-git$/ ) { - $vc="GIT"; - } elsif ( -e "CVSROOT" || defined($ENV{"CVSROOT"}) ) { - print STDERR "Guess you are using CVS ...\n"; - $vc="CVS"; - } elsif ( -e "$file2,v" ) { - print STDERR "Guess you are using RCS ...\n"; - $vc="RCS"; - } elsif ( -d ".svn" ) { - print STDERR "Guess you are using SVN ...\n"; - $vc="SVN"; - } elsif ( -d ".git" ) { - print STDERR "Guess you are using GIT ...\n"; - $vc="GIT"; - } else { - print STDERR "Cannot figure out version control system, so I default to CVS\n"; - $vc="CVS"; - } -} - -if (defined($dir) && $dir=~/^\.\/?/ ) { - print STDERR "You wrote -dir=. but you do not really like to do that, do you ?\n"; - exit 10 -} - -if ( scalar(@revs)>0 ) { - if ( $vc eq "CVS" ) { - $diffcmd = "cvs diff -u -r"; - $patchcmd = "patch -R -p0"; - } elsif ( $vc eq "RCS" ) { - $diffcmd = "rcsdiff -u -r"; - $patchcmd = "patch -R -p0"; - } elsif ( $vc eq "SVN" ) { - $diffcmd = "svn diff -r "; - $patchcmd = "patch -R -p0"; - } elsif ( $vc eq "GIT" ) { - $diffcmd = "git diff -r --relative --no-prefix "; - $patchcmd = "patch -R -p0"; - # alternatively: - # $diffcmd = "git diff "; - # $patchcmd = "patch -R -p1"; - } else { - print STDERR "Unknown versioning system $vc \n"; - exit 10; - } -} - - -# make file list (last arguments), initial arguments have to be passed to latexdiff -# We assume an argument is a valid file rather than a latexdiff argument -# if it has extension .tex or .bbl - -@files=($file2); -while( $file1=pop @ARGV ) { - if ( $file1 =~ /\.(tex|bbl)$/ ) { - # $file1 looks like a valid file name and is prepended to file list - unshift @files, $file1 ; - } else { - # $file1 looks like an option for latexdiff, push it back to argument stack - unshift @ldoptions, $file1 ; - } -} - -if ( scalar(@revs) == 0 ) { - pod2usage("When -r option is not used, two .tex files (old and new) must be given on the command line") unless @files==2; - # compare two files - $file1=shift @files ; -} - -if ( scalar(@revs) == 2 ) { - $append = "-diff$revs[0]-$revs[1]"; -} elsif ( scalar(@revs) == 1 || $revs[0] ) { - $append = "-diff$revs[0]"; -} else { - $append = "-diff"; -} - -if ( defined ($dir) && ! $dir ) { - # bare -d option => choose directory name - ($dir=$append) =~ s/^-//; -} - -if ( ($vc eq "SVN" || $vc eq "CVS") && scalar(@revs)) { - length($revs[$#revs]) > 0 or $revs[$#revs]="HEAD"; - length($revs[0]) > 0 or $revs[0]="HEAD"; -} - -#exit ; - - -# cycle through all files - -@difffiles=(); -while ( $infile=$file2=shift @files ) { - print STDERR "Working on $infile \n"; - if ( scalar(@revs) == 1 ) { - ($file1=$infile) =~ s/\.(tex|bbl)/-oldtmp-$$.$1/ ; - push @tmpfiles,$file1; - # compare file with previous version ($revs[0]="") or specified version - ### system("$diffcmd$revs[0] $infile| $patchcmd -o$file1") ; - if (system("$diffcmd$revs[0] $infile | $patchcmd -o$file1")==0 and -z $file1 ) { - # no differences detected, i.e. file is equal to current version - system("\cp $infile $file1"); - } - } elsif ( scalar(@revs) == 2 ) { - ($file1=$infile) =~ s/\.(tex|bbl)/-oldtmp-$$.$1/ ; - $file2 =~ s/\.(tex|bbl)/-newtmp-$$.$1/ ; - push @tmpfiles,$file2; - ; - if (system("$diffcmd$revs[1] $infile | $patchcmd -o$file2")==0 and -z $file2 ) { - system("\cp $infile $file2"); - } - if (system("$diffcmd$revs[0] $infile | $patchcmd -o$file1")==0 and -z $file1 ) { - system("\cp $infile $file1"); - }; - } - - if ( -z $file1 || -z $file2) { - print STDERR "One or both of the files to compare are empty. Possibly something went wrong in the retrieval of older versions. Aborting ...\n" ; - exit(10); - } - - # Get name of difference file - if ( defined($dir) ) { - $diff="$dir/$infile" ; - } else { - ($diff=$infile) =~ s/\.(tex|bbl)$/$append.$1/ ; - } - # make directories if needed - $dirname=dirname($diff) ; - system("mkdir -p $dirname") unless ( -e $dirname ); - - # Remaining options are passed to latexdiff - $options = join(" ",@ldoptions); - - if ( -e $diff && ! $force ) { - print STDERR "OK to overwrite existing file $diff (y/n)? "; - $answer = ; - unless ($answer =~ /^y/i ) { - unlink @tmpfiles; - die "Abort ... " ; - } - } - print "Running $latexdiff\n"; - unless ( system("$latexdiff $options $file1 $file2 > $diff") == 0 ) { - print STDERR "Something went wrong in $latexdiff. Deleting $diff and abort\n" ; unlink $diff ; exit(5) - }; - print "Generated difference file $diff\n"; - - if ( ( $postscript or $pdf ) and !( scalar(@revs) && greptex( qr/\\document(?:class|style)/ , $diff ) ) ) { - # save filename for later processing if postscript or pdf conversion is requested and either two-file mode was used (scalar(@revs)==0) or the diff file contains documentclass statement (ie. is a root document) - push @difffiles, $diff ; - } - - unlink @tmpfiles; -} - -foreach $diff ( @difffiles ) { - chomp($cwd=(`pwd`)); - if (defined($dir)) { - ( $diff =~ s/$dir\/?// ) ; - chdir $dir ; - } - @ptmpfiles=(); - ( $diffbase=$diff) =~ s/\.(tex)$// ; - - # adapt magically changebar styles to [pdftex] display driver if pdf output was selected - if ( $pdf ) { - system("sed \"s/Package\\[dvips\\]/Package[pdftex]/\" $diff > $diff.tmp$$ ; \\mv $diff.tmp$$ $diff"); - } - print STDERR "PDF: $pdf Postscript: $postscript cwd $cwd\n"; - - if ( system("grep -q \'^[^%]*\\\\bibliography\' $diff") == 0 ) { - if ( $postscript) { - system("latex --interaction=batchmode $diff; bibtex $diffbase"); - push @ptmpfiles, "$diffbase.bbl","$diffbase.bbl" ; - } elsif ( $pdf ) { - system("pdflatex --interaction=batchmode $diff; bibtex $diffbase"); - push @ptmpfiles, "$diffbase.bbl","$diffbase.bbl" ; - } - } - - if ( $postscript ) { - my $dvi="$diffbase.dvi"; - my $ps="$diffbase.ps"; - - system("latex --interaction=batchmode $diff; latex $diff; dvips -o $ps $dvi"); - push @ptmpfiles, "$diffbase.aux","$diffbase.log",$dvi ; - print "Generated postscript file $ps\n"; - } - elsif ( $pdf ) { - system("pdflatex --interaction=batchmode $diff; pdflatex $diff"); - push @ptmpfiles, "$diffbase.aux","$diffbase.log"; - } - unlink @ptmpfiles; - chdir $cwd; -} - -# greptex returns 1 if regex is not matched in filename -# 0 if there is a match -sub greptex { - my ($regex,$filename)=@_; - my ($i)=0; - open (FH, $filename) or die("Couldn't open $filename: $!"); - while () { - next if /^\s*%/; # skip comment lines - if ( m/$regex/ ) { - close(FH); - return(0); - } - # only scan 25 lines - $i++; - last if $i>25 ; - } - close(FH); - return(1); -} - - -=head1 NAME - -latexdiff-vc - wrapper script that calls latexdiff for different versions of a file under version management (CVS, RCS or SVN) - -=head1 SYNOPSIS - -B [ F ] [ F ] B<-r> [F] [B<-r> F] F [ F ...] - - or - -B [ F ] [ F ][ B<--postscript> | B<--pdf> ] F F - -=head1 DESCRIPTION - -I is a wrapper script that applies I to a -file, or multiple files under version control (CVS, RCS or SVN), and optionally runs the -sequence of C and C or C commands necessary to -produce pdf or postscript output of the difference tex file(s). It can -also be applied to a pair of files to automatise the generation of difference -file in postscript or pdf format. - -=head1 OPTIONS - -=over 4 - -=item B<--rcs>, B<--svn>, B<--cvs>, or B<--git> - -Set the version system. -If no version system is specified, latexdiff-vc will venture a guess. - -latexdiff-cvs and latexdiff-rcs are variants of latexdiff-vc which default to -the respective versioning system. However, this default can still be overridden using the options above. - -=item B<-r>, B<-r> F or B<--revision>, B<--revision=>F - -Choose revision (under RCS, CVS, SVN or GIT). One or two B<-r> options can be -specified, and they result in different behaviour: - -=over 4 - -=item B -r F ... - -compares F with the most recent version checked into RCS. - -=item B -r F F ... - -compares F with revision F. - -=item B -r F -r F F ... - -compares revisions F and F of F. - -Multiple files can be specified for all of the above options. All files must have the -extension C<.tex>, though. - -=item B F F - -compares two files. - -=back - -The name of the difference file is generated automatically and -reported to stdout. - -=item B<-d> or B<--dir> B<-d> F or B<--dir=>F - -Rather than appending the string C and optionally the version -numbers given to the output-file, this will prepend a directory name C -to the -original filename, creating the directory and subdirectories should they not exist already. This is particularly useful in order to clone a -complete directory hierarchy. Optionally, a pathname F can be specified, which is prepended instead of C. - -=item B<--fast> or B<--so> - -Use C or C, respectively (instead of C). - -=item B<--ps> or B<--postscript> - -Generate postscript output from difference file. This will run the -sequence C on the difference file (do not use -this option in the rare cases, where three C commands are -required if you care about correct referencing). If the difference -file contains a C<\bibliography> tag, run the sequence C. - -=item B<--pdf> - -Generate pdf output from difference file using C. This will -run the sequence C on the difference file, or -C for files requiring bibtex. - -=item B<--force> - -Overwrite existing diff files without asking for confirmation. Default -behaviour is to ask for confirmation before overwriting an existing difference -file. - -=item B<--help> or -B<-h> - -Show help text - -=item B<--version> - -Show version number - -=back - -All other options are passed on to C. - -=head1 SEE ALSO - -L - -=head1 PORTABILITY - -I uses external commands and is therefore -limited to Unix-like systems. It also requires the RCS version control -system and latex to be installed on the system. Modules from Perl 5.8 -or higher are required. - -=head1 BUG REPORTING - - Please submit bug reports through -the latexdiff project page I or send -to I. Include the serial number of I -(option C<--version>) -. -=head1 AUTHOR - -Copyright (C) 2005,2012 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 -Contributors: S Utcke, H Bruyninckx - -=cut - diff --git a/latexdiff-1.0.2/latexdiff-vc.1 b/latexdiff-1.0.2/latexdiff-vc.1 deleted file mode 100644 index 497b8fe..0000000 --- a/latexdiff-1.0.2/latexdiff-vc.1 +++ /dev/null @@ -1,246 +0,0 @@ -.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` "" -. ds C' "" -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.ie \nF \{\ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. nr % 0 -. rr F -.\} -.el \{\ -. de IX -.. -.\} -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "LATEXDIFF-VC 1" -.TH LATEXDIFF-VC 1 "2012-12-16" "perl v5.12.4" " " -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -latexdiff\-vc \- wrapper script that calls latexdiff for different versions of a file under version management (CVS, RCS or SVN) -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBlatexdiff-vc\fR [ \fIlatexdiff-options\fR ] [ \fIlatexdiff-vc-options\fR ] \fB\-r\fR [\fIrev1\fR] [\fB\-r\fR \fIrev2\fR] \fIfile1.tex\fR [ \fIfile2.tex\fR ...] -.PP -.Vb 1 -\& or -.Ve -.PP -\&\fBlatexdiff-vc\fR [ \fIlatexdiff-options\fR ] [ \fIlatexdiff-vc-options\fR ][ \fB\-\-postscript\fR | \fB\-\-pdf\fR ] \fIold.tex\fR \fInew.tex\fR -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -\&\fIlatexdiff-vc\fR is a wrapper script that applies \fIlatexdiff\fR to a -file, or multiple files under version control (\s-1CVS\s0, \s-1RCS\s0 or \s-1SVN\s0), and optionally runs the -sequence of \f(CW\*(C`latex\*(C'\fR and \f(CW\*(C`dvips\*(C'\fR or \f(CW\*(C`pdflatex\*(C'\fR commands necessary to -produce pdf or postscript output of the difference tex file(s). It can -also be applied to a pair of files to automatise the generation of difference -file in postscript or pdf format. -.SH "OPTIONS" -.IX Header "OPTIONS" -.IP "\fB\-\-rcs\fR, \fB\-\-svn\fR, \fB\-\-cvs\fR, or \fB\-\-git\fR" 4 -.IX Item "--rcs, --svn, --cvs, or --git" -Set the version system. -If no version system is specified, latexdiff-vc will venture a guess. -.Sp -latexdiff-cvs and latexdiff-rcs are variants of latexdiff-vc which default to -the respective versioning system. However, this default can still be overridden using the options above. -.IP "\fB\-r\fR, \fB\-r\fR \fIrev\fR or \fB\-\-revision\fR, \fB\-\-revision=\fR\fIrev\fR" 4 -.IX Item "-r, -r rev or --revision, --revision=rev" -Choose revision (under \s-1RCS\s0, \s-1CVS\s0, \s-1SVN\s0 or \s-1GIT\s0). One or two \fB\-r\fR options can be -specified, and they result in different behaviour: -.RS 4 -.IP "\fBlatexdiff-vc\fR \-r \fIfile.tex\fR ..." 4 -.IX Item "latexdiff-vc -r file.tex ..." -compares \fIfile.tex\fR with the most recent version checked into \s-1RCS\s0. -.IP "\fBlatexdiff-vc\fR \-r \fIrev1\fR \fIfile.tex\fR ..." 4 -.IX Item "latexdiff-vc -r rev1 file.tex ..." -compares \fIfile.tex\fR with revision \fIrev1\fR. -.IP "\fBlatexdiff-vc\fR \-r \fIrev1\fR \-r \fIrev2\fR \fIfile.tex\fR ..." 4 -.IX Item "latexdiff-vc -r rev1 -r rev2 file.tex ..." -compares revisions \fIrev1\fR and \fIrev2\fR of \fIfile.tex\fR. -.Sp -Multiple files can be specified for all of the above options. All files must have the -extension \f(CW\*(C`.tex\*(C'\fR, though. -.IP "\fBlatexdiff-vc\fR \fIold.tex\fR \fInew.tex\fR" 4 -.IX Item "latexdiff-vc old.tex new.tex" -compares two files. -.RE -.RS 4 -.Sp -The name of the difference file is generated automatically and -reported to stdout. -.RE -.IP "\fB\-d\fR or \fB\-\-dir\fR \fB\-d\fR \fIpath\fR or \fB\-\-dir=\fR\fIpath\fR" 4 -.IX Item "-d or --dir -d path or --dir=path" -Rather than appending the string \f(CW\*(C`diff\*(C'\fR and optionally the version -numbers given to the output-file, this will prepend a directory name \f(CW\*(C`diff\*(C'\fR -to the -original filename, creating the directory and subdirectories should they not exist already. This is particularly useful in order to clone a -complete directory hierarchy. Optionally, a pathname \fIpath\fR can be specified, which is prepended instead of \f(CW\*(C`diff\*(C'\fR. -.IP "\fB\-\-fast\fR or \fB\-\-so\fR" 4 -.IX Item "--fast or --so" -Use \f(CW\*(C`latexdiff\-fast\*(C'\fR or \f(CW\*(C`latexdiff\-so\*(C'\fR, respectively (instead of \f(CW\*(C`latexdiff\*(C'\fR). -.IP "\fB\-\-ps\fR or \fB\-\-postscript\fR" 4 -.IX Item "--ps or --postscript" -Generate postscript output from difference file. This will run the -sequence \f(CW\*(C`latex; latex; dvips\*(C'\fR on the difference file (do not use -this option in the rare cases, where three \f(CW\*(C`latex\*(C'\fR commands are -required if you care about correct referencing). If the difference -file contains a \f(CW\*(C`\ebibliography\*(C'\fR tag, run the sequence \f(CW\*(C`latex; -bibtex; latex; latex; dvips\*(C'\fR. -.IP "\fB\-\-pdf\fR" 4 -.IX Item "--pdf" -Generate pdf output from difference file using \f(CW\*(C`pdflatex\*(C'\fR. This will -run the sequence \f(CW\*(C`pdflatex; pdflatex\*(C'\fR on the difference file, or -\&\f(CW\*(C`pdflatex; bibtex; pdflatex; pdflatex\*(C'\fR for files requiring bibtex. -.IP "\fB\-\-force\fR" 4 -.IX Item "--force" -Overwrite existing diff files without asking for confirmation. Default -behaviour is to ask for confirmation before overwriting an existing difference -file. -.IP "\fB\-\-help\fR or \fB\-h\fR" 4 -.IX Item "--help or -h" -Show help text -.IP "\fB\-\-version\fR" 4 -.IX Item "--version" -Show version number -.PP -All other options are passed on to \f(CW\*(C`latexdiff\*(C'\fR. -.SH "SEE ALSO" -.IX Header "SEE ALSO" -latexdiff -.SH "PORTABILITY" -.IX Header "PORTABILITY" -\&\fIlatexdiff-vc\fR uses external commands and is therefore -limited to Unix-like systems. It also requires the \s-1RCS\s0 version control -system and latex to be installed on the system. Modules from Perl 5.8 -or higher are required. -.SH "BUG REPORTING" -.IX Header "BUG REPORTING" -.Vb 6 -\& Please submit bug reports through -\&the latexdiff project page I or send -\&to I. Include the serial number of I -\&(option C<\-\-version>) -\&. -\&=head1 AUTHOR -.Ve -.PP -Copyright (C) 2005,2012 Frederik Tilmann -.PP -This program is free software; you can redistribute it and/or modify -it under the terms of the \s-1GNU\s0 General Public License Version 3 -Contributors: S Utcke, H Bruyninckx diff --git a/latexdiff-1.0.2/latexdiff.1 b/latexdiff-1.0.2/latexdiff.1 deleted file mode 100644 index 2f075da..0000000 --- a/latexdiff-1.0.2/latexdiff.1 +++ /dev/null @@ -1,758 +0,0 @@ -.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` "" -. ds C' "" -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.ie \nF \{\ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. nr % 0 -. rr F -.\} -.el \{\ -. de IX -.. -.\} -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "LATEXDIFF 1" -.TH LATEXDIFF 1 "2012-12-16" "perl v5.12.4" " " -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -latexdiff \- determine and markup differences between two latex files -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBlatexdiff\fR [ \fB\s-1OPTIONS\s0\fR ] \fIold.tex\fR \fInew.tex\fR > \fIdiff.tex\fR -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -Briefly, \fIlatexdiff\fR is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called \f(CW\*(C`old.tex\*(C'\fR and \f(CW\*(C`new.tex\*(C'\fR, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. -.PP -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "\f(CW\*(C`%DIF\ >\*(C'\fR" is appended to each added line, i.e. a -line present in \f(CW\*(C`new.tex\*(C'\fR but not in \f(CW\*(C`old.tex\*(C'\fR. Discarded lines - are deactivated by prepending "\f(CW\*(C`%DIF\ <\*(C'\fR". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file \f(CW\*(C`diff.tex\*(C'\fR will be similar to -\&\f(CW\*(C`new.tex\*(C'\fR. At the end of the preamble, the definitions for \fIlatexdiff\fR markup commands are inserted. -In differencing the main body of the text, \fIlatexdiff\fR attempts to -satisfy the following guidelines (in order of priority): -.IP "1." 3 -If both \f(CW\*(C`old.tex\*(C'\fR and \f(CW\*(C`new.tex\*(C'\fR are valid LaTeX, then the resulting -\&\f(CW\*(C`diff.tex\*(C'\fR should also be valid LateX. (\s-1NB\s0 If a few plain TeX commands -are used within \f(CW\*(C`old.tex\*(C'\fR or \f(CW\*(C`new.tex\*(C'\fR then \f(CW\*(C`diff.tex\*(C'\fR is not -guaranteed to work but usually will). -.IP "2." 3 -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -\&\f(CW\*(C`diff.tex\*(C'\fR. -.IP "3." 3 -If a changed passage contains text or text-producing commands, then -running \f(CW\*(C`diff.tex\*(C'\fR through LateX should produce output where added -and discarded passages are highlighted. -.IP "4." 3 -Where there are insignificant differences, e.g. in the positioning of -line breaks, \f(CW\*(C`diff.tex\*(C'\fR should follow the formatting of \f(CW\*(C`new.tex\*(C'\fR -.PP -For differencing the same algorithm as \fIdiff\fR is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, \f(CW\*(C`\ecaption\*(C'\fR and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write -.PP -.Vb 1 -\& \esection{\etextem{This is an emphasized section title}} -.Ve -.PP -and not -.PP -.Vb 1 -\& \esection {\etextem{This is an emphasized section title}} -.Ve -.PP -or -.PP -.Vb 1 -\& \esection\etextem{This is an emphasized section title} -.Ve -.PP -even though all varieties are the same to LaTeX (but see -\&\fB\-\-allow\-spaces\fR option which allows the second variety). -.PP -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the \s-1PICTUREENV\s0 configuration variable, set by -default to \f(CW\*(C`picture\*(C'\fR and \f(CW\*(C`DIFnomarkup\*(C'\fR environments; see \fB\-\-config\fR -option). The latter environment (\f(CW\*(C`DIFnomarkup\*(C'\fR) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by \f(CW\*(C`\ebegin{DIFnomarkup}\*(C'\fR and \f(CW\*(C`\eend{DIFnomarkup}\*(C'\fR. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, -.PP -\&\f(CW\*(C`\enewenvironment{DIFnomarkup}{}{}\*(C'\fR -.PP -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. -.PP -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. -.PP -All markup commands inserted by \fIlatexdiff\fR begin with "\f(CW\*(C`\eDIF\*(C'\fR". Added -blocks containing words, commands or comments which are in \f(CW\*(C`new.tex\*(C'\fR -but not in \f(CW\*(C`old.tex\*(C'\fR are marked by \f(CW\*(C`\eDIFaddbegin\*(C'\fR and \f(CW\*(C`\eDIFaddend\*(C'\fR. -Discarded blocks are marked by \f(CW\*(C`\eDIFdelbegin\*(C'\fR and \f(CW\*(C`\eDIFdelend\*(C'\fR. -Within added blocks all text is highlighted with \f(CW\*(C`\eDIFadd\*(C'\fR like this: -\&\f(CW\*(C`\eDIFadd{Added text block}\*(C'\fR -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces \*(L"{\*(R" and \*(L"}\*(R" are never put within -the scope of \f(CW\*(C`\eDIFadd\*(C'\fR. Added comments are marked by prepending -"\f(CW\*(C`%DIF\ >\ \*(C'\fR". -.PP -Within deleted blocks text is highlighted with \f(CW\*(C`\eDIFdel\*(C'\fR. Deleted -comments are marked by prepending "\f(CW\*(C`%DIF\ <\ \*(C'\fR\*(L". Non-safe command -and curly braces within deleted blocks are commented out with -\&\*(R"\f(CW\*(C`%DIFDELCMD\ <\ \*(C'\fR". -.SH "OPTIONS" -.IX Header "OPTIONS" -.SS "Preamble" -.IX Subsection "Preamble" -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. -.IP "\fB\-\-type=markupstyle\fR or \fB\-t markupstyle\fR" 4 -.IX Item "--type=markupstyle or -t markupstyle" -Add code to preamble for selected markup style. This option defines -\&\f(CW\*(C`\eDIFadd\*(C'\fR and \f(CW\*(C`\eDIFdel\*(C'\fR commands. -Available styles: -.Sp -\&\f(CW\*(C`UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE -CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR\*(C'\fR -.Sp -[ Default: \f(CW\*(C`UNDERLINE\*(C'\fR ] -.IP "\fB\-\-subtype=markstyle\fR or \fB\-s markstyle\fR" 4 -.IX Item "--subtype=markstyle or -s markstyle" -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -\&\f(CW\*(C`\eDIFaddbegin\*(C'\fR, \f(CW\*(C`\eDIFaddend\*(C'\fR, \f(CW\*(C`\eDIFdelbegin\*(C'\fR and \f(CW\*(C`\eDIFdelend\*(C'\fR commands. -Available styles: \f(CW\*(C`SAFE MARGINAL COLOR DVIPSCOL\*(C'\fR -.Sp -[ Default: \f(CW\*(C`SAFE\*(C'\fR ] -.IP "\fB\-\-floattype=markstyle\fR or \fB\-f markstyle\fR" 4 -.IX Item "--floattype=markstyle or -f markstyle" -Add code to preamble for selected style which -replace standard marking and markup commands within floats -(e.g., marginal remarks cause an error within floats -so marginal marking can be disabled thus). This option defines all -\&\f(CW\*(C`\eDIF...FL\*(C'\fR commands. -Available styles: \f(CW\*(C`FLOATSAFE TRADITIONALSAFE IDENTICAL\*(C'\fR -.Sp -[ Default: \f(CW\*(C`FLOATSAFE\*(C'\fR ] -.IP "\fB\-\-encoding=enc\fR or \fB\-e enc\fR" 4 -.IX Item "--encoding=enc or -e enc" -Specify encoding of old.tex and new.tex. Typical encodings are -\&\f(CW\*(C`ascii\*(C'\fR, \f(CW\*(C`utf8\*(C'\fR, \f(CW\*(C`latin1\*(C'\fR, \f(CW\*(C`latin9\*(C'\fR. A list of available encodings can be -obtained by executing -.Sp -\&\f(CW\*(C`perl \-MEncode \-e \*(Aqprint join ("\en",Encode\-\*(C'\fRencodings( \*(L":all\*(R" )) ;' > -.Sp -[Default encoding is utf8 unless the first few lines of the preamble contain -an invocation \f(CW\*(C`\eusepackage[..]{inputenc}\*(C'\fR in which case the -encoding chosen by this command is asssumed. Note that \s-1ASCII\s0 (standard -latex) is a subset of utf8] -.IP "\fB\-\-preamble=file\fR or \fB\-p file\fR" 4 -.IX Item "--preamble=file or -p file" -Insert file at end of preamble instead of generating -preamble. The preamble must define the following commands -\&\f(CW\*(C`\eDIFaddbegin, \eDIFaddend, \eDIFadd{..}, -\&\eDIFdelbegin,\eDIFdelend,\eDIFdel{..},\*(C'\fR -and varieties for use within floats -\&\f(CW\*(C`\eDIFaddbeginFL, \eDIFaddendFL, \eDIFaddFL{..}, -\&\eDIFdelbeginFL, \eDIFdelendFL, \eDIFdelFL{..}\*(C'\fR -(If this option is set \fB\-t\fR, \fB\-s\fR, and \fB\-f\fR options -are ignored.) -.IP "\fB\-\-packages=pkg1,pkg2,..\fR" 4 -.IX Item "--packages=pkg1,pkg2,.." -Tell latexdiff that .tex file is processed with the packages in list -loaded. This is normally not necessary if the .tex file includes the -preamble, as the preamble is automatically scanned for \f(CW\*(C`\eusepackage\*(C'\fR commands. -Use of the \fB\-\-packages\fR option disables automatic scanning, so if for any -reason package specific parsing needs to be switched off, use \fB\-\-packages=none\fR. -The following packages trigger special behaviour: -.RS 4 -.ie n .IP """amsmath""" 8 -.el .IP "\f(CWamsmath\fR" 8 -.IX Item "amsmath" -Configuration variable amsmath is set to \f(CW\*(C`align*\*(C'\fR (Default: \f(CW\*(C`eqnarray*\*(C'\fR) -.ie n .IP """endfloat""" 8 -.el .IP "\f(CWendfloat\fR" 8 -.IX Item "endfloat" -Ensure that \f(CW\*(C`\ebegin{figure}\*(C'\fR and \f(CW\*(C`\eend{figure}\*(C'\fR always appear by themselves on a line. -.ie n .IP """hyperref""" 8 -.el .IP "\f(CWhyperref\fR" 8 -.IX Item "hyperref" -Change name of \f(CW\*(C`\eDIFadd\*(C'\fR and \f(CW\*(C`\eDIFdel\*(C'\fR commands to \f(CW\*(C`\eDIFaddtex\*(C'\fR and \f(CW\*(C`\eDIFdeltex\*(C'\fR and -define new \f(CW\*(C`\eDIFadd\*(C'\fR and \f(CW\*(C`\eDIFdel\*(C'\fR commands, which provide a wrapper for these commands, -using them for the text but not for the link defining command (where any markup would cause -errors). -.RE -.RS 4 -.Sp -[ Default: scan the preamble for \f(CW\*(C`\e\eusepackage\*(C'\fR commands to determine - loaded packages.] -.RE -.IP "\fB\-\-show\-preamble\fR" 4 -.IX Item "--show-preamble" -Print generated or included preamble commands to stdout. -.SS "Configuration" -.IX Subsection "Configuration" -.ie n .IP "\fB\-\-exclude\-safecmd=exclude\-file\fR or \fB\-A exclude-file\fR or \fB\-\-exclude\-safecmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-exclude\-safecmd=exclude\-file\fR or \fB\-A exclude-file\fR or \fB\-\-exclude\-safecmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--exclude-safecmd=exclude-file or -A exclude-file or --exclude-safecmd=cmd1,cmd2,..." -.PD 0 -.IP "\fB\-\-replace\-safecmd=replace\-file\fR" 4 -.IX Item "--replace-safecmd=replace-file" -.ie n .IP "\fB\-\-append\-safecmd=append\-file\fR or \fB\-a append-file\fR or \fB\-\-append\-safecmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-append\-safecmd=append\-file\fR or \fB\-a append-file\fR or \fB\-\-append\-safecmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--append-safecmd=append-file or -a append-file or --append-safecmd=cmd1,cmd2,..." -.PD -Exclude from, replace or append to the list of regular expressions (RegEx) -matching commands which are safe to use within the -scope of a \f(CW\*(C`\eDIFadd\*(C'\fR or \f(CW\*(C`\eDIFdel\*(C'\fR command. The file must contain -one Perl-RegEx per line (Comment lines beginning with # or % are -ignored). Note that the RegEx needs to match the whole of -the token, i.e., /^regex$/ is implied and that the initial -\&\*(L"\e\*(R" of the command is not included. -The \fB\-\-exclude\-safecmd\fR and \fB\-\-append\-safecmd\fR options can be combined with the \-\fB\-\-replace\-safecmd\fR -option and can be used repeatedly to add cumulatively to the lists. - \fB\-\-exclude\-safecmd\fR -and \fB\-\-append\-safecmd\fR can also take a comma separated list as input. If a -comma for one of the regex is required, escape it thus \*(L"\e,\*(R". In most cases it -will be necessary to protect the comma-separated list from the shell by putting -it in quotation marks. -.ie n .IP "\fB\-\-exclude\-textcmd=exclude\-file\fR or \fB\-X exclude-file\fR or \fB\-\-exclude\-textcmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-exclude\-textcmd=exclude\-file\fR or \fB\-X exclude-file\fR or \fB\-\-exclude\-textcmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--exclude-textcmd=exclude-file or -X exclude-file or --exclude-textcmd=cmd1,cmd2,..." -.PD 0 -.IP "\fB\-\-replace\-textcmd=replace\-file\fR" 4 -.IX Item "--replace-textcmd=replace-file" -.ie n .IP "\fB\-\-append\-textcmd=append\-file\fR or \fB\-x append-file\fR or \fB\-\-append\-textcmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-append\-textcmd=append\-file\fR or \fB\-x append-file\fR or \fB\-\-append\-textcmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--append-textcmd=append-file or -x append-file or --append-textcmd=cmd1,cmd2,..." -.PD -Exclude from, replace or append to the list of regular expressions -matching commands whose last argument is text. See -entry for \fB\-\-exclude\-safecmd\fR directly above for further details. -.IP "\fB\-\-replace\-context1cmd=replace\-file\fR" 4 -.IX Item "--replace-context1cmd=replace-file" -.PD 0 -.ie n .IP "\fB\-\-append\-context1cmd=append\-file\fR or =item \fB\-\-append\-context1cmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-append\-context1cmd=append\-file\fR or =item \fB\-\-append\-context1cmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--append-context1cmd=append-file or =item --append-context1cmd=cmd1,cmd2,..." -.PD -Replace or append to the list of regex matching commands -whose last argument is text but which require a particular -context to work, e.g. \ecaption will only work within a figure -or table. These commands behave like text commands, except when -they occur in a deleted section, when they are disabled, but their -argument is shown as deleted text. -.IP "\fB\-\-replace\-context2cmd=replace\-file\fR" 4 -.IX Item "--replace-context2cmd=replace-file" -.PD 0 -.ie n .IP "\fB\-\-append\-context2cmd=append\-file\fR or =item \fB\-\-append\-context2cmd=""cmd1,cmd2,...""\fR As corresponding commands for context1. The only difference is that context2 commands are completely disabled in deleted sections, including their arguments." 4 -.el .IP "\fB\-\-append\-context2cmd=append\-file\fR or =item \fB\-\-append\-context2cmd=``cmd1,cmd2,...''\fR As corresponding commands for context1. The only difference is that context2 commands are completely disabled in deleted sections, including their arguments." 4 -.IX Item "--append-context2cmd=append-file or =item --append-context2cmd=cmd1,cmd2,... As corresponding commands for context1. The only difference is that context2 commands are completely disabled in deleted sections, including their arguments." -.IP "\fB\-\-config var1=val1,var2=val2,...\fR or \fB\-c var1=val1,..\fR" 4 -.IX Item "--config var1=val1,var2=val2,... or -c var1=val1,.." -.IP "\fB\-c configfile\fR" 4 -.IX Item "-c configfile" -.PD -Set configuration variables. The option can be repeated to set different -variables (as an alternative to the comma-separated list). -Available variables (see below for further explanations): -.Sp -\&\f(CW\*(C`MINWORDSBLOCK\*(C'\fR (integer) -.Sp -\&\f(CW\*(C`FLOATENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`PICTUREENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`MATHENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`MATHREPL\*(C'\fR (String) -.Sp -\&\f(CW\*(C`MATHARRENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`MATHARRREPL\*(C'\fR (String) -.Sp -\&\f(CW\*(C`ARRENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`COUNTERCMD\*(C'\fR (RegEx) -.IP "\fB\-\-show\-safecmd\fR" 4 -.IX Item "--show-safecmd" -Print list of RegEx matching and excluding safe commands. -.IP "\fB\-\-show\-textcmd\fR" 4 -.IX Item "--show-textcmd" -Print list of RegEx matching and excluding commands with text argument. -.IP "\fB\-\-show\-config\fR" 4 -.IX Item "--show-config" -Show values of configuration variables. -.IP "\fB\-\-show\-all\fR" 4 -.IX Item "--show-all" -Combine all \-\-show commands. -.Sp -\&\s-1NB\s0 For all \-\-show commands, no \f(CW\*(C`old.tex\*(C'\fR or \f(CW\*(C`new.tex\*(C'\fR file needs to be specified, and no -differencing takes place. -.SS "Other configuration options:" -.IX Subsection "Other configuration options:" -.IP "\fB\-\-allow\-spaces\fR" 4 -.IX Item "--allow-spaces" -Allow spaces between bracketed or braced arguments to commands. Note -that this option might have undesirable side effects (unrelated scope -might get lumpeded with preceding commands) so should only be used if the -default produces erroneous results. (Default requires arguments to -directly follow each other without intervening spaces). -.IP "\fB\-\-math\-markup=level\fR" 4 -.IX Item "--math-markup=level" -Determine granularity of markup in displayed math environments: -Possible values for level are (both numerical and text labels are acceptable): -.Sp -\&\f(CW\*(C`off\*(C'\fR or \f(CW0\fR: suppress markup for math environments. Deleted equations will not -appear in diff file. This mode can be used if all the other modes -cause invalid latex code. -.Sp -\&\f(CW\*(C`whole\*(C'\fR or \f(CW1\fR: Differencing on the level of whole equations. Even trivial changes -to equations cause the whole equation to be marked changed. This -mode can be used if processing in coarse or fine mode results in -invalid latex code. -.Sp -\&\f(CW\*(C`coarse\*(C'\fR or \f(CW2\fR: Detect changes within equations marked up with a coarse -granularity; changes in equation type (e.g.displaymath to equation) -appear as a change to the complete equation. This mode is recommended -for situations where the content and order of some equations are still -being changed. [Default] -.Sp -\&\f(CW\*(C`fine\*(C'\fR or \f(CW3\fR: Detect small change in equations and mark up at fine granularity. -This mode is most suitable, if only minor changes to equations are -expected, e.g. correction of typos. -.IP "\fB\-\-disable\-citation\-markup\fR" 4 -.IX Item "--disable-citation-markup" -Suppress citation markup in styles using ulem (\s-1UNDERLINE\s0, -\&\s-1FONTSTRIKE\s0, \s-1CULINECHBAR\s0) -.IP "\fB\-\-enable\-citation\-markup\fR" 4 -.IX Item "--enable-citation-markup" -Protect citation commands in changed sections with \e\embox command [i.e. use default behaviour for ulem package for other packages] -.SS "Miscellaneous" -.IX Subsection "Miscellaneous" -.RS 4 -Output various status information to stderr during processing. -Default is to work silently. -.Sp -\&\fB\-\-driver=type\fR -.Sp -Choose driver for changebar package (only relevant for styles using - changebar: \s-1CCHANGEBAR\s0 \s-1CFONTCHBAR\s0 \s-1CULINECHBAR\s0 \s-1CHANGEBAR\s0). Possible -drivers are listed in changebar manual, e.g. pdftex,dvips,dvitops - [Default: dvips] -.Sp -\&\fB\-\-ignore\-warnings\fR -.Sp -Suppress warnings about inconsistencies in length between input and -parsed strings and missing characters. These warning messages are -often related to non-standard latex or latex constructions with a -syntax unknown to \f(CW\*(C`latexdiff\*(C'\fR but the resulting difference argument -is often fully functional anyway, particularly if the non-standard -latex only occurs in parts of the text which have not changed. -.Sp -\&\fB\-\-label=label\fR or -\&\fB\-L label\fR -.Sp -Sets the labels used to describe the old and new files. The first use -of this option sets the label describing the old file and the second -use of the option sets the label for the new file, i.e. set both -labels like this \f(CW\*(C`\-L labelold \-L labelnew\*(C'\fR. -[Default: use the filename and modification dates for the label] -.Sp -\&\fB\-\-no\-label\fR -.Sp -Suppress inclusion of old and new file names as comment in output file -.Sp -\&\fB\-\-visble\-label\fR -.Sp -Include old and new filenames (or labels set with \-\-label option) as -visible output. -.Sp -\&\fB\-\-flatten\fR -.Sp -Replace \f(CW\*(C`\einput\*(C'\fR and \f(CW\*(C`\einclude\*(C'\fR commands within body by the content -of the files in their argument. If \f(CW\*(C`\eincludeonly\*(C'\fR is present in the -preamble, only those files are expanded into the document. However, -no recursion is done, i.e. \f(CW\*(C`\einput\*(C'\fR and \f(CW\*(C`\einclude\*(C'\fR commands within -included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, -respectively, making it possible to organise files into old and new directories. -\&\-\-flatten is applied recursively, so inputted files can contain further -\&\f(CW\*(C`\einput\*(C'\fR statements. -.Sp -Use of this option might result in prohibitive processing times for -larger documents, and the resulting difference document -no longer reflects the structure of the input documents. -.Sp -\&\fB\-\-help\fR or -\&\fB\-h\fR -.Sp -Show help text -.Sp -\&\fB\-\-version\fR -.Sp -Show version number -.RE -.SS "Predefined styles" -.IX Subsection "Predefined styles" -.SS "Major types" -.IX Subsection "Major types" -The major type determine the markup of plain text and some selected latex commands outside floats by defining the markup commands \f(CW\*(C`\eDIFadd{...}\*(C'\fR and \f(CW\*(C`\eDIFdel{...}\*(C'\fR . -.ie n .IP """UNDERLINE""" 10 -.el .IP "\f(CWUNDERLINE\fR" 10 -.IX Item "UNDERLINE" -Added text is wavy-underlined and blue, discarded text is struck out and red -(Requires color and ulem packages). Overstriking does not work in displayed math equations such that deleted parts of equation are underlined, not struck out (this is a shortcoming inherent to the ulem package). -.ie n .IP """CTRADITIONAL""" 10 -.el .IP "\f(CWCTRADITIONAL\fR" 10 -.IX Item "CTRADITIONAL" -Added text is blue and set in sans-serif, and a red footnote is created for each discarded -piece of text. (Requires color package) -.ie n .IP """TRADITIONAL""" 10 -.el .IP "\f(CWTRADITIONAL\fR" 10 -.IX Item "TRADITIONAL" -Like \f(CW\*(C`CTRADITIONAL\*(C'\fR but without the use of color. -.ie n .IP """CFONT""" 10 -.el .IP "\f(CWCFONT\fR" 10 -.IX Item "CFONT" -Added text is blue and set in sans-serif, and discarded text is red and very small size. -.ie n .IP """FONTSTRIKE""" 10 -.el .IP "\f(CWFONTSTRIKE\fR" 10 -.IX Item "FONTSTRIKE" -Added tex is set in sans-serif, discarded text small and struck out -.ie n .IP """CCHANGEBAR""" 10 -.el .IP "\f(CWCCHANGEBAR\fR" 10 -.IX Item "CCHANGEBAR" -Added text is blue, and discarded text is red. Additionally, the changed text is marked with a bar in the margin (Requires color and changebar packages). -.ie n .IP """CFONTCHBAR""" 10 -.el .IP "\f(CWCFONTCHBAR\fR" 10 -.IX Item "CFONTCHBAR" -Like \f(CW\*(C`CFONT\*(C'\fR but with additional changebars (Requires color and changebar packages). -.ie n .IP """CULINECHBAR""" 10 -.el .IP "\f(CWCULINECHBAR\fR" 10 -.IX Item "CULINECHBAR" -Like \f(CW\*(C`UNDERLINE\*(C'\fR but with additional changebars (Requires color, ulem and changebar packages). -.ie n .IP """CHANGEBAR""" 10 -.el .IP "\f(CWCHANGEBAR\fR" 10 -.IX Item "CHANGEBAR" -No mark up of text, but mark margins with changebars (Requires changebar package). -.ie n .IP """INVISIBLE""" 10 -.el .IP "\f(CWINVISIBLE\fR" 10 -.IX Item "INVISIBLE" -No visible markup (but generic markup commands will still be inserted. -.SS "Subtypes" -.IX Subsection "Subtypes" -The subtype defines the commands that are inserted at the begin and end of added or discarded blocks, irrespectively of whether these blocks contain text or commands (Defined commands: \f(CW\*(C`\eDIFaddbegin, \eDIFaddend, \eDIFdelbegin, \eDIFdelend\*(C'\fR) -.ie n .IP """SAFE""" 10 -.el .IP "\f(CWSAFE\fR" 10 -.IX Item "SAFE" -No additional markup (Recommended choice) -.ie n .IP """MARGIN""" 10 -.el .IP "\f(CWMARGIN\fR" 10 -.IX Item "MARGIN" -Mark beginning and end of changed blocks with symbols in the margin nearby (using -the standard \f(CW\*(C`\emarginpar\*(C'\fR command \- note that this sometimes moves somewhat -from the intended position. -.ie n .IP """COLOR""" 10 -.el .IP "\f(CWCOLOR\fR" 10 -.IX Item "COLOR" -An alternative way of marking added passages in blue, and deleted ones in red. -(It is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete, for example -with citation commands). -.ie n .IP """DVIPSCOL""" 10 -.el .IP "\f(CWDVIPSCOL\fR" 10 -.IX Item "DVIPSCOL" -An alternative way of marking added passages in blue, and deleted ones in red. Note -that \f(CW\*(C`DVIPSCOL\*(C'\fR only works with the dvips converter, e.g. not pdflatex. -(it is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete). -.SS "Float Types" -.IX Subsection "Float Types" -Some of the markup used in the main text might cause problems when used within -floats (e.g. figures or tables). For this reason alternative versions of all -markup commands are used within floats. The float type defines these alternative commands. -.ie n .IP """FLOATSAFE""" 10 -.el .IP "\f(CWFLOATSAFE\fR" 10 -.IX Item "FLOATSAFE" -Use identical markup for text as in the main body, but set all commands marking the begin and end of changed blocks to null-commands. You have to choose this float type if your subtype is \f(CW\*(C`MARGIN\*(C'\fR as \f(CW\*(C`\emarginpar\*(C'\fR does not work properly within floats. -.ie n .IP """TRADITIONALSAFE""" 10 -.el .IP "\f(CWTRADITIONALSAFE\fR" 10 -.IX Item "TRADITIONALSAFE" -Mark additions the same way as in the main text. Deleted environments are marked by angular brackets \e[ and \e] and the deleted text is set in scriptscript size. This float type should always be used with the \f(CW\*(C`TRADITIONAL\*(C'\fR and \f(CW\*(C`CTRADITIONAL\*(C'\fR markup types as the \efootnote command does not work properly in floating environments. -.ie n .IP """IDENTICAL""" 10 -.el .IP "\f(CWIDENTICAL\fR" 10 -.IX Item "IDENTICAL" -Make no difference between the main text and floats. -.SS "Configuration Variables" -.IX Subsection "Configuration Variables" -.ie n .IP """MINWORDSBLOCK""" 10 -.el .IP "\f(CWMINWORDSBLOCK\fR" 10 -.IX Item "MINWORDSBLOCK" -Minimum number of tokens required to form an independent block. This value is -used in the algorithm to detect changes of complete blocks by merging identical text parts of less than \f(CW\*(C`MINWORDSBLOCK\*(C'\fR to the preceding added and discarded parts. -.Sp -[ Default: 3 ] -.ie n .IP """FLOATENV""" 10 -.el .IP "\f(CWFLOATENV\fR" 10 -.IX Item "FLOATENV" -Environments whose name matches the regular expression in \f(CW\*(C`FLOATENV\*(C'\fR are -considered floats. Within these environments, the \fIlatexdiff\fR markup commands -are replaced by their \s-1FL\s0 variaties. -.Sp -[ Default: \f(CW\*(C`(?:figure|table|plate)[\ew\ed*@]*\*(C'\fR\ ] -.ie n .IP """PICTUREENV""" 10 -.el .IP "\f(CWPICTUREENV\fR" 10 -.IX Item "PICTUREENV" -Within environments whose name matches the regular expression in \f(CW\*(C`PICTUREENV\*(C'\fR -all latexdiff markup is removed (in pathologic cases this might lead to - inconsistent markup but this situation should be rare). -.Sp -[ Default: \f(CW\*(C`(?:picture|DIFnomarkup)[\ew\ed*@]*\*(C'\fR\ ] -.ie n .IP """MATHENV"",""MATHREPL""" 10 -.el .IP "\f(CWMATHENV\fR,\f(CWMATHREPL\fR" 10 -.IX Item "MATHENV,MATHREPL" -If both \ebegin and \eend for a math environment (environment name matching \f(CW\*(C`MATHENV\*(C'\fR -or \e[ and \e]) -are within the same deleted block, they are replaced by a \ebegin and \eend commands for \f(CW\*(C`MATHREPL\*(C'\fR -rather than being commented out. -.Sp -[ Default: \f(CW\*(C`MATHENV\*(C'\fR=\f(CW\*(C`(?:displaymath|equation)\*(C'\fR\ , \f(CW\*(C`MATHREPL\*(C'\fR=\f(CW\*(C`displaymath\*(C'\fR\ ] -.ie n .IP """MATHARRENV"",""MATHARRREPL""" 10 -.el .IP "\f(CWMATHARRENV\fR,\f(CWMATHARRREPL\fR" 10 -.IX Item "MATHARRENV,MATHARRREPL" -as \f(CW\*(C`MATHENV\*(C'\fR,\f(CW\*(C`MATHREPL\*(C'\fR but for equation arrays -.Sp -[ Default: \f(CW\*(C`MATHARRENV\*(C'\fR=\f(CW\*(C`eqnarray\e*?\*(C'\fR\ , \f(CW\*(C`MATHREPL\*(C'\fR=\f(CW\*(C`eqnarray\*(C'\fR\ ] -.ie n .IP """ARRENV""" 10 -.el .IP "\f(CWARRENV\fR" 10 -.IX Item "ARRENV" -If a match to \f(CW\*(C`ARRENV\*(C'\fR is found within an inline math environment within a deleted or added block, then the inlined math -is surrounded by \f(CW\*(C`\embox{\*(C'\fR...\f(CW\*(C`}\*(C'\fR. This is necessary as underlining does not work within inlined array environments. -.Sp -[ Default: \f(CW\*(C`ARRENV\*(C'\fR=\f(CW\*(C`(?:array|[pbvBV]matrix)\*(C'\fR\ -.ie n .IP """COUNTERCMD""" 10 -.el .IP "\f(CWCOUNTERCMD\fR" 10 -.IX Item "COUNTERCMD" -If a command in a deleted block which is also in the textcmd list matches \f(CW\*(C`COUNTERCMD\*(C'\fR then an -additional command \f(CW\*(C`\eaddtocounter{\*(C'\fR\fIcntcmd\fR\f(CW\*(C`}{\-1}\*(C'\fR, where \fIcntcmd\fR is the matching command, is appended in the diff file such that the numbering in the diff file remains synchronized with the -numbering in the new file. -.Sp -[ Default: \f(CW\*(C`COUNTERCMD\*(C'\fR=\f(CW\*(C`(?:footnote|part|section|subsection\*(C'\fR ... -.Sp -\&\f(CW\*(C`|subsubsection|paragraph|subparagraph)\*(C'\fR ] -.SH "COMMON PROBLEMS" -.IX Header "COMMON PROBLEMS" -.IP "Citations result in overfull boxes" 10 -.IX Item "Citations result in overfull boxes" -There is an incompatibility between the \f(CW\*(C`ulem\*(C'\fR package, which \f(CW\*(C`latexdiff\*(C'\fR uses for underlining and striking out in the \s-1UNDERLINE\s0 style, -the default style. In order to be able to mark up citations properly, they are placed with an \f(CW\*(C`\embox\*(C'\fR command in post-processing. As mboxes -cannot be broken across lines, this procedure frequently results in overfull boxes, possibly obscuring the content as it extends beyond the right margin. If this is a problem, you have two possibilities: -.Sp -1. Use \f(CW\*(C`COLOR\*(C'\fR or \f(CW\*(C`DVIPSCOL\*(C'\fR subtype markup (option \f(CW\*(C`\-s COLOR\*(C'\fR): If this markup is chosen, then changed citations are no longer marked up -with the wavy line (additions) or struck out (deletions), but are still highlighted in the appropriate color. -.Sp -2. Choose option \f(CW\*(C`\-\-disable\-citation\-markup\*(C'\fR which turns off the marking up of citations: deleted citations are no longer shown, and -added ctations are shown without markup. (This was the default behaviour of latexdiff at versions 0.6 and older) -.IP "Changes in complicated mathematical equations result in latex processing errors" 10 -.IX Item "Changes in complicated mathematical equations result in latex processing errors" -Try options \f(CW\*(C`\-\-math\-markup=whole\*(C'\fR. If even that fails, you can turn off mark up for equations with \f(CW\*(C`\-\-math\-markup=off\*(C'\fR. -.SH "BUGS" -.IX Header "BUGS" -Option allow-spaces not implemented entirely consistently. It breaks -the rules that number and type of white space does not matter, as -different numbers of inter-argument spaces are treated as significant. -.PP -Please submit bug reports on the latexdiff project page \fIhttp://latexdiff.berlios.de\fR, -send them to user discussion list \f(CW\*(C`latexdiff\-users@lists.berlios,de\*(C'\fR (prior subscription -to list required, also on project webpage) -or send them to \fItilmann@gfz\-potsdam.de\fR. Include the serial number of \fIlatexdiff\fR -(from comments at the top of the source or use \fB\-\-version\fR). If you come across latex -files that are error-free and conform to the specifications set out -above, and whose differencing still does not result in error-free -latex, please send me those files, ideally edited to only contain the -offending passage as long as that still reproduces the problem. If your -file relies on non-standard class files, you must include those. I will not -look at examples where I have trouble to latex the original files. -.SH "SEE ALSO" -.IX Header "SEE ALSO" -latexrevise, latexdiff-vc -.SH "PORTABILITY" -.IX Header "PORTABILITY" -\&\fIlatexdiff\fR does not make use of external commands and thus should run -on any platform supporting Perl 5.6 or higher. If files with encodings -other than \s-1ASCII\s0 or \s-1UTF\-8\s0 are processed, Perl 5.8 or higher is required. -.PP -The standard version of \fIlatexdiff\fR requires installation of the Perl package -\&\f(CW\*(C`Algorithm::Diff\*(C'\fR (available from \fIwww.cpan.org\fR \- -\&\fIhttp://search.cpan.org/~nedkonz/Algorithm\-Diff\-1.15\fR) but a stand-alone -version, \fIlatexdiff-so\fR, which has this package inlined, is available, too. -\&\fIlatexdiff-fast\fR requires the \fIdiff\fR command to be present. -.SH "AUTHOR" -.IX Header "AUTHOR" -Version 1.0.2 -Copyright (C) 2004\-2012 Frederik Tilmann -.PP -This program is free software; you can redistribute it and/or modify -it under the terms of the \s-1GNU\s0 General Public License Version 3 -.PP -Contributors of fixes and additions: V. Kuhlmann, J. Paisley, N. Becker, T. Doerges, K. Huebner, -T. Connors, Sebastian Gouezel and many others. -Thanks to the many people who send in bug reports, feature suggestions, and other feedback. -.SH "POD ERRORS" -.IX Header "POD ERRORS" -Hey! \fBThe above document had some coding errors, which are explained below:\fR -.IP "Around line 2942:" 4 -.IX Item "Around line 2942:" -=over should be: '=over' or '=over positive_number' -.Sp -You can't have =items (as at line 2948) unless the first thing after the =over is an =item diff --git a/latexdiff-1.0.2/latexrevise b/latexdiff-1.0.2/latexrevise deleted file mode 100755 index 0f333fb..0000000 --- a/latexdiff-1.0.2/latexrevise +++ /dev/null @@ -1,539 +0,0 @@ -#!/usr/bin/env perl -# latexrevise - takes output file of latexdiff and removes either discarded -# or appended passages, then deletes all other latexdiff markup -# -# Copyright (C) 2004 F J Tilmann (tilmann@gfz-potsdam.de, ftilmann@users.berlios.de) -# -# Project webpages: http://latexdiff.berlios.de/ -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# Note: version number now keeping up with latexdiff -# Version 1.0.2 Option --version -# Version 1.0.1 no changes to latexrevise -# Version 0.3 Updated for compatibility with latexdiff 0.3 output (DIFAUXCMD removal) -# Version 0.1 First public release - -use Getopt::Long ; -use strict; -use warnings; - -my $versionstring=< \$accept, - 'decline|d'=> \$decline, - 'simplify|s' => \$simplify, - 'comment|c=s' => \$comment, - 'comment-environment|e=s' => \$comenv, - 'markup|m=s' => \$markup, - 'markup-environment|n=s' => \$markenv, - 'no-warnings|q' => \$verbose, - 'version' => \$version, - 'verbose|V' => \$verbose, - 'help|h|H' => \$help); - -if ( $help ) { - usage() ; -} - -if ( $version ) { - die $versionstring ; -} - - -if ( ($accept && $decline) || ($accept && $simplify) || ($decline && $simplify) ) { - die '-a,-d and -s options are mutually axclusive. Type latexrevise -h to get more help.'; -} - - - -print STDERR "ACCEPT mode\n" if $verbose && $accept; -print STDERR "DECLINE mode\n" if $verbose && $decline; -print STDERR "SIMPLIFY mode. WARNING: The output will not normally be valid latex,\n" if $verbose && $simplify; - -# Slurp old and new files -{ - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $input=<>; -} - -# split into parts -($preamble,$body,$post)=splitdoc($input,'\begin{document}','\end{document}'); - -if (length $preamble && ( $accept || $decline ) ) { - # - # WORK ON PREAMBLE - # - # (compare subroutine linediff in latexdiff to make sure correct strings are used) - - # remove extra commands added to preamble by latexdiff - $preamble =~ s/${PREAMBLEXTBEG}.*?${PREAMBLEXTEND}\n{0,1}//smg ; - - if ( $accept ) { - # delete mark up in appended lines - $preamble =~ s/^(.*) %DIF > $/$1/mg ; - } elsif ( $decline ) { - # delete appended lines - # $preamble =~ s/^(.*) %DIF > $//mg ; - $preamble =~ s/^(.*) %DIF > \n//mg ; - # delete markup in deleted lines - $preamble =~ s/^%DIF < //mg ; - } - # remove any remaining DIF markups - #$preamble =~ s/%DIF.*$//mg ; - $preamble =~ s/%DIF.*?\n//sg ; -} -#print $preamble ; - -# -# WORK ON BODY -# -if ($accept) { - # remove ADDMARKOPEN, ADDMARKCLOSE tokens - @matches= $body =~ m/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/sg; - checkpure(@matches); - $body =~ s/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/$1/sg; - # remove text flanked by DELMARKOPEN, DELMARKCLOSE tokens - @matches= $body =~ m/${DELMARKOPEN}(.*?)${DELMARKCLOSE}/sg; - checkpure(@matches); - $body =~ s/${DELMARKOPEN}(.*?)${DELMARKCLOSE}//sg; - # remove markup of added comments - $body =~ s/%${ADDCOMMENT}(.*?)$/%$1/mg ; - # remove deleted comments (full line) - $body =~ s/^%${DELCOMMENT}.*?\n//mg ; - # remove deleted comments (part of line) - $body =~ s/%${DELCOMMENT}.*?$//mg ; -} -elsif ( $decline) { - # remove DELMARKOPEN, DELMARKCLOSE tokens - @matches= $body =~ m/${DELMARKOPEN}(.*?)${DELMARKCLOSE}/sg; - checkpure(@matches); - $body =~ s/${DELMARKOPEN}(.*?)${DELMARKCLOSE}/$1/sg; - # remove text flanked by ADDMARKOPEN, ADDMARKCLOSE tokens - # as latexdiff algorithm keeps the formatting and white spaces - # of the new text, sometimes whitespace might be inserted or - # removed inappropriately. We try to guess whether this has - # happened - - # Mop up tokens. This must be done already now as otherwise - # detection of white-space problems does not work - $cnt = $body =~ s/${DELOPEN}($pat4)${DELCLOSE}/$1/sg; - # remove markup of deleted commands - $cnt += $body =~ s/${DELCMDOPEN}(.*?)${DELCMDCLOSE}/$1/sg ; - $cnt += $body =~ s/${DELCMDOPEN}//g ; - # remove aux commands - $cnt += $body =~ s/^.*${AUXCMD}$/${someword}/mg; $body =~ s/${someword}\n//g; - - while ( $body =~ m/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/s ) { - $prematch=$`; - $postmatch=$'; - checkpure($1); - if ( $prematch =~ /\w$/s && $postmatch =~ /^\w/ ) { - # apparently no white-space between word=>Insert white space - $body =~ s/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/ /s ; - } - elsif ( $prematch =~ /\s$/s && $postmatch =~ /^[.,;:]/ ) { - # space immediately before one of ".,:;" => remove this space - $body =~ s/\s${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}//s ; - } - else { - # do not insert or remove any extras - $body =~ s/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}//s; - } - } -# Alternative without special cases treatment -# @matches= $body =~ m/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/sg; -# checkpure(@matches); -# $body =~ s/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}//sg; - # remove markup of deleted comments - $body =~ s/%${DELCOMMENT}(.*?)$/%$1/mg ; - # remove added comments (full line) - $body =~ s/^%${ADDCOMMENT}.*?\n//mg ; - # remove added comments (part of line) - $body =~ s/%${ADDCOMMENT}.*?$//mg ; -} - -# remove any remaining tokens -if ( $accept || $decline || $simplify ) { - # first substitution command deals with special case of added paragraph - $cnt = $body =~ s/${ADDOPEN}($pat4)\n${ADDCLOSE}\n/$1\n/sg; - $cnt += $body =~ s/${ADDOPEN}($pat4)${ADDCLOSE}/$1/sg; - $cnt==0 || warn 'Remaining $ADDOPEN tokens in DECLINE mode\n' unless ( $quiet || $accept || $simplify ); -} -if ($accept || $simplify ) { - # Note: in decline mode these commands have already been removed above - $cnt = $body =~ s/${DELOPEN}($pat4)${DELCLOSE}/$1/sg; - #### remove markup of deleted commands - $cnt += $body =~ s/${DELCMDOPEN}(.*?)${DELCMDCLOSE}/$1/sg ; - $cnt += $body =~ s/${DELCMDOPEN}//g ; - # remove aux commands - # $cnt += - $body =~ s/^.*${AUXCMD}$/${someword}/mg; $body =~ s/${someword}\n//g; - - #### remove deleted comments - ###$cnt += $body =~ s/${DIFDELCMD}.*?$//mg ; - $cnt==0 || warn 'Remaining $DELOPEN or $DIFDELCMD tokens in ACCEPT mode\n' unless ( $quiet || $simplify ); -} - -# Remove comment commands -if (defined($comment)) { - print STDERR "Removing \\$comment\{..\} sequences ..." if $verbose; - # protect $comments in comments by making them look different - $body =~ s/(%.*)${comment}(.*)$/$1${someword}$2/mg ; - # carry out the substitution - $cnt = 0 + $body =~ s/\\${comment}(?:\[${brat0}\])?\{${pat4}\}//sg ; - print STDERR "$cnt matches found and removed.\n" if $verbose; - # and undo the protection substitution - $body =~ s/(%.*)${someword}(.*)$/$1${comment}$2/mg ; -} -if (defined($comenv)) { - print STDERR "Removing $comenv environments ..." if $verbose; - $body =~ s/(%.*)${comenv}/$1${someword}/mg ; -## $cnt = 0 + $body =~ s/\\begin(?:\[${brat0}\])?\{\$comenv\}.*?\\end\{\$comenv\}//sg ; - $cnt = 0 + $body =~ s/\\begin(?:\[${brat0}\])?\{${comenv}\}.*?\\end\{${comenv}\}\s*?\n//sg ; - print STDERR "$cnt matches found and removed.\n" if $verbose; - $body =~ s/(%.*)${someword}/$1${comenv}/mg ; -} - -if (defined($markup)) { - print STDERR "Removing \\$markup\{..\} cpmmands ..." if $verbose; - # protect $markups in comments by making them look different - $body =~ s/(%.*)${markup}(.*)$/$1${someword}$2/mg ; - # carry out the substitution - $cnt = 0 + $body =~ s/\\${markup}(?:\[${brat0}\])?\{(${pat4})\}/$1/sg ; - print STDERR "$cnt matches found and removed.\n" if $verbose; - # and undo the protection substitution - $body =~ s/(%.*)${someword}(.*)$/$1${markup}$2/mg ; -} -if (defined($markenv)) { - print STDERR "Removing $markenv environments ..." if $verbose; - $body =~ s/(%.*)${markenv}/$1${someword}/mg ; - $cnt = 0 + $body =~ s/\\begin(?:\[${brat0}\])?\{${markenv}\}\n?//sg; - $cnt += 0 + $body =~ s/\\end\{${markenv}\}\n?//sg; - print STDERR $cnt/2, " matches found and removed.\n" if $verbose; - $body =~ s/(%.*)${someword}/$1${markenv}/mg ; -} - - -if ( length $preamble ) { - print "$preamble\\begin{document}${body}\\end{document}$post"; -} else { - print $body; -} - -# checkpure(@matches) -# checks whether any of the strings in matches contains -# $ADDMARKOPEN, $ADDMARKCLOSE,$DELMARKOPEN, or $DELMARKCLOSE -# If so, die reporting nesting problems, otherwise return to caller -sub checkpure { - while (defined($_=shift)) { - if ( /$ADDMARKOPEN/ || /$ADDMARKCLOSE/ - || /$DELMARKOPEN/ || /$DELMARKCLOSE/ ) { - die <=0 && $j>$i ) { - $part1 = substr($text,0,$i) ; - $part2 = substr($text,$i+$l1,$j-$i-$l1); - $part3 = substr($text,$j+$l2) unless $j+$l2 >= length $text; - } else { - die "$word1 or $word2 not in the correct order or not present as a pair." - } - return ($part1,$part2,$part3); -} - - - -sub usage { - die <<"EOF"; -Usage: $0 [OPTIONS] [diff.tex] > revised.tex - -Read a file diff.tex (output of latexdiff), and remove its markup. -If no filename is given read from standard input. The command can be used -in ACCEPT, DECLINE, or SIMPLIFY mode, and be used to remove user-defined -latex commands from the input (see options -c, -e, -m, -n below). -In ACCEPT mode, all appended text fragments (or preamble lines) -are kept, and all discarded text fragments (or preamble lines) are -deleted. -In DECLINE mode, all discarded text fragments are kept, and all appended -text fragments are deleted. -If you wish to keep some changes, edit the diff.tex file in -advance, and manually remove those tokens which would otherwise be -deleted. Note that latexrevise only pays attention to the \\DIFaddbegin, -\\DIFaddend, \\DIFdelbegin, and \\DIFdelend tokens and corresponding FL -varieties. All \\DIFadd and \\DIFdel commands (but not their content) are -simply deleted. The commands added by latexdiff to the preamble are also -removed. -In SIMPLIFY mode all latexdiff markup is removed from the body of the text (after -\\begin{document}) except for \\DIFaddbegin, \\DIFaddend, \\DIFdelbegin, \\DIFdelend -tokens and the corresponding FL varieties of those commands. The result -will not in general be valid latex-code but might be easier to read and edit in -preparation for a subsequent run in ACCEPT or DECLINE mode. -In SIMPLIFY mode the preamble is left unmodified. - --a ---accept Run in ACCEPT mode (delete all blocks marked by \\DIFdelbegin - and \\DIFdelend). - --d ---decline Run in DECLINE mode (delete all blocks marked by \\DIFaddbegin - and \\DIFaddend). - --s ---simplify Run in SIMPLIFY mode (Keep all \\DIFaddbegin, \\DIFaddend, - \\DIFdelbegin, \\DIFdelend tokens, but remove all other latexdiff - markup from body. - -Note that the three mode options are mutually exclusive. If no mode option is given, -latexrevise simply removes user annotations and markup according to the following four -options. - - --c cmd ---comment=cmd Remove \\cmd{...}. cmd is supposed to mark some explicit - anotations which should be removed from the file before - release. - --e envir ---comment-environment=envir - Remove explicit annotation environments from the text, i.e. remove - \\begin{envir} - ... - \\end{envir} - blocks. - --m cmd ---markup=cmd Remove the markup command cmd but leave its argument, i.e. - turn \\cmd{abc} into abc. - --n envir ---markup-environment=envir - Similarly, remove \\begin{envir} and \\end{envir} commands, - but leave content of the environment in the text. - --q ---no-warnings Do not warn users about \\DIDadd{..} or \\DIFdel statements - which should not be there anymore - --V ---verbose Verbose output - -EOF -} - -=head1 NAME - -latexrevise - selectively remove markup and text from latexdiff output - -=head1 SYNOPSIS - -B [ B ] [ F ] > F - -=head1 DESCRIPTION - -I reads a file C (output of I), and remove the markup commands. -If no filename is given the input is read from standard input. The command can be used -in I, I, or I mode, or can be used to remove user-defined -latex commands from the input (see B<-c>, B<-e>, B<-m>, and B<-n> below). -In I mode, all appended text fragments (or preamble lines) -are kept, and all discarded text fragments (or preamble lines) are -deleted. -In I mode, all discarded text fragments are kept, and all appended -text fragments are deleted. -If you wish to keep some changes, edit the diff.tex file in -advance, and manually remove those tokens which would otherwise be -deleted. Note that I only pays attention to the C<\DIFaddbegin>, -C<\DIFaddend>, C<\DIFdelbegin>, and C<\DIFdelend> tokens and corresponding FL -varieties. All C<\DIFadd> and C<\DIFdel> commands (but not their contents) are -simply deleted. The commands added by latexdiff to the preamble are also -removed. -In I mode, C<\DIFaddbegin, \DIFaddend, \DIFdelbegin, \DIFdelend> -tokens and their corresponding C varieties are kept but all other markup (e.g. C and <\DIFdel>) is removed. The result -will not in general be valid latex-code but it will be easier to read and edit in -preparation for a subsequent run in I or I mode. -In I mode the preamble is left unmodified. - -=head1 OPTIONS - -=over 4 - -=item B<-a> or B<--accept> - -Run in I mode (delete all blocks marked by C<\DIFdelbegin> and C<\DIFdelend>). - -=item B<-d> or B<--decline> - -Run in I mode (delete all blocks marked by C<\DIFaddbegin> -and C<\DIFaddend>). - -=item B<-s> or B<--simplify> - -Run in I mode (Keep all C<\DIFaddbegin>, C<\DIFaddend>, -C<\DIFdelbegin>, C<\DIFdelend> tokens, but remove all other latexdiff -markup from body). - -=back - -Note that the three mode options are mutually exclusive. If no mode option is given, -I simply removes user annotations and markup according to the following four -options. - -=over 4 - -=item B<-c cmd> or B<--comment=cmd> - -Remove C<\cmd{...}> sequences. C is supposed to mark some explicit -anotations which should be removed from the file before -release. - -=item B<-e envir> or B<--comment-environment=envir> - -Remove explicit annotation environments from the text, i.e. remove - - \begin{envir} - ... - \end{envir} - -blocks. - -=item B<-m cmd> or B<--markup=cmd> - -Remove the markup command C<\cmd> but leave its argument, i.e. -turn C<\cmd{abc}> into C. - -=item B<-n envir> or B<--markup-environment=envir> - -Similarly, remove C<\begin{envir}> and C<\end{envir}> commands but -leave content of the environment in the text. - - -=item B<-V> or B<--verbose> - -Verbose output - -=item B<-q> or B<--no-warnings> - -Do not warn users about C<\DIDadd{..}> or C<\DIFdel{..}> statements -which should have been removed already. - -=back - -=head1 BUGS - -The current version is a beta version which has not yet been -extensively tested, but worked fine locally. Please submit bug reports through -the latexdiff project page I or send -to I. Include the serial number of I -(from comments at the top of the source). If you come across latexdiff -output which is not processed correctly by I please include the -problem file as well as the old and new files on which it is based, -ideally edited to only contain the offending passage as long as that still -reproduces the problem. - -Note that I gets confused by commented C<\begin{document}> or -C<\end{document}> statements - -=head1 SEE ALSO - -L - -=head1 PORTABILITY - -I does not make use of external commands and thus should run -on any platform supporting PERL v5 or higher. - -=head1 AUTHOR - -Copyright (C) 2004 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 - -=cut diff --git a/latexdiff-1.0.2/latexrevise.1 b/latexdiff-1.0.2/latexrevise.1 deleted file mode 100644 index b8d0d2d..0000000 --- a/latexdiff-1.0.2/latexrevise.1 +++ /dev/null @@ -1,235 +0,0 @@ -.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` "" -. ds C' "" -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.ie \nF \{\ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. nr % 0 -. rr F -.\} -.el \{\ -. de IX -.. -.\} -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "LATEXREVISE 1" -.TH LATEXREVISE 1 "2012-12-16" "perl v5.12.4" " " -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -latexrevise \- selectively remove markup and text from latexdiff output -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBlatexrevise\fR [ \fB\s-1OPTIONS\s0\fR ] [ \fIdiff.tex\fR ] > \fIrevised.tex\fR -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -\&\fIlatexrevise\fR reads a file \f(CW\*(C`diff.tex\*(C'\fR (output of \fIlatexdiff\fR), and remove the markup commands. -If no filename is given the input is read from standard input. The command can be used -in \fI\s-1ACCEPT\s0\fR, \fI\s-1DECLINE\s0\fR, or \fI\s-1SIMPLIFY\s0\fR mode, or can be used to remove user-defined -latex commands from the input (see \fB\-c\fR, \fB\-e\fR, \fB\-m\fR, and \fB\-n\fR below). -In \fI\s-1ACCEPT\s0\fR mode, all appended text fragments (or preamble lines) -are kept, and all discarded text fragments (or preamble lines) are -deleted. -In \fI\s-1DECLINE\s0\fR mode, all discarded text fragments are kept, and all appended -text fragments are deleted. -If you wish to keep some changes, edit the diff.tex file in -advance, and manually remove those tokens which would otherwise be -deleted. Note that \fIlatexrevise\fR only pays attention to the \f(CW\*(C`\eDIFaddbegin\*(C'\fR, -\&\f(CW\*(C`\eDIFaddend\*(C'\fR, \f(CW\*(C`\eDIFdelbegin\*(C'\fR, and \f(CW\*(C`\eDIFdelend\*(C'\fR tokens and corresponding \s-1FL\s0 -varieties. All \f(CW\*(C`\eDIFadd\*(C'\fR and \f(CW\*(C`\eDIFdel\*(C'\fR commands (but not their contents) are -simply deleted. The commands added by latexdiff to the preamble are also -removed. -In \fI\s-1SIMPLIFY\s0\fR mode, \f(CW\*(C`\eDIFaddbegin, \eDIFaddend, \eDIFdelbegin, \eDIFdelend\*(C'\fR -tokens and their corresponding \f(CW\*(C`FL\*(C'\fR varieties are kept but all other markup (e.g. \f(CW\*(C`DIFadd\*(C'\fR and <\eDIFdel>) is removed. The result -will not in general be valid latex-code but it will be easier to read and edit in -preparation for a subsequent run in \fI\s-1ACCEPT\s0\fR or \fI\s-1DECLINE\s0\fR mode. -In \fI\s-1SIMPLIFY\s0\fR mode the preamble is left unmodified. -.SH "OPTIONS" -.IX Header "OPTIONS" -.IP "\fB\-a\fR or \fB\-\-accept\fR" 4 -.IX Item "-a or --accept" -Run in \fI\s-1ACCEPT\s0\fR mode (delete all blocks marked by \f(CW\*(C`\eDIFdelbegin\*(C'\fR and \f(CW\*(C`\eDIFdelend\*(C'\fR). -.IP "\fB\-d\fR or \fB\-\-decline\fR" 4 -.IX Item "-d or --decline" -Run in \fI\s-1DECLINE\s0\fR mode (delete all blocks marked by \f(CW\*(C`\eDIFaddbegin\*(C'\fR -and \f(CW\*(C`\eDIFaddend\*(C'\fR). -.IP "\fB\-s\fR or \fB\-\-simplify\fR" 4 -.IX Item "-s or --simplify" -Run in \fI\s-1SIMPLIFY\s0\fR mode (Keep all \f(CW\*(C`\eDIFaddbegin\*(C'\fR, \f(CW\*(C`\eDIFaddend\*(C'\fR, -\&\f(CW\*(C`\eDIFdelbegin\*(C'\fR, \f(CW\*(C`\eDIFdelend\*(C'\fR tokens, but remove all other latexdiff -markup from body). -.PP -Note that the three mode options are mutually exclusive. If no mode option is given, -\&\fIlatexrevise\fR simply removes user annotations and markup according to the following four -options. -.IP "\fB\-c cmd\fR or \fB\-\-comment=cmd\fR" 4 -.IX Item "-c cmd or --comment=cmd" -Remove \f(CW\*(C`\ecmd{...}\*(C'\fR sequences. \f(CW\*(C`cmd\*(C'\fR is supposed to mark some explicit -anotations which should be removed from the file before -release. -.IP "\fB\-e envir\fR or \fB\-\-comment\-environment=envir\fR" 4 -.IX Item "-e envir or --comment-environment=envir" -Remove explicit annotation environments from the text, i.e. remove -.Sp -.Vb 3 -\& \ebegin{envir} -\& ... -\& \eend{envir} -.Ve -.Sp -blocks. -.IP "\fB\-m cmd\fR or \fB\-\-markup=cmd\fR" 4 -.IX Item "-m cmd or --markup=cmd" -Remove the markup command \f(CW\*(C`\ecmd\*(C'\fR but leave its argument, i.e. -turn \f(CW\*(C`\ecmd{abc}\*(C'\fR into \f(CW\*(C`abc\*(C'\fR. -.IP "\fB\-n envir\fR or \fB\-\-markup\-environment=envir\fR" 4 -.IX Item "-n envir or --markup-environment=envir" -Similarly, remove \f(CW\*(C`\ebegin{envir}\*(C'\fR and \f(CW\*(C`\eend{envir}\*(C'\fR commands but -leave content of the environment in the text. -.IP "\fB\-V\fR or \fB\-\-verbose\fR" 4 -.IX Item "-V or --verbose" -Verbose output -.IP "\fB\-q\fR or \fB\-\-no\-warnings\fR" 4 -.IX Item "-q or --no-warnings" -Do not warn users about \f(CW\*(C`\eDIDadd{..}\*(C'\fR or \f(CW\*(C`\eDIFdel{..}\*(C'\fR statements -which should have been removed already. -.SH "BUGS" -.IX Header "BUGS" -The current version is a beta version which has not yet been -extensively tested, but worked fine locally. Please submit bug reports through -the latexdiff project page \fIhttp://developer.berlios.de/projects/latexdiff/\fR or send -to \fItilmann@gfz\-potsdam.de\fR. Include the serial number of \fIlatexrevise\fR -(from comments at the top of the source). If you come across latexdiff -output which is not processed correctly by \fIlatexrevise\fR please include the -problem file as well as the old and new files on which it is based, -ideally edited to only contain the offending passage as long as that still -reproduces the problem. -.PP -Note that \fIlatexrevise\fR gets confused by commented \f(CW\*(C`\ebegin{document}\*(C'\fR or -\&\f(CW\*(C`\eend{document}\*(C'\fR statements -.SH "SEE ALSO" -.IX Header "SEE ALSO" -latexdiff -.SH "PORTABILITY" -.IX Header "PORTABILITY" -\&\fIlatexrevise\fR does not make use of external commands and thus should run -on any platform supporting \s-1PERL\s0 v5 or higher. -.SH "AUTHOR" -.IX Header "AUTHOR" -Copyright (C) 2004 Frederik Tilmann -.PP -This program is free software; you can redistribute it and/or modify -it under the terms of the \s-1GNU\s0 General Public License Version 3 diff --git a/latexdiff-1.0.3/COPYING b/latexdiff-1.0.3/COPYING deleted file mode 100644 index d6fa915..0000000 --- a/latexdiff-1.0.3/COPYING +++ /dev/null @@ -1,623 +0,0 @@ - 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 - - diff --git a/latexdiff-1.0.3/README b/latexdiff-1.0.3/README deleted file mode 100644 index 7c7ff86..0000000 --- a/latexdiff-1.0.3/README +++ /dev/null @@ -1,107 +0,0 @@ -INTRODUCTION - -latexdiff is a Perl script, which compares two latex files and marks -up significant differences between them (i.e. a diff for latex files). - Various options are available for visual markup using standard latex -packages such as "color.sty". Changes not directly affecting visible -text, for example in formatting commands, are still marked in -the latex source. - -A rudimentary revision facilility is provided by another Perl script, -latexrevise, which accepts or rejects all changes. Manual -editing of the difference file can be used to override this default -behaviour and accept or reject selected changes only. - -The author is F Tilmann (ftilmann@users.berlios.de). - -Project webpage: http://latexdiff.berlios.de/ -CTAN page: http://www.ctan.org/tex-archive/support/latexdiff - - -REQUIREMENTS - -Perl 5.8 or higher must be installed. - The latexdiff script makes use of the Perl package Algorithm::Diff (available -from www.cpan.org, current version 1.19). You can either install this package, or -use the standalone version of latexdiff, latexdiff-so, which has version 1.15 of -this package inlined and does not require external installation of -the package. Because latexdiff uses internal functions of Algorithm:Diff whose -calling format or availability can change without notice, the preferred method is -now to use the standalone version. - -As an alternative, latexdiff-fast has a modified version of Algorithm::Diff inlined, -which internally uses the UNIX diff command. This version is much faster but is dependent -on an external "diff" command. Subtle differences in the algorithm of Algorithm::Diff and -UNIX-diff mean that the resulting set of differences will generally not be the same as -for the standard latexdiff. In most practical cases, these differences are minor, though. - -INSTALLATION UNIX/LINUX - -The basic installation procedure is almost trivial: - -1. Copy latexdiff, latexrevise and latexdiff-vc into a directory which - is in the search path and make them executable. If the Algorithm::Diff - package is not installed, use latexdiff-so instead of latexdiff. - -2. Copy latexdiff.1 and latexrevise.1 into the correct man directory - -3. Optionally create soft links latexdiff-cvs latexdiff-rcs, and - latexdiff-svn for latexdiff-vc. - -The attached Makefile contains example commands to carry out above -steps as root for a typical UNIX installation. Type - - make install (for the stand alone version) -or - make install-ext (for the version using the external Algorithm::Diff) -or - make install-fast (for the version using the UNIX 'diff' function for fast differencing) - -to get it rolling. You can type - - make test -or - make test-ext -or - make test-fast - -to test the respective versions on a brief example before installation - - -DOCUMENTATION: - -Usage instructions are in the manual latexdiff-man.pdf as well as the -man pages. - -CHANGELOGS: - -Check out the comment lines at the beginning of the perl scripts (latexdiff, latexdiff-vc, latexrevise) - -CONTRIBUTIONS - -The directory contrib contains code written by others relating to latexdiff. -Currently this directory contains: - -latexdiff-wrap (Author: V. Kuhlmann) An alternative wrapper script which can be used - instead of latexdiff-vc. Its main use is as a template for customised wrapper scripts. - -latexdiff.spec (Author: T. Doerges) spec file for RPM generation - -latexchanges (Author: Jan-Ake Larsson) Wrapper script for applying latexdiff with numbered documen version -(see contrib/README.latexchanges for a more detailed description) - -Cntributions by the following authors were incorporated into the latexdiff code, or inspired me to -extend latexdiff in a similar way: J. Paisley, N. Becker, K. Huebner - -LICENSE (also see file COPYING) - -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 (file LICENSE in the -distribution). - diff --git a/latexdiff-1.0.3/doc/example-diff.tex b/latexdiff-1.0.3/doc/example-diff.tex deleted file mode 100644 index a476481..0000000 --- a/latexdiff-1.0.3/doc/example-diff.tex +++ /dev/null @@ -1,89 +0,0 @@ -\documentclass[12pt,a4paper]{article} -%DIF LATEXDIFF DIFFERENCE FILE -%DIF DEL example-draft.tex Sun Jan 27 23:50:07 2013 -%DIF ADD example-rev.tex Sun Jan 27 23:50:07 2013 - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -%DIF 7c7 -%DIF < \setlength{\textwidth}{6.5in} -%DIF ------- -\setlength{\textwidth}{6in} %DIF > -%DIF ------- - -\title{latexdiff Example - \DIFdelbegin \DIFdel{Draft }\DIFdelend \DIFaddbegin \DIFadd{Revised }\DIFaddend version} -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even %DIF > -% if some preamble might eventually end up as visible text.) %DIF > -%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF -%DIF UNDERLINE PREAMBLE %DIF PREAMBLE -\RequirePackage[normalem]{ulem} %DIF PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} %DIF PREAMBLE -\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}} %DIF PREAMBLE -\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}} %DIF PREAMBLE -%DIF SAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddbegin}{} %DIF PREAMBLE -\providecommand{\DIFaddend}{} %DIF PREAMBLE -\providecommand{\DIFdelbegin}{} %DIF PREAMBLE -\providecommand{\DIFdelend}{} %DIF PREAMBLE -%DIF FLOATSAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} %DIF PREAMBLE -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} %DIF PREAMBLE -\providecommand{\DIFaddbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFaddendFL}{} %DIF PREAMBLE -\providecommand{\DIFdelbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFdelendFL}{} %DIF PREAMBLE -%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of \DIFaddbegin \DIFadd{the }\DIFaddend latexdiff features. -Type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -or -\begin{verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{verbatim} -to display the markup. - -\section*{\DIFdelbegin \DIFdel{Another }\DIFdelend \DIFaddbegin \DIFadd{Yet another }\DIFaddend section title} - - \DIFdelbegin \DIFdel{A paragraph with a line only in the draft document. }\DIFdelend More things could be said were it not for the constraints of time and space. - -\DIFaddbegin \DIFadd{A paragraph with a line only in the revised document. }\DIFaddend More things could be -said were it not for the constraints of time and space. - -And here is a \DIFdelbegin \DIFdel{tipo}\DIFdelend \DIFaddbegin \DIFadd{typo}\DIFaddend . - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & \DIFdelbegin \DIFdel{Grey }\DIFdelend \DIFaddbegin \DIFadd{White }\DIFaddend \\ -Saruman & \DIFdelbegin \DIFdel{White -}\DIFdelend \DIFaddbegin \DIFadd{Evil -}\DIFaddend \end{tabular} - -And \DIFdelbegin \DIFdel{sometimes a whole paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}\DIFdelend \DIFaddbegin \DIFadd{now for something completely different, with not a paragraph in sight}\DIFaddend . -No change, -no markup! -\end{document} - - diff --git a/latexdiff-1.0.3/doc/latexdiff-man.tex b/latexdiff-1.0.3/doc/latexdiff-man.tex deleted file mode 100644 index b6bb37e..0000000 --- a/latexdiff-1.0.3/doc/latexdiff-man.tex +++ /dev/null @@ -1,355 +0,0 @@ -\documentclass[a4]{article} -\usepackage{graphicx} -%\def\C++{{\rm C\kern-.05em\raise.3ex\hbox{\footnotesize ++}}} -%\def\underscore{\leavevmode\kern.04em\vbox{\hrule width 0.4em height 0.3pt}} -\setlength{\parindent}{0pt} -%\setlength{\textwidth}{6.5in} -%\setlength{\oddsidemargin}{0.0in} -\title{Marking up differences between latex files with {\em latexdiff}} -\author{F.J. Tilmann\thanks{tilmann@gfz-potsdam.de,ftilmann@users.berlios.de}} -\date{\today} - -\begin{document} -\maketitle - -\section*{Preamble} - -{\em latexdiff} is a Perl script, which compares two -latex files and marks up significant differences between them. Various options are available for visual markup using standard -latex packages such as {\em color.sty}. Changes not directly affecting visible -text, for example in formatting commands, are still marked in the -latex source. - -A rudimentary revision facilility is provided by another Perl script, -{\em latexrevise}, which accepts or rejects all changes. Manual editing -of the difference file can be used to override this default behaviour -and accept or reject selected changes only. - -There is no explicit support for annotations as these are trivial to implement. -For example, I include the following command definition in the preamble -\begin{verbatim} -\newcommand{\remark}[1]{{ \bf [ \footnotesize #1 ]}} -\end{verbatim} -and mark up annotations as follows -\begin{verbatim} -... The roadrunner is the fastest running bird \remark{Check this -again with a zoologist!}. The most famous roadrunner ... -\end{verbatim} -Alternatively, instead of a command like \verb#\remark# in the example just given, an -equivalent annotation environment could be defined. -{\em latexrevise} can remove such comments or -environments from the text body. - -%It is planned that the revision capabilities of this system will be -%further expanded, dependent on the amount of feedback received. - -On the following pages you find the {\em man} pages for {\em - latexdiff} and {\em latexrevise} and a simple example. - -\include{latexdiff} -\setcounter{section}{0} - -\include{latexrevise} -\setcounter{section}{0} - -\include{latexdiff-vc} -\setcounter{section}{0} - -\section*{A simple example} - -We start with a draft text, \verb|example-draft.tex|, listed here in -full but also included in the distribution (except that the ``verbatim'' environment had -to be renamed to ``Verbatim'' for the listing). - -{\scriptsize -\begin{verbatim} -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6.5in} - -\title{latexdiff Example - Draft version} -\author{F Tilmann} - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of latexdiff features. -Type -\begin{Verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{Verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{Verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{Verbatim} -or -\begin{Verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{Verbatim} -to display the markup. Of course, instead of \verb|xpdf| you can use -\verb|okular, evince, acroread| or any other pdf or postscript viewer. - -\section*{Another section title} - -A paragraph with a line only in the draft document. More things -could be said were it not for the constraints of time and space. - -More things could be said were it not for the constraints of time and space. - -And here is a tipo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & Grey \\ -Saruman & White -\end{tabular} - -And sometimes a whole paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical. -No change, no markup! -\end{document} -\end{verbatim} -} - -We can now edit -this text as we would do with any other latex file to create -a new revision of the text, \verb|example-rev.tex|. We should run -\begin{verbatim} -latex example-rev.tex -\end{verbatim} -and look at the resulting \verb|.dvi| file to make sure that all -changes are valid. An example revision is listed here: - -{\scriptsize -\begin{verbatim} -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6in} - -\title{latexdiff Example - Revised version} -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even -% if some preamble might eventually end up as visible text.) - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of the latexdiff features. -Type -\begin{Verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{Verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{Verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{Verbatim} -or -\begin{Verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{Verbatim} -to display the markup. - -\section*{Yet another section title} - - More things could be said were it not for the constraints of time and space. - -A paragraph with a line only in the revised document. -More things could be said were it not for the constraints of time and space. - -And here is a typo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & White \\ -Saruman & Evil -\end{tabular} - -And now for something completely different, with not a paragraph in sight. -No change, -no markup! -\end{document} -\end{verbatim} -} - -To compare both revisions, type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -This results in the following difference file (a few newlines have been -added in this listing for legibility reasosn): -{\scriptsize -\begin{verbatim} -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -%DIF 7c7 -%DIF < \setlength{\textwidth}{6.5in} -%DIF ------- -\setlength{\textwidth}{6in} %DIF > -%DIF ------- - -%DIF 9c9 -%DIF < \title{latexdiff Example - Draft version} -%DIF ------- -\title{latexdiff Example - Revised version} %DIF > -%DIF ------- -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even %DIF > -% if some preamble might eventually end up as visible text.) %DIF > -%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF -%DIF UNDERLINE PREAMBLE %DIF PREAMBLE -\RequirePackage[normalem]{ulem} %DIF PREAMBLE -\RequirePackage{color} %DIF PREAMBLE -\providecommand{\DIFadd}[1]{{\color{blue}\uline{#1}}} %DIF PREAMBLE -\providecommand{\DIFdel}[1]{{\color{red}\sout{#1}}} %DIF PREAMBLE -%DIF SAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddbegin}{} %DIF PREAMBLE -\providecommand{\DIFaddend}{} %DIF PREAMBLE -\providecommand{\DIFdelbegin}{} %DIF PREAMBLE -\providecommand{\DIFdelend}{} %DIF PREAMBLE -%DIF FLOATSAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} %DIF PREAMBLE -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} %DIF PREAMBLE -\providecommand{\DIFaddbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFaddendFL}{} %DIF PREAMBLE -\providecommand{\DIFdelbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFdelendFL}{} %DIF PREAMBLE -%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of latexdiff features. -Type -\begin{Verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{Verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{Verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{Verbatim} -or -\begin{Verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{Verbatim} -to display the markup. - -\section*{\DIFaddbegin \DIFadd{Yet another }\DIFaddend \DIFdelbegin -\DIFdel{Another }\DIFdelend section title} - - \DIFdelbegin \DIFdel{A paragraph with a line only in the draft - document. }\DIFdelend More things could - be said were it not for the constraints of time and space. - -\DIFaddbegin \DIFadd{A paragraph with a line only in the revised - document. }\DIFaddend More things could be said -were it not for the constraints of time and space. - -And here is a \DIFaddbegin \DIFadd{typo}\DIFaddend \DIFdelbegin -\DIFdel{tipo}\DIFdelend . - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & \DIFaddbegin \DIFadd{White }\DIFaddend \DIFdelbegin -\DIFdel{Grey }\DIFdelend \\ -Saruman & \DIFaddbegin \DIFadd{Evil -}\DIFaddend \DIFdelbegin \DIFdel{White -}\DIFdelend \end{tabular} - -And \DIFaddbegin \DIFadd{now for something completely different, with not - a paragraph in sight}\DIFaddend \DIFdelbegin \DIFdel{sometimes a whole - paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}\DIFdelend . -No change, -no markup! -\end{document} -\end{verbatim} -} -Type -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -to make the markup visible. This is what it looks like: - -\vspace{1cm} -\framebox[\textwidth]{\includegraphics[width=\textwidth]{example-diff}} -\vspace{1cm} - -If you approve of all the changes in the revision, just continue with -\verb|example-rev.tex| for the next revision. If you like to adopt -most but not all changes you can use \verb|latexrevise| in the -following manner. Simply remove the \verb|\DIFdelbegin| and -\verb|\DIFdelend| tags around the text you would like to keep and -simply remove the text between \verb|\DIFaddbegin| and -\verb|\DIFaddend| tags, if you do not wish to keep them. Say you are happy with all proposed changes for the -example above except in -the last paragraph where you prefer the original draft. You have -to change - -{\scriptsize -\begin{verbatim} -... -And \DIFaddbegin \DIFadd{now for something completely different, with not - a paragraph in sight}\DIFaddend \DIFdelbegin \DIFdel{sometimes a whole - paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}\DIFdelend . -... -\end{verbatim} -} -into -{\scriptsize -\begin{verbatim} -... -And \DIFdel{sometimes a whole - paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}. -... -\end{verbatim} -} -and run -\begin{verbatim} -latexrevise -a example-rev.tex > example-final.tex -\end{verbatim} -\verb|example-final.tex| is then almost identical to -\verb|example-rev.tex| except for the last paragraph. -\end{document} diff --git a/latexdiff-1.0.3/example/example-draft.tex b/latexdiff-1.0.3/example/example-draft.tex deleted file mode 100644 index 593a170..0000000 --- a/latexdiff-1.0.3/example/example-draft.tex +++ /dev/null @@ -1,59 +0,0 @@ -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6.5in} - -\title{latexdiff Example - Draft version} -\author{F Tilmann} - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of latexdiff features. -Type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -or -\begin{verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{verbatim} -to display the markup. - -\section*{Another section title} - -A paragraph with a line only in the draft document. More things could be said -were it not for the constraints of time and space. - -More things could be said were it not for the constraints of time and space. - -And here is a tipo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & Grey \\ -Saruman & White -\end{tabular} - -And sometimes a whole paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical. -No change, no markup! -\end{document} - - diff --git a/latexdiff-1.0.3/example/example-rev.tex b/latexdiff-1.0.3/example/example-rev.tex deleted file mode 100644 index 4bcaf15..0000000 --- a/latexdiff-1.0.3/example/example-rev.tex +++ /dev/null @@ -1,60 +0,0 @@ -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6in} - -\title{latexdiff Example - Revised version} -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even -% if some preamble might eventually end up as visible text.) - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of the latexdiff features. -Type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -or -\begin{verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{verbatim} -to display the markup. - -\section*{Yet another section title} - - More things could be said were it not for the constraints of time and space. - -A paragraph with a line only in the revised document. More things could be -said were it not for the constraints of time and space. - -And here is a typo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & White \\ -Saruman & Evil -\end{tabular} - -And now for something completely different, with not a paragraph in sight. -No change, -no markup! -\end{document} - - diff --git a/latexdiff-1.0.3/latexdiff b/latexdiff-1.0.3/latexdiff deleted file mode 100755 index febae2d..0000000 --- a/latexdiff-1.0.3/latexdiff +++ /dev/null @@ -1,3415 +0,0 @@ -#!/usr/bin/env perl -##!/usr/bin/perl -w -# latexdiff - differences two latex files on the word level -# and produces a latex file with the differences marked up. -# -# Copyright (C) 2004-12 F J Tilmann (tilmann@gfz-potsdam.de, ftilmann@users.berlios.de) -# -# Project webpages: http://latexdiff.berlios.de/ -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# -# Version 1.0.3 -# - fix bug in add_safe_commands that made latexdiff hang on DeclareMathOperator -# command in preamble -# - \(..\) inline math expressions were not parsed correctly, if the contained a linebreak -# - applied patch contributed by tomflannaghan via Berlios: [ Patch #3431 ] Adds correct handling of \left< and \right> -# - \$ is treated correctly as a literal dollar sign (thanks to Reed Cartwright and Joshua Miller for reporting this bug -# and sketching out the solution) -# - \^ and \_ are correctly interpreted as accent and underlined space, respectively, not as superscript of subscript (thanks to Wail Yahyaoui for pointing out this bug) -# -# Version 1.0.1 - treat \big,\bigg etc. equivalently to \left and -# \right - include starred version in MATHENV - apply -# - flatten recursively and --flatten expansion is now -# aware of comments (thanks to Tim Connors for patch) -# - Change to post-processing for more reliability for -# deleted math environments -# - On linux systems, recognise and remove DOS style newlines -# - Provide markup for some special preamble commands (\title, -# \author,\date, -# - configurable by setting context2cmd -# - for styles using ulem package, remove \emph and \text.. from list of -# safe commands in order to allow linebreaks within the -# highlighted sections. -# - for ulem style, now show citations by enclosing them in \mbox commands. -# This unfortunately implies linebreaks within citations no longer function, -# so this functionality can be turned off (Option --disable-citation-markup). -# With --enable-citation-markup, the mbox markup is forced for other styles) -# - new substyle COLOR. This is particularly useful for marking up citations -# and some special post-processing is implemented to retain cite -# commands in deleted blocks. -# - four different levels of math-markup -# - Option --driver for choosing driver for modes employing changebar package -# - accept \\* as valid command (and other commands of form \.*). Also accept -# \ (backslashed newline) -# - some typo fixes, include commands defined in preamble as safe commands -# (Sebastian Gouezel) -# - include compared filenames as comments as line 2 and 3 of -# the preamble (can be modified with option --label, and suppressed with -# --no-label), option --visible-label to show files in generated pdf or dvi -# at the beginning of main document -# -# Version 0.5 A number of minor improvements based on feedback -# Deleted blocks are now shown before added blocks -# Package specific processing -# -# Version 0.43 unreleased typo in list of styles at the end -# Add protect to all \cbstart, \cbend commands -# More robust substitution of deleted math commands -# -# Version 0.42 November 06 Bug fixes only -# -# Version 0.4 March 06 option for fast differencing using UNIX diff command, several minor bug fixes (\par bug, improved highlighting of textcmds) -# -# Version 0.3 August 05 improved parsing of displayed math, --allow-spaces -# option, several minor bug fixes -# -# Version 0.25 October 04 Fix bug with deleted equations, add math mode commands to safecmd, add | to allowed interpunctuation signs -# Version 0.2 September 04 extension to utf-8 and variable encodings -# Version 0.1 August 04 First public release - -use Algorithm::Diff qw(traverse_sequences); - -use Getopt::Long ; -use strict ; -use warnings; -use utf8 ; - -my ($algodiffversion)=split(/ /,$Algorithm::Diff::VERSION); - - -my ($versionstring)=< 0, - WHOLE => 1, - COARSE => 2, - FINE => 3 -}; - - -my (@configlist,@labels, - @appendsafelist,@excludesafelist, - @appendtextlist,@excludetextlist, - @appendcontext1list,@appendcontext2list, - @packagelist); -my ($assign,@config); -# Hash where keys corresponds to the names of all included packages (including the documentclass as another package -# the optional arguments to the package are the values of the hash elements -my ($pkg,%packages); -# Defaults -$type='UNDERLINE'; -$subtype='SAFE'; -$floattype='FLOATSAFE'; -$mathmarkup=COARSE; - -$verbose=0; -# output debug and intermediate files, set to 0 in final distribution -$debug=0; -# define character properties -sub IsNonAsciiPunct { return <<'END' # Unicode punctuation but excluding ASCII punctuation -+utf8::IsPunct --utf8::IsASCII -END -} -sub IsNonAsciiS { return <<'END' # Unicode symbol but excluding ASCII -+utf8::IsS --utf8::IsASCII -END -} - - -my %verbhash; - -Getopt::Long::Configure('bundling'); -GetOptions('type|t=s' => \$type, - 'subtype|s=s' => \$subtype, - 'floattype|f=s' => \$floattype, - 'config|c=s' => \@configlist, - 'preamble|p=s' => \$preamblefile, - 'encoding|e=s' => \$encoding, - 'label|L=s' => \@labels, - 'no-label' => \$nolabel, - 'visible-label' => \$visiblelabel, - 'exclude-safecmd|A=s' => \@excludesafelist, - 'replace-safecmd=s' => \$replacesafe, - 'append-safecmd|a=s' => \@appendsafelist, - 'exclude-textcmd|X=s' => \@excludetextlist, - 'replace-textcmd=s' => \$replacetext, - 'append-textcmd|x=s' => \@appendtextlist, - 'replace-context1cmd=s' => \$replacecontext1, - 'append-context1cmd=s' => \@appendcontext1list, - 'replace-context2cmd=s' => \$replacecontext2, - 'append-context2cmd=s' => \@appendcontext2list, - 'show-preamble' => \$showpreamble, - 'show-safecmd' => \$showsafe, - 'show-textcmd' => \$showtext, - 'show-config' => \$showconfig, - 'show-all' => \$showall, - 'packages=s' => \@packagelist, - 'allow-spaces' => \$allowspaces, - 'math-markup=s' => \$mathmarkup, - 'enable-citation-markup' => \$enablecitmark, - 'disable-citation-markup' => \$disablecitmark, - 'verbose|V' => \$verbose, - 'ignore-warnings' => \$ignorewarnings, - 'driver=s'=> \$driver, - 'flatten' => \$flatten, - 'version' => \$version, - 'help|h|H' => \$help); - -if ( $help ) { - usage() ; -} - - -if ( $version ) { - die $versionstring ; -} - -print STDERR $versionstring if $verbose; - -if (defined($showall)){ - $showpreamble=$showsafe=$showtext=$showconfig=1; -} - -if (defined($mathmarkup)) { - $mathmarkup=~tr/a-z/A-Z/; - if ( $mathmarkup eq 'OFF' ){ - $mathmarkup=OFF; - } elsif ( $mathmarkup eq 'WHOLE' ){ - $mathmarkup=WHOLE; - } elsif ( $mathmarkup eq 'COARSE' ){ - $mathmarkup=COARSE; - } elsif ( $mathmarkup eq 'FINE' ){ - $mathmarkup=FINE; - } elsif ( $mathmarkup !~ m/^[0123]$/ ) { - die "Illegal value: ($mathmarkup) for option--math-markup. Possible values: OFF,WHOLE,COARSE,FINE,0- "; - } - # else use numerical value -} - -# setting extra preamble commands -if (defined($preamblefile)) { - $latexdiffpreamble=join "\n",(extrapream($preamblefile),""); -} else { - $latexdiffpreamble=join "\n",(extrapream($type,$subtype,$floattype),""); -} - -if ( defined($driver) ) { - # for changebar only - $latexdiffpreamble=~s/\[dvips\]/[$driver]/sg; -} -# setting up @SAFECMDLIST and @SAFECMDEXCL -if (defined($replacesafe)) { - init_regex_arr_ext(\@SAFECMDLIST,$replacesafe); -} else { - init_regex_arr_data(\@SAFECMDLIST, "SAFE COMMANDS"); -} -foreach $appendsafe ( @appendsafelist ) { - init_regex_arr_ext(\@SAFECMDLIST, $appendsafe); -} -foreach $excludesafe ( @excludesafelist ) { - init_regex_arr_ext(\@SAFECMDEXCL, $excludesafe); -} - -# Special: treat all cite commands as safe except in UNDERLINE and FONTSTRIKE mode -# (there is a conflict between citation and ulem package, see -# package documentation) -# Use post-processing - -if ( uc($type) ne "UNDERLINE" && uc($type) ne "FONTSTRIKE" && uc($type) ne "CULINECHBAR" ) { - push (@SAFECMDLIST, qr/^cite.*$/); -} else { - ### Experimental: disable text and emph commands - push (@SAFECMDLIST, qr/^cite.*$/) unless $disablecitmark; - push(@SAFECMDEXCL, qr/^emph$/, qr/^text..$/); - # replace \cite{..} by \mbox{\cite{..}} in added or deleted blocks in post-processing - if ( uc($subtype) eq "COLOR" or uc($subtype) eq "DVIPSCOL" ) { - # remove \cite command again from list of safe commands - pop @SAFECMDLIST; - # deleted cite commands - $CITE2CMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite-type commands which should be reinstated in deleted blocks - } else { - $CITECMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite commands which need to be protected within an mbox in UNDERLINE and other modes using ulem - } -} -$CITECMD='(?:cite\w*|nocite)' if $enablecitmark ; # as above for explicit selection - -# setting up @TEXTCMDLIST and @TEXTCMDEXCL -if (defined($replacetext)) { - init_regex_arr_ext(\@TEXTCMDLIST,$replacetext); -} else { - init_regex_arr_data(\@TEXTCMDLIST, "TEXT COMMANDS"); -} -foreach $appendtext ( @appendtextlist ) { - init_regex_arr_ext(\@TEXTCMDLIST, $appendtext); -} -foreach $excludetext ( @excludetextlist ) { - init_regex_arr_ext(\@TEXTCMDEXCL, $excludetext); -} - - -# setting up @CONTEXT1CMDLIST ( @CONTEXT1CMDEXCL exist but is always empty ) -if (defined($replacecontext1)) { - init_regex_arr_ext(\@CONTEXT1CMDLIST,$replacecontext1); -} else { - init_regex_arr_data(\@CONTEXT1CMDLIST, "CONTEXT1 COMMANDS"); -} -foreach $appendcontext1 ( @appendcontext1list ) { - init_regex_arr_ext(\@CONTEXT1CMDLIST, $appendcontext1); -} - - -# setting up @CONTEXT2CMDLIST ( @CONTEXT2CMDEXCL exist but is always empty ) -if (defined($replacecontext2)) { - init_regex_arr_ext(\@CONTEXT2CMDLIST,$replacecontext2); -} else { - init_regex_arr_data(\@CONTEXT2CMDLIST, "CONTEXT2 COMMANDS"); -} -foreach $appendcontext2 ( @appendcontext2list ) { - init_regex_arr_ext(\@CONTEXT2CMDLIST, $appendcontext2); -} - -# setting configuration variables -@config=(); -foreach $config ( @configlist ) { - if (-f $config ) { - open(FILE,$config) or die ("Couldn't open configuration file $config: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@config,$_); - } - close(FILE); - } - else { -# foreach ( split(",",$config) ) { -# push @config,$_; -# } - push @config,split(",",$config) - } -} -foreach $assign ( @config ) { - $assign=~ m/\s*(\w*)\s*=\s*(\S*)\s*$/ or die "Illegal assignment $assign in configuration list (must be variable=value)"; - if ( $1 eq "MINWORDSBLOCK" ) { $MINWORDSBLOCK = $2; } - elsif ( $1 eq "FLOATENV" ) { $FLOATENV = $2 ; } - elsif ( $1 eq "PICTUREENV" ) { $PICTUREENV = $2 ; } - elsif ( $1 eq "MATHENV" ) { $MATHENV = $2 ; } - elsif ( $1 eq "MATHREPL" ) { $MATHREPL = $2 ; } - elsif ( $1 eq "MATHARRENV" ) { $MATHARRENV = $2 ; } - elsif ( $1 eq "MATHARRREPL" ) { $MATHARRREPL = $2 ; } - elsif ( $1 eq "ARRENV" ) { $ARRENV = $2 ; } - elsif ( $1 eq "COUNTERCMD" ) { $COUNTERCMD = $2 ; } - else { die "Unknown variable $1 in assignment.";} -} - -if ( $mathmarkup == COARSE || $mathmarkup == WHOLE ) { - push(@MATHTEXTCMDLIST,qr/^MATHBLOCK(?:$MATHENV|$MATHARRENV|SQUAREBRACKET)$/); -} - - - -foreach $pkg ( @packagelist ) { - map { $packages{$_}="" } split(/,/,$pkg) ; -} - -if ($showpreamble) { - print "\nPreamble commands:\n"; - print $latexdiffpreamble ; -} - -if ($showsafe) { - print "\nCommands safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE (unless excluded):\n"; - print_regex_arr(@SAFECMDLIST); - print "\nCommands not safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE :\n"; - print_regex_arr(@SAFECMDEXCL); -} - -if ($showtext) { - print "\nCommands with last argument textual (unless excluded) and safe in every context:\n"; - print_regex_arr(@TEXTCMDLIST); - print "\nContext1 commands (last argument textual, command will be disabled in deleted passages, last argument will be shown as plain text):\n"; - print_regex_arr(@CONTEXT1CMDLIST); - print "\nContext2 commands (last argument textual, command and its argument will be disabled in deleted passages):\n"; - print_regex_arr(@CONTEXT2CMDLIST); - print "\nExclude list of Commands with last argument not textual (overrides patterns above):\n"; - print_regex_arr(@TEXTCMDEXCL); -} - - -if ($showconfig) { - print "Configuration variables:\n"; - print "MINWORDSBLOCK=$MINWORDSBLOCK\n"; - print "FLOATENV=$FLOATENV\n"; - print "PICTUREENV=$PICTUREENV\n"; - print "MATHENV=$MATHENV\n"; - print "MATHREPL=$MATHREPL\n"; - print "MATHARRENV=$MATHARRENV\n"; - print "MATHARRREPL=$MATHARRREPL\n"; - print "ARRENV=$ARRENV\n"; - print "COUNTERCMD=$COUNTERCMD\n"; -} -if ($showconfig || $showtext || $showsafe || $showpreamble) { - exit 0; } -if ( @ARGV != 2 ) { - print STDERR "2 and only 2 non-option arguments required. Write latexdiff -h to get help\n"; - exit(2); -} - -# Are extra spaces between command arguments permissible? -my $extraspace; -if ($allowspaces) { - $extraspace='\s*'; -} else { - $extraspace=''; -} - -# append context lists to text lists (as text property is implied) -push @TEXTCMDLIST, @CONTEXT1CMDLIST; -push @TEXTCMDLIST, @CONTEXT2CMDLIST; - -push @TEXTCMDLIST, @MATHTEXTCMDLIST if $mathmarkup==COARSE; - -# internal additions to SAFECMDLIST -push(@SAFECMDLIST, qr/^QLEFTBRACE$/, qr/^QRIGHTBRACE$/); - - -# Patterns. These are used by some of the subroutines, too -# I can only define them down here because value of extraspace depends on an option - my $pat0 = '(?:[^{}])*'; - my $pat1 = '(?:[^{}]|\{'.$pat0.'\})*'; - my $pat2 = '(?:[^{}]|\{'.$pat1.'\})*'; - my $pat3 = '(?:[^{}]|\{'.$pat2.'\})*'; - my $pat4 = '(?:[^{}]|\{'.$pat3.'\})*'; - my $pat5 = '(?:[^{}]|\{'.$pat4.'\})*'; - my $pat6 = '(?:[^{}]|\{'.$pat5.'\})*'; - my $brat0 = '(?:[^\[\]]|\\\[|\\\])*'; - - my $quotemarks = '(?:\'\')|(?:\`\`)'; - my $punct='[0.,\/\'\`:;\"\?\(\)\[\]!~\p{IsNonAsciiPunct}\p{IsNonAsciiS}]'; - my $number='-?\d*\.\d*'; - my $mathpunct='[+=<>\-\|]'; - my $and = '&'; - my $coords= '[\-.,\s\d]*'; -# word: sequence of letters or accents followed by letter - my $word='(?:[-\w\d*]|\\\\[\"\'\`~^][A-Za-z\*])+'; - my $cmdleftright='\\\\(?:left|right|[Bb]igg?[lrm]?|middle)\s*(?:[<>()\[\]|]|\\\\(?:[|{}]|\w+))'; - - my $cmdoptseq='\\\\[\w\d\*]+'.$extraspace.'(?:(?:\['.$brat0.'\]|\{'. $pat6 . '\}|\(' . $coords .'\))'.$extraspace.')*'; - my $backslashnl='\\\\\n'; - my $oneletcmd='\\\\.\*?(?:\['.$brat0.'\]|\{'. $pat6 . '\})*'; - my $math='\$(?:[^$]|\\\$)*?\$|\\\\[(](?:.|\n)*?\\\\[)]'; -## the current maths command cannot cope with newline within the math expression - - my $comment='%.*?\n'; - my $pat=qr/(?:\A\s*)?(?:${and}|${quotemarks}|${number}|${word}|$cmdleftright|${cmdoptseq}|${math}|${backslashnl}|${oneletcmd}|${comment}|${punct}|${mathpunct}|\{|\})\s*/ ; - - - -# now we are done setting up and can start working -my ($oldfile, $newfile) = @ARGV; -# check for existence of input files -if ( ! -e $oldfile ) { - die "Input file $oldfile does not exist."; -} -if ( ! -e $newfile ) { - die "Input file $newfile does not exist."; -} - - -# set the labels to be included into the file -my ($oldtime,$newtime,$oldlabel,$newlabel); -if (defined($labels[0])) { - $oldlabel=$labels[0] ; -} else { - $oldtime=localtime((stat($oldfile))[9]); - $oldlabel="$oldfile " . " "x(length($newfile)-length($oldfile)) . $oldtime; -} -if (defined($labels[1])) { - $newlabel=$labels[1] ; -} else { - $newtime=localtime((stat($newfile))[9]); - $newlabel="$newfile " . " "x(length($oldfile)-length($newfile)) . $newtime; -} - -$encoding=guess_encoding($newfile) unless defined($encoding); - -$encoding = "utf8" if $encoding =~ m/^utf8/i ; -if (lc($encoding) eq "utf8" ) { - binmode(STDOUT, ":utf8"); - binmode(STDERR, ":utf8"); -} - -$old=read_file_with_encoding($oldfile,$encoding); -$new=read_file_with_encoding($newfile,$encoding); - - - - -# reset time -exetime(1); -($oldpreamble,$oldbody,$oldpost)=splitdoc($old,'\\\\begin\{document\}','\\\\end\{document\}'); - - -($newpreamble,$newbody,$newpost)=splitdoc($new,'\\\\begin\{document\}','\\\\end\{document\}'); - - -if ($flatten) { - $oldbody=flatten($oldbody,$oldpreamble,$oldfile,$encoding); - $newbody=flatten($newbody,$newpreamble,$newfile,$encoding); -} - -my @auxlines; -if ( length $oldpreamble && length $newpreamble ) { - # pre-process preamble by looking for commands used in \maketitle (title, author, date etc commands) - # and marking up content with latexdiff markup - @auxlines=preprocess_preamble($oldpreamble,$newpreamble); - - @oldpreamble = split /\n/, $oldpreamble; - @newpreamble = split /\n/, $newpreamble; - - # If a command is defined in the preamble of the new file, and only uses safe commands, then it can be considered to be safe) (contribution S. Gouezel) - # Base this assessment on the new preamble - add_safe_commands($newpreamble); - - %packages=list_packages(@newpreamble) unless %packages; - if (defined $packages{"hyperref"} ) { - print STDERR "hyperref package detected.\n" if $verbose ; - $latexdiffpreamble =~ s/\{\\DIFadd\}/{\\DIFaddtex}/g; - $latexdiffpreamble =~ s/\{\\DIFdel\}/{\\DIFdeltex}/g; - $latexdiffpreamble .= join "\n",(extrapream("HYPERREF"),""); - } - print STDERR "Differencing preamble.\n" if $verbose; - - # insert dummy first line such that line count begins with line 1 (rather than perl's line 0) - just so that line numbers inserted by linediff are correct - unshift @newpreamble,''; - unshift @oldpreamble,''; - @diffpreamble = linediff(\@oldpreamble, \@newpreamble); - # remove dummy line again - shift @diffpreamble; - # add filenames, modification time and latexdiff mark - defined($nolabel) or splice @diffpreamble,1,0, - "%DIF LATEXDIFF DIFFERENCE FILE", - ,"%DIF DEL $oldlabel", - "%DIF ADD $newlabel"; - if ( @auxlines ) { - push @diffpreamble,"%DIF DELETED TITLE COMMANDS FOR MARKUP"; - push @diffpreamble,join("\n",@auxlines); - } - push @diffpreamble,$latexdiffpreamble; - push @diffpreamble,'\begin{document}'; -} -elsif ( !length $oldpreamble && !length $newpreamble ) { - @diffpreamble=(); -} else { - print STDERR "Either both texts must have preamble or neither text must have the preamble.\n"; - exit(2); -} - -if (defined $packages{"amsmath"} or defined $packages{"amsart"} or defined $packages{"amsbook"} ) { - print STDERR "amsmath package detected.\n" if $verbose ; - $MATHARRREPL='align*'; -} - -print STDERR "Preprocessing body. " if $verbose; -my ($oldleadin,$newleadin)=preprocess($oldbody,$newbody); - - -# run difference algorithm -@diffbody=bodydiff($oldbody, $newbody); -$diffbo=join("",@diffbody); -if ( $debug ) { - open(RAWDIFF,">","latexdiff.debug.bodydiff"); - print RAWDIFF $diffbo; - close(RAWDIFF); -} -print STDERR "(",exetime()," s)\n","Postprocessing body. \n " if $verbose; -postprocess($diffbo); -$diffall =join("\n",@diffpreamble) ; -# add visible labels -if (defined($visiblelabel)) { - # Give information right after \begin{document} (or at the beginning of the text for files without preamble - ### if \date command is used, add information to \date argument, otherwise give right after \begin{document} - ### $diffall=~s/(\\date$extraspace(?:\[$brat0\])?$extraspace)\{($pat6)\}/$1\{$2 \\ LATEXDIFF comparison \\ Old: $oldlabel \\ New: $newlabel \}/ or - $diffbo = "\\begin{verbatim}LATEXDIFF comparison\nOld: $oldlabel\nNew: $newlabel\\end{verbatim}\n$diffbo" ; -} - -$diffall .= "$newleadin$diffbo" ; -$diffall .= "\\end{document}$newpost" if length $newpreamble ; -if ( lc($encoding) ne "utf8" && lc($encoding) ne "ascii" ) { - print STDERR "Encoding output file to $encoding\n" if $verbose; - $diffall=Encode::encode($encoding,$diffall); - binmode STDOUT; -} -print $diffall; - - -print STDERR "(",exetime()," s)\n","Done.\n" if $verbose; - - - -## guess_encoding(filename) -## reads the first 20 lines of filename and looks for call of inputenc package -## if found, return the option of this package (encoding), otherwise return ascii -sub guess_encoding { - my ($filename)=@_; - my ($i,$enc); - open (FH, $filename) or die("Couldn't open $filename: $!"); - $i=0; - while () { - next if /^\s*%/; # skip comment lines - if (m/\\usepackage\[(\w*?)\]\{inputenc\}/) { - close(FH); - return($1); - } - last if (++$i > 20 ); # scan at most 20 non-comment lines - } - close(FH); - return("ascii"); -} - - -sub read_file_with_encoding { - my ($output); - my ($filename, $encoding) = @_; - - if (lc($encoding) eq "utf8" ) { - open (FILE, "<:utf8",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } elsif ( lc($encoding) eq "ascii") { - open (FILE, $filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } else { - require Encode; - open (FILE, "<",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - print STDERR "Converting $filename from $encoding to utf8\n" if $verbose; - $output=Encode::decode($encoding,$output); - } - close FILE; - if ($^O eq "linux" ) { - $output =~ s/\r\n/\n/g ; - } - return $output; -} - -# %packages=list_packages(@preamble) -# scans the arguments for \documentclass and \usepackage statements and constructs a hash -# whose keys are the included packages, and whose values are the associated optional arguments -sub list_packages { - my (@preamble)=@_; - my %packages=(); - foreach $line ( @preamble ) { - # get rid of comments - $line=~s/(?catfile($dirname,$fname), "\n" if $debug; - # content of file becomes replacement value (use recursion), add \newpage if the command was include - ###$replacement=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - $replacement=flatten(read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding), $preamble,$filename,$encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - # \include always starts a new page; use explicit \newpage command to simulate this - $begline=(defined($1)? $1 : "") ; - $newpage=(defined($3)? " \\newpage " : "") ; - "$begline$newpage$replacement$newpage"; - }/exgm; - - return($text); -} - - -# print_regex_arr(@arr) -# prints regex array without x-ism expansion put in by pearl to stdout -sub print_regex_arr { - my $dumstring; - $dumstring = join(" ",@_); # PERL generates string (?-xism:^ref$) for quoted refex ^ref$ - $dumstring =~ s/\(\?-xism:\^(.*?)\$\)/$1/g; # remove string and ^,$ marks before output - print $dumstring,"\n"; -} - - -# @lines=extrapream($type) -# reads line from appendix (end of file after __END__ token) -sub extrapream { - my $type; - my @retval=("%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - my ($copy); - - while (@_) { - $copy=0; - $type=shift ; - if ( -f $type ) { - open (FILE,$type) or die "Cannot open preamble file $type: $!"; - print STDERR "Reading preamble file $type\n" if $verbose ; - while () { - chomp ; - if ( $_ =~ m/%DIF PREAMBLE/ ) { - push (@retval,"$_"); - } else { - push (@retval,"$_ %DIF PREAMBLE"); - } - } - } - else { # not (-f $type) - $type=uc($type); # upcase argument - print STDERR "Preamble Internal Type $type\n" if $verbose; - while () { - if ( m/^%DIF $type/ ) { - $copy=1; } - elsif ( m/^%DIF END $type/ ) { - last; } - chomp; - push (@retval,"$_ %DIF PREAMBLE") if $copy; - } - if ( $copy == 0 ) { - print STDERR "\nPreamble style $type not implemented.\n"; - print STDERR "Write latexdiff -h to get help with available styles\n"; - exit(2); - } - seek DATA,0,0; # rewind DATA handle to file begin - } - } - push (@retval,"%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - return @retval; -} - - -# ($part1,$part2,$part3)=splitdoc($text,$word1,$word2) -# splits $text into 3 parts at $word1 and $word2. -# if neither $word1 nor $word2 exist, $part1 and $part3 are empty, $part2 is $text -# If only $word1 or $word2 exist but not the other, output an error message. - -# NB this version avoids $` and $' for performance reason although it only makes a tiny difference -# (in one test gain a tenth of a second for a 30s run) -sub splitdoc { - my ($text,$word1,$word2)=@_; - my ($part1,$part2,$part3)=("","",""); - my ($rest,$pos); - - if ( $text =~ m/(^[^%]*)($word1)/mg ) { - $pos=pos $text; - $part1=substr($text,0,$pos-length($2)); - $rest=substr($text,$pos); - if ( $rest =~ m/(^[^%]*)($word2)/mg ) { - $pos=pos $rest; - $part2=substr($rest,0,$pos-length($2)); - $part3=substr($rest,$pos); - } - else { - die "$word1 and $word2 not in the correct order or not present as a pair." ; - } - } else { - $part2=$text; - die "$word2 present but not $word1." if ( $text =~ m/(^[^%]*)$word2/ms ); - } - return ($part1,$part2,$part3); -} - - - - - -# bodydiff($old,$new) -sub bodydiff { - my ($oldwords, $newwords) = @_; - my @retwords; - - print STDERR "(",exetime()," s)\n","Splitting into latex tokens \n" if $verbose; - print STDERR "Parsing $oldfile \n" if $verbose; - my @oldwords = splitlatex($oldwords); - print STDERR "Parsing $newfile \n" if $verbose; - my @newwords = splitlatex($newwords); - - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - print STDERR "(",exetime()," s)\n","Pass 1: Expanding text commands and merging isolated identities with changed blocks " if $verbose; - pass1(\@oldwords, \@newwords); - - - print STDERR "(",exetime()," s)\n","Pass 2: inserting DIF tokens and mark up. " if $verbose; - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold2.tex"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew2.tex"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - @retwords=pass2(\@oldwords, \@newwords); - - return(@retwords); -} - - - - -# @words=splitlatex($string) -# split string according to latex rules -# Each element of words is either -# a word (including trailing spaces and punctuation) -# a latex command -sub splitlatex { - my ($string) = @_ ; - # if input is empty, return empty list - length($string)>0 or return (); - - my @retval=($string =~ m/$pat/osg); - - if (length($string) != length(join("",@retval))) { - print STDERR "\nWARNING: Inconsistency in length of input string and parsed string:\n This often indicates faulty or non-standard latex code.\n In many cases you can ignore this and the following warning messages.\n Note that character numbers in the following are counted beginning after \\begin{document} and are only approximate." unless $ignorewarnings; - print STDERR "DEBUG Original length ",length($string)," Parsed length ",length(join("",@retval)),"\n" if $debug; - print STDERR "DEBUG Input string: |$string|\n" if (length($string)<500) && $debug; - print STDERR "DEBUG Token parsing: |",join("+",@retval),"|\n" if (length($string)<500) && $debug ; - @retval=(); - # slow way only do this if other m//sg method fails - my $last = 0; - while ( $string =~ m/$pat/osg ) { - my $match=$&; - if ($last + length $& != pos $string ) { - my $pos=pos($string); - my $offset=30<$last ? 30 : $last; - my $dum=substr($string,$last-$offset,$pos-$last+2*$offset); - my $dum1=$dum; - my $cnt=$#retval; - my $i; - $dum1 =~ s/\n/ /g; - unless ($ignorewarnings) { - print STDERR "\n$dum1\n"; - print STDERR " " x 30,"^" x ($pos-$last)," " x 30,"\n"; - print STDERR "Missing characters near word " . (scalar @retval) . " character index: " . $last . "-" . pos($string) . " Length: " . length($match) . " Match: |$match| (expected match marked above).\n"; - } - # put in missing characters `by hand' - push (@retval, substr($dum,$offset,$pos-$last-length($match))); -# Note: there seems to be a bug in substr with utf8 that made the following line output substr which were too long, -# using dum instead appears to work -# push (@retval, substr($string,$last, pos($string)-$last-length($match))); - } - push (@retval, $match); - $last=pos $string; - } - - } - return @retval; -} - - -# pass1( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Where an common-subsequence block is flanked by deleted or appended blocks, -# and is shorter than $MINWORDSBLOCK words it is appended -# to the last deleted or appended word. If the block contains tokens other than words -# or punctuation it is not merged. -# Deleted or appended block consisting of words and safe commands only are -# also merged, to prevent break-up in pass2 (after previous isolated words have been removed) -# If there are commands with textual arguments (e.g. \caption) both in corresponding -# appended and deleted blocks split them such that the command and opening bracket -# are one token, then the rest is split up following standard rules, and the closing -# bracket is a separate token, ie. turn -# "\caption{This is a textual argument}" into -# ("\caption{","This ","is ","a ","textual ","argument","}") -# No return value. Destructively changes sequences -sub pass1 { - my $seq1 = shift ; - my $seq2 = shift ; - - my $len1 = scalar @$seq1; - my $len2 = scalar @$seq2; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - - my ($last1,$last2)=(-1,-1) ; - my $cnt=0; - my $block=[]; - my $addblock=[]; - my $delblock=[]; - my $todo=[]; - my $instruction=[]; - my $i; - my (@delmid,@addmid,@dummy); - - my ($addcmds,$delcmds,$matchindex); - my ($addtextblocks,$deltextblocks); - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $adddiscard = sub { - if ($cnt > 0 ) { - $matblkcnt++; - # just after an unchanged block -# print STDERR "Unchanged block $cnt, $last1,$last2 \n"; - if ($cnt < $MINWORDSBLOCK - && $cnt==scalar ( - grep { /^$wpat/ || ( /^\\([\w\d\*]+)((?:\[$brat0\]|\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && scalar(@dummy=split(" ",$2))<3 ) } - @$block) ) { - # merge identical blocks shorter than $MINWORDSBLOCK - # and only containing ordinary words - # with preceding different word - # We cannot carry out this merging immediately as this - # would change the index numbers of seq1 and seq2 and confuse - # the algorithm, instead we store in @$todo where we have to merge - push(@$todo, [ $last1,$last2,$cnt,@$block ]); - } - $block = []; - $cnt=0; $last1=-1; $last2=-1; - } - }; - my $discard=sub { $deltokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$delblock,[ $seq1->[$_[0]],$_[0] ]); - $last1=$_[0] }; - - my $add = sub { $addtokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$addblock,[ $seq2->[$_[1]],$_[1] ]); - $last2=$_[1] }; - - my $match = sub { $mattokcnt++; - if ($cnt==0) { # first word of matching sequence after changed sequence or at beginning of word sequence - $deltextblocks = extracttextblocks($delblock); - $delblkcnt++ if scalar @$delblock; - $addtextblocks = extracttextblocks($addblock); - $addblkcnt++ if scalar @$addblock; - - $delcmds = extractcommands($delblock); - $addcmds = extractcommands($addblock); - # keygen(third argument of _longestCommonSubsequence) implies to sort on command (0th elements of $addcmd elements) - # the calling format for longestCommonSubsequence has changed between versions of - # Algorithm::Diff so we need to check which one we are using - if ( $algodiffversion > 1.15 ) { - ### Algorithm::Diff 1.19 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, 0, sub { $_[0]->[0] } ); - } else { - ### Algorithm::Diff 1.15 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, sub { $_[0]->[0] } ); - } - - for ($i=0 ; $i<=$#$matchindex ; $i++) { - if (defined($matchindex->[$i])){ - $j=$matchindex->[$i]; - @delmid=splitlatex($delcmds->[$i][3]); - @addmid=splitlatex($addcmds->[$j][3]); - while (scalar(@$deltextblocks) && $deltextblocks->[0][0]<$delcmds->[$i][1]) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) }; - push(@$todo, [$index,-1,$cnt,@$block]); - } - push(@$todo, [ $delcmds->[$i][1],-1,-1,$delcmds->[$i][2],@delmid,$delcmds->[$i][4]]); - - while (scalar(@$addtextblocks) && $addtextblocks->[0][0]<$addcmds->[$j][1]) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - push(@$todo, [ -1,$addcmds->[$j][1],-1,$addcmds->[$j][2],@addmid,$addcmds->[$j][4]]); - } - } - # mop up remaining textblocks - while (scalar(@$deltextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) } ; - push(@$todo, [$index,-1,$cnt,@$block]); - } - while (scalar(@$addtextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - - $addblock=[]; - $delblock=[]; - } - push(@$block,$seq2->[$_[1]]); - $cnt++ }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - - - # now carry out the merging/splitting. Refer to elements relative from - # the end (with negative indices) as these offsets don't change before the instruction is executed - # cnt>0: merged small unchanged groups with previous changed blocks - # cnt==-1: split textual commands into components - foreach $instruction ( @$todo) { - ($last1,$last2,$cnt,@$block)=@$instruction ; - if ($cnt>=0) { - splice(@$seq1,$last1-$len1,1+$cnt,join("",$seq1->[$last1-$len1],@$block)) if $last1>=0; - splice(@$seq2,$last2-$len2,1+$cnt,join("",$seq2->[$last2-$len2],@$block)) if $last2>=0; - } else { - splice(@$seq1,$last1-$len1,1,@$block) if $last1>=0; - splice(@$seq2,$last2-$len2,1,@$block) if $last2>=0; - } - } - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens in $matblkcnt blocks.\n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } -} - - -# extracttextblocks(\@blockindex) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [[ $index, $textblock, $cnt ], .. -# where $index index of block to be merged -# $textblock contains all the words to be merged with the word at $index (but does not contain this word) -# $cnt is length of block -# -# requires: iscmd -# -sub extracttextblocks { - my $block=shift; - my ($i,$token,$index); - my $textblock=[]; - my $last=-1; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # store pure text blocks - if ($token =~ /$wpat/ || ( $token =~/^\\([\w\d\*]+)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && !iscmd($1,\@TEXTCMDLIST,\@TEXTCMDEXCL))) { - # we have text or a command which can be treated as text - if ($last<0) { - # new pure-text block - $last=$index; - } else { - # add to pure-text block - push(@$textblock, $token); - } - } else { - # it is not text - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - $textblock=[]; - $last=-1; - } - } - # finish processing a possibly unfinished block before returning - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - return($retval) -} - - - -# extractcommands( \@blockindex ) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [ [ "\cmd1", index, "\cmd1[optarg]{arg1}{", "arg2" ,"} " ],.. -# where index is just taken from input array -# command must have a textual argument as last argument -# -# requires: iscmd -# -sub extractcommands { - my $block=shift; - my ($i,$token,$index,$cmd,$open,$mid,$closing); - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: \cmd - # $3: last argument - # $4: } + trailing spaces - if ( ( $token =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL) ) { - # push(@$retval,[ $2,$index,$1,$3,$4 ]); - ($cmd,$open,$mid,$closing) = ($2,$1,$3,$4) ; - $closing =~ s/\}/\\RIGHTBRACE/ ; - push(@$retval,[ $cmd,$index,$open,$mid,$closing ]); - } - } - return $retval; -} - -# iscmd($cmd,\@regexarray,\@regexexcl) checks -# return 1 if $cmd matches any of the patterns in the -# array $@regexarray, and none of the patterns in \@regexexcl, otherwise return 0 -sub iscmd { - my ($cmd,$regexar,$regexexcl)=@_; - my ($ret)=0; - foreach $pat ( @$regexar ) { - if ( $cmd =~ m/^${pat}$/ ) { - $ret=1 ; - last; - } - } - return 0 unless $ret; - foreach $pat ( @$regexexcl ) { - return 0 if ( $cmd =~ m/^${pat}$/ ); - } - return 1; -} - - -# pass2( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Mark begin and end of deleted and appended sequences with tags $DELOPEN and $DELCLOSE -# and $ADDOPEN and $ADDCLOSE, respectively, however exclude { } & and all comands, unless -# they match an element of the whitelist (SAFECMD) -# For words in TEXTCMD but not in SAFECMD, enclose interior with $ADDOPEN and $ADDCLOSE brackets -# Deleted comment lines are marked with %DIF < -# Added comment lines are marked with %DIF > -sub pass2 { - my $seq1 = shift ; - my $seq2 = shift ; - - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $retval = []; - my $delhunk = []; - my $addhunk = []; - - my $discard = sub { $deltokcnt++; - push ( @$delhunk, $seq1->[$_[0]]) }; - - my $add = sub { $addtokcnt++; - push ( @$addhunk, $seq2->[$_[1]]) }; - - my $match = sub { $mattokcnt++; - if ( scalar @$delhunk ) { - $delblkcnt++; - # mark up changes, but comment out commands - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk); - $delhunk = []; - } - if ( scalar @$addhunk ) { - $addblkcnt++; - # we mark up changes, but simply quote commands - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk); - $addhunk = []; - } - push(@$retval,$seq2->[$_[1]]) }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - # clear up unprocessed hunks - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk) if scalar @$delhunk; - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk) if scalar @$addhunk; - - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens. \n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } - - return(@$retval); -} - -# marktags($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,\@block) -# returns ($openmark,$open,$block,$close,$closemark) if @block only contains no commands (except white-listed ones), -# braces, ampersands, or comments -# mark comments with $comment -# exclude all other exceptions from scope of open, close like this -# ($openmark, $open,...,$close, $opencmd,command, command,$closecmd, $open, ..., $close, $closemark) -# If $opencmd begins with "%" marktags assumes it is operating on a deleted block, otherwise on an added block -sub marktags { - my ($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,$block)=@_; - my $word; - my (@argtext); - my $retval=[]; - my $noncomment=0; - my $cmd=-1; # -1 at beginning 0: last token written is a ordinary word - # 1: last token written is a command - # for keeping track whether we are just in a command sequence or in a word sequence - my $cmdcomment= ($opencmd =~ m/^%/); # Flag to indicate whether opencmd is a comment (i.e. if we intend to simply comment out changed commands) - my ($command,$commandword,$closingbracket) ; # temporary variables needed below to remember sub-pattern matches - -# split this block to flatten out sequences joined in pass1 - @$block=splitlatex(join "",@$block); - foreach (@$block) { - $word=$_; - if ( $word =~ s/^%/%$comment/ ) { - # a comment - if ($cmd==1) { - push (@$retval,$closecmd) ; - $cmd=-1; - } - push (@$retval,$word); - next; - } - if (! $noncomment) { - push (@$retval,$openmark); - $noncomment=1; - } - # negative lookahead pattern (?!) in second clause is put in to avoid mathcing \( .. \) patterns - # also note that second pattern will match \\ - # Note: the second pattern should really be $word =~ /^\\(?!\()(\\|[\w*@]+)/, ie * replaced by + - # and then all commands \" \' etc declared safe. But as I don't have a complete list of one letter - # commands, and nobody has complained so far, I will eave this as is - if ( $word =~ /^[&{}\[\]]/ || ( $word =~ /^\\(?!\()(\\|[\w*@]*)/ && !iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL)) ) { - # word is a command or other significant token (not in SAFECMDLIST) - ## same conditions as in subroutine extractcommand: - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: cmd - # $3: last argument - # $4: } + trailing spaces - ### pre-0.3 if ( ( $token =~ m/^(\\([\w\d\*]+)(?:\[$brat0\]|\{$pat6\})*\{)($pat6)(\}\s*)$/so ) - if ( ( $word =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && (iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL)|| iscmd($2,\@MATHTEXTCMDLIST,\@MATHTEXTCMDEXCL)) - && ( !$cmdcomment || !iscmd($2,\@CONTEXT2CMDLIST, \@CONTEXT2CMDEXCL) ) ) { - # Condition 1: word is a command? - if yes, $1,$2,.. will be set as above - # Condition 2: word is a text command - we mark up the interior of the word. There is a separate check for MATHTEXTCMDLIST - # because for $mathmarkup=WHOLE, the commands should not be split in pass1 (ie. math mode commands are not in - # TEXTCMDLIST, but the interior of MATHTEXT commands should be highlighted in both deleted and added blocks - # Condition 3: But if we are in a deleted block ($cmdcomment=1) and - # $2 (the command) is in context2, just treat it as an ordinary command (i.e. comment it open with $opencmd) - # Because we do not want to disable this command - # here we do not use $opencmd and $closecmd($opencmd is empty) - if ($cmd==1) { - push (@$retval,$closecmd) ; - } elsif ($cmd==0) { - push (@$retval,$close) ; - } - $command=$1; $commandword=$2; $closingbracket=$4; - @argtext=splitlatex($3); # split textual argument into tokens - # and mark it up (but we do not need openmark and closemark) - # insert command with initial arguments, marked-up final argument, and closing bracket - if ( $cmdcomment && iscmd($commandword,\@CONTEXT1CMDLIST, \@CONTEXT1CMDEXCL) ) { - # context1cmd in a deleted environment; delete command itself but keep last argument, marked up - push (@$retval,$opencmd); - $command =~ s/\n/\n${opencmd}/sg ; # repeat opencmd at the beginning of each line - # argument, note that the additional comment character is included - # to suppress linebreak after opening parentheses, which is important - # for latexrevise - push (@$retval,$command,"%\n{$AUXCMD\n",marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } elsif ( iscmd($commandword,,\@MATHTEXTCMDLIST, \@MATHTEXTCMDEXCL) ) { - # MATHBLOCK pseudo command: consider all commands safe, except & and \\ - # Keep these commands even in deleted blocks, hence set $opencmd and $closecmd (5th and 6th argument of marktags) to - # "" - local @SAFECMDLIST=(".*"); - local @SAFECMDEXCL=('\\','\\\\'); - push(@$retval,$command,marktags("","",$open,$close,"","",$comment,\@argtext)#@argtext - ,$closingbracket); - } else { - # normal textcmd or context1cmd in an added block - push (@$retval,$command,marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } - push (@$retval,$AUXCMD,"\n") if $cmdcomment ; - $cmd=-1 ; - } else { - # ordinary command - push (@$retval,$opencmd) if $cmd==-1 ; - push (@$retval,$close,$opencmd) if $cmd==0 ; - $word =~ s/\n/\n${opencmd}/sg if $cmdcomment ; # if opencmd is a comment, repeat this at the beginning of every line - push (@$retval,$word); - $cmd=1; - } - } else { - # just an ordinary word or word in SAFECMD - push (@$retval,$open) if $cmd==-1 ; - push (@$retval,$closecmd,$open) if $cmd==1 ; - push (@$retval,$word); - $cmd=0; - } - } - push (@$retval,$close) if $cmd==0; - push (@$retval,$closecmd) if $cmd==1; - - push (@$retval,$closemark) if ($noncomment); - return @$retval; -} - -# preprocess($string, ..) -# carry out the following pre-processing steps for all arguments: -# 1. Remove leading white-space -# Change \{ to \LEFTBRACE and \} to \RIGHTBRACE -# #. change begin and end commands within comments to BEGINDIF, ENDDIF -# so they don't disturb the pattern matching (if there are several \begin or \end in one line -# 2. mark all first empty line (in block of several) with \PAR tokens -# 3. Convert all '\%' into '\PERCENTAGE ' and all '\$' into \DOLLAR to make parsing regular expressions easier -# 4. Convert all \verb|some verbatim text| commands (where | can be an arbitrary character) -# into \verb{hash} -# 5. Convert \begin{verbatim} some verbatim text \end{verbatim} into \verbatim{hash} -# 6. Convert _n into \SUBSCRIPTNB{n} and _{nnn} into \SUBSCRIPT{nn} -# 7. Convert ^n into \SUPERSCRIPTNB{n} and ^{nnn} into \SUPERSCRIPT{nn} -# 8. a. Convert $$ $$ into \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} -# b. Convert \[ \] into \begin{SQUAREBRACKET} \end{SQUAREBRACKET} -# 9. Convert all picture environmentent (\begin{PICTUREENV} .. \end{PICTUREENV} \PICTUREBLOCKenv -# For --block-math-markup option -convert all \begin{MATH} .. \end{MATH} -# into \MATHBLOCKmath{...} commands, where MATH/math is any valid math environment - -# 10. Add final token STOP to the very end. This is put in because the algorithm works better if the last token is identical. This is removed again in postprocessing. -# -# NB: step 6 and 7 is likely to convert some "_" inappropriately, e.g. in file -# names or labels but it does not matter because they are converted back in the postprocessing step -# Returns: leading white space removed in step 1 -sub preprocess { - my @leadin=() ; - for (@_) { - s/^(\s*)//s; - push(@leadin,$1); - # Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE - s/(?{$hstr}) && $string ne $hash->{$hstr}) { - warn "Repeated hash value for verbatim mode in spite of different content."; - $hstr="-$hstr"; - } - $hash->{$hstr}=$string; - return($hstr); -} - -#string=fromhash(\%hash,$fromstring) -# restores string value stored in hash -#string=fromhash(\%hash,$fromstring,$prependstring) -# additionally begins each line with prependstring -sub fromhash { - my ($hash,$hstr)=($_[0],$_[1]); - my $retstr=$hash->{$hstr}; - if ( $#_ >= 2) { - $retstr =~ s/^/$_[2]/mg; - } - return $retstr; -} - - -# postprocess($string, ..) -# carry out the following post-processing steps for all arguments: -# * Remove STOP token from the end -# * Replace \RIGHTBRACE by } -# * change citation commands within comments to protect from processing (using marker CITEDIF) -# 1. Check all deleted blocks: -# a.where a deleted block contains a matching \begin and -# \end environment (these will be disabled by a %DIFDELCMD statements), for selected environments enable -# these commands again (such that for example displayed math in a deleted equation -# is properly within math mode. For math mode environments replace numbered equation -# environments with their display only variety (so that equation numbers in new file and -# diff file are identical). Where the correct type of math environment cannot be determined -# use a place holder MATHMODE -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file -# Replace all MATHMODE environment commands by the correct environment to achieve matching -# pairs -# c. Convert MATHBLOCKmath commands to their uncounted numbers (e.g. convert equation -> displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL -# d. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# For added blocks: -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# 2. If --block-math-markup option set: Convert \MATHBLOCKmath{..} commands back to environments -# -# Convert all PICTUREblock{..} commands back to the appropriate environments -# 3. Convert DIFadd, DIFdel, DIFFaddbegin , ... into FL varieties -# within floats (currently recognised float environments: plate,table,figure -# plus starred varieties). -# 4. Remove empty %DIFDELCMD < lines -# 4. Convert \begin{SQUAREBRACKET} \end{SQUAREBRACKET} into \[ \] -# Convert \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} into $$ $$ -# 5. Convert \SUPERSCRIPTNB{n} into ^n and \SUPERSCRIPT{nn} into ^{nnn} -# 6. Convert \SUBSCRIPTNB{n} into _n and \SUBCRIPT{nn} into _{nnn} -# 7. Expand hashes of verb and verbatim environments -# 8. Convert '\PERCENTAGE ' back into '\%' and '\DOLLAR ' into '\$' -# 9.. remove all \PAR tokens -# 10. package specific processing: endfloat: make sure \begin{figure} and \end{figure} are always -# on a line by themselves, similarly for table environment -# 4, undo renaming of the \begin and \end in comments -# Change \QLEFTBRACE, \QRIGHTBRACE to \{,\} -# -# Note have to manually synchronize substitution commands below and -# DIF.. command names in the header -sub postprocess { - my ($begin,$len,$cnt,$float,$delblock,$addblock); - # second level blocks - my ($begin2,$cnt2,$len2,$eqarrayblock,$mathblock); - - for (@_) { - - # change $'s in comments to something harmless - 1 while s/(%.*)\$/$1DOLLARDIF/mg ; - - # Remove final STOP token - s/ STOP$//; - # Replace \RIGHTBRACE by } - s/\\RIGHTBRACE/}/g; - - # change citation commands within comments to protect from processing - if ($CITECMD){ - 1 while s/(%.*)\\($CITECMD)/$1\\CITEDIF$2/m ; - } - # Check all deleted blocks: where a deleted block contains a matching \begin and - # \end environment (these will be disabled by a %DIFDELCMD statements), enable - # these commands again (such that for example displayed math in a deleted equation - # is properly within math mode. For math mode environments replace numbered equation - # environments with their display only variety (so that equation numbers in new file and - # diff file are identical - while ( m/\\DIFdelbegin.*?\\DIFdelend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $delblock=$&; - - - ### (.*?[^\n]?)\n? construct is necessary to avoid empty lines in math mode, which result in - ### an error - # displayed math environments - if ($mathmarkup == FINE ) { - $delblock=~ s/(\%DIFDELCMD < \s*\\begin\{((?:$MATHENV)|SQUAREBRACKET)\}.*?(?:$DELCMDCLOSE|\n))(.*?[^\n]?)\n?(\%DIFDELCMD < \s*\\end\{\2\})/\\begin{$MATHREPL}$AUXCMD\n$1$3\n\\end{$MATHREPL}$AUXCMD\n$4/sg; - # also transform the opposite pair \end{displaymath} .. \begin{displaymath} but we have to be careful not to interfere with the results of the transformation in the line directly above - ### pre-0.42 obsolete version which did not work on eqnarray test $delblock=~ s/(? displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL - $delblock=~ s/\\MATHBLOCK($MATHENV)\{($pat6)\}/\\MATHBLOCK$MATHREPL\{$2\}/sg; - $delblock=~ s/\\MATHBLOCK($MATHARRENV)\{($pat6)\}/\\MATHBLOCK$MATHARRREPL\{$2\}/sg; - } - - -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file - $delblock=~ s/\\($COUNTERCMD)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*\s*${AUXCMD}\n)/\\$1$2\\addtocounter{$1}{-1}${AUXCMD}\n/sg ; - - -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es - while ( $delblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($delblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($delblock,$begin2,$len2)=$mathblock; - pos($delblock) = $begin2 + length($mathblock); - } - if ($CITE2CMD) { - $delblock=~s/($DELCMDOPEN\s*\\($CITE2CMD)(.*)$DELCMDCLOSE)/ - # Replacement code - {my ($aux,$all); - $aux=$all=$1; - $aux=~s#\n?($DELCMDOPEN|$DELCMDCLOSE)##g; - $all."$aux$AUXCMD\n";}/sge; - } - # or protect \cite commands with \mbox - if ($CITECMD) { - $delblock=~s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat6\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified delblock - substr($_,$begin,$len)=$delblock; - pos = $begin + length($delblock); - } - # make the array modification in added blocks - while ( m/\\DIFaddbegin.*?\\DIFaddend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $addblock=$&; - while ( $addblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($addblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($addblock,$begin2,$len2)=$mathblock; - pos($addblock) = $begin2 + length($mathblock); - } - if ($CITECMD) { - my $addblockbefore=$addblock; - $addblock=~ s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat2\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified addblock - substr($_,$begin,$len)=$addblock; - pos = $begin + length($addblock); - } - - - ### old place for BEGINDIF, ENDDIF replacement - # change begin and end commands within comments such that they - # don't disturb the pattern matching (if there are several \begin or \end in one line - # this substitution is insufficient but that appears unlikely) - # This needs to be repeated here to also get rid of DIFdelcmd-protected environments - s/(%.*)\\begin\{(.*)$/$1\\BEGINDIF\{$2/mg ; - s/(%.*)\\end\{(.*)$/$1\\ENDDIF\{$2/mg ; - - # Replace MATHMODE environments from step 1a above by the correct Math environment - - # The next line is complicated. The negative look-ahead insertion makes sure that no \end{$MATHENV} (or other mathematical - # environments) are between the \begin{$MATHENV} and \end{MATHMODE} commands. This is necessary as the minimal matching - # is not globally minimal but only 'locally' (matching is beginning from the left side of the string) - if ( $mathmarkup == FINE ) { - 1 while s/\\begin{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}((?:.(?!(?:\\end{(?:(?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}|\\begin{MATHMODE})))*?)\\end{MATHMODE}/\\begin{$1}$2\\end{$1}/s; - 1 while s/\\begin{MATHMODE}((?:.(?!\\end{MATHMODE}))*?)\\end{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}/\\begin{$2}$1\\end{$2}/s; - # convert remaining \begin{MATHMODE} \end{MATHMODE} (and not containing & or \\ )into MATHREPL environments - s/\\begin{MATHMODE}((?:(.(?!(?[1])) { - $optargnew=$newhash{$cmd}->[1]; - } else { - $optargnew=""; - } - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - } else { - $optargold=""; - } - - if ( defined($oldhash{$cmd}) ) { - $argold=$oldhash{$cmd}->[2]; - } else { - $argold=""; - } - $argnew=$newhash{$cmd}->[2]; - $argdiff="{" . join("",bodydiff($argold,$argnew)) ."}"; - if ( length $optargnew ) { - $optargdiff="[".join("",bodydiff($optargold,$optargnew))."]" ; - $optargdiff =~ s/\\DIFaddbegin /\\DIFaddbeginFL /g; - $optargdiff =~ s/\\DIFaddend /\\DIFaddendFL /g; - $optargdiff =~ s/\\DIFadd\{/\\DIFaddFL{/g; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - ### print STDERR "DEBUG s/\\Q$newhash{$cmd}->[0]\\E/\\$cmd$optargdiff$argdiff/s\n"; - # Note: \Q and \E force literal interpretation of what it between them but allow - # variable interpolation, such that e.g. \title matches just that and not TAB-itle - $$newpreambleref=~s/\Q$newhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s; - # replace this in old preamble if necessary - if ( defined($oldhash{$cmd}->[0])) { - $$oldpreambleref=~s/\Q$oldhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s ; - } - ### print STDERR "DEBUG NEW PRE ".$$newpreambleref."\n"; - } - - foreach $cmd ( keys %oldhash ) { - # if this has already been dealt with above can just skip - next if defined($newhash{$cmd}) ; - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - $optargdiff="[".join("",bodydiff($optargold,""))."]" ; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - $argdiff="{" . join("",bodydiff($argold,"")) ."}"; - $auxline = "\\$cmd$optargdiff$argdiff"; - $auxline =~s/$/$AUXCMD/sg; - push @auxlines,$auxline; - } - # add auxcmd comment to highlight added lines - return(@auxlines); -} - - - -# @diffs=linediff(\@seq1, \@seq2) -# mark up lines like this -#%DIF mm-mmdnn -#%< old deleted line(s) -#%DIF ------- -#%DIF mmann-nn -#new appended line %< -#%DIF ------- -# Future extension: mark change explicitly -# Assumes: traverse_sequence traverses deletions before insertions in changed sequences -# all line numbers relative to line 0 (first line of real file) -sub linediff { - my $seq1 = shift ; - my $seq2 = shift ; - - my $block = []; - my $retseq = []; - my @begin=('','',''); # dummy initialisation - my $instring ; - - my $discard = sub { @begin=('d',$_[0],$_[1]) unless scalar @$block ; - push(@$block, "%DIF < " . $seq1->[$_[0]]) }; - my $add = sub { if (! scalar @$block) { - @begin=('a',$_[0],$_[1]) ;} - elsif ( $begin[0] eq 'd' ) { - $begin[0]='c'; $begin[2]=$_[1]; - push(@$block, "%DIF -------") } - push(@$block, $seq2->[$_[1]] . " %DIF > " ) }; - my $match = sub { if ( scalar @$block ) { - if ( $begin[0] eq 'd' && $begin[1]!=$_[0]-1) { - $instring = sprintf "%%DIF %d-%dd%d",$begin[1],$_[0]-1,$begin[2]; } - elsif ( $begin[0] eq 'a' && $begin[2]!=$_[1]-1) { - $instring = sprintf "%%DIF %da%d-%d",$begin[1],$begin[2],$_[1]-1; } - elsif ( $begin[0] eq 'c' ) { - $instring = sprintf "%%DIF %sc%s", - ($begin[1]==$_[0]-1) ? "$begin[1]" : $begin[1]."-".($_[0]-1) , - ($begin[2]==$_[1]-1) ? "$begin[2]" : $begin[2]."-".($_[1]-1) ; } - else { - $instring = sprintf "%%DIF %d%s%d",$begin[1],$begin[0],$begin[2]; } - push @$retseq, $instring,@$block, "%DIF -------" ; - $block = []; - } - push @$retseq, $seq2->[$_[1]] - }; - # key function: remove multiple spaces (such that insertion or deletion of redundant white space is not reported) - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - push @$retseq, @$block if scalar @$block; - - return wantarray ? @$retseq : $retseq ; -} - - - -# init_regex_arr_data(\@array,"TOKEN INIT") -# scans DATA file handel for line "%% TOKEN INIT" line -# then appends each line not beginning with % into array (as a quoted regex) -sub init_regex_arr_data { - my ($arr,$token)=@_; - my ($copy); - while () { - if ( m/^%%BEGIN $token\s*$/ ) { - $copy=1; } - elsif ( m/^%%END $token\s*/ ) { - last; } - chomp; - push (@$arr,qr/^$_$/) if ( $copy && !/^%/ ) ; - } - seek DATA,0,0; # rewind DATA handle to file begin -} - - -# init_regex_arr_ext(\@array,$arg) -# fills array with regular expressions. -# if arg is a file name, then read in list of regular expressions from that file -# (one expression per line) -# Otherwise treat arg as a comma separated list of regular expressions -sub init_regex_arr_ext { - my ($arr,$arg)=@_; - my $regex; - if ( -f $ arg ) { - open(FILE,"$arg") or die ("Couldn't open $arg: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@$arr,qr/^$_$/); - } - close(FILE); - } - else { - # assume it is a comma-separated list of reg-ex - foreach $regex (split(qr/(?=1) { - $reset=shift; - } - if ($reset) { - $lasttime=times(); - } - else { - $retval=times()-$lasttime; - $lasttime=$lasttime+$retval; - return($retval); - } -} - - -sub usage { - die <<"EOF"; -Usage: $0 [options] old.tex new.tex > diff.tex - -Compares two latex files and writes tex code to stdout, which has the same -format as new.tex but has all changes relative to old.tex marked up or commented. - ---type=markupstyle --t markupstyle Add code to preamble for selected markup style - Available styles: UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE - CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR - [ Default: UNDERLINE ] - ---subtype=markstyle --s markstyle Add code to preamble for selected style for bracketing - commands (e.g. to mark changes in margin) - Available styles: SAFE MARGINAL DVIPSCOL COLOR - [ Default: SAFE ] - ---floattype=markstyle --f markstyle Add code to preamble for selected style which - replace standard marking and markup commands within floats - (e.g., marginal remarks cause an error within floats - so marginal marking can be disabled thus) - Available styles: FLOATSAFE IDENTICAL - [ Default: FLOATSAFE ] - ---encoding=enc --e enc Specify encoding of old.tex and new.tex. Typical encodings are - ascii, utf8, latin1, latin9. A list of available encodings can be - obtained by executing - perl -MEncode -e 'print join ("\\n",Encode->encodings( ":all" )) ;' - [Default encoding is utf8 unless the first few lines of the preamble contain - an invocation "\\usepackage[..]{inputenc} in which case the - encoding chosen by this command is asssumed. Note that ASCII (standard - latex) is a subset of utf8] - ---preamble=file --p file Insert file at end of preamble instead of auto-generating - preamble. The preamble must define the following commands - \\DIFaddbegin,\\DIFaddend,\\DIFadd{..}, - \\DIFdelbegin,\\DIFdelend,\\DIFdel{..}, - and varieties for use within floats - \\DIFaddbeginFL,\\DIFaddendFL,\\DIFaddFL{..}, - \\DIFdelbeginFL,\\DIFdelendFL,\\DIFdelFL{..} - (If this option is set -t, -s, and -f options - are ignored.) - ---exclude-safecmd=exclude-file ---exclude-safecmd="cmd1,cmd2,..." --A exclude-file ---replace-safecmd=replace-file ---append-safecmd=append-file ---append-safecmd="cmd1,cmd2,..." --a append-file Exclude from, replace or append to the list of regex - matching commands which are safe to use within the - scope of a \\DIFadd or \\DIFdel command. The file must contain - one Perl-RegEx per line (Comment lines beginning with # or % are - ignored). A literal comma within the comma-separated list must be - escaped thus "\\,", Note that the RegEx needs to match the whole of - the token, i.e., /^regex\$/ is implied and that the initial - "\\" of the command is not included. The --exclude-safecmd - and --append-safecmd options can be combined with the --replace-safecmd - option and can be used repeatedly to add cumulatively to the lists. - ---exclude-textcmd=exclude-file ---exclude-textcmd="cmd1,cmd2,..." --X exclude-file ---replace-textcmd=replace-file ---append-textcmd=append-file ---append-textcmd="cmd1,cmd2,..." --x append-file Exclude from, replace or append to the list of regex - matching commands whose last argument is text. See - entry for --exclude-safecmd directly above for further details. - ---replace-context1cmd=replace-file ---append-context1cmd=append-file ---append-context1cmd="cmd1,cmd2,..." - Replace or append to the list of regex matching commands - whose last argument is text but which require a particular - context to work, e.g. \\caption will only work within a figure - or table. These commands behave like text commands, except when - they occur in a deleted section, when they are disabled, but their - argument is shown as deleted text. - ---replace-context2cmd=replace-file ---append-context2cmd=append-file ---append-context2cmd="cmd1,cmd2,..." - As corresponding commands for context1. The only difference is that - context2 commands are completely disabled in deleted sections, including - their arguments. - - ---config var1=val1,var2=val2,... --c var1=val1,.. Set configuration variables. --c configfile Available variables: - MINWORDSBLOCK (integer) - FLOATENV (RegEx) - PICTUREENV (RegEx) - MATHENV (RegEx) - MATHREPL (String) - MATHARRENV (RegEx) - MATHARRREPL (String) - ARRENV (RegEx) - COUNTERCMD (RegEx) - This option can be repeated. - - ---packages=pkg1,pkg2,.. - Tell latexdiff that .tex file is processed with the packages in list - loaded. This is normally not necessary if the .tex file includes the - preamble, as the preamble is automatically scanned for \\usepackage commands. - Use of the --packages option disables automatic scanning, so if for any - reason package specific parsing needs to be switched off, use --packages=none. - The following packages trigger special behaviour: - endfloat hyperref amsmath - [ Default: scan the preamble for \\usepackage commands to determine - loaded packages.] - ---show-preamble Print generated or included preamble commands to stdout. - ---show-safecmd Print list of regex matching and excluding safe commands. - ---show-textcmd Print list of regex matching and excluding commands with text argument. - ---show-config Show values of configuration variables - ---show-all Show all of the above - - NB For all --show commands, no old.tex or new.tex file needs to be given, and no - differencing takes place. - -Other configuration options: - ---allow-spaces Allow spaces between bracketed or braced arguments to commands - [Default requires arguments to directly follow each other without - intervening spaces] - ---math-markup=level Determine granularity of markup in displayed math environments: - Possible values for level are (both numerical and text labels are acceptable): - off or 0: suppress markup for math environments. Deleted equations will not - appear in diff file. This mode can be used if all the other modes - cause invalid latex code. - whole or 1: Differencing on the level of whole equations. Even trivial changes - to equations cause the whole equation to be marked changed. This - mode can be used if processing in coarse or fine mode results in - invalid latex code. - coarse or 2: Detect changes within equations marked up with a coarse - granularity; changes in equation type (e.g.displaymath to equation) - appear as a change to the complete equation. This mode is recommended - for situations where the content and order of some equations are still - being changed. [Default] - fine or 3: Detect small change in equations and mark up and fine granularity. - This mode is most suitable, if only minor changes to equations are - expected, e.g. correction of typos. - ---disable-citation-markup Suppress citation markup in styles using ulem (UNDERLINE, - FONTSTRIKE, CULINECHBAR) ---enable-citation-markup Protect citation commands in changed sections with \\mbox command - [i.e. use default behaviour for ulem package for other packages] - -Miscelleneous options - ---label=label --L label Sets the labels used to describe the old and new files. The first use - of this option sets the label describing the old file and the second - use of the option sets the label for the new file. - [Default: use the filename and modification dates for the label] - ---no-label Suppress inclusion of old and new file names as comment in output file - ---visble-label Include old and new filenames (or labels set with --label option) as - visible output - ---flatten Replace \\input and \\include commands within body by the content - of the files in their argument. If \\includeonly is present in the - preamble, only those files are expanded into the document. However, - no recursion is done, i.e. \\input and \\include commands within - included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, - respectively, making it possible to organise files into old and new directories. - --flatten is applied recursively, so inputted files can contain further - \\input statements. - ---help --h Show this help text. - ---ignore-warnings Suppress warnings about inconsistencies in length between input - and parsed strings and missing characters. - ---verbose --V Output various status information to stderr during processing. - Default is to work silently. - ---version Show version number. - -For further information, consult http://latexdiff.berlios.de -EOF -} - -=head1 NAME - -latexdiff - determine and markup differences between two latex files - -=head1 SYNOPSIS - -B [ B ] F F > F - -=head1 DESCRIPTION - -Briefly, I is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called C and C, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. - -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "S>>" is appended to each added line, i.e. a -line present in C but not in C. Discarded lines - are deactivated by prepending "S>>". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file C will be similar to -C. At the end of the preamble, the definitions for I markup commands are inserted. -In differencing the main body of the text, I attempts to -satisfy the following guidelines (in order of priority): - -=over 3 - -=item 1 - -If both C and C are valid LaTeX, then the resulting -C should also be valid LateX. (NB If a few plain TeX commands -are used within C or C then C is not -guaranteed to work but usually will). - -=item 2 - -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -C. - -=item 3 - -If a changed passage contains text or text-producing commands, then -running C through LateX should produce output where added -and discarded passages are highlighted. - -=item 4 - -Where there are insignificant differences, e.g. in the positioning of -line breaks, C should follow the formatting of C - -=back - -For differencing the same algorithm as I is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, C<\caption> and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write - - \section{\textem{This is an emphasized section title}} - -and not - - \section {\textem{This is an emphasized section title}} - -or - - \section\textem{This is an emphasized section title} - -even though all varieties are the same to LaTeX (but see -B<--allow-spaces> option which allows the second variety). - -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the PICTUREENV configuration variable, set by -default to C and C environments; see B<--config> -option). The latter environment (C) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by C<\begin{DIFnomarkup}> and C<\end{DIFnomarkup}>. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, - -C<\newenvironment{DIFnomarkup}{}{}> - -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. - -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. - -All markup commands inserted by I begin with "C<\DIF>". Added -blocks containing words, commands or comments which are in C -but not in C are marked by C<\DIFaddbegin> and C<\DIFaddend>. -Discarded blocks are marked by C<\DIFdelbegin> and C<\DIFdelend>. -Within added blocks all text is highlighted with C<\DIFadd> like this: -C<\DIFadd{Added text block}> -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces "{" and "}" are never put within -the scope of C<\DIFadd>. Added comments are marked by prepending -"S >>". - -Within deleted blocks text is highlighted with C<\DIFdel>. Deleted -comments are marked by prepending "S >>". Non-safe command -and curly braces within deleted blocks are commented out with -"S >>". - - - -=head1 OPTIONS - -=head2 Preamble - -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. - -=over 4 - -=item B<--type=markupstyle> or -B<-t markupstyle> - -Add code to preamble for selected markup style. This option defines -C<\DIFadd> and C<\DIFdel> commands. -Available styles: - -C - -[ Default: C ] - -=item B<--subtype=markstyle> or -B<-s markstyle> - -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -C<\DIFaddbegin>, C<\DIFaddend>, C<\DIFdelbegin> and C<\DIFdelend> commands. -Available styles: C - -[ Default: C ] - -=item B<--floattype=markstyle> or -B<-f markstyle> - -Add code to preamble for selected style which -replace standard marking and markup commands within floats -(e.g., marginal remarks cause an error within floats -so marginal marking can be disabled thus). This option defines all -C<\DIF...FL> commands. -Available styles: C - -[ Default: C ] - -=item B<--encoding=enc> or -B<-e enc> - -Specify encoding of old.tex and new.tex. Typical encodings are -C, C, C, C. A list of available encodings can be -obtained by executing - -Cencodings( ":all" )) ;' > - -[Default encoding is utf8 unless the first few lines of the preamble contain -an invocation C<\usepackage[..]{inputenc}> in which case the -encoding chosen by this command is asssumed. Note that ASCII (standard -latex) is a subset of utf8] - -=item B<--preamble=file> or -B<-p file> - -Insert file at end of preamble instead of generating -preamble. The preamble must define the following commands -C<\DIFaddbegin, \DIFaddend, \DIFadd{..}, -\DIFdelbegin,\DIFdelend,\DIFdel{..},> -and varieties for use within floats -C<\DIFaddbeginFL, \DIFaddendFL, \DIFaddFL{..}, -\DIFdelbeginFL, \DIFdelendFL, \DIFdelFL{..}> -(If this option is set B<-t>, B<-s>, and B<-f> options -are ignored.) - -=item B<--packages=pkg1,pkg2,..> - -Tell latexdiff that .tex file is processed with the packages in list -loaded. This is normally not necessary if the .tex file includes the -preamble, as the preamble is automatically scanned for C<\usepackage> commands. -Use of the B<--packages> option disables automatic scanning, so if for any -reason package specific parsing needs to be switched off, use B<--packages=none>. -The following packages trigger special behaviour: - -=over 8 - -=item C - -Configuration variable amsmath is set to C (Default: C) - -=item C - -Ensure that C<\begin{figure}> and C<\end{figure}> always appear by themselves on a line. - -=item C - -Change name of C<\DIFadd> and C<\DIFdel> commands to C<\DIFaddtex> and C<\DIFdeltex> and -define new C<\DIFadd> and C<\DIFdel> commands, which provide a wrapper for these commands, -using them for the text but not for the link defining command (where any markup would cause -errors). - -=back - -[ Default: scan the preamble for C<\\usepackage> commands to determine - loaded packages.] - - - -=item B<--show-preamble> - -Print generated or included preamble commands to stdout. - -=back - -=head2 Configuration - -=over 4 - -=item B<--exclude-safecmd=exclude-file> or -B<-A exclude-file> or B<--exclude-safecmd="cmd1,cmd2,..."> - -=item B<--replace-safecmd=replace-file> - -=item B<--append-safecmd=append-file> or -B<-a append-file> or B<--append-safecmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions (RegEx) -matching commands which are safe to use within the -scope of a C<\DIFadd> or C<\DIFdel> command. The file must contain -one Perl-RegEx per line (Comment lines beginning with # or % are -ignored). Note that the RegEx needs to match the whole of -the token, i.e., /^regex$/ is implied and that the initial -"\" of the command is not included. -The B<--exclude-safecmd> and B<--append-safecmd> options can be combined with the -B<--replace-safecmd> -option and can be used repeatedly to add cumulatively to the lists. - B<--exclude-safecmd> -and B<--append-safecmd> can also take a comma separated list as input. If a -comma for one of the regex is required, escape it thus "\,". In most cases it -will be necessary to protect the comma-separated list from the shell by putting -it in quotation marks. - -=item B<--exclude-textcmd=exclude-file> or -B<-X exclude-file> or B<--exclude-textcmd="cmd1,cmd2,..."> - -=item B<--replace-textcmd=replace-file> - -=item B<--append-textcmd=append-file> or -B<-x append-file> or B<--append-textcmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions -matching commands whose last argument is text. See -entry for B<--exclude-safecmd> directly above for further details. - - -=item B<--replace-context1cmd=replace-file> - -=item B<--append-context1cmd=append-file> or -=item B<--append-context1cmd="cmd1,cmd2,..."> - -Replace or append to the list of regex matching commands -whose last argument is text but which require a particular -context to work, e.g. \caption will only work within a figure -or table. These commands behave like text commands, except when -they occur in a deleted section, when they are disabled, but their -argument is shown as deleted text. - -=item B<--replace-context2cmd=replace-file> - -=item B<--append-context2cmd=append-file> or -=item B<--append-context2cmd="cmd1,cmd2,..."> -As corresponding commands for context1. The only difference is that -context2 commands are completely disabled in deleted sections, including -their arguments. - - - -=item B<--config var1=val1,var2=val2,...> or B<-c var1=val1,..> - -=item B<-c configfile> - -Set configuration variables. The option can be repeated to set different -variables (as an alternative to the comma-separated list). -Available variables (see below for further explanations): - -C (integer) - -C (RegEx) - -C (RegEx) - -C (RegEx) - -C (String) - -C (RegEx) - -C (String) - -C (RegEx) - -C (RegEx) - -=item B<--show-safecmd> - -Print list of RegEx matching and excluding safe commands. - -=item B<--show-textcmd> - -Print list of RegEx matching and excluding commands with text argument. - -=item B<--show-config> - -Show values of configuration variables. - -=item B<--show-all> - -Combine all --show commands. - -NB For all --show commands, no C or C file needs to be specified, and no -differencing takes place. - -=back - -=head2 Other configuration options: - -=over 4 - -=item B<--allow-spaces> - -Allow spaces between bracketed or braced arguments to commands. Note -that this option might have undesirable side effects (unrelated scope -might get lumpeded with preceding commands) so should only be used if the -default produces erroneous results. (Default requires arguments to -directly follow each other without intervening spaces). - -=item B<--math-markup=level> - -Determine granularity of markup in displayed math environments: -Possible values for level are (both numerical and text labels are acceptable): - -C or C<0>: suppress markup for math environments. Deleted equations will not -appear in diff file. This mode can be used if all the other modes -cause invalid latex code. - -C or C<1>: Differencing on the level of whole equations. Even trivial changes -to equations cause the whole equation to be marked changed. This -mode can be used if processing in coarse or fine mode results in -invalid latex code. - -C or C<2>: Detect changes within equations marked up with a coarse -granularity; changes in equation type (e.g.displaymath to equation) -appear as a change to the complete equation. This mode is recommended -for situations where the content and order of some equations are still -being changed. [Default] - -C or C<3>: Detect small change in equations and mark up at fine granularity. -This mode is most suitable, if only minor changes to equations are -expected, e.g. correction of typos. - -=item B<--disable-citation-markup> - -Suppress citation markup in styles using ulem (UNDERLINE, -FONTSTRIKE, CULINECHBAR) - -=item B<--enable-citation-markup> - -Protect citation commands in changed sections with \\mbox command [i.e. use default behaviour for ulem package for other packages] - -=back - -=head2 Miscellaneous - -=over 4 -=item B<--verbose> or B<-V> - -Output various status information to stderr during processing. -Default is to work silently. - -=item B<--driver=type> - -Choose driver for changebar package (only relevant for styles using - changebar: CCHANGEBAR CFONTCHBAR CULINECHBAR CHANGEBAR). Possible -drivers are listed in changebar manual, e.g. pdftex,dvips,dvitops - [Default: dvips] - -=item B<--ignore-warnings> - -Suppress warnings about inconsistencies in length between input and -parsed strings and missing characters. These warning messages are -often related to non-standard latex or latex constructions with a -syntax unknown to C but the resulting difference argument -is often fully functional anyway, particularly if the non-standard -latex only occurs in parts of the text which have not changed. - -=item B<--label=label> or -B<-L label> - -Sets the labels used to describe the old and new files. The first use -of this option sets the label describing the old file and the second -use of the option sets the label for the new file, i.e. set both -labels like this C<-L labelold -L labelnew>. -[Default: use the filename and modification dates for the label] - -=item B<--no-label> - -Suppress inclusion of old and new file names as comment in output file - -=item B<--visble-label> - -Include old and new filenames (or labels set with --label option) as -visible output. - -=item B<--flatten> - -Replace C<\input> and C<\include> commands within body by the content -of the files in their argument. If C<\includeonly> is present in the -preamble, only those files are expanded into the document. However, -no recursion is done, i.e. C<\input> and C<\include> commands within -included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, -respectively, making it possible to organise files into old and new directories. ---flatten is applied recursively, so inputted files can contain further -C<\input> statements. - -Use of this option might result in prohibitive processing times for -larger documents, and the resulting difference document -no longer reflects the structure of the input documents. - -=item B<--help> or -B<-h> - -Show help text - -=item B<--version> - -Show version number - -=back - - - -=head2 Predefined styles - -=head2 Major types - -The major type determine the markup of plain text and some selected latex commands outside floats by defining the markup commands C<\DIFadd{...}> and C<\DIFdel{...}> . - -=over 10 - -=item C - -Added text is wavy-underlined and blue, discarded text is struck out and red -(Requires color and ulem packages). Overstriking does not work in displayed math equations such that deleted parts of equation are underlined, not struck out (this is a shortcoming inherent to the ulem package). - -=item C - -Added text is blue and set in sans-serif, and a red footnote is created for each discarded -piece of text. (Requires color package) - -=item C - -Like C but without the use of color. - -=item C - -Added text is blue and set in sans-serif, and discarded text is red and very small size. - -=item C - -Added tex is set in sans-serif, discarded text small and struck out - -=item C - -Added text is blue, and discarded text is red. Additionally, the changed text is marked with a bar in the margin (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color, ulem and changebar packages). - -=item C - -No mark up of text, but mark margins with changebars (Requires changebar package). - -=item C - -No visible markup (but generic markup commands will still be inserted. - -=back - -=head2 Subtypes - -The subtype defines the commands that are inserted at the begin and end of added or discarded blocks, irrespectively of whether these blocks contain text or commands (Defined commands: C<\DIFaddbegin, \DIFaddend, \DIFdelbegin, \DIFdelend>) - -=over 10 - -=item C - -No additional markup (Recommended choice) - -=item C - -Mark beginning and end of changed blocks with symbols in the margin nearby (using -the standard C<\marginpar> command - note that this sometimes moves somewhat -from the intended position. - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. -(It is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete, for example -with citation commands). - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. Note -that C only works with the dvips converter, e.g. not pdflatex. -(it is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete). - -=back - -=head2 Float Types - -Some of the markup used in the main text might cause problems when used within -floats (e.g. figures or tables). For this reason alternative versions of all -markup commands are used within floats. The float type defines these alternative commands. - -=over 10 - -=item C - -Use identical markup for text as in the main body, but set all commands marking the begin and end of changed blocks to null-commands. You have to choose this float type if your subtype is C as C<\marginpar> does not work properly within floats. - -=item C - -Mark additions the same way as in the main text. Deleted environments are marked by angular brackets \[ and \] and the deleted text is set in scriptscript size. This float type should always be used with the C and C markup types as the \footnote command does not work properly in floating environments. - -=item C - -Make no difference between the main text and floats. - -=back - - -=head2 Configuration Variables - -=over 10 - -=item C - -Minimum number of tokens required to form an independent block. This value is -used in the algorithm to detect changes of complete blocks by merging identical text parts of less than C to the preceding added and discarded parts. - -[ Default: 3 ] - -=item C - -Environments whose name matches the regular expression in C are -considered floats. Within these environments, the I markup commands -are replaced by their FL variaties. - -[ Default: S >] - -=item C - -Within environments whose name matches the regular expression in C -all latexdiff markup is removed (in pathologic cases this might lead to - inconsistent markup but this situation should be rare). - -[ Default: S >] - -=item C,C - -If both \begin and \end for a math environment (environment name matching C -or \[ and \]) -are within the same deleted block, they are replaced by a \begin and \end commands for C -rather than being commented out. - -[ Default: C=S >, C=S >] - -=item C,C - -as C,C but for equation arrays - -[ Default: C=S >, C=S >] - -=item C - -If a match to C is found within an inline math environment within a deleted or added block, then the inlined math -is surrounded by C<\mbox{>...C<}>. This is necessary as underlining does not work within inlined array environments. - -[ Default: C=S > - -=item C - -If a command in a deleted block which is also in the textcmd list matches C then an -additional command C<\addtocounter{>FC<}{-1}>, where F is the matching command, is appended in the diff file such that the numbering in the diff file remains synchronized with the -numbering in the new file. - -[ Default: C=C<(?:footnote|part|section|subsection> ... - -C<|subsubsection|paragraph|subparagraph)> ] - -=back - -=head1 COMMON PROBLEMS - -=over 10 - -=item Citations result in overfull boxes - -There is an incompatibility between the C package, which C uses for underlining and striking out in the UNDERLINE style, -the default style. In order to be able to mark up citations properly, they are placed with an C<\mbox> command in post-processing. As mboxes -cannot be broken across lines, this procedure frequently results in overfull boxes, possibly obscuring the content as it extends beyond the right margin. If this is a problem, you have two possibilities: - -1. Use C or C subtype markup (option C<-s COLOR>): If this markup is chosen, then changed citations are no longer marked up -with the wavy line (additions) or struck out (deletions), but are still highlighted in the appropriate color. - -2. Choose option C<--disable-citation-markup> which turns off the marking up of citations: deleted citations are no longer shown, and -added ctations are shown without markup. (This was the default behaviour of latexdiff at versions 0.6 and older) - -=item Changes in complicated mathematical equations result in latex processing errors - -Try options C<--math-markup=whole>. If even that fails, you can turn off mark up for equations with C<--math-markup=off>. - -=back - -=head1 BUGS - -Option allow-spaces not implemented entirely consistently. It breaks -the rules that number and type of white space does not matter, as -different numbers of inter-argument spaces are treated as significant. - -Please submit bug reports on the latexdiff project page I, -send them to user discussion list C (prior subscription -to list required, also on project webpage) -or send them to I. Include the serial number of I -(from comments at the top of the source or use B<--version>). If you come across latex -files that are error-free and conform to the specifications set out -above, and whose differencing still does not result in error-free -latex, please send me those files, ideally edited to only contain the -offending passage as long as that still reproduces the problem. If your -file relies on non-standard class files, you must include those. I will not -look at examples where I have trouble to latex the original files. - -=head1 SEE ALSO - -L, L - -=head1 PORTABILITY - -I does not make use of external commands and thus should run -on any platform supporting Perl 5.6 or higher. If files with encodings -other than ASCII or UTF-8 are processed, Perl 5.8 or higher is required. - -The standard version of I requires installation of the Perl package -C (available from I - -I) but a stand-alone -version, I, which has this package inlined, is available, too. -I requires the I command to be present. - -=head1 AUTHOR - -Version 1.0.2 -Copyright (C) 2004-2012 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 - -Contributors of fixes and additions: V. Kuhlmann, J. Paisley, N. Becker, T. Doerges, K. Huebner, -T. Connors, Sebastian Gouezel and many others. -Thanks to the many people who send in bug reports, feature suggestions, and other feedback. - -=cut - -__END__ -%%BEGIN SAFE COMMANDS -% Regex matching commands which can safely be in the -% argument of a \DIFadd or \DIFdel command (leave out the \) -arabic -dashbox -emph -fbox -framebox -hspace -math.* -makebox -mbox -pageref -ref -symbol -raisebox -rule -text.* -shortstack -usebox -dag -ddag -copyright -pounds -S -P -oe -OE -ae -AE -aa -AA -o -O -l -L -frac -ss -sqrt -ldots -cdots -vdots -ddots -alpha -beta -gamma -delta -epsilon -varepsilon -zeta -eta -theta -vartheta -iota -kappa -lambda -mu -nu -xi -pi -varpi -rho -varrho -sigma -varsigma -tau -upsilon -phi -varphi -chi -psi -omega -Gamma -Delta -Theta -Lambda -Xi -Pi -Sigma -Upsilon -Phi -Psi -Omega -ps -mp -times -div -ast -star -circ -bullet -cdot -cap -cup -uplus -sqcap -vee -wedge -setminus -wr -diamond -(?:big)?triangle.* -lhd -rhd -unlhd -unrhd -oplus -ominus -otimes -oslash -odot -bigcirc -d?dagger -amalg -leq -prec -preceq -ll -(?:sq)?su[bp]set(?:eq)? -in -vdash -geq -succ(?:eq)? -gg -ni -dashv -equiv -sim(?:eq)? -asymp -approx -cong -neq -doteq -propto -models -perp -mid -parallel -bowtie -Join -smile -frown -.*arrow -(?:long)?mapsto -.*harpoon.* -leadsto -aleph -hbar -imath -jmath -ell -wp -Re -Im -mho -prime -emptyset -nabla -surd -top -bot -angle -forall -exists -neg -flat -natural -sharp -backslash -partial -infty -Box -Diamond -triangle -clubsuit -diamondsuit -heartsuit -spadesuit -sum -prod -coprod -int -oint -big(?:sq)?c[au]p -bigvee -bigwedge -bigodot -bigotimes -bigoplus -biguplus -(?:arc)?(?:cos|sin|tan|cot)h? -csc -arg -deg -det -dim -exp -gcd -hom -inf -ker -lg -lim -liminf -limsup -ln -log -max -min -Pr -sec -sup -[Hclbdruvt] -(SUPER|SUB)SCRIPTNB -(SUPER|SUB)SCRIPT -PERCENTAGE -DOLLAR -%%END SAFE COMMANDS - -%%BEGIN TEXT COMMANDS -% Regex matching commands with a text argument (leave out the \) -addcontents.* -cc -closing -chapter -dashbox -emph -encl -fbox -framebox -footnote -footnotetext -framebox -part -(sub){0,2}section\*? -(sub)?paragraph\*? -makebox -mbox -opening -parbox -raisebox -savebox -sbox -shortstack -signature -text.* -value -underline -sqrt -(SUPER|SUB)SCRIPT -%%END TEXT COMMANDS - -%%BEGIN CONTEXT1 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -caption -%%END CONTEXT1 COMMANDS - -%%BEGIN CONTEXT2 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -title -author -date -institute -%%END CONTEXT2 COMMANDS - - -%% TYPES (Commands for highlighting changed blocks) - -%DIF UNDERLINE PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}} -\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}} -%DIF END UNDERLINE PREAMBLE - -%DIF CTRADITIONAL PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} [..\footnote{removed: #1} ]}} -%DIF END CTRADITIONAL PREAMBLE - -%DIF TRADITIONAL PREAMBLE -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{[..\footnote{removed: #1} ]}} -%DIF END TRADITIONAL PREAMBLE - -%DIF CFONT PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} \scriptsize #1}} -%DIF END CFONT PREAMBLE - -%DIF FONTSTRIKE PREAMBLE -\RequirePackage[normalem]{ulem} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{\footnotesize \sout{#1}}} -%DIF END FONTSTRIKE PREAMBLE - -%DIF CCHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}#1}\protect\cbdelete} -%DIF END CCHANGEBAR PREAMBLE - -%DIF CFONTCHBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\sf #1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\scriptsize #1}\protect\cbdelete} -%DIF END CFONTCHBAR PREAMBLE - -%DIF CULINECHBAR PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage[dvips]{changebar} -\RequirePackage{color} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\uwave{#1}}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\sout{#1}}\protect\cbdelete} -%DIF END CULINECHBAR PREAMBLE - -%DIF CHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\providecommand{\DIFadd}[1]{\protect\cbstart{#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete} -%DIF END CHANGEBAR PREAMBLE - -%DIF INVISIBLE PREAMBLE -\providecommand{\DIFadd}[1]{#1} -\providecommand{\DIFdel}[1]{} -%DIF END INVISIBLE PREAMBLE - - -%% SUBTYPES (Markers for beginning and end of changed blocks) - -%DIF SAFE PREAMBLE -\providecommand{\DIFaddbegin}{} -\providecommand{\DIFaddend}{} -\providecommand{\DIFdelbegin}{} -\providecommand{\DIFdelend}{} -%DIF END SAFE PREAMBLE - -%DIF MARGIN PREAMBLE -\providecommand{\DIFaddbegin}{\protect\marginpar{a[}} -\providecommand{\DIFaddend}{\protect\marginpar{]}} -\providecommand{\DIFdelbegin}{\protect\marginpar{d[}} -\providecommand{\DIFdelend}{\protect\marginpar{]}} -%DIF END BRACKET PREAMBLE - -%DIF DVIPSCOL PREAMBLE -%Note: only works with dvips converter -\RequirePackage{color} -\RequirePackage{dvipscol} -\providecommand{\DIFaddbegin}{\protect\nogroupcolor{blue}} -\providecommand{\DIFaddend}{\protect\nogroupcolor{black}} -\providecommand{\DIFdelbegin}{\protect\nogroupcolor{red}} -\providecommand{\DIFdelend}{\protect\nogroupcolor{black}} -%DIF END DVIPSCOL PREAMBLE - -%DIF COLOR PREAMBLE -\RequirePackage{color} -\providecommand{\DIFaddbegin}{\protect\color{blue}} -\providecommand{\DIFaddend}{\protect\color{black}} -\providecommand{\DIFdelbegin}{\protect\color{red}} -\providecommand{\DIFdelend}{\protect\color{black}} -%DIF END COLOR PREAMBLE - - -%% FLOAT TYPES - -%DIF FLOATSAFE PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%DIF IDENTICAL PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{\DIFaddbegin} -\providecommand{\DIFaddendFL}{\DIFaddend} -\providecommand{\DIFdelbeginFL}{\DIFdelbegin} -\providecommand{\DIFdelendFL}{\DIFdelend} -%DIF END IDENTICAL PREAMBLE - -%DIF TRADITIONALSAFE PREAMBLE -% procidecommand color to make this work for TRADITIONAL and CTRADITIONAL -\providecommand{\color}[1]{} -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdel}[1]{{\protect\color{red}[..{\scriptsize {removed: #1}} ]}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%% SPECIAL PACKAGE PREAMBLE COMMANDS - -% Standard \DIFadd and \DIFdel are redefined as \DIFaddtex and \DIFdeltex -% when hyperref package is included. -%DIF HYPERREF PREAMBLE -\providecommand{\DIFadd}[1]{\texorpdfstring{\DIFaddtex{#1}}{#1}} -\providecommand{\DIFdel}[1]{\texorpdfstring{\DIFdeltex{#1}}{}} -%DIF END HYPERREF PACKAGE diff --git a/latexdiff-1.0.3/latexdiff-fast b/latexdiff-1.0.3/latexdiff-fast deleted file mode 100755 index e53afc1..0000000 --- a/latexdiff-1.0.3/latexdiff-fast +++ /dev/null @@ -1,3976 +0,0 @@ -#!/usr/bin/env perl -##!/usr/bin/perl -w -# latexdiff - differences two latex files on the word level -# and produces a latex file with the differences marked up. -# -# Copyright (C) 2004-12 F J Tilmann (tilmann@gfz-potsdam.de, ftilmann@users.berlios.de) -# -# Project webpages: http://latexdiff.berlios.de/ -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# -# Version 1.0.3 -# - fix bug in add_safe_commands that made latexdiff hang on DeclareMathOperator -# command in preamble -# - \(..\) inline math expressions were not parsed correctly, if the contained a linebreak -# - applied patch contributed by tomflannaghan via Berlios: [ Patch #3431 ] Adds correct handling of \left< and \right> -# - \$ is treated correctly as a literal dollar sign (thanks to Reed Cartwright and Joshua Miller for reporting this bug -# and sketching out the solution) -# - \^ and \_ are correctly interpreted as accent and underlined space, respectively, not as superscript of subscript (thanks to Wail Yahyaoui for pointing out this bug) -# -# Version 1.0.1 - treat \big,\bigg etc. equivalently to \left and -# \right - include starred version in MATHENV - apply -# - flatten recursively and --flatten expansion is now -# aware of comments (thanks to Tim Connors for patch) -# - Change to post-processing for more reliability for -# deleted math environments -# - On linux systems, recognise and remove DOS style newlines -# - Provide markup for some special preamble commands (\title, -# \author,\date, -# - configurable by setting context2cmd -# - for styles using ulem package, remove \emph and \text.. from list of -# safe commands in order to allow linebreaks within the -# highlighted sections. -# - for ulem style, now show citations by enclosing them in \mbox commands. -# This unfortunately implies linebreaks within citations no longer function, -# so this functionality can be turned off (Option --disable-citation-markup). -# With --enable-citation-markup, the mbox markup is forced for other styles) -# - new substyle COLOR. This is particularly useful for marking up citations -# and some special post-processing is implemented to retain cite -# commands in deleted blocks. -# - four different levels of math-markup -# - Option --driver for choosing driver for modes employing changebar package -# - accept \\* as valid command (and other commands of form \.*). Also accept -# \ (backslashed newline) -# - some typo fixes, include commands defined in preamble as safe commands -# (Sebastian Gouezel) -# - include compared filenames as comments as line 2 and 3 of -# the preamble (can be modified with option --label, and suppressed with -# --no-label), option --visible-label to show files in generated pdf or dvi -# at the beginning of main document -# -# Version 0.5 A number of minor improvements based on feedback -# Deleted blocks are now shown before added blocks -# Package specific processing -# -# Version 0.43 unreleased typo in list of styles at the end -# Add protect to all \cbstart, \cbend commands -# More robust substitution of deleted math commands -# -# Version 0.42 November 06 Bug fixes only -# -# Version 0.4 March 06 option for fast differencing using UNIX diff command, several minor bug fixes (\par bug, improved highlighting of textcmds) -# -# Version 0.3 August 05 improved parsing of displayed math, --allow-spaces -# option, several minor bug fixes -# -# Version 0.25 October 04 Fix bug with deleted equations, add math mode commands to safecmd, add | to allowed interpunctuation signs -# Version 0.2 September 04 extension to utf-8 and variable encodings -# Version 0.1 August 04 First public release - -# Inserted block for differenceing -# use Algorithm::Diff qw(traverse_sequences); -# in standard version -# The following BEGIN block contains a verbatim copy of -# Ned Konz' Algorithm::Diff package version 1.15 except -# that subroutine _longestCommonSubsequence has been replace by -# a routine which internally uses the UNIX diff command for -# the differencing rather than the Perl routines if the -# length of the sequences exceeds some threshold. -# Also, all POD documentation has been stripped out. -# -# (the distribution on which this modification is based is available -# from http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15 -# the most recent version can be found via http://search.cpan.org/search?module=Algorithm::Diff ) -# Please note that the LICENCSE for Algorithm::Diff : -# "Copyright (c) 2000-2002 Ned Konz. All rights reserved. -# This program is free software; -# you can redistribute it and/or modify it under the same terms -# as Perl itself." -# The fast-differencing version of latexdiff is provided as a convenience -# for latex users under Unix-like systems which have a 'diff' command. -# If you believe -# the inlining of Algorithm::Diff violates its license please contact -# me and I will modify the latexdiff distribution accordingly. -# Frederik Tilmann (tilmann@esc.cam.ac.uk) -# Jonathan Paisley is acknowledged for the idea of using the system diff -# command to achieve shorter running times -BEGIN { -package Algorithm::Diff; -use strict; -use vars qw($VERSION @EXPORT_OK @ISA @EXPORT); -use integer; # see below in _replaceNextLargerWith() for mod to make - # if you don't use this -require Exporter; -@ISA = qw(Exporter); -@EXPORT = qw(); -@EXPORT_OK = qw(LCS diff traverse_sequences traverse_balanced sdiff); -$VERSION = sprintf('%d.%02d fast', (q$Revision: 1.15 $ =~ /\d+/g)); - -# Global parameters - -use File::Temp qw/tempfile/; -# if larger number of elements in longestCommonSubsequence smaller than -# this number, then use internal algorithm, otherwise use UNIX diff -use constant THRESHOLD => 100 ; -# Detect whether diff --minimal option is available -# if yes we use it -use constant MINIMAL => ( system('diff','--minimal','/dev/null','/dev/null') >> 8 ==0 ? "--minimal" : "" ) ; - - - -# McIlroy-Hunt diff algorithm -# Adapted from the Smalltalk code of Mario I. Wolczko, -# by Ned Konz, perl@bike-nomad.com - - -# Create a hash that maps each element of $aCollection to the set of positions -# it occupies in $aCollection, restricted to the elements within the range of -# indexes specified by $start and $end. -# The fourth parameter is a subroutine reference that will be called to -# generate a string to use as a key. -# Additional parameters, if any, will be passed to this subroutine. -# -# my $hashRef = _withPositionsOfInInterval( \@array, $start, $end, $keyGen ); - -sub _withPositionsOfInInterval -{ - my $aCollection = shift; # array ref - my $start = shift; - my $end = shift; - my $keyGen = shift; - my %d; - my $index; - for ( $index = $start ; $index <= $end ; $index++ ) - { - my $element = $aCollection->[$index]; - my $key = &$keyGen( $element, @_ ); - if ( exists( $d{$key} ) ) - { - unshift ( @{ $d{$key} }, $index ); - } - else - { - $d{$key} = [$index]; - } - } - return wantarray ? %d : \%d; -} - -# Find the place at which aValue would normally be inserted into the array. If -# that place is already occupied by aValue, do nothing, and return undef. If -# the place does not exist (i.e., it is off the end of the array), add it to -# the end, otherwise replace the element at that point with aValue. -# It is assumed that the array's values are numeric. -# This is where the bulk (75%) of the time is spent in this module, so try to -# make it fast! - -sub _replaceNextLargerWith -{ - my ( $array, $aValue, $high ) = @_; - $high ||= $#$array; - - # off the end? - if ( $high == -1 || $aValue > $array->[-1] ) - { - push ( @$array, $aValue ); - return $high + 1; - } - - # binary search for insertion point... - my $low = 0; - my $index; - my $found; - while ( $low <= $high ) - { - $index = ( $high + $low ) / 2; - - # $index = int(( $high + $low ) / 2); # without 'use integer' - $found = $array->[$index]; - - if ( $aValue == $found ) - { - return undef; - } - elsif ( $aValue > $found ) - { - $low = $index + 1; - } - else - { - $high = $index - 1; - } - } - - # now insertion point is in $low. - $array->[$low] = $aValue; # overwrite next larger - return $low; -} - -# This method computes the longest common subsequence in $a and $b. - -# Result is array or ref, whose contents is such that -# $a->[ $i ] == $b->[ $result[ $i ] ] -# foreach $i in ( 0 .. $#result ) if $result[ $i ] is defined. - -# An additional argument may be passed; this is a hash or key generating -# function that should return a string that uniquely identifies the given -# element. It should be the case that if the key is the same, the elements -# will compare the same. If this parameter is undef or missing, the key -# will be the element as a string. - -# By default, comparisons will use "eq" and elements will be turned into keys -# using the default stringizing operator '""'. - -# Additional parameters, if any, will be passed to the key generation routine. - -sub _longestCommonSubsequence -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $keyGen = shift; # code ref - my $compare; # code ref - - # set up code refs - # Note that these are optimized. - if ( !defined($keyGen) ) # optimize for strings - { - $keyGen = sub { $_[0] }; - $compare = sub { my ( $a, $b ) = @_; $a eq $b }; - } - else - { - $compare = sub { - my $a = shift; - my $b = shift; - &$keyGen( $a, @_ ) eq &$keyGen( $b, @_ ); - }; - } - - my ( $aStart, $aFinish, $bStart, $bFinish, $matchVector ) = - ( 0, $#$a, 0, $#$b, [] ); - - # Check whether to use internal routine (small number of elements) - # or use it as a wrapper for UNIX diff - if ( ( $#$a > $#$b ? $#$a : $#$b) < THRESHOLD ) { - ### print STDERR "DEBUG: regular longestCommonSubsequence\n"; - # First we prune off any common elements at the beginning - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aStart], $b->[$bStart], @_ ) ) - { - $matchVector->[ $aStart++ ] = $bStart++; - } - - # now the end - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aFinish], $b->[$bFinish], @_ ) ) - { - $matchVector->[ $aFinish-- ] = $bFinish--; - } - - # Now compute the equivalence classes of positions of elements - my $bMatches = - _withPositionsOfInInterval( $b, $bStart, $bFinish, $keyGen, @_ ); - my $thresh = []; - my $links = []; - - my ( $i, $ai, $j, $k ); - for ( $i = $aStart ; $i <= $aFinish ; $i++ ) - { - $ai = &$keyGen( $a->[$i], @_ ); - if ( exists( $bMatches->{$ai} ) ) - { - $k = 0; - for $j ( @{ $bMatches->{$ai} } ) - { - - # optimization: most of the time this will be true - if ( $k and $thresh->[$k] > $j and $thresh->[ $k - 1 ] < $j ) - { - $thresh->[$k] = $j; - } - else - { - $k = _replaceNextLargerWith( $thresh, $j, $k ); - } - - # oddly, it's faster to always test this (CPU cache?). - if ( defined($k) ) - { - $links->[$k] = - [ ( $k ? $links->[ $k - 1 ] : undef ), $i, $j ]; - } - } - } - } - - if (@$thresh) - { - for ( my $link = $links->[$#$thresh] ; $link ; $link = $link->[0] ) - { - $matchVector->[ $link->[1] ] = $link->[2]; - } - } - } - else { - my ($fha,$fhb,$fna,$fnb,$ele,$key); - my ($alines,$blines,$alb,$alf,$blb,$blf); - my ($minimal)=MINIMAL; - # large number of elements, use system diff - ### print STDERR "DEBUG: fast (diff) longestCommonSubsequence\n"; - - ($fha,$fna)=tempfile("DiffA-XXXX") or die "_longestCommonSubsequence: Cannot open tempfile for sequence A"; - ($fhb,$fnb)=tempfile("DiffB-XXXX") or die "_longestCommonSubsequence: Cannot open tempfile for sequence B"; - # prepare sequence A - foreach $ele ( @$a ) { - $key=&$keyGen( $ele, @_ ); - $key =~ s/\\/\\\\/g ; - $key =~ s/\n/\\n/sg ; - print $fha "$key\n" ; - } - close($fha); - # prepare sequence B - foreach $ele ( @$b ) { - $key=&$keyGen( $ele, @_ ); - $key =~ s/\\/\\\\/g ; - $key =~ s/\n/\\n/sg ; - print $fhb "$key\n" ; - } - close($fhb); - - open(DIFFPIPE, "diff $minimal $fna $fnb |") or die "_longestCommonSubsequence: Cannot launch diff process. $!" ; - # The diff line numbering begins with 1, but Perl subscripts start with 0 - # We follow the diff numbering but substract 1 when assigning to matchVector - $aStart++; $bStart++ ; $aFinish++ ; $bFinish++ ; - while( ) { - if ( ($alines,$blines) = ( m/^(\d*(?:,\d*)?)?c(\d*(?:,\d*)?)?$/ ) ) { - ($alb,$alf)=split(/,/,$alines); - ($blb,$blf)=split(/,/,$blines); - $alf=$alb unless defined($alf); - $blf=$blb unless defined($blf); - while($aStart < $alb ) { - $matchVector->[ -1 + $aStart++ ] = -1 + $bStart++ ; - } - # check for consistency - $bStart==$blb or die "_longestCommonSubsequence: Fatal error in interpreting diff output: Inconsistency in changed sequence"; - $aStart=$alf+1; - $bStart=$blf+1; - } - elsif ( ($alb,$blines) = ( m/^(\d*)a(\d*(?:,\d*)?)$/ ) ) { - ($blb,$blf)=split(/,/,$blines); - $blf=$blb unless defined($blf); - while ( $bStart < $blb ) { - $matchVector->[ -1 + $aStart++ ] = -1 + $bStart++ ; - } - $aStart==$alb+1 or die "_longestCommonSubsequence: Fatal error in interpreting diff output: Inconsistency in appended sequence near elements $aStart and $bStart"; - $bStart=$blf+1; - } - elsif ( ($alines,$blb) = ( m/^(\d*(?:,\d*)?)d(\d*)$/ ) ) { - ($alb,$alf)=split(/,/,$alines); - $alf=$alb unless defined($alf); - while ( $aStart < $alb ) { - $matchVector->[ -1 + $aStart++ ] = -1 + $bStart++ ; - } - $bStart==$blb+1 or die "_longestCommonSubsequence: Fatal error in interpreting diff output: Inconsistency in deleted sequence near elements $aStart and $bStart"; - $aStart=$alf+1; - } - elsif ( m/^Binary files/ ) { - # if diff reports it is a binary file force --text mode. I do not like - # to always use this option because it is probably only available in GNU diff - open(DIFFPIPE, "diff --text $fna $fnb |") or die "Cannot launch diff process. $!" ; - } - # Default: just skip line - } - while ($aStart <= $aFinish ) { - $matchVector->[ -1 + $aStart++ ] = -1 + $bStart++ ; - } - $bStart==$bFinish+1 or die "_longestCommonSubsequence: Fatal error in interpreting diff output: Inconsistency at end"; - close DIFFPIPE; - # check whether a system error has occurred or return status is greater than or equal to 5 - if ( $! || ($? >> 8) > 5) { - print STDERR "diff process failed with exit code ", ($? >> 8), " $!\n"; - die; - } - unlink $fna,$fnb ; - } - return wantarray ? @$matchVector : $matchVector; -} - -sub traverse_sequences -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $finishedACallback = $callbacks->{'A_FINISHED'}; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $finishedBCallback = $callbacks->{'B_FINISHED'}; - my $matchVector = _longestCommonSubsequence( $a, $b, $keyGen, @_ ); - - # Process all the lines in @$matchVector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai; - - for ( $ai = 0 ; $ai <= $#$matchVector ; $ai++ ) - { - my $bLine = $matchVector->[$ai]; - if ( defined($bLine) ) # matched - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi < $bLine; - &$matchCallback( $ai, $bi++, @_ ); - } - else - { - &$discardACallback( $ai, $bi, @_ ); - } - } - - # The last entry (if any) processed was a match. - # $ai and $bi point just past the last matching lines in their sequences. - - while ( $ai <= $lastA or $bi <= $lastB ) - { - - # last A? - if ( $ai == $lastA + 1 and $bi <= $lastB ) - { - if ( defined($finishedACallback) ) - { - &$finishedACallback( $lastA, @_ ); - $finishedACallback = undef; - } - else - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi <= $lastB; - } - } - - # last B? - if ( $bi == $lastB + 1 and $ai <= $lastA ) - { - if ( defined($finishedBCallback) ) - { - &$finishedBCallback( $lastB, @_ ); - $finishedBCallback = undef; - } - else - { - &$discardACallback( $ai++, $bi, @_ ) while $ai <= $lastA; - } - } - - &$discardACallback( $ai++, $bi, @_ ) if $ai <= $lastA; - &$discardBCallback( $ai, $bi++, @_ ) if $bi <= $lastB; - } - - return 1; -} - -sub traverse_balanced -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $changeCallback = $callbacks->{'CHANGE'}; - my $matchVector = _longestCommonSubsequence( $a, $b, $keyGen, @_ ); - - # Process all the lines in match vector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai = 0; - my $ma = -1; - my $mb; - - while (1) - { - - # Find next match indices $ma and $mb - do { $ma++ } while ( $ma <= $#$matchVector && !defined $matchVector->[$ma] ); - - last if $ma > $#$matchVector; # end of matchVector? - $mb = $matchVector->[$ma]; - - # Proceed with discard a/b or change events until - # next match - while ( $ai < $ma || $bi < $mb ) - { - - if ( $ai < $ma && $bi < $mb ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai < $ma ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi < $mb - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - # Match - &$matchCallback( $ai++, $bi++, @_ ); - } - - while ( $ai <= $lastA || $bi <= $lastB ) - { - if ( $ai <= $lastA && $bi <= $lastB ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai <= $lastA ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi <= $lastB - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - return 1; -} - -sub LCS -{ - my $a = shift; # array ref - my $matchVector = _longestCommonSubsequence( $a, @_ ); - my @retval; - my $i; - for ( $i = 0 ; $i <= $#$matchVector ; $i++ ) - { - if ( defined( $matchVector->[$i] ) ) - { - push ( @retval, $a->[$i] ); - } - } - return wantarray ? @retval : \@retval; -} - -sub diff -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $hunk = []; - my $discard = sub { push ( @$hunk, [ '-', $_[0], $a->[ $_[0] ] ] ) }; - my $add = sub { push ( @$hunk, [ '+', $_[1], $b->[ $_[1] ] ] ) }; - my $match = sub { push ( @$retval, $hunk ) if scalar(@$hunk); $hunk = [] }; - traverse_sequences( $a, $b, - { MATCH => $match, DISCARD_A => $discard, DISCARD_B => $add }, @_ ); - &$match(); - return wantarray ? @$retval : $retval; -} - -sub sdiff -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $discard = sub { push ( @$retval, [ '-', $a->[ $_[0] ], "" ] ) }; - my $add = sub { push ( @$retval, [ '+', "", $b->[ $_[1] ] ] ) }; - my $change = sub { - push ( @$retval, [ 'c', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - my $match = sub { - push ( @$retval, [ 'u', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - traverse_balanced( - $a, - $b, - { - MATCH => $match, - DISCARD_A => $discard, - DISCARD_B => $add, - CHANGE => $change, - }, - @_ - ); - return wantarray ? @$retval : $retval; -} - -1; -} -import Algorithm::Diff qw(traverse_sequences); -# End of inserted block for stand-alone version - - -use Getopt::Long ; -use strict ; -use warnings; -use utf8 ; - -my ($algodiffversion)=split(/ /,$Algorithm::Diff::VERSION); - - -my ($versionstring)=< 0, - WHOLE => 1, - COARSE => 2, - FINE => 3 -}; - - -my (@configlist,@labels, - @appendsafelist,@excludesafelist, - @appendtextlist,@excludetextlist, - @appendcontext1list,@appendcontext2list, - @packagelist); -my ($assign,@config); -# Hash where keys corresponds to the names of all included packages (including the documentclass as another package -# the optional arguments to the package are the values of the hash elements -my ($pkg,%packages); -# Defaults -$type='UNDERLINE'; -$subtype='SAFE'; -$floattype='FLOATSAFE'; -$mathmarkup=COARSE; - -$verbose=0; -# output debug and intermediate files, set to 0 in final distribution -$debug=0; -# define character properties -sub IsNonAsciiPunct { return <<'END' # Unicode punctuation but excluding ASCII punctuation -+utf8::IsPunct --utf8::IsASCII -END -} -sub IsNonAsciiS { return <<'END' # Unicode symbol but excluding ASCII -+utf8::IsS --utf8::IsASCII -END -} - - -my %verbhash; - -Getopt::Long::Configure('bundling'); -GetOptions('type|t=s' => \$type, - 'subtype|s=s' => \$subtype, - 'floattype|f=s' => \$floattype, - 'config|c=s' => \@configlist, - 'preamble|p=s' => \$preamblefile, - 'encoding|e=s' => \$encoding, - 'label|L=s' => \@labels, - 'no-label' => \$nolabel, - 'visible-label' => \$visiblelabel, - 'exclude-safecmd|A=s' => \@excludesafelist, - 'replace-safecmd=s' => \$replacesafe, - 'append-safecmd|a=s' => \@appendsafelist, - 'exclude-textcmd|X=s' => \@excludetextlist, - 'replace-textcmd=s' => \$replacetext, - 'append-textcmd|x=s' => \@appendtextlist, - 'replace-context1cmd=s' => \$replacecontext1, - 'append-context1cmd=s' => \@appendcontext1list, - 'replace-context2cmd=s' => \$replacecontext2, - 'append-context2cmd=s' => \@appendcontext2list, - 'show-preamble' => \$showpreamble, - 'show-safecmd' => \$showsafe, - 'show-textcmd' => \$showtext, - 'show-config' => \$showconfig, - 'show-all' => \$showall, - 'packages=s' => \@packagelist, - 'allow-spaces' => \$allowspaces, - 'math-markup=s' => \$mathmarkup, - 'enable-citation-markup' => \$enablecitmark, - 'disable-citation-markup' => \$disablecitmark, - 'verbose|V' => \$verbose, - 'ignore-warnings' => \$ignorewarnings, - 'driver=s'=> \$driver, - 'flatten' => \$flatten, - 'version' => \$version, - 'help|h|H' => \$help); - -if ( $help ) { - usage() ; -} - - -if ( $version ) { - die $versionstring ; -} - -print STDERR $versionstring if $verbose; - -if (defined($showall)){ - $showpreamble=$showsafe=$showtext=$showconfig=1; -} - -if (defined($mathmarkup)) { - $mathmarkup=~tr/a-z/A-Z/; - if ( $mathmarkup eq 'OFF' ){ - $mathmarkup=OFF; - } elsif ( $mathmarkup eq 'WHOLE' ){ - $mathmarkup=WHOLE; - } elsif ( $mathmarkup eq 'COARSE' ){ - $mathmarkup=COARSE; - } elsif ( $mathmarkup eq 'FINE' ){ - $mathmarkup=FINE; - } elsif ( $mathmarkup !~ m/^[0123]$/ ) { - die "Illegal value: ($mathmarkup) for option--math-markup. Possible values: OFF,WHOLE,COARSE,FINE,0- "; - } - # else use numerical value -} - -# setting extra preamble commands -if (defined($preamblefile)) { - $latexdiffpreamble=join "\n",(extrapream($preamblefile),""); -} else { - $latexdiffpreamble=join "\n",(extrapream($type,$subtype,$floattype),""); -} - -if ( defined($driver) ) { - # for changebar only - $latexdiffpreamble=~s/\[dvips\]/[$driver]/sg; -} -# setting up @SAFECMDLIST and @SAFECMDEXCL -if (defined($replacesafe)) { - init_regex_arr_ext(\@SAFECMDLIST,$replacesafe); -} else { - init_regex_arr_data(\@SAFECMDLIST, "SAFE COMMANDS"); -} -foreach $appendsafe ( @appendsafelist ) { - init_regex_arr_ext(\@SAFECMDLIST, $appendsafe); -} -foreach $excludesafe ( @excludesafelist ) { - init_regex_arr_ext(\@SAFECMDEXCL, $excludesafe); -} - -# Special: treat all cite commands as safe except in UNDERLINE and FONTSTRIKE mode -# (there is a conflict between citation and ulem package, see -# package documentation) -# Use post-processing - -if ( uc($type) ne "UNDERLINE" && uc($type) ne "FONTSTRIKE" && uc($type) ne "CULINECHBAR" ) { - push (@SAFECMDLIST, qr/^cite.*$/); -} else { - ### Experimental: disable text and emph commands - push (@SAFECMDLIST, qr/^cite.*$/) unless $disablecitmark; - push(@SAFECMDEXCL, qr/^emph$/, qr/^text..$/); - # replace \cite{..} by \mbox{\cite{..}} in added or deleted blocks in post-processing - if ( uc($subtype) eq "COLOR" or uc($subtype) eq "DVIPSCOL" ) { - # remove \cite command again from list of safe commands - pop @SAFECMDLIST; - # deleted cite commands - $CITE2CMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite-type commands which should be reinstated in deleted blocks - } else { - $CITECMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite commands which need to be protected within an mbox in UNDERLINE and other modes using ulem - } -} -$CITECMD='(?:cite\w*|nocite)' if $enablecitmark ; # as above for explicit selection - -# setting up @TEXTCMDLIST and @TEXTCMDEXCL -if (defined($replacetext)) { - init_regex_arr_ext(\@TEXTCMDLIST,$replacetext); -} else { - init_regex_arr_data(\@TEXTCMDLIST, "TEXT COMMANDS"); -} -foreach $appendtext ( @appendtextlist ) { - init_regex_arr_ext(\@TEXTCMDLIST, $appendtext); -} -foreach $excludetext ( @excludetextlist ) { - init_regex_arr_ext(\@TEXTCMDEXCL, $excludetext); -} - - -# setting up @CONTEXT1CMDLIST ( @CONTEXT1CMDEXCL exist but is always empty ) -if (defined($replacecontext1)) { - init_regex_arr_ext(\@CONTEXT1CMDLIST,$replacecontext1); -} else { - init_regex_arr_data(\@CONTEXT1CMDLIST, "CONTEXT1 COMMANDS"); -} -foreach $appendcontext1 ( @appendcontext1list ) { - init_regex_arr_ext(\@CONTEXT1CMDLIST, $appendcontext1); -} - - -# setting up @CONTEXT2CMDLIST ( @CONTEXT2CMDEXCL exist but is always empty ) -if (defined($replacecontext2)) { - init_regex_arr_ext(\@CONTEXT2CMDLIST,$replacecontext2); -} else { - init_regex_arr_data(\@CONTEXT2CMDLIST, "CONTEXT2 COMMANDS"); -} -foreach $appendcontext2 ( @appendcontext2list ) { - init_regex_arr_ext(\@CONTEXT2CMDLIST, $appendcontext2); -} - -# setting configuration variables -@config=(); -foreach $config ( @configlist ) { - if (-f $config ) { - open(FILE,$config) or die ("Couldn't open configuration file $config: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@config,$_); - } - close(FILE); - } - else { -# foreach ( split(",",$config) ) { -# push @config,$_; -# } - push @config,split(",",$config) - } -} -foreach $assign ( @config ) { - $assign=~ m/\s*(\w*)\s*=\s*(\S*)\s*$/ or die "Illegal assignment $assign in configuration list (must be variable=value)"; - if ( $1 eq "MINWORDSBLOCK" ) { $MINWORDSBLOCK = $2; } - elsif ( $1 eq "FLOATENV" ) { $FLOATENV = $2 ; } - elsif ( $1 eq "PICTUREENV" ) { $PICTUREENV = $2 ; } - elsif ( $1 eq "MATHENV" ) { $MATHENV = $2 ; } - elsif ( $1 eq "MATHREPL" ) { $MATHREPL = $2 ; } - elsif ( $1 eq "MATHARRENV" ) { $MATHARRENV = $2 ; } - elsif ( $1 eq "MATHARRREPL" ) { $MATHARRREPL = $2 ; } - elsif ( $1 eq "ARRENV" ) { $ARRENV = $2 ; } - elsif ( $1 eq "COUNTERCMD" ) { $COUNTERCMD = $2 ; } - else { die "Unknown variable $1 in assignment.";} -} - -if ( $mathmarkup == COARSE || $mathmarkup == WHOLE ) { - push(@MATHTEXTCMDLIST,qr/^MATHBLOCK(?:$MATHENV|$MATHARRENV|SQUAREBRACKET)$/); -} - - - -foreach $pkg ( @packagelist ) { - map { $packages{$_}="" } split(/,/,$pkg) ; -} - -if ($showpreamble) { - print "\nPreamble commands:\n"; - print $latexdiffpreamble ; -} - -if ($showsafe) { - print "\nCommands safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE (unless excluded):\n"; - print_regex_arr(@SAFECMDLIST); - print "\nCommands not safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE :\n"; - print_regex_arr(@SAFECMDEXCL); -} - -if ($showtext) { - print "\nCommands with last argument textual (unless excluded) and safe in every context:\n"; - print_regex_arr(@TEXTCMDLIST); - print "\nContext1 commands (last argument textual, command will be disabled in deleted passages, last argument will be shown as plain text):\n"; - print_regex_arr(@CONTEXT1CMDLIST); - print "\nContext2 commands (last argument textual, command and its argument will be disabled in deleted passages):\n"; - print_regex_arr(@CONTEXT2CMDLIST); - print "\nExclude list of Commands with last argument not textual (overrides patterns above):\n"; - print_regex_arr(@TEXTCMDEXCL); -} - - -if ($showconfig) { - print "Configuration variables:\n"; - print "MINWORDSBLOCK=$MINWORDSBLOCK\n"; - print "FLOATENV=$FLOATENV\n"; - print "PICTUREENV=$PICTUREENV\n"; - print "MATHENV=$MATHENV\n"; - print "MATHREPL=$MATHREPL\n"; - print "MATHARRENV=$MATHARRENV\n"; - print "MATHARRREPL=$MATHARRREPL\n"; - print "ARRENV=$ARRENV\n"; - print "COUNTERCMD=$COUNTERCMD\n"; -} -if ($showconfig || $showtext || $showsafe || $showpreamble) { - exit 0; } -if ( @ARGV != 2 ) { - print STDERR "2 and only 2 non-option arguments required. Write latexdiff -h to get help\n"; - exit(2); -} - -# Are extra spaces between command arguments permissible? -my $extraspace; -if ($allowspaces) { - $extraspace='\s*'; -} else { - $extraspace=''; -} - -# append context lists to text lists (as text property is implied) -push @TEXTCMDLIST, @CONTEXT1CMDLIST; -push @TEXTCMDLIST, @CONTEXT2CMDLIST; - -push @TEXTCMDLIST, @MATHTEXTCMDLIST if $mathmarkup==COARSE; - -# internal additions to SAFECMDLIST -push(@SAFECMDLIST, qr/^QLEFTBRACE$/, qr/^QRIGHTBRACE$/); - - -# Patterns. These are used by some of the subroutines, too -# I can only define them down here because value of extraspace depends on an option - my $pat0 = '(?:[^{}])*'; - my $pat1 = '(?:[^{}]|\{'.$pat0.'\})*'; - my $pat2 = '(?:[^{}]|\{'.$pat1.'\})*'; - my $pat3 = '(?:[^{}]|\{'.$pat2.'\})*'; - my $pat4 = '(?:[^{}]|\{'.$pat3.'\})*'; - my $pat5 = '(?:[^{}]|\{'.$pat4.'\})*'; - my $pat6 = '(?:[^{}]|\{'.$pat5.'\})*'; - my $brat0 = '(?:[^\[\]]|\\\[|\\\])*'; - - my $quotemarks = '(?:\'\')|(?:\`\`)'; - my $punct='[0.,\/\'\`:;\"\?\(\)\[\]!~\p{IsNonAsciiPunct}\p{IsNonAsciiS}]'; - my $number='-?\d*\.\d*'; - my $mathpunct='[+=<>\-\|]'; - my $and = '&'; - my $coords= '[\-.,\s\d]*'; -# word: sequence of letters or accents followed by letter - my $word='(?:[-\w\d*]|\\\\[\"\'\`~^][A-Za-z\*])+'; - my $cmdleftright='\\\\(?:left|right|[Bb]igg?[lrm]?|middle)\s*(?:[<>()\[\]|]|\\\\(?:[|{}]|\w+))'; - - my $cmdoptseq='\\\\[\w\d\*]+'.$extraspace.'(?:(?:\['.$brat0.'\]|\{'. $pat6 . '\}|\(' . $coords .'\))'.$extraspace.')*'; - my $backslashnl='\\\\\n'; - my $oneletcmd='\\\\.\*?(?:\['.$brat0.'\]|\{'. $pat6 . '\})*'; - my $math='\$(?:[^$]|\\\$)*?\$|\\\\[(](?:.|\n)*?\\\\[)]'; -## the current maths command cannot cope with newline within the math expression - - my $comment='%.*?\n'; - my $pat=qr/(?:\A\s*)?(?:${and}|${quotemarks}|${number}|${word}|$cmdleftright|${cmdoptseq}|${math}|${backslashnl}|${oneletcmd}|${comment}|${punct}|${mathpunct}|\{|\})\s*/ ; - - - -# now we are done setting up and can start working -my ($oldfile, $newfile) = @ARGV; -# check for existence of input files -if ( ! -e $oldfile ) { - die "Input file $oldfile does not exist."; -} -if ( ! -e $newfile ) { - die "Input file $newfile does not exist."; -} - - -# set the labels to be included into the file -my ($oldtime,$newtime,$oldlabel,$newlabel); -if (defined($labels[0])) { - $oldlabel=$labels[0] ; -} else { - $oldtime=localtime((stat($oldfile))[9]); - $oldlabel="$oldfile " . " "x(length($newfile)-length($oldfile)) . $oldtime; -} -if (defined($labels[1])) { - $newlabel=$labels[1] ; -} else { - $newtime=localtime((stat($newfile))[9]); - $newlabel="$newfile " . " "x(length($oldfile)-length($newfile)) . $newtime; -} - -$encoding=guess_encoding($newfile) unless defined($encoding); - -$encoding = "utf8" if $encoding =~ m/^utf8/i ; -if (lc($encoding) eq "utf8" ) { - binmode(STDOUT, ":utf8"); - binmode(STDERR, ":utf8"); -} - -$old=read_file_with_encoding($oldfile,$encoding); -$new=read_file_with_encoding($newfile,$encoding); - - - - -# reset time -exetime(1); -($oldpreamble,$oldbody,$oldpost)=splitdoc($old,'\\\\begin\{document\}','\\\\end\{document\}'); - - -($newpreamble,$newbody,$newpost)=splitdoc($new,'\\\\begin\{document\}','\\\\end\{document\}'); - - -if ($flatten) { - $oldbody=flatten($oldbody,$oldpreamble,$oldfile,$encoding); - $newbody=flatten($newbody,$newpreamble,$newfile,$encoding); -} - -my @auxlines; -if ( length $oldpreamble && length $newpreamble ) { - # pre-process preamble by looking for commands used in \maketitle (title, author, date etc commands) - # and marking up content with latexdiff markup - @auxlines=preprocess_preamble($oldpreamble,$newpreamble); - - @oldpreamble = split /\n/, $oldpreamble; - @newpreamble = split /\n/, $newpreamble; - - # If a command is defined in the preamble of the new file, and only uses safe commands, then it can be considered to be safe) (contribution S. Gouezel) - # Base this assessment on the new preamble - add_safe_commands($newpreamble); - - %packages=list_packages(@newpreamble) unless %packages; - if (defined $packages{"hyperref"} ) { - print STDERR "hyperref package detected.\n" if $verbose ; - $latexdiffpreamble =~ s/\{\\DIFadd\}/{\\DIFaddtex}/g; - $latexdiffpreamble =~ s/\{\\DIFdel\}/{\\DIFdeltex}/g; - $latexdiffpreamble .= join "\n",(extrapream("HYPERREF"),""); - } - print STDERR "Differencing preamble.\n" if $verbose; - - # insert dummy first line such that line count begins with line 1 (rather than perl's line 0) - just so that line numbers inserted by linediff are correct - unshift @newpreamble,''; - unshift @oldpreamble,''; - @diffpreamble = linediff(\@oldpreamble, \@newpreamble); - # remove dummy line again - shift @diffpreamble; - # add filenames, modification time and latexdiff mark - defined($nolabel) or splice @diffpreamble,1,0, - "%DIF LATEXDIFF DIFFERENCE FILE", - ,"%DIF DEL $oldlabel", - "%DIF ADD $newlabel"; - if ( @auxlines ) { - push @diffpreamble,"%DIF DELETED TITLE COMMANDS FOR MARKUP"; - push @diffpreamble,join("\n",@auxlines); - } - push @diffpreamble,$latexdiffpreamble; - push @diffpreamble,'\begin{document}'; -} -elsif ( !length $oldpreamble && !length $newpreamble ) { - @diffpreamble=(); -} else { - print STDERR "Either both texts must have preamble or neither text must have the preamble.\n"; - exit(2); -} - -if (defined $packages{"amsmath"} or defined $packages{"amsart"} or defined $packages{"amsbook"} ) { - print STDERR "amsmath package detected.\n" if $verbose ; - $MATHARRREPL='align*'; -} - -print STDERR "Preprocessing body. " if $verbose; -my ($oldleadin,$newleadin)=preprocess($oldbody,$newbody); - - -# run difference algorithm -@diffbody=bodydiff($oldbody, $newbody); -$diffbo=join("",@diffbody); -if ( $debug ) { - open(RAWDIFF,">","latexdiff.debug.bodydiff"); - print RAWDIFF $diffbo; - close(RAWDIFF); -} -print STDERR "(",exetime()," s)\n","Postprocessing body. \n " if $verbose; -postprocess($diffbo); -$diffall =join("\n",@diffpreamble) ; -# add visible labels -if (defined($visiblelabel)) { - # Give information right after \begin{document} (or at the beginning of the text for files without preamble - ### if \date command is used, add information to \date argument, otherwise give right after \begin{document} - ### $diffall=~s/(\\date$extraspace(?:\[$brat0\])?$extraspace)\{($pat6)\}/$1\{$2 \\ LATEXDIFF comparison \\ Old: $oldlabel \\ New: $newlabel \}/ or - $diffbo = "\\begin{verbatim}LATEXDIFF comparison\nOld: $oldlabel\nNew: $newlabel\\end{verbatim}\n$diffbo" ; -} - -$diffall .= "$newleadin$diffbo" ; -$diffall .= "\\end{document}$newpost" if length $newpreamble ; -if ( lc($encoding) ne "utf8" && lc($encoding) ne "ascii" ) { - print STDERR "Encoding output file to $encoding\n" if $verbose; - $diffall=Encode::encode($encoding,$diffall); - binmode STDOUT; -} -print $diffall; - - -print STDERR "(",exetime()," s)\n","Done.\n" if $verbose; - - - -## guess_encoding(filename) -## reads the first 20 lines of filename and looks for call of inputenc package -## if found, return the option of this package (encoding), otherwise return ascii -sub guess_encoding { - my ($filename)=@_; - my ($i,$enc); - open (FH, $filename) or die("Couldn't open $filename: $!"); - $i=0; - while () { - next if /^\s*%/; # skip comment lines - if (m/\\usepackage\[(\w*?)\]\{inputenc\}/) { - close(FH); - return($1); - } - last if (++$i > 20 ); # scan at most 20 non-comment lines - } - close(FH); - return("ascii"); -} - - -sub read_file_with_encoding { - my ($output); - my ($filename, $encoding) = @_; - - if (lc($encoding) eq "utf8" ) { - open (FILE, "<:utf8",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } elsif ( lc($encoding) eq "ascii") { - open (FILE, $filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } else { - require Encode; - open (FILE, "<",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - print STDERR "Converting $filename from $encoding to utf8\n" if $verbose; - $output=Encode::decode($encoding,$output); - } - close FILE; - if ($^O eq "linux" ) { - $output =~ s/\r\n/\n/g ; - } - return $output; -} - -# %packages=list_packages(@preamble) -# scans the arguments for \documentclass and \usepackage statements and constructs a hash -# whose keys are the included packages, and whose values are the associated optional arguments -sub list_packages { - my (@preamble)=@_; - my %packages=(); - foreach $line ( @preamble ) { - # get rid of comments - $line=~s/(?catfile($dirname,$fname), "\n" if $debug; - # content of file becomes replacement value (use recursion), add \newpage if the command was include - ###$replacement=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - $replacement=flatten(read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding), $preamble,$filename,$encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - # \include always starts a new page; use explicit \newpage command to simulate this - $begline=(defined($1)? $1 : "") ; - $newpage=(defined($3)? " \\newpage " : "") ; - "$begline$newpage$replacement$newpage"; - }/exgm; - - return($text); -} - - -# print_regex_arr(@arr) -# prints regex array without x-ism expansion put in by pearl to stdout -sub print_regex_arr { - my $dumstring; - $dumstring = join(" ",@_); # PERL generates string (?-xism:^ref$) for quoted refex ^ref$ - $dumstring =~ s/\(\?-xism:\^(.*?)\$\)/$1/g; # remove string and ^,$ marks before output - print $dumstring,"\n"; -} - - -# @lines=extrapream($type) -# reads line from appendix (end of file after __END__ token) -sub extrapream { - my $type; - my @retval=("%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - my ($copy); - - while (@_) { - $copy=0; - $type=shift ; - if ( -f $type ) { - open (FILE,$type) or die "Cannot open preamble file $type: $!"; - print STDERR "Reading preamble file $type\n" if $verbose ; - while () { - chomp ; - if ( $_ =~ m/%DIF PREAMBLE/ ) { - push (@retval,"$_"); - } else { - push (@retval,"$_ %DIF PREAMBLE"); - } - } - } - else { # not (-f $type) - $type=uc($type); # upcase argument - print STDERR "Preamble Internal Type $type\n" if $verbose; - while () { - if ( m/^%DIF $type/ ) { - $copy=1; } - elsif ( m/^%DIF END $type/ ) { - last; } - chomp; - push (@retval,"$_ %DIF PREAMBLE") if $copy; - } - if ( $copy == 0 ) { - print STDERR "\nPreamble style $type not implemented.\n"; - print STDERR "Write latexdiff -h to get help with available styles\n"; - exit(2); - } - seek DATA,0,0; # rewind DATA handle to file begin - } - } - push (@retval,"%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - return @retval; -} - - -# ($part1,$part2,$part3)=splitdoc($text,$word1,$word2) -# splits $text into 3 parts at $word1 and $word2. -# if neither $word1 nor $word2 exist, $part1 and $part3 are empty, $part2 is $text -# If only $word1 or $word2 exist but not the other, output an error message. - -# NB this version avoids $` and $' for performance reason although it only makes a tiny difference -# (in one test gain a tenth of a second for a 30s run) -sub splitdoc { - my ($text,$word1,$word2)=@_; - my ($part1,$part2,$part3)=("","",""); - my ($rest,$pos); - - if ( $text =~ m/(^[^%]*)($word1)/mg ) { - $pos=pos $text; - $part1=substr($text,0,$pos-length($2)); - $rest=substr($text,$pos); - if ( $rest =~ m/(^[^%]*)($word2)/mg ) { - $pos=pos $rest; - $part2=substr($rest,0,$pos-length($2)); - $part3=substr($rest,$pos); - } - else { - die "$word1 and $word2 not in the correct order or not present as a pair." ; - } - } else { - $part2=$text; - die "$word2 present but not $word1." if ( $text =~ m/(^[^%]*)$word2/ms ); - } - return ($part1,$part2,$part3); -} - - - - - -# bodydiff($old,$new) -sub bodydiff { - my ($oldwords, $newwords) = @_; - my @retwords; - - print STDERR "(",exetime()," s)\n","Splitting into latex tokens \n" if $verbose; - print STDERR "Parsing $oldfile \n" if $verbose; - my @oldwords = splitlatex($oldwords); - print STDERR "Parsing $newfile \n" if $verbose; - my @newwords = splitlatex($newwords); - - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - print STDERR "(",exetime()," s)\n","Pass 1: Expanding text commands and merging isolated identities with changed blocks " if $verbose; - pass1(\@oldwords, \@newwords); - - - print STDERR "(",exetime()," s)\n","Pass 2: inserting DIF tokens and mark up. " if $verbose; - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold2.tex"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew2.tex"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - @retwords=pass2(\@oldwords, \@newwords); - - return(@retwords); -} - - - - -# @words=splitlatex($string) -# split string according to latex rules -# Each element of words is either -# a word (including trailing spaces and punctuation) -# a latex command -sub splitlatex { - my ($string) = @_ ; - # if input is empty, return empty list - length($string)>0 or return (); - - my @retval=($string =~ m/$pat/osg); - - if (length($string) != length(join("",@retval))) { - print STDERR "\nWARNING: Inconsistency in length of input string and parsed string:\n This often indicates faulty or non-standard latex code.\n In many cases you can ignore this and the following warning messages.\n Note that character numbers in the following are counted beginning after \\begin{document} and are only approximate." unless $ignorewarnings; - print STDERR "DEBUG Original length ",length($string)," Parsed length ",length(join("",@retval)),"\n" if $debug; - print STDERR "DEBUG Input string: |$string|\n" if (length($string)<500) && $debug; - print STDERR "DEBUG Token parsing: |",join("+",@retval),"|\n" if (length($string)<500) && $debug ; - @retval=(); - # slow way only do this if other m//sg method fails - my $last = 0; - while ( $string =~ m/$pat/osg ) { - my $match=$&; - if ($last + length $& != pos $string ) { - my $pos=pos($string); - my $offset=30<$last ? 30 : $last; - my $dum=substr($string,$last-$offset,$pos-$last+2*$offset); - my $dum1=$dum; - my $cnt=$#retval; - my $i; - $dum1 =~ s/\n/ /g; - unless ($ignorewarnings) { - print STDERR "\n$dum1\n"; - print STDERR " " x 30,"^" x ($pos-$last)," " x 30,"\n"; - print STDERR "Missing characters near word " . (scalar @retval) . " character index: " . $last . "-" . pos($string) . " Length: " . length($match) . " Match: |$match| (expected match marked above).\n"; - } - # put in missing characters `by hand' - push (@retval, substr($dum,$offset,$pos-$last-length($match))); -# Note: there seems to be a bug in substr with utf8 that made the following line output substr which were too long, -# using dum instead appears to work -# push (@retval, substr($string,$last, pos($string)-$last-length($match))); - } - push (@retval, $match); - $last=pos $string; - } - - } - return @retval; -} - - -# pass1( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Where an common-subsequence block is flanked by deleted or appended blocks, -# and is shorter than $MINWORDSBLOCK words it is appended -# to the last deleted or appended word. If the block contains tokens other than words -# or punctuation it is not merged. -# Deleted or appended block consisting of words and safe commands only are -# also merged, to prevent break-up in pass2 (after previous isolated words have been removed) -# If there are commands with textual arguments (e.g. \caption) both in corresponding -# appended and deleted blocks split them such that the command and opening bracket -# are one token, then the rest is split up following standard rules, and the closing -# bracket is a separate token, ie. turn -# "\caption{This is a textual argument}" into -# ("\caption{","This ","is ","a ","textual ","argument","}") -# No return value. Destructively changes sequences -sub pass1 { - my $seq1 = shift ; - my $seq2 = shift ; - - my $len1 = scalar @$seq1; - my $len2 = scalar @$seq2; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - - my ($last1,$last2)=(-1,-1) ; - my $cnt=0; - my $block=[]; - my $addblock=[]; - my $delblock=[]; - my $todo=[]; - my $instruction=[]; - my $i; - my (@delmid,@addmid,@dummy); - - my ($addcmds,$delcmds,$matchindex); - my ($addtextblocks,$deltextblocks); - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $adddiscard = sub { - if ($cnt > 0 ) { - $matblkcnt++; - # just after an unchanged block -# print STDERR "Unchanged block $cnt, $last1,$last2 \n"; - if ($cnt < $MINWORDSBLOCK - && $cnt==scalar ( - grep { /^$wpat/ || ( /^\\([\w\d\*]+)((?:\[$brat0\]|\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && scalar(@dummy=split(" ",$2))<3 ) } - @$block) ) { - # merge identical blocks shorter than $MINWORDSBLOCK - # and only containing ordinary words - # with preceding different word - # We cannot carry out this merging immediately as this - # would change the index numbers of seq1 and seq2 and confuse - # the algorithm, instead we store in @$todo where we have to merge - push(@$todo, [ $last1,$last2,$cnt,@$block ]); - } - $block = []; - $cnt=0; $last1=-1; $last2=-1; - } - }; - my $discard=sub { $deltokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$delblock,[ $seq1->[$_[0]],$_[0] ]); - $last1=$_[0] }; - - my $add = sub { $addtokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$addblock,[ $seq2->[$_[1]],$_[1] ]); - $last2=$_[1] }; - - my $match = sub { $mattokcnt++; - if ($cnt==0) { # first word of matching sequence after changed sequence or at beginning of word sequence - $deltextblocks = extracttextblocks($delblock); - $delblkcnt++ if scalar @$delblock; - $addtextblocks = extracttextblocks($addblock); - $addblkcnt++ if scalar @$addblock; - - $delcmds = extractcommands($delblock); - $addcmds = extractcommands($addblock); - # keygen(third argument of _longestCommonSubsequence) implies to sort on command (0th elements of $addcmd elements) - # the calling format for longestCommonSubsequence has changed between versions of - # Algorithm::Diff so we need to check which one we are using - if ( $algodiffversion > 1.15 ) { - ### Algorithm::Diff 1.19 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, 0, sub { $_[0]->[0] } ); - } else { - ### Algorithm::Diff 1.15 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, sub { $_[0]->[0] } ); - } - - for ($i=0 ; $i<=$#$matchindex ; $i++) { - if (defined($matchindex->[$i])){ - $j=$matchindex->[$i]; - @delmid=splitlatex($delcmds->[$i][3]); - @addmid=splitlatex($addcmds->[$j][3]); - while (scalar(@$deltextblocks) && $deltextblocks->[0][0]<$delcmds->[$i][1]) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) }; - push(@$todo, [$index,-1,$cnt,@$block]); - } - push(@$todo, [ $delcmds->[$i][1],-1,-1,$delcmds->[$i][2],@delmid,$delcmds->[$i][4]]); - - while (scalar(@$addtextblocks) && $addtextblocks->[0][0]<$addcmds->[$j][1]) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - push(@$todo, [ -1,$addcmds->[$j][1],-1,$addcmds->[$j][2],@addmid,$addcmds->[$j][4]]); - } - } - # mop up remaining textblocks - while (scalar(@$deltextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) } ; - push(@$todo, [$index,-1,$cnt,@$block]); - } - while (scalar(@$addtextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - - $addblock=[]; - $delblock=[]; - } - push(@$block,$seq2->[$_[1]]); - $cnt++ }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - - - # now carry out the merging/splitting. Refer to elements relative from - # the end (with negative indices) as these offsets don't change before the instruction is executed - # cnt>0: merged small unchanged groups with previous changed blocks - # cnt==-1: split textual commands into components - foreach $instruction ( @$todo) { - ($last1,$last2,$cnt,@$block)=@$instruction ; - if ($cnt>=0) { - splice(@$seq1,$last1-$len1,1+$cnt,join("",$seq1->[$last1-$len1],@$block)) if $last1>=0; - splice(@$seq2,$last2-$len2,1+$cnt,join("",$seq2->[$last2-$len2],@$block)) if $last2>=0; - } else { - splice(@$seq1,$last1-$len1,1,@$block) if $last1>=0; - splice(@$seq2,$last2-$len2,1,@$block) if $last2>=0; - } - } - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens in $matblkcnt blocks.\n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } -} - - -# extracttextblocks(\@blockindex) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [[ $index, $textblock, $cnt ], .. -# where $index index of block to be merged -# $textblock contains all the words to be merged with the word at $index (but does not contain this word) -# $cnt is length of block -# -# requires: iscmd -# -sub extracttextblocks { - my $block=shift; - my ($i,$token,$index); - my $textblock=[]; - my $last=-1; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # store pure text blocks - if ($token =~ /$wpat/ || ( $token =~/^\\([\w\d\*]+)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && !iscmd($1,\@TEXTCMDLIST,\@TEXTCMDEXCL))) { - # we have text or a command which can be treated as text - if ($last<0) { - # new pure-text block - $last=$index; - } else { - # add to pure-text block - push(@$textblock, $token); - } - } else { - # it is not text - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - $textblock=[]; - $last=-1; - } - } - # finish processing a possibly unfinished block before returning - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - return($retval) -} - - - -# extractcommands( \@blockindex ) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [ [ "\cmd1", index, "\cmd1[optarg]{arg1}{", "arg2" ,"} " ],.. -# where index is just taken from input array -# command must have a textual argument as last argument -# -# requires: iscmd -# -sub extractcommands { - my $block=shift; - my ($i,$token,$index,$cmd,$open,$mid,$closing); - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: \cmd - # $3: last argument - # $4: } + trailing spaces - if ( ( $token =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL) ) { - # push(@$retval,[ $2,$index,$1,$3,$4 ]); - ($cmd,$open,$mid,$closing) = ($2,$1,$3,$4) ; - $closing =~ s/\}/\\RIGHTBRACE/ ; - push(@$retval,[ $cmd,$index,$open,$mid,$closing ]); - } - } - return $retval; -} - -# iscmd($cmd,\@regexarray,\@regexexcl) checks -# return 1 if $cmd matches any of the patterns in the -# array $@regexarray, and none of the patterns in \@regexexcl, otherwise return 0 -sub iscmd { - my ($cmd,$regexar,$regexexcl)=@_; - my ($ret)=0; - foreach $pat ( @$regexar ) { - if ( $cmd =~ m/^${pat}$/ ) { - $ret=1 ; - last; - } - } - return 0 unless $ret; - foreach $pat ( @$regexexcl ) { - return 0 if ( $cmd =~ m/^${pat}$/ ); - } - return 1; -} - - -# pass2( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Mark begin and end of deleted and appended sequences with tags $DELOPEN and $DELCLOSE -# and $ADDOPEN and $ADDCLOSE, respectively, however exclude { } & and all comands, unless -# they match an element of the whitelist (SAFECMD) -# For words in TEXTCMD but not in SAFECMD, enclose interior with $ADDOPEN and $ADDCLOSE brackets -# Deleted comment lines are marked with %DIF < -# Added comment lines are marked with %DIF > -sub pass2 { - my $seq1 = shift ; - my $seq2 = shift ; - - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $retval = []; - my $delhunk = []; - my $addhunk = []; - - my $discard = sub { $deltokcnt++; - push ( @$delhunk, $seq1->[$_[0]]) }; - - my $add = sub { $addtokcnt++; - push ( @$addhunk, $seq2->[$_[1]]) }; - - my $match = sub { $mattokcnt++; - if ( scalar @$delhunk ) { - $delblkcnt++; - # mark up changes, but comment out commands - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk); - $delhunk = []; - } - if ( scalar @$addhunk ) { - $addblkcnt++; - # we mark up changes, but simply quote commands - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk); - $addhunk = []; - } - push(@$retval,$seq2->[$_[1]]) }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - # clear up unprocessed hunks - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk) if scalar @$delhunk; - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk) if scalar @$addhunk; - - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens. \n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } - - return(@$retval); -} - -# marktags($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,\@block) -# returns ($openmark,$open,$block,$close,$closemark) if @block only contains no commands (except white-listed ones), -# braces, ampersands, or comments -# mark comments with $comment -# exclude all other exceptions from scope of open, close like this -# ($openmark, $open,...,$close, $opencmd,command, command,$closecmd, $open, ..., $close, $closemark) -# If $opencmd begins with "%" marktags assumes it is operating on a deleted block, otherwise on an added block -sub marktags { - my ($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,$block)=@_; - my $word; - my (@argtext); - my $retval=[]; - my $noncomment=0; - my $cmd=-1; # -1 at beginning 0: last token written is a ordinary word - # 1: last token written is a command - # for keeping track whether we are just in a command sequence or in a word sequence - my $cmdcomment= ($opencmd =~ m/^%/); # Flag to indicate whether opencmd is a comment (i.e. if we intend to simply comment out changed commands) - my ($command,$commandword,$closingbracket) ; # temporary variables needed below to remember sub-pattern matches - -# split this block to flatten out sequences joined in pass1 - @$block=splitlatex(join "",@$block); - foreach (@$block) { - $word=$_; - if ( $word =~ s/^%/%$comment/ ) { - # a comment - if ($cmd==1) { - push (@$retval,$closecmd) ; - $cmd=-1; - } - push (@$retval,$word); - next; - } - if (! $noncomment) { - push (@$retval,$openmark); - $noncomment=1; - } - # negative lookahead pattern (?!) in second clause is put in to avoid mathcing \( .. \) patterns - # also note that second pattern will match \\ - # Note: the second pattern should really be $word =~ /^\\(?!\()(\\|[\w*@]+)/, ie * replaced by + - # and then all commands \" \' etc declared safe. But as I don't have a complete list of one letter - # commands, and nobody has complained so far, I will eave this as is - if ( $word =~ /^[&{}\[\]]/ || ( $word =~ /^\\(?!\()(\\|[\w*@]*)/ && !iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL)) ) { - # word is a command or other significant token (not in SAFECMDLIST) - ## same conditions as in subroutine extractcommand: - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: cmd - # $3: last argument - # $4: } + trailing spaces - ### pre-0.3 if ( ( $token =~ m/^(\\([\w\d\*]+)(?:\[$brat0\]|\{$pat6\})*\{)($pat6)(\}\s*)$/so ) - if ( ( $word =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && (iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL)|| iscmd($2,\@MATHTEXTCMDLIST,\@MATHTEXTCMDEXCL)) - && ( !$cmdcomment || !iscmd($2,\@CONTEXT2CMDLIST, \@CONTEXT2CMDEXCL) ) ) { - # Condition 1: word is a command? - if yes, $1,$2,.. will be set as above - # Condition 2: word is a text command - we mark up the interior of the word. There is a separate check for MATHTEXTCMDLIST - # because for $mathmarkup=WHOLE, the commands should not be split in pass1 (ie. math mode commands are not in - # TEXTCMDLIST, but the interior of MATHTEXT commands should be highlighted in both deleted and added blocks - # Condition 3: But if we are in a deleted block ($cmdcomment=1) and - # $2 (the command) is in context2, just treat it as an ordinary command (i.e. comment it open with $opencmd) - # Because we do not want to disable this command - # here we do not use $opencmd and $closecmd($opencmd is empty) - if ($cmd==1) { - push (@$retval,$closecmd) ; - } elsif ($cmd==0) { - push (@$retval,$close) ; - } - $command=$1; $commandword=$2; $closingbracket=$4; - @argtext=splitlatex($3); # split textual argument into tokens - # and mark it up (but we do not need openmark and closemark) - # insert command with initial arguments, marked-up final argument, and closing bracket - if ( $cmdcomment && iscmd($commandword,\@CONTEXT1CMDLIST, \@CONTEXT1CMDEXCL) ) { - # context1cmd in a deleted environment; delete command itself but keep last argument, marked up - push (@$retval,$opencmd); - $command =~ s/\n/\n${opencmd}/sg ; # repeat opencmd at the beginning of each line - # argument, note that the additional comment character is included - # to suppress linebreak after opening parentheses, which is important - # for latexrevise - push (@$retval,$command,"%\n{$AUXCMD\n",marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } elsif ( iscmd($commandword,,\@MATHTEXTCMDLIST, \@MATHTEXTCMDEXCL) ) { - # MATHBLOCK pseudo command: consider all commands safe, except & and \\ - # Keep these commands even in deleted blocks, hence set $opencmd and $closecmd (5th and 6th argument of marktags) to - # "" - local @SAFECMDLIST=(".*"); - local @SAFECMDEXCL=('\\','\\\\'); - push(@$retval,$command,marktags("","",$open,$close,"","",$comment,\@argtext)#@argtext - ,$closingbracket); - } else { - # normal textcmd or context1cmd in an added block - push (@$retval,$command,marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } - push (@$retval,$AUXCMD,"\n") if $cmdcomment ; - $cmd=-1 ; - } else { - # ordinary command - push (@$retval,$opencmd) if $cmd==-1 ; - push (@$retval,$close,$opencmd) if $cmd==0 ; - $word =~ s/\n/\n${opencmd}/sg if $cmdcomment ; # if opencmd is a comment, repeat this at the beginning of every line - push (@$retval,$word); - $cmd=1; - } - } else { - # just an ordinary word or word in SAFECMD - push (@$retval,$open) if $cmd==-1 ; - push (@$retval,$closecmd,$open) if $cmd==1 ; - push (@$retval,$word); - $cmd=0; - } - } - push (@$retval,$close) if $cmd==0; - push (@$retval,$closecmd) if $cmd==1; - - push (@$retval,$closemark) if ($noncomment); - return @$retval; -} - -# preprocess($string, ..) -# carry out the following pre-processing steps for all arguments: -# 1. Remove leading white-space -# Change \{ to \LEFTBRACE and \} to \RIGHTBRACE -# #. change begin and end commands within comments to BEGINDIF, ENDDIF -# so they don't disturb the pattern matching (if there are several \begin or \end in one line -# 2. mark all first empty line (in block of several) with \PAR tokens -# 3. Convert all '\%' into '\PERCENTAGE ' and all '\$' into \DOLLAR to make parsing regular expressions easier -# 4. Convert all \verb|some verbatim text| commands (where | can be an arbitrary character) -# into \verb{hash} -# 5. Convert \begin{verbatim} some verbatim text \end{verbatim} into \verbatim{hash} -# 6. Convert _n into \SUBSCRIPTNB{n} and _{nnn} into \SUBSCRIPT{nn} -# 7. Convert ^n into \SUPERSCRIPTNB{n} and ^{nnn} into \SUPERSCRIPT{nn} -# 8. a. Convert $$ $$ into \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} -# b. Convert \[ \] into \begin{SQUAREBRACKET} \end{SQUAREBRACKET} -# 9. Convert all picture environmentent (\begin{PICTUREENV} .. \end{PICTUREENV} \PICTUREBLOCKenv -# For --block-math-markup option -convert all \begin{MATH} .. \end{MATH} -# into \MATHBLOCKmath{...} commands, where MATH/math is any valid math environment - -# 10. Add final token STOP to the very end. This is put in because the algorithm works better if the last token is identical. This is removed again in postprocessing. -# -# NB: step 6 and 7 is likely to convert some "_" inappropriately, e.g. in file -# names or labels but it does not matter because they are converted back in the postprocessing step -# Returns: leading white space removed in step 1 -sub preprocess { - my @leadin=() ; - for (@_) { - s/^(\s*)//s; - push(@leadin,$1); - # Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE - s/(?{$hstr}) && $string ne $hash->{$hstr}) { - warn "Repeated hash value for verbatim mode in spite of different content."; - $hstr="-$hstr"; - } - $hash->{$hstr}=$string; - return($hstr); -} - -#string=fromhash(\%hash,$fromstring) -# restores string value stored in hash -#string=fromhash(\%hash,$fromstring,$prependstring) -# additionally begins each line with prependstring -sub fromhash { - my ($hash,$hstr)=($_[0],$_[1]); - my $retstr=$hash->{$hstr}; - if ( $#_ >= 2) { - $retstr =~ s/^/$_[2]/mg; - } - return $retstr; -} - - -# postprocess($string, ..) -# carry out the following post-processing steps for all arguments: -# * Remove STOP token from the end -# * Replace \RIGHTBRACE by } -# * change citation commands within comments to protect from processing (using marker CITEDIF) -# 1. Check all deleted blocks: -# a.where a deleted block contains a matching \begin and -# \end environment (these will be disabled by a %DIFDELCMD statements), for selected environments enable -# these commands again (such that for example displayed math in a deleted equation -# is properly within math mode. For math mode environments replace numbered equation -# environments with their display only variety (so that equation numbers in new file and -# diff file are identical). Where the correct type of math environment cannot be determined -# use a place holder MATHMODE -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file -# Replace all MATHMODE environment commands by the correct environment to achieve matching -# pairs -# c. Convert MATHBLOCKmath commands to their uncounted numbers (e.g. convert equation -> displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL -# d. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# For added blocks: -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# 2. If --block-math-markup option set: Convert \MATHBLOCKmath{..} commands back to environments -# -# Convert all PICTUREblock{..} commands back to the appropriate environments -# 3. Convert DIFadd, DIFdel, DIFFaddbegin , ... into FL varieties -# within floats (currently recognised float environments: plate,table,figure -# plus starred varieties). -# 4. Remove empty %DIFDELCMD < lines -# 4. Convert \begin{SQUAREBRACKET} \end{SQUAREBRACKET} into \[ \] -# Convert \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} into $$ $$ -# 5. Convert \SUPERSCRIPTNB{n} into ^n and \SUPERSCRIPT{nn} into ^{nnn} -# 6. Convert \SUBSCRIPTNB{n} into _n and \SUBCRIPT{nn} into _{nnn} -# 7. Expand hashes of verb and verbatim environments -# 8. Convert '\PERCENTAGE ' back into '\%' and '\DOLLAR ' into '\$' -# 9.. remove all \PAR tokens -# 10. package specific processing: endfloat: make sure \begin{figure} and \end{figure} are always -# on a line by themselves, similarly for table environment -# 4, undo renaming of the \begin and \end in comments -# Change \QLEFTBRACE, \QRIGHTBRACE to \{,\} -# -# Note have to manually synchronize substitution commands below and -# DIF.. command names in the header -sub postprocess { - my ($begin,$len,$cnt,$float,$delblock,$addblock); - # second level blocks - my ($begin2,$cnt2,$len2,$eqarrayblock,$mathblock); - - for (@_) { - - # change $'s in comments to something harmless - 1 while s/(%.*)\$/$1DOLLARDIF/mg ; - - # Remove final STOP token - s/ STOP$//; - # Replace \RIGHTBRACE by } - s/\\RIGHTBRACE/}/g; - - # change citation commands within comments to protect from processing - if ($CITECMD){ - 1 while s/(%.*)\\($CITECMD)/$1\\CITEDIF$2/m ; - } - # Check all deleted blocks: where a deleted block contains a matching \begin and - # \end environment (these will be disabled by a %DIFDELCMD statements), enable - # these commands again (such that for example displayed math in a deleted equation - # is properly within math mode. For math mode environments replace numbered equation - # environments with their display only variety (so that equation numbers in new file and - # diff file are identical - while ( m/\\DIFdelbegin.*?\\DIFdelend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $delblock=$&; - - - ### (.*?[^\n]?)\n? construct is necessary to avoid empty lines in math mode, which result in - ### an error - # displayed math environments - if ($mathmarkup == FINE ) { - $delblock=~ s/(\%DIFDELCMD < \s*\\begin\{((?:$MATHENV)|SQUAREBRACKET)\}.*?(?:$DELCMDCLOSE|\n))(.*?[^\n]?)\n?(\%DIFDELCMD < \s*\\end\{\2\})/\\begin{$MATHREPL}$AUXCMD\n$1$3\n\\end{$MATHREPL}$AUXCMD\n$4/sg; - # also transform the opposite pair \end{displaymath} .. \begin{displaymath} but we have to be careful not to interfere with the results of the transformation in the line directly above - ### pre-0.42 obsolete version which did not work on eqnarray test $delblock=~ s/(? displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL - $delblock=~ s/\\MATHBLOCK($MATHENV)\{($pat6)\}/\\MATHBLOCK$MATHREPL\{$2\}/sg; - $delblock=~ s/\\MATHBLOCK($MATHARRENV)\{($pat6)\}/\\MATHBLOCK$MATHARRREPL\{$2\}/sg; - } - - -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file - $delblock=~ s/\\($COUNTERCMD)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*\s*${AUXCMD}\n)/\\$1$2\\addtocounter{$1}{-1}${AUXCMD}\n/sg ; - - -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es - while ( $delblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($delblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($delblock,$begin2,$len2)=$mathblock; - pos($delblock) = $begin2 + length($mathblock); - } - if ($CITE2CMD) { - $delblock=~s/($DELCMDOPEN\s*\\($CITE2CMD)(.*)$DELCMDCLOSE)/ - # Replacement code - {my ($aux,$all); - $aux=$all=$1; - $aux=~s#\n?($DELCMDOPEN|$DELCMDCLOSE)##g; - $all."$aux$AUXCMD\n";}/sge; - } - # or protect \cite commands with \mbox - if ($CITECMD) { - $delblock=~s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat6\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified delblock - substr($_,$begin,$len)=$delblock; - pos = $begin + length($delblock); - } - # make the array modification in added blocks - while ( m/\\DIFaddbegin.*?\\DIFaddend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $addblock=$&; - while ( $addblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($addblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($addblock,$begin2,$len2)=$mathblock; - pos($addblock) = $begin2 + length($mathblock); - } - if ($CITECMD) { - my $addblockbefore=$addblock; - $addblock=~ s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat2\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified addblock - substr($_,$begin,$len)=$addblock; - pos = $begin + length($addblock); - } - - - ### old place for BEGINDIF, ENDDIF replacement - # change begin and end commands within comments such that they - # don't disturb the pattern matching (if there are several \begin or \end in one line - # this substitution is insufficient but that appears unlikely) - # This needs to be repeated here to also get rid of DIFdelcmd-protected environments - s/(%.*)\\begin\{(.*)$/$1\\BEGINDIF\{$2/mg ; - s/(%.*)\\end\{(.*)$/$1\\ENDDIF\{$2/mg ; - - # Replace MATHMODE environments from step 1a above by the correct Math environment - - # The next line is complicated. The negative look-ahead insertion makes sure that no \end{$MATHENV} (or other mathematical - # environments) are between the \begin{$MATHENV} and \end{MATHMODE} commands. This is necessary as the minimal matching - # is not globally minimal but only 'locally' (matching is beginning from the left side of the string) - if ( $mathmarkup == FINE ) { - 1 while s/\\begin{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}((?:.(?!(?:\\end{(?:(?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}|\\begin{MATHMODE})))*?)\\end{MATHMODE}/\\begin{$1}$2\\end{$1}/s; - 1 while s/\\begin{MATHMODE}((?:.(?!\\end{MATHMODE}))*?)\\end{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}/\\begin{$2}$1\\end{$2}/s; - # convert remaining \begin{MATHMODE} \end{MATHMODE} (and not containing & or \\ )into MATHREPL environments - s/\\begin{MATHMODE}((?:(.(?!(?[1])) { - $optargnew=$newhash{$cmd}->[1]; - } else { - $optargnew=""; - } - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - } else { - $optargold=""; - } - - if ( defined($oldhash{$cmd}) ) { - $argold=$oldhash{$cmd}->[2]; - } else { - $argold=""; - } - $argnew=$newhash{$cmd}->[2]; - $argdiff="{" . join("",bodydiff($argold,$argnew)) ."}"; - if ( length $optargnew ) { - $optargdiff="[".join("",bodydiff($optargold,$optargnew))."]" ; - $optargdiff =~ s/\\DIFaddbegin /\\DIFaddbeginFL /g; - $optargdiff =~ s/\\DIFaddend /\\DIFaddendFL /g; - $optargdiff =~ s/\\DIFadd\{/\\DIFaddFL{/g; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - ### print STDERR "DEBUG s/\\Q$newhash{$cmd}->[0]\\E/\\$cmd$optargdiff$argdiff/s\n"; - # Note: \Q and \E force literal interpretation of what it between them but allow - # variable interpolation, such that e.g. \title matches just that and not TAB-itle - $$newpreambleref=~s/\Q$newhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s; - # replace this in old preamble if necessary - if ( defined($oldhash{$cmd}->[0])) { - $$oldpreambleref=~s/\Q$oldhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s ; - } - ### print STDERR "DEBUG NEW PRE ".$$newpreambleref."\n"; - } - - foreach $cmd ( keys %oldhash ) { - # if this has already been dealt with above can just skip - next if defined($newhash{$cmd}) ; - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - $optargdiff="[".join("",bodydiff($optargold,""))."]" ; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - $argdiff="{" . join("",bodydiff($argold,"")) ."}"; - $auxline = "\\$cmd$optargdiff$argdiff"; - $auxline =~s/$/$AUXCMD/sg; - push @auxlines,$auxline; - } - # add auxcmd comment to highlight added lines - return(@auxlines); -} - - - -# @diffs=linediff(\@seq1, \@seq2) -# mark up lines like this -#%DIF mm-mmdnn -#%< old deleted line(s) -#%DIF ------- -#%DIF mmann-nn -#new appended line %< -#%DIF ------- -# Future extension: mark change explicitly -# Assumes: traverse_sequence traverses deletions before insertions in changed sequences -# all line numbers relative to line 0 (first line of real file) -sub linediff { - my $seq1 = shift ; - my $seq2 = shift ; - - my $block = []; - my $retseq = []; - my @begin=('','',''); # dummy initialisation - my $instring ; - - my $discard = sub { @begin=('d',$_[0],$_[1]) unless scalar @$block ; - push(@$block, "%DIF < " . $seq1->[$_[0]]) }; - my $add = sub { if (! scalar @$block) { - @begin=('a',$_[0],$_[1]) ;} - elsif ( $begin[0] eq 'd' ) { - $begin[0]='c'; $begin[2]=$_[1]; - push(@$block, "%DIF -------") } - push(@$block, $seq2->[$_[1]] . " %DIF > " ) }; - my $match = sub { if ( scalar @$block ) { - if ( $begin[0] eq 'd' && $begin[1]!=$_[0]-1) { - $instring = sprintf "%%DIF %d-%dd%d",$begin[1],$_[0]-1,$begin[2]; } - elsif ( $begin[0] eq 'a' && $begin[2]!=$_[1]-1) { - $instring = sprintf "%%DIF %da%d-%d",$begin[1],$begin[2],$_[1]-1; } - elsif ( $begin[0] eq 'c' ) { - $instring = sprintf "%%DIF %sc%s", - ($begin[1]==$_[0]-1) ? "$begin[1]" : $begin[1]."-".($_[0]-1) , - ($begin[2]==$_[1]-1) ? "$begin[2]" : $begin[2]."-".($_[1]-1) ; } - else { - $instring = sprintf "%%DIF %d%s%d",$begin[1],$begin[0],$begin[2]; } - push @$retseq, $instring,@$block, "%DIF -------" ; - $block = []; - } - push @$retseq, $seq2->[$_[1]] - }; - # key function: remove multiple spaces (such that insertion or deletion of redundant white space is not reported) - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - push @$retseq, @$block if scalar @$block; - - return wantarray ? @$retseq : $retseq ; -} - - - -# init_regex_arr_data(\@array,"TOKEN INIT") -# scans DATA file handel for line "%% TOKEN INIT" line -# then appends each line not beginning with % into array (as a quoted regex) -sub init_regex_arr_data { - my ($arr,$token)=@_; - my ($copy); - while () { - if ( m/^%%BEGIN $token\s*$/ ) { - $copy=1; } - elsif ( m/^%%END $token\s*/ ) { - last; } - chomp; - push (@$arr,qr/^$_$/) if ( $copy && !/^%/ ) ; - } - seek DATA,0,0; # rewind DATA handle to file begin -} - - -# init_regex_arr_ext(\@array,$arg) -# fills array with regular expressions. -# if arg is a file name, then read in list of regular expressions from that file -# (one expression per line) -# Otherwise treat arg as a comma separated list of regular expressions -sub init_regex_arr_ext { - my ($arr,$arg)=@_; - my $regex; - if ( -f $ arg ) { - open(FILE,"$arg") or die ("Couldn't open $arg: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@$arr,qr/^$_$/); - } - close(FILE); - } - else { - # assume it is a comma-separated list of reg-ex - foreach $regex (split(qr/(?=1) { - $reset=shift; - } - if ($reset) { - $lasttime=times(); - } - else { - $retval=times()-$lasttime; - $lasttime=$lasttime+$retval; - return($retval); - } -} - - -sub usage { - die <<"EOF"; -Usage: $0 [options] old.tex new.tex > diff.tex - -Compares two latex files and writes tex code to stdout, which has the same -format as new.tex but has all changes relative to old.tex marked up or commented. - ---type=markupstyle --t markupstyle Add code to preamble for selected markup style - Available styles: UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE - CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR - [ Default: UNDERLINE ] - ---subtype=markstyle --s markstyle Add code to preamble for selected style for bracketing - commands (e.g. to mark changes in margin) - Available styles: SAFE MARGINAL DVIPSCOL COLOR - [ Default: SAFE ] - ---floattype=markstyle --f markstyle Add code to preamble for selected style which - replace standard marking and markup commands within floats - (e.g., marginal remarks cause an error within floats - so marginal marking can be disabled thus) - Available styles: FLOATSAFE IDENTICAL - [ Default: FLOATSAFE ] - ---encoding=enc --e enc Specify encoding of old.tex and new.tex. Typical encodings are - ascii, utf8, latin1, latin9. A list of available encodings can be - obtained by executing - perl -MEncode -e 'print join ("\\n",Encode->encodings( ":all" )) ;' - [Default encoding is utf8 unless the first few lines of the preamble contain - an invocation "\\usepackage[..]{inputenc} in which case the - encoding chosen by this command is asssumed. Note that ASCII (standard - latex) is a subset of utf8] - ---preamble=file --p file Insert file at end of preamble instead of auto-generating - preamble. The preamble must define the following commands - \\DIFaddbegin,\\DIFaddend,\\DIFadd{..}, - \\DIFdelbegin,\\DIFdelend,\\DIFdel{..}, - and varieties for use within floats - \\DIFaddbeginFL,\\DIFaddendFL,\\DIFaddFL{..}, - \\DIFdelbeginFL,\\DIFdelendFL,\\DIFdelFL{..} - (If this option is set -t, -s, and -f options - are ignored.) - ---exclude-safecmd=exclude-file ---exclude-safecmd="cmd1,cmd2,..." --A exclude-file ---replace-safecmd=replace-file ---append-safecmd=append-file ---append-safecmd="cmd1,cmd2,..." --a append-file Exclude from, replace or append to the list of regex - matching commands which are safe to use within the - scope of a \\DIFadd or \\DIFdel command. The file must contain - one Perl-RegEx per line (Comment lines beginning with # or % are - ignored). A literal comma within the comma-separated list must be - escaped thus "\\,", Note that the RegEx needs to match the whole of - the token, i.e., /^regex\$/ is implied and that the initial - "\\" of the command is not included. The --exclude-safecmd - and --append-safecmd options can be combined with the --replace-safecmd - option and can be used repeatedly to add cumulatively to the lists. - ---exclude-textcmd=exclude-file ---exclude-textcmd="cmd1,cmd2,..." --X exclude-file ---replace-textcmd=replace-file ---append-textcmd=append-file ---append-textcmd="cmd1,cmd2,..." --x append-file Exclude from, replace or append to the list of regex - matching commands whose last argument is text. See - entry for --exclude-safecmd directly above for further details. - ---replace-context1cmd=replace-file ---append-context1cmd=append-file ---append-context1cmd="cmd1,cmd2,..." - Replace or append to the list of regex matching commands - whose last argument is text but which require a particular - context to work, e.g. \\caption will only work within a figure - or table. These commands behave like text commands, except when - they occur in a deleted section, when they are disabled, but their - argument is shown as deleted text. - ---replace-context2cmd=replace-file ---append-context2cmd=append-file ---append-context2cmd="cmd1,cmd2,..." - As corresponding commands for context1. The only difference is that - context2 commands are completely disabled in deleted sections, including - their arguments. - - ---config var1=val1,var2=val2,... --c var1=val1,.. Set configuration variables. --c configfile Available variables: - MINWORDSBLOCK (integer) - FLOATENV (RegEx) - PICTUREENV (RegEx) - MATHENV (RegEx) - MATHREPL (String) - MATHARRENV (RegEx) - MATHARRREPL (String) - ARRENV (RegEx) - COUNTERCMD (RegEx) - This option can be repeated. - - ---packages=pkg1,pkg2,.. - Tell latexdiff that .tex file is processed with the packages in list - loaded. This is normally not necessary if the .tex file includes the - preamble, as the preamble is automatically scanned for \\usepackage commands. - Use of the --packages option disables automatic scanning, so if for any - reason package specific parsing needs to be switched off, use --packages=none. - The following packages trigger special behaviour: - endfloat hyperref amsmath - [ Default: scan the preamble for \\usepackage commands to determine - loaded packages.] - ---show-preamble Print generated or included preamble commands to stdout. - ---show-safecmd Print list of regex matching and excluding safe commands. - ---show-textcmd Print list of regex matching and excluding commands with text argument. - ---show-config Show values of configuration variables - ---show-all Show all of the above - - NB For all --show commands, no old.tex or new.tex file needs to be given, and no - differencing takes place. - -Other configuration options: - ---allow-spaces Allow spaces between bracketed or braced arguments to commands - [Default requires arguments to directly follow each other without - intervening spaces] - ---math-markup=level Determine granularity of markup in displayed math environments: - Possible values for level are (both numerical and text labels are acceptable): - off or 0: suppress markup for math environments. Deleted equations will not - appear in diff file. This mode can be used if all the other modes - cause invalid latex code. - whole or 1: Differencing on the level of whole equations. Even trivial changes - to equations cause the whole equation to be marked changed. This - mode can be used if processing in coarse or fine mode results in - invalid latex code. - coarse or 2: Detect changes within equations marked up with a coarse - granularity; changes in equation type (e.g.displaymath to equation) - appear as a change to the complete equation. This mode is recommended - for situations where the content and order of some equations are still - being changed. [Default] - fine or 3: Detect small change in equations and mark up and fine granularity. - This mode is most suitable, if only minor changes to equations are - expected, e.g. correction of typos. - ---disable-citation-markup Suppress citation markup in styles using ulem (UNDERLINE, - FONTSTRIKE, CULINECHBAR) ---enable-citation-markup Protect citation commands in changed sections with \\mbox command - [i.e. use default behaviour for ulem package for other packages] - -Miscelleneous options - ---label=label --L label Sets the labels used to describe the old and new files. The first use - of this option sets the label describing the old file and the second - use of the option sets the label for the new file. - [Default: use the filename and modification dates for the label] - ---no-label Suppress inclusion of old and new file names as comment in output file - ---visble-label Include old and new filenames (or labels set with --label option) as - visible output - ---flatten Replace \\input and \\include commands within body by the content - of the files in their argument. If \\includeonly is present in the - preamble, only those files are expanded into the document. However, - no recursion is done, i.e. \\input and \\include commands within - included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, - respectively, making it possible to organise files into old and new directories. - --flatten is applied recursively, so inputted files can contain further - \\input statements. - ---help --h Show this help text. - ---ignore-warnings Suppress warnings about inconsistencies in length between input - and parsed strings and missing characters. - ---verbose --V Output various status information to stderr during processing. - Default is to work silently. - ---version Show version number. - -For further information, consult http://latexdiff.berlios.de -EOF -} - -=head1 NAME - -latexdiff - determine and markup differences between two latex files - -=head1 SYNOPSIS - -B [ B ] F F > F - -=head1 DESCRIPTION - -Briefly, I is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called C and C, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. - -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "S>>" is appended to each added line, i.e. a -line present in C but not in C. Discarded lines - are deactivated by prepending "S>>". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file C will be similar to -C. At the end of the preamble, the definitions for I markup commands are inserted. -In differencing the main body of the text, I attempts to -satisfy the following guidelines (in order of priority): - -=over 3 - -=item 1 - -If both C and C are valid LaTeX, then the resulting -C should also be valid LateX. (NB If a few plain TeX commands -are used within C or C then C is not -guaranteed to work but usually will). - -=item 2 - -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -C. - -=item 3 - -If a changed passage contains text or text-producing commands, then -running C through LateX should produce output where added -and discarded passages are highlighted. - -=item 4 - -Where there are insignificant differences, e.g. in the positioning of -line breaks, C should follow the formatting of C - -=back - -For differencing the same algorithm as I is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, C<\caption> and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write - - \section{\textem{This is an emphasized section title}} - -and not - - \section {\textem{This is an emphasized section title}} - -or - - \section\textem{This is an emphasized section title} - -even though all varieties are the same to LaTeX (but see -B<--allow-spaces> option which allows the second variety). - -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the PICTUREENV configuration variable, set by -default to C and C environments; see B<--config> -option). The latter environment (C) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by C<\begin{DIFnomarkup}> and C<\end{DIFnomarkup}>. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, - -C<\newenvironment{DIFnomarkup}{}{}> - -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. - -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. - -All markup commands inserted by I begin with "C<\DIF>". Added -blocks containing words, commands or comments which are in C -but not in C are marked by C<\DIFaddbegin> and C<\DIFaddend>. -Discarded blocks are marked by C<\DIFdelbegin> and C<\DIFdelend>. -Within added blocks all text is highlighted with C<\DIFadd> like this: -C<\DIFadd{Added text block}> -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces "{" and "}" are never put within -the scope of C<\DIFadd>. Added comments are marked by prepending -"S >>". - -Within deleted blocks text is highlighted with C<\DIFdel>. Deleted -comments are marked by prepending "S >>". Non-safe command -and curly braces within deleted blocks are commented out with -"S >>". - - - -=head1 OPTIONS - -=head2 Preamble - -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. - -=over 4 - -=item B<--type=markupstyle> or -B<-t markupstyle> - -Add code to preamble for selected markup style. This option defines -C<\DIFadd> and C<\DIFdel> commands. -Available styles: - -C - -[ Default: C ] - -=item B<--subtype=markstyle> or -B<-s markstyle> - -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -C<\DIFaddbegin>, C<\DIFaddend>, C<\DIFdelbegin> and C<\DIFdelend> commands. -Available styles: C - -[ Default: C ] - -=item B<--floattype=markstyle> or -B<-f markstyle> - -Add code to preamble for selected style which -replace standard marking and markup commands within floats -(e.g., marginal remarks cause an error within floats -so marginal marking can be disabled thus). This option defines all -C<\DIF...FL> commands. -Available styles: C - -[ Default: C ] - -=item B<--encoding=enc> or -B<-e enc> - -Specify encoding of old.tex and new.tex. Typical encodings are -C, C, C, C. A list of available encodings can be -obtained by executing - -Cencodings( ":all" )) ;' > - -[Default encoding is utf8 unless the first few lines of the preamble contain -an invocation C<\usepackage[..]{inputenc}> in which case the -encoding chosen by this command is asssumed. Note that ASCII (standard -latex) is a subset of utf8] - -=item B<--preamble=file> or -B<-p file> - -Insert file at end of preamble instead of generating -preamble. The preamble must define the following commands -C<\DIFaddbegin, \DIFaddend, \DIFadd{..}, -\DIFdelbegin,\DIFdelend,\DIFdel{..},> -and varieties for use within floats -C<\DIFaddbeginFL, \DIFaddendFL, \DIFaddFL{..}, -\DIFdelbeginFL, \DIFdelendFL, \DIFdelFL{..}> -(If this option is set B<-t>, B<-s>, and B<-f> options -are ignored.) - -=item B<--packages=pkg1,pkg2,..> - -Tell latexdiff that .tex file is processed with the packages in list -loaded. This is normally not necessary if the .tex file includes the -preamble, as the preamble is automatically scanned for C<\usepackage> commands. -Use of the B<--packages> option disables automatic scanning, so if for any -reason package specific parsing needs to be switched off, use B<--packages=none>. -The following packages trigger special behaviour: - -=over 8 - -=item C - -Configuration variable amsmath is set to C (Default: C) - -=item C - -Ensure that C<\begin{figure}> and C<\end{figure}> always appear by themselves on a line. - -=item C - -Change name of C<\DIFadd> and C<\DIFdel> commands to C<\DIFaddtex> and C<\DIFdeltex> and -define new C<\DIFadd> and C<\DIFdel> commands, which provide a wrapper for these commands, -using them for the text but not for the link defining command (where any markup would cause -errors). - -=back - -[ Default: scan the preamble for C<\\usepackage> commands to determine - loaded packages.] - - - -=item B<--show-preamble> - -Print generated or included preamble commands to stdout. - -=back - -=head2 Configuration - -=over 4 - -=item B<--exclude-safecmd=exclude-file> or -B<-A exclude-file> or B<--exclude-safecmd="cmd1,cmd2,..."> - -=item B<--replace-safecmd=replace-file> - -=item B<--append-safecmd=append-file> or -B<-a append-file> or B<--append-safecmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions (RegEx) -matching commands which are safe to use within the -scope of a C<\DIFadd> or C<\DIFdel> command. The file must contain -one Perl-RegEx per line (Comment lines beginning with # or % are -ignored). Note that the RegEx needs to match the whole of -the token, i.e., /^regex$/ is implied and that the initial -"\" of the command is not included. -The B<--exclude-safecmd> and B<--append-safecmd> options can be combined with the -B<--replace-safecmd> -option and can be used repeatedly to add cumulatively to the lists. - B<--exclude-safecmd> -and B<--append-safecmd> can also take a comma separated list as input. If a -comma for one of the regex is required, escape it thus "\,". In most cases it -will be necessary to protect the comma-separated list from the shell by putting -it in quotation marks. - -=item B<--exclude-textcmd=exclude-file> or -B<-X exclude-file> or B<--exclude-textcmd="cmd1,cmd2,..."> - -=item B<--replace-textcmd=replace-file> - -=item B<--append-textcmd=append-file> or -B<-x append-file> or B<--append-textcmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions -matching commands whose last argument is text. See -entry for B<--exclude-safecmd> directly above for further details. - - -=item B<--replace-context1cmd=replace-file> - -=item B<--append-context1cmd=append-file> or -=item B<--append-context1cmd="cmd1,cmd2,..."> - -Replace or append to the list of regex matching commands -whose last argument is text but which require a particular -context to work, e.g. \caption will only work within a figure -or table. These commands behave like text commands, except when -they occur in a deleted section, when they are disabled, but their -argument is shown as deleted text. - -=item B<--replace-context2cmd=replace-file> - -=item B<--append-context2cmd=append-file> or -=item B<--append-context2cmd="cmd1,cmd2,..."> -As corresponding commands for context1. The only difference is that -context2 commands are completely disabled in deleted sections, including -their arguments. - - - -=item B<--config var1=val1,var2=val2,...> or B<-c var1=val1,..> - -=item B<-c configfile> - -Set configuration variables. The option can be repeated to set different -variables (as an alternative to the comma-separated list). -Available variables (see below for further explanations): - -C (integer) - -C (RegEx) - -C (RegEx) - -C (RegEx) - -C (String) - -C (RegEx) - -C (String) - -C (RegEx) - -C (RegEx) - -=item B<--show-safecmd> - -Print list of RegEx matching and excluding safe commands. - -=item B<--show-textcmd> - -Print list of RegEx matching and excluding commands with text argument. - -=item B<--show-config> - -Show values of configuration variables. - -=item B<--show-all> - -Combine all --show commands. - -NB For all --show commands, no C or C file needs to be specified, and no -differencing takes place. - -=back - -=head2 Other configuration options: - -=over 4 - -=item B<--allow-spaces> - -Allow spaces between bracketed or braced arguments to commands. Note -that this option might have undesirable side effects (unrelated scope -might get lumpeded with preceding commands) so should only be used if the -default produces erroneous results. (Default requires arguments to -directly follow each other without intervening spaces). - -=item B<--math-markup=level> - -Determine granularity of markup in displayed math environments: -Possible values for level are (both numerical and text labels are acceptable): - -C or C<0>: suppress markup for math environments. Deleted equations will not -appear in diff file. This mode can be used if all the other modes -cause invalid latex code. - -C or C<1>: Differencing on the level of whole equations. Even trivial changes -to equations cause the whole equation to be marked changed. This -mode can be used if processing in coarse or fine mode results in -invalid latex code. - -C or C<2>: Detect changes within equations marked up with a coarse -granularity; changes in equation type (e.g.displaymath to equation) -appear as a change to the complete equation. This mode is recommended -for situations where the content and order of some equations are still -being changed. [Default] - -C or C<3>: Detect small change in equations and mark up at fine granularity. -This mode is most suitable, if only minor changes to equations are -expected, e.g. correction of typos. - -=item B<--disable-citation-markup> - -Suppress citation markup in styles using ulem (UNDERLINE, -FONTSTRIKE, CULINECHBAR) - -=item B<--enable-citation-markup> - -Protect citation commands in changed sections with \\mbox command [i.e. use default behaviour for ulem package for other packages] - -=back - -=head2 Miscellaneous - -=over 4 -=item B<--verbose> or B<-V> - -Output various status information to stderr during processing. -Default is to work silently. - -=item B<--driver=type> - -Choose driver for changebar package (only relevant for styles using - changebar: CCHANGEBAR CFONTCHBAR CULINECHBAR CHANGEBAR). Possible -drivers are listed in changebar manual, e.g. pdftex,dvips,dvitops - [Default: dvips] - -=item B<--ignore-warnings> - -Suppress warnings about inconsistencies in length between input and -parsed strings and missing characters. These warning messages are -often related to non-standard latex or latex constructions with a -syntax unknown to C but the resulting difference argument -is often fully functional anyway, particularly if the non-standard -latex only occurs in parts of the text which have not changed. - -=item B<--label=label> or -B<-L label> - -Sets the labels used to describe the old and new files. The first use -of this option sets the label describing the old file and the second -use of the option sets the label for the new file, i.e. set both -labels like this C<-L labelold -L labelnew>. -[Default: use the filename and modification dates for the label] - -=item B<--no-label> - -Suppress inclusion of old and new file names as comment in output file - -=item B<--visble-label> - -Include old and new filenames (or labels set with --label option) as -visible output. - -=item B<--flatten> - -Replace C<\input> and C<\include> commands within body by the content -of the files in their argument. If C<\includeonly> is present in the -preamble, only those files are expanded into the document. However, -no recursion is done, i.e. C<\input> and C<\include> commands within -included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, -respectively, making it possible to organise files into old and new directories. ---flatten is applied recursively, so inputted files can contain further -C<\input> statements. - -Use of this option might result in prohibitive processing times for -larger documents, and the resulting difference document -no longer reflects the structure of the input documents. - -=item B<--help> or -B<-h> - -Show help text - -=item B<--version> - -Show version number - -=back - - - -=head2 Predefined styles - -=head2 Major types - -The major type determine the markup of plain text and some selected latex commands outside floats by defining the markup commands C<\DIFadd{...}> and C<\DIFdel{...}> . - -=over 10 - -=item C - -Added text is wavy-underlined and blue, discarded text is struck out and red -(Requires color and ulem packages). Overstriking does not work in displayed math equations such that deleted parts of equation are underlined, not struck out (this is a shortcoming inherent to the ulem package). - -=item C - -Added text is blue and set in sans-serif, and a red footnote is created for each discarded -piece of text. (Requires color package) - -=item C - -Like C but without the use of color. - -=item C - -Added text is blue and set in sans-serif, and discarded text is red and very small size. - -=item C - -Added tex is set in sans-serif, discarded text small and struck out - -=item C - -Added text is blue, and discarded text is red. Additionally, the changed text is marked with a bar in the margin (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color, ulem and changebar packages). - -=item C - -No mark up of text, but mark margins with changebars (Requires changebar package). - -=item C - -No visible markup (but generic markup commands will still be inserted. - -=back - -=head2 Subtypes - -The subtype defines the commands that are inserted at the begin and end of added or discarded blocks, irrespectively of whether these blocks contain text or commands (Defined commands: C<\DIFaddbegin, \DIFaddend, \DIFdelbegin, \DIFdelend>) - -=over 10 - -=item C - -No additional markup (Recommended choice) - -=item C - -Mark beginning and end of changed blocks with symbols in the margin nearby (using -the standard C<\marginpar> command - note that this sometimes moves somewhat -from the intended position. - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. -(It is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete, for example -with citation commands). - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. Note -that C only works with the dvips converter, e.g. not pdflatex. -(it is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete). - -=back - -=head2 Float Types - -Some of the markup used in the main text might cause problems when used within -floats (e.g. figures or tables). For this reason alternative versions of all -markup commands are used within floats. The float type defines these alternative commands. - -=over 10 - -=item C - -Use identical markup for text as in the main body, but set all commands marking the begin and end of changed blocks to null-commands. You have to choose this float type if your subtype is C as C<\marginpar> does not work properly within floats. - -=item C - -Mark additions the same way as in the main text. Deleted environments are marked by angular brackets \[ and \] and the deleted text is set in scriptscript size. This float type should always be used with the C and C markup types as the \footnote command does not work properly in floating environments. - -=item C - -Make no difference between the main text and floats. - -=back - - -=head2 Configuration Variables - -=over 10 - -=item C - -Minimum number of tokens required to form an independent block. This value is -used in the algorithm to detect changes of complete blocks by merging identical text parts of less than C to the preceding added and discarded parts. - -[ Default: 3 ] - -=item C - -Environments whose name matches the regular expression in C are -considered floats. Within these environments, the I markup commands -are replaced by their FL variaties. - -[ Default: S >] - -=item C - -Within environments whose name matches the regular expression in C -all latexdiff markup is removed (in pathologic cases this might lead to - inconsistent markup but this situation should be rare). - -[ Default: S >] - -=item C,C - -If both \begin and \end for a math environment (environment name matching C -or \[ and \]) -are within the same deleted block, they are replaced by a \begin and \end commands for C -rather than being commented out. - -[ Default: C=S >, C=S >] - -=item C,C - -as C,C but for equation arrays - -[ Default: C=S >, C=S >] - -=item C - -If a match to C is found within an inline math environment within a deleted or added block, then the inlined math -is surrounded by C<\mbox{>...C<}>. This is necessary as underlining does not work within inlined array environments. - -[ Default: C=S > - -=item C - -If a command in a deleted block which is also in the textcmd list matches C then an -additional command C<\addtocounter{>FC<}{-1}>, where F is the matching command, is appended in the diff file such that the numbering in the diff file remains synchronized with the -numbering in the new file. - -[ Default: C=C<(?:footnote|part|section|subsection> ... - -C<|subsubsection|paragraph|subparagraph)> ] - -=back - -=head1 COMMON PROBLEMS - -=over 10 - -=item Citations result in overfull boxes - -There is an incompatibility between the C package, which C uses for underlining and striking out in the UNDERLINE style, -the default style. In order to be able to mark up citations properly, they are placed with an C<\mbox> command in post-processing. As mboxes -cannot be broken across lines, this procedure frequently results in overfull boxes, possibly obscuring the content as it extends beyond the right margin. If this is a problem, you have two possibilities: - -1. Use C or C subtype markup (option C<-s COLOR>): If this markup is chosen, then changed citations are no longer marked up -with the wavy line (additions) or struck out (deletions), but are still highlighted in the appropriate color. - -2. Choose option C<--disable-citation-markup> which turns off the marking up of citations: deleted citations are no longer shown, and -added ctations are shown without markup. (This was the default behaviour of latexdiff at versions 0.6 and older) - -=item Changes in complicated mathematical equations result in latex processing errors - -Try options C<--math-markup=whole>. If even that fails, you can turn off mark up for equations with C<--math-markup=off>. - -=back - -=head1 BUGS - -Option allow-spaces not implemented entirely consistently. It breaks -the rules that number and type of white space does not matter, as -different numbers of inter-argument spaces are treated as significant. - -Please submit bug reports on the latexdiff project page I, -send them to user discussion list C (prior subscription -to list required, also on project webpage) -or send them to I. Include the serial number of I -(from comments at the top of the source or use B<--version>). If you come across latex -files that are error-free and conform to the specifications set out -above, and whose differencing still does not result in error-free -latex, please send me those files, ideally edited to only contain the -offending passage as long as that still reproduces the problem. If your -file relies on non-standard class files, you must include those. I will not -look at examples where I have trouble to latex the original files. - -=head1 SEE ALSO - -L, L - -=head1 PORTABILITY - -I does not make use of external commands and thus should run -on any platform supporting Perl 5.6 or higher. If files with encodings -other than ASCII or UTF-8 are processed, Perl 5.8 or higher is required. - -The standard version of I requires installation of the Perl package -C (available from I - -I) but a stand-alone -version, I, which has this package inlined, is available, too. -I requires the I command to be present. - -=head1 AUTHOR - -Version 1.0.2 -Copyright (C) 2004-2012 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 - -Contributors of fixes and additions: V. Kuhlmann, J. Paisley, N. Becker, T. Doerges, K. Huebner, -T. Connors, Sebastian Gouezel and many others. -Thanks to the many people who send in bug reports, feature suggestions, and other feedback. - -=cut - -__END__ -%%BEGIN SAFE COMMANDS -% Regex matching commands which can safely be in the -% argument of a \DIFadd or \DIFdel command (leave out the \) -arabic -dashbox -emph -fbox -framebox -hspace -math.* -makebox -mbox -pageref -ref -symbol -raisebox -rule -text.* -shortstack -usebox -dag -ddag -copyright -pounds -S -P -oe -OE -ae -AE -aa -AA -o -O -l -L -frac -ss -sqrt -ldots -cdots -vdots -ddots -alpha -beta -gamma -delta -epsilon -varepsilon -zeta -eta -theta -vartheta -iota -kappa -lambda -mu -nu -xi -pi -varpi -rho -varrho -sigma -varsigma -tau -upsilon -phi -varphi -chi -psi -omega -Gamma -Delta -Theta -Lambda -Xi -Pi -Sigma -Upsilon -Phi -Psi -Omega -ps -mp -times -div -ast -star -circ -bullet -cdot -cap -cup -uplus -sqcap -vee -wedge -setminus -wr -diamond -(?:big)?triangle.* -lhd -rhd -unlhd -unrhd -oplus -ominus -otimes -oslash -odot -bigcirc -d?dagger -amalg -leq -prec -preceq -ll -(?:sq)?su[bp]set(?:eq)? -in -vdash -geq -succ(?:eq)? -gg -ni -dashv -equiv -sim(?:eq)? -asymp -approx -cong -neq -doteq -propto -models -perp -mid -parallel -bowtie -Join -smile -frown -.*arrow -(?:long)?mapsto -.*harpoon.* -leadsto -aleph -hbar -imath -jmath -ell -wp -Re -Im -mho -prime -emptyset -nabla -surd -top -bot -angle -forall -exists -neg -flat -natural -sharp -backslash -partial -infty -Box -Diamond -triangle -clubsuit -diamondsuit -heartsuit -spadesuit -sum -prod -coprod -int -oint -big(?:sq)?c[au]p -bigvee -bigwedge -bigodot -bigotimes -bigoplus -biguplus -(?:arc)?(?:cos|sin|tan|cot)h? -csc -arg -deg -det -dim -exp -gcd -hom -inf -ker -lg -lim -liminf -limsup -ln -log -max -min -Pr -sec -sup -[Hclbdruvt] -(SUPER|SUB)SCRIPTNB -(SUPER|SUB)SCRIPT -PERCENTAGE -DOLLAR -%%END SAFE COMMANDS - -%%BEGIN TEXT COMMANDS -% Regex matching commands with a text argument (leave out the \) -addcontents.* -cc -closing -chapter -dashbox -emph -encl -fbox -framebox -footnote -footnotetext -framebox -part -(sub){0,2}section\*? -(sub)?paragraph\*? -makebox -mbox -opening -parbox -raisebox -savebox -sbox -shortstack -signature -text.* -value -underline -sqrt -(SUPER|SUB)SCRIPT -%%END TEXT COMMANDS - -%%BEGIN CONTEXT1 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -caption -%%END CONTEXT1 COMMANDS - -%%BEGIN CONTEXT2 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -title -author -date -institute -%%END CONTEXT2 COMMANDS - - -%% TYPES (Commands for highlighting changed blocks) - -%DIF UNDERLINE PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}} -\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}} -%DIF END UNDERLINE PREAMBLE - -%DIF CTRADITIONAL PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} [..\footnote{removed: #1} ]}} -%DIF END CTRADITIONAL PREAMBLE - -%DIF TRADITIONAL PREAMBLE -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{[..\footnote{removed: #1} ]}} -%DIF END TRADITIONAL PREAMBLE - -%DIF CFONT PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} \scriptsize #1}} -%DIF END CFONT PREAMBLE - -%DIF FONTSTRIKE PREAMBLE -\RequirePackage[normalem]{ulem} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{\footnotesize \sout{#1}}} -%DIF END FONTSTRIKE PREAMBLE - -%DIF CCHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}#1}\protect\cbdelete} -%DIF END CCHANGEBAR PREAMBLE - -%DIF CFONTCHBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\sf #1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\scriptsize #1}\protect\cbdelete} -%DIF END CFONTCHBAR PREAMBLE - -%DIF CULINECHBAR PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage[dvips]{changebar} -\RequirePackage{color} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\uwave{#1}}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\sout{#1}}\protect\cbdelete} -%DIF END CULINECHBAR PREAMBLE - -%DIF CHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\providecommand{\DIFadd}[1]{\protect\cbstart{#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete} -%DIF END CHANGEBAR PREAMBLE - -%DIF INVISIBLE PREAMBLE -\providecommand{\DIFadd}[1]{#1} -\providecommand{\DIFdel}[1]{} -%DIF END INVISIBLE PREAMBLE - - -%% SUBTYPES (Markers for beginning and end of changed blocks) - -%DIF SAFE PREAMBLE -\providecommand{\DIFaddbegin}{} -\providecommand{\DIFaddend}{} -\providecommand{\DIFdelbegin}{} -\providecommand{\DIFdelend}{} -%DIF END SAFE PREAMBLE - -%DIF MARGIN PREAMBLE -\providecommand{\DIFaddbegin}{\protect\marginpar{a[}} -\providecommand{\DIFaddend}{\protect\marginpar{]}} -\providecommand{\DIFdelbegin}{\protect\marginpar{d[}} -\providecommand{\DIFdelend}{\protect\marginpar{]}} -%DIF END BRACKET PREAMBLE - -%DIF DVIPSCOL PREAMBLE -%Note: only works with dvips converter -\RequirePackage{color} -\RequirePackage{dvipscol} -\providecommand{\DIFaddbegin}{\protect\nogroupcolor{blue}} -\providecommand{\DIFaddend}{\protect\nogroupcolor{black}} -\providecommand{\DIFdelbegin}{\protect\nogroupcolor{red}} -\providecommand{\DIFdelend}{\protect\nogroupcolor{black}} -%DIF END DVIPSCOL PREAMBLE - -%DIF COLOR PREAMBLE -\RequirePackage{color} -\providecommand{\DIFaddbegin}{\protect\color{blue}} -\providecommand{\DIFaddend}{\protect\color{black}} -\providecommand{\DIFdelbegin}{\protect\color{red}} -\providecommand{\DIFdelend}{\protect\color{black}} -%DIF END COLOR PREAMBLE - - -%% FLOAT TYPES - -%DIF FLOATSAFE PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%DIF IDENTICAL PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{\DIFaddbegin} -\providecommand{\DIFaddendFL}{\DIFaddend} -\providecommand{\DIFdelbeginFL}{\DIFdelbegin} -\providecommand{\DIFdelendFL}{\DIFdelend} -%DIF END IDENTICAL PREAMBLE - -%DIF TRADITIONALSAFE PREAMBLE -% procidecommand color to make this work for TRADITIONAL and CTRADITIONAL -\providecommand{\color}[1]{} -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdel}[1]{{\protect\color{red}[..{\scriptsize {removed: #1}} ]}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%% SPECIAL PACKAGE PREAMBLE COMMANDS - -% Standard \DIFadd and \DIFdel are redefined as \DIFaddtex and \DIFdeltex -% when hyperref package is included. -%DIF HYPERREF PREAMBLE -\providecommand{\DIFadd}[1]{\texorpdfstring{\DIFaddtex{#1}}{#1}} -\providecommand{\DIFdel}[1]{\texorpdfstring{\DIFdeltex{#1}}{}} -%DIF END HYPERREF PACKAGE diff --git a/latexdiff-1.0.3/latexdiff-so b/latexdiff-1.0.3/latexdiff-so deleted file mode 100755 index e1f1d9b..0000000 --- a/latexdiff-1.0.3/latexdiff-so +++ /dev/null @@ -1,3872 +0,0 @@ -#!/usr/bin/env perl -##!/usr/bin/perl -w -# latexdiff - differences two latex files on the word level -# and produces a latex file with the differences marked up. -# -# Copyright (C) 2004-12 F J Tilmann (tilmann@gfz-potsdam.de, ftilmann@users.berlios.de) -# -# Project webpages: http://latexdiff.berlios.de/ -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# -# Version 1.0.3 -# - fix bug in add_safe_commands that made latexdiff hang on DeclareMathOperator -# command in preamble -# - \(..\) inline math expressions were not parsed correctly, if the contained a linebreak -# - applied patch contributed by tomflannaghan via Berlios: [ Patch #3431 ] Adds correct handling of \left< and \right> -# - \$ is treated correctly as a literal dollar sign (thanks to Reed Cartwright and Joshua Miller for reporting this bug -# and sketching out the solution) -# - \^ and \_ are correctly interpreted as accent and underlined space, respectively, not as superscript of subscript (thanks to Wail Yahyaoui for pointing out this bug) -# -# Version 1.0.1 - treat \big,\bigg etc. equivalently to \left and -# \right - include starred version in MATHENV - apply -# - flatten recursively and --flatten expansion is now -# aware of comments (thanks to Tim Connors for patch) -# - Change to post-processing for more reliability for -# deleted math environments -# - On linux systems, recognise and remove DOS style newlines -# - Provide markup for some special preamble commands (\title, -# \author,\date, -# - configurable by setting context2cmd -# - for styles using ulem package, remove \emph and \text.. from list of -# safe commands in order to allow linebreaks within the -# highlighted sections. -# - for ulem style, now show citations by enclosing them in \mbox commands. -# This unfortunately implies linebreaks within citations no longer function, -# so this functionality can be turned off (Option --disable-citation-markup). -# With --enable-citation-markup, the mbox markup is forced for other styles) -# - new substyle COLOR. This is particularly useful for marking up citations -# and some special post-processing is implemented to retain cite -# commands in deleted blocks. -# - four different levels of math-markup -# - Option --driver for choosing driver for modes employing changebar package -# - accept \\* as valid command (and other commands of form \.*). Also accept -# \ (backslashed newline) -# - some typo fixes, include commands defined in preamble as safe commands -# (Sebastian Gouezel) -# - include compared filenames as comments as line 2 and 3 of -# the preamble (can be modified with option --label, and suppressed with -# --no-label), option --visible-label to show files in generated pdf or dvi -# at the beginning of main document -# -# Version 0.5 A number of minor improvements based on feedback -# Deleted blocks are now shown before added blocks -# Package specific processing -# -# Version 0.43 unreleased typo in list of styles at the end -# Add protect to all \cbstart, \cbend commands -# More robust substitution of deleted math commands -# -# Version 0.42 November 06 Bug fixes only -# -# Version 0.4 March 06 option for fast differencing using UNIX diff command, several minor bug fixes (\par bug, improved highlighting of textcmds) -# -# Version 0.3 August 05 improved parsing of displayed math, --allow-spaces -# option, several minor bug fixes -# -# Version 0.25 October 04 Fix bug with deleted equations, add math mode commands to safecmd, add | to allowed interpunctuation signs -# Version 0.2 September 04 extension to utf-8 and variable encodings -# Version 0.1 August 04 First public release - -# Inserted block for stand-alone version replaces -# use Algorithm::Diff qw(traverse_sequences); -# in standard version -# The following BEGIN block contains a verbatim copy of -# Ned Konz' Algorithm::Diff package version 1.15 except -# that all POD documentation has been stripped out. -# I encourage you to download and install the Algorithm::Diff -# package and use the standard latexdiff version instead -# (current distribution available from http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15 -# the most recent version can be found via http://search.cpan.org/search?module=Algorithm::Diff ) -# Please note that the LICENCSE for Algorithm::Diff : -# "Copyright (c) 2000-2002 Ned Konz. All rights reserved. -# This program is free software; -# you can redistribute it and/or modify it under the same terms -# as Perl itself." -# The stand-alone version of latexdiff is provided as a convenience -# for latex users with no knowledge of PERL who do not wish to install -# additional packages to be able to use latexdiff. If you believe -# the inlining of Algorithm::Diff violates its license please contact -# me and I will modify the latexdiff distribution accordingly. -# Frederik Tilmann (tilmann@esc.cam.ac.uk) -BEGIN { -package Algorithm::Diff; -use strict; -use vars qw($VERSION @EXPORT_OK @ISA @EXPORT); -use integer; # see below in _replaceNextLargerWith() for mod to make - # if you don't use this -require Exporter; -@ISA = qw(Exporter); -@EXPORT = qw(); -@EXPORT_OK = qw(LCS diff traverse_sequences traverse_balanced sdiff); -$VERSION = sprintf('%d.%02d so', (q$Revision: 1.15 $ =~ /\d+/g)); - -# McIlroy-Hunt diff algorithm -# Adapted from the Smalltalk code of Mario I. Wolczko, -# by Ned Konz, perl@bike-nomad.com - - -# Create a hash that maps each element of $aCollection to the set of positions -# it occupies in $aCollection, restricted to the elements within the range of -# indexes specified by $start and $end. -# The fourth parameter is a subroutine reference that will be called to -# generate a string to use as a key. -# Additional parameters, if any, will be passed to this subroutine. -# -# my $hashRef = _withPositionsOfInInterval( \@array, $start, $end, $keyGen ); - -sub _withPositionsOfInInterval -{ - my $aCollection = shift; # array ref - my $start = shift; - my $end = shift; - my $keyGen = shift; - my %d; - my $index; - for ( $index = $start ; $index <= $end ; $index++ ) - { - my $element = $aCollection->[$index]; - my $key = &$keyGen( $element, @_ ); - if ( exists( $d{$key} ) ) - { - unshift ( @{ $d{$key} }, $index ); - } - else - { - $d{$key} = [$index]; - } - } - return wantarray ? %d : \%d; -} - -# Find the place at which aValue would normally be inserted into the array. If -# that place is already occupied by aValue, do nothing, and return undef. If -# the place does not exist (i.e., it is off the end of the array), add it to -# the end, otherwise replace the element at that point with aValue. -# It is assumed that the array's values are numeric. -# This is where the bulk (75%) of the time is spent in this module, so try to -# make it fast! - -sub _replaceNextLargerWith -{ - my ( $array, $aValue, $high ) = @_; - $high ||= $#$array; - - # off the end? - if ( $high == -1 || $aValue > $array->[-1] ) - { - push ( @$array, $aValue ); - return $high + 1; - } - - # binary search for insertion point... - my $low = 0; - my $index; - my $found; - while ( $low <= $high ) - { - $index = ( $high + $low ) / 2; - - # $index = int(( $high + $low ) / 2); # without 'use integer' - $found = $array->[$index]; - - if ( $aValue == $found ) - { - return undef; - } - elsif ( $aValue > $found ) - { - $low = $index + 1; - } - else - { - $high = $index - 1; - } - } - - # now insertion point is in $low. - $array->[$low] = $aValue; # overwrite next larger - return $low; -} - -# This method computes the longest common subsequence in $a and $b. - -# Result is array or ref, whose contents is such that -# $a->[ $i ] == $b->[ $result[ $i ] ] -# foreach $i in ( 0 .. $#result ) if $result[ $i ] is defined. - -# An additional argument may be passed; this is a hash or key generating -# function that should return a string that uniquely identifies the given -# element. It should be the case that if the key is the same, the elements -# will compare the same. If this parameter is undef or missing, the key -# will be the element as a string. - -# By default, comparisons will use "eq" and elements will be turned into keys -# using the default stringizing operator '""'. - -# Additional parameters, if any, will be passed to the key generation routine. - -sub _longestCommonSubsequence -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $keyGen = shift; # code ref - my $compare; # code ref - - # set up code refs - # Note that these are optimized. - if ( !defined($keyGen) ) # optimize for strings - { - $keyGen = sub { $_[0] }; - $compare = sub { my ( $a, $b ) = @_; $a eq $b }; - } - else - { - $compare = sub { - my $a = shift; - my $b = shift; - &$keyGen( $a, @_ ) eq &$keyGen( $b, @_ ); - }; - } - - my ( $aStart, $aFinish, $bStart, $bFinish, $matchVector ) = - ( 0, $#$a, 0, $#$b, [] ); - - # First we prune off any common elements at the beginning - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aStart], $b->[$bStart], @_ ) ) - { - $matchVector->[ $aStart++ ] = $bStart++; - } - - # now the end - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aFinish], $b->[$bFinish], @_ ) ) - { - $matchVector->[ $aFinish-- ] = $bFinish--; - } - - # Now compute the equivalence classes of positions of elements - my $bMatches = - _withPositionsOfInInterval( $b, $bStart, $bFinish, $keyGen, @_ ); - my $thresh = []; - my $links = []; - - my ( $i, $ai, $j, $k ); - for ( $i = $aStart ; $i <= $aFinish ; $i++ ) - { - $ai = &$keyGen( $a->[$i], @_ ); - if ( exists( $bMatches->{$ai} ) ) - { - $k = 0; - for $j ( @{ $bMatches->{$ai} } ) - { - - # optimization: most of the time this will be true - if ( $k and $thresh->[$k] > $j and $thresh->[ $k - 1 ] < $j ) - { - $thresh->[$k] = $j; - } - else - { - $k = _replaceNextLargerWith( $thresh, $j, $k ); - } - - # oddly, it's faster to always test this (CPU cache?). - if ( defined($k) ) - { - $links->[$k] = - [ ( $k ? $links->[ $k - 1 ] : undef ), $i, $j ]; - } - } - } - } - - if (@$thresh) - { - for ( my $link = $links->[$#$thresh] ; $link ; $link = $link->[0] ) - { - $matchVector->[ $link->[1] ] = $link->[2]; - } - } - - return wantarray ? @$matchVector : $matchVector; -} - -sub traverse_sequences -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $finishedACallback = $callbacks->{'A_FINISHED'}; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $finishedBCallback = $callbacks->{'B_FINISHED'}; - my $matchVector = _longestCommonSubsequence( $a, $b, $keyGen, @_ ); - - # Process all the lines in @$matchVector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai; - - for ( $ai = 0 ; $ai <= $#$matchVector ; $ai++ ) - { - my $bLine = $matchVector->[$ai]; - if ( defined($bLine) ) # matched - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi < $bLine; - &$matchCallback( $ai, $bi++, @_ ); - } - else - { - &$discardACallback( $ai, $bi, @_ ); - } - } - - # The last entry (if any) processed was a match. - # $ai and $bi point just past the last matching lines in their sequences. - - while ( $ai <= $lastA or $bi <= $lastB ) - { - - # last A? - if ( $ai == $lastA + 1 and $bi <= $lastB ) - { - if ( defined($finishedACallback) ) - { - &$finishedACallback( $lastA, @_ ); - $finishedACallback = undef; - } - else - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi <= $lastB; - } - } - - # last B? - if ( $bi == $lastB + 1 and $ai <= $lastA ) - { - if ( defined($finishedBCallback) ) - { - &$finishedBCallback( $lastB, @_ ); - $finishedBCallback = undef; - } - else - { - &$discardACallback( $ai++, $bi, @_ ) while $ai <= $lastA; - } - } - - &$discardACallback( $ai++, $bi, @_ ) if $ai <= $lastA; - &$discardBCallback( $ai, $bi++, @_ ) if $bi <= $lastB; - } - - return 1; -} - -sub traverse_balanced -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $changeCallback = $callbacks->{'CHANGE'}; - my $matchVector = _longestCommonSubsequence( $a, $b, $keyGen, @_ ); - - # Process all the lines in match vector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai = 0; - my $ma = -1; - my $mb; - - while (1) - { - - # Find next match indices $ma and $mb - do { $ma++ } while ( $ma <= $#$matchVector && !defined $matchVector->[$ma] ); - - last if $ma > $#$matchVector; # end of matchVector? - $mb = $matchVector->[$ma]; - - # Proceed with discard a/b or change events until - # next match - while ( $ai < $ma || $bi < $mb ) - { - - if ( $ai < $ma && $bi < $mb ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai < $ma ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi < $mb - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - # Match - &$matchCallback( $ai++, $bi++, @_ ); - } - - while ( $ai <= $lastA || $bi <= $lastB ) - { - if ( $ai <= $lastA && $bi <= $lastB ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai <= $lastA ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi <= $lastB - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - return 1; -} - -sub LCS -{ - my $a = shift; # array ref - my $matchVector = _longestCommonSubsequence( $a, @_ ); - my @retval; - my $i; - for ( $i = 0 ; $i <= $#$matchVector ; $i++ ) - { - if ( defined( $matchVector->[$i] ) ) - { - push ( @retval, $a->[$i] ); - } - } - return wantarray ? @retval : \@retval; -} - -sub diff -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $hunk = []; - my $discard = sub { push ( @$hunk, [ '-', $_[0], $a->[ $_[0] ] ] ) }; - my $add = sub { push ( @$hunk, [ '+', $_[1], $b->[ $_[1] ] ] ) }; - my $match = sub { push ( @$retval, $hunk ) if scalar(@$hunk); $hunk = [] }; - traverse_sequences( $a, $b, - { MATCH => $match, DISCARD_A => $discard, DISCARD_B => $add }, @_ ); - &$match(); - return wantarray ? @$retval : $retval; -} - -sub sdiff -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $discard = sub { push ( @$retval, [ '-', $a->[ $_[0] ], "" ] ) }; - my $add = sub { push ( @$retval, [ '+', "", $b->[ $_[1] ] ] ) }; - my $change = sub { - push ( @$retval, [ 'c', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - my $match = sub { - push ( @$retval, [ 'u', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - traverse_balanced( - $a, - $b, - { - MATCH => $match, - DISCARD_A => $discard, - DISCARD_B => $add, - CHANGE => $change, - }, - @_ - ); - return wantarray ? @$retval : $retval; -} - -1; -} -import Algorithm::Diff qw(traverse_sequences); -# End of inserted block for stand-alone version - -use Getopt::Long ; -use strict ; -use warnings; -use utf8 ; - -my ($algodiffversion)=split(/ /,$Algorithm::Diff::VERSION); - - -my ($versionstring)=< 0, - WHOLE => 1, - COARSE => 2, - FINE => 3 -}; - - -my (@configlist,@labels, - @appendsafelist,@excludesafelist, - @appendtextlist,@excludetextlist, - @appendcontext1list,@appendcontext2list, - @packagelist); -my ($assign,@config); -# Hash where keys corresponds to the names of all included packages (including the documentclass as another package -# the optional arguments to the package are the values of the hash elements -my ($pkg,%packages); -# Defaults -$type='UNDERLINE'; -$subtype='SAFE'; -$floattype='FLOATSAFE'; -$mathmarkup=COARSE; - -$verbose=0; -# output debug and intermediate files, set to 0 in final distribution -$debug=0; -# define character properties -sub IsNonAsciiPunct { return <<'END' # Unicode punctuation but excluding ASCII punctuation -+utf8::IsPunct --utf8::IsASCII -END -} -sub IsNonAsciiS { return <<'END' # Unicode symbol but excluding ASCII -+utf8::IsS --utf8::IsASCII -END -} - - -my %verbhash; - -Getopt::Long::Configure('bundling'); -GetOptions('type|t=s' => \$type, - 'subtype|s=s' => \$subtype, - 'floattype|f=s' => \$floattype, - 'config|c=s' => \@configlist, - 'preamble|p=s' => \$preamblefile, - 'encoding|e=s' => \$encoding, - 'label|L=s' => \@labels, - 'no-label' => \$nolabel, - 'visible-label' => \$visiblelabel, - 'exclude-safecmd|A=s' => \@excludesafelist, - 'replace-safecmd=s' => \$replacesafe, - 'append-safecmd|a=s' => \@appendsafelist, - 'exclude-textcmd|X=s' => \@excludetextlist, - 'replace-textcmd=s' => \$replacetext, - 'append-textcmd|x=s' => \@appendtextlist, - 'replace-context1cmd=s' => \$replacecontext1, - 'append-context1cmd=s' => \@appendcontext1list, - 'replace-context2cmd=s' => \$replacecontext2, - 'append-context2cmd=s' => \@appendcontext2list, - 'show-preamble' => \$showpreamble, - 'show-safecmd' => \$showsafe, - 'show-textcmd' => \$showtext, - 'show-config' => \$showconfig, - 'show-all' => \$showall, - 'packages=s' => \@packagelist, - 'allow-spaces' => \$allowspaces, - 'math-markup=s' => \$mathmarkup, - 'enable-citation-markup' => \$enablecitmark, - 'disable-citation-markup' => \$disablecitmark, - 'verbose|V' => \$verbose, - 'ignore-warnings' => \$ignorewarnings, - 'driver=s'=> \$driver, - 'flatten' => \$flatten, - 'version' => \$version, - 'help|h|H' => \$help); - -if ( $help ) { - usage() ; -} - - -if ( $version ) { - die $versionstring ; -} - -print STDERR $versionstring if $verbose; - -if (defined($showall)){ - $showpreamble=$showsafe=$showtext=$showconfig=1; -} - -if (defined($mathmarkup)) { - $mathmarkup=~tr/a-z/A-Z/; - if ( $mathmarkup eq 'OFF' ){ - $mathmarkup=OFF; - } elsif ( $mathmarkup eq 'WHOLE' ){ - $mathmarkup=WHOLE; - } elsif ( $mathmarkup eq 'COARSE' ){ - $mathmarkup=COARSE; - } elsif ( $mathmarkup eq 'FINE' ){ - $mathmarkup=FINE; - } elsif ( $mathmarkup !~ m/^[0123]$/ ) { - die "Illegal value: ($mathmarkup) for option--math-markup. Possible values: OFF,WHOLE,COARSE,FINE,0- "; - } - # else use numerical value -} - -# setting extra preamble commands -if (defined($preamblefile)) { - $latexdiffpreamble=join "\n",(extrapream($preamblefile),""); -} else { - $latexdiffpreamble=join "\n",(extrapream($type,$subtype,$floattype),""); -} - -if ( defined($driver) ) { - # for changebar only - $latexdiffpreamble=~s/\[dvips\]/[$driver]/sg; -} -# setting up @SAFECMDLIST and @SAFECMDEXCL -if (defined($replacesafe)) { - init_regex_arr_ext(\@SAFECMDLIST,$replacesafe); -} else { - init_regex_arr_data(\@SAFECMDLIST, "SAFE COMMANDS"); -} -foreach $appendsafe ( @appendsafelist ) { - init_regex_arr_ext(\@SAFECMDLIST, $appendsafe); -} -foreach $excludesafe ( @excludesafelist ) { - init_regex_arr_ext(\@SAFECMDEXCL, $excludesafe); -} - -# Special: treat all cite commands as safe except in UNDERLINE and FONTSTRIKE mode -# (there is a conflict between citation and ulem package, see -# package documentation) -# Use post-processing - -if ( uc($type) ne "UNDERLINE" && uc($type) ne "FONTSTRIKE" && uc($type) ne "CULINECHBAR" ) { - push (@SAFECMDLIST, qr/^cite.*$/); -} else { - ### Experimental: disable text and emph commands - push (@SAFECMDLIST, qr/^cite.*$/) unless $disablecitmark; - push(@SAFECMDEXCL, qr/^emph$/, qr/^text..$/); - # replace \cite{..} by \mbox{\cite{..}} in added or deleted blocks in post-processing - if ( uc($subtype) eq "COLOR" or uc($subtype) eq "DVIPSCOL" ) { - # remove \cite command again from list of safe commands - pop @SAFECMDLIST; - # deleted cite commands - $CITE2CMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite-type commands which should be reinstated in deleted blocks - } else { - $CITECMD='(?:cite\w*|nocite)' unless $disablecitmark ; # \cite commands which need to be protected within an mbox in UNDERLINE and other modes using ulem - } -} -$CITECMD='(?:cite\w*|nocite)' if $enablecitmark ; # as above for explicit selection - -# setting up @TEXTCMDLIST and @TEXTCMDEXCL -if (defined($replacetext)) { - init_regex_arr_ext(\@TEXTCMDLIST,$replacetext); -} else { - init_regex_arr_data(\@TEXTCMDLIST, "TEXT COMMANDS"); -} -foreach $appendtext ( @appendtextlist ) { - init_regex_arr_ext(\@TEXTCMDLIST, $appendtext); -} -foreach $excludetext ( @excludetextlist ) { - init_regex_arr_ext(\@TEXTCMDEXCL, $excludetext); -} - - -# setting up @CONTEXT1CMDLIST ( @CONTEXT1CMDEXCL exist but is always empty ) -if (defined($replacecontext1)) { - init_regex_arr_ext(\@CONTEXT1CMDLIST,$replacecontext1); -} else { - init_regex_arr_data(\@CONTEXT1CMDLIST, "CONTEXT1 COMMANDS"); -} -foreach $appendcontext1 ( @appendcontext1list ) { - init_regex_arr_ext(\@CONTEXT1CMDLIST, $appendcontext1); -} - - -# setting up @CONTEXT2CMDLIST ( @CONTEXT2CMDEXCL exist but is always empty ) -if (defined($replacecontext2)) { - init_regex_arr_ext(\@CONTEXT2CMDLIST,$replacecontext2); -} else { - init_regex_arr_data(\@CONTEXT2CMDLIST, "CONTEXT2 COMMANDS"); -} -foreach $appendcontext2 ( @appendcontext2list ) { - init_regex_arr_ext(\@CONTEXT2CMDLIST, $appendcontext2); -} - -# setting configuration variables -@config=(); -foreach $config ( @configlist ) { - if (-f $config ) { - open(FILE,$config) or die ("Couldn't open configuration file $config: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@config,$_); - } - close(FILE); - } - else { -# foreach ( split(",",$config) ) { -# push @config,$_; -# } - push @config,split(",",$config) - } -} -foreach $assign ( @config ) { - $assign=~ m/\s*(\w*)\s*=\s*(\S*)\s*$/ or die "Illegal assignment $assign in configuration list (must be variable=value)"; - if ( $1 eq "MINWORDSBLOCK" ) { $MINWORDSBLOCK = $2; } - elsif ( $1 eq "FLOATENV" ) { $FLOATENV = $2 ; } - elsif ( $1 eq "PICTUREENV" ) { $PICTUREENV = $2 ; } - elsif ( $1 eq "MATHENV" ) { $MATHENV = $2 ; } - elsif ( $1 eq "MATHREPL" ) { $MATHREPL = $2 ; } - elsif ( $1 eq "MATHARRENV" ) { $MATHARRENV = $2 ; } - elsif ( $1 eq "MATHARRREPL" ) { $MATHARRREPL = $2 ; } - elsif ( $1 eq "ARRENV" ) { $ARRENV = $2 ; } - elsif ( $1 eq "COUNTERCMD" ) { $COUNTERCMD = $2 ; } - else { die "Unknown variable $1 in assignment.";} -} - -if ( $mathmarkup == COARSE || $mathmarkup == WHOLE ) { - push(@MATHTEXTCMDLIST,qr/^MATHBLOCK(?:$MATHENV|$MATHARRENV|SQUAREBRACKET)$/); -} - - - -foreach $pkg ( @packagelist ) { - map { $packages{$_}="" } split(/,/,$pkg) ; -} - -if ($showpreamble) { - print "\nPreamble commands:\n"; - print $latexdiffpreamble ; -} - -if ($showsafe) { - print "\nCommands safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE (unless excluded):\n"; - print_regex_arr(@SAFECMDLIST); - print "\nCommands not safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE :\n"; - print_regex_arr(@SAFECMDEXCL); -} - -if ($showtext) { - print "\nCommands with last argument textual (unless excluded) and safe in every context:\n"; - print_regex_arr(@TEXTCMDLIST); - print "\nContext1 commands (last argument textual, command will be disabled in deleted passages, last argument will be shown as plain text):\n"; - print_regex_arr(@CONTEXT1CMDLIST); - print "\nContext2 commands (last argument textual, command and its argument will be disabled in deleted passages):\n"; - print_regex_arr(@CONTEXT2CMDLIST); - print "\nExclude list of Commands with last argument not textual (overrides patterns above):\n"; - print_regex_arr(@TEXTCMDEXCL); -} - - -if ($showconfig) { - print "Configuration variables:\n"; - print "MINWORDSBLOCK=$MINWORDSBLOCK\n"; - print "FLOATENV=$FLOATENV\n"; - print "PICTUREENV=$PICTUREENV\n"; - print "MATHENV=$MATHENV\n"; - print "MATHREPL=$MATHREPL\n"; - print "MATHARRENV=$MATHARRENV\n"; - print "MATHARRREPL=$MATHARRREPL\n"; - print "ARRENV=$ARRENV\n"; - print "COUNTERCMD=$COUNTERCMD\n"; -} -if ($showconfig || $showtext || $showsafe || $showpreamble) { - exit 0; } -if ( @ARGV != 2 ) { - print STDERR "2 and only 2 non-option arguments required. Write latexdiff -h to get help\n"; - exit(2); -} - -# Are extra spaces between command arguments permissible? -my $extraspace; -if ($allowspaces) { - $extraspace='\s*'; -} else { - $extraspace=''; -} - -# append context lists to text lists (as text property is implied) -push @TEXTCMDLIST, @CONTEXT1CMDLIST; -push @TEXTCMDLIST, @CONTEXT2CMDLIST; - -push @TEXTCMDLIST, @MATHTEXTCMDLIST if $mathmarkup==COARSE; - -# internal additions to SAFECMDLIST -push(@SAFECMDLIST, qr/^QLEFTBRACE$/, qr/^QRIGHTBRACE$/); - - -# Patterns. These are used by some of the subroutines, too -# I can only define them down here because value of extraspace depends on an option - my $pat0 = '(?:[^{}])*'; - my $pat1 = '(?:[^{}]|\{'.$pat0.'\})*'; - my $pat2 = '(?:[^{}]|\{'.$pat1.'\})*'; - my $pat3 = '(?:[^{}]|\{'.$pat2.'\})*'; - my $pat4 = '(?:[^{}]|\{'.$pat3.'\})*'; - my $pat5 = '(?:[^{}]|\{'.$pat4.'\})*'; - my $pat6 = '(?:[^{}]|\{'.$pat5.'\})*'; - my $brat0 = '(?:[^\[\]]|\\\[|\\\])*'; - - my $quotemarks = '(?:\'\')|(?:\`\`)'; - my $punct='[0.,\/\'\`:;\"\?\(\)\[\]!~\p{IsNonAsciiPunct}\p{IsNonAsciiS}]'; - my $number='-?\d*\.\d*'; - my $mathpunct='[+=<>\-\|]'; - my $and = '&'; - my $coords= '[\-.,\s\d]*'; -# word: sequence of letters or accents followed by letter - my $word='(?:[-\w\d*]|\\\\[\"\'\`~^][A-Za-z\*])+'; - my $cmdleftright='\\\\(?:left|right|[Bb]igg?[lrm]?|middle)\s*(?:[<>()\[\]|]|\\\\(?:[|{}]|\w+))'; - - my $cmdoptseq='\\\\[\w\d\*]+'.$extraspace.'(?:(?:\['.$brat0.'\]|\{'. $pat6 . '\}|\(' . $coords .'\))'.$extraspace.')*'; - my $backslashnl='\\\\\n'; - my $oneletcmd='\\\\.\*?(?:\['.$brat0.'\]|\{'. $pat6 . '\})*'; - my $math='\$(?:[^$]|\\\$)*?\$|\\\\[(](?:.|\n)*?\\\\[)]'; -## the current maths command cannot cope with newline within the math expression - - my $comment='%.*?\n'; - my $pat=qr/(?:\A\s*)?(?:${and}|${quotemarks}|${number}|${word}|$cmdleftright|${cmdoptseq}|${math}|${backslashnl}|${oneletcmd}|${comment}|${punct}|${mathpunct}|\{|\})\s*/ ; - - - -# now we are done setting up and can start working -my ($oldfile, $newfile) = @ARGV; -# check for existence of input files -if ( ! -e $oldfile ) { - die "Input file $oldfile does not exist."; -} -if ( ! -e $newfile ) { - die "Input file $newfile does not exist."; -} - - -# set the labels to be included into the file -my ($oldtime,$newtime,$oldlabel,$newlabel); -if (defined($labels[0])) { - $oldlabel=$labels[0] ; -} else { - $oldtime=localtime((stat($oldfile))[9]); - $oldlabel="$oldfile " . " "x(length($newfile)-length($oldfile)) . $oldtime; -} -if (defined($labels[1])) { - $newlabel=$labels[1] ; -} else { - $newtime=localtime((stat($newfile))[9]); - $newlabel="$newfile " . " "x(length($oldfile)-length($newfile)) . $newtime; -} - -$encoding=guess_encoding($newfile) unless defined($encoding); - -$encoding = "utf8" if $encoding =~ m/^utf8/i ; -if (lc($encoding) eq "utf8" ) { - binmode(STDOUT, ":utf8"); - binmode(STDERR, ":utf8"); -} - -$old=read_file_with_encoding($oldfile,$encoding); -$new=read_file_with_encoding($newfile,$encoding); - - - - -# reset time -exetime(1); -($oldpreamble,$oldbody,$oldpost)=splitdoc($old,'\\\\begin\{document\}','\\\\end\{document\}'); - - -($newpreamble,$newbody,$newpost)=splitdoc($new,'\\\\begin\{document\}','\\\\end\{document\}'); - - -if ($flatten) { - $oldbody=flatten($oldbody,$oldpreamble,$oldfile,$encoding); - $newbody=flatten($newbody,$newpreamble,$newfile,$encoding); -} - -my @auxlines; -if ( length $oldpreamble && length $newpreamble ) { - # pre-process preamble by looking for commands used in \maketitle (title, author, date etc commands) - # and marking up content with latexdiff markup - @auxlines=preprocess_preamble($oldpreamble,$newpreamble); - - @oldpreamble = split /\n/, $oldpreamble; - @newpreamble = split /\n/, $newpreamble; - - # If a command is defined in the preamble of the new file, and only uses safe commands, then it can be considered to be safe) (contribution S. Gouezel) - # Base this assessment on the new preamble - add_safe_commands($newpreamble); - - %packages=list_packages(@newpreamble) unless %packages; - if (defined $packages{"hyperref"} ) { - print STDERR "hyperref package detected.\n" if $verbose ; - $latexdiffpreamble =~ s/\{\\DIFadd\}/{\\DIFaddtex}/g; - $latexdiffpreamble =~ s/\{\\DIFdel\}/{\\DIFdeltex}/g; - $latexdiffpreamble .= join "\n",(extrapream("HYPERREF"),""); - } - print STDERR "Differencing preamble.\n" if $verbose; - - # insert dummy first line such that line count begins with line 1 (rather than perl's line 0) - just so that line numbers inserted by linediff are correct - unshift @newpreamble,''; - unshift @oldpreamble,''; - @diffpreamble = linediff(\@oldpreamble, \@newpreamble); - # remove dummy line again - shift @diffpreamble; - # add filenames, modification time and latexdiff mark - defined($nolabel) or splice @diffpreamble,1,0, - "%DIF LATEXDIFF DIFFERENCE FILE", - ,"%DIF DEL $oldlabel", - "%DIF ADD $newlabel"; - if ( @auxlines ) { - push @diffpreamble,"%DIF DELETED TITLE COMMANDS FOR MARKUP"; - push @diffpreamble,join("\n",@auxlines); - } - push @diffpreamble,$latexdiffpreamble; - push @diffpreamble,'\begin{document}'; -} -elsif ( !length $oldpreamble && !length $newpreamble ) { - @diffpreamble=(); -} else { - print STDERR "Either both texts must have preamble or neither text must have the preamble.\n"; - exit(2); -} - -if (defined $packages{"amsmath"} or defined $packages{"amsart"} or defined $packages{"amsbook"} ) { - print STDERR "amsmath package detected.\n" if $verbose ; - $MATHARRREPL='align*'; -} - -print STDERR "Preprocessing body. " if $verbose; -my ($oldleadin,$newleadin)=preprocess($oldbody,$newbody); - - -# run difference algorithm -@diffbody=bodydiff($oldbody, $newbody); -$diffbo=join("",@diffbody); -if ( $debug ) { - open(RAWDIFF,">","latexdiff.debug.bodydiff"); - print RAWDIFF $diffbo; - close(RAWDIFF); -} -print STDERR "(",exetime()," s)\n","Postprocessing body. \n " if $verbose; -postprocess($diffbo); -$diffall =join("\n",@diffpreamble) ; -# add visible labels -if (defined($visiblelabel)) { - # Give information right after \begin{document} (or at the beginning of the text for files without preamble - ### if \date command is used, add information to \date argument, otherwise give right after \begin{document} - ### $diffall=~s/(\\date$extraspace(?:\[$brat0\])?$extraspace)\{($pat6)\}/$1\{$2 \\ LATEXDIFF comparison \\ Old: $oldlabel \\ New: $newlabel \}/ or - $diffbo = "\\begin{verbatim}LATEXDIFF comparison\nOld: $oldlabel\nNew: $newlabel\\end{verbatim}\n$diffbo" ; -} - -$diffall .= "$newleadin$diffbo" ; -$diffall .= "\\end{document}$newpost" if length $newpreamble ; -if ( lc($encoding) ne "utf8" && lc($encoding) ne "ascii" ) { - print STDERR "Encoding output file to $encoding\n" if $verbose; - $diffall=Encode::encode($encoding,$diffall); - binmode STDOUT; -} -print $diffall; - - -print STDERR "(",exetime()," s)\n","Done.\n" if $verbose; - - - -## guess_encoding(filename) -## reads the first 20 lines of filename and looks for call of inputenc package -## if found, return the option of this package (encoding), otherwise return ascii -sub guess_encoding { - my ($filename)=@_; - my ($i,$enc); - open (FH, $filename) or die("Couldn't open $filename: $!"); - $i=0; - while () { - next if /^\s*%/; # skip comment lines - if (m/\\usepackage\[(\w*?)\]\{inputenc\}/) { - close(FH); - return($1); - } - last if (++$i > 20 ); # scan at most 20 non-comment lines - } - close(FH); - return("ascii"); -} - - -sub read_file_with_encoding { - my ($output); - my ($filename, $encoding) = @_; - - if (lc($encoding) eq "utf8" ) { - open (FILE, "<:utf8",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } elsif ( lc($encoding) eq "ascii") { - open (FILE, $filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } else { - require Encode; - open (FILE, "<",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - print STDERR "Converting $filename from $encoding to utf8\n" if $verbose; - $output=Encode::decode($encoding,$output); - } - close FILE; - if ($^O eq "linux" ) { - $output =~ s/\r\n/\n/g ; - } - return $output; -} - -# %packages=list_packages(@preamble) -# scans the arguments for \documentclass and \usepackage statements and constructs a hash -# whose keys are the included packages, and whose values are the associated optional arguments -sub list_packages { - my (@preamble)=@_; - my %packages=(); - foreach $line ( @preamble ) { - # get rid of comments - $line=~s/(?catfile($dirname,$fname), "\n" if $debug; - # content of file becomes replacement value (use recursion), add \newpage if the command was include - ###$replacement=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - $replacement=flatten(read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding), $preamble,$filename,$encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - # \include always starts a new page; use explicit \newpage command to simulate this - $begline=(defined($1)? $1 : "") ; - $newpage=(defined($3)? " \\newpage " : "") ; - "$begline$newpage$replacement$newpage"; - }/exgm; - - return($text); -} - - -# print_regex_arr(@arr) -# prints regex array without x-ism expansion put in by pearl to stdout -sub print_regex_arr { - my $dumstring; - $dumstring = join(" ",@_); # PERL generates string (?-xism:^ref$) for quoted refex ^ref$ - $dumstring =~ s/\(\?-xism:\^(.*?)\$\)/$1/g; # remove string and ^,$ marks before output - print $dumstring,"\n"; -} - - -# @lines=extrapream($type) -# reads line from appendix (end of file after __END__ token) -sub extrapream { - my $type; - my @retval=("%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - my ($copy); - - while (@_) { - $copy=0; - $type=shift ; - if ( -f $type ) { - open (FILE,$type) or die "Cannot open preamble file $type: $!"; - print STDERR "Reading preamble file $type\n" if $verbose ; - while () { - chomp ; - if ( $_ =~ m/%DIF PREAMBLE/ ) { - push (@retval,"$_"); - } else { - push (@retval,"$_ %DIF PREAMBLE"); - } - } - } - else { # not (-f $type) - $type=uc($type); # upcase argument - print STDERR "Preamble Internal Type $type\n" if $verbose; - while () { - if ( m/^%DIF $type/ ) { - $copy=1; } - elsif ( m/^%DIF END $type/ ) { - last; } - chomp; - push (@retval,"$_ %DIF PREAMBLE") if $copy; - } - if ( $copy == 0 ) { - print STDERR "\nPreamble style $type not implemented.\n"; - print STDERR "Write latexdiff -h to get help with available styles\n"; - exit(2); - } - seek DATA,0,0; # rewind DATA handle to file begin - } - } - push (@retval,"%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - return @retval; -} - - -# ($part1,$part2,$part3)=splitdoc($text,$word1,$word2) -# splits $text into 3 parts at $word1 and $word2. -# if neither $word1 nor $word2 exist, $part1 and $part3 are empty, $part2 is $text -# If only $word1 or $word2 exist but not the other, output an error message. - -# NB this version avoids $` and $' for performance reason although it only makes a tiny difference -# (in one test gain a tenth of a second for a 30s run) -sub splitdoc { - my ($text,$word1,$word2)=@_; - my ($part1,$part2,$part3)=("","",""); - my ($rest,$pos); - - if ( $text =~ m/(^[^%]*)($word1)/mg ) { - $pos=pos $text; - $part1=substr($text,0,$pos-length($2)); - $rest=substr($text,$pos); - if ( $rest =~ m/(^[^%]*)($word2)/mg ) { - $pos=pos $rest; - $part2=substr($rest,0,$pos-length($2)); - $part3=substr($rest,$pos); - } - else { - die "$word1 and $word2 not in the correct order or not present as a pair." ; - } - } else { - $part2=$text; - die "$word2 present but not $word1." if ( $text =~ m/(^[^%]*)$word2/ms ); - } - return ($part1,$part2,$part3); -} - - - - - -# bodydiff($old,$new) -sub bodydiff { - my ($oldwords, $newwords) = @_; - my @retwords; - - print STDERR "(",exetime()," s)\n","Splitting into latex tokens \n" if $verbose; - print STDERR "Parsing $oldfile \n" if $verbose; - my @oldwords = splitlatex($oldwords); - print STDERR "Parsing $newfile \n" if $verbose; - my @newwords = splitlatex($newwords); - - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - print STDERR "(",exetime()," s)\n","Pass 1: Expanding text commands and merging isolated identities with changed blocks " if $verbose; - pass1(\@oldwords, \@newwords); - - - print STDERR "(",exetime()," s)\n","Pass 2: inserting DIF tokens and mark up. " if $verbose; - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold2.tex"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew2.tex"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - @retwords=pass2(\@oldwords, \@newwords); - - return(@retwords); -} - - - - -# @words=splitlatex($string) -# split string according to latex rules -# Each element of words is either -# a word (including trailing spaces and punctuation) -# a latex command -sub splitlatex { - my ($string) = @_ ; - # if input is empty, return empty list - length($string)>0 or return (); - - my @retval=($string =~ m/$pat/osg); - - if (length($string) != length(join("",@retval))) { - print STDERR "\nWARNING: Inconsistency in length of input string and parsed string:\n This often indicates faulty or non-standard latex code.\n In many cases you can ignore this and the following warning messages.\n Note that character numbers in the following are counted beginning after \\begin{document} and are only approximate." unless $ignorewarnings; - print STDERR "DEBUG Original length ",length($string)," Parsed length ",length(join("",@retval)),"\n" if $debug; - print STDERR "DEBUG Input string: |$string|\n" if (length($string)<500) && $debug; - print STDERR "DEBUG Token parsing: |",join("+",@retval),"|\n" if (length($string)<500) && $debug ; - @retval=(); - # slow way only do this if other m//sg method fails - my $last = 0; - while ( $string =~ m/$pat/osg ) { - my $match=$&; - if ($last + length $& != pos $string ) { - my $pos=pos($string); - my $offset=30<$last ? 30 : $last; - my $dum=substr($string,$last-$offset,$pos-$last+2*$offset); - my $dum1=$dum; - my $cnt=$#retval; - my $i; - $dum1 =~ s/\n/ /g; - unless ($ignorewarnings) { - print STDERR "\n$dum1\n"; - print STDERR " " x 30,"^" x ($pos-$last)," " x 30,"\n"; - print STDERR "Missing characters near word " . (scalar @retval) . " character index: " . $last . "-" . pos($string) . " Length: " . length($match) . " Match: |$match| (expected match marked above).\n"; - } - # put in missing characters `by hand' - push (@retval, substr($dum,$offset,$pos-$last-length($match))); -# Note: there seems to be a bug in substr with utf8 that made the following line output substr which were too long, -# using dum instead appears to work -# push (@retval, substr($string,$last, pos($string)-$last-length($match))); - } - push (@retval, $match); - $last=pos $string; - } - - } - return @retval; -} - - -# pass1( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Where an common-subsequence block is flanked by deleted or appended blocks, -# and is shorter than $MINWORDSBLOCK words it is appended -# to the last deleted or appended word. If the block contains tokens other than words -# or punctuation it is not merged. -# Deleted or appended block consisting of words and safe commands only are -# also merged, to prevent break-up in pass2 (after previous isolated words have been removed) -# If there are commands with textual arguments (e.g. \caption) both in corresponding -# appended and deleted blocks split them such that the command and opening bracket -# are one token, then the rest is split up following standard rules, and the closing -# bracket is a separate token, ie. turn -# "\caption{This is a textual argument}" into -# ("\caption{","This ","is ","a ","textual ","argument","}") -# No return value. Destructively changes sequences -sub pass1 { - my $seq1 = shift ; - my $seq2 = shift ; - - my $len1 = scalar @$seq1; - my $len2 = scalar @$seq2; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - - my ($last1,$last2)=(-1,-1) ; - my $cnt=0; - my $block=[]; - my $addblock=[]; - my $delblock=[]; - my $todo=[]; - my $instruction=[]; - my $i; - my (@delmid,@addmid,@dummy); - - my ($addcmds,$delcmds,$matchindex); - my ($addtextblocks,$deltextblocks); - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $adddiscard = sub { - if ($cnt > 0 ) { - $matblkcnt++; - # just after an unchanged block -# print STDERR "Unchanged block $cnt, $last1,$last2 \n"; - if ($cnt < $MINWORDSBLOCK - && $cnt==scalar ( - grep { /^$wpat/ || ( /^\\([\w\d\*]+)((?:\[$brat0\]|\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && scalar(@dummy=split(" ",$2))<3 ) } - @$block) ) { - # merge identical blocks shorter than $MINWORDSBLOCK - # and only containing ordinary words - # with preceding different word - # We cannot carry out this merging immediately as this - # would change the index numbers of seq1 and seq2 and confuse - # the algorithm, instead we store in @$todo where we have to merge - push(@$todo, [ $last1,$last2,$cnt,@$block ]); - } - $block = []; - $cnt=0; $last1=-1; $last2=-1; - } - }; - my $discard=sub { $deltokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$delblock,[ $seq1->[$_[0]],$_[0] ]); - $last1=$_[0] }; - - my $add = sub { $addtokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$addblock,[ $seq2->[$_[1]],$_[1] ]); - $last2=$_[1] }; - - my $match = sub { $mattokcnt++; - if ($cnt==0) { # first word of matching sequence after changed sequence or at beginning of word sequence - $deltextblocks = extracttextblocks($delblock); - $delblkcnt++ if scalar @$delblock; - $addtextblocks = extracttextblocks($addblock); - $addblkcnt++ if scalar @$addblock; - - $delcmds = extractcommands($delblock); - $addcmds = extractcommands($addblock); - # keygen(third argument of _longestCommonSubsequence) implies to sort on command (0th elements of $addcmd elements) - # the calling format for longestCommonSubsequence has changed between versions of - # Algorithm::Diff so we need to check which one we are using - if ( $algodiffversion > 1.15 ) { - ### Algorithm::Diff 1.19 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, 0, sub { $_[0]->[0] } ); - } else { - ### Algorithm::Diff 1.15 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, sub { $_[0]->[0] } ); - } - - for ($i=0 ; $i<=$#$matchindex ; $i++) { - if (defined($matchindex->[$i])){ - $j=$matchindex->[$i]; - @delmid=splitlatex($delcmds->[$i][3]); - @addmid=splitlatex($addcmds->[$j][3]); - while (scalar(@$deltextblocks) && $deltextblocks->[0][0]<$delcmds->[$i][1]) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) }; - push(@$todo, [$index,-1,$cnt,@$block]); - } - push(@$todo, [ $delcmds->[$i][1],-1,-1,$delcmds->[$i][2],@delmid,$delcmds->[$i][4]]); - - while (scalar(@$addtextblocks) && $addtextblocks->[0][0]<$addcmds->[$j][1]) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - push(@$todo, [ -1,$addcmds->[$j][1],-1,$addcmds->[$j][2],@addmid,$addcmds->[$j][4]]); - } - } - # mop up remaining textblocks - while (scalar(@$deltextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) } ; - push(@$todo, [$index,-1,$cnt,@$block]); - } - while (scalar(@$addtextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - - $addblock=[]; - $delblock=[]; - } - push(@$block,$seq2->[$_[1]]); - $cnt++ }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - - - # now carry out the merging/splitting. Refer to elements relative from - # the end (with negative indices) as these offsets don't change before the instruction is executed - # cnt>0: merged small unchanged groups with previous changed blocks - # cnt==-1: split textual commands into components - foreach $instruction ( @$todo) { - ($last1,$last2,$cnt,@$block)=@$instruction ; - if ($cnt>=0) { - splice(@$seq1,$last1-$len1,1+$cnt,join("",$seq1->[$last1-$len1],@$block)) if $last1>=0; - splice(@$seq2,$last2-$len2,1+$cnt,join("",$seq2->[$last2-$len2],@$block)) if $last2>=0; - } else { - splice(@$seq1,$last1-$len1,1,@$block) if $last1>=0; - splice(@$seq2,$last2-$len2,1,@$block) if $last2>=0; - } - } - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens in $matblkcnt blocks.\n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } -} - - -# extracttextblocks(\@blockindex) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [[ $index, $textblock, $cnt ], .. -# where $index index of block to be merged -# $textblock contains all the words to be merged with the word at $index (but does not contain this word) -# $cnt is length of block -# -# requires: iscmd -# -sub extracttextblocks { - my $block=shift; - my ($i,$token,$index); - my $textblock=[]; - my $last=-1; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # store pure text blocks - if ($token =~ /$wpat/ || ( $token =~/^\\([\w\d\*]+)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && !iscmd($1,\@TEXTCMDLIST,\@TEXTCMDEXCL))) { - # we have text or a command which can be treated as text - if ($last<0) { - # new pure-text block - $last=$index; - } else { - # add to pure-text block - push(@$textblock, $token); - } - } else { - # it is not text - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - $textblock=[]; - $last=-1; - } - } - # finish processing a possibly unfinished block before returning - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - return($retval) -} - - - -# extractcommands( \@blockindex ) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [ [ "\cmd1", index, "\cmd1[optarg]{arg1}{", "arg2" ,"} " ],.. -# where index is just taken from input array -# command must have a textual argument as last argument -# -# requires: iscmd -# -sub extractcommands { - my $block=shift; - my ($i,$token,$index,$cmd,$open,$mid,$closing); - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: \cmd - # $3: last argument - # $4: } + trailing spaces - if ( ( $token =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL) ) { - # push(@$retval,[ $2,$index,$1,$3,$4 ]); - ($cmd,$open,$mid,$closing) = ($2,$1,$3,$4) ; - $closing =~ s/\}/\\RIGHTBRACE/ ; - push(@$retval,[ $cmd,$index,$open,$mid,$closing ]); - } - } - return $retval; -} - -# iscmd($cmd,\@regexarray,\@regexexcl) checks -# return 1 if $cmd matches any of the patterns in the -# array $@regexarray, and none of the patterns in \@regexexcl, otherwise return 0 -sub iscmd { - my ($cmd,$regexar,$regexexcl)=@_; - my ($ret)=0; - foreach $pat ( @$regexar ) { - if ( $cmd =~ m/^${pat}$/ ) { - $ret=1 ; - last; - } - } - return 0 unless $ret; - foreach $pat ( @$regexexcl ) { - return 0 if ( $cmd =~ m/^${pat}$/ ); - } - return 1; -} - - -# pass2( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Mark begin and end of deleted and appended sequences with tags $DELOPEN and $DELCLOSE -# and $ADDOPEN and $ADDCLOSE, respectively, however exclude { } & and all comands, unless -# they match an element of the whitelist (SAFECMD) -# For words in TEXTCMD but not in SAFECMD, enclose interior with $ADDOPEN and $ADDCLOSE brackets -# Deleted comment lines are marked with %DIF < -# Added comment lines are marked with %DIF > -sub pass2 { - my $seq1 = shift ; - my $seq2 = shift ; - - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $retval = []; - my $delhunk = []; - my $addhunk = []; - - my $discard = sub { $deltokcnt++; - push ( @$delhunk, $seq1->[$_[0]]) }; - - my $add = sub { $addtokcnt++; - push ( @$addhunk, $seq2->[$_[1]]) }; - - my $match = sub { $mattokcnt++; - if ( scalar @$delhunk ) { - $delblkcnt++; - # mark up changes, but comment out commands - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk); - $delhunk = []; - } - if ( scalar @$addhunk ) { - $addblkcnt++; - # we mark up changes, but simply quote commands - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk); - $addhunk = []; - } - push(@$retval,$seq2->[$_[1]]) }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - # clear up unprocessed hunks - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk) if scalar @$delhunk; - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk) if scalar @$addhunk; - - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens. \n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } - - return(@$retval); -} - -# marktags($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,\@block) -# returns ($openmark,$open,$block,$close,$closemark) if @block only contains no commands (except white-listed ones), -# braces, ampersands, or comments -# mark comments with $comment -# exclude all other exceptions from scope of open, close like this -# ($openmark, $open,...,$close, $opencmd,command, command,$closecmd, $open, ..., $close, $closemark) -# If $opencmd begins with "%" marktags assumes it is operating on a deleted block, otherwise on an added block -sub marktags { - my ($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,$block)=@_; - my $word; - my (@argtext); - my $retval=[]; - my $noncomment=0; - my $cmd=-1; # -1 at beginning 0: last token written is a ordinary word - # 1: last token written is a command - # for keeping track whether we are just in a command sequence or in a word sequence - my $cmdcomment= ($opencmd =~ m/^%/); # Flag to indicate whether opencmd is a comment (i.e. if we intend to simply comment out changed commands) - my ($command,$commandword,$closingbracket) ; # temporary variables needed below to remember sub-pattern matches - -# split this block to flatten out sequences joined in pass1 - @$block=splitlatex(join "",@$block); - foreach (@$block) { - $word=$_; - if ( $word =~ s/^%/%$comment/ ) { - # a comment - if ($cmd==1) { - push (@$retval,$closecmd) ; - $cmd=-1; - } - push (@$retval,$word); - next; - } - if (! $noncomment) { - push (@$retval,$openmark); - $noncomment=1; - } - # negative lookahead pattern (?!) in second clause is put in to avoid mathcing \( .. \) patterns - # also note that second pattern will match \\ - # Note: the second pattern should really be $word =~ /^\\(?!\()(\\|[\w*@]+)/, ie * replaced by + - # and then all commands \" \' etc declared safe. But as I don't have a complete list of one letter - # commands, and nobody has complained so far, I will eave this as is - if ( $word =~ /^[&{}\[\]]/ || ( $word =~ /^\\(?!\()(\\|[\w*@]*)/ && !iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL)) ) { - # word is a command or other significant token (not in SAFECMDLIST) - ## same conditions as in subroutine extractcommand: - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: cmd - # $3: last argument - # $4: } + trailing spaces - ### pre-0.3 if ( ( $token =~ m/^(\\([\w\d\*]+)(?:\[$brat0\]|\{$pat6\})*\{)($pat6)(\}\s*)$/so ) - if ( ( $word =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && (iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL)|| iscmd($2,\@MATHTEXTCMDLIST,\@MATHTEXTCMDEXCL)) - && ( !$cmdcomment || !iscmd($2,\@CONTEXT2CMDLIST, \@CONTEXT2CMDEXCL) ) ) { - # Condition 1: word is a command? - if yes, $1,$2,.. will be set as above - # Condition 2: word is a text command - we mark up the interior of the word. There is a separate check for MATHTEXTCMDLIST - # because for $mathmarkup=WHOLE, the commands should not be split in pass1 (ie. math mode commands are not in - # TEXTCMDLIST, but the interior of MATHTEXT commands should be highlighted in both deleted and added blocks - # Condition 3: But if we are in a deleted block ($cmdcomment=1) and - # $2 (the command) is in context2, just treat it as an ordinary command (i.e. comment it open with $opencmd) - # Because we do not want to disable this command - # here we do not use $opencmd and $closecmd($opencmd is empty) - if ($cmd==1) { - push (@$retval,$closecmd) ; - } elsif ($cmd==0) { - push (@$retval,$close) ; - } - $command=$1; $commandword=$2; $closingbracket=$4; - @argtext=splitlatex($3); # split textual argument into tokens - # and mark it up (but we do not need openmark and closemark) - # insert command with initial arguments, marked-up final argument, and closing bracket - if ( $cmdcomment && iscmd($commandword,\@CONTEXT1CMDLIST, \@CONTEXT1CMDEXCL) ) { - # context1cmd in a deleted environment; delete command itself but keep last argument, marked up - push (@$retval,$opencmd); - $command =~ s/\n/\n${opencmd}/sg ; # repeat opencmd at the beginning of each line - # argument, note that the additional comment character is included - # to suppress linebreak after opening parentheses, which is important - # for latexrevise - push (@$retval,$command,"%\n{$AUXCMD\n",marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } elsif ( iscmd($commandword,,\@MATHTEXTCMDLIST, \@MATHTEXTCMDEXCL) ) { - # MATHBLOCK pseudo command: consider all commands safe, except & and \\ - # Keep these commands even in deleted blocks, hence set $opencmd and $closecmd (5th and 6th argument of marktags) to - # "" - local @SAFECMDLIST=(".*"); - local @SAFECMDEXCL=('\\','\\\\'); - push(@$retval,$command,marktags("","",$open,$close,"","",$comment,\@argtext)#@argtext - ,$closingbracket); - } else { - # normal textcmd or context1cmd in an added block - push (@$retval,$command,marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } - push (@$retval,$AUXCMD,"\n") if $cmdcomment ; - $cmd=-1 ; - } else { - # ordinary command - push (@$retval,$opencmd) if $cmd==-1 ; - push (@$retval,$close,$opencmd) if $cmd==0 ; - $word =~ s/\n/\n${opencmd}/sg if $cmdcomment ; # if opencmd is a comment, repeat this at the beginning of every line - push (@$retval,$word); - $cmd=1; - } - } else { - # just an ordinary word or word in SAFECMD - push (@$retval,$open) if $cmd==-1 ; - push (@$retval,$closecmd,$open) if $cmd==1 ; - push (@$retval,$word); - $cmd=0; - } - } - push (@$retval,$close) if $cmd==0; - push (@$retval,$closecmd) if $cmd==1; - - push (@$retval,$closemark) if ($noncomment); - return @$retval; -} - -# preprocess($string, ..) -# carry out the following pre-processing steps for all arguments: -# 1. Remove leading white-space -# Change \{ to \LEFTBRACE and \} to \RIGHTBRACE -# #. change begin and end commands within comments to BEGINDIF, ENDDIF -# so they don't disturb the pattern matching (if there are several \begin or \end in one line -# 2. mark all first empty line (in block of several) with \PAR tokens -# 3. Convert all '\%' into '\PERCENTAGE ' and all '\$' into \DOLLAR to make parsing regular expressions easier -# 4. Convert all \verb|some verbatim text| commands (where | can be an arbitrary character) -# into \verb{hash} -# 5. Convert \begin{verbatim} some verbatim text \end{verbatim} into \verbatim{hash} -# 6. Convert _n into \SUBSCRIPTNB{n} and _{nnn} into \SUBSCRIPT{nn} -# 7. Convert ^n into \SUPERSCRIPTNB{n} and ^{nnn} into \SUPERSCRIPT{nn} -# 8. a. Convert $$ $$ into \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} -# b. Convert \[ \] into \begin{SQUAREBRACKET} \end{SQUAREBRACKET} -# 9. Convert all picture environmentent (\begin{PICTUREENV} .. \end{PICTUREENV} \PICTUREBLOCKenv -# For --block-math-markup option -convert all \begin{MATH} .. \end{MATH} -# into \MATHBLOCKmath{...} commands, where MATH/math is any valid math environment - -# 10. Add final token STOP to the very end. This is put in because the algorithm works better if the last token is identical. This is removed again in postprocessing. -# -# NB: step 6 and 7 is likely to convert some "_" inappropriately, e.g. in file -# names or labels but it does not matter because they are converted back in the postprocessing step -# Returns: leading white space removed in step 1 -sub preprocess { - my @leadin=() ; - for (@_) { - s/^(\s*)//s; - push(@leadin,$1); - # Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE - s/(?{$hstr}) && $string ne $hash->{$hstr}) { - warn "Repeated hash value for verbatim mode in spite of different content."; - $hstr="-$hstr"; - } - $hash->{$hstr}=$string; - return($hstr); -} - -#string=fromhash(\%hash,$fromstring) -# restores string value stored in hash -#string=fromhash(\%hash,$fromstring,$prependstring) -# additionally begins each line with prependstring -sub fromhash { - my ($hash,$hstr)=($_[0],$_[1]); - my $retstr=$hash->{$hstr}; - if ( $#_ >= 2) { - $retstr =~ s/^/$_[2]/mg; - } - return $retstr; -} - - -# postprocess($string, ..) -# carry out the following post-processing steps for all arguments: -# * Remove STOP token from the end -# * Replace \RIGHTBRACE by } -# * change citation commands within comments to protect from processing (using marker CITEDIF) -# 1. Check all deleted blocks: -# a.where a deleted block contains a matching \begin and -# \end environment (these will be disabled by a %DIFDELCMD statements), for selected environments enable -# these commands again (such that for example displayed math in a deleted equation -# is properly within math mode. For math mode environments replace numbered equation -# environments with their display only variety (so that equation numbers in new file and -# diff file are identical). Where the correct type of math environment cannot be determined -# use a place holder MATHMODE -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file -# Replace all MATHMODE environment commands by the correct environment to achieve matching -# pairs -# c. Convert MATHBLOCKmath commands to their uncounted numbers (e.g. convert equation -> displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL -# d. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# For added blocks: -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# 2. If --block-math-markup option set: Convert \MATHBLOCKmath{..} commands back to environments -# -# Convert all PICTUREblock{..} commands back to the appropriate environments -# 3. Convert DIFadd, DIFdel, DIFFaddbegin , ... into FL varieties -# within floats (currently recognised float environments: plate,table,figure -# plus starred varieties). -# 4. Remove empty %DIFDELCMD < lines -# 4. Convert \begin{SQUAREBRACKET} \end{SQUAREBRACKET} into \[ \] -# Convert \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} into $$ $$ -# 5. Convert \SUPERSCRIPTNB{n} into ^n and \SUPERSCRIPT{nn} into ^{nnn} -# 6. Convert \SUBSCRIPTNB{n} into _n and \SUBCRIPT{nn} into _{nnn} -# 7. Expand hashes of verb and verbatim environments -# 8. Convert '\PERCENTAGE ' back into '\%' and '\DOLLAR ' into '\$' -# 9.. remove all \PAR tokens -# 10. package specific processing: endfloat: make sure \begin{figure} and \end{figure} are always -# on a line by themselves, similarly for table environment -# 4, undo renaming of the \begin and \end in comments -# Change \QLEFTBRACE, \QRIGHTBRACE to \{,\} -# -# Note have to manually synchronize substitution commands below and -# DIF.. command names in the header -sub postprocess { - my ($begin,$len,$cnt,$float,$delblock,$addblock); - # second level blocks - my ($begin2,$cnt2,$len2,$eqarrayblock,$mathblock); - - for (@_) { - - # change $'s in comments to something harmless - 1 while s/(%.*)\$/$1DOLLARDIF/mg ; - - # Remove final STOP token - s/ STOP$//; - # Replace \RIGHTBRACE by } - s/\\RIGHTBRACE/}/g; - - # change citation commands within comments to protect from processing - if ($CITECMD){ - 1 while s/(%.*)\\($CITECMD)/$1\\CITEDIF$2/m ; - } - # Check all deleted blocks: where a deleted block contains a matching \begin and - # \end environment (these will be disabled by a %DIFDELCMD statements), enable - # these commands again (such that for example displayed math in a deleted equation - # is properly within math mode. For math mode environments replace numbered equation - # environments with their display only variety (so that equation numbers in new file and - # diff file are identical - while ( m/\\DIFdelbegin.*?\\DIFdelend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $delblock=$&; - - - ### (.*?[^\n]?)\n? construct is necessary to avoid empty lines in math mode, which result in - ### an error - # displayed math environments - if ($mathmarkup == FINE ) { - $delblock=~ s/(\%DIFDELCMD < \s*\\begin\{((?:$MATHENV)|SQUAREBRACKET)\}.*?(?:$DELCMDCLOSE|\n))(.*?[^\n]?)\n?(\%DIFDELCMD < \s*\\end\{\2\})/\\begin{$MATHREPL}$AUXCMD\n$1$3\n\\end{$MATHREPL}$AUXCMD\n$4/sg; - # also transform the opposite pair \end{displaymath} .. \begin{displaymath} but we have to be careful not to interfere with the results of the transformation in the line directly above - ### pre-0.42 obsolete version which did not work on eqnarray test $delblock=~ s/(? displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL - $delblock=~ s/\\MATHBLOCK($MATHENV)\{($pat6)\}/\\MATHBLOCK$MATHREPL\{$2\}/sg; - $delblock=~ s/\\MATHBLOCK($MATHARRENV)\{($pat6)\}/\\MATHBLOCK$MATHARRREPL\{$2\}/sg; - } - - -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file - $delblock=~ s/\\($COUNTERCMD)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*\s*${AUXCMD}\n)/\\$1$2\\addtocounter{$1}{-1}${AUXCMD}\n/sg ; - - -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es - while ( $delblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($delblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($delblock,$begin2,$len2)=$mathblock; - pos($delblock) = $begin2 + length($mathblock); - } - if ($CITE2CMD) { - $delblock=~s/($DELCMDOPEN\s*\\($CITE2CMD)(.*)$DELCMDCLOSE)/ - # Replacement code - {my ($aux,$all); - $aux=$all=$1; - $aux=~s#\n?($DELCMDOPEN|$DELCMDCLOSE)##g; - $all."$aux$AUXCMD\n";}/sge; - } - # or protect \cite commands with \mbox - if ($CITECMD) { - $delblock=~s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat6\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified delblock - substr($_,$begin,$len)=$delblock; - pos = $begin + length($delblock); - } - # make the array modification in added blocks - while ( m/\\DIFaddbegin.*?\\DIFaddend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $addblock=$&; - while ( $addblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($addblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($addblock,$begin2,$len2)=$mathblock; - pos($addblock) = $begin2 + length($mathblock); - } - if ($CITECMD) { - my $addblockbefore=$addblock; - $addblock=~ s/(\\($CITECMD)${extraspace}(?:\[$brat0\]${extraspace}){0,2}\{$pat2\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } -# splice in modified addblock - substr($_,$begin,$len)=$addblock; - pos = $begin + length($addblock); - } - - - ### old place for BEGINDIF, ENDDIF replacement - # change begin and end commands within comments such that they - # don't disturb the pattern matching (if there are several \begin or \end in one line - # this substitution is insufficient but that appears unlikely) - # This needs to be repeated here to also get rid of DIFdelcmd-protected environments - s/(%.*)\\begin\{(.*)$/$1\\BEGINDIF\{$2/mg ; - s/(%.*)\\end\{(.*)$/$1\\ENDDIF\{$2/mg ; - - # Replace MATHMODE environments from step 1a above by the correct Math environment - - # The next line is complicated. The negative look-ahead insertion makes sure that no \end{$MATHENV} (or other mathematical - # environments) are between the \begin{$MATHENV} and \end{MATHMODE} commands. This is necessary as the minimal matching - # is not globally minimal but only 'locally' (matching is beginning from the left side of the string) - if ( $mathmarkup == FINE ) { - 1 while s/\\begin{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}((?:.(?!(?:\\end{(?:(?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}|\\begin{MATHMODE})))*?)\\end{MATHMODE}/\\begin{$1}$2\\end{$1}/s; - 1 while s/\\begin{MATHMODE}((?:.(?!\\end{MATHMODE}))*?)\\end{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}/\\begin{$2}$1\\end{$2}/s; - # convert remaining \begin{MATHMODE} \end{MATHMODE} (and not containing & or \\ )into MATHREPL environments - s/\\begin{MATHMODE}((?:(.(?!(?[1])) { - $optargnew=$newhash{$cmd}->[1]; - } else { - $optargnew=""; - } - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - } else { - $optargold=""; - } - - if ( defined($oldhash{$cmd}) ) { - $argold=$oldhash{$cmd}->[2]; - } else { - $argold=""; - } - $argnew=$newhash{$cmd}->[2]; - $argdiff="{" . join("",bodydiff($argold,$argnew)) ."}"; - if ( length $optargnew ) { - $optargdiff="[".join("",bodydiff($optargold,$optargnew))."]" ; - $optargdiff =~ s/\\DIFaddbegin /\\DIFaddbeginFL /g; - $optargdiff =~ s/\\DIFaddend /\\DIFaddendFL /g; - $optargdiff =~ s/\\DIFadd\{/\\DIFaddFL{/g; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - ### print STDERR "DEBUG s/\\Q$newhash{$cmd}->[0]\\E/\\$cmd$optargdiff$argdiff/s\n"; - # Note: \Q and \E force literal interpretation of what it between them but allow - # variable interpolation, such that e.g. \title matches just that and not TAB-itle - $$newpreambleref=~s/\Q$newhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s; - # replace this in old preamble if necessary - if ( defined($oldhash{$cmd}->[0])) { - $$oldpreambleref=~s/\Q$oldhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s ; - } - ### print STDERR "DEBUG NEW PRE ".$$newpreambleref."\n"; - } - - foreach $cmd ( keys %oldhash ) { - # if this has already been dealt with above can just skip - next if defined($newhash{$cmd}) ; - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - $optargdiff="[".join("",bodydiff($optargold,""))."]" ; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - $argdiff="{" . join("",bodydiff($argold,"")) ."}"; - $auxline = "\\$cmd$optargdiff$argdiff"; - $auxline =~s/$/$AUXCMD/sg; - push @auxlines,$auxline; - } - # add auxcmd comment to highlight added lines - return(@auxlines); -} - - - -# @diffs=linediff(\@seq1, \@seq2) -# mark up lines like this -#%DIF mm-mmdnn -#%< old deleted line(s) -#%DIF ------- -#%DIF mmann-nn -#new appended line %< -#%DIF ------- -# Future extension: mark change explicitly -# Assumes: traverse_sequence traverses deletions before insertions in changed sequences -# all line numbers relative to line 0 (first line of real file) -sub linediff { - my $seq1 = shift ; - my $seq2 = shift ; - - my $block = []; - my $retseq = []; - my @begin=('','',''); # dummy initialisation - my $instring ; - - my $discard = sub { @begin=('d',$_[0],$_[1]) unless scalar @$block ; - push(@$block, "%DIF < " . $seq1->[$_[0]]) }; - my $add = sub { if (! scalar @$block) { - @begin=('a',$_[0],$_[1]) ;} - elsif ( $begin[0] eq 'd' ) { - $begin[0]='c'; $begin[2]=$_[1]; - push(@$block, "%DIF -------") } - push(@$block, $seq2->[$_[1]] . " %DIF > " ) }; - my $match = sub { if ( scalar @$block ) { - if ( $begin[0] eq 'd' && $begin[1]!=$_[0]-1) { - $instring = sprintf "%%DIF %d-%dd%d",$begin[1],$_[0]-1,$begin[2]; } - elsif ( $begin[0] eq 'a' && $begin[2]!=$_[1]-1) { - $instring = sprintf "%%DIF %da%d-%d",$begin[1],$begin[2],$_[1]-1; } - elsif ( $begin[0] eq 'c' ) { - $instring = sprintf "%%DIF %sc%s", - ($begin[1]==$_[0]-1) ? "$begin[1]" : $begin[1]."-".($_[0]-1) , - ($begin[2]==$_[1]-1) ? "$begin[2]" : $begin[2]."-".($_[1]-1) ; } - else { - $instring = sprintf "%%DIF %d%s%d",$begin[1],$begin[0],$begin[2]; } - push @$retseq, $instring,@$block, "%DIF -------" ; - $block = []; - } - push @$retseq, $seq2->[$_[1]] - }; - # key function: remove multiple spaces (such that insertion or deletion of redundant white space is not reported) - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - push @$retseq, @$block if scalar @$block; - - return wantarray ? @$retseq : $retseq ; -} - - - -# init_regex_arr_data(\@array,"TOKEN INIT") -# scans DATA file handel for line "%% TOKEN INIT" line -# then appends each line not beginning with % into array (as a quoted regex) -sub init_regex_arr_data { - my ($arr,$token)=@_; - my ($copy); - while () { - if ( m/^%%BEGIN $token\s*$/ ) { - $copy=1; } - elsif ( m/^%%END $token\s*/ ) { - last; } - chomp; - push (@$arr,qr/^$_$/) if ( $copy && !/^%/ ) ; - } - seek DATA,0,0; # rewind DATA handle to file begin -} - - -# init_regex_arr_ext(\@array,$arg) -# fills array with regular expressions. -# if arg is a file name, then read in list of regular expressions from that file -# (one expression per line) -# Otherwise treat arg as a comma separated list of regular expressions -sub init_regex_arr_ext { - my ($arr,$arg)=@_; - my $regex; - if ( -f $ arg ) { - open(FILE,"$arg") or die ("Couldn't open $arg: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@$arr,qr/^$_$/); - } - close(FILE); - } - else { - # assume it is a comma-separated list of reg-ex - foreach $regex (split(qr/(?=1) { - $reset=shift; - } - if ($reset) { - $lasttime=times(); - } - else { - $retval=times()-$lasttime; - $lasttime=$lasttime+$retval; - return($retval); - } -} - - -sub usage { - die <<"EOF"; -Usage: $0 [options] old.tex new.tex > diff.tex - -Compares two latex files and writes tex code to stdout, which has the same -format as new.tex but has all changes relative to old.tex marked up or commented. - ---type=markupstyle --t markupstyle Add code to preamble for selected markup style - Available styles: UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE - CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR - [ Default: UNDERLINE ] - ---subtype=markstyle --s markstyle Add code to preamble for selected style for bracketing - commands (e.g. to mark changes in margin) - Available styles: SAFE MARGINAL DVIPSCOL COLOR - [ Default: SAFE ] - ---floattype=markstyle --f markstyle Add code to preamble for selected style which - replace standard marking and markup commands within floats - (e.g., marginal remarks cause an error within floats - so marginal marking can be disabled thus) - Available styles: FLOATSAFE IDENTICAL - [ Default: FLOATSAFE ] - ---encoding=enc --e enc Specify encoding of old.tex and new.tex. Typical encodings are - ascii, utf8, latin1, latin9. A list of available encodings can be - obtained by executing - perl -MEncode -e 'print join ("\\n",Encode->encodings( ":all" )) ;' - [Default encoding is utf8 unless the first few lines of the preamble contain - an invocation "\\usepackage[..]{inputenc} in which case the - encoding chosen by this command is asssumed. Note that ASCII (standard - latex) is a subset of utf8] - ---preamble=file --p file Insert file at end of preamble instead of auto-generating - preamble. The preamble must define the following commands - \\DIFaddbegin,\\DIFaddend,\\DIFadd{..}, - \\DIFdelbegin,\\DIFdelend,\\DIFdel{..}, - and varieties for use within floats - \\DIFaddbeginFL,\\DIFaddendFL,\\DIFaddFL{..}, - \\DIFdelbeginFL,\\DIFdelendFL,\\DIFdelFL{..} - (If this option is set -t, -s, and -f options - are ignored.) - ---exclude-safecmd=exclude-file ---exclude-safecmd="cmd1,cmd2,..." --A exclude-file ---replace-safecmd=replace-file ---append-safecmd=append-file ---append-safecmd="cmd1,cmd2,..." --a append-file Exclude from, replace or append to the list of regex - matching commands which are safe to use within the - scope of a \\DIFadd or \\DIFdel command. The file must contain - one Perl-RegEx per line (Comment lines beginning with # or % are - ignored). A literal comma within the comma-separated list must be - escaped thus "\\,", Note that the RegEx needs to match the whole of - the token, i.e., /^regex\$/ is implied and that the initial - "\\" of the command is not included. The --exclude-safecmd - and --append-safecmd options can be combined with the --replace-safecmd - option and can be used repeatedly to add cumulatively to the lists. - ---exclude-textcmd=exclude-file ---exclude-textcmd="cmd1,cmd2,..." --X exclude-file ---replace-textcmd=replace-file ---append-textcmd=append-file ---append-textcmd="cmd1,cmd2,..." --x append-file Exclude from, replace or append to the list of regex - matching commands whose last argument is text. See - entry for --exclude-safecmd directly above for further details. - ---replace-context1cmd=replace-file ---append-context1cmd=append-file ---append-context1cmd="cmd1,cmd2,..." - Replace or append to the list of regex matching commands - whose last argument is text but which require a particular - context to work, e.g. \\caption will only work within a figure - or table. These commands behave like text commands, except when - they occur in a deleted section, when they are disabled, but their - argument is shown as deleted text. - ---replace-context2cmd=replace-file ---append-context2cmd=append-file ---append-context2cmd="cmd1,cmd2,..." - As corresponding commands for context1. The only difference is that - context2 commands are completely disabled in deleted sections, including - their arguments. - - ---config var1=val1,var2=val2,... --c var1=val1,.. Set configuration variables. --c configfile Available variables: - MINWORDSBLOCK (integer) - FLOATENV (RegEx) - PICTUREENV (RegEx) - MATHENV (RegEx) - MATHREPL (String) - MATHARRENV (RegEx) - MATHARRREPL (String) - ARRENV (RegEx) - COUNTERCMD (RegEx) - This option can be repeated. - - ---packages=pkg1,pkg2,.. - Tell latexdiff that .tex file is processed with the packages in list - loaded. This is normally not necessary if the .tex file includes the - preamble, as the preamble is automatically scanned for \\usepackage commands. - Use of the --packages option disables automatic scanning, so if for any - reason package specific parsing needs to be switched off, use --packages=none. - The following packages trigger special behaviour: - endfloat hyperref amsmath - [ Default: scan the preamble for \\usepackage commands to determine - loaded packages.] - ---show-preamble Print generated or included preamble commands to stdout. - ---show-safecmd Print list of regex matching and excluding safe commands. - ---show-textcmd Print list of regex matching and excluding commands with text argument. - ---show-config Show values of configuration variables - ---show-all Show all of the above - - NB For all --show commands, no old.tex or new.tex file needs to be given, and no - differencing takes place. - -Other configuration options: - ---allow-spaces Allow spaces between bracketed or braced arguments to commands - [Default requires arguments to directly follow each other without - intervening spaces] - ---math-markup=level Determine granularity of markup in displayed math environments: - Possible values for level are (both numerical and text labels are acceptable): - off or 0: suppress markup for math environments. Deleted equations will not - appear in diff file. This mode can be used if all the other modes - cause invalid latex code. - whole or 1: Differencing on the level of whole equations. Even trivial changes - to equations cause the whole equation to be marked changed. This - mode can be used if processing in coarse or fine mode results in - invalid latex code. - coarse or 2: Detect changes within equations marked up with a coarse - granularity; changes in equation type (e.g.displaymath to equation) - appear as a change to the complete equation. This mode is recommended - for situations where the content and order of some equations are still - being changed. [Default] - fine or 3: Detect small change in equations and mark up and fine granularity. - This mode is most suitable, if only minor changes to equations are - expected, e.g. correction of typos. - ---disable-citation-markup Suppress citation markup in styles using ulem (UNDERLINE, - FONTSTRIKE, CULINECHBAR) ---enable-citation-markup Protect citation commands in changed sections with \\mbox command - [i.e. use default behaviour for ulem package for other packages] - -Miscelleneous options - ---label=label --L label Sets the labels used to describe the old and new files. The first use - of this option sets the label describing the old file and the second - use of the option sets the label for the new file. - [Default: use the filename and modification dates for the label] - ---no-label Suppress inclusion of old and new file names as comment in output file - ---visble-label Include old and new filenames (or labels set with --label option) as - visible output - ---flatten Replace \\input and \\include commands within body by the content - of the files in their argument. If \\includeonly is present in the - preamble, only those files are expanded into the document. However, - no recursion is done, i.e. \\input and \\include commands within - included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, - respectively, making it possible to organise files into old and new directories. - --flatten is applied recursively, so inputted files can contain further - \\input statements. - ---help --h Show this help text. - ---ignore-warnings Suppress warnings about inconsistencies in length between input - and parsed strings and missing characters. - ---verbose --V Output various status information to stderr during processing. - Default is to work silently. - ---version Show version number. - -For further information, consult http://latexdiff.berlios.de -EOF -} - -=head1 NAME - -latexdiff - determine and markup differences between two latex files - -=head1 SYNOPSIS - -B [ B ] F F > F - -=head1 DESCRIPTION - -Briefly, I is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called C and C, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. - -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "S>>" is appended to each added line, i.e. a -line present in C but not in C. Discarded lines - are deactivated by prepending "S>>". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file C will be similar to -C. At the end of the preamble, the definitions for I markup commands are inserted. -In differencing the main body of the text, I attempts to -satisfy the following guidelines (in order of priority): - -=over 3 - -=item 1 - -If both C and C are valid LaTeX, then the resulting -C should also be valid LateX. (NB If a few plain TeX commands -are used within C or C then C is not -guaranteed to work but usually will). - -=item 2 - -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -C. - -=item 3 - -If a changed passage contains text or text-producing commands, then -running C through LateX should produce output where added -and discarded passages are highlighted. - -=item 4 - -Where there are insignificant differences, e.g. in the positioning of -line breaks, C should follow the formatting of C - -=back - -For differencing the same algorithm as I is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, C<\caption> and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write - - \section{\textem{This is an emphasized section title}} - -and not - - \section {\textem{This is an emphasized section title}} - -or - - \section\textem{This is an emphasized section title} - -even though all varieties are the same to LaTeX (but see -B<--allow-spaces> option which allows the second variety). - -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the PICTUREENV configuration variable, set by -default to C and C environments; see B<--config> -option). The latter environment (C) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by C<\begin{DIFnomarkup}> and C<\end{DIFnomarkup}>. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, - -C<\newenvironment{DIFnomarkup}{}{}> - -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. - -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. - -All markup commands inserted by I begin with "C<\DIF>". Added -blocks containing words, commands or comments which are in C -but not in C are marked by C<\DIFaddbegin> and C<\DIFaddend>. -Discarded blocks are marked by C<\DIFdelbegin> and C<\DIFdelend>. -Within added blocks all text is highlighted with C<\DIFadd> like this: -C<\DIFadd{Added text block}> -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces "{" and "}" are never put within -the scope of C<\DIFadd>. Added comments are marked by prepending -"S >>". - -Within deleted blocks text is highlighted with C<\DIFdel>. Deleted -comments are marked by prepending "S >>". Non-safe command -and curly braces within deleted blocks are commented out with -"S >>". - - - -=head1 OPTIONS - -=head2 Preamble - -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. - -=over 4 - -=item B<--type=markupstyle> or -B<-t markupstyle> - -Add code to preamble for selected markup style. This option defines -C<\DIFadd> and C<\DIFdel> commands. -Available styles: - -C - -[ Default: C ] - -=item B<--subtype=markstyle> or -B<-s markstyle> - -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -C<\DIFaddbegin>, C<\DIFaddend>, C<\DIFdelbegin> and C<\DIFdelend> commands. -Available styles: C - -[ Default: C ] - -=item B<--floattype=markstyle> or -B<-f markstyle> - -Add code to preamble for selected style which -replace standard marking and markup commands within floats -(e.g., marginal remarks cause an error within floats -so marginal marking can be disabled thus). This option defines all -C<\DIF...FL> commands. -Available styles: C - -[ Default: C ] - -=item B<--encoding=enc> or -B<-e enc> - -Specify encoding of old.tex and new.tex. Typical encodings are -C, C, C, C. A list of available encodings can be -obtained by executing - -Cencodings( ":all" )) ;' > - -[Default encoding is utf8 unless the first few lines of the preamble contain -an invocation C<\usepackage[..]{inputenc}> in which case the -encoding chosen by this command is asssumed. Note that ASCII (standard -latex) is a subset of utf8] - -=item B<--preamble=file> or -B<-p file> - -Insert file at end of preamble instead of generating -preamble. The preamble must define the following commands -C<\DIFaddbegin, \DIFaddend, \DIFadd{..}, -\DIFdelbegin,\DIFdelend,\DIFdel{..},> -and varieties for use within floats -C<\DIFaddbeginFL, \DIFaddendFL, \DIFaddFL{..}, -\DIFdelbeginFL, \DIFdelendFL, \DIFdelFL{..}> -(If this option is set B<-t>, B<-s>, and B<-f> options -are ignored.) - -=item B<--packages=pkg1,pkg2,..> - -Tell latexdiff that .tex file is processed with the packages in list -loaded. This is normally not necessary if the .tex file includes the -preamble, as the preamble is automatically scanned for C<\usepackage> commands. -Use of the B<--packages> option disables automatic scanning, so if for any -reason package specific parsing needs to be switched off, use B<--packages=none>. -The following packages trigger special behaviour: - -=over 8 - -=item C - -Configuration variable amsmath is set to C (Default: C) - -=item C - -Ensure that C<\begin{figure}> and C<\end{figure}> always appear by themselves on a line. - -=item C - -Change name of C<\DIFadd> and C<\DIFdel> commands to C<\DIFaddtex> and C<\DIFdeltex> and -define new C<\DIFadd> and C<\DIFdel> commands, which provide a wrapper for these commands, -using them for the text but not for the link defining command (where any markup would cause -errors). - -=back - -[ Default: scan the preamble for C<\\usepackage> commands to determine - loaded packages.] - - - -=item B<--show-preamble> - -Print generated or included preamble commands to stdout. - -=back - -=head2 Configuration - -=over 4 - -=item B<--exclude-safecmd=exclude-file> or -B<-A exclude-file> or B<--exclude-safecmd="cmd1,cmd2,..."> - -=item B<--replace-safecmd=replace-file> - -=item B<--append-safecmd=append-file> or -B<-a append-file> or B<--append-safecmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions (RegEx) -matching commands which are safe to use within the -scope of a C<\DIFadd> or C<\DIFdel> command. The file must contain -one Perl-RegEx per line (Comment lines beginning with # or % are -ignored). Note that the RegEx needs to match the whole of -the token, i.e., /^regex$/ is implied and that the initial -"\" of the command is not included. -The B<--exclude-safecmd> and B<--append-safecmd> options can be combined with the -B<--replace-safecmd> -option and can be used repeatedly to add cumulatively to the lists. - B<--exclude-safecmd> -and B<--append-safecmd> can also take a comma separated list as input. If a -comma for one of the regex is required, escape it thus "\,". In most cases it -will be necessary to protect the comma-separated list from the shell by putting -it in quotation marks. - -=item B<--exclude-textcmd=exclude-file> or -B<-X exclude-file> or B<--exclude-textcmd="cmd1,cmd2,..."> - -=item B<--replace-textcmd=replace-file> - -=item B<--append-textcmd=append-file> or -B<-x append-file> or B<--append-textcmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions -matching commands whose last argument is text. See -entry for B<--exclude-safecmd> directly above for further details. - - -=item B<--replace-context1cmd=replace-file> - -=item B<--append-context1cmd=append-file> or -=item B<--append-context1cmd="cmd1,cmd2,..."> - -Replace or append to the list of regex matching commands -whose last argument is text but which require a particular -context to work, e.g. \caption will only work within a figure -or table. These commands behave like text commands, except when -they occur in a deleted section, when they are disabled, but their -argument is shown as deleted text. - -=item B<--replace-context2cmd=replace-file> - -=item B<--append-context2cmd=append-file> or -=item B<--append-context2cmd="cmd1,cmd2,..."> -As corresponding commands for context1. The only difference is that -context2 commands are completely disabled in deleted sections, including -their arguments. - - - -=item B<--config var1=val1,var2=val2,...> or B<-c var1=val1,..> - -=item B<-c configfile> - -Set configuration variables. The option can be repeated to set different -variables (as an alternative to the comma-separated list). -Available variables (see below for further explanations): - -C (integer) - -C (RegEx) - -C (RegEx) - -C (RegEx) - -C (String) - -C (RegEx) - -C (String) - -C (RegEx) - -C (RegEx) - -=item B<--show-safecmd> - -Print list of RegEx matching and excluding safe commands. - -=item B<--show-textcmd> - -Print list of RegEx matching and excluding commands with text argument. - -=item B<--show-config> - -Show values of configuration variables. - -=item B<--show-all> - -Combine all --show commands. - -NB For all --show commands, no C or C file needs to be specified, and no -differencing takes place. - -=back - -=head2 Other configuration options: - -=over 4 - -=item B<--allow-spaces> - -Allow spaces between bracketed or braced arguments to commands. Note -that this option might have undesirable side effects (unrelated scope -might get lumpeded with preceding commands) so should only be used if the -default produces erroneous results. (Default requires arguments to -directly follow each other without intervening spaces). - -=item B<--math-markup=level> - -Determine granularity of markup in displayed math environments: -Possible values for level are (both numerical and text labels are acceptable): - -C or C<0>: suppress markup for math environments. Deleted equations will not -appear in diff file. This mode can be used if all the other modes -cause invalid latex code. - -C or C<1>: Differencing on the level of whole equations. Even trivial changes -to equations cause the whole equation to be marked changed. This -mode can be used if processing in coarse or fine mode results in -invalid latex code. - -C or C<2>: Detect changes within equations marked up with a coarse -granularity; changes in equation type (e.g.displaymath to equation) -appear as a change to the complete equation. This mode is recommended -for situations where the content and order of some equations are still -being changed. [Default] - -C or C<3>: Detect small change in equations and mark up at fine granularity. -This mode is most suitable, if only minor changes to equations are -expected, e.g. correction of typos. - -=item B<--disable-citation-markup> - -Suppress citation markup in styles using ulem (UNDERLINE, -FONTSTRIKE, CULINECHBAR) - -=item B<--enable-citation-markup> - -Protect citation commands in changed sections with \\mbox command [i.e. use default behaviour for ulem package for other packages] - -=back - -=head2 Miscellaneous - -=over 4 -=item B<--verbose> or B<-V> - -Output various status information to stderr during processing. -Default is to work silently. - -=item B<--driver=type> - -Choose driver for changebar package (only relevant for styles using - changebar: CCHANGEBAR CFONTCHBAR CULINECHBAR CHANGEBAR). Possible -drivers are listed in changebar manual, e.g. pdftex,dvips,dvitops - [Default: dvips] - -=item B<--ignore-warnings> - -Suppress warnings about inconsistencies in length between input and -parsed strings and missing characters. These warning messages are -often related to non-standard latex or latex constructions with a -syntax unknown to C but the resulting difference argument -is often fully functional anyway, particularly if the non-standard -latex only occurs in parts of the text which have not changed. - -=item B<--label=label> or -B<-L label> - -Sets the labels used to describe the old and new files. The first use -of this option sets the label describing the old file and the second -use of the option sets the label for the new file, i.e. set both -labels like this C<-L labelold -L labelnew>. -[Default: use the filename and modification dates for the label] - -=item B<--no-label> - -Suppress inclusion of old and new file names as comment in output file - -=item B<--visble-label> - -Include old and new filenames (or labels set with --label option) as -visible output. - -=item B<--flatten> - -Replace C<\input> and C<\include> commands within body by the content -of the files in their argument. If C<\includeonly> is present in the -preamble, only those files are expanded into the document. However, -no recursion is done, i.e. C<\input> and C<\include> commands within -included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, -respectively, making it possible to organise files into old and new directories. ---flatten is applied recursively, so inputted files can contain further -C<\input> statements. - -Use of this option might result in prohibitive processing times for -larger documents, and the resulting difference document -no longer reflects the structure of the input documents. - -=item B<--help> or -B<-h> - -Show help text - -=item B<--version> - -Show version number - -=back - - - -=head2 Predefined styles - -=head2 Major types - -The major type determine the markup of plain text and some selected latex commands outside floats by defining the markup commands C<\DIFadd{...}> and C<\DIFdel{...}> . - -=over 10 - -=item C - -Added text is wavy-underlined and blue, discarded text is struck out and red -(Requires color and ulem packages). Overstriking does not work in displayed math equations such that deleted parts of equation are underlined, not struck out (this is a shortcoming inherent to the ulem package). - -=item C - -Added text is blue and set in sans-serif, and a red footnote is created for each discarded -piece of text. (Requires color package) - -=item C - -Like C but without the use of color. - -=item C - -Added text is blue and set in sans-serif, and discarded text is red and very small size. - -=item C - -Added tex is set in sans-serif, discarded text small and struck out - -=item C - -Added text is blue, and discarded text is red. Additionally, the changed text is marked with a bar in the margin (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color, ulem and changebar packages). - -=item C - -No mark up of text, but mark margins with changebars (Requires changebar package). - -=item C - -No visible markup (but generic markup commands will still be inserted. - -=back - -=head2 Subtypes - -The subtype defines the commands that are inserted at the begin and end of added or discarded blocks, irrespectively of whether these blocks contain text or commands (Defined commands: C<\DIFaddbegin, \DIFaddend, \DIFdelbegin, \DIFdelend>) - -=over 10 - -=item C - -No additional markup (Recommended choice) - -=item C - -Mark beginning and end of changed blocks with symbols in the margin nearby (using -the standard C<\marginpar> command - note that this sometimes moves somewhat -from the intended position. - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. -(It is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete, for example -with citation commands). - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. Note -that C only works with the dvips converter, e.g. not pdflatex. -(it is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete). - -=back - -=head2 Float Types - -Some of the markup used in the main text might cause problems when used within -floats (e.g. figures or tables). For this reason alternative versions of all -markup commands are used within floats. The float type defines these alternative commands. - -=over 10 - -=item C - -Use identical markup for text as in the main body, but set all commands marking the begin and end of changed blocks to null-commands. You have to choose this float type if your subtype is C as C<\marginpar> does not work properly within floats. - -=item C - -Mark additions the same way as in the main text. Deleted environments are marked by angular brackets \[ and \] and the deleted text is set in scriptscript size. This float type should always be used with the C and C markup types as the \footnote command does not work properly in floating environments. - -=item C - -Make no difference between the main text and floats. - -=back - - -=head2 Configuration Variables - -=over 10 - -=item C - -Minimum number of tokens required to form an independent block. This value is -used in the algorithm to detect changes of complete blocks by merging identical text parts of less than C to the preceding added and discarded parts. - -[ Default: 3 ] - -=item C - -Environments whose name matches the regular expression in C are -considered floats. Within these environments, the I markup commands -are replaced by their FL variaties. - -[ Default: S >] - -=item C - -Within environments whose name matches the regular expression in C -all latexdiff markup is removed (in pathologic cases this might lead to - inconsistent markup but this situation should be rare). - -[ Default: S >] - -=item C,C - -If both \begin and \end for a math environment (environment name matching C -or \[ and \]) -are within the same deleted block, they are replaced by a \begin and \end commands for C -rather than being commented out. - -[ Default: C=S >, C=S >] - -=item C,C - -as C,C but for equation arrays - -[ Default: C=S >, C=S >] - -=item C - -If a match to C is found within an inline math environment within a deleted or added block, then the inlined math -is surrounded by C<\mbox{>...C<}>. This is necessary as underlining does not work within inlined array environments. - -[ Default: C=S > - -=item C - -If a command in a deleted block which is also in the textcmd list matches C then an -additional command C<\addtocounter{>FC<}{-1}>, where F is the matching command, is appended in the diff file such that the numbering in the diff file remains synchronized with the -numbering in the new file. - -[ Default: C=C<(?:footnote|part|section|subsection> ... - -C<|subsubsection|paragraph|subparagraph)> ] - -=back - -=head1 COMMON PROBLEMS - -=over 10 - -=item Citations result in overfull boxes - -There is an incompatibility between the C package, which C uses for underlining and striking out in the UNDERLINE style, -the default style. In order to be able to mark up citations properly, they are placed with an C<\mbox> command in post-processing. As mboxes -cannot be broken across lines, this procedure frequently results in overfull boxes, possibly obscuring the content as it extends beyond the right margin. If this is a problem, you have two possibilities: - -1. Use C or C subtype markup (option C<-s COLOR>): If this markup is chosen, then changed citations are no longer marked up -with the wavy line (additions) or struck out (deletions), but are still highlighted in the appropriate color. - -2. Choose option C<--disable-citation-markup> which turns off the marking up of citations: deleted citations are no longer shown, and -added ctations are shown without markup. (This was the default behaviour of latexdiff at versions 0.6 and older) - -=item Changes in complicated mathematical equations result in latex processing errors - -Try options C<--math-markup=whole>. If even that fails, you can turn off mark up for equations with C<--math-markup=off>. - -=back - -=head1 BUGS - -Option allow-spaces not implemented entirely consistently. It breaks -the rules that number and type of white space does not matter, as -different numbers of inter-argument spaces are treated as significant. - -Please submit bug reports on the latexdiff project page I, -send them to user discussion list C (prior subscription -to list required, also on project webpage) -or send them to I. Include the serial number of I -(from comments at the top of the source or use B<--version>). If you come across latex -files that are error-free and conform to the specifications set out -above, and whose differencing still does not result in error-free -latex, please send me those files, ideally edited to only contain the -offending passage as long as that still reproduces the problem. If your -file relies on non-standard class files, you must include those. I will not -look at examples where I have trouble to latex the original files. - -=head1 SEE ALSO - -L, L - -=head1 PORTABILITY - -I does not make use of external commands and thus should run -on any platform supporting Perl 5.6 or higher. If files with encodings -other than ASCII or UTF-8 are processed, Perl 5.8 or higher is required. - -The standard version of I requires installation of the Perl package -C (available from I - -I) but a stand-alone -version, I, which has this package inlined, is available, too. -I requires the I command to be present. - -=head1 AUTHOR - -Version 1.0.2 -Copyright (C) 2004-2012 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 - -Contributors of fixes and additions: V. Kuhlmann, J. Paisley, N. Becker, T. Doerges, K. Huebner, -T. Connors, Sebastian Gouezel and many others. -Thanks to the many people who send in bug reports, feature suggestions, and other feedback. - -=cut - -__END__ -%%BEGIN SAFE COMMANDS -% Regex matching commands which can safely be in the -% argument of a \DIFadd or \DIFdel command (leave out the \) -arabic -dashbox -emph -fbox -framebox -hspace -math.* -makebox -mbox -pageref -ref -symbol -raisebox -rule -text.* -shortstack -usebox -dag -ddag -copyright -pounds -S -P -oe -OE -ae -AE -aa -AA -o -O -l -L -frac -ss -sqrt -ldots -cdots -vdots -ddots -alpha -beta -gamma -delta -epsilon -varepsilon -zeta -eta -theta -vartheta -iota -kappa -lambda -mu -nu -xi -pi -varpi -rho -varrho -sigma -varsigma -tau -upsilon -phi -varphi -chi -psi -omega -Gamma -Delta -Theta -Lambda -Xi -Pi -Sigma -Upsilon -Phi -Psi -Omega -ps -mp -times -div -ast -star -circ -bullet -cdot -cap -cup -uplus -sqcap -vee -wedge -setminus -wr -diamond -(?:big)?triangle.* -lhd -rhd -unlhd -unrhd -oplus -ominus -otimes -oslash -odot -bigcirc -d?dagger -amalg -leq -prec -preceq -ll -(?:sq)?su[bp]set(?:eq)? -in -vdash -geq -succ(?:eq)? -gg -ni -dashv -equiv -sim(?:eq)? -asymp -approx -cong -neq -doteq -propto -models -perp -mid -parallel -bowtie -Join -smile -frown -.*arrow -(?:long)?mapsto -.*harpoon.* -leadsto -aleph -hbar -imath -jmath -ell -wp -Re -Im -mho -prime -emptyset -nabla -surd -top -bot -angle -forall -exists -neg -flat -natural -sharp -backslash -partial -infty -Box -Diamond -triangle -clubsuit -diamondsuit -heartsuit -spadesuit -sum -prod -coprod -int -oint -big(?:sq)?c[au]p -bigvee -bigwedge -bigodot -bigotimes -bigoplus -biguplus -(?:arc)?(?:cos|sin|tan|cot)h? -csc -arg -deg -det -dim -exp -gcd -hom -inf -ker -lg -lim -liminf -limsup -ln -log -max -min -Pr -sec -sup -[Hclbdruvt] -(SUPER|SUB)SCRIPTNB -(SUPER|SUB)SCRIPT -PERCENTAGE -DOLLAR -%%END SAFE COMMANDS - -%%BEGIN TEXT COMMANDS -% Regex matching commands with a text argument (leave out the \) -addcontents.* -cc -closing -chapter -dashbox -emph -encl -fbox -framebox -footnote -footnotetext -framebox -part -(sub){0,2}section\*? -(sub)?paragraph\*? -makebox -mbox -opening -parbox -raisebox -savebox -sbox -shortstack -signature -text.* -value -underline -sqrt -(SUPER|SUB)SCRIPT -%%END TEXT COMMANDS - -%%BEGIN CONTEXT1 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -caption -%%END CONTEXT1 COMMANDS - -%%BEGIN CONTEXT2 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -title -author -date -institute -%%END CONTEXT2 COMMANDS - - -%% TYPES (Commands for highlighting changed blocks) - -%DIF UNDERLINE PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}} -\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}} -%DIF END UNDERLINE PREAMBLE - -%DIF CTRADITIONAL PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} [..\footnote{removed: #1} ]}} -%DIF END CTRADITIONAL PREAMBLE - -%DIF TRADITIONAL PREAMBLE -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{[..\footnote{removed: #1} ]}} -%DIF END TRADITIONAL PREAMBLE - -%DIF CFONT PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} \scriptsize #1}} -%DIF END CFONT PREAMBLE - -%DIF FONTSTRIKE PREAMBLE -\RequirePackage[normalem]{ulem} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{\footnotesize \sout{#1}}} -%DIF END FONTSTRIKE PREAMBLE - -%DIF CCHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}#1}\protect\cbdelete} -%DIF END CCHANGEBAR PREAMBLE - -%DIF CFONTCHBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\sf #1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\scriptsize #1}\protect\cbdelete} -%DIF END CFONTCHBAR PREAMBLE - -%DIF CULINECHBAR PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage[dvips]{changebar} -\RequirePackage{color} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\uwave{#1}}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\sout{#1}}\protect\cbdelete} -%DIF END CULINECHBAR PREAMBLE - -%DIF CHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\providecommand{\DIFadd}[1]{\protect\cbstart{#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete} -%DIF END CHANGEBAR PREAMBLE - -%DIF INVISIBLE PREAMBLE -\providecommand{\DIFadd}[1]{#1} -\providecommand{\DIFdel}[1]{} -%DIF END INVISIBLE PREAMBLE - - -%% SUBTYPES (Markers for beginning and end of changed blocks) - -%DIF SAFE PREAMBLE -\providecommand{\DIFaddbegin}{} -\providecommand{\DIFaddend}{} -\providecommand{\DIFdelbegin}{} -\providecommand{\DIFdelend}{} -%DIF END SAFE PREAMBLE - -%DIF MARGIN PREAMBLE -\providecommand{\DIFaddbegin}{\protect\marginpar{a[}} -\providecommand{\DIFaddend}{\protect\marginpar{]}} -\providecommand{\DIFdelbegin}{\protect\marginpar{d[}} -\providecommand{\DIFdelend}{\protect\marginpar{]}} -%DIF END BRACKET PREAMBLE - -%DIF DVIPSCOL PREAMBLE -%Note: only works with dvips converter -\RequirePackage{color} -\RequirePackage{dvipscol} -\providecommand{\DIFaddbegin}{\protect\nogroupcolor{blue}} -\providecommand{\DIFaddend}{\protect\nogroupcolor{black}} -\providecommand{\DIFdelbegin}{\protect\nogroupcolor{red}} -\providecommand{\DIFdelend}{\protect\nogroupcolor{black}} -%DIF END DVIPSCOL PREAMBLE - -%DIF COLOR PREAMBLE -\RequirePackage{color} -\providecommand{\DIFaddbegin}{\protect\color{blue}} -\providecommand{\DIFaddend}{\protect\color{black}} -\providecommand{\DIFdelbegin}{\protect\color{red}} -\providecommand{\DIFdelend}{\protect\color{black}} -%DIF END COLOR PREAMBLE - - -%% FLOAT TYPES - -%DIF FLOATSAFE PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%DIF IDENTICAL PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{\DIFaddbegin} -\providecommand{\DIFaddendFL}{\DIFaddend} -\providecommand{\DIFdelbeginFL}{\DIFdelbegin} -\providecommand{\DIFdelendFL}{\DIFdelend} -%DIF END IDENTICAL PREAMBLE - -%DIF TRADITIONALSAFE PREAMBLE -% procidecommand color to make this work for TRADITIONAL and CTRADITIONAL -\providecommand{\color}[1]{} -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdel}[1]{{\protect\color{red}[..{\scriptsize {removed: #1}} ]}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%% SPECIAL PACKAGE PREAMBLE COMMANDS - -% Standard \DIFadd and \DIFdel are redefined as \DIFaddtex and \DIFdeltex -% when hyperref package is included. -%DIF HYPERREF PREAMBLE -\providecommand{\DIFadd}[1]{\texorpdfstring{\DIFaddtex{#1}}{#1}} -\providecommand{\DIFdel}[1]{\texorpdfstring{\DIFdeltex{#1}}{}} -%DIF END HYPERREF PACKAGE diff --git a/latexdiff-1.0.3/latexdiff-vc b/latexdiff-1.0.3/latexdiff-vc deleted file mode 100755 index 56696da..0000000 --- a/latexdiff-1.0.3/latexdiff-vc +++ /dev/null @@ -1,493 +0,0 @@ -#!/usr/bin/env perl -# -# latexdiff-vc - wrapper script for applying latexdiff to rcs managed files -# and for automatised creation of postscript or pdf from difference file -# -# Copyright (C) 2005-13 F J Tilmann (tilmann@gfz-potsdam.de, ftilmann@users.berlios.de) -# -# Project webpages: http://latexdiff.berlios.de/ -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# -# Contributors: S Utcke, H Bruyninckx -# -# 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 . -# -# Detailed usage information at the end of the file -# -# version 1.0.3: Bug fix: replace use of system('cp...') with File::Copy::copy (Patch contributed by D. Bremner) -# Quotes around system call file arguments to allow filenames with spaces (Patch contributed by ssteve) -# version 1.0.2: - option --so to use latexdiff-so -# version 1.0.1 (change version numbering to match that of latexdiff) -# - Option --fast to use latexdiff-fast, -# - git support (thanks to Bjorn Magnus Mathisen, Santi Béjar, Pietro Battiston and Stefan Alfredson for patches) - UNTESTED -# version 0.25: -# - bbl is allowed as alternative extension (instead of .tex) -# version 0.26a -# - Bug fix: it copes now correctly with the possibility that there are no changes between current -# and archived version -use Getopt::Long ; -use Pod::Usage qw/pod2usage/ ; -use File::Temp qw/tempdir/ ; -use File::Basename qw/dirname/; -use File::Copy; - -use strict ; -use warnings ; - -my $versionstring=< 1); -# Variables -my ($file1,$file2,$diff,$diffbase,$answer,$options,$infile,$append,$dirname,$cwd); -my (@files,@ldoptions,@tmpfiles,@ptmpfiles,@difffiles); # , - -Getopt::Long::Configure('pass_through','bundling'); - -GetOptions('revision|r:s' => \@revs, - 'cvs' => \$cvs, - 'rcs' => \$rcs, - 'svn' => \$svn, - 'git' => \$git, - 'dir|d:s' => \$dir, - 'fast' => \$fast, - 'so' => \$so, - 'postscript|ps' => \$postscript, - 'pdf' => \$pdf, - 'force' => \$force, - 'version' => \$version, - 'help|h' => \$help); - -if ( $help ) { - pod2usage(1) ; -} - -if ( $version ) { - die $versionstring ; -} - -if ( $so ) { - $latexdiff='latexdiff-so'; -} -if ( $fast ) { - die "Cannot specify more than one of --fast or --so " if ($so); - $latexdiff='latexdiff-fast'; -} - -if ( $cvs ) { - $vc="CVS"; -} -if ( $rcs ) { - die "Cannot specify more than one of --cvs, --rcs --svn or --git." if ($vc); - $vc="RCS"; -} -if ( $svn ) { - die "Cannot specify more than one of --cvs, --rcs --svn or --git." if ($vc); - $vc="SVN"; -} -if ( $git ) { - die "Cannot specify more than one of --cvs, --rcs, --svn or --git." if ($vc); - $vc="GIT"; -} - - -# check whether the first file name or first passed-through option for latexdiff got misinterpreted as an option to an empty -r option -if ( @revs && ( -f $revs[$#revs] || $revs[$#revs] =~ /^-/ ) ) { - unshift @ARGV,$revs[$#revs]; - $revs[$#revs]=""; -} -# check whether the first file name or first passed-through option for latexdiff got misinterpreted as an option to an empty -d option -if ( defined($dir) && ( -f $dir || $dir =~ /^-/ ) ) { - unshift @ARGV,$dir; - $dir=""; -} - -#print "DEBUG: latexdiff-vc command line: ", join(" ",@ARGV), "\n"; - -$file2=pop @ARGV; -( defined($file2) && $file2 =~ /\.(tex|bbl)$/ ) or pod2usage("Must specify at least one tex or bbl file"); - -if (! $vc && scalar(@revs)>0 ) { - # have to guess $vc - # check whether we have a special name - if ( $0 =~ /-cvs$/ ) { - $vc="CVS"; - } elsif ( $0 =~ /-rcs$/ ) { - $vc="RCS"; - } elsif ( $0 =~ /-svn$/ ) { - $vc="SVN"; - } elsif ( $0 =~ /-git$/ ) { - $vc="GIT"; - } elsif ( -e "CVSROOT" || defined($ENV{"CVSROOT"}) ) { - print STDERR "Guess you are using CVS ...\n"; - $vc="CVS"; - } elsif ( -e "$file2,v" ) { - print STDERR "Guess you are using RCS ...\n"; - $vc="RCS"; - } elsif ( -d ".svn" ) { - print STDERR "Guess you are using SVN ...\n"; - $vc="SVN"; - } elsif ( -d ".git" ) { - print STDERR "Guess you are using GIT ...\n"; - $vc="GIT"; - } else { - print STDERR "Cannot figure out version control system, so I default to CVS\n"; - $vc="CVS"; - } -} - -if (defined($dir) && $dir=~/^\.\/?/ ) { - print STDERR "You wrote -dir=. but you do not really like to do that, do you ?\n"; - exit 10 -} - -if ( scalar(@revs)>0 ) { - if ( $vc eq "CVS" ) { - $diffcmd = "cvs diff -u -r"; - $patchcmd = "patch -R -p0"; - } elsif ( $vc eq "RCS" ) { - $diffcmd = "rcsdiff -u -r"; - $patchcmd = "patch -R -p0"; - } elsif ( $vc eq "SVN" ) { - $diffcmd = "svn diff -r "; - $patchcmd = "patch -R -p0"; - } elsif ( $vc eq "GIT" ) { - $diffcmd = "git diff -r --relative --no-prefix "; - $patchcmd = "patch -R -p0"; - # alternatively: - # $diffcmd = "git diff "; - # $patchcmd = "patch -R -p1"; - } else { - print STDERR "Unknown versioning system $vc \n"; - exit 10; - } -} - - -# make file list (last arguments), initial arguments have to be passed to latexdiff -# We assume an argument is a valid file rather than a latexdiff argument -# if it has extension .tex or .bbl - -@files=($file2); -while( $file1=pop @ARGV ) { - if ( $file1 =~ /\.(tex|bbl)$/ ) { - # $file1 looks like a valid file name and is prepended to file list - unshift @files, $file1 ; - } else { - # $file1 looks like an option for latexdiff, push it back to argument stack - unshift @ldoptions, $file1 ; - } -} - -if ( scalar(@revs) == 0 ) { - pod2usage("When -r option is not used, two .tex files (old and new) must be given on the command line") unless @files==2; - # compare two files - $file1=shift @files ; -} - -if ( scalar(@revs) == 2 ) { - $append = "-diff$revs[0]-$revs[1]"; -} elsif ( scalar(@revs) == 1 || $revs[0] ) { - $append = "-diff$revs[0]"; -} else { - $append = "-diff"; -} - -if ( defined ($dir) && ! $dir ) { - # bare -d option => choose directory name - ($dir=$append) =~ s/^-//; -} - -if ( ($vc eq "SVN" || $vc eq "CVS") && scalar(@revs)) { - length($revs[$#revs]) > 0 or $revs[$#revs]="HEAD"; - length($revs[0]) > 0 or $revs[0]="HEAD"; -} - -#exit ; - - -# cycle through all files - -@difffiles=(); -while ( $infile=$file2=shift @files ) { - print STDERR "Working on $infile \n"; - if ( scalar(@revs) == 1 ) { - ($file1=$infile) =~ s/\.(tex|bbl)/-oldtmp-$$.$1/ ; - push @tmpfiles,$file1; - # compare file with previous version ($revs[0]="") or specified version - ### system("$diffcmd$revs[0] $infile| $patchcmd -o$file1") ; - if (system("$diffcmd$revs[0] \"$infile\" | $patchcmd -o\"$file1\"")==0 and -z $file1 ) { - # no differences detected, i.e. file is equal to current version - copy($infile,$file1) || die "copy($infile,$file1) failed: $!"; - } - } elsif ( scalar(@revs) == 2 ) { - ($file1=$infile) =~ s/\.(tex|bbl)/-oldtmp-$$.$1/ ; - $file2 =~ s/\.(tex|bbl)/-newtmp-$$.$1/ ; - push @tmpfiles,$file2; - if (system("$diffcmd$revs[1] $infile | $patchcmd -o$file2")==0 and -z $file2 ) { - copy($infile,$file2) || die "copy($infile,$file2) failed: $!"; - } - if (system("$diffcmd$revs[0] $infile | $patchcmd -o$file1")==0 and -z $file1 ) { - copy($infile,$file1) || die "copy($infile,$file1) failed: $!"; - }; - } - - if ( -z $file1 || -z $file2) { - print STDERR "One or both of the files to compare are empty. Possibly something went wrong in the retrieval of older versions. Aborting ...\n" ; - exit(10); - } - - # Get name of difference file - if ( defined($dir) ) { - $diff="$dir/$infile" ; - } else { - ($diff=$infile) =~ s/\.(tex|bbl)$/$append.$1/ ; - } - # make directories if needed - $dirname=dirname($diff) ; - system("mkdir -p $dirname") unless ( -e $dirname ); - - # Remaining options are passed to latexdiff - $options = join(" ",@ldoptions); - - if ( -e $diff && ! $force ) { - print STDERR "OK to overwrite existing file $diff (y/n)? "; - $answer = ; - unless ($answer =~ /^y/i ) { - unlink @tmpfiles; - die "Abort ... " ; - } - } - print "Running $latexdiff\n"; - unless ( system("$latexdiff $options \"$file1\" \"$file2\" > \"$diff\"") == 0 ) { - print STDERR "Something went wrong in $latexdiff. Deleting $diff and abort\n" ; unlink $diff ; exit(5) - }; - print "Generated difference file $diff\n"; - - if ( ( $postscript or $pdf ) and !( scalar(@revs) && greptex( qr/\\document(?:class|style)/ , $diff ) ) ) { - # save filename for later processing if postscript or pdf conversion is requested and either two-file mode was used (scalar(@revs)==0) or the diff file contains documentclass statement (ie. is a root document) - push @difffiles, $diff ; - } - - unlink @tmpfiles; -} - -foreach $diff ( @difffiles ) { - chomp($cwd=(`pwd`)); - if (defined($dir)) { - ( $diff =~ s/$dir\/?// ) ; - chdir $dir ; - } - @ptmpfiles=(); - ( $diffbase=$diff) =~ s/\.(tex)$// ; - - # adapt magically changebar styles to [pdftex] display driver if pdf output was selected - if ( $pdf ) { - system("sed \"s/Package\\[dvips\\]/Package[pdftex]/\" \"$diff\" > \"$diff.tmp$$\" ; \\mv \"$diff.tmp$$\" \"$diff\""); - } - print STDERR "PDF: $pdf Postscript: $postscript cwd $cwd\n"; - - if ( system("grep -q \'^[^%]*\\\\bibliography\' \"$diff\"") == 0 ) { - if ( $postscript) { - system("latex --interaction=batchmode \"$diff\"; bibtex \"$diffbase\""); - push @ptmpfiles, "$diffbase.bbl","$diffbase.bbl" ; - } elsif ( $pdf ) { - system("pdflatex --interaction=batchmode \"$diff\"; bibtex \"$diffbase\""); - push @ptmpfiles, "$diffbase.bbl","$diffbase.bbl" ; - } - } - - if ( $postscript ) { - my $dvi="$diffbase.dvi"; - my $ps="$diffbase.ps"; - - system("latex --interaction=batchmode \"$diff\"; latex \"$diff\"; dvips -o $ps $dvi"); - push @ptmpfiles, "$diffbase.aux","$diffbase.log",$dvi ; - print "Generated postscript file $ps\n"; - } - elsif ( $pdf ) { - system("pdflatex --interaction=batchmode \"$diff\"; pdflatex \"$diff\""); - push @ptmpfiles, "$diffbase.aux","$diffbase.log"; - } - unlink @ptmpfiles; - chdir $cwd; -} - -# greptex returns 1 if regex is not matched in filename -# 0 if there is a match -sub greptex { - my ($regex,$filename)=@_; - my ($i)=0; - open (FH, $filename) or die("Couldn't open $filename: $!"); - while () { - next if /^\s*%/; # skip comment lines - if ( m/$regex/ ) { - close(FH); - return(0); - } - # only scan 25 lines - $i++; - last if $i>25 ; - } - close(FH); - return(1); -} - - -=head1 NAME - -latexdiff-vc - wrapper script that calls latexdiff for different versions of a file under version management (CVS, RCS or SVN) - -=head1 SYNOPSIS - -B [ F ] [ F ] B<-r> [F] [B<-r> F] F [ F ...] - - or - -B [ F ] [ F ][ B<--postscript> | B<--pdf> ] F F - -=head1 DESCRIPTION - -I is a wrapper script that applies I to a -file, or multiple files under version control (CVS, RCS or SVN), and optionally runs the -sequence of C and C or C commands necessary to -produce pdf or postscript output of the difference tex file(s). It can -also be applied to a pair of files to automatise the generation of difference -file in postscript or pdf format. - -=head1 OPTIONS - -=over 4 - -=item B<--rcs>, B<--svn>, B<--cvs>, or B<--git> - -Set the version system. -If no version system is specified, latexdiff-vc will venture a guess. - -latexdiff-cvs and latexdiff-rcs are variants of latexdiff-vc which default to -the respective versioning system. However, this default can still be overridden using the options above. - -=item B<-r>, B<-r> F or B<--revision>, B<--revision=>F - -Choose revision (under RCS, CVS, SVN or GIT). One or two B<-r> options can be -specified, and they result in different behaviour: - -=over 4 - -=item B -r F ... - -compares F with the most recent version checked into RCS. - -=item B -r F F ... - -compares F with revision F. - -=item B -r F -r F F ... - -compares revisions F and F of F. - -Multiple files can be specified for all of the above options. All files must have the -extension C<.tex>, though. - -=item B F F - -compares two files. - -=back - -The name of the difference file is generated automatically and -reported to stdout. - -=item B<-d> or B<--dir> B<-d> F or B<--dir=>F - -Rather than appending the string C and optionally the version -numbers given to the output-file, this will prepend a directory name C -to the -original filename, creating the directory and subdirectories should they not exist already. This is particularly useful in order to clone a -complete directory hierarchy. Optionally, a pathname F can be specified, which is prepended instead of C. - -=item B<--fast> or B<--so> - -Use C or C, respectively (instead of C). - -=item B<--ps> or B<--postscript> - -Generate postscript output from difference file. This will run the -sequence C on the difference file (do not use -this option in the rare cases, where three C commands are -required if you care about correct referencing). If the difference -file contains a C<\bibliography> tag, run the sequence C. - -=item B<--pdf> - -Generate pdf output from difference file using C. This will -run the sequence C on the difference file, or -C for files requiring bibtex. - -=item B<--force> - -Overwrite existing diff files without asking for confirmation. Default -behaviour is to ask for confirmation before overwriting an existing difference -file. - -=item B<--help> or -B<-h> - -Show help text - -=item B<--version> - -Show version number - -=back - -All other options are passed on to C. - -=head1 SEE ALSO - -L - -=head1 PORTABILITY - -I uses external commands and is therefore -limited to Unix-like systems. It also requires the RCS version control -system and latex to be installed on the system. Modules from Perl 5.8 -or higher are required. - -=head1 BUG REPORTING - - Please submit bug reports through -the latexdiff project page I or send -to I. Include the serial number of I -(option C<--version>) -. -=head1 AUTHOR - -Copyright (C) 2005,2012 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 -Contributors: S Utcke, H Bruyninckx - -=cut - diff --git a/latexdiff-1.0.3/latexdiff-vc.1 b/latexdiff-1.0.3/latexdiff-vc.1 deleted file mode 100644 index 6b8806d..0000000 --- a/latexdiff-1.0.3/latexdiff-vc.1 +++ /dev/null @@ -1,246 +0,0 @@ -.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` "" -. ds C' "" -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.ie \nF \{\ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. nr % 0 -. rr F -.\} -.el \{\ -. de IX -.. -.\} -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "LATEXDIFF-VC 1" -.TH LATEXDIFF-VC 1 "2013-06-10" "perl v5.14.2" " " -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -latexdiff\-vc \- wrapper script that calls latexdiff for different versions of a file under version management (CVS, RCS or SVN) -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBlatexdiff-vc\fR [ \fIlatexdiff-options\fR ] [ \fIlatexdiff-vc-options\fR ] \fB\-r\fR [\fIrev1\fR] [\fB\-r\fR \fIrev2\fR] \fIfile1.tex\fR [ \fIfile2.tex\fR ...] -.PP -.Vb 1 -\& or -.Ve -.PP -\&\fBlatexdiff-vc\fR [ \fIlatexdiff-options\fR ] [ \fIlatexdiff-vc-options\fR ][ \fB\-\-postscript\fR | \fB\-\-pdf\fR ] \fIold.tex\fR \fInew.tex\fR -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -\&\fIlatexdiff-vc\fR is a wrapper script that applies \fIlatexdiff\fR to a -file, or multiple files under version control (\s-1CVS\s0, \s-1RCS\s0 or \s-1SVN\s0), and optionally runs the -sequence of \f(CW\*(C`latex\*(C'\fR and \f(CW\*(C`dvips\*(C'\fR or \f(CW\*(C`pdflatex\*(C'\fR commands necessary to -produce pdf or postscript output of the difference tex file(s). It can -also be applied to a pair of files to automatise the generation of difference -file in postscript or pdf format. -.SH "OPTIONS" -.IX Header "OPTIONS" -.IP "\fB\-\-rcs\fR, \fB\-\-svn\fR, \fB\-\-cvs\fR, or \fB\-\-git\fR" 4 -.IX Item "--rcs, --svn, --cvs, or --git" -Set the version system. -If no version system is specified, latexdiff-vc will venture a guess. -.Sp -latexdiff-cvs and latexdiff-rcs are variants of latexdiff-vc which default to -the respective versioning system. However, this default can still be overridden using the options above. -.IP "\fB\-r\fR, \fB\-r\fR \fIrev\fR or \fB\-\-revision\fR, \fB\-\-revision=\fR\fIrev\fR" 4 -.IX Item "-r, -r rev or --revision, --revision=rev" -Choose revision (under \s-1RCS\s0, \s-1CVS\s0, \s-1SVN\s0 or \s-1GIT\s0). One or two \fB\-r\fR options can be -specified, and they result in different behaviour: -.RS 4 -.IP "\fBlatexdiff-vc\fR \-r \fIfile.tex\fR ..." 4 -.IX Item "latexdiff-vc -r file.tex ..." -compares \fIfile.tex\fR with the most recent version checked into \s-1RCS\s0. -.IP "\fBlatexdiff-vc\fR \-r \fIrev1\fR \fIfile.tex\fR ..." 4 -.IX Item "latexdiff-vc -r rev1 file.tex ..." -compares \fIfile.tex\fR with revision \fIrev1\fR. -.IP "\fBlatexdiff-vc\fR \-r \fIrev1\fR \-r \fIrev2\fR \fIfile.tex\fR ..." 4 -.IX Item "latexdiff-vc -r rev1 -r rev2 file.tex ..." -compares revisions \fIrev1\fR and \fIrev2\fR of \fIfile.tex\fR. -.Sp -Multiple files can be specified for all of the above options. All files must have the -extension \f(CW\*(C`.tex\*(C'\fR, though. -.IP "\fBlatexdiff-vc\fR \fIold.tex\fR \fInew.tex\fR" 4 -.IX Item "latexdiff-vc old.tex new.tex" -compares two files. -.RE -.RS 4 -.Sp -The name of the difference file is generated automatically and -reported to stdout. -.RE -.IP "\fB\-d\fR or \fB\-\-dir\fR \fB\-d\fR \fIpath\fR or \fB\-\-dir=\fR\fIpath\fR" 4 -.IX Item "-d or --dir -d path or --dir=path" -Rather than appending the string \f(CW\*(C`diff\*(C'\fR and optionally the version -numbers given to the output-file, this will prepend a directory name \f(CW\*(C`diff\*(C'\fR -to the -original filename, creating the directory and subdirectories should they not exist already. This is particularly useful in order to clone a -complete directory hierarchy. Optionally, a pathname \fIpath\fR can be specified, which is prepended instead of \f(CW\*(C`diff\*(C'\fR. -.IP "\fB\-\-fast\fR or \fB\-\-so\fR" 4 -.IX Item "--fast or --so" -Use \f(CW\*(C`latexdiff\-fast\*(C'\fR or \f(CW\*(C`latexdiff\-so\*(C'\fR, respectively (instead of \f(CW\*(C`latexdiff\*(C'\fR). -.IP "\fB\-\-ps\fR or \fB\-\-postscript\fR" 4 -.IX Item "--ps or --postscript" -Generate postscript output from difference file. This will run the -sequence \f(CW\*(C`latex; latex; dvips\*(C'\fR on the difference file (do not use -this option in the rare cases, where three \f(CW\*(C`latex\*(C'\fR commands are -required if you care about correct referencing). If the difference -file contains a \f(CW\*(C`\ebibliography\*(C'\fR tag, run the sequence \f(CW\*(C`latex; -bibtex; latex; latex; dvips\*(C'\fR. -.IP "\fB\-\-pdf\fR" 4 -.IX Item "--pdf" -Generate pdf output from difference file using \f(CW\*(C`pdflatex\*(C'\fR. This will -run the sequence \f(CW\*(C`pdflatex; pdflatex\*(C'\fR on the difference file, or -\&\f(CW\*(C`pdflatex; bibtex; pdflatex; pdflatex\*(C'\fR for files requiring bibtex. -.IP "\fB\-\-force\fR" 4 -.IX Item "--force" -Overwrite existing diff files without asking for confirmation. Default -behaviour is to ask for confirmation before overwriting an existing difference -file. -.IP "\fB\-\-help\fR or \fB\-h\fR" 4 -.IX Item "--help or -h" -Show help text -.IP "\fB\-\-version\fR" 4 -.IX Item "--version" -Show version number -.PP -All other options are passed on to \f(CW\*(C`latexdiff\*(C'\fR. -.SH "SEE ALSO" -.IX Header "SEE ALSO" -latexdiff -.SH "PORTABILITY" -.IX Header "PORTABILITY" -\&\fIlatexdiff-vc\fR uses external commands and is therefore -limited to Unix-like systems. It also requires the \s-1RCS\s0 version control -system and latex to be installed on the system. Modules from Perl 5.8 -or higher are required. -.SH "BUG REPORTING" -.IX Header "BUG REPORTING" -.Vb 6 -\& Please submit bug reports through -\&the latexdiff project page I or send -\&to I. Include the serial number of I -\&(option C<\-\-version>) -\&. -\&=head1 AUTHOR -.Ve -.PP -Copyright (C) 2005,2012 Frederik Tilmann -.PP -This program is free software; you can redistribute it and/or modify -it under the terms of the \s-1GNU\s0 General Public License Version 3 -Contributors: S Utcke, H Bruyninckx diff --git a/latexdiff-1.0.3/latexdiff.1 b/latexdiff-1.0.3/latexdiff.1 deleted file mode 100644 index 03007f9..0000000 --- a/latexdiff-1.0.3/latexdiff.1 +++ /dev/null @@ -1,758 +0,0 @@ -.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` "" -. ds C' "" -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.ie \nF \{\ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. nr % 0 -. rr F -.\} -.el \{\ -. de IX -.. -.\} -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "LATEXDIFF 1" -.TH LATEXDIFF 1 "2013-06-09" "perl v5.14.2" " " -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -latexdiff \- determine and markup differences between two latex files -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBlatexdiff\fR [ \fB\s-1OPTIONS\s0\fR ] \fIold.tex\fR \fInew.tex\fR > \fIdiff.tex\fR -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -Briefly, \fIlatexdiff\fR is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called \f(CW\*(C`old.tex\*(C'\fR and \f(CW\*(C`new.tex\*(C'\fR, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. -.PP -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "\f(CW\*(C`%DIF\ >\*(C'\fR" is appended to each added line, i.e. a -line present in \f(CW\*(C`new.tex\*(C'\fR but not in \f(CW\*(C`old.tex\*(C'\fR. Discarded lines - are deactivated by prepending "\f(CW\*(C`%DIF\ <\*(C'\fR". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file \f(CW\*(C`diff.tex\*(C'\fR will be similar to -\&\f(CW\*(C`new.tex\*(C'\fR. At the end of the preamble, the definitions for \fIlatexdiff\fR markup commands are inserted. -In differencing the main body of the text, \fIlatexdiff\fR attempts to -satisfy the following guidelines (in order of priority): -.IP "1." 3 -If both \f(CW\*(C`old.tex\*(C'\fR and \f(CW\*(C`new.tex\*(C'\fR are valid LaTeX, then the resulting -\&\f(CW\*(C`diff.tex\*(C'\fR should also be valid LateX. (\s-1NB\s0 If a few plain TeX commands -are used within \f(CW\*(C`old.tex\*(C'\fR or \f(CW\*(C`new.tex\*(C'\fR then \f(CW\*(C`diff.tex\*(C'\fR is not -guaranteed to work but usually will). -.IP "2." 3 -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -\&\f(CW\*(C`diff.tex\*(C'\fR. -.IP "3." 3 -If a changed passage contains text or text-producing commands, then -running \f(CW\*(C`diff.tex\*(C'\fR through LateX should produce output where added -and discarded passages are highlighted. -.IP "4." 3 -Where there are insignificant differences, e.g. in the positioning of -line breaks, \f(CW\*(C`diff.tex\*(C'\fR should follow the formatting of \f(CW\*(C`new.tex\*(C'\fR -.PP -For differencing the same algorithm as \fIdiff\fR is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, \f(CW\*(C`\ecaption\*(C'\fR and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write -.PP -.Vb 1 -\& \esection{\etextem{This is an emphasized section title}} -.Ve -.PP -and not -.PP -.Vb 1 -\& \esection {\etextem{This is an emphasized section title}} -.Ve -.PP -or -.PP -.Vb 1 -\& \esection\etextem{This is an emphasized section title} -.Ve -.PP -even though all varieties are the same to LaTeX (but see -\&\fB\-\-allow\-spaces\fR option which allows the second variety). -.PP -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the \s-1PICTUREENV\s0 configuration variable, set by -default to \f(CW\*(C`picture\*(C'\fR and \f(CW\*(C`DIFnomarkup\*(C'\fR environments; see \fB\-\-config\fR -option). The latter environment (\f(CW\*(C`DIFnomarkup\*(C'\fR) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by \f(CW\*(C`\ebegin{DIFnomarkup}\*(C'\fR and \f(CW\*(C`\eend{DIFnomarkup}\*(C'\fR. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, -.PP -\&\f(CW\*(C`\enewenvironment{DIFnomarkup}{}{}\*(C'\fR -.PP -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. -.PP -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. -.PP -All markup commands inserted by \fIlatexdiff\fR begin with "\f(CW\*(C`\eDIF\*(C'\fR". Added -blocks containing words, commands or comments which are in \f(CW\*(C`new.tex\*(C'\fR -but not in \f(CW\*(C`old.tex\*(C'\fR are marked by \f(CW\*(C`\eDIFaddbegin\*(C'\fR and \f(CW\*(C`\eDIFaddend\*(C'\fR. -Discarded blocks are marked by \f(CW\*(C`\eDIFdelbegin\*(C'\fR and \f(CW\*(C`\eDIFdelend\*(C'\fR. -Within added blocks all text is highlighted with \f(CW\*(C`\eDIFadd\*(C'\fR like this: -\&\f(CW\*(C`\eDIFadd{Added text block}\*(C'\fR -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces \*(L"{\*(R" and \*(L"}\*(R" are never put within -the scope of \f(CW\*(C`\eDIFadd\*(C'\fR. Added comments are marked by prepending -"\f(CW\*(C`%DIF\ >\ \*(C'\fR". -.PP -Within deleted blocks text is highlighted with \f(CW\*(C`\eDIFdel\*(C'\fR. Deleted -comments are marked by prepending "\f(CW\*(C`%DIF\ <\ \*(C'\fR\*(L". Non-safe command -and curly braces within deleted blocks are commented out with -\&\*(R"\f(CW\*(C`%DIFDELCMD\ <\ \*(C'\fR". -.SH "OPTIONS" -.IX Header "OPTIONS" -.SS "Preamble" -.IX Subsection "Preamble" -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. -.IP "\fB\-\-type=markupstyle\fR or \fB\-t markupstyle\fR" 4 -.IX Item "--type=markupstyle or -t markupstyle" -Add code to preamble for selected markup style. This option defines -\&\f(CW\*(C`\eDIFadd\*(C'\fR and \f(CW\*(C`\eDIFdel\*(C'\fR commands. -Available styles: -.Sp -\&\f(CW\*(C`UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE -CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR\*(C'\fR -.Sp -[ Default: \f(CW\*(C`UNDERLINE\*(C'\fR ] -.IP "\fB\-\-subtype=markstyle\fR or \fB\-s markstyle\fR" 4 -.IX Item "--subtype=markstyle or -s markstyle" -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -\&\f(CW\*(C`\eDIFaddbegin\*(C'\fR, \f(CW\*(C`\eDIFaddend\*(C'\fR, \f(CW\*(C`\eDIFdelbegin\*(C'\fR and \f(CW\*(C`\eDIFdelend\*(C'\fR commands. -Available styles: \f(CW\*(C`SAFE MARGINAL COLOR DVIPSCOL\*(C'\fR -.Sp -[ Default: \f(CW\*(C`SAFE\*(C'\fR ] -.IP "\fB\-\-floattype=markstyle\fR or \fB\-f markstyle\fR" 4 -.IX Item "--floattype=markstyle or -f markstyle" -Add code to preamble for selected style which -replace standard marking and markup commands within floats -(e.g., marginal remarks cause an error within floats -so marginal marking can be disabled thus). This option defines all -\&\f(CW\*(C`\eDIF...FL\*(C'\fR commands. -Available styles: \f(CW\*(C`FLOATSAFE TRADITIONALSAFE IDENTICAL\*(C'\fR -.Sp -[ Default: \f(CW\*(C`FLOATSAFE\*(C'\fR ] -.IP "\fB\-\-encoding=enc\fR or \fB\-e enc\fR" 4 -.IX Item "--encoding=enc or -e enc" -Specify encoding of old.tex and new.tex. Typical encodings are -\&\f(CW\*(C`ascii\*(C'\fR, \f(CW\*(C`utf8\*(C'\fR, \f(CW\*(C`latin1\*(C'\fR, \f(CW\*(C`latin9\*(C'\fR. A list of available encodings can be -obtained by executing -.Sp -\&\f(CW\*(C`perl \-MEncode \-e \*(Aqprint join ("\en",Encode\-\*(C'\fRencodings( \*(L":all\*(R" )) ;' > -.Sp -[Default encoding is utf8 unless the first few lines of the preamble contain -an invocation \f(CW\*(C`\eusepackage[..]{inputenc}\*(C'\fR in which case the -encoding chosen by this command is asssumed. Note that \s-1ASCII\s0 (standard -latex) is a subset of utf8] -.IP "\fB\-\-preamble=file\fR or \fB\-p file\fR" 4 -.IX Item "--preamble=file or -p file" -Insert file at end of preamble instead of generating -preamble. The preamble must define the following commands -\&\f(CW\*(C`\eDIFaddbegin, \eDIFaddend, \eDIFadd{..}, -\&\eDIFdelbegin,\eDIFdelend,\eDIFdel{..},\*(C'\fR -and varieties for use within floats -\&\f(CW\*(C`\eDIFaddbeginFL, \eDIFaddendFL, \eDIFaddFL{..}, -\&\eDIFdelbeginFL, \eDIFdelendFL, \eDIFdelFL{..}\*(C'\fR -(If this option is set \fB\-t\fR, \fB\-s\fR, and \fB\-f\fR options -are ignored.) -.IP "\fB\-\-packages=pkg1,pkg2,..\fR" 4 -.IX Item "--packages=pkg1,pkg2,.." -Tell latexdiff that .tex file is processed with the packages in list -loaded. This is normally not necessary if the .tex file includes the -preamble, as the preamble is automatically scanned for \f(CW\*(C`\eusepackage\*(C'\fR commands. -Use of the \fB\-\-packages\fR option disables automatic scanning, so if for any -reason package specific parsing needs to be switched off, use \fB\-\-packages=none\fR. -The following packages trigger special behaviour: -.RS 4 -.ie n .IP """amsmath""" 8 -.el .IP "\f(CWamsmath\fR" 8 -.IX Item "amsmath" -Configuration variable amsmath is set to \f(CW\*(C`align*\*(C'\fR (Default: \f(CW\*(C`eqnarray*\*(C'\fR) -.ie n .IP """endfloat""" 8 -.el .IP "\f(CWendfloat\fR" 8 -.IX Item "endfloat" -Ensure that \f(CW\*(C`\ebegin{figure}\*(C'\fR and \f(CW\*(C`\eend{figure}\*(C'\fR always appear by themselves on a line. -.ie n .IP """hyperref""" 8 -.el .IP "\f(CWhyperref\fR" 8 -.IX Item "hyperref" -Change name of \f(CW\*(C`\eDIFadd\*(C'\fR and \f(CW\*(C`\eDIFdel\*(C'\fR commands to \f(CW\*(C`\eDIFaddtex\*(C'\fR and \f(CW\*(C`\eDIFdeltex\*(C'\fR and -define new \f(CW\*(C`\eDIFadd\*(C'\fR and \f(CW\*(C`\eDIFdel\*(C'\fR commands, which provide a wrapper for these commands, -using them for the text but not for the link defining command (where any markup would cause -errors). -.RE -.RS 4 -.Sp -[ Default: scan the preamble for \f(CW\*(C`\e\eusepackage\*(C'\fR commands to determine - loaded packages.] -.RE -.IP "\fB\-\-show\-preamble\fR" 4 -.IX Item "--show-preamble" -Print generated or included preamble commands to stdout. -.SS "Configuration" -.IX Subsection "Configuration" -.ie n .IP "\fB\-\-exclude\-safecmd=exclude\-file\fR or \fB\-A exclude-file\fR or \fB\-\-exclude\-safecmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-exclude\-safecmd=exclude\-file\fR or \fB\-A exclude-file\fR or \fB\-\-exclude\-safecmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--exclude-safecmd=exclude-file or -A exclude-file or --exclude-safecmd=cmd1,cmd2,..." -.PD 0 -.IP "\fB\-\-replace\-safecmd=replace\-file\fR" 4 -.IX Item "--replace-safecmd=replace-file" -.ie n .IP "\fB\-\-append\-safecmd=append\-file\fR or \fB\-a append-file\fR or \fB\-\-append\-safecmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-append\-safecmd=append\-file\fR or \fB\-a append-file\fR or \fB\-\-append\-safecmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--append-safecmd=append-file or -a append-file or --append-safecmd=cmd1,cmd2,..." -.PD -Exclude from, replace or append to the list of regular expressions (RegEx) -matching commands which are safe to use within the -scope of a \f(CW\*(C`\eDIFadd\*(C'\fR or \f(CW\*(C`\eDIFdel\*(C'\fR command. The file must contain -one Perl-RegEx per line (Comment lines beginning with # or % are -ignored). Note that the RegEx needs to match the whole of -the token, i.e., /^regex$/ is implied and that the initial -\&\*(L"\e\*(R" of the command is not included. -The \fB\-\-exclude\-safecmd\fR and \fB\-\-append\-safecmd\fR options can be combined with the \-\fB\-\-replace\-safecmd\fR -option and can be used repeatedly to add cumulatively to the lists. - \fB\-\-exclude\-safecmd\fR -and \fB\-\-append\-safecmd\fR can also take a comma separated list as input. If a -comma for one of the regex is required, escape it thus \*(L"\e,\*(R". In most cases it -will be necessary to protect the comma-separated list from the shell by putting -it in quotation marks. -.ie n .IP "\fB\-\-exclude\-textcmd=exclude\-file\fR or \fB\-X exclude-file\fR or \fB\-\-exclude\-textcmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-exclude\-textcmd=exclude\-file\fR or \fB\-X exclude-file\fR or \fB\-\-exclude\-textcmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--exclude-textcmd=exclude-file or -X exclude-file or --exclude-textcmd=cmd1,cmd2,..." -.PD 0 -.IP "\fB\-\-replace\-textcmd=replace\-file\fR" 4 -.IX Item "--replace-textcmd=replace-file" -.ie n .IP "\fB\-\-append\-textcmd=append\-file\fR or \fB\-x append-file\fR or \fB\-\-append\-textcmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-append\-textcmd=append\-file\fR or \fB\-x append-file\fR or \fB\-\-append\-textcmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--append-textcmd=append-file or -x append-file or --append-textcmd=cmd1,cmd2,..." -.PD -Exclude from, replace or append to the list of regular expressions -matching commands whose last argument is text. See -entry for \fB\-\-exclude\-safecmd\fR directly above for further details. -.IP "\fB\-\-replace\-context1cmd=replace\-file\fR" 4 -.IX Item "--replace-context1cmd=replace-file" -.PD 0 -.ie n .IP "\fB\-\-append\-context1cmd=append\-file\fR or =item \fB\-\-append\-context1cmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-append\-context1cmd=append\-file\fR or =item \fB\-\-append\-context1cmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--append-context1cmd=append-file or =item --append-context1cmd=cmd1,cmd2,..." -.PD -Replace or append to the list of regex matching commands -whose last argument is text but which require a particular -context to work, e.g. \ecaption will only work within a figure -or table. These commands behave like text commands, except when -they occur in a deleted section, when they are disabled, but their -argument is shown as deleted text. -.IP "\fB\-\-replace\-context2cmd=replace\-file\fR" 4 -.IX Item "--replace-context2cmd=replace-file" -.PD 0 -.ie n .IP "\fB\-\-append\-context2cmd=append\-file\fR or =item \fB\-\-append\-context2cmd=""cmd1,cmd2,...""\fR As corresponding commands for context1. The only difference is that context2 commands are completely disabled in deleted sections, including their arguments." 4 -.el .IP "\fB\-\-append\-context2cmd=append\-file\fR or =item \fB\-\-append\-context2cmd=``cmd1,cmd2,...''\fR As corresponding commands for context1. The only difference is that context2 commands are completely disabled in deleted sections, including their arguments." 4 -.IX Item "--append-context2cmd=append-file or =item --append-context2cmd=cmd1,cmd2,... As corresponding commands for context1. The only difference is that context2 commands are completely disabled in deleted sections, including their arguments." -.IP "\fB\-\-config var1=val1,var2=val2,...\fR or \fB\-c var1=val1,..\fR" 4 -.IX Item "--config var1=val1,var2=val2,... or -c var1=val1,.." -.IP "\fB\-c configfile\fR" 4 -.IX Item "-c configfile" -.PD -Set configuration variables. The option can be repeated to set different -variables (as an alternative to the comma-separated list). -Available variables (see below for further explanations): -.Sp -\&\f(CW\*(C`MINWORDSBLOCK\*(C'\fR (integer) -.Sp -\&\f(CW\*(C`FLOATENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`PICTUREENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`MATHENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`MATHREPL\*(C'\fR (String) -.Sp -\&\f(CW\*(C`MATHARRENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`MATHARRREPL\*(C'\fR (String) -.Sp -\&\f(CW\*(C`ARRENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`COUNTERCMD\*(C'\fR (RegEx) -.IP "\fB\-\-show\-safecmd\fR" 4 -.IX Item "--show-safecmd" -Print list of RegEx matching and excluding safe commands. -.IP "\fB\-\-show\-textcmd\fR" 4 -.IX Item "--show-textcmd" -Print list of RegEx matching and excluding commands with text argument. -.IP "\fB\-\-show\-config\fR" 4 -.IX Item "--show-config" -Show values of configuration variables. -.IP "\fB\-\-show\-all\fR" 4 -.IX Item "--show-all" -Combine all \-\-show commands. -.Sp -\&\s-1NB\s0 For all \-\-show commands, no \f(CW\*(C`old.tex\*(C'\fR or \f(CW\*(C`new.tex\*(C'\fR file needs to be specified, and no -differencing takes place. -.SS "Other configuration options:" -.IX Subsection "Other configuration options:" -.IP "\fB\-\-allow\-spaces\fR" 4 -.IX Item "--allow-spaces" -Allow spaces between bracketed or braced arguments to commands. Note -that this option might have undesirable side effects (unrelated scope -might get lumpeded with preceding commands) so should only be used if the -default produces erroneous results. (Default requires arguments to -directly follow each other without intervening spaces). -.IP "\fB\-\-math\-markup=level\fR" 4 -.IX Item "--math-markup=level" -Determine granularity of markup in displayed math environments: -Possible values for level are (both numerical and text labels are acceptable): -.Sp -\&\f(CW\*(C`off\*(C'\fR or \f(CW0\fR: suppress markup for math environments. Deleted equations will not -appear in diff file. This mode can be used if all the other modes -cause invalid latex code. -.Sp -\&\f(CW\*(C`whole\*(C'\fR or \f(CW1\fR: Differencing on the level of whole equations. Even trivial changes -to equations cause the whole equation to be marked changed. This -mode can be used if processing in coarse or fine mode results in -invalid latex code. -.Sp -\&\f(CW\*(C`coarse\*(C'\fR or \f(CW2\fR: Detect changes within equations marked up with a coarse -granularity; changes in equation type (e.g.displaymath to equation) -appear as a change to the complete equation. This mode is recommended -for situations where the content and order of some equations are still -being changed. [Default] -.Sp -\&\f(CW\*(C`fine\*(C'\fR or \f(CW3\fR: Detect small change in equations and mark up at fine granularity. -This mode is most suitable, if only minor changes to equations are -expected, e.g. correction of typos. -.IP "\fB\-\-disable\-citation\-markup\fR" 4 -.IX Item "--disable-citation-markup" -Suppress citation markup in styles using ulem (\s-1UNDERLINE\s0, -\&\s-1FONTSTRIKE\s0, \s-1CULINECHBAR\s0) -.IP "\fB\-\-enable\-citation\-markup\fR" 4 -.IX Item "--enable-citation-markup" -Protect citation commands in changed sections with \e\embox command [i.e. use default behaviour for ulem package for other packages] -.SS "Miscellaneous" -.IX Subsection "Miscellaneous" -.RS 4 -Output various status information to stderr during processing. -Default is to work silently. -.Sp -\&\fB\-\-driver=type\fR -.Sp -Choose driver for changebar package (only relevant for styles using - changebar: \s-1CCHANGEBAR\s0 \s-1CFONTCHBAR\s0 \s-1CULINECHBAR\s0 \s-1CHANGEBAR\s0). Possible -drivers are listed in changebar manual, e.g. pdftex,dvips,dvitops - [Default: dvips] -.Sp -\&\fB\-\-ignore\-warnings\fR -.Sp -Suppress warnings about inconsistencies in length between input and -parsed strings and missing characters. These warning messages are -often related to non-standard latex or latex constructions with a -syntax unknown to \f(CW\*(C`latexdiff\*(C'\fR but the resulting difference argument -is often fully functional anyway, particularly if the non-standard -latex only occurs in parts of the text which have not changed. -.Sp -\&\fB\-\-label=label\fR or -\&\fB\-L label\fR -.Sp -Sets the labels used to describe the old and new files. The first use -of this option sets the label describing the old file and the second -use of the option sets the label for the new file, i.e. set both -labels like this \f(CW\*(C`\-L labelold \-L labelnew\*(C'\fR. -[Default: use the filename and modification dates for the label] -.Sp -\&\fB\-\-no\-label\fR -.Sp -Suppress inclusion of old and new file names as comment in output file -.Sp -\&\fB\-\-visble\-label\fR -.Sp -Include old and new filenames (or labels set with \-\-label option) as -visible output. -.Sp -\&\fB\-\-flatten\fR -.Sp -Replace \f(CW\*(C`\einput\*(C'\fR and \f(CW\*(C`\einclude\*(C'\fR commands within body by the content -of the files in their argument. If \f(CW\*(C`\eincludeonly\*(C'\fR is present in the -preamble, only those files are expanded into the document. However, -no recursion is done, i.e. \f(CW\*(C`\einput\*(C'\fR and \f(CW\*(C`\einclude\*(C'\fR commands within -included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, -respectively, making it possible to organise files into old and new directories. -\&\-\-flatten is applied recursively, so inputted files can contain further -\&\f(CW\*(C`\einput\*(C'\fR statements. -.Sp -Use of this option might result in prohibitive processing times for -larger documents, and the resulting difference document -no longer reflects the structure of the input documents. -.Sp -\&\fB\-\-help\fR or -\&\fB\-h\fR -.Sp -Show help text -.Sp -\&\fB\-\-version\fR -.Sp -Show version number -.RE -.SS "Predefined styles" -.IX Subsection "Predefined styles" -.SS "Major types" -.IX Subsection "Major types" -The major type determine the markup of plain text and some selected latex commands outside floats by defining the markup commands \f(CW\*(C`\eDIFadd{...}\*(C'\fR and \f(CW\*(C`\eDIFdel{...}\*(C'\fR . -.ie n .IP """UNDERLINE""" 10 -.el .IP "\f(CWUNDERLINE\fR" 10 -.IX Item "UNDERLINE" -Added text is wavy-underlined and blue, discarded text is struck out and red -(Requires color and ulem packages). Overstriking does not work in displayed math equations such that deleted parts of equation are underlined, not struck out (this is a shortcoming inherent to the ulem package). -.ie n .IP """CTRADITIONAL""" 10 -.el .IP "\f(CWCTRADITIONAL\fR" 10 -.IX Item "CTRADITIONAL" -Added text is blue and set in sans-serif, and a red footnote is created for each discarded -piece of text. (Requires color package) -.ie n .IP """TRADITIONAL""" 10 -.el .IP "\f(CWTRADITIONAL\fR" 10 -.IX Item "TRADITIONAL" -Like \f(CW\*(C`CTRADITIONAL\*(C'\fR but without the use of color. -.ie n .IP """CFONT""" 10 -.el .IP "\f(CWCFONT\fR" 10 -.IX Item "CFONT" -Added text is blue and set in sans-serif, and discarded text is red and very small size. -.ie n .IP """FONTSTRIKE""" 10 -.el .IP "\f(CWFONTSTRIKE\fR" 10 -.IX Item "FONTSTRIKE" -Added tex is set in sans-serif, discarded text small and struck out -.ie n .IP """CCHANGEBAR""" 10 -.el .IP "\f(CWCCHANGEBAR\fR" 10 -.IX Item "CCHANGEBAR" -Added text is blue, and discarded text is red. Additionally, the changed text is marked with a bar in the margin (Requires color and changebar packages). -.ie n .IP """CFONTCHBAR""" 10 -.el .IP "\f(CWCFONTCHBAR\fR" 10 -.IX Item "CFONTCHBAR" -Like \f(CW\*(C`CFONT\*(C'\fR but with additional changebars (Requires color and changebar packages). -.ie n .IP """CULINECHBAR""" 10 -.el .IP "\f(CWCULINECHBAR\fR" 10 -.IX Item "CULINECHBAR" -Like \f(CW\*(C`UNDERLINE\*(C'\fR but with additional changebars (Requires color, ulem and changebar packages). -.ie n .IP """CHANGEBAR""" 10 -.el .IP "\f(CWCHANGEBAR\fR" 10 -.IX Item "CHANGEBAR" -No mark up of text, but mark margins with changebars (Requires changebar package). -.ie n .IP """INVISIBLE""" 10 -.el .IP "\f(CWINVISIBLE\fR" 10 -.IX Item "INVISIBLE" -No visible markup (but generic markup commands will still be inserted. -.SS "Subtypes" -.IX Subsection "Subtypes" -The subtype defines the commands that are inserted at the begin and end of added or discarded blocks, irrespectively of whether these blocks contain text or commands (Defined commands: \f(CW\*(C`\eDIFaddbegin, \eDIFaddend, \eDIFdelbegin, \eDIFdelend\*(C'\fR) -.ie n .IP """SAFE""" 10 -.el .IP "\f(CWSAFE\fR" 10 -.IX Item "SAFE" -No additional markup (Recommended choice) -.ie n .IP """MARGIN""" 10 -.el .IP "\f(CWMARGIN\fR" 10 -.IX Item "MARGIN" -Mark beginning and end of changed blocks with symbols in the margin nearby (using -the standard \f(CW\*(C`\emarginpar\*(C'\fR command \- note that this sometimes moves somewhat -from the intended position. -.ie n .IP """COLOR""" 10 -.el .IP "\f(CWCOLOR\fR" 10 -.IX Item "COLOR" -An alternative way of marking added passages in blue, and deleted ones in red. -(It is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete, for example -with citation commands). -.ie n .IP """DVIPSCOL""" 10 -.el .IP "\f(CWDVIPSCOL\fR" 10 -.IX Item "DVIPSCOL" -An alternative way of marking added passages in blue, and deleted ones in red. Note -that \f(CW\*(C`DVIPSCOL\*(C'\fR only works with the dvips converter, e.g. not pdflatex. -(it is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete). -.SS "Float Types" -.IX Subsection "Float Types" -Some of the markup used in the main text might cause problems when used within -floats (e.g. figures or tables). For this reason alternative versions of all -markup commands are used within floats. The float type defines these alternative commands. -.ie n .IP """FLOATSAFE""" 10 -.el .IP "\f(CWFLOATSAFE\fR" 10 -.IX Item "FLOATSAFE" -Use identical markup for text as in the main body, but set all commands marking the begin and end of changed blocks to null-commands. You have to choose this float type if your subtype is \f(CW\*(C`MARGIN\*(C'\fR as \f(CW\*(C`\emarginpar\*(C'\fR does not work properly within floats. -.ie n .IP """TRADITIONALSAFE""" 10 -.el .IP "\f(CWTRADITIONALSAFE\fR" 10 -.IX Item "TRADITIONALSAFE" -Mark additions the same way as in the main text. Deleted environments are marked by angular brackets \e[ and \e] and the deleted text is set in scriptscript size. This float type should always be used with the \f(CW\*(C`TRADITIONAL\*(C'\fR and \f(CW\*(C`CTRADITIONAL\*(C'\fR markup types as the \efootnote command does not work properly in floating environments. -.ie n .IP """IDENTICAL""" 10 -.el .IP "\f(CWIDENTICAL\fR" 10 -.IX Item "IDENTICAL" -Make no difference between the main text and floats. -.SS "Configuration Variables" -.IX Subsection "Configuration Variables" -.ie n .IP """MINWORDSBLOCK""" 10 -.el .IP "\f(CWMINWORDSBLOCK\fR" 10 -.IX Item "MINWORDSBLOCK" -Minimum number of tokens required to form an independent block. This value is -used in the algorithm to detect changes of complete blocks by merging identical text parts of less than \f(CW\*(C`MINWORDSBLOCK\*(C'\fR to the preceding added and discarded parts. -.Sp -[ Default: 3 ] -.ie n .IP """FLOATENV""" 10 -.el .IP "\f(CWFLOATENV\fR" 10 -.IX Item "FLOATENV" -Environments whose name matches the regular expression in \f(CW\*(C`FLOATENV\*(C'\fR are -considered floats. Within these environments, the \fIlatexdiff\fR markup commands -are replaced by their \s-1FL\s0 variaties. -.Sp -[ Default: \f(CW\*(C`(?:figure|table|plate)[\ew\ed*@]*\*(C'\fR\ ] -.ie n .IP """PICTUREENV""" 10 -.el .IP "\f(CWPICTUREENV\fR" 10 -.IX Item "PICTUREENV" -Within environments whose name matches the regular expression in \f(CW\*(C`PICTUREENV\*(C'\fR -all latexdiff markup is removed (in pathologic cases this might lead to - inconsistent markup but this situation should be rare). -.Sp -[ Default: \f(CW\*(C`(?:picture|DIFnomarkup)[\ew\ed*@]*\*(C'\fR\ ] -.ie n .IP """MATHENV"",""MATHREPL""" 10 -.el .IP "\f(CWMATHENV\fR,\f(CWMATHREPL\fR" 10 -.IX Item "MATHENV,MATHREPL" -If both \ebegin and \eend for a math environment (environment name matching \f(CW\*(C`MATHENV\*(C'\fR -or \e[ and \e]) -are within the same deleted block, they are replaced by a \ebegin and \eend commands for \f(CW\*(C`MATHREPL\*(C'\fR -rather than being commented out. -.Sp -[ Default: \f(CW\*(C`MATHENV\*(C'\fR=\f(CW\*(C`(?:displaymath|equation)\*(C'\fR\ , \f(CW\*(C`MATHREPL\*(C'\fR=\f(CW\*(C`displaymath\*(C'\fR\ ] -.ie n .IP """MATHARRENV"",""MATHARRREPL""" 10 -.el .IP "\f(CWMATHARRENV\fR,\f(CWMATHARRREPL\fR" 10 -.IX Item "MATHARRENV,MATHARRREPL" -as \f(CW\*(C`MATHENV\*(C'\fR,\f(CW\*(C`MATHREPL\*(C'\fR but for equation arrays -.Sp -[ Default: \f(CW\*(C`MATHARRENV\*(C'\fR=\f(CW\*(C`eqnarray\e*?\*(C'\fR\ , \f(CW\*(C`MATHREPL\*(C'\fR=\f(CW\*(C`eqnarray\*(C'\fR\ ] -.ie n .IP """ARRENV""" 10 -.el .IP "\f(CWARRENV\fR" 10 -.IX Item "ARRENV" -If a match to \f(CW\*(C`ARRENV\*(C'\fR is found within an inline math environment within a deleted or added block, then the inlined math -is surrounded by \f(CW\*(C`\embox{\*(C'\fR...\f(CW\*(C`}\*(C'\fR. This is necessary as underlining does not work within inlined array environments. -.Sp -[ Default: \f(CW\*(C`ARRENV\*(C'\fR=\f(CW\*(C`(?:array|[pbvBV]matrix)\*(C'\fR\ -.ie n .IP """COUNTERCMD""" 10 -.el .IP "\f(CWCOUNTERCMD\fR" 10 -.IX Item "COUNTERCMD" -If a command in a deleted block which is also in the textcmd list matches \f(CW\*(C`COUNTERCMD\*(C'\fR then an -additional command \f(CW\*(C`\eaddtocounter{\*(C'\fR\fIcntcmd\fR\f(CW\*(C`}{\-1}\*(C'\fR, where \fIcntcmd\fR is the matching command, is appended in the diff file such that the numbering in the diff file remains synchronized with the -numbering in the new file. -.Sp -[ Default: \f(CW\*(C`COUNTERCMD\*(C'\fR=\f(CW\*(C`(?:footnote|part|section|subsection\*(C'\fR ... -.Sp -\&\f(CW\*(C`|subsubsection|paragraph|subparagraph)\*(C'\fR ] -.SH "COMMON PROBLEMS" -.IX Header "COMMON PROBLEMS" -.IP "Citations result in overfull boxes" 10 -.IX Item "Citations result in overfull boxes" -There is an incompatibility between the \f(CW\*(C`ulem\*(C'\fR package, which \f(CW\*(C`latexdiff\*(C'\fR uses for underlining and striking out in the \s-1UNDERLINE\s0 style, -the default style. In order to be able to mark up citations properly, they are placed with an \f(CW\*(C`\embox\*(C'\fR command in post-processing. As mboxes -cannot be broken across lines, this procedure frequently results in overfull boxes, possibly obscuring the content as it extends beyond the right margin. If this is a problem, you have two possibilities: -.Sp -1. Use \f(CW\*(C`COLOR\*(C'\fR or \f(CW\*(C`DVIPSCOL\*(C'\fR subtype markup (option \f(CW\*(C`\-s COLOR\*(C'\fR): If this markup is chosen, then changed citations are no longer marked up -with the wavy line (additions) or struck out (deletions), but are still highlighted in the appropriate color. -.Sp -2. Choose option \f(CW\*(C`\-\-disable\-citation\-markup\*(C'\fR which turns off the marking up of citations: deleted citations are no longer shown, and -added ctations are shown without markup. (This was the default behaviour of latexdiff at versions 0.6 and older) -.IP "Changes in complicated mathematical equations result in latex processing errors" 10 -.IX Item "Changes in complicated mathematical equations result in latex processing errors" -Try options \f(CW\*(C`\-\-math\-markup=whole\*(C'\fR. If even that fails, you can turn off mark up for equations with \f(CW\*(C`\-\-math\-markup=off\*(C'\fR. -.SH "BUGS" -.IX Header "BUGS" -Option allow-spaces not implemented entirely consistently. It breaks -the rules that number and type of white space does not matter, as -different numbers of inter-argument spaces are treated as significant. -.PP -Please submit bug reports on the latexdiff project page \fIhttp://latexdiff.berlios.de\fR, -send them to user discussion list \f(CW\*(C`latexdiff\-users@lists.berlios,de\*(C'\fR (prior subscription -to list required, also on project webpage) -or send them to \fItilmann@gfz\-potsdam.de\fR. Include the serial number of \fIlatexdiff\fR -(from comments at the top of the source or use \fB\-\-version\fR). If you come across latex -files that are error-free and conform to the specifications set out -above, and whose differencing still does not result in error-free -latex, please send me those files, ideally edited to only contain the -offending passage as long as that still reproduces the problem. If your -file relies on non-standard class files, you must include those. I will not -look at examples where I have trouble to latex the original files. -.SH "SEE ALSO" -.IX Header "SEE ALSO" -latexrevise, latexdiff-vc -.SH "PORTABILITY" -.IX Header "PORTABILITY" -\&\fIlatexdiff\fR does not make use of external commands and thus should run -on any platform supporting Perl 5.6 or higher. If files with encodings -other than \s-1ASCII\s0 or \s-1UTF\-8\s0 are processed, Perl 5.8 or higher is required. -.PP -The standard version of \fIlatexdiff\fR requires installation of the Perl package -\&\f(CW\*(C`Algorithm::Diff\*(C'\fR (available from \fIwww.cpan.org\fR \- -\&\fIhttp://search.cpan.org/~nedkonz/Algorithm\-Diff\-1.15\fR) but a stand-alone -version, \fIlatexdiff-so\fR, which has this package inlined, is available, too. -\&\fIlatexdiff-fast\fR requires the \fIdiff\fR command to be present. -.SH "AUTHOR" -.IX Header "AUTHOR" -Version 1.0.2 -Copyright (C) 2004\-2012 Frederik Tilmann -.PP -This program is free software; you can redistribute it and/or modify -it under the terms of the \s-1GNU\s0 General Public License Version 3 -.PP -Contributors of fixes and additions: V. Kuhlmann, J. Paisley, N. Becker, T. Doerges, K. Huebner, -T. Connors, Sebastian Gouezel and many others. -Thanks to the many people who send in bug reports, feature suggestions, and other feedback. -.SH "POD ERRORS" -.IX Header "POD ERRORS" -Hey! \fBThe above document had some coding errors, which are explained below:\fR -.IP "Around line 2956:" 4 -.IX Item "Around line 2956:" -=over should be: '=over' or '=over positive_number' -.Sp -You can't have =items (as at line 2962) unless the first thing after the =over is an =item diff --git a/latexdiff-1.0.3/latexrevise b/latexdiff-1.0.3/latexrevise deleted file mode 100755 index 0f333fb..0000000 --- a/latexdiff-1.0.3/latexrevise +++ /dev/null @@ -1,539 +0,0 @@ -#!/usr/bin/env perl -# latexrevise - takes output file of latexdiff and removes either discarded -# or appended passages, then deletes all other latexdiff markup -# -# Copyright (C) 2004 F J Tilmann (tilmann@gfz-potsdam.de, ftilmann@users.berlios.de) -# -# Project webpages: http://latexdiff.berlios.de/ -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# Note: version number now keeping up with latexdiff -# Version 1.0.2 Option --version -# Version 1.0.1 no changes to latexrevise -# Version 0.3 Updated for compatibility with latexdiff 0.3 output (DIFAUXCMD removal) -# Version 0.1 First public release - -use Getopt::Long ; -use strict; -use warnings; - -my $versionstring=< \$accept, - 'decline|d'=> \$decline, - 'simplify|s' => \$simplify, - 'comment|c=s' => \$comment, - 'comment-environment|e=s' => \$comenv, - 'markup|m=s' => \$markup, - 'markup-environment|n=s' => \$markenv, - 'no-warnings|q' => \$verbose, - 'version' => \$version, - 'verbose|V' => \$verbose, - 'help|h|H' => \$help); - -if ( $help ) { - usage() ; -} - -if ( $version ) { - die $versionstring ; -} - - -if ( ($accept && $decline) || ($accept && $simplify) || ($decline && $simplify) ) { - die '-a,-d and -s options are mutually axclusive. Type latexrevise -h to get more help.'; -} - - - -print STDERR "ACCEPT mode\n" if $verbose && $accept; -print STDERR "DECLINE mode\n" if $verbose && $decline; -print STDERR "SIMPLIFY mode. WARNING: The output will not normally be valid latex,\n" if $verbose && $simplify; - -# Slurp old and new files -{ - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $input=<>; -} - -# split into parts -($preamble,$body,$post)=splitdoc($input,'\begin{document}','\end{document}'); - -if (length $preamble && ( $accept || $decline ) ) { - # - # WORK ON PREAMBLE - # - # (compare subroutine linediff in latexdiff to make sure correct strings are used) - - # remove extra commands added to preamble by latexdiff - $preamble =~ s/${PREAMBLEXTBEG}.*?${PREAMBLEXTEND}\n{0,1}//smg ; - - if ( $accept ) { - # delete mark up in appended lines - $preamble =~ s/^(.*) %DIF > $/$1/mg ; - } elsif ( $decline ) { - # delete appended lines - # $preamble =~ s/^(.*) %DIF > $//mg ; - $preamble =~ s/^(.*) %DIF > \n//mg ; - # delete markup in deleted lines - $preamble =~ s/^%DIF < //mg ; - } - # remove any remaining DIF markups - #$preamble =~ s/%DIF.*$//mg ; - $preamble =~ s/%DIF.*?\n//sg ; -} -#print $preamble ; - -# -# WORK ON BODY -# -if ($accept) { - # remove ADDMARKOPEN, ADDMARKCLOSE tokens - @matches= $body =~ m/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/sg; - checkpure(@matches); - $body =~ s/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/$1/sg; - # remove text flanked by DELMARKOPEN, DELMARKCLOSE tokens - @matches= $body =~ m/${DELMARKOPEN}(.*?)${DELMARKCLOSE}/sg; - checkpure(@matches); - $body =~ s/${DELMARKOPEN}(.*?)${DELMARKCLOSE}//sg; - # remove markup of added comments - $body =~ s/%${ADDCOMMENT}(.*?)$/%$1/mg ; - # remove deleted comments (full line) - $body =~ s/^%${DELCOMMENT}.*?\n//mg ; - # remove deleted comments (part of line) - $body =~ s/%${DELCOMMENT}.*?$//mg ; -} -elsif ( $decline) { - # remove DELMARKOPEN, DELMARKCLOSE tokens - @matches= $body =~ m/${DELMARKOPEN}(.*?)${DELMARKCLOSE}/sg; - checkpure(@matches); - $body =~ s/${DELMARKOPEN}(.*?)${DELMARKCLOSE}/$1/sg; - # remove text flanked by ADDMARKOPEN, ADDMARKCLOSE tokens - # as latexdiff algorithm keeps the formatting and white spaces - # of the new text, sometimes whitespace might be inserted or - # removed inappropriately. We try to guess whether this has - # happened - - # Mop up tokens. This must be done already now as otherwise - # detection of white-space problems does not work - $cnt = $body =~ s/${DELOPEN}($pat4)${DELCLOSE}/$1/sg; - # remove markup of deleted commands - $cnt += $body =~ s/${DELCMDOPEN}(.*?)${DELCMDCLOSE}/$1/sg ; - $cnt += $body =~ s/${DELCMDOPEN}//g ; - # remove aux commands - $cnt += $body =~ s/^.*${AUXCMD}$/${someword}/mg; $body =~ s/${someword}\n//g; - - while ( $body =~ m/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/s ) { - $prematch=$`; - $postmatch=$'; - checkpure($1); - if ( $prematch =~ /\w$/s && $postmatch =~ /^\w/ ) { - # apparently no white-space between word=>Insert white space - $body =~ s/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/ /s ; - } - elsif ( $prematch =~ /\s$/s && $postmatch =~ /^[.,;:]/ ) { - # space immediately before one of ".,:;" => remove this space - $body =~ s/\s${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}//s ; - } - else { - # do not insert or remove any extras - $body =~ s/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}//s; - } - } -# Alternative without special cases treatment -# @matches= $body =~ m/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/sg; -# checkpure(@matches); -# $body =~ s/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}//sg; - # remove markup of deleted comments - $body =~ s/%${DELCOMMENT}(.*?)$/%$1/mg ; - # remove added comments (full line) - $body =~ s/^%${ADDCOMMENT}.*?\n//mg ; - # remove added comments (part of line) - $body =~ s/%${ADDCOMMENT}.*?$//mg ; -} - -# remove any remaining tokens -if ( $accept || $decline || $simplify ) { - # first substitution command deals with special case of added paragraph - $cnt = $body =~ s/${ADDOPEN}($pat4)\n${ADDCLOSE}\n/$1\n/sg; - $cnt += $body =~ s/${ADDOPEN}($pat4)${ADDCLOSE}/$1/sg; - $cnt==0 || warn 'Remaining $ADDOPEN tokens in DECLINE mode\n' unless ( $quiet || $accept || $simplify ); -} -if ($accept || $simplify ) { - # Note: in decline mode these commands have already been removed above - $cnt = $body =~ s/${DELOPEN}($pat4)${DELCLOSE}/$1/sg; - #### remove markup of deleted commands - $cnt += $body =~ s/${DELCMDOPEN}(.*?)${DELCMDCLOSE}/$1/sg ; - $cnt += $body =~ s/${DELCMDOPEN}//g ; - # remove aux commands - # $cnt += - $body =~ s/^.*${AUXCMD}$/${someword}/mg; $body =~ s/${someword}\n//g; - - #### remove deleted comments - ###$cnt += $body =~ s/${DIFDELCMD}.*?$//mg ; - $cnt==0 || warn 'Remaining $DELOPEN or $DIFDELCMD tokens in ACCEPT mode\n' unless ( $quiet || $simplify ); -} - -# Remove comment commands -if (defined($comment)) { - print STDERR "Removing \\$comment\{..\} sequences ..." if $verbose; - # protect $comments in comments by making them look different - $body =~ s/(%.*)${comment}(.*)$/$1${someword}$2/mg ; - # carry out the substitution - $cnt = 0 + $body =~ s/\\${comment}(?:\[${brat0}\])?\{${pat4}\}//sg ; - print STDERR "$cnt matches found and removed.\n" if $verbose; - # and undo the protection substitution - $body =~ s/(%.*)${someword}(.*)$/$1${comment}$2/mg ; -} -if (defined($comenv)) { - print STDERR "Removing $comenv environments ..." if $verbose; - $body =~ s/(%.*)${comenv}/$1${someword}/mg ; -## $cnt = 0 + $body =~ s/\\begin(?:\[${brat0}\])?\{\$comenv\}.*?\\end\{\$comenv\}//sg ; - $cnt = 0 + $body =~ s/\\begin(?:\[${brat0}\])?\{${comenv}\}.*?\\end\{${comenv}\}\s*?\n//sg ; - print STDERR "$cnt matches found and removed.\n" if $verbose; - $body =~ s/(%.*)${someword}/$1${comenv}/mg ; -} - -if (defined($markup)) { - print STDERR "Removing \\$markup\{..\} cpmmands ..." if $verbose; - # protect $markups in comments by making them look different - $body =~ s/(%.*)${markup}(.*)$/$1${someword}$2/mg ; - # carry out the substitution - $cnt = 0 + $body =~ s/\\${markup}(?:\[${brat0}\])?\{(${pat4})\}/$1/sg ; - print STDERR "$cnt matches found and removed.\n" if $verbose; - # and undo the protection substitution - $body =~ s/(%.*)${someword}(.*)$/$1${markup}$2/mg ; -} -if (defined($markenv)) { - print STDERR "Removing $markenv environments ..." if $verbose; - $body =~ s/(%.*)${markenv}/$1${someword}/mg ; - $cnt = 0 + $body =~ s/\\begin(?:\[${brat0}\])?\{${markenv}\}\n?//sg; - $cnt += 0 + $body =~ s/\\end\{${markenv}\}\n?//sg; - print STDERR $cnt/2, " matches found and removed.\n" if $verbose; - $body =~ s/(%.*)${someword}/$1${markenv}/mg ; -} - - -if ( length $preamble ) { - print "$preamble\\begin{document}${body}\\end{document}$post"; -} else { - print $body; -} - -# checkpure(@matches) -# checks whether any of the strings in matches contains -# $ADDMARKOPEN, $ADDMARKCLOSE,$DELMARKOPEN, or $DELMARKCLOSE -# If so, die reporting nesting problems, otherwise return to caller -sub checkpure { - while (defined($_=shift)) { - if ( /$ADDMARKOPEN/ || /$ADDMARKCLOSE/ - || /$DELMARKOPEN/ || /$DELMARKCLOSE/ ) { - die <=0 && $j>$i ) { - $part1 = substr($text,0,$i) ; - $part2 = substr($text,$i+$l1,$j-$i-$l1); - $part3 = substr($text,$j+$l2) unless $j+$l2 >= length $text; - } else { - die "$word1 or $word2 not in the correct order or not present as a pair." - } - return ($part1,$part2,$part3); -} - - - -sub usage { - die <<"EOF"; -Usage: $0 [OPTIONS] [diff.tex] > revised.tex - -Read a file diff.tex (output of latexdiff), and remove its markup. -If no filename is given read from standard input. The command can be used -in ACCEPT, DECLINE, or SIMPLIFY mode, and be used to remove user-defined -latex commands from the input (see options -c, -e, -m, -n below). -In ACCEPT mode, all appended text fragments (or preamble lines) -are kept, and all discarded text fragments (or preamble lines) are -deleted. -In DECLINE mode, all discarded text fragments are kept, and all appended -text fragments are deleted. -If you wish to keep some changes, edit the diff.tex file in -advance, and manually remove those tokens which would otherwise be -deleted. Note that latexrevise only pays attention to the \\DIFaddbegin, -\\DIFaddend, \\DIFdelbegin, and \\DIFdelend tokens and corresponding FL -varieties. All \\DIFadd and \\DIFdel commands (but not their content) are -simply deleted. The commands added by latexdiff to the preamble are also -removed. -In SIMPLIFY mode all latexdiff markup is removed from the body of the text (after -\\begin{document}) except for \\DIFaddbegin, \\DIFaddend, \\DIFdelbegin, \\DIFdelend -tokens and the corresponding FL varieties of those commands. The result -will not in general be valid latex-code but might be easier to read and edit in -preparation for a subsequent run in ACCEPT or DECLINE mode. -In SIMPLIFY mode the preamble is left unmodified. - --a ---accept Run in ACCEPT mode (delete all blocks marked by \\DIFdelbegin - and \\DIFdelend). - --d ---decline Run in DECLINE mode (delete all blocks marked by \\DIFaddbegin - and \\DIFaddend). - --s ---simplify Run in SIMPLIFY mode (Keep all \\DIFaddbegin, \\DIFaddend, - \\DIFdelbegin, \\DIFdelend tokens, but remove all other latexdiff - markup from body. - -Note that the three mode options are mutually exclusive. If no mode option is given, -latexrevise simply removes user annotations and markup according to the following four -options. - - --c cmd ---comment=cmd Remove \\cmd{...}. cmd is supposed to mark some explicit - anotations which should be removed from the file before - release. - --e envir ---comment-environment=envir - Remove explicit annotation environments from the text, i.e. remove - \\begin{envir} - ... - \\end{envir} - blocks. - --m cmd ---markup=cmd Remove the markup command cmd but leave its argument, i.e. - turn \\cmd{abc} into abc. - --n envir ---markup-environment=envir - Similarly, remove \\begin{envir} and \\end{envir} commands, - but leave content of the environment in the text. - --q ---no-warnings Do not warn users about \\DIDadd{..} or \\DIFdel statements - which should not be there anymore - --V ---verbose Verbose output - -EOF -} - -=head1 NAME - -latexrevise - selectively remove markup and text from latexdiff output - -=head1 SYNOPSIS - -B [ B ] [ F ] > F - -=head1 DESCRIPTION - -I reads a file C (output of I), and remove the markup commands. -If no filename is given the input is read from standard input. The command can be used -in I, I, or I mode, or can be used to remove user-defined -latex commands from the input (see B<-c>, B<-e>, B<-m>, and B<-n> below). -In I mode, all appended text fragments (or preamble lines) -are kept, and all discarded text fragments (or preamble lines) are -deleted. -In I mode, all discarded text fragments are kept, and all appended -text fragments are deleted. -If you wish to keep some changes, edit the diff.tex file in -advance, and manually remove those tokens which would otherwise be -deleted. Note that I only pays attention to the C<\DIFaddbegin>, -C<\DIFaddend>, C<\DIFdelbegin>, and C<\DIFdelend> tokens and corresponding FL -varieties. All C<\DIFadd> and C<\DIFdel> commands (but not their contents) are -simply deleted. The commands added by latexdiff to the preamble are also -removed. -In I mode, C<\DIFaddbegin, \DIFaddend, \DIFdelbegin, \DIFdelend> -tokens and their corresponding C varieties are kept but all other markup (e.g. C and <\DIFdel>) is removed. The result -will not in general be valid latex-code but it will be easier to read and edit in -preparation for a subsequent run in I or I mode. -In I mode the preamble is left unmodified. - -=head1 OPTIONS - -=over 4 - -=item B<-a> or B<--accept> - -Run in I mode (delete all blocks marked by C<\DIFdelbegin> and C<\DIFdelend>). - -=item B<-d> or B<--decline> - -Run in I mode (delete all blocks marked by C<\DIFaddbegin> -and C<\DIFaddend>). - -=item B<-s> or B<--simplify> - -Run in I mode (Keep all C<\DIFaddbegin>, C<\DIFaddend>, -C<\DIFdelbegin>, C<\DIFdelend> tokens, but remove all other latexdiff -markup from body). - -=back - -Note that the three mode options are mutually exclusive. If no mode option is given, -I simply removes user annotations and markup according to the following four -options. - -=over 4 - -=item B<-c cmd> or B<--comment=cmd> - -Remove C<\cmd{...}> sequences. C is supposed to mark some explicit -anotations which should be removed from the file before -release. - -=item B<-e envir> or B<--comment-environment=envir> - -Remove explicit annotation environments from the text, i.e. remove - - \begin{envir} - ... - \end{envir} - -blocks. - -=item B<-m cmd> or B<--markup=cmd> - -Remove the markup command C<\cmd> but leave its argument, i.e. -turn C<\cmd{abc}> into C. - -=item B<-n envir> or B<--markup-environment=envir> - -Similarly, remove C<\begin{envir}> and C<\end{envir}> commands but -leave content of the environment in the text. - - -=item B<-V> or B<--verbose> - -Verbose output - -=item B<-q> or B<--no-warnings> - -Do not warn users about C<\DIDadd{..}> or C<\DIFdel{..}> statements -which should have been removed already. - -=back - -=head1 BUGS - -The current version is a beta version which has not yet been -extensively tested, but worked fine locally. Please submit bug reports through -the latexdiff project page I or send -to I. Include the serial number of I -(from comments at the top of the source). If you come across latexdiff -output which is not processed correctly by I please include the -problem file as well as the old and new files on which it is based, -ideally edited to only contain the offending passage as long as that still -reproduces the problem. - -Note that I gets confused by commented C<\begin{document}> or -C<\end{document}> statements - -=head1 SEE ALSO - -L - -=head1 PORTABILITY - -I does not make use of external commands and thus should run -on any platform supporting PERL v5 or higher. - -=head1 AUTHOR - -Copyright (C) 2004 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 - -=cut diff --git a/latexdiff-1.0.3/latexrevise.1 b/latexdiff-1.0.3/latexrevise.1 deleted file mode 100644 index 8b14197..0000000 --- a/latexdiff-1.0.3/latexrevise.1 +++ /dev/null @@ -1,235 +0,0 @@ -.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` "" -. ds C' "" -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.ie \nF \{\ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. nr % 0 -. rr F -.\} -.el \{\ -. de IX -.. -.\} -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "LATEXREVISE 1" -.TH LATEXREVISE 1 "2013-01-27" "perl v5.14.2" " " -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -latexrevise \- selectively remove markup and text from latexdiff output -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBlatexrevise\fR [ \fB\s-1OPTIONS\s0\fR ] [ \fIdiff.tex\fR ] > \fIrevised.tex\fR -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -\&\fIlatexrevise\fR reads a file \f(CW\*(C`diff.tex\*(C'\fR (output of \fIlatexdiff\fR), and remove the markup commands. -If no filename is given the input is read from standard input. The command can be used -in \fI\s-1ACCEPT\s0\fR, \fI\s-1DECLINE\s0\fR, or \fI\s-1SIMPLIFY\s0\fR mode, or can be used to remove user-defined -latex commands from the input (see \fB\-c\fR, \fB\-e\fR, \fB\-m\fR, and \fB\-n\fR below). -In \fI\s-1ACCEPT\s0\fR mode, all appended text fragments (or preamble lines) -are kept, and all discarded text fragments (or preamble lines) are -deleted. -In \fI\s-1DECLINE\s0\fR mode, all discarded text fragments are kept, and all appended -text fragments are deleted. -If you wish to keep some changes, edit the diff.tex file in -advance, and manually remove those tokens which would otherwise be -deleted. Note that \fIlatexrevise\fR only pays attention to the \f(CW\*(C`\eDIFaddbegin\*(C'\fR, -\&\f(CW\*(C`\eDIFaddend\*(C'\fR, \f(CW\*(C`\eDIFdelbegin\*(C'\fR, and \f(CW\*(C`\eDIFdelend\*(C'\fR tokens and corresponding \s-1FL\s0 -varieties. All \f(CW\*(C`\eDIFadd\*(C'\fR and \f(CW\*(C`\eDIFdel\*(C'\fR commands (but not their contents) are -simply deleted. The commands added by latexdiff to the preamble are also -removed. -In \fI\s-1SIMPLIFY\s0\fR mode, \f(CW\*(C`\eDIFaddbegin, \eDIFaddend, \eDIFdelbegin, \eDIFdelend\*(C'\fR -tokens and their corresponding \f(CW\*(C`FL\*(C'\fR varieties are kept but all other markup (e.g. \f(CW\*(C`DIFadd\*(C'\fR and <\eDIFdel>) is removed. The result -will not in general be valid latex-code but it will be easier to read and edit in -preparation for a subsequent run in \fI\s-1ACCEPT\s0\fR or \fI\s-1DECLINE\s0\fR mode. -In \fI\s-1SIMPLIFY\s0\fR mode the preamble is left unmodified. -.SH "OPTIONS" -.IX Header "OPTIONS" -.IP "\fB\-a\fR or \fB\-\-accept\fR" 4 -.IX Item "-a or --accept" -Run in \fI\s-1ACCEPT\s0\fR mode (delete all blocks marked by \f(CW\*(C`\eDIFdelbegin\*(C'\fR and \f(CW\*(C`\eDIFdelend\*(C'\fR). -.IP "\fB\-d\fR or \fB\-\-decline\fR" 4 -.IX Item "-d or --decline" -Run in \fI\s-1DECLINE\s0\fR mode (delete all blocks marked by \f(CW\*(C`\eDIFaddbegin\*(C'\fR -and \f(CW\*(C`\eDIFaddend\*(C'\fR). -.IP "\fB\-s\fR or \fB\-\-simplify\fR" 4 -.IX Item "-s or --simplify" -Run in \fI\s-1SIMPLIFY\s0\fR mode (Keep all \f(CW\*(C`\eDIFaddbegin\*(C'\fR, \f(CW\*(C`\eDIFaddend\*(C'\fR, -\&\f(CW\*(C`\eDIFdelbegin\*(C'\fR, \f(CW\*(C`\eDIFdelend\*(C'\fR tokens, but remove all other latexdiff -markup from body). -.PP -Note that the three mode options are mutually exclusive. If no mode option is given, -\&\fIlatexrevise\fR simply removes user annotations and markup according to the following four -options. -.IP "\fB\-c cmd\fR or \fB\-\-comment=cmd\fR" 4 -.IX Item "-c cmd or --comment=cmd" -Remove \f(CW\*(C`\ecmd{...}\*(C'\fR sequences. \f(CW\*(C`cmd\*(C'\fR is supposed to mark some explicit -anotations which should be removed from the file before -release. -.IP "\fB\-e envir\fR or \fB\-\-comment\-environment=envir\fR" 4 -.IX Item "-e envir or --comment-environment=envir" -Remove explicit annotation environments from the text, i.e. remove -.Sp -.Vb 3 -\& \ebegin{envir} -\& ... -\& \eend{envir} -.Ve -.Sp -blocks. -.IP "\fB\-m cmd\fR or \fB\-\-markup=cmd\fR" 4 -.IX Item "-m cmd or --markup=cmd" -Remove the markup command \f(CW\*(C`\ecmd\*(C'\fR but leave its argument, i.e. -turn \f(CW\*(C`\ecmd{abc}\*(C'\fR into \f(CW\*(C`abc\*(C'\fR. -.IP "\fB\-n envir\fR or \fB\-\-markup\-environment=envir\fR" 4 -.IX Item "-n envir or --markup-environment=envir" -Similarly, remove \f(CW\*(C`\ebegin{envir}\*(C'\fR and \f(CW\*(C`\eend{envir}\*(C'\fR commands but -leave content of the environment in the text. -.IP "\fB\-V\fR or \fB\-\-verbose\fR" 4 -.IX Item "-V or --verbose" -Verbose output -.IP "\fB\-q\fR or \fB\-\-no\-warnings\fR" 4 -.IX Item "-q or --no-warnings" -Do not warn users about \f(CW\*(C`\eDIDadd{..}\*(C'\fR or \f(CW\*(C`\eDIFdel{..}\*(C'\fR statements -which should have been removed already. -.SH "BUGS" -.IX Header "BUGS" -The current version is a beta version which has not yet been -extensively tested, but worked fine locally. Please submit bug reports through -the latexdiff project page \fIhttp://developer.berlios.de/projects/latexdiff/\fR or send -to \fItilmann@gfz\-potsdam.de\fR. Include the serial number of \fIlatexrevise\fR -(from comments at the top of the source). If you come across latexdiff -output which is not processed correctly by \fIlatexrevise\fR please include the -problem file as well as the old and new files on which it is based, -ideally edited to only contain the offending passage as long as that still -reproduces the problem. -.PP -Note that \fIlatexrevise\fR gets confused by commented \f(CW\*(C`\ebegin{document}\*(C'\fR or -\&\f(CW\*(C`\eend{document}\*(C'\fR statements -.SH "SEE ALSO" -.IX Header "SEE ALSO" -latexdiff -.SH "PORTABILITY" -.IX Header "PORTABILITY" -\&\fIlatexrevise\fR does not make use of external commands and thus should run -on any platform supporting \s-1PERL\s0 v5 or higher. -.SH "AUTHOR" -.IX Header "AUTHOR" -Copyright (C) 2004 Frederik Tilmann -.PP -This program is free software; you can redistribute it and/or modify -it under the terms of the \s-1GNU\s0 General Public License Version 3 diff --git a/latexdiff-1.0.4/COPYING b/latexdiff-1.0.4/COPYING deleted file mode 100644 index d6fa915..0000000 --- a/latexdiff-1.0.4/COPYING +++ /dev/null @@ -1,623 +0,0 @@ - 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 - - diff --git a/latexdiff-1.0.4/Makefile b/latexdiff-1.0.4/Makefile deleted file mode 100644 index 4546730..0000000 --- a/latexdiff-1.0.4/Makefile +++ /dev/null @@ -1,64 +0,0 @@ -# Modify these paths to the requirements of your own system -# For the current setting you will need root permission but -# it is perfectly acceptable to choose user directories -# -INSTALLPATH = /usr/local -INSTALLMANPATH = $(INSTALLPATH)/man -INSTALLEXECPATH = $(INSTALLPATH)/bin - -default: - @echo "To install stand-alone version type: make install" - @echo " (Note the standard version requires prior installation" - @echo " of the PERL package Algorithm::Diff available from " - @echo " the PERL archive www.cpan.org)" - @echo " " - @echo "To install fast version (using UNIX diff) type: make install fast " - @echo " " - @echo "To install the version which uses the system Algorithm::Diff package type: make install-ext" - @echo " " - -install: install-so - -install-ext: install-latexdiff install-latexrevise install-latexdiff-vc install-man - -install-so: install-latexdiff-so install-latexrevise install-latexdiff-vc install-man - -install-fast: install-latexdiff-fast install-latexrevise install-latexdiff-vc install-man - -install-man: - install latexrevise.1 latexdiff.1 latexdiff-vc.1 $(INSTALLMANPATH)/man1 - -install-latexdiff: - install latexdiff $(INSTALLEXECPATH) - -install-latexdiff-so: - if [ -e $(INSTALLEXECPATH)/latexdiff ]; then rm $(INSTALLEXECPATH)/latexdiff; fi - install latexdiff-so $(INSTALLEXECPATH) - cd $(INSTALLEXECPATH); ln -s latexdiff-so latexdiff - -install-latexdiff-fast: - if [ -e $(INSTALLEXECPATH)/latexdiff ]; then rm $(INSTALLEXECPATH)/latexdiff; fi - install latexdiff-fast $(INSTALLEXECPATH) - cd $(INSTALLEXECPATH); ln -s latexdiff-fast latexdiff - -install-latexrevise: - install latexrevise $(INSTALLEXECPATH) - -install-latexdiff-vc: - install latexdiff-vc $(INSTALLEXECPATH) - cd $(INSTALLEXECPATH); for vcs in cvs rcs svn ; do if [ -e latexdiff-$$vcs ]; then rm latexdiff-$$vcs; fi; ln -s latexdiff-vc latexdiff-$$vcs ; done - -test-ext: - @echo "latexdiff example/example-draft.tex example/example-rev.tex (system Algorithm::Diff)" - ./latexdiff -V example/example-draft.tex example/example-rev.tex > example/example-diff.tex - @echo "Difference file created: example/example-diff.tex" - -test-so: - @echo "latexdiff example/example-draft.tex example/example-rev.tex (stand-alone version)" - ./latexdiff-so -V example/example-draft.tex example/example-rev.tex > example/example-diff.tex - @echo "Difference file created: example/example-diff.tex" - -test-fast: - @echo "latexdiff example/example-draft.tex example/example-rev.tex (stand-alone version)" - ./latexdiff-fast -V example/example-draft.tex example/example-rev.tex > example/example-diff.tex - @echo "Difference file created: example/example-diff.tex" diff --git a/latexdiff-1.0.4/README b/latexdiff-1.0.4/README deleted file mode 100644 index e9e1893..0000000 --- a/latexdiff-1.0.4/README +++ /dev/null @@ -1,108 +0,0 @@ -INTRODUCTION - -latexdiff is a Perl script, which compares two latex files and marks -up significant differences between them (i.e. a diff for latex files). - Various options are available for visual markup using standard latex -packages such as "color.sty". Changes not directly affecting visible -text, for example in formatting commands, are still marked in -the latex source. - -A rudimentary revision facilility is provided by another Perl script, -latexrevise, which accepts or rejects all changes. Manual -editing of the difference file can be used to override this default -behaviour and accept or reject selected changes only. - -The author is F Tilmann (ftilmann@users.berlios.de). - -Project webpage: http://latexdiff.berlios.de/ -CTAN page: http://www.ctan.org/tex-archive/support/latexdiff - - -REQUIREMENTS - -Perl 5.8 or higher must be installed. - The latexdiff script makes use of the Perl package Algorithm::Diff (available -from www.cpan.org, current version 1.19). You can either install this package, or -use the standalone version of latexdiff, latexdiff-so, which has version 1.15 of -this package inlined and does not require external installation of -the package. Because latexdiff uses internal functions of Algorithm:Diff whose -calling format or availability can change without notice, the preferred method is -now to use the standalone version. - -As an alternative, latexdiff-fast has a modified version of Algorithm::Diff inlined, -which internally uses the UNIX diff command. This version is much faster but is dependent -on an external "diff" command. Subtle differences in the algorithm of Algorithm::Diff and -UNIX-diff mean that the resulting set of differences will generally not be the same as -for the standard latexdiff. In most practical cases, these differences are minor, though. - -INSTALLATION UNIX/LINUX - -The basic installation procedure is almost trivial: - -1. Copy latexdiff, latexrevise and latexdiff-vc into a directory which - is in the search path and make them executable. If the Algorithm::Diff - package is not installed, use latexdiff-so instead of latexdiff. - -2. Copy latexdiff.1 and latexrevise.1 into the correct man directory - -3. Optionally create soft links latexdiff-cvs latexdiff-rcs, and - latexdiff-svn for latexdiff-vc. - -The attached trivial Makefile contains example commands to carry out above -steps as root for a typical UNIX installation. Type - - make install (for the stand alone version) -or - make install-ext (for the version using the external Algorithm::Diff) -or - make install-fast (for the version using the UNIX 'diff' function for fast differencing) - -to get it rolling. You can type - - make test -or - make test-ext -or - make test-fast - -to test the respective versions on a brief example before installation. It will often be -as easy to carry out these steps manually instead of using the Makefile. - - -DOCUMENTATION: - -Usage instructions are in the manual latexdiff-man.pdf as well as the -man pages. - -CHANGELOGS: - -Check out the comment lines at the beginning of the perl scripts (latexdiff, latexdiff-vc, latexrevise) - -CONTRIBUTIONS - -The directory contrib contains code written by others relating to latexdiff. -Currently this directory contains: - -latexdiff-wrap (Author: V. Kuhlmann) An alternative wrapper script which can be used - instead of latexdiff-vc. Its main use is as a template for customised wrapper scripts. - -latexdiff.spec (Author: T. Doerges) spec file for RPM generation - -latexchanges (Author: Jan-Ake Larsson) Wrapper script for applying latexdiff with numbered documen version -(see contrib/README.latexchanges for a more detailed description) - -Cntributions by the following authors were incorporated into the latexdiff code, or inspired me to -extend latexdiff in a similar way: J. Paisley, N. Becker, K. Huebner - -LICENSE (also see file COPYING) - -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 (file LICENSE in the -distribution). - diff --git a/latexdiff-1.0.4/contrib/README.latexchanges b/latexdiff-1.0.4/contrib/README.latexchanges deleted file mode 100644 index 4a02765..0000000 --- a/latexdiff-1.0.4/contrib/README.latexchanges +++ /dev/null @@ -1,13 +0,0 @@ -latexchanges.py (Jan-Ake Larsson): -Here's a wrapper I wrote for latexdiff, intended as a drop-in -replacement for latex, when you have several numbered (or dated) -versions of a manuscript. My coauthors don't as a rule know what CVS or -SVN is, they simply use a number or date for the different versions. - -latexchanges replaces the current DVI with one that includes a -latexdiff to the last version. The last version is selected as the -TEX file in the same directory with the same prefix (up to a number -or a dot), that has an mtime immediately preceding the given TEX -file. - - diff --git a/latexdiff-1.0.4/contrib/latexchanges.py b/latexdiff-1.0.4/contrib/latexchanges.py deleted file mode 100644 index de7acbe..0000000 --- a/latexdiff-1.0.4/contrib/latexchanges.py +++ /dev/null @@ -1,67 +0,0 @@ -#! /bin/env python -# latexchanges -# -# Wrapper for latexdiff, intended as a drop-in replacement for latex, -# when you have several numbered (or dated) versions of a manuscript. -# My coauthors don't as a rule know what CVS or SVN is, they simply -# use a number or date for the different versions. -# -# latexchanges replaces the current DVI with one that includes a -# latexdiff to the last version. The last version is selected as the -# TEX file in the same directory with the same prefix (up to a number -# or a dot), that has an mtime immediately preceding the given TEX -# file. -# -# (I should probably add CVS version numbering too, at some point.) -# -# Copyright (C) 2009 by Jan-\AA{}ke Larsson -# Released under the terms of the GNU General Public License (GPL) -# Version 2. See http://www.gnu.org/ for details. -# -# Please do provide patches and bug reports, but remember: if it -# breaks, you get to keep the pieces. -# -# Jan-\AA{}ke Larsson -# Sept 16 2009 - -from os import listdir,system,stat -from sys import argv -from re import split - -name="" -newarg=[] - -# Find filename argument -for i in range(1,len(argv)): - if argv[i][-4:]==".tex": - basename=split('[0-9.]',argv[i])[0] - name=argv[i][:-4] - newarg.append(name+".changes.tex") - else: - newarg.append(argv[i]) - -if name: - print "Filename",name+".tex" - print "Prefix is",basename - # Find last archived version - mtime=stat(name+".tex").st_mtime - old_mtime=0 - ls=listdir(".") - for j in ls: - if j.startswith(basename) and j.endswith(".tex")\ - and not j.endswith(".changes.tex"): - tmptime=stat(j).st_mtime - if mtime>tmptime and old_mtime0: - print "Comparing with",oldname - system ("/bin/cp "+name+".aux "+name+".changes.aux") - system ("/bin/cp "+name+".bbl "+name+".changes.bbl") - system ("latexdiff "+oldname+" "+name+".tex > "+name+".changes.tex") - system ("latex "+" ".join(newarg)) - system ("cp "+name+".changes.dvi "+name+".dvi") - else: - system ("latex "+" ".join(argv[1:])) diff --git a/latexdiff-1.0.4/contrib/latexdiff-wrap b/latexdiff-1.0.4/contrib/latexdiff-wrap deleted file mode 100755 index 894b424..0000000 --- a/latexdiff-1.0.4/contrib/latexdiff-wrap +++ /dev/null @@ -1,192 +0,0 @@ -#!/bin/bash -# -# latexdiff-wrap -# -# Wrapper for latexdiff, to -# * provide support for documents consiting of more than 1 latex file -# * provide my common arguments -# -# Copyright (C) by Volker Kuhlmann -# Released under the terms of the GNU General Public License (GPL) Version 2. -# See http://www.gnu.org/ for details. -# -# Volker Kuhlmann -# 5, 6, 7, 12, 16, 17 Oct 2005 -# 31 Jan; 5, 7, 13, 15 Feb 2006 -# - -VERSION="0.6, 15 Feb 2006" -AUTHOR="Volker Kuhlmann " -COPYRIGHT="Copyright (C) 2005-2006" - - -#### -#### Constants and initialised variables -# -diffcmd="latexdiff" -diffrc="$HOME/texmf/latexdiff" -#diffargs="-e latin1 --ignore-warnings -p latexdiff-preamble.sty" -diffargs="-e latin1 --ignore-warnings" -diffargs="$diffargs --append-safecmd $diffrc/safe-cmds" -diffargs="$diffargs --append-textcmd $diffrc/text-cmds" -# Note: Can't use multiple --append-safecmd -# show current command lists: -#diffcmd="$diffcmd --show-safecmd --show-textcmd --show-config" - - -#### -#### Version, Usage, Help -# -show_version() { - echo "${0##*/} version $VERSION -$COPYRIGHT by $AUTHOR" -} - -show_usage() { - echo " -Usage: ${0##*/} OLDDIR NEWDIR DIFFDIR [DIFFARGS --] FILE.tex [...] - ${0##*/} --show [DIFFARGS] -Version $VERSION -$COPYRIGHT by $AUTHOR -" -} - -show_help() { - show_usage - echo "\ -For each FILE.tex, build a new file DIFFDIR/FILE.tex with markup of the changes -which were made from OLDDIR/FILE.tex to NEWDIR/FILE.tex. -Any path given with FILE.tex is stripped off. -Any DIFFARGS are added to the latexdiff call, if present (remember to follow -them with a double-hyphen on its own before the FILE arguments). - -With --show, shows the settings latexdiff would be running with, including the -changes applied by the user. -" -} - -# For scripts not using function library only: -Version() { show_version; exitwith ErrVersion; } -Usage() { show_help; exitwith ErrUsage; } -Help() { test "$1" && exitwith ErrHelp show_help; show_help; exitwith ErrOK; } - - -#### -#### Error/Exit codes -# -exitwith() { - exec 1>&2 # write stdout on stderr instead - case "$1" in - ErrOK) - exit 0;; - ErrVersion|ErrUsage|ErrHelp) - # Output generated by function (program) $2, if given - test -n "$2" && "$2" - exit 1;; - # more codes in here - # more codes in here - ErrBadoption) - echo "Bad option '$2'." - echo "Call with -h for help." - exit 9;; - ErrMissingParameter) - echo "A required parameter for option $2 is missing." - echo "Call with -h for help." - exit 9;; - *) - echo "Internal error: exitwith() called with illegal error code '$1'." - exit 19;; - esac -} - - -#### -#### Parse command line parameters -# - -# If the next arg starts with a "-", collect additional argument for latexdiff -# until "--". -scanextraargs() { - addargs=() - case "$1" in -*) - while [ $# -gt 0 -a "$1" != "--" ]; do - addargs=( "${addargs[@]}" "$1" ) - shift - done - test "$1" == "--" && shift - ;; esac - fileargs=( "$@" ) -} - -case "$1" in - --version) Version;; - --usage) Usage;; - --help|-h|-help) Help;; - --show) - shift - scanextraargs "$@" - (set -x - $diffcmd $diffargs "${addargs[@]}" \ - --show-safecmd --show-textcmd --show-config - ) | fmt - exit $? ;; -esac - -olddir="${1%/}" -newdir="${2%/}" -diffdir="${3%/}" - -if ! [ -d "$olddir" -a -d "$newdir" -a -d "$diffdir" ]; then - Help 1>&2 err -fi - -shift 3 - -scanextraargs "$@" -set -- "${fileargs[@]}" - - - -#### -#### Functions -# -#set -x -Log() { echo 1>&2 "+ $@"; "$@"; } - - -#### -#### Main -# - -# Create output directory, just in case. -(set -x -mkdir -p "$diffdir" -) -while [ $# -gt 0 ]; do - file="${1##*/}" - echo Examining: "$file" - # No point running latexdiff if both files are identical, - # but run latexdiff on top-level LaTeX file in any case. - if cmp --quiet "$olddir/$file" "$newdir/$file" \ - && ! grep -lq '\\begin.*{document}' "$newdir/$file"; then - (set -x - cp -p "$olddir/$file" "$diffdir" - ) - else - # Delete file, to make sure it's not clobbered by redirecting stdout - # in case it's a symlink to te original. - test -f "$diffdir/$file" && (set -x - rm "$diffdir/$file" - ) - # Run latexdiff if both input files are present. - run=1 - test -f "$olddir/$file" || { echo 1>&2 "No file: $olddir/$file"; run=; } - test -f "$newdir/$file" || { echo 1>&2 "No file: $newdir/$file"; run=; } - test -n "$run" && \ - (set -x - $diffcmd $diffargs "${addargs[@]}" \ - "$olddir/$file" "$newdir/$file" > "$diffdir/$file" - ) - fi - shift -done diff --git a/latexdiff-1.0.4/contrib/latexdiff.spec b/latexdiff-1.0.4/contrib/latexdiff.spec deleted file mode 100644 index 9255a69..0000000 --- a/latexdiff-1.0.4/contrib/latexdiff.spec +++ /dev/null @@ -1,58 +0,0 @@ -Summary: Diff for LaTeX files -Name: latexdiff -Version: 0.5 -Release: 1 -License: GPL -Group: Productivity/Publishing/TeX/Utilities -URL: http://www.tug.org/tex-archive/help/Catalogue/entries/latexdiff.html -Source0: %{name}.zip -BuildArch: noarch -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root -# only required for 'make install-ext' -# Requires: perl-Algorithm-Diff - - -%description -latexdiff is a Perl script, which compares two latex files and marks -up significant differences between them (i.e. a diff for latex files). - Various options are available for visual markup using standard latex -packages such as "color.sty". Changes not directly affecting visible -text, for example in formatting commands, are still marked in -the latex source. - -(C) 2004 Frederik Tilmann - - -%prep -%setup -n %{name} - - -%build -# quick had to adapt the Makefile -%{__mv} Makefile Makefile.old -%{__sed} \ - -e "s;INSTALLPATH = /usr/local;INSTALLPATH = \${DESTDIR}%{_prefix};" \ - -e "s;INSTALLMANPATH = \$(INSTALLPATH)/man;INSTALLMANPATH = \${DESTDIR}%{_mandir};" \ - Makefile.old > Makefile - - -%install -%{__mkdir_p} $RPM_BUILD_ROOT%{_bindir} -%{__mkdir_p} $RPM_BUILD_ROOT%{_mandir}/man1 - -%makeinstall - - -%clean -[ "${RPM_BUILD_ROOT}" != "/" ] && [ -d "${RPM_BUILD_ROOT}" ] && %{__rm} -rf "${RPM_BUILD_ROOT}" - - -%files -%defattr(-,root,root) -%doc example CHANGES LICENSE README -%{_bindir}/* -%{_mandir}/man*/* - -%changelog -* Thu Jan 4 2007 Till Dörges - 0.5-1 -- Initial build. diff --git a/latexdiff-1.0.4/doc/example-diff.tex b/latexdiff-1.0.4/doc/example-diff.tex deleted file mode 100644 index 7166571..0000000 --- a/latexdiff-1.0.4/doc/example-diff.tex +++ /dev/null @@ -1,89 +0,0 @@ -\documentclass[12pt,a4paper]{article} -%DIF LATEXDIFF DIFFERENCE FILE -%DIF DEL example-draft.tex Thu Jun 12 00:01:26 2014 -%DIF ADD example-rev.tex Thu Jun 12 00:01:26 2014 - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -%DIF 7c7 -%DIF < \setlength{\textwidth}{6.5in} -%DIF ------- -\setlength{\textwidth}{6in} %DIF > -%DIF ------- - -\title{latexdiff Example - \DIFdelbegin \DIFdel{Draft }\DIFdelend \DIFaddbegin \DIFadd{Revised }\DIFaddend version} -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even %DIF > -% if some preamble might eventually end up as visible text.) %DIF > -%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF -%DIF UNDERLINE PREAMBLE %DIF PREAMBLE -\RequirePackage[normalem]{ulem} %DIF PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} %DIF PREAMBLE -\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}} %DIF PREAMBLE -\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}} %DIF PREAMBLE -%DIF SAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddbegin}{} %DIF PREAMBLE -\providecommand{\DIFaddend}{} %DIF PREAMBLE -\providecommand{\DIFdelbegin}{} %DIF PREAMBLE -\providecommand{\DIFdelend}{} %DIF PREAMBLE -%DIF FLOATSAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} %DIF PREAMBLE -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} %DIF PREAMBLE -\providecommand{\DIFaddbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFaddendFL}{} %DIF PREAMBLE -\providecommand{\DIFdelbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFdelendFL}{} %DIF PREAMBLE -%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of \DIFaddbegin \DIFadd{the }\DIFaddend latexdiff features. -Type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -or -\begin{verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{verbatim} -to display the markup. - -\section*{\DIFdelbegin \DIFdel{Another }\DIFdelend \DIFaddbegin \DIFadd{Yet another }\DIFaddend section title} - - \DIFdelbegin \DIFdel{A paragraph with a line only in the draft document. }\DIFdelend More things could be said were it not for the constraints of time and space. - -\DIFaddbegin \DIFadd{A paragraph with a line only in the revised document. }\DIFaddend More things could be -said were it not for the constraints of time and space. - -And here is a \DIFdelbegin \DIFdel{tipo}\DIFdelend \DIFaddbegin \DIFadd{typo}\DIFaddend . - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & \DIFdelbegin \DIFdel{Grey }\DIFdelend \DIFaddbegin \DIFadd{White }\DIFaddend \\ -Saruman & \DIFdelbegin \DIFdel{White -}\DIFdelend \DIFaddbegin \DIFadd{Evil -}\DIFaddend \end{tabular} - -And \DIFdelbegin \DIFdel{sometimes a whole paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}\DIFdelend \DIFaddbegin \DIFadd{now for something completely different, with not a paragraph in sight}\DIFaddend . -No change, -no markup! -\end{document} - - diff --git a/latexdiff-1.0.4/doc/latexdiff-man.pdf b/latexdiff-1.0.4/doc/latexdiff-man.pdf deleted file mode 100644 index a3d640adfe2d4ad29e63e2918dccda9a83d7d045..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 261188 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

w5oU>LYHJw&S7Swye33)xfAmZ)=GBw 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 PMd&8MV6MKOkjWXFY$K`Oe4O#ArZB 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 S4jwixE>0wBYAKL3(tiP50o!B% diff --git a/latexdiff-1.0.4/doc/latexdiff-man.tex b/latexdiff-1.0.4/doc/latexdiff-man.tex deleted file mode 100644 index b6bb37e..0000000 --- a/latexdiff-1.0.4/doc/latexdiff-man.tex +++ /dev/null @@ -1,355 +0,0 @@ -\documentclass[a4]{article} -\usepackage{graphicx} -%\def\C++{{\rm C\kern-.05em\raise.3ex\hbox{\footnotesize ++}}} -%\def\underscore{\leavevmode\kern.04em\vbox{\hrule width 0.4em height 0.3pt}} -\setlength{\parindent}{0pt} -%\setlength{\textwidth}{6.5in} -%\setlength{\oddsidemargin}{0.0in} -\title{Marking up differences between latex files with {\em latexdiff}} -\author{F.J. Tilmann\thanks{tilmann@gfz-potsdam.de,ftilmann@users.berlios.de}} -\date{\today} - -\begin{document} -\maketitle - -\section*{Preamble} - -{\em latexdiff} is a Perl script, which compares two -latex files and marks up significant differences between them. Various options are available for visual markup using standard -latex packages such as {\em color.sty}. Changes not directly affecting visible -text, for example in formatting commands, are still marked in the -latex source. - -A rudimentary revision facilility is provided by another Perl script, -{\em latexrevise}, which accepts or rejects all changes. Manual editing -of the difference file can be used to override this default behaviour -and accept or reject selected changes only. - -There is no explicit support for annotations as these are trivial to implement. -For example, I include the following command definition in the preamble -\begin{verbatim} -\newcommand{\remark}[1]{{ \bf [ \footnotesize #1 ]}} -\end{verbatim} -and mark up annotations as follows -\begin{verbatim} -... The roadrunner is the fastest running bird \remark{Check this -again with a zoologist!}. The most famous roadrunner ... -\end{verbatim} -Alternatively, instead of a command like \verb#\remark# in the example just given, an -equivalent annotation environment could be defined. -{\em latexrevise} can remove such comments or -environments from the text body. - -%It is planned that the revision capabilities of this system will be -%further expanded, dependent on the amount of feedback received. - -On the following pages you find the {\em man} pages for {\em - latexdiff} and {\em latexrevise} and a simple example. - -\include{latexdiff} -\setcounter{section}{0} - -\include{latexrevise} -\setcounter{section}{0} - -\include{latexdiff-vc} -\setcounter{section}{0} - -\section*{A simple example} - -We start with a draft text, \verb|example-draft.tex|, listed here in -full but also included in the distribution (except that the ``verbatim'' environment had -to be renamed to ``Verbatim'' for the listing). - -{\scriptsize -\begin{verbatim} -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6.5in} - -\title{latexdiff Example - Draft version} -\author{F Tilmann} - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of latexdiff features. -Type -\begin{Verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{Verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{Verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{Verbatim} -or -\begin{Verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{Verbatim} -to display the markup. Of course, instead of \verb|xpdf| you can use -\verb|okular, evince, acroread| or any other pdf or postscript viewer. - -\section*{Another section title} - -A paragraph with a line only in the draft document. More things -could be said were it not for the constraints of time and space. - -More things could be said were it not for the constraints of time and space. - -And here is a tipo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & Grey \\ -Saruman & White -\end{tabular} - -And sometimes a whole paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical. -No change, no markup! -\end{document} -\end{verbatim} -} - -We can now edit -this text as we would do with any other latex file to create -a new revision of the text, \verb|example-rev.tex|. We should run -\begin{verbatim} -latex example-rev.tex -\end{verbatim} -and look at the resulting \verb|.dvi| file to make sure that all -changes are valid. An example revision is listed here: - -{\scriptsize -\begin{verbatim} -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6in} - -\title{latexdiff Example - Revised version} -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even -% if some preamble might eventually end up as visible text.) - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of the latexdiff features. -Type -\begin{Verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{Verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{Verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{Verbatim} -or -\begin{Verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{Verbatim} -to display the markup. - -\section*{Yet another section title} - - More things could be said were it not for the constraints of time and space. - -A paragraph with a line only in the revised document. -More things could be said were it not for the constraints of time and space. - -And here is a typo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & White \\ -Saruman & Evil -\end{tabular} - -And now for something completely different, with not a paragraph in sight. -No change, -no markup! -\end{document} -\end{verbatim} -} - -To compare both revisions, type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -This results in the following difference file (a few newlines have been -added in this listing for legibility reasosn): -{\scriptsize -\begin{verbatim} -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -%DIF 7c7 -%DIF < \setlength{\textwidth}{6.5in} -%DIF ------- -\setlength{\textwidth}{6in} %DIF > -%DIF ------- - -%DIF 9c9 -%DIF < \title{latexdiff Example - Draft version} -%DIF ------- -\title{latexdiff Example - Revised version} %DIF > -%DIF ------- -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even %DIF > -% if some preamble might eventually end up as visible text.) %DIF > -%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF -%DIF UNDERLINE PREAMBLE %DIF PREAMBLE -\RequirePackage[normalem]{ulem} %DIF PREAMBLE -\RequirePackage{color} %DIF PREAMBLE -\providecommand{\DIFadd}[1]{{\color{blue}\uline{#1}}} %DIF PREAMBLE -\providecommand{\DIFdel}[1]{{\color{red}\sout{#1}}} %DIF PREAMBLE -%DIF SAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddbegin}{} %DIF PREAMBLE -\providecommand{\DIFaddend}{} %DIF PREAMBLE -\providecommand{\DIFdelbegin}{} %DIF PREAMBLE -\providecommand{\DIFdelend}{} %DIF PREAMBLE -%DIF FLOATSAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} %DIF PREAMBLE -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} %DIF PREAMBLE -\providecommand{\DIFaddbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFaddendFL}{} %DIF PREAMBLE -\providecommand{\DIFdelbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFdelendFL}{} %DIF PREAMBLE -%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of latexdiff features. -Type -\begin{Verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{Verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{Verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{Verbatim} -or -\begin{Verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{Verbatim} -to display the markup. - -\section*{\DIFaddbegin \DIFadd{Yet another }\DIFaddend \DIFdelbegin -\DIFdel{Another }\DIFdelend section title} - - \DIFdelbegin \DIFdel{A paragraph with a line only in the draft - document. }\DIFdelend More things could - be said were it not for the constraints of time and space. - -\DIFaddbegin \DIFadd{A paragraph with a line only in the revised - document. }\DIFaddend More things could be said -were it not for the constraints of time and space. - -And here is a \DIFaddbegin \DIFadd{typo}\DIFaddend \DIFdelbegin -\DIFdel{tipo}\DIFdelend . - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & \DIFaddbegin \DIFadd{White }\DIFaddend \DIFdelbegin -\DIFdel{Grey }\DIFdelend \\ -Saruman & \DIFaddbegin \DIFadd{Evil -}\DIFaddend \DIFdelbegin \DIFdel{White -}\DIFdelend \end{tabular} - -And \DIFaddbegin \DIFadd{now for something completely different, with not - a paragraph in sight}\DIFaddend \DIFdelbegin \DIFdel{sometimes a whole - paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}\DIFdelend . -No change, -no markup! -\end{document} -\end{verbatim} -} -Type -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -to make the markup visible. This is what it looks like: - -\vspace{1cm} -\framebox[\textwidth]{\includegraphics[width=\textwidth]{example-diff}} -\vspace{1cm} - -If you approve of all the changes in the revision, just continue with -\verb|example-rev.tex| for the next revision. If you like to adopt -most but not all changes you can use \verb|latexrevise| in the -following manner. Simply remove the \verb|\DIFdelbegin| and -\verb|\DIFdelend| tags around the text you would like to keep and -simply remove the text between \verb|\DIFaddbegin| and -\verb|\DIFaddend| tags, if you do not wish to keep them. Say you are happy with all proposed changes for the -example above except in -the last paragraph where you prefer the original draft. You have -to change - -{\scriptsize -\begin{verbatim} -... -And \DIFaddbegin \DIFadd{now for something completely different, with not - a paragraph in sight}\DIFaddend \DIFdelbegin \DIFdel{sometimes a whole - paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}\DIFdelend . -... -\end{verbatim} -} -into -{\scriptsize -\begin{verbatim} -... -And \DIFdel{sometimes a whole - paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}. -... -\end{verbatim} -} -and run -\begin{verbatim} -latexrevise -a example-rev.tex > example-final.tex -\end{verbatim} -\verb|example-final.tex| is then almost identical to -\verb|example-rev.tex| except for the last paragraph. -\end{document} diff --git a/latexdiff-1.0.4/example/example-draft.tex b/latexdiff-1.0.4/example/example-draft.tex deleted file mode 100644 index 593a170..0000000 --- a/latexdiff-1.0.4/example/example-draft.tex +++ /dev/null @@ -1,59 +0,0 @@ -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6.5in} - -\title{latexdiff Example - Draft version} -\author{F Tilmann} - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of latexdiff features. -Type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -or -\begin{verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{verbatim} -to display the markup. - -\section*{Another section title} - -A paragraph with a line only in the draft document. More things could be said -were it not for the constraints of time and space. - -More things could be said were it not for the constraints of time and space. - -And here is a tipo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & Grey \\ -Saruman & White -\end{tabular} - -And sometimes a whole paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical. -No change, no markup! -\end{document} - - diff --git a/latexdiff-1.0.4/example/example-rev.tex b/latexdiff-1.0.4/example/example-rev.tex deleted file mode 100644 index 4bcaf15..0000000 --- a/latexdiff-1.0.4/example/example-rev.tex +++ /dev/null @@ -1,60 +0,0 @@ -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6in} - -\title{latexdiff Example - Revised version} -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even -% if some preamble might eventually end up as visible text.) - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of the latexdiff features. -Type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -or -\begin{verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{verbatim} -to display the markup. - -\section*{Yet another section title} - - More things could be said were it not for the constraints of time and space. - -A paragraph with a line only in the revised document. More things could be -said were it not for the constraints of time and space. - -And here is a typo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & White \\ -Saruman & Evil -\end{tabular} - -And now for something completely different, with not a paragraph in sight. -No change, -no markup! -\end{document} - - diff --git a/latexdiff-1.0.4/latexdiff b/latexdiff-1.0.4/latexdiff deleted file mode 100755 index 717a093..0000000 --- a/latexdiff-1.0.4/latexdiff +++ /dev/null @@ -1,3540 +0,0 @@ -#!/usr/bin/env perl -##!/usr/bin/perl -w -# latexdiff - differences two latex files on the word level -# and produces a latex file with the differences marked up. -# -# Copyright (C) 2004-12 F J Tilmann (tilmann@gfz-potsdam.de) -# -# Repository/issue tracker: https://github.com/ftilmann/latexdiff -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# -# ToDo: -# -# Version 1.0.4 -# - introduce list UNSAFEMATHCMD, which holds list of commands which cannot be marked up with \DIFadd or \DIFdel commands (only relevant for WHOLE and COARSE math markup modes) -# - new subtype LABEL which gives each change a label. This can later be used to only display pages where changes -# have been made (instructions for that are put as comments into the diff'ed file) inspired by answer on http://tex.stackexchange.com/questions/166049/invisible-markers-in-pdfs-using-pdflatex -# - Configuration variables take into accout some commands from additional packages: -# tikzpicture environment now treated as PICTUREENV, and \smallmatrix in ARRENV (amsmath) -# - --flatten: support for \subfile command (subfiles package) (in response to http://tex.stackexchange.com/questions/167620/latexdiff-with-subfiles ) -# - --flatten: \bibliography commands expand if corresponding bbl file present -# - angled bracket optional commands now parsed correctly (patch #3570) submitted by Dave Kleinschmidt (thanks) -# - \RequirePackage now treated as synonym of \usepackage with respect to setting packages -# - special rules for apacite package (redefine citation commands) -# - recognise /dev/null as 'file-like' arguments for --preamble and --config options -# - fix units package incompatibility with ulem for text maths statements $ ..$ (thanks to Stuart Prescott for reporting this) -# - amsmath environment cases treated correctly (Bug fix #19029) (thanks to Jalar) -# - {,} in comments no longer confuse latexdiff (Bug fix #19146) -# - \% in one-letter sub/Superscripts was not converted correctly -# -# Version 1.0.3 -# - fix bug in add_safe_commands that made latexdiff hang on DeclareMathOperator -# command in preamble -# - \(..\) inline math expressions were not parsed correctly, if they contained a linebreak -# - applied patch contributed by tomflannaghan via Berlios: [ Patch #3431 ] Adds correct handling of \left< and \right> -# - \$ is treated correctly as a literal dollar sign (thanks to Reed Cartwright and Joshua Miller for reporting this bug -# and sketching out the solution) -# - \^ and \_ are correctly interpreted as accent and underlined space, respectively, not as superscript of subscript -# (thanks to Wail Yahyaoui for pointing out this bug) -# -# Version 1.0.1 - treat \big,\bigg etc. equivalently to \left and -# \right - include starred version in MATHENV - apply -# - flatten recursively and --flatten expansion is now -# aware of comments (thanks to Tim Connors for patch) -# - Change to post-processing for more reliability for -# deleted math environments -# - On linux systems, recognise and remove DOS style newlines -# - Provide markup for some special preamble commands (\title, -# \author,\date, -# - configurable by setting context2cmd -# - for styles using ulem package, remove \emph and \text.. from list of -# safe commands in order to allow linebreaks within the -# highlighted sections. -# - for ulem style, now show citations by enclosing them in \mbox commands. -# This unfortunately implies linebreaks within citations no longer function, -# so this functionality can be turned off (Option --disable-citation-markup). -# With --enable-citation-markup, the mbox markup is forced for other styles) -# - new substyle COLOR. This is particularly useful for marking up citations -# and some special post-processing is implemented to retain cite -# commands in deleted blocks. -# - four different levels of math-markup -# - Option --driver for choosing driver for modes employing changebar package -# - accept \\* as valid command (and other commands of form \.*). Also accept -# \ (backslashed newline) -# - some typo fixes, include commands defined in preamble as safe commands -# (Sebastian Gouezel) -# - include compared filenames as comments as line 2 and 3 of -# the preamble (can be modified with option --label, and suppressed with -# --no-label), option --visible-label to show files in generated pdf or dvi -# at the beginning of main document -# -# Version 0.5 A number of minor improvements based on feedback -# Deleted blocks are now shown before added blocks -# Package specific processing -# -# Version 0.43 unreleased typo in list of styles at the end -# Add protect to all \cbstart, \cbend commands -# More robust substitution of deleted math commands -# -# Version 0.42 November 06 Bug fixes only -# -# Version 0.4 March 06 option for fast differencing using UNIX diff command, several minor bug fixes (\par bug, improved highlighting of textcmds) -# -# Version 0.3 August 05 improved parsing of displayed math, --allow-spaces -# option, several minor bug fixes -# -# Version 0.25 October 04 Fix bug with deleted equations, add math mode commands to safecmd, add | to allowed interpunctuation signs -# Version 0.2 September 04 extension to utf-8 and variable encodings -# Version 0.1 August 04 First public release - -use Algorithm::Diff qw(traverse_sequences); - -use Getopt::Long ; -use strict ; -use warnings; -use utf8 ; - -my ($algodiffversion)=split(/ /,$Algorithm::Diff::VERSION); - - -my ($versionstring)=< 0, - WHOLE => 1, - COARSE => 2, - FINE => 3 -}; - - -my (@configlist,@labels, - @appendsafelist,@excludesafelist, - @appendtextlist,@excludetextlist, - @appendcontext1list,@appendcontext2list, - @packagelist); -my ($assign,@config); -# Hash where keys corresponds to the names of all included packages (including the documentclass as another package -# the optional arguments to the package are the values of the hash elements -my ($pkg,%packages); -# Defaults -$type='UNDERLINE'; -$subtype='SAFE'; -$floattype='FLOATSAFE'; -$mathmarkup=COARSE; - -$verbose=0; -# output debug and intermediate files, set to 0 in final distribution -$debug=0; -# insert preamble directly after documentclass - experimental feature, set to 0 in final distribution -# Note that this failed with mini example (or other files, where packages used in latexdiff preamble -# are called again with incompatible options in preamble of resulting file) -$earlylatexdiffpreamble=0; - -# define character properties -sub IsNonAsciiPunct { return <<'END' # Unicode punctuation but excluding ASCII punctuation -+utf8::IsPunct --utf8::IsASCII -END -} -sub IsNonAsciiS { return <<'END' # Unicode symbol but excluding ASCII -+utf8::IsS --utf8::IsASCII -END -} - - -my %verbhash; - -Getopt::Long::Configure('bundling'); -GetOptions('type|t=s' => \$type, - 'subtype|s=s' => \$subtype, - 'floattype|f=s' => \$floattype, - 'config|c=s' => \@configlist, - 'preamble|p=s' => \$preamblefile, - 'encoding|e=s' => \$encoding, - 'label|L=s' => \@labels, - 'no-label' => \$nolabel, - 'visible-label' => \$visiblelabel, - 'exclude-safecmd|A=s' => \@excludesafelist, - 'replace-safecmd=s' => \$replacesafe, - 'append-safecmd|a=s' => \@appendsafelist, - 'exclude-textcmd|X=s' => \@excludetextlist, - 'replace-textcmd=s' => \$replacetext, - 'append-textcmd|x=s' => \@appendtextlist, - 'replace-context1cmd=s' => \$replacecontext1, - 'append-context1cmd=s' => \@appendcontext1list, - 'replace-context2cmd=s' => \$replacecontext2, - 'append-context2cmd=s' => \@appendcontext2list, - 'show-preamble' => \$showpreamble, - 'show-safecmd' => \$showsafe, - 'show-textcmd' => \$showtext, - 'show-config' => \$showconfig, - 'show-all' => \$showall, - 'packages=s' => \@packagelist, - 'allow-spaces' => \$allowspaces, - 'math-markup=s' => \$mathmarkup, - 'enable-citation-markup' => \$enablecitmark, - 'disable-citation-markup' => \$disablecitmark, - 'verbose|V' => \$verbose, - 'ignore-warnings' => \$ignorewarnings, - 'driver=s'=> \$driver, - 'flatten' => \$flatten, - 'version' => \$version, - 'help|h|H' => \$help); - -if ( $help ) { - usage() ; -} - - -if ( $version ) { - die $versionstring ; -} - -print STDERR $versionstring if $verbose; - -if (defined($showall)){ - $showpreamble=$showsafe=$showtext=$showconfig=1; -} - -if (defined($mathmarkup)) { - $mathmarkup=~tr/a-z/A-Z/; - if ( $mathmarkup eq 'OFF' ){ - $mathmarkup=OFF; - } elsif ( $mathmarkup eq 'WHOLE' ){ - $mathmarkup=WHOLE; - } elsif ( $mathmarkup eq 'COARSE' ){ - $mathmarkup=COARSE; - } elsif ( $mathmarkup eq 'FINE' ){ - $mathmarkup=FINE; - } elsif ( $mathmarkup !~ m/^[0123]$/ ) { - die "Illegal value: ($mathmarkup) for option--math-markup. Possible values: OFF,WHOLE,COARSE,FINE,0- "; - } - # else use numerical value -} - -# setting extra preamble commands -if (defined($preamblefile)) { - $latexdiffpreamble=join "\n",(extrapream($preamblefile),""); -} else { - $latexdiffpreamble=join "\n",(extrapream($type,$subtype,$floattype),""); -} - -if ( defined($driver) ) { - # for changebar only - $latexdiffpreamble=~s/\[dvips\]/[$driver]/sg; -} -# setting up @SAFECMDLIST and @SAFECMDEXCL -if (defined($replacesafe)) { - init_regex_arr_ext(\@SAFECMDLIST,$replacesafe); -} else { - init_regex_arr_data(\@SAFECMDLIST, "SAFE COMMANDS"); -} -foreach $appendsafe ( @appendsafelist ) { - init_regex_arr_ext(\@SAFECMDLIST, $appendsafe); -} -foreach $excludesafe ( @excludesafelist ) { - init_regex_arr_ext(\@SAFECMDEXCL, $excludesafe); -} - -# setting up @TEXTCMDLIST and @TEXTCMDEXCL -if (defined($replacetext)) { - init_regex_arr_ext(\@TEXTCMDLIST,$replacetext); -} else { - init_regex_arr_data(\@TEXTCMDLIST, "TEXT COMMANDS"); -} -foreach $appendtext ( @appendtextlist ) { - init_regex_arr_ext(\@TEXTCMDLIST, $appendtext); -} -foreach $excludetext ( @excludetextlist ) { - init_regex_arr_ext(\@TEXTCMDEXCL, $excludetext); -} - - -# setting up @CONTEXT1CMDLIST ( @CONTEXT1CMDEXCL exist but is always empty ) -if (defined($replacecontext1)) { - init_regex_arr_ext(\@CONTEXT1CMDLIST,$replacecontext1); -} else { - init_regex_arr_data(\@CONTEXT1CMDLIST, "CONTEXT1 COMMANDS"); -} -foreach $appendcontext1 ( @appendcontext1list ) { - init_regex_arr_ext(\@CONTEXT1CMDLIST, $appendcontext1); -} - - -# setting up @CONTEXT2CMDLIST ( @CONTEXT2CMDEXCL exist but is always empty ) -if (defined($replacecontext2)) { - init_regex_arr_ext(\@CONTEXT2CMDLIST,$replacecontext2); -} else { - init_regex_arr_data(\@CONTEXT2CMDLIST, "CONTEXT2 COMMANDS"); -} -foreach $appendcontext2 ( @appendcontext2list ) { - init_regex_arr_ext(\@CONTEXT2CMDLIST, $appendcontext2); -} - -# setting configuration variables -@config=(); -foreach $config ( @configlist ) { - if (-f $config || lc $config eq '/dev/null' ) { - open(FILE,$config) or die ("Couldn't open configuration file $config: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@config,$_); - } - close(FILE); - } - else { -# foreach ( split(",",$config) ) { -# push @config,$_; -# } - push @config,split(",",$config) - } -} -foreach $assign ( @config ) { - $assign=~ m/\s*(\w*)\s*=\s*(\S*)\s*$/ or die "Illegal assignment $assign in configuration list (must be variable=value)"; - if ( $1 eq "MINWORDSBLOCK" ) { $MINWORDSBLOCK = $2; } - elsif ( $1 eq "FLOATENV" ) { $FLOATENV = $2 ; } - elsif ( $1 eq "PICTUREENV" ) { $PICTUREENV = $2 ; } - elsif ( $1 eq "MATHENV" ) { $MATHENV = $2 ; } - elsif ( $1 eq "MATHREPL" ) { $MATHREPL = $2 ; } - elsif ( $1 eq "MATHARRENV" ) { $MATHARRENV = $2 ; } - elsif ( $1 eq "MATHARRREPL" ) { $MATHARRREPL = $2 ; } - elsif ( $1 eq "ARRENV" ) { $ARRENV = $2 ; } - elsif ( $1 eq "COUNTERCMD" ) { $COUNTERCMD = $2 ; } - else { die "Unknown variable $1 in assignment.";} -} - -if ( $mathmarkup == COARSE || $mathmarkup == WHOLE ) { - push(@MATHTEXTCMDLIST,qr/^MATHBLOCK(?:$MATHENV|$MATHARRENV|SQUAREBRACKET)$/); -} - - - -foreach $pkg ( @packagelist ) { - map { $packages{$_}="" } split(/,/,$pkg) ; -} - -if ($showpreamble) { - print "\nPreamble commands:\n"; - print $latexdiffpreamble ; -} - -if ($showsafe) { - print "\nCommands safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE (unless excluded):\n"; - print_regex_arr(@SAFECMDLIST); - print "\nCommands not safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE :\n"; - print_regex_arr(@SAFECMDEXCL); -} - -if ($showtext) { - print "\nCommands with last argument textual (unless excluded) and safe in every context:\n"; - print_regex_arr(@TEXTCMDLIST); - print "\nContext1 commands (last argument textual, command will be disabled in deleted passages, last argument will be shown as plain text):\n"; - print_regex_arr(@CONTEXT1CMDLIST); - print "\nContext2 commands (last argument textual, command and its argument will be disabled in deleted passages):\n"; - print_regex_arr(@CONTEXT2CMDLIST); - print "\nExclude list of Commands with last argument not textual (overrides patterns above):\n"; - print_regex_arr(@TEXTCMDEXCL); -} - - -if ($showconfig) { - print "Configuration variables:\n"; - print "MINWORDSBLOCK=$MINWORDSBLOCK\n"; - print "FLOATENV=$FLOATENV\n"; - print "PICTUREENV=$PICTUREENV\n"; - print "MATHENV=$MATHENV\n"; - print "MATHREPL=$MATHREPL\n"; - print "MATHARRENV=$MATHARRENV\n"; - print "MATHARRREPL=$MATHARRREPL\n"; - print "ARRENV=$ARRENV\n"; - print "COUNTERCMD=$COUNTERCMD\n"; -} -if ($showconfig || $showtext || $showsafe || $showpreamble) { - exit 0; } -if ( @ARGV != 2 ) { - print STDERR "2 and only 2 non-option arguments required. Write latexdiff -h to get help\n"; - exit(2); -} - -# Are extra spaces between command arguments permissible? -my $extraspace; -if ($allowspaces) { - $extraspace='\s*'; -} else { - $extraspace=''; -} - -# append context lists to text lists (as text property is implied) -push @TEXTCMDLIST, @CONTEXT1CMDLIST; -push @TEXTCMDLIST, @CONTEXT2CMDLIST; - -push @TEXTCMDLIST, @MATHTEXTCMDLIST if $mathmarkup==COARSE; - -# internal additions to SAFECMDLIST -push(@SAFECMDLIST, qr/^QLEFTBRACE$/, qr/^QRIGHTBRACE$/); - - -# Patterns. These are used by some of the subroutines, too -# I can only define them down here because value of extraspace depends on an option - my $pat0 = '(?:[^{}])*'; - my $pat1 = '(?:[^{}]|\{'.$pat0.'\})*'; - my $pat2 = '(?:[^{}]|\{'.$pat1.'\})*'; - my $pat3 = '(?:[^{}]|\{'.$pat2.'\})*'; - my $pat4 = '(?:[^{}]|\{'.$pat3.'\})*'; - my $pat5 = '(?:[^{}]|\{'.$pat4.'\})*'; - my $pat6 = '(?:[^{}]|\{'.$pat5.'\})*'; - my $brat0 = '(?:[^\[\]]|\\\[|\\\])*'; - my $abrat0 = '(?:[^<>])*'; - - my $quotemarks = '(?:\'\')|(?:\`\`)'; - my $punct='[0.,\/\'\`:;\"\?\(\)\[\]!~\p{IsNonAsciiPunct}\p{IsNonAsciiS}]'; - my $number='-?\d*\.\d*'; - my $mathpunct='[+=<>\-\|]'; - my $and = '&'; - my $coords= '[\-.,\s\d]*'; -# word: sequence of letters or accents followed by letter - my $word='(?:[-\w\d*]|\\\\[\"\'\`~^][A-Za-z\*])+'; - my $cmdleftright='\\\\(?:left|right|[Bb]igg?[lrm]?|middle)\s*(?:[<>()\[\]|]|\\\\(?:[|{}]|\w+))'; - - my $cmdoptseq='\\\\[\w\d\*]+'.$extraspace.'(?:(?:<'.$abrat0.'>|\['.$brat0.'\]|\{'. $pat6 . '\}|\(' . $coords .'\))'.$extraspace.')*'; - my $backslashnl='\\\\\n'; - my $oneletcmd='\\\\.\*?(?:\['.$brat0.'\]|\{'. $pat6 . '\})*'; - my $math='\$(?:[^$]|\\\$)*?\$|\\\\[(](?:.|\n)*?\\\\[)]'; -## the current maths command cannot cope with newline within the math expression - - my $comment='%.*?\n'; - my $pat=qr/(?:\A\s*)?(?:${and}|${quotemarks}|${number}|${word}|$cmdleftright|${cmdoptseq}|${math}|${backslashnl}|${oneletcmd}|${comment}|${punct}|${mathpunct}|\{|\})\s*/ ; - -# now we are done setting up and can start working -my ($oldfile, $newfile) = @ARGV; -# check for existence of input files -if ( ! -e $oldfile ) { - die "Input file $oldfile does not exist."; -} -if ( ! -e $newfile ) { - die "Input file $newfile does not exist."; -} - - -# set the labels to be included into the file -my ($oldtime,$newtime,$oldlabel,$newlabel); -if (defined($labels[0])) { - $oldlabel=$labels[0] ; -} else { - $oldtime=localtime((stat($oldfile))[9]); - $oldlabel="$oldfile " . " "x(length($newfile)-length($oldfile)) . $oldtime; -} -if (defined($labels[1])) { - $newlabel=$labels[1] ; -} else { - $newtime=localtime((stat($newfile))[9]); - $newlabel="$newfile " . " "x(length($oldfile)-length($newfile)) . $newtime; -} - -$encoding=guess_encoding($newfile) unless defined($encoding); - -$encoding = "utf8" if $encoding =~ m/^utf8/i ; -if (lc($encoding) eq "utf8" ) { - binmode(STDOUT, ":utf8"); - binmode(STDERR, ":utf8"); -} - -$old=read_file_with_encoding($oldfile,$encoding); -$new=read_file_with_encoding($newfile,$encoding); - - - - -# reset time -exetime(1); -($oldpreamble,$oldbody,$oldpost)=splitdoc($old,'\\\\begin\{document\}','\\\\end\{document\}'); - - -($newpreamble,$newbody,$newpost)=splitdoc($new,'\\\\begin\{document\}','\\\\end\{document\}'); - - -if ($flatten) { - $oldbody=flatten($oldbody,$oldpreamble,$oldfile,$encoding); - $newbody=flatten($newbody,$newpreamble,$newfile,$encoding); -} - - - - -my @auxlines; -if ( length $oldpreamble && length $newpreamble ) { - # pre-process preamble by looking for commands used in \maketitle (title, author, date etc commands) - # and marking up content with latexdiff markup - @auxlines=preprocess_preamble($oldpreamble,$newpreamble); - - @oldpreamble = split /\n/, $oldpreamble; - @newpreamble = split /\n/, $newpreamble; - - # If a command is defined in the preamble of the new file, and only uses safe commands, then it can be considered to be safe) (contribution S. Gouezel) - # Base this assessment on the new preamble - add_safe_commands($newpreamble); - - # get a list of packages from preamble if not predefine - %packages=list_packages(@newpreamble) unless %packages; - ### if ( %packages ) {print STDERR "DEBUG Packages: ",%packages,"\n" ;} - if (defined $packages{"hyperref"} ) { - # deleted lines should not generate or appear in link names: - print STDERR "hyperref package detected.\n" if $verbose ; - $latexdiffpreamble =~ s/\{\\DIFadd\}/{\\DIFaddtex}/g; - $latexdiffpreamble =~ s/\{\\DIFdel\}/{\\DIFdeltex}/g; - $latexdiffpreamble .= join "\n",(extrapream("HYPERREF"),""); - } - - if (defined $packages{"units"} && ( $latexdiffpreamble =~ /\\RequirePackage(?:\[$brat0\])?\{ulem\}/ ) ) { - # protect inlined maths environments by surrounding with an \mbox - # this is done to get around an incompatibility between the ulem and units package - # where spaces in the argument to underlined or crossed-out \unit commands cause an error message - print STDERR "units package detected at the same time as style using ulem.\n" if $verbose ; - $MBOXINLINEMATH=1; - } - - print STDERR "Differencing preamble.\n" if $verbose; - - # insert dummy first line such that line count begins with line 1 (rather than perl's line 0) - just so that line numbers inserted by linediff are correct - unshift @newpreamble,''; - unshift @oldpreamble,''; - @diffpreamble = linediff(\@oldpreamble, \@newpreamble); - # remove dummy line again - shift @diffpreamble; - # add filenames, modification time and latexdiff mark - defined($nolabel) or splice @diffpreamble,1,0, - "%DIF LATEXDIFF DIFFERENCE FILE", - ,"%DIF DEL $oldlabel", - "%DIF ADD $newlabel"; - if ( @auxlines ) { - push @diffpreamble,"%DIF DELETED TITLE COMMANDS FOR MARKUP"; - push @diffpreamble,join("\n",@auxlines); - } - if ( $earlylatexdiffpreamble) { - # insert latexdiff command directly after documentclass at beginning of preamble - # note that grep is only run for its side effect - ( grep { s/^([^%]*\\documentclass.*)$/$1$latexdiffpreamble/ } @diffpreamble )==1 or die "Could not find documentclass statement in preamble"; - } else { - # insert latexdiff commands at the end of preamble (default behaviour) - push @diffpreamble,$latexdiffpreamble; - } - push @diffpreamble,'\begin{document}'; -} -elsif ( !length $oldpreamble && !length $newpreamble ) { - @diffpreamble=(); -} else { - print STDERR "Either both texts must have preamble or neither text must have the preamble.\n"; - exit(2); -} - -# Special: treat all cite commands as safe except in UNDERLINE and FONTSTRIKE mode -# (there is a conflict between citation and ulem package, see -# package documentation) -# Use post-processing -# and $packages{"apacite"}!~/natbibpapa/ -my ($citpat,$citpatsafe); - -if ( defined $packages{"apacite"} ) { - print STDERR "DEBUG apacite citation commands\n" if $debug; - $citpatsafe=qr/^(?:mask)?(?:full|short)?cite(?:A|author|year)?(?:NP)?$/; - $citpat='(?:mask)?(?:full|short|no)?cite(?:A|author|year|meta)?(?:NP)?'; -} else { - # citation command pattern for all other citation schemes - $citpatsafe=qr/^cite.*$/; - $citpat='(?:cite\w*|nocite)'; -}; - -if ( uc($type) ne "UNDERLINE" && uc($type) ne "FONTSTRIKE" && uc($type) ne "CULINECHBAR" ) { - push (@SAFECMDLIST, $citpatsafe); -} else { - ### Experimental: disable text and emph commands - push (@SAFECMDLIST, $citpatsafe) unless $disablecitmark; - push(@SAFECMDEXCL, qr/^emph$/, qr/^text..$/); - # replace \cite{..} by \mbox{\cite{..}} in added or deleted blocks in post-processing - if ( uc($subtype) eq "COLOR" or uc($subtype) eq "DVIPSCOL" ) { - # remove \cite command again from list of safe commands - pop @SAFECMDLIST; - # deleted cite commands - $CITE2CMD=$citpat unless $disablecitmark ; # \cite-type commands which should be reinstated in deleted blocks - } else { - $CITECMD=$citpat unless $disablecitmark ; # \cite commands which need to be protected within an mbox in UNDERLINE and other modes using ulem - } -} -$CITECMD=$citpat if $enablecitmark ; # as above for explicit selection - -print STDERR "CITECMD:|$CITECMD|\n" if $debug; - -if (defined $packages{"amsmath"} or defined $packages{"amsart"} or defined $packages{"amsbook"} ) { - print STDERR "amsmath package detected.\n" if $verbose ; - $MATHARRREPL='align*'; -} - -print STDERR "Preprocessing body. " if $verbose; -my ($oldleadin,$newleadin)=preprocess($oldbody,$newbody); - - -# run difference algorithm -@diffbody=bodydiff($oldbody, $newbody); -$diffbo=join("",@diffbody); -if ( $debug ) { - open(RAWDIFF,">","latexdiff.debug.bodydiff"); - print RAWDIFF $diffbo; - close(RAWDIFF); -} -print STDERR "(",exetime()," s)\n","Postprocessing body. \n " if $verbose; -postprocess($diffbo); -$diffall =join("\n",@diffpreamble) ; -# add visible labels -if (defined($visiblelabel)) { - # Give information right after \begin{document} (or at the beginning of the text for files without preamble - ### if \date command is used, add information to \date argument, otherwise give right after \begin{document} - ### $diffall=~s/(\\date$extraspace(?:\[$brat0\])?$extraspace)\{($pat6)\}/$1\{$2 \\ LATEXDIFF comparison \\ Old: $oldlabel \\ New: $newlabel \}/ or - $diffbo = "\\begin{verbatim}LATEXDIFF comparison\nOld: $oldlabel\nNew: $newlabel\\end{verbatim}\n$diffbo" ; -} - -$diffall .= "$newleadin$diffbo" ; -$diffall .= "\\end{document}$newpost" if length $newpreamble ; -if ( lc($encoding) ne "utf8" && lc($encoding) ne "ascii" ) { - print STDERR "Encoding output file to $encoding\n" if $verbose; - $diffall=Encode::encode($encoding,$diffall); - binmode STDOUT; -} -print $diffall; - - -print STDERR "(",exetime()," s)\n","Done.\n" if $verbose; - - - -## guess_encoding(filename) -## reads the first 20 lines of filename and looks for call of inputenc package -## if found, return the option of this package (encoding), otherwise return ascii -sub guess_encoding { - my ($filename)=@_; - my ($i,$enc); - open (FH, $filename) or die("Couldn't open $filename: $!"); - $i=0; - while () { - next if /^\s*%/; # skip comment lines - if (m/\\usepackage\[(\w*?)\]\{inputenc\}/) { - close(FH); - return($1); - } - last if (++$i > 20 ); # scan at most 20 non-comment lines - } - close(FH); - return("ascii"); -} - - -sub read_file_with_encoding { - my ($output); - my ($filename, $encoding) = @_; - - if (lc($encoding) eq "utf8" ) { - open (FILE, "<:utf8",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } elsif ( lc($encoding) eq "ascii") { - open (FILE, $filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } else { - require Encode; - open (FILE, "<",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - print STDERR "Converting $filename from $encoding to utf8\n" if $verbose; - $output=Encode::decode($encoding,$output); - } - close FILE; - if ($^O eq "linux" ) { - $output =~ s/\r\n/\n/g ; - } - return $output; -} - -# %packages=list_packages(@preamble) -# scans the arguments for \documentclass,\RequirePackage and \usepackage statements and constructs a hash -# whose keys are the included packages, and whose values are the associated optional arguments -sub list_packages { - my (@preamble)=@_; - my %packages=(); - foreach $line ( @preamble ) { - # get rid of comments - $line=~s/(?catfile($dirname,$fname), "\n" if $debug; - # content of file becomes replacement value (use recursion), add \newpage if the command was include - ###$replacement=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - $replacement=flatten(read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding), $preamble,$filename,$encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - # \include always starts a new page; use explicit \newpage command to simulate this - $begline=(defined($1)? $1 : "") ; - $newpage=(defined($3)? " \\newpage " : "") ; - "$begline$newpage$replacement$newpage"; - }/exgm; - # replace bibliography with bbl file if it exists - $text=~s/(^(?:[^%\n]|\\%)*)\\bibliography{(.*?)}/{ - if ( -f $bblfile ){ - $replacement=read_file_with_encoding(File::Spec->catfile($bblfile), $encoding); - } else { - warn "Bibliography file $bblfile cannot be found. No flattening of \\bibliography done. Run bibtex on old and new files first"; - $replacement="\\bibliography{$2}"; - } - $begline=(defined($1)? $1 : "") ; - "$begline$replacement"; - }/exgm; - # replace subfile with contents (subfile package) - $text=~s/(^(?:[^%\n]|\\%)*)\\subfile{(.*?)}/{ - $fname = $2; - # # add tex extension unless there is a three letter extension already - $fname .= ".tex" unless $fname =~ m|\.\w{3}|; - print STDERR "DEBUG Beg of line match |$1|\n" if defined($1) && $debug ; - print STDERR "Include file as subfile $fname\n" if $verbose; - print STDERR "DEBUG looking for file ",File::Spec->catfile($dirname,$fname), "\n" if $debug; - # content of file becomes replacement value (use recursion) - # now strip away everything outside and including \begin{document} and \end{document} pair# - # # note: no checking for comments is made - $subfile=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - ($subpreamble,$subbody,$subpost)=splitdoc($subfile,'\\\\begin\{document\}','\\\\end\{document\}'); - $replacement=flatten($subbody, $preamble,$filename,$encoding); - $begline=(defined($1)? $1 : "") ; - "$begline$replacement"; - }/exgm; - - return($text); -} - - -# print_regex_arr(@arr) -# prints regex array without x-ism expansion put in by pearl to stdout -sub print_regex_arr { - my $dumstring; - $dumstring = join(" ",@_); # PERL generates string (?-xism:^ref$) for quoted refex ^ref$ - $dumstring =~ s/\(\?-xism:\^(.*?)\$\)/$1/g; # remove string and ^,$ marks before output - print $dumstring,"\n"; -} - - -# @lines=extrapream($type) -# reads line from appendix (end of file after __END__ token) -sub extrapream { - my $type; - my @retval=("%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - my ($copy); - - while (@_) { - $copy=0; - $type=shift ; - if ( -f $type || lc $type eq '/dev/null' ) { - open (FILE,$type) or die "Cannot open preamble file $type: $!"; - print STDERR "Reading preamble file $type\n" if $verbose ; - while () { - chomp ; - if ( $_ =~ m/%DIF PREAMBLE/ ) { - push (@retval,"$_"); - } else { - push (@retval,"$_ %DIF PREAMBLE"); - } - } - } - else { # not (-f $type) - $type=uc($type); # upcase argument - print STDERR "Preamble Internal Type $type\n" if $verbose; - while () { - if ( m/^%DIF $type/ ) { - $copy=1; } - elsif ( m/^%DIF END $type/ ) { - last; } - chomp; - push (@retval,"$_ %DIF PREAMBLE") if $copy; - } - if ( $copy == 0 ) { - print STDERR "\nPreamble style $type not implemented.\n"; - print STDERR "Write latexdiff -h to get help with available styles\n"; - exit(2); - } - seek DATA,0,0; # rewind DATA handle to file begin - } - } - push (@retval,"%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - return @retval; -} - - -# ($part1,$part2,$part3)=splitdoc($text,$word1,$word2) -# splits $text into 3 parts at $word1 and $word2. -# if neither $word1 nor $word2 exist, $part1 and $part3 are empty, $part2 is $text -# If only $word1 or $word2 exist but not the other, output an error message. - -# NB this version avoids $` and $' for performance reason although it only makes a tiny difference -# (in one test gain a tenth of a second for a 30s run) -sub splitdoc { - my ($text,$word1,$word2)=@_; - my ($part1,$part2,$part3)=("","",""); - my ($rest,$pos); - - if ( $text =~ m/(^[^%]*)($word1)/mg ) { - $pos=pos $text; - $part1=substr($text,0,$pos-length($2)); - $rest=substr($text,$pos); - if ( $rest =~ m/(^[^%]*)($word2)/mg ) { - $pos=pos $rest; - $part2=substr($rest,0,$pos-length($2)); - $part3=substr($rest,$pos); - } - else { - die "$word1 and $word2 not in the correct order or not present as a pair." ; - } - } else { - $part2=$text; - die "$word2 present but not $word1." if ( $text =~ m/(^[^%]*)$word2/ms ); - } - return ($part1,$part2,$part3); -} - - - - - -# bodydiff($old,$new) -sub bodydiff { - my ($oldwords, $newwords) = @_; - my @retwords; - - print STDERR "(",exetime()," s)\n","Splitting into latex tokens \n" if $verbose; - print STDERR "Parsing $oldfile \n" if $verbose; - my @oldwords = splitlatex($oldwords); - print STDERR "Parsing $newfile \n" if $verbose; - my @newwords = splitlatex($newwords); - - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - print STDERR "(",exetime()," s)\n","Pass 1: Expanding text commands and merging isolated identities with changed blocks " if $verbose; - pass1(\@oldwords, \@newwords); - - - print STDERR "(",exetime()," s)\n","Pass 2: inserting DIF tokens and mark up. " if $verbose; - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold2.tex"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew2.tex"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - @retwords=pass2(\@oldwords, \@newwords); - - return(@retwords); -} - - - - -# @words=splitlatex($string) -# split string according to latex rules -# Each element of words is either -# a word (including trailing spaces and punctuation) -# a latex command -sub splitlatex { - my ($string) = @_ ; - # if input is empty, return empty list - length($string)>0 or return (); - - my @retval=($string =~ m/$pat/osg); - - if (length($string) != length(join("",@retval))) { - print STDERR "\nWARNING: Inconsistency in length of input string and parsed string:\n This often indicates faulty or non-standard latex code.\n In many cases you can ignore this and the following warning messages.\n Note that character numbers in the following are counted beginning after \\begin{document} and are only approximate." unless $ignorewarnings; - print STDERR "DEBUG Original length ",length($string)," Parsed length ",length(join("",@retval)),"\n" if $debug; - print STDERR "DEBUG Input string: |$string|\n" if (length($string)<500) && $debug; - print STDERR "DEBUG Token parsing: |",join("+",@retval),"|\n" if (length($string)<500) && $debug ; - @retval=(); - # slow way only do this if other m//sg method fails - my $last = 0; - while ( $string =~ m/$pat/osg ) { - my $match=$&; - if ($last + length $& != pos $string ) { - my $pos=pos($string); - my $offset=30<$last ? 30 : $last; - my $dum=substr($string,$last-$offset,$pos-$last+2*$offset); - my $dum1=$dum; - my $cnt=$#retval; - my $i; - $dum1 =~ s/\n/ /g; - unless ($ignorewarnings) { - print STDERR "\n$dum1\n"; - print STDERR " " x 30,"^" x ($pos-$last)," " x 30,"\n"; - print STDERR "Missing characters near word " . (scalar @retval) . " character index: " . $last . "-" . pos($string) . " Length: " . length($match) . " Match: |$match| (expected match marked above).\n"; - } - # put in missing characters `by hand' - push (@retval, substr($dum,$offset,$pos-$last-length($match))); -# Note: there seems to be a bug in substr with utf8 that made the following line output substr which were too long, -# using dum instead appears to work -# push (@retval, substr($string,$last, pos($string)-$last-length($match))); - } - push (@retval, $match); - $last=pos $string; - } - - } - return @retval; -} - - -# pass1( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Where an common-subsequence block is flanked by deleted or appended blocks, -# and is shorter than $MINWORDSBLOCK words it is appended -# to the last deleted or appended word. If the block contains tokens other than words -# or punctuation it is not merged. -# Deleted or appended block consisting of words and safe commands only are -# also merged, to prevent break-up in pass2 (after previous isolated words have been removed) -# If there are commands with textual arguments (e.g. \caption) both in corresponding -# appended and deleted blocks split them such that the command and opening bracket -# are one token, then the rest is split up following standard rules, and the closing -# bracket is a separate token, ie. turn -# "\caption{This is a textual argument}" into -# ("\caption{","This ","is ","a ","textual ","argument","}") -# No return value. Destructively changes sequences -sub pass1 { - my $seq1 = shift ; - my $seq2 = shift ; - - my $len1 = scalar @$seq1; - my $len2 = scalar @$seq2; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - - my ($last1,$last2)=(-1,-1) ; - my $cnt=0; - my $block=[]; - my $addblock=[]; - my $delblock=[]; - my $todo=[]; - my $instruction=[]; - my $i; - my (@delmid,@addmid,@dummy); - - my ($addcmds,$delcmds,$matchindex); - my ($addtextblocks,$deltextblocks); - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $adddiscard = sub { - if ($cnt > 0 ) { - $matblkcnt++; - # just after an unchanged block -# print STDERR "Unchanged block $cnt, $last1,$last2 \n"; - if ($cnt < $MINWORDSBLOCK - && $cnt==scalar ( - grep { /^$wpat/ || ( /^\\([\w\d\*]+)((?:\[$brat0\]|\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && scalar(@dummy=split(" ",$2))<3 ) } - @$block) ) { - # merge identical blocks shorter than $MINWORDSBLOCK - # and only containing ordinary words - # with preceding different word - # We cannot carry out this merging immediately as this - # would change the index numbers of seq1 and seq2 and confuse - # the algorithm, instead we store in @$todo where we have to merge - push(@$todo, [ $last1,$last2,$cnt,@$block ]); - } - $block = []; - $cnt=0; $last1=-1; $last2=-1; - } - }; - my $discard=sub { $deltokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$delblock,[ $seq1->[$_[0]],$_[0] ]); - $last1=$_[0] }; - - my $add = sub { $addtokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$addblock,[ $seq2->[$_[1]],$_[1] ]); - $last2=$_[1] }; - - my $match = sub { $mattokcnt++; - if ($cnt==0) { # first word of matching sequence after changed sequence or at beginning of word sequence - $deltextblocks = extracttextblocks($delblock); - $delblkcnt++ if scalar @$delblock; - $addtextblocks = extracttextblocks($addblock); - $addblkcnt++ if scalar @$addblock; - - $delcmds = extractcommands($delblock); - $addcmds = extractcommands($addblock); - # keygen(third argument of _longestCommonSubsequence) implies to sort on command (0th elements of $addcmd elements) - # the calling format for longestCommonSubsequence has changed between versions of - # Algorithm::Diff so we need to check which one we are using - if ( $algodiffversion > 1.15 ) { - ### Algorithm::Diff 1.19 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, 0, sub { $_[0]->[0] } ); - } else { - ### Algorithm::Diff 1.15 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, sub { $_[0]->[0] } ); - } - - for ($i=0 ; $i<=$#$matchindex ; $i++) { - if (defined($matchindex->[$i])){ - $j=$matchindex->[$i]; - @delmid=splitlatex($delcmds->[$i][3]); - @addmid=splitlatex($addcmds->[$j][3]); - while (scalar(@$deltextblocks) && $deltextblocks->[0][0]<$delcmds->[$i][1]) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) }; - push(@$todo, [$index,-1,$cnt,@$block]); - } - push(@$todo, [ $delcmds->[$i][1],-1,-1,$delcmds->[$i][2],@delmid,$delcmds->[$i][4]]); - - while (scalar(@$addtextblocks) && $addtextblocks->[0][0]<$addcmds->[$j][1]) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - push(@$todo, [ -1,$addcmds->[$j][1],-1,$addcmds->[$j][2],@addmid,$addcmds->[$j][4]]); - } - } - # mop up remaining textblocks - while (scalar(@$deltextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) } ; - push(@$todo, [$index,-1,$cnt,@$block]); - } - while (scalar(@$addtextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - - $addblock=[]; - $delblock=[]; - } - push(@$block,$seq2->[$_[1]]); - $cnt++ }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - - - # now carry out the merging/splitting. Refer to elements relative from - # the end (with negative indices) as these offsets don't change before the instruction is executed - # cnt>0: merged small unchanged groups with previous changed blocks - # cnt==-1: split textual commands into components - foreach $instruction ( @$todo) { - ($last1,$last2,$cnt,@$block)=@$instruction ; - if ($cnt>=0) { - splice(@$seq1,$last1-$len1,1+$cnt,join("",$seq1->[$last1-$len1],@$block)) if $last1>=0; - splice(@$seq2,$last2-$len2,1+$cnt,join("",$seq2->[$last2-$len2],@$block)) if $last2>=0; - } else { - splice(@$seq1,$last1-$len1,1,@$block) if $last1>=0; - splice(@$seq2,$last2-$len2,1,@$block) if $last2>=0; - } - } - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens in $matblkcnt blocks.\n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } -} - - -# extracttextblocks(\@blockindex) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [[ $index, $textblock, $cnt ], .. -# where $index index of block to be merged -# $textblock contains all the words to be merged with the word at $index (but does not contain this word) -# $cnt is length of block -# -# requires: iscmd -# -sub extracttextblocks { - my $block=shift; - my ($i,$token,$index); - my $textblock=[]; - my $last=-1; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # store pure text blocks - if ($token =~ /$wpat/ || ( $token =~/^\\([\w\d\*]+)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && !iscmd($1,\@TEXTCMDLIST,\@TEXTCMDEXCL))) { - # we have text or a command which can be treated as text - if ($last<0) { - # new pure-text block - $last=$index; - } else { - # add to pure-text block - push(@$textblock, $token); - } - } else { - # it is not text - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - $textblock=[]; - $last=-1; - } - } - # finish processing a possibly unfinished block before returning - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - return($retval) -} - - - -# extractcommands( \@blockindex ) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [ [ "\cmd1", index, "\cmd1[optarg]{arg1}{", "arg2" ,"} " ],.. -# where index is just taken from input array -# command must have a textual argument as last argument -# -# requires: iscmd -# -sub extractcommands { - my $block=shift; - my ($i,$token,$index,$cmd,$open,$mid,$closing); - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: \cmd - # $3: last argument - # $4: } + trailing spaces - if ( ( $token =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL) ) { - # push(@$retval,[ $2,$index,$1,$3,$4 ]); - ($cmd,$open,$mid,$closing) = ($2,$1,$3,$4) ; - $closing =~ s/\}/\\RIGHTBRACE/ ; - push(@$retval,[ $cmd,$index,$open,$mid,$closing ]); - } - } - return $retval; -} - -# iscmd($cmd,\@regexarray,\@regexexcl) checks -# return 1 if $cmd matches any of the patterns in the -# array $@regexarray, and none of the patterns in \@regexexcl, otherwise return 0 -sub iscmd { - my ($cmd,$regexar,$regexexcl)=@_; - my ($ret)=0; - foreach $pat ( @$regexar ) { - if ( $cmd =~ m/^${pat}$/ ) { - $ret=1 ; - last; - } - } - return 0 unless $ret; - foreach $pat ( @$regexexcl ) { - return 0 if ( $cmd =~ m/^${pat}$/ ); - } - return 1; -} - - -# pass2( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Mark begin and end of deleted and appended sequences with tags $DELOPEN and $DELCLOSE -# and $ADDOPEN and $ADDCLOSE, respectively, however exclude { } & and all comands, unless -# they match an element of the whitelist (SAFECMD) -# For words in TEXTCMD but not in SAFECMD, enclose interior with $ADDOPEN and $ADDCLOSE brackets -# Deleted comment lines are marked with %DIF < -# Added comment lines are marked with %DIF > -sub pass2 { - my $seq1 = shift ; - my $seq2 = shift ; - - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $retval = []; - my $delhunk = []; - my $addhunk = []; - - my $discard = sub { $deltokcnt++; - push ( @$delhunk, $seq1->[$_[0]]) }; - - my $add = sub { $addtokcnt++; - push ( @$addhunk, $seq2->[$_[1]]) }; - - my $match = sub { $mattokcnt++; - if ( scalar @$delhunk ) { - $delblkcnt++; - # mark up changes, but comment out commands - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk); - $delhunk = []; - } - if ( scalar @$addhunk ) { - $addblkcnt++; - # we mark up changes, but simply quote commands - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk); - $addhunk = []; - } - push(@$retval,$seq2->[$_[1]]) }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - # clear up unprocessed hunks - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk) if scalar @$delhunk; - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk) if scalar @$addhunk; - - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens. \n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } - - return(@$retval); -} - -# marktags($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,\@block) -# returns ($openmark,$open,$block,$close,$closemark) if @block only contains no commands (except white-listed ones), -# braces, ampersands, or comments -# mark comments with $comment -# exclude all other exceptions from scope of open, close like this -# ($openmark, $open,...,$close, $opencmd,command, command,$closecmd, $open, ..., $close, $closemark) -# If $opencmd begins with "%" marktags assumes it is operating on a deleted block, otherwise on an added block -sub marktags { - my ($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,$block)=@_; - my $word; - my (@argtext); - my $retval=[]; - my $noncomment=0; - my $cmd=-1; # -1 at beginning 0: last token written is a ordinary word - # 1: last token written is a command - # for keeping track whether we are just in a command sequence or in a word sequence - my $cmdcomment= ($opencmd =~ m/^%/); # Flag to indicate whether opencmd is a comment (i.e. if we intend to simply comment out changed commands) - my ($command,$commandword,$closingbracket) ; # temporary variables needed below to remember sub-pattern matches - -# split this block to flatten out sequences joined in pass1 - @$block=splitlatex(join "",@$block); - foreach (@$block) { - $word=$_; - if ( $word =~ s/^%/%$comment/ ) { - # a comment - if ($cmd==1) { - push (@$retval,$closecmd) ; - $cmd=-1; - } - push (@$retval,$word); - next; - } - if (! $noncomment) { - push (@$retval,$openmark); - $noncomment=1; - } - # negative lookahead pattern (?!) in second clause is put in to avoid mathcing \( .. \) patterns - # also note that second pattern will match \\ - # Note: the second pattern should really be $word =~ /^\\(?!\()(\\|[\w*@]+)/, ie * replaced by + - # and then all commands \" \' etc declared safe. But as I don't have a complete list of one letter - # commands, and nobody has complained so far, I will eave this as is - if ( $word =~ /^[&{}\[\]]/ || ( $word =~ /^\\(?!\()(\\|[\w*@]*)/ && !iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL)) ) { - # word is a command or other significant token (not in SAFECMDLIST) - ## same conditions as in subroutine extractcommand: - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: cmd - # $3: last argument - # $4: } + trailing spaces - ### pre-0.3 if ( ( $token =~ m/^(\\([\w\d\*]+)(?:\[$brat0\]|\{$pat6\})*\{)($pat6)(\}\s*)$/so ) - if ( ( $word =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && (iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL)|| iscmd($2,\@MATHTEXTCMDLIST,\@MATHTEXTCMDEXCL)) - && ( !$cmdcomment || !iscmd($2,\@CONTEXT2CMDLIST, \@CONTEXT2CMDEXCL) ) ) { - # Condition 1: word is a command? - if yes, $1,$2,.. will be set as above - # Condition 2: word is a text command - we mark up the interior of the word. There is a separate check for MATHTEXTCMDLIST - # because for $mathmarkup=WHOLE, the commands should not be split in pass1 (ie. math mode commands are not in - # TEXTCMDLIST, but the interior of MATHTEXT commands should be highlighted in both deleted and added blocks - # Condition 3: But if we are in a deleted block ($cmdcomment=1) and - # $2 (the command) is in context2, just treat it as an ordinary command (i.e. comment it open with $opencmd) - # Because we do not want to disable this command - # here we do not use $opencmd and $closecmd($opencmd is empty) - if ($cmd==1) { - push (@$retval,$closecmd) ; - } elsif ($cmd==0) { - push (@$retval,$close) ; - } - $command=$1; $commandword=$2; $closingbracket=$4; - @argtext=splitlatex($3); # split textual argument into tokens - # and mark it up (but we do not need openmark and closemark) - # insert command with initial arguments, marked-up final argument, and closing bracket - if ( $cmdcomment && iscmd($commandword,\@CONTEXT1CMDLIST, \@CONTEXT1CMDEXCL) ) { - # context1cmd in a deleted environment; delete command itself but keep last argument, marked up - push (@$retval,$opencmd); - $command =~ s/\n/\n${opencmd}/sg ; # repeat opencmd at the beginning of each line - # argument, note that the additional comment character is included - # to suppress linebreak after opening parentheses, which is important - # for latexrevise - push (@$retval,$command,"%\n{$AUXCMD\n",marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } elsif ( iscmd($commandword,,\@MATHTEXTCMDLIST, \@MATHTEXTCMDEXCL) ) { - # MATHBLOCK pseudo command: consider all commands safe, except & and \\ - # Keep these commands even in deleted blocks, hence set $opencmd and $closecmd (5th and 6th argument of marktags) to - # "" - local @SAFECMDLIST=(".*"); - local @SAFECMDEXCL=('\\','\\\\',@UNSAFEMATHCMD); - push(@$retval,$command,marktags("","",$open,$close,"","",$comment,\@argtext)#@argtext - ,$closingbracket); - } else { - # normal textcmd or context1cmd in an added block - push (@$retval,$command,marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } - push (@$retval,$AUXCMD,"\n") if $cmdcomment ; - $cmd=-1 ; - } else { - # ordinary command - push (@$retval,$opencmd) if $cmd==-1 ; - push (@$retval,$close,$opencmd) if $cmd==0 ; - $word =~ s/\n/\n${opencmd}/sg if $cmdcomment ; # if opencmd is a comment, repeat this at the beginning of every line - push (@$retval,$word); - $cmd=1; - } - } else { - # just an ordinary word or word in SAFECMD - push (@$retval,$open) if $cmd==-1 ; - push (@$retval,$closecmd,$open) if $cmd==1 ; - push (@$retval,$word); - $cmd=0; - } - } - push (@$retval,$close) if $cmd==0; - push (@$retval,$closecmd) if $cmd==1; - - push (@$retval,$closemark) if ($noncomment); - return @$retval; -} - -# preprocess($string, ..) -# carry out the following pre-processing steps for all arguments: -# 1. Remove leading white-space -# Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE -# #. Change {,} in comments to \CLEFTBRACE, \CRIGHTBRACE -# 2. mark all first empty line (in block of several) with \PAR tokens -# 3. Convert all '\%' into '\PERCENTAGE ' and all '\$' into \DOLLAR to make parsing regular expressions easier -# 4. Convert all \verb|some verbatim text| commands (where | can be an arbitrary character) -# into \verb{hash} -# 5. Convert \begin{verbatim} some verbatim text \end{verbatim} into \verbatim{hash} -# 6. Convert _n into \SUBSCRIPTNB{n} and _{nnn} into \SUBSCRIPT{nn} -# 7. Convert ^n into \SUPERSCRIPTNB{n} and ^{nnn} into \SUPERSCRIPT{nn} -# 8. a. Convert $$ $$ into \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} -# b. Convert \[ \] into \begin{SQUAREBRACKET} \end{SQUAREBRACKET} -# 9. Convert all picture environmentent (\begin{PICTUREENV} .. \end{PICTUREENV} \PICTUREBLOCKenv -# For --block-math-markup option -convert all \begin{MATH} .. \end{MATH} -# into \MATHBLOCKmath{...} commands, where MATH/math is any valid math environment - -# 10. Add final token STOP to the very end. This is put in because the algorithm works better if the last token is identical. This is removed again in postprocessing. -# -# NB: step 6 and 7 is likely to convert some "_" inappropriately, e.g. in file -# names or labels but it does not matter because they are converted back in the postprocessing step -# Returns: leading white space removed in step 1 -sub preprocess { - my @leadin=() ; - for (@_) { - s/^(\s*)//s; - push(@leadin,$1); - # Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE - s/(?{$hstr}) && $string ne $hash->{$hstr}) { - warn "Repeated hash value for verbatim mode in spite of different content."; - $hstr="-$hstr"; - } - $hash->{$hstr}=$string; - return($hstr); -} - -#string=fromhash(\%hash,$fromstring) -# restores string value stored in hash -#string=fromhash(\%hash,$fromstring,$prependstring) -# additionally begins each line with prependstring -sub fromhash { - my ($hash,$hstr)=($_[0],$_[1]); - my $retstr=$hash->{$hstr}; - if ( $#_ >= 2) { - $retstr =~ s/^/$_[2]/mg; - } - return $retstr; -} - - -# postprocess($string, ..) -# carry out the following post-processing steps for all arguments: -# * Remove STOP token from the end -# * Replace \RIGHTBRACE by } -# * change citation commands within comments to protect from processing (using marker CITEDIF) -# 1. Check all deleted blocks: -# a.where a deleted block contains a matching \begin and -# \end environment (these will be disabled by a %DIFDELCMD statements), for selected environments enable -# these commands again (such that for example displayed math in a deleted equation -# is properly within math mode. For math mode environments replace numbered equation -# environments with their display only variety (so that equation numbers in new file and -# diff file are identical). Where the correct type of math environment cannot be determined -# use a place holder MATHMODE -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file -# Replace all MATHMODE environment commands by the correct environment to achieve matching -# pairs -# c. Convert MATHBLOCKmath commands to their uncounted numbers (e.g. convert equation -> displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL -# d. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# For added blocks: -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# 2. If --block-math-markup option set: Convert \MATHBLOCKmath{..} commands back to environments -# -# Convert all PICTUREblock{..} commands back to the appropriate environments -# 3. Convert DIFadd, DIFdel, DIFFaddbegin , ... into FL varieties -# within floats (currently recognised float environments: plate,table,figure -# plus starred varieties). -# 4. Remove empty %DIFDELCMD < lines -# 4. Convert \begin{SQUAREBRACKET} \end{SQUAREBRACKET} into \[ \] -# Convert \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} into $$ $$ -# 5. Convert \SUPERSCRIPTNB{n} into ^n and \SUPERSCRIPT{nn} into ^{nnn} -# 6. Convert \SUBSCRIPTNB{n} into _n and \SUBCRIPT{nn} into _{nnn} -# 7. Expand hashes of verb and verbatim environments -# 8. Convert '\PERCENTAGE ' back into '\%' and '\DOLLAR ' into '\$' -# 9.. remove all \PAR tokens -# 10. package specific processing: endfloat: make sure \begin{figure} and \end{figure} are always -# on a line by themselves, similarly for table environment -# 4, undo renaming of the \begin, \end,{,} in comments -# Change \QLEFTBRACE, \QRIGHTBRACE to \{,\} -# -# Note have to manually synchronize substitution commands below and -# DIF.. command names in the header -sub postprocess { - my ($begin,$len,$cnt,$float,$delblock,$addblock); - # second level blocks - my ($begin2,$cnt2,$len2,$eqarrayblock,$mathblock); - - for (@_) { - - # change $'s in comments to something harmless - 1 while s/(%.*)\$/$1DOLLARDIF/mg ; - - # Remove final STOP token - s/ STOP$//; - # Replace \RIGHTBRACE by } - s/\\RIGHTBRACE/}/g; - - # change citation commands within comments to protect from processing - if ($CITECMD){ - 1 while s/(%.*)\\($CITECMD)/$1\\CITEDIF$2/m ; - } - # Check all deleted blocks: where a deleted block contains a matching \begin and - # \end environment (these will be disabled by a %DIFDELCMD statements), enable - # these commands again (such that for example displayed math in a deleted equation - # is properly within math mode. For math mode environments replace numbered equation - # environments with their display only variety (so that equation numbers in new file and - # diff file are identical - while ( m/\\DIFdelbegin.*?\\DIFdelend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $delblock=$&; - - - ### (.*?[^\n]?)\n? construct is necessary to avoid empty lines in math mode, which result in - ### an error - # displayed math environments - if ($mathmarkup == FINE ) { - $delblock=~ s/(\%DIFDELCMD < \s*\\begin\{((?:$MATHENV)|SQUAREBRACKET)\}.*?(?:$DELCMDCLOSE|\n))(.*?[^\n]?)\n?(\%DIFDELCMD < \s*\\end\{\2\})/\\begin{$MATHREPL}$AUXCMD\n$1$3\n\\end{$MATHREPL}$AUXCMD\n$4/sg; - # also transform the opposite pair \end{displaymath} .. \begin{displaymath} but we have to be careful not to interfere with the results of the transformation in the line directly above - ### pre-0.42 obsolete version which did not work on eqnarray test $delblock=~ s/(? displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL - $delblock=~ s/\\MATHBLOCK($MATHENV)\{($pat6)\}/\\MATHBLOCK$MATHREPL\{$2\}/sg; - $delblock=~ s/\\MATHBLOCK($MATHARRENV)\{($pat6)\}/\\MATHBLOCK$MATHARRREPL\{$2\}/sg; - } - - -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file - $delblock=~ s/\\($COUNTERCMD)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*\s*${AUXCMD}\n)/\\$1$2\\addtocounter{$1}{-1}${AUXCMD}\n/sg ; - - -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es - while ( $delblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($delblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($delblock,$begin2,$len2)=$mathblock; - pos($delblock) = $begin2 + length($mathblock); - } - if ($CITE2CMD) { - $delblock=~s/($DELCMDOPEN\s*\\($CITE2CMD)(.*)$DELCMDCLOSE)/ - # Replacement code - {my ($aux,$all); - $aux=$all=$1; - $aux=~s#\n?($DELCMDOPEN|$DELCMDCLOSE)##g; - $all."$aux$AUXCMD\n";}/sge; - } - # or protect \cite commands with \mbox - if ($CITECMD) { - $delblock=~s/(\\($CITECMD)${extraspace}(?:<$abrat0>${extraspace})?(?:\[$brat0\]${extraspace}){0,2}\{$pat6\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } - # if MBOXINLINEMATH is set, protect inlined math environments with an extra mbox - if ( $MBOXINLINEMATH ) { - # note additional \newline after command is omitted from output if right at the end of deleted block (otherwise a spurious empty line is generated) - $delblock=~s/($math)(?:[\s\n]*)?/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/sg; - } - -# splice in modified delblock - substr($_,$begin,$len)=$delblock; - pos = $begin + length($delblock); - } - # make the array modification in added blocks - while ( m/\\DIFaddbegin.*?\\DIFaddend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $addblock=$&; - while ( $addblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($addblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($addblock,$begin2,$len2)=$mathblock; - pos($addblock) = $begin2 + length($mathblock); - } - if ($CITECMD) { - my $addblockbefore=$addblock; - #(?:mask)?(?:full|short|no)?cite(?:A|author|year|meta)(?:NP)?$/ - ###my $CITECMD; $CITECMD="cite(?:A)$"; - $addblock=~ s/(\\($CITECMD)${extraspace}(?:<$abrat0>${extraspace})?(?:\[$brat0\]${extraspace}){0,2}\{$pat2\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - print STDERR "DEBUG: CITECMD $CITECMD\nDEBUG: addblock before:|$addblockbefore|\n" if $debug; - print STDERR "DEBUG: addblock after: |$addblock|\n" if $debug; - } - # if MBOXINLINEMATH is set, protect inlined math environments with an extra mbox - if ( $MBOXINLINEMATH ) { - ##$addblock=~s/($math)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/sg; - $addblock=~s/($math)(?:[\s\n]*)?/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/sg; - } -# splice in modified addblock - substr($_,$begin,$len)=$addblock; - pos = $begin + length($addblock); - } - - - - # Replace MATHMODE environments from step 1a above by the correct Math environment - - # The next line is complicated. The negative look-ahead insertion makes sure that no \end{$MATHENV} (or other mathematical - # environments) are between the \begin{$MATHENV} and \end{MATHMODE} commands. This is necessary as the minimal matching - # is not globally minimal but only 'locally' (matching is beginning from the left side of the string) - if ( $mathmarkup == FINE ) { - 1 while s/\\begin{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}((?:.(?!(?:\\end{(?:(?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}|\\begin{MATHMODE})))*?)\\end{MATHMODE}/\\begin{$1}$2\\end{$1}/s; - 1 while s/\\begin{MATHMODE}((?:.(?!\\end{MATHMODE}))*?)\\end{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}/\\begin{$2}$1\\end{$2}/s; - # convert remaining \begin{MATHMODE} \end{MATHMODE} (and not containing & or \\ )into MATHREPL environments - s/\\begin{MATHMODE}((?:(.(?!(?[1])) { - $optargnew=$newhash{$cmd}->[1]; - } else { - $optargnew=""; - } - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - } else { - $optargold=""; - } - - if ( defined($oldhash{$cmd}) ) { - $argold=$oldhash{$cmd}->[2]; - } else { - $argold=""; - } - $argnew=$newhash{$cmd}->[2]; - $argdiff="{" . join("",bodydiff($argold,$argnew)) ."}"; - if ( length $optargnew ) { - $optargdiff="[".join("",bodydiff($optargold,$optargnew))."]" ; - $optargdiff =~ s/\\DIFaddbegin /\\DIFaddbeginFL /g; - $optargdiff =~ s/\\DIFaddend /\\DIFaddendFL /g; - $optargdiff =~ s/\\DIFadd\{/\\DIFaddFL{/g; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - ### print STDERR "DEBUG s/\\Q$newhash{$cmd}->[0]\\E/\\$cmd$optargdiff$argdiff/s\n"; - # Note: \Q and \E force literal interpretation of what it between them but allow - # variable interpolation, such that e.g. \title matches just that and not TAB-itle - $$newpreambleref=~s/\Q$newhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s; - # replace this in old preamble if necessary - if ( defined($oldhash{$cmd}->[0])) { - $$oldpreambleref=~s/\Q$oldhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s ; - } - ### print STDERR "DEBUG NEW PRE ".$$newpreambleref."\n"; - } - - foreach $cmd ( keys %oldhash ) { - # if this has already been dealt with above can just skip - next if defined($newhash{$cmd}) ; - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - $optargdiff="[".join("",bodydiff($optargold,""))."]" ; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - $argdiff="{" . join("",bodydiff($argold,"")) ."}"; - $auxline = "\\$cmd$optargdiff$argdiff"; - $auxline =~s/$/$AUXCMD/sg; - push @auxlines,$auxline; - } - # add auxcmd comment to highlight added lines - return(@auxlines); -} - - - -# @diffs=linediff(\@seq1, \@seq2) -# mark up lines like this -#%DIF mm-mmdnn -#%< old deleted line(s) -#%DIF ------- -#%DIF mmann-nn -#new appended line %< -#%DIF ------- -# Future extension: mark change explicitly -# Assumes: traverse_sequence traverses deletions before insertions in changed sequences -# all line numbers relative to line 0 (first line of real file) -sub linediff { - my $seq1 = shift ; - my $seq2 = shift ; - - my $block = []; - my $retseq = []; - my @begin=('','',''); # dummy initialisation - my $instring ; - - my $discard = sub { @begin=('d',$_[0],$_[1]) unless scalar @$block ; - push(@$block, "%DIF < " . $seq1->[$_[0]]) }; - my $add = sub { if (! scalar @$block) { - @begin=('a',$_[0],$_[1]) ;} - elsif ( $begin[0] eq 'd' ) { - $begin[0]='c'; $begin[2]=$_[1]; - push(@$block, "%DIF -------") } - push(@$block, $seq2->[$_[1]] . " %DIF > " ) }; - my $match = sub { if ( scalar @$block ) { - if ( $begin[0] eq 'd' && $begin[1]!=$_[0]-1) { - $instring = sprintf "%%DIF %d-%dd%d",$begin[1],$_[0]-1,$begin[2]; } - elsif ( $begin[0] eq 'a' && $begin[2]!=$_[1]-1) { - $instring = sprintf "%%DIF %da%d-%d",$begin[1],$begin[2],$_[1]-1; } - elsif ( $begin[0] eq 'c' ) { - $instring = sprintf "%%DIF %sc%s", - ($begin[1]==$_[0]-1) ? "$begin[1]" : $begin[1]."-".($_[0]-1) , - ($begin[2]==$_[1]-1) ? "$begin[2]" : $begin[2]."-".($_[1]-1) ; } - else { - $instring = sprintf "%%DIF %d%s%d",$begin[1],$begin[0],$begin[2]; } - push @$retseq, $instring,@$block, "%DIF -------" ; - $block = []; - } - push @$retseq, $seq2->[$_[1]] - }; - # key function: remove multiple spaces (such that insertion or deletion of redundant white space is not reported) - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - push @$retseq, @$block if scalar @$block; - - return wantarray ? @$retseq : $retseq ; -} - - - -# init_regex_arr_data(\@array,"TOKEN INIT") -# scans DATA file handel for line "%% TOKEN INIT" line -# then appends each line not beginning with % into array (as a quoted regex) -sub init_regex_arr_data { - my ($arr,$token)=@_; - my ($copy); - while () { - if ( m/^%%BEGIN $token\s*$/ ) { - $copy=1; } - elsif ( m/^%%END $token\s*/ ) { - last; } - chomp; - push (@$arr,qr/^$_$/) if ( $copy && !/^%/ ) ; - } - seek DATA,0,0; # rewind DATA handle to file begin -} - - -# init_regex_arr_ext(\@array,$arg) -# fills array with regular expressions. -# if arg is a file name, then read in list of regular expressions from that file -# (one expression per line) -# Otherwise treat arg as a comma separated list of regular expressions -sub init_regex_arr_ext { - my ($arr,$arg)=@_; - my $regex; - if ( -f $ arg ) { - open(FILE,"$arg") or die ("Couldn't open $arg: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@$arr,qr/^$_$/); - } - close(FILE); - } - else { - # assume it is a comma-separated list of reg-ex - foreach $regex (split(qr/(?=1) { - $reset=shift; - } - if ($reset) { - $lasttime=times(); - } - else { - $retval=times()-$lasttime; - $lasttime=$lasttime+$retval; - return($retval); - } -} - - -sub usage { - die <<"EOF"; -Usage: $0 [options] old.tex new.tex > diff.tex - -Compares two latex files and writes tex code to stdout, which has the same -format as new.tex but has all changes relative to old.tex marked up or commented. - ---type=markupstyle --t markupstyle Add code to preamble for selected markup style - Available styles: UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE - CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR - [ Default: UNDERLINE ] - ---subtype=markstyle --s markstyle Add code to preamble for selected style for bracketing - commands (e.g. to mark changes in margin) - Available styles: SAFE MARGINAL DVIPSCOL COLOR LABEL - [ Default: SAFE ] - ---floattype=markstyle --f markstyle Add code to preamble for selected style which - replace standard marking and markup commands within floats - (e.g., marginal remarks cause an error within floats - so marginal marking can be disabled thus) - Available styles: FLOATSAFE IDENTICAL - [ Default: FLOATSAFE ] - ---encoding=enc --e enc Specify encoding of old.tex and new.tex. Typical encodings are - ascii, utf8, latin1, latin9. A list of available encodings can be - obtained by executing - perl -MEncode -e 'print join ("\\n",Encode->encodings( ":all" )) ;' - [Default encoding is utf8 unless the first few lines of the preamble contain - an invocation "\\usepackage[..]{inputenc} in which case the - encoding chosen by this command is asssumed. Note that ASCII (standard - latex) is a subset of utf8] - ---preamble=file --p file Insert file at end of preamble instead of auto-generating - preamble. The preamble must define the following commands - \\DIFaddbegin,\\DIFaddend,\\DIFadd{..}, - \\DIFdelbegin,\\DIFdelend,\\DIFdel{..}, - and varieties for use within floats - \\DIFaddbeginFL,\\DIFaddendFL,\\DIFaddFL{..}, - \\DIFdelbeginFL,\\DIFdelendFL,\\DIFdelFL{..} - (If this option is set -t, -s, and -f options - are ignored.) - ---exclude-safecmd=exclude-file ---exclude-safecmd="cmd1,cmd2,..." --A exclude-file ---replace-safecmd=replace-file ---append-safecmd=append-file ---append-safecmd="cmd1,cmd2,..." --a append-file Exclude from, replace or append to the list of regex - matching commands which are safe to use within the - scope of a \\DIFadd or \\DIFdel command. The file must contain - one Perl-RegEx per line (Comment lines beginning with # or % are - ignored). A literal comma within the comma-separated list must be - escaped thus "\\,", Note that the RegEx needs to match the whole of - the token, i.e., /^regex\$/ is implied and that the initial - "\\" of the command is not included. The --exclude-safecmd - and --append-safecmd options can be combined with the --replace-safecmd - option and can be used repeatedly to add cumulatively to the lists. - ---exclude-textcmd=exclude-file ---exclude-textcmd="cmd1,cmd2,..." --X exclude-file ---replace-textcmd=replace-file ---append-textcmd=append-file ---append-textcmd="cmd1,cmd2,..." --x append-file Exclude from, replace or append to the list of regex - matching commands whose last argument is text. See - entry for --exclude-safecmd directly above for further details. - ---replace-context1cmd=replace-file ---append-context1cmd=append-file ---append-context1cmd="cmd1,cmd2,..." - Replace or append to the list of regex matching commands - whose last argument is text but which require a particular - context to work, e.g. \\caption will only work within a figure - or table. These commands behave like text commands, except when - they occur in a deleted section, when they are disabled, but their - argument is shown as deleted text. - ---replace-context2cmd=replace-file ---append-context2cmd=append-file ---append-context2cmd="cmd1,cmd2,..." - As corresponding commands for context1. The only difference is that - context2 commands are completely disabled in deleted sections, including - their arguments. - - ---config var1=val1,var2=val2,... --c var1=val1,.. Set configuration variables. --c configfile Available variables: - MINWORDSBLOCK (integer) - FLOATENV (RegEx) - PICTUREENV (RegEx) - MATHENV (RegEx) - MATHREPL (String) - MATHARRENV (RegEx) - MATHARRREPL (String) - ARRENV (RegEx) - COUNTERCMD (RegEx) - This option can be repeated. - - ---packages=pkg1,pkg2,.. - Tell latexdiff that .tex file is processed with the packages in list - loaded. This is normally not necessary if the .tex file includes the - preamble, as the preamble is automatically scanned for \\usepackage commands. - Use of the --packages option disables automatic scanning, so if for any - reason package specific parsing needs to be switched off, use --packages=none. - The following packages trigger special behaviour: - endfloat hyperref amsmath apacite - [ Default: scan the preamble for \\usepackage commands to determine - loaded packages.] - ---show-preamble Print generated or included preamble commands to stdout. - ---show-safecmd Print list of regex matching and excluding safe commands. - ---show-textcmd Print list of regex matching and excluding commands with text argument. - ---show-config Show values of configuration variables - ---show-all Show all of the above - - NB For all --show commands, no old.tex or new.tex file needs to be given, and no - differencing takes place. - -Other configuration options: - ---allow-spaces Allow spaces between bracketed or braced arguments to commands - [Default requires arguments to directly follow each other without - intervening spaces] - ---math-markup=level Determine granularity of markup in displayed math environments: - Possible values for level are (both numerical and text labels are acceptable): - off or 0: suppress markup for math environments. Deleted equations will not - appear in diff file. This mode can be used if all the other modes - cause invalid latex code. - whole or 1: Differencing on the level of whole equations. Even trivial changes - to equations cause the whole equation to be marked changed. This - mode can be used if processing in coarse or fine mode results in - invalid latex code. - coarse or 2: Detect changes within equations marked up with a coarse - granularity; changes in equation type (e.g.displaymath to equation) - appear as a change to the complete equation. This mode is recommended - for situations where the content and order of some equations are still - being changed. [Default] - fine or 3: Detect small change in equations and mark up and fine granularity. - This mode is most suitable, if only minor changes to equations are - expected, e.g. correction of typos. - ---disable-citation-markup Suppress citation markup in styles using ulem (UNDERLINE, - FONTSTRIKE, CULINECHBAR) ---enable-citation-markup Protect citation commands in changed sections with \\mbox command - [i.e. use default behaviour for ulem package for other packages] - -Miscelleneous options - ---label=label --L label Sets the labels used to describe the old and new files. The first use - of this option sets the label describing the old file and the second - use of the option sets the label for the new file. - [Default: use the filename and modification dates for the label] - ---no-label Suppress inclusion of old and new file names as comment in output file - ---visible-label Include old and new filenames (or labels set with --label option) as - visible output - ---flatten Replace \\input and \\include commands within body by the content - of the files in their argument. If \\includeonly is present in the - preamble, only those files are expanded into the document. However, - no recursion is done, i.e. \\input and \\include commands within - included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, - respectively, making it possible to organise files into old and new directories. - --flatten is applied recursively, so inputted files can contain further - \\input statements. - ---help --h Show this help text. - ---ignore-warnings Suppress warnings about inconsistencies in length between input - and parsed strings and missing characters. - ---verbose --V Output various status information to stderr during processing. - Default is to work silently. - ---version Show version number. - -EOF -} - -=head1 NAME - -latexdiff - determine and markup differences between two latex files - -=head1 SYNOPSIS - -B [ B ] F F > F - -=head1 DESCRIPTION - -Briefly, I is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called C and C, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. - -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "S>>" is appended to each added line, i.e. a -line present in C but not in C. Discarded lines - are deactivated by prepending "S>>". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file C will be similar to -C. At the end of the preamble, the definitions for I markup commands are inserted. -In differencing the main body of the text, I attempts to -satisfy the following guidelines (in order of priority): - -=over 3 - -=item 1 - -If both C and C are valid LaTeX, then the resulting -C should also be valid LateX. (NB If a few plain TeX commands -are used within C or C then C is not -guaranteed to work but usually will). - -=item 2 - -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -C. - -=item 3 - -If a changed passage contains text or text-producing commands, then -running C through LateX should produce output where added -and discarded passages are highlighted. - -=item 4 - -Where there are insignificant differences, e.g. in the positioning of -line breaks, C should follow the formatting of C - -=back - -For differencing the same algorithm as I is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, C<\caption> and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write - - \section{\textem{This is an emphasized section title}} - -and not - - \section {\textem{This is an emphasized section title}} - -or - - \section\textem{This is an emphasized section title} - -even though all varieties are the same to LaTeX (but see -B<--allow-spaces> option which allows the second variety). - -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the PICTUREENV configuration variable, set by -default to C and C environments; see B<--config> -option). The latter environment (C) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by C<\begin{DIFnomarkup}> and C<\end{DIFnomarkup}>. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, - -C<\newenvironment{DIFnomarkup}{}{}> - -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. - -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. - -All markup commands inserted by I begin with "C<\DIF>". Added -blocks containing words, commands or comments which are in C -but not in C are marked by C<\DIFaddbegin> and C<\DIFaddend>. -Discarded blocks are marked by C<\DIFdelbegin> and C<\DIFdelend>. -Within added blocks all text is highlighted with C<\DIFadd> like this: -C<\DIFadd{Added text block}> -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces "{" and "}" are never put within -the scope of C<\DIFadd>. Added comments are marked by prepending -"S >>". - -Within deleted blocks text is highlighted with C<\DIFdel>. Deleted -comments are marked by prepending "S >>". Non-safe command -and curly braces within deleted blocks are commented out with -"S >>". - - - -=head1 OPTIONS - -=head2 Preamble - -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. - -=over 4 - -=item B<--type=markupstyle> or -B<-t markupstyle> - -Add code to preamble for selected markup style. This option defines -C<\DIFadd> and C<\DIFdel> commands. -Available styles: - -C - -[ Default: C ] - -=item B<--subtype=markstyle> or -B<-s markstyle> - -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -C<\DIFaddbegin>, C<\DIFaddend>, C<\DIFdelbegin> and C<\DIFdelend> commands. -Available styles: C - -[ Default: C ] - -=item B<--floattype=markstyle> or -B<-f markstyle> - -Add code to preamble for selected style which -replace standard marking and markup commands within floats -(e.g., marginal remarks cause an error within floats -so marginal marking can be disabled thus). This option defines all -C<\DIF...FL> commands. -Available styles: C - -[ Default: C ] - -=item B<--encoding=enc> or -B<-e enc> - -Specify encoding of old.tex and new.tex. Typical encodings are -C, C, C, C. A list of available encodings can be -obtained by executing - -Cencodings( ":all" )) ;' > - -[Default encoding is utf8 unless the first few lines of the preamble contain -an invocation C<\usepackage[..]{inputenc}> in which case the -encoding chosen by this command is asssumed. Note that ASCII (standard -latex) is a subset of utf8] - -=item B<--preamble=file> or -B<-p file> - -Insert file at end of preamble instead of generating -preamble. The preamble must define the following commands -C<\DIFaddbegin, \DIFaddend, \DIFadd{..}, -\DIFdelbegin,\DIFdelend,\DIFdel{..},> -and varieties for use within floats -C<\DIFaddbeginFL, \DIFaddendFL, \DIFaddFL{..}, -\DIFdelbeginFL, \DIFdelendFL, \DIFdelFL{..}> -(If this option is set B<-t>, B<-s>, and B<-f> options -are ignored.) - -=item B<--packages=pkg1,pkg2,..> - -Tell latexdiff that .tex file is processed with the packages in list -loaded. This is normally not necessary if the .tex file includes the -preamble, as the preamble is automatically scanned for C<\usepackage> commands. -Use of the B<--packages> option disables automatic scanning, so if for any -reason package specific parsing needs to be switched off, use B<--packages=none>. -The following packages trigger special behaviour: - -=over 8 - -=item C - -Configuration variable amsmath is set to C (Default: C) - -=item C - -Ensure that C<\begin{figure}> and C<\end{figure}> always appear by themselves on a line. - -=item C - -Change name of C<\DIFadd> and C<\DIFdel> commands to C<\DIFaddtex> and C<\DIFdeltex> and -define new C<\DIFadd> and C<\DIFdel> commands, which provide a wrapper for these commands, -using them for the text but not for the link defining command (where any markup would cause -errors). - -=item C - -Redefine the commands recognised as citation commands. - -=back - -[ Default: scan the preamble for C<\\usepackage> commands to determine - loaded packages.] - - - -=item B<--show-preamble> - -Print generated or included preamble commands to stdout. - -=back - -=head2 Configuration - -=over 4 - -=item B<--exclude-safecmd=exclude-file> or -B<-A exclude-file> or B<--exclude-safecmd="cmd1,cmd2,..."> - -=item B<--replace-safecmd=replace-file> - -=item B<--append-safecmd=append-file> or -B<-a append-file> or B<--append-safecmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions (RegEx) -matching commands which are safe to use within the -scope of a C<\DIFadd> or C<\DIFdel> command. The file must contain -one Perl-RegEx per line (Comment lines beginning with # or % are -ignored). Note that the RegEx needs to match the whole of -the token, i.e., /^regex$/ is implied and that the initial -"\" of the command is not included. -The B<--exclude-safecmd> and B<--append-safecmd> options can be combined with the -B<--replace-safecmd> -option and can be used repeatedly to add cumulatively to the lists. - B<--exclude-safecmd> -and B<--append-safecmd> can also take a comma separated list as input. If a -comma for one of the regex is required, escape it thus "\,". In most cases it -will be necessary to protect the comma-separated list from the shell by putting -it in quotation marks. - -=item B<--exclude-textcmd=exclude-file> or -B<-X exclude-file> or B<--exclude-textcmd="cmd1,cmd2,..."> - -=item B<--replace-textcmd=replace-file> - -=item B<--append-textcmd=append-file> or -B<-x append-file> or B<--append-textcmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions -matching commands whose last argument is text. See -entry for B<--exclude-safecmd> directly above for further details. - - -=item B<--replace-context1cmd=replace-file> - -=item B<--append-context1cmd=append-file> or -=item B<--append-context1cmd="cmd1,cmd2,..."> - -Replace or append to the list of regex matching commands -whose last argument is text but which require a particular -context to work, e.g. \caption will only work within a figure -or table. These commands behave like text commands, except when -they occur in a deleted section, when they are disabled, but their -argument is shown as deleted text. - -=item B<--replace-context2cmd=replace-file> - -=item B<--append-context2cmd=append-file> or -=item B<--append-context2cmd="cmd1,cmd2,..."> -As corresponding commands for context1. The only difference is that -context2 commands are completely disabled in deleted sections, including -their arguments. - - - -=item B<--config var1=val1,var2=val2,...> or B<-c var1=val1,..> - -=item B<-c configfile> - -Set configuration variables. The option can be repeated to set different -variables (as an alternative to the comma-separated list). -Available variables (see below for further explanations): - -C (integer) - -C (RegEx) - -C (RegEx) - -C (RegEx) - -C (String) - -C (RegEx) - -C (String) - -C (RegEx) - -C (RegEx) - -=item B<--show-safecmd> - -Print list of RegEx matching and excluding safe commands. - -=item B<--show-textcmd> - -Print list of RegEx matching and excluding commands with text argument. - -=item B<--show-config> - -Show values of configuration variables. - -=item B<--show-all> - -Combine all --show commands. - -NB For all --show commands, no C or C file needs to be specified, and no -differencing takes place. - -=back - -=head2 Other configuration options: - -=over 4 - -=item B<--allow-spaces> - -Allow spaces between bracketed or braced arguments to commands. Note -that this option might have undesirable side effects (unrelated scope -might get lumpeded with preceding commands) so should only be used if the -default produces erroneous results. (Default requires arguments to -directly follow each other without intervening spaces). - -=item B<--math-markup=level> - -Determine granularity of markup in displayed math environments: -Possible values for level are (both numerical and text labels are acceptable): - -C or C<0>: suppress markup for math environments. Deleted equations will not -appear in diff file. This mode can be used if all the other modes -cause invalid latex code. - -C or C<1>: Differencing on the level of whole equations. Even trivial changes -to equations cause the whole equation to be marked changed. This -mode can be used if processing in coarse or fine mode results in -invalid latex code. - -C or C<2>: Detect changes within equations marked up with a coarse -granularity; changes in equation type (e.g.displaymath to equation) -appear as a change to the complete equation. This mode is recommended -for situations where the content and order of some equations are still -being changed. [Default] - -C or C<3>: Detect small change in equations and mark up at fine granularity. -This mode is most suitable, if only minor changes to equations are -expected, e.g. correction of typos. - -=item B<--disable-citation-markup> - -Suppress citation markup in styles using ulem (UNDERLINE, -FONTSTRIKE, CULINECHBAR) - -=item B<--enable-citation-markup> - -Protect citation commands in changed sections with \\mbox command [i.e. use default behaviour for ulem package for other packages] - -=back - -=head2 Miscellaneous - -=over 4 - -=item B<--verbose> or B<-V> - -Output various status information to stderr during processing. -Default is to work silently. - -=item B<--driver=type> - -Choose driver for changebar package (only relevant for styles using - changebar: CCHANGEBAR CFONTCHBAR CULINECHBAR CHANGEBAR). Possible -drivers are listed in changebar manual, e.g. pdftex,dvips,dvitops - [Default: dvips] - -=item B<--ignore-warnings> - -Suppress warnings about inconsistencies in length between input and -parsed strings and missing characters. These warning messages are -often related to non-standard latex or latex constructions with a -syntax unknown to C but the resulting difference argument -is often fully functional anyway, particularly if the non-standard -latex only occurs in parts of the text which have not changed. - -=item B<--label=label> or -B<-L label> - -Sets the labels used to describe the old and new files. The first use -of this option sets the label describing the old file and the second -use of the option sets the label for the new file, i.e. set both -labels like this C<-L labelold -L labelnew>. -[Default: use the filename and modification dates for the label] - -=item B<--no-label> - -Suppress inclusion of old and new file names as comment in output file - -=item B<--visble-label> - -Include old and new filenames (or labels set with --label option) as -visible output. - -=item B<--flatten> - -Replace C<\input> and C<\include> commands within body by the content -of the files in their argument. If C<\includeonly> is present in the -preamble, only those files are expanded into the document. However, -no recursion is done, i.e. C<\input> and C<\include> commands within -included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, -respectively, making it possible to organise files into old and new directories. ---flatten is applied recursively, so inputted files can contain further -C<\input> statements. - -Use of this option might result in prohibitive processing times for -larger documents, and the resulting difference document -no longer reflects the structure of the input documents. - -=item B<--help> or -B<-h> - -Show help text - -=item B<--version> - -Show version number - -=back - - - -=head2 Predefined styles - -=head2 Major types - -The major type determine the markup of plain text and some selected latex commands outside floats by defining the markup commands C<\DIFadd{...}> and C<\DIFdel{...}> . - -=over 10 - -=item C - -Added text is wavy-underlined and blue, discarded text is struck out and red -(Requires color and ulem packages). Overstriking does not work in displayed math equations such that deleted parts of equation are underlined, not struck out (this is a shortcoming inherent to the ulem package). - -=item C - -Added text is blue and set in sans-serif, and a red footnote is created for each discarded -piece of text. (Requires color package) - -=item C - -Like C but without the use of color. - -=item C - -Added text is blue and set in sans-serif, and discarded text is red and very small size. - -=item C - -Added tex is set in sans-serif, discarded text small and struck out - -=item C - -Added text is blue, and discarded text is red. Additionally, the changed text is marked with a bar in the margin (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color, ulem and changebar packages). - -=item C - -No mark up of text, but mark margins with changebars (Requires changebar package). - -=item C - -No visible markup (but generic markup commands will still be inserted. - -=back - -=head2 Subtypes - -The subtype defines the commands that are inserted at the begin and end of added or discarded blocks, irrespectively of whether these blocks contain text or commands (Defined commands: C<\DIFaddbegin, \DIFaddend, \DIFdelbegin, \DIFdelend>) - -=over 10 - -=item C - -No additional markup (Recommended choice) - -=item C - -Mark beginning and end of changed blocks with symbols in the margin nearby (using -the standard C<\marginpar> command - note that this sometimes moves somewhat -from the intended position. - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. -(It is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete, for example -with citation commands). - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. Note -that C only works with the dvips converter, e.g. not pdflatex. -(it is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete). - -=back - -=head2 Float Types - -Some of the markup used in the main text might cause problems when used within -floats (e.g. figures or tables). For this reason alternative versions of all -markup commands are used within floats. The float type defines these alternative commands. - -=over 10 - -=item C - -Use identical markup for text as in the main body, but set all commands marking the begin and end of changed blocks to null-commands. You have to choose this float type if your subtype is C as C<\marginpar> does not work properly within floats. - -=item C - -Mark additions the same way as in the main text. Deleted environments are marked by angular brackets \[ and \] and the deleted text is set in scriptscript size. This float type should always be used with the C and C markup types as the \footnote command does not work properly in floating environments. - -=item C - -Make no difference between the main text and floats. - -=back - - -=head2 Configuration Variables - -=over 10 - -=item C - -Minimum number of tokens required to form an independent block. This value is -used in the algorithm to detect changes of complete blocks by merging identical text parts of less than C to the preceding added and discarded parts. - -[ Default: 3 ] - -=item C - -Environments whose name matches the regular expression in C are -considered floats. Within these environments, the I markup commands -are replaced by their FL variaties. - -[ Default: S >] - -=item C - -Within environments whose name matches the regular expression in C -all latexdiff markup is removed (in pathologic cases this might lead to - inconsistent markup but this situation should be rare). - -[ Default: S >] - -=item C,C - -If both \begin and \end for a math environment (environment name matching C -or \[ and \]) -are within the same deleted block, they are replaced by a \begin and \end commands for C -rather than being commented out. - -[ Default: C=S >, C=S >] - -=item C,C - -as C,C but for equation arrays - -[ Default: C=S >, C=S >] - -=item C - -If a match to C is found within an inline math environment within a deleted or added block, then the inlined math -is surrounded by C<\mbox{>...C<}>. This is necessary as underlining does not work within inlined array environments. - -[ Default: C=S > - -=item C - -If a command in a deleted block which is also in the textcmd list matches C then an -additional command C<\addtocounter{>FC<}{-1}>, where F is the matching command, is appended in the diff file such that the numbering in the diff file remains synchronized with the -numbering in the new file. - -[ Default: C=C<(?:footnote|part|section|subsection> ... - -C<|subsubsection|paragraph|subparagraph)> ] - -=back - -=head1 COMMON PROBLEMS - -=over 10 - -=item Citations result in overfull boxes - -There is an incompatibility between the C package, which C uses for underlining and striking out in the UNDERLINE style, -the default style. In order to be able to mark up citations properly, they are placed with an C<\mbox> command in post-processing. As mboxes -cannot be broken across lines, this procedure frequently results in overfull boxes, possibly obscuring the content as it extends beyond the right margin. If this is a problem, you have two possibilities: - -1. Use C or C subtype markup (option C<-s COLOR>): If this markup is chosen, then changed citations are no longer marked up -with the wavy line (additions) or struck out (deletions), but are still highlighted in the appropriate color. - -2. Choose option C<--disable-citation-markup> which turns off the marking up of citations: deleted citations are no longer shown, and -added ctations are shown without markup. (This was the default behaviour of latexdiff at versions 0.6 and older) - -=item Changes in complicated mathematical equations result in latex processing errors - -Try options C<--math-markup=whole>. If even that fails, you can turn off mark up for equations with C<--math-markup=off>. - -=back - -=head1 BUGS - -Option allow-spaces not implemented entirely consistently. It breaks -the rules that number and type of white space does not matter, as -different numbers of inter-argument spaces are treated as significant. - -Please submit bug reports using the issue tracker of the github repository page I, -or send them to I. Include the serial number of I -(from comments at the top of the source or use B<--version>). If you come across latex -files that are error-free and conform to the specifications set out -above, and whose differencing still does not result in error-free -latex, please send me those files, ideally edited to only contain the -offending passage as long as that still reproduces the problem. If your -file relies on non-standard class files, you must include those. I will not -look at examples where I have trouble to latex the original files. - -=head1 SEE ALSO - -L, L - -=head1 PORTABILITY - -I does not make use of external commands and thus should run -on any platform supporting Perl 5.6 or higher. If files with encodings -other than ASCII or UTF-8 are processed, Perl 5.8 or higher is required. - -The standard version of I requires installation of the Perl package -C (available from I - -I) but a stand-alone -version, I, which has this package inlined, is available, too. -I requires the I command to be present. - -=head1 AUTHOR - -Version 1.0.4 -Copyright (C) 2004-2012 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 - -Contributors of fixes and additions: V. Kuhlmann, J. Paisley, N. Becker, T. Doerges, K. Huebner, -T. Connors, Sebastian Gouezel and many others. -Thanks to the many people who sent in bug reports, feature suggestions, and other feedback. - -=cut - -__END__ -%%BEGIN SAFE COMMANDS -% Regex matching commands which can safely be in the -% argument of a \DIFadd or \DIFdel command (leave out the \) -arabic -dashbox -emph -fbox -framebox -hspace -math.* -makebox -mbox -pageref -ref -symbol -raisebox -rule -text.* -shortstack -usebox -dag -ddag -copyright -pounds -S -P -oe -OE -ae -AE -aa -AA -o -O -l -L -frac -ss -sqrt -ldots -cdots -vdots -ddots -alpha -beta -gamma -delta -epsilon -varepsilon -zeta -eta -theta -vartheta -iota -kappa -lambda -mu -nu -xi -pi -varpi -rho -varrho -sigma -varsigma -tau -upsilon -phi -varphi -chi -psi -omega -Gamma -Delta -Theta -Lambda -Xi -Pi -Sigma -Upsilon -Phi -Psi -Omega -ps -mp -times -div -ast -star -circ -bullet -cdot -cap -cup -uplus -sqcap -vee -wedge -setminus -wr -diamond -(?:big)?triangle.* -lhd -rhd -unlhd -unrhd -oplus -ominus -otimes -oslash -odot -bigcirc -d?dagger -amalg -leq -prec -preceq -ll -(?:sq)?su[bp]set(?:eq)? -in -vdash -geq -succ(?:eq)? -gg -ni -dashv -equiv -sim(?:eq)? -asymp -approx -cong -neq -doteq -propto -models -perp -mid -parallel -bowtie -Join -smile -frown -.*arrow -(?:long)?mapsto -.*harpoon.* -leadsto -aleph -hbar -imath -jmath -ell -wp -Re -Im -mho -prime -emptyset -nabla -surd -top -bot -angle -forall -exists -neg -flat -natural -sharp -backslash -partial -infty -Box -Diamond -triangle -clubsuit -diamondsuit -heartsuit -spadesuit -sum -prod -coprod -int -oint -big(?:sq)?c[au]p -bigvee -bigwedge -bigodot -bigotimes -bigoplus -biguplus -(?:arc)?(?:cos|sin|tan|cot)h? -csc -arg -deg -det -dim -exp -gcd -hom -inf -ker -lg -lim -liminf -limsup -ln -log -max -min -Pr -sec -sup -[Hclbdruvt] -(SUPER|SUB)SCRIPTNB -(SUPER|SUB)SCRIPT -PERCENTAGE -DOLLAR -%%END SAFE COMMANDS - -%%BEGIN TEXT COMMANDS -% Regex matching commands with a text argument (leave out the \) -addcontents.* -cc -closing -chapter -dashbox -emph -encl -fbox -framebox -footnote -footnotetext -framebox -part -(sub){0,2}section\*? -(sub)?paragraph\*? -makebox -mbox -opening -parbox -raisebox -savebox -sbox -shortstack -signature -text.* -value -underline -sqrt -(SUPER|SUB)SCRIPT -%%END TEXT COMMANDS - -%%BEGIN CONTEXT1 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -caption -%%END CONTEXT1 COMMANDS - -%%BEGIN CONTEXT2 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -title -author -date -institute -%%END CONTEXT2 COMMANDS - - -%% TYPES (Commands for highlighting changed blocks) - -%DIF UNDERLINE PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}} -\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}} -%DIF END UNDERLINE PREAMBLE - -%DIF CTRADITIONAL PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} [..\footnote{removed: #1} ]}} -%DIF END CTRADITIONAL PREAMBLE - -%DIF TRADITIONAL PREAMBLE -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{[..\footnote{removed: #1} ]}} -%DIF END TRADITIONAL PREAMBLE - -%DIF CFONT PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} \scriptsize #1}} -%DIF END CFONT PREAMBLE - -%DIF FONTSTRIKE PREAMBLE -\RequirePackage[normalem]{ulem} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{\footnotesize \sout{#1}}} -%DIF END FONTSTRIKE PREAMBLE - -%DIF CCHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}#1}\protect\cbdelete} -%DIF END CCHANGEBAR PREAMBLE - -%DIF CFONTCHBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\sf #1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\scriptsize #1}\protect\cbdelete} -%DIF END CFONTCHBAR PREAMBLE - -%DIF CULINECHBAR PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage[dvips]{changebar} -\RequirePackage{color} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\uwave{#1}}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\sout{#1}}\protect\cbdelete} -%DIF END CULINECHBAR PREAMBLE - -%DIF CHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\providecommand{\DIFadd}[1]{\protect\cbstart{#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete} -%DIF END CHANGEBAR PREAMBLE - -%DIF INVISIBLE PREAMBLE -\providecommand{\DIFadd}[1]{#1} -\providecommand{\DIFdel}[1]{} -%DIF END INVISIBLE PREAMBLE - - -%% SUBTYPES (Markers for beginning and end of changed blocks) - -%DIF SAFE PREAMBLE -\providecommand{\DIFaddbegin}{} -\providecommand{\DIFaddend}{} -\providecommand{\DIFdelbegin}{} -\providecommand{\DIFdelend}{} -%DIF END SAFE PREAMBLE - -%DIF MARGIN PREAMBLE -\providecommand{\DIFaddbegin}{\protect\marginpar{a[}} -\providecommand{\DIFaddend}{\protect\marginpar{]}} -\providecommand{\DIFdelbegin}{\protect\marginpar{d[}} -\providecommand{\DIFdelend}{\protect\marginpar{]}} -%DIF END BRACKET PREAMBLE - -%DIF DVIPSCOL PREAMBLE -%Note: only works with dvips converter -\RequirePackage{color} -\RequirePackage{dvipscol} -\providecommand{\DIFaddbegin}{\protect\nogroupcolor{blue}} -\providecommand{\DIFaddend}{\protect\nogroupcolor{black}} -\providecommand{\DIFdelbegin}{\protect\nogroupcolor{red}} -\providecommand{\DIFdelend}{\protect\nogroupcolor{black}} -%DIF END DVIPSCOL PREAMBLE - -%DIF COLOR PREAMBLE -\RequirePackage{color} -\providecommand{\DIFaddbegin}{\protect\color{blue}} -\providecommand{\DIFaddend}{\protect\color{black}} -\providecommand{\DIFdelbegin}{\protect\color{red}} -\providecommand{\DIFdelend}{\protect\color{black}} -%DIF END COLOR PREAMBLE - -%DIF LABEL PREAMBLE -% To show only pages with changes (pdf) (external program pdftk needs to be installed) -% (only works for simple documents with non-repeated page numbers) -% pdflatex diff.tex -% pdflatex diff.tex -% pdftk diff.pdf cat `perl -lne 'if (m/\\newlabel{DIFchg[be]\d*}{{.*}{(.*)}}/) { print $1 }' diff.aux | uniq | tr -s \\n ' '` output diff-changedpages.pdf -% To show only pages with changes (dvips/dvipdf) -% latex diff.tex -% latex diff.tex -% dvips -pp `perl -lne 'if (m/\\newlabel{DIFchg[be]\d*}{{.*}{(.*)}}/) { print $1 }' diff.aux | uniq | tr -s \\n ','` diff.dvi -\typeout{Check comments in preamble of output for instructions how to show only pages where changes have been made} -\newcount\DIFcounterb -\global\DIFcounterb 0\relax -\newcount\DIFcountere -\global\DIFcountere 0\relax -\providecommand{\DIFaddbegin}{\global\advance\DIFcounterb 1\relax\label{DIFchgb\the\DIFcounterb}} %DIF PREAMBLE -\providecommand{\DIFaddend}{\global\advance\DIFcountere 1\relax\label{DIFchge\the\DIFcountere}} %DIF PREAMBLE -\providecommand{\DIFdelbegin}{\global\advance\DIFcounterb 1\relax\label{DIFchgb\the\DIFcounterb}} %DIF PREAMBLE -\providecommand{\DIFdelend}{\global\advance\DIFcountere 1\relax\label{DIFchge\the\DIFcountere}} %DIF PREAMBLE -%DIF END LABEL PREAMBLE -%% FLOAT TYPES - -%DIF FLOATSAFE PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%DIF IDENTICAL PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{\DIFaddbegin} -\providecommand{\DIFaddendFL}{\DIFaddend} -\providecommand{\DIFdelbeginFL}{\DIFdelbegin} -\providecommand{\DIFdelendFL}{\DIFdelend} -%DIF END IDENTICAL PREAMBLE - -%DIF TRADITIONALSAFE PREAMBLE -% procidecommand color to make this work for TRADITIONAL and CTRADITIONAL -\providecommand{\color}[1]{} -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdel}[1]{{\protect\color{red}[..{\scriptsize {removed: #1}} ]}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END TRADITIONALSAFE PREAMBLE - -%% SPECIAL PACKAGE PREAMBLE COMMANDS - -% Standard \DIFadd and \DIFdel are redefined as \DIFaddtex and \DIFdeltex -% when hyperref package is included. -%DIF HYPERREF PREAMBLE -\providecommand{\DIFadd}[1]{\texorpdfstring{\DIFaddtex{#1}}{#1}} -\providecommand{\DIFdel}[1]{\texorpdfstring{\DIFdeltex{#1}}{}} -%DIF END HYPERREF PACKAGE diff --git a/latexdiff-1.0.4/latexdiff-fast b/latexdiff-1.0.4/latexdiff-fast deleted file mode 100755 index 22f2f8f..0000000 --- a/latexdiff-1.0.4/latexdiff-fast +++ /dev/null @@ -1,4101 +0,0 @@ -#!/usr/bin/env perl -##!/usr/bin/perl -w -# latexdiff - differences two latex files on the word level -# and produces a latex file with the differences marked up. -# -# Copyright (C) 2004-12 F J Tilmann (tilmann@gfz-potsdam.de) -# -# Repository/issue tracker: https://github.com/ftilmann/latexdiff -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# -# ToDo: -# -# Version 1.0.4 -# - introduce list UNSAFEMATHCMD, which holds list of commands which cannot be marked up with \DIFadd or \DIFdel commands (only relevant for WHOLE and COARSE math markup modes) -# - new subtype LABEL which gives each change a label. This can later be used to only display pages where changes -# have been made (instructions for that are put as comments into the diff'ed file) inspired by answer on http://tex.stackexchange.com/questions/166049/invisible-markers-in-pdfs-using-pdflatex -# - Configuration variables take into accout some commands from additional packages: -# tikzpicture environment now treated as PICTUREENV, and \smallmatrix in ARRENV (amsmath) -# - --flatten: support for \subfile command (subfiles package) (in response to http://tex.stackexchange.com/questions/167620/latexdiff-with-subfiles ) -# - --flatten: \bibliography commands expand if corresponding bbl file present -# - angled bracket optional commands now parsed correctly (patch #3570) submitted by Dave Kleinschmidt (thanks) -# - \RequirePackage now treated as synonym of \usepackage with respect to setting packages -# - special rules for apacite package (redefine citation commands) -# - recognise /dev/null as 'file-like' arguments for --preamble and --config options -# - fix units package incompatibility with ulem for text maths statements $ ..$ (thanks to Stuart Prescott for reporting this) -# - amsmath environment cases treated correctly (Bug fix #19029) (thanks to Jalar) -# - {,} in comments no longer confuse latexdiff (Bug fix #19146) -# - \% in one-letter sub/Superscripts was not converted correctly -# -# Version 1.0.3 -# - fix bug in add_safe_commands that made latexdiff hang on DeclareMathOperator -# command in preamble -# - \(..\) inline math expressions were not parsed correctly, if they contained a linebreak -# - applied patch contributed by tomflannaghan via Berlios: [ Patch #3431 ] Adds correct handling of \left< and \right> -# - \$ is treated correctly as a literal dollar sign (thanks to Reed Cartwright and Joshua Miller for reporting this bug -# and sketching out the solution) -# - \^ and \_ are correctly interpreted as accent and underlined space, respectively, not as superscript of subscript -# (thanks to Wail Yahyaoui for pointing out this bug) -# -# Version 1.0.1 - treat \big,\bigg etc. equivalently to \left and -# \right - include starred version in MATHENV - apply -# - flatten recursively and --flatten expansion is now -# aware of comments (thanks to Tim Connors for patch) -# - Change to post-processing for more reliability for -# deleted math environments -# - On linux systems, recognise and remove DOS style newlines -# - Provide markup for some special preamble commands (\title, -# \author,\date, -# - configurable by setting context2cmd -# - for styles using ulem package, remove \emph and \text.. from list of -# safe commands in order to allow linebreaks within the -# highlighted sections. -# - for ulem style, now show citations by enclosing them in \mbox commands. -# This unfortunately implies linebreaks within citations no longer function, -# so this functionality can be turned off (Option --disable-citation-markup). -# With --enable-citation-markup, the mbox markup is forced for other styles) -# - new substyle COLOR. This is particularly useful for marking up citations -# and some special post-processing is implemented to retain cite -# commands in deleted blocks. -# - four different levels of math-markup -# - Option --driver for choosing driver for modes employing changebar package -# - accept \\* as valid command (and other commands of form \.*). Also accept -# \ (backslashed newline) -# - some typo fixes, include commands defined in preamble as safe commands -# (Sebastian Gouezel) -# - include compared filenames as comments as line 2 and 3 of -# the preamble (can be modified with option --label, and suppressed with -# --no-label), option --visible-label to show files in generated pdf or dvi -# at the beginning of main document -# -# Version 0.5 A number of minor improvements based on feedback -# Deleted blocks are now shown before added blocks -# Package specific processing -# -# Version 0.43 unreleased typo in list of styles at the end -# Add protect to all \cbstart, \cbend commands -# More robust substitution of deleted math commands -# -# Version 0.42 November 06 Bug fixes only -# -# Version 0.4 March 06 option for fast differencing using UNIX diff command, several minor bug fixes (\par bug, improved highlighting of textcmds) -# -# Version 0.3 August 05 improved parsing of displayed math, --allow-spaces -# option, several minor bug fixes -# -# Version 0.25 October 04 Fix bug with deleted equations, add math mode commands to safecmd, add | to allowed interpunctuation signs -# Version 0.2 September 04 extension to utf-8 and variable encodings -# Version 0.1 August 04 First public release - -# Inserted block for differenceing -# use Algorithm::Diff qw(traverse_sequences); -# in standard version -# The following BEGIN block contains a verbatim copy of -# Ned Konz' Algorithm::Diff package version 1.15 except -# that subroutine _longestCommonSubsequence has been replace by -# a routine which internally uses the UNIX diff command for -# the differencing rather than the Perl routines if the -# length of the sequences exceeds some threshold. -# Also, all POD documentation has been stripped out. -# -# (the distribution on which this modification is based is available -# from http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15 -# the most recent version can be found via http://search.cpan.org/search?module=Algorithm::Diff ) -# Please note that the LICENCSE for Algorithm::Diff : -# "Copyright (c) 2000-2002 Ned Konz. All rights reserved. -# This program is free software; -# you can redistribute it and/or modify it under the same terms -# as Perl itself." -# The fast-differencing version of latexdiff is provided as a convenience -# for latex users under Unix-like systems which have a 'diff' command. -# If you believe -# the inlining of Algorithm::Diff violates its license please contact -# me and I will modify the latexdiff distribution accordingly. -# Frederik Tilmann (tilmann@esc.cam.ac.uk) -# Jonathan Paisley is acknowledged for the idea of using the system diff -# command to achieve shorter running times -BEGIN { -package Algorithm::Diff; -use strict; -use vars qw($VERSION @EXPORT_OK @ISA @EXPORT); -use integer; # see below in _replaceNextLargerWith() for mod to make - # if you don't use this -require Exporter; -@ISA = qw(Exporter); -@EXPORT = qw(); -@EXPORT_OK = qw(LCS diff traverse_sequences traverse_balanced sdiff); -$VERSION = sprintf('%d.%02d fast', (q$Revision: 1.15 $ =~ /\d+/g)); - -# Global parameters - -use File::Temp qw/tempfile/; -# if larger number of elements in longestCommonSubsequence smaller than -# this number, then use internal algorithm, otherwise use UNIX diff -use constant THRESHOLD => 100 ; -# Detect whether diff --minimal option is available -# if yes we use it -use constant MINIMAL => ( system('diff','--minimal','/dev/null','/dev/null') >> 8 ==0 ? "--minimal" : "" ) ; - - - -# McIlroy-Hunt diff algorithm -# Adapted from the Smalltalk code of Mario I. Wolczko, -# by Ned Konz, perl@bike-nomad.com - - -# Create a hash that maps each element of $aCollection to the set of positions -# it occupies in $aCollection, restricted to the elements within the range of -# indexes specified by $start and $end. -# The fourth parameter is a subroutine reference that will be called to -# generate a string to use as a key. -# Additional parameters, if any, will be passed to this subroutine. -# -# my $hashRef = _withPositionsOfInInterval( \@array, $start, $end, $keyGen ); - -sub _withPositionsOfInInterval -{ - my $aCollection = shift; # array ref - my $start = shift; - my $end = shift; - my $keyGen = shift; - my %d; - my $index; - for ( $index = $start ; $index <= $end ; $index++ ) - { - my $element = $aCollection->[$index]; - my $key = &$keyGen( $element, @_ ); - if ( exists( $d{$key} ) ) - { - unshift ( @{ $d{$key} }, $index ); - } - else - { - $d{$key} = [$index]; - } - } - return wantarray ? %d : \%d; -} - -# Find the place at which aValue would normally be inserted into the array. If -# that place is already occupied by aValue, do nothing, and return undef. If -# the place does not exist (i.e., it is off the end of the array), add it to -# the end, otherwise replace the element at that point with aValue. -# It is assumed that the array's values are numeric. -# This is where the bulk (75%) of the time is spent in this module, so try to -# make it fast! - -sub _replaceNextLargerWith -{ - my ( $array, $aValue, $high ) = @_; - $high ||= $#$array; - - # off the end? - if ( $high == -1 || $aValue > $array->[-1] ) - { - push ( @$array, $aValue ); - return $high + 1; - } - - # binary search for insertion point... - my $low = 0; - my $index; - my $found; - while ( $low <= $high ) - { - $index = ( $high + $low ) / 2; - - # $index = int(( $high + $low ) / 2); # without 'use integer' - $found = $array->[$index]; - - if ( $aValue == $found ) - { - return undef; - } - elsif ( $aValue > $found ) - { - $low = $index + 1; - } - else - { - $high = $index - 1; - } - } - - # now insertion point is in $low. - $array->[$low] = $aValue; # overwrite next larger - return $low; -} - -# This method computes the longest common subsequence in $a and $b. - -# Result is array or ref, whose contents is such that -# $a->[ $i ] == $b->[ $result[ $i ] ] -# foreach $i in ( 0 .. $#result ) if $result[ $i ] is defined. - -# An additional argument may be passed; this is a hash or key generating -# function that should return a string that uniquely identifies the given -# element. It should be the case that if the key is the same, the elements -# will compare the same. If this parameter is undef or missing, the key -# will be the element as a string. - -# By default, comparisons will use "eq" and elements will be turned into keys -# using the default stringizing operator '""'. - -# Additional parameters, if any, will be passed to the key generation routine. - -sub _longestCommonSubsequence -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $keyGen = shift; # code ref - my $compare; # code ref - - # set up code refs - # Note that these are optimized. - if ( !defined($keyGen) ) # optimize for strings - { - $keyGen = sub { $_[0] }; - $compare = sub { my ( $a, $b ) = @_; $a eq $b }; - } - else - { - $compare = sub { - my $a = shift; - my $b = shift; - &$keyGen( $a, @_ ) eq &$keyGen( $b, @_ ); - }; - } - - my ( $aStart, $aFinish, $bStart, $bFinish, $matchVector ) = - ( 0, $#$a, 0, $#$b, [] ); - - # Check whether to use internal routine (small number of elements) - # or use it as a wrapper for UNIX diff - if ( ( $#$a > $#$b ? $#$a : $#$b) < THRESHOLD ) { - ### print STDERR "DEBUG: regular longestCommonSubsequence\n"; - # First we prune off any common elements at the beginning - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aStart], $b->[$bStart], @_ ) ) - { - $matchVector->[ $aStart++ ] = $bStart++; - } - - # now the end - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aFinish], $b->[$bFinish], @_ ) ) - { - $matchVector->[ $aFinish-- ] = $bFinish--; - } - - # Now compute the equivalence classes of positions of elements - my $bMatches = - _withPositionsOfInInterval( $b, $bStart, $bFinish, $keyGen, @_ ); - my $thresh = []; - my $links = []; - - my ( $i, $ai, $j, $k ); - for ( $i = $aStart ; $i <= $aFinish ; $i++ ) - { - $ai = &$keyGen( $a->[$i], @_ ); - if ( exists( $bMatches->{$ai} ) ) - { - $k = 0; - for $j ( @{ $bMatches->{$ai} } ) - { - - # optimization: most of the time this will be true - if ( $k and $thresh->[$k] > $j and $thresh->[ $k - 1 ] < $j ) - { - $thresh->[$k] = $j; - } - else - { - $k = _replaceNextLargerWith( $thresh, $j, $k ); - } - - # oddly, it's faster to always test this (CPU cache?). - if ( defined($k) ) - { - $links->[$k] = - [ ( $k ? $links->[ $k - 1 ] : undef ), $i, $j ]; - } - } - } - } - - if (@$thresh) - { - for ( my $link = $links->[$#$thresh] ; $link ; $link = $link->[0] ) - { - $matchVector->[ $link->[1] ] = $link->[2]; - } - } - } - else { - my ($fha,$fhb,$fna,$fnb,$ele,$key); - my ($alines,$blines,$alb,$alf,$blb,$blf); - my ($minimal)=MINIMAL; - # large number of elements, use system diff - ### print STDERR "DEBUG: fast (diff) longestCommonSubsequence\n"; - - ($fha,$fna)=tempfile("DiffA-XXXX") or die "_longestCommonSubsequence: Cannot open tempfile for sequence A"; - ($fhb,$fnb)=tempfile("DiffB-XXXX") or die "_longestCommonSubsequence: Cannot open tempfile for sequence B"; - # prepare sequence A - foreach $ele ( @$a ) { - $key=&$keyGen( $ele, @_ ); - $key =~ s/\\/\\\\/g ; - $key =~ s/\n/\\n/sg ; - print $fha "$key\n" ; - } - close($fha); - # prepare sequence B - foreach $ele ( @$b ) { - $key=&$keyGen( $ele, @_ ); - $key =~ s/\\/\\\\/g ; - $key =~ s/\n/\\n/sg ; - print $fhb "$key\n" ; - } - close($fhb); - - open(DIFFPIPE, "diff $minimal $fna $fnb |") or die "_longestCommonSubsequence: Cannot launch diff process. $!" ; - # The diff line numbering begins with 1, but Perl subscripts start with 0 - # We follow the diff numbering but substract 1 when assigning to matchVector - $aStart++; $bStart++ ; $aFinish++ ; $bFinish++ ; - while( ) { - if ( ($alines,$blines) = ( m/^(\d*(?:,\d*)?)?c(\d*(?:,\d*)?)?$/ ) ) { - ($alb,$alf)=split(/,/,$alines); - ($blb,$blf)=split(/,/,$blines); - $alf=$alb unless defined($alf); - $blf=$blb unless defined($blf); - while($aStart < $alb ) { - $matchVector->[ -1 + $aStart++ ] = -1 + $bStart++ ; - } - # check for consistency - $bStart==$blb or die "_longestCommonSubsequence: Fatal error in interpreting diff output: Inconsistency in changed sequence"; - $aStart=$alf+1; - $bStart=$blf+1; - } - elsif ( ($alb,$blines) = ( m/^(\d*)a(\d*(?:,\d*)?)$/ ) ) { - ($blb,$blf)=split(/,/,$blines); - $blf=$blb unless defined($blf); - while ( $bStart < $blb ) { - $matchVector->[ -1 + $aStart++ ] = -1 + $bStart++ ; - } - $aStart==$alb+1 or die "_longestCommonSubsequence: Fatal error in interpreting diff output: Inconsistency in appended sequence near elements $aStart and $bStart"; - $bStart=$blf+1; - } - elsif ( ($alines,$blb) = ( m/^(\d*(?:,\d*)?)d(\d*)$/ ) ) { - ($alb,$alf)=split(/,/,$alines); - $alf=$alb unless defined($alf); - while ( $aStart < $alb ) { - $matchVector->[ -1 + $aStart++ ] = -1 + $bStart++ ; - } - $bStart==$blb+1 or die "_longestCommonSubsequence: Fatal error in interpreting diff output: Inconsistency in deleted sequence near elements $aStart and $bStart"; - $aStart=$alf+1; - } - elsif ( m/^Binary files/ ) { - # if diff reports it is a binary file force --text mode. I do not like - # to always use this option because it is probably only available in GNU diff - open(DIFFPIPE, "diff --text $fna $fnb |") or die "Cannot launch diff process. $!" ; - } - # Default: just skip line - } - while ($aStart <= $aFinish ) { - $matchVector->[ -1 + $aStart++ ] = -1 + $bStart++ ; - } - $bStart==$bFinish+1 or die "_longestCommonSubsequence: Fatal error in interpreting diff output: Inconsistency at end"; - close DIFFPIPE; - # check whether a system error has occurred or return status is greater than or equal to 5 - if ( $! || ($? >> 8) > 5) { - print STDERR "diff process failed with exit code ", ($? >> 8), " $!\n"; - die; - } - unlink $fna,$fnb ; - } - return wantarray ? @$matchVector : $matchVector; -} - -sub traverse_sequences -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $finishedACallback = $callbacks->{'A_FINISHED'}; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $finishedBCallback = $callbacks->{'B_FINISHED'}; - my $matchVector = _longestCommonSubsequence( $a, $b, $keyGen, @_ ); - - # Process all the lines in @$matchVector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai; - - for ( $ai = 0 ; $ai <= $#$matchVector ; $ai++ ) - { - my $bLine = $matchVector->[$ai]; - if ( defined($bLine) ) # matched - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi < $bLine; - &$matchCallback( $ai, $bi++, @_ ); - } - else - { - &$discardACallback( $ai, $bi, @_ ); - } - } - - # The last entry (if any) processed was a match. - # $ai and $bi point just past the last matching lines in their sequences. - - while ( $ai <= $lastA or $bi <= $lastB ) - { - - # last A? - if ( $ai == $lastA + 1 and $bi <= $lastB ) - { - if ( defined($finishedACallback) ) - { - &$finishedACallback( $lastA, @_ ); - $finishedACallback = undef; - } - else - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi <= $lastB; - } - } - - # last B? - if ( $bi == $lastB + 1 and $ai <= $lastA ) - { - if ( defined($finishedBCallback) ) - { - &$finishedBCallback( $lastB, @_ ); - $finishedBCallback = undef; - } - else - { - &$discardACallback( $ai++, $bi, @_ ) while $ai <= $lastA; - } - } - - &$discardACallback( $ai++, $bi, @_ ) if $ai <= $lastA; - &$discardBCallback( $ai, $bi++, @_ ) if $bi <= $lastB; - } - - return 1; -} - -sub traverse_balanced -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $changeCallback = $callbacks->{'CHANGE'}; - my $matchVector = _longestCommonSubsequence( $a, $b, $keyGen, @_ ); - - # Process all the lines in match vector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai = 0; - my $ma = -1; - my $mb; - - while (1) - { - - # Find next match indices $ma and $mb - do { $ma++ } while ( $ma <= $#$matchVector && !defined $matchVector->[$ma] ); - - last if $ma > $#$matchVector; # end of matchVector? - $mb = $matchVector->[$ma]; - - # Proceed with discard a/b or change events until - # next match - while ( $ai < $ma || $bi < $mb ) - { - - if ( $ai < $ma && $bi < $mb ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai < $ma ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi < $mb - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - # Match - &$matchCallback( $ai++, $bi++, @_ ); - } - - while ( $ai <= $lastA || $bi <= $lastB ) - { - if ( $ai <= $lastA && $bi <= $lastB ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai <= $lastA ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi <= $lastB - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - return 1; -} - -sub LCS -{ - my $a = shift; # array ref - my $matchVector = _longestCommonSubsequence( $a, @_ ); - my @retval; - my $i; - for ( $i = 0 ; $i <= $#$matchVector ; $i++ ) - { - if ( defined( $matchVector->[$i] ) ) - { - push ( @retval, $a->[$i] ); - } - } - return wantarray ? @retval : \@retval; -} - -sub diff -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $hunk = []; - my $discard = sub { push ( @$hunk, [ '-', $_[0], $a->[ $_[0] ] ] ) }; - my $add = sub { push ( @$hunk, [ '+', $_[1], $b->[ $_[1] ] ] ) }; - my $match = sub { push ( @$retval, $hunk ) if scalar(@$hunk); $hunk = [] }; - traverse_sequences( $a, $b, - { MATCH => $match, DISCARD_A => $discard, DISCARD_B => $add }, @_ ); - &$match(); - return wantarray ? @$retval : $retval; -} - -sub sdiff -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $discard = sub { push ( @$retval, [ '-', $a->[ $_[0] ], "" ] ) }; - my $add = sub { push ( @$retval, [ '+', "", $b->[ $_[1] ] ] ) }; - my $change = sub { - push ( @$retval, [ 'c', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - my $match = sub { - push ( @$retval, [ 'u', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - traverse_balanced( - $a, - $b, - { - MATCH => $match, - DISCARD_A => $discard, - DISCARD_B => $add, - CHANGE => $change, - }, - @_ - ); - return wantarray ? @$retval : $retval; -} - -1; -} -import Algorithm::Diff qw(traverse_sequences); -# End of inserted block for stand-alone version - - -use Getopt::Long ; -use strict ; -use warnings; -use utf8 ; - -my ($algodiffversion)=split(/ /,$Algorithm::Diff::VERSION); - - -my ($versionstring)=< 0, - WHOLE => 1, - COARSE => 2, - FINE => 3 -}; - - -my (@configlist,@labels, - @appendsafelist,@excludesafelist, - @appendtextlist,@excludetextlist, - @appendcontext1list,@appendcontext2list, - @packagelist); -my ($assign,@config); -# Hash where keys corresponds to the names of all included packages (including the documentclass as another package -# the optional arguments to the package are the values of the hash elements -my ($pkg,%packages); -# Defaults -$type='UNDERLINE'; -$subtype='SAFE'; -$floattype='FLOATSAFE'; -$mathmarkup=COARSE; - -$verbose=0; -# output debug and intermediate files, set to 0 in final distribution -$debug=0; -# insert preamble directly after documentclass - experimental feature, set to 0 in final distribution -# Note that this failed with mini example (or other files, where packages used in latexdiff preamble -# are called again with incompatible options in preamble of resulting file) -$earlylatexdiffpreamble=0; - -# define character properties -sub IsNonAsciiPunct { return <<'END' # Unicode punctuation but excluding ASCII punctuation -+utf8::IsPunct --utf8::IsASCII -END -} -sub IsNonAsciiS { return <<'END' # Unicode symbol but excluding ASCII -+utf8::IsS --utf8::IsASCII -END -} - - -my %verbhash; - -Getopt::Long::Configure('bundling'); -GetOptions('type|t=s' => \$type, - 'subtype|s=s' => \$subtype, - 'floattype|f=s' => \$floattype, - 'config|c=s' => \@configlist, - 'preamble|p=s' => \$preamblefile, - 'encoding|e=s' => \$encoding, - 'label|L=s' => \@labels, - 'no-label' => \$nolabel, - 'visible-label' => \$visiblelabel, - 'exclude-safecmd|A=s' => \@excludesafelist, - 'replace-safecmd=s' => \$replacesafe, - 'append-safecmd|a=s' => \@appendsafelist, - 'exclude-textcmd|X=s' => \@excludetextlist, - 'replace-textcmd=s' => \$replacetext, - 'append-textcmd|x=s' => \@appendtextlist, - 'replace-context1cmd=s' => \$replacecontext1, - 'append-context1cmd=s' => \@appendcontext1list, - 'replace-context2cmd=s' => \$replacecontext2, - 'append-context2cmd=s' => \@appendcontext2list, - 'show-preamble' => \$showpreamble, - 'show-safecmd' => \$showsafe, - 'show-textcmd' => \$showtext, - 'show-config' => \$showconfig, - 'show-all' => \$showall, - 'packages=s' => \@packagelist, - 'allow-spaces' => \$allowspaces, - 'math-markup=s' => \$mathmarkup, - 'enable-citation-markup' => \$enablecitmark, - 'disable-citation-markup' => \$disablecitmark, - 'verbose|V' => \$verbose, - 'ignore-warnings' => \$ignorewarnings, - 'driver=s'=> \$driver, - 'flatten' => \$flatten, - 'version' => \$version, - 'help|h|H' => \$help); - -if ( $help ) { - usage() ; -} - - -if ( $version ) { - die $versionstring ; -} - -print STDERR $versionstring if $verbose; - -if (defined($showall)){ - $showpreamble=$showsafe=$showtext=$showconfig=1; -} - -if (defined($mathmarkup)) { - $mathmarkup=~tr/a-z/A-Z/; - if ( $mathmarkup eq 'OFF' ){ - $mathmarkup=OFF; - } elsif ( $mathmarkup eq 'WHOLE' ){ - $mathmarkup=WHOLE; - } elsif ( $mathmarkup eq 'COARSE' ){ - $mathmarkup=COARSE; - } elsif ( $mathmarkup eq 'FINE' ){ - $mathmarkup=FINE; - } elsif ( $mathmarkup !~ m/^[0123]$/ ) { - die "Illegal value: ($mathmarkup) for option--math-markup. Possible values: OFF,WHOLE,COARSE,FINE,0- "; - } - # else use numerical value -} - -# setting extra preamble commands -if (defined($preamblefile)) { - $latexdiffpreamble=join "\n",(extrapream($preamblefile),""); -} else { - $latexdiffpreamble=join "\n",(extrapream($type,$subtype,$floattype),""); -} - -if ( defined($driver) ) { - # for changebar only - $latexdiffpreamble=~s/\[dvips\]/[$driver]/sg; -} -# setting up @SAFECMDLIST and @SAFECMDEXCL -if (defined($replacesafe)) { - init_regex_arr_ext(\@SAFECMDLIST,$replacesafe); -} else { - init_regex_arr_data(\@SAFECMDLIST, "SAFE COMMANDS"); -} -foreach $appendsafe ( @appendsafelist ) { - init_regex_arr_ext(\@SAFECMDLIST, $appendsafe); -} -foreach $excludesafe ( @excludesafelist ) { - init_regex_arr_ext(\@SAFECMDEXCL, $excludesafe); -} - -# setting up @TEXTCMDLIST and @TEXTCMDEXCL -if (defined($replacetext)) { - init_regex_arr_ext(\@TEXTCMDLIST,$replacetext); -} else { - init_regex_arr_data(\@TEXTCMDLIST, "TEXT COMMANDS"); -} -foreach $appendtext ( @appendtextlist ) { - init_regex_arr_ext(\@TEXTCMDLIST, $appendtext); -} -foreach $excludetext ( @excludetextlist ) { - init_regex_arr_ext(\@TEXTCMDEXCL, $excludetext); -} - - -# setting up @CONTEXT1CMDLIST ( @CONTEXT1CMDEXCL exist but is always empty ) -if (defined($replacecontext1)) { - init_regex_arr_ext(\@CONTEXT1CMDLIST,$replacecontext1); -} else { - init_regex_arr_data(\@CONTEXT1CMDLIST, "CONTEXT1 COMMANDS"); -} -foreach $appendcontext1 ( @appendcontext1list ) { - init_regex_arr_ext(\@CONTEXT1CMDLIST, $appendcontext1); -} - - -# setting up @CONTEXT2CMDLIST ( @CONTEXT2CMDEXCL exist but is always empty ) -if (defined($replacecontext2)) { - init_regex_arr_ext(\@CONTEXT2CMDLIST,$replacecontext2); -} else { - init_regex_arr_data(\@CONTEXT2CMDLIST, "CONTEXT2 COMMANDS"); -} -foreach $appendcontext2 ( @appendcontext2list ) { - init_regex_arr_ext(\@CONTEXT2CMDLIST, $appendcontext2); -} - -# setting configuration variables -@config=(); -foreach $config ( @configlist ) { - if (-f $config || lc $config eq '/dev/null' ) { - open(FILE,$config) or die ("Couldn't open configuration file $config: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@config,$_); - } - close(FILE); - } - else { -# foreach ( split(",",$config) ) { -# push @config,$_; -# } - push @config,split(",",$config) - } -} -foreach $assign ( @config ) { - $assign=~ m/\s*(\w*)\s*=\s*(\S*)\s*$/ or die "Illegal assignment $assign in configuration list (must be variable=value)"; - if ( $1 eq "MINWORDSBLOCK" ) { $MINWORDSBLOCK = $2; } - elsif ( $1 eq "FLOATENV" ) { $FLOATENV = $2 ; } - elsif ( $1 eq "PICTUREENV" ) { $PICTUREENV = $2 ; } - elsif ( $1 eq "MATHENV" ) { $MATHENV = $2 ; } - elsif ( $1 eq "MATHREPL" ) { $MATHREPL = $2 ; } - elsif ( $1 eq "MATHARRENV" ) { $MATHARRENV = $2 ; } - elsif ( $1 eq "MATHARRREPL" ) { $MATHARRREPL = $2 ; } - elsif ( $1 eq "ARRENV" ) { $ARRENV = $2 ; } - elsif ( $1 eq "COUNTERCMD" ) { $COUNTERCMD = $2 ; } - else { die "Unknown variable $1 in assignment.";} -} - -if ( $mathmarkup == COARSE || $mathmarkup == WHOLE ) { - push(@MATHTEXTCMDLIST,qr/^MATHBLOCK(?:$MATHENV|$MATHARRENV|SQUAREBRACKET)$/); -} - - - -foreach $pkg ( @packagelist ) { - map { $packages{$_}="" } split(/,/,$pkg) ; -} - -if ($showpreamble) { - print "\nPreamble commands:\n"; - print $latexdiffpreamble ; -} - -if ($showsafe) { - print "\nCommands safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE (unless excluded):\n"; - print_regex_arr(@SAFECMDLIST); - print "\nCommands not safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE :\n"; - print_regex_arr(@SAFECMDEXCL); -} - -if ($showtext) { - print "\nCommands with last argument textual (unless excluded) and safe in every context:\n"; - print_regex_arr(@TEXTCMDLIST); - print "\nContext1 commands (last argument textual, command will be disabled in deleted passages, last argument will be shown as plain text):\n"; - print_regex_arr(@CONTEXT1CMDLIST); - print "\nContext2 commands (last argument textual, command and its argument will be disabled in deleted passages):\n"; - print_regex_arr(@CONTEXT2CMDLIST); - print "\nExclude list of Commands with last argument not textual (overrides patterns above):\n"; - print_regex_arr(@TEXTCMDEXCL); -} - - -if ($showconfig) { - print "Configuration variables:\n"; - print "MINWORDSBLOCK=$MINWORDSBLOCK\n"; - print "FLOATENV=$FLOATENV\n"; - print "PICTUREENV=$PICTUREENV\n"; - print "MATHENV=$MATHENV\n"; - print "MATHREPL=$MATHREPL\n"; - print "MATHARRENV=$MATHARRENV\n"; - print "MATHARRREPL=$MATHARRREPL\n"; - print "ARRENV=$ARRENV\n"; - print "COUNTERCMD=$COUNTERCMD\n"; -} -if ($showconfig || $showtext || $showsafe || $showpreamble) { - exit 0; } -if ( @ARGV != 2 ) { - print STDERR "2 and only 2 non-option arguments required. Write latexdiff -h to get help\n"; - exit(2); -} - -# Are extra spaces between command arguments permissible? -my $extraspace; -if ($allowspaces) { - $extraspace='\s*'; -} else { - $extraspace=''; -} - -# append context lists to text lists (as text property is implied) -push @TEXTCMDLIST, @CONTEXT1CMDLIST; -push @TEXTCMDLIST, @CONTEXT2CMDLIST; - -push @TEXTCMDLIST, @MATHTEXTCMDLIST if $mathmarkup==COARSE; - -# internal additions to SAFECMDLIST -push(@SAFECMDLIST, qr/^QLEFTBRACE$/, qr/^QRIGHTBRACE$/); - - -# Patterns. These are used by some of the subroutines, too -# I can only define them down here because value of extraspace depends on an option - my $pat0 = '(?:[^{}])*'; - my $pat1 = '(?:[^{}]|\{'.$pat0.'\})*'; - my $pat2 = '(?:[^{}]|\{'.$pat1.'\})*'; - my $pat3 = '(?:[^{}]|\{'.$pat2.'\})*'; - my $pat4 = '(?:[^{}]|\{'.$pat3.'\})*'; - my $pat5 = '(?:[^{}]|\{'.$pat4.'\})*'; - my $pat6 = '(?:[^{}]|\{'.$pat5.'\})*'; - my $brat0 = '(?:[^\[\]]|\\\[|\\\])*'; - my $abrat0 = '(?:[^<>])*'; - - my $quotemarks = '(?:\'\')|(?:\`\`)'; - my $punct='[0.,\/\'\`:;\"\?\(\)\[\]!~\p{IsNonAsciiPunct}\p{IsNonAsciiS}]'; - my $number='-?\d*\.\d*'; - my $mathpunct='[+=<>\-\|]'; - my $and = '&'; - my $coords= '[\-.,\s\d]*'; -# word: sequence of letters or accents followed by letter - my $word='(?:[-\w\d*]|\\\\[\"\'\`~^][A-Za-z\*])+'; - my $cmdleftright='\\\\(?:left|right|[Bb]igg?[lrm]?|middle)\s*(?:[<>()\[\]|]|\\\\(?:[|{}]|\w+))'; - - my $cmdoptseq='\\\\[\w\d\*]+'.$extraspace.'(?:(?:<'.$abrat0.'>|\['.$brat0.'\]|\{'. $pat6 . '\}|\(' . $coords .'\))'.$extraspace.')*'; - my $backslashnl='\\\\\n'; - my $oneletcmd='\\\\.\*?(?:\['.$brat0.'\]|\{'. $pat6 . '\})*'; - my $math='\$(?:[^$]|\\\$)*?\$|\\\\[(](?:.|\n)*?\\\\[)]'; -## the current maths command cannot cope with newline within the math expression - - my $comment='%.*?\n'; - my $pat=qr/(?:\A\s*)?(?:${and}|${quotemarks}|${number}|${word}|$cmdleftright|${cmdoptseq}|${math}|${backslashnl}|${oneletcmd}|${comment}|${punct}|${mathpunct}|\{|\})\s*/ ; - -# now we are done setting up and can start working -my ($oldfile, $newfile) = @ARGV; -# check for existence of input files -if ( ! -e $oldfile ) { - die "Input file $oldfile does not exist."; -} -if ( ! -e $newfile ) { - die "Input file $newfile does not exist."; -} - - -# set the labels to be included into the file -my ($oldtime,$newtime,$oldlabel,$newlabel); -if (defined($labels[0])) { - $oldlabel=$labels[0] ; -} else { - $oldtime=localtime((stat($oldfile))[9]); - $oldlabel="$oldfile " . " "x(length($newfile)-length($oldfile)) . $oldtime; -} -if (defined($labels[1])) { - $newlabel=$labels[1] ; -} else { - $newtime=localtime((stat($newfile))[9]); - $newlabel="$newfile " . " "x(length($oldfile)-length($newfile)) . $newtime; -} - -$encoding=guess_encoding($newfile) unless defined($encoding); - -$encoding = "utf8" if $encoding =~ m/^utf8/i ; -if (lc($encoding) eq "utf8" ) { - binmode(STDOUT, ":utf8"); - binmode(STDERR, ":utf8"); -} - -$old=read_file_with_encoding($oldfile,$encoding); -$new=read_file_with_encoding($newfile,$encoding); - - - - -# reset time -exetime(1); -($oldpreamble,$oldbody,$oldpost)=splitdoc($old,'\\\\begin\{document\}','\\\\end\{document\}'); - - -($newpreamble,$newbody,$newpost)=splitdoc($new,'\\\\begin\{document\}','\\\\end\{document\}'); - - -if ($flatten) { - $oldbody=flatten($oldbody,$oldpreamble,$oldfile,$encoding); - $newbody=flatten($newbody,$newpreamble,$newfile,$encoding); -} - - - - -my @auxlines; -if ( length $oldpreamble && length $newpreamble ) { - # pre-process preamble by looking for commands used in \maketitle (title, author, date etc commands) - # and marking up content with latexdiff markup - @auxlines=preprocess_preamble($oldpreamble,$newpreamble); - - @oldpreamble = split /\n/, $oldpreamble; - @newpreamble = split /\n/, $newpreamble; - - # If a command is defined in the preamble of the new file, and only uses safe commands, then it can be considered to be safe) (contribution S. Gouezel) - # Base this assessment on the new preamble - add_safe_commands($newpreamble); - - # get a list of packages from preamble if not predefine - %packages=list_packages(@newpreamble) unless %packages; - ### if ( %packages ) {print STDERR "DEBUG Packages: ",%packages,"\n" ;} - if (defined $packages{"hyperref"} ) { - # deleted lines should not generate or appear in link names: - print STDERR "hyperref package detected.\n" if $verbose ; - $latexdiffpreamble =~ s/\{\\DIFadd\}/{\\DIFaddtex}/g; - $latexdiffpreamble =~ s/\{\\DIFdel\}/{\\DIFdeltex}/g; - $latexdiffpreamble .= join "\n",(extrapream("HYPERREF"),""); - } - - if (defined $packages{"units"} && ( $latexdiffpreamble =~ /\\RequirePackage(?:\[$brat0\])?\{ulem\}/ ) ) { - # protect inlined maths environments by surrounding with an \mbox - # this is done to get around an incompatibility between the ulem and units package - # where spaces in the argument to underlined or crossed-out \unit commands cause an error message - print STDERR "units package detected at the same time as style using ulem.\n" if $verbose ; - $MBOXINLINEMATH=1; - } - - print STDERR "Differencing preamble.\n" if $verbose; - - # insert dummy first line such that line count begins with line 1 (rather than perl's line 0) - just so that line numbers inserted by linediff are correct - unshift @newpreamble,''; - unshift @oldpreamble,''; - @diffpreamble = linediff(\@oldpreamble, \@newpreamble); - # remove dummy line again - shift @diffpreamble; - # add filenames, modification time and latexdiff mark - defined($nolabel) or splice @diffpreamble,1,0, - "%DIF LATEXDIFF DIFFERENCE FILE", - ,"%DIF DEL $oldlabel", - "%DIF ADD $newlabel"; - if ( @auxlines ) { - push @diffpreamble,"%DIF DELETED TITLE COMMANDS FOR MARKUP"; - push @diffpreamble,join("\n",@auxlines); - } - if ( $earlylatexdiffpreamble) { - # insert latexdiff command directly after documentclass at beginning of preamble - # note that grep is only run for its side effect - ( grep { s/^([^%]*\\documentclass.*)$/$1$latexdiffpreamble/ } @diffpreamble )==1 or die "Could not find documentclass statement in preamble"; - } else { - # insert latexdiff commands at the end of preamble (default behaviour) - push @diffpreamble,$latexdiffpreamble; - } - push @diffpreamble,'\begin{document}'; -} -elsif ( !length $oldpreamble && !length $newpreamble ) { - @diffpreamble=(); -} else { - print STDERR "Either both texts must have preamble or neither text must have the preamble.\n"; - exit(2); -} - -# Special: treat all cite commands as safe except in UNDERLINE and FONTSTRIKE mode -# (there is a conflict between citation and ulem package, see -# package documentation) -# Use post-processing -# and $packages{"apacite"}!~/natbibpapa/ -my ($citpat,$citpatsafe); - -if ( defined $packages{"apacite"} ) { - print STDERR "DEBUG apacite citation commands\n" if $debug; - $citpatsafe=qr/^(?:mask)?(?:full|short)?cite(?:A|author|year)?(?:NP)?$/; - $citpat='(?:mask)?(?:full|short|no)?cite(?:A|author|year|meta)?(?:NP)?'; -} else { - # citation command pattern for all other citation schemes - $citpatsafe=qr/^cite.*$/; - $citpat='(?:cite\w*|nocite)'; -}; - -if ( uc($type) ne "UNDERLINE" && uc($type) ne "FONTSTRIKE" && uc($type) ne "CULINECHBAR" ) { - push (@SAFECMDLIST, $citpatsafe); -} else { - ### Experimental: disable text and emph commands - push (@SAFECMDLIST, $citpatsafe) unless $disablecitmark; - push(@SAFECMDEXCL, qr/^emph$/, qr/^text..$/); - # replace \cite{..} by \mbox{\cite{..}} in added or deleted blocks in post-processing - if ( uc($subtype) eq "COLOR" or uc($subtype) eq "DVIPSCOL" ) { - # remove \cite command again from list of safe commands - pop @SAFECMDLIST; - # deleted cite commands - $CITE2CMD=$citpat unless $disablecitmark ; # \cite-type commands which should be reinstated in deleted blocks - } else { - $CITECMD=$citpat unless $disablecitmark ; # \cite commands which need to be protected within an mbox in UNDERLINE and other modes using ulem - } -} -$CITECMD=$citpat if $enablecitmark ; # as above for explicit selection - -print STDERR "CITECMD:|$CITECMD|\n" if $debug; - -if (defined $packages{"amsmath"} or defined $packages{"amsart"} or defined $packages{"amsbook"} ) { - print STDERR "amsmath package detected.\n" if $verbose ; - $MATHARRREPL='align*'; -} - -print STDERR "Preprocessing body. " if $verbose; -my ($oldleadin,$newleadin)=preprocess($oldbody,$newbody); - - -# run difference algorithm -@diffbody=bodydiff($oldbody, $newbody); -$diffbo=join("",@diffbody); -if ( $debug ) { - open(RAWDIFF,">","latexdiff.debug.bodydiff"); - print RAWDIFF $diffbo; - close(RAWDIFF); -} -print STDERR "(",exetime()," s)\n","Postprocessing body. \n " if $verbose; -postprocess($diffbo); -$diffall =join("\n",@diffpreamble) ; -# add visible labels -if (defined($visiblelabel)) { - # Give information right after \begin{document} (or at the beginning of the text for files without preamble - ### if \date command is used, add information to \date argument, otherwise give right after \begin{document} - ### $diffall=~s/(\\date$extraspace(?:\[$brat0\])?$extraspace)\{($pat6)\}/$1\{$2 \\ LATEXDIFF comparison \\ Old: $oldlabel \\ New: $newlabel \}/ or - $diffbo = "\\begin{verbatim}LATEXDIFF comparison\nOld: $oldlabel\nNew: $newlabel\\end{verbatim}\n$diffbo" ; -} - -$diffall .= "$newleadin$diffbo" ; -$diffall .= "\\end{document}$newpost" if length $newpreamble ; -if ( lc($encoding) ne "utf8" && lc($encoding) ne "ascii" ) { - print STDERR "Encoding output file to $encoding\n" if $verbose; - $diffall=Encode::encode($encoding,$diffall); - binmode STDOUT; -} -print $diffall; - - -print STDERR "(",exetime()," s)\n","Done.\n" if $verbose; - - - -## guess_encoding(filename) -## reads the first 20 lines of filename and looks for call of inputenc package -## if found, return the option of this package (encoding), otherwise return ascii -sub guess_encoding { - my ($filename)=@_; - my ($i,$enc); - open (FH, $filename) or die("Couldn't open $filename: $!"); - $i=0; - while () { - next if /^\s*%/; # skip comment lines - if (m/\\usepackage\[(\w*?)\]\{inputenc\}/) { - close(FH); - return($1); - } - last if (++$i > 20 ); # scan at most 20 non-comment lines - } - close(FH); - return("ascii"); -} - - -sub read_file_with_encoding { - my ($output); - my ($filename, $encoding) = @_; - - if (lc($encoding) eq "utf8" ) { - open (FILE, "<:utf8",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } elsif ( lc($encoding) eq "ascii") { - open (FILE, $filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } else { - require Encode; - open (FILE, "<",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - print STDERR "Converting $filename from $encoding to utf8\n" if $verbose; - $output=Encode::decode($encoding,$output); - } - close FILE; - if ($^O eq "linux" ) { - $output =~ s/\r\n/\n/g ; - } - return $output; -} - -# %packages=list_packages(@preamble) -# scans the arguments for \documentclass,\RequirePackage and \usepackage statements and constructs a hash -# whose keys are the included packages, and whose values are the associated optional arguments -sub list_packages { - my (@preamble)=@_; - my %packages=(); - foreach $line ( @preamble ) { - # get rid of comments - $line=~s/(?catfile($dirname,$fname), "\n" if $debug; - # content of file becomes replacement value (use recursion), add \newpage if the command was include - ###$replacement=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - $replacement=flatten(read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding), $preamble,$filename,$encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - # \include always starts a new page; use explicit \newpage command to simulate this - $begline=(defined($1)? $1 : "") ; - $newpage=(defined($3)? " \\newpage " : "") ; - "$begline$newpage$replacement$newpage"; - }/exgm; - # replace bibliography with bbl file if it exists - $text=~s/(^(?:[^%\n]|\\%)*)\\bibliography{(.*?)}/{ - if ( -f $bblfile ){ - $replacement=read_file_with_encoding(File::Spec->catfile($bblfile), $encoding); - } else { - warn "Bibliography file $bblfile cannot be found. No flattening of \\bibliography done. Run bibtex on old and new files first"; - $replacement="\\bibliography{$2}"; - } - $begline=(defined($1)? $1 : "") ; - "$begline$replacement"; - }/exgm; - # replace subfile with contents (subfile package) - $text=~s/(^(?:[^%\n]|\\%)*)\\subfile{(.*?)}/{ - $fname = $2; - # # add tex extension unless there is a three letter extension already - $fname .= ".tex" unless $fname =~ m|\.\w{3}|; - print STDERR "DEBUG Beg of line match |$1|\n" if defined($1) && $debug ; - print STDERR "Include file as subfile $fname\n" if $verbose; - print STDERR "DEBUG looking for file ",File::Spec->catfile($dirname,$fname), "\n" if $debug; - # content of file becomes replacement value (use recursion) - # now strip away everything outside and including \begin{document} and \end{document} pair# - # # note: no checking for comments is made - $subfile=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - ($subpreamble,$subbody,$subpost)=splitdoc($subfile,'\\\\begin\{document\}','\\\\end\{document\}'); - $replacement=flatten($subbody, $preamble,$filename,$encoding); - $begline=(defined($1)? $1 : "") ; - "$begline$replacement"; - }/exgm; - - return($text); -} - - -# print_regex_arr(@arr) -# prints regex array without x-ism expansion put in by pearl to stdout -sub print_regex_arr { - my $dumstring; - $dumstring = join(" ",@_); # PERL generates string (?-xism:^ref$) for quoted refex ^ref$ - $dumstring =~ s/\(\?-xism:\^(.*?)\$\)/$1/g; # remove string and ^,$ marks before output - print $dumstring,"\n"; -} - - -# @lines=extrapream($type) -# reads line from appendix (end of file after __END__ token) -sub extrapream { - my $type; - my @retval=("%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - my ($copy); - - while (@_) { - $copy=0; - $type=shift ; - if ( -f $type || lc $type eq '/dev/null' ) { - open (FILE,$type) or die "Cannot open preamble file $type: $!"; - print STDERR "Reading preamble file $type\n" if $verbose ; - while () { - chomp ; - if ( $_ =~ m/%DIF PREAMBLE/ ) { - push (@retval,"$_"); - } else { - push (@retval,"$_ %DIF PREAMBLE"); - } - } - } - else { # not (-f $type) - $type=uc($type); # upcase argument - print STDERR "Preamble Internal Type $type\n" if $verbose; - while () { - if ( m/^%DIF $type/ ) { - $copy=1; } - elsif ( m/^%DIF END $type/ ) { - last; } - chomp; - push (@retval,"$_ %DIF PREAMBLE") if $copy; - } - if ( $copy == 0 ) { - print STDERR "\nPreamble style $type not implemented.\n"; - print STDERR "Write latexdiff -h to get help with available styles\n"; - exit(2); - } - seek DATA,0,0; # rewind DATA handle to file begin - } - } - push (@retval,"%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - return @retval; -} - - -# ($part1,$part2,$part3)=splitdoc($text,$word1,$word2) -# splits $text into 3 parts at $word1 and $word2. -# if neither $word1 nor $word2 exist, $part1 and $part3 are empty, $part2 is $text -# If only $word1 or $word2 exist but not the other, output an error message. - -# NB this version avoids $` and $' for performance reason although it only makes a tiny difference -# (in one test gain a tenth of a second for a 30s run) -sub splitdoc { - my ($text,$word1,$word2)=@_; - my ($part1,$part2,$part3)=("","",""); - my ($rest,$pos); - - if ( $text =~ m/(^[^%]*)($word1)/mg ) { - $pos=pos $text; - $part1=substr($text,0,$pos-length($2)); - $rest=substr($text,$pos); - if ( $rest =~ m/(^[^%]*)($word2)/mg ) { - $pos=pos $rest; - $part2=substr($rest,0,$pos-length($2)); - $part3=substr($rest,$pos); - } - else { - die "$word1 and $word2 not in the correct order or not present as a pair." ; - } - } else { - $part2=$text; - die "$word2 present but not $word1." if ( $text =~ m/(^[^%]*)$word2/ms ); - } - return ($part1,$part2,$part3); -} - - - - - -# bodydiff($old,$new) -sub bodydiff { - my ($oldwords, $newwords) = @_; - my @retwords; - - print STDERR "(",exetime()," s)\n","Splitting into latex tokens \n" if $verbose; - print STDERR "Parsing $oldfile \n" if $verbose; - my @oldwords = splitlatex($oldwords); - print STDERR "Parsing $newfile \n" if $verbose; - my @newwords = splitlatex($newwords); - - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - print STDERR "(",exetime()," s)\n","Pass 1: Expanding text commands and merging isolated identities with changed blocks " if $verbose; - pass1(\@oldwords, \@newwords); - - - print STDERR "(",exetime()," s)\n","Pass 2: inserting DIF tokens and mark up. " if $verbose; - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold2.tex"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew2.tex"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - @retwords=pass2(\@oldwords, \@newwords); - - return(@retwords); -} - - - - -# @words=splitlatex($string) -# split string according to latex rules -# Each element of words is either -# a word (including trailing spaces and punctuation) -# a latex command -sub splitlatex { - my ($string) = @_ ; - # if input is empty, return empty list - length($string)>0 or return (); - - my @retval=($string =~ m/$pat/osg); - - if (length($string) != length(join("",@retval))) { - print STDERR "\nWARNING: Inconsistency in length of input string and parsed string:\n This often indicates faulty or non-standard latex code.\n In many cases you can ignore this and the following warning messages.\n Note that character numbers in the following are counted beginning after \\begin{document} and are only approximate." unless $ignorewarnings; - print STDERR "DEBUG Original length ",length($string)," Parsed length ",length(join("",@retval)),"\n" if $debug; - print STDERR "DEBUG Input string: |$string|\n" if (length($string)<500) && $debug; - print STDERR "DEBUG Token parsing: |",join("+",@retval),"|\n" if (length($string)<500) && $debug ; - @retval=(); - # slow way only do this if other m//sg method fails - my $last = 0; - while ( $string =~ m/$pat/osg ) { - my $match=$&; - if ($last + length $& != pos $string ) { - my $pos=pos($string); - my $offset=30<$last ? 30 : $last; - my $dum=substr($string,$last-$offset,$pos-$last+2*$offset); - my $dum1=$dum; - my $cnt=$#retval; - my $i; - $dum1 =~ s/\n/ /g; - unless ($ignorewarnings) { - print STDERR "\n$dum1\n"; - print STDERR " " x 30,"^" x ($pos-$last)," " x 30,"\n"; - print STDERR "Missing characters near word " . (scalar @retval) . " character index: " . $last . "-" . pos($string) . " Length: " . length($match) . " Match: |$match| (expected match marked above).\n"; - } - # put in missing characters `by hand' - push (@retval, substr($dum,$offset,$pos-$last-length($match))); -# Note: there seems to be a bug in substr with utf8 that made the following line output substr which were too long, -# using dum instead appears to work -# push (@retval, substr($string,$last, pos($string)-$last-length($match))); - } - push (@retval, $match); - $last=pos $string; - } - - } - return @retval; -} - - -# pass1( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Where an common-subsequence block is flanked by deleted or appended blocks, -# and is shorter than $MINWORDSBLOCK words it is appended -# to the last deleted or appended word. If the block contains tokens other than words -# or punctuation it is not merged. -# Deleted or appended block consisting of words and safe commands only are -# also merged, to prevent break-up in pass2 (after previous isolated words have been removed) -# If there are commands with textual arguments (e.g. \caption) both in corresponding -# appended and deleted blocks split them such that the command and opening bracket -# are one token, then the rest is split up following standard rules, and the closing -# bracket is a separate token, ie. turn -# "\caption{This is a textual argument}" into -# ("\caption{","This ","is ","a ","textual ","argument","}") -# No return value. Destructively changes sequences -sub pass1 { - my $seq1 = shift ; - my $seq2 = shift ; - - my $len1 = scalar @$seq1; - my $len2 = scalar @$seq2; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - - my ($last1,$last2)=(-1,-1) ; - my $cnt=0; - my $block=[]; - my $addblock=[]; - my $delblock=[]; - my $todo=[]; - my $instruction=[]; - my $i; - my (@delmid,@addmid,@dummy); - - my ($addcmds,$delcmds,$matchindex); - my ($addtextblocks,$deltextblocks); - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $adddiscard = sub { - if ($cnt > 0 ) { - $matblkcnt++; - # just after an unchanged block -# print STDERR "Unchanged block $cnt, $last1,$last2 \n"; - if ($cnt < $MINWORDSBLOCK - && $cnt==scalar ( - grep { /^$wpat/ || ( /^\\([\w\d\*]+)((?:\[$brat0\]|\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && scalar(@dummy=split(" ",$2))<3 ) } - @$block) ) { - # merge identical blocks shorter than $MINWORDSBLOCK - # and only containing ordinary words - # with preceding different word - # We cannot carry out this merging immediately as this - # would change the index numbers of seq1 and seq2 and confuse - # the algorithm, instead we store in @$todo where we have to merge - push(@$todo, [ $last1,$last2,$cnt,@$block ]); - } - $block = []; - $cnt=0; $last1=-1; $last2=-1; - } - }; - my $discard=sub { $deltokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$delblock,[ $seq1->[$_[0]],$_[0] ]); - $last1=$_[0] }; - - my $add = sub { $addtokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$addblock,[ $seq2->[$_[1]],$_[1] ]); - $last2=$_[1] }; - - my $match = sub { $mattokcnt++; - if ($cnt==0) { # first word of matching sequence after changed sequence or at beginning of word sequence - $deltextblocks = extracttextblocks($delblock); - $delblkcnt++ if scalar @$delblock; - $addtextblocks = extracttextblocks($addblock); - $addblkcnt++ if scalar @$addblock; - - $delcmds = extractcommands($delblock); - $addcmds = extractcommands($addblock); - # keygen(third argument of _longestCommonSubsequence) implies to sort on command (0th elements of $addcmd elements) - # the calling format for longestCommonSubsequence has changed between versions of - # Algorithm::Diff so we need to check which one we are using - if ( $algodiffversion > 1.15 ) { - ### Algorithm::Diff 1.19 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, 0, sub { $_[0]->[0] } ); - } else { - ### Algorithm::Diff 1.15 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, sub { $_[0]->[0] } ); - } - - for ($i=0 ; $i<=$#$matchindex ; $i++) { - if (defined($matchindex->[$i])){ - $j=$matchindex->[$i]; - @delmid=splitlatex($delcmds->[$i][3]); - @addmid=splitlatex($addcmds->[$j][3]); - while (scalar(@$deltextblocks) && $deltextblocks->[0][0]<$delcmds->[$i][1]) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) }; - push(@$todo, [$index,-1,$cnt,@$block]); - } - push(@$todo, [ $delcmds->[$i][1],-1,-1,$delcmds->[$i][2],@delmid,$delcmds->[$i][4]]); - - while (scalar(@$addtextblocks) && $addtextblocks->[0][0]<$addcmds->[$j][1]) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - push(@$todo, [ -1,$addcmds->[$j][1],-1,$addcmds->[$j][2],@addmid,$addcmds->[$j][4]]); - } - } - # mop up remaining textblocks - while (scalar(@$deltextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) } ; - push(@$todo, [$index,-1,$cnt,@$block]); - } - while (scalar(@$addtextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - - $addblock=[]; - $delblock=[]; - } - push(@$block,$seq2->[$_[1]]); - $cnt++ }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - - - # now carry out the merging/splitting. Refer to elements relative from - # the end (with negative indices) as these offsets don't change before the instruction is executed - # cnt>0: merged small unchanged groups with previous changed blocks - # cnt==-1: split textual commands into components - foreach $instruction ( @$todo) { - ($last1,$last2,$cnt,@$block)=@$instruction ; - if ($cnt>=0) { - splice(@$seq1,$last1-$len1,1+$cnt,join("",$seq1->[$last1-$len1],@$block)) if $last1>=0; - splice(@$seq2,$last2-$len2,1+$cnt,join("",$seq2->[$last2-$len2],@$block)) if $last2>=0; - } else { - splice(@$seq1,$last1-$len1,1,@$block) if $last1>=0; - splice(@$seq2,$last2-$len2,1,@$block) if $last2>=0; - } - } - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens in $matblkcnt blocks.\n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } -} - - -# extracttextblocks(\@blockindex) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [[ $index, $textblock, $cnt ], .. -# where $index index of block to be merged -# $textblock contains all the words to be merged with the word at $index (but does not contain this word) -# $cnt is length of block -# -# requires: iscmd -# -sub extracttextblocks { - my $block=shift; - my ($i,$token,$index); - my $textblock=[]; - my $last=-1; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # store pure text blocks - if ($token =~ /$wpat/ || ( $token =~/^\\([\w\d\*]+)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && !iscmd($1,\@TEXTCMDLIST,\@TEXTCMDEXCL))) { - # we have text or a command which can be treated as text - if ($last<0) { - # new pure-text block - $last=$index; - } else { - # add to pure-text block - push(@$textblock, $token); - } - } else { - # it is not text - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - $textblock=[]; - $last=-1; - } - } - # finish processing a possibly unfinished block before returning - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - return($retval) -} - - - -# extractcommands( \@blockindex ) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [ [ "\cmd1", index, "\cmd1[optarg]{arg1}{", "arg2" ,"} " ],.. -# where index is just taken from input array -# command must have a textual argument as last argument -# -# requires: iscmd -# -sub extractcommands { - my $block=shift; - my ($i,$token,$index,$cmd,$open,$mid,$closing); - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: \cmd - # $3: last argument - # $4: } + trailing spaces - if ( ( $token =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL) ) { - # push(@$retval,[ $2,$index,$1,$3,$4 ]); - ($cmd,$open,$mid,$closing) = ($2,$1,$3,$4) ; - $closing =~ s/\}/\\RIGHTBRACE/ ; - push(@$retval,[ $cmd,$index,$open,$mid,$closing ]); - } - } - return $retval; -} - -# iscmd($cmd,\@regexarray,\@regexexcl) checks -# return 1 if $cmd matches any of the patterns in the -# array $@regexarray, and none of the patterns in \@regexexcl, otherwise return 0 -sub iscmd { - my ($cmd,$regexar,$regexexcl)=@_; - my ($ret)=0; - foreach $pat ( @$regexar ) { - if ( $cmd =~ m/^${pat}$/ ) { - $ret=1 ; - last; - } - } - return 0 unless $ret; - foreach $pat ( @$regexexcl ) { - return 0 if ( $cmd =~ m/^${pat}$/ ); - } - return 1; -} - - -# pass2( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Mark begin and end of deleted and appended sequences with tags $DELOPEN and $DELCLOSE -# and $ADDOPEN and $ADDCLOSE, respectively, however exclude { } & and all comands, unless -# they match an element of the whitelist (SAFECMD) -# For words in TEXTCMD but not in SAFECMD, enclose interior with $ADDOPEN and $ADDCLOSE brackets -# Deleted comment lines are marked with %DIF < -# Added comment lines are marked with %DIF > -sub pass2 { - my $seq1 = shift ; - my $seq2 = shift ; - - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $retval = []; - my $delhunk = []; - my $addhunk = []; - - my $discard = sub { $deltokcnt++; - push ( @$delhunk, $seq1->[$_[0]]) }; - - my $add = sub { $addtokcnt++; - push ( @$addhunk, $seq2->[$_[1]]) }; - - my $match = sub { $mattokcnt++; - if ( scalar @$delhunk ) { - $delblkcnt++; - # mark up changes, but comment out commands - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk); - $delhunk = []; - } - if ( scalar @$addhunk ) { - $addblkcnt++; - # we mark up changes, but simply quote commands - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk); - $addhunk = []; - } - push(@$retval,$seq2->[$_[1]]) }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - # clear up unprocessed hunks - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk) if scalar @$delhunk; - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk) if scalar @$addhunk; - - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens. \n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } - - return(@$retval); -} - -# marktags($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,\@block) -# returns ($openmark,$open,$block,$close,$closemark) if @block only contains no commands (except white-listed ones), -# braces, ampersands, or comments -# mark comments with $comment -# exclude all other exceptions from scope of open, close like this -# ($openmark, $open,...,$close, $opencmd,command, command,$closecmd, $open, ..., $close, $closemark) -# If $opencmd begins with "%" marktags assumes it is operating on a deleted block, otherwise on an added block -sub marktags { - my ($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,$block)=@_; - my $word; - my (@argtext); - my $retval=[]; - my $noncomment=0; - my $cmd=-1; # -1 at beginning 0: last token written is a ordinary word - # 1: last token written is a command - # for keeping track whether we are just in a command sequence or in a word sequence - my $cmdcomment= ($opencmd =~ m/^%/); # Flag to indicate whether opencmd is a comment (i.e. if we intend to simply comment out changed commands) - my ($command,$commandword,$closingbracket) ; # temporary variables needed below to remember sub-pattern matches - -# split this block to flatten out sequences joined in pass1 - @$block=splitlatex(join "",@$block); - foreach (@$block) { - $word=$_; - if ( $word =~ s/^%/%$comment/ ) { - # a comment - if ($cmd==1) { - push (@$retval,$closecmd) ; - $cmd=-1; - } - push (@$retval,$word); - next; - } - if (! $noncomment) { - push (@$retval,$openmark); - $noncomment=1; - } - # negative lookahead pattern (?!) in second clause is put in to avoid mathcing \( .. \) patterns - # also note that second pattern will match \\ - # Note: the second pattern should really be $word =~ /^\\(?!\()(\\|[\w*@]+)/, ie * replaced by + - # and then all commands \" \' etc declared safe. But as I don't have a complete list of one letter - # commands, and nobody has complained so far, I will eave this as is - if ( $word =~ /^[&{}\[\]]/ || ( $word =~ /^\\(?!\()(\\|[\w*@]*)/ && !iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL)) ) { - # word is a command or other significant token (not in SAFECMDLIST) - ## same conditions as in subroutine extractcommand: - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: cmd - # $3: last argument - # $4: } + trailing spaces - ### pre-0.3 if ( ( $token =~ m/^(\\([\w\d\*]+)(?:\[$brat0\]|\{$pat6\})*\{)($pat6)(\}\s*)$/so ) - if ( ( $word =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && (iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL)|| iscmd($2,\@MATHTEXTCMDLIST,\@MATHTEXTCMDEXCL)) - && ( !$cmdcomment || !iscmd($2,\@CONTEXT2CMDLIST, \@CONTEXT2CMDEXCL) ) ) { - # Condition 1: word is a command? - if yes, $1,$2,.. will be set as above - # Condition 2: word is a text command - we mark up the interior of the word. There is a separate check for MATHTEXTCMDLIST - # because for $mathmarkup=WHOLE, the commands should not be split in pass1 (ie. math mode commands are not in - # TEXTCMDLIST, but the interior of MATHTEXT commands should be highlighted in both deleted and added blocks - # Condition 3: But if we are in a deleted block ($cmdcomment=1) and - # $2 (the command) is in context2, just treat it as an ordinary command (i.e. comment it open with $opencmd) - # Because we do not want to disable this command - # here we do not use $opencmd and $closecmd($opencmd is empty) - if ($cmd==1) { - push (@$retval,$closecmd) ; - } elsif ($cmd==0) { - push (@$retval,$close) ; - } - $command=$1; $commandword=$2; $closingbracket=$4; - @argtext=splitlatex($3); # split textual argument into tokens - # and mark it up (but we do not need openmark and closemark) - # insert command with initial arguments, marked-up final argument, and closing bracket - if ( $cmdcomment && iscmd($commandword,\@CONTEXT1CMDLIST, \@CONTEXT1CMDEXCL) ) { - # context1cmd in a deleted environment; delete command itself but keep last argument, marked up - push (@$retval,$opencmd); - $command =~ s/\n/\n${opencmd}/sg ; # repeat opencmd at the beginning of each line - # argument, note that the additional comment character is included - # to suppress linebreak after opening parentheses, which is important - # for latexrevise - push (@$retval,$command,"%\n{$AUXCMD\n",marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } elsif ( iscmd($commandword,,\@MATHTEXTCMDLIST, \@MATHTEXTCMDEXCL) ) { - # MATHBLOCK pseudo command: consider all commands safe, except & and \\ - # Keep these commands even in deleted blocks, hence set $opencmd and $closecmd (5th and 6th argument of marktags) to - # "" - local @SAFECMDLIST=(".*"); - local @SAFECMDEXCL=('\\','\\\\',@UNSAFEMATHCMD); - push(@$retval,$command,marktags("","",$open,$close,"","",$comment,\@argtext)#@argtext - ,$closingbracket); - } else { - # normal textcmd or context1cmd in an added block - push (@$retval,$command,marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } - push (@$retval,$AUXCMD,"\n") if $cmdcomment ; - $cmd=-1 ; - } else { - # ordinary command - push (@$retval,$opencmd) if $cmd==-1 ; - push (@$retval,$close,$opencmd) if $cmd==0 ; - $word =~ s/\n/\n${opencmd}/sg if $cmdcomment ; # if opencmd is a comment, repeat this at the beginning of every line - push (@$retval,$word); - $cmd=1; - } - } else { - # just an ordinary word or word in SAFECMD - push (@$retval,$open) if $cmd==-1 ; - push (@$retval,$closecmd,$open) if $cmd==1 ; - push (@$retval,$word); - $cmd=0; - } - } - push (@$retval,$close) if $cmd==0; - push (@$retval,$closecmd) if $cmd==1; - - push (@$retval,$closemark) if ($noncomment); - return @$retval; -} - -# preprocess($string, ..) -# carry out the following pre-processing steps for all arguments: -# 1. Remove leading white-space -# Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE -# #. Change {,} in comments to \CLEFTBRACE, \CRIGHTBRACE -# 2. mark all first empty line (in block of several) with \PAR tokens -# 3. Convert all '\%' into '\PERCENTAGE ' and all '\$' into \DOLLAR to make parsing regular expressions easier -# 4. Convert all \verb|some verbatim text| commands (where | can be an arbitrary character) -# into \verb{hash} -# 5. Convert \begin{verbatim} some verbatim text \end{verbatim} into \verbatim{hash} -# 6. Convert _n into \SUBSCRIPTNB{n} and _{nnn} into \SUBSCRIPT{nn} -# 7. Convert ^n into \SUPERSCRIPTNB{n} and ^{nnn} into \SUPERSCRIPT{nn} -# 8. a. Convert $$ $$ into \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} -# b. Convert \[ \] into \begin{SQUAREBRACKET} \end{SQUAREBRACKET} -# 9. Convert all picture environmentent (\begin{PICTUREENV} .. \end{PICTUREENV} \PICTUREBLOCKenv -# For --block-math-markup option -convert all \begin{MATH} .. \end{MATH} -# into \MATHBLOCKmath{...} commands, where MATH/math is any valid math environment - -# 10. Add final token STOP to the very end. This is put in because the algorithm works better if the last token is identical. This is removed again in postprocessing. -# -# NB: step 6 and 7 is likely to convert some "_" inappropriately, e.g. in file -# names or labels but it does not matter because they are converted back in the postprocessing step -# Returns: leading white space removed in step 1 -sub preprocess { - my @leadin=() ; - for (@_) { - s/^(\s*)//s; - push(@leadin,$1); - # Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE - s/(?{$hstr}) && $string ne $hash->{$hstr}) { - warn "Repeated hash value for verbatim mode in spite of different content."; - $hstr="-$hstr"; - } - $hash->{$hstr}=$string; - return($hstr); -} - -#string=fromhash(\%hash,$fromstring) -# restores string value stored in hash -#string=fromhash(\%hash,$fromstring,$prependstring) -# additionally begins each line with prependstring -sub fromhash { - my ($hash,$hstr)=($_[0],$_[1]); - my $retstr=$hash->{$hstr}; - if ( $#_ >= 2) { - $retstr =~ s/^/$_[2]/mg; - } - return $retstr; -} - - -# postprocess($string, ..) -# carry out the following post-processing steps for all arguments: -# * Remove STOP token from the end -# * Replace \RIGHTBRACE by } -# * change citation commands within comments to protect from processing (using marker CITEDIF) -# 1. Check all deleted blocks: -# a.where a deleted block contains a matching \begin and -# \end environment (these will be disabled by a %DIFDELCMD statements), for selected environments enable -# these commands again (such that for example displayed math in a deleted equation -# is properly within math mode. For math mode environments replace numbered equation -# environments with their display only variety (so that equation numbers in new file and -# diff file are identical). Where the correct type of math environment cannot be determined -# use a place holder MATHMODE -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file -# Replace all MATHMODE environment commands by the correct environment to achieve matching -# pairs -# c. Convert MATHBLOCKmath commands to their uncounted numbers (e.g. convert equation -> displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL -# d. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# For added blocks: -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# 2. If --block-math-markup option set: Convert \MATHBLOCKmath{..} commands back to environments -# -# Convert all PICTUREblock{..} commands back to the appropriate environments -# 3. Convert DIFadd, DIFdel, DIFFaddbegin , ... into FL varieties -# within floats (currently recognised float environments: plate,table,figure -# plus starred varieties). -# 4. Remove empty %DIFDELCMD < lines -# 4. Convert \begin{SQUAREBRACKET} \end{SQUAREBRACKET} into \[ \] -# Convert \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} into $$ $$ -# 5. Convert \SUPERSCRIPTNB{n} into ^n and \SUPERSCRIPT{nn} into ^{nnn} -# 6. Convert \SUBSCRIPTNB{n} into _n and \SUBCRIPT{nn} into _{nnn} -# 7. Expand hashes of verb and verbatim environments -# 8. Convert '\PERCENTAGE ' back into '\%' and '\DOLLAR ' into '\$' -# 9.. remove all \PAR tokens -# 10. package specific processing: endfloat: make sure \begin{figure} and \end{figure} are always -# on a line by themselves, similarly for table environment -# 4, undo renaming of the \begin, \end,{,} in comments -# Change \QLEFTBRACE, \QRIGHTBRACE to \{,\} -# -# Note have to manually synchronize substitution commands below and -# DIF.. command names in the header -sub postprocess { - my ($begin,$len,$cnt,$float,$delblock,$addblock); - # second level blocks - my ($begin2,$cnt2,$len2,$eqarrayblock,$mathblock); - - for (@_) { - - # change $'s in comments to something harmless - 1 while s/(%.*)\$/$1DOLLARDIF/mg ; - - # Remove final STOP token - s/ STOP$//; - # Replace \RIGHTBRACE by } - s/\\RIGHTBRACE/}/g; - - # change citation commands within comments to protect from processing - if ($CITECMD){ - 1 while s/(%.*)\\($CITECMD)/$1\\CITEDIF$2/m ; - } - # Check all deleted blocks: where a deleted block contains a matching \begin and - # \end environment (these will be disabled by a %DIFDELCMD statements), enable - # these commands again (such that for example displayed math in a deleted equation - # is properly within math mode. For math mode environments replace numbered equation - # environments with their display only variety (so that equation numbers in new file and - # diff file are identical - while ( m/\\DIFdelbegin.*?\\DIFdelend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $delblock=$&; - - - ### (.*?[^\n]?)\n? construct is necessary to avoid empty lines in math mode, which result in - ### an error - # displayed math environments - if ($mathmarkup == FINE ) { - $delblock=~ s/(\%DIFDELCMD < \s*\\begin\{((?:$MATHENV)|SQUAREBRACKET)\}.*?(?:$DELCMDCLOSE|\n))(.*?[^\n]?)\n?(\%DIFDELCMD < \s*\\end\{\2\})/\\begin{$MATHREPL}$AUXCMD\n$1$3\n\\end{$MATHREPL}$AUXCMD\n$4/sg; - # also transform the opposite pair \end{displaymath} .. \begin{displaymath} but we have to be careful not to interfere with the results of the transformation in the line directly above - ### pre-0.42 obsolete version which did not work on eqnarray test $delblock=~ s/(? displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL - $delblock=~ s/\\MATHBLOCK($MATHENV)\{($pat6)\}/\\MATHBLOCK$MATHREPL\{$2\}/sg; - $delblock=~ s/\\MATHBLOCK($MATHARRENV)\{($pat6)\}/\\MATHBLOCK$MATHARRREPL\{$2\}/sg; - } - - -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file - $delblock=~ s/\\($COUNTERCMD)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*\s*${AUXCMD}\n)/\\$1$2\\addtocounter{$1}{-1}${AUXCMD}\n/sg ; - - -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es - while ( $delblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($delblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($delblock,$begin2,$len2)=$mathblock; - pos($delblock) = $begin2 + length($mathblock); - } - if ($CITE2CMD) { - $delblock=~s/($DELCMDOPEN\s*\\($CITE2CMD)(.*)$DELCMDCLOSE)/ - # Replacement code - {my ($aux,$all); - $aux=$all=$1; - $aux=~s#\n?($DELCMDOPEN|$DELCMDCLOSE)##g; - $all."$aux$AUXCMD\n";}/sge; - } - # or protect \cite commands with \mbox - if ($CITECMD) { - $delblock=~s/(\\($CITECMD)${extraspace}(?:<$abrat0>${extraspace})?(?:\[$brat0\]${extraspace}){0,2}\{$pat6\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } - # if MBOXINLINEMATH is set, protect inlined math environments with an extra mbox - if ( $MBOXINLINEMATH ) { - # note additional \newline after command is omitted from output if right at the end of deleted block (otherwise a spurious empty line is generated) - $delblock=~s/($math)(?:[\s\n]*)?/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/sg; - } - -# splice in modified delblock - substr($_,$begin,$len)=$delblock; - pos = $begin + length($delblock); - } - # make the array modification in added blocks - while ( m/\\DIFaddbegin.*?\\DIFaddend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $addblock=$&; - while ( $addblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($addblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($addblock,$begin2,$len2)=$mathblock; - pos($addblock) = $begin2 + length($mathblock); - } - if ($CITECMD) { - my $addblockbefore=$addblock; - #(?:mask)?(?:full|short|no)?cite(?:A|author|year|meta)(?:NP)?$/ - ###my $CITECMD; $CITECMD="cite(?:A)$"; - $addblock=~ s/(\\($CITECMD)${extraspace}(?:<$abrat0>${extraspace})?(?:\[$brat0\]${extraspace}){0,2}\{$pat2\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - print STDERR "DEBUG: CITECMD $CITECMD\nDEBUG: addblock before:|$addblockbefore|\n" if $debug; - print STDERR "DEBUG: addblock after: |$addblock|\n" if $debug; - } - # if MBOXINLINEMATH is set, protect inlined math environments with an extra mbox - if ( $MBOXINLINEMATH ) { - ##$addblock=~s/($math)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/sg; - $addblock=~s/($math)(?:[\s\n]*)?/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/sg; - } -# splice in modified addblock - substr($_,$begin,$len)=$addblock; - pos = $begin + length($addblock); - } - - - - # Replace MATHMODE environments from step 1a above by the correct Math environment - - # The next line is complicated. The negative look-ahead insertion makes sure that no \end{$MATHENV} (or other mathematical - # environments) are between the \begin{$MATHENV} and \end{MATHMODE} commands. This is necessary as the minimal matching - # is not globally minimal but only 'locally' (matching is beginning from the left side of the string) - if ( $mathmarkup == FINE ) { - 1 while s/\\begin{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}((?:.(?!(?:\\end{(?:(?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}|\\begin{MATHMODE})))*?)\\end{MATHMODE}/\\begin{$1}$2\\end{$1}/s; - 1 while s/\\begin{MATHMODE}((?:.(?!\\end{MATHMODE}))*?)\\end{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}/\\begin{$2}$1\\end{$2}/s; - # convert remaining \begin{MATHMODE} \end{MATHMODE} (and not containing & or \\ )into MATHREPL environments - s/\\begin{MATHMODE}((?:(.(?!(?[1])) { - $optargnew=$newhash{$cmd}->[1]; - } else { - $optargnew=""; - } - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - } else { - $optargold=""; - } - - if ( defined($oldhash{$cmd}) ) { - $argold=$oldhash{$cmd}->[2]; - } else { - $argold=""; - } - $argnew=$newhash{$cmd}->[2]; - $argdiff="{" . join("",bodydiff($argold,$argnew)) ."}"; - if ( length $optargnew ) { - $optargdiff="[".join("",bodydiff($optargold,$optargnew))."]" ; - $optargdiff =~ s/\\DIFaddbegin /\\DIFaddbeginFL /g; - $optargdiff =~ s/\\DIFaddend /\\DIFaddendFL /g; - $optargdiff =~ s/\\DIFadd\{/\\DIFaddFL{/g; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - ### print STDERR "DEBUG s/\\Q$newhash{$cmd}->[0]\\E/\\$cmd$optargdiff$argdiff/s\n"; - # Note: \Q and \E force literal interpretation of what it between them but allow - # variable interpolation, such that e.g. \title matches just that and not TAB-itle - $$newpreambleref=~s/\Q$newhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s; - # replace this in old preamble if necessary - if ( defined($oldhash{$cmd}->[0])) { - $$oldpreambleref=~s/\Q$oldhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s ; - } - ### print STDERR "DEBUG NEW PRE ".$$newpreambleref."\n"; - } - - foreach $cmd ( keys %oldhash ) { - # if this has already been dealt with above can just skip - next if defined($newhash{$cmd}) ; - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - $optargdiff="[".join("",bodydiff($optargold,""))."]" ; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - $argdiff="{" . join("",bodydiff($argold,"")) ."}"; - $auxline = "\\$cmd$optargdiff$argdiff"; - $auxline =~s/$/$AUXCMD/sg; - push @auxlines,$auxline; - } - # add auxcmd comment to highlight added lines - return(@auxlines); -} - - - -# @diffs=linediff(\@seq1, \@seq2) -# mark up lines like this -#%DIF mm-mmdnn -#%< old deleted line(s) -#%DIF ------- -#%DIF mmann-nn -#new appended line %< -#%DIF ------- -# Future extension: mark change explicitly -# Assumes: traverse_sequence traverses deletions before insertions in changed sequences -# all line numbers relative to line 0 (first line of real file) -sub linediff { - my $seq1 = shift ; - my $seq2 = shift ; - - my $block = []; - my $retseq = []; - my @begin=('','',''); # dummy initialisation - my $instring ; - - my $discard = sub { @begin=('d',$_[0],$_[1]) unless scalar @$block ; - push(@$block, "%DIF < " . $seq1->[$_[0]]) }; - my $add = sub { if (! scalar @$block) { - @begin=('a',$_[0],$_[1]) ;} - elsif ( $begin[0] eq 'd' ) { - $begin[0]='c'; $begin[2]=$_[1]; - push(@$block, "%DIF -------") } - push(@$block, $seq2->[$_[1]] . " %DIF > " ) }; - my $match = sub { if ( scalar @$block ) { - if ( $begin[0] eq 'd' && $begin[1]!=$_[0]-1) { - $instring = sprintf "%%DIF %d-%dd%d",$begin[1],$_[0]-1,$begin[2]; } - elsif ( $begin[0] eq 'a' && $begin[2]!=$_[1]-1) { - $instring = sprintf "%%DIF %da%d-%d",$begin[1],$begin[2],$_[1]-1; } - elsif ( $begin[0] eq 'c' ) { - $instring = sprintf "%%DIF %sc%s", - ($begin[1]==$_[0]-1) ? "$begin[1]" : $begin[1]."-".($_[0]-1) , - ($begin[2]==$_[1]-1) ? "$begin[2]" : $begin[2]."-".($_[1]-1) ; } - else { - $instring = sprintf "%%DIF %d%s%d",$begin[1],$begin[0],$begin[2]; } - push @$retseq, $instring,@$block, "%DIF -------" ; - $block = []; - } - push @$retseq, $seq2->[$_[1]] - }; - # key function: remove multiple spaces (such that insertion or deletion of redundant white space is not reported) - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - push @$retseq, @$block if scalar @$block; - - return wantarray ? @$retseq : $retseq ; -} - - - -# init_regex_arr_data(\@array,"TOKEN INIT") -# scans DATA file handel for line "%% TOKEN INIT" line -# then appends each line not beginning with % into array (as a quoted regex) -sub init_regex_arr_data { - my ($arr,$token)=@_; - my ($copy); - while () { - if ( m/^%%BEGIN $token\s*$/ ) { - $copy=1; } - elsif ( m/^%%END $token\s*/ ) { - last; } - chomp; - push (@$arr,qr/^$_$/) if ( $copy && !/^%/ ) ; - } - seek DATA,0,0; # rewind DATA handle to file begin -} - - -# init_regex_arr_ext(\@array,$arg) -# fills array with regular expressions. -# if arg is a file name, then read in list of regular expressions from that file -# (one expression per line) -# Otherwise treat arg as a comma separated list of regular expressions -sub init_regex_arr_ext { - my ($arr,$arg)=@_; - my $regex; - if ( -f $ arg ) { - open(FILE,"$arg") or die ("Couldn't open $arg: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@$arr,qr/^$_$/); - } - close(FILE); - } - else { - # assume it is a comma-separated list of reg-ex - foreach $regex (split(qr/(?=1) { - $reset=shift; - } - if ($reset) { - $lasttime=times(); - } - else { - $retval=times()-$lasttime; - $lasttime=$lasttime+$retval; - return($retval); - } -} - - -sub usage { - die <<"EOF"; -Usage: $0 [options] old.tex new.tex > diff.tex - -Compares two latex files and writes tex code to stdout, which has the same -format as new.tex but has all changes relative to old.tex marked up or commented. - ---type=markupstyle --t markupstyle Add code to preamble for selected markup style - Available styles: UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE - CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR - [ Default: UNDERLINE ] - ---subtype=markstyle --s markstyle Add code to preamble for selected style for bracketing - commands (e.g. to mark changes in margin) - Available styles: SAFE MARGINAL DVIPSCOL COLOR LABEL - [ Default: SAFE ] - ---floattype=markstyle --f markstyle Add code to preamble for selected style which - replace standard marking and markup commands within floats - (e.g., marginal remarks cause an error within floats - so marginal marking can be disabled thus) - Available styles: FLOATSAFE IDENTICAL - [ Default: FLOATSAFE ] - ---encoding=enc --e enc Specify encoding of old.tex and new.tex. Typical encodings are - ascii, utf8, latin1, latin9. A list of available encodings can be - obtained by executing - perl -MEncode -e 'print join ("\\n",Encode->encodings( ":all" )) ;' - [Default encoding is utf8 unless the first few lines of the preamble contain - an invocation "\\usepackage[..]{inputenc} in which case the - encoding chosen by this command is asssumed. Note that ASCII (standard - latex) is a subset of utf8] - ---preamble=file --p file Insert file at end of preamble instead of auto-generating - preamble. The preamble must define the following commands - \\DIFaddbegin,\\DIFaddend,\\DIFadd{..}, - \\DIFdelbegin,\\DIFdelend,\\DIFdel{..}, - and varieties for use within floats - \\DIFaddbeginFL,\\DIFaddendFL,\\DIFaddFL{..}, - \\DIFdelbeginFL,\\DIFdelendFL,\\DIFdelFL{..} - (If this option is set -t, -s, and -f options - are ignored.) - ---exclude-safecmd=exclude-file ---exclude-safecmd="cmd1,cmd2,..." --A exclude-file ---replace-safecmd=replace-file ---append-safecmd=append-file ---append-safecmd="cmd1,cmd2,..." --a append-file Exclude from, replace or append to the list of regex - matching commands which are safe to use within the - scope of a \\DIFadd or \\DIFdel command. The file must contain - one Perl-RegEx per line (Comment lines beginning with # or % are - ignored). A literal comma within the comma-separated list must be - escaped thus "\\,", Note that the RegEx needs to match the whole of - the token, i.e., /^regex\$/ is implied and that the initial - "\\" of the command is not included. The --exclude-safecmd - and --append-safecmd options can be combined with the --replace-safecmd - option and can be used repeatedly to add cumulatively to the lists. - ---exclude-textcmd=exclude-file ---exclude-textcmd="cmd1,cmd2,..." --X exclude-file ---replace-textcmd=replace-file ---append-textcmd=append-file ---append-textcmd="cmd1,cmd2,..." --x append-file Exclude from, replace or append to the list of regex - matching commands whose last argument is text. See - entry for --exclude-safecmd directly above for further details. - ---replace-context1cmd=replace-file ---append-context1cmd=append-file ---append-context1cmd="cmd1,cmd2,..." - Replace or append to the list of regex matching commands - whose last argument is text but which require a particular - context to work, e.g. \\caption will only work within a figure - or table. These commands behave like text commands, except when - they occur in a deleted section, when they are disabled, but their - argument is shown as deleted text. - ---replace-context2cmd=replace-file ---append-context2cmd=append-file ---append-context2cmd="cmd1,cmd2,..." - As corresponding commands for context1. The only difference is that - context2 commands are completely disabled in deleted sections, including - their arguments. - - ---config var1=val1,var2=val2,... --c var1=val1,.. Set configuration variables. --c configfile Available variables: - MINWORDSBLOCK (integer) - FLOATENV (RegEx) - PICTUREENV (RegEx) - MATHENV (RegEx) - MATHREPL (String) - MATHARRENV (RegEx) - MATHARRREPL (String) - ARRENV (RegEx) - COUNTERCMD (RegEx) - This option can be repeated. - - ---packages=pkg1,pkg2,.. - Tell latexdiff that .tex file is processed with the packages in list - loaded. This is normally not necessary if the .tex file includes the - preamble, as the preamble is automatically scanned for \\usepackage commands. - Use of the --packages option disables automatic scanning, so if for any - reason package specific parsing needs to be switched off, use --packages=none. - The following packages trigger special behaviour: - endfloat hyperref amsmath apacite - [ Default: scan the preamble for \\usepackage commands to determine - loaded packages.] - ---show-preamble Print generated or included preamble commands to stdout. - ---show-safecmd Print list of regex matching and excluding safe commands. - ---show-textcmd Print list of regex matching and excluding commands with text argument. - ---show-config Show values of configuration variables - ---show-all Show all of the above - - NB For all --show commands, no old.tex or new.tex file needs to be given, and no - differencing takes place. - -Other configuration options: - ---allow-spaces Allow spaces between bracketed or braced arguments to commands - [Default requires arguments to directly follow each other without - intervening spaces] - ---math-markup=level Determine granularity of markup in displayed math environments: - Possible values for level are (both numerical and text labels are acceptable): - off or 0: suppress markup for math environments. Deleted equations will not - appear in diff file. This mode can be used if all the other modes - cause invalid latex code. - whole or 1: Differencing on the level of whole equations. Even trivial changes - to equations cause the whole equation to be marked changed. This - mode can be used if processing in coarse or fine mode results in - invalid latex code. - coarse or 2: Detect changes within equations marked up with a coarse - granularity; changes in equation type (e.g.displaymath to equation) - appear as a change to the complete equation. This mode is recommended - for situations where the content and order of some equations are still - being changed. [Default] - fine or 3: Detect small change in equations and mark up and fine granularity. - This mode is most suitable, if only minor changes to equations are - expected, e.g. correction of typos. - ---disable-citation-markup Suppress citation markup in styles using ulem (UNDERLINE, - FONTSTRIKE, CULINECHBAR) ---enable-citation-markup Protect citation commands in changed sections with \\mbox command - [i.e. use default behaviour for ulem package for other packages] - -Miscelleneous options - ---label=label --L label Sets the labels used to describe the old and new files. The first use - of this option sets the label describing the old file and the second - use of the option sets the label for the new file. - [Default: use the filename and modification dates for the label] - ---no-label Suppress inclusion of old and new file names as comment in output file - ---visible-label Include old and new filenames (or labels set with --label option) as - visible output - ---flatten Replace \\input and \\include commands within body by the content - of the files in their argument. If \\includeonly is present in the - preamble, only those files are expanded into the document. However, - no recursion is done, i.e. \\input and \\include commands within - included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, - respectively, making it possible to organise files into old and new directories. - --flatten is applied recursively, so inputted files can contain further - \\input statements. - ---help --h Show this help text. - ---ignore-warnings Suppress warnings about inconsistencies in length between input - and parsed strings and missing characters. - ---verbose --V Output various status information to stderr during processing. - Default is to work silently. - ---version Show version number. - -EOF -} - -=head1 NAME - -latexdiff - determine and markup differences between two latex files - -=head1 SYNOPSIS - -B [ B ] F F > F - -=head1 DESCRIPTION - -Briefly, I is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called C and C, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. - -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "S>>" is appended to each added line, i.e. a -line present in C but not in C. Discarded lines - are deactivated by prepending "S>>". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file C will be similar to -C. At the end of the preamble, the definitions for I markup commands are inserted. -In differencing the main body of the text, I attempts to -satisfy the following guidelines (in order of priority): - -=over 3 - -=item 1 - -If both C and C are valid LaTeX, then the resulting -C should also be valid LateX. (NB If a few plain TeX commands -are used within C or C then C is not -guaranteed to work but usually will). - -=item 2 - -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -C. - -=item 3 - -If a changed passage contains text or text-producing commands, then -running C through LateX should produce output where added -and discarded passages are highlighted. - -=item 4 - -Where there are insignificant differences, e.g. in the positioning of -line breaks, C should follow the formatting of C - -=back - -For differencing the same algorithm as I is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, C<\caption> and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write - - \section{\textem{This is an emphasized section title}} - -and not - - \section {\textem{This is an emphasized section title}} - -or - - \section\textem{This is an emphasized section title} - -even though all varieties are the same to LaTeX (but see -B<--allow-spaces> option which allows the second variety). - -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the PICTUREENV configuration variable, set by -default to C and C environments; see B<--config> -option). The latter environment (C) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by C<\begin{DIFnomarkup}> and C<\end{DIFnomarkup}>. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, - -C<\newenvironment{DIFnomarkup}{}{}> - -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. - -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. - -All markup commands inserted by I begin with "C<\DIF>". Added -blocks containing words, commands or comments which are in C -but not in C are marked by C<\DIFaddbegin> and C<\DIFaddend>. -Discarded blocks are marked by C<\DIFdelbegin> and C<\DIFdelend>. -Within added blocks all text is highlighted with C<\DIFadd> like this: -C<\DIFadd{Added text block}> -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces "{" and "}" are never put within -the scope of C<\DIFadd>. Added comments are marked by prepending -"S >>". - -Within deleted blocks text is highlighted with C<\DIFdel>. Deleted -comments are marked by prepending "S >>". Non-safe command -and curly braces within deleted blocks are commented out with -"S >>". - - - -=head1 OPTIONS - -=head2 Preamble - -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. - -=over 4 - -=item B<--type=markupstyle> or -B<-t markupstyle> - -Add code to preamble for selected markup style. This option defines -C<\DIFadd> and C<\DIFdel> commands. -Available styles: - -C - -[ Default: C ] - -=item B<--subtype=markstyle> or -B<-s markstyle> - -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -C<\DIFaddbegin>, C<\DIFaddend>, C<\DIFdelbegin> and C<\DIFdelend> commands. -Available styles: C - -[ Default: C ] - -=item B<--floattype=markstyle> or -B<-f markstyle> - -Add code to preamble for selected style which -replace standard marking and markup commands within floats -(e.g., marginal remarks cause an error within floats -so marginal marking can be disabled thus). This option defines all -C<\DIF...FL> commands. -Available styles: C - -[ Default: C ] - -=item B<--encoding=enc> or -B<-e enc> - -Specify encoding of old.tex and new.tex. Typical encodings are -C, C, C, C. A list of available encodings can be -obtained by executing - -Cencodings( ":all" )) ;' > - -[Default encoding is utf8 unless the first few lines of the preamble contain -an invocation C<\usepackage[..]{inputenc}> in which case the -encoding chosen by this command is asssumed. Note that ASCII (standard -latex) is a subset of utf8] - -=item B<--preamble=file> or -B<-p file> - -Insert file at end of preamble instead of generating -preamble. The preamble must define the following commands -C<\DIFaddbegin, \DIFaddend, \DIFadd{..}, -\DIFdelbegin,\DIFdelend,\DIFdel{..},> -and varieties for use within floats -C<\DIFaddbeginFL, \DIFaddendFL, \DIFaddFL{..}, -\DIFdelbeginFL, \DIFdelendFL, \DIFdelFL{..}> -(If this option is set B<-t>, B<-s>, and B<-f> options -are ignored.) - -=item B<--packages=pkg1,pkg2,..> - -Tell latexdiff that .tex file is processed with the packages in list -loaded. This is normally not necessary if the .tex file includes the -preamble, as the preamble is automatically scanned for C<\usepackage> commands. -Use of the B<--packages> option disables automatic scanning, so if for any -reason package specific parsing needs to be switched off, use B<--packages=none>. -The following packages trigger special behaviour: - -=over 8 - -=item C - -Configuration variable amsmath is set to C (Default: C) - -=item C - -Ensure that C<\begin{figure}> and C<\end{figure}> always appear by themselves on a line. - -=item C - -Change name of C<\DIFadd> and C<\DIFdel> commands to C<\DIFaddtex> and C<\DIFdeltex> and -define new C<\DIFadd> and C<\DIFdel> commands, which provide a wrapper for these commands, -using them for the text but not for the link defining command (where any markup would cause -errors). - -=item C - -Redefine the commands recognised as citation commands. - -=back - -[ Default: scan the preamble for C<\\usepackage> commands to determine - loaded packages.] - - - -=item B<--show-preamble> - -Print generated or included preamble commands to stdout. - -=back - -=head2 Configuration - -=over 4 - -=item B<--exclude-safecmd=exclude-file> or -B<-A exclude-file> or B<--exclude-safecmd="cmd1,cmd2,..."> - -=item B<--replace-safecmd=replace-file> - -=item B<--append-safecmd=append-file> or -B<-a append-file> or B<--append-safecmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions (RegEx) -matching commands which are safe to use within the -scope of a C<\DIFadd> or C<\DIFdel> command. The file must contain -one Perl-RegEx per line (Comment lines beginning with # or % are -ignored). Note that the RegEx needs to match the whole of -the token, i.e., /^regex$/ is implied and that the initial -"\" of the command is not included. -The B<--exclude-safecmd> and B<--append-safecmd> options can be combined with the -B<--replace-safecmd> -option and can be used repeatedly to add cumulatively to the lists. - B<--exclude-safecmd> -and B<--append-safecmd> can also take a comma separated list as input. If a -comma for one of the regex is required, escape it thus "\,". In most cases it -will be necessary to protect the comma-separated list from the shell by putting -it in quotation marks. - -=item B<--exclude-textcmd=exclude-file> or -B<-X exclude-file> or B<--exclude-textcmd="cmd1,cmd2,..."> - -=item B<--replace-textcmd=replace-file> - -=item B<--append-textcmd=append-file> or -B<-x append-file> or B<--append-textcmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions -matching commands whose last argument is text. See -entry for B<--exclude-safecmd> directly above for further details. - - -=item B<--replace-context1cmd=replace-file> - -=item B<--append-context1cmd=append-file> or -=item B<--append-context1cmd="cmd1,cmd2,..."> - -Replace or append to the list of regex matching commands -whose last argument is text but which require a particular -context to work, e.g. \caption will only work within a figure -or table. These commands behave like text commands, except when -they occur in a deleted section, when they are disabled, but their -argument is shown as deleted text. - -=item B<--replace-context2cmd=replace-file> - -=item B<--append-context2cmd=append-file> or -=item B<--append-context2cmd="cmd1,cmd2,..."> -As corresponding commands for context1. The only difference is that -context2 commands are completely disabled in deleted sections, including -their arguments. - - - -=item B<--config var1=val1,var2=val2,...> or B<-c var1=val1,..> - -=item B<-c configfile> - -Set configuration variables. The option can be repeated to set different -variables (as an alternative to the comma-separated list). -Available variables (see below for further explanations): - -C (integer) - -C (RegEx) - -C (RegEx) - -C (RegEx) - -C (String) - -C (RegEx) - -C (String) - -C (RegEx) - -C (RegEx) - -=item B<--show-safecmd> - -Print list of RegEx matching and excluding safe commands. - -=item B<--show-textcmd> - -Print list of RegEx matching and excluding commands with text argument. - -=item B<--show-config> - -Show values of configuration variables. - -=item B<--show-all> - -Combine all --show commands. - -NB For all --show commands, no C or C file needs to be specified, and no -differencing takes place. - -=back - -=head2 Other configuration options: - -=over 4 - -=item B<--allow-spaces> - -Allow spaces between bracketed or braced arguments to commands. Note -that this option might have undesirable side effects (unrelated scope -might get lumpeded with preceding commands) so should only be used if the -default produces erroneous results. (Default requires arguments to -directly follow each other without intervening spaces). - -=item B<--math-markup=level> - -Determine granularity of markup in displayed math environments: -Possible values for level are (both numerical and text labels are acceptable): - -C or C<0>: suppress markup for math environments. Deleted equations will not -appear in diff file. This mode can be used if all the other modes -cause invalid latex code. - -C or C<1>: Differencing on the level of whole equations. Even trivial changes -to equations cause the whole equation to be marked changed. This -mode can be used if processing in coarse or fine mode results in -invalid latex code. - -C or C<2>: Detect changes within equations marked up with a coarse -granularity; changes in equation type (e.g.displaymath to equation) -appear as a change to the complete equation. This mode is recommended -for situations where the content and order of some equations are still -being changed. [Default] - -C or C<3>: Detect small change in equations and mark up at fine granularity. -This mode is most suitable, if only minor changes to equations are -expected, e.g. correction of typos. - -=item B<--disable-citation-markup> - -Suppress citation markup in styles using ulem (UNDERLINE, -FONTSTRIKE, CULINECHBAR) - -=item B<--enable-citation-markup> - -Protect citation commands in changed sections with \\mbox command [i.e. use default behaviour for ulem package for other packages] - -=back - -=head2 Miscellaneous - -=over 4 - -=item B<--verbose> or B<-V> - -Output various status information to stderr during processing. -Default is to work silently. - -=item B<--driver=type> - -Choose driver for changebar package (only relevant for styles using - changebar: CCHANGEBAR CFONTCHBAR CULINECHBAR CHANGEBAR). Possible -drivers are listed in changebar manual, e.g. pdftex,dvips,dvitops - [Default: dvips] - -=item B<--ignore-warnings> - -Suppress warnings about inconsistencies in length between input and -parsed strings and missing characters. These warning messages are -often related to non-standard latex or latex constructions with a -syntax unknown to C but the resulting difference argument -is often fully functional anyway, particularly if the non-standard -latex only occurs in parts of the text which have not changed. - -=item B<--label=label> or -B<-L label> - -Sets the labels used to describe the old and new files. The first use -of this option sets the label describing the old file and the second -use of the option sets the label for the new file, i.e. set both -labels like this C<-L labelold -L labelnew>. -[Default: use the filename and modification dates for the label] - -=item B<--no-label> - -Suppress inclusion of old and new file names as comment in output file - -=item B<--visble-label> - -Include old and new filenames (or labels set with --label option) as -visible output. - -=item B<--flatten> - -Replace C<\input> and C<\include> commands within body by the content -of the files in their argument. If C<\includeonly> is present in the -preamble, only those files are expanded into the document. However, -no recursion is done, i.e. C<\input> and C<\include> commands within -included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, -respectively, making it possible to organise files into old and new directories. ---flatten is applied recursively, so inputted files can contain further -C<\input> statements. - -Use of this option might result in prohibitive processing times for -larger documents, and the resulting difference document -no longer reflects the structure of the input documents. - -=item B<--help> or -B<-h> - -Show help text - -=item B<--version> - -Show version number - -=back - - - -=head2 Predefined styles - -=head2 Major types - -The major type determine the markup of plain text and some selected latex commands outside floats by defining the markup commands C<\DIFadd{...}> and C<\DIFdel{...}> . - -=over 10 - -=item C - -Added text is wavy-underlined and blue, discarded text is struck out and red -(Requires color and ulem packages). Overstriking does not work in displayed math equations such that deleted parts of equation are underlined, not struck out (this is a shortcoming inherent to the ulem package). - -=item C - -Added text is blue and set in sans-serif, and a red footnote is created for each discarded -piece of text. (Requires color package) - -=item C - -Like C but without the use of color. - -=item C - -Added text is blue and set in sans-serif, and discarded text is red and very small size. - -=item C - -Added tex is set in sans-serif, discarded text small and struck out - -=item C - -Added text is blue, and discarded text is red. Additionally, the changed text is marked with a bar in the margin (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color, ulem and changebar packages). - -=item C - -No mark up of text, but mark margins with changebars (Requires changebar package). - -=item C - -No visible markup (but generic markup commands will still be inserted. - -=back - -=head2 Subtypes - -The subtype defines the commands that are inserted at the begin and end of added or discarded blocks, irrespectively of whether these blocks contain text or commands (Defined commands: C<\DIFaddbegin, \DIFaddend, \DIFdelbegin, \DIFdelend>) - -=over 10 - -=item C - -No additional markup (Recommended choice) - -=item C - -Mark beginning and end of changed blocks with symbols in the margin nearby (using -the standard C<\marginpar> command - note that this sometimes moves somewhat -from the intended position. - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. -(It is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete, for example -with citation commands). - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. Note -that C only works with the dvips converter, e.g. not pdflatex. -(it is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete). - -=back - -=head2 Float Types - -Some of the markup used in the main text might cause problems when used within -floats (e.g. figures or tables). For this reason alternative versions of all -markup commands are used within floats. The float type defines these alternative commands. - -=over 10 - -=item C - -Use identical markup for text as in the main body, but set all commands marking the begin and end of changed blocks to null-commands. You have to choose this float type if your subtype is C as C<\marginpar> does not work properly within floats. - -=item C - -Mark additions the same way as in the main text. Deleted environments are marked by angular brackets \[ and \] and the deleted text is set in scriptscript size. This float type should always be used with the C and C markup types as the \footnote command does not work properly in floating environments. - -=item C - -Make no difference between the main text and floats. - -=back - - -=head2 Configuration Variables - -=over 10 - -=item C - -Minimum number of tokens required to form an independent block. This value is -used in the algorithm to detect changes of complete blocks by merging identical text parts of less than C to the preceding added and discarded parts. - -[ Default: 3 ] - -=item C - -Environments whose name matches the regular expression in C are -considered floats. Within these environments, the I markup commands -are replaced by their FL variaties. - -[ Default: S >] - -=item C - -Within environments whose name matches the regular expression in C -all latexdiff markup is removed (in pathologic cases this might lead to - inconsistent markup but this situation should be rare). - -[ Default: S >] - -=item C,C - -If both \begin and \end for a math environment (environment name matching C -or \[ and \]) -are within the same deleted block, they are replaced by a \begin and \end commands for C -rather than being commented out. - -[ Default: C=S >, C=S >] - -=item C,C - -as C,C but for equation arrays - -[ Default: C=S >, C=S >] - -=item C - -If a match to C is found within an inline math environment within a deleted or added block, then the inlined math -is surrounded by C<\mbox{>...C<}>. This is necessary as underlining does not work within inlined array environments. - -[ Default: C=S > - -=item C - -If a command in a deleted block which is also in the textcmd list matches C then an -additional command C<\addtocounter{>FC<}{-1}>, where F is the matching command, is appended in the diff file such that the numbering in the diff file remains synchronized with the -numbering in the new file. - -[ Default: C=C<(?:footnote|part|section|subsection> ... - -C<|subsubsection|paragraph|subparagraph)> ] - -=back - -=head1 COMMON PROBLEMS - -=over 10 - -=item Citations result in overfull boxes - -There is an incompatibility between the C package, which C uses for underlining and striking out in the UNDERLINE style, -the default style. In order to be able to mark up citations properly, they are placed with an C<\mbox> command in post-processing. As mboxes -cannot be broken across lines, this procedure frequently results in overfull boxes, possibly obscuring the content as it extends beyond the right margin. If this is a problem, you have two possibilities: - -1. Use C or C subtype markup (option C<-s COLOR>): If this markup is chosen, then changed citations are no longer marked up -with the wavy line (additions) or struck out (deletions), but are still highlighted in the appropriate color. - -2. Choose option C<--disable-citation-markup> which turns off the marking up of citations: deleted citations are no longer shown, and -added ctations are shown without markup. (This was the default behaviour of latexdiff at versions 0.6 and older) - -=item Changes in complicated mathematical equations result in latex processing errors - -Try options C<--math-markup=whole>. If even that fails, you can turn off mark up for equations with C<--math-markup=off>. - -=back - -=head1 BUGS - -Option allow-spaces not implemented entirely consistently. It breaks -the rules that number and type of white space does not matter, as -different numbers of inter-argument spaces are treated as significant. - -Please submit bug reports using the issue tracker of the github repository page I, -or send them to I. Include the serial number of I -(from comments at the top of the source or use B<--version>). If you come across latex -files that are error-free and conform to the specifications set out -above, and whose differencing still does not result in error-free -latex, please send me those files, ideally edited to only contain the -offending passage as long as that still reproduces the problem. If your -file relies on non-standard class files, you must include those. I will not -look at examples where I have trouble to latex the original files. - -=head1 SEE ALSO - -L, L - -=head1 PORTABILITY - -I does not make use of external commands and thus should run -on any platform supporting Perl 5.6 or higher. If files with encodings -other than ASCII or UTF-8 are processed, Perl 5.8 or higher is required. - -The standard version of I requires installation of the Perl package -C (available from I - -I) but a stand-alone -version, I, which has this package inlined, is available, too. -I requires the I command to be present. - -=head1 AUTHOR - -Version 1.0.4 -Copyright (C) 2004-2012 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 - -Contributors of fixes and additions: V. Kuhlmann, J. Paisley, N. Becker, T. Doerges, K. Huebner, -T. Connors, Sebastian Gouezel and many others. -Thanks to the many people who sent in bug reports, feature suggestions, and other feedback. - -=cut - -__END__ -%%BEGIN SAFE COMMANDS -% Regex matching commands which can safely be in the -% argument of a \DIFadd or \DIFdel command (leave out the \) -arabic -dashbox -emph -fbox -framebox -hspace -math.* -makebox -mbox -pageref -ref -symbol -raisebox -rule -text.* -shortstack -usebox -dag -ddag -copyright -pounds -S -P -oe -OE -ae -AE -aa -AA -o -O -l -L -frac -ss -sqrt -ldots -cdots -vdots -ddots -alpha -beta -gamma -delta -epsilon -varepsilon -zeta -eta -theta -vartheta -iota -kappa -lambda -mu -nu -xi -pi -varpi -rho -varrho -sigma -varsigma -tau -upsilon -phi -varphi -chi -psi -omega -Gamma -Delta -Theta -Lambda -Xi -Pi -Sigma -Upsilon -Phi -Psi -Omega -ps -mp -times -div -ast -star -circ -bullet -cdot -cap -cup -uplus -sqcap -vee -wedge -setminus -wr -diamond -(?:big)?triangle.* -lhd -rhd -unlhd -unrhd -oplus -ominus -otimes -oslash -odot -bigcirc -d?dagger -amalg -leq -prec -preceq -ll -(?:sq)?su[bp]set(?:eq)? -in -vdash -geq -succ(?:eq)? -gg -ni -dashv -equiv -sim(?:eq)? -asymp -approx -cong -neq -doteq -propto -models -perp -mid -parallel -bowtie -Join -smile -frown -.*arrow -(?:long)?mapsto -.*harpoon.* -leadsto -aleph -hbar -imath -jmath -ell -wp -Re -Im -mho -prime -emptyset -nabla -surd -top -bot -angle -forall -exists -neg -flat -natural -sharp -backslash -partial -infty -Box -Diamond -triangle -clubsuit -diamondsuit -heartsuit -spadesuit -sum -prod -coprod -int -oint -big(?:sq)?c[au]p -bigvee -bigwedge -bigodot -bigotimes -bigoplus -biguplus -(?:arc)?(?:cos|sin|tan|cot)h? -csc -arg -deg -det -dim -exp -gcd -hom -inf -ker -lg -lim -liminf -limsup -ln -log -max -min -Pr -sec -sup -[Hclbdruvt] -(SUPER|SUB)SCRIPTNB -(SUPER|SUB)SCRIPT -PERCENTAGE -DOLLAR -%%END SAFE COMMANDS - -%%BEGIN TEXT COMMANDS -% Regex matching commands with a text argument (leave out the \) -addcontents.* -cc -closing -chapter -dashbox -emph -encl -fbox -framebox -footnote -footnotetext -framebox -part -(sub){0,2}section\*? -(sub)?paragraph\*? -makebox -mbox -opening -parbox -raisebox -savebox -sbox -shortstack -signature -text.* -value -underline -sqrt -(SUPER|SUB)SCRIPT -%%END TEXT COMMANDS - -%%BEGIN CONTEXT1 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -caption -%%END CONTEXT1 COMMANDS - -%%BEGIN CONTEXT2 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -title -author -date -institute -%%END CONTEXT2 COMMANDS - - -%% TYPES (Commands for highlighting changed blocks) - -%DIF UNDERLINE PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}} -\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}} -%DIF END UNDERLINE PREAMBLE - -%DIF CTRADITIONAL PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} [..\footnote{removed: #1} ]}} -%DIF END CTRADITIONAL PREAMBLE - -%DIF TRADITIONAL PREAMBLE -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{[..\footnote{removed: #1} ]}} -%DIF END TRADITIONAL PREAMBLE - -%DIF CFONT PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} \scriptsize #1}} -%DIF END CFONT PREAMBLE - -%DIF FONTSTRIKE PREAMBLE -\RequirePackage[normalem]{ulem} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{\footnotesize \sout{#1}}} -%DIF END FONTSTRIKE PREAMBLE - -%DIF CCHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}#1}\protect\cbdelete} -%DIF END CCHANGEBAR PREAMBLE - -%DIF CFONTCHBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\sf #1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\scriptsize #1}\protect\cbdelete} -%DIF END CFONTCHBAR PREAMBLE - -%DIF CULINECHBAR PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage[dvips]{changebar} -\RequirePackage{color} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\uwave{#1}}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\sout{#1}}\protect\cbdelete} -%DIF END CULINECHBAR PREAMBLE - -%DIF CHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\providecommand{\DIFadd}[1]{\protect\cbstart{#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete} -%DIF END CHANGEBAR PREAMBLE - -%DIF INVISIBLE PREAMBLE -\providecommand{\DIFadd}[1]{#1} -\providecommand{\DIFdel}[1]{} -%DIF END INVISIBLE PREAMBLE - - -%% SUBTYPES (Markers for beginning and end of changed blocks) - -%DIF SAFE PREAMBLE -\providecommand{\DIFaddbegin}{} -\providecommand{\DIFaddend}{} -\providecommand{\DIFdelbegin}{} -\providecommand{\DIFdelend}{} -%DIF END SAFE PREAMBLE - -%DIF MARGIN PREAMBLE -\providecommand{\DIFaddbegin}{\protect\marginpar{a[}} -\providecommand{\DIFaddend}{\protect\marginpar{]}} -\providecommand{\DIFdelbegin}{\protect\marginpar{d[}} -\providecommand{\DIFdelend}{\protect\marginpar{]}} -%DIF END BRACKET PREAMBLE - -%DIF DVIPSCOL PREAMBLE -%Note: only works with dvips converter -\RequirePackage{color} -\RequirePackage{dvipscol} -\providecommand{\DIFaddbegin}{\protect\nogroupcolor{blue}} -\providecommand{\DIFaddend}{\protect\nogroupcolor{black}} -\providecommand{\DIFdelbegin}{\protect\nogroupcolor{red}} -\providecommand{\DIFdelend}{\protect\nogroupcolor{black}} -%DIF END DVIPSCOL PREAMBLE - -%DIF COLOR PREAMBLE -\RequirePackage{color} -\providecommand{\DIFaddbegin}{\protect\color{blue}} -\providecommand{\DIFaddend}{\protect\color{black}} -\providecommand{\DIFdelbegin}{\protect\color{red}} -\providecommand{\DIFdelend}{\protect\color{black}} -%DIF END COLOR PREAMBLE - -%DIF LABEL PREAMBLE -% To show only pages with changes (pdf) (external program pdftk needs to be installed) -% (only works for simple documents with non-repeated page numbers) -% pdflatex diff.tex -% pdflatex diff.tex -% pdftk diff.pdf cat `perl -lne 'if (m/\\newlabel{DIFchg[be]\d*}{{.*}{(.*)}}/) { print $1 }' diff.aux | uniq | tr -s \\n ' '` output diff-changedpages.pdf -% To show only pages with changes (dvips/dvipdf) -% latex diff.tex -% latex diff.tex -% dvips -pp `perl -lne 'if (m/\\newlabel{DIFchg[be]\d*}{{.*}{(.*)}}/) { print $1 }' diff.aux | uniq | tr -s \\n ','` diff.dvi -\typeout{Check comments in preamble of output for instructions how to show only pages where changes have been made} -\newcount\DIFcounterb -\global\DIFcounterb 0\relax -\newcount\DIFcountere -\global\DIFcountere 0\relax -\providecommand{\DIFaddbegin}{\global\advance\DIFcounterb 1\relax\label{DIFchgb\the\DIFcounterb}} %DIF PREAMBLE -\providecommand{\DIFaddend}{\global\advance\DIFcountere 1\relax\label{DIFchge\the\DIFcountere}} %DIF PREAMBLE -\providecommand{\DIFdelbegin}{\global\advance\DIFcounterb 1\relax\label{DIFchgb\the\DIFcounterb}} %DIF PREAMBLE -\providecommand{\DIFdelend}{\global\advance\DIFcountere 1\relax\label{DIFchge\the\DIFcountere}} %DIF PREAMBLE -%DIF END LABEL PREAMBLE -%% FLOAT TYPES - -%DIF FLOATSAFE PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%DIF IDENTICAL PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{\DIFaddbegin} -\providecommand{\DIFaddendFL}{\DIFaddend} -\providecommand{\DIFdelbeginFL}{\DIFdelbegin} -\providecommand{\DIFdelendFL}{\DIFdelend} -%DIF END IDENTICAL PREAMBLE - -%DIF TRADITIONALSAFE PREAMBLE -% procidecommand color to make this work for TRADITIONAL and CTRADITIONAL -\providecommand{\color}[1]{} -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdel}[1]{{\protect\color{red}[..{\scriptsize {removed: #1}} ]}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END TRADITIONALSAFE PREAMBLE - -%% SPECIAL PACKAGE PREAMBLE COMMANDS - -% Standard \DIFadd and \DIFdel are redefined as \DIFaddtex and \DIFdeltex -% when hyperref package is included. -%DIF HYPERREF PREAMBLE -\providecommand{\DIFadd}[1]{\texorpdfstring{\DIFaddtex{#1}}{#1}} -\providecommand{\DIFdel}[1]{\texorpdfstring{\DIFdeltex{#1}}{}} -%DIF END HYPERREF PACKAGE diff --git a/latexdiff-1.0.4/latexdiff-so b/latexdiff-1.0.4/latexdiff-so deleted file mode 100755 index 6cd69fd..0000000 --- a/latexdiff-1.0.4/latexdiff-so +++ /dev/null @@ -1,3997 +0,0 @@ -#!/usr/bin/env perl -##!/usr/bin/perl -w -# latexdiff - differences two latex files on the word level -# and produces a latex file with the differences marked up. -# -# Copyright (C) 2004-12 F J Tilmann (tilmann@gfz-potsdam.de) -# -# Repository/issue tracker: https://github.com/ftilmann/latexdiff -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# -# ToDo: -# -# Version 1.0.4 -# - introduce list UNSAFEMATHCMD, which holds list of commands which cannot be marked up with \DIFadd or \DIFdel commands (only relevant for WHOLE and COARSE math markup modes) -# - new subtype LABEL which gives each change a label. This can later be used to only display pages where changes -# have been made (instructions for that are put as comments into the diff'ed file) inspired by answer on http://tex.stackexchange.com/questions/166049/invisible-markers-in-pdfs-using-pdflatex -# - Configuration variables take into accout some commands from additional packages: -# tikzpicture environment now treated as PICTUREENV, and \smallmatrix in ARRENV (amsmath) -# - --flatten: support for \subfile command (subfiles package) (in response to http://tex.stackexchange.com/questions/167620/latexdiff-with-subfiles ) -# - --flatten: \bibliography commands expand if corresponding bbl file present -# - angled bracket optional commands now parsed correctly (patch #3570) submitted by Dave Kleinschmidt (thanks) -# - \RequirePackage now treated as synonym of \usepackage with respect to setting packages -# - special rules for apacite package (redefine citation commands) -# - recognise /dev/null as 'file-like' arguments for --preamble and --config options -# - fix units package incompatibility with ulem for text maths statements $ ..$ (thanks to Stuart Prescott for reporting this) -# - amsmath environment cases treated correctly (Bug fix #19029) (thanks to Jalar) -# - {,} in comments no longer confuse latexdiff (Bug fix #19146) -# - \% in one-letter sub/Superscripts was not converted correctly -# -# Version 1.0.3 -# - fix bug in add_safe_commands that made latexdiff hang on DeclareMathOperator -# command in preamble -# - \(..\) inline math expressions were not parsed correctly, if they contained a linebreak -# - applied patch contributed by tomflannaghan via Berlios: [ Patch #3431 ] Adds correct handling of \left< and \right> -# - \$ is treated correctly as a literal dollar sign (thanks to Reed Cartwright and Joshua Miller for reporting this bug -# and sketching out the solution) -# - \^ and \_ are correctly interpreted as accent and underlined space, respectively, not as superscript of subscript -# (thanks to Wail Yahyaoui for pointing out this bug) -# -# Version 1.0.1 - treat \big,\bigg etc. equivalently to \left and -# \right - include starred version in MATHENV - apply -# - flatten recursively and --flatten expansion is now -# aware of comments (thanks to Tim Connors for patch) -# - Change to post-processing for more reliability for -# deleted math environments -# - On linux systems, recognise and remove DOS style newlines -# - Provide markup for some special preamble commands (\title, -# \author,\date, -# - configurable by setting context2cmd -# - for styles using ulem package, remove \emph and \text.. from list of -# safe commands in order to allow linebreaks within the -# highlighted sections. -# - for ulem style, now show citations by enclosing them in \mbox commands. -# This unfortunately implies linebreaks within citations no longer function, -# so this functionality can be turned off (Option --disable-citation-markup). -# With --enable-citation-markup, the mbox markup is forced for other styles) -# - new substyle COLOR. This is particularly useful for marking up citations -# and some special post-processing is implemented to retain cite -# commands in deleted blocks. -# - four different levels of math-markup -# - Option --driver for choosing driver for modes employing changebar package -# - accept \\* as valid command (and other commands of form \.*). Also accept -# \ (backslashed newline) -# - some typo fixes, include commands defined in preamble as safe commands -# (Sebastian Gouezel) -# - include compared filenames as comments as line 2 and 3 of -# the preamble (can be modified with option --label, and suppressed with -# --no-label), option --visible-label to show files in generated pdf or dvi -# at the beginning of main document -# -# Version 0.5 A number of minor improvements based on feedback -# Deleted blocks are now shown before added blocks -# Package specific processing -# -# Version 0.43 unreleased typo in list of styles at the end -# Add protect to all \cbstart, \cbend commands -# More robust substitution of deleted math commands -# -# Version 0.42 November 06 Bug fixes only -# -# Version 0.4 March 06 option for fast differencing using UNIX diff command, several minor bug fixes (\par bug, improved highlighting of textcmds) -# -# Version 0.3 August 05 improved parsing of displayed math, --allow-spaces -# option, several minor bug fixes -# -# Version 0.25 October 04 Fix bug with deleted equations, add math mode commands to safecmd, add | to allowed interpunctuation signs -# Version 0.2 September 04 extension to utf-8 and variable encodings -# Version 0.1 August 04 First public release - -# Inserted block for stand-alone version replaces -# use Algorithm::Diff qw(traverse_sequences); -# in standard version -# The following BEGIN block contains a verbatim copy of -# Ned Konz' Algorithm::Diff package version 1.15 except -# that all POD documentation has been stripped out. -# I encourage you to download and install the Algorithm::Diff -# package and use the standard latexdiff version instead -# (current distribution available from http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15 -# the most recent version can be found via http://search.cpan.org/search?module=Algorithm::Diff ) -# Please note that the LICENCSE for Algorithm::Diff : -# "Copyright (c) 2000-2002 Ned Konz. All rights reserved. -# This program is free software; -# you can redistribute it and/or modify it under the same terms -# as Perl itself." -# The stand-alone version of latexdiff is provided as a convenience -# for latex users with no knowledge of PERL who do not wish to install -# additional packages to be able to use latexdiff. If you believe -# the inlining of Algorithm::Diff violates its license please contact -# me and I will modify the latexdiff distribution accordingly. -# Frederik Tilmann (tilmann@esc.cam.ac.uk) -BEGIN { -package Algorithm::Diff; -use strict; -use vars qw($VERSION @EXPORT_OK @ISA @EXPORT); -use integer; # see below in _replaceNextLargerWith() for mod to make - # if you don't use this -require Exporter; -@ISA = qw(Exporter); -@EXPORT = qw(); -@EXPORT_OK = qw(LCS diff traverse_sequences traverse_balanced sdiff); -$VERSION = sprintf('%d.%02d so', (q$Revision: 1.15 $ =~ /\d+/g)); - -# McIlroy-Hunt diff algorithm -# Adapted from the Smalltalk code of Mario I. Wolczko, -# by Ned Konz, perl@bike-nomad.com - - -# Create a hash that maps each element of $aCollection to the set of positions -# it occupies in $aCollection, restricted to the elements within the range of -# indexes specified by $start and $end. -# The fourth parameter is a subroutine reference that will be called to -# generate a string to use as a key. -# Additional parameters, if any, will be passed to this subroutine. -# -# my $hashRef = _withPositionsOfInInterval( \@array, $start, $end, $keyGen ); - -sub _withPositionsOfInInterval -{ - my $aCollection = shift; # array ref - my $start = shift; - my $end = shift; - my $keyGen = shift; - my %d; - my $index; - for ( $index = $start ; $index <= $end ; $index++ ) - { - my $element = $aCollection->[$index]; - my $key = &$keyGen( $element, @_ ); - if ( exists( $d{$key} ) ) - { - unshift ( @{ $d{$key} }, $index ); - } - else - { - $d{$key} = [$index]; - } - } - return wantarray ? %d : \%d; -} - -# Find the place at which aValue would normally be inserted into the array. If -# that place is already occupied by aValue, do nothing, and return undef. If -# the place does not exist (i.e., it is off the end of the array), add it to -# the end, otherwise replace the element at that point with aValue. -# It is assumed that the array's values are numeric. -# This is where the bulk (75%) of the time is spent in this module, so try to -# make it fast! - -sub _replaceNextLargerWith -{ - my ( $array, $aValue, $high ) = @_; - $high ||= $#$array; - - # off the end? - if ( $high == -1 || $aValue > $array->[-1] ) - { - push ( @$array, $aValue ); - return $high + 1; - } - - # binary search for insertion point... - my $low = 0; - my $index; - my $found; - while ( $low <= $high ) - { - $index = ( $high + $low ) / 2; - - # $index = int(( $high + $low ) / 2); # without 'use integer' - $found = $array->[$index]; - - if ( $aValue == $found ) - { - return undef; - } - elsif ( $aValue > $found ) - { - $low = $index + 1; - } - else - { - $high = $index - 1; - } - } - - # now insertion point is in $low. - $array->[$low] = $aValue; # overwrite next larger - return $low; -} - -# This method computes the longest common subsequence in $a and $b. - -# Result is array or ref, whose contents is such that -# $a->[ $i ] == $b->[ $result[ $i ] ] -# foreach $i in ( 0 .. $#result ) if $result[ $i ] is defined. - -# An additional argument may be passed; this is a hash or key generating -# function that should return a string that uniquely identifies the given -# element. It should be the case that if the key is the same, the elements -# will compare the same. If this parameter is undef or missing, the key -# will be the element as a string. - -# By default, comparisons will use "eq" and elements will be turned into keys -# using the default stringizing operator '""'. - -# Additional parameters, if any, will be passed to the key generation routine. - -sub _longestCommonSubsequence -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $keyGen = shift; # code ref - my $compare; # code ref - - # set up code refs - # Note that these are optimized. - if ( !defined($keyGen) ) # optimize for strings - { - $keyGen = sub { $_[0] }; - $compare = sub { my ( $a, $b ) = @_; $a eq $b }; - } - else - { - $compare = sub { - my $a = shift; - my $b = shift; - &$keyGen( $a, @_ ) eq &$keyGen( $b, @_ ); - }; - } - - my ( $aStart, $aFinish, $bStart, $bFinish, $matchVector ) = - ( 0, $#$a, 0, $#$b, [] ); - - # First we prune off any common elements at the beginning - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aStart], $b->[$bStart], @_ ) ) - { - $matchVector->[ $aStart++ ] = $bStart++; - } - - # now the end - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aFinish], $b->[$bFinish], @_ ) ) - { - $matchVector->[ $aFinish-- ] = $bFinish--; - } - - # Now compute the equivalence classes of positions of elements - my $bMatches = - _withPositionsOfInInterval( $b, $bStart, $bFinish, $keyGen, @_ ); - my $thresh = []; - my $links = []; - - my ( $i, $ai, $j, $k ); - for ( $i = $aStart ; $i <= $aFinish ; $i++ ) - { - $ai = &$keyGen( $a->[$i], @_ ); - if ( exists( $bMatches->{$ai} ) ) - { - $k = 0; - for $j ( @{ $bMatches->{$ai} } ) - { - - # optimization: most of the time this will be true - if ( $k and $thresh->[$k] > $j and $thresh->[ $k - 1 ] < $j ) - { - $thresh->[$k] = $j; - } - else - { - $k = _replaceNextLargerWith( $thresh, $j, $k ); - } - - # oddly, it's faster to always test this (CPU cache?). - if ( defined($k) ) - { - $links->[$k] = - [ ( $k ? $links->[ $k - 1 ] : undef ), $i, $j ]; - } - } - } - } - - if (@$thresh) - { - for ( my $link = $links->[$#$thresh] ; $link ; $link = $link->[0] ) - { - $matchVector->[ $link->[1] ] = $link->[2]; - } - } - - return wantarray ? @$matchVector : $matchVector; -} - -sub traverse_sequences -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $finishedACallback = $callbacks->{'A_FINISHED'}; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $finishedBCallback = $callbacks->{'B_FINISHED'}; - my $matchVector = _longestCommonSubsequence( $a, $b, $keyGen, @_ ); - - # Process all the lines in @$matchVector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai; - - for ( $ai = 0 ; $ai <= $#$matchVector ; $ai++ ) - { - my $bLine = $matchVector->[$ai]; - if ( defined($bLine) ) # matched - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi < $bLine; - &$matchCallback( $ai, $bi++, @_ ); - } - else - { - &$discardACallback( $ai, $bi, @_ ); - } - } - - # The last entry (if any) processed was a match. - # $ai and $bi point just past the last matching lines in their sequences. - - while ( $ai <= $lastA or $bi <= $lastB ) - { - - # last A? - if ( $ai == $lastA + 1 and $bi <= $lastB ) - { - if ( defined($finishedACallback) ) - { - &$finishedACallback( $lastA, @_ ); - $finishedACallback = undef; - } - else - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi <= $lastB; - } - } - - # last B? - if ( $bi == $lastB + 1 and $ai <= $lastA ) - { - if ( defined($finishedBCallback) ) - { - &$finishedBCallback( $lastB, @_ ); - $finishedBCallback = undef; - } - else - { - &$discardACallback( $ai++, $bi, @_ ) while $ai <= $lastA; - } - } - - &$discardACallback( $ai++, $bi, @_ ) if $ai <= $lastA; - &$discardBCallback( $ai, $bi++, @_ ) if $bi <= $lastB; - } - - return 1; -} - -sub traverse_balanced -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $changeCallback = $callbacks->{'CHANGE'}; - my $matchVector = _longestCommonSubsequence( $a, $b, $keyGen, @_ ); - - # Process all the lines in match vector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai = 0; - my $ma = -1; - my $mb; - - while (1) - { - - # Find next match indices $ma and $mb - do { $ma++ } while ( $ma <= $#$matchVector && !defined $matchVector->[$ma] ); - - last if $ma > $#$matchVector; # end of matchVector? - $mb = $matchVector->[$ma]; - - # Proceed with discard a/b or change events until - # next match - while ( $ai < $ma || $bi < $mb ) - { - - if ( $ai < $ma && $bi < $mb ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai < $ma ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi < $mb - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - # Match - &$matchCallback( $ai++, $bi++, @_ ); - } - - while ( $ai <= $lastA || $bi <= $lastB ) - { - if ( $ai <= $lastA && $bi <= $lastB ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai <= $lastA ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi <= $lastB - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - return 1; -} - -sub LCS -{ - my $a = shift; # array ref - my $matchVector = _longestCommonSubsequence( $a, @_ ); - my @retval; - my $i; - for ( $i = 0 ; $i <= $#$matchVector ; $i++ ) - { - if ( defined( $matchVector->[$i] ) ) - { - push ( @retval, $a->[$i] ); - } - } - return wantarray ? @retval : \@retval; -} - -sub diff -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $hunk = []; - my $discard = sub { push ( @$hunk, [ '-', $_[0], $a->[ $_[0] ] ] ) }; - my $add = sub { push ( @$hunk, [ '+', $_[1], $b->[ $_[1] ] ] ) }; - my $match = sub { push ( @$retval, $hunk ) if scalar(@$hunk); $hunk = [] }; - traverse_sequences( $a, $b, - { MATCH => $match, DISCARD_A => $discard, DISCARD_B => $add }, @_ ); - &$match(); - return wantarray ? @$retval : $retval; -} - -sub sdiff -{ - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $discard = sub { push ( @$retval, [ '-', $a->[ $_[0] ], "" ] ) }; - my $add = sub { push ( @$retval, [ '+', "", $b->[ $_[1] ] ] ) }; - my $change = sub { - push ( @$retval, [ 'c', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - my $match = sub { - push ( @$retval, [ 'u', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - traverse_balanced( - $a, - $b, - { - MATCH => $match, - DISCARD_A => $discard, - DISCARD_B => $add, - CHANGE => $change, - }, - @_ - ); - return wantarray ? @$retval : $retval; -} - -1; -} -import Algorithm::Diff qw(traverse_sequences); -# End of inserted block for stand-alone version - -use Getopt::Long ; -use strict ; -use warnings; -use utf8 ; - -my ($algodiffversion)=split(/ /,$Algorithm::Diff::VERSION); - - -my ($versionstring)=< 0, - WHOLE => 1, - COARSE => 2, - FINE => 3 -}; - - -my (@configlist,@labels, - @appendsafelist,@excludesafelist, - @appendtextlist,@excludetextlist, - @appendcontext1list,@appendcontext2list, - @packagelist); -my ($assign,@config); -# Hash where keys corresponds to the names of all included packages (including the documentclass as another package -# the optional arguments to the package are the values of the hash elements -my ($pkg,%packages); -# Defaults -$type='UNDERLINE'; -$subtype='SAFE'; -$floattype='FLOATSAFE'; -$mathmarkup=COARSE; - -$verbose=0; -# output debug and intermediate files, set to 0 in final distribution -$debug=0; -# insert preamble directly after documentclass - experimental feature, set to 0 in final distribution -# Note that this failed with mini example (or other files, where packages used in latexdiff preamble -# are called again with incompatible options in preamble of resulting file) -$earlylatexdiffpreamble=0; - -# define character properties -sub IsNonAsciiPunct { return <<'END' # Unicode punctuation but excluding ASCII punctuation -+utf8::IsPunct --utf8::IsASCII -END -} -sub IsNonAsciiS { return <<'END' # Unicode symbol but excluding ASCII -+utf8::IsS --utf8::IsASCII -END -} - - -my %verbhash; - -Getopt::Long::Configure('bundling'); -GetOptions('type|t=s' => \$type, - 'subtype|s=s' => \$subtype, - 'floattype|f=s' => \$floattype, - 'config|c=s' => \@configlist, - 'preamble|p=s' => \$preamblefile, - 'encoding|e=s' => \$encoding, - 'label|L=s' => \@labels, - 'no-label' => \$nolabel, - 'visible-label' => \$visiblelabel, - 'exclude-safecmd|A=s' => \@excludesafelist, - 'replace-safecmd=s' => \$replacesafe, - 'append-safecmd|a=s' => \@appendsafelist, - 'exclude-textcmd|X=s' => \@excludetextlist, - 'replace-textcmd=s' => \$replacetext, - 'append-textcmd|x=s' => \@appendtextlist, - 'replace-context1cmd=s' => \$replacecontext1, - 'append-context1cmd=s' => \@appendcontext1list, - 'replace-context2cmd=s' => \$replacecontext2, - 'append-context2cmd=s' => \@appendcontext2list, - 'show-preamble' => \$showpreamble, - 'show-safecmd' => \$showsafe, - 'show-textcmd' => \$showtext, - 'show-config' => \$showconfig, - 'show-all' => \$showall, - 'packages=s' => \@packagelist, - 'allow-spaces' => \$allowspaces, - 'math-markup=s' => \$mathmarkup, - 'enable-citation-markup' => \$enablecitmark, - 'disable-citation-markup' => \$disablecitmark, - 'verbose|V' => \$verbose, - 'ignore-warnings' => \$ignorewarnings, - 'driver=s'=> \$driver, - 'flatten' => \$flatten, - 'version' => \$version, - 'help|h|H' => \$help); - -if ( $help ) { - usage() ; -} - - -if ( $version ) { - die $versionstring ; -} - -print STDERR $versionstring if $verbose; - -if (defined($showall)){ - $showpreamble=$showsafe=$showtext=$showconfig=1; -} - -if (defined($mathmarkup)) { - $mathmarkup=~tr/a-z/A-Z/; - if ( $mathmarkup eq 'OFF' ){ - $mathmarkup=OFF; - } elsif ( $mathmarkup eq 'WHOLE' ){ - $mathmarkup=WHOLE; - } elsif ( $mathmarkup eq 'COARSE' ){ - $mathmarkup=COARSE; - } elsif ( $mathmarkup eq 'FINE' ){ - $mathmarkup=FINE; - } elsif ( $mathmarkup !~ m/^[0123]$/ ) { - die "Illegal value: ($mathmarkup) for option--math-markup. Possible values: OFF,WHOLE,COARSE,FINE,0- "; - } - # else use numerical value -} - -# setting extra preamble commands -if (defined($preamblefile)) { - $latexdiffpreamble=join "\n",(extrapream($preamblefile),""); -} else { - $latexdiffpreamble=join "\n",(extrapream($type,$subtype,$floattype),""); -} - -if ( defined($driver) ) { - # for changebar only - $latexdiffpreamble=~s/\[dvips\]/[$driver]/sg; -} -# setting up @SAFECMDLIST and @SAFECMDEXCL -if (defined($replacesafe)) { - init_regex_arr_ext(\@SAFECMDLIST,$replacesafe); -} else { - init_regex_arr_data(\@SAFECMDLIST, "SAFE COMMANDS"); -} -foreach $appendsafe ( @appendsafelist ) { - init_regex_arr_ext(\@SAFECMDLIST, $appendsafe); -} -foreach $excludesafe ( @excludesafelist ) { - init_regex_arr_ext(\@SAFECMDEXCL, $excludesafe); -} - -# setting up @TEXTCMDLIST and @TEXTCMDEXCL -if (defined($replacetext)) { - init_regex_arr_ext(\@TEXTCMDLIST,$replacetext); -} else { - init_regex_arr_data(\@TEXTCMDLIST, "TEXT COMMANDS"); -} -foreach $appendtext ( @appendtextlist ) { - init_regex_arr_ext(\@TEXTCMDLIST, $appendtext); -} -foreach $excludetext ( @excludetextlist ) { - init_regex_arr_ext(\@TEXTCMDEXCL, $excludetext); -} - - -# setting up @CONTEXT1CMDLIST ( @CONTEXT1CMDEXCL exist but is always empty ) -if (defined($replacecontext1)) { - init_regex_arr_ext(\@CONTEXT1CMDLIST,$replacecontext1); -} else { - init_regex_arr_data(\@CONTEXT1CMDLIST, "CONTEXT1 COMMANDS"); -} -foreach $appendcontext1 ( @appendcontext1list ) { - init_regex_arr_ext(\@CONTEXT1CMDLIST, $appendcontext1); -} - - -# setting up @CONTEXT2CMDLIST ( @CONTEXT2CMDEXCL exist but is always empty ) -if (defined($replacecontext2)) { - init_regex_arr_ext(\@CONTEXT2CMDLIST,$replacecontext2); -} else { - init_regex_arr_data(\@CONTEXT2CMDLIST, "CONTEXT2 COMMANDS"); -} -foreach $appendcontext2 ( @appendcontext2list ) { - init_regex_arr_ext(\@CONTEXT2CMDLIST, $appendcontext2); -} - -# setting configuration variables -@config=(); -foreach $config ( @configlist ) { - if (-f $config || lc $config eq '/dev/null' ) { - open(FILE,$config) or die ("Couldn't open configuration file $config: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@config,$_); - } - close(FILE); - } - else { -# foreach ( split(",",$config) ) { -# push @config,$_; -# } - push @config,split(",",$config) - } -} -foreach $assign ( @config ) { - $assign=~ m/\s*(\w*)\s*=\s*(\S*)\s*$/ or die "Illegal assignment $assign in configuration list (must be variable=value)"; - if ( $1 eq "MINWORDSBLOCK" ) { $MINWORDSBLOCK = $2; } - elsif ( $1 eq "FLOATENV" ) { $FLOATENV = $2 ; } - elsif ( $1 eq "PICTUREENV" ) { $PICTUREENV = $2 ; } - elsif ( $1 eq "MATHENV" ) { $MATHENV = $2 ; } - elsif ( $1 eq "MATHREPL" ) { $MATHREPL = $2 ; } - elsif ( $1 eq "MATHARRENV" ) { $MATHARRENV = $2 ; } - elsif ( $1 eq "MATHARRREPL" ) { $MATHARRREPL = $2 ; } - elsif ( $1 eq "ARRENV" ) { $ARRENV = $2 ; } - elsif ( $1 eq "COUNTERCMD" ) { $COUNTERCMD = $2 ; } - else { die "Unknown variable $1 in assignment.";} -} - -if ( $mathmarkup == COARSE || $mathmarkup == WHOLE ) { - push(@MATHTEXTCMDLIST,qr/^MATHBLOCK(?:$MATHENV|$MATHARRENV|SQUAREBRACKET)$/); -} - - - -foreach $pkg ( @packagelist ) { - map { $packages{$_}="" } split(/,/,$pkg) ; -} - -if ($showpreamble) { - print "\nPreamble commands:\n"; - print $latexdiffpreamble ; -} - -if ($showsafe) { - print "\nCommands safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE (unless excluded):\n"; - print_regex_arr(@SAFECMDLIST); - print "\nCommands not safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE :\n"; - print_regex_arr(@SAFECMDEXCL); -} - -if ($showtext) { - print "\nCommands with last argument textual (unless excluded) and safe in every context:\n"; - print_regex_arr(@TEXTCMDLIST); - print "\nContext1 commands (last argument textual, command will be disabled in deleted passages, last argument will be shown as plain text):\n"; - print_regex_arr(@CONTEXT1CMDLIST); - print "\nContext2 commands (last argument textual, command and its argument will be disabled in deleted passages):\n"; - print_regex_arr(@CONTEXT2CMDLIST); - print "\nExclude list of Commands with last argument not textual (overrides patterns above):\n"; - print_regex_arr(@TEXTCMDEXCL); -} - - -if ($showconfig) { - print "Configuration variables:\n"; - print "MINWORDSBLOCK=$MINWORDSBLOCK\n"; - print "FLOATENV=$FLOATENV\n"; - print "PICTUREENV=$PICTUREENV\n"; - print "MATHENV=$MATHENV\n"; - print "MATHREPL=$MATHREPL\n"; - print "MATHARRENV=$MATHARRENV\n"; - print "MATHARRREPL=$MATHARRREPL\n"; - print "ARRENV=$ARRENV\n"; - print "COUNTERCMD=$COUNTERCMD\n"; -} -if ($showconfig || $showtext || $showsafe || $showpreamble) { - exit 0; } -if ( @ARGV != 2 ) { - print STDERR "2 and only 2 non-option arguments required. Write latexdiff -h to get help\n"; - exit(2); -} - -# Are extra spaces between command arguments permissible? -my $extraspace; -if ($allowspaces) { - $extraspace='\s*'; -} else { - $extraspace=''; -} - -# append context lists to text lists (as text property is implied) -push @TEXTCMDLIST, @CONTEXT1CMDLIST; -push @TEXTCMDLIST, @CONTEXT2CMDLIST; - -push @TEXTCMDLIST, @MATHTEXTCMDLIST if $mathmarkup==COARSE; - -# internal additions to SAFECMDLIST -push(@SAFECMDLIST, qr/^QLEFTBRACE$/, qr/^QRIGHTBRACE$/); - - -# Patterns. These are used by some of the subroutines, too -# I can only define them down here because value of extraspace depends on an option - my $pat0 = '(?:[^{}])*'; - my $pat1 = '(?:[^{}]|\{'.$pat0.'\})*'; - my $pat2 = '(?:[^{}]|\{'.$pat1.'\})*'; - my $pat3 = '(?:[^{}]|\{'.$pat2.'\})*'; - my $pat4 = '(?:[^{}]|\{'.$pat3.'\})*'; - my $pat5 = '(?:[^{}]|\{'.$pat4.'\})*'; - my $pat6 = '(?:[^{}]|\{'.$pat5.'\})*'; - my $brat0 = '(?:[^\[\]]|\\\[|\\\])*'; - my $abrat0 = '(?:[^<>])*'; - - my $quotemarks = '(?:\'\')|(?:\`\`)'; - my $punct='[0.,\/\'\`:;\"\?\(\)\[\]!~\p{IsNonAsciiPunct}\p{IsNonAsciiS}]'; - my $number='-?\d*\.\d*'; - my $mathpunct='[+=<>\-\|]'; - my $and = '&'; - my $coords= '[\-.,\s\d]*'; -# word: sequence of letters or accents followed by letter - my $word='(?:[-\w\d*]|\\\\[\"\'\`~^][A-Za-z\*])+'; - my $cmdleftright='\\\\(?:left|right|[Bb]igg?[lrm]?|middle)\s*(?:[<>()\[\]|]|\\\\(?:[|{}]|\w+))'; - - my $cmdoptseq='\\\\[\w\d\*]+'.$extraspace.'(?:(?:<'.$abrat0.'>|\['.$brat0.'\]|\{'. $pat6 . '\}|\(' . $coords .'\))'.$extraspace.')*'; - my $backslashnl='\\\\\n'; - my $oneletcmd='\\\\.\*?(?:\['.$brat0.'\]|\{'. $pat6 . '\})*'; - my $math='\$(?:[^$]|\\\$)*?\$|\\\\[(](?:.|\n)*?\\\\[)]'; -## the current maths command cannot cope with newline within the math expression - - my $comment='%.*?\n'; - my $pat=qr/(?:\A\s*)?(?:${and}|${quotemarks}|${number}|${word}|$cmdleftright|${cmdoptseq}|${math}|${backslashnl}|${oneletcmd}|${comment}|${punct}|${mathpunct}|\{|\})\s*/ ; - -# now we are done setting up and can start working -my ($oldfile, $newfile) = @ARGV; -# check for existence of input files -if ( ! -e $oldfile ) { - die "Input file $oldfile does not exist."; -} -if ( ! -e $newfile ) { - die "Input file $newfile does not exist."; -} - - -# set the labels to be included into the file -my ($oldtime,$newtime,$oldlabel,$newlabel); -if (defined($labels[0])) { - $oldlabel=$labels[0] ; -} else { - $oldtime=localtime((stat($oldfile))[9]); - $oldlabel="$oldfile " . " "x(length($newfile)-length($oldfile)) . $oldtime; -} -if (defined($labels[1])) { - $newlabel=$labels[1] ; -} else { - $newtime=localtime((stat($newfile))[9]); - $newlabel="$newfile " . " "x(length($oldfile)-length($newfile)) . $newtime; -} - -$encoding=guess_encoding($newfile) unless defined($encoding); - -$encoding = "utf8" if $encoding =~ m/^utf8/i ; -if (lc($encoding) eq "utf8" ) { - binmode(STDOUT, ":utf8"); - binmode(STDERR, ":utf8"); -} - -$old=read_file_with_encoding($oldfile,$encoding); -$new=read_file_with_encoding($newfile,$encoding); - - - - -# reset time -exetime(1); -($oldpreamble,$oldbody,$oldpost)=splitdoc($old,'\\\\begin\{document\}','\\\\end\{document\}'); - - -($newpreamble,$newbody,$newpost)=splitdoc($new,'\\\\begin\{document\}','\\\\end\{document\}'); - - -if ($flatten) { - $oldbody=flatten($oldbody,$oldpreamble,$oldfile,$encoding); - $newbody=flatten($newbody,$newpreamble,$newfile,$encoding); -} - - - - -my @auxlines; -if ( length $oldpreamble && length $newpreamble ) { - # pre-process preamble by looking for commands used in \maketitle (title, author, date etc commands) - # and marking up content with latexdiff markup - @auxlines=preprocess_preamble($oldpreamble,$newpreamble); - - @oldpreamble = split /\n/, $oldpreamble; - @newpreamble = split /\n/, $newpreamble; - - # If a command is defined in the preamble of the new file, and only uses safe commands, then it can be considered to be safe) (contribution S. Gouezel) - # Base this assessment on the new preamble - add_safe_commands($newpreamble); - - # get a list of packages from preamble if not predefine - %packages=list_packages(@newpreamble) unless %packages; - ### if ( %packages ) {print STDERR "DEBUG Packages: ",%packages,"\n" ;} - if (defined $packages{"hyperref"} ) { - # deleted lines should not generate or appear in link names: - print STDERR "hyperref package detected.\n" if $verbose ; - $latexdiffpreamble =~ s/\{\\DIFadd\}/{\\DIFaddtex}/g; - $latexdiffpreamble =~ s/\{\\DIFdel\}/{\\DIFdeltex}/g; - $latexdiffpreamble .= join "\n",(extrapream("HYPERREF"),""); - } - - if (defined $packages{"units"} && ( $latexdiffpreamble =~ /\\RequirePackage(?:\[$brat0\])?\{ulem\}/ ) ) { - # protect inlined maths environments by surrounding with an \mbox - # this is done to get around an incompatibility between the ulem and units package - # where spaces in the argument to underlined or crossed-out \unit commands cause an error message - print STDERR "units package detected at the same time as style using ulem.\n" if $verbose ; - $MBOXINLINEMATH=1; - } - - print STDERR "Differencing preamble.\n" if $verbose; - - # insert dummy first line such that line count begins with line 1 (rather than perl's line 0) - just so that line numbers inserted by linediff are correct - unshift @newpreamble,''; - unshift @oldpreamble,''; - @diffpreamble = linediff(\@oldpreamble, \@newpreamble); - # remove dummy line again - shift @diffpreamble; - # add filenames, modification time and latexdiff mark - defined($nolabel) or splice @diffpreamble,1,0, - "%DIF LATEXDIFF DIFFERENCE FILE", - ,"%DIF DEL $oldlabel", - "%DIF ADD $newlabel"; - if ( @auxlines ) { - push @diffpreamble,"%DIF DELETED TITLE COMMANDS FOR MARKUP"; - push @diffpreamble,join("\n",@auxlines); - } - if ( $earlylatexdiffpreamble) { - # insert latexdiff command directly after documentclass at beginning of preamble - # note that grep is only run for its side effect - ( grep { s/^([^%]*\\documentclass.*)$/$1$latexdiffpreamble/ } @diffpreamble )==1 or die "Could not find documentclass statement in preamble"; - } else { - # insert latexdiff commands at the end of preamble (default behaviour) - push @diffpreamble,$latexdiffpreamble; - } - push @diffpreamble,'\begin{document}'; -} -elsif ( !length $oldpreamble && !length $newpreamble ) { - @diffpreamble=(); -} else { - print STDERR "Either both texts must have preamble or neither text must have the preamble.\n"; - exit(2); -} - -# Special: treat all cite commands as safe except in UNDERLINE and FONTSTRIKE mode -# (there is a conflict between citation and ulem package, see -# package documentation) -# Use post-processing -# and $packages{"apacite"}!~/natbibpapa/ -my ($citpat,$citpatsafe); - -if ( defined $packages{"apacite"} ) { - print STDERR "DEBUG apacite citation commands\n" if $debug; - $citpatsafe=qr/^(?:mask)?(?:full|short)?cite(?:A|author|year)?(?:NP)?$/; - $citpat='(?:mask)?(?:full|short|no)?cite(?:A|author|year|meta)?(?:NP)?'; -} else { - # citation command pattern for all other citation schemes - $citpatsafe=qr/^cite.*$/; - $citpat='(?:cite\w*|nocite)'; -}; - -if ( uc($type) ne "UNDERLINE" && uc($type) ne "FONTSTRIKE" && uc($type) ne "CULINECHBAR" ) { - push (@SAFECMDLIST, $citpatsafe); -} else { - ### Experimental: disable text and emph commands - push (@SAFECMDLIST, $citpatsafe) unless $disablecitmark; - push(@SAFECMDEXCL, qr/^emph$/, qr/^text..$/); - # replace \cite{..} by \mbox{\cite{..}} in added or deleted blocks in post-processing - if ( uc($subtype) eq "COLOR" or uc($subtype) eq "DVIPSCOL" ) { - # remove \cite command again from list of safe commands - pop @SAFECMDLIST; - # deleted cite commands - $CITE2CMD=$citpat unless $disablecitmark ; # \cite-type commands which should be reinstated in deleted blocks - } else { - $CITECMD=$citpat unless $disablecitmark ; # \cite commands which need to be protected within an mbox in UNDERLINE and other modes using ulem - } -} -$CITECMD=$citpat if $enablecitmark ; # as above for explicit selection - -print STDERR "CITECMD:|$CITECMD|\n" if $debug; - -if (defined $packages{"amsmath"} or defined $packages{"amsart"} or defined $packages{"amsbook"} ) { - print STDERR "amsmath package detected.\n" if $verbose ; - $MATHARRREPL='align*'; -} - -print STDERR "Preprocessing body. " if $verbose; -my ($oldleadin,$newleadin)=preprocess($oldbody,$newbody); - - -# run difference algorithm -@diffbody=bodydiff($oldbody, $newbody); -$diffbo=join("",@diffbody); -if ( $debug ) { - open(RAWDIFF,">","latexdiff.debug.bodydiff"); - print RAWDIFF $diffbo; - close(RAWDIFF); -} -print STDERR "(",exetime()," s)\n","Postprocessing body. \n " if $verbose; -postprocess($diffbo); -$diffall =join("\n",@diffpreamble) ; -# add visible labels -if (defined($visiblelabel)) { - # Give information right after \begin{document} (or at the beginning of the text for files without preamble - ### if \date command is used, add information to \date argument, otherwise give right after \begin{document} - ### $diffall=~s/(\\date$extraspace(?:\[$brat0\])?$extraspace)\{($pat6)\}/$1\{$2 \\ LATEXDIFF comparison \\ Old: $oldlabel \\ New: $newlabel \}/ or - $diffbo = "\\begin{verbatim}LATEXDIFF comparison\nOld: $oldlabel\nNew: $newlabel\\end{verbatim}\n$diffbo" ; -} - -$diffall .= "$newleadin$diffbo" ; -$diffall .= "\\end{document}$newpost" if length $newpreamble ; -if ( lc($encoding) ne "utf8" && lc($encoding) ne "ascii" ) { - print STDERR "Encoding output file to $encoding\n" if $verbose; - $diffall=Encode::encode($encoding,$diffall); - binmode STDOUT; -} -print $diffall; - - -print STDERR "(",exetime()," s)\n","Done.\n" if $verbose; - - - -## guess_encoding(filename) -## reads the first 20 lines of filename and looks for call of inputenc package -## if found, return the option of this package (encoding), otherwise return ascii -sub guess_encoding { - my ($filename)=@_; - my ($i,$enc); - open (FH, $filename) or die("Couldn't open $filename: $!"); - $i=0; - while () { - next if /^\s*%/; # skip comment lines - if (m/\\usepackage\[(\w*?)\]\{inputenc\}/) { - close(FH); - return($1); - } - last if (++$i > 20 ); # scan at most 20 non-comment lines - } - close(FH); - return("ascii"); -} - - -sub read_file_with_encoding { - my ($output); - my ($filename, $encoding) = @_; - - if (lc($encoding) eq "utf8" ) { - open (FILE, "<:utf8",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } elsif ( lc($encoding) eq "ascii") { - open (FILE, $filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } else { - require Encode; - open (FILE, "<",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - print STDERR "Converting $filename from $encoding to utf8\n" if $verbose; - $output=Encode::decode($encoding,$output); - } - close FILE; - if ($^O eq "linux" ) { - $output =~ s/\r\n/\n/g ; - } - return $output; -} - -# %packages=list_packages(@preamble) -# scans the arguments for \documentclass,\RequirePackage and \usepackage statements and constructs a hash -# whose keys are the included packages, and whose values are the associated optional arguments -sub list_packages { - my (@preamble)=@_; - my %packages=(); - foreach $line ( @preamble ) { - # get rid of comments - $line=~s/(?catfile($dirname,$fname), "\n" if $debug; - # content of file becomes replacement value (use recursion), add \newpage if the command was include - ###$replacement=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - $replacement=flatten(read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding), $preamble,$filename,$encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - # \include always starts a new page; use explicit \newpage command to simulate this - $begline=(defined($1)? $1 : "") ; - $newpage=(defined($3)? " \\newpage " : "") ; - "$begline$newpage$replacement$newpage"; - }/exgm; - # replace bibliography with bbl file if it exists - $text=~s/(^(?:[^%\n]|\\%)*)\\bibliography{(.*?)}/{ - if ( -f $bblfile ){ - $replacement=read_file_with_encoding(File::Spec->catfile($bblfile), $encoding); - } else { - warn "Bibliography file $bblfile cannot be found. No flattening of \\bibliography done. Run bibtex on old and new files first"; - $replacement="\\bibliography{$2}"; - } - $begline=(defined($1)? $1 : "") ; - "$begline$replacement"; - }/exgm; - # replace subfile with contents (subfile package) - $text=~s/(^(?:[^%\n]|\\%)*)\\subfile{(.*?)}/{ - $fname = $2; - # # add tex extension unless there is a three letter extension already - $fname .= ".tex" unless $fname =~ m|\.\w{3}|; - print STDERR "DEBUG Beg of line match |$1|\n" if defined($1) && $debug ; - print STDERR "Include file as subfile $fname\n" if $verbose; - print STDERR "DEBUG looking for file ",File::Spec->catfile($dirname,$fname), "\n" if $debug; - # content of file becomes replacement value (use recursion) - # now strip away everything outside and including \begin{document} and \end{document} pair# - # # note: no checking for comments is made - $subfile=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - ($subpreamble,$subbody,$subpost)=splitdoc($subfile,'\\\\begin\{document\}','\\\\end\{document\}'); - $replacement=flatten($subbody, $preamble,$filename,$encoding); - $begline=(defined($1)? $1 : "") ; - "$begline$replacement"; - }/exgm; - - return($text); -} - - -# print_regex_arr(@arr) -# prints regex array without x-ism expansion put in by pearl to stdout -sub print_regex_arr { - my $dumstring; - $dumstring = join(" ",@_); # PERL generates string (?-xism:^ref$) for quoted refex ^ref$ - $dumstring =~ s/\(\?-xism:\^(.*?)\$\)/$1/g; # remove string and ^,$ marks before output - print $dumstring,"\n"; -} - - -# @lines=extrapream($type) -# reads line from appendix (end of file after __END__ token) -sub extrapream { - my $type; - my @retval=("%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - my ($copy); - - while (@_) { - $copy=0; - $type=shift ; - if ( -f $type || lc $type eq '/dev/null' ) { - open (FILE,$type) or die "Cannot open preamble file $type: $!"; - print STDERR "Reading preamble file $type\n" if $verbose ; - while () { - chomp ; - if ( $_ =~ m/%DIF PREAMBLE/ ) { - push (@retval,"$_"); - } else { - push (@retval,"$_ %DIF PREAMBLE"); - } - } - } - else { # not (-f $type) - $type=uc($type); # upcase argument - print STDERR "Preamble Internal Type $type\n" if $verbose; - while () { - if ( m/^%DIF $type/ ) { - $copy=1; } - elsif ( m/^%DIF END $type/ ) { - last; } - chomp; - push (@retval,"$_ %DIF PREAMBLE") if $copy; - } - if ( $copy == 0 ) { - print STDERR "\nPreamble style $type not implemented.\n"; - print STDERR "Write latexdiff -h to get help with available styles\n"; - exit(2); - } - seek DATA,0,0; # rewind DATA handle to file begin - } - } - push (@retval,"%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - return @retval; -} - - -# ($part1,$part2,$part3)=splitdoc($text,$word1,$word2) -# splits $text into 3 parts at $word1 and $word2. -# if neither $word1 nor $word2 exist, $part1 and $part3 are empty, $part2 is $text -# If only $word1 or $word2 exist but not the other, output an error message. - -# NB this version avoids $` and $' for performance reason although it only makes a tiny difference -# (in one test gain a tenth of a second for a 30s run) -sub splitdoc { - my ($text,$word1,$word2)=@_; - my ($part1,$part2,$part3)=("","",""); - my ($rest,$pos); - - if ( $text =~ m/(^[^%]*)($word1)/mg ) { - $pos=pos $text; - $part1=substr($text,0,$pos-length($2)); - $rest=substr($text,$pos); - if ( $rest =~ m/(^[^%]*)($word2)/mg ) { - $pos=pos $rest; - $part2=substr($rest,0,$pos-length($2)); - $part3=substr($rest,$pos); - } - else { - die "$word1 and $word2 not in the correct order or not present as a pair." ; - } - } else { - $part2=$text; - die "$word2 present but not $word1." if ( $text =~ m/(^[^%]*)$word2/ms ); - } - return ($part1,$part2,$part3); -} - - - - - -# bodydiff($old,$new) -sub bodydiff { - my ($oldwords, $newwords) = @_; - my @retwords; - - print STDERR "(",exetime()," s)\n","Splitting into latex tokens \n" if $verbose; - print STDERR "Parsing $oldfile \n" if $verbose; - my @oldwords = splitlatex($oldwords); - print STDERR "Parsing $newfile \n" if $verbose; - my @newwords = splitlatex($newwords); - - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - print STDERR "(",exetime()," s)\n","Pass 1: Expanding text commands and merging isolated identities with changed blocks " if $verbose; - pass1(\@oldwords, \@newwords); - - - print STDERR "(",exetime()," s)\n","Pass 2: inserting DIF tokens and mark up. " if $verbose; - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold2.tex"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew2.tex"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - @retwords=pass2(\@oldwords, \@newwords); - - return(@retwords); -} - - - - -# @words=splitlatex($string) -# split string according to latex rules -# Each element of words is either -# a word (including trailing spaces and punctuation) -# a latex command -sub splitlatex { - my ($string) = @_ ; - # if input is empty, return empty list - length($string)>0 or return (); - - my @retval=($string =~ m/$pat/osg); - - if (length($string) != length(join("",@retval))) { - print STDERR "\nWARNING: Inconsistency in length of input string and parsed string:\n This often indicates faulty or non-standard latex code.\n In many cases you can ignore this and the following warning messages.\n Note that character numbers in the following are counted beginning after \\begin{document} and are only approximate." unless $ignorewarnings; - print STDERR "DEBUG Original length ",length($string)," Parsed length ",length(join("",@retval)),"\n" if $debug; - print STDERR "DEBUG Input string: |$string|\n" if (length($string)<500) && $debug; - print STDERR "DEBUG Token parsing: |",join("+",@retval),"|\n" if (length($string)<500) && $debug ; - @retval=(); - # slow way only do this if other m//sg method fails - my $last = 0; - while ( $string =~ m/$pat/osg ) { - my $match=$&; - if ($last + length $& != pos $string ) { - my $pos=pos($string); - my $offset=30<$last ? 30 : $last; - my $dum=substr($string,$last-$offset,$pos-$last+2*$offset); - my $dum1=$dum; - my $cnt=$#retval; - my $i; - $dum1 =~ s/\n/ /g; - unless ($ignorewarnings) { - print STDERR "\n$dum1\n"; - print STDERR " " x 30,"^" x ($pos-$last)," " x 30,"\n"; - print STDERR "Missing characters near word " . (scalar @retval) . " character index: " . $last . "-" . pos($string) . " Length: " . length($match) . " Match: |$match| (expected match marked above).\n"; - } - # put in missing characters `by hand' - push (@retval, substr($dum,$offset,$pos-$last-length($match))); -# Note: there seems to be a bug in substr with utf8 that made the following line output substr which were too long, -# using dum instead appears to work -# push (@retval, substr($string,$last, pos($string)-$last-length($match))); - } - push (@retval, $match); - $last=pos $string; - } - - } - return @retval; -} - - -# pass1( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Where an common-subsequence block is flanked by deleted or appended blocks, -# and is shorter than $MINWORDSBLOCK words it is appended -# to the last deleted or appended word. If the block contains tokens other than words -# or punctuation it is not merged. -# Deleted or appended block consisting of words and safe commands only are -# also merged, to prevent break-up in pass2 (after previous isolated words have been removed) -# If there are commands with textual arguments (e.g. \caption) both in corresponding -# appended and deleted blocks split them such that the command and opening bracket -# are one token, then the rest is split up following standard rules, and the closing -# bracket is a separate token, ie. turn -# "\caption{This is a textual argument}" into -# ("\caption{","This ","is ","a ","textual ","argument","}") -# No return value. Destructively changes sequences -sub pass1 { - my $seq1 = shift ; - my $seq2 = shift ; - - my $len1 = scalar @$seq1; - my $len2 = scalar @$seq2; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - - my ($last1,$last2)=(-1,-1) ; - my $cnt=0; - my $block=[]; - my $addblock=[]; - my $delblock=[]; - my $todo=[]; - my $instruction=[]; - my $i; - my (@delmid,@addmid,@dummy); - - my ($addcmds,$delcmds,$matchindex); - my ($addtextblocks,$deltextblocks); - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $adddiscard = sub { - if ($cnt > 0 ) { - $matblkcnt++; - # just after an unchanged block -# print STDERR "Unchanged block $cnt, $last1,$last2 \n"; - if ($cnt < $MINWORDSBLOCK - && $cnt==scalar ( - grep { /^$wpat/ || ( /^\\([\w\d\*]+)((?:\[$brat0\]|\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && scalar(@dummy=split(" ",$2))<3 ) } - @$block) ) { - # merge identical blocks shorter than $MINWORDSBLOCK - # and only containing ordinary words - # with preceding different word - # We cannot carry out this merging immediately as this - # would change the index numbers of seq1 and seq2 and confuse - # the algorithm, instead we store in @$todo where we have to merge - push(@$todo, [ $last1,$last2,$cnt,@$block ]); - } - $block = []; - $cnt=0; $last1=-1; $last2=-1; - } - }; - my $discard=sub { $deltokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$delblock,[ $seq1->[$_[0]],$_[0] ]); - $last1=$_[0] }; - - my $add = sub { $addtokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$addblock,[ $seq2->[$_[1]],$_[1] ]); - $last2=$_[1] }; - - my $match = sub { $mattokcnt++; - if ($cnt==0) { # first word of matching sequence after changed sequence or at beginning of word sequence - $deltextblocks = extracttextblocks($delblock); - $delblkcnt++ if scalar @$delblock; - $addtextblocks = extracttextblocks($addblock); - $addblkcnt++ if scalar @$addblock; - - $delcmds = extractcommands($delblock); - $addcmds = extractcommands($addblock); - # keygen(third argument of _longestCommonSubsequence) implies to sort on command (0th elements of $addcmd elements) - # the calling format for longestCommonSubsequence has changed between versions of - # Algorithm::Diff so we need to check which one we are using - if ( $algodiffversion > 1.15 ) { - ### Algorithm::Diff 1.19 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, 0, sub { $_[0]->[0] } ); - } else { - ### Algorithm::Diff 1.15 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, sub { $_[0]->[0] } ); - } - - for ($i=0 ; $i<=$#$matchindex ; $i++) { - if (defined($matchindex->[$i])){ - $j=$matchindex->[$i]; - @delmid=splitlatex($delcmds->[$i][3]); - @addmid=splitlatex($addcmds->[$j][3]); - while (scalar(@$deltextblocks) && $deltextblocks->[0][0]<$delcmds->[$i][1]) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) }; - push(@$todo, [$index,-1,$cnt,@$block]); - } - push(@$todo, [ $delcmds->[$i][1],-1,-1,$delcmds->[$i][2],@delmid,$delcmds->[$i][4]]); - - while (scalar(@$addtextblocks) && $addtextblocks->[0][0]<$addcmds->[$j][1]) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - push(@$todo, [ -1,$addcmds->[$j][1],-1,$addcmds->[$j][2],@addmid,$addcmds->[$j][4]]); - } - } - # mop up remaining textblocks - while (scalar(@$deltextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) } ; - push(@$todo, [$index,-1,$cnt,@$block]); - } - while (scalar(@$addtextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - - $addblock=[]; - $delblock=[]; - } - push(@$block,$seq2->[$_[1]]); - $cnt++ }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - - - # now carry out the merging/splitting. Refer to elements relative from - # the end (with negative indices) as these offsets don't change before the instruction is executed - # cnt>0: merged small unchanged groups with previous changed blocks - # cnt==-1: split textual commands into components - foreach $instruction ( @$todo) { - ($last1,$last2,$cnt,@$block)=@$instruction ; - if ($cnt>=0) { - splice(@$seq1,$last1-$len1,1+$cnt,join("",$seq1->[$last1-$len1],@$block)) if $last1>=0; - splice(@$seq2,$last2-$len2,1+$cnt,join("",$seq2->[$last2-$len2],@$block)) if $last2>=0; - } else { - splice(@$seq1,$last1-$len1,1,@$block) if $last1>=0; - splice(@$seq2,$last2-$len2,1,@$block) if $last2>=0; - } - } - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens in $matblkcnt blocks.\n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } -} - - -# extracttextblocks(\@blockindex) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [[ $index, $textblock, $cnt ], .. -# where $index index of block to be merged -# $textblock contains all the words to be merged with the word at $index (but does not contain this word) -# $cnt is length of block -# -# requires: iscmd -# -sub extracttextblocks { - my $block=shift; - my ($i,$token,$index); - my $textblock=[]; - my $last=-1; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # store pure text blocks - if ($token =~ /$wpat/ || ( $token =~/^\\([\w\d\*]+)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && !iscmd($1,\@TEXTCMDLIST,\@TEXTCMDEXCL))) { - # we have text or a command which can be treated as text - if ($last<0) { - # new pure-text block - $last=$index; - } else { - # add to pure-text block - push(@$textblock, $token); - } - } else { - # it is not text - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - $textblock=[]; - $last=-1; - } - } - # finish processing a possibly unfinished block before returning - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - return($retval) -} - - - -# extractcommands( \@blockindex ) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [ [ "\cmd1", index, "\cmd1[optarg]{arg1}{", "arg2" ,"} " ],.. -# where index is just taken from input array -# command must have a textual argument as last argument -# -# requires: iscmd -# -sub extractcommands { - my $block=shift; - my ($i,$token,$index,$cmd,$open,$mid,$closing); - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: \cmd - # $3: last argument - # $4: } + trailing spaces - if ( ( $token =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL) ) { - # push(@$retval,[ $2,$index,$1,$3,$4 ]); - ($cmd,$open,$mid,$closing) = ($2,$1,$3,$4) ; - $closing =~ s/\}/\\RIGHTBRACE/ ; - push(@$retval,[ $cmd,$index,$open,$mid,$closing ]); - } - } - return $retval; -} - -# iscmd($cmd,\@regexarray,\@regexexcl) checks -# return 1 if $cmd matches any of the patterns in the -# array $@regexarray, and none of the patterns in \@regexexcl, otherwise return 0 -sub iscmd { - my ($cmd,$regexar,$regexexcl)=@_; - my ($ret)=0; - foreach $pat ( @$regexar ) { - if ( $cmd =~ m/^${pat}$/ ) { - $ret=1 ; - last; - } - } - return 0 unless $ret; - foreach $pat ( @$regexexcl ) { - return 0 if ( $cmd =~ m/^${pat}$/ ); - } - return 1; -} - - -# pass2( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Mark begin and end of deleted and appended sequences with tags $DELOPEN and $DELCLOSE -# and $ADDOPEN and $ADDCLOSE, respectively, however exclude { } & and all comands, unless -# they match an element of the whitelist (SAFECMD) -# For words in TEXTCMD but not in SAFECMD, enclose interior with $ADDOPEN and $ADDCLOSE brackets -# Deleted comment lines are marked with %DIF < -# Added comment lines are marked with %DIF > -sub pass2 { - my $seq1 = shift ; - my $seq2 = shift ; - - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $retval = []; - my $delhunk = []; - my $addhunk = []; - - my $discard = sub { $deltokcnt++; - push ( @$delhunk, $seq1->[$_[0]]) }; - - my $add = sub { $addtokcnt++; - push ( @$addhunk, $seq2->[$_[1]]) }; - - my $match = sub { $mattokcnt++; - if ( scalar @$delhunk ) { - $delblkcnt++; - # mark up changes, but comment out commands - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk); - $delhunk = []; - } - if ( scalar @$addhunk ) { - $addblkcnt++; - # we mark up changes, but simply quote commands - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk); - $addhunk = []; - } - push(@$retval,$seq2->[$_[1]]) }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - # clear up unprocessed hunks - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk) if scalar @$delhunk; - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk) if scalar @$addhunk; - - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens. \n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } - - return(@$retval); -} - -# marktags($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,\@block) -# returns ($openmark,$open,$block,$close,$closemark) if @block only contains no commands (except white-listed ones), -# braces, ampersands, or comments -# mark comments with $comment -# exclude all other exceptions from scope of open, close like this -# ($openmark, $open,...,$close, $opencmd,command, command,$closecmd, $open, ..., $close, $closemark) -# If $opencmd begins with "%" marktags assumes it is operating on a deleted block, otherwise on an added block -sub marktags { - my ($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,$block)=@_; - my $word; - my (@argtext); - my $retval=[]; - my $noncomment=0; - my $cmd=-1; # -1 at beginning 0: last token written is a ordinary word - # 1: last token written is a command - # for keeping track whether we are just in a command sequence or in a word sequence - my $cmdcomment= ($opencmd =~ m/^%/); # Flag to indicate whether opencmd is a comment (i.e. if we intend to simply comment out changed commands) - my ($command,$commandword,$closingbracket) ; # temporary variables needed below to remember sub-pattern matches - -# split this block to flatten out sequences joined in pass1 - @$block=splitlatex(join "",@$block); - foreach (@$block) { - $word=$_; - if ( $word =~ s/^%/%$comment/ ) { - # a comment - if ($cmd==1) { - push (@$retval,$closecmd) ; - $cmd=-1; - } - push (@$retval,$word); - next; - } - if (! $noncomment) { - push (@$retval,$openmark); - $noncomment=1; - } - # negative lookahead pattern (?!) in second clause is put in to avoid mathcing \( .. \) patterns - # also note that second pattern will match \\ - # Note: the second pattern should really be $word =~ /^\\(?!\()(\\|[\w*@]+)/, ie * replaced by + - # and then all commands \" \' etc declared safe. But as I don't have a complete list of one letter - # commands, and nobody has complained so far, I will eave this as is - if ( $word =~ /^[&{}\[\]]/ || ( $word =~ /^\\(?!\()(\\|[\w*@]*)/ && !iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL)) ) { - # word is a command or other significant token (not in SAFECMDLIST) - ## same conditions as in subroutine extractcommand: - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: cmd - # $3: last argument - # $4: } + trailing spaces - ### pre-0.3 if ( ( $token =~ m/^(\\([\w\d\*]+)(?:\[$brat0\]|\{$pat6\})*\{)($pat6)(\}\s*)$/so ) - if ( ( $word =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && (iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL)|| iscmd($2,\@MATHTEXTCMDLIST,\@MATHTEXTCMDEXCL)) - && ( !$cmdcomment || !iscmd($2,\@CONTEXT2CMDLIST, \@CONTEXT2CMDEXCL) ) ) { - # Condition 1: word is a command? - if yes, $1,$2,.. will be set as above - # Condition 2: word is a text command - we mark up the interior of the word. There is a separate check for MATHTEXTCMDLIST - # because for $mathmarkup=WHOLE, the commands should not be split in pass1 (ie. math mode commands are not in - # TEXTCMDLIST, but the interior of MATHTEXT commands should be highlighted in both deleted and added blocks - # Condition 3: But if we are in a deleted block ($cmdcomment=1) and - # $2 (the command) is in context2, just treat it as an ordinary command (i.e. comment it open with $opencmd) - # Because we do not want to disable this command - # here we do not use $opencmd and $closecmd($opencmd is empty) - if ($cmd==1) { - push (@$retval,$closecmd) ; - } elsif ($cmd==0) { - push (@$retval,$close) ; - } - $command=$1; $commandword=$2; $closingbracket=$4; - @argtext=splitlatex($3); # split textual argument into tokens - # and mark it up (but we do not need openmark and closemark) - # insert command with initial arguments, marked-up final argument, and closing bracket - if ( $cmdcomment && iscmd($commandword,\@CONTEXT1CMDLIST, \@CONTEXT1CMDEXCL) ) { - # context1cmd in a deleted environment; delete command itself but keep last argument, marked up - push (@$retval,$opencmd); - $command =~ s/\n/\n${opencmd}/sg ; # repeat opencmd at the beginning of each line - # argument, note that the additional comment character is included - # to suppress linebreak after opening parentheses, which is important - # for latexrevise - push (@$retval,$command,"%\n{$AUXCMD\n",marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } elsif ( iscmd($commandword,,\@MATHTEXTCMDLIST, \@MATHTEXTCMDEXCL) ) { - # MATHBLOCK pseudo command: consider all commands safe, except & and \\ - # Keep these commands even in deleted blocks, hence set $opencmd and $closecmd (5th and 6th argument of marktags) to - # "" - local @SAFECMDLIST=(".*"); - local @SAFECMDEXCL=('\\','\\\\',@UNSAFEMATHCMD); - push(@$retval,$command,marktags("","",$open,$close,"","",$comment,\@argtext)#@argtext - ,$closingbracket); - } else { - # normal textcmd or context1cmd in an added block - push (@$retval,$command,marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } - push (@$retval,$AUXCMD,"\n") if $cmdcomment ; - $cmd=-1 ; - } else { - # ordinary command - push (@$retval,$opencmd) if $cmd==-1 ; - push (@$retval,$close,$opencmd) if $cmd==0 ; - $word =~ s/\n/\n${opencmd}/sg if $cmdcomment ; # if opencmd is a comment, repeat this at the beginning of every line - push (@$retval,$word); - $cmd=1; - } - } else { - # just an ordinary word or word in SAFECMD - push (@$retval,$open) if $cmd==-1 ; - push (@$retval,$closecmd,$open) if $cmd==1 ; - push (@$retval,$word); - $cmd=0; - } - } - push (@$retval,$close) if $cmd==0; - push (@$retval,$closecmd) if $cmd==1; - - push (@$retval,$closemark) if ($noncomment); - return @$retval; -} - -# preprocess($string, ..) -# carry out the following pre-processing steps for all arguments: -# 1. Remove leading white-space -# Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE -# #. Change {,} in comments to \CLEFTBRACE, \CRIGHTBRACE -# 2. mark all first empty line (in block of several) with \PAR tokens -# 3. Convert all '\%' into '\PERCENTAGE ' and all '\$' into \DOLLAR to make parsing regular expressions easier -# 4. Convert all \verb|some verbatim text| commands (where | can be an arbitrary character) -# into \verb{hash} -# 5. Convert \begin{verbatim} some verbatim text \end{verbatim} into \verbatim{hash} -# 6. Convert _n into \SUBSCRIPTNB{n} and _{nnn} into \SUBSCRIPT{nn} -# 7. Convert ^n into \SUPERSCRIPTNB{n} and ^{nnn} into \SUPERSCRIPT{nn} -# 8. a. Convert $$ $$ into \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} -# b. Convert \[ \] into \begin{SQUAREBRACKET} \end{SQUAREBRACKET} -# 9. Convert all picture environmentent (\begin{PICTUREENV} .. \end{PICTUREENV} \PICTUREBLOCKenv -# For --block-math-markup option -convert all \begin{MATH} .. \end{MATH} -# into \MATHBLOCKmath{...} commands, where MATH/math is any valid math environment - -# 10. Add final token STOP to the very end. This is put in because the algorithm works better if the last token is identical. This is removed again in postprocessing. -# -# NB: step 6 and 7 is likely to convert some "_" inappropriately, e.g. in file -# names or labels but it does not matter because they are converted back in the postprocessing step -# Returns: leading white space removed in step 1 -sub preprocess { - my @leadin=() ; - for (@_) { - s/^(\s*)//s; - push(@leadin,$1); - # Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE - s/(?{$hstr}) && $string ne $hash->{$hstr}) { - warn "Repeated hash value for verbatim mode in spite of different content."; - $hstr="-$hstr"; - } - $hash->{$hstr}=$string; - return($hstr); -} - -#string=fromhash(\%hash,$fromstring) -# restores string value stored in hash -#string=fromhash(\%hash,$fromstring,$prependstring) -# additionally begins each line with prependstring -sub fromhash { - my ($hash,$hstr)=($_[0],$_[1]); - my $retstr=$hash->{$hstr}; - if ( $#_ >= 2) { - $retstr =~ s/^/$_[2]/mg; - } - return $retstr; -} - - -# postprocess($string, ..) -# carry out the following post-processing steps for all arguments: -# * Remove STOP token from the end -# * Replace \RIGHTBRACE by } -# * change citation commands within comments to protect from processing (using marker CITEDIF) -# 1. Check all deleted blocks: -# a.where a deleted block contains a matching \begin and -# \end environment (these will be disabled by a %DIFDELCMD statements), for selected environments enable -# these commands again (such that for example displayed math in a deleted equation -# is properly within math mode. For math mode environments replace numbered equation -# environments with their display only variety (so that equation numbers in new file and -# diff file are identical). Where the correct type of math environment cannot be determined -# use a place holder MATHMODE -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file -# Replace all MATHMODE environment commands by the correct environment to achieve matching -# pairs -# c. Convert MATHBLOCKmath commands to their uncounted numbers (e.g. convert equation -> displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL -# d. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# For added blocks: -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# 2. If --block-math-markup option set: Convert \MATHBLOCKmath{..} commands back to environments -# -# Convert all PICTUREblock{..} commands back to the appropriate environments -# 3. Convert DIFadd, DIFdel, DIFFaddbegin , ... into FL varieties -# within floats (currently recognised float environments: plate,table,figure -# plus starred varieties). -# 4. Remove empty %DIFDELCMD < lines -# 4. Convert \begin{SQUAREBRACKET} \end{SQUAREBRACKET} into \[ \] -# Convert \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} into $$ $$ -# 5. Convert \SUPERSCRIPTNB{n} into ^n and \SUPERSCRIPT{nn} into ^{nnn} -# 6. Convert \SUBSCRIPTNB{n} into _n and \SUBCRIPT{nn} into _{nnn} -# 7. Expand hashes of verb and verbatim environments -# 8. Convert '\PERCENTAGE ' back into '\%' and '\DOLLAR ' into '\$' -# 9.. remove all \PAR tokens -# 10. package specific processing: endfloat: make sure \begin{figure} and \end{figure} are always -# on a line by themselves, similarly for table environment -# 4, undo renaming of the \begin, \end,{,} in comments -# Change \QLEFTBRACE, \QRIGHTBRACE to \{,\} -# -# Note have to manually synchronize substitution commands below and -# DIF.. command names in the header -sub postprocess { - my ($begin,$len,$cnt,$float,$delblock,$addblock); - # second level blocks - my ($begin2,$cnt2,$len2,$eqarrayblock,$mathblock); - - for (@_) { - - # change $'s in comments to something harmless - 1 while s/(%.*)\$/$1DOLLARDIF/mg ; - - # Remove final STOP token - s/ STOP$//; - # Replace \RIGHTBRACE by } - s/\\RIGHTBRACE/}/g; - - # change citation commands within comments to protect from processing - if ($CITECMD){ - 1 while s/(%.*)\\($CITECMD)/$1\\CITEDIF$2/m ; - } - # Check all deleted blocks: where a deleted block contains a matching \begin and - # \end environment (these will be disabled by a %DIFDELCMD statements), enable - # these commands again (such that for example displayed math in a deleted equation - # is properly within math mode. For math mode environments replace numbered equation - # environments with their display only variety (so that equation numbers in new file and - # diff file are identical - while ( m/\\DIFdelbegin.*?\\DIFdelend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $delblock=$&; - - - ### (.*?[^\n]?)\n? construct is necessary to avoid empty lines in math mode, which result in - ### an error - # displayed math environments - if ($mathmarkup == FINE ) { - $delblock=~ s/(\%DIFDELCMD < \s*\\begin\{((?:$MATHENV)|SQUAREBRACKET)\}.*?(?:$DELCMDCLOSE|\n))(.*?[^\n]?)\n?(\%DIFDELCMD < \s*\\end\{\2\})/\\begin{$MATHREPL}$AUXCMD\n$1$3\n\\end{$MATHREPL}$AUXCMD\n$4/sg; - # also transform the opposite pair \end{displaymath} .. \begin{displaymath} but we have to be careful not to interfere with the results of the transformation in the line directly above - ### pre-0.42 obsolete version which did not work on eqnarray test $delblock=~ s/(? displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL - $delblock=~ s/\\MATHBLOCK($MATHENV)\{($pat6)\}/\\MATHBLOCK$MATHREPL\{$2\}/sg; - $delblock=~ s/\\MATHBLOCK($MATHARRENV)\{($pat6)\}/\\MATHBLOCK$MATHARRREPL\{$2\}/sg; - } - - -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file - $delblock=~ s/\\($COUNTERCMD)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*\s*${AUXCMD}\n)/\\$1$2\\addtocounter{$1}{-1}${AUXCMD}\n/sg ; - - -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es - while ( $delblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($delblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($delblock,$begin2,$len2)=$mathblock; - pos($delblock) = $begin2 + length($mathblock); - } - if ($CITE2CMD) { - $delblock=~s/($DELCMDOPEN\s*\\($CITE2CMD)(.*)$DELCMDCLOSE)/ - # Replacement code - {my ($aux,$all); - $aux=$all=$1; - $aux=~s#\n?($DELCMDOPEN|$DELCMDCLOSE)##g; - $all."$aux$AUXCMD\n";}/sge; - } - # or protect \cite commands with \mbox - if ($CITECMD) { - $delblock=~s/(\\($CITECMD)${extraspace}(?:<$abrat0>${extraspace})?(?:\[$brat0\]${extraspace}){0,2}\{$pat6\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - } - # if MBOXINLINEMATH is set, protect inlined math environments with an extra mbox - if ( $MBOXINLINEMATH ) { - # note additional \newline after command is omitted from output if right at the end of deleted block (otherwise a spurious empty line is generated) - $delblock=~s/($math)(?:[\s\n]*)?/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/sg; - } - -# splice in modified delblock - substr($_,$begin,$len)=$delblock; - pos = $begin + length($delblock); - } - # make the array modification in added blocks - while ( m/\\DIFaddbegin.*?\\DIFaddend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $addblock=$&; - while ( $addblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($addblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($addblock,$begin2,$len2)=$mathblock; - pos($addblock) = $begin2 + length($mathblock); - } - if ($CITECMD) { - my $addblockbefore=$addblock; - #(?:mask)?(?:full|short|no)?cite(?:A|author|year|meta)(?:NP)?$/ - ###my $CITECMD; $CITECMD="cite(?:A)$"; - $addblock=~ s/(\\($CITECMD)${extraspace}(?:<$abrat0>${extraspace})?(?:\[$brat0\]${extraspace}){0,2}\{$pat2\})(\s*)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/msg ; - print STDERR "DEBUG: CITECMD $CITECMD\nDEBUG: addblock before:|$addblockbefore|\n" if $debug; - print STDERR "DEBUG: addblock after: |$addblock|\n" if $debug; - } - # if MBOXINLINEMATH is set, protect inlined math environments with an extra mbox - if ( $MBOXINLINEMATH ) { - ##$addblock=~s/($math)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/sg; - $addblock=~s/($math)(?:[\s\n]*)?/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/sg; - } -# splice in modified addblock - substr($_,$begin,$len)=$addblock; - pos = $begin + length($addblock); - } - - - - # Replace MATHMODE environments from step 1a above by the correct Math environment - - # The next line is complicated. The negative look-ahead insertion makes sure that no \end{$MATHENV} (or other mathematical - # environments) are between the \begin{$MATHENV} and \end{MATHMODE} commands. This is necessary as the minimal matching - # is not globally minimal but only 'locally' (matching is beginning from the left side of the string) - if ( $mathmarkup == FINE ) { - 1 while s/\\begin{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}((?:.(?!(?:\\end{(?:(?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}|\\begin{MATHMODE})))*?)\\end{MATHMODE}/\\begin{$1}$2\\end{$1}/s; - 1 while s/\\begin{MATHMODE}((?:.(?!\\end{MATHMODE}))*?)\\end{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}/\\begin{$2}$1\\end{$2}/s; - # convert remaining \begin{MATHMODE} \end{MATHMODE} (and not containing & or \\ )into MATHREPL environments - s/\\begin{MATHMODE}((?:(.(?!(?[1])) { - $optargnew=$newhash{$cmd}->[1]; - } else { - $optargnew=""; - } - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - } else { - $optargold=""; - } - - if ( defined($oldhash{$cmd}) ) { - $argold=$oldhash{$cmd}->[2]; - } else { - $argold=""; - } - $argnew=$newhash{$cmd}->[2]; - $argdiff="{" . join("",bodydiff($argold,$argnew)) ."}"; - if ( length $optargnew ) { - $optargdiff="[".join("",bodydiff($optargold,$optargnew))."]" ; - $optargdiff =~ s/\\DIFaddbegin /\\DIFaddbeginFL /g; - $optargdiff =~ s/\\DIFaddend /\\DIFaddendFL /g; - $optargdiff =~ s/\\DIFadd\{/\\DIFaddFL{/g; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - ### print STDERR "DEBUG s/\\Q$newhash{$cmd}->[0]\\E/\\$cmd$optargdiff$argdiff/s\n"; - # Note: \Q and \E force literal interpretation of what it between them but allow - # variable interpolation, such that e.g. \title matches just that and not TAB-itle - $$newpreambleref=~s/\Q$newhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s; - # replace this in old preamble if necessary - if ( defined($oldhash{$cmd}->[0])) { - $$oldpreambleref=~s/\Q$oldhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s ; - } - ### print STDERR "DEBUG NEW PRE ".$$newpreambleref."\n"; - } - - foreach $cmd ( keys %oldhash ) { - # if this has already been dealt with above can just skip - next if defined($newhash{$cmd}) ; - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - $optargdiff="[".join("",bodydiff($optargold,""))."]" ; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - $argdiff="{" . join("",bodydiff($argold,"")) ."}"; - $auxline = "\\$cmd$optargdiff$argdiff"; - $auxline =~s/$/$AUXCMD/sg; - push @auxlines,$auxline; - } - # add auxcmd comment to highlight added lines - return(@auxlines); -} - - - -# @diffs=linediff(\@seq1, \@seq2) -# mark up lines like this -#%DIF mm-mmdnn -#%< old deleted line(s) -#%DIF ------- -#%DIF mmann-nn -#new appended line %< -#%DIF ------- -# Future extension: mark change explicitly -# Assumes: traverse_sequence traverses deletions before insertions in changed sequences -# all line numbers relative to line 0 (first line of real file) -sub linediff { - my $seq1 = shift ; - my $seq2 = shift ; - - my $block = []; - my $retseq = []; - my @begin=('','',''); # dummy initialisation - my $instring ; - - my $discard = sub { @begin=('d',$_[0],$_[1]) unless scalar @$block ; - push(@$block, "%DIF < " . $seq1->[$_[0]]) }; - my $add = sub { if (! scalar @$block) { - @begin=('a',$_[0],$_[1]) ;} - elsif ( $begin[0] eq 'd' ) { - $begin[0]='c'; $begin[2]=$_[1]; - push(@$block, "%DIF -------") } - push(@$block, $seq2->[$_[1]] . " %DIF > " ) }; - my $match = sub { if ( scalar @$block ) { - if ( $begin[0] eq 'd' && $begin[1]!=$_[0]-1) { - $instring = sprintf "%%DIF %d-%dd%d",$begin[1],$_[0]-1,$begin[2]; } - elsif ( $begin[0] eq 'a' && $begin[2]!=$_[1]-1) { - $instring = sprintf "%%DIF %da%d-%d",$begin[1],$begin[2],$_[1]-1; } - elsif ( $begin[0] eq 'c' ) { - $instring = sprintf "%%DIF %sc%s", - ($begin[1]==$_[0]-1) ? "$begin[1]" : $begin[1]."-".($_[0]-1) , - ($begin[2]==$_[1]-1) ? "$begin[2]" : $begin[2]."-".($_[1]-1) ; } - else { - $instring = sprintf "%%DIF %d%s%d",$begin[1],$begin[0],$begin[2]; } - push @$retseq, $instring,@$block, "%DIF -------" ; - $block = []; - } - push @$retseq, $seq2->[$_[1]] - }; - # key function: remove multiple spaces (such that insertion or deletion of redundant white space is not reported) - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - push @$retseq, @$block if scalar @$block; - - return wantarray ? @$retseq : $retseq ; -} - - - -# init_regex_arr_data(\@array,"TOKEN INIT") -# scans DATA file handel for line "%% TOKEN INIT" line -# then appends each line not beginning with % into array (as a quoted regex) -sub init_regex_arr_data { - my ($arr,$token)=@_; - my ($copy); - while () { - if ( m/^%%BEGIN $token\s*$/ ) { - $copy=1; } - elsif ( m/^%%END $token\s*/ ) { - last; } - chomp; - push (@$arr,qr/^$_$/) if ( $copy && !/^%/ ) ; - } - seek DATA,0,0; # rewind DATA handle to file begin -} - - -# init_regex_arr_ext(\@array,$arg) -# fills array with regular expressions. -# if arg is a file name, then read in list of regular expressions from that file -# (one expression per line) -# Otherwise treat arg as a comma separated list of regular expressions -sub init_regex_arr_ext { - my ($arr,$arg)=@_; - my $regex; - if ( -f $ arg ) { - open(FILE,"$arg") or die ("Couldn't open $arg: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@$arr,qr/^$_$/); - } - close(FILE); - } - else { - # assume it is a comma-separated list of reg-ex - foreach $regex (split(qr/(?=1) { - $reset=shift; - } - if ($reset) { - $lasttime=times(); - } - else { - $retval=times()-$lasttime; - $lasttime=$lasttime+$retval; - return($retval); - } -} - - -sub usage { - die <<"EOF"; -Usage: $0 [options] old.tex new.tex > diff.tex - -Compares two latex files and writes tex code to stdout, which has the same -format as new.tex but has all changes relative to old.tex marked up or commented. - ---type=markupstyle --t markupstyle Add code to preamble for selected markup style - Available styles: UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE - CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR - [ Default: UNDERLINE ] - ---subtype=markstyle --s markstyle Add code to preamble for selected style for bracketing - commands (e.g. to mark changes in margin) - Available styles: SAFE MARGINAL DVIPSCOL COLOR LABEL - [ Default: SAFE ] - ---floattype=markstyle --f markstyle Add code to preamble for selected style which - replace standard marking and markup commands within floats - (e.g., marginal remarks cause an error within floats - so marginal marking can be disabled thus) - Available styles: FLOATSAFE IDENTICAL - [ Default: FLOATSAFE ] - ---encoding=enc --e enc Specify encoding of old.tex and new.tex. Typical encodings are - ascii, utf8, latin1, latin9. A list of available encodings can be - obtained by executing - perl -MEncode -e 'print join ("\\n",Encode->encodings( ":all" )) ;' - [Default encoding is utf8 unless the first few lines of the preamble contain - an invocation "\\usepackage[..]{inputenc} in which case the - encoding chosen by this command is asssumed. Note that ASCII (standard - latex) is a subset of utf8] - ---preamble=file --p file Insert file at end of preamble instead of auto-generating - preamble. The preamble must define the following commands - \\DIFaddbegin,\\DIFaddend,\\DIFadd{..}, - \\DIFdelbegin,\\DIFdelend,\\DIFdel{..}, - and varieties for use within floats - \\DIFaddbeginFL,\\DIFaddendFL,\\DIFaddFL{..}, - \\DIFdelbeginFL,\\DIFdelendFL,\\DIFdelFL{..} - (If this option is set -t, -s, and -f options - are ignored.) - ---exclude-safecmd=exclude-file ---exclude-safecmd="cmd1,cmd2,..." --A exclude-file ---replace-safecmd=replace-file ---append-safecmd=append-file ---append-safecmd="cmd1,cmd2,..." --a append-file Exclude from, replace or append to the list of regex - matching commands which are safe to use within the - scope of a \\DIFadd or \\DIFdel command. The file must contain - one Perl-RegEx per line (Comment lines beginning with # or % are - ignored). A literal comma within the comma-separated list must be - escaped thus "\\,", Note that the RegEx needs to match the whole of - the token, i.e., /^regex\$/ is implied and that the initial - "\\" of the command is not included. The --exclude-safecmd - and --append-safecmd options can be combined with the --replace-safecmd - option and can be used repeatedly to add cumulatively to the lists. - ---exclude-textcmd=exclude-file ---exclude-textcmd="cmd1,cmd2,..." --X exclude-file ---replace-textcmd=replace-file ---append-textcmd=append-file ---append-textcmd="cmd1,cmd2,..." --x append-file Exclude from, replace or append to the list of regex - matching commands whose last argument is text. See - entry for --exclude-safecmd directly above for further details. - ---replace-context1cmd=replace-file ---append-context1cmd=append-file ---append-context1cmd="cmd1,cmd2,..." - Replace or append to the list of regex matching commands - whose last argument is text but which require a particular - context to work, e.g. \\caption will only work within a figure - or table. These commands behave like text commands, except when - they occur in a deleted section, when they are disabled, but their - argument is shown as deleted text. - ---replace-context2cmd=replace-file ---append-context2cmd=append-file ---append-context2cmd="cmd1,cmd2,..." - As corresponding commands for context1. The only difference is that - context2 commands are completely disabled in deleted sections, including - their arguments. - - ---config var1=val1,var2=val2,... --c var1=val1,.. Set configuration variables. --c configfile Available variables: - MINWORDSBLOCK (integer) - FLOATENV (RegEx) - PICTUREENV (RegEx) - MATHENV (RegEx) - MATHREPL (String) - MATHARRENV (RegEx) - MATHARRREPL (String) - ARRENV (RegEx) - COUNTERCMD (RegEx) - This option can be repeated. - - ---packages=pkg1,pkg2,.. - Tell latexdiff that .tex file is processed with the packages in list - loaded. This is normally not necessary if the .tex file includes the - preamble, as the preamble is automatically scanned for \\usepackage commands. - Use of the --packages option disables automatic scanning, so if for any - reason package specific parsing needs to be switched off, use --packages=none. - The following packages trigger special behaviour: - endfloat hyperref amsmath apacite - [ Default: scan the preamble for \\usepackage commands to determine - loaded packages.] - ---show-preamble Print generated or included preamble commands to stdout. - ---show-safecmd Print list of regex matching and excluding safe commands. - ---show-textcmd Print list of regex matching and excluding commands with text argument. - ---show-config Show values of configuration variables - ---show-all Show all of the above - - NB For all --show commands, no old.tex or new.tex file needs to be given, and no - differencing takes place. - -Other configuration options: - ---allow-spaces Allow spaces between bracketed or braced arguments to commands - [Default requires arguments to directly follow each other without - intervening spaces] - ---math-markup=level Determine granularity of markup in displayed math environments: - Possible values for level are (both numerical and text labels are acceptable): - off or 0: suppress markup for math environments. Deleted equations will not - appear in diff file. This mode can be used if all the other modes - cause invalid latex code. - whole or 1: Differencing on the level of whole equations. Even trivial changes - to equations cause the whole equation to be marked changed. This - mode can be used if processing in coarse or fine mode results in - invalid latex code. - coarse or 2: Detect changes within equations marked up with a coarse - granularity; changes in equation type (e.g.displaymath to equation) - appear as a change to the complete equation. This mode is recommended - for situations where the content and order of some equations are still - being changed. [Default] - fine or 3: Detect small change in equations and mark up and fine granularity. - This mode is most suitable, if only minor changes to equations are - expected, e.g. correction of typos. - ---disable-citation-markup Suppress citation markup in styles using ulem (UNDERLINE, - FONTSTRIKE, CULINECHBAR) ---enable-citation-markup Protect citation commands in changed sections with \\mbox command - [i.e. use default behaviour for ulem package for other packages] - -Miscelleneous options - ---label=label --L label Sets the labels used to describe the old and new files. The first use - of this option sets the label describing the old file and the second - use of the option sets the label for the new file. - [Default: use the filename and modification dates for the label] - ---no-label Suppress inclusion of old and new file names as comment in output file - ---visible-label Include old and new filenames (or labels set with --label option) as - visible output - ---flatten Replace \\input and \\include commands within body by the content - of the files in their argument. If \\includeonly is present in the - preamble, only those files are expanded into the document. However, - no recursion is done, i.e. \\input and \\include commands within - included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, - respectively, making it possible to organise files into old and new directories. - --flatten is applied recursively, so inputted files can contain further - \\input statements. - ---help --h Show this help text. - ---ignore-warnings Suppress warnings about inconsistencies in length between input - and parsed strings and missing characters. - ---verbose --V Output various status information to stderr during processing. - Default is to work silently. - ---version Show version number. - -EOF -} - -=head1 NAME - -latexdiff - determine and markup differences between two latex files - -=head1 SYNOPSIS - -B [ B ] F F > F - -=head1 DESCRIPTION - -Briefly, I is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called C and C, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. - -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "S>>" is appended to each added line, i.e. a -line present in C but not in C. Discarded lines - are deactivated by prepending "S>>". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file C will be similar to -C. At the end of the preamble, the definitions for I markup commands are inserted. -In differencing the main body of the text, I attempts to -satisfy the following guidelines (in order of priority): - -=over 3 - -=item 1 - -If both C and C are valid LaTeX, then the resulting -C should also be valid LateX. (NB If a few plain TeX commands -are used within C or C then C is not -guaranteed to work but usually will). - -=item 2 - -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -C. - -=item 3 - -If a changed passage contains text or text-producing commands, then -running C through LateX should produce output where added -and discarded passages are highlighted. - -=item 4 - -Where there are insignificant differences, e.g. in the positioning of -line breaks, C should follow the formatting of C - -=back - -For differencing the same algorithm as I is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, C<\caption> and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write - - \section{\textem{This is an emphasized section title}} - -and not - - \section {\textem{This is an emphasized section title}} - -or - - \section\textem{This is an emphasized section title} - -even though all varieties are the same to LaTeX (but see -B<--allow-spaces> option which allows the second variety). - -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the PICTUREENV configuration variable, set by -default to C and C environments; see B<--config> -option). The latter environment (C) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by C<\begin{DIFnomarkup}> and C<\end{DIFnomarkup}>. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, - -C<\newenvironment{DIFnomarkup}{}{}> - -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. - -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. - -All markup commands inserted by I begin with "C<\DIF>". Added -blocks containing words, commands or comments which are in C -but not in C are marked by C<\DIFaddbegin> and C<\DIFaddend>. -Discarded blocks are marked by C<\DIFdelbegin> and C<\DIFdelend>. -Within added blocks all text is highlighted with C<\DIFadd> like this: -C<\DIFadd{Added text block}> -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces "{" and "}" are never put within -the scope of C<\DIFadd>. Added comments are marked by prepending -"S >>". - -Within deleted blocks text is highlighted with C<\DIFdel>. Deleted -comments are marked by prepending "S >>". Non-safe command -and curly braces within deleted blocks are commented out with -"S >>". - - - -=head1 OPTIONS - -=head2 Preamble - -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. - -=over 4 - -=item B<--type=markupstyle> or -B<-t markupstyle> - -Add code to preamble for selected markup style. This option defines -C<\DIFadd> and C<\DIFdel> commands. -Available styles: - -C - -[ Default: C ] - -=item B<--subtype=markstyle> or -B<-s markstyle> - -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -C<\DIFaddbegin>, C<\DIFaddend>, C<\DIFdelbegin> and C<\DIFdelend> commands. -Available styles: C - -[ Default: C ] - -=item B<--floattype=markstyle> or -B<-f markstyle> - -Add code to preamble for selected style which -replace standard marking and markup commands within floats -(e.g., marginal remarks cause an error within floats -so marginal marking can be disabled thus). This option defines all -C<\DIF...FL> commands. -Available styles: C - -[ Default: C ] - -=item B<--encoding=enc> or -B<-e enc> - -Specify encoding of old.tex and new.tex. Typical encodings are -C, C, C, C. A list of available encodings can be -obtained by executing - -Cencodings( ":all" )) ;' > - -[Default encoding is utf8 unless the first few lines of the preamble contain -an invocation C<\usepackage[..]{inputenc}> in which case the -encoding chosen by this command is asssumed. Note that ASCII (standard -latex) is a subset of utf8] - -=item B<--preamble=file> or -B<-p file> - -Insert file at end of preamble instead of generating -preamble. The preamble must define the following commands -C<\DIFaddbegin, \DIFaddend, \DIFadd{..}, -\DIFdelbegin,\DIFdelend,\DIFdel{..},> -and varieties for use within floats -C<\DIFaddbeginFL, \DIFaddendFL, \DIFaddFL{..}, -\DIFdelbeginFL, \DIFdelendFL, \DIFdelFL{..}> -(If this option is set B<-t>, B<-s>, and B<-f> options -are ignored.) - -=item B<--packages=pkg1,pkg2,..> - -Tell latexdiff that .tex file is processed with the packages in list -loaded. This is normally not necessary if the .tex file includes the -preamble, as the preamble is automatically scanned for C<\usepackage> commands. -Use of the B<--packages> option disables automatic scanning, so if for any -reason package specific parsing needs to be switched off, use B<--packages=none>. -The following packages trigger special behaviour: - -=over 8 - -=item C - -Configuration variable amsmath is set to C (Default: C) - -=item C - -Ensure that C<\begin{figure}> and C<\end{figure}> always appear by themselves on a line. - -=item C - -Change name of C<\DIFadd> and C<\DIFdel> commands to C<\DIFaddtex> and C<\DIFdeltex> and -define new C<\DIFadd> and C<\DIFdel> commands, which provide a wrapper for these commands, -using them for the text but not for the link defining command (where any markup would cause -errors). - -=item C - -Redefine the commands recognised as citation commands. - -=back - -[ Default: scan the preamble for C<\\usepackage> commands to determine - loaded packages.] - - - -=item B<--show-preamble> - -Print generated or included preamble commands to stdout. - -=back - -=head2 Configuration - -=over 4 - -=item B<--exclude-safecmd=exclude-file> or -B<-A exclude-file> or B<--exclude-safecmd="cmd1,cmd2,..."> - -=item B<--replace-safecmd=replace-file> - -=item B<--append-safecmd=append-file> or -B<-a append-file> or B<--append-safecmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions (RegEx) -matching commands which are safe to use within the -scope of a C<\DIFadd> or C<\DIFdel> command. The file must contain -one Perl-RegEx per line (Comment lines beginning with # or % are -ignored). Note that the RegEx needs to match the whole of -the token, i.e., /^regex$/ is implied and that the initial -"\" of the command is not included. -The B<--exclude-safecmd> and B<--append-safecmd> options can be combined with the -B<--replace-safecmd> -option and can be used repeatedly to add cumulatively to the lists. - B<--exclude-safecmd> -and B<--append-safecmd> can also take a comma separated list as input. If a -comma for one of the regex is required, escape it thus "\,". In most cases it -will be necessary to protect the comma-separated list from the shell by putting -it in quotation marks. - -=item B<--exclude-textcmd=exclude-file> or -B<-X exclude-file> or B<--exclude-textcmd="cmd1,cmd2,..."> - -=item B<--replace-textcmd=replace-file> - -=item B<--append-textcmd=append-file> or -B<-x append-file> or B<--append-textcmd="cmd1,cmd2,..."> - -Exclude from, replace or append to the list of regular expressions -matching commands whose last argument is text. See -entry for B<--exclude-safecmd> directly above for further details. - - -=item B<--replace-context1cmd=replace-file> - -=item B<--append-context1cmd=append-file> or -=item B<--append-context1cmd="cmd1,cmd2,..."> - -Replace or append to the list of regex matching commands -whose last argument is text but which require a particular -context to work, e.g. \caption will only work within a figure -or table. These commands behave like text commands, except when -they occur in a deleted section, when they are disabled, but their -argument is shown as deleted text. - -=item B<--replace-context2cmd=replace-file> - -=item B<--append-context2cmd=append-file> or -=item B<--append-context2cmd="cmd1,cmd2,..."> -As corresponding commands for context1. The only difference is that -context2 commands are completely disabled in deleted sections, including -their arguments. - - - -=item B<--config var1=val1,var2=val2,...> or B<-c var1=val1,..> - -=item B<-c configfile> - -Set configuration variables. The option can be repeated to set different -variables (as an alternative to the comma-separated list). -Available variables (see below for further explanations): - -C (integer) - -C (RegEx) - -C (RegEx) - -C (RegEx) - -C (String) - -C (RegEx) - -C (String) - -C (RegEx) - -C (RegEx) - -=item B<--show-safecmd> - -Print list of RegEx matching and excluding safe commands. - -=item B<--show-textcmd> - -Print list of RegEx matching and excluding commands with text argument. - -=item B<--show-config> - -Show values of configuration variables. - -=item B<--show-all> - -Combine all --show commands. - -NB For all --show commands, no C or C file needs to be specified, and no -differencing takes place. - -=back - -=head2 Other configuration options: - -=over 4 - -=item B<--allow-spaces> - -Allow spaces between bracketed or braced arguments to commands. Note -that this option might have undesirable side effects (unrelated scope -might get lumpeded with preceding commands) so should only be used if the -default produces erroneous results. (Default requires arguments to -directly follow each other without intervening spaces). - -=item B<--math-markup=level> - -Determine granularity of markup in displayed math environments: -Possible values for level are (both numerical and text labels are acceptable): - -C or C<0>: suppress markup for math environments. Deleted equations will not -appear in diff file. This mode can be used if all the other modes -cause invalid latex code. - -C or C<1>: Differencing on the level of whole equations. Even trivial changes -to equations cause the whole equation to be marked changed. This -mode can be used if processing in coarse or fine mode results in -invalid latex code. - -C or C<2>: Detect changes within equations marked up with a coarse -granularity; changes in equation type (e.g.displaymath to equation) -appear as a change to the complete equation. This mode is recommended -for situations where the content and order of some equations are still -being changed. [Default] - -C or C<3>: Detect small change in equations and mark up at fine granularity. -This mode is most suitable, if only minor changes to equations are -expected, e.g. correction of typos. - -=item B<--disable-citation-markup> - -Suppress citation markup in styles using ulem (UNDERLINE, -FONTSTRIKE, CULINECHBAR) - -=item B<--enable-citation-markup> - -Protect citation commands in changed sections with \\mbox command [i.e. use default behaviour for ulem package for other packages] - -=back - -=head2 Miscellaneous - -=over 4 - -=item B<--verbose> or B<-V> - -Output various status information to stderr during processing. -Default is to work silently. - -=item B<--driver=type> - -Choose driver for changebar package (only relevant for styles using - changebar: CCHANGEBAR CFONTCHBAR CULINECHBAR CHANGEBAR). Possible -drivers are listed in changebar manual, e.g. pdftex,dvips,dvitops - [Default: dvips] - -=item B<--ignore-warnings> - -Suppress warnings about inconsistencies in length between input and -parsed strings and missing characters. These warning messages are -often related to non-standard latex or latex constructions with a -syntax unknown to C but the resulting difference argument -is often fully functional anyway, particularly if the non-standard -latex only occurs in parts of the text which have not changed. - -=item B<--label=label> or -B<-L label> - -Sets the labels used to describe the old and new files. The first use -of this option sets the label describing the old file and the second -use of the option sets the label for the new file, i.e. set both -labels like this C<-L labelold -L labelnew>. -[Default: use the filename and modification dates for the label] - -=item B<--no-label> - -Suppress inclusion of old and new file names as comment in output file - -=item B<--visble-label> - -Include old and new filenames (or labels set with --label option) as -visible output. - -=item B<--flatten> - -Replace C<\input> and C<\include> commands within body by the content -of the files in their argument. If C<\includeonly> is present in the -preamble, only those files are expanded into the document. However, -no recursion is done, i.e. C<\input> and C<\include> commands within -included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, -respectively, making it possible to organise files into old and new directories. ---flatten is applied recursively, so inputted files can contain further -C<\input> statements. - -Use of this option might result in prohibitive processing times for -larger documents, and the resulting difference document -no longer reflects the structure of the input documents. - -=item B<--help> or -B<-h> - -Show help text - -=item B<--version> - -Show version number - -=back - - - -=head2 Predefined styles - -=head2 Major types - -The major type determine the markup of plain text and some selected latex commands outside floats by defining the markup commands C<\DIFadd{...}> and C<\DIFdel{...}> . - -=over 10 - -=item C - -Added text is wavy-underlined and blue, discarded text is struck out and red -(Requires color and ulem packages). Overstriking does not work in displayed math equations such that deleted parts of equation are underlined, not struck out (this is a shortcoming inherent to the ulem package). - -=item C - -Added text is blue and set in sans-serif, and a red footnote is created for each discarded -piece of text. (Requires color package) - -=item C - -Like C but without the use of color. - -=item C - -Added text is blue and set in sans-serif, and discarded text is red and very small size. - -=item C - -Added tex is set in sans-serif, discarded text small and struck out - -=item C - -Added text is blue, and discarded text is red. Additionally, the changed text is marked with a bar in the margin (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color and changebar packages). - -=item C - -Like C but with additional changebars (Requires color, ulem and changebar packages). - -=item C - -No mark up of text, but mark margins with changebars (Requires changebar package). - -=item C - -No visible markup (but generic markup commands will still be inserted. - -=back - -=head2 Subtypes - -The subtype defines the commands that are inserted at the begin and end of added or discarded blocks, irrespectively of whether these blocks contain text or commands (Defined commands: C<\DIFaddbegin, \DIFaddend, \DIFdelbegin, \DIFdelend>) - -=over 10 - -=item C - -No additional markup (Recommended choice) - -=item C - -Mark beginning and end of changed blocks with symbols in the margin nearby (using -the standard C<\marginpar> command - note that this sometimes moves somewhat -from the intended position. - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. -(It is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete, for example -with citation commands). - -=item C - -An alternative way of marking added passages in blue, and deleted ones in red. Note -that C only works with the dvips converter, e.g. not pdflatex. -(it is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete). - -=back - -=head2 Float Types - -Some of the markup used in the main text might cause problems when used within -floats (e.g. figures or tables). For this reason alternative versions of all -markup commands are used within floats. The float type defines these alternative commands. - -=over 10 - -=item C - -Use identical markup for text as in the main body, but set all commands marking the begin and end of changed blocks to null-commands. You have to choose this float type if your subtype is C as C<\marginpar> does not work properly within floats. - -=item C - -Mark additions the same way as in the main text. Deleted environments are marked by angular brackets \[ and \] and the deleted text is set in scriptscript size. This float type should always be used with the C and C markup types as the \footnote command does not work properly in floating environments. - -=item C - -Make no difference between the main text and floats. - -=back - - -=head2 Configuration Variables - -=over 10 - -=item C - -Minimum number of tokens required to form an independent block. This value is -used in the algorithm to detect changes of complete blocks by merging identical text parts of less than C to the preceding added and discarded parts. - -[ Default: 3 ] - -=item C - -Environments whose name matches the regular expression in C are -considered floats. Within these environments, the I markup commands -are replaced by their FL variaties. - -[ Default: S >] - -=item C - -Within environments whose name matches the regular expression in C -all latexdiff markup is removed (in pathologic cases this might lead to - inconsistent markup but this situation should be rare). - -[ Default: S >] - -=item C,C - -If both \begin and \end for a math environment (environment name matching C -or \[ and \]) -are within the same deleted block, they are replaced by a \begin and \end commands for C -rather than being commented out. - -[ Default: C=S >, C=S >] - -=item C,C - -as C,C but for equation arrays - -[ Default: C=S >, C=S >] - -=item C - -If a match to C is found within an inline math environment within a deleted or added block, then the inlined math -is surrounded by C<\mbox{>...C<}>. This is necessary as underlining does not work within inlined array environments. - -[ Default: C=S > - -=item C - -If a command in a deleted block which is also in the textcmd list matches C then an -additional command C<\addtocounter{>FC<}{-1}>, where F is the matching command, is appended in the diff file such that the numbering in the diff file remains synchronized with the -numbering in the new file. - -[ Default: C=C<(?:footnote|part|section|subsection> ... - -C<|subsubsection|paragraph|subparagraph)> ] - -=back - -=head1 COMMON PROBLEMS - -=over 10 - -=item Citations result in overfull boxes - -There is an incompatibility between the C package, which C uses for underlining and striking out in the UNDERLINE style, -the default style. In order to be able to mark up citations properly, they are placed with an C<\mbox> command in post-processing. As mboxes -cannot be broken across lines, this procedure frequently results in overfull boxes, possibly obscuring the content as it extends beyond the right margin. If this is a problem, you have two possibilities: - -1. Use C or C subtype markup (option C<-s COLOR>): If this markup is chosen, then changed citations are no longer marked up -with the wavy line (additions) or struck out (deletions), but are still highlighted in the appropriate color. - -2. Choose option C<--disable-citation-markup> which turns off the marking up of citations: deleted citations are no longer shown, and -added ctations are shown without markup. (This was the default behaviour of latexdiff at versions 0.6 and older) - -=item Changes in complicated mathematical equations result in latex processing errors - -Try options C<--math-markup=whole>. If even that fails, you can turn off mark up for equations with C<--math-markup=off>. - -=back - -=head1 BUGS - -Option allow-spaces not implemented entirely consistently. It breaks -the rules that number and type of white space does not matter, as -different numbers of inter-argument spaces are treated as significant. - -Please submit bug reports using the issue tracker of the github repository page I, -or send them to I. Include the serial number of I -(from comments at the top of the source or use B<--version>). If you come across latex -files that are error-free and conform to the specifications set out -above, and whose differencing still does not result in error-free -latex, please send me those files, ideally edited to only contain the -offending passage as long as that still reproduces the problem. If your -file relies on non-standard class files, you must include those. I will not -look at examples where I have trouble to latex the original files. - -=head1 SEE ALSO - -L, L - -=head1 PORTABILITY - -I does not make use of external commands and thus should run -on any platform supporting Perl 5.6 or higher. If files with encodings -other than ASCII or UTF-8 are processed, Perl 5.8 or higher is required. - -The standard version of I requires installation of the Perl package -C (available from I - -I) but a stand-alone -version, I, which has this package inlined, is available, too. -I requires the I command to be present. - -=head1 AUTHOR - -Version 1.0.4 -Copyright (C) 2004-2012 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 - -Contributors of fixes and additions: V. Kuhlmann, J. Paisley, N. Becker, T. Doerges, K. Huebner, -T. Connors, Sebastian Gouezel and many others. -Thanks to the many people who sent in bug reports, feature suggestions, and other feedback. - -=cut - -__END__ -%%BEGIN SAFE COMMANDS -% Regex matching commands which can safely be in the -% argument of a \DIFadd or \DIFdel command (leave out the \) -arabic -dashbox -emph -fbox -framebox -hspace -math.* -makebox -mbox -pageref -ref -symbol -raisebox -rule -text.* -shortstack -usebox -dag -ddag -copyright -pounds -S -P -oe -OE -ae -AE -aa -AA -o -O -l -L -frac -ss -sqrt -ldots -cdots -vdots -ddots -alpha -beta -gamma -delta -epsilon -varepsilon -zeta -eta -theta -vartheta -iota -kappa -lambda -mu -nu -xi -pi -varpi -rho -varrho -sigma -varsigma -tau -upsilon -phi -varphi -chi -psi -omega -Gamma -Delta -Theta -Lambda -Xi -Pi -Sigma -Upsilon -Phi -Psi -Omega -ps -mp -times -div -ast -star -circ -bullet -cdot -cap -cup -uplus -sqcap -vee -wedge -setminus -wr -diamond -(?:big)?triangle.* -lhd -rhd -unlhd -unrhd -oplus -ominus -otimes -oslash -odot -bigcirc -d?dagger -amalg -leq -prec -preceq -ll -(?:sq)?su[bp]set(?:eq)? -in -vdash -geq -succ(?:eq)? -gg -ni -dashv -equiv -sim(?:eq)? -asymp -approx -cong -neq -doteq -propto -models -perp -mid -parallel -bowtie -Join -smile -frown -.*arrow -(?:long)?mapsto -.*harpoon.* -leadsto -aleph -hbar -imath -jmath -ell -wp -Re -Im -mho -prime -emptyset -nabla -surd -top -bot -angle -forall -exists -neg -flat -natural -sharp -backslash -partial -infty -Box -Diamond -triangle -clubsuit -diamondsuit -heartsuit -spadesuit -sum -prod -coprod -int -oint -big(?:sq)?c[au]p -bigvee -bigwedge -bigodot -bigotimes -bigoplus -biguplus -(?:arc)?(?:cos|sin|tan|cot)h? -csc -arg -deg -det -dim -exp -gcd -hom -inf -ker -lg -lim -liminf -limsup -ln -log -max -min -Pr -sec -sup -[Hclbdruvt] -(SUPER|SUB)SCRIPTNB -(SUPER|SUB)SCRIPT -PERCENTAGE -DOLLAR -%%END SAFE COMMANDS - -%%BEGIN TEXT COMMANDS -% Regex matching commands with a text argument (leave out the \) -addcontents.* -cc -closing -chapter -dashbox -emph -encl -fbox -framebox -footnote -footnotetext -framebox -part -(sub){0,2}section\*? -(sub)?paragraph\*? -makebox -mbox -opening -parbox -raisebox -savebox -sbox -shortstack -signature -text.* -value -underline -sqrt -(SUPER|SUB)SCRIPT -%%END TEXT COMMANDS - -%%BEGIN CONTEXT1 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -caption -%%END CONTEXT1 COMMANDS - -%%BEGIN CONTEXT2 COMMANDS -% Regex matching commands with a text argument (leave out the \), which will fail out of context, but whose argument should be printed as plain text -title -author -date -institute -%%END CONTEXT2 COMMANDS - - -%% TYPES (Commands for highlighting changed blocks) - -%DIF UNDERLINE PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}} -\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}} -%DIF END UNDERLINE PREAMBLE - -%DIF CTRADITIONAL PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} [..\footnote{removed: #1} ]}} -%DIF END CTRADITIONAL PREAMBLE - -%DIF TRADITIONAL PREAMBLE -\RequirePackage[stable]{footmisc} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{[..\footnote{removed: #1} ]}} -%DIF END TRADITIONAL PREAMBLE - -%DIF CFONT PREAMBLE -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{{\protect\color{blue} \sf #1}} -\providecommand{\DIFdel}[1]{{\protect\color{red} \scriptsize #1}} -%DIF END CFONT PREAMBLE - -%DIF FONTSTRIKE PREAMBLE -\RequirePackage[normalem]{ulem} -\providecommand{\DIFadd}[1]{{\sf #1}} -\providecommand{\DIFdel}[1]{{\footnotesize \sout{#1}}} -%DIF END FONTSTRIKE PREAMBLE - -%DIF CCHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}#1}\protect\cbdelete} -%DIF END CCHANGEBAR PREAMBLE - -%DIF CFONTCHBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\sf #1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\scriptsize #1}\protect\cbdelete} -%DIF END CFONTCHBAR PREAMBLE - -%DIF CULINECHBAR PREAMBLE -\RequirePackage[normalem]{ulem} -\RequirePackage[dvips]{changebar} -\RequirePackage{color} -\providecommand{\DIFadd}[1]{\protect\cbstart{\protect\color{blue}\uwave{#1}}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete{\protect\color{red}\sout{#1}}\protect\cbdelete} -%DIF END CULINECHBAR PREAMBLE - -%DIF CHANGEBAR PREAMBLE -\RequirePackage[dvips]{changebar} -\providecommand{\DIFadd}[1]{\protect\cbstart{#1}\protect\cbend} -\providecommand{\DIFdel}[1]{\protect\cbdelete} -%DIF END CHANGEBAR PREAMBLE - -%DIF INVISIBLE PREAMBLE -\providecommand{\DIFadd}[1]{#1} -\providecommand{\DIFdel}[1]{} -%DIF END INVISIBLE PREAMBLE - - -%% SUBTYPES (Markers for beginning and end of changed blocks) - -%DIF SAFE PREAMBLE -\providecommand{\DIFaddbegin}{} -\providecommand{\DIFaddend}{} -\providecommand{\DIFdelbegin}{} -\providecommand{\DIFdelend}{} -%DIF END SAFE PREAMBLE - -%DIF MARGIN PREAMBLE -\providecommand{\DIFaddbegin}{\protect\marginpar{a[}} -\providecommand{\DIFaddend}{\protect\marginpar{]}} -\providecommand{\DIFdelbegin}{\protect\marginpar{d[}} -\providecommand{\DIFdelend}{\protect\marginpar{]}} -%DIF END BRACKET PREAMBLE - -%DIF DVIPSCOL PREAMBLE -%Note: only works with dvips converter -\RequirePackage{color} -\RequirePackage{dvipscol} -\providecommand{\DIFaddbegin}{\protect\nogroupcolor{blue}} -\providecommand{\DIFaddend}{\protect\nogroupcolor{black}} -\providecommand{\DIFdelbegin}{\protect\nogroupcolor{red}} -\providecommand{\DIFdelend}{\protect\nogroupcolor{black}} -%DIF END DVIPSCOL PREAMBLE - -%DIF COLOR PREAMBLE -\RequirePackage{color} -\providecommand{\DIFaddbegin}{\protect\color{blue}} -\providecommand{\DIFaddend}{\protect\color{black}} -\providecommand{\DIFdelbegin}{\protect\color{red}} -\providecommand{\DIFdelend}{\protect\color{black}} -%DIF END COLOR PREAMBLE - -%DIF LABEL PREAMBLE -% To show only pages with changes (pdf) (external program pdftk needs to be installed) -% (only works for simple documents with non-repeated page numbers) -% pdflatex diff.tex -% pdflatex diff.tex -% pdftk diff.pdf cat `perl -lne 'if (m/\\newlabel{DIFchg[be]\d*}{{.*}{(.*)}}/) { print $1 }' diff.aux | uniq | tr -s \\n ' '` output diff-changedpages.pdf -% To show only pages with changes (dvips/dvipdf) -% latex diff.tex -% latex diff.tex -% dvips -pp `perl -lne 'if (m/\\newlabel{DIFchg[be]\d*}{{.*}{(.*)}}/) { print $1 }' diff.aux | uniq | tr -s \\n ','` diff.dvi -\typeout{Check comments in preamble of output for instructions how to show only pages where changes have been made} -\newcount\DIFcounterb -\global\DIFcounterb 0\relax -\newcount\DIFcountere -\global\DIFcountere 0\relax -\providecommand{\DIFaddbegin}{\global\advance\DIFcounterb 1\relax\label{DIFchgb\the\DIFcounterb}} %DIF PREAMBLE -\providecommand{\DIFaddend}{\global\advance\DIFcountere 1\relax\label{DIFchge\the\DIFcountere}} %DIF PREAMBLE -\providecommand{\DIFdelbegin}{\global\advance\DIFcounterb 1\relax\label{DIFchgb\the\DIFcounterb}} %DIF PREAMBLE -\providecommand{\DIFdelend}{\global\advance\DIFcountere 1\relax\label{DIFchge\the\DIFcountere}} %DIF PREAMBLE -%DIF END LABEL PREAMBLE -%% FLOAT TYPES - -%DIF FLOATSAFE PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END FLOATSAFE PREAMBLE - -%DIF IDENTICAL PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} -\providecommand{\DIFaddbeginFL}{\DIFaddbegin} -\providecommand{\DIFaddendFL}{\DIFaddend} -\providecommand{\DIFdelbeginFL}{\DIFdelbegin} -\providecommand{\DIFdelendFL}{\DIFdelend} -%DIF END IDENTICAL PREAMBLE - -%DIF TRADITIONALSAFE PREAMBLE -% procidecommand color to make this work for TRADITIONAL and CTRADITIONAL -\providecommand{\color}[1]{} -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} -\providecommand{\DIFdel}[1]{{\protect\color{red}[..{\scriptsize {removed: #1}} ]}} -\providecommand{\DIFaddbeginFL}{} -\providecommand{\DIFaddendFL}{} -\providecommand{\DIFdelbeginFL}{} -\providecommand{\DIFdelendFL}{} -%DIF END TRADITIONALSAFE PREAMBLE - -%% SPECIAL PACKAGE PREAMBLE COMMANDS - -% Standard \DIFadd and \DIFdel are redefined as \DIFaddtex and \DIFdeltex -% when hyperref package is included. -%DIF HYPERREF PREAMBLE -\providecommand{\DIFadd}[1]{\texorpdfstring{\DIFaddtex{#1}}{#1}} -\providecommand{\DIFdel}[1]{\texorpdfstring{\DIFdeltex{#1}}{}} -%DIF END HYPERREF PACKAGE diff --git a/latexdiff-1.0.4/latexdiff-vc b/latexdiff-1.0.4/latexdiff-vc deleted file mode 100755 index d38fc14..0000000 --- a/latexdiff-1.0.4/latexdiff-vc +++ /dev/null @@ -1,507 +0,0 @@ -#!/usr/bin/env perl -# -# latexdiff-vc - wrapper script for applying latexdiff to rcs managed files -# and for automatised creation of postscript or pdf from difference file -# -# Copyright (C) 2005-13 F J Tilmann (tilmann@gfz-potsdam.de) -# -# Repository: https://github.com/ftilmann/latexdiff -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# -# Contributors: S Utcke, H Bruyninckx -# -# 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 . -# -# Detailed usage information at the end of the file -# -# version 1.0.4alpha: -# - [ Patch #3486 contributed by cbarbu] add additional compilation for styles using chbar + avoid pdf/postscripts repeat in the code -# version 1.0.3: Bug fix: replace use of system('cp...') with File::Copy::copy (Patch contributed by D. Bremner) -# Quotes around system call file arguments to allow filenames with spaces (Patch contributed by ssteve) -# version 1.0.2: - option --so to use latexdiff-so -# version 1.0.1 (change version numbering to match that of latexdiff) -# - Option --fast to use latexdiff-fast, -# - git support (thanks to Bjorn Magnus Mathisen, Santi Béjar, Pietro Battiston and Stefan Alfredson for patches) - UNTESTED -# version 0.25: -# - bbl is allowed as alternative extension (instead of .tex) -# version 0.26a -# - Bug fix: it copes now correctly with the possibility that there are no changes between current -# and archived version -use Getopt::Long ; -use Pod::Usage qw/pod2usage/ ; -use File::Temp qw/tempdir/ ; -use File::Basename qw/dirname/; -use File::Copy; - -use strict ; -use warnings ; - -my $versionstring=< 1); -# Variables -my ($file1,$file2,$diff,$diffbase,$answer,$options,$infile,$append,$dirname,$cwd); -my (@files,@ldoptions,@tmpfiles,@ptmpfiles,@difffiles,$extracomp); # , - -Getopt::Long::Configure('pass_through','bundling'); - -GetOptions('revision|r:s' => \@revs, - 'cvs' => \$cvs, - 'rcs' => \$rcs, - 'svn' => \$svn, - 'git' => \$git, - 'dir|d:s' => \$dir, - 'fast' => \$fast, - 'so' => \$so, - 'postscript|ps' => \$postscript, - 'pdf' => \$pdf, - 'force' => \$force, - 'version' => \$version, - 'help|h' => \$help); - -$extracomp = join(" ",grep(/BAR/,@ARGV)); # special latexdiff options requiring additional compilation - -if ( $help ) { - pod2usage(1) ; -} - -if ( $version ) { - die $versionstring ; -} - -if ( $so ) { - $latexdiff='latexdiff-so'; -} -if ( $fast ) { - die "Cannot specify more than one of --fast or --so " if ($so); - $latexdiff='latexdiff-fast'; -} - -if ( $cvs ) { - $vc="CVS"; -} -if ( $rcs ) { - die "Cannot specify more than one of --cvs, --rcs --svn or --git." if ($vc); - $vc="RCS"; -} -if ( $svn ) { - die "Cannot specify more than one of --cvs, --rcs --svn or --git." if ($vc); - $vc="SVN"; -} -if ( $git ) { - die "Cannot specify more than one of --cvs, --rcs, --svn or --git." if ($vc); - $vc="GIT"; -} - - -# check whether the first file name or first passed-through option for latexdiff got misinterpreted as an option to an empty -r option -if ( @revs && ( -f $revs[$#revs] || $revs[$#revs] =~ /^-/ ) ) { - unshift @ARGV,$revs[$#revs]; - $revs[$#revs]=""; -} -# check whether the first file name or first passed-through option for latexdiff got misinterpreted as an option to an empty -d option -if ( defined($dir) && ( -f $dir || $dir =~ /^-/ ) ) { - unshift @ARGV,$dir; - $dir=""; -} - -#print "DEBUG: latexdiff-vc command line: ", join(" ",@ARGV), "\n"; - -$file2=pop @ARGV; -( defined($file2) && $file2 =~ /\.(tex|bbl)$/ ) or pod2usage("Must specify at least one tex or bbl file"); - -if (! $vc && scalar(@revs)>0 ) { - # have to guess $vc - # check whether we have a special name - if ( $0 =~ /-cvs$/ ) { - $vc="CVS"; - } elsif ( $0 =~ /-rcs$/ ) { - $vc="RCS"; - } elsif ( $0 =~ /-svn$/ ) { - $vc="SVN"; - } elsif ( $0 =~ /-git$/ ) { - $vc="GIT"; - } elsif ( -e "$file2,v" ) { - print STDERR "Guess you are using RCS ...\n"; - $vc="RCS"; - } elsif ( -d ".svn" ) { - print STDERR "Guess you are using SVN ...\n"; - $vc="SVN"; - } elsif ( -d ".git" ) { - print STDERR "Guess you are using GIT ...\n"; - $vc="GIT"; - } elsif ( -e "CVSROOT" || defined($ENV{"CVSROOT"}) ) { - print STDERR "Guess you are using CVS ...\n"; - $vc="CVS"; - } else { - print STDERR "Cannot figure out version control system, so I default to CVS\n"; - $vc="CVS"; - } -} - -if (defined($dir) && $dir=~/^\.\/?/ ) { - print STDERR "You wrote -dir=. but you do not really like to do that, do you ?\n"; - exit 10 -} - -if ( scalar(@revs)>0 ) { - if ( $vc eq "CVS" ) { - $diffcmd = "cvs diff -u -r"; - $patchcmd = "patch -R -p0"; - } elsif ( $vc eq "RCS" ) { - $diffcmd = "rcsdiff -u -r"; - $patchcmd = "patch -R -p0"; - } elsif ( $vc eq "SVN" ) { - $diffcmd = "svn diff -r "; - $patchcmd = "patch -R -p0"; - } elsif ( $vc eq "GIT" ) { - $diffcmd = "git diff -r --relative --no-prefix "; - $patchcmd = "patch -R -p0"; - # alternatively: - # $diffcmd = "git diff "; - # $patchcmd = "patch -R -p1"; - } else { - print STDERR "Unknown versioning system $vc \n"; - exit 10; - } -} - - -# make file list (last arguments), initial arguments have to be passed to latexdiff -# We assume an argument is a valid file rather than a latexdiff argument -# if it has extension .tex or .bbl - -@files=($file2); -while( $file1=pop @ARGV ) { - if ( $file1 =~ /\.(tex|bbl)$/ ) { - # $file1 looks like a valid file name and is prepended to file list - unshift @files, $file1 ; - } else { - # $file1 looks like an option for latexdiff, push it back to argument stack - unshift @ldoptions, $file1 ; - } -} - -if ( scalar(@revs) == 0 ) { - pod2usage("When -r option is not used, two .tex files (old and new) must be given on the command line") unless @files==2; - # compare two files - $file1=shift @files ; -} - -if ( scalar(@revs) == 2 ) { - $append = "-diff$revs[0]-$revs[1]"; -} elsif ( scalar(@revs) == 1 || $revs[0] ) { - $append = "-diff$revs[0]"; -} else { - $append = "-diff"; -} - -if ( defined ($dir) && ! $dir ) { - # bare -d option => choose directory name - ($dir=$append) =~ s/^-//; -} - -if ( ($vc eq "SVN" || $vc eq "CVS") && scalar(@revs)) { - length($revs[$#revs]) > 0 or $revs[$#revs]="HEAD"; - length($revs[0]) > 0 or $revs[0]="HEAD"; -} - -#exit ; - - -# cycle through all files - -@difffiles=(); -while ( $infile=$file2=shift @files ) { - print STDERR "Working on $infile \n"; - if ( scalar(@revs) == 1 ) { - ($file1=$infile) =~ s/\.(tex|bbl)/-oldtmp-$$.$1/ ; - push @tmpfiles,$file1; - # compare file with previous version ($revs[0]="") or specified version - ### system("$diffcmd$revs[0] $infile| $patchcmd -o$file1") ; - if (system("$diffcmd$revs[0] \"$infile\" | $patchcmd -o\"$file1\"")==0 and -z $file1 ) { - # no differences detected, i.e. file is equal to current version - copy($infile,$file1) || die "copy($infile,$file1) failed: $!"; - } - } elsif ( scalar(@revs) == 2 ) { - ($file1=$infile) =~ s/\.(tex|bbl)/-oldtmp-$$.$1/ ; - $file2 =~ s/\.(tex|bbl)/-newtmp-$$.$1/ ; - push @tmpfiles,$file2; - if (system("$diffcmd$revs[1] $infile | $patchcmd -o$file2")==0 and -z $file2 ) { - copy($infile,$file2) || die "copy($infile,$file2) failed: $!"; - } - if (system("$diffcmd$revs[0] $infile | $patchcmd -o$file1")==0 and -z $file1 ) { - copy($infile,$file1) || die "copy($infile,$file1) failed: $!"; - }; - } - - if ( -z $file1 || -z $file2) { - print STDERR "One or both of the files to compare are empty. Possibly something went wrong in the retrieval of older versions. Aborting ...\n" ; - exit(10); - } - - # Get name of difference file - if ( defined($dir) ) { - $diff="$dir/$infile" ; - } else { - ($diff=$infile) =~ s/\.(tex|bbl)$/$append.$1/ ; - } - # make directories if needed - $dirname=dirname($diff) ; - system("mkdir -p $dirname") unless ( -e $dirname ); - - # Remaining options are passed to latexdiff - $options = join(" ",@ldoptions); - - if ( -e $diff && ! $force ) { - print STDERR "OK to overwrite existing file $diff (y/n)? "; - $answer = ; - unless ($answer =~ /^y/i ) { - unlink @tmpfiles; - die "Abort ... " ; - } - } - print "Running $latexdiff\n"; - unless ( system("$latexdiff $options \"$file1\" \"$file2\" > \"$diff\"") == 0 ) { - print STDERR "Something went wrong in $latexdiff. Deleting $diff and abort\n" ; unlink $diff ; exit(5) - }; - print "Generated difference file $diff\n"; - - if ( ( $postscript or $pdf ) and !( scalar(@revs) && greptex( qr/\\document(?:class|style)/ , $diff ) ) ) { - # save filename for later processing if postscript or pdf conversion is requested and either two-file mode was used (scalar(@revs)==0) or the diff file contains documentclass statement (ie. is a root document) - push @difffiles, $diff ; - } - - unlink @tmpfiles; -} - -foreach $diff ( @difffiles ) { - chomp($cwd=(`pwd`)); - if (defined($dir)) { - ( $diff =~ s/$dir\/?// ) ; - chdir $dir ; - } - @ptmpfiles=(); - ( $diffbase=$diff) =~ s/\.(tex)$// ; - - # adapt magically changebar styles to [pdftex] display driver if pdf output was selected - if ( $pdf ) { - system("sed \"s/Package\\[dvips\\]/Package[pdftex]/\" \"$diff\" > \"$diff.tmp$$\" ; \\mv \"$diff.tmp$$\" \"$diff\""); - $latexcmd = "pdflatex"; - } elsif ( $postscript ) { - $latexcmd = "latex"; - } - - if ( $pdf | $postscript ) { - print STDERR "PDF: $pdf Postscript: $postscript cwd $cwd\n"; - - if ( system("grep -q \'^[^%]*\\\\bibliography\' \"$diff\"") == 0 ) { - system("$latexcmd --interaction=batchmode \"$diff\"; bibtex \"$diffbase\";"); - push @ptmpfiles, "$diffbase.bbl","$diffbase.bbl" ; - } - - # if special needs, as CHANGEBAR - if ( $extracomp ) { - # print "Extracomp\n"; - system("$latexcmd --interaction=batchmode \"$diff\";"); - } - - # final compilation - system("$latexcmd --interaction=batchmode \"$diff\";"); # needed if cross-refs - system("$latexcmd \"$diff\";"); # final, with possible error messages - - if ( $postscript ) { - my $dvi="$diffbase.dvi"; - my $ps="$diffbase.ps"; - - system("dvips -o $ps $dvi"); - push @ptmpfiles, "$diffbase.aux","$diffbase.log",$dvi ; - print "Generated postscript file $ps\n"; - } - elsif ( $pdf ) { - push @ptmpfiles, "$diffbase.aux","$diffbase.log"; - } - } - unlink @ptmpfiles; - chdir $cwd; -} - -# greptex returns 1 if regex is not matched in filename -# 0 if there is a match -sub greptex { - my ($regex,$filename)=@_; - my ($i)=0; - open (FH, $filename) or die("Couldn't open $filename: $!"); - while () { - next if /^\s*%/; # skip comment lines - if ( m/$regex/ ) { - close(FH); - return(0); - } - # only scan 25 lines - $i++; - last if $i>25 ; - } - close(FH); - return(1); -} - - -=head1 NAME - -latexdiff-vc - wrapper script that calls latexdiff for different versions of a file under version management (CVS, RCS or SVN) - -=head1 SYNOPSIS - -B [ F ] [ F ] B<-r> [F] [B<-r> F] F [ F ...] - - or - -B [ F ] [ F ][ B<--postscript> | B<--pdf> ] F F - -=head1 DESCRIPTION - -I is a wrapper script that applies I to a -file, or multiple files under version control (CVS, RCS or SVN), and optionally runs the -sequence of C and C or C commands necessary to -produce pdf or postscript output of the difference tex file(s). It can -also be applied to a pair of files to automatise the generation of difference -file in postscript or pdf format. - -=head1 OPTIONS - -=over 4 - -=item B<--rcs>, B<--svn>, B<--cvs>, or B<--git> - -Set the version system. -If no version system is specified, latexdiff-vc will venture a guess. - -latexdiff-cvs and latexdiff-rcs are variants of latexdiff-vc which default to -the respective versioning system. However, this default can still be overridden using the options above. - -=item B<-r>, B<-r> F or B<--revision>, B<--revision=>F - -Choose revision (under RCS, CVS, SVN or GIT). One or two B<-r> options can be -specified, and they result in different behaviour: - -=over 4 - -=item B -r F ... - -compares F with the most recent version checked into RCS. - -=item B -r F F ... - -compares F with revision F. - -=item B -r F -r F F ... - -compares revisions F and F of F. - -Multiple files can be specified for all of the above options. All files must have the -extension C<.tex>, though. - -=item B F F - -compares two files. - -=back - -The name of the difference file is generated automatically and -reported to stdout. - -=item B<-d> or B<--dir> B<-d> F or B<--dir=>F - -Rather than appending the string C and optionally the version -numbers given to the output-file, this will prepend a directory name C -to the -original filename, creating the directory and subdirectories should they not exist already. This is particularly useful in order to clone a -complete directory hierarchy. Optionally, a pathname F can be specified, which is prepended instead of C. - -=item B<--fast> or B<--so> - -Use C or C, respectively (instead of C). - -=item B<--ps> or B<--postscript> - -Generate postscript output from difference file. This will run the -sequence C on the difference file (do not use -this option in the rare cases, where three C commands are -required if you care about correct referencing). If the difference -file contains a C<\bibliography> tag, run the sequence C. - -=item B<--pdf> - -Generate pdf output from difference file using C. This will -run the sequence C on the difference file, or -C for files requiring bibtex. - -=item B<--force> - -Overwrite existing diff files without asking for confirmation. Default -behaviour is to ask for confirmation before overwriting an existing difference -file. - -=item B<--help> or -B<-h> - -Show help text - -=item B<--version> - -Show version number - -=back - -All other options are passed on to C. - -=head1 SEE ALSO - -L - -=head1 PORTABILITY - -I uses external commands and is therefore -limited to Unix-like systems. It also requires the RCS version control -system and latex to be installed on the system. Modules from Perl 5.8 -or higher are required. - -=head1 BUG REPORTING - -Please submit bug reports using the issue tracker of the github repository page I, -or send them to I. Include the serial number of I -(option C<--version>) -. -=head1 AUTHOR - -Copyright (C) 2005,2012 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 -Contributors: S Utcke, H Bruyninckx - -=cut - diff --git a/latexdiff-1.0.4/latexdiff-vc.1 b/latexdiff-1.0.4/latexdiff-vc.1 deleted file mode 100644 index 87341f1..0000000 --- a/latexdiff-1.0.4/latexdiff-vc.1 +++ /dev/null @@ -1,252 +0,0 @@ -.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` "" -. ds C' "" -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -. ds C` -. ds C' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.\" -.\" Avoid warning from groff about undefined register 'F'. -.de IX -.. -.nr rF 0 -.if \n(.g .if rF .nr rF 1 -.if (\n(rF:(\n(.g==0)) \{ -. if \nF \{ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. if !\nF==2 \{ -. nr % 0 -. nr F 2 -. \} -. \} -.\} -.rr rF -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "LATEXDIFF-VC 1" -.TH LATEXDIFF-VC 1 "2014-07-20" "perl v5.18.2" " " -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -latexdiff\-vc \- wrapper script that calls latexdiff for different versions of a file under version management (CVS, RCS or SVN) -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBlatexdiff-vc\fR [ \fIlatexdiff-options\fR ] [ \fIlatexdiff-vc-options\fR ] \fB\-r\fR [\fIrev1\fR] [\fB\-r\fR \fIrev2\fR] \fIfile1.tex\fR [ \fIfile2.tex\fR ...] -.PP -.Vb 1 -\& or -.Ve -.PP -\&\fBlatexdiff-vc\fR [ \fIlatexdiff-options\fR ] [ \fIlatexdiff-vc-options\fR ][ \fB\-\-postscript\fR | \fB\-\-pdf\fR ] \fIold.tex\fR \fInew.tex\fR -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -\&\fIlatexdiff-vc\fR is a wrapper script that applies \fIlatexdiff\fR to a -file, or multiple files under version control (\s-1CVS, RCS\s0 or \s-1SVN\s0), and optionally runs the -sequence of \f(CW\*(C`latex\*(C'\fR and \f(CW\*(C`dvips\*(C'\fR or \f(CW\*(C`pdflatex\*(C'\fR commands necessary to -produce pdf or postscript output of the difference tex file(s). It can -also be applied to a pair of files to automatise the generation of difference -file in postscript or pdf format. -.SH "OPTIONS" -.IX Header "OPTIONS" -.IP "\fB\-\-rcs\fR, \fB\-\-svn\fR, \fB\-\-cvs\fR, or \fB\-\-git\fR" 4 -.IX Item "--rcs, --svn, --cvs, or --git" -Set the version system. -If no version system is specified, latexdiff-vc will venture a guess. -.Sp -latexdiff-cvs and latexdiff-rcs are variants of latexdiff-vc which default to -the respective versioning system. However, this default can still be overridden using the options above. -.IP "\fB\-r\fR, \fB\-r\fR \fIrev\fR or \fB\-\-revision\fR, \fB\-\-revision=\fR\fIrev\fR" 4 -.IX Item "-r, -r rev or --revision, --revision=rev" -Choose revision (under \s-1RCS, CVS, SVN\s0 or \s-1GIT\s0). One or two \fB\-r\fR options can be -specified, and they result in different behaviour: -.RS 4 -.IP "\fBlatexdiff-vc\fR \-r \fIfile.tex\fR ..." 4 -.IX Item "latexdiff-vc -r file.tex ..." -compares \fIfile.tex\fR with the most recent version checked into \s-1RCS.\s0 -.IP "\fBlatexdiff-vc\fR \-r \fIrev1\fR \fIfile.tex\fR ..." 4 -.IX Item "latexdiff-vc -r rev1 file.tex ..." -compares \fIfile.tex\fR with revision \fIrev1\fR. -.IP "\fBlatexdiff-vc\fR \-r \fIrev1\fR \-r \fIrev2\fR \fIfile.tex\fR ..." 4 -.IX Item "latexdiff-vc -r rev1 -r rev2 file.tex ..." -compares revisions \fIrev1\fR and \fIrev2\fR of \fIfile.tex\fR. -.Sp -Multiple files can be specified for all of the above options. All files must have the -extension \f(CW\*(C`.tex\*(C'\fR, though. -.IP "\fBlatexdiff-vc\fR \fIold.tex\fR \fInew.tex\fR" 4 -.IX Item "latexdiff-vc old.tex new.tex" -compares two files. -.RE -.RS 4 -.Sp -The name of the difference file is generated automatically and -reported to stdout. -.RE -.IP "\fB\-d\fR or \fB\-\-dir\fR \fB\-d\fR \fIpath\fR or \fB\-\-dir=\fR\fIpath\fR" 4 -.IX Item "-d or --dir -d path or --dir=path" -Rather than appending the string \f(CW\*(C`diff\*(C'\fR and optionally the version -numbers given to the output-file, this will prepend a directory name \f(CW\*(C`diff\*(C'\fR -to the -original filename, creating the directory and subdirectories should they not exist already. This is particularly useful in order to clone a -complete directory hierarchy. Optionally, a pathname \fIpath\fR can be specified, which is prepended instead of \f(CW\*(C`diff\*(C'\fR. -.IP "\fB\-\-fast\fR or \fB\-\-so\fR" 4 -.IX Item "--fast or --so" -Use \f(CW\*(C`latexdiff\-fast\*(C'\fR or \f(CW\*(C`latexdiff\-so\*(C'\fR, respectively (instead of \f(CW\*(C`latexdiff\*(C'\fR). -.IP "\fB\-\-ps\fR or \fB\-\-postscript\fR" 4 -.IX Item "--ps or --postscript" -Generate postscript output from difference file. This will run the -sequence \f(CW\*(C`latex; latex; dvips\*(C'\fR on the difference file (do not use -this option in the rare cases, where three \f(CW\*(C`latex\*(C'\fR commands are -required if you care about correct referencing). If the difference -file contains a \f(CW\*(C`\ebibliography\*(C'\fR tag, run the sequence \f(CW\*(C`latex; -bibtex; latex; latex; dvips\*(C'\fR. -.IP "\fB\-\-pdf\fR" 4 -.IX Item "--pdf" -Generate pdf output from difference file using \f(CW\*(C`pdflatex\*(C'\fR. This will -run the sequence \f(CW\*(C`pdflatex; pdflatex\*(C'\fR on the difference file, or -\&\f(CW\*(C`pdflatex; bibtex; pdflatex; pdflatex\*(C'\fR for files requiring bibtex. -.IP "\fB\-\-force\fR" 4 -.IX Item "--force" -Overwrite existing diff files without asking for confirmation. Default -behaviour is to ask for confirmation before overwriting an existing difference -file. -.IP "\fB\-\-help\fR or \fB\-h\fR" 4 -.IX Item "--help or -h" -Show help text -.IP "\fB\-\-version\fR" 4 -.IX Item "--version" -Show version number -.PP -All other options are passed on to \f(CW\*(C`latexdiff\*(C'\fR. -.SH "SEE ALSO" -.IX Header "SEE ALSO" -latexdiff -.SH "PORTABILITY" -.IX Header "PORTABILITY" -\&\fIlatexdiff-vc\fR uses external commands and is therefore -limited to Unix-like systems. It also requires the \s-1RCS\s0 version control -system and latex to be installed on the system. Modules from Perl 5.8 -or higher are required. -.SH "BUG REPORTING" -.IX Header "BUG REPORTING" -Please submit bug reports using the issue tracker of the github repository page \fIhttps://github.com/ftilmann/latexdiff.git\fR, -or send them to \fItilmann@gfz\-potsdam.de\fR. Include the serial number of \fIlatexdiff-vc\fR -(option \f(CW\*(C`\-\-version\*(C'\fR) -\&. -=head1 \s-1AUTHOR\s0 -.PP -Copyright (C) 2005,2012 Frederik Tilmann -.PP -This program is free software; you can redistribute it and/or modify -it under the terms of the \s-1GNU\s0 General Public License Version 3 -Contributors: S Utcke, H Bruyninckx diff --git a/latexdiff-1.0.4/latexdiff.1 b/latexdiff-1.0.4/latexdiff.1 deleted file mode 100644 index cc7c69a..0000000 --- a/latexdiff-1.0.4/latexdiff.1 +++ /dev/null @@ -1,751 +0,0 @@ -.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` "" -. ds C' "" -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -. ds C` -. ds C' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.\" -.\" Avoid warning from groff about undefined register 'F'. -.de IX -.. -.nr rF 0 -.if \n(.g .if rF .nr rF 1 -.if (\n(rF:(\n(.g==0)) \{ -. if \nF \{ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. if !\nF==2 \{ -. nr % 0 -. nr F 2 -. \} -. \} -.\} -.rr rF -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "LATEXDIFF 1" -.TH LATEXDIFF 1 "2014-07-21" "perl v5.18.2" " " -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -latexdiff \- determine and markup differences between two latex files -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBlatexdiff\fR [ \fB\s-1OPTIONS\s0\fR ] \fIold.tex\fR \fInew.tex\fR > \fIdiff.tex\fR -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -Briefly, \fIlatexdiff\fR is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called \f(CW\*(C`old.tex\*(C'\fR and \f(CW\*(C`new.tex\*(C'\fR, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. -.PP -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "\f(CW\*(C`%DIF\ >\*(C'\fR" is appended to each added line, i.e. a -line present in \f(CW\*(C`new.tex\*(C'\fR but not in \f(CW\*(C`old.tex\*(C'\fR. Discarded lines - are deactivated by prepending "\f(CW\*(C`%DIF\ <\*(C'\fR". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file \f(CW\*(C`diff.tex\*(C'\fR will be similar to -\&\f(CW\*(C`new.tex\*(C'\fR. At the end of the preamble, the definitions for \fIlatexdiff\fR markup commands are inserted. -In differencing the main body of the text, \fIlatexdiff\fR attempts to -satisfy the following guidelines (in order of priority): -.IP "1." 3 -If both \f(CW\*(C`old.tex\*(C'\fR and \f(CW\*(C`new.tex\*(C'\fR are valid LaTeX, then the resulting -\&\f(CW\*(C`diff.tex\*(C'\fR should also be valid LateX. (\s-1NB\s0 If a few plain TeX commands -are used within \f(CW\*(C`old.tex\*(C'\fR or \f(CW\*(C`new.tex\*(C'\fR then \f(CW\*(C`diff.tex\*(C'\fR is not -guaranteed to work but usually will). -.IP "2." 3 -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -\&\f(CW\*(C`diff.tex\*(C'\fR. -.IP "3." 3 -If a changed passage contains text or text-producing commands, then -running \f(CW\*(C`diff.tex\*(C'\fR through LateX should produce output where added -and discarded passages are highlighted. -.IP "4." 3 -Where there are insignificant differences, e.g. in the positioning of -line breaks, \f(CW\*(C`diff.tex\*(C'\fR should follow the formatting of \f(CW\*(C`new.tex\*(C'\fR -.PP -For differencing the same algorithm as \fIdiff\fR is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, \f(CW\*(C`\ecaption\*(C'\fR and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write -.PP -.Vb 1 -\& \esection{\etextem{This is an emphasized section title}} -.Ve -.PP -and not -.PP -.Vb 1 -\& \esection {\etextem{This is an emphasized section title}} -.Ve -.PP -or -.PP -.Vb 1 -\& \esection\etextem{This is an emphasized section title} -.Ve -.PP -even though all varieties are the same to LaTeX (but see -\&\fB\-\-allow\-spaces\fR option which allows the second variety). -.PP -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the \s-1PICTUREENV\s0 configuration variable, set by -default to \f(CW\*(C`picture\*(C'\fR and \f(CW\*(C`DIFnomarkup\*(C'\fR environments; see \fB\-\-config\fR -option). The latter environment (\f(CW\*(C`DIFnomarkup\*(C'\fR) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by \f(CW\*(C`\ebegin{DIFnomarkup}\*(C'\fR and \f(CW\*(C`\eend{DIFnomarkup}\*(C'\fR. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, -.PP -\&\f(CW\*(C`\enewenvironment{DIFnomarkup}{}{}\*(C'\fR -.PP -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. -.PP -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. -.PP -All markup commands inserted by \fIlatexdiff\fR begin with "\f(CW\*(C`\eDIF\*(C'\fR". Added -blocks containing words, commands or comments which are in \f(CW\*(C`new.tex\*(C'\fR -but not in \f(CW\*(C`old.tex\*(C'\fR are marked by \f(CW\*(C`\eDIFaddbegin\*(C'\fR and \f(CW\*(C`\eDIFaddend\*(C'\fR. -Discarded blocks are marked by \f(CW\*(C`\eDIFdelbegin\*(C'\fR and \f(CW\*(C`\eDIFdelend\*(C'\fR. -Within added blocks all text is highlighted with \f(CW\*(C`\eDIFadd\*(C'\fR like this: -\&\f(CW\*(C`\eDIFadd{Added text block}\*(C'\fR -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces \*(L"{\*(R" and \*(L"}\*(R" are never put within -the scope of \f(CW\*(C`\eDIFadd\*(C'\fR. Added comments are marked by prepending -"\f(CW\*(C`%DIF\ >\ \*(C'\fR". -.PP -Within deleted blocks text is highlighted with \f(CW\*(C`\eDIFdel\*(C'\fR. Deleted -comments are marked by prepending "\f(CW\*(C`%DIF\ <\ \*(C'\fR\*(L". Non-safe command -and curly braces within deleted blocks are commented out with -\&\*(R"\f(CW\*(C`%DIFDELCMD\ <\ \*(C'\fR". -.SH "OPTIONS" -.IX Header "OPTIONS" -.SS "Preamble" -.IX Subsection "Preamble" -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. -.IP "\fB\-\-type=markupstyle\fR or \fB\-t markupstyle\fR" 4 -.IX Item "--type=markupstyle or -t markupstyle" -Add code to preamble for selected markup style. This option defines -\&\f(CW\*(C`\eDIFadd\*(C'\fR and \f(CW\*(C`\eDIFdel\*(C'\fR commands. -Available styles: -.Sp -\&\f(CW\*(C`UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE -CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR\*(C'\fR -.Sp -[ Default: \f(CW\*(C`UNDERLINE\*(C'\fR ] -.IP "\fB\-\-subtype=markstyle\fR or \fB\-s markstyle\fR" 4 -.IX Item "--subtype=markstyle or -s markstyle" -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -\&\f(CW\*(C`\eDIFaddbegin\*(C'\fR, \f(CW\*(C`\eDIFaddend\*(C'\fR, \f(CW\*(C`\eDIFdelbegin\*(C'\fR and \f(CW\*(C`\eDIFdelend\*(C'\fR commands. -Available styles: \f(CW\*(C`SAFE MARGINAL COLOR DVIPSCOL LABEL\*(C'\fR -.Sp -[ Default: \f(CW\*(C`SAFE\*(C'\fR ] -.IP "\fB\-\-floattype=markstyle\fR or \fB\-f markstyle\fR" 4 -.IX Item "--floattype=markstyle or -f markstyle" -Add code to preamble for selected style which -replace standard marking and markup commands within floats -(e.g., marginal remarks cause an error within floats -so marginal marking can be disabled thus). This option defines all -\&\f(CW\*(C`\eDIF...FL\*(C'\fR commands. -Available styles: \f(CW\*(C`FLOATSAFE TRADITIONALSAFE IDENTICAL\*(C'\fR -.Sp -[ Default: \f(CW\*(C`FLOATSAFE\*(C'\fR ] -.IP "\fB\-\-encoding=enc\fR or \fB\-e enc\fR" 4 -.IX Item "--encoding=enc or -e enc" -Specify encoding of old.tex and new.tex. Typical encodings are -\&\f(CW\*(C`ascii\*(C'\fR, \f(CW\*(C`utf8\*(C'\fR, \f(CW\*(C`latin1\*(C'\fR, \f(CW\*(C`latin9\*(C'\fR. A list of available encodings can be -obtained by executing -.Sp -\&\f(CW\*(C`perl \-MEncode \-e \*(Aqprint join ("\en",Encode\-\*(C'\fRencodings( \*(L":all\*(R" )) ;' > -.Sp -[Default encoding is utf8 unless the first few lines of the preamble contain -an invocation \f(CW\*(C`\eusepackage[..]{inputenc}\*(C'\fR in which case the -encoding chosen by this command is asssumed. Note that \s-1ASCII \s0(standard -latex) is a subset of utf8] -.IP "\fB\-\-preamble=file\fR or \fB\-p file\fR" 4 -.IX Item "--preamble=file or -p file" -Insert file at end of preamble instead of generating -preamble. The preamble must define the following commands -\&\f(CW\*(C`\eDIFaddbegin, \eDIFaddend, \eDIFadd{..}, -\&\eDIFdelbegin,\eDIFdelend,\eDIFdel{..},\*(C'\fR -and varieties for use within floats -\&\f(CW\*(C`\eDIFaddbeginFL, \eDIFaddendFL, \eDIFaddFL{..}, -\&\eDIFdelbeginFL, \eDIFdelendFL, \eDIFdelFL{..}\*(C'\fR -(If this option is set \fB\-t\fR, \fB\-s\fR, and \fB\-f\fR options -are ignored.) -.IP "\fB\-\-packages=pkg1,pkg2,..\fR" 4 -.IX Item "--packages=pkg1,pkg2,.." -Tell latexdiff that .tex file is processed with the packages in list -loaded. This is normally not necessary if the .tex file includes the -preamble, as the preamble is automatically scanned for \f(CW\*(C`\eusepackage\*(C'\fR commands. -Use of the \fB\-\-packages\fR option disables automatic scanning, so if for any -reason package specific parsing needs to be switched off, use \fB\-\-packages=none\fR. -The following packages trigger special behaviour: -.RS 4 -.ie n .IP """amsmath""" 8 -.el .IP "\f(CWamsmath\fR" 8 -.IX Item "amsmath" -Configuration variable amsmath is set to \f(CW\*(C`align*\*(C'\fR (Default: \f(CW\*(C`eqnarray*\*(C'\fR) -.ie n .IP """endfloat""" 8 -.el .IP "\f(CWendfloat\fR" 8 -.IX Item "endfloat" -Ensure that \f(CW\*(C`\ebegin{figure}\*(C'\fR and \f(CW\*(C`\eend{figure}\*(C'\fR always appear by themselves on a line. -.ie n .IP """hyperref""" 8 -.el .IP "\f(CWhyperref\fR" 8 -.IX Item "hyperref" -Change name of \f(CW\*(C`\eDIFadd\*(C'\fR and \f(CW\*(C`\eDIFdel\*(C'\fR commands to \f(CW\*(C`\eDIFaddtex\*(C'\fR and \f(CW\*(C`\eDIFdeltex\*(C'\fR and -define new \f(CW\*(C`\eDIFadd\*(C'\fR and \f(CW\*(C`\eDIFdel\*(C'\fR commands, which provide a wrapper for these commands, -using them for the text but not for the link defining command (where any markup would cause -errors). -.ie n .IP """apacite""" 8 -.el .IP "\f(CWapacite\fR" 8 -.IX Item "apacite" -Redefine the commands recognised as citation commands. -.RE -.RS 4 -.Sp -[ Default: scan the preamble for \f(CW\*(C`\e\eusepackage\*(C'\fR commands to determine - loaded packages.] -.RE -.IP "\fB\-\-show\-preamble\fR" 4 -.IX Item "--show-preamble" -Print generated or included preamble commands to stdout. -.SS "Configuration" -.IX Subsection "Configuration" -.ie n .IP "\fB\-\-exclude\-safecmd=exclude\-file\fR or \fB\-A exclude-file\fR or \fB\-\-exclude\-safecmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-exclude\-safecmd=exclude\-file\fR or \fB\-A exclude-file\fR or \fB\-\-exclude\-safecmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--exclude-safecmd=exclude-file or -A exclude-file or --exclude-safecmd=cmd1,cmd2,..." -.PD 0 -.IP "\fB\-\-replace\-safecmd=replace\-file\fR" 4 -.IX Item "--replace-safecmd=replace-file" -.ie n .IP "\fB\-\-append\-safecmd=append\-file\fR or \fB\-a append-file\fR or \fB\-\-append\-safecmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-append\-safecmd=append\-file\fR or \fB\-a append-file\fR or \fB\-\-append\-safecmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--append-safecmd=append-file or -a append-file or --append-safecmd=cmd1,cmd2,..." -.PD -Exclude from, replace or append to the list of regular expressions (RegEx) -matching commands which are safe to use within the -scope of a \f(CW\*(C`\eDIFadd\*(C'\fR or \f(CW\*(C`\eDIFdel\*(C'\fR command. The file must contain -one Perl-RegEx per line (Comment lines beginning with # or % are -ignored). Note that the RegEx needs to match the whole of -the token, i.e., /^regex$/ is implied and that the initial -\&\*(L"\e\*(R" of the command is not included. -The \fB\-\-exclude\-safecmd\fR and \fB\-\-append\-safecmd\fR options can be combined with the \-\fB\-\-replace\-safecmd\fR -option and can be used repeatedly to add cumulatively to the lists. - \fB\-\-exclude\-safecmd\fR -and \fB\-\-append\-safecmd\fR can also take a comma separated list as input. If a -comma for one of the regex is required, escape it thus \*(L"\e,\*(R". In most cases it -will be necessary to protect the comma-separated list from the shell by putting -it in quotation marks. -.ie n .IP "\fB\-\-exclude\-textcmd=exclude\-file\fR or \fB\-X exclude-file\fR or \fB\-\-exclude\-textcmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-exclude\-textcmd=exclude\-file\fR or \fB\-X exclude-file\fR or \fB\-\-exclude\-textcmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--exclude-textcmd=exclude-file or -X exclude-file or --exclude-textcmd=cmd1,cmd2,..." -.PD 0 -.IP "\fB\-\-replace\-textcmd=replace\-file\fR" 4 -.IX Item "--replace-textcmd=replace-file" -.ie n .IP "\fB\-\-append\-textcmd=append\-file\fR or \fB\-x append-file\fR or \fB\-\-append\-textcmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-append\-textcmd=append\-file\fR or \fB\-x append-file\fR or \fB\-\-append\-textcmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--append-textcmd=append-file or -x append-file or --append-textcmd=cmd1,cmd2,..." -.PD -Exclude from, replace or append to the list of regular expressions -matching commands whose last argument is text. See -entry for \fB\-\-exclude\-safecmd\fR directly above for further details. -.IP "\fB\-\-replace\-context1cmd=replace\-file\fR" 4 -.IX Item "--replace-context1cmd=replace-file" -.PD 0 -.ie n .IP "\fB\-\-append\-context1cmd=append\-file\fR or =item \fB\-\-append\-context1cmd=""cmd1,cmd2,...""\fR" 4 -.el .IP "\fB\-\-append\-context1cmd=append\-file\fR or =item \fB\-\-append\-context1cmd=``cmd1,cmd2,...''\fR" 4 -.IX Item "--append-context1cmd=append-file or =item --append-context1cmd=cmd1,cmd2,..." -.PD -Replace or append to the list of regex matching commands -whose last argument is text but which require a particular -context to work, e.g. \ecaption will only work within a figure -or table. These commands behave like text commands, except when -they occur in a deleted section, when they are disabled, but their -argument is shown as deleted text. -.IP "\fB\-\-replace\-context2cmd=replace\-file\fR" 4 -.IX Item "--replace-context2cmd=replace-file" -.PD 0 -.ie n .IP "\fB\-\-append\-context2cmd=append\-file\fR or =item \fB\-\-append\-context2cmd=""cmd1,cmd2,...""\fR As corresponding commands for context1. The only difference is that context2 commands are completely disabled in deleted sections, including their arguments." 4 -.el .IP "\fB\-\-append\-context2cmd=append\-file\fR or =item \fB\-\-append\-context2cmd=``cmd1,cmd2,...''\fR As corresponding commands for context1. The only difference is that context2 commands are completely disabled in deleted sections, including their arguments." 4 -.IX Item "--append-context2cmd=append-file or =item --append-context2cmd=cmd1,cmd2,... As corresponding commands for context1. The only difference is that context2 commands are completely disabled in deleted sections, including their arguments." -.IP "\fB\-\-config var1=val1,var2=val2,...\fR or \fB\-c var1=val1,..\fR" 4 -.IX Item "--config var1=val1,var2=val2,... or -c var1=val1,.." -.IP "\fB\-c configfile\fR" 4 -.IX Item "-c configfile" -.PD -Set configuration variables. The option can be repeated to set different -variables (as an alternative to the comma-separated list). -Available variables (see below for further explanations): -.Sp -\&\f(CW\*(C`MINWORDSBLOCK\*(C'\fR (integer) -.Sp -\&\f(CW\*(C`FLOATENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`PICTUREENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`MATHENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`MATHREPL\*(C'\fR (String) -.Sp -\&\f(CW\*(C`MATHARRENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`MATHARRREPL\*(C'\fR (String) -.Sp -\&\f(CW\*(C`ARRENV\*(C'\fR (RegEx) -.Sp -\&\f(CW\*(C`COUNTERCMD\*(C'\fR (RegEx) -.IP "\fB\-\-show\-safecmd\fR" 4 -.IX Item "--show-safecmd" -Print list of RegEx matching and excluding safe commands. -.IP "\fB\-\-show\-textcmd\fR" 4 -.IX Item "--show-textcmd" -Print list of RegEx matching and excluding commands with text argument. -.IP "\fB\-\-show\-config\fR" 4 -.IX Item "--show-config" -Show values of configuration variables. -.IP "\fB\-\-show\-all\fR" 4 -.IX Item "--show-all" -Combine all \-\-show commands. -.Sp -\&\s-1NB\s0 For all \-\-show commands, no \f(CW\*(C`old.tex\*(C'\fR or \f(CW\*(C`new.tex\*(C'\fR file needs to be specified, and no -differencing takes place. -.SS "Other configuration options:" -.IX Subsection "Other configuration options:" -.IP "\fB\-\-allow\-spaces\fR" 4 -.IX Item "--allow-spaces" -Allow spaces between bracketed or braced arguments to commands. Note -that this option might have undesirable side effects (unrelated scope -might get lumpeded with preceding commands) so should only be used if the -default produces erroneous results. (Default requires arguments to -directly follow each other without intervening spaces). -.IP "\fB\-\-math\-markup=level\fR" 4 -.IX Item "--math-markup=level" -Determine granularity of markup in displayed math environments: -Possible values for level are (both numerical and text labels are acceptable): -.Sp -\&\f(CW\*(C`off\*(C'\fR or \f(CW0\fR: suppress markup for math environments. Deleted equations will not -appear in diff file. This mode can be used if all the other modes -cause invalid latex code. -.Sp -\&\f(CW\*(C`whole\*(C'\fR or \f(CW1\fR: Differencing on the level of whole equations. Even trivial changes -to equations cause the whole equation to be marked changed. This -mode can be used if processing in coarse or fine mode results in -invalid latex code. -.Sp -\&\f(CW\*(C`coarse\*(C'\fR or \f(CW2\fR: Detect changes within equations marked up with a coarse -granularity; changes in equation type (e.g.displaymath to equation) -appear as a change to the complete equation. This mode is recommended -for situations where the content and order of some equations are still -being changed. [Default] -.Sp -\&\f(CW\*(C`fine\*(C'\fR or \f(CW3\fR: Detect small change in equations and mark up at fine granularity. -This mode is most suitable, if only minor changes to equations are -expected, e.g. correction of typos. -.IP "\fB\-\-disable\-citation\-markup\fR" 4 -.IX Item "--disable-citation-markup" -Suppress citation markup in styles using ulem (\s-1UNDERLINE, -FONTSTRIKE, CULINECHBAR\s0) -.IP "\fB\-\-enable\-citation\-markup\fR" 4 -.IX Item "--enable-citation-markup" -Protect citation commands in changed sections with \e\embox command [i.e. use default behaviour for ulem package for other packages] -.SS "Miscellaneous" -.IX Subsection "Miscellaneous" -.IP "\fB\-\-verbose\fR or \fB\-V\fR" 4 -.IX Item "--verbose or -V" -Output various status information to stderr during processing. -Default is to work silently. -.IP "\fB\-\-driver=type\fR" 4 -.IX Item "--driver=type" -Choose driver for changebar package (only relevant for styles using - changebar: \s-1CCHANGEBAR CFONTCHBAR CULINECHBAR CHANGEBAR\s0). Possible -drivers are listed in changebar manual, e.g. pdftex,dvips,dvitops - [Default: dvips] -.IP "\fB\-\-ignore\-warnings\fR" 4 -.IX Item "--ignore-warnings" -Suppress warnings about inconsistencies in length between input and -parsed strings and missing characters. These warning messages are -often related to non-standard latex or latex constructions with a -syntax unknown to \f(CW\*(C`latexdiff\*(C'\fR but the resulting difference argument -is often fully functional anyway, particularly if the non-standard -latex only occurs in parts of the text which have not changed. -.IP "\fB\-\-label=label\fR or \fB\-L label\fR" 4 -.IX Item "--label=label or -L label" -Sets the labels used to describe the old and new files. The first use -of this option sets the label describing the old file and the second -use of the option sets the label for the new file, i.e. set both -labels like this \f(CW\*(C`\-L labelold \-L labelnew\*(C'\fR. -[Default: use the filename and modification dates for the label] -.IP "\fB\-\-no\-label\fR" 4 -.IX Item "--no-label" -Suppress inclusion of old and new file names as comment in output file -.IP "\fB\-\-visble\-label\fR" 4 -.IX Item "--visble-label" -Include old and new filenames (or labels set with \-\-label option) as -visible output. -.IP "\fB\-\-flatten\fR" 4 -.IX Item "--flatten" -Replace \f(CW\*(C`\einput\*(C'\fR and \f(CW\*(C`\einclude\*(C'\fR commands within body by the content -of the files in their argument. If \f(CW\*(C`\eincludeonly\*(C'\fR is present in the -preamble, only those files are expanded into the document. However, -no recursion is done, i.e. \f(CW\*(C`\einput\*(C'\fR and \f(CW\*(C`\einclude\*(C'\fR commands within -included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, -respectively, making it possible to organise files into old and new directories. -\&\-\-flatten is applied recursively, so inputted files can contain further -\&\f(CW\*(C`\einput\*(C'\fR statements. -.Sp -Use of this option might result in prohibitive processing times for -larger documents, and the resulting difference document -no longer reflects the structure of the input documents. -.IP "\fB\-\-help\fR or \fB\-h\fR" 4 -.IX Item "--help or -h" -Show help text -.IP "\fB\-\-version\fR" 4 -.IX Item "--version" -Show version number -.SS "Predefined styles" -.IX Subsection "Predefined styles" -.SS "Major types" -.IX Subsection "Major types" -The major type determine the markup of plain text and some selected latex commands outside floats by defining the markup commands \f(CW\*(C`\eDIFadd{...}\*(C'\fR and \f(CW\*(C`\eDIFdel{...}\*(C'\fR . -.ie n .IP """UNDERLINE""" 10 -.el .IP "\f(CWUNDERLINE\fR" 10 -.IX Item "UNDERLINE" -Added text is wavy-underlined and blue, discarded text is struck out and red -(Requires color and ulem packages). Overstriking does not work in displayed math equations such that deleted parts of equation are underlined, not struck out (this is a shortcoming inherent to the ulem package). -.ie n .IP """CTRADITIONAL""" 10 -.el .IP "\f(CWCTRADITIONAL\fR" 10 -.IX Item "CTRADITIONAL" -Added text is blue and set in sans-serif, and a red footnote is created for each discarded -piece of text. (Requires color package) -.ie n .IP """TRADITIONAL""" 10 -.el .IP "\f(CWTRADITIONAL\fR" 10 -.IX Item "TRADITIONAL" -Like \f(CW\*(C`CTRADITIONAL\*(C'\fR but without the use of color. -.ie n .IP """CFONT""" 10 -.el .IP "\f(CWCFONT\fR" 10 -.IX Item "CFONT" -Added text is blue and set in sans-serif, and discarded text is red and very small size. -.ie n .IP """FONTSTRIKE""" 10 -.el .IP "\f(CWFONTSTRIKE\fR" 10 -.IX Item "FONTSTRIKE" -Added tex is set in sans-serif, discarded text small and struck out -.ie n .IP """CCHANGEBAR""" 10 -.el .IP "\f(CWCCHANGEBAR\fR" 10 -.IX Item "CCHANGEBAR" -Added text is blue, and discarded text is red. Additionally, the changed text is marked with a bar in the margin (Requires color and changebar packages). -.ie n .IP """CFONTCHBAR""" 10 -.el .IP "\f(CWCFONTCHBAR\fR" 10 -.IX Item "CFONTCHBAR" -Like \f(CW\*(C`CFONT\*(C'\fR but with additional changebars (Requires color and changebar packages). -.ie n .IP """CULINECHBAR""" 10 -.el .IP "\f(CWCULINECHBAR\fR" 10 -.IX Item "CULINECHBAR" -Like \f(CW\*(C`UNDERLINE\*(C'\fR but with additional changebars (Requires color, ulem and changebar packages). -.ie n .IP """CHANGEBAR""" 10 -.el .IP "\f(CWCHANGEBAR\fR" 10 -.IX Item "CHANGEBAR" -No mark up of text, but mark margins with changebars (Requires changebar package). -.ie n .IP """INVISIBLE""" 10 -.el .IP "\f(CWINVISIBLE\fR" 10 -.IX Item "INVISIBLE" -No visible markup (but generic markup commands will still be inserted. -.SS "Subtypes" -.IX Subsection "Subtypes" -The subtype defines the commands that are inserted at the begin and end of added or discarded blocks, irrespectively of whether these blocks contain text or commands (Defined commands: \f(CW\*(C`\eDIFaddbegin, \eDIFaddend, \eDIFdelbegin, \eDIFdelend\*(C'\fR) -.ie n .IP """SAFE""" 10 -.el .IP "\f(CWSAFE\fR" 10 -.IX Item "SAFE" -No additional markup (Recommended choice) -.ie n .IP """MARGIN""" 10 -.el .IP "\f(CWMARGIN\fR" 10 -.IX Item "MARGIN" -Mark beginning and end of changed blocks with symbols in the margin nearby (using -the standard \f(CW\*(C`\emarginpar\*(C'\fR command \- note that this sometimes moves somewhat -from the intended position. -.ie n .IP """COLOR""" 10 -.el .IP "\f(CWCOLOR\fR" 10 -.IX Item "COLOR" -An alternative way of marking added passages in blue, and deleted ones in red. -(It is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete, for example -with citation commands). -.ie n .IP """DVIPSCOL""" 10 -.el .IP "\f(CWDVIPSCOL\fR" 10 -.IX Item "DVIPSCOL" -An alternative way of marking added passages in blue, and deleted ones in red. Note -that \f(CW\*(C`DVIPSCOL\*(C'\fR only works with the dvips converter, e.g. not pdflatex. -(it is recommeneded to use instead the main types to effect colored markup, -although in some cases coloring with dvipscol can be more complete). -.SS "Float Types" -.IX Subsection "Float Types" -Some of the markup used in the main text might cause problems when used within -floats (e.g. figures or tables). For this reason alternative versions of all -markup commands are used within floats. The float type defines these alternative commands. -.ie n .IP """FLOATSAFE""" 10 -.el .IP "\f(CWFLOATSAFE\fR" 10 -.IX Item "FLOATSAFE" -Use identical markup for text as in the main body, but set all commands marking the begin and end of changed blocks to null-commands. You have to choose this float type if your subtype is \f(CW\*(C`MARGIN\*(C'\fR as \f(CW\*(C`\emarginpar\*(C'\fR does not work properly within floats. -.ie n .IP """TRADITIONALSAFE""" 10 -.el .IP "\f(CWTRADITIONALSAFE\fR" 10 -.IX Item "TRADITIONALSAFE" -Mark additions the same way as in the main text. Deleted environments are marked by angular brackets \e[ and \e] and the deleted text is set in scriptscript size. This float type should always be used with the \f(CW\*(C`TRADITIONAL\*(C'\fR and \f(CW\*(C`CTRADITIONAL\*(C'\fR markup types as the \efootnote command does not work properly in floating environments. -.ie n .IP """IDENTICAL""" 10 -.el .IP "\f(CWIDENTICAL\fR" 10 -.IX Item "IDENTICAL" -Make no difference between the main text and floats. -.SS "Configuration Variables" -.IX Subsection "Configuration Variables" -.ie n .IP """MINWORDSBLOCK""" 10 -.el .IP "\f(CWMINWORDSBLOCK\fR" 10 -.IX Item "MINWORDSBLOCK" -Minimum number of tokens required to form an independent block. This value is -used in the algorithm to detect changes of complete blocks by merging identical text parts of less than \f(CW\*(C`MINWORDSBLOCK\*(C'\fR to the preceding added and discarded parts. -.Sp -[ Default: 3 ] -.ie n .IP """FLOATENV""" 10 -.el .IP "\f(CWFLOATENV\fR" 10 -.IX Item "FLOATENV" -Environments whose name matches the regular expression in \f(CW\*(C`FLOATENV\*(C'\fR are -considered floats. Within these environments, the \fIlatexdiff\fR markup commands -are replaced by their \s-1FL\s0 variaties. -.Sp -[ Default: \f(CW\*(C`(?:figure|table|plate)[\ew\ed*@]*\*(C'\fR\ ] -.ie n .IP """PICTUREENV""" 10 -.el .IP "\f(CWPICTUREENV\fR" 10 -.IX Item "PICTUREENV" -Within environments whose name matches the regular expression in \f(CW\*(C`PICTUREENV\*(C'\fR -all latexdiff markup is removed (in pathologic cases this might lead to - inconsistent markup but this situation should be rare). -.Sp -[ Default: \f(CW\*(C`(?:picture|DIFnomarkup)[\ew\ed*@]*\*(C'\fR\ ] -.ie n .IP """MATHENV"",""MATHREPL""" 10 -.el .IP "\f(CWMATHENV\fR,\f(CWMATHREPL\fR" 10 -.IX Item "MATHENV,MATHREPL" -If both \ebegin and \eend for a math environment (environment name matching \f(CW\*(C`MATHENV\*(C'\fR -or \e[ and \e]) -are within the same deleted block, they are replaced by a \ebegin and \eend commands for \f(CW\*(C`MATHREPL\*(C'\fR -rather than being commented out. -.Sp -[ Default: \f(CW\*(C`MATHENV\*(C'\fR=\f(CW\*(C`(?:displaymath|equation)\*(C'\fR\ , \f(CW\*(C`MATHREPL\*(C'\fR=\f(CW\*(C`displaymath\*(C'\fR\ ] -.ie n .IP """MATHARRENV"",""MATHARRREPL""" 10 -.el .IP "\f(CWMATHARRENV\fR,\f(CWMATHARRREPL\fR" 10 -.IX Item "MATHARRENV,MATHARRREPL" -as \f(CW\*(C`MATHENV\*(C'\fR,\f(CW\*(C`MATHREPL\*(C'\fR but for equation arrays -.Sp -[ Default: \f(CW\*(C`MATHARRENV\*(C'\fR=\f(CW\*(C`eqnarray\e*?\*(C'\fR\ , \f(CW\*(C`MATHREPL\*(C'\fR=\f(CW\*(C`eqnarray\*(C'\fR\ ] -.ie n .IP """ARRENV""" 10 -.el .IP "\f(CWARRENV\fR" 10 -.IX Item "ARRENV" -If a match to \f(CW\*(C`ARRENV\*(C'\fR is found within an inline math environment within a deleted or added block, then the inlined math -is surrounded by \f(CW\*(C`\embox{\*(C'\fR...\f(CW\*(C`}\*(C'\fR. This is necessary as underlining does not work within inlined array environments. -.Sp -[ Default: \f(CW\*(C`ARRENV\*(C'\fR=\f(CW\*(C`(?:array|[pbvBV]matrix)\*(C'\fR\ -.ie n .IP """COUNTERCMD""" 10 -.el .IP "\f(CWCOUNTERCMD\fR" 10 -.IX Item "COUNTERCMD" -If a command in a deleted block which is also in the textcmd list matches \f(CW\*(C`COUNTERCMD\*(C'\fR then an -additional command \f(CW\*(C`\eaddtocounter{\*(C'\fR\fIcntcmd\fR\f(CW\*(C`}{\-1}\*(C'\fR, where \fIcntcmd\fR is the matching command, is appended in the diff file such that the numbering in the diff file remains synchronized with the -numbering in the new file. -.Sp -[ Default: \f(CW\*(C`COUNTERCMD\*(C'\fR=\f(CW\*(C`(?:footnote|part|section|subsection\*(C'\fR ... -.Sp -\&\f(CW\*(C`|subsubsection|paragraph|subparagraph)\*(C'\fR ] -.SH "COMMON PROBLEMS" -.IX Header "COMMON PROBLEMS" -.IP "Citations result in overfull boxes" 10 -.IX Item "Citations result in overfull boxes" -There is an incompatibility between the \f(CW\*(C`ulem\*(C'\fR package, which \f(CW\*(C`latexdiff\*(C'\fR uses for underlining and striking out in the \s-1UNDERLINE\s0 style, -the default style. In order to be able to mark up citations properly, they are placed with an \f(CW\*(C`\embox\*(C'\fR command in post-processing. As mboxes -cannot be broken across lines, this procedure frequently results in overfull boxes, possibly obscuring the content as it extends beyond the right margin. If this is a problem, you have two possibilities: -.Sp -1. Use \f(CW\*(C`COLOR\*(C'\fR or \f(CW\*(C`DVIPSCOL\*(C'\fR subtype markup (option \f(CW\*(C`\-s COLOR\*(C'\fR): If this markup is chosen, then changed citations are no longer marked up -with the wavy line (additions) or struck out (deletions), but are still highlighted in the appropriate color. -.Sp -2. Choose option \f(CW\*(C`\-\-disable\-citation\-markup\*(C'\fR which turns off the marking up of citations: deleted citations are no longer shown, and -added ctations are shown without markup. (This was the default behaviour of latexdiff at versions 0.6 and older) -.IP "Changes in complicated mathematical equations result in latex processing errors" 10 -.IX Item "Changes in complicated mathematical equations result in latex processing errors" -Try options \f(CW\*(C`\-\-math\-markup=whole\*(C'\fR. If even that fails, you can turn off mark up for equations with \f(CW\*(C`\-\-math\-markup=off\*(C'\fR. -.SH "BUGS" -.IX Header "BUGS" -Option allow-spaces not implemented entirely consistently. It breaks -the rules that number and type of white space does not matter, as -different numbers of inter-argument spaces are treated as significant. -.PP -Please submit bug reports using the issue tracker of the github repository page \fIhttps://github.com/ftilmann/latexdiff.git\fR, -or send them to \fItilmann@gfz\-potsdam.de\fR. Include the serial number of \fIlatexdiff\fR -(from comments at the top of the source or use \fB\-\-version\fR). If you come across latex -files that are error-free and conform to the specifications set out -above, and whose differencing still does not result in error-free -latex, please send me those files, ideally edited to only contain the -offending passage as long as that still reproduces the problem. If your -file relies on non-standard class files, you must include those. I will not -look at examples where I have trouble to latex the original files. -.SH "SEE ALSO" -.IX Header "SEE ALSO" -latexrevise, latexdiff-vc -.SH "PORTABILITY" -.IX Header "PORTABILITY" -\&\fIlatexdiff\fR does not make use of external commands and thus should run -on any platform supporting Perl 5.6 or higher. If files with encodings -other than \s-1ASCII\s0 or \s-1UTF\-8\s0 are processed, Perl 5.8 or higher is required. -.PP -The standard version of \fIlatexdiff\fR requires installation of the Perl package -\&\f(CW\*(C`Algorithm::Diff\*(C'\fR (available from \fIwww.cpan.org\fR \- -\&\fIhttp://search.cpan.org/~nedkonz/Algorithm\-Diff\-1.15\fR) but a stand-alone -version, \fIlatexdiff-so\fR, which has this package inlined, is available, too. -\&\fIlatexdiff-fast\fR requires the \fIdiff\fR command to be present. -.SH "AUTHOR" -.IX Header "AUTHOR" -Version 1.0.4 -Copyright (C) 2004\-2012 Frederik Tilmann -.PP -This program is free software; you can redistribute it and/or modify -it under the terms of the \s-1GNU\s0 General Public License Version 3 -.PP -Contributors of fixes and additions: V. Kuhlmann, J. Paisley, N. Becker, T. Doerges, K. Huebner, -T. Connors, Sebastian Gouezel and many others. -Thanks to the many people who sent in bug reports, feature suggestions, and other feedback. diff --git a/latexdiff-1.0.4/latexrevise b/latexdiff-1.0.4/latexrevise deleted file mode 100755 index 85955af..0000000 --- a/latexdiff-1.0.4/latexrevise +++ /dev/null @@ -1,538 +0,0 @@ -#!/usr/bin/env perl -# latexrevise - takes output file of latexdiff and removes either discarded -# or appended passages, then deletes all other latexdiff markup -# -# Copyright (C) 2004 F J Tilmann (tilmann@gfz-potsdam.de) -# -# Repository: https://github.com/ftilmann/latexdiff -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# Note: version number now keeping up with latexdiff -# Version 1.0.2 Option --version -# Version 1.0.1 no changes to latexrevise -# Version 0.3 Updated for compatibility with latexdiff 0.3 output (DIFAUXCMD removal) -# Version 0.1 First public release - -use Getopt::Long ; -use strict; -use warnings; - -my $versionstring=< \$accept, - 'decline|d'=> \$decline, - 'simplify|s' => \$simplify, - 'comment|c=s' => \$comment, - 'comment-environment|e=s' => \$comenv, - 'markup|m=s' => \$markup, - 'markup-environment|n=s' => \$markenv, - 'no-warnings|q' => \$verbose, - 'version' => \$version, - 'verbose|V' => \$verbose, - 'help|h|H' => \$help); - -if ( $help ) { - usage() ; -} - -if ( $version ) { - die $versionstring ; -} - - -if ( ($accept && $decline) || ($accept && $simplify) || ($decline && $simplify) ) { - die '-a,-d and -s options are mutually axclusive. Type latexrevise -h to get more help.'; -} - - - -print STDERR "ACCEPT mode\n" if $verbose && $accept; -print STDERR "DECLINE mode\n" if $verbose && $decline; -print STDERR "SIMPLIFY mode. WARNING: The output will not normally be valid latex,\n" if $verbose && $simplify; - -# Slurp old and new files -{ - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $input=<>; -} - -# split into parts -($preamble,$body,$post)=splitdoc($input,'\begin{document}','\end{document}'); - -if (length $preamble && ( $accept || $decline ) ) { - # - # WORK ON PREAMBLE - # - # (compare subroutine linediff in latexdiff to make sure correct strings are used) - - # remove extra commands added to preamble by latexdiff - $preamble =~ s/${PREAMBLEXTBEG}.*?${PREAMBLEXTEND}\n{0,1}//smg ; - - if ( $accept ) { - # delete mark up in appended lines - $preamble =~ s/^(.*) %DIF > $/$1/mg ; - } elsif ( $decline ) { - # delete appended lines - # $preamble =~ s/^(.*) %DIF > $//mg ; - $preamble =~ s/^(.*) %DIF > \n//mg ; - # delete markup in deleted lines - $preamble =~ s/^%DIF < //mg ; - } - # remove any remaining DIF markups - #$preamble =~ s/%DIF.*$//mg ; - $preamble =~ s/%DIF.*?\n//sg ; -} -#print $preamble ; - -# -# WORK ON BODY -# -if ($accept) { - # remove ADDMARKOPEN, ADDMARKCLOSE tokens - @matches= $body =~ m/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/sg; - checkpure(@matches); - $body =~ s/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/$1/sg; - # remove text flanked by DELMARKOPEN, DELMARKCLOSE tokens - @matches= $body =~ m/${DELMARKOPEN}(.*?)${DELMARKCLOSE}/sg; - checkpure(@matches); - $body =~ s/${DELMARKOPEN}(.*?)${DELMARKCLOSE}//sg; - # remove markup of added comments - $body =~ s/%${ADDCOMMENT}(.*?)$/%$1/mg ; - # remove deleted comments (full line) - $body =~ s/^%${DELCOMMENT}.*?\n//mg ; - # remove deleted comments (part of line) - $body =~ s/%${DELCOMMENT}.*?$//mg ; -} -elsif ( $decline) { - # remove DELMARKOPEN, DELMARKCLOSE tokens - @matches= $body =~ m/${DELMARKOPEN}(.*?)${DELMARKCLOSE}/sg; - checkpure(@matches); - $body =~ s/${DELMARKOPEN}(.*?)${DELMARKCLOSE}/$1/sg; - # remove text flanked by ADDMARKOPEN, ADDMARKCLOSE tokens - # as latexdiff algorithm keeps the formatting and white spaces - # of the new text, sometimes whitespace might be inserted or - # removed inappropriately. We try to guess whether this has - # happened - - # Mop up tokens. This must be done already now as otherwise - # detection of white-space problems does not work - $cnt = $body =~ s/${DELOPEN}($pat4)${DELCLOSE}/$1/sg; - # remove markup of deleted commands - $cnt += $body =~ s/${DELCMDOPEN}(.*?)${DELCMDCLOSE}/$1/sg ; - $cnt += $body =~ s/${DELCMDOPEN}//g ; - # remove aux commands - $cnt += $body =~ s/^.*${AUXCMD}$/${someword}/mg; $body =~ s/${someword}\n//g; - - while ( $body =~ m/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/s ) { - $prematch=$`; - $postmatch=$'; - checkpure($1); - if ( $prematch =~ /\w$/s && $postmatch =~ /^\w/ ) { - # apparently no white-space between word=>Insert white space - $body =~ s/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/ /s ; - } - elsif ( $prematch =~ /\s$/s && $postmatch =~ /^[.,;:]/ ) { - # space immediately before one of ".,:;" => remove this space - $body =~ s/\s${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}//s ; - } - else { - # do not insert or remove any extras - $body =~ s/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}//s; - } - } -# Alternative without special cases treatment -# @matches= $body =~ m/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}/sg; -# checkpure(@matches); -# $body =~ s/${ADDMARKOPEN}(.*?)${ADDMARKCLOSE}//sg; - # remove markup of deleted comments - $body =~ s/%${DELCOMMENT}(.*?)$/%$1/mg ; - # remove added comments (full line) - $body =~ s/^%${ADDCOMMENT}.*?\n//mg ; - # remove added comments (part of line) - $body =~ s/%${ADDCOMMENT}.*?$//mg ; -} - -# remove any remaining tokens -if ( $accept || $decline || $simplify ) { - # first substitution command deals with special case of added paragraph - $cnt = $body =~ s/${ADDOPEN}($pat4)\n${ADDCLOSE}\n/$1\n/sg; - $cnt += $body =~ s/${ADDOPEN}($pat4)${ADDCLOSE}/$1/sg; - $cnt==0 || warn 'Remaining $ADDOPEN tokens in DECLINE mode\n' unless ( $quiet || $accept || $simplify ); -} -if ($accept || $simplify ) { - # Note: in decline mode these commands have already been removed above - $cnt = $body =~ s/${DELOPEN}($pat4)${DELCLOSE}/$1/sg; - #### remove markup of deleted commands - $cnt += $body =~ s/${DELCMDOPEN}(.*?)${DELCMDCLOSE}/$1/sg ; - $cnt += $body =~ s/${DELCMDOPEN}//g ; - # remove aux commands - # $cnt += - $body =~ s/^.*${AUXCMD}$/${someword}/mg; $body =~ s/${someword}\n//g; - - #### remove deleted comments - ###$cnt += $body =~ s/${DIFDELCMD}.*?$//mg ; - $cnt==0 || warn 'Remaining $DELOPEN or $DIFDELCMD tokens in ACCEPT mode\n' unless ( $quiet || $simplify ); -} - -# Remove comment commands -if (defined($comment)) { - print STDERR "Removing \\$comment\{..\} sequences ..." if $verbose; - # protect $comments in comments by making them look different - $body =~ s/(%.*)${comment}(.*)$/$1${someword}$2/mg ; - # carry out the substitution - $cnt = 0 + $body =~ s/\\${comment}(?:\[${brat0}\])?\{${pat4}\}//sg ; - print STDERR "$cnt matches found and removed.\n" if $verbose; - # and undo the protection substitution - $body =~ s/(%.*)${someword}(.*)$/$1${comment}$2/mg ; -} -if (defined($comenv)) { - print STDERR "Removing $comenv environments ..." if $verbose; - $body =~ s/(%.*)${comenv}/$1${someword}/mg ; -## $cnt = 0 + $body =~ s/\\begin(?:\[${brat0}\])?\{\$comenv\}.*?\\end\{\$comenv\}//sg ; - $cnt = 0 + $body =~ s/\\begin(?:\[${brat0}\])?\{${comenv}\}.*?\\end\{${comenv}\}\s*?\n//sg ; - print STDERR "$cnt matches found and removed.\n" if $verbose; - $body =~ s/(%.*)${someword}/$1${comenv}/mg ; -} - -if (defined($markup)) { - print STDERR "Removing \\$markup\{..\} cpmmands ..." if $verbose; - # protect $markups in comments by making them look different - $body =~ s/(%.*)${markup}(.*)$/$1${someword}$2/mg ; - # carry out the substitution - $cnt = 0 + $body =~ s/\\${markup}(?:\[${brat0}\])?\{(${pat4})\}/$1/sg ; - print STDERR "$cnt matches found and removed.\n" if $verbose; - # and undo the protection substitution - $body =~ s/(%.*)${someword}(.*)$/$1${markup}$2/mg ; -} -if (defined($markenv)) { - print STDERR "Removing $markenv environments ..." if $verbose; - $body =~ s/(%.*)${markenv}/$1${someword}/mg ; - $cnt = 0 + $body =~ s/\\begin(?:\[${brat0}\])?\{${markenv}\}\n?//sg; - $cnt += 0 + $body =~ s/\\end\{${markenv}\}\n?//sg; - print STDERR $cnt/2, " matches found and removed.\n" if $verbose; - $body =~ s/(%.*)${someword}/$1${markenv}/mg ; -} - - -if ( length $preamble ) { - print "$preamble\\begin{document}${body}\\end{document}$post"; -} else { - print $body; -} - -# checkpure(@matches) -# checks whether any of the strings in matches contains -# $ADDMARKOPEN, $ADDMARKCLOSE,$DELMARKOPEN, or $DELMARKCLOSE -# If so, die reporting nesting problems, otherwise return to caller -sub checkpure { - while (defined($_=shift)) { - if ( /$ADDMARKOPEN/ || /$ADDMARKCLOSE/ - || /$DELMARKOPEN/ || /$DELMARKCLOSE/ ) { - die <=0 && $j>$i ) { - $part1 = substr($text,0,$i) ; - $part2 = substr($text,$i+$l1,$j-$i-$l1); - $part3 = substr($text,$j+$l2) unless $j+$l2 >= length $text; - } else { - die "$word1 or $word2 not in the correct order or not present as a pair." - } - return ($part1,$part2,$part3); -} - - - -sub usage { - die <<"EOF"; -Usage: $0 [OPTIONS] [diff.tex] > revised.tex - -Read a file diff.tex (output of latexdiff), and remove its markup. -If no filename is given read from standard input. The command can be used -in ACCEPT, DECLINE, or SIMPLIFY mode, and be used to remove user-defined -latex commands from the input (see options -c, -e, -m, -n below). -In ACCEPT mode, all appended text fragments (or preamble lines) -are kept, and all discarded text fragments (or preamble lines) are -deleted. -In DECLINE mode, all discarded text fragments are kept, and all appended -text fragments are deleted. -If you wish to keep some changes, edit the diff.tex file in -advance, and manually remove those tokens which would otherwise be -deleted. Note that latexrevise only pays attention to the \\DIFaddbegin, -\\DIFaddend, \\DIFdelbegin, and \\DIFdelend tokens and corresponding FL -varieties. All \\DIFadd and \\DIFdel commands (but not their content) are -simply deleted. The commands added by latexdiff to the preamble are also -removed. -In SIMPLIFY mode all latexdiff markup is removed from the body of the text (after -\\begin{document}) except for \\DIFaddbegin, \\DIFaddend, \\DIFdelbegin, \\DIFdelend -tokens and the corresponding FL varieties of those commands. The result -will not in general be valid latex-code but might be easier to read and edit in -preparation for a subsequent run in ACCEPT or DECLINE mode. -In SIMPLIFY mode the preamble is left unmodified. - --a ---accept Run in ACCEPT mode (delete all blocks marked by \\DIFdelbegin - and \\DIFdelend). - --d ---decline Run in DECLINE mode (delete all blocks marked by \\DIFaddbegin - and \\DIFaddend). - --s ---simplify Run in SIMPLIFY mode (Keep all \\DIFaddbegin, \\DIFaddend, - \\DIFdelbegin, \\DIFdelend tokens, but remove all other latexdiff - markup from body. - -Note that the three mode options are mutually exclusive. If no mode option is given, -latexrevise simply removes user annotations and markup according to the following four -options. - - --c cmd ---comment=cmd Remove \\cmd{...}. cmd is supposed to mark some explicit - anotations which should be removed from the file before - release. - --e envir ---comment-environment=envir - Remove explicit annotation environments from the text, i.e. remove - \\begin{envir} - ... - \\end{envir} - blocks. - --m cmd ---markup=cmd Remove the markup command cmd but leave its argument, i.e. - turn \\cmd{abc} into abc. - --n envir ---markup-environment=envir - Similarly, remove \\begin{envir} and \\end{envir} commands, - but leave content of the environment in the text. - --q ---no-warnings Do not warn users about \\DIDadd{..} or \\DIFdel statements - which should not be there anymore - --V ---verbose Verbose output - -EOF -} - -=head1 NAME - -latexrevise - selectively remove markup and text from latexdiff output - -=head1 SYNOPSIS - -B [ B ] [ F ] > F - -=head1 DESCRIPTION - -I reads a file C (output of I), and remove the markup commands. -If no filename is given the input is read from standard input. The command can be used -in I, I, or I mode, or can be used to remove user-defined -latex commands from the input (see B<-c>, B<-e>, B<-m>, and B<-n> below). -In I mode, all appended text fragments (or preamble lines) -are kept, and all discarded text fragments (or preamble lines) are -deleted. -In I mode, all discarded text fragments are kept, and all appended -text fragments are deleted. -If you wish to keep some changes, edit the diff.tex file in -advance, and manually remove those tokens which would otherwise be -deleted. Note that I only pays attention to the C<\DIFaddbegin>, -C<\DIFaddend>, C<\DIFdelbegin>, and C<\DIFdelend> tokens and corresponding FL -varieties. All C<\DIFadd> and C<\DIFdel> commands (but not their contents) are -simply deleted. The commands added by latexdiff to the preamble are also -removed. -In I mode, C<\DIFaddbegin, \DIFaddend, \DIFdelbegin, \DIFdelend> -tokens and their corresponding C varieties are kept but all other markup (e.g. C and <\DIFdel>) is removed. The result -will not in general be valid latex-code but it will be easier to read and edit in -preparation for a subsequent run in I or I mode. -In I mode the preamble is left unmodified. - -=head1 OPTIONS - -=over 4 - -=item B<-a> or B<--accept> - -Run in I mode (delete all blocks marked by C<\DIFdelbegin> and C<\DIFdelend>). - -=item B<-d> or B<--decline> - -Run in I mode (delete all blocks marked by C<\DIFaddbegin> -and C<\DIFaddend>). - -=item B<-s> or B<--simplify> - -Run in I mode (Keep all C<\DIFaddbegin>, C<\DIFaddend>, -C<\DIFdelbegin>, C<\DIFdelend> tokens, but remove all other latexdiff -markup from body). - -=back - -Note that the three mode options are mutually exclusive. If no mode option is given, -I simply removes user annotations and markup according to the following four -options. - -=over 4 - -=item B<-c cmd> or B<--comment=cmd> - -Remove C<\cmd{...}> sequences. C is supposed to mark some explicit -anotations which should be removed from the file before -release. - -=item B<-e envir> or B<--comment-environment=envir> - -Remove explicit annotation environments from the text, i.e. remove - - \begin{envir} - ... - \end{envir} - -blocks. - -=item B<-m cmd> or B<--markup=cmd> - -Remove the markup command C<\cmd> but leave its argument, i.e. -turn C<\cmd{abc}> into C. - -=item B<-n envir> or B<--markup-environment=envir> - -Similarly, remove C<\begin{envir}> and C<\end{envir}> commands but -leave content of the environment in the text. - - -=item B<-V> or B<--verbose> - -Verbose output - -=item B<-q> or B<--no-warnings> - -Do not warn users about C<\DIDadd{..}> or C<\DIFdel{..}> statements -which should have been removed already. - -=back - -=head1 BUGS - -The current version is a beta version which has not yet been -extensively tested, but worked fine locally. Please submit bug reports using the issue tracker of the github repository page I, -or send them to I.. Include the serial number of I -(Option --version). If you come across latexdiff -output which is not processed correctly by I please include the -problem file as well as the old and new files on which it is based, -ideally edited to only contain the offending passage as long as that still -reproduces the problem. - -Note that I gets confused by commented C<\begin{document}> or -C<\end{document}> statements - -=head1 SEE ALSO - -L - -=head1 PORTABILITY - -I does not make use of external commands and thus should run -on any platform supporting PERL v5 or higher. - -=head1 AUTHOR - -Copyright (C) 2004 Frederik Tilmann - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 - -=cut diff --git a/latexdiff-1.0.4/latexrevise.1 b/latexdiff-1.0.4/latexrevise.1 deleted file mode 100644 index b39017e..0000000 --- a/latexdiff-1.0.4/latexrevise.1 +++ /dev/null @@ -1,243 +0,0 @@ -.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` "" -. ds C' "" -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -. ds C` -. ds C' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.\" -.\" Avoid warning from groff about undefined register 'F'. -.de IX -.. -.nr rF 0 -.if \n(.g .if rF .nr rF 1 -.if (\n(rF:(\n(.g==0)) \{ -. if \nF \{ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. if !\nF==2 \{ -. nr % 0 -. nr F 2 -. \} -. \} -.\} -.rr rF -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "LATEXREVISE 1" -.TH LATEXREVISE 1 "2014-07-20" "perl v5.18.2" " " -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -latexrevise \- selectively remove markup and text from latexdiff output -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBlatexrevise\fR [ \fB\s-1OPTIONS\s0\fR ] [ \fIdiff.tex\fR ] > \fIrevised.tex\fR -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -\&\fIlatexrevise\fR reads a file \f(CW\*(C`diff.tex\*(C'\fR (output of \fIlatexdiff\fR), and remove the markup commands. -If no filename is given the input is read from standard input. The command can be used -in \fI\s-1ACCEPT\s0\fR, \fI\s-1DECLINE\s0\fR, or \fI\s-1SIMPLIFY\s0\fR mode, or can be used to remove user-defined -latex commands from the input (see \fB\-c\fR, \fB\-e\fR, \fB\-m\fR, and \fB\-n\fR below). -In \fI\s-1ACCEPT\s0\fR mode, all appended text fragments (or preamble lines) -are kept, and all discarded text fragments (or preamble lines) are -deleted. -In \fI\s-1DECLINE\s0\fR mode, all discarded text fragments are kept, and all appended -text fragments are deleted. -If you wish to keep some changes, edit the diff.tex file in -advance, and manually remove those tokens which would otherwise be -deleted. Note that \fIlatexrevise\fR only pays attention to the \f(CW\*(C`\eDIFaddbegin\*(C'\fR, -\&\f(CW\*(C`\eDIFaddend\*(C'\fR, \f(CW\*(C`\eDIFdelbegin\*(C'\fR, and \f(CW\*(C`\eDIFdelend\*(C'\fR tokens and corresponding \s-1FL\s0 -varieties. All \f(CW\*(C`\eDIFadd\*(C'\fR and \f(CW\*(C`\eDIFdel\*(C'\fR commands (but not their contents) are -simply deleted. The commands added by latexdiff to the preamble are also -removed. -In \fI\s-1SIMPLIFY\s0\fR mode, \f(CW\*(C`\eDIFaddbegin, \eDIFaddend, \eDIFdelbegin, \eDIFdelend\*(C'\fR -tokens and their corresponding \f(CW\*(C`FL\*(C'\fR varieties are kept but all other markup (e.g. \f(CW\*(C`DIFadd\*(C'\fR and <\eDIFdel>) is removed. The result -will not in general be valid latex-code but it will be easier to read and edit in -preparation for a subsequent run in \fI\s-1ACCEPT\s0\fR or \fI\s-1DECLINE\s0\fR mode. -In \fI\s-1SIMPLIFY\s0\fR mode the preamble is left unmodified. -.SH "OPTIONS" -.IX Header "OPTIONS" -.IP "\fB\-a\fR or \fB\-\-accept\fR" 4 -.IX Item "-a or --accept" -Run in \fI\s-1ACCEPT\s0\fR mode (delete all blocks marked by \f(CW\*(C`\eDIFdelbegin\*(C'\fR and \f(CW\*(C`\eDIFdelend\*(C'\fR). -.IP "\fB\-d\fR or \fB\-\-decline\fR" 4 -.IX Item "-d or --decline" -Run in \fI\s-1DECLINE\s0\fR mode (delete all blocks marked by \f(CW\*(C`\eDIFaddbegin\*(C'\fR -and \f(CW\*(C`\eDIFaddend\*(C'\fR). -.IP "\fB\-s\fR or \fB\-\-simplify\fR" 4 -.IX Item "-s or --simplify" -Run in \fI\s-1SIMPLIFY\s0\fR mode (Keep all \f(CW\*(C`\eDIFaddbegin\*(C'\fR, \f(CW\*(C`\eDIFaddend\*(C'\fR, -\&\f(CW\*(C`\eDIFdelbegin\*(C'\fR, \f(CW\*(C`\eDIFdelend\*(C'\fR tokens, but remove all other latexdiff -markup from body). -.PP -Note that the three mode options are mutually exclusive. If no mode option is given, -\&\fIlatexrevise\fR simply removes user annotations and markup according to the following four -options. -.IP "\fB\-c cmd\fR or \fB\-\-comment=cmd\fR" 4 -.IX Item "-c cmd or --comment=cmd" -Remove \f(CW\*(C`\ecmd{...}\*(C'\fR sequences. \f(CW\*(C`cmd\*(C'\fR is supposed to mark some explicit -anotations which should be removed from the file before -release. -.IP "\fB\-e envir\fR or \fB\-\-comment\-environment=envir\fR" 4 -.IX Item "-e envir or --comment-environment=envir" -Remove explicit annotation environments from the text, i.e. remove -.Sp -.Vb 3 -\& \ebegin{envir} -\& ... -\& \eend{envir} -.Ve -.Sp -blocks. -.IP "\fB\-m cmd\fR or \fB\-\-markup=cmd\fR" 4 -.IX Item "-m cmd or --markup=cmd" -Remove the markup command \f(CW\*(C`\ecmd\*(C'\fR but leave its argument, i.e. -turn \f(CW\*(C`\ecmd{abc}\*(C'\fR into \f(CW\*(C`abc\*(C'\fR. -.IP "\fB\-n envir\fR or \fB\-\-markup\-environment=envir\fR" 4 -.IX Item "-n envir or --markup-environment=envir" -Similarly, remove \f(CW\*(C`\ebegin{envir}\*(C'\fR and \f(CW\*(C`\eend{envir}\*(C'\fR commands but -leave content of the environment in the text. -.IP "\fB\-V\fR or \fB\-\-verbose\fR" 4 -.IX Item "-V or --verbose" -Verbose output -.IP "\fB\-q\fR or \fB\-\-no\-warnings\fR" 4 -.IX Item "-q or --no-warnings" -Do not warn users about \f(CW\*(C`\eDIDadd{..}\*(C'\fR or \f(CW\*(C`\eDIFdel{..}\*(C'\fR statements -which should have been removed already. -.SH "BUGS" -.IX Header "BUGS" -The current version is a beta version which has not yet been -extensively tested, but worked fine locally. Please submit bug reports using the issue tracker of the github repository page \fIhttps://github.com/ftilmann/latexdiff.git\fR, -or send them to \fItilmann@gfz\-potsdam.de\fR.. Include the serial number of \fIlatexrevise\fR -(Option \-\-version). If you come across latexdiff -output which is not processed correctly by \fIlatexrevise\fR please include the -problem file as well as the old and new files on which it is based, -ideally edited to only contain the offending passage as long as that still -reproduces the problem. -.PP -Note that \fIlatexrevise\fR gets confused by commented \f(CW\*(C`\ebegin{document}\*(C'\fR or -\&\f(CW\*(C`\eend{document}\*(C'\fR statements -.SH "SEE ALSO" -.IX Header "SEE ALSO" -latexdiff -.SH "PORTABILITY" -.IX Header "PORTABILITY" -\&\fIlatexrevise\fR does not make use of external commands and thus should run -on any platform supporting \s-1PERL\s0 v5 or higher. -.SH "AUTHOR" -.IX Header "AUTHOR" -Copyright (C) 2004 Frederik Tilmann -.PP -This program is free software; you can redistribute it and/or modify -it under the terms of the \s-1GNU\s0 General Public License Version 3 diff --git a/latexdiff-1.1.0/COPYING b/latexdiff-1.1.0/COPYING deleted file mode 100644 index d6fa915..0000000 --- a/latexdiff-1.1.0/COPYING +++ /dev/null @@ -1,623 +0,0 @@ - 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 - - diff --git a/latexdiff-1.1.0/Makefile b/latexdiff-1.1.0/Makefile deleted file mode 100644 index 148ead2..0000000 --- a/latexdiff-1.1.0/Makefile +++ /dev/null @@ -1,64 +0,0 @@ -# Modify these paths to the requirements of your own system -# For the current setting you will need root permission but -# it is perfectly acceptable to choose user directories -# -INSTALLPATH = /usr/local -INSTALLMANPATH = $(INSTALLPATH)/man -INSTALLEXECPATH = $(INSTALLPATH)/bin - -default: - @echo "To install stand-alone version type: make install" - @echo " (Note the standard version requires prior installation" - @echo " of the PERL package Algorithm::Diff available from " - @echo " the PERL archive www.cpan.org)" - @echo " " - @echo "To install fast version (using UNIX diff) type: make install fast " - @echo " " - @echo "To install the version which uses the system Algorithm::Diff package type: make install-ext" - @echo " " - -install: install-so - -install-ext: install-latexdiff install-latexrevise install-latexdiff-vc install-man - -install-so: install-latexdiff-so install-latexrevise install-latexdiff-vc install-man - -install-fast: install-latexdiff-fast install-latexrevise install-latexdiff-vc install-man - -install-man: - install latexrevise.1 latexdiff.1 latexdiff-vc.1 $(INSTALLMANPATH)/man1 - -install-latexdiff: - install latexdiff $(INSTALLEXECPATH) - -install-latexdiff-so: - if [ -e $(INSTALLEXECPATH)/latexdiff ]; then rm $(INSTALLEXECPATH)/latexdiff; fi - install latexdiff-so $(INSTALLEXECPATH) - cd $(INSTALLEXECPATH); ln -s latexdiff-so latexdiff - -install-latexdiff-fast: - if [ -e $(INSTALLEXECPATH)/latexdiff ]; then rm $(INSTALLEXECPATH)/latexdiff; fi - install latexdiff-fast $(INSTALLEXECPATH) - cd $(INSTALLEXECPATH); ln -s latexdiff-fast latexdiff - -install-latexrevise: - install latexrevise $(INSTALLEXECPATH) - -install-latexdiff-vc: - install latexdiff-vc $(INSTALLEXECPATH) - cd $(INSTALLEXECPATH); for vcs in cvs rcs svn git hg ; do if [ -e latexdiff-$$vcs ]; then rm latexdiff-$$vcs; fi; ln -s latexdiff-vc latexdiff-$$vcs ; done - -test-ext: - @echo "latexdiff example/example-draft.tex example/example-rev.tex (system Algorithm::Diff)" - ./latexdiff -V example/example-draft.tex example/example-rev.tex > example/example-diff.tex - @echo "Difference file created: example/example-diff.tex" - -test-so: - @echo "latexdiff example/example-draft.tex example/example-rev.tex (stand-alone version)" - ./latexdiff-so -V example/example-draft.tex example/example-rev.tex > example/example-diff.tex - @echo "Difference file created: example/example-diff.tex" - -test-fast: - @echo "latexdiff example/example-draft.tex example/example-rev.tex (stand-alone version)" - ./latexdiff-fast -V example/example-draft.tex example/example-rev.tex > example/example-diff.tex - @echo "Difference file created: example/example-diff.tex" diff --git a/latexdiff-1.1.0/README b/latexdiff-1.1.0/README deleted file mode 100644 index 911b585..0000000 --- a/latexdiff-1.1.0/README +++ /dev/null @@ -1,108 +0,0 @@ -INTRODUCTION - -latexdiff is a Perl script, which compares two latex files and marks -up significant differences between them (i.e. a diff for latex files). - Various options are available for visual markup using standard latex -packages such as "color.sty". Changes not directly affecting visible -text, for example in formatting commands, are still marked in -the latex source. - -A rudimentary revision facilility is provided by another Perl script, -latexrevise, which accepts or rejects all changes. Manual -editing of the difference file can be used to override this default -behaviour and accept or reject selected changes only. - -The author is F Tilmann. - -Project webpage: https://github.com/ftilmann/latexdiff/ -CTAN page: http://www.ctan.org/pkg/latexdiff - - -REQUIREMENTS - -Perl 5.8 or higher must be installed. - The latexdiff script makes use of the Perl package Algorithm::Diff (available -from www.cpan.org, current version 1.19). You can either install this package, or -use the standalone version of latexdiff, latexdiff-so, which has version 1.15 of -this package inlined and does not require external installation of -the package. Because latexdiff uses internal functions of Algorithm:Diff whose -calling format or availability can change without notice, the preferred method is -now to use the standalone version. - -As an alternative, latexdiff-fast has a modified version of Algorithm::Diff inlined, -which internally uses the UNIX diff command. This version is much faster but is dependent -on an external "diff" command. Subtle differences in the algorithm of Algorithm::Diff and -UNIX-diff mean that the resulting set of differences will generally not be the same as -for the standard latexdiff. In most practical cases, these differences are minor, though. - -INSTALLATION UNIX/LINUX - -The basic installation procedure is almost trivial: - -1. Copy latexdiff, latexrevise and latexdiff-vc into a directory which - is in the search path and make them executable. If the Algorithm::Diff - package is not installed, use latexdiff-so instead of latexdiff. - -2. Copy latexdiff.1 and latexrevise.1 into the correct man directory - -3. Optionally create soft links latexdiff-cvs latexdiff-rcs, latexdiff-git - latexdiff-svn and latexdiff-hg for latexdiff-vc. - -The attached trivial Makefile contains example commands to carry out above -steps as root for a typical UNIX installation. Type - - make install (for the stand alone version) -or - make install-ext (for the version using the external Algorithm::Diff) -or - make install-fast (for the version using the UNIX 'diff' function for fast differencing) - -to get it rolling. You can type - - make test -or - make test-ext -or - make test-fast - -to test the respective versions on a brief example before installation. It will often be -as easy to carry out these steps manually instead of using the Makefile. - - -DOCUMENTATION: - -Usage instructions are in the manual latexdiff-man.pdf as well as the -man pages. - -CHANGELOGS: - -Check out the comment lines at the beginning of the perl scripts (latexdiff, latexdiff-vc, latexrevise) - -CONTRIBUTIONS - -The directory contrib contains code written by others relating to latexdiff. -Currently this directory contains: - -latexdiff-wrap (Author: V. Kuhlmann) An alternative wrapper script which can be used - instead of latexdiff-vc. Its main use is as a template for customised wrapper scripts. - -latexdiff.spec (Author: T. Doerges) spec file for RPM generation - -latexchanges (Author: Jan-Ake Larsson) Wrapper script for applying latexdiff with numbered documen version -(see contrib/README.latexchanges for a more detailed description) - -Contributions by the following authors were incorporated into the latexdiff code, or inspired me to -extend latexdiff in a similar way: J. Paisley, N. Becker, K. Huebner - -LICENSE (also see file COPYING) - -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 (file LICENSE in the -distribution). - diff --git a/latexdiff-1.1.0/contrib/README.latexchanges b/latexdiff-1.1.0/contrib/README.latexchanges deleted file mode 100644 index 4a02765..0000000 --- a/latexdiff-1.1.0/contrib/README.latexchanges +++ /dev/null @@ -1,13 +0,0 @@ -latexchanges.py (Jan-Ake Larsson): -Here's a wrapper I wrote for latexdiff, intended as a drop-in -replacement for latex, when you have several numbered (or dated) -versions of a manuscript. My coauthors don't as a rule know what CVS or -SVN is, they simply use a number or date for the different versions. - -latexchanges replaces the current DVI with one that includes a -latexdiff to the last version. The last version is selected as the -TEX file in the same directory with the same prefix (up to a number -or a dot), that has an mtime immediately preceding the given TEX -file. - - diff --git a/latexdiff-1.1.0/contrib/latexchanges.py b/latexdiff-1.1.0/contrib/latexchanges.py deleted file mode 100644 index de7acbe..0000000 --- a/latexdiff-1.1.0/contrib/latexchanges.py +++ /dev/null @@ -1,67 +0,0 @@ -#! /bin/env python -# latexchanges -# -# Wrapper for latexdiff, intended as a drop-in replacement for latex, -# when you have several numbered (or dated) versions of a manuscript. -# My coauthors don't as a rule know what CVS or SVN is, they simply -# use a number or date for the different versions. -# -# latexchanges replaces the current DVI with one that includes a -# latexdiff to the last version. The last version is selected as the -# TEX file in the same directory with the same prefix (up to a number -# or a dot), that has an mtime immediately preceding the given TEX -# file. -# -# (I should probably add CVS version numbering too, at some point.) -# -# Copyright (C) 2009 by Jan-\AA{}ke Larsson -# Released under the terms of the GNU General Public License (GPL) -# Version 2. See http://www.gnu.org/ for details. -# -# Please do provide patches and bug reports, but remember: if it -# breaks, you get to keep the pieces. -# -# Jan-\AA{}ke Larsson -# Sept 16 2009 - -from os import listdir,system,stat -from sys import argv -from re import split - -name="" -newarg=[] - -# Find filename argument -for i in range(1,len(argv)): - if argv[i][-4:]==".tex": - basename=split('[0-9.]',argv[i])[0] - name=argv[i][:-4] - newarg.append(name+".changes.tex") - else: - newarg.append(argv[i]) - -if name: - print "Filename",name+".tex" - print "Prefix is",basename - # Find last archived version - mtime=stat(name+".tex").st_mtime - old_mtime=0 - ls=listdir(".") - for j in ls: - if j.startswith(basename) and j.endswith(".tex")\ - and not j.endswith(".changes.tex"): - tmptime=stat(j).st_mtime - if mtime>tmptime and old_mtime0: - print "Comparing with",oldname - system ("/bin/cp "+name+".aux "+name+".changes.aux") - system ("/bin/cp "+name+".bbl "+name+".changes.bbl") - system ("latexdiff "+oldname+" "+name+".tex > "+name+".changes.tex") - system ("latex "+" ".join(newarg)) - system ("cp "+name+".changes.dvi "+name+".dvi") - else: - system ("latex "+" ".join(argv[1:])) diff --git a/latexdiff-1.1.0/contrib/latexdiff-wrap b/latexdiff-1.1.0/contrib/latexdiff-wrap deleted file mode 100755 index 894b424..0000000 --- a/latexdiff-1.1.0/contrib/latexdiff-wrap +++ /dev/null @@ -1,192 +0,0 @@ -#!/bin/bash -# -# latexdiff-wrap -# -# Wrapper for latexdiff, to -# * provide support for documents consiting of more than 1 latex file -# * provide my common arguments -# -# Copyright (C) by Volker Kuhlmann -# Released under the terms of the GNU General Public License (GPL) Version 2. -# See http://www.gnu.org/ for details. -# -# Volker Kuhlmann -# 5, 6, 7, 12, 16, 17 Oct 2005 -# 31 Jan; 5, 7, 13, 15 Feb 2006 -# - -VERSION="0.6, 15 Feb 2006" -AUTHOR="Volker Kuhlmann " -COPYRIGHT="Copyright (C) 2005-2006" - - -#### -#### Constants and initialised variables -# -diffcmd="latexdiff" -diffrc="$HOME/texmf/latexdiff" -#diffargs="-e latin1 --ignore-warnings -p latexdiff-preamble.sty" -diffargs="-e latin1 --ignore-warnings" -diffargs="$diffargs --append-safecmd $diffrc/safe-cmds" -diffargs="$diffargs --append-textcmd $diffrc/text-cmds" -# Note: Can't use multiple --append-safecmd -# show current command lists: -#diffcmd="$diffcmd --show-safecmd --show-textcmd --show-config" - - -#### -#### Version, Usage, Help -# -show_version() { - echo "${0##*/} version $VERSION -$COPYRIGHT by $AUTHOR" -} - -show_usage() { - echo " -Usage: ${0##*/} OLDDIR NEWDIR DIFFDIR [DIFFARGS --] FILE.tex [...] - ${0##*/} --show [DIFFARGS] -Version $VERSION -$COPYRIGHT by $AUTHOR -" -} - -show_help() { - show_usage - echo "\ -For each FILE.tex, build a new file DIFFDIR/FILE.tex with markup of the changes -which were made from OLDDIR/FILE.tex to NEWDIR/FILE.tex. -Any path given with FILE.tex is stripped off. -Any DIFFARGS are added to the latexdiff call, if present (remember to follow -them with a double-hyphen on its own before the FILE arguments). - -With --show, shows the settings latexdiff would be running with, including the -changes applied by the user. -" -} - -# For scripts not using function library only: -Version() { show_version; exitwith ErrVersion; } -Usage() { show_help; exitwith ErrUsage; } -Help() { test "$1" && exitwith ErrHelp show_help; show_help; exitwith ErrOK; } - - -#### -#### Error/Exit codes -# -exitwith() { - exec 1>&2 # write stdout on stderr instead - case "$1" in - ErrOK) - exit 0;; - ErrVersion|ErrUsage|ErrHelp) - # Output generated by function (program) $2, if given - test -n "$2" && "$2" - exit 1;; - # more codes in here - # more codes in here - ErrBadoption) - echo "Bad option '$2'." - echo "Call with -h for help." - exit 9;; - ErrMissingParameter) - echo "A required parameter for option $2 is missing." - echo "Call with -h for help." - exit 9;; - *) - echo "Internal error: exitwith() called with illegal error code '$1'." - exit 19;; - esac -} - - -#### -#### Parse command line parameters -# - -# If the next arg starts with a "-", collect additional argument for latexdiff -# until "--". -scanextraargs() { - addargs=() - case "$1" in -*) - while [ $# -gt 0 -a "$1" != "--" ]; do - addargs=( "${addargs[@]}" "$1" ) - shift - done - test "$1" == "--" && shift - ;; esac - fileargs=( "$@" ) -} - -case "$1" in - --version) Version;; - --usage) Usage;; - --help|-h|-help) Help;; - --show) - shift - scanextraargs "$@" - (set -x - $diffcmd $diffargs "${addargs[@]}" \ - --show-safecmd --show-textcmd --show-config - ) | fmt - exit $? ;; -esac - -olddir="${1%/}" -newdir="${2%/}" -diffdir="${3%/}" - -if ! [ -d "$olddir" -a -d "$newdir" -a -d "$diffdir" ]; then - Help 1>&2 err -fi - -shift 3 - -scanextraargs "$@" -set -- "${fileargs[@]}" - - - -#### -#### Functions -# -#set -x -Log() { echo 1>&2 "+ $@"; "$@"; } - - -#### -#### Main -# - -# Create output directory, just in case. -(set -x -mkdir -p "$diffdir" -) -while [ $# -gt 0 ]; do - file="${1##*/}" - echo Examining: "$file" - # No point running latexdiff if both files are identical, - # but run latexdiff on top-level LaTeX file in any case. - if cmp --quiet "$olddir/$file" "$newdir/$file" \ - && ! grep -lq '\\begin.*{document}' "$newdir/$file"; then - (set -x - cp -p "$olddir/$file" "$diffdir" - ) - else - # Delete file, to make sure it's not clobbered by redirecting stdout - # in case it's a symlink to te original. - test -f "$diffdir/$file" && (set -x - rm "$diffdir/$file" - ) - # Run latexdiff if both input files are present. - run=1 - test -f "$olddir/$file" || { echo 1>&2 "No file: $olddir/$file"; run=; } - test -f "$newdir/$file" || { echo 1>&2 "No file: $newdir/$file"; run=; } - test -n "$run" && \ - (set -x - $diffcmd $diffargs "${addargs[@]}" \ - "$olddir/$file" "$newdir/$file" > "$diffdir/$file" - ) - fi - shift -done diff --git a/latexdiff-1.1.0/contrib/latexdiff.spec b/latexdiff-1.1.0/contrib/latexdiff.spec deleted file mode 100644 index 9255a69..0000000 --- a/latexdiff-1.1.0/contrib/latexdiff.spec +++ /dev/null @@ -1,58 +0,0 @@ -Summary: Diff for LaTeX files -Name: latexdiff -Version: 0.5 -Release: 1 -License: GPL -Group: Productivity/Publishing/TeX/Utilities -URL: http://www.tug.org/tex-archive/help/Catalogue/entries/latexdiff.html -Source0: %{name}.zip -BuildArch: noarch -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root -# only required for 'make install-ext' -# Requires: perl-Algorithm-Diff - - -%description -latexdiff is a Perl script, which compares two latex files and marks -up significant differences between them (i.e. a diff for latex files). - Various options are available for visual markup using standard latex -packages such as "color.sty". Changes not directly affecting visible -text, for example in formatting commands, are still marked in -the latex source. - -(C) 2004 Frederik Tilmann - - -%prep -%setup -n %{name} - - -%build -# quick had to adapt the Makefile -%{__mv} Makefile Makefile.old -%{__sed} \ - -e "s;INSTALLPATH = /usr/local;INSTALLPATH = \${DESTDIR}%{_prefix};" \ - -e "s;INSTALLMANPATH = \$(INSTALLPATH)/man;INSTALLMANPATH = \${DESTDIR}%{_mandir};" \ - Makefile.old > Makefile - - -%install -%{__mkdir_p} $RPM_BUILD_ROOT%{_bindir} -%{__mkdir_p} $RPM_BUILD_ROOT%{_mandir}/man1 - -%makeinstall - - -%clean -[ "${RPM_BUILD_ROOT}" != "/" ] && [ -d "${RPM_BUILD_ROOT}" ] && %{__rm} -rf "${RPM_BUILD_ROOT}" - - -%files -%defattr(-,root,root) -%doc example CHANGES LICENSE README -%{_bindir}/* -%{_mandir}/man*/* - -%changelog -* Thu Jan 4 2007 Till Dörges - 0.5-1 -- Initial build. diff --git a/latexdiff-1.1.0/doc/latexdiff-man.pdf b/latexdiff-1.1.0/doc/latexdiff-man.pdf deleted file mode 100644 index cb909a55603056be4ff4e66cbdd496cdd279fc24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 289524 zcmbTeV~}OrwyvEvD($S9wr$(CDs9`g%}U$0tx8qesI=`{Yu&x>TIW0ai@VPqzgmnK zZS+1OX2kpSx3xA&mSLCx^Z?s$765K;7&>WV8&fAU00S#MJK)a? zhECMn%E{OPKqqQt;AAXpY-np_48zL{#$Xi(VDl^o(z$nQ zbBaNJRH98Vfs4VYCS}ER8eU?pgS}W;&08EE<;p8ek8|(1(N1WP5)Bo?J$gwe9KhBm z^ljLIW{D5LUy_*~K~(D!#E%f}n72Ys2kIx!y3;bTs|%kpn~GrfzIU;;>qy{lv65y{ z<|9{PVBt%0Lj-Ss`t{v*F`9O6+YQ<_`PGd^s?T4&N}|>s<76dY%illH2lVHY@4a?a z**VK`RaEmFZ3gWTRlC``3_^7a-yBK###V%z5om)T27-_DUEoqyQJ%{$gpG@x=3Zs+ zlQz-qN}`UBsO;>OyP>PKGG55QBB<70EtSXBU0AaPD{UAwX2YV?l6@iHw@EIpYmOG3 zwuP7)6N6PWv`17)jqI~96h#& z+kQraV*19VzbF*<3om$Lz$`OF{4Owd^F^E0?R!{T=XRaV3Dv;#8;X+;JeLvnqms22 z6yOW{$p-;F{OUSKhPAUX&eL-kEEj#Y9rs-}B7v5tv!COuRVqZ-V{yqC#ep4b$+{F< zBr-SI{uzg@Ol-Gk(WI0ZRjJeN(UBTKDnM1TXj;Z6Wu<=7P)Fq#Jp%K!O<*0{_uj`G z=qtAEs1S5YX%?8TP{nZ4Pq{o+yaINiWi;T?sVznEogjm^(xeDKBLO-cBxJ$bVy69C zOmP$L+%AIzXWsBfo^}H28=jZF9@fns7NQwo8lL0srEomg-bMY6L1J;Z=+FrHkn=z? zoMCBkg-)6?osMyG@`1~W*310zx%F-N`~kDh%o#PI!>Z^tlO)Q)fi>*8Kg3Uy^!R&k ze@1hnvaDAG67zdO_1}9nt3UuJqnKuSEzh!1#J&pb}Y5R4F$)G3o8L4JM-2%8sD&*2NgH6bK_iI+N< z^lsfpD(UJIymp$h#s8{ys$A$Zf1Yx5iekCuOvG;v@jCV8QA~DkYJPsgsiXDTERjxX z6JiSm_;6i_(d`IK4u1=Ai-Bek#xSaJP z!_L9-T3}ZqV~{Kgf9pc#-aW+tV?g7QxgDzIiFQgUBg7W3Q;>@*ijP~TeAT4^TWjN` z#cd3T`FhLFXCtcE)$dm}T|tuemq^MX0GOw9w4C-XEMiOs1QfKFD)~d)thxsedfcJN z`1p;wq#P6t>IT^A`0lbcN5VOe-{AH2z*q^i0KbK4nR=UiQShj`LK22Nmj&)r>X@SC zTo5kF2SsH+@0QTUO1I}HwH z!&UpezU{>!SRhFlm-mx6NCL_JDP;nnTmEqJLK<$N4mQ#kYL2w=T18_ul}-sZBXf87 z^Q)TeRVKP5)V_00D5+*$r7{367rc_T=Q_f4E8waQV#~|259VpQKs2=*$9L1Zr|LbG zE(n;=eOAYpPl}(;9pz)msB${aWMX;QXQ>fZM)uz^pT@y z07eb~)y)x)Pf$k%Pmls>HA@sa&sWpF4D8&!fSHwq?OHzkc$tPJscLjML%dcTAmGSy z{}ui0_IXi4N7ZV87X8M@o&Y2@&9>+I$Jgt2{7SOL}QN({2?RNIl7a%7=$+}&<6s4zw!y6&U7UW>Ya0Re8yr>*Dx;r_zmE2xzsf>qCJWFg(T zQfgc7gk?eCIL|C(mA}mNqI&$OLVHj38D$YvqQ5^K$2p7IzNjWmA+zpxhMMqBUOw;c z*XQpoPF-pQw{;Y_Sw=ZE^W?1>@sx9b7OcUSI$*&((Px3iV_aF#TXQa~H%&(SKha!8E zsCC^y{pn-02aHw9x2xA zUD_n^JiSWn7!1O!ln(aE+sk$fyzj{gqi(tu_Yen~{l&Cm)i#=t)NZBOjT}#xq{$z} zv*)qeW>I*3w>Y$NwSj1GKSPsDS02#YZ@9SA2IkB&MNRKt7_}dIknBk;&fE)+H6UlG zNa!%Fot9fHWVq@fGTMBRS%qS$^oT1U*vj*?iRsv%3tHh4wy=y~0FmZ5N>7C+7wyXb zWS2|+-Q8koVPxpVP&6KPiDm${bR~`aY5#F;GU$E=FAH*!E{p7Xnh75w(9z(XQju;< z^)czlV7cW?o?ckm7QcS+fchfcUljjtw3!{0uR$6=MtW1sKENxf6OOs42%h)JTmHH>Rjpv_@?CSGQ8bMhKVa!Q?}m@Y z*bpW9T&V~xFQR|A_#LLwmS>sPSKA~sP7Sd6v;FLzafP~ZO<6Mo%+{#)&>nzx+%JQ$ zl-521eVqQU>zI}e<}qUWJ1&y${6J1s>srNvqJ}az4puGw%hx7GNb8BapfFwSZ7~M% z?kp$@0Q@G(&gNY5TFoC#_hn`+8Uqnm1}VKb@Y_QPENd>{WXm@CUi>WFx0rW~<+!l0 z!_~TC;3=x+cj(Gd&Rcqm3Jm2>Je-b30pBU;5kOKl4-{rDX;7|Z3t@}$a3u=bXt(jT zM#|}3+6kg&J-<99-bdp(gAaILkK$X-*x&|G1QQVKZ7V#Qp1L(Ah_4x-d>kBsfL_hL zn@oL1!raQDR^+XU8IyAnlVu%+#uY=Y-{xmQcJB*e!~^El3n9jRLYK380e!K zju9lcHRM8@>)7DbWdl8={@_I;(S_ebvxMZ^c0&l|9!U4Hw@DCG$?m@JhoxIdV-I3y zOKP+bCx-E#0;P30V0Og6SI|0MDPLD86a6VYaq6Y1hx#B%N|<%0Y=U!HH=~#~LksdT zp~6>Na_p9uSG17FP3J3kFwYwY3?6r*gWwwLjJ@ulT2yAtD2SbkOb;*}9bIx4L$s$f zzcDRVIR2&fY$vlzV>@4U&q;}_aM!F031ZIeY$^ZRx)&}9jpeW(x`qB$w~@yd3Yz8L zULh5RoHmCw!N2+_aslxp#I`()N>@!N%PLKpJuVFy=1Q6pHitpuBi+_QFkZg_^gKJc z%$JwnPr$DyxJWXZ@)W_+KsS=!t7|9h%i(n_4#KD?C2P%VzZVr46b!V&)>AVK-)GK- zq2q~9*N*Ls5lf645Jx>71#9Ifh)1~0ONd);f^Z?H#zJyvJKZdjQc_u!`yGF-0_f@OeKU*W+NI(ij>M^*x61%RX;o`E|)X&12+5+MBXd=+8Sm z0^0pk7jWUVW0e98B@*1!(H2xJQ?B?nRfl@y)lLFQ!)axghjM^-Uw?HX3vV*JWWMRg zNEN3O%3bgf!gIKE9ux>^7E;7|v^%xK$4SEEZxM$2x za;2qeeRUtLrPf1R4b_5(lqwi$h0VTB_6=Gqq9bgNDn;hY;K1=0k)T{_H5QC2swth7sa1W(# zf%Qy0Ddv|`skZwv+YZ{CSueV z@4dlJ0VMg464Q(Ih4&9XYoEzHgiz>oY`B2M;U5wf0L9N=ZqUkwWYm)OZ~I$}e&1gS z=j<&2?nmw_th^eBrd6Qo8x;$D>W)!CeP=9SRMD_}5394AP6HJY^+G!lw8`*|Kl{-* zQfLeFx(*+ch+&?`0-Em-edu#|*y;qXJx3api+l7Xd;;4w8Vb=JJSgA%Nq{?ZSM1_f z_zjd4cE3JBnr7;{JZ0*srt*R#>2>8jfIo%@sXFKuc=Z*A#>HBBJ>wcA?!eQB1e_eD zB_(@O`y+_ujIK64-U&x8q&-Kz6vwJKjInhqI zqp6tj?`y^gmr|M+3+ zGV4uvIiH8Q`PJ<3Hc?7k`BsAUPt zxUO}dU0Xv^`Gz>^r~;Mgw$+#2Pp4BIkFH~s_evFK77bd#ny+;-s*8i&b0$q=YM)ol zY?Rjs8cnXxQ<_xgO{Ne#((W4sr!VoIyLfAr-)7#Yuw6KFa2tLBBi`_gbA5MnUA*B& zu~TvSnBt5OynKCeb3)5G)?8T|HFm$|fNHYTZVG<=XnQ`VRIeJCk&DjNK}WM;!H)BT z&2d{70&a2~0q|!+-pxFR`GQ}DV4UE6HkVkPYVv-#H6V2Dk_PRG3{7bDv6@&JD9zqT z*43O0AMhtbGb<#kxOW6OD_BoB>MDD(V;1VFrqDxy3fG%~EuQ^Qs_vz91Ydlpc7VtA z*rm{S3TV=HX@aW?2M1yYed#^Z%EGF-%9a}#t+3b(N7kat3(r>yCje1F241bQwyQ9&W*19j9wq(tD@R) zar2dkgB9McP(Vej*`4(G4vI2!-@4yzGNN>BbN%$%L7%Z2QQzH6p)HxJ(kW7uNE82^ z)S$;8GrK)M#agK#Qjo89E`k2h$bP1(>)B)Mcz`9`iR zSex8ImN9@WA12A|HwgTq9^M@OCUzSvaoC-pV{vLN9{?F=LI4wH*;x_VSWsurUX`Mr-N+`;1un@DL;5gYGpYqMp9we3-=SpvLzXTdn^s_=ZAFJmF$Lzwy5 z1*WXSfS%XHx88od!<0O<+6-<=@d6SXP8MQyXp-6sVU0y(V`wmbEgSM^Z{MHMks6HCE zCHgBOoa#jwdN{-3E5}lz>r}p7%&G-E-*wzLS5f=kem!aVt0g=+ef=Td*(^KSQ1>}B zonxPu<5lAtQ(H2W9~(@&;7*BDPR~Q1TyxI1F3P^NxO##LMwEFyf_wZzl|NoVV??r% zo(_inwya>5(DoC))miXvW6qh3;43p3*~P($syW4SD2zB>?_XXz(f28cd|4bIsH|DS zdf|Y_+R?ljpsL@U3AM`OQ$Td@g~`vl2gUm_b#^Te2i;6cxiS<9ZJ*1pB}im{B<05I z0Q^3H@}=Lvqz`F>V8h5=V88C`lOnS-%aoqM!L@t~>N^9Ap)Er(BG9DeLq~l!50EXy z4|gMSGL+tF1ZrYShY(q}Sf$~i-pDv$YJ*POdXy^?BFGeZ6Ulqfs1o(wq`F)lMDeIS zjni_~kX?wwmM9H?k+WjovQYv^U!lDi@(>1vAvzHf1`cKP&RF%{HYCaz$+t^HK$_fE z!5ORX$KFUR{p-7)8~8E=hkPR+8`c^Oh-aC}V_GP3!?vz&CT~iIjti|Zu$zzdB4^k; z0FQAIWw6X~552N>i(Rh0+-ppwuv;aN;qB_Ux;(f{ZAr5>fd5g8E*SxIw#KiM-D~(F zp*OZq5u)KVy(vx}vO9WmeVurR(cr|obyEtUHS7g4a*WJrl}9P>*PML|!ZU;%_)g4P zvkShkB#PL1D?9>9jJ|e*AA_dR_{N5kB+gp%<;X5&RK1MEJ=LK57f_Zs~y8ffnVN|qX zCr}vrEdfQSglnI|K9;v~Q5i*9@eAm7l0ZU(t0VEUsO6|$iUVysRdC0679?(|fqa`7 zZV-{>Ty9HQZ~$V}w}oB|*ltg0F^miUb_Qmlt`^VZ3@V-s9nlEXdryogf@_pa>BtH2 ze*Mx!wfTb-I)-kUfz(n(+gwTC!15Ixb@AXrJ8U#r5X-YQ*ovYMpp+!bs@zQ{a%YR+ zBmPEV8ZHn`fN`K+9ftf+v79oK4NDTLKdPG46W0kzpaigr-fh1h+L!p9FU@#~H$%1W z;h^tj_FN9yiD#aYF~1Uk9U;fC7{{c;L5G&sOeZ4Pj7I6P6JicJI*TtL3bhkoRMcX zgaL-E4cax)*P8~l)5tSpD-7O7S9+9{G$;{FVFy<4(oKeOq9`Ndz3XiTLwSdDawAX`=4~*W zx*_VR^A)t+uQ28z1Ys}V>rH{r1sa-iNJk7u_RIH25FQ2Bwn0nQP_*i1sW(^?KNzNq z3Dl>$qZPZ^PHT2Cwstg0oHqYrdU8Qn{o(u|g@sRptbb9y@!?yA+XTl!| zen3)6#gniV5pM)(&Z@Jd3hR0Lqt|K>0ej=15#txRtPVD7%Zl_L)J+K;idu$Mh9N^f zQ5c5HgLl>%t|By_8H%r#@zSFQf#8E#rraeO;@7H%-(;F&nOqtZn5-h;KS-u?-lCEzjS&O(%%Fk3^Da2rJXjD8cf9Adas;O?mYligHkKfEny~8q0(HAr$$;u_TCdouDHl zSXta(C!LLQgeClGh!snmIubHm|A}$9M30s`x|$(;%M23s@n~jg?34=Y+IsrhYnM~0(3J!zMf<#dLMTDwFI7x- z9kTmx1g`-7=6We!ubmyLTd9LYD%7+$_{3d(?5M4hQtI;_xmjnH%dg#X1n_w>-cXoF zH1EXmKGY(eu3yhx$z zR=LVqRMo>IhdI6(bp6UqQb^(M{?>OLYVmmFtmSOpWia$e@Y+;cjG2|)pNJUO00Rl~ z{=RQK+luw%QIG~-7zhIUzOlGn77bajBl};a2qAesn%kF@>20lv=BThVv0A>U9@;HNSFg=r-@3fugj?!%HDYqqJuh%eAM4K zuONx0HISF5wo;B2aeTJ81VX;jww`3EQ=*H)m|$J7*gL7@t0Ui9iz@G?95oP| zldiXcM+o^B6^rKar3)o5Y#_9?RFu7^{e09Au&!|5sz}MCX(asdz-BoT7V}53a6FA1~~km^L6u(G}YG7Pij* z^|i(Aj&5Ny#X|~Tv9f+QCX6g5+mWC*psN29JhO#z8;=%=5x-IE^ZCh2yVi*AAZYf( zeH81csO9}rolAVID|y;kW(_hHLT?x^lm1y9sc!MRn z64(J-O<5;uNG*?;gQOeM*C|KCj-4=1vmVTI(^4}^#=@I)Iz(oHhsZIX?yXfh;<38- zxTD7JUopq%>b7Ek)NYCU4`|y�TdOK9S*H`}bo&SsS)dId)t_&|mSh?vJ7+ed9(| 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

xPuIBi`?K96 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¨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 z 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≫Eu58mrk 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 diff --git a/latexdiff-1.1.0/doc/latexdiff-man.tex b/latexdiff-1.1.0/doc/latexdiff-man.tex deleted file mode 100644 index 2adffcc..0000000 --- a/latexdiff-1.1.0/doc/latexdiff-man.tex +++ /dev/null @@ -1,355 +0,0 @@ -\documentclass[a4]{article} -\usepackage{graphicx} -%\def\C++{{\rm C\kern-.05em\raise.3ex\hbox{\footnotesize ++}}} -%\def\underscore{\leavevmode\kern.04em\vbox{\hrule width 0.4em height 0.3pt}} -\setlength{\parindent}{0pt} -%\setlength{\textwidth}{6.5in} -%\setlength{\oddsidemargin}{0.0in} -\title{Marking up differences between latex files with {\em latexdiff}} -\author{F.J. Tilmann\thanks{tilmann@gfz-potsdam.de}} -\date{\today} - -\begin{document} -\maketitle - -\section*{Preamble} - -{\em latexdiff} is a Perl script, which compares two -latex files and marks up significant differences between them. Various options are available for visual markup using standard -latex packages such as {\em color.sty}. Changes not directly affecting visible -text, for example in formatting commands, are still marked in the -latex source. - -A rudimentary revision facilility is provided by another Perl script, -{\em latexrevise}, which accepts or rejects all changes. Manual editing -of the difference file can be used to override this default behaviour -and accept or reject selected changes only. - -There is no explicit support for annotations as these are trivial to implement. -For example, I include the following command definition in the preamble -\begin{verbatim} -\newcommand{\remark}[1]{{ \bf [ \footnotesize #1 ]}} -\end{verbatim} -and mark up annotations as follows -\begin{verbatim} -... The roadrunner is the fastest running bird \remark{Check this -again with a zoologist!}. The most famous roadrunner ... -\end{verbatim} -Alternatively, instead of a command like \verb#\remark# in the example just given, an -equivalent annotation environment could be defined. -{\em latexrevise} can remove such comments or -environments from the text body. - -%It is planned that the revision capabilities of this system will be -%further expanded, dependent on the amount of feedback received. - -On the following pages you find the {\em man} pages for {\em - latexdiff} and {\em latexrevise} and a simple example. - -\include{latexdiff} -\setcounter{section}{0} - -\include{latexrevise} -\setcounter{section}{0} - -\include{latexdiff-vc} -\setcounter{section}{0} - -\section*{A simple example} - -We start with a draft text, \verb|example-draft.tex|, listed here in -full but also included in the distribution (except that the ``verbatim'' environment had -to be renamed to ``Verbatim'' for the listing). - -{\scriptsize -\begin{verbatim} -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6.5in} - -\title{latexdiff Example - Draft version} -\author{F Tilmann} - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of latexdiff features. -Type -\begin{Verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{Verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{Verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{Verbatim} -or -\begin{Verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{Verbatim} -to display the markup. Of course, instead of \verb|xpdf| you can use -\verb|okular, evince, acroread| or any other pdf or postscript viewer. - -\section*{Another section title} - -A paragraph with a line only in the draft document. More things -could be said were it not for the constraints of time and space. - -More things could be said were it not for the constraints of time and space. - -And here is a tipo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & Grey \\ -Saruman & White -\end{tabular} - -And sometimes a whole paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical. -No change, no markup! -\end{document} -\end{verbatim} -} - -We can now edit -this text as we would do with any other latex file to create -a new revision of the text, \verb|example-rev.tex|. We should run -\begin{verbatim} -latex example-rev.tex -\end{verbatim} -and look at the resulting \verb|.dvi| file to make sure that all -changes are valid. An example revision is listed here: - -{\scriptsize -\begin{verbatim} -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6in} - -\title{latexdiff Example - Revised version} -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even -% if some preamble might eventually end up as visible text.) - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of the latexdiff features. -Type -\begin{Verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{Verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{Verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{Verbatim} -or -\begin{Verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{Verbatim} -to display the markup. - -\section*{Yet another section title} - - More things could be said were it not for the constraints of time and space. - -A paragraph with a line only in the revised document. -More things could be said were it not for the constraints of time and space. - -And here is a typo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & White \\ -Saruman & Evil -\end{tabular} - -And now for something completely different, with not a paragraph in sight. -No change, -no markup! -\end{document} -\end{verbatim} -} - -To compare both revisions, type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -This results in the following difference file (a few newlines have been -added in this listing for legibility reasosn): -{\scriptsize -\begin{verbatim} -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -%DIF 7c7 -%DIF < \setlength{\textwidth}{6.5in} -%DIF ------- -\setlength{\textwidth}{6in} %DIF > -%DIF ------- - -%DIF 9c9 -%DIF < \title{latexdiff Example - Draft version} -%DIF ------- -\title{latexdiff Example - Revised version} %DIF > -%DIF ------- -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even %DIF > -% if some preamble might eventually end up as visible text.) %DIF > -%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF -%DIF UNDERLINE PREAMBLE %DIF PREAMBLE -\RequirePackage[normalem]{ulem} %DIF PREAMBLE -\RequirePackage{color} %DIF PREAMBLE -\providecommand{\DIFadd}[1]{{\color{blue}\uline{#1}}} %DIF PREAMBLE -\providecommand{\DIFdel}[1]{{\color{red}\sout{#1}}} %DIF PREAMBLE -%DIF SAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddbegin}{} %DIF PREAMBLE -\providecommand{\DIFaddend}{} %DIF PREAMBLE -\providecommand{\DIFdelbegin}{} %DIF PREAMBLE -\providecommand{\DIFdelend}{} %DIF PREAMBLE -%DIF FLOATSAFE PREAMBLE %DIF PREAMBLE -\providecommand{\DIFaddFL}[1]{\DIFadd{#1}} %DIF PREAMBLE -\providecommand{\DIFdelFL}[1]{\DIFdel{#1}} %DIF PREAMBLE -\providecommand{\DIFaddbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFaddendFL}{} %DIF PREAMBLE -\providecommand{\DIFdelbeginFL}{} %DIF PREAMBLE -\providecommand{\DIFdelendFL}{} %DIF PREAMBLE -%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of latexdiff features. -Type -\begin{Verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{Verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{Verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{Verbatim} -or -\begin{Verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{Verbatim} -to display the markup. - -\section*{\DIFaddbegin \DIFadd{Yet another }\DIFaddend \DIFdelbegin -\DIFdel{Another }\DIFdelend section title} - - \DIFdelbegin \DIFdel{A paragraph with a line only in the draft - document. }\DIFdelend More things could - be said were it not for the constraints of time and space. - -\DIFaddbegin \DIFadd{A paragraph with a line only in the revised - document. }\DIFaddend More things could be said -were it not for the constraints of time and space. - -And here is a \DIFaddbegin \DIFadd{typo}\DIFaddend \DIFdelbegin -\DIFdel{tipo}\DIFdelend . - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & \DIFaddbegin \DIFadd{White }\DIFaddend \DIFdelbegin -\DIFdel{Grey }\DIFdelend \\ -Saruman & \DIFaddbegin \DIFadd{Evil -}\DIFaddend \DIFdelbegin \DIFdel{White -}\DIFdelend \end{tabular} - -And \DIFaddbegin \DIFadd{now for something completely different, with not - a paragraph in sight}\DIFaddend \DIFdelbegin \DIFdel{sometimes a whole - paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}\DIFdelend . -No change, -no markup! -\end{document} -\end{verbatim} -} -Type -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -to make the markup visible. This is what it looks like: - -\vspace{1cm} -\framebox[\textwidth]{\includegraphics[width=\textwidth]{example-diff}} -\vspace{1cm} - -If you approve of all the changes in the revision, just continue with -\verb|example-rev.tex| for the next revision. If you like to adopt -most but not all changes you can use \verb|latexrevise| in the -following manner. Simply remove the \verb|\DIFdelbegin| and -\verb|\DIFdelend| tags around the text you would like to keep and -simply remove the text between \verb|\DIFaddbegin| and -\verb|\DIFaddend| tags, if you do not wish to keep them. Say you are happy with all proposed changes for the -example above except in -the last paragraph where you prefer the original draft. You have -to change - -{\scriptsize -\begin{verbatim} -... -And \DIFaddbegin \DIFadd{now for something completely different, with not - a paragraph in sight}\DIFaddend \DIFdelbegin \DIFdel{sometimes a whole - paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}\DIFdelend . -... -\end{verbatim} -} -into -{\scriptsize -\begin{verbatim} -... -And \DIFdel{sometimes a whole - paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical}. -... -\end{verbatim} -} -and run -\begin{verbatim} -latexrevise -a example-rev.tex > example-final.tex -\end{verbatim} -\verb|example-final.tex| is then almost identical to -\verb|example-rev.tex| except for the last paragraph. -\end{document} diff --git a/latexdiff-1.1.0/example/example-draft.tex b/latexdiff-1.1.0/example/example-draft.tex deleted file mode 100644 index 593a170..0000000 --- a/latexdiff-1.1.0/example/example-draft.tex +++ /dev/null @@ -1,59 +0,0 @@ -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6.5in} - -\title{latexdiff Example - Draft version} -\author{F Tilmann} - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of latexdiff features. -Type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -or -\begin{verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{verbatim} -to display the markup. - -\section*{Another section title} - -A paragraph with a line only in the draft document. More things could be said -were it not for the constraints of time and space. - -More things could be said were it not for the constraints of time and space. - -And here is a tipo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & Grey \\ -Saruman & White -\end{tabular} - -And sometimes a whole paragraph gets completely rewritten. In this -case latexdiff marks up the whole paragraph even if some words in it -are identical. -No change, no markup! -\end{document} - - diff --git a/latexdiff-1.1.0/example/example-rev.tex b/latexdiff-1.1.0/example/example-rev.tex deleted file mode 100644 index 4bcaf15..0000000 --- a/latexdiff-1.1.0/example/example-rev.tex +++ /dev/null @@ -1,60 +0,0 @@ -\documentclass[12pt,a4paper]{article} - -\setlength{\topmargin}{-0.2in} -\setlength{\textheight}{9.5in} -\setlength{\oddsidemargin}{0.0in} - -\setlength{\textwidth}{6in} - -\title{latexdiff Example - Revised version} -\author{F Tilmann} -% Note how in the preamble visual markup is never used (even -% if some preamble might eventually end up as visible text.) - -\begin{document} -\maketitle - -\section*{Introduction} - -This is an extremely simple document that showcases some of the latexdiff features. -Type -\begin{verbatim} -latexdiff -t UNDERLINE example-draft.tex example-rev.tex > example-diff.tex -\end{verbatim} -to create the difference file. You can inspect this file directly. Then run either -\begin{verbatim} -pdflatex example-diff.tex -xpdf example-diff.pdf -\end{verbatim} -or -\begin{verbatim} -latex example-diff.tex -dvips -o example-diff.ps example-diff.dvi -gv example-diff.ps -\end{verbatim} -to display the markup. - -\section*{Yet another section title} - - More things could be said were it not for the constraints of time and space. - -A paragraph with a line only in the revised document. More things could be -said were it not for the constraints of time and space. - -And here is a typo. - -Here is a table: - -\begin{tabular}{ll} -Name & Description \\ -\hline -Gandalf & White \\ -Saruman & Evil -\end{tabular} - -And now for something completely different, with not a paragraph in sight. -No change, -no markup! -\end{document} - - diff --git a/latexdiff-1.1.0/latexdiff b/latexdiff-1.1.0/latexdiff deleted file mode 100755 index bb75ce4..0000000 --- a/latexdiff-1.1.0/latexdiff +++ /dev/null @@ -1,3824 +0,0 @@ -#!/usr/bin/env perl -##!/usr/bin/perl -w -# latexdiff - differences two latex files on the word level -# and produces a latex file with the differences marked up. -# -# Copyright (C) 2004-12 F J Tilmann (tilmann@gfz-potsdam.de) -# -# Repository/issue tracker: https://github.com/ftilmann/latexdiff -# CTAN page: http://www.ctan.org/tex-archive/support/latexdiff -# -# 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 . -# -# Detailed usage information at the end of the file -# -# ToDo: -# DONE -# -# Version 1.1.0 -# - treat diacritics (\",\', etc) as safe commands -# - treat \_ and \& correctly as safe commands, even if used without spacing to the next word -# - Add a BOLD markup type that sets added text in bold face (Contribution by Victor Zabalza via pull request ) -# - add append-mboxsafecmd list option to be able to specify special safe commands which need to be surrounded by mbox to avoid breaking (mostly this is needed with ulem package) -# - support for siunitx and cleveref packages: protect \SI command in siunitx package and \cref,\Cref{range}{*} in cleveref packages (thanks to Stefan Pinnow for testing) -# - experimental support for chemformula, mhchem packages: define \ch and \ce in packages as safe (but not \ch,\cee in equation array environments) - these unfortunately will not be marked up (thanks to Stefan Pinnow for testing) -# - bug fix: packages identified correctly even if \usepackage command options extend over several lines (previously \usepackage command needed to be fully contained in one line) -# - new subtype ONLYCHANGEDPAGE outputs only changed pages (might not work well for floating material) -# - new subtype ZLABEL operates similarly to LABEL but uses absolute page numbers (needs zref package) -# - undocumented option --debug/--nodebug to override default setting for debug mode (Default: 0 for release version, 1: for development version -# -# Version 1.0.4 -# - introduce list UNSAFEMATHCMD, which holds list of commands which cannot be marked up with \DIFadd or \DIFdel commands (only relevant for WHOLE and COARSE math markup modes) -# - new subtype LABEL which gives each change a label. This can later be used to only display pages where changes -# have been made (instructions for that are put as comments into the diff'ed file) inspired by answer on http://tex.stackexchange.com/questions/166049/invisible-markers-in-pdfs-using-pdflatex -# - Configuration variables take into accout some commands from additional packages: -# tikzpicture environment now treated as PICTUREENV, and \smallmatrix in ARRENV (amsmath) -# - --flatten: support for \subfile command (subfiles package) (in response to http://tex.stackexchange.com/questions/167620/latexdiff-with-subfiles ) -# - --flatten: \bibliography commands expand if corresponding bbl file present -# - angled bracket optional commands now parsed correctly (patch #3570) submitted by Dave Kleinschmidt (thanks) -# - \RequirePackage now treated as synonym of \usepackage with respect to setting packages -# - special rules for apacite package (redefine citation commands) -# - recognise /dev/null as 'file-like' arguments for --preamble and --config options -# - fix units package incompatibility with ulem for text maths statements $ ..$ (thanks to Stuart Prescott for reporting this) -# - amsmath environment cases treated correctly (Bug fix #19029) (thanks to Jalar) -# - {,} in comments no longer confuse latexdiff (Bug fix #19146) -# - \% in one-letter sub/Superscripts was not converted correctly -# -# Version 1.0.3 -# - fix bug in add_safe_commands that made latexdiff hang on DeclareMathOperator -# command in preamble -# - \(..\) inline math expressions were not parsed correctly, if they contained a linebreak -# - applied patch contributed by tomflannaghan via Berlios: [ Patch #3431 ] Adds correct handling of \left< and \right> -# - \$ is treated correctly as a literal dollar sign (thanks to Reed Cartwright and Joshua Miller for reporting this bug -# and sketching out the solution) -# - \^ and \_ are correctly interpreted as accent and underlined space, respectively, not as superscript of subscript -# (thanks to Wail Yahyaoui for pointing out this bug) -# -# Version 1.0.1 - treat \big,\bigg etc. equivalently to \left and -# \right - include starred version in MATHENV - apply -# - flatten recursively and --flatten expansion is now -# aware of comments (thanks to Tim Connors for patch) -# - Change to post-processing for more reliability for -# deleted math environments -# - On linux systems, recognise and remove DOS style newlines -# - Provide markup for some special preamble commands (\title, -# \author,\date, -# - configurable by setting context2cmd -# - for styles using ulem package, remove \emph and \text.. from list of -# safe commands in order to allow linebreaks within the -# highlighted sections. -# - for ulem style, now show citations by enclosing them in \mbox commands. -# This unfortunately implies linebreaks within citations no longer function, -# so this functionality can be turned off (Option --disable-citation-markup). -# With --enable-citation-markup, the mbox markup is forced for other styles) -# - new substyle COLOR. This is particularly useful for marking up citations -# and some special post-processing is implemented to retain cite -# commands in deleted blocks. -# - four different levels of math-markup -# - Option --driver for choosing driver for modes employing changebar package -# - accept \\* as valid command (and other commands of form \.*). Also accept -# \ (backslashed newline) -# - some typo fixes, include commands defined in preamble as safe commands -# (Sebastian Gouezel) -# - include compared filenames as comments as line 2 and 3 of -# the preamble (can be modified with option --label, and suppressed with -# --no-label), option --visible-label to show files in generated pdf or dvi -# at the beginning of main document -# -# Version 0.5 A number of minor improvements based on feedback -# Deleted blocks are now shown before added blocks -# Package specific processing -# -# Version 0.43 unreleased typo in list of styles at the end -# Add protect to all \cbstart, \cbend commands -# More robust substitution of deleted math commands -# -# Version 0.42 November 06 Bug fixes only -# -# Version 0.4 March 06 option for fast differencing using UNIX diff command, several minor bug fixes (\par bug, improved highlighting of textcmds) -# -# Version 0.3 August 05 improved parsing of displayed math, --allow-spaces -# option, several minor bug fixes -# -# Version 0.25 October 04 Fix bug with deleted equations, add math mode commands to safecmd, add | to allowed interpunctuation signs -# Version 0.2 September 04 extension to utf-8 and variable encodings -# Version 0.1 August 04 First public release - -use Algorithm::Diff qw(traverse_sequences); - -use Getopt::Long ; -use strict ; -use warnings; -use utf8 ; - -my ($algodiffversion)=split(/ /,$Algorithm::Diff::VERSION); - - -my ($versionstring)=< 0, - WHOLE => 1, - COARSE => 2, - FINE => 3 -}; - -my ($mboxcmd); - -my (@configlist,@labels, - @appendsafelist,@excludesafelist, - @appendmboxsafelist,@excludemboxsafelist, - @appendtextlist,@excludetextlist, - @appendcontext1list,@appendcontext2list, - @packagelist); -my ($assign,@config); -# Hash where keys corresponds to the names of all included packages (including the documentclass as another package -# the optional arguments to the package are the values of the hash elements -my ($pkg,%packages); -# Defaults -$mathmarkup=COARSE; - -$verbose=0; -# output debug and intermediate files, set to 0 in final distribution -$debug=0; -# insert preamble directly after documentclass - experimental feature, set to 0 in final distribution -# Note that this failed with mini example (or other files, where packages used in latexdiff preamble -# are called again with incompatible options in preamble of resulting file) -$earlylatexdiffpreamble=0; - -# define character properties -sub IsNonAsciiPunct { return <<'END' # Unicode punctuation but excluding ASCII punctuation -+utf8::IsPunct --utf8::IsASCII -END -} -sub IsNonAsciiS { return <<'END' # Unicode symbol but excluding ASCII -+utf8::IsS --utf8::IsASCII -END -} - - -my %verbhash; - -Getopt::Long::Configure('bundling'); -GetOptions('type|t=s' => \$type, - 'subtype|s=s' => \$subtype, - 'floattype|f=s' => \$floattype, - 'config|c=s' => \@configlist, - 'preamble|p=s' => \$preamblefile, - 'encoding|e=s' => \$encoding, - 'label|L=s' => \@labels, - 'no-label' => \$nolabel, - 'visible-label' => \$visiblelabel, - 'exclude-safecmd|A=s' => \@excludesafelist, - 'replace-safecmd=s' => \$replacesafe, - 'append-safecmd|a=s' => \@appendsafelist, - 'exclude-textcmd|X=s' => \@excludetextlist, - 'replace-textcmd=s' => \$replacetext, - 'append-textcmd|x=s' => \@appendtextlist, - 'replace-context1cmd=s' => \$replacecontext1, - 'append-context1cmd=s' => \@appendcontext1list, - 'replace-context2cmd=s' => \$replacecontext2, - 'append-context2cmd=s' => \@appendcontext2list, - 'exclude-mboxsafecmd=s' => \@excludemboxsafelist, - 'append-mboxsafecmd=s' => \@appendmboxsafelist, - 'show-preamble' => \$showpreamble, - 'show-safecmd' => \$showsafe, - 'show-textcmd' => \$showtext, - 'show-config' => \$showconfig, - 'show-all' => \$showall, - 'packages=s' => \@packagelist, - 'allow-spaces' => \$allowspaces, - 'math-markup=s' => \$mathmarkup, - 'enable-citation-markup|enforce-auto-mbox' => \$enablecitmark, - 'disable-citation-markup|disable-auto-mbox' => \$disablecitmark, - 'verbose|V' => \$verbose, - 'ignore-warnings' => \$ignorewarnings, - 'driver=s'=> \$driver, - 'flatten' => \$flatten, - 'version' => \$version, - 'help|h|H' => \$help, - 'debug!' => \$debug ); - -if ( $help ) { - usage() ; -} - - -if ( $version ) { - die $versionstring ; -} - -print STDERR $versionstring if $verbose; - -if (defined($showall)){ - $showpreamble=$showsafe=$showtext=$showconfig=1; -} -# Default types -$type='UNDERLINE' unless defined($type); -$subtype='SAFE' unless defined($subtype); -# set floattype to IDENTICAL for LABEL and ONLYCHANGEDPAGE subtype, unless it has been set explicitly on the command line -$floattype=($subtype eq 'LABEL' || $subtype eq 'ONLYCHANGEDPAGE') ? 'IDENTICAL' : 'FLOATSAFE' unless defined($floattype); -if ( $subtype eq 'LABEL' ) { - print STDERR "Note that LABEL subtype is deprecated. If possible, use ZLABEL instead (requires zref package)"; -} - -if (defined($mathmarkup)) { - $mathmarkup=~tr/a-z/A-Z/; - if ( $mathmarkup eq 'OFF' ){ - $mathmarkup=OFF; - } elsif ( $mathmarkup eq 'WHOLE' ){ - $mathmarkup=WHOLE; - } elsif ( $mathmarkup eq 'COARSE' ){ - $mathmarkup=COARSE; - } elsif ( $mathmarkup eq 'FINE' ){ - $mathmarkup=FINE; - } elsif ( $mathmarkup !~ m/^[0123]$/ ) { - die "Illegal value: ($mathmarkup) for option--math-markup. Possible values: OFF,WHOLE,COARSE,FINE,0- "; - } - # else use numerical value -} - -# setting extra preamble commands -if (defined($preamblefile)) { - $latexdiffpreamble=join "\n",(extrapream($preamblefile),""); -} else { - $latexdiffpreamble=join "\n",(extrapream($type,$subtype,$floattype),""); -} - -if ( defined($driver) ) { - # for changebar only - $latexdiffpreamble=~s/\[dvips\]/[$driver]/sg; -} -# setting up @SAFECMDLIST and @SAFECMDEXCL -if (defined($replacesafe)) { - init_regex_arr_ext(\@SAFECMDLIST,$replacesafe); -} else { - init_regex_arr_data(\@SAFECMDLIST, "SAFE COMMANDS"); -} -foreach $appendsafe ( @appendsafelist ) { - init_regex_arr_ext(\@SAFECMDLIST, $appendsafe); -} -foreach $excludesafe ( @excludesafelist ) { - init_regex_arr_ext(\@SAFECMDEXCL, $excludesafe); -} -# setting up @MBOXCMDLIST and @MBOXCMDEXCL -foreach $mboxsafe ( @appendmboxsafelist ) { - init_regex_arr_ext(\@MBOXCMDLIST, $mboxsafe); -} -foreach $mboxsafe ( @excludemboxsafelist ) { - init_regex_arr_ext(\@MBOXCMDEXCL, $mboxsafe); -} - - - -# setting up @TEXTCMDLIST and @TEXTCMDEXCL -if (defined($replacetext)) { - init_regex_arr_ext(\@TEXTCMDLIST,$replacetext); -} else { - init_regex_arr_data(\@TEXTCMDLIST, "TEXT COMMANDS"); -} -foreach $appendtext ( @appendtextlist ) { - init_regex_arr_ext(\@TEXTCMDLIST, $appendtext); -} -foreach $excludetext ( @excludetextlist ) { - init_regex_arr_ext(\@TEXTCMDEXCL, $excludetext); -} - - -# setting up @CONTEXT1CMDLIST ( @CONTEXT1CMDEXCL exist but is always empty ) -if (defined($replacecontext1)) { - init_regex_arr_ext(\@CONTEXT1CMDLIST,$replacecontext1); -} else { - init_regex_arr_data(\@CONTEXT1CMDLIST, "CONTEXT1 COMMANDS"); -} -foreach $appendcontext1 ( @appendcontext1list ) { - init_regex_arr_ext(\@CONTEXT1CMDLIST, $appendcontext1); -} - - -# setting up @CONTEXT2CMDLIST ( @CONTEXT2CMDEXCL exist but is always empty ) -if (defined($replacecontext2)) { - init_regex_arr_ext(\@CONTEXT2CMDLIST,$replacecontext2); -} else { - init_regex_arr_data(\@CONTEXT2CMDLIST, "CONTEXT2 COMMANDS"); -} -foreach $appendcontext2 ( @appendcontext2list ) { - init_regex_arr_ext(\@CONTEXT2CMDLIST, $appendcontext2); -} - -# setting configuration variables -@config=(); -foreach $config ( @configlist ) { - if (-f $config || lc $config eq '/dev/null' ) { - open(FILE,$config) or die ("Couldn't open configuration file $config: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@config,$_); - } - close(FILE); - } - else { -# foreach ( split(",",$config) ) { -# push @config,$_; -# } - push @config,split(",",$config) - } -} -foreach $assign ( @config ) { - $assign=~ m/\s*(\w*)\s*=\s*(\S*)\s*$/ or die "Illegal assignment $assign in configuration list (must be variable=value)"; - if ( $1 eq "MINWORDSBLOCK" ) { $MINWORDSBLOCK = $2; } - elsif ( $1 eq "FLOATENV" ) { $FLOATENV = $2 ; } - elsif ( $1 eq "PICTUREENV" ) { $PICTUREENV = $2 ; } - elsif ( $1 eq "MATHENV" ) { $MATHENV = $2 ; } - elsif ( $1 eq "MATHREPL" ) { $MATHREPL = $2 ; } - elsif ( $1 eq "MATHARRENV" ) { $MATHARRENV = $2 ; } - elsif ( $1 eq "MATHARRREPL" ) { $MATHARRREPL = $2 ; } - elsif ( $1 eq "ARRENV" ) { $ARRENV = $2 ; } - elsif ( $1 eq "COUNTERCMD" ) { $COUNTERCMD = $2 ; } - else { die "Unknown variable $1 in assignment.";} -} - -if ( $mathmarkup == COARSE || $mathmarkup == WHOLE ) { - push(@MATHTEXTCMDLIST,qr/^MATHBLOCK(?:$MATHENV|$MATHARRENV|SQUAREBRACKET)$/); -} - - - -foreach $pkg ( @packagelist ) { - map { $packages{$_}="" } split(/,/,$pkg) ; -} - -if ($showpreamble) { - print "\nPreamble commands:\n"; - print $latexdiffpreamble ; -} - -if ($showsafe) { - print "\nCommands safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE (unless excluded):\n"; - print_regex_arr(@SAFECMDLIST); - print "\nCommands not safe within scope of $ADDOPEN $ADDCLOSE and $DELOPEN $DELCLOSE :\n"; - print_regex_arr(@SAFECMDEXCL); -} - -if ($showtext) { - print "\nCommands with last argument textual (unless excluded) and safe in every context:\n"; - print_regex_arr(@TEXTCMDLIST); - print "\nContext1 commands (last argument textual, command will be disabled in deleted passages, last argument will be shown as plain text):\n"; - print_regex_arr(@CONTEXT1CMDLIST); - print "\nContext2 commands (last argument textual, command and its argument will be disabled in deleted passages):\n"; - print_regex_arr(@CONTEXT2CMDLIST); - print "\nExclude list of Commands with last argument not textual (overrides patterns above):\n"; - print_regex_arr(@TEXTCMDEXCL); -} - - -if ($showconfig) { - print "Configuration variables:\n"; - print "MINWORDSBLOCK=$MINWORDSBLOCK\n"; - print "FLOATENV=$FLOATENV\n"; - print "PICTUREENV=$PICTUREENV\n"; - print "MATHENV=$MATHENV\n"; - print "MATHREPL=$MATHREPL\n"; - print "MATHARRENV=$MATHARRENV\n"; - print "MATHARRREPL=$MATHARRREPL\n"; - print "ARRENV=$ARRENV\n"; - print "COUNTERCMD=$COUNTERCMD\n"; -} -if ($showconfig || $showtext || $showsafe || $showpreamble) { - exit 0; } -if ( @ARGV != 2 ) { - print STDERR "2 and only 2 non-option arguments required. Write latexdiff -h to get help\n"; - exit(2); -} - -# Are extra spaces between command arguments permissible? -my $extraspace; -if ($allowspaces) { - $extraspace='\s*'; -} else { - $extraspace=''; -} - -# append context lists to text lists (as text property is implied) -push @TEXTCMDLIST, @CONTEXT1CMDLIST; -push @TEXTCMDLIST, @CONTEXT2CMDLIST; - -push @TEXTCMDLIST, @MATHTEXTCMDLIST if $mathmarkup==COARSE; - -# internal additions to SAFECMDLIST -push(@SAFECMDLIST, qr/^QLEFTBRACE$/, qr/^QRIGHTBRACE$/); - - -# Patterns. These are used by some of the subroutines, too -# I can only define them down here because value of extraspace depends on an option - my $pat0 = '(?:[^{}])*'; - my $pat1 = '(?:[^{}]|\{'.$pat0.'\})*'; - my $pat2 = '(?:[^{}]|\{'.$pat1.'\})*'; - my $pat3 = '(?:[^{}]|\{'.$pat2.'\})*'; - my $pat4 = '(?:[^{}]|\{'.$pat3.'\})*'; - my $pat5 = '(?:[^{}]|\{'.$pat4.'\})*'; - my $pat6 = '(?:[^{}]|\{'.$pat5.'\})*'; - my $brat0 = '(?:[^\[\]]|\\\[|\\\])*'; - my $abrat0 = '(?:[^<>])*'; - - my $quotemarks = '(?:\'\')|(?:\`\`)'; - my $punct='[0.,\/\'\`:;\"\?\(\)\[\]!~\p{IsNonAsciiPunct}\p{IsNonAsciiS}]'; - my $number='-?\d*\.\d*'; - my $mathpunct='[+=<>\-\|]'; - my $and = '&'; - my $coords= '[\-.,\s\d]*'; -# quoted underscore - this needs special treatment as perl treats _ as a letter (\w) but latex does not -# such that a\_b is interpreted as a{\_}b by latex but a{\_b} by perl - my $quotedunderscore='\\\\_'; -# word: sequence of letters or accents followed by letter - my $word='(?:[-\w\d*]|\\\\[\"\'\`~^][A-Za-z\*])+'; - my $cmdleftright='\\\\(?:left|right|[Bb]igg?[lrm]?|middle)\s*(?:[<>()\[\]|]|\\\\(?:[|{}]|\w+))'; - my $cmdoptseq='\\\\[\w\d\*]+'.$extraspace.'(?:(?:<'.$abrat0.'>|\['.$brat0.'\]|\{'. $pat6 . '\}|\(' . $coords .'\))'.$extraspace.')*'; - my $backslashnl='\\\\\n'; - my $oneletcmd='\\\\.\*?(?:\['.$brat0.'\]|\{'. $pat6 . '\})*'; - my $math='\$(?:[^$]|\\\$)*?\$|\\\\[(](?:.|\n)*?\\\\[)]'; -## the current maths command cannot cope with newline within the math expression - my $comment='%.*?\n'; - my $pat=qr/(?:\A\s*)?(?:${and}|${quotemarks}|${number}|${word}|$quotedunderscore|$cmdleftright|${cmdoptseq}|${math}|${backslashnl}|${oneletcmd}|${comment}|${punct}|${mathpunct}|\{|\})\s*/ ; - -# now we are done setting up and can start working -my ($oldfile, $newfile) = @ARGV; -# check for existence of input files -if ( ! -e $oldfile ) { - die "Input file $oldfile does not exist."; -} -if ( ! -e $newfile ) { - die "Input file $newfile does not exist."; -} - - -# set the labels to be included into the file -my ($oldtime,$newtime,$oldlabel,$newlabel); -if (defined($labels[0])) { - $oldlabel=$labels[0] ; -} else { - $oldtime=localtime((stat($oldfile))[9]); - $oldlabel="$oldfile " . " "x(length($newfile)-length($oldfile)) . $oldtime; -} -if (defined($labels[1])) { - $newlabel=$labels[1] ; -} else { - $newtime=localtime((stat($newfile))[9]); - $newlabel="$newfile " . " "x(length($oldfile)-length($newfile)) . $newtime; -} - -$encoding=guess_encoding($newfile) unless defined($encoding); - -$encoding = "utf8" if $encoding =~ m/^utf8/i ; -if (lc($encoding) eq "utf8" ) { - binmode(STDOUT, ":utf8"); - binmode(STDERR, ":utf8"); -} - -$old=read_file_with_encoding($oldfile,$encoding); -$new=read_file_with_encoding($newfile,$encoding); - - - - -# reset time -exetime(1); -($oldpreamble,$oldbody,$oldpost)=splitdoc($old,'\\\\begin\{document\}','\\\\end\{document\}'); - - -($newpreamble,$newbody,$newpost)=splitdoc($new,'\\\\begin\{document\}','\\\\end\{document\}'); - - -if ($flatten) { - $oldbody=flatten($oldbody,$oldpreamble,$oldfile,$encoding); - $newbody=flatten($newbody,$newpreamble,$newfile,$encoding); -} - - - - -my @auxlines; - -# boolean variab -my ($ulem)=0; - -if ( length $oldpreamble && length $newpreamble ) { - # pre-process preamble by looking for commands used in \maketitle (title, author, date etc commands) - # and marking up content with latexdiff markup - @auxlines=preprocess_preamble($oldpreamble,$newpreamble); - - @oldpreamble = split /\n/, $oldpreamble; - @newpreamble = split /\n/, $newpreamble; - - # If a command is defined in the preamble of the new file, and only uses safe commands, then it can be considered to be safe) (contribution S. Gouezel) - # Base this assessment on the new preamble - add_safe_commands($newpreamble); - - # get a list of packages from preamble if not predefine - %packages=list_packages($newpreamble) unless %packages; - if ( %packages && $debug ) { my $key ; foreach $key (keys %packages) { print STDERR "DEBUG \\usepackage[",$packages{$key},"]{",$key,"}\n" ;} } - - if (defined $packages{"hyperref"} ) { - # deleted lines should not generate or appear in link names: - print STDERR "hyperref package detected.\n" if $verbose ; - $latexdiffpreamble =~ s/\{\\DIFadd\}/{\\DIFaddtex}/g; - $latexdiffpreamble =~ s/\{\\DIFdel\}/{\\DIFdeltex}/g; - $latexdiffpreamble .= join "\n",(extrapream("HYPERREF"),""); - ### $latexdiffpreamble .= '%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF FOR HYPERREF PACKAGE' . "\n"; - ### $latexdiffpreamble .= '\providecommand{\DIFadd}[1]{\texorpdfstring{\DIFaddtex{#1}}{#1}}' . "\n"; - ### $latexdiffpreamble .= '\providecommand{\DIFdel}[1]{\texorpdfstring{\DIFdeltex{#1}}{}}' . "\n"; - ### $latexdiffpreamble .= '%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF FOR HYPERREF PACKAGE' . "\n"; - } - - print STDERR "Differencing preamble.\n" if $verbose; - - # insert dummy first line such that line count begins with line 1 (rather than perl's line 0) - just so that line numbers inserted by linediff are correct - unshift @newpreamble,''; - unshift @oldpreamble,''; - @diffpreamble = linediff(\@oldpreamble, \@newpreamble); - # remove dummy line again - shift @diffpreamble; - # add filenames, modification time and latexdiff mark - defined($nolabel) or splice @diffpreamble,1,0, - "%DIF LATEXDIFF DIFFERENCE FILE", - ,"%DIF DEL $oldlabel", - "%DIF ADD $newlabel"; - if ( @auxlines ) { - push @diffpreamble,"%DIF DELETED TITLE COMMANDS FOR MARKUP"; - push @diffpreamble,join("\n",@auxlines); - } - if ( $earlylatexdiffpreamble) { - # insert latexdiff command directly after documentclass at beginning of preamble - # note that grep is only run for its side effect - ( grep { s/^([^%]*\\documentclass.*)$/$1$latexdiffpreamble/ } @diffpreamble )==1 or die "Could not find documentclass statement in preamble"; - } else { - # insert latexdiff commands at the end of preamble (default behaviour) - push @diffpreamble,$latexdiffpreamble; - } - push @diffpreamble,'\begin{document}'; -} -elsif ( !length $oldpreamble && !length $newpreamble ) { - @diffpreamble=(); -} else { - print STDERR "Either both texts must have preamble or neither text must have the preamble.\n"; - exit(2); -} - -# Special: treat all cite commands as safe except in UNDERLINE and FONTSTRIKE mode -# (there is a conflict between citation and ulem package, see -# package documentation) -# Use post-processing -# and $packages{"apacite"}!~/natbibpapa/ - -$ulem = ($latexdiffpreamble =~ /\\RequirePackage(?:\[$brat0\])?\{ulem\}/ || defined $packages{"ulem"}); - - -if (defined $packages{"units"} && $ulem ) { - # protect inlined maths environments by surrounding with an \mbox - # this is done to get around an incompatibility between the ulem and units package - # where spaces in the argument to underlined or crossed-out \unit commands cause an error message - print STDERR "units package detected at the same time as style using ulem.\n" if $verbose ; - $MBOXINLINEMATH=1; -} - -if (defined $packages{"siunitx"} ) { - # protect SI command by surrounding them with an \mbox - # this is done to get around an incompatibility between the ulem and siunitx package - print STDERR "siunitx package detected.\n" if $verbose ; - my $mboxcmds='SI,ang,numlist,numrange,SIlist,SIrange'; - init_regex_arr_ext(\@SAFECMDLIST,'num,si'); - if ( $enablecitmark || ( $ulem && ! $disablecitmark )) { - init_regex_arr_ext(\@MBOXCMDLIST,$mboxcmds); - } else { - init_regex_arr_ext(\@SAFECMDLIST,$mboxcmds); - } -} - -if (defined $packages{"cleveref"} ) { - # protect selected command by surrounding them with an \mbox - # this is done to get around an incompatibility between ulem and cleveref package - print STDERR "cleveref package detected.\n" if $verbose ; - my $mboxcmds='[Cc]ref(?:range)?\*?,labelcref,(?:lc)?name[cC]refs?' ; - if ( $enablecitmark || ( $ulem && ! $disablecitmark )) { - init_regex_arr_ext(\@MBOXCMDLIST,$mboxcmds); - } else { - init_regex_arr_ext(\@SAFECMDLIST,$mboxcmds); - } -} - -if (defined $packages{"glossaries"} ) { - # protect selected command by surrounding them with an \mbox - # this is done to get around an incompatibility between ulem and glossaries package - print STDERR "glossaries package detected.\n" if $verbose ; - my $mboxcmds='[gG][lL][sS](?:|pl|disp|link|first|firstplural|desc|user[iv][iv]?[iv]?),[aA][cC][rR](?:long|longpl|full|fullpl),[aA][cC][lfp]?[lfp]?'; - init_regex_arr_ext(\@SAFECMDLIST,'[gG][lL][sS](?:(?:entry)?(?:text|plural|name|symbol)|displaynumberlist|entryfirst|entryfirstplural|entrydesc|entrydescplural|entrysymbolplural|entryuser[iv][iv]?[iv]?|entrynumberlist|entrydisplaynumberlist|entrylong|entrylongpl|entryshort|entryshortpl|entryfull|entryfullpl),[gG]lossentry(?:name|desc|symbol),[aA][cC][rR](?:short|shortpl),[aA]csp?'); - if ( $enablecitmark || ( $ulem && ! $disablecitmark )) { - init_regex_arr_ext(\@MBOXCMDLIST,$mboxcmds); - } else { - init_regex_arr_ext(\@SAFECMDLIST,$mboxcmds); - } -} - -if (defined $packages{"chemformula"} ) { - print STDERR "chemformula package detected.\n" if $verbose ; - init_regex_arr_ext(\@SAFECMDLIST,'ch'); - push(@UNSAFEMATHCMD,'ch'); - # The next command would be needed to allow highlighting the interior of \ch commands in math environments - # but the redefinitions in chemformula are too deep to make this viable - # push(@MATHTEXTCMDLIST,'ch'); -} - -if (defined $packages{"mhchem"} ) { - print STDERR "mhchem package detected.\n" if $verbose ; - init_regex_arr_ext(\@SAFECMDLIST,'ce'); - push(@UNSAFEMATHCMD,'cee'); - # The next command would be needed to allow highlighting the interior of \cee commands in math environments - # but the redefinitions in chemformula are too deep to make this viable - # push(@MATHTEXTCMDLIST,'cee'); -} - - -my ( $citpat); - -if ( defined $packages{"apacite"} ) { - print STDERR "apacite package detected.\n" if $verbose ; - $citpat='(?:mask)?(?:full|short|no)?cite(?:A|author|year|meta)?(?:NP)?'; -} else { - # citation command pattern for all other citation schemes - $citpat='(?:cite\w*|nocite)'; -}; - -if ( ! $ulem ) { - # modes not using ulem: citation is safe - push (@SAFECMDLIST, $citpat); -} else { - ### Experimental: disable text and emph commands - push(@SAFECMDEXCL, qr/^emph$/, qr/^text..$/); - # replace \cite{..} by \mbox{\cite{..}} in added or deleted blocks in post-processing - push(@MBOXCMDLIST,$citpat) unless $disablecitmark; - if ( uc($subtype) eq "COLOR" or uc($subtype) eq "DVIPSCOL" ) { - # remove \cite command again from list of safe commands - pop @MBOXCMDLIST; - # deleted cite commands - } -} -push(@MBOXCMDLIST,$citpat) if $enablecitmark ; - - -if (defined $packages{"amsmath"} or defined $packages{"amsart"} or defined $packages{"amsbook"} ) { - print STDERR "amsmath package detected.\n" if $verbose ; - $MATHARRREPL='align*'; -} - -# add commands in MBOXCMDLIST to SAFECMDLIST -foreach $mboxcmd ( @MBOXCMDLIST ) { - init_regex_arr_ext(\@SAFECMDLIST, $mboxcmd); -} - - - -print STDERR "Preprocessing body. " if $verbose; -preprocess($oldbody,$newbody); - - -# run difference algorithm -@diffbody=bodydiff($oldbody, $newbody); -$diffbo=join("",@diffbody); -if ( $debug ) { - open(RAWDIFF,">","latexdiff.debug.bodydiff"); - print RAWDIFF $diffbo; - close(RAWDIFF); -} -print STDERR "(",exetime()," s)\n","Postprocessing body. \n " if $verbose; -postprocess($diffbo); -$diffall =join("\n",@diffpreamble) ; -# add visible labels -if (defined($visiblelabel)) { - # Give information right after \begin{document} (or at the beginning of the text for files without preamble - ### if \date command is used, add information to \date argument, otherwise give right after \begin{document} - ### $diffall=~s/(\\date$extraspace(?:\[$brat0\])?$extraspace)\{($pat6)\}/$1\{$2 \\ LATEXDIFF comparison \\ Old: $oldlabel \\ New: $newlabel \}/ or - $diffbo = "\\begin{verbatim}LATEXDIFF comparison\nOld: $oldlabel\nNew: $newlabel\\end{verbatim}\n$diffbo" ; -} - -$diffall .= "$diffbo" ; -$diffall .= "\\end{document}$newpost" if length $newpreamble ; -if ( lc($encoding) ne "utf8" && lc($encoding) ne "ascii" ) { - print STDERR "Encoding output file to $encoding\n" if $verbose; - $diffall=Encode::encode($encoding,$diffall); - binmode STDOUT; -} -print $diffall; - - -print STDERR "(",exetime()," s)\n","Done.\n" if $verbose; - - - -## guess_encoding(filename) -## reads the first 20 lines of filename and looks for call of inputenc package -## if found, return the option of this package (encoding), otherwise return ascii -sub guess_encoding { - my ($filename)=@_; - my ($i,$enc); - open (FH, $filename) or die("Couldn't open $filename: $!"); - $i=0; - while () { - next if /^\s*%/; # skip comment lines - if (m/\\usepackage\[(\w*?)\]\{inputenc\}/) { - close(FH); - return($1); - } - last if (++$i > 20 ); # scan at most 20 non-comment lines - } - close(FH); - return("ascii"); -} - - -sub read_file_with_encoding { - my ($output); - my ($filename, $encoding) = @_; - - if (lc($encoding) eq "utf8" ) { - open (FILE, "<:utf8",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } elsif ( lc($encoding) eq "ascii") { - open (FILE, $filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - } else { - require Encode; - open (FILE, "<",$filename) or die("Couldn't open $filename: $!"); - local $/ ; # locally set record operator to undefined, ie. enable whole-file mode - $output=; - print STDERR "Converting $filename from $encoding to utf8\n" if $verbose; - $output=Encode::decode($encoding,$output); - } - close FILE; - if ($^O eq "linux" ) { - $output =~ s/\r\n/\n/g ; - } - return $output; -} - -## %packages=list_packages(@preamble) -## scans the arguments for \documentclass,\RequirePackage and \usepackage statements and constructs a hash -## whose keys are the included packages, and whose values are the associated optional arguments -#sub list_packages { -# my (@preamble)=@_; -# my %packages=(); -# foreach $line ( @preamble ) { -# # get rid of comments -# $line=~s/(?catfile($dirname,$fname), "\n" if $debug; - # content of file becomes replacement value (use recursion), add \newpage if the command was include - ###$replacement=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - $replacement=flatten(read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding), $preamble,$filename,$encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - # \include always starts a new page; use explicit \newpage command to simulate this - $newpage=(defined($3)? " \\newpage " : "") ; - "$begline$newpage$replacement$newpage"; - }/exgm; - # replace bibliography with bbl file if it exists - $text=~s/(^(?:[^%\n]|\\%)*)\\bibliography{(.*?)}/{ - if ( -f $bblfile ){ - $replacement=read_file_with_encoding(File::Spec->catfile($bblfile), $encoding); - } else { - warn "Bibliography file $bblfile cannot be found. No flattening of \\bibliography done. Run bibtex on old and new files first"; - $replacement="\\bibliography{$2}"; - } - $begline=(defined($1)? $1 : "") ; - "$begline$replacement"; - }/exgm; - # replace subfile with contents (subfile package) - $text=~s/(^(?:[^%\n]|\\%)*)\\subfile{(.*?)}/{ - $begline=(defined($1)? $1 : "") ; - $fname = $2; - # # add tex extension unless there is a three letter extension already - $fname .= ".tex" unless $fname =~ m|\.\w{3}|; - print STDERR "Include file as subfile $fname\n" if $verbose; - # content of file becomes replacement value (use recursion) - # now strip away everything outside and including \begin{document} and \end{document} pair# - # # note: no checking for comments is made - $subfile=read_file_with_encoding(File::Spec->catfile($dirname,$fname), $encoding) or die "Couldn't find file ",File::Spec->catfile($dirname,$fname),": $!"; - ($subpreamble,$subbody,$subpost)=splitdoc($subfile,'\\\\begin\{document\}','\\\\end\{document\}'); - $replacement=flatten($subbody, $preamble,$filename,$encoding); - "$begline$replacement"; - }/exgm; - - return($text); -} - - -# print_regex_arr(@arr) -# prints regex array without x-ism expansion put in by pearl to stdout -sub print_regex_arr { - my $dumstring; - $dumstring = join(" ",@_); # PERL generates string (?-xism:^ref$) for quoted refex ^ref$ - $dumstring =~ s/\(\?-xism:\^(.*?)\$\)/$1/g; # remove string and ^,$ marks before output - print $dumstring,"\n"; -} - - -# @lines=extrapream($type) -# reads line from appendix (end of file after __END__ token) -sub extrapream { - my $type; - my @retval=("%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - my ($copy); - - while (@_) { - $copy=0; - $type=shift ; - if ( -f $type || lc $type eq '/dev/null' ) { - open (FILE,$type) or die "Cannot open preamble file $type: $!"; - print STDERR "Reading preamble file $type\n" if $verbose ; - while () { - chomp ; - if ( $_ =~ m/%DIF PREAMBLE/ ) { - push (@retval,"$_"); - } else { - push (@retval,"$_ %DIF PREAMBLE"); - } - } - } - else { # not (-f $type) - $type=uc($type); # upcase argument - print STDERR "Preamble Internal Type $type\n" if $verbose; - while () { - if ( m/^%DIF $type/ ) { - $copy=1; } - elsif ( m/^%DIF END $type/ ) { - last; } - chomp; - push (@retval,"$_ %DIF PREAMBLE") if $copy; - } - if ( $copy == 0 ) { - print STDERR "\nPreamble style $type not implemented.\n"; - print STDERR "Write latexdiff -h to get help with available styles\n"; - exit(2); - } - seek DATA,0,0; # rewind DATA handle to file begin - } - } - push (@retval,"%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF") ; - return @retval; -} - - -# ($part1,$part2,$part3)=splitdoc($text,$word1,$word2) -# splits $text into 3 parts at $word1 and $word2. -# if neither $word1 nor $word2 exist, $part1 and $part3 are empty, $part2 is $text -# If only $word1 or $word2 exist but not the other, output an error message. - -# NB this version avoids $` and $' for performance reason although it only makes a tiny difference -# (in one test gain a tenth of a second for a 30s run) -sub splitdoc { - my ($text,$word1,$word2)=@_; - my ($part1,$part2,$part3)=("","",""); - my ($rest,$pos); - - if ( $text =~ m/(^[^%]*)($word1)/mg ) { - $pos=pos $text; - $part1=substr($text,0,$pos-length($2)); - $rest=substr($text,$pos); - if ( $rest =~ m/(^[^%]*)($word2)/mg ) { - $pos=pos $rest; - $part2=substr($rest,0,$pos-length($2)); - $part3=substr($rest,$pos); - } - else { - die "$word1 and $word2 not in the correct order or not present as a pair." ; - } - } else { - $part2=$text; - die "$word2 present but not $word1." if ( $text =~ m/(^[^%]*)$word2/ms ); - } - return ($part1,$part2,$part3); -} - - - - - -# bodydiff($old,$new) -sub bodydiff { - my ($oldwords, $newwords) = @_; - my @retwords; - - print STDERR "(",exetime()," s)\n","Splitting into latex tokens \n" if $verbose; - print STDERR "Parsing $oldfile \n" if $verbose; - my @oldwords = splitlatex($oldwords); - print STDERR "Parsing $newfile \n" if $verbose; - my @newwords = splitlatex($newwords); - - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - print STDERR "(",exetime()," s)\n","Pass 1: Expanding text commands and merging isolated identities with changed blocks " if $verbose; - pass1(\@oldwords, \@newwords); - - - print STDERR "(",exetime()," s)\n","Pass 2: inserting DIF tokens and mark up. " if $verbose; - if ( $debug ) { - open(TOKENOLD,">","latexdiff.debug.tokenold2"); - print TOKENOLD join("***\n",@oldwords); - close(TOKENOLD); - open(TOKENNEW,">","latexdiff.debug.tokennew2"); - print TOKENNEW join("***\n",@newwords); - close(TOKENNEW); - } - - @retwords=pass2(\@oldwords, \@newwords); - - return(@retwords); -} - - - - -# @words=splitlatex($string) -# split string according to latex rules -# Each element of words is either -# a word (including trailing spaces and punctuation) -# a latex command -# if there is white space in the beginning return that as first token -sub splitlatex { - my ($inputstring) = @_ ; - my $string=$inputstring ; - # if input is empty, return empty list - length($string)>0 or return (); - $string=~s/^(\s*)//s; - my $leadin=$1; - length($string)>0 or return ($leadin); - - my @retval=($string =~ m/$pat/osg); - - if (length($string) != length(join("",@retval))) { - print STDERR "\nWARNING: Inconsistency in length of input string and parsed string:\n This often indicates faulty or non-standard latex code.\n In many cases you can ignore this and the following warning messages.\n Note that character numbers in the following are counted beginning after \\begin{document} and are only approximate." unless $ignorewarnings; - print STDERR "DEBUG Original length ",length($string)," Parsed length ",length(join("",@retval)),"\n" if $debug; - print STDERR "DEBUG Input string: |$string|\n" if (length($string)<500) && $debug; - print STDERR "DEBUG Token parsing: |",join("+",@retval),"|\n" if (length($string)<500) && $debug ; - @retval=(); - # slow way only do this if other m//sg method fails - my $last = 0; - while ( $string =~ m/$pat/osg ) { - my $match=$&; - if ($last + length $& != pos $string ) { - my $pos=pos($string); - my $offset=30<$last ? 30 : $last; - my $dum=substr($string,$last-$offset,$pos-$last+2*$offset); - my $dum1=$dum; - my $cnt=$#retval; - my $i; - $dum1 =~ s/\n/ /g; - unless ($ignorewarnings) { - print STDERR "\n$dum1\n"; - print STDERR " " x 30,"^" x ($pos-$last)," " x 30,"\n"; - print STDERR "Missing characters near word " . (scalar @retval) . " character index: " . $last . "-" . pos($string) . " Length: " . length($match) . " Match: |$match| (expected match marked above).\n"; - } - # put in missing characters `by hand' - push (@retval, substr($dum,$offset,$pos-$last-length($match))); -# Note: there seems to be a bug in substr with utf8 that made the following line output substr which were too long, -# using dum instead appears to work -# push (@retval, substr($string,$last, pos($string)-$last-length($match))); - } - push (@retval, $match); - $last=pos $string; - } - - } - unshift(@retval,$leadin) if (length($leadin)>0); - return @retval; -} - - -# pass1( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Where an common-subsequence block is flanked by deleted or appended blocks, -# and is shorter than $MINWORDSBLOCK words it is appended -# to the last deleted or appended word. If the block contains tokens other than words -# or punctuation it is not merged. -# Deleted or appended block consisting of words and safe commands only are -# also merged, to prevent break-up in pass2 (after previous isolated words have been removed) -# If there are commands with textual arguments (e.g. \caption) both in corresponding -# appended and deleted blocks split them such that the command and opening bracket -# are one token, then the rest is split up following standard rules, and the closing -# bracket is a separate token, ie. turn -# "\caption{This is a textual argument}" into -# ("\caption{","This ","is ","a ","textual ","argument","}") -# No return value. Destructively changes sequences -sub pass1 { - my $seq1 = shift ; - my $seq2 = shift ; - - my $len1 = scalar @$seq1; - my $len2 = scalar @$seq2; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - - my ($last1,$last2)=(-1,-1) ; - my $cnt=0; - my $block=[]; - my $addblock=[]; - my $delblock=[]; - my $todo=[]; - my $instruction=[]; - my $i; - my (@delmid,@addmid,@dummy); - - my ($addcmds,$delcmds,$matchindex); - my ($addtextblocks,$deltextblocks); - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $adddiscard = sub { - if ($cnt > 0 ) { - $matblkcnt++; - # just after an unchanged block -# print STDERR "Unchanged block $cnt, $last1,$last2 \n"; - if ($cnt < $MINWORDSBLOCK - && $cnt==scalar ( - grep { /^$wpat/ || ( /^\\((?:[`'^"~=.]|[\w\d@*]+))((?:\[$brat0\]|\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && scalar(@dummy=split(" ",$2))<3 ) } - @$block) ) { - # merge identical blocks shorter than $MINWORDSBLOCK - # and only containing ordinary words - # with preceding different word - # We cannot carry out this merging immediately as this - # would change the index numbers of seq1 and seq2 and confuse - # the algorithm, instead we store in @$todo where we have to merge - push(@$todo, [ $last1,$last2,$cnt,@$block ]); - } - $block = []; - $cnt=0; $last1=-1; $last2=-1; - } - }; - my $discard=sub { $deltokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$delblock,[ $seq1->[$_[0]],$_[0] ]); - $last1=$_[0] }; - - my $add = sub { $addtokcnt++; - &$adddiscard; #($_[0],$_[1]); - push(@$addblock,[ $seq2->[$_[1]],$_[1] ]); - $last2=$_[1] }; - - my $match = sub { $mattokcnt++; - if ($cnt==0) { # first word of matching sequence after changed sequence or at beginning of word sequence - $deltextblocks = extracttextblocks($delblock); - $delblkcnt++ if scalar @$delblock; - $addtextblocks = extracttextblocks($addblock); - $addblkcnt++ if scalar @$addblock; - - $delcmds = extractcommands($delblock); - $addcmds = extractcommands($addblock); - # keygen(third argument of _longestCommonSubsequence) implies to sort on command (0th elements of $addcmd elements) - # the calling format for longestCommonSubsequence has changed between versions of - # Algorithm::Diff so we need to check which one we are using - if ( $algodiffversion > 1.15 ) { - ### Algorithm::Diff 1.19 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, 0, sub { $_[0]->[0] } ); - } else { - ### Algorithm::Diff 1.15 - $matchindex=Algorithm::Diff::_longestCommonSubsequence($delcmds,$addcmds, sub { $_[0]->[0] } ); - } - - for ($i=0 ; $i<=$#$matchindex ; $i++) { - if (defined($matchindex->[$i])){ - $j=$matchindex->[$i]; - @delmid=splitlatex($delcmds->[$i][3]); - @addmid=splitlatex($addcmds->[$j][3]); - while (scalar(@$deltextblocks) && $deltextblocks->[0][0]<$delcmds->[$i][1]) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) }; - push(@$todo, [$index,-1,$cnt,@$block]); - } - push(@$todo, [ $delcmds->[$i][1],-1,-1,$delcmds->[$i][2],@delmid,$delcmds->[$i][4]]); - - while (scalar(@$addtextblocks) && $addtextblocks->[0][0]<$addcmds->[$j][1]) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - push(@$todo, [ -1,$addcmds->[$j][1],-1,$addcmds->[$j][2],@addmid,$addcmds->[$j][4]]); - } - } - # mop up remaining textblocks - while (scalar(@$deltextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$deltextblocks) } ; - push(@$todo, [$index,-1,$cnt,@$block]); - } - while (scalar(@$addtextblocks)) { - my ($index,$block,$cnt)=@{ shift(@$addtextblocks) }; - push(@$todo, [-1,$index,$cnt,@$block]); - } - - $addblock=[]; - $delblock=[]; - } - push(@$block,$seq2->[$_[1]]); - $cnt++ }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - - - # now carry out the merging/splitting. Refer to elements relative from - # the end (with negative indices) as these offsets don't change before the instruction is executed - # cnt>0: merged small unchanged groups with previous changed blocks - # cnt==-1: split textual commands into components - foreach $instruction ( @$todo) { - ($last1,$last2,$cnt,@$block)=@$instruction ; - if ($cnt>=0) { - splice(@$seq1,$last1-$len1,1+$cnt,join("",$seq1->[$last1-$len1],@$block)) if $last1>=0; - splice(@$seq2,$last2-$len2,1+$cnt,join("",$seq2->[$last2-$len2],@$block)) if $last2>=0; - } else { - splice(@$seq1,$last1-$len1,1,@$block) if $last1>=0; - splice(@$seq2,$last2-$len2,1,@$block) if $last2>=0; - } - } - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens in $matblkcnt blocks.\n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } -} - - -# extracttextblocks(\@blockindex) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [[ $index, $textblock, $cnt ], .. -# where $index index of block to be merged -# $textblock contains all the words to be merged with the word at $index (but does not contain this word) -# $cnt is length of block -# -# requires: iscmd -# -sub extracttextblocks { - my $block=shift; - my ($i,$token,$index); - my $textblock=[]; - my $last=-1; - my $wpat=qr/^(?:[a-zA-Z.,'`:;?()!]*)[\s~]*$/; #' - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # store pure text blocks - if ($token =~ /$wpat/ || ( $token =~/^\\((?:[`'^"~=.]|[\w\d@\*]+))((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*)/o - && iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL) - && !iscmd($1,\@TEXTCMDLIST,\@TEXTCMDEXCL))) { - # we have text or a command which can be treated as text - if ($last<0) { - # new pure-text block - $last=$index; - } else { - # add to pure-text block - push(@$textblock, $token); - } - } else { - # it is not text - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - $textblock=[]; - $last=-1; - } - } - # finish processing a possibly unfinished block before returning - if (scalar(@$textblock)) { - push(@$retval,[ $last, $textblock, scalar(@$textblock) ]); - } - return($retval) -} - - - -# extractcommands( \@blockindex ) -# $blockindex has the following format -# [ [ token1, index1 ], [token2, index2],.. ] -# where index refers to the index in the original old or new word sequence -# Returns: reference to an array of the form -# [ [ "\cmd1", index, "\cmd1[optarg]{arg1}{", "arg2" ,"} " ],.. -# where index is just taken from input array -# command must have a textual argument as last argument -# -# requires: iscmd -# -sub extractcommands { - my $block=shift; - my ($i,$token,$index,$cmd,$open,$mid,$closing); - my $retval=[]; - - for ($i=0;$i< scalar @$block;$i++) { - ($token,$index)=@{ $block->[$i] }; - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: \cmd - # $3: last argument - # $4: } + trailing spaces - if ( ( $token =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL) ) { - # push(@$retval,[ $2,$index,$1,$3,$4 ]); - ($cmd,$open,$mid,$closing) = ($2,$1,$3,$4) ; - $closing =~ s/\}/\\RIGHTBRACE/ ; - push(@$retval,[ $cmd,$index,$open,$mid,$closing ]); - } - } - return $retval; -} - -# iscmd($cmd,\@regexarray,\@regexexcl) checks -# return 1 if $cmd matches any of the patterns in the -# array $@regexarray, and none of the patterns in \@regexexcl, otherwise return 0 -sub iscmd { - my ($cmd,$regexar,$regexexcl)=@_; - my ($ret)=0; - foreach $pat ( @$regexar ) { - if ( $cmd =~ m/^${pat}$/ ) { - $ret=1 ; - last; - } - } - return 0 unless $ret; - foreach $pat ( @$regexexcl ) { - return 0 if ( $cmd =~ m/^${pat}$/ ); - } - return 1; -} - - -# pass2( \@seq1,\@seq2) -# Look for differences between seq1 and seq2. -# Mark begin and end of deleted and appended sequences with tags $DELOPEN and $DELCLOSE -# and $ADDOPEN and $ADDCLOSE, respectively, however exclude { } & and all comands, unless -# they match an element of the whitelist (SAFECMD) -# For words in TEXTCMD but not in SAFECMD, enclose interior with $ADDOPEN and $ADDCLOSE brackets -# Deleted comment lines are marked with %DIF < -# Added comment lines are marked with %DIF > -sub pass2 { - my $seq1 = shift ; - my $seq2 = shift ; - - my ($addtokcnt,$deltokcnt,$mattokcnt)=(0,0,0); - my ($addblkcnt,$delblkcnt,$matblkcnt)=(0,0,0); - - my $retval = []; - my $delhunk = []; - my $addhunk = []; - - my $discard = sub { $deltokcnt++; - push ( @$delhunk, $seq1->[$_[0]]) }; - - my $add = sub { $addtokcnt++; - push ( @$addhunk, $seq2->[$_[1]]) }; - - my $match = sub { $mattokcnt++; - if ( scalar @$delhunk ) { - $delblkcnt++; - # mark up changes, but comment out commands - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk); - $delhunk = []; - } - if ( scalar @$addhunk ) { - $addblkcnt++; - # we mark up changes, but simply quote commands - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk); - $addhunk = []; - } - push(@$retval,$seq2->[$_[1]]) }; - - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - # clear up unprocessed hunks - push @$retval,marktags($DELMARKOPEN,$DELMARKCLOSE,$DELOPEN,$DELCLOSE,$DELCMDOPEN,$DELCMDCLOSE,$DELCOMMENT,$delhunk) if scalar @$delhunk; - push @$retval,marktags($ADDMARKOPEN,$ADDMARKCLOSE,$ADDOPEN,$ADDCLOSE,"","",$ADDCOMMENT,$addhunk) if scalar @$addhunk; - - - if ($verbose) { - print STDERR "\n"; - print STDERR " $mattokcnt matching tokens. \n"; - print STDERR " $deltokcnt discarded tokens in $delblkcnt blocks.\n"; - print STDERR " $addtokcnt appended tokens in $addblkcnt blocks.\n"; - } - - return(@$retval); -} - -# marktags($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,\@block) -# returns ($openmark,$open,$block,$close,$closemark) if @block contains no commands (except white-listed ones), -# braces, ampersands, or comments -# mark comments with $comment -# exclude all other exceptions from scope of open, close like this -# ($openmark, $open,...,$close, $opencmd,command, command,$closecmd, $open, ..., $close, $closemark) -# If $opencmd begins with "%" marktags assumes it is operating on a deleted block, otherwise on an added block -sub marktags { - my ($openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment,$block)=@_; - my $word; - my (@argtext); - my $retval=[]; - my $noncomment=0; - my $cmd=-1; # -1 at beginning 0: last token written is a ordinary word - # 1: last token written is a command - # for keeping track whether we are just in a command sequence or in a word sequence - my $cmdcomment= ($opencmd =~ m/^%/); # Flag to indicate whether opencmd is a comment (i.e. if we intend to simply comment out changed commands) - my ($command,$commandword,$closingbracket) ; # temporary variables needed below to remember sub-pattern matches - -# split this block to flatten out sequences joined in pass1 - @$block=splitlatex(join "",@$block); - ### print STDERR "DEBUG: marktags $openmark,$closemark,$open,$close,$opencmd,$closecmd,$comment\n" if $debug; - ### print STDERR "DEBUG: marktags blocksplit ",join("|",@$block),"\n" if $debug; - foreach (@$block) { - $word=$_; - ### print STDERR "DEBUG MARKTAGS: |$word|\n" if $debug; - if ( $word =~ s/^%/%$comment/ ) { - # a comment - if ($cmd==1) { - push (@$retval,$closecmd) ; - $cmd=-1; - } - push (@$retval,$word); - next; - } - if ( $word =~ m/^\s*$/ ) { - ### print STDERR "DEBUG MARKTAGS: whitespace detected |$word| cmdcom |$cmdcomment| |$opencmd|\n" if $debug; - # a sequence of white-space characters - this should only ever happen for the first element of block. - # in deleted block, omit, otherwise just copy it in - if ( ! $cmdcomment) { # ignore in deleted blocks - push(@$retval,$word); - } - next; - } - if (! $noncomment) { - push (@$retval,$openmark); - $noncomment=1; - } - # negative lookahead pattern (?!) in second clause is put in to avoid matching \( .. \) patterns - # also note that second pattern will match \\ - ### print STDERR "DEBUG marktags: Considering word |$word|\n"; - if ( $word =~ /^[&{}\[\]]/ || ( $word =~ /^\\(?!\()(\\|[`'^"~=.]|[\w*@]+)/ && !iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL)) ) { - ###print STDERR "DEBUG MARKTAGS is a non-safe command ($1)\n" if $debug; - ### if ( $word =~ /^[&{}\[\]]/ || ( $word =~ /^\\([\w*@\\% ]+)/ && !iscmd($1,\@SAFECMDLIST,\@SAFECMDEXCL)) ) { - # word is a command or other significant token (not in SAFECMDLIST) - ## same conditions as in subroutine extractcommand: - # check if token is an alphanumeric command sequence with at least one non-optional argument - # \cmd[...]{...}{last argument} - # Capturing in the following results in these associations - # $1: \cmd[...]{...}{ - # $2: cmd - # $3: last argument - # $4: } + trailing spaces - ### pre-0.3 if ( ( $token =~ m/^(\\([\w\d\*]+)(?:\[$brat0\]|\{$pat6\})*\{)($pat6)(\}\s*)$/so ) - if ( ( $word =~ m/^(\\([\w\d\*]+)(?:${extraspace}\[$brat0\]|${extraspace}\{$pat6\})*${extraspace}\{)($pat6)(\}\s*)$/so ) - && (iscmd($2,\@TEXTCMDLIST,\@TEXTCMDEXCL)|| iscmd($2,\@MATHTEXTCMDLIST,\@MATHTEXTCMDEXCL)) - && ( !$cmdcomment || !iscmd($2,\@CONTEXT2CMDLIST, \@CONTEXT2CMDEXCL) ) ) { - # Condition 1: word is a command? - if yes, $1,$2,.. will be set as above - # Condition 2: word is a text command - we mark up the interior of the word. There is a separate check for MATHTEXTCMDLIST - # because for $mathmarkup=WHOLE, the commands should not be split in pass1 (ie. math mode commands are not in - # TEXTCMDLIST, but the interior of MATHTEXT commands should be highlighted in both deleted and added blocks - # Condition 3: But if we are in a deleted block ($cmdcomment=1) and - # $2 (the command) is in context2, just treat it as an ordinary command (i.e. comment it open with $opencmd) - # Because we do not want to disable this command - # here we do not use $opencmd and $closecmd($opencmd is empty) - if ($cmd==1) { - push (@$retval,$closecmd) ; - } elsif ($cmd==0) { - push (@$retval,$close) ; - } - $command=$1; $commandword=$2; $closingbracket=$4; - @argtext=splitlatex($3); # split textual argument into tokens - # and mark it up (but we do not need openmark and closemark) - # insert command with initial arguments, marked-up final argument, and closing bracket - if ( $cmdcomment && iscmd($commandword,\@CONTEXT1CMDLIST, \@CONTEXT1CMDEXCL) ) { - # context1cmd in a deleted environment; delete command itself but keep last argument, marked up - push (@$retval,$opencmd); - $command =~ s/\n/\n${opencmd}/sg ; # repeat opencmd at the beginning of each line - # argument, note that the additional comment character is included - # to suppress linebreak after opening parentheses, which is important - # for latexrevise - push (@$retval,$command,"%\n{$AUXCMD\n",marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } elsif ( iscmd($commandword,,\@MATHTEXTCMDLIST, \@MATHTEXTCMDEXCL) ) { - # MATHBLOCK pseudo command: consider all commands safe, except & and \\ - # Keep these commands even in deleted blocks, hence set $opencmd and $closecmd (5th and 6th argument of marktags) to - # "" - local @SAFECMDLIST=(".*"); - local @SAFECMDEXCL=('\\','\\\\',@UNSAFEMATHCMD); - ### print STDERR "DEBUG: Command $command argtext ",join(",",@argtext),"\n" if $debug; - push(@$retval,$command,marktags("","",$open,$close,"","",$comment,\@argtext)#@argtext - ,$closingbracket); - } else { - # normal textcmd or context1cmd in an added block - push (@$retval,$command,marktags("","",$open,$close,$opencmd,$closecmd,$comment,\@argtext),$closingbracket); - } - push (@$retval,$AUXCMD,"\n") if $cmdcomment ; - $cmd=-1 ; - } else { - # ordinary command - push (@$retval,$opencmd) if $cmd==-1 ; - push (@$retval,$close,$opencmd) if $cmd==0 ; - $word =~ s/\n/\n${opencmd}/sg if $cmdcomment ; # if opencmd is a comment, repeat this at the beginning of every line - push (@$retval,$word); - $cmd=1; - } - } else { - ###print STDERR "DEBUG MARKTAGS is an ordinary word or SAFECMD command \n" if $debug; - # just an ordinary word or command in SAFECMD - push (@$retval,$open) if $cmd==-1 ; - push (@$retval,$closecmd,$open) if $cmd==1 ; - ###TODO: check here if it is a command in MBOXCMD list, and surround it with \mbox{...} - ### $word =~ /^\\(?!\()(\\|[`'^"~=.]|[\w*@]+)/ && iscmd($1,\@MBOXCMDLIST,\@MBOXCMDEXCL)) - ### but actually this check has been carried out already so can simply check if word begins with backslash - if ( $word =~ /^\\(?!\()(\\|[`'^"~=.]|[\w*@]+)(.*?)(\s*)$/s && iscmd($1,\@MBOXCMDLIST,\@MBOXCMDEXCL)) { - # $word is a safe command in MBOXCMDLIST - ###print STDERR "DEBUG Mboxsafecmd detected:$word:\n" if $debug ; - push(@$retval,"\\mbox{$AUXCMD\n\\" . $1 . $2 . $3 ."}$AUXCMD\n" ); - } else { - # $word is a normal word or a safe command (not in MBOXCMDLIST - push (@$retval,$word); - } - $cmd=0; - } - } - push (@$retval,$close) if $cmd==0; - push (@$retval,$closecmd) if $cmd==1; - - push (@$retval,$closemark) if ($noncomment); - return @$retval; -} - -# preprocess($string, ..) -# carry out the following pre-processing steps for all arguments: -# 1. Remove leading white-space -# Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE and \& to \AMPERSAND -# #. Change {,} in comments to \CLEFTBRACE, \CRIGHTBRACE -# 2. mark all first empty line (in block of several) with \PAR tokens -# 3. Convert all '\%' into '\PERCENTAGE ' and all '\$' into \DOLLAR to make parsing regular expressions easier -# 4. Convert all \verb|some verbatim text| commands (where | can be an arbitrary character) -# into \verb{hash} -# 5. Convert \begin{verbatim} some verbatim text \end{verbatim} into \verbatim{hash} -# 6. Convert _n into \SUBSCRIPTNB{n} and _{nnn} into \SUBSCRIPT{nn} -# 7. Convert ^n into \SUPERSCRIPTNB{n} and ^{nnn} into \SUPERSCRIPT{nn} -# 8. a. Convert $$ $$ into \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} -# b. Convert \[ \] into \begin{SQUAREBRACKET} \end{SQUAREBRACKET} -# 9. Convert all picture environmentent (\begin{PICTUREENV} .. \end{PICTUREENV} \PICTUREBLOCKenv -# For --block-math-markup option -convert all \begin{MATH} .. \end{MATH} -# into \MATHBLOCKmath{...} commands, where MATH/math is any valid math environment - -# 10. Add final token STOP to the very end. This is put in because the algorithm works better if the last token is identical. This is removed again in postprocessing. -# -# NB: step 6 and 7 is likely to convert some "_" inappropriately, e.g. in file -# names or labels but it does not matter because they are converted back in the postprocessing step -# Returns: leading white space removed in step 1 -sub preprocess { - for (@_) { - # Change \{ to \QLEFTBRACE and \} to \QRIGHTBRACE - s/(?{$hstr}) && $string ne $hash->{$hstr}) { - warn "Repeated hash value for verbatim mode in spite of different content."; - $hstr="-$hstr"; - } - $hash->{$hstr}=$string; - return($hstr); -} - -#string=fromhash(\%hash,$fromstring) -# restores string value stored in hash -#string=fromhash(\%hash,$fromstring,$prependstring) -# additionally begins each line with prependstring -sub fromhash { - my ($hash,$hstr)=($_[0],$_[1]); - my $retstr=$hash->{$hstr}; - if ( $#_ >= 2) { - $retstr =~ s/^/$_[2]/mg; - } - return $retstr; -} - - -# postprocess($string, ..) -# carry out the following post-processing steps for all arguments: -# * Remove STOP token from the end -# * Replace \RIGHTBRACE by } -# * change citation commands within comments to protect from processing (using marker CITEDIF) -# 1. Check all deleted blocks: -# a.where a deleted block contains a matching \begin and -# \end environment (these will be disabled by a %DIFDELCMD statements), for selected environments enable -# these commands again (such that for example displayed math in a deleted equation -# is properly within math mode. For math mode environments replace numbered equation -# environments with their display only variety (so that equation numbers in new file and -# diff file are identical). Where the correct type of math environment cannot be determined -# use a place holder MATHMODE -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file -# Replace all MATHMODE environment commands by the correct environment to achieve matching -# pairs -# c. Convert MATHBLOCKmath commands to their uncounted numbers (e.g. convert equation -> displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL -# d. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# For added blocks: -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es -# d. place \cite commands in mbox'es (for UNDERLINE style) -# -# 2. If --block-math-markup option set: Convert \MATHBLOCKmath{..} commands back to environments -# -# Convert all PICTUREblock{..} commands back to the appropriate environments -# 3. Convert DIFadd, DIFdel, DIFFaddbegin , ... into FL varieties -# within floats (currently recognised float environments: plate,table,figure -# plus starred varieties). -# 4. Remove empty %DIFDELCMD < lines -# 4. Convert \begin{SQUAREBRACKET} \end{SQUAREBRACKET} into \[ \] -# Convert \begin{DOLLARDOLLAR} \end{DOLLARDOLLAR} into $$ $$ -# 5. Convert \SUPERSCRIPTNB{n} into ^n and \SUPERSCRIPT{nn} into ^{nnn} -# 6. Convert \SUBSCRIPTNB{n} into _n and \SUBCRIPT{nn} into _{nnn} -# 7. Expand hashes of verb and verbatim environments -# 8. Convert '\PERCENTAGE ' back into '\%' and '\DOLLAR ' into '\$' -# 9.. remove all \PAR tokens -# 10. package specific processing: endfloat: make sure \begin{figure} and \end{figure} are always -# on a line by themselves, similarly for table environment -# 4, undo renaming of the \begin, \end,{,} in comments -# Change \QLEFTBRACE, \QRIGHTBRACE,\AMPERSAND to \{,\},\& -# -# Note have to manually synchronize substitution commands below and -# DIF.. command names in the header -sub postprocess { - my ($begin,$len,$cnt,$float,$delblock,$addblock); - # second level blocks - my ($begin2,$cnt2,$len2,$eqarrayblock,$mathblock); - - for (@_) { - - # change $'s in comments to something harmless - 1 while s/(%.*)\$/$1DOLLARDIF/mg ; - - # Remove final STOP token - s/ STOP$//; - # Replace \RIGHTBRACE by } - s/\\RIGHTBRACE/}/g; - - # Check all deleted blocks: where a deleted block contains a matching \begin and - # \end environment (these will be disabled by a %DIFDELCMD statements), enable - # these commands again (such that for example displayed math in a deleted equation - # is properly within math mode. For math mode environments replace numbered equation - # environments with their display only variety (so that equation numbers in new file and - # diff file are identical - while ( m/\\DIFdelbegin.*?\\DIFdelend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $delblock=$&; - - - ### (.*?[^\n]?)\n? construct is necessary to avoid empty lines in math mode, which result in - ### an error - # displayed math environments - if ($mathmarkup == FINE ) { - $delblock=~ s/(\%DIFDELCMD < \s*\\begin\{((?:$MATHENV)|SQUAREBRACKET)\}.*?(?:$DELCMDCLOSE|\n))(.*?[^\n]?)\n?(\%DIFDELCMD < \s*\\end\{\2\})/\\begin{$MATHREPL}$AUXCMD\n$1$3\n\\end{$MATHREPL}$AUXCMD\n$4/sg; - # also transform the opposite pair \end{displaymath} .. \begin{displaymath} but we have to be careful not to interfere with the results of the transformation in the line directly above - ### pre-0.42 obsolete version which did not work on eqnarray test $delblock=~ s/(? displaymath -# (environments defined in $MATHENV will be replaced by $MATHREPL, and environments in $MATHARRENV -# will be replaced by $MATHARRREPL - $delblock=~ s/\\MATHBLOCK($MATHENV)\{($pat6)\}/\\MATHBLOCK$MATHREPL\{$2\}/sg; - $delblock=~ s/\\MATHBLOCK($MATHARRENV)\{($pat6)\}/\\MATHBLOCK$MATHARRREPL\{$2\}/sg; - } - - -# b.where one of the commands matching $COUNTERCMD is used as a DIFAUXCMD, add a statement -# subtracting one from the respective counter to keep numbering consistent with new file - $delblock=~ s/\\($COUNTERCMD)((?:${extraspace}\[$brat0\]${extraspace}|${extraspace}\{$pat6\})*\s*${AUXCMD}\n)/\\$1$2\\addtocounter{$1}{-1}${AUXCMD}\n/sg ; - - -# c. If in-line math mode contains array environment, enclose the whole environment in \mbox'es - while ( $delblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($delblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($delblock,$begin2,$len2)=$mathblock; - pos($delblock) = $begin2 + length($mathblock); - } - # if MBOXINLINEMATH is set, protect inlined math environments with an extra mbox - if ( $MBOXINLINEMATH ) { - # note additional \newline after command is omitted from output if right at the end of deleted block (otherwise a spurious empty line is generated) - $delblock=~s/($math)(?:[\s\n]*)?/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/sg; - } - -# splice in modified delblock - substr($_,$begin,$len)=$delblock; - pos = $begin + length($delblock); - } - # make the array modification in added blocks - while ( m/\\DIFaddbegin.*?\\DIFaddend/sg ) { - $cnt=0; - $len=length($&); - $begin=pos($_) - $len; - $addblock=$&; - while ( $addblock =~ m/($math)(\s*)/sg ) { - $cnt2=0; - $len2=length($&); - $begin2=pos($addblock) - $len2; - $mathblock="%\n\\mbox{$AUXCMD\n$1\n}$AUXCMD\n"; - next unless $mathblock =~ m/\{$ARRENV\}/ ; - substr($addblock,$begin2,$len2)=$mathblock; - pos($addblock) = $begin2 + length($mathblock); - } - # if MBOXINLINEMATH is set, protect inlined math environments with an extra mbox - if ( $MBOXINLINEMATH ) { - ##$addblock=~s/($math)/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/sg; - $addblock=~s/($math)(?:[\s\n]*)?/\\mbox{$AUXCMD\n$1\n}$AUXCMD\n/sg; - } -# splice in modified addblock - substr($_,$begin,$len)=$addblock; - pos = $begin + length($addblock); - } - - - - # Replace MATHMODE environments from step 1a above by the correct Math environment - - # The next line is complicated. The negative look-ahead insertion makes sure that no \end{$MATHENV} (or other mathematical - # environments) are between the \begin{$MATHENV} and \end{MATHMODE} commands. This is necessary as the minimal matching - # is not globally minimal but only 'locally' (matching is beginning from the left side of the string) - if ( $mathmarkup == FINE ) { - 1 while s/\\begin{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}((?:.(?!(?:\\end{(?:(?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}|\\begin{MATHMODE})))*?)\\end{MATHMODE}/\\begin{$1}$2\\end{$1}/s; - 1 while s/\\begin{MATHMODE}((?:.(?!\\end{MATHMODE}))*?)\\end{((?:$MATHENV)|(?:$MATHARRENV)|SQUAREBRACKET)}/\\begin{$2}$1\\end{$2}/s; - # convert remaining \begin{MATHMODE} \end{MATHMODE} (and not containing & or \\ )into MATHREPL environments - s/\\begin{MATHMODE}((?:(.(?!(?[1])) { - $optargnew=$newhash{$cmd}->[1]; - } else { - $optargnew=""; - } - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - } else { - $optargold=""; - } - - if ( defined($oldhash{$cmd}) ) { - $argold=$oldhash{$cmd}->[2]; - } else { - $argold=""; - } - $argnew=$newhash{$cmd}->[2]; - $argdiff="{" . join("",bodydiff($argold,$argnew)) ."}"; - if ( length $optargnew ) { - $optargdiff="[".join("",bodydiff($optargold,$optargnew))."]" ; - $optargdiff =~ s/\\DIFaddbegin /\\DIFaddbeginFL /g; - $optargdiff =~ s/\\DIFaddend /\\DIFaddendFL /g; - $optargdiff =~ s/\\DIFadd\{/\\DIFaddFL{/g; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - ### print STDERR "DEBUG s/\\Q$newhash{$cmd}->[0]\\E/\\$cmd$optargdiff$argdiff/s\n"; - # Note: \Q and \E force literal interpretation of what it between them but allow - # variable interpolation, such that e.g. \title matches just that and not TAB-itle - $$newpreambleref=~s/\Q$newhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s; - # replace this in old preamble if necessary - if ( defined($oldhash{$cmd}->[0])) { - $$oldpreambleref=~s/\Q$oldhash{$cmd}->[0]\E/\\$cmd$optargdiff$argdiff/s ; - } - ### print STDERR "DEBUG NEW PRE ".$$newpreambleref."\n"; - } - - foreach $cmd ( keys %oldhash ) { - # if this has already been dealt with above can just skip - next if defined($newhash{$cmd}) ; - if ( defined($oldhash{$cmd}->[1])) { - $optargold=$oldhash{$cmd}->[1]; - $optargdiff="[".join("",bodydiff($optargold,""))."]" ; - $optargdiff =~ s/\\DIFdelbegin /\\DIFdelbeginFL /g; - $optargdiff =~ s/\\DIFdelend /\\DIFdelendFL /g; - $optargdiff =~ s/\\DIFdel\{/\\DIFdelFL{/g; - } else { - $optargdiff=""; - } - $argdiff="{" . join("",bodydiff($argold,"")) ."}"; - $auxline = "\\$cmd$optargdiff$argdiff"; - $auxline =~s/$/$AUXCMD/sg; - push @auxlines,$auxline; - } - # add auxcmd comment to highlight added lines - return(@auxlines); -} - - - -# @diffs=linediff(\@seq1, \@seq2) -# mark up lines like this -#%DIF mm-mmdnn -#%< old deleted line(s) -#%DIF ------- -#%DIF mmann-nn -#new appended line %< -#%DIF ------- -# Future extension: mark change explicitly -# Assumes: traverse_sequence traverses deletions before insertions in changed sequences -# all line numbers relative to line 0 (first line of real file) -sub linediff { - my $seq1 = shift ; - my $seq2 = shift ; - - my $block = []; - my $retseq = []; - my @begin=('','',''); # dummy initialisation - my $instring ; - - my $discard = sub { @begin=('d',$_[0],$_[1]) unless scalar @$block ; - push(@$block, "%DIF < " . $seq1->[$_[0]]) }; - my $add = sub { if (! scalar @$block) { - @begin=('a',$_[0],$_[1]) ;} - elsif ( $begin[0] eq 'd' ) { - $begin[0]='c'; $begin[2]=$_[1]; - push(@$block, "%DIF -------") } - push(@$block, $seq2->[$_[1]] . " %DIF > " ) }; - my $match = sub { if ( scalar @$block ) { - if ( $begin[0] eq 'd' && $begin[1]!=$_[0]-1) { - $instring = sprintf "%%DIF %d-%dd%d",$begin[1],$_[0]-1,$begin[2]; } - elsif ( $begin[0] eq 'a' && $begin[2]!=$_[1]-1) { - $instring = sprintf "%%DIF %da%d-%d",$begin[1],$begin[2],$_[1]-1; } - elsif ( $begin[0] eq 'c' ) { - $instring = sprintf "%%DIF %sc%s", - ($begin[1]==$_[0]-1) ? "$begin[1]" : $begin[1]."-".($_[0]-1) , - ($begin[2]==$_[1]-1) ? "$begin[2]" : $begin[2]."-".($_[1]-1) ; } - else { - $instring = sprintf "%%DIF %d%s%d",$begin[1],$begin[0],$begin[2]; } - push @$retseq, $instring,@$block, "%DIF -------" ; - $block = []; - } - push @$retseq, $seq2->[$_[1]] - }; - # key function: remove multiple spaces (such that insertion or deletion of redundant white space is not reported) - my $keyfunc = sub { join(" ",split(" ",shift())) }; - - traverse_sequences($seq1,$seq2, { MATCH=>$match, DISCARD_A=>$discard, DISCARD_B=>$add }, $keyfunc ); - push @$retseq, @$block if scalar @$block; - - return wantarray ? @$retseq : $retseq ; -} - - - -# init_regex_arr_data(\@array,"TOKEN INIT") -# scans DATA file handel for line "%% TOKEN INIT" line -# then appends each line not beginning with % into array (as a quoted regex) -sub init_regex_arr_data { - my ($arr,$token)=@_; - my ($copy); - while () { - if ( m/^%%BEGIN $token\s*$/ ) { - $copy=1; } - elsif ( m/^%%END $token\s*/ ) { - last; } - chomp; - push (@$arr,qr/^$_$/) if ( $copy && !/^%/ ) ; - } - seek DATA,0,0; # rewind DATA handle to file begin -} - - -# init_regex_arr_ext(\@array,$arg) -# fills array with regular expressions. -# if arg is a file name, then read in list of regular expressions from that file -# (one expression per line) -# Otherwise treat arg as a comma separated list of regular expressions -sub init_regex_arr_ext { - my ($arr,$arg)=@_; - my $regex; - if ( -f $ arg ) { - open(FILE,"$arg") or die ("Couldn't open $arg: $!"); - while () { - chomp; - next if /^\s*#/ || /^\s*%/ || /^\s*$/ ; - push (@$arr,qr/^$_$/); - } - close(FILE); - } - else { - # assume it is a comma-separated list of reg-ex - foreach $regex (split(qr/(?=1) { - $reset=shift; - } - if ($reset) { - $lasttime=times(); - } - else { - $retval=times()-$lasttime; - $lasttime=$lasttime+$retval; - return($retval); - } -} - - -sub usage { - die <<"EOF"; -Usage: $0 [options] old.tex new.tex > diff.tex - -Compares two latex files and writes tex code to stdout, which has the same -format as new.tex but has all changes relative to old.tex marked up or commented. - ---type=markupstyle --t markupstyle Add code to preamble for selected markup style - Available styles: UNDERLINE CTRADITIONAL TRADITIONAL CFONT FONTSTRIKE INVISIBLE - CHANGEBAR CCHANGEBAR CULINECHBAR CFONTCBHBAR BOLD - [ Default: UNDERLINE ] - ---subtype=markstyle --s markstyle Add code to preamble for selected style for bracketing - commands (e.g. to mark changes in margin) - Available styles: SAFE MARGINAL DVIPSCOL COLOR ZLABEL ONLYCHANGEDPAGE (LABEL)* - [ Default: SAFE ] - * LABEL subtype is deprecated - ---floattype=markstyle --f markstyle Add code to preamble for selected style which - replace standard marking and markup commands within floats - (e.g., marginal remarks cause an error within floats - so marginal marking can be disabled thus) - Available styles: FLOATSAFE IDENTICAL - [ Default: FLOATSAFE ] - ---encoding=enc --e enc Specify encoding of old.tex and new.tex. Typical encodings are - ascii, utf8, latin1, latin9. A list of available encodings can be - obtained by executing - perl -MEncode -e 'print join ("\\n",Encode->encodings( ":all" )) ;' - [Default encoding is utf8 unless the first few lines of the preamble contain - an invocation "\\usepackage[..]{inputenc} in which case the - encoding chosen by this command is asssumed. Note that ASCII (standard - latex) is a subset of utf8] - ---preamble=file --p file Insert file at end of preamble instead of auto-generating - preamble. The preamble must define the following commands - \\DIFaddbegin,\\DIFaddend,\\DIFadd{..}, - \\DIFdelbegin,\\DIFdelend,\\DIFdel{..}, - and varieties for use within floats - \\DIFaddbeginFL,\\DIFaddendFL,\\DIFaddFL{..}, - \\DIFdelbeginFL,\\DIFdelendFL,\\DIFdelFL{..} - (If this option is set -t, -s, and -f options - are ignored.) - ---exclude-safecmd=exclude-file ---exclude-safecmd="cmd1,cmd2,..." --A exclude-file ---replace-safecmd=replace-file ---append-safecmd=append-file ---append-safecmd="cmd1,cmd2,..." --a append-file Exclude from, replace or append to the list of regex - matching commands which are safe to use within the - scope of a \\DIFadd or \\DIFdel command. The file must contain - one Perl-RegEx per line (Comment lines beginning with # or % are - ignored). A literal comma within the comma-separated list must be - escaped thus "\\,", Note that the RegEx needs to match the whole of - the token, i.e., /^regex\$/ is implied and that the initial - "\\" of the command is not included. The --exclude-safecmd - and --append-safecmd options can be combined with the --replace-safecmd - option and can be used repeatedly to add cumulatively to the lists. - ---exclude-textcmd=exclude-file ---exclude-textcmd="cmd1,cmd2,..." --X exclude-file ---replace-textcmd=replace-file ---append-textcmd=append-file ---append-textcmd="cmd1,cmd2,..." --x append-file Exclude from, replace or append to the list of regex - matching commands whose last argument is text. See - entry for --exclude-safecmd directly above for further details. - ---replace-context1cmd=replace-file ---append-context1cmd=append-file ---append-context1cmd="cmd1,cmd2,..." - Replace or append to the list of regex matching commands - whose last argument is text but which require a particular - context to work, e.g. \\caption will only work within a figure - or table. These commands behave like text commands, except when - they occur in a deleted section, when they are disabled, but their - argument is shown as deleted text. - ---replace-context2cmd=replace-file ---append-context2cmd=append-file ---append-context2cmd="cmd1,cmd2,..." - As corresponding commands for context1. The only difference is that - context2 commands are completely disabled in deleted sections, including - their arguments. - ---exclude-mboxsafecmd=exclude-file ---exclude-mboxsafecmd="cmd1,cmd2,..." ---append-mboxsafecmd=append-file ---append-mboxsafecmd="cmd1,cmd2,..." - Define safe commands, which additionally need to be protected by encapsulating - in an \\mbox{..}. This is sometimes needed to get around incompatibilities - between external packages and the ulem package, which is used for highlighting - in the default style UNDERLINE as well as CULINECHBAR CFONTSTRIKE - - - ---config var1=val1,var2=val2,... --c var1=val1,.. Set configuration variables. --c configfile Available variables: - MINWORDSBLOCK (integer) - FLOATENV (RegEx) - PICTUREENV (RegEx) - MATHENV (RegEx) - MATHREPL (String) - MATHARRENV (RegEx) - MATHARRREPL (String) - ARRENV (RegEx) - COUNTERCMD (RegEx) - This option can be repeated. - - ---packages=pkg1,pkg2,.. - Tell latexdiff that .tex file is processed with the packages in list - loaded. This is normally not necessary if the .tex file includes the - preamble, as the preamble is automatically scanned for \\usepackage commands. - Use of the --packages option disables automatic scanning, so if for any - reason package specific parsing needs to be switched off, use --packages=none. - The following packages trigger special behaviour: - endfloat hyperref amsmath apacite siunitx cleveref glossaries mhchem chemformula - [ Default: scan the preamble for \\usepackage commands to determine - loaded packages.] - ---show-preamble Print generated or included preamble commands to stdout. - ---show-safecmd Print list of regex matching and excluding safe commands. - ---show-textcmd Print list of regex matching and excluding commands with text argument. - ---show-config Show values of configuration variables - ---show-all Show all of the above - - NB For all --show commands, no old.tex or new.tex file needs to be given, and no - differencing takes place. - -Other configuration options: - ---allow-spaces Allow spaces between bracketed or braced arguments to commands - [Default requires arguments to directly follow each other without - intervening spaces] - ---math-markup=level Determine granularity of markup in displayed math environments: - Possible values for level are (both numerical and text labels are acceptable): - off or 0: suppress markup for math environments. Deleted equations will not - appear in diff file. This mode can be used if all the other modes - cause invalid latex code. - whole or 1: Differencing on the level of whole equations. Even trivial changes - to equations cause the whole equation to be marked changed. This - mode can be used if processing in coarse or fine mode results in - invalid latex code. - coarse or 2: Detect changes within equations marked up with a coarse - granularity; changes in equation type (e.g.displaymath to equation) - appear as a change to the complete equation. This mode is recommended - for situations where the content and order of some equations are still - being changed. [Default] - fine or 3: Detect small change in equations and mark up and fine granularity. - This mode is most suitable, if only minor changes to equations are - expected, e.g. correction of typos. - ---disable-citation-markup ---disable-auto-mbox Suppress citation markup and markup of other vulnerable commands in styles - using ulem (UNDERLINE,FONTSTRIKE, CULINECHBAR) - (the two options are identical and are simply aliases) - ---enable-citation-markup ---enforce-auto-mbox Protect citation commands and other vulnerable commands in changed sections - with \\mbox command, i.e. use default behaviour for ulem package for other packages - (the two options are identical and are simply aliases) - -Miscelleneous options - ---label=label --L label Sets the labels used to describe the old and new files. The first use - of this option sets the label describing the old file and the second - use of the option sets the label for the new file. - [Default: use the filename and modification dates for the label] - ---no-label Suppress inclusion of old and new file names as comment in output file - ---visible-label Include old and new filenames (or labels set with --label option) as - visible output - ---flatten Replace \\input and \\include commands within body by the content - of the files in their argument. If \\includeonly is present in the - preamble, only those files are expanded into the document. However, - no recursion is done, i.e. \\input and \\include commands within - included sections are not expanded. The included files are assumed to - be located in the same directories as the old and new master files, - respectively, making it possible to organise files into old and new directories. - --flatten is applied recursively, so inputted files can contain further - \\input statements. - ---help --h Show this help text. - ---ignore-warnings Suppress warnings about inconsistencies in length between input - and parsed strings and missing characters. - ---verbose --V Output various status information to stderr during processing. - Default is to work silently. - ---version Show version number. - -EOF -} - -=head1 NAME - -latexdiff - determine and markup differences between two latex files - -=head1 SYNOPSIS - -B [ B ] F F > F - -=head1 DESCRIPTION - -Briefly, I is a utility program to aid in the management of -revisions of latex documents. It compares two valid latex files, here -called C and C, finds significant differences -between them (i.e., ignoring the number of white spaces and position -of line breaks), and adds special commands to highlight the -differences. Where visual highlighting is not possible, e.g. for changes -in the formatting, the differences are -nevertheless marked up in the source. - -The program treats the preamble differently from the main document. -Differences between the preambles are found using line-based -differencing (similarly to the Unix diff command, but ignoring white -spaces). A comment, "S>>" is appended to each added line, i.e. a -line present in C but not in C. Discarded lines - are deactivated by prepending "S>>". Changed blocks are preceded by -comment lines giving information about line numbers in the original files. Where there are insignificant -differences, the resulting file C will be similar to -C. At the end of the preamble, the definitions for I markup commands are inserted. -In differencing the main body of the text, I attempts to -satisfy the following guidelines (in order of priority): - -=over 3 - -=item 1 - -If both C and C are valid LaTeX, then the resulting -C should also be valid LateX. (NB If a few plain TeX commands -are used within C or C then C is not -guaranteed to work but usually will). - -=item 2 - -Significant differences are determined on the level of -individual words. All significant differences, including differences -between comments should be clearly marked in the resulting source code -C. - -=item 3 - -If a changed passage contains text or text-producing commands, then -running C through LateX should produce output where added -and discarded passages are highlighted. - -=item 4 - -Where there are insignificant differences, e.g. in the positioning of -line breaks, C should follow the formatting of C - -=back - -For differencing the same algorithm as I is used but words -instead of lines are compared. An attempt is made to recognize -blocks which are completely changed such that they can be marked up as a unit. -Comments are differenced line by line -but the number of spaces within comments is ignored. Commands including -all their arguments are generally compared as one unit, i.e., no mark-up -is inserted into the arguments of commands. However, for a selected -number of commands (for example, C<\caption> and all sectioning -commands) the last argument is known to be text. This text is -split into words and differenced just as ordinary text (use options to -show and change the list of text commands, see below). As the -algorithm has no detailed knowledge of LaTeX, it assumes all pairs of -curly braces immediately following a command (i.e. a sequence of -letters beginning with a backslash) are arguments for that command. -As a restriction to condition 1 above it is thus necessary to surround -all arguments with curly braces, and to not insert -extraneous spaces. For example, write - - \section{\textem{This is an emphasized section title}} - -and not - - \section {\textem{This is an emphasized section title}} - -or - - \section\textem{This is an emphasized section title} - -even though all varieties are the same to LaTeX (but see -B<--allow-spaces> option which allows the second variety). - -For environments whose content does not conform to standard LaTeX or -where graphical markup does not make sense all markup commands can be -removed by setting the PICTUREENV configuration variable, set by -default to C and C environments; see B<--config> -option). The latter environment (C) can be used to -protect parts of the latex file where the markup results in illegal -markup. You have to surround the offending passage in both the old and -new file by C<\begin{DIFnomarkup}> and C<\end{DIFnomarkup}>. You must -define the environment in the preambles of both old and new -documents. I prefer to define it as a null-environment, - -C<\newenvironment{DIFnomarkup}{}{}> - -but the choice is yours. Any markup within the environment will be -removed, and generally everything within the environment will just be -taken from the new file. - -It is also possible to difference files which do not have a preamble. - In this case, the file is processed in the main document -mode, but the definitions of the markup commands are not inserted. - -All markup commands inserted by I begin with "C<\DIF>". Added -blocks containing words, commands or comments which are in C -but not in C are marked by C<\DIFaddbegin> and C<\DIFaddend>. -Discarded blocks are marked by C<\DIFdelbegin> and C<\DIFdelend>. -Within added blocks all text is highlighted with C<\DIFadd> like this: -C<\DIFadd{Added text block}> -Selected `safe' commands can be contained in these text blocks as well -(use options to show and change the list of safe commands, see below). -All other commands as well as braces "{" and "}" are never put within -the scope of C<\DIFadd>. Added comments are marked by prepending -"S >>". - -Within deleted blocks text is highlighted with C<\DIFdel>. Deleted -comments are marked by prepending "S >>". Non-safe command -and curly braces within deleted blocks are commented out with -"S >>". - - - -=head1 OPTIONS - -=head2 Preamble - -The following options determine the visual markup style by adding the appropriate -command definitions to the preamble. See the end of this section for a description of -available styles. - -=over 4 - -=item B<--type=markupstyle> or -B<-t markupstyle> - -Add code to preamble for selected markup style. This option defines -C<\DIFadd> and C<\DIFdel> commands. -Available styles: - -C - -[ Default: C ] - -=item B<--subtype=markstyle> or -B<-s markstyle> - -Add code to preamble for selected style for bracketing -commands (e.g. to mark changes in margin). This option defines -C<\DIFaddbegin>, C<\DIFaddend>, C<\DIFdelbegin> and C<\DIFdelend> commands. -Available styles: C - -[ Default: C ] -* Subtype C