summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/context/perl/texutil.pl
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2006-01-09 01:54:09 +0000
committerKarl Berry <karl@freefriends.org>2006-01-09 01:54:09 +0000
commit50b347972956e0bfbe7029305e0f459e5ce3ac0c (patch)
treed1b824bbc33a30bf7fcf54b866a1cff949d2e0bf /Master/texmf-dist/scripts/context/perl/texutil.pl
parent52f01b2f769ac290674a469d46f149985042ee2e (diff)
trunk/Master/texmf-dist/scripts
git-svn-id: svn://tug.org/texlive/trunk@92 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/scripts/context/perl/texutil.pl')
-rw-r--r--Master/texmf-dist/scripts/context/perl/texutil.pl2902
1 files changed, 2902 insertions, 0 deletions
diff --git a/Master/texmf-dist/scripts/context/perl/texutil.pl b/Master/texmf-dist/scripts/context/perl/texutil.pl
new file mode 100644
index 00000000000..0a0d2975354
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/perl/texutil.pl
@@ -0,0 +1,2902 @@
+eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $argv:q'
+ if 0;
+
+#D \module
+#D [ file=texutil.pl,
+#D version=2003.09.16,
+#D title=pre- and postprocessing utilities,
+#D subtitle=\TEXUTIL,
+#D author=Hans Hagen,
+#D date=\currentdate,
+#D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+#C
+#C This module is part of the \CONTEXT\ macro||package and is
+#C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+#C details.
+
+# much functionality will move to ctxtools, xmltools and pdftools; that way texutil
+# becomes limited to tui processing only, which is cleaner (also for taco's binary
+# version)
+
+# Thanks to Tobias Burnus for the german translations.
+# Thanks to Thomas Esser for hooking it into web2c
+# Thanks to Taco Hoekwater for making the file -w proof and some fixes
+# Thanks to Alex Knowles and friends for the right JPG specs
+# Thanks to Sebastian Rahtz for the eps to PDF method
+# Thanks to Fabrice Popineau for windows bin code
+
+#D We started with a hack provided by Thomas Esser. This
+#D expression replaces the unix specific line \type
+#D {#!/usr/bin/perl}.
+
+# undocumented:
+#
+# --analyze file.pdf : reports some statistics
+# --purge [jobname] : removes temporary files
+# --purgeall [jobname] : removes all temporary files
+
+#D This is \TEXUTIL, a utility program (script) to be used
+#D alongside the \CONTEXT\ macro package. This \PERL\ script is
+#D derived from the \MODULA\ version and uses slightly better
+#D algoritms for sanitizing \TEX\ specific (sub|)|strings.
+#D
+#D This implementation has some features not found in the
+#D binary version, like scanning illustrations other than \EPS.
+#D I would suggest to keep an eye on the version number:
+
+$Program = "TeXUtil 9.0.0 - ConTeXt / PRAGMA ADE 1992-2004" ;
+
+#D By the way, this is my first \PERL\ script, which means
+#D that it will be improved as soon as I find new and/or more
+#D suitable solutions in the \PERL\ manuals. As can be seen in
+#D the definition of \type{$Program}, this program is part of
+#D the \CONTEXT\ suite, and therefore can communicate with the
+#D users in english as well as some other languages. One can
+#D set his favourite language by saying something like:
+
+#D \starttypen
+#D perl texutil.pl --int=de --fig *.eps *.tif *.pdf *.png *.jpg
+#D \stoptypen
+#D
+#D or simpler:
+#D
+#D \starttypen
+#D perl texutil.pl --fig *.*
+#D \stoptypen
+
+#D Of course one can also say \type{--interface=nl}, which
+#D happens to be my native language.
+
+#D I won't go into too much detail on the algoritms used.
+#D The next few pages show the functionality as reported by the
+#D helpinformation and controled by command line arguments
+#D and can serve as additional documentation.
+
+#D \TEXUTIL\ can handle different tasks; which one is active
+#D depends on the command line arguments. These are handled by
+#D a \PERL\ system module. This means that, at least for the
+#D moment, there is no external control as provided by the
+#D \PRAGMA\ environment system.
+
+use Getopt::Long ;
+use FindBin ;
+
+#D We don't want error messages and accept partial switches,
+#D which saves users some typing.
+
+$Getopt::Long::passthrough = 1 ; # no error message
+$Getopt::Long::autoabbrev = 1 ; # partial switch accepted
+
+#D We also predefine the interface language and set a boolean
+#D that keeps track of unknown options. \voetnoot {This feature
+#D is still to be implemented.}
+
+$UserInterface = "en" ;
+$UnknownOptions = 0 ;
+$TcXPath = '' ;
+
+#D We need this for calling GS.
+
+use Config ;
+
+my $dosish = ($Config{'osname'} =~ /^(ms)?dos|^os\/2|^(ms|cyg)win/i) ;
+
+#D Here come the options:
+
+&GetOptions
+ ("references" => \$ProcessReferences,
+ "ij" => \$ProcessIJ,
+ "high" => \$ProcessHigh,
+ "quotes" => \$ProcessQuotes,
+ "tcxpath=s" => \$TcXPath,
+ "documents" => \$ProcessDocuments,
+ "type=s" => \$ProcessType,
+ "outputfile=s" => \$ProcessOutputFile,
+ "sources" => \$ProcessSources,
+ "setups" => \$ProcessSetups,
+ "templates" => \$ProcessTemplates,
+ "infos" => \$ProcessInfos,
+ "figures" => \$ProcessFigures,
+ "epspage" =>\$ProcessEpsPage,
+ "epstopdf" =>\$ProcessEpsToPdf,
+ "logfile" => \$ProcessLogFile,
+ "box" =>\$ProcessBox,
+ "hbox" =>\$ProcessHBox,
+ "vbox" =>\$ProcessVBox,
+ "criterium=f" =>\$ProcessCriterium,
+ "unknown" =>\$ProcessUnknown,
+ "purge" => \$PurgeFiles,
+ "purgeall" => \$PurgeAllFiles,
+ "analyze" => \$AnalyzeFile,
+ "filter" => \$FilterPages,
+ "help" => \$ProcessHelp,
+ "silent" => \$ProcessSilent,
+ "verbose" => \$ProcessVerbose,
+ "interface=s" => \$UserInterface) ;
+
+# A bit old, this code, could be an array. Anyhow, we will
+# replace texutil soon.
+
+$InputFile = "@ARGV" ; # niet waterdicht
+
+#D We need some hacks to suppress terminal output. This
+#D piece of code is based on page~193 of "Programming Perl".
+
+$ProgramLog = "texutil.log" ;
+
+# Well, it seems that unix' symlinks are sensitive for being
+# hijacked. The assumption is that a known file can be a problem.
+# Of course when one knows that certains files are processed,
+# the names are always known and hijacking can always take
+# place. But let's use a slightly less predictable name here:
+#
+# if ((@ARGV[0]) && (@ARGV[0] ne "")) {
+# $ProgramLog = "@ARGV[0]-$ProgramLog" ;
+# } else {
+# # no need to be silent
+# $ProcessSilent = 0 ;
+# }
+#
+# or better, let's drop this feature, since i'm not in the mood
+# now to test hacks like this (i'll just wait till the age of
+# computer anarchy has ended).
+
+$ProgramLog = "/dev/null" ;
+
+# Maybe we should just write to the nul device. (In the rewritten
+# version I can treat unix more strick.)
+
+sub RedirectTerminal
+ { open SAVEDSTDOUT, ">&STDOUT" ;
+ open STDOUT, ">$ProgramLog" ;
+ select STDOUT; $| = 1 }
+
+#D And, indeed:
+
+if ($ProcessSilent)
+ { RedirectTerminal }
+else
+ { $ProcessVerbose = 0 }
+
+#D We can temporary open the terminal channel.
+
+sub OpenTerminal
+ { close STDOUT ;
+ open STDOUT, ">&SAVEDSTDOUT" }
+
+sub CloseTerminal
+ { open SAVEDSTDOUT, ">&STDOUT" ;
+ open STDOUT, ">>$ProgramLog" ;
+ select STDOUT; $| = 1 }
+
+#D By default wildcards are expanded into a list. The
+#D subroutine below is therefore only needed when no file or
+#D pattern is given.
+
+sub CompFileName
+ { my ($a,$b) = @_ ;
+ my ($fa,$sa) = split(/\./,$a) ;
+ my ($fb,$sb) = split(/\./,$b) ;
+ if (($sa =~ /^\d+$/o)&&($sb =~ /^\d+$/o))
+ { $a = $fa . "." . sprintf("%10d",$sa) ; $a =~ s/\s/0/o ;
+ $b = $fb . "." . sprintf("%10d",$sb) ; $b =~ s/\s/0/o }
+ return (lc ($a) cmp lc ($b)) }
+
+sub CheckInputFiles
+ { @UserSuppliedFiles = glob $_[0] ;
+ @UserSuppliedFiles = sort { CompFileName($a,$b) } @UserSuppliedFiles }
+
+#D The next subroutine takes care of the optional output
+#D filename (e.g. for figure dimensions).
+
+$ProcessOutputFile = "" ;
+
+my $Rubish ;
+
+sub SetOutputFile
+ { ($OutFilNam, $OutFilSuf) = split (/\./, $_[0], 2) ;
+ unless ($ProcessOutputFile eq "")
+ { $ProcessOutputFile .= "." . $OutFilSuf ;
+ ($OutFilNam, $OutFilSuf, $Rubish) = split (/\./, $ProcessOutputFile , 3)}
+ $OutputFile = $OutFilNam . "." . $OutFilSuf }
+
+#D Sometimes we need to split filenames.
+
+my ($FileName, $FileSuffix) = ("","") ;
+
+sub SplitFileName
+ { my $Rubish = "" ;
+ if ($_[0] =~ /^\.\//)
+ { ($Rubish, $FileName) = split ( /^\.\//, $_[0], 2) }
+ else
+ { $FileName = $_[0] }
+ return split (/\./, $FileName, 2) }
+
+#D In order to support multiple interfaces, we save the
+#D messages in a hash table. As a bonus we can get a quick
+#D overview of the messages we deal with.
+
+my %MS ;
+
+sub Report
+ { foreach $_ (@_)
+ { if (! defined $MS{$_})
+ { print $_ }
+ else
+ { print $MS{$_} }
+ print " " }
+ print "\n" }
+
+#D The messages are saved in a hash table and are called
+#D by name. This contents of this table depends on the
+#D interface language in use.
+
+#D \startcompressdefinitions
+
+if ($UserInterface eq "nl")
+
+ { # begin of dutch section
+
+ $MS{"ProcessingReferences"} = "commando's, lijsten en indexen verwerken" ;
+ $MS{"MergingReferences"} = "indexen samenvoegen" ;
+ $MS{"GeneratingDocumentation"} = "ConTeXt documentatie file voorbereiden" ;
+ $MS{"GeneratingSources"} = "ConTeXt broncode file genereren" ;
+ $MS{"FilteringDefinitions"} = "ConTeXt definities filteren" ;
+ $MS{"CopyingTemplates"} = "TeXEdit toets templates copieren" ;
+ $MS{"CopyingInformation"} = "TeXEdit help informatie copieren" ;
+ $MS{"GeneratingFigures"} = "figuur file genereren" ;
+ $MS{"FilteringLogFile"} = "log file filteren (poor mans version)" ;
+
+ $MS{"SortingIJ"} = "IJ sorteren onder Y" ;
+ $MS{"ConvertingHigh"} = "hoge ASCII waarden converteren" ;
+ $MS{"ProcessingQuotes"} = "characters met accenten afhandelen" ;
+ $MS{"ForcingFileType"} = "filetype instellen" ;
+ $MS{"UsingEps"} = "EPS files afhandelen" ;
+ $MS{"UsingTif"} = "TIF files afhandelen" ;
+ $MS{"UsingPdf"} = "PDF files afhandelen" ;
+ $MS{"UsingPng"} = "PNG files afhandelen" ;
+ $MS{"UsingJpg"} = "JPG files afhandelen" ;
+ $MS{"EpsToPdf"} = "EPS converteren naar PDF";
+ $MS{"EpsPage"} = "EPS pagina instellen";
+ $MS{"FilteringBoxes"} = "overfull boxes filteren" ;
+ $MS{"ApplyingCriterium"} = "criterium toepassen" ;
+ $MS{"FilteringUnknown"} = "onbekende ... filteren" ;
+
+ $MS{"NoInputFile"} = "geen invoer file opgegeven" ;
+ $MS{"NoOutputFile"} = "geen uitvoer file gegenereerd" ;
+ $MS{"EmptyInputFile"} = "lege invoer file" ;
+ $MS{"NotYetImplemented"} = "nog niet beschikbaar" ;
+
+ $MS{"Action"} = " actie :" ;
+ $MS{"Option"} = " optie :" ;
+ $MS{"Error"} = " fout :" ;
+ $MS{"Remark"} = " opmerking :" ;
+ $MS{"SystemCall"} = " systeemaanroep :" ;
+ $MS{"BadSystemCall"} = " foute systeemaanroep :" ;
+ $MS{"MissingSubroutine"} = " onbekende subroutine :" ;
+
+ $MS{"EmbeddedFiles"} = " gebruikte files :" ;
+ $MS{"BeginEndError"} = " b/e fout in :" ;
+ $MS{"SynonymEntries"} = " aantal synoniemen :" ;
+ $MS{"SynonymErrors"} = " fouten :" ;
+ $MS{"RegisterEntries"} = " aantal ingangen :" ;
+ $MS{"RegisterErrors"} = " fouten :" ;
+ $MS{"PassedCommands"} = " aantal commando's :" ;
+
+ $MS{"MultiPagePdfFile"} = " te veel pagina's :" ;
+ $MS{"MissingMediaBox"} = " geen mediabox :" ;
+ $MS{"MissingBoundingBox"} = " geen boundingbox :" ;
+
+ $MS{"NOfDocuments"} = " documentatie blokken :" ;
+ $MS{"NOfDefinitions"} = " definitie blokken :" ;
+ $MS{"NOfSkips"} = " overgeslagen blokken :" ;
+ $MS{"NOfSetups"} = " gecopieerde setups :" ;
+ $MS{"NOfTemplates"} = " gecopieerde templates :" ;
+ $MS{"NOfInfos"} = " gecopieerde helpinfos :" ;
+ $MS{"NOfFigures"} = " verwerkte figuren :" ;
+ $MS{"NOfBoxes"} = " te volle boxen :" ;
+ $MS{"NOfUnknown"} = " onbekende ... :" ;
+
+ $MS{"InputFile"} = " invoer file :" ;
+ $MS{"OutputFile"} = " outvoer file :" ;
+ $MS{"FileType"} = " type file :" ;
+ $MS{"EpsFile"} = " eps file :" ;
+ $MS{"PdfFile"} = " pdf file :" ;
+ $MS{"TifFile"} = " tif file :" ;
+ $MS{"PngFile"} = " png file :" ;
+ $MS{"JpgFile"} = " jpg file :" ;
+ $MS{"MPFile"} = " metapost file :" ;
+
+ $MS{"LoadedFilter"} = " geladen filter :" ;
+ $MS{"RemappedKeys"} = " onderschepte keys :" ;
+ $MS{"WrongFilterPath"} = " fout filter pad :" ;
+
+ $MS{"Overfull"} = "te vol" ;
+ $MS{"Entries"} = "ingangen" ;
+ $MS{"References"} = "verwijzingen" ;
+
+ $MS{"PlugInInit"} = " plugin initialized :" ;
+ $MS{"PlugInReport"} = " plugin report :" ;
+
+ } # end of dutch section
+
+elsif ($UserInterface eq "de")
+
+ { # begin of german section
+
+ $MS{"ProcessingReferences"} = "Verarbeiten der Befehle, Listen und Register" ;
+ $MS{"MergingReferences"} = "Register verschmelzen" ;
+ $MS{"GeneratingDocumentation"} = "Vorbereiten der ConTeXt-Dokumentationsdatei" ;
+ $MS{"GeneratingSources"} = "Erstellen einer nur Quelltext ConTeXt-Datei" ;
+ $MS{"FilteringDefinitions"} = "Filtern der ConTeXt-Definitionen" ;
+ $MS{"CopyingTemplates"} = "Kopieren der TeXEdit-Test-key-templates" ;
+ $MS{"CopyingInformation"} = "Kopieren der TeXEdit-Hilfsinformation" ;
+ $MS{"GeneratingFigures"} = "Erstellen einer Abb-Uebersichtsdatei" ;
+ $MS{"FilteringLogFile"} = "Filtern der log-Datei" ;
+
+ $MS{"SortingIJ"} = "Sortiere IJ nach Y" ;
+ $MS{"ConvertingHigh"} = "Konvertiere hohe ASCII-Werte" ;
+ $MS{"ProcessingQuotes"} = "Verarbeiten der Akzentzeichen" ;
+ $MS{"ForcingFileType"} = "Dateityp einstellen" ;
+ $MS{"UsingEps"} = "EPS-Dateien verarbeite" ;
+ $MS{"UsingTif"} = "TIF-Dateien verarbeite" ;
+ $MS{"UsingPdf"} = "PDF-Dateien verarbeite" ;
+ $MS{"UsingPng"} = "PNG-Dateien verarbeite" ;
+ $MS{"UsingJpg"} = "JPG-Dateien verarbeite" ;
+ $MS{"EpsToPdf"} = "convert EPS to PDF";
+ $MS{"EpsPage"} = "setup EPS page";
+
+ $MS{"FilteringBoxes"} = "Filtern der ueberfuellten Boxen" ;
+ $MS{"ApplyingCriterium"} = "Anwenden des uebervoll-Kriteriums" ;
+ $MS{"FilteringUnknown"} = "Filter unbekannt ..." ;
+
+ $MS{"NoInputFile"} = "Keine Eingabedatei angegeben" ;
+ $MS{"NoOutputFile"} = "Keine Ausgabedatei generiert" ;
+ $MS{"EmptyInputFile"} = "Leere Eingabedatei" ;
+ $MS{"NotYetImplemented"} = "Noch nicht verfuegbar" ;
+
+ $MS{"Action"} = " Aktion :" ;
+ $MS{"Option"} = " Option :" ;
+ $MS{"Error"} = " Fehler :" ;
+ $MS{"Remark"} = " Anmerkung :" ;
+ $MS{"SystemCall"} = " system call :" ;
+ $MS{"BadSystemCall"} = " bad system call :" ;
+ $MS{"MissingSubroutine"} = " missing subroutine :" ;
+ $MS{"SystemCall"} = " Systemaufruf :" ;
+ $MS{"BadSystemCall"} = " Fehlerhafter Aufruf :" ;
+ $MS{"MissingSubroutine"} = " Fehlende Unterroutine :" ;
+
+ $MS{"EmbeddedFiles"} = " Eingebettete Dateien :" ;
+ $MS{"BeginEndError"} = " Beg./Ende-Fehler in :" ;
+ $MS{"SynonymEntries"} = " Synonymeintraege :" ;
+ $MS{"SynonymErrors"} = " Fehlerhafte Eintraege :" ;
+ $MS{"RegisterEntries"} = " Registereintraege :" ;
+ $MS{"RegisterErrors"} = " Fehlerhafte Eintraege :" ;
+ $MS{"PassedCommands"} = " Verarbeite Befehle :" ;
+
+ $MS{"MultiPagePdfFile"} = " zu viele Seiten :" ;
+ $MS{"MissingMediaBox"} = " fehlende mediabox :" ;
+ $MS{"MissingBoundingBox"} = " fehlende boundingbox :" ;
+
+ $MS{"NOfDocuments"} = " Dokumentbloecke :" ;
+ $MS{"NOfDefinitions"} = " Definitionsbloecke :" ;
+ $MS{"NOfSkips"} = "Uebersprungene Bloecke :" ;
+ $MS{"NOfSetups"} = " Kopierte setups :" ;
+ $MS{"NOfTemplates"} = " Kopierte templates :" ;
+ $MS{"NOfInfos"} = " Kopierte helpinfos :" ;
+ $MS{"NOfFigures"} = " Verarbeitete Abb. :" ;
+ $MS{"NOfBoxes"} = " Zu volle Boxen :" ;
+ $MS{"NOfUnknown"} = " Unbekannt ... :" ;
+
+ $MS{"InputFile"} = " Eingabedatei :" ;
+ $MS{"OutputFile"} = " Ausgabedatei :" ;
+ $MS{"FileType"} = " Dateityp :" ;
+ $MS{"EpsFile"} = " eps-Datei :" ;
+ $MS{"PdfFile"} = " pdf-Datei :" ;
+ $MS{"TifFile"} = " tif-Datei :" ;
+ $MS{"PngFile"} = " png-Datei :" ;
+ $MS{"JpgFile"} = " jpg-Datei :" ;
+ $MS{"MPFile"} = " metapost-Datei :" ;
+
+ $MS{"LoadedFilter"} = " loaded filter :" ; # tobias
+ $MS{"RemappedKeys"} = " remapped keys :" ; # tobias
+ $MS{"WrongFilterPath"} = " wrong filter path :" ; # tobias
+
+ $MS{"Overfull"} = "zu voll" ;
+ $MS{"Entries"} = "Eintraege" ;
+ $MS{"References"} = "Referenzen" ;
+
+ $MS{"ExtraProgram"} = " extra program :" ;
+ $MS{"PlugInInit"} = " plugin initialized :" ;
+ $MS{"PlugInReport"} = " plugin report :" ;
+
+ } # end of german section
+
+elsif ($UserInterface eq "it")
+
+ { # begin of italian section
+
+ $MS{"ProcessingReferences"} = "elaborazione di comandi, liste e registri" ;
+ $MS{"MergingReferences"} = "fusione dei registri" ;
+ $MS{"GeneratingDocumentation"} = "preparazione del file di documentazione ConTeXt" ;
+ $MS{"GeneratingSources"} = "generazione del solo sorgente ConTeXt" ;
+ $MS{"FilteringDefinitions"} = "filtraggio delle definizioni formali ConTeXt" ;
+ $MS{"CopyingTemplates"} = "copia dei modelli rapidi di voci di TeXEdit" ;
+ $MS{"CopyingInformation"} = "copia delle informazioni di aiuto di TeXEdit" ;
+ $MS{"GeneratingFigures"} = "generazione del file di elengo delle figure" ;
+ $MS{"FilteringLogFile"} = "filtraggio del file di log" ;
+
+ $MS{"SortingIJ"} = "IJ elencato sotto Y" ;
+ $MS{"ConvertingHigh"} = "conversione dei valori ASCII alti" ;
+ $MS{"ProcessingQuotes"} = "elaborazione dei caratteri accentati" ;
+ $MS{"ForcingFileType"} = "impostazine del tipo di file" ;
+ $MS{"UsingEps"} = "elaborazione del file EPS" ;
+ $MS{"UsingTif"} = "elaborazione del file TIF" ;
+ $MS{"UsingPdf"} = "elaborazione del file PDF" ;
+ $MS{"UsingPng"} = "elaborazione del file PNG" ;
+ $MS{"UsingJpg"} = "elaborazione del file JPG" ;
+ $MS{"EpsToPdf"} = "conversione da EPS a PDF";
+ $MS{"EpsPage"} = "impostazione pagina EPS";
+
+ $MS{"FilteringBoxes"} = "filtraggio delle overfull boxes" ;
+ $MS{"ApplyingCriterium"} = "applicazione del criterio overfull" ;
+ $MS{"FilteringUnknown"} = "filtraggio dei messaggi non conosciuti ..." ;
+
+ $MS{"NoInputFile"} = "nessun file di input specificato" ;
+ $MS{"NoOutputFile"} = "nessun file di output generato" ;
+ $MS{"EmptyInputFile"} = "file di input vuoto" ;
+ $MS{"NotYetImplemented"} = "non ancora disponibile" ;
+
+ $MS{"Action"} = " azione :" ;
+ $MS{"Option"} = " opzione :" ;
+ $MS{"Error"} = " errore :" ;
+ $MS{"Remark"} = " commento :" ;
+ $MS{"SystemCall"} = " chiamata di sistema :" ;
+ $MS{"BadSystemCall"} = "chiamata di sistema er :" ; # GB: Hans, I need more space!
+ $MS{"MissingSubroutine"} = " subroutine mancante :" ;
+
+ $MS{"EmbeddedFiles"} = " file inclusi :" ;
+ $MS{"BeginEndError"} = " errore di i/f in :" ;
+ $MS{"SynonymEntries"} = " voci di sinonimi :" ;
+ $MS{"SynonymErrors"} = " voci errate :" ;
+ $MS{"RegisterEntries"} = " voci di registro :" ;
+ $MS{"RegisterErrors"} = " voci errate :" ;
+ $MS{"PassedCommands"} = " comandi passati :" ;
+
+ $MS{"MultiPagePdfFile"} = " troppe pagine :" ;
+ $MS{"MissingMediaBox"} = " mediabox mancante :" ;
+ $MS{"MissingBoundingBox"} = " boundingbox mancante :" ;
+
+ $MS{"NOfDocuments"} = " blocchi di documento :" ;
+ $MS{"NOfDefinitions"} = "blocchi di definizioni :" ;
+ $MS{"NOfSkips"} = " blocchi saltati :" ;
+ $MS{"NOfSetups"} = " impostazioni copiate :" ;
+ $MS{"NOfTemplates"} = " modelli copiati :" ;
+ $MS{"NOfInfos"} = " helpinfo copiati :" ;
+ $MS{"NOfFigures"} = " figure elaborate :" ;
+ $MS{"NOfBoxes"} = " overfull boxes :" ;
+ $MS{"NOfUnknown"} = " sconosciuti ... :" ;
+
+ $MS{"InputFile"} = " file di input :" ;
+ $MS{"OutputFile"} = " file di output :" ;
+ $MS{"FileType"} = " tipo di file :" ;
+ $MS{"EpsFile"} = " file eps :" ;
+ $MS{"PdfFile"} = " file pdf :" ;
+ $MS{"TifFile"} = " file tif :" ;
+ $MS{"PngFile"} = " file png :" ;
+ $MS{"JpgFile"} = " file jpg :" ;
+ $MS{"MPFile"} = " file metapost :" ;
+
+ $MS{"LoadedFilter"} = " filtro caricato :" ;
+ $MS{"RemappedKeys"} = " voci rimappate :" ;
+ $MS{"WrongFilterPath"} = "percorso filtro errato :" ;
+
+ $MS{"Overfull"} = "overfull" ;
+ $MS{"Entries"} = "voci" ;
+ $MS{"References"} = "riferimenti" ;
+
+ $MS{"ExtraProgram"} = " extra program :" ;
+ $MS{"PlugInInit"} = " plugin initialized :" ;
+ $MS{"PlugInReport"} = " plugin report :" ;
+
+ } # end of italian section
+
+else
+
+ { # begin of english section
+
+ $MS{"ProcessingReferences"} = "processing commands, lists and registers" ;
+ $MS{"MergingReferences"} = "merging registers" ;
+ $MS{"GeneratingDocumentation"} = "preparing ConTeXt documentation file" ;
+ $MS{"GeneratingSources"} = "generating ConTeXt source only file" ;
+ $MS{"FilteringDefinitions"} = "filtering formal ConTeXt definitions" ;
+ $MS{"CopyingTemplates"} = "copying TeXEdit quick key templates" ;
+ $MS{"CopyingInformation"} = "copying TeXEdit help information" ;
+ $MS{"GeneratingFigures"} = "generating figure directory file" ;
+ $MS{"FilteringLogFile"} = "filtering log file" ;
+
+ $MS{"SortingIJ"} = "sorting IJ under Y" ;
+ $MS{"ConvertingHigh"} = "converting high ASCII values" ;
+ $MS{"ProcessingQuotes"} = "handling accented characters" ;
+ $MS{"ForcingFileType"} = "setting up filetype" ;
+ $MS{"UsingEps"} = "processing EPS-file" ;
+ $MS{"UsingTif"} = "processing TIF-file" ;
+ $MS{"UsingPdf"} = "processing PDF-file" ;
+ $MS{"UsingPng"} = "processing PNG-file" ;
+ $MS{"UsingJpg"} = "processing JPG-file" ;
+ $MS{"EpsToPdf"} = "convert EPS to PDF";
+ $MS{"EpsPage"} = "setup EPS page";
+
+ $MS{"FilteringBoxes"} = "filtering overfull boxes" ;
+ $MS{"ApplyingCriterium"} = "applying overfull criterium" ;
+ $MS{"FilteringUnknown"} = "filtering unknown ..." ;
+
+ $MS{"NoInputFile"} = "no input file given" ;
+ $MS{"NoOutputFile"} = "no output file generated" ;
+ $MS{"EmptyInputFile"} = "empty input file" ;
+ $MS{"NotYetImplemented"} = "not yet available" ;
+
+ $MS{"Action"} = " action :" ;
+ $MS{"Option"} = " option :" ;
+ $MS{"Error"} = " error :" ;
+ $MS{"Remark"} = " remark :" ;
+ $MS{"SystemCall"} = " system call :" ;
+ $MS{"BadSystemCall"} = " bad system call :" ;
+ $MS{"MissingSubroutine"} = " missing subroutine :" ;
+
+ $MS{"EmbeddedFiles"} = " embedded files :" ;
+ $MS{"BeginEndError"} = " b/e error in :" ;
+ $MS{"SynonymEntries"} = " synonym entries :" ;
+ $MS{"SynonymErrors"} = " bad entries :" ;
+ $MS{"RegisterEntries"} = " register entries :" ;
+ $MS{"RegisterErrors"} = " bad entries :" ;
+ $MS{"PassedCommands"} = " passed commands :" ;
+
+ $MS{"MultiPagePdfFile"} = " too many pages :" ;
+ $MS{"MissingMediaBox"} = " missing mediabox :" ;
+ $MS{"MissingBoundingBox"} = " missing boundingbox :" ;
+
+ $MS{"NOfDocuments"} = " document blocks :" ;
+ $MS{"NOfDefinitions"} = " definition blocks :" ;
+ $MS{"NOfSkips"} = " skipped blocks :" ;
+ $MS{"NOfSetups"} = " copied setups :" ;
+ $MS{"NOfTemplates"} = " copied templates :" ;
+ $MS{"NOfInfos"} = " copied helpinfos :" ;
+ $MS{"NOfFigures"} = " processed figures :" ;
+ $MS{"NOfBoxes"} = " overfull boxes :" ;
+ $MS{"NOfUnknown"} = " unknown ... :" ;
+
+ $MS{"InputFile"} = " input file :" ;
+ $MS{"OutputFile"} = " output file :" ;
+ $MS{"FileType"} = " file type :" ;
+ $MS{"EpsFile"} = " eps file :" ;
+ $MS{"PdfFile"} = " pdf file :" ;
+ $MS{"TifFile"} = " tif file :" ;
+ $MS{"PngFile"} = " png file :" ;
+ $MS{"JpgFile"} = " jpg file :" ;
+ $MS{"MPFile"} = " metapost file :" ;
+
+ $MS{"LoadedFilter"} = " loaded filter :" ;
+ $MS{"RemappedKeys"} = " remapped keys :" ;
+ $MS{"WrongFilterPath"} = " wrong filter path :" ;
+
+ $MS{"Overfull"} = "overfull" ;
+ $MS{"Entries"} = "entries" ;
+ $MS{"References"} = "references" ;
+
+ $MS{"ExtraProgram"} = " extra program :" ;
+ $MS{"PlugInInit"} = " plugin initialized :" ;
+ $MS{"PlugInReport"} = " plugin report :" ;
+
+ } # end of english section
+
+#D \stopcompressdefinitions
+
+#D Showing the banner (name and version of the program) and
+#D offering helpinfo is rather straightforward.
+
+sub ShowBanner
+ { Report("\n $Program\n") }
+
+sub ShowHelpInfo
+ { Report("HelpInfo") }
+
+#D The helpinfo is also saved in the hash table. This looks
+#D like a waste of energy and space, but the program gains
+#D readability.
+
+#D \startcompressdefinitions
+
+if ($UserInterface eq "nl")
+
+ { # begin of dutch section
+
+ $MS{"HelpInfo"} =
+
+" --references hulp file verwerken / tui->tuo \n" .
+" --ij : IJ als Y sorteren \n" .
+" --high : hoge ASCII waarden converteren \n" .
+" --quotes : quotes converteren \n" .
+" --tcxpath : tcx filter pad \n" .
+" \n" .
+" --purge(all) tijdelijke (klad) files verwijderen \n" .
+" \n" .
+" --documents documentatie file genereren / tex->ted \n" .
+" --sources broncode file genereren / tex->tes \n" .
+" --setups ConTeXt definities filteren / tex->texutil.tus \n" .
+" --templates TeXEdit templates filteren / tex->tud \n" .
+" --infos TeXEdit helpinfo filteren / tex->tud \n" .
+" \n" .
+" --figures eps figuren lijst genereren / *->texutil.tuf \n" .
+" --epspage : voorbereiden voor pdf \n" .
+" --epstopdf : omzetten naar pdf \n" .
+" \n" .
+" --logfile logfile filteren / log->$ProgramLog \n" .
+" --box : overfull boxes controleren \n" .
+" --criterium : overfull criterium in pt \n" .
+" --unknown :onbekende ... controleren \n" ;
+
+ } # end of dutch section
+
+elsif ($UserInterface eq "de")
+
+ { # begin of german section
+
+ $MS{"HelpInfo"} =
+
+" --references Verarbeiten der Hilfsdatei / tui->tuo \n" .
+" --ij : Sortiere IJ als Y \n" .
+" --high : Konvertiere hohe ASCII-Werte \n" .
+" --quotes : Konvertiere akzentuierte Buchstaben \n" .
+" --tcxpath : tcx Filter Path \n" .
+" \n" .
+" --purge(all) entferne temporaere ConTeXt-Dateien \n" .
+" \n" .
+" --documents Erstelle Dokumentationsdatei / tex->ted \n" .
+" --sources Erstelle reine Quelltextdateien / tex->tes \n" .
+" --setups Filtere ConTeXt-Definitionen / tex->texutil.tus\n" .
+" --templates Filtere TeXEdit-templates / tex->tud \n" .
+" --infos Filtere TeXEdit-helpinfo / tex->tud \n" .
+" \n" .
+" --figures Erstelle eps-Abbildungsliste / *->texutil.tuf \n" .
+" --epspage : Bereite fuer pdf vor \n" .
+" --epstopdf : Konvertiere zu pdf \n" .
+" \n" .
+" --logfile Filtere log-Datei / log->$ProgramLog \n" .
+" --box : Ueberpruefe uebervolle Boxen \n" .
+" --criterium : Uebervoll-Kriterium in pt \n" .
+" --unknown : Ueberpruefe auf unbekannte ... \n" ;
+
+ } # end of german section
+
+elsif ($UserInterface eq "it")
+
+ { # begin of italian section GB: Hans, I need more space!
+
+ $MS{"HelpInfo"} =
+
+" --references elabora file ausiliari / tui->tuo \n" .
+" --ij : elenca IJ come Y \n" .
+" --high : converti i valori ASCII alti \n" .
+" --quotes : converti caratteri accentati \n" .
+" --tcxpath : percorso del filtro tcx \n" .
+" \n" .
+" --purge(all) rimuovi i file temporanei ConTeXt \n" .
+" \n" .
+" --documents genera file di documentazione / tex->ted \n" .
+" --sources genera solo sorgente / tex->tes \n" .
+" --setups filtra definizioni ConTeXt / tex->texutil.tus \n" .
+" --templates filtra modelli TeXEdit / tex->tud \n" .
+" --infos filtra helpinfo TeXEdit / tex->tud \n" .
+" \n" .
+" --figures genera lista figure eps / *->texutil.tuf \n" .
+" --epspage : prepara per pdf \n" .
+" --epstopdf : converti in pdf \n" .
+" \n" .
+" --logfile filtra logfile / log->$ProgramLog \n" .
+" --box : controlla overful boxes \n" .
+" --criterium : criterio overfull in pt \n" .
+" --unknown : controlla sconosciuti ... \n" ;
+
+ } # end of italian section
+
+else
+
+ { # begin of english section
+
+ $MS{"HelpInfo"} =
+
+" --references process auxiliary file / tui->tuo \n" .
+" --ij : sort IJ as Y \n" .
+" --high : convert high ASCII values \n" .
+" --quotes : convert quotes characters \n" .
+" --tcxpath : tcx filter path \n" .
+" \n" .
+" --purge(all) clean up temporary context files \n" .
+" \n" .
+" --documents generate documentation file / tex->ted \n" .
+" --sources generate source only file / tex->tes \n" .
+" --setups filter ConTeXt definitions / tex->texutil.tus \n" .
+" --templates filter TeXEdit templates / tex->tud \n" .
+" --infos filter TeXEdit helpinfo / tex->tud \n" .
+" \n" .
+" --figures generate eps figure list / *->texutil.tuf \n" .
+" --epspage : prepare for pdf \n" .
+" --epstopdf : convert to pdf \n" .
+" \n" .
+" --logfile filter logfile / log->$ProgramLog \n" .
+" --box : check overful boxes \n" .
+" --criterium : overfull criterium in pt \n" .
+" --unknown : check unknown ... \n" ;
+
+ } # end of english section
+
+#D \stopcompressdefinitions
+
+#D In order to sort strings correctly, we have to sanitize
+#D them. This is especially needed when we include \TEX\
+#D commands, quotes characters and compound word placeholders.
+#D
+#D \startopsomming[opelkaar]
+#D \som \type{\name}: csnames are stripped
+#D \som \type{{}}: are removed
+#D \som \type{\"e}: and alike are translated into \type{"e} etc.
+#D \som \type{"e}: is translated into an \type{e} and \type{b} etc.
+#D \som \type{||}: becomes \type{-}
+#D \som \type{\-}: also becomes \type{-}
+#D \som \type{<*..>}: becomes \type{..} (internal XML entity)
+#D \stopopsomming
+#D
+#D Of course other accented characters are handled too. The
+#D appended string is responsible for decent sorting.
+#D
+#D \startPL
+#D $TargetString = SanitizedString ( $SourceString ) ;
+#D \stopPL
+#D
+#D The sort order depends on the ordering in array
+#D \type{$ASCII}:
+
+$ASCII{"^"} = "a" ; $ASCII{'"'} = "b" ; $ASCII{"`"} = "c" ;
+$ASCII{"'"} = "d" ; $ASCII{"~"} = "e" ; $ASCII{","} = "f" ;
+
+#sub SanitizedString
+# { my ($string) = $_[0] ;
+# if ($ProcessQuotes)
+# { $string =~ s/\\([\^\"\`\'\~\,])/$1/gio ;
+# $copied = $string ;
+# $copied =~ s/([\^\"\`\'\~\,])([a-zA-Z])/$ASCII{$1}/gio ;
+# $string =~ s/([\^\"\`\'\~\,])([a-zA-Z])/$2/gio ;
+# $string=$string.$copied }
+# $string =~ s/\\-|\|\|/\-/gio ;
+# $string =~ s/\\[a-zA-Z]*| |\{|\}//gio ;
+# return $string }
+
+#D YET UNDOCUMENTED
+
+my $SortN = 0 ; my @Filter ;
+
+# copied from texexec
+
+my @paths ;
+my $kpsewhich = '' ;
+my $pathslash = '/' ; if ($0 =~ /\\/) { $pathslash = "\\" }
+
+sub checked_path
+ { my $path = shift ;
+ if ((defined($path))&&($path ne ''))
+ { $path =~ s/[\/\\]/$pathslash/go ;
+ $path =~ s/[\/\\]*$//go ;
+ $path .= $pathslash }
+ else
+ { $path = '' }
+ return $path }
+
+if ($ENV{PATH} =~ /\;/)
+ { @paths = split(/\;/,$ENV{PATH}) }
+else
+ { @paths = split(/\:/,$ENV{PATH}) }
+
+# until here.
+
+sub InitializeKeys
+ { my $filename = $ARGV[0] ;
+ return unless (open(TEX,"$filename.tex")) ;
+ for ($i=0;$i<=255;$i++)
+ { @Filter[$i] = $i }
+ if ($TcXPath eq '')
+ { foreach (@paths)
+ { my $p = checked_path($_) . 'kpsewhich' ;
+ if ((-e $p)||(-e $p . '.exe'))
+ { $kpsewhich = $p ; last } } }
+ $kpsewhich = "\"$kpsewhich\"" if ($kpsewhich =~ m/^[^\"].* /) ;
+ while (<TEX>)
+ { chomp ;
+ my $Filter ;
+ if (/^\%/)
+ { if (s/.*translat.*?=([\:\/0-9\-a-z]*)/$1/oi)
+ { my $Translation = $_ ;
+ if ($TcXPath ne '')
+ { $TcXPath = checked_path($TcXPath) ;
+ $Filter = "$TcXPath$pathslash$Translation.tcx" }
+ elsif ($kpsewhich ne '')
+ { $Filter = `$kpsewhich --format="web2c files" $Translation.tcx` ;
+ chomp $Filter }
+ else
+ { last }
+ if (open(ASC,$Filter))
+ { Report ("LoadedFilter", $Translation) ;
+ while (<ASC>)
+ { if (/^(\d+)\s*(\d+)/)
+ { @Filter[$2] = $1 } }
+ close (ASC) }
+ elsif ($TcXPath ne '')
+ { Report ("WrongFilterPath", $TcXPath) }
+ last } }
+ else
+ { last } }
+ close (TEX) }
+
+sub HandleKey
+ { ++$SortN ;
+ $RestOfLine =~ s/\{(.*)\}/$1/o ;
+ my ($lan, $enc, $str, $chr, $map, $alf) = split(/\}\s*\{/, $RestOfLine) ;
+ if ($str =~ /^(\d+)/) { $str = ''.chr(@Filter[$1]) }
+ $map = chr(ord($MAP[$i])+128) ;
+ $STR[$SortN] = $str ;
+ $CHR[$SortN] = $chr ;
+ $MAP[$SortN] = $map ;
+#print "$chr$map = $alf\n" ;
+# $ALF{"$chr$map"} = $alf }
+ $ALF{"$map"} = $alf }
+
+sub FlushKeys
+ { Report ("RemappedKeys", $SortN) }
+
+sub SanitizedString
+ { my $string = my $original = shift ;
+ if ($SortN)
+ { my $copied = $string ;
+ for ($i=1;$i<=$SortN;$i++)
+ { my $s = $STR[$i] ;
+ my $c = $CHR[$i] ;
+ my $m = $MAP[$i] ;
+ # print "[$i $s $c $m]\n" ;
+ $string =~ s/($s)/$c/ge ;
+ $copied =~ s/($s)/$m/ge }
+ $string .= "\x00";
+ $string .= $copied }
+ elsif ($ProcessQuotes)
+ { $string =~ s/\\([\^\"\`\'\~\,])/$1/gio ;
+ $copied = $string ;
+ $copied =~ s/([\^\"\`\'\~\,])([a-zA-Z])/$ASCII{$1}/gi ;
+ $string =~ s/([\^\"\`\'\~\,])([a-zA-Z])/$2/gio ;
+ $string .= "\x00";
+ $string .= $copied }
+# new and very experimental, will change
+$string =~ s/\<\*(.*?)\>/\\$1 /go ; # reduce entities / will be table too
+$string =~ s/\\getXMLentity\s*\{(.*?)\}/$1/gio ; # {tex} => tex
+$string =~ s/\<[a-zA-Z\/].*?\>//go ; # remove elements
+# so far
+ $string =~ s/\\-|\|\|/\-/gio ;
+ $string =~ s/\\[a-zA-Z]*| |\{|\}//gio ; # ?
+#print "$original $string $copied\n" ;
+ return $string }
+
+#D This subroutine looks a bit complicated, which is due to the
+#D fact that we want to sort for instance an accented \type{e}
+#D after the plain \type{e}, so the imaginary words
+#D
+#D \starttypen
+#D eerste
+#D \"eerste
+#D \"e\"erste
+#D eerst\"e
+#D \stoptypen
+#D
+#D come out in an acceptable order.
+
+#D We also have to deal with the typical \TEX\ sequences with
+#D the double \type{^}'s, like \type{^^45}. These hexadecimal
+#D coded characters are just converted.
+#D
+#D \startPL
+#D $TargetString = HighConverted ( $SourceString ) ;
+#D \stopPL
+
+sub HighConverted
+ { my ($string) = $_[0] ;
+ $string =~ s/\^\^([a-f0-9][a-f0-9])/chr hex($1)/geo ;
+ return $string }
+
+#D \extras
+#D {references}
+#D
+#D \CONTEXT\ can handle many lists, registers (indexes),
+#D tables of whatever and references. This data is collected
+#D in one pass and processed in a second one. In between,
+#D relevant data is saved in the file \type{\jobname.tui}.
+#D This file also holds some additional information concerning
+#D second pass optimizations.
+#D
+#D The main task of \TEXUTIL\ is to sort lists and registers
+#D (indexes). The results are stored in again one file called
+#D \type{\jobname.tuo}.
+#D
+#D Just for debugging purposes the nesting of files loaded
+#D during the \CONTEXT\ run is stored. Of course this only
+#D applies to files that are handled by the \CONTEXT\ file
+#D structuring commands (projects, products, components and
+#D environments).
+#D
+#D We have to handle the entries:
+#D
+#D \starttypen
+#D f b {test}
+#D f e {test}
+#D \stoptypen
+#D
+#D and only report some status info at the end of the run.
+
+sub InitializeFiles
+ { $NOfFiles = 0 ;
+ $NOfBadFiles = 0 }
+
+sub HandleFile
+ { $RestOfLine =~ s/.*\{(.*)\}/$1/gio ;
+ ++$Files{$RestOfLine} }
+
+sub FlushFiles # hash needs to be sorted, else problem on macosx
+ { print TUO "%\n" . "% $Program / Files\n" . "%\n" ;
+ foreach $File (sort keys %Files)
+ { print TUO "% $File ($Files{$File})\n" }
+ print TUO "%\n" ;
+ $NOfFiles = keys %Files ;
+ Report("EmbeddedFiles", $NOfFiles) ;
+ foreach $File (sort keys %Files)
+ { unless (($Files{$File} % 2) eq 0)
+ { ++$NOfBadFiles ;
+ Report("BeginEndError", $File) } } }
+
+#D Commands don't need a special treatment. They are just
+#D copied. Such commands are tagged by a \type{c}, like:
+#D
+#D \starttypen
+#D c \thisisutilityversion{year.month.day}
+#D c \twopassentry{class}{key}{value}
+#D c \mainreference{prefix}{entry}{pagenumber}{realpage}{tag}
+#D c \listentry{category}{tag}{number}{title}{pagenumber}{realpage}
+#D c \initializevariable\realnumberofpages{number}
+#D \stoptypen
+#D
+#D For historic reasons we check for the presense of the
+#D backslash.
+
+my $NOfPositionsFound = 0 ;
+my $TotalNOfPositions = 0 ;
+my $TotalNOfMPgraphics = 0 ;
+
+my $SectionSeparator = ":" ;
+
+sub InitializeCommands
+ { print TUO "%\n" . "% $Program / Commands\n" . "%\n" ;
+ $NOfCommands = 0 }
+
+sub HandleCommand
+ { ++$NOfCommands ;
+ $RestOfLine =~ s/^\\//go ;
+ if ($RestOfLine =~ /^pospxy/o)
+ { ++$NOfPositionsFound }
+ elsif ($RestOfLine =~ /^initializevariable\\totalnofpositions\{(.*)\}/o)
+ { $TotalNOfPositions = $1 }
+ elsif ($RestOfLine =~ /^initializevariable\\totalnofMPgraphics\{(.*)\}/o)
+ { $TotalNOfMPgraphics = $1 }
+# todo: reg how to
+# elsif ($RestOfLine =~ /^thisissectionseparator\{(.*)\}/o)
+# { $SectionSeparator = $1 }
+ elsif ($RestOfLine =~ /^thisisbytesequence\{(.*)\}/o)
+ { $RestOfLine =~ s/\^//go }
+ print TUO "\\$RestOfLine\n" }
+
+sub FlushCommands
+ { Report ("PassedCommands", $NOfCommands) }
+
+#D Experimental: Extra
+#D
+#D s p : extra programs
+
+my @ExtraPrograms = () ;
+
+sub InitializeExtra
+ { }
+
+sub HandleExtra
+ { if ($RestOfLine =~ /(.)\s+(.*)\s*$/o)
+ { if ($1 eq "p")
+ { my $str = $2 ; $str =~ s/^\{(.*)\}$/$1/o ;
+ push @ExtraPrograms,$str } } }
+
+sub FlushExtra
+ { print TUO "%\n" . "% $Program / System\n" . "%\n" ;
+ foreach $EP (@ExtraPrograms)
+ { print TUO "% extra program : $EP\n" } }
+
+sub RunExtraPrograms
+ { foreach $EP (@ExtraPrograms)
+ { Report ("ExtraProgram", $EP) ;
+ system($EP) } }
+
+#D Plugins
+#D
+#D test.pm:
+#D
+#D \starttypen
+#D see plugtest.pm
+#D \stoptypen
+#D
+#D utility format:
+#D
+#D \starttypen
+#D p u {name} {data} {data} ...
+#D \stoptypen
+
+my $pm_path ;
+
+BEGIN
+ { ## $pm_path = `kpsewhich --format="other text files" --progname=context texutil.pl` ;
+ ## chomp($pm_path) ;
+ # $pm_path =~ s/texutil\.pl.*// }
+ # $pm_path = $0 ;
+ # $pm_path =~ s/\\/\//o ;
+ # $pm_path =~ s/texutil\.pl.*//io ;
+ ## $pm_path =~ s/(.*)texutil.*?$/$1/i ;
+ $pm_path = "$FindBin::Bin/" ;
+ if ($pm_path eq "") { $pm_path = "./" } }
+
+use lib $pm_path ;
+
+my %UserPlugIns ;
+
+sub HandlePlugIn
+ { if ($RestOfLine =~ /\s*u\s*\{(.*?)\}\s*(.*)\s*/io)
+ { my $tag = $1 ;
+ my $arg = $2 ;
+ if (! defined($UserPlugIns{$tag}))
+ { $UserPlugIns{$tag} = 1 ;
+ eval("use $tag") ;
+ my $result = $tag->identify ;
+ if ($result ne "")
+ { Report ("PlugInInit", "$tag -> $result") }
+ else
+ { Report ("PlugInInit", $tag ) }
+ $tag->initialize() }
+ if (defined($UserPlugIns{$tag}))
+ { $arg =~ s/\{(.*)\}/$1/o ;
+ my @args = split(/\}\s*\{/o, $arg) ;
+ $tag->handle(@args) } } }
+
+sub FlushPlugIns
+ { foreach my $tag (keys %UserPlugIns)
+ { my @report = $tag->report ;
+ foreach $rep (@report)
+ { my ($key,$val) = split (/\s*\:\s*/,$rep) ;
+ if ($val ne "")
+ { Report ("PlugInReport", "$tag -> $key -> $val") }
+ else
+ { Report ("PlugInReport", "$tag -> $key") } }
+ $tag->process ;
+ print TUO "%\n" . "% $Program / " . $tag->identify . "\n" . "%\n" ;
+ foreach my $str ($tag->results)
+ { print TUO "\\plugincommand\{$str\}\n" } } }
+
+#D Synonyms are a sort of key||value pairs and are used for
+#D ordered lists like abbreviations and units.
+#D
+#D \starttypen
+#D s e {class}{sanitized key}{key}{associated data}
+#D \stoptypen
+#D
+#D The sorted lists are saved as (surprise):
+#D
+#D \starttypen
+#D \synonymentry{class}{sanitized key}{key}{associated data}
+#D \stoptypen
+
+sub InitializeSynonyms
+ { $NOfSynonyms = 0 ;
+ $NOfBadSynonyms = 0 }
+
+#M \definieersynoniem [testname] [testnames] [\testmeaning]
+#M
+#M \stelsynoniemenin [testname] [criterium=alles]
+
+#D Let's first make clear what we can expect. Synonym
+#D entries look like:
+#D
+#D \startbuffer
+#D \testname [alpha] {\sl alpha} {a greek letter a}
+#D \testname {alpha} {another a}
+#D \testname [Beta] {\kap{beta}} {a greek letter b}
+#D \testname {beta} {indeed another b}
+#D \testname {gamma} {something alike g}
+#D \testname {delta} {just a greek d}
+#D \stopbuffer
+#D
+#D \typebuffer
+#D
+#D This not that spectacular list is to be sorted according
+#D to the keys (names). \haalbuffer
+
+sub HandleSynonym
+ { ++$NOfSynonyms ;
+ ($SecondTag, $RestOfLine) = split(/ /, $RestOfLine, 2) ;
+ ($Class, $Key, $Entry, $Meaning) = split(/} \{/, $RestOfLine) ;
+ chop $Meaning ;
+ $Class = substr $Class, 1 ;
+ if ($Entry eq "")
+ { ++$NOfBadSynonyms }
+ else
+ { $SynonymEntry[$NOfSynonyms] =
+ join ($JOIN,$Class,$Key,$Entry,$Meaning) } }
+
+#D Depending on the settings\voetnoot{One can call for
+#D all defined entries, call only the used ones, change
+#D layout, attach (funny) commands etc.} a list of
+#D {\em testnames} looks like:
+#D
+#D \plaatslijstmettestnames
+#D
+#D Watch the order in which these entries are sorted.
+
+sub FlushSynonyms
+ { print TUO "%\n" . "% $Program / Synonyms\n" . "%\n" ;
+ @SynonymEntry = sort { lc($a) cmp lc($b) } @SynonymEntry ;
+ $NOfSaneSynonyms = 0 ;
+ for ($n=1; $n<=$NOfSynonyms; $n++)
+ { # check normally not needed
+ if (($n==1)||($SynonymEntry[$n] ne $SynonymEntry[$n-1]))
+ { ($Class, $Key, $Entry, $Meaning) =
+ split(/$JOIN/, $SynonymEntry[$n]) ;
+ ++$NOfSaneSynonyms ;
+ print TUO "\\synonymentry{$Class}{$Key}{$Entry}{$Meaning}\n" } }
+ Report("SynonymEntries", $NOfSynonyms, "->", $NOfSaneSynonyms, "Entries") ;
+ if ($NOfBadSynonyms>0)
+ { Report("SynonymErrors", $NOfBadSynonyms) } }
+
+#D Register entries need a bit more care, especially when they
+#D are nested. In the near future we will also handle page
+#D ranges.
+#D
+#D \starttypen
+#D r e {class}{tag}{sanitized key}{key}{pagenumber}{realpage}
+#D r s {class}{tag}{sanitized key}{key}{string}{pagenumber}
+#D r r {class}{tag}{sanitized key}{key}{string}{pagenumber}
+#D \stoptypen
+#D
+#D The last one indicates the start of a range.
+
+#D The first one is the normal entry, the second one concerns
+#D {\em see this or that} entries. Keys are sanitized, unless
+#D the user supplies a sanitized key. To save a lot of
+#D programming, all data concerning an entry is stored in one
+#D string. Subentries are specified as:
+#D
+#D \starttypen
+#D first&second&third
+#D first+second+third
+#D \stoptypen
+#D
+#D When these characters are needed for typesetting purposes, we
+#D can also use the first character to specify the separator:
+#D
+#D \starttypen
+#D &$x^2+y^2=r^2$
+#D +this \& that
+#D \stoptypen
+#D
+#D Subentries are first unpacked and next stored in a
+#D consistent way, which means that we can use both separators
+#D alongside each other. We leave it to the reader to sort
+#D out the dirty tricks.
+
+$SPLIT ="%%" ;
+$JOIN ="__" ;
+
+sub InitializeRegisters
+ { $NOfEntries = 0 ;
+ $NOfBadEntries = 0 }
+
+$ProcessType = "" ;
+
+$RegStat{"f"} = 1 ;
+$RegStat{"e"} = 2 ; # end up between from and to
+$RegStat{"t"} = 3 ;
+$RegStat{"s"} = 4 ;
+
+my $RegSep = "$SectionSeparator$SectionSeparator" ;
+
+sub HandleRegister # the } { makes sure that local {} is ok
+ { ($SecondTag, $RestOfLine) = split(/ /, $RestOfLine, 2) ;
+ ++$NOfEntries ;
+ #~ if ($SecondTag eq "s")
+ #~ { ($Class, $Location, $Key, $Entry, $SeeToo, $Page ) =
+ #~ split(/} \{/, $RestOfLine) ;
+ #~ chop $Page ;
+ #~ $Class = substr $Class, 1 ;
+ #~ $RealPage = 0 }
+ #~ else
+ #~ { ($Class, $Location, $Key, $Entry, $Page, $RealPage ) =
+ #~ split(/} \{/, $RestOfLine) ;
+ #~ chop $RealPage ;
+ #~ $Class = substr $Class, 1 ;
+ #~ $SeeToo = "" }
+ if ($SecondTag eq "s")
+ { if ($RestOfLine =~ /^\s*(.*?)\}\s\{(.*?)\}\s\{(.*?)\}\s\{(.*)\}\s\{(.*?)\}\s\{(.*?)\s*$/o)
+ { ($Class, $Location, $Key, $Entry, $SeeToo, $Page ) = ($1,$2,$3,$4,$5,$6) ;
+ chop $Page ;
+ $Class = substr $Class, 1 ;
+ $RealPage = 0 }
+ else
+ { return } }
+ else
+ { if ($RestOfLine =~ /^\s*(.*?)\}\s\{(.*?)\}\s\{(.*?)\}\s\{(.*)\}\s\{(.*?)\}\s\{(.*?)\s*$/o)
+ { ($Class, $Location, $Key, $Entry, $Page, $RealPage ) = ($1,$2,$3,$4,$5,$6) ;
+ chop $RealPage ;
+ $Class = substr $Class, 1 ;
+ $SeeToo = "" }
+ else
+ { return } }
+ $_ = $Key ;
+ if (/$RegSep/)
+ { ($PageHow,$Key) = split (/$RegSep/) }
+ else
+ { $PageHow = "" }
+ $_ = $Entry ;
+ if (/$RegSep/)
+ { ($TextHow,$Entry) = split (/$RegSep/) }
+ else
+ { $TextHow = "" }
+ #
+ if ($Key eq "")
+ { $Key = SanitizedString($Entry) }
+ if ($SortMethod ne '')
+ { $ProcessHigh = 0 }
+ if ($ProcessHigh)
+ { $Key = HighConverted($Key) }
+ $KeyTag = substr $Key, 0, 1 ;
+ if ($KeyTag eq "&")
+ { $Key =~ s/^\&//go ;
+ $Key =~ s/([^\\])\&/$1$SPLIT/go }
+ elsif ($KeyTag eq "+")
+ { $Key =~ s/^\+//go ;
+ $Key =~ s/([^\\])\+/$1$SPLIT/go }
+ else
+ { $Key =~ s/([^\\])\&/$1$SPLIT/go ;
+ $Key =~ s/([^\\])\+/$1$SPLIT/go }
+ $Key .= " " ; # so, "Word" comes for "Word Another Word"
+ $EntryTag = substr $Entry, 0, 1 ;
+ if ($EntryTag eq "&")
+ { $Entry =~ s/^\&//go ;
+ $Entry =~ s/([^\\])\&/$1$SPLIT/go }
+ elsif ($EntryTag eq "+")
+ { $Entry =~ s/^\+//go ;
+ $Entry =~ s/([^\\])\+/$1$SPLIT/go }
+ elsif ($KeyTag eq "&")
+ { $Entry =~ s/([^\\])\&/$1$SPLIT/go }
+ elsif ($KeyTag eq "+")
+ { $Entry =~ s/([^\\])\+/$1$SPLIT/go }
+ else
+ { $Entry =~ s/([^\\])\&/$1$SPLIT/go ;
+ $Entry =~ s/([^\\])\+/$1$SPLIT/go }
+ $Key =~ s/^([^a-zA-Z])/ $1/go ;
+ $Key =~ s/^\s*\{(.*)\}$SPLIT/$1$SPLIT/go ; ####### new
+ $Entry =~ s/^\{(.*)\}$SPLIT/$1$SPLIT/go ; ###### new
+ if ($ProcessIJ) { $Key =~ s/ij/yy/go }
+ $LCKey = lc $Key ;
+ $RegStatus = $RegStat{$SecondTag} ;
+ $RealPageNumber= sprintf("%6i",$RealPage) ;
+ $RegisterEntry[$NOfEntries] =
+ join($JOIN,$Class,$LCKey,$Key,$Entry,$TextHow,$RegStatus,
+ $RealPageNumber,$Location,$Page,$PageHow,$SeeToo) }
+
+#M \definieerregister [testentry] [testentries]
+
+#D The previous routine deals with entries like:
+#D
+#D \startbuffer
+#D \testentry {alpha}
+#D \testentry {beta}
+#D \testentry {gamma}
+#D \testentry {gamma}
+#D \testentry {delta}
+#D \testentry {epsilon}
+#D \testentry {alpha+first}
+#D \testentry {alpha+second}
+#D \testentry {alpha+second}
+#D \testentry {alpha+third}
+#D \testentry {alpha+second+one}
+#D \testentry {alpha+second+one}
+#D \testentry {alpha+second+two}
+#D \testentry {alpha+second+three}
+#D \testentry {gamma+first+one}
+#D \testentry {gamma+second}
+#D \testentry {gamma+second+one}
+#D
+#D \testentry {alpha+fourth}
+#D \testentry {&alpha&fourth}
+#D \testentry {+alpha+fourth}
+#D
+#D \testentry [alpha+fourth] {alpha+fourth}
+#D \testentry [&alpha&fourth&one] {&alpha&fourth&one}
+#D \testentry [+alpha+fourth+two] {&alpha&fourth&two}
+#D
+#D \testentry {\kap{alpha}+fifth}
+#D \testentry {\kap{alpha}+f\'ifth}
+#D \testentry {\kap{alpha}+f"ifth}
+#D
+#D \testentry [&betaformula] {&$a^2+b^2=c^2$}
+#D
+#D \testentry {zeta \& more}
+#D
+#D \testentry [pagehowto::key]{texthowto::entry}
+#D
+#D % a very special case, when key has , and is constructed
+#D
+#D \testentry [pagehowto::{key}]{texthowto::{entry}}
+#D
+#D \stopbuffer
+#D
+#D \typebuffer
+#D
+#D \haalbuffer After being sorted, these entries are
+#D turned into something \TEX\ using:
+
+$CollapseEntries = 0 ;
+
+$RegisterEntry[0] = ("") ;
+
+sub How
+ { return "$TextHow$RegSep" . "$_[0]" }
+
+sub FlushSavedLine
+ { if (($CollapseEntries)&&($SavedFrom ne ""))
+ { if ($SavedTo ne "")
+ { print TUO "\\registerfrom$SavedFrom" ;
+ print TUO "\\registerto$SavedTo" }
+ else
+ { print TUO "\\registerpage$SavedFrom" } }
+ $SavedHow = "" ;
+ $SavedFrom = "" ;
+ $SavedTo = "" ;
+ $SavedEntry = "" }
+
+sub FlushRegisters
+ { print TUO "%\n" . "% $Program / Registers\n" . "%\n" ;
+ @RegisterEntry = sort { lc($a) cmp lc($b) } @RegisterEntry ;
+ $NOfSaneEntries = 0 ;
+ $NOfSanePages = 0 ;
+ $LastPage = "" ;
+ $LastRealPage = "" ;
+ $AlfaClass = "" ;
+ $Alfa = "" ;
+ $PreviousA = "" ;
+ $PreviousB = "" ;
+ $PreviousC = "" ;
+ $ActualA = "" ;
+ $ActualB = "" ;
+ $ActualC = "" ;
+
+ $SavedFrom = "" ;
+ $SavedTo = "" ;
+ $SavedEntry = "" ;
+ $SavedHow = "" ;
+
+ for ($n=1 ; $n<=$NOfEntries ; ++$n)
+ { ($Class, $LCKey, $Key, $Entry, $TextHow, $RegisterState,
+ $RealPage, $Location, $Page, $PageHow, $SeeToo) =
+ split(/$JOIN/, $RegisterEntry[$n]) ;
+ $RealPage =~ s/^\s*//o ;
+ $TestAlfa = lc substr $Key, 0, 1 ;
+ #
+ if ($SortN)
+ { $AlfKey = $Key ;
+ $AlfKey =~ s/(.).*\x00(.).*/$2/o ;
+ if (defined($ALF{$AlfKey}))
+ { $TestAlfa = $ALF{$AlfKey} } }
+ #
+ if ((lc $TestAlfa ne lc $Alfa) or ($AlfaClass ne $Class))
+ { # $Alfa= lc substr $Key, 0, 1 ;
+ $Alfa = $TestAlfa ;
+ $AlfaClass = $Class ;
+ if ($Alfa ne " ")
+ { FlushSavedLine ;
+ print TUO "\\registerentry{$Class}{$Alfa}\n" } }
+ ($ActualA, $ActualB, $ActualC ) =
+ split(/$SPLIT/, $Entry, 3) ;
+ unless ($ActualA) { $ActualA = "" }
+ unless ($ActualB) { $ActualB = "" }
+ unless ($ActualC) { $ActualC = "" }
+ if (How($ActualA) eq $PreviousA)
+ { $ActualA = "" }
+ else
+ { $PreviousA = How($ActualA) ;
+ $PreviousB = "" ;
+ $PreviousC = "" }
+ if (How($ActualB) eq $PreviousB)
+ { $ActualB = "" }
+ else
+ { $PreviousB = How($ActualB) ;
+ $PreviousC = "" }
+ if (How($ActualC) eq $PreviousC)
+ { $ActualC = "" }
+ else
+ { $PreviousC = How($ActualC) }
+ $Copied = 0 ;
+ if ($ActualA ne "")
+ { FlushSavedLine ;
+ print TUO "\\registerentrya{$Class}{$ActualA}\n" ;
+ $Copied = 1 }
+ if ($ActualB ne "")
+ { FlushSavedLine ;
+ print TUO "\\registerentryb{$Class}{$ActualB}\n" ;
+ $Copied = 1 }
+ if ($ActualC ne "")
+ { FlushSavedLine ;
+ print TUO "\\registerentryc{$Class}{$ActualC}\n" ;
+ $Copied = 1 }
+ if ($Copied)
+ { $NOfSaneEntries++ }
+ if ($RealPage eq 0)
+ { FlushSavedLine ;
+ print TUO "\\registersee{$Class}{$PageHow,$TextHow}{$SeeToo}{$Page}\n" ;
+ $LastPage = $Page ;
+ $LastRealPage = $RealPage }
+ else {
+if (($SavedHow ne $PageHow) && ($PageHow ne "")) {
+ # last valid page attribute counts
+ $SavedHow = $PageHow ;
+}
+ if (($Copied) || ! (($LastPage eq $Page) && ($LastRealPage eq $RealPage)))
+ { # print "$LastPage / $Page // $LastRealPage / $RealPage\n" ;
+ $NextEntry = "{$Class}{$PreviousA}{$PreviousB}{$PreviousC}{$PageHow,$TextHow}" ;
+ #~ $SavedLine = "{$Class}{$PageHow,$TextHow}{$Location}{$Page}{$RealPage}\n" ;
+ $SavedLine = "{$Class}{$SavedHow,$TextHow}{$Location}{$Page}{$RealPage}\n" ;
+ if ($RegisterState eq $RegStat{"f"})
+ { FlushSavedLine ;
+ print TUO "\\registerfrom$SavedLine" }
+ elsif ($RegisterState eq $RegStat{"t"})
+ { FlushSavedLine ;
+ print TUO "\\registerto$SavedLine" ; $SavedHow = '' ; }
+ else
+ { if ($CollapseEntries)
+ { if ($SavedEntry ne $NextEntry)
+ { $SavedFrom = $SavedLine }
+ else
+ { $SavedTo = $SavedLine }
+ $SavedEntry = $NextEntry }
+ else
+ { print TUO "\\registerpage$SavedLine" ; $SavedHow = '' ; }
+ }
+ ++$NOfSanePages ;
+ $LastPage = $Page ;
+ $LastRealPage = $RealPage } } }
+
+FlushSavedLine ;
+
+ Report("RegisterEntries", $NOfEntries, "->", $NOfSaneEntries, "Entries",
+ $NOfSanePages, "References") ;
+ if ($NOfBadEntries>0)
+ { Report("RegisterErrors", $NOfBadEntries) } }
+
+#D As promised, we show the results:
+#D
+#D \plaatstestentry
+
+#D For debugging purposes we flush some status information. The
+#D faster machines become, the more important this section will
+#D be. The totals, when changed, force texexec to do a second pass.
+
+sub FlushData
+ { print TUO "%\n" . "% $Program / Status\n" . "%\n" ;
+ print TUO "" .
+ "% embedded files : $NOfFiles ($NOfBadFiles errors)\n" .
+ "% synonym entries : $NOfSynonyms ($NOfBadSynonyms errors)\n" .
+ "% register entries : $NOfEntries ($NOfBadEntries errors)\n" .
+ "% metapost graphics : $TotalNOfMPgraphics\n" .
+ "% position commands : $TotalNOfPositions " ;
+ if ($TotalNOfPositions)
+ { if ($NOfPositionsFound)
+ { print TUO "(resolved)\n" }
+ else
+ { print TUO "(unresolved)\n" } }
+ else
+ { print TUO "(not used)\n" } }
+
+#D The functionallity described on the previous few pages is
+#D called upon in the main routine:
+
+sub NormalHandleReferences
+ { if ($InputFile eq "")
+ { Report("Error", "NoInputFile") }
+ else
+ { unless (open (TUI, "$InputFile.tui"))
+ { Report("Error", "EmptyInputFile", $InputFile) }
+ else
+ { Report("InputFile", "$InputFile.tui" ) ;
+ unlink "$InputFile.tmp" ;
+ rename "$InputFile.tuo", "$InputFile.tmp" ;
+ Report("OutputFile", "$InputFile.tuo" ) ;
+ open (TUO, ">$InputFile.tuo") ;
+ print TUO "%\n" . "% $Program / Commands\n" . "%\n" ;
+ while (<TUI>)
+ { $SomeLine = $_ ;
+ chomp $SomeLine ;
+ ($FirstTag, $RestOfLine) = split ' ', $SomeLine, 2 ;
+ if ($FirstTag eq "c")
+ { HandleCommand }
+ elsif ($FirstTag eq "s")
+ { HandleSynonym }
+ elsif ($FirstTag eq "r")
+ { HandleRegister }
+ elsif ($FirstTag eq "f")
+ { HandleFile }
+ elsif ($FirstTag eq "k")
+ { HandleKey }
+ elsif ($FirstTag eq "e")
+ { HandleExtra }
+ elsif ($FirstTag eq "p")
+ { HandlePlugIn }
+ elsif ($FirstTag eq "q")
+ { $ValidOutput = 0 ;
+ last } }
+ if ($ValidOutput)
+ { FlushCommands ; # already done during pass
+ FlushKeys ;
+ FlushRegisters ;
+ FlushSynonyms ;
+ FlushPlugIns ;
+ FlushFiles ;
+ FlushData ;
+ FlushExtra ;
+ close (TUO) ;
+ RunExtraPrograms }
+ else
+ { close (TUO) ;
+ unlink "$InputFile.tuo" ;
+ rename "$InputFile.tmp", "$InputFile.tuo" ;
+ Report ("Remark", "NoOutputFile") } } } }
+
+my $Suffix ;
+
+sub MergerHandleReferences
+ { unlink "texutil.tuo" ;
+ Report("OutputFile", "texutil.tuo" ) ;
+ open (TUO, ">texutil.tuo") ;
+ foreach $InputFile (@ARGV)
+ { ($InputFile, $Suffix) = split (/\./, $InputFile, 2) ;
+ unless (open (TUI, "$InputFile.tui"))
+ { Report("Error", "EmptyInputFile", $InputFile) }
+ else
+ { Report("InputFile", "$InputFile.tui" ) ;
+ while (<TUI>)
+ { $SomeLine = $_ ;
+ chomp $SomeLine ;
+ ($FirstTag, $RestOfLine) = split ' ', $SomeLine, 2 ;
+ if ($FirstTag eq "r")
+ { HandleRegister } } } }
+ if ($ValidOutput)
+ { FlushRegisters ;
+ close (TUO) }
+ else
+ { close (TUO) ;
+ unlink "texutil.tuo" ;
+ Report ("Remark", "NoOutputFile") } }
+
+# sub HandleReferences
+# { Report("Action", "ProcessingReferences") ;
+# if ($ProcessIJ )
+# { Report("Option", "SortingIJ") }
+# if ($ProcessHigh)
+# { Report("Option", "ConvertingHigh") }
+# if ($ProcessQuotes)
+# { Report("Option", "ProcessingQuotes") }
+# if ($InputFile eq "")
+# { Report("Error", "NoInputFile") }
+# else
+# { unless (open (TUI, "$InputFile.tui"))
+# { Report("Error", "EmptyInputFile", $InputFile) }
+# else
+# { Report("InputFile", "$InputFile.tui" ) ;
+# InitializeCommands ;
+# InitializeRegisters ;
+# InitializeSynonyms ;
+# InitializeFiles ;
+# $ValidOutput = 1 ;
+# unlink "$InputFile.tmp" ;
+# rename "$InputFile.tuo", "$InputFile.tmp" ;
+# Report("OutputFile", "$InputFile.tuo" ) ;
+# open (TUO, ">$InputFile.tuo") ;
+# while (<TUI>)
+# { $SomeLine = $_ ;
+# chomp $SomeLine ;
+# ($FirstTag, $RestOfLine) = split ' ', $SomeLine, 2 ;
+# if ($FirstTag eq "c")
+# { HandleCommand }
+# elsif ($FirstTag eq "s")
+# { HandleSynonym }
+# elsif ($FirstTag eq "r")
+# { HandleRegister }
+# elsif ($FirstTag eq "f")
+# { HandleFile }
+# elsif ($FirstTag eq "q")
+# { $ValidOutput = 0 ;
+# last } }
+# if ($ValidOutput)
+# { FlushCommands ; # already done during pass
+# FlushRegisters ;
+# FlushSynonyms ;
+# FlushFiles ;
+# FlushData ;
+# close (TUO) }
+# else
+# { close (TUO) ;
+# unlink "$InputFile.tuo" ;
+# rename "$InputFile.tmp", "$InputFile.tuo" ;
+# Report ("Remark", "NoOutputFile") } } } }
+
+sub HandleReferences
+ { $Merging = @ARGV ;
+ $Merging = ($Merging>1) ;
+ if ($Merging)
+ { Report("Action", "MergingReferences") }
+ else
+ { Report("Action", "ProcessingReferences") }
+ if ($ProcessIJ )
+ { Report("Option", "SortingIJ") }
+ if ($ProcessHigh)
+ { Report("Option", "ConvertingHigh") }
+ if ($ProcessQuotes)
+ { Report("Option", "ProcessingQuotes") }
+ InitializeKeys ;
+ InitializeCommands ;
+ InitializeExtra ;
+ InitializeRegisters ;
+ InitializeSynonyms ;
+ InitializeFiles ;
+ $ValidOutput = 1 ;
+ if ($Merging)
+ { MergerHandleReferences }
+ else
+ { NormalHandleReferences } }
+
+# moved to ctxtools
+#
+# sub HandleDocuments
+# { my $files = @ARGV.join(' ') ; system("ctxtools $files") }
+
+#D \extras
+#D {documents}
+#D
+#D Documentation can be woven into a source file. The next
+#D routine generates a new, \TEX\ ready file with the
+#D documentation and source fragments properly tagged. The
+#D documentation is included as comment:
+#D
+#D \starttypen
+#D %D ...... some kind of documentation
+#D %M ...... macros needed for documenation
+#D %S B begin skipping
+#D %S E end skipping
+#D \stoptypen
+#D
+#D The most important tag is \type{%D}. Both \TEX\ and
+#D \METAPOST\ files use \type{%} as a comment chacacter, while
+#D \PERL\ uses \type{#}. Therefore \type{#D} is also handled.
+#D
+#D The generated file gets the suffix \type{ted} and is
+#D structured as:
+#D
+#D \starttypen
+#D \startmodule[type=suffix]
+#D \startdocumentation
+#D \stopdocumentation
+#D \startdefinition
+#D \stopdefinition
+#D \stopmodule
+#D \stoptypen
+#D
+#D Macro definitions specific to the documentation are not
+#D surrounded by start||stop commands. The suffix specifaction
+#D can be overruled at runtime, but defaults to the file
+#D extension. This specification can be used for language
+#D depended verbatim typesetting.
+
+my $skippingbang = 0 ;
+
+sub HandleDocuments
+ { Report("Action", "GeneratingDocumentation") ;
+ if ($ProcessType ne "")
+ { Report("Option", "ForcingFileType", $ProcessType) }
+ if ($InputFile eq "")
+ { Report("Error", "NoInputFile") }
+ else
+ { CheckInputFiles ($InputFile) ;
+ foreach $FullName (@UserSuppliedFiles)
+ { ($FileName, $FileSuffix) = SplitFileName ($FullName) ;
+ unless ($FileSuffix)
+ { $FileSuffix = "tex" }
+ unless (-f "$FileName.$FileSuffix")
+ { next }
+ unless (open (TEX, "$FileName.$FileSuffix"))
+ { Report("Error", "EmptyInputFile", "$FileName.$FileSuffix" ) }
+ else
+ { Report("InputFile", "$FileName.$FileSuffix") ;
+ Report("OutputFile", "$FileName.ted") ;
+ open (TED, ">$FileName.ted") ;
+ $NOfDocuments = 0 ;
+ $NOfDefinitions = 0 ;
+ $NOfSkips = 0 ;
+ $SkipLevel = 0 ;
+ $InDocument = 0 ;
+ $InDefinition = 0 ;
+ $skippingbang = 0 ;
+ if ($ProcessType eq "")
+ { $FileType=lc $FileSuffix }
+ else
+ { $FileType=lc $ProcessType }
+ Report("FileType", $FileType) ;
+ # we need to signal to texexec what interfaec to use
+ my $firstline = <TEX> ;
+ if ($firstline =~ /^\%.*interface\=/)
+ { print TED $firstline }
+ else
+ { seek TEX, 0, 0 }
+ # so far
+ print TED "\\startmodule[type=$FileType]\n" ;
+ while (<TEX>)
+ { chomp ;
+ s/\s*$//o ;
+ if ($skippingbang)
+ { $skippingbang = 0 }
+ elsif (/^[%\#]D/)
+ { if ($SkipLevel == 0)
+ { if (length $_ < 3)
+ {$SomeLine = "" }
+ else # HH: added after that
+ {$SomeLine = substr $_, 3 }
+ if ($InDocument)
+ { print TED "$SomeLine\n" }
+ else
+ { if ($InDefinition)
+ { print TED "\\stopdefinition\n" ;
+ $InDefinition = 0 }
+ unless ($InDocument)
+ { print TED "\n\\startdocumentation\n" }
+ print TED "$SomeLine\n" ;
+ $InDocument = 1 ;
+ ++$NOfDocuments } } }
+ elsif (/^[%\#]M/)
+ { if ($SkipLevel == 0)
+ { $SomeLine = substr $_, 3 ;
+ print TED "$SomeLine\n" } }
+ elsif (/^[%\%]S B]/)
+ { ++$SkipLevel ;
+ ++$NOfSkips }
+ elsif (/^[%\%]S E]/)
+ { --$SkipLevel }
+ elsif (/^[%\#]/)
+ { }
+ elsif (/^eval \'\(exit \$\?0\)\' \&\& eval \'exec perl/o)
+ { $skippingbang = 1 }
+ elsif ($SkipLevel == 0)
+ { $InLocalDocument = $InDocument ;
+ $SomeLine = $_ ;
+ if ($InDocument)
+ { print TED "\\stopdocumentation\n" ;
+ $InDocument = 0 }
+ if (($SomeLine eq "") && ($InDefinition))
+ { print TED "\\stopdefinition\n" ;
+ $InDefinition = 0 }
+ else
+ { if ($InDefinition)
+ { print TED "$SomeLine\n" }
+ elsif ($SomeLine ne "")
+ { print TED "\n" . "\\startdefinition\n" ;
+ $InDefinition = 1 ;
+ unless ($InLocalDocument)
+ { ++$NOfDefinitions }
+ print TED "$SomeLine\n" } } } }
+ if ($InDocument)
+ { print TED "\\stopdocumentation\n" }
+ if ($InDefinition)
+ { print TED "\\stopdefinition\n" }
+ print TED "\\stopmodule\n" ;
+ close (TED) ;
+ unless (($NOfDocuments) || ($NOfDefinitions))
+ { unlink "$FileName.ted" }
+ Report ("NOfDocuments", $NOfDocuments) ;
+ Report ("NOfDefinitions", $NOfDefinitions) ;
+ Report ("NOfSkips", $NOfSkips) } } } }
+
+#D \extras
+#D {sources}
+#D
+#D Documented sources can be stripped of documentation and
+#D comments, although at the current processing speeds the
+#D overhead of skipping the documentation at run time is
+#D neglectable. Only lines beginning with a \type{%} are
+#D stripped. The stripped files gets the suffix \type{tes}.
+
+sub HandleSources
+ { Report("Action", "GeneratingSources") ;
+ if ($InputFile eq "")
+ { Report("Error", "NoInputFile") }
+ else
+ { CheckInputFiles ($InputFile) ;
+ foreach $FullName (@UserSuppliedFiles)
+ { ($FileName, $FileSuffix) = SplitFileName ($FullName) ;
+ unless ($FileSuffix)
+ { $FileSuffix = "tex" }
+ unless (-f "$FileName.$FileSuffix")
+ { next }
+ unless (open (TEX, "$FileName.$FileSuffix"))
+ { Report("Error", "EmptyInputFile", "$FileName.$FileSuffix" ) }
+ else
+ { Report("InputFile", "$FileName.$FileSuffix") ;
+ Report("OutputFile", "$FileName.tes") ;
+ open (TES, ">$FileName.tes") ;
+ $EmptyLineDone = 1 ;
+ $FirstCommentDone = 0 ;
+ while (<TEX>)
+ { $SomeLine = $_ ;
+ chomp $SomeLine ;
+ if ($SomeLine eq "")
+ { unless ($FirstCommentDone)
+ { $FirstCommentDone = 1 ;
+ print TES
+ "\n% further documentation is removed\n\n" ;
+ $EmptyLineDone = 1 }
+ unless ($EmptyLineDone)
+ { print TES "\n" ;
+ $EmptyLineDone = 1 } }
+ elsif ($SomeLine =~ /^%/)
+ { unless ($FirstCommentDone)
+ { print TES "$SomeLine\n" ;
+ $EmptyLineDone = 0 } }
+ else
+ { print TES "$SomeLine\n" ;
+ $EmptyLineDone = 0 } }
+ close (TES) ;
+ unless ($FirstCommentDone)
+ { unlink "$FileName.tes" } } } } }
+
+#D \extras
+#D {setups}
+#D
+#D All \CONTEXT\ commands are specified in a compact format
+#D that can be used to generate quick reference tables and
+#D cards. Such setups are preceded by \type{%S}. The setups
+#D are collected in the file \type{texutil.tus}.
+
+sub HandleSetups
+ { Report("Action", "FilteringDefinitions" ) ;
+ if ($InputFile eq "")
+ { Report("Error", "NoInputFile") }
+ else
+ { SetOutputFile ("texutil.tus" ) ;
+ Report("OutputFile", $OutputFile) ;
+ open (TUS, ">$OutputFile") ; # always reset!
+ $NOfSetups = 0 ;
+ CheckInputFiles ($InputFile) ;
+ foreach $FullName (@UserSuppliedFiles)
+ { ($FileName, $FileSuffix) = SplitFileName ($FullName) ;
+ unless ($FileSuffix)
+ { $FileSuffix = "tex" }
+ unless (-f "$FileName.$FileSuffix")
+ { next }
+ unless (open (TEX, "$FileName.$FileSuffix"))
+ { Report("Error", "EmptyInputFile", "$FileName.$FileSuffix" ) }
+ else
+ { Report("InputFile", "$FileName.$FileSuffix") ;
+ print TUS "%\n" . "% File : $FileName.$FileSuffix\n" . "%\n" ;
+ while (<TEX>)
+ { $SomeLine = $_ ;
+ chomp $SomeLine ;
+ ($Tag, $RestOfLine) = split(/ /, $SomeLine, 2) ;
+ if ($Tag eq "%S")
+ { ++$NOfSetups ;
+ while ($Tag eq "%S")
+ { print TUS "$RestOfLine\n" ;
+ $SomeLine = <TEX> ;
+ chomp $SomeLine ;
+ ($Tag, $RestOfLine) = split(/ /, $SomeLine, 2) }
+ print TUS "\n" } } } }
+ close (TUS) ;
+ unless ($NOfSetups)
+ { unlink $OutputFile }
+ Report("NOfSetups", $NOfSetups) } }
+
+#D \extras
+#D {templates, infos}
+#D
+#D From the beginning, the \CONTEXT\ source files contained
+#D helpinfo and key||templates for \TEXEDIT. In fact, for a
+#D long time, this was the only documentation present. More
+#D and more typeset (interactive) documentation is replacing
+#D this helpinfo, but we still support the traditional method.
+#D This information is formatted like:
+#D
+#D \starttypen
+#D %I n=Struts
+#D %I c=\strut,\setnostrut,\setstrut,\toonstruts
+#D %I
+#D %I text
+#D %I ....
+#D %P
+#D %I text
+#D %I ....
+#D \stoptypen
+#D
+#D Templates look like:
+#D
+#D \starttypen
+#D %T n=kap
+#D %T m=kap
+#D %T a=k
+#D %T
+#D %T \kap{?}
+#D \stoptypen
+#D
+#D The key||value pairs stand for {\em name}, {\em mnemonic},
+#D {\em key}. This information is copied to files with the
+#D extension \type{tud}.
+
+sub HandleEditorCues
+ { if ($ProcessTemplates)
+ { Report("Action", "CopyingTemplates" ) }
+ if ($ProcessInfos)
+ {Report("Action", "CopyingInformation" ) }
+ if ($InputFile eq "")
+ { Report("Error", "NoInputFile") }
+ else
+ { CheckInputFiles ($InputFile) ;
+ foreach $FullName (@UserSuppliedFiles)
+ { ($FileName, $FileSuffix) = SplitFileName ($FullName) ;
+ if ($FileSuffix eq "")
+ { $FileSuffix = "tex" }
+ unless (-f "$FileName.$FileSuffix")
+ { next }
+ unless (open (TEX, "$FileName.$FileSuffix"))
+ { Report("Error", "EmptyInputFile", "$FileName.$FileSuffix" ) }
+ else
+ { Report("InputFile", "$FileName.$FileSuffix") ;
+ Report("OutputFile", "$FileName.tud") ;
+ open (TUD, ">$FileName.tud") ;
+ $NOfTemplates = 0 ;
+ $NOfInfos = 0 ;
+ while (<TEX>)
+ { $SomeLine = $_ ;
+ chomp $SomeLine ;
+ ($Tag, $RestOfLine) = split(/ /, $SomeLine, 2) ;
+ if (($Tag eq "%T") && ($ProcessTemplates))
+ { ++$NOfTemplates ;
+ while ($Tag eq "%T")
+ { print TUD "$SomeLine\n" ;
+ $SomeLine = <TEX> ;
+ chomp $SomeLine ;
+ ($Tag, $RestOfLine) = split(/ /, $SomeLine, 2) }
+ print TUD "\n" }
+ elsif (($Tag eq "%I") && ($ProcessInfos))
+ { ++$NOfInfos ;
+ while (($Tag eq "%I") || ($Tag eq "%P"))
+ { print TUD "$SomeLine\n" ;
+ $SomeLine = <TEX> ;
+ chomp $SomeLine ;
+ ($Tag, $RestOfLine) = split(/ /, $SomeLine, 2) }
+ print TUD "\n" } }
+ close (TUD) ;
+ unless (($NOfTemplates) || ($NOfInfos))
+ { unlink "$FileName.tud" }
+ if ($ProcessTemplates)
+ { Report("NOfTemplates", $NOfTemplates) }
+ if ($ProcessInfos)
+ { Report("NOfInfos", $NOfInfos) } } } } }
+
+#D \extras
+#D {figures}
+#D
+#D Directories can be scanned for illustrations in \EPS, \PDF,
+#D \TIFF, \PNG\ or \JPG\ format. The resulting file \type{texutil.tuf}
+#D contains entries like:
+#D
+#D \starttypen
+#D \thisisfigureversion{year.month.day}
+#D \presetfigure[file][...specifications...]
+#D \stoptypen
+#D
+#D where the specifications are:
+#D
+#D \starttypen
+#D [e=suffix,x=xoffset,y=yoffset,w=width,h=height,t=title,c=creator,s=size]
+#D \stoptypen
+#D
+#D This data can be used when determining dimensions and
+#D generate directories of illustrations.
+
+$DPtoCM = 2.54/72.0 ;
+$INtoCM = 2.54 ;
+
+sub SaveFigurePresets
+ { my ($FNam, $FTyp, $FUni, $FXof, $FYof, $FWid, $FHei, $FTit, $FCre, $FSiz) = @_ ;
+ if ($ProcessVerbose)
+ { OpenTerminal ;
+ if ($FUni)
+ { print "n=$FNam t=$FTyp " .
+ (sprintf "x=%1.3fcm y=%1.3fcm ", $FXof, $FYof) .
+ (sprintf "w=%5.3fcm h=%5.3fcm\n", $FWid, $FHei) }
+ else
+ { print "n=$FNam t=$FTyp " .
+ "x=${FXof}bp y=${FYof}bp " .
+ "w=${FWid}bp h=${FHei}bp\n" }
+ CloseTerminal }
+ else
+ { ++$NOfFigures ;
+ $Figures[$NOfFigures] = "\\presetfigure[$FNam][e=$FTyp" ;
+ if ($FUni)
+ { $Figures[$NOfFigures] .= (sprintf ",w=%5.3fcm,h=%5.3fcm", $FWid, $FHei) }
+ else
+ { $Figures[$NOfFigures] .= ",w=${FWid}bp,h=${FHei}bp" }
+ if (($FXof!=0)||($FYof!=0))
+ { if ($FUni)
+ { $Figures[$NOfFigures] .= (sprintf ",x=%1.3fcm,y=%1.3fcm", $FXof, $FYof) }
+ else
+ { $Figures[$NOfFigures] .= ",x=${FXof}bp,y=${FYof}bp" } }
+ if ($FTit)
+ { $Figures[$NOfFigures] .= ",t=\{$FTit\}" }
+ if ($FCre)
+ { $Figures[$NOfFigures] .= ",c=\{$FCre\}" }
+ $Figures[$NOfFigures] .= ",s=$FSiz]\n" } }
+
+#D The \EPS\ to \PDF\ conversion pipe to \GHOSTSCRIPT\ is
+#D inspired by a script posted by Sebastian Ratz at the
+#D \PDFTEX\ mailing list. Watch the bounding box check, we
+#D use the values found in an earlier pass.
+
+sub ConvertEpsToEps
+ { my ( $SuppliedFileName , $LLX, $LLY, $URX, $URY ) = @_ ;
+ ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ;
+ if ($ProcessEpsToPdf)
+ { if ($dosish) { $gs = "gswin32c" } else { $gs = "gs" }
+ unlink "$FileName.pdf" ;
+ $GSCommandLine = "-q " .
+ "-sDEVICE=pdfwrite " .
+ "-dNOCACHE " .
+ "-dUseFlateCompression=true " .
+ "-dMaxSubsetPct=100 " .
+ "-sOutputFile=$FileName.pdf " .
+ "- -c " .
+ "quit " ;
+ open ( EPS, "| $gs $GSCommandLine") }
+ elsif ($PDFReady)
+ { return }
+ else
+ { open ( EPS, ">texutil.tmp" ) ;
+ binmode EPS }
+ open ( TMP , "$SuppliedFileName" ) ;
+ binmode TMP ;
+ $EpsBBOX = 0 ;
+ $EpsWidth = $URX - $LLX ;
+ $EpsHeight = $URY - $LLY ;
+ $EpsXOffset = 0 - $LLX ;
+ $EpsYOffset = 0 - $LLY ;
+ while (<TMP>)
+ { if (/%!PS/)
+ { s/(.*)%!PS/%!PS/o ;
+ print EPS $_ ;
+ last } }
+ while (<TMP>)
+ { if ((!$PDFReady)&&(/^%%(HiResB|ExactB|B)oundingBox:/o))
+ { unless ($EpsBBOX)
+ { print EPS "%%PDFready: $Program\n" ;
+ print EPS "%%BoundingBox: 0 0 $EpsWidth $EpsHeight\n" ;
+ print EPS "<< /PageSize [$EpsWidth $EpsHeight] >> setpagedevice\n" ;
+ print EPS "gsave $EpsXOffset $EpsYOffset translate\n" ;
+ $EpsBBOX = 1 } }
+ elsif (/^%%EOF/o) # when final: (/^%%(EOF|Trailer)/o)
+ { last }
+ elsif (/^%%Trailer/o)
+ { last }
+ else
+ { print EPS $_ } }
+ close ( TMP ) ;
+ if (($EpsBBOX)&&(!$PDFReady))
+ { print EPS "grestore\n%%EOF\n%%RestOfFileIgnored: $Program\n" ;
+ close ( EPS ) ;
+ Report ( "PdfFile", "$SuppliedFileName" ) ;
+ unless ($ProcessEpsToPdf)
+ { unlink "$SuppliedFileName" ;
+ rename "texutil.tmp", "$SuppliedFileName" } }
+ else
+ { close (EPS) }
+ unlink "texutil.tmp" }
+
+sub HandleEpsFigure
+ { my ($SuppliedFileName) = @_ ;
+ my ($Temp) = "" ;
+ if (-f $SuppliedFileName)
+ { ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ;
+ if ($FileSuffix ne "")
+ {#$Temp = $FileSuffix ;
+ #$Temp =~ s/[0-9]//go ;
+ #if ($Temp eq "")
+ if ($FileSuffix =~ /^[0-9]+$/o)
+ { $EpsFileName = $SuppliedFileName;
+ Report ( "MPFile", "$SuppliedFileName" ) }
+ elsif ((lc $FileSuffix ne "eps")&&(lc $FileSuffix ne "mps"))
+ { return }
+ else
+ { $EpsFileName = $SuppliedFileName; # $FileName
+ Report ( "EpsFile", "$SuppliedFileName" ) }
+ $EpsTitle = "" ;
+ $EpsCreator = "" ;
+ open ( EPS , $SuppliedFileName ) ;
+ binmode EPS ;
+ $EpsSize = -s EPS ;
+ $PDFReady = 0 ;
+ $MPSFound = 0 ;
+ $BBoxFound = 0 ;
+ while (<EPS>)
+ { $SomeLine = $_;
+ chomp $SomeLine ;
+ if (($BBoxFound) && ((substr $SomeLine,0,1) ne "%"))
+ { last }
+ if ($BBoxFound<2)
+ { if ($SomeLine =~ /^%%BoundingBox:(?!\s+\(atend\))/io) # atend (th)
+ { $EpsBBox = $SomeLine ; $BBoxFound = 1 ; next }
+ elsif ($SomeLine =~ /^%%HiResBoundingBox:/io)
+ { $EpsBBox = $SomeLine ; $BBoxFound = 2 ; next }
+ elsif ($SomeLine =~ /^%%ExactBoundingBox:/io)
+ { $EpsBBox = $SomeLine ; $BBoxFound = 3 ; next } }
+ if ($SomeLine =~ /^%%PDFready:/io)
+ { $PDFReady = 1 }
+ elsif ($SomeLine =~ /^%%Creator:/io)
+ { ($Tag, $EpsCreator) = split (/ /, $SomeLine, 2) ;
+ if ($EpsCreator =~ /MetaPost/io)
+ { $MPSFound = 1 } }
+ elsif ($SomeLine =~ /^%%Title:/io)
+ { ($Tag, $EpsTitle) = split (/ /, $SomeLine, 2) } }
+ close ( EPS ) ;
+ if ($BBoxFound)
+ { ($Tag, $LLX, $LLY, $URX, $URY, $RestOfLine) = split (/ /, $EpsBBox, 6 ) ;
+ $EpsHeight = ($URY-$LLY)*$DPtoCM ;
+ $EpsWidth = ($URX-$LLX)*$DPtoCM ;
+ $EpsXOffset = $LLX*$DPtoCM ;
+ $EpsYOffset = $LLY*$DPtoCM ;
+ if ($MPSFound)
+ { $EpsType = "mps" }
+ else
+ { $EpsType = "eps" }
+ SaveFigurePresets
+ ( $EpsFileName, $EpsType, 1,
+ $EpsXOffset, $EpsYOffset, $EpsWidth, $EpsHeight,
+ $EpsTitle, $EpsCreator, $EpsSize ) ;
+ if (($ProcessEpsPage) || ($ProcessEpsToPdf))
+ { ConvertEpsToEps ( $SuppliedFileName, $LLX, $LLY, $URX, $URY ) } }
+ else
+ { Report ( "MissingBoundingBox", "$SuppliedFileName" ) } } } }
+
+#D The \PDF\ scanning does a similar job. This time we
+#D search for a mediabox. I could have shared some lines
+#D with the previous routines, but prefer readability.
+
+sub HandlePdfFigure
+ { my ( $SuppliedFileName ) = @_ ;
+ ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ;
+ if (lc $FileSuffix ne "pdf")
+ { return }
+ else
+ { $PdfFileName = $SuppliedFileName ;
+ Report ( "PdfFile", "$SuppliedFileName" ) }
+ open ( PDF , $SuppliedFileName ) ;
+ binmode PDF ;
+ $PdfSize = -s PDF ;
+ $MediaBoxFound = 0 ;
+ $MediaBox = 0 ;
+ $PageFound = 0 ;
+ $PagesFound = 0 ;
+ while (<PDF>)
+ { $SomeLine = $_ ;
+ chomp ($SomeLine) ;
+ if ($SomeLine =~ /\/Type\s*\/Pages/io)
+ { $PagesFound = 1 }
+ elsif ($SomeLine =~ /\/Type\s*\/Page/io)
+ { ++$PageFound ;
+ if ($PageFound>1) { last } }
+ if (($PageFound)||($PagesFound))
+ { if (($MediaBoxFound < 2) && ($SomeLine =~ /\/ArtBox\s*\[/io))
+ { $MediaBoxFound = 3 ;
+ $MediaBox = $SomeLine }
+ elsif (($MediaBoxFound < 2) && ($SomeLine =~ /\/CropBox\s*\[/io))
+ { $MediaBoxFound = 2 ;
+ $MediaBox = $SomeLine }
+ elsif (($MediaBoxFound == 0) && ($SomeLine =~ /\/MediaBox\s*\[/io))
+ { $MediaBoxFound = 1 ;
+ $MediaBox = $SomeLine } } }
+ close ( PDF ) ;
+ if ($PageFound>1)
+ { Report ( "MultiPagePdfFile", "$SuppliedFileName" ) }
+ if (($MediaBoxFound) && ($MediaBox))
+ { my $D = "[0-9\-\.]" ;
+ $MediaBox =~ /\/(Media|Crop|Art)Box\s*\[\s*($D+)\s*($D+)\s*($D+)\s*($D+)/o ;
+ $LLX = $2 ; $LLY = $3 ; $URX = $4 ; $URY = $5 ;
+ $PdfHeight = ($URY-$LLY)*$DPtoCM ;
+ $PdfWidth = ($URX-$LLX)*$DPtoCM ;
+ $PdfXOffset = $LLX*$DPtoCM ;
+ $PdfYOffset = $LLY*$DPtoCM ;
+ SaveFigurePresets
+ ( $PdfFileName, "pdf", 1,
+ $PdfXOffset, $PdfYOffset, $PdfWidth, $PdfHeight,
+ "", "", $PdfSize ) }
+ else
+ { Report ( "MissingMediaBox", "$SuppliedFileName" ) } }
+
+#D A previous version of \TEXUTIL\ used \type{tifftags} or
+#D \type{tiffinfo} for collecting the dimensions. However,
+#D the current implementation does this job itself.
+
+sub TifGetByte
+ { my $B = 0 ;
+ read TIF, $B, 1 ;
+ return ord($B) }
+
+sub TifGetShort
+ { my $S = 0 ;
+ read TIF, $S, 2 ;
+ if ($TifLittleEndian)
+ { return (unpack ("v", $S)) }
+ else
+ { return (unpack ("n", $S)) } }
+
+sub TifGetLong
+ { my $L = 0 ;
+ read TIF, $L, 4 ;
+ if ($TifLittleEndian)
+ { return (unpack ("V", $L)) }
+ else
+ { return (unpack ("N", $L)) } }
+
+sub TifGetRational
+ { my ($N, $M) = (0,0) ;
+ $N = TifGetLong ;
+ $M = TifGetLong ;
+ return $N/$M }
+
+sub TifGetAscii
+ { my $S = "" ;
+ --$TifValues;
+ unless ($TifValues)
+ { return "" }
+ else
+ { read TIF, $S, $TifValues ;
+ return $S } }
+
+sub TifGetWhatever
+ { if ($_[0]==1)
+ { return TifGetByte }
+ elsif ($_[0]==2)
+ { return TifGetAscii }
+ elsif ($_[0]==3)
+ { return TifGetShort }
+ elsif ($_[0]==4)
+ { return TifGetLong }
+ elsif ($_[0]==5)
+ { return TifGetRational }
+ else
+ { return 0 } }
+
+sub TifGetChunk
+ { seek TIF, $TifNextChunk, 0 ;
+ $Length = TifGetShort ;
+ $TifNextChunk += 2 ;
+ for ($i=1; $i<=$Length; $i++)
+ { seek TIF, $TifNextChunk, 0 ;
+ $TifTag = TifGetShort ;
+ $TifType = TifGetShort ;
+ $TifValues = TifGetLong ;
+ if ($TifTag==256)
+ { $TifWidth = TifGetWhatever($TifType) }
+ elsif ($TifTag==257)
+ { $TifHeight = TifGetWhatever($TifType) }
+ elsif ($TifTag==296)
+ { $TifUnit = TifGetWhatever($TifType) }
+ elsif ($TifTag==282)
+ { seek TIF, TifGetLong, 0 ;
+ $TifHRes = TifGetWhatever($TifType) }
+ elsif ($TifTag==283)
+ { seek TIF, TifGetLong, 0 ;
+ $TifVRes = TifGetWhatever($TifType) }
+ elsif ($TifTag==350)
+ { seek TIF, TifGetLong, 0 ;
+ $TifCreator = TifGetWhatever($TifType) }
+ elsif ($TifTag==315)
+ { seek TIF, TifGetLong, 0 ;
+ $TifAuthor = TifGetWhatever($TifType) }
+ elsif ($TifTag==269)
+ { seek TIF, TifGetLong, 0 ;
+ $TifTitle = TifGetWhatever($TifType) }
+ $TifNextChunk += 12 }
+ seek TIF, $TifNextChunk, 0 ;
+ $TifNextChunk = TifGetLong ;
+ return ($TifNextChunk>0) }
+
+sub HandleTifFigure
+ { my ( $SuppliedFileName ) = @_ ;
+ ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ;
+ if (lc $FileSuffix ne "tif")
+ { return }
+ else
+ { $TifFile = $SuppliedFileName ;
+ if (open ( TIF, $TifFile )) { # { must be here, perl 5.003 bug
+ Report ( "TifFile", "$SuppliedFileName" ) ;
+ binmode TIF;
+ $TifWidth = 0 ;
+ $TifHeight = 0 ;
+ $TifTitle = "" ;
+ $TifAuthor = "" ;
+ $TifCreator = "" ;
+ $TifUnit = 0 ;
+ $TifHRes = 1 ;
+ $TifVRes = 1 ;
+ $TifSize = -s TIF ;
+ $TifByteOrder = "" ;
+ seek TIF, 0, 0 ;
+ read TIF, $TifByteOrder, 2 ;
+ $TifLittleEndian = ($TifByteOrder eq "II") ;
+ $TifTag = TifGetShort;
+ unless ($TifTag == 42)
+ { close ( TIF ) ;
+ return }
+ $TifNextChunk = TifGetLong ;
+ while (TifGetChunk) { }
+ if ($TifUnit==2)
+ { $TifMult = $INtoCM }
+ elsif ($TifUnit==3)
+ { $TifMult = 1 }
+ else
+ { $TifMult = 72 }
+ $TifWidth = ($TifWidth /$TifHRes)*$TifMult ;
+ $TifHeight = ($TifHeight/$TifVRes)*$TifMult ;
+ close ( TIF ) ;
+ SaveFigurePresets
+ ( $TifFile, "tif", $TifUnit,
+ 0, 0, $TifWidth, $TifHeight,
+ $TifTitle, $TifCreator, $TifSize ) } } }
+
+#D I first intended to use the public utility \type{pngmeta}
+#D (many thanks to Taco for compiling it), but using this
+#D utility to analyze lots of \PNG\ files, I tried to do a
+#D similar job in \PERL. Here are the results:
+
+my ($PngSize, $PngWidth, $PngHeight) = (0,0,0) ;
+my ($PngMult, $PngHRes, $PngVRes, $PngUnit) = (0,1,1,0) ;
+my ($PngFile, $PngTitle, $PngAuthor, $PngCreator) = ("","","") ;
+my ($PngNextChunk, $PngLength, $PngType) = (0,0,0) ;
+my ($PngKeyword, $PngDummy) = ("","") ;
+
+my $PngSignature = chr(137) . chr(80) . chr(78) . chr(71) .
+ chr (13) . chr(10) . chr(26) . chr(10) ;
+sub PngGetByte
+ { my ($B) = 0 ;
+ read PNG, $B, 1 ;
+ return (ord($B)) }
+
+sub PngGetLong
+ { my ($L) = 0 ;
+ read PNG, $L, 4 ;
+ return (unpack("N", $L)) }
+
+sub PngGetChunk
+ { if ($PngNextChunk<$PngSize)
+ { seek PNG, $PngNextChunk, 0 ;
+ $PngLength = PngGetLong ;
+ $PngNextChunk = $PngNextChunk + $PngLength + 12 ;
+ read PNG, $PngType, 4 ;
+ if ($PngType eq "")
+ { return 0 }
+ elsif ($PngType eq "IEND")
+ { return 0 }
+ elsif ($PngType eq "IHDR")
+ { $PngWidth = PngGetLong ;
+ $PngHeight = PngGetLong }
+ elsif ($PngType eq "pHYs")
+ { $PngHRes = PngGetLong ;
+ $PngVRes = PngGetLong ;
+ read PNG, $PngUnit, 1 }
+ elsif ($PngType eq "tEXt")
+ { read PNG, $PngKeyword, $PngLength ;
+ ($PngKeyword,$PngDummy) = split(/\x00/,$PngKeyword) ;
+ if ( $PngKeyword eq "Title")
+ { $PngTitle = $PngDummy }
+ elsif ( $PngKeyword eq "Author")
+ { $PngAuthor = $PngDummy }
+ elsif ( $PngKeyword eq "Software")
+ { $PngCreator = $PngDummy } }
+ return 1 }
+ else
+ { return 0 } }
+
+sub HandlePngFigure
+ { my ( $SuppliedFileName ) = @_ ;
+ ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ;
+ if (lc $FileSuffix ne "png")
+ { return }
+ else
+ { $PngFile = $SuppliedFileName ;
+ if (open ( PNG, $PngFile ))
+ { Report ( "PngFile", "$SuppliedFileName" ) }
+ $PngSize = 0 ;
+ $PngWidth = 0 ;
+ $PngHeight = 0 ;
+ $PngTitle = "" ;
+ $PngAuthor = "" ;
+ $PngCreator = "" ;
+ $PngUnit = 0 ;
+ $PngVRes = 1 ;
+ $PngHRes = 1 ;
+ $PngSig = "" ;
+ $PngSize = -s PNG ;
+ binmode PNG ;
+ seek PNG, 0, 0 ;
+ read PNG, $PngSig, 8;
+ unless ($PngSig eq $PngSignature)
+ { close ( PNG ) ;
+ return }
+ $PngNextChunk = 8 ;
+ while (PngGetChunk) { }
+ $PngWidth = ($PngWidth /$PngVRes) ;
+ $PngHeight = ($PngHeight/$PngHRes) ;
+ close ( PNG ) ;
+ SaveFigurePresets
+ ( $PngFile, "png", $PngUnit,
+ 0, 0, $PngWidth, $PngHeight,
+ $PngTitle, $PngCreator, $PngSize ) } }
+
+#D Well, we also offer \JPG\ scanning (actually \JFIF)
+#D scanning. (I can recomend David Salomon's book on Data
+#D Compression to those interested in the internals of
+#D \JPG.)
+#D
+#D It took me some time to discover that the (sort of)
+#D reference document I used had a faulty byte position table.
+#D Nevertheless, when I was finaly able to grab the header,
+#D Piet van Oostrum pointer me to the \PERL\ script of Alex
+#D Knowles (and numerous other contributers), from which I
+#D could deduce what segment contained the dimensions.
+
+my ($JpgSize, $JpgWidth, $JpgHeight) = (0,0,0) ;
+my ($JpgMult, $JpgUnit, $JpgHRes, $JpgVRes) = (1,0,1,1) ;
+my ($JpgFile, $JpgVersion, $JpgDummy) = ("",0,"") ;
+my ($JpgSig, $JpgPos, $JpgLen, $JpgSoi, $JpgApp) = ("",0,0,0,0) ;
+
+my $JpgSignature = "JFIF" . chr(0) ;
+
+sub JpgGetByte
+ { my ($B) = 0 ;
+ read JPG, $B, 1 ;
+ return ( ord($B) ) }
+
+sub JpgGetInteger
+ { my ($I) = 0 ;
+ read JPG, $I, 2 ;
+ return (unpack("n", $I)) }
+
+sub HandleJpgFigure
+ { my ($SuppliedFileName) = @_ ;
+ ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ;
+ if (lc $FileSuffix ne "jpg")
+ { return }
+ else
+ { $JpgFile = $SuppliedFileName ;
+ Report ( "JpgFile", "$SuppliedFileName" ) }
+ open ( JPG, $JpgFile ) ;
+ binmode JPG ;
+ $JpgSignature = "JFIF" . chr(0) ;
+ $JpgSize = -s JPG ;
+ $JpgWidth = 0 ;
+ $JpgHeight = 0 ;
+ $JpgUnit = 0 ;
+ $JpgVRes = 1 ;
+ $JpgHRes = 1 ;
+ seek JPG, 0, 0 ;
+ read JPG, $JpgSig, 4 ;
+ unless ($JpgSig eq chr(255).chr(216).chr(255).chr(224))
+ { close ( JPG ) ;
+ return }
+ $JpgLen = JpgGetInteger;
+ read JPG, $JpgSig, 5 ;
+ unless ($JpgSig eq $JpgSignature)
+ { close ( JPG ) ;
+ return }
+ $JpgUnit = JpgGetByte ;
+ $JpgVersion = JpgGetInteger ;
+ $JpgHRes = JpgGetInteger ;
+ $JpgVRes = JpgGetInteger ;
+ $JpgPos = $JpgLen + 4 ;
+ $JpgSoi = 255 ;
+ while ()
+ { seek JPG, $JpgPos, 0 ;
+ $JpgSoi = JpgGetByte ;
+ $JpgApp = JpgGetByte ;
+ $JpgLen = JpgGetInteger ;
+ if ($JpgSoi!=255)
+ { last }
+ if (($JpgApp>=192) && ($JpgApp<=195)) # Found in the perl script.
+ { $JpgDummy = JpgGetByte ; # Found in the perl script.
+ $JpgHeight = JpgGetInteger ; # Found in the perl script.
+ $JpgWidth = JpgGetInteger } # Found in the perl script.
+ $JpgPos = $JpgPos + $JpgLen + 2 }
+ close ( JPG ) ;
+ if ($JpgUnit==1)
+ { $JpgMult = $INtoCM }
+ else
+ { $JpgMult = 1 }
+ $JpgHRes = 72 unless $JpgHRes>1 ;
+ $JpgVRes = 72 unless $JpgVRes>1 ;
+ $JpgWidth = ($JpgWidth/$JpgHRes)*$JpgMult ;
+ $JpgHeight = ($JpgHeight/$JpgVRes)*$JpgMult ;
+ close ( JPG ) ;
+ SaveFigurePresets
+ ( $JpgFile, "jpg", $JpgUnit,
+ 0, 0, $JpgWidth, $JpgHeight,
+ "", "", $JpgSize ) }
+
+#D Now we can handle figures!
+
+sub InitializeFigures
+ { $NOfFigures = 0 }
+
+sub FlushFigures
+ { SetOutputFile ("texutil.tuf") ;
+ open ( TUF, ">$OutputFile" ) ;
+ print TUF "%\n" . "% $Program / Figures\n" . "%\n" ;
+ print TUF "\\thisisfigureversion\{1996.06.01\}\n" . "%\n" ;
+ for ($n=1 ; $n<=$NOfFigures ; ++$n)
+ { print TUF $Figures[$n] }
+ close (TUF) ;
+ if ($NOfFigures)
+ { Report("OutputFile", $OutputFile ) }
+ else
+ { unlink $OutputFile }
+ Report ( "NOfFigures", $NOfFigures ) }
+
+sub DoHandleFigures
+ { my ($FigureSuffix, $FigureMethod) = @_ ;
+ if ($InputFile eq "")
+ { $InputFile = $FigureSuffix }
+ CheckInputFiles ($InputFile) ;
+ foreach $FileName (@UserSuppliedFiles)
+ { &{$FigureMethod} ( $FileName ) } }
+
+sub HandleFigures
+ { Report("Action", "GeneratingFigures" ) ;
+ foreach $FileType (@ARGV)
+ { if ($FileType=~/\.eps/io)
+ { Report("Option", "UsingEps") ;
+ if ($ProcessEpsToPdf) { Report("Option", "EpsToPdf") }
+ if ($ProcessEpsPage) { Report("Option", "EpsPage") }
+ last } }
+ foreach $FileType (@ARGV)
+ { if ($FileType=~/\.pdf/io)
+ { Report("Option", "UsingPdf") ;
+ last } }
+ foreach $FileType (@ARGV)
+ { if ($FileType=~/\.tif/io)
+ { Report("Option", "UsingTif") ;
+ #RunTifPrograms ;
+ last } }
+ foreach $FileType (@ARGV)
+ { if ($FileType=~/\.png/io)
+ { Report("Option", "UsingPng") ;
+ last } }
+ foreach $FileType (@ARGV)
+ { if ($FileType=~/\.jpg/io)
+ { Report("Option", "UsingJpg") ;
+ last } }
+ InitializeFigures ;
+ DoHandleFigures ("eps", "HandleEpsFigure") ;
+ DoHandleFigures ("pdf", "HandlePdfFigure") ;
+ DoHandleFigures ("tif", "HandleTifFigure") ;
+ DoHandleFigures ("png", "HandlePngFigure") ;
+ DoHandleFigures ("jpg", "HandleJpgFigure") ;
+ FlushFigures }
+
+#D \extras
+#D {logfiles}
+#D
+#D This (poor man's) log file scanning routine filters
+#D overfull box messages from a log file (\type{\hbox},
+#D \type{\vbox} or both). The collected problems are saved
+#D in \type{$ProgramLog}. One can specify a selection
+#D criterium.
+#D
+#D \CONTEXT\ reports unknown entities. These can also be
+#D filtered. When using fast computers, or when processing
+#D files in batch, one has to rely on the log files and/or
+#D this filter.
+
+$Unknown = "onbekende verwijzing|" .
+ "unbekannte Referenz|" .
+ "unknown reference|" .
+ "dubbele verwijzing|" .
+ "duplicate reference|" .
+ "doppelte Referenz" ;
+
+sub FlushLogTopic
+ { unless ($TopicFound)
+ { $TopicFound = 1 ;
+ print ALL "\n% File: $FileName.log\n\n" } }
+
+sub HandleLogFile
+ { if ($ProcessBox)
+ { Report("Option", "FilteringBoxes", "(\\vbox & \\hbox)") ;
+ $Key = "[h|v]box" }
+ elsif ($ProcessHBox)
+ { Report("Option", "FilteringBoxes", "(\\hbox)") ;
+ $Key = "hbox" ;
+ $ProcessBox = 1 }
+ elsif ($ProcessVBox)
+ { Report("Option", "FilteringBoxes", "(\\vbox)") ;
+ $Key = "vbox" ;
+ $ProcessBox = 1 }
+ if (($ProcessBox) && ($ProcessCriterium))
+ { Report("Option", "ApplyingCriterium") }
+ if ($ProcessUnknown)
+ { Report("Option", "FilteringUnknown") }
+ unless (($ProcessBox) || ($ProcessUnknown))
+ { ShowHelpInfo ;
+ return }
+ Report("Action", "FilteringLogFile" ) ;
+ if ($InputFile eq "")
+ { Report("Error", "NoInputFile") }
+ else
+ { $NOfBoxes = 0 ;
+ $NOfMatching = 0 ;
+ $NOfUnknown = 0 ;
+ SetOutputFile ($ProgramLog) ;
+ Report("OutputFile", $OutputFile) ;
+ CheckInputFiles ($InputFile) ;
+ open ( ALL, ">$OutputFile" ) ;
+ foreach $FullName (@UserSuppliedFiles)
+ { ($FileName, $FileSuffix) = SplitFileName ($FullName) ;
+ if (! open (LOG, "$FileName.log"))
+ { Report("Error", "EmptyInputFile", "$FileName.$FileSuffix" ) }
+ elsif (-e "$FileName.tex")
+ { $TopicFound = 0 ;
+ Report("InputFile", "$FileName.log") ;
+ while (<LOG>)
+ { $SomeLine = $_ ;
+ chomp $SomeLine ;
+ if (($ProcessBox) && ($SomeLine =~ /Overfull \\$Key/))
+ { ++$NOfBoxes ;
+ $SomePoints = $SomeLine ;
+ $SomePoints =~ s/.*\((.*)pt.*/$1/ ;
+ if ($SomePoints>=$ProcessCriterium)
+ { ++$NOfMatching ;
+ FlushLogTopic ;
+ print ALL "$SomeLine\n" ;
+ $SomeLine=<LOG> ;
+ print ALL $SomeLine } }
+ if (($ProcessUnknown) && ($SomeLine =~ /$Unknown/io))
+ { ++$NOfUnknown ;
+ FlushLogTopic ;
+ print ALL "$SomeLine\n" } } } }
+ close (ALL) ;
+ unless (($NOfBoxes) ||($NOfUnknown))
+ { unlink $OutputFile }
+ if ($ProcessBox)
+ { Report ( "NOfBoxes" , "$NOfBoxes", "->", $NOfMatching, "Overfull") }
+ if ($ProcessUnknown)
+ { Report ( "NOfUnknown", "$NOfUnknown") } } }
+
+#D Undocumented feature.
+#
+# obsolete, i.e now in ctxtools, so this will become:
+#
+# sub PurgeFiles {
+# if ($PurgeAllFiles) {
+# system("ctxtools --purge $ARGV[0]") ;
+# } else {
+# system("ctxtools --purge --all $ARGV[0]") ;
+# }
+
+my $removedfiles = 0 ;
+my $keptfiles = 0 ;
+my $persistentfiles = 0 ;
+my $reclaimedbytes = 0 ;
+
+sub RemoveContextFile
+ { my $filename = shift ;
+ my $filesize = -s $filename ;
+ unlink $filename ;
+ if (-e $filename)
+ { ++$persistentfiles ;
+ print " persistent : $filename\n" }
+ else
+ { ++$removedfiles ; $reclaimedbytes += $filesize ;
+ print " removed : $filename\n" } }
+
+sub KeepContextFile
+ { my $filename = shift ;
+ ++$keptfiles ;
+ print " kept : $filename\n" }
+
+my @dontaskprefixes = sort glob "mpx-*" ; push @dontaskprefixes ,
+ ("tex-form.tex","tex-edit.tex","tex-temp.tex",
+ "texexec.tex","texexec.tui","texexec.tuo",
+ "texexec.ps","texexec.pdf","texexec.dvi",
+ "cont-opt.tex","cont-opt.bak") ;
+my @dontasksuffixes =
+ ("mpgraph.mp","mpgraph.mpd","mpgraph.mpo","mpgraph.mpy",
+ "mprun.mp", "mprun.mpd", "mprun.mpo", "mprun.mpy",
+ "xlscript.xsl") ;
+my @forsuresuffixes =
+ ("tui","tup","ted","tes","top",
+ "log","tmp","run","bck","rlg",
+ "mpt","mpx","mpd","mpo") ;
+my @texonlysuffixes =
+ ("dvi","ps","pdf") ;
+my @texnonesuffixes =
+ ("tuo","tub","top") ;
+
+if ($PurgeAllFiles)
+ { push @forsuresuffixes, @texnonesuffixes ; @texnonesuffixes = [] }
+
+sub PurgeFiles # no my in foreach
+ { my $pattern = $ARGV[0] ; my $strippedname, $basename ;
+ my @files = () ;
+ if ($pattern eq '')
+ { $pattern = "*.*" ;
+ @files = glob $pattern }
+ else
+ { $pattern = $ARGV[0] . "-*.*" ;
+ @files = glob $pattern ;
+ $pattern = $ARGV[0] . ".*" ;
+ push(@files,glob $pattern) }
+ @files = sort @files ;
+ print " purging files : $pattern\n\n" ;
+ foreach $file (@dontaskprefixes)
+ { if (-e $file)
+ { RemoveContextFile($file) } }
+ foreach $file (@dontasksuffixes)
+ { if (-e $file)
+ { RemoveContextFile($file) } }
+ foreach $suffix (@dontasksuffixes)
+ { foreach (@files)
+ { if (/$suffix$/i)
+ { RemoveContextFile($_) } } }
+ foreach $suffix (@forsuresuffixes)
+ { foreach (@files)
+ { if (/\.$suffix$/i)
+ { RemoveContextFile($_) } } }
+ foreach $file (@files)
+ { if ($file =~ /(.*?)\.\d+$/)
+ { $basename = $1 ;
+ if (($file =~ /mp(graph|run)/) || (-e "$basename.mp"))
+ { RemoveContextFile($file) } } }
+ foreach $suffix (@texnonesuffixes)
+ { foreach (@files)
+ { if (/(.*)\.$suffix$/i)
+ { if ((-e "$1.tex")||(-e "$1.xml")||(-e "$1.fo"))
+ { KeepContextFile($_) }
+ else
+ { $strippedname = $1 ;
+ $strippedname =~ s/\-[a-z]$//io ;
+ if ((-e "$strippedname.tex")||(-e "$strippedname.xml"))
+ { KeepContextFile($_." (potential result file)") }
+ else
+ { RemoveContextFile($_) } } } } }
+ if ($removedfiles||$keptfiles||$persistentfiles)
+ { print "\n" }
+ print " removed files : $removedfiles\n" ;
+ print " kept files : $keptfiles\n" ;
+ print " persistent files : $persistentfiles\n" ;
+ print " reclaimed bytes : $reclaimedbytes\n" }
+
+#D Another undocumented feature.
+#
+# obsolete, i.e now in pdftools, so this will become:
+#
+# sub AnalyzeFile
+# { system("pdftools --analyze $ARGV[0]") }
+
+sub AnalyzeFile
+ { my $filename = $ARGV[0] ;
+ return unless (($filename =~ /\.pdf/)&&(-e $filename)) ;
+ my $filesize = -s $filename ;
+ print " analyzing file : $filename\n" ;
+ print " file size : $filesize\n" ;
+ open (PDF, $filename) ;
+ binmode PDF ;
+ my $Object = 0 ;
+ my $Annot = 0 ;
+ my $Link = 0 ;
+ my $Widget = 0 ;
+ my $Named = 0 ;
+ my $Script = 0 ;
+ my $Cross = 0 ;
+ while (<PDF>)
+ { while (/\d+\s+\d+\s+obj/go) { ++$Object } ;
+ while (/\/Type\s*\/Annot/go) { ++$Annot } ;
+ while (/\/GoToR\s*\/F/go) { ++$Cross } ;
+ while (/\/Subtype\s*\/Link/go) { ++$Link } ;
+ while (/\/Subtype\s*\/Widget/go) { ++$Widget } ;
+ while (/\/S\s*\/Named/go) { ++$Named } ;
+ while (/\/S\s*\/JavaScript/go) { ++$Script } }
+ close (PDF) ;
+ print " objects : $Object\n" ;
+ print " annotations : $Annot\n" ;
+ print " links : $Link ($Named named / $Script scripts / $Cross files)\n" ;
+ print " widgets : $Widget\n" }
+
+# moved to ctxtools
+#
+# sub FilterPages
+# { system("ctxtools $ARGV{0]") }
+
+sub FilterPages # temp feature / no reporting
+ { my $filename = $ARGV[0] ;
+ return unless -f "$filename.pdf" ;
+ my $old = '' ;
+ my $n = 0 ;
+ if (open(PDF,"<$filename.pdf") && open(TUO,">>$filename.tuo"))
+ { binmode PDF ;
+ while (<PDF>)
+ { chomp ;
+ if (($_ eq '/Type /Page') && ($old =~ /^(\d+)\s+0\s+obj/o))
+ { ++$n ; $p = $1 ;
+ print TUO "\\objectreference{PDFP}{$n}{$p}{$n}\n" }
+ else
+ { $old = $_ } }
+ close(PDF) ;
+ close(TUO) } }
+
+ ShowBanner ;
+
+if ($UnknownOptions ) { ShowHelpInfo } # not yet done
+elsif ($ProcessReferences) { HandleReferences }
+elsif ($ProcessDocuments ) { HandleDocuments }
+elsif ($ProcessSources ) { HandleSources }
+elsif ($ProcessSetups ) { HandleSetups }
+elsif ($ProcessTemplates ) { HandleEditorCues }
+elsif ($ProcessInfos ) { HandleEditorCues }
+elsif ($ProcessFigures ) { HandleFigures }
+elsif ($ProcessLogFile ) { HandleLogFile }
+elsif ($PurgeFiles ) { PurgeFiles }
+elsif ($PurgeAllFiles ) { PurgeFiles }
+elsif ($AnalyzeFile ) { AnalyzeFile }
+elsif ($FilterPages ) { FilterPages }
+elsif ($SciteApi ) { GenerateSciteApi }
+elsif ($ProcessHelp ) { ShowHelpInfo } # redundant
+else { ShowHelpInfo }
+
+#D So far.