diff options
Diffstat (limited to 'usergrps/uktug/baskervi/8_3/texutil.pl')
-rw-r--r-- | usergrps/uktug/baskervi/8_3/texutil.pl | 2057 |
1 files changed, 2057 insertions, 0 deletions
diff --git a/usergrps/uktug/baskervi/8_3/texutil.pl b/usergrps/uktug/baskervi/8_3/texutil.pl new file mode 100644 index 0000000000..35701807e2 --- /dev/null +++ b/usergrps/uktug/baskervi/8_3/texutil.pl @@ -0,0 +1,2057 @@ +#!/usr/bin/perl +#-w + +#D \module +#D [ file=texutil.pl, +#D version=1998.06.05, +#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 script is part of the \CONTEXT\ macro||package and is +#C therefore copyrighted by \PRAGMA. Non||commercial use is +#C granted. + +# Thanks to Tobias Burnus for the german translations. +# Thanks to Taco Hoekwater for making the file -w proof. +# Thanks to Sebastan Ratz for the eps to pdf method + +# Due to recent extensions, this file must be optimized, +# e.g. some common stuctures in figure scanning can be sub'd. + +#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 This implementation is therefore not entirely compatible +#D with the original \TEXUTIL, although most users will +#D probably never notice. Now how was this program called? + +$Program = "TeXUtil 6.5 - ConTeXt / PRAGMA 1992-1998" ; + +#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 --interface=de --fig *.eps *.tif *.pdf *.png +#D \stoptypen +#D +#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 ; + +#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 Most task are handled by the procedures below. The one +# #D exception is the handling of \TIFF\ files when collecting +# #D illustration files. When needed, \TEXUTIL\ calls for +# #D \TIFFINFO\ or \TIFFTAGS, but more alternatives can be added +# #D by extending \type{@TiffPrograms}. +# #D +# #D @TiffPrograms = ("tiffinfo", "tifftags") ; + +#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.} + +$Interface = "en" ; +$UnknownOptions = 0 ; + +#D Here come the options: + +&GetOptions + ("references" => \$ProcessReferences, + "ij" => \$ProcessIJ, + "high" => \$ProcessHigh, + "quotes" => \$ProcessQuotes, + "documents" => \$ProcessDocuments, + "type=s" => \$ProcessType, + "outputfile=s" => \$ProcessOutputFile, + "sources" => \$ProcessSources, + "setups" => \$ProcessSetups, + "templates" => \$ProcessTemplates, + "infos" => \$ProcessInfos, + "figures" => \$ProcessFigures, + "eps" =>\$ProcessEps, + "tif" =>\$ProcessTif, + "pdf" =>\$ProcessPdf, + "png" =>\$ProcessPng, + "epspage" =>\$ProcessEpsPage, + "epstopdf" =>\$ProcessEpsToPdf, + "logfile" => \$ProcessLogFile, + "box" =>\$ProcessBox, + "hbox" =>\$ProcessHBox, + "vbox" =>\$ProcessVBox, + "criterium=f" =>\$ProcessCriterium, + "unknown" =>\$ProcessUnknown, + "help" => \$ProcessHelp, + "silent" => \$ProcessSilent, + "verbose" => \$ProcessVerbose, + "interface=s" => \$Interface) ; + +#D We need some hacks to suppress terminal output. This +#D piece of code is based on page~193 of "Programming Perl". + +sub RedirectTerminal + { open SAVEDSTDOUT, ">&STDOUT" ; + open STDOUT, ">$program.log" ; + 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, ">>$program.log" ; + 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. + +$InputFile = "@ARGV" ; + +sub CheckInputFiles + { my ($UserSuppliedPath) = @_ ; + @UserSuppliedFiles = map { split " " } sort lc $UserSuppliedPath } + +#D The next subroutine takes care of the optional output +#D filename (e.g. for figure dimensions). + +sub SetOutputFile + { ($OutFilNam, $OutFilSuf) = split (/\./, @_[0], 2) ; + unless ($ProcessOutputFile eq "") + { $ProcessOutputFile .= "." . $OutFilSuf ; + ($OutFilNam, $OutFilSuf, $Rubish) = split (/\./, $ProcessOutputFile , 3)} + $OutputFile = $OutFilNam . "." . $OutFilSuf } + +#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. + +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 ($Interface eq "nl") + + { # begin of dutch section + + $MS{"ProcessingReferences"} = "commando's, lijsten en indexen verwerken" ; + $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{"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{"MPFile"} = " metapost file :" ; + + $MS{"Overfull"} = "te vol" ; + $MS{"Entries"} = "ingangen" ; + $MS{"References"} = "verwijzingen" ; + + } # end of dutch section + +elsif ($Interface eq "de") + + { # begin of german section + + $MS{"ProcessingReferences"} = "Verarbeiten der Befehle, Listen und Register" ; + $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{"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"} = " too many pages :" ; # TOBIAS + $MS{"MissingMediaBox"} = " missing mediabox :" ; # TOBIAS + $MS{"MissingBoundingBox"} = " missing boundingbox :" ; # TOBIAS + + $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{"MPFile"} = " metapost-Datei :" ; + + $MS{"Overfull"} = "zu voll" ; + $MS{"Entries"} = "Eintraege" ; + $MS{"References"} = "Referenzen" ; + + } # end of german section + +else + + { # begin of english section + + $MS{"ProcessingReferences"} = "processing commands, lists and 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{"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{"MPFile"} = " metapost file :" ; + + $MS{"Overfull"} = "overfull" ; + $MS{"Entries"} = "entries" ; + $MS{"References"} = "references" ; + + } # 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 ($Interface 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" . +" \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" . +" --eps : eps files verwerken \n" . +" --tif : tif files verwerken \n" . +" --pdf : pdf files verwerken \n" . +" --png : png files verwerken \n" . +" --epspage : voorbereiden voor pdf \n" . +" --epstopdf : omzetten naar pdf \n" . +" \n" . +" --logfile logfile filteren / log->texutil.log \n" . +" --box : overfull boxes controleren \n" . +" --criterium : overfull criterium in pt \n" . +" --unknown :onbekende ... controleren \n" ; + + } # end of dutch section + +elsif ($Interface eq "de") # TOBIAS ! + + { # 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" . +" \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" . +" --eps : Verarbeite eps-Dateien \n" . +" --tif : Verarbeite tif-Dateien \n" . +" --pdf : Verarbeite pdf-Dateien \n" . +" --png : Verarbeite png-Dateien \n" . +" --epspage : prepare voor pdf \n" . +" --epstopdf : convert to \n" . +" \n" . +" --logfile Filtere log-Datei / log->texutil.log \n" . +" --box : Ueberpruefe uebervolle Boxen \n" . +" --criterium : Uebervoll-Kriterium in pt \n" . +" --unknown : Ueberpruefe auf unbekannte ... \n" ; + + } # end of german 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" . +" \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" . +" --eps : process eps files \n" . +" --tif : process tif files \n" . +" --pdf : process pdf files \n" . +" --png : process png files \n" . +" --epspage : prepare voor pdf \n" . +" --epstopdf : convert to \n" . +" \n" . +" --logfile filter logfile / log->texutil.log \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 \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 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 + { print TUO "%\n" . "% $Program / Files\n" . "%\n" ; + foreach $File (keys %Files) + { print TUO "% $File ($Files{$File})\n" } + print TUO "%\n" ; + $NOfFiles = keys %Files ; + Report("EmbeddedFiles", $NOfFiles) ; + foreach $File (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 \realnumberofpages{number} +#D \stoptypen +#D +#D For historic reasons we check for the presense of the +#D backslash. + +sub InitializeCommands + { print TUO "%\n" . "% $Program / Commands\n" . "%\n" ; + $NOfCommands = 0 } + +sub HandleCommand + { ++$NOfCommands ; + $RestOfLine =~ s/^\\//go ; + print TUO "\\$RestOfLine\n" } + +sub FlushCommands + { Report ("PassedCommands", $NOfCommands) } + +#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] = + $Class . $JOIN . + $Key . $JOIN . + $Entry . $JOIN . + $Meaning ; + $SynonymEntry[$NOfSynonyms+1] = "" ; } } + +#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. + +$SynonymEntry[0] = ("") ; # TH: initalize + +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 ($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 \stoptypen + +#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 = "" ; # TH: initialize + +sub HandleRegister + { ($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 ($Key eq "") + { $Key = SanitizedString($Entry) } + 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 } + $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 } + else + { $Entry =~ s/([^\\])\&/$1$SPLIT/go ; + $Entry =~ s/([^\\])\+/$1$SPLIT/go } + $Key =~ s/^([^a-zA-Z])/ $1/go ; + if ($ProcessIJ) + { $Key =~ s/ij/yy/go } + $LCKey = lc $Key ; + $RegisterEntry[$NOfEntries] = + $Class . $JOIN . + $LCKey . $JOIN . + $Key . $JOIN . + $Entry . $JOIN . + $RealPage . $JOIN . + $Location . $JOIN . + $Page . $JOIN . + $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 \stopbuffer +#D +#D \typebuffer +#D +#D \haalbuffer After being sorted, these entries are +#D turned into something \TEX\ using: + +$RegisterEntry[0] = ("") ; # TH: initialize + +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 = "" ; + for ($n=1 ; $n<=$NOfEntries ; ++$n) + { ($Class, $LCKey, $Key, $Entry, $RealPage, $Location, $Page, $SeeToo) = + split(/$JOIN/, $RegisterEntry[$n]) ; + if (((lc substr $Key, 0, 1) ne lc $Alfa) or ($AlfaClass ne $Class)) + { $Alfa= lc substr $Key, 0, 1 ; + $AlfaClass = $Class ; + if ($Alfa ne " ") + { print TUO "\\registerentry{$Class}{$Alfa}\n" } } + ($ActualA, $ActualB, $ActualC ) = + split(/$SPLIT/, $Entry, 3) ; + unless ($ActualA) { $ActualA = "" } # TH: this would be an error + unless ($ActualB) { $ActualB = "" } # TH: might become undef through split() + unless ($ActualC) { $ActualC = "" } # TH: might become undef through split() + if ($ActualA eq $PreviousA) + { $ActualA = "" } + else + { $PreviousA = $ActualA ; + $PreviousB = "" ; + $PreviousC = "" } + if ($ActualB eq $PreviousB) + { $ActualB = "" } + else + { $PreviousB = $ActualB ; + $PreviousC = "" } + if ($ActualC eq $PreviousC) + { $ActualC = "" } + else + { $PreviousC = $ActualC } + $Copied = 0 ; + if ($ActualA ne "") + { print TUO "\\registerentrya{$Class}{$ActualA}\n" ; + $Copied = 1 } + if ($ActualB ne "") + { print TUO "\\registerentryb{$Class}{$ActualB}\n" ; + $Copied = 1 } + if ($ActualC ne "") + { print TUO "\\registerentryc{$Class}{$ActualC}\n" ; + $Copied = 1 } + if ($Copied) + { $NOfSaneEntries++ } + if ($RealPage eq 0) + { print TUO "\\registersee{$Class}{$SeeToo}{$Page}\n" ; + $LastPage = $Page ; + $LastRealPage = $RealPage } + elsif (($Copied) || + ! (($LastPage eq $Page) and ($LastRealPage eq $RealPage))) + { print TUO "\\registerpage{$Class}{$Location}{$Page}{$RealPage}\n" ; + ++$NOfSanePages ; + $LastPage = $Page ; + $LastRealPage = $RealPage } } + 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. + +sub FlushData + { print TUO + "% \n" . + "% embedded files : $NOfFiles ($NOfBadFiles errors)\n" . + "% passed commands : $NOfCommands\n" . + "% synonym entries : $NOfSynonyms ($NOfBadSynonyms errors)\n" . + "% register entries : $NOfEntries ($NOfBadEntries errors)" } + +#D The functionallity described on the previous few pages is +#D called upon in the main routine: + +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 ($SomeLine=<TUI>) + { 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 } + else + { unlink "$InputFile.tuo" ; + rename "$InputFile.tmp", "$InputFile.tuo" ; + Report ("Error", "NoOutputFile") } } } } + +#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. + +sub HandleDocuments + { Report("Action", "HandlingDocuments") ; + if ($ProcessType ne "") + { Report("Option", "ForcingFileType", $ProcessType) } + if ($InputFile eq "") + { Report("Error", "NoInputFile") } + else + { CheckInputFiles ($InputFile) ; + foreach $FullName (@UserSuppliedFiles) + { ($FileName, $FileSuffix) = split (/\./, $FullName, 2) ; + 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 ; + if ($ProcessType eq "") + { $FileType=lc $FileSuffix } + else + { $FileType=lc $ProcessType } + Report("FileType", $FileType) ; + print TED "\\startmodule[type=$FileType]\n" ; + while (<TEX>) # TH: $SomeLines replaced by $_ + { chomp ; + if (/^[%\#]D/) + { if ($SkipLevel == 0) + { if (length $_ < 3) # TH: empty #D comment + {$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 ($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) = split (/\./, $FullName, 2) ; + 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 ($SomeLine=<TEX>) + { 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) ; # TH: repaired + 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) = split (/\./, $FullName, 2) ; + 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 ($SomeLine=<TEX>) + { 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) = split (/\./, $FullName, 2) ; + 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 ($SomeLine=<TEX>) + { 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\ or \PNG\ 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. + +$PTtoCM = 2.54/72.0 ; +$INtoCM = 2.54 ; + +sub SaveFigurePresets + { my ($FNam, $FTyp, $FXof, $FYof, $FWid, $FHei, $FTit, $FCre, $FSiz) = @_ ; + if ($ProcessVerbose) + { OpenTerminal ; + print "n=$FNam t=$FTyp" . + (sprintf " x=%5.3fcm y=%5.3fcm", $FXof, $FYof) . + (sprintf " w=%5.3fcm h=%5.3fcm\n", $FWid, $FHei) ; + CloseTerminal } + else + { ++$NOfFigures ; + $Figures[$NOfFigures] = "\\presetfigure[$FNam][e=$FTyp" . + (sprintf ",w=%5.3fcm,h=%5.3fcm", $FWid, $FHei) ; + if (($FXof!=0)||($FYof!=0)) + { $Figures[$NOfFigures] .= (sprintf ",x=%5.3fcm,y=%5.3fcm", $FXof, $FYof) } + if ($FTit) + { $Figures[$NOfFigures] .= ",t=\{$FTit\}" } + if ($FCre) + { $Figures[$NOfFigures] .= ",c=\{$FCre\}" } + $Figures[$NOfFigures] .= ",s=$FSiz]\n" } } + +#D The \EPS\ to \PDF\ conversion is inspired by a script posted +#D by Sebastian Ratz at the \PDFTEX\ mailing list. + +sub ConvertEpsToEps + { my ( $SuppliedFileName , $LLX, $LLY, $URX, $URY ) = @_ ; + ($FileName, $FileSuffix) = split (/\./, $SuppliedFileName, 2) ; + if ($ProcessEpsToPdf) + { unlink "$FileName.pdf" ; + $GSCommandLine = "-q " . + "-sDEVICE=pdfwrite " . + "-dNOCACHE " . + "-dUseFlateCompression=false " . + "-sDEVICE=pdfwrite " . + "-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 (/^%%(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) + { last } + else + { print EPS $_ } } + close ( TMP ) ; + if ($EpsBBOX) + { 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 ) = @_ ; + ($FileName, $FileSuffix) = split ( /\./, $SuppliedFileName, 2) ; + $Temp = $FileSuffix; + $Temp =~ s/[0-9]//go; + if ($Temp eq "") + { $EpsFileName = $SuppliedFileName; + Report ( "MPFile", "$SuppliedFileName" ) } + elsif (lc $FileSuffix ne "eps") + { return } + else + { $EpsFileName = $SuppliedFileName; # $FileName + Report ( "EpsFile", "$SuppliedFileName" ) } + $HiResBBOX = "" ; + $LoResBBOX = "" ; + $EpsTitle = "" ; + $EpsCreator = "" ; + open ( EPS , $SuppliedFileName ) ; + binmode EPS ; + $EpsSize = -s EPS ; + $PDFReady = 0 ; + $MPSFound = 0 ; + $BBoxFound = 0 ; + while ($SomeLine = <EPS>) + { chomp $SomeLine ; + if ( ($BBoxFound) && ((substr $SomeLine,0,1) ne "%") ) + { last } + unless ($HiResBBOX) + { if ($SomeLine =~ /^%%BoundingBox:/io) + { ($Tag, $LoResBBOX) = split (/ /, $SomeLine, 2) ; + $BBoxFound = 1 ; next } + elsif ($SomeLine =~ /^%%HiResBoundingBox:/io) + { ($Tag, $HiResBBOX) = split (/ /, $SomeLine, 2) ; + $BBoxFound = 1 ; next } + elsif ($SomeLine =~ /^%%ExactBoundingBox:/io) + { ($Tag, $HiResBBOX) = split (/ /, $SomeLine, 2) ; + $BBoxFound = 1 ; 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) + { if ($HiResBBOX) + { $EpsBBOX = $HiResBBOX } + else + { $EpsBBOX = $LoResBBOX } + if ($EpsBBOX) + { ($LLX, $LLY, $URX, $URY, $RestOfLine) = split (/ /, $EpsBBOX, 5 ) ; + $EpsHeight = ($URY-$LLY)*$PTtoCM ; + $EpsWidth = ($URX-$LLX)*$PTtoCM ; + $EpsXOffset = $LLX*$PTtoCM ; + $EpsYOffset = $LLY*$PTtoCM ; + if ($ProcessGS) + { $EpsType = "pdf" } + elsif ($MPSFound) + { $EpsType = "mps" } + else + { $EpsType = "eps" } + SaveFigurePresets + ( $EpsFileName, $EpsType, + $EpsXOffset, $EpsYOffset, $EpsWidth, $EpsHeight, + $EpsTitle, $EpsCreator, $EpsSize ) ; + if (($ProcessEpsPage) || ($ProcessEpsToPdf)) + { ConvertEpsToEps ( $SuppliedFileName, $LLX, $LLY, $URX, $URY ) } } } + else + { Report ( "MissingBoundingBox", "$SuppliedFileName" ) } } + +sub HandleEpsFigures + { if ($InputFile eq "") + { $InputFile = "*.eps" } + CheckInputFiles ($InputFile) ; + foreach $FileName (@UserSuppliedFiles) + { HandleEpsFigure ( $FileName ) } } + +#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) = split ( /\./, $SuppliedFileName, 2) ; + 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 ($SomeLine = <PDF>) + { chomp ($SomeLine) ; + if ($SomeLine =~ /\/Type \/Pages/io) + { $PagesFound = 1 } + elsif ($SomeLine =~ /\/Type \/Page/io) + { ++$PageFound ; + if ($PageFound>1) { last } } + elsif ((($PageFound)||($PagesFound)) && ($SomeLine =~ /\/MediaBox /io)) + { ($Tag, $MediaBox) = split (/ /, $SomeLine, 2) ; + $MediaBoxFound = 1 ; + if ($PagesFound) { last } } } + close ( PDF ) ; + if ($PageFound>1) + { Report ( "MultiPagePdfFile", "$SuppliedFileName" ) } + elsif (($MediaBoxFound) && ($MediaBox)) + { ($MediaBox, $RestOfLine) = split (/\]/, $MediaBox, 2 ) ; + ($RestOfLine, $MediaBox) = split (/\[/, $MediaBox, 2 ) ; + ($LLX, $LLY, $URX, $URY, $RestOfLine) = split (/ /, $MediaBox, 5 ) ; + $PdfHeight = ($URY-$LLY)*$PTtoCM ; + $PdfWidth = ($URX-$LLX)*$PTtoCM ; + $PdfXOffset = $LLX*$PTtoCM ; + $PdfYOffset = $LLY*$PTtoCM ; + SaveFigurePresets + ( $PdfFileName, "pdf", + $PdfXOffset, $PdfYOffset, $PdfWidth, $PdfHeight, + "", "", $PdfSize ) } + else + { Report ( "MissingMediaBox", "$SuppliedFileName" ) } } + +sub HandlePdfFigures + { if ($InputFile eq "") + { $InputFile = "*.pdf" } + CheckInputFiles ($InputFile) ; + foreach $FileName (@UserSuppliedFiles) + { HandlePdfFigure ( $FileName ) } } + +# #D Here we call the programs that generate information on +# #D the \TIFF\ files. The names of the programs are defined +# #D earlier. +# +# sub RunTifPrograms +# { $FindTifFigure = "" ; +# $UsedTifProgram = "" ; +# unlink "tifdata.tmp" ; +# foreach $TifProgram (@TifPrograms) +# { if ((system ("$TifProgram *.tif > tifdata.tmp") == 0) +# && (-s "tifdata.tmp")) +# { $UsedTifProgram = $TifProgram ; +# $FindTifFigure = "FindTifFigure_$UsedTifProgram" ; +# last } } } +# +# #D The scanning routines use filehandle \type{TMP} and call for +# #D \type{ReportTifFigure} with the arguments \type{Name}, +# #D \type{Width} and \type{Height}. +# +# sub ReportTifFigure +# { my ($Name, $Width, $Height) = @_ ; +# $Name = lc $Name ; +# # +# # if ($InputFile ne "") +# # { $Ok = 0 ; +# # foreach $IFile (@UserSuppliedFiles) +# # { $Ok = ($Ok || ($IFile eq "$Name.tif" )) } +# # else +# # { $Ok = 1 } +# # +# $Ok = 1 ; +# # +# if ($Ok) +# { $Size = -s "$Name.tif" ; +# Report ( "TifFile", "$Name.tif") ; +# $Figures[++$NOfFigures] = +# "\\presetfigure[$Name][e=tif" . +# (sprintf ",w=%5.3fcm,h=%5.3fcm", $Width, $Height) . +# ",s=$Size]\n" } } +# +# sub HandleTifFigures +# { if ($ProcessTif) +# { if (-s "tifdata.tmp") +# { Report ( "SystemCall", "$UsedTifProgram -> tifdata.tmp" ) ; +# if ((defined &$FindTifFigure) && (open(TMP, "tifdata.tmp"))) +# { &$FindTifFigure } +# else +# { Report ( "MissingSubroutine", $FindTifFigure ) } } +# else +# { } } } # Report ( "BadSystemCall", "@TifPrograms" ) } } } +# +# #D The next few routines are program specific. Let's cross our +# #D fingers on the stability off their output. As one can +# #D see, we have to work a bit harder when we use \TIFFINFO\ +# #D instead of \TIFFTAGS. +# +# sub FindTifFigure_tiffinfo +# { while ( $TifName = <TMP> ) +# { chomp $TifName ; +# if (($TifName =~ s/^(.*)\.tif\:.*/$1/i) && +# ($SomeLineA = <TMP>) && ($SomeLineA = <TMP>) && +# ($SomeLineA = <TMP>) && ($SomeLineB = <TMP>)) +# { chomp $SomeLineA ; +# $TifWidth = $SomeLineA ; +# $TifWidth =~ s/.*Image Width: (.*) .*/$1/i ; +# $TifHeight = $SomeLineA ; +# $TifHeight =~ s/.*Image Length: (.*).*/$1/i ; +# $TifWRes = $SomeLineB ; +# $TifWRes =~ s/.*Resolution: (.*)\,.*/$1/i ; +# $TifHRes = $SomeLineB ; +# $TifHRes =~ s/.*Resolution: .*\, (.*).*/$1/i ; +# $TifWidth = ($TifWidth/$TifWRes)*$INtoCM ; +# # $TifHeight = ($TifHeight/$TifHRes)*$INtoCM ; +# ReportTifFigure ($TifName, $TifWidth, $TifHeight) } } } +# +# sub FindTifFigure_tifftags +# { while ( $TifName = <TMP> ) +# { chomp $TifName ; +# if (($TifName =~ s/.*\`(.*)\.tif\'.*/$1/i) && +# ($SomeLine = <TMP>) && ($SomeLine = <TMP>)) +# { chomp $SomeLine ; +# $TifWidth = $SomeLine ; +# $TifWidth =~ s/.*\((.*) pt.*\((.*) pt.*/$1/ ; +# $TifHeight = $SomeLine ; +# $TifHeight =~ s/.*\((.*) pt.*\((.*) pt.*/$2/ ; +# $TifWidth = $TifWidth*$PTtoCM ; +# $TifHeight = $TifHeight*$PTtoCM ; +# ReportTifFigure ($TifName, $TifWidth, $TifHeight) } } } + +#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 ($S_1) ; + read TIF, $S_1, 1 ; + return ( ord($S_1) ) } + +sub TifGetShort + { my ($S_1, $S_2) ; + if ($TifLittleEndian) + { read TIF, $S_2, 1 ; + read TIF, $S_1, 1 } + else + { read TIF, $S_1, 1 ; + read TIF, $S_2, 1 } + return ( ord($S_1)*256 + + ord($S_2) ) } + +sub TifGetLong + { my ($S_1, $S_2, $S_3, $S_4) ; + if ($TifLittleEndian) + { read TIF, $S_4, 1 ; + read TIF, $S_3, 1 ; + read TIF, $S_2, 1 ; + read TIF, $S_1, 1 } + else + { read TIF, $S_1, 1 ; + read TIF, $S_2, 1 ; + read TIF, $S_3, 1 ; + read TIF, $S_4, 1 } + return ( ord($S_1)*16777216 + + ord($S_2)*65536 + + ord($S_3)*256 + + ord($S_4) ) } + +sub TifGetRational + { my ($N, $M) ; + $N = TifGetLong ; + $M = TifGetLong ; + return $N/$M } + +sub TifGetAscii + { my ($S) ; + --$TifValues; + if ($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 ; + #print "[start at $TifNextChunk with length $Length]\n" ; + $TifNextChunk += 2 ; + for ($i=1; $i<=$Length; $i++) + { seek TIF, $TifNextChunk, 0 ; + $TifTag = TifGetShort ; + $TifType = TifGetShort ; + $TifValues = TifGetLong ; + #print "[tag $TifTag of type $TifType]\n" ; + 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 ; + #print $TifNextChunk; + return ($TifNextChunk>0) } + +sub TifAnalyzeFile + { my ( $SuppliedFileName ) = @_ ; + ($FileName, $FileSuffix) = split ( /\./, $SuppliedFileName, 2) ; + if (lc $FileSuffix ne "tif") + { return } + else + { $TifFile = $SuppliedFileName ; + Report ( "TifFile", "$SuppliedFileName" ) } + $TifSize = 0 ; + $TifWidth = 0 ; + $TifHeight = 0 ; + $TifTitle = "" ; + $TifAuthor = "" ; + $TifCreator = "" ; + $TifUnit = 0 ; + $TifHRes = 1 ; + $TifVRes = 1 ; + open ( TIF, $TifFile ) ; + binmode TIF; + $TifSize = -s TIF ; + seek TIF, 0, 0 ; + read TIF, $TifByteOrder, 2 ; + $TifLittleEndian = ($TifByteOrder eq "II") ; + $TifTag = TifGetShort; + unless ($TifTag == 42) + { close ( TIF ) ; + return } + $TifNextChunk = TifGetLong ; + while (TifGetChunk) { } + #print "[$TifWidth,$TifHeight,$TifUnit,$TifHRes,$TifVRes]\n"; + if ($TifUnit==2) + { $TifMult = $INtoCM } + else + { $TifMult = 1 } + $TifWidth = ($TifWidth /$TifHRes)*$TifMult ; + $TifHeight = ($TifHeight/$TifVRes)*$TifMult ; + unless ($TifUnit) + { while ($TifHeight>20) + { $TifHeight /= 5 ; $TifWidth /= 5 } } + close ( TIF ) ; + SaveFigurePresets + ( $TifFile, "tif", + 0, 0, $TifWidth, $TifHeight, + $TifTitle, $TifCreator, $TifSize ) } + +sub HandleTifFigures + { if ($InputFile eq "") + { $InputFile = "*.tif" } + CheckInputFiles ($InputFile) ; + foreach $FileName (@UserSuppliedFiles) + { TifAnalyzeFile ( $FileName ) } } + +#D I first intended to use the public utility \type{pngmeta} +#D (many thanks to Taco for comiling 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: + +sub PngGetInteger + { my ($S_1, $S_2, $S_3, $S_4) ; + read PNG, $S_1, 1 ; + read PNG, $S_2, 1 ; + read PNG, $S_3, 1 ; + read PNG, $S_4, 1 ; + return ( ord($S_1)*16777216 + + ord($S_2)*65526 + + ord($S_3)*256 + + ord($S_4) ) } + +sub PngGetChunk + { seek PNG, $PngNextChunk, 0 ; + $Length = PngGetInteger ; + $PngNextChunk = $PngNextChunk + $Length + 12 ; + read PNG, $PngType, 4 ; + if ($PngType eq "") + { return 0 } + elsif ($PngType eq "IHDR") + { $PngWidth = PngGetInteger ; + $PngHeight = PngGetInteger } + elsif ($PngType eq "pHYs") + { $PngHRes = PngGetInteger ; + $PngVRes = PngGetInteger ; + read PNG, $PngUnit, 1 } + elsif ($PngType eq "tEXt") + { read PNG, $PngKeyword, 79 ; + read PNG, $Temp, 1 ; + if ( $PngKeyword eq "Title") + { read PNG, $PngTitle, $Length } + elsif ( $PngKeyword eq "Author") + { read PNG, $PngAuthor, $Length } + elsif ( $PngKeyword eq "Software") + { read PNG, $PngCreator, $Length } } + return 1 } + +sub PngAnalyzeFile + { my ( $SuppliedFileName ) = @_ ; + ($FileName, $FileSuffix) = split ( /\./, $SuppliedFileName, 2) ; + if (lc $FileSuffix ne "png") + { return } + else + { $PngFile = $SuppliedFileName ; + Report ( "PngFile", "$SuppliedFileName" ) } + $PngSize = 0 ; + $PngWidth = 0 ; + $PngHeight = 0 ; + $PngTitle = "" ; + $PngAuthor = "" ; + $PngCreator = "" ; + $PngUnit = 0 ; + $PngVRes = 1 ; + $PngHRes = 1 ; + $PngSignature = chr(137) . chr(80) . chr(78) . chr(71) . + chr (13) . chr(10) . chr(26) . chr(10) ; + open ( PNG, $PngFile ) ; + binmode PNG ; + $PngSize = -s PNG ; + seek PNG, 0, 0 ; + read PNG, $Str, 8; + unless ($Str eq $PngSignature) + { close ( PNG ) ; + return } + $PngNextChunk = 8 ; + while (PngGetChunk) { } + $PngWidth = ($PngWidth /$PngVRes) ; + $PngHeight = ($PngHeight/$PngHRes) ; + unless ($PngUnit) + { while ($PngHeight>20) + { $PngHeight /= 5 ; $PngWidth /= 5 } } + close ( PNG ) ; + SaveFigurePresets + ( $PngFile, "png", + 0, 0, $PngWidth, $PngHeight, + $PngTitle, $PngCreator, $PngSize ) } + +sub HandlePngFigures + { if ($InputFile eq "") + { $InputFile = "*.png" } + CheckInputFiles ($InputFile) ; + foreach $FileName (@UserSuppliedFiles) + { PngAnalyzeFile ( $FileName ) } } + +#D Now we can handle figures! + +sub InitializeFigures + { $NOfFigures = 0 } + +sub FlushFigures + { $Figures = sort { lc ($a) cmp lc ($b) } $Figures ; + 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 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 } } + InitializeFigures ; + HandleEpsFigures ; + HandlePdfFigures ; + HandleTifFigures ; + HandlePngFigures ; + 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{texutil.log}. 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 = "onbekend|unknown|unbekant" ; + +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 ("$Program.log") ; + Report("OutputFile", $OutputFile) ; + CheckInputFiles ($InputFile) ; + open ( ALL, ">$OutputFile" ) ; + foreach $FullName (@UserSuppliedFiles) + { ($FileName, $FileSuffix) = split (/\./, $FullName, 2) ; + if (! open (LOG, "$FileName.log")) + { Report("Error", "EmptyInputFile", "$FileName.$FileSuffix" ) } + elsif (-e "$FileName.tex") + { $TopicFound = 0 ; + Report("InputFile", "$FileName.log") ; + while ($SomeLine=<LOG>) + { chomp $SomeLine ; + if (($ProcessBox) && ($SomeLine =~ /Overfull \\$Key/)) + { ++$NOfBoxes ; + $SomePoints = $SomeLine ; + $SomePoints =~ s/.*\((.*)pt.*/$1/ ; + if ($SomePoints>=$ProcessCriterium) + { ++$NOfMatching ; + FlushLogTopic ; + print ALL "$SomeLine" ; + $SomeLine=<LOG> ; + print ALL $SomeLine } } + if (($ProcessUnknown) && ($SomeLine =~ /$Unknown/io)) + { ++$NOfUnknown ; + FlushLogTopic ; + print ALL "$SomeLine" } } } } + close (ALL) ; + unless (($NOfBoxes) ||($NOfUnknown)) + { unlink $OutputFile } + if ($ProcessBox) + { Report ( "NOfBoxes" , "$NOfBoxes", "->", $NOfMatching, "Overfull") } + if ($ProcessUnknown) + { Report ( "NOfUnknown", "$NOfUnknown") } } } + +#D We're done! All this actions and options are organized in +#D one large conditional: + + 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 ($ProcessHelp ) { ShowHelpInfo } # redundant +else { ShowHelpInfo } + +#D So far. |