summaryrefslogtreecommitdiff
path: root/support/lintex
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/lintex
Initial commit
Diffstat (limited to 'support/lintex')
-rw-r--r--support/lintex/COPYING340
-rw-r--r--support/lintex/Makefile23
-rw-r--r--support/lintex/README93
-rw-r--r--support/lintex/cxx/Makefile41
-rw-r--r--support/lintex/cxx/cleandir.cxx230
-rw-r--r--support/lintex/cxx/cleandir.hh21
-rw-r--r--support/lintex/cxx/cleanup.cxx98
-rw-r--r--support/lintex/cxx/cleanup.hh23
-rw-r--r--support/lintex/cxx/file.cxx70
-rw-r--r--support/lintex/cxx/file.hh108
-rw-r--r--support/lintex/cxx/ltx.cxx166
-rw-r--r--support/lintex/cxx/ltx.hh41
-rw-r--r--support/lintex/lintex.1136
-rw-r--r--support/lintex/lintex.c983
-rw-r--r--support/lintex/lintex.com90
-rw-r--r--support/lintex/lintex.pdfbin0 -> 8549 bytes
-rw-r--r--support/lintex/lintexrc2
-rw-r--r--support/lintex/mktests.sh13
18 files changed, 2478 insertions, 0 deletions
diff --git a/support/lintex/COPYING b/support/lintex/COPYING
new file mode 100644
index 0000000000..2ba72d57f6
--- /dev/null
+++ b/support/lintex/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/support/lintex/Makefile b/support/lintex/Makefile
new file mode 100644
index 0000000000..193da4aba9
--- /dev/null
+++ b/support/lintex/Makefile
@@ -0,0 +1,23 @@
+# $Id: Makefile,v 1.3 2001/12/02 11:00:05 loreti Exp $
+
+CFLAGS += -ansi -pedantic -Wall `pkg-config --libs --cflags libconfig`
+#CFLAGS = -ansi -Wall -g `pkg-config --libs --cflags libconfig`
+
+ROOT = /usr/local
+
+.PHONY: install clean
+
+lintex: lintex.c Makefile
+ $(CC) $(CXXFLAGS) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ lintex.c
+
+install: lintex
+ strip lintex
+ mv lintex $(ROOT)/bin
+ cp lintex.1 $(ROOT)/man/man1
+
+lintex.pdf: lintex.1
+ groff -man -Tps $< | ps2pdf - $@
+
+clean:
+ -rm *~ *.o core
+ -rm lintex lintex.pdf
diff --git a/support/lintex/README b/support/lintex/README
new file mode 100644
index 0000000000..554ecb889e
--- /dev/null
+++ b/support/lintex/README
@@ -0,0 +1,93 @@
+"lintex" is a C program that removes auxilliary (La)TeX files that are
+usually not needed after a (La)TeX run (log, aux, dvi, ... files);
+they are however actually removed only if their modification time is
+more recent than the one of the related TeX source. The backup files
+usually created by many editors are also removed.
+
+To remove or not remove additional extensions, lintex can parse the
+configuration file $HOME/.lintexrc . See the included example and the
+manpage for more details
+
+lintex is distributed under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+Here follows an example run:
+
+ryan@nu $ lintex -h
+lintex version 1.13 (2012-09-11)
+Usage:
+ lintex [OPTIONS] [DIR [DIR ...]]
+Purpose:
+ Removes unneeded TeX auxiliary files and editor backup files from the
+ given directories (default: the current directory); the TeX files are
+ actually removed only if their modification time is more recent than
+ the one of the related TeX source and if they aren't readonly.
+ Please see the manpage for a list of extensions that get removed.
+Options:
+ -i : asks the user before removing any file;
+ -r : scans recursively the subdirectories of the given
+ directories;
+ -b ext : "ext" is the trailing string identifying editor backup files
+ (defaults to "~"). -b "" avoids any cleanup of special
+ files;
+ -p : pretend, show what files would be removed but don't actually
+ remove them;
+ -k : keeps final document (.pdf, .ps, .dvi, etc.);
+ -o : permit removal of files older than their sources;
+ -q : quiet, only print error messages;
+ -v : verbose, prints which files were removed and which weren't;
+ -d : debug output, prints the answers to all of life's questions.
+ryan@nu $ ls -lR
+.:
+total 4
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 bar.aux
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 bar.dvi
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 bar.log
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 bar.pdf
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 bar.ps
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 bar.tex
+drwxr-xr-x 2 ryan ryan 4096 Sep 3 18:26 dir1/
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 foo.aux
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 foo.dvi
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 foo.log
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 foo.pdf
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 foo.ps
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:28 foo.tex
+
+./dir1:
+total 0
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 baz.aux
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 baz.dvi
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 baz.log
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 baz.pdf
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 baz.ps
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 baz.tex
+ryan@nu $ lintex -r README .
+lintex: "README" cannot be opened (or is not a directory)
+./bar.aux has been removed
+./bar.dvi has been removed
+./bar.log has been removed
+./bar.pdf has been removed
+./bar.ps has been removed
+./dir1/baz.aux has been removed
+./dir1/baz.dvi has been removed
+./dir1/baz.log has been removed
+./dir1/baz.pdf has been removed
+./dir1/baz.ps has been removed
+ryan@nu $ ls -lR
+.:
+total 4
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 bar.tex
+drwxr-xr-x 2 ryan ryan 4096 Sep 3 18:26 dir1/
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 foo.aux
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 foo.dvi
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 foo.log
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 foo.pdf
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 foo.ps
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:28 foo.tex
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 README
+
+./dir1:
+total 0
+-rw-r--r-- 1 ryan ryan 0 Sep 3 18:26 baz.tex
diff --git a/support/lintex/cxx/Makefile b/support/lintex/cxx/Makefile
new file mode 100644
index 0000000000..c53b349da6
--- /dev/null
+++ b/support/lintex/cxx/Makefile
@@ -0,0 +1,41 @@
+# Author: Maurizio Loreti, aka MLO or (HAM) I3NOO
+# Work: University of Padova - Department of Physics
+# Via F. Marzolo, 8 - 35131 PADOVA - Italy
+# Phone: +39 (049) 827-7216 FAX: +39 (049) 827-7102
+# EMail: loreti@pd.infn.it
+# WWW: http://www.pd.infn.it/~loreti/mlo.html
+#
+# $Id: Makefile,v 1.9 2005/01/21 08:16:48 loreti Exp $
+#
+######################################################
+
+.PHONY: clean
+
+CXX = g++
+#CXXFLAGS = -std=c++98 -pedantic -W -Wall -g -DDEBUG
+CXXFLAGS = -std=c++98 -pedantic -W -Wall -O2
+
+#CXX = KCC
+#CXXFLAGS = -O -DDEBUG
+#CXXFLAGS = -O
+
+LDFLAGS =
+
+ltx: ltx.o cleandir.o cleanup.o file.o
+ $(CXX) $(LDFLAGS) -o $@ ltx.o cleandir.o cleanup.o file.o
+
+ltx.o: ltx.cxx ltx.hh cleandir.hh
+ $(CXX) $(CXXFLAGS) -o $@ -c ltx.cxx
+
+cleandir.o: cleandir.cxx cleandir.hh cleanup.hh
+ $(CXX) $(CXXFLAGS) -o $@ -c cleandir.cxx
+
+cleanup.o: cleanup.cxx cleanup.hh file.hh
+ $(CXX) $(CXXFLAGS) -o $@ -c cleanup.cxx
+
+file.o: file.cxx file.hh
+ $(CXX) $(CXXFLAGS) -o $@ -c file.cxx
+
+clean:
+ -rm *~ *.o ltx
+ -if [ -d ti_files ]; then rm ti_files/* && rmdir ti_files; fi
diff --git a/support/lintex/cxx/cleandir.cxx b/support/lintex/cxx/cleandir.cxx
new file mode 100644
index 0000000000..799f702c35
--- /dev/null
+++ b/support/lintex/cxx/cleandir.cxx
@@ -0,0 +1,230 @@
+// Author: Maurizio Loreti, aka MLO or (HAM) I3NOO
+// Work: University of Padova - Department of Physics
+// Via F. Marzolo, 8 - 35131 PADOVA - Italy
+// Phone: +39 (049) 827-7216 FAX: +39 (049) 827-7102
+// EMail: loreti@pd.infn.it
+// WWW: http://www.pd.infn.it/~loreti/mlo.html
+//
+// -------------------------------------------------------------------
+//
+// $Id: cleandir.cxx,v 1.11 2002/09/25 12:19:41 loreti Exp $
+//
+// -------------------------------------------------------------------
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+#include <cstring>
+#include "ltx.hh" // Includes: functional, iostream, string
+#include "cleandir.hh" // Includes: string
+#include "cleanup.hh" // Includes: string
+#include "file.hh" // Includes: list, map, string, utility, ctime
+
+extern "C" {
+ #include <dirent.h>
+ #include <sys/stat.h>
+ #include <sys/types.h>
+}
+
+using std::cerr;
+using std::cout;
+using std::strcmp;
+using std::string;
+
+// Local variables
+
+namespace {
+ // In "re" are defined the extensions of the files relevant for
+ // LaTeX; ".tex" is missing, being handled separately. THIS ARRAY
+ // MUST BE SORTED IN ASCENDING ORDER.
+
+ const char * re[] = {
+ ".aux", ".dvi", ".idx", ".ilg", ".ind",
+ ".lof", ".log", ".lot", ".pdf", ".ps",
+ ".toc"
+ };
+ const size_t nRE = sizeof(re) / sizeof(re[0]);
+ std::vector<string> texExts(re, re + nRE);
+
+ const string tex(".tex");
+ const string dot(".");
+
+ const size_t filename_max = 256;
+}
+
+// Local functions (declarations)
+
+namespace {
+ void check_file(const string &, const time_t, currDir &);
+}
+
+// Code
+
+void scan_dir(
+ const string & name
+) {
+ // Scans the directory "name", building the related instantiation of
+ // the class "currDir" containing all the informations for the
+ // relevant files; then calls "clean_dir" to perform the actual
+ // cleanup. If the "-r" options has been specified, recurses over
+ // all the directories under the current one.
+
+#if defined(DEBUG)
+ static bool firstTime(true);
+
+ if (firstTime) {
+ cout << "--------------------Relevant extensions ("
+ << nRE << ")\n";
+ copy(texExts.begin(), texExts.end(),
+ std::ostream_iterator<string>(cout, " "));
+ cout << std::endl;
+ firstTime = false;
+ }
+
+ cout << "--------------------scan_dir called for \""
+ << name << "\"\n";
+#endif // DEBUG
+
+ DIR * pDir;
+
+ if ((pDir = opendir( name.c_str() )) != 0) {
+
+ string fullName(name);
+ if (*(fullName.rbegin()) != '/') fullName.append("/");
+
+ currDir thisDir(fullName);
+ std::list<string> subDirs;
+ struct dirent * pDe;
+
+ // Reads every file: skips null inodes (already deleted
+ // files), and the two special files "." and ".." .
+
+ while ((pDe = readdir(pDir)) != 0) {
+ if (pDe->d_ino == 0) continue;
+
+#if defined(DEBUG)
+ cout << "Next file: " << pDe->d_name << " - ";
+#endif // DEBUG
+
+ if (strcmp(pDe->d_name, ".") == 0) {
+#if defined(DEBUG)
+ cout << "skipped\n";
+#endif // DEBUG
+ continue;
+ }
+
+ if (strcmp(pDe->d_name, "..") == 0) {
+#if defined(DEBUG)
+ cout << "skipped\n";
+#endif // DEBUG
+ continue;
+ }
+
+ // Gets the file related informations with stat(2) (we need file
+ // type and modification time). If the call to "stat" fails,
+ // the file is not considered.
+
+ char tName[filename_max];
+ std::strcpy(tName, fullName.c_str());
+ std::strcat(tName, pDe->d_name);
+
+ struct stat sStat;
+
+ if (stat(tName, &sStat) != 0) {
+#if defined(DEBUG)
+ cout << "got error from stat()\n";
+#else
+ cerr << ltx::progname << ": error calling stat("
+ << tName << ")\n";
+#endif // DEBUG
+
+ } else {
+ if (S_ISDIR(sStat.st_mode) != 0) {
+#if defined(DEBUG)
+ cout << "is a directory\n";
+#endif // DEBUG
+
+ // If needed, push the subdirectory names in the dedicated
+ // list, for future recursion; plain files are handled by
+ // the local procedure check_file().
+
+ if (ltx::recurse) subDirs.push_back(tName);
+
+ } else {
+ check_file(pDe->d_name, sStat.st_mtime, thisDir);
+ }
+ }
+ }
+
+ // Looks if some cleanup has to be performed
+
+ clean_files(thisDir);
+
+ if (ltx::recurse) {
+ for_each(subDirs.begin(), subDirs.end(), std::ptr_fun(scan_dir));
+ }
+
+ closedir(pDir);
+ } else {
+ cerr << ltx::progname << ": \"" << name
+ << "\" could not be opened (or is not a directory)\n";
+ }
+}
+
+namespace {
+ void check_file(
+ const string & name,
+ const time_t mTime,
+ currDir & CDir
+ ) {
+ // - If the file "name" matches the trailing string identifying
+ // backup editor files, is removed;
+ // - if it matches a relevant extension, is inserted in the
+ // "currDir" instance.
+
+ string::size_type where;
+
+ if (ltx::lTrailEd > 0) {
+ if ((where = name.rfind(ltx::trailEd)) != string::npos) {
+ if ((where + ltx::lTrailEd) == name.size()) {
+ #if defined(DEBUG)
+ cout << "matches the default editor extension\n";
+ #endif // DEBUG
+ nuke(CDir.getName(), name);
+ return;
+ }
+ }
+ }
+
+ // Breaks the file name in "basename" and "extension"; and checks
+ // the latter against the known ones (".tex" files are handled
+ // separately).
+
+ if ((where = name.find_last_of(dot)) != string::npos) {
+ string extension = name.substr(where);
+ string basename = name.substr(0, where);
+ fileFamily & fF = CDir.getFileFamily(basename);
+
+ if (extension == tex) {
+ fF.addExtension(mTime, 0);
+ #if defined(DEBUG)
+ cout << "inserted\n";
+ #endif // DEBUG
+
+ } else if (binary_search(texExts.begin(), texExts.end(), extension)) {
+ fF.addExtension(mTime, &extension);
+ #if defined(DEBUG)
+ cout << "extension " << extension << " - inserted\n";
+ } else {
+ cout << "extension not relevant\n";
+ #endif // DEBUG
+
+ }
+
+ #if defined(DEBUG)
+ } else {
+ cout << "no extension\n";
+ #endif // DEBUG
+ }
+ }
+}
diff --git a/support/lintex/cxx/cleandir.hh b/support/lintex/cxx/cleandir.hh
new file mode 100644
index 0000000000..3c29d3a012
--- /dev/null
+++ b/support/lintex/cxx/cleandir.hh
@@ -0,0 +1,21 @@
+// Author: Maurizio Loreti, aka MLO or (HAM) I3NOO
+// Work: University of Padova - Department of Physics
+// Via F. Marzolo, 8 - 35131 PADOVA - Italy
+// Phone: +39 (049) 827-7216 FAX: +39 (049) 827-7102
+// EMail: loreti@pd.infn.it
+// WWW: http://www.pd.infn.it/~loreti/mlo.html
+//
+// -------------------------------------------------------------------
+//
+// $Id: cleandir.hh,v 1.1 2001/01/22 10:43:43 loreti Exp $
+//
+// -------------------------------------------------------------------
+
+#ifndef CLEANDIR_H_
+#define CLEANDIR_H_
+
+#include <string>
+
+void scan_dir(const std::string &);
+
+#endif // CLEANDIR_H_
diff --git a/support/lintex/cxx/cleanup.cxx b/support/lintex/cxx/cleanup.cxx
new file mode 100644
index 0000000000..f930490757
--- /dev/null
+++ b/support/lintex/cxx/cleanup.cxx
@@ -0,0 +1,98 @@
+// Author: Maurizio Loreti, aka MLO or (HAM) I3NOO
+// Work: University of Padova - Department of Physics
+// Via F. Marzolo, 8 - 35131 PADOVA - Italy
+// Phone: +39 (049) 827-7216 FAX: +39 (049) 827-7102
+// EMail: loreti@pd.infn.it
+// WWW: http://www.pd.infn.it/~loreti/mlo.html
+//
+// -------------------------------------------------------------------
+//
+// $Id: cleanup.cxx,v 1.8 2005/01/21 08:16:49 loreti Exp $
+//
+// -------------------------------------------------------------------
+
+#include <cstdio>
+#include <cctype>
+#include "ltx.hh" // Includes: functional, iostream, string
+#include "file.hh" // Includes: list, map, string, utility, ctime
+#include "cleanup.hh" // Includes: string
+
+using std::cin;
+using std::cout;
+using std::string;
+
+namespace {
+ const int answerLength(64);
+}
+
+void clean_files(
+ const currDir & dir
+) {
+ // Loops over all the file families stored in "dir", then loops over
+ // all the extensions in this file family; if a ".tex" file with a
+ // modification time former than the modification time of the target
+ // file exists, the file is removed.
+
+ fileCollection::const_iterator iter, iterEnd = dir.end();
+
+ for (iter = dir.begin(); iter != iterEnd; iter++) {
+
+ const fileFamily * pFF = iter->second;
+ std::list<extInfo>::const_iterator jter;
+ std::list<extInfo>::const_iterator jterEnd = pFF->end();
+
+ for (jter = pFF->begin(); jter != jterEnd; jter++) {
+
+ string fullName = iter->first + jter->first;
+
+ if (pFF->hasTex()) {
+ if (difftime(jter->second, pFF->texMtime()) > 0.0) {
+
+ if (ltx::confirm) {
+ char answer[answerLength], c;
+
+ do {
+ cout << "Remove " << dir.getName()
+ << fullName << " (y|n) ? ";
+ cin.get(answer, answerLength);
+ if (cin.gcount() < answerLength-1 ) {
+ cin.ignore();
+ }
+ c = tolower(static_cast<unsigned char>(answer[0]));
+ } while (c != 'y' && c != 'n');
+ if (c != 'y') continue;
+ }
+ nuke(dir.getName(), fullName);
+
+ } else {
+ cout << dir.getName() << fullName
+ << " not removed; " << iter->first
+ << ".tex is newer\n";
+ }
+ } else {
+ cout << dir.getName() << fullName
+ << " not removed; " << iter->first
+ << ".tex does not exist\n";
+ }
+ }
+ }
+}
+
+void nuke(
+ const string & dirName,
+ const string & fileName
+) {
+ // Removes the file "fileName" from the directory "dirName". If the
+ // preprocessor symbol 'DEBUG' is defined, the file is not actually
+ // removed: but a message is printed on the standard output stream,
+ // informing that the Finger Of Death has been raised to him.
+
+ string target = dirName + fileName;
+
+#if defined(DEBUG)
+ cout << "FOD: " << target << std::endl;
+#else
+ remove(target.c_str());
+ cout << target << " has been removed.\n";
+#endif // DEBUG
+}
diff --git a/support/lintex/cxx/cleanup.hh b/support/lintex/cxx/cleanup.hh
new file mode 100644
index 0000000000..b692dd8f14
--- /dev/null
+++ b/support/lintex/cxx/cleanup.hh
@@ -0,0 +1,23 @@
+// Author: Maurizio Loreti, aka MLO or (HAM) I3NOO
+// Work: University of Padova - Department of Physics
+// Via F. Marzolo, 8 - 35131 PADOVA - Italy
+// Phone: +39 (049) 827-7216 FAX: +39 (049) 827-7102
+// EMail: loreti@pd.infn.it
+// WWW: http://www.pd.infn.it/~loreti/mlo.html
+//
+// -------------------------------------------------------------------
+//
+// $Id: cleanup.hh,v 1.2 2002/09/12 10:15:44 loreti Exp $
+//
+// -------------------------------------------------------------------
+
+#ifndef CLEANUP_H_
+#define CLEANUP_H_
+
+#include <string>
+#include "file.hh"
+
+void clean_files(const currDir &);
+void nuke(const std::string &, const std::string &);
+
+#endif // CLEANUP_H_
diff --git a/support/lintex/cxx/file.cxx b/support/lintex/cxx/file.cxx
new file mode 100644
index 0000000000..35c9362385
--- /dev/null
+++ b/support/lintex/cxx/file.cxx
@@ -0,0 +1,70 @@
+// Author: Maurizio Loreti, aka MLO or (HAM) I3NOO
+// Work: University of Padova - Department of Physics
+// Via F. Marzolo, 8 - 35131 PADOVA - Italy
+// Phone: +39 (049) 827-7216 FAX: +39 (049) 827-7102
+// EMail: loreti@pd.infn.it
+// WWW: http://www.pd.infn.it/~loreti/mlo.html
+//
+// -------------------------------------------------------------------
+//
+// $Id: file.cxx,v 1.7 2002/09/12 10:15:44 loreti Exp $
+//
+// -------------------------------------------------------------------
+
+#include <algorithm>
+#include <functional>
+#include <iostream>
+#include "file.hh" // Includes: list, map, string, utility, ctime
+
+using std::string;
+
+// Methods for the class fileFamily
+
+void fileFamily::addExtension(
+ time_t mTime,
+ const string * pExtName
+) {
+ // Insert the file informations in a fileFamily. "mTime" is the
+ // modification time, "pExtName" points to the file extension or is
+ // NULL for an extension of ".tex" .
+
+ if (pExtName) {
+ _extInfo.push_back( std::make_pair(*pExtName, mTime) );
+ } else {
+ _hasTex = true;
+ _texMtime = mTime;
+ }
+}
+
+// Auxiliary function object for currDir objects
+
+struct releaseFileFamily
+ : public std::unary_function<fileCollectionElement, void> {
+ void operator() (fileCollectionElement & p) {
+ delete p.second; }
+};
+
+// Methods for the class currDir
+
+currDir::~currDir()
+{
+ for_each(_dirContent.begin(), _dirContent.end(), releaseFileFamily());
+}
+
+fileFamily & currDir::getFileFamily(
+ const string & base
+) {
+ // Gets the file family related to the basename "base". If this is
+ // the first file found, a fileFamily instance is allocated with
+ // "operator new" (and will be later deleted in the currDir class
+ // destructor).
+
+ fileFamily * retval = _dirContent[ base ];
+
+ if (retval == 0) {
+ retval = new fileFamily;
+ _dirContent[ base ] = retval;
+ }
+
+ return *retval;
+}
diff --git a/support/lintex/cxx/file.hh b/support/lintex/cxx/file.hh
new file mode 100644
index 0000000000..d395d74f2a
--- /dev/null
+++ b/support/lintex/cxx/file.hh
@@ -0,0 +1,108 @@
+// Author: Maurizio Loreti, aka MLO or (HAM) I3NOO
+// Work: University of Padova - Department of Physics
+// Via F. Marzolo, 8 - 35131 PADOVA - Italy
+// Phone: +39 (049) 827-7216 FAX: +39 (049) 827-7102
+// EMail: loreti@pd.infn.it
+// WWW: http://www.pd.infn.it/~loreti/mlo.html
+//
+// -------------------------------------------------------------------
+//
+// $Id: file.hh,v 1.3 2002/09/12 10:15:44 loreti Exp $
+//
+// -------------------------------------------------------------------
+
+#ifndef FILE_H_
+#define FILE_H_
+
+#include <list>
+#include <map>
+#include <string>
+#include <utility>
+#include <ctime>
+
+// Classes for the handling of directories and files.
+//
+// - The files are abstracted as a basename, an extension and a
+// modification time: the basename being defined as all the file
+// name characters up to (but not including) the last "."; and the
+// extension as the remainder. A file may have an empty basename or
+// an empty extension.
+//
+// - A "file family" is a set of files having all the same basename
+// and different extensions. In this context, an extension of
+// ".tex" is considered 'special' and is managed separately; the
+// class "fileFamily" actually contains informations about the
+// existence of a .tex member and its modification time, plus a list
+// of all the related files with different extensions.
+//
+// - For the file families, methods are provided to test for the
+// existence of a .tex; to get its modification time; to add a
+// member to the family; and to retrieve the list of all the
+// extensions found.
+
+typedef std::pair< std::string, time_t > extInfo;
+
+class fileFamily {
+private:
+ bool _hasTex;
+ time_t _texMtime;
+ std::list<extInfo> _extInfo;
+
+ // Prevents any use of the copy constructor and of the assignment
+ // operator
+
+ fileFamily & operator = (const fileFamily & rhs);
+ fileFamily(const fileFamily & rhs);
+
+public:
+ fileFamily() : _hasTex(false), _texMtime(0) {}
+ ~fileFamily() {}
+
+ bool hasTex() const { return _hasTex; }
+ time_t texMtime() const { return _texMtime; }
+
+ void addExtension(time_t, const std::string *);
+
+ // Const-iterators over all the found extensions
+
+ std::list<extInfo>::const_iterator begin() const {
+ return _extInfo.begin(); }
+ std::list<extInfo>::const_iterator end() const {
+ return _extInfo.end(); }
+};
+
+// A directory is seen as a directory name plus a collection of file
+// families; that collection is implemented as an STL map. Methods
+// are provided to add a file, to retrieve the directory name, and to
+// iterate over the file families.
+
+typedef std::pair< const std::string, fileFamily * > fileCollectionElement;
+typedef std::map< const std::string, fileFamily * > fileCollection;
+
+class currDir {
+private:
+ std::string _name;
+ fileCollection _dirContent;
+
+ // Prevents any use of the copy constructor and of the assignment
+ // operator
+
+ currDir & operator = (const currDir & rhs);
+ currDir(const currDir & rhs);
+
+public:
+ currDir(const std::string & dirName) : _name(dirName) { }
+ ~currDir();
+
+ const std::string & getName() const { return _name; }
+ fileFamily & getFileFamily(const std::string &);
+
+ // Iterators over all the found file families
+
+ fileCollection::const_iterator begin() const {
+ return _dirContent.begin(); }
+ fileCollection::const_iterator end() const {
+ return _dirContent.end(); };
+};
+
+#endif // FILE_H_
diff --git a/support/lintex/cxx/ltx.cxx b/support/lintex/cxx/ltx.cxx
new file mode 100644
index 0000000000..a82de99fdb
--- /dev/null
+++ b/support/lintex/cxx/ltx.cxx
@@ -0,0 +1,166 @@
+// Author: Maurizio Loreti, aka MLO or (HAM) I3NOO
+// Work: University of Padova - Department of Physics
+// Via F. Marzolo, 8 - 35131 PADOVA - Italy
+// Phone: +39 (049) 827-7216 FAX: +39 (049) 827-7102
+// EMail: loreti@pd.infn.it
+// WWW: http://www.pd.infn.it/~loreti/mlo.html
+//
+// -------------------------------------------------------------------
+//
+// C++ version of the program "lintex", born as an exercise
+// in programming.
+//
+// $Id: ltx.cxx,v 1.9 2006/09/11 12:25:41 loreti Exp $
+//
+// -------------------------------------------------------------------
+
+#include <algorithm>
+#include <list>
+#include <cstring>
+#include "ltx.hh" // Includes: functional, iostream, string
+#include "cleandir.hh" // Includes: string
+
+extern "C" {
+ #include <getopt.h>
+ #include <unistd.h>
+}
+
+using std::cout;
+using std::endl;
+using std::string;
+
+// Global variables (definition)
+
+namespace ltx {
+ string progname;
+ string trailEd("~");
+ string::size_type lTrailEd;
+ bool confirm(false);
+ bool recurse(false);
+}
+
+using namespace ltx;
+
+// Local procedures
+
+namespace {
+ char *basename(char *);
+ void syntax();
+}
+
+int main(
+ int argc,
+ char *argv[]
+) {
+ std::list<string> targets;
+
+ // Gets the executable name
+
+ progname = argv[0] = basename(argv[0]);
+
+ // Decodes the command line options and arguments
+
+ char shortOpts[] = "irb::";
+ struct option longOpts[] = {
+ {"interactive", no_argument, 0, 'i'},
+ {"recursive", no_argument, 0, 'r'},
+ {"backup", optional_argument, 0, 'b'},
+ { 0, 0, 0, 0}
+ };
+
+ int c;
+ while ((c = getopt_long(argc, argv, shortOpts, longOpts, 0)) != -1) {
+ switch (c) {
+ case 'i':
+ confirm = true;
+ break;
+
+ case 'r':
+ recurse = true;
+ break;
+
+ case 'b':
+ trailEd = optarg ? optarg : "";
+ break;
+
+ case 'h':
+ case '?':
+ syntax();
+ return 0;
+
+ default:
+ std::cerr << "Can't happen: " << __FILE__ << ' '
+ << __LINE__ << endl;
+ return 0;
+ }
+ }
+
+ while (optind < argc) targets.push_back( argv[optind++] );
+
+ // Computes the length of the extension identifying the backup
+ // files, and, if no target directories were explicitly given,
+ // scans the current one.
+
+ lTrailEd = trailEd.size();
+
+ if (targets.empty()) targets.push_back(".");
+
+#if defined(DEBUG)
+ cout << "--------------------Argument analysis\n";
+ cout << "Confirm = " << confirm << endl;
+ cout << "Recurse = " << recurse << endl;
+ cout << "Trailing editor extension = \"" << trailEd
+ << "\" (length " << lTrailEd << ")\n";
+ cout << "Target directories:\n";
+
+ for_each(targets.begin(), targets.end(), printBefore(" "));
+#endif // DEBUG
+
+ // Scans in turn all the wanted directories
+
+ for_each(targets.begin(), targets.end(), std::ptr_fun(scan_dir));
+
+ return 0;
+}
+
+namespace {
+ char *basename(
+ char *pc
+ ) {
+ // Strips the (eventual) path name from the full file name pointed
+ // to by "pc"; if no file name is given, returns an empty string.
+
+ char *p = std::strrchr(pc, '/');
+ if (p == 0) return pc;
+ return ++p;
+ }
+
+ void syntax()
+ {
+ cout <<
+ "\nUsage:\t " << progname << " [options] [dir [dir ... ]]\n";
+ cout <<
+ "Purpose: removes TeX auxiliary files and editor backup files from "
+ "the\n";
+ cout
+ << "\t given directories (default: from the current directory). TeX\n";
+ cout <<
+ "\t auxiliary files are actually removed only if their modification\n";
+ cout <<
+ "\t time is more recent than the one of the related TeX source file.\n";
+ cout <<
+ "Options: -i | --interactive : asks before removing files;\n";
+ cout <<
+ "\t -r | --recursive : scans recursively the given directories;\n";
+ cout <<
+ "\t -b=ext | --backup=ext : \"ext\" is the trailing string "
+ "identifying\n";
+ cout <<
+ "\t\t\t\t editor backup files.\n";
+ cout <<
+ "Notes:\t \"ext\" defaults to \"~\"; -b \"\" avoids the unconditional "
+ "cleanup of\n";
+ cout <<
+ "\t any special file.\n" << endl;
+ }
+}
diff --git a/support/lintex/cxx/ltx.hh b/support/lintex/cxx/ltx.hh
new file mode 100644
index 0000000000..ce41519d57
--- /dev/null
+++ b/support/lintex/cxx/ltx.hh
@@ -0,0 +1,41 @@
+// Author: Maurizio Loreti, aka MLO or (HAM) I3NOO
+// Work: University of Padova - Department of Physics
+// Via F. Marzolo, 8 - 35131 PADOVA - Italy
+// Phone: +39 (049) 827-7216 FAX: +39 (049) 827-7102
+// EMail: loreti@pd.infn.it
+// WWW: http://www.pd.infn.it/~loreti/mlo.html
+//
+// -------------------------------------------------------------------
+//
+// $Id: ltx.hh,v 1.2 2002/09/12 10:15:44 loreti Exp $
+//
+// -------------------------------------------------------------------
+
+#include <functional>
+#include <iostream>
+#include <string>
+
+// Auxiliary function object used to print (on an output stream) a
+// leading text followed by the argument string and an end-of-line.
+
+class printBefore : public std::unary_function< std::string, void > {
+private:
+ const std::string & _leader;
+ std::ostream & _os;
+
+public:
+ printBefore(const std::string & b = "", std::ostream & o = std::cout)
+ : _leader(b), _os(o) {}
+ ~printBefore() {}
+ void operator() (const std::string & s) { _os << _leader << s << std::endl; }
+};
+
+// Global variables (declaration)
+
+namespace ltx {
+ extern std::string progname;
+ extern std::string trailEd;
+ extern std::string::size_type lTrailEd;
+ extern bool confirm;
+ extern bool recurse;
+}
diff --git a/support/lintex/lintex.1 b/support/lintex/lintex.1
new file mode 100644
index 0000000000..95c955e8df
--- /dev/null
+++ b/support/lintex/lintex.1
@@ -0,0 +1,136 @@
+.ig \"-*- nroff -*-
+..
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+.\" Like TP, but if specified indent is more than half
+.\" the current line-length - indent, use the default indent.
+.de Tp
+.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP
+.el .TP "\\$1"
+..
+.TH lintex 1 "11 September 2012" "lintex version 1.13"
+.SH NAME
+lintex \- removes TeX-related garbage files
+.SH SYNOPSIS
+.BR lintex " [ " "\-i" " ] [ " "\-r" " ] [ " "\-b ext" " ] [ " "\-p" " ]"
+.RB " [ " "\-k" " ] [ " "\-o" " ] [ " "\-q" " ] [ " "\-v" " ] [ " "\-d" " ]"
+.RI " [ " dir " [ " dir " \|.\|.\|.\| ]]"
+.SH DESCRIPTION
+.B lintex
+is a program that removes TeX-related auxiliary files, normally not
+needed after a successful TeX run (i.e. log, aux, dvi, \.\.\. files);
+they are actually removed only if their modification timestamp is more
+recent than the one of the related TeX source and if they aren't readonly.
+In addition, all the backup files that your favorite editor has generated
+are also removed.
+.SH OPTIONS
+.TP
+.B \-i
+Asks the user permission before actually removing any file.
+.TP
+.B \-r
+The given directories are scanned recursively; i.e., if they contain
+any subdirectory structure, all the tree will be cleaned up.
+.TP
+.B \-b ext
+.B ext
+is the trailer string (the \'extension\') that identifies the backup
+files generated by your editor, e.g.
+.BR "\-b .bak" ";"
+.B ext
+defaults to ~ (the tilde character), i.e. to the
+.IR emacs
+convention. If
+.B ext
+includes characters having a special meaning for the shell, it must be
+enclosed in quotes: e.g.
+.B
+\-b "~"
+(equivalent to the default). Specifying the null string, as in
+.BR "\-b """"" ","
+inhibits the cleanup of any special file.
+.TP
+.B \-p
+Pretends, show what files would be removed but don't actually remove them.
+.TP
+.B \-k
+Keeps final documents (.pdf, .ps, .dvi).
+.TP
+.B \-o
+Permits the removal of files older than their sources.
+.TP
+.B \-q
+Quiet, only prints error messages.
+.TP
+.B \-v
+Verbose, prints which files were removed and which weren't.
+.TP
+.B \-d
+Debug, prints the answers to all of life's questions.
+.SH PARAMETERS
+.TP
+.SM
+.I dir
+The name(s), separated by whitespace, of one or more directories to be
+cleaned; if missing, the default is the current directory.
+.SH EXTENSIONS THAT GET REMOVED
+All files ending in the following extensions may be removed when appropriate:
+
+ .aux, .bbl, .blg, .dvi, .idx, .ilg, .ind, .lof, .log, .lot, .nav, .out,\
+ .pdf, .ps, .snm, .thm, .toc, .toc.old, .synctex.gz, .xyc
+.SH ENVIRONMENT
+The \fBHOME\fP environment variable determines the location of the configuration
+file, see \fBFILES\fP below.
+.SH FILES
+Users can create a configuration file \fI$HOME/.lintexrc\fP which optionally
+contains the keys \fBremove-keys\fP and \fBkeep-keys\fP, each followed by a
+Python style list of extensions to additionally remove or keep, respectively.
+Each extension \fImust\fP be preceded by a period, e.g. ".pdf" and not "pdf".
+The \fBkeep-keys\fP key is only used when the keep option (\fB\-k\fP) is passed.
+Note that the extensions listed in the \fBkeep-keys\fP field replace the
+defaults used by the \fB\-k\fP option. The \fBkeep-keys\fP option also takes
+precedence over \fBremove-keys\fP: no file ending in an extension removed by
+default or listed in \fBremove-keys\fP will be deleted if its extension is
+listed in \fBkeep-keys\fP and the \fB\-k\fP option was passed. For example, the
+configuration file
+
+ keep-keys = [".pdf", ".ps", ".log"];
+ remove-keys = [".txt", ".1"];
+
+will keep any file ending in ".pdf", ".ps" or ".log" when lintex is called with
+the \fP\-k\fP option (but \fInot\fP files ending in ".dvi"), and adds ".txt" and
+".1" to the list of extensions to check for removal. The following configuration
+file provides lintex with its default behaviour:
+
+ keep-keys = [".pdf", ".ps", ".dvi"];
+ remove-keys = [];
+.SH AUTHOR
+lintex was written by Maurizio Loreti <Maurizio_Loreti\@gmail.com> between 1996
+and 2002.
+.LP
+As of 2010, lintex is maintained by Ryan Kavanagh <rak\@debian.org>. It
+features several extensions/bug fixes. Feel free to email him with your comments
+and suggestions.
+
+.SH COPYRIGHT
+
+Copyright \[co] 1996\(en2002 Maurizio Loreti <Maurizio_Loreti\@gmail.com>
+
+Copyright \[co] 2010\(en2012 Ryan Kavanagh <rak\@debian.org>
+
+.B lintex
+is free software; you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+.LP
+.B lintex
+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
+(here included in the file
+.IR COPYING "),"
+for more details.
diff --git a/support/lintex/lintex.c b/support/lintex/lintex.c
new file mode 100644
index 0000000000..f1b685f4e1
--- /dev/null
+++ b/support/lintex/lintex.c
@@ -0,0 +1,983 @@
+/*
+ Copyright (C) 2010-2012 Ryan Kavanagh <rak@debian.org>
+ Copyright (C) 1996–2002 Maurizio Loreti:
+ *------------------------------------------------------*
+ | Author: Maurizio Loreti, aka MLO or (HAM) I3NOO |
+ | Work: University of Padova - Department of Physics |
+ | Via F. Marzolo, 8 - 35131 PADOVA - Italy |
+ | Phone: ++39(49) 827-7216 FAX: ++39(49) 827-7102 |
+ | EMail: loreti@padova.infn.it |
+ | WWW: http://wwwcdf.pd.infn.it/~loreti/mlo.html |
+ *------------------------------------------------------*
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The lintex website now resides at:
+ http://github.com/ryanakca/lintex
+
+ Description: the command "lintex [-i] [-r] [dir1 [dir2 ...]]" scans
+ the directories given as parameters (the default is the current
+ directory), looking for TeX-related files no more needed and to be
+ removed. With the option -i the user is asked before actually
+ removing any file; with the option -r, the given directories are
+ scanned recursively.
+
+ Environment: the program has been developed under Solaris 2; but
+ should run on every system supporting opendir/readdir/closedir and
+ stat. The file names in the struct dirent (defined in <dirent.h>)
+ are assumed to be null terminated (this is guaranteed under Solaris
+ 2).
+
+ History:
+ 1.00 - 1996-07-05 , first release
+ 1.01 - 1996-07-25 , improved (modify time in nodes)
+ 1.02 - 1996-10-16 , list garbage files w/out .tex
+ 1.03 - 1997-05-21 , call to basename; uploaded to CTAN, where lives
+ in /tex-archive/support/lintex . Added a man
+ page and a Makefile.
+ 1.04 - 1998-06-22 , multiple directories in the command line; -r
+ command option; -I and -R accepted, in addition
+ to -i and -r; more extensions in protoTree; code
+ cleanup.
+ 1.05 - 2001-12-02 , linked list structure optimized.
+ 1.06 - 2002-09-25 , added .pdf extension.
+ 1.07 - 2010-08-11 , don't delete read only files; delete .bbl BibTeX
+ files; add -k to keep final product; added
+ extensions for files generated by Beamer class
+ 1.08 - 2010-10-01 , Add support for different verbosity levels, be
+ relatively quiet by default; dropped support for
+ the DEBUG and FULLDEBUG compiler flags. It's all
+ taken care of with command line options now;
+ added a -p (pretend) flag that shows what we would
+ have removed, but doesn't do anything.
+ 1.09 - 2010-11-30 , Add support for removing files older than their
+ source; remove duplicate entry in usage; update
+ usage to not be wider than 72 characters.
+ 1.10 - 2011-01-30 , Also remove .thm (generated by ntheorem), .out
+ (generated by hyperref), .toc.old (memoir?); list
+ removal extensions in manpage.
+ 1.11 - 2011-11-07 , Also remove .synctex.gz files.
+ 1.12 - 2012-08-30 , Also remove xypic's .xyc files.
+ 1.13 - 2012-09-11 , Add support for configuration file; updated
+ documentation.
+
+ ---------------------------------------------------------------------*/
+
+/**
+ | Included files
+**/
+
+#include <stdio.h> /* Standard library */
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <sys/types.h> /* Unix proper */
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include <libconfig.h> /* Configuration file support */
+
+/**
+ | Definitions:
+ | - LONG_ENOUGH: length of the buffer used to read the answer from the
+ | user, when the -i command option is specified;
+ | - MAX_B_EXT: maximum length of the extension for backup files (including
+ | the leading dot and the trailing '\0').
+ | - TRUE, FALSE: guess what?
+ | - VERSION: lintex version
+ | - QUIET, WHISPER, VERBOSE and DEBUG:
+ | * QUIET: no output
+ | * WHISPER: only print actions that are taken (ie. list files that are
+ | removed, default starting as of 1.08)
+ | * VERBOSE: list files on which actions are taken as well as those which
+ | aren't (default up to / including 1.07)
+ | * DEDUG: print debug information (originally FULLDEBUG compiler flag)
+ | means print everything you can for those who want to debug.
+ | Errors will be sent to stderr regardless of the output level.
+**/
+
+#define LONG_ENOUGH 48
+#define MAX_B_EXT 8
+#define TRUE 1
+#define FALSE 0
+#define VERSION "1.13 (2012-09-11)"
+#define QUIET 0
+#define WHISPER 1
+#define VERBOSE 2
+#define DEBUG 3
+
+/**
+ | Type definitions:
+ | - Froot: the root of a linked list structure, where file names having a
+ | given extension (pointed to by Froot.extension) will be stored;
+ | these linked lists are also used to store directory names (with fake
+ | extension strings).
+ | - Fnode: an entry in the linked list of the file names; contains the
+ | file modification time, the file name and a pointer to the next node.
+ | As a side note, the so called 'struct hack', here used to store the
+ | file name, is not guaranteed to work by the current C ANSI standard;
+ | but no environment/compiler where it does not work is currently
+ | known.
+**/
+
+typedef struct sFroot {
+ char *extension;
+ struct sFnode *firstNode;
+ struct sFnode *lastNode;
+} Froot;
+
+typedef struct sFnode {
+ time_t mTime;
+ struct sFnode *next;
+ int write;
+ char name[1];
+} Fnode;
+
+/**
+ | Global variables:
+ | - confirm: will be 0 or 1 according to the -i command option;
+ | - recurse: will be 0 or 1 according to the -r command option;
+ | - keep: will be 0 or 1 according to the -k command option;
+ | - output_level: See the definitions above for more details;
+ | - pretend: will be 0 or 1 according to -p command option;
+ | - older: will be 0 or 1 according to -o command option;
+ | - bExt: the extension for backup files: defaults to "~" (the emacs
+ | convention);
+ | - n_bExt: the length of the previous string;
+ | - programName: the name of the executable;
+ | - protoTree: Froot's of the file names having extensions relevant to
+ | TeX. ".tex" extensions are assumed to be pointed to by protoTree[0].
+ | - keep_exts: Array containing extensions to keep.
+ | - protoTreeSize, keep_exts_size: number of elements in protoTree and
+ | keep_exts.
+**/
+
+Froot *protoTree;
+char **keep_exts;
+int protoTreeSize;
+
+static int confirm = FALSE;
+static int recurse = FALSE;
+static int keep = FALSE;
+static int output_level = WHISPER;
+static int pretend = FALSE;
+static int older = FALSE;
+static char bExt[MAX_B_EXT] = "~";
+static size_t n_bExt;
+static char *programName;
+
+char *remove_exts[] = {
+ ".tex", /* Must be first */
+ ".aux",
+ ".bbl",
+ ".blg",
+ ".dvi",
+ ".idx",
+ ".ilg",
+ ".ind",
+ ".lof",
+ ".log",
+ ".lot",
+ ".nav",
+ ".out",
+ ".pdf",
+ ".ps",
+ ".snm",
+ ".synctex.gz",
+ ".thm",
+ ".toc",
+ ".toc.old",
+ ".xyc"
+};
+
+char *keep_exts_defaults[] = {
+ ".pdf",
+ ".ps",
+ ".dvi"
+};
+int keep_exts_size = 3;
+
+/**
+ | Procedure prototypes (in alphabetical order)
+**/
+
+static char *baseName(char *);
+static Froot *buildTree(char *, Froot *);
+static void clean(char *);
+static void examineTree(Froot *, char *);
+static void insertNode(char *, size_t, time_t, int, Froot *);
+static void noMemory(void);
+static void nuke(char *);
+static void putsMessage(char *, int);
+static void printTree(Froot *);
+static void releaseTree(Froot *);
+static void setupTrees(void);
+static void syntax(void);
+
+/*---------------------------*
+ | And now, our main program |
+ *---------------------------*/
+
+int main(
+ int argc,
+ char *argv[]
+){
+ Froot *dirNames; /* To hold the directories to be scanned */
+ Fnode *pFN; /* Running pointer over directory names */
+ int to_bExt = FALSE; /* Flag "next parameter to bExt" */
+
+ /**
+ | Scans the arguments appropriately; the required directories are stored
+ | in the linked list starting at "dirNames".
+ **/
+
+ programName = baseName(argv[0]);
+
+ if ((dirNames = calloc(2, sizeof(Froot))) == 0) {
+ noMemory();
+ }
+ dirNames->extension = "argv";
+
+ while (--argc) {
+ if ((*++argv)[0] == '-') {
+ switch ( (*argv)[1] ) {
+ case 'i': case 'I':
+ confirm = TRUE;
+ break;
+
+ case 'r': case 'R':
+ recurse = TRUE;
+ break;
+
+ case 'k': case 'K':
+ keep = TRUE;
+ break;
+
+ case 'b': case 'B':
+ to_bExt = TRUE;
+ break;
+
+ case 'q': case 'Q':
+ output_level = QUIET;
+ break;
+
+ case 'v': case 'V':
+ output_level = VERBOSE;
+ break;
+
+ case 'd': case 'D':
+ output_level = DEBUG;
+ break;
+
+ case 'p': case 'P':
+ pretend = TRUE;
+ break;
+
+ case 'o': case 'O':
+ older = TRUE;
+ break;
+
+ default:
+ syntax();
+ }
+
+ } else {
+ if (to_bExt) {
+ strcpy(bExt, *argv);
+ to_bExt = FALSE;
+ } else {
+ insertNode(*argv, 0, 0, 0, dirNames);
+ }
+ }
+ }
+
+ if (to_bExt) {
+ syntax();
+ }
+ n_bExt = strlen(bExt);
+
+ setupTrees();
+
+ /**
+ | If no parameter has been given, clean the current directory
+ **/
+
+ if ((pFN = dirNames->firstNode) == 0) {
+ clean(".");
+ } else {
+ while (pFN != 0) {
+ clean(pFN->name);
+ pFN = pFN->next;
+ }
+ }
+ releaseTree(dirNames);
+
+ return EXIT_SUCCESS;
+}
+
+/*------------------------------------------*
+ | The called procedures (in logical order) |
+ *------------------------------------------*/
+
+static void setupTrees(void)
+{
+ /**
+ | Initialise protoTree, keep_exts
+ **/
+ config_t cfg; /* To hold our config */
+ config_setting_t *setting; /* To hold a setting */
+ int i; /* Iterator */
+ int needed; /* number of characters in filename */
+ char *extension, *cfg_file;
+
+ if (output_level >= DEBUG)
+ printf("Initialising protoTree, keep_exts.\n");
+
+ protoTreeSize = sizeof(remove_exts) / sizeof(char *) + 1;
+ if ((protoTree = malloc(sizeof(Froot) * protoTreeSize)) == 0) {
+ noMemory();
+ }
+ /* remove_exts has (protoTreeSize - 1) elements */
+ if (output_level >= DEBUG)
+ printf("Created protoTree of size %d\n", protoTreeSize);
+ for (i=0; i < protoTreeSize - 1; i++) {
+ protoTree[i].extension = remove_exts[i];
+ protoTree[i].firstNode = 0;
+ protoTree[i].lastNode = 0;
+ if (output_level >= DEBUG)
+ printf("Added %d-th extension %s to protoTree of size %d at pos %d\n",
+ i, remove_exts[i], protoTreeSize, i);
+ }
+
+ /* Add the sentinel */
+ protoTree[protoTreeSize - 1].extension = 0;
+ protoTree[protoTreeSize - 1].firstNode = 0;
+ protoTree[protoTreeSize - 1].lastNode = 0;
+ if (output_level >= DEBUG)
+ printf("Added sentinal to protoTree at pos %d.\n", protoTreeSize - 1);
+
+ keep_exts = keep_exts_defaults;
+ /**
+ | Initialise and read the config file
+ **/
+
+ config_init(&cfg);
+
+ needed = strlen(getenv("HOME")) + strlen("/.lintexrc") + 1;
+ cfg_file = (char *) malloc(sizeof(char) * needed);
+ if (getenv("HOME")) {
+ strcpy(cfg_file, getenv("HOME"));
+ strcat(cfg_file, "/.lintexrc");
+ if (output_level >= DEBUG)
+ printf("Using config file %s.\n", cfg_file);
+ }
+
+ if (! access(cfg_file, R_OK)) {
+ /* We have read access to the config file */
+ if (! config_read_file(&cfg, cfg_file)) {
+ fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg),
+ config_error_line(&cfg), config_error_text(&cfg));
+ config_destroy(&cfg);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Lets extract our settings */
+ /* Extensions to remove */
+ setting = config_lookup(&cfg, "remove-exts");
+ if (setting != NULL) {
+ unsigned int count = config_setting_length(setting);
+
+ Froot *protoTreeTemp;
+ if ((protoTreeTemp = (Froot *) malloc(sizeof(Froot) * (count + protoTreeSize))) == 0) {
+ noMemory();
+ }
+ memcpy(protoTreeTemp, protoTree, sizeof(Froot) * protoTreeSize);
+ if (output_level >= DEBUG)
+ printf("Copied protoTree to larger location to add config exts.\n");
+
+ for (i = 0; i < count; i++) {
+ extension = (char *) config_setting_get_string_elem(setting, i);
+ protoTreeTemp[protoTreeSize - 1 + i].extension = extension;
+ protoTreeTemp[protoTreeSize - 1 + i].firstNode = 0;
+ protoTreeTemp[protoTreeSize - 1 + i].lastNode = 0;
+ if (output_level >= DEBUG)
+ printf("Added %d-th config extension %s to protoTree of size %d at pos %d\n",
+ i, extension, protoTreeSize + count, protoTreeSize - 1 + i);
+ }
+
+ /* Add the sentinel */
+ protoTreeTemp[protoTreeSize - 1 + count].extension = 0;
+ protoTreeTemp[protoTreeSize - 1 + count].firstNode = 0;
+ protoTreeTemp[protoTreeSize - 1 + count].lastNode = 0;
+ protoTree = protoTreeTemp;
+ if (output_level >= DEBUG)
+ printf("Added sentinel to protoTree at position %d\n", protoTreeSize - 1 + count);
+
+ protoTreeSize += count;
+ }
+
+ /* Extensions to keep */
+ setting = config_lookup(&cfg, "keep-exts");
+ if (setting != NULL) {
+ int i;
+ keep_exts_size = config_setting_length(setting);
+
+ if ((keep_exts = (char **) malloc(sizeof(char *) * keep_exts_size)) == 0) {
+ noMemory();
+ }
+
+ for (i = 0; i < keep_exts_size; i++) {
+ keep_exts[i] = (char *) config_setting_get_string_elem(setting, i);
+ if (output_level >= DEBUG)
+ printf("Added %d-th config extension %s to keep_exts of size %d at pos %d\n",
+ i, keep_exts[i], keep_exts_size, i);
+ }
+ }
+ } else {
+ if (! access(cfg_file, F_OK)) {
+ /* File exists */
+ fprintf(stderr,
+ "Warning: Insufficient permissions to read config file $HOME/.lintexrc");
+ }
+ }
+}
+
+static void insertNode(
+ char *name,
+ size_t lName,
+ time_t mTime,
+ int write,
+ Froot *root
+){
+
+ /**
+ | Creates a new Fnode, to be inserted at the _end_ of the linked
+ | list pointed to by root->firstNode (i.e., the list is organized
+ | as a "queue", a.k.a. "FIFO" list): if a new node cannot be created,
+ | an error message is printed and the program aborted.
+ | If "lName" is bigger than zero, the file name is represented by the
+ | first lName characters of "name"; otherwise by the whole string in
+ | "name".
+ **/
+
+ Fnode *pFN; /* The new node created by insertNode */
+ size_t sSize; /* Structure size */
+
+ sSize = sizeof(Fnode) + (lName == 0 ? strlen(name) : lName);
+
+ if ((pFN = malloc(sSize)) == 0) {
+ noMemory();
+ }
+ pFN->mTime = mTime;
+ pFN->write = write;
+ pFN->next = 0;
+
+ if (lName == 0) {
+ strcpy(pFN->name, name);
+ } else {
+ strncpy(pFN->name, name, lName);
+ pFN->name[lName] = '\0';
+ }
+
+ if (root->lastNode == 0) {
+ root->firstNode = pFN;
+ } else {
+ root->lastNode->next = pFN;
+ }
+ root->lastNode = pFN;
+}
+
+static void noMemory(void)
+{
+ fprintf(stderr, "%s: couldn't obtain heap memory\n", programName);
+ exit(EXIT_FAILURE);
+}
+
+static void clean(
+ char *dirName
+){
+
+ /**
+ | Does the job for the directory "dirName".
+ |
+ | Builds a structure holding the TeX-related files, and does the
+ | required cleanup; finally, removes the file structure.
+ | If the list appended to "dirs" has been filled, recurse over the
+ | tree of subdirectories.
+ **/
+
+ Froot *teXTree; /* Root node of the TeX-related files */
+ Froot *dirs; /* Subdirectories in this directory */
+ Fnode *pFN; /* Running pointer over subdirectories */
+
+ if ((dirs = calloc(2, sizeof(Froot))) == 0) {
+ noMemory();
+ }
+ dirs->extension = "subs";
+
+ if ((teXTree = buildTree(dirName, dirs)) != 0) {
+
+ if (output_level >= DEBUG) {
+ printTree(teXTree);
+ }
+
+ examineTree(teXTree, dirName);
+ releaseTree(teXTree);
+ }
+
+ for (pFN = dirs->firstNode; pFN != 0; pFN = pFN->next) {
+ clean(pFN->name);
+ }
+ releaseTree(dirs);
+}
+
+static Froot *buildTree(
+ char *dirName,
+ Froot *subDirs
+){
+
+ /**
+ | - Opens the required directory;
+ | - allocates a structure to hold the names of the TeX-related files,
+ | initialized from the global structure "protoTree";
+ | - starts a loop over all the files of the given directory.
+ **/
+
+ DIR *pDir; /* Pointer returned from opendir() */
+ struct dirent *pDe; /* Pointer returned from readdir() */
+ Froot *teXTree; /* Root node of the TeX-related files */
+
+ if (output_level >= DEBUG) {
+ printf("* Scanning directory \"%s\" - confirm = %c, recurse = %c, ",
+ dirName, (confirm ? 'Y' : 'N'), (recurse ? 'Y' : 'N')),
+ printf("keep = %c\n", (keep ? 'Y' : 'N'));
+ printf("* Editor trailer: \"%s\"\n", bExt);
+ puts("------------------------------Phase 1: directory scan");
+ }
+
+ if ((pDir = opendir(dirName)) == 0) {
+ fprintf(stderr,
+ "%s: \"%s\" cannot be opened (or is not a directory)\n",
+ programName, dirName);
+ return 0;
+ }
+
+ if ((teXTree = malloc(protoTreeSize * sizeof(Froot))) == 0) {
+ noMemory();
+ }
+ memcpy(teXTree, protoTree, protoTreeSize * sizeof(Froot));
+
+ while ((pDe = readdir(pDir)) != 0) {
+ char tName[FILENAME_MAX]; /* Fully qualified file name */
+ struct stat sStat; /* To be filled by stat(2) */
+ size_t len; /* Lenght of the current file name */
+ size_t last; /* Index of its last character */
+ char *pFe; /* Pointer to file extension */
+
+ /**
+ | - Tests for empty inodes (already removed files);
+ | - skips the . and .. (current and previous directory);
+ | - tests the trailing part of the file name against the extension of
+ | the backup files, to be always deleted.
+ **/
+
+ if (pDe->d_ino == 0) continue;
+ if (strcmp(pDe->d_name, ".") == 0) continue;
+ if (strcmp(pDe->d_name, "..") == 0) continue;
+
+ sprintf(tName, "%s/%s", dirName, pDe->d_name);
+
+ len = strlen(pDe->d_name);
+ last = len - 1;
+
+ if (n_bExt != 0) { /* If 0, no backup files to delete */
+ int crit; /* What exceeds backup extensions */
+
+ crit = len - n_bExt;
+ if (crit > 0 && strcmp(pDe->d_name + crit, bExt) == 0) {
+ nuke(tName);
+ continue;
+ }
+ }
+
+ /**
+ | If the file is a directory and the -r option has been given, stores
+ | the directory name in the linked list pointed to by "subDirs", for
+ | recursive calls.
+ |
+ | N.B.: if stat(2) fails, the file is skipped.
+ **/
+
+ if (stat(tName, &sStat) != 0) {
+ fprintf(stderr, "File \"%s", tName);
+ perror("\"");
+ continue;
+ }
+
+ if (S_ISDIR(sStat.st_mode) != 0) {
+
+ if (output_level >= DEBUG) {
+ printf("File %s - is a directory\n", pDe->d_name);
+ }
+
+ if (recurse) {
+ insertNode(tName, 0, 0, 0, subDirs);
+ }
+ continue;
+ }
+
+ /**
+ | If the file has an extension (the rightmost dot followed by at
+ | least one character), and if that extension matches one of the
+ | entries in teXTree[i].extension: stores the file name (with the
+ | extension stripped) in the appropriate linked list, together with
+ | its modification time.
+ **/
+
+ if ((pFe = strrchr(pDe->d_name, '.')) != 0) {
+ size_t nameLen;
+
+ nameLen = pFe - pDe->d_name;
+ if (nameLen < last) {
+ Froot *pTT;
+
+ if (output_level >= DEBUG) {
+ printf("File %s - extension %s", pDe->d_name, pFe);
+ }
+
+ /**
+ | Loop on recognized TeX-related file extensions
+ **/
+
+ for (pTT = teXTree; pTT->extension != 0; pTT++) {
+ if (strcmp(pFe, pTT->extension) == 0) {
+ int i;
+ if (keep) {
+ i = 0;
+ } else {
+ i = keep_exts_size;
+ }
+ for (i = 0; i < keep_exts_size; i++) {
+ if (strcmp(pFe, keep_exts[i]) == 0) {
+ /**
+ | The current file's extension is in keep_exts, we want to keep
+ | it.
+ **/
+ i = -1;
+ break;
+ }
+ }
+
+ if ((!keep) | (i != -1)) {
+ /**
+ | Only add the file if we didn't find its extension in keep_exts
+ **/
+ insertNode(pDe->d_name, nameLen, sStat.st_mtime, access(tName, W_OK), pTT);
+ if (output_level >= DEBUG) {
+ printf(" - inserted in tree");
+ }
+ } else if (keep) {
+ if (output_level >= DEBUG) {
+ printf(" - not inserted in tree (extension in keep-exts)");
+ } else if (output_level >= VERBOSE) {
+ printf("*** %s not removed; keep activated ***\n", pDe->d_name);
+ }
+ }
+ break;
+ }
+ } /* loop on known extensions */
+
+ if (output_level >= DEBUG) {
+ puts("");
+ }
+
+ } else {
+ if (output_level >= VERBOSE) {
+ printf("File %s - empty extension\n", pDe->d_name);
+ }
+ }
+
+ } else {
+ if (output_level >= DEBUG) {
+ printf("File %s - without extension\n", pDe->d_name);
+ }
+ }
+ } /* while (readdir) ... */
+
+ if (closedir(pDir) != 0) {
+ fprintf(stderr, "Directory \"%s", dirName);
+ perror("\"");
+ }
+
+ return teXTree;
+}
+
+static void printTree(
+ Froot *teXTree
+){
+
+ /**
+ | Prints all the file names archived in the linked lists (for
+ | debugging purposes).
+ **/
+
+ if (output_level >= DEBUG) {
+ Froot *pTT; /* Running pointer over teXTree elements */
+
+ puts("------------------------------Phase 2: tree printout");;
+ for (pTT = teXTree; pTT->extension != 0; pTT++) {
+ Fnode *pTeX; /* Running pointer over TeX-related files */
+ int nNodes = 0; /* Counter */
+
+ for (pTeX = pTT->firstNode; pTeX != 0; pTeX = pTeX->next) {
+ ++nNodes;
+ printf("%s%s\n", pTeX->name, pTT->extension);
+ }
+ printf(" --> %d file%s with extension %s\n", nNodes,
+ (nNodes == 1 ? "" : "s"), pTT->extension);
+ }
+ }
+}
+
+static void examineTree(
+ Froot *teXTree,
+ char *dirName
+){
+
+ /**
+ | Examines the linked lists for this directory doing the effective
+ | cleanup.
+ **/
+
+ Froot *pTT; /* Pointer over linked list trees */
+ Fnode *pTeX; /* Running pointer over the .tex files */
+
+ /**
+ | Looks, for all the .tex files, if a corresponding entry with the same
+ | name exists (with a different extension) in the other lists; if so,
+ | and if its modification time is later than the one of the related
+ | .tex file, removes it from the file system.
+ **/
+ putsMessage("------------------------------Phase 3: effective cleanup",
+ DEBUG);
+
+ for (pTeX = teXTree->firstNode; pTeX != 0; pTeX = pTeX->next) {
+ char tName[FILENAME_MAX];
+
+ sprintf(tName, "%s/%s.tex", dirName, pTeX->name);
+ pTT = teXTree;
+
+ if (output_level >= DEBUG) {
+ printf(" Finding files related to %s:\n", tName);
+ }
+
+ for (pTT++; pTT->extension != 0; pTT++) {
+ Fnode *pComp;
+
+ for (pComp = pTT->firstNode; pComp != 0; pComp = pComp->next) {
+ char cName[FILENAME_MAX];
+
+ if (strcmp(pTeX->name, pComp->name) == 0) {
+ sprintf(cName, "%s/%s%s", dirName, pTeX->name, pTT->extension);
+ pComp->name[0] = '\0';
+
+ /**
+ | Remove generated file if more recent than source (default) or if
+ | we permit the removal of files older than source
+ **/
+ if (difftime(pComp->mTime, pTeX->mTime) > 0.0 || older) {
+ if (pComp->write == 0) {
+ nuke(cName);
+ } else {
+ if (output_level >= DEBUG) {
+ printf("*** %s readonly; perms are %d***\n", cName,
+ pComp->write);
+ }
+ if (output_level >= VERBOSE) {
+ printf("*** %s not removed; it is read only ***\n", cName);
+ }
+ }
+ } else {
+ if (output_level >= VERBOSE) {
+ printf("*** %s not removed; %s is newer ***\n", cName, tName);
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ | If some garbage file has not been deleted, list it
+ **/
+
+ putsMessage("------------------------------Phase 4: left garbage files",
+ DEBUG);
+
+ pTT = teXTree;
+ for (pTT++; pTT->extension != 0; pTT++) {
+ Fnode *pComp;
+
+ for (pComp = pTT->firstNode; pComp != 0; pComp = pComp->next) {
+ if (pComp->name[0] != '\0') {
+ char cName[FILENAME_MAX];
+
+ sprintf(cName, "%s/%s%s", dirName, pComp->name, pTT->extension);
+ if (output_level >= VERBOSE) {
+ printf("*** %s not removed; no .tex file found ***\n", cName);
+ }
+ }
+ }
+ }
+}
+
+static void releaseTree(
+ Froot *teXTree
+){
+
+ /**
+ | Cleanup of the file name storage structures: an _array_ of Froot's,
+ | terminated by a NULL extension pointer as a sentinel, is assumed.
+ | Every linked list nodes is freed; then releaseTree frees also the
+ | root structure.
+ **/
+
+ Froot *pFR;
+
+ putsMessage("------------------------------Phase 5: tree cleanup", DEBUG);
+
+ for (pFR = teXTree; pFR->extension != 0; pFR++) {
+ Fnode *pFN, *p;
+
+ int nNodes = 0;
+ if (output_level >= DEBUG) {
+ printf("Dealing with extensions %s ...", pFR->extension);
+ }
+
+ for (pFN = pFR->firstNode; pFN != 0; pFN = p) {
+ p = pFN->next;
+ free(pFN);
+
+ nNodes++;
+ }
+
+ if (output_level >= DEBUG) {
+ printf(" %d nodes freed\n", nNodes);
+ }
+ }
+
+ free(teXTree);
+}
+
+static void nuke(
+ char *name
+){
+
+ /**
+ | Removes "name" (the fully qualified file name) from the file system
+ **/
+
+ if ((output_level >= DEBUG) || pretend) {
+ printf("*** File \"%s\" would have been removed ***\n", name);
+ }
+
+ if (pretend) {
+ /* We don't need to continue if we aren't going to remove the file */
+ return;
+ }
+
+ if (confirm) {
+ char yn[LONG_ENOUGH], c;
+
+ do {
+ printf("Remove %s (y|n) ? ", name);
+ if (fgets(yn, LONG_ENOUGH, stdin) == 0) return;
+ if (yn[0] == '\0' || (c = tolower((unsigned char) yn[0])) == 'n') {
+ return;
+ }
+ } while (c != 'y');
+ }
+
+ if (remove(name) != 0) {
+ fprintf(stderr, "File \"%s", name);
+ perror("\"");
+ } else {
+ if (output_level >= WHISPER) {
+ printf("%s has been removed\n", name);
+ }
+ }
+
+}
+
+static char *baseName(
+ char *pc
+){
+ char *p;
+
+/**
+ | Strips the (eventual) path information from the string pointed
+ | to by 'pc'; if no file name is given, returns an empty string.
+**/
+
+ p = strrchr(pc, '/');
+ if (p == 0) return pc;
+ return ++p;
+}
+
+static void putsMessage(
+ char *message,
+ int message_level
+){
+ if (message_level <= output_level) {
+ puts(message);
+ }
+}
+
+static void syntax()
+{
+ printf("lintex version %s\n", VERSION);
+ puts("Usage:");
+ printf(" %s [OPTIONS] [DIR [DIR ...]]\n", programName);
+ puts("Purpose:");
+ puts(" Removes unneeded TeX auxiliary files and editor backup files from"
+ " the");
+ puts(" given directories (default: the current directory); the TeX files"
+ " are");
+ puts(" actually removed only if their modification time is more recent"
+ " than");
+ puts(" the one of the related TeX source and if they aren't readonly.");
+ puts(" Please see the manpage for a list of extensions that get removed.");
+ puts("Options:");
+ puts(" -i : asks the user before removing any file;");
+ puts(" -r : scans recursively the subdirectories of the given");
+ puts(" directories;");
+ puts(" -b ext : \"ext\" is the trailing string identifying editor backup"
+ " files");
+ puts(" (defaults to \"~\"). -b \"\" avoids any cleanup of special");
+ puts(" files;");
+ puts(" -p : pretend, show what files would be removed but don't actually");
+ puts(" remove them;");
+ puts(" -k : keeps final document (.pdf, .ps, .dvi);");
+ puts(" -o : permit removal of files older than their sources;");
+ puts(" -q : quiet, only print error messages;");
+ puts(" -v : verbose, prints which files were removed and which weren't;");
+ puts(" -d : debug output, prints the answers to all of life's questions.");
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/support/lintex/lintex.com b/support/lintex/lintex.com
new file mode 100644
index 0000000000..6c77c6facd
--- /dev/null
+++ b/support/lintex/lintex.com
@@ -0,0 +1,90 @@
+$! Last Rev.: MLO 1996-03-18
+$! File: LINTEX.COM --- To delete TeX-related garbage (files with extensions
+$! .DVI, .AUX, .TOC, ...)
+$! @LINTEX deletes TeX-related files only if a .TEX exists
+$! @LINTEX F ('force') deletes TeX-related files anyway
+$! @LINTEX C ('confirm') asks user if a .TEX does not exists
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$ ver = f$verify(0)
+$ say := write sys$output
+$!
+$ if p1 .eqs. ""
+$ then
+$ opt = ""
+$ else
+$ opt = f$extract(0, 1, f$edit(p1, "upcase"))
+$ if opt.nes."F" .and. opt.nes."C"
+$ then
+$ say "''opt': invalid option"
+$ exit
+$ endif
+$ endif
+$!
+$ filext = "DVI/AUX/TOC/LIS/LOF/LOT/PS"
+$ numext = 0
+$!
+$ purge /log
+$!
+$ eloop: ext = f$element(numext, "/", filext)
+$ if ext .nes. "/"
+$ then
+$ filnam = "*." + ext
+$ floop: file = f$search(filnam, 1)
+$ if file .nes. ""
+$ then
+$ first = f$locate("]", file)
+$ len = f$length(file)
+$ if first .eq. len
+$ then
+$ short = file
+$ else
+$ short = f$extract(first+1, len, file)
+$ endif
+$ filedate = f$cvtime(f$file(file, "cdt"))
+$ gosub delchk
+$ goto floop
+$ endif
+$ numext = numext + 1
+$ goto eloop
+$ endif
+$!
+$ if ver then set verify
+$ exit
+$!
+$! SUBROUTINE DELCHK
+$!
+$ delchk:
+$ texfile = f$parse(".tex;", file)
+$ tex = f$search(texfile, 2)
+$ if tex .eqs. ""
+$ then
+$ errmes = "a .TEX file does not exist."
+$ gosub chkopt
+$ else
+$ texdate = f$cvtime(f$file(tex, "cdt"))
+$ if texdate .les. filedate
+$ then
+$ delete /log 'file'
+$ else
+$ errmes = "the .TEX file is newer."
+$ gosub chkopt
+$ endif
+$ endif
+$ return
+$!
+$! SUBROUTINE CHKOPT
+$!
+$ chkopt:
+$ if opt.eqs."F"
+$ then
+$ delete /log 'file'
+$ else
+$ if opt.eqs."C"
+$ then
+$ delete /log /confirm 'file'
+$ else
+$ say "--> ''short' not deleted; ''errmes'"
+$ endif
+$ endif
+$ return
diff --git a/support/lintex/lintex.pdf b/support/lintex/lintex.pdf
new file mode 100644
index 0000000000..4bbb58b6e5
--- /dev/null
+++ b/support/lintex/lintex.pdf
Binary files differ
diff --git a/support/lintex/lintexrc b/support/lintex/lintexrc
new file mode 100644
index 0000000000..45f77d192a
--- /dev/null
+++ b/support/lintex/lintexrc
@@ -0,0 +1,2 @@
+keep-exts = [".pdf", ".ps", ".dvi"];
+remove-exts = [".glo", ".gls"];
diff --git a/support/lintex/mktests.sh b/support/lintex/mktests.sh
new file mode 100644
index 0000000000..6f97bc3150
--- /dev/null
+++ b/support/lintex/mktests.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+mkdir -p test/dir1
+for ext in foo bar dir1/baz; do \
+ touch test/${ext}.tex; \
+done
+sleep 1
+for test in foo bar dir1/baz; do \
+ for ext in pdf ps dvi log aux; do \
+ touch test/${test}.${ext}; \
+ done; \
+done
+sleep 1
+touch test/foo.tex