summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ankarström <john@ankarstrom.se>2021-05-26 14:32:00 +0200
committerJohn Ankarström <john@ankarstrom.se>2021-05-26 14:32:00 +0200
commit2c4d11d53fc2ce6d99d520cb42b13ec06b5baf16 (patch)
treed42bfbd623a95b2810639f6e0e18a8020ae5d83c
parent4c6301c10bb7280279ccad200f0756497c0dd6d0 (diff)
downloadmum-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-xsrc/mum140
1 files 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 = () })
+ (?<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;
+}