From 2c4d11d53fc2ce6d99d520cb42b13ec06b5baf16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Ankarstr=C3=B6m?= Date: Wed, 26 May 2021 14:32:00 +0200 Subject: mum: Implement mbox index reading, range parsing For clarity's sake, I've also converted program-global variables to uppercase. --- src/mum | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 116 insertions(+), 24 deletions(-) diff --git a/src/mum b/src/mum index cba5c11..07cec1d 100755 --- a/src/mum +++ b/src/mum @@ -6,33 +6,30 @@ use warnings; use Data::Dumper; -# Open TTY for reading and writing - -open my $tty, '+<:unix', '/dev/tty' or die "Could not open /dev/tty: $!"; - # Define range syntax -my @range; # range (one/two references) -our %ref; # current reference +my @RANGE; # range (one/two references) +our %REF; # current reference + my $d = qr{ (?(DEFINE) - (? (?{ @range = () }) + (? (?{ @RANGE = () }) ( (?&ref) | (?&ref),(?&ref) | (?&grep) ) - (?{ push @range, \%ref }) + (?{ push @RANGE, \%REF }) ) - (? ( (\d+) (?{ local %ref = (line => $^N) }) - | (\.|\$) (?{ local %ref = (spec => $^N) }) - | ' ([a-z]) (?{ local %ref = (mark => $^N) }) - | (?&next) (?{ local %ref = (next => $^R) }) - | (?&prev) (?{ local %ref = (prev => $^R) }) + (? ( (\d+) (?{ local %REF = (line => $^N) }) + | (\.|\$) (?{ local %REF = (spec => $^N) }) + | ' ([a-z]) (?{ local %REF = (mark => $^N) }) + | (?&next) (?{ local %REF = (next => $^R) }) + | (?&prev) (?{ local %REF = (prev => $^R) }) ) - ( ([+-] \d+) (?{ local %ref = (%ref, plus => 0+$^N) }) + ( ([+-] \d+) (?{ local %REF = (%REF, plus => 0+$^N) }) )? ) - (? g((?&next)) (?{ local %ref = (grep => $^R) }) + (? g((?&next)) (?{ local %REF = (grep => $^R) }) ) (? /(([^/\\]++ | \\.)*+)/ (?{ $^N }) ) @@ -43,12 +40,22 @@ my $d = qr{ # Define program state -my $message = 1; # selected message +my $MESSAGE = 0; # selected message +my $INDEX = '-'; # loaded mbox index +my @MESSAGES; # loaded messages +my %MARKS; # saved marks + +# Open TTY for reading and writing + +open my $tty, '+<:unix', '/dev/tty' or die "Could not open /dev/tty: $!"; -# Run program +# Run main loop while () { - print $tty "$message& "; + $MESSAGE = 1 if $MESSAGE < 1; + $MESSAGE = @MESSAGES if $MESSAGE > @MESSAGES; + + print $tty "$MESSAGE:$INDEX& "; # Read next command from user @@ -67,16 +74,19 @@ while () { # range without command elsif (/^(?&range) \Z $d/x) { - print Dumper(@range), "\n"; # select last message in range - print "range without command\n"; + my ($a, $b); + $a = toloc(0, $RANGE[0]) if @RANGE > 1; + $b = toloc($a, $RANGE[$#RANGE]) or next; + $MESSAGE = $b; } # +/- (++/--) elsif (/^(? \d*) (? (\+\+?|--?)) \Z/x) { + my $num = $+{num} || 1; for ($+{dir}) { - $message += $+{num} || 1 if /\+/; - $message -= $+{num} || 1 if /-/; + $MESSAGE += $num if /\+/; + $MESSAGE -= $num if /-/; goto h if length($_) > 1; } } @@ -94,7 +104,7 @@ h: # p elsif (/^ (?&range)? p \Z $d/x) { - print Dumper(@range), "\n"; + print Dumper(@RANGE), "\n"; print "p\n"; } @@ -110,9 +120,31 @@ h: print "!\n"; } + # r[a] + elsif (/^ra? \s+ (? .*)/x) { + my $idx = $+{index}; + $idx =~ s/\.i$//; + $idx .= '.i'; # be sure to open index and not mbox + open my $h, '<', $idx or do { + warn "failed to open $idx: $!\n"; + next; + }; + ($INDEX = $idx) =~ s/\.i$//; + local $/ = ''; + @MESSAGES = () if not $cmd =~ /^ra/; # overwrite + my $offset = 0; + while (<$h>) { + s/^From .*\n/$&M-Index-Offset: $offset\n/; + push @MESSAGES, $_; + $offset += length $_; + } + close $h; + print scalar @MESSAGES, " messages\n"; + } + # empty command elsif (/^$/) { - $message++; + $MESSAGE++; } # unrecognized command @@ -122,3 +154,63 @@ h: } } } + +# Subroutines + +# Parse ref/grep and return corresponding location +sub toloc { + my $start = shift; # starting position for searches (optional) + my %ref = %{(shift)}; # reference to parse + my $loc; # location to return + + if ($ref{line}) { + $loc = $ref{line}; + } + + elsif ($ref{mark}) { + if ($MARKS{$ref{mark}}) { + $loc = $MARKS{$ref{mark}}; + } else { + warn "mark '$ref{mark} not set\n"; + return; + } + } + + elsif ($ref{spec}) { + $loc = $MESSAGE if $ref{spec} eq '.'; + $loc = scalar @MESSAGES if $ref{spec} eq '$'; + } + + elsif ($ref{next}) { + $start = 1 if not $start; + $loc = $start-1; + for (@MESSAGES[$start-1..$#MESSAGES]) { + $loc++; + goto found if /$ref{next}/; + } + warn "pattern /$ref{next}/ not found\n"; + return; + } + + elsif ($ref{prev}) { + $start = @MESSAGES if not $start; + $loc = $start-1; + for (@MESSAGES[0..$start-1]) { + $loc--; + goto found if m?$ref{prev}?; + } + warn "pattern ?$ref{prev}? not found\n"; + return; + } + + elsif ($ref{grep}) { + # to be implemented + return; + } + +found: + $loc += $ref{plus} if $ref{plus}; + $loc = 1 if $loc < 1; + $loc = @MESSAGES if $loc > @MESSAGES; + return $loc; +} -- cgit v1.2.3