#! /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 Data::Dumper qw(Dumper); use Fcntl qw(SEEK_SET SEEK_CUR SEEK_END); # binmode(STDOUT, ":utf8"); # binmode(STDERR, ":utf8"); # binmode(STDIN, ":utf8"); # use open ":encoding(utf8)"; our $tabstopwidth = 8; 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 $linkhistfile = File::Spec->catfile($intlistdir, "link_history"); my $filehistfile = File::Spec->catfile($intlistdir, "file_history"); our @searchhistory = (); our @linkhistory = (); our @filehistory = (); our $searchhistff; our $linkhistff; our $filehistff; our $print = 1; sub print_or_errorline { our $print; my $msg = shift; if ($print) { print $msg."\n"; } else { errorline($msg); } } sub print_or_opcodeline { our $print; my $msg = shift; if ($print) { print $msg."\n"; } else { opcodeline($msg); } } 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 $linkhistff; if (defined $linkhistff) { close $linkhistff; $linkhistff = undef; } open($linkhistff, "+>>", $linkhistfile) or die_or_errorline($die_if_true, "Cannot open I/O file \"$linkhistfile\": $!"); 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 @linkhistory; 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 $linkhistff) { @linkhistory = (); seek($linkhistff, 0, SEEK_SET); while (<$linkhistff>) { s/[\r\n]+$//; if (s/^\"//) { # " push(@linkhistory, $_); } else { die_or_errorline($die_if_true, "Invalid link 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); our $priorseek = undef; our %priorreg = (); our $SUMMARYLINES; our $DETAILLINES = 0; sub readline_replace { my $ff = shift; my $noprocess = shift; our $priorseek; our %priorreg = (); if ($noprocess) { return readline($ff); } my $line = readline($ff); if (not defined $line) { return undef; } while (not $line =~ /^--------/) { $priorseek = tell($ff); $line = readline($ff); if (not defined $line) { return undef; } } my $seek = tell($ff); $line = readline($ff); if (not defined $line) { return undef; } my $summary = $line; my $prefix = " ("; my $suffix = ""; $summary =~ s/[\r\n]+$//; while (readline($ff)) { if (/^[^\t]/) { last; } if (/^\s+AH = (?:AMIS )?multiplex number([\r\n]*$| for )/) { next; } if (/^\s+(E?[ABCD][XHL]|E?[SD]I|E?[BS]P|[DESC]S) \s*=\s*([0-9A-Fa-f]+[Hh]?) (?:\.\.[0-9A-Fa-f]+[Hh]? |-[0-9A-Fa-f]+[Hh]? |\s+to\s+[0-9A-Fa-f]+[Hh]? )?[\r\n]*$/x) { $priorreg{uc($1)} = [uc($2)]; $summary .= "$prefix$1=$2"; $prefix = "/"; $suffix = ")"; } elsif (/^\s+(E?[ABCD][XHL]|E?[SD]I|E?[BS]P|[DESC]S) \s*=\s*([0-9A-Fa-f]+[Hh]?) ((?:\s*\/\s*[0-9A-Fa-f]+[Hh]?)+) [\r\n]*$/x) { my $reg = $1; $priorreg{uc($reg)} = [uc($2)]; $summary .= "$prefix$1=$2"; (my $alt = $3) =~ s/^\s*\/\s*//; foreach my $var (split /\s*\/\s*/, $alt) { push(@{ $priorreg{uc($reg)} }, uc($var)); $summary .= ",$var"; } $prefix = "/"; $suffix = ")"; } elsif (/^\s+(E?[ABCD][XHL]|E?[SD]I|E?[BS]P|[DESC]S) \s*=\s*([0-9A-Fa-f]+[Hh]?) \s*\(?\s*(\'\S+\'|\"\S+\")\s*\)?[\r\n]*$/x) { my $reg = $1; my $number = $2; my $text = $3; $text =~ s/[\'\"]+//g; my @values = unpack("(H2)*", $text); my $numeric = uc($number); $numeric =~ s/H//; if ($numeric eq uc(join('', @values)) or $numeric eq uc(join('', reverse(@values)))) { $priorreg{uc($reg)} = [uc($number)]; $summary .= "$prefix$reg=$number"; $prefix = "/"; $suffix = ")"; } } } $summary .= $suffix; seek($ff, $seek, SEEK_SET); return $summary; } 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_link_history = (); our $link_history_index = 0; sub selecthyperlink { our @array_lstff; our @array_listingfiles; our $currentfile; our $detaillinesamount; our $detaildrawlinestart; our $SUMMARYLINES; our $DETAILLINES; our $resultlinestart; our $resultlineend; our $resultfile; our $resultseek; our $resultsummary; our $currentlinkline; our $currentlinkoffset; our $multi; our $activelistingfile; our $redrawrequested; our $statuspage_in_effect; our @array_drawlinestart; our $indetailfocus; our @array_link_history; our $link_history_index; our $listlinks; our $debuglistlinks; our $listonlybroken; our $listlinebreak; if ($listlinks and $debuglistlinks and 0) { print( "File: " .(File::Spec->splitpath($array_listingfiles[$activelistingfile]) )[-1] .", line=$currentlinkline, ofs=$currentlinkoffset\n" ); } my %priorstate = ( currentfile => $currentfile, currentlinkline => $currentlinkline, currentlinkoffset => $currentlinkoffset, detaildrawlinestart => $detaildrawlinestart, resultlinestart => $resultlinestart, resultlineend => $resultlineend, resultfile => $resultfile, resultseek => $resultseek, activelistingfile => $activelistingfile, array_drawlinestart => [@array_drawlinestart], indetailfocus => $indetailfocus, detaillines_nonzero => ($DETAILLINES != 0), ); my $link = shift; my $summaryindex = shift; my $quietnotfound = shift; my $label; my $name = undef; my $findint = undef; my $findreg = undef; my $findtable = undef; my $findmem = undef; my $findcall = undef; my $findport = undef; my $found = 0; my $drawing = 0; my $drawnline = 1 + ($SUMMARYLINES - 4); if ($listlinks) { $drawnline = 1; } elsif (defined $link and $DETAILLINES == 0) { $drawnline = 1 + ($LINES - ($LINES - 8) - 4); # $DETAILLINES = $LINES - 8; # $SUMMARYLINES = $LINES - $DETAILLINES; } my $first = 1; my $line = 0; if (defined $link and not defined $resultseek) { $resultseek = 0; } seek($array_lstff[$currentfile], $resultseek, SEEK_SET); $detaillinesamount = 0; while (defined ($_ = readline_replace($array_lstff[$currentfile], 1))) { if (not $first and /^--------/) { last; } $first = 0; $line += 1; } $detaillinesamount = $line; seek($array_lstff[$currentfile], $resultseek, SEEK_SET); $drawing = 0; $line = 0; $first = 1; my $second = 0; my $nextsecond = 0; my $drawone = 0; my $int = undef; MATCHLINK: while (defined ($_ = readline_replace($array_lstff[$currentfile], 1))) { $second = $nextsecond; $nextsecond = 0; $line += 1; if ($line == $detaildrawlinestart) { $drawing = 1; } elsif ($line == 1) { $drawone = 1; } if (not $listlinks and $drawnline > ($LINES - 4)) { last; } if (not $first and /^--------/) { last; } if ($first and /^-{8}.-([0-9A-Fa-f]{2})/) { $int = sprintf("%02X", hex($1)); } if ($first) { $nextsecond = 1; } $first = 0; if ($drawing or $drawone or defined $link) { $drawone = 0; my $withtabs = $_; $withtabs =~ s/[\r\n]+$//; my $expanded = expandtabs($withtabs); my $maskhighlight = ""; my $linking = $expanded; if (defined $link) { $second = 0; $linking = $link; $linking =~ s/^call\s*/\@/i; $linking =~ s/ ^([0-9A-Fa-f]{1,2})[Hh]? \.[Mm]{2}([0-9A-Fa-f]{2})[Hh]?\b/ "INT ".sprintf("%02X", hex($1))."\/AL=$2h"/xe; $linking =~ s/ ^([0-9A-Fa-f]{1,2})[Hh]? \.([0-9A-Fa-f]{4})[Hh]?\b/ "INT ".sprintf("%02X", hex($1))."\/AX=$2h"/xe; $linking =~ s/ ^([0-9A-Fa-f]{1,2})[Hh]? \.([0-9A-Fa-f]{2})[Hh]?\b/ "INT ".sprintf("%02X", hex($1))."\/AH=$2h"/xe; $linking =~ s/ ^([0-9A-Fa-f]{1,2})[Hh]? / "INT ".sprintf("%02X", hex($1))/xe; while ($linking =~ s/ ^([^\"]*)_+ /$1/x) { # do nothing } $linking =~ s/^([0-9A-Za-z]+)/uc($1)/xe; } my $linkpattern = < $link_history_index) { pop(@array_link_history); } $link_history_index += 1; push(@array_link_history, \%priorstate); last PATTERNINTSEARCHFILES; } } if (not $found) { if (not defined $quietnotfound or $quietnotfound == 0) { if ($listlinks and $listonlybroken) { if ($listlinks) { print("From \"$resultsummary\":"); if ($listlinebreak) { print("\n"); } else { print(" "); } } print_or_opcodeline("Hyperlink selected: $label"); } print_or_errorline("Hyperlink target not found"); } } } } else { if ((not $multi and defined $array_lstff[$activelistingfile] or $multi and scalar (grep {defined $_} @array_lstff))) { my @files = getfiles(); my $found = 0; PATTERNTABLESEARCHFILES: foreach my $currentfile (@files) { my $line = 0; my $lastemptyline = 0; my $lastsummaryline = 0; my $summaryline = 0; seek($array_lstff[$currentfile], 0, SEEK_SET); PATTERNTABLESEARCHSINGLEFILE: while (defined ($_ = readline($array_lstff[$currentfile]))) { $line += 1; if (/^--------/) { $summaryline += 1; $lastsummaryline = $line; } if (/^\s*$/) { $lastemptyline = $line; } if (not /\(Table $findtable\)/i) { next; } if (defined $summaryindex and $summaryindex) { $summaryindex -= 1; next; } $found = 1; $activelistingfile = $currentfile; $array_drawlinestart[$activelistingfile] = $summaryline; $resultlinestart = $summaryline; $resultlineend = $summaryline; $resultfile = $currentfile; if ($lastemptyline > $lastsummaryline) { $detaildrawlinestart = $lastemptyline + 2 - $lastsummaryline; } else { $detaildrawlinestart = 1; } $DETAILLINES = $LINES - 8; $SUMMARYLINES = $LINES - $DETAILLINES; $indetailfocus = 1; while (scalar @array_link_history > $link_history_index) { pop(@array_link_history); } $link_history_index += 1; push(@array_link_history, \%priorstate); last PATTERNTABLESEARCHFILES; } } if (not $found) { if (not defined $quietnotfound or $quietnotfound == 0) { if ($listlinks and $listonlybroken) { if ($listlinks) { print("From \"$resultsummary\":"); if ($listlinebreak) { print("\n"); } else { print(" "); } } print_or_opcodeline("Hyperlink selected: $label"); } print_or_errorline("Hyperlink target not found"); } } } } } $redrawrequested = 1; } our @array_listingfiles = (); our @array_lstff = (); our @array_drawlinestart = (); our $detaildrawlinestart = 0; our $detaillinesamount = 0; our $indetailfocus = 0; 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 $firstlinkline = undef; our $firstlinkoffset = undef; our $currentlinkline = undef; our $currentlinkoffset = undef; our $cursorsetline = undef; our $cursorsetcol = undef; our $linkcommand = undef; our @array_offsets = (); our $multi = 0; our $listlinks = 0; our $listonlybroken = 0; our $listlinebreak = 0; our $listfirst = 0; our $liststart = 0; our $listamount = undef; our $debuglistlinks = 0; my $multi_disable_next = 0; my $help = 0; my $update_opcode2line = 0; Getopt::Long::Configure("no_auto_abbrev"); GetOptions( 'listing|file=s@' => \@array_listingfiles, 'link|l=s' => \$linkcommand, 'list!' => \$listlinks, 'broken|b!' => \$listonlybroken, 'linebreak!' => \$listlinebreak, 'first!' => \$listfirst, 'start=i' => \$liststart, 'amount=i' => \$listamount, 'debuglist!' => \$debuglistlinks, '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; } our $resultlinestart = 0; our $resultlineend = 0; our $resultfile = undef; our $resultseek = undef; our $resultsummary = undef; if ($listlinks) { my $line = 0; my $found = 0; $DETAILLINES = 50 - 8; $SUMMARYLINES = 50 - $DETAILLINES; $indetailfocus = 1; our $currentfile = $activelistingfile; my $moresummaries = 1; my $summaryindex = $liststart; my $firstsummary = 1; while ($moresummaries) { $moresummaries = 0; if (defined $linkcommand) { $resultsummary = "[Link command line switch]"; selecthyperlink($linkcommand, $summaryindex, not $firstsummary); $firstsummary = 0; if (not $listfirst and $link_history_index) { if (not defined $listamount or $listamount > 1) { $summaryindex += 1; $moresummaries = 1; if (defined $listamount) { $listamount -= 1; } } } if ($link_history_index == 0) { last; } $link_history_index = 0; } else { $moresummaries = 1; 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(); PATTERNLISTFILES: foreach my $currentfile (@files) { my $line = 0; seek($array_lstff[$currentfile], 0, SEEK_SET); PATTERNLISTSINGLEFILE: while (defined ($_ = readline_replace($array_lstff[$currentfile], $statuspage_in_effect))) { $line += 1; if ( 1 and ($currentfile == $activelistingfile and $line > $array_drawlinestart[$activelistingfile] or $currentfile > $activelistingfile ) ) { if (1) { $lastresultline = $line; $lastresultfile = $currentfile; last PATTERNLISTFILES; } } } } if ($lastresultline) { if ($debuglistlinks and 0) { print( "File: " .(File::Spec->splitpath($array_listingfiles[$activelistingfile]) )[-1] .", line=$lastresultline\n" ); } $activelistingfile = $lastresultfile; $array_drawlinestart[$activelistingfile] = $lastresultline; $resultfile = $lastresultfile; $resultlinestart = $lastresultline; $resultlineend = $lastresultline; } else { last; } } } my $moredetails = 1; $detaildrawlinestart = 1; $currentlinkline = undef; $currentlinkoffset = undef; while ($moredetails) { $moredetails = 0; $currentfile = $activelistingfile; my $drawing = 0; my $drawnline = 0; my $ii = 0; my $jj = 0; $line = 0; seek($array_lstff[$currentfile], 0, SEEK_SET); while (defined ($_ = readline_replace($array_lstff[$currentfile], $statuspage_in_effect))) { $line += 1; if (defined $resultfile and $resultfile == $currentfile and $line >= $resultlinestart) { $resultseek = $priorseek; $resultsummary = $_; last; } } if (1) { my $priorlinkline = undef; my $priorlinkoffset = undef; seek($array_lstff[$currentfile], $resultseek, SEEK_SET); my $first = 1; $line = 0; $detaillinesamount = 0; while (defined ($_ = readline_replace($array_lstff[$currentfile], 1))) { if (not $first and /^--------/) { last; } $first = 0; $line += 1; } $detaillinesamount = $line; seek($array_lstff[$currentfile], $resultseek, SEEK_SET); $drawing = 0; $line = 0; $first = 1; my $second = 0; my $nextsecond = 0; my $drawone = 0; my $int = undef; $firstlinkline = undef; while (defined ($_ = readline_replace($array_lstff[$currentfile], 1))) { $second = $nextsecond; $nextsecond = 0; $line += 1; if (not $first and /^--------/) { last; } if ($first and /^-{8}.-([0-9A-Fa-f]{2})/) { $int = sprintf("%02X", hex($1)); } if ($first) { $nextsecond = 1; } $first = 0; $found = 0; if (1) { $drawone = 0; my $withtabs = $_; $withtabs =~ s/[\r\n]+$//; my $expanded = expandtabs($withtabs); my $maskhighlight = ""; my $linking = $expanded; while (not $second and $linking =~ /(\bINT\s?[0-9A-Fa-f]{2}[Hh]? (?:\/(?:E?[ABCD][XHL]|E?[SD]I|E?[SB]P|[DESC]S)=[0-9A-Fa-f]{2,}[Hh]?)+ (?:\"[^"]+\")? ) |(\bINT\s?[0-9A-Fa-f]{2}[Hh]? (?:\"[^"]+\")? ) |(\b(?:E?A[XHL])=[0-9A-Fa-f]{2,}[Hh]? (?:\/(?:E?[ABCD][XHL]|E?[SD]I|E?[SB]P|[DESC]S)=[0-9A-Fa-f]{2,}[Hh]?)* (?:\"[^"]+\")? ) |(\#[0-9A-Z][0-9]{4}\b) |(\bMEM\s?[0-9A-Fa-fXx]{1,4}[Hh]?:[0-9A-Fa-fXx]{1,4}[Hh]? (?:\"[^"]+\")? ) |(\bMEM\s?[0-9A-Fa-fXx]{1,8}[Hh]? (?:\"[^"]+\")? ) |(\@[0-9A-Fa-fXx]{1,4}[Hh]?:[0-9A-Fa-fXx]{1,4}[Hh]? (?:\"[^"]+\")? ) |(\bPORT\s?[0-9A-Fa-fXx]{1,4}[Hh]?-[0-9A-Fa-fXx]{1,4}[Hh]? (?:\"[^"]+\")? ) |(\bPORT\s?[0-9A-Fa-fXx]{1,4}[Hh]? (?:\"[^"]+\")? ) /x) { if (defined $3 and not defined $int) { $maskhighlight .= " " x (length ($`) + length ($&)); $linking = $'; next; } $maskhighlight .= " " x length $`; my $offset = length $maskhighlight; if (not defined $currentlinkline) { $currentlinkline = $line; $currentlinkoffset = $offset; $found = 1; last; } if (defined $priorlinkline and $priorlinkline == $currentlinkline and $priorlinkoffset == $currentlinkoffset) { $currentlinkline = $line; $currentlinkoffset = $offset; $found = 1; if ($debuglistlinks and 0) { print( "File: " .(File::Spec->splitpath($array_listingfiles[$activelistingfile]) )[-1] .", line=$line, ofs=$offset, priorline=$priorlinkline, priorofs=$priorlinkoffset" .", >>$expanded<<\n" ); } last; } $priorlinkline = $line; $priorlinkoffset = $offset; $maskhighlight .= "_" x length $&; $linking = $'; } $drawnline += 1; } if ($found) { last; } } if ($found) { if ($debuglistlinks and 0) { print( "File: " .(File::Spec->splitpath($array_listingfiles[$activelistingfile]) )[-1] .", line=$currentlinkline, ofs=$currentlinkoffset, $resultsummary\n" ); } selecthyperlink(); if ($link_history_index) { $link_history_index = 0; my %newstate = %{ $array_link_history[$link_history_index] }; $currentfile = $newstate{currentfile}; $currentlinkline = $newstate{currentlinkline}; $currentlinkoffset = $newstate{currentlinkoffset}; $detaildrawlinestart = $newstate{detaildrawlinestart}; $resultlinestart = $newstate{resultlinestart}; $resultlineend = $newstate{resultlineend}; $resultfile = $newstate{resultfile}; $resultseek = $newstate{resultseek}; $activelistingfile = $newstate{activelistingfile}; @array_drawlinestart = @{ $newstate{array_drawlinestart} }; $indetailfocus = $newstate{indetailfocus}; } $moredetails = 1; } } } } exit; } $print = 0; initscr(); noecho(); cbreak(); nodelay(1); keypad(1); $SUMMARYLINES = $LINES - $DETAILLINES; my $reloadrequested = 0; my $updaterequested = 1; our $redrawrequested = 1; my $winch = 0; my $selected = 0; my $instructionsamount = 0; 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 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 checkresultlineinarea { my $candidatedrawlinestart = shift; if ($candidatedrawlinestart <= 0) { return 0; } if (not $resultlinestart) { return 1; } my $draw_area_start = $candidatedrawlinestart + int($SUMMARYLINES / 10); my $draw_area_size = int($SUMMARYLINES / 10) * 9; if ($draw_area_size > ($SUMMARYLINES - 7)) { $draw_area_size = $SUMMARYLINES - 7; } my $draw_area_end = $candidatedrawlinestart + $draw_area_size; if ($resultlinestart < $draw_area_start or $resultlineend > $draw_area_end) { return 0; } else { return 1; } } sub getlink { my $prompt = shift; our $link; errorline($prompt); write_errorline(0); my $rc = 0; my $input; ($rc, $input) = getinput($prompt, $LINES - 2, \@linkhistory, $linkhistff); if ($rc == 0) { errorline(""); } elsif ($rc == 1 or $rc == 2) { $link = $input; } elsif ($rc == 3) { errorline("No link in history"); } return $rc; } 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; $SUMMARYLINES = $LINES - $DETAILLINES; } 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; $SUMMARYLINES = $LINES - $DETAILLINES; } if ($updaterequested and $statuspage_in_effect) { $updaterequested = 0; $redrawrequested = 1; $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 (defined ($_ = readline_replace($array_lstff[$currentfile], $statuspage_in_effect))) { $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; $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 (defined ($_ = readline_replace($array_lstff[$currentfile], $statuspage_in_effect))) { $line += 1; } $array_linesamount[$currentfile] = $line; } $update_opcode2line = 1; next; } } } our $currentfile = $activelistingfile; if ($redrawrequested and defined $array_lstff[$currentfile]) { my $drawing = 0; my $drawingresult = 0; my $drawinghighlight = 0; my $newdrawlinestart; my $newdrawlineend; if (defined $resultfile and $resultfile == $currentfile and $resultlinestart) { if ($resultlinestart and not checkresultlineinarea($array_drawlinestart[$currentfile])) { $newdrawlinestart = 1; if ($resultlinestart > int($SUMMARYLINES / 4)) { $newdrawlinestart = $resultlinestart - int($SUMMARYLINES / 4); } $array_drawlinestart[$currentfile] = $newdrawlinestart; } } my $drawnline = 0; my $ii = 0; my $jj = 0; $line = 0; seek($array_lstff[$currentfile], 0, SEEK_SET); while (defined ($_ = readline_replace($array_lstff[$currentfile], $statuspage_in_effect))) { $line += 1; if ($line == $array_drawlinestart[$currentfile]) { $drawing = 1; } if (defined $resultfile and $resultfile == $currentfile and $line == $resultlinestart) { $resultseek = $priorseek; $resultsummary = $_; standout(); $drawingresult = 1; } if (defined $resultfile and $resultfile == $currentfile and $line > $resultlineend) { standend(); $drawingresult = 0; } if ($drawnline > ($SUMMARYLINES - 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; } } if (defined $resultfile and $resultfile == $currentfile and $drawingresult and $line <= $resultlineend) { standend(); $drawingresult = 0; } while ($drawnline <= ($SUMMARYLINES - 4)) { addnstring($drawnline, 0, " " x $COLS, $COLS); $drawnline += 1; } if ($DETAILLINES) { seek($array_lstff[$currentfile], $resultseek, SEEK_SET); my $first = 1; $line = 0; $detaillinesamount = 0; while (defined ($_ = readline_replace($array_lstff[$currentfile], 1))) { if (not $first and /^--------/) { last; } $first = 0; $line += 1; } $detaillinesamount = $line; seek($array_lstff[$currentfile], $resultseek, SEEK_SET); $drawing = 0; $line = 0; $first = 1; my $second = 0; my $nextsecond = 0; my $drawone = 0; my $int = undef; $firstlinkline = undef; $cursorsetline = undef; while (defined ($_ = readline_replace($array_lstff[$currentfile], 1))) { $second = $nextsecond; $nextsecond = 0; $line += 1; if ($line == $detaildrawlinestart) { $drawing = 1; } elsif ($line == 1) { $drawone = 1; } if ($drawnline > ($LINES - 4)) { last; } if (not $first and /^--------/) { last; } if ($first and /^-{8}.-([0-9A-Fa-f]{2})/) { $int = sprintf("%02X", hex($1)); } if ($first) { $nextsecond = 1; } $first = 0; if ($drawing or $drawone) { $drawone = 0; 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 if ($withtabs =~ /\t/) { $masksearchresult = expandtabswithcontent($withtabs, $masksearchresult); } } my $maskhighlight = ""; my $linking = $expanded; while (not $second and $linking =~ /(\bINT\s?[0-9A-Fa-f]{2}[Hh]? (?:\/(?:E?[ABCD][XHL]|E?[SD]I|E?[SB]P|[DESC]S)=[0-9A-Fa-f]{2,}[Hh]?)+ (?:\"[^"]+\")? ) |(\bINT\s?[0-9A-Fa-f]{2}[Hh]? (?:\"[^"]+\")? ) |(\b(?:E?A[XHL])=[0-9A-Fa-f]{2,}[Hh]? (?:\/(?:E?[ABCD][XHL]|E?[SD]I|E?[SB]P|[DESC]S)=[0-9A-Fa-f]{2,}[Hh]?)* (?:\"[^"]+\")? ) |(\#[0-9A-Z][0-9]{4}\b) |(\bMEM\s?[0-9A-Fa-fXx]{1,4}[Hh]?:[0-9A-Fa-fXx]{1,4}[Hh]? (?:\"[^"]+\")? ) |(\bMEM\s?[0-9A-Fa-fXx]{1,8}[Hh]? (?:\"[^"]+\")? ) |(\@[0-9A-Fa-fXx]{1,4}[Hh]?:[0-9A-Fa-fXx]{1,4}[Hh]? (?:\"[^"]+\")? ) |(\bPORT\s?[0-9A-Fa-fXx]{1,4}[Hh]?-[0-9A-Fa-fXx]{1,4}[Hh]? (?:\"[^"]+\")? ) |(\bPORT\s?[0-9A-Fa-fXx]{1,4}[Hh]? (?:\"[^"]+\")? ) /x) { if (defined $3 and not defined $int) { $maskhighlight .= " " x (length ($`) + length ($&)); $linking = $'; next; } $maskhighlight .= " " x length $`; my $offset = length $maskhighlight; if (not defined $firstlinkline) { $firstlinkline = $line; $firstlinkoffset = $offset; } if (defined $currentlinkline and $currentlinkline < $firstlinkline) { $cursorsetline = undef; $currentlinkline = undef; } if (defined $currentlinkline and $currentlinkline == $line and $currentlinkoffset == $offset) { $cursorsetline = $drawnline; $cursorsetcol = $offset; } $maskhighlight .= "_" x length $&; $linking = $'; } 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; } if (defined $currentlinkline and not defined $cursorsetline) { $cursorsetline = undef; $currentlinkline = undef; } } $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(); if (not defined $cursorsetline) { move($LINES - 1, $COLS - 1); } else { move($cursorsetline, $cursorsetcol); } if ($needrefresh) { refresh(); } $redrawrequested = 0; if (defined $linkcommand) { selecthyperlink($linkcommand); $redrawrequested = 1; $linkcommand = undef; next; } 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 "\n" and not $statuspage_in_effect) { if (not defined $resultfile or $resultfile != $currentfile or $resultlinestart == 0) { $resultlinestart = $array_drawlinestart[$currentfile]; $resultlineend = $resultlinestart; $resultfile = $currentfile; $redrawrequested = 1; opcodeline("Now in list line select mode"); } elsif ($DETAILLINES == 0) { $DETAILLINES = int($LINES / 2); $SUMMARYLINES = $LINES - $DETAILLINES; $redrawrequested = 1; $detaildrawlinestart = 1; opcodeline("Now in detail view with list"); } elsif ($indetailfocus == 0) { $DETAILLINES = $LINES - 8; $SUMMARYLINES = $LINES - $DETAILLINES; $indetailfocus = 1; $redrawrequested = 1; opcodeline("Now in detail view focus"); } else { if (not defined $currentlinkline) { errorline("No hyperlink selected"); last; } selecthyperlink(); last; } last; } elsif ($key eq 'l' and not $statuspage_in_effect) { our $link; my $rc = getlink('#'); if ($rc == 1 or $rc == 2) { selecthyperlink($link); } $redrawrequested = 1; last; } elsif (($key eq "\e" or $key eq " ") and not $statuspage_in_effect) { if (not defined $resultfile or $resultfile != $currentfile or $resultlinestart == 0) { dobeep(); } elsif ($DETAILLINES == 0) { $resultlinestart = 0; $resultlineend = 0; $redrawrequested = 1; opcodeline(""); } elsif ($indetailfocus == 0) { $DETAILLINES = 0; $SUMMARYLINES = $LINES - $DETAILLINES; $redrawrequested = 1; $firstlinkline = undef; $currentlinkline = undef; $cursorsetline = undef; opcodeline("Now in list line select mode"); } else { $indetailfocus = 0; $DETAILLINES = int($LINES / 2); $SUMMARYLINES = $LINES - $DETAILLINES; $redrawrequested = 1; opcodeline("Now in detail view with list"); } last; } 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) or $key eq "`") { if ($DETAILLINES) { if (not defined $currentlinkline) { if (defined $firstlinkline) { $currentlinkline = $firstlinkline; $currentlinkoffset = $firstlinkoffset; } else { errorline("No hyperlink visible"); } } else { my $priorlinkline = undef; my $priorlinkoffset = undef; my $backtick = $key eq "`"; my $backtickfirst = 0; if ($backtick and $currentlinkline == $firstlinkline and $currentlinkoffset == $firstlinkoffset) { $backtickfirst = 1; } my $found = 0; my $drawing = 0; my $drawnline = 1 + ($SUMMARYLINES - 4); seek($array_lstff[$currentfile], $resultseek, SEEK_SET); my $first = 1; $line = 0; $detaillinesamount = 0; while (defined ($_ = readline_replace($array_lstff[$currentfile], 1))) { if (not $first and /^--------/) { last; } $first = 0; $line += 1; } $detaillinesamount = $line; seek($array_lstff[$currentfile], $resultseek, SEEK_SET); $drawing = 0; $line = 0; $first = 1; my $second = 0; my $nextsecond = 0; my $drawone = 0; my $int = undef; while (defined ($_ = readline_replace($array_lstff[$currentfile], 1))) { $second = $nextsecond; $nextsecond = 0; $line += 1; if ($line == $detaildrawlinestart) { $drawing = 1; } elsif ($line == 1) { $drawone = 1; } if ($drawnline > ($LINES - 4)) { last; } if (not $first and /^--------/) { last; } if ($first and /^-{8}.-([0-9A-Fa-f]{2})/) { $int = sprintf("%02X", hex($1)); } if ($first) { $nextsecond = 1; } $first = 0; if ($drawing or $drawone) { $drawone = 0; my $withtabs = $_; $withtabs =~ s/[\r\n]+$//; my $expanded = expandtabs($withtabs); my $maskhighlight = ""; my $linking = $expanded; while (not $second and $linking =~ /(\bINT\s?[0-9A-Fa-f]{2}[Hh]? (?:\/(?:E?[ABCD][XHL]|E?[SD]I|E?[SB]P|[DESC]S)=[0-9A-Fa-f]{2,}[Hh]?)+ (?:\"[^"]+\")? ) |(\bINT\s?[0-9A-Fa-f]{2}[Hh]? (?:\"[^"]+\")? ) |(\b(?:E?A[XHL])=[0-9A-Fa-f]{2,}[Hh]? (?:\/(?:E?[ABCD][XHL]|E?[SD]I|E?[SB]P|[DESC]S)=[0-9A-Fa-f]{2,}[Hh]?)* (?:\"[^"]+\")? ) |(\#[0-9A-Z][0-9]{4}\b) |(\bMEM\s?[0-9A-Fa-fXx]{1,4}[Hh]?:[0-9A-Fa-fXx]{1,4}[Hh]? (?:\"[^"]+\")? ) |(\bMEM\s?[0-9A-Fa-fXx]{1,8}[Hh]? (?:\"[^"]+\")? ) |(\@[0-9A-Fa-fXx]{1,4}[Hh]?:[0-9A-Fa-fXx]{1,4}[Hh]? (?:\"[^"]+\")? ) |(\bPORT\s?[0-9A-Fa-fXx]{1,4}[Hh]?-[0-9A-Fa-fXx]{1,4}[Hh]? (?:\"[^"]+\")? ) |(\bPORT\s?[0-9A-Fa-fXx]{1,4}[Hh]? (?:\"[^"]+\")? ) /x) { if (defined $3 and not defined $int) { $maskhighlight .= " " x (length($`) + length($&)); $linking = $'; next; } $maskhighlight .= " " x length $`; my $offset = length $maskhighlight; if (not $backtick) { if (defined $priorlinkline and $priorlinkline == $currentlinkline and $priorlinkoffset == $currentlinkoffset) { $currentlinkline = $line; $currentlinkoffset = $offset; $found = 1; last; } } elsif (not $backtickfirst) { if ($currentlinkline == $line and $currentlinkoffset == $offset) { $currentlinkline = $priorlinkline; $currentlinkoffset = $priorlinkoffset; $found = 1; last; } } else { $currentlinkline = $line; $currentlinkoffset = $offset; } $priorlinkline = $line; $priorlinkoffset = $offset; $maskhighlight .= "_" x length $&; $linking = $'; } $drawnline += 1; } if ($found) { last; } } if (not $found and not $backtickfirst) { if (defined $firstlinkline) { $currentlinkline = $firstlinkline; $currentlinkoffset = $firstlinkoffset; } else { dobeep(); } } } $redrawrequested = 1; last; } else { if ($activestop < $#stops) { $activestop += 1; } else { $activestop = 0; } $redrawrequested = 1; last; } } elsif (($key eq 'b' or $key eq 'f') and not $statuspage_in_effect) { if ($key eq 'b' and $link_history_index == 0) { errorline("No earlier link history entry!"); last; } if ($key eq 'f' and ($link_history_index + 1) >= scalar @array_link_history) { errorline("No later link history entry!"); last; } my %newstate; if ($key eq 'b' and $link_history_index == scalar @array_link_history) { my %priorstate = ( currentfile => $currentfile, currentlinkline => $currentlinkline, currentlinkoffset => $currentlinkoffset, detaildrawlinestart => $detaildrawlinestart, resultlinestart => $resultlinestart, resultlineend => $resultlineend, resultfile => $resultfile, resultseek => $resultseek, activelistingfile => $activelistingfile, array_drawlinestart => [@array_drawlinestart], indetailfocus => $indetailfocus, detaillines_nonzero => ($DETAILLINES != 0), ); push(@array_link_history, \%priorstate); } if ($key eq 'b') { $link_history_index -= 1; %newstate = %{ $array_link_history[$link_history_index] }; } else { $link_history_index += 1; %newstate = %{ $array_link_history[$link_history_index] }; } $currentfile = $newstate{currentfile}; $currentlinkline = $newstate{currentlinkline}; $currentlinkoffset = $newstate{currentlinkoffset}; $detaildrawlinestart = $newstate{detaildrawlinestart}; $resultlinestart = $newstate{resultlinestart}; $resultlineend = $newstate{resultlineend}; $resultfile = $newstate{resultfile}; $resultseek = $newstate{resultseek}; $activelistingfile = $newstate{activelistingfile}; @array_drawlinestart = @{ $newstate{array_drawlinestart} }; $indetailfocus = $newstate{indetailfocus}; my $detaillines_nonzero = $newstate{detaillines_nonzero}; $DETAILLINES = 0; if ($detaillines_nonzero) { if ($indetailfocus) { $DETAILLINES = $LINES - 8; } else { $DETAILLINES = int($LINES / 2); } } $SUMMARYLINES = $LINES - $DETAILLINES; $redrawrequested = 1; last; } elsif ($key eq '/' or $key eq '?') { my $rc = getsearchpattern($key); if ($rc == 1 or $rc == 2) { if ($indetailfocus) { if (1) { if (not defined $resultseek) { $resultseek = 0; } my $lastresultline = 0; my $lastresultfile; my $currentfile = $activelistingfile; if (1) { my $line = 0; my $first = 1; seek($array_lstff[$currentfile], $resultseek, SEEK_SET); PATTERNSEARCHENTRY: while (defined ($_ = readline_replace($array_lstff[$currentfile], 1))) { if (not $first and /^--------/) { last; } $first = 0; $line += 1; if ( $key eq '?' and $rc == 2 and ($line < $detaildrawlinestart) or $key eq '?' and $rc == 1 and ($line <= $detaildrawlinestart) or $key eq '/' and $rc == 2 and ($line > $detaildrawlinestart) or $key eq '/' and $rc == 1 and ($line >= $detaildrawlinestart) ) { my $withtabs = $_; $withtabs =~ s/[\r\n]+$//; if ($withtabs =~ /$searchpattern/) { $lastresultline = $line; $lastresultfile = $currentfile; if ($key eq '/') { last PATTERNSEARCHENTRY; } } } } } if ($lastresultline) { if ($detaildrawlinestart == $lastresultline) { dobeep(); } $detaildrawlinestart = $lastresultline; $updaterequested = 1; } else { errorline("Pattern not found"); } } $redrawrequested = 1; last; } else { 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 (defined ($_ = readline_replace($array_lstff[$currentfile], $statuspage_in_effect))) { $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"); } } $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 ($indetailfocus) { if ($detaildrawlinestart > 1) { $detaildrawlinestart -= 1; $redrawrequested = 1; last; } else { dobeep(); } } elsif (not defined $resultfile or $resultfile != $currentfile or $resultlinestart == 0) { if ($array_drawlinestart[$activelistingfile] > 1) { $array_drawlinestart[$activelistingfile] -= 1; $redrawrequested = 1; last; } else { dobeep(); } } else { if ($resultlinestart != 1) { if ($DETAILLINES != 0 and not $indetailfocus) { $detaildrawlinestart = 1; } $resultlinestart -= 1; $resultlineend = $resultlinestart; $redrawrequested = 1; last; } else { dobeep(); } } } elsif ($key eq KEY_DOWN) { if ($indetailfocus) { if (($detaildrawlinestart + $DETAILLINES - 1) < $detaillinesamount) { $detaildrawlinestart += 1; $redrawrequested = 1; last; } else { dobeep(); } } elsif (not defined $resultfile or $resultfile != $currentfile or $resultlinestart == 0) { if (($array_drawlinestart[$activelistingfile] + $SUMMARYLINES - 5) < $array_linesamount[$activelistingfile]) { $array_drawlinestart[$activelistingfile] += 1; $redrawrequested = 1; last; } else { dobeep(); } } else { if ($resultlinestart < $array_linesamount[$activelistingfile]) { if ($DETAILLINES != 0 and not $indetailfocus) { $detaildrawlinestart = 1; } $resultlinestart += 1; $resultlineend = $resultlinestart; $redrawrequested = 1; last; } else { dobeep(); } } } elsif ($key eq KEY_PPAGE) { if ($indetailfocus) { if ($detaildrawlinestart > 1) { if ($detaildrawlinestart > ($DETAILLINES - 5)) { $detaildrawlinestart -= ($DETAILLINES - 5); } else { $detaildrawlinestart = 1; } $redrawrequested = 1; last; } else { dobeep(); } } elsif (not defined $resultfile or $resultfile != $currentfile or $resultlinestart == 0) { if ($array_drawlinestart[$activelistingfile] > 1) { if ($array_drawlinestart[$activelistingfile] > ($SUMMARYLINES - 5)) { $array_drawlinestart[$activelistingfile] -= ($SUMMARYLINES - 5); } else { $array_drawlinestart[$activelistingfile] = 1; } $redrawrequested = 1; last; } else { dobeep(); } } else { if ($resultlinestart > 1) { if ($DETAILLINES != 0 and not $indetailfocus) { $detaildrawlinestart = 1; } if ($resultlinestart > ($SUMMARYLINES - 5)) { $resultlinestart -= ($SUMMARYLINES - 5); } else { $resultlinestart = 1; } $resultlineend = $resultlinestart; $redrawrequested = 1; last; } else { dobeep(); } } } elsif ($key eq KEY_NPAGE) { if ($indetailfocus) { if (($detaildrawlinestart + $DETAILLINES - 5) < $detaillinesamount) { if (($detaildrawlinestart + $DETAILLINES - 5 + $DETAILLINES - 5) <= ($detaillinesamount)) { $detaildrawlinestart += ($DETAILLINES - 5); } elsif ($detaillinesamount >= $DETAILLINES - 5) { $detaildrawlinestart = $detaillinesamount - ($DETAILLINES - 5); } else { $detaildrawlinestart = 1; } $redrawrequested = 1; last; } else { dobeep(); } } elsif (not defined $resultfile or $resultfile != $currentfile or $resultlinestart == 0) { if (($array_drawlinestart[$activelistingfile] + $SUMMARYLINES - 5) < $array_linesamount[$activelistingfile]) { if (($array_drawlinestart[$activelistingfile] + $SUMMARYLINES - 5 + $SUMMARYLINES - 5) <= ($array_linesamount[$activelistingfile])) { $array_drawlinestart[$activelistingfile] += ($SUMMARYLINES - 5); } elsif ($array_linesamount[$activelistingfile] >= $SUMMARYLINES - 5) { $array_drawlinestart[$activelistingfile] = $array_linesamount[$activelistingfile] - ($SUMMARYLINES - 5); } else { $array_drawlinestart[$activelistingfile] = 1; } $redrawrequested = 1; last; } else { dobeep(); } } else { if (($resultlinestart + $SUMMARYLINES - 5) < $array_linesamount[$activelistingfile]) { if ($DETAILLINES != 0 and not $indetailfocus) { $detaildrawlinestart = 1; } if (($resultlinestart + $SUMMARYLINES - 5 + $SUMMARYLINES - 5) <= ($array_linesamount[$activelistingfile])) { $resultlinestart += ($SUMMARYLINES - 5); } elsif ($array_linesamount[$activelistingfile] >= $SUMMARYLINES - 5) { $resultlinestart = $array_linesamount[$activelistingfile] - ($SUMMARYLINES - 5); } else { $resultlinestart = 1; } $resultlineend = $resultlinestart; $redrawrequested = 1; last; } else { dobeep(); } } } elsif ($originalkey eq 'g') { if ($indetailfocus) { $detaildrawlinestart = 1; $redrawrequested = 1; last; } elsif (not defined $resultfile or $resultfile != $currentfile or $resultlinestart == 0) { $array_drawlinestart[$activelistingfile] = 1; $redrawrequested = 1; last; } else { if ($DETAILLINES != 0 and not $indetailfocus) { $detaildrawlinestart = 1; } $resultlinestart = 1; $resultlineend = $resultlinestart; $redrawrequested = 1; last; } } elsif ($originalkey eq 'G') { if ($indetailfocus) { if ($detaillinesamount >= ($DETAILLINES - 5)) { $detaildrawlinestart = $detaillinesamount - ($DETAILLINES - 5); } else { $detaildrawlinestart = 1; } $redrawrequested = 1; last; } elsif (not defined $resultfile or $resultfile != $currentfile or $resultlinestart == 0) { if ($array_linesamount[$activelistingfile] >= ($SUMMARYLINES - 5)) { $array_drawlinestart[$activelistingfile] = $array_linesamount[$activelistingfile] - ($SUMMARYLINES - 5); } else { $array_drawlinestart[$activelistingfile] = 1; } $redrawrequested = 1; last; } else { if ($DETAILLINES != 0 and not $indetailfocus) { $detaildrawlinestart = 1; } $resultlinestart = $array_linesamount[$activelistingfile]; $resultlineend = $resultlinestart; $redrawrequested = 1; last; } } else { dobeep(); } } } }