File Coverage

blib/lib/Term/CallEditor.pm
Criterion Covered Total %
statement 58 80 72.5
branch 21 46 45.6
condition 5 11 45.4
subroutine 9 10 90.0
pod 1 1 100.0
total 94 148 63.5


line stmt bran cond sub pod time code
1             # -*- Perl -*-
2             #
3             # Solicits data from an external editor. Run perldoc(1) on this module
4             # for additional documentation.
5              
6             package Term::CallEditor;
7              
8 1     1   70217 use strict;
  1         3  
  1         28  
9 1     1   6 use warnings;
  1         2  
  1         34  
10              
11             require 5.008;
12              
13 1     1   5 use vars qw(@EXPORT @ISA $VERSION $errstr);
  1         2  
  1         92  
14             @EXPORT = qw(solicit);
15             @ISA = qw(Exporter);
16 1     1   7 use Exporter;
  1         2  
  1         55  
17              
18 1     1   843 use File::Temp 0.19 qw(tempfile);
  1         21902  
  1         63  
19 1     1   7 use IO::Handle; # for way olden versions of Perl
  1         2  
  1         38  
20 1     1   499 use POSIX qw(getpgrp tcgetpgrp);
  1         6361  
  1         5  
21 1     1   1988 use Text::ParseWords qw(shellwords);
  1         1400  
  1         696  
22              
23             $VERSION = '1.01';
24              
25             sub solicit {
26 7     7 1 19448 my $message = shift;
27 7   50     34 my $params = shift || {};
28 7         32 $errstr = '';
29              
30 7 50 33     138 unless (exists $params->{skip_interative} and $params->{skip_interative}) {
31 0 0       0 return unless _is_interactive();
32             }
33              
34 7 50       63 File::Temp->safe_level($params->{safe_level}) if exists $params->{safe_level};
35             # NOTE olden versions of File::Temp (pre 0.2307) set EXLOCK to true,
36             # so turn that off so don't have a lock on the file that the EDITOR
37             # may then stumble over. way olden versions do not have this flag
38 7         159 my ($tfh, $filename) = tempfile(UNLINK => 1, EXLOCK => 0);
39              
40 7 50 33     6777 unless ($tfh and $filename) {
41 0         0 $errstr = 'no temporary file';
42 0         0 return;
43             }
44              
45 7 100 66     121 if (exists $params->{binmode_layer}
    50          
46             and defined $params->{binmode_layer}) {
47 1         24 binmode($tfh, $params->{binmode_layer});
48             } elsif ($params->{BINMODE}) {
49 0         0 binmode($tfh);
50             }
51              
52 7         116 select((select($tfh), $|++)[0]);
53              
54 7 50       38 if (defined $message) {
55 7         19 my $ref = ref $message;
56 7 50       20 if (not $ref) {
    0          
    0          
    0          
    0          
57 7         364 print $tfh $message;
58             } elsif ($ref eq 'SCALAR') {
59 0         0 print $tfh $$message;
60             } elsif ($ref eq 'ARRAY') {
61 0         0 print $tfh "@$message";
62             } elsif ($ref eq 'GLOB') {
63 0         0 while (my $line = readline $message) {
64 0         0 print $tfh $line;
65             }
66             } elsif (UNIVERSAL::can($message, 'getlines')) {
67 0         0 print $tfh $message->getlines;
68             }
69             # Help the bits reach the disk
70 7         78 $tfh->flush();
71 7 50       108 $params->{NOSYNC} = 1 if $^O =~ m/Win32/;
72 7 50       59 if (!$params->{NOSYNC}) {
73 7         55484 $tfh->sync();
74             }
75             }
76              
77 7 50       167 my $ed = defined $params->{DEFAULT_EDITOR} ? $params->{DEFAULT_EDITOR} : 'vi';
78 7         30 my $status;
79             my @errs;
80             # new in 2020, support for VISUAL !!
81 7         37 for my $editor ($ENV{VISUAL}, $ENV{EDITOR}, $ed) {
82 21 100       99 next unless length $editor;
83 10         181 my @cmd = (shellwords($editor), $filename);
84 10         2047 $status = system { $cmd[0] } @cmd;
  10         36174  
85 10 100       648 if ($status != 0) {
86 8 100       697 push @errs,
87             ($status != -1)
88             ? "external editor failed: editor=$editor, errstr=$?"
89             : "could not launch program: editor=$editor, errstr=$!";
90             } else {
91 2         134 last;
92             }
93             }
94 7 100       96 if ($status != 0) {
95 5         118 $errstr = join ' ', @errs;
96 5         298 return;
97             }
98              
99             # Must reopen filename; the editor could pull a rename(2) on us, in
100             # which case $tfh is now invalid.
101 2         36 my $outfh;
102 2 50       342 unless (open($outfh, '<', $filename)) {
103 0         0 $errstr = "could not reopen tmp file: errstr=$!";
104 0         0 return;
105             }
106              
107 2 50       160 return wantarray ? ($outfh, $filename) : $outfh;
108             }
109              
110             # Perl CookBook code to check whether terminal is interactive
111             sub _is_interactive {
112 0     0     my $tty;
113 0 0         unless (open $tty, '<', '/dev/tty') {
114 0           $errstr = "cannot open /dev/tty: errno=$!";
115 0           return;
116             }
117 0           my $tpgrp = tcgetpgrp fileno $tty;
118 0           my $pgrp = getpgrp();
119 0           close $tty;
120 0 0         unless ($tpgrp == $pgrp) {
121 0           $errstr = "no exclusive control of tty: pgrp=$pgrp, tpgrp=$tpgrp";
122 0           return;
123             }
124 0           return 1;
125             }
126              
127             1;
128             __END__