File Coverage

blib/lib/Psh.pm
Criterion Covered Total %
statement 7 393 1.7
branch 0 218 0.0
condition 0 29 0.0
subroutine 3 30 10.0
pod 0 22 0.0
total 10 692 1.4


line stmt bran cond sub pod time code
1             package Psh;
2              
3 1     1   5 use vars qw($VERSION);
  1         2  
  1         58  
4              
5             $VERSION='1.8.1';
6              
7             BEGIN {
8 1     1   42 require Psh::OS;
9             }
10              
11             require Psh::Util;
12             require Psh::Locale;
13             require Psh::Strategy;
14             require Psh::Joblist;
15             require Psh::Parser;
16             require Psh::PerlEval;
17             require Psh::Options;
18              
19 1     1   3 use strict;
  1         2  
  1         4702  
20              
21             ##############################################################################
22             ##############################################################################
23             ##
24             ## Variables
25             ##
26             ##############################################################################
27             ##############################################################################
28              
29              
30             #
31             # Private, Lexical Variables:
32             #
33              
34              
35             my ($input,$readline_saves_history);
36             ##############################################################################
37             ##############################################################################
38             ##
39             ## SUBROUTINES: Command-line processing
40             ##
41             ##############################################################################
42             ##############################################################################
43              
44             #
45             # void handle_message (string MESSAGE, string FROM = 'eval')
46             #
47             # handles any message that an eval might have returned. Distinguishes
48             # internal messages from Psh's signal handlers from all other
49             # messages. It displays internal messages with print_out or does
50             # nothing with them if FROM = 'main_loop'. It displays other messages with
51             # print_error, and if FROM = 'main_loop', psh dies in addition.
52             #
53              
54             sub handle_message
55             {
56 0     0 0   my ($message, $from) = @_;
57              
58 0 0         if (!defined($from)) { $from = 'eval'; }
  0            
59              
60 0           chomp $message;
61              
62 0 0         if ($message) {
63 0 0         return if ($from eq 'hide');
64 0 0         if ($message =~ m/^SECRET $Psh::bin:(.*)$/s) {
65 0 0         if ($from ne 'main_loop') { Psh::Util::print_out("$1\n"); }
  0            
66             } else {
67 0           Psh::Util::print_error("$from error ($message)!\n");
68 0 0         if ($from eq 'main_loop') {
69 0 0         if( Psh::Options::get_option('ignoredie')) {
70 0           Psh::Util::print_error_i18n('internal_error');
71             } else {
72 0           die("Internal psh error.");
73             }
74             }
75             }
76             }
77             }
78              
79             sub evl {
80 0     0 0   my ($line, @use_strats) = @_;
81              
82 0           local @Psh::temp_use_strats;
83 0 0         push @Psh::temp_use_strats, @use_strats if @use_strats;
84              
85 0           process_variable($line);
86 0           return ($Psh::last_success_code, @Psh::last_result);
87             }
88              
89             sub _evl {
90 0     0     my @elements= @_;
91 0           my @result=();
92 0           my $trace= Psh::Options::get_option('trace');
93 0           while( my $element= shift @elements) {
94 0           my @tmp= @$element;
95 0           my $type= shift @tmp;
96 0 0         if ($type == Psh::Parser::T_EXECUTE()) {
    0          
    0          
97 0 0         if ($trace) {
98 0           for (my $i=1; $i<@tmp; $i++) {
99 0           print STDERR "+ $tmp[$i][4]\n";
100             }
101             }
102 0           eval {
103 0           @result= Psh::OS::execute_complex_command(\@tmp);
104             };
105 0           handle_message($@);
106             } elsif ($type == Psh::Parser::T_OR()) {
107 0 0 0       return @result if @result and $result[0]; # we already had success
108             } elsif ($type == Psh::Parser::T_AND()) {
109 0 0         return (0) unless @result;
110 0 0         next if ($result[0]); # we last had success
111 0           return (0);
112             } else {
113 0           Psh::Util::print_error("evl: Don't know type $type\n");
114             }
115             }
116 0           return @result;
117             }
118              
119             #
120             # string read_until(PROMPT_TEMPL, string TERMINATOR, subr GET)
121             #
122             # Get successive lines via calls to GET until one of those
123             # entire lines matches the patterm TERMINATOR. Used to implement
124             # the `<
125             #
126             # TODO: Undo any side effects of, e.g., m//.
127             #
128              
129             sub read_until
130             {
131 0     0 0   my ($prompt_templ, $terminator, $get) = @_;
132 0           my $input;
133             my $temp;
134              
135 0           my @input;
136              
137 0           while (1) {
138 0 0         $temp = $prompt_templ?&$get(Psh::Prompt::prompt_string($prompt_templ),
139             1,\&Psh::Prompt::pre_prompt_hook):
140             &$get();
141 0 0         if (!defined($temp)) {
142 0           Psh::Util::print_error_i18n('input_incomplete',join('',@input),$Psh::bin);
143 0           return '';
144             }
145 0 0         last if $temp =~ m/^$terminator$/;
146 0           push @input, $temp;
147             }
148              
149 0           return join('',@input);
150             }
151              
152             # string read_until_complete(PROMPT_TEMPL, string SO_FAR, subr GET)
153             #
154             # Get successive lines via calls to GET until the cumulative input so
155             # far is not an incomplete expression according to
156             # incomplete_expr. Prompting is done with PROMPT_TEMPL.
157             #
158              
159             sub read_until_complete
160             {
161 0     0 0   my ($prompt_templ, $sofar, $get) = @_;
162 0           my $temp;
163 0           my @input=();
164              
165 0           while (1) {
166 0 0         $temp = $prompt_templ?
167             &$get(Psh::Prompt::prompt_string($prompt_templ),1,
168             \&Psh::Prompt::pre_prompt_hook):
169             &$get();
170 0 0         if (!defined($temp)) {
171 0           Psh::Util::print_error_i18n('input_incomplete',$sofar,$Psh::bin);
172 0           return '';
173             }
174 0           $sofar .= $temp;
175 0 0         last if Psh::Parser::incomplete_expr($sofar) <= 0;
176             }
177              
178 0           return $sofar;
179             }
180              
181              
182             #
183             # void process(bool Q_PROMPT, subr GET)
184             #
185             # Process lines produced by the subroutine reference GET until it
186             # returns undef. GET must be a reference to a subroutine which takes a
187             # string argument (the prompt, which may be empty) and returns the
188             # next line of input, or undef if there is none.
189             #
190             # Any output generated is handled by the various print_xxx routines
191             #
192             # The prompt is printed only if the Q_PROMPT argument is true. When
193             # sourcing files (like .pshrc), it is important to not print the
194             # prompt string, but for interactive use, it is important to print it.
195             #
196             # TODO: Undo any side effects, e.g. done by m//.
197             #
198              
199             sub process
200             {
201 0     0 0   my ($q_prompt, $get) = @_;
202 0           local $Psh::cmd;
203              
204 0           my $last_result_array = '';
205 0           my $result_array_ref = \@Psh::val;
206 0           my $result_array_name = 'Psh::val';
207              
208 0           my $control_d_counter=0;
209              
210 0 0         if ($q_prompt) {
211 0           require Psh::Prompt;
212             }
213              
214 0           while (1) {
215 0 0         if ($q_prompt) {
216 0           $input = &$get(Psh::Prompt::prompt_string(Psh::Prompt::normal_prompt()), 0, \&Psh::Prompt::pre_prompt_hook);
217             } else {
218 0           $input = &$get();
219             }
220              
221 0           Psh::OS::reap_children(); # Check wether we have dead children
222 0 0         Psh::OS::check_terminal_size() if $Psh::interactive;
223              
224 0           $Psh::cmd++;
225              
226 0 0         unless (defined($input)) {
227 0 0         last unless $Psh::interactive;
228 0           print STDOUT "\n";
229 0           $control_d_counter++;
230 0   0       my $control_d_max=$ENV{IGNOREEOF}||0;
231 0 0         if ($control_d_max !~ /^\d$/) {
232 0           $control_d_max=10;
233             }
234 0 0         Psh::OS::exit_psh() if ($control_d_counter>=$control_d_max);
235 0           next;
236             }
237 0           $control_d_counter=0;
238              
239 0 0         next unless $input;
240 0 0         next if $input=~ m/^\s*$/;
241              
242 0 0         if ($input =~ m/(.*)<<([a-zA-Z_0-9\-]*)(.*)/) {
    0          
243 0           my $pre= $1;
244 0           my $terminator = $2;
245 0           my $post= $3;
246              
247 0 0         my $continuation = $q_prompt ? Psh::Prompt::continue_prompt() : '';
248 0           $input = join('',$pre,'"',
249             read_until($continuation, $terminator, $get),
250             $terminator,'"',$post,"\n");
251             } elsif (Psh::Parser::incomplete_expr($input) > 0) {
252 0 0         my $continuation = $q_prompt ? Psh::Prompt::continue_prompt() : '';
253 0           $input = read_until_complete($continuation, $input, $get);
254             }
255              
256 0           chomp $input;
257              
258 0           my ($success,@result);
259 0           my @elements= eval { Psh::Parser::parse_line($input) };
  0            
260 0 0         Psh::Util::print_debug_class('e',"(evl) Error: $@") if $@;
261 0 0         if (@elements) {
262 0           my $result;
263 0           ($success,$result)= _evl(@elements);
264 0           Psh::Util::print_debug_class('s',"Success: $success\n");
265 0           $Psh::last_success_code= $success;
266 0 0         if ($result) {
267 0           @Psh::last_result= @result= @$result;
268             } else {
269 0           undef @Psh::last_result;
270 0           undef @result;
271             }
272             } else {
273 0           undef $Psh::last_success_code;
274 0           undef @Psh::last_result;
275             }
276              
277 0 0         next unless $Psh::interactive;
278              
279 0           my $qEcho = 0;
280 0           my $echo= Psh::Options::get_option('echo');
281              
282 0 0         if (ref($echo) eq 'CODE') {
    0          
283 0           $qEcho = &$echo(@result);
284             } elsif (ref($echo)) {
285 0           Psh::Util::print_warning_i18n('psh_echo_wrong',$Psh::bin);
286             } else {
287 0 0         if ($echo) { $qEcho = defined_and_nonempty(@result); }
  0            
288             }
289              
290 0 0         if ($qEcho) {
291             # Figure out where we'll save the result:
292 0 0         if ($last_result_array ne $Psh::result_array) {
293 0           $last_result_array = $Psh::result_array;
294 0           my $what = ref($last_result_array);
295 0 0         if ($what eq 'ARRAY') {
    0          
296 0           $result_array_ref = $last_result_array;
297 0           $result_array_name =
298             find_array_name($result_array_ref);
299 0 0         if (!defined($result_array_name)) {
300 0           $result_array_name = 'anonymous';
301             }
302             } elsif ($what) {
303 0           Psh::Util::print_warning_i18n('psh_result_array_wrong',$Psh::bin);
304 0           $result_array_ref = \@Psh::val;
305 0           $result_array_name = 'Psh::val';
306             } else { # Ordinary string
307 0           $result_array_name = $last_result_array;
308 0           $result_array_name =~ s/^\@//;
309 0           $result_array_ref = (Psh::PerlEval::protected_eval("\\\@$result_array_name"))[0];
310             }
311             }
312 0 0         if (scalar(@result) > 1) {
313 0           my $n = scalar(@{$result_array_ref});
  0            
314 0           push @{$result_array_ref}, \@result;
  0            
315 0 0         if ($Psh::interactive) {
316 0           my @printresult=();
317 0           foreach my $val (@result) {
318 0 0         if (defined $val) {
319 0           push @printresult,qq['$val'];
320             } else {
321 0           push @printresult,qq[undef];
322             }
323             }
324 0           Psh::Util::print_out("\$$result_array_name\[$n] = [", join(',',@printresult), "]\n");
325             }
326             } else {
327 0           my $n = scalar(@{$result_array_ref});
  0            
328 0           my $res = $result[0];
329 0           push @{$result_array_ref}, $res;
  0            
330 0           Psh::Util::print_out("\$$result_array_name\[$n] = \"$res\"\n");
331             }
332 0 0         if (@{$result_array_ref}>100) {
  0            
333 0           shift @{$result_array_ref};
  0            
334             }
335             }
336             }
337             }
338              
339             # string find_array_name ( arrayref REF, string PACKAGE )
340             #
341             # If REF is a reference to an array variable in the given PACKAGE or
342             # any of its subpackages, find the name of that variable and return
343             # it. PACKAGE defaults to main.
344              
345             sub find_array_name {
346 0     0 0   my ($arref, $pack) = @_;
347 0 0         if (!defined($pack)) { $pack = "::"; }
  0            
348 0           my @otherpacks = ();
349 0           for my $symb ( keys %{$pack} ) {
  0            
350 0 0         if ($symb =~ m/::$/) {
  0 0          
351 0 0 0       push @otherpacks, $symb unless ($pack eq 'main::' and $symb eq 'main::');
352             }
353 0           elsif (\@{"$pack$symb"} eq $arref) { return "$pack$symb"; }
354             }
355 0           for my $subpack (@otherpacks) {
356 0           my $ans = find_array_name($arref,"$pack$subpack");
357 0 0         if (defined($ans)) { return $ans; }
  0            
358             }
359 0           return undef;
360             }
361              
362             #
363             # bool defined_and_nonempty(args)
364             #
365             # returns true if it has any defined, nonempty args
366             #
367              
368             sub defined_and_nonempty
369             {
370 0 0   0 0   if (!defined(@_)) { return 0; }
  0            
371 0 0         if (scalar(@_) == 0) { return 0; }
  0            
372              
373 0 0         if (scalar(@_) == 1) {
374 0 0         if (!defined($_[0])) { return 0; }
  0            
375 0 0         if ($_[0] eq '') { return 0; }
  0            
376              
377 0           return 1;
378             }
379              
380 0           return 1; # multiple args always true
381             }
382              
383              
384             #
385             # void process_file(string FILENAME)
386             #
387             # process() the lines of FILENAME
388             #
389              
390             sub process_file
391             {
392 0     0 0   my $path= shift;
393              
394 0           Psh::Util::print_debug("[PROCESSING FILE $path]\n");
395 0           local $Psh::interactive=0;
396              
397 0 0         if (!-r $path) {
398 0           Psh::Util::print_error_i18n('cannot_read_script',$path,$Psh::bin);
399 0           return;
400             }
401              
402 0           local(*FILE);
403 0 0         unless (open(FILE, "< $path")) {
404 0           Psh::Util::print_error_i18n('cannot_open_script',$path,$Psh::bin);
405 0           return;
406             }
407              
408 0           Psh::OS::lock(*FILE);
409              
410 0 0 0       if ($Psh::debugging=~ /f/ or
411             $Psh::debugging eq '1') {
412             process(0, sub {
413 0     0     my $txt=;
414 0           Psh::Util::print_debug_class('f',$txt);
415 0           return $txt;
416 0           }); # don't prompt
417             } else {
418 0     0     process(0, sub { my $txt=;$txt });
  0            
  0            
419             }
420              
421 0           Psh::OS::unlock(*FILE);
422 0           close(FILE);
423              
424 0           Psh::Util::print_debug("[FINISHED PROCESSING FILE $path]\n");
425             }
426              
427             sub process_variable {
428 0     0 0   my $var= shift;
429 0           local $Psh::interactive=0;
430 0           my @lines;
431 0 0         if (ref $var eq 'ARRAY') {
432 0           @lines=@$var;
433             } else {
434 0           @lines= split /\n/, $var;
435 0           @lines= map { $_."\n" } @lines;
  0            
436             }
437 0     0     process(0, sub { shift @lines });
  0            
438             }
439              
440             #
441             # string iget(string PROMPT [, boolean returnflag [, code prompt_hook]])
442             #
443             # Interactive line getting routine. If we have a
444             # Term::ReadLine instance, use it and record the
445             # input into the history buffer. Otherwise, just
446             # grab an input line from STDIN.
447             #
448             # If returnflag is true, iget will return after
449             # the user pressed ^C
450             #
451             # readline() returns a line WITHOUT a "\n" at the
452             # end, and returns one WITH a "\n", UNLESS
453             # the end of the input stream occurs after a non-
454             # newline character. So, first we chomp() the
455             # output of (if we aren't using readline()),
456             # and then we tack the newline back on in both
457             # cases. Other code later strips it off if necessary.
458             #
459             # iget() uses PROMPT as the prompt; this may be the empty string if no
460             # prompting is necessary.
461             #
462              
463             sub iget
464             {
465 0     0 0   my $prompt = shift;
466 0           my $returnflag= shift;
467 0           my $prompt_hook= shift;
468              
469 0           my $prompt_pre= '';
470 0           my $line;
471 0           my $sigint = 0;
472 0           $Psh::interactive=1;
473              
474             # Additional newline handling for prompts as Term::ReadLine::Perl
475             # cannot use them properly
476 0 0 0       if( $Psh::term->ReadLine eq 'Term::ReadLine::Perl' &&
477             $prompt=~ /^(.*\n)([^\n]+)$/) {
478 0           $prompt_pre=$1;
479 0           $prompt=$2;
480             }
481              
482 0           Psh::OS::setup_readline_handler();
483              
484 0           LINE: do {
485 0 0         $sigint= 0 if ($sigint);
486             # Trap ^C in an eval. The sighandler will die which will be
487             # trapped. Then we reprompt
488 0 0         if ($Psh::term) {
489 0 0         &$prompt_hook if $prompt_hook;
490 0 0         print $prompt_pre if $prompt_pre;
491 0           eval { $line = $Psh::term->readline($prompt); };
  0            
492             } else {
493 0           eval {
494 0 0         &$prompt_hook if $prompt_hook;
495 0 0         print $prompt_pre if $prompt_pre;
496 0 0         print $prompt if $prompt;
497 0           $line = ;
498             };
499             }
500 0 0         if( $@) {
501 0 0         if( $@ =~ /Signal INT/) {
502 0           $sigint= 1;
503 0           Psh::Util::print_out_i18n('readline_interrupted');
504 0 0         if( $returnflag) {
505 0           Psh::OS::remove_readline_handler();
506 0           return undef;
507             }
508             } else {
509 0           handle_message( $@, 'iget');
510             }
511             }
512             } while ($sigint);
513              
514 0           Psh::OS::remove_readline_handler();
515 0           Psh::OS::reinstall_resize_handler();
516              
517 0 0         return undef unless defined $line;
518 0           chomp $line;
519              
520 0           add_history($line);
521 0           return $line . "\n"; # This is expected by other code.
522             }
523              
524             sub add_history
525             {
526 0     0 0   my $line=shift;
527 0 0 0       return if !$line or $line =~ /^\s*$/;
528 0 0 0       if (!@Psh::history || $Psh::history[$#Psh::history] ne $line) {
529 0           my $len= Psh::Options::get_option('histsize');
530 0 0         $Psh::term->addhistory($line) if $Psh::term;
531 0           push(@Psh::history, $line);
532 0 0         if( @Psh::history>$len) {
533 0           splice(@Psh::history,0,-$len);
534             }
535             }
536             }
537              
538             sub save_history
539             {
540 0 0   0 0   return unless $Psh::term;
541 0           Psh::Util::print_debug_class('o',"[Saving history]\n");
542 0 0         if( Psh::Options::get_option('save_history')) {
543 0           my $file= Psh::Options::get_option('history_file');
544 0 0         return unless $file;
545 0 0         if ($readline_saves_history) {
546 0           $Psh::term->StifleHistory(Psh::Options::get_option('histsize'));
547 0           $Psh::term->WriteHistory($file);
548             } else {
549 0           local(*F_HISTORY);
550 0 0         if (open(F_HISTORY,">> $file")) {
551 0           Psh::OS::lock(*F_HISTORY, Psh::OS::LOCK_EX());
552 0           foreach (@Psh::history) {
553 0           print F_HISTORY $_;
554 0           print F_HISTORY "\n";
555             }
556 0           Psh::OS::unlock(*F_HISTORY);
557 0           close(F_HISTORY);
558             }
559             }
560             }
561             }
562              
563             #
564             # void minimal_initialize()
565             #
566             # Initialize just enough to be able to read the .pshrc file; leave
567             # uncritical user-accessible variables until later in case the user
568             # sets them in .pshrc.
569              
570             sub minimal_initialize
571             {
572 0     0 0   $| = 1; # Set output autoflush on
573              
574             #
575             # Set up accessible psh:: package variables:
576             #
577              
578 0           $Psh::eval_preamble = '';
579 0           $Psh::currently_active = 0;
580 0           $Psh::result_array = '';
581 0           $Psh::which_regexp = '^[-a-zA-Z0-9_.~+]+$'; #'
582              
583 0 0         if ($]>=5.005) {
584 0           eval {
585 0           $Psh::which_regexp= qr($Psh::which_regexp); # compile for speed reasons
586             };
587 0 0         Psh::Util::print_debug_class('e',"(minimal_init) Error: $@") if $@;
588             }
589              
590 0           $Psh::cmd = 1;
591 0           my @tmp= Psh::OS::splitdir($0);
592 0           $Psh::bin= pop @tmp;
593 0           Psh::Options::set_option('history_file',
594             Psh::OS::catfile(Psh::OS::get_home_dir(),
595             '.'.$Psh::bin.'_history'));
596              
597 0 0         $Psh::old_shell = $ENV{SHELL} if $ENV{SHELL};
598 0           $ENV{SHELL} = $0;
599 0           $ENV{OLDPWD}= $ENV{PWD} = Psh::OS::getcwd_psh();
600              
601 0           Psh::OS::inc_shlvl();
602 0           Psh::OS::setup_signal_handlers();
603              
604             # The following accessible variables are undef during the
605             # .pshrc file:
606 0           undef $Psh::longhost;
607 0           undef $Psh::host;
608              
609 0           @Psh::val = ();
610 0           @Psh::history= ();
611              
612 0           Psh::Strategy::setup_defaults();
613             }
614              
615             #
616             # void finish_initialize()
617             #
618             # Set the remaining psh:: package variables if they haven't been set
619             # in the .pshrc file, and do other "late" initialization steps that
620             # depend on these variable values.
621              
622             sub finish_initialize
623             {
624 0 0   0 0   Psh::OS::setup_sigsegv_handler() if
625             Psh::Options::get_option('ignoresegfault');
626              
627 0 0         if (!defined($Psh::longhost)) {
628 0   0       $Psh::longhost = $ENV{HOSTNAME}||Psh::OS::get_hostname();
629 0           chomp $Psh::longhost;
630             }
631 0 0         if (!defined($Psh::host)) {
632 0           $Psh::host= $Psh::longhost;
633 0 0         $Psh::host= $1 if( $Psh::longhost=~ /([^\.]+)\..*/);
634             }
635 0           $ENV{HOSTNAME}= $Psh::host;
636             }
637              
638             sub initialize_interactive_mode {
639 0 0   0 0   if (-t STDIN) {
640             #
641             # Set up Term::ReadLine:
642             #
643 0           eval { require Term::ReadLine; };
  0            
644 0 0         if ($@) {
645 0           $Psh::term = undef;
646 0           Psh::Util::print_error_i18n('no_readline');
647             } else {
648 0           eval { $Psh::term= Term::ReadLine->new('psh'); };
  0            
649 0 0         if( $@) {
650             # Try one more time after a second, maybe the tty is
651             # not setup
652 0           sleep 1;
653 0           eval { $Psh::term= Term::ReadLine->new('psh'); };
  0            
654 0 0         if( $@) {
655 0           Psh::Util::print_error_i18n('readline_error',$@);
656 0           $Psh::term= undef;
657             }
658             }
659 0 0         if( $Psh::term) {
660 0           $Psh::term->MinLine(10000); # We will handle history adding
661             # ourselves (undef causes trouble).
662 0           $Psh::term->ornaments(0);
663 0           Psh::Util::print_debug_class('i','[Using ReadLine: ', $Psh::term->ReadLine(), "]\n");
664 0 0         if ($Psh::term->ReadLine() eq 'Term::ReadLine::Gnu') {
665 0           $readline_saves_history = 1;
666             }
667 0           my $attribs= $Psh::term->Attribs;
668 0           $attribs->{completion_function} =
669             \&completion_dummy;
670              
671 0           my $word_break=" \\\n\t\"&{}('`\$\%\@~<>=;|/";
672 0           $attribs->{special_prefixes}= "\$\%\@\~\&";
673 0           $attribs->{word_break_characters}= $word_break;
674 0           $attribs->{completer_word_break_characters}= $word_break ;
675             }
676             }
677              
678 0           Psh::OS::install_resize_handler();
679 0           Psh::OS::reinstall_resize_handler();
680             # ReadLine objects often mess with the SIGWINCH handler
681              
682 0           setup_term_misc();
683             }
684              
685 0 0 0       if (defined($Psh::term) and Psh::Options::get_option('save_history')) {
686 0           my $file= Psh::Options::get_option('history_file');
687 0 0         return unless $file;
688 0 0         if ($readline_saves_history) {
689 0           $Psh::term->StifleHistory(Psh::Options::get_option('histsize'));
690 0           $Psh::term->ReadHistory($file);
691             } else {
692 0           local(*F_HISTORY);
693 0 0         if (open(F_HISTORY,"< $file")) {
694 0           Psh::OS::lock(*F_HISTORY);
695 0           while () {
696 0           chomp;
697 0           $Psh::term->addhistory($_);
698             }
699 0           Psh::OS::unlock(*F_HISTORY);
700 0           close(F_HISTORY);
701             }
702             }
703             }
704             }
705              
706              
707             #
708             # We're used for the first TAB completion - load
709             # the real completion module and call it
710             #
711             sub completion_dummy {
712 0     0 0   my @args= @_;
713              
714 0           require Psh::Completion;
715 0           Psh::Completion::init();
716 0           $Psh::term->Attribs->{completion_function} =
717             \&Psh::Completion::completion;
718 0           return Psh::Completion::completion(@_);
719             }
720              
721             sub setup_term_misc {
722 0 0   0 0   return unless $Psh::term;
723 0 0         if ($Psh::term->can('add_defun')) { # Term::ReadLine::Gnu
724 0           $Psh::term->add_defun('run-help', \&run_help);
725 0           $Psh::term->parse_and_bind("\"\eh\":run-help"); # bind to ESC-h
726             }
727             }
728              
729             sub run_help {
730 0     0 0   require Psh::Builtins::Help;
731 0           my $line= substr($Psh::term->Attribs->{line_buffer},0,
732             $Psh::term->Attribs->{end});
733 0           Psh::Builtins::Help::any_help($line);
734             }
735              
736             #
737             # void process_rc()
738             #
739             # Search for and process .pshrc files.
740             #
741              
742             sub process_rc
743             {
744 0     0 0   my $opt_f= shift;
745 0           my @rc;
746              
747 0 0         if ($opt_f) {
748 0           push @rc, $opt_f;
749             } else {
750 0           push @rc, Psh::OS::get_rc_files();
751             }
752              
753 0           foreach my $rc (@rc) {
754 0 0         if (-r $rc) {
755 0           Psh::Util::print_debug_class('i',"[PROCESSING $rc]\n");
756 0           process_file($rc);
757             }
758             }
759             }
760              
761              
762             #
763             # void process_args()
764             #
765             # Process files listed on command-line.
766             #
767              
768             sub process_args
769             {
770 0     0 0   Psh::Util::print_debug_class('i',"[PROCESSING @ARGV FILES]\n");
771              
772 0           foreach my $arg (@ARGV) {
773 0 0         if (-r $arg) {
774 0           Psh::Util::print_debug('i',"[PROCESSING $arg]\n");
775 0           process_file($arg);
776             }
777             }
778             }
779              
780              
781             #
782             # void main_loop()
783             #
784             # Determine whether or not we are operating interactively,
785             # set up the input routine accordingly, and process the
786             # input.
787             #
788              
789             sub main_loop
790             {
791 0 0   0 0   my $interactive = (-t STDIN) and (-t STDOUT);
792 0           my $get;
793              
794 0           Psh::Util::print_debug_class('i',"[STARTING MAIN LOOP]\n");
795              
796 0 0         if ($interactive) { $get = \&iget; }
  0            
797 0     0     else { $get = sub { return ; }; }
  0            
798              
799 0           process($interactive, $get);
800             }
801              
802             # bool is_number(ARG)
803             #
804             # Return true if ARG is a number
805             #
806              
807             sub is_number
808             {
809 0     0 0   my $test = shift;
810 0   0       return defined($test) && !ref($test) &&
811             $test=~/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/o;
812             }
813              
814             #
815             # End of file.
816             #
817              
818             1;