"Fossies" - the Fresh Open Source Software Archive

Member "install-tl-20231127/tlpkg/installer/install-menu-text.pl" (20 Feb 2023, 34342 Bytes) of package /linux/misc/install-tl-unx.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Perl source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 #!/usr/bin/env perl
    2 # $Id: install-menu-text.pl 65951 2023-02-20 10:13:03Z siepo $
    3 #
    4 # Copyright 2007-2022 Norbert Preining, Karl Berry
    5 # Copyright 2007-2008 Reinhard Kotucha
    6 # This file is licensed under the GNU General Public License version 2
    7 # or any later version.
    8 #
    9 # This file implements the text based menu system for the TeX Live installer.
   10 
   11 use vars qw(@::end_install_hook
   12             $::opt_no_cls $::opt_select_repository $::run_menu);
   13 
   14 our %vars;
   15 our $opt_in_place;
   16 our $tlpdb;
   17 our @media_available;
   18 our $media;
   19 our $previoustlpdb;
   20 our @collections_std;
   21 our $texlive_release;
   22 
   23 my $MENU_CONTINUE = -1;
   24 our $MENU_INSTALL = 0;
   25 our $MENU_ABORT   = 1;
   26 our $MENU_QUIT    = 2;
   27 
   28 
   29 my $RETURN = $MENU_CONTINUE;
   30 
   31 my $portable_toggled = 0;
   32 my $ptoggle_alert = "\n".
   33     "   !! Portable option changed;\n" .
   34     "   !! Directories have been reinitialized!\n";
   35 
   36 # some strings to describe the different meanings of tlpdbopt_file_assoc
   37 $::fileassocdesc[0] = __("None");
   38 $::fileassocdesc[1] = __("Only new");
   39 $::fileassocdesc[2] = __("All");
   40 
   41 $::deskintdesc[0] = __("None");
   42 $::deskintdesc[1] = __("Menu shortcuts");
   43 if (wndws()) { $::deskintdesc[2] = __("Launcher"); }
   44 
   45 sub clear_screen {
   46   return 0 if ($::opt_no_cls);
   47   system (unix() ? 'clear' : 'cls');
   48 }
   49 
   50 sub string_to_list {
   51   my $string=shift;
   52   return split(//, $string);
   53 }
   54 
   55 sub button { # for main menu: 1 char
   56   my $val=shift;
   57   my $vals=shift; # array ref to descriptions of possible values
   58   if (defined $vals) {
   59     return "[$val]";
   60   } else { # just yes/no
   61     return ($val)? '[X]':'[ ]';
   62   }
   63 }
   64 
   65 sub obutton { # for options menu: more chars allowed
   66   my $val=shift;
   67   my $vals=shift; # array ref to descriptions of possible values
   68   $vals = [' ', 'X'] unless defined $vals;
   69   return "[$$vals[$val]]";
   70 }
   71 
   72 sub hbar {
   73   return '=' x79, "\n";
   74 }
   75 
   76 sub toggle {
   77   my $var=shift;
   78   my $vals=shift; # array ref to descriptions of possible values
   79   $vals = [' ', 'X'] unless defined $vals;
   80   my $n_vals = @$vals;
   81   $vars{$var} += 1;
   82   $vars{$var} = 0 unless $vars{$var} < $n_vals;
   83 }
   84 
   85 sub menu_head {
   86   my $text = shift;
   87   clear_screen;
   88   print hbar(), "$text\n\n";
   89 }
   90 
   91 sub other_options {
   92   my @options=@_;
   93   my %opts=(
   94     '-' => 'deselect all',
   95     '+' => 'select all',
   96     'R' => 'return to main menu',
   97     'P' => 'save installation profile to \'texlive.profile\' and exit',
   98     'Q' => 'quit'
   99       );
  100 
  101   $opts{'I'}=$vars{'instopt_portable'} ? 'start portable installation' :
  102     'start installation to hard disk';
  103 
  104   print "\nActions:";
  105   if ($options[$#options] eq 'diskspace') {
  106     pop @options;
  107     calc_depends ();
  108     print " (disk space required: $vars{'total_size'} MB)";
  109   }
  110   print "\n";
  111 
  112   for my $option (@options) {
  113     if (defined $opts{"$option"}) {
  114       printf " <%s> %s\n", $option, $opts{$option};
  115     } else {
  116       die "other_options: $opts{$option} undefined.\n";
  117     }
  118   }
  119 }
  120 
  121 sub prompt {
  122   my $prompt = shift;
  123   print "\n$prompt: ";
  124   my $answer = <STDIN>;
  125   $answer = "q" if !defined($answer);
  126   chomp($answer);
  127   return "$answer";
  128 }
  129 
  130 # The menu loop. A menu is a function.  Its return value is a
  131 # reference to another menu or to itself.
  132 sub run_menu_text {
  133   my (@args) = @_;
  134   my $default = 0;
  135   # select mirror if -select-mirror is given
  136   if ($::opt_select_repository) {
  137     # network is always available
  138     my @mirror_list = TeXLive::TLUtils::create_mirror_list();
  139     print "Please select a repository:\n";
  140     print "Network repositories:" if ($#media_available >= 0);
  141     my @sel_to_index;
  142     my $selind = 0;
  143     # this is for 0 mirror.ctan.org, but it is printed last!
  144     push @sel_to_index, 0;
  145     $selind++;
  146     for my $i (0..$#mirror_list) {
  147       if ($mirror_list[$i] !~ m/^  /) {
  148         print "\n$mirror_list[$i]\n";
  149       } else {
  150         print " " if 1 <= $selind && $selind <= 9; # align
  151         print "[$selind] $mirror_list[$i]\n";
  152         push @sel_to_index, $i;
  153         $selind++;
  154       }
  155     }
  156     print "----\n";
  157     print "[0] default mirror   https://mirror.ctan.org\n";
  158     my $local_ind = "a";
  159     if ($#media_available >= 0) {
  160       print "Local repositories:\n";
  161       # we have some local media present, propose to use it
  162       for my $l (@media_available) {
  163         my ($a, $b) = split ('#', $l);
  164         if ($a eq 'local_compressed') {
  165           print "[$local_ind] compressed archive at $b\n";
  166           $default = $local_ind;
  167           #$local_ind = chr(ord($local_ind)+1);
  168           $local_ind++;
  169         } elsif ($a eq 'local_uncompressed') {
  170           print "[$local_ind] uncompressed archive at $b\n";
  171           $default = $local_ind;
  172           $local_ind++;
  173         } elsif ($a eq 'NET') {
  174           print "[$local_ind] cmd line repository: $b\n";
  175           $default = $local_ind;
  176           $local_ind++;
  177         } else {
  178           warn "$0: Unknown media $l";
  179         }
  180       }
  181     }
  182     print "[q] quit\n";
  183     $selind--;
  184     my $selstr = "Your selection ";
  185     if ($local_ind ne "a") {
  186       # we got at least some local repository
  187       if ($local_ind eq "b") {
  188         $selstr .= "(a,0-$selind,q)";
  189         $local_ind = chr(ord($local_ind)-1);
  190       } else {
  191         # that does not work!!!
  192         #$local_ind--;
  193         $local_ind = chr(ord($local_ind)-1);
  194         $selstr .= "(a-$local_ind,0-$selind,q)";
  195       }
  196     }
  197     $selstr .= " [$default]: ";
  198     my $got_answer = 0;
  199     my $ans = undef;
  200     while (!defined($ans)) {
  201       print $selstr;
  202       $ans = readline(*STDIN);
  203       if (!defined($ans)) {
  204         print "Please select `q' to quit the program!\n";
  205       } else {
  206         chomp($ans);
  207         $ans = $default if ($ans eq "");
  208         if ($ans =~ m/^[0-9]+$/) {
  209           if (0 <= $ans && $ans <= $selind) {
  210             my $mfull;
  211             if ($ans == 0) {
  212               $::init_remote_needed = 'ctan';
  213             } else {
  214               # only if something else but the predefined mirror is selected
  215               # we something here
  216               $mfull = TeXLive::TLUtils::extract_mirror_entry($mirror_list[$sel_to_index[$ans]]);
  217               print "selected mirror: ", $mfull, "\n";
  218               $::init_remote_needed = $mfull;
  219             }
  220           }
  221         } elsif ($ans =~ m/^[a-$local_ind]$/) {
  222           my $i = ord($ans) - ord('a');
  223           my $t = $media_available[$i];
  224           $t =~ s/^[^#]*#//;
  225           $::init_remote_needed = $t;
  226         } elsif ($ans eq 'q' || $ans eq 'Q') {
  227           print "Goodbye.\n";
  228           exit 0;
  229         } else {
  230           print "Not a valid answer: $ans.\n";
  231           $ans = undef;
  232         }
  233       }
  234     } 
  235   }
  236 
  237   # run remote init
  238   if (!do_remote_init($::init_remote_needed)) {
  239     warn "\n";
  240     warn "Please select a different mirror!  See info above.\n";
  241     print STDERR "Press Enter to exit... ";
  242     my $ans = readline (*STDIN);
  243     exit (1);
  244   }
  245 
  246   # the text mode installer does not take look at any argument
  247   # except -old-installation-found.
  248   while (@args) {
  249     my $f = shift @args;
  250     if ($f =~ m/^-old-installation-found=(.*)$/) {
  251       my $dn = $1;
  252       print "\nAn existing installation of TeX Live has been found in $dn\n";
  253       print "
  254 If you want its selection of schemes/collections and various options
  255 to be used, press `y', otherwise anything else.
  256 
  257 Import settings from previous TeX Live installation: (y/n): ";
  258       chomp(my $yn = <STDIN>);
  259       if (defined $yn && $yn =~ m/^y$/i) {
  260         import_settings_from_old_tlpdb($dn);
  261       }
  262     }
  263   }
  264   my $menu=\&main_menu;
  265   while ($RETURN == $MENU_CONTINUE) {
  266     $menu=$menu->();
  267   }
  268   return($RETURN);
  269 }
  270 $::run_menu = \&run_menu_text;
  271 
  272 sub binary_menu {
  273   my %command=(
  274     'self' => \&binary_menu,
  275     'R' => \&main_menu,
  276     'Q' => \&quit
  277       );
  278 
  279   my @binaries;
  280   my @keys=string_to_list "abcdefghijklmopstuvwxyz";
  281   my $index=0;
  282   my %keyval;
  283   my $selected_platform;
  284 
  285   menu_head "Available platforms:";
  286 
  287   foreach my $key (keys %vars) {
  288     if ($key =~ /binary_(.*)/) {
  289       push @binaries, $1;
  290     }
  291   }
  292   
  293   @binaries=sort TeXLive::TLUtils::sort_archs @binaries;
  294 
  295   foreach my $binary (@binaries) {
  296     printf "   %s %s %s (%s)\n", $keys[$index],
  297            button($vars{"binary_$binary"}),
  298            platform_desc($binary),
  299            "$binary";
  300     $keyval{"$keys[$index]"} = "binary_$binary";
  301     ++$index;
  302   }
  303   other_options qw(- + R Q diskspace);
  304 
  305   my $answer = prompt 'Enter letter(s) to (de)select platforms';
  306 
  307   my @keystrokes=string_to_list $answer;
  308 
  309   foreach my $keystroke (@keystrokes) {
  310     if ($keystroke eq '-') {
  311       for my $binary (@binaries) {
  312         $vars{"binary_$binary"}=0 if defined $vars{"binary_$binary"};
  313       }
  314     }
  315     if ($keystroke eq '+') {
  316       for my $binary (@binaries) {
  317         $vars{"binary_$binary"}=1 if defined $vars{"binary_$binary"};
  318       }
  319     }
  320     if (defined $keyval{$keystroke}) {
  321       toggle "$keyval{$keystroke}";
  322     } elsif (!defined $command{"\u$answer"}) {
  323       print "Unknown command: $answer\n\n";
  324     }
  325   }
  326   if ($vars{"binary_windows"}) {
  327     $vars{"collection-wintools"} = 1;
  328   } else {
  329     $vars{"collection-wintools"} = 0;
  330   }
  331   if (defined $command{"\u$answer"}) {
  332     return $command{"\u$answer"}->();
  333   } else {
  334     return $command{'self'}->();
  335   }
  336 }
  337 
  338 
  339 sub scheme_menu {
  340   my %command=(
  341     'self' => \&scheme_menu,
  342     'R' => \&main_menu,
  343     'Q' => \&quit
  344       );
  345 
  346   my @schemes;
  347   my @keys=string_to_list "abcdefghijklmnopstuvwxyz";
  348   my %keyval;
  349   my $index=0;
  350 
  351   menu_head 'Select scheme:';
  352 
  353   @schemes = schemes_ordered_for_presentation();
  354   foreach my $pkg (@schemes) {
  355     $vars{"$pkg"}=($vars{'selected_scheme'} eq $pkg)? 1:0;
  356   }
  357   push @schemes, "scheme-custom";
  358 
  359   foreach my $scheme (@schemes) {
  360     $keyval{$keys[$index]}="$scheme";
  361     if ($scheme ne "scheme-custom") {
  362       my $tlpobj = $tlpdb->get_package("$scheme");
  363       printf " %s %s %s\n", $keys[$index], button($vars{"$scheme"}),
  364              $tlpobj->shortdesc;
  365     } else {
  366       printf " %s %s custom selection of collections\n",
  367              $keys[$index], button($vars{'selected_scheme'} eq "scheme-custom");
  368     }
  369     ++$index;
  370   }
  371 
  372   select_scheme($vars{'selected_scheme'});
  373 
  374   if ($vars{"binary_windows"}) {
  375     $vars{"collection-wintools"} = 1;
  376   } else {
  377     $vars{"collection-wintools"} = 0;
  378   }
  379 
  380   other_options qw(R Q diskspace);
  381   my $answer = prompt 'Enter letter to select scheme';
  382 
  383   if (defined $keyval{"$answer"}) {
  384     $vars{'selected_scheme'}=$keyval{"$answer"};
  385     select_scheme($vars{'selected_scheme'});
  386     return $command{'self'}->();
  387   }
  388   if (defined $command{"\u$answer"}) {
  389     return $command{"\u$answer"}->();
  390   } else {
  391     print "Unknown command: $answer\n\n";
  392     return $command{'self'}->();
  393   }
  394 }
  395 
  396 
  397 sub collection_menu {
  398   my %command=(
  399     'self' => \&collection_menu,
  400     'R' => \&main_menu,
  401     'Q' => \&quit
  402       );
  403 
  404   my @collections;
  405   my @keys=string_to_list "abcdefghijklmnopstuvwxyzABCDEFGHIJKLMNOPSTUVWXYZ";
  406   my %keyval;
  407   my $index=0;
  408   my @coll_short_desc;
  409   my @coll_long_desc;
  410 
  411   menu_head 'Select collections:';
  412 
  413   @collections=sort @collections_std;
  414 
  415   foreach my $collection (@collections) {
  416     next if ($collection eq 'collection-perl');
  417     my $tlpobj = $tlpdb->get_package("$collection");
  418     if (length $tlpobj->shortdesc>30) {
  419       push @coll_long_desc, $collection;
  420     } else {
  421       push @coll_short_desc, $collection;
  422     }
  423   }
  424   my $singlecolumn_index=@coll_short_desc-1;
  425 
  426 ##<cols=2>
  427   my $lines=@coll_short_desc/2;
  428   ++$lines if (@coll_short_desc%2);
  429   for (0..$lines-1) {
  430     $index=$_;
  431     my $collection=$coll_short_desc[$index];
  432     my $tlpobj = $tlpdb->get_package("$collection");
  433     $keyval{$keys[$index]}="$collection";
  434     printf " %s %s %-33s", $keys[$index], button($vars{"$collection"}),
  435     substr($tlpobj->shortdesc,0,33);
  436     if (defined $coll_short_desc[$index+$lines]) {
  437       my $collection=$coll_short_desc[$index+$lines];
  438       my $tlpobj=$tlpdb->get_package("$collection");
  439       $keyval{$keys[$index+$lines]}="$collection";
  440       printf " %s %s %-32s\n", $keys[$index+$lines],
  441       button($vars{"$collection"}), substr($tlpobj->shortdesc,0,32);
  442     } else {
  443       print "\n";
  444     }
  445   }
  446 ##</cols=2>
  447   $index=$singlecolumn_index;
  448 #  print "\n$index\n\n";
  449   foreach my $collection (@coll_long_desc) {
  450     my $tlpobj=$tlpdb->get_package("$collection");
  451     $keyval{$keys[$index+1]}="$collection";
  452     printf " %s %s %s\n", $keys[$index+1], button($vars{"$collection"}),
  453     $tlpobj->shortdesc;
  454     ++$index;
  455   }
  456 ##</cols=1>
  457 
  458   other_options qw(- + R Q diskspace);
  459   my $answer = prompt 'Enter letter(s) to (de)select collection(s)';
  460 
  461   my @keystrokes=string_to_list $answer;
  462 
  463   foreach my $keystroke (@keystrokes) {
  464     if ($keystroke eq '-') {
  465       for my $collection (@collections) {
  466         $vars{"$collection"}=0 if defined $vars{"$collection"};
  467       }
  468     }
  469     if ($keystroke eq '+') {
  470       for my $collection (@collections) {
  471         $vars{"$collection"}=1 if defined $vars{"$collection"};
  472       }
  473     }
  474     if (defined $keyval{$keystroke}) {
  475       toggle "$keyval{$keystroke}";
  476     } elsif (!defined $command{"\u$answer"}) {
  477       print "Unknown command: $answer\n\n";
  478     }
  479   }
  480 
  481   if (defined $command{"\u$answer"}) {
  482     # if we play around with collections we also select custom-scheme
  483     # but we do not switch back to originally afterwards, too complicated
  484     # to be done
  485     select_scheme("scheme-custom");
  486     return $command{"\u$answer"}->();
  487   } else {
  488     return $command{'self'}->();
  489   }
  490 }
  491 
  492 
  493 sub directories_menu
  494 {
  495   my %command=(
  496     'self' => \&directories_menu,
  497     'R' => \&main_menu,
  498     'Q' => \&quit
  499       );
  500 
  501   menu_head "Directories customization:";
  502   if (!TeXLive::TLUtils::texdir_check($vars{'TEXDIR'}, 1)) {
  503     print "!! The default location as given below is forbidden or
  504 !! can't be written to.
  505 !! Either change the destination directory using <1> or create it
  506 !! outside this script.
  507 ";
  508   }
  509   my $texmfdir = $vars{'TEXDIR'} .
  510     ($vars{'TEXDIR'} =~ /\/$/ ? 'texmf-dist' : '/texmf-dist');
  511   if (!$opt_in_place) {
  512     print <<"EOF";
  513  <1> TEXDIR:         $vars{'TEXDIR'}
  514      main tree:      $texmfdir
  515 EOF
  516   } else {
  517     print <<"EOF";
  518      TEXDIR:         $vars{'TEXDIR'}
  519      main tree:      $texmfdir
  520 EOF
  521   }
  522   if (!$vars{'instopt_portable'}) {
  523     print <<"EOF";
  524 
  525  <2> TEXMFLOCAL:     $vars{'TEXMFLOCAL'}
  526  <3> TEXMFSYSVAR:    $vars{'TEXMFSYSVAR'}
  527  <4> TEXMFSYSCONFIG: $vars{'TEXMFSYSCONFIG'}
  528 
  529  <5> TEXMFVAR:       $vars{'TEXMFVAR'}
  530  <6> TEXMFCONFIG:    $vars{'TEXMFCONFIG'}
  531  <7> TEXMFHOME:      $vars{'TEXMFHOME'}
  532 
  533 EOF
  534 
  535     if (wndws()) {
  536       print " Note: ~ will expand to %USERPROFILE%\n";
  537     } else {
  538       print " Note: ~ will expand to \$HOME (or to %USERPROFILE% on Windows)\n";
  539     }
  540   }
  541 
  542   other_options qw(R Q);
  543   my $answer = prompt 'Enter command';
  544 
  545   if ("\u$answer" eq '1' and !$opt_in_place) {
  546     print "New value for TEXDIR [$vars{'TEXDIR'}]: ";
  547     $answer = &input_dirname ();
  548     # update free space information
  549     if ($answer ne $vars{'TEXDIR'}) {
  550       $vars{'free_size'} = TeXLive::TLUtils::diskfree($answer);
  551     }
  552     $vars{'TEXDIR'} = $answer if $answer ne "";
  553     my $texdirnoslash;
  554     if ($vars{'TEXDIR'}=~/^(.*)\/$texlive_release$/) {
  555       $texdirnoslash = $1;
  556       $vars{'TEXMFLOCAL'}="$texdirnoslash/texmf-local";
  557       $vars{'TEXMFSYSVAR'}="$texdirnoslash/$texlive_release/texmf-var";
  558       $vars{'TEXMFSYSCONFIG'}="$texdirnoslash/$texlive_release/texmf-config";
  559     } elsif ($vars{'TEXDIR'}=~/^(.*)$/) {
  560       $texdirnoslash = $1;
  561       $texdirnoslash =~ s!/$!!;
  562       $vars{'TEXMFLOCAL'}="$texdirnoslash/texmf-local";
  563       $vars{'TEXMFSYSVAR'}="$texdirnoslash/texmf-var";
  564       $vars{'TEXMFSYSCONFIG'}="$texdirnoslash/texmf-config";
  565     }
  566     return $command{'self'};
  567 
  568   } elsif ("\u$answer" eq '2' and !$vars{'instopt_portable'}) {
  569     print "New value for TEXMFLOCAL [$vars{'TEXMFLOCAL'}]: ";
  570     $answer = &input_dirname ();
  571     $vars{'TEXMFLOCAL'} = $answer if $answer ne "";
  572     return $command{'self'};
  573 
  574   } elsif ("\u$answer" eq '3' and !$vars{'instopt_portable'}) {
  575     print "New value for TEXMFSYSVAR [$vars{'TEXMFSYSVAR'}]: ";
  576     $answer = &input_dirname ();
  577     $vars{'TEXMFSYSVAR'} = $answer if $answer ne "";
  578     return $command{'self'};
  579 
  580   } elsif ("\u$answer" eq '4' and !$vars{'instopt_portable'}) {
  581     print "New value for TEXMFSYSCONFIG [$vars{'TEXMFSYSCONFIG'}]: ";
  582     $answer = &input_dirname ();
  583     $vars{'TEXMFSYSCONFIG'} = $answer if $answer ne "";
  584     return $command{'self'};
  585 
  586   } elsif ("\u$answer" eq '5' and !$vars{'instopt_portable'}) {
  587     print "New value for TEXMFVAR [$vars{'TEXMFVAR'}]: ";
  588     $answer = &input_dirname ("noexpansion");
  589     $vars{'TEXMFVAR'} = $answer if $answer ne "";
  590     return $command{'self'};
  591 
  592   } elsif ("\u$answer" eq '6' and !$vars{'instopt_portable'}) {
  593     print "New value for TEXMFCONFIG [$vars{'TEXMFCONFIG'}]: ";
  594     $answer = &input_dirname ("noexpansion");
  595     $vars{'TEXMFCONFIG'} = $answer if $answer ne "";
  596     return $command{'self'};
  597 
  598   } elsif ("\u$answer" eq '7' and !$vars{'instopt_portable'}) {
  599     print "New value for TEXMFHOME [$vars{'TEXMFHOME'}]: ";
  600     $answer = &input_dirname ("noexpansion");
  601     $vars{'TEXMFHOME'} = $answer if $answer ne "";
  602     return $command{'self'};
  603   }
  604 
  605   if (defined $command{"\u$answer"}) {
  606     return $command{"\u$answer"}->();
  607   } else {
  608     print "Unknown command: $answer\n\n";
  609     return $command{'self'}->();
  610   }
  611 }
  612 
  613 
  614 # Helper function to read a directory name and clean it up.
  615 # Unless NO_EXPANSION is true, convert to absolute path.
  616 #
  617 sub input_dirname
  618 {
  619   my $noexpansion = shift;
  620   chomp (my $answer = <STDIN>);
  621   return "" if $answer eq "";
  622 
  623   $answer =~ s!\\!/!g if wndws();  # switch to forward slashes
  624 
  625   if (!$noexpansion) {
  626     $answer = TeXLive::TLUtils::expand_tilde($answer);
  627   }
  628 
  629   if ($answer !~ m/^~/) {
  630     # relative paths are unlikely to work in texmf.cnf, et al.,
  631     # and don't have any apparent practical use.  Convert to absolute.
  632     if (! File::Spec->file_name_is_absolute($answer)) {
  633       $answer = TeXLive::TLUtils::tl_abs_path($answer);
  634       $answer = "" unless defined $answer;
  635     }
  636   }
  637   return $answer;
  638 }
  639 
  640 
  641 $vars{'page'}=0;
  642 
  643 sub html2text {
  644   my $filename=shift;
  645   my @text;
  646   open IN, "$filename";
  647   @all_lines=<IN>;
  648   close IN;
  649   chomp @all_lines;
  650 
  651   my $itemcnt;
  652   my $ordered_list=0;
  653   my $h1_indent=25;
  654   my $h2_indent=3;
  655   my $h3_indent=6;
  656 
  657   for (@all_lines) {
  658     next if /DOCTYPE/;
  659     next if /<!--/;
  660     next if /<title/i;
  661     next if /<\/?body/i;
  662     next if /<\/?html/i;
  663     next if /<\/?head/i;
  664     next if /<\/?meta/i;
  665     next if /^\s*$/; # ignore empty lines
  666 
  667     s/<i>/"/gi;  s/<\/i>/"/gi;  # italics
  668     s/<tt>/'/gi; s/<\/tt>/'/gi; # typewriter
  669     s/<p>.*//gi;                # paragraphs
  670     s/<\/ul>.*//gi;             # unsorted lists
  671     s/<\/ol>.*//gi;             # ordered lists
  672     s/&mdash;/--/gi;            # mdash
  673     s/&lt;/</gi; s/&gt;/>/gi;   # < and >
  674     if (/<h1>(.*?)<\/h1>/i) {
  675       push @text, " " x $h1_indent. "$1\n";
  676       push @text, " " x $h1_indent. "=" x (length $1). "\n";
  677       push @text, "\n";
  678     } elsif (/<h2>(.*?)<\/h2>/i) {
  679       push @text, "\n";
  680       push @text, " " x $h2_indent. "$1\n";
  681       push @text, " " x $h2_indent. "~" x (length $1). "\n";
  682       push @text, "\n";
  683     } elsif (/<h3>(.*?)<\/h3>/i) {
  684       push @text, "\n";
  685       push @text, " " x $h3_indent. "$1\n";
  686       push @text, " " x $h3_indent. "-" x (length $1). "\n";
  687       push @text, "\n";
  688     } elsif (/<ol>/i) {
  689       $ordered_list=1;
  690       $itemcnt=1;
  691     } elsif (/<ul>/i) {
  692       $ordered_list=0;
  693     } elsif (/^\s*<li>\s*(.*)/) {
  694       if ($ordered_list) {
  695         push @text, "\n";
  696         push @text, " $itemcnt. $1\n";
  697         ++$itemcnt;
  698       } else {
  699         push @text, "\n";
  700         push @text, " * $1\n";
  701       }
  702     } else {
  703       push @text, "$_\n";
  704     }
  705   }
  706   return @text;
  707 }
  708 
  709 
  710 # dumping the html doc to stdout does not seem very helpful,
  711 # and did not work for years with no one noticing, so this
  712 # function is no longer used.
  713 sub help_menu {
  714   my %command=(
  715     'self' => \&help_menu,
  716     'R' => \&main_menu,
  717     'Q' => \&quit
  718       );
  719   my $installer_help = "notused/tlpkg/installer/install-tl.html";
  720 
  721   clear_screen;
  722 
  723   my @text=html2text ($installer_help);
  724   my $lines=(@text);
  725   my $overlap=3;
  726   my $lps=32; # lines per screen - overlap
  727   my $firstline=$vars{'page'}*$lps;
  728   my $lastline=$firstline+$lps+$overlap;
  729   my $line=0;
  730 #  print "<<<$firstline>>> <<<$lastline>>>\n";
  731   for (@text) {
  732     print "$_" if ($line>=$firstline and $line<=$lastline);
  733     ++$line;
  734   }
  735   print "\n", hbar,
  736   "  <T> top  <N> next page  <P> previous page  <R> return"
  737       . "  <Q> quit         --", $vars{'page'}+1, "--\n";
  738 
  739   my $answer = prompt 'Enter command';
  740 
  741   if ("\u$answer" eq 'T') {
  742     $vars{'page'}=0;
  743     return $command{'self'};
  744 
  745   } elsif ("\u$answer" eq 'N') {
  746     $vars{'page'}+=1 unless $lastline>$lines;
  747     return $command{'self'};
  748 
  749   } elsif ("\u$answer" eq 'P') {
  750     $vars{'page'}-=1 if $vars{'page'}>=1;
  751     return $command{'self'};
  752 
  753   } elsif (defined $command{"\u$answer"}) {
  754     return $command{"\u$answer"};
  755 
  756   } else {
  757     print "Unknown command: $answer\n\n";
  758     return $command{'self'};
  759   }
  760 }
  761 
  762 
  763 sub options_menu {
  764   my $b_path=obutton($vars{'instopt_adjustpath'});
  765   my $b_doc=obutton($vars{'tlpdbopt_install_docfiles'});
  766   my $b_src=obutton($vars{'tlpdbopt_install_srcfiles'});
  767   my $b_fmt=obutton($vars{'tlpdbopt_create_formats'});
  768   my $b_letter=obutton($vars{'instopt_letter'});
  769   my $b_adjustrepo=obutton($vars{'instopt_adjustrepo'});
  770   my $b_deskint=obutton(
  771     $vars{'tlpdbopt_desktop_integration'}, \@::deskintdesc);
  772   my $b_admin=obutton($vars{'tlpdbopt_w32_multi_user'});
  773   my $b_addoneditor=obutton($vars{'collection-texworks'});
  774   my $b_restricted=obutton($vars{'instopt_write18_restricted'});
  775 
  776   my $sys_bin=$vars{'tlpdbopt_sys_bin'};
  777   my $sys_man=$vars{'tlpdbopt_sys_man'};
  778   my $sys_info=$vars{'tlpdbopt_sys_info'};
  779 
  780   my $t_sys_bin=($vars{'instopt_adjustpath'})? $vars{'tlpdbopt_sys_bin'}:'';
  781   my $t_sys_man=($vars{'instopt_adjustpath'})? $vars{'tlpdbopt_sys_man'}:'';
  782   my $t_sys_info=($vars{'instopt_adjustpath'})? $vars{'tlpdbopt_sys_info'}:'';
  783 
  784   my %command=(
  785     'self' => \&options_menu,
  786     'R' => \&main_menu,
  787     'Q' => \&quit
  788       );
  789 
  790   clear_screen;
  791   menu_head "Options customization:";
  792 
  793   print <<"EOF";
  794  <P> use letter size instead of A4 by default: $b_letter
  795  <E> execution of restricted list of programs: $b_restricted
  796  <F> create all format files:                  $b_fmt
  797 EOF
  798 ;
  799   if ($vars{'doc_splitting_supported'} and !$opt_in_place) {
  800     print " <D> install font/macro doc tree:              $b_doc\n";
  801   }
  802   if ($vars{'src_splitting_supported'} and !$opt_in_place) {
  803     print " <S> install font/macro source tree:           $b_src\n";
  804   }
  805   if (!$vars{'instopt_portable'}) {
  806     if (unix() || $::opt_all_options) {
  807       print <<"EOF";
  808  <L> create symlinks in standard directories:  $b_path
  809             binaries to: $t_sys_bin
  810             manpages to: $t_sys_man
  811                 info to: $t_sys_info
  812 EOF
  813 ;
  814     } else {
  815       print <<"EOF";
  816  <L> adjust registry entry for path:           $b_path
  817 EOF
  818 ;
  819     }
  820     if ((wndws() && !$vars{'instopt_portable'}) || $::opt_all_options) {
  821       print " <M> Start menu shortcuts / launcher:          ".obutton(
  822           $vars{'tlpdbopt_desktop_integration'}, \@::deskintdesc)."\n";
  823       print " <N> update file associations:                 ".obutton(
  824         $vars{'tlpdbopt_file_assocs'}, \@::fileassocdesc)."\n";
  825       if ($::opt_all_options || TeXLive::TLWinGoo::admin()) {
  826         # if we are admin we allow normal user installation, too
  827         print " <U> make installation available to all users: $b_admin\n";
  828       }
  829     }
  830   }
  831   if (wndws() || $::opt_all_options) {
  832     print " <W> install TeXworks front end:               $b_addoneditor\n";
  833   }
  834   if ($media ne "NET") {
  835     print " <Y> after install, set CTAN as source for package updates: $b_adjustrepo\n";
  836   }
  837   other_options qw(R Q diskspace);
  838   my $answer = prompt 'Enter command';
  839 
  840   # instopt_adjustpath
  841 
  842   if (unix()) {
  843     if (("\u$answer" eq 'L') and !$vars{'instopt_portable'}) {
  844       my $home = TeXLive::TLUtils::get_user_home();
  845       toggle 'instopt_adjustpath';
  846       if ($vars{'instopt_adjustpath'}) {
  847         print "New value for binary directory [$sys_bin]: ";
  848         chomp($answer=<STDIN>);
  849         $vars{'tlpdbopt_sys_bin'} =  "$answer" if (length $answer);
  850         $vars{'tlpdbopt_sys_bin'} =~ s@\\@/@g if (wndws());
  851         $vars{'tlpdbopt_sys_bin'} =~ s/^~/$home/;
  852         if ($vars{'tlpdbopt_sys_bin'}=~/^(.*)\/bin$/) {
  853           $vars{'tlpdbopt_sys_man'}="$1/man";
  854           $vars{'tlpdbopt_sys_info'}="$1/info";
  855         }
  856         print "New value for man directory    [$vars{'tlpdbopt_sys_man'}]: ";
  857         chomp($answer=<STDIN>);
  858         $vars{'tlpdbopt_sys_man'}="$answer" if (length $answer);
  859         $vars{'tlpdbopt_sys_man'} =~ s@\\@/@g if (wndws());
  860         $vars{'tlpdbopt_sys_man'} =~ s/^~/$home/;
  861 
  862         print "New value for info directory   [$vars{'tlpdbopt_sys_info'}]: ";
  863         chomp($answer=<STDIN>);
  864         $vars{'tlpdbopt_sys_info'}="$answer" if (length $answer);
  865         $vars{'tlpdbopt_sys_info'} =~ s@\\@/@g if (wndws());
  866         $vars{'tlpdbopt_sys_info'} =~ s/^~/$home/;
  867       }
  868       return $command{'self'};
  869     }
  870   } else {
  871     if (("\u$answer" eq 'L') and !$vars{'instopt_portable'}) {
  872       my $home = TeXLive::TLUtils::get_user_home;
  873       toggle 'instopt_adjustpath';
  874       return $command{'self'};
  875     }
  876   }
  877 
  878 #  # tlpdbopt_desktop_integration, tlpdbopt_file_assocs
  879 #
  880 #  if (wndws() || $::opt_all_options) {
  881 #    if ("\u$answer" eq 'M' and !$vars{'instopt_portable'}) {
  882 #      toggle 'tlpdbopt_desktop_integration';
  883 #      return $command{'self'};
  884 #
  885 #    } elsif ("\u$answer" eq 'N' and !$vars{'instopt_portable'}) {
  886 #      print "New value for file_assocs:\n";
  887 #      print "  0 -- don't tweak the file associations\n";
  888 #      print "  1 -- only add new file associations, don't overwrite old ones\n";
  889 #      print "  2 -- always create file associations to TeX Live programs\n";
  890 #      print "New value for file_assocs [$vars{'tlpdbopt_file_assocs'}]: ";
  891 #      chomp (my $a = <STDIN>);
  892 #      if ($a eq "0" || $a eq "1" || $a eq "2") {
  893 #        $vars{'tlpdbopt_file_assocs'} = $a;
  894 #      }
  895 #      return $command{'self'};
  896 #
  897 #    } elsif ("\u$answer" eq 'U' and !$vars{'instopt_portable'}) {
  898 #      toggle 'tlpdbopt_w32_multi_user';
  899 #      return $command{'self'};
  900 #    }
  901 #  }
  902 
  903   # other options
  904 
  905   if (("\u$answer" eq 'M') && !$vars{'instopt_portable'}) {
  906     toggle ('tlpdbopt_desktop_integration', \@::deskintdesc);
  907     return $command{'self'};
  908 
  909   } elsif (("\u$answer" eq 'N') && !$vars{'instopt_portable'}) {
  910     toggle ('tlpdbopt_file_assocs', \@::fileassocdesc);
  911     return $command{'self'};
  912 
  913   } elsif ("\u$answer" eq 'P') {
  914     toggle 'instopt_letter';
  915     return $command{'self'};
  916 
  917   } elsif ("\u$answer" eq 'F') {
  918     toggle 'tlpdbopt_create_formats';
  919     return $command{'self'};
  920 
  921   } elsif ("\u$answer" eq 'E') {
  922     toggle 'instopt_write18_restricted';
  923     return $command{'self'};
  924 
  925   } elsif ("\u$answer" eq 'S' and !$opt_in_place) {
  926     toggle 'tlpdbopt_install_srcfiles';
  927     return $command{'self'};
  928 
  929   } elsif ("\u$answer" eq 'D' and !$opt_in_place) {
  930     toggle 'tlpdbopt_install_docfiles';
  931     return $command{'self'};
  932 
  933   } elsif (defined $command{"\u$answer"}) {
  934     return $command{"\u$answer"};
  935 
  936   } elsif (("\u$answer" eq 'W') && ($::opt_all_options || wndws()) &&
  937        !$opt_in_place ) {
  938     toggle 'collection-texworks';
  939     return $command{'self'};
  940 
  941   } elsif ("\u$answer" eq 'Y' and $media ne "NET") {
  942     toggle 'instopt_adjustrepo';
  943     return $command{'self'};
  944 
  945   } else {
  946     print "Unknown or unsupported command: $answer\n\n";
  947     return $command{'self'};
  948   }
  949 }
  950 
  951 
  952 sub quit {
  953   exit 0;
  954   $RETURN = $MENU_QUIT;
  955 }
  956 
  957 sub do_install {
  958   my $reserve = 100;
  959   my $doit = 1;
  960   if ($vars{'free_size'} > 0
  961       && $vars{'free_size'} + $reserve < $vars{'total_size'}) { 
  962     print STDERR <<"EOF";
  963 *** WARNING ****************************************************
  964 The installation requires $vars{'total_size'}M of disk space
  965 but only $vars{'free_size'}M is available.
  966 
  967 You probably want to either clean up the destination filesystem,
  968 or choose a different installation location,
  969 or reduce what gets installed.
  970 
  971 Press Enter to return to the menu, or i to install anyway.
  972 ****************************************************************
  973 EOF
  974     my $ans = readline (*STDIN);
  975     $doit = 0;
  976     chomp($ans);
  977     if ($ans eq "i" or $ans eq "I") {
  978       $doit = 1;
  979     }
  980   }
  981   if ($doit) {
  982     # set env variable to make install-tl not trip over
  983     $ENV{'TEXLIVE_INSTALL_NO_DISKCHECK'} = 1;
  984     $RETURN = $MENU_INSTALL;
  985   } else {
  986     main_menu();
  987   }
  988 }
  989 
  990 sub toggle_portable {
  991   if ($vars{'instopt_portable'}) {
  992     $vars{'instopt_portable'} = 0;
  993     $vars{'tlpdbopt_desktop_integration'} = 0;
  994     $vars{'instopt_adjustpath'} = 0;
  995     $vars{'tlpdbopt_file_assocs'} = 0;
  996     $vars{'tlpdbopt_w32_multi_user'} = 0;
  997   } else {
  998     $vars{'instopt_portable'} = 1;
  999     $vars{'tlpdbopt_desktop_integration'} = 1;
 1000     $vars{'instopt_adjustpath'} = 1;
 1001     $vars{'tlpdbopt_file_assocs'} = 1;
 1002     $vars{'tlpdbopt_w32_multi_user'} = 1;
 1003   }
 1004   $portable_toggled = 1;
 1005   set_texlive_default_dirs(); # this sub tests for portable and in_place
 1006   main_menu;
 1007 }
 1008 
 1009 sub callback_save_profile {
 1010   create_profile("texlive.profile");
 1011   print "Installation profile saved to 'texlive.profile', exiting.\n";
 1012   exit(0);
 1013 }
 1014 
 1015 sub main_menu {
 1016   my $this_platform=platform_desc($vars{'this_platform'});
 1017 
 1018   my $b_path=button($vars{'instopt_adjustpath'});
 1019   my $b_doc=button($vars{'tlpdbopt_install_docfiles'});
 1020   my $b_src=button($vars{'tlpdbopt_install_srcfiles'});
 1021   my $b_fmt=button($vars{'tlpdbopt_create_formats'});
 1022   my $b_letter=button($vars{'instopt_letter'});
 1023   my $b_deskint=button($vars{'tlpdbopt_desktop_integration'}, \@::deskintdesc);
 1024   if (wndws()) {
 1025     my $b_fileassoc=button($vars{'tlpdbopt_file_assocs'}, \@::fileassocdesc);
 1026   }
 1027   my $b_admin=button($vars{'tlpdbopt_w32_multi_user'});
 1028   my $b_addoneditor=button($vars{'collection-texworks'});
 1029   my $b_restricted=button($vars{'instopt_write18_restricted'});
 1030   my $b_adjustrepo=button($vars{'instopt_adjustrepo'});
 1031 
 1032   my $warn_nobin;
 1033 
 1034   $warn_nobin=set_install_platform;
 1035 
 1036   $vars{'n_systems_selected'}=0;
 1037   $vars{'n_collections_selected'}=0;
 1038   foreach my $key (keys %vars) {
 1039     if ($key=~/^binary.*/) {
 1040       ++$vars{'n_systems_selected'} if $vars{$key}==1;
 1041     }
 1042     if ($key=~/^collection/) {
 1043       ++$vars{'n_collections_selected'} if $vars{$key}==1;
 1044     }
 1045   }
 1046   calc_depends();
 1047 
 1048   my %command = (
 1049     'self' => \&main_menu,
 1050     'D' => \&directories_menu,
 1051     'I' => \&do_install,
 1052     'O' => \&options_menu,
 1053     'Q' => \&quit,
 1054     'V' => \&toggle_portable,
 1055     'P' => \&callback_save_profile,
 1056   );
 1057   if (!$opt_in_place) {
 1058     $command{'B'} = \&binary_menu if unix();
 1059     $command{'C'} = \&collection_menu;
 1060     $command{'S'} = \&scheme_menu;
 1061   }
 1062 
 1063   clear_screen;
 1064   my $freestring = ($vars{'free_size'} >= 0 ? " (free: $vars{'free_size'} MB)" : "");
 1065   print <<"EOF";
 1066 ======================> TeX Live installation procedure <=====================
 1067 
 1068 ======>   Letters/digits in <angle brackets> indicate   <=======
 1069 ======>   menu items for actions or customizations      <=======
 1070 = help>   https://tug.org/texlive/doc/install-tl.html   <=======
 1071 
 1072  Detected platform: $this_platform
 1073  $warn_nobin
 1074 EOF
 1075 
 1076   if (!$opt_in_place) {
 1077     print <<"EOF";
 1078  <B> set binary platforms: $vars{'n_systems_selected'} out of $vars{'n_systems_available'}
 1079 
 1080  <S> set installation scheme: $vars{'selected_scheme'}
 1081 
 1082  <C> set installation collections:
 1083      $vars{'n_collections_selected'} collections out of $vars{'n_collections_available'}, disk space required: $vars{'total_size'} MB$freestring
 1084 EOF
 1085 
 1086   }
 1087     if ($portable_toggled) {
 1088       print $ptoggle_alert;
 1089       $portable_toggled = 0;
 1090     }
 1091     print <<"EOF";
 1092 
 1093  <D> set directories:
 1094    TEXDIR (the main TeX directory):
 1095 EOF
 1096 
 1097   if (TeXLive::TLUtils::texdir_check($vars{'TEXDIR'}, 1)) {
 1098     print "     $vars{'TEXDIR'}\n";
 1099   } else {
 1100     print "     !! default location: $vars{'TEXDIR'}\n";
 1101     print "     !! is not writable or not allowed, please select a different one!\n";
 1102   }
 1103   print <<"EOF";
 1104    TEXMFLOCAL (directory for site-wide local files):
 1105      $vars{'TEXMFLOCAL'}
 1106    TEXMFSYSVAR (directory for variable and automatically generated data):
 1107      $vars{'TEXMFSYSVAR'}
 1108    TEXMFSYSCONFIG (directory for local config):
 1109      $vars{'TEXMFSYSCONFIG'}
 1110    TEXMFVAR (personal directory for variable and automatically generated data):
 1111      $vars{'TEXMFVAR'}
 1112    TEXMFCONFIG (personal directory for local config):
 1113      $vars{'TEXMFCONFIG'}
 1114    TEXMFHOME (directory for user-specific files):
 1115      $vars{'TEXMFHOME'}
 1116 
 1117 EOF
 1118 
 1119 print <<"EOF";
 1120  <O> options:
 1121    $b_letter use letter size instead of A4 by default
 1122    $b_restricted allow execution of restricted list of programs via \\write18
 1123    $b_fmt create all format files
 1124 EOF
 1125 
 1126   if (!$opt_in_place) {
 1127     if ($vars{'doc_splitting_supported'}) {
 1128       print "   $b_doc install macro/font doc tree\n";
 1129     }
 1130     if ($vars{'src_splitting_supported'}) {
 1131       print "   $b_src install macro/font source tree\n";
 1132     }
 1133   }
 1134   if (wndws()) {
 1135     if (!$vars{'instopt_portable'}) {
 1136       print "   $b_path adjust search path\n";
 1137       print "   $b_deskint add menu items, shortcuts, etc.\n";
 1138       print "   [$vars{'tlpdbopt_file_assocs'}] update file associations\n";
 1139       if (admin()) {
 1140         print "   $b_admin make installation available to all users\n";
 1141       }
 1142     }
 1143     print "   $b_addoneditor install TeXworks front end\n";
 1144   }
 1145 
 1146   print "   $b_path create symlinks to standard directories\n"
 1147     unless ($vars{'instopt_portable'} || wndws());
 1148   
 1149   print "   $b_adjustrepo after install, set CTAN as source "
 1150           . "for package updates\n"
 1151     unless ($media eq 'NET');
 1152 
 1153   if ($vars{'instopt_portable'}) {
 1154     print "\n <V> set up for regular installation to hard disk\n";
 1155   } else {
 1156     print "\n <V> set up for portable installation\n";
 1157   }
 1158 
 1159   other_options qw(I P Q);
 1160   my $answer = prompt 'Enter command';
 1161 
 1162   if (defined $command{"\u$answer"}) {
 1163     return $command{"\u$answer"};
 1164   } else {
 1165     print "Unknown command: $answer\n\n";
 1166     return $command{'self'};
 1167   }
 1168 }
 1169 # needs a terminal 1 for require to succeed!
 1170 1;
 1171 
 1172 __END__
 1173 
 1174 ### Local Variables:
 1175 ### perl-indent-level: 2
 1176 ### tab-width: 2
 1177 ### indent-tabs-mode: nil
 1178 ### End:
 1179 # vim:set tabstop=2 expandtab: #