diff options
Diffstat (limited to 'scripts')
28 files changed, 5468 insertions, 446 deletions
diff --git a/scripts/context/perl/makempy.pl b/scripts/context/perl/makempy.pl index 49298f318..5b52ee0bb 100644 --- a/scripts/context/perl/makempy.pl +++ b/scripts/context/perl/makempy.pl @@ -18,8 +18,8 @@ eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $ # of binaries on UNIX as well as did some usefull suggestions # to improve the functionality. -# This script uses GhostScript and PStoEdit as well as -# pdfTeX, and if requested TeXEdit and ConTeXt. +# This script uses GhostScript and PStoEdit as well as +# pdfTeX, and if requested TeXEdit and ConTeXt. # todo: we can nowadays do without the intermediate step, because GS # can now handle PDF quite good diff --git a/scripts/context/perl/texexec.pl b/scripts/context/perl/texexec.pl index fe6c8421f..0e6e5d098 100644 --- a/scripts/context/perl/texexec.pl +++ b/scripts/context/perl/texexec.pl @@ -34,6 +34,8 @@ eval '(exit $?0)' && eval 'exec perl -w -S $0 ${1+"$@"}' && eval 'exec perl -w - use strict ; +my $OriginalArgs = join(' ',@ARGV) ; + #~ use warnings ; # strange warnings, todo # todo: second run of checksum of mp file with --nomprun changes @@ -48,6 +50,9 @@ use Getopt::Long; use Class::Struct; # needed for help subsystem use FindBin; use File::Compare; +use File::Temp; + +use IO::Handle; autoflush STDOUT 1; my %ConTeXtInterfaces; # otherwise problems with strict my %ResponseInterface; # since i dunno how to allocate else @@ -195,11 +200,15 @@ my $Paranoid = 0 ; my $NotParanoid = 0 ; my $BoxType = '' ; +my $TempDir = '' ; + my $StartLine = 0 ; my $StartColumn = 0 ; my $EndLine = 0 ; my $EndColumn = 0 ; +my $MpEngineSupport = 0 ; # not now, we also need to patch executemp in context itself + # makempy : my $MakeMpy = ''; @@ -303,6 +312,8 @@ my $MakeMpy = ''; "paranoid" => \$Paranoid, "notparanoid" => \$NotParanoid, "boxtype=s" => \$BoxType, # media art crop bleed trim + #### unix is unsafe (symlink viruses) + "tempdir=s" => \$TempDir, #### experiment "startline=s" => \$StartLine, "startcolumn=s" => \$StartColumn, @@ -409,7 +420,7 @@ if ( ( $LogFile ne '' ) && ( $LogFile =~ /\w+\.log$/io ) ) { *STDERR = *LOGFILE; } -my $Program = " TeXExec 5.2.5 - ConTeXt / PRAGMA ADE 1997-2005"; +my $Program = " TeXExec 5.3.2 - ConTeXt / PRAGMA ADE 1997-2005"; print "\n$Program\n\n"; @@ -742,7 +753,9 @@ my $MpVirginFlag = IniValue( 'MpVirginFlag', '-ini' ); my $MpPassString = IniValue( 'MpPassString', '' ); my $MpFormat = IniValue( 'MpFormat', $MetaFun ); my $MpFormatPath = IniValue( 'MpFormatPath', $TeXFormatPath ); -my $UseEnginePath = IniValue( 'UseEnginePath', $TheEnginePath); +my $UseEnginePath = IniValue( 'UseEnginePath', ''); + +if ($TheEnginePath) { $UseEnginePath = 1 } my $FmtLanguage = IniValue( 'FmtLanguage', '' ); my $FmtBodyFont = IniValue( 'FmtBodyFont', '' ); @@ -787,18 +800,20 @@ if ( $MpFormatFlag eq "" ) { $MpFormatFlag = "-mem=" ; } -if ($UseEnginePath && (! $MakeFormats)) { - $MpFormatFlag .= $MpExecutable . '/' ; - $TeXFormatFlag .= $TeXExecutable . '/' ; -} +#~ if ($UseEnginePath && (! $MakeFormats)) { + #~ if ($MpEngineSupport) { + #~ $MpFormatFlag .= $MpExecutable . '/' ; + #~ } ; + #~ $TeXFormatFlag .= $TeXExecutable . '/' ; +#~ } #~ if ( $TeXFormatFlag eq "" ) { $TeXFormatFlag = "&" } #~ if ( $MpFormatFlag eq "" ) { $MpFormatFlag = "&" } -unless ( $dosish && !$escapeshell ) { - if ( $TeXFormatFlag eq "&" ) { $TeXFormatFlag = "\\&" } - if ( $MpFormatFlag eq "&" ) { $MpFormatFlag = "\\&" } -} +#~ unless ( $dosish && !$escapeshell ) { + #~ if ( $TeXFormatFlag eq "&" ) { $TeXFormatFlag = "\\&" } + #~ if ( $MpFormatFlag eq "&" ) { $MpFormatFlag = "\\&" } +#~ } if ($TeXProgram) { $TeXExecutable = $TeXProgram } @@ -1490,6 +1505,10 @@ sub PrepRunTeX { if ( $TeXTranslation ne '' ) { $cmd .= "-translate-file=$TeXTranslation " } $cmd .= "$TeXFormatFlag$TeXFormatPath$Format $JobName.$JobSuffix $PipeString"; if ($Verbose) { print "\n$cmd\n\n" } +unless ( $dosish && ! $escapeshell ) { + #~ $cmd =~ s/[^\\]\&/\\\&/io ; + $cmd =~ s/([^\\])\&/$1\\\&/io ; +} return $cmd; } @@ -1497,6 +1516,7 @@ sub RunTeX { my ( $JobName, $JobSuffix ) = @_; my $StartTime = time; my $cmd = PrepRunTeX($JobName, $JobSuffix, ''); + print $cmd if ($Verbose) ; if ($EnterBatchMode) { $Problems = system("$cmd"); } else { @@ -1667,7 +1687,7 @@ sub CopyFile { # agressive copy, works for open files like in gs close(OUT); } -sub CheckChanges { # also tub +sub CheckMPChanges { my $JobName = shift; my $checksum = 0; my $MPJobName = MPJobName( $JobName, "mpgraph" ); @@ -1691,6 +1711,18 @@ sub CheckChanges { # also tub return $checksum; } +sub CheckTubChanges { + my $JobName = shift; + my $checksum = 0; + if ( open( TUB, "$JobName.tub" ) ) { + while (<TUB>) { + $checksum += do { unpack( "%32C*", <TUB> ) % 65535 } + } + close(TUB); + } + return $checksum; +} + my $DummyFile = 0; sub isXMLfile { @@ -1854,9 +1886,12 @@ if ($JobSuffix =~ /\_fo$/i) { } print " TeX run : $TeXRuns\n\n"; my ( $mpchecksumbefore, $mpchecksumafter ) = ( 0, 0 ); - if ($AutoMPRun) { $mpchecksumbefore = CheckChanges($JobName) } + my ( $tubchecksumbefore, $tubchecksumafter ) = ( 0, 0 ); + if ($AutoMPRun) { $mpchecksumbefore = CheckMPChanges($JobName) } + $tubchecksumbefore = CheckTubChanges($JobName) ; $Problems = RunTeX( $JobName, $JobSuffix ); - if ($AutoMPRun) { $mpchecksumafter = CheckChanges($JobName) } + $tubchecksumafter = CheckTubChanges($JobName) ; + if ($AutoMPRun) { $mpchecksumafter = CheckMPChanges($JobName) } if ( ( !$Problems ) && ( $NOfRuns > 1 ) ) { if ( !$NoMPMode ) { $MPrundone = RunTeXMP( $JobName, "mpgraph" ); @@ -1868,6 +1903,9 @@ if ($JobSuffix =~ /\_fo$/i) { ( $StopRunning && ( $mpchecksumafter == $mpchecksumbefore ) ); } + $StopRunning = + ( $StopRunning + && ( $tubchecksumafter == $tubchecksumbefore ) ); } } if ( ( $NOfRuns == 1 ) && $ForceTeXutil ) { @@ -2043,7 +2081,7 @@ sub RunListing { foreach $FileName (@FileNames) { $CleanFileName = lc CleanTeXFileName($FileName); print LIS "\\page\n"; - print LIS "\\setupfootertexts[\\tttf $CleanFileName][\\tttf \pagenumber]\n"; + print LIS "\\setupfootertexts[\\tttf $CleanFileName][\\tttf \\pagenumber]\n"; print LIS "\\typefile\{$FileName\}\n"; } print LIS "\\stoptext\n"; @@ -2248,33 +2286,76 @@ sub RunCombine { sub LocatedFormatPath { my $FormatPath = shift; my $EnginePath = shift; + my $EngineDone = shift; if ( ( $FormatPath eq '' ) && ( $kpsewhich ne '' ) ) { - $FormatPath = `$kpsewhich --expand-var=\$TEXFORMATS` ; - chomp $FormatPath; + unless ($EngineDone) { + my $str = $ENV{"TEXFORMATS"} ; + $str =~ s/\$ENGINE//io ; + $ENV{"TEXFORMATS"} = $str ; + } + # expanded paths + print " assuming engine : $EnginePath\n"; + if (($UseEnginePath)&&($EngineDone)) { + $FormatPath = `$kpsewhich --engine=$EnginePath --show-path=fmt` ; + } else { + $FormatPath = `$kpsewhich --show-path=fmt` ; + } + chomp $FormatPath ; + if ( ( $FormatPath ne '' ) && $Verbose ) { + print "located formatpath (1) : $FormatPath\n"; + } + # fall back if ($FormatPath eq '') { - $FormatPath = `$kpsewhich --show-path=fmt`; - chomp $FormatPath; + if (($UseEnginePath)&&($EngineDone)) { + if ($dosish) { + $FormatPath = `$kpsewhich --engine=$EnginePath --expand-var=\$TEXFORMATS` ; + } else { + $FormatPath = `$kpsewhich --engine=$EnginePath --expand-var=\\\$TEXFORMATS` ; + } + } else { + if ($dosish) { + $FormatPath = `$kpsewhich --expand-var=\$TEXFORMATS` ; + } else { + $FormatPath = `$kpsewhich --expand-var=\\\$TEXFORMATS` ; + } + } + } + chomp $FormatPath ; + if ( ( $FormatPath ne '' ) && $Verbose ) { + print "located formatpath (2) : $FormatPath\n"; } - $FormatPath =~ s/\.+\;//o; # should be a sub - $FormatPath =~ s/\;.*//o; - $FormatPath =~ s/\!//go; + # + if ( ( $FormatPath ne '' ) && ($FormatPath =~ /unsetengine/) ) { + $FormatPath =~ s/unsetengine/$EnginePath/; + if ( ( $FormatPath ne '' ) && $Verbose ) { + print "located formatpath (!) : $FormatPath (unbugged)\n"; + } + } + # take first one + if ($dosish) { + $FormatPath =~ s/\;.*//o; + } else { + $FormatPath =~ s/\:.*//o; + } + # remove clever things + $FormatPath =~ s/[\!\{\}\,]//go; $FormatPath =~ s/\\/\//go; $FormatPath =~ s/\/\//\//go; $FormatPath =~ s/[\/\\]$//; if ( ( $FormatPath ne '' ) && $Verbose ) { - print " located formatpath : $FormatPath\n"; + print "located formatpath (3) : $FormatPath\n"; } $FormatPath .= '/'; } - if ($UseEnginePath && ($FormatPath ne '' && ($FormatPath !~ /$EnginePath\/$/))) { + if ($UseEnginePath && $EngineDone && ($FormatPath ne '') && ($FormatPath !~ /$EnginePath\/$/)) { $FormatPath .= $EnginePath ; unless (-d $FormatPath) { mkdir $FormatPath ; } $FormatPath .= '/' ; } - + print " using formatpath : $FormatPath\n" if $Verbose ; return $FormatPath; } @@ -2300,7 +2381,7 @@ sub RunOneFormat { $TeXPrefix = "*"; } my $CurrentPath = cwd(); - my $TheTeXFormatPath = LocatedFormatPath($TeXFormatPath, $TeXExecutable); + my $TheTeXFormatPath = LocatedFormatPath($TeXFormatPath, $TeXExecutable,1); if ( $TheTeXFormatPath ne '' ) { chdir $TheTeXFormatPath } MakeUserFile; MakeResponseFile; @@ -2314,6 +2395,12 @@ sub RunOneFormat { RestoreUserFile; if ( ( $TheTeXFormatPath ne '' ) && ( $CurrentPath ne '' ) ) { + print "\n"; + if ($UseEnginePath) { + print " used engineformatpath : $TheTeXFormatPath\n"; + } else { + print " used formatpath : $TheTeXFormatPath\n"; + } chdir $CurrentPath; } } @@ -2355,31 +2442,110 @@ sub RunFormats { } sub RunMpFormat { + # engine is not supported by MP my $MpFormat = shift; return if ( $MpFormat eq '' ); my $CurrentPath = cwd(); - my $TheMpFormatPath = LocatedFormatPath($MpFormatPath, $MpExecutable); + my $TheMpFormatPath = LocatedFormatPath($MpFormatPath,$MpExecutable,$MpEngineSupport); if ( $TheMpFormatPath ne '' ) { chdir $TheMpFormatPath } $own_quote = ($MpExecutable =~ m/^[^\"].* / ? "\"" : "") ; my $cmd = "$own_quote$MpExecutable$own_quote $MpVirginFlag $MpPassString $MpFormat"; + +unless ( $dosish && !$escapeshell ) { + $cmd =~ s/[^\\]\&/\\\&/io ; +} + if ($Verbose) { print "\n$cmd\n\n" } system($cmd ) ; if ( ( $TheMpFormatPath ne '' ) && ( $CurrentPath ne '' ) ) { + print "\n"; + #~ if ($UseEnginePath) { + #~ print " used engineformatpath : $TheMpFormatPath\n"; + #~ } else { + print " used formatpath : $TheMpFormatPath\n"; + #~ } chdir $CurrentPath; } } + +my $dir = File::Temp::tempdir(CLEANUP=>1) ; +my ($fh, $filename) = File::Temp::tempfile(DIR=>$dir, UNLINK=>1); + +sub checktexformatpath { + # engine support is either broken of not implemented in some + # distributions, so we need to take care of it ourselves + my $texformats ; + if (defined($ENV{'TEXFORMATS'})) { + $texformats = $ENV{'TEXFORMATS'} ; + } else{ + $texformats = '' ; + } + if ($texformats eq '') { + if ($dosish) { + $texformats = `kpsewhich --expand-var=\$TEXFORMATS`.chomp ; + } else { + $texformats = `kpsewhich --expand-var=\\\$TEXFORMATS`.chomp ; + } + } + if ($texformats !~ /web2c[\/\\].*\$ENGINE/) { + $texformats =~ s/web2c/web2c\/{\$ENGINE,}/ ; + $ENV{'TEXFORMATS'} = $texformats ; + print " fixing texformat path : $ENV{'TEXFORMATS'}\n"; + } + if (! defined($ENV{'ENGINE'})) { + if ($MpEngineSupport) { + $ENV{'ENGINE'} .= $MpExecutable ; + } ; + $ENV{'ENGINE'} = $TeXExecutable ; + } +} + sub RunFiles { my $currentpath = cwd() ; + my $oldrunpath = $RunPath ; + # new + checktexformatpath ; # test if current path is writable if (! -w "$currentpath") { print " current path readonly : $currentpath\n"; - if ($ENV{"TEMP"} && -e $ENV{"TEMP"}) { - $RunPath = $ENV{"TEMP"} ; - } elsif ($ENV{"TMP"} && -e $ENV{"TMP"}) { - $RunPath = $ENV{"TMP"} ; + # + # we cannot use the following because then the result will + # also be removed and users will not know where to look + # + # $RunPath = File::Temp::tempdir(CLEANUP=>1) ; + # if ($RunPath) { + # print " using temp path : $RunPath\n"; + # } else { + # print " problematic temp path : $currentpath\n"; + # exit ; + # } + # + foreach my $d ($ENV{"TMPDIR"},$ENV{"TEMP"},$ENV{"TMP"},"/tmp") { + if ($d && -e $d) { $RunPath = $d ; last ; } + } + if ($TempDir eq '') { + print " provide temp path for : $RunPath\n"; + exit ; + } elsif ($RunPath ne $oldrunpath) { + chdir ($RunPath) ; + unless (-e $TempDir) { + print " creating texexec path : $TempDir\n"; + mkdir ("$TempDir", 077) + } + if (-e $TempDir) { + $RunPath += $TempDir ; + } else { + # we abort this run because on unix an invalid tmp + # path can be an indication of a infected system + print " problematic temp path : $RunPath\n"; + exit ; + } + } else { + print " no writable temp path : $RunPath\n"; + exit ; } } # test if we need to change paths @@ -2640,6 +2806,7 @@ sub doRunMP { ########### } # prevent nameclash, experimental my $MpMpName = "$MpName"; + print "$cmd $MpMpName" if ($Verbose) ; $Problems = system("$cmd $MpMpName"); open( MPL, "$MpName.log" ); while (<MPL>) # can be one big line unix under win @@ -2732,45 +2899,6 @@ sub load_set_file { if ( $SetFile ne "" ) { load_set_file( $SetFile, $Verbose ) } -# todo : more consistent argv handling -# -# sub ifargs -# { $problems = (@ARGV==0) ; -# if ($problems) -# { print " warning : nothing to do\n" } -# return $problems } - -# sub check_texmf_root -# { return if ($TeXRoot eq "") ; -# my $root = $TeXRoot ; -# $root =~ s/\\/\//goi ; -# if (-d $root) -# { print " using tex root : $root \n" ; -# $ENV{TEXROOT} = $root ; -# $ENV{TEXMFCNF} = "$root/texmf-local/web2c" ; -# $ENV{TEXMFFONTS} = "$root/texmf-fonts" ; -# $ENV{TEXMFLOCAL} = "$root/texmf-local" ; -# $ENV{TEXMFMAIN} = "$root/texmf" } -# else -# { print " invalid tex root : $root \n" } } -# -# sub check_texmf_tree -# { return if ($TeXTree eq "") ; -# my $tree = $TeXTree ; -# unless (-d $tree) -# { $tree = $ENV{TEXMFLOCAL} ; -# $tree =~ s/texmf.*//io ; -# $tree .= $TeXTree } -# if (-d $tree) -# { print " using texmf tree : $tree \n" ; -# $ENV{TEXMFPROJECT} = $tree ; -# if ((-f "$tree/web2c/cont-en.efmt")|| -# (-f "$tree/web2c/cont-nl.efmt")) -# { $ENV{TEXFORMATS} = "$tree/web2c" } -# $ENV{TEXMF} = '{$TEXMFPROJECT,$TEXMFFONTS,$TEXMFLOCAL,!!$TEXMFMAIN}' } -# else -# { print " invalid texmf tree : $tree \n" } } - sub check_texmf_root { } sub check_texmf_tree { } @@ -2834,6 +2962,7 @@ if ($HelpAsked) { show_help_info } elsif ($Version) { show_version_info + #~ system("texmfstart ctxtools --check $OriginalArgs") ; } elsif ($TypesetListing) { check_texmf_root; check_texmf_tree; @@ -2859,23 +2988,12 @@ if ($HelpAsked) { else { RunFormats ; } + #~ system("texmfstart ctxtools $OriginalArgs") ; } elsif (@ARGV) { check_texmf_root; check_texmf_tree; @ARGV = <@ARGV>; RunFiles; -#~ } else { - #~ if ($Modules ne "") { # kind of fall back: texexec --use=set-02 --pdf - #~ my @tmp = split(',', $Modules) ; - #~ @ARGV[0] = @tmp[0] ; - #~ } - #~ if (@ARGV) { - #~ check_texmf_root; - #~ check_texmf_tree; - #~ RunFiles; - #~ } elsif ( !$HelpAsked ) { - #~ show_help_options; -#~ } } } elsif ( !$HelpAsked ) { show_help_options; } diff --git a/scripts/context/perl/texexec.rme b/scripts/context/perl/texexec.rme index 419d1faec..f38b4be7f 100644 --- a/scripts/context/perl/texexec.rme +++ b/scripts/context/perl/texexec.rme @@ -51,7 +51,7 @@ set TeXShell to tetex % % Here are some general defaults. They can be overruled later. -set UseEnginePath to false +set UseEnginePath to true set UsedInterfaces to en nl metafun mptopdf set UserInterface to en diff --git a/scripts/context/perl/texfont.pl b/scripts/context/perl/texfont.pl index 71433cb56..732fb0f3e 100644 --- a/scripts/context/perl/texfont.pl +++ b/scripts/context/perl/texfont.pl @@ -144,7 +144,7 @@ my $remove = 0 ; my $expert = 0 ; my $trace = 0 ; my $afmpl = 0 ; -my $trees = 'TEXMFFONTS,TEXMFLOCAL,TEXMFEXTRA,TEXMFMAIN' ; +my $trees = 'TEXMFFONTS,TEXMFLOCAL,TEXMFEXTRA,TEXMFMAIN,TEXMFDIST' ; my $pattern = '' ; my $fontsuffix = "" ; @@ -649,12 +649,13 @@ sub UnLink sub globafmfiles { my ($runpath, $pattern) = @_ ; my @files = validglob("$runpath/$pattern.afm") ; + report("locating afm files : using pattern $runpath/$pattern.afm"); if ($preproc && !$lcdf) { @files = validglob("$runpath/$pattern.*tf") ; - report("locating otf files : using pattern $pattern"); + report("locating otf files : using pattern $runpath/$pattern.*tf"); unless (@files) { @files = validglob("$sourcepath/$pattern.ttf") ; - report("locating ttf files : using pattern $pattern") } + report("locating ttf files : using pattern $sourcepath/$pattern.ttf") } } if (@files) # also elsewhere { report("locating afm files : using pattern $pattern") } @@ -758,13 +759,9 @@ unless ($tex) { report "warning : can't open $texfile" } if ($map) { print MAP "% This file is generated by the TeXFont Perl script.\n" ; print MAP "%\n" ; - print MAP "% You need to add the following line to pdftex.cfg:\n" ; + print MAP "% You need to add the following line to your file:\n" ; print MAP "%\n" ; - print MAP "% map +$mapfile\n" ; - print MAP "%\n" ; - print MAP "% Alternatively in your TeX source you can say:\n" ; - print MAP "%\n" ; - print MAP "% \\pdf \{+$mapfile\}\n" ; + print MAP "% \\pdfmapfile{+$mapfile}\n" ; print MAP "%\n" ; print MAP "% In ConTeXt you can best use:\n" ; print MAP "%\n" ; diff --git a/scripts/context/perl/texutil.pl b/scripts/context/perl/texutil.pl index 025fe8946..d5e6ef9ea 100644 --- a/scripts/context/perl/texutil.pl +++ b/scripts/context/perl/texutil.pl @@ -134,11 +134,38 @@ my $dosish = ($Config{'osname'} =~ /^(ms)?dos|^os\/2|^(ms|cyg)win/i) ; "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" ; @@ -166,8 +193,6 @@ sub CloseTerminal #D subroutine below is therefore only needed when no file or #D pattern is given. -$InputFile = "@ARGV" ; # niet waterdicht - sub CompFileName { my ($a,$b) = @_ ; my ($fa,$sa) = split(/\./,$a) ; @@ -1360,6 +1385,7 @@ sub FlushSavedLine print TUO "\\registerto$SavedTo" } else { print TUO "\\registerpage$SavedFrom" } } + $SavedHow = "" ; $SavedFrom = "" ; $SavedTo = "" ; $SavedEntry = "" } @@ -1383,6 +1409,7 @@ sub FlushRegisters $SavedFrom = "" ; $SavedTo = "" ; $SavedEntry = "" ; + $SavedHow = "" ; for ($n=1 ; $n<=$NOfEntries ; ++$n) { ($Class, $LCKey, $Key, $Entry, $TextHow, $RegisterState, @@ -1393,7 +1420,6 @@ sub FlushRegisters # if ($SortN) { $AlfKey = $Key ; -# $AlfKey =~ s/(.).*\x00(.).*/$1$2/o ; $AlfKey =~ s/(.).*\x00(.).*/$2/o ; if (defined($ALF{$AlfKey})) { $TestAlfa = $ALF{$AlfKey} } } @@ -1445,11 +1471,16 @@ sub FlushRegisters print TUO "\\registersee{$Class}{$PageHow,$TextHow}{$SeeToo}{$Page}\n" ; $LastPage = $Page ; $LastRealPage = $RealPage } - elsif (($Copied) || - ! (($LastPage eq $Page) and ($LastRealPage eq $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}{$PageHow,$TextHow}{$Location}{$Page}{$RealPage}\n" ; + $SavedLine = "{$Class}{$SavedHow,$TextHow}{$Location}{$Page}{$RealPage}\n" ; if ($RegisterState eq $RegStat{"f"}) { FlushSavedLine ; print TUO "\\registerfrom$SavedLine" } @@ -1468,7 +1499,7 @@ sub FlushRegisters } ++$NOfSanePages ; $LastPage = $Page ; - $LastRealPage = $RealPage } } + $LastRealPage = $RealPage } } } FlushSavedLine ; @@ -2205,10 +2236,10 @@ sub HandlePdfFigure { if (($MediaBoxFound < 2) && ($SomeLine =~ /\/ArtBox\s*\[/io)) { $MediaBoxFound = 3 ; $MediaBox = $SomeLine } - elsif (($MediaBoxFound < 2) && ($SomeLine =~ /\/CropBox\s*\[ /io)) + elsif (($MediaBoxFound < 2) && ($SomeLine =~ /\/CropBox\s*\[/io)) { $MediaBoxFound = 2 ; $MediaBox = $SomeLine } - elsif (($MediaBoxFound == 0) && ($SomeLine =~ /\/MediaBox\s*\[ /io)) + elsif (($MediaBoxFound == 0) && ($SomeLine =~ /\/MediaBox\s*\[/io)) { $MediaBoxFound = 1 ; $MediaBox = $SomeLine } } } close ( PDF ) ; diff --git a/scripts/context/ruby/base/file.rb b/scripts/context/ruby/base/file.rb new file mode 100644 index 000000000..b7170d555 --- /dev/null +++ b/scripts/context/ruby/base/file.rb @@ -0,0 +1,133 @@ +require 'ftools' + +class File + + def File.suffixed(name,sufa,sufb=nil) + if sufb then + unsuffixed(name) + "-#{sufa}.#{sufb}" + else + unsuffixed(name) + ".#{sufa}" + end + end + + def File.unsuffixed(name) + name.sub(/\.[^\.]*?$/o, '') + end + + def File.suffix(name,default='') + if name =~ /\.([^\.]*?)$/o then + $1 + else + default + end + end + + def File.splitname(name,suffix='') + if name =~ /(.*)\.([^\.]*?)$/o then + [$1, $2] + else + [name, suffix] + end + end + +end + +class File + + def File.silentopen(name,method='r') + begin + f = File.open(name,method) + rescue + return nil + else + return f + end + end + + def File.silentread(name) + begin + data = IO.read(name) + rescue + return nil + else + return data + end + end + + def File.atleast?(name,n=0) + begin + size = FileTest.size(name) + rescue + return false + else + return size > n + end + end + + def File.appended(name,str='') + if FileTest.file?(name) then + begin + if f = File.open(name,'a') then + f << str + f.close + return true + end + rescue + end + end + return false + end + + def File.written(name,str='') + begin + if f = File.open(name,'w') then + f << str + f.close + return true + end + rescue + end + return false + end + + def File.silentdelete(filename) + begin File.delete(filename) ; rescue ; end + end + + def File.silentcopy(oldname,newname) + return if File.expand_path(oldname) == File.expand_path(newname) + begin File.copy(oldname,newname) ; rescue ; end + end + + def File.silentrename(oldname,newname) + # in case of troubles, we just copy the file; we + # maybe working over multiple file systems or + # apps may have mildly locked files (like gs does) + return if File.expand_path(oldname) == File.expand_path(newname) + begin File.delete(newname) ; rescue ; end + begin + File.rename(oldname,newname) + rescue + begin File.copy(oldname,newname) ; rescue ; end + end + end + +end + +class File + + # handles "c:\tmp\test.tex" as well as "/${TEMP}/test.tex") + + def File.unixfied(filename) + begin + str = filename.gsub(/\$\{*([a-z0-9\_]+)\}*/oi) do + if ENV.key?($1) then ENV[$1] else $1 end + end + str.gsub(/[\/\\]+/o, '/') + rescue + filename + end + end + +end + diff --git a/scripts/context/ruby/base/kpse.rb b/scripts/context/ruby/base/kpse.rb new file mode 100644 index 000000000..6dbd6e6cf --- /dev/null +++ b/scripts/context/ruby/base/kpse.rb @@ -0,0 +1,270 @@ +# module : base/kpse +# copyright : PRAGMA Advanced Document Engineering +# version : 2002-2005 +# author : Hans Hagen +# +# project : ConTeXt / eXaMpLe +# concept : Hans Hagen +# info : j.hagen@xs4all.nl +# www : www.pragma-ade.com + +# rename this one to environment + +module Kpse + + @@located = Hash.new + @@paths = Hash.new + @@scripts = Hash.new + @@formats = ['tex','texmfscripts','other text files'] + @@progname = 'context' + @@ownpath = $0.sub(/[\\\/][a-z0-9\-]*?\.rb/i,'') + @@problems = false + @@tracing = false + @@distribution = 'web2c' + @@crossover = true + @@mswindows = Config::CONFIG['host_os'] =~ /mswin/ + + # check first in bin path + + ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| + @@distribution = 'miktex' if path =~ /miktex/o + end + + # if @@crossover then + # ENV.keys.each do |k| + # case k + # when /\_CTX\_KPSE\_V\_(.*?)\_/io then @@located[$1] = ENV[k].dup + # when /\_CTX\_KPSE\_P\_(.*?)\_/io then @@paths [$1] = ENV[k].dup.split(';') + # when /\_CTX\_KPSE\_S\_(.*?)\_/io then @@scripts[$1] = ENV[k].dup + # end + # end + # end + + if @@crossover then + ENV.keys.each do |k| + case k + when /\_CTX\_KPSE\_V\_(.*?)\_/io then @@located[$1] = ENV[k].dup + when /\_CTX\_KPSE\_P\_(.*?)\_/io then @@paths [$1] = ENV[k].dup.split(';') + when /\_CTX\_KPSE\_S\_(.*?)\_/io then @@scripts[$1] = ENV[k].dup + end + end + end + + def Kpse.inspect + @@located.keys.sort.each do |k| puts("located : #{k} -> #{@@located[k]}\n") end + @@paths .keys.sort.each do |k| puts("paths : #{k} -> #{@@paths [k]}\n") end + @@scripts.keys.sort.each do |k| puts("scripts : #{k} -> #{@@scripts[k]}\n") end + end + + def Kpse.distribution + @@distribution + end + + def Kpse.found(filename, progname=nil, format=nil) + begin + tag = Kpse.key(filename) # all + if @@located.key?(tag) then + return @@located[tag] + elsif FileTest.file?(filename) then + setvariable(tag,filename) + return filename + elsif FileTest.file?(File.join(@@ownpath,filename)) then + setvariable(tag,File.join(@@ownpath,filename)) + return @@located[tag] + else + [progname,@@progname].flatten.compact.uniq.each do |prg| + [format,@@formats].flatten.compact.uniq.each do |fmt| + begin + tag = Kpse.key(filename,prg,fmt) + if @@located.key?(tag) then + return @@located[tag] + elsif p = Kpse.kpsewhich(filename,prg,fmt) then + setvariable(tag,p.chomp) + return @@located[tag] + end + rescue + end + end + end + setvariable(tag,filename) + return filename + end + rescue + filename + end + end + + def Kpse.kpsewhich(filename,progname,format) + Kpse.run("-progname=#{progname} -format=\"#{format}\" #{filename}") + end + + def Kpse.which + Kpse.Kpsewhich + end + + def Kpse.run(arguments) + puts arguments if @@tracing + begin + if @@problems then + results = '' + else + results = `kpsewhich #{arguments}`.chomp + end + rescue + puts "unable to run kpsewhich" if @@tracing + @@problems, results = true, '' + end + puts results if @@tracing + return results + end + + def Kpse.formatpaths + unless @@paths.key?('formatpaths') then + begin + setpath('formatpaths',run("--show-path=fmt").gsub(/\\/,'/').split(File::PATH_SEPARATOR)) + rescue + setpath('formatpaths',[]) + end + end + return @@paths['formatpaths'] + end + + def Kpse.key(filename='',progname='all',format='all') + [progname,format,filename].join('-') + end + + def Kpse.formatpath(engine='pdfetex',enginepath=true) + + unless @@paths.key?(engine) then + # overcome a bug/error in web2c/distributions/kpse + if ENV['TEXFORMATS'] then + ENV['TEXFORMATS'] = ENV['TEXFORMATS'].sub(/\$ENGINE/io,'') + end + # use modern method + if enginepath then + formatpath = run("--engine=#{engine} --show-path=fmt") + else + formatpath = run("--show-path=fmt") + end + # use ancient method + if formatpath.empty? then + if enginepath then + if @@mswindows then + formatpath = run("--engine=#{engine} --expand-var=\$TEXFORMATS") + else + formatpath = run("--engine=#{engine} --expand-var=\\\$TEXFORMATS") + end + else + if enginepath then + formatpath = run("--expand-var=\$TEXFORMATS") + else + formatpath = run("--expand-var=\\\$TEXFORMATS") + end + end + end + # overcome a bug/error in web2c/distributions/kpse + formatpath.sub!(/unsetengine/, engine) + # take first one + if ! formatpath.empty? then + formatpath = formatpath.split(File::PATH_SEPARATOR).first + # remove clever things + formatpath.gsub!(/[\!\{\}\,]/, '') + unless formatpath.empty? then + if enginepath then + newformatpath = File.join(formatpath,engine).gsub(/[\/\\]+/, '/') + if FileTest.directory?(newformatpath) then + formatpath = newformatpath + else + begin + File.makedirs(newformatpath) + rescue + else + formatpath = newformatpath if FileTest.directory?(newformatpath) + end + end + else + formatpath = formatpath.gsub(/[\/\\]+/, '/').gsub(/\/$/, '') + end + end + end + setpath(engine,formatpath) + end + return @@paths[engine] + end + + def Kpse.update + case @@distribution + when 'miktex' then + system('initexmf --update-fndb') + else + # always mktexlsr anyway + + end + system('mktexlsr') + end + + def Kpse.distribution + ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| + if path =~ /miktex/ then + return 'miktex' + end + end + return 'web2c' + end + + def Kpse.miktex? + distribution == 'miktex' + end + + def Kpse.web2c? + distribution == 'web2c' + end + + # engine support is either broken of not implemented in some + # distributions, so we need to take care of it ourselves + + def Kpse.fixtexmfvars(engine=nil) + ENV['ENGINE'] = engine if engine + texformats = if ENV['TEXFORMATS'] then ENV['TEXFORMATS'].dup else '' end + if @@mswindows then + texformats = `kpsewhich --expand-var=\$TEXFORMATS`.chomp if texformats.empty? + else + texformats = `kpsewhich --expand-var=\\\$TEXFORMATS`.chomp if texformats.empty? + end + if texformats !~ /web2c[\/\\].*\$ENGINE/ then + ENV['TEXFORMATS'] = texformats.gsub(/web2c/, "web2c/{\$ENGINE,}") + return true + else + return false + end + + end + + def Kpse.runscript(name,filename=[],options=[]) + setscript(name,`texmfstart --locate #{name}`) unless @@scripts.key?(name) + system("#{@@scripts[name]} #{[options].flatten.join(' ')} #{[filename].flatten.join(' ')}") + end + + def Kpse.pipescript(name,filename=[],options=[]) + setscript(name,`texmfstart --locate #{name}`) unless @@scripts.key?(name) + `#{@@scripts[name]} #{[options].flatten.join(' ')} #{[filename].flatten.join(' ')}` + end + + private + + def Kpse.setvariable(key,value) + @@located[key] = value + ENV["_CTX_K_V_#{key}_"] = @@located[key] if @@crossover + end + + def Kpse.setscript(key,value) + @@scripts[key] = value + ENV["_CTX_K_S_#{key}_"] = @@scripts[key] if @@crossover + end + + def Kpse.setpath(key,value) + @@paths[key] = [value].flatten.uniq + ENV["_CTX_K_P_#{key}_"] = @@paths[key].join(';') if @@crossover + end + +end diff --git a/scripts/context/ruby/base/logger.rb b/scripts/context/ruby/base/logger.rb new file mode 100644 index 000000000..2526cdb0e --- /dev/null +++ b/scripts/context/ruby/base/logger.rb @@ -0,0 +1,104 @@ +# module : base/logger +# copyright : PRAGMA Advanced Document Engineering +# version : 2002-2005 +# author : Hans Hagen +# +# project : ConTeXt / eXaMpLe +# concept : Hans Hagen +# info : j.hagen@xs4all.nl +# www : www.pragma-ade.com + +require 'thread' + +# The next calls are valid: + +# @log.report('a','b','c', 'd') +# @log.report('a','b',"c #{d}") +# @log.report("a b c #{d}") + +# Keep in mind that "whatever #{something}" is two times faster than +# 'whatever ' + something or ['whatever',something].join and that +# when verbosity is not needed the following is much faster too: + +# @log.report('a','b','c', 'd') if @log.verbose? +# @log.report('a','b',"c #{d}") if @log.verbose? +# @log.report("a b c #{d}") if @log.verbose? + +# The last three cases are equally fast when verbosity is turned off. + +# Under consideration: verbose per instance + +class Logger + + @@length = 0 + @@verbose = false + + def initialize(tag=nil,length=0,verbose=false) + @tag = tag || '' + @@verbose = @@verbose || verbose + @@length = @tag.length if @tag.length > @@length + @@length = length if length > @@length + end + + def report(*str) + begin + case str.length + when 0 + print("\n") + return true + when 1 + message = str.first + else + message = [str].flatten.collect{|s| s.to_s}.join(' ').chomp + end + if @tag.empty? then + print("#{message}\n") + else + # try to avoid too many adjustments + @tag = @tag.ljust(@@length) unless @tag.length == @@length + print("#{@tag} | #{message}\n") + end + rescue + end + return true + end + + def reportlines(*str) + unless @tag.empty? then + @tag = @tag.ljust(@@length) unless @tag.length == @@length + end + report([str].flatten.collect{|s| s.gsub(/\n/,"\n#{@tag} | ")}.join(' ')) + end + + def debug(*str) + report(str) if @@verbose + end + + def error(*str) + if ! $! || $!.to_s.empty? then + report(str) + else + report(str,$!) + end + end + + def verbose + @@verbose = true + end + + def silent + @@verbose = false + end + + def verbose? + @@verbose + end + + # attr_reader :tag + + # alias fatal error + # alias info debug + # alias warn debug + # alias debug? :verbose? + +end diff --git a/scripts/context/ruby/base/pdf.rb b/scripts/context/ruby/base/pdf.rb new file mode 100644 index 000000000..49d177b5d --- /dev/null +++ b/scripts/context/ruby/base/pdf.rb @@ -0,0 +1,53 @@ +module PDFview + + @files = Hash.new + + def PDFview.open(*list) + begin + [*list].flatten.each do |file| + filename = fullname(file) + if FileTest.file?(filename) then + result = `pdfopen --file #{filename} 2>&1` + @files[filename] = true + end + end + rescue + end + end + + def PDFview.close(*list) + [*list].flatten.each do |file| + filename = fullname(file) + begin + if @files.key?(filename) then + result = `pdfclose --file #{filename} 2>&1` + else + closeall + return + end + rescue + end + @files.delete(filename) + end + end + + def PDFview.closeall + begin + result = `pdfclose --all 2>&1` + rescue + end + @files.clear + end + + def PDFview.fullname(name) + name + if name =~ /\.pdf$/ then '' else '.pdf' end + end + +end + +puts ('' || false) + +# PDFview.open("t:/document/show-exa.pdf") +# PDFview.open("t:/document/show-gra.pdf") +# PDFview.close("t:/document/show-exa.pdf") +# PDFview.close("t:/document/show-gra.pdf") diff --git a/scripts/context/ruby/base/state.rb b/scripts/context/ruby/base/state.rb new file mode 100644 index 000000000..f57231592 --- /dev/null +++ b/scripts/context/ruby/base/state.rb @@ -0,0 +1,75 @@ +require "md5" + +# todo: register omissions per file + +class FileState + + def initialize + @states = Hash.new + @omiter = Hash.new + end + + def reset + @states.clear + @omiter.clear + end + + def register(filename,omit=nil) + unless @states.key?(filename) then + @states[filename] = Array.new + @omiter[filename] = omit + end + @states[filename] << checksum(filename,@omiter[filename]) + end + + def update(filename=nil) + [filename,@states.keys].flatten.compact.uniq.each do |fn| + register(fn) + end + end + + def inspect(filename=nil) + result = '' + [filename,@states.keys].flatten.compact.uniq.sort.each do |fn| + if @states.key?(fn) then + result += "#{fn}: #{@states[fn].inspect}\n" + end + end + result + end + + def changed?(filename) + if @states.key?(filename) then + n = @states[filename].length + if n>1 then + changed = @states[filename][n-1] != @states[filename][n-2] + else + changed = true + end + else + changed = true + end + return changed + end + + def checksum(filename,omit=nil) + sum = '' + begin + if FileTest.file?(filename) && (data = IO.read(filename)) then + data.gsub!(/\n.*?(#{[omit].flatten.join('|')}).*?\n/ms,"\n") if omit + sum = MD5.new(data).hexdigest.upcase + end + rescue + sum = '' + end + return sum + end + + def stable? + @states.keys.each do |s| + return false if changed?(s) + end + return true + end + +end diff --git a/scripts/context/ruby/xmpl/switch.rb b/scripts/context/ruby/base/switch.rb index de747bbd5..d011a78ae 100644 --- a/scripts/context/ruby/xmpl/switch.rb +++ b/scripts/context/ruby/base/switch.rb @@ -1,21 +1,26 @@ -# module : xmpl/switch -# copyright : PRAGMA Publishing On Demand -# version : 1.00 - 2002 +# module : base/switch +# copyright : PRAGMA Advanced Document Engineering +# version : 2002-2005 # author : Hans Hagen # -# project : eXaMpLe +# project : ConTeXt / eXaMpLe # concept : Hans Hagen # info : j.hagen@xs4all.nl -# www : www.pragma-pod.com / www.pragma-ade.com +# www : www.pragma-ade.com # we cannot use getoptlong because we want to be more -# tolerant; also we want to be case insensitive. +# tolerant; also we want to be case insensitive (2002). # we could make each option a class itself, but this is # simpler; also we can put more in the array # beware: regexps/o in methods are optimized globally +require "rbconfig" + +$mswindows = Config::CONFIG['host_os'] =~ /mswin/ +$separator = File::PATH_SEPARATOR + class String def has_suffix?(suffix) @@ -24,6 +29,48 @@ class String end +# may move to another module + +class File + + def File.needsupdate(oldname,newname) + begin + if $mswindows then + return File.stat(oldname).mtime > File.stat(newname).mtime + else + return File.stat(oldname).mtime != File.stat(newname).mtime + end + rescue + return true + end + end + + def File.syncmtimes(oldname,newname) + begin + if $mswindows then + # does not work (yet) + t = File.mtime(oldname) # i'm not sure if the time is frozen, so we do it here + File.utime(0,t,oldname,newname) + else + t = File.mtime(oldname) # i'm not sure if the time is frozen, so we do it here + File.utime(0,t,oldname,newname) + end + rescue + end + end + + def File.timestamp(name) + begin + "#{File.stat(name).mtime}" + rescue + return 'unknown' + end + end + +end + +# main thing + module CommandBase # this module can be used as a mixin in a command handler @@ -43,28 +90,43 @@ module CommandBase # only works in 1.8 # # def report(*str) - # @logger.report(str) + # @logger.report(str) # end # # def version # just a bit of playing with defs - # report(@banner.join(' - ')) - # def report(*str) - # @logger.report - # @logger.report(str) - # def report(*str) - # @logger.report(str) - # end - # end - # def version - # end + # report(@banner.join(' - ')) + # def report(*str) + # @logger.report + # @logger.report(str) + # def report(*str) + # @logger.report(str) + # end + # end + # def version + # end # end def report(*str) + initlogger ; @logger.report(str) + end + + def debug(*str) + initlogger ; @logger.debug(str) + end + + def error(*str) + initlogger ; @logger.error(str) + end + + def initlogger if @forcenewline then @logger.report @forcenewline = false end - @logger.report(str) + end + + def logger + @logger end def version # just a bit of playing with defs @@ -89,6 +151,18 @@ module CommandBase def option(key) @commandline.option(key) end + def oneof(*key) + @commandline.oneof(*key) + end + + def globfiles(pattern='*',suffix=nil) + @commandline.setarguments([pattern].flatten) + if files = findfiles(suffix) then + @commandline.setarguments(files) + else + @commandline.setarguments + end + end private @@ -190,7 +264,11 @@ class CommandLine end - def register (option,shortcut,kind,default=false,action=false,helptext='') + def setarguments(args=[]) + @arguments = if args then args else [] end + end + + def register(option,shortcut,kind,default=false,action=false,helptext='') if kind == FLAG then @options[option] = default elsif not default then @@ -316,8 +394,45 @@ class CommandLine end end - def option(str) - @options[str] # @options.fetch(str,'') + def option(str,default=nil) + if @options.key?(str) then + @options[str] + elsif default then + default + else + @options[str] + end + end + + def checkedoption(str,default='') + if @options.key?(str) then + if @options[str].empty? then default else @options[str] end + else + default + end + end + + def foundoption(str,default='') + str = str.split(',') if str.class == String + str.each do |s| + return str if @options.key?(str) + end + return default + end + + def oneof(*key) + [*key].flatten.compact.each do |k| + return true if @options.key?(k) && @options[k] + end + return false + end + + def setoption(str,value) + @options[str] = value + end + + def getoption(str,value='') # value ? + @options[str] end def argument(n=0) @@ -336,7 +451,7 @@ class CommandLine end end - # a few local methods, cannot be defined nested (yet) + # a few local methods, cannot be defined nested (yet) private @@ -387,11 +502,6 @@ class CommandLine end if foundkey then @provided[foundkey] = true - # if value.class == FalseClass then - # @options[foundkey] = true - # else - # @options[foundkey] = if foundkind == VALUE then cleanvalue(value) else true end - # end if foundkind == VALUE then @options[foundkey] = cleanvalue(value) else diff --git a/scripts/context/ruby/base/system.rb b/scripts/context/ruby/base/system.rb new file mode 100644 index 000000000..ed8c2756e --- /dev/null +++ b/scripts/context/ruby/base/system.rb @@ -0,0 +1,102 @@ +# module : base/system +# copyright : PRAGMA Advanced Document Engineering +# version : 2002-2005 +# author : Hans Hagen +# +# project : ConTeXt / eXaMpLe +# concept : Hans Hagen +# info : j.hagen@xs4all.nl +# www : www.pragma-ade.com + +require "rbconfig" + +module System + + @@mswindows = Config::CONFIG['host_os'] =~ /mswin/ + @@binpaths = ENV['PATH'].split(File::PATH_SEPARATOR) + @@binsuffixes = if $mswindows then ['.exe','.com','.bat'] else ['','.sh','.csh'] end + @@located = Hash.new + @@binnames = Hash.new + + if @@mswindows then + @@binnames['ghostscript'] = ['gswin32c.exe','gs.cmd','gs.bat'] + @@binnames['imagemagick'] = ['imagemagick.exe','convert.exe'] + @@binnames['inkscape'] = ['inkscape.exe'] + else + @@binnames['ghostscript'] = ['gs'] + @@binnames['imagemagick'] = ['convert'] + @@binnames['inkscape'] = ['inkscape'] + end + + + def System.null + if @@mswindows then 'nul' else '/dev/null/' end + end + + def System.binnames(str) + if @@binnames.key?(str) then + @@binnames[str] + else + [str] + end + end + + def System.locatedprogram(program) + if @@located.key?(program) then + return @@located[program] + else + System.binnames(program).each do |binname| + if binname =~ /\..*$/io then + @@binpaths.each do |path| + if FileTest.file?(str = File.join(path,binname)) then + return @@located[program] = str + end + end + end + binname.gsub!(/\..*$/io, '') + @@binpaths.each do |path| + @@binsuffixes.each do |suffix| + if FileTest.file?(str = File.join(path,"#{binname}#{suffix}")) then + return @@located[program] = str + end + end + end + end + end + return @@located[program] = "texmfstart #{program}" + end + + def System.command(program,arguments='') + if program =~ /^(.*?) (.*)$/ then + program = System.locatedprogram($1) + ' ' + $2 + else + program = System.locatedprogram(program) + end + program = program + ' ' + arguments if ! arguments.empty? + program.gsub!(/\s+/io, ' ') + program.gsub!(/(\.\/)+/io, '') + program.gsub!(/\\/io, '/') + return program + end + + def System.run(program,arguments='',pipe=false,collect=false) + if pipe then + if collect then + `#{System.command(program,arguments)} 2>&1` + else + `#{System.command(program,arguments)}` + end + else + system(System.command(program,arguments)) + end + end + + def System.pipe(program,arguments='',collect=false) + System.run(program,arguments,true) + end + + def System.safepath(path) + if path.match(/ /o) then "\"#{path}\"" else path end + end + +end diff --git a/scripts/context/ruby/base/tex.rb b/scripts/context/ruby/base/tex.rb new file mode 100644 index 000000000..e9f66ea8d --- /dev/null +++ b/scripts/context/ruby/base/tex.rb @@ -0,0 +1,1281 @@ +# module : base/tex +# copyright : PRAGMA Advanced Document Engineering +# version : 2005 +# author : Hans Hagen +# +# project : ConTeXt / eXaMpLe +# concept : Hans Hagen +# info : j.hagen@xs4all.nl +# www : www.pragma-ade.com + +# todo: write systemcall for mpost to file so that it can be run +# faster + +require 'base/variables' +require 'base/kpse' +require 'base/system' +require 'base/state' +require 'base/pdf' +require 'base/file' + +class TEX + + # The make-part of this class was made on a rainy day while listening + # to "10.000 clowns on a rainy day" by Jan Akkerman. Unfortunately the + # make method is not as swinging as this live cd. + + include Variables + + @@texengines = Hash.new + @@mpsengines = Hash.new + @@backends = Hash.new + @@runoptions = Hash.new + @@texformats = Hash.new + @@mpsformats = Hash.new + @@prognames = Hash.new + + ['tex','pdftex','pdfetex','standard'] .each do |e| @@texengines[e] = 'pdfetex' end + ['aleph','omega'] .each do |e| @@texengines[e] = 'aleph' end + ['xetex'] .each do |e| @@texengines[e] = 'xetex' end + + ['metapost','mpost','standard'] .each do |e| @@mpsengines[e] = 'mpost' end + + ['pdfetex','pdftex','pdf','pdftex','standard'] .each do |b| @@backends[b] = 'pdftex' end + ['dvipdfmx','dvipdfm','dpx','dpm'] .each do |b| @@backends[b] = 'dvipdfmx' end + ['xetex','xtx'] .each do |b| @@backends[b] = 'xetex' end + ['dvips','ps'] .each do |b| @@backends[b] = 'dvips' end + ['dvipsone'] .each do |b| @@backends[b] = 'dvipsone' end + ['acrobat','adobe','distiller'] .each do |b| @@backends[b] = 'acrobat' end + + # todo norwegian (no) + + ['plain'] .each do |f| @@texformats[f] = 'plain' end + ['cont-en','en','english','context','standard'].each do |f| @@texformats[f] = 'cont-en' end + ['cont-nl','nl','dutch'] .each do |f| @@texformats[f] = 'cont-nl' end + ['cont-de','de','german'] .each do |f| @@texformats[f] = 'cont-de' end + ['cont-it','it','italian'] .each do |f| @@texformats[f] = 'cont-it' end + ['cont-cz','cz','czech'] .each do |f| @@texformats[f] = 'cont-cz' end + ['cont-ro','ro','romanian'] .each do |f| @@texformats[f] = 'cont-ro' end + ['cont-uk','uk','brittish'] .each do |f| @@texformats[f] = 'cont-uk' end + ['mptopdf'] .each do |f| @@texformats[f] = 'mptopdf' end + + ['plain','mpost'] .each do |f| @@mpsformats[f] = 'plain' end + ['metafun','context','standard'] .each do |f| @@mpsformats[f] = 'metafun' end + + ['pdfetex','aleph','omega'] .each do |p| @@prognames[p] = 'context' end + ['mpost'] .each do |p| @@prognames[p] = 'metafun' end + + @@runoptions['xetex'] = ['--no-pdf'] + + @@booleanvars = [ + 'batchmode', 'nonstopmode', 'fastmode', 'fastdisabled', 'silentmode', 'final', + 'paranoid', 'notparanoid', 'nobanner', 'once', 'allpatterrns', + 'nompmode', 'nomprun', 'automprun', + 'nomapfiles', + 'arrange', 'noarrange', + 'forcexml', 'foxet', + 'mpyforce', 'forcempy', + 'forcetexutil', 'texutil', + 'globalfile', 'autopath', + 'purge', 'pdfopen', 'simplerun', + ] + @@stringvars = [ + 'modefile', 'result', 'suffix', 'response', 'path', + 'filters', 'usemodules', 'environments', 'separation', 'setuppath', + 'arguments', 'input', 'output', 'randomseed', 'modes', 'filename', + 'modefile', + ] + @@standardvars = [ + 'mainlanguage', 'bodyfont', 'language' + ] + @@knownvars = [ + 'engine', 'distribution', 'texformats', 'mpsformats', 'progname', 'interface', + 'runs', 'backend' + ] + + @@extrabooleanvars = [] + @@extrastringvars = [] + + def booleanvars + [@@booleanvars,@@extrabooleanvars].flatten + end + def stringvars + [@@stringvars,@@extrastringvars].flatten + end + def standardvars + @@standardvars + end + def knownvars + @@knownvars + end + + def setextrastringvars(vars) + @@extrastringvars << vars + end + def setextrabooleanvars(vars) + @@extrabooleanvars << vars + end + + @@temprunfile = 'texexec' + @@temptexfile = 'texexec.tex' + + def initialize(logger) + @logger = logger + @cleanups = Array.new + @variables = Hash.new + @startuptime = Time.now + # options + booleanvars.each do |k| + setvariable(k,false) + end + stringvars.each do |k| + setvariable(k,'') + end + standardvars.each do |k| + setvariable(k,'standard') + end + setvariable('distribution', Kpse.distribution) + setvariable('texformats', defaulttexformats) + setvariable('mpsformats', defaultmpsformats) + setvariable('progname', 'context') + setvariable('interface', 'standard') + setvariable('engine', 'standard') + setvariable('backend', 'pdftex') + setvariable('runs', '8') + setvariable('randomseed', rand(1440)) + # files + setvariable('files', []) + end + + def runtime + Time.now - @startuptime + end + + def reportruntime + report("runtime: #{runtime}") + end + + def inspect(name=nil) + if ! name || name.empty? then + name = [booleanvars,stringvars,standardvars,knownvars] + end + [name].flatten.each do |n| + if str = getvariable(n) then + unless (str.class == String) && str.empty? then + report("option '#{n}' is set to '#{str}'") + end + end + end + end + + def tempfilename(suffix='') + @@temprunfile + if suffix.empty? then '' else ".#{suffix}" end + end + + def cleanup + @cleanups.each do |name| + begin + File.delete(name) if FileTest.file?(name) + rescue + report("unable to delete #{name}") + end + end + end + + def cleanuptemprunfiles + begin + Dir.glob("#{@@temprunfile}*").each do |name| + if File.file?(name) && (File.splitname(name)[1] !~ /(pdf|dvi)/o) then + begin File.delete(name) ; rescue ; end + end + end + rescue + end + end + + def texengines + @@texengines.keys.sort + end + + def mpsengines + @@mpsengines.keys.sort + end + + def backends + @@backends.keys.sort + end + + def texformats + @@texformats.keys.sort + end + + def mpsformats + @@mpsformats.keys.sort + end + + def defaulttexformats + ['en','nl','mptopdf'] + end + + def defaultmpsformats + ['metafun'] + end + + def runoptions(engine) + if @@runoptions.key?(engine) then @@runoptions[engine].join(' ') else '' end + end + + # private + + def cleanuplater(name) + begin + @cleanups.push(File.expand_path(name)) + rescue + @cleanups.push(name) + end + end + + def openedfile(name) + cleanuplater(name) if f = File.open(name, 'w') + return f + end + + def prefixed(format,engine) + case engine + when /etex|eetex|pdfetex|pdfeetex|pdfxtex|xpdfetex|eomega|aleph|xetex/io then + "*#{format}" + else + format + end + end + + def quoted(str) + if str =~ /^[^\"].* / then "\"#{str}\"" else str end + end + + def getarrayvariable(str='') + str = getvariable(str) + if str.class == String then str.split(',') else str.flatten end + end + + def validtexformat(str) + validsomething(str,@@texformats) + end + def validmpsformat(str) + validsomething(str,@@mpsformats) + end + def validtexengine(str) + validsomething(str,@@texengines) + end + def validmpsengine(str) + validsomething(str,@@mpsengines) + end + def validsomething(str,something) + if str then + list = [str].flatten.collect do |s| + something[s] + end .compact.uniq + if list.length>0 then + if str.class == String then list.first else list end + else + false + end + else + false + end + end + + def validbackend(str) + if str && @@backends.key?(str) then + @@backends[str] + else + @@backends['standard'] + end + end + + def validprogname(str,engine='standard') + if str && @@prognames.key?(str) then + @@prognames[str] + elsif (engine != 'standard') && @@prognames.key?(engine) then + @@prognames[engine] + else + str + end + end + + # we no longer support the & syntax + + def formatflag(engine=nil,format=nil) + case getvariable('distribution') + when 'standard' then prefix = "--fmt" + when /web2c/io then prefix = web2cformatflag(engine) + when /miktex/io then prefix = "--undump" + else return "" + end + if format then + if engine then + "#{prefix}=#{engine}/#{format}" + else + "#{prefix}=#{format}" + end + else + prefix + end + end + + def web2cformatflag(engine=nil) + # funny that we've standardized on the fmt suffix (at the cost of + # upward compatibility problems) but stuck to the bas/mem/fmt flags + if engine then + case validmpsengine(engine) + when /mpost/ then "--mem" + when /mfont/ then "--bas" + else "--fmt" + end + else + "--fmt" + end + end + + def prognameflag(progname=nil) + case getvariable('distribution') + when 'standard' then prefix = "--progname" + when /web2c/io then prefix = "--progname" + when /miktex/io then prefix = "--alias" + else return "" + end + if progname then + if progname = validprogname(progname) then + "#{prefix}=#{progname}" + else + "" + end + else + prefix + end + end + + def iniflag + "--ini" + end + def tcxflag + "--translate-file=natural.tcx" + end + + def filestate(file) + File.mtime(file).strftime("%d/%m/%Y %H:%M:%S") + end + + # will go to context/process context/listing etc + + def contextversion # ook elders gebruiken + filename = Kpse.found('context.tex') + version = 'unknown' + begin + if FileTest.file?(filename) && IO.read(filename).match(/\\contextversion\{(\d+\.\d+\.\d+)\}/) then + version = $1 + end + rescue + end + return version + end + + def makeformats + # goody + if getvariable('texformats') == 'standard' then + setvariable('texformats',[getvariable('interface')]) unless getvariable('interface').empty? + end + # prepare + texformats = validtexformat(getarrayvariable('texformats')) + mpsformats = validmpsformat(getarrayvariable('mpsformats')) + texengine = validtexengine(getvariable('texengine')) + mpsengine = validmpsengine(getvariable('mpsengine')) + # save current path + savedpath = Dir.getwd + # generate tex formats + if texformats && texengine && (progname = validprogname(getvariable('progname'),texengine)) then + report("using tex engine #{texengine}") + texformatpath = Kpse.formatpath(texengine,true) + # can be empty, to do + report("using tex format path #{texformatpath}") + begin + Dir.chdir(texformatpath) + rescue + end + if texformats.length > 0 then + makeuserfile + makeresponsefile + end + texformats.each do |format| + if texformat = validtexformat(format) then + report("generating tex format #{texformat}") + # report("some texmf environment variables are fixed") if Kpse.fixtexmfvars(texengine) + command = [quoted(texengine),prognameflag(progname),iniflag,tcxflag,prefixed(texformat,texengine)].join(' ') + report(command) if getvariable('verbose') + system(command) + end + end + else + texformatpath = '' + end + # generate mps formats + if mpsformats && mpsengine && (progname = validprogname(getvariable('progname'),mpsengine)) then + report("using mp engine #{mpsengine}") + mpsformatpath = Kpse.formatpath(mpsengine,false) + report("using mps format path #{mpsformatpath}") + begin + Dir.chdir(mpsformatpath) + rescue + end + mpsformats.each do |format| + if mpsformat = validmpsformat(format) then + report("generating mps format #{mpsformat}") + # report("some texmf environment variables are fixed") if Kpse.fixtexmfvars(mpsengine) + command = [quoted(mpsengine),prognameflag(progname),iniflag,tcxflag,mpsformat].join(' ') + report(command) if getvariable('verbose') + system(command) + end + end + else + mpsformatpath = '' + end + # check for problems + report("tex engine path: #{texformatpath}") unless texformatpath.empty? + report("mps engine path: #{mpsformatpath}") unless mpsformatpath.empty? + [['fmt','tex'],['mem','mps']].each do |f| + [[texformatpath,'global'],[mpsformatpath,'global'],[savedpath,'current']].each do |p| + begin + Dir.chdir(p[0]) + rescue + else + Dir.glob("*.#{f[0]}").each do |file| + report("#{f[1]}format: #{filestate(file)} > #{File.expand_path(file)}") + end + end + end + end + # to be sure, go back to current path + begin + Dir.chdir(savedpath) + rescue + end + # finalize + cleanup + reportruntime + end + + def checkcontext + + # todo : report texmf.cnf en problems + + # basics + report("current distribution: #{Kpse.distribution}") + report("context source date: #{contextversion}") + formatpaths = Kpse.formatpaths + globpattern = "**/{#{formatpaths.join(',')}}/*/*.{fmt,efmt,ofmt,xfmt,mem}" + report("format path: #{formatpaths.join(' ')}") + # utilities + report + ['texexec','texutil','ctxtools'].each do |program| + result = `texmfstart #{program} --help` + result.sub!(/.*?(#{program}[^\n]+)\n.*/mi) do $1 end + report("#{result}") + end + # formats + cleanuptemprunfiles + if formats = Dir.glob(globpattern) then + formats.sort.each do |name| + cleanuptemprunfiles + if f = open(tempfilename('tex'),'w') then + # kind of aleph-run-out-of-par safe + f << "\\starttext\n" + f << " \\relax test \\relax\n" + f << "\\stoptext\n" + f << "\\endinput\n" + f.close + if FileTest.file?(tempfilename('tex')) then + format = File.basename(name) + engine = if name =~ /(pdfetex|aleph|xetex)[\/\\]#{format}/ then $1 else '' end + if engine.empty? then + engineflag = "" + else + engineflag = "--engine=#{$1}" + end + case format + when /cont\-([a-z]+)/ then + interface = $1.sub(/cont\-/,'') + report + report("testing interface #{interface}") + flags = ['--process','--batch','--once',"--interface=#{interface}",engineflag] +# to be adapted ! +result = Kpse.pipescript('newtexexec',tempfilename,flags) +# to just texexec + if FileTest.file?("#{@@temprunfile}.log") then + logdata = IO.read("#{@@temprunfile}.log") + if logdata =~ /^\s*This is (.*?)[\s\,]+(.*?)$/mois then + if validtexengine($1.downcase) then + report("#{$1} #{$2.gsub(/\(format.*$/,'')}".strip) + end + end + if logdata =~ /^\s*(ConTeXt)\s+(.*int:\s+[a-z]+.*?)\s*$/mois then + report("#{$1} #{$2}".gsub(/\s+/,' ').strip) + end + else + report("format #{format} does not work") + end + when /metafun/ then + # todo + when /mptopdf/ then + # todo + end + else + report("error in creating #{tempfilename('tex')}") + end + end + cleanuptemprunfiles + end + end + cleanuptemprunfiles + + end + + private + + def makeuserfile + language = getvariable('language') + mainlanguage = getvariable('mainlanguage') + bodyfont = getvariable('bodyfont') + if f = openedfile("cont-fmt.tex") then + f << "\\unprotect" + case language + when 'all' then + f << "\\preloadallpatterns\n" + when '' then + f << "% no language presets\n" + when 'standard' + f << "% using defaults\n" + else + languages = language.split(',') + languages.each do |l| + f << "\\installlanguage[\\s!#{l}][\\c!state=\\v!start]\n" + end + mainlanguage = languages.first + end + unless mainlanguage == 'standard' then + f << "\\setupcurrentlanguage[\\s!#{mainlanguage}]\n"; + end + unless bodyfont == 'standard' then + # ~ will become obsolete when lmr is used + f << "\\definetypescriptsynonym[cmr][#{bodyfont}]" + # ~ is already obsolete for some years now + f << "\\definefilesynonym[font-cmr][font-#{bodyfont}]\n" + end + f << "\\protect\n" + f << "\\endinput\n" + f.close + end + end + + def makeresponsefile + interface = getvariable('interface') + if f = openedfile("mult-def.tex") then + case interface + when 'standard' then + f << "% using default response interface" + else + f << "\\def\\currentresponses\{#{interface}\}\n" + end + f << "\\endinput\n" + f.close + end + end + + private # will become baee/context + + @@preamblekeys = [ + ['tex','texengine'],['program','texengine'], + ['ctx','ctxfilter'],['translate','ctxfilter'], + ['output','backend'],['modes','modes'],['version','contextversion'], + ['format','texformat'],['interface','texformat'] + ] + + def scantexpreamble(filename) + if tex = File.open(filename) then + while str = tex.gets.chomp do + if str =~ /^\%\s*(.*)/o then + vars = Hash.new + $1.split(/\s+/o).each do |s| + k, v = s.split('=') + vars[k] = v + end + @@preamblekeys.each do |v| + setvariable(v[1],vars[v[0]]) if vars.key?(v[0]) + end + else + break + end + end + tex.close + end + end + + def scantexcontent(filename) + if tex = File.open(filename) then + while str = tex.gets.chomp do + case str + when /^\%/o then + # next + when /\\(starttekst|stoptekst|startonderdeel|startdocument|startoverzicht)/o then + setvariable('texformat','nl') ; break + when /\\(stelle|verwende|umgebung|benutze)/o then + setvariable('texformat','de') ; break + when /\\(stel|gebruik|omgeving)/o then + setvariable('texformat','nl') ; break + when /\\(use|setup|environment)/o then + setvariable('texformat','en') ; break + when /\\(usa|imposta|ambiente)/o then + setvariable('texformat','it') ; break + when /(height|width|style)=/o then + setvariable('texformat','en') ; break + when /(hoehe|breite|schrift)=/o then + setvariable('texformat','de') ; break + when /(hoogte|breedte|letter)=/o then + setvariable('texformat','nl') ; break + when /(altezza|ampiezza|stile)=/o then + setvariable('texformat','it') ; break + when /externfiguur/o then + setvariable('texformat','nl') ; break + when /externalfigure/o then + setvariable('texformat','en') ; break + when /externeabbildung/o then + setvariable('texformat','de') ; break + when /figuraesterna/o then + setvariable('texformat','it') ; break + end + end + tex.close + end + + end + + private # will become base/context + + def pushresult(filename,resultname) + fname = File.unsuffixed(filename) + rname = File.unsuffixed(resultname) + if ! rname.empty? && (rname != fname) then + report("outputfile #{result}") + ['tuo','log','dvi','pdf'].each do |s| + File.silentrename(File.suffixed(fname,s),File.suffixed('texexec',s)) + end + ['tuo'].each do |s| + File.silentrename(File.suffixed(rname,s),File.suffixed(fname,s)) if FileTest(suffixed(rname,s)) + end + end + end + + def popresult(filename,resultname) + fname = File.unsuffixed(filename) + rname = File.unsuffixed(resultname) + if ! rname.empty? && (rname != fname) then + report("renaming #{fname} to #{rname}") + ['tuo','log','dvi','pdf'].each do |s| + File.silentrename(File.suffixed(fname,s),File.suffixed(rname,s)) + end + report("restoring #{fname}") + unless $fname == 'texexec' then + ['tuo','log','dvi','pdf'].each do |s| + File.silentrename(File.suffixed('texexec',s),File.suffixed(fname,s)) + end + end + end + end + + def makestubfile(jobname,jobsuffix,forcexml=false) + if tmp = File.open(File.suffixed(jobname,'run'),'w') then + fullname = File.suffixed(jobname,jobsuffix) + tmp << "\\starttext\n" + if forcexml then + if FileTest.file?(fullname) && (xml = File.open(fullname)) then + xml.each do |line| + if line =~ /<[a-z]+/io then + break + elsif line =~ /<\?context\-directive\s+(.+?)\s+(.+?)\s+(.+?)\s*\?>/o then + category, key, value = $1, $2, $3 + if category == 'job' then + if key == 'stylefile' then + tmp << "\\environment $value\n" + elsif key == 'module' then + tmp << "\\usemodule[$value]\n" + elsif key == 'interface' then + contextinterface = value + end + end + end + end + xml.close + end + tmp << "\\processXMLfilegrouped{#{fullname}}\n" + else + tmp << "\\processfile{#{fullname}}\n" + end + tmp << "\\stoptext\n" + tmp.close + jobsuffix = "run" + end + return jobsuffix + end + +end + +class TEX + + def processtex # much to do: mp, xml, runs etc + setvariable('texformats',[getvariable('interface')]) unless getvariable('interface').empty? + getarrayvariable('files').each do |filename| + setvariable('filename',filename) + report("processing document '#{filename}'") + processcontextfile + end + reportruntime + end + + def processmptex + getarrayvariable('files').each do |filename| + setvariable('filename',filename) + report("processing graphic '#{filename}'") + runtexmp(filename) + end + reportruntime + end + + def processmpxtex + getarrayvariable('files').each do |filename| + setvariable('filename',filename) + report("processing text of graphic '#{filename}'") + processmpx(filename,true) + end + reportruntime + end + + def makeoptionfile(jobname, jobsuffix, finalrun, fastdisabled, kindofrun) + if opt = File.open(File.suffixed(jobname,'top'),'w') then + # local handies + opt << "\% $JobName.top\n" + opt << "\\unprotect\n" + opt << "\\setupsystem[\\c!n=#{kindofrun}]\n" + opt << "\\def\\MPOSTformatswitch\{#{prognameflag('metafun')} #{formatflag('mpost')}=\}" + if getvariable('batchmode') then + opt << "\\batchmode\n" + end + if getvariable('nonstopmode') then + opt << "\\nonstopmode\n" + end + if getvariable('paranoid') then + opt << "\\def\\maxreadlevel{1}\n" + end + if (str = File.unixfied(getvariable('modefile'))) && ! str.empty? then + opt << "\\readlocfile{#{str}}{}{}\n" + end + if (str = File.unixfied(getvariable('result'))) && ! str.empty? then + opt << "\\setupsystem[file=#{str}]\n" + elsif (str = getvariable('suffix')) && ! str.empty? then + opt << "\\setupsystem[file=#{File.suffixed(jobname,str,nil)}]\n" + end + if (str = File.unixfied(getvariable('path'))) && ! str.empty? then + opt << "\\usepath[#{str}]\n" unless str.empty? + end + if (str = getvariable('mainlanguage').downcase) && ! str.empty? && ! str.standard? then + opt << "\\setuplanguage[#{str}]\n" + end + if str = validbackend(getvariable('backend')) then + opt << "\\setupoutput[#{str}]\n" + end + if getvariable('color') then + opt << "\\setupcolors[\\c!state=\\v!start]\n" + end + if getvariable('nompmode') || getvariable('nomprun') || getvariable('automprun') then + opt << "\\runMPgraphicsfalse\n" + end + if getvariable('fastmode') && ! getvariable('fastdisabled') then + opt << "\\fastmode\n" + end + if getvariable('silent') then + opt << "\\silentmode\n" + end + if (str = getvariable('separation')) && ! str.empty? then + opt << "\\setupcolors[\\c!split=#{str}]\n" + end + if (str = getvariable('setuppath')) && ! str.empty? then + opt << "\\setupsystem[\\c!directory=\{#{str}\}]\n" + end + if (str = getvariable('paperformat')) && ! str.empty? && ! str.standard? then + if str =~ /^([a-z]+\d+)([a-z]+\d+)$/io then # A5A4 A4A3 A2A1 ... + opt << "\\setuppapersize[#{$1.upcase}][#{$2.upcase}]\n" + else # ...*... + pf = str.upcase.split(/[x\*]/o) + pf << pf[0] if pd.size == 1 + opt << "\\setuppapersize[#{pf[0]}][#{pf[1]}]\n" + end + end + if (str = getvariable('background')) && ! str.empty? then + opt << "\\defineoverlay[whatever][{\\externalfigure[#{str}][\\c!factor=\\v!max]}]\n" + opt << "\\setupbackgrounds[\\v!page][\\c!background=whatever]\n" + end + if getvariable('centerpage') then + opt << "\\setuplayout[\\c!location=\\v!middle,\\c!marking=\\v!on]\n" + end + if getvariable('nomapfiles') then + opt << "\\disablemapfiles\n" + end + if getvariable('noarrange') then + opt << "\\setuparranging[\\v!disable]\n" + elsif getvariable('arrange') then + arrangement = Array.new + if finalrun then + arrangement << "\\v!doublesided" unless getvariable('noduplex') + case printformat + when '' then arrangement << "\\v!normal" + when /.*up/oi then arrangement << "\\v!rotated" + when /.*down/oi then arrangement << ["2DOWN","\\v!rotated"] + when /.*side/oi then arrangement << ["2SIDE","\\v!rotated"] + end + else + arrangement << "\\v!disable" + end + opt << "\\setuparranging[#{arrangement.flatten.join(',')}]\n" if arrangement.size > 0 + end + if (str = getvariable('modes')) && ! str.empty? then + opt << "\\enablemode[#{modes}]\n" + end + if (str = getvariable('arguments')) && ! str.empty? then + opt << "\\setupenv[#{str}]\n" + end + if (str = getvariable('randomseed')) && ! str.empty? then + opt << "\\setupsystem[\\c!random=#{str}]\n" + end + if (str = getvariable('input')) && ! str.empty? then + opt << "\\setupsystem[inputfile=#{str}]\n" + else + opt << "\\setupsystem[inputfile=#{File.suffixed(jobname,jobsuffix)}]\n" + end + if (str = getvariable('pages')) && ! str.empty? then + if str.downcase == 'odd' then + opt << "\\chardef\\whichpagetoshipout=1\n" + elsif str.downcase == 'even' then + opt << "\\chardef\\whichpagetoshipout=2\n" + else + pagelist = Array.new + str.split(/\,/).each do |page| + pagerange = page.split(/(\:|\.\.)/o ) + if pagerange.size > 1 then + pagerange.first.to_i.upto(pagerange.last.to_i) do |p| + pagelist << p.to_s + end + else + pagelist << page + end + end + opt << "\\def\\pagestoshipout\{pagelist.join(',')\}\n"; + end + end + opt << "\\protect\n"; + begin + getvariable('filters').split(',').each do |f| opt << "\\useXMLfilter[#{f}]\n" end + rescue + end + begin + getvariable('usemodules').split(',').each do |m| opt << "\\usemodule[#{m}]\n" end + rescue + end + begin + getvariable('environments').split(',').each do |e| opt << "\\usemodule[#{e}]\n" end + rescue + end + opt << "\\endinput\n" + opt.close + end + end + + def takeprecautions + ENV['MPXCOMAND'] = '0' # else loop + if getvariable('paranoid') then + ENV['SHELL_ESCAPE'] = ENV['SHELL_ESCAPE'] || 'f' + ENV['OPENOUT_ANY'] = ENV['OPENOUT_ANY'] || 'p' + ENV['OPENIN_ANY'] = ENV['OPENIN_ANY'] || 'p' + else + ENV['SHELL_ESCAPE'] = ENV['SHELL_ESCAPE'] || 't' + ENV['OPENOUT_ANY'] = ENV['OPENOUT_ANY'] || 'p' + ENV['OPENIN_ANY'] = ENV['OPENIN_ANY'] || 'a' + end + if (ENV['OPENIN_ANY'] == 'p') || (ENV['OPENOUT_ANY'] == 'p') then + setvariable('paranoid', true) + end + if ENV.key?('SHELL_ESCAPE') && (ENV['SHELL_ESCAPE'] == 'f') then + setvariable('automprun',true) + end + ['TXRESOURCES','MPRESOURCES','MFRESOURCES'].each do |res| + [getvariable('runpath'),getvariable('path')].each do |pat| + unless pat.empty? then + if ENV.key?(res) then + ENV[res] = if ENV[res].empty? then pat else pat + ":" + ENV[res] end + else + ENV[res] = pat + end + end + end + end + end + + def runtex(filename) + texengine = validtexengine(getvariable('texengine')) + texformat = validtexformat(getarrayvariable('texformats').first) + progname = validprogname(getvariable('progname')) + report("tex engine: #{texengine}") + report("tex format: #{texformat}") + report("progname: #{progname}") + if texengine && texformat && progname then + command = [quoted(texengine),prognameflag(progname),formatflag(texengine,texformat),runoptions(texengine),filename].join(' ') + report(command) if getvariable('verbose') + system(command) + else + false + end + end + + def runmp(filename) + mpsengine = validmpsengine(getvariable('mpsengine')) + mpsformat = validmpsformat(getarrayvariable('mpsformats').first) + progname = validprogname(getvariable('progname')) + if mpsengine && mpsformat && progname then + command = [quoted(mpsengine),prognameflag(progname),formatflag(mpsengine,mpsformat),runoptions(mpsengine),filename].join(' ') + report(command) if getvariable('verbose') + system(command) + else + false + end + end + + def runtexmp(filename,filetype='') + mpfile = File.suffixed(filename,filetype,'mp') + if File.atleast?(mpfile,25) then + # first run needed + File.silentdelete(File.suffixed(mpfile,'mpt')) + doruntexmp(mpfile,false) + mpgraphics = checkmpgraphics(mpfile) + mplabels = checkmplabels(mpfile) + if mpgraphics || mplabels then + # second run needed + doruntexmp(mpfile,mplabels) + end + end + end + + def runtexmpjob(filename,filetype='') + mpfile = File.suffixed(filename,filetype,'mp') + if File.atleast?(mpfile,25) && (data = File.silentread(mpfile)) then + textranslation = if data =~ /^\%\s+translate.*?\=([\w\d\-]+)/io then $1 else '' end + mpjobname = if data =~ /collected graphics of job \"(.+)\"/io then $1 else '' end + if File.unsuffixed(filename) =~ /#{mpjobname}/ then # don't optimize + options = Array.new + options.push("--mptex") + options.push("--nomp") + options.push("--mpyforce") if getvariable('forcempy') || getvariable('mpyforce') + options.push("--translate=#{textranslation}") unless textranslation.empty? + options.push("--batch") if getvariable('batchmode') + options.push("--nonstop") if getvariable('nonstopmode') + return runtexexec(mpfile,options) + end + end + return false + end + + def runtexutil(filename=[], options=['--ref','--ij','--high']) + Kpse.runscript('texutil',filename,options) + end + + def runtexexec(filename=[], options=[]) + Kpse.runscript('texexec',filename,options) + end + + def processcontextfile + + takeprecautions + + jobname = getvariable('filename') + suffix = getvariable('suffix') + result = getvariable('result') + + final = getvariable('final') + + if getvariable('autopath') then + jobname = File.basename(jobname) + inppath = File.dirname(jobname) + else + inppath = '' + end + + jobname, jobsuffix = File.splitname(jobname,'tex') + + jobname = File.unixfied(jobname) + inppath = File.unixfied(inppath) + result = File.unixfied(result) + + orisuffix = jobsuffix # still needed ? + + PDFview.closeall if getvariable('pdfopen') + + forcexml = jobsuffix === /(xml|fo|fox|rlg|exa|)/io # === returns true|false, =~ returns position + dummyfile = false + + # fuzzy code snippet: (we kunnen kpse: prefix gebruiken) + + unless FileTest.file?(File.suffixed(jobname,jobsuffix)) then + inppath.split(',').each do |ip| + break if dummyfile = FileTest.file?(File.join(ip,File.suffixed(jobname,jobsuffix))) + end + end + + jobsuffix = makestubfile(jobname,jobsuffix,forcexml) if dummyfile || forcexml + + if getvariable('globalfile') || FileTest.file?(File.suffixed(jobname,jobsuffix)) then + + unless dummyfile # we don't need this for xml + scantexpreamble(File.suffixed(jobname,jobsuffix)) + scantexcontent(File.suffixed(jobname,jobsuffix)) if getvariable('texformat').standard? + end + + result = File.suffixed(jobname,suffix) unless suffix.empty? + + pushresult(jobname,result) + + if getvariable('simplerun') then + makeoptionfile(jobname,orisuffix,true,true,3) + problems = runtex(File.suffixed(jobname,jobsuffix)) + if problems then + ok = runtexutil(jobname) if getvariable('texutil') || getvariable('forcetexutil') + popresult(jobname,result) + end + File.silentrename(File.suffixed(jobname,'top'),File.suffixed(jobname,'tmp')) + else + mprundone, ok, stoprunning = false, true, false + texruns, nofruns = 0, getvariable('runs').to_i + state = FileState.new + ['tub','tuo'].each do |s| + state.register(File.suffixed(jobname,s)) + end + ['mprun','mpgraph'].each do |s| + state.register(File.suffixed(jobname,s,'mp'),'randomseed') + # state.register(File.suffixed(jobname,s,'mpo')) + end + while ! stoprunning && (texruns < nofruns) && ok do + texruns += 1 + report("TeX run #{texruns}") + if texruns == 1 then + makeoptionfile(jobname,orisuffix,false,false,1) + else + makeoptionfile(jobname,orisuffix,false,false,2) + end + ok = runtex(File.suffixed(jobname,jobsuffix)) + if ok && (nofruns > 1) then + unless getvariable('nomprun') then + mprundone = runtexmpjob(jobname, "mpgraph") + mprundone = runtexmpjob(jobname, "mprun") + end + ok = runtexutil(jobname) + state.update + stoprunning = state.stable? + end + end + ok = runtexutil(jobname) if (nofruns == 1) && getvariable('texutil') + finalrun = getvariable('arrange') && ! getvariable('noarrange') + if ! problems && finalrun && (nofruns > 1) then + makeoptionfile(jobname,orisuffix,true,finalrun,4) + report("final TeX run #{texruns}") + problems = runtex(File.suffixed(jobname,jobsuffix)) + end + File.silentcopy(File.suffixed(jobname,'top'),File.suffixed(jobname,'tmp')) + ['tup','top'].each do |s| # previous tuo file / runtime option file + File.silentdelete(File.suffixed(jobname,s)) + end + case validbackend(getvariable('driver')) + when 'dvipdfmx' then system("dvipdfmx -f dvipdfmx.map -d 4 #{File.unsuffixed(jobname)}") + when 'xetex' then system("xdv2pdf #{File.suffixed(jobname,'xdv')}") + when 'dvips' then system("dvips #{File.unsuffixed(jobname)}") + end + popresult(jobname,result) + end + + Kpse.runscript('ctxtools',jobname,'--purge') if getvariable('purge') + + begin + File.delete(File.suffixed(jobname,jobsuffix)) if dummyfile || forcexml + rescue + report("unable to delete stub file") + end + + if ! problems && getvariable('pdfopen') then + PDFview.open(if resultname.empty? then jobname else resultname end) + end + + end + + end + + # mp specific + + def doruntexmp(mpname,mergebe=true,context=true) + texfound = false + mpbetex = Hash.new + mpfile = File.suffixed(mpname,'mp') + mpcopy = File.suffixed(mpname,'copy','mp') + setvariable('mp.file',mpfile) + setvariable('mp.line','') + setvariable('mp.error','') + if mpdata = File.silentread(mpfile) then + mpdata.gsub!(/^\#.*\n/o,'') + File.silentrename(mpfile,mpcopy) + texfound = mergebe || mpdata =~ /btex .*? etex/o + if mp = File.silentopen(mpfile,'w') then + mpdata.gsub!(/(btex.*?)\;(.*?etex)/o) do "#{$1}@@@#{$2}" end + mpdata.gsub!(/(\".*?)\;(.*?\")/o) do "#{$1}@@@#{$2}" end + mpdata.gsub!(/\;/o, "\;\n") + mpdata.gsub!(/\n+/o, "\n") + mpdata.gsub!(/(btex.*?)@@@(.*?etex)/o) do "#{$1}\;#{$2}" end + mpdata.gsub!(/(\".*?)@@@(.*?\")/o) do "#{$1};#{$2}" end + if mergebe then + mpdata.gsub!(/beginfig\s*\((\d+)\)\s*\;(.*?)endfig\s*\;/o) do + n, str = $1, $2 + if str =~ /(.*?)(verbatimtex.*?etex)\s*\;(.*)/o then + "beginfig(#{n})\;\n$1$2\;\n#{mpbetex(n)}\n$3\;endfig\;\n" + else + "beginfig(#{n})\;\n#{mpbetex(n)}\n#{str}\;endfig\;\n" + end + end + end + unless mpdata =~ /beginfig\s*\(\s*0\s*\)/o then + mp << mpbetex[0] if mpbetex.key?(0) + end + mp << mpdata # ?? + mp << "\n" + mp << "end" + mp << "\n" + mp.close + end + processmpx(mpname) if texfound + if getvariable('batchmode') then + options = ' --interaction=batch' + elsif getvariable('nonstopmode') then + options = ' --interaction=nonstop' + else + options = '' + end + # todo plain|mpost|metafun + ok = runmp(mpname) + if f = File.silentopen(File.suffixed(mpfile,'log')) then + while str = f.gets do + if str =~ /^l\.(\d+)\s(.*?)\n/o then + setvariable('mp.line',$1) + setvariable('mp.error',$2) + break + end + end + f.close + end + File.silentrename(mpfile,"mptrace.tmp") + File.silentrename(mpcopy, mpfile) + end + end + + def processmpx(mpname,context=true) + mpname = File.suffixed(mpname,'mp') + if File.atleast?(mpname,10) && (data = File.silentread(mpname)) then + begin + if data =~ /(btex|etex|verbatimtex)/o then + mptex = File.suffixed(mpname,'temp','tex') + mpdvi = File.suffixed(mpname,'temp','dvi') + mplog = File.suffixed(mpname,'temp','log') + mpmpx = File.suffixed(mpname,'temp','mpx') + ok = system("mpto #{mpname} > #{mptex}") + if ok && File.appended(mptex, "\\end\n") then + if context then + ok = RunConTeXtFile(mptex) + else + ok = RunSomeTeXFile(mptex) + end + ok = ok && FileTest.file?(mpdvi) && system("dvitomp #{mpdvi} #{mpmpx}") + [mptex,mpdvi,mplog].each do |mpfil| + File.silentdelete(mpfil) + end + end + end + rescue + # error in processing mpx file + end + end + end + + def checkmpgraphics(mpname) + mpoptions = '' + if getvariable('makempy') then + mpoptions += " --makempy " + end + if getvariable('mpyforce') || getvariable('forcempy') then + mpoptions += " --force " + else + mponame = File.suffixed(mpname,'mpo') + mpyname = File.suffixed(mpname,'mpy') + return false unless File.atleast?(mponame,32) + mpochecksum = State.new.checksum(mponame) + return false if mpochecksum.empty? + # where does the checksum get into the file? + # maybe let texexec do it? + # solution: add one if not present or update when different + if f = File.open(mpyname) then + str = f.gets.chomp + f.close + if str =~ /^\%\s*mpochecksum\s*\:\s*(\d+)/o then + return false if mpochecksum == $1 + end + end + end + return Kpse.runscript('makempy',mpname) + end + + def checkmplabels(mpname) + mpname = File.suffixed(mpname,'mpt') + if File.atleast?(mpname,10) && (mp = File.open(mpname)) then + labels = Hash.new + while str = mp.gets do + if str =~ /%\s*setup\s*:\s*(.*)/o then + t = $1 + else + t = '' + end + if str =~ /%\s*figure\s*(\d+)\s*:\s*(.*)/o then + unless t.empty? then + labels[$1] += "#{t}\n" + t = '' + end + labels[$1] += "$2\n" + end + end + mp.close + return labels if labels.size>0 + end + return nil + end + +end + +class String + + def standard? + begin + self == 'standard' + rescue + false + end + end + +end diff --git a/scripts/context/ruby/base/tool.rb b/scripts/context/ruby/base/tool.rb new file mode 100644 index 000000000..c9e6a1890 --- /dev/null +++ b/scripts/context/ruby/base/tool.rb @@ -0,0 +1,305 @@ +# module : base/tool +# copyright : PRAGMA Advanced Document Engineering +# version : 2002-2005 +# author : Hans Hagen +# +# project : ConTeXt / eXaMpLe +# concept : Hans Hagen +# info : j.hagen@xs4all.nl +# www : www.pragma-ade.com + +require 'timeout' +require 'socket' +require 'rbconfig' + +module Tool + + $constructedtempdir = '' + + def Tool.constructtempdir(create,mainpath='',fallback='') + begin + mainpath += '/' unless mainpath.empty? + timeout(5) do + begin + t = Time.now + u = t.usec.to_s % [1..2] [0..3] + pth = t.strftime("#{mainpath}%Y%m%d-%H%M%S-#{u}-#{Process.pid}") + if pth == $constructedtempdir + # sleep(0.01) + retry + end + Dir.mkdir(pth) if create + $constructedtempdir = pth + return pth + rescue + # sleep(0.01) + retry + end + end + rescue TimeoutError + # ok + rescue + # ok + end + unless fallback.empty? + begin + pth = "#{mainpath}#{fallback}" + mkdir(pth) if create + $constructedtempdir = path + return pth + rescue + return '.' + end + else + return '.' + end + + end + + def Tool.findtempdir(*vars) + constructtempdir(false,*vars) + end + + def Tool.maketempdir(*vars) + constructtempdir(true,*vars) + end + + # print maketempdir + "\n" + # print maketempdir + "\n" + # print maketempdir + "\n" + # print maketempdir + "\n" + # print maketempdir + "\n" + + + def Tool.ruby_platform + case RUBY_PLATFORM + when /(mswin|bccwin|mingw|cygwin)/i then 'mswin' + when /(linux)/i then 'linux' + when /(netbsd|unix)/i then 'unix' + when /(darwin|rhapsody|nextstep)/i then 'macosx' + else 'unix' + end + end + + $defaultlineseparator = $/ # $RS in require 'English' + + def Tool.file_platform(filename) + + begin + if f = open(filename,'rb') then + str = f.read(4000) + f.close + nn = str.count("\n") + nr = str.count("\r") + if nn>nr then + return 2 + elsif nn<nr then + return 3 + else + return 1 + end + else + return 0 + end + rescue + return 0 + end + + end + + def Tool.path_separator + return File::PATH_SEPARATOR + end + + def Tool.line_separator(filename) + + case file_platform(filename) + when 1 then return $defaultlineseparator + when 2 then return "\n" + when 3 then return "\r" + else return $defaultlineseparator + end + + end + + def Tool.default_line_separator + $defaultlineseparator + end + + def Tool.simplefilename(old) + + return old unless test(?f,old) + + new = old.downcase + new.gsub!(/[^A-Za-z0-9\-\.\\\/]/o) do # funny chars + '-' + end + if old =~ /[a-zA-Z]\:/o + # seems like we have a dos/windows drive prefix, so roll back + new.sub!(/^(.)\-/) do + $1 + ':' + end + end + new.gsub!(/(.+?)\.(.+?)(\..+)$/o) do # duplicate . + $1 + '-' + $2 + $3 + end + new.gsub!(/\-+/o) do # duplicate - + '-' + end + new + + end + + if Config::CONFIG['host_os'] =~ /mswin/ then + + require 'Win32API' + + GetShortPathName = Win32API.new('kernel32', 'GetShortPathName', ['P','P','N'], 'N') + GetLongPathName = Win32API.new('kernel32', 'GetLongPathName', ['P','P','N'], 'N') + + def Tool.dowith_pathname (filename,filemethod) + filename.gsub!(/\\/o,'/') + case filename + when /\;/o then + # could be a path spec + return filename + when /\s+/o then + # danger lurking + buffer = ' ' * 260 + length = filemethod.call(filename,buffer,buffer.size) + if length>0 then + return buffer.slice(0..length-1) + else + # when the path or file does not exist, nothing is returned + # so we try to handle the path separately from the basename + basename = File.basename(filename) + pathname = File.dirname(filename) + length = filemethod.call(pathname,buffer,260) + if length>0 then + return buffer.slice(0..length-1) + '/' + basename + else + return filename + end + end + else + # no danger + return filename + end + end + + def Tool.shortpathname(filename) + dowith_pathname(filename,GetShortPathName) + end + + def Tool.longpathname(filename) + dowith_pathname(filename,GetLongPathName) + end + + else + + def Tool.shortpathname(filename) + filename + end + + def Tool.longpathname(filename) + filename + end + + end + + # print shortpathname("C:/Program Files/ABBYY FineReader 6.0/matrix.str")+ "!\n" + # print shortpathname("C:/Program Files/ABBYY FineReader 6.0/matrix.strx")+ "!\n" + + def Tool.checksuffix(old) + + return old unless test(?f,old) + + new = old + + unless new =~ /\./io # no suffix + f = open(filename,'rb') + if str = f.gets + case str + when /^\%\!PS/io + # logging.report(filename, 'analyzed as EPS') + new = new + '.eps' + when /^\%PDF/io + # logging.report(filename, 'analyzed as PDF') + new = new + '.pdf' + else + # logging.report(filename, 'fallback as TIF') + new = new + '.tif' + end + end + f.close + end + + new.sub!(/\.jpeg$/io) do + '.jpg' + end + new.sub!(/\.tiff$/io) do + '.tif' + end + new.sub!(/\.ai$/io) do + '.eps' + end + new.sub!(/\.ai(.*?)$/io) do + '-' + $1 + '.eps' + end + new + + end + + def Tool.cleanfilename(old,logging=nil) + + return old unless test(?f,old) + + new = checksuffix(simplefilename(old)) + unless new == old + begin + File.rename(old,new) + logging.report("renaming fuzzy name #{old} to #{new}") unless logging + return old + rescue + logging.report("unable to rename fuzzy name #{old} to #{new}") unless logging + end + end + return new + + end + + def Tool.preventduplicates(old,logging=nil) + + return false unless test(?f,old) + + if old =~ /\.(tif|jpg|png|tiff)$/io + suffix = $1 + new = old + newn, news = new.split('.') + if test(?e,'newn.eps') + new = newn + '-' + suffix + '.' + suffix + begin + File.rename(old,new) + logging.report("renaming duplicate #{old} to #{new}") unless logging + return true + rescue + logging.report("unable to rename duplicate #{old} to #{new}") unless logging + end + end + end + return false + + end + + def Tool.servername + host = Socket::gethostname + begin + Socket::gethostbyname(host)[0] + rescue + host + end + end + + # print file_platform(ARGV[0]) + +end diff --git a/scripts/context/ruby/base/variables.rb b/scripts/context/ruby/base/variables.rb new file mode 100644 index 000000000..0c495d22d --- /dev/null +++ b/scripts/context/ruby/base/variables.rb @@ -0,0 +1,37 @@ +# module : base/variables +# copyright : PRAGMA Advanced Document Engineering +# version : 2002-2005 +# author : Hans Hagen +# +# project : ConTeXt / eXaMpLe +# concept : Hans Hagen +# info : j.hagen@xs4all.nl +# www : www.pragma-ade.com + +# ['base/tool','tool'].each do |r| begin require r ; rescue Exception ; else break ; end ; end + +require 'base/tool' + +module Variables + + def setvariable(key,value='') + @variables[key] = value + end + + def replacevariable(key,value='') + @variables[key] = value if @variables.key?(key) + end + + def getvariable(key,default='') + if @variables.key?(key) then @variables[key] else default end + end + + def report(*str) + @logger.report(*str) + end + + def debug(*str) + @logger.debug(str) + end + +end diff --git a/scripts/context/ruby/ctxtools.rb b/scripts/context/ruby/ctxtools.rb index 9953087d8..1a87e298e 100644 --- a/scripts/context/ruby/ctxtools.rb +++ b/scripts/context/ruby/ctxtools.rb @@ -2,24 +2,37 @@ # program : ctxtools # copyright : PRAGMA Advanced Document Engineering +# version : 2004-2005 # author : Hans Hagen +# +# project : ConTeXt / eXaMpLe +# concept : Hans Hagen +# info : j.hagen@xs4all.nl +# www : www.pragma-ade.com # This script will harbor some handy manipulations on context # related files. # todo: move scite here +# +# todo: move kpse call to kpse class/module + -banner = ['CtxTools', 'version 1.2.1', '2004/2005', 'PRAGMA ADE/POD'] +banner = ['CtxTools', 'version 1.2.2', '2004/2005', 'PRAGMA ADE/POD'] unless defined? ownpath ownpath = $0.sub(/[\\\/][a-z0-9\-]*?\.rb/i,'') $: << ownpath end -require 'ftools' -require 'xmpl/switch' -require 'exa/logger' +require 'base/switch' +require 'base/logger' +require 'base/system' + require 'rexml/document' +require 'ftools' + +exit if defined?(REQUIRE2LIB) class String @@ -362,18 +375,19 @@ class Commands public - def purgefiles + def purgefiles(all=false) pattern = @commandline.arguments - purgeall = @commandline.option("all") + purgeall = @commandline.option("all") || all $dontaskprefixes.push(Dir.glob("mpx-*")) $dontaskprefixes.flatten! $dontaskprefixes.sort! if purgeall then - forsuresuffixes.push(texnonesuffixes) - texnonesuffixes = [] + $forsuresuffixes.push($texnonesuffixes) + $texnonesuffixes = [] + $forsuresuffixes.flatten! end if ! pattern || pattern.empty? then @@ -442,6 +456,10 @@ class Commands end + def purgeall + purgefiles(true) # for old times sake + end + private $removedfiles = 0 @@ -680,25 +698,29 @@ class Commands pdffile = "#{filename}.pdf" tuofile = "#{filename}.tuo" if FileTest.file?(pdffile) then - prevline, n = '', 0 - if (pdf = File.open(pdffile)) && (tuo = File.open(tuofile,'a')) then - report('filtering page object numbers') - pdf.binmode - while line = pdf.gets do - line.chomp - # typical pdftex search - if (line =~ /\/Type \/Page/o) && (prevline =~ /^(\d+)\s+0\s+obj/o) then - p = $1 - n += 1 - tuo.puts("\\objectreference{PDFP}{#{n}}{#{p}}{#{n}}\n") - else - prevline = line + begin + prevline, n = '', 0 + if (pdf = File.open(pdffile)) && (tuo = File.open(tuofile,'a')) then + report('filtering page object numbers') + pdf.binmode + while line = pdf.gets do + line.chomp + # typical pdftex search + if (line =~ /\/Type \/Page/o) && (prevline =~ /^(\d+)\s+0\s+obj/o) then + p = $1 + n += 1 + tuo.puts("\\objectreference{PDFP}{#{n}}{#{p}}{#{n}}\n") + else + prevline = line + end end end + pdf.close + tuo.close + report("number of pages : #{n}") + rescue + report("fatal error in filtering pages") end - pdf.close - tuo.close - report("number of pages : #{n}") end end @@ -836,15 +858,18 @@ class Language rmename = "lang-#{@language}.rme" logname = "lang-#{@language}.log" + desname = "lang-all.xml" + @data.gsub!(/\\[nc]\{(.+?)\}/) do $1 end @data.gsub!(/\{\}/) do '' end @data.gsub!(/\n+/mo) do "\n" end @read.gsub!(/\n+/mo) do "\n" end description = '' + commentfile = rmename.dup begin - desfile = `kpsewhich -progname=context lang-all.xml`.chomp + desfile = `kpsewhich -progname=context #{desname}`.chomp if f = File.new(desfile) then if doc = REXML::Document.new(f) then if e = REXML::XPath.first(doc.root,"/descriptions/description[@language='#{@language}']") then @@ -856,6 +881,7 @@ class Language description = '' else unless description.empty? then + commentfile = desname.dup str = "<!-- copied from lang-all.xml\n\n" str << "<?xml version='1.0' standalone='yes'?>\n\n" str << description.chomp @@ -913,7 +939,7 @@ class Language end data.gsub!(/(\s*\n\s*)+/mo, "\n") f << banner - f << comment("context pattern file, see #{rmename} for original comment") + f << comment("context pattern file, see #{commentfile} for original comment") f << comment("source of data: #{@filenames.join(' ')}") f << description f << comment("begin pattern data") @@ -937,7 +963,7 @@ class Language end data.gsub!(/(\s*\n\s*)+/mo, "\n") f << banner - f << comment("context hyphenation file, see #{rmename} for original comment") + f << comment("context hyphenation file, see #{commentfile} for original comment") f.<< comment("source of data: #{@filenames.join(' ')}") f << description f.<< comment("begin hyphenation data") @@ -1142,7 +1168,7 @@ class Commands end -logger = EXA::ExaLogger.new(banner.shift) +logger = Logger.new(banner.shift) commandline = CommandLine.new commandline.registeraction('touchcontextfile', 'update context version') @@ -1158,22 +1184,25 @@ commandline.registeraction('purgefiles', 'remove temporary files [--all] [basena commandline.registeraction('documentation', 'generate documentation file [--type=] [filename]') -commandline.registeraction('filterpages') # no help, hidden temporary feature +commandline.registeraction('filterpages') # no help, hidden temporary feature +commandline.registeraction('purgeallfiles') # no help, compatibility feature commandline.registeraction('patternfiles', 'generate pattern files [languagecode|all]') -commandline.registeraction('help') -commandline.registeraction('version') - commandline.registervalue('type','') -# commandline.registerflag('recurse') -# commandline.registerflag('force') +commandline.registerflag('recurse') +commandline.registerflag('force') commandline.registerflag('pipe') commandline.registerflag('all') commandline.registerflag('xml') commandline.registerflag('log') +# general + +commandline.registeraction('help') +commandline.registeraction('version') + commandline.expand Commands.new(commandline,logger,banner).send(commandline.action || 'help') diff --git a/scripts/context/ruby/exa/logger.rb b/scripts/context/ruby/exa/logger.rb deleted file mode 100644 index 0bbd67f24..000000000 --- a/scripts/context/ruby/exa/logger.rb +++ /dev/null @@ -1,108 +0,0 @@ -# module : exa/logger -# copyright : PRAGMA Publishing On Demand -# version : 1.01 - 2002/2003 -# author : Hans Hagen -# -# project : eXaMpLe -# concept : Hans Hagen -# info : j.hagen@xs4all.nl -# www : www.pragma-pod.com / www.pragma-ade.com - -require 'thread' - -module EXA - - # The next calls are valid: - # - # @log.report('a','b','c', 'd') - # @log.report('a','b',"c #{d}") - # @log.report("a b c #{d}") - # - # Keep in mind that "whatever #{something}" is two times faster than - # 'whatever ' + something or ['whatever',something].join and that - # when verbosity is not needed the following is much faster too: - # - # @log.report('a','b','c', 'd') if @log.verbose? - # @log.report('a','b',"c #{d}") if @log.verbose? - # @log.report("a b c #{d}") if @log.verbose? - # - # The last three cases are equally fast when verbosity is turned off. - - # Under consideration: verbose per instance - - class ExaLogger - - @@length = 0 - @@verbose = false - - def initialize(tag=nil,length=0,verbose=false) - @tag = tag || '' - @@verbose = @@verbose || verbose - @@length = @tag.length if @tag.length > @@length - @@length = length if length > @@length - end - - def report(*str) - begin - case str.length - when 0 - print("\n") - return true - when 1 - message = str.first - else - message = [str].flatten.collect{|s| s.to_s}.join(' ').chomp - end - if @tag.empty? then - print("#{message}\n") - else - # try to avoid too many adjustments - @tag = @tag.ljust(@@length) unless @tag.length == @@length - print("#{@tag} | #{message}\n") - end - rescue - end - return true - end - - def reportlines(*str) - unless @tag.empty? then - @tag = @tag.ljust(@@length) unless @tag.length == @@length - end - report([str].flatten.collect{|s| s.gsub(/\n/,"\n#{@tag} | ")}.join(' ')) - end - - def debug(*str) - report(str) if @@verbose - end - - def error(*str) - if ! $! || $!.to_s.empty? then - report(str) - else - report(str,$!) - end - end - - def verbose - @@verbose = true - end - - def silent - @@verbose = false - end - - def verbose? - @@verbose - end - - # attr_reader :tag - - # alias fatal error - # alias info debug - # alias warn debug - # alias debug? :verbose? - - end - -end diff --git a/scripts/context/ruby/graphics/gs.rb b/scripts/context/ruby/graphics/gs.rb new file mode 100644 index 000000000..e9ad2a07f --- /dev/null +++ b/scripts/context/ruby/graphics/gs.rb @@ -0,0 +1,631 @@ +# module : graphics/gs +# copyright : PRAGMA Advanced Document Engineering +# version : 2002-2005 +# author : Hans Hagen +# +# project : ConTeXt / eXaMpLe +# concept : Hans Hagen +# info : j.hagen@xs4all.nl +# www : www.pragma-ade.com + +# ['base/variables','../variables','variables'].each do |r| begin require r ; rescue Exception ; else break ; end ; end +# ['base/system', '../system', 'system' ].each do |r| begin require r ; rescue Exception ; else break ; end ; end + +require 'base/variables' +require 'base/system' + +class GhostScript + + include Variables + + @@pstopdfoptions = [ + 'AntiAliasColorImages', + 'AntiAliasGrayImages', + 'AntiAliasMonoImages', + 'ASCII85EncodePages', + 'AutoFilterColorImages', + 'AutoFilterGrayImages', + 'AutoPositionEPSFiles', + 'AutoRotatePages', + 'Binding', + 'ColorConversionStrategy', + 'ColorImageDepth', + 'ColorImageDownsampleThreshold', + 'ColorImageDownsampleType', + 'ColorImageFilter', + 'ColorImageResolution', + 'CompatibilityLevel', + 'CompressPages', + #'ConvertCMYKImagesToRGB', # buggy + #'ConvertImagesToIndexed', # buggy + 'CreateJobTicket', + 'DetectBlends', + 'DoThumbnails', + 'DownsampleColorImages', + 'DownsampleGrayImages', + 'DownsampleMonoImages', + 'EmbedAllFonts', + 'EncodeColorImages', + 'EncodeGrayImages', + 'EncodeMonoImages', + 'EndPage', + 'FirstPage', + 'GrayImageDepth', + 'GrayImageDownsampleThreshold', + 'GrayImageDownsampleType', + 'GrayImageFilter', + 'GrayImageResolution', + 'MaxSubsetPct', + 'MonoImageDepth', + 'MonoImageDownsampleThreshold', + 'MonoImageDownsampleType', + 'MonoImageFilter', + 'MonoImageResolution', + 'Optimize', + 'ParseDCSComments', + 'ParseDCSCommentsForDocInfo', + 'PreserveCopyPage', + 'PreserveEPSInfo', + 'PreserveHalftoneInfo', + 'PreserveOPIComments', + 'PreserveOverprintSettings', + 'SubsetFonts', + 'UseFlateCompression' + ] + + @@methods = Hash.new + + @@methods['raw'] = '1' + @@methods['bound'] = '2' + @@methods['bounded'] = '2' + @@methods['crop'] = '3' + @@methods['cropped'] = '3' + @@methods['down'] = '4' + @@methods['downsample'] = '4' + @@methods['downsampled'] = '4' + @@methods['simplify'] = '5' + @@methods['simplified'] = '5' + + @@tempfile = 'gstemp' + @@pstempfile = @@tempfile + '.ps' + @@pdftempfile = @@tempfile + '.pdf' + + @@bboxspec = '\s*([\-\d\.]+)' + '\s+([\-\d\.]+)'*3 + + def initialize(logger=nil) + + unless logger then + puts('gs class needs a logger') + exit + end + + @variables = Hash.new + @psoptions = Hash.new + @logger = logger + + setvariable('profile', 'gsprofile.ini') + setvariable('pipe', true) + setvariable('method', 2) + setvariable('force', false) + setvariable('colormodel', 'cmyk') + setvariable('inputfile', '') + setvariable('outputfile', '') + + @@pstopdfoptions.each do |key| + @psoptions[key] = '' + end + + reset + + end + + def reset + @llx = @lly = @ulx = @uly = 0 + @oldbbox = [@llx,@lly,@urx,@ury] + @width = @height = @xoffset = @yoffset = @offset = 0 + @rs = Tool.default_line_separator + end + + def supported?(filename) + psfile?(filename) || pdffile?(filename) + end + + def psfile?(filename) + filename =~ /\.(eps|epsf|ps|ai\d*)$/io + end + + def pdffile?(filename) + filename =~ /\.(pdf)$/io + end + + def setpsoption(key,value) + @psoptions[key] = value unless value.empty? + end + + def setdimensions (llx,lly,urx,ury) + @oldbbox = [llx,lly,urx,ury] + @llx, @lly = llx.to_f-@offset, lly.to_f-@offset + @urx, @ury = urx.to_f+@offset, ury.to_f+@offset + @width, @height = @urx - @llx, @ury - @lly + @xoffset, @yoffset = 0 - @llx, 0 - @lly + end + + def setoffset (offset=0) + @offset = offset.to_f + setdimensions(@llx,@lly,@urx,@ury) if dimensions? + end + + def resetdimensions + setdimensions(0,0,0,0) + end + + def dimensions? + (@width>0) && (@height>0) + end + + def convert + + inpfile = getvariable('inputfile') + + if inpfile.empty? then + report('no inputfile specified') + return false + end + + unless FileTest.file?(inpfile) then + report("unknown input file #{inpfile}") + return false + end + + outfile = getvariable('outputfile') + + if outfile.empty? then + outfile = inpfile + outfile = outfile.sub(/^.*[\\\/]/,'') + end + + outfile = outfile.sub(/\.(pdf|eps|ps|ai)/i, "") + resultfile = outfile + '.pdf' + setvariable('outputfile', resultfile) + + # flags + + saveprofile(getvariable('profile')) + + begin + gsmethod = method(getvariable('method')).to_i + report("conversion method #{gsmethod}") + rescue + gsmethod = 1 + report("fallback conversion method #{gsmethod}") + end + + debug('piping data') if getvariable('pipe') + + ok = false + begin + case gsmethod + when 0, 1 then ok = convertasis(inpfile,resultfile) + when 2 then ok = convertbounded(inpfile,resultfile) + when 3 then ok = convertcropped(inpfile,resultfile) + when 4 then ok = downsample(inpfile,resultfile,'screen') + when 5 then ok = downsample(inpfile,resultfile,'prepress') + else report("invalid conversion method #{gsmethod}") + end + rescue + report('job aborted due to some error') + begin + File.delete(resultfile) if test(?e,resultfile) + rescue + report("unable to delete faulty #{resultfile}") + end + ok = false + ensure + deleteprofile(getvariable('profile')) + File.delete(@@pstempfile) if test(?e,@@pstempfile) + File.delete(@@pdftempfile) if test(?e,@@pdftempfile) + end + return ok + end + + # private + + def method (str) + if @@methods.key?(str) then + @@methods[str] + else + str + end + end + + def pdfmethod? (str) + case method(str).to_i + when 4, 5 then return true + end + return false + end + + def pdfprefix (str) + case method(str).to_i + when 4 then return 'lowres-' + when 5 then return 'normal-' + end + return '' + end + + def psmethod? (str) + ! pdfmethod?(str) + end + + def insertprofile (flags) + for key in flags.keys do + replacevariable("flag.#{key}", flags[key]) + end + end + + def deleteprofile (filename) + begin + File.delete(filename) if FileTest.file?(filename) + rescue + end + end + + def saveprofile (filename) + return if filename.empty? || ! (ini = open(filename,"w")) + @@pstopdfoptions.each do |k| + str = @psoptions[k] + # beware, booleans are translated, but so are yes/no which is dangerous + if str.class == String then + if ! str.empty? && (str != 'empty') then + str.sub!(/(.+)\-/io, '') + str = "/" + str unless str =~ /^(true|false|none|[\d\.\-\+]+)$/ + ini.puts("-d#{k}=#{str}\n") + end + end + end + ini.close + debug("gs profile #{filename} saved") + end + + def gsstream # private + if getvariable('pipe') then '-' else @@pstempfile end + end + + def gscolorswitch + case getvariable('colormodel') + when 'cmyk' then '-dProcessColorModel=/DeviceCMYK ' + when 'rgb' then '-dProcessColorModel=/DeviceRGB ' + when 'gray' then '-dProcessColorModel=/DeviceGRAY ' + else + '' + end + end + + def gsdefaults + defaults = '' + begin + defaults << '-dAutoRotatePages=/None ' if @psoptions['AutoRotatePages'].empty? + rescue + defaults << '-dAutoRotatePages=/None ' + end + return defaults + end + + def convertasis (inpfile, outfile) + + report("converting #{inpfile} as-is") + + @rs = Tool.line_separator(inpfile) + debug("platform mac") if @rs == "\r" + + arguments = '' + arguments << "\@gsprofile.ini " + arguments << "-q -sDEVICE=pdfwrite -dNOPAUSE -dNOCACHE -dBATCH " +arguments << "#{gsdefaults} " + arguments << "#{gscolorswitch} " + arguments << "-sOutputFile=#{outfile} #{inpfile} -c quit " + + debug("ghostscript: #{arguments}") + unless ok = System.run('ghostscript',arguments) then + begin + report("removing file #{outfile}") + File.delete(outfile) if FileTest.file?(outfile) + rescue + debug("file #{outfile} may be invalid") + end + end + return ok + + end + + def convertbounded (inpfile, outfile) + + report("converting #{inpfile} bounded") + + begin + return false if FileTest.file?(outfile) && (! File.delete(outfile)) + rescue + return false + end + + arguments = '' + arguments << "\@gsprofile.ini " + arguments << "-q -sDEVICE=pdfwrite -dNOPAUSE -dNOCACHE -dBATCH -dSAFER" + arguments << "#{gscolorswitch} " +arguments << "#{gsdefaults} " + arguments << "-sOutputFile=#{outfile} #{gsstream} -c quit " + + debug("ghostscript: #{arguments}") + debug('opening input file') + + @rs = Tool.line_separator(inpfile) + debug("platform #{mac}") if @rs == "\r" + + return false unless tmp = open(inpfile, 'rb') + + debug('opening pipe/file') + + if getvariable('pipe') then + + return false unless eps = IO.popen(System.command('ghostscript',arguments),'wb') + debug('piping data') + unless pipebounded(tmp,eps) then + debug('something went wrong in the pipe') + File.delete(outfile) if test(?e,outfile) + end + debug('closing pipe') + eps.close_write + + else + + return false unless eps = File.open(@@pstempfile, 'wb') + + debug('copying data') + + if pipebounded(tmp,eps) then + eps.close + debug('processing temp file') + begin + ok = System.run('ghostscript',arguments) + rescue + ok = false + # debug("fatal error: #{$!}") + ensure + end + else + eps.close + ok = false + end + + unless ok then + begin + report('no output file due to error') + File.delete(outfile) if test(?e,outfile) + rescue + debug('file',outfile,'may be invalid') + end + end + + debug('deleting temp file') + begin + File.delete(@@pstempfile) if test(?e,@@pstempfile) + rescue + end + + end + + tmp.close + return FileTest.file?(outfile) + + end + + # hm, strange, no execute here, todo ! ! ! + + def getdimensions (inpfile) + + # -dEPSFitPage and -dEPSCrop behave weird (don't work) + + arguments = "-sDEVICE=bbox -dSAFER -dNOPAUSE -dBATCH #{inpfile}" + + debug("ghostscript: #{arguments}") + + begin + bbox = System.run('ghostscript',arguments,true,true) + rescue + bbox = '' + end + + resetdimensions + + debug('bbox spec', bbox) + + if bbox =~ /(Exact|HiRes)BoundingBox:#{@@bboxspec}/mois then + debug("high res bbox #{$2} #{$3} #{$4} #{$5}") + setdimensions($2,$3,$4,$5) + elsif bbox =~ /BoundingBox:#{@@bboxspec}/mois + debug("low res bbox #{$1} #{$2} #{$3} #{$4}") + setdimensions($1,$2,$3,$4) + end + + return dimensions? + + end + + def convertcropped (inpfile, outfile) + + report("converting #{inpfile} cropped") + + convertbounded(inpfile, @@pdftempfile) + + return unless test(?e,@@pdftempfile) + + arguments = " --offset=#{@offset} #{@@pdftempfile} #{outfile}" + + unless ok = System.run('cropcrap',arguments) then + report('cropping failed') + begin + File.delete(outfile) + rescue + end + begin + File.move(@@pdftempfile,outfile) + rescue + File.copy(@@pdftempfile,outfile) + File.delete(@@pdftempfile) + end + end + + return ok + + end + + def pipebounded (eps, out) + + epsbbox, skip, buffer = false, false, '' + + debug('stripping preamble crap') + + while str = eps.gets(rs=@rs) do + if str =~ /%!PS/mois + str = str.sub(/(.*)%!PS/mois, "%!PS") + out.puts(str) + break + elsif str =~ /%PDF\-\d+\.\d+/mois + debug("looks like a pdf file, so let\'s quit") + return false + end + end + + debug('locating boundingbox') + + # why no BeginData check + + while str = eps.gets(rs=@rs) + case str + when /^%%Page:/io then + break + when /^%%(Crop|HiResBounding|ExactBounding)Box:#{@@bboxspec}/mois then + debug('high res boundingbox found') + setdimensions($2,$3,$4,$5) + break + when /^%%BoundingBox:#{@@bboxspec}/mois then + debug('low res boundingbox found') + setdimensions($1,$2,$3,$4) + end + end + + eps.rewind + + while str = eps.gets(rs=@rs) do + if skip then + skip = false if str =~ /^%+(EndData|EndPhotoshop|BeginProlog).*$/o + out.puts(str) if $1 == "BeginProlog" + elsif str =~ /^%(BeginPhotoshop)\:\s*\d+.*$/o then + skip = true + elsif str =~ /^%%/mos then + if ! epsbbox && str =~ /^%%(Page:|EndProlog)/io then + out.puts(str) if $1 == "EndProlog" + debug('faking papersize') + out.puts("<< /PageSize [#{@width} #{@height}] >> setpagedevice\n") + out.puts("gsave #{@xoffset} #{@yoffset} translate\n") + epsbbox = true + elsif str =~ /^%%BeginBinary\:\s*\d+\s*$/o then + debug('copying binary data') + out.puts(str) + while str = eps.gets(rs=@rs) + if str =~ /^%%EndBinary\s*$/o then + out.puts(str) + else + out.write(str) + end + end + elsif str =~ /^%AI9\_PrivateDataBegin/o then + debug('ignore private ai crap') + break + elsif str =~ /^%%EOF/o then + debug('ignore post eof crap') + break + # elsif str =~ /^%%PageTrailer/o then + # debug('ignoring post page trailer crap') + # break + elsif str =~ /^%%Trailer/o then + debug('ignoring post trailer crap') + break + elsif str =~ /^%%Creator.*Illustrator.*$/io then + debug('getting rid of problematic creator spec') + str = "% Creator: Adobe Illustrator ..." + out.puts(str) + elsif str =~ /^%%AI.*(PaperRect|Margin)/io then + debug('removing AI paper crap') + elsif str =~ /^%%AI.*Version.*$/io then + debug('removing dangerous version info') + elsif str =~ /^(%+AI.*Thumbnail.*)$/o then + debug('skipping AI thumbnail') + skip = true + else + out.puts(str) + end + else + out.puts(str) + end + end + + debug('done, sending EOF') + + out.puts "grestore\n%%EOF\n" + + # ok = $? == 0 + # report('process aborted, broken pipe, fatal error') unless ok + # return ok + + return true + + end + + def downsample (inpfile, outfile, method='screen') + + # gs <= 8.50 + + report("downsampling #{inpfile}") + + doit = true + unless getvariable('force') then + begin + if f = File.open(inpfile) then + f.binmode + while doit && (data = f.gets) do + if data =~ /\/ArtBox\s*\[\s*[\d\.]+\s+[\d\.]+\s+[\d\.]+\s+[\d\.]+\s*\]/io then + doit = false + end + end + f.close + end + rescue + end + end + + if doit then + arguments = '' + arguments << "-dPDFSETTINGS=/#{method} -dEmbedAllFonts=true " + arguments << "#{gscolorswitch} " +arguments << "#{gsdefaults} " + arguments << "-q -sDEVICE=pdfwrite -dNOPAUSE -dNOCACHE -dBATCH -dSAFER " + arguments << "-sOutputFile=#{outfile} #{inpfile} -c quit " + unless ok = System.run('ghostscript',arguments) then + begin + File.delete(outfile) if FileTest.file?(outfile) + report("removing file #{outfile}") + rescue + debug("file #{outfile} may be invalid") + end + end + return ok + else + report("crop problem, straight copying #{inpfile}") + File.copy(inpfile,outfile) + return false + end + + end + +end diff --git a/scripts/context/ruby/graphics/inkscape.rb b/scripts/context/ruby/graphics/inkscape.rb new file mode 100644 index 000000000..4495c3070 --- /dev/null +++ b/scripts/context/ruby/graphics/inkscape.rb @@ -0,0 +1,103 @@ +# module : graphics/inkscape +# copyright : PRAGMA Advanced Document Engineering +# version : 2002-2005 +# author : Hans Hagen +# +# project : ConTeXt / eXaMpLe +# concept : Hans Hagen +# info : j.hagen@xs4all.nl +# www : www.pragma-ade.com + +# ['base/variables','variables'].each do |r| begin require r ; rescue Exception ; else break ; end ; end +# ['graphics/gs','gs'].each do |r| begin require r ; rescue Exception ; else break ; end ; end + +require 'base/variables' +require 'base/system' +require 'graphics/gs' + +class InkScape + + include Variables + + def initialize(logger=nil) + + unless logger then + puts('inkscape class needs a logger') + exit + end + + @variables = Hash.new + @logger = logger + + reset + + end + + def reset + # nothing yet + end + + def supported?(filename) + filename =~ /.*\.(svg|svgz)/io + end + + def convert(logfile=System.null) + + inpfilename = getvariable('inputfile').dup + outfilename = getvariable('outputfile').dup + outfilename = inpfilename.dup if outfilename.empty? + outfilename.gsub!(/(\.[^\.]*?)$/, ".pdf") + tmpfilename = outfilename.gsub(/(\.[^\.]*?)$/, ".ps") + + if inpfilename.empty? || outfilename.empty? then + report("no filenames given") + return false + end + if inpfilename == outfilename then + report("filenames must differ (#{inpfilename} #{outfilename})") + return false + end + unless FileTest.file?(inpfilename) then + report("unknown file #{inpfilename}") + return false + end + + report("converting #{inpfilename} to #{tmpfilename}") + + # we need to redirect the error info else we get a pop up console + + resultpipe = "--without-gui --print=\">#{tmpfilename}\" 2>#{logfile}" + + arguments = [resultpipe,inpfilename].join(' ').gsub(/\s+/,' ') + + ok = true + begin + debug("inkscape: #{arguments}") + # should work + # ok = System.run('inkscape',arguments) # does not work here + # but 0.40 only works with this: + ok = system("inkscape #{arguments}") + # and 0.41 fails with everything + rescue + report("aborted due to error") + return false + else + return false unless ok + end + + ghostscript = GhostScript.new(@logger) + + ghostscript.setvariable('inputfile',tmpfilename) + ghostscript.setvariable('outputfile',outfilename) + + report("converting #{tmpfilename} to #{outfilename}") + + ghostscript.convert + + begin + File.delete(tmpfilename) + rescue + end + end + +end diff --git a/scripts/context/ruby/graphics/magick.rb b/scripts/context/ruby/graphics/magick.rb new file mode 100644 index 000000000..f59087bdf --- /dev/null +++ b/scripts/context/ruby/graphics/magick.rb @@ -0,0 +1,161 @@ +# module : graphics/inkscape +# copyright : PRAGMA Advanced Document Engineering +# version : 2002-2005 +# author : Hans Hagen +# +# project : ConTeXt / eXaMpLe +# concept : Hans Hagen +# info : j.hagen@xs4all.nl +# www : www.pragma-ade.com + +# ['base/variables','variables'].each do |r| begin require r ; rescue Exception ; else break ; end ; end + +require 'base/variables' + +class ImageMagick + + include Variables + + def initialize(logger=nil) + + unless logger then + puts('magick class needs a logger') + exit + end + + @variables = Hash.new + @logger = logger + + reset + + end + + def reset + ['compression','depth','colorspace','quality'].each do |key| + setvariable(key) + end + end + + def supported?(filename) # ? pdf + filename =~ /.*\.(png|gif|tif|tiff|jpg|jpeg|eps|ai\d*)/io + end + + def convert(suffix='pdf') + + inpfilename = getvariable('inputfile').dup + outfilename = getvariable('outputfile').dup + outfilename = inpfilename.dup if outfilename.empty? + outfilename.gsub!(/(\.[^\.]*?)$/, ".#{suffix}") + + if inpfilename.empty? || outfilename.empty? then + report("no filenames given") + return false + end + if inpfilename == outfilename then + report("filenames must differ (#{inpfilename} #{outfilename})") + return false + end + unless FileTest.file?(inpfilename) then + report("unknown file #{inpfilename}") + return false + end + + if inpfilename =~ /\.tif+$/io then + tmpfilename = 'temp.png' + arguments = "#{inpfilename} #{tmpfilename}" + begin + debug("imagemagick: #{arguments}") + ok = System.run('imagemagick',arguments) + rescue + report("aborted due to error") + return false + else + return false unless ok + end + inpfilename = tmpfilename + end + + compression = depth = colorspace = quality = '' + + if getvariable('compression') =~ /(zip|jpeg)/o then + compression = " -compress #{$1}" + end + if getvariable('depth') =~ /(8|16)/o then + depth = "-depth #{$1}" + end + if getvariable('colorspace') =~ /(gray|rgb|cmyk)/o then + colorspace = "-colorspace #{$1}" + end + case getvariable('quality') + when 'low' then quality = '-quality 0' + when 'medium' then quality = '-quality 75' + when 'high' then quality = '-quality 100' + end + + report("converting #{inpfilename} to #{outfilename}") + + arguments = [compression,depth,colorspace,quality,inpfilename,outfilename].join(' ').gsub(/\s+/,' ') + + begin + debug("imagemagick: #{arguments}") + ok = System.run('imagemagick',arguments) + rescue + report("aborted due to error") + return false + else + return ok + end + + end + + def autoconvert + + inpfilename = getvariable('inputfile') + outfilename = getvariable('outputfile') + + if inpfilename.empty? || ! FileTest.file?(inpfilename) then + report("missing file #{inpfilename}") + return + end + + outfilename = inpfilename.dup if outfilename.empty? + tmpfilename = 'temp.jpg' + + reset + + megabyte = 1024*1024 + + ok = false + + if FileTest.size(inpfilename)>2*megabyte + setvariable('compression','zip') + ok = convert + else + setvariable('compression','jpeg') + if FileTest.size(inpfilename)>10*megabyte then + setvariable('quality',85) + elsif FileTest.size(inpfilename)>5*megabyte then + setvariable('quality',90) + else + setvariable('quality',95) + end + report("auto quality #{getvariable('quality')}") + setvariable('outputfile', tmpfilename) + ok = convert('jpg') + setvariable('inputfile', tmpfilename) + setvariable('outputfile', outfilename) + ok = convert + begin + File.delete(tmpfilename) + rescue + report("#{tmpfilename} cannot be deleted") + end + end + + reset + + return ok + + end + +end diff --git a/scripts/context/ruby/newimgtopdf.rb b/scripts/context/ruby/newimgtopdf.rb new file mode 100644 index 000000000..3c1636cf2 --- /dev/null +++ b/scripts/context/ruby/newimgtopdf.rb @@ -0,0 +1,86 @@ +#!/usr/bin/env ruby + +# program : newimgtopdf +# copyright : PRAGMA Advanced Document Engineering +# version : 2002-2005 +# author : Hans Hagen +# +# project : ConTeXt / eXaMpLe +# concept : Hans Hagen +# info : j.hagen@xs4all.nl +# www : www.pragma-ade.com + +unless defined? ownpath + ownpath = $0.sub(/[\\\/]\w*?\.rb/i,'') + $: << ownpath +end + +require 'base/switch' +require 'base/logger' + +require 'graphics/magick' + +banner = ['ImgToPdf', 'version 1.1.1', '2002-2005', 'PRAGMA ADE/POD'] + +class Commands + + include CommandBase + + # nowadays we would force a directive, but + # for old times sake we handle default usage + + def main + filename = @commandline.argument('first') + + if filename.empty? then + help + else + convert + end + end + + # actions + + def convert + + magick = Magick.new(session) + + ['compression','depth','colorspace','quality','inputpath','outputpath'].each do |v| + magick.setvariable(v,@commandline.option(v)) + end + + @commandline.arguments.each do |fullname| + magick.setvariable('inputfile',fullname) + magick.setvariable('outputfile',fullname.gsub(/(\..*?$)/io, '.pdf')) + if @commandline.option('auto') then + magick.autoconvert + else + magick.convert + end + end + end + +end + +logger = Logger.new(banner.shift) +commandline = CommandLine.new + +commandline.registerflag('auto') + +commandline.registervalue('compression') +commandline.registervalue('depth') +commandline.registervalue('colorspace') +commandline.registervalue('quality') + +commandline.registervalue('inputpath') +commandline.registervalue('outputpath') + + +commandline.registeraction('help') +commandline.registeraction('version') + +commandline.registeraction('convert', 'convert image into pdf') + +commandline.expand + +Commands.new(commandline,logger,banner).send(commandline.action || 'main') diff --git a/scripts/context/ruby/newpstopdf.rb b/scripts/context/ruby/newpstopdf.rb new file mode 100644 index 000000000..aa3a14fef --- /dev/null +++ b/scripts/context/ruby/newpstopdf.rb @@ -0,0 +1,527 @@ +#!/usr/bin/env ruby + +# program : pstopdf +# copyright : PRAGMA Advanced Document Engineering +# version : 2002-2005 +# author : Hans Hagen +# +# project : ConTeXt / eXaMpLe +# concept : Hans Hagen +# info : j.hagen@xs4all.nl +# www : www.pragma-ade.com + +banner = ['PsToPdf', 'version 2.0.0', '2002-2005', 'PRAGMA ADE/POD'] + +unless defined? ownpath + ownpath = $0.sub(/[\\\/]\w*?\.rb/i,'') + $: << ownpath +end + +# todo: paden/prefix in magick and inkscape +# todo: clean up method handling (pass strings, no numbers) + +require 'base/switch' +require 'base/tool' +require 'base/logger' + +require 'graphics/gs' +require 'graphics/magick' +require 'graphics/inkscape' + +require 'rexml/document' + +exit if defined?(REQUIRE2LIB) + +class Commands + + include CommandBase + + # nowadays we would force a directive, but + # for old times sake we handle default usage + + def main + filename = @commandline.argument('first') + pattern = @commandline.option('pattern') + globfiles(pattern) if filename.empty? && ! pattern.empty? + filename = @commandline.argument('first') + if filename.empty? then + help + elsif filename =~ /\.exa$/ then + request + else + convert + end + end + + # actions + + def convert + + ghostscript = GhostScript.new(logger) + magick = ImageMagick.new(logger) + inkscape = InkScape.new(logger) + + outpath = @commandline.option('outputpath') + unless outpath.empty? then + begin + File.expand_path(outpath) + outpath = File.makedirs(outpath) unless FileTest.directory?(outpath) + rescue + # sorry + end + end + + @commandline.arguments.each do |filename| + + filename = Tool.cleanfilename(filename,@commandline) + inppath = @commandline.option('inputpath') + if inppath.empty? then + inppath = '.' + fullname = filename # avoid duplicate './' + else + fullname = File.join(inppath,filename) + end + if FileTest.file?(fullname) then + handle_whatever(ghostscript,inkscape,magick,filename) + else + report("file #{fullname} does not exist") + end + + end + + end + + def request + + # <exa:request> + # <exa:application> + # <exa:command>pstopdf</exa:command> + # <exa:filename>E:/tmp/demo.ps</exa:filename> + # </exa:application> + # <exa:data> + # <exa:variable label='gs:DoThumbnails'>false</exa:variable> + # <exa:variable label='gs:ColorImageDepth'>-1</exa:variable> + # </exa:data> + # </exa:request> + + ghostscript = GhostScript.new(logger) + magick = ImageMagick.new(logger) + inkscape = InkScape.new(logger) + + dataname = @commandline.argument('first') || '' + filename = @commandline.argument('second') || '' + + if dataname.empty? || ! FileTest.file?(dataname) then + report('provide valid exa file') + return + else + begin + request = REXML::Document.new(File.new(dataname)) + rescue + report('provide valid exa file (xml error)') + return + end + end + if filename.empty? then + begin + if filename = REXML::XPath.first(request.root,"exa:request/exa:application/exa:filename/text()") then + filename = filename.to_s + else + report('no filename found in exa file') + return + end + rescue + filename = '' + end + end + if filename.empty? then + report('provide valid filename') + return + elsif ! FileTest.file?(filename) then + report("invalid filename #{filename}") + return + end + + [ghostscript,inkscape,magick].each do |i| + i.setvariable('inputfile',filename) + end + + # set ghostscript variables + REXML::XPath.each(request.root,"/exa:request/exa:data/exa:variable") do |v| + begin + if (key = v.attributes['label']) and (value = v.text.to_s) then + case key + when /gs[\:\.](var[\:\.])*(offset)/io then ghostscript.setoffset(value) + when /gs[\:\.](var[\:\.])*(method)/io then ghostscript.setvariable('method',value) + when /gs[\:\.](var[\:\.])*(.*)/io then ghostscript.setpsoption($2,value) + end + end + rescue + end + end + + # no inkscape and magick variables (yet) + + handle_whatever(ghostscript,inkscape,magick,filename) + + end + + def watch + + ghostscript = GhostScript.new(logger) + magick = ImageMagick.new(logger) + inkscape = InkScape.new(logger) + + pathname = commandline.option('watch') + + unless pathname and not pathname.empty? then + report('empty watchpath is not supported') + exit + end + + if pathname == '.' then + report("watchpath #{pathname} is not supported") + exit + end + + if FileTest.directory?(pathname) then + if Dir.chdir(pathname) then + report("watching path #{pathname}") + else + report("unable to change to path #{pathname}") + exit + end + else + report("invalid path #{pathname}") + exit + end + + waiting = false + + loop do + + if waiting then + report("waiting #{getvariable('delay')}") + waiting = false + sleep(getvariable('delay').to_i) + end + + files = Dir.glob("**/*.*") + + if files and files.length > 0 then + + files.each do |fullname| + + next unless fullname + + if FileTest.directory?(fullname) then + debug('skipping path', fullname) + next + end + + unless magick.supported(fullname) then + debug('not supported', fullname) + next + end + + if (! FileTest.file?(fullname)) || (FileTest.size(fullname) < 100) then + debug("skipping small crap file #{fullname}") + next + end + + debug("handling file #{fullname}") + + begin + next unless File.rename(fullname,fullname) # access trick + rescue + next # being written + end + + fullname = Tool.cleanfilename(fullname,@commandline) + + fullname.gsub!(/\\/io, '/') + + filename = File.basename(fullname) + filepath = File.dirname(fullname) + + next if filename =~ /gstemp.*/io + + if filepath !~ /(result|done|raw|crop|bound|bitmap)/io then + begin + File.makedirs(filepath+'/raw') + File.makedirs(filepath+'/bound') + File.makedirs(filepath+'/crop') + File.makedirs(filepath+'/bitmap') + debug("creating prefered input paths on #{filepath}") + rescue + debug("creating input paths on #{filepath} failed") + end + end + + if filepath =~ /^(.*\/|)(done|result)$/io then + debug("skipping file #{fullname}") + else + report("start processing file #{fullname}") + if filepath =~ /^(.*\/*)(raw|crop|bound)$/io then + donepath = $1 + 'done' + resultpath = $1 + 'result' + case $2 + when 'raw' then method = 1 + when 'bound' then method = 2 + when 'crop' then method = 3 + else method = 2 + end + report("forcing method #{method}") + else + method = 2 + donepath = filepath + '/done' + resultpath = filepath + '/result' + report("default method #{method}") + end + + begin + File.makedirs(donepath) + File.makedirs(resultpath) + rescue + report('result path creation fails') + end + + if FileTest.directory?(donepath) && FileTest.directory?(resultpath) then + + resultname = resultpath + '/' + filename.sub(/\..*$/,'') + '.pdf' + + @commandline.setoption('inputpath', filepath) + @commandline.setoption('outputpath', resultpath) + @commandline.setoption('method', method) + + if ghostscript.psfile?(fullname) then + handle_ghostscript(ghostscript,filename) + else + handle_magick(magick,filename) + end + + sleep(1) # calm down + + if FileTest.file?(fullname) then + begin + File.copy(fullname,donepath + '/' + filename) + File.delete(fullname) + rescue + report('cleanup fails') + end + end + + end + + end + + end + + end + + waiting = true + end + + end + + private + + def handle_whatever(ghostscript,inkscape,magick,filename) + if ghostscript.psfile?(filename) then + # report("processing ps file #{filename}") + ghostscript.setvariable('pipe',false) if @commandline.option('nopipe') + # ghostscript.setvariable('pipe',not @commandline.option('nopipe')) + ghostscript.setvariable('colormodel',@commandline.option('colormodel')) + ghostscript.setvariable('offset',@commandline.option('offset')) + handle_ghostscript(ghostscript,filename) + elsif ghostscript.pdffile?(filename) && ghostscript.pdfmethod?(@commandline.option('method')) then + # report("processing pdf file #{filename}") + handle_ghostscript(ghostscript,filename) + elsif inkscape.supported?(filename) then + # report("processing non ps/pdf file #{filename}") + handle_inkscape(inkscape,filename) + elsif magick.supported?(filename) then + # report("processing non ps/pdf file #{filename}") + handle_magick(magick,filename) + end + end + + def handle_magick(magick,filename) + + report("converting non-ps file #{filename} into pdf") + + inppath = @commandline.option('inputpath') + outpath = @commandline.option('outputpath') + + inppath = inppath + '/' if not inppath.empty? + outpath = outpath + '/' if not outpath.empty? + + prefix = @commandline.option('prefix') + suffix = @commandline.option('suffix') + + inpfilename = "#{inppath}#{filename}" + outfilename = "#{outpath}#{prefix}#{filename.sub(/\.(.*?)$/, '')}#{suffix}.pdf" + + magick.setvariable('inputfile' , inpfilename) + magick.setvariable('outputfile', outfilename) + + magick.autoconvert + + end + + def handle_inkscape(inkscape,filename) + + report("converting svg(z) file #{filename} into pdf") + + inppath = @commandline.option('inputpath') + outpath = @commandline.option('outputpath') + + inppath = inppath + '/' if not inppath.empty? + outpath = outpath + '/' if not outpath.empty? + + prefix = @commandline.option('prefix') + suffix = @commandline.option('suffix') + + inpfilename = "#{inppath}#{filename}" + outfilename = "#{outpath}#{prefix}#{filename.sub(/\.(.*?)$/, '')}#{suffix}.pdf" + + inkscape.setvariable('inputfile' , inpfilename) + inkscape.setvariable('outputfile', outfilename) + + if @commandline.option('verbose') || @commandline.option('debug') then + logname = filename.gsub(/\.[^\.]*?$/, '.log') + report("log info saved in #{logname}") + inkscape.convert(logname) # logname ook doorgeven + else + inkscape.convert + end + + end + + def handle_ghostscript(ghostscript,filename) + + ghostscript.reset + + method = ghostscript.method(@commandline.option('method')) + force = ghostscript.method(@commandline.option('force')) + + ghostscript.setvariable('method', method) + ghostscript.setvariable('force', force) + + # report("conversion method #{method}") + + inppath = @commandline.option('inputpath') + outpath = @commandline.option('outputpath') + + inppath = inppath + '/' if not inppath.empty? + outpath = outpath + '/' if not outpath.empty? + + prefix = @commandline.option('prefix') + suffix = @commandline.option('suffix') + + ok = false + + if ghostscript.pdfmethod?(method) then + + report("converting pdf file #{filename} into pdf") + + if prefix.empty? && suffix.empty? && inppath.empty? && outpath.empty? then + prefix = ghostscript.pdfprefix(method) + end + + if ghostscript.pdffile?(filename) then + + filename = filename.sub(/\.pdf$/, '') + + inpfilename = "#{inppath}#{filename}.pdf" + outfilename = "#{outpath}#{prefix}#{filename}#{suffix}.pdf" + + ghostscript.setvariable('inputfile' ,inpfilename) + ghostscript.setvariable('outputfile',outfilename) + + if FileTest.file?(inpfilename) then + ok = ghostscript.convert + else + report("no file found #{filename}") + end + + else + report("no pdf file #{filename}") + end + + elsif ghostscript.psfile?(filename) then + + if filename =~ /(.*)\.(.*?)$/io then + filename, filesuffix = $1, $2 + else + filesuffix = 'eps' + end + + report("converting #{filesuffix} (ps) into pdf") + + inpfilename = "#{inppath}#{filename}.#{filesuffix}" + outfilename = "#{outpath}#{prefix}#{filename}#{suffix}.pdf" + + ghostscript.setvariable('inputfile' , inpfilename) + ghostscript.setvariable('outputfile', outfilename) + + if FileTest.file?(inpfilename) then + ok = ghostscript.convert + if ! ok && FileTest.file?(outfilename) then + begin + File.delete(outfilename) + rescue + end + end + else + report("no file with name #{filename} found") + end + + else + report('file must be of type eps/ps/ai/pdf') + end + + return ok + + end + +end + +# ook pdf -> pdf onder optie 0, andere kleurruimte + +logger = Logger.new(banner.shift) +commandline = CommandLine.new + +commandline.registerflag('debug') +commandline.registerflag('verbose') +commandline.registerflag('nopipe') + +commandline.registervalue('method',2) +commandline.registervalue('offset',0) + +commandline.registervalue('prefix') +commandline.registervalue('suffix') + +commandline.registervalue('inputpath') +commandline.registervalue('outputpath') + +commandline.registerflag('watch') +commandline.registerflag('force') + +commandline.registervalue('delay',2) + +commandline.registervalue('colormodel','cmyk') +commandline.registervalue('pattern','') + +commandline.registeraction('help') +commandline.registeraction('version') + +commandline.registeraction('convert', 'convert ps into pdf') +commandline.registeraction('request', 'handles exa request file') +commandline.registeraction('watch', 'watch folders for conversions (untested)') + +commandline.expand + +logger.verbose if (commandline.option('verbose') || commandline.option('debug')) + +Commands.new(commandline,logger,banner).send(commandline.action || 'main') diff --git a/scripts/context/ruby/newtexexec.rb b/scripts/context/ruby/newtexexec.rb new file mode 100644 index 000000000..38c9675ca --- /dev/null +++ b/scripts/context/ruby/newtexexec.rb @@ -0,0 +1,588 @@ +banner = ['TeXExec', 'version 6.0.1', '1997-2005', 'PRAGMA ADE/POD'] + +unless defined? ownpath + ownpath = $0.sub(/[\\\/][a-z0-9\-]*?\.rb/i,'') + $: << ownpath +end + +require 'base/switch' +require 'base/logger' +require 'base/variables' +require 'base/system' + +require 'base/tex' + +require 'ftools' # needed ? + +require 'base/kpse' # needed ? +require 'base/pdf' # needed ? +require 'base/state' # needed ? +require 'base/file' # needed ? + +class Commands + + include CommandBase + + def make + if job = TEX.new(logger) then + # prepare, move to TEX ? + if @commandline.option('fast') then + report('using existing database') + else + report('updating file database') + Kpse.update + end + prepare(job) + # bonus, overloads language switch ! + job.setvariable('language','all') if @commandline.option('all') + if @commandline.arguments.length > 0 then + if @commandline.arguments.first == 'all' then + job.setvariable('texformats',job.defaulttexformats) + job.setvariable('mpsformats',job.defaultmpsformats) + else + job.setvariable('texformats',@commandline.arguments) + job.setvariable('mpsformats',@commandline.arguments) + end + end + job.makeformats + job.inspect && Kpse.inspect if @commandline.option('verbose') + end + end + + def check + if job = TEX.new(logger) then + job.checkcontext + job.inspect && Kpse.inspect if @commandline.option('verbose') + end + end + + def process + if job = TEX.new(logger) then + job.setvariable('files',@commandline.arguments) + prepare(job) + job.processtex + job.inspect && Kpse.inspect if @commandline.option('verbose') + end + end + + def main + if @commandline.arguments.length>0 then + process + else + help + end + end + + def mptex + if job = TEX.new(logger) then + job.setvariable('files',@commandline.arguments) + prepare(job) + job.processmptex + job.inspect && Kpse.inspect if @commandline.option('verbose') + end + end + + def mpxtex + if job = TEX.new(logger) then + job.setvariable('files',@commandline.arguments) + prepare(job) + job.processmpxtex + job.inspect && Kpse.inspect if @commandline.option('verbose') + end + end + + # hard coded goodies # to be redone as s-ctx-.. with vars passed as such + + def listing + if job = TEX.new(logger) then + prepare(job) + job.cleanuptemprunfiles + files = @commandline.arguments.sort + if files.length > 0 then + if f = File.open(job.tempfilename('tex'),'w') then + backspace = @commandline.checkedoption('backspace', '1.5cm') + topspace = @commandline.checkedoption('topspace', '1.5cm') + pretty = @commandline.option('pretty') + f << "% interface=english\n" + f << "\\setupbodyfont[11pt,tt]\n" + f << "\\setuplayout\n" + f << " [topspace=#{topspace},backspace=#{backspace},\n" + f << " header=0cm,footer=1.5cm,\n" + f << " width=middle,height=middle]\n" + f << "\\setuptyping[lines=yes]\n" + f << "\\setuptyping[option=color]\n" if pretty + f << "\\starttext\n"; + files.each do |filename| + report("list file: #{filename}") + cleanname = cleantexfilename(filename).downcase + f << "\\page\n" + f << "\\setupfootertexts[\\tttf #{cleanname}][\\tttf \\pagenumber]\n" + f << "\\typefile{#{filename}}\n" + end + f << "\\stoptext\n" + f.close + job.setvariable('interface','english') + job.setvariable('simplerun',true) + job.setvariable('files',[job.tempfilename]) + job.processtex + else + report('no files to list') + end + else + report('no files to list') + end + job.cleanuptemprunfiles + end + end + + def figures + # this one will be redone using rlxtools + if job = TEX.new(logger) then + prepare(job) + job.cleanuptemprunfiles + files = @commandline.arguments.sort + if files.length > 0 then + if f = File.open(job.tempfilename('tex'),'w') then + job.runtexutil(files,"--figures") + figures = @commandline.checkedoption('method', 'a').downcase + paperoffset = @commandline.checkedoption('paperoffset', '0pt') + backspace = @commandline.checkedoption('backspace', '1.5cm') + topspace = @commandline.checkedoption('topspace', '1.5cm') + boxtype = @commandline.checkedoption('boxtype','') + f << "% format=english\n"; + f << "\\setuplayout\n"; + f << " [topspace=#{topspace},backspace=#{backspace},\n" + f << " header=1.5cm,footer=0pt,\n"; + f << " width=middle,height=middle]\n"; + if @commandline.option('fullscreen') then + f << "\\setupinteraction\n"; + f << " [state=start]\n"; + f << "\\setupinteractionscreen\n"; + f << " [option=max]\n"; + end + boxtype += "box" unless boxtype.empty? || (boxtype =~ /box$/io) + f << "\\starttext\n"; + f << "\\showexternalfigures[alternative=#{figures},offset=#{paperoffset},size=#{boxtype}]\n"; + f << "\\stoptext\n"; + f.close + job.setvariable('interface','english') + job.setvariable('simplerun',true) + job.setvariable('files',[job.tempfilename]) + job.processtex + File.silentdelete('texutil.tuf') + else + report('no figures to show') + end + else + report('no figures to show') + end + job.cleanuptemprunfiles + end + end + + def modules + msuffixes = ['tex','mp','pl','pm','rb'] + if job = TEX.new(logger) then + prepare(job) + job.cleanuptemprunfiles + files = @commandline.arguments.sort + if files.length > 0 then + files.each do |fname| + fnames = Array.new + if FileTest.file?(fname) then + fnames << fname + else + msuffixes.each do |fsuffix| + fnames << File.suffixed(fname,fsuffix) + end + end + fnames.each do |ffname| + if msuffixes.include?(File.splitname(ffname)[1]) && FileTest.file?(ffname) then + if mod = File.open(job.tempfilename('tex'),'w') then + job.runtexutil(ffname,"--documents") + if ted = File.silentopen(File.suffixed(ffname,'ted')) then + firstline = ted.gets + if firstline =~ /interface=/o then + mod << firstline + else + mod << "% interface=en\n" + end + ted.close + else + mod << "% interface=en\n" + end + mod << "\\usemodule[abr-01,mod-01]\n" + mod << "\\def\\ModuleNumber{1}\n" + mod << "\\starttext\n" + # todo: global file too + mod << "\\readlocfile{#{File.suffixed(ffname,'ted')}}{}{}\n" + mod << "\\stoptext\n" + mod.close + job.setvariable('interface','english') # redundant + job.setvariable('simplerun',true) + job.setvariable('files',[job.tempfilename]) + job.processtex + ["dvi", "pdf","tuo"].each do |s| + File.silentrename(job.tempfilename(s),File.suffixed(ffname,s)); + end + end + end + end + end + else + report('no modules to process') + end + job.cleanuptemprunfiles + end + end + + def arrange + if job = TEX.new(logger) then + prepare(job) + job.cleanuptemprunfiles + files = @commandline.arguments.sort + if files.length > 0 then + if f = File.open(job.tempfilename('tex'),'w') then + emptypages = @commandline.checkedoption('addempty', '') + paperoffset = @commandline.checkedoption('paperoffset', '1cm') + textwidth = @commandline.checkedoption('textwidth', '0cm') + backspace = @commandline.checkedoption('backspace', '1.5cm') + topspace = @commandline.checkedoption('topspace', '1.5cm') + f << "\\definepapersize\n" + f << " [offset=#{paperoffset}]\n" + f << "\\setuplayout\n" + f << " [backspace=#{backspace},\n" + f << " topspace=#{topspace},\n" + f << " marking=on,\n" if @commandline.option('marking') + f << " width=middle,\n" + f << " height=middle,\n" + f << " location=middle,\n" + f << " header=0pt,\n" + f << " footer=0pt]\n" + unless @commandline.option('noduplex') then + f << "\\setuppagenumbering\n" + f << " [alternative=doublesided]\n" + end + f << "\\starttext\n" + files.each do |filename| + report("arranging file #{filename}") + f << "\\insertpages\n" + f << " [#{filename}]\n" + f << " [#{addempty}]\n" unless addempty.empty? + f << " [width=#{textwidth}]\n" + end + f << "\\stoptext\n" + f.close + job.setvariable('interface','english') + job.setvariable('simplerun',true) + job.setvariable('files',[job.tempfilename]) + job.processtex + else + report('no files to arrange') + end + else + report('no files to arrange') + end + job.cleanuptemprunfiles + end + end + + def select + if job = TEX.new(logger) then + prepare(job) + job.cleanuptemprunfiles + files = @commandline.arguments.sort + if files.length > 0 then + if f = File.open(job.tempfilename('tex'),'w') then + selection = @commandline.checkedoption('selection', '') + paperoffset = @commandline.checkedoption('paperoffset', '1cm') + textwidth = @commandline.checkedoption('textwidth', '0cm') + backspace = @commandline.checkedoption('backspace', '1.5cm') + topspace = @commandline.checkedoption('topspace', '1.5cm') + paperformat = @commandline.checkedoption('paperoffset', 'A4*A4').split(/[\*x]/o) + from, to = paperformat[0] || 'A4', paperformat[1] || paperformat[0] || 'A4' + f << "\\setuppapersize[#{from}][#{to}]\n" + f << "\\definepapersize\n"; + f << " [offset=#{paperoffset}]\n"; + f << "\\setuplayout\n"; + f << " [backspace=#{backspace},\n"; + f << " topspace=#{topspace},\n"; + f << " marking=on,\n" if @commandline.option('marking') + f << " width=middle,\n"; + f << " height=middle,\n"; + f << " location=middle,\n"; + f << " header=0pt,\n"; + f << " footer=0pt]\n"; + f << "\\setupexternalfigures\n"; + f << " [directory=]\n"; + f << "\\starttext\n"; + unless selection.empty? then + f << "\\filterpages\n" + f << " [#{files.first}][#{selection}][width=#{textwidth}]\n" + end + f << "\\stoptext\n" + f.close + job.setvariable('interface','english') + job.setvariable('simplerun',true) + job.setvariable('files',[job.tempfilename]) + job.processtex + else + report('no files to selectt') + end + else + report('no files to select') + end + job.cleanuptemprunfiles + end + end + + def copy + copyortrim(false,'copy') + end + + def trim + copyortrim(true,'trim') + end + + def copyortrim(trim=false) + if job = TEX.new(logger) then + prepare(job) + job.cleanuptemprunfiles + files = @commandline.arguments.sort + if files.length > 0 then + if f = File.open(job.tempfilename('tex'),'w') then + scale = @commandline.checkedoption('scale') + scale = (scale * 1000).to_i if scale < 10 + paperoffset = @commandline.checkedoption('paperoffset', '1cm') + f << "\\starttext\n" + files.each do |filename| + result = @commandline.checkedoption('result','texexec') + if (filename !~ /^texexec/io) && (filename !~ /^#{result}/) then + report("copying file: #{filename}") + f << "\\getfiguredimensions\n" + f << " [#{filename}]\n" + f << " [page=1" + f << ",\n size=trimbox" if trim + f << "]\n" + f << "\\definepapersize\n" + f << " [copy]\n" + f << " [width=\\naturalfigurewidth,\n" + f << " height=\\naturalfigureheight]\n" + f << "\\setuppapersize\n" + f << " [copy][copy]\n" + f << "\\setuplayout\n" + f << " [page]\n" + f << "\\setupexternalfigures\n" + f << " [directory=]\n" + f << "\\copypages\n" + f << " [#[filename}]\n" + f << " [scale=#{scale},\n" + f << " marking=on,\n" if @commandline.option('markings') + f << " size=trimbox,\n" if trim + f << " offset=#{paperoffset}]\n" + end + end + f << "\\stoptext\n" + f.close + job.setvariable('interface','english') + job.setvariable('simplerun',true) + job.setvariable('files',[job.tempfilename]) + job.processtex + else + report("no files to #{what}") + end + else + report("no files to #{what}") + end + job.cleanuptemprunfiles + end + end + + def combine + if job = TEX.new(logger) then + prepare(job) + job.cleanuptemprunfiles + files = @commandline.arguments.sort + if files.length > 0 then + if f = File.open(job.tempfilename('tex'),'w') then + paperoffset = @commandline.checkedoption('paperoffset', '1cm') + combination = @commandline.checkedoption('combination','2*2').split(/[\*x]/o) + paperformat = @commandline.checkedoption('paperoffset', 'A4*A4').split(/[\*x]/o) + nx, ny = combination[0] || '2', combination[1] || combination[0] || '2' + from, to = paperformat[0] || 'A4', paperformat[1] || paperformat[0] || 'A4' + f << "\\setuppapersize[#{from}][#{to}]\n" + f << "\\setuplayout\n" + f << " [topspace=#{paperoffset},\n" + f << " backspace=#{paperoffset},\n" + f << " header=0pt,\n" + f << " footer=1cm,\n" + f << " width=middle,\n" + f << " height=middle]\n" + if @commandline.option('nobanner') then + f << "\\setuplayout\n" + f << " [footer=0cm]\n" + end + f << "\\setupexternalfigures\n" + f << " [directory=]\n" + f << "\\starttext\n" + files.each do |filename| + result = @commandline.checkedoption('result','texexec') + if (filename !~ /^texexec/io) && (filename !~ /^#{result}/) then + report("combination file: #{filename}") + cleanname = cleantexfilename(filename).downcase + f << "\\setupfootertexts\n" + f << " [\\tttf #{cleanname}\\quad\\quad\\currentdate\\quad\\quad\\pagenumber]\n" + f << "\\combinepages[#{filename}][nx=#{nx},ny=#{ny}]\n" + f << "\\page\n" + end + end + f << "\\stoptext\n" + f.close + job.setvariable('interface','english') + job.setvariable('simplerun',true) + job.setvariable('files',[job.tempfilename]) + job.processtex + else + report('no files to list') + end + else + report('no files to list') + end + job.cleanuptemprunfiles + end + end + + private + + def prepare(job) + + job.booleanvars.each do |k| + job.setvariable(k,@commandline.option(k)) + end + job.stringvars.each do |k| + job.setvariable(k,@commandline.option(k)) + end + job.standardvars.each do |k| + job.setvariable(k,@commandline.option(k)) + end + job.knownvars.each do |k| + job.setvariable(k,@commandline.option(k)) unless @commandline.option(k).empty? + end + + if (str = @commandline.option('engine')) && ! str.standard? && ! str.empty? then + job.setvariable('texengine',str) + elsif @commandline.oneof('pdfetex','pdftex','pdf') then + job.setvariable('texengine','pdfetex') + elsif @commandline.oneof('xetex','xtx') then + job.setvariable('texengine','xetex') + elsif @commandline.oneof('aleph') then + job.setvariable('texengine','aleph') + else + job.setvariable('texengine','standard') + end + + if (str = @commandline.option('backend')) && ! str.standard? && ! str.empty? then + job.setvariable('backend',str) + elsif @commandline.oneof('pdfetex','pdftex','pdf') then + job.setvariable('backend','pdftex') + elsif @commandline.oneof('dvipdfmx','dvipdfm','dpx','dpm') then + job.setvariable('backend','dvipdfmx') + elsif @commandline.oneof('xetex','xtx') then + job.setvariable('backend','xetex') + elsif @commandline.oneof('aleph') then + job.setvariable('backend','dvipdfmx') + else + job.setvariable('backend','standard') + end + + job.setvariable('mpsengine',@commandline.option('engine')) + + end + + def cleantexfilename(filename) + filename.gsub(/([\$\_\#])/) do "\\$1" end.gsub(/([\~])/) do "\\string$1" end + end + +end + +logger = Logger.new(banner.shift) +commandline = CommandLine.new + +# actions + +commandline.registeraction('make', 'make formats') +commandline.registeraction('check', 'check versions') +commandline.registeraction('process', 'process file') +commandline.registeraction('mptex', 'process mp file') +commandline.registeraction('mpxtex', 'process mpx file') + +commandline.registeraction('listing', 'list of file content') +commandline.registeraction('figures', 'generate overview of figures') +commandline.registeraction('modules', 'generate module documentation') +commandline.registeraction('arrange', 'impose pages (booklets)') +commandline.registeraction('select', 'select pages from file(s)') +commandline.registeraction('copy', 'copy pages from file(s)') +commandline.registeraction('trim', 'trim pages from file(s)') +commandline.registeraction('combine', 'combine multiple pages') + +@@extrastringvars = [ + 'pages', 'background', 'backspace', 'topspace', 'boxtype', 'tempdir', + 'printformat', 'paperformat', 'method', 'scale', 'selection', + 'combination', 'paperoffset', 'textwidth', 'addempty', 'logfile', + 'startline', 'endline', 'startcolumn', 'endcolumn', 'scale' +] + +@@extrabooleanvars = [ + 'centerpage', 'noduplex', 'color', 'pretty', + 'fullscreen', 'screensaver', 'markings' +] + +if job = TEX.new(logger) then + + job.setextrastringvars(@@extrastringvars) + job.setextrabooleanvars(@@extrabooleanvars) + + job.booleanvars.each do |k| + commandline.registerflag(k) + end + job.stringvars.each do |k| + commandline.registervalue(k,'') + end + job.standardvars.each do |k| + commandline.registervalue(k,'standard') + end + job.knownvars.each do |k| + commandline.registervalue(k,'') + end + +end + +# todo: register flags -> first one true + +commandline.registerflag('pdf') +commandline.registerflag('pdftex') +commandline.registerflag('pdfetex') + +commandline.registerflag('dvipdfmx') +commandline.registerflag('dvipdfm') +commandline.registerflag('dpx') +commandline.registerflag('dpm') + +commandline.registerflag('xetex') +commandline.registerflag('xtx') + +commandline.registerflag('aleph') + +commandline.registerflag('all') +commandline.registerflag('fast') + +# generic + +commandline.registeraction('help') +commandline.registeraction('version') + +commandline.registerflag('verbose') + +commandline.expand + +Commands.new(commandline,logger,banner).send(commandline.action || 'main') diff --git a/scripts/context/ruby/rlxtools.rb b/scripts/context/ruby/rlxtools.rb new file mode 100644 index 000000000..a3f41b06b --- /dev/null +++ b/scripts/context/ruby/rlxtools.rb @@ -0,0 +1,261 @@ +#!/usr/bin/env ruby + +# program : rlxtools +# copyright : PRAGMA Advanced Document Engineering +# version : 2004-2005 +# author : Hans Hagen +# +# project : ConTeXt / eXaMpLe +# concept : Hans Hagen +# info : j.hagen@xs4all.nl +# www : www.pragma-ade.com + +banner = ['RlxTools', 'version 1.0.1', '2004/2005', 'PRAGMA ADE/POD'] + +unless defined? ownpath + ownpath = $0.sub(/[\\\/][a-z0-9\-]*?\.rb/i,'') + $: << ownpath +end + +require 'base/switch' +require 'base/logger' +require 'base/system' +require 'base/kpse' + +require 'ftools' +require 'rexml/document' + +class Commands + + include CommandBase + + # <?xml version='1.0 standalone='yes'?> + # <rl:manipulators> + # <rl:manipulator name='lowres' suffix='pdf'> + # <rl:step> + # texmfstart + # --verbose + # --iftouched=<rl:value name='path'/>/<rl:value name='file'/>,<rl:value name='path'/>/<rl:value name='prefix'/><rl:value name='file'/> + # pstopdf + # --method=5 + # --inputpath=<rl:value name='path'/> + # --outputpath=<rl:value name='path'/>/<rl:value name='prefix'/> + # <rl:value name='file'/> + # </rl:step> + # </rl:manipulator> + # </rl:manipulators> + # + # <?xml version='1.0' standalone='yes'?> + # <rl:library> + # <rl:usage> + # <rl:type>figure</rl:type> + # <rl:state>found</rl:state> + # <rl:file>cow.pdf</rl:file> + # <rl:suffix>pdf</rl:suffix> + # <rl:path>.</rl:path> + # <rl:conversion>lowres</rl:conversion> + # <rl:prefix>lowres/</rl:prefix> + # <rl:width>276.03125pt</rl:width> + # <rl:height>200.75pt</rl:height> + # </rl:usage> + # </r:library> + + def manipulate + + procname = @commandline.argument('first') || '' + filename = @commandline.argument('second') || '' + + procname = Kpse.found(procname) + + if procname.empty? || ! FileTest.file?(procname) then + report('provide valid manipulator file') + elsif filename.empty? || ! FileTest.file?(filename) then + report('provide valid resource log file') + else + begin + data = REXML::Document.new(File.new(filename)) + rescue + report('provide valid resource log file (xml error)') + return + end + begin + proc = REXML::Document.new(File.new(procname)) + rescue + report('provide valid manipulator file (xml error)') + return + end + report("manipulator file: #{procname}") + report("resourcelog file: #{filename}") + begin + nofrecords, nofdone = 0, 0 + REXML::XPath.each(data.root,"/rl:library/rl:usage") do |usage| + nofrecords += 1 + variables = Hash.new + usage.elements.each do |e| + variables[e.name] = e.text.to_s + end + report("processing record #{nofrecords} (#{variables['file'] || 'noname'}: #{variables.size} entries)") + if conversion = variables['conversion'] then + report("testing for conversion #{conversion}") + if suffix = variables['suffix'] then + if file = variables['file'] then + report("conversion #{conversion} for suffix #{suffix} for file #{file}") + else + report("conversion #{conversion} for suffix #{suffix}") + end + pattern = "@name='#{conversion}' and @suffix='#{suffix}'" + if steps = REXML::XPath.first(proc.root,"/rl:manipulators/rl:manipulator[#{pattern}]") then + localsteps = steps.deep_clone + ['rl:old','rl:new'].each do |tag| + REXML::XPath.each(localsteps,tag) do |extras| + REXML::XPath.each(extras,"rl:value") do |value| + if name = value.attributes['name'] then + substititute(value,variables[name.to_s]) + end + end + end + end + old = REXML::XPath.first(localsteps,"rl:old") + new = REXML::XPath.first(localsteps,"rl:new") + if old && new then + old, new = justtext(old.to_s), justtext(new.to_s) + variables['old'], variables['new'] = old, new + begin + [old,new].each do |d| + File.makedirs(File.dirname(d)) + end + rescue + report("error during path creation") + end + report("old file #{old}") + report("new file #{new}") + level = if File.needsupdate(old,new) then 2 else 0 end + else + level = 1 + end + if level>0 then + REXML::XPath.each(localsteps,"rl:step") do |command| + REXML::XPath.each(command,"rl:old") do |value| + replace(value,old) + end + REXML::XPath.each(command,"rl:new") do |value| + replace(value,new) + end + REXML::XPath.each(command,"rl:value") do |value| + if name = value.attributes['name'] then + substititute(value,variables[name.to_s]) + end + end + str = justtext(command.to_s) + # str.gsub!(/(\.\/)+/io, '') + report("command #{str}") + System.run(str) unless @commandline.option('test') + report("synchronizing #{old} and #{new}") + File.syncmtimes(old,new) if level > 1 + nofdone += 1 + end + else + report("no need for a manipulation") + end + else + report("no manipulator found") + end + else + report("no suffix specified") + end + else + report("no conversion needed") + end + end + if nofdone > 0 then + jobname = filename.gsub(/\.(.*?)$/,'') # not 'tuo' here + tuoname = jobname + '.tuo' + if FileTest.file?(tuoname) && (f = File.open(tuoname,'a')) then + f.puts("%\n% number of rlx manipulations: #{nofdone}\n") + f.close + end + end + rescue + report('error in manipulating files') + end + begin + logname = "#{filename}.log" + File.delete(logname) if FileTest.file?(logname) + File.copy(filename,logname) + rescue + end + end + + end + + private + + def justtext(str) + str = str.to_s + str.gsub!(/<[^>]*?>/o, '') + str.gsub!(/\s+/o, ' ') + str.gsub!(/</o, '<') + str.gsub!(/>/o, '>') + str.gsub!(/&/o, '&') + str.gsub!(/[\/\\]+/o, '/') + return str.strip + end + + def substititute(value,str) + if str then + begin + if value.attributes.key?('method') then + str = filtered(str.to_s,value.attributes['method'].to_s) + end + if str.empty? && value.attributes.key?('default') then + str = value.attributes['default'].to_s + end + value.insert_after(value,REXML::Text.new(str.to_s)) + rescue Exception + end + end + end + + def replace(value,str) + if str then + begin + value.insert_after(value,REXML::Text.new(str.to_s)) + rescue Exception + end + end + end + + def filtered(str,method) + + str = str.to_s # to be sure + case method + when 'name' then # no path, no suffix + case str + when /^.*[\\\/](.+?)\..*?$/o then $1 + when /^.*[\\\/](.+?)$/o then $1 + when /^(.*)\..*?$/o then $1 + else str + end + when 'path' then if str =~ /^(.+)([\\\/])(.*?)$/o then $1 else '' end + when 'suffix' then if str =~ /^.*\.(.*?)$/o then $1 else '' end + when 'nosuffix' then if str =~ /^(.*)\..*?$/o then $1 else str end + when 'nopath' then if str =~ /^.*[\\\/](.*?)$/o then $1 else str end + else str + end + end + +end + +logger = Logger.new(banner.shift) +commandline = CommandLine.new + +commandline.registeraction('manipulate', ' [--test] manipulatorfile resourselog') + +commandline.registeraction('help') +commandline.registeraction('version') + +commandline.registerflag('test') + +commandline.expand + +Commands.new(commandline,logger,banner).send(commandline.action || 'help') diff --git a/scripts/context/ruby/texmfstart.rb b/scripts/context/ruby/texmfstart.rb index 3131c6780..120c73e80 100644 --- a/scripts/context/ruby/texmfstart.rb +++ b/scripts/context/ruby/texmfstart.rb @@ -2,7 +2,7 @@ # program : texmfstart # copyright : PRAGMA Advanced Document Engineering -# version : 1.05 - 2003/2004 +# version : 1.5.5 - 2003/2005 # author : Hans Hagen # # project : ConTeXt / eXaMpLe @@ -24,17 +24,75 @@ # --exec => exec instead of system # --iftouched=a,b => only if timestamp a<>b +# we don't depend on other libs + require "rbconfig" $mswindows = Config::CONFIG['host_os'] =~ /mswin/ $separator = File::PATH_SEPARATOR -$version = "1.5.2" +$version = "1.6.0" if $mswindows then require "win32ole" require "Win32API" +end + +exit if defined?(REQUIRE2LIB) + +$stdout.sync = true +$stderr.sync = true + +$applications = Hash.new +$suffixinputs = Hash.new +$predefined = Hash.new + +$suffixinputs['pl'] = 'PERLINPUTS' +$suffixinputs['rb'] = 'RUBYINPUTS' +$suffixinputs['py'] = 'PYTHONINPUTS' +$suffixinputs['jar'] = 'JAVAINPUTS' +$suffixinputs['pdf'] = 'PDFINPUTS' + +$predefined['texexec'] = 'texexec.pl' +$predefined['texutil'] = 'texutil.pl' +$predefined['texfont'] = 'texfont.pl' +$predefined['examplex'] = 'examplex.rb' +$predefined['concheck'] = 'concheck.rb' +$predefined['textools'] = 'textools.rb' +$predefined['ctxtools'] = 'ctxtools.rb' +$predefined['rlxtools'] = 'rlxtools.rb' +$predefined['pdftools'] = 'pdftools.rb' +$predefined['exatools'] = 'exatools.rb' +$predefined['xmltools'] = 'xmltools.rb' +$predefined['pstopdf'] = 'pstopdf.rb' + +$scriptlist = 'rb|pl|py|jar' +$documentlist = 'pdf|ps|eps|htm|html' + +$crossover = true # to other tex tools, else only local + +$applications['unknown'] = '' +$applications['perl'] = $applications['pl'] = 'perl' +$applications['ruby'] = $applications['rb'] = 'ruby' +$applications['python'] = $applications['py'] = 'python' +$applications['java'] = $applications['jar'] = 'java' + +if $mswindows then + $applications['pdf'] = ['',"pdfopen --page #{$page} --file",'acroread'] + $applications['html'] = ['','netscape','mozilla','opera','iexplore'] + $applications['ps'] = ['','gview32','gv','gswin32','gs'] +else + $applications['pdf'] = ["pdfopen --page #{$page} --file",'acroread'] + $applications['html'] = ['netscape','mozilla','opera'] + $applications['ps'] = ['gview','gv','gs'] +end + +$applications['htm'] = $applications['html'] +$applications['eps'] = $applications['ps'] + +if $mswindows then + GetShortPathName = Win32API.new('kernel32', 'GetShortPathName', ['P','P','N'], 'N') GetLongPathName = Win32API.new('kernel32', 'GetLongPathName', ['P','P','N'], 'N') @@ -92,7 +150,11 @@ class File def File.needsupdate(oldname,newname) begin - return File.stat(oldname).mtime != File.stat(newname).mtime + if $mswindows then + return File.stat(oldname).mtime > File.stat(newname).mtime + else + return File.stat(oldname).mtime != File.stat(newname).mtime + end rescue return true end @@ -100,38 +162,25 @@ class File def File.syncmtimes(oldname,newname) begin - t = File.mtime(oldname) # i'm not sure if the time is frozen, so we do it here - File.utime(0,t,oldname,newname) + if $mswindows then + # does not work (yet) + else + t = File.mtime(oldname) # i'm not sure if the time is frozen, so we do it here + File.utime(0,t,oldname,newname) + end rescue end end -end - -$applications = Hash.new -$suffixinputs = Hash.new -$predefined = Hash.new - -$suffixinputs['pl'] = 'PERLINPUTS' -$suffixinputs['rb'] = 'RUBYINPUTS' -$suffixinputs['py'] = 'PYTHONINPUTS' -$suffixinputs['jar'] = 'JAVAINPUTS' -$suffixinputs['pdf'] = 'PDFINPUTS' - -$predefined['texexec'] = 'texexec.pl' -$predefined['texutil'] = 'texutil.pl' -$predefined['texfont'] = 'texfont.pl' -$predefined['examplex'] = 'examplex.rb' -$predefined['concheck'] = 'concheck.rb' -$predefined['textools'] = 'textools.rb' -$predefined['ctxtools'] = 'ctxtools.rb' -$predefined['pdftools'] = 'pdftools.rb' -$predefined['exatools'] = 'exatools.rb' -$predefined['xmltools'] = 'xmltools.rb' -$predefined['pstopdf'] = 'pstopdf.rb' + def File.timestamp(name) + begin + "#{File.stat(name).mtime}" + rescue + return 'unknown' + end + end -$scriptlist = 'rb|pl|py|jar' -$documentlist = 'pdf|ps|eps|htm|html' +end def hashed (arr=[]) arg = if arr.class == String then arr.split(' ') else arr.dup end @@ -158,7 +207,7 @@ end def launch(filename) if $browser && $mswindows then - filename.gsub!(/\.[\/\\]/) do + filename = filename.gsub(/\.[\/\\]/) do Dir.getwd + '/' end report("launching #{filename}") @@ -172,54 +221,89 @@ def launch(filename) end def expanded(arg) # no "other text files", too restricted - arg.gsub(/kpse\:(\S+)/o) do - original, resolved = $1, '' + arg.gsub(/(env)\:([a-zA-Z\-\_\.0-9]+)/o) do + method, original, resolved = $1, $2, '' + if resolved = ENV[original] then + report("environment variable #{original} expands to #{resolved}") unless $report + resolved + else + report("environment variable #{original} cannot be resolved") unless $report + original + end + end . gsub(/(kpse|loc)\:([a-zA-Z\-\_\.0-9]+)/o) do # was: \S + method, original, resolved = $1, $2, '' if $program && ! $program.empty? then - pstr = "-progname=#{$program}" + pstrings = ["-progname=#{$program}"] else - pstr = '' + pstrings = ['','progname=context'] end # auto suffix with texinputs as fall back - begin - resolved = `kpsewhich #{pstr} #{original}`.chomp - rescue - resolved = '' - end - # elsewhere in the tree - if resolved.empty? then - begin - resolved = `kpsewhich #{pstr} -format="other text files" #{original}`.chomp - rescue - resolved = '' - end - end - if resolved.empty? then - report("#{original} is not resolved") unless $report - original - else - report("#{original} is resolved to #{resolved}") unless $report + if ENV["_CTX_K_V_#{original}_"] then + resolved = ENV["_CTX_K_V_#{original}_"] + report("environment provides #{original} as #{resolved}") unless $report resolved + else + pstrings.each do |pstr| + if resolved.empty? then + command = "kpsewhich #{pstr} #{original}" + report("running #{command}") + begin + resolved = `#{command}`.chomp + rescue + resolved = '' + end + end + # elsewhere in the tree + if resolved.empty? then + command = "kpsewhich #{pstr} -format=\"other text files\" #{original}" + report("running #{command}") + begin + resolved = `#{command}`.chomp + rescue + resolved = '' + end + end + end + if resolved.empty? then + report("#{original} is not resolved") unless $report + ENV["_CTX_K_V_#{original}_"] = original if $crossover + original + else + report("#{original} is resolved to #{resolved}") unless $report + ENV["_CTX_K_V_#{original}_"] = resolved if $crossover + resolved + end end end end def runcommand(command) if $locate then - print(command) + command = command.split(' ').collect do |c| + if c =~ /\//o then + begin + cc = File.expand_path(c) + c = cc if FileTest.file?(cc) + rescue + end + end + c + end . join(' ') + print command # to stdout and no newline elsif $execute then - report("using 'exec' instead of 'system' call: #{command}") if $verbose + report("using 'exec' instead of 'system' call: #{command}") begin Dir.chdir($path) if ! $path.empty? rescue - report("unable to chdir to: #{$path}") if $verbose + report("unable to chdir to: #{$path}") end exec(command) else - report("using 'system' call: #{command}") if $verbose + report("using 'system' call: #{command}") begin Dir.chdir($path) if ! $path.empty? rescue - report("unable to chdir to: #{$path}") if $verbose + report("unable to chdir to: #{$path}") end system(command) end @@ -230,29 +314,27 @@ def runoneof(application,fullname,browserpermitted) return true else report("starting #{$filename}") unless $report - print "\n" if $report && $verbose + ouput("\n") if $report && $verbose applications = $applications[application] if applications.class == Array then if $report then - print [fullname,expanded($arguments)].join(' ') + output([fullname,expanded($arguments)].join(' ')) return true else applications.each do |a| - if runcommand([a,fullname,expanded($arguments)].join(' ')) then - return true - end + return true if runcommand([a,fullname,expanded($arguments)].join(' ')) end end elsif applications.empty? then if $report then - print [fullname,expanded($arguments)].join(' ') + output([fullname,expanded($arguments)].join(' ')) return true else return runcommand([fullname,expanded($arguments)].join(' ')) end else if $report then - print [applications,fullname,expanded($arguments)].join(' ') + output([applications,fullname,expanded($arguments)].join(' ')) return true else return runcommand([applications,fullname,expanded($arguments)].join(' ')) @@ -263,7 +345,11 @@ def runoneof(application,fullname,browserpermitted) end def report(str) - print str + "\n" if $verbose ; + $stderr.puts(str) if $verbose +end + +def output(str) + $stderr.puts(str) end def usage @@ -283,23 +369,35 @@ def usage print(" texmfstart --page=2 --file=showcase.pdf\n") print(" texmfstart --program=yourtex yourscript.pl arg-1 arg-2\n") print(" texmfstart --direct xsltproc kpse:somefile.xsl somefile.xml\n") - print(" texmfstart bin:xsltproc kpse:somefile.xsl somefile.xml\n") + print(" texmfstart bin:xsltproc env:somepreset kpse:somefile.xsl somefile.xml\n") print(" texmfstart --iftouched=normal,lowres downsample.rb normal lowres\n") end # somehow registration does not work out (at least not under windows) def registered?(filename) - return ENV["texmfstart.#{filename}"] != nil + if $crossover then + return ENV["_CTX_K_S_#{filename}_"] != nil + else + return ENV["texmfstart.#{filename}"] != nil + end end def registered(filename) - return ENV["texmfstart.#{filename}"] + if $crossover then + return ENV["_CTX_K_S_#{filename}_"] + else + return ENV["texmfstart.#{filename}"] + end end def register(filename,fullname) if fullname && ! fullname.empty? then # && FileTest.file?(fullname) - ENV["texmfstart.#{filename}"] = fullname + if $crossover then + ENV["_CTX_K_S_#{filename}_"] = fullname + else + ENV["texmfstart.#{filename}"] = fullname + end return true else return false @@ -307,6 +405,7 @@ def register(filename,fullname) end def find(filename,program) + filename = filename.sub(/script:/o, '') # so we have bin: and script: and nothing if $predefined.key?(filename) then report("expanding '#{filename}' to '#{$predefined[filename]}'") filename = $predefined[filename] @@ -333,13 +432,17 @@ def find(filename,program) end end filename.sub!(/^.*[\\\/]/, '') - # next we look at the current path - suffixlist.each do |suffix| - report("locating '#{filename}.#{suffix}' in currentpath") - fullname = './'+filename+'.'+suffix - if FileTest.file?(fullname) && register(filename,fullname) then - report("'#{filename}.#{suffix}' located in currentpath") - return shortpathname(fullname) + # next we look at the current path and the callerpath + ownpath = $0.sub(/[\\\/][a-z0-9\-]*?\.rb/i,'') + [['.','current'],[ownpath,'caller']].each do |p| + suffixlist.each do |suffix| + fname = "#{filename}.#{suffix}" + fullname = File.join(p[0],fname) + report("locating '#{fname}' in #{p[1]} path") + if FileTest.file?(fullname) && register(filename,fullname) then + report("'#{fname}' located in #{p[1]} path") + return shortpathname(fullname) + end end end # now we consult environment settings @@ -408,7 +511,18 @@ def find(filename,program) return shortpathname(fullname) if register(filename,fullname) end end - return fullname if register(filename,fullname) + return shortpathname(fullname) if register(filename,fullname) + # let's take a look at the path + paths = ENV['PATH'].split($separator) + suffixlist.each do |s| + paths.each do |p| + report("checking #{p} for suffix #{s}") + if FileTest.file?(File.join(p,"#{filename}.#{s}")) then + fullname = File.join(p,"#{filename}.#{s}") + return shortpathname(fullname) if register(filename,fullname) + end + end + end # bad luck, we need to search the tree ourselves if (suffixlist.length == 1) && (suffixlist.first =~ /(#{$documentlist})/) then report("aggressively locating '#{filename}' in document trees") @@ -540,78 +654,19 @@ def make(filename,windows=false,linux=false) return false end -$stdout.sync = true -$directives = hashed(ARGV) - -$help = $directives['help'] || false -$filename = $directives['file'] || '' -$program = $directives['program'] || 'context' -$direct = $directives['direct'] || false -$page = $directives['page'] || 0 -$browser = $directives['browser'] || false -$report = $directives['report'] || false -$verbose = $directives['verbose'] || false -$arguments = $directives['arguments'] || '' -$execute = $directives['execute'] || $directives['exec'] || false -$locate = $directives['locate'] || false - -$path = $directives['path'] || '' - -$make = $directives['make'] || false -$unix = $directives['unix'] || false -$windows = $directives['windows'] || false -$stubpath = $directives['stubpath'] || '' -$indirect = $directives['indirect'] || false - -$iftouched = $directives['iftouched'] || false - -$openoffice = $directives['oo'] || false - -$applications['unknown'] = '' -$applications['perl'] = $applications['pl'] = 'perl' -$applications['ruby'] = $applications['rb'] = 'ruby' -$applications['python'] = $applications['py'] = 'python' -$applications['java'] = $applications['jar'] = 'java' - -if $openoffice then - if ENV['OOPATH'] then - if FileTest.directory?(ENV['OOPATH']) then - report("using open office python") if $verbose - if $mswindows then - $applications['python'] = $applications['py'] = "\"#{File.join(ENV['OOPATH'],'program','python.bat')}\"" - else - $applications['python'] = $applications['py'] = File.join(ENV['OOPATH'],'python') - end - report("python path #{$applications['python']}") if $verbose - else - report("environment variable 'OOPATH' does not exist") if $verbose - end - else - report("environment variable 'OOPATH' is not set") if $verbose - end -end - -if $mswindows then - $applications['pdf'] = ['',"pdfopen --page #{$page} --file",'acroread'] - $applications['html'] = ['','netscape','mozilla','opera','iexplore'] - $applications['ps'] = ['','gview32','gv','gswin32','gs'] -else - $applications['pdf'] = ["pdfopen --page #{$page} --file",'acroread'] - $applications['html'] = ['netscape','mozilla','opera'] - $applications['ps'] = ['gview','gv','gs'] -end - -$applications['htm'] = $applications['html'] -$applications['eps'] = $applications['ps'] - def process(&block) if $iftouched then files = $directives['iftouched'].split(',') oldname, newname = files[0], files[1] if oldname && newname && File.needsupdate(oldname,newname) then + report("file #{oldname}: #{File.timestamp(oldname)}") + report("file #{newname}: #{File.timestamp(newname)}") + report("file is touched, processing started") yield File.syncmtimes(oldname,newname) + else + report("file #{oldname} is untouched") end else yield @@ -619,29 +674,84 @@ def process(&block) end -# system("perl -V") +def main -if $help || ! $filename || $filename.empty? then - usage -else - report("texmfstart version #{$version}") if $verbose - if $make then - if $windows then - make($filename,true,false) - elsif $unix then - make($filename,false,true) + $directives = hashed(ARGV) + + $help = $directives['help'] || false + $batch = $directives['batch'] || false + $filename = $directives['file'] || '' + $program = $directives['program'] || 'context' + $direct = $directives['direct'] || false + $page = $directives['page'] || 0 + $browser = $directives['browser'] || false + $report = $directives['report'] || false + $verbose = $directives['verbose'] || (ENV['_CTX_VERBOSE_'] =~ /(y|yes|t|true|on)/io) || false + $arguments = $directives['arguments'] || '' + $execute = $directives['execute'] || $directives['exec'] || false + $locate = $directives['locate'] || false + + $path = $directives['path'] || '' + + $make = $directives['make'] || false + $unix = $directives['unix'] || false + $windows = $directives['windows'] || false + $stubpath = $directives['stubpath'] || '' + $indirect = $directives['indirect'] || false + + $iftouched = $directives['iftouched'] || false + + $openoffice = $directives['oo'] || false + + $crossover = false if $directives['clear'] + + ENV['_CTX_VERBOSE_'] = 'yes' if $verbose + + if $openoffice then + if ENV['OOPATH'] then + if FileTest.directory?(ENV['OOPATH']) then + report("using open office python") + if $mswindows then + $applications['python'] = $applications['py'] = "\"#{File.join(ENV['OOPATH'],'program','python.bat')}\"" + else + $applications['python'] = $applications['py'] = File.join(ENV['OOPATH'],'python') + end + report("python path #{$applications['python']}") + else + report("environment variable 'OOPATH' does not exist") + end else - make($filename,$mswindows,!$mswindows) + report("environment variable 'OOPATH' is not set") end - elsif $browser && $filename =~ /^http\:\/\// then - launch($filename) + end + + if $help || ! $filename || $filename.empty? then + usage + elsif $batch && $filename && ! $filename.empty? then + # todo, take commands from file and avoid multiple starts and checks else - process do - if $direct || $filename =~ /^bin\:/ then - direct($filename) + report("texmfstart version #{$version}") + if $make then + if $windows then + make($filename,true,false) + elsif $unix then + make($filename,false,true) else - run(find(shortpathname($filename),$program)) + make($filename,$mswindows,!$mswindows) + end + elsif $browser && $filename =~ /^http\:\/\// then + launch($filename) + else + process do + if $direct || $filename =~ /^bin\:/ then + direct($filename) + else # script: or no prefix + run(find(shortpathname($filename),$program)) + end end end end + end + +main diff --git a/scripts/context/ruby/texsync.rb b/scripts/context/ruby/texsync.rb index 37faf2b30..22b7d46c0 100644 --- a/scripts/context/ruby/texsync.rb +++ b/scripts/context/ruby/texsync.rb @@ -2,22 +2,29 @@ # program : texsync # copyright : PRAGMA Advanced Document Engineering -# version : 1.1 - 2003/2004 +# version : 2003-2005 # author : Hans Hagen +# +# project : ConTeXt / eXaMpLe +# concept : Hans Hagen +# info : j.hagen@xs4all.nl +# www : www.pragma-ade.com # For the moment this script only handles the 'minimal' context # distribution. In due time I will add a few more options, like # synchronization of the iso image. -banner = ['TeXSync', 'version 1.1', '2002/2004', 'PRAGMA ADE/POD'] +banner = ['TeXSync', 'version 1.1.1', '2002/2004', 'PRAGMA ADE/POD'] unless defined? ownpath ownpath = $0.sub(/[\\\/]\w*?\.rb/i,'') $: << ownpath end -require 'xmpl/switch' -require 'exa/logger' +require 'base/switch' +require 'base/logger' +# require 'base/tool' + require 'rbconfig' class Commands @@ -134,7 +141,7 @@ class Commands texpaths = ['texmf','texmf-local','texmf-fonts','texmf-mswin','texmf-linux','texmf-macos'] elsif option('terse') then texpaths = ['texmf','texmf-local','texmf-fonts'] - case Config::CONFIG['host_os'] + case Config::CONFIG['host_os'] # or: Tool.ruby_platform when /mswin/ then texpaths.push('texmf-mswin') when /linux/ then texpaths.push('texmf-linux') when /darwin/ then texpaths.push('texmf-macosx') @@ -176,7 +183,7 @@ class Commands end -logger = EXA::ExaLogger.new(banner.shift) +logger = Logger.new(banner.shift) commandline = CommandLine.new commandline.registeraction('update', 'update installed tree') diff --git a/scripts/context/ruby/textools.rb b/scripts/context/ruby/textools.rb index a1880890d..7d23c7dbc 100644 --- a/scripts/context/ruby/textools.rb +++ b/scripts/context/ruby/textools.rb @@ -2,22 +2,28 @@ # program : textools # copyright : PRAGMA Advanced Document Engineering -# version : 1.1 - 2002/2004 +# version : 2002-2005 # author : Hans Hagen +# +# project : ConTeXt / eXaMpLe +# concept : Hans Hagen +# info : j.hagen@xs4all.nl +# www : www.pragma-ade.com # This script will harbor some handy manipulations on tex # related files. -banner = ['TeXTools', 'version 1.2', '2002/2004', 'PRAGMA ADE/POD'] +banner = ['TeXTools', 'version 1.2.1', '2002/2005', 'PRAGMA ADE/POD'] unless defined? ownpath ownpath = $0.sub(/[\\\/][a-z0-9\-]*?\.rb/i,'') $: << ownpath end +require 'base/switch' +require 'base/logger' + require 'ftools' -require 'xmpl/switch' -require 'exa/logger' # Remark # @@ -717,7 +723,7 @@ class Commands end -logger = EXA::ExaLogger.new(banner.shift) +logger = Logger.new(banner.shift) commandline = CommandLine.new commandline.registeraction('removemapnames' , '[pattern] [--recurse]') diff --git a/scripts/context/ruby/xmltools.rb b/scripts/context/ruby/xmltools.rb index be5bf814c..a57f74450 100644 --- a/scripts/context/ruby/xmltools.rb +++ b/scripts/context/ruby/xmltools.rb @@ -2,21 +2,26 @@ # program : xmltools # copyright : PRAGMA Advanced Document Engineering -# version : 1.0 - 2002/2004 +# version : 2002-2005 # author : Hans Hagen +# +# project : ConTeXt / eXaMpLe +# concept : Hans Hagen +# info : j.hagen@xs4all.nl +# www : www.pragma-ade.com # This script will harbor some handy manipulations on tex # related files. -banner = ['XMLTools', 'version 1.1', '2002/2004', 'PRAGMA ADE/POD'] +banner = ['XMLTools', 'version 1.1.1', '2002/2005', 'PRAGMA ADE/POD'] unless defined? ownpath ownpath = $0.sub(/[\\\/][a-z0-9\-]*?\.rb/i,'') $: << ownpath end -require 'xmpl/switch' -require 'exa/logger' +require 'base/switch' +require 'base/logger' class String @@ -312,7 +317,7 @@ class Commands end -logger = EXA::ExaLogger.new(banner.shift) +logger = Logger.new(banner.shift) commandline = CommandLine.new commandline.registeraction('dir', 'generate directory listing') |