diff options
author | John Ankarström <john@ankarstrom.se> | 2021-05-26 14:32:00 +0200 |
---|---|---|
committer | John Ankarström <john@ankarstrom.se> | 2021-05-26 14:32:00 +0200 |
commit | 2c4d11d53fc2ce6d99d520cb42b13ec06b5baf16 (patch) | |
tree | d42bfbd623a95b2810639f6e0e18a8020ae5d83c | |
parent | 4c6301c10bb7280279ccad200f0756497c0dd6d0 (diff) | |
download | mum-2c4d11d53fc2ce6d99d520cb42b13ec06b5baf16.tar.gz |
mum: Implement mbox index reading, range parsing
For clarity's sake, I've also converted program-global variables
to uppercase.
-rwxr-xr-x | src/mum | 140 |
1 files changed, 116 insertions, 24 deletions
@@ -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 = () }) + (?<range> (?{ @RANGE = () }) ( (?&ref) | (?&ref),(?&ref) | (?&grep) ) - (?{ push @range, \%ref }) + (?{ push @RANGE, \%REF }) ) - (?<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) }) + (?<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 = (%ref, plus => 0+$^N) }) + ( ([+-] \d+) (?{ local %REF = (%REF, plus => 0+$^N) }) )? ) - (?<grep> g((?&next)) (?{ local %ref = (grep => $^R) }) + (?<grep> g((?&next)) (?{ local %REF = (grep => $^R) }) ) (?<next> /(([^/\\]++ | \\.)*+)/ (?{ $^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 (/^(?<num> \d*) (?<dir> (\+\+?|--?)) \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+ (?<index> .*)/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; +} |