Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | # |
2 | # Please see the .pod files for documentation. This module is copyrighted | |
3 | # as per the usual perl legalese: | |
4 | # Copyright (c) 1997 Austin Schutz. | |
5 | # expect() interface & functionality enhancements (c) 1999 Roland Giersig. | |
6 | # | |
7 | # All rights reserved. This program is free software; you can | |
8 | # redistribute it and/or modify it under the same terms as Perl | |
9 | # itself. | |
10 | # | |
11 | # Don't blame/flame me if you bust your stuff. | |
12 | # Austin Schutz <ASchutz@users.sourceforge.net> | |
13 | # | |
14 | # This module now is maintained by | |
15 | # Roland Giersig <RGiersig@cpan.org> | |
16 | # | |
17 | ||
18 | use 5; # 4 won't cut it. | |
19 | ||
20 | package Expect; | |
21 | ||
22 | use IO::Pty 0.97; # We need make_slave_controlling_terminal() | |
23 | use IO::Tty; | |
24 | ||
25 | use strict 'refs'; | |
26 | use strict 'vars'; | |
27 | use strict 'subs'; | |
28 | use POSIX; # For setsid. | |
29 | use Fcntl; # For checking file handle settings. | |
30 | use Carp qw(cluck croak carp confess); | |
31 | use IO::Handle; | |
32 | use Exporter; | |
33 | ||
34 | # This is necessary to make routines within Expect work. | |
35 | ||
36 | @Expect::ISA = qw(IO::Pty Exporter); | |
37 | @Expect::EXPORT = qw(expect exp_continue exp_continue_timeout); | |
38 | ||
39 | BEGIN { | |
40 | $Expect::VERSION = 1.15; | |
41 | # These are defaults which may be changed per object, or set as | |
42 | # the user wishes. | |
43 | # This will be unset, since the default behavior differs between | |
44 | # spawned processes and initialized filehandles. | |
45 | # $Expect::Log_Stdout = 1; | |
46 | $Expect::Log_Group = 1; | |
47 | $Expect::Debug = 0; | |
48 | $Expect::Exp_Max_Accum = 0; # unlimited | |
49 | $Expect::Exp_Internal = 0; | |
50 | $Expect::Manual_Stty = 0; | |
51 | $Expect::Multiline_Matching = 1; | |
52 | $Expect::Do_Soft_Close = 0; | |
53 | @Expect::Before_List = (); | |
54 | @Expect::After_List = (); | |
55 | %Expect::Spawned_PIDs = (); | |
56 | } | |
57 | ||
58 | sub version { | |
59 | my($version) = shift; | |
60 | warn "Version $version is later than $Expect::VERSION. It may not be supported" if (defined ($version) && ($version > $Expect::VERSION)); | |
61 | ||
62 | die "Versions before 1.03 are not supported in this release" if ((defined ($version)) && ($version < 1.03)); | |
63 | return $Expect::VERSION; | |
64 | } | |
65 | ||
66 | sub new { | |
67 | ||
68 | my ($class) = shift; | |
69 | $class = ref($class) if ref($class); # so we can be called as $exp->new() | |
70 | ||
71 | # Create the pty which we will use to pass process info. | |
72 | my($self) = new IO::Pty; | |
73 | die "$class: Could not assign a pty" unless $self; | |
74 | bless $self => $class; | |
75 | $self->autoflush(1); | |
76 | ||
77 | # This is defined here since the default is different for | |
78 | # initialized handles as opposed to spawned processes. | |
79 | ${*$self}{exp_Log_Stdout} = 1; | |
80 | $self->_init_vars(); | |
81 | ||
82 | if (@_) { | |
83 | # we got add'l parms, so pass them to spawn | |
84 | return $self->spawn(@_); | |
85 | } | |
86 | return $self; | |
87 | } | |
88 | ||
89 | sub spawn { | |
90 | my ($class) = shift; | |
91 | my $self; | |
92 | ||
93 | if (ref($class)) { | |
94 | $self = $class; | |
95 | } else { | |
96 | $self = $class->new(); | |
97 | } | |
98 | ||
99 | croak "Cannot reuse an object with an already spawned command" | |
100 | if exists ${*$self}{"exp_Command"}; | |
101 | my(@cmd) = @_; # spawn is passed command line args. | |
102 | ${*$self}{"exp_Command"} = \@cmd; | |
103 | ||
104 | # set up pipe to detect childs exec error | |
105 | pipe(STAT_RDR, STAT_WTR) or die "Cannot open pipe: $!"; | |
106 | STAT_WTR->autoflush(1); | |
107 | ||
108 | my $pid = fork; | |
109 | ||
110 | unless (defined ($pid)) { | |
111 | warn "Cannot fork: $!" if $^W; | |
112 | return undef; | |
113 | } | |
114 | ||
115 | if($pid) { | |
116 | # parent | |
117 | my $errno; | |
118 | ${*$self}{exp_Pid} = $pid; | |
119 | close STAT_WTR; | |
120 | $self->close_slave(); | |
121 | $self->set_raw() if $self->raw_pty and isatty($self); | |
122 | ||
123 | # now wait for child exec (eof due to close-on-exit) or exec error | |
124 | my $errstatus = sysread(STAT_RDR, $errno, 256); | |
125 | die "Cannot sync with child: $!" if not defined $errstatus; | |
126 | close STAT_RDR; | |
127 | if ($errstatus) { | |
128 | $! = $errno+0; | |
129 | warn "Cannot exec(@cmd): $!\n" if $^W; | |
130 | return undef; | |
131 | } | |
132 | } | |
133 | else { | |
134 | # child | |
135 | close STAT_RDR; | |
136 | ||
137 | $self->make_slave_controlling_terminal(); | |
138 | my $slv = $self->slave() | |
139 | or die "Cannot get slave: $!"; | |
140 | ||
141 | $slv->set_raw() if $self->raw_pty; | |
142 | close($self); | |
143 | close(STDIN); | |
144 | open(STDIN,"<&". $slv->fileno()) | |
145 | or die "Couldn't reopen STDIN for reading, $!\n"; | |
146 | close(STDOUT); | |
147 | open(STDOUT,">&". $slv->fileno()) | |
148 | or die "Couldn't reopen STDOUT for writing, $!\n"; | |
149 | close(STDERR); | |
150 | open(STDERR,">&". $slv->fileno()) | |
151 | or die "Couldn't reopen STDERR for writing, $!\n"; | |
152 | ||
153 | { exec(@cmd) }; | |
154 | print STAT_WTR $!+0; | |
155 | die "Cannot exec(@cmd): $!\n"; | |
156 | } | |
157 | ||
158 | # This is sort of for code compatibility, and to make debugging a little | |
159 | # easier. By code compatibility I mean that previously the process's | |
160 | # handle was referenced by $process{Pty_Handle} instead of just $process. | |
161 | # This is almost like 'naming' the handle to the process. | |
162 | # I think this also reflects Tcl Expect-like behavior. | |
163 | ${*$self}{exp_Pty_Handle} = "spawn id(".$self->fileno().")"; | |
164 | if ((${*$self}{"exp_Debug"}) or (${*$self}{"exp_Exp_Internal"})) { | |
165 | cluck("Spawned '@cmd'\r\n", | |
166 | "\t${*$self}{exp_Pty_Handle}\r\n", | |
167 | "\tPid: ${*$self}{exp_Pid}\r\n", | |
168 | "\tTty: ".$self->SUPER::ttyname()."\r\n", | |
169 | ); | |
170 | } | |
171 | $Expect::Spawned_PIDs{${*$self}{exp_Pid}} = undef; | |
172 | return $self; | |
173 | } | |
174 | ||
175 | ||
176 | sub exp_init { | |
177 | # take a filehandle, for use later with expect() or interconnect() . | |
178 | # All the functions are written for reading from a tty, so if the naming | |
179 | # scheme looks odd, that's why. | |
180 | my ($class) = shift; | |
181 | my($self) = shift; | |
182 | bless $self, $class; | |
183 | croak "exp_init not passed a file object, stopped" | |
184 | unless defined($self->fileno()); | |
185 | $self->autoflush(1); | |
186 | # Define standard variables.. debug states, etc. | |
187 | $self->_init_vars(); | |
188 | # Turn of logging. By default we don't want crap from a file to get spewed | |
189 | # on screen as we read it. | |
190 | ${*$self}{exp_Log_Stdout} = 0; | |
191 | ${*$self}{exp_Pty_Handle} = "handle id(".$self->fileno().")"; | |
192 | ${*$self}{exp_Pty_Handle} = "STDIN" if $self->fileno() == fileno (STDIN); | |
193 | print STDERR "Initialized ${*$self}{exp_Pty_Handle}.'\r\n" | |
194 | if ${*$self}{"exp_Debug"}; | |
195 | return $self; | |
196 | } | |
197 | ||
198 | # make an alias | |
199 | *init = \&exp_init; | |
200 | ||
201 | ###################################################################### | |
202 | # We're happy OOP people. No direct access to stuff. | |
203 | # For standard read-writeable parameters, we define some autoload magic... | |
204 | my %Writeable_Vars = ( debug => 'exp_Debug', | |
205 | exp_internal => 'exp_Exp_Internal', | |
206 | do_soft_close => 'exp_Do_Soft_Close', | |
207 | max_accum => 'exp_Max_Accum', | |
208 | match_max => 'exp_Max_Accum', | |
209 | notransfer => 'exp_NoTransfer', | |
210 | log_stdout => 'exp_Log_Stdout', | |
211 | log_user => 'exp_Log_Stdout', | |
212 | log_group => 'exp_Log_Group', | |
213 | manual_stty => 'exp_Manual_Stty', | |
214 | restart_timeout_upon_receive => 'exp_Continue', | |
215 | raw_pty => 'exp_Raw_Pty', | |
216 | ); | |
217 | my %Readable_Vars = ( pid => 'exp_Pid', | |
218 | exp_pid => 'exp_Pid', | |
219 | exp_match_number => 'exp_Match_Number', | |
220 | match_number => 'exp_Match_Number', | |
221 | exp_error => 'exp_Error', | |
222 | error => 'exp_Error', | |
223 | exp_command => 'exp_Command', | |
224 | command => 'exp_Command', | |
225 | exp_match => 'exp_Match', | |
226 | match => 'exp_Match', | |
227 | exp_matchlist => 'exp_Matchlist', | |
228 | matchlist => 'exp_Matchlist', | |
229 | exp_before => 'exp_Before', | |
230 | before => 'exp_Before', | |
231 | exp_after => 'exp_After', | |
232 | after => 'exp_After', | |
233 | exp_exitstatus => 'exp_Exit', | |
234 | exitstatus => 'exp_Exit', | |
235 | exp_pty_handle => 'exp_Pty_Handle', | |
236 | pty_handle => 'exp_Pty_Handle', | |
237 | exp_logfile => 'exp_Log_File', | |
238 | logfile => 'exp_Log_File', | |
239 | %Writeable_Vars, | |
240 | ); | |
241 | ||
242 | sub AUTOLOAD { | |
243 | my $self = shift; | |
244 | my $type = ref($self) | |
245 | or croak "$self is not an object"; | |
246 | ||
247 | use vars qw($AUTOLOAD); | |
248 | my $name = $AUTOLOAD; | |
249 | $name =~ s/.*:://; # strip fully-qualified portion | |
250 | ||
251 | unless (exists $Readable_Vars{$name}) { | |
252 | croak "ERROR: cannot find method `$name' in class $type"; | |
253 | } | |
254 | my $varname = $Readable_Vars{$name}; | |
255 | my $tmp; | |
256 | $tmp = ${*$self}{$varname} if exists ${*$self}{$varname}; | |
257 | ||
258 | if (@_) { | |
259 | if (exists $Writeable_Vars{$name}) { | |
260 | my $ref = ref($tmp); | |
261 | if ($ref eq 'ARRAY') { | |
262 | ${*$self}{$varname} = [ @_ ]; | |
263 | } elsif ($ref eq 'HASH') { | |
264 | ${*$self}{$varname} = { @_ }; | |
265 | } else { | |
266 | ${*$self}{$varname} = shift; | |
267 | } | |
268 | } else { | |
269 | carp "Trying to set read-only variable `$name'" | |
270 | if $^W; | |
271 | } | |
272 | } | |
273 | ||
274 | my $ref = ref($tmp); | |
275 | return (wantarray? @{$tmp} : $tmp) if ($ref eq 'ARRAY'); | |
276 | return (wantarray? %{$tmp} : $tmp) if ($ref eq 'HASH'); | |
277 | return $tmp; | |
278 | } | |
279 | ||
280 | ###################################################################### | |
281 | ||
282 | sub set_seq { | |
283 | # Set an escape sequence/function combo for a read handle for interconnect. | |
284 | # Ex: $read_handle->set_seq('\17',\&function,\@parameters); | |
285 | my($self) = shift; | |
286 | my($escape_sequence,$function) = (shift,shift); | |
287 | ${${*$self}{exp_Function}}{$escape_sequence} = $function; | |
288 | if ((!defined($function)) ||($function eq 'undef')) { | |
289 | ${${*$self}{exp_Function}}{$escape_sequence} = \&_undef; | |
290 | } | |
291 | ${${*$self}{exp_Parameters}}{$escape_sequence} = shift; | |
292 | # This'll be a joy to execute. :) | |
293 | if ( ${*$self}{"exp_Debug"} ) { | |
294 | print STDERR "Escape seq. '" . $escape_sequence; | |
295 | print STDERR "' function for ${*$self}{exp_Pty_Handle} set to '"; | |
296 | print STDERR ${${*$self}{exp_Function}}{$escape_sequence}; | |
297 | print STDERR "(" . join(',', @_) . ")'\r\n"; | |
298 | } | |
299 | } | |
300 | ||
301 | sub set_group { | |
302 | my($self) = shift; | |
303 | my($write_handle); | |
304 | # Make sure we can read from the read handle | |
305 | if (! defined($_[0])) { | |
306 | if (defined (${*$self}{exp_Listen_Group})) { | |
307 | return @{${*$self}{exp_Listen_Group}}; | |
308 | } else { | |
309 | # Refrain from referencing an undef | |
310 | return undef; | |
311 | } | |
312 | } | |
313 | @{${*$self}{exp_Listen_Group}} = (); | |
314 | if ($self->_get_mode() !~ 'r') { | |
315 | warn("Attempting to set a handle group on ${*$self}{exp_Pty_Handle}, ", | |
316 | "a non-readable handle!\r\n"); | |
317 | } | |
318 | while ($write_handle = shift) { | |
319 | if ($write_handle->_get_mode() !~ 'w') { | |
320 | warn("Attempting to set a non-writeable listen handle ", | |
321 | "${*$write_handle}{exp_Pty_handle} for ", | |
322 | "${*$self}{exp_Pty_Handle}!\r\n"); | |
323 | } | |
324 | push (@{${*$self}{exp_Listen_Group}},$write_handle); | |
325 | } | |
326 | } | |
327 | ||
328 | sub log_file { | |
329 | my $self = shift; | |
330 | ||
331 | return(${*$self}{exp_Log_File}) | |
332 | if not @_; # we got no param, return filehandle | |
333 | ||
334 | my $file = shift; | |
335 | my $mode = shift || "a"; | |
336 | ||
337 | if (${*$self}{exp_Log_File} and ref(${*$self}{exp_Log_File}) ne 'CODE') { | |
338 | close(${*$self}{exp_Log_File}); | |
339 | ${*$self}{exp_Log_File} = undef; | |
340 | } | |
341 | return if (not $file); | |
342 | my $fh = $file; | |
343 | if (not ref($file)) { | |
344 | # it's a filename | |
345 | $fh = new IO::File $file, $mode | |
346 | or croak "Cannot open logfile $file: $!"; | |
347 | } | |
348 | if (ref($file) ne 'CODE') { | |
349 | croak "Given logfile doesn't have a 'print' method" | |
350 | if not $fh->can("print"); | |
351 | $fh->autoflush(1); # so logfile is up to date | |
352 | } | |
353 | ||
354 | ${*$self}{exp_Log_File} = $fh; | |
355 | } | |
356 | ||
357 | ||
358 | # I'm going to leave this here in case I might need to change something. | |
359 | # Previously this was calling `stty`, in a most bastardized manner. | |
360 | sub exp_stty { | |
361 | my($self) = shift; | |
362 | my($mode) = "@_"; | |
363 | ||
364 | return undef unless defined($mode); | |
365 | if (not defined $INC{"IO/Stty.pm"}) { | |
366 | carp "IO::Stty not installed, cannot change mode"; | |
367 | return undef; | |
368 | } | |
369 | ||
370 | if (${*$self}{"exp_Debug"}) { | |
371 | print STDERR "Setting ${*$self}{exp_Pty_Handle} to tty mode '$mode'\r\n"; | |
372 | } | |
373 | unless (POSIX::isatty($self)) { | |
374 | if (${*$self}{"exp_Debug"} or $^W) { | |
375 | warn "${*$self}{exp_Pty_Handle} is not a tty. Not changing mode"; | |
376 | } | |
377 | return ''; # No undef to avoid warnings elsewhere. | |
378 | } | |
379 | IO::Stty::stty($self, split(/\s/,$mode)); | |
380 | } | |
381 | ||
382 | *stty = \&exp_stty; | |
383 | ||
384 | # If we want to clear the buffer. Otherwise Accum will grow during send_slow | |
385 | # etc. and contain the remainder after matches. | |
386 | sub clear_accum { | |
387 | my ($self) = shift; | |
388 | my ($temp) = (${*$self}{exp_Accum}); | |
389 | ${*$self}{exp_Accum} = ''; | |
390 | # return the contents of the accumulator. | |
391 | return $temp; | |
392 | } | |
393 | ||
394 | sub set_accum { | |
395 | my ($self) = shift; | |
396 | my ($temp) = (${*$self}{exp_Accum}); | |
397 | ${*$self}{exp_Accum} = shift; | |
398 | # return the contents of the accumulator. | |
399 | return $temp; | |
400 | } | |
401 | ||
402 | ###################################################################### | |
403 | # define constants for pattern subs | |
404 | sub exp_continue() { "exp_continue" } | |
405 | sub exp_continue_timeout() { "exp_continue_timeout" } | |
406 | ||
407 | ###################################################################### | |
408 | # Expect on multiple objects at once. | |
409 | # | |
410 | # Call as Expect::expect($timeout, -i => \@exp_list, @patternlist, | |
411 | # -i => $exp, @pattern_list, ...); | |
412 | # or $exp->expect($timeout, @patternlist, -i => \@exp_list, @patternlist, | |
413 | # -i => $exp, @pattern_list, ...); | |
414 | # | |
415 | # Patterns are arrays that consist of | |
416 | # [ $pattern_type, $pattern, $sub, @subparms ] | |
417 | # | |
418 | # Optional $pattern_type is '-re' (RegExp, default) or '-ex' (exact); | |
419 | # | |
420 | # $sub is optional CODE ref, which is called as &{$sub}($exp, @subparms) | |
421 | # if pattern matched; may return exp_continue or exp_continue_timeout. | |
422 | # | |
423 | # Old-style syntax (pure pattern strings with optional type) also supported. | |
424 | # | |
425 | ||
426 | sub expect { | |
427 | my $self; | |
428 | $self = shift if (ref($_[0]) and $_[0]->isa('Expect')); | |
429 | shift if defined $_[0] and $_[0] eq 'Expect'; # or as Expect->expect | |
430 | my $timeout = shift; | |
431 | my $timeout_hook = undef; | |
432 | ||
433 | my @object_list; | |
434 | my %patterns; | |
435 | ||
436 | my @pattern_list; | |
437 | my @timeout_list; | |
438 | my $curr_list; | |
439 | ||
440 | if ($self) { | |
441 | $curr_list = [$self]; | |
442 | } else { | |
443 | # called directly, so first parameter must be '-i' to establish | |
444 | # object list. | |
445 | $curr_list = []; | |
446 | croak "expect(): ERROR: if called directly (not as \$obj->expect(...), but as Expect::expect(...), first parameter MUST be '-i' to set an object (list) for the patterns to work on." | |
447 | if ($_[0] ne '-i'); | |
448 | } | |
449 | # Let's make a list of patterns wanting to be evaled as regexps. | |
450 | my $parm; | |
451 | my $parm_nr = 1; | |
452 | while ($parm = shift) { | |
453 | if (ref($parm)) { | |
454 | if (ref($parm) eq 'ARRAY') { | |
455 | my $err = _add_patterns_to_list(\@pattern_list, \@timeout_list, | |
456 | $parm_nr, $parm); | |
457 | carp ("expect(): Warning: multiple `timeout' patterns (", | |
458 | scalar(@timeout_list), ").\r\n") | |
459 | if @timeout_list > 1; | |
460 | $timeout_hook = $timeout_list[-1] if $timeout_list[-1]; | |
461 | croak $err if $err; | |
462 | $parm_nr++; | |
463 | } else { | |
464 | croak ("expect(): Unknown pattern ref $parm"); | |
465 | } | |
466 | } else { | |
467 | # not a ref, is an option or raw pattern | |
468 | if (substr($parm, 0, 1) eq '-') { | |
469 | # it's an option | |
470 | if ($parm eq '-i') { | |
471 | # first add collected patterns to object list | |
472 | if (scalar(@$curr_list)) { | |
473 | push @object_list, $curr_list if not exists $patterns{"$curr_list"}; | |
474 | push @{$patterns{"$curr_list"}}, @pattern_list; | |
475 | @pattern_list = (); | |
476 | } | |
477 | # now put parm(s) into current object list | |
478 | if (ref($_[0]) eq 'ARRAY') { | |
479 | $curr_list = shift; | |
480 | } else { | |
481 | $curr_list = [ shift ]; | |
482 | } | |
483 | } elsif ($parm eq '-re' | |
484 | or $parm eq '-ex') { | |
485 | if (ref($_[1]) eq 'CODE') { | |
486 | push @pattern_list, [ $parm_nr, $parm, shift, shift ]; | |
487 | } else { | |
488 | push @pattern_list, [ $parm_nr, $parm, shift, undef ]; | |
489 | } | |
490 | $parm_nr++; | |
491 | } else { | |
492 | croak ("Unknown option $parm"); | |
493 | } | |
494 | } else { | |
495 | # a plain pattern, check if it is followed by a CODE ref | |
496 | if (ref($_[0]) eq 'CODE') { | |
497 | if ($parm eq 'timeout') { | |
498 | push @timeout_list, shift; | |
499 | carp ("expect(): Warning: multiple `timeout' patterns (", | |
500 | scalar(@timeout_list), ").\r\n") | |
501 | if @timeout_list > 1; | |
502 | $timeout_hook = $timeout_list[-1] if $timeout_list[-1]; | |
503 | } elsif ($parm eq 'eof') { | |
504 | push @pattern_list, [ $parm_nr, "-$parm", undef, shift ]; | |
505 | } else { | |
506 | push @pattern_list, [ $parm_nr, '-ex', $parm, shift ]; | |
507 | } | |
508 | } else { | |
509 | push @pattern_list, [ $parm_nr, '-ex', $parm, undef ]; | |
510 | } | |
511 | $parm_nr++; | |
512 | } | |
513 | } | |
514 | } | |
515 | ||
516 | # add rest of collected patterns to object list | |
517 | carp "expect(): Empty object list" unless $curr_list; | |
518 | push @object_list, $curr_list if not exists $patterns{"$curr_list"}; | |
519 | push @{$patterns{"$curr_list"}}, @pattern_list; | |
520 | ||
521 | my $debug = $self ? ${*$self}{exp_Debug} : $Expect::Debug; | |
522 | my $internal = $self ? ${*$self}{exp_Exp_Internal} : $Expect::Exp_Internal; | |
523 | ||
524 | # now start matching... | |
525 | ||
526 | if (@Expect::Before_List) { | |
527 | print STDERR ("Starting BEFORE pattern matching...\r\n") | |
528 | if ($debug or $internal); | |
529 | _multi_expect(0, undef, @Expect::Before_List); | |
530 | } | |
531 | ||
532 | cluck ("Starting EXPECT pattern matching...\r\n") | |
533 | if ($debug or $internal); | |
534 | my @ret; | |
535 | @ret = _multi_expect($timeout, $timeout_hook, | |
536 | map { [$_, @{$patterns{"$_"}}] } @object_list); | |
537 | ||
538 | if (@Expect::After_List) { | |
539 | print STDERR ("Starting AFTER pattern matching...\r\n") | |
540 | if ($debug or $internal); | |
541 | _multi_expect(0, undef, @Expect::After_List); | |
542 | } | |
543 | ||
544 | wantarray ? @ret : $ret[0]; | |
545 | } | |
546 | ||
547 | ###################################################################### | |
548 | # the real workhorse | |
549 | # | |
550 | sub _multi_expect($$@) { | |
551 | my $timeout = shift; | |
552 | my $timeout_hook = shift; | |
553 | ||
554 | if ($timeout_hook) { | |
555 | croak "Unknown timeout_hook type $timeout_hook" | |
556 | unless (ref($timeout_hook) eq 'CODE' | |
557 | or ref($timeout_hook) eq 'ARRAY'); | |
558 | } | |
559 | ||
560 | foreach my $pat (@_) { | |
561 | my @patterns = @{$pat}[1..$#{$pat}]; | |
562 | foreach my $exp (@{$pat->[0]}) { | |
563 | ${*$exp}{exp_New_Data} = 1; # first round we always try to match | |
564 | if (exists ${*$exp}{"exp_Max_Accum"} and ${*$exp}{"exp_Max_Accum"}) { | |
565 | ${*$exp}{exp_Accum} = | |
566 | $exp->_trim_length(${*$exp}{exp_Accum}, | |
567 | ${*$exp}{exp_Max_Accum}); | |
568 | } | |
569 | print STDERR ("${*$exp}{exp_Pty_Handle}: beginning expect.\r\n", | |
570 | "\tTimeout: ", | |
571 | (defined($timeout) ? $timeout : "unlimited" ), | |
572 | " seconds.\r\n", | |
573 | "\tCurrent time: ". localtime(). "\r\n", | |
574 | ) if $Expect::Debug; | |
575 | ||
576 | # What are we expecting? What do you expect? :-) | |
577 | if (${*$exp}{exp_Exp_Internal}) { | |
578 | print STDERR "${*$exp}{exp_Pty_Handle}: list of patterns:\r\n"; | |
579 | foreach my $pattern (@patterns) { | |
580 | print STDERR (' ', | |
581 | defined($pattern->[0])? | |
582 | '#'. $pattern->[0].': ' : | |
583 | '', | |
584 | $pattern->[1], | |
585 | " `", _make_readable($pattern->[2]), | |
586 | "'\r\n"); | |
587 | } | |
588 | print STDERR "\r\n"; | |
589 | } | |
590 | } | |
591 | } | |
592 | ||
593 | my $successful_pattern; | |
594 | my $exp_matched; | |
595 | my $err; | |
596 | my $before; | |
597 | my $after; | |
598 | my $match; | |
599 | my @matchlist; | |
600 | ||
601 | # Set the last loop time to now for time comparisons at end of loop. | |
602 | my $start_loop_time = time(); | |
603 | my $exp_cont = 1; | |
604 | ||
605 | READLOOP: | |
606 | while ($exp_cont) { | |
607 | $exp_cont = 1; | |
608 | $err = ""; | |
609 | my $rmask = ''; | |
610 | my $time_left = undef; | |
611 | if (defined $timeout) { | |
612 | $time_left = $timeout - (time() - $start_loop_time); | |
613 | $time_left = 0 if $time_left < 0; | |
614 | } | |
615 | ||
616 | $exp_matched = undef; | |
617 | # Test for a match first so we can test the current Accum w/out | |
618 | # worrying about an EOF. | |
619 | ||
620 | foreach my $pat (@_) { | |
621 | my @patterns = @{$pat}[1..$#{$pat}]; | |
622 | foreach my $exp (@{$pat->[0]}) { | |
623 | # build mask for select in next section... | |
624 | my $fn = $exp->fileno(); | |
625 | vec($rmask, $fn, 1) = 1 if defined $fn; | |
626 | ||
627 | next unless ${*$exp}{exp_New_Data}; | |
628 | ||
629 | # clear error status | |
630 | ${*$exp}{exp_Error} = undef; | |
631 | ||
632 | # This could be huge. We should attempt to do something | |
633 | # about this. Because the output is used for debugging | |
634 | # I'm of the opinion that showing smaller amounts if the | |
635 | # total is huge should be ok. | |
636 | # Thus the 'trim_length' | |
637 | print STDERR ("\r\n${*$exp}{exp_Pty_Handle}: Does `", | |
638 | $exp->_trim_length(_make_readable(${*$exp}{exp_Accum})), | |
639 | "'\r\nmatch:\r\n") | |
640 | if ${*$exp}{exp_Exp_Internal}; | |
641 | ||
642 | # we don't keep the parameter number anymore | |
643 | # (clashes with before & after), instead the parameter number is | |
644 | # stored inside the pattern; we keep the pattern ref | |
645 | # and look up the number later. | |
646 | foreach my $pattern (@patterns) { | |
647 | print STDERR (" pattern", | |
648 | defined($pattern->[0])? ' #' . $pattern->[0] : '', | |
649 | ": ", $pattern->[1], | |
650 | " `", _make_readable($pattern->[2]), | |
651 | "'? ") | |
652 | if (${*$exp}{exp_Exp_Internal}); | |
653 | ||
654 | # Matching exactly | |
655 | if ($pattern->[1] eq '-ex') { | |
656 | my $match_index = index(${*$exp}{exp_Accum}, | |
657 | $pattern->[2]); | |
658 | ||
659 | # We matched if $match_index > -1 | |
660 | if ($match_index > -1) { | |
661 | $before = substr(${*$exp}{exp_Accum}, 0, $match_index); | |
662 | $match = substr(${*$exp}{exp_Accum}, $match_index, | |
663 | length($pattern->[2])); | |
664 | $after = substr(${*$exp}{exp_Accum}, | |
665 | $match_index + length($pattern->[2])) ; | |
666 | ${*$exp}{exp_Before} = $before; | |
667 | ${*$exp}{exp_Match} = $match; | |
668 | ${*$exp}{exp_After} = $after; | |
669 | ${*$exp}{exp_Match_Number} = $pattern->[0]; | |
670 | $exp_matched = $exp; | |
671 | } | |
672 | } elsif ($pattern->[1] eq '-re') { | |
673 | # m// in array context promises to return an empty list | |
674 | # but doesn't if the pattern doesn't contain brackets (), | |
675 | # so we kludge around by adding an empty bracket | |
676 | # at the end. | |
677 | ||
678 | if ($Expect::Multiline_Matching) { | |
679 | @matchlist = (${*$exp}{exp_Accum} | |
680 | =~ m/$pattern->[2]()/m); | |
681 | ($match, $before, $after) = ($&, $`, $'); | |
682 | } else { | |
683 | @matchlist = (${*$exp}{exp_Accum} | |
684 | =~ m/$pattern->[2]()/); | |
685 | ($match, $before, $after) = ($&, $`, $'); | |
686 | } | |
687 | if (@matchlist) { | |
688 | # Matching regexp | |
689 | ${*$exp}{exp_Before} = $before; | |
690 | ${*$exp}{exp_Match} = $match; | |
691 | ${*$exp}{exp_After} = $after; | |
692 | pop @matchlist; # remove kludged empty bracket from end | |
693 | @{${*$exp}{exp_Matchlist}} = @matchlist; | |
694 | ${*$exp}{exp_Match_Number} = $pattern->[0]; | |
695 | $exp_matched = $exp; | |
696 | } | |
697 | } else { | |
698 | # 'timeout' or 'eof' | |
699 | } | |
700 | ||
701 | if ($exp_matched) { | |
702 | ${*$exp}{exp_Accum} = $after | |
703 | unless ${*$exp}{exp_NoTransfer}; | |
704 | print STDERR "YES!!\r\n" | |
705 | if ${*$exp}{exp_Exp_Internal}; | |
706 | print STDERR (" Before match string: `", | |
707 | $exp->_trim_length(_make_readable(($before))), | |
708 | "'\r\n", | |
709 | " Match string: `", _make_readable($match), | |
710 | "'\r\n", | |
711 | " After match string: `", | |
712 | $exp->_trim_length(_make_readable(($after))), | |
713 | "'\r\n", | |
714 | " Matchlist: (", | |
715 | join(", ", | |
716 | map("`" | |
717 | . $exp->_trim_length(_make_readable(($_))) | |
718 | . "'", | |
719 | @matchlist), | |
720 | ), | |
721 | ")\r\n", | |
722 | ) if (${*$exp}{exp_Exp_Internal}); | |
723 | ||
724 | # call hook function if defined | |
725 | if ($pattern->[3]) { | |
726 | print STDERR ("Calling hook $pattern->[3]...\r\n", | |
727 | ) if (${*$exp}{exp_Exp_Internal} or $Expect::Debug); | |
728 | if ($#{$pattern} > 3) { | |
729 | # call with parameters if given | |
730 | $exp_cont = &{$pattern->[3]}($exp, | |
731 | @{$pattern}[4..$#{$pattern}]); | |
732 | } else { | |
733 | $exp_cont = &{$pattern->[3]}($exp); | |
734 | } | |
735 | } | |
736 | if ($exp_cont and $exp_cont eq exp_continue) { | |
737 | print STDERR ("Continuing expect, restarting timeout...\r\n") | |
738 | if (${*$exp}{exp_Exp_Internal} or $Expect::Debug); | |
739 | $start_loop_time = time(); # restart timeout count | |
740 | next READLOOP; | |
741 | } elsif ($exp_cont and $exp_cont eq exp_continue_timeout) { | |
742 | print STDERR ("Continuing expect...\r\n") | |
743 | if (${*$exp}{exp_Exp_Internal} or $Expect::Debug); | |
744 | next READLOOP; | |
745 | } | |
746 | last READLOOP; | |
747 | } | |
748 | print STDERR "No.\r\n" if ${*$exp}{exp_Exp_Internal}; | |
749 | } | |
750 | print STDERR "\r\n" if ${*$exp}{exp_Exp_Internal}; | |
751 | # don't have to match again until we get new data | |
752 | ${*$exp}{exp_New_Data} = 0; | |
753 | } | |
754 | } # End of matching section | |
755 | ||
756 | # No match, let's see what is pending on the filehandles... | |
757 | print STDERR ("Waiting for new data (", | |
758 | defined($time_left)? $time_left : 'unlimited', | |
759 | " seconds)...\r\n", | |
760 | ) if ($Expect::Exp_Internal or $Expect::Debug); | |
761 | my $nfound = select($rmask, undef, undef, $time_left); | |
762 | ||
763 | # go until we don't find something (== timeout). | |
764 | if (not $nfound) { | |
765 | # No pattern, no EOF. Did we time out? | |
766 | $err = "1:TIMEOUT"; | |
767 | foreach my $pat (@_) { | |
768 | foreach my $exp (@{$pat->[0]}) { | |
769 | $before = ${*$exp}{exp_Before} = ${*$exp}{exp_Accum}; | |
770 | next if not defined $exp->fileno(); # skip already closed | |
771 | ${*$exp}{exp_Error} = $err unless ${*$exp}{exp_Error}; | |
772 | } | |
773 | } | |
774 | print STDERR ("TIMEOUT\r\n") | |
775 | if ($Expect::Debug or $Expect::Exp_Internal); | |
776 | if ($timeout_hook) { | |
777 | my $ret; | |
778 | print STDERR ("Calling timeout function $timeout_hook...\r\n") | |
779 | if ($Expect::Debug or $Expect::Exp_Internal); | |
780 | if (ref($timeout_hook) eq 'CODE') { | |
781 | $ret = &{$timeout_hook}($_[0]->[0]); | |
782 | } else { | |
783 | if ($#{$timeout_hook} > 3) { | |
784 | $ret = &{$timeout_hook->[3]}($_[0]->[0], | |
785 | @{$timeout_hook}[4..$#{$timeout_hook}]); | |
786 | } else { | |
787 | $ret = &{$timeout_hook->[3]}($_[0]->[0]); | |
788 | } | |
789 | } | |
790 | if ($ret and $ret eq exp_continue) { | |
791 | $start_loop_time = time(); # restart timeout count | |
792 | next READLOOP; | |
793 | } | |
794 | } | |
795 | last READLOOP; | |
796 | } | |
797 | ||
798 | my @bits = split(//,unpack('b*',$rmask)); | |
799 | foreach my $pat (@_) { | |
800 | foreach my $exp (@{$pat->[0]}) { | |
801 | next if not defined $exp->fileno(); # skip already closed | |
802 | if ($bits[$exp->fileno()]) { | |
803 | print STDERR ("${*$exp}{exp_Pty_Handle}: new data.\r\n") | |
804 | if $Expect::Debug; | |
805 | # read in what we found. | |
806 | my $buffer; | |
807 | my $nread = sysread($exp, $buffer, 2048); | |
808 | ||
809 | # Make errors (nread undef) show up as EOF. | |
810 | $nread = 0 unless defined ($nread); | |
811 | ||
812 | if ($nread == 0) { | |
813 | print STDERR ("${*$exp}{exp_Pty_Handle}: EOF\r\n") | |
814 | if ($Expect::Debug); | |
815 | $before = ${*$exp}{exp_Before} = $exp->clear_accum(); | |
816 | $err = "2:EOF"; | |
817 | ${*$exp}{exp_Error} = $err; | |
818 | ${*$exp}{exp_Has_EOF} = 1; | |
819 | $exp_cont = undef; | |
820 | foreach my $eof_pat (grep {$_->[1] eq '-eof'} @{$pat}[1..$#{$pat}]) { | |
821 | my $ret; | |
822 | print STDERR ("Calling EOF hook $eof_pat->[3]...\r\n", | |
823 | ) if ($Expect::Debug); | |
824 | if ($#{$eof_pat} > 3) { | |
825 | # call with parameters if given | |
826 | $ret = &{$eof_pat->[3]}($exp, | |
827 | @{$eof_pat}[4..$#{$eof_pat}]); | |
828 | } else { | |
829 | $ret = &{$eof_pat->[3]}($exp); | |
830 | } | |
831 | if ($ret and | |
832 | ($ret eq exp_continue | |
833 | or $ret eq exp_continue_timeout)) { | |
834 | $exp_cont = $ret; | |
835 | } | |
836 | } | |
837 | # is it dead? | |
838 | if (defined(${*$exp}{exp_Pid})) { | |
839 | my $ret = waitpid(${*$exp}{exp_Pid}, WNOHANG); | |
840 | if ($ret == ${*$exp}{exp_Pid}) { | |
841 | printf STDERR ("%s: exit(0x%02X)\r\n", | |
842 | ${*$exp}{exp_Pty_Handle}, $?) | |
843 | if ($Expect::Debug); | |
844 | $err = "3:Child PID ${*$exp}{exp_Pid} exited with status $?"; | |
845 | ${*$exp}{exp_Error} = $err; | |
846 | ${*$exp}{exp_Exit} = $?; | |
847 | delete $Expect::Spawned_PIDs{${*$exp}{exp_Pid}}; | |
848 | ${*$exp}{exp_Pid} = undef; | |
849 | } | |
850 | } | |
851 | print STDERR ("${*$exp}{exp_Pty_Handle}: closing...\r\n") | |
852 | if ($Expect::Debug); | |
853 | $exp->hard_close(); | |
854 | next; | |
855 | } | |
856 | print STDERR ("${*$exp}{exp_Pty_Handle}: read $nread byte(s).\r\n") | |
857 | if ($Expect::Debug); | |
858 | ||
859 | # ugly hack for broken solaris ttys that spew <blank><backspace> | |
860 | # into our pretty output | |
861 | $buffer =~ s/ \cH//g; | |
862 | # Append it to the accumulator. | |
863 | ${*$exp}{exp_Accum} .= $buffer; | |
864 | if (exists ${*$exp}{exp_Max_Accum} | |
865 | and ${*$exp}{exp_Max_Accum}) { | |
866 | ${*$exp}{exp_Accum} = | |
867 | $exp->_trim_length(${*$exp}{exp_Accum}, | |
868 | ${*$exp}{exp_Max_Accum}); | |
869 | } | |
870 | ${*$exp}{exp_New_Data} = 1; # next round we try to match again | |
871 | ||
872 | $exp_cont = exp_continue | |
873 | if (exists ${*$exp}{exp_Continue} and ${*$exp}{exp_Continue}); | |
874 | # Now propagate what we have read to other listeners... | |
875 | $exp->_print_handles($buffer); | |
876 | ||
877 | # End handle reading section. | |
878 | } | |
879 | } | |
880 | } # end read loop | |
881 | $start_loop_time = time() # restart timeout count | |
882 | if ($exp_cont and $exp_cont eq exp_continue); | |
883 | } | |
884 | # End READLOOP | |
885 | ||
886 | # Post loop. Do we have anything? | |
887 | # Tell us status | |
888 | if ($Expect::Debug or $Expect::Exp_Internal) { | |
889 | if ($exp_matched) { | |
890 | print STDERR ("Returning from expect ", | |
891 | ${*$exp_matched}{exp_Error} ? 'un' : '', | |
892 | "successfully.", | |
893 | ${*$exp_matched}{exp_Error} ? | |
894 | "\r\n Error: ${*$exp_matched}{exp_Error}." : '', | |
895 | "\r\n"); | |
896 | } else { | |
897 | print STDERR ("Returning from expect with TIMEOUT or EOF\r\n"); | |
898 | } | |
899 | if ($Expect::Debug and $exp_matched) { | |
900 | print STDERR " ${*$exp_matched}{exp_Pty_Handle}: accumulator: `"; | |
901 | if (${*$exp_matched}{exp_Error}) { | |
902 | print STDERR ($exp_matched->_trim_length | |
903 | (_make_readable(${*$exp_matched}{exp_Before})), | |
904 | "'\r\n"); | |
905 | } else { | |
906 | print STDERR ($exp_matched->_trim_length | |
907 | (_make_readable(${*$exp_matched}{exp_Accum})), | |
908 | "'\r\n"); | |
909 | } | |
910 | } | |
911 | } | |
912 | ||
913 | if ($exp_matched) { | |
914 | return wantarray? | |
915 | (${*$exp_matched}{exp_Match_Number}, | |
916 | ${*$exp_matched}{exp_Error}, | |
917 | ${*$exp_matched}{exp_Match}, | |
918 | ${*$exp_matched}{exp_Before}, | |
919 | ${*$exp_matched}{exp_After}, | |
920 | $exp_matched, | |
921 | ) : | |
922 | ${*$exp_matched}{exp_Match_Number}; | |
923 | } | |
924 | ||
925 | return wantarray? (undef, $err, undef, $before, undef, undef) : undef; | |
926 | } | |
927 | ||
928 | ||
929 | # Patterns are arrays that consist of | |
930 | # [ $pattern_type, $pattern, $sub, @subparms ] | |
931 | # optional $pattern_type is '-re' (RegExp, default) or '-ex' (exact); | |
932 | # $sub is optional CODE ref, which is called as &{$sub}($exp, @subparms) | |
933 | # if pattern matched; | |
934 | # the $parm_nr gets unshifted onto the array for reporting purposes. | |
935 | ||
936 | sub _add_patterns_to_list($$$@) { | |
937 | my $listref = shift; | |
938 | my $timeoutlistref = shift; # gets timeout patterns | |
939 | my $store_parm_nr = shift; | |
940 | my $parm_nr = $store_parm_nr || 1; | |
941 | foreach my $parm (@_) { | |
942 | if (not ref($parm) eq 'ARRAY') { | |
943 | return "Parameter #$parm_nr is not an ARRAY ref."; | |
944 | } | |
945 | $parm = [@$parm]; # make copy | |
946 | if ($parm->[0] =~ m/\A-/) { | |
947 | # it's an option | |
948 | if ($parm->[0] ne '-re' | |
949 | and $parm->[0] ne '-ex') { | |
950 | return "Unknown option $parm->[0] in pattern #$parm_nr"; | |
951 | } | |
952 | } else { | |
953 | if ($parm->[0] eq 'timeout') { | |
954 | if (defined $timeoutlistref) { | |
955 | splice @$parm, 0, 1, ("-$parm->[0]", undef); | |
956 | unshift @$parm, $store_parm_nr? $parm_nr: undef; | |
957 | push @$timeoutlistref, $parm; | |
958 | } | |
959 | next; | |
960 | } elsif ($parm->[0] eq 'eof') { | |
961 | splice @$parm, 0, 1, ("-$parm->[0]", undef); | |
962 | } else { | |
963 | unshift @$parm, '-re'; # defaults to RegExp | |
964 | } | |
965 | } | |
966 | if (@$parm > 2) { | |
967 | if (ref($parm->[2]) ne 'CODE') { | |
968 | croak ("Pattern #$parm_nr doesn't have a CODE reference", | |
969 | "after the pattern."); | |
970 | } | |
971 | } else { | |
972 | push @$parm, undef; # make sure we have three elements | |
973 | } | |
974 | ||
975 | unshift @$parm, $store_parm_nr? $parm_nr: undef; | |
976 | push @$listref, $parm; | |
977 | $parm_nr++ | |
978 | } | |
979 | return undef; | |
980 | } | |
981 | ||
982 | ###################################################################### | |
983 | # $process->interact([$in_handle],[$escape sequence]) | |
984 | # If you don't specify in_handle STDIN will be used. | |
985 | sub interact { | |
986 | my ($self) = (shift); | |
987 | my ($infile) = (shift); | |
988 | my ($escape_sequence) = shift; | |
989 | my ($in_object,$in_handle,@old_group,$return_value); | |
990 | my ($old_manual_stty_val,$old_log_stdout_val); | |
991 | my ($outfile,$out_object); | |
992 | @old_group = $self->set_group(); | |
993 | # If the handle is STDIN we'll | |
994 | # $infile->fileno == 0 should be stdin.. follow stdin rules. | |
995 | no strict 'subs'; # Allow bare word 'STDIN' | |
996 | unless (defined($infile)) { | |
997 | # We need a handle object Associated with STDIN. | |
998 | $infile = new IO::File; | |
999 | $infile->IO::File::fdopen(STDIN,'r'); | |
1000 | $outfile = new IO::File; | |
1001 | $outfile->IO::File::fdopen(STDOUT,'w'); | |
1002 | } elsif (fileno($infile) == fileno(STDIN)) { | |
1003 | # With STDIN we want output to go to stdout. | |
1004 | $outfile = new IO::File; | |
1005 | $outfile->IO::File::fdopen(STDOUT,'w'); | |
1006 | } else { | |
1007 | undef ($outfile); | |
1008 | } | |
1009 | # Here we assure ourselves we have an Expect object. | |
1010 | $in_object = Expect->exp_init($infile); | |
1011 | if (defined($outfile)) { | |
1012 | # as above.. we want output to go to stdout if we're given stdin. | |
1013 | $out_object = Expect->exp_init($outfile); | |
1014 | $out_object->manual_stty(1); | |
1015 | $self->set_group($out_object); | |
1016 | } else { | |
1017 | $self->set_group($in_object); | |
1018 | } | |
1019 | $in_object->set_group($self); | |
1020 | $in_object->set_seq($escape_sequence,undef) if defined($escape_sequence); | |
1021 | # interconnect normally sets stty -echo raw. Interact really sort | |
1022 | # of implies we don't do that by default. If anyone wanted to they could | |
1023 | # set it before calling interact, of use interconnect directly. | |
1024 | $old_manual_stty_val = $self->manual_stty(); | |
1025 | $self->manual_stty(1); | |
1026 | # I think this is right. Don't send stuff from in_obj to stdout by default. | |
1027 | # in theory whatever 'self' is should echo what's going on. | |
1028 | $old_log_stdout_val = $self->log_stdout(); | |
1029 | $self->log_stdout(0); | |
1030 | $in_object->log_stdout(0); | |
1031 | # Allow for the setting of an optional EOF escape function. | |
1032 | # $in_object->set_seq('EOF',undef); | |
1033 | # $self->set_seq('EOF',undef); | |
1034 | Expect::interconnect($self,$in_object); | |
1035 | $self->log_stdout($old_log_stdout_val); | |
1036 | $self->set_group(@old_group); | |
1037 | # If old_group was undef, make sure that occurs. This is a slight hack since | |
1038 | # it modifies the value directly. | |
1039 | # Normally an undef passed to set_group will return the current groups. | |
1040 | # It is possible that it may be of worth to make it possible to undef | |
1041 | # The current group without doing this. | |
1042 | unless (@old_group) { | |
1043 | @{${*$self}{exp_Listen_Group}} = (); | |
1044 | } | |
1045 | $self->manual_stty($old_manual_stty_val); | |
1046 | return $return_value; | |
1047 | } | |
1048 | ||
1049 | sub interconnect { | |
1050 | ||
1051 | # my ($handle)=(shift); call as Expect::interconnect($spawn1,$spawn2,...) | |
1052 | my ($rmask,$nfound,$nread); | |
1053 | my ($rout, @bits, $emask, $eout, @ebits ) = (); | |
1054 | my ($escape_sequence,$escape_character_buffer); | |
1055 | my (@handles) = @_; | |
1056 | my ($handle,$read_handle,$write_handle); | |
1057 | my ($read_mask,$temp_mask) = ('',''); | |
1058 | ||
1059 | # Get read/write handles | |
1060 | foreach $handle(@handles) { | |
1061 | $temp_mask = ''; | |
1062 | vec($temp_mask,$handle->fileno(),1) = 1; | |
1063 | # Under Linux w/ 5.001 the next line comes up w/ 'Uninit var.'. | |
1064 | # It appears to be impossible to make the warning go away. | |
1065 | # doing something like $temp_mask='' unless defined ($temp_mask) | |
1066 | # has no effect whatsoever. This may be a bug in 5.001. | |
1067 | $read_mask = $read_mask | $temp_mask; | |
1068 | } | |
1069 | if ($Expect::Debug) { | |
1070 | print STDERR "Read handles:\r\n"; | |
1071 | foreach $handle(@handles) { | |
1072 | print STDERR "\tRead handle: "; | |
1073 | print STDERR "'${*$handle}{exp_Pty_Handle}'\r\n"; | |
1074 | print STDERR "\t\tListen Handles:"; | |
1075 | foreach $write_handle(@{${*$handle}{exp_Listen_Group}}) { | |
1076 | print STDERR " '${*$write_handle}{exp_Pty_Handle}'"; | |
1077 | } | |
1078 | print STDERR ".\r\n"; | |
1079 | } | |
1080 | } | |
1081 | ||
1082 | # I think if we don't set raw/-echo here we may have trouble. We don't | |
1083 | # want a bunch of echoing crap making all the handles jabber at each other. | |
1084 | foreach $handle(@handles) { | |
1085 | unless (${*$handle}{"exp_Manual_Stty"}) { | |
1086 | # This is probably O/S specific. | |
1087 | ${*$handle}{exp_Stored_Stty} = $handle->exp_stty('-g'); | |
1088 | print STDERR "Setting tty for ${*$handle}{exp_Pty_Handle} to 'raw -echo'.\r\n"if ${*$handle}{"exp_Debug"}; | |
1089 | $handle->exp_stty("raw -echo"); | |
1090 | } | |
1091 | foreach $write_handle (@{${*$handle}{exp_Listen_Group}}) { | |
1092 | unless (${*$write_handle}{"exp_Manual_Stty"}) { | |
1093 | ${*$write_handle}{exp_Stored_Stty} = $write_handle->exp_stty('-g'); | |
1094 | print STDERR "Setting ${*$write_handle}{exp_Pty_Handle} to 'raw -echo'.\r\n"if ${*$handle}{"exp_Debug"}; | |
1095 | $write_handle->exp_stty("raw -echo"); | |
1096 | } | |
1097 | } | |
1098 | } | |
1099 | ||
1100 | print STDERR "Attempting interconnection\r\n" if $Expect::Debug; | |
1101 | ||
1102 | # Wait until the process dies or we get EOF | |
1103 | # In the case of !${*$handle}{exp_Pid} it means | |
1104 | # the handle was exp_inited instead of spawned. | |
1105 | CONNECT_LOOP: | |
1106 | # Go until we have a reason to stop | |
1107 | while (1) { | |
1108 | # test each handle to see if it's still alive. | |
1109 | foreach $read_handle (@handles) { | |
1110 | waitpid(${*$read_handle}{exp_Pid}, WNOHANG) | |
1111 | if (exists (${*$read_handle}{exp_Pid}) and ${*$read_handle}{exp_Pid}); | |
1112 | if (exists(${*$read_handle}{exp_Pid}) | |
1113 | and (${*$read_handle}{exp_Pid}) | |
1114 | and (! kill(0,${*$read_handle}{exp_Pid}))) { | |
1115 | print STDERR "Got EOF (${*$read_handle}{exp_Pty_Handle} died) reading ${*$read_handle}{exp_Pty_Handle}\r\n" | |
1116 | if ${*$read_handle}{"exp_Debug"}; | |
1117 | last CONNECT_LOOP unless defined(${${*$read_handle}{exp_Function}}{"EOF"}); | |
1118 | last CONNECT_LOOP unless &{${${*$read_handle}{exp_Function}}{"EOF"}}(@{${${*$read_handle}{exp_Parameters}}{"EOF"}}); | |
1119 | } | |
1120 | } | |
1121 | ||
1122 | # Every second? No, go until we get something from someone. | |
1123 | ($nfound) = select($rout = $read_mask, undef, $eout = $emask, undef); | |
1124 | # Is there anything to share? May be -1 if interrupted by a signal... | |
1125 | next CONNECT_LOOP if not defined $nfound or $nfound < 1; | |
1126 | # Which handles have stuff? | |
1127 | @bits = split(//,unpack('b*',$rout)); | |
1128 | $eout = 0 unless defined ($eout); | |
1129 | @ebits = split(//,unpack('b*',$eout)); | |
1130 | # print "Ebits: $eout\r\n"; | |
1131 | foreach $read_handle(@handles) { | |
1132 | if ($bits[$read_handle->fileno()]) { | |
1133 | $nread = sysread( $read_handle, ${*$read_handle}{exp_Pty_Buffer}, 1024 ); | |
1134 | # Appease perl -w | |
1135 | $nread = 0 unless defined ($nread); | |
1136 | print STDERR "interconnect: read $nread byte(s) from ${*$read_handle}{exp_Pty_Handle}.\r\n" if ${*$read_handle}{"exp_Debug"} > 1; | |
1137 | # Test for escape seq. before printing. | |
1138 | # Appease perl -w | |
1139 | $escape_character_buffer = '' unless defined ($escape_character_buffer); | |
1140 | $escape_character_buffer .= ${*$read_handle}{exp_Pty_Buffer}; | |
1141 | foreach $escape_sequence (keys(%{${*$read_handle}{exp_Function}})) { | |
1142 | print STDERR "Tested escape sequence $escape_sequence from ${*$read_handle}{exp_Pty_Handle}"if ${*$read_handle}{"exp_Debug"} > 1; | |
1143 | # Make sure it doesn't grow out of bounds. | |
1144 | $escape_character_buffer = $read_handle->_trim_length($escape_character_buffer,${*$read_handle}{"exp_Max_Accum"}) if (${*$read_handle}{"exp_Max_Accum"}); | |
1145 | if ($escape_character_buffer =~ /($escape_sequence)/) { | |
1146 | if (${*$read_handle}{"exp_Debug"}) { | |
1147 | print STDERR "\r\ninterconnect got escape sequence from ${*$read_handle}{exp_Pty_Handle}.\r\n"; | |
1148 | # I'm going to make the esc. seq. pretty because it will | |
1149 | # probably contain unprintable characters. | |
1150 | print STDERR "\tEscape Sequence: '"._trim_length(undef,_make_readable($escape_sequence))."'\r\n"; | |
1151 | print STDERR "\tMatched by string: '"._trim_length(undef,_make_readable($&))."'\r\n"; | |
1152 | } | |
1153 | # Print out stuff before the escape. | |
1154 | # Keep in mind that the sequence may have been split up | |
1155 | # over several reads. | |
1156 | # Let's get rid of it from this read. If part of it was | |
1157 | # in the last read there's not a lot we can do about it now. | |
1158 | if (${*$read_handle}{exp_Pty_Buffer} =~ /($escape_sequence)/) { | |
1159 | $read_handle->_print_handles($`); | |
1160 | } else { | |
1161 | $read_handle->_print_handles(${*$read_handle}{exp_Pty_Buffer}) | |
1162 | } | |
1163 | # Clear the buffer so no more matches can be made and it will | |
1164 | # only be printed one time. | |
1165 | ${*$read_handle}{exp_Pty_Buffer} = ''; | |
1166 | $escape_character_buffer = ''; | |
1167 | # Do the function here. Must return non-zero to continue. | |
1168 | # More cool syntax. Maybe I should turn these in to objects. | |
1169 | last CONNECT_LOOP unless &{${${*$read_handle}{exp_Function}}{$escape_sequence}}(@{${${*$read_handle}{exp_Parameters}}{$escape_sequence}}); | |
1170 | } | |
1171 | } | |
1172 | $nread = 0 unless defined($nread); # Appease perl -w? | |
1173 | waitpid(${*$read_handle}{exp_Pid}, WNOHANG) if (defined (${*$read_handle}{exp_Pid}) &&${*$read_handle}{exp_Pid}); | |
1174 | if ($nread == 0) { | |
1175 | print STDERR "Got EOF reading ${*$read_handle}{exp_Pty_Handle}\r\n"if ${*$read_handle}{"exp_Debug"}; | |
1176 | last CONNECT_LOOP unless defined(${${*$read_handle}{exp_Function}}{"EOF"}); | |
1177 | last CONNECT_LOOP unless &{${${*$read_handle}{exp_Function}}{"EOF"}}(@{${${*$read_handle}{exp_Parameters}}{"EOF"}}); | |
1178 | } | |
1179 | last CONNECT_LOOP if ($nread < 0); # This would be an error | |
1180 | $read_handle->_print_handles(${*$read_handle}{exp_Pty_Buffer}); | |
1181 | } | |
1182 | # I'm removing this because I haven't determined what causes exceptions | |
1183 | # consistently. | |
1184 | if (0) #$ebits[$read_handle->fileno()]) | |
1185 | { | |
1186 | print STDERR "Got Exception reading ${*$read_handle}{exp_Pty_Handle}\r\n"if ${*$read_handle}{"exp_Debug"}; | |
1187 | last CONNECT_LOOP unless defined(${${*$read_handle}{exp_Function}}{"EOF"}); | |
1188 | last CONNECT_LOOP unless &{${${*$read_handle}{exp_Function}}{"EOF"}}(@{${${*$read_handle}{exp_Parameters}}{"EOF"}}); | |
1189 | } | |
1190 | } | |
1191 | } | |
1192 | foreach $handle(@handles) { | |
1193 | unless (${*$handle}{"exp_Manual_Stty"}) { | |
1194 | $handle->exp_stty(${*$handle}{exp_Stored_Stty}); | |
1195 | } | |
1196 | foreach $write_handle (@{${*$handle}{exp_Listen_Group}}) { | |
1197 | unless (${*$write_handle}{"exp_Manual_Stty"}) { | |
1198 | $write_handle->exp_stty(${*$write_handle}{exp_Stored_Stty}); | |
1199 | } | |
1200 | } | |
1201 | } | |
1202 | } | |
1203 | ||
1204 | # user can decide if log output gets also sent to logfile | |
1205 | sub print_log_file { | |
1206 | my $self = shift; | |
1207 | if (${*$self}{exp_Log_File}) { | |
1208 | if (ref(${*$self}{exp_Log_File}) eq 'CODE') { | |
1209 | ${*$self}{exp_Log_File}->(@_); | |
1210 | } else { | |
1211 | ${*$self}{exp_Log_File}->print(@_); | |
1212 | } | |
1213 | } | |
1214 | } | |
1215 | ||
1216 | # we provide our own print so we can debug what gets sent to the | |
1217 | # processes... | |
1218 | sub print (@) { | |
1219 | my ($self, @args) = @_; | |
1220 | if (${*$self}{exp_Exp_Internal}) { | |
1221 | my $args = _make_readable(join('', @args)); | |
1222 | cluck "Sending '$args' to ${*$self}{exp_Pty_Handle}\r\n"; | |
1223 | } | |
1224 | foreach my $arg (@args) { | |
1225 | while (length($arg) > 80) { | |
1226 | $self->SUPER::print(substr($arg, 0, 80)); | |
1227 | $arg = substr($arg, 80); | |
1228 | } | |
1229 | $self->SUPER::print($arg); | |
1230 | } | |
1231 | } | |
1232 | ||
1233 | # make an alias for Tcl/Expect users for a DWIM experience... | |
1234 | *send = \&print; | |
1235 | ||
1236 | # This is an Expect standard. It's nice for talking to modems and the like | |
1237 | # where from time to time they get unhappy if you send items too quickly. | |
1238 | sub send_slow{ | |
1239 | my ($self) = shift; | |
1240 | my($char,@linechars,$nfound,$rmask); | |
1241 | my($sleep_time) = shift; | |
1242 | # Flushing makes it so each character can be seen separately. | |
1243 | while ($_=shift) { | |
1244 | @linechars = split (''); | |
1245 | foreach $char (@linechars) { | |
1246 | # How slow? | |
1247 | select (undef,undef,undef,$sleep_time); | |
1248 | ||
1249 | print $self $char; | |
1250 | print STDERR "Printed character \'"._make_readable($char)."\' to ${*$self}{exp_Pty_Handle}.\r\n" if ${*$self}{"exp_Debug"} > 1; | |
1251 | # I think I can get away with this if I save it in accum | |
1252 | if (${*$self}{"exp_Log_Stdout"} ||${*$self}{exp_Log_Group}) { | |
1253 | $rmask = ""; | |
1254 | vec($rmask,$self->fileno(),1) = 1; | |
1255 | # .01 sec granularity should work. If we miss something it will | |
1256 | # probably get flushed later, maybe in an expect call. | |
1257 | while (select($rmask,undef,undef,.01)) { | |
1258 | sysread($self,${*$self}{exp_Pty_Buffer},1024); | |
1259 | # Is this necessary to keep? Probably.. # | |
1260 | # if you need to expect it later. | |
1261 | ${*$self}{exp_Accum}.= ${*$self}{exp_Pty_Buffer}; | |
1262 | ${*$self}{exp_Accum} = $self->_trim_length(${*$self}{exp_Accum},${*$self}{"exp_Max_Accum"}) if (${*$self}{"exp_Max_Accum"}); | |
1263 | $self->_print_handles(${*$self}{exp_Pty_Buffer}); | |
1264 | print STDERR "Received \'".$self->_trim_length(_make_readable($char))."\' from ${*$self}{exp_Pty_Handle}\r\n" if ${*$self}{"exp_Debug"} > 1; | |
1265 | } | |
1266 | } | |
1267 | } | |
1268 | } | |
1269 | } | |
1270 | ||
1271 | sub test_handles { | |
1272 | # This should be called by Expect::test_handles($timeout,@objects); | |
1273 | my ($rmask, $allmask, $rout, $nfound, @bits); | |
1274 | my ($timeout) = shift; | |
1275 | my (@handle_list) = @_; | |
1276 | my($handle); | |
1277 | foreach $handle (@handle_list) { | |
1278 | $rmask = ''; | |
1279 | vec($rmask,$handle->fileno(),1) = 1; | |
1280 | $allmask = '' unless defined ($allmask); | |
1281 | $allmask = $allmask | $rmask; | |
1282 | } | |
1283 | ($nfound) = select($rout = $allmask, undef, undef, $timeout); | |
1284 | return () unless $nfound; | |
1285 | # Which handles have stuff? | |
1286 | @bits = split(//,unpack('b*',$rout)); | |
1287 | ||
1288 | my $handle_num = 0; | |
1289 | my @return_list = (); | |
1290 | foreach $handle (@handle_list) { | |
1291 | # I go to great lengths to get perl -w to shut the hell up. | |
1292 | if (defined($bits[$handle->fileno()]) and ($bits[$handle->fileno()])) { | |
1293 | push(@return_list,$handle_num); | |
1294 | } | |
1295 | } continue { | |
1296 | $handle_num++; | |
1297 | } | |
1298 | return (@return_list); | |
1299 | } | |
1300 | ||
1301 | # Be nice close. This should emulate what an interactive shell does after a | |
1302 | # command finishes... sort of. We're not as patient as a shell. | |
1303 | sub soft_close { | |
1304 | my($self) = shift; | |
1305 | my($nfound,$nread,$rmask,$returned_pid); | |
1306 | my($end_time,$select_time,$temp_buffer); | |
1307 | my($close_status); | |
1308 | # Give it 15 seconds to cough up an eof. | |
1309 | cluck "Closing ${*$self}{exp_Pty_Handle}.\r\n" if ${*$self}{exp_Debug}; | |
1310 | return -1 if not defined $self->fileno(); # skip if handle already closed | |
1311 | unless (exists ${*$self}{exp_Has_EOF} and ${*$self}{exp_Has_EOF}) { | |
1312 | $end_time = time() + 15; | |
1313 | while ($end_time > time()) { | |
1314 | $select_time = $end_time - time(); | |
1315 | # Sanity check. | |
1316 | $select_time = 0 if $select_time < 0; | |
1317 | $rmask = ''; | |
1318 | vec($rmask,$self->fileno(),1) = 1; | |
1319 | ($nfound) = select($rmask,undef,undef,$select_time); | |
1320 | last unless (defined($nfound) && $nfound); | |
1321 | $nread = sysread($self,$temp_buffer,8096); | |
1322 | # 0 = EOF. | |
1323 | unless (defined($nread) && $nread) { | |
1324 | print STDERR "Got EOF from ${*$self}{exp_Pty_Handle}.\r\n" if ${*$self}{exp_Debug}; | |
1325 | last; | |
1326 | } | |
1327 | $self->_print_handles($temp_buffer); | |
1328 | } | |
1329 | if (($end_time <= time()) && ${*$self}{exp_Debug}) { | |
1330 | print STDERR "Timed out waiting for an EOF from ${*$self}{exp_Pty_Handle}.\r\n"; | |
1331 | } | |
1332 | } | |
1333 | if ( ($close_status = $self->close()) && ${*$self}{exp_Debug}) { | |
1334 | print STDERR "${*$self}{exp_Pty_Handle} closed.\r\n"; | |
1335 | } | |
1336 | # quit now if it isn't a process. | |
1337 | return $close_status unless defined(${*$self}{exp_Pid}); | |
1338 | # Now give it 15 seconds to die. | |
1339 | $end_time = time() + 15; | |
1340 | while ($end_time > time()) { | |
1341 | $returned_pid = waitpid(${*$self}{exp_Pid}, &WNOHANG); | |
1342 | # Stop here if the process dies. | |
1343 | if (defined($returned_pid) && $returned_pid) { | |
1344 | delete $Expect::Spawned_PIDs{$returned_pid}; | |
1345 | if (${*$self}{exp_Debug}) { | |
1346 | printf STDERR ("Pid %d of %s exited, Status: 0x%02X\r\n", | |
1347 | ${*$self}{exp_Pid}, ${*$self}{exp_Pty_Handle}, $?); | |
1348 | } | |
1349 | ${*$self}{exp_Pid} = undef; | |
1350 | ${*$self}{exp_Exit} = $?; | |
1351 | return ${*$self}{exp_Exit}; | |
1352 | } | |
1353 | sleep 1; # Keep loop nice. | |
1354 | } | |
1355 | # Send it a term if it isn't dead. | |
1356 | if (${*$self}{exp_Debug}) { | |
1357 | print STDERR "${*$self}{exp_Pty_Handle} not exiting, sending TERM.\r\n"; | |
1358 | } | |
1359 | kill TERM => ${*$self}{exp_Pid}; | |
1360 | # Now to be anal retentive.. wait 15 more seconds for it to die. | |
1361 | $end_time = time() + 15; | |
1362 | while ($end_time > time()) { | |
1363 | $returned_pid = waitpid(${*$self}{exp_Pid}, &WNOHANG); | |
1364 | if (defined($returned_pid) && $returned_pid) { | |
1365 | delete $Expect::Spawned_PIDs{$returned_pid}; | |
1366 | if (${*$self}{exp_Debug}) { | |
1367 | printf STDERR ("Pid %d of %s terminated, Status: 0x%02X\r\n", | |
1368 | ${*$self}{exp_Pid}, ${*$self}{exp_Pty_Handle}, $?); | |
1369 | } | |
1370 | ${*$self}{exp_Pid} = undef; | |
1371 | ${*$self}{exp_Exit} = $?; | |
1372 | return $?; | |
1373 | } | |
1374 | sleep 1; | |
1375 | } | |
1376 | # Since this is a 'soft' close, sending it a -9 would be inappropriate. | |
1377 | return undef; | |
1378 | } | |
1379 | ||
1380 | # 'Make it go away' close. | |
1381 | sub hard_close { | |
1382 | my($self) = shift; | |
1383 | my($nfound,$nread,$rmask,$returned_pid); | |
1384 | my($end_time,$select_time,$temp_buffer); | |
1385 | my($close_status); | |
1386 | cluck "Closing ${*$self}{exp_Pty_Handle}.\r\n" if ${*$self}{exp_Debug}; | |
1387 | # Don't wait for an EOF. | |
1388 | if ( ($close_status = $self->close()) && ${*$self}{exp_Debug}) { | |
1389 | print STDERR "${*$self}{exp_Pty_Handle} closed.\r\n"; | |
1390 | } | |
1391 | # Return now if handle. | |
1392 | return $close_status unless defined(${*$self}{exp_Pid}); | |
1393 | # Now give it 5 seconds to die. Less patience here if it won't die. | |
1394 | $end_time = time() + 5; | |
1395 | while ($end_time > time()) { | |
1396 | $returned_pid = waitpid(${*$self}{exp_Pid}, &WNOHANG); | |
1397 | # Stop here if the process dies. | |
1398 | if (defined($returned_pid) && $returned_pid) { | |
1399 | delete $Expect::Spawned_PIDs{$returned_pid}; | |
1400 | if (${*$self}{exp_Debug}) { | |
1401 | printf STDERR ("Pid %d of %s terminated, Status: 0x%02X\r\n", | |
1402 | ${*$self}{exp_Pid}, ${*$self}{exp_Pty_Handle}, $?); | |
1403 | } | |
1404 | ${*$self}{exp_Pid} = undef; | |
1405 | ${*$self}{exp_Exit} = $?; | |
1406 | return ${*$self}{exp_Exit}; | |
1407 | } | |
1408 | sleep 1; # Keep loop nice. | |
1409 | } | |
1410 | # Send it a term if it isn't dead. | |
1411 | if (${*$self}{exp_Debug}) { | |
1412 | print STDERR "${*$self}{exp_Pty_Handle} not exiting, sending TERM.\r\n"; | |
1413 | } | |
1414 | kill TERM => ${*$self}{exp_Pid}; | |
1415 | # wait 15 more seconds for it to die. | |
1416 | $end_time = time() + 15; | |
1417 | while ($end_time > time()) { | |
1418 | $returned_pid = waitpid(${*$self}{exp_Pid}, &WNOHANG); | |
1419 | if (defined($returned_pid) && $returned_pid) { | |
1420 | delete $Expect::Spawned_PIDs{$returned_pid}; | |
1421 | if (${*$self}{exp_Debug}) { | |
1422 | printf STDERR ("Pid %d of %s terminated, Status: 0x%02X\r\n", | |
1423 | ${*$self}{exp_Pid}, ${*$self}{exp_Pty_Handle}, $?); | |
1424 | } | |
1425 | ${*$self}{exp_Pid} = undef; | |
1426 | ${*$self}{exp_Exit} = $?; | |
1427 | return ${*$self}{exp_Exit}; | |
1428 | } | |
1429 | sleep 1; | |
1430 | } | |
1431 | kill KILL => ${*$self}{exp_Pid}; | |
1432 | # wait 5 more seconds for it to die. | |
1433 | $end_time = time() + 5; | |
1434 | while ($end_time > time()) { | |
1435 | $returned_pid = waitpid(${*$self}{exp_Pid}, &WNOHANG); | |
1436 | if (defined($returned_pid) && $returned_pid) { | |
1437 | delete $Expect::Spawned_PIDs{$returned_pid}; | |
1438 | if (${*$self}{exp_Debug}) { | |
1439 | printf STDERR ("Pid %d of %s killed, Status: 0x%02X\r\n", | |
1440 | ${*$self}{exp_Pid}, ${*$self}{exp_Pty_Handle}, $?); | |
1441 | } | |
1442 | ${*$self}{exp_Pid} = undef; | |
1443 | ${*$self}{exp_Exit} = $?; | |
1444 | return ${*$self}{exp_Exit}; | |
1445 | } | |
1446 | sleep 1; | |
1447 | } | |
1448 | warn "Pid ${*$self}{exp_Pid} of ${*$self}{exp_Pty_Handle} is HUNG.\r\n"; | |
1449 | ${*$self}{exp_Pid} = undef; | |
1450 | return undef; | |
1451 | } | |
1452 | ||
1453 | # These should not be called externally. | |
1454 | ||
1455 | sub _init_vars { | |
1456 | my($self) = shift; | |
1457 | ||
1458 | # for every spawned process or filehandle. | |
1459 | ${*$self}{exp_Log_Stdout} = $Expect::Log_Stdout | |
1460 | if defined ($Expect::Log_Stdout); | |
1461 | ${*$self}{exp_Log_Group} = $Expect::Log_Group; | |
1462 | ${*$self}{exp_Debug} = $Expect::Debug; | |
1463 | ${*$self}{exp_Exp_Internal} = $Expect::Exp_Internal; | |
1464 | ${*$self}{exp_Manual_Stty} = $Expect::Manual_Stty; | |
1465 | ${*$self}{exp_Stored_Stty} = 'sane'; | |
1466 | ${*$self}{exp_Do_Soft_Close} = $Expect::Do_Soft_Close; | |
1467 | ||
1468 | # sysread doesn't like my or local vars. | |
1469 | ${*$self}{exp_Pty_Buffer} = ''; | |
1470 | ||
1471 | # Initialize accumulator. | |
1472 | ${*$self}{exp_Max_Accum} = $Expect::Exp_Max_Accum; | |
1473 | ${*$self}{exp_Accum} = ''; | |
1474 | ${*$self}{exp_NoTransfer} = 0; | |
1475 | ||
1476 | # create empty expect_before & after lists | |
1477 | ${*$self}{exp_expect_before_list} = []; | |
1478 | ${*$self}{exp_expect_after_list} = []; | |
1479 | } | |
1480 | ||
1481 | ||
1482 | sub _make_readable { | |
1483 | $_ = shift; | |
1484 | $_ = '' unless defined ($_); | |
1485 | study; # Speed things up? | |
1486 | s/\\/\\\\/g; # So we can tell easily(?) what is a backslash | |
1487 | s/\n/\\n/g; | |
1488 | s/\r/\\r/g; | |
1489 | s/\t/\\t/g; | |
1490 | s/\'/\\\'/g; # So we can tell whassa quote and whassa notta quote. | |
1491 | s/\"/\\\"/g; | |
1492 | # Formfeed (does anyone use formfeed?) | |
1493 | s/\f/\\f/g; | |
1494 | s/\010/\\b/g; | |
1495 | # escape control chars high/low, but allow ISO 8859-1 chars | |
1496 | s/[\000-\037\177-\237\377]/sprintf("\\%03lo",ord($&))/ge; | |
1497 | ||
1498 | return $_; | |
1499 | } | |
1500 | ||
1501 | sub _trim_length { | |
1502 | # This is sort of a reverse truncation function | |
1503 | # Mostly so we don't have to see the full output when we're using | |
1504 | # Also used if Max_Accum gets set to limit the size of the accumulator | |
1505 | # for matching functions. | |
1506 | # exp_internal | |
1507 | my($self) = shift; | |
1508 | my($string) = shift; | |
1509 | my($length) = shift; | |
1510 | ||
1511 | # If we're not passed a length (_trim_length is being used for debugging | |
1512 | # purposes) AND debug >= 3, don't trim. | |
1513 | return($string) if (defined ($self) and | |
1514 | ${*$self}{"exp_Debug"} >= 3 and (!(defined($length)))); | |
1515 | my($indicate_truncation) = '...' unless $length; | |
1516 | $length = 1021 unless $length; | |
1517 | return($string) unless $length < length($string); | |
1518 | # We wouldn't want the accumulator to begin with '...' if max_accum is passed | |
1519 | # This is because this funct. gets called internally w/ max_accum | |
1520 | # and is also used to print information back to the user. | |
1521 | return $indicate_truncation.substr($string,(length($string) - $length),$length); | |
1522 | } | |
1523 | ||
1524 | sub _print_handles { | |
1525 | # Given crap from 'self' and the handles self wants to print to, print to | |
1526 | # them. these are indicated by the handle's 'group' | |
1527 | my($self) = shift; | |
1528 | my($print_this) = shift; | |
1529 | my($handle); | |
1530 | if (${*$self}{exp_Log_Group}) { | |
1531 | foreach $handle(@{${*$self}{exp_Listen_Group}}) { | |
1532 | $print_this = '' unless defined ($print_this); | |
1533 | # Appease perl -w | |
1534 | print STDERR "Printed '".$self->_trim_length(_make_readable($print_this))."' to ${*$handle}{exp_Pty_Handle} from ${*$self}{exp_Pty_Handle}.\r\n" if (${*$handle}{"exp_Debug"} > 1); | |
1535 | print $handle $print_this; | |
1536 | } | |
1537 | } | |
1538 | # If ${*$self}{exp_Pty_Handle} is STDIN this would make it echo. | |
1539 | print STDOUT $print_this | |
1540 | if ${*$self}{"exp_Log_Stdout"}; | |
1541 | $self->print_log_file($print_this); | |
1542 | $|= 1; # This should not be necessary but autoflush() doesn't always work. | |
1543 | } | |
1544 | ||
1545 | sub _get_mode { | |
1546 | my($fcntl_flags) = ''; | |
1547 | my($handle) = shift; | |
1548 | # What mode are we opening with? use fcntl to find out. | |
1549 | $fcntl_flags = fcntl(\*{$handle},Fcntl::F_GETFL,$fcntl_flags); | |
1550 | die "fcntl returned undef during exp_init of $handle, $!\r\n" unless defined($fcntl_flags); | |
1551 | if ($fcntl_flags | (Fcntl::O_RDWR)) { | |
1552 | return 'rw'; | |
1553 | } elsif ($fcntl_flags | (Fcntl::O_WRONLY)) { | |
1554 | return 'w' | |
1555 | } else { | |
1556 | # Under Solaris (among others?) O_RDONLY is implemented as 0. so |O_RDONLY would fail. | |
1557 | return 'r'; | |
1558 | } | |
1559 | } | |
1560 | ||
1561 | ||
1562 | sub _undef { | |
1563 | return undef; | |
1564 | # Seems a little retarded but &CORE::undef fails in interconnect. | |
1565 | # This is used for the default escape sequence function. | |
1566 | # w/out the leading & it won't compile. | |
1567 | } | |
1568 | ||
1569 | # clean up child processes | |
1570 | sub DESTROY { | |
1571 | my $self = shift; | |
1572 | if (${*$self}{exp_Do_Soft_Close}) { | |
1573 | $self->soft_close(); | |
1574 | } | |
1575 | $self->hard_close(); | |
1576 | } | |
1577 | ||
1578 | 1; |