#!/usr/bin/env perl # $Id$ # install-menu-txt.pl # # Copyright 2007, 2008 Reinhard Kotucha # Copyright 2007, 2008, 2009 Norbert Preining # This file is licensed under the GNU General Public License version 2 # or any later version. # # This file implements the text based menu system for the TeX Live installer. use vars qw(@::end_install_hook $::opt_no_cls); our %vars; our $tlpdb; our @media_available; our $previoustlpdb; our @collections_std; our @collections_lang; our @collections_lang_doc; our $texlive_release; my $MENU_CONTINUE = -1; our $MENU_INSTALL = 0; our $MENU_ABORT = 1; our $MENU_QUIT = 2; my $RETURN = $MENU_CONTINUE; # issue welcome message on end of installation push @::end_install_hook, sub { if (win32()) { print TeXLive::TLUtils::welcome(); } else { print TeXLive::TLUtils::welcome_paths(); } }; sub clear_screen { return 0 if ($::opt_no_cls); system (unix() ? 'clear' : 'cls'); } sub string_to_list { my $string=shift; return split(//, $string); } sub button { my $val=shift; return ($val)? '[X]':'[ ]'; } sub hbar { return '=' x79, "\n"; } sub toggle { my $var=shift; $vars{$var} = ($vars{$var} ? 0 : 1); } sub menu_head { my $text=shift; clear_screen; print "$text\n", hbar, "\n"; } sub other_options { my @options=@_; my %opts=( '-' => 'deselect all', '+' => 'select all', 'H' => 'help', 'R' => 'return to main menu', 'Q' => 'quit' ); if ($vars{'from_dvd'}) { $opts{'I'}='start installation for running from DVD'; } else { $opts{'I'}='start installation to hard disk'; } if ($options[$#options] eq 'diskspace') { pop @options; calc_depends (); print "\nOther actions: ". "Disk space required: $vars{'total_size'} MB\n"; } else { print "\nOther actions:\n"; } for my $option (@options) { if (defined $opts{"$option"}) { printf " <%s> %s\n", $option, $opts{$option}; } else { die "other_options: $opts{$option} undefined.\n"; } } } sub prompt { my $prompt=shift; print "\n$prompt: "; my $answer = ; $answer = "q" if !defined($answer); chomp($answer); return "$answer"; } # The menu loop. A menu is a function. Its return value is a # reference to another menu or to itself. sub run_menu_text { my (@args) = @_; # the text mode installer does not take interest in any argument # but the -old-installation-found while (@args) { my $f = shift @args; if ($f =~ m/^-old-installation-found=(.*)$/) { my $dn = $1; print "\nAn old installation of TeX Live has been found in $dn\n"; print " If you want the selection of collections and various options being taken over press `y', otherwise anything else. Import settings from previous TeX Live installation: (y/n): "; chomp(my $yn = ); if ($yn =~ m/^y$/i) { import_settings_from_old_tlpdb($dn); } } } my $menu=\&main_menu; while ($RETURN == $MENU_CONTINUE) { $menu=$menu->(); } return($RETURN); } $::run_menu = \&run_menu_text; sub binary_menu { my %command=( 'self' => \&binary_menu, 'R' => \&main_menu, 'Q' => \&quit ); my @binaries; my @keys=string_to_list "abcdefghijklmopstuvwxyz"; my $index=0; my %keyval; my $selected_platform; menu_head "Available sets of binaries:"; foreach my $key (keys %vars) { if ($key =~ /binary_(.*)/) { push @binaries, $1; } } @binaries=sort(@binaries); foreach my $binary (@binaries) { printf " %s %s %-16s %s\n", $keys[$index], button($vars{"binary_$binary"}), "$binary", platform_desc($binary); $keyval{"$keys[$index]"} = "binary_$binary"; ++$index; } other_options qw(- + R Q diskspace); my $answer=prompt 'Press key to select/deselect binary systems'; my @keystrokes=string_to_list $answer; foreach my $keystroke (@keystrokes) { if ($keystroke eq '-') { for my $binary (@binaries) { $vars{"binary_$binary"}=0 if defined $vars{"binary_$binary"}; } } if ($keystroke eq '+') { for my $binary (@binaries) { $vars{"binary_$binary"}=1 if defined $vars{"binary_$binary"}; } } if (defined $keyval{$keystroke}) { toggle "$keyval{$keystroke}"; } elsif (!defined $command{"\u$answer"}) { print "Unknown command: $keystroke\n\n"; } } if ($vars{"binary_win32"}) { $vars{"collection-wintools"} = 1; } else { $vars{"collection-wintools"} = 0; } if (defined $command{"\u$answer"}) { return $command{"\u$answer"}->(); } else { return $command{'self'}->(); } } sub scheme_menu { my %command=( 'self' => \&scheme_menu, 'R' => \&main_menu, 'Q' => \&quit ); my @schemes; my @keys=string_to_list "abcdefghijklmnopstuvwxyz"; my %keyval; my $index=0; menu_head 'Select a scheme:'; foreach my $pkg ($tlpdb->schemes) { push @schemes, $pkg; $vars{"$pkg"}=($vars{'selected_scheme'} eq $pkg)? 1:0; } @schemes=sort @schemes; push @schemes, "scheme-custom"; foreach my $scheme (@schemes) { $keyval{$keys[$index]}="$scheme"; if ($scheme ne "scheme-custom") { my $tlpobj = $tlpdb->get_package("$scheme"); printf " %s %s %s\n", $keys[$index], button($vars{"$scheme"}), $tlpobj->shortdesc; } else { printf " %s %s custom selection of collections\n", $keys[$index], button($vars{'selected_scheme'} eq "scheme-custom"); } ++$index; } select_scheme($vars{'selected_scheme'}); if ($vars{"binary_win32"}) { $vars{"collection-wintools"} = 1; } else { $vars{"collection-wintools"} = 0; } other_options qw(R Q diskspace); my $answer=prompt 'Press key to select a scheme'; if (defined $keyval{"$answer"}) { $vars{'selected_scheme'}=$keyval{"$answer"}; select_scheme($vars{'selected_scheme'}); return $command{'self'}->(); } if (defined $command{"\u$answer"}) { return $command{"\u$answer"}->(); } else { print "Unknown command: $answer\n\n"; return $command{'self'}->(); } } sub collection_menu { my %command=( 'self' => \&collection_menu, 'R' => \&main_menu, 'Q' => \&quit ); my @collections; my @keys=string_to_list "abcdefghijklmnopstuvwxyzABCDEFGHIJKLMNOPSTUVWXYZ"; my %keyval; my $index=0; my @coll_short_desc; my @coll_long_desc; menu_head 'Select collections:'; @collections=sort @collections_std; foreach my $collection (@collections) { next if ($collection eq 'collection-perl'); my $tlpobj = $tlpdb->get_package("$collection"); if (length $tlpobj->shortdesc>30) { push @coll_long_desc, $collection; } else { push @coll_short_desc, $collection; } } my $singlecolumn_index=@coll_short_desc-1; ## my $lines=@coll_short_desc/2; ++$lines if (@coll_short_desc%2); for (0..$lines-1) { $index=$_; my $collection=$coll_short_desc[$index]; my $tlpobj = $tlpdb->get_package("$collection"); $keyval{$keys[$index]}="$collection"; printf " %s %s %-33s", $keys[$index], button($vars{"$collection"}), substr($tlpobj->shortdesc,0,33); if (defined $coll_short_desc[$index+$lines]) { my $collection=$coll_short_desc[$index+$lines]; my $tlpobj=$tlpdb->get_package("$collection"); $keyval{$keys[$index+$lines]}="$collection"; printf " %s %s %-32s\n", $keys[$index+$lines], button($vars{"$collection"}), substr($tlpobj->shortdesc,0,32); } else { print "\n"; } } ## $index=$singlecolumn_index; # print "\n$index\n\n"; foreach my $collection (@coll_long_desc) { my $tlpobj=$tlpdb->get_package("$collection"); $keyval{$keys[$index+1]}="$collection"; printf " %s %s %s\n", $keys[$index+1], button($vars{"$collection"}), $tlpobj->shortdesc; ++$index; } ## other_options qw(- + R Q diskspace); my $answer=prompt 'Press key to select collections'; my @keystrokes=string_to_list $answer; foreach my $keystroke (@keystrokes) { if ($keystroke eq '-') { for my $collection (@collections) { $vars{"$collection"}=0 if defined $vars{"$collection"}; } } if ($keystroke eq '+') { for my $collection (@collections) { $vars{"$collection"}=1 if defined $vars{"$collection"}; } } if (defined $keyval{$keystroke}) { toggle "$keyval{$keystroke}"; } } if (defined $command{"\u$answer"}) { return $command{"\u$answer"}->(); } else { print "Unknown command: $answer\n\n"; return $command{'self'}->(); } } sub language_menu { my %command=( 'self' => \&language_menu, 'R' => \&main_menu, 'Q' => \&quit ); my @languages; my @lang_docs; my @lang_keys=string_to_list "abcdefghijklmnopstuvwxyz0123456789"; my @lang_doc_keys=string_to_list "ABCDEFGHIJKLMNOPSTUVWXYZ"; my %keyval; my $lang_index=0; my $lang_doc_index=0; my $lines; menu_head 'Select language support:'; @languages=sort @collections_lang; @lang_docs=sort @collections_lang_doc; $lines=@languages/2; ++$lines if (@languages%2); for my $index (0..$lines-1) { my $language=$languages[$index]; my $tlpobj = $tlpdb->get_package("$language"); $keyval{$lang_keys[$index]}="$language"; printf " %s %s %-33s", $lang_keys[$index], button($vars{"$language"}), substr($tlpobj->shortdesc,0,33); if (defined $languages[$index+$lines]) { my $language=$languages[$index+$lines]; my $tlpobj = $tlpdb->get_package("$language"); $keyval{$lang_keys[$index+$lines]}="$language"; printf " %s %s %-32s\n", $lang_keys[$index+$lines], button($vars{"$language"}), substr($tlpobj->shortdesc,0,32); } else { print "\n"; } } print "\nSelect language-specific documentation:\n\n"; $lines=@lang_docs/2; ++$lines if (@lang_docs%2); for my $index (0..$lines-1) { my $lang_doc=$lang_docs[$index]; my $tlpobj = $tlpdb->get_package("$lang_doc"); $keyval{$lang_doc_keys[$index]}="$lang_doc"; printf " %s %s %-33s", $lang_doc_keys[$index], button($vars{"$lang_doc"}), substr($tlpobj->shortdesc,0,33); if (defined $lang_docs[$index+$lines]) { my $lang_doc=$lang_docs[$index+$lines]; my $tlpobj = $tlpdb->get_package("$lang_doc"); $keyval{$lang_doc_keys[$index+$lines]}="$lang_doc"; printf " %s %s %-32s\n", $lang_doc_keys[$index+$lines], button($vars{"$lang_doc"}), substr($tlpobj->shortdesc,0,32); } else { print "\n"; } } other_options qw (+ - R Q diskspace); my $answer=prompt 'Press key to select language'; my @keystrokes=string_to_list $answer; foreach my $keystroke (@keystrokes) { if ($keystroke eq '-') { for my $collection (@languages,@lang_docs) { $vars{"$collection"}=0 if defined $vars{"$collection"}; } } if ($keystroke eq '+') { for my $collection (@languages,@lang_docs) { $vars{"$collection"}=1 if defined $vars{"$collection"}; } } if (defined $keyval{$keystroke}) { toggle "$keyval{$keystroke}"; } } if (defined $keyval{"$answer"}) { # $vars{'selected_scheme'}=$keyval{"$answer"}; return $command{'self'}->(); } if (defined $command{"\u$answer"}) { return $command{"\u$answer"}->(); } else { print "Unknown command: $answer\n\n"; return $command{'self'}->(); } } sub directories_menu { my %command=( 'self' => \&directories_menu, 'R' => \&main_menu, 'Q' => \&quit ); my $maindir = $vars{'from_dvd'} ? 'TEXDIRW' : 'TEXDIR'; menu_head "Current directories setup:"; if (!TeXLive::TLUtils::texdir_check($vars{$maindir})) { print "!! The default location as given below can't be written to. !! Either change the destination directory using <1> or create it !! outside this script. "; } if ($vars{'from_dvd'}) { print <<"EOF"; <1> TEXDIRW: $vars{'TEXDIRW'} (root for configuration- and generated data) EOF } else { print <<"EOF"; <1> TEXDIR: $vars{'TEXDIR'} support tree: $vars{'TEXDIR'}/texmf EOF } print <<"EOF"; <2> TEXMFLOCAL: $vars{'TEXMFLOCAL'} <3> TEXMFSYSVAR: $vars{'TEXMFSYSVAR'} <4> TEXMFSYSCONFIG: $vars{'TEXMFSYSCONFIG'} <5> TEXMFHOME: $vars{'TEXMFHOME'} EOF if (win32) { print " Note: ~ will expand to %USERPROFILE%\n"; } else { print " Note: ~ will expand to \$HOME (or to %USERPROFILE% on Windows)\n"; } other_options qw(R Q); my $answer = prompt 'Enter command'; if ("\u$answer" eq '1') { print "New value for $maindir [$vars{$maindir}]: "; $answer = &input_dirname (); $vars{$maindir} = $answer if $answer ne ""; if ($vars{$maindir}=~/^(.*)\/$texlive_release$/) { $vars{'TEXMFLOCAL'}="$1/texmf-local"; $vars{'TEXMFSYSVAR'}="$1/$texlive_release/texmf-var"; $vars{'TEXMFSYSCONFIG'}="$1/$texlive_release/texmf-config"; } elsif ($vars{$maindir}=~/^(.*)$/) { $vars{'TEXMFLOCAL'}="$1/texmf-local"; $vars{'TEXMFSYSVAR'}="$1/texmf-var"; $vars{'TEXMFSYSCONFIG'}="$1/texmf-config"; } $vars{'TEXDIRW'} = $vars{'TEXDIR'} unless $vars{'from_dvd'}; return $command{'self'}; } elsif ("\u$answer" eq '2') { print "New value for TEXMFLOCAL [$vars{'TEXMFLOCAL'}]: "; $answer = &input_dirname (); $vars{'TEXMFLOCAL'} = $answer if $answer ne ""; return $command{'self'}; } elsif ("\u$answer" eq '3') { print "New value for TEXMFSYSVAR [$vars{'TEXMFSYSVAR'}]: "; $answer = &input_dirname (); $vars{'TEXMFSYSVAR'} = $answer if $answer ne ""; return $command{'self'}; } elsif ("\u$answer" eq '4') { print "New value for TEXMFSYSCONFIG [$vars{'TEXMFSYSCONFIG'}]: "; $answer = &input_dirname (); $vars{'TEXMFSYSCONFIG'} = $answer if $answer ne ""; return $command{'self'}; } elsif ("\u$answer" eq '5') { print "New value for TEXMFHOME [$vars{'TEXMFHOME'}]: "; $answer = &input_dirname (1); $vars{'TEXMFHOME'} = $answer if $answer ne ""; return $command{'self'}; } if (defined $command{"\u$answer"}) { return $command{"\u$answer"}->(); } else { print "Unknown command: $answer\n\n"; return $command{'self'}->(); } } # Helper function to read a directory name and clean it up. # sub input_dirname { my $noexpansion = shift; chomp (my $answer = ); return "" if $answer eq ""; $answer =~ s!\\!/!g if win32(); # switch to forward slashes if (!$noexpansion) { my $home = getenv('HOME'); $home = getenv('USERPROFILE') if win32(); $home ||= '~'; $answer =~ s/^~/$home/; # $home expansion } if ($answer !~ m/^~/) { # relative paths are unlikely to work in texmf.cnf, et al., # and don't have any apparent practical use. Convert to absolute. if (! File::Spec->file_name_is_absolute($answer)) { $answer = Cwd::abs_path($answer); } } return $answer; } $vars{'page'}=0; sub html2text { my $filename=shift; my @text; open IN, "$filename"; @all_lines=; close IN; chomp @all_lines; my $itemcnt; my $ordered_list=0; my $h1_indent=25; my $h2_indent=3; my $h3_indent=6; for (@all_lines) { next if /DOCTYPE/; next if /