New manual pages.
authormdw <mdw>
Tue, 6 Jul 1999 19:13:45 +0000 (19:13 +0000)
committermdw <mdw>
Tue, 6 Jul 1999 19:13:45 +0000 (19:13 +0000)
man/lbuf.3 [new file with mode: 0644]
man/mLib.3 [new file with mode: 0644]
man/mdwopt.3 [new file with mode: 0644]
man/testrig.3 [new file with mode: 0644]

diff --git a/man/lbuf.3 b/man/lbuf.3
new file mode 100644 (file)
index 0000000..ecd58aa
--- /dev/null
@@ -0,0 +1,206 @@
+.\" -*-nroff-*-
+.TH lbuf 3 "6 July 1999" mLib
+.SH "NAME"
+lbuf \- split lines out of asynchronously received blocks
+.\" @lbuf_flush
+.\" @lbuf_close
+.\" @lbuf_free
+.\" @lbuf_snarf
+.\" @lbuf_init
+.SH "SYNOPSIS"
+.nf
+.B "#include <mLib/lbuf.h>"
+
+.BI "void lbuf_flush(lbuf *" b ", char *" p ", size_t " len );
+.BI "void lbuf_close(lbuf *" b );
+.BI "size_t lbuf_free(lbuf *" b ", char **" p );
+.BI "void lbuf_snarf(lbuf *" b ", const void *" p ", size_t " sz );
+.BI "void lbuf_init(lbuf *" b ,
+.BI "               void (*" func ")(char *" s ", void *" p ),
+.BI "               void *" p );
+.fi
+.SH "DESCRIPTION"
+The declarations in
+.B <mLib/lbuf.h>
+implement a handy object called a
+.IR "line buffer" .
+Given unpredictably-sized chunks of data, the line buffer extracts
+completed lines of text and passes them to a caller-supplied function.
+This is useful in nonblocking network servers, for example: the server
+can feed input from a client into a line buffer as it arrives and deal
+with completed text lines as they appear without having to wait for
+newline characters.
+.PP
+The state of a line buffer is stored in an object of type
+.BR lbuf .
+This is a structure which must be allocated by the caller.  The
+structure should normally be considered opaque (see the section on
+.B Disablement
+for an exception to this).
+.SS "Initialization and finalization"
+The function
+.B lbuf_init
+initializes a line buffer ready for use.  It is given three arguments:
+.TP
+.I b
+A pointer to the block of memory to use for the line buffer.  This is
+all the memory the line buffer requires.
+.TP
+.I func
+The
+.I line-handler
+function to which the line buffer should pass completed lines of text.
+.TP
+.I p
+A pointer argument to be passed to the function when a completed line of
+text arrives.
+.PP
+Since the line buffer requires no memory except for the actual
+.B lbuf
+object, and doesn't hook itself onto anything else, it can just be
+thrown away when you don't want it any more.  No explicit finalization
+is required.
+.SS "Inserting data into the buffer"
+There are two interfaces for inserting data into the buffer.  One's much
+simpler than the other, although it's less expressive.
+.PP
+The simple interface is
+.BR lbuf_snarf .
+This function is given three arguments: a pointer
+.I b
+to a line buffer structure; a pointer
+.I p
+ to a chunk of data to read; and the size
+.I sz
+of the chunk of data.  The data is pushed through the line buffer and
+any complete lines are passed on to the line handler.
+.PP
+The complex interface is the pair of functions
+.I lbuf_free
+and
+.IR lbuf_flush .
+.PP
+The 
+.B lbuf_free
+function returns the address and size of a free portion of the line
+buffer's memory into which data may be written.  The function is passed
+the address 
+.I l
+of the line buffer.  Its result is the size of the free area, and it
+writes the base address of this free space to the location pointed to by
+the argument
+.IR p .
+The caller's data must be written to ascending memory locations starting
+at
+.BI * p
+and no data may be written beyond the end of the free space.  However,
+it isn't necessary to completely fill the buffer.
+.PP
+Once the free area has had some data written to it,
+.B lbuf_flush
+is called to examine the new data and break it into text lines.  This is
+given three arguments:
+.TP
+.I b
+The address of the line buffer.
+.TP
+.I p
+The address at which the new data has been written.  This must be the
+base address returned from
+.BR lbuf_free .
+.TP
+.I len
+The number of bytes which have been written to the buffer.
+.PP
+The
+.B lbuf_flush
+function breaks the new data into lines as described below, and passes
+each one in turn to the line-handler function.
+.PP
+The
+.B lbuf_snarf
+function is trivially implemented in terms of the more complex
+.B lbuf_free / lbuf_flush
+interface.
+.SS "Line breaking"
+The line buffer considers a line to end with either a simple linefeed
+character (the normal Unix convention) or a carriage-return/linefeed
+pair (the Internet convention).
+.PP
+The line buffer has a fixed amount of memory available to it.  This is
+deliberate, to prevent a trivial attack whereby a remote user sends a
+stream of data containing no newline markers, wasting the server's
+memory.  Instead, the buffer will truncate overly long lines (silently)
+and return only the initial portion.  It will ignore the rest of the
+line completely.
+.SS "Line-handler functions"
+Completed lines, as already said, are passed to the caller's
+line-handler function.  The function is given two arguments:
+the address
+.I s
+of the line which has just been read, and the pointer
+.I p
+which was set up in the call to
+.B lbuf_init .
+The line passed is null-terminated, and has had its trailing newline
+stripped.  The area of memory in which the string is located may be
+overwritten by the line-handler function, although writing beyond the
+terminating zero byte is not permitted.
+.PP
+The line pointer argument
+.I s
+may be null to signify end-of-file.  See the next section.
+.SS "Flushing the remaining data"
+When the client program knows that there's no more data arriving (for
+example, an end-of-file condition exists on its data source) it should
+call the function
+.BR lbuf_close
+to flush out the remaining data in the buffer as one last (improperly
+terminated) line.  This will pass the remaining text to the line
+handler, if there is any, and then call the handler one final time with
+a null pointer rather than the address of a text line to inform it of
+the end-of-file.
+.SS "Disablement"
+The line buffer is intended to be used in higher-level program objects,
+such as the buffer selector described in
+.BR selbuf (3).
+Unfortunately, a concept from this high level needs to exist at the line
+buffer level, which complicates the description somewhat.  The idea is
+that, when a line-handler attached to some higher-level object decides
+that it's read enough, it can
+.I disable
+the object so that it doesn't see any more data.
+.PP
+Clearly, since an
+.B lbuf_flush
+call can emit more than one line, so it must be aware that the line
+handler isn't interested in any more lines.  However, this fact must
+also be signalled to the higher-level object so that it can detach
+itself from its data source.
+.PP
+Rather than invent some complex interface for this, the line buffer
+exports one of its structure members,
+.BR flags .
+A higher-level object wishing to disable the line buffer simply clears
+the bit
+.B LBUF_ENABLE
+in the flags word.
+.PP
+Disabling a buffer causes an immediate return from
+.BR lbuf_flush .
+However, it is not permitted for the functions
+.B lbuf_flush
+or
+.B lbuf_close
+to be called on a disabled buffer.  (This condition isn't checked for;
+it'll just do the wrong thing.)  Furthermore, the
+.B lbuf_snarf
+function does not handle disablement at all, because it would complicate
+the interface so much that it wouldn't have any advantage over the more
+general
+.BR lbuf_free / lbuf_flush .
+.SH "SEE ALSO"
+.BR selbuf (3),
+.BR mLib (3).
+.SH "AUTHOR"
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/mLib.3 b/man/mLib.3
new file mode 100644 (file)
index 0000000..ba309f9
--- /dev/null
@@ -0,0 +1,210 @@
+.\" -*-nroff-*-
+.TH mLib 3 "7 July 1999" mLib
+.SH NAME
+mLib \- library of miscellaneous utilities
+.\" @mLib
+.SH DESCRIPTION
+The
+.B mLib
+library is a mixed back of things which the author finds useful in large
+numbers of programs.  As a result, its structure is somewhat arbitrary,
+and it's accreted extra bits over time rather than actually being
+designed as a whole.  In the author's opinion this isn't too much of a
+hardship.
+.PP
+At the most granular level,
+.B mLib
+is split into `modules', each of which has its own header file and
+manual page.  Sometimes there are identifiable `chunks' of several
+modules which fit together as a whole.  Modules and chunks fit into
+`layers', each depending on the ones below it.  The header file for
+module
+.I foo
+would be put in
+.BR <mLib/ \c
+.IR foo \c
+.BR > .
+.PP
+This description is a bit abstract, and
+.BR mLib ,
+as a result of its history, doesn't fit it as well as I might like.
+Even so, it's not too bad a model really.
+.PP
+The rest of this section describes the various chunks and layers.
+.SS "Exception handling"
+Right at the bottom, there's a fairly primitive exception handling
+system.  It's provided by the
+.B exc
+module, and stands alone.  It's used mainly by the memory allocation
+modules to raise exceptions when there's no more memory to be had.
+.SS "Memory allocation"
+The
+.B alloc
+module provides simple veneers onto traditional memory allocation
+functions like
+.BR malloc (3)
+and
+.BR strdup (3)
+(although
+.B mLib
+doesn't actually depend on
+.B strdup
+being defined in the library) which raise exceptions when there's not
+enough memory left.
+.PP
+The
+.B sub
+module handles efficient allocation of small blocks.  It allocates
+memory in relatively big chunks and divides the chunks up into small
+blocks before returning them.  It keeps lists of differently-sized
+blocks so allocation and freeing is fast.  The downside is that your
+code must know how big a block is when it's being freed.
+.PP
+The
+.B track
+module (not yet documented) is a simple memory allocation tracker.  It
+can be handy when trying to fix memory leaks.
+.SS "String handling"
+The
+.B str
+module provides some trivial string-manipulation functions which tend to
+be useful quite often.
+.PP
+The
+.B dstr
+module implements a dynamic string data type.  It works quite quickly
+and well, and is handy in security-sensitive programs, to prevent
+buffer-overflows.  Dynamic strings are used occasionally through the
+rest of the library, mainly as output arguments.
+.PP
+The
+.B dspool
+module implements a `pool' of dynamic strings which saves lots of
+allocation and deallocation when a piece of code has high string
+turnover.
+.SS "Program identification and error reporting"
+The
+.B quis
+module remembers the name of the program and supplies it when asked.
+It's used in error messages and similar things.
+.PP
+The
+.B report
+module emits standard Unixy error messages.  It provides functions
+.B moan
+and
+.B die
+which the author uses rather a lot.
+.PP
+The
+.B trace
+module (not yet documented)
+provides an interface for emitting tracing information with configurable
+verbosity levels.  It needs improving to be able to cope with outputting
+to the system log.
+.SS "Other data types"
+The
+.B sym
+module implements a rather good extending hash table.  Keys and values can
+be arbitrary data.
+.PP
+The
+.B dynarray
+module (not yet documented) implements unbounded sparse arrays.  It
+needs rewriting.
+.SS "Miscellaneous utilities"
+The
+.B crc32
+module calculates CRC values for strings.  It's used by the symbol table
+manager as a hash function.
+.PP
+The
+.B lock
+module does POSIX
+.BR fcntl (2)-style
+locking with a timeout.
+.PP
+The
+.B lbuf
+module implements a `line buffer', which is an object that emits
+completed lines of text from an incoming asynchronous data stream.  It's
+remarkably handy in programs that want to read lines from pipes and
+sockets can't block while waiting for a line-end to arrive.
+.PP
+The
+.B tv
+module provides some macros and functions for playing with
+.B "struct timeval"
+.PP
+The
+.B bits
+module defines some types and macros for playing with words as chunks of
+bits.  There are portable rotate and shift macros (harder than you'd
+think), and macros to do loading and storing in known-endian formats.
+values.
+.PP
+The
+.B mdwopt
+module implements a fairly serious options parser compatible with the
+GNU options parser.
+.PP
+The
+.B testrig
+module provides a generic structure for reading test vectors from files
+and running them through functions.  I mainly use it for testing
+cryptographic transformations of various kinds.
+.SS "Encoding and decoding"
+The
+.B base64
+module does base64 encoding and decoding, as defined in RFC2045.  Base64
+encodes arbitrary binary data in a reliable way which is resistant to
+character-set transformations and other mail transport bogosity.
+.PP
+The
+.B url
+module does urlencoding and decoding, as defined in RFC1866.
+Urlencoding encodes arbitrary (but mostly text-like) name/value pairs as
+a text string containing no whitespace.
+.SS "Multiplexed I/O"
+The
+.B sel
+module provides a basis for doing nonblocking I/O in Unix systems.  It
+provides types and functions for receiving events when files are ready
+for reading or writing, and when timers expire.
+.PP
+The
+.B conn
+module implements nonblocking network connections in a way which fits in
+with the
+.B sel
+system.  It makes nonblocking connects pretty much trivial.
+.PP
+The
+.B selbuf
+module attaches to the
+.B sel
+system and sends an event when lines of text arrive on a file.  It's
+useful when reading text from a network connection.
+.SH "SEE ALSO"
+.BR alloc (3),
+.BR base64 (3),
+.BR bits (3),
+.BR conn (3),
+.BR crc32 (3),
+.BR dspool (3),
+.BR dstr (3),
+.BR exc (3),
+.BR lbuf (3),
+.BR lock (3),
+.BR mdwopt (3),
+.BR quis (3),
+.BR report (3),
+.BR sel (3),
+.BR selbuf (3),
+.BR str (3),
+.BR sub (3),
+.BR sym (3),
+.BR tv (3),
+.BR url (3).
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/mdwopt.3 b/man/mdwopt.3
new file mode 100644 (file)
index 0000000..693d0a8
--- /dev/null
@@ -0,0 +1,432 @@
+.\" -*-nroff-*-
+.TH mdwopt 3 "6 July 1999" mLib
+.SH "NAME"
+mdwopt \- command-line option parser
+.\" @mdwopt
+.SH "SYNOPSIS"
+.nf
+.B "#include <mLib/mdwopt.h>"
+
+.BI "int mdwopt(int " argc ", char *const *" argv ,
+.BI "           const char *" shortopt ,
+.BI "           const struct option *" longopt ", int *" longind ,
+.BI "           mdwopt_data *" data ", int " flags );
+
+.BI "int getopt(int " argc ", char *const *" argv ", const char *" o );
+
+.BI "int getopt_long(int " argc ", char *const *" argv ,
+.BI "                const char * "shortopt ,
+.BI "                const struct option *" longopt ", int *" longind );
+
+.BI "int getopt_long_only(int " argc ", char *const *" argv ,
+.BI "                    const char * "shortopt ,
+.BI "                    const struct option *" longopt ", int *" longind );
+.fi
+.SH "OVERVIEW"
+The
+.B mdwopt
+function is a command line options parser which is (mostly) compatible
+with the standard POSIX and GNU
+.B getopt
+functions, although provides more features than either.  It's not the
+most featureful options parser around, but it's good enough for my
+purposes at the moment.
+.SH "OPTION SYNTAX"
+A command line consists of a number of
+.I words
+(which may contain spaces, according to various shell quoting
+conventions).  A word may be an option, an argument to an option, or a
+non-option.  An option begins with a special character, usually
+.RB ` \- ',
+although
+.RB ` + '
+is also used sometimes.  As special exceptions, the word containing only
+a
+.RB ` \- '
+is considered to be a non-option, since it usually represents standard
+input or output as a filename, and the word containing only a
+double-dash
+.RB ` \-\-'
+is used to mark all following words as being non-options regardless of
+their initial character.
+.PP
+Traditionally, all words after the first non-option have been considered
+to be non-options automatically, so that options must be specified
+before filenames.  However, this implementation can extract all the
+options from the command line regardless of their position.  This can
+usually be disabled by setting one of the environment variables
+.B POSIXLY_CORRECT
+or
+.BR _POSIX_OPTION_ORDER .
+.PP
+There are two different styles of options:
+.I short
+and
+.IR long .
+Traditional Unix (and POSIX) only uses short options.  The long options
+are a GNU convention.
+.SS "Short option syntax"
+Short options are the sort which Unix has known for ages: an option is a
+single letter, preceded by a
+.RB ` \-| '.
+Short options can be joined together to save space (and possibly to make
+silly words): e.g., instead of giving options
+.RB ` "\-x \-y" ',
+a user could write
+.RB ` \-xy '.
+Some short options can have arguments which appear after the option
+letter, either immediately following, or in the next word; so an option
+with an argument could be written as
+.RB ` "\-o foo" '
+or as
+.RB ` \-ofoo ').
+Note that options with optional arguments must be written in the second
+style.
+.PP
+When a short option controls a flag setting, it is sometimes possible to
+explicitly turn the flag off, as well as turning it on, (usually to
+override default options).  This is usually done by using a
+.RB ` + '
+instead of a 
+.RB ` \- '
+to introduce the option.  (Some programs use upper-case option letters
+to indicate this instead.)
+.SS "Long option syntax"
+Long options, as popularized by the GNU utilities, are given long-ish
+memorable names, preceded by a double-dash
+.RB ` \-\- '.
+Since their names are more than a single character, long options can't
+be combined in the same way as short options.  Arguments to long options
+may be given either in the same word, separated from the option name by
+an equals sign, or in the following word.
+.PP
+Long option names can be abbreviated if necessary, as long as the
+abbreviation is unique.  This means that options can have sensible and
+memorable names but still not require much typing from an experienced
+user.
+.PP
+Like short options, long options can control flag settings.  The options
+to manipulate these settings come in pairs: an option of the form
+.RB ` \-\-set\-flag '
+might set the flag, while an option of the form
+.RB ` \-\-no\-set\-flag '
+might clear it.
+.PP
+It is usual for applications to provide both short and long options with
+identical behaviour.  Some applications with lots of options may only
+provide long options (although they will often be only two or three
+characters long).  In this case, long options can be preceded with a
+single
+.RB ` \- '
+character, and negated by a
+.RB ` + '
+character.
+.SS "Numerical options"
+Finally, some (older) programs accept arguments of the form
+.RB ` \- \c
+.IR number ',
+to set some numerical parameter, typically a line count of some kind.
+.SH "PARSING OPTIONS WITH \fBmdwopt\fP"
+An application parses its options by calling
+.B mdwopt
+repeatedly.  Each time it is called,
+.B mdwopt
+returns a value describing the option just read, and stores information
+about the option in a data block.
+.PP
+The data block is a structure containing at least the following members:
+.TP
+.B arg
+Pointer to the argument of the current option, or null.  Argument
+strings persist for as long as the underlying command line argument
+array
+.I argv
+does, so it's usually safe just to remember the pointer.
+.TP
+.B opt
+Value of the current option
+.TP
+.B int
+Must be initialized to 0 before the first call to
+.BR mdwopt .
+After the last call, it is the index into
+.I argv
+of the first nonoption argument.
+.TP
+.B err
+Set to nonzero to allow
+.B mdwopt
+to emit error messages about illegal option syntax.  (This would be a
+flag setting, but it has to be here for
+.B getopt
+compatibility.)
+.TP
+.B prog
+Contains the program's name, stripped of any path prefix.  This is an
+obsolete feature: the
+.BR quis (3)
+module does the job in a more sensible way.
+.PP
+Prior to the first call to
+.BR mdwopt ,
+the
+.B err
+and
+.B ind
+members of the structure must be initialized
+.PP
+The arguments
+.I argc
+and
+.I argv
+describe the command-line argument array which is to be parsed.  These
+will usually be exactly the arguments passed to the program's
+.B main
+function.
+.SS "Short option parsing"
+Short options are described by a string,
+.IR shortopt ,
+which once upon a time just contained the permitted option characters.
+Now the options string begins with a collection of flag characters, and
+various flag characters can be put after options characters to change
+their properties.
+.PP
+If the first character of the short options string is
+.RB ` + ',
+.RB ` \- '
+or
+.RB ` ! ',
+the order in which options are read is modified, as follows:
+.TP
+.RB ` + '
+Forces the POSIX order to be used. As soon as a non-option is found,
+.B mdwopt
+returns \-1.
+.TP
+.RB ` \- '
+Makes
+.B mdwopt
+treat non-options as being `special' sorts of option. When a non-option
+word is found, the value 0 is returned, and the actual text of the word
+is stored as being the option's argument.
+.TP
+.RB ` ! '
+forces the default order to be used regardless of environment variable
+settings.  The entire command line is scanned for options, which are
+returned in order.  However, during this process, the options are moved
+in the
+.I argv
+array, so that they appear before the non-options.
+.PP
+A
+.RB ` : '
+character may be placed after the ordering flag (or at the very
+beginning if no ordering flag is given) which indicates that the
+character
+.RB ` : ',
+rather than
+.RB ` ? ',
+should be returned if a missing argument error is detected.
+.PP
+Each option in the string can be followed by a
+.RB ` + '
+sign, indicating that it can be negated, a
+.RB ` : '
+sign indicating that it requires an argument, or a
+.RB ` :: '
+string, indicating an optional argument.  Both
+.RB ` + '
+and one of
+.RB ` : '
+or
+.RB ` :: '
+may be given, although the
+.RB ` + '
+must come first.
+.PP
+If an option is found, the option character is returned to the caller.
+A pointer to an argument is stored in the
+.B arg
+member of the data block; a null pointer is stored if there was no
+argument.  If a negated option was found, the option character is
+returned ORred with
+.B OPTF_NEGATED
+(bit 8 set).
+.SS "Long option parsing"
+Long options are described in a table.  Each entry in the
+table is of type
+.BR "struct option" ,
+which contains the following members (in order):
+.TP
+.B name
+Pointer to the option's name.
+.TP
+.B has_arg
+A flags word describing the option.  (The name is historical.)
+.TP
+.B flag
+Address of the flag variable to use when this option is matched.
+.TP
+.B val
+Value to store or return when this option is matched.
+.PP
+The table is terminated by an entry whose
+.B name
+field is a null pointer.
+.PP
+When
+.B mdwopt
+finds a long option, it looks the name up in the table. The index of the
+matching entry is stored in the
+.I longind
+variable, passed to
+.B mdwopt
+(unless 
+.I longind
+is null): a value of \-1 indicates that no long option was found. The
+behaviour is then dependent on the values in the table entry.
+.PP
+If the flag bit
+.B OPTF_ARGREQ
+is set in
+.B has_arg
+then the option has a required argument, which may be separated from the
+option name by an equals sign or placed in the following word.  If the
+flag bit
+.B OPTF_ARGOPT
+is set then the argument is optional.  If present, the argument must be
+in the same word as the option name, separated by an equals sign.  It is
+an error for both flags to be set; if neither is set then the option
+does not take an argument.
+.PP
+If
+.B flag
+is nonzero, it points to an integer to be modified by
+.BR mdwopt .
+Usually the value in the
+.B val
+field is simply stored in the
+.B flag
+variable. If the flag
+.B OPTF_SWITCH
+is set in the
+.B has_arg
+member, however, the value is combined with the existing value of the
+flags using a bitwise OR.  If
+.B OPTF_NEGATE
+is set in the
+.B has_arg
+field, then the flag bit will be cleared if a matching negated long
+option is found.  The value 0 is returned.
+.PP
+If
+.B flag
+is zero, the value in
+.B val
+is returned by
+.BR mdwopt ,
+possibly with bit 8 set if the option was
+negated.
+.PP
+Arguments for long options are stored in the
+.B arg
+.SS "Other optional features"
+The
+.I flags
+argument contains a bitmask of features which may be enabled:
+.TP
+.B OPTF_NOLONGS
+Don't allow any long options.  This makes
+.B mdwopt
+compatible with traditional Unix
+.BR getopt .
+.TP
+.B OPTF_NOSHORTS
+A slightly misnamed flag.  Short options are read normally.  However,
+long options may also begin with a single dash
+.RB ` \- '
+(or the
+.RB ` + '
+sign if negated).  Long options may not be combined with short options:
+an option word which begins with a short option must contain only short
+options.
+.TP
+.B OPTF_NUMBERS
+Read numeric options.  If a numeric option is found, the character
+.RB ` # '
+is returned and the text of the number is stored in the
+.B arg
+member of the data block.
+.TP
+.B OPTF_NEGATION
+Allow negation of options.  Negated options are returned ORed with
+.BR OPTF_NEGATED .
+.TP
+.B OPTF_ENVVAR
+Options will be read from an environment variable before scanning the
+actual command line provided.  The name of the environment variable is
+found by capitalizing the program name.  (This allows a user to have
+different default settings for a program, by calling it through
+different symbolic links.)
+.TP
+.B OPTF_NOPROGNAME
+Don't read the program name from
+.IR argv \c
+.BR [0] ,
+and don't set the
+.B prog
+data block member.  Options start right at the beginning of
+.IR argv .
+.TP
+.B OPTF_NEGNUMBER
+Allow negated numeric options.  Negated numeric options begin with a
+.RB ` + '
+rather than a
+.RB ` \- '.
+The return value is
+.RB ` # ' " | OPTF_NEGATED" .
+.SS "Compatibility features"
+The macros
+.BR getopt ,
+.B getopt_long
+and
+.B getopt_long_only
+correspond to calls to
+.B mdwopt
+with various flag settings.  See the macro definitions for the actual
+mappings, and the documentation for the functions to see how they're
+meant to work.
+.PP
+Additionally, there is a global data block, which is specified by
+passing a null
+.I data
+argument to
+.BR mdwopt .
+The members of this block may be referred to by their traditional names:
+.TP
+.B optarg
+The argument of the current option.
+.TP
+.B optopt
+Option code of the current option.
+.TP
+.B opterr
+Nonzero if
+.B mdwopt
+is to report errors.  This is the default.
+.TP
+.B optind
+Index of the first non-option argument.
+.TP
+.B optprog
+Name of the program, stripped of path prefix.
+.PP
+These names aren't considered deprecated: they help make the code easier
+to read by people used to the traditional
+.B getopt
+function.
+.SH "SEE ALSO"
+.BR getopt (3),
+.BR mLib (3).
+.SH "AUTHOR"
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/testrig.3 b/man/testrig.3
new file mode 100644 (file)
index 0000000..5d37c26
--- /dev/null
@@ -0,0 +1,174 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.in +5
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.in -5
+.sp 1
+..
+.de hP
+.IP
+.ft B
+\h'-\w'\\$1\ 'u'\\$1\ \c
+.ft P
+..
+.ie t .ds o \(bu
+.el .ds o o
+.TH testrig 3 "5 June 1999" mLib
+.SH NAME
+testrig \- generic test rig
+.\" @test_run
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/testrig.h>"
+
+.BI "void test_run(int " argc ", char *" argv [],
+.BI "              const test_chunk " chunk [],
+.BI "              const char *" def );
+.fi
+.SH DESCRIPTION
+The
+.B test_run
+function is intended to be called from the
+.B main
+function of a test rig program to check that a particular function or
+suite of functions are running properly.  The arguments
+.I argc
+and
+.I argv
+should just be the arguments given to
+.BR main .
+The
+.I def
+argument gives the name of the default file of test vectors to read.
+This can be overridden at run-time by passing the program a
+.B \-f
+command-line option.  The
+.I chunk
+argument is (the address of) an array of
+.I "chunk definitions"
+describing the layout of the test vector file.
+.SS "Test vector file syntax"
+Test vector files are mostly free-form.  Comments begin with a hash
+.RB (` # ')
+and extend to the end of the line.  Apart from that, newline characters
+are just considered to be whitespace.
+.PP
+Test vector files have the following syntax:
+.PP
+.I file
+::=
+.RI [ chunk ...]
+.br
+.I chunk
+::=
+.I name
+.B {
+.RI [ test-vector ...]
+.B }
+.br
+.I test-vector
+::=
+.RI [ value ...]
+.B ;
+.PP
+Briefly in English: a test vector file is divided into chunks, each of
+which consists of a textual name and a brace-enclosed list of test
+vectors.  Each test vector consists of a number of values terminated by
+a semicolon.
+.PP
+A value is either a sequence of
+.I "word characters"
+(alphanumerics and some other characters)
+or a string enclosed in quote marks (double or single).  Quoted strings
+may contain newlines.  In either type of value, a backslash escapes the
+following character.
+.SS "Chunk definitions"
+The caller must supply an array of one or more
+.IR "chunk definitions" .
+Each one describes the format of a named chunk: the number and type of
+the values required and the function to call in order to test the system
+against that test vector.  The array is terminated by a chunk definition
+whose name field is a null pointer.
+.PP
+A chunk definition is described by the following structure:
+.VS
+typedef struct test_chunk {
+  const char *name;             /* Name of this chunk */
+  int (*test)(dstr dv[]);       /* Test verification function */
+  test_type *f[TEST_FIELDMAX];  /* Field definitions */
+} test_chunk;
+.VE
+The members of this structure are as follows:
+.TP
+.I "name"
+The name of the chunk described by this chunk definition, or null if
+this is the termination marker.
+.TP
+.I "test"
+The test function.  It is passed an array of dynamic strings, one for
+each field, and must return nonzero if the test succeeded or zero if the
+test failed.  On success, the function should not write anything to
+stdout or stderr; on failure, a report of the test arguments should be
+emitted to stderr.
+.TP
+.I "f"
+Definitions of the fields.  This is an array of pointers to
+.I "field types"
+(see below), terminated by a null pointer.
+.PP
+When the test driver encounters a chunk it has a definition for, it
+reads test vectors one by one, translating each value according to the
+designated field type, and then passing the completed array of fields to
+the test function.
+.SS "Field types"
+A field type describes how a field is to be read and written.  A field
+type is described by a structure:
+.VS
+typedef struct test_type {
+  void (*cvt)(const char *buf, dstr *d);
+  void (*dump)(dstr *d, FILE *fp);
+} test_type;
+.VE
+The
+.I cvt
+member is a function called to read an input string stored in
+.I buf
+and output internal-format data in the dynamic string
+.IR d .
+The testrig driver has already stripped of quotes and dealt with
+backslash escapes.
+The
+.I dump
+member is called to write the internal-format data in dynamic string
+.I d
+to the
+.B stdio
+stream
+.IR fp .
+.PP
+There are three predefined field types:
+.TP
+.B "type_string"
+The simplest type.  The string contents is not interpreted at all.
+.TP
+.B "type_hex"
+The string is interpreted as binary data encoded as hexadecimal.
+.TP
+.B "type_int"
+The string is interpreted as a textual representation of an integer.
+The integer is written to the dynamic string, and can be read out again
+with the expression
+.VS
+*(int *)d.buf
+.VE
+which isn't pretty but does the job.
+.SH "SEE ALSO"
+.BR mLib (3).
+.SH "AUTHOR"
+Mark Wooding, <mdw@nsict.org>