summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/context
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2006-01-09 01:54:09 +0000
committerKarl Berry <karl@freefriends.org>2006-01-09 01:54:09 +0000
commit50b347972956e0bfbe7029305e0f459e5ce3ac0c (patch)
treed1b824bbc33a30bf7fcf54b866a1cff949d2e0bf /Master/texmf-dist/scripts/context
parent52f01b2f769ac290674a469d46f149985042ee2e (diff)
trunk/Master/texmf-dist/scripts
git-svn-id: svn://tug.org/texlive/trunk@92 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/scripts/context')
-rw-r--r--Master/texmf-dist/scripts/context/perl/cont_mis.pm69
-rw-r--r--Master/texmf-dist/scripts/context/perl/cont_set.pm670
-rw-r--r--Master/texmf-dist/scripts/context/perl/fdf2tan.pl121
-rw-r--r--Master/texmf-dist/scripts/context/perl/fdf2tex.pl213
-rw-r--r--Master/texmf-dist/scripts/context/perl/makempy.pl365
-rw-r--r--Master/texmf-dist/scripts/context/perl/mptopdf.pl123
-rw-r--r--Master/texmf-dist/scripts/context/perl/path_tre.pm36
-rw-r--r--Master/texmf-dist/scripts/context/perl/texexec.pl3252
-rw-r--r--Master/texmf-dist/scripts/context/perl/texexec.rme169
-rw-r--r--Master/texmf-dist/scripts/context/perl/texfind.pl270
-rw-r--r--Master/texmf-dist/scripts/context/perl/texfont.pl1154
-rw-r--r--Master/texmf-dist/scripts/context/perl/texshow.pl936
-rw-r--r--Master/texmf-dist/scripts/context/perl/texutil.pl2902
-rw-r--r--Master/texmf-dist/scripts/context/perl/utiplug.pm30
-rw-r--r--Master/texmf-dist/scripts/context/ruby/base/ctx.rb285
-rw-r--r--Master/texmf-dist/scripts/context/ruby/base/file.rb147
-rw-r--r--Master/texmf-dist/scripts/context/ruby/base/kpse.rb305
-rw-r--r--Master/texmf-dist/scripts/context/ruby/base/kpsefast.rb881
-rw-r--r--Master/texmf-dist/scripts/context/ruby/base/logger.rb104
-rw-r--r--Master/texmf-dist/scripts/context/ruby/base/pdf.rb51
-rw-r--r--Master/texmf-dist/scripts/context/ruby/base/state.rb75
-rw-r--r--Master/texmf-dist/scripts/context/ruby/base/switch.rb605
-rw-r--r--Master/texmf-dist/scripts/context/ruby/base/system.rb102
-rw-r--r--Master/texmf-dist/scripts/context/ruby/base/tex.rb1495
-rw-r--r--Master/texmf-dist/scripts/context/ruby/base/texutil.rb872
-rw-r--r--Master/texmf-dist/scripts/context/ruby/base/tool.rb306
-rw-r--r--Master/texmf-dist/scripts/context/ruby/base/variables.rb45
-rw-r--r--Master/texmf-dist/scripts/context/ruby/concheck.rb461
-rw-r--r--Master/texmf-dist/scripts/context/ruby/ctxtools.rb1405
-rw-r--r--Master/texmf-dist/scripts/context/ruby/fcd_start.rb453
-rw-r--r--Master/texmf-dist/scripts/context/ruby/graphics/gs.rb641
-rw-r--r--Master/texmf-dist/scripts/context/ruby/graphics/inkscape.rb103
-rw-r--r--Master/texmf-dist/scripts/context/ruby/graphics/magick.rb161
-rw-r--r--Master/texmf-dist/scripts/context/ruby/mpstools.rb5
-rw-r--r--Master/texmf-dist/scripts/context/ruby/newimgtopdf.rb86
-rw-r--r--Master/texmf-dist/scripts/context/ruby/newpstopdf.rb530
-rw-r--r--Master/texmf-dist/scripts/context/ruby/newtexexec.rb609
-rw-r--r--Master/texmf-dist/scripts/context/ruby/newtexutil.rb96
-rw-r--r--Master/texmf-dist/scripts/context/ruby/rlxtools.rb262
-rw-r--r--Master/texmf-dist/scripts/context/ruby/texmfstart.rb847
-rw-r--r--Master/texmf-dist/scripts/context/ruby/texsync.rb207
-rw-r--r--Master/texmf-dist/scripts/context/ruby/textools.rb885
-rw-r--r--Master/texmf-dist/scripts/context/ruby/tmftools.rb133
-rw-r--r--Master/texmf-dist/scripts/context/ruby/xmltools.rb352
44 files changed, 22819 insertions, 0 deletions
diff --git a/Master/texmf-dist/scripts/context/perl/cont_mis.pm b/Master/texmf-dist/scripts/context/perl/cont_mis.pm
new file mode 100644
index 00000000000..6bd449bf045
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/perl/cont_mis.pm
@@ -0,0 +1,69 @@
+#D \module
+#D [ file=cont\_mis.pm,
+#D version=1999.05.05,
+#D title=General modules,
+#D subtitle=all kind of subs,
+#D author=Hans Hagen,
+#D date=\currentdate,
+#D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+#C
+#C This module is part of the \CONTEXT\ macro||package and is
+#C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+#C details.
+
+#D Not yet documented, source will be cleaned up.
+
+package cont_mis ;
+
+use strict ;
+
+my ($message, $separator, $content) ;
+
+format =
+@>>>>>>>>>>>>>>>>>>>>> @ @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+$message,$separator,$content
+.
+
+sub report
+ { ($message, $separator, $content) = @_ ; write }
+
+sub crlf { print "\n" }
+sub banner { crlf ; report (shift , '/', shift) ; crlf }
+sub message { report (shift , ':', shift) }
+sub help { report (shift , ' ', shift) }
+sub status { message ('status' , shift) }
+sub warning { message ('warning' , shift) }
+sub error { message ('error' , shift) }
+sub continue { message ('' , shift) }
+
+sub hex_color
+ { my ($r,$g,$b) = @_ ;
+ if ($r>1) { $r=0xffff } else { $r = 0xffff*$r }
+ if ($g>1) { $g=0xffff } else { $g = 0xffff*$g }
+ if ($b>1) { $b=0xffff } else { $b = 0xffff*$b }
+ local $_ = sprintf "%4x%4x%4x", $r, $g, $b ;
+ s/ /0/go ;
+ return $_ }
+
+sub InterfaceFound
+ { local $_ = shift ;
+ if (/^\%.*interface=(.*?)\b/)
+ { return $1 }
+ elsif (/\\(starttekst|stoptekst|startonderdeel)/)
+ { return 'nl' }
+ elsif (/\\(stelle|verwende|umgebung|benutze)/)
+ { return 'de' }
+ elsif (/\\(stel|gebruik|omgeving)/)
+ { return 'nl' }
+ elsif (/\\(use|setup|environment)/)
+ { return 'en' }
+ elsif (/(hoogte|breedte|letter)=/)
+ { return 'nl' }
+ elsif (/(height|width|style)=/)
+ { return 'en' }
+ elsif (/(hoehe|breite|schrift)=/)
+ { return 'de' }
+ else
+ { return '' } }
+
+1;
diff --git a/Master/texmf-dist/scripts/context/perl/cont_set.pm b/Master/texmf-dist/scripts/context/perl/cont_set.pm
new file mode 100644
index 00000000000..41c62e75440
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/perl/cont_set.pm
@@ -0,0 +1,670 @@
+#D \module
+#D [ file=cont\_set.pm,
+#D version=1999.04.01,
+#D title=General modules,
+#D subtitle=showing \CONTEXT\ commands,
+#D author=Hans Hagen,
+#D date=\currentdate,
+#D copyright={PRAGMA / Hans Hagen \& Ton Otten},
+#D suggestions={Tobias Burnus \& Taco Hoekater}]
+#C
+#C This module is part of the \CONTEXT\ macro||package and is
+#C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+#C details.
+
+# todo: tacos speed patch
+
+#D As always: thanks to Taco and Tobias for testing this
+#D module and providing suggestions and code snippets as
+#D well as haunting bugs.
+
+package cont_set ;
+
+#D This module (package) deals with providing help information
+#D about the \CONTEXT\ commands. The data needed is derived
+#D from the setup files by \CONTEXT\ itself. The data is
+#D stored in files with suffix \type {tws} (tex work setup).
+#D This module introduces some subroutines:
+#D
+#D \starttabulatie[|Tl|p|]
+#D \NC \type {set\_setup\_interface} \NC sets the primary interface
+#D to search in \NC \NR
+#D \NC \type {set\_setup\_title} \NC sets the title of the main
+#D window title \NC \NR
+#D \NC \type {setups\_found} \NC locate the \type {tws} files
+#D using the \type {kpsewhich}
+#D program \NC \NR
+#D \NC \type {show\_setups} \NC allocate the radio buttons
+#D that can be used to select a
+#D command set \NC \NR
+#D \NC \type {load\_setup(filename)} \NC load the names \type {tws}
+#D file \NC \NR
+#D \NC \type {load\_setups} \NC all found command files can
+#D be loaded at once \NC \NR
+#D \NC \type {setup\_found(filename)} \NC this routine returns~1 when
+#D the file is loaded \NC \NR
+#D \NC \type {update\_setup} \NC when we browse the list with
+#D commands, this routine takes care
+#D of updating the text area \NC \NR
+#D \NC \type {change\_setup} \NC we can manually set the
+#D command set we want to browse,
+#D and this routine takes care of
+#D this \NC \NR
+#D \NC \type {show\_setup(command)} \NC context sensitive help can be
+#D provided by calling this sub \NC \NR
+#D \stoptabulatie
+#D
+#D First we load some packages and set some constants.
+
+use Tk ;
+use Tk::ROText ;
+use Config ;
+
+use strict;
+
+use subs qw/ update_setup / ;
+
+my $dosish = ($Config{'osname'} =~ /dos|win/i) ;
+my $default_size = $dosish ? 9 : 12 ;
+
+my $textfont = "Courier $default_size " ;
+my $userfont = "Courier $default_size italic" ;
+my $buttonfont = "Helvetica $default_size bold " ;
+
+unless ($dosish)
+ { $textfont = "-adobe-courier-bold-r-normal--$default_size-120-75-75-m-70-iso8859-1" ;
+ $userfont = "-adobe-courier-bold-o-normal--$default_size-120-75-75-m-70-iso8859-1" ;
+ $buttonfont = "-adobe-helvetica-bold-r-normal--$default_size-120-75-75-p-69-iso8859-1" }
+
+my $s_vertical = 30 ;
+my $s_horizontal = 72 ;
+my $c_horizontal = 24 ;
+
+#D The main window is not resizable, but the text area and
+#D command list will have scrollbars.
+
+my %lw ; # stack of lists
+
+my $mw = MainWindow -> new ( -title => 'ConTeXt commands' ) ;
+
+$mw -> withdraw() ; $mw -> resizable ('y', 'y') ;
+
+sub SetupWindow { return $mw } ;
+
+my $bw = $mw -> Frame () ; # buttons
+my $tw = $mw -> Frame () ; # sw + fw
+my $fw = $tw -> Frame () ; # string + list
+
+my $request = $fw -> Entry ( -font => $textfont ,
+ -background => 'ivory1' ,
+ -width => $c_horizontal ) ;
+
+my $cw = $fw -> Scrolled ( 'Listbox' ,
+ -scrollbars => 'e' ,
+ -font => $textfont ,
+ -width => $c_horizontal ,
+ -selectbackground => 'gray' ,
+ -background => 'ivory1' ,
+ -selectmode => 'browse' ) ;
+
+$cw -> pack ( -side => 'bottom' , -fill => 'both' , -expand => 1 ) ;
+$request -> pack ( -side => 'top' , -fill => 'x' ) ;
+
+my $sw = $tw -> Scrolled ( 'ROText' ,
+ -scrollbars => 'se' ,
+ -height => $s_vertical ,
+ -width => $s_horizontal ,
+ -wrap => 'none' ,
+ -background => 'ivory1' ,
+ -font => $textfont ) ;
+
+
+#D And the whole bunch of widgets are packed in the main
+#D window.
+
+sub pack_them_all
+ { $sw -> pack ( -side => 'left' , -fill => 'both' , -expand => 1 ) ;
+ $fw -> pack ( -side => 'right' , -fill => 'y' , -expand => 0 ) ;
+ $bw -> pack ( -side => 'top' , -fill => 'x' , -anchor => 'w' , -expand => 1 ) ;
+ $tw -> pack ( -side => 'bottom', -fill => 'both' , -expand => 1 ) }
+
+sub unpack_them_all
+ { }
+
+pack_them_all ;
+
+#D We scan for available setup files, with suffix \type {tws}.
+#D These should be somewhere on the system, grouped in one
+#D directory. At least the english file \type {cont-en.tws}
+#D should be found.
+
+my $tws_path = '' ;
+my @setup_files = ('cont-en.tws') ;
+my $setup_file = $setup_files[0] ;
+my $setup_interface = 'en' ;
+my $old_setup_file = '' ;
+
+sub set_setup_interface
+ { $setup_interface = shift }
+
+sub set_setup_title
+ { $mw -> configure ( -title => shift ) }
+
+sub setups_found
+ { $tws_path = `kpsewhich --format="other text files" --progname=context cont-en.tws` ;
+ $tws_path =~ s/cont-en\.tws.*// ;
+ chop $tws_path ;
+ @setup_files = glob ("$tws_path*.tws") ;
+ if (@setup_files)
+ { foreach (@setup_files) { s/\.tws// ; s/.*\/// }
+ $setup_file = $setup_files[0] ;
+ return 1 }
+ else
+ { return 0 } }
+
+#D A hide button
+
+sub show_hide_button
+ { my $hb = $bw -> Button ( -text => "hide" ,
+ -font => $buttonfont ,
+ -command => \&hide_widget ) ;
+ $hb -> pack ( -padx => '2p',
+ -pady => '2p',
+ -side => 'right' ) }
+
+sub hide_widget
+ { $mw -> withdraw() }
+
+#D The setup files can be shown and chosen.
+
+sub show_setups
+ { unpack_them_all ;
+ foreach (@setup_files)
+ { $lw{$_} = $bw -> Radiobutton ( -text => lc $_ ,
+ -value => $_ ,
+ -font => $buttonfont ,
+ -selectcolor => 'ivory1' ,
+ -indicatoron => 0 ,
+ -command => \&change_setup ,
+ -variable => \$setup_file ) ;
+ $lw{$_} -> pack ( -padx => '2p',
+ -pady => '2p',
+ -side => 'left' ) }
+ pack_them_all }
+
+$cw -> bind ('<B1-Motion>', \&update_setup ) ;
+$cw -> bind ('<1>' , \&update_setup ) ;
+$cw -> bind ('<Key>' , \&update_setup ) ;
+
+$sw -> tag ('configure', 'user' , -font => $userfont ) ;
+$sw -> tag ('configure', 'command' , -foreground => 'green3' ) ;
+$sw -> tag ('configure', 'variable' , -font => $userfont ) ;
+$sw -> tag ('configure', 'default' , -underline => 1 ) ;
+$sw -> tag ('configure', 'symbol' , -foreground => 'blue3' ) ;
+$sw -> tag ('configure', 'or' , -foreground => 'yellow3' ) ;
+$sw -> tag ('configure', 'argument' , -foreground => 'red3' ) ;
+$sw -> tag ('configure', 'par' , -lmargin1 => '4m' ,
+ -lmargin2 => '6m' ) ;
+
+my %setups ;
+my %commands ;
+my %loadedsetups ;
+my %positions ;
+my %crosslinks ;
+
+my $current_setup = '' ;
+
+#D Setups are organized in files called \type {*.tws} and
+#D alike. Several files can be loaded simultaneously. When
+#D loading, we grab whole paragraphs. The variables and values
+#D belonging to a command, are stored in the hash table \type
+#D {setups}, one per language. The command templates are
+#D stored in \type {commands}.
+#D
+#D A \type {tws} file is generated by \CONTEXT\ from the setup
+#D definition files. Only \CONTEXT\ knows the current meaning
+#D of commands and keywords. The files are generating by
+#D simply saying something like:
+#D
+#D \starttypen
+#D texexec --interface=en setupd
+#D texexec --interface=de setupd
+#D texexec --interface=nl setupd
+#D texexec --interface=cz setupd
+#D texexec --interface=it setupd
+#D \stoptypen
+#D
+#D This results in files formatted as:
+#D
+#D \starttypen
+#D startsetup
+#D com:setupcolors
+#D typ:vars/
+#D var:state:start,stop,global,local:
+#D var:conversion:yes,no,always:
+#D var:reduction:yes,no:
+#D var:rgb:yes,no:
+#D var:cmyk:yes,no:
+#D stopsetup
+#D \stoptypen
+#D
+#D This format can be stored rather efficient and parsed rather
+#D fast. What more do we need.
+
+sub load_setup
+ { my $filename = shift ;
+ unless (keys %{$commands{$filename}})
+ { local $/ = 'stopsetup' ; # in plaats van '' ivm unix ; (taco)
+ $current_setup = '' ;
+ if (open(SETUP, "$tws_path$filename.tws" ))
+ { my $position = 0 ;
+ while (<SETUP>)
+ { chomp ;
+ s/startsetup//mso ;
+ s/stopsetup//mso ; # redundant geworden
+ s/\r\n //gms ; # in plaats van s/ //gms ; (taco)
+ s/com\:(.*?)\:\s(.*)//mso ;
+ my $string = $1 ;
+ my $command = $1 ;
+ my $setup = $2 ;
+ ++$position ;
+ $string =~ s/(.*?)\<\<(.*?)\>\>(.*?)/$1$2$3/o ;
+ $setups {$filename}{$string} = $setup ;
+ $commands {$filename}{$string} = $command ;
+ $positions {$filename}{$string} = $position ;
+ $crosslinks{$filename}[$position] = $string }
+ close (SETUP) } }
+ my @list = sort {lc $a cmp lc $b} keys %{$commands{$filename}} ;
+ $cw -> delete ('0.0', 'end') ;
+ $cw -> insert ('end', @list) ;
+ $cw -> selectionSet ('0.0', '0.0') ;
+ $cw -> activate ('0.0') ;
+ $setup_file = $filename ;
+ update_setup }
+
+sub load_setups
+ { foreach my $setup (@setup_files) { load_setup ($setup) } ;
+ $mw -> deiconify() }
+
+#D The core of this module deals with transforming the
+#D definitions like shown earlier. Details on the format
+#D can be found in the file \type {setupd.tex}. We use the
+#D \type {Tk::Text} automatic hanging identation features.
+#D The next subs are examples of the kind you write once
+#D and never look at again.
+
+my @arguments = () ;
+my $nested_setup = 0 ;
+my $continue_setup = 0 ;
+my $argument = 0 ;
+my $stopsuffix = '' ;
+my $stopcommand = '' ;
+
+my %arg ;
+
+$arg {repeat} = '//n*/' ;
+$arg {arg} = 'argument/{/.../}' ;
+$arg {args} = 'argument/{/..,...,../}' ;
+$arg {dis} = 'argument/$$/.../$$' ;
+$arg {idx} = 'argument/{/.../}' ;
+$arg {idxs} = 'argument/{/..+...+../}' ;
+$arg {mat} = 'argument/$/...:$' ;
+$arg {nop} = '//.../' ;
+$arg {fil} = '//.../' ;
+$arg {pos} = 'symbol/(/.../)' ;
+$arg {poss} = 'symbol/(/...,.../)' ;
+$arg {sep} = 'command//\\\\/' ;
+$arg {ref} = 'symbol/[/ref/]' ;
+$arg {refs} = 'symbol/[/ref,../]' ;
+$arg {val} = 'symbol/[/.../]' ;
+$arg {vals} = 'symbol/[/..,...,../]' ;
+$arg {var} = 'symbol/[/..=../]' ;
+$arg {vars} = 'symbol/[/..,..=..,../]' ;
+$arg {cmd} = 'command//\cmd/' ;
+$arg {dest} = 'symbol/[/..ref/]' ;
+$arg {dests} = 'symbol/[/..,..refs,../]' ;
+$arg {trip} = 'symbol/[/x:y:z=/]' ;
+$arg {trips} = 'symbol/[/x:y:z=,../]' ;
+$arg {wrd} = 'argument/{/.../}' ;
+$arg {wrds} = 'argument/{/......./}' ;
+$arg {par} = 'command//\par/' ;
+$arg {stp} = '//stop/' ;
+$arg {par} = 'command///' ;
+
+sub show_command
+ { my $command = shift ;
+ local $_ = $commands{$setup_file}{$command} ;
+ if ($command eq $_)
+ { $sw -> insert ('end', "\\$command", 'command' ) }
+ elsif (/(.*?)\<\<(.*?)\>\>(.*?)/o)
+ { $sw -> insert ('end', "\\", 'command' ) ;
+ if ($1) { $sw -> insert ('end', $1, 'command' ) }
+ if ($2) { $sw -> insert ('end', $2, ['command','user'] ) }
+ if ($3) { $sw -> insert ('end', $3, 'command' ) }
+ $stopsuffix = $2 } }
+
+sub show_left_argument
+ { local $_ = shift ;
+ my @thearg = split (/\//, $arg{$arguments[$_]}) ;
+ $sw -> insert ('end', $thearg[1], ['par',$thearg[0]] ) }
+
+sub show_middle_argument
+ { local $_ = shift ;
+ my @thearg = split (/\//, $arg{$arguments[$_]}) ;
+ if ($thearg[1])
+ { $sw -> insert ('end', $thearg[2], 'par' ) }
+ else
+ { $sw -> insert ('end', $thearg[2], ['par',$thearg[0]] ) } }
+
+sub show_right_argument
+ { local $_ = shift ;
+ my @thearg = split (/\//, $arg{$arguments[$_]}) ;
+ $sw -> insert ('end', $thearg[3], ['par',$thearg[0]] ) ;
+ ++$argument }
+
+sub show_reference
+ { if (($nested_setup<=1)&&(defined($arguments[$argument])))
+ { if ($arguments[$argument]=~/ref/)
+ { $sw -> insert ('end', "\n" ) ;
+ show_left_argument ($argument) ;
+ show_middle_argument ($argument) ;
+ show_right_argument ($argument) } } }
+
+sub show_stop_command
+ { my $before_stop = shift ;
+ if ($stopcommand)
+ { if ($stopsuffix)
+ { $sw -> insert ('end', '\\stop', 'command' ) ;
+ $sw -> insert ('end', $stopsuffix, ['command','user'] ) }
+ else
+ { $sw -> insert ('end', $stopcommand, 'command' ) } } }
+
+sub show_whatever_left
+ { while ($argument<@arguments)
+ { $sw -> insert ('end', "\n" ) ;
+ show_left_argument ($argument) ;
+ show_middle_argument ($argument) ;
+ show_right_argument ($argument) ;
+ ++$argument }
+ if ($stopcommand)
+ { $sw -> insert ('end', "\n...\n...\n...\n", 'par') ;
+ show_stop_command } }
+
+sub do_update_setup # type: 0=all 1=vars 2=vals
+ { my ($command, $type) = @_ ;
+ my $setup = $setups{$setup_file}{$command} ;
+ my $default = '' ;
+ my $key = '' ;
+ my $meaning = '' ;
+ my @values = () ;
+ local $_ ;
+ ++$nested_setup ;
+ while ($setup=~/(typ|var|val|ivr|ivl)\:(.*?)\:\s/mgo)
+ { $key = $1 ;
+ $meaning = $2 ;
+ if (($key=~/var/o)&&($type!=2))
+ { $_ = $meaning ; s/(.*?)\:(.*?)\:(.*)//o ;
+ if (($nested_setup>1)&&(!$2)) { next }
+ $key = $1 ;
+ if ($3) { $default = $3 } else { $default = '' }
+ $_= $2 ; s/\s//go ; @values = split (/,/,$_) ;
+ if ($continue_setup)
+ { $sw -> insert ('end', ",\n ", 'par') }
+ else
+ { $continue_setup = 1 ;
+ $sw -> insert ('end', "\n", 'par') ;
+ show_left_argument($argument) }
+ $sw -> insert ('end', $key , 'par' ) ;
+ $sw -> insert ('end', '=', ['symbol','par'] ) ;
+ #while (1)
+ while (@values)
+ { my $value = shift @values ;
+ if ($value =~ /^\*/o)
+ { $value =~ s/^\*//o ;
+ $sw -> insert ('end', lc $value, ['variable','par'] ) }
+ elsif ($value eq $default)
+ { $sw -> insert ('end', $value, ['default','par'] ) }
+ else
+ { $sw -> insert ('end', $value, 'par' ) }
+ if (@values)
+ { $sw -> insert ('end', '|' , ['or','par'] ) }
+ else
+ { last } } }
+ elsif (($key=~/val/o)&&($type!=1))
+ { $_ = $meaning ; s/(.*)\:(.*)//o ;
+ if (($nested_setup>1)&&(!$2)) { next }
+ $_ = $1 ; s/\s//go ; @values = split (/,/,$_) ;
+ if ($2) { $default = $2 } else { $default = '' }
+ if ($continue_setup)
+ { $continue_setup = 0 ;
+ show_right_argument($argument) }
+ $sw -> insert ('end', "\n" , 'par') ;
+ show_left_argument($argument) ;
+ #while (1)
+ while (@values)
+ { unless (@values) { last }
+ my $value = shift (@values) ;
+ if ($value =~ /^\*/o)
+ { $value =~ s/^\*//o ;
+ $sw -> insert ('end', lc $value, ['variable','par'] ) }
+ elsif ($value eq $default)
+ { $sw -> insert ('end', $value, ['default','par'] ) }
+ else
+ { $sw -> insert ('end', $value, 'par' ) }
+ if (@values)
+ { $sw -> insert ('end', ', ', 'par' ) }
+ else
+ { last } }
+ show_right_argument($argument) }
+ elsif ($key=~/typ/o)
+ { if ($nested_setup==1)
+ { show_command ($command) ;
+ my $arguments = $meaning ;
+ if ($arguments=~/stp/)
+ { $_ = $command ;
+ s/start(.*)/$1/o ;
+ $stopcommand = "\\stop$_" ;
+ $arguments =~ s/stp//go }
+ @arguments = split (/\//,$arguments) ;
+ if (@arguments)
+ { for (my $i=0;$i<@arguments;$i++)
+ { show_left_argument ($i) ;
+ show_middle_argument ($i) ;
+ show_right_argument ($i) }
+ if ($stopcommand)
+ { $sw -> insert ('end', ' ... ') ;
+ show_stop_command }
+ $sw -> insert ('end', "\n\n") ;
+ show_command ($command) }
+ $argument = 0 ;
+ $continue_setup = 0 } }
+ elsif ($key=~/ivr/o)
+ { $meaning =~ s/(.*)\:(.*)//o ;
+ do_update_setup ($1,1) }
+ elsif ($key=~/ivl/o)
+ { $meaning =~ s/(.*)\:(.*)//o ;
+ do_update_setup ($1,2) }
+ show_reference }
+ --$nested_setup ;
+ if (($continue_setup)&&(!$nested_setup))
+ { show_right_argument ;
+ show_whatever_left } }
+
+#D Now the real work is done, we only have to define a few
+#D housekeeping routines. The next sub adapts the text area
+#D to the current selected command and normally is bound to
+#D the list browsing commands.
+
+sub update_setup
+ { $old_setup_file = $setup_file ;
+ if (keys %{$commands{$setup_file}})
+ { my $key ;
+ unless ($cw->curselection)
+ { $cw -> selectionSet('0.0','0.0') }
+ $key = $cw -> get($cw->curselection) ;
+ if ($current_setup ne $key)
+ { $current_setup = $key ;
+ $sw -> delete ('1.0', 'end' ) ;
+ $nested_setup = 0 ;
+ $argument = 0 ;
+ $stopcommand = '' ;
+ $stopsuffix = '' ;
+ do_update_setup ($key,0) ;
+ $mw -> raise ;
+ $mw -> focus } } }
+
+#D In editors we want to provide context sensitive help
+#D information. The next sub first tries to locate the
+#D commands asked for in the setup data currently selected,
+#D and when not found takes a look at all the loaded files.
+
+sub show_setup
+ { my $asked_for = shift ;
+ unless ($asked_for) { return }
+ my $found = 0 ;
+ $asked_for =~ s/^\\// ;
+ if ($setup_interface)
+ { $found = 0 ;
+ foreach my $name (@setup_files)
+ { if (($name=~/\-$setup_interface/)&&(exists($commands{$name}{$asked_for})))
+ { $found = 1 ;
+ $setup_file = $name ;
+ last } } }
+ if (!($found)&&(exists($commands{$setup_file}{$asked_for})))
+ { $found = 1 }
+ else
+ { $found = 0 ;
+ foreach my $name (@setup_files)
+ { if (exists($commands{$name}{$asked_for}))
+ { $found = 1 ;
+ $setup_file = $name ;
+ last } } }
+ if ($found)
+ { my @list = sort {lc $a cmp lc $b} keys %{$commands{$setup_file}} ;
+ $cw -> delete ('0.0', 'end') ;
+ $cw -> insert ('end', @list) ;
+ $found = 0 ;
+ foreach (@list) { if ($_ eq $asked_for) { last } ++$found }
+ my $index = "$found.0" ;
+ $cw -> selectionSet ($index, $index) ;
+ $cw -> activate ($index) ;
+ $cw -> see ($index) ;
+ update_setup ;
+ $mw -> raise ;
+ $mw -> focus } }
+
+#D Whenever a new set of commands is selected (by means of the
+#D buttons on top the screen) the list and text are to be
+#D updated.
+
+sub change_setup
+ { my $command = '' ;
+ if ($old_setup_file)
+ { unless ($cw->curselection)
+ { $cw -> selectionSet('0.0','0.0') }
+ $command = $cw -> get($cw->curselection) ;
+ my $position = $positions{$old_setup_file}{$command} ;
+ $command = $crosslinks{$setup_file}[$position] }
+ load_setup($setup_file) ;
+ my @list = sort {lc $a cmp lc $b} keys %{$commands{$setup_file}} ;
+ $cw -> delete ('0.0', 'end') ;
+ $cw -> insert ('end', @list) ;
+ if ($command)
+ { show_setup($command) }
+ else
+ { $cw -> selectionClear ('0.0','end') ;
+ $cw -> selectionSet ('0.0', '0.0') ;
+ $cw -> see ('0.0') ;
+ $cw -> activate ('0.0') }
+ update_setup ;
+ $mw -> raise ;
+ $mw -> focus }
+
+#D Sometimes we want to make sure the dat is loaded indeed:
+
+sub setup_found
+ { my $filename = shift ;
+ if (-e "$tws_path$filename.tws")
+ { $setup_file = $filename ;
+ return 1 }
+ else
+ { return 0 } }
+
+#D The next feature is dedicated to Tobias, who suggested
+#D it, and Taco, who saw it as yet another proof of the
+#D speed of \PERL. It's also dedicated to Ton, who needs it
+#D for translating the big manual.
+
+sub handle_request
+ { my $index = $cw -> index('end') ;
+ unless ($index) { return }
+ my $req = $request -> get ;
+ unless ($req) { return }
+ $req =~ s/\\//o ;
+ $req =~ s/\s//go ;
+ $request -> delete('0','end') ;
+ $request -> insert('0',$req) ;
+ unless ($req) { return }
+ my ($l,$c) = split (/\./,$index) ;
+ for (my $i=0;$i<=$l;$i++)
+ { $index = "$i.0" ;
+ my $str = $cw -> get ($index, $index) ;
+ if ($str =~ /^$req/)
+ { $cw -> selectionClear ('0.0','end') ;
+ $cw -> selectionSet ($index, $index) ;
+ $cw -> activate ($index) ;
+ $cw -> see ($index) ;
+ update_setup ;
+ $mw -> raise ;
+ $mw -> focus ;
+ return } } }
+
+$request -> bind ('<Return>', sub { handle_request } ) ;
+
+sub insert_request
+ { my ($self, $chr) = @_ ;
+ if ($self ne $request)
+ { $request -> insert ('end', $chr) }
+ handle_request }
+
+foreach my $chr ('a'..'z','A'..'Z')
+ { $mw -> bind ( "<KeyPress-$chr>", sub { insert_request(shift, $chr) } ) }
+
+$mw -> bind ( "<backslash>", sub { insert_request(shift, "\\") } ) ;
+
+sub delete_request
+ { my $self = shift ;
+ if ($self ne $request)
+ { my $to = $request -> index ('end') ;
+ my $from = $to - 1 ;
+ if ($from<0) { $from = 0 }
+ $request -> delete ($from,$to) }
+ handle_request }
+
+$mw -> bind ( "<BackSpace>", sub { delete_request } ) ;
+
+sub new_request
+ { $request -> delete (0,'end') ;
+ handle_request }
+
+$mw -> bind ( "<space>", sub { new_request } ) ;
+
+#D Just in case:
+
+sub raise_setup
+ { $mw -> raise }
+
+sub dont_exit
+ { $mw -> protocol( 'WM_DELETE_WINDOW' => sub { } ) }
+
+#D An example use is:
+#D
+#D \starttypen
+#D load_setup ("cont-$nl") ;
+#D show_setup ('omlijnd') ;
+#D MainLoop () ;
+#D \stoptypen
+#D
+#D Now everything is done, we return 1:
+
+1 ;
diff --git a/Master/texmf-dist/scripts/context/perl/fdf2tan.pl b/Master/texmf-dist/scripts/context/perl/fdf2tan.pl
new file mode 100644
index 00000000000..c612f9886e1
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/perl/fdf2tan.pl
@@ -0,0 +1,121 @@
+eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $argv:q'
+ if 0;
+
+#D \module
+#D [ file=fdf2tan.pl,
+#D version=2000.02.06,
+#D title=converting \FDF\ annotations,
+#D subtitle=fdf2tan,
+#D author=Hans Hagen,
+#D date=\currentdate,
+#D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+#C
+#C This module is part of the \CONTEXT\ macro||package and is
+#C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+#C details.
+
+#D This is a preliminary version, that will probably be changed
+#D and merged into a more general module.
+
+use Text::Wrap ;
+
+my $filename = $ARGV[0] ; exit if ($filename eq '') ;
+
+$filename =~ s/\..*$//o ;
+
+my $D = "[0-9\-\.]" ;
+my $nn = 0 ;
+
+my %stack ;
+
+sub saveobject
+ { $n = shift ; $str = shift ;
+ if ($n>$max) { $max = $n }
+ if ($str =~ s/\/Type\s+\/Annot\s+\/Subtype\s+\/Text//o)
+ { ++$nn ;
+ $str =~ s/\/Page\s+(\d+)//o ;
+ $page = $1 ; ++$page ;
+ $str =~ s/\/Rect\s+\[\s*(.*?)\s*\]//o ;
+ $rec = $1 ;
+ if ($rec =~ /($D+)\s*($D+)\s*($D+)\s*($D+)/o)
+ { $FDFllx = $1 ; $FDFlly = $2 ; $FDFurx = $3 ; $FDFury = $4 }
+ $X = $FDFllx - $PDFllx ;
+ $Y = $PDFury - $FDFury ;
+ $str =~ s/\/M\s.*$//o ;
+ $str =~ s/\/T\s.*$//o ;
+ $str =~ s/^.*\/Contents\s.*?\(//o ;
+ $str =~ s/\)\s+$//o ;
+ $str =~ s/\\\\r/@@@@@@/o ;
+ $str =~ s/\\r/\n/go;
+ $str =~ s/@@@@@@/\\r/o ;
+ $str =~ s/\\([\<\>\(\)\{\}\\])/$1/go ;
+ $stack{sprintf("test:%3d %3d %3d\n",$page,$Y,$X)} =
+ "\\startFDFcomment[$page]" .
+ sprintf("[%.3f,%.3f]",$X,$Y) .
+ "\n$str\n\\stopFDFcomment\n\n" } }
+
+exit unless (open (PDF,"<$filename.pdf")) ; binmode PDF ;
+exit unless (open (FDF,"<$filename.fdf")) ;
+exit unless (open (TAN,">$filename.tan")) ;
+
+print "processing $filename ... " ;
+
+$PDFllx = 0 ; $PDFlly = 0 ; $PDFurx = 597 ; $PDFury = 847 ;
+
+while (<PDF>)
+ { if (/\/MediaBox\s*\[\s*($D+)\s*($D+)\s*($D+)\s*($D+)/o)
+ { $PDFllx = $1 ; $PDFlly = $2 ; $PDFurx = $3 ; $PDFury = $4 ;
+ last } }
+
+$_ = "" ; while ($Line=<FDF>) { chomp $Line; $_ .= $Line }
+
+s/\\n/ /go ;
+s/\\\s//go ;
+
+s/\\225/\\\/L/go ; s/\\226/\\OE/go ; s/\\227/\\vS/go ;
+s/\\230/\\"Y/go ; s/\\231/\\vZ/go ; s/\\233/\\\/l/go ;
+s/\\234/\\oe/go ; s/\\235/\\vs/go ; s/\\236/\\vz/go ;
+s/\\253/\\<</go ; s/\\273/\\>>/go ; s/\\300/\\`A/go ;
+s/\\301/\\'A/go ; s/\\302/\\^A/go ; s/\\303/\\~A/go ;
+s/\\304/\\"A/go ; s/\\305/\\oA/go ; s/\\306/\\AE/go ;
+s/\\307/\\,C/go ; s/\\310/\\`E/go ; s/\\311/\\'E/go ;
+s/\\312/\\^E/go ; s/\\313/\\"E/go ; s/\\314/\\`I/go ;
+s/\\315/\\'I/go ; s/\\316/\\^I/go ; s/\\317/\\"I/go ;
+s/\\321/\\~N/go ; s/\\322/\\`O/go ; s/\\323/\\'O/go ;
+s/\\324/\\^O/go ; s/\\325/\\~O/go ; s/\\326/\\"O/go ;
+s/\\330/\\\/O/go ; s/\\331/\\`U/go ; s/\\332/\\'U/go ;
+s/\\333/\\^U/go ; s/\\334/\\"U/go ; s/\\335/\\'Y/go ;
+s/\\337/\\SS/go ; s/\\340/\\`a/go ; s/\\341/\\'a/go ;
+s/\\342/\\^a/go ; s/\\343/\\~a/go ; s/\\344/\\"a/go ;
+s/\\345/\\oa/go ; s/\\346/\\ae/go ; s/\\347/\\,c/go ;
+s/\\350/\\`e/go ; s/\\351/\\'e/go ; s/\\352/\\^e/go ;
+s/\\353/\\"e/go ; s/\\354/\\`i/go ; s/\\355/\\'i/go ;
+s/\\356/\\^i/go ; s/\\357/\\"i/go ; s/\\361/\\~n/go ;
+s/\\362/\\`o/go ; s/\\363/\\'o/go ; s/\\364/\\^o/go ;
+s/\\365/\\~o/go ; s/\\366/\\"o/go ; s/\\370/\\\/o/go ;
+s/\\371/\\`u/go ; s/\\372/\\'u/go ; s/\\373/\\^u/go ;
+s/\\374/\\"u/go ; s/\\375/\\'y/go ; s/\\377/\\"y/go ;
+
+s/\\(\d\d\d)/[$1]/go ;
+
+while (s/(\d+)(\s+\d+\s+obj)(.*?)endobj/saveobject($1,$3)/goe) { }
+
+$wrap::columns = 80 ;
+
+foreach $key (sort keys %stack)
+ { print TAN wrap("","",$stack{$key}) }
+
+close (PDF) ; close (FDF) ; close (TAN) ;
+
+if (open (TAN,">fdf-tan.tex"))
+ { print TAN "% interface=en output=pdftex\n\n" .
+ "\\setupcolors[state=start]\n\n" .
+ "\\setupinteraction[state=start]\n\n" .
+ "\\setupbodyfont[pos,10pt]\n\n" .
+ "\\starttext\n\n" .
+ "\\usemodule[fdfann]\n\n" .
+ "\\annotatepages[$filename]\n\n" .
+ "\\stoptext\n" ;
+ close (TAN) }
+
+print "$nn annotations found, run 'texexec fdf-tan'\n" ;
diff --git a/Master/texmf-dist/scripts/context/perl/fdf2tex.pl b/Master/texmf-dist/scripts/context/perl/fdf2tex.pl
new file mode 100644
index 00000000000..f9684cd9f21
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/perl/fdf2tex.pl
@@ -0,0 +1,213 @@
+eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $argv:q'
+ if 0;
+
+# not yet public
+
+# We're dealing with:
+
+$InpFile = $ARGV[0] ; $OutFile = $ARGV[1] ; $Field = $ARGV[2] ;
+
+# beware: fields are funny sorted
+
+$Program = "fdf2tex 1.02 - ConTeXt / PRAGMA 1997-2000" ;
+
+if ($Field eq "")
+ { print "\n$Program\n\n" }
+
+# filter \type{filename.fdf} into \type{filename.fdt}
+
+unless ($OutFile)
+ { $OutFile = $InpFile ;
+ $OutFile =~ s/\..*// }
+
+unless ($InpFile=~/\./)
+ { if (-e "$InpFile.fdf")
+ { $InpFile .= ".fdf" }
+ elsif (-e "$InpFile.xml")
+ { $InpFile .= ".xml" } }
+
+unless ($OutFile=~/\./)
+ { $OutFile .= ".fdt" }
+
+if (open (FDF, "<$InpFile"))
+ { binmode FDF ;
+ open (FDT, ">$OutFile") ;
+ if ($Field eq "")
+ { print " input file : $InpFile\n" ;
+ print " output file : $OutFile\n" } }
+else
+ { if ($Field eq "")
+ { print " error : $InpFile not found\n" }
+ exit }
+
+# load the whole file in the buffer
+
+$_ = "" ; while ($Line=<FDF>) { chomp $Line; $_ .= $Line }
+
+# or faster: dan ///s gebruiken (ipv m)
+
+# $/ = "\0777" ; $_ = <FDF> ;
+
+# zoom in on the objects and remove the header and trialer
+
+if ($InpFile =~ /\.xml$/)
+
+{ # begin kind of xml alternative
+
+s/\>\s*\</\>\</goms ;
+$N = s/\<field\s+(.*?)\/\>/\\FDFfield\[$1\]\n/goms ;
+s/(name|value)\=\"(.*?)\"/$1=\{$2\}/goms ;
+s/\} (name|value)/\}\,$1/goms ;
+s/\<fdfobject\>(.*?)\<\/fdfobject\>/\\beginFDFobject\n$1\\endFDFobject\n/goms ;
+s/\<fdfdata\>(.*?)\<\/fdfdata\>/\\beginFDFdata\n$1\\endFDFdata\n/goms ;
+s/\<fdffields\>(.*?)\<\/fdffields\>/\\beginFDFfields\n$1\\endFDFfields\n/goms ;
+
+} # end kind of xml alternative
+
+else
+
+{ # begin fdf alternative
+
+s/.*?obj\s*?<<(.*?)>>\s*?endobj/\n\\beginFDFobject$1\n\\endFDFobject/go;
+s/trailer.*//;
+
+# zoom in on the FDF data
+
+s/\/FDF.*?<<(.*)>>/\n\\beginFDFdata$1\n\\endFDFdata/go;
+
+# zoom in on the Field collection and remove whatever else
+
+s/\/Fields.*?\[.*?<<.*?(.*).*?>>.*?\]/\n\\beginFDFfields<<$1>>\n\\endFDFfields/go;
+s/\\endFDFfields.*\n\\endFDFdata/\\endFDFfields\n\\endFDFdata/go;
+
+# tag each field
+
+$N = s/\<<(.*?)>>/\n\\FDFfield[$1]/go;
+
+# remove non relevant entries, but keep \type{/T} and \type{/V}
+
+s/\s*?\/[Kids|Opt]\s*?<<.*?>>//go;
+s/\s*?\/[Ff|setFf|ClrFf|F|SetF|ClrF]\s*?\d*?//go;
+s/\s*?\/[AP|A|AS]\s*?\[.*?\]//go;
+s/\s*?\/AS\s*?\/.*?\s//go;
+
+# format the field identifier
+
+s/(.*?)\/T.*?\((.*?)\)/$1 name=$2,/go;
+
+# format the value, which can be a name or string
+
+s/\/V\s?\((.*?)\)/value=\{$1\},/go;
+s/\/V\s?\/(.*?)[\s|\/]/value=\{$1\},/go;
+
+# sanitize some special \TeX\ tokens
+
+s/(\#|\$|\&|\^|\_|\|)/\\$1/go;
+
+# remove spaces and commas
+
+#s/\s?([name|value])/$1/go;
+s/\[\s*/\[/go;
+s/,\]/\]/go;
+
+# convert PDFDocEncoding
+
+s/\\225/\\\/L/ ;
+s/\\226/\\OE/ ;
+s/\\227/\\vS/ ;
+s/\\230/\\"Y/ ;
+s/\\231/\\vZ/ ;
+s/\\233/\\\/l/ ;
+s/\\234/\\oe/ ;
+s/\\235/\\vs/ ;
+s/\\236/\\vz/ ;
+s/\\253/\\<</ ;
+s/\\273/\\>>/ ;
+s/\\300/\\`A/ ;
+s/\\301/\\'A/ ;
+s/\\302/\\^A/ ;
+s/\\303/\\~A/ ;
+s/\\304/\\"A/ ;
+s/\\305/\\oA/ ;
+s/\\306/\\AE/ ;
+s/\\307/\\,C/ ;
+s/\\310/\\`E/ ;
+s/\\311/\\'E/ ;
+s/\\312/\\^E/ ;
+s/\\313/\\"E/ ;
+s/\\314/\\`I/ ;
+s/\\315/\\'I/ ;
+s/\\316/\\^I/ ;
+s/\\317/\\"I/ ;
+s/\\321/\\~N/ ;
+s/\\322/\\`O/ ;
+s/\\323/\\'O/ ;
+s/\\324/\\^O/ ;
+s/\\325/\\~O/ ;
+s/\\326/\\"O/ ;
+s/\\330/\\\/O/ ;
+s/\\331/\\`U/ ;
+s/\\332/\\'U/ ;
+s/\\333/\\^U/ ;
+s/\\334/\\"U/ ;
+s/\\335/\\'Y/ ;
+s/\\337/\\ss/ ;
+s/\\340/\\`a/ ;
+s/\\341/\\'a/ ;
+s/\\342/\\^a/ ;
+s/\\343/\\~a/ ;
+s/\\344/\\"a/ ;
+s/\\345/\\oa/ ;
+s/\\346/\\ae/ ;
+s/\\347/\\,c/ ;
+s/\\350/\\`e/ ;
+s/\\351/\\'e/ ;
+s/\\352/\\^e/ ;
+s/\\353/\\"e/ ;
+s/\\354/\\`i/ ;
+s/\\355/\\'i/ ;
+s/\\356/\\^i/ ;
+s/\\357/\\"i/ ;
+s/\\361/\\~n/ ;
+s/\\362/\\`o/ ;
+s/\\363/\\'o/ ;
+s/\\364/\\^o/ ;
+s/\\365/\\~o/ ;
+s/\\366/\\"o/ ;
+s/\\370/\\\/o/ ;
+s/\\371/\\`u/ ;
+s/\\372/\\'u/ ;
+s/\\373/\\^u/ ;
+s/\\374/\\"u/ ;
+s/\\375/\\'y/ ;
+s/\\377/\\"y/ ;
+
+s/\\\</\</ ;
+s/\\\>/\>/ ;
+s/\\\(/\(/ ;
+s/\\\)/\)/ ;
+s/\#/\\#/ ;
+
+# convert newline and return commands
+
+s/\\n/ /go;
+s/\\r/\\par /go;
+
+} # end fdf alternative
+
+# flush buffer
+
+print FDT $_ ;
+
+close FDT ;
+close FDF ;
+
+# report some characteristics
+
+if ($Field eq "")
+ { print " number of fields : $N\n" }
+else
+ { if (/\\FDFfield\[value\=\{(.*)\}\,\s*name=$Field/mos)
+ { print "$1" }
+ elsif (/\\FDFfield\[name=$Field\,\s*value\=\{(.*)\}/mos)
+ { print "$1" } }
diff --git a/Master/texmf-dist/scripts/context/perl/makempy.pl b/Master/texmf-dist/scripts/context/perl/makempy.pl
new file mode 100644
index 00000000000..49fd9bbd21a
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/perl/makempy.pl
@@ -0,0 +1,365 @@
+eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $argv:q'
+ if 0;
+
+#D \module
+#D [ file=makempy.pl,
+#D version=2000.12.14,
+#D title=\METAFUN,
+#D subtitle=\METAPOST\ Text Graphics,
+#D author=Hans Hagen,
+#D date=\currentdate,
+#D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+#C
+#C This module is part of the \CONTEXT\ macro||package and is
+#C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+#C details.
+
+# Tobias Burnus provided the code needed to proper testing
+# 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.
+
+# todo: we can nowadays do without the intermediate step, because GS
+# can now handle PDF quite good
+
+use Getopt::Long ;
+use Config ;
+use strict ;
+
+$Getopt::Long::passthrough = 1 ; # no error message
+$Getopt::Long::autoabbrev = 1 ; # partial switch accepted
+
+my $help = 0 ;
+my $silent = 0 ;
+my $force = 0 ;
+my $noclean = 0 ;
+
+my $amethod = my $pmethod = my $gmethod = 0 ;
+
+my $format = "plain" ; # can be "context" for plain users too
+
+&GetOptions
+ ( "help" => \$help ,
+ "silent" => \$silent ,
+ "force" => \$force ,
+ "pdftops" => \$pmethod ,
+ "xpdf" => \$pmethod ,
+# "acrobat" => \$amethod , # nowadays the reader is not that clear about this being permitted
+ "reader" => \$amethod ,
+ "gs" => \$gmethod ,
+ "ghostscript" => \$gmethod ,
+ "noclean" => \$noclean ) ;
+
+my $mpochecksum = 0 ;
+
+my %tex ; my %start ; my %stop ;
+
+$tex{plain} = "pdftex" ;
+$tex{latex} = "pdflatex" ;
+$tex{context} = "texexec --batch --once --interface=en --pdf" ;
+
+$start{plain} = '' ;
+$stop{plain} = '\end' ;
+
+$start{latex} = '\begin{document}' ;
+$stop{latex} = '\end{document}' ;
+
+$start{context} = '\starttext' ;
+$stop{context} = '\stoptext' ;
+
+my $ghostscript = "" ;
+my $pstoedit = "" ;
+my $pdftops = "" ;
+my $acroread = "" ;
+
+my $wereondos = ($Config{'osname'} =~ /dos|mswin/io) ;
+
+# Unix only: assume that "gs" in the path. We could also
+# use $ghostscipt = system "which gs" but this would require
+# that which is installedd on the system.
+
+sub checkenv
+ { my ($var, $env) = @_ ;
+ if ($var)
+ { return $var }
+ elsif ($ENV{$env})
+ { return $ENV{$env} }
+ else
+ { return $var } }
+
+$ghostscript = checkenv ($ghostscript, "GS_PROG" ) ;
+$ghostscript = checkenv ($ghostscript, "GS" ) ;
+$pstoedit = checkenv ($pstoedit , "PSTOEDIT") ;
+$pdftops = checkenv ($pdftops , "PDFTOPS" ) ;
+$acroread = checkenv ($acroread , "ACROREAD") ;
+
+sub setenv
+ { my ($var, $unix, $win) = @_ ;
+ if ($var)
+ { return $var }
+ elsif ($wereondos)
+ { return $win }
+ else
+ { return $unix } }
+
+$ghostscript = setenv($ghostscript, "gs" , "gswin32c") ;
+$pstoedit = setenv($pstoedit , "pstoedit", "pstoedit") ;
+$pdftops = setenv($pdftops , "pdftops" , "pdftops" ) ;
+$acroread = setenv($acroread , "acroread", "" ) ;
+
+# Force a method if unknown.
+
+unless ($pmethod||$amethod||$gmethod)
+ { if ($wereondos) { $pmethod = 1 } else { $amethod = 1 } }
+
+# Set the error redirection used under Unix:
+# stderr -> stdout
+
+my $logredirection = '>>' ;
+
+# This unfortunally doesn't work with the ksh and simple sh
+#
+# if (!$wereondos)
+# { $logredirection = '2>&1 >>' ; # Bash
+# $logredirection = '>>&' ; # tcsh, Bash
+# default $logredirection. }
+
+# Some TeX Code Snippets.
+
+my $macros = '
+
+% auxiliary macros
+
+\input supp-mis.tex
+
+\def\startTEXpage[scale=#1]%
+ {\output{}
+ \batchmode
+ \pdfoutput=1
+ \pdfcompresslevel=9
+ \hoffset=-1in
+ \voffset=\hoffset
+ \scratchcounter=#1
+ \divide\scratchcounter1000
+ \edef\TEXscale{\the\scratchcounter\space}
+ \forgetall
+ \setbox0=\vbox\bgroup}
+
+\def\stopTEXpage
+ {\egroup
+ \dimen0=\ht0 \advance\dimen0 \dp0
+ \setbox2=\vbox to 10\dimen0
+ {\pdfliteral{\TEXscale 0 0 \TEXscale 0 0 cm}
+ \copy0
+ \pdfliteral{1 0 0 1 0 0 cm}
+ \vfill}
+ \wd2=10\wd0
+ \pdfpageheight=\ht2
+ \pdfpagewidth=\wd2
+ \ScaledPointsToBigPoints{\number\pdfpageheight}\pdfcropheight
+ \ScaledPointsToBigPoints{\number\pdfpagewidth }\pdfcropwidth
+ \expanded{\pdfpageattr{/CropBox [0 0 \pdfcropwidth \space \pdfcropheight]}}
+ \shipout\hbox{\box2}}
+
+% end of auxiliary macros' ;
+
+sub report
+ { return if $silent ;
+ my $str = shift ;
+ if ($str =~ /(.*?)\s+([\:\/])\s+(.*)/o)
+ { if ($1 eq "") { $str = " " } else { $str = $2 }
+ print sprintf("%22s $str %s\n",$1,$3) } }
+
+sub error
+ { report("processing aborted : " . shift) ;
+ exit }
+
+sub process
+ { report("generating : " . shift) }
+
+sub banner
+ { return if $silent ;
+ print "\n" ;
+ report ("MakeMPY 1.1 - MetaFun / PRAGMA ADE 2000-2004") ;
+ print "\n" }
+
+my $metfile = "" ; # main metapost file
+my $mpofile = "" ; # metapost text specifiation file (provided)
+my $mpyfile = "" ; # metapost text picture file (generated)
+my $texfile = "" ; # temporary tex file
+my $pdffile = "" ; # temporary pdf file
+my $tmpfile = "" ; # temporary metapost file
+my $posfile = "" ; # temporary postscript file
+my $logfile = "" ; # temporary log file
+my $errfile = "" ; # final log file (with suffix log)
+
+sub show_help_info
+ { banner ;
+ report ("--help : this message" ) ;
+ report ("--noclean : don't remove temporary files" ) ;
+ report ("--force : force processing (ignore checksum)" ) ;
+ report ("--silent : don't show messages" ) ;
+ print "\n" ;
+ report ("--acrobat : use acrobat (reader) for pdf->ps (on unix)") ;
+ report ("--pdftops : use pdftops (xpdf) pdf->ps") ;
+ report ("--ghostscript : use ghostscript (gs) for pdf->ps") ;
+ print "\n" ;
+ report ("input file : metapost file with graphics") ;
+ report ("programs needed : texexec and english context") ;
+ report (" : pdftops from the xpdf suite, or") ; # page size buggy
+ report (" : pdf2ps and ghostscript, or") ;
+ report (" : acrobat reader for unix, and") ;
+ report (" : pstoedit and ghostscript") ;
+ report ("output file : metapost file with pictures") ;
+ exit }
+
+sub check_input_file
+ { my $file = $ARGV[0] ;
+ if ((!defined($file))||($file eq ""))
+ { banner ; error("no filename given") }
+ else
+ { $file =~ s/\.mp.*$//o ;
+ $metfile = "$file.mp" ;
+ $mpofile = "$file.mpo" ;
+ $mpyfile = "$file.mpy" ;
+ $logfile = "$file.log" ;
+ $texfile = "mpy-$file.tex" ;
+ $pdffile = "mpy-$file.pdf" ;
+ $posfile = "mpy-$file.pos" ;
+ $tmpfile = "mpy-$file.tmp" ;
+ $errfile = "mpy-$file.log" ;
+ if (! -f $metfile)
+ { banner ; error("$metfile is empty") }
+ elsif (-s $mpofile < 32)
+ { unlink $mpofile ; # may exist with zero length
+ unlink $mpyfile ; # get rid of left overs
+ exit }
+ else
+ { banner ; report("processing file : $mpofile") } } }
+
+sub verify_check_sum # checksum calculation from perl documentation
+ { return unless (open (MPO,"$mpofile")) ;
+ $mpochecksum = do { local $/ ; unpack("%32C*",<MPO>) % 65535 } ;
+ close (MPO) ;
+ return unless open (MPY,"$mpyfile") ;
+ my $str = <MPY> ; chomp $str ;
+ close (MPY) ;
+ if ($str =~ /^\%\s*mpochecksum\s*\:\s*(\d+)/o)
+ { if ($mpochecksum eq $1)
+ { report("mpo checksum : $mpochecksum / unchanged") ;
+ exit unless $force }
+ else
+ { report("mpo checksum : $mpochecksum / changed") } } }
+
+sub cleanup_files
+ { my @files = <mpy-*.*> ;
+ foreach (@files) { unless (/\.log/o) { unlink $_ } } }
+
+sub construct_tex_file
+ { my $n = 0 ;
+ unless (open (MPO, "<$mpofile"))
+ { error("unable to open $mpofile") }
+ unless (open (TEX, ">$texfile"))
+ { error("unable to open $texfile") }
+ my $textext = "" ;
+ while (<MPO>)
+ { s/\s*$//mois ;
+ if (/\%\s*format=(\w+)/)
+ { $format = $1 }
+ else # if (!/^\%/)
+ { if (/startTEXpage/o)
+ { ++$n ;
+ $textext .= "$start{$format}\n" ;
+ $start{$format} = "" }
+ $textext .= "$_\n" } }
+ unless (defined($tex{$format})) { $format = "plain" }
+ if ($format eq "context") { $macros = "" }
+ # print TEX "$start{$format}\n$macros\n$textext\n$stop{$format}\n" ;
+ print TEX "$start{$format}\n\n" if $start{$format} ;
+ print TEX "$macros\n" if $macros ;
+ print TEX "$textext\n" if $textext ;
+ print TEX "$stop{$format}\n" if $stop{$format} ;
+ close (MPO) ;
+ close (TEX) ;
+ report("tex format : $format") ;
+ report("requested texts : $n") }
+
+sub construct_mpy_file
+ { unless (open (TMP, "<$tmpfile"))
+ { error("unable to open $tmpfile file") }
+ unless (open (MPY, ">$mpyfile"))
+ { error("unable to open $mpyfile file") }
+ print MPY "% mpochecksum : $mpochecksum\n" ;
+ my $copying = my $n = 0 ;
+ while (<TMP>)
+ { if (s/beginfig/begingraphictextfig/o)
+ { print MPY $_ ; $copying = 1 ; ++$n }
+ elsif (s/endfig/endgraphictextfig/o)
+ { print MPY $_ ; $copying = 0 }
+ elsif ($copying)
+ { print MPY $_ } }
+ close (TMP) ;
+ close (MPY) ;
+ report("processed texts : $n") ;
+ report("produced file : $mpyfile") }
+
+sub run
+ { my ($resultfile, $program,$arguments) = @_ ;
+ my $result = system("$program $arguments $logredirection $logfile") ;
+ unless (-f $resultfile) { error("invalid `$program' run") } }
+
+sub make_pdf_pages
+ { process ("pdf file") ;
+ run ($pdffile, "$tex{$format}", "$texfile") }
+
+sub make_mp_figures
+ { process ("postscript file") ;
+ if ($pmethod) { run($posfile, "$pdftops",
+ "-paper match $pdffile $posfile") }
+ if ($gmethod) { run($posfile, "$ghostscript",
+ "-q -sOutputFile=$posfile -dNOPAUSE -dBATCH -dSAFER -sDEVICE=pswrite $pdffile") }
+ if ($amethod) { run($posfile, "$acroread",
+ "-toPostScript -pairs $pdffile $posfile") } }
+
+sub make_mp_pictures_ps
+ { process ("metapost file") ;
+ run ($tmpfile, "$pstoedit", "-ssp -dt -f mpost $posfile $tmpfile") }
+
+sub make_mp_pictures_pdf
+ { process ("metapost file") ;
+ run ($tmpfile, "$pstoedit", "-ssp -dt -f mpost $pdffile $tmpfile") }
+
+if ($help) { show_help_info }
+
+check_input_file ;
+verify_check_sum ;
+cleanup_files ;
+construct_tex_file ;
+make_pdf_pages ;
+if (1)
+ { make_mp_pictures_pdf ; }
+else
+ { make_mp_figures ;
+ make_mp_pictures_ps ; }
+construct_mpy_file ; # less save : rename $tmpfile, $mpyfile ;
+unless ($noclean) { cleanup_files }
+
+# a simple test file (needs context)
+#
+# % output=pdftex
+#
+# \starttext
+#
+# \startMPpage
+# graphictext
+# "\bf MAKE"
+# scaled 8
+# zscaled (1,2)
+# withdrawcolor \MPcolor{blue}
+# withfillcolor \MPcolor{gray}
+# withpen pencircle scaled 5pt ;
+# \stopMPpage
+#
+# \stoptext
diff --git a/Master/texmf-dist/scripts/context/perl/mptopdf.pl b/Master/texmf-dist/scripts/context/perl/mptopdf.pl
new file mode 100644
index 00000000000..efbc5ba0122
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/perl/mptopdf.pl
@@ -0,0 +1,123 @@
+eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $argv:q'
+ if 0;
+
+# MikTeX users can set environment variable TEXSYSTEM to "miktex".
+
+#D \module
+#D [ file=mptopdf.pl,
+#D version=2005.10.31,
+#D title=converting MP to PDF,
+#D subtitle=\MPTOPDF,
+#D author=Hans Hagen,
+#D date=\currentdate,
+#D url=www.pragma-ade.nl,
+#D copyright={PRAGMA ADE / Hans Hagen \& Ton Otten}]
+#C
+#C This module is part of the \CONTEXT\ macro||package and is
+#C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+#C details.
+
+# use File::Copy ; # not in every perl
+
+use Config ;
+use Getopt::Long ;
+use strict ;
+
+$Getopt::Long::passthrough = 1 ; # no error message
+$Getopt::Long::autoabbrev = 1 ; # partial switch accepted
+
+my $Help = my $Latex = my $RawMP = my $MetaFun = 0 ;
+my $PassOn = '' ;
+
+&GetOptions
+ ( "help" => \$Help ,
+ "rawmp" => \$RawMP,
+ "metafun" => \$MetaFun,
+ "passon" => \$PassOn,
+ "latex" => \$Latex ) ;
+
+my $program = "MPtoPDF 1.3" ;
+my $pattern = $ARGV[0] ;
+my $done = 0 ;
+my $report = '' ;
+my $texlatexswitch = " --tex=latex --format=latex " ;
+my $mplatexswitch = " --tex=latex " ;
+
+my $dosish = ($Config{'osname'} =~ /^(ms)?dos|^os\/2|^(ms|cyg)win/i) ;
+my $miktex = ($ENV{"TEXSYSTEM"} =~ /miktex/io);
+my $escapeshell = ( ($ENV{'SHELL'}) && ($ENV{'SHELL'} =~ m/sh/i ));
+
+my @files ;
+my $command = my $mpbin = '' ;
+
+sub CopyFile # agressive copy, works for open files like in gs
+ { my ($From,$To) = @_ ;
+ return unless open(INP,"<$From") ; binmode INP ;
+ return unless open(OUT,">$To") ; binmode OUT ;
+ while (<INP>) { print OUT $_ }
+ close (INP) ;
+ close (OUT) }
+
+if (($pattern eq '')||($Help))
+ { print "\n$program : provide MP output file (or pattern)\n" ;
+ exit }
+elsif ($pattern =~ /\.mp$/io)
+ { shift @ARGV ; my $rest = join(" ", @ARGV) ;
+ if (open(INP,$pattern))
+ { while (<INP>)
+ { if (/(documentstyle|documentclass|begin\{document\})/io)
+ { $Latex = 1 ; last } }
+ close (INP) }
+ if ($RawMP)
+ { if ($Latex)
+ { $rest .= " $mplatexswitch" }
+ if ($MetaFun) {
+ $mpbin = 'mpost --mem=metafun --progname=mpost' ;
+ } else {
+ $mpbin = 'mpost --mem=mpost' ;
+ }
+ }
+ else
+ { if ($Latex)
+ { $rest .= " $texlatexswitch" }
+ $mpbin = 'texexec --mptex $PassOn' }
+ my $error = system ("$mpbin $rest $pattern") ;
+ if ($error)
+ { print "\n$program : error while processing mp file\n" ; exit }
+ else
+ { $pattern =~ s/\.mp$//io ;
+ @files = glob "$pattern.*" } }
+elsif (-e $pattern)
+ { @files = ($pattern) }
+elsif ($pattern =~ /.\../o)
+ { @files = glob "$pattern" }
+else
+ { $pattern .= '.*' ;
+ @files = glob "$pattern" }
+
+foreach my $file (@files)
+ { $_ = $file ;
+ if (s/\.(\d+|mps)$// && -e $file)
+ { if ($miktex)
+ { $command = "pdfetex -undump=mptopdf" }
+ else
+ { $command = "pdfetex --fmt=mptopdf --progname=context" }
+ if ($dosish)
+ { $command = "$command \\relax $file" }
+ else
+ { $command = "$command \\\\relax $file" }
+ #~ print $command ;
+ system($command) ;
+ rename ("$_.pdf", "$_-$1.pdf") ;
+ if (-e "$_.pdf") { CopyFile ("$_.pdf", "$_-$1.pdf") }
+ if ($done) { $report .= " +" }
+ $report .= " $_-$1.pdf" ;
+ ++$done } }
+
+if ($report eq '')
+ { $report = '*' }
+
+if ($done)
+ { print "\n$program : $pattern is converted to$report\n" }
+else
+ { print "\n$program : no filename matches $pattern\n" }
diff --git a/Master/texmf-dist/scripts/context/perl/path_tre.pm b/Master/texmf-dist/scripts/context/perl/path_tre.pm
new file mode 100644
index 00000000000..546afcd27b6
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/perl/path_tre.pm
@@ -0,0 +1,36 @@
+#D \module
+#D [ file=path\_tre.pm,
+#D version=1999.05.05,
+#D title=Path modules,
+#D subtitle=selecting a path,
+#D author=Hans Hagen,
+#D date=\currentdate,
+#D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+#C
+#C This module is part of the \CONTEXT\ macro||package and is
+#C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+#C details.
+
+#D Not yet documented, source will be cleaned up.
+
+package Tk::path_tre ;
+
+use Tk;
+require Tk::DirTree ;
+
+use base qw(Tk::DirTree);
+use strict;
+
+Construct Tk::Widget 'PathTree';
+
+sub ClassInit
+ { my ($class,$mw) = @_ ;
+ return $class -> SUPER::ClassInit ($mw) }
+
+sub dirnames
+ { my ( $w, $dir ) = @_ ;
+ unless ($dir=~/\//) { $dir .= '/' }
+ my @names = $w->Callback("-dircmd", $dir, $w->cget("-showhidden"));
+ return( @names ) }
+
+__END__
diff --git a/Master/texmf-dist/scripts/context/perl/texexec.pl b/Master/texmf-dist/scripts/context/perl/texexec.pl
new file mode 100644
index 00000000000..2f3b89e0461
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/perl/texexec.pl
@@ -0,0 +1,3252 @@
+eval '(exit $?0)' && eval 'exec perl -w -S $0 ${1+"$@"}' && eval 'exec perl -w -S $0 $argv:q'
+ if 0 ;
+
+#D \module
+#D [ file=texexec.pl,
+#D version=2004.08.29,
+#D title=running \ConTeXt,
+#D subtitle=\TEXEXEC,
+#D author=Hans Hagen,
+#D date=\currentdate,
+#D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+#C
+#C This module is part of the \CONTEXT\ macro||package and is
+#C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+#C details.
+
+# Thanks to Tobias Burnus for the german translations.
+# Thanks to Thomas Esser for hooking it into web2c
+# Thanks to Taco Hoekwater for suggesting improvements
+# Thanks to Wybo Dekker for the advanced help interface and making it strict
+# Thanks to Fabrice Popineau for windows path trickery and fixes
+
+# (I still have to completely understand the help code -)
+
+#D We started with a hack provided by Thomas Esser. This
+#D expression replaces the unix specific line \type
+#D {#!/usr/bin/perl}.
+
+#D History has learned that writing wrappers like this is quite painful
+#D because of differences between platforms, changes in the tex command
+#D line flags (fmt), default behaviour (e.g. 8 bit), and the assumption
+#D that everyone runs the same tex and that distributers take care of
+#D everything. Well, the result is a messy script like this ... Sorry.
+
+use strict ;
+
+my $OriginalArgs = join(' ',@ARGV) ;
+
+#~ use warnings ; # strange warnings, todo
+
+# todo: second run of checksum of mp file with --nomprun changes
+# todo: warning if no args
+# todo: <<<< in messages
+# todo: cleanup
+
+use Cwd;
+use Time::Local;
+use Config;
+use Getopt::Long;
+use Class::Struct; # needed for help subsystem
+use FindBin;
+use File::Compare;
+use File::Temp;
+use Digest::MD5;
+
+#~ use IO::Handle; autoflush STDOUT 1;
+
+my %ConTeXtInterfaces; # otherwise problems with strict
+my %ResponseInterface; # since i dunno how to allocate else
+
+my %Help;
+
+#D In this script we will launch some programs and other
+#D scripts. \TEXEXEC\ uses an ini||file to sort out where
+#D those programs are stored. Two boolean variables keep
+#D track of the way to call the programs. In \TEXEXEC,
+#D \type {$dosish} keeps track of the operating system.
+#D It will be no surprise that Thomas Esser provided me
+#D the neccessary code to accomplish this.
+
+$ENV{"MPXCOMMAND"} = "0"; # otherwise loop
+
+my $TotalTime = time;
+
+# start random seed hack
+#
+# This hack is needed since tex has 1 minute resolution, so
+# we need to be smaller about 1440 (== 24*60 == tex's max time)
+# in which case (david a's) random calculator will overflow.
+
+# my ( $sec, $min, $rest ) = gmtime;
+# my $RandomSeed = $min * 60 + $sec;
+#
+# # i have to look up the mod function -)
+#
+# if ( $RandomSeed > 2880 ) { $RandomSeed -= 2880 }
+# if ( $RandomSeed > 1440 ) { $RandomSeed -= 1440 }
+
+my ($sec, $min) = gmtime;
+my $RandomSeed = ($min * 60 + $sec) % 2880; # else still overflow
+
+# See usage of $Random and $RandomSeed later on.
+#
+# end random seed hack
+
+my $dosish = ( $Config{'osname'} =~ /^(ms)?dos|^os\/2|^mswin/i );
+my $escapeshell = ( ($ENV{'SHELL'}) && ($ENV{'SHELL'} =~ m/sh/i ));
+
+my $TeXUtil = 'texutil';
+my $TeXExec = 'texexec';
+my $MetaFun = 'metafun';
+my $MpToPdf = 'mptopdf';
+
+$Getopt::Long::passthrough = 1; # no error message
+$Getopt::Long::autoabbrev = 1; # partial switch accepted
+
+my $AddEmpty = '';
+my $Alone = 0;
+my $Optimize = 0;
+my $ForceTeXutil = 0;
+my $Arrange = 0;
+my $BackSpace = '0pt';
+my $Background = '';
+my $CenterPage = 0;
+my $ConTeXtInterface = 'unknown';
+my $Convert = '';
+my $DoMPTeX = 0;
+my $DoMPXTeX = 0;
+my $EnterBatchMode = 0;
+my $EnterNonStopMode = 0;
+my $Environments = '';
+my $Modules = '';
+my $FastMode = 0;
+my $FinalMode = 0;
+my $Format = '';
+my $MpDoFormat = '';
+my $HelpAsked = 0;
+my $Version = 0;
+my $MainBodyFont = 'standard';
+my $MainLanguage = 'standard';
+my $MainResponse = 'standard';
+my $MakeFormats = 0;
+my $Markings = 0;
+my $Mode = '';
+my $NoArrange = 0;
+my $NoDuplex = 0;
+my $NOfRuns = 8;
+my $NoMPMode = 0;
+my $NoMPRun = 0;
+my $NoBanner = 0;
+my $AutoMPRun = 0;
+my $OutputFormat = 'standard';
+my $Pages = '';
+my $PageScale = '1000'; # == 1.0
+my $PaperFormat = 'standard';
+my $PaperOffset = '0pt';
+my $PassOn = '';
+my $PdfArrange = 0;
+my $PdfSelect = 0;
+my $PdfCombine = 0;
+my $PdfOpen = 0;
+my $PdfClose = 0;
+my $AutoPdf = 0;
+my $PrintFormat = 'standard';
+my $ProducePdfT = 0;
+my $ProducePdfM = 0;
+my $ProducePdfX = 0;
+my $ProducePdfXTX = 0;
+my $ProducePs = 0;
+my $Input = "";
+my $Result = '';
+my $Suffix = '';
+my $RunOnce = 0;
+my $Selection = '';
+my $Combination = '2*4';
+my $SilentMode = 0;
+my $TeXProgram = '';
+my $TeXTranslation = '';
+my $TextWidth = '0pt';
+my $TopSpace = '0pt';
+my $TypesetFigures = 0;
+my $ForceFullScreen = 0;
+my $ScreenSaver = 0;
+my $TypesetListing = 0;
+my $TypesetModule = 0;
+my $UseColor = 0;
+my $Verbose = 0;
+my $PdfCopy = 0;
+my $PdfTrim = 0;
+my $LogFile = "";
+my $MpyForce = 0;
+my $InpPath = "";
+my $AutoPath = 0;
+my $RunPath = "";
+my $Arguments = "";
+my $Pretty = 0;
+my $SetFile = "";
+my $TeXTree = "";
+my $TeXRoot = "";
+my $Purge = 0;
+my $Separation = "";
+my $ModeFile = "";
+my $GlobalFile = 0;
+my $AllPatterns = 0;
+my $ForceXML = 0;
+my $Random = 0;
+my $Filters = '';
+my $NoMapFiles = 0 ;
+my $Foxet = 0 ;
+my $TheEnginePath = 0 ;
+my $Paranoid = 0 ;
+my $NotParanoid = 0 ;
+my $BoxType = '' ;
+my $Local = '' ;
+
+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 = '';
+
+&GetOptions(
+ "arrange" => \$Arrange,
+ "batch" => \$EnterBatchMode,
+ "nonstop" => \$EnterNonStopMode,
+ "color" => \$UseColor,
+ "centerpage" => \$CenterPage,
+ "convert=s" => \$Convert,
+ "environments=s" => \$Environments,
+ "usemodules=s" => \$Modules,
+ "xml" => \$ForceXML,
+ "xmlfilters=s" => \$Filters,
+ "fast" => \$FastMode,
+ "final" => \$FinalMode,
+ "format=s" => \$Format,
+ "mpformat=s" => \$MpDoFormat,
+ "help" => \$HelpAsked,
+ "version" => \$Version,
+ "interface=s" => \$ConTeXtInterface,
+ "language=s" => \$MainLanguage,
+ "bodyfont=s" => \$MainBodyFont,
+ "results=s" => \$Result,
+ "response=s" => \$MainResponse,
+ "make" => \$MakeFormats,
+ "mode=s" => \$Mode,
+ "module" => \$TypesetModule,
+ "figures=s" => \$TypesetFigures,
+ "fullscreen" => \$ForceFullScreen,
+ "screensaver" => \$ScreenSaver,
+ "listing" => \$TypesetListing,
+ "mptex" => \$DoMPTeX,
+ "mpxtex" => \$DoMPXTeX,
+ "noarrange" => \$NoArrange,
+ "nomp" => \$NoMPMode,
+ "nomprun" => \$NoMPRun,
+ "nobanner" => \$NoBanner,
+ "automprun" => \$AutoMPRun,
+ "once" => \$RunOnce,
+ "output=s" => \$OutputFormat,
+ "pages=s" => \$Pages,
+ "paperformat=s" => \$PaperFormat,
+ "passon=s" => \$PassOn,
+ "path=s" => \$InpPath,
+ "autopath" => \$AutoPath,
+ "pdf" => \$ProducePdfT,
+ "pdm" => \$ProducePdfM,
+ "dpm" => \$ProducePdfM,
+ "pdx" => \$ProducePdfX,
+ "dpx" => \$ProducePdfX,
+ "xtx" => \$ProducePdfXTX,
+ "ps" => \$ProducePs,
+ "pdfarrange" => \$PdfArrange,
+ "pdfselect" => \$PdfSelect,
+ "pdfcombine" => \$PdfCombine,
+ "pdfcopy" => \$PdfCopy,
+ "pdftrim" => \$PdfTrim,
+ "scale=s" => \$PageScale,
+ "selection=s" => \$Selection,
+ "combination=s" => \$Combination,
+ "noduplex" => \$NoDuplex,
+ "paperoffset=s" => \$PaperOffset,
+ "backspace=s" => \$BackSpace,
+ "topspace=s" => \$TopSpace,
+ "markings" => \$Markings,
+ "textwidth=s" => \$TextWidth,
+ "addempty=s" => \$AddEmpty,
+ "background=s" => \$Background,
+ "logfile=s" => \$LogFile,
+ "print=s" => \$PrintFormat,
+ "suffix=s" => \$Suffix,
+ "runs=s" => \$NOfRuns,
+ "silent" => \$SilentMode,
+ "tex=s" => \$TeXProgram,
+ "verbose" => \$Verbose,
+ "alone" => \$Alone,
+ "optimize" => \$Optimize,
+ "texutil" => \$ForceTeXutil,
+ "mpyforce" => \$MpyForce,
+ "input=s" => \$Input,
+ "arguments=s" => \$Arguments,
+ "pretty" => \$Pretty,
+ "setfile=s" => \$SetFile, # obsolete
+ "purge" => \$Purge,
+ #### yet undocumented #################
+ "runpath=s" => \$RunPath,
+ "random" => \$Random,
+ "makempy=s" => \$MakeMpy,
+ "allpatterns" => \$AllPatterns,
+ "separation=s" => \$Separation,
+ "textree=s" => \$TeXTree,
+ "texroot=s" => \$TeXRoot,
+ "translate=s" => \$TeXTranslation,
+ "pdfclose" => \$PdfClose,
+ "pdfopen" => \$PdfOpen,
+ "autopdf" => \$AutoPdf,
+ "modefile=s" => \$ModeFile, # additional modes file
+ "globalfile" => \$GlobalFile,
+ "nomapfiles" => \$NoMapFiles,
+ "foxet" => \$Foxet,
+ "engine" => \$TheEnginePath,
+ "paranoid" => \$Paranoid,
+ "notparanoid" => \$NotParanoid,
+ "boxtype=s" => \$BoxType, # media art crop bleed trim
+ "local" => \$Local,
+ #### unix is unsafe (symlink viruses)
+ "tempdir=s" => \$TempDir,
+ #### experiment
+ "startline=s" => \$StartLine,
+ "startcolumn=s" => \$StartColumn,
+ "endline=s" => \$EndLine,
+ "endcolumn=s" => \$EndColumn
+); # don't check name
+
+if ($Foxet) {
+ $ProducePdfT = 1 ;
+ $ForceXML = 1 ;
+ $Modules = "foxet" ;
+ $Purge = 1 ;
+}
+
+# a set file (like blabla.bat) can set paths now
+
+if ( $SetFile ne "" ) { load_set_file( $SetFile, $Verbose ); $SetFile = "" }
+
+# later we will do a second attempt.
+
+$SIG{INT} = "IGNORE";
+
+if ( $ARGV[0] && $ARGV[0] =~ /\.mpx$/io ) { # catch -tex=.... bug in mpost
+ $TeXProgram = '';
+ $DoMPXTeX = 1;
+ $NoMPMode = 1;
+}
+
+####
+
+if ($Paranoid) {
+ $ENV{shell_escape} = 'f' ;
+ $ENV{openout_any} = 'p' ;
+ $ENV{openin_any} = 'p' ;
+} elsif ($NotParanoid) {
+ $ENV{shell_escape} = 't' ;
+ $ENV{openout_any} = 'p' ;
+ $ENV{openin_any} = 'a' ;
+}
+
+if (defined $ENV{openin_any} && $ENV{openin_any} eq 'p') {
+ $Paranoid = 1 ; # extra test in order to set readlevel
+}
+
+if ((defined $ENV{shell_escape} && $ENV{shell_escape} eq 'f') ||
+ (defined $ENV{SHELL_ESCAPE} && $ENV{SHELL_ESCAPE} eq 'f')) {
+ $AutoMPRun = 1 ;
+}
+
+if ($ScreenSaver) {
+ $ForceFullScreen = 1;
+ $TypesetFigures = 'c';
+ $ProducePdfT = 1;
+ $Purge = 1;
+}
+
+if ( $DoMPTeX || $DoMPXTeX ) {
+ $RunOnce = 1;
+ $ProducePdfT = 0;
+ $ProducePdfX = 0;
+ $ProducePdfM = 0;
+ $ProducePdfXTX = 0;
+ $ProducePs = 0;
+}
+
+if ( $PdfArrange || $PdfSelect || $PdfCopy || $PdfTrim || $PdfCombine ) {
+ $ProducePdfT = 1;
+ $RunOnce = 1;
+}
+
+if ($ProducePdfT) { $OutputFormat = "pdftex" }
+elsif ($ProducePdfM) { $OutputFormat = "dvipdfm" }
+elsif ($ProducePdfX) { $OutputFormat = "dvipdfmx" }
+elsif ($ProducePdfXTX) { $OutputFormat = "xetex" }
+elsif ($ProducePs) { $OutputFormat = "dvips" }
+
+if ( $ProducePdfXTX ) {
+ $TeXProgram = 'xetex' ; # ignore the default pdfetex engine
+ $PassOn .= ' -no-pdf ' ; # Adam Lindsay's preference
+}
+
+if ($AutoPdf) {
+ $PdfOpen = $PdfClose = 1 ;
+}
+
+# this is our hook into paranoid path extensions, assumes that
+# these three vars are part of path specs in texmf.cnf
+
+foreach my $i ('TXRESOURCES','MPRESOURCES','MFRESOURCES') {
+ foreach my $j ($RunPath,$InpPath) {
+ if ($j ne '') {
+ if ($ENV{$i} ne '') {
+ $ENV{$i} = $ENV{$i} . ',' . $j ;
+ } else {
+ $ENV{$i} = $j ;
+ }
+ }
+ }
+}
+
+if ( $RunOnce || $Pages || $TypesetFigures || $TypesetListing ) { $NOfRuns = 1 }
+
+if ( ( $LogFile ne '' ) && ( $LogFile =~ /\w+\.log$/io ) ) {
+ open( LOGFILE, ">$LogFile" );
+ *STDOUT = *LOGFILE;
+ *STDERR = *LOGFILE;
+}
+
+my $Program = " TeXExec 5.4.3 - ConTeXt / PRAGMA ADE 1997-2005";
+
+print "\n$Program\n\n";
+
+if ($Verbose) { print " current path : " . cwd . "\n" }
+
+my $pathslash = '/';
+if ( $FindBin::Bin =~ /\\/ ) { $pathslash = "\\" }
+my $cur_path = ".$pathslash";
+
+# we need to handle window's "Program Files" path (patch by Fabrice P)
+
+my $own_path = "$FindBin::Bin/";
+my $own_type = $FindBin::Script;
+my $own_quote = ( $own_path =~ m/^[^\"].* / ? "\"" : "" );
+my $own_stub = "";
+
+if ( $own_type =~ /(\.pl|perl)/oi ) { $own_stub = "perl " }
+
+if ( $own_type =~ /(\.(pl|bin|exe))$/io ) { $own_type = $1 }
+else { $own_type = '' }
+
+sub checked_path {
+ my $path = shift;
+ if ( ( defined($path) ) && ( $path ne '' ) ) {
+ $path =~ s/[\/\\]/$pathslash/go;
+ $path =~ s/[\/\\]*$//go;
+ $path .= $pathslash;
+ } else {
+ $path = '';
+ }
+ return $path;
+}
+
+sub checked_file {
+ my $path = shift;
+ if ( ( defined($path) ) && ( $path ne '' ) ) {
+ $path =~ s/[\/\\]/$pathslash/go;
+ } else {
+ $path = '';
+ }
+ return $path;
+}
+
+sub CheckPath {
+ my ( $Key, $Value ) = @_;
+ if ( ( $Value =~ /\// ) && ( $Value !~ /\;/ ) ) # no multipath test yet
+ {
+ $Value = checked_path($Value);
+ unless ( -d $Value ) {
+ print " error : $Key set to unknown path $Value\n";
+ }
+ }
+}
+
+# set <variable> to <value>
+# for <script> set <variable> to <value>
+# except for <script> set <variable> to <value>
+
+my $IniPath = '';
+
+#D The kpsewhich program is not available in all tex distributions, so
+#D we have to locate it before running it (as suggested by Thomas).
+
+my @paths;
+
+if ( $ENV{PATH} =~ /\;/ ) { @paths = split( /\;/, $ENV{PATH} ) }
+else { @paths = split( /\:/, $ENV{PATH} ) }
+
+my $kpsewhich = '';
+
+sub found_ini_file {
+ my $suffix = shift ;
+ #~ $IniPath = $0 ;
+ #~ $IniPath ~= s/\.pl$//io ;
+ #~ $IniPath = $InPath . ".'" + $suffix ;
+ #~ if (-e $IniPath) {
+ #~ }
+ # not really needed to check on texmfscripts, better on own path
+ print " locating ini file : kpsewhiching texexec.$suffix on scripts\n" if $Verbose ;
+ my $IniPath = `$kpsewhich --format="texmfscripts" -progname=context texexec.$suffix` ;
+ chomp($IniPath) ;
+ if ($IniPath eq '') {
+ print " locating ini file : kpsewhiching texexec.$suffix elsewhere\n" if $Verbose ;
+ $IniPath = `$kpsewhich --format="other text files" -progname=context texexec.$suffix` ;
+ chomp($IniPath) ;
+ }
+ return $IniPath ;
+}
+
+if ( $IniPath eq '' ) {
+ foreach (@paths) {
+ my $p = checked_path($_) . 'kpsewhich';
+ if ( ( -e $p ) || ( -e $p . '.exe' ) ) {
+ $kpsewhich = $p;
+ # FP: catch spurious error messages here if there $p has
+ # spaces and $own_quote is not set
+ $kpsewhich = ($kpsewhich =~ m/^[^\"].* / ? "\"$kpsewhich\"" : "$kpsewhich") ;
+ $IniPath = found_ini_file("ini");
+ unless ( -e $IniPath ) { $IniPath = found_ini_file("rme") }
+ last;
+ }
+ }
+ if ($Verbose) {
+ if ( $kpsewhich eq '' ) {
+ print " locating ini file : kpsewhich not found in path\n";
+ } elsif ( $IniPath eq '' ) {
+ print " locating ini file : not found by kpsewhich\n";
+ } else {
+ if ( $IniPath =~ /rme/oi ) {
+ print " locating ini file : not found by kpsewhich, using '.rme' file\n";
+ } else {
+ print " locating ini file : found by kpsewhich\n";
+ }
+ }
+ }
+}
+
+#D Now, when we didn't find the \type {kpsewhich}, we have
+#D to revert to some other method. We could have said:
+#D
+#D \starttypen
+#D unless ($IniPath)
+#D { $IniPath = `perl texpath.pl texexec.ini` }
+#D \stoptypen
+#D
+#D But loading perl (for the second time) take some time. Instead of
+#D providing a module, which can introduce problems with loading, I
+#D decided to copy the code of \type {texpath} into this file.
+
+use File::Find;
+# use File::Copy ; no standard in perl
+
+my ( $ReportPath, $ReportName, $ReportFile ) = ( 0, 0, 1 );
+my ( $FileToLocate, $PathToStartOn ) = ( '', '' );
+my ( $LocatedPath, $LocatedName, $LocatedFile ) = ( '', '', '' );
+
+sub DoLocateFile { # we have to keep on pruning
+ if ( lc $_ eq $FileToLocate ) {
+ $LocatedPath = $File::Find::dir;
+ $LocatedName = $_;
+ $LocatedFile = $File::Find::name;
+ }
+ if ($LocatedName) { $File::Find::prune = 1 }
+}
+
+sub LocatedFile {
+ $PathToStartOn = shift;
+ $FileToLocate = lc shift;
+ if ( $FileToLocate eq '' ) {
+ $FileToLocate = $PathToStartOn;
+ $PathToStartOn = $own_path;
+ }
+ ( $LocatedPath, $LocatedName, $LocatedFile ) = ( '', '', '' );
+ if ( $FileToLocate ne '' ) {
+ if ( -e $cur_path . $FileToLocate ) {
+ $LocatedPath = $cur_path;
+ $LocatedName = $FileToLocate;
+ $LocatedFile = $cur_path . $FileToLocate;
+ } else {
+ $_ = checked_path($PathToStartOn);
+ if ( -e $_ . $FileToLocate ) {
+ $LocatedPath = $_;
+ $LocatedName = $FileToLocate;
+ $LocatedFile = $_ . $FileToLocate;
+ } else {
+ $_ = checked_path($PathToStartOn);
+ if (/(.*?[\/\\]texmf[\/\\]).*/i) {
+ my $SavedRoot = $1;
+ File::Find::find( \&DoLocateFile,
+ checked_path( $1 . 'context/' ) );
+ unless ($LocatedFile) {
+ File::Find::find( \&DoLocateFile, $SavedRoot );
+ }
+ } else {
+ $_ = checked_path($_);
+ File::Find::find( \&DoLocateFile, $_ );
+ }
+ }
+ }
+ }
+ return ( $LocatedPath, $LocatedName, $LocatedFile );
+}
+
+#D So now we can say:
+
+unless ($IniPath) {
+ ( $LocatedPath, $LocatedName, $IniPath ) =
+ LocatedFile( $own_path, 'texexec.ini' );
+ if ($Verbose) {
+ if ( $IniPath eq '' ) {
+ print " locating ini file : not found by searching\n";
+ } else {
+ print " locating ini file : found by searching\n";
+ }
+ }
+}
+
+#D The last resorts:
+
+unless ($IniPath) {
+ if ( $ENV{TEXEXEC_INI_FILE} ) {
+ $IniPath = checked_path( $ENV{TEXEXEC_INI_FILE} ) . 'texexec.ini';
+ unless ( -e $IniPath ) { $IniPath = '' }
+ }
+ if ($Verbose) {
+ if ( $IniPath eq '' ) {
+ print " locating ini file : no environment variable set\n";
+ } else {
+ print " locating ini file : found by environment variable\n";
+ }
+ }
+}
+
+unless ($IniPath) {
+ $IniPath = $own_path . 'texexec.ini';
+ unless ( -e $IniPath ) { $IniPath = '' }
+ if ($Verbose) {
+ if ( $IniPath eq '' ) {
+ print " locating ini file : not found in own path\n";
+ } else {
+ print " locating ini file : found in own path\n";
+ }
+ }
+}
+
+#D Now we're ready for loading the initialization file! We
+#D also define some non strict variables. Using \type {$Done}
+#D permits assignments.
+
+my %Done;
+
+unless ($IniPath) { $IniPath = 'texexec.ini' }
+
+if ( open( INI, $IniPath ) ) {
+ if ($Verbose) { print " reading : $IniPath\n" }
+ while (<INI>) {
+ if ( !/^[a-zA-Z\s]/oi ) { }
+ elsif (/except for\s+(\S+)\s+set\s+(\S+)\s*to\s*(.*)\s*/goi) {
+ my $one = $1;
+ my $two = $2;
+ my $three = $3;
+ if ( $one ne $Done{"TeXShell"} ) {
+ $three =~ s/^[\'\"]//o;
+ $three =~ s/[\'\"]$//o;
+ $three =~ s/\s*$//o;
+ if ($Verbose) {
+ print " setting : '$two' to '$three' except for '$one'\n";
+ }
+ $Done{"$two"} = $three;
+ CheckPath( $two, $three );
+ }
+ } elsif (/for\s+(\S+)\s+set\s+(\S+)\s*to\s*(.*)\s*/goi) {
+ my $one = $1;
+ my $two = $2;
+ my $three = $3;
+ $three =~ s/\s*$//o;
+ if ( $one eq $Done{"TeXShell"} ) {
+ $three =~ s/^[\'\"]//o;
+ $three =~ s/[\'\"]$//o;
+ if ($Verbose) {
+ print
+" setting : '$two' to '$three' for '$one'\n";
+ }
+ $Done{"$two"} = $three;
+ CheckPath( $two, $three );
+ }
+ } elsif (/set\s+(\S+)\s*to\s*(.*)\s*/goi) {
+ my $one = $1;
+ my $two = $2;
+ unless ( defined( $Done{"$one"} ) ) {
+ $two =~ s/^[\'\"]//o;
+ $two =~ s/[\'\"]$//o;
+ $two =~ s/\s*$//o;
+ if ($Verbose) {
+ print
+ " setting : '$one' to '$two' for 'all'\n";
+ }
+ $Done{"$one"} = $two;
+ CheckPath( $one, $two );
+ }
+ }
+ }
+ close(INI);
+ if ($Verbose) { print "\n" }
+} elsif ($Verbose) {
+ print
+ " warning : $IniPath not found, did you read 'texexec.rme'?\n";
+ exit 1;
+} else {
+ print
+ " warning : $IniPath not found, try 'texexec --verbose'\n";
+ exit 1;
+}
+
+sub IniValue {
+ my ( $Key, $Default ) = @_;
+ if ( defined( $Done{$Key} ) ) { $Default = $Done{$Key} }
+ if ($Default =~ /^(true|yes|on)$/io) {
+ $Default = 1 ;
+ } elsif ($Default =~ /^(false|no|off)$/io) {
+ $Default = 0 ;
+ }
+ if ($Verbose) { print " used setting : $Key = $Default\n" }
+ return $Default;
+}
+
+my $TeXShell = IniValue( 'TeXShell', '' );
+my $SetupPath = IniValue( 'SetupPath', '' );
+my $UserInterface = IniValue( 'UserInterface', 'en' );
+my $UsedInterfaces = IniValue( 'UsedInterfaces', 'en' );
+my $TeXFontsPath = IniValue( 'TeXFontsPath', '.' );
+my $MpExecutable = IniValue( 'MpExecutable', 'mpost' );
+my $MpToTeXExecutable = IniValue( 'MpToTeXExecutable', 'mpto' );
+my $DviToMpExecutable = IniValue( 'DviToMpExecutable', 'dvitomp' );
+my $TeXProgramPath = IniValue( 'TeXProgramPath', '' );
+my $TeXFormatPath = IniValue( 'TeXFormatPath', '' );
+my $ConTeXtPath = IniValue( 'ConTeXtPath', '' );
+my $TeXScriptsPath = IniValue( 'TeXScriptsPath', '' );
+my $TeXHashExecutable = IniValue( 'TeXHashExecutable', '' );
+my $TeXExecutable = IniValue( 'TeXExecutable', 'tex' );
+my $TeXVirginFlag = IniValue( 'TeXVirginFlag', '-ini' );
+my $TeXBatchFlag = IniValue( 'TeXBatchFlag', '-interaction=batchmode' );
+my $TeXNonStopFlag = IniValue( 'TeXNonStopFlag', '-interaction=nonstopmode' );
+my $MpBatchFlag = IniValue( 'MpBatchFlag', '-interaction=batchmode' );
+my $MpNonStopFlag = IniValue( 'MpNonStopFlag', '-interaction=nonstopmode' );
+my $TeXPassString = IniValue( 'TeXPassString', '' );
+my $TeXFormatFlag = IniValue( 'TeXFormatFlag', '' );
+my $MpFormatFlag = IniValue( 'MpFormatFlag', '' );
+my $MpVirginFlag = IniValue( 'MpVirginFlag', '-ini' );
+my $MpPassString = IniValue( 'MpPassString', '' );
+my $MpFormat = IniValue( 'MpFormat', $MetaFun );
+my $MpFormatPath = IniValue( 'MpFormatPath', $TeXFormatPath );
+my $UseEnginePath = IniValue( 'UseEnginePath', '');
+
+if ($TheEnginePath) { $UseEnginePath = 1 }
+
+# ok, let's force the engine; let's also forget about
+# fmtutil, since it does not support $engine subpaths
+# we will replace texexec anyway
+
+$UseEnginePath = 1 ;
+$Alone = 1 ;
+
+my $FmtLanguage = IniValue( 'FmtLanguage', '' );
+my $FmtBodyFont = IniValue( 'FmtBodyFont', '' );
+my $FmtResponse = IniValue( 'FmtResponse', '' );
+my $TcXPath = IniValue( 'TcXPath', '' );
+
+
+$SetFile = IniValue( 'SetFile', $SetFile );
+
+if ( ($Verbose) && ( $kpsewhich ne '' ) ) {
+ print "\n";
+ my $CnfFile = `$kpsewhich -progname=context texmf.cnf`;
+ chomp($CnfFile);
+ print " applications will use : $CnfFile\n";
+}
+
+if ( ($FmtLanguage) && ( $MainLanguage eq 'standard' ) ) {
+ $MainLanguage = $FmtLanguage;
+}
+if ( ($FmtBodyFont) && ( $MainBodyFont eq 'standard' ) ) {
+ $MainBodyFont = $FmtBodyFont;
+}
+if ( ($FmtResponse) && ( $MainResponse eq 'standard' ) ) {
+ $MainResponse = $FmtResponse;
+}
+
+# new versions, > 2004 will have -fmt as switch
+
+if ( $TeXFormatFlag eq "" ) {
+ if ($TeXProgram =~ /(etex|pdfetex)/) {
+ $TeXFormatFlag = "-efmt=" ; # >=2004 -fmt=
+ } elsif ($TeXProgram =~ /(eomega)/) {
+ $TeXFormatFlag = "-eoft=" ; # >=2004 obsolete
+ } elsif ($TeXProgram =~ /(aleph)/) {
+ $TeXFormatFlag = "-fmt=" ;
+ } else {
+ $TeXFormatFlag = "-fmt=" ;
+ }
+}
+
+if ( $MpFormatFlag eq "" ) {
+ $MpFormatFlag = "-mem=" ;
+}
+
+if ($TeXProgram) { $TeXExecutable = $TeXProgram }
+
+my $fmtutil = '';
+
+# obsolete
+#
+# if ( $MakeFormats || $Verbose ) {
+# if ($Alone || $UseEnginePath) {
+# if ($Verbose) { print " generating format : not using fmtutil\n" }
+# } elsif ( $TeXShell =~ /tetex|fptex/i ) {
+# foreach (@paths) {
+# my $p = checked_path($_) . 'fmtutil';
+# if ( -e $p ) { $fmtutil = $p; last }
+# elsif ( -e $p . '.exe' ) { $fmtutil = $p . '.exe'; last }
+# }
+# $fmtutil = ($fmtutil =~ m/^[^\"].* / ? "\"$fmtutil\"" : "$fmtutil") ;
+# if ($Verbose) {
+# if ( $fmtutil eq '' ) {
+# print " locating fmtutil : not found in path\n";
+# } else {
+# print " locating fmtutil : $fmtutil\n";
+# }
+# }
+# }
+# }
+
+if ($Verbose) { print "\n" }
+
+unless ($TeXScriptsPath) { $TeXScriptsPath = $own_path }
+
+unless ($ConTeXtPath) { $ConTeXtPath = $TeXScriptsPath }
+
+if ( $ENV{"HOME"} ) {
+ if ($SetupPath) { $SetupPath .= "," }
+# my $home = $ENV{"HOME"};
+# $home = ($home =~ m/^[^\"].* / ? "\"$home\"" : "$home") ;
+# $SetupPath .= $home;
+ $SetupPath .= $ENV{"HOME"};
+}
+
+if ($TeXFormatPath) { $TeXFormatPath =~ s/[\/\\]$//; $TeXFormatPath .= '/' }
+if ($MpFormatPath) { $MpFormatPath =~ s/[\/\\]$//; $MpFormatPath .= '/' }
+if ($ConTeXtPath) { $ConTeXtPath =~ s/[\/\\]$//; $ConTeXtPath .= '/' }
+if ($SetupPath) { $SetupPath =~ s/[\/\\]$//; $SetupPath .= '/' }
+if ($TeXScriptsPath) { $TeXScriptsPath =~ s/[\/\\]$//; $TeXScriptsPath .= '/' }
+
+sub QuotePath {
+ my ($path) = @_;
+ my @l = split(",", $path);
+ map { my $e = $_; $e = ($e =~ m/^[^\"].* / ? "\"$e\"" : "$e"); $_ = $e ;} @l;
+ return join(",", @l);
+}
+
+$SetupPath = &QuotePath($SetupPath);
+
+$SetupPath =~ s/\\/\//go;
+
+my %OutputFormats;
+
+# the mother of all drivers
+
+$OutputFormats{dvips} = "dvips";
+
+# needs an update
+
+$OutputFormats{acrobat} = "acrobat";
+
+# the core drivers
+
+$OutputFormats{pdftex} = "pdftex"; $OutputFormats{pdf} = "pdftex";
+$OutputFormats{dvipdfm} = "dvipdfm"; $OutputFormats{dpm} = "dvipdfm";
+$OutputFormats{dvipdfmx} = "dvipdfmx"; $OutputFormats{dpx} = "dvipdfmx";
+$OutputFormats{xetex} = "xetex"; $OutputFormats{xtx} = "xetex";
+$OutputFormats{dvips} = "dvips"; $OutputFormats{ps} = "dvips";
+
+# kind of obsolete now that yandy is gone
+
+$OutputFormats{dvipsone} = "dvipsone";
+$OutputFormats{dviwindo} = "dviwindo";
+
+# it was never finished
+
+$OutputFormats{dviview} = "dviview";
+
+my @ConTeXtFormats = ( "nl", "en", "de", "cz", "uk", "it", "ro", "xx");
+
+sub SetInterfaces {
+ my ( $short, $long, $full ) = @_;
+ $ConTeXtInterfaces{$short} = $short;
+ $ConTeXtInterfaces{$long} = $short;
+ $ResponseInterface{$short} = $full;
+ $ResponseInterface{$long} = $full;
+}
+
+#SetInterfaces ( "en" , "unknown" , "english" ) ;
+
+SetInterfaces( "nl", "dutch", "dutch" );
+SetInterfaces( "en", "english", "english" );
+SetInterfaces( "de", "german", "german" );
+SetInterfaces( "cz", "czech", "czech" );
+SetInterfaces( "uk", "brittish", "english" );
+SetInterfaces( "it", "italian", "italian" );
+SetInterfaces( "no", "norwegian", "norwegian" );
+SetInterfaces( "ro", "romanian", "romanian" );
+
+# Sub-option
+
+struct Subopt => {
+ desc => '$', # description
+ vals => '%' # assignable values
+};
+
+# Main option
+
+struct Opt => {
+ desc => '$', # desciption
+ vals => '%', # assignable values
+ subs => '%' # suboptions
+};
+
+my $helpdone = 0;
+
+sub print_subopt {
+ my ( $k, $opt ) = @_;
+ $~ = 'H3';
+ write;
+ for $k ( sort keys %{ $opt->vals } ) {
+ print_val( $k, ${ $opt->vals }{$k} );
+ }
+ format H3 =
+@>>>>>>>>>>>>>>>>>>>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+"--$k",$opt->desc
+.
+}
+
+sub print_val {
+ my ( $k, $opt ) = @_;
+ $~ = 'H2';
+ write;
+ format H2 =
+ @<<<<<<<< : @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+$k,$opt
+.
+}
+
+# read all options
+
+my $recurse = -1 ;
+my $shorthelp;
+my @help;
+my @opts = <DATA>;
+while (@opts) {
+ $_ = shift @opts;
+ last if /^--+/;
+ my ( $k, $v ) = split( /\s+/, $_, 2 ); # was \t
+ $Help{$k} = read_options($v);
+}
+
+# read a main option plus its
+# description,
+# assignable values and
+# sub-options and their
+# description and
+# assignable values
+
+sub read_options {
+ $recurse++;
+ my $v = shift;
+ chomp;
+ my $opt = $recurse ? Subopt->new() : Opt->new();
+ $opt->desc($v);
+
+ while (@opts) {
+ $_ = shift @opts;
+ if (/^--+/) { unshift @opts, $_ if $recurse; last }
+ if ( $recurse && !/^=/ ) { unshift @opts, $_; last }
+ chomp;
+ my ( $kk, $vv ) = split( /\s+/, $_, 2 ); # was \t
+ $vv ||= '';
+ if (/^=/) { $opt->vals( $kk, $vv ) }
+ elsif ( !$recurse ) { $opt->subs( $kk, read_options($vv) ) }
+ }
+ $recurse--;
+ $opt;
+}
+
+sub print_opt {
+ my ( $k, $opt ) = @_;
+ if ($helpdone) { $shorthelp or print "\n" }
+ $helpdone = 1; # hh
+ $~ = 'H1';
+ write;
+ return if $shorthelp < 0;
+ for $k ( sort keys %{ $opt->vals } ) {
+ print_val( $k, ${ $opt->vals }{$k} );
+ }
+ return if $shorthelp > 0;
+
+ for $k ( sort keys %{ $opt->subs } ) {
+ print_subopt( $k, ${ $opt->subs }{$k} );
+ }
+ format H1 =
+@>>>>>>>>>>>>>>>>>>>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+"--$k",$opt->desc
+.
+}
+
+# help to help
+
+sub show_help_options {
+ print # "\n" .
+ " --help overview of all options and their values\n"
+ . " --help all all about all options\n"
+ . " --help short just the main options\n"
+ . " --help mode ... pdf all about a few options\n"
+ . " --help '*.pdf' all about options containing 'pdf'\n"
+ . "\n"
+ . " more info http://www.pragma-ade.com/general/manuals/mtexexec.pdf\n"
+ . " http://www.ntg.nl/mailman/listinfo/ntg-context\n";
+}
+
+# determine what user wants to see
+
+if ($HelpAsked) {
+ $shorthelp = 0;
+ @help = ( sort keys %Help );
+ if ( "@ARGV" eq "all" ) { # everything
+ } elsif ( "@ARGV" eq "short" ) { # nearly everything
+ $shorthelp--;
+ } elsif ( "@ARGV" eq "help" ) { # help on help
+ show_help_options;
+ exit;
+ } elsif (@ARGV) { # one or a few options, completely
+ my @h = @ARGV;
+ @help = ();
+ for (@h) { # print "testing $_\n";
+ # next if (/^[\*\?]/) ; # HH, else error
+ if (/^[\*\?]/) { $_ = ".$_" } # HH, else error
+ $Help{$_} and push( @help, $_ ) or do {
+ my $unknown = $_;
+ for ( keys %Help ) { /$unknown/ and push( @help, $_ ) }
+ }
+ }
+ } else { # all main option and their assignable values
+ $shorthelp++;
+ }
+}
+
+sub show_help_info {
+ map { print_opt( $_, $Help{$_} ) } @help;
+}
+
+# uncomment this to see the structure of a Help element:
+# print Dumper($Help{pdfselect});
+
+#### end of help system
+
+my $FinalRunNeeded = 0;
+
+sub MPJobName {
+ my $JobName = shift;
+ my $MPfile = shift;
+ my $MPJobName = '';
+ if ( -e "$JobName-$MPfile.mp" && -s "$JobName-$MPfile.mp" > 100 ) {
+ $MPJobName = "$JobName-$MPfile.mp"
+ } elsif ( -e "$MPfile.mp" && -s "$MPfile.mp" > 100 ) {
+ $MPJobName = "$MPfile.mp"
+ } else { $MPJobName = "" }
+ return $MPJobName;
+}
+
+sub System {
+ my $cmd = shift ;
+ unless ( $dosish && ! $escapeshell ) {
+ $cmd =~ s/([^\\])\&/$1\\\&/io ;
+ }
+ if ($Verbose) {
+ print "\n$cmd\n\n" ;
+ }
+ system($cmd)
+}
+
+sub Pipe {
+ my $cmd = shift ;
+ unless ( $dosish && ! $escapeshell ) {
+ $cmd =~ s/([^\\])\&/$1\\\&/io ;
+ }
+ if ($Verbose) {
+ print "\n$cmd\n\n" ;
+ }
+ return `$cmd`
+}
+
+
+sub RunPerlScript {
+ my ( $ScriptName, $Options ) = @_;
+ my $cmd = '';
+ $own_quote = ($own_path =~ m/^[^\"].* / ? "\"" : "") ;
+ if ($Verbose) {
+ $Options .= ' --verbose' ;
+ }
+ if ($dosish) {
+ if ( -e "own_path$ScriptName$own_type" ) {
+ $cmd =
+"$own_stub$own_quote$own_path$ScriptName$own_type$own_quote $Options";
+ } elsif ( -e "$TeXScriptsPath$ScriptName$own_type" ) {
+ $cmd =
+"$own_stub$own_quote$TeXScriptsPath$ScriptName$own_type$own_quote $Options";
+ } else {
+ $cmd = "";
+ }
+ } else {
+ $cmd = "$ScriptName $Options";
+ }
+ unless ( $cmd eq "" ) {
+ System($cmd) ;
+ }
+}
+
+my $FullFormat = '';
+
+sub CheckOutputFormat {
+ my $Ok = 1;
+ if ( $OutputFormat ne 'standard' ) {
+ my @OutputFormat = split( /,/, $OutputFormat );
+ foreach my $F (@OutputFormat) {
+ if ( defined( $OutputFormats{ lc $F } ) ) {
+ my $OF = $OutputFormats{ lc $F };
+ next if ( ",$FullFormat," =~ /\,$OF\,/ );
+ if ($FullFormat) { $FullFormat .= "," }
+ $FullFormat .= "$OutputFormats{lc $F}";
+ } else {
+ $Ok = 0;
+ }
+ }
+ if ( !$Ok ) {
+ print(" unknown output format : $OutputFormat\n");
+ }
+ }
+ unless ($FullFormat) { $FullFormat = $OutputFormat }
+} # 'standard' to terminal
+
+sub MakeOptionFile {
+ my ( $FinalRun, $FastDisabled, $JobName, $JobSuffix, $KindOfRun ) = @_;
+ open( OPT, ">$JobName.top" );
+ print OPT "\% $JobName.top\n";
+ print OPT "\\unprotect\n";
+ if ($EnterBatchMode) { print OPT "\\batchmode\n" }
+ if ($EnterNonStopMode) { print OPT "\\nonstopmode\n" }
+ if ($Paranoid) {
+ print " paranoid file mode : very true\n";
+ print OPT "\\def\\maxreadlevel{1}\n" ;
+ }
+ $ModeFile =~ s/\\/\//gio ; # do this at top of file
+ $Result =~ s/\\/\//gio ; # do this at top of file
+ if ( $ModeFile ne '' ) { print OPT "\\readlocfile{$ModeFile}{}{}" }
+ if ( $Result ne '' ) { print OPT "\\setupsystem[file=$Result]\n" }
+ elsif ($Suffix) { print OPT "\\setupsystem[file=$JobName$Suffix]\n" }
+ if ( $InpPath ne "" ) {
+ $InpPath =~ s/\\/\//go;
+ $InpPath =~ s/\/$//go;
+ print OPT "\\usepath[$InpPath]\n";
+ }
+ $MainLanguage = lc $MainLanguage;
+ unless ( $MainLanguage eq "standard" ) {
+ print OPT "\\setuplanguage[$MainLanguage]\n";
+ }
+ # can best become : \use...[mik] / [web]
+ if ( $TeXShell =~ /MikTeX/io ) {
+ print OPT "\\def\\MPOSTbatchswitch \{$MpBatchFlag\}";
+ print OPT "\\def\\MPOSTnonstopswitch \{$MpNonStopFlag\}";
+ print OPT "\\def\\MPOSTformatswitch \{$MpPassString $MpFormatFlag\}";
+ }
+ #
+ if ( $FullFormat ne 'standard' ) {
+ print OPT "\\setupoutput[$FullFormat]\n";
+ }
+ if ($UseColor) { print OPT "\\setupcolors[\\c!state=\\v!start]\n" }
+ if ( $NoMPMode || $NoMPRun || $AutoMPRun ) {
+ print OPT "\\runMPgraphicsfalse\n";
+ }
+ if ( ($FastMode) && ( !$FastDisabled ) ) { print OPT "\\fastmode\n" }
+ if ($SilentMode) { print OPT "\\silentmode\n" }
+ if ( $Separation ne "" ) {
+ print OPT "\\setupcolors[\\c!split=$Separation]\n";
+ }
+ if ($SetupPath) { print OPT "\\setupsystem[\\c!directory=\{$SetupPath\}]\n" }
+ print OPT "\\setupsystem[\\c!n=$KindOfRun]\n";
+ $_ = $PaperFormat;
+ #unless (($PdfArrange)||($PdfSelect)||($PdfCombine)||($PdfCopy))
+ unless ( ($PdfSelect) || ($PdfCombine) || ($PdfCopy) || ($PdfTrim) ) {
+ if (/.4.3/goi) {
+ print OPT "\\setuppapersize[A4][A3]\n" ;
+ } elsif (/.5.4/goi) {
+ print OPT "\\setuppapersize[A5][A4]\n" ;
+ } elsif ( !/standard/ ) {
+ s/x/\*/io;
+ if (/\w+\d+/) { $_ = uc $_ }
+ my ( $from, $to ) = split(/\*/);
+ if ( $to eq "" ) { $to = $from }
+ print OPT "\\setuppapersize[$from][$to]\n";
+ }
+ }
+ if ( ( $PdfSelect || $PdfCombine || $PdfCopy || $PdfTrim || $PdfArrange )
+ && ( $Background ne '' ) )
+ {
+ print " background graphic : $Background\n";
+ print OPT "\\defineoverlay[whatever][{\\externalfigure[$Background][\\c!factor=\\v!max]}]\n";
+ print OPT "\\setupbackgrounds[\\v!page][\\c!background=whatever]\n";
+ }
+ if ($CenterPage) {
+ print OPT
+ "\\setuplayout[\\c!location=\\v!middle,\\c!marking=\\v!on]\n";
+ }
+ if ($NoMapFiles) {
+ print OPT "\\disablemapfiles\n";
+ }
+ if ($NoArrange) { print OPT "\\setuparranging[\\v!disable]\n" }
+ elsif ( $Arrange || $PdfArrange ) {
+ $FinalRunNeeded = 1;
+ if ($FinalRun) {
+ my $DupStr;
+ if ($NoDuplex) { $DupStr = "" }
+ else { $DupStr = ",\\v!doublesided" }
+ if ( $PrintFormat eq '' ) {
+ print OPT "\\setuparranging[\\v!normal]\n";
+ } elsif ( $PrintFormat =~ /.*up/goi ) {
+ print OPT "\\setuparranging[2UP,\\v!rotated$DupStr]\n";
+ } elsif ( $PrintFormat =~ /.*down/goi ) {
+ print OPT "\\setuparranging[2DOWN,\\v!rotated$DupStr]\n";
+ } elsif ( $PrintFormat =~ /.*side/goi ) {
+ print OPT "\\setuparranging[2SIDE,\\v!rotated$DupStr]\n";
+ } else {
+ print OPT "\\setuparranging[$PrintFormat]\n";
+ }
+ } else {
+ print OPT "\\setuparranging[\\v!disable]\n";
+ }
+ }
+ if ($Arguments) { print OPT "\\setupenv[$Arguments]\n" }
+ if ($Input) { print OPT "\\setupsystem[inputfile=$Input]\n" }
+ else { print OPT "\\setupsystem[inputfile=$JobName.$JobSuffix]\n" }
+ if ($Random) { print OPT "\\setupsystem[\\c!random=$RandomSeed]\n" }
+ if ($Mode) { print OPT "\\enablemode[$Mode]\n" }
+ if ($Pages) {
+ if ( lc $Pages eq "odd" ) {
+ print OPT "\\chardef\\whichpagetoshipout=1\n";
+ } elsif ( lc $Pages eq "even" ) {
+ print OPT "\\chardef\\whichpagetoshipout=2\n";
+ } else {
+ my @Pages = split( /\,/, $Pages );
+ $Pages = '';
+ foreach my $page (@Pages) {
+ if ( $page =~ /\:/ ) {
+ my ( $from, $to ) = split( /\:/, $page );
+ foreach ( my $i = $from ; $i <= $to ; $i++ ) {
+ $Pages .= $i . ',';
+ }
+ } else {
+ $Pages .= $page . ',';
+ }
+ }
+ chop $Pages;
+ print OPT "\\def\\pagestoshipout\{$Pages\}\n";
+ }
+ }
+ print OPT "\\protect\n";
+ if ( $Filters ne "" ) {
+ foreach my $F ( split( /,/, $Filters ) ) {
+ print OPT "\\useXMLfilter[$F]\n";
+ }
+ }
+ if ( $Modules ne "" ) {
+ foreach my $M ( split( /,/, $Modules ) ) {
+ print OPT "\\usemodule[$M]\n";
+ }
+ }
+ if ( $Environments ne "" ) {
+ foreach my $E ( split( /,/, $Environments ) ) {
+ print OPT "\\environment $E\n";
+ }
+ }
+ close(OPT);
+}
+
+my $UserFileOk = 0;
+my @MainLanguages;
+my $AllLanguages = '';
+
+sub MakeUserFile {
+ $UserFileOk = 0;
+ if ($AllPatterns) {
+ open( USR, ">cont-fmt.tex" );
+ print USR "\\preloadallpatterns\n";
+ } else {
+ return
+ if ( ( $MainLanguage eq 'standard' )
+ && ( $MainBodyFont eq 'standard' ) );
+ print " preparing user file : cont-fmt.tex\n";
+ open( USR, ">cont-fmt.tex" );
+ print USR "\\unprotect\n";
+ $AllLanguages = $MainLanguage;
+ if ( $MainLanguage ne 'standard' ) {
+ @MainLanguages = split( /\,/, $MainLanguage );
+ foreach (@MainLanguages) {
+ print USR "\\installlanguage[\\s!$_][\\c!state=\\v!start]\n";
+ }
+ $MainLanguage = $MainLanguages[0];
+ print USR "\\setupcurrentlanguage[\\s!$MainLanguage]\n";
+ }
+ if ( $MainBodyFont ne 'standard' ) {
+ print USR "\\definetypescriptsynonym[cmr][$MainBodyFont]";
+ print USR "\\definefilesynonym[font-cmr][font-$MainBodyFont]\n";
+ }
+ print USR "\\protect\n";
+ }
+ print USR "\\endinput\n";
+ close(USR);
+ ReportUserFile();
+ print "\n";
+ $UserFileOk = 1;
+}
+
+sub RemoveResponseFile { unlink "mult-def.tex" }
+
+sub MakeResponseFile {
+ if ( $MainResponse eq 'standard' ) { RemoveResponseFile() }
+ elsif ( !defined( $ResponseInterface{$MainResponse} ) ) {
+ RemoveResponseFile();
+ } else {
+ my $MR = $ResponseInterface{$MainResponse};
+ print " preparing interface file : mult-def.tex\n";
+ print " response language : $MR\n";
+ open( DEF, ">mult-def.tex" );
+ print DEF "\\def\\currentresponses\{$MR\}\n\\endinput\n";
+ close(DEF);
+ }
+}
+
+sub RestoreUserFile {
+ unlink "cont-fmt.log";
+ rename "cont-fmt.tex", "cont-fmt.log";
+ ReportUserFile();
+}
+
+sub ReportUserFile {
+ return unless ($UserFileOk);
+ print "\n";
+ if ( $MainLanguage ne 'standard' ) {
+ print " additional patterns : $AllLanguages\n";
+ print " default language : $MainLanguage\n";
+ }
+ if ( $MainBodyFont ne 'standard' ) {
+ print " default bodyfont : $MainBodyFont\n";
+ }
+}
+
+sub CheckPositions { }
+
+my $ConTeXtVersion = "unknown";
+my $ConTeXtModes = '';
+
+sub ScanTeXPreamble {
+ my ($FileName) = @_;
+ open( TEX, $FileName );
+ while (<TEX>) {
+ chomp;
+ if (/^\%.*/) {
+ if (/tex=([a-z]*)/goi) { $TeXExecutable = $1 }
+ if (/translat.*?=([\:\/0-9\-a-z]*)/goi) { $TeXTranslation = $1 }
+ if (/program=([a-z]*)/goi) { $TeXExecutable = $1 }
+ if (/output=([a-z\,\-]*)/goi) { $OutputFormat = $1 }
+ if (/modes=([a-z\,\-]*)/goi) { $ConTeXtModes = $1 }
+ if (/textree=([a-z\-]*)/goi) { $TeXTree = $1 }
+ if (/texroot=([a-z\-]*)/goi) { $TeXRoot = $1 }
+ if ( $ConTeXtInterface eq "unknown" ) {
+
+ if (/format=([a-z]*)/goi) {
+ $ConTeXtInterface = $ConTeXtInterfaces{$1};
+ }
+ if (/interface=([a-z]*)/goi) {
+ $ConTeXtInterface = $ConTeXtInterfaces{"$1"};
+ }
+ }
+ if (/version=([a-z]*)/goi) { $ConTeXtVersion = $1 }
+ } else {
+ last;
+ }
+ }
+ close(TEX);
+
+ # handy later on
+
+ $ProducePdfT = ($OutputFormat eq "pdftex") ;
+ $ProducePdfM = ($OutputFormat eq "dvipdfm") ;
+ $ProducePdfX = ($OutputFormat eq "dvipdfmx") ;
+ $ProducePdfXTX = ($OutputFormat eq "xetex") ;
+ $ProducePs = ($OutputFormat eq "dvips") ;
+}
+
+sub ScanContent {
+ my ($ConTeXtInput) = @_;
+ open( TEX, $ConTeXtInput );
+ while (<TEX>) {
+ next if (/^\%/) ;
+ if (
+/\\(starttekst|stoptekst|startonderdeel|startdocument|startoverzicht)/
+ )
+ {
+ $ConTeXtInterface = "nl";
+ last;
+ } elsif (/\\(stelle|verwende|umgebung|benutze)/) {
+ $ConTeXtInterface = "de";
+ last;
+ } elsif (/\\(stel|gebruik|omgeving)/) {
+ $ConTeXtInterface = "nl";
+ last;
+ } elsif (/\\(use|setup|environment)/) {
+ $ConTeXtInterface = "en";
+ last;
+ } elsif (/\\(usa|imposta|ambiente)/) {
+ $ConTeXtInterface = "it";
+ last;
+ } elsif (/(height|width|style)=/) {
+ $ConTeXtInterface = "en";
+ last;
+ } elsif (/(hoehe|breite|schrift)=/) {
+ $ConTeXtInterface = "de";
+ last;
+ }
+ # brr, can be \c!
+ elsif (/(hoogte|breedte|letter)=/) { $ConTeXtInterface = "nl"; last }
+ elsif (/(altezza|ampiezza|stile)=/) { $ConTeXtInterface = "it"; last }
+ elsif (/externfiguur/) { $ConTeXtInterface = "nl"; last }
+ elsif (/externalfigure/) { $ConTeXtInterface = "en"; last }
+ elsif (/externeabbildung/) { $ConTeXtInterface = "de"; last }
+ elsif (/figuraesterna/) { $ConTeXtInterface = "it"; last }
+ }
+ close(TEX);
+}
+
+if ( $ConTeXtInterfaces{$ConTeXtInterface} ) {
+ $ConTeXtInterface = $ConTeXtInterfaces{$ConTeXtInterface};
+}
+
+my $Problems = my $Ok = 0;
+
+sub PrepRunTeX {
+ my ( $JobName, $JobSuffix, $PipeString ) = @_;
+ my $cmd;
+ my $TeXProgNameFlag = '';
+ if ( !$dosish ) # we assume tetex on linux
+ {
+ $TeXProgramPath = '';
+ $TeXFormatPath = '';
+ if ( !$TeXProgNameFlag
+ && ( $Format =~ /^cont/ )
+ && ( $TeXPassString !~ /progname/io ) )
+ {
+ $TeXProgNameFlag = "-progname=context";
+ }
+ }
+ $own_quote = ($TeXProgramPath =~ m/^[^\"].* / ? "\"" : "") ;
+ $cmd = join( ' ',
+ "$own_quote$TeXProgramPath$TeXExecutable$own_quote",
+ $TeXProgNameFlag, $TeXPassString, $PassOn, "" );
+ if ($EnterBatchMode) { $cmd .= "$TeXBatchFlag " }
+ if ($EnterNonStopMode) { $cmd .= "$TeXNonStopFlag " }
+ if ( $TeXTranslation ne '' ) { $cmd .= "-translate-file=$TeXTranslation " }
+ $cmd .= "$TeXFormatFlag$TeXFormatPath$Format $JobName.$JobSuffix $PipeString";
+ return $cmd;
+}
+
+my $emergencyend = "" ;
+#~ my $emergencyend = "\\emergencyend" ;
+
+sub RunTeX {
+ my ( $JobName, $JobSuffix ) = @_;
+ my $StartTime = time;
+ my $cmd = PrepRunTeX($JobName, $JobSuffix, '');
+ if ($EnterBatchMode) {
+ $Problems = System("$cmd $emergencyend");
+ } else {
+ $Problems = System("$cmd $emergencyend");
+ }
+ my $StopTime = time - $StartTime;
+ print "\n return code : $Problems";
+ print "\n run time : $StopTime seconds\n";
+ return $Problems;
+}
+
+sub PushResult {
+ my $File = shift;
+ $File =~ s/\..*$//o;
+ $Result =~ s/\..*$//o;
+ if ( ( $Result ne '' ) && ( $Result ne $File ) ) {
+ print " outputfile : $Result\n";
+ unlink "texexec.tuo";
+ rename "$File.tuo", "texexec.tuo";
+ unlink "texexec.log";
+ rename "$File.log", "texexec.log";
+ unlink "texexec.dvi";
+ rename "$File.dvi", "texexec.dvi";
+ unlink "texexec.pdf";
+ rename "$File.pdf", "texexec.pdf";
+
+ if ( -e "$Result.tuo" ) {
+ unlink "$File.tuo";
+ rename "$Result.tuo", "$File.tuo";
+ }
+ }
+ if ($Optimize) { unlink "$File.tuo" }
+}
+
+sub PopResult {
+ my $File = shift;
+ $File =~ s/\..*$//o;
+ $Result =~ s/\..*$//o;
+ if ( ( $Result ne '' ) && ( $Result ne $File ) ) {
+ print " renaming : $File to $Result\n";
+ unlink "$Result.tuo";
+ rename "$File.tuo", "$Result.tuo";
+ unlink "$Result.log";
+ rename "$File.log", "$Result.log";
+ unlink "$Result.dvi";
+ rename "$File.dvi", "$Result.dvi";
+ if ( -e "$File.dvi" ) { CopyFile( "$File.dvi", "$Result.dvi" ) }
+ unlink "$Result.pdf";
+ rename "$File.pdf", "$Result.pdf";
+ if ( -e "$File.pdf" ) { CopyFile( "$File.pdf", "$Result.pdf" ) }
+ return if ( $File ne "texexec" );
+ rename "texexec.tuo", "$File.tuo";
+ rename "texexec.log", "$File.log";
+ rename "texexec.dvi", "$File.dvi";
+ rename "texexec.pdf", "$File.pdf";
+ }
+}
+
+sub RunTeXutil {
+ my $StopRunning;
+ my $JobName = shift;
+ unlink "$JobName.tup";
+ rename "$JobName.tuo", "$JobName.tup";
+ print " sorting and checking : running texutil\n";
+ my $TcXSwitch = '';
+ if ( $TcXPath ne '' ) { $TcXSwitch = "--tcxpath=$TcXPath" }
+ RunPerlScript( $TeXUtil, "--ref --ij --high $TcXPath $JobName" );
+
+ if ( -e "$JobName.tuo" ) {
+ CheckPositions($JobName);
+ #~ print " utility file check : $JobName.tup <-> $JobName.tuo\n";
+ $StopRunning = !compare( "$JobName.tup", "$JobName.tuo" );
+ } else {
+ $StopRunning = 1;
+ } # otherwise potential loop
+ if ( !$StopRunning ) {
+ print "\n utility file analysis : another run needed\n";
+ }
+ return $StopRunning;
+}
+
+sub PurgeFiles {
+ my $JobName = shift;
+ print "\n purging files : $JobName\n";
+ RunPerlScript( $TeXUtil, "--purge $JobName" );
+ unlink( $Result . '.log' ) if ( -f $Result . '.log' );
+}
+
+sub RunTeXMP {
+ my $JobName = shift;
+ my $MPfile = shift;
+ my $MPrundone = 0;
+ my $MPJobName = MPJobName( $JobName, $MPfile );
+ my $MPFoundJobName = "";
+ if ( $MPJobName ne "" ) {
+ if ( open( MP, "$MPJobName" ) ) {
+ $_ = <MP>;
+ chomp; # we should handle the prefix as well
+ if (/^\%\s+translate.*?\=([\w\d\-]+)/io) { $TeXTranslation = $1 }
+ if (/collected graphics of job \"(.+)\"/i) { $MPFoundJobName = $1 }
+ close(MP);
+ if ( $MPFoundJobName ne "" ) {
+ if ( $JobName =~ /$MPFoundJobName$/i ) {
+ if ( $MpExecutable ne '' ) {
+ print
+ " generating graphics : metaposting $MPJobName\n";
+ my $ForceMpy = "";
+ if ($MpyForce) { $ForceMpy = "--mpyforce" }
+ my $ForceTCX = '';
+ if ( $TeXTranslation ne '' ) {
+ $ForceTCX = "--translate=$TeXTranslation ";
+ }
+ if ($EnterBatchMode) {
+ RunPerlScript( $TeXExec,
+"$ForceTCX $ForceMpy --mptex --nomp --batch $MPJobName"
+ );
+ } elsif ($EnterNonStopMode) {
+ RunPerlScript( $TeXExec,
+"$ForceTCX $ForceMpy --mptex --nomp --nonstop $MPJobName"
+ );
+ } else {
+ RunPerlScript( $TeXExec,
+ "$ForceTCX $ForceMpy --mptex --nomp $MPJobName"
+ );
+ }
+ } else {
+ print
+ " generating graphics : metapost cannot be run\n";
+ }
+ $MPrundone = 1;
+ }
+ }
+ }
+ }
+ return $MPrundone;
+}
+
+sub CopyFile { # agressive copy, works for open files like in gs
+ my ( $From, $To ) = @_;
+ return unless open( INP, "<$From" );
+ binmode INP;
+ return unless open( OUT, ">$To" );
+ binmode OUT;
+ while (<INP>) { print OUT $_ }
+ close(INP);
+ close(OUT);
+}
+
+#~ sub CheckMPChanges {
+ #~ my $JobName = shift;
+ #~ my $checksum = 0;
+ #~ my $MPJobName = MPJobName( $JobName, "mpgraph" );
+ #~ if ( open( MP, $MPJobName ) ) {
+ #~ while (<MP>) {
+ #~ unless (/random/oi) {
+ #~ $checksum += do { unpack( "%32C*", <MP> ) % 65535 }
+ #~ }
+ #~ }
+ #~ close(MP);
+ #~ }
+ #~ $MPJobName = MPJobName( $JobName, "mprun" );
+ #~ if ( open( MP, $MPJobName ) ) {
+ #~ while (<MP>) {
+ #~ unless (/random/oi) {
+ #~ $checksum += do { unpack( "%32C*", <MP> ) % 65535 }
+ #~ }
+ #~ }
+ #~ close(MP);
+ #~ }
+ #~ print " mpgraph/mprun : $checksum\n";
+ #~ return $checksum;
+#~ }
+
+sub CheckMPChanges {
+ my $JobName = shift; my $str = '' ;
+ my $MPJobName = MPJobName( $JobName, "mpgraph" );
+ if ( open( MP, $MPJobName ) ) {
+ $str .= do { local $/ ; <MP> ; } ;
+ close(MP) ;
+ }
+ $MPJobName = MPJobName( $JobName, "mprun" );
+ if ( open( MP, $MPJobName ) ) {
+ $str .= do { local $/ ; <MP> ; } ;
+ close(MP) ;
+ }
+ $str =~ s/^.*?random.*?$//oim ;
+ return Digest::MD5::md5_hex($str) ;
+}
+
+#~ 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;
+#~ }
+
+sub CheckTubChanges {
+ my $JobName = shift; my $str = '' ;
+ if ( open( TUB, "$JobName.tub" ) ) {
+ $str = do { local $/ ; <TUB> ; } ;
+ close(TUB);
+ }
+ return Digest::MD5::md5_hex($str);
+}
+
+
+my $DummyFile = 0;
+
+sub isXMLfile {
+ my $Name = shift;
+ if ( ($ForceXML) || ( $Name =~ /\.(xml|fo|fox)$/io ) ) { return 1 }
+ else {
+ open( XML, $Name );
+ my $str = <XML>;
+ close(XML);
+ return ( $str =~ /\<\?xml /io );
+ }
+}
+
+sub RunConTeXtFile {
+ my ( $JobName, $JobSuffix ) = @_;
+ if ($AutoPath) {
+ if ($JobName =~ /^(.*)[\/\\](.*?)$/o) {
+ $InpPath = $1 ;
+ $JobName = $2 ;
+ }
+ }
+ $JobName =~ s/\\/\//goi;
+ $InpPath =~ s/\\/\//goi;
+ my $OriSuffix = $JobSuffix;
+ if ($JobSuffix =~ /\_fo$/i) {
+ if (! -f $JobName) {
+ print "stripping funny suffix : _fo\n";
+ $JobName =~ s/\_fo$//io ;
+ $JobSuffix =~ s/\_fo$//io ;
+ $OriSuffix =~ s/\_fo$//io ;
+ }
+ }
+ if (($dosish) && ($PdfClose)) {
+ my $ok = System("pdfclose --file $JobName.pdf") if -e "$JobName.pdf" ;
+ if (($Result ne '') && (-e "$Result.pdf")) {
+ $ok = System("pdfclose --file $Result.pdf") ;
+ }
+ System("pdfclose --all") unless $ok ;
+ }
+ if ( -e "$JobName.$JobSuffix" ) {
+ $DummyFile = ( ($ForceXML) || ( $JobSuffix =~ /(xml|fo|fox)/io ) );
+ }
+ # to be considered :
+ # { $DummyFile = isXMLfile("$JobName.$JobSuffix") }
+ elsif ( $InpPath ne "" ) {
+ my @InpPaths = split( /,/, $InpPath );
+ foreach my $rp (@InpPaths) {
+ if ( -e "$rp/$JobName.$JobSuffix" ) { $DummyFile = 1; last }
+ }
+ }
+ if ($DummyFile) {
+ open( TMP, ">$JobName.run" );
+ if ( ( $JobSuffix =~ /(xml|fo|fox)/io ) || $ForceXML ) {
+ # scan xml preamble
+ open(XML,"<$JobName.$JobSuffix") ;
+ while (<XML>) {
+ if (/\<\?context\-directive\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*?)\s*\?\>/o) {
+ my ($class, $key, $value, $rest) = ($1, $2, $3, $4) ;
+ if ($class eq 'job') {
+ if (($key eq 'mode') || ($key eq 'modes')) {
+ print TMP "\\enablemode[$value]\n" ;
+ } elsif (($key eq 'stylefile') || ($key eq 'environment')) {
+ print TMP "\\environment $value\n" ;
+ } elsif ($key eq 'module') {
+ print TMP "\\usemodule[$value]\n" ;
+ } elsif ($key eq 'interface') {
+ $ConTeXtInterface = $value ;
+ } elsif ($key eq 'control') {
+ if ($rest == 'purge') { $Purge = 1 }
+ }
+ }
+ } elsif (/\<[a-z]+/io) {
+ last ;
+ }
+ }
+ close(XML) ;
+ if ( $Filters ne "" ) {
+ print " using xml filters : $Filters\n";
+ }
+ print TMP "\\starttext\n";
+ print TMP "\\processXMLfilegrouped{$JobName.$JobSuffix}\n";
+ print TMP "\\stoptext\n";
+ } else {
+ print TMP "\\starttext\n";
+ print TMP "\\processfile{$JobName.$JobSuffix}\n";
+ print TMP "\\stoptext\n";
+ }
+ close(TMP);
+ $JobSuffix = "run";
+ }
+ if ( ( -e "$JobName.$JobSuffix" ) || ($GlobalFile) ) {
+ unless ($DummyFile) { # we don't need this for xml
+ ScanTeXPreamble("$JobName.$JobSuffix");
+ if ( $ConTeXtInterface eq "unknown" ) {
+ ScanContent("$JobName.$JobSuffix");
+ }
+ }
+ if ( $ConTeXtInterface eq "unknown" ) {
+ $ConTeXtInterface = $UserInterface;
+ }
+ if ( $ConTeXtInterface eq "unknown" ) { $ConTeXtInterface = "en" }
+ if ( $ConTeXtInterface eq "" ) { $ConTeXtInterface = "en" }
+ CheckOutputFormat;
+ my $StopRunning = 0;
+ my $MPrundone = 0;
+ if ( $Format eq '' ) { $Format = "cont-$ConTeXtInterface" }
+ print " executable : $TeXProgramPath$TeXExecutable\n";
+ print " format : $TeXFormatPath$Format\n";
+ if ($InpPath) { print " source path : $InpPath\n" }
+
+ if ($DummyFile) {
+ print " dummy file : $JobName.$JobSuffix\n";
+ }
+ print " inputfile : $JobName\n";
+ print " output : $FullFormat\n";
+ print " interface : $ConTeXtInterface\n";
+ if ( $TeXTranslation ne '' ) {
+ print " translation : $TeXTranslation\n";
+ }
+ my $Options = '';
+ if ($Random) { $Options .= " random" }
+ if ($FastMode) { $Options .= " fast" }
+ if ($FinalMode) { $Options .= " final" }
+ if ($Verbose) { $Options .= " verbose" }
+ if ($TypesetListing) { $Options .= " listing" }
+ if ($TypesetModule) { $Options .= " module" }
+ if ($TypesetFigures) { $Options .= " figures" }
+ if ($MakeFormats) { $Options .= " make" }
+ if ($RunOnce) { $Options .= " once" }
+ if ($UseColor) { $Options .= " color" }
+ if ($EnterBatchMode) { $Options .= " batch" }
+ if ($EnterNonStopMode) { $Options .= " nonstop" }
+ if ($NoMPMode) { $Options .= " nomp" }
+ if ($CenterPage) { $Options .= " center" }
+ if ($Arrange) { $Options .= " arrange" }
+ if ($NoArrange) { $Options .= " no-arrange" }
+ if ($Options) { print " options :$Options\n" }
+ if ($ConTeXtModes) { print " possible modes : $ConTeXtModes\n" }
+ if ($Mode) { print " current mode : $Mode\n" }
+ else { print " current mode : none\n" }
+ if ($Arguments) { print " arguments : $Arguments\n" }
+ if ($Modules) { print " modules : $Modules\n" }
+ if ($Environments) { print " environments : $Environments\n" }
+ if ($Suffix) { $Result = "$JobName$Suffix" }
+ PushResult($JobName);
+ $Problems = 0;
+ my $TeXRuns = 0;
+
+ if ( ($PdfArrange) || ($PdfSelect) || ($RunOnce) ) {
+ MakeOptionFile( 1, 1, $JobName, $OriSuffix, 3 );
+ print "\n";
+ $Problems = RunTeX( $JobName, $JobSuffix );
+ if ($ForceTeXutil) { $Ok = RunTeXutil($JobName) }
+ CopyFile( "$JobName.top", "$JobName.tmp" );
+ unlink "$JobName.top"; # runtime option file
+ PopResult($JobName);
+ } else {
+ while ( !$StopRunning && ( $TeXRuns < $NOfRuns ) && ( !$Problems ) )
+ {
+ ++$TeXRuns;
+ if ( $TeXRuns == 1 ) {
+ MakeOptionFile( 0, 0, $JobName, $OriSuffix, 1 );
+ } else {
+ MakeOptionFile( 0, 0, $JobName, $OriSuffix, 2 );
+ }
+ print " TeX run : $TeXRuns\n\n";
+ my ( $mpchecksumbefore, $mpchecksumafter ) = ( '', '' );
+ my ( $tubchecksumbefore, $tubchecksumafter ) = ( '', '' );
+ if ($AutoMPRun) { $mpchecksumbefore = CheckMPChanges($JobName) }
+ $tubchecksumbefore = CheckTubChanges($JobName) ;
+ $Problems = RunTeX( $JobName, $JobSuffix );
+ $tubchecksumafter = CheckTubChanges($JobName) ;
+ if ($AutoMPRun) { $mpchecksumafter = CheckMPChanges($JobName) }
+ if ( ( !$Problems ) && ( $NOfRuns > 1 ) ) {
+ unless ( $NoMPMode ) {
+ $MPrundone = RunTeXMP( $JobName, "mpgraph" );
+ $MPrundone = RunTeXMP( $JobName, "mprun" );
+ }
+ $StopRunning = RunTeXutil($JobName);
+ if ($AutoMPRun) {
+ $StopRunning =
+ ( $StopRunning
+ && ( $mpchecksumafter eq $mpchecksumbefore ) );
+ }
+ $StopRunning =
+ ( $StopRunning
+ && ( $tubchecksumafter eq $tubchecksumbefore ) );
+ }
+ }
+ if ( ( $NOfRuns == 1 ) && $ForceTeXutil ) {
+ $Ok = RunTeXutil($JobName);
+ }
+ if ( ( !$Problems )
+ && ( ( $FinalMode || $FinalRunNeeded ) )
+ && ( $NOfRuns > 1 ) )
+ {
+ MakeOptionFile( 1, $FinalMode, $JobName, $OriSuffix, 4 );
+ print " final TeX run : $TeXRuns\n\n";
+ $Problems = RunTeX( $JobName, $JobSuffix );
+ }
+ CopyFile( "$JobName.top", "$JobName.tmp" );
+ unlink "$JobName.tup"; # previous tuo file
+ unlink "$JobName.top"; # runtime option file
+ if ($ProducePdfX) {
+ $ENV{'backend'} = $ENV{'progname'} = 'dvipdfm' ;
+ $ENV{'TEXFONTMAPS'} = '.;$TEXMF/fonts/map/{dvipdfm,dvips,}//' ;
+ System("dvipdfmx -d 4 $JobName") ;
+ } elsif ($ProducePdfM) {
+ $ENV{'backend'} = $ENV{'progname'} = 'dvipdfm' ;
+ $ENV{'TEXFONTMAPS'} = '.;$TEXMF/fonts/map/{dvipdfm,dvips,}//' ;
+ System("dvipdfm $JobName") ;
+ } elsif ($ProducePdfXTX) {
+ $ENV{'backend'} = $ENV{'progname'} = 'xetex' ;
+ $ENV{'TEXFONTMAPS'} = '.;$TEXMF/fonts/map/{xetex,pdftex,dvips,}//' ;
+ System("xdv2pdf $JobName.xdv") ;
+ } elsif ($ProducePs) {
+ $ENV{'backend'} = $ENV{'progname'} = 'dvips' ;
+ $ENV{'TEXFONTMAPS'} = '.;$TEXMF/fonts/map/{dvips,pdftex,}//' ;
+ # temp hack, some day there will be map file loading in specials
+ my $mapfiles = '' ;
+ if (-f "$JobName.tui") {
+ open(TUI,"$JobName.tui") ;
+ while (<TUI>) {
+ if (/c \\usedmapfile\{.\}\{(.*?)\}/o) {
+ $mapfiles .= "-u +$1 " ;
+ }
+ }
+ close(TUI) ;
+ }
+ System("dvips $mapfiles $JobName.dvi") ;
+ }
+ PopResult($JobName);
+ }
+ if ($Purge) { PurgeFiles($JobName) }
+ if ($DummyFile) # $JobSuffix == run
+ {
+ unlink "$JobName.$JobSuffix";
+ }
+ if ((!$Problems) && ($PdfOpen)) {
+ if ($Result ne '') {
+ System("pdfopen --file $Result.pdf") if -f "$Result.pdf"
+ } else {
+ System("pdfopen --file $JobName.pdf") if -f "$JobName.pdf"
+ }
+ }
+ }
+}
+
+sub RunSomeTeXFile {
+ my ( $JobName, $JobSuffix ) = @_;
+ if ( -e "$JobName.$JobSuffix" ) {
+ PushResult($JobName);
+ print " executable : $TeXProgramPath$TeXExecutable\n";
+ print " format : $TeXFormatPath$Format\n";
+ print " inputfile : $JobName.$JobSuffix\n";
+ $Problems = RunTeX( $JobName, $JobSuffix );
+ PopResult($JobName);
+ }
+}
+
+my $ModuleFile = "texexec";
+my $ListingFile = "texexec";
+my $FiguresFile = "texexec";
+my $ArrangeFile = "texexec";
+my $SelectFile = "texexec";
+my $CopyFile = "texexec";
+my $CombineFile = "texexec";
+
+sub RunModule {
+ my @FileNames = sort @_;
+ if ($FileNames[0]) {
+ unless ( -e $FileNames[0] ) {
+ my $Name = $FileNames[0];
+ @FileNames = ( "$Name.tex", "$Name.mp", "$Name.pl", "$Name.pm" );
+ }
+ foreach my $FileName (@FileNames) {
+ next unless -e $FileName;
+ my ( $Name, $Suffix ) = split( /\./, $FileName );
+ next unless $Suffix =~ /(tex|mp|pl|pm)/io;
+ DoRunModule( $Name, $Suffix );
+ }
+ } else {
+ print " module : no modules found\n\n";
+ }
+}
+
+# the next one can be more efficient: directly process ted
+# file a la --use=abr-01,mod-01
+
+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 ($UseEnginePath) {
+ if ($dosish) {
+ $texformats = `kpsewhich --engine=$TeXExecutable --expand-var=\$TEXFORMATS` ;
+ } else {
+ $texformats = `kpsewhich --engine=$TeXExecutable --expand-var=\\\$TEXFORMATS` ;
+ }
+ } else {
+ if ($dosish) {
+ $texformats = `kpsewhich --expand-var=\$TEXFORMATS` ;
+ } else {
+ $texformats = `kpsewhich --expand-var=\\\$TEXFORMATS` ;
+ }
+ }
+ chomp($texformats) ;
+ }
+ if (($texformats !~ /web2c\/.*$TeXExecutable/) && ($texformats !~ /web2c[\/\\].*\$engine/i)) {
+ $texformats =~ s/(web2c\/\{)(\,\})/$1\$engine$2/ ; # needed for empty engine flags
+ if ($texformats !~ /web2c[\/\\].*\$ENGINE/) {
+ $texformats =~ s/web2c/web2c\/{\$engine,}/ ; # needed for me
+ }
+ $ENV{'TEXFORMATS'} = $texformats ;
+ print " fixing texformat path : $ENV{'TEXFORMATS'}\n";
+ } else {
+ print " using texformat path : $ENV{'TEXFORMATS'}\n" if ($Verbose) ;
+ }
+ if (! defined($ENV{'ENGINE'})) {
+ if ($MpEngineSupport) {
+ $ENV{'ENGINE'} .= $MpExecutable ;
+ } ;
+ $ENV{'ENGINE'} = $TeXExecutable ;
+ print "fixing engine variable : $ENV{'ENGINE'}\n";
+ }
+}
+
+sub DoRunModule {
+ my ( $FileName, $FileSuffix ) = @_;
+ RunPerlScript( $TeXUtil, "--documents $FileName.$FileSuffix" );
+ print " module : $FileName\n\n";
+ open( MOD, ">$ModuleFile.tex" );
+ # we need to signal to texexec what interface to use
+ open( TED, "$FileName.ted" );
+ my $firstline = <TED>;
+ close(TED);
+ if ( $firstline =~ /interface=/ ) {
+ print MOD $firstline ;
+ } else {
+ print MOD "% interface=en\n" ;
+ }
+ # so far
+ print MOD "\\usemodule[abr-01,mod-01]\n";
+ print MOD "\\def\\ModuleNumber{1}\n";
+ print MOD "\\starttext\n";
+ print MOD "\\readlocfile{$FileName.ted}{}{}\n";
+ print MOD "\\stoptext\n";
+ close(MOD);
+ checktexformatpath ;
+ RunConTeXtFile( $ModuleFile, "tex" );
+ if ( $FileName ne $ModuleFile ) {
+ foreach my $FileSuffix ( "dvi", "pdf", "tui", "tuo", "log" ) {
+ unlink("$FileName.$FileSuffix");
+ rename( "$ModuleFile.$FileSuffix", "$FileName.$FileSuffix" );
+ }
+ }
+ unlink("$ModuleFile.tex");
+}
+
+sub RunFigures {
+ my @Files = @_ ;
+ $TypesetFigures = lc $TypesetFigures;
+ return unless ( $TypesetFigures =~ /[abcd]/o );
+ unlink "$FiguresFile.pdf";
+ if (@Files) { RunPerlScript( $TeXUtil, "--figures @Files" ) }
+ open( FIG, ">$FiguresFile.tex" );
+ print FIG "% format=english\n";
+ print FIG "\\setuplayout\n";
+ print FIG " [topspace=1.5cm,backspace=1.5cm,\n";
+ print FIG " header=1.5cm,footer=0pt,\n";
+ print FIG " width=middle,height=middle]\n";
+ if ($ForceFullScreen) {
+ print FIG "\\setupinteraction\n";
+ print FIG " [state=start]\n";
+ print FIG "\\setupinteractionscreen\n";
+ print FIG " [option=max]\n";
+ }
+ if ($BoxType ne '') {
+ if ($BoxType !~ /box$/io) {
+ $BoxType .= "box" ;
+ }
+ }
+ print FIG "\\starttext\n";
+ print FIG "\\showexternalfigures[alternative=$TypesetFigures,offset=$PaperOffset,size=$BoxType]\n";
+ print FIG "\\stoptext\n";
+ close(FIG);
+ $ConTeXtInterface = "en";
+ checktexformatpath ;
+ RunConTeXtFile( $FiguresFile, "tex" );
+ unlink('texutil.tuf') if ( -f 'texutil.tuf' );
+}
+
+sub CleanTeXFileName {
+ my $str = shift;
+ $str =~ s/([\$\_\#])/\\$1/go;
+ $str =~ s/([\~])/\\string$1/go;
+ return $str;
+}
+
+sub RunListing {
+ my $FileName = my $CleanFileName = shift;
+ my @FileNames = glob $FileName;
+ return unless -f $FileNames[0];
+ print " input file : $FileName\n";
+ if ( $BackSpace eq "0pt" ) { $BackSpace = "1.5cm" }
+ else { print " backspace : $BackSpace\n" }
+ if ( $TopSpace eq "0pt" ) { $TopSpace = "1.5cm" }
+ else { print " topspace : $TopSpace\n" }
+ open( LIS, ">$ListingFile.tex" );
+ print LIS "% format=english\n";
+ print LIS "\\setupbodyfont[11pt,tt]\n";
+ print LIS "\\setuplayout\n";
+ print LIS " [topspace=$TopSpace,backspace=$BackSpace,\n";
+ print LIS " header=0cm,footer=1.5cm,\n";
+ print LIS " width=middle,height=middle]\n";
+ print LIS "\\setuptyping[lines=yes]\n";
+ if ($Pretty) { print LIS "\\setuptyping[option=color]\n" }
+ print LIS "\\starttext\n";
+
+ foreach $FileName (@FileNames) {
+ $CleanFileName = lc CleanTeXFileName($FileName);
+ print LIS "\\page\n";
+ print LIS "\\setupfootertexts[\\tttf $CleanFileName][\\tttf \\pagenumber]\n";
+ print LIS "\\typefile\{$FileName\}\n";
+ }
+ print LIS "\\stoptext\n";
+ close(LIS);
+ $ConTeXtInterface = "en";
+ checktexformatpath ;
+ RunConTeXtFile( $ListingFile, "tex" );
+}
+
+sub RunArrange {
+ my @files = @_;
+ print " backspace : $BackSpace\n";
+ print " topspace : $TopSpace\n";
+ print " paperoffset : $PaperOffset\n";
+ if ( $AddEmpty eq '' ) { print " empty pages added : none\n" }
+ else { print " empty pages added : $AddEmpty\n" }
+ if ( $TextWidth eq '0pt' ) { print " textwidth : unknown\n" }
+ else { print " textwidth : $TextWidth\n" }
+ open( ARR, ">$ArrangeFile.tex" );
+ print ARR "% format=english\n";
+ print ARR "\\definepapersize\n";
+ print ARR " [offset=$PaperOffset]\n";
+ print ARR "\\setuplayout\n";
+ print ARR " [backspace=$BackSpace,\n";
+ print ARR " topspace=$TopSpace,\n";
+
+ if ($Markings) {
+ print ARR " marking=on,\n";
+ print " cutmarkings : on\n";
+ }
+ print ARR " width=middle,\n";
+ print ARR " height=middle,\n";
+ print ARR " location=middle,\n";
+ print ARR " header=0pt,\n";
+ print ARR " footer=0pt]\n";
+ if ($NoDuplex) { print " duplex : off\n" }
+ else {
+ print " duplex : on\n";
+ print ARR "\\setuppagenumbering\n";
+ print ARR " [alternative=doublesided]\n";
+ }
+ print ARR "\\starttext\n";
+ foreach my $FileName (@files) {
+ print " pdffile : $FileName\n";
+ print ARR "\\insertpages\n [$FileName]";
+ if ( $AddEmpty ne '' ) { print ARR "[$AddEmpty]" }
+ print ARR "[width=$TextWidth]\n";
+ }
+ print ARR "\\stoptext\n";
+ close(ARR);
+ $ConTeXtInterface = "en";
+ checktexformatpath ;
+ RunConTeXtFile( $ModuleFile, "tex" );
+}
+
+sub RunSelect {
+ my $FileName = shift;
+ print " pdffile : $FileName\n";
+ print " backspace : $BackSpace\n";
+ print " topspace : $TopSpace\n";
+ print " paperoffset : $PaperOffset\n";
+ if ( $TextWidth eq '0pt' ) { print " textwidth : unknown\n" }
+ else { print " textwidth : $TextWidth\n" }
+ open( SEL, ">$SelectFile.tex" );
+ print SEL "% format=english\n";
+ print SEL "\\definepapersize\n";
+ print SEL " [offset=$PaperOffset]\n";
+ if ($PaperFormat =~ /fit/) {
+ print SEL "\\getfiguredimensions[$FileName]\n" ;
+ print SEL "\\expanded{\\definepapersize[fit][width=\\figurewidth,height=\\figureheight]}\n" ;
+ print SEL "\\setuppapersize[fit][fit]\n";
+ $PaperFormat = '' ; # avoid overloading in option file
+ } elsif ( $PaperFormat ne 'standard' ) {
+ $_ = $PaperFormat; # NO UPPERCASE !
+ s/x/\*/io;
+ my ( $from, $to ) = split(/\*/);
+ if ( $to eq "" ) { $to = $from }
+ print " papersize : $PaperFormat\n";
+ print SEL "\\setuppapersize[$from][$to]\n";
+ $PaperFormat = '' ; # avoid overloading in option file
+ }
+ #
+ print SEL "\\setuplayout\n";
+ print SEL " [backspace=$BackSpace,\n";
+ print SEL " topspace=$TopSpace,\n";
+ if ($Markings) {
+ print SEL " marking=on,\n";
+ print " cutmarkings : on\n";
+ }
+ print SEL " width=middle,\n";
+ print SEL " height=middle,\n";
+ print SEL " location=middle,\n";
+ print SEL " header=0pt,\n";
+ print SEL " footer=0pt]\n";
+ print SEL "\\setupexternalfigures\n";
+ print SEL " [directory=]\n";
+ print SEL "\\starttext\n";
+
+ if ( $Selection ne '' ) {
+ print SEL "\\filterpages\n";
+ print SEL " [$FileName][$Selection][width=$TextWidth]\n";
+ }
+ print SEL "\\stoptext\n";
+ close(SEL);
+ $ConTeXtInterface = "en";
+ checktexformatpath ;
+ RunConTeXtFile( $SelectFile, "tex" );
+}
+
+sub RunCopy {
+ my $DoTrim = shift ;
+ my @Files = @_ ;
+ if ( $PageScale == 1000 ) {
+ print " offset : $PaperOffset\n";
+ } else {
+ print " scale : $PageScale\n";
+ if ( $PageScale < 10 ) { $PageScale = int( $PageScale * 1000 ) }
+ }
+ open( COP, ">$CopyFile.tex" );
+ print COP "% format=english\n";
+ print COP "\\starttext\n";
+ for my $FileName (@Files) {
+ print " pdffile : $FileName\n";
+ print COP "\\getfiguredimensions\n";
+ print COP " [$FileName]\n";
+ print COP " [page=1";
+ if ($DoTrim) {
+ print COP ",\n size=trimbox";
+ }
+ print COP "]\n";
+ print COP "\\definepapersize\n";
+ print COP " [copy]\n";
+ print COP " [width=\\naturalfigurewidth,\n";
+ print COP " height=\\naturalfigureheight]\n";
+ print COP "\\setuppapersize\n";
+ print COP " [copy][copy]\n";
+ print COP "\\setuplayout\n";
+ print COP " [page]\n";
+ print COP "\\setupexternalfigures\n";
+ print COP " [directory=]\n";
+ print COP "\\copypages\n";
+ print COP " [$FileName]\n";
+ print COP " [scale=$PageScale,\n";
+ if ($Markings) {
+ print COP " marking=on,\n";
+ print " cutmarkings : on\n";
+ }
+ if ($DoTrim) {
+ print COP " size=trimbox,\n";
+ print " cropping to : trimbox\n";
+ }
+ print COP " offset=$PaperOffset]\n";
+ }
+ print COP "\\stoptext\n";
+ close(COP);
+ $ConTeXtInterface = "en";
+ checktexformatpath ;
+ RunConTeXtFile( $CopyFile, "tex" );
+}
+
+sub RunCombine {
+ my @Files = @_;
+ $Combination =~ s/x/\*/io;
+ my ( $nx, $ny ) = split( /\*/, $Combination, 2 );
+ return unless ( $nx && $ny );
+ print " combination : $Combination\n";
+ open( COM, ">$CombineFile.tex" );
+ print COM "% format=english\n";
+ if ( $PaperFormat ne 'standard' ) {
+ $_ = $PaperFormat; # NO UPPERCASE !
+ s/x/\*/io;
+ my ( $from, $to ) = split(/\*/);
+ if ( $to eq "" ) { $to = $from }
+ print " papersize : $PaperFormat\n";
+ print COM "\\setuppapersize[$from][$to]\n";
+ }
+ #
+ if ( $PaperOffset eq '0pt' ) { $PaperOffset = '1cm' }
+ print " paper offset : $PaperOffset\n";
+ print COM "\\setuplayout\n";
+ print COM " [topspace=$PaperOffset,\n";
+ print COM " backspace=$PaperOffset,\n";
+ print COM " header=0pt,\n";
+ print COM " footer=1cm,\n";
+ print COM " width=middle,\n";
+ print COM " height=middle]\n";
+
+ if ($NoBanner) {
+ print COM "\\setuplayout\n";
+ print COM " [footer=0cm]\n";
+ }
+ print COM "\\setupexternalfigures\n";
+ print COM " [directory=]\n";
+ print COM "\\starttext\n";
+ for my $FileName (@Files) {
+ next if ( $FileName =~ /^texexec/io );
+ next if (($Result ne '') && ( $FileName =~ /^$Result/i ));
+ print " pdffile : $FileName\n";
+ my $CleanFileName = CleanTeXFileName($FileName);
+ print COM "\\setupfootertexts\n";
+ print COM " [\\tttf $CleanFileName\\quad\\quad\\currentdate\\quad\\quad\\pagenumber]\n";
+ print COM "\\combinepages[$FileName][nx=$nx,ny=$ny]\n";
+ print COM "\\page\n";
+ }
+ print COM "\\stoptext\n";
+ close(COM);
+ $ConTeXtInterface = "en";
+ checktexformatpath ;
+ RunConTeXtFile( $CombineFile, "tex" );
+}
+
+sub LocatedFormatPath { # watch out $engine is lowercase in kpse
+ my $FormatPath = shift;
+ my $EnginePath = shift;
+ my $EngineDone = shift;
+ if ($Local) {
+ $FormatPath = '.' ; # for patrick
+ } else {
+ if ( ( $FormatPath eq '' ) && ( $kpsewhich ne '' ) ) {
+ 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 '') {
+ if (($UseEnginePath)&&($EngineDone)) {
+ if ($dosish) {
+ $FormatPath = `$kpsewhich --engine=$EnginePath --expand-path=\$TEXFORMATS` ;
+ } else {
+ $FormatPath = `$kpsewhich --engine=$EnginePath --expand-path=\\\$TEXFORMATS` ;
+ }
+ }
+ chomp($FormatPath) ;
+ # either no enginepath or failed run
+ if ($FormatPath eq '') {
+ if ($dosish) {
+ $FormatPath = `$kpsewhich --expand-path=\$TEXFORMATS` ;
+ } else {
+ $FormatPath = `$kpsewhich --expand-path=\\\$TEXFORMATS` ;
+ }
+ }
+ chomp $FormatPath ;
+ }
+ chomp($FormatPath) ;
+ if ( ( $FormatPath ne '' ) && $Verbose ) {
+ print "located formatpath (2) : $FormatPath\n";
+ }
+ $FormatPath =~ s/\\/\//g ;
+ if ($FormatPath ne '') {
+ my @fpaths ;
+ if ($dosish) {
+ @fpaths = split(';', $FormatPath) ;
+ } else {
+ @fpaths = split(':', $FormatPath) ;
+ }
+ # take first writable unless current
+ foreach my $fp (@fpaths) {
+ # remove funny patterns
+ $fp =~ s/\/+$// ;
+ $fp =~ s/^!!// ;
+ $fp =~ s/unsetengine/$EnginePath/ ;
+ if (($fp ne '') && ($fp ne '.')) {
+ # correct if needed
+ # append engine unless engine is already there
+ $fp =~ "$fp/$EnginePath" if ($fp =~ /[\\\/]$EnginePath[\\\/]*$/) ;
+ # path may not yet be present
+ # check if usable format path
+ my $fpp = $fp ;
+ $fpp =~ s/\/*$EnginePath\/*// ;
+ if ((-d $fpp) && (-w $fpp)) {
+ $FormatPath = $fpp ;
+ last ;
+ }
+ }
+ }
+ }
+ $FormatPath = '.' if (($FormatPath eq '') || (! -w $FormatPath)) ;
+ if ( ( $FormatPath ne '' ) && $Verbose ) {
+ print "located formatpath (3) : $FormatPath\n";
+ }
+ $FormatPath .= '/';
+ }
+ if ($UseEnginePath && $EngineDone && ($FormatPath ne '') && ($FormatPath !~ /$EnginePath\/$/)) {
+ $FormatPath .= $EnginePath ;
+ unless (-d $FormatPath) {
+ mkdir $FormatPath ;
+ }
+ $FormatPath .= '/' ;
+ }
+ }
+ print " using formatpath : $FormatPath\n" if $Verbose ;
+ return $FormatPath;
+}
+
+sub RunOneFormat {
+ my ($FormatName) = @_;
+ my @TeXFormatPath;
+ my $TeXPrefix = "";
+ if ( ( $fmtutil ne "" ) && ( $FormatName !~ /metafun|mptopdf/io ) ) {
+ # could not happen, not supported any more
+ my $cmd = "$fmtutil --byfmt $FormatName";
+ MakeUserFile; # this works only when the path is kept
+ MakeResponseFile;
+ $Problems = System("$cmd");
+ RemoveResponseFile;
+ RestoreUserFile;
+ } else {
+ $Problems = 1;
+ }
+ if ($Problems) {
+ $Problems = 0;
+ if ( $TeXExecutable =~ /etex|eetex|pdfetex|pdfeetex|pdfxtex|xpdfetex|eomega|aleph|xetex/io ) {
+ $TeXPrefix = "*";
+ }
+ my $CurrentPath = cwd();
+ my $TheTeXFormatPath = LocatedFormatPath($TeXFormatPath, $TeXExecutable,1);
+ if ( $TheTeXFormatPath ne '' ) { chdir $TheTeXFormatPath }
+ MakeUserFile;
+ MakeResponseFile;
+ $own_quote = ($TeXProgramPath =~ m/^[^\"].* / ? "\"" : "") ;
+ my $cmd =
+ "$own_quote$TeXProgramPath$TeXExecutable$own_quote $TeXVirginFlag "
+ . "$TeXPassString $PassOn ${TeXPrefix}$FormatName";
+ $Problems = System($cmd) ;
+ RemoveResponseFile;
+ RestoreUserFile;
+
+ if ( ( $TheTeXFormatPath ne '' ) && ( $CurrentPath ne '' ) ) {
+ print "\n";
+ if ($UseEnginePath) {
+ print " used engineformatpath : $TheTeXFormatPath\n";
+ } else {
+ print " used formatpath : $TheTeXFormatPath\n";
+ }
+ print "\n";
+ chdir $CurrentPath;
+ }
+ }
+}
+
+sub RunFormats {
+ my $ConTeXtFormatsPrefix;
+ my $MetaFunDone = 0;
+ if (@ARGV) { @ConTeXtFormats = @ARGV }
+ elsif ( $UsedInterfaces ne '' ) {
+ @ConTeXtFormats = split /[\,\s]/, $UsedInterfaces;
+ }
+ if ($Format) { @ConTeXtFormats = $Format; $ConTeXtFormatsPrefix = ''; }
+ else { $ConTeXtFormatsPrefix = "cont-"; }
+ if ( $TeXHashExecutable ne '' ) {
+ unless ($FastMode) {
+ $own_quote = ($TeXProgramPath =~ m/^[^\"].* / ? "\"" : "") ;
+ my $cmd = "$own_quote$TeXProgramPath$TeXHashExecutable$own_quote";
+ print "\n";
+ print " TeX hash binary : $TeXProgramPath$TeXHashExecutable\n";
+ print " comment : hashing may take a while ...\n";
+ System($cmd);
+ }
+ }
+ foreach my $Interface (@ConTeXtFormats) {
+ if ( $Interface eq $MetaFun ) {
+ RunMpFormat($MetaFun);
+ $MetaFunDone = 1;
+ } elsif ( $Interface eq $MpToPdf ) {
+ if ( $TeXExecutable =~ /pdf/io ) { RunOneFormat("$MpToPdf") }
+ } else {
+ RunOneFormat("$ConTeXtFormatsPrefix$Interface");
+ }
+ }
+ print "\n";
+ print " TeX binary : $TeXProgramPath$TeXExecutable\n";
+ print " format(s) : @ConTeXtFormats\n\n";
+}
+
+sub RunMpFormat {
+ # engine is not supported by MP
+ my $MpFormat = shift;
+ return if ( $MpFormat eq '' );
+ my $CurrentPath = cwd();
+ 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";
+ System($cmd ) ;
+ if ( ( $TheMpFormatPath ne '' ) && ( $CurrentPath ne '' ) ) {
+ print "\n";
+ print " used formatpath : $TheMpFormatPath\n";
+ print "\n";
+ chdir $CurrentPath;
+ }
+}
+
+
+my $dir = File::Temp::tempdir(CLEANUP=>1) ;
+my ($fh, $filename) = File::Temp::tempfile(DIR=>$dir, UNLINK=>1);
+
+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";
+ #
+ # 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
+ if (($RunPath ne "") && (-w "$RunPath")) {
+ print " changing to path : $RunPath\n";
+ $InpPath = $currentpath ;
+ chdir ($RunPath) ;
+ }
+ # start working
+ if ($PdfArrange) {
+ my @arrangedfiles = ();
+ foreach my $JobName (@ARGV) {
+ unless ( $JobName =~ /.*\.pdf$/oi ) {
+ if ( -f "$JobName.pdf" ) { $JobName .= ".pdf" }
+ else { $JobName .= ".PDF" }
+ }
+ push @arrangedfiles, $JobName;
+ }
+ if (@arrangedfiles) { RunArrange(@arrangedfiles) }
+ } elsif ( ($PdfSelect) || ($PdfCopy) || ($PdfTrim) || ($PdfCombine) ) {
+ my $JobName = $ARGV[0];
+ if ( $JobName ne '' ) {
+ unless ( $JobName =~ /.*\.pdf$/oi ) {
+ if ( -f "$JobName.pdf" ) { $JobName .= ".pdf" }
+ else { $JobName .= ".PDF" }
+ }
+ if ($PdfSelect) {
+ RunSelect($JobName) ;
+ } elsif ($PdfCopy) {
+ # RunCopy($JobName) ;
+ RunCopy(0,@ARGV) ;
+ } elsif ($PdfTrim) {
+ # RunCopy($JobName) ;
+ RunCopy(1,@ARGV) ;
+ } else {
+ # RunCombine ($JobName) ;
+ RunCombine(@ARGV);
+ }
+ }
+ } elsif ($TypesetModule) {
+ RunModule(@ARGV);
+ } else {
+ my $JobSuffix = "tex";
+ foreach my $JobName (@ARGV) {
+ next if ($JobName =~ /^\-/io) ;
+ # start experiment - full name spec including suffix is prerequisite
+ if (($StartLine>0) && ($EndLine>=$StartLine) && (-e $JobName)) {
+ if (open(INP,$JobName) && open(OUT,'>texexec.tex')) {
+ print " writing partial file : $JobName\n";
+ my $Line = 1 ;
+ my $Preamble = 1 ;
+ while (my $str = <INP>) {
+ if ($Preamble) {
+ if ($str =~ /\\start(text|tekst|product|project|component)/io) {
+ $Preamble = 0 ;
+ } else {
+ print OUT $str;
+ }
+ } elsif ($Line==$StartLine) {
+ print OUT "\\starttext\n" ; # todo: multilingual
+ print OUT $str ;
+ } elsif ($Line==$EndLine) {
+ print OUT $str ;
+ print OUT "\\stoptext\n" ; # todo: multilingual
+ last ;
+ } elsif (($Line>$StartLine) && ($Line<$EndLine)) {
+ print OUT $str ;
+ }
+ $Line += 1 ;
+ }
+ close(INP) ;
+ close(OUT) ;
+ $JobName = 'texexec.tex' ;
+ print " using job name : $JobName\n";
+ }
+ }
+ # end experiment
+ if ( $JobName =~ s/\.(\w+)$//io ) { $JobSuffix = $1 }
+ if ( ( $Format eq '' ) || ( $Format =~ /^cont.*/io ) ) {
+ RunConTeXtFile( $JobName, $JobSuffix );
+ } else {
+ RunSomeTeXFile( $JobName, $JobSuffix );
+ }
+ unless ( -s "$JobName.log" ) { unlink("$JobName.log") }
+ unless ( -s "$JobName.tui" ) { unlink("$JobName.tui") }
+ }
+ }
+}
+
+my $MpTmp = "tmpgraph"; # todo: prefix met jobname
+my $MpKep = "$MpTmp.kep"; # sub => MpTmp("kep")
+my $MpLog = "$MpTmp.log";
+my $MpBck = "$MpTmp.bck";
+my $MpTex = "$MpTmp.tex";
+my $MpDvi = "$MpTmp.dvi";
+
+my %mpbetex;
+
+sub RunMP { ###########
+ if ( ($MpExecutable) && ($MpToTeXExecutable) && ($DviToMpExecutable) ) {
+ foreach my $RawMpName (@ARGV) {
+ my ( $MpName, $Rest ) = split( /\./, $RawMpName, 2 );
+ my $MpFile = "$MpName.mp";
+ if ( -e $MpFile
+ and ( -s $MpFile > 25 ) ) # texunlink makes empty file
+ {
+ unlink "$MpName.mpt";
+ doRunMP( $MpName, 0 );
+ # test for graphics, new per 14/12/2000
+ my $mpgraphics = checkMPgraphics($MpName);
+ # test for labels
+ my $mplabels = checkMPlabels($MpName);
+ if ( $mpgraphics || $mplabels ) {
+ doRunMP( $MpName, $mplabels );
+ }
+ }
+ }
+ }
+}
+
+my $mpochecksum = '';
+
+#~ sub checkMPgraphics { # also see makempy
+ #~ my $MpName = shift;
+ #~ if ( $MakeMpy ne '' ) { $MpName .= " --$MakeMpy " } # extra switches
+ #~ if ($MpyForce) { $MpName .= " --force " } # dirty
+ #~ else {
+ #~ return 0 unless -s "$MpName.mpo" > 32;
+ #~ return 0 unless ( open( MPO, "$MpName.mpo" ) );
+ #~ $mpochecksum = do { local $/; unpack( "%32C*", <MPO> ) % 65535 };
+ #~ close(MPO);
+ #~ if ( open( MPY, "$MpName.mpy" ) ) {
+ #~ my $str = <MPY>;
+ #~ chomp $str;
+ #~ close(MPY);
+ #~ if ( $str =~ /^\%\s*mpochecksum\s*\:\s*(\d+)/o ) {
+ #~ return 0 if ( ( $mpochecksum eq $1 ) && ( $mpochecksum ne 0 ) );
+ #~ }
+ #~ }
+ #~ }
+ #~ RunPerlScript( "makempy", "$MpName" );
+ #~ print " second MP run needed : text graphics found\n";
+ #~ return 1;
+#~ }
+
+sub checkMPgraphics { # also see makempy
+ my $MpName = shift;
+ if ( $MakeMpy ne '' ) { $MpName .= " --$MakeMpy " } # extra switches
+ if ($MpyForce) { $MpName .= " --force " } # dirty
+ else {
+ return 0 unless -s "$MpName.mpo" > 32;
+ return 0 unless ( open( MPO, "$MpName.mpo" ) );
+ $mpochecksum = do { local $/; Digest::MD5::md5_hex(<MPO>) ; };
+ close(MPO);
+ if ( open( MPY, "$MpName.mpy" ) ) {
+ my $str = <MPY>;
+ chomp $str;
+ close(MPY);
+ if ( $str =~ /^\%\s*mpochecksum\s*\:\s*([a-fA-F0-9]+)/o ) {
+ return 0 if ( ( $mpochecksum eq $1 ) && ( $mpochecksum ne '' ) );
+ }
+ }
+ }
+ RunPerlScript( "makempy", "$MpName" );
+ print " second MP run needed : text graphics found\n";
+ return 1;
+}
+
+sub checkMPlabels {
+ my $MpName = shift;
+ return 0 unless ((-f "$MpName.mpt") && ((-s "$MpName.mpt")>10) );
+ return 0 unless open( MP, "$MpName.mpt" );
+ my $n = 0;
+ my $t = "" ;
+ while (<MP>) {
+ if (/% setup : (.*)/o) {
+ $t = $1 ;
+ } else {
+ $t = "" ;
+ }
+ if (/% figure (\d+) : (.*)/o) {
+ if ($t ne "") {
+ $mpbetex{$1} .= "$t\n" ;
+ $t = "" ;
+ }
+ $mpbetex{$1} .= "$2\n";
+ ++$n ;
+ }
+ }
+ close(MP);
+ print " second MP run needed : $n tex labels found\n" if $n;
+ return $n;
+}
+
+sub doMergeMP {
+ # make sure that the verbatimtex ends up before btex etc
+ my ($n,$str) = @_ ;
+ if ($str =~ /(.*?)(verbatimtex.*?etex)\s*\;(.*)/mois) {
+ return "beginfig($n)\;\n$1$2\;\n$mpbetex{$n}\n$3\;endfig\;\n" ;
+ } else {
+ return "beginfig($n)\;\n$mpbetex{$n}\n$str\;endfig\;\n" ;
+ }
+}
+
+sub doRunMP { ###########
+ my ( $MpName, $MergeBE ) = @_;
+ my $TexFound = 0;
+ my $MpFile = "$MpName.mp";
+ if ( open( MP, $MpFile ) ) { # fails with %
+ my $MPdata = "";
+ while (<MP>) {
+ unless (/^\%/) { $MPdata .= $_ }
+ }
+ $_ = $MPdata;
+ close(MP);
+
+ # save old file
+ unlink($MpKep);
+ return if ( -e $MpKep );
+ rename( $MpFile, $MpKep );
+ # check for tex stuff
+
+ $TexFound = $MergeBE || /btex .*? etex/o;
+
+ # shorten lines into new file if okay
+ unless ( -e $MpFile ) {
+ open( MP, ">$MpFile" );
+ s/(btex.*?)\;(.*?etex)/$1\@\@\@$2/gmois;
+ s/(\".*?)\;(.*?\")/$1\@\@\@$2/gmois; # added
+ s/\;/\;\n/gmois;
+ s/\n\n/\n/gmois;
+ s/(btex.*?)\@\@\@(.*?etex)/$1\;$2/gmois;
+ s/(\".*?)\@\@\@(.*?\")/$1\;$2/gmois; # added
+ # merge labels
+ if ($MergeBE) {
+ # i hate this indirect (sub regexp) mess
+ s/beginfig\s*\((\d+)\)\s*\;(.*?)endfig\s*\;/doMergeMP($1,$2)/gems ;
+ }
+ unless (/beginfig\s*\(\s*0\s*\)/gmois) {
+ if (defined($mpbetex{0})) { # test added, warning
+ print MP $mpbetex{0} ;
+ }
+ }
+ print MP $_;
+ print MP "\n" . "end" . "\n";
+ close(MP);
+ }
+ if ($TexFound) {
+ print " metapost to tex : $MpName\n";
+ $own_quote = ($MpToTeXExecutable =~ m/^[^\"].* / ? "\"" : "") ;
+ $Problems =
+ System("$own_quote$MpToTeXExecutable$own_quote $MpFile > $MpTex");
+ if ( -e $MpTex && !$Problems ) {
+ open( TMP, ">>$MpTex" );
+ print TMP "\\end\{document\}\n"; # to be sure
+ close(TMP);
+ if ( ( $Format eq '' ) || ( $Format =~ /^cont.*/io ) ) {
+ $OutputFormat = "dvips";
+ RunConTeXtFile( $MpTmp, "tex" );
+ } else {
+ RunSomeTeXFile( $MpTmp, "tex" );
+ }
+ if ( -e $MpDvi && !$Problems ) {
+ print " dvi to metapost : $MpName\n";
+ $own_quote = ($DviToMpExecutable =~ m/^[^\"].* / ? "\"" : "") ;
+ $Problems = System("$own_quote$DviToMpExecutable$own_quote $MpDvi $MpName.mpx");
+ }
+ unlink $MpBck;
+ rename $MpTex, $MpBck;
+ unlink $MpDvi;
+ }
+ }
+ print " metapost : $MpName\n";
+ $own_quote = ($MpExecutable =~ m/^[^\"].* / ? "\"" : "") ;
+ my $cmd = "$own_quote$MpExecutable$own_quote";
+ if ($EnterBatchMode) { $cmd .= " $MpBatchFlag " }
+ if ($EnterNonStopMode) { $cmd .= " $MpNonStopFlag " }
+ if ( ( $MpFormat ne '' ) && ( $MpFormat !~ /(plain|mpost)/oi ) ) {
+ print " format : $MpFormat\n";
+ $cmd .= " $MpPassString $MpFormatFlag$MpFormat ";
+ }
+ # prevent nameclash, experimental
+ my $MpMpName = "$MpName";
+ $Problems = System("$cmd $MpMpName");
+ open( MPL, "$MpName.log" );
+ while (<MPL>) # can be one big line unix under win
+ {
+ while (/^l\.(\d+)\s/gmois) {
+ print " error in metapost run : $MpName.mp:$1\n";
+ }
+ }
+ close(MPL) ;
+ unlink "mptrace.tmp";
+ rename( $MpFile, "mptrace.tmp" );
+ if ( -e $MpKep ) {
+ unlink($MpFile);
+ rename( $MpKep, $MpFile );
+ }
+ }
+}
+
+sub RunMPX {
+ my $MpName = shift;
+ $MpName =~ s/\..*$//o;
+ my $MpFile = $MpName . ".mp";
+ if ( ($MpToTeXExecutable)
+ && ($DviToMpExecutable)
+ && ( -e $MpFile )
+ && ( -s $MpFile > 5 )
+ && open( MP, $MpFile ) )
+ {
+ local $/ = "\0777";
+ $_ = <MP>;
+ close(MP);
+ if (/(btex|etex|verbatimtex)/mos) {
+ print " generating mpx file : $MpName\n";
+ $own_quote = ($MpToTeXExecutable =~ m/^[^\"].* / ? "\"" : "") ;
+ $Problems =
+ System("$own_quote$MpToTeXExecutable$own_quote $MpFile > $MpTex");
+ if ( -e $MpTex && !$Problems ) {
+ open( TMP, ">>$MpTex" );
+ print TMP "\\end\n"; # to be sure
+ close(TMP);
+ checktexformatpath ;
+ if ( ( $Format eq '' ) || ( $Format =~ /^cont.*/io ) ) {
+ RunConTeXtFile( $MpTmp, "tex" );
+ } else {
+ RunSomeTeXFile( $MpTmp, "tex" );
+ }
+ if ( -e $MpDvi && !$Problems ) {
+ $own_quote = ($DviToMpExecutable =~ m/^[^\"].* / ? "\"" : "") ;
+ $Problems =
+ System("$own_quote$DviToMpExecutable$own_quote $MpDvi $MpName.mpx");
+ }
+ unlink $MpTex;
+ unlink $MpDvi;
+ }
+ }
+ }
+}
+
+sub load_set_file {
+ my %new;
+ my %old;
+ my ( $file, $trace ) = @_;
+ if ( open( BAT, $file ) ) {
+ while (<BAT>) {
+ chomp;
+ if (/\s*SET\s+(.+?)\=(.+)\s*/io) {
+ my ( $var, $val ) = ( $1, $2 );
+ $val =~ s/\%(.+?)\%/$ENV{$1}/goi;
+ unless ( defined( $old{$var} ) ) {
+ if ( defined( $ENV{$var} ) ) { $old{$var} = $ENV{$var} }
+ else { $old{$var} = "" }
+ }
+ $ENV{$var} = $new{$var} = $val;
+ }
+ }
+ close(BAT);
+ }
+ if ($trace) {
+ foreach my $key ( sort keys %new ) {
+ if ( $old{$key} ne $new{$key} ) {
+ print " changing env variable : '$key' from '$old{$key}' to '$new{$key}'\n";
+ } elsif ( $old{$key} eq "" ) {
+ print " setting env variable : '$key' to '$new{$key}'\n";
+ } else {
+ print " keeping env variable : '$key' at '$new{$key}'\n";
+ }
+ }
+ print "\n";
+ }
+}
+
+if ( $SetFile ne "" ) { load_set_file( $SetFile, $Verbose ) }
+
+sub check_texmf_root { }
+sub check_texmf_tree { }
+
+sub AnalyzeVersion
+ { my $str = join("\n", @_) ;
+ my ($texengine,$type) = ('unknown', 'unknown');
+ open (LOG, "<texvers.log") ;
+ while (<LOG>)
+ { /^\s*This is (.*(pdf)?(|e|x)TeX.*?)$/o and $texengine = $1 ;
+ /^\s*ConTeXt (.*int: ([a-z]+).*?)\s*$/o and $type = $1; }
+ $type =~ s/ int: ([a-z]+)//;
+ $texengine =~ s/ Version//;
+ $texengine =~ s/ \(format.*$//;
+ close (LOG);
+ return ($texengine,$type) }
+
+sub show_version_info {
+ my ($texengine,$type);
+ open (TEX,">texvers.tex") ;
+ print TEX "\\bye " ;
+ close (TEX) ;
+ my $texutil = `$TeXUtil --help`;
+ $texutil =~ s/.*(TeXUtil[^\n]+)\n.*?$/$1/s;
+ print " texexec :$Program\n" ;
+ print " texutil : $texutil" ;
+ my $contexttext = `$kpsewhich context.tex`;
+ my $contextversion = "<not found>";
+ if ($contexttext) {
+ chop $contexttext;
+ { local $/;
+ open (IN,"<$contexttext");
+ $contextversion = <IN>;
+ close IN;
+ }
+ $contextversion =~ s/.*contextversion\{([0-9.]+)\}.*/$1/s;
+ }
+ $EnterBatchMode = 1;
+ $Format = 'cont-en';
+ my $cmd = PrepRunTeX("texvers","tex",'') ;
+ ($texengine,$type) = AnalyzeVersion(Pipe($cmd)) ;
+ print " tex : $texengine\n" ;
+ print " context : ver: $contextversion\n" ;
+ print " cont-en : $type\n" ;
+ foreach my $a (qw(cz de it nl ro uk xx)) {
+ my $test = Pipe("$kpsewhich -format='fmt' cont-$a") ;
+ if (defined $test && $test) {
+ $Format = 'cont-' . $a;
+ $cmd = PrepRunTeX("texvers","tex",'');
+ ($texengine,$type) = AnalyzeVersion(Pipe($cmd)) ;
+ print " cont-$a : $type\n" ;
+ }
+ }
+ unlink <texvers.*>;
+}
+
+# the main thing
+
+if ($HelpAsked) {
+ show_help_info
+} elsif ($Version) {
+ show_version_info
+} elsif ($TypesetListing) {
+ check_texmf_root;
+ check_texmf_tree;
+ RunListing(@ARGV);
+} elsif ($TypesetFigures) {
+ check_texmf_root;
+ check_texmf_tree;
+ RunFigures(@ARGV);
+} elsif ($DoMPTeX) {
+ check_texmf_root;
+ check_texmf_tree;
+ RunMP;
+} elsif ($DoMPXTeX) {
+ check_texmf_root;
+ check_texmf_tree;
+ RunMPX( $ARGV[0] );
+} elsif ($MakeFormats) {
+ check_texmf_root;
+ check_texmf_tree;
+ if ( $MpDoFormat ne '' ) {
+ RunMpFormat($MpDoFormat) ;
+ }
+ else {
+ RunFormats ;
+ }
+} elsif (@ARGV) {
+ check_texmf_root;
+ check_texmf_tree;
+ @ARGV = <@ARGV>;
+ RunFiles;
+} elsif ( !$HelpAsked ) {
+ show_help_options;
+}
+
+$TotalTime = time - $TotalTime;
+
+unless ($HelpAsked) { print "\n total run time : $TotalTime seconds\n" }
+
+if ($Problems) { exit 1 }
+
+__DATA__
+arrange process and arrange
+-----------
+batch run in batch mode (don't pause)
+-----------
+nonstop run in non stop mode (don't pause)
+-----------
+centerpage center the page on the paper
+-----------
+color enable color (when not yet enabled)
+-----------
+usemodule load some modules first
+=name list of modules
+-----------
+xmlfilter apply XML filter
+=name list of filters
+-----------
+environment load some environments first
+=name list of environments
+-----------
+fast skip as much as possible
+-----------
+figures typeset figure directory
+=a room for corrections
+=b just graphics
+=c one (cropped) per page
+paperoffset room left at paper border
+fullscreen force full screen mode (pdf)
+-----------
+screensaver turn graphic file into a (pdf) full screen file
+-----------
+final add a final run without skipping
+-----------
+format fmt file
+=name format file (memory dump)
+-----------
+mpformat mem file
+=name format file (memory dump)
+-----------
+interface user interface
+=en English
+=nl Dutch
+=de German
+=cz Czech
+=uk Brittish
+=it Italian
+-----------
+language main hyphenation language
+=xx standard abbreviation
+-----------
+listing produce a verbatim listing
+backspace inner margin of the page
+topspace top/bottom margin of the page
+pretty enable pretty printing
+color use color for pretty printing
+-----------
+make build format files
+language patterns to include
+bodyfont bodyfont to preload
+response response interface language
+format TeX format
+mpformat MetaPost format
+program TeX program
+-----------
+mode running mode
+=list modes to set
+-----------
+module typeset tex/pl/mp module
+-----------
+mptex run an MetaPost plus btex-etex cycle
+-----------
+mpxtex generatet an MetaPostmpx file
+-----------
+noarrange process but ignore arrange
+-----------
+nomp don't run MetaPost at all
+-----------
+nomprun don't run MetaPost at runtime
+-----------
+automprun MetaPost at runtime when needed
+-----------
+once run TeX only once (no TeXUtil either)
+-----------
+output specials to use
+=pdftex Han The Than's pdf backend
+=dvips Thomas Rokicky's dvi to ps converter
+=dvipsone YandY's dvi to ps converter
+=dviwindo YandY's windows previewer
+=dvipdfm Mark Wicks' dvi to pdf converter
+=dvipdfmx Jin-Hwan Cho's extended dvipdfm
+-----------
+passon switches to pass to TeX (--src for MikTeX)
+-----------
+pages pages to output
+=odd odd pages
+=even even pages
+=x,y:z pages x and y to z
+-----------
+paper paper input and output format
+=a4a3 A4 printed on A3
+=a5a4 A5 printed on A4
+-----------
+path document source path
+=string path
+-----------
+pdf produce PDF directly using pdf(e)tex
+-----------
+pdfarrange arrange pdf pages
+paperoffset room left at paper border
+paper paper format
+noduplex single sided
+backspace inner margin of the page
+topspace top/bottom margin of the page
+markings add cutmarks
+background
+=string background graphic
+addempty add empty page after
+textwidth width of the original (one sided) text
+-----------
+pdfcombine combine pages to one page
+paperformat paper format
+combination n*m pages per page
+paperoffset room left at paper border
+nobanner no footerline
+-----------
+pdfcopy scale pages down/up
+scale new page scale
+paperoffset room left at paper border
+markings add cutmarks
+background
+=string background graphic
+-----------
+pdfselect select pdf pages
+selection pages to select
+=odd odd pages
+=even even pages
+=x,y:z pages x and y to z
+paperoffset room left at paper border
+paperformat paper format
+backspace inner margin of the page
+topspace top/bottom margin of the page
+markings add cutmarks
+background
+=string background graphic
+addempty add empty page after
+textwidth width of the original (one sided) text
+-----------
+print page imposition scheme
+=up 2 pages per sheet doublesided
+=down 2 rotated pages per sheet doublesided
+-----------
+result resulting file
+=name filename
+-----------
+input input file (if used)
+=name filename
+-----------
+suffix resulting file suffix
+=string suffix
+-----------
+runs maximum number of TeX runs
+=n number of runs
+-----------
+silent minimize (status) messages
+-----------
+tex TeX binary
+=name binary of executable
+-----------
+textree additional texmf tree to be used
+=path subpath of tex root
+-----------
+texroot root of tex trees
+=path tex root
+-----------
+verbose shows some additional info
+-----------
+help show this or more, e.g. '--help interface'
+-----------
+alone bypass utilities (e.g. fmtutil for non-standard fmt's)
+-----------
+texutil force TeXUtil run
+-----------
+version display various version information
+-----------
+setfile load environment (batch) file
diff --git a/Master/texmf-dist/scripts/context/perl/texexec.rme b/Master/texmf-dist/scripts/context/perl/texexec.rme
new file mode 100644
index 00000000000..f38b4be7fe0
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/perl/texexec.rme
@@ -0,0 +1,169 @@
+% == introduction ==
+%
+% This is 'texexec.ini', the file used by texexec to determine where
+% to find files, what TeX to use, what flags to pass, etc. Although
+% TeXexec tries to locate things itself, a little help is sometimes
+% needed. One can influence texexec by setting some variables. These
+% are only needed when the automatic determined settings fail.
+%
+% == interfacing ==
+%
+% UsedInterfaces nl,en the formats generated with --make
+% UserInterface nl the default format used
+%
+% == binaries ==
+%
+% TeXExecutable pdfetex the TeX binary to use
+% MpExecutable mpost the MetaPost binary to use
+% MpToTeXExecutable mpto the MetaPost to TeX converter
+% DviToMpExecutable dvitomp the DVI to MetaPost converter
+%
+% == Scripts ==
+%
+% DviSpecialScript dvispec the DVI special filter script
+%
+% == flags ==
+%
+% TeXFormatFlag -fmt= the format introducer
+% TeXVirginFlag -ini the format generation switch
+%
+% == paths ==
+%
+% TeXFormatPath texmf/... fmt files
+% ConTeXtPath texmf/tex/context/base sources
+% SetupPath texmf/tex/base/user cont-sys/usr file
+% TeXScriptsPath texmf/context/perltk scripts
+% TeXFontsPath texmf font files
+%
+% MpFormatPath TeXFormatPath mem files
+%
+% == the main shell setting ==
+%
+% As shown below, one can define his/her own sections. We default to
+% the teTeX/fpTeX web2c based settings.
+
+set TeXShell to tetex
+%set TeXShell to fptex
+%set TeXShell to miktex
+%set TeXShell to private
+
+% == setting up the variables ==
+%
+% Here are some general defaults. They can be overruled later.
+
+set UseEnginePath to true
+
+set UsedInterfaces to en nl metafun mptopdf
+set UserInterface to en
+
+set TeXExecutable to tex
+
+set MpExecutable to mpost
+set MpToTeXExecutable to mpto
+set DviToMpExecutable to dvitomp
+set DviSpecialScript to dvispec
+
+set MpFormat to metafun
+
+set TeXFormatFlag to &
+set MpFormatFlag to &
+
+% For teTeX the next settings will do.
+
+% -default-translate-file=cp8bit -file-line-error-style
+
+for tetex set TeXHashExecutable to mktexlsr
+for tetex set TeXExecutable to pdfetex
+for tetex set TeXVirginFlag to -ini
+for tetex set TeXPassString to -progname=context
+for tetex set TeXBatchFlag to -int=batchmode
+for tetex set TeXNonStopFlag to -int=nonstopmode
+for tetex set MpToTeXExecutable to mpto
+for tetex set MpVirginFlag to -ini
+for tetex set MpPassString to -progname=mpost
+for tetex set MpBatchFlag to -int=batchmode
+for tetex set MpNonStopFlag to -int=nonstopmode
+
+% These also apply to fpTeX.
+
+% -default-translate-file=cp8bit -file-line-error-style
+
+for fptex set TeXHashExecutable to mktexlsr
+for fptex set TeXExecutable to pdfetex
+for fptex set TeXVirginFlag to -ini
+for fptex set TeXPassString to -progname=context
+for fptex set TeXBatchFlag to -int=batchmode
+for fptex set TeXNonStopFlag to -int=nonstopmode
+for fptex set MpToTeXExecutable to mpto
+for fptex set MpVirginFlag to -ini
+for fptex set MpPassString to -progname=mpost
+for fptex set MpBatchFlag to -int=batchmode
+for fptex set MpNonStopFlag to -int=nonstopmode
+
+% a downward compatibility test (<7.5.3), next year we will use -8bit
+
+for tetex set TeXVirginFlag to -ini -translate-file=natural.tcx
+for fptex set TeXVirginFlag to -ini -translate-file=natural.tcx
+for tetex set MpVirginFlag to -ini -translate-file=natural.tcx
+for fptex set MpVirginFlag to -ini -translate-file=natural.tcx
+
+for tetex set TeXPassString to -progname=context -translate-file=natural.tcx
+for fptex set TeXPassString to -progname=context -translate-file=natural.tcx
+for tetex set MpPassString to -progname=mpost -translate-file=natural.tcx
+for fptex set MpPassString to -progname=mpost -translate-file=natural.tcx
+
+% MikTeX users probably have to set up some paths too.
+
+for miktex set TeXHashExecutable to initexmf --update-fndb
+for miktex set TeXExecutable to pdfetex
+for miktex set TeXVirginFlag to --initialize
+for miktex set TeXPassString to --alias=context --translate-file=natural.tcx
+for miktex set TeXBatchFlag to --interaction=batchmode
+for miktex set TeXNonStopFlag to --interaction=nonstopmode
+for miktex set MpToTeXExecutable to mptotex
+for miktex set MpVirginFlag to --initialize
+for miktex set MpPassString to --alias=mpost --translate-file=natural.tcx
+for miktex set MpBatchFlag to --interaction=batchmode
+for miktex set MpNonStopFlag to --interaction=nonstopmode
+
+for miktex set TeXFormatFlag to --undump=
+for miktex set MpFormatFlag to --undump=
+
+% These are the settings used on some machines at PRAGMA ADE that
+% don't use the texmf tree. They can serve as an example for local
+% settings. Local settings should either be added to the previous
+% one, or go without the 'for' directives. Consider these
+% settings as an example.
+
+for private set UsedInterfaces to en nl
+for private set UserInterface to nl
+for private set ConTeXtPath to t:/sources/
+for private set SetupPath to t:/perl/
+for private set TeXScriptsPath to t:/perl/
+
+% == read this too ==
+%
+% If this file is called 'texexec.rme', copy it to 'texexec.ini',
+% check the settings above, change them according to your TeX
+% distribution, and say:
+%
+% texexec --verbose
+%
+% When set up properly, you should see your local settings fly by.
+% When these settings are ok, the next call should work:
+%
+% texexec --make
+%
+% and you should be able to process a file by saying
+%
+% texexec filename
+%
+% See 'mtexexec.pdf' for more information on the flags you can use with
+% 'texexec'. Also make sure you have the 'texutil' script installed in
+% the same path as 'texexec'.
+
+% Experimental
+%
+% set TcXPath to d:/tex/texmf/web2c
+% set FmtLanguage to pl
+% set FmtBodyFont to plr
diff --git a/Master/texmf-dist/scripts/context/perl/texfind.pl b/Master/texmf-dist/scripts/context/perl/texfind.pl
new file mode 100644
index 00000000000..53a560c7954
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/perl/texfind.pl
@@ -0,0 +1,270 @@
+eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $argv:q'
+ if 0;
+
+#D \module
+#D [ file=texfind.pl,
+#D version=1998.05.10,
+#D title=\TEXFIND,
+#D subtitle=searching files,
+#D author=Hans Hagen,
+#D date=\currentdate,
+#D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+#C
+#C This module is part of the \CONTEXT\ macro||package and is
+#C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+#C details.
+
+# test with "doif(un|)defined"
+
+use strict ;
+use Getopt::Long ;
+use File::Find ;
+use Cwd ;
+use Tk ;
+use Tk::widgets ;
+use Tk::ROText ;
+
+use FindBin ;
+use lib $FindBin::Bin ;
+use path_tre ;
+
+my $FileSuffix = 'tex' ;
+my $SearchString = '' ;
+my $Recurse = 0 ;
+my $NumberOfHits = 0 ;
+my $QuitSearch = 0 ;
+my $Location = '' ;
+my $currentpath = '.' ;
+
+my @FileList ;
+
+my ($dw, $mw, $log, $sea, $fil, $num, $but, $dir, $loc) ;
+
+$mw = MainWindow -> new () ;
+$dw = MainWindow -> new () ;
+
+$mw -> protocol( 'WM_DELETE_WINDOW' => sub { exit } ) ;
+$dw -> protocol( 'WM_DELETE_WINDOW' => sub { exit } ) ;
+
+$log = $mw -> Scrolled ( 'ROText' ,
+ -scrollbars => 'se' ,
+ -font => 'courier' ,
+ -wrap => 'none' ,
+ -width => 65 ,
+ -height => 22 )
+ -> pack ( -side => 'bottom' ,
+ -padx => 2 ,
+ -pady => 2 ,
+ -expand => 1 ,
+ -fill => 'both' ) ;
+
+$sea = $mw -> Entry ( -textvariable => \$SearchString ,
+ -font => 'courier' ,
+ -width => 20 )
+ -> pack ( -side => 'left' ,
+ -padx => 2 ,
+ -pady => 2 ) ;
+
+$fil = $mw -> Entry ( -textvariable => \$FileSuffix ,
+ -font => 'courier' ,
+ -width => 5 )
+ -> pack ( -side => 'left' ,
+ -padx => 2 ,
+ -pady => 2 ) ;
+
+$but = $mw -> Checkbutton ( -variable => \$Recurse ,
+ -text => 'recurse' )
+ -> pack ( -side => 'left' ) ;
+
+$num = $mw -> Entry ( -textvariable => \$NumberOfHits ,
+ -font => 'courier' ,
+ -justify => 'right' ,
+ -width => 5 )
+ -> pack ( -side => 'right' ,
+ -padx => 2 ,
+ -pady => 2 ) ;
+
+$loc = $mw -> Entry ( -textvariable => \$Location ,
+ -font => 'courier' ,
+ -width => 8 )
+ -> pack ( -side => 'right' ,
+ -padx => 2 ,
+ -pady => 2 ) ;
+
+sub BuildDir
+ { if (Exists($dir)) { $dir -> destroy } ;
+ $dir = $dw -> Scrolled ( 'PathTree' ,
+ -scrollbars => 'se' )
+ -> pack ( -expand => 1 ,
+ -fill => 'both' ,
+ -padx => 2 ,
+ -pady => 2 ) ;
+ $dir -> configure ( -font => 'courier' ,
+ -height => 24 ,
+ -width => 65 ,
+ -selectbackground => 'blue3' ,
+ -browsecmd => \&ChangePath ) ;
+ $dir -> bind ('<Return>' , \&ShowFile ) ;
+ $dir -> bind ('<Double-1>' , \&ShowFile ) }
+
+BuildDir ;
+
+sub ShowFile { $mw -> raise ; $sea -> focusForce }
+sub ShowPath { $dw -> raise ; $dir -> focusForce }
+
+$log -> tagConfigure ( 'found', -foreground => 'green3' ) ;
+$log -> tagConfigure ( 'title', -foreground => 'blue3' ) ;
+
+$sea -> bind ('<Return>' , \&LocateStrings ) ;
+$fil -> bind ('<Return>' , \&LocateStrings ) ;
+$loc -> bind ('<Return>' , \&ChangeLocation ) ;
+$log -> bind ('<Return>' , \&ShowPath ) ;
+
+$sea -> bind ('<KeyPress>' , \&QuitSearch ) ;
+$fil -> bind ('<KeyPress>' , \&QuitSearch ) ;
+$loc -> bind ('<KeyPress>' , \&QuitSearch ) ;
+
+$sea -> bind ('<Escape>' , \&QuitSearch ) ;
+$fil -> bind ('<Escape>' , \&QuitSearch ) ;
+$loc -> bind ('<Escape>' , \&QuitSearch ) ;
+$log -> bind ('<Escape>' , \&QuitSearch ) ;
+
+$sea -> bind ('<Double-1>' , \&LocateStrings ) ;
+$fil -> bind ('<Double-1>' , \&LocateStrings ) ;
+$loc -> bind ('<Double-1>' , \&ChangeLocation ) ;
+$log -> bind ('<Double-1>' , \&ShowPath ) ;
+
+sub ChangePath
+ { my $currentpath = shift ;
+chdir($currentpath) ;
+ $QuitSearch = 1 ;
+ $log -> delete ('1.0', 'end') ;
+ $log -> insert ('end', "$currentpath\n\n", 'title') }
+
+sub ChangeLocation
+ { $QuitSearch = 1 ;
+ $log -> delete ('1.0', 'end') ;
+ $Location =~ s/^\s*//o ;
+ $Location =~ s/\s*$//o ;
+ $Location =~ s/(\\|\/\/)/\//go ;
+ unless (-d $Location)
+ { unless ($Location =~ /\//) { $Location .= '/' } }
+ if (-d $Location)
+ { $log -> insert ('end', "changed to location '$Location'\n\n", 'title') ;
+ $currentpath = $Location ;
+ chdir ($currentpath) ;
+ $dir -> destroy ;
+ BuildDir ;
+ $dw -> raise ;
+ $dw -> focusForce }
+ else
+ { $log -> insert ('end', "unknown location '$Location'\n\n", 'title') ;
+ $Location = '' } }
+
+sub QuitSearch
+ { $QuitSearch = 1 }
+
+sub SearchFile
+ { my ($FileName, $SearchString) = @_ ;
+ my $Ok = 0 ; my $len ;
+ open (TEX, $FileName) ;
+ my $LineNumber = 0 ;
+ while (<TEX>)
+ { ++$LineNumber ;
+ if ($QuitSearch)
+ { if ($Ok) { $log -> see ('end') }
+ last }
+ if (/$SearchString/i)
+ { ++$NumberOfHits ; $num -> update ;
+ unless ($Ok)
+ { $Ok = 1 ;
+ $log -> insert ('end', "$FileName\n\n",'title') }
+ $log -> insert ('end', sprintf("%5i : ",$LineNumber), 'title') ;
+ s/^\s*//o ;
+#
+ $len = 0 ;
+ while (/(.*?)($SearchString)/gi)
+ { $len += length($1) + length($2) ;
+ $log -> insert ('end', "$1") ;
+ $log -> insert ('end', "$2", 'found' ) }
+ $_ = substr($_,$len) ;
+ $log -> insert ('end', "$_") ;
+#
+ $log -> update ;
+ $log -> see ('end') } }
+ if ($Ok) { $log -> insert ('end', "\n") }
+ close (TEX) }
+
+sub DoLocateFiles
+ { @FileList = () ;
+ $NumberOfHits = 0 ;
+ if ($FileSuffix ne "")
+ { $log -> delete ('1.0', 'end') ;
+ if ($Recurse)
+ { $log -> insert ('end', "recursively identifying files\n", 'title') ;
+ $log -> see ('end') ;
+ find (\&wanted, $currentpath) ;
+ sub wanted
+ { if ($QuitSearch) { last ; return }
+ if (/.*\.$FileSuffix/i)
+ { ++$NumberOfHits ; $num -> update ;
+ push @FileList, $File::Find::name } } }
+ else
+ { $log -> insert ('end', "identifying files\n", 'title') ;
+ $log -> see ('end') ;
+ opendir(DIR, $currentpath) ; my @TEMPLIST = readdir(DIR) ; closedir(DIR) ;
+ foreach my $FileName (@TEMPLIST)
+ { if ($FileName =~ /.*\.$FileSuffix/i)
+ { ++$NumberOfHits ; $num -> update ;
+ if ($QuitSearch)
+ { last }
+ push @FileList, $FileName } } }
+ @FileList = sort @FileList } }
+
+sub DoLocateStrings
+ { $log -> delete ('1.0', 'end') ;
+ $log -> update ;
+ $log -> see ('end') ;
+ $NumberOfHits = 0 ;
+ if ($SearchString ne "")
+ { foreach my $FileName (@FileList)
+ { if ($QuitSearch)
+ { $log -> insert ('end', "search aborted\n", 'title') ;
+ $log -> see ('end') ;
+ last }
+ SearchFile($FileName,$SearchString) } }
+ unless ($QuitSearch)
+ { $log -> insert ('end', "done\n", 'title') ;
+ $log -> see ('end') } }
+
+sub LocateStrings
+ { $QuitSearch = 0 ;
+ DoLocateFiles() ;
+ DoLocateStrings() }
+
+$log -> insert ('end',
+
+ "data fields\n\n" , '' ,
+
+
+ "string :", 'title', " regular expression to search for\n" , '' ,
+ "suffix :", 'title', " type of file to search in\n" , '' ,
+ "recurse :", 'title', " enable searching subpaths\n" , '' ,
+ "location :", 'title', " drive of root path\n" , '' ,
+ "counter :", 'title', " file/hit counter\n\n" , '' ,
+
+ "key bindings\n\n" , '' ,
+
+ "double 1 :", 'title', " directory window <-> search window\n" , '' ,
+ "enter :", 'title', " start searching\n" , '' ,
+ "escape :", 'title', " quit searching\n\n" , '' ,
+
+ "current path\n\n" , '' ,
+
+ cwd(), 'title', "\n\n" , 'title' ) ;
+
+$log -> update ;
+
+ShowPath ;
+
+MainLoop() ;
diff --git a/Master/texmf-dist/scripts/context/perl/texfont.pl b/Master/texmf-dist/scripts/context/perl/texfont.pl
new file mode 100644
index 00000000000..425417374de
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/perl/texfont.pl
@@ -0,0 +1,1154 @@
+eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $argv:q'
+ if 0;
+
+# This is an example of a crappy unstructured file but once
+# I know what should happen exactly, I will clean it up.
+
+# once it works all right, afmpl will be default
+
+# todo : ttf (partially doen already)
+
+# added: $pattern in order to avoid fuzzy shelle expansion of
+# filenames (not consistent over perl and shells); i hate that
+# kind of out of control features.
+
+#D \module
+#D [ file=texfont.pl,
+#D version=2004.02.06, % 2000.12.14
+#D title=Font Handling,
+#D subtitle=installing and generating,
+#D author=Hans Hagen ++,
+#D date=\currentdate,
+#D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+#C
+#C This module is part of the \CONTEXT\ macro||package and is
+#C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+#C details.
+
+#D For usage information, see \type {mfonts.pdf}.
+
+#D Todo : copy afm/pfb from main to local files to ensure metrics
+#D Todo : Wybo's help system
+#D Todo : list of encodings [texnansi, ec, textext]
+
+#D Thanks to George N. White III for solving a couple of bugs.
+#D Thanks to Adam T. Lindsay for adding Open Type support (and more).
+
+use strict ;
+
+my $savedoptions = join (" ",@ARGV) ;
+
+use Config ;
+use FindBin ;
+use File::Copy ;
+use Getopt::Long ;
+
+$Getopt::Long::passthrough = 1 ; # no error message
+$Getopt::Long::autoabbrev = 1 ; # partial switch accepted
+
+# Unless a user has specified an installation path, we take
+# the dedicated font path or the local path.
+
+## $dosish = ($Config{'osname'} =~ /dos|mswin/i) ;
+my $dosish = ($Config{'osname'} =~ /^(ms)?dos|^os\/2|^(ms|cyg)win/i) ;
+
+my $IsWin32 = ($^O =~ /MSWin32/i);
+my $SpacyPath = 0 ;
+
+# great, the win32api is not present in all perls
+
+BEGIN {
+ $IsWin32 = ($^O =~ /MSWin32/i) ;
+ $SpacyPath = 0 ;
+ if ($IsWin32) {
+ my $str = `kpsewhich -expand-path=\$TEXMF` ;
+ $SpacyPath = ($str =~ / /) ;
+ if ($SpacyPath) {
+ require Win32::API; import Win32::API;
+ }
+ }
+}
+
+# great, glob changed to bsd glob in an incompatible way ... sigh, we now
+# have to catch a failed glob returning the pattern
+#
+# to stupid either:
+#
+# sub validglob {
+# my @globbed = glob(shift) ;
+# if ((@globbed) && (! -e $globbed[0])) {
+# return () ;
+# } else {
+# return @globbed ;
+# }
+# }
+#
+# so now we have:
+
+sub validglob {
+ my @globbed = glob(shift) ;
+ my @globout = () ;
+ foreach my $file (@globbed) {
+ push (@globout,$file) if (-e $file) ;
+ }
+ return @globout ;
+}
+
+sub GetShortPathName {
+ my ($filename) = @_ ;
+ return $filename unless (($IsWin32)&&($SpacyPath)) ;
+ my $GetShortPathName = new Win32::API('kernel32', 'GetShortPathName', 'PPN', 'N') ;
+ if(not defined $GetShortPathName) {
+ die "Can't import API GetShortPathName: $!\n" ;
+ }
+ my $buffer = " " x 260;
+ my $len = $GetShortPathName->Call($filename, $buffer, 260) ;
+ return substr($buffer, 0, $len) ;
+}
+
+my $installpath = "" ;
+
+if (defined($ENV{TEXMFLOCAL})) {
+ $installpath = "TEXMFLOCAL" ;
+}
+
+if (defined($ENV{TEXMFFONTS})) {
+ $installpath = "TEXMFFONTS" ;
+}
+
+if ($installpath eq "") {
+ $installpath = "TEXMFLOCAL" ; # redundant
+}
+
+my $encoding = "texnansi" ;
+my $vendor = "" ;
+my $collection = "" ;
+my $fontroot = "" ; #/usr/people/gwhite/texmf-fonts" ;
+my $help = 0 ;
+my $makepath = 0 ;
+my $show = 0 ;
+my $install = 0 ;
+my $sourcepath = "." ;
+my $passon = "" ;
+my $extend = "" ;
+my $narrow = "" ;
+my $slant = "" ;
+my $spaced = "" ;
+my $caps = "" ;
+my $noligs = 0 ;
+my $test = 0 ;
+my $virtual = 0 ;
+my $novirtual = 0 ;
+my $listing = 0 ;
+my $remove = 0 ;
+my $expert = 0 ;
+my $trace = 0 ;
+my $afmpl = 0 ;
+my $trees = 'TEXMFFONTS,TEXMFLOCAL,TEXMFEXTRA,TEXMFMAIN,TEXMFDIST' ;
+my $pattern = '' ;
+
+my $fontsuffix = "" ;
+my $namesuffix = "" ;
+
+my $batch = "" ;
+
+my $weight = "" ;
+my $width = "" ;
+
+my $preproc = 0 ; # atl: formerly OpenType switch
+my $variant = "" ; # atl: encoding variant
+my $extension = "pfb" ; # atl: default font extension
+my $lcdf = "" ; # atl: trigger for lcdf otftotfm
+
+my @cleanup = () ; # atl: build list of generated files to delete
+
+# todo: parse name for style, take face from command line
+#
+# @Faces = ("Serif","Sans","Mono") ;
+# @Styles = ("Slanted","Spaced", "Italic","Bold","BoldSlanted","BoldItalic") ;
+#
+# for $fac (@Faces) { for $sty (@Styles) { $FacSty{"$fac$sty"} = "" } }
+
+&GetOptions
+ ( "help" => \$help,
+ "makepath" => \$makepath,
+ "noligs" => \$noligs,
+ "show" => \$show,
+ "install" => \$install,
+ "encoding=s" => \$encoding,
+ "variant=s" => \$variant, # atl: used as a suffix to $encfile only
+ "vendor=s" => \$vendor,
+ "collection=s" => \$collection,
+ "fontroot=s" => \$fontroot,
+ "sourcepath=s" => \$sourcepath,
+ "passon=s" => \$passon,
+ "slant=s" => \$slant,
+ "spaced=s" => \$spaced,
+ "extend=s" => \$extend,
+ "narrow=s" => \$narrow,
+ "listing" => \$listing,
+ "remove" => \$remove,
+ "test" => \$test,
+ "virtual" => \$virtual,
+ "novirtual" => \$novirtual,
+ "caps=s" => \$caps,
+ "batch" => \$batch,
+ "weight=s" => \$weight,
+ "width=s" => \$width,
+ "expert" => \$expert,
+ "afmpl" => \$afmpl,
+ "afm2pl" => \$afmpl,
+ "rootlist=s" => \$trees,
+ "pattern=s" => \$pattern,
+ "trace" => \$trace, # --verbose conflicts with --ve
+ "preproc" => \$preproc, # atl: trigger conversion to pfb
+ "lcdf" => \$lcdf ) ; # atl: trigger use of lcdf fonttoools
+
+# for/from Fabrice:
+
+my $own_path = "$FindBin::Bin/" ;
+
+$FindBin::RealScript =~ m/([^\.]*)(\.pl|\.bat|\.exe|)/io ;
+
+my $own_name = $1 ;
+my $own_type = $2 ;
+my $own_stub = "" ;
+
+if ($own_type =~ /pl/oi) {
+ $own_stub = "perl "
+}
+
+if ($caps) { $afmpl = 0 } # for the moment
+
+# so we can use both combined
+
+if ($lcdf) {
+ $novirtual = 1 ;
+}
+
+if (!$novirtual) {
+ $virtual = 1 ;
+}
+
+# A couple of routines.
+
+sub report {
+ my $str = shift ;
+ $str =~ s/ / /goi ;
+ if ($str =~ /(.*?)\s+([\:\/])\s+(.*)/o) {
+ if ($1 eq "") {
+ $str = " " ;
+ } else {
+ $str = $2 ;
+ }
+ print sprintf("%22s $str %s\n",$1,$3) ;
+ }
+}
+
+sub error {
+ report("processing aborted : " . shift) ;
+ print "\n" ;
+ report "--help : show some more info" ;
+ exit ;
+}
+
+# The banner.
+
+print "\n" ;
+report ("TeXFont 2.2.1 - ConTeXt / PRAGMA ADE 2000-2004") ;
+print "\n" ;
+
+# Handy for scripts: one can provide a preferred path, if it
+# does not exist, the current path is taken.
+
+if (!(-d $sourcepath)&&($sourcepath ne 'auto')) { $sourcepath = "." }
+
+# Let's make multiple masters if requested.
+
+sub create_mm_font
+ { my ($name,$weight,$width) = @_ ; my $flag = my $args = my $tags = "" ;
+ my $ok ;
+ if ($name ne "")
+ { report ("mm source file : $name") }
+ else
+ { error ("missing mm source file") }
+ if ($weight ne "")
+ { report ("weight : $weight") ;
+ $flag .= " --weight=$weight " ;
+ $tags .= "-weight-$weight" }
+ if ($width ne "")
+ { report ("width : $width") ;
+ $flag .= " --width=$width " ;
+ $tags .= "-width-$width" }
+ error ("no specification given") if ($tags eq "") ;
+ error ("no amfm file found") unless (-f "$sourcepath/$name.amfm") ;
+ error ("no pfb file found") unless (-f "$sourcepath/$name.pfb") ;
+ $args = "$flag --precision=5 --kern-precision=0 --output=$sourcepath/$name$tags.afm" ;
+ my $command = "mmafm $args $sourcepath/$name.amfm" ;
+ print "$command\n" if $trace ;
+ $ok = `$command` ; chomp $ok ;
+ if ($ok ne "") { report ("warning $ok") }
+ $args = "$flag --precision=5 --output=$sourcepath/$name$tags.pfb" ;
+ $command = "mmpfb $args $sourcepath/$name.pfb" ;
+ print "$command\n" if $trace ;
+ $ok = `$command` ; chomp $ok ;
+ if ($ok ne "") { report ("warning $ok") }
+ report ("mm result file : $name$tags") }
+
+if (($weight ne "")||($width ne ""))
+ { create_mm_font($ARGV[0],$weight,$width) ;
+ exit }
+
+# go on
+
+if (($listing||$remove)&&($sourcepath eq "."))
+ { $sourcepath = "auto" }
+
+if ($fontroot eq "")
+ { if ($dosish)
+ { $fontroot = `kpsewhich -expand-path=\$$installpath` }
+ else
+ { $fontroot = `kpsewhich -expand-path=\\\$$installpath` }
+ chomp $fontroot }
+
+
+if ($fontroot =~ /\s+/) # needed for windows, spaces in name
+ { $fontroot = &GetShortPathName($fontroot) } # but ugly when not needed
+
+if ($test)
+ { $vendor = $collection = "test" ;
+ $install = 1 }
+
+if (($spaced ne "") && ($spaced !~ /\d/)) { $spaced = "50" }
+if (($slant ne "") && ($slant !~ /\d/)) { $slant = "0.167" }
+if (($extend ne "") && ($extend !~ /\d/)) { $extend = "1.200" }
+if (($narrow ne "") && ($narrow !~ /\d/)) { $narrow = "0.800" }
+if (($caps ne "") && ($caps !~ /\d/)) { $caps = "0.800" }
+
+$encoding = lc $encoding ;
+$vendor = lc $vendor ;
+$collection = lc $collection ;
+
+if ($encoding =~ /default/oi) { $encoding = "texnansi" }
+
+my $lcfontroot = lc $fontroot ;
+
+# Auto search paths
+
+my @trees = split(/\,/,$trees) ;
+
+# Test for help asked.
+
+if ($help)
+ { report "--fontroot=path : texmf destination font root (default: $lcfontroot)" ;
+ report "--rootlist=paths : texmf source roots (default: $trees)" ;
+ report "--sourcepath=path : when installing, copy from this path (default: $sourcepath)" ;
+ report "--sourcepath=auto : locate and use vendor/collection" ;
+ print "\n" ;
+ report "--vendor=name : vendor name/directory" ;
+ report "--collection=name : font collection" ;
+ report "--encoding=name : encoding vector (default: $encoding)" ;
+ report "--variant=name : encoding variant (.enc file or otftotfm features)" ;
+ print "\n" ;
+ report "--spaced=s : space glyphs in font by promille of em (0 - 1000)" ;
+ report "--slant=s : slant glyphs in font by factor (0.0 - 1.5)" ;
+ report "--extend=s : extend glyphs in font by factor (0.0 - 1.5)" ;
+ report "--caps=s : capitalize lowercase chars by factor (0.5 - 1.0)" ;
+ report "--noligs : remove ligatures" ;
+ print "\n" ;
+ report "--install : copy files from source to font tree" ;
+ report "--listing : list files on auto sourcepath" ;
+ report "--remove : remove files on auto sourcepath" ;
+ report "--makepath : when needed, create the paths" ;
+ print "\n" ;
+ report "--test : use test paths for vendor/collection" ;
+ report "--show : run tex on texfont.tex" ;
+ print "\n" ;
+ report "--batch : process given batch file" ;
+ print "\n" ;
+ report "--weight : multiple master weight" ;
+ report "--width : multiple master width" ;
+ print "\n" ;
+ report "--expert : also handle expert fonts" ;
+ print "\n" ;
+ report "--afmpl : use afm2pl instead of afm2tfm" ;
+ report "--preproc : pre-process ttf/otf, converting them to pfb" ;
+ report "--lcdf : use lcdf fonttools to create virtual encoding" ;
+ exit }
+
+if (($batch)||(($ARGV[0]) && ($ARGV[0] =~ /.+\.dat$/io)))
+ { my $batchfile = $ARGV[0] ;
+ unless (-f $batchfile)
+ { if ($batchfile !~ /\.dat$/io) { $batchfile .= ".dat" } }
+ unless (-f $batchfile)
+ { report ("trying to locate : $batchfile") ;
+ $batchfile = `kpsewhich -format="other text files" -progname=context $batchfile` ;
+ chomp $batchfile }
+ error ("unknown batch file $batchfile") unless -e $batchfile ;
+ report ("processing batch file : $batchfile") ;
+ my $select = (($vendor ne "")||($collection ne "")) ;
+ my $selecting = 0 ;
+ if (open(BAT, $batchfile))
+ { while (<BAT>)
+ { chomp ;
+ s/(.+)\#.*/$1/o ;
+ next if (/^\s*$/io) ;
+ if ($select)
+ { if ($selecting)
+ { if (/^\s*[\#\%]/io) { if (!/\-\-/o) { last } else { next } } }
+ elsif ((/^\s*[\#\%]/io)&&(/$vendor/i)&&(/$collection/i))
+ { $selecting = 1 ; next }
+ else
+ { next } }
+ else
+ { next if (/^\s*[\#\%]/io) ;
+ next unless (/\-\-/oi) }
+ s/\s+/ /gio ;
+ s/(--en.*\=)\?/$1$encoding/io ;
+ report ("batch line : $_") ;
+ # system ("perl $0 --fontroot=$fontroot $_") }
+ my $own_quote = ( $own_path =~ m/^[^\"].* / ? "\"" : "" );
+ my $switches = '' ;
+ $switches .= "--afmpl " if $afmpl ;
+ system ("$own_stub$own_quote$own_path$own_name$own_type$own_quote $switches --fontroot=$fontroot $_") }
+ close (BAT) }
+ exit }
+
+error ("unknown vendor $vendor") unless $vendor ;
+error ("unknown collection $collection") unless $collection ;
+error ("unknown tex root $lcfontroot") unless -d $fontroot ;
+
+my $varlabel = $variant ;
+
+if ($lcdf)
+ { $varlabel =~ s/,/-/goi ;
+ $varlabel =~ tr/a-z/A-Z/ }
+
+if ($varlabel ne "")
+ { $varlabel = "-$varlabel" }
+
+my $identifier = "$encoding$varlabel-$vendor-$collection" ;
+
+my $outlinepath = $sourcepath ; my $path = "" ;
+
+my $shape = "" ;
+
+if ($noligs)
+ { report ("ligatures : removed") ;
+ $fontsuffix .= "-unligatured" ;
+ $namesuffix .= "-NoLigs" }
+
+if ($caps ne "")
+ { if ($caps <0.5) { $caps = 0.5 }
+ elsif ($caps >1.0) { $caps = 1.0 }
+ $shape .= " -c $caps " ;
+ report ("caps factor : $caps") ;
+ $fontsuffix .= "-capitalized-" . int(1000*$caps) ;
+ $namesuffix .= "-Caps" }
+
+if ($extend ne "")
+ { if ($extend<0.0) { $extend = 0.0 }
+ elsif ($extend>1.5) { $extend = 1.5 }
+ report ("extend factor : $extend") ;
+ if ($lcdf)
+ { $shape .= " -E $extend " }
+ else
+ { $shape .= " -e $extend " }
+ $fontsuffix .= "-extended-" . int(1000*$extend) ;
+ $namesuffix .= "-Extended" }
+
+if ($narrow ne "") # goodie
+ { $extend = $narrow ;
+ if ($extend<0.0) { $extend = 0.0 }
+ elsif ($extend>1.5) { $extend = 1.5 }
+ report ("narrow factor : $extend") ;
+ if ($lcdf)
+ { $shape .= " -E $extend " }
+ else
+ { $shape .= " -e $extend " }
+ $fontsuffix .= "-narrowed-" . int(1000*$extend) ;
+ $namesuffix .= "-Narrowed" }
+
+if ($slant ne "")
+ { if ($slant <0.0) { $slant = 0.0 }
+ elsif ($slant >1.5) { $slant = 1.5 }
+ report ("slant factor : $slant") ;
+ if ($lcdf)
+ { $shape .= " -S $slant " }
+ else
+ { $shape .= " -s $slant " }
+ $fontsuffix .= "-slanted-" . int(1000*$slant) ;
+ $namesuffix .= "-Slanted" }
+
+if ($spaced ne "")
+ { if ($spaced < 0) { $spaced = 0 }
+ elsif ($spaced >1000) { $spaced = 1000 }
+ report ("space factor : $spaced") ;
+ if ($lcdf)
+ { $shape .= " -L $spaced " }
+ else
+ { $shape .= " -m $spaced " }
+ $fontsuffix .= "-spaced-" . $spaced ;
+ $namesuffix .= "-Spaced" }
+
+if ($sourcepath eq "auto") # todo uppercase root
+ { foreach my $root (@trees)
+ { if ($dosish)
+ { $path = `kpsewhich -expand-path=\$$root` }
+ else
+ { $path = `kpsewhich -expand-path=\\\$$root` }
+ chomp $path ;
+ $path = $ENV{$root} if (($path eq '') && defined($ENV{$root})) ;
+ report ("checking root : $root") ;
+ if ($preproc)
+ { $sourcepath = "$path/fonts/truetype/$vendor/$collection" }
+ else
+ { $sourcepath = "$path/fonts/afm/$vendor/$collection" }
+ unless (-d $sourcepath)
+ { my $ven = $vendor ; $ven =~ s/(........).*/$1/ ;
+ my $col = $collection ; $col =~ s/(........).*/$1/ ;
+ $sourcepath = "$path/fonts/afm/$ven/$col" ;
+ if (-d $sourcepath)
+ { $vendor = $ven ; $collection = $col } }
+ $outlinepath = "$path/fonts/type1/$vendor/$collection" ;
+ if (-d $sourcepath)
+ { # $install = 0 ; # no copy needed
+ $makepath = 1 ; # make on local if needed
+ my @files = validglob("$sourcepath/*.afm") ;
+ if ($preproc)
+ { @files = validglob("$sourcepath/*.otf") ;
+ report("locating : otf files") }
+ unless (@files)
+ { @files = validglob("$sourcepath/*.ttf") ;
+ report("locating : ttf files") }
+ if (@files)
+ { if ($listing)
+ { report ("fontpath : $sourcepath" ) ;
+ print "\n" ;
+ foreach my $file (@files)
+ { if (open(AFM,$file))
+ { my $name = "unknown name" ;
+ while (<AFM>)
+ { chomp ;
+ if (/^fontname\s+(.*?)$/oi)
+ { $name = $1 ; last } }
+ close (AFM) ;
+ if ($preproc)
+ { $file =~ s/.*\/(.*)\..tf/$1/io }
+ else
+ { $file =~ s/.*\/(.*)\.afm/$1/io }
+ report ("$file : $name") } }
+ exit }
+ elsif ($remove)
+ { error ("no removal from : $root") if ($root eq 'TEXMFMAIN') ;
+ foreach my $file (@files)
+ { if ($preproc)
+ { $file =~ s/.*\/(.*)\..tf/$1/io }
+ else
+ { $file =~ s/.*\/(.*)\.afm/$1/io }
+ foreach my $sub ("tfm","vf")
+ { foreach my $typ ("","-raw")
+ { my $nam = "$path/fonts/$sub/$vendor/$collection/$encoding$varlabel$typ-$file.$sub" ;
+ # { my $nam = "$path/fonts/$sub/$vendor/$collection/$encoding$varlabel$typ-$file$fontsuffix.$sub" ;
+ if (-s $nam)
+ { report ("removing : $encoding$varlabel$typ-$file.$sub") ;
+ unlink $nam } } } }
+ my $nam = "$encoding$varlabel-$vendor-$collection.tex" ;
+ if (-e $nam)
+ { report ("removing : $nam") ;
+ unlink "$nam" }
+ my $mapfile = "$encoding$varlabel-$vendor-$collection" ;
+ my $maproot = "$fontroot/fonts/map/pdftex/context";
+ if (-e "$maproot$mapfile.map")
+ { report ("renaming : $mapfile.map -> $mapfile.bak") ;
+ unlink "$maproot$mapfile.bak" ;
+ rename "$maproot$mapfile.map", "$maproot$mapfile.bak" }
+ exit }
+ else
+ { last } } } }
+ error ("unknown subpath ../fonts/afm/$vendor/$collection") unless -d $sourcepath }
+
+error ("unknown source path $sourcepath") unless -d $sourcepath ;
+error ("unknown option $ARGV[0]") if (($ARGV[0]||'') =~ /\-\-/) ;
+
+my $afmpath = "$fontroot/fonts/afm/$vendor/$collection" ;
+my $tfmpath = "$fontroot/fonts/tfm/$vendor/$collection" ;
+my $vfpath = "$fontroot/fonts/vf/$vendor/$collection" ;
+my $pfbpath = "$fontroot/fonts/type1/$vendor/$collection" ;
+my $ttfpath = "$fontroot/fonts/truetype/$vendor/$collection" ;
+my $mappath = "$fontroot/fonts/map/pdftex/context" ;
+my $encpath = "$fontroot/fonts/enc/dvips/context" ;
+
+# are not on local path ! ! ! !
+
+foreach my $path ($afmpath, $pfbpath)
+ { my @gzipped = <$path/*.gz> ;
+ foreach my $file (@gzipped)
+ { print "file = $file\n";
+ system ("gzip -d $file") } }
+
+# For gerben, we only generate a new database when an lsr file is present but for
+# myself we force this when texmf-fonts is used (else I get compatibility problems).
+
+if (($fontroot =~ /texmf\-fonts/o) || (-e "$fontroot/ls-R") || (-e "$fontroot/ls-r") || (-e "$fontroot/LS-R")) {
+ system ("mktexlsr $fontroot") ;
+}
+
+sub do_make_path
+ { my $str = shift ;
+ if ($str =~ /^(.*)\/.*?$/)
+ { do_make_path($1) }
+ mkdir $str, 0755 unless -d $str }
+
+sub make_path
+ { my $str = shift ;
+ do_make_path("$fontroot/fonts") ;
+ do_make_path("$fontroot/fonts/$str") ;
+ do_make_path("$fontroot/fonts/$str/$vendor") ;
+ do_make_path("$fontroot/fonts/$str/$vendor/$collection") }
+
+if ($makepath&&$install)
+ { make_path ("afm") ; make_path ("type1") }
+
+do_make_path($mappath) ;
+do_make_path($encpath) ;
+
+# now fonts/map and fonts/enc
+
+make_path ("vf") ;
+make_path ("tfm") ;
+
+if ($install)
+ { error ("unknown afm path $afmpath") unless -d $afmpath ;
+ error ("unknown pfb path $pfbpath") unless -d $pfbpath }
+
+error ("unknown tfm path $tfmpath") unless -d $tfmpath ;
+error ("unknown vf path $vfpath" ) unless -d $vfpath ;
+error ("unknown map path $mappath") unless -d $mappath ;
+
+my $mapfile = "$identifier.map" ;
+my $bakfile = "$identifier.bak" ;
+my $texfile = "$identifier.tex" ;
+
+ report "encoding vector : $encoding" ;
+if ($variant) { report "encoding variant : $variant" }
+ report "vendor name : $vendor" ;
+ report " source path : $sourcepath" ;
+ report "font collection : $collection" ;
+ report "texmf font root : $lcfontroot" ;
+ report "pdftex map file : $mapfile" ;
+
+if ($install) { report "source path : $sourcepath" }
+
+my $fntlist = "" ;
+
+my $runpath = $sourcepath ;
+
+my @files ;
+
+sub UnLink
+ { foreach my $f (@_)
+ { if (unlink $f)
+ { report "deleted : $f" if $trace } } }
+
+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 $runpath/$pattern.*tf");
+ unless (@files)
+ { @files = validglob("$sourcepath/$pattern.ttf") ;
+ report("locating ttf files : using pattern $sourcepath/$pattern.ttf") }
+ }
+ if (@files) # also elsewhere
+ { report("locating afm files : using pattern $pattern") }
+ else
+ { @files = validglob("$runpath/$pattern.ttf") ;
+ if (@files)
+ { report("locating afm files : using ttf files") ;
+ $extension = "ttf" ;
+ foreach my $file (@files)
+ { $file =~ s/\.ttf$//io ;
+ report ("generating afm file : $file.afm") ;
+ my $command = "ttf2afm \"$file.ttf\" -o \"$file.afm\"" ;
+ system($command) ;
+ print "$command\n" if $trace ;
+ push(@cleanup, "$file.afm") }
+ @files = validglob("$runpath/$pattern.afm") }
+ else # try doing the pre-processing earlier
+ { report("locating afm files : using otf files") ;
+ $extension = "otf" ;
+ @files = validglob("$runpath/$pattern.otf") ;
+ foreach my $file (@files)
+ { $file =~ s/\.otf$//io ;
+ if (!$lcdf)
+ { report ("generating afm file : $file.afm") ;
+ preprocess_font("$file.otf", "$file.bdf") ;
+ push(@cleanup,"$file.afm") }
+ if ($preproc)
+ { my $command = "cfftot1 --output=$file.pfb $file.otf" ;
+ print "$command\n" if $trace ;
+ report("converting : $file.otf to $file.pfb") ;
+ system($command) ;
+ push(@cleanup, "$file.pfb") ;
+ }
+ }
+ if ($lcdf)
+ { @files = validglob("$runpath/$pattern.otf") }
+ else
+ { @files = validglob("$runpath/$pattern.afm") }
+ }
+ }
+ return @files }
+
+if ($pattern eq '') { if ($ARGV[0]) { $pattern = $ARGV[0] } }
+
+if ($pattern ne '')
+ { report ("processing files : all in pattern $pattern") ;
+ @files = globafmfiles($runpath,$pattern) }
+elsif ("$extend$narrow$slant$spaced$caps" ne "")
+ { error ("transformation needs file spec") }
+else
+ { $pattern = "*" ;
+ report ("processing files : all on afm path") ;
+ @files = globafmfiles($runpath,$pattern) }
+
+sub copy_files
+ { my ($suffix,$sourcepath,$topath) = @_ ;
+ my @files = validglob("$sourcepath/$pattern.$suffix") ;
+ return if ($topath eq $sourcepath) ;
+ report ("copying files : $suffix") ;
+ foreach my $file (@files)
+ { my $ok = $file =~ /(.*)\/(.+?)\.(.*)/ ;
+ my ($path,$name,$suffix) = ($1,$2,$3) ;
+ UnLink "$topath/$name.$suffix" ;
+ report ("copying : $name.$suffix") ;
+ copy ($file,"$topath/$name.$suffix") } }
+
+if ($install)
+ { copy_files("afm",$sourcepath,$afmpath) ;
+# copy_files("tfm",$sourcepath,$tfmpath) ; # raw supplied names
+ copy_files("pfb",$outlinepath,$pfbpath) ;
+ if ($extension eq "ttf")
+ { make_path("truetype") ;
+ copy_files("ttf",$sourcepath,$ttfpath) }
+ if ($extension eq "otf")
+ { make_path("truetype") ;
+ copy_files("otf",$sourcepath,$ttfpath) } }
+
+error ("no afm files found") unless @files ;
+
+my $map = my $tex = 0 ; my $mapdata = my $texdata = "" ;
+
+copy ("$mappath/$mapfile","$mappath/$bakfile") ;
+
+if (open (MAP,"<$mappath/$mapfile"))
+ { report ("extending map file : $mappath/$mapfile") ;
+ while (<MAP>) { unless (/^\%/o) { $mapdata .= $_ } }
+ close (MAP) }
+else
+ { report ("no map file at : $mappath/$mapfile") }
+
+if (open (TEX,"<$texfile"))
+ { while (<TEX>) { unless (/stoptext/o) { $texdata .= $_ } }
+ close (TEX) }
+
+$map = open (MAP,">$mapfile") ;
+$tex = open (TEX,">$texfile") ;
+
+unless ($map) { report "warning : can't open $mapfile" }
+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 your file:\n" ;
+ print MAP "%\n" ;
+ print MAP "% \\pdfmapfile{+$mapfile}\n" ;
+ print MAP "%\n" ;
+ print MAP "% In ConTeXt you can best use:\n" ;
+ print MAP "%\n" ;
+ print MAP "% \\loadmapfile\[$mapfile\]\n\n" }
+
+if ($tex)
+ { if ($texdata eq "")
+ { print TEX "% output=pdftex interface=en\n" ;
+ print TEX "\n" ;
+ print TEX "\\usemodule[fnt-01]\n" ;
+ print TEX "\n" ;
+ print TEX "\\loadmapfile[$mapfile]\n" ;
+ print TEX "\n" ;
+ print TEX "\\starttext\n\n" }
+ else
+ { print TEX "$texdata" ;
+ print TEX "\n\%appended section\n\n\\page\n\n" } }
+
+sub removeligatures
+ { my $filename = shift ; my $skip = 0 ;
+ copy ("$filename.vpl","$filename.tmp") ;
+ if ((open(TMP,"<$filename.tmp"))&&(open(VPL,">$filename.vpl")))
+ { report "removing ligatures : $filename" ;
+ while (<TMP>)
+ { chomp ;
+ if ($skip)
+ { if (/^\s*\)\s*$/o) { $skip = 0 ; print VPL "$_\n" } }
+ elsif (/\(LIGTABLE/o)
+ { $skip = 1 ; print VPL "$_\n" }
+ else
+ { print VPL "$_\n" } }
+ close(TMP) ; close(VPL) }
+ UnLink ("$filename.tmp") }
+
+my $raw = my $use = my $maplist = my $texlist = my $report = "" ;
+
+$use = "$encoding$varlabel-" ; $raw = $use . "raw-" ;
+
+my $encfil = "" ;
+
+if ($encoding ne "") # evt -progname=context
+ { $encfil = `kpsewhich -progname=pdftex $encoding$varlabel.enc` ;
+ chomp $encfil ; if ($encfil eq "") { $encfil = "$encoding$varlabel.enc" } }
+
+sub preprocess_font
+ { my ($infont,$pfbfont) = @_ ;
+ if ($infont ne "")
+ { report ("otf/ttf source file : $infont") ;
+ report ("destination file : $pfbfont") ; }
+ else
+ { error ("missing otf/ttf source file") }
+ open (CONVERT, "| pfaedit -script -") || error ("couldn't open pipe to pfaedit") ;
+ report ("pre-processing with : pfaedit") ;
+ print CONVERT "Open('$infont');\n Generate('$pfbfont', '', 1) ;\n" ;
+ close (CONVERT) }
+
+foreach my $file (@files)
+ { my $option = my $slant = my $spaced = my $extend = my $vfstr = my $encstr = "" ;
+ my $strange = "" ; my ($rawfont,$cleanfont,$restfont) ;
+ $file = $file ;
+ my $ok = $file =~ /(.*)\/(.+?)\.(.*)/ ;
+ my ($path,$name,$suffix) = ($1,$2,$3) ;
+ # remove trailing _'s
+ my $fontname = $name ;
+ my $cleanname = $fontname ;
+ $cleanname =~ s/\_//gio ;
+ # atl: pre-process an opentype or truetype file by converting to pfb
+ if ($preproc && !$lcdf)
+ { unless (-f "$afmpath/$cleanname.afm" && -f "$pfbpath/$cleanname.pfb")
+ { preprocess_font("$path/$name.$suffix", "$pfbpath/$cleanname.pfb") ;
+ rename("$pfbpath/$cleanname.afm", "$afmpath/$cleanname.afm")
+ || error("couldn't move afm product of pre-process.") }
+ $path = $afmpath ;
+ $file = "$afmpath/$cleanname.afm" }
+ # cleanup
+ foreach my $suf ("tfm", "vf", "vpl")
+ { UnLink "$raw$cleanname$fontsuffix.$suf" ;
+ UnLink "$use$cleanname$fontsuffix.$suf" }
+ UnLink "texfont.log" ;
+ # set switches
+ if ($encoding ne "")
+ { $encstr = " -T $encfil" }
+ if ($caps ne "")
+ { $vfstr = " -V $raw$cleanname$fontsuffix" }
+ else # if ($virtual)
+ { $vfstr = " -v $raw$cleanname$fontsuffix" }
+ my $font = "";
+ # let's see what we have here (we force texnansi.enc to avoid error messages)
+ if ($lcdf)
+ { my $command = "otfinfo -p $file" ;
+ print "$command\n" if $trace ;
+ $font = `$command` ;
+ chomp $font ;
+ $cleanname = $cleanfont = $font }
+ else
+ { my $command = "afm2tfm \"$file\" -p texnansi.enc texfont.tfm" ;
+ print "$command\n" if $trace ;
+ $font = `$command` ;
+ UnLink "texfont.tfm" ;
+ ($rawfont,$cleanfont,$restfont) = split(/\s/,$font) }
+ if ($font =~ /(math|expert)/io) { $strange = lc $1 }
+ $cleanfont =~ s/\_/\-/goi ;
+ $cleanfont =~ s/\-+$//goi ;
+ print "\n" ;
+ if (($strange eq "expert")&&($expert))
+ { report ("font identifier : $cleanfont$namesuffix -> $strange -> tfm") }
+ elsif ($strange ne "")
+ { report ("font identifier : $cleanfont$namesuffix -> $strange -> skipping") }
+ elsif ($afmpl)
+ { report ("font identifier : $cleanfont$namesuffix -> text -> tfm") }
+ elsif ($virtual)
+ { report ("font identifier : $cleanfont$namesuffix -> text -> tfm + vf") }
+ else
+ { report ("font identifier : $cleanfont$namesuffix -> text -> tfm") }
+ # don't handle strange fonts
+ if ($strange eq "")
+ { # atl: support for lcdf otftotfm
+ if ($lcdf && $extension eq "otf")
+ { # no vf, bypass afm, use otftotfm to get encoding and tfm
+ my $varstr = my $encout = my $tfmout = "" ;
+ report "processing files : otf -> tfm + enc" ;
+ if ($encoding ne "")
+ { $encfil = `kpsewhich -progname=pdftex $encoding.enc` ;
+ chomp $encfil ; if ($encfil eq "") { $encfil = "$encoding.enc" }
+ $encstr = " -e $encfil " }
+ if ($variant ne "")
+ { ( $varstr = $variant ) =~ s/,/ -f /goi ;
+ $varstr = " -f $varstr" }
+ $encout = "$encpath/$use$cleanfont.enc" ;
+ if (-e $encout)
+ { report ("renaming : $encout -> $use$cleanfont.bak") ;
+ UnLink "$encpath/$use$cleanfont.bak" ;
+ rename $encout, "$encpath/$use$cleanfont.bak" }
+ UnLink "texfont.map" ;
+ $tfmout = "$use$cleanfont$fontsuffix" ;
+ my $otfcommand = "otftotfm -a $varstr $encstr $passon $shape --name=\"$tfmout\" --encoding-dir=\"$encpath/\" --tfm-dir=\"$tfmpath/\" --vf-dir=\"$vfpath/\" --no-type1 --map-file=./texfont.map \"$file\"" ;
+ print "$otfcommand\n" if $trace ;
+ system("$otfcommand") ;
+ $encfil = $encout }
+ else
+ { # generate tfm and vpl, $file is on afm path
+ my $font = '' ;
+ if ($afmpl)
+ { report " generating pl : $cleanname$fontsuffix (from $cleanname)" ;
+ $encstr = " -p $encfil" ;
+ my $command = "afm2pl -f afm2tfm $shape $passon $encstr $file $cleanname$fontsuffix.vpl" ;
+ print "$command\n" if $trace ;
+ my $ok = `$command` ;
+ if (open (TMP,"$cleanname$fontsuffix.map"))
+ { $font = <TMP> ;
+ close(TMP) ;
+ UnLink "$cleanname$fontsuffix.map" } }
+ else
+ { report "generating raw tfm/vpl : $raw$cleanname$fontsuffix (from $cleanname)" ;
+ my $command = "afm2tfm $file $shape $passon $encstr $vfstr $raw$cleanname$fontsuffix" ;
+ print "$command\n" if $trace ;
+ $font = `$command` }
+ # generate vf file if needed
+ chomp $font ;
+ if ($font =~ /.*?([\d\.]+)\s*ExtendFont/io) { $extend = $1 }
+ if ($font =~ /.*?([\d\.]+)\s*SlantFont/io) { $slant = $1 }
+ if ($extend ne "") { $option .= " $1 ExtendFont " }
+ if ($slant ne "") { $option .= " $1 SlantFont " }
+ if ($noligs) { removeligatures("$raw$cleanname$fontsuffix") }
+ if ($afmpl)
+ { report "generating new tfm : $use$cleanname$fontsuffix" ;
+ my $command = "pltotf $cleanname$fontsuffix.vpl $use$cleanname$fontsuffix.tfm" ;
+ print "$command\n" if $trace ;
+ my $ok = `$command` }
+ elsif ($virtual)
+ { report "generating new vf : $use$cleanname$fontsuffix (from $raw$cleanname)" ;
+ my $command = "vptovf $raw$cleanname$fontsuffix.vpl $use$cleanname$fontsuffix.vf $use$cleanname$fontsuffix.tfm" ;
+ print "$command\n" if $trace ;
+ my $ok = `$command` }
+ else
+ { report "generating new tfm : $use$cleanname$fontsuffix (from $raw$cleanname)" ;
+ my $command = "pltotf $raw$cleanname$fontsuffix.vpl $use$cleanname$fontsuffix.tfm" ;
+ print "$command\n" if $trace ;
+ my $ok = `$command` } } }
+ elsif (-e "$sourcepath/$cleanname.tfm" )
+ { report "using existing tfm : $cleanname.tfm" }
+ elsif (($strange eq "expert")&&($expert))
+ { report "creating tfm file : $cleanname.tfm" ;
+ my $command = "afm2tfm $file $cleanname.tfm" ;
+ print "$command\n" if $trace ;
+ my $font = `$command` }
+ else
+ { report "use supplied tfm : $cleanname" }
+ # report results
+ if (!$lcdf)
+ { ($rawfont,$cleanfont,$restfont) = split(/\s/,$font) }
+ $cleanfont =~ s/\_/\-/goi ;
+ $cleanfont =~ s/\-+$//goi ;
+ # copy files
+ my $usename = "$use$cleanname$fontsuffix" ;
+ my $rawname = "$raw$cleanname$fontsuffix" ;
+
+ if ($lcdf eq "")
+ { if ($strange ne "")
+ { UnLink ("$vfpath/$cleanname.vf", "$tfmpath/$cleanname.tfm") ;
+ copy ("$cleanname.tfm","$tfmpath/$cleanname.tfm") ;
+ copy ("$usename.tfm","$tfmpath/$usename.tfm") ;
+ # or when available, use vendor one :
+ copy ("$sourcepath/$cleanname.tfm","$tfmpath/$cleanname.tfm") }
+ elsif ($virtual)
+ { UnLink ("$vfpath/$rawname.vf", "$vfpath/$usename.vf") ;
+ UnLink ("$tfmpath/$rawname.tfm", "$tfmpath/$usename.tfm") ;
+ copy ("$usename.vf" ,"$vfpath/$usename.vf") ;
+ copy ("$rawname.tfm","$tfmpath/$rawname.tfm") ;
+ copy ("$usename.tfm","$tfmpath/$usename.tfm") }
+ elsif ($afmpl)
+ { UnLink ("$vfpath/$rawname.vf", "$vfpath/$usename.vf", "$vfpath/$cleanname.vf") ;
+ UnLink ("$tfmpath/$rawname.tfm", "$tfmpath/$usename.tfm", "$tfmpath/$cleanname.tfm") ;
+ copy ("$usename.tfm","$tfmpath/$usename.tfm") }
+ else
+ { UnLink ("$vfpath/$usename.vf", "$tfmpath/$usename.tfm") ;
+ # slow but prevents conflicting vf's
+ my $rubish = `kpsewhich $usename.vf` ; chomp $rubish ;
+ if ($rubish ne "") { UnLink $rubish }
+ #
+ copy ("$usename.tfm","$tfmpath/$usename.tfm") } }
+ # cleanup
+ foreach my $suf ("tfm", "vf", "vpl")
+ { UnLink ("$rawname.$suf", "$usename.$suf") ;
+ UnLink ("$cleanname.$suf", "$fontname.$suf") ;
+ UnLink ("$cleanname$fontsuffix.$suf", "$fontname$fontsuffix.$suf") }
+ # add line to maps file
+ $option =~ s/^\s+(.*)/$1/o ;
+ $option =~ s/(.*)\s+$/$1/o ;
+ $option =~ s/ / /o ;
+ if ($option ne "")
+ { $option = "\"$option\" 4" }
+ else
+ { $option = "4" }
+ # adding cleanfont is kind of dangerous
+ my $thename = my $str = my $theencoding = "" ;
+ if ($strange ne "")
+ { $thename = $cleanname ; $theencoding = "" ; }
+ elsif ($lcdf)
+ { $thename = $usename ; $theencoding = " $encoding$varlabel-$cleanname.enc" }
+ elsif ($afmpl)
+ { $thename = $usename ; $theencoding = " $encoding$varlabel.enc" }
+ elsif ($virtual)
+ { $thename = $rawname ; $theencoding = " $encoding$varlabel.enc" }
+ else
+ { $thename = $usename ; $theencoding = " $encoding$varlabel.enc" }
+ # quit rest if no type 1 file
+ my $pfb_sourcepath = $sourcepath ;
+ $pfb_sourcepath =~ s@/afm/@/type1/@ ;
+ unless ((-e "$pfbpath/$fontname.$extension")||
+ (-e "$pfb_sourcepath/$fontname.$extension")||
+ (-e "$sourcepath/$fontname.$extension")||
+ (-e "$ttfpath/$fontname.$extension"))
+ { if ($tex) { $report .= "missing file: \\type \{$fontname.pfb\}\n" }
+ report ("missing pfb file : $fontname.pfb") }
+ # now add entry to map
+ if ($strange eq "") {
+ if ($extension eq "otf") {
+ if ($lcdf) {
+ my $mapline = "" ;
+ if (open(ALTMAP,"texfont.map")) {
+ while (<ALTMAP>) {
+ chomp ;
+ # atl: we assume this b/c we always force otftotfm --no-type1
+ if (/<<(.*)\.otf$/oi) {
+ $mapline = $_ ; last ;
+ }
+ }
+ close(ALTMAP) ;
+ } else {
+ report("no mapfile from otftotfm : texfont.map") ;
+ }
+ if ($preproc) {
+ $mapline =~ s/<\[/</;
+ $mapline =~ s/<<(\S+)\.otf$/<$1\.pfb/ ;
+ } else {
+ $mapline =~ s/<<(\S+)\.otf$/<< $ttfpath\/$fontname.$extension/ ;
+ }
+ $str = "$mapline\n" ;
+ } else {
+ if ($preproc) {
+ $str = "$thename $cleanfont $option < $fontname.pfb$theencoding\n" ;
+ } else {
+ # PdfTeX can't subset OTF files, so we have to include the whole thing
+ # It looks like we also need to be explicit on where to find the file
+ $str = "$thename $cleanfont $option << $ttfpath/$fontname.$extension <[$theencoding\n" ;
+ }
+ }
+ } else {
+ $str = "$thename $cleanfont $option < $fontname.$extension$theencoding\n" ;
+ }
+ } else {
+ $str = "$thename $cleanfont < $fontname.$extension\n" ;
+ }
+ # check for redundant entries
+ if ($map) {
+ $mapdata =~ s/^$thename\s.*?$//gmis ;
+ if ($afmpl) {
+ if ($mapdata =~ s/^$rawname\s.*?$//gmis) {
+ report ("removing raw file : $rawname") ;
+ }
+ }
+ $maplist .= $str ;
+ $mapdata .= $str ;
+ }
+ # write lines to tex file
+ if (($strange eq "expert")&&($expert)) {
+ $fntlist .= "\\definefontsynonym[$cleanfont$namesuffix][$cleanname] \% expert\n" ;
+ } elsif ($strange ne "") {
+ $fntlist .= "\%definefontsynonym[$cleanfont$namesuffix][$cleanname]\n" ;
+ } else {
+ $fntlist .= "\\definefontsynonym[$cleanfont$namesuffix][$usename][encoding=$encoding]\n" ;
+ }
+ next unless $tex ;
+ if (($strange eq "expert")&&($expert)) {
+ $texlist .= "\\ShowFont[$cleanfont$namesuffix][$cleanname]\n" ;
+ } elsif ($strange ne "") {
+ $texlist .= "\%ShowFont[$cleanfont$namesuffix][$cleanname]\n" ;
+ } else {
+ $texlist .= "\\ShowFont[$cleanfont$namesuffix][$usename][$encoding]\n"
+ }
+}
+
+if ($map)
+ { report ("updating map file : $mapfile") ;
+ while ($mapdata =~ s/\n\n+/\n/mois) {} ;
+ $mapdata =~ s/^\s*//gmois ;
+ print MAP $mapdata }
+
+if ($tex)
+ { $mappath =~ s/\\/\//go ;
+ $savedoptions =~ s/^\s+//gmois ; $savedoptions =~ s/\s+$//gmois ;
+ $fntlist =~ s/^\s+//gmois ; $fntlist =~ s/\s+$//gmois ;
+ $maplist =~ s/^\s+//gmois ; $maplist =~ s/\s+$//gmois ;
+ print TEX "$texlist" ;
+ print TEX "\n" ;
+ print TEX "\\setupheadertexts[\\tttf example definitions]\n" ;
+ print TEX "\n" ;
+ print TEX "\\starttyping\n" ;
+ print TEX "texfont $savedoptions\n" ;
+ print TEX "\\stoptyping\n" ;
+ print TEX "\n" ;
+ print TEX "\\starttyping\n" ;
+ print TEX "$mappath/$mapfile\n" ;
+ print TEX "\\stoptyping\n" ;
+ print TEX "\n" ;
+ print TEX "\\starttyping\n" ;
+ print TEX "$fntlist\n" ;
+ print TEX "\\stoptyping\n" ;
+ print TEX "\n" ;
+ print TEX "\\page\n" ;
+ print TEX "\n" ;
+ print TEX "\\setupheadertexts[\\tttf $mapfile]\n" ;
+ print TEX "\n" ;
+ print TEX "\\starttyping\n" ;
+ print TEX "$maplist\n" ;
+ print TEX "\\stoptyping\n" ;
+ print TEX "\n" ;
+ print TEX "\\stoptext\n" }
+
+if ($map) { close (MAP) }
+if ($tex) { close (TEX) }
+
+copy ($mapfile,"$mappath/$mapfile") ;
+
+# atl: global cleanup with generated files (afm & ttf don't mix)
+
+UnLink(@cleanup) ;
+
+print "\n" ; report ("generating : ls-r databases") ;
+
+# Refresh database.
+
+print "\n" ; system ("mktexlsr $fontroot") ; print "\n" ;
+
+# Process the test file.
+
+if ($show) { system ("texexec --once --silent $texfile") }
+
+@files = validglob("$identifier.*") ;
+
+foreach my $file (@files)
+ { unless ($file =~ /(tex|pdf|log|mp|tmp)$/io) { unlink $file } }
+
+exit ;
diff --git a/Master/texmf-dist/scripts/context/perl/texshow.pl b/Master/texmf-dist/scripts/context/perl/texshow.pl
new file mode 100644
index 00000000000..79222c9f03c
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/perl/texshow.pl
@@ -0,0 +1,936 @@
+eval '(exit $?0)' && eval 'exec perl -w -S $0 ${1+"$@"}' && eval 'exec perl -w -S $0 $argv:q'
+ if 0;
+
+#D \module
+#D [ file=texshow.pl,
+#D version=2005.01.06,
+#D title=TeXShow,
+#D subtitle=showing \CONTEXT\ commands,
+#D author=Taco Hoekwater,
+#D date=\currentdate,
+#D copyright={Taco Hoekwater}]
+
+#D Early 1999 \TEXSHOW\ showed up in the \CONTEXT\ distribution. At that time
+#D the user interface was described in files named \type {setup*.tex}. The
+#D program used a stripped down version of these definition files, generated
+#D by \CONTEXT\ itself. \TEXSHOW\ shows you the commands, their (optional)
+#D arguments, as well as the parameters and their values. For some five years
+#D there was no need to change \TEXSHOW. However, when a few years ago we
+#D started providing an \XML\ variant of the user interface definitions, Taco
+#D came up with \TEXSHOW||\XML. Because Patricks \CONTEXT\ garden and tools
+#D like \CTXTOOLS\ also use the \XML\ definitions, it's time to drop the old
+#D \TEX\ based definitions and move forward. From now on Taco's version is the
+#D one to be used.
+#D
+#D Hans Hagen - Januari 2005
+
+use strict;
+use Getopt::Long ;
+use XML::Parser;
+use Data::Dumper;
+use Tk;
+use Tk::ROText ;
+use Config;
+use Time::HiRes;
+
+$Getopt::Long::passthrough = 1 ; # no error message
+$Getopt::Long::autoabbrev = 1 ; # partial switch accepted
+
+my $ShowHelp = 0;
+my $Debug = 0;
+my $Editmode = 0;
+my $Interface = 'cont-en';
+my $current_command;
+my $current_interface;
+my $current_part;
+my @setup_files;
+
+my %setups;
+my %commes;
+my %descrs;
+my %examps;
+my %trees;
+my %positions;
+my %locations;
+my %crosslinks;
+
+
+&GetOptions
+ ( "help" => \$ShowHelp ,
+ "interface=s" => \$Interface ,
+ "debug" => \$Debug,
+ "edit" => \$Editmode) ;
+
+print "\n";
+
+show('TeXShow-XML 0.2 beta','Taco Hoekwater 2004',"/");
+
+print "\n";
+
+if ($ShowHelp) {
+ show('--help','print this help');
+ show('--interface=lg','primary interface');
+ show('--debug','print debugging info');
+ show('string','show info about command \'string\'');
+ show('string lg','show info about \'string\' in language \'lg\'');
+ print "\n";
+ exit 0;
+}
+
+my $command = $ARGV[0] || '';
+my $interface = $ARGV[1] || '';
+if ($interface =~ /^[a-z][a-z]$/i) {
+ $Interface = 'cont-' . lc($interface);
+} elsif ($interface && $command =~ /^[a-z][a-z]$/i) {
+ show('debug',"switching '$interface' and '$command'");
+ $Interface = 'cont-' . lc($command);
+ $command = $interface;
+}
+
+if ($command =~ s/^\\//) {
+ show('debug','removed initial command backslash');
+}
+
+show('interface', $Interface);
+if ($command){
+ show ('command', "\\$command") ;
+}
+
+print "\n";
+
+show('status','searching for setup files');
+
+my $setup_path;
+my ($mainwindow,$interfaceframe,$partframe,$leftframe,$rightframe,$buttonframe);
+my ($request,$listbox,$textwindow,%interfacebuttons,%partbuttons);
+
+my ($textfont,$userfont,$buttonfont);
+
+my $Part;
+
+if (setups_found($Interface)) {
+ $current_interface = '';
+ $current_command = '';
+ $current_part = 'Command';
+ show('status','loading setups') ;
+ load_setups($Interface) ;
+ show ('status','initializing display') ;
+ initialize_display();
+ change_setup();
+ show_command ($command);
+ $mainwindow->deiconify();
+ show ('status','entering main loop') ;
+ MainLoop () ;
+ show ('status','closing down') ;
+} else {
+ show ('error','no setup files found') ;
+}
+print "\n";
+
+sub initialize_display {
+ my $dosish = ($Config{'osname'} =~ /dos|win/i) ;
+ my $default_size = $dosish ? 9 : 12 ;
+ my $s_vertical = 30 ;
+ my $s_horizontal = 72 ;
+ my $c_horizontal = 24 ;
+ if (!$dosish) {
+ $textfont = "-adobe-courier-bold-r-normal--$default_size-120-75-75-m-70-iso8859-1" ;
+ $userfont = "-adobe-courier-bold-o-normal--$default_size-120-75-75-m-70-iso8859-1" ;
+ $buttonfont = "-adobe-helvetica-bold-r-normal--$default_size-120-75-75-p-69-iso8859-1";
+ } else {
+ $textfont = "Courier $default_size " ;
+ $userfont = "Courier $default_size italic" ;
+ $buttonfont = "Helvetica $default_size bold " ;
+ }
+ $mainwindow = MainWindow -> new ( -title => 'ConTeXt commands' ) ;
+ $buttonframe = $mainwindow -> Frame () ; # buttons
+ $leftframe = $mainwindow -> Frame () ; # leftside
+ $rightframe = $mainwindow -> Frame();
+ $request = $rightframe -> Entry (-font => $textfont,
+ -background => 'ivory1',
+ -width => $c_horizontal);
+ $listbox = $rightframe -> Scrolled ('Listbox',
+ -scrollbars => 'e',
+ -font => $textfont,
+ -width => $c_horizontal,
+ -selectbackground => 'gray',
+ -background => 'ivory1',
+ -selectmode => 'browse') ;
+ $textwindow = $leftframe -> Scrolled ('ROText',
+ -scrollbars => 'se',
+ -height => $s_vertical,
+ -width => $s_horizontal,
+ -wrap => 'none',
+ -background => 'ivory1',
+ -font => $textfont);
+ $interfaceframe = $leftframe -> Frame();
+ $mainwindow -> withdraw() ;
+ $mainwindow -> resizable ('y', 'y') ;
+ foreach (@setup_files) {
+ $interfacebuttons{$_} = $buttonframe -> Radiobutton (-text => $_,
+ -value => $_,
+ -font => $buttonfont,
+ -selectcolor => 'ivory1',
+ -indicatoron => 0,
+ -command => \&change_setup,
+ -variable => \$Interface );
+
+ $interfacebuttons{$_} -> pack (-padx => '2p',-pady => '2p','-side' => 'left' );
+ }
+ foreach (qw(Command Description Comments Examples)) {
+ $partbuttons{$_} = $interfaceframe -> Radiobutton (-text => $_,
+ -value => $_,
+ -font => $buttonfont,
+ -selectcolor => 'ivory1',
+ -indicatoron => 0,
+ -command => \&change_part,
+ -variable => \$Part );
+ $partbuttons{$_} -> pack (-padx => '2p',-pady => '2p','-side' => 'left' );
+ }
+ # global top
+ $buttonframe -> pack ( -side => 'top' , -fill => 'x' , -expand => 0 ) ;
+ # top in left
+ $interfaceframe -> pack ( -side => 'top' , -fill => 'x' , -expand => 0 ) ;
+ $textwindow -> pack ( -side => 'top' , -fill => 'both' , -expand => 1 ) ;
+ $leftframe -> pack ( -side => 'left' , -fill => 'both' , -expand => 1 ) ;
+ # right
+ $request -> pack ( -side => 'top' , -fill => 'x' ) ;
+ $listbox -> pack ( -side => 'bottom' , -fill => 'both' , -expand => 1 ) ;
+ $rightframe -> pack ( -side => 'right' , -fill => 'both' , -expand => 1 ) ;
+ $listbox -> bind ('<B1-Motion>', \&show_command ) ;
+ $listbox -> bind ('<1>' , \&show_command ) ;
+ $listbox -> bind ('<Key>' , \&show_command ) ;
+ $textwindow -> tag ('configure', 'user' , -font => $userfont ) ;
+ $textwindow -> tag ('configure', 'optional' , -font => $userfont ) ;
+ $textwindow -> tag ('configure', 'command' , -foreground => 'green3' ) ;
+ $textwindow -> tag ('configure', 'variable' , -font => $userfont ) ;
+ $textwindow -> tag ('configure', 'default' , -underline => 1 ) ;
+ $textwindow -> tag ('configure', 'symbol' , -foreground => 'blue3' ) ;
+ $textwindow -> tag ('configure', 'or' , -foreground => 'yellow3' ) ;
+ $textwindow -> tag ('configure', 'argument' , -foreground => 'red3' ) ;
+ $textwindow -> tag ('configure', 'par' , -lmargin1 => '4m' ,
+ -wrap => 'word' ,
+ -lmargin2 => '6m' ) ;
+ foreach my $chr ('a'..'z','A'..'Z') {
+ $mainwindow -> bind ( "<KeyPress-$chr>", sub { insert_request(shift, $chr) } );
+ }
+ $request -> bind ('<Return>', sub { handle_request() } ) ;
+ $mainwindow -> bind ( "<backslash>", sub { insert_request(shift, "\\") } ) ;
+ $mainwindow -> bind ( "<space>", sub { new_request() } ) ;
+ $mainwindow -> bind ( "<BackSpace>", sub { delete_request() } ) ;
+ $mainwindow -> bind ( "<Prior>", sub { prev_command() } ) ;
+ $mainwindow -> bind ( "<Next>", sub { next_command() } ) ;
+}
+
+sub show {
+ my ($pre,$post,$sep) = @_;
+ unless ($pre eq 'debug' && !$Debug) {
+ $sep = ':' unless defined $sep;
+ print sprintf("%22s $sep %+s\n",$pre,$post);
+ }
+}
+
+sub change_setup {
+ # switches to another setup file
+ if ($current_interface ne $Interface ) {
+ my $loc = 0;
+ if ($current_command) {
+ $loc = $positions{$Interface}{$current_command} || 0;
+ }
+ my @list = sort {lc $a cmp lc $b} keys %{$setups{$Interface}} ;
+ my $num = 0;
+ map { $locations{$Interface}{$_} = $num++; } @list;
+ $listbox -> delete ('0.0', 'end') ;
+ $listbox -> insert ('end', @list) ;
+ # try to switch to other command as well, here.
+ if ($current_command ne '') {
+ show_command($crosslinks{$Interface}[$loc] || '');
+ } else {
+ $listbox -> selectionSet ('0.0', '0.0') ;
+ $listbox -> activate ('0.0') ;
+ }
+ }
+ $current_interface = $Interface;
+ $mainwindow -> focus ;
+}
+
+sub change_part {
+ if ($Part ne $current_part) {
+ if($Part eq 'Command') {
+ show_command();
+ } elsif ($Part eq 'Description') {
+ show_description();
+ } elsif ($Part eq 'Comments') {
+ show_comments();
+ } elsif ($Part eq 'Examples') {
+ show_examples();
+ }
+ }
+ $current_part = $Part;
+}
+
+
+sub setups_found {
+ # find the setup files
+ my ($primary) = @_;
+ $setup_path = `kpsewhich --progname=context cont-en.xml` ;
+ chomp $setup_path;
+ show ('debug', "path = '$setup_path'");
+ if ($setup_path) {
+ $setup_path =~ s/cont-en\.xml.*// ;
+ @setup_files = glob ("${setup_path}cont\-??.xml") ; # HH: pattern patched, too greedy
+ show ('debug', "globbed path into '@setup_files'");
+ if (@setup_files) {
+ my $found = 0;
+ foreach (@setup_files) {
+ s/\.xml.*$//;
+ s/^.*?cont-/cont-/;
+ if ($_ eq $primary) {
+ $found = 1;
+ show ('debug', "found primary setup '$primary'");
+ } else {
+ show ('debug', "found non-primary setup '$_'");
+ }
+ }
+ if ($found) {
+ return 1;
+ } else {
+ show('error',"setup file for '$primary' not found, using 'cont-en'");
+ $Interface = 'cont-en';
+ return 1;
+ }
+ } else {
+ show('error',"setup file glob failed");
+ }
+ } elsif ($!) {
+ show('error','kpsewhich not found');
+ } else {
+ show('error','setup files not found');
+ }
+ return 0;
+}
+
+sub load_setup {
+ my ($path,$filename) = @_;
+ unless (keys %{$setups{$filename}}) {
+ if (open(IN,"<${path}$filename.xml")) {
+ my $position = 0 ;
+ local $/ = '</cd:command>';
+ while (my $data= <IN>) {
+ if ($data =~ /\<\/cd:interface/) {
+ next;
+ }
+ if ($data =~ /\<cd:interface/) {
+ $data =~ s/^(.*?)\<cd:command/\<cd:command/sm;
+ my $meta = $1;
+ }
+ #
+ $data =~ s/\s*\n\s*//g;
+ $data =~ /\<cd:command(.*?)\>/;
+ my $info = $1;
+ my ($name,$environment) = ('','');
+ while ($info =~ s/^\s*(.*?)\s*=\s*(["'])(.*?)\2\s*//) {
+ my $a = $1; my $b = $3;
+ if ($a eq 'name') {
+ $name = $b;
+ } elsif ($a eq 'type') {
+ $environment = $b;
+ }
+ }
+ my $cmd = $name;
+ if ($environment) {
+ $cmd = "start" . $name;
+ }
+ $setups {$filename}{$cmd} = $data ;
+ $trees {$filename}{$cmd} = undef;
+ $positions {$filename}{$cmd} = ++$position ;
+ $crosslinks{$filename}[$position] = $cmd ;
+ }
+ close IN;
+ # now get explanations as well ...
+ my $explname = $filename;
+ $explname =~ s/cont-/expl-/;
+ my $extras = 0 ;
+ if (open(IN,"<${path}$explname.xml")) {
+ local $/ = '</cd:explanation>';
+ while (my $data= <IN>) {
+ if ($data =~ /\<\/cd:explanations/) {
+ next;
+ }
+ if ($data =~ /\<cd:explanations/) {
+ $data =~ s/^(.*?)\<cd:explanation /\<cd:explanation /sm;
+ my $meta = $1;
+ }
+ #
+ $extras++;
+ $data =~ /\<cd:explanation(.*?)\>/;
+ my $info = $1;
+ my ($name,$environment) = ('','');
+ while ($info =~ s/^\s*(.*?)\s*=\s*(["'])(.*?)\2\s*//) {
+ my $a = $1; my $b = $3;
+ if ($a eq 'name') {
+ $name = $b;
+ } elsif ($a eq 'type') {
+ $environment = $b;
+ }
+ }
+ my $cmd = $name;
+ if ($environment) {
+ $cmd = "start" . $name;
+ }
+ my $comment = '';
+ my $description = '';
+ my @examples = ();
+ $data =~ /\<cd:description\>(.*)\<\/cd:description\>/s and $description = $1;
+ $data =~ /\<cd:comment\>(.*)\<\/cd:comment\>/s and $comment = $1;
+ while ($data =~ s/\<cd:example\>(.*?)\<\/cd:example\>//s) {
+ push @examples, $1;
+ }
+ if (length($comment) && $comment =~ /\S/) {
+ $commes {$filename}{$cmd} = $comment;
+ }
+ if (length($description) && $description =~ /\S/) {
+ $descrs {$filename}{$cmd} = $description;
+ }
+ my $testex = "@examples";
+ if (length($testex) && $testex =~ /\S/) {
+ $examps {$filename}{$cmd} = [@examples];
+ }
+ }
+ }
+ if ($extras) {
+ show('debug',"interface '$filename', $position\&$extras commands");
+ } else {
+ show('debug',"interface '$filename', $position commands");
+ }
+ } else {
+ show ('debug',"open() of ${path}$filename.xml failed");
+ }
+ }
+ $Interface = $filename ;
+}
+
+sub load_setups {
+ my ($primary) = @_;
+ # load all setup files, but default to $primary
+ my $t0 = [Time::HiRes::gettimeofday()];
+ foreach my $setup (@setup_files) {
+ if ($setup ne $primary) {
+ load_setup ($setup_path,$setup);
+ show('status',"loading '$setup' took " .Time::HiRes::tv_interval($t0) . " seconds");
+ $t0 = [Time::HiRes::gettimeofday()];
+ };
+ };
+ load_setup ($setup_path,$primary);
+ show('status',"loading '$primary' took " .Time::HiRes::tv_interval($t0) . " seconds");
+}
+
+my @history = ();
+my $current_history = 0;
+
+sub show_command {
+ my ($command,$nofix) = @_;
+ if (keys %{$setups{$Interface}}) {
+ my $key = '';
+ if (defined $command && $command &&
+ (defined $setups{$Interface}{$command} ||
+ defined $setups{$Interface}{"start" . $command})) {
+ $key = $command;
+ my $whence =$locations{$Interface}{$command};
+ $listbox -> selectionClear ('0.0','end') ;
+ $listbox -> selectionSet($whence,$whence);
+ $listbox -> activate($whence);
+ $listbox -> see($whence);
+ } else {
+ $listbox -> selectionSet('0.0','0.0') unless $listbox->curselection();
+ $key = $listbox -> get($listbox->curselection()) ;
+ }
+ show('debug',"current command: $current_command");
+ show('debug'," new command: $key");
+ $current_command = $key ;
+ $textwindow -> delete ('1.0', 'end' ) ;
+ $partbuttons{"Command"}->select();
+ $partbuttons{"Command"}->configure('-state' => 'normal');
+ $partbuttons{"Description"}->configure('-state' => 'disabled');
+ $partbuttons{"Comments"}->configure('-state' => 'disabled');
+ $partbuttons{"Examples"}->configure('-state' => 'disabled');
+ if (defined $commes{$Interface}{$key}) {
+ $partbuttons{"Comments"}->configure('-state' => 'normal');
+ }
+ if (defined $descrs{$Interface}{$key}) {
+ $partbuttons{"Description"}->configure('-state' => 'normal');
+ }
+ if (defined $examps{$Interface}{$key}) {
+ $partbuttons{"Examples"}->configure('-state' => 'normal');
+ }
+ unless (defined $nofix && $nofix) {
+ push @history, $key;
+ $current_history = $#history;
+ }
+ do_update_command ($key) ;
+ $mainwindow -> update();
+ $mainwindow -> focus() ;
+ }
+}
+
+sub prev_command {
+ if ($current_history > 0) {
+ $current_history--;
+ show_command($history[$current_history],1);
+ }
+}
+
+sub next_command {
+ unless ($current_history == $#history) {
+ $current_history++;
+ show_command($history[$current_history],1);
+ }
+}
+
+sub show_description {
+ $textwindow -> delete ('1.0', 'end' ) ;
+ if (defined $descrs{$current_interface}{$current_command}) {
+ $textwindow-> insert ('end',$descrs{$current_interface}{$current_command});
+ }
+ $mainwindow -> update();
+ $mainwindow -> focus() ;
+}
+
+sub show_comments {
+ $textwindow -> delete ('1.0', 'end' ) ;
+ if (defined $commes{$current_interface}{$current_command}) {
+ $textwindow-> insert ('end',$commes{$current_interface}{$current_command});
+ }
+ $mainwindow -> update();
+ $mainwindow -> focus() ;
+}
+
+
+sub show_examples {
+ $textwindow -> delete ('1.0', 'end' ) ;
+ if (defined $examps{$current_interface}{$current_command}) {
+ $textwindow-> insert ('end',join("\n\n",@{$examps{$current_interface}{$current_command}}));
+ }
+ $mainwindow -> update();
+ $mainwindow -> focus() ;
+}
+
+
+
+
+sub has_attr {
+ my ($elem,$att,$val) = @_;
+ return 1 if (attribute($elem,$att) eq $val);
+ return 0;
+}
+
+
+sub view_post {
+ my ($stuff,$extra) = @_;
+ $extra = '' unless defined $extra;
+ $stuff =~ /^(.)(.*?)(.)$/;
+ my ($l,$c,$r) = ($1,$2,$3);
+ if ($l eq '[' || $l eq '(') {
+ return ($l,['symbol','par',$extra],$c,['par',$extra],$r,['symbol','par',$extra],"\n",'par');
+ } else {
+ return ($l,['argument','par',$extra],$c,['par',$extra],$r,['argument','par',$extra],"\n",'par');
+ }
+}
+
+sub view_pre {
+ my ($stuff) = @_;
+ $stuff =~ /^(.)(.*?)(.)$/;
+ my ($l,$c,$r) = ($1,$2,$3);
+ if ($l eq '[' || $l eq '(') {
+ return ($l,['symbol'],$c,'',$r,['symbol']);
+ } else {
+ return ($l,['argument'],$c,'',$r,['argument']);
+ }
+}
+
+sub create_setup_arguments {
+ my $argx = shift;
+ my @predisp = ();
+ my @postdisp = ();
+ foreach my $arg (children($argx)) {
+ if (name($arg) eq 'cd:keywords') {
+ # children are Constant* & Inherit? & Variable*
+ my @children = children($arg);
+ my $optional = (attribute($arg,'optional') eq 'yes' ? 'optional' : '');
+ if (@children){
+ push @predisp,'[', ['symbol',$optional];
+ if (has_attr($arg,'list', 'yes')) {
+ if (has_attr($arg,'interactive', 'exclusive')) {
+ push @predisp, '...', '';
+ } else {
+ push @predisp, '..,...,..', '';
+ }
+ } else {
+ push @predisp,'...', '';
+ }
+ push @predisp,']', ['symbol',$optional];
+ }
+ push @postdisp,'[', ['symbol','par',$optional];
+ my $firsttrue = 1;
+ foreach my $kwd (@children) {
+ if ($firsttrue) {
+ $firsttrue = 0;
+ } else {
+ push @postdisp,', ', ['symbol','par'];
+ }
+ if (name($kwd) eq 'cd:constant' ||
+ name($kwd) eq 'cd:variable') {
+ my $v = attribute($kwd,'type');
+ my $def = '';
+ my $var = '';
+ $var = 'variable' if (name($kwd) eq 'cd:variable') ;
+ $def = 'default' if (has_attr($kwd,'default', 'yes'));
+ if ($v =~ /^cd:/) {
+ $v =~ s/^cd://;
+ $v .= "s" if (has_attr($arg,'list', 'yes'));
+ push @postdisp, $v, ['user',$def,'par',$var];
+ } else {
+ push @postdisp, $v, [$def,'par',$var];
+ }
+ } elsif (name($kwd) eq 'cd:inherit') {
+ my $v = attribute($kwd,'name');
+ $textwindow -> tag ('configure', $v , -foreground => 'blue3',-underline => 1 ) ;
+ $textwindow -> tagBind($v,'<ButtonPress>',sub {show_command($v)} );
+ push @postdisp,"see ","par", "$v", [$v,'par'];
+ }
+ }
+ push @postdisp,']', ['symbol','par',$optional];
+ push @postdisp,"\n", 'par';
+ } elsif (name($arg) eq 'cd:assignments') {
+ # children are Parameter* & Inherit?
+ my @children = children($arg);
+ my $optional = (attribute($arg,'optional') eq 'yes' ? 'optional' : '');
+ if (@children) {
+ push @predisp,'[', ['symbol',$optional];
+ if (has_attr($arg,'list', 'yes')) {
+ push @predisp, '..,..=..,..', '';
+ } else {
+ push @predisp,'..=..', '';
+ }
+ push @predisp,']', ['symbol',$optional];
+ push @postdisp,'[', ['symbol','par',$optional];
+ my $isfirst = 1;
+ foreach my $assn (@children) {
+ if ($isfirst) {
+ $isfirst = 0;
+ } else {
+ push @postdisp,",\n ", ['symbol','par'];
+ }
+ if (name($assn) eq 'cd:parameter') {
+ push @postdisp,attribute($assn,'name'), 'par';
+ push @postdisp,'=', ['symbol','par'];
+ my $firstxtrue = 1;
+ foreach my $par (children($assn)) {
+ if ($firstxtrue) {
+ $firstxtrue = 0;
+ } else {
+ push @postdisp,'|', ['or','par'];
+ }
+ if (name($par) eq 'cd:constant' || name($par) eq 'cd:variable') {
+ my $var = '';
+ $var = 'variable' if name($par) eq 'cd:variable';
+ my $v = attribute($par,'type');
+ if ($v =~ /^cd:/) {
+ $v =~ s/^cd://;
+ push @postdisp,$v, ['user','par',$var];
+ } else {
+ push @postdisp,$v, ['par',$var];
+ }
+ }
+ }
+ } elsif (name($assn) eq 'cd:inherit') {
+ my $v = attribute($assn,'name');
+ $textwindow -> tag ('configure', $v , -foreground => 'blue3',-underline => 1 ) ;
+ $textwindow -> tagBind($v,'<ButtonPress>',sub {show_command($v)} );
+ push @postdisp,"see ","par", "$v", [$v,'par'];
+ }
+ }
+ push @postdisp,"]", ['symbol','par',$optional], "\n", '';
+ }
+ } elsif (name($arg) eq 'cd:content') {
+ push @predisp, view_pre('{...}');
+ push @postdisp, view_post('{...}');
+ } elsif (name($arg) eq 'cd:triplet') {
+ if (has_attr($arg,'list','yes')) {
+ push @predisp, view_pre('[x:y:z=,..]');
+ push @postdisp,view_post('[x:y:z=,..]');
+ } else {
+ push @predisp, view_pre('[x:y:z=]');
+ push @postdisp,view_post('[x:y:z=]');
+ }
+ } elsif (name($arg) eq 'cd:reference') {
+ my $optional = (attribute($arg,'optional') eq 'yes' ? 'optional' : '');
+ if (has_attr($arg,'list','yes')) {
+ push @postdisp, view_post('[ref,..]',$optional);
+ push @predisp, view_pre('[ref,..]');
+ } else {
+ push @postdisp, view_post('[ref]',$optional);
+ push @predisp, view_pre('[ref]');;
+ }
+ } elsif (name($arg) eq 'cd:word') {
+ if (has_attr($arg,'list','yes')) {
+ push @predisp, view_pre ('{...,...}');
+ push @postdisp,view_post('{...,...}');
+ } else {
+ push @predisp, view_pre('{...}');
+ push @postdisp, view_post('{...}');
+ }
+ } elsif (name($arg) eq 'cd:nothing') {
+ my $sep = attribute($arg,'separator');
+ if ($sep) {
+ if($sep eq 'backslash') {
+# push @postdisp,'\\\\','par';
+ push @predisp,'\\\\','';
+ } else {
+# push @postdisp,$sep,'par';
+ push @predisp,$sep,'';
+ }
+ }
+ push @predisp,'...','';
+ push @postdisp,'text',['variable','par'],"\n",'par';
+ } elsif (name($arg) eq 'cd:file') {
+ push @predisp,'...',['default'];
+ push @postdisp,'...',['default','par'],"\n",'par';
+ } elsif (name($arg) eq 'cd:csname') {
+ push @predisp,'\command',['command'];
+ push @postdisp,'\command',['command','par'],"\n",'par';
+ } elsif (name($arg) eq 'cd:index') {
+ if (has_attr($arg,'list','yes')) {
+ push @predisp,view_pre('{..+...+..}');
+ push @postdisp,view_post('{..+...+..}');
+ } else {
+ push @predisp, view_pre('{...}');
+ push @postdisp,view_post('{...}');
+ }
+ } elsif (name($arg) eq 'cd:position') {
+ if (has_attr($arg,'list','yes')) {
+ push @predisp,view_pre('(...,...)');
+ push @postdisp,view_post('(...,...)');
+ } else {
+ push @predisp,view_pre('(...)');
+ push @postdisp,view_post('(...)');
+ }
+ } elsif (name($arg) eq 'cd:displaymath') {
+ push @predisp, ('$$',['argument'],'...','','$$',['argument']);
+ push @postdisp, ('$$',['argument','par'],'...',['par'],'$$',['argument','par']);
+ } elsif (name($arg) eq 'cd:tex') {
+ my $sep = attribute($arg,'separator');
+ if ($sep) {
+ if($sep eq 'backslash') {
+# push @postdisp,'\\\\','par';
+ push @predisp,'\\\\','';
+ } else {
+# push @postdisp,$sep,'par';
+ push @predisp,$sep,'';
+ }
+ }
+ my $cmd = "\\" . attribute($arg,'command');
+ push @predisp,$cmd,'';
+# push @postdisp,$cmd,['command','par'],"\n",'par';
+ }
+ }
+ return (\@predisp,\@postdisp);
+}
+
+
+# <foo><head id="a">Hello <em>there</em></head><bar>Howdy<ref/></bar>do</foo>
+#
+# would be:
+#
+# Tag Content
+# ==================================================================
+# [foo, [{}, head, [{id => "a"}, 0, "Hello ", em, [{}, 0, "there"]],
+# bar, [ {}, 0, "Howdy", ref, [{}]],
+# 0, "do"
+# ]
+# ]
+
+sub attribute {
+ my ($elem,$att) = @_;
+ if (defined $elem->[1] && defined $elem->[1]->[0] && defined $elem->[1]->[0]->{$att}) {
+ my $ret = $elem->[1]->[0]->{$att};
+ show ('debug',"returning attribute $att=$ret");
+ return $elem->[1]->[0]->{$att};
+ } else {
+ return '';
+ }
+}
+
+sub name {
+ my ($elem) = @_;
+ if (defined $elem->[0] ) {
+ return $elem->[0];
+ } else {
+ return '';
+ }
+}
+
+# return all children at a certain level
+sub children {
+ my ($elem) = @_;
+ if (defined $elem->[1] && defined $elem->[1]->[1]) {
+ my @items = @{$elem->[1]};
+ shift @items ; # deletes the attribute.
+ my @ret = ();
+ while (@items) {
+ push @ret, [shift @items, shift @items];
+ }
+ return @ret;
+ } else {
+ return ();
+ }
+}
+
+# return the first child with the right name
+sub find {
+ my ($elem,$name) = @_;
+ if ($elem->[0] eq $name) {
+ return $elem;
+ }
+ if (ref($elem->[1]) eq 'ARRAY') {
+ my @contents = @{$elem->[1]};
+ shift @contents;
+ while (my $ename = shift @contents) {
+ my $con = shift @contents;
+ if ($ename eq $name) {
+ return [$ename,$con];
+ }
+ }
+ }
+ return [];
+}
+
+sub do_update_command # type: 0=display, 1=compute only
+ { my ($command, $type) = @_ ;
+ $type = 0 unless defined $type;
+ my $setup;
+ if (!defined $trees{$Interface}{$command}) {
+ my $parser = XML::Parser->new('Style' => 'Tree');
+ $trees{$Interface}{$command} = $parser->parse($setups{$Interface}{$command});
+ }
+ $setup = $trees{$Interface}{$command} ;
+ my $predisp = undef;
+ my $postdisp = undef;
+ my @cmddisp = ();
+ my @cmddispafter = ();
+ my $pradisp = undef;
+ my $altdisp = undef;
+ if (attribute($setup,'file')) {
+ my $filename = attribute($setup,'file');
+ my $fileline = attribute($setup,'line') || 0;
+ $textwindow->insert ('end',"$filename:${fileline}::\n\n", '' );
+ }
+ # start with backslash
+ push @cmddisp, "\\", 'command' ;
+ my $env = 0;
+ if (has_attr($setup,'type','environment')) {
+ $env = 1;
+ }
+ if ($env) { push @cmddisp, "start", 'command' ; }
+ if ($env) { push @cmddispafter, " ... ", '', "\\stop", 'command' ; }
+ my $seq = find($setup,'cd:sequence');
+ # display rest of command name
+ foreach my $seqpart (children($seq)) {
+ my $text = attribute($seqpart,'value');
+ if (name($seqpart) eq 'cd:variable') {
+ push @cmddisp, $text, ['command','user'];
+ if ($env) { push @cmddispafter, $text, ['command','user']; }
+ } elsif (name($seqpart) eq 'cd:string') {
+ push @cmddisp, $text, 'command';
+ if ($env) { push @cmddispafter, $text, 'command'; }
+ }
+ }
+ #
+ my $args = find($setup,'cd:arguments');
+ # display commands
+ if ($args) {
+ my $curarg = 0;
+ foreach my $arg (children($args)) {
+ if (name($arg) eq 'cd:choice') {
+ my ($a,$b) = children($arg);
+ ($predisp,$postdisp) = create_setup_arguments(['cd:arguments',[{}, @$a]]);
+ ($pradisp,$altdisp) = create_setup_arguments(['cd:arguments',[{}, @$b]]);
+ } else {
+ ($predisp,$postdisp) = create_setup_arguments($args);
+ }
+ $curarg++;
+ }
+ }
+ return if $type;
+ if(defined $postdisp) {
+ if(defined $altdisp) {
+ $textwindow->insert('end',@cmddisp,@$predisp,@cmddispafter, "\n",'',
+ @cmddisp,@$pradisp,@cmddispafter, "\n\n",'',
+ @cmddisp, "\n",'',
+ @$postdisp, "\n",'',
+ @cmddisp, "\n",'',
+ @$altdisp);
+ } else {
+ $textwindow->insert('end',@cmddisp,@$predisp, @cmddispafter ,"\n\n",'',
+ @cmddisp,"\n",'',
+ @$postdisp);
+ }
+ } else {
+ $textwindow->insert('end',@cmddisp);
+ }
+}
+
+
+#D The next feature is dedicated to Tobias, who suggested
+#D it, and Taco, who saw it as yet another proof of the
+#D speed of \PERL. It's also dedicated to Ton, who needs it
+#D for translating the big manual.
+
+sub handle_request {
+ my $index = $listbox -> index('end') ;
+ return unless $index;
+ my $req = $request -> get ;
+ return unless $req;
+ $req =~ s/\\//o ;
+ $req =~ s/\s//go ;
+ $request -> delete('0','end') ;
+ $request -> insert('0',$req) ;
+ return unless $req;
+ my ($l,$c) = split (/\./,$index) ;
+ for (my $i=0;$i<=$l;$i++) {
+ $index = "$i.0" ;
+ my $str = $listbox -> get ($index, $index) ;
+ if (defined $str && ref($str) eq 'ARRAY') {
+ $str = "@{$str}";
+ }
+ if (defined $str && $str =~ /^$req/) {
+ show_command($str) ;
+ return ;
+ }
+ }
+}
+
+sub insert_request {
+ my ($self, $chr) = @_ ;
+ # don't echo duplicate if $chr was keyed in in the (focussed) entrybox
+ $request -> insert ('end', $chr) unless $self eq $request;
+ handle_request();
+}
+
+sub delete_request {
+ my $self = shift ;
+ # delete last character, carefully
+ if ($self ne $request) {
+ my $to = $request -> index ('end') ;
+ my $from = $to - 1 ;
+ if ($from<0) { $from = 0 }
+ $request -> delete ($from,$to);
+ }
+ handle_request();
+}
+
+sub new_request {
+ $request -> delete (0,'end') ;
+ handle_request();
+}
+
diff --git a/Master/texmf-dist/scripts/context/perl/texutil.pl b/Master/texmf-dist/scripts/context/perl/texutil.pl
new file mode 100644
index 00000000000..0a0d2975354
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/perl/texutil.pl
@@ -0,0 +1,2902 @@
+eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $argv:q'
+ if 0;
+
+#D \module
+#D [ file=texutil.pl,
+#D version=2003.09.16,
+#D title=pre- and postprocessing utilities,
+#D subtitle=\TEXUTIL,
+#D author=Hans Hagen,
+#D date=\currentdate,
+#D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+#C
+#C This module is part of the \CONTEXT\ macro||package and is
+#C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+#C details.
+
+# much functionality will move to ctxtools, xmltools and pdftools; that way texutil
+# becomes limited to tui processing only, which is cleaner (also for taco's binary
+# version)
+
+# Thanks to Tobias Burnus for the german translations.
+# Thanks to Thomas Esser for hooking it into web2c
+# Thanks to Taco Hoekwater for making the file -w proof and some fixes
+# Thanks to Alex Knowles and friends for the right JPG specs
+# Thanks to Sebastian Rahtz for the eps to PDF method
+# Thanks to Fabrice Popineau for windows bin code
+
+#D We started with a hack provided by Thomas Esser. This
+#D expression replaces the unix specific line \type
+#D {#!/usr/bin/perl}.
+
+# undocumented:
+#
+# --analyze file.pdf : reports some statistics
+# --purge [jobname] : removes temporary files
+# --purgeall [jobname] : removes all temporary files
+
+#D This is \TEXUTIL, a utility program (script) to be used
+#D alongside the \CONTEXT\ macro package. This \PERL\ script is
+#D derived from the \MODULA\ version and uses slightly better
+#D algoritms for sanitizing \TEX\ specific (sub|)|strings.
+#D
+#D This implementation has some features not found in the
+#D binary version, like scanning illustrations other than \EPS.
+#D I would suggest to keep an eye on the version number:
+
+$Program = "TeXUtil 9.0.0 - ConTeXt / PRAGMA ADE 1992-2004" ;
+
+#D By the way, this is my first \PERL\ script, which means
+#D that it will be improved as soon as I find new and/or more
+#D suitable solutions in the \PERL\ manuals. As can be seen in
+#D the definition of \type{$Program}, this program is part of
+#D the \CONTEXT\ suite, and therefore can communicate with the
+#D users in english as well as some other languages. One can
+#D set his favourite language by saying something like:
+
+#D \starttypen
+#D perl texutil.pl --int=de --fig *.eps *.tif *.pdf *.png *.jpg
+#D \stoptypen
+#D
+#D or simpler:
+#D
+#D \starttypen
+#D perl texutil.pl --fig *.*
+#D \stoptypen
+
+#D Of course one can also say \type{--interface=nl}, which
+#D happens to be my native language.
+
+#D I won't go into too much detail on the algoritms used.
+#D The next few pages show the functionality as reported by the
+#D helpinformation and controled by command line arguments
+#D and can serve as additional documentation.
+
+#D \TEXUTIL\ can handle different tasks; which one is active
+#D depends on the command line arguments. These are handled by
+#D a \PERL\ system module. This means that, at least for the
+#D moment, there is no external control as provided by the
+#D \PRAGMA\ environment system.
+
+use Getopt::Long ;
+use FindBin ;
+
+#D We don't want error messages and accept partial switches,
+#D which saves users some typing.
+
+$Getopt::Long::passthrough = 1 ; # no error message
+$Getopt::Long::autoabbrev = 1 ; # partial switch accepted
+
+#D We also predefine the interface language and set a boolean
+#D that keeps track of unknown options. \voetnoot {This feature
+#D is still to be implemented.}
+
+$UserInterface = "en" ;
+$UnknownOptions = 0 ;
+$TcXPath = '' ;
+
+#D We need this for calling GS.
+
+use Config ;
+
+my $dosish = ($Config{'osname'} =~ /^(ms)?dos|^os\/2|^(ms|cyg)win/i) ;
+
+#D Here come the options:
+
+&GetOptions
+ ("references" => \$ProcessReferences,
+ "ij" => \$ProcessIJ,
+ "high" => \$ProcessHigh,
+ "quotes" => \$ProcessQuotes,
+ "tcxpath=s" => \$TcXPath,
+ "documents" => \$ProcessDocuments,
+ "type=s" => \$ProcessType,
+ "outputfile=s" => \$ProcessOutputFile,
+ "sources" => \$ProcessSources,
+ "setups" => \$ProcessSetups,
+ "templates" => \$ProcessTemplates,
+ "infos" => \$ProcessInfos,
+ "figures" => \$ProcessFigures,
+ "epspage" =>\$ProcessEpsPage,
+ "epstopdf" =>\$ProcessEpsToPdf,
+ "logfile" => \$ProcessLogFile,
+ "box" =>\$ProcessBox,
+ "hbox" =>\$ProcessHBox,
+ "vbox" =>\$ProcessVBox,
+ "criterium=f" =>\$ProcessCriterium,
+ "unknown" =>\$ProcessUnknown,
+ "purge" => \$PurgeFiles,
+ "purgeall" => \$PurgeAllFiles,
+ "analyze" => \$AnalyzeFile,
+ "filter" => \$FilterPages,
+ "help" => \$ProcessHelp,
+ "silent" => \$ProcessSilent,
+ "verbose" => \$ProcessVerbose,
+ "interface=s" => \$UserInterface) ;
+
+# A bit old, this code, could be an array. Anyhow, we will
+# replace texutil soon.
+
+$InputFile = "@ARGV" ; # niet waterdicht
+
+#D We need some hacks to suppress terminal output. This
+#D piece of code is based on page~193 of "Programming Perl".
+
+$ProgramLog = "texutil.log" ;
+
+# Well, it seems that unix' symlinks are sensitive for being
+# hijacked. The assumption is that a known file can be a problem.
+# Of course when one knows that certains files are processed,
+# the names are always known and hijacking can always take
+# place. But let's use a slightly less predictable name here:
+#
+# if ((@ARGV[0]) && (@ARGV[0] ne "")) {
+# $ProgramLog = "@ARGV[0]-$ProgramLog" ;
+# } else {
+# # no need to be silent
+# $ProcessSilent = 0 ;
+# }
+#
+# or better, let's drop this feature, since i'm not in the mood
+# now to test hacks like this (i'll just wait till the age of
+# computer anarchy has ended).
+
+$ProgramLog = "/dev/null" ;
+
+# Maybe we should just write to the nul device. (In the rewritten
+# version I can treat unix more strick.)
+
+sub RedirectTerminal
+ { open SAVEDSTDOUT, ">&STDOUT" ;
+ open STDOUT, ">$ProgramLog" ;
+ select STDOUT; $| = 1 }
+
+#D And, indeed:
+
+if ($ProcessSilent)
+ { RedirectTerminal }
+else
+ { $ProcessVerbose = 0 }
+
+#D We can temporary open the terminal channel.
+
+sub OpenTerminal
+ { close STDOUT ;
+ open STDOUT, ">&SAVEDSTDOUT" }
+
+sub CloseTerminal
+ { open SAVEDSTDOUT, ">&STDOUT" ;
+ open STDOUT, ">>$ProgramLog" ;
+ select STDOUT; $| = 1 }
+
+#D By default wildcards are expanded into a list. The
+#D subroutine below is therefore only needed when no file or
+#D pattern is given.
+
+sub CompFileName
+ { my ($a,$b) = @_ ;
+ my ($fa,$sa) = split(/\./,$a) ;
+ my ($fb,$sb) = split(/\./,$b) ;
+ if (($sa =~ /^\d+$/o)&&($sb =~ /^\d+$/o))
+ { $a = $fa . "." . sprintf("%10d",$sa) ; $a =~ s/\s/0/o ;
+ $b = $fb . "." . sprintf("%10d",$sb) ; $b =~ s/\s/0/o }
+ return (lc ($a) cmp lc ($b)) }
+
+sub CheckInputFiles
+ { @UserSuppliedFiles = glob $_[0] ;
+ @UserSuppliedFiles = sort { CompFileName($a,$b) } @UserSuppliedFiles }
+
+#D The next subroutine takes care of the optional output
+#D filename (e.g. for figure dimensions).
+
+$ProcessOutputFile = "" ;
+
+my $Rubish ;
+
+sub SetOutputFile
+ { ($OutFilNam, $OutFilSuf) = split (/\./, $_[0], 2) ;
+ unless ($ProcessOutputFile eq "")
+ { $ProcessOutputFile .= "." . $OutFilSuf ;
+ ($OutFilNam, $OutFilSuf, $Rubish) = split (/\./, $ProcessOutputFile , 3)}
+ $OutputFile = $OutFilNam . "." . $OutFilSuf }
+
+#D Sometimes we need to split filenames.
+
+my ($FileName, $FileSuffix) = ("","") ;
+
+sub SplitFileName
+ { my $Rubish = "" ;
+ if ($_[0] =~ /^\.\//)
+ { ($Rubish, $FileName) = split ( /^\.\//, $_[0], 2) }
+ else
+ { $FileName = $_[0] }
+ return split (/\./, $FileName, 2) }
+
+#D In order to support multiple interfaces, we save the
+#D messages in a hash table. As a bonus we can get a quick
+#D overview of the messages we deal with.
+
+my %MS ;
+
+sub Report
+ { foreach $_ (@_)
+ { if (! defined $MS{$_})
+ { print $_ }
+ else
+ { print $MS{$_} }
+ print " " }
+ print "\n" }
+
+#D The messages are saved in a hash table and are called
+#D by name. This contents of this table depends on the
+#D interface language in use.
+
+#D \startcompressdefinitions
+
+if ($UserInterface eq "nl")
+
+ { # begin of dutch section
+
+ $MS{"ProcessingReferences"} = "commando's, lijsten en indexen verwerken" ;
+ $MS{"MergingReferences"} = "indexen samenvoegen" ;
+ $MS{"GeneratingDocumentation"} = "ConTeXt documentatie file voorbereiden" ;
+ $MS{"GeneratingSources"} = "ConTeXt broncode file genereren" ;
+ $MS{"FilteringDefinitions"} = "ConTeXt definities filteren" ;
+ $MS{"CopyingTemplates"} = "TeXEdit toets templates copieren" ;
+ $MS{"CopyingInformation"} = "TeXEdit help informatie copieren" ;
+ $MS{"GeneratingFigures"} = "figuur file genereren" ;
+ $MS{"FilteringLogFile"} = "log file filteren (poor mans version)" ;
+
+ $MS{"SortingIJ"} = "IJ sorteren onder Y" ;
+ $MS{"ConvertingHigh"} = "hoge ASCII waarden converteren" ;
+ $MS{"ProcessingQuotes"} = "characters met accenten afhandelen" ;
+ $MS{"ForcingFileType"} = "filetype instellen" ;
+ $MS{"UsingEps"} = "EPS files afhandelen" ;
+ $MS{"UsingTif"} = "TIF files afhandelen" ;
+ $MS{"UsingPdf"} = "PDF files afhandelen" ;
+ $MS{"UsingPng"} = "PNG files afhandelen" ;
+ $MS{"UsingJpg"} = "JPG files afhandelen" ;
+ $MS{"EpsToPdf"} = "EPS converteren naar PDF";
+ $MS{"EpsPage"} = "EPS pagina instellen";
+ $MS{"FilteringBoxes"} = "overfull boxes filteren" ;
+ $MS{"ApplyingCriterium"} = "criterium toepassen" ;
+ $MS{"FilteringUnknown"} = "onbekende ... filteren" ;
+
+ $MS{"NoInputFile"} = "geen invoer file opgegeven" ;
+ $MS{"NoOutputFile"} = "geen uitvoer file gegenereerd" ;
+ $MS{"EmptyInputFile"} = "lege invoer file" ;
+ $MS{"NotYetImplemented"} = "nog niet beschikbaar" ;
+
+ $MS{"Action"} = " actie :" ;
+ $MS{"Option"} = " optie :" ;
+ $MS{"Error"} = " fout :" ;
+ $MS{"Remark"} = " opmerking :" ;
+ $MS{"SystemCall"} = " systeemaanroep :" ;
+ $MS{"BadSystemCall"} = " foute systeemaanroep :" ;
+ $MS{"MissingSubroutine"} = " onbekende subroutine :" ;
+
+ $MS{"EmbeddedFiles"} = " gebruikte files :" ;
+ $MS{"BeginEndError"} = " b/e fout in :" ;
+ $MS{"SynonymEntries"} = " aantal synoniemen :" ;
+ $MS{"SynonymErrors"} = " fouten :" ;
+ $MS{"RegisterEntries"} = " aantal ingangen :" ;
+ $MS{"RegisterErrors"} = " fouten :" ;
+ $MS{"PassedCommands"} = " aantal commando's :" ;
+
+ $MS{"MultiPagePdfFile"} = " te veel pagina's :" ;
+ $MS{"MissingMediaBox"} = " geen mediabox :" ;
+ $MS{"MissingBoundingBox"} = " geen boundingbox :" ;
+
+ $MS{"NOfDocuments"} = " documentatie blokken :" ;
+ $MS{"NOfDefinitions"} = " definitie blokken :" ;
+ $MS{"NOfSkips"} = " overgeslagen blokken :" ;
+ $MS{"NOfSetups"} = " gecopieerde setups :" ;
+ $MS{"NOfTemplates"} = " gecopieerde templates :" ;
+ $MS{"NOfInfos"} = " gecopieerde helpinfos :" ;
+ $MS{"NOfFigures"} = " verwerkte figuren :" ;
+ $MS{"NOfBoxes"} = " te volle boxen :" ;
+ $MS{"NOfUnknown"} = " onbekende ... :" ;
+
+ $MS{"InputFile"} = " invoer file :" ;
+ $MS{"OutputFile"} = " outvoer file :" ;
+ $MS{"FileType"} = " type file :" ;
+ $MS{"EpsFile"} = " eps file :" ;
+ $MS{"PdfFile"} = " pdf file :" ;
+ $MS{"TifFile"} = " tif file :" ;
+ $MS{"PngFile"} = " png file :" ;
+ $MS{"JpgFile"} = " jpg file :" ;
+ $MS{"MPFile"} = " metapost file :" ;
+
+ $MS{"LoadedFilter"} = " geladen filter :" ;
+ $MS{"RemappedKeys"} = " onderschepte keys :" ;
+ $MS{"WrongFilterPath"} = " fout filter pad :" ;
+
+ $MS{"Overfull"} = "te vol" ;
+ $MS{"Entries"} = "ingangen" ;
+ $MS{"References"} = "verwijzingen" ;
+
+ $MS{"PlugInInit"} = " plugin initialized :" ;
+ $MS{"PlugInReport"} = " plugin report :" ;
+
+ } # end of dutch section
+
+elsif ($UserInterface eq "de")
+
+ { # begin of german section
+
+ $MS{"ProcessingReferences"} = "Verarbeiten der Befehle, Listen und Register" ;
+ $MS{"MergingReferences"} = "Register verschmelzen" ;
+ $MS{"GeneratingDocumentation"} = "Vorbereiten der ConTeXt-Dokumentationsdatei" ;
+ $MS{"GeneratingSources"} = "Erstellen einer nur Quelltext ConTeXt-Datei" ;
+ $MS{"FilteringDefinitions"} = "Filtern der ConTeXt-Definitionen" ;
+ $MS{"CopyingTemplates"} = "Kopieren der TeXEdit-Test-key-templates" ;
+ $MS{"CopyingInformation"} = "Kopieren der TeXEdit-Hilfsinformation" ;
+ $MS{"GeneratingFigures"} = "Erstellen einer Abb-Uebersichtsdatei" ;
+ $MS{"FilteringLogFile"} = "Filtern der log-Datei" ;
+
+ $MS{"SortingIJ"} = "Sortiere IJ nach Y" ;
+ $MS{"ConvertingHigh"} = "Konvertiere hohe ASCII-Werte" ;
+ $MS{"ProcessingQuotes"} = "Verarbeiten der Akzentzeichen" ;
+ $MS{"ForcingFileType"} = "Dateityp einstellen" ;
+ $MS{"UsingEps"} = "EPS-Dateien verarbeite" ;
+ $MS{"UsingTif"} = "TIF-Dateien verarbeite" ;
+ $MS{"UsingPdf"} = "PDF-Dateien verarbeite" ;
+ $MS{"UsingPng"} = "PNG-Dateien verarbeite" ;
+ $MS{"UsingJpg"} = "JPG-Dateien verarbeite" ;
+ $MS{"EpsToPdf"} = "convert EPS to PDF";
+ $MS{"EpsPage"} = "setup EPS page";
+
+ $MS{"FilteringBoxes"} = "Filtern der ueberfuellten Boxen" ;
+ $MS{"ApplyingCriterium"} = "Anwenden des uebervoll-Kriteriums" ;
+ $MS{"FilteringUnknown"} = "Filter unbekannt ..." ;
+
+ $MS{"NoInputFile"} = "Keine Eingabedatei angegeben" ;
+ $MS{"NoOutputFile"} = "Keine Ausgabedatei generiert" ;
+ $MS{"EmptyInputFile"} = "Leere Eingabedatei" ;
+ $MS{"NotYetImplemented"} = "Noch nicht verfuegbar" ;
+
+ $MS{"Action"} = " Aktion :" ;
+ $MS{"Option"} = " Option :" ;
+ $MS{"Error"} = " Fehler :" ;
+ $MS{"Remark"} = " Anmerkung :" ;
+ $MS{"SystemCall"} = " system call :" ;
+ $MS{"BadSystemCall"} = " bad system call :" ;
+ $MS{"MissingSubroutine"} = " missing subroutine :" ;
+ $MS{"SystemCall"} = " Systemaufruf :" ;
+ $MS{"BadSystemCall"} = " Fehlerhafter Aufruf :" ;
+ $MS{"MissingSubroutine"} = " Fehlende Unterroutine :" ;
+
+ $MS{"EmbeddedFiles"} = " Eingebettete Dateien :" ;
+ $MS{"BeginEndError"} = " Beg./Ende-Fehler in :" ;
+ $MS{"SynonymEntries"} = " Synonymeintraege :" ;
+ $MS{"SynonymErrors"} = " Fehlerhafte Eintraege :" ;
+ $MS{"RegisterEntries"} = " Registereintraege :" ;
+ $MS{"RegisterErrors"} = " Fehlerhafte Eintraege :" ;
+ $MS{"PassedCommands"} = " Verarbeite Befehle :" ;
+
+ $MS{"MultiPagePdfFile"} = " zu viele Seiten :" ;
+ $MS{"MissingMediaBox"} = " fehlende mediabox :" ;
+ $MS{"MissingBoundingBox"} = " fehlende boundingbox :" ;
+
+ $MS{"NOfDocuments"} = " Dokumentbloecke :" ;
+ $MS{"NOfDefinitions"} = " Definitionsbloecke :" ;
+ $MS{"NOfSkips"} = "Uebersprungene Bloecke :" ;
+ $MS{"NOfSetups"} = " Kopierte setups :" ;
+ $MS{"NOfTemplates"} = " Kopierte templates :" ;
+ $MS{"NOfInfos"} = " Kopierte helpinfos :" ;
+ $MS{"NOfFigures"} = " Verarbeitete Abb. :" ;
+ $MS{"NOfBoxes"} = " Zu volle Boxen :" ;
+ $MS{"NOfUnknown"} = " Unbekannt ... :" ;
+
+ $MS{"InputFile"} = " Eingabedatei :" ;
+ $MS{"OutputFile"} = " Ausgabedatei :" ;
+ $MS{"FileType"} = " Dateityp :" ;
+ $MS{"EpsFile"} = " eps-Datei :" ;
+ $MS{"PdfFile"} = " pdf-Datei :" ;
+ $MS{"TifFile"} = " tif-Datei :" ;
+ $MS{"PngFile"} = " png-Datei :" ;
+ $MS{"JpgFile"} = " jpg-Datei :" ;
+ $MS{"MPFile"} = " metapost-Datei :" ;
+
+ $MS{"LoadedFilter"} = " loaded filter :" ; # tobias
+ $MS{"RemappedKeys"} = " remapped keys :" ; # tobias
+ $MS{"WrongFilterPath"} = " wrong filter path :" ; # tobias
+
+ $MS{"Overfull"} = "zu voll" ;
+ $MS{"Entries"} = "Eintraege" ;
+ $MS{"References"} = "Referenzen" ;
+
+ $MS{"ExtraProgram"} = " extra program :" ;
+ $MS{"PlugInInit"} = " plugin initialized :" ;
+ $MS{"PlugInReport"} = " plugin report :" ;
+
+ } # end of german section
+
+elsif ($UserInterface eq "it")
+
+ { # begin of italian section
+
+ $MS{"ProcessingReferences"} = "elaborazione di comandi, liste e registri" ;
+ $MS{"MergingReferences"} = "fusione dei registri" ;
+ $MS{"GeneratingDocumentation"} = "preparazione del file di documentazione ConTeXt" ;
+ $MS{"GeneratingSources"} = "generazione del solo sorgente ConTeXt" ;
+ $MS{"FilteringDefinitions"} = "filtraggio delle definizioni formali ConTeXt" ;
+ $MS{"CopyingTemplates"} = "copia dei modelli rapidi di voci di TeXEdit" ;
+ $MS{"CopyingInformation"} = "copia delle informazioni di aiuto di TeXEdit" ;
+ $MS{"GeneratingFigures"} = "generazione del file di elengo delle figure" ;
+ $MS{"FilteringLogFile"} = "filtraggio del file di log" ;
+
+ $MS{"SortingIJ"} = "IJ elencato sotto Y" ;
+ $MS{"ConvertingHigh"} = "conversione dei valori ASCII alti" ;
+ $MS{"ProcessingQuotes"} = "elaborazione dei caratteri accentati" ;
+ $MS{"ForcingFileType"} = "impostazine del tipo di file" ;
+ $MS{"UsingEps"} = "elaborazione del file EPS" ;
+ $MS{"UsingTif"} = "elaborazione del file TIF" ;
+ $MS{"UsingPdf"} = "elaborazione del file PDF" ;
+ $MS{"UsingPng"} = "elaborazione del file PNG" ;
+ $MS{"UsingJpg"} = "elaborazione del file JPG" ;
+ $MS{"EpsToPdf"} = "conversione da EPS a PDF";
+ $MS{"EpsPage"} = "impostazione pagina EPS";
+
+ $MS{"FilteringBoxes"} = "filtraggio delle overfull boxes" ;
+ $MS{"ApplyingCriterium"} = "applicazione del criterio overfull" ;
+ $MS{"FilteringUnknown"} = "filtraggio dei messaggi non conosciuti ..." ;
+
+ $MS{"NoInputFile"} = "nessun file di input specificato" ;
+ $MS{"NoOutputFile"} = "nessun file di output generato" ;
+ $MS{"EmptyInputFile"} = "file di input vuoto" ;
+ $MS{"NotYetImplemented"} = "non ancora disponibile" ;
+
+ $MS{"Action"} = " azione :" ;
+ $MS{"Option"} = " opzione :" ;
+ $MS{"Error"} = " errore :" ;
+ $MS{"Remark"} = " commento :" ;
+ $MS{"SystemCall"} = " chiamata di sistema :" ;
+ $MS{"BadSystemCall"} = "chiamata di sistema er :" ; # GB: Hans, I need more space!
+ $MS{"MissingSubroutine"} = " subroutine mancante :" ;
+
+ $MS{"EmbeddedFiles"} = " file inclusi :" ;
+ $MS{"BeginEndError"} = " errore di i/f in :" ;
+ $MS{"SynonymEntries"} = " voci di sinonimi :" ;
+ $MS{"SynonymErrors"} = " voci errate :" ;
+ $MS{"RegisterEntries"} = " voci di registro :" ;
+ $MS{"RegisterErrors"} = " voci errate :" ;
+ $MS{"PassedCommands"} = " comandi passati :" ;
+
+ $MS{"MultiPagePdfFile"} = " troppe pagine :" ;
+ $MS{"MissingMediaBox"} = " mediabox mancante :" ;
+ $MS{"MissingBoundingBox"} = " boundingbox mancante :" ;
+
+ $MS{"NOfDocuments"} = " blocchi di documento :" ;
+ $MS{"NOfDefinitions"} = "blocchi di definizioni :" ;
+ $MS{"NOfSkips"} = " blocchi saltati :" ;
+ $MS{"NOfSetups"} = " impostazioni copiate :" ;
+ $MS{"NOfTemplates"} = " modelli copiati :" ;
+ $MS{"NOfInfos"} = " helpinfo copiati :" ;
+ $MS{"NOfFigures"} = " figure elaborate :" ;
+ $MS{"NOfBoxes"} = " overfull boxes :" ;
+ $MS{"NOfUnknown"} = " sconosciuti ... :" ;
+
+ $MS{"InputFile"} = " file di input :" ;
+ $MS{"OutputFile"} = " file di output :" ;
+ $MS{"FileType"} = " tipo di file :" ;
+ $MS{"EpsFile"} = " file eps :" ;
+ $MS{"PdfFile"} = " file pdf :" ;
+ $MS{"TifFile"} = " file tif :" ;
+ $MS{"PngFile"} = " file png :" ;
+ $MS{"JpgFile"} = " file jpg :" ;
+ $MS{"MPFile"} = " file metapost :" ;
+
+ $MS{"LoadedFilter"} = " filtro caricato :" ;
+ $MS{"RemappedKeys"} = " voci rimappate :" ;
+ $MS{"WrongFilterPath"} = "percorso filtro errato :" ;
+
+ $MS{"Overfull"} = "overfull" ;
+ $MS{"Entries"} = "voci" ;
+ $MS{"References"} = "riferimenti" ;
+
+ $MS{"ExtraProgram"} = " extra program :" ;
+ $MS{"PlugInInit"} = " plugin initialized :" ;
+ $MS{"PlugInReport"} = " plugin report :" ;
+
+ } # end of italian section
+
+else
+
+ { # begin of english section
+
+ $MS{"ProcessingReferences"} = "processing commands, lists and registers" ;
+ $MS{"MergingReferences"} = "merging registers" ;
+ $MS{"GeneratingDocumentation"} = "preparing ConTeXt documentation file" ;
+ $MS{"GeneratingSources"} = "generating ConTeXt source only file" ;
+ $MS{"FilteringDefinitions"} = "filtering formal ConTeXt definitions" ;
+ $MS{"CopyingTemplates"} = "copying TeXEdit quick key templates" ;
+ $MS{"CopyingInformation"} = "copying TeXEdit help information" ;
+ $MS{"GeneratingFigures"} = "generating figure directory file" ;
+ $MS{"FilteringLogFile"} = "filtering log file" ;
+
+ $MS{"SortingIJ"} = "sorting IJ under Y" ;
+ $MS{"ConvertingHigh"} = "converting high ASCII values" ;
+ $MS{"ProcessingQuotes"} = "handling accented characters" ;
+ $MS{"ForcingFileType"} = "setting up filetype" ;
+ $MS{"UsingEps"} = "processing EPS-file" ;
+ $MS{"UsingTif"} = "processing TIF-file" ;
+ $MS{"UsingPdf"} = "processing PDF-file" ;
+ $MS{"UsingPng"} = "processing PNG-file" ;
+ $MS{"UsingJpg"} = "processing JPG-file" ;
+ $MS{"EpsToPdf"} = "convert EPS to PDF";
+ $MS{"EpsPage"} = "setup EPS page";
+
+ $MS{"FilteringBoxes"} = "filtering overfull boxes" ;
+ $MS{"ApplyingCriterium"} = "applying overfull criterium" ;
+ $MS{"FilteringUnknown"} = "filtering unknown ..." ;
+
+ $MS{"NoInputFile"} = "no input file given" ;
+ $MS{"NoOutputFile"} = "no output file generated" ;
+ $MS{"EmptyInputFile"} = "empty input file" ;
+ $MS{"NotYetImplemented"} = "not yet available" ;
+
+ $MS{"Action"} = " action :" ;
+ $MS{"Option"} = " option :" ;
+ $MS{"Error"} = " error :" ;
+ $MS{"Remark"} = " remark :" ;
+ $MS{"SystemCall"} = " system call :" ;
+ $MS{"BadSystemCall"} = " bad system call :" ;
+ $MS{"MissingSubroutine"} = " missing subroutine :" ;
+
+ $MS{"EmbeddedFiles"} = " embedded files :" ;
+ $MS{"BeginEndError"} = " b/e error in :" ;
+ $MS{"SynonymEntries"} = " synonym entries :" ;
+ $MS{"SynonymErrors"} = " bad entries :" ;
+ $MS{"RegisterEntries"} = " register entries :" ;
+ $MS{"RegisterErrors"} = " bad entries :" ;
+ $MS{"PassedCommands"} = " passed commands :" ;
+
+ $MS{"MultiPagePdfFile"} = " too many pages :" ;
+ $MS{"MissingMediaBox"} = " missing mediabox :" ;
+ $MS{"MissingBoundingBox"} = " missing boundingbox :" ;
+
+ $MS{"NOfDocuments"} = " document blocks :" ;
+ $MS{"NOfDefinitions"} = " definition blocks :" ;
+ $MS{"NOfSkips"} = " skipped blocks :" ;
+ $MS{"NOfSetups"} = " copied setups :" ;
+ $MS{"NOfTemplates"} = " copied templates :" ;
+ $MS{"NOfInfos"} = " copied helpinfos :" ;
+ $MS{"NOfFigures"} = " processed figures :" ;
+ $MS{"NOfBoxes"} = " overfull boxes :" ;
+ $MS{"NOfUnknown"} = " unknown ... :" ;
+
+ $MS{"InputFile"} = " input file :" ;
+ $MS{"OutputFile"} = " output file :" ;
+ $MS{"FileType"} = " file type :" ;
+ $MS{"EpsFile"} = " eps file :" ;
+ $MS{"PdfFile"} = " pdf file :" ;
+ $MS{"TifFile"} = " tif file :" ;
+ $MS{"PngFile"} = " png file :" ;
+ $MS{"JpgFile"} = " jpg file :" ;
+ $MS{"MPFile"} = " metapost file :" ;
+
+ $MS{"LoadedFilter"} = " loaded filter :" ;
+ $MS{"RemappedKeys"} = " remapped keys :" ;
+ $MS{"WrongFilterPath"} = " wrong filter path :" ;
+
+ $MS{"Overfull"} = "overfull" ;
+ $MS{"Entries"} = "entries" ;
+ $MS{"References"} = "references" ;
+
+ $MS{"ExtraProgram"} = " extra program :" ;
+ $MS{"PlugInInit"} = " plugin initialized :" ;
+ $MS{"PlugInReport"} = " plugin report :" ;
+
+ } # end of english section
+
+#D \stopcompressdefinitions
+
+#D Showing the banner (name and version of the program) and
+#D offering helpinfo is rather straightforward.
+
+sub ShowBanner
+ { Report("\n $Program\n") }
+
+sub ShowHelpInfo
+ { Report("HelpInfo") }
+
+#D The helpinfo is also saved in the hash table. This looks
+#D like a waste of energy and space, but the program gains
+#D readability.
+
+#D \startcompressdefinitions
+
+if ($UserInterface eq "nl")
+
+ { # begin of dutch section
+
+ $MS{"HelpInfo"} =
+
+" --references hulp file verwerken / tui->tuo \n" .
+" --ij : IJ als Y sorteren \n" .
+" --high : hoge ASCII waarden converteren \n" .
+" --quotes : quotes converteren \n" .
+" --tcxpath : tcx filter pad \n" .
+" \n" .
+" --purge(all) tijdelijke (klad) files verwijderen \n" .
+" \n" .
+" --documents documentatie file genereren / tex->ted \n" .
+" --sources broncode file genereren / tex->tes \n" .
+" --setups ConTeXt definities filteren / tex->texutil.tus \n" .
+" --templates TeXEdit templates filteren / tex->tud \n" .
+" --infos TeXEdit helpinfo filteren / tex->tud \n" .
+" \n" .
+" --figures eps figuren lijst genereren / *->texutil.tuf \n" .
+" --epspage : voorbereiden voor pdf \n" .
+" --epstopdf : omzetten naar pdf \n" .
+" \n" .
+" --logfile logfile filteren / log->$ProgramLog \n" .
+" --box : overfull boxes controleren \n" .
+" --criterium : overfull criterium in pt \n" .
+" --unknown :onbekende ... controleren \n" ;
+
+ } # end of dutch section
+
+elsif ($UserInterface eq "de")
+
+ { # begin of german section
+
+ $MS{"HelpInfo"} =
+
+" --references Verarbeiten der Hilfsdatei / tui->tuo \n" .
+" --ij : Sortiere IJ als Y \n" .
+" --high : Konvertiere hohe ASCII-Werte \n" .
+" --quotes : Konvertiere akzentuierte Buchstaben \n" .
+" --tcxpath : tcx Filter Path \n" .
+" \n" .
+" --purge(all) entferne temporaere ConTeXt-Dateien \n" .
+" \n" .
+" --documents Erstelle Dokumentationsdatei / tex->ted \n" .
+" --sources Erstelle reine Quelltextdateien / tex->tes \n" .
+" --setups Filtere ConTeXt-Definitionen / tex->texutil.tus\n" .
+" --templates Filtere TeXEdit-templates / tex->tud \n" .
+" --infos Filtere TeXEdit-helpinfo / tex->tud \n" .
+" \n" .
+" --figures Erstelle eps-Abbildungsliste / *->texutil.tuf \n" .
+" --epspage : Bereite fuer pdf vor \n" .
+" --epstopdf : Konvertiere zu pdf \n" .
+" \n" .
+" --logfile Filtere log-Datei / log->$ProgramLog \n" .
+" --box : Ueberpruefe uebervolle Boxen \n" .
+" --criterium : Uebervoll-Kriterium in pt \n" .
+" --unknown : Ueberpruefe auf unbekannte ... \n" ;
+
+ } # end of german section
+
+elsif ($UserInterface eq "it")
+
+ { # begin of italian section GB: Hans, I need more space!
+
+ $MS{"HelpInfo"} =
+
+" --references elabora file ausiliari / tui->tuo \n" .
+" --ij : elenca IJ come Y \n" .
+" --high : converti i valori ASCII alti \n" .
+" --quotes : converti caratteri accentati \n" .
+" --tcxpath : percorso del filtro tcx \n" .
+" \n" .
+" --purge(all) rimuovi i file temporanei ConTeXt \n" .
+" \n" .
+" --documents genera file di documentazione / tex->ted \n" .
+" --sources genera solo sorgente / tex->tes \n" .
+" --setups filtra definizioni ConTeXt / tex->texutil.tus \n" .
+" --templates filtra modelli TeXEdit / tex->tud \n" .
+" --infos filtra helpinfo TeXEdit / tex->tud \n" .
+" \n" .
+" --figures genera lista figure eps / *->texutil.tuf \n" .
+" --epspage : prepara per pdf \n" .
+" --epstopdf : converti in pdf \n" .
+" \n" .
+" --logfile filtra logfile / log->$ProgramLog \n" .
+" --box : controlla overful boxes \n" .
+" --criterium : criterio overfull in pt \n" .
+" --unknown : controlla sconosciuti ... \n" ;
+
+ } # end of italian section
+
+else
+
+ { # begin of english section
+
+ $MS{"HelpInfo"} =
+
+" --references process auxiliary file / tui->tuo \n" .
+" --ij : sort IJ as Y \n" .
+" --high : convert high ASCII values \n" .
+" --quotes : convert quotes characters \n" .
+" --tcxpath : tcx filter path \n" .
+" \n" .
+" --purge(all) clean up temporary context files \n" .
+" \n" .
+" --documents generate documentation file / tex->ted \n" .
+" --sources generate source only file / tex->tes \n" .
+" --setups filter ConTeXt definitions / tex->texutil.tus \n" .
+" --templates filter TeXEdit templates / tex->tud \n" .
+" --infos filter TeXEdit helpinfo / tex->tud \n" .
+" \n" .
+" --figures generate eps figure list / *->texutil.tuf \n" .
+" --epspage : prepare for pdf \n" .
+" --epstopdf : convert to pdf \n" .
+" \n" .
+" --logfile filter logfile / log->$ProgramLog \n" .
+" --box : check overful boxes \n" .
+" --criterium : overfull criterium in pt \n" .
+" --unknown : check unknown ... \n" ;
+
+ } # end of english section
+
+#D \stopcompressdefinitions
+
+#D In order to sort strings correctly, we have to sanitize
+#D them. This is especially needed when we include \TEX\
+#D commands, quotes characters and compound word placeholders.
+#D
+#D \startopsomming[opelkaar]
+#D \som \type{\name}: csnames are stripped
+#D \som \type{{}}: are removed
+#D \som \type{\"e}: and alike are translated into \type{"e} etc.
+#D \som \type{"e}: is translated into an \type{e} and \type{b} etc.
+#D \som \type{||}: becomes \type{-}
+#D \som \type{\-}: also becomes \type{-}
+#D \som \type{<*..>}: becomes \type{..} (internal XML entity)
+#D \stopopsomming
+#D
+#D Of course other accented characters are handled too. The
+#D appended string is responsible for decent sorting.
+#D
+#D \startPL
+#D $TargetString = SanitizedString ( $SourceString ) ;
+#D \stopPL
+#D
+#D The sort order depends on the ordering in array
+#D \type{$ASCII}:
+
+$ASCII{"^"} = "a" ; $ASCII{'"'} = "b" ; $ASCII{"`"} = "c" ;
+$ASCII{"'"} = "d" ; $ASCII{"~"} = "e" ; $ASCII{","} = "f" ;
+
+#sub SanitizedString
+# { my ($string) = $_[0] ;
+# if ($ProcessQuotes)
+# { $string =~ s/\\([\^\"\`\'\~\,])/$1/gio ;
+# $copied = $string ;
+# $copied =~ s/([\^\"\`\'\~\,])([a-zA-Z])/$ASCII{$1}/gio ;
+# $string =~ s/([\^\"\`\'\~\,])([a-zA-Z])/$2/gio ;
+# $string=$string.$copied }
+# $string =~ s/\\-|\|\|/\-/gio ;
+# $string =~ s/\\[a-zA-Z]*| |\{|\}//gio ;
+# return $string }
+
+#D YET UNDOCUMENTED
+
+my $SortN = 0 ; my @Filter ;
+
+# copied from texexec
+
+my @paths ;
+my $kpsewhich = '' ;
+my $pathslash = '/' ; if ($0 =~ /\\/) { $pathslash = "\\" }
+
+sub checked_path
+ { my $path = shift ;
+ if ((defined($path))&&($path ne ''))
+ { $path =~ s/[\/\\]/$pathslash/go ;
+ $path =~ s/[\/\\]*$//go ;
+ $path .= $pathslash }
+ else
+ { $path = '' }
+ return $path }
+
+if ($ENV{PATH} =~ /\;/)
+ { @paths = split(/\;/,$ENV{PATH}) }
+else
+ { @paths = split(/\:/,$ENV{PATH}) }
+
+# until here.
+
+sub InitializeKeys
+ { my $filename = $ARGV[0] ;
+ return unless (open(TEX,"$filename.tex")) ;
+ for ($i=0;$i<=255;$i++)
+ { @Filter[$i] = $i }
+ if ($TcXPath eq '')
+ { foreach (@paths)
+ { my $p = checked_path($_) . 'kpsewhich' ;
+ if ((-e $p)||(-e $p . '.exe'))
+ { $kpsewhich = $p ; last } } }
+ $kpsewhich = "\"$kpsewhich\"" if ($kpsewhich =~ m/^[^\"].* /) ;
+ while (<TEX>)
+ { chomp ;
+ my $Filter ;
+ if (/^\%/)
+ { if (s/.*translat.*?=([\:\/0-9\-a-z]*)/$1/oi)
+ { my $Translation = $_ ;
+ if ($TcXPath ne '')
+ { $TcXPath = checked_path($TcXPath) ;
+ $Filter = "$TcXPath$pathslash$Translation.tcx" }
+ elsif ($kpsewhich ne '')
+ { $Filter = `$kpsewhich --format="web2c files" $Translation.tcx` ;
+ chomp $Filter }
+ else
+ { last }
+ if (open(ASC,$Filter))
+ { Report ("LoadedFilter", $Translation) ;
+ while (<ASC>)
+ { if (/^(\d+)\s*(\d+)/)
+ { @Filter[$2] = $1 } }
+ close (ASC) }
+ elsif ($TcXPath ne '')
+ { Report ("WrongFilterPath", $TcXPath) }
+ last } }
+ else
+ { last } }
+ close (TEX) }
+
+sub HandleKey
+ { ++$SortN ;
+ $RestOfLine =~ s/\{(.*)\}/$1/o ;
+ my ($lan, $enc, $str, $chr, $map, $alf) = split(/\}\s*\{/, $RestOfLine) ;
+ if ($str =~ /^(\d+)/) { $str = ''.chr(@Filter[$1]) }
+ $map = chr(ord($MAP[$i])+128) ;
+ $STR[$SortN] = $str ;
+ $CHR[$SortN] = $chr ;
+ $MAP[$SortN] = $map ;
+#print "$chr$map = $alf\n" ;
+# $ALF{"$chr$map"} = $alf }
+ $ALF{"$map"} = $alf }
+
+sub FlushKeys
+ { Report ("RemappedKeys", $SortN) }
+
+sub SanitizedString
+ { my $string = my $original = shift ;
+ if ($SortN)
+ { my $copied = $string ;
+ for ($i=1;$i<=$SortN;$i++)
+ { my $s = $STR[$i] ;
+ my $c = $CHR[$i] ;
+ my $m = $MAP[$i] ;
+ # print "[$i $s $c $m]\n" ;
+ $string =~ s/($s)/$c/ge ;
+ $copied =~ s/($s)/$m/ge }
+ $string .= "\x00";
+ $string .= $copied }
+ elsif ($ProcessQuotes)
+ { $string =~ s/\\([\^\"\`\'\~\,])/$1/gio ;
+ $copied = $string ;
+ $copied =~ s/([\^\"\`\'\~\,])([a-zA-Z])/$ASCII{$1}/gi ;
+ $string =~ s/([\^\"\`\'\~\,])([a-zA-Z])/$2/gio ;
+ $string .= "\x00";
+ $string .= $copied }
+# new and very experimental, will change
+$string =~ s/\<\*(.*?)\>/\\$1 /go ; # reduce entities / will be table too
+$string =~ s/\\getXMLentity\s*\{(.*?)\}/$1/gio ; # {tex} => tex
+$string =~ s/\<[a-zA-Z\/].*?\>//go ; # remove elements
+# so far
+ $string =~ s/\\-|\|\|/\-/gio ;
+ $string =~ s/\\[a-zA-Z]*| |\{|\}//gio ; # ?
+#print "$original $string $copied\n" ;
+ return $string }
+
+#D This subroutine looks a bit complicated, which is due to the
+#D fact that we want to sort for instance an accented \type{e}
+#D after the plain \type{e}, so the imaginary words
+#D
+#D \starttypen
+#D eerste
+#D \"eerste
+#D \"e\"erste
+#D eerst\"e
+#D \stoptypen
+#D
+#D come out in an acceptable order.
+
+#D We also have to deal with the typical \TEX\ sequences with
+#D the double \type{^}'s, like \type{^^45}. These hexadecimal
+#D coded characters are just converted.
+#D
+#D \startPL
+#D $TargetString = HighConverted ( $SourceString ) ;
+#D \stopPL
+
+sub HighConverted
+ { my ($string) = $_[0] ;
+ $string =~ s/\^\^([a-f0-9][a-f0-9])/chr hex($1)/geo ;
+ return $string }
+
+#D \extras
+#D {references}
+#D
+#D \CONTEXT\ can handle many lists, registers (indexes),
+#D tables of whatever and references. This data is collected
+#D in one pass and processed in a second one. In between,
+#D relevant data is saved in the file \type{\jobname.tui}.
+#D This file also holds some additional information concerning
+#D second pass optimizations.
+#D
+#D The main task of \TEXUTIL\ is to sort lists and registers
+#D (indexes). The results are stored in again one file called
+#D \type{\jobname.tuo}.
+#D
+#D Just for debugging purposes the nesting of files loaded
+#D during the \CONTEXT\ run is stored. Of course this only
+#D applies to files that are handled by the \CONTEXT\ file
+#D structuring commands (projects, products, components and
+#D environments).
+#D
+#D We have to handle the entries:
+#D
+#D \starttypen
+#D f b {test}
+#D f e {test}
+#D \stoptypen
+#D
+#D and only report some status info at the end of the run.
+
+sub InitializeFiles
+ { $NOfFiles = 0 ;
+ $NOfBadFiles = 0 }
+
+sub HandleFile
+ { $RestOfLine =~ s/.*\{(.*)\}/$1/gio ;
+ ++$Files{$RestOfLine} }
+
+sub FlushFiles # hash needs to be sorted, else problem on macosx
+ { print TUO "%\n" . "% $Program / Files\n" . "%\n" ;
+ foreach $File (sort keys %Files)
+ { print TUO "% $File ($Files{$File})\n" }
+ print TUO "%\n" ;
+ $NOfFiles = keys %Files ;
+ Report("EmbeddedFiles", $NOfFiles) ;
+ foreach $File (sort keys %Files)
+ { unless (($Files{$File} % 2) eq 0)
+ { ++$NOfBadFiles ;
+ Report("BeginEndError", $File) } } }
+
+#D Commands don't need a special treatment. They are just
+#D copied. Such commands are tagged by a \type{c}, like:
+#D
+#D \starttypen
+#D c \thisisutilityversion{year.month.day}
+#D c \twopassentry{class}{key}{value}
+#D c \mainreference{prefix}{entry}{pagenumber}{realpage}{tag}
+#D c \listentry{category}{tag}{number}{title}{pagenumber}{realpage}
+#D c \initializevariable\realnumberofpages{number}
+#D \stoptypen
+#D
+#D For historic reasons we check for the presense of the
+#D backslash.
+
+my $NOfPositionsFound = 0 ;
+my $TotalNOfPositions = 0 ;
+my $TotalNOfMPgraphics = 0 ;
+
+my $SectionSeparator = ":" ;
+
+sub InitializeCommands
+ { print TUO "%\n" . "% $Program / Commands\n" . "%\n" ;
+ $NOfCommands = 0 }
+
+sub HandleCommand
+ { ++$NOfCommands ;
+ $RestOfLine =~ s/^\\//go ;
+ if ($RestOfLine =~ /^pospxy/o)
+ { ++$NOfPositionsFound }
+ elsif ($RestOfLine =~ /^initializevariable\\totalnofpositions\{(.*)\}/o)
+ { $TotalNOfPositions = $1 }
+ elsif ($RestOfLine =~ /^initializevariable\\totalnofMPgraphics\{(.*)\}/o)
+ { $TotalNOfMPgraphics = $1 }
+# todo: reg how to
+# elsif ($RestOfLine =~ /^thisissectionseparator\{(.*)\}/o)
+# { $SectionSeparator = $1 }
+ elsif ($RestOfLine =~ /^thisisbytesequence\{(.*)\}/o)
+ { $RestOfLine =~ s/\^//go }
+ print TUO "\\$RestOfLine\n" }
+
+sub FlushCommands
+ { Report ("PassedCommands", $NOfCommands) }
+
+#D Experimental: Extra
+#D
+#D s p : extra programs
+
+my @ExtraPrograms = () ;
+
+sub InitializeExtra
+ { }
+
+sub HandleExtra
+ { if ($RestOfLine =~ /(.)\s+(.*)\s*$/o)
+ { if ($1 eq "p")
+ { my $str = $2 ; $str =~ s/^\{(.*)\}$/$1/o ;
+ push @ExtraPrograms,$str } } }
+
+sub FlushExtra
+ { print TUO "%\n" . "% $Program / System\n" . "%\n" ;
+ foreach $EP (@ExtraPrograms)
+ { print TUO "% extra program : $EP\n" } }
+
+sub RunExtraPrograms
+ { foreach $EP (@ExtraPrograms)
+ { Report ("ExtraProgram", $EP) ;
+ system($EP) } }
+
+#D Plugins
+#D
+#D test.pm:
+#D
+#D \starttypen
+#D see plugtest.pm
+#D \stoptypen
+#D
+#D utility format:
+#D
+#D \starttypen
+#D p u {name} {data} {data} ...
+#D \stoptypen
+
+my $pm_path ;
+
+BEGIN
+ { ## $pm_path = `kpsewhich --format="other text files" --progname=context texutil.pl` ;
+ ## chomp($pm_path) ;
+ # $pm_path =~ s/texutil\.pl.*// }
+ # $pm_path = $0 ;
+ # $pm_path =~ s/\\/\//o ;
+ # $pm_path =~ s/texutil\.pl.*//io ;
+ ## $pm_path =~ s/(.*)texutil.*?$/$1/i ;
+ $pm_path = "$FindBin::Bin/" ;
+ if ($pm_path eq "") { $pm_path = "./" } }
+
+use lib $pm_path ;
+
+my %UserPlugIns ;
+
+sub HandlePlugIn
+ { if ($RestOfLine =~ /\s*u\s*\{(.*?)\}\s*(.*)\s*/io)
+ { my $tag = $1 ;
+ my $arg = $2 ;
+ if (! defined($UserPlugIns{$tag}))
+ { $UserPlugIns{$tag} = 1 ;
+ eval("use $tag") ;
+ my $result = $tag->identify ;
+ if ($result ne "")
+ { Report ("PlugInInit", "$tag -> $result") }
+ else
+ { Report ("PlugInInit", $tag ) }
+ $tag->initialize() }
+ if (defined($UserPlugIns{$tag}))
+ { $arg =~ s/\{(.*)\}/$1/o ;
+ my @args = split(/\}\s*\{/o, $arg) ;
+ $tag->handle(@args) } } }
+
+sub FlushPlugIns
+ { foreach my $tag (keys %UserPlugIns)
+ { my @report = $tag->report ;
+ foreach $rep (@report)
+ { my ($key,$val) = split (/\s*\:\s*/,$rep) ;
+ if ($val ne "")
+ { Report ("PlugInReport", "$tag -> $key -> $val") }
+ else
+ { Report ("PlugInReport", "$tag -> $key") } }
+ $tag->process ;
+ print TUO "%\n" . "% $Program / " . $tag->identify . "\n" . "%\n" ;
+ foreach my $str ($tag->results)
+ { print TUO "\\plugincommand\{$str\}\n" } } }
+
+#D Synonyms are a sort of key||value pairs and are used for
+#D ordered lists like abbreviations and units.
+#D
+#D \starttypen
+#D s e {class}{sanitized key}{key}{associated data}
+#D \stoptypen
+#D
+#D The sorted lists are saved as (surprise):
+#D
+#D \starttypen
+#D \synonymentry{class}{sanitized key}{key}{associated data}
+#D \stoptypen
+
+sub InitializeSynonyms
+ { $NOfSynonyms = 0 ;
+ $NOfBadSynonyms = 0 }
+
+#M \definieersynoniem [testname] [testnames] [\testmeaning]
+#M
+#M \stelsynoniemenin [testname] [criterium=alles]
+
+#D Let's first make clear what we can expect. Synonym
+#D entries look like:
+#D
+#D \startbuffer
+#D \testname [alpha] {\sl alpha} {a greek letter a}
+#D \testname {alpha} {another a}
+#D \testname [Beta] {\kap{beta}} {a greek letter b}
+#D \testname {beta} {indeed another b}
+#D \testname {gamma} {something alike g}
+#D \testname {delta} {just a greek d}
+#D \stopbuffer
+#D
+#D \typebuffer
+#D
+#D This not that spectacular list is to be sorted according
+#D to the keys (names). \haalbuffer
+
+sub HandleSynonym
+ { ++$NOfSynonyms ;
+ ($SecondTag, $RestOfLine) = split(/ /, $RestOfLine, 2) ;
+ ($Class, $Key, $Entry, $Meaning) = split(/} \{/, $RestOfLine) ;
+ chop $Meaning ;
+ $Class = substr $Class, 1 ;
+ if ($Entry eq "")
+ { ++$NOfBadSynonyms }
+ else
+ { $SynonymEntry[$NOfSynonyms] =
+ join ($JOIN,$Class,$Key,$Entry,$Meaning) } }
+
+#D Depending on the settings\voetnoot{One can call for
+#D all defined entries, call only the used ones, change
+#D layout, attach (funny) commands etc.} a list of
+#D {\em testnames} looks like:
+#D
+#D \plaatslijstmettestnames
+#D
+#D Watch the order in which these entries are sorted.
+
+sub FlushSynonyms
+ { print TUO "%\n" . "% $Program / Synonyms\n" . "%\n" ;
+ @SynonymEntry = sort { lc($a) cmp lc($b) } @SynonymEntry ;
+ $NOfSaneSynonyms = 0 ;
+ for ($n=1; $n<=$NOfSynonyms; $n++)
+ { # check normally not needed
+ if (($n==1)||($SynonymEntry[$n] ne $SynonymEntry[$n-1]))
+ { ($Class, $Key, $Entry, $Meaning) =
+ split(/$JOIN/, $SynonymEntry[$n]) ;
+ ++$NOfSaneSynonyms ;
+ print TUO "\\synonymentry{$Class}{$Key}{$Entry}{$Meaning}\n" } }
+ Report("SynonymEntries", $NOfSynonyms, "->", $NOfSaneSynonyms, "Entries") ;
+ if ($NOfBadSynonyms>0)
+ { Report("SynonymErrors", $NOfBadSynonyms) } }
+
+#D Register entries need a bit more care, especially when they
+#D are nested. In the near future we will also handle page
+#D ranges.
+#D
+#D \starttypen
+#D r e {class}{tag}{sanitized key}{key}{pagenumber}{realpage}
+#D r s {class}{tag}{sanitized key}{key}{string}{pagenumber}
+#D r r {class}{tag}{sanitized key}{key}{string}{pagenumber}
+#D \stoptypen
+#D
+#D The last one indicates the start of a range.
+
+#D The first one is the normal entry, the second one concerns
+#D {\em see this or that} entries. Keys are sanitized, unless
+#D the user supplies a sanitized key. To save a lot of
+#D programming, all data concerning an entry is stored in one
+#D string. Subentries are specified as:
+#D
+#D \starttypen
+#D first&second&third
+#D first+second+third
+#D \stoptypen
+#D
+#D When these characters are needed for typesetting purposes, we
+#D can also use the first character to specify the separator:
+#D
+#D \starttypen
+#D &$x^2+y^2=r^2$
+#D +this \& that
+#D \stoptypen
+#D
+#D Subentries are first unpacked and next stored in a
+#D consistent way, which means that we can use both separators
+#D alongside each other. We leave it to the reader to sort
+#D out the dirty tricks.
+
+$SPLIT ="%%" ;
+$JOIN ="__" ;
+
+sub InitializeRegisters
+ { $NOfEntries = 0 ;
+ $NOfBadEntries = 0 }
+
+$ProcessType = "" ;
+
+$RegStat{"f"} = 1 ;
+$RegStat{"e"} = 2 ; # end up between from and to
+$RegStat{"t"} = 3 ;
+$RegStat{"s"} = 4 ;
+
+my $RegSep = "$SectionSeparator$SectionSeparator" ;
+
+sub HandleRegister # the } { makes sure that local {} is ok
+ { ($SecondTag, $RestOfLine) = split(/ /, $RestOfLine, 2) ;
+ ++$NOfEntries ;
+ #~ if ($SecondTag eq "s")
+ #~ { ($Class, $Location, $Key, $Entry, $SeeToo, $Page ) =
+ #~ split(/} \{/, $RestOfLine) ;
+ #~ chop $Page ;
+ #~ $Class = substr $Class, 1 ;
+ #~ $RealPage = 0 }
+ #~ else
+ #~ { ($Class, $Location, $Key, $Entry, $Page, $RealPage ) =
+ #~ split(/} \{/, $RestOfLine) ;
+ #~ chop $RealPage ;
+ #~ $Class = substr $Class, 1 ;
+ #~ $SeeToo = "" }
+ if ($SecondTag eq "s")
+ { if ($RestOfLine =~ /^\s*(.*?)\}\s\{(.*?)\}\s\{(.*?)\}\s\{(.*)\}\s\{(.*?)\}\s\{(.*?)\s*$/o)
+ { ($Class, $Location, $Key, $Entry, $SeeToo, $Page ) = ($1,$2,$3,$4,$5,$6) ;
+ chop $Page ;
+ $Class = substr $Class, 1 ;
+ $RealPage = 0 }
+ else
+ { return } }
+ else
+ { if ($RestOfLine =~ /^\s*(.*?)\}\s\{(.*?)\}\s\{(.*?)\}\s\{(.*)\}\s\{(.*?)\}\s\{(.*?)\s*$/o)
+ { ($Class, $Location, $Key, $Entry, $Page, $RealPage ) = ($1,$2,$3,$4,$5,$6) ;
+ chop $RealPage ;
+ $Class = substr $Class, 1 ;
+ $SeeToo = "" }
+ else
+ { return } }
+ $_ = $Key ;
+ if (/$RegSep/)
+ { ($PageHow,$Key) = split (/$RegSep/) }
+ else
+ { $PageHow = "" }
+ $_ = $Entry ;
+ if (/$RegSep/)
+ { ($TextHow,$Entry) = split (/$RegSep/) }
+ else
+ { $TextHow = "" }
+ #
+ if ($Key eq "")
+ { $Key = SanitizedString($Entry) }
+ if ($SortMethod ne '')
+ { $ProcessHigh = 0 }
+ if ($ProcessHigh)
+ { $Key = HighConverted($Key) }
+ $KeyTag = substr $Key, 0, 1 ;
+ if ($KeyTag eq "&")
+ { $Key =~ s/^\&//go ;
+ $Key =~ s/([^\\])\&/$1$SPLIT/go }
+ elsif ($KeyTag eq "+")
+ { $Key =~ s/^\+//go ;
+ $Key =~ s/([^\\])\+/$1$SPLIT/go }
+ else
+ { $Key =~ s/([^\\])\&/$1$SPLIT/go ;
+ $Key =~ s/([^\\])\+/$1$SPLIT/go }
+ $Key .= " " ; # so, "Word" comes for "Word Another Word"
+ $EntryTag = substr $Entry, 0, 1 ;
+ if ($EntryTag eq "&")
+ { $Entry =~ s/^\&//go ;
+ $Entry =~ s/([^\\])\&/$1$SPLIT/go }
+ elsif ($EntryTag eq "+")
+ { $Entry =~ s/^\+//go ;
+ $Entry =~ s/([^\\])\+/$1$SPLIT/go }
+ elsif ($KeyTag eq "&")
+ { $Entry =~ s/([^\\])\&/$1$SPLIT/go }
+ elsif ($KeyTag eq "+")
+ { $Entry =~ s/([^\\])\+/$1$SPLIT/go }
+ else
+ { $Entry =~ s/([^\\])\&/$1$SPLIT/go ;
+ $Entry =~ s/([^\\])\+/$1$SPLIT/go }
+ $Key =~ s/^([^a-zA-Z])/ $1/go ;
+ $Key =~ s/^\s*\{(.*)\}$SPLIT/$1$SPLIT/go ; ####### new
+ $Entry =~ s/^\{(.*)\}$SPLIT/$1$SPLIT/go ; ###### new
+ if ($ProcessIJ) { $Key =~ s/ij/yy/go }
+ $LCKey = lc $Key ;
+ $RegStatus = $RegStat{$SecondTag} ;
+ $RealPageNumber= sprintf("%6i",$RealPage) ;
+ $RegisterEntry[$NOfEntries] =
+ join($JOIN,$Class,$LCKey,$Key,$Entry,$TextHow,$RegStatus,
+ $RealPageNumber,$Location,$Page,$PageHow,$SeeToo) }
+
+#M \definieerregister [testentry] [testentries]
+
+#D The previous routine deals with entries like:
+#D
+#D \startbuffer
+#D \testentry {alpha}
+#D \testentry {beta}
+#D \testentry {gamma}
+#D \testentry {gamma}
+#D \testentry {delta}
+#D \testentry {epsilon}
+#D \testentry {alpha+first}
+#D \testentry {alpha+second}
+#D \testentry {alpha+second}
+#D \testentry {alpha+third}
+#D \testentry {alpha+second+one}
+#D \testentry {alpha+second+one}
+#D \testentry {alpha+second+two}
+#D \testentry {alpha+second+three}
+#D \testentry {gamma+first+one}
+#D \testentry {gamma+second}
+#D \testentry {gamma+second+one}
+#D
+#D \testentry {alpha+fourth}
+#D \testentry {&alpha&fourth}
+#D \testentry {+alpha+fourth}
+#D
+#D \testentry [alpha+fourth] {alpha+fourth}
+#D \testentry [&alpha&fourth&one] {&alpha&fourth&one}
+#D \testentry [+alpha+fourth+two] {&alpha&fourth&two}
+#D
+#D \testentry {\kap{alpha}+fifth}
+#D \testentry {\kap{alpha}+f\'ifth}
+#D \testentry {\kap{alpha}+f"ifth}
+#D
+#D \testentry [&betaformula] {&$a^2+b^2=c^2$}
+#D
+#D \testentry {zeta \& more}
+#D
+#D \testentry [pagehowto::key]{texthowto::entry}
+#D
+#D % a very special case, when key has , and is constructed
+#D
+#D \testentry [pagehowto::{key}]{texthowto::{entry}}
+#D
+#D \stopbuffer
+#D
+#D \typebuffer
+#D
+#D \haalbuffer After being sorted, these entries are
+#D turned into something \TEX\ using:
+
+$CollapseEntries = 0 ;
+
+$RegisterEntry[0] = ("") ;
+
+sub How
+ { return "$TextHow$RegSep" . "$_[0]" }
+
+sub FlushSavedLine
+ { if (($CollapseEntries)&&($SavedFrom ne ""))
+ { if ($SavedTo ne "")
+ { print TUO "\\registerfrom$SavedFrom" ;
+ print TUO "\\registerto$SavedTo" }
+ else
+ { print TUO "\\registerpage$SavedFrom" } }
+ $SavedHow = "" ;
+ $SavedFrom = "" ;
+ $SavedTo = "" ;
+ $SavedEntry = "" }
+
+sub FlushRegisters
+ { print TUO "%\n" . "% $Program / Registers\n" . "%\n" ;
+ @RegisterEntry = sort { lc($a) cmp lc($b) } @RegisterEntry ;
+ $NOfSaneEntries = 0 ;
+ $NOfSanePages = 0 ;
+ $LastPage = "" ;
+ $LastRealPage = "" ;
+ $AlfaClass = "" ;
+ $Alfa = "" ;
+ $PreviousA = "" ;
+ $PreviousB = "" ;
+ $PreviousC = "" ;
+ $ActualA = "" ;
+ $ActualB = "" ;
+ $ActualC = "" ;
+
+ $SavedFrom = "" ;
+ $SavedTo = "" ;
+ $SavedEntry = "" ;
+ $SavedHow = "" ;
+
+ for ($n=1 ; $n<=$NOfEntries ; ++$n)
+ { ($Class, $LCKey, $Key, $Entry, $TextHow, $RegisterState,
+ $RealPage, $Location, $Page, $PageHow, $SeeToo) =
+ split(/$JOIN/, $RegisterEntry[$n]) ;
+ $RealPage =~ s/^\s*//o ;
+ $TestAlfa = lc substr $Key, 0, 1 ;
+ #
+ if ($SortN)
+ { $AlfKey = $Key ;
+ $AlfKey =~ s/(.).*\x00(.).*/$2/o ;
+ if (defined($ALF{$AlfKey}))
+ { $TestAlfa = $ALF{$AlfKey} } }
+ #
+ if ((lc $TestAlfa ne lc $Alfa) or ($AlfaClass ne $Class))
+ { # $Alfa= lc substr $Key, 0, 1 ;
+ $Alfa = $TestAlfa ;
+ $AlfaClass = $Class ;
+ if ($Alfa ne " ")
+ { FlushSavedLine ;
+ print TUO "\\registerentry{$Class}{$Alfa}\n" } }
+ ($ActualA, $ActualB, $ActualC ) =
+ split(/$SPLIT/, $Entry, 3) ;
+ unless ($ActualA) { $ActualA = "" }
+ unless ($ActualB) { $ActualB = "" }
+ unless ($ActualC) { $ActualC = "" }
+ if (How($ActualA) eq $PreviousA)
+ { $ActualA = "" }
+ else
+ { $PreviousA = How($ActualA) ;
+ $PreviousB = "" ;
+ $PreviousC = "" }
+ if (How($ActualB) eq $PreviousB)
+ { $ActualB = "" }
+ else
+ { $PreviousB = How($ActualB) ;
+ $PreviousC = "" }
+ if (How($ActualC) eq $PreviousC)
+ { $ActualC = "" }
+ else
+ { $PreviousC = How($ActualC) }
+ $Copied = 0 ;
+ if ($ActualA ne "")
+ { FlushSavedLine ;
+ print TUO "\\registerentrya{$Class}{$ActualA}\n" ;
+ $Copied = 1 }
+ if ($ActualB ne "")
+ { FlushSavedLine ;
+ print TUO "\\registerentryb{$Class}{$ActualB}\n" ;
+ $Copied = 1 }
+ if ($ActualC ne "")
+ { FlushSavedLine ;
+ print TUO "\\registerentryc{$Class}{$ActualC}\n" ;
+ $Copied = 1 }
+ if ($Copied)
+ { $NOfSaneEntries++ }
+ if ($RealPage eq 0)
+ { FlushSavedLine ;
+ print TUO "\\registersee{$Class}{$PageHow,$TextHow}{$SeeToo}{$Page}\n" ;
+ $LastPage = $Page ;
+ $LastRealPage = $RealPage }
+ else {
+if (($SavedHow ne $PageHow) && ($PageHow ne "")) {
+ # last valid page attribute counts
+ $SavedHow = $PageHow ;
+}
+ if (($Copied) || ! (($LastPage eq $Page) && ($LastRealPage eq $RealPage)))
+ { # print "$LastPage / $Page // $LastRealPage / $RealPage\n" ;
+ $NextEntry = "{$Class}{$PreviousA}{$PreviousB}{$PreviousC}{$PageHow,$TextHow}" ;
+ #~ $SavedLine = "{$Class}{$PageHow,$TextHow}{$Location}{$Page}{$RealPage}\n" ;
+ $SavedLine = "{$Class}{$SavedHow,$TextHow}{$Location}{$Page}{$RealPage}\n" ;
+ if ($RegisterState eq $RegStat{"f"})
+ { FlushSavedLine ;
+ print TUO "\\registerfrom$SavedLine" }
+ elsif ($RegisterState eq $RegStat{"t"})
+ { FlushSavedLine ;
+ print TUO "\\registerto$SavedLine" ; $SavedHow = '' ; }
+ else
+ { if ($CollapseEntries)
+ { if ($SavedEntry ne $NextEntry)
+ { $SavedFrom = $SavedLine }
+ else
+ { $SavedTo = $SavedLine }
+ $SavedEntry = $NextEntry }
+ else
+ { print TUO "\\registerpage$SavedLine" ; $SavedHow = '' ; }
+ }
+ ++$NOfSanePages ;
+ $LastPage = $Page ;
+ $LastRealPage = $RealPage } } }
+
+FlushSavedLine ;
+
+ Report("RegisterEntries", $NOfEntries, "->", $NOfSaneEntries, "Entries",
+ $NOfSanePages, "References") ;
+ if ($NOfBadEntries>0)
+ { Report("RegisterErrors", $NOfBadEntries) } }
+
+#D As promised, we show the results:
+#D
+#D \plaatstestentry
+
+#D For debugging purposes we flush some status information. The
+#D faster machines become, the more important this section will
+#D be. The totals, when changed, force texexec to do a second pass.
+
+sub FlushData
+ { print TUO "%\n" . "% $Program / Status\n" . "%\n" ;
+ print TUO "" .
+ "% embedded files : $NOfFiles ($NOfBadFiles errors)\n" .
+ "% synonym entries : $NOfSynonyms ($NOfBadSynonyms errors)\n" .
+ "% register entries : $NOfEntries ($NOfBadEntries errors)\n" .
+ "% metapost graphics : $TotalNOfMPgraphics\n" .
+ "% position commands : $TotalNOfPositions " ;
+ if ($TotalNOfPositions)
+ { if ($NOfPositionsFound)
+ { print TUO "(resolved)\n" }
+ else
+ { print TUO "(unresolved)\n" } }
+ else
+ { print TUO "(not used)\n" } }
+
+#D The functionallity described on the previous few pages is
+#D called upon in the main routine:
+
+sub NormalHandleReferences
+ { if ($InputFile eq "")
+ { Report("Error", "NoInputFile") }
+ else
+ { unless (open (TUI, "$InputFile.tui"))
+ { Report("Error", "EmptyInputFile", $InputFile) }
+ else
+ { Report("InputFile", "$InputFile.tui" ) ;
+ unlink "$InputFile.tmp" ;
+ rename "$InputFile.tuo", "$InputFile.tmp" ;
+ Report("OutputFile", "$InputFile.tuo" ) ;
+ open (TUO, ">$InputFile.tuo") ;
+ print TUO "%\n" . "% $Program / Commands\n" . "%\n" ;
+ while (<TUI>)
+ { $SomeLine = $_ ;
+ chomp $SomeLine ;
+ ($FirstTag, $RestOfLine) = split ' ', $SomeLine, 2 ;
+ if ($FirstTag eq "c")
+ { HandleCommand }
+ elsif ($FirstTag eq "s")
+ { HandleSynonym }
+ elsif ($FirstTag eq "r")
+ { HandleRegister }
+ elsif ($FirstTag eq "f")
+ { HandleFile }
+ elsif ($FirstTag eq "k")
+ { HandleKey }
+ elsif ($FirstTag eq "e")
+ { HandleExtra }
+ elsif ($FirstTag eq "p")
+ { HandlePlugIn }
+ elsif ($FirstTag eq "q")
+ { $ValidOutput = 0 ;
+ last } }
+ if ($ValidOutput)
+ { FlushCommands ; # already done during pass
+ FlushKeys ;
+ FlushRegisters ;
+ FlushSynonyms ;
+ FlushPlugIns ;
+ FlushFiles ;
+ FlushData ;
+ FlushExtra ;
+ close (TUO) ;
+ RunExtraPrograms }
+ else
+ { close (TUO) ;
+ unlink "$InputFile.tuo" ;
+ rename "$InputFile.tmp", "$InputFile.tuo" ;
+ Report ("Remark", "NoOutputFile") } } } }
+
+my $Suffix ;
+
+sub MergerHandleReferences
+ { unlink "texutil.tuo" ;
+ Report("OutputFile", "texutil.tuo" ) ;
+ open (TUO, ">texutil.tuo") ;
+ foreach $InputFile (@ARGV)
+ { ($InputFile, $Suffix) = split (/\./, $InputFile, 2) ;
+ unless (open (TUI, "$InputFile.tui"))
+ { Report("Error", "EmptyInputFile", $InputFile) }
+ else
+ { Report("InputFile", "$InputFile.tui" ) ;
+ while (<TUI>)
+ { $SomeLine = $_ ;
+ chomp $SomeLine ;
+ ($FirstTag, $RestOfLine) = split ' ', $SomeLine, 2 ;
+ if ($FirstTag eq "r")
+ { HandleRegister } } } }
+ if ($ValidOutput)
+ { FlushRegisters ;
+ close (TUO) }
+ else
+ { close (TUO) ;
+ unlink "texutil.tuo" ;
+ Report ("Remark", "NoOutputFile") } }
+
+# sub HandleReferences
+# { Report("Action", "ProcessingReferences") ;
+# if ($ProcessIJ )
+# { Report("Option", "SortingIJ") }
+# if ($ProcessHigh)
+# { Report("Option", "ConvertingHigh") }
+# if ($ProcessQuotes)
+# { Report("Option", "ProcessingQuotes") }
+# if ($InputFile eq "")
+# { Report("Error", "NoInputFile") }
+# else
+# { unless (open (TUI, "$InputFile.tui"))
+# { Report("Error", "EmptyInputFile", $InputFile) }
+# else
+# { Report("InputFile", "$InputFile.tui" ) ;
+# InitializeCommands ;
+# InitializeRegisters ;
+# InitializeSynonyms ;
+# InitializeFiles ;
+# $ValidOutput = 1 ;
+# unlink "$InputFile.tmp" ;
+# rename "$InputFile.tuo", "$InputFile.tmp" ;
+# Report("OutputFile", "$InputFile.tuo" ) ;
+# open (TUO, ">$InputFile.tuo") ;
+# while (<TUI>)
+# { $SomeLine = $_ ;
+# chomp $SomeLine ;
+# ($FirstTag, $RestOfLine) = split ' ', $SomeLine, 2 ;
+# if ($FirstTag eq "c")
+# { HandleCommand }
+# elsif ($FirstTag eq "s")
+# { HandleSynonym }
+# elsif ($FirstTag eq "r")
+# { HandleRegister }
+# elsif ($FirstTag eq "f")
+# { HandleFile }
+# elsif ($FirstTag eq "q")
+# { $ValidOutput = 0 ;
+# last } }
+# if ($ValidOutput)
+# { FlushCommands ; # already done during pass
+# FlushRegisters ;
+# FlushSynonyms ;
+# FlushFiles ;
+# FlushData ;
+# close (TUO) }
+# else
+# { close (TUO) ;
+# unlink "$InputFile.tuo" ;
+# rename "$InputFile.tmp", "$InputFile.tuo" ;
+# Report ("Remark", "NoOutputFile") } } } }
+
+sub HandleReferences
+ { $Merging = @ARGV ;
+ $Merging = ($Merging>1) ;
+ if ($Merging)
+ { Report("Action", "MergingReferences") }
+ else
+ { Report("Action", "ProcessingReferences") }
+ if ($ProcessIJ )
+ { Report("Option", "SortingIJ") }
+ if ($ProcessHigh)
+ { Report("Option", "ConvertingHigh") }
+ if ($ProcessQuotes)
+ { Report("Option", "ProcessingQuotes") }
+ InitializeKeys ;
+ InitializeCommands ;
+ InitializeExtra ;
+ InitializeRegisters ;
+ InitializeSynonyms ;
+ InitializeFiles ;
+ $ValidOutput = 1 ;
+ if ($Merging)
+ { MergerHandleReferences }
+ else
+ { NormalHandleReferences } }
+
+# moved to ctxtools
+#
+# sub HandleDocuments
+# { my $files = @ARGV.join(' ') ; system("ctxtools $files") }
+
+#D \extras
+#D {documents}
+#D
+#D Documentation can be woven into a source file. The next
+#D routine generates a new, \TEX\ ready file with the
+#D documentation and source fragments properly tagged. The
+#D documentation is included as comment:
+#D
+#D \starttypen
+#D %D ...... some kind of documentation
+#D %M ...... macros needed for documenation
+#D %S B begin skipping
+#D %S E end skipping
+#D \stoptypen
+#D
+#D The most important tag is \type{%D}. Both \TEX\ and
+#D \METAPOST\ files use \type{%} as a comment chacacter, while
+#D \PERL\ uses \type{#}. Therefore \type{#D} is also handled.
+#D
+#D The generated file gets the suffix \type{ted} and is
+#D structured as:
+#D
+#D \starttypen
+#D \startmodule[type=suffix]
+#D \startdocumentation
+#D \stopdocumentation
+#D \startdefinition
+#D \stopdefinition
+#D \stopmodule
+#D \stoptypen
+#D
+#D Macro definitions specific to the documentation are not
+#D surrounded by start||stop commands. The suffix specifaction
+#D can be overruled at runtime, but defaults to the file
+#D extension. This specification can be used for language
+#D depended verbatim typesetting.
+
+my $skippingbang = 0 ;
+
+sub HandleDocuments
+ { Report("Action", "GeneratingDocumentation") ;
+ if ($ProcessType ne "")
+ { Report("Option", "ForcingFileType", $ProcessType) }
+ if ($InputFile eq "")
+ { Report("Error", "NoInputFile") }
+ else
+ { CheckInputFiles ($InputFile) ;
+ foreach $FullName (@UserSuppliedFiles)
+ { ($FileName, $FileSuffix) = SplitFileName ($FullName) ;
+ unless ($FileSuffix)
+ { $FileSuffix = "tex" }
+ unless (-f "$FileName.$FileSuffix")
+ { next }
+ unless (open (TEX, "$FileName.$FileSuffix"))
+ { Report("Error", "EmptyInputFile", "$FileName.$FileSuffix" ) }
+ else
+ { Report("InputFile", "$FileName.$FileSuffix") ;
+ Report("OutputFile", "$FileName.ted") ;
+ open (TED, ">$FileName.ted") ;
+ $NOfDocuments = 0 ;
+ $NOfDefinitions = 0 ;
+ $NOfSkips = 0 ;
+ $SkipLevel = 0 ;
+ $InDocument = 0 ;
+ $InDefinition = 0 ;
+ $skippingbang = 0 ;
+ if ($ProcessType eq "")
+ { $FileType=lc $FileSuffix }
+ else
+ { $FileType=lc $ProcessType }
+ Report("FileType", $FileType) ;
+ # we need to signal to texexec what interfaec to use
+ my $firstline = <TEX> ;
+ if ($firstline =~ /^\%.*interface\=/)
+ { print TED $firstline }
+ else
+ { seek TEX, 0, 0 }
+ # so far
+ print TED "\\startmodule[type=$FileType]\n" ;
+ while (<TEX>)
+ { chomp ;
+ s/\s*$//o ;
+ if ($skippingbang)
+ { $skippingbang = 0 }
+ elsif (/^[%\#]D/)
+ { if ($SkipLevel == 0)
+ { if (length $_ < 3)
+ {$SomeLine = "" }
+ else # HH: added after that
+ {$SomeLine = substr $_, 3 }
+ if ($InDocument)
+ { print TED "$SomeLine\n" }
+ else
+ { if ($InDefinition)
+ { print TED "\\stopdefinition\n" ;
+ $InDefinition = 0 }
+ unless ($InDocument)
+ { print TED "\n\\startdocumentation\n" }
+ print TED "$SomeLine\n" ;
+ $InDocument = 1 ;
+ ++$NOfDocuments } } }
+ elsif (/^[%\#]M/)
+ { if ($SkipLevel == 0)
+ { $SomeLine = substr $_, 3 ;
+ print TED "$SomeLine\n" } }
+ elsif (/^[%\%]S B]/)
+ { ++$SkipLevel ;
+ ++$NOfSkips }
+ elsif (/^[%\%]S E]/)
+ { --$SkipLevel }
+ elsif (/^[%\#]/)
+ { }
+ elsif (/^eval \'\(exit \$\?0\)\' \&\& eval \'exec perl/o)
+ { $skippingbang = 1 }
+ elsif ($SkipLevel == 0)
+ { $InLocalDocument = $InDocument ;
+ $SomeLine = $_ ;
+ if ($InDocument)
+ { print TED "\\stopdocumentation\n" ;
+ $InDocument = 0 }
+ if (($SomeLine eq "") && ($InDefinition))
+ { print TED "\\stopdefinition\n" ;
+ $InDefinition = 0 }
+ else
+ { if ($InDefinition)
+ { print TED "$SomeLine\n" }
+ elsif ($SomeLine ne "")
+ { print TED "\n" . "\\startdefinition\n" ;
+ $InDefinition = 1 ;
+ unless ($InLocalDocument)
+ { ++$NOfDefinitions }
+ print TED "$SomeLine\n" } } } }
+ if ($InDocument)
+ { print TED "\\stopdocumentation\n" }
+ if ($InDefinition)
+ { print TED "\\stopdefinition\n" }
+ print TED "\\stopmodule\n" ;
+ close (TED) ;
+ unless (($NOfDocuments) || ($NOfDefinitions))
+ { unlink "$FileName.ted" }
+ Report ("NOfDocuments", $NOfDocuments) ;
+ Report ("NOfDefinitions", $NOfDefinitions) ;
+ Report ("NOfSkips", $NOfSkips) } } } }
+
+#D \extras
+#D {sources}
+#D
+#D Documented sources can be stripped of documentation and
+#D comments, although at the current processing speeds the
+#D overhead of skipping the documentation at run time is
+#D neglectable. Only lines beginning with a \type{%} are
+#D stripped. The stripped files gets the suffix \type{tes}.
+
+sub HandleSources
+ { Report("Action", "GeneratingSources") ;
+ if ($InputFile eq "")
+ { Report("Error", "NoInputFile") }
+ else
+ { CheckInputFiles ($InputFile) ;
+ foreach $FullName (@UserSuppliedFiles)
+ { ($FileName, $FileSuffix) = SplitFileName ($FullName) ;
+ unless ($FileSuffix)
+ { $FileSuffix = "tex" }
+ unless (-f "$FileName.$FileSuffix")
+ { next }
+ unless (open (TEX, "$FileName.$FileSuffix"))
+ { Report("Error", "EmptyInputFile", "$FileName.$FileSuffix" ) }
+ else
+ { Report("InputFile", "$FileName.$FileSuffix") ;
+ Report("OutputFile", "$FileName.tes") ;
+ open (TES, ">$FileName.tes") ;
+ $EmptyLineDone = 1 ;
+ $FirstCommentDone = 0 ;
+ while (<TEX>)
+ { $SomeLine = $_ ;
+ chomp $SomeLine ;
+ if ($SomeLine eq "")
+ { unless ($FirstCommentDone)
+ { $FirstCommentDone = 1 ;
+ print TES
+ "\n% further documentation is removed\n\n" ;
+ $EmptyLineDone = 1 }
+ unless ($EmptyLineDone)
+ { print TES "\n" ;
+ $EmptyLineDone = 1 } }
+ elsif ($SomeLine =~ /^%/)
+ { unless ($FirstCommentDone)
+ { print TES "$SomeLine\n" ;
+ $EmptyLineDone = 0 } }
+ else
+ { print TES "$SomeLine\n" ;
+ $EmptyLineDone = 0 } }
+ close (TES) ;
+ unless ($FirstCommentDone)
+ { unlink "$FileName.tes" } } } } }
+
+#D \extras
+#D {setups}
+#D
+#D All \CONTEXT\ commands are specified in a compact format
+#D that can be used to generate quick reference tables and
+#D cards. Such setups are preceded by \type{%S}. The setups
+#D are collected in the file \type{texutil.tus}.
+
+sub HandleSetups
+ { Report("Action", "FilteringDefinitions" ) ;
+ if ($InputFile eq "")
+ { Report("Error", "NoInputFile") }
+ else
+ { SetOutputFile ("texutil.tus" ) ;
+ Report("OutputFile", $OutputFile) ;
+ open (TUS, ">$OutputFile") ; # always reset!
+ $NOfSetups = 0 ;
+ CheckInputFiles ($InputFile) ;
+ foreach $FullName (@UserSuppliedFiles)
+ { ($FileName, $FileSuffix) = SplitFileName ($FullName) ;
+ unless ($FileSuffix)
+ { $FileSuffix = "tex" }
+ unless (-f "$FileName.$FileSuffix")
+ { next }
+ unless (open (TEX, "$FileName.$FileSuffix"))
+ { Report("Error", "EmptyInputFile", "$FileName.$FileSuffix" ) }
+ else
+ { Report("InputFile", "$FileName.$FileSuffix") ;
+ print TUS "%\n" . "% File : $FileName.$FileSuffix\n" . "%\n" ;
+ while (<TEX>)
+ { $SomeLine = $_ ;
+ chomp $SomeLine ;
+ ($Tag, $RestOfLine) = split(/ /, $SomeLine, 2) ;
+ if ($Tag eq "%S")
+ { ++$NOfSetups ;
+ while ($Tag eq "%S")
+ { print TUS "$RestOfLine\n" ;
+ $SomeLine = <TEX> ;
+ chomp $SomeLine ;
+ ($Tag, $RestOfLine) = split(/ /, $SomeLine, 2) }
+ print TUS "\n" } } } }
+ close (TUS) ;
+ unless ($NOfSetups)
+ { unlink $OutputFile }
+ Report("NOfSetups", $NOfSetups) } }
+
+#D \extras
+#D {templates, infos}
+#D
+#D From the beginning, the \CONTEXT\ source files contained
+#D helpinfo and key||templates for \TEXEDIT. In fact, for a
+#D long time, this was the only documentation present. More
+#D and more typeset (interactive) documentation is replacing
+#D this helpinfo, but we still support the traditional method.
+#D This information is formatted like:
+#D
+#D \starttypen
+#D %I n=Struts
+#D %I c=\strut,\setnostrut,\setstrut,\toonstruts
+#D %I
+#D %I text
+#D %I ....
+#D %P
+#D %I text
+#D %I ....
+#D \stoptypen
+#D
+#D Templates look like:
+#D
+#D \starttypen
+#D %T n=kap
+#D %T m=kap
+#D %T a=k
+#D %T
+#D %T \kap{?}
+#D \stoptypen
+#D
+#D The key||value pairs stand for {\em name}, {\em mnemonic},
+#D {\em key}. This information is copied to files with the
+#D extension \type{tud}.
+
+sub HandleEditorCues
+ { if ($ProcessTemplates)
+ { Report("Action", "CopyingTemplates" ) }
+ if ($ProcessInfos)
+ {Report("Action", "CopyingInformation" ) }
+ if ($InputFile eq "")
+ { Report("Error", "NoInputFile") }
+ else
+ { CheckInputFiles ($InputFile) ;
+ foreach $FullName (@UserSuppliedFiles)
+ { ($FileName, $FileSuffix) = SplitFileName ($FullName) ;
+ if ($FileSuffix eq "")
+ { $FileSuffix = "tex" }
+ unless (-f "$FileName.$FileSuffix")
+ { next }
+ unless (open (TEX, "$FileName.$FileSuffix"))
+ { Report("Error", "EmptyInputFile", "$FileName.$FileSuffix" ) }
+ else
+ { Report("InputFile", "$FileName.$FileSuffix") ;
+ Report("OutputFile", "$FileName.tud") ;
+ open (TUD, ">$FileName.tud") ;
+ $NOfTemplates = 0 ;
+ $NOfInfos = 0 ;
+ while (<TEX>)
+ { $SomeLine = $_ ;
+ chomp $SomeLine ;
+ ($Tag, $RestOfLine) = split(/ /, $SomeLine, 2) ;
+ if (($Tag eq "%T") && ($ProcessTemplates))
+ { ++$NOfTemplates ;
+ while ($Tag eq "%T")
+ { print TUD "$SomeLine\n" ;
+ $SomeLine = <TEX> ;
+ chomp $SomeLine ;
+ ($Tag, $RestOfLine) = split(/ /, $SomeLine, 2) }
+ print TUD "\n" }
+ elsif (($Tag eq "%I") && ($ProcessInfos))
+ { ++$NOfInfos ;
+ while (($Tag eq "%I") || ($Tag eq "%P"))
+ { print TUD "$SomeLine\n" ;
+ $SomeLine = <TEX> ;
+ chomp $SomeLine ;
+ ($Tag, $RestOfLine) = split(/ /, $SomeLine, 2) }
+ print TUD "\n" } }
+ close (TUD) ;
+ unless (($NOfTemplates) || ($NOfInfos))
+ { unlink "$FileName.tud" }
+ if ($ProcessTemplates)
+ { Report("NOfTemplates", $NOfTemplates) }
+ if ($ProcessInfos)
+ { Report("NOfInfos", $NOfInfos) } } } } }
+
+#D \extras
+#D {figures}
+#D
+#D Directories can be scanned for illustrations in \EPS, \PDF,
+#D \TIFF, \PNG\ or \JPG\ format. The resulting file \type{texutil.tuf}
+#D contains entries like:
+#D
+#D \starttypen
+#D \thisisfigureversion{year.month.day}
+#D \presetfigure[file][...specifications...]
+#D \stoptypen
+#D
+#D where the specifications are:
+#D
+#D \starttypen
+#D [e=suffix,x=xoffset,y=yoffset,w=width,h=height,t=title,c=creator,s=size]
+#D \stoptypen
+#D
+#D This data can be used when determining dimensions and
+#D generate directories of illustrations.
+
+$DPtoCM = 2.54/72.0 ;
+$INtoCM = 2.54 ;
+
+sub SaveFigurePresets
+ { my ($FNam, $FTyp, $FUni, $FXof, $FYof, $FWid, $FHei, $FTit, $FCre, $FSiz) = @_ ;
+ if ($ProcessVerbose)
+ { OpenTerminal ;
+ if ($FUni)
+ { print "n=$FNam t=$FTyp " .
+ (sprintf "x=%1.3fcm y=%1.3fcm ", $FXof, $FYof) .
+ (sprintf "w=%5.3fcm h=%5.3fcm\n", $FWid, $FHei) }
+ else
+ { print "n=$FNam t=$FTyp " .
+ "x=${FXof}bp y=${FYof}bp " .
+ "w=${FWid}bp h=${FHei}bp\n" }
+ CloseTerminal }
+ else
+ { ++$NOfFigures ;
+ $Figures[$NOfFigures] = "\\presetfigure[$FNam][e=$FTyp" ;
+ if ($FUni)
+ { $Figures[$NOfFigures] .= (sprintf ",w=%5.3fcm,h=%5.3fcm", $FWid, $FHei) }
+ else
+ { $Figures[$NOfFigures] .= ",w=${FWid}bp,h=${FHei}bp" }
+ if (($FXof!=0)||($FYof!=0))
+ { if ($FUni)
+ { $Figures[$NOfFigures] .= (sprintf ",x=%1.3fcm,y=%1.3fcm", $FXof, $FYof) }
+ else
+ { $Figures[$NOfFigures] .= ",x=${FXof}bp,y=${FYof}bp" } }
+ if ($FTit)
+ { $Figures[$NOfFigures] .= ",t=\{$FTit\}" }
+ if ($FCre)
+ { $Figures[$NOfFigures] .= ",c=\{$FCre\}" }
+ $Figures[$NOfFigures] .= ",s=$FSiz]\n" } }
+
+#D The \EPS\ to \PDF\ conversion pipe to \GHOSTSCRIPT\ is
+#D inspired by a script posted by Sebastian Ratz at the
+#D \PDFTEX\ mailing list. Watch the bounding box check, we
+#D use the values found in an earlier pass.
+
+sub ConvertEpsToEps
+ { my ( $SuppliedFileName , $LLX, $LLY, $URX, $URY ) = @_ ;
+ ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ;
+ if ($ProcessEpsToPdf)
+ { if ($dosish) { $gs = "gswin32c" } else { $gs = "gs" }
+ unlink "$FileName.pdf" ;
+ $GSCommandLine = "-q " .
+ "-sDEVICE=pdfwrite " .
+ "-dNOCACHE " .
+ "-dUseFlateCompression=true " .
+ "-dMaxSubsetPct=100 " .
+ "-sOutputFile=$FileName.pdf " .
+ "- -c " .
+ "quit " ;
+ open ( EPS, "| $gs $GSCommandLine") }
+ elsif ($PDFReady)
+ { return }
+ else
+ { open ( EPS, ">texutil.tmp" ) ;
+ binmode EPS }
+ open ( TMP , "$SuppliedFileName" ) ;
+ binmode TMP ;
+ $EpsBBOX = 0 ;
+ $EpsWidth = $URX - $LLX ;
+ $EpsHeight = $URY - $LLY ;
+ $EpsXOffset = 0 - $LLX ;
+ $EpsYOffset = 0 - $LLY ;
+ while (<TMP>)
+ { if (/%!PS/)
+ { s/(.*)%!PS/%!PS/o ;
+ print EPS $_ ;
+ last } }
+ while (<TMP>)
+ { if ((!$PDFReady)&&(/^%%(HiResB|ExactB|B)oundingBox:/o))
+ { unless ($EpsBBOX)
+ { print EPS "%%PDFready: $Program\n" ;
+ print EPS "%%BoundingBox: 0 0 $EpsWidth $EpsHeight\n" ;
+ print EPS "<< /PageSize [$EpsWidth $EpsHeight] >> setpagedevice\n" ;
+ print EPS "gsave $EpsXOffset $EpsYOffset translate\n" ;
+ $EpsBBOX = 1 } }
+ elsif (/^%%EOF/o) # when final: (/^%%(EOF|Trailer)/o)
+ { last }
+ elsif (/^%%Trailer/o)
+ { last }
+ else
+ { print EPS $_ } }
+ close ( TMP ) ;
+ if (($EpsBBOX)&&(!$PDFReady))
+ { print EPS "grestore\n%%EOF\n%%RestOfFileIgnored: $Program\n" ;
+ close ( EPS ) ;
+ Report ( "PdfFile", "$SuppliedFileName" ) ;
+ unless ($ProcessEpsToPdf)
+ { unlink "$SuppliedFileName" ;
+ rename "texutil.tmp", "$SuppliedFileName" } }
+ else
+ { close (EPS) }
+ unlink "texutil.tmp" }
+
+sub HandleEpsFigure
+ { my ($SuppliedFileName) = @_ ;
+ my ($Temp) = "" ;
+ if (-f $SuppliedFileName)
+ { ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ;
+ if ($FileSuffix ne "")
+ {#$Temp = $FileSuffix ;
+ #$Temp =~ s/[0-9]//go ;
+ #if ($Temp eq "")
+ if ($FileSuffix =~ /^[0-9]+$/o)
+ { $EpsFileName = $SuppliedFileName;
+ Report ( "MPFile", "$SuppliedFileName" ) }
+ elsif ((lc $FileSuffix ne "eps")&&(lc $FileSuffix ne "mps"))
+ { return }
+ else
+ { $EpsFileName = $SuppliedFileName; # $FileName
+ Report ( "EpsFile", "$SuppliedFileName" ) }
+ $EpsTitle = "" ;
+ $EpsCreator = "" ;
+ open ( EPS , $SuppliedFileName ) ;
+ binmode EPS ;
+ $EpsSize = -s EPS ;
+ $PDFReady = 0 ;
+ $MPSFound = 0 ;
+ $BBoxFound = 0 ;
+ while (<EPS>)
+ { $SomeLine = $_;
+ chomp $SomeLine ;
+ if (($BBoxFound) && ((substr $SomeLine,0,1) ne "%"))
+ { last }
+ if ($BBoxFound<2)
+ { if ($SomeLine =~ /^%%BoundingBox:(?!\s+\(atend\))/io) # atend (th)
+ { $EpsBBox = $SomeLine ; $BBoxFound = 1 ; next }
+ elsif ($SomeLine =~ /^%%HiResBoundingBox:/io)
+ { $EpsBBox = $SomeLine ; $BBoxFound = 2 ; next }
+ elsif ($SomeLine =~ /^%%ExactBoundingBox:/io)
+ { $EpsBBox = $SomeLine ; $BBoxFound = 3 ; next } }
+ if ($SomeLine =~ /^%%PDFready:/io)
+ { $PDFReady = 1 }
+ elsif ($SomeLine =~ /^%%Creator:/io)
+ { ($Tag, $EpsCreator) = split (/ /, $SomeLine, 2) ;
+ if ($EpsCreator =~ /MetaPost/io)
+ { $MPSFound = 1 } }
+ elsif ($SomeLine =~ /^%%Title:/io)
+ { ($Tag, $EpsTitle) = split (/ /, $SomeLine, 2) } }
+ close ( EPS ) ;
+ if ($BBoxFound)
+ { ($Tag, $LLX, $LLY, $URX, $URY, $RestOfLine) = split (/ /, $EpsBBox, 6 ) ;
+ $EpsHeight = ($URY-$LLY)*$DPtoCM ;
+ $EpsWidth = ($URX-$LLX)*$DPtoCM ;
+ $EpsXOffset = $LLX*$DPtoCM ;
+ $EpsYOffset = $LLY*$DPtoCM ;
+ if ($MPSFound)
+ { $EpsType = "mps" }
+ else
+ { $EpsType = "eps" }
+ SaveFigurePresets
+ ( $EpsFileName, $EpsType, 1,
+ $EpsXOffset, $EpsYOffset, $EpsWidth, $EpsHeight,
+ $EpsTitle, $EpsCreator, $EpsSize ) ;
+ if (($ProcessEpsPage) || ($ProcessEpsToPdf))
+ { ConvertEpsToEps ( $SuppliedFileName, $LLX, $LLY, $URX, $URY ) } }
+ else
+ { Report ( "MissingBoundingBox", "$SuppliedFileName" ) } } } }
+
+#D The \PDF\ scanning does a similar job. This time we
+#D search for a mediabox. I could have shared some lines
+#D with the previous routines, but prefer readability.
+
+sub HandlePdfFigure
+ { my ( $SuppliedFileName ) = @_ ;
+ ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ;
+ if (lc $FileSuffix ne "pdf")
+ { return }
+ else
+ { $PdfFileName = $SuppliedFileName ;
+ Report ( "PdfFile", "$SuppliedFileName" ) }
+ open ( PDF , $SuppliedFileName ) ;
+ binmode PDF ;
+ $PdfSize = -s PDF ;
+ $MediaBoxFound = 0 ;
+ $MediaBox = 0 ;
+ $PageFound = 0 ;
+ $PagesFound = 0 ;
+ while (<PDF>)
+ { $SomeLine = $_ ;
+ chomp ($SomeLine) ;
+ if ($SomeLine =~ /\/Type\s*\/Pages/io)
+ { $PagesFound = 1 }
+ elsif ($SomeLine =~ /\/Type\s*\/Page/io)
+ { ++$PageFound ;
+ if ($PageFound>1) { last } }
+ if (($PageFound)||($PagesFound))
+ { if (($MediaBoxFound < 2) && ($SomeLine =~ /\/ArtBox\s*\[/io))
+ { $MediaBoxFound = 3 ;
+ $MediaBox = $SomeLine }
+ elsif (($MediaBoxFound < 2) && ($SomeLine =~ /\/CropBox\s*\[/io))
+ { $MediaBoxFound = 2 ;
+ $MediaBox = $SomeLine }
+ elsif (($MediaBoxFound == 0) && ($SomeLine =~ /\/MediaBox\s*\[/io))
+ { $MediaBoxFound = 1 ;
+ $MediaBox = $SomeLine } } }
+ close ( PDF ) ;
+ if ($PageFound>1)
+ { Report ( "MultiPagePdfFile", "$SuppliedFileName" ) }
+ if (($MediaBoxFound) && ($MediaBox))
+ { my $D = "[0-9\-\.]" ;
+ $MediaBox =~ /\/(Media|Crop|Art)Box\s*\[\s*($D+)\s*($D+)\s*($D+)\s*($D+)/o ;
+ $LLX = $2 ; $LLY = $3 ; $URX = $4 ; $URY = $5 ;
+ $PdfHeight = ($URY-$LLY)*$DPtoCM ;
+ $PdfWidth = ($URX-$LLX)*$DPtoCM ;
+ $PdfXOffset = $LLX*$DPtoCM ;
+ $PdfYOffset = $LLY*$DPtoCM ;
+ SaveFigurePresets
+ ( $PdfFileName, "pdf", 1,
+ $PdfXOffset, $PdfYOffset, $PdfWidth, $PdfHeight,
+ "", "", $PdfSize ) }
+ else
+ { Report ( "MissingMediaBox", "$SuppliedFileName" ) } }
+
+#D A previous version of \TEXUTIL\ used \type{tifftags} or
+#D \type{tiffinfo} for collecting the dimensions. However,
+#D the current implementation does this job itself.
+
+sub TifGetByte
+ { my $B = 0 ;
+ read TIF, $B, 1 ;
+ return ord($B) }
+
+sub TifGetShort
+ { my $S = 0 ;
+ read TIF, $S, 2 ;
+ if ($TifLittleEndian)
+ { return (unpack ("v", $S)) }
+ else
+ { return (unpack ("n", $S)) } }
+
+sub TifGetLong
+ { my $L = 0 ;
+ read TIF, $L, 4 ;
+ if ($TifLittleEndian)
+ { return (unpack ("V", $L)) }
+ else
+ { return (unpack ("N", $L)) } }
+
+sub TifGetRational
+ { my ($N, $M) = (0,0) ;
+ $N = TifGetLong ;
+ $M = TifGetLong ;
+ return $N/$M }
+
+sub TifGetAscii
+ { my $S = "" ;
+ --$TifValues;
+ unless ($TifValues)
+ { return "" }
+ else
+ { read TIF, $S, $TifValues ;
+ return $S } }
+
+sub TifGetWhatever
+ { if ($_[0]==1)
+ { return TifGetByte }
+ elsif ($_[0]==2)
+ { return TifGetAscii }
+ elsif ($_[0]==3)
+ { return TifGetShort }
+ elsif ($_[0]==4)
+ { return TifGetLong }
+ elsif ($_[0]==5)
+ { return TifGetRational }
+ else
+ { return 0 } }
+
+sub TifGetChunk
+ { seek TIF, $TifNextChunk, 0 ;
+ $Length = TifGetShort ;
+ $TifNextChunk += 2 ;
+ for ($i=1; $i<=$Length; $i++)
+ { seek TIF, $TifNextChunk, 0 ;
+ $TifTag = TifGetShort ;
+ $TifType = TifGetShort ;
+ $TifValues = TifGetLong ;
+ if ($TifTag==256)
+ { $TifWidth = TifGetWhatever($TifType) }
+ elsif ($TifTag==257)
+ { $TifHeight = TifGetWhatever($TifType) }
+ elsif ($TifTag==296)
+ { $TifUnit = TifGetWhatever($TifType) }
+ elsif ($TifTag==282)
+ { seek TIF, TifGetLong, 0 ;
+ $TifHRes = TifGetWhatever($TifType) }
+ elsif ($TifTag==283)
+ { seek TIF, TifGetLong, 0 ;
+ $TifVRes = TifGetWhatever($TifType) }
+ elsif ($TifTag==350)
+ { seek TIF, TifGetLong, 0 ;
+ $TifCreator = TifGetWhatever($TifType) }
+ elsif ($TifTag==315)
+ { seek TIF, TifGetLong, 0 ;
+ $TifAuthor = TifGetWhatever($TifType) }
+ elsif ($TifTag==269)
+ { seek TIF, TifGetLong, 0 ;
+ $TifTitle = TifGetWhatever($TifType) }
+ $TifNextChunk += 12 }
+ seek TIF, $TifNextChunk, 0 ;
+ $TifNextChunk = TifGetLong ;
+ return ($TifNextChunk>0) }
+
+sub HandleTifFigure
+ { my ( $SuppliedFileName ) = @_ ;
+ ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ;
+ if (lc $FileSuffix ne "tif")
+ { return }
+ else
+ { $TifFile = $SuppliedFileName ;
+ if (open ( TIF, $TifFile )) { # { must be here, perl 5.003 bug
+ Report ( "TifFile", "$SuppliedFileName" ) ;
+ binmode TIF;
+ $TifWidth = 0 ;
+ $TifHeight = 0 ;
+ $TifTitle = "" ;
+ $TifAuthor = "" ;
+ $TifCreator = "" ;
+ $TifUnit = 0 ;
+ $TifHRes = 1 ;
+ $TifVRes = 1 ;
+ $TifSize = -s TIF ;
+ $TifByteOrder = "" ;
+ seek TIF, 0, 0 ;
+ read TIF, $TifByteOrder, 2 ;
+ $TifLittleEndian = ($TifByteOrder eq "II") ;
+ $TifTag = TifGetShort;
+ unless ($TifTag == 42)
+ { close ( TIF ) ;
+ return }
+ $TifNextChunk = TifGetLong ;
+ while (TifGetChunk) { }
+ if ($TifUnit==2)
+ { $TifMult = $INtoCM }
+ elsif ($TifUnit==3)
+ { $TifMult = 1 }
+ else
+ { $TifMult = 72 }
+ $TifWidth = ($TifWidth /$TifHRes)*$TifMult ;
+ $TifHeight = ($TifHeight/$TifVRes)*$TifMult ;
+ close ( TIF ) ;
+ SaveFigurePresets
+ ( $TifFile, "tif", $TifUnit,
+ 0, 0, $TifWidth, $TifHeight,
+ $TifTitle, $TifCreator, $TifSize ) } } }
+
+#D I first intended to use the public utility \type{pngmeta}
+#D (many thanks to Taco for compiling it), but using this
+#D utility to analyze lots of \PNG\ files, I tried to do a
+#D similar job in \PERL. Here are the results:
+
+my ($PngSize, $PngWidth, $PngHeight) = (0,0,0) ;
+my ($PngMult, $PngHRes, $PngVRes, $PngUnit) = (0,1,1,0) ;
+my ($PngFile, $PngTitle, $PngAuthor, $PngCreator) = ("","","") ;
+my ($PngNextChunk, $PngLength, $PngType) = (0,0,0) ;
+my ($PngKeyword, $PngDummy) = ("","") ;
+
+my $PngSignature = chr(137) . chr(80) . chr(78) . chr(71) .
+ chr (13) . chr(10) . chr(26) . chr(10) ;
+sub PngGetByte
+ { my ($B) = 0 ;
+ read PNG, $B, 1 ;
+ return (ord($B)) }
+
+sub PngGetLong
+ { my ($L) = 0 ;
+ read PNG, $L, 4 ;
+ return (unpack("N", $L)) }
+
+sub PngGetChunk
+ { if ($PngNextChunk<$PngSize)
+ { seek PNG, $PngNextChunk, 0 ;
+ $PngLength = PngGetLong ;
+ $PngNextChunk = $PngNextChunk + $PngLength + 12 ;
+ read PNG, $PngType, 4 ;
+ if ($PngType eq "")
+ { return 0 }
+ elsif ($PngType eq "IEND")
+ { return 0 }
+ elsif ($PngType eq "IHDR")
+ { $PngWidth = PngGetLong ;
+ $PngHeight = PngGetLong }
+ elsif ($PngType eq "pHYs")
+ { $PngHRes = PngGetLong ;
+ $PngVRes = PngGetLong ;
+ read PNG, $PngUnit, 1 }
+ elsif ($PngType eq "tEXt")
+ { read PNG, $PngKeyword, $PngLength ;
+ ($PngKeyword,$PngDummy) = split(/\x00/,$PngKeyword) ;
+ if ( $PngKeyword eq "Title")
+ { $PngTitle = $PngDummy }
+ elsif ( $PngKeyword eq "Author")
+ { $PngAuthor = $PngDummy }
+ elsif ( $PngKeyword eq "Software")
+ { $PngCreator = $PngDummy } }
+ return 1 }
+ else
+ { return 0 } }
+
+sub HandlePngFigure
+ { my ( $SuppliedFileName ) = @_ ;
+ ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ;
+ if (lc $FileSuffix ne "png")
+ { return }
+ else
+ { $PngFile = $SuppliedFileName ;
+ if (open ( PNG, $PngFile ))
+ { Report ( "PngFile", "$SuppliedFileName" ) }
+ $PngSize = 0 ;
+ $PngWidth = 0 ;
+ $PngHeight = 0 ;
+ $PngTitle = "" ;
+ $PngAuthor = "" ;
+ $PngCreator = "" ;
+ $PngUnit = 0 ;
+ $PngVRes = 1 ;
+ $PngHRes = 1 ;
+ $PngSig = "" ;
+ $PngSize = -s PNG ;
+ binmode PNG ;
+ seek PNG, 0, 0 ;
+ read PNG, $PngSig, 8;
+ unless ($PngSig eq $PngSignature)
+ { close ( PNG ) ;
+ return }
+ $PngNextChunk = 8 ;
+ while (PngGetChunk) { }
+ $PngWidth = ($PngWidth /$PngVRes) ;
+ $PngHeight = ($PngHeight/$PngHRes) ;
+ close ( PNG ) ;
+ SaveFigurePresets
+ ( $PngFile, "png", $PngUnit,
+ 0, 0, $PngWidth, $PngHeight,
+ $PngTitle, $PngCreator, $PngSize ) } }
+
+#D Well, we also offer \JPG\ scanning (actually \JFIF)
+#D scanning. (I can recomend David Salomon's book on Data
+#D Compression to those interested in the internals of
+#D \JPG.)
+#D
+#D It took me some time to discover that the (sort of)
+#D reference document I used had a faulty byte position table.
+#D Nevertheless, when I was finaly able to grab the header,
+#D Piet van Oostrum pointer me to the \PERL\ script of Alex
+#D Knowles (and numerous other contributers), from which I
+#D could deduce what segment contained the dimensions.
+
+my ($JpgSize, $JpgWidth, $JpgHeight) = (0,0,0) ;
+my ($JpgMult, $JpgUnit, $JpgHRes, $JpgVRes) = (1,0,1,1) ;
+my ($JpgFile, $JpgVersion, $JpgDummy) = ("",0,"") ;
+my ($JpgSig, $JpgPos, $JpgLen, $JpgSoi, $JpgApp) = ("",0,0,0,0) ;
+
+my $JpgSignature = "JFIF" . chr(0) ;
+
+sub JpgGetByte
+ { my ($B) = 0 ;
+ read JPG, $B, 1 ;
+ return ( ord($B) ) }
+
+sub JpgGetInteger
+ { my ($I) = 0 ;
+ read JPG, $I, 2 ;
+ return (unpack("n", $I)) }
+
+sub HandleJpgFigure
+ { my ($SuppliedFileName) = @_ ;
+ ($FileName, $FileSuffix) = SplitFileName ($SuppliedFileName) ;
+ if (lc $FileSuffix ne "jpg")
+ { return }
+ else
+ { $JpgFile = $SuppliedFileName ;
+ Report ( "JpgFile", "$SuppliedFileName" ) }
+ open ( JPG, $JpgFile ) ;
+ binmode JPG ;
+ $JpgSignature = "JFIF" . chr(0) ;
+ $JpgSize = -s JPG ;
+ $JpgWidth = 0 ;
+ $JpgHeight = 0 ;
+ $JpgUnit = 0 ;
+ $JpgVRes = 1 ;
+ $JpgHRes = 1 ;
+ seek JPG, 0, 0 ;
+ read JPG, $JpgSig, 4 ;
+ unless ($JpgSig eq chr(255).chr(216).chr(255).chr(224))
+ { close ( JPG ) ;
+ return }
+ $JpgLen = JpgGetInteger;
+ read JPG, $JpgSig, 5 ;
+ unless ($JpgSig eq $JpgSignature)
+ { close ( JPG ) ;
+ return }
+ $JpgUnit = JpgGetByte ;
+ $JpgVersion = JpgGetInteger ;
+ $JpgHRes = JpgGetInteger ;
+ $JpgVRes = JpgGetInteger ;
+ $JpgPos = $JpgLen + 4 ;
+ $JpgSoi = 255 ;
+ while ()
+ { seek JPG, $JpgPos, 0 ;
+ $JpgSoi = JpgGetByte ;
+ $JpgApp = JpgGetByte ;
+ $JpgLen = JpgGetInteger ;
+ if ($JpgSoi!=255)
+ { last }
+ if (($JpgApp>=192) && ($JpgApp<=195)) # Found in the perl script.
+ { $JpgDummy = JpgGetByte ; # Found in the perl script.
+ $JpgHeight = JpgGetInteger ; # Found in the perl script.
+ $JpgWidth = JpgGetInteger } # Found in the perl script.
+ $JpgPos = $JpgPos + $JpgLen + 2 }
+ close ( JPG ) ;
+ if ($JpgUnit==1)
+ { $JpgMult = $INtoCM }
+ else
+ { $JpgMult = 1 }
+ $JpgHRes = 72 unless $JpgHRes>1 ;
+ $JpgVRes = 72 unless $JpgVRes>1 ;
+ $JpgWidth = ($JpgWidth/$JpgHRes)*$JpgMult ;
+ $JpgHeight = ($JpgHeight/$JpgVRes)*$JpgMult ;
+ close ( JPG ) ;
+ SaveFigurePresets
+ ( $JpgFile, "jpg", $JpgUnit,
+ 0, 0, $JpgWidth, $JpgHeight,
+ "", "", $JpgSize ) }
+
+#D Now we can handle figures!
+
+sub InitializeFigures
+ { $NOfFigures = 0 }
+
+sub FlushFigures
+ { SetOutputFile ("texutil.tuf") ;
+ open ( TUF, ">$OutputFile" ) ;
+ print TUF "%\n" . "% $Program / Figures\n" . "%\n" ;
+ print TUF "\\thisisfigureversion\{1996.06.01\}\n" . "%\n" ;
+ for ($n=1 ; $n<=$NOfFigures ; ++$n)
+ { print TUF $Figures[$n] }
+ close (TUF) ;
+ if ($NOfFigures)
+ { Report("OutputFile", $OutputFile ) }
+ else
+ { unlink $OutputFile }
+ Report ( "NOfFigures", $NOfFigures ) }
+
+sub DoHandleFigures
+ { my ($FigureSuffix, $FigureMethod) = @_ ;
+ if ($InputFile eq "")
+ { $InputFile = $FigureSuffix }
+ CheckInputFiles ($InputFile) ;
+ foreach $FileName (@UserSuppliedFiles)
+ { &{$FigureMethod} ( $FileName ) } }
+
+sub HandleFigures
+ { Report("Action", "GeneratingFigures" ) ;
+ foreach $FileType (@ARGV)
+ { if ($FileType=~/\.eps/io)
+ { Report("Option", "UsingEps") ;
+ if ($ProcessEpsToPdf) { Report("Option", "EpsToPdf") }
+ if ($ProcessEpsPage) { Report("Option", "EpsPage") }
+ last } }
+ foreach $FileType (@ARGV)
+ { if ($FileType=~/\.pdf/io)
+ { Report("Option", "UsingPdf") ;
+ last } }
+ foreach $FileType (@ARGV)
+ { if ($FileType=~/\.tif/io)
+ { Report("Option", "UsingTif") ;
+ #RunTifPrograms ;
+ last } }
+ foreach $FileType (@ARGV)
+ { if ($FileType=~/\.png/io)
+ { Report("Option", "UsingPng") ;
+ last } }
+ foreach $FileType (@ARGV)
+ { if ($FileType=~/\.jpg/io)
+ { Report("Option", "UsingJpg") ;
+ last } }
+ InitializeFigures ;
+ DoHandleFigures ("eps", "HandleEpsFigure") ;
+ DoHandleFigures ("pdf", "HandlePdfFigure") ;
+ DoHandleFigures ("tif", "HandleTifFigure") ;
+ DoHandleFigures ("png", "HandlePngFigure") ;
+ DoHandleFigures ("jpg", "HandleJpgFigure") ;
+ FlushFigures }
+
+#D \extras
+#D {logfiles}
+#D
+#D This (poor man's) log file scanning routine filters
+#D overfull box messages from a log file (\type{\hbox},
+#D \type{\vbox} or both). The collected problems are saved
+#D in \type{$ProgramLog}. One can specify a selection
+#D criterium.
+#D
+#D \CONTEXT\ reports unknown entities. These can also be
+#D filtered. When using fast computers, or when processing
+#D files in batch, one has to rely on the log files and/or
+#D this filter.
+
+$Unknown = "onbekende verwijzing|" .
+ "unbekannte Referenz|" .
+ "unknown reference|" .
+ "dubbele verwijzing|" .
+ "duplicate reference|" .
+ "doppelte Referenz" ;
+
+sub FlushLogTopic
+ { unless ($TopicFound)
+ { $TopicFound = 1 ;
+ print ALL "\n% File: $FileName.log\n\n" } }
+
+sub HandleLogFile
+ { if ($ProcessBox)
+ { Report("Option", "FilteringBoxes", "(\\vbox & \\hbox)") ;
+ $Key = "[h|v]box" }
+ elsif ($ProcessHBox)
+ { Report("Option", "FilteringBoxes", "(\\hbox)") ;
+ $Key = "hbox" ;
+ $ProcessBox = 1 }
+ elsif ($ProcessVBox)
+ { Report("Option", "FilteringBoxes", "(\\vbox)") ;
+ $Key = "vbox" ;
+ $ProcessBox = 1 }
+ if (($ProcessBox) && ($ProcessCriterium))
+ { Report("Option", "ApplyingCriterium") }
+ if ($ProcessUnknown)
+ { Report("Option", "FilteringUnknown") }
+ unless (($ProcessBox) || ($ProcessUnknown))
+ { ShowHelpInfo ;
+ return }
+ Report("Action", "FilteringLogFile" ) ;
+ if ($InputFile eq "")
+ { Report("Error", "NoInputFile") }
+ else
+ { $NOfBoxes = 0 ;
+ $NOfMatching = 0 ;
+ $NOfUnknown = 0 ;
+ SetOutputFile ($ProgramLog) ;
+ Report("OutputFile", $OutputFile) ;
+ CheckInputFiles ($InputFile) ;
+ open ( ALL, ">$OutputFile" ) ;
+ foreach $FullName (@UserSuppliedFiles)
+ { ($FileName, $FileSuffix) = SplitFileName ($FullName) ;
+ if (! open (LOG, "$FileName.log"))
+ { Report("Error", "EmptyInputFile", "$FileName.$FileSuffix" ) }
+ elsif (-e "$FileName.tex")
+ { $TopicFound = 0 ;
+ Report("InputFile", "$FileName.log") ;
+ while (<LOG>)
+ { $SomeLine = $_ ;
+ chomp $SomeLine ;
+ if (($ProcessBox) && ($SomeLine =~ /Overfull \\$Key/))
+ { ++$NOfBoxes ;
+ $SomePoints = $SomeLine ;
+ $SomePoints =~ s/.*\((.*)pt.*/$1/ ;
+ if ($SomePoints>=$ProcessCriterium)
+ { ++$NOfMatching ;
+ FlushLogTopic ;
+ print ALL "$SomeLine\n" ;
+ $SomeLine=<LOG> ;
+ print ALL $SomeLine } }
+ if (($ProcessUnknown) && ($SomeLine =~ /$Unknown/io))
+ { ++$NOfUnknown ;
+ FlushLogTopic ;
+ print ALL "$SomeLine\n" } } } }
+ close (ALL) ;
+ unless (($NOfBoxes) ||($NOfUnknown))
+ { unlink $OutputFile }
+ if ($ProcessBox)
+ { Report ( "NOfBoxes" , "$NOfBoxes", "->", $NOfMatching, "Overfull") }
+ if ($ProcessUnknown)
+ { Report ( "NOfUnknown", "$NOfUnknown") } } }
+
+#D Undocumented feature.
+#
+# obsolete, i.e now in ctxtools, so this will become:
+#
+# sub PurgeFiles {
+# if ($PurgeAllFiles) {
+# system("ctxtools --purge $ARGV[0]") ;
+# } else {
+# system("ctxtools --purge --all $ARGV[0]") ;
+# }
+
+my $removedfiles = 0 ;
+my $keptfiles = 0 ;
+my $persistentfiles = 0 ;
+my $reclaimedbytes = 0 ;
+
+sub RemoveContextFile
+ { my $filename = shift ;
+ my $filesize = -s $filename ;
+ unlink $filename ;
+ if (-e $filename)
+ { ++$persistentfiles ;
+ print " persistent : $filename\n" }
+ else
+ { ++$removedfiles ; $reclaimedbytes += $filesize ;
+ print " removed : $filename\n" } }
+
+sub KeepContextFile
+ { my $filename = shift ;
+ ++$keptfiles ;
+ print " kept : $filename\n" }
+
+my @dontaskprefixes = sort glob "mpx-*" ; push @dontaskprefixes ,
+ ("tex-form.tex","tex-edit.tex","tex-temp.tex",
+ "texexec.tex","texexec.tui","texexec.tuo",
+ "texexec.ps","texexec.pdf","texexec.dvi",
+ "cont-opt.tex","cont-opt.bak") ;
+my @dontasksuffixes =
+ ("mpgraph.mp","mpgraph.mpd","mpgraph.mpo","mpgraph.mpy",
+ "mprun.mp", "mprun.mpd", "mprun.mpo", "mprun.mpy",
+ "xlscript.xsl") ;
+my @forsuresuffixes =
+ ("tui","tup","ted","tes","top",
+ "log","tmp","run","bck","rlg",
+ "mpt","mpx","mpd","mpo") ;
+my @texonlysuffixes =
+ ("dvi","ps","pdf") ;
+my @texnonesuffixes =
+ ("tuo","tub","top") ;
+
+if ($PurgeAllFiles)
+ { push @forsuresuffixes, @texnonesuffixes ; @texnonesuffixes = [] }
+
+sub PurgeFiles # no my in foreach
+ { my $pattern = $ARGV[0] ; my $strippedname, $basename ;
+ my @files = () ;
+ if ($pattern eq '')
+ { $pattern = "*.*" ;
+ @files = glob $pattern }
+ else
+ { $pattern = $ARGV[0] . "-*.*" ;
+ @files = glob $pattern ;
+ $pattern = $ARGV[0] . ".*" ;
+ push(@files,glob $pattern) }
+ @files = sort @files ;
+ print " purging files : $pattern\n\n" ;
+ foreach $file (@dontaskprefixes)
+ { if (-e $file)
+ { RemoveContextFile($file) } }
+ foreach $file (@dontasksuffixes)
+ { if (-e $file)
+ { RemoveContextFile($file) } }
+ foreach $suffix (@dontasksuffixes)
+ { foreach (@files)
+ { if (/$suffix$/i)
+ { RemoveContextFile($_) } } }
+ foreach $suffix (@forsuresuffixes)
+ { foreach (@files)
+ { if (/\.$suffix$/i)
+ { RemoveContextFile($_) } } }
+ foreach $file (@files)
+ { if ($file =~ /(.*?)\.\d+$/)
+ { $basename = $1 ;
+ if (($file =~ /mp(graph|run)/) || (-e "$basename.mp"))
+ { RemoveContextFile($file) } } }
+ foreach $suffix (@texnonesuffixes)
+ { foreach (@files)
+ { if (/(.*)\.$suffix$/i)
+ { if ((-e "$1.tex")||(-e "$1.xml")||(-e "$1.fo"))
+ { KeepContextFile($_) }
+ else
+ { $strippedname = $1 ;
+ $strippedname =~ s/\-[a-z]$//io ;
+ if ((-e "$strippedname.tex")||(-e "$strippedname.xml"))
+ { KeepContextFile($_." (potential result file)") }
+ else
+ { RemoveContextFile($_) } } } } }
+ if ($removedfiles||$keptfiles||$persistentfiles)
+ { print "\n" }
+ print " removed files : $removedfiles\n" ;
+ print " kept files : $keptfiles\n" ;
+ print " persistent files : $persistentfiles\n" ;
+ print " reclaimed bytes : $reclaimedbytes\n" }
+
+#D Another undocumented feature.
+#
+# obsolete, i.e now in pdftools, so this will become:
+#
+# sub AnalyzeFile
+# { system("pdftools --analyze $ARGV[0]") }
+
+sub AnalyzeFile
+ { my $filename = $ARGV[0] ;
+ return unless (($filename =~ /\.pdf/)&&(-e $filename)) ;
+ my $filesize = -s $filename ;
+ print " analyzing file : $filename\n" ;
+ print " file size : $filesize\n" ;
+ open (PDF, $filename) ;
+ binmode PDF ;
+ my $Object = 0 ;
+ my $Annot = 0 ;
+ my $Link = 0 ;
+ my $Widget = 0 ;
+ my $Named = 0 ;
+ my $Script = 0 ;
+ my $Cross = 0 ;
+ while (<PDF>)
+ { while (/\d+\s+\d+\s+obj/go) { ++$Object } ;
+ while (/\/Type\s*\/Annot/go) { ++$Annot } ;
+ while (/\/GoToR\s*\/F/go) { ++$Cross } ;
+ while (/\/Subtype\s*\/Link/go) { ++$Link } ;
+ while (/\/Subtype\s*\/Widget/go) { ++$Widget } ;
+ while (/\/S\s*\/Named/go) { ++$Named } ;
+ while (/\/S\s*\/JavaScript/go) { ++$Script } }
+ close (PDF) ;
+ print " objects : $Object\n" ;
+ print " annotations : $Annot\n" ;
+ print " links : $Link ($Named named / $Script scripts / $Cross files)\n" ;
+ print " widgets : $Widget\n" }
+
+# moved to ctxtools
+#
+# sub FilterPages
+# { system("ctxtools $ARGV{0]") }
+
+sub FilterPages # temp feature / no reporting
+ { my $filename = $ARGV[0] ;
+ return unless -f "$filename.pdf" ;
+ my $old = '' ;
+ my $n = 0 ;
+ if (open(PDF,"<$filename.pdf") && open(TUO,">>$filename.tuo"))
+ { binmode PDF ;
+ while (<PDF>)
+ { chomp ;
+ if (($_ eq '/Type /Page') && ($old =~ /^(\d+)\s+0\s+obj/o))
+ { ++$n ; $p = $1 ;
+ print TUO "\\objectreference{PDFP}{$n}{$p}{$n}\n" }
+ else
+ { $old = $_ } }
+ close(PDF) ;
+ close(TUO) } }
+
+ ShowBanner ;
+
+if ($UnknownOptions ) { ShowHelpInfo } # not yet done
+elsif ($ProcessReferences) { HandleReferences }
+elsif ($ProcessDocuments ) { HandleDocuments }
+elsif ($ProcessSources ) { HandleSources }
+elsif ($ProcessSetups ) { HandleSetups }
+elsif ($ProcessTemplates ) { HandleEditorCues }
+elsif ($ProcessInfos ) { HandleEditorCues }
+elsif ($ProcessFigures ) { HandleFigures }
+elsif ($ProcessLogFile ) { HandleLogFile }
+elsif ($PurgeFiles ) { PurgeFiles }
+elsif ($PurgeAllFiles ) { PurgeFiles }
+elsif ($AnalyzeFile ) { AnalyzeFile }
+elsif ($FilterPages ) { FilterPages }
+elsif ($SciteApi ) { GenerateSciteApi }
+elsif ($ProcessHelp ) { ShowHelpInfo } # redundant
+else { ShowHelpInfo }
+
+#D So far.
diff --git a/Master/texmf-dist/scripts/context/perl/utiplug.pm b/Master/texmf-dist/scripts/context/perl/utiplug.pm
new file mode 100644
index 00000000000..2bc162e1e38
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/perl/utiplug.pm
@@ -0,0 +1,30 @@
+package utiplug ;
+
+my @data ;
+my @result ;
+
+sub utiplug::initialize
+ { @data = () }
+
+sub utiplug::process
+ { @data = sort @data ;
+ for (my $i=0; $i<@data; $i++)
+ { @result[$i] = "\\plugintest\{$i\}\{$data[$i]\}" } }
+
+sub utiplug::handle
+ { my ($self,$text,$rest) = @_ ; push @data, $text }
+
+sub utiplug::identify
+ { return "utiplug test plugin" }
+
+sub utiplug::report
+ { my $keys = @data ;
+ if ($keys)
+ { return ("done", "keys:$keys") }
+ else
+ { return ("nothing done") } }
+
+sub utiplug::results
+ { return @result }
+
+1 ;
diff --git a/Master/texmf-dist/scripts/context/ruby/base/ctx.rb b/Master/texmf-dist/scripts/context/ruby/base/ctx.rb
new file mode 100644
index 00000000000..852c3f7046e
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/base/ctx.rb
@@ -0,0 +1,285 @@
+# module : base/ctx
+# 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
+
+# report ?
+
+require 'base/system'
+require 'base/file'
+require 'base/switch' # has needsupdate, bad place
+
+require 'rexml/document'
+
+class CtxRunner
+
+ attr_reader :environments, :modules, :filters
+
+ def initialize(jobname=nil,logger=nil)
+ if @logger = logger then
+ def report(str='')
+ @logger.report(str)
+ end
+ else
+ def report(str='')
+ puts(str)
+ end
+ end
+ @jobname = jobname
+ @ctxname = nil
+ @xmldata = nil
+ @prepfiles = Hash.new
+ @environments = Array.new
+ @modules = Array.new
+ @filters = Array.new
+ end
+
+ def manipulate(ctxname=nil,defaultname=nil)
+
+ if ctxname then
+ @ctxname = ctxname
+ @jobname = File.suffixed(@ctxname,'tex') unless @jobname
+ else
+ @ctxname = File.suffixed(@jobname,'ctx') if @jobname
+ end
+
+ if not @ctxname then
+ report('provide ctx file')
+ return
+ end
+
+ if not FileTest.file?(@ctxname) and defaultname and FileTest.file?(defaultname) then
+ @ctxname = defaultname
+ end
+
+ if not FileTest.file?(@ctxname) then
+ report('provide ctx file')
+ return
+ end
+
+ @xmldata = IO.read(@ctxname)
+
+ unless @xmldata =~ /^.*<\?xml.*?\?>/moi then
+ report("ctx file #{@ctxname} is no xml file, skipping")
+ return
+ else
+ report("loading ctx file #{@ctxname}")
+ end
+
+ begin
+ @xmldata = REXML::Document.new(@xmldata)
+ rescue
+ report('provide valid ctx file (xml error)')
+ return
+ else
+ include(@xmldata,'ctx:include','name')
+ end
+
+ begin
+ variables = Hash.new
+ if @jobname then
+ variables['job'] = @jobname
+ end
+ REXML::XPath.each(@xmldata.root,"//ctx:value[@name='job']") do |val|
+ substititute(val,variables['job'])
+ end
+ REXML::XPath.each(@xmldata.root,"/ctx:job/ctx:message") do |mes|
+ report("preprocessing: #{justtext(mes)}")
+ end
+ REXML::XPath.each(@xmldata.root,"/ctx:job/ctx:process/ctx:resources/ctx:environment") do |sty|
+ @environments << justtext(sty)
+ end
+ REXML::XPath.each(@xmldata.root,"/ctx:job/ctx:process/ctx:resources/ctx:module") do |mod|
+ @modules << justtext(mod)
+ end
+ REXML::XPath.each(@xmldata.root,"/ctx:job/ctx:process/ctx:resources/ctx:filter") do |fil|
+ @filters << justtext(mod)
+ end
+ REXML::XPath.each(@xmldata.root,"/ctx:job/ctx:preprocess/ctx:files") do |files|
+ REXML::XPath.each(files,"ctx:file") do |pattern|
+ preprocessor = pattern.attributes['processor']
+ if preprocessor and not preprocessor.empty? then
+ pattern = justtext(pattern)
+ Dir.glob(pattern).each do |oldfile|
+ newfile = "#{oldfile}.prep"
+ if File.needsupdate(oldfile,newfile) then
+ begin
+ File.delete(newfile)
+ rescue
+ # hope for the best
+ end
+ # there can be a sequence of processors
+ preprocessor.split(',').each do |pp|
+ if command = REXML::XPath.first(@xmldata.root,"/ctx:job/ctx:preprocess/ctx:processors/ctx:processor[@name='#{pp}']") then
+ # a lie: no <?xml ...?>
+ command = REXML::Document.new(command.to_s) # don't infect original
+ command = command.elements["ctx:processor"]
+ report("preprocessing #{oldfile} using #{pp}")
+ REXML::XPath.each(command,"ctx:old") do |value| replace(value,oldfile) end
+ REXML::XPath.each(command,"ctx:new") do |value| replace(value,newfile) end
+ variables['old'] = oldfile
+ variables['new'] = newfile
+ REXML::XPath.each(command,"ctx:value") do |value|
+ if name = value.attributes['name'] then
+ substititute(value,variables[name.to_s])
+ end
+ end
+ command = justtext(command)
+ report(command)
+ unless ok = System.run(command) then
+ report("error in preprocessing file #{oldfile}")
+ end
+ end
+ end
+ if FileTest.file?(newfile) then
+ File.syncmtimes(oldfile,newfile)
+ else
+ report("preprocessing #{oldfile} gave no #{newfile}")
+ end
+ else
+ report("#{oldfile} needs no preprocessing")
+ end
+ @prepfiles[oldfile] = FileTest.file?(newfile)
+ end
+ end
+ end
+ end
+ rescue
+ report("fatal error in preprocessing #{@ctxname}: #{$!}")
+ end
+ end
+
+ def savelog(ctlname=nil)
+ unless ctlname then
+ if @jobname then
+ ctlname = File.suffixed(@jobname,'ctl')
+ elsif @ctxname then
+ ctlname = File.suffixed(@ctxname,'ctl')
+ else
+ return
+ end
+ end
+ if @prepfiles.length > 0 then
+ if log = File.open(ctlname,'w') then
+ log << "<?xml version='1.0' standalone='yes'?>\n\n"
+ log << "<ctx:preplist>\n"
+ @prepfiles.keys.sort.each do |prep|
+ log << "\t<ctx:prepfile done='#{yes_or_no(@prepfiles[prep])}'>#{File.basename(prep)}</ctx:prepfile>\n"
+ end
+ log << "</ctx:preplist>\n"
+ log.close
+ end
+ else
+ begin
+ File.delete(ctlname)
+ rescue
+ end
+ end
+ end
+
+ private
+
+ def include(xmldata,element='ctx:include',attribute='name')
+ loop do
+ begin
+ more = false
+ REXML::XPath.each(xmldata.root,element) do |e|
+ begin
+ name = e.attributes.get_attribute(attribute).to_s
+ name = e.text.to_s if name.empty?
+ name.strip! if name
+ if name and not name.empty? and FileTest.file?(name) then
+ if f = File.open(name,'r') and i = REXML::Document.new(f) then
+ report("including ctx file #{name}")
+ REXML::XPath.each(i.root,"*") do |ii|
+ xmldata.root.insert_after(e,ii)
+ more = true
+ end
+ end
+ else
+ report("no valid ctx inclusion file #{name}")
+ end
+ rescue Exception
+ # skip this file
+ ensure
+ xmldata.root.delete(e)
+ end
+ end
+ break unless more
+ rescue Exception
+ break # forget about inclusion
+ end
+ end
+ end
+
+ private
+
+ def yes_or_no(b)
+ if b then 'yes' else 'no' end
+ end
+
+ private # copied from rlxtools.rb
+
+ def justtext(str)
+ str = str.to_s
+ str.gsub!(/<[^>]*?>/o, '')
+ str.gsub!(/\s+/o, ' ')
+ str.gsub!(/&lt;/o, '<')
+ str.gsub!(/&gt;/o, '>')
+ str.gsub!(/&amp;/o, '&')
+ str.gsub!(/&quot;/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
diff --git a/Master/texmf-dist/scripts/context/ruby/base/file.rb b/Master/texmf-dist/scripts/context/ruby/base/file.rb
new file mode 100644
index 00000000000..42fb346c409
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/base/file.rb
@@ -0,0 +1,147 @@
+# module : base/file
+# 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 'ftools'
+
+class File
+
+ def File.suffixed(name,sufa,sufb=nil)
+ if sufb then
+ if sufa.empty? then
+ unsuffixed(name) + ".#{sufb}"
+ else
+ unsuffixed(name) + "-#{sufa}.#{sufb}"
+ end
+ 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/Master/texmf-dist/scripts/context/ruby/base/kpse.rb b/Master/texmf-dist/scripts/context/ruby/base/kpse.rb
new file mode 100644
index 00000000000..dc4898ffc58
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/base/kpse.rb
@@ -0,0 +1,305 @@
+# 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
+#
+# todo: web2c vs miktex module and include in kpse
+
+require 'rbconfig'
+
+# beware $engine is lowercase in kpse
+#
+# miktex has mem|fmt|base paths
+
+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/
+
+ @@distribution = 'miktex' if ENV['PATH'] =~ /miktex[\\\/]bin/o
+
+ @@usekpserunner = false || ENV['KPSEFAST'] == 'yes'
+
+ require 'base/tool' if @@usekpserunner
+
+ 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.distribution
+ @@distribution
+ end
+
+ def Kpse.miktex?
+ @@distribution == 'miktex'
+ end
+
+ def Kpse.web2c?
+ @@distribution == 'web2c'
+ 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.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
+ if @@usekpserunner then
+ results = KpseRunner.kpsewhich(arguments).chomp
+ else
+ results = `kpsewhich #{arguments}`.chomp
+ end
+ end
+ rescue
+ puts "unable to run kpsewhich" if @@tracing
+ @@problems, results = true, ''
+ end
+ puts results if @@tracing
+ return results
+ end
+
+ def Kpse.formatpaths
+ # maybe we should check for writeability
+ 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)
+
+ # because engine support in distributions is not always
+ # as we expect, we need to check for it;
+
+ # todo: miktex
+
+ if miktex? then
+ return '.'
+ else
+ unless @@paths.key?(engine) then
+ # savedengine = ENV['engine']
+ if ENV['TEXFORMATS'] && ! ENV['TEXFORMATS'].empty? then
+ # make sure that we have a lowercase entry
+ ENV['TEXFORMATS'] = ENV['TEXFORMATS'].sub(/\$engine/io,"\$engine")
+ # well, we will append anyway, so we could also strip it
+ # ENV['TEXFORMATS'] = ENV['TEXFORMATS'].sub(/\$engine/io,"")
+ end
+ # use modern method
+ if enginepath then
+ formatpath = run("--engine=#{engine} --show-path=fmt")
+ else
+ # ENV['engine'] = engine if engine
+ formatpath = run("--show-path=fmt")
+ end
+ # use ancient method
+ if formatpath.empty? then
+ if enginepath then
+ if @@mswindows then
+ formatpath = run("--engine=#{engine} --expand-path=\$TEXFORMATS")
+ else
+ formatpath = run("--engine=#{engine} --expand-path=\\\$TEXFORMATS")
+ end
+ end
+ # either no enginepath or failed run
+ if formatpath.empty? then
+ if @@mswindows then
+ formatpath = run("--expand-path=\$TEXFORMATS")
+ else
+ formatpath = run("--expand-path=\\\$TEXFORMATS")
+ end
+ end
+ end
+ # locate writable path
+ if ! formatpath.empty? then
+ formatpath.split(File::PATH_SEPARATOR).each do |fp|
+ fp.gsub!(/\\/,'/')
+ # remove funny patterns
+ fp.sub!(/^!!/,'')
+ fp.sub!(/\/+$/,'')
+ fp.sub!(/unsetengine/,if enginepath then engine else '' end)
+ if ! fp.empty? && (fp != '.') then
+ # strip (possible engine) and test for writeability
+ fpp = fp.sub(/#{engine}\/*$/,'')
+ if FileTest.directory?(fpp) && FileTest.writable?(fpp) then
+ # use this path
+ formatpath = fp.dup
+ break
+ end
+ end
+ end
+ end
+ # needed !
+ begin File.makedirs(formatpath) ; rescue ; end ;
+ # fall back to current path
+ formatpath = '.' if formatpath.empty? || ! FileTest.writable?(formatpath)
+ # append engine but prevent duplicates
+ formatpath = File.join(formatpath.sub(/\/*#{engine}\/*$/,''), engine) if enginepath
+ begin File.makedirs(formatpath) ; rescue ; end ;
+ setpath(engine,formatpath)
+ # ENV['engine'] = savedengine
+ end
+ return @@paths[engine].first
+ end
+ end
+
+ def Kpse.update
+ system('initexmf -u') if Kpse.miktex?
+ system('mktexlsr')
+ end
+
+ # engine support is either broken of not implemented in some
+ # distributions, so we need to take care of it ourselves (without
+ # delays due to kpse calls); there can be many paths in the string
+ #
+ # in a year or so, i will drop this check
+
+ def Kpse.fixtexmfvars(engine=nil)
+ ENV['ENGINE'] = engine if engine
+ texformats = if ENV['TEXFORMATS'] then ENV['TEXFORMATS'].dup else '' end
+ if texformats.empty? then
+ if engine then
+ if @@mswindows then
+ texformats = `kpsewhich --engine=#{engine} --expand-var=\$TEXFORMATS`.chomp
+ else
+ texformats = `kpsewhich --engine=#{engine} --expand-var=\\\$TEXFORMATS`.chomp
+ end
+ else
+ if @@mswindows then
+ texformats = `kpsewhich --expand-var=\$TEXFORMATS`.chomp
+ else
+ texformats = `kpsewhich --expand-var=\\\$TEXFORMATS`.chomp
+ end
+ end
+ end
+ if engine then
+ texformats.sub!(/unsetengine/,engine)
+ else
+ texformats.sub!(/unsetengine/,"\$engine")
+ end
+ if engine && (texformats =~ /web2c[\/\\].*#{engine}/o) then
+ # ok, engine is seen
+ return false
+ elsif texformats =~ /web2c[\/\\].*\$engine/io then
+ # shouldn't happen
+ return false
+ else
+ ENV['TEXFORMATS'] = texformats.gsub(/(web2c\/\{)(,\})/o) do
+ "#{$1}\$engine#{$2}"
+ end
+ if texformats !~ /web2c[\/\\].*\$engine/io then
+ ENV['TEXFORMATS'] = texformats.gsub(/web2c\/*/, "web2c/{\$engine,}")
+ end
+ return true
+ end
+ end
+
+ def Kpse.runscript(name,filename=[],options=[])
+ setscript(name,`texmfstart --locate #{name}`) unless @@scripts.key?(name)
+ cmd = "#{@@scripts[name]} #{[options].flatten.join(' ')} #{[filename].flatten.join(' ')}"
+ system(cmd)
+ end
+
+ def Kpse.pipescript(name,filename=[],options=[])
+ setscript(name,`texmfstart --locate #{name}`) unless @@scripts.key?(name)
+ cmd = "#{@@scripts[name]} #{[options].flatten.join(' ')} #{[filename].flatten.join(' ')}"
+ `#{cmd}`
+ 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.collect do |p|
+ p.sub(/^!!/,'').sub(/\/*$/,'')
+ end
+ ENV["_CTX_K_P_#{key}_"] = @@paths[key].join(';') if @@crossover
+ end
+
+end
diff --git a/Master/texmf-dist/scripts/context/ruby/base/kpsefast.rb b/Master/texmf-dist/scripts/context/ruby/base/kpsefast.rb
new file mode 100644
index 00000000000..52ab28d0fe7
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/base/kpsefast.rb
@@ -0,0 +1,881 @@
+# module : base/kpsefast
+# 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: multiple cnf files
+
+class File
+
+ def File.locate_file(path,name)
+ begin
+ files = Dir.entries(path)
+ if files.include?(name) then
+ fullname = File.join(path,name)
+ return fullname if FileTest.file?(fullname)
+ end
+ files.each do |p|
+ fullname = File.join(path,p)
+ if p != '.' and p != '..' and FileTest.directory?(fullname) and result = locate_file(fullname,name) then
+ return result
+ end
+ end
+ rescue
+ # bad path
+ end
+ return nil
+ end
+
+ def File.glob_file(pattern)
+ return Dir.glob(pattern).first
+ end
+
+end
+
+class KPSEFAST
+
+ # formats are an incredible inconsistent mess
+
+ @@suffixes = Hash.new
+ @@formats = Hash.new
+ @@suffixmap = Hash.new
+
+ @@suffixes['gf'] = ['.<resolution>gf'] # todo
+ @@suffixes['pk'] = ['.<resolution>pk'] # todo
+ @@suffixes['tfm'] = ['.tfm']
+ @@suffixes['afm'] = ['.afm']
+ @@suffixes['base'] = ['.base']
+ @@suffixes['bib'] = ['.bib']
+ @@suffixes['bst'] = ['.bst']
+ @@suffixes['cnf'] = ['.cnf']
+ @@suffixes['ls-R'] = ['ls-R', 'ls-r']
+ @@suffixes['fmt'] = ['.fmt', '.efmt', '.efm', '.ofmt', '.ofm', '.oft', '.eofmt', '.eoft', '.eof', '.pfmt', '.pfm', '.epfmt', '.epf', '.xpfmt', '.xpf', '.afmt', '.afm']
+ @@suffixes['map'] = ['.map']
+ @@suffixes['mem'] = ['.mem']
+ @@suffixes['mf'] = ['.mf']
+ @@suffixes['mfpool'] = ['.pool']
+ @@suffixes['mft'] = ['.mft']
+ @@suffixes['mp'] = ['.mp']
+ @@suffixes['mppool'] = ['.pool']
+ @@suffixes['ocp'] = ['.ocp']
+ @@suffixes['ofm'] = ['.ofm', '.tfm']
+ @@suffixes['opl'] = ['.opl']
+ @@suffixes['otp'] = ['.otp']
+ @@suffixes['ovf'] = ['.ovf']
+ @@suffixes['ovp'] = ['.ovp']
+ @@suffixes['graphic/figure'] = ['.eps', '.epsi']
+ @@suffixes['tex'] = ['.tex']
+ @@suffixes['texpool'] = ['.pool']
+ @@suffixes['PostScript header'] = ['.pro']
+ @@suffixes['type1 fonts'] = ['.pfa', '.pfb']
+ @@suffixes['vf'] = ['.vf']
+ @@suffixes['ist'] = ['.ist']
+ @@suffixes['truetype fonts'] = ['.ttf', '.ttc']
+ @@suffixes['web'] = ['.web', '.ch']
+ @@suffixes['cweb'] = ['.w', '.web', '.ch']
+ @@suffixes['enc files'] = ['.enc']
+ @@suffixes['cmap files'] = ['.cmap']
+ @@suffixes['subfont definition files'] = ['.sfd']
+ @@suffixes['lig files'] = ['.lig']
+ @@suffixes['bitmap font'] = []
+ @@suffixes['MetaPost support'] = []
+ @@suffixes['TeX system documentation'] = []
+ @@suffixes['TeX system sources'] = []
+ @@suffixes['Troff fonts'] = []
+ @@suffixes['dvips config'] = []
+ @@suffixes['type42 fonts'] = []
+ @@suffixes['web2c files'] = []
+ @@suffixes['other text files'] = []
+ @@suffixes['other binary files'] = []
+ @@suffixes['misc fonts'] = []
+ @@suffixes['opentype fonts'] = []
+ @@suffixes['pdftex config'] = []
+ @@suffixes['texmfscripts'] = []
+
+ # replacements
+
+ @@suffixes['fmt'] = ['.fmt']
+ @@suffixes['type1 fonts'] = ['.pfa', '.pfb', '.pfm']
+ @@suffixes['tex'] = ['.tex', '.xml']
+ @@suffixes['texmfscripts'] = ['rb','lua','py','pl']
+
+ @@suffixes.keys.each do |k| @@suffixes[k].each do |s| @@suffixmap[s] = k end end
+
+ # TTF2TFMINPUTS
+ # MISCFONTS
+ # TEXCONFIG
+ # DVIPDFMINPUTS
+ # OTFFONTS
+
+ @@formats['gf'] = ''
+ @@formats['pk'] = ''
+ @@formats['tfm'] = 'TFMFONTS'
+ @@formats['afm'] = 'AFMFONTS'
+ @@formats['base'] = 'MFBASES'
+ @@formats['bib'] = ''
+ @@formats['bst'] = ''
+ @@formats['cnf'] = ''
+ @@formats['ls-R'] = ''
+ @@formats['fmt'] = ''
+ @@formats['map'] = 'TEXFONTMAPS'
+ @@formats['mem'] = 'MPMEMS'
+ @@formats['mf'] = 'MFINPUTS'
+ @@formats['mfpool'] = 'MFPOOL'
+ @@formats['mft'] = ''
+ @@formats['mp'] = 'MPINPUTS'
+ @@formats['mppool'] = 'MPPOOL'
+ @@formats['ocp'] = 'OCPINPUTS'
+ @@formats['ofm'] = 'OFMFONTS'
+ @@formats['opl'] = 'OPLFONTS'
+ @@formats['otp'] = 'OTPINPUTS'
+ @@formats['ovf'] = 'OVFFONTS'
+ @@formats['ovp'] = 'OVPFONTS'
+ @@formats['graphic/figure'] = ''
+ @@formats['tex'] = 'TEXINPUTS'
+ @@formats['texpool'] = 'TEXPOOL'
+ @@formats['PostScript header'] = 'TEXPSHEADERS'
+ @@formats['type1 fonts'] = 'T1FONTS'
+ @@formats['vf'] = 'VFFONTS'
+ @@formats['ist'] = ''
+ @@formats['truetype fonts'] = 'TTFONTS'
+ @@formats['web'] = ''
+ @@formats['cweb'] = ''
+ @@formats['enc files'] = 'ENCFONTS'
+ @@formats['cmap files'] = 'CMAPFONTS'
+ @@formats['subfont definition files'] = 'SFDFONTS'
+ @@formats['lig files'] = 'LIGFONTS'
+ @@formats['bitmap font'] = ''
+ @@formats['MetaPost support'] = ''
+ @@formats['TeX system documentation'] = ''
+ @@formats['TeX system sources'] = ''
+ @@formats['Troff fonts'] = ''
+ @@formats['dvips config'] = ''
+ @@formats['type42 fonts'] = 'T42FONTS'
+ @@formats['web2c files'] = 'WEB2C'
+ @@formats['other text files'] = ''
+ @@formats['other binary files'] = ''
+ @@formats['misc fonts'] = ''
+ @@formats['opentype fonts'] = 'OPENTYPEFONTS'
+ @@formats['pdftex config'] = 'PDFTEXCONFIG'
+ @@formats['texmfscripts'] = 'TEXMFSCRIPTS'
+
+ attr_accessor :progname, :engine, :format, :rootpath, :treepath,
+ :verbose, :remember, :scandisk, :diskcache, :renewcache
+
+ @@cacheversion = '1'
+
+ def initialize
+ @rootpath = ''
+ @treepath = ''
+ @progname = 'kpsewhich'
+ @engine = 'pdfetex'
+ @variables = Hash.new
+ @expansions = Hash.new
+ @files = Hash.new
+ @found = Hash.new
+ @kpsevars = Hash.new
+ @lsrfiles = Array.new
+ @cnffiles = Array.new
+ @verbose = true
+ @remember = true
+ @scandisk = true
+ @diskcache = true
+ @renewcache = false
+ @isolate = false
+
+ @diskcache = false
+ @cachepath = nil
+ @cachefile = 'tmftools.log'
+ end
+
+ # {$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}
+ #
+ # $SELFAUTOLOC : /usr/tex/bin/platform
+ # $SELFAUTODIR : /usr/tex/bin
+ # $SELFAUTOPARENT : /usr/tex
+ #
+ # since we live in scriptpath we need a slightly different method
+
+ def load_cnf
+ ownpath = File.expand_path($0)
+ if ownpath.gsub!(/texmf.*?$/o, '') then
+ ENV['SELFAUTOPARENT'] = ownpath
+ else
+ ENV['SELFAUTOPARENT'] = '.'
+ end
+ unless @treepath.empty? then
+ unless @rootpath.empty? then
+ @treepath = @treepath.split(',').collect do |p| File.join(@rootpath,p) end.join(',')
+ end
+ ENV['TEXMF'] = @treepath
+ ENV['TEXMFCNF'] = File.join(@treepath.split(',').first,'texmf/web2c')
+ end
+ unless @rootpath.empty? then
+ ENV['TEXMFCNF'] = File.join(@rootpath,'texmf/web2c')
+ ENV['SELFAUTOPARENT'] = @rootpath
+ @isolate = true
+ end
+ filenames = Array.new
+ if ENV['TEXMFCNF'] and not ENV['TEXMFCNF'].empty? then
+ filenames << File.join(ENV['TEXMFCNF'],'texmf.cnf')
+ elsif ENV['SELFAUTOPARENT'] == '.' then
+ filenames << File.join('.','texmf.cnf')
+ else
+ ['texmf-local','texmf'].each do |tree|
+ filenames << File.join(ENV['SELFAUTOPARENT'],tree,'web2c','texmf.cnf')
+ end
+ end
+ # <root>/texmf/web2c/texmf.cnf
+ @rootpath = filenames.first
+ 3.times do
+ @rootpath = File.dirname(@rootpath)
+ end
+ filenames.collect! do |f|
+ f.gsub("\\", '/')
+ end
+ filenames.each do |fname|
+ if FileTest.file?(fname) and f = File.open(fname) then
+ @cnffiles << fname
+ while line = f.gets do
+ loop do
+ # concatenate lines ending with \
+ break unless line.sub!(/\\\s*$/o) do
+ f.gets || ''
+ end
+ end
+ case line
+ when /^[\%\#]/o then
+ # comment
+ when /^\s*(.*?)\s*\=\s*(.*?)\s*$/o then
+ key, value = $1, $2
+ unless @variables.key?(key) then
+ value.sub!(/\%.*$/,'')
+ value.sub!(/\~/, "$HOME")
+ @variables[key] = value
+ end
+ @kpsevars[key] = true
+ end
+ end
+ f.close
+ end
+ end
+ end
+
+ def load_lsr
+ @lsrfiles = []
+ simplified_list(expansion('TEXMF')).each do |p|
+ ['ls-R','ls-r'].each do |f|
+ filename = File.join(p,f)
+ if FileTest.file?(filename) then
+ @lsrfiles << [filename,File.size(filename)]
+ break
+ end
+ end
+ end
+ @files = Hash.new
+ if @diskcache then
+ ['HOME','TEMP','TMP','TMPDIR'].each do |key|
+ if ENV[key] then
+ if FileTest.directory?(ENV[key]) then
+ @cachepath = ENV[key]
+ @cachefile = [@rootpath.gsub(/[^A-Z0-9]/io, '-').gsub(/\-+/,'-'),File.basename(@cachefile)].join('-')
+ break
+ end
+ end
+ end
+ if @cachepath and not @renewcache and FileTest.file?(File.join(@cachepath,@cachefile)) then
+ begin
+ if f = File.open(File.join(@cachepath,@cachefile)) then
+ cacheversion = Marshal.load(f)
+ if cacheversion == @@cacheversion then
+ lsrfiles = Marshal.load(f)
+ if lsrfiles == @lsrfiles then
+ @files = Marshal.load(f)
+ end
+ end
+ f.close
+ end
+ rescue
+ @files = Hash.new
+ end
+ end
+ end
+ return if @files.size > 0
+ @lsrfiles.each do |filedata|
+ filename, filesize = filedata
+ filepath = File.dirname(filename)
+ begin
+ path = '.'
+ data = IO.readlines(filename)
+ if data[0].chomp =~ /% ls\-R \-\- filename database for kpathsea\; do not change this line\./io then
+ data.each do |line|
+ case line
+ when /^[a-zA-Z0-9]/o then
+ line.chomp!
+ if @files[line] then
+ @files[line] << path
+ else
+ @files[line] = [path]
+ end
+ when /^\.\/(.*?)\:$/o then
+ path = File.join(filepath,$1)
+ end
+ end
+ end
+ rescue
+ # sorry
+ end
+ end
+ if @diskcache and @cachepath and f = File.open(File.join(@cachepath,@cachefile),'wb') then
+ f << Marshal.dump(@@cacheversion)
+ f << Marshal.dump(@lsrfiles)
+ f << Marshal.dump(@files)
+ f.close
+ end
+ end
+
+ def expand_variables
+ @expansions = Hash.new
+ if @isolate then
+ @variables['TEXMFCNF'] = ENV['TEXMFCNF'].dup
+ @variables['SELFAUTOPARENT'] = ENV['SELFAUTOPARENT'].dup
+ else
+ ENV.keys.each do |e|
+ if e =~ /^([a-zA-Z]+)\_(.*)\s*$/o then
+ @expansions["#{$1}.#{$2}"] = ENV[e].dup
+ else
+ @expansions[e] = ENV[e].dup
+ end
+ end
+ end
+ @variables.keys.each do |k|
+ @expansions[k] = @variables[k].dup unless @expansions[k]
+ end
+ loop do
+ busy = false
+ @expansions.keys.each do |k|
+ @expansions[k].gsub!(/\$([a-zA-Z0-9\_\-]*)/o) do
+ busy = true
+ @expansions[$1] || ''
+ end
+ @expansions[k].gsub!(/\$\{([a-zA-Z0-9\_\-]*)\}/o) do
+ busy = true
+ @expansions[$1] || ''
+ end
+ end
+ break unless busy
+ end
+ @expansions.keys.each do |k|
+ @expansions[k] = @expansions[k].gsub("\\", '/')
+ end
+ end
+
+ def variable(name='')
+ (name and not name.empty? and @variables[name.sub('$','')]) or ''
+ end
+
+ def expansion(name='')
+ (name and not name.empty? and @expansions[name.sub('$','')]) or ''
+ end
+
+ def variable?(name='')
+ name and not name.empty? and @variables.key?(name.sub('$',''))
+ end
+
+ def expansion?(name='')
+ name and not name.empty? and @expansions.key?(name.sub('$',''))
+ end
+
+ def simplified_list(str)
+ lst = str.gsub(/^\{/o,'').gsub(/\}$/o,'').split(",")
+ lst.collect do |l|
+ l.sub(/^[\!]*/,'').sub(/[\/\\]*$/o,'')
+ end
+ end
+
+ def original_variable(variable)
+ if variable?("#{@progname}.#{variable}") then
+ variable("#{@progname}.#{variable}")
+ elsif variable?(variable) then
+ variable(variable)
+ else
+ ''
+ end
+ end
+
+ def expanded_variable(variable)
+ if expansion?("#{variable}.#{@progname}") then
+ expansion("#{variable}.#{@progname}")
+ elsif expansion?(variable) then
+ expansion(variable)
+ else
+ ''
+ end
+ end
+
+ def original_path(filename='')
+ _expanded_path_(original_variable(var_of_format_or_suffix(filename)).split(";"))
+ end
+
+ def expanded_path(filename='')
+ _expanded_path_(expanded_variable(var_of_format_or_suffix(filename)).split(";"))
+ end
+
+ def _expanded_path_(pathlist)
+ i, n = 0, 0
+ pathlist.collect! do |mainpath|
+ mainpath.gsub(/([\{\}])/o) do
+ if $1 == "{" then
+ i += 1 ; n = i if i > n ; "<#{i}>"
+ else
+ i -= 1 ; "</#{i+1}>"
+ end
+ end
+ end
+ n.times do |i|
+ loop do
+ more = false
+ newlist = []
+ pathlist.each do |path|
+ unless path.sub!(/^(.*?)<(#{n-i})>(.*?)<\/\2>(.*?)$/) do
+ pre, mid, post = $1, $3, $4
+ mid.gsub!(/\,$/,',.')
+ mid.split(',').each do |m|
+ more = true
+ if m == '.' then
+ newlist << "#{pre}#{post}"
+ else
+ newlist << "#{pre}#{m}#{post}"
+ end
+ end
+ end then
+ newlist << path
+ end
+ end
+ if more then
+ pathlist = [newlist].flatten # copy -)
+ else
+ break
+ end
+ end
+ end
+ pathlist = pathlist.uniq.collect do |path|
+ p = path.gsub(/^\/+/o) do '' end
+ # p.gsub!(/(.)\/\/(.)/o) do "#{$1}/#{$2}" end
+ # p.gsub!(/\/\/+$/o) do '//' end
+ p.gsub!(/\/\/+/o) do '//' end
+ p
+ end
+ pathlist
+ end
+
+ # todo: ignore case
+
+ def var_of_format(str)
+ @@formats[str] || ''
+ end
+
+ def var_of_suffix(str) # includes .
+ if @@suffixmap.key?(str) then @@formats[@@suffixmap[str]] else '' end
+ end
+
+ def var_of_format_or_suffix(str)
+ if @@formats.key?(@format) then
+ @@formats[@format]
+ elsif @@suffixmap.key?(File.extname(str)) then # extname includes .
+ @@formats[@@suffixmap[File.extname(str)]] # extname includes .
+ else
+ ''
+ end
+ end
+
+end
+
+class KPSEFAST
+
+ # test things
+
+ def list_variables(kpseonly=true)
+ @variables.keys.sort.each do |k|
+ if kpseonly then
+ puts("#{k} = #{@variables[k]}") if @kpsevars[k]
+ else
+ puts("#{if @kpsevars[k] then 'K' else 'E' end} #{k} = #{@variables[k]}")
+ end
+ end
+ end
+
+ def list_expansions(kpseonly=true)
+ @expansions.keys.sort.each do |k|
+ if kpseonly then
+ puts("#{k} = #{@expansions[k]}") if @kpsevars[k]
+ else
+ puts("#{if @kpsevars[k] then 'K' else 'E' end} #{k} = #{@expansions[k]}")
+ end
+ end
+ end
+
+ def list_lsr
+ puts("files = #{@files.size}")
+ end
+
+ def set_test_patterns
+ @variables["KPSE_TEST_PATTERN_A"] = "foo/{1,2}/bar//"
+ @variables["KPSE_TEST_PATTERN_B"] = "!!x{A,B{1,2}}y"
+ @variables["KPSE_TEST_PATTERN_C"] = "x{A,B//{1,2}}y"
+ @variables["KPSE_TEST_PATTERN_D"] = "x{A,B//{1,2,}}//y"
+ end
+
+ def show_test_patterns
+ ['A','B','D'].each do |i|
+ puts ""
+ puts @variables ["KPSE_TEST_PATTERN_#{i}"]
+ puts ""
+ puts expand_path("KPSE_TEST_PATTERN_#{i}").split(File::PATH_SEPARATOR)
+ puts ""
+ end
+ end
+
+end
+
+class KPSEFAST
+
+ # kpse stuff
+
+ def expand_braces(str) # output variable and brace expansion of STRING.
+ _expanded_path_(original_variable(str).split(";")).join(File::PATH_SEPARATOR)
+ end
+
+ def expand_path(str) # output complete path expansion of STRING.
+ _expanded_path_(expanded_variable(str).split(";")).join(File::PATH_SEPARATOR)
+ end
+
+ def expand_var(str) # output variable expansion of STRING.
+ expanded_variable(str)
+ end
+
+ def show_path(str) # output search path for file type NAME
+ expanded_path(var_of_format(str)).join(File::PATH_SEPARATOR)
+ end
+
+ def var_value(str) # output the value of variable $STRING.
+ original_variable(str)
+ end
+
+end
+
+class KPSEFAST
+
+ def find_file(filename)
+ find_files(filename,true)
+ end
+
+ def find_files(filename,first=false)
+ if @remember then
+ stamp = "#{filename}--#{@format}--#{@engine}--#{@progname}"
+ return @found[stamp] if @found.key?(stamp)
+ end
+ pathlist = expanded_path(filename)
+ result = []
+ filelist = if @files.key?(filename) then @files[filename].uniq else nil end
+ done = false
+ pathlist.each do |path|
+ doscan = if path =~ /^\!\!/o then false else true end
+ recurse = if path =~ /\/\/$/o then true else false end
+ pathname = path.dup
+ pathname.gsub!(/^\!+/o, '')
+ done = false
+ if not done and filelist then
+ # checking for exact match
+ if filelist.include?(pathname) then
+ result << pathname
+ done = true
+ end
+ if not done and recurse then
+ # checking for fuzzy //
+ pathname.gsub!(/\/+$/o, '/.*')
+ # pathname.gsub!(/\/\//o,'/[\/]*/')
+ pathname.gsub!(/\/\//o,'/.*?/')
+ re = /^#{pathname}/
+ filelist.each do |f|
+ if re =~ f then
+ result << f # duplicates will be filtered later
+ done = true
+ end
+ break if done
+ end
+ end
+ end
+ if not done and doscan then
+ # checking for path itself
+ pname = pathname.sub(/\.\*$/,'')
+ if not pname =~ /\*/o and FileTest.file?(File.join(pname,filename)) then
+ result << pname
+ done = true
+ end
+ end
+ break if done and first
+ end
+ if not done and @scandisk then
+ pathlist.each do |path|
+ pathname = path.dup
+ unless pathname.gsub!(/^\!+/o, '') then # !! prevents scan
+ recurse = pathname.gsub!(/\/+$/o, '')
+ complex = pathname.gsub!(/\/\//o,'/*/')
+ if recurse then
+ if complex then
+ if ok = File.glob_file("#{pathname}/**/#{filename}") then
+ result << File.dirname(ok)
+ done = true
+ end
+ elsif ok = File.locate_file(pathname,filename) then
+ result << File.dirname(ok)
+ done = true
+ end
+ elsif complex then
+ if ok = File.glob_file("#{pathname}/#{filename}") then
+ result << File.dirname(ok)
+ done = true
+ end
+ elsif FileTest.file?(File.join(pathname,filename)) then
+ result << pathname
+ done = true
+ end
+ break if done and first
+ end
+ end
+ end
+ result = result.uniq.collect do |pathname|
+ File.join(pathname,filename)
+ end
+ @found[stamp] = result if @remember
+ return result # redundant
+ end
+
+end
+
+class KPSEFAST
+
+ class FileData
+ attr_accessor :tag, :name, :size, :date
+ def initialize(tag=0,name=nil,size=nil,date=nil)
+ @tag, @name, @size, @date = tag, name, size, date
+ end
+ def FileData.sizes(a)
+ a.collect do |aa|
+ aa.size
+ end
+ end
+ def report
+ case @tag
+ when 1
+ "deleted | #{@size.to_s.rjust(8)} | #{@date.strftime('%m/%d/%Y %I:%M')} | #{@name}"
+ when 2
+ "present | #{@size.to_s.rjust(8)} | #{@date.strftime('%m/%d/%Y %I:%M')} | #{@name}"
+ when 3
+ "obsolete | #{' '*8} | #{' '*16} | #{@name}"
+ end
+ end
+ end
+
+ def analyze_files(filter='',strict=false,sort='',delete=false)
+ puts("command line = #{ARGV.join(' ')}")
+ puts("number of files = #{@files.size}")
+ puts("filter pattern = #{filter}")
+ puts("loaded cnf files = #{@cnffiles.join(' ')}")
+ puts('')
+ if filter.gsub!(/^not:/,'') then
+ def the_same(filter,filename)
+ not filter or filter.empty? or /#{filter}/ !~ filename
+ end
+ else
+ def the_same(filter,filename)
+ not filter or filter.empty? or /#{filter}/ =~ filename
+ end
+ end
+ @files.keys.each do |name|
+ if @files[name].size > 1 then
+ data = Array.new
+ @files[name].each do |path|
+ filename = File.join(path,name)
+ # if not filter or filter.empty? or /#{filter}/ =~ filename then
+ if the_same(filter,filename) then
+ if FileTest.file?(filename) then
+ if delete then
+ data << FileData.new(1,filename,File.size(filename),File.mtime(filename))
+ begin
+ File.delete(filename) if delete
+ rescue
+ end
+ else
+ data << FileData.new(2,filename,File.size(filename),File.mtime(filename))
+ end
+ else
+ # data << FileData.new(3,filename)
+ end
+ end
+ end
+ if data.length > 1 then
+ if strict then
+ # if data.collect do |d| d.size end.uniq! then
+ # data.sort! do |a,b| b.size <=> a.size end
+ # data.each do |d| puts d.report end
+ # puts ''
+ # end
+ data.sort! do |a,b|
+ if a.size and b.size then
+ b.size <=> a.size
+ else
+ 0
+ end
+ end
+ bunch = Array.new
+ done = false
+ data.each do |d|
+ if bunch.size == 0 then
+ bunch << d
+ elsif bunch[0].size == d.size then
+ bunch << d
+ else
+ if bunch.size > 1 then
+ bunch.each do |b|
+ puts b.report
+ end
+ done = true
+ end
+ bunch = [d]
+ end
+ end
+ puts '' if done
+ else
+ case sort
+ when 'size' then data.sort! do |a,b| a.size <=> b.size end
+ when 'revsize' then data.sort! do |a,b| b.size <=> a.size end
+ when 'date' then data.sort! do |a,b| a.date <=> b.date end
+ when 'revdate' then data.sort! do |a,b| b.date <=> a.date end
+ end
+ data.each do |d| puts d.report end
+ puts ''
+ end
+ end
+ end
+ end
+ end
+
+end
+
+module KpseRunner
+
+ @@kpse = nil
+
+ def KpseRunner.kpsewhich(arg='')
+ options, arguments = split_args(arg)
+ unless @@kpse then
+ @@kpse = KPSEFAST.new
+ @@kpse.load_cnf
+ @@kpse.progname = options['progname'] || ''
+ @@kpse.engine = options['engine'] || ''
+ @@kpse.format = options['format'] || ''
+ @@kpse.expand_variables
+ @@kpse.load_lsr
+ else
+ @@kpse.progname = options['progname'] || ''
+ @@kpse.engine = options['engine'] || ''
+ @@kpse.format = options['format'] || ''
+ @@kpse.expand_variables
+ end
+ if option = options['expand-braces'] and not option.empty? then
+ @@kpse.expand_braces(option)
+ elsif option = options['expand-path'] and not option.empty? then
+ @@kpse.expand_path(option)
+ elsif option = options['expand-var'] and not option.empty? then
+ @@kpse.expand_var(option)
+ elsif option = options['show-path'] and not option.empty? then
+ @@kpse.show_path(option)
+ elsif option = options['var-value'] and not option.empty? then
+ @@kpse.expand_var(option)
+ elsif arguments.size > 0 then
+ files = Array.new
+ arguments.each do |option|
+ if file = @@kpse.find_file(option) and not file.empty? then
+ files << file
+ end
+ end
+ files.join("\n")
+ else
+ ''
+ end
+ end
+
+ def KpseRunner.kpsereset
+ @@kpse = nil
+ end
+
+ private
+
+ def KpseRunner.split_args(arg)
+ vars, args = Hash.new, Array.new
+ arg.gsub!(/([\"\'])(.*?)\1/o) do
+ $2.gsub(' ','<space/>')
+ end
+ arg = arg.split(/\s+/o)
+ arg.collect! do |a|
+ a.gsub('<space/>',' ')
+ end
+ arg.each do |a|
+ if a =~ /^(.*?)\=(.*?)$/o then
+ k, v = $1, $2
+ vars[k.sub(/^\-+/,'')] = v
+ else
+ args << a
+ end
+ end
+ # puts vars.inspect
+ # puts args.inspect
+ return vars, args
+ end
+
+end
+
+if false then
+
+ k = KPSEFAST.new # (root)
+ k.set_test_patterns
+ k.load_cnf
+ k.expand_variables
+ k.load_lsr
+
+ k.show_test_patterns
+ # puts k.list_variables
+ # puts k.list_expansions
+ # k.list_lsr
+ # puts k.expansion("$TEXMF")
+ # puts k.expanded_path("TEXINPUTS","context")
+
+ # k.progname, k.engine, k.format = 'context', 'pdfetex', 'tfm'
+ # k.scandisk = false # == must_exist
+ # k.expand_variables
+
+ # 10.times do |i| puts k.find_file('texnansi-lmr10.tfm') end
+
+ # puts "expand braces $TEXMF"
+ # puts k.expand_braces("$TEXMF")
+ # puts "expand path $TEXMF"
+ # puts k.expand_path("$TEXMF")
+ # puts "expand var $TEXMF"
+ # puts k.expand_var("$TEXMF")
+ # puts "expand path $TEXMF"
+ # puts k.show_path('tfm')
+ # puts "expand value $TEXINPUTS"
+ # puts k.var_value("$TEXINPUTS")
+ # puts "expand value $TEXINPUTS.context"
+ # puts k.var_value("$TEXINPUTS.context")
+
+ exit
+
+end
diff --git a/Master/texmf-dist/scripts/context/ruby/base/logger.rb b/Master/texmf-dist/scripts/context/ruby/base/logger.rb
new file mode 100644
index 00000000000..2526cdb0e25
--- /dev/null
+++ b/Master/texmf-dist/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/Master/texmf-dist/scripts/context/ruby/base/pdf.rb b/Master/texmf-dist/scripts/context/ruby/base/pdf.rb
new file mode 100644
index 00000000000..d8cbf9e0523
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/base/pdf.rb
@@ -0,0 +1,51 @@
+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
+
+# 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/Master/texmf-dist/scripts/context/ruby/base/state.rb b/Master/texmf-dist/scripts/context/ruby/base/state.rb
new file mode 100644
index 00000000000..f57231592a7
--- /dev/null
+++ b/Master/texmf-dist/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/Master/texmf-dist/scripts/context/ruby/base/switch.rb b/Master/texmf-dist/scripts/context/ruby/base/switch.rb
new file mode 100644
index 00000000000..64d518bd42f
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/base/switch.rb
@@ -0,0 +1,605 @@
+# module : base/switch
+# 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
+
+# we cannot use getoptlong because we want to be more
+# 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)
+ self =~ /\.#{suffix}$/i
+ end
+
+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
+
+ $stdout.sync = true
+
+ def initialize(commandline,logger,banner)
+ @commandline, @logger, @banner = commandline, logger, banner
+ @forcenewline, @versiondone = false, false
+ version if @commandline.option('version')
+ end
+
+ def reportlines(*str)
+ @logger.reportlines(str)
+ end
+
+ # only works in 1.8
+ #
+ # def 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
+ # 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
+ end
+
+ def logger
+ @logger
+ end
+
+ def version # just a bit of playing with defs
+ unless @versiondone then
+ report(@banner.join(' - '))
+ @forcenewline = true
+ @versiondone = true
+ end
+ end
+
+ def help
+ version # is nilled when already given
+ @commandline.helpkeys.each do |k|
+ if @commandline.help?(k) then
+ kstr = ('--'+k).ljust(@commandline.helplength+2)
+ message = @commandline.helptext(k)
+ message = '' if message == CommandLine::NOHELP
+ message = message.split(/\s*\n\s*/)
+ loop do
+ report("#{kstr} #{message.shift}")
+ kstr = ' '*kstr.length
+ break if message.length == 0
+ end
+ end
+ end
+ end
+
+ 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
+
+ def findfiles(suffix=nil)
+
+ if @commandline.arguments.length>1 then
+ return @commandline.arguments
+ else
+ pattern = @commandline.argument('first')
+ pattern = '*' if pattern.empty?
+ if suffix && ! pattern.match(/\..+$/o) then
+ suffix = '.' + suffix
+ pattern += suffix unless pattern =~ /#{suffix}$/
+ end
+ # not {} safe
+ pattern = '**/' + pattern if @commandline.option('recurse')
+ files = Dir[pattern]
+ if files && files.length>0 then
+ return files
+ else
+ pattern = @commandline.argument('first')
+ if FileTest.file?(pattern) then
+ return [pattern]
+ else
+ report("no files match pattern #{pattern}")
+ return nil
+ end
+ end
+ end
+
+ end
+
+ def globbed(pattern,recurse=false)
+
+ files = Array.new
+ pattern.split(' ').each do |p|
+ if recurse then
+ if p =~ /^(.*)(\/.*?)$/i then
+ p = $1 + '/**' + $2
+ else
+ p = '**/' + p
+ end
+ p.gsub!(/[\\\/]+/, '/')
+ end
+ files.push(Dir.glob(p))
+ end
+ files.flatten.sort do |a,b|
+ pathcompare(a,b)
+ end
+ end
+
+ def pathcompare(a,b)
+
+ aa, bb = a.split('/'), b.split('/')
+ if aa.length == bb.length then
+ aa.each_index do |i|
+ if aa[i]<bb[i] then
+ return -1
+ elsif aa[i]>bb[i] then
+ return +1
+ end
+ end
+ return 0
+ else
+ return aa.length <=> bb.length
+ end
+
+ end
+
+end
+
+class CommandLine
+
+ VALUE, FLAG = 1, 2
+ NOHELP = 'no arguments'
+
+ def initialize(prefix='-')
+
+ @registered = Array.new
+ @options = Hash.new
+ @unchecked = Hash.new
+ @arguments = Array.new
+ @original = ARGV.join(' ')
+ @helptext = Hash.new
+ @mandated = Hash.new
+ @provided = Hash.new
+ @prefix = prefix
+ @actions = Array.new
+
+ # The quotes in --switch="some value" get lost in ARGV, so we need to do some trickery here.
+
+ @original = ''
+ ARGV.each do |a|
+ aa = a.strip.gsub(/^([#{@prefix}]+\w+\=)([^\"].*?\s+.*[^\"])$/) do
+ $1 + "\"" + $2 + "\""
+ end
+ @original += if @original.empty? then '' else ' ' end + aa
+ end
+
+ end
+
+ 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
+ @options[option] = ''
+ else
+ @options[option] = default
+ end
+ @registered.push([option,shortcut,kind])
+ @mandated[option] = false
+ # @provided[option] = false
+ @helptext[option] = helptext
+ @actions.push(option) if action
+ end
+
+ def registerflag(option,default=false,helptext='')
+ if default.class == String then
+ register(option,'',FLAG,false,false,default)
+ else
+ register(option,'',FLAG,false,false,helptext)
+ end
+ end
+
+ def registervalue(option,default='',helptext='')
+ register(option,'',VALUE,default,false,helptext)
+ end
+
+ def registeraction(option,helptext='')
+ register(option,'',FLAG,false,true,helptext)
+ end
+
+ def registermandate(*option)
+ [*option].each do |o|
+ [o].each do |oo|
+ @mandated[oo] = true
+ end
+ end
+ end
+
+ def actions
+ a = @actions.delete_if do |t|
+ ! option(t)
+ end
+ if a && a.length>0 then
+ return a
+ else
+ return nil
+ end
+ end
+
+ def action
+ @actions.each do |t|
+ return t if option(t)
+ end
+ return nil
+ end
+
+ def forgotten
+ @mandated.keys.sort - @provided.keys.sort
+ end
+
+ def registerhelp(option,text='')
+ @helptext['unknown'] = if text.empty? then option else text end
+ end
+
+ def helpkeys(option='.*')
+ @helptext.keys.sort.grep(/#{option}/)
+ end
+
+ def helptext(option)
+ @helptext.fetch(option,'')
+ end
+
+ def help?(option)
+ @helptext[option] && ! @helptext[option].empty?
+ end
+
+ def helplength
+ n = 0
+ @helptext.keys.each do |h|
+ n = h.length if h.length>n
+ end
+ return n
+ end
+
+ def expand
+
+ # todo : '' or false, depending on type
+ # @options.clear
+ # @arguments.clear
+
+ dirtyvalue(@original).split(' ').each do |arg|
+ case arg
+ when /^[#{@prefix}][#{@prefix}](.+?)\=(.*?)$/ then locatedouble($1,$2)
+ when /^[#{@prefix}][#{@prefix}](.+?)$/ then locatedouble($1,false)
+ when /^[#{@prefix}](.)\=(.)$/ then locatesingle($1,$2)
+ when /^[#{@prefix}](.+?)$/ then locateseries($1,false)
+ when /^[\+\-]+/o then # do nothing
+ else
+ arguments.push(arg)
+ end
+ end
+
+ @options or @unchecked or @arguments
+
+ end
+
+ def extend (str)
+ @original = @original + ' ' + str
+ end
+
+ def replace (str)
+ @original = str
+ end
+
+ def show
+ # print "-- options --\n"
+ @options.keys.sort.each do |key|
+ print "option: #{key} -> #{@options[key]}\n"
+ end
+ # print "-- arguments --\n"
+ @arguments.each_index do |key|
+ print "argument: #{key} -> #{@arguments[key]}\n"
+ end
+ end
+
+ 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)
+ if n.class == String then
+ case n
+ when 'first' then argument(0)
+ when 'second' then argument(1)
+ when 'third' then argument(2)
+ else
+ argument(0)
+ end
+ elsif @arguments[n] then
+ @arguments[n]
+ else
+ ''
+ end
+ end
+
+ # a few local methods, cannot be defined nested (yet)
+
+ private
+
+ def dirtyvalue(value)
+ if value then
+ value.gsub(/([\"\'])(.*?)\1/) do
+ $2.gsub(/\s+/o, "\xFF")
+ end
+ else
+ ''
+ end
+ end
+
+ def cleanvalue(value)
+ if value then
+ # value.sub(/^([\"\'])(.*?)\1$/) { $2.gsub(/\xFF/o, ' ') }
+ value.gsub(/\xFF/o, ' ')
+ else
+ ''
+ end
+ end
+
+ def locatedouble(key, value)
+
+ foundkey, foundkind = nil, nil
+
+ @registered.each do |option, shortcut, kind|
+ if option == key then
+ foundkey, foundkind = option, kind
+ break
+ end
+ end
+ unless foundkey then
+ @registered.each do |option, shortcut, kind|
+ n = 0
+ if option =~ /^#{key}/i then
+ case n
+ when 0
+ foundkey, foundkind = option, kind
+ n = 1
+ when 1
+ # ambiguous matches, like --fix => --fixme --fixyou
+ foundkey, foundkind = nil, nil
+ break
+ end
+ end
+ end
+ end
+ if foundkey then
+ @provided[foundkey] = true
+ if foundkind == VALUE then
+ @options[foundkey] = cleanvalue(value)
+ else
+ @options[foundkey] = true
+ end
+ else
+ if value.class == FalseClass then
+ @unchecked[key] = true
+ else
+ @unchecked[key] = cleanvalue(value)
+ end
+ end
+
+ end
+
+ def locatesingle(key, value)
+
+ @registered.each do |option, shortcut, kind|
+ if shortcut == key then
+ @provided[option] = true
+ @options[option] = if kind == VALUE then '' else cleanvalue(value) end
+ break
+ end
+ end
+
+ end
+
+ def locateseries(series, value)
+
+ series.each do |key|
+ locatesingle(key,cleanvalue(value))
+ end
+
+ end
+
+ public
+
+ attr_reader :arguments, :options, :original, :unchecked
+
+end
+
+# options = CommandLine.new
+#
+# options.register("filename", "f", CommandLine::VALUE)
+# options.register("request" , "r", CommandLine::VALUE)
+# options.register("verbose" , "v", CommandLine::FLAG)
+#
+# options.expand
+# options.extend(str)
+# options.show
+#
+# c = CommandLine.new
+#
+# c.registervalue('aaaa')
+# c.registervalue('test')
+# c.registervalue('zzzz')
+#
+# c.registerhelp('aaaa','some aaaa to enter')
+# c.registerhelp('test','some text to enter')
+# c.registerhelp('zzzz','some zzzz to enter')
+#
+# c.registermandate('test')
+#
+# c.expand
+#
+# class CommandLine
+#
+# def showhelp (banner,*str)
+# if helpkeys(*str).length>0
+# print banner
+# helpkeys(*str).each do |h|
+# print helptext(h) + "\n"
+# end
+# true
+# else
+# false
+# end
+# end
+#
+# def showmandate(banner)
+# if forgotten.length>0
+# print banner
+# forgotten.each do |f|
+# print helptext(f) + "\n"
+# end
+# true
+# else
+# false
+# end
+# end
+#
+# end
+#
+# c.showhelp("you can provide:\n\n")
+# c.showmandate("you also need to provide:\n\n")
diff --git a/Master/texmf-dist/scripts/context/ruby/base/system.rb b/Master/texmf-dist/scripts/context/ruby/base/system.rb
new file mode 100644
index 00000000000..ed8c2756e2b
--- /dev/null
+++ b/Master/texmf-dist/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/Master/texmf-dist/scripts/context/ruby/base/tex.rb b/Master/texmf-dist/scripts/context/ruby/base/tex.rb
new file mode 100644
index 00000000000..2cc9d25422e
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/base/tex.rb
@@ -0,0 +1,1495 @@
+# 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
+
+# report ?
+
+require 'base/variables'
+require 'base/kpse'
+require 'base/system'
+require 'base/state'
+require 'base/pdf'
+require 'base/file'
+require 'base/ctx'
+
+class String
+
+ def standard?
+ begin
+ self == 'standard'
+ rescue
+ false
+ end
+ end
+
+end
+
+class Array
+
+ def standard?
+ begin
+ self.include?('standard')
+ rescue
+ false
+ end
+ end
+
+end
+
+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
+ @@texmakestr = Hash.new
+ @@texprocstr = Hash.new
+ @@mpsmakestr = Hash.new
+ @@mpsprocstr = Hash.new
+
+ @@texmethods = Hash.new
+ @@mpsmethods = 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
+
+ ['latex'] .each do |f| @@texformats[f] = 'latex.ltx' 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
+
+ ['plain','default','standard','mptopdf'] .each do |f| @@texmethods[f] = 'plain' end
+ ['cont-en','cont-nl','cont-de','cont-it',
+ 'cont-cz','cont-ro','cont-uk'] .each do |f| @@texmethods[f] = 'context' end
+ ['latex'] .each do |f| @@texmethods[f] = 'latex' end
+
+ ['plain','default','standard'] .each do |f| @@mpsmethods[f] = 'plain' end
+ ['metafun'] .each do |f| @@mpsmethods[f] = 'metafun' end
+
+ @@texmakestr['plain'] = "\\dump"
+ @@mpsmakestr['plain'] = "\\dump"
+
+ ['cont-en','cont-nl','cont-de','cont-it',
+ 'cont-cz','cont-ro','cont-uk'] .each do |f| @@texprocstr[f] = "\\emergencyend" end
+
+ @@runoptions['xetex'] = ['--no-pdf']
+
+ @@booleanvars = [
+ 'batchmode', 'nonstopmode', 'fast', 'fastdisabled', 'silentmode', 'final',
+ 'paranoid', 'notparanoid', 'nobanner', 'once', 'allpatterns',
+ 'nompmode', 'nomprun', 'automprun',
+ 'nomapfiles', 'local',
+ 'arrange', 'noarrange',
+ 'forcexml', 'foxet',
+ 'mpyforce', 'forcempy',
+ 'forcetexutil', 'texutil',
+ 'globalfile', 'autopath',
+ 'purge', 'purgeall', 'autopdf', 'simplerun', 'verbose',
+ 'nooptionfile'
+ ]
+ @@stringvars = [
+ 'modefile', 'result', 'suffix', 'response', 'path',
+ 'filters', 'usemodules', 'environments', 'separation', 'setuppath',
+ 'arguments', 'input', 'output', 'randomseed', 'modes', 'filename',
+ 'modefile', 'ctxfile'
+ ]
+ @@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=nil)
+ if @logger = logger then
+ def report(str='')
+ @logger.report(str)
+ end
+ else
+ def report(str='')
+ puts(str)
+ end
+ end
+ @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') # replaced by tex/mpsengine
+ setvariable('backend', 'pdftex')
+ setvariable('runs', '8')
+ setvariable('randomseed', rand(1440).to_s)
+ # files
+ setvariable('files', [])
+ # defaults
+ setvariable('texengine', 'standard')
+ setvariable('mpsengine', 'standard')
+ setvariable('backend', 'standard')
+ 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 backends() @@backends.keys.sort end
+
+ def texengines() @@texengines.keys.sort end
+ def mpsengines() @@mpsengines.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 texmakeextras(format) @@texmakestr[format] || '' end
+ def mpsmakeextras(format) @@mpsmakestr[format] || '' end
+ def texprocextras(format) @@texprocstr[format] || '' end
+ def mpsprocextras(format) @@mpsprocstr[format] || '' end
+
+ def texmethod(format) @@texmethods[str] || @@texmethods['standard'] end
+ def mpsmethod(format) @@mpsmethods[str] || @@mpsmethods['standard'] 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)
+ begin
+ f = File.open(name,'w')
+ rescue
+ report("file '#{File.expand_path(name)}' cannot be opened for writing")
+ return nil
+ else
+ cleanuplater(name) if f
+ return f
+ end
+ 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 validtexmethod(str) [validsomething(str,@@texmethods)].flatten.first end
+ def validmpsmethod(str) [validsomething(str,@@mpsmethods)].flatten.first 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() # should go to kpse and kpse should become texenv
+ if Kpse.miktex? then
+ "-initialize"
+ else
+ "--ini"
+ end
+ end
+ def tcxflag(file="natural.tcx")
+ if Kpse.miktex? then
+ "-tcx=#{file}"
+ else
+ "--translate-file=#{file}"
+ end
+ 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
+ if getvariable('fast') then
+ report('using existing database')
+ else
+ report('updating file database')
+ Kpse.update
+ end
+ # 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 = if getvariable('local') then '.' else Kpse.formatpath(texengine,true) end
+ # 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 |texformat|
+ report("generating tex format #{texformat}")
+ command = [quoted(texengine),prognameflag(progname),iniflag,tcxflag,prefixed(texformat,texengine),texmakeextras(texformat)].join(' ')
+ report(command) if getvariable('verbose')
+ system(command)
+ end
+ else
+ texformatpath = ''
+ end
+ # generate mps formats
+ if mpsformats && mpsengine && (progname = validprogname(getvariable('progname'),mpsengine)) then
+ report("using mp engine #{mpsengine}")
+ mpsformatpath = if getvariable('local') then '.' else Kpse.formatpath(mpsengine,false) end
+ report("using mps format path #{mpsformatpath}")
+ begin
+ Dir.chdir(mpsformatpath)
+ rescue
+ end
+ mpsformats.each do |mpsformat|
+ report("generating mps format #{mpsformat}")
+ command = [quoted(mpsengine),prognameflag(progname),iniflag,tcxflag,mpsformat,mpsmakeextras(mpsformat)].join(' ')
+ report(command) if getvariable('verbose')
+ system(command)
+ 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('start of analysis')
+ results = Array.new
+ ['texexec','texutil','ctxtools'].each do |program|
+ result = `texmfstart #{program} --help`
+ result.sub!(/.*?(#{program}[^\n]+)\n.*/mi) do $1 end
+ results.push("#{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\-/,'')
+ results.push('')
+ results.push("testing interface #{interface}")
+ flags = ['--process','--batch','--once',"--interface=#{interface}",engineflag]
+ # result = Kpse.pipescript('newtexexec',tempfilename,flags)
+ result = runtexexec([tempfilename], flags, 1)
+ if FileTest.file?("#{@@temprunfile}.log") then
+ logdata = IO.read("#{@@temprunfile}.log")
+ if logdata =~ /^\s*This is (.*?)[\s\,]+(.*?)$/mois then
+ if validtexengine($1.downcase) then
+ results.push("#{$1} #{$2.gsub(/\(format.*$/,'')}".strip)
+ end
+ end
+ if logdata =~ /^\s*(ConTeXt)\s+(.*int:\s+[a-z]+.*?)\s*$/mois then
+ results.push("#{$1} #{$2}".gsub(/\s+/,' ').strip)
+ end
+ else
+ results.push("format #{format} does not work")
+ end
+ when /metafun/ then
+ # todo
+ when /mptopdf/ then
+ # todo
+ end
+ else
+ results.push("error in creating #{tempfilename('tex')}")
+ end
+ end
+ cleanuptemprunfiles
+ end
+ end
+ report('end of analysis')
+ report
+ results.each do |line|
+ report(line)
+ 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'],
+ ['translate','tcxfilter'],
+ ['tcx','tcxfilter'],
+ ['output','backend'],
+ ['mode','mode'],
+ ['ctx','ctxfile'],
+ ['version','contextversion'],
+ ['format','texformat'],
+ ['interface','texformat']
+ ]
+
+ def scantexpreamble(filename)
+ begin
+ if FileTest.file?(filename) and tex = File.open(filename) then
+ while str = tex.gets and str.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
+ rescue
+ # well, let's not worry too much
+ end
+ end
+
+ def scantexcontent(filename)
+ if FileTest.file?(filename) and tex = File.open(filename) then
+ while str = tex.gets do
+ case str.chomp
+ 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 #{rname}")
+ ['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.file?(File.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(rawname,forcexml=false)
+ if tmp = File.open(File.suffixed(rawname,'run'),'w') then
+ tmp << "\\starttext\n"
+ if forcexml then
+ if FileTest.file?(rawname) && (xml = File.open(rawname)) then
+ xml.each do |line|
+ case line
+ when /<\?context\-directive\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*?)\s*\?>/o then
+ category, key, value, rest = $1, $2, $3, $4
+ case category
+ when 'job' then
+ case key
+ when 'control' then
+ setvariable(value,if rest.empty? then true else rest end)
+ when 'mode', 'modes' then
+ tmp << "\\enablemode[#{value}]\n"
+ when 'stylefile', 'environment' then
+ tmp << "\\environment #{value}\n"
+ when 'module' then
+ tmp << "\\usemodule[#{value}]\n"
+ when 'interface' then
+ contextinterface = value
+ end
+ end
+ when /<[a-z]+/io then # beware of order, first pi test
+ break
+ end
+ end
+ xml.close
+ end
+ tmp << "\\processXMLfilegrouped{#{rawname}}\n"
+ else
+ tmp << "\\processfile{#{rawname}}\n"
+ end
+ tmp << "\\stoptext\n"
+ tmp.close
+ return "run"
+ else
+ return File.splitname(rawname)[1]
+ end
+ 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}'")
+ processfile
+ 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 deleteoptionfile(rawname)
+ begin
+ File.delete(File.suffixed(rawname,'top'))
+ rescue
+ end
+ end
+
+ def makeoptionfile(rawname, jobname, jobsuffix, finalrun, fastdisabled, kindofrun)
+ # jobsuffix = orisuffix
+ if topname = File.suffixed(rawname,'top') and opt = File.open(topname,'w') then
+ # local handies
+ opt << "\% #{topname}\n"
+ opt << "\\unprotect\n"
+ opt << "\\setupsystem[\\c!n=#{kindofrun}]\n"
+ opt << "\\def\\MPOSTformatswitch\{#{prognameflag('metafun')} #{formatflag('mpost')}=\}\n"
+ 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=#{jobname}.#{str}]\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('fast') && ! getvariable('fastdisabled') then
+ opt << "\\fastmode\n"
+ end
+ if getvariable('silentmode') 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=#{rawname}]\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(',').uniq.each do |f| opt << "\\useXMLfilter[#{f}]\n" end ; rescue ; end
+ begin getvariable('usemodules' ).split(',').uniq.each do |m| opt << "\\usemodule[#{m}]\n" end ; rescue ; end
+ begin getvariable('environments').split(',').uniq.each do |e| opt << "\\environment #{e}\n" end ; rescue ; end
+ # this will become:
+ # begin getvariable('environments').split(',').uniq.each do |e| opt << "\\useenvironment[#{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'
+ elsif getvariable('notparanoid') then
+ ENV['SHELL_ESCAPE'] = ENV['SHELL_ESCAPE'] || 't'
+ ENV['OPENOUT_ANY'] = ENV['OPENOUT_ANY'] || 'a'
+ ENV['OPENIN_ANY'] = ENV['OPENIN_ANY'] || 'a'
+ end
+ if ENV['OPENIN_ANY'] && (ENV['OPENIN_ANY'] == 'p') then # first test redundant
+ 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,texprocextras(texformat)].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,mpsprocextras(mpsformat)].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 ! mpjobname.empty? and 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')
+ options.push("--output=ps")
+ return runtexexec(mpfile,options,2)
+ end
+ end
+ return false
+ end
+
+ def runtexutil(filename=[], options=['--ref','--ij','--high'], old=false)
+ filename.each do |fname|
+ if old then
+ Kpse.runscript('texutil',fname,options)
+ else
+ begin
+ logger = Logger.new('TeXUtil')
+ if tu = TeXUtil::Converter.new(logger) and tu.loaded(fname) then
+ tu.saved if tu.processed
+ end
+ rescue
+ Kpse.runscript('texutil',fname,options)
+ end
+ end
+ end
+ end
+
+ # 1=tex 2=mptex 3=mpxtex
+
+ def runtexexec(filename=[], options=[], mode=nil)
+ begin
+ if mode and job = TEX.new(@logger) then
+ options.each do |option|
+ if option=~ /^\-*(.*?)\=(.*)$/o then
+ job.setvariable($1,$2)
+ else
+ job.setvariable(option,true)
+ end
+ end
+ job.setvariable("files",filename)
+ case mode
+ when 1 then job.processtex
+ when 2 then job.processmptex
+ when 3 then job.processmpxtex
+ end
+ job.inspect && Kpse.inspect if getvariable('verbose')
+ return true
+ else
+ Kpse.runscript('texexec',filename,options)
+ end
+ rescue
+ Kpse.runscript('texexec',filename,options)
+ end
+ end
+
+ def fixbackendvars(backend)
+ ENV['backend'] = backend ;
+ ENV['progname'] = backend unless validtexengine(backend)
+ ENV['TEXFONTMAPS'] = ".;\$TEXMF/fonts/map/{#{backend},pdftex,dvips,}//"
+ end
+
+ def runbackend(rawname)
+ case validbackend(getvariable('backend'))
+ when 'dvipdfmx' then
+ fixbackendvars('dvipdfm')
+ system("dvipdfmx -d 4 #{File.unsuffixed(rawname)}")
+ when 'xetex' then
+ fixbackendvars('xetex')
+ system("xdv2pdf #{File.suffixed(jrawname,'xdv')}")
+ when 'dvips' then
+ fixbackendvars('dvips')
+ mapfiles = ''
+ begin
+ if tuifile = File.suffixed(rawname,'tui') and FileTest.file?(tuifile) then
+ IO.read(tuifile).scan(/^c \\usedmapfile\{.\}\{(.*?)\}\s*$/o) do
+ mapfiles += "-u +#{$1} " ;
+ end
+ end
+ rescue
+ mapfiles = ''
+ end
+ system("dvips #{mapfiles} #{File.unsuffixed(rawname)}")
+ when 'pdftex' then
+ # no need for postprocessing
+ else
+ report("no postprocessing needed")
+ end
+ end
+
+ def processfile
+
+ takeprecautions
+
+ rawname = getvariable('filename')
+
+ jobname = getvariable('filename')
+ suffix = getvariable('suffix')
+ result = getvariable('result')
+
+ runonce = getvariable('once')
+ finalrun = getvariable('final') || (getvariable('arrange') && ! getvariable('noarrange'))
+ globalfile = getvariable('globalfile')
+
+ 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 ?
+
+ setvariable('nomprun',true) if orisuffix == 'mpx' # else cylic run
+
+ PDFview.closeall if getvariable('autopdf')
+
+ forcexml = jobsuffix.match(/^(xml|fo|fox|rlg|exa)$/io) # nil or match
+
+ dummyfile = false
+
+ # fuzzy code snippet: (we kunnen kpse: prefix gebruiken)
+
+ unless FileTest.file?(File.suffixed(jobname,jobsuffix)) then
+ if FileTest.file?(rawname + '.tex') then
+ jobname = rawname.dup
+ jobsuffix = 'tex'
+ end
+ end
+
+ # we can have funny names, like 2005.10.10 (given without suffix)
+
+ rawname = jobname + '.' + jobsuffix
+
+ unless FileTest.file?(rawname) then
+ inppath.split(',').each do |ip|
+ break if dummyfile = FileTest.file?(File.join(ip,rawname))
+ end
+ end
+
+ # preprocess files
+
+ ctx = CtxRunner.new(rawname,@logger)
+ if getvariable('ctxfile').empty? then
+ ctx.manipulate(File.suffixed(rawname,'ctx'),'jobname.ctx')
+ else
+ ctx.manipulate(File.suffixed(getvariable('ctxfile'),'ctx'))
+ end
+ ctx.savelog(File.suffixed(rawname,'ctl'))
+
+ envs = ctx.environments
+ mods = ctx.modules
+
+ # merge environment and module specs
+
+ envs << getvariable('environments') unless getvariable('environments').empty?
+ mods << getvariable('modules') unless getvariable('modules') .empty?
+
+ envs = envs.uniq.join(',')
+ mods = mods.uniq.join(',')
+
+ report("using environments #{envs}") if envs.length > 0
+ report("using modules #{mods}") if mods.length > 0
+
+ setvariable('environments', envs)
+ setvariable('modules', mods)
+
+ # end of preprocessing and merging
+
+ jobsuffix = makestubfile(rawname,forcexml) if dummyfile || forcexml
+
+ if globalfile || FileTest.file?(rawname) then
+
+ if not dummyfile and not globalfile then
+ scantexpreamble(rawname)
+ scantexcontent(rawname) if getvariable('texformats').standard?
+ end
+
+ result = File.suffixed(rawname,suffix) unless suffix.empty?
+
+ pushresult(rawname,result)
+
+ method = validtexmethod(validtexformat(getvariable('texformats')))
+
+ report("tex processing method: #{method}")
+
+ case method
+
+ when 'context' then
+ if getvariable('simplerun') || runonce then
+ makeoptionfile(rawname,jobname,orisuffix,true,true,3) unless getvariable('nooptionfile')
+ ok = runtex(rawname)
+ if ok then
+ ok = runtexutil(rawname) if getvariable('texutil') || getvariable('forcetexutil')
+ runbackend(rawname)
+ popresult(rawname,result)
+ end
+ File.silentdelete(File.suffixed(rawname,'tmp'))
+ File.silentrename(File.suffixed(rawname,'top'),File.suffixed(rawname,'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(rawname,s))
+ end
+ if getvariable('automprun') then # check this
+ ['mprun','mpgraph'].each do |s|
+ state.register(File.suffixed(rawname,s,'mp'),'randomseed')
+ end
+ end
+ while ! stoprunning && (texruns < nofruns) && ok do
+ texruns += 1
+ report("TeX run #{texruns}")
+ if texruns == 1 then
+ makeoptionfile(rawname,jobname,orisuffix,false,false,1) unless getvariable('nooptionfile')
+ else
+ makeoptionfile(rawname,jobname,orisuffix,false,false,2) unless getvariable('nooptionfile')
+ end
+ ok = runtex(File.suffixed(rawname,jobsuffix))
+ if ok && (nofruns > 1) then
+ unless getvariable('nompmode') then
+ mprundone = runtexmpjob(rawname, "mpgraph")
+ mprundone = runtexmpjob(rawname, "mprun")
+ end
+ ok = runtexutil(rawname)
+ state.update
+ stoprunning = state.stable?
+ end
+ end
+ ok = runtexutil(rawname) if (nofruns == 1) && getvariable('texutil')
+ if ok && finalrun && (nofruns > 1) then
+ makeoptionfile(rawname,jobname,orisuffix,true,finalrun,4) unless getvariable('nooptionfile')
+ report("final TeX run #{texruns}")
+ ok = runtex(File.suffixed(rawname,jobsuffix))
+ end
+ ['tmp','top'].each do |s| # previous tuo file / runtime option file
+ File.silentdelete(File.suffixed(rawname,s))
+ end
+ File.silentrename(File.suffixed(rawname,'top'),File.suffixed(rawname,'tmp'))
+ if ok then
+ runbackend(rawname)
+ popresult(rawname,result)
+ end
+ end
+
+ Kpse.runscript('ctxtools',rawname,'--purge') if getvariable('purge')
+ Kpse.runscript('ctxtools',rawname,'--purgeall') if getvariable('purgeall')
+
+ when 'latex' then
+
+ ok = runtex(rawname)
+
+ else
+
+ ok = runtex(rawname)
+
+ end
+
+ if (dummyfile or forcexml) and FileTest.file?(rawname) then
+ begin
+ File.delete(File.suffixed(rawname,'run'))
+ rescue
+ report("unable to delete stub file")
+ end
+ end
+
+ if ok and getvariable('autopdf') then
+ PDFview.open(File.suffixed(if result.empty? then rawname else result end,'pdf'))
+ 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
diff --git a/Master/texmf-dist/scripts/context/ruby/base/texutil.rb b/Master/texmf-dist/scripts/context/ruby/base/texutil.rb
new file mode 100644
index 00000000000..c279bcc97a6
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/base/texutil.rb
@@ -0,0 +1,872 @@
+require "base/file"
+require "base/logger"
+
+class String
+
+ # real dirty, but inspect does a pretty good escaping but
+ # unfortunately puts quotes around the string so we need
+ # to strip these
+
+ # def escaped
+ # self.inspect[1,self.inspect.size-2]
+ # end
+
+ def escaped
+ str = self.inspect ; str[1,str.size-2]
+ end
+
+ def splitdata
+ if self =~ /^\s*(.*?)\s*\{(.*)\}\s*$/o then
+ first, second = $1, $2
+ if first.empty? then
+ [second.split(/\} \{/o)].flatten
+ else
+ [first.split(/\s+/o)] + [second.split(/\} \{/o)]
+ end
+ else
+ []
+ end
+ end
+
+end
+
+class Logger
+ def banner(str)
+ report(str)
+ return "%\n% #{str}\n%\n"
+ end
+end
+
+class TeXUtil
+
+ class Plugin
+
+ # we need to reset module data for each run; persistent data is
+ # possible, just don't reinitialize the data structures that need
+ # to be persistent; we reset afterwards becausethen we know what
+ # plugins are defined
+
+ def initialize(logger)
+ @plugins = Array.new
+ @logger = logger
+ end
+
+ def reset(name)
+ if @plugins.include?(name) then
+ begin
+ eval("#{name}").reset(@logger)
+ rescue Exception
+ @logger.report("fatal error in resetting plugin")
+ end
+ else
+ @logger.report("no plugin #{name}")
+ end
+ end
+
+ def resets
+ @plugins.each do |p|
+ reset(p)
+ end
+ end
+
+ def register(name, file=nil) # maybe also priority
+ if file then
+ begin
+ require("#{file.downcase.sub(/\.rb$/,'')}.rb")
+ rescue Exception
+ @logger.report("no plugin file #{file} for #{name}")
+ else
+ @plugins.push(name)
+ end
+ else
+ @plugins.push(name)
+ end
+ return self
+ end
+
+ def reader(name, data=[])
+ if @plugins.include?(name) then
+ begin
+ eval("#{name}").reader(@logger,data.flatten)
+ rescue Exception
+ @logger.report("fatal error in plugin reader #{name} (#{$!})")
+ end
+ else
+ @logger.report("no plugin #{name}")
+ end
+ end
+
+ def readers(data=[])
+ @plugins.each do |p|
+ reader(p,data.flatten)
+ end
+ end
+
+ def writers(handle)
+ @plugins.each do |p|
+ begin
+ eval("#{p}").writer(@logger,handle)
+ rescue Exception
+ @logger.report("fatal error in plugin writer #{p} (#{$!})")
+ end
+ end
+ end
+
+ def processors
+ @plugins.each do |p|
+ begin
+ eval("#{p}").processor(@logger)
+ rescue Exception
+ @logger.report("fatal error in plugin processor #{p} (#{$!})")
+ end
+ end
+ end
+
+ end
+
+ class Sorter
+
+ def initialize(max=12)
+ @rep, @map, @exp, @div = Hash.new, Hash.new, Hash.new, Hash.new
+ @max = max
+ @rexa, @rexb = nil, nil
+ end
+
+ def replacer(from,to='') # and expand
+ @max = [@max,to.length+1].max if to
+ @rep[from.escaped] = to || ''
+ end
+
+ # sorter.reducer('ch', 'c')
+ # sorter.reducer('ij', 'y')
+
+ def reducer(from,to='')
+ @max = [@max,to.length+1].max if to
+ @map[from] = to || ''
+ end
+
+ # sorter.expander('aeligature', 'ae')
+ # sorter.expander('ijligature', 'y')
+
+ def expander(from,to=nil)
+ from, to = converted(from), converted(to)
+ @max = [@max,to.length+1].max if to
+ @exp[from] = to || from || ''
+ end
+
+ def division(from,to=nil)
+ from, to = converted(from), converted(to)
+ @max = [@max,to.length+1].max if to
+ @div[from] = to || from || ''
+ end
+
+ # shortcut("\\ab\\cd\\e\\f", 'iacute')
+ # shortcut("\\\'\\i", 'iacute')
+ # shortcut("\\\'i", 'iacute')
+ # shortcut("\\\"e", 'ediaeresis')
+ # shortcut("\\\'o", 'oacute')
+
+ def shortcut(from,to)
+ replacer(from,to)
+ expander(to)
+ end
+
+ def prepare
+ if @rep.size > 0 then
+ @rexa = /(#{@rep.keys.join('|')})/ # o
+ else
+ @rexa = nil
+ end
+ if @map.size > 0 then
+ # watch out, order of match matters
+ @rexb = /(\\[a-zA-Z]+|#{@map.keys.join('|')}|.)\s*/ # o
+ else
+ @rexb = /(\\[a-zA-Z]+|.)\s*/o
+ end
+ end
+
+ def remap(str)
+ s = str.dup
+ s.gsub!(/(\d+)/o) do
+ $1.rjust(10,'a') # rest is b .. k
+ end
+ if @rexa then
+ s.gsub!(@rexa) do
+ @rep[$1.escaped]
+ end
+ end
+ if @rexb then
+ s.gsub!(@rexb) do
+ token = $1.sub(/\\/o, '')
+ if @exp.key?(token) then
+ @exp[token].ljust(@max,' ')
+ elsif @map.key?(token) then
+ @map[token].ljust(@max,' ')
+ else
+ ''
+ end
+ end
+ end
+ s
+ end
+
+ def preset(shortcuts=[],expansions=[],reductions=[],divisions=[])
+ # maybe we should move this to sort-def.tex
+ 'a'.upto('z') do |c| expander(c) ; division(c) end
+ expander('1','b') ; expander('2','c') ; expander('3','e') ; expander('4','f')
+ expander('5','g') ; expander('6','h') ; expander('7','i') ; expander('8','i')
+ expander('9','j') ; expander('0','a') ; expander('-','-') ;
+ # end potential move
+ shortcuts.each do |s| shortcut(s[0],s[1]) end
+ expansions.each do |e| expander(e[0],e[1]) end
+ reductions.each do |r| reducer(r[0],r[1]) end
+ divisions.each do |d| division(d[0],d[1]) end
+ end
+
+ def simplify(str)
+ s = str.dup
+ # ^^
+ # s.gsub!(/\^\^([a-f0-9][a-f0-9])/o, $1.hex.chr)
+ # \- ||
+ s.gsub!(/(\\\-|\|\|)/o) do '-' end
+ # {}
+ s.gsub!(/\{\}/o) do '' end
+ # <*..> (internal xml entity)
+ s.gsub!(/<\*(.*?)>/o) do $1 end
+ # entities
+ s.gsub!(/\\getXMLentity\s*\{(.*?)\}/o) do $1 end
+ # elements
+ s.gsub!(/\<.*?>/o) do '' end
+ # what to do with xml and utf-8
+ # \"e etc
+ # unknown \cs
+ s.gsub!(/\\[a-z][a-z]+\s*\{(.*?)\}/o) do $1 end
+ return s
+ end
+
+ def getdivision(str)
+ @div[str] || str
+ end
+
+ def division?(str)
+ @div.key?(str)
+ end
+
+ private
+
+ def converted(str)
+ if str then
+ str.gsub(/([\+\-]*\d+)/o) do
+ n = $1.to_i
+ if n > 0 then
+ 'z'*n
+ elsif n < 0 then
+ '-'*(-n) # '-' precedes 'a'
+ else
+ ''
+ end
+ end
+ else
+ nil
+ end
+ end
+
+ end
+
+ class Plugin
+
+ module MyFiles
+
+ @@files = Hash.new
+
+ def MyFiles::reset(logger)
+ @@files = Hash.new
+ end
+
+ def MyFiles::reader(logger,data)
+ case data[0]
+ when 'b', 'e' then
+ if @@files.key?(data[1]) then
+ @@files[data[1]] += 1
+ else
+ @@files[data[1]] = 1
+ end
+ end
+ end
+
+ def MyFiles::writer(logger,handle)
+ handle << logger.banner("loaded files: #{@@files.size}")
+ @@files.keys.sort.each do |k|
+ handle << "% > #{k} #{@@files[k]/2}\n"
+ end
+ end
+
+ def MyFiles::processor(logger)
+ @@files.keys.sort.each do |k|
+ unless (@@files[k] % 2) == 0 then
+ logger.report("check loading of file #{k}, begin/end problem")
+ end
+ end
+ end
+
+ end
+
+ end
+
+ class Plugin
+
+ module MyCommands
+
+ @@commands = []
+
+ def MyCommands::reset(logger)
+ @@commands = []
+ end
+
+ def MyCommands::reader(logger,data)
+ @@commands.push(data.shift+data.collect do |d| "\{#{d}\}" end.join)
+ end
+
+ def MyCommands::writer(logger,handle)
+ handle << logger.banner("commands: #{@@commands.size}")
+ @@commands.each do |c|
+ handle << "#{c}\n"
+ end
+ end
+
+ def MyCommands::processor(logger)
+ end
+
+ end
+
+ end
+
+ class Plugin
+
+ module MyExtras
+
+ @@programs = []
+
+ def MyExtras::reset(logger)
+ @@programs = []
+ end
+
+ def MyExtras::reader(logger,data)
+ case data[0]
+ when 'p' then
+ @@programs.push(data[1]) if data[0]
+ end
+ end
+
+ def MyExtras::writer(logger,handle)
+ handle << logger.banner("programs: #{@@programs.size}")
+ @@programs.each do |p|
+ handle << "% #{p} (#{@@programs[p.to_i]})\n"
+ end
+ end
+
+ def MyExtras::processor(logger)
+ @@programs.each do |p|
+ cmd = "texmfstart #{@@programs[p.to_i]}"
+ logger.report("running #{cmd}")
+ system(cmd)
+ end
+ end
+
+ end
+
+ end
+
+ class Plugin
+
+ module MySynonyms
+
+ class Synonym
+
+ @@debug = false
+ @@debug = true
+
+ def initialize(t, c, k, d)
+ @type, @command, @key, @sortkey, @data = t, c, k, k, d
+ end
+
+ attr_reader :type, :command, :key, :data
+ attr_reader :sortkey
+ attr_writer :sortkey
+
+ def build(sorter)
+ @sortkey = sorter.remap(sorter.simplify(@key.downcase))
+ if @sortkey.empty? then
+ @sortkey = sorter.remap(@command.downcase)
+ end
+ end
+
+ def <=> (other)
+ @sortkey <=> other.sortkey
+ end
+
+ def Synonym.flush(list,handle)
+ if @@debug then
+ list.each do |entry|
+ handle << "% [#{entry.sortkey}]\n"
+ end
+ end
+ list.each do |entry|
+ handle << "\\synonymentry{#{entry.type}}{#{entry.command}}{#{entry.key}}{#{entry.data}}\n"
+ end
+ end
+
+ end
+
+ @@synonyms = Hash.new
+
+ def MySynonyms::reset(logger)
+ @@synonyms = Hash.new
+ end
+
+ def MySynonyms::reader(logger,data)
+ if data[0] == 'e' then
+ @@synonyms[data[1]] = Array.new unless @@synonyms.key?(data[1])
+ @@synonyms[data[1]].push(Synonym.new(data[1],data[2],data[3],data[4]))
+ end
+ end
+
+ def MySynonyms::writer(logger,handle)
+ if @@synonyms.size > 0 then
+ @@synonyms.keys.sort.each do |s|
+ handle << logger.banner("synonyms: #{s} #{@@synonyms[s].size}")
+ Synonym.flush(@@synonyms[s],handle)
+ end
+ end
+ end
+
+ def MySynonyms::processor(logger)
+ sorter = Sorter.new
+ sorter.preset(eval("MyKeys").shortcuts,eval("MyKeys").expansions,eval("MyKeys").reductions,eval("MyKeys").divisions)
+ sorter.prepare
+ @@synonyms.keys.each do |s|
+ @@synonyms[s].each_index do |i|
+ @@synonyms[s][i].build(sorter)
+ end
+ @@synonyms[s] = @@synonyms[s].sort
+ end
+ end
+
+ end
+
+ end
+
+ class Plugin
+
+ module MyRegisters
+
+ class Register
+
+ @@debug = false
+ @@debug = true
+
+ @@howto = /^(.*?)\:\:(.*)$/o
+ @@split = ' && '
+
+ def initialize(state, t, l, k, e, s, p, r)
+ @state, @type, @location, @key, @entry, @seetoo, @page, @realpage = state, t, l, k, e, s, p, r
+ if @key =~ @@howto then @pagehowto, @key = $1, $2 else @pagehowto = '' end
+ if @entry =~ @@howto then @texthowto, @entry = $1, $2 else @texthowto = '' end
+ @key = @entry.dup if @key.empty?
+ @sortkey = @key.dup
+ @nofentries, @nofpages = 0, 0
+ end
+
+ attr_reader :state, :type, :location, :key, :entry, :seetoo, :page, :realpage, :texthowto, :pagehowto
+ attr_reader :sortkey
+ attr_writer :sortkey
+
+ def build(sorter)
+ @entry, @key = [@entry, @key].collect do |target|
+ # +a+b+c &a&b&c a+b+c a&b&c
+ case target[0,1]
+ when '&' then target = target.sub(/^./o,'').gsub(/([^\\])\&/o) do "#{$1}#{@@split}" end
+ when '+' then target = target.sub(/^./o,'').gsub(/([^\\])\+/o) do "#{$1}#{@@split}" end
+ else target = target .gsub(/([^\\])[\&\+]/o) do "#{$1}#{@@split}" end
+ end
+ # {a}{b}{c}
+ # if target =~ /^\{(.*)\}$/o then
+ # $1.split(/\} \{/o).join(@@split) # space between } { is mandate
+ # else
+ target
+ # end
+ end
+ @sortkey = sorter.simplify(@key)
+ @sortkey = @sortkey.split(@@split).collect do |c| sorter.remap(c) end.join(@@split)
+ # if ($Key eq "") { $Key = SanitizedString($Entry) }
+ # if ($ProcessHigh){ $Key = HighConverted($Key) }
+ @sortkey = [
+ @sortkey.downcase,
+ @sortkey,
+ @texthowto.ljust(10,' '),
+ @state,
+ @realpage.rjust(6,' '),
+ @pagehowto
+ ].join(@@split)
+ end
+
+ def <=> (other)
+ @sortkey <=> other.sortkey
+ end
+
+ # more module like
+
+ @@savedhowto, @@savedfrom, @@savedto, @@savedentry = '', '', '', '', ''
+ @@collapse = false
+
+ def Register.flushsavedline(handle)
+ if @@collapse && ! @@savedfrom.empty? then
+ if ! @@savedto.empty? then
+ handle << "\\registerfrom#{@@savedfrom}"
+ handle << "\\registerto#{@@savedto}"
+ else
+ handle << "\\registerpage#{@@savedfrom}"
+ end
+ end
+ @@savedhowto, @@savedfrom, @@savedto, @@savedentry = '', '', '', ''
+ end
+
+ def Register.flush(list,handle,sorter)
+ # a bit messy, quite old mechanism, maybe some day ...
+ # alphaclass can go, now flushed per class
+ if list.size > 0 then
+ @nofentries, @nofpages = 0, 0
+ current, previous, howto = Array.new, Array.new, Array.new
+ lastpage, lastrealpage = '', ''
+ alphaclass, alpha = '', ''
+ @@savedhowto, @@savedfrom, @@savedto, @@savedentry = '', '', '', ''
+ if @@debug then
+ list.each do |entry|
+ handle << "% [#{entry.sortkey.gsub(/#{@@split}/o,'] [')}]\n"
+ end
+ end
+ list.each do |entry|
+ if entry.sortkey =~ /^(\S+)/o then
+ if sorter.division?($1) then
+ testalpha = sorter.getdivision($1)
+ else
+ testalpha = entry.sortkey[0,1].downcase
+ end
+ else
+ testalpha = entry.sortkey[0,1].downcase
+ end
+ if testalpha != alpha.downcase or alphaclass != entry.class then
+ alpha = testalpha
+ alphaclass = entry.class
+ if alpha != ' ' then
+ flushsavedline(handle)
+ if alpha =~ /^[a-zA-Z]$/o then
+ character = alpha.dup
+ elsif alpha.length > 1 then
+ # character = "\\getvalue\{#{alpha}\}"
+ character = "\\#{alpha}"
+ else
+ character = "\\#{alpha}"
+ end
+ handle << "\\registerentry{#{entry.type}}{#{character}}\n"
+ end
+ end
+ current = [entry.entry.split(@@split),'','',''].flatten
+ howto = current.collect do |e|
+ e + '::' + entry.texthowto
+ end
+ if howto[0] == previous[0] then
+ current[0] = ''
+ else
+ previous[0] = howto[0].dup
+ previous[1] = ''
+ previous[2] = ''
+ end
+ if howto[1] == previous[1] then
+ current[1] = ''
+ else
+ previous[1] = howto[1].dup
+ previous[2] = ''
+ end
+ if howto[2] == previous[2] then
+ current[2] = ''
+ else
+ previous[2] = howto[2].dup
+ end
+ copied = false
+ unless current[0].empty? then
+ Register.flushsavedline(handle)
+ handle << "\\registerentrya{#{entry.type}}{#{current[0]}}\n"
+ copied = true
+ end
+ unless current[1].empty? then
+ Register.flushsavedline(handle)
+ handle << "\\registerentryb{#{entry.type}}{#{current[1]}}\n"
+ copied = true
+ end
+ unless current[2].empty? then
+ Register.flushsavedline(handle)
+ handle << "\\registerentryc{#{entry.type}}{#{current[2]}}\n"
+ copied = true
+ end
+ @nofentries += 1 if copied
+ if entry.realpage.to_i == 0 then
+ Register.flushsavedline(handle)
+ handle << "\\registersee{#{entry.type}}{#{entry.pagehowto},#{entry.texthowto}}{#{entry.seetoo}}{#{entry.page}}\n" ;
+ lastpage, lastrealpage = entry.page, entry.realpage
+ elsif @@savedhowto != entry.pagehowto and ! entry.pagehowto.empty? then
+ @@savedhowto = entry.pagehowto
+ end
+ if copied || ! ((lastpage == entry.page) && (lastrealpage == entry.realpage)) then
+ nextentry = "{#{entry.type}}{#{previous[0]}}{#{previous[1]}}{#{previous[2]}}{#{entry.pagehowto},#{entry.texthowto}}"
+ savedline = "{#{entry.type}}{#{@@savedhowto},#{entry.texthowto}}{#{entry.location}}{#{entry.page}}{#{entry.realpage}}"
+ if entry.state == 1 then # from
+ Register.flushsavedline(handle)
+ handle << "\\registerfrom#{savedline}\n"
+ elsif entry.state == 3 then # to
+ Register.flushsavedline(handle)
+ handle << "\\registerto#{savedline}\n"
+ @@savedhowto = '' # test
+ elsif @@collapse then
+ if savedentry != nextentry then
+ savedFrom = savedline
+ else
+ savedTo, savedentry = savedline, nextentry
+ end
+ else
+ handle << "\\registerpage#{savedline}\n"
+ @@savedhowto = '' # test
+ end
+ @nofpages += 1
+ lastpage, lastrealpage = entry.page, entry.realpage
+ end
+ end
+ Register.flushsavedline(handle)
+ end
+ end
+
+ end
+
+ @@registers = Hash.new
+ @@sorter = Sorter.new
+
+ def MyRegisters::reset(logger)
+ @@registers = Hash.new
+ @@sorter = Sorter.new
+ end
+
+ def MyRegisters::reader(logger,data)
+ case data[0]
+ when 'f' then
+ @@registers[data[1]] = Array.new unless @@registers.key?(data[1])
+ @@registers[data[1]].push(Register.new(1,data[1],data[2],data[3],data[4],nil,data[5],data[6]))
+ when 'e' then
+ @@registers[data[1]] = Array.new unless @@registers.key?(data[1])
+ @@registers[data[1]].push(Register.new(2,data[1],data[2],data[3],data[4],nil,data[5],data[6]))
+ when 't' then
+ @@registers[data[1]] = Array.new unless @@registers.key?(data[1])
+ @@registers[data[1]].push(Register.new(3,data[1],data[2],data[3],data[4],nil,data[5],data[6]))
+ when 's' then
+ @@registers[data[1]] = Array.new unless @@registers.key?(data[1])
+ @@registers[data[1]].push(Register.new(4,data[1],data[2],data[3],data[4],data[5],data[6],nil))
+ end
+ end
+
+ def MyRegisters::writer(logger,handle)
+ if @@registers.size > 0 then
+ @@registers.keys.sort.each do |s|
+ handle << logger.banner("registers: #{s} #{@@registers[s].size}")
+ Register.flush(@@registers[s],handle,@@sorter)
+ # report("register #{@@registers[s].class}: #{@@registers[s].@nofentries} entries and #{@@registers[s].@nofpages} pages")
+ end
+ end
+ end
+
+ def MyRegisters::processor(logger)
+ @@sorter.preset(eval("MyKeys").shortcuts,eval("MyKeys").expansions,eval("MyKeys").reductions,eval("MyKeys").divisions)
+ @@sorter.prepare
+ @@registers.keys.each do |s|
+ @@registers[s].each_index do |i|
+ @@registers[s][i].build(@@sorter)
+ end
+ @@registers[s] = @@registers[s].sort
+ end
+ end
+
+ end
+
+ end
+
+ class Plugin
+
+ module MyPlugins
+
+ @@plugins = nil
+
+ def MyPlugins::reset(logger)
+ @@plugins = nil
+ end
+
+ def MyPlugins::reader(logger,data)
+ @@plugins = Plugin.new(logger) unless @@plugins
+ case data[0]
+ when 'r' then
+ logger.report("registering plugin #{data[1]}")
+ @@plugins.register(data[1],data[2])
+ when 'd' then
+ begin
+ @@plugins.reader(data[1],data[2,data.length-1])
+ rescue
+ @@plugins.reader(data[1],['error'])
+ end
+ end
+ end
+
+ def MyPlugins::writer(logger,handle)
+ @@plugins.writers(handle) if @@plugins
+ end
+
+ def MyPlugins::processor(logger)
+ @@plugins.processors if @@plugins
+ end
+
+ end
+
+ end
+
+ class Plugin
+
+ module MyKeys
+
+ @@shortcuts = Array.new
+ @@expansions = Array.new
+ @@reductions = Array.new
+ @@divisions = Array.new
+
+ def MyKeys::shortcuts
+ @@shortcuts
+ end
+ def MyKeys::expansions
+ @@expansions
+ end
+ def MyKeys::reductions
+ @@reductions
+ end
+ def MyKeys::divisions
+ @@divisions
+ end
+
+ def MyKeys::reset(logger)
+ @@shortcuts = Array.new
+ @@expansions = Array.new
+ @@reductions = Array.new
+ end
+
+ def MyKeys::reader(logger,data)
+ key = data.shift
+ grp = data.shift # language code, todo
+ case key
+ when 's' then @@shortcuts.push(data)
+ when 'e' then @@expansions.push(data)
+ when 'r' then @@reductions.push(data)
+ when 'd' then @@divisions.push(data)
+ end
+ end
+
+ def MyKeys::writer(logger,handle)
+ end
+
+ def MyKeys::processor(logger)
+ logger.report("shortcuts : #{@@shortcuts.size}") # logger.report(@@shortcuts.inspect)
+ logger.report("expansions: #{@@expansions.size}") # logger.report(@@expansions.inspect)
+ logger.report("reductions: #{@@reductions.size}") # logger.report(@@reductions.inspect)
+ logger.report("divisions : #{@@divisions.size}") # logger.report(@@divisions.inspect)
+ end
+
+ end
+
+ end
+
+ class Converter
+
+ def initialize(logger=nil)
+ if @logger = logger then
+ def report(str)
+ @logger.report(str)
+ end
+ def banner(str)
+ @logger.banner(str)
+ end
+ else
+ @logger = self
+ def report(str)
+ puts(str)
+ end
+ def banner(str)
+ puts(str)
+ end
+ end
+ @filename = 'texutil'
+ @fatalerror = false
+ @plugins = Plugin.new(@logger)
+ ['MyFiles', 'MyCommands', 'MySynonyms', 'MyRegisters', 'MyExtras', 'MyPlugins', 'MyKeys'].each do |p|
+ @plugins.register(p)
+ end
+ end
+
+ def loaded(filename)
+ begin
+ report("parsing file #{filename}")
+ if f = open(File.suffixed(filename,'tui')) then
+ f.each do |line|
+ case line.chomp
+ when /^f (.*)$/o then @plugins.reader('MyFiles', $1.splitdata)
+ when /^c (.*)$/o then @plugins.reader('MyCommands', [$1])
+ when /^e (.*)$/o then @plugins.reader('MyExtras', $1.splitdata)
+ when /^s (.*)$/o then @plugins.reader('MySynonyms', $1.splitdata)
+ when /^r (.*)$/o then @plugins.reader('MyRegisters',$1.splitdata)
+ when /^p (.*)$/o then @plugins.reader('MyPlugins', $1.splitdata)
+ when /^x (.*)$/o then @plugins.reader('MyKeys', $1.splitdata)
+ else report("unknown entry #{line[0,1]} in line #{line.chomp}")
+ end
+ end
+ f.close
+ end
+ rescue
+ report("fatal error in parsing #{filename}")
+ @filename = 'texutil'
+ else
+ @filename = filename
+ end
+ end
+
+ def processed
+ @plugins.processors
+ return true # for the moment
+ end
+
+ def saved(filename=@filename)
+ if @fatalerror then
+ report("fatal error, no tuo file saved")
+ else
+ begin
+ if f = File.open(File.suffixed(filename,'tuo'),'w') then
+ @plugins.writers(f)
+ f.close
+ end
+ rescue
+ report("fatal error when saving file (#{$!})")
+ else
+ report("tuo file saved")
+ end
+ end
+ @plugins.resets
+ end
+
+ def reset
+ @plugins.resets
+ end
+
+ end
+
+end
diff --git a/Master/texmf-dist/scripts/context/ruby/base/tool.rb b/Master/texmf-dist/scripts/context/ruby/base/tool.rb
new file mode 100644
index 00000000000..7f40e773d0c
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/base/tool.rb
@@ -0,0 +1,306 @@
+# 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)
+ str.gsub!(/(.*?)\%\!PS/mo, "%!PS") # don't look into preamble crap
+ 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/Master/texmf-dist/scripts/context/ruby/base/variables.rb b/Master/texmf-dist/scripts/context/ruby/base/variables.rb
new file mode 100644
index 00000000000..5cbc5ba538e
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/base/variables.rb
@@ -0,0 +1,45 @@
+# 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 checkedvariable(str,default='')
+ if @variables.key?(key) then
+ if @variables[key].empty? then default else @variables[key] end
+ else
+ default
+ end
+ end
+
+ def report(*str)
+ @logger.report(*str)
+ end
+
+ def debug(*str)
+ @logger.debug(str)
+ end
+
+end
diff --git a/Master/texmf-dist/scripts/context/ruby/concheck.rb b/Master/texmf-dist/scripts/context/ruby/concheck.rb
new file mode 100644
index 00000000000..bf09bbdc8da
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/concheck.rb
@@ -0,0 +1,461 @@
+# Program : concheck (tex & context syntax checker)
+# Copyright : PRAGMA ADE / Hasselt NL / www.pragma-ade.com
+# Author : Hans Hagen
+# Version : 1.1 / 2003.08.18
+
+# remarks:
+#
+# - the error messages are formatted like tex's messages so that scite can see them
+# - begin and end tags are only tested on a per line basis because we assume clean sources
+# - maybe i'll add begin{something} ... end{something} checking
+
+# # example validation file
+#
+# begin interface en
+#
+# 1 text
+# 4 Question
+# 0 endinput
+# 0 setupsomething
+# 0 chapter
+#
+# end interface en
+
+# nicer
+
+# class Interface
+
+ # def initialize (language = 'unknown')
+ # @valid = Array.new
+ # @language = language
+ # end
+
+ # def register (left, right)
+ # @valid.push([left,right])
+ # end
+
+# end
+
+# $interfaces = Hash.new
+
+# $interfaces['en'] = Interface.new('english')
+# $interfaces['nl'] = Interface.new('dutch')
+
+# $interfaces['en'].add('\\\\start','\\\\stop')
+# $interfaces['en'].add('\\\\begin','\\\\end')
+# $interfaces['en'].add('\\\\Start','\\\\Stop')
+# $interfaces['en'].add('\\\\Begin','\\\\End')
+
+# $interfaces['nl'].add('\\\\start','\\\\stop')
+# $interfaces['nl'].add('\\\\beginvan','\\\\eindvan')
+# $interfaces['nl'].add('\\\\Start','\\\\Stop')
+# $interfaces['nl'].add('\\\\BeginVan','\\\\Eindvan')
+
+# rest todo
+
+$valid = Hash.new
+
+$valid['en'] = Array.new
+$valid['nl'] = Array.new
+
+#$valid['en'].push(['',''])
+$valid['en'].push(['\\\\start','\\\\stop'])
+$valid['en'].push(['\\\\begin','\\\\end'])
+$valid['en'].push(['\\\\Start','\\\\Stop'])
+$valid['en'].push(['\\\\Begin','\\\\End'])
+
+#$valid['nl'].push(['',''])
+$valid['nl'].push(['\\\\start','\\\\stop'])
+$valid['nl'].push(['\\\\beginvan','\\\\eindvan'])
+$valid['nl'].push(['\\\\Start','\\\\Stop'])
+$valid['nl'].push(['\\\\BeginVan','\\\\Eindvan'])
+
+$valid_tex = "\\\\end\(input|insert|csname|linechar|graf|buffer|strut\)"
+$valid_mp = "(enddef||end||endinput)"
+
+$start_verbatim = Hash.new
+$stop_verbatim = Hash.new
+
+$start_verbatim['en'] = '\\\\starttyping'
+$start_verbatim['nl'] = '\\\\starttypen'
+
+$stop_verbatim['en'] = '\\\\stoptyping'
+$stop_verbatim['nl'] = '\\\\stoptypen'
+
+def message(str, filename=nil, line=nil, column=nil)
+ if filename then
+ if line then
+ if column then
+ puts("error in file #{filename} at line #{line} in column #{column}: #{str}\n")
+ else
+ puts("error in file #{filename} at line #{line}: #{str}\n")
+ end
+ else
+ puts("file #{filename}: #{str}\n")
+ end
+ else
+ puts(str+"\n")
+ end
+end
+
+def load_file (filename='')
+ begin
+ data = IO.readlines(filename)
+ data.collect! do |d|
+ if d =~ /^\s*%/o then
+ ''
+ elsif d =~ /(.*?[^\\])%.*$/o then
+ $1
+ else
+ d
+ end
+ end
+ rescue
+ message("provide proper filename")
+ return nil
+ end
+ # print data.to_s + "\n"
+ return data
+end
+
+def guess_interface(data)
+ if data.first =~ /^%.*interface\=(.*)\s*/ then
+ return $1
+ else
+ data.each do |line|
+ case line
+ when /\\(starttekst|stoptekst|startonderdeel|startdocument|startoverzicht)/o then return 'nl'
+ when /\\(stelle|verwende|umgebung|benutze)/o then return 'de'
+ when /\\(stel|gebruik|omgeving)/ then return 'nl'
+ when /\\(use|setup|environment)/ then return 'en'
+ when /\\(usa|imposta|ambiente)/ then return 'it'
+ when /(height|width|style)=/ then return 'en'
+ when /(hoehe|breite|schrift)=/ then return 'de'
+ when /(hoogte|breedte|letter)=/ then return 'nl'
+ when /(altezza|ampiezza|stile)=/ then return 'it'
+ when /externfiguur/ then return 'nl'
+ when /externalfigure/ then return 'en'
+ when /externeabbildung/ then return 'de'
+ when /figuraesterna/ then return 'it'
+ end
+ end
+ return 'en'
+ end
+end
+
+def cleanup_data(data, interface='en')
+ verbatim = 0
+ re_start = /^\s*#{$start_verbatim[interface]}/
+ re_stop = /^\s*#{$stop_verbatim[interface]}/
+ data.collect! do |d|
+ if d =~ re_start then
+ verbatim += 1
+ if verbatim>1 then
+ ''
+ else
+ d
+ end
+ elsif d =~ re_stop then
+ verbatim -= 1
+ if verbatim>0 then
+ ''
+ else
+ d
+ end
+ elsif verbatim > 0 then
+ ''
+ else
+ d
+ end
+ end
+ return data
+end
+
+def load_valid(data, interface=nil)
+ if data && (data.first =~ /^%.*valid\=(.*)\s*/)
+ filename = $1
+ filename = '../' + filename unless test(?f,filename)
+ filename = '../' + filename unless test(?f,filename)
+ if test(?f,filename) then
+ interface = guess_interface(data) unless interface
+ if $valid.has_key?(interface) then
+ interface = $valid[interface]
+ else
+ interface = $valid['en']
+ end
+ begin
+ message("loading validation file",filename)
+ validkeys = Hash.new
+ line = 1
+ IO.readlines(filename).each do |l|
+ if l =~ /\s+[\#\%]/io then
+ # ignore line
+ elsif l =~ /^\s*(begin|end)\s+interface\s+([a-z][a-z])/o then
+ # not yet supported
+ elsif l =~ /^\s*(\d+)\s+([a-zA-Z]*)$/o then
+ type, key = $1.to_i, $2.strip
+ if interface[type] then
+ validkeys[interface[type].first+key] = true
+ validkeys[interface[type].last+key] = true
+ else
+ error_message(filename,line,nil,'wrong definition')
+ end
+ end
+ line += 1
+ end
+ if validkeys then
+ message("#{validkeys.length} validation keys loaded",filename)
+ end
+ return validkeys
+ rescue
+ message("invalid validation file",filename)
+ end
+ else
+ message("unknown validation file", filename)
+ end
+ else
+ message("no extra validation file specified")
+ end
+ return nil
+end
+
+def some_chr_error(data, filename, left, right)
+ levels = Array.new
+ for line in 0..data.length-1 do
+ str = data[line]
+ column = 0
+ while column<str.length do
+ case str[column].chr
+ when "\%" then
+ break
+ when "\\" then
+ column += 2
+ when left then
+ levels.push([line,column])
+ column += 1
+ when right then
+ if levels.pop
+ column += 1
+ else
+ message("missing #{left} for #{right}",filename,line+1,column+1)
+ return true
+ end
+ else
+ column += 1
+ end
+ end
+ end
+ if levels && levels.length>0 then
+ levels.each do |l|
+ column = l.pop
+ line = l.pop
+ message("missing #{right} for #{left}",filename,line+1,column+1)
+ end
+ return true
+ else
+ return false
+ end
+end
+
+def some_wrd_error(data, filename, start, stop, ignore)
+ levels = Array.new
+ len = 0
+ re_start = /[^\%]*(#{start})([a-zA-Z]*)/
+ re_stop = /[^\%]*(#{stop})([a-zA-Z]*)/
+ re_ignore = /#{ignore}.*/
+ str_start = start.gsub(/\\+/,'\\')
+ str_stop = stop.gsub(/\\+/,'\\')
+ line = 0
+ while line<data.length do
+ dataline = data[line].split(/[^\\A-Za-z]/)
+ if dataline.length>0 then
+ # todo: more on one line
+ dataline.each do |dataword|
+ case dataword
+ when re_ignore then
+ # just go on
+ when re_start then
+ levels.push([line,$2])
+ # print ' '*levels.length + '>' + $2 + "\n"
+ when re_stop then
+ # print ' '*levels.length + '<' + $2 + "\n"
+ if levels && levels.last && (levels.last[1] == $2) then
+ levels.pop
+ elsif levels && levels.last then
+ message("#{str_stop}#{levels.last[1]} expected instead of #{str_stop}#{$2}",filename,line+1)
+ return true
+ else
+ message("missing #{str_start}#{$2} for #{str_stop}#{$2}",filename,line+1)
+ return true
+ end
+ else
+ # just go on
+ end
+ end
+ end
+ line += 1
+ end
+ if levels && levels.length>0 then
+ levels.each do |l|
+ text = l.pop
+ line = l.pop
+ message("missing #{str_stop}#{text} for #{str_start}#{text}",filename,line+1)
+ end
+ return true
+ else
+ return false
+ end
+end
+
+def some_sym_error (data, filename, symbol,template=false)
+ saved = Array.new
+ inside = false
+ level = 0
+ for line in 0..data.length-1 do
+ str = data[line]
+ column = 0
+ while column<str.length do
+ case str[column].chr
+ when "[" then
+ level += 1 if template
+ when "]" then
+ level -= 1 if template && level > 0
+ when "\%" then
+ break
+ when "\\" then
+ column += 1
+ when symbol then
+ if level == 0 then
+ inside = ! inside
+ saved = [line,column]
+ else
+ # we're in some kind of template or so
+ end
+ else
+ # go on
+ end
+ column += 1
+ end
+ end
+ if inside && saved && level == 0 then
+ column = saved.pop
+ line = saved.pop
+ message("missing #{symbol} for #{symbol}",filename,line+1)
+ return true
+ else
+ return false
+ end
+end
+
+def some_key_error(data, filename, valid)
+ return if (! valid) || (valid.length == 0)
+ error = false
+ # data.foreach do |line| ... end
+ for line in 0..data.length-1 do
+ data[line].scan(/\\([a-zA-Z]+)/io) do
+ unless valid.has_key?($1) then
+ message("unknown command \\#{$1}",filename,line+1)
+ error = true
+ end
+ end
+ end
+ return error
+end
+
+# todo : language dependent
+
+def check_file_tex (filename)
+ if data = load_file(filename) then
+ message("checking tex file", filename)
+ interface = guess_interface(data)
+ valid = load_valid(data,interface)
+ data = cleanup_data(data,interface)
+ # data.each do |d| print d end
+ $valid[interface].each do |v|
+ return false if some_wrd_error(data, filename, v[0], v[1] ,$valid_tex)
+ end
+ # return false if some_wrd_error(data, filename, '\\\\start' , '\\\\stop' , $valid_tex)
+ # return false if some_wrd_error(data, filename, '\\\\Start' , '\\\\Stop' , $valid_tex)
+ # return false if some_wrd_error(data, filename, '\\\\beginvan', '\\\\eindvan', $valid_tex)
+ # return false if some_wrd_error(data, filename, '\\\\begin' , '\\\\end|\\\\eind', $valid_tex)
+ return false if some_sym_error(data, filename, '$', false)
+ return false if some_sym_error(data, filename, '|', true)
+ return false if some_chr_error(data, filename, '{', '}')
+ return false if some_chr_error(data, filename, '[', ']')
+ return false if some_chr_error(data, filename, '(', ')')
+ return false if some_key_error(data, filename, valid)
+ message("no errors in tex code", filename)
+ return true
+ else
+ return false
+ end
+end
+
+def check_file_mp (filename)
+ if data = load_file(filename) then
+ message("checking metapost file", filename)
+ interface = guess_interface(data)
+ valid = load_valid(data,interface)
+ $valid[interface].each do |v|
+ return false if some_wrd_error(data, filename, v[0], v[1] ,$valid_tex)
+ end
+ # return false if some_wrd_error(data, filename, '', 'begin', 'end', $valid_mp)
+ return false if some_chr_error(data, filename, '{', '}')
+ return false if some_chr_error(data, filename, '[', ']')
+ return false if some_chr_error(data, filename, '(', ')')
+ return false if some_key_error(data, filename, valid)
+ message("no errors in metapost code", filename)
+ return true
+ else
+ return true
+ end
+end
+
+def check_file_text(filename='')
+ if data = load_file(filename) then
+ for line in 0..data.length-1 do
+ # case data[line]
+ # when /\s([\:\;\,\.\?\!])/ then
+ # message("space before #{$1}",filename,line+1)
+ # when /\D([\:\;\,\.\?\!])\S/ then
+ # message("no space after #{$1}",filename,line+1)
+ # end
+ if data[line] =~ /\s([\:\;\,\.\?\!])/ then
+ message("space before #{$1}",filename,line+1)
+ else
+ data[line].gsub!(/\[.*?\]/o, '')
+ data[line].gsub!(/\(.*?\)/o, '')
+ data[line].gsub!(/\[.*?$/o, '')
+ data[line].gsub!(/^.*?\]/o, '')
+ if data[line] =~ /\D([\:\;\,\.\?\!])\S/ then
+ message("no space after #{$1}",filename,line+1)
+ end
+ end
+ end
+ end
+end
+
+def check_file(filename='')
+ case filename
+ when '' then
+ message("provide filename")
+ return false
+ when /\.tex$/i then
+ return check_file_tex(filename) # && check_file_text(filename)
+ when /\.mp$/i then
+ return check_file_mp(filename)
+ else
+ message("only tex and metapost files are checked")
+ return false
+ end
+end
+
+if filename = ARGV[0] then
+ if check_file(filename) then
+ exit 0
+ else
+ exit 1
+ end
+else
+ exit 1
+end
diff --git a/Master/texmf-dist/scripts/context/ruby/ctxtools.rb b/Master/texmf-dist/scripts/context/ruby/ctxtools.rb
new file mode 100644
index 00000000000..94e6e735a20
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/ctxtools.rb
@@ -0,0 +1,1405 @@
+#!/usr/bin/env ruby
+
+# 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.2', '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 'rexml/document'
+require 'ftools'
+require 'kconv'
+
+exit if defined?(REQUIRE2LIB)
+
+class String
+
+ def i_translate(element, attribute, category)
+ self.gsub!(/(<#{element}.*?#{attribute}=)([\"\'])(.*?)\2/) do
+ if category.key?($3) then
+ # puts "#{element} #{$3} -> #{category[$3]}\n" if element == 'cd:inherit'
+ # puts "#{element} #{$3} => #{category[$3]}\n" if element == 'cd:command'
+ "#{$1}#{$2}#{category[$3]}#{$2}"
+ else
+ # puts "#{element} #{$3} -> ?\n" if element == 'cd:inherit'
+ # puts "#{element} #{$3} => ?\n" if element == 'cd:command'
+ "#{$1}#{$2}#{$3}#{$2}" # unchanged
+ end
+ end
+ end
+
+ def i_load(element, category)
+ self.scan(/<#{element}.*?name=([\"\'])(.*?)\1.*?value=\1(.*?)\1/) do
+ category[$2] = $3
+ end
+ end
+
+end
+
+class Commands
+
+ include CommandBase
+
+ public
+
+ def touchcontextfile
+ dowithcontextfile(1)
+ end
+
+ def contextversion
+ dowithcontextfile(2)
+ end
+
+ private
+
+ def dowithcontextfile(action)
+ maincontextfile = 'context.tex'
+ unless FileTest.file?(maincontextfile) then
+ begin
+ maincontextfile = `kpsewhich -progname=context #{maincontextfile}`.chomp
+ rescue
+ maincontextfile = ''
+ end
+ end
+ unless maincontextfile.empty? then
+ case action
+ when 1 then touchfile(maincontextfile)
+ when 2 then reportversion(maincontextfile)
+ end
+ end
+
+ end
+
+ def touchfile(filename)
+
+ if FileTest.file?(filename) then
+ if data = IO.read(filename) then
+ timestamp = Time.now.strftime('%Y.%m.%d')
+ prevstamp = ''
+ begin
+ data.gsub!(/\\contextversion\{(\d+\.\d+\.\d+)\}/) do
+ prevstamp = $1
+ "\\contextversion{#{timestamp}}"
+ end
+ rescue
+ else
+ begin
+ File.delete(filename+'.old')
+ rescue
+ end
+ begin
+ File.copy(filename,filename+'.old')
+ rescue
+ end
+ begin
+ if f = File.open(filename,'w') then
+ f.puts(data)
+ f.close
+ end
+ rescue
+ end
+ end
+ if prevstamp.empty? then
+ report("#{filename} is not updated, no timestamp found")
+ else
+ report("#{filename} is updated from #{prevstamp} to #{timestamp}")
+ end
+ end
+ else
+ report("#{filename} is not found")
+ end
+
+ end
+
+ def reportversion(filename)
+
+ version = 'unknown'
+ begin
+ if FileTest.file?(filename) && IO.read(filename).match(/\\contextversion\{(\d+\.\d+\.\d+)\}/) then
+ version = $1
+ end
+ rescue
+ end
+ if @commandline.option("pipe") then
+ print version
+ else
+ report("context version: #{version}")
+ end
+
+ end
+
+end
+
+class Commands
+
+ include CommandBase
+
+ public
+
+ def jeditinterface
+ editinterface('jedit')
+ end
+
+ def bbeditinterface
+ editinterface('bbedit')
+ end
+
+ def sciteinterface
+ editinterface('scite')
+ end
+
+ def rawinterface
+ editinterface('raw')
+ end
+
+ private
+
+ def editinterface(type='raw')
+
+ return unless FileTest.file?("cont-en.xml")
+
+ interfaces = @commandline.arguments
+
+ if interfaces.empty? then
+ interfaces = ['en', 'cz','de','it','nl','ro']
+ end
+
+ interfaces.each do |interface|
+ begin
+ collection = Hash.new
+ mappings = Hash.new
+ if f = open("keys-#{interface}.xml") then
+ while str = f.gets do
+ if str =~ /\<cd\:command\s+name=\"(.*?)\"\s+value=\"(.*?)\".*?\>/o then
+ mappings[$1] = $2
+ end
+ end
+ f.close
+ if f = open("cont-en.xml") then
+ while str = f.gets do
+ if str =~ /\<cd\:command\s+name=\"(.*?)\"\s+type=\"environment\".*?\>/o then
+ collection["start#{mappings[$1]}"] = ''
+ collection["stop#{mappings[$1]}"] = ''
+ elsif str =~ /\<cd\:command\s+name=\"(.*?)\".*?\>/o then
+ collection["#{mappings[$1]}"] = ''
+ end
+ end
+ f.close
+ case type
+ when 'jedit' then
+ if f = open("context-jedit-#{interface}.xml", 'w') then
+ f.puts("<?xml version='1.0'?>\n\n")
+ f.puts("<!DOCTYPE MODE SYSTEM 'xmode.dtd'>\n\n")
+ f.puts("<MODE>\n")
+ f.puts(" <RULES>\n")
+ f.puts(" <KEYWORDS>\n")
+ collection.keys.sort.each do |name|
+ f.puts(" <KEYWORD2>\\#{name}</KEYWORD2>\n") unless name.empty?
+ end
+ f.puts(" </KEYWORDS>\n")
+ f.puts(" </RULES>\n")
+ f.puts("</MODE>\n")
+ f.close
+ end
+ when 'bbedit' then
+ if f = open("context-bbedit-#{interface}.xml", 'w') then
+ f.puts("<?xml version='1.0'?>\n\n")
+ f.puts("<key>BBLMKeywordList</key>\n")
+ f.puts("<array>\n")
+ collection.keys.sort.each do |name|
+ f.puts(" <string>\\#{name}</string>\n") unless name.empty?
+ end
+ f.puts("</array>\n")
+ f.close
+ end
+ when 'scite' then
+ if f = open("cont-#{interface}-scite.properties", 'w') then
+ i = 0
+ f.write("keywordclass.macros.context.#{interface}=")
+ collection.keys.sort.each do |name|
+ unless name.empty? then
+ if i==0 then
+ f.write("\\\n ")
+ i = 5
+ else
+ i = i - 1
+ end
+ f.write("#{name} ")
+ end
+ end
+ f.write("\n")
+ f.close
+ end
+ else # raw
+ collection.keys.sort.each do |name|
+ puts("\\#{name}\n") unless name.empty?
+ end
+ end
+ end
+ end
+ end
+ end
+
+ end
+
+end
+
+class Commands
+
+ include CommandBase
+
+ public
+
+ def translateinterface
+
+ # since we know what kind of file we're dealing with,
+ # we do it quick and dirty instead of using rexml or
+ # xslt
+
+ interfaces = @commandline.arguments
+
+ if interfaces.empty? then
+ interfaces = ['cz','de','it','nl','ro']
+ else
+ interfaces.delete('en')
+ end
+
+ interfaces.flatten.each do |interface|
+
+ variables, constants, strings, list, data = Hash.new, Hash.new, Hash.new, '', ''
+
+ keyfile, intfile, outfile = "keys-#{interface}.xml", "cont-en.xml", "cont-#{interface}.xml"
+
+ report("generating #{keyfile}")
+
+ begin
+ one = "texexec --make --alone --all #{interface}"
+ two = "texexec --batch --silent --interface=#{interface} x-set-01"
+ if @commandline.option("force") then
+ system(one)
+ system(two)
+ elsif not system(two) then
+ system(one)
+ system(two)
+ end
+ rescue
+ end
+
+ unless File.file?(keyfile) then
+ report("no #{keyfile} generated")
+ next
+ end
+
+ report("loading #{keyfile}")
+
+ begin
+ list = IO.read(keyfile)
+ rescue
+ list = empty
+ end
+
+ if list.empty? then
+ report("error in loading #{keyfile}")
+ next
+ end
+
+ list.i_load('cd:variable', variables)
+ list.i_load('cd:constant', constants)
+ list.i_load('cd:command' , strings)
+ # list.i_load('cd:element' , strings)
+
+ report("loading #{intfile}")
+
+ begin
+ data = IO.read(intfile)
+ rescue
+ data = empty
+ end
+
+ if data.empty? then
+ report("error in loading #{intfile}")
+ next
+ end
+
+ report("translating interface en to #{interface}")
+
+ data.i_translate('cd:string' , 'value', strings)
+ data.i_translate('cd:variable' , 'value', variables)
+ data.i_translate('cd:parameter', 'name' , constants)
+ data.i_translate('cd:constant' , 'type' , variables)
+ data.i_translate('cd:variable' , 'type' , variables)
+ data.i_translate('cd:inherit' , 'name' , strings)
+ # data.i_translate('cd:command' , 'name' , strings)
+
+ report("saving #{outfile}")
+
+ begin
+ if f = File.open(outfile, 'w') then
+ f.write(data)
+ f.close
+ end
+ rescue
+ end
+
+ end
+
+ end
+
+end
+
+class Commands
+
+ include CommandBase
+
+ public
+
+ def purgefiles(all=false)
+
+ pattern = @commandline.arguments
+ purgeall = @commandline.option("all") || all
+ recurse = @commandline.option("recurse")
+
+ $dontaskprefixes.push(Dir.glob("mpx-*"))
+ $dontaskprefixes.flatten!
+ $dontaskprefixes.sort!
+
+ if purgeall then
+ $forsuresuffixes.push($texnonesuffixes)
+ $texnonesuffixes = []
+ $forsuresuffixes.flatten!
+ end
+
+ if ! pattern || pattern.empty? then
+ globbed = if recurse then "**/*.*" else "*.*" end
+ files = Dir.glob(globbed)
+ report("purging files : #{globbed}")
+ else
+ pattern.each do |pat|
+ globbed = if recurse then "**/#{pat}-*.*" else "#{pat}-*.*" end
+ files = Dir.glob(globbed)
+ globbed = if recurse then "**/#{pat}.*" else "#{pat}.*" end
+ files.push(Dir.glob(globbed))
+ end
+ report("purging files : #{pattern.join(' ')}")
+ end
+ files.flatten!
+ files.sort!
+
+ $dontaskprefixes.each do |file|
+ removecontextfile(file)
+ end
+ $dontasksuffixes.each do |suffix|
+ files.each do |file|
+ removecontextfile(file) if file =~ /#{suffix}$/i
+ end
+ end
+ $forsuresuffixes.each do |suffix|
+ files.each do |file|
+ removecontextfile(file) if file =~ /\.#{suffix}$/i
+ end
+ end
+ files.each do |file|
+ if file =~ /(.*?)\.\d+$/o then
+ basename = $1
+ if file =~ /mp(graph|run)/o || FileTest.file?("#{basename}.mp") then
+ removecontextfile($file)
+ end
+ end
+ end
+ $texnonesuffixes.each do |suffix|
+ files.each do |file|
+ if file =~ /(.*)\.#{suffix}$/i then
+ if FileTest.file?("#{$1}.tex") || FileTest.file?("#{$1}.xml") || FileTest.file?("#{$1}.fo") then
+ keepcontextfile(file)
+ else
+ strippedname = $1.gsub(/\-[a-z]$/io, '')
+ if FileTest.file?("#{strippedname}.tex") || FileTest.file?("#{strippedname}.xml") then
+ keepcontextfile("#{file} (potential result file)")
+ else
+ removecontextfile(file)
+ end
+ end
+ end
+ end
+ end
+
+ files = Dir.glob("*.*")
+ $dontasksuffixes.each do |suffix|
+ files.each do |file|
+ removecontextfile(file) if file =~ /^#{suffix}$/i
+ end
+ end
+
+ if $removedfiles || $keptfiles || $persistentfiles then
+ report("removed files : #{$removedfiles}")
+ report("kept files : #{$keptfiles}")
+ report("persistent files : #{$persistentfiles}")
+ report("reclaimed bytes : #{$reclaimedbytes}")
+ end
+
+ end
+
+ def purgeallfiles
+ purgefiles(true) # for old times sake
+ end
+
+ private
+
+ $removedfiles = 0
+ $keptfiles = 0
+ $persistentfiles = 0
+ $reclaimedbytes = 0
+
+ $dontaskprefixes = [
+ # "tex-form.tex", "tex-edit.tex", "tex-temp.tex",
+ "texexec.tex", "texexec.tui", "texexec.tuo",
+ "texexec.ps", "texexec.pdf", "texexec.dvi",
+ "cont-opt.tex", "cont-opt.bak"
+ ]
+ $dontasksuffixes = [
+ "mp(graph|run)\\.mp", "mp(graph|run)\\.mpd", "mp(graph|run)\\.mpo", "mp(graph|run)\\.mpy",
+ "mp(graph|run)\\.\\d+",
+ "xlscript\\.xsl"
+ ]
+ $forsuresuffixes = [
+ "tui", "tup", "ted", "tes", "top",
+ "log", "tmp", "run", "bck", "rlg",
+ "mpt", "mpx", "mpd", "mpo"
+ ]
+ $texonlysuffixes = [
+ "dvi", "ps", "pdf"
+ ]
+ $texnonesuffixes = [
+ "tuo", "tub", "top"
+ ]
+
+ def removecontextfile (filename)
+ if filename && FileTest.file?(filename) then
+ begin
+ filesize = FileTest.size(filename)
+ File.delete(filename)
+ rescue
+ report("problematic : #{filename}")
+ else
+ if FileTest.file?(filename) then
+ $persistentfiles += 1
+ report("persistent : #{filename}")
+ else
+ $removedfiles += 1
+ $reclaimedbytes += filesize
+ report("removed : #{filename}")
+ end
+ end
+ end
+ end
+
+ def keepcontextfile (filename)
+ if filename && FileTest.file?(filename) then
+ $keptfiles += 1
+ report("not removed : #{filename}")
+ end
+ end
+
+end
+
+#D Documentation can be woven into a source file. The next
+#D routine generates a new, \TEX\ ready file with the
+#D documentation and source fragments properly tagged. The
+#D documentation is included as comment:
+#D
+#D \starttypen
+#D %D ...... some kind of documentation
+#D %M ...... macros needed for documenation
+#D %S B begin skipping
+#D %S E end skipping
+#D \stoptypen
+#D
+#D The most important tag is \type {%D}. Both \TEX\ and \METAPOST\
+#D files use \type{%} as a comment chacacter, while \PERL, \RUBY\
+#D and alike use \type{#}. Therefore \type{#D} is also handled.
+#D
+#D The generated file gets the suffix \type{ted} and is
+#D structured as:
+#D
+#D \starttypen
+#D \startmodule[type=suffix]
+#D \startdocumentation
+#D \stopdocumentation
+#D \startdefinition
+#D \stopdefinition
+#D \stopmodule
+#D \stoptypen
+#D
+#D Macro definitions specific to the documentation are not
+#D surrounded by start||stop commands. The suffix specifaction
+#D can be overruled at runtime, but defaults to the file
+#D extension. This specification can be used for language
+#D depended verbatim typesetting.
+
+class Commands
+
+ include CommandBase
+
+ public
+
+ def documentation
+ files = @commandline.arguments
+ processtype = @commandline.option("type")
+ files.each do |fullname|
+ if fullname =~ /(.*)\.(.+?)$/o then
+ filename, filesuffix = $1, $2
+ else
+ filename, filesuffix = fullname, 'tex'
+ end
+ filesuffix = 'tex' if filesuffix.empty?
+ fullname, resultname = "#{filename}.#{filesuffix}", "#{filename}.ted"
+ if ! FileTest.file?(fullname)
+ report("empty input file #{fullname}")
+ elsif ! tex = File.open(fullname)
+ report("invalid input file #{fullname}")
+ elsif ! ted = File.open(resultname,'w') then
+ report("unable to openresult file #{resultname}")
+ else
+ report("input file : #{fullname}")
+ report("output file : #{resultname}")
+ nofdocuments, nofdefinitions, nofskips = 0, 0, 0
+ skiplevel, indocument, indefinition, skippingbang = 0, false, false, false
+ if processtype.empty? then
+ filetype = filesuffix.downcase
+ else
+ filetype = processtype.downcase
+ end
+ report("filetype : #{filetype}")
+ # we need to signal to texexec what interface to use
+ firstline = tex.gets
+ if firstline =~ /^\%.*interface\=/ then
+ ted.puts(firstline)
+ else
+ tex.rewind # seek(0)
+ end
+ ted.puts("\\startmodule[type=#{filetype}]\n")
+ while str = tex.gets do
+ if skippingbang then
+ skippingbang = false
+ else
+ str.chomp!
+ str.sub!(/\s*$/o, '')
+ case str
+ when /^[%\#]D/io then
+ if skiplevel == 0 then
+ someline = if str.length < 3 then "" else str[3,str.length-1] end
+ if indocument then
+ ted.puts("#{someline}\n")
+ else
+ if indefinition then
+ ted.puts("\\stopdefinition\n")
+ indefinition = false
+ end
+ unless indocument then
+ ted.puts("\n\\startdocumentation\n")
+ end
+ ted.puts("#{someline}\n")
+ indocument = true
+ nofdocuments += 1
+ end
+ end
+ when /^[%\#]M/io then
+ if skiplevel == 0 then
+ someline = if str.length < 3 then "" else str[3,str.length-1] end
+ ted.puts("#{someline}\n")
+ end
+ when /^[%\%]S B/io then
+ skiplevel += 1
+ nofskips += 1
+ when /^[%\%]S E/io then
+ skiplevel -= 1
+ when /^[%\#]/io then
+ #nothing
+ when /^eval \'\(exit \$\?0\)\' \&\& eval \'exec perl/o then
+ skippingbang = true
+ else
+ if skiplevel == 0 then
+ inlocaldocument = indocument
+ someline = str
+ if indocument then
+ ted.puts("\\stopdocumentation\n")
+ indocument = false
+ end
+ if someline.empty? && indefinition then
+ ted.puts("\\stopdefinition\n")
+ indefinition = false
+ elsif indefinition then
+ ted.puts("#{someline}\n")
+ elsif ! someline.empty? then
+ ted.puts("\n\\startdefinition\n")
+ indefinition = true
+ unless inlocaldocument then
+ nofdefinitions += 1
+ ted.puts("#{someline}\n")
+ end
+ end
+ end
+ end
+ end
+ end
+ if indocument then
+ ted.puts("\\stopdocumentation\n")
+ end
+ if indefinition then
+ ted.puts("\\stopdefinition\n")
+ end
+ ted.puts("\\stopmodule\n")
+ ted.close
+
+ if nofdocuments == 0 && nofdefinitions == 0 then
+ begin
+ File.delete(resultname)
+ rescue
+ end
+ end
+ report("documentation sections : #{nofdocuments}")
+ report("definition sections : #{nofdefinitions}")
+ report("skipped sections : #{nofskips}")
+ end
+ end
+ end
+
+end
+
+#D This feature was needed when \PDFTEX\ could not yet access page object
+#D numbers (versions prior to 1.11).
+
+class Commands
+
+ include CommandBase
+
+ public
+
+ def filterpages # temp feature / no reporting
+ filename = @commandline.argument('first')
+ filename.sub!(/\.([a-z]+?)$/io,'')
+ pdffile = "#{filename}.pdf"
+ tuofile = "#{filename}.tuo"
+ if FileTest.file?(pdffile) then
+ 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
+ end
+ end
+
+end
+
+# This script is used to generate hyphenation pattern files
+# that suit ConTeXt. One reason for independent files is that
+# over the years too many uncommunicated changes took place
+# as well that inconsistency in content, naming, and location
+# in the texmf tree takes more time than I'm willing to spend
+# on it. Pattern files are normally shipped for LaTeX (and
+# partially plain). A side effect of independent files is that
+# we can make them encoding independent.
+#
+# Maybe I'll make this hyptools.tex
+
+class Language
+
+ include CommandBase
+
+ def initialize(commandline=nil, language='en', filenames=nil, encoding='ec')
+ @commandline= commandline
+ @language = language
+ @filenames = filenames
+ @remapping = Array.new
+ @unicode = Hash.new
+ @encoding = encoding
+ @data = ''
+ @read = ''
+ preload_accents()
+ preload_unicode() if @commandline.option('utf8')
+ case @encoding.downcase
+ when 't1', 'ec', 'cork' then preload_vector('ec')
+ when 'y', 'texnansi' then preload_vector('texnansi')
+ end
+ end
+
+ def report(str)
+ if @commandline then
+ @commandline.report(str)
+ else
+ puts("#{str}\n")
+ end
+ end
+
+ def remap(from, to)
+ @remapping.push([from,to])
+ end
+
+ def load(filenames=@filenames)
+ begin
+ if filenames then
+ @filenames.each do |fileset|
+ [fileset].flatten.each do |filename|
+ begin
+ if fname = located(filename) then
+ data = IO.read(fname)
+ @data += data.gsub(/\%.*$/, '')
+ data.gsub!(/(\\patterns|\\hyphenation)\s*\{.*/mo) do '' end
+ @read += "\n% preamble of file #{fname}\n\n#{data}\n"
+ report("file #{fname} is loaded")
+ break # next fileset
+ end
+ rescue
+ report("file #{filename} is not readable")
+ end
+ end
+ end
+ end
+ rescue
+ end
+ end
+
+ def valid?
+ ! @data.empty?
+ end
+
+ def convert
+ if @data then
+ n = 0
+ @remapping.each do |k|
+ @data.gsub!(k[0]) do
+ # report("#{k[0]} => #{k[1]}")
+ n += 1
+ k[1]
+ end
+ end
+ report("#{n} changes in patterns and exceptions")
+ if @commandline.option('utf8') then
+ n = 0
+ @data.gsub!(/\[(.*?)\]/o) do
+ n += 1
+ @unicode[$1] || $1
+ end
+ report("#{n} unicode utf8 entries")
+ end
+ return true
+ else
+ return false
+ end
+ end
+
+ def comment(str)
+ str.gsub!(/^\n/o, '')
+ str.chomp!
+ if @commandline.option('xml') then
+ "<!-- #{str.strip} -->\n\n"
+ else
+ "% #{str.strip}\n\n"
+ end
+ end
+
+ def content(tag, str)
+ lst = str.split(/\s+/)
+ lst.collect! do |l|
+ l.strip
+ end
+ if lst.length>0 then
+ lst = "\n#{lst.join("\n")}\n"
+ else
+ lst = ""
+ end
+ if @commandline.option('xml') then
+ lst.gsub!(/\[(.*?)\]/o) do
+ "&#{$1};"
+ end
+ "<#{tag}>#{lst}</#{tag}>\n\n"
+ else
+ "\\#{tag} \{#{lst}\}\n\n"
+ end
+ end
+
+ def banner
+ if @commandline.option('xml') then
+ "<?xml version='1.0' standalone='yes' ?>\n\n"
+ end
+ end
+
+ def triggerunicode
+ if @commandline.option('utf8') then
+ "% xetex needs utf8 encoded patterns and for patterns\n" +
+ "% coded as such we need to enable this regime when\n" +
+ "% not in xetex; this code will be moved into context\n" +
+ "% as soon as we've spread the generic patterns\n" +
+ "\n" +
+ "\\ifx\\XeTeXversion\\undefined \\else\n" +
+ " \\ifx\\enableregime\\undefined \\else\n" +
+ " \\enableregime[utf]\n" +
+ " \\fi\n" +
+ "\\fi\n" +
+ "\n"
+ end
+ end
+
+ def save
+ xml = @commandline.option("xml")
+
+ patname = "lang-#{@language}.pat"
+ hypname = "lang-#{@language}.hyp"
+ 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 #{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
+ description = e.to_s
+ end
+ end
+ end
+ rescue
+ 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
+ str << "\n\nend of copy -->\n"
+ str.gsub!(/^/io, "% ") unless @commandline.option('xml')
+ description = comment("begin description data")
+ description << str + "\n"
+ description << comment("end description data")
+ report("description found for language #{@language}")
+ end
+ end
+
+ begin
+ if description.empty? || @commandline.option('log') then
+ if f = File.open(logname,'w') then
+ report("saving #{@remapping.length} remap patterns in #{logname}")
+ @remapping.each do |m|
+ f.puts("#{m[0].inspect} => #{m[1]}\n")
+ end
+ f.close
+ end
+ else
+ File.delete(logname) if FileTest.file?(logname)
+ end
+ rescue
+ end
+
+ begin
+ if description.empty? || @commandline.option('log') then
+ if f = File.open(rmename,'w') then
+ data = @read.dup
+ data.gsub!(/(\s*\n\s*)+/mo, "\n")
+ f << comment("comment copied from public hyphenation files}")
+ f << comment("source of data: #{@filenames.join(' ')}")
+ f << comment("begin original comment")
+ f << "#{data}\n"
+ f << comment("end original comment")
+ f.close
+ report("comment saved in file #{rmename}")
+ else
+ report("file #{rmename} is not writable")
+ end
+ else
+ File.delete(rmename) if FileTest.file?(rmename)
+ end
+ rescue
+ end
+
+ begin
+ if f = File.open(patname,'w') then
+ data = ''
+ @data.scan(/\\patterns\s*\{\s*(.*?)\s*\}/m) do
+ report("merging patterns")
+ data += $1 + "\n"
+ end
+ data.gsub!(/(\s*\n\s*)+/mo, "\n")
+
+ f << banner
+ f << comment("context pattern file, see #{commentfile} for original comment")
+ f << comment("source of data: #{@filenames.join(' ')}")
+ f << description
+ f << comment("begin pattern data")
+ f << triggerunicode
+ f << content('patterns', data)
+ f << comment("end pattern data")
+ f.close
+ report("patterns saved in file #{patname}")
+ else
+ report("file #{patname} is not writable")
+ end
+ rescue
+ report("problems with file #{patname}")
+ end
+
+ begin
+ if f = File.open(hypname,'w') then
+ data = ''
+ @data.scan(/\\hyphenation\s*\{\s*(.*?)\s*\}/m) do
+ report("merging exceptions")
+ data += $1 + "\n"
+ end
+ data.gsub!(/(\s*\n\s*)+/mo, "\n")
+ f << banner
+ f << comment("context hyphenation file, see #{commentfile} for original comment")
+ f << comment("source of data: #{@filenames.join(' ')}")
+ f << description
+ f << comment("begin hyphenation data")
+ f << triggerunicode
+ f << content('hyphenation', data)
+ f << comment("end hyphenation data")
+ f.close
+ report("exceptions saved in file #{hypname}")
+ else
+ report("file #{hypname} is not writable")
+ end
+ rescue
+ report("problems with file #{hypname}")
+ end
+ end
+
+ def process
+ load
+ if valid? then
+ convert
+ save
+ else
+ report("aborted due to missing files")
+ end
+ end
+
+ def Language::generate(commandline, language='', filenames='', encoding='ec')
+ if ! language.empty? && ! filenames.empty? then
+ commandline.report("processing language #{language}")
+ commandline.report("")
+ language = Language.new(commandline,language,filenames,encoding)
+ language.load
+ language.convert
+ language.save
+ commandline.report("")
+ end
+ end
+
+ private
+
+ def located(filename)
+ begin
+ fname = `kpsewhich -progname=context #{filename}`.chomp
+ if FileTest.file?(fname) then
+ report("using file #{fname}")
+ return fname
+ else
+ report("file #{filename} is not present")
+ return nil
+ end
+ rescue
+ report("file #{filename} cannot be located using kpsewhich")
+ return nil
+ end
+ end
+
+ def preload_accents
+
+ begin
+ if filename = located("enco-acc.tex") then
+ if data = IO.read(filename) then
+ report("preloading accent conversions")
+ data.scan(/\\defineaccent\s*\\*(.+?)\s*\{*(.+?)\}*\s*\{\\(.+?)\}/o) do
+ one, two, three = $1, $2, $3
+ one.gsub!(/[\`\~\!\^\*\_\-\+\=\:\;\"\'\,\.\?]/o) do
+ "\\#{one}"
+ end
+ remap(/\\#{one} #{two}/, "[#{three}]")
+ remap(/\\#{one}#{two}/, "[#{three}]") unless one =~ /[a-zA-Z]/o
+ remap(/\\#{one}\{#{two}\}/, "[#{three}]")
+ end
+ end
+ end
+ rescue
+ end
+
+ end
+
+ def preload_unicode
+
+ # \definecharacter Agrave {\uchar0{192}}
+
+ begin
+ if filename = located("enco-uc.tex") then
+ if data = IO.read(filename) then
+ report("preloading unicode conversions")
+ data.scan(/\\definecharacter\s*(.+?)\s*\{\\uchar\{*(\d+)\}*\s*\{(\d+)\}/o) do
+ one, two, three = $1, $2.to_i, $3.to_i
+ @unicode[one] = [(two*256 + three)].pack("U")
+ end
+ end
+ end
+ rescue
+ report("error in loading unicode mapping (#{$!})")
+ end
+
+ end
+
+ def preload_vector(encoding='')
+
+ # funny polish
+
+ case @language
+ when 'pl' then
+ remap(/\/a/, "[aogonek]") ; remap(/\/A/, "[Aogonek]")
+ remap(/\/c/, "[cacute]") ; remap(/\/C/, "[Cacute]")
+ remap(/\/e/, "[eogonek]") ; remap(/\/E/, "[Eogonek]")
+ remap(/\/l/, "[lstroke]") ; remap(/\/L/, "[Lstroke]")
+ remap(/\/n/, "[nacute]") ; remap(/\/N/, "[Nacute]")
+ remap(/\/o/, "[oacute]") ; remap(/\/O/, "[Oacute]")
+ remap(/\/s/, "[sacute]") ; remap(/\/S/, "[Sacute]")
+ remap(/\/x/, "[zacute]") ; remap(/\/X/, "[Zacute]")
+ remap(/\/z/, "[zdotaccent]") ; remap(/\/Z/, "[Zdotaccent]")
+ when 'sl' then
+ remap(/\"c/,"[ccaron]") ; remap(/\"C/,"[Ccaron]")
+ remap(/\"s/,"[scaron]") ; remap(/\"S/,"[Scaron]")
+ remap(/\"z/,"[zcaron]") ; remap(/\"Z/,"[Zcaron]")
+ when 'da' then
+ remap(/X/, "[aeligature]")
+ remap(/Y/, "[ostroke]")
+ remap(/Z/, "[aring]")
+ when 'ca' then
+ remap(/\\c\{.*?\}/, "")
+ when 'de', 'deo' then
+ remap(/\\c\{.*?\}/, "")
+ remap(/\\n\{\}/, "")
+ remap(/\\3/, "[ssharp]")
+ remap(/\\9/, "[ssharp]")
+ remap(/\"a/, "[adiaeresis]")
+ remap(/\"o/, "[odiaeresis]")
+ remap(/\"u/, "[udiaeresis]")
+ when 'fr' then
+ remap(/\\ae/, "[adiaeresis]")
+ remap(/\\oe/, "[odiaeresis]")
+ when 'la' then
+ # \lccode`'=`' somewhere else, todo
+ remap(/\\c\{.*?\}/, "")
+ remap(/\\a\s*/, "[aeligature]")
+ remap(/\\o\s*/, "[oeligature]")
+ else
+ end
+
+ if ! encoding.empty? then
+ begin
+ filename = `kpsewhich -progname=context enco-#{encoding}.tex`
+ if data = IO.read(filename.chomp) then
+ report("preloading #{encoding} character mappings")
+ data.scan(/\\definecharacter\s*([a-zA-Z]+)\s*(\d+)\s*/o) do
+ name, number = $1, $2
+ remap(/\^\^#{sprintf("%02x",number)}/, "[#{name}]")
+ end
+ end
+ rescue
+ end
+ end
+
+ end
+
+end
+
+class Commands
+
+ include CommandBase
+
+ public
+
+ @@languagedata = Hash.new
+
+ def patternfiles
+ language = @commandline.argument('first')
+ if (language == 'all') || language.empty? then
+ languages = @@languagedata.keys.sort
+ elsif @@languagedata.key?(language) then
+ languages = [language]
+ else
+ languages = []
+ end
+ languages.each do |language|
+ encoding = @@languagedata[language][0] || ''
+ files = @@languagedata[language][1] || []
+ Language::generate(self,language,files,encoding)
+ end
+ end
+
+ private
+
+ # todo: filter the fallback list from context
+
+ # The first entry in the array is the encoding which will be used
+ # when interpreting th eraw patterns. The second entry is a list of
+ # filesets (string|aray), each first match of a set is taken.
+
+ @@languagedata['ba' ] = [ 'ec' , ['bahyph.tex'] ]
+ @@languagedata['ca' ] = [ 'ec' , ['cahyph.tex'] ]
+ @@languagedata['cy' ] = [ 'ec' , ['cyhyph.tex'] ]
+ @@languagedata['cz' ] = [ 'ec' , ['czhyphen.tex','czhyphen.ex'] ]
+ @@languagedata['de' ] = [ 'ec' , ['dehyphn.tex'] ]
+ @@languagedata['deo'] = [ 'ec' , ['dehypht.tex'] ]
+ @@languagedata['da' ] = [ 'ec' , ['dkspecial.tex','dkcommon.tex'] ]
+ # elhyph.tex
+ @@languagedata['es' ] = [ 'ec' , ['eshyph.tex'] ]
+ @@languagedata['fi' ] = [ 'ec' , ['ethyph.tex'] ]
+ @@languagedata['fi' ] = [ 'ec' , ['fihyph.tex'] ]
+ @@languagedata['fr' ] = [ 'ec' , ['frhyph.tex'] ]
+ # ghyphen.readme ghyph31.readme grphyph
+ @@languagedata['hr' ] = [ 'ec' , ['hrhyph.tex'] ]
+ @@languagedata['hu' ] = [ 'ec' , ['huhyphn.tex'] ]
+ @@languagedata['en' ] = [ 'default' , [['ushyphmax.tex','ushyph.tex','hyphen.tex']] ]
+ # inhyph.tex
+ @@languagedata['is' ] = [ 'ec' , ['ishyph.tex'] ]
+ @@languagedata['it' ] = [ 'ec' , ['ithyph.tex'] ]
+ @@languagedata['la' ] = [ 'ec' , ['lahyph.tex'] ]
+ # mnhyph
+ @@languagedata['nl' ] = [ 'ec' , ['nehyph96.tex'] ]
+ @@languagedata['no' ] = [ 'ec' , ['nohyph.tex'] ]
+ # oldgrhyph.tex
+ @@languagedata['pl' ] = [ 'ec' , ['plhyph.tex'] ]
+ @@languagedata['pt' ] = [ 'ec' , ['pthyph.tex'] ]
+ @@languagedata['ro' ] = [ 'ec' , ['rohyph.tex'] ]
+ @@languagedata['sl' ] = [ 'ec' , ['sihyph.tex'] ]
+ @@languagedata['sk' ] = [ 'ec' , ['skhyphen.tex','skhyphen.ex'] ]
+ # sorhyph.tex / upper sorbian
+ # srhyphc.tex / cyrillic
+ @@languagedata['sv' ] = [ 'ec' , ['svhyph.tex'] ]
+ @@languagedata['tr' ] = [ 'ec' , ['tkhyph.tex'] ]
+ @@languagedata['uk' ] = [ 'default' , [['ukhyphen.tex','ukhyph.tex']] ]
+
+end
+
+class Commands
+
+ include CommandBase
+
+ def dpxmapfiles
+
+ force = @commandline.option("force")
+
+ texmfroot = @commandline.argument('first')
+ texmfroot = '.' if texmfroot.empty?
+ maproot = "#{texmfroot}/fonts/map/pdftex/context"
+
+ if File.directory?(maproot) then
+ if files = Dir.glob("#{maproot}/*.map") and files.size > 0 then
+ files.each do |pdffile|
+ next if File.basename(pdffile) == 'pdftex.map'
+ pdffile = File.expand_path(pdffile)
+ dpxfile = File.expand_path(pdffile.sub(/pdftex/i,'dvipdfm'))
+ unless pdffile == dpxfile then
+ begin
+ if data = File.read(pdffile) then
+ report("< #{File.basename(pdffile)} - pdf(e)tex")
+ n = 0
+ data = data.collect do |line|
+ if line =~ /^[\%\#]+/mo then
+ ''
+ else
+ encoding = if line =~ /([a-z0-9\-]+)\.enc/io then $1 else '' end
+ fontfile = if line =~ /([a-z0-9\-]+)\.(pfb|ttf)/io then $1 else nil end
+ metrics = if line =~ /^([a-z0-9\-]+)[\s\<]+/io then $1 else nil end
+ slant = if line =~ /\"([\d\.]+)\s+SlantFont\"/io then "-s #{$1}" else '' end
+ if metrics && encoding && fontfile then
+ n += 1
+ "#{metrics} #{encoding} #{fontfile} #{slant}"
+ else
+ ''
+ end
+ end
+ end
+ data.delete_if do |line|
+ line.gsub(/\s+/,'').empty?
+ end
+ begin
+ if force then
+ if n > 0 then
+ File.makedirs(File.dirname(dpxfile))
+ if f = File.open(dpxfile,'w') then
+ report("> #{File.basename(dpxfile)} - dvipdfm(x) - #{n}")
+ f.puts(data)
+ f.close
+ else
+ report("? #{File.basename(dpxfile)} - dvipdfm(x)")
+ end
+ else
+ report("- #{File.basename(dpxfile)} - dvipdfm(x)")
+ begin File.delete(dpxname) ; rescue ; end
+ end
+ else
+ report(". #{File.basename(dpxfile)} - dvipdfm(x) - #{n}")
+ end
+ rescue
+ report("error in saving dvipdfm file")
+ end
+ else
+ report("error in loading pdftex file")
+ end
+ rescue
+ report("error in processing pdftex file")
+ end
+ end
+ end
+ if force then
+ begin
+ report("regenerating database for #{texmfroot}")
+ system("mktexlsr #{texmfroot}")
+ rescue
+ end
+ end
+ else
+ report("no mapfiles found in #{maproot}")
+ end
+ else
+ report("provide proper texmfroot")
+ end
+
+ end
+
+end
+
+class Commands
+
+ include CommandBase
+
+ # usage : ctxtools --listentities entities.xml
+ # document: <!DOCTYPE something SYSTEM "entities.xml">
+
+ def flushentities(handle,entities,doctype=nil) # 'stylesheet'
+ tab = if doctype then "\t" else "" end
+ handle.puts("<!DOCTYPE #{doctype} [") if doctype
+ entities.keys.sort.each do |k|
+ handle.puts("#{tab}<!ENTITY #{k} \"\&\##{entities[k]};\">")
+ end
+ handle.puts("]>") if doctype
+ end
+
+ def listentities
+
+ # filename = `texmfstart tmftools.rb --progname=context enco-uc.tex`.chomp
+ filename = `kpsewhich --progname=context enco-uc.tex`.chomp
+ outputname = @commandline.argument('first')
+
+ if filename and not filename.empty? and FileTest.file?(filename) then
+ entities = Hash.new
+ IO.readlines(filename).each do |line|
+ if line =~ /\\definecharacter\s+([a-zA-Z]+)\s+\{\\uchar\{*(\d+)\}*\{(\d+)\}\}/o then
+ name, low, high = $1, $2.to_i, $3.to_i
+ entities[name] = low*256 + high
+ end
+ end
+ if outputname and not outputname.empty? then
+ if f = File.open(outputname,'w') then
+ flushentities(f,entities)
+ f.close
+ else
+ flushentities($stdout,entities)
+ end
+ else
+ flushentities($stdout,entities)
+ end
+ end
+
+ end
+
+end
+
+
+logger = Logger.new(banner.shift)
+commandline = CommandLine.new
+
+commandline.registeraction('touchcontextfile', 'update context version')
+commandline.registeraction('contextversion', 'report context version')
+
+commandline.registeraction('jeditinterface', 'generate jedit syntax files [--pipe]')
+commandline.registeraction('bbeditinterface', 'generate bbedit syntax files [--pipe]')
+commandline.registeraction('sciteinterface', 'generate scite syntax files [--pipe]')
+commandline.registeraction('rawinterface', 'generate raw syntax files [--pipe]')
+
+commandline.registeraction('translateinterface', 'generate interface files (xml) [nl de ..]')
+commandline.registeraction('purgefiles', 'remove temporary files [--all --recurse] [basename]')
+
+commandline.registeraction('documentation', 'generate documentation [--type=] [filename]')
+
+commandline.registeraction('filterpages') # no help, hidden temporary feature
+commandline.registeraction('purgeallfiles') # no help, compatibility feature
+
+commandline.registeraction('patternfiles', 'generate pattern files [--all --xml --utf8] [languagecode]')
+
+commandline.registeraction('dpxmapfiles', 'convert pdftex mapfiles to dvipdfmx [--force] [texmfroot]')
+commandline.registeraction('listentities', 'create doctype entity definition from enco-uc.tex')
+
+commandline.registervalue('type','')
+
+commandline.registerflag('recurse')
+commandline.registerflag('force')
+commandline.registerflag('pipe')
+commandline.registerflag('all')
+commandline.registerflag('xml')
+commandline.registerflag('log')
+commandline.registerflag('utf8')
+
+# general
+
+commandline.registeraction('help')
+commandline.registeraction('version')
+
+commandline.expand
+
+Commands.new(commandline,logger,banner).send(commandline.action || 'help')
diff --git a/Master/texmf-dist/scripts/context/ruby/fcd_start.rb b/Master/texmf-dist/scripts/context/ruby/fcd_start.rb
new file mode 100644
index 00000000000..8ac48f79e8c
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/fcd_start.rb
@@ -0,0 +1,453 @@
+# Hans Hagen / PRAGMA ADE / 2005 / www.pragma-ade.com
+#
+# Fast Change Dir
+#
+# This is a kind of variant of the good old ncd
+# program. This script uses the same indirect cmd
+# trick as Erwin Waterlander's wcd program.
+#
+# === windows: fcd.cmd ===
+#
+# @echo off
+# ruby -S fcd_start.rb %1 %2 %3 %4 %5 %6 %7 %8 %9
+# if exist "%HOME%/fcd_stage.cmd" call %HOME%/fcd_stage.cmd
+#
+# === linux: fcd (fcd.sh) ===
+#
+# !/usr/bin/env sh
+# ruby -S fcd_start.rb $1 $2 $3 $4 $5 $6 $7 $8 $9
+# if test -f "$HOME/fcd_stage.sh" ; then
+# . $HOME/fcd_stage.sh ;
+# fi;
+#
+# ===
+#
+# On linux, one should source the file: ". fcd args" in order
+# to make the chdir persistent.
+#
+# You can create a stub with:
+#
+# ruby fcd_start.rb --stub --verbose
+#
+# usage:
+#
+# fcd --make t:\
+# fcd --add f:\project
+# fcd [--find] whatever
+# fcd [--find] whatever c (c being a list entry)
+# fcd [--find] whatever . (last choice with this pattern)
+# fcd --list
+
+require 'rbconfig'
+
+class FastCD
+
+ @@rootpath = nil
+
+ ['HOME','TEMP','TMP','TMPDIR'].each do |key|
+ if ENV[key] then
+ if FileTest.directory?(ENV[key]) then
+ @@rootpath = ENV[key]
+ break
+ end
+ end
+ end
+
+ exit unless @@rootpath
+
+ @@mswindows = Config::CONFIG['host_os'] =~ /mswin/
+ @@maxlength = 26
+
+ require 'Win32API' if @@mswindows
+
+ if @@mswindows then
+ @@stubcode = [
+ '@echo off',
+ '',
+ 'if not exist "%HOME%" goto temp',
+ '',
+ ':home',
+ '',
+ 'ruby -S fcd_start.rb %1 %2 %3 %4 %5 %6 %7 %8 %9',
+ '',
+ 'if exist "%HOME%\fcd_stage.cmd" call %HOME%\fcd_stage.cmd',
+ 'goto end',
+ '',
+ ':temp',
+ '',
+ 'ruby -S fcd_start.rb %1 %2 %3 %4 %5 %6 %7 %8 %9',
+ '',
+ 'if exist "%TEMP%\fcd_stage.cmd" call %TEMP%\fcd_stage.cmd',
+ 'goto end',
+ '',
+ ':end'
+ ].join("\n")
+ else
+ @@stubcode = [
+ '#!/usr/bin/env sh',
+ '',
+ 'ruby -S fcd_start.rb $1 $2 $3 $4 $5 $6 $7 $8 $9',
+ '',
+ 'if test -f "$HOME/fcd_stage.sh" ; then',
+ ' . $HOME/fcd_stage.sh ;',
+ 'fi;'
+ ].join("\n")
+ end
+
+ @@selfpath = File.dirname($0)
+ @@datafile = File.join(@@rootpath,'fcd_state.dat')
+ @@histfile = File.join(@@rootpath,'fcd_state.his')
+ @@cdirfile = File.join(@@rootpath,if @@mswindows then 'fcd_stage.cmd' else 'fcd_stage.sh' end)
+ @@stubfile = File.join(@@selfpath,if @@mswindows then 'fcd.cmd' else 'fcd' end)
+
+ def initialize(verbose=false)
+ @list = Array.new
+ @hist = Hash.new
+ @result = Array.new
+ @pattern = ''
+ @result = ''
+ @verbose = verbose
+ if f = File.open(@@cdirfile,'w') then
+ f << "#{if @@mswindows then 'rem' else '#' end} no dir to change to"
+ f.close
+ else
+ report("unable to create stub #{@@cdirfile}")
+ end
+ end
+
+ def filename(name)
+ File.join(@@root,name)
+ end
+
+ def report(str,verbose=@verbose)
+ puts(">> #{str}") if verbose
+ end
+
+ def flush(str,verbose=@verbose)
+ print(str) if verbose
+ end
+
+ def clear
+ if FileTest.file?(@@histfile)
+ begin
+ File.delete(@@histfile)
+ rescue
+ report("error in deleting history file '#{@histfile}'")
+ else
+ report("history file '#{@histfile}' is deleted")
+ end
+ else
+ report("no history file '#{@histfile}'")
+ end
+ end
+
+ def scan(dir='.')
+ begin
+ [dir].flatten.sort.uniq.each do |dir|
+ begin
+ Dir.chdir(dir)
+ report("scanning '#{dir}'")
+ # flush(">> ")
+ Dir.glob("**/*").each do |d|
+ if FileTest.directory?(d) then
+ @list << File.expand_path(d)
+ # flush(".")
+ end
+ end
+ # flush("\n")
+ @list = @list.sort.uniq
+ report("#{@list.size} entries found")
+ rescue
+ report("unknown directory '#{dir}'")
+ end
+ end
+ rescue
+ report("invalid dir specification ")
+ end
+ end
+
+ def save
+ begin
+ if f = File.open(@@datafile,'w') then
+ @list.each do |l|
+ f.puts(l)
+ end
+ f.close
+ report("#{@list.size} status bytes saved in #{@@datafile}")
+ else
+ report("unable to save status in #{@@datafile}")
+ end
+ rescue
+ report("error in saving status in #{@@datafile}")
+ end
+ end
+
+ def remember
+ if @hist[@pattern] == @result then
+ # no need to save result
+ else
+ begin
+ if f = File.open(@@histfile,'w') then
+ @hist[@pattern] = @result
+ @hist.keys.each do |k|
+ f.puts("#{k} #{@hist[k]}")
+ end
+ f.close
+ report("#{@hist.size} history entries saved in #{@@histfile}")
+ else
+ report("unable to save history in #{@@histfile}")
+ end
+ rescue
+ report("error in saving history in #{@@histfile}")
+ end
+ end
+ end
+
+ def load
+ begin
+ @list = IO.read(@@datafile).split("\n")
+ report("#{@list.length} status bytes loaded from #{@@datafile}")
+ rescue
+ report("error in loading status from #{@@datafile}")
+ end
+ begin
+ IO.readlines(@@histfile).each do |line|
+ if line =~ /^(.*?)\s+(.*)$/i then
+ @hist[$1] = $2
+ end
+ end
+ report("#{@hist.length} history entries loaded from #{@@histfile}")
+ rescue
+ report("error in loading history from #{@@histfile}")
+ end
+ end
+
+ def show
+ begin
+ puts("directories:")
+ puts("\n")
+ if @list.length > 0 then
+ @list.each do |l|
+ puts(l)
+ end
+ else
+ puts("no entries")
+ end
+ puts("\n")
+ puts("history:")
+ puts("\n")
+ if @hist.length > 0 then
+ @hist.keys.sort.each do |h|
+ puts("#{h} >> #{@hist[h]}")
+ end
+ else
+ puts("no entries")
+ end
+ rescue
+ end
+ end
+
+ def find(pattern=nil)
+ begin
+ if pattern = [pattern].flatten.first then
+ if pattern.length > 0 and @pattern = pattern then
+ @result = @list.grep(/\/#{@pattern}$/i)
+ if @result.length == 0 then
+ @result = @list.grep(/\/#{@pattern}[^\/]*$/i)
+ end
+ end
+ end
+ rescue
+ end
+ end
+
+ def chdir(dir)
+ begin
+ if dir then
+ if f = File.open(@@cdirfile,'w') then
+ if @@mswindows then
+ f.puts("cd /d #{dir.gsub('/','\\')}")
+ else
+ f.puts("cd #{dir.gsub("\\",'/')}")
+ end
+ end
+ @result = dir
+ report("changing to #{dir}",true)
+ else
+ report("not changing dir")
+ end
+ rescue
+ end
+ end
+
+ def choose(args=[])
+ unless @pattern.empty? then
+ begin
+ case @result.size
+ when 0 then
+ report("dir '#{@pattern}' not found",true)
+ when 1 then
+ chdir(@result[0])
+ else
+ list = @result.dup
+ begin
+ if answer = args[1] then # assignment & test
+ if answer == '.' and @hist.key?(@pattern) then
+ if FileTest.directory?(@hist[@pattern]) then
+ print("last choice ")
+ chdir(@hist[@pattern])
+ return
+ end
+ else
+ index = answer[0] - ?a
+ if dir = list[index] then
+ chdir(dir)
+ return
+ end
+ end
+ end
+ rescue
+ end
+ loop do
+ print("\n")
+ list.each_index do |i|
+ if i < @@maxlength then
+ puts("#{(i+?a).chr} #{list[i]}")
+ else
+ puts("\n there are #{list.length-@@maxlength} entries more")
+ break
+ end
+ end
+ print("\n>> ")
+ if answer = wait then
+ if answer >= ?a and answer <= ?z then
+ index = answer - ?a
+ if dir = list[index] then
+ print("#{answer.chr} ")
+ chdir(dir)
+ elsif @hist.key?(@pattern) and FileTest.directory?(@hist[@pattern]) then
+ print("last choice ")
+ chdir(@hist[@pattern])
+ else
+ print("quit\n")
+ end
+ break
+ elsif list.length >= @@maxlength then
+ @@maxlength.times do |i| list.shift end
+ print("next set")
+ print("\n")
+ elsif @hist.key?(@pattern) and FileTest.directory?(@hist[@pattern]) then
+ print("last choice ")
+ chdir(@hist[@pattern])
+ break
+ else
+ print("quit\n")
+ break
+ end
+ end
+ end
+ end
+ rescue
+ # report($!)
+ end
+ end
+ end
+
+ def wait
+ begin
+ $stdout.flush
+ return getc
+ rescue
+ return nil
+ end
+ end
+
+ def getc
+ begin
+ if @@mswindows then
+ ch = Win32API.new('crtdll','_getch',[],'L').call
+ else
+ system('stty raw -echo')
+ ch = $stdin.getc
+ system('stty -raw echo')
+ end
+ rescue
+ ch = nil
+ end
+ return ch
+ end
+
+ def check
+ unless FileTest.file?(@@stubfile) then
+ report("creating stub #{@@stubfile}")
+ begin
+ if f = File.open(@@stubfile,'w') then
+ f.puts(@@stubcode)
+ f.close
+ end
+ rescue
+ report("unable to create stub #{@@stubfile}")
+ else
+ unless @mswindows then
+ begin
+ File.chmod(0755,@@stubfile)
+ rescue
+ report("unable to change protections on #{@@stubfile}")
+ end
+ end
+ end
+ else
+ report("stub #{@@stubfile} already present")
+ end
+ end
+
+end
+
+verbose, action, args = false, :find, Array.new
+
+usage = "fcd [--make|add|show|find] [--verbose] [pattern]"
+
+ARGV.each do |a|
+ case a
+ when '-v', '--verbose' then verbose = true
+ when '-m', '--make' then action = :make
+ when '-c', '--clear' then action = :clear
+ when '-a', '--add' then action = :add
+ when '-s', '--show' then action = :show
+ when '-l', '--list' then action = :show
+ when '-f', '--find' then action = :find
+ when '--stub' then action = :stub
+ when '-h', '--help' then puts "usage: #{usage}" ; exit
+ when /^\-\-.*/ then puts "unknown switch: #{a}" + "\n" + "usage: #{usage}" ; exit
+ else args << a
+ end
+end
+
+$stdout.sync = true
+
+fcd = FastCD.new(verbose)
+
+fcd.report("Fast Change Dir / version 1.0")
+
+case action
+ when :make then
+ fcd.clear
+ fcd.scan(args)
+ fcd.save
+ when :clear then
+ fcd.clear
+ when :add then
+ fcd.load
+ fcd.scan(args)
+ fcd.save
+ when :show then
+ fcd.load
+ fcd.show
+ when :find then
+ fcd.load
+ fcd.find(args)
+ fcd.choose(args)
+ fcd.remember
+ when :stub
+ fcd.check
+end
diff --git a/Master/texmf-dist/scripts/context/ruby/graphics/gs.rb b/Master/texmf-dist/scripts/context/ruby/graphics/gs.rb
new file mode 100644
index 00000000000..807cad10ccd
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/graphics/gs.rb
@@ -0,0 +1,641 @@
+# 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("fatal error: #{$!}")
+ 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, ''
+
+ while str = eps.gets(rs=@rs) do
+ if str =~ /^%!PS/oi then
+ debug("looks like a valid ps file")
+ break
+ elsif str =~ /%PDF\-\d+\.\d+/oi then
+ debug("looks like a pdf file, so let\'s quit")
+ return false
+ end
+ end
+
+ debug('locating boundingbox')
+
+ # why no BeginData check
+
+ eps.rewind
+
+ while str = eps.gets(rs=@rs) do
+ case str
+ when /^%%Page:/io then
+ break
+ when /^%%(Crop|HiResBounding|ExactBounding)Box:#{@@bboxspec}/moi then
+ debug('high res boundingbox found')
+ setdimensions($2,$3,$4,$5)
+ break
+ when /^%%BoundingBox:#{@@bboxspec}/moi then
+ debug('low res boundingbox found')
+ setdimensions($1,$2,$3,$4)
+ end
+ end
+
+ debug('no boundingbox found') if @width == 0
+
+ eps.rewind
+
+ while str = eps.gets(rs=@rs) do
+ if str.sub!(/^(.*)%!PS/moi, "%!PS") then
+ debug("removing pre banner data")
+ out.puts(str)
+ break
+ end
+ end
+
+ 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/Master/texmf-dist/scripts/context/ruby/graphics/inkscape.rb b/Master/texmf-dist/scripts/context/ruby/graphics/inkscape.rb
new file mode 100644
index 00000000000..4495c3070f4
--- /dev/null
+++ b/Master/texmf-dist/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/Master/texmf-dist/scripts/context/ruby/graphics/magick.rb b/Master/texmf-dist/scripts/context/ruby/graphics/magick.rb
new file mode 100644
index 00000000000..f59087bdf44
--- /dev/null
+++ b/Master/texmf-dist/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/Master/texmf-dist/scripts/context/ruby/mpstools.rb b/Master/texmf-dist/scripts/context/ruby/mpstools.rb
new file mode 100644
index 00000000000..6dc0c35ad0c
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/mpstools.rb
@@ -0,0 +1,5 @@
+# todo
+
+puts("This program is yet unfinished, for the moment it just calls 'mptopdf'.\n\n")
+
+system("texmfstart mptopdf #{ARGV.join(' ')}")
diff --git a/Master/texmf-dist/scripts/context/ruby/newimgtopdf.rb b/Master/texmf-dist/scripts/context/ruby/newimgtopdf.rb
new file mode 100644
index 00000000000..3c1636cf2bc
--- /dev/null
+++ b/Master/texmf-dist/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/Master/texmf-dist/scripts/context/ruby/newpstopdf.rb b/Master/texmf-dist/scripts/context/ruby/newpstopdf.rb
new file mode 100644
index 00000000000..898f987cbce
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/newpstopdf.rb
@@ -0,0 +1,530 @@
+#!/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)
+# --method=crop|bounded|raw|...
+# --resolution=low|normal|medium|high|printer|print|screen|ebook|default
+# + downward compatible flag handling
+
+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/Master/texmf-dist/scripts/context/ruby/newtexexec.rb b/Master/texmf-dist/scripts/context/ruby/newtexexec.rb
new file mode 100644
index 00000000000..27f8eeed96f
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/newtexexec.rb
@@ -0,0 +1,609 @@
+banner = ['TeXExec', 'version 6.1.0', '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 'base/texutil'
+
+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(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 main
+ if @commandline.arguments.length>0 then
+ process
+ else
+ help
+ 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 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('nooptionfile',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", true)
+ 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('nooptionfile',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
+ if job = TEX.new(logger) then
+ prepare(job)
+ job.cleanuptemprunfiles
+ files = @commandline.arguments.sort
+ msuffixes = ['tex','mp','pl','pm','rb']
+ 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
+ # will become a call to ctxtools
+ job.runtexutil(ffname,"--documents", true)
+ 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('nooptionfile',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', '0cm')
+ textwidth = @commandline.checkedoption('textwidth', '0cm')
+ backspace = @commandline.checkedoption('backspace', '0cm')
+ topspace = @commandline.checkedoption('topspace', '0cm')
+ 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('nooptionfile',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', '0cm')
+ textwidth = @commandline.checkedoption('textwidth', '0cm')
+ backspace = @commandline.checkedoption('backspace', '0cm')
+ topspace = @commandline.checkedoption('topspace', '0cm')
+ paperformat = @commandline.checkedoption('paperformat', 'A4*A4').split(/[\*x]/o)
+ from, to = paperformat[0] || 'A4', paperformat[1] || paperformat[0] || 'A4'
+ if from == 'fit' or to == 'fit' then
+ f << "\\getfiguredimensions[#{files.first}]\n"
+ if from == 'fit' then
+ f << "\\expanded{\\definepapersize[from-fit][width=\\figurewidth,height=\\figureheight]}\n"
+ from = 'from-fit'
+ end
+ if to == 'fit' then
+ f << "\\expanded{\\definepapersize[to-fit][width=\\figurewidth,height=\\figureheight]}\n"
+ to = 'to-fit'
+ end
+ end
+ job.setvariable('paperformat','') # else overloaded later on
+ 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('nooptionfile',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', '0cm')
+ 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('nooptionfile',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', '0cm')
+ 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('nooptionfile',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')
+ elsif @commandline.oneof('dvips','ps') then
+ job.setvariable('backend','dvips')
+ else
+ job.setvariable('backend','standard')
+ end
+
+ if (str = @commandline.option('engine')) && ! str.standard? && ! str.empty? then
+ job.setvariable('mpsengine',@commandline.option('engine'))
+ else
+ job.setvariable('mpsengine','standard')
+ end
+
+ end
+
+ def cleantexfilename(filename)
+ filename.gsub(/([\$\_\#])/) do "\\$1" end.gsub(/([\~])/) do "\\string$1" end
+ end
+
+end
+
+logger = Logger.new(banner.shift)
+commandline = CommandLine.new
+
+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('dvips')
+commandline.registerflag('ps')
+
+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/Master/texmf-dist/scripts/context/ruby/newtexutil.rb b/Master/texmf-dist/scripts/context/ruby/newtexutil.rb
new file mode 100644
index 00000000000..af003a8e7b2
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/newtexutil.rb
@@ -0,0 +1,96 @@
+banner = ['TeXUtil ', 'version 9.1.0', '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/file'
+require 'base/texutil'
+
+class Commands
+
+ include CommandBase
+
+ def references
+ filename = @commandline.argument('first')
+ if not filename.empty? and FileTest.file?(File.suffixed(filename,'tuo')) then
+ if tu = TeXUtil::Converter.new(logger) and tu.loaded(filename) then
+ tu.saved if tu.processed
+ end
+ end
+ end
+
+ def main
+ if @commandline.arguments.length>0 then
+ references
+ else
+ help
+ end
+ end
+
+ def purgefiles
+ system("texmfstart ctxtools --purge #{@commandline.argument.join(' ')}")
+ end
+
+ def purgeallfiles
+ system("texmfstart ctxtools --purgeall #{@commandline.argument.join(' ')}")
+ end
+
+ def documentation
+ system("texmfstart ctxtools --document #{@commandline.argument.join(' ')}")
+ end
+
+ def analyzefile
+ system("texmfstart pdftools --analyze #{@commandline.argument.join(' ')}")
+ end
+
+ def filterpages # obsolete
+ system("texmfstart ctxtools --purge #{@commandline.argument.join(' ')}")
+ end
+
+ def figures
+ report("this code is not yet converted from perl to ruby")
+ end
+
+ def logfile
+ report("this code is not yet converted from perl to ruby")
+ end
+
+end
+
+logger = Logger.new(banner.shift)
+commandline = CommandLine.new
+
+# main feature
+
+commandline.registeraction('references', 'convert tui file into tuo file')
+
+# todo features
+
+commandline.registeraction('figures', 'generate figure dimensions file')
+commandline.registeraction('logfile', 'filter essential log messages')
+
+# backward compatibility features
+
+commandline.registeraction('purgefiles', 'remove most temporary files')
+commandline.registeraction('purgeallfiles', 'remove all temporary files')
+commandline.registeraction('documentation', 'generate documentation file from source')
+commandline.registeraction('analyzefile', 'analyze pdf file')
+
+# old feature, not needed any longer due to extension of pdftex
+
+commandline.registeraction('filterpages')
+
+# generic features
+
+commandline.registeraction('help')
+commandline.registeraction('version')
+
+commandline.registerflag('verbose')
+
+commandline.expand
+
+Commands.new(commandline,logger,banner).send(commandline.action || 'main')
diff --git a/Master/texmf-dist/scripts/context/ruby/rlxtools.rb b/Master/texmf-dist/scripts/context/ruby/rlxtools.rb
new file mode 100644
index 00000000000..7962474eb10
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/rlxtools.rb
@@ -0,0 +1,262 @@
+#!/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!(/&lt;/o, '<')
+ str.gsub!(/&gt;/o, '>')
+ str.gsub!(/&amp;/o, '&')
+ str.gsub!(/&quot;/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/Master/texmf-dist/scripts/context/ruby/texmfstart.rb b/Master/texmf-dist/scripts/context/ruby/texmfstart.rb
new file mode 100644
index 00000000000..dc166bf92c3
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/texmfstart.rb
@@ -0,0 +1,847 @@
+#!/usr/bin/env ruby
+
+# program : texmfstart
+# copyright : PRAGMA Advanced Document Engineering
+# version : 1.5.5 - 2003/2005
+# author : Hans Hagen
+#
+# project : ConTeXt / eXaMpLe
+# info : j.hagen@xs4all.nl
+# www : www.pragma-pod.com / www.pragma-ade.com
+
+# no special requirements, i.e. no exa modules/classes used
+
+# texmfstart [switches] filename [optional arguments]
+#
+# ruby2exe texmfstart --help -> avoids stub test
+#
+# Of couse I can make this into a nice class, which i'll undoubtely will
+# do when I feel the need. In that case it will be part of a bigger game.
+
+# turning this into a service would be nice, so some day ...
+
+# --locate => provides location
+# --exec => exec instead of system
+# --iftouched=a,b => only if timestamp a<>b
+#
+# file: path: bin:
+
+# texmfstart --exec bin:scite *.tex
+
+# we don't depend on other libs
+
+$ownpath = File.expand_path(File.dirname($0)) unless defined? $ownpath
+
+require "rbconfig"
+
+$mswindows = Config::CONFIG['host_os'] =~ /mswin/
+$separator = File::PATH_SEPARATOR
+$version = "1.6.2"
+
+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['lua'] = 'LUAINPUTS'
+$suffixinputs['jar'] = 'JAVAINPUTS'
+$suffixinputs['pdf'] = 'PDFINPUTS'
+
+$predefined['texexec'] = 'texexec.pl'
+$predefined['texutil'] = 'texutil.pl'
+$predefined['texfont'] = 'texfont.pl'
+
+$predefined['mptopdf'] = 'mptopdf.pl'
+$predefined['pstopdf'] = 'pstopdf.rb'
+
+$predefined['examplex'] = 'examplex.rb'
+$predefined['concheck'] = 'concheck.rb'
+
+$predefined['textools'] = 'textools.rb'
+$predefined['tmftools'] = 'tmftools.rb'
+$predefined['ctxtools'] = 'ctxtools.rb'
+$predefined['rlxtools'] = 'rlxtools.rb'
+$predefined['pdftools'] = 'pdftools.rb'
+$predefined['mpstools'] = 'mpstools.rb'
+$predefined['exatools'] = 'exatools.rb'
+$predefined['xmltools'] = 'xmltools.rb'
+
+
+if ENV['TEXMFSTART_MODE'] = 'experimental' then
+ $predefined['texexec'] = 'newtexexec.rb'
+ $predefined['pstopdf'] = 'newpstopdf.rb'
+end
+
+$scriptlist = 'rb|pl|py|lua|jar'
+$documentlist = 'pdf|ps|eps|htm|html'
+
+$editor = ENV['EDITOR'] || ENV['editor'] || 'scite'
+
+$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['lua'] = $applications['lua'] = 'lua'
+$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')
+
+ def dowith_pathname (filename,filemethod)
+ filename = filename.gsub(/\\/o,'/') # no gsub! because filename can be frozen
+ 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 longpathname (filename)
+ dowith_pathname(filename,GetLongPathName)
+ end
+
+ def shortpathname (filename)
+ dowith_pathname(filename,GetShortPathName)
+ end
+
+else
+
+ def longpathname (filename)
+ filename
+ end
+
+ def shortpathname (filename)
+ filename
+ end
+
+end
+
+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.timestamp(name)
+ begin
+ "#{File.stat(name).mtime}"
+ rescue
+ return 'unknown'
+ end
+ end
+
+ def File.syncmtimes(oldname,newname)
+ begin
+ 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
+
+def hashed (arr=[])
+ arg = if arr.class == String then arr.split(' ') else arr.dup end
+ hsh = Hash.new
+ if arg.length > 0
+ hsh['arguments'] = ''
+ done = false
+ arg.each do |s|
+ if done then
+ hsh['arguments'] += ' ' + s
+ else
+ kvl = s.split('=')
+ if kvl[0].sub!(/^\-+/,'') then
+ hsh[kvl[0]] = if kvl.length > 1 then kvl[1] else true end
+ else
+ hsh['file'] = s
+ done = true
+ end
+ end
+ end
+ end
+ return hsh
+end
+
+def launch(filename)
+ if $browser && $mswindows then
+ filename = filename.gsub(/\.[\/\\]/) do
+ Dir.getwd + '/'
+ end
+ report("launching #{filename}")
+ ie = WIN32OLE.new("InternetExplorer.Application")
+ ie.visible = true
+ ie.navigate(filename)
+ return true
+ else
+ return false
+ end
+end
+
+def expanded(arg) # no "other text files", too restricted
+ arg.gsub(/(env|environment)\:([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|file|path)\:([a-zA-Z\-\_\.0-9]+)/o) do # was: \S
+ method, original, resolved = $1, $2, ''
+ if $program && ! $program.empty? then
+ pstrings = ["-progname=#{$program}"]
+ else
+ pstrings = ['','progname=context']
+ end
+ # auto suffix with texinputs as fall back
+ 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
+ original = File.dirname(original) if method =~ /path/
+ report("#{original} is not resolved") unless $report
+ ENV["_CTX_K_V_#{original}_"] = original if $crossover
+ original
+ else
+ resolved = File.dirname(resolved) if method =~ /path/
+ 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
+ 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}")
+ begin
+ Dir.chdir($path) if ! $path.empty?
+ rescue
+ report("unable to chdir to: #{$path}")
+ end
+ exec(command)
+ else
+ report("using 'system' call: #{command}")
+ begin
+ Dir.chdir($path) if ! $path.empty?
+ rescue
+ report("unable to chdir to: #{$path}")
+ end
+ system(command)
+ end
+end
+
+def runoneof(application,fullname,browserpermitted)
+ if browserpermitted && launch(fullname) then
+ return true
+ else
+ report("starting #{$filename}") unless $report
+ output("\n") if $report && $verbose
+ applications = $applications[application]
+ if applications.class == Array then
+ if $report then
+ output([fullname,expanded($arguments)].join(' '))
+ return true
+ else
+ applications.each do |a|
+ return true if runcommand([a,fullname,expanded($arguments)].join(' '))
+ end
+ end
+ elsif applications.empty? then
+ if $report then
+ output([fullname,expanded($arguments)].join(' '))
+ return true
+ else
+ return runcommand([fullname,expanded($arguments)].join(' '))
+ end
+ else
+ if $report then
+ output([applications,fullname,expanded($arguments)].join(' '))
+ return true
+ else
+ return runcommand([applications,fullname,expanded($arguments)].join(' '))
+ end
+ end
+ return false
+ end
+end
+
+def report(str)
+ $stderr.puts(str) if $verbose
+end
+
+def output(str)
+ $stderr.puts(str)
+end
+
+def usage
+ print "version : #{$version} - 2003/2005 - www.pragma-ade.com\n"
+ print("\n")
+ print("usage : texmfstart [switches] filename [optional arguments]\n")
+ print("\n")
+ print("switches : --verbose --report --browser --direct --execute --locate --iftouched\n")
+ print(" --program --file --page --arguments --batch --edit --report --clear\n")
+ print(" --make --lmake --wmake --path --stubpath --indirect --before --after\n")
+ print("\n")
+ print("example : texmfstart pstopdf.rb cow.eps\n")
+ print(" texmfstart --locate examplex.rb\n")
+ print(" texmfstart --execute examplex.rb\n")
+ print(" texmfstart --browser examplap.pdf\n")
+ print(" texmfstart showcase.pdf\n")
+ 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 env:somepreset path:somefile.xsl somefile.xml\n")
+ print(" texmfstart --iftouched=normal,lowres downsample.rb normal lowres\n")
+ print(" texmfstart texmfstart bin:scite kpse:texmf.cnf\n")
+ print(" texmfstart texmfstart --exec bin:scite *.tex\n")
+ print(" texmfstart texmfstart --edit texmf.cnf\n")
+end
+
+# somehow registration does not work out (at least not under windows)
+
+def tag(name)
+ if $crossover then "_CTX_K_S_#{name}_" else "TEXMFSTART.#{name}" end
+end
+
+def registered?(filename)
+ return ENV[tag(filename)] != nil
+end
+
+def registered(filename)
+ return ENV[tag(filename)]
+end
+
+def register(filename,fullname)
+ if fullname && ! fullname.empty? then # && FileTest.file?(fullname)
+ ENV[tag(filename)] = fullname
+ report("registering '#{filename}' as '#{fullname}'")
+ return true
+ else
+ return false
+ end
+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]
+ end
+ if registered?(filename) then
+ report("already located '#{filename}'")
+ return registered(filename)
+ end
+ # create suffix list
+ if filename =~ /^(.*)\.(.+)$/ then
+ filename = $1
+ suffixlist = [$2]
+ else
+ suffixlist = [$scriptlist.split('|'),$documentlist.split('|')].flatten
+ end
+ # first we honor a given path
+ if filename =~ /[\\\/]/ then
+ report("trying to honor '#{filename}'")
+ suffixlist.each do |suffix|
+ fullname = filename+'.'+suffix
+ if FileTest.file?(fullname) && register(filename,fullname)
+ return shortpathname(fullname)
+ end
+ end
+ end
+ filename.sub!(/^.*[\\\/]/, '')
+ # next we look at the current path and the callerpath
+ [['.','current'],[$ownpath,'caller'],[registered("THREAD"),'thread']].each do |p|
+ if p && ! p.empty? then
+ suffixlist.each do |suffix|
+ fname = "#{filename}.#{suffix}"
+ fullname = File.expand_path(File.join(p[0],fname))
+ report("locating '#{fname}' in #{p[1]} path '#{p[0]}'")
+ if FileTest.file?(fullname) && register(filename,fullname) then
+ report("'#{fname}' located in #{p[1]} path")
+ return shortpathname(fullname)
+ end
+ end
+ end
+ end
+ # now we consult environment settings
+ fullname = nil
+ suffixlist.each do |suffix|
+ begin
+ break unless $suffixinputs[suffix]
+ environment = ENV[$suffixinputs[suffix]] || ENV[$suffixinputs[suffix]+".#{$program}"]
+ if ! environment || environment.empty? then
+ begin
+ environment = `kpsewhich -expand-path=\$#{$suffixinputs[suffix]}`.chomp
+ rescue
+ environment = nil
+ else
+ if environment && ! environment.empty? then
+ report("using kpsewhich variable #{$suffixinputs[suffix]}")
+ end
+ end
+ elsif environment && ! environment.empty? then
+ report("using environment variable #{$suffixinputs[suffix]}")
+ end
+ if environment && ! environment.empty? then
+ environment.split($separator).each do |e|
+ e.strip!
+ e = '.' if e == '\.' # somehow . gets escaped
+ e += '/' unless e =~ /[\\\/]$/
+ fullname = e + filename + '.' + suffix
+ report("testing '#{fullname}'")
+ if FileTest.file?(fullname) then
+ break
+ else
+ fullname = nil
+ end
+ end
+ end
+ rescue
+ report("environment string '#{$suffixinputs[suffix]}' cannot be used to locate '#{filename}'")
+ fullname = nil
+ else
+ return shortpathname(fullname) if register(filename,fullname)
+ end
+ end
+ return shortpathname(fullname) if register(filename,fullname)
+ # then we fall back on kpsewhich
+ suffixlist.each do |suffix|
+ # TDS script scripts location as per 2004
+ if suffix =~ /(#{$scriptlist})/ then
+ begin
+ report("using 'kpsewhich' to locate '#{filename}' in suffix space '#{suffix}' (1)")
+ fullname = `kpsewhich -progname=#{program} -format=texmfscripts #{filename}.#{suffix}`.chomp
+ rescue
+ report("kpsewhich cannot locate '#{filename}' in suffix space '#{suffix}' (1)")
+ fullname = nil
+ else
+ return shortpathname(fullname) if register(filename,fullname)
+ end
+ end
+ # old TDS location: .../texmf/context/...
+ begin
+ report("using 'kpsewhich' to locate '#{filename}' in suffix space '#{suffix}' (2)")
+ fullname = `kpsewhich -progname=#{program} -format="other text files" #{filename}.#{suffix}`.chomp
+ rescue
+ report("kpsewhich cannot locate '#{filename}' in suffix space '#{suffix}' (2)")
+ fullname = nil
+ else
+ return shortpathname(fullname) if register(filename,fullname)
+ end
+ end
+ 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")
+ begin
+ texroot = `kpsewhich -expand-var=$SELFAUTOPARENT`.chomp
+ rescue
+ texroot = ''
+ else
+ texroot.sub!(/[\\\/][^\\\/]*?$/, '')
+ end
+ if not texroot.empty? then
+ sffxlst = suffixlist.join(',')
+ begin
+ report("locating '#{filename}' in document tree '#{texroot}/doc*'")
+ if (result = Dir.glob("#{texroot}/doc*/**/#{filename}.{#{sffxlst}}")) && result && result[0] && FileTest.file?(result[0]) then
+ fullname = result[0]
+ end
+ rescue
+ report("locating '#{filename}.#{suffix}' in tree '#{texroot}' aborted")
+ end
+ end
+ return shortpathname(fullname) if register(filename,fullname)
+ end
+ report("aggressively locating '#{filename}' in tex trees")
+ begin
+ textrees = `kpsewhich -expand-var=$TEXMF`.chomp
+ rescue
+ textrees = ''
+ end
+ if not textrees.empty? then
+ textrees.gsub!(/[\{\}\!]/, '')
+ textrees = textrees.split(',')
+ if (suffixlist.length == 1) && (suffixlist.first =~ /(#{$documentlist})/) then
+ speedup = ['doc**','**']
+ else
+ speedup = ['**']
+ end
+ sffxlst = suffixlist.join(',')
+ speedup.each do |speed|
+ textrees.each do |tt|
+ tt.gsub!(/[\\\/]$/, '')
+ if FileTest.directory?(tt) then
+ begin
+ report("locating '#{filename}' in tree '#{tt}/#{speed}/#{filename}.{#{sffxlst}}'")
+ if (result = Dir.glob("#{tt}/#{speed}/#{filename}.{#{sffxlst}}")) && result && result[0] && FileTest.file?(result[0]) then
+ fullname = result[0]
+ break
+ end
+ rescue
+ report("locating '#{filename}' in tree '#{tt}' aborted")
+ next
+ end
+ end
+ end
+ break if fullname && ! fullname.empty?
+ end
+ end
+ if register(filename,fullname) then
+ return shortpathname(fullname)
+ else
+ return ''
+ end
+end
+
+def run(fullname)
+ if ! fullname || fullname.empty? then
+ report("the file '#{$filename}' is not found")
+ elsif FileTest.file?(fullname) then
+ begin
+ case fullname
+ when /\.(#{$scriptlist})$/ then
+ return runoneof($1,fullname,false)
+ when /\.(#{$documentlist})$/ then
+ return runoneof($1,fullname,true)
+ else
+ return runoneof('unknown',fullname,false)
+ end
+ rescue
+ report("starting '#{$filename}' in program space '#{$program}' fails")
+ end
+ else
+ report("the file '#{$filename}' in program space '#{$program}' is not accessible")
+ end
+ return false
+end
+
+def direct(fullname)
+ begin
+ return runcommand([fullname.sub(/^(bin|binary)\:/, ''),expanded($arguments)].join(' '))
+ rescue
+ return false
+ end
+end
+
+def edit(filename)
+ begin
+ return runcommand([$editor,expanded(filename),expanded($arguments)].join(' '))
+ rescue
+ return false
+ end
+end
+
+def make(filename,windows=false,linux=false)
+ basename = filename.dup
+ basename.sub!(/\.[^.]+?$/, '')
+ basename.sub!(/^.*[\\\/]/, '')
+ basename = $stubpath + '/' + basename unless $stubpath.empty?
+ if basename == filename then
+ report('nothing made')
+ else
+ program = nil
+ if filename =~ /[\\\/]/ && filename =~ /\.(#{$scriptlist})$/ then
+ program = $applications[$1]
+ end
+ filename = "\"#{filename}\"" if filename =~ /\s/
+ program = 'texmfstart' if $indirect || ! program || program.empty?
+ begin
+ if windows && f = open(basename+'.bat','w') then
+ f.binmode
+ f.write("@echo off\015\012")
+ f.write("#{program} #{filename} %*\015\012")
+ f.close
+ report("windows stub '#{basename}.bat' made")
+ elsif linux && f = open(basename,'w') then
+ f.binmode
+ f.write("#!/bin/sh\012")
+ f.write("#{program} #{filename} $@\012")
+ f.close
+ report("unix stub '#{basename}' made")
+ end
+ rescue
+ report("failed to make stub '#{basename}'")
+ else
+ return true
+ end
+ end
+ return false
+end
+
+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
+ end
+
+end
+
+def checktree(tree)
+ unless tree.empty? then
+ begin
+ setuptex = File.join(tree,'setuptex.tmf')
+ if FileTest.file?(setuptex) then
+ report('')
+ report("tex tree : #{setuptex}")
+ ENV['TEXPATH'] = tree.sub(/\/+$/,'') # + '/'
+ ENV['TMP'] = ENV['TMP'] || ENV['TEMP'] || ENV['TMPDIR'] || ENV['HOME']
+ case RUBY_PLATFORM
+ when /(mswin|bccwin|mingw|cygwin)/i then ENV['TEXOS'] = ENV['TEXOS'] || 'texmf-mswin'
+ when /(linux)/i then ENV['TEXOS'] = ENV['TEXOS'] || 'texmf-linux'
+ when /(darwin|rhapsody|nextstep)/i then ENV['TEXOS'] = ENV['TEXOS'] || 'texmf-macosx'
+ # when /(netbsd|unix)/i then # todo
+ else # todo
+ end
+ ENV['TEXMFOS'] = "#{ENV['TEXPATH']}/#{ENV['TEXOS']}"
+ report('')
+ report("preset : TEXPATH => #{ENV['TEXPATH']}")
+ report("preset : TEXOS => #{ENV['TEXOS']}")
+ report("preset : TEXMFOS => #{ENV['TEXMFOS']}")
+ report("preset : TMP => #{ENV['TMP']}")
+ report('')
+ IO.readlines(File.join(tree,'setuptex.tmf')).each do |line|
+ case line
+ when /^[\#\%]/ then
+ # comment
+ when /^(.*?)\s+\=\s+(.*)\s*$/ then
+ k, v = $1, $2
+ ENV[k] = v.gsub(/\%(.*?)\%/) do
+ ENV[$1] || ''
+ end
+ report("user set : #{k} => #{ENV[k]}")
+ end
+ end
+ else
+ report("no setup file '#{setuptex}'")
+ end
+ rescue
+ end
+ end
+end
+
+def execute(arguments)
+
+ arguments = arguments.split(/\s+/) if arguments.class == String
+
+ $directives = hashed(arguments)
+
+ $help = $directives['help'] || false
+ $batch = $directives['batch'] || false
+ $filename = $directives['file'] || ''
+ $program = $directives['program'] || 'context'
+ $direct = $directives['direct'] || false
+ $edit = $directives['edit'] || 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'] || ''
+ $tree = $directives['tree'] || ''
+
+
+ $make = $directives['make'] || false
+ $unix = $directives['unix'] || false
+ $windows = $directives['windows'] || false
+ $stubpath = $directives['stubpath'] || ''
+ $indirect = $directives['indirect'] || false
+
+ $before = $directives['before'] || ''
+ $after = $directives['after'] || ''
+
+ $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
+ report("environment variable 'OOPATH' is not set")
+ end
+ end
+
+ if $help || ! $filename || $filename.empty? then
+ usage
+ checktree($tree)
+ elsif $batch && $filename && ! $filename.empty? then
+ # todo, take commands from file and avoid multiple starts and checks
+ else
+ report("texmfstart version #{$version}")
+ checktree($tree)
+ if $make then
+ if $windows then
+ make($filename,true,false)
+ elsif $unix then
+ make($filename,false,true)
+ else
+ make($filename,$mswindows,!$mswindows)
+ end
+ elsif $browser && $filename =~ /^http\:\/\// then
+ launch($filename)
+ else
+ begin
+ process do
+ if $direct || $filename =~ /^bin\:/ then
+ direct($filename)
+ elsif $edit && ! $editor.empty? then
+ edit($filename)
+ else # script: or no prefix
+ command = find(shortpathname($filename),$program)
+ register("THREAD",File.dirname(File.expand_path(command)))
+ run(command)
+ end
+ end
+ rescue
+ report('fatal error in starting process')
+ end
+ end
+ end
+
+end
+
+execute(ARGV)
diff --git a/Master/texmf-dist/scripts/context/ruby/texsync.rb b/Master/texmf-dist/scripts/context/ruby/texsync.rb
new file mode 100644
index 00000000000..22b7d46c0fe
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/texsync.rb
@@ -0,0 +1,207 @@
+#!/usr/bin/env ruby
+
+# program : texsync
+# copyright : PRAGMA Advanced Document Engineering
+# 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.1', '2002/2004', 'PRAGMA ADE/POD']
+
+unless defined? ownpath
+ ownpath = $0.sub(/[\\\/]\w*?\.rb/i,'')
+ $: << ownpath
+end
+
+require 'base/switch'
+require 'base/logger'
+# require 'base/tool'
+
+require 'rbconfig'
+
+class Commands
+
+ include CommandBase
+
+ @@formats = ['en','nl','de','cz','it','ro']
+ @@always = ['metafun','mptopdf','en','nl']
+ @@rsync = 'rsync -r -z -c --progress --stats "--exclude=*.fmt" "--exclude=*.efmt" "--exclude=*.mem"'
+
+ @@kpsewhich = Hash.new
+
+ @@kpsewhich['minimal'] = 'SELFAUTOPARENT'
+ @@kpsewhich['context'] = 'TEXMFLOCAL'
+ @@kpsewhich['documentation'] = 'TEXMFLOCAL'
+ @@kpsewhich['unknown'] = 'SELFAUTOPARENT'
+
+ def update
+
+ report
+
+ return unless destination = getdestination
+
+ texpaths = gettexpaths
+ address = option('address')
+ user = option('user')
+ tree = option('tree')
+ force = option('force')
+
+ ok = true
+ begin
+ report("synchronizing '#{tree}' from '#{address}' to '#{destination}'")
+ report
+ if texpaths then
+ texpaths.each do |path|
+ report("synchronizing path '#{path}' of '#{tree}' from '#{address}' to '#{destination}'")
+ command = "#{rsync} #{user}@#{address}::#{tree}/#{path} #{destination}/{path}"
+ ok = ok && system(command) if force
+ end
+ else
+ command = "#{@@rsync} #{user}@#{address}::#{tree} #{destination}"
+ ok = system(command) if force
+ end
+ rescue
+ report("error in running rsync")
+ ok = false
+ ensure
+ if force then
+ if ok then
+ if option('make') then
+ report("generating tex and metapost formats")
+ report
+ @@formats.delete_if do |f|
+ begin
+ `kpsewhich cont-#{f}`.chomp.empty?
+ rescue
+ end
+ end
+ str = [@@formats,@@always].flatten.uniq.join(' ')
+ begin
+ system("texexec --make --alone #{str}")
+ rescue
+ report("unable to generate formats '#{str}'")
+ else
+ report
+ end
+ else
+ report("regenerate the formats files if needed")
+ end
+ else
+ report("error in synchronizing '#{tree}'")
+ end
+ else
+ report("provide --force to execute '#{command}'") unless force
+ end
+ end
+
+ end
+
+ def list
+
+ report
+
+ address = option('address')
+ user = option('user')
+ result = nil
+
+ begin
+ report("fetching list of trees from '#{address}'")
+ command = "#{@@rsync} #{user}@#{address}::"
+ if option('force') then
+ result = `#{command}`.chomp
+ else
+ report("provide --force to execute '#{command}'")
+ end
+ rescue
+ result = nil
+ else
+ if result then
+ report("available trees:")
+ report
+ reportlines(result)
+ end
+ ensure
+ report("unable to fetch list") unless result
+ end
+
+ end
+
+ private
+
+ def gettexpaths
+ if option('full') then
+ 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'] # 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')
+ end
+ else
+ texpaths = nil
+ end
+ texpaths
+ end
+
+ def getdestination
+ if (destination = option('destination')) && ! destination.empty? then
+ begin
+ if @@kpsewhich.key?(destination) then
+ destination = @@kpsewhich[option('tree')] || @@kpsewhich['unknown']
+ destination = `kpsewhich --expand-var=$#{destination}`.chomp
+ elsif ! FileTest.directory?(destination) then
+ destination = nil
+ end
+ rescue
+ report("unable to determine destination tex root")
+ else
+ if ! destination || destination.empty? then
+ report("no destination is specified")
+ elsif not FileTest.directory?(destination) then
+ report("invalid destination '#{destination}'")
+ elsif not FileTest.writable?(destination) then
+ report("destination '#{destination}' is not writable")
+ else
+ report("using destination '#{destination}'")
+ return destination
+ end
+ end
+ else
+ report("unknown destination")
+ end
+ return nil
+ end
+
+end
+
+logger = Logger.new(banner.shift)
+commandline = CommandLine.new
+
+commandline.registeraction('update', 'update installed tree')
+commandline.registeraction('list', 'list available trees')
+
+commandline.registerflag('terse', 'download as less as possible (esp binaries)')
+commandline.registerflag('full', 'download everything (all binaries)')
+commandline.registerflag('force', 'confirm action')
+commandline.registerflag('make', 'remake formats')
+
+commandline.registervalue('address', 'www.pragma-ade.com', 'adress of repository (www.pragma-ade)')
+commandline.registervalue('user', 'guest', 'user account (guest)')
+commandline.registervalue('tree', 'tex', 'tree to synchronize (tex)')
+commandline.registervalue('destination', nil, 'destination of tree (kpsewhich)')
+
+commandline.registeraction('help')
+commandline.registeraction('version')
+
+commandline.expand
+
+Commands.new(commandline,logger,banner).send(commandline.action || 'help')
diff --git a/Master/texmf-dist/scripts/context/ruby/textools.rb b/Master/texmf-dist/scripts/context/ruby/textools.rb
new file mode 100644
index 00000000000..78982f175a1
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/textools.rb
@@ -0,0 +1,885 @@
+#!/usr/bin/env ruby
+
+# program : textools
+# 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
+
+# This script will harbor some handy manipulations on tex
+# related files.
+
+banner = ['TeXTools', 'version 1.2.2', '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'
+
+# Remark
+#
+# The fixtexmftrees feature does not realy belong in textools, but
+# since it looks like no measures will be taken to make texlive (and
+# tetex) downward compatible with respect to fonts installed by
+# users, we provide this fixer. This option also moves script files
+# to their new location (only for context) in the TDS. Beware: when
+# locating scripts, the --format switch in kpsewhich should now use
+# 'texmfscripts' instead of 'other text files' (texmfstart is already
+# aware of this). Files will only be moved when --force is given. Let
+# me know if more fixes need to be made.
+
+class Commands
+
+ include CommandBase
+
+ def hidemapnames
+ report('hiding FontNames in map files')
+ xidemapnames(true)
+ end
+
+ def videmapnames
+ report('unhiding FontNames in map files')
+ xidemapnames(false)
+ end
+
+ def removemapnames
+
+ report('removing FontNames from map files')
+
+ if files = findfiles('map') then
+ report
+ files.sort.each do |fn|
+ gn = fn # + '.nonames'
+ hn = fn + '.original'
+ begin
+ if FileTest.file?(fn) && ! FileTest.file?(hn) then
+ if File.rename(fn,hn) then
+ if (fh = File.open(hn,'r')) && (gh = File.open(gn,'w')) then
+ report("processing #{fn}")
+ while str = fh.gets do
+ str.sub!(/^([^\%]+?)(\s+)([^\"\<\s]*?)(\s)/) do
+ $1 + $2 + " "*$3.length + $4
+ end
+ gh.puts(str)
+ end
+ fh.close
+ gh.close
+ else
+ report("no permissions to handle #{fn}")
+ end
+ else
+ report("unable to rename #{fn} to #{hn}")
+ end
+ else
+ report("not processing #{fn} due to presence of #{hn}")
+ end
+ rescue
+ report("error in handling #{fn}")
+ end
+ end
+ end
+
+ end
+
+ def restoremapnames
+
+ report('restoring FontNames in map files')
+
+ if files = findfiles('map') then
+ report
+ files.sort.each do |fn|
+ hn = fn + '.original'
+ begin
+ if FileTest.file?(hn) then
+ File.delete(fn) if FileTest.file?(fn)
+ report("#{fn} restored") if File.rename(hn,fn)
+ else
+ report("no original found for #{fn}")
+ end
+ rescue
+ report("error in restoring #{fn}")
+ end
+ end
+ end
+
+ end
+
+ def findfile
+
+ report('locating file in texmf tree')
+
+ # ! not in tree
+ # ? fuzzy
+ # . in tree
+ # > in tree and used
+
+ if filename = @commandline.argument('first') then
+ if filename && ! filename.empty? then
+ report
+ used = kpsefile(filename) || pathfile(filename)
+ if paths = texmfroots then
+ found, prefered = false, false
+ paths.each do |p|
+ if files = texmffiles(p,filename) then
+ found = true
+ files.each do |f|
+ # unreadable: report("#{if f == used then '>' else '.' end} #{f}")
+ if f == used then
+ prefered = true
+ report("> #{f}")
+ else
+ report(". #{f}")
+ end
+ end
+ end
+ end
+ if prefered then
+ report("! #{used}") unless found
+ else
+ report("> #{used}")
+ end
+ elsif used then
+ report("? #{used}")
+ else
+ report('no file found')
+ end
+ else
+ report('no file specified')
+ end
+ else
+ report('no file specified')
+ end
+
+ end
+
+ def unzipfiles
+
+ report('g-unzipping files')
+
+ if files = findfiles('gz') then
+ report
+ files.each do |f|
+ begin
+ system("gunzip -d #{f}")
+ rescue
+ report("unable to unzip file #{f}")
+ else
+ report("file #{f} is unzipped")
+ end
+ end
+ end
+
+ end
+
+ def fixafmfiles
+
+ report('fixing afm files')
+
+ if files = findfiles('afm') then
+ report
+ ok = false
+ files.each do |filename|
+ if filename =~ /\.afm$/io then
+ if f = File.open(filename) then
+ result = ''
+ done = false
+ while str = f.gets do
+ str.chomp!
+ str.strip!
+ if str.empty? then
+ # skip
+ elsif (str.length > 200) && (str =~ /^(comment|notice)\s(.*)\s*$/io) then
+ done = true
+ tag, words, len = $1, $2.split(' '), 0
+ result += tag
+ while words.size > 0 do
+ str = words.shift
+ len += str.length + 1
+ result += ' ' + str
+ if len > (70 - tag.length) then
+ result += "\n"
+ result += tag if words.size > 0
+ len = 0
+ end
+ end
+ result += "\n" if len>0
+ else
+ result += str + "\n"
+ end
+ end
+ f.close
+ if done then
+ ok = true
+ begin
+ if File.rename(filename,filename+'.original') then
+ if FileTest.file?(filename) then
+ report("something to fix in #{filename} but error in renaming (3)")
+ elsif f = File.open(filename,'w') then
+ f.puts(result)
+ f.close
+ report('file', filename, 'has been fixed')
+ else
+ report("something to fix in #{filename} but error in opening (4)")
+ File.rename(filename+'.original',filename) # gamble
+ end
+ else
+ report("something to fix in #{filename} but error in renaming (2)")
+ end
+ rescue
+ report("something to fix in #{filename} but error in renaming (1)")
+ end
+ else
+ report("nothing to fix in #{filename}")
+ end
+ else
+ report("error in opening #{filename}")
+ end
+ end
+ end
+ report('no files match the pattern') unless ok
+ end
+
+ end
+
+ def mactodos
+
+ report('fixing mac newlines')
+
+ if files = findfiles('tex') then
+ report
+ files.each do |filename|
+ begin
+ report("converting file #{filename}")
+ tmpfilename = filename + '.tmp'
+ if f = File.open(filename) then
+ if g = File.open(tmpfilename, 'w')
+ while str = f.gets do
+ g.puts(str.gsub(/\r/,"\n"))
+ end
+ if f.close && g.close && FileTest.file?(tmpfilename) then
+ File.delete(filename)
+ File.rename(tmpfilename,filename)
+ end
+ else
+ report("unable to open temporary file #{tmpfilename}")
+ end
+ else
+ report("unable to open #{filename}")
+ end
+ rescue
+ report("problems with fixing #{filename}")
+ end
+ end
+ end
+
+ end
+
+ def fixtexmftrees
+
+ if paths = @commandline.argument('first') then
+ paths = [paths] if ! paths.empty?
+ end
+ paths = texmfroots if paths.empty?
+
+ if paths then
+
+ moved = 0
+ force = @commandline.option('force')
+
+ report
+ report("checking TDS 2003 => TDS 2004 : map files")
+ # report
+
+ # move [map,enc] files from /texmf/[dvips,pdftex,dvipdfmx] -> /texmf/fonts/[*]
+
+ ['map','enc'].each do |suffix|
+ paths.each do |path|
+ ['dvips','pdftex','dvipdfmx'].each do |program|
+ report
+ report("checking #{suffix} files for #{program} on #{path}")
+ report
+ moved += movefiles("#{path}/#{program}","#{path}/fonts/#{suffix}/#{program}",suffix) do
+ # nothing
+ end
+ end
+ end
+ end
+
+ report
+ report("checking TDS 2003 => TDS 2004 : scripts")
+ # report
+
+ # move [rb,pl,py] files from /texmf/someplace -> /texmf/scripts/someplace
+
+ ['rb','pl','py'].each do |suffix|
+ paths.each do |path|
+ ['context'].each do |program|
+ report
+ report("checking #{suffix} files for #{program} on #{path}")
+ report
+ moved += movefiles("#{path}/#{program}","#{path}/scripts/#{program}",suffix) do |f|
+ f.gsub!(/\/(perl|ruby|python)tk\//o) do
+ "/#{$1}/"
+ end
+ end
+ end
+ end
+ end
+
+ begin
+ if moved>0 then
+ report
+ if force then
+ system('mktexlsr')
+ report
+ report("#{moved} files moved")
+ else
+ report("#{moved} files will be moved")
+ end
+ else
+ report('no files need to be moved')
+ end
+ rescue
+ report('you need to run mktexlsr')
+ end
+
+ end
+
+ end
+
+ def replacefile
+
+ report('replace file')
+
+ if newname = @commandline.argument('first') then
+ if newname && ! newname.empty? then
+ report
+ report("replacing #{newname}")
+ report
+ oldname = kpsefile(File.basename(newname))
+ force = @commandline.option('force')
+ if oldname && ! oldname.empty? then
+ oldname = File.expand_path(oldname)
+ newname = File.expand_path(newname)
+ report("old: #{oldname}")
+ report("new: #{newname}")
+ report
+ if newname == oldname then
+ report('unable to replace itself')
+ elsif force then
+ begin
+ File.copy(newname,oldname)
+ rescue
+ report('error in replacing the old file')
+ end
+ else
+ report('the old file will be replaced (use --force)')
+ end
+ else
+ report('nothing to replace')
+ end
+ else
+ report('no file specified')
+ end
+ else
+ report('no file specified')
+ end
+
+ end
+
+ private # general
+
+ def texmfroots
+ begin
+ paths = `kpsewhich -expand-path=\$TEXMF`.chomp
+ rescue
+ else
+ return paths.split(/#{File::PATH_SEPARATOR}/) if paths && ! paths.empty?
+ end
+ return nil
+ end
+
+ def texmffiles(root, filename)
+ begin
+ files = Dir.glob("#{root}/**/#{filename}")
+ rescue
+ else
+ return files if files && files.length>0
+ end
+ return nil
+ end
+
+ def pathfile(filename)
+ used = nil
+ begin
+ if ! filename || filename.empty? then
+ return nil
+ else
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
+ if FileTest.file?(File.join(path,filename)) then
+ used = File.join(path,filename)
+ break
+ end
+ end
+ end
+ rescue
+ used = nil
+ else
+ used = nil if used && used.empty?
+ end
+ return used
+ end
+
+ def kpsefile(filename)
+ used = nil
+ begin
+ if ! filename || filename.empty? then
+ return nil
+ else
+ used = `kpsewhich #{filename}`.chomp
+ end
+ if used && used.empty? then
+ used = `kpsewhich -progname=context #{filename}`.chomp
+ end
+ if used && used.empty? then
+ used = `kpsewhich -format=texmfscripts #{filename}`.chomp
+ end
+ if used && used.empty? then
+ used = `kpsewhich -progname=context -format=texmfscripts #{filename}`.chomp
+ end
+ if used && used.empty? then
+ used = `kpsewhich -format="other text files" #{filename}`.chomp
+ end
+ if used && used.empty? then
+ used = `kpsewhich -progname=context -format="other text files" #{filename}`.chomp
+ end
+ rescue
+ used = nil
+ else
+ used = nil if used && used.empty?
+ end
+ return used
+ end
+
+ def downcasefilenames
+
+ report('downcase filenames')
+
+ force = @commandline.option('force')
+
+ # if @commandline.option('recurse') then
+ # files = Dir.glob('**/*')
+ # else
+ # files = Dir.glob('*')
+ # end
+ # if files && files.length>0 then
+
+ if files = findfiles() then
+ files.each do |oldname|
+ if FileTest.file?(oldname) then
+ newname = oldname.downcase
+ if oldname != newname then
+ if force then
+ begin
+ File.rename(oldname,newname)
+ rescue
+ report("#{oldname} == #{oldname}\n")
+ else
+ report("#{oldname} => #{newname}\n")
+ end
+ else
+ report("(#{oldname} => #{newname})\n")
+ end
+ end
+ end
+ end
+ end
+ end
+
+ def stripformfeeds
+
+ report('strip formfeeds')
+
+ force = @commandline.option('force')
+
+ if files = findfiles() then
+ files.each do |filename|
+ if FileTest.file?(filename) then
+ begin
+ data = IO.readlines(filename).join('')
+ rescue
+ else
+ if data.gsub!(/\n*\f\n*/io,"\n\n") then
+ if force then
+ if f = open(filename,'w') then
+ report("#{filename} is stripped\n")
+ f.puts(data)
+ f.close
+ else
+ report("#{filename} cannot be stripped\n")
+ end
+ else
+ report("#{filename} will be stripped\n")
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+
+ public
+
+ def showfont
+
+ file = @commandline.argument('first')
+
+ if file.empty? then
+ report('provide filename')
+ else
+ file.sub!(/\.afm$/,'')
+ begin
+ report("analyzing afm file #{file}.afm")
+ file = `kpsewhich #{file}.afm`.chomp
+ rescue
+ report('unable to run kpsewhich')
+ return
+ end
+
+ names = Array.new
+
+ if FileTest.file?(file) then
+ File.new(file).each do |line|
+ if line.match(/^C\s*([\-\d]+)\s*\;.*?\s*N\s*(.+?)\s*\;/o) then
+ names.push($2)
+ end
+ end
+ ranges = names.size
+ report("number of glyphs: #{ranges}")
+ ranges = ranges/256 + 1
+ report("number of subsets: #{ranges}")
+ file = File.basename(file).sub(/\.afm$/,'')
+ tex = File.open("textools.tex",'w')
+ map = File.open("textools.map",'w')
+ tex.puts("\\starttext\n")
+ tex.puts("\\loadmapfile[textools.map]\n")
+ for i in 1..ranges do
+ rfile = "#{file}-range-#{i}"
+ report("generating enc file #{rfile}.enc")
+ flushencoding("#{rfile}", (i-1)*256, i*256-1, names)
+ # catch console output
+ report("generating tfm file #{rfile}.tfm")
+ mapline = `afm2tfm #{file}.afm -T #{rfile}.enc #{rfile}.tfm`
+ # more robust replacement
+ mapline = "#{rfile} <#{rfile}.enc <#{file}.pfb"
+ # final entry in map file
+ mapline = "#{mapline} <#{file}.pfb"
+ map.puts("#{mapline}\n")
+ tex.puts("\\showfont[#{rfile}][unknown]\n")
+ end
+ tex.puts("\\stoptext\n")
+ report("generating map file textools.map")
+ report("generating tex file textools.tex")
+ map.close
+ tex.close
+ else
+ report("invalid file #{file}")
+ end
+ end
+
+ end
+
+ private
+
+ def flushencoding (file, from, to, names)
+ n = 0
+ out = File.open("#{file}.enc",'w')
+ out.puts("/#{file.gsub(/\-/,'')} [\n")
+ for i in from..to do
+ if names[i] then
+ n += 1
+ out.puts("/#{names[i]}\n")
+ else
+ out.puts("/.notdef\n")
+ end
+ end
+ out.puts("] def\n")
+ out.close
+ return n
+ end
+
+ private # specific
+
+ def movefiles(from_path,to_path,suffix,&block)
+ obsolete = 'obsolete'
+ force = @commandline.option('force')
+ moved = 0
+ if files = texmffiles(from_path, "*.#{suffix}") then
+ files.each do |filename|
+ newfilename = filename.sub(/^#{from_path}/, to_path)
+ yield(newfilename) if block
+ if FileTest.file?(newfilename) then
+ begin
+ File.rename(filename,filename+'.obsolete') if force
+ rescue
+ report("#{filename} cannot be made obsolete") if force
+ else
+ if force then
+ report("#{filename} is made obsolete")
+ else
+ report("#{filename} will become obsolete")
+ end
+ end
+ else
+ begin
+ File.makedirs(File.dirname(newfilename)) if force
+ rescue
+ end
+ begin
+ File.copy(filename,newfilename) if force
+ rescue
+ report("#{filename} cannot be copied to #{newfilename}")
+ else
+ begin
+ File.delete(filename) if force
+ rescue
+ report("#{filename} cannot be deleted") if force
+ else
+ if force then
+ report("#{filename} is moved to #{newfilename}")
+ moved += 1
+ else
+ report("#{filename} will be moved to #{newfilename}")
+ end
+ end
+ end
+ end
+ end
+ else
+ report('no matches found')
+ end
+ return moved
+ end
+
+ def xidemapnames(hide)
+
+ filter = /^([^\%]+?)(\s+)([^\"\<\s]*?)(\s)/
+ banner = '% textools:nn '
+
+ if files = findfiles('map') then
+ report
+ files.sort.each do |fn|
+ if fn.has_suffix?('map') then
+ begin
+ lines = IO.read(fn)
+ report("processing #{fn}")
+ if f = File.open(fn,'w') then
+ skip = false
+ if hide then
+ lines.each do |str|
+ if skip then
+ skip = false
+ elsif str =~ /#{banner}/ then
+ skip = true
+ elsif str =~ filter then
+ f.puts(banner+str)
+ str.sub!(filter) do
+ $1 + $2 + " "*$3.length + $4
+ end
+ end
+ f.puts(str)
+ end
+ else
+ lines.each do |str|
+ if skip then
+ skip = false
+ elsif str.sub!(/#{banner}/, '') then
+ f.puts(str)
+ skip = true
+ else
+ f.puts(str)
+ end
+ end
+ end
+ f.close
+ end
+ rescue
+ report("error in handling #{fn}")
+ end
+ end
+ end
+ end
+
+ end
+
+ public
+
+ def updatetree
+
+ nocheck = @commandline.option('nocheck')
+ merge = @commandline.option('merge')
+ delete = @commandline.option('delete')
+ force = @commandline.option('force')
+ root = @commandline.argument('first').gsub(/\\/,'/')
+ path = @commandline.argument('second').gsub(/\\/,'/')
+
+ if FileTest.directory?(root) then
+ report("scanning #{root}")
+ rootfiles = Dir.glob("#{root}/**/*")
+ else
+ report("provide source root")
+ return
+ end
+ if rootfiles.size > 0 then
+ report("#{rootfiles.size} files")
+ else
+ report("no files")
+ return
+ end
+ rootfiles.collect! do |rf|
+ rf.gsub(/\\/o, '/').sub(/#{root}\//o, '')
+ end
+ rootfiles = rootfiles.delete_if do |rf|
+ FileTest.directory?(File.join(root,rf))
+ end
+
+ if FileTest.directory?(path) then
+ report("scanning #{path}")
+ pathfiles = Dir.glob("#{path}/**/*")
+ else
+ report("provide destination root")
+ return
+ end
+ if pathfiles.size > 0 then
+ report("#{pathfiles.size} files")
+ else
+ report("no files")
+ return
+ end
+ pathfiles.collect! do |pf|
+ pf.gsub(/\\/o, '/').sub(/#{path}\//o, '')
+ end
+ pathfiles = pathfiles.delete_if do |pf|
+ FileTest.directory?(File.join(path,pf))
+ end
+
+ root = File.expand_path(root)
+ path = File.expand_path(path)
+
+ donepaths = Hash.new
+ copiedfiles = Hash.new
+
+ # update existing files, assume similar paths
+
+ report("")
+ pathfiles.each do |f| # destination
+ p = File.join(path,f)
+ if rootfiles.include?(f) then
+ r = File.join(root,f)
+ if p != r then
+ if nocheck or File.mtime(p) < File.mtime(r) then
+ copiedfiles[File.expand_path(p)] = true
+ report("updating '#{r}' to '#{p}'")
+ begin
+ begin File.makedirs(File.dirname(p)) if force ; rescue ; end
+ File.copy(r,p) if force
+ rescue
+ report("updating failed")
+ end
+ else
+ report("not updating '#{r}'")
+ end
+ end
+ end
+ end
+
+ # merging non existing files
+
+ report("")
+ rootfiles.each do |f|
+ donepaths[File.dirname(f)] = true
+ r = File.join(root,f)
+ if not pathfiles.include?(f) then
+ p = File.join(path,f)
+ if p != r then
+ if merge then
+ copiedfiles[File.expand_path(p)] = true
+ report("merging '#{r}' to '#{p}'")
+ begin
+ begin File.makedirs(File.dirname(p)) if force ; rescue ; end
+ File.copy(r,p) if force
+ rescue
+ report("merging failed")
+ end
+ else
+ report("not merging '#{r}'")
+ end
+ end
+ end
+ end
+
+ # deleting obsolete files
+
+ report("")
+ donepaths.keys.sort.each do |d|
+ pathfiles = Dir.glob("#{path}/#{d}/**/*")
+ pathfiles.each do |p|
+ r = File.join(root,d,File.basename(p))
+ if FileTest.file?(p) and not FileTest.file?(r) and not copiedfiles.key?(File.expand_path(p)) then
+ if delete then
+ report("deleting '#{p}'")
+ begin
+ File.delete(p) if force
+ rescue
+ report("deleting failed")
+ end
+ else
+ report("not deleting '#{p}'")
+ end
+ end
+ end
+ end
+
+ end
+
+end
+
+logger = Logger.new(banner.shift)
+commandline = CommandLine.new
+
+commandline.registeraction('removemapnames' , '[pattern] [--recurse]')
+commandline.registeraction('restoremapnames' , '[pattern] [--recurse]')
+commandline.registeraction('hidemapnames' , '[pattern] [--recurse]')
+commandline.registeraction('videmapnames' , '[pattern] [--recurse]')
+commandline.registeraction('findfile' , 'filename [--recurse]')
+commandline.registeraction('unzipfiles' , '[pattern] [--recurse]')
+commandline.registeraction('fixafmfiles' , '[pattern] [--recurse]')
+commandline.registeraction('mactodos' , '[pattern] [--recurse]')
+commandline.registeraction('fixtexmftrees' , '[texmfroot] [--force]')
+commandline.registeraction('replacefile' , 'filename [--force]')
+commandline.registeraction('updatetree' , 'fromroot toroot [--force --nocheck --merge --delete]')
+commandline.registeraction('downcasefilenames', '[--recurse] [--force]') # not yet documented
+commandline.registeraction('stripformfeeds' , '[--recurse] [--force]') # not yet documented
+commandline.registeraction('showfont' , 'filename')
+
+commandline.registeraction('help')
+commandline.registeraction('version')
+
+commandline.registerflag('recurse')
+commandline.registerflag('force')
+commandline.registerflag('merge')
+commandline.registerflag('delete')
+commandline.registerflag('nocheck')
+
+commandline.expand
+
+Commands.new(commandline,logger,banner).send(commandline.action || 'help')
diff --git a/Master/texmf-dist/scripts/context/ruby/tmftools.rb b/Master/texmf-dist/scripts/context/ruby/tmftools.rb
new file mode 100644
index 00000000000..d125c5cae69
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/tmftools.rb
@@ -0,0 +1,133 @@
+#!/usr/bin/env ruby
+
+# program : tmftools
+# copyright : PRAGMA Advanced Document Engineering
+# version : 2005
+# author : Hans Hagen
+#
+# project : ConTeXt
+# concept : Hans Hagen
+# info : j.hagen@xs4all.nl
+# www : www.pragma-ade.com
+
+# The script based alternative is not slower than the kpse one.
+# Loading is a bit faster when the log file is used.
+
+# todo: create database
+
+# tmftools [some of the kpsewhich switches]
+
+# tmftools --analyze
+# tmftools --analyze > kpsewhat.log
+# tmftools --analyze --strict > kpsewhat.log
+# tmftools --analyze --delete --force "texmf-local/fonts/.*/somename"
+
+# the real thing
+
+banner = ['TMFTools', 'version 1.0.0 (experimental, no help yet)', '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/kpsefast'
+
+class Commands
+
+ include CommandBase
+
+ def init_kpse
+ k = KPSEFAST.new
+ k.rootpath = @commandline.option('rootpath')
+ k.treepath = @commandline.option('treepath')
+ k.progname = @commandline.option('progname')
+ k.engine = @commandline.option('engine')
+ k.format = @commandline.option('format')
+ k.diskcache = @commandline.option('diskcache')
+ k.renewcache = @commandline.option('renewcache')
+ k.load_cnf
+ k.expand_variables
+ k.load_lsr
+ return k
+ end
+
+ def main
+ if option = @commandline.option('expand-braces') and not option.empty? then
+ puts init_kpse.expand_braces(option)
+ elsif option = @commandline.option('expand-path') and not option.empty? then
+ puts init_kpse.expand_path(option)
+ elsif option = @commandline.option('expand-var') and not option.empty? then
+ if option == '*' then
+ init_kpse.list_expansions()
+ else
+ puts init_kpse.expand_var(option)
+ end
+ elsif option = @commandline.option('show-path') and not option.empty? then
+ puts init_kpse.show_path(option)
+ elsif option = @commandline.option('var-value') and not option.empty? then
+ if option == '*' then
+ init_kpse.list_variables()
+ else
+ puts init_kpse.expand_var(option)
+ end
+ elsif @commandline.arguments.size > 0 then
+ kpse = init_kpse
+ @commandline.arguments.each do |option|
+ puts kpse.find_file(option)
+ end
+ else
+ help
+ end
+ end
+
+ def analyze
+ pattern = @commandline.argument('first')
+ strict = @commandline.option('strict')
+ sort = @commandline.option('sort')
+ delete = @commandline.option('delete') and @commandline.option('force')
+ init_kpse.analyze_files(pattern, strict, sort, delete)
+ end
+
+end
+
+logger = Logger.new(banner.shift)
+commandline = CommandLine.new
+
+# kpsewhich compatible options
+
+commandline.registervalue('expand-braces','')
+commandline.registervalue('expand-path','')
+commandline.registervalue('expand-var','')
+commandline.registervalue('show-path','')
+commandline.registervalue('var-value','')
+
+commandline.registervalue('engine','')
+commandline.registervalue('progname','')
+commandline.registervalue('format','')
+
+# additional goodies
+
+commandline.registervalue('rootpath','')
+commandline.registervalue('treepath','')
+commandline.registervalue('sort','')
+
+commandline.registerflag('diskcache')
+commandline.registerflag('renewcache')
+commandline.registerflag('strict')
+commandline.registerflag('delete')
+commandline.registerflag('force')
+
+commandline.registeraction('analyze', "[--strict --sort --rootpath --treepath]\n[--delete [--force]] [pattern]")
+
+# general purpose options
+
+commandline.registerflag('verbose')
+commandline.registeraction('help')
+commandline.registeraction('version')
+
+commandline.expand
+
+Commands.new(commandline,logger,banner).send(commandline.action || 'main')
diff --git a/Master/texmf-dist/scripts/context/ruby/xmltools.rb b/Master/texmf-dist/scripts/context/ruby/xmltools.rb
new file mode 100644
index 00000000000..a57f7445020
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/ruby/xmltools.rb
@@ -0,0 +1,352 @@
+#!/usr/bin/env ruby
+
+# program : xmltools
+# 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
+
+# This script will harbor some handy manipulations on tex
+# related files.
+
+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 'base/switch'
+require 'base/logger'
+
+class String
+
+ def astring(n=10)
+ gsub(/(\d+)/o) do $1.to_s.rjust(n) end.gsub(/ /o, '0')
+ end
+
+ def xstring
+ if self =~ /\'/o then
+ "\"#{self.gsub(/\"/, '&quot;')}\""
+ else
+ "\'#{self}\'"
+ end
+ end
+
+end
+
+class Array
+
+ def asort(n=10)
+ sort {|x,y| x.astring(n) <=> y.astring(n)}
+ end
+
+end
+
+class Commands
+
+ include CommandBase
+
+ def dir
+
+ @xmlns = "xmlns='http://www.pragma-ade.com/rlg/xmldir.rng'"
+
+ pattern = @commandline.option('pattern')
+ recurse = @commandline.option('recurse')
+ stripname = @commandline.option('stripname')
+ longname = @commandline.option('longname')
+ url = @commandline.option('url')
+ outputfile = @commandline.option('output')
+ root = @commandline.option('root')
+
+ def generate(output,files,url,root,longname)
+
+ class << output
+ def xputs(str,n=0)
+ puts("#{' '*n}#{str}")
+ end
+ end
+
+ dirname = ''
+ output.xputs("<?xml version='1.0'?>\n\n")
+ if ! root || root.empty? then
+ rootatt = @xmlns
+ else
+ rootatt = " #{@xmlns} root='#{root}'"
+ end
+ rootatt += " timestamp='#{Time.now}'"
+ if url.empty? then
+ output.xputs("<files #{rootatt}>\n")
+ else
+ output.xputs("<files url='#{url}'#{rootatt}>\n")
+ end
+ files.each do |f|
+ bn, dn = File.basename(f), File.dirname(f)
+ if dirname != dn then
+ output.xputs("</directory>\n", 2) if dirname != ''
+ output.xputs("<directory name='#{dn}'>\n", 2)
+ dirname = dn
+ end
+ if longname && dn != '.' then
+ output.xputs("<file name='#{dn}/#{bn}'>\n", 4)
+ else
+ output.xputs("<file name='#{bn}'>\n", 4)
+ end
+ output.xputs("<base>#{bn.sub(/\..*$/,'')}</base>\n", 6)
+ if File.stat(f).file? then
+ bt = bn.sub(/^.*\./,'')
+ if bt != bn then
+ output.xputs("<type>#{bt}</type>\n", 6)
+ end
+ output.xputs("<size>#{File.stat(f).size}</size>\n", 6)
+ end
+ output.xputs("<date>#{File.stat(f).mtime.strftime("%Y-%m-%d %H:%M")}</date>\n", 6)
+ output.xputs("</file>\n", 4)
+ end
+ output.xputs("</directory>\n", 2) if dirname != ''
+ output.xputs("</files>\n")
+
+ end
+
+ if pattern.empty? then
+ report('provide --pattern=')
+ return
+ end
+
+ unless outputfile.empty? then
+ begin
+ output = File.open(outputfile,'w')
+ rescue
+ report("unable to open #{outputfile}")
+ return
+ end
+ else
+ report('provide --output')
+ return
+ end
+
+ if stripname && pattern.class == String && ! pattern.empty? then
+ pattern = File.dirname(pattern)
+ end
+
+ pattern = '*' if pattern.empty?
+
+ unless root.empty? then
+ unless FileTest.directory?(root) then
+ report("unknown root #{root}")
+ return
+ end
+ begin
+ Dir.chdir(root)
+ rescue
+ report("unable to change to root #{root}")
+ return
+ end
+ end
+
+ generate(output, globbed(pattern, recurse), url, root, longname)
+
+ output.close if output
+
+ end
+
+ alias ls :dir
+
+ def mmlpages
+
+ file = @commandline.argument('first')
+ eps = @commandline.option('eps')
+ jpg = @commandline.option('jpg')
+ png = @commandline.option('png')
+ style = @commandline.option('style')
+ modes = @commandline.option('modes')
+
+ file = file.sub(/\.xml/io, '')
+ long = "#{file}-mmlpages"
+ if FileTest.file?(file+'.xml') then
+ style = "--arg=\"style=#{style}\"" unless style.empty?
+ modes = "--mode=#{modes}" unless modes.empty?
+ if system("texmfstart texexec.pl --batch --pdf --once --result=#{long} --use=mmlpag #{style} #{modes} #{file}.xml") then
+ if eps then
+ if f = open("#{file}-mmlpages.txt") then
+ while line = f.gets do
+ data = Hash.new
+ if fields = line.split then
+ fields.each do |fld|
+ key, value = fld.split('=')
+ data[key] = value if key && value
+ end
+ if data.key?('p') then
+ page = data['p']
+ name = "#{long}-#{page.to_i-1}"
+ if eps then
+ report("generating eps file #{name}")
+ if system("pdftops -eps -f #{page} -l #{page} #{long}.pdf #{name}.eps") then
+ if data.key?('d') then
+ if epsfile = IO.read("#{name}.eps") then
+ epsfile.sub!(/^(\%\%BoundingBox:.*?$)/i) do
+ newline = $1 + "\n%%Baseline: #{data['d']}\n"
+ if data.key?('w') && data.key?('h') then
+ newline += "%%PositionWidth: #{data['w']}\n"
+ newline += "%%PositionHeight: #{data['h']}\n"
+ newline += "%%PositionDepth: #{data['d']}"
+ end
+ newline
+ end
+ if g = File.open("#{name}.eps",'wb') then
+ g.write(epsfile)
+ g.close
+ end
+ end
+ end
+ else
+ report("error in generating eps from #{name}")
+ end
+ end
+ end
+ end
+ end
+ f.close
+ else
+ report("missing data log file #{file}")
+ end
+ end
+ if png then
+ report("generating png file for #{long}")
+ system("imagemagick #{long}.pdf #{long}-%d.png")
+ end
+ if jpg then
+ report("generating jpg files for #{long}")
+ system("imagemagick #{long}.pdf #{long}-%d.jpg")
+ end
+ else
+ report("error in processing file #{file}")
+ end
+ system("texmfstart texutil --purge")
+ else
+ report("error in processing file #{file}")
+ end
+
+ end
+
+ def analyze
+
+ file = @commandline.argument('first')
+ result = @commandline.option('output')
+
+ if FileTest.file?(file) then
+ if data = IO.read(file) then
+ report("xml file #{file} loaded")
+ elements = Hash.new
+ attributes = Hash.new
+ entities = Hash.new
+ data.scan(/<([^>\s\/\!\?]+)([^>]*?)>/o) do
+ element, attributelist = $1, $2
+ if elements.key?(element) then
+ elements[element] += 1
+ else
+ elements[element] = 1
+ end
+ attributelist.scan(/\s*([^\=]+)\=([\"\'])(.*?)(\2)/) do
+ key, value = $1, $3
+ attributes[element] = Hash.new unless attributes.key?(element)
+ attributes[element][key] = Hash.new unless attributes[element].key?(key)
+ if attributes[element][key].key?(value) then
+ attributes[element][key][value] += 1
+ else
+ attributes[element][key][value] = 1
+ end
+ end
+ end
+ data.scan(/\&([^\;]+)\;/o) do
+ entity = $1
+ if entities.key?(entity) then
+ entities[entity] += 1
+ else
+ entities[entity] = 1
+ end
+ end
+ result = file.gsub(/\..*?$/, '') + '.xlg' if result.empty?
+ if f = File.open(result,'w') then
+ report("saving report in #{result}")
+ f.puts "<?xml version='1.0'?>\n"
+ f.puts "<document>\n"
+ if entities.length>0 then
+ f.puts " <entities>\n"
+ entities.keys.asort.each do |entity|
+ f.puts " <entity name=#{entity.xstring} n=#{entities[entity].to_s.xstring}/>\n"
+ end
+ f.puts " </entities>\n"
+ end
+ if elements.length>0 then
+ f.puts " <elements>\n"
+ elements.keys.sort.each do |element|
+ if attributes.key?(element) then
+ f.puts " <element name=#{element.xstring} n=#{elements[element].to_s.xstring}>\n"
+ if attributes.key?(element) then
+ attributes[element].keys.asort.each do |attribute|
+ f.puts " <attribute name=#{attribute.xstring}>\n"
+ attributes[element][attribute].keys.asort.each do |value|
+ f.puts " <instance value=#{value.xstring} n=#{attributes[element][attribute][value].to_s.xstring}/>\n"
+ end
+ f.puts " </attribute>\n"
+ end
+ end
+ f.puts " </element>\n"
+ else
+ f.puts " <element name=#{element.xstring} n=#{elements[element].to_s.xstring}/>\n"
+ end
+ end
+ f.puts " </elements>\n"
+ end
+ f.puts "</document>\n"
+ else
+ report("unable to open file '#{result}'")
+ end
+ else
+ report("unable to load file '#{file}'")
+ end
+ else
+ report("unknown file '#{file}'")
+ end
+ end
+
+end
+
+logger = Logger.new(banner.shift)
+commandline = CommandLine.new
+
+commandline.registeraction('dir', 'generate directory listing')
+commandline.registeraction('mmlpages','generate graphic from mathml')
+commandline.registeraction('analyze', 'report entities and elements')
+
+# commandline.registeraction('dir', 'filename --pattern= --output= [--recurse --stripname --longname --url --root]')
+# commandline.registeraction('mmlpages','filename [--eps --jpg --png --style= --mode=]')
+
+commandline.registeraction('ls')
+
+commandline.registeraction('help')
+commandline.registeraction('version')
+
+commandline.registerflag('stripname')
+commandline.registerflag('longname')
+commandline.registerflag('recurse')
+
+commandline.registervalue('pattern')
+commandline.registervalue('url')
+commandline.registervalue('output')
+commandline.registervalue('root')
+
+commandline.registerflag('eps')
+commandline.registerflag('png')
+commandline.registerflag('jpg')
+commandline.registervalue('style')
+commandline.registervalue('modes')
+
+commandline.expand
+
+Commands.new(commandline,logger,banner).send(commandline.action || 'help')