@node Expect
@chapter Expect

The macros in this section are made available with:

@smalllisp
(use-modules (ice-9 expect))
@end smalllisp

@code{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 @code{expect} macro
is described below; @code{expect-strings} is a front-end to @code{expect}
based on regexec (see the regular expression documentation).

@defmac expect-strings clause @dots{}
By default, @code{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:

@smalllisp
(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")))))
@end smalllisp

The regular expression is compiled with the @code{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 @code{=>} can be used to indicate that the expression is a
procedure which will accept the result of a successful regular expression
match.  E.g.,

@smalllisp
("^daemon" => write)
("^d\\(aemon\\)" => (lambda args (for-each write args)))
("^da\\(em\\)on" => (lambda (all sub)
                         (write all) (newline)
                         (write sub) (newline)))
@end smalllisp

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 behaviour
of @code{expect} (and @code{expect-strings}).
Most have default top-level bindings to the value @code{#f}, 
which produces the default behaviour.
They can be redefined at the
top level or locally bound in a form enclosing the expect expression.

@table @code
@item expect-port
A port to read characters from, instead of the current input port.
@item expect-timeout
@code{expect} will terminate after this number of
seconds, returning @code{#f} or the value returned by expect-timeout-proc.
@item expect-timeout-proc
A procedure called if timeout occurs.  The procedure takes a single argument:
the accumulated string.
@item 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.
@item 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.
@item expect-strings-compile-flags
Flags to be used when compiling a regular expression, which are passed
to @code{make-regexp} @xref{Regexp Functions}.  The default value
is @code{regexp/newline}.
@item expect-strings-exec-flags
Flags to be used when executing a regular expression, which are
passed to regexp-exec @xref{Regexp Functions}.
The default value is @code{regexp/noteol}, which prevents @code{$}
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.
@end table

Here's an example using all of the variables:

@smalllisp
(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"))))
@end smalllisp
@end defmac

@defmac expect clause @dots{}
@code{expect} is used in the same way as @code{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 @code{#f}, but if end-of-file is reached, the procedures
are called an additional time with the final accumulated string and
@code{#t}.

The test is successful if the procedure returns a non-false value.

If the @code{=>} 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:

@smalllisp
(let ((expect-port (open-input-file "/etc/passwd")))
  (expect
     ((lambda (s) (string=? s "fnord!"))
        (display "Got a nobody user!\n"))))
@end smalllisp

The control variables described for @code{expect-strings} also
influence the behaviour of @code{expect}, with the exception of 
variables whose names begin with @code{expect-strings-}.
@end defmac
