expect Functions¶
- function expect/spawn [argv]¶
Spawn a process defined by argv
- Param argv:
command and arguments
- Type argv:
list
- Return:
- Rtype:
struct-instance
- Raises ^system-error:
spawn
will set and return spawn-id.Tip
spawn-id
defaults to#f
however if you set it to#n
or a list of spawn-id(s) thenspawn
will prepend any new value to the list.
- function expect/exp-case [clauses]¶
define-template: (exp-case & clauses) (x e)
exp-case
looks to find the first match from the clauses:passed to exp-case-before, if any
passed to
exp-case
itself, if anypassed to exp-case-after, if any
exp-case
operates on the current value of spawn-id (no such value can be passed directly asexp-case
is a template).Each clause in clauses takes one of the forms
([:str-kw]* string body)
(:term-kw body)
Here,
:str-kw
is one of the string keywords::re
indicating thatstring
should be used for a regular expression match:gl
indicating thatstring
should be used for a glob-style pattern match (the default) – see regex-pattern-string for how the string is modified:ex
indicating thatstring
should be used for an exact match – see regex-exact-string for how the string is modified:icase
indicates that a case-insensitive match should be used
:term-kw
is one of the terminal keywords::eof
for matching the End of File indicatorNote
If
spawn-id
is a list thenbody
will be called for each spawn-id for which the condition is true.If
spawn-id
is a list then it is inadvisable to call(exp-continue)
in thebody
of an:eof
clause as that will prevent the invocation of any other extant End of File notifications.See also the End of File note below.
:timeout
for matching a time outNote
:timeout
will be true for all spawn-ids if spawn-id is a list. Thebody
will be called with the value of spawn-id (which could be a list or a struct instance).:all
to match everything in the buffer, ie. in effect, to empty the bufferNote
:all
always matches and therefore will not read any more data from the spawned process.If
spawn-id
is a list then for each spawn-id in the list the entire buffer will be matched and thebody
called.
body
will be invoked as though the body of a function with the following arguments:for a successful string match, including
:all
, the arguments arespawn-id
,r
, the result of the match as per regexec, andprefix
, the contents of the spawn-id’s buffer before the matchfor a successful terminal match, excluding
:all
, the argument isspawn-id
body
can invoke the function(exp-continue)
to loop around again.body
can invoke the function(exp-break [value])
to exit the loop immediately.Passing no clauses will still attempt to match using any existing clauses from exp-case-before or exp-case-after.
If a clause matches,
exp-case
returns the value frombody
. If no clauses match or all spawn-ids have indicated End of File, or a timeout has occurred and there is no:timeout
clauseexp-case
returns#f
.End of File
If the spawned process indicates End of File then the master file descriptor is generally closed although this is not guaranteed.
Call exp-wait to clean up both file descriptors and spawned processes.
Note
All (supported) operating systems can use poll(2). However, some tested operating systems (Mac OS 10.5.8) return
POLLNVAL
for (pseudo-terminal) devices.In this case, the code reverts to the uses of select(2) with any associated limits (notably,
FD_SETSIZE
).- Example:
From the top of the Idio distribution you might try:
import expect spawn ls -1 ;; minus one ! (expect-case (:re "NG[.]" { printf ":re '%s' => %s\n" prefix r (exp-continue) }) ("doc?" { printf ":gl '%s' => %s\n" prefix r (exp-continue) }) (:icase "EXT?" { printf ":gl '%s' => %s\n" prefix r (exp-continue) }) (:ex "NSE." { printf ":ex '%s' => %s\n" prefix r (exp-continue) }) (:eof { printf ":eof\n" }) (:timeout { printf ":timeout\n" }))
to get:
:re 'bin CONTRIBUTI' => #[ ("NG." 15 18) ] :gl 'md ' => #[ ("doc\r" 4 8) ] :gl ' ' => #[ ("ext\r" 1 5) ] :ex ' lib LICENSE LICE' => #[ ("NSE." 19 23) ] :eof
- function expect/exp-continue [value]¶
define-template: (exp-continue & args) (x e)
exp-continue
stops processing the current exp-case clauses and starts the next iteration of the loop. value is ignored and set to#<void>
if not supplied.Warning
exp-continue
ignores any protection blocks set up by unwind-protect or dynamic-wind.
- function expect/exp-break [value]¶
define-template: (exp-break & args) (x e)
exp-break
returns value from the enclosing exp-case or#<void>
if no value is supplied.Warning
exp-break
ignores any protection blocks set up by unwind-protect or dynamic-wind.
- function expect/exp-case-before [clauses]¶
define-template: (exp-case-before & clauses) (x e)
exp-case-before
establishes match clauses identically to exp-case except the clauses are tested before those passed inexp-case
.Invoking
exp-case-before
doesn’t actually perform any matching, you must still callexp-case
.Passing no clauses effectively unsets this behaviour.
- Example:
import expect spawn echo foo (exp-case-before ("foo" { 'before })) (exp-case ("foo" { 'normally }))
to have
exp-case
returnbefore
.
- function expect/exp-case-after [clauses]¶
define-template: (exp-case-after & clauses) (x e)
exp-case-after
establishes match clauses identically to exp-case except the clauses are tested after those passed inexp-case
.Invoking
exp-case-after
doesn’t actually perform any matching, you must still callexp-case
.Passing no clauses effectively unsets this behaviour.
- Example:
import expect spawn echo foo (exp-case-after ("foo" { 'after })) (exp-case ("bar" { 'bar }))
to have
exp-case
returnafter
.
- function expect/exp-close (:spawn-id spawn-id)¶
close the master file descriptor to the spawned process
- Keyword :spawn-id:
the spawn-id(s) to use, defaults to spawn-id
- Type :spawn-id:
expect/struct-spawn, optional
- Return:
#<unspec>
exp-close
will also set the mfd structure element to#f
spawn-id can be a struct-spawn or a list of such
struct-spawn
s.
- function expect/exp-log-file file (:spawn-id spawn-id) (:append #t)¶
Log the send/expect dialog for spawn-id to file or not
- Param file:
the file to log to
- Type file:
see below
- Keyword :spawn-id:
the spawn-id(s) to use, defaults to spawn-id
- Type :spawn-id:
expect/struct-spawn, optional
- Keyword :append:
to append or not, defaults to
#t
- Type :append:
boolean, optional
- Return:
#<unspec>
file can be:
#f
to disable logging to a fileIf the existing log file was passed as a string, ie. it was opened by this module, then the associated log file handle will be closed. If this log file was shared with other spawn-ids then this closure will affect all of them.
Both log-file and lfh will be set to
#f
in all cases.a string, indicating the filename to log to
an output handle
a file descriptor (open for output)
spawn-id can be a struct-spawn or a list of such
struct-spawn
s.
- function expect/exp-log-user on?¶
Log the send/expect dialog to the user (ie. stdout) or not
- Param on?:
to log or not
- Type on?:
boolean
- Return:
#<unspec>
The default is to have logging to the user enabled.
- function expect/exp-send msg (:slow #f) (:human #f) (:spawn-id spawn-id) (:cr #f)¶
send msg to the spawned process
- Param msg:
the string to send
- Type msg:
string
- Keyword :slow:
send msg slowly, defaults to
#f
- Type :slow:
boolean, optional
- Keyword :human:
send msg humanly, defaults to
#f
- Type :human:
boolean, optional
- Keyword :spawn-id:
the spawn-id to use, defaults to spawn-id
- Type :spawn-id:
expect/struct-spawn, optional
- Keyword :cr:
to send a ‘carriage return’ or not, defaults to
#f
- Type :cr:
boolean, optional
- Return:
#<unspec>
:slow says to use the value of exp-slow which is a tuple of the number of code points in a burst prefixed by a delay of a number of milliseconds. The default is
(600 50)
– 600 code points and a 50 ms delay – roughly equivalent to a 115200 baud modem (if the code points were ASCII).:human says to use the value of exp-human which is a tuple of:
the average gap between in-word code points
the average gap transitioning from an in-word code point to a non-word code point
a moderating factor, K:
“tiredness” might be represented by a K < 1 and preternaturally consistent typing by a K > 1
the minimum inter-code point gap
the maximum inter-code point gap
The default is
(180 240 1 45 360)
roughly equivalent to a 60 wpm typist.The algorithm used to calculate the inter-code point gap is the inverse cumulative distribution function of the Weibull distribution. The same as Don Libes’ expect(1).
:human is preferred to :slow if both are supplied.
:spawn-id can be passed a C/int representing an open (for output) file descriptor which will be used instead. For example, to send output to the user pass
libc/STDOUT_FILENO
.- Example:
Suppose we wanted to observe a professional typist attempting a well-known English pangram:
exp-send "The quick brown fox jumps over the lazy dog" :spawn-id libc/STDOUT_FILENO :human #t
- function expect/exp-send-human fd msg¶
send msg slowly as if a human was typing
- Param fd:
file descriptor
- Type fd:
C/int
- Param msg:
message to send
- Type msg:
string
- Return:
#<unspec>
exp-send-human
uses a similar algorithm to expect(1)See also
exp-send for details
- function expect/exp-wait (:spawn-id spawn-id) (:close #t)¶
wait for the spawned process
- Keyword :spawn-id:
the spawn-id(s) to use, defaults to spawn-id
- Type :spawn-id:
- Keyword :close:
close the mfd, defaults to
#t
- Type :close:
boolean
- Return:
see below
- Rtype:
list
exp-wait
will call exp-close if :close is true andexp-close
has not already been called.Otherwise
exp-wait
will read data from the spawned process until End of File (or some ^system-error) is indicated.Warning
Neither option is ideal if the spawned process has not completed its processing
pro-actively closing the mfd of a running program will probably have the operating system send the spawned process a hangup signal
This is most likely to result in a failed process state (and presumes the spawned process does not ignore or otherwise handle a
SIGHUP
).on the other hand, not closing the mfd might have the spawned process block waiting for full output buffers to be emptied, hence reading from the spawned process until End of File is indicated
However, if the spawned process is waiting for some input before writing any final output then the spawned process will also block.
exp-wait
will return a list of the result from waitpid plus a decoding of the status, eg.(exit 0)
or(killed 1)
(see tip).spawn-id can be a struct-spawn or a list of such
struct-spawn
s. If spawn-id is a list the value returned will be a list of individual result lists.Tip
The per-spawn-id result is also stored in the
struct-spawn
structure as the status field.
- function expect/exp-spawn-sync [spawn-id [timeout]]¶
wait for the spawned processes to be “ready”
- Param spawn-id:
the spawn-id(s) to use, defaults to spawn-id
- Type spawn-id:
a list of expect/struct-spawn
- Param timeout:
timeout per spawn-id (in seconds), defaults to exp-timeout
- Type timeout:
integer
- Return:
unspecified
- Rtype:
unspecified
If you spawn multiple processes on a transiently/mechanically under-resourced system where a subsequent exp-case is intended to test patterns against all processes it is quite possible that one or more of the spawned processes will not (yet) have been scheduled to run by the operating system before the
exp-case
starts.poll(2)/select(2) will quite happily return with what is available from those processes that have been scheduled leaving the possibility of missing data from not yet ready processes.
exp-spawn-sync
will test each of the spawn-ids in spawn-id in turn for a response which will give the operating system an opportunity to schedule the process in. The response could be that the is output available to be read, there is no output or an error has occurred – however, at least a response is ready.There should be no need to use
exp-spawn-sync
for single-instance spawn-ids as the followingexp-case
provides the same functionality implicitly.exp-spawn-sync
is only of use where multiple spawn-ids are expected to be tested against simultaneously.
- function expect/exp-set-winsize [spawn-id [lines [columns]]]¶
set the terminal’s window size
- Param spawn-id:
the spawn-id to be set, default spawn-id
- Type spawn-id:
struct-spawn, optional
- Param lines:
terminal lines, default that of Idio’s terminal, if available
- Type lines:
fixnum|C/int
- Param columns:
terminal columns, default that of Idio’s terminal, if available
- Type columns:
fixnum|C/int
- Return:
#<unspec>
Last built at 2024-12-21T07:10:38Z+0000 from 62cca4c (dev) for Idio 0.3.b.6