Skip to content

Commit 27025b0

Browse files
authored
ed: factor r command out of edEdit() (briandfoy#922)
* Edit (e) command has a forceful alternative (E), but read (r) command doesn't (since r doesn't destroy the buffer) * edEdit() continues to handle e and E ($QuestionsMode param determines the mode) * r and e commands both use the saved filename if no argument is provided * Command arguments starting with '!' now call function init_pipe(), which rejects NUL and provides an argument list to pipe form of open() * Also add helper functions open_file_ro() and readin_lines() for common code * r command never updates $RememberedFilename; e command updates it if a file argument was provided * test1: "e !this" --> bad command, show error, buffer unchanged * test2: "r !this" --> same as test1 * test3: "e !ls -l" --> buffer replaced with ls output if buffer is clean * test4: "E !echo E" --> buffer replaced with ls output unconditionally * test5: "1,2e a.s" --> invalid command, e doesn't take any addresses * test6: "0r a.s" --> file a.s is read into the beginning of the buffer
1 parent 8513145 commit 27025b0

File tree

1 file changed

+105
-78
lines changed

1 file changed

+105
-78
lines changed

bin/ed

Lines changed: 105 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ use strict;
4747

4848
use File::Temp qw();
4949
use Getopt::Std qw(getopts);
50+
use Text::ParseWords qw(quotewords);
5051

5152
use constant A_NOMATCH => -1;
5253
use constant A_NOPAT => -2;
@@ -96,16 +97,10 @@ my $UndoLine;
9697

9798
# constants
9899

99-
my $NO_APPEND_MODE = 0;
100-
my $NO_INSERT_MODE = 0;
101-
my $INSERT_MODE = 1;
102-
my $APPEND_MODE = 2;
103-
my $QUESTIONS_MODE = 1;
104-
my $NO_QUESTIONS_MODE = 0;
105100
my $PRINT_NUM = 1;
106101
my $PRINT_BIN = 2;
107102

108-
our $VERSION = '0.26';
103+
our $VERSION = '0.27';
109104

110105
my @ESC = (
111106
'\\000', '\\001', '\\002', '\\003', '\\004', '\\005', '\\006', '\\a',
@@ -222,7 +217,7 @@ $args[0] = shift;
222217
$args[0] = undef if (defined($args[0]) && $args[0] eq '-');
223218
Usage() if @ARGV;
224219
$Scripted = $opt{'s'};
225-
edEdit($NO_QUESTIONS_MODE, $NO_APPEND_MODE);
220+
edEdit(0);
226221
input() while 1;
227222

228223
sub input {
@@ -509,8 +504,7 @@ sub edPrintBin { edPrint($PRINT_BIN); }
509504
sub edQuitAsk { edQuit(1); }
510505
sub edAppend { edInsert(1); }
511506
sub edWriteAppend { edWrite(1); }
512-
sub edEditAsk { edEdit(!$Scripted, $NO_INSERT_MODE); }
513-
sub edRead { edEdit($QUESTIONS_MODE,$INSERT_MODE); }
507+
sub edEditAsk { edEdit(!$Scripted); }
514508

515509
#
516510
# Perform text substitution
@@ -678,6 +672,50 @@ sub edWrite {
678672
return;
679673
}
680674

675+
sub edRead {
676+
my(@tmp_lines, $chars, $fh, $filename, $do_pipe, $targ);
677+
678+
$targ = $adrs[1];
679+
$targ = $adrs[0] unless defined $targ;
680+
$targ = maxline() unless defined $targ;
681+
682+
if (defined $args[0]) {
683+
return E_FNAME unless (length $args[0]);
684+
if ($args[0] =~ s/\A\!//) {
685+
$do_pipe = 1;
686+
$fh = init_pipe($args[0]);
687+
return E_OPEN unless $fh;
688+
}
689+
$filename = $args[0];
690+
} elsif (defined $RememberedFilename) {
691+
$filename = $RememberedFilename;
692+
} else {
693+
return E_NOFILE;
694+
}
695+
696+
unless ($do_pipe) {
697+
$fh = open_file_ro($filename);
698+
return E_OPEN unless $fh;
699+
}
700+
@tmp_lines = readin_lines($fh, 0);
701+
$chars = 0;
702+
foreach (@tmp_lines) {
703+
$chars += length;
704+
}
705+
unless (close $fh) {
706+
warn "$filename: $!\n";
707+
return E_CLOSE;
708+
}
709+
print "$chars\n" unless $Scripted;
710+
return unless @tmp_lines; # nothing to add
711+
712+
splice @lines, $targ + 1, 0, @tmp_lines;
713+
$CurrentLineNum = $targ + scalar(@tmp_lines);
714+
715+
$NeedToSave = 1;
716+
$UserHasBeenWarned = 0;
717+
return;
718+
}
681719

682720
#
683721
# Read in the named file
@@ -687,36 +725,24 @@ sub edWrite {
687725
# 1 - success
688726

689727
sub edEdit {
690-
my($QuestionsMode,$InsertMode) = @_;
728+
my $QuestionsMode = shift;
691729
my(@tmp_lines, $chars, $fh, $filename);
692730

693-
if ($InsertMode) {
694-
if (defined $adrs[1]) {
695-
$adrs[0] = $adrs[1];
696-
}
697-
if (!defined($adrs[0])) {
698-
$adrs[0] = maxline();
699-
}
700-
} else {
701-
if (defined($adrs[0]) or defined($adrs[1])) {
702-
return E_ADDREXT;
703-
}
704-
if ($NeedToSave && $QuestionsMode && !$UserHasBeenWarned) {
705-
$UserHasBeenWarned = 1;
706-
return E_UNSAVED;
707-
}
731+
return E_ADDREXT if defined($adrs[0]) or defined($adrs[1]);
732+
if ($NeedToSave && $QuestionsMode && !$UserHasBeenWarned) {
733+
$UserHasBeenWarned = 1;
734+
return E_UNSAVED;
708735
}
709-
710736
my $do_pipe = 0;
711737
if (defined $args[0]) {
712738
return E_FNAME unless (length $args[0]);
713739
if ($args[0] =~ s/\A\!//) {
714740
$do_pipe = 1;
741+
$fh = init_pipe($args[0]);
742+
return E_OPEN unless $fh;
743+
} else {
744+
$filename = $RememberedFilename = $args[0];
715745
}
716-
if (!$InsertMode && !$do_pipe) {
717-
$RememberedFilename = $args[0];
718-
}
719-
$filename = $args[0];
720746
} elsif (defined $RememberedFilename) {
721747
$filename = $RememberedFilename;
722748
} else {
@@ -725,61 +751,67 @@ sub edEdit {
725751
return;
726752
}
727753

728-
if ($do_pipe) {
729-
return unless (open $fh, "$filename |"); # no error
730-
} else {
731-
if (-d $filename) {
732-
warn "$filename: is a directory\n";
733-
return E_READ;
734-
}
735-
unless (open $fh, '<', $filename) {
736-
warn "$filename: $!\n";
737-
return E_OPEN;
738-
}
754+
unless ($do_pipe) {
755+
$fh = open_file_ro($filename);
756+
return E_OPEN unless $fh;
739757
}
758+
@tmp_lines = readin_lines($fh, 0);
740759
$chars = 0;
741-
while (<$fh>) {
742-
push @tmp_lines, $_;
760+
foreach (@tmp_lines) {
743761
$chars += length;
744762
}
745763
unless (close $fh) {
746764
warn "$filename: $!\n";
747765
return E_CLOSE;
748766
}
749-
if ($chars == 0) {
750-
$UserHasBeenWarned = 0;
751-
$CurrentLineNum = 0;
752-
@lines = (0);
753-
print "0\n" unless $Scripted;
767+
print "$chars\n" unless $Scripted;
768+
769+
@lines = (undef, @tmp_lines); # tmp_lines can be empty
770+
$CurrentLineNum = maxline();
771+
$NeedToSave = $UserHasBeenWarned = 0;
772+
return;
773+
}
774+
775+
sub init_pipe {
776+
my $cmd = shift;
777+
return if $cmd =~ m/\0/;
778+
return unless $cmd =~ m/\S/;
779+
$cmd =~ s/(\A\s+)|(\s+\z)//g;
780+
my @arglist = quotewords('\s+', 0, $cmd);
781+
my $fh;
782+
unless (open $fh, '-|', @arglist) {
783+
warn "open: $!\n";
754784
return;
755785
}
756-
if (substr($tmp_lines[-1], -1, 1) ne "\n") {
757-
$tmp_lines[-1] .= "\n";
758-
$chars++;
786+
return $fh;
787+
}
788+
789+
sub readin_lines {
790+
my ($fh, $dot) = @_;
791+
my @tmp;
792+
while (<$fh>) {
793+
last if $dot && m/\A\.\Z/;
794+
push @tmp, $_;
795+
}
796+
if (@tmp && substr($tmp[-1], -1, 1) ne "\n") {
797+
$tmp[-1] .= "\n";
759798
print "Newline appended\n";
760799
}
800+
return @tmp;
801+
}
761802

762-
# now that we've got it, figure out what to do with it
763-
764-
if ($InsertMode) {
765-
if (maxline() != 0 && $adrs[0] == maxline()) {
766-
push(@lines,@tmp_lines);
767-
} elsif ($adrs[0] == 0) {
768-
splice @lines, 1, 0, @tmp_lines;
769-
} else {
770-
splice @lines, $adrs[0] + 1, 0, @tmp_lines;
771-
}
772-
$CurrentLineNum = $adrs[0] + scalar(@tmp_lines);
773-
$NeedToSave = 1;
774-
} else {
775-
@lines = (undef, @tmp_lines);
776-
$NeedToSave = 0;
777-
$CurrentLineNum = maxline();
803+
sub open_file_ro {
804+
my $path = shift;
805+
my $fh;
806+
if (-d $path) {
807+
warn "$path: is a directory\n";
808+
return;
778809
}
779-
780-
$UserHasBeenWarned = 0;
781-
print "$chars\n" unless $Scripted;
782-
return;
810+
unless (open $fh, '<', $path) {
811+
warn "$path: $!\n";
812+
return;
813+
}
814+
return $fh;
783815
}
784816

785817
#
@@ -788,7 +820,6 @@ sub edEdit {
788820

789821
sub edInsert {
790822
my $append = shift;
791-
my(@tmp_lines);
792823

793824
return E_ARGEXT if defined $args[0];
794825

@@ -799,11 +830,7 @@ sub edInsert {
799830
$adrs[0] = $CurrentLineNum;
800831
}
801832

802-
# suck the text into a temp array
803-
while (<>) {
804-
last if (/^\.$/);
805-
push(@tmp_lines,$_);
806-
}
833+
my @tmp_lines = readin_lines(*STDIN, 1);
807834
return unless (@tmp_lines); # no change
808835

809836
my $src = $adrs[0];

0 commit comments

Comments
 (0)