Add a man page.
authorRichard W.M. Jones <rjones@redhat.com>
Sat, 26 Apr 2014 10:50:13 +0000 (11:50 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Sat, 26 Apr 2014 10:50:13 +0000 (11:50 +0100)
Move all the documentation from the header file to the man page.

.gitignore
Makefile.am
README
configure.ac
miniexpect.h
miniexpect.pod [new file with mode: 0644]

index 60d02d0..e8814ae 100644 (file)
@@ -26,6 +26,7 @@
 /libtool
 /ltmain.sh
 /m4/
+/miniexpect.3
 /missing
 /stamp-h1
 /test-driver
index 80e4053..6139816 100644 (file)
@@ -17,7 +17,7 @@
 
 ACLOCAL_AMFLAGS = -I m4
 
-EXTRA_DIST =
+EXTRA_DIST = miniexpect.3
 
 # The library.
 
@@ -45,6 +45,20 @@ test_spawn_SOURCES = test-spawn.c
 test_spawn_CFLAGS = $(PCRE_CFLAGS) -Wall
 test_spawn_LDADD = libminiexpect.la
 
+# Man pages.
+
+man_MANS = miniexpect.3
+
+if HAVE_POD2MAN
+miniexpect.3: miniexpect.pod
+       $(POD2MAN) \
+         --section 3 \
+         --release "$(PACKAGE)-$(VERSION)" \
+         -c "Library functions" \
+         $< > $@-t
+       mv $@-t $@
+endif
+
 # Clean.
 
 CLEANFILES = *~
diff --git a/README b/README
index f739940..f1f5a95 100644 (file)
--- a/README
+++ b/README
@@ -21,7 +21,11 @@ Source is available from: http://git.annexia.org/?p=miniexpect.git;a=summary
 Using the library
 -----------------
 
-The API is described in miniexpect.h.
+If you wanted to copy the library into your own code (instead of
+linking to it as a dependency), you only need to copy the two files:
+miniexpect.h, miniexpect.c.
 
-To understand how to use the API, take a look at the examples and
+The API is documented in the manual page (miniexpect.pod / miniexpect.3).
+
+For examples of how to use the API in reality, see the examples and
 tests in the source directory.
index 4edc425..6051e3e 100644 (file)
@@ -45,6 +45,10 @@ AC_SYS_LARGEFILE
 dnl The only dependency is libpcre (Perl Compatible Regular Expressions).
 PKG_CHECK_MODULES([PCRE], [libpcre])
 
+dnl Optional for building the manual page.  This is part of Perl.
+AC_CHECK_PROG([POD2MAN], [pod2man], [pod2man], [no])
+AM_CONDITIONAL([HAVE_POD2MAN], [test "x$POD2MAN" != "xno"])
+
 dnl Produce output files.
 AC_CONFIG_HEADERS([config.h])
 
index ba3607a..31b7269 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+/* ** NOTE ** All API documentation is in the manual page.
+ *
+ * To read the manual page from the source directory, do:
+ *    man ./miniexpect.3
+ * If you have installed miniexpect, do:
+ *    man 3 miniexpect
+ *
+ * The source for the manual page is miniexpect.pod.
+ */
+
 #ifndef MINIEXPECT_H_
 #define MINIEXPECT_H_
 
 
 /* This handle is created per subprocess that is spawned. */
 struct mexp_h {
-  int fd;                       /* File descriptor pointing to pty. */
-  pid_t pid;                    /* Subprocess PID. */
-
-  /* Timeout (milliseconds, 1/1000th seconds).  The caller may set
-   * this before calling mexp_expect.  Set it to -1 to mean no
-   * timeout.  The default is 60000 (= 60 seconds).
-   */
+  int fd;
+  pid_t pid;
   int timeout;
-
-  /* The read buffer is allocated by the library when mexp_expect is
-   * called.  It is available so you can examine the buffer to see
-   * what part of the regexp matched.  Note this buffer does not
-   * contain the full input from the process, but it will contain at
-   * least the part matched by the regular expression (and maybe some
-   * more).
-   */
-  char *buffer;                 /* Read buffer. */
-  size_t len;                   /* Length of data in the buffer. */
-  size_t alloc;                 /* Allocated size of the buffer. */
-
-  /* The caller may set this to set the size (in bytes) for reads from
-   * the subprocess.  The default is 1024.
-   */
+  char *buffer;
+  size_t len;
+  size_t alloc;
   size_t read_size;
-
-  /* If mexp_expect returns MEXP_PCRE_ERROR, then the actual PCRE
-   * error code is returned here.  See pcre_exec(3) for details.
-   */
   int pcre_error;
-
-  /* Opaque pointers for use of the caller.  The library will not
-   * touch these.
-   */
   void *user1;
   void *user2;
   void *user3;
 };
 typedef struct mexp_h mexp_h;
 
-/* Spawn a subprocess.
- *
- * If successful it returns a handle.  If it fails, it returns NULL
- * and sets errno.
- */
+/* Spawn a subprocess. */
 extern mexp_h *mexp_spawnv (const char *file, char **argv);
-
-/* Same as mexp_spawnv, but it uses a NULL-terminated variable length
- * list of arguments.
- */
 extern mexp_h *mexp_spawnl (const char *file, const char *arg, ...);
 
-/* Close the handle and clean up the subprocess.
- *
- * This returns:
- *   0:   successful close, subprocess exited cleanly.
- *   -1:  error in system call, see errno.
- *   > 0: exit status of subprocess if it didn't exit cleanly.  Use
- *        WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG etc macros to
- *        examine this.
- *
- * Notes:
- *
- * - Even in the error cases, the handle is always closed and
- *   freed by this call.
- *
- * - It is normal for the kernel to send SIGHUP to the subprocess.
- *   If the subprocess doesn't catch the SIGHUP, then it will die
- *   (WIFSIGNALED (status) && WTERMSIG (status) == SIGHUP).  This
- *   case should not necessarily be considered an error.
- */
+/* Close the handle. */
 extern int mexp_close (mexp_h *h);
 
-/* The list of regular expressions passed to mexp_expect. */
+/* Expect. */
 struct mexp_regexp {
-  int r;                        /* The returned value from mexp_expect
-                                 * if this regular expression matches.
-                                 * MUST be > 0.
-                                 */
-  const pcre *re;               /* The compiled regular expression. */
-  const pcre_extra *extra;      /* See pcre_exec. */
-  int options;                  /* See pcre_exec. */
+  int r;
+  const pcre *re;
+  const pcre_extra *extra;
+  int options;
 };
 typedef struct mexp_regexp mexp_regexp;
 
@@ -116,46 +72,9 @@ enum mexp_status {
   MEXP_PCRE_ERROR = -3,
 };
 
-/* Expect some output from the subprocess.  Match the output against
- * the PCRE regular expression(s) in the list, and return which one
- * matched.
- *
- * See example-sshpass.c for an example of how to pass in regular
- * expressions.
- *
- * This can return:
- *
- *   MEXP_TIMEOUT:
- *     No input matched before the timeout (mexp_h->timeout) was reached.
- *   MEXP_EOF:
- *     The subprocess closed the connection.
- *   MEXP_ERROR:
- *     There was a system call error (eg. from the read call).  See errno.
- *   MEXP_PCRE_ERROR
- *     There was a pcre_exec error.  h->pcre_error is set to the error code
- *     (see pcreapi(3) for a list of PCRE_* error codes and what they mean).
- *
- * Notes:
- *
- * - 'regexps' may be NULL or an empty list, which means we don't
- *   match against a regular expression.  This is useful if you just
- *   want to wait for EOF or timeout.
- *
- * - 'regexps[].re', 'regexps[].extra', 'regexps[].options', 'ovector'
- *   and 'ovecsize' are passed through to the pcre_exec function.
- */
 extern int mexp_expect (mexp_h *h, const mexp_regexp *regexps,
                         int *ovector, int ovecsize);
 
-/* This is a convenience function for writing something (eg. a
- * password or command) to the subprocess.  You could do this by
- * writing directly to 'h->fd', but this function does all the error
- * checking for you.
- *
- * Returns the number of bytes if the whole message was written OK
- * (partial writes are not possible with this function), or -1 if
- * there was an error (check errno).
- */
 extern int mexp_printf (mexp_h *h, const char *fs, ...)
   __attribute__((format(printf,2,3)));
 
diff --git a/miniexpect.pod b/miniexpect.pod
new file mode 100644 (file)
index 0000000..f17cda9
--- /dev/null
@@ -0,0 +1,332 @@
+=encoding utf8
+
+=head1 NAME
+
+miniexpect - A very simple expect library for C.
+
+=head1 SYNOPSIS
+
+ #include <errno.h>
+ #include <sys/wait.h>
+ #include <pcre.h>
+ #include <miniexpect.h>
+ mexp_h *h;
+ h = mexp_spawnl ("ssh", "ssh", "host");
+ switch (mexp_expect (h, regexps, ovector, ovecsize)) {
+   ...
+ }
+ mexp_close (h);
+
+ cc prog.c -o prog -lminiexpect
+
+=head1 DESCRIPTION
+
+miniexpect is a very simple expect-like library for C.
+
+It has a saner interface than libexpect, and doesn't depend on Tcl.
+It is also thread safe, const-correct and uses modern C standards.
+
+It is standalone, except that it requires the PCRE (Perl Compatible
+Regular Expressions) library from http://www.pcre.org/.  The PCRE
+dependency is fundamental because we want to offer the most powerful
+regular expression syntax to match on, but more importantly because
+PCRE has a convenient way to detect partial matches which made this
+library very simple to implement.
+
+This manual page documents the API.  Examples of how to use the API
+can be found in the source directory.
+
+=head1 CONCEPTS
+
+Miniexpect lets you start up an external program, control it (by
+sending commands to it), and close it down gracefully.  Two things
+make this different from other APIs like L<popen(3)> and L<system(3)>:
+Firstly miniexpect creates a pseudoterminal (pty).  Secondly
+miniexpect lets you match the output of the program using regular
+expressions.  Both of these are handy for controlling interactive
+programs that might (for example) ask for passwords, but you can use
+miniexpect on just about any external program.
+
+You can control multiple programs at the same time.
+
+=head1 SPAWNING THE SUBPROCESS
+
+There are two calls for creating a subprocess:
+
+B<mexp_h *mexp_spawnl (const char *file, const char *arg, ...);>
+
+This creates a subprocess running the external program C<file> (the
+current C<$PATH> is searched unless you give an absolute path).
+C<arg, ...> are the arguments to the program.  Usually the first
+argument should be the name of the program.
+
+The return value is a handle (see next section).
+
+If there was an error running the subprocess, C<NULL> is returned and
+the error is available in C<errno>.
+
+For example, to run an ssh subprocess you could do:
+
+ h = mexp_spawnl ("ssh", "ssh", "-l", "root", "host");
+
+or to run a particular ssh binary:
+
+ h = mexp_spawnl ("/usr/local/bin/ssh", "ssh", "-l", "root", "host");
+
+An alternative to C<mexp_spawnl> is:
+
+B<mexp_h *mexp_spawnv (const char *file, char **argv);>
+
+This is the same as C<mexp_spawnl> except that you pass the arguments
+in a NULL-terminated array.
+
+=head1 HANDLES
+
+After spawning a subprocess, you get back a handle.  There are various
+fields in this handle which you can read or write:
+
+ struct mexp_h {
+   int fd;
+   pid_t pid;
+
+C<fd> is the pty of the subprocess.  You can read and write to this if
+you want, although convenience functions are also provided (see
+below).  C<pid> is the process ID of the subprocess.  You can send it
+signals if you want.
+
+   int timeout;
+
+C<timeout> is the timeout in milliseconds (1/1000th of a second) used
+by C<mexp_expect> (see below).  You can set this before calling
+C<mexp_expect> if you want.  Setting it to -1 means no timeout.  The
+default setting is 60000 (60 seconds).
+
+   char *buffer;
+   size_t len;
+   size_t alloc;
+
+If C<mexp_expect> returns a match then these variables contain the
+read buffer.  Note this buffer does not contain the full input from
+the process, but it will contain at least the part matched by the
+regular expression (and maybe some more).  C<buffer> is the read
+buffer and C<len> is the number of bytes of data in the buffer.
+
+   size_t read_size;
+
+Callers may set this to the natural size (in bytes) for reads from the
+subprocess.  The default is 1024.  Most callers will not need to
+change this.
+
+   int pcre_error;
+
+If C<mexp_expect> returns C<MEXP_PCRE_ERROR>, then the actual PCRE
+error code returned by L<pcre_exec(3)> is available here.  For a list
+of PCRE error codes, see L<pcreapi(3)>.
+
+   void *user1;
+   void *user2;
+   void *user3;
+
+Opaque pointers for use by the caller.  The library will not touch
+these.
+
+ };
+ typedef struct mexp_h mexp_h;
+
+=head1 CLOSING THE HANDLE
+
+To close the handle and clean up the subprocess, call:
+
+B<int mexp_close (mexp_h *h);>
+
+This returns the status code from the subprocess.  This is in the form
+of a L<waitpid(2)>/L<system(3)> status so you have to use the macros
+C<WIFEXITED>, C<WEXITSTATUS>, C<WIFSIGNALED>, C<WTERMSIG> etc defined
+in C<E<lt>sys/wait.hE<gt>> to parse it.
+
+If there was a system call error, then C<-1> is returned.  The error
+will be in C<errno>.
+
+Notes:
+
+=over 4
+
+=item *
+
+Even in error cases, the handle is always closed and its memory is
+freed by this call.
+
+=item *
+
+It is normal for the kernel to send SIGHUP to the subprocess.
+
+If the subprocess doesn't catch the SIGHUP, then it will die
+with status:
+
+ WIFSIGNALED (status) && WTERMSIG (status) == SIGHUP
+
+This case should not necessarily be considered an error.
+
+=back
+
+=head1 EXPECT FUNCTION
+
+Miniexpect contains a powerful regular expression matching function
+based on L<pcre(3)>:
+
+B<int mexp_expect (mexp_h *h, const mexp_regexp *regexps,
+int *ovector, int ovecsize);>
+
+The output of the subprocess is matched against the list of PCRE
+regular expressions in C<regexps>.  C<regexps> is a list of regular
+expression structures:
+
+ struct mexp_regexp {
+   int r;
+   const pcre *re;
+   const pcre_extra *extra;
+   int options;
+ };
+ typedef struct mexp_regexp mexp_regexp;
+
+C<r> is the integer code returned from C<mexp_expect> if this regular
+expression matches.  It B<must> be E<gt> 0.  C<r == 0> indicates the
+end of the list of regular expressions.  C<re> is the compiled regular
+expression.
+
+Possible return values are:
+
+=over 4
+
+=item C<MEXP_TIMEOUT>
+
+No input matched before the timeout (C<h-E<gt>timeout>) was
+reached.
+
+=item C<MEXP_EOF>
+
+The subprocess closed the connection.
+
+=item C<MEXP_ERROR>
+
+There was a system call error (eg. from the read call).  The error is
+returned in C<errno>.
+
+=item C<MEXP_PCRE_ERROR>
+
+There was a C<pcre_exec> error.  C<h-E<gt>pcre_error> is set to the
+error code.  See L<pcreapi(3)> for a list of the C<PCRE_*> error codes
+and what they mean.
+
+=item C<r> E<gt> 0
+
+If any regexp matches, the associated integer code (C<regexps[].r>)
+is returned.
+
+=back
+
+Notes:
+
+=over 4
+
+=item *
+
+C<regexps> may be NULL or an empty list, which means we don't match
+against a regular expression.  This is useful if you just want to wait
+for EOF or timeout.
+
+=item *
+
+C<regexps[].re>, C<regexps[].extra>, C<regexps[].options>, C<ovector>
+and C<ovecsize> are passed through to the L<pcre_exec(3)> function.
+
+=back
+
+=head2 mexp_expect example
+
+It is easier to understand C<mexp_expect> by considering a simple
+example.
+
+In this example we are waiting for ssh to either send us a password
+prompt, or (if no password was required) a command prompt, and based
+on the output we will either send back a password or a command.
+
+The unusual C<(mexp_regexp[]){...}> syntax is called a "compound
+literal" and is available in C99.  If you need to use an older
+compiler, you can just use a local variable instead.
+
+ mexp_h *h;
+ char *errptr;
+ int offset;
+ pcre *password_re, *prompt_re;
+ int ovecsize = 12;
+ int ovector[ovecsize];
+ password_re = pcre_compile ("assword", 0, &errptr, &offset, NULL);
+ prompt_re = pcre_compile ("[$#] ", 0, &errptr, &offset, NULL);
+ switch (mexp_expect (h,
+                      (mexp_regexp[]) {
+                        { 100, .re = password_re },
+                        { 101, .re = prompt_re },
+                        { 0 },
+                      }, ovector, ovecsize)) {
+  case 100:
+    /* here you would send a password */
+    break;
+  case 101:
+    /* here you would send a command */
+    break;
+  case MEXP_EOF:
+    fprintf (stderr, "error: ssh closed the connection unexpectedly\n");
+    exit (EXIT_FAILURE);
+  case MEXP_TIMEOUT:
+    fprintf (stderr, "error: timeout before reaching the prompt\n");
+    exit (EXIT_FAILURE);
+  case MEXP_ERROR:
+    perror ("mexp_expect");
+    exit (EXIT_FAILURE);
+  case MEXP_PCRE_ERROR:
+    fprintf (stderr, "error: PCRE error: %d\n", h->pcre_error);
+    exit (EXIT_FAILURE);
+ }
+
+=head1 SENDING COMMANDS TO THE SUBPROCESS
+
+You can write to the subprocess simply by writing to C<h-E<gt>fd>.
+However we also provide a convenience function:
+
+B<int mexp_printf (mexp_h *h, const char *fs, ...);>
+
+This returns the number of bytes, if the whole message was written OK.
+If there was an error, -1 is returned and the error is available in
+C<errno>.  Note that this function will not do a partial write.  If it
+cannot write all the data, then it will return an error.
+
+=head1 SOURCE
+
+Source is available from:
+L<http://git.annexia.org/?p=miniexpect.git;a=summary>
+
+=head1 SEE ALSO
+
+L<pcre(3)>,
+L<pcre_exec(3)>,
+L<pcreapi(3)>,
+L<waitpid(2)>,
+L<system(3)>.
+
+=head1 AUTHORS
+
+Richard W.M. Jones (C<rjones at redhat dot com>)
+
+=head1 LICENSE
+
+The library is released under the Library GPL (LGPL) version 2 or at
+your option any later version.
+
+=head1 COPYRIGHT
+
+Copyright (C) 2014 Red Hat Inc.