File Coverage

lib/Devel/Trepan/Options.pm
Criterion Covered Total %
statement 40 110 36.3
branch 1 52 1.9
condition 1 14 7.1
subroutine 14 23 60.8
pod 0 8 0.0
total 56 207 27.0


line stmt bran cond sub pod time code
1             # Copyright (C) 2011-2014, 2019 Rocky Bernstein <rocky@cpan.org>
2 13     13   5401 use strict;
  13         30  
  13         355  
3 13     13   61 use warnings;
  13         26  
  13         497  
4             package Devel::Trepan::Options;
5 13     13   7860 use Getopt::Long qw(GetOptionsFromArray);
  13         143438  
  13         83  
6 13     13   33995 use Pod::Usage;
  13         629748  
  13         1802  
7 13     13   122 use Pod::Find qw(pod_where);
  13         30  
  13         930  
8 13     13   97 use File::Spec;
  13         31  
  13         439  
9 13     13   808 use File::HomeDir;
  13         6028  
  13         1297  
10              
11 13     13   97 use vars qw(@EXPORT $DEFAULT_OPTIONS $PROGRAM_NAME $VERSION);
  13         27  
  13         1328  
12             @EXPORT = qw( process_options whence_file $DEFAULT_OPTIONS $PROGRAM_NAME);
13             our @ISA;
14             $VERSION='1.0.1'; # To fool CPAN indexer. Is <= real version
15              
16             BEGIN {
17 13     13   43 $PROGRAM_NAME = 'trepan.pl';
18 13         86 my @OLD_INC = @INC;
19 13     13   82 use rlib '../..';
  13         43  
  13         114  
20 13     13   5412 use rlib '.';
  13         31  
  13         229  
21 13     13   9731 use Devel::Trepan::Version;
  13         33  
  13         544  
22 13         358 @INC = @OLD_INC;
23             }
24              
25 13     13   79 use constant PROGRAM_NAME => $PROGRAM_NAME;
  13         31  
  13         20988  
26              
27             @ISA = qw(Exporter);
28              
29             # Return whether we want Terminal highlighting by default
30             sub default_term() {
31             ($ENV{'TERM'} && ($ENV{'TERM'} ne 'dumb' ||
32 26 50 33 26 0 2984 (exists($ENV{'EMACS'}) && $ENV{'EMACS'} eq 't')))
33             ? 'lightbg' : undef
34             }
35              
36             my $HOME = File::HomeDir->my_home;
37             my $initfile = File::Spec->catfile($HOME, '.treplrc');
38             $DEFAULT_OPTIONS = {
39             basename => 0,
40             batchfile => undef,
41             cmddir => [], # Additional directories of debugger commands
42             cmdfiles => [], # Files containing debugger commands to 'source'
43             exec_strs => [], # Perl strings to evaluate
44             fall_off_end => 0, # Don't go into debugger on termination?
45             highlight => default_term(),
46             # Default values used only when 'server' or 'client' # (out-of-process debugging)
47             host => 'localhost',
48             includes => [], # includes to add to @INC.
49             initfile => $initfile,
50             initial_dir => undef, # If --cd option was given, we save it here.
51             modules => [], # modules ot add to perl -M
52             nx => 0, # Don't run user startup file (e.g. .treplrc)
53             port => 1954,
54             post_mortem => 0, # Go into debugger on die?
55             readline => 1, # Try to use GNU Readline?
56             testing => undef,
57             traceprint => 0, # set -x tracing?
58             verbose => 0, # show what we are doing?
59              
60             };
61              
62             sub show_version()
63             {
64 0     0 0   printf "$PROGRAM_NAME, version %s\n", $Devel::Trepan::Version::VERSION;
65 0           exit 10;
66             }
67              
68             sub check_tcp_opts($$) {
69 0     0 0   my ($server_client, $opts) = @_;
70 0           my ($protocol, $host, $port) = @$opts;
71 0   0       $opts->[1] = $host || $DEFAULT_OPTIONS->{host};
72 0   0       $opts->[2] = $port || $DEFAULT_OPTIONS->{port};
73 0 0         unless ($opts->[2] =~ /^\d+$/) {
74 0           print STDERR "port should be a number: got $opts->[2]\n";
75 0           $opts->[2] = $DEFAULT_OPTIONS->{port};
76             }
77 0           $opts;
78             }
79              
80             sub bad_tty_opts($$) {
81 0     0 0   my ($server_client, $opts) = @_;
82 0 0         if (scalar @$opts != 3) {
83 0           return "For now, you need to specify an input and output pseudo tty";
84             }
85 0           my ($protocol, $inp_pty, $out_pty) = @$opts;
86 0 0         return "input pseudo-tty '$inp_pty' is not character device"
87             unless -c $inp_pty;
88 0 0         return "output pseudo-tty name '$out_pty' is not a character device"
89             unless -c $out_pty;
90 0 0         return "input pseudo-tty '$inp_pty' is not readable"
91             unless -r $inp_pty;
92 0 0         return "output pseudo-tty '$out_pty' is not writeable"
93             unless -w $out_pty;
94 0           return undef;
95             }
96              
97             sub check_protocol($)
98             {
99 0     0 0   my ($opts) = @_;
100 0           my $server_type = $opts->[0];
101 0 0         if ($server_type !~ /^tcp|^tty/) {
102 0           print STDERR
103             "Protocol should be either 'tcp' or 'tty': got '$server_type'\n";
104 0           $opts->[0] = 'tcp';
105             }
106             }
107              
108             sub parse_client_server_opts($$$)
109             {
110 0     0 0   my ($server_client, $opts, $server_opts) = @_;
111 0 0         if (scalar @$server_opts == 1) {
    0          
112 0 0         if (!$server_opts->[0]) {
113 0           $server_opts->[0] = 'tcp';
114             }
115 0           check_protocol($server_opts);
116             } elsif (scalar @$server_opts <= 3) {
117 0           check_protocol($server_opts);
118 0 0         if ($server_opts->[0] eq 'tcp'){
119 0           $server_opts = check_tcp_opts($server_client, $server_opts);
120 0           $opts->{host} = $server_opts->[1];
121 0           $opts->{port} = $server_opts->[2];
122             } else {
123 0           my $mess = bad_tty_opts($server_client, $server_opts);
124 0 0         die $mess if $mess;
125             }
126             }
127             }
128              
129             sub process_options($)
130             {
131 0     0 0   $Getopt::Long::autoabbrev = 1;
132 0           my ($argv) = @_;
133 0           my ($show_version, $help, $man);
134 0           my $opts = $DEFAULT_OPTIONS;
135              
136             my $result = &GetOptionsFromArray($argv,
137             'basename' => \$opts->{basename},
138             'batch:s' => \$opts->{batchfile},
139             'bw' => \$opts->{bw},
140             'cd:s' => \$opts->{initial_dir},
141             'client=s@{0,3}' => \$opts->{client},
142             'cmddir=s@' => \$opts->{cmddir},
143             'command=s@' => \$opts->{cmdfiles},
144             'e|exec=s@' => \$opts->{exec_strs},
145             'fall-off-end' => \$opts->{fall_off_end},
146             'help' => \$help,
147             'highlight' => \$opts->{highlight},
148             'I|includes=s@' => \$opts->{includes},
149             'man' => \$man,
150             'M|modules=s@' => \$opts->{modules},
151 0     0     'no-highlight' => sub { $opts->{highlight} = 0},
152 0     0     'no-readline' => sub { $opts->{readline} = 0},
153             'nx' => \$opts->{nx},
154             'post-mortem' => \$opts->{post_mortem},
155             'readline' => \$opts->{readline},
156             'server=s@{0,3}' => \$opts->{server},
157             'testing:s' => \$opts->{testing},
158             'verbose' => \$opts->{verbose},
159             'version' => \$show_version,
160             'x|trace' => \$opts->{traceprint},
161 0           );
162              
163 0 0         pod2usage(-input => pod_where({-inc => 1}, __PACKAGE__),
164             -exitstatus => 1) if $help;
165 0 0         pod2usage(-exitstatus => 10, -verbose => 2,
166             -input => pod_where({-inc => 1}, __PACKAGE__)) if $man;
167 0 0         show_version() if $show_version;
168             chdir $opts->{initial_dir} || die "Can't chdir to $opts->{initial_dir}" if
169 0 0 0       defined($opts->{initial_dir});
170 0           my $batch_filename = $opts->{testing};
171 0 0         $batch_filename = $opts->{batchfile} unless defined $batch_filename;
172 0 0         if ($batch_filename) {
173 0 0         if (scalar(@{$opts->{cmdfiles}}) != 0) {
  0            
174             printf(STDERR "--batch option disables command files: %s\n",
175 0           join(', ', @{$opts->{cmdfiles}}));
  0            
176 0           $opts->{cmdfiles} = [];
177             }
178 0           $opts->{nx} = 1;
179             }
180 0 0 0       if ($opts->{server} and $opts->{client}) {
181 0           printf STDERR
182             "Pick only on from of the --server or --client options\n";
183             } else {
184             # use Enbugger 'trepan'; Enbugger->stop;
185             # $opts->{server} = ['tcp'];
186 0 0         if ($opts->{server}) {
    0          
187 0           parse_client_server_opts('server', $opts, $opts->{server});
188             } elsif ($opts->{client}) {
189             parse_client_server_opts('client', $opts, $opts->{client})
190 0           }
191             }
192              
193 0           $opts;
194             }
195              
196             # Do a shell-like path lookup for prog_script and return the results.
197             # If we can't find anything return the string given.
198             sub whence_file($)
199             {
200 0     0 0   my $prog_script = shift;
201              
202             # If we have an relative or absolute file name, don't do anything.
203 0 0         return $prog_script if
204             File::Spec->file_name_is_absolute($prog_script);
205 0           my $first_char = substr($prog_script, 0, 1);
206 0 0         return $prog_script if index('./', $first_char) != -1;
207              
208 0           for my $dirname (File::Spec->path()) {
209 0           my $prog_script_try = File::Spec->catfile($dirname, $prog_script);
210 0 0         return $prog_script_try if -r $prog_script_try;
211             }
212             # Failure
213 0           return $prog_script;
214             }
215              
216             unless (caller) {
217             my $argv = \@ARGV;
218             my $opts = process_options($argv);
219             printf "whence file for perl: %s\n", whence_file('perl');
220             require Data::Dumper;
221             import Data::Dumper;
222             print Dumper($opts), "\n";
223             my $pid = fork();
224             # if ($pid == 0) {
225             # my @argv = qw(--version);
226             # my $opts = process_options(\@argv);
227             # exit 0;
228             # } else {
229             # waitpid($pid, 0);
230             # print "exit code: ", $?>>8, "\n";
231             # }
232             # $pid = fork();
233             # if ($pid == 0) {
234             # my @argv = qw(--cd /tmp --cmddir /tmp);
235             # my $opts = process_options(\@argv);
236             # print Dumper($opts), "\n";
237             # exit 0;
238             # } else {
239             # waitpid($pid, 0);
240             # print "exit code: ", $?>>8, "\n";
241             # }
242             # exit;
243             # $pid = fork();
244             # if ($pid == 0) {
245             # my @argv = qw(--cd /bogus);
246             # my $opts = process_options(\@argv);
247             # exit 0
248             # } else {
249             # waitpid($pid, 0);
250             # print "exit code: ", $?>>8, "\n";
251             # }
252             # $pid = fork();
253             # if ($pid == 0) {
254             # my @argv = ('--batch', __FILE__);
255             # my $opts = process_options(\@argv);
256             # print Dumper($opts), "\n";
257             # exit 0
258             # } else {
259             # waitpid($pid, 0);
260             # print "exit code: ", $?>>8, "\n";
261             # }
262              
263             # $pid = fork();
264             if ($pid == 0) {
265             my @argv = ('--server', '--', __FILE__);
266             my $opts = process_options(\@argv);
267             print Dumper($opts), "\n";
268             exit 0
269             } else {
270             waitpid($pid, 0);
271             print "exit code: ", $?>>8, "\n";
272             }
273              
274             }
275              
276             1;
277              
278             __END__
279              
280             =head1 TrepanPl
281              
282             trepan.pl - Perl "Trepanning" Debugger
283              
284             =head1 SYNOPSIS
285              
286             trepan.pl [options] [[--] perl-program [perl-program-options ...]]
287              
288             Options:
289             --help brief help message
290             --man full documentation
291             --basename Show basename only on source file listings.
292             (Needed in regression tests)
293             --bw Use Bullwinkle Processor (for front-ends) rather
294             that the command-line processor
295             -c| --command FILE Run or 'source' debugger command file FILE
296             --cmddir DIR Read DIR for additional debugger commands
297             --batch FILE Like --command, but quit after reading FILE.
298             This option has precidence over --command and
299             will also set --nx
300             --cd DIR Change current directory to DIR
301             -e| --exec STRING eval STRING. Multiple -e's can be given.
302             Works like Perl's -e switch
303             --nx Don't run user startup file (e.g. .treplrc)
304              
305             --client {'tcp' host port} | {'tty', input-slave output-slave}
306             Set for out-of-process debugging.
307             The client runs outside of this process.
308             'tcp' uses TCP/IP
309             'tty' uses pseudo tty.
310              
311             --server {'tcp' host port} | {'tty'}
312             Set for out-of-process debugging. The server
313             rus the Perl program to be debugged runs.
314              
315             --fall-off-end Don't stay in debugger when program terminates
316              
317             --include | -I DIR Add DIR to @INC in invoking program
318              
319             --module | -M MOD Add module MOD in invoking program
320              
321             --post-mortem Enter debugger on die
322             --readline | --no-readline
323             Try or don't try to use Term::Readline
324             -x|--trace Simulate line tracing (think POSIX shell set -x)
325             --highlight | --no-highlight
326             Use or don't use ANSI terminal sequences for syntax
327             highlight
328             --verbose Show what trepan.pl is invoking under the
329             covers
330              
331             =head1 DESCRIPTION
332              
333             B<trepan.pl> is a gdb-like debugger. Much of the interface and code has
334             been adapted from the trepanning debuggers of Ruby.
335              
336             =cut