#! /usr/bin/perl # Interrupt List Lister # by E. C. Masloch, 2020 to 2026 # # Usage of the works is permitted provided that this # instrument is retained with the works, so that any entity # that uses the works is notified of this instrument. # # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. use warnings; use strict; use utf8; use Curses; use Audio::Beep; use Syntax::Keyword::Try; use Getopt::Long; use File::Spec; use Switch; use File::HomeDir; use File::Path qw(make_path); use Fcntl qw(SEEK_SET SEEK_CUR SEEK_END); # binmode(STDOUT, ":utf8"); # binmode(STDERR, ":utf8"); # binmode(STDIN, ":utf8"); # use open ":encoding(utf8)"; my $datadir = File::HomeDir->my_data(); if (not defined $datadir) { my $datadir = File::HomeDir->my_home(); } if (not defined $datadir) { die "Unable to get data directory\n"; } my $intlistdir = File::Spec->catdir($datadir, ".intlist"); make_path($intlistdir); my $searchhistfile = File::Spec->catfile($intlistdir, "search_history"); my $filehistfile = File::Spec->catfile($intlistdir, "file_history"); our @searchhistory = (); our @filehistory = (); our $searchhistff; our $filehistff; sub die_or_errorline { my $die_if_true = shift; my $msg = shift; if ($die_if_true) { die $msg."\n"; } else { errorline($msg); } } sub rereadhistories { my $die_if_true = shift; our $searchhistff; if (defined $searchhistff) { close $searchhistff; $searchhistff = undef; } open($searchhistff, "+>>", $searchhistfile) or die_or_errorline($die_if_true, "Cannot open I/O file \"$searchhistfile\": $!"); our $filehistff; if (defined $filehistff) { close $filehistff; $filehistff = undef; } open($filehistff, "+>>", $filehistfile) or die_or_errorline($die_if_true, "Cannot open I/O file \"$filehistfile\": $!"); our @searchhistory; our @filehistory; if (defined $searchhistff) { @searchhistory = (); seek($searchhistff, 0, SEEK_SET); while (<$searchhistff>) { s/[\r\n]+$//; if (s/^\"//) { # " push(@searchhistory, $_); } else { die_or_errorline($die_if_true, "Invalid search history file content"); } } } if (defined $filehistff) { @filehistory = (); seek($filehistff, 0, SEEK_SET); while (<$filehistff>) { s/[\r\n]+$//; if (s/^\"//) { # " push(@filehistory, $_); } else { die_or_errorline($die_if_true, "Invalid file history file content"); } } } } rereadhistories(1); sub trim { my $str = shift; $str =~ s/^\s+|\s+$//g; return $str; }; sub dobeep { try { Audio::Beep::beep(400, 100); } catch { Curses::beep(); } }; our @array_listingfiles = (); our @array_lstff = (); our @array_drawlinestart = (); our $activelistingfile = 0; our @saved_array_listingfiles = (); our @saved_array_lstff = (); our @saved_array_drawlinestart = (); our $saved_activelistingfile = 0; our $statuspage_in_effect = 0; our $D_statuspage_in_effect = 0; our $statuspage = ""; our @array_offsets = (); my $multi = 0; my $multi_disable_next = 0; my $help = 0; my $update_opcode2line = 0; Getopt::Long::Configure("no_auto_abbrev"); GetOptions( 'listing=s@' => \@array_listingfiles, 'multi!' => \$multi, 'help|h' => \$help, ) or die; foreach (@array_listingfiles) { push(@array_drawlinestart, 0); } foreach (@array_listingfiles) { push(@array_lstff, undef); } my $empty = shift; if (not scalar @array_listingfiles or defined $empty or $help) { die("Usage: $0 --listing file.lst\n") } sub addnstring { my $line = shift; my $column = shift; my $string = shift; my $limit = shift; if (length $string > $limit) { $string =~ s/^(.{$limit}).*$/$1/; } addstring($line, $column, $string); } my $ii = 0; foreach my $fn (@array_listingfiles) { open($array_lstff[$ii], "+<", $fn) or die "Cannot open input/output file \"$fn\": $!\n"; binmode($array_lstff[$ii]); $ii += 1; } initscr(); noecho(); cbreak(); nodelay(1); keypad(1); my $reloadrequested = 0; my $updaterequested = 1; my $redrawrequested = 1; my $winch = 0; my $selected = 0; my $instructionsamount = 0; my $resultlinestart; my $resultlineend; my $resultfile; my $foundamount; my @array_linesamount = (0) x scalar @array_listingfiles; my $drawlineend = 0; my @stops = (0, 8); my $highstops = 8; my $activestop = 0; my $saved_activestop = 0; my $maxstop = 15; my $activedisplacement = 0; my $autodisplace = 1; our $needrefresh = 0; our $savederrorline = ""; our $savederrorlinedobeep = 1; our $priorerrorline = ""; our $savedopcodeline = ""; our $savedopcode2line = ""; our $prioropcodeline = ""; our $prioropcode2line = ""; our $savedcommandline = ""; our $priorcommandline = ""; our $searchpattern = ""; our $abort = 0; $SIG{'USR1'} = sub { $updaterequested = 1; $selected = 0; $activedisplacement = 0; $autodisplace = 1; }; $SIG{'USR2'} = sub { $reloadrequested = 1; $updaterequested = 1; $selected = 0; $activedisplacement = 0; $autodisplace = 1; }; $SIG{'WINCH'} = sub { $redrawrequested = 1; $winch = 1; }; $SIG{'INT'} = \&ctrlchandler; sub ctrlchandler { $SIG{'INT'} = \&ctrlchandler; our $abort; $abort = 1; } sub errorline { our $savederrorline; our $savederrorlinedobeep; $savederrorline = shift; my $dobeep = shift; if (defined $dobeep) { $savederrorlinedobeep = $dobeep; } } sub write_errorline { my $dobeep = shift; our $savederrorlinedobeep; our $needrefresh; our $savederrorline; our $priorerrorline; my $string = $savederrorline; if ($string ne $priorerrorline or $redrawrequested) { if ($string ne $priorerrorline and length $string and $dobeep and $savederrorlinedobeep) { dobeep(); } $savederrorlinedobeep = 1; standout(); addstring($LINES - 2, 0, sprintf("%*s", - $COLS, $string)); standend(); $priorerrorline = $string; $needrefresh = 1; } } sub opcodeline { our $savedopcodeline; $savedopcodeline = shift; } sub opcode2line { our $savedopcode2line; $savedopcode2line = shift; } sub write_opcodeline { our $needrefresh; our $savedopcodeline; our $savedopcode2line; our $prioropcodeline; our $prioropcode2line; my $string = $savedopcodeline; my $string2 = $savedopcode2line; if ($string ne $prioropcodeline or $string2 ne $prioropcode2line or $redrawrequested) { addstring($LINES - 3, 0, sprintf("%*s", - ($COLS - length $string2), $string)); addstring($LINES - 3, ($COLS - length $string2), $string2); $prioropcodeline = $string; $prioropcode2line = $string2; $needrefresh = 1; } } sub commandline { our $savedcommandline; $savedcommandline = shift; } sub write_commandline { our $needrefresh; our $savedcommandline; our $priorcommandline; my $string = $savedcommandline; if ($string ne $priorcommandline or $redrawrequested) { $priorcommandline = $string; my $mask = $string; $mask =~ s/#/ /g; while ($mask =~ s/^([# ]*)([^_]*)(_.)/$1.(" " x length $2)."##"/e) { next; } $mask =~ s/##/_/g; $mask =~ s/[^ _]/ /g; $string =~ s/_//g; addstring($LINES - 1, 0, sprintf("%*s", - $COLS, $string)); while ($mask =~ s/^( *)(_+)/$1.(" " x length $2)/e) { chgat($LINES - 1, length $1, length $2, A_STANDOUT, 0, 0); } $needrefresh = 1; } } # https://github.com/abergs/tabstospaces/issues/4#issuecomment-524465830 our $tabstopwidth = 8; sub replacefunc { our $tabstopwidth; my $length = shift; my $string = shift; $string =~ s/^((?:[^\t]{$tabstopwidth})*[^\t]{$length})\t/ $1." " x ($tabstopwidth - $length) /e; return $string; }; sub expandtabs { our $tabstopwidth; my $string = shift; while ($string =~ /\t/) { foreach my $length (0 .. $tabstopwidth - 1) { $string = replacefunc($length, $string); }; }; return $string; } sub getsearchpattern { my $prompt = shift; our $searchpattern; errorline($prompt); write_errorline(0); my $rc = 0; my $input; ($rc, $input) = getinput($prompt, $LINES - 2, \@searchhistory, $searchhistff); if ($rc == 0) { errorline(""); } elsif ($rc == 1 or $rc == 2) { try { my $teststring = ""; $teststring =~ /$input/; $searchpattern = $input; errorline("Search pattern set to \"".$searchpattern."\"", 0); } catch { errorline("Invalid search pattern"); $rc = 4; } } elsif ($rc == 3) { errorline("No search pattern in history"); } return $rc; # return: # 0 = no pattern set (aborted) # 1 = new pattern set # 2 = empty pattern selected (pattern set to last history entry) # 3 = empty pattern with empty history # 4 = invalid pattern given } sub getinput { my $prompt = shift; my $line = shift; my $history = shift; my $histff = shift; my $rc = 0; our $abort; noecho(); nodelay(0); my $input = ""; my $newinput; my $promptlength = length $prompt; my $column = $promptlength; my $offset = 0; my $lastskip = 0; my $redraw = 0; my $limit = 1025; my $beep = 0; my $edited = 0; my $historyindex = scalar @$history; move($line, $column); while (1) { if ($winch) { endwin(); refresh(); $winch = 0; $redraw = 1; } if ($redraw) { my $show = $input; my $col = $column; my $skip = 0; my $maxpercol = ($COLS - 1 - $promptlength); move($line, $promptlength); if (length $show > $maxpercol) { if ($offset >= $lastskip) { $col -= $lastskip; $skip += $lastskip; } my $maxpercolhalf = int($maxpercol / 2); if ($maxpercolhalf == 0) { $maxpercolhalf = 1; } while ($col > ($maxpercol + $promptlength)) { $col -= $maxpercolhalf; $skip += $maxpercolhalf; } if ($skip <= $lastskip and $col > $promptlength and $col == ($maxpercol + $promptlength) and (length $show) > ($skip + $maxpercol)) { $col -= 1; $skip += 1; } } $show =~ s/^.{$skip}(.*)$/$1/; $show =~ s/^(.{0,$maxpercol}).*$/$1/; $lastskip = $skip; addstring($show); standout(); addstring(" " x ($COLS - $promptlength - length $show)); standend(); move($line, $col); $redraw = 0; } if ($beep) { dobeep(); $beep = 0; } my ($ch, $key) = getchar(); if (defined $ch) { if (ord($ch) == 9) { $beep = 1; next; } if (ord($ch) == 10) { last; } if (length $input >= $limit) { $beep = 1; next; } $edited = 1; $newinput = substr($input, 0, $offset); $newinput .= $ch; if ($offset < length $input) { $newinput .= substr($input, $offset); } $input = $newinput; $column += 1; $offset += 1; $redraw = 1; } else { switch($key) { case KEY_ENTER { last; } case KEY_LEFT { if ($offset) { $offset -= 1; $column -= 1; $redraw = 1; } else { dobeep(); } } case KEY_RIGHT { if ($offset < length $input) { $offset += 1; $column += 1; $redraw = 1; } else { dobeep(); } } case KEY_BACKSPACE { if ($offset) { $edited = 1; $newinput = substr($input, 0, $offset - 1); if ($offset < length $input) { $newinput .= substr($input, $offset); } $input = $newinput; $offset -= 1; $column -= 1; $redraw = 1; } else { if (length $input) { $beep = 1; } else { noecho(); nodelay(1); return (0, ""); } } } case KEY_DC { if ($offset < length $input) { $edited = 1; $newinput = substr($input, 0, $offset); if ($offset + 1 < length $input) { $newinput .= substr($input, $offset + 1); } $input = $newinput; $redraw = 1; } else { dobeep(); } } case KEY_HOME { $offset = 0; $column = $promptlength; $redraw = 1; } case KEY_END { $offset = length $input; $column = $offset + $promptlength; $redraw = 1; } case KEY_UP { if ($edited) { dobeep(); } else { if ($historyindex) { $historyindex -= 1; $input = $history->[$historyindex]; $offset = length $input; $column = $offset + $promptlength; $lastskip = 0; $redraw = 1; } else { dobeep(); } } } case KEY_DOWN { if ($edited) { dobeep(); } else { if ($historyindex < scalar @$history - 1) { $historyindex += 1; $input = $history->[$historyindex]; $offset = length $input; $column = $offset + $promptlength; $lastskip = 0; $redraw = 1; } else { dobeep(); } } } else { if ($abort) { $abort = 0; noecho(); nodelay(1); return (0, ""); } dobeep(); } } } } $rc = 1; if ($input eq "") { $input = $history->[$#$history]; $rc = 2; if (not defined $input) { $input = ""; $rc = 3; } } elsif (not scalar @$history or $history->[$#$history] ne $input) { push(@$history, $input); my $lasthistentry = ""; seek($histff, 0, SEEK_SET); while (<$histff>) { s/[\r\n]+$//; if (s/^\"//) { # " $lasthistentry = $_; } } if ($lasthistentry ne $input) { print $histff "\"".$input."\n"; flush $histff; } } noecho(); nodelay(1); return ($rc, $input); # return: # 0 = no input set (aborted) # 1 = new input set # 2 = empty input selected (input set to last history entry) # 3 = empty input with empty history } sub getfiles { my $forcemulti = shift; my @files = (); if ($multi or defined $forcemulti and $forcemulti) { my $index = 0; foreach my $ff (@array_lstff) { if (defined $ff) { push (@files, $index); } $index += 1; } } else { push (@files, $activelistingfile); } return @files; } # my $segsel; my $preserveerrorline = 0; while (1) { if ($abort) { endwin(); print("Aborting \n"); exit(127); } my $line = 0; if ($winch) { endwin(); refresh(); $winch = 0; } if ($updaterequested and $statuspage_in_effect) { $updaterequested = 0; $redrawrequested = 1; $resultlinestart = 0; $resultlineend = 0; $resultfile = undef; if (not $preserveerrorline) { errorline(""); } $preserveerrorline = 0; opcodeline(""); if (1) { my @files = getfiles(1); foreach my $currentfile (@files) { $array_linesamount[$currentfile] = 0; $line = 0; seek($array_lstff[$currentfile], 0, SEEK_SET); while (readline $array_lstff[$currentfile]) { $line += 1; } $array_linesamount[$currentfile] = $line; } } my $put_into_opcode2line = ""; $put_into_opcode2line .= sprintf("%-16s", "status page"); { $put_into_opcode2line .= " " x (2+2+1+2); } opcode2line($put_into_opcode2line); } elsif ($updaterequested) { if ($reloadrequested) { $reloadrequested = 0; if (defined $array_lstff[$activelistingfile]) { close $array_lstff[$activelistingfile]; $array_lstff[$activelistingfile] = undef; } if (not open($array_lstff[$activelistingfile], "+<", $array_listingfiles[$activelistingfile])) { errorline("Cannot open input/output file: $!"); $array_lstff[$activelistingfile] = undef; } else { binmode($array_lstff[$activelistingfile]); } } if ($updaterequested and (not $multi and defined $array_lstff[$activelistingfile] or $multi and scalar (grep {defined $_} @array_lstff))) { $updaterequested = 0; $redrawrequested = 1; $resultlinestart = 0; $resultlineend = 0; $resultfile = undef; $foundamount = 0; if (not $preserveerrorline) { errorline(""); } $preserveerrorline = 0; opcodeline(""); if (not $array_drawlinestart[$activelistingfile]) { $array_drawlinestart[$activelistingfile] = 1; } if (1) { my @files = getfiles(1); foreach my $currentfile (@files) { $array_linesamount[$currentfile] = 0; $line = 0; seek($array_lstff[$currentfile], 0, SEEK_SET); while (readline $array_lstff[$currentfile]) { $line += 1; } $array_linesamount[$currentfile] = $line; } $update_opcode2line = 1; next; } } } my $currentfile = $activelistingfile; if ($redrawrequested and defined $array_lstff[$currentfile]) { my $drawing = 0; my $drawingresult = 0; my $drawinghighlight = 0; my $newdrawlinestart; my $newdrawlineend; my $drawnline = 0; my $ii = 0; my $jj = 0; $line = 0; seek($array_lstff[$currentfile], 0, SEEK_SET); while (readline $array_lstff[$currentfile]) { $line += 1; if ($line == $array_drawlinestart[$currentfile]) { $drawing = 1; } if ($drawnline > ($LINES - 4)) { last; } if ($drawing) { my $withtabs = $_; $withtabs =~ s/[\r\n]+$//; my $expanded = expandtabs($withtabs); my $maskopcodes = ""; my $masksearchresult = ""; if (defined $searchpattern and $searchpattern ne "") { my $searching = $withtabs; while ($searching =~ /$searchpattern/) { $masksearchresult .= " " x length $`; $masksearchresult .= "_" x length $&; $searching = $'; if (substr($searchpattern, 0, 1) eq '^') { last; } } # $withtabs = has the tab stops to expand # $masksearchresult = has the blanks or underscores # at the corresponding positions sub replacefuncwithcontent { our $tabstopwidth; my $length = shift; my $stringtabs = shift; my $stringcontent = shift; my $newstringcontent = ""; my $part; if ($stringtabs =~ s/^((?:[^\t]{$tabstopwidth})*[^\t]{$length})\t/ $1." " x ($tabstopwidth - $length) /e) { $part = substr($stringcontent, 0, length $1); $newstringcontent .= $part; if (length $stringcontent > length $1) { $part = substr($stringcontent, length $1, 1); if (defined $part) { $newstringcontent .= $part x ($tabstopwidth - $length); } $part = substr($stringcontent, (length $1) + 1); if (defined $part) { $newstringcontent .= $part; } } $stringcontent = $newstringcontent; } return $stringtabs, $stringcontent; }; sub expandtabswithcontent { our $tabstopwidth; my $stringtabs = shift; my $stringcontent = shift; while ($stringtabs =~ /\t/) { foreach my $length (0 .. $tabstopwidth - 1) { ($stringtabs, $stringcontent) = replacefuncwithcontent($length, $stringtabs, $stringcontent); }; }; return $stringcontent; } if ($withtabs =~ /\t/) { $masksearchresult = expandtabswithcontent($withtabs, $masksearchresult); } } my $maskhighlight = ""; if ($activestop) { my $stop; if ($activestop <= $#stops) { $stop = $stops[$activestop]; } else { $stop = $stops[$#stops] + $highstops * ($activestop - $#stops); } $expanded =~ s/^.{0,$stop}//; $maskopcodes =~ s/^.{0,$stop}//; $masksearchresult =~ s/^.{0,$stop}//; $maskhighlight =~ s/^.{0,$stop}//; } addnstring($drawnline, 0, $expanded."\n", $COLS); while ($maskopcodes =~ s/^( *)(_+)/$1.(" " x length $2)/e) { chgat($drawnline, length $1, length $2, A_NORMAL, 0, 0); } my $searchhighlight = $drawingresult ? A_NORMAL : A_STANDOUT; while ($masksearchresult =~ s/^( *)(_+)/$1.(" " x length $2)/e) { chgat($drawnline, length $1, length $2, $searchhighlight, 0, 0); } while ($maskhighlight =~ s/^( *)(_+)/$1.(" " x length $2)/e) { chgat($drawnline, length $1, length $2, $searchhighlight, 0, 0); } if (length $expanded >= $COLS) { addstring($drawnline, $COLS - 1, ">"); chgat($drawnline, $COLS - 1, 1, A_STANDOUT, 0, 0); } $drawnline += 1; } } while ($drawnline <= ($LINES - 4)) { addnstring($drawnline, 0, " " x $COLS, $COLS); $drawnline += 1; } $needrefresh = 1; } if ($multi_disable_next) { $multi_disable_next = 0; $multi = 0; } my $command = "_(_Q_)uit"; if ($statuspage_in_effect) { $command .= " _(_X_) Close Status Page"; } else { $command .= " _(_R_)eload"; if ($#array_listingfiles) { if ($multi) { $command .= " Un_(_m_)ulti"; } else { $command .= " _(_M_)ulti"; } if (not $multi) { $command .= " _(_C_)ycle"; } if ($activelistingfile) { $command .= " _(_S_)witch"; } } } if ($activestop < $maxstop) { $command .= " _(_-_>_) Stop"; } if ($activestop > 0) { $command .= " _(_<_-_) Stop"; } commandline($command); if ($update_opcode2line) { $update_opcode2line = 0; my $put_into_opcode2line = ""; if ($#array_listingfiles) { $put_into_opcode2line .= sprintf("%2u/%2u ", $activelistingfile + 1, scalar @array_listingfiles); } $put_into_opcode2line .= sprintf("%12s", ( File::Spec->splitpath($array_listingfiles[$activelistingfile]) )[-1]); opcode2line($put_into_opcode2line); } write_errorline(1); write_opcodeline(); write_commandline(); move($LINES - 1, $COLS - 1); if ($needrefresh) { refresh(); } $redrawrequested = 0; my ($in, $out) = ('', ''); vec($in, fileno(STDIN), 1) = 1; select($out = $in, undef, undef, 1); KEYINPUT: while ((my $key = getch()) ne ERR) { my $originalkey = $key; if ($key ge 'A' and $key le 'Z') { $key = chr(ord($key) - ord('A') + ord('a')); } if ($key eq 'q') { endwin(); print("Exiting \n"); exit; } elsif ($key eq 'r' and not $statuspage_in_effect) { $reloadrequested = 1; $updaterequested = 1; $selected = 0; $activedisplacement = 0; last; } elsif ($key eq 'c' and not $statuspage_in_effect) { if ($multi) { dobeep(); } else { if ($originalkey eq 'c') { if ($activelistingfile < $#array_listingfiles) { $activelistingfile += 1; } else { $activelistingfile = 0; } } else { if ($activelistingfile > 0) { $activelistingfile -= 1; } else { $activelistingfile = $#array_listingfiles; } } if (not defined $array_lstff[$activelistingfile]) { errorline("Input file not opened"); } else { $updaterequested = 1; $selected = 0; $activedisplacement = 0; } } last; } elsif ($key eq 's' and not $statuspage_in_effect) { if (not $#array_listingfiles) { errorline("Missing additional listing file for switching"); } elsif (not $activelistingfile) { errorline("Listing file is already first in list"); } else { @array_listingfiles[$activelistingfile - 1,$activelistingfile] = @array_listingfiles[$activelistingfile,$activelistingfile - 1]; @array_drawlinestart[$activelistingfile - 1,$activelistingfile] = @array_drawlinestart[$activelistingfile,$activelistingfile - 1]; @array_lstff[$activelistingfile - 1,$activelistingfile] = @array_lstff[$activelistingfile,$activelistingfile - 1]; if ($resultfile == $activelistingfile) { $resultfile -= 1; } $activelistingfile -= 1; $updaterequested = 1; last; } } elsif ($key eq 'o' and not $statuspage_in_effect) { my $prompt = "Filename: "; errorline($prompt); write_errorline(0); my $rc = 0; my $input; ($rc, $input) = getinput($prompt, $LINES - 2, \@filehistory, $filehistff); if ($rc == 0) { errorline(""); } elsif ($rc == 1 or $rc == 2) { my $ii = 0; foreach my $fn (@array_listingfiles) { if ($fn eq $input) { errorline("File already opened"); $preserveerrorline = 1; $rc = 5; if ($activelistingfile != $ii) { $activelistingfile = $ii; if (not defined $array_lstff[$activelistingfile]) { errorline("Input file not opened"); } else { $updaterequested = 1; $selected = 0; $activedisplacement = 0; } } else { $updaterequested = 1; $selected = 0; $activedisplacement = 0; } last KEYINPUT; } $ii += 1; } my $ff; if (not open($ff, "+<", $input)) { errorline("Cannot open input/output file: $!"); } else { binmode($ff); errorline(""); $array_listingfiles[scalar @array_listingfiles] = $input; $array_lstff[scalar @array_listingfiles] = $ff; $array_drawlinestart[scalar @array_listingfiles] = 0; if (1 or not $multi) { $activelistingfile = scalar @array_listingfiles; } { $updaterequested = 1; $selected = 0; $activedisplacement = 0; } } } elsif ($rc == 3) { errorline("No filename in history"); } last; } elsif ($key eq 'e' and not $statuspage_in_effect) { if (not $#array_listingfiles) { errorline("Must leave open at least one file"); } else { if (defined $array_lstff[$activelistingfile]) { close $array_lstff[$activelistingfile]; $array_lstff[$activelistingfile] = undef; } splice @array_listingfiles, $activelistingfile, 1; splice @array_lstff, $activelistingfile, 1; splice @array_drawlinestart, $activelistingfile, 1; if ($resultfile == scalar @array_listingfiles) { $resultfile = undef; } if ($activelistingfile == scalar @array_listingfiles) { $activelistingfile -= 1; } if (not defined $array_lstff[$activelistingfile]) { errorline("Input file not opened"); } else { $updaterequested = 1; $selected = 0; $activedisplacement = 0; } } } elsif ($key eq 'h') { rereadhistories(0); } elsif ($key eq 'm' and not $statuspage_in_effect) { $multi = 1 - $multi; } elsif ($key eq 'a' and not $statuspage_in_effect) { $multi = 1; $multi_disable_next = 1; $updaterequested = 1; } elsif ($key eq KEY_LEFT) { if ($activestop > 0) { $activestop -= 1; $redrawrequested = 1; } else { dobeep(); } last; } elsif ($key eq KEY_RIGHT) { if ($activestop < $maxstop) { $activestop += 1; $redrawrequested = 1; } else { dobeep(); } last; } elsif ($key eq chr(9)) { if ($activestop < $#stops) { $activestop += 1; } else { $activestop = 0; } $redrawrequested = 1; last; } elsif ($key eq '/' or $key eq '?') { my $rc = getsearchpattern($key); if ($rc == 1 or $rc == 2) { if (1 and (not $multi and defined $array_lstff[$activelistingfile] or $multi and scalar (grep {defined $_} @array_lstff))) { my $lastresultline = 0; my $lastresultfile; my @files = getfiles(); PATTERNSEARCHFILES: foreach my $currentfile (@files) { my $line = 0; seek($array_lstff[$currentfile], 0, SEEK_SET); PATTERNSEARCHSINGLEFILE: while (readline $array_lstff[$currentfile]) { $line += 1; if ( $key eq '?' and $rc == 2 and ($currentfile == $activelistingfile and $line < $array_drawlinestart[$activelistingfile] or $currentfile < $activelistingfile ) or $key eq '?' and $rc == 1 and ($currentfile == $activelistingfile and $line <= $array_drawlinestart[$activelistingfile] or $currentfile < $activelistingfile ) or $key eq '/' and $rc == 2 and ($currentfile == $activelistingfile and $line > $array_drawlinestart[$activelistingfile] or $currentfile > $activelistingfile ) or $key eq '/' and $rc == 1 and ($currentfile == $activelistingfile and $line >= $array_drawlinestart[$activelistingfile] or $currentfile > $activelistingfile ) ) { my $withtabs = $_; $withtabs =~ s/[\r\n]+$//; if ($withtabs =~ /$searchpattern/) { $lastresultline = $line; $lastresultfile = $currentfile; if ($key eq '/') { last PATTERNSEARCHFILES; } } } } } if ($lastresultline) { if ($lastresultfile == $activelistingfile and $array_drawlinestart[$activelistingfile] == $lastresultline) { dobeep(); } $activelistingfile = $lastresultfile; $array_drawlinestart[$activelistingfile] = $lastresultline; $updaterequested = 1; } else { errorline("Pattern not found"); dobeep(); } } $redrawrequested = 1; last; } } elsif ($key eq 'x') { if ($statuspage_in_effect) { close $array_lstff[0]; @array_listingfiles = @saved_array_listingfiles; @array_lstff = @saved_array_lstff; @array_drawlinestart = @saved_array_drawlinestart; $activelistingfile = $saved_activelistingfile; $activestop = $saved_activestop; @saved_array_listingfiles = (); @saved_array_lstff = (); @saved_array_drawlinestart = (); $saved_activelistingfile = 0; $saved_activestop = 0; $statuspage_in_effect = 0; } else { $statuspage = ""; $statuspage .= "Status page\n" ."\n" ."Open files:\n"; my $ii = 0; foreach my $fn (@array_listingfiles) { $ii += 1; $statuspage .= sprintf(" %2u ", $ii)."\"".$fn."\"\n"; } my $ff; if (not open($ff, '<', \$statuspage)) { errorline("Internal error opening status page"); last; } @saved_array_listingfiles = @array_listingfiles; @saved_array_lstff = @array_lstff; @saved_array_drawlinestart = @array_drawlinestart; $saved_activelistingfile = $activelistingfile; $saved_activestop = $activestop; @array_listingfiles = ("status page"); @array_lstff = ($ff); @array_drawlinestart = (1); $activelistingfile = 0; $activestop = 0; $statuspage_in_effect = 1; } $updaterequested = 1; last; } elsif (1) { if ($key eq KEY_UP) { if ($array_drawlinestart[$activelistingfile] > 1) { $array_drawlinestart[$activelistingfile] -= 1; $redrawrequested = 1; last; } else { dobeep(); } } elsif ($key eq KEY_DOWN) { if (($array_drawlinestart[$activelistingfile] + $LINES - 5) < $array_linesamount[$activelistingfile]) { $array_drawlinestart[$activelistingfile] += 1; $redrawrequested = 1; last; } else { dobeep(); } } elsif ($key eq KEY_PPAGE) { if ($array_drawlinestart[$activelistingfile] > 1) { if ($array_drawlinestart[$activelistingfile] >= ($LINES - 5)) { $array_drawlinestart[$activelistingfile] -= ($LINES - 5); } else { $array_drawlinestart[$activelistingfile] = 1; } $redrawrequested = 1; last; } else { dobeep(); } } elsif ($key eq KEY_NPAGE) { if (($array_drawlinestart[$activelistingfile] + $LINES - 5) < $array_linesamount[$activelistingfile]) { if (($array_drawlinestart[$activelistingfile] + $LINES - 5 + $LINES - 5) <= ($array_linesamount[$activelistingfile])) { $array_drawlinestart[$activelistingfile] += ($LINES - 5); } elsif ($array_linesamount[$activelistingfile] >= $LINES - 5) { $array_drawlinestart[$activelistingfile] = $array_linesamount[$activelistingfile] - ($LINES - 5); } else { $array_drawlinestart[$activelistingfile] = 1; } $redrawrequested = 1; last; } else { dobeep(); } } elsif ($originalkey eq 'g') { $array_drawlinestart[$activelistingfile] = 1; $redrawrequested = 1; last; } elsif ($originalkey eq 'G') { if ($array_linesamount[$activelistingfile] >= ($LINES - 5)) { $array_drawlinestart[$activelistingfile] = $array_linesamount[$activelistingfile] - ($LINES - 5); } else { $array_drawlinestart[$activelistingfile] = 1; } $redrawrequested = 1; last; } else { dobeep(); } } } }