From 05fbeb037cbb48a9c86e843becba9d02486868cc Mon Sep 17 00:00:00 2001 Message-Id: <05fbeb037cbb48a9c86e843becba9d02486868cc.1713251393.git.mdw@distorted.org.uk> From: Mark Wooding Date: Tue, 6 Jul 1999 19:13:45 +0000 Subject: [PATCH] New manual pages. Organization: Straylight/Edgeware From: mdw --- man/lbuf.3 | 206 ++++++++++++++++++++++++ man/mLib.3 | 210 ++++++++++++++++++++++++ man/mdwopt.3 | 432 ++++++++++++++++++++++++++++++++++++++++++++++++++ man/testrig.3 | 174 ++++++++++++++++++++ 4 files changed, 1022 insertions(+) create mode 100644 man/lbuf.3 create mode 100644 man/mLib.3 create mode 100644 man/mdwopt.3 create mode 100644 man/testrig.3 diff --git a/man/lbuf.3 b/man/lbuf.3 new file mode 100644 index 0000000..ecd58aa --- /dev/null +++ b/man/lbuf.3 @@ -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 " + +.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 +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, diff --git a/man/mLib.3 b/man/mLib.3 new file mode 100644 index 0000000..ba309f9 --- /dev/null +++ b/man/mLib.3 @@ -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 . +.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, diff --git a/man/mdwopt.3 b/man/mdwopt.3 new file mode 100644 index 0000000..693d0a8 --- /dev/null +++ b/man/mdwopt.3 @@ -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 " + +.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, diff --git a/man/testrig.3 b/man/testrig.3 new file mode 100644 index 0000000..5d37c26 --- /dev/null +++ b/man/testrig.3 @@ -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 " + +.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]