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:
spawnwill set and return spawn-id.Tip
spawn-iddefaults to#fhowever if you set it to#nor a list of spawn-id(s) thenspawnwill prepend any new value to the list.
- function expect/exp-case [clauses]¶
define-template: (exp-case & clauses) (x e)
exp-caselooks to find the first match from the clauses:passed to exp-case-before, if any
passed to
exp-caseitself, if anypassed to exp-case-after, if any
exp-caseoperates on the current value of spawn-id (no such value can be passed directly asexp-caseis a template).Each clause in clauses takes one of the forms
([:str-kw]* string body)(:term-kw body)Here,
:str-kwis one of the string keywords::reindicating thatstringshould be used for a regular expression match:glindicating thatstringshould be used for a glob-style pattern match (the default) – see regex-pattern-string for how the string is modified:exindicating thatstringshould be used for an exact match – see regex-exact-string for how the string is modified:icaseindicates that a case-insensitive match should be used
:term-kwis one of the terminal keywords::eoffor matching the End of File indicatorNote
If
spawn-idis a list thenbodywill be called for each spawn-id for which the condition is true.If
spawn-idis a list then it is inadvisable to call(exp-continue)in thebodyof an:eofclause as that will prevent the invocation of any other extant End of File notifications.See also the End of File note below.
:timeoutfor matching a time outNote
:timeoutwill be true for all spawn-ids if spawn-id is a list. Thebodywill be called with the value of spawn-id (which could be a list or a struct instance).:allto match everything in the buffer, ie. in effect, to empty the bufferNote
:allalways matches and therefore will not read any more data from the spawned process.If
spawn-idis a list then for each spawn-id in the list the entire buffer will be matched and thebodycalled.
bodywill 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
bodycan invoke the function(exp-continue)to loop around again.bodycan 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-casereturns 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:timeoutclauseexp-casereturns#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
POLLNVALfor (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-continuestops 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-continueignores any protection blocks set up by unwind-protect or dynamic-wind.
- function expect/exp-break [value]¶
define-template: (exp-break & args) (x e)
exp-breakreturns value from the enclosing exp-case or#<void>if no value is supplied.Warning
exp-breakignores 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-beforeestablishes match clauses identically to exp-case except the clauses are tested before those passed inexp-case.Invoking
exp-case-beforedoesn’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-casereturnbefore.
- function expect/exp-case-after [clauses]¶
define-template: (exp-case-after & clauses) (x e)
exp-case-afterestablishes match clauses identically to exp-case except the clauses are tested after those passed inexp-case.Invoking
exp-case-afterdoesn’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-casereturnafter.
- 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-closewill also set the mfd structure element to#fspawn-id can be a struct-spawn or a list of such
struct-spawns.
- 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:
#fto 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
#fin 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-spawns.
- 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-humanuses 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-waitwill call exp-close if :close is true andexp-closehas not already been called.Otherwise
exp-waitwill 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-waitwill 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-spawns. 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-spawnstructure 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-casestarts.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-syncwill 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-syncfor single-instance spawn-ids as the followingexp-caseprovides the same functionality implicitly.exp-spawn-syncis 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 2025-10-29T07:10:37Z+0000 from 3d9f9d3 (dev) for Idio 0.3.b.6