This file describes the current implementation of the expect module
for Python.

  The expect module is written in C and is built into the Python
executable. Currently this module needs both the expect and the tcl
libraries. The only calls made to libtcl are for regexp functions. I
haven't tried to see how to replace them as I use a shared lib version
of libexpect for Linux I built myself that needs libtcl to link with
anyway...


  Once the module is loaded with the import command these new functions and
constants are available:

Constants:
----------

__name__   : 'expect'
  You already know this one :)

error      : 'expect.error'
  The name of the exception returned in case of error.

timeout    : 'expect.timeout'
eof        : 'expect.eof'
full_buffer: 'expect.full_buffer'
  Exceptions return by the functions whenever one of these 3
  conditions occurs.

glob       : 1
exact      : 2
regexp     : 3
null       : 5
  One of the parameters given to the expect() method of a spawn
  object, to tell how string given in argument must be matched.
  'null' is matched if the remove_nulls flags is 0 and there is a NULL
  byte in the stream.

Functions:
----------

setdeffullbuffer([int])
setdefloguser([int])
setdeftimeout([int])
setdefremove_nulls([int])
setdefmatch_max([int])
  These 4 functions let you consult or change the value of the expect
  global variables exp_full_buffer, exp_loguser, exp_timeout,
  exp_remove_nulls and exp_match_max.
  - If given no parameter they return the current value.
  - If given a parameter they set the new value and return the
    previous value.

  The acceptable values are :
   fullbuffer : 0 to disable the FULLBUFFER error, 1 to enable it.
   loguser : 0 to disable, 1 to enable.
   timeout : -1 = no timeout, 0 = return immediatly if no match,
             > 0 = wait n seconds before timeout.
   remove_nulls : 0 to disable, 1 to enable.
   match_max : Must be >= 1.

  These four values are global for all newly created spawn
  objects. Their initial value is the same as the one provided by the
  libexpect library.

spawn(string, list/tuple of strings)
  This function has got the same syntax as posix.execv. It spawns a
  new process under the control of expect and return a spawn
  object. It raises an exception if the exp_spawnv() functions fails.
  The first argument is the name of the program to launch and the
  tuple/list is the parameter list.

expect(list of 2 element tuples, timeout = default_timeout):
  This is the core of the module. The arguments are a list of patterns
  to match, and an optional timeout which is an integer representing seconds.
  If a timeout parameter is not passed in, the default timeout is used.
  Each element of the list must be of one of the following kinds
  (spawn object, pattern object) or
  ([spawn object, spawn object, ...], pattern object) or
  ([spawn object, spawn object, ...], [pattern object, pattern object, ...]) or
  (spawn object, [pattern object, pattern object, ...])

  Each pattern object must be of the kind
  (type, string, object), or (type, [string, string,...], object) where:
    type = expect.glob, expect.exact, expect.regexp, expect.null.
    string = string to match, in the way specified by 'type'.
    object = any object. It will be part of the return value of the expect
             function if the match is successfull.

  The return value is a 2-tuple whose first element is the object corresponding
  to the successful match and whose second element is the spawn object
  corresponding to the successful match.

  An exception is raised is raised if:
   * There is an error: expect.error is raised
   * A timeout occurs: expect.timeout is raised
   * An End Of File occurs: expect.eof is raised, the associated value of the
       exception is the spawn object on which End Of File was detected
   * The internal buffer is full and the full_buffer flag for a spawn object is
       set:
        expect.full_buffer is raised, the associated value of the exception is
        the spawn object whose buffer was full with a set full_buffer flag

  Example:
    try:
        val, spawn = expect.expect([([exp1, exp2], [(expect.glob, 'ftp> ', 1),
                         (expect.glob, 'Connection timeout', 2)])])
        if val == 1:
            spawn.send("Goober")
			# Go On
        elif val == 2:
			spawn.send("Foo")
            print 'Connection with the server timed out'
    except expect.timeout
        print 'We must be hung somewhere...'


  The expect() method cannot be safely intermixed with the read() call of a
  spawn object.


The spawn object:
------------------

The spawn object has got the following members.

alive: 
  1 if the process is alive. 
  This becomes 0 once the process finishes and the expect modules
  receives the SIGCHLD signal, or if the user ends the process (by
  sending the 'quit\n' characteres to an ftp session for example).
  Once this value is zero the spawn methods raise an exception that
  says 'connection dead'.

fd:
  The file descriptor of the spawned process as returned by the
  exp_spawnv() function.

pid:
  The process id of the spawned process.

status:
  Undefined while alive==1, this hold the status of the ending process
  as returned by the waitpid() function. waitpid() doesn't seem to
  exist on all systems, any suggestion/replacement?

timeout:
loguser:
full_buffer:
remove_nulls:
match_max:
  The initial value of these members is the same as the global one,
  but can be modified for each object individually. Giving these
  variables an invalid value raises the ValueError exception.

buffer: 
The value of the current internal buffer of the spawn object, there
is one buffer for each spawn object. Its value is None at the
beginning. It only makes sense after a call to expect(). If the
previous call to expect() was a failure and there is nothing more in
the buffer the value will be None.

match_index: 
  Index of the first matching character in 'buffer'.

match_len: 
  Length of the matching string.

match_end:
  Index of the caracter after the last matching one.

Therefore the matching string is :
    exp.string[exp.match_index:exp.match_end]
If there was not match during the previous call to expect then
    match_index = match_len = match_end = 0.


The spawn object has got the following members.

send(string):
  Sends the string to the process as if typed on the keyboard.
  Returns None.
  Raises an exception if the number of bytes written is different from
  the number of bytes given as parameter.
  Raises an exception if the process has finished.

read([int]):
  Reads a given number of bytes from the process or, if no value is
  given, reads until EOF.
  Returns a string, which will be empty if there is nothing to read.
  This function works in a non blocking way by using select(), once
  there is nothing to read it returns.
  Raises an exception if it cannot read from the file descriptor.
  Raises an exception if the process has finished.

interact(char):
  Lets the user work interactively with the program until the
  character 'char' is hit, and the control is given back to the python
  script. For the moment the implementation is rather simplistic and a
  Ctrl-C interrupts it.

close():
  Close the connection to the spawned program, which has the side
  effect to end this one. This lets you end the spawned program
  without having to wait for python's garbage collecting to do the
  job.

---------------------

  Look at the archie.py and autpasswd.py scripts for an example.

  I think the only thing in Tcl on which this module is dependent is
the regexp routine. It would be better to use python's routines. An
argument to expect() could directly be a regex object instead of a
string. But I don't know if these regexp routines are compatible.


95/08/15:
  I am starting to make changes to have the expect module use the
Python regexp library instead of the Tcl one. I have tested my changes
once and it worked fine. But I haven't touched it for a long time,
moreover Saad Mufti proposed a lots of changes to the code so I
commented out my modifications for the moment.
  Those interested can look at the '#ifdef USE_PYTHON_REGEXP' in the
code. You also need to apply the 'expect.diff' to Expect. This has
only been tested with Expect 5.16! It may be outdated now. The
'tclsyms.c' file may also be needed in case you get tons of undefined
symbols when linking expectmodule with libexpect. I repeat: these
changes will only work with a lot of manual tweaking.

  All suggestions and bug reports are welcome, thanks!
