The macros in this section are made available with:
(use-modules (ice-9 expect))
expect
is a macro for selecting actions based on the output from
a port. The name comes from a tool of similar functionality by Don Libes.
Actions can be taken when a particular string is matched, when a timeout
occurs, or when end-of-file is seen on the port. The expect
macro
is described below; expect-strings
is a front-end to expect
based on regexec (see the regular expression documentation).
By default, expect-strings
will read from the current input port.
The first term in each clause consists of an expression evaluating to
a string pattern (regular expression). As characters
are read one-by-one from the port, they are accumulated in a buffer string
which is matched against each of the patterns. When a
pattern matches, the remaining expression(s) in
the clause are evaluated and the value of the last is returned. For example:
(with-input-from-file "/etc/passwd" (lambda () (expect-strings ("^nobody" (display "Got a nobody user.\n") (display "That's no problem.\n")) ("^daemon" (display "Got a daemon user.\n")))))
The regular expression is compiled with the REG_NEWLINE
flag, so
that the ^ and $ anchors will match at any newline, not just at the start
and end of the string.
There are two other ways to write a clause:
The expression(s) to evaluate can be omitted, in which case the result of the regular expression match (converted to strings, as obtained from regexec with match-pick set to "") will be returned if the pattern matches.
The symbol =>
can be used to indicate that the expression is a
procedure which will accept the result of a successful regular expression
match. E.g.,
("^daemon" => write) ("^d(aemon)" => (lambda args (for-each write args))) ("^da(em)on" => (lambda (all sub) (write all) (newline) (write sub) (newline)))
The order of the substrings corresponds to the order in which the opening brackets occur.
A number of variables can be used to control the behavior
of expect
(and expect-strings
).
Most have default top-level bindings to the value #f
,
which produces the default behavior.
They can be redefined at the
top level or locally bound in a form enclosing the expect expression.
expect-port
A port to read characters from, instead of the current input port.
expect-timeout
expect
will terminate after this number of
seconds, returning #f
or the value returned by expect-timeout-proc.
expect-timeout-proc
A procedure called if timeout occurs. The procedure takes a single argument: the accumulated string.
expect-eof-proc
A procedure called if end-of-file is detected on the input port. The procedure takes a single argument: the accumulated string.
expect-char-proc
A procedure to be called every time a character is read from the port. The procedure takes a single argument: the character which was read.
expect-strings-compile-flags
Flags to be used when compiling a regular expression, which are passed
to make-regexp
See Regexp Functions. The default value
is regexp/newline
.
expect-strings-exec-flags
Flags to be used when executing a regular expression, which are
passed to regexp-exec See Regexp Functions.
The default value is regexp/noteol
, which prevents $
from matching the end of the string while it is still accumulating,
but still allows it to match after a line break or at the end of file.
Here’s an example using all of the variables:
(let ((expect-port (open-input-file "/etc/passwd")) (expect-timeout 1) (expect-timeout-proc (lambda (s) (display "Times up!\n"))) (expect-eof-proc (lambda (s) (display "Reached the end of the file!\n"))) (expect-char-proc display) (expect-strings-compile-flags (logior regexp/newline regexp/icase)) (expect-strings-exec-flags 0)) (expect-strings ("^nobody" (display "Got a nobody user\n"))))
expect
is used in the same way as expect-strings
,
but tests are specified not as patterns, but as procedures. The
procedures are called in turn after each character is read from the
port, with two arguments: the value of the accumulated string and
a flag to indicate whether end-of-file has been reached. The flag
will usually be #f
, but if end-of-file is reached, the procedures
are called an additional time with the final accumulated string and
#t
.
The test is successful if the procedure returns a non-false value.
If the =>
syntax is used, then if the test succeeds it must return
a list containing the arguments to be provided to the corresponding
expression.
In the following example, a string will only be matched at the beginning of the file:
(let ((expect-port (open-input-file "/etc/passwd"))) (expect ((lambda (s eof?) (string=? s "fnord!")) (display "Got a nobody user!\n"))))
The control variables described for expect-strings
also
influence the behavior of expect
, with the exception of
variables whose names begin with expect-strings-
.