chiark / gitweb /
Add a slew of manual pages.
authormdw <mdw>
Sun, 20 Jun 1999 23:31:26 +0000 (23:31 +0000)
committermdw <mdw>
Sun, 20 Jun 1999 23:31:26 +0000 (23:31 +0000)
18 files changed:
man/alloc.3 [new file with mode: 0644]
man/base64.3 [new file with mode: 0644]
man/bits.3 [new file with mode: 0644]
man/conn.3 [new file with mode: 0644]
man/crc32.3 [new file with mode: 0644]
man/dspool.3 [new file with mode: 0644]
man/dstr.3 [new file with mode: 0644]
man/exc.3 [new file with mode: 0644]
man/lock.3 [new file with mode: 0644]
man/quis.3 [new file with mode: 0644]
man/report.3 [new file with mode: 0644]
man/sel.3 [new file with mode: 0644]
man/selbuf.3 [new file with mode: 0644]
man/str.3 [new file with mode: 0644]
man/sub.3 [new file with mode: 0644]
man/sym.3 [new file with mode: 0644]
man/tv.3 [new file with mode: 0644]
man/url.3 [new file with mode: 0644]

diff --git a/man/alloc.3 b/man/alloc.3
new file mode 100644 (file)
index 0000000..c0793f0
--- /dev/null
@@ -0,0 +1,68 @@
+.\" -*-nroff-*-
+.TH alloc 3mLib "8 May 1999" "mLib"
+.SH NAME
+alloc \- mLib low-level memory allocation
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/alloc.h>"
+
+.BI "void *xmalloc(size_t " sz );
+.BI "void *xrealloc(void *" p ", size_t " sz );
+.BI "char *xstrdup(const char *" s );
+.fi
+.SH DESCRIPTION
+These functions allocate and return blocks of memory.  If insufficient
+memory is available, an
+.B EXC_NOMEM
+exception is raised.
+.PP
+The
+.B xmalloc
+and
+.B xrealloc
+functions are veneers over the standard
+.BR malloc (3)
+and
+.BR realloc (3)
+functions.
+.B xmalloc
+allocates a block of
+.I sz
+bytes and returns a pointer to the base of the block;
+.B xrealloc
+is given a pointer 
+.I p
+to a block of memory, and returns the address of a new block of size
+.I sz
+bytes with the same contents as the original one (either truncated, if
+the new block is smaller, or padded with rubbish at the end if bigger).
+.PP
+The
+.B xstrdup
+function allocates and returns a block of memory containing a copy of
+the null-terminated string
+.IR p .
+The block is just large enough for the string and its null terminator.
+.PP
+The memory blocks allocated by these functions can be released by
+calling the standard
+.BR free (3)
+function.
+.SH "RETURN VALUE"
+The
+.BR xmalloc ,
+.B xrealloc
+and
+.B xstrdup
+functions return pointers to the blocks they allocated.  They do not
+return if a block couldn't be allocated; instead, the exception
+.B EXC_NOMEM
+is raised.
+.SH "SEE ALSO"
+.BR malloc (3),
+.BR realloc (3),
+.BR free (3),
+.BR exc (3mLib).
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
+
diff --git a/man/base64.3 b/man/base64.3
new file mode 100644 (file)
index 0000000..4e6186b
--- /dev/null
@@ -0,0 +1,89 @@
+.\" -*-nroff-*-
+.TH base64 3mLib "20 June 1999" mLib
+.SH NAME
+base64 \- conversion to and from base64 encoding
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/base64.h>
+
+.BI "void base64_encode(base64_ctx *" ctx ,
+.BI "                   const void *" p ", size_t " sz ,
+.BI "                   dstr *" d );
+.BI "void base64_decode(base64_ctx *" ctx ,
+.BI "                   const void *" p ", size_t " sz ,
+.BI "                   dstr *" d );
+.BI "void base64_init(base64_ctx *" ctx );
+.fi
+.SH DESCRIPTION
+The
+.B base64
+functions perform base64 encoding and decoding of arbitrary binary
+strings.  The base64 encoding is defined by RFC2045.
+.PP
+Before encoding or decoding a string, a
+.I context
+(of type
+.BR base64_ctx )
+must be initialized, by passing it to
+.BR base64_init .
+The context contains data which must be retained between calls to encode
+or decode substrings.  The
+.B base64_init
+function sets up initial values for the data, and sets up defaults for
+the output formatting settings (see below).
+.PP
+Encoding of a string is performed by the
+.B base64_encode
+function.  It is passed a pointer to a context block
+.IR ctx ,
+the input substring to encode passed by address
+.I p
+and length
+.IR sz ,
+and a pointer to a dynamic string
+.I d
+in which to write its output (see
+.BR dstr (3mLib)
+for details on dynamic strings).  Once all the input data has been
+passed through
+.B base64_encode
+it is necessary to flush the final few bytes of output.  This is
+achieved by passing
+.B base64_encode
+a null pointer as its source argument.  It is an error to attempt to
+continue encoding after flushing output.
+.PP
+The output of the
+.B base64_encode
+function is formatted into lines using values from the context
+structure.  The
+.B indent
+member is a pointer to a null-terminated string which is used to
+separate the output lines.  The default indent string contains only a
+newline character.  The
+.B maxline
+member gives the maxmimum length of line that
+.B base64_encode
+is allowed to produce.  If this is not a multiple of 4, it is rounded
+up to the next highest multiple of four before use.  A value of zero
+instructs
+.B base64_encode
+not to perform line splitting: the output will be a single (possibly
+very long) output line.  The default maximum line length is 72
+characters.  You may set these parameters by direct assignment to the
+context structure once it has been initialized.
+.PP
+Decoding is performed similarly by the
+.B base64_decode
+function.  The comments above about flushing output apply equally to
+decoding.
+.PP
+Decoding ignores all whitespace characters in the encoded string.  It
+also ignores
+.RB ` = '
+characters in the string and works out the final block length
+automatically based on the input size.
+.SH "SEE ALSO"
+.BR dstr (3mLib).
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/bits.3 b/man/bits.3
new file mode 100644 (file)
index 0000000..77eeede
--- /dev/null
@@ -0,0 +1,172 @@
+.\" -*-nroff-*-
+.TH bits 3mLib "20 June 1999" mLib
+.SH NAME
+bits \- portable bit manipulation macros
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/bits.h>"
+
+.BI "octet U8(" v );
+.BI "uint16 U16(" v );
+.BI "uint32 U32(" v );
+
+.BI "octet LSL8(" v ", " s );
+.BI "octet LSR8(" v ", " s );
+.BI "uint16 LSL16(" v ", " s );
+.BI "uint16 LSR16(" v ", " s );
+.BI "uint32 LSL32(" v ", " s );
+.BI "uint32 LSR32(" v ", " s );
+
+.BI "octet ROL8(" v ", " s );
+.BI "octet ROR8(" v ", " s );
+.BI "uint16 ROL16(" v ", " s );
+.BI "uint16 ROR16(" v ", " s );
+.BI "uint32 ROL32(" v ", " s );
+.BI "uint32 ROR32(" v ", " s );
+
+.BI "octet GETBYTE(" p ", " o );
+.BI "void PUTBYTE(" p ", " o ", " v );
+
+.BI "octet LOAD8(" p );
+.BI "void STORE8(" p ", " v );
+
+.BI "uint16 LOAD16_B(" p );
+.BI "uint16 LOAD16_L(" p );
+.BI "uint16 LOAD16(" p );
+.BI "void STORE16_B(" p ", " v );
+.BI "void STORE16_L(" p ", " v );
+.BI "void STORE16(" p ", " v );
+
+.BI "uint32 LOAD32_B(" p );
+.BI "uint32 LOAD32_L(" p );
+.BI "uint32 LOAD32(" p );
+.BI "void STORE32_B(" p ", " v );
+.BI "void STORE32_L(" p ", " v );
+.BI "void STORE32(" p ", " v );
+.fi
+.SH DESCRIPTION
+The header file
+.B <mLib/bits.h>
+contains a number of useful definitions for portably dealing with bit-
+and byte-level manipulation of larger quantities.  It declares three
+types:
+.TP
+.B octet
+Equivalent to
+.BR "unsigned char" .
+This is intended to be used when a character array is used to represent
+the octets of some external data format.  Note that on some
+architectures the
+.B "unsigned char"
+type may occupy more than 8 bits.
+.TP
+.B uint16
+Equivalent to
+.BR "unsigned short" .
+Intended to be used when a 16-bit value is required.  This type is
+always capable of representing any 16-bit unsigned value, but the actual
+type may be wider than 16 bits and will require masking.
+.TP
+.B uint32
+Equivalent to some (architecture-dependent) standard type.  Capable of
+representing any unsigned 32-bit value, although the the actual type may
+be wider than 32 bits.
+.PP
+The constants
+.BR MASK8 ,
+.B MASK16
+and
+.B MASK32
+contain bitmasks appropriate for discarding additional bits from a value
+before use as an 8-, 16- or 32-bit quantity.  The macros
+.BR U8 ,
+.B U16
+and
+.B U32
+perform masking and type-coercion on a value, and may be more useful in
+general.  For example,
+.B U16(x)
+yields a value of type
+.B uint16
+which contains (only) the least-significant 16 bits of
+.BR x .
+.PP
+The macros
+.BI LSL n
+and
+.BI LSR n
+perform left and right logical shift operations on values of width
+.IR n ,
+where
+.I n
+is one of
+.BR 8 ,
+.B 16
+or
+.BR 32 .
+The first argument, written
+.IR v ,
+is the value to shift, and the second, written
+.IR s ,
+is the number of bits to shift.  The value
+.I s
+is reduced modulo
+.I n
+before use.  Similarly, the macros
+.BI ROL n
+and
+.BI ROR n
+perform left and right rotations (cyclic shifts) on values of width
+.IR n .
+These macros are all written in such a way as to maximize portability.
+A compiler may be able to spot that simple machine instructions will
+suffice in many cases, although that's not the main objective.
+.PP
+The macros
+.BI LOAD n
+and
+.BI STORE n
+(where again
+.I n
+is one of
+.BR 8 ,
+.B 16
+or
+.BR 32 )
+perform transformations between
+.IR n -bit
+quantities and arrays of octets.  For example,
+.B LOAD32(q)
+returns the 32-bit value stored in the four octets starting at address
+.BR q ,
+and
+.B STORE16(q, x)
+stores the 16-bit value
+.B x
+in the 2 octets starting at address
+.BR q .
+Values are loaded and stored such that the most significant octet is
+assigned the lowest address (i.e., they use network, or big-endian byte
+order).  Macros
+.BI LOAD n _L
+and
+.BI STORE n _L
+are also provided for
+.I n
+either
+.B 16
+or
+.BR 32 :
+they use little-endian byte order.  There are
+explicit big-endian macros
+.BI LOAD n _B
+and
+.BI STORE n _B
+too.  The pointer arguments don't have to be pointers to octets; the
+value arguments don't have to be of the right type.  The macros perform
+all appropriate type casting and masking.  Again, these macros are
+written with portability foremost in mind, although it seems they don't
+actually perform at all badly in real use.
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
+
diff --git a/man/conn.3 b/man/conn.3
new file mode 100644 (file)
index 0000000..60c9510
--- /dev/null
@@ -0,0 +1,76 @@
+.\" -*-nroff-*-
+.TH conn 3mLib "23 May 1999" mLib
+.SH NAME
+conn \- selector for nonblocking connections
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/conn.h>
+
+.BI "void conn_init(conn *" c ", sel_state *" s ", int " fd ,
+.BI "               struct sockaddr *" dst ", int " dsz ,
+.BI "               void (*" func ")(int " fd ", void *" p ),
+.BI "               void *" p );
+
+.BI "void conn_kill(conn *" c );
+.fi
+.SH DESCRIPTION
+The
+.B conn
+selector manages a nonblocking connection to a remote socket.  The
+selector's state is maintained in an object of type
+.BR conn .
+.PP
+Before use, a
+.B conn
+selector must be initialized.  This requires a call to
+.B conn_init
+with a fairly large number of arguments:
+.TP
+.I c
+Pointer to
+.B conn
+object which needs to be initialized.
+.TP
+.I s
+Pointer to a multiplexor object (type
+.BR sel_state )
+to which this selector should be attached.  See
+.BR sel (3mLib)
+for more details about multiplexors, and how this whole system works.
+.TP
+.I fd
+File descriptor for the socket you want to connect.  This becomes the
+`property' of the
+.B conn
+selector until the connection attempt finishes.  For example, if there's
+an error, the descriptor will be closed.
+.TP
+.I dst
+Pointer to destination socket address for the connection.  Make sure
+that the address has the right family.
+.TP
+.I dsz 
+Size of the destination socket address.
+.TP
+.I func
+A function to call when the connection is complete.  It is passed the
+file descriptor of the connected socket, and the pointer passed
+to
+.B conn_init
+as the
+.I p
+argument.  If the connection failed, a file descriptor value of \-1 is
+passed, and the global
+.B errno
+value is set appropriately.
+.TP
+.I p
+An arbitrary pointer whose value is passed to the handler function when
+the connection finishes.
+.PP
+If you want to cancel the connection attempt before it finishes, call
+.B conn_kill
+with the address of the selector.  The file descriptor is closed, and
+the selector becomes safe to be discarded.
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/crc32.3 b/man/crc32.3
new file mode 100644 (file)
index 0000000..911cf5f
--- /dev/null
@@ -0,0 +1,48 @@
+.\" -*-nroff-*-
+.TH crc32 3mLib "8 May 1999" "mLib"
+.SH NAME
+crc32 \- calculate 32-bit CRC
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/crc32.h>"
+
+.BI "int crc32(unsigned long " crc ", const void *" buf ", size_t " sz );
+.BI CRC32( result ", " crc ", " buf ", " sz )
+.fi
+.SH DESCRIPTION
+The
+.B crc32
+function calculates a 32-bit cyclic redundancy check of the data block
+at address
+.I buf
+and size
+.I sz
+passed to it.
+.PP
+The function is restartable.  For a first call, pass zero as the value
+of the
+.I crc
+argument; for subsequent blocks, pass in the previous output.  The final
+answer is equal to the result you'd get from computing a CRC over the
+concatenation of the individual blocks.
+.PP
+The
+.B CRC32
+macro calculates a CRC inline.  The calculated CRC value is placed in
+the variable named by
+.IR result .
+Only use the macro version when efficiency is a major concern: it makes
+the code rather harder to read.
+.PP
+Note that a CRC is not cryptographically strong: it's fairly easy for an
+adversary to construct blocks of data with any desired CRC, or to modify
+a given block in a way which doesn't change its (unknown) CRC.
+.PP
+The exact behaviour of the CRC is beyond the scope of this manual;
+suffice to say that the result is, in some suitable representation, the
+remainder after division in the finite field GF(2^32) of the block by a
+carefully chosen polynomial of order 32.
+.SH "RETURN VALUE"
+The return value is the 32-bit CRC of the input block.
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/dspool.3 b/man/dspool.3
new file mode 100644 (file)
index 0000000..72465dc
--- /dev/null
@@ -0,0 +1,85 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.in +5n
+.ft B
+.nf
+..
+.de VE
+.ft R
+.in -5n
+.sp 1
+.fi
+..
+.TH dspool 3mLib "20 June 1999" mLib
+.SH NAME
+dspool \- pools of preallocated dynamic strings
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/dspool.h>
+
+.BI "void dspool_create(dspool *" p ", size_t " isz );
+.BI "void dspool_destroy(dspool *" p );
+.BI "dstr *dspool_get(dspool *" p );
+.BI "void dspool_put(dspool *" p ", dstr *" d );
+
+.BI "dstr *DSGET(dspool *" p ", d );
+.BI "void DSPUT(dspool *" p ", dstr *" d );
+.fi
+.SH DESCRIPTION
+A dynamic string pool maintains a collection of `spare' dynamic
+strings.  Some pieces of code require high turnover of strings, and
+allocating and freeing them entails a large amount of overhead.  A
+dynamic string pool keeps a list of dynamic strings which have been
+allocated but are not currently in use.
+.PP
+A pool is created by the function
+.BR dspool_create .
+It is passed the address of a pool structure
+.I p
+and the initial size
+.I izs
+to allocate for new dynamic strings obtained from the pool.  A newly
+created pool contains no strings.  Once a pool is no longer required,
+the function
+.B dspool_destroy
+will release all the strings in the pool, such that the pool can safely
+be thrown away.
+.PP
+A string is obtained from a pool by calling
+.BR dspool_get .
+If the pool is empty, a new string is allocated; otherwise a string is
+chosen from those currently in the pool.
+.PP
+A string is returned to the pool by the
+.B dspool_put
+function.  It is passed the address of a pool and the address of a
+string to return.  The string must have been allocated from
+.I some
+dynamic string pool, although it's not actually necessary to return it
+to the pool from which it was allocated.
+.PP
+The macro call
+.VS
+DSGET(p, d);
+.VE
+is equivalent to the assignment
+.VS
+d = dspool_get(p);
+.VE
+(except that it's probably quicker).  The macro
+.B DSPUT
+is entirely equivalent to the function
+.B dspool_put
+except for improved performance.
+.SH CAVEATS
+The string pool allocator requires the suballocator (see
+.BR sub (3mLib)
+for details).  You must ensure that
+.B sub_init
+is called before any strings are allocated from a string pool.
+.SH SEE ALSO
+.BR dstr (3mLib),
+.BR sub (3mLib).
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/dstr.3 b/man/dstr.3
new file mode 100644 (file)
index 0000000..3eec044
--- /dev/null
@@ -0,0 +1,368 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.RS 5
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.RE
+.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 dstr 3mLib "8 May 1999" "mLib"
+dstr \- a simple dynamic string type
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/dstr.h>"
+
+.BI "void dstr_create(dstr *" d );
+.BI "void dstr_destroy(dstr *" d );
+.BI "void dstr_reset(dstr *" d );
+
+.BI "void dstr_ensure(dstr *" d ", size_t " sz );
+.BI "void dstr_tidy(dstr *" d );
+
+.BI "void dstr_putc(dstr *" d ", char " ch );
+.BI "void dstr_putz(dstr *" d );
+.BI "void dstr_puts(dstr *" d ", const char *" s );
+.BI "int dstr_vputf(dstr *" d ", va_list " ap );
+.BI "int dstr_putf(dstr *" d ", ...);
+.BI "void dstr_putd(dstr *" d ", const dstr *" p );
+.BI "void dstr_putm(dstr *" d ", const void *" p ", size_t " sz );
+.BI "int dstr_putline(dstr *" d ", FILE *" fp );
+.BI "size_t dstr_write(const dstr *" d ", FILE *" fp );
+
+.BI "void DCREATE(dstr *" d );
+.BI "void DDESTROY(dstr *" d );
+.BI "void DRESET(dstr *" d );
+.BI "void DENSURE(dstr *" d ", size_t " sz );
+.BI "void DPUTZ(dstr *" d );
+.BI "void DPUTS(dstr *" d ", const char *" s );
+.BI "void DPUTD(dstr *" d ", const dstr *" p );
+.BI "void DPUTM(dstr *" d ", const void *" p ", size_t " sz );
+.BI "size_t DWRITE(const dstr *" d ", FILE *" fp );
+.fi
+.SH SUMMARY
+The header
+.B dstr.h
+declares a type for representing dynamically extending strings, and a
+small collection of useful operations on them.  None of the operations
+returns a failure result on an out-of-memory condition; instead, the
+exception
+.B EXC_NOMEM
+is raised.
+.PP
+Many of the functions which act on dynamic strings have macro
+equivalents.  These equivalent macros may evaluate their arguments
+multiple times.
+.SH "UNDERLYING TYPE"
+A
+.B dstr
+object is a small structure with the following members:
+.VS
+typedef struct dstr {
+  char *buf;           /* Pointer to string buffer */
+  size_t sz;           /* Size of the buffer */
+  size_t len;          /* Length of the string */
+} dstr;
+.VE
+The
+.B buf
+member points to the actual character data in the string.  The data may
+or may not be null terminated, depending on what operations have
+recently been performed on it.  None of the
+.B dstr
+functions depend on the string being null-terminated; indeed, all of
+them work fine on strings containing arbitrary binary data.  You can
+force null-termination by calling the
+.B dstr_putz
+function, or the
+.B DPUTZ
+macro.
+.PP
+The
+.B sz
+member describes the current size of the buffer.  This reflects the
+maximum possible length of string that can be represented in
+.B buf
+without allocating a new buffer.
+.PP
+The
+.B len
+member describes the current length of the string.  It is the number of
+bytes in the string which are actually interesting.  The length does
+.I not
+include a null-terminating byte, if there is one.
+.PP
+The following invariants are maintained by
+.B dstr
+and must hold when any function is called:
+.HP \*o
+If 
+.B sz
+is nonzero, then
+.B buf
+points to a block of memory of length
+.BR sz .
+If
+.B sz
+is zero, then
+.B buf
+is a null pointer.
+.HP \*o
+At all times,
+.BI sz " >= " len\fR.
+.PP
+Note that there is no equaivalent of the standard C distinction between
+the empty string (a pointer to an array of characters whose first
+element is zero) and the nonexistant string (a null pointer).  Any
+.B dstr
+whose
+.B len
+is zero is an empty string.
+.SH "CREATION AND DESTRUCTION"
+The caller is responsible for allocating the
+.B dstr
+structure.  It can be initialized in any of the following ways:
+.HP \*o
+Using the macro
+.B DSTR_INIT
+as an initializer in the declaration of the object.
+.HP \*o
+Passing its address to the
+.B dstr_create
+function.
+.HP \*o
+Passing its address to the (equivalent)
+.B DCREATE
+macro.
+.PP
+The initial value of a
+.B dstr
+is the empty string.
+.PP
+The additional storage space for a string's contents may be reclaimed by
+passing it to the
+.B dstr_destroy
+function, or the
+.B DDESTROY
+macro.  After destruction, a string's value is reset to the empty
+string:
+.I "it's still a valid"
+.BR dstr .
+However, once a string has been destroyed, it's safe to deallocate the
+underlying
+.B dstr
+object.
+.PP
+The
+.B dstr_reset
+function empties a string
+.I without
+deallocating any memory.  Therefore appending more characters is quick,
+beause the old buffer is still there and doesn't need to be allocated.
+Calling
+.VS
+dstr_reset(d);
+.VE
+is equivalent to directly assinging
+.VS
+d->len = 0;
+.VE
+There's also a macro
+.B DRESET
+which does the same job as the
+.B dstr_reset
+function.
+.SH "EXTENDING A STRING"
+All memory allocation for strings is done by the function
+.BR dstr_ensure .
+Given a pointer 
+.I d
+to a
+.B dstr
+and a size
+.IR sz ,
+the function ensures that there are at least
+.I sz
+unused bytes in the string's buffer.  The current algorithm for
+extending the buffer is fairly unsophisticated, but seems to work
+relatively well \- see the source if you really want to know what it's
+doing.
+.PP
+Extending a string never returns a failure result.  Instead, if there
+isn't enough memory for a longer string, the exception
+.B EXC_NOMEM
+is raised.  See
+.BR exc (3mLib)
+for more information about 
+.BR mLib 's
+exception handling system.
+.PP
+Note that if an ensure operation needs to reallocate a string buffer,
+any pointers you've taken into the string become invalid.
+.PP
+There's a macro
+.B DENSURE
+which does a quick inline check to see whether there's enough space in
+a string's buffer.  This saves a procedure call when no reallocation
+needs to be done.  The
+.B DENSURE
+macro is called in the same way as the
+.B dstr_ensure
+function.
+.PP
+The function
+.B dstr_tidy
+`trims' a string's buffer so that it's just large enough for the string
+contents and a null terminating byte.  This might raise an exception due
+to lack of memory.  (There are two possible ways this might happen.
+Firstly, the underlying allocator might just be braindamaged enough to
+fail on reducing a block's size.  Secondly, tidying an empty string with no
+buffer allocated for it causes allocation of a buffer large enough for
+the terminating null byte.)
+.SH "CONTRIBUTING DATA TO A STRING"
+There are a collection of functions which add data to a string.  All of
+these functions add their new data to the
+.I end
+of the string.  This is good, because programs usually build strings
+left-to-right.  If you want to do something more clever, that's up to
+you.
+.PP
+Several of these functions have equivalent macros which do the main work
+inline.  (There still might need to be a function call if the buffer
+needs to be extended.)
+.PP
+Any of these functions might extend the string, causing pointers into
+the string buffer to be invalidated.  If you don't want that to happen,
+pre-ensure enough space before you start.
+.PP
+The simplest function is
+.B dstr_putc
+which appends a single character
+.I ch
+to the end of the string.  It has a macro equivalent called
+.BR DPUTC .
+.PP
+The function
+.B dstr_putz
+places a zero byte at the end of the string.  It does
+.I not
+affect the string's length, so any other data added to the string will
+overwrite the null terminator.  This is useful if you want to pass your
+string to one of the standard C library string-handling functions.  The
+macro
+.B DPUTZ
+does the same thing.
+.PP
+The function
+.B dstr_puts
+writes a C-style null-terminated string to the end of a dynamic string.
+A terminating zero byte is also written, as if
+.B dstr_putz
+were called.  The macro
+.B DPUTS
+does the same job.
+.PP
+The function
+.B dstr_putf
+works similarly to the standard
+.BR sprintf (3)
+function.  It accepts a
+.BR print (3)-style
+format string and an arbitrary number of arguments to format and writes
+the resulting text to the end of a dynamic string, returning the number
+of characters so written.  A terminating zero byte is also appended.
+The formatting is intended to be convenient and safe rather than
+efficient, so don't expect blistering performance.  Similarly, there may
+be differences between the formatting done by
+.B dstr_putf
+and
+.BR sprintf (3)
+because the former has to do most of its work itself.  In particular,
+.B dstr_putf
+doesn't (and probably never will) understand the
+.RB ` n$ '
+positional paramter notation accepted by many Unix C libraries.  There
+is no macro equivalent of
+.BR dstr_putf .
+.PP
+The function
+.B dstr_vputf
+provides access to the `guts' of
+.BR dstr_putf :
+given a format string and a
+.B va_list
+pointer, it will format the arguments according to the format string,
+just as
+.B dstr_putf
+does.
+.PP
+The function
+.B dstr_putd
+appends the contents of one dynamic string to another.  A null
+terminator is also appended.  The macro
+.B DPUTD
+does the same thing.
+.PP
+The function
+.B dstr_putm
+puts an arbitrary block of memory, addressed by
+.IR p ,
+with length
+.I sz
+bytes, at the end of a dynamic string.  No terminating null is appended:
+it's assumed that if you're playing with arbitrary chunks of memory then
+you're probably not going to be using the resulting data as a normal
+text string.  The macro
+.B DPUTM
+works the same way.
+.PP
+The function
+.B dstr_putline
+reads a line from an input stream
+.I fp
+and appends it to a string.  If an error occurs, or end-of-file is
+encountered, before any characters have been read, then
+.B dstr_putline
+returns the value
+.BR EOF.
+Otherwise, it reads until it encounters a newline character, an error,
+or end-of-file, and returns the number of characters read.  If reading
+was terminated by a newline character, the newline character is
+.I not
+inserted in the buffer.  A terminating null is appended, as by
+.BR dstr_putz .
+.SH "OTHER FUNCTIONS"
+The
+.B dstr_write
+function writes a string to an output stream
+.IR fp .
+It returns the number of characters written, or
+.B 0
+if an error occurred before the first write.  No newline character is
+written to the stream, unless the string actually contains one already.
+The macro
+.B DWRITE
+is equivalent.
+.SH "SECURITY CONSIDERATIONS"
+The implemenetation of the
+.B dstr
+functions is designed to do string handling in security-critical
+programs.  However, there may be bugs in the code somewhere.  In
+particular, the
+.B dstr_putf
+functions is quite complicated, and could do with some checking by
+independent people who know what they're doing.
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/exc.3 b/man/exc.3
new file mode 100644 (file)
index 0000000..368a6f8
--- /dev/null
+++ b/man/exc.3
@@ -0,0 +1,250 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.in +5n
+.ft B
+.nf
+..
+.de VE
+.ft R
+.in -5n
+.sp 1
+.fi
+..
+.TH exc 3mLib "20 June 1999" mLib
+.SH NAME
+exc \- exception handling for C programs
+.SH SYNOPSIS
+.B "#include <mLib/exc.h>
+.sp 1
+.B TRY
+.I statement
+.B CATCH
+.I statement
+.B END_TRY;
+.br
+.B EXIT_TRY;
+.sp 1
+.BI "THROW(exc_extype " type
+.RB [ ,
+.IR data ]\fB);
+.br
+.B RETHROW;
+.sp 1
+.nf
+.B "typedef void (*exc__uncaught)(exc_extype, exc_exval);"
+.BI "exc__uncaught exc_uncaught(exc__uncaught " proc );
+
+.BI "exc_extype EXC_PAIR(unsigned char " x ", unsigned char " y );
+.BI "exc_extype EXC_ALLOC(exc_extype " owner ", exc_extype " type );
+.BI "exc_extype EXC_ALLOCN(exc_extype " owner ", exc_extype " type );
+.BI "exc_extype EXC_ALLOCI(exc_extype " owner ", exc_extype " type );
+.BI "exc_extype EXC_ALLOCP(exc_extype " owner ", exc_extype " type );
+.BI "exc_extype EXC_ALLOCS(exc_extype " owner ", exc_extype " type );
+.fi
+.SH DESCRIPTION
+The header file
+.B <mLib/exc.h>
+introduces some new syntax and definitions to support exception handling
+in C.  The marriage is not particularly successful, although it works
+well enough in practice.
+.PP
+The syntax introduced consists of new
+.B TRY
+and
+.B EXIT_TRY
+statements and a pair of new expression types
+.B THROW
+and
+.BR RETHROW .
+It's unfortunately important to remember that the syntax is provided
+using macro expansion and standard C facilities; some of the
+restrictions of these features show through.
+.SS "The TRY statement"
+The
+.B TRY
+statement associates an exception handler with a piece of code.  The
+second statement is an
+.IR "exception handler" .
+Its
+.I "dynamic scope"
+is the duration of the first statement's execution, together with the
+duration of any functions called within the dynamic scope.  (Note in
+particular that an exception handler is not within its own dynamic
+scope.)  A thrown exception causes the exception handler with
+dynamically innermost scope to be executed.
+.PP
+Two special variables are provided to the exception handler:
+.TP
+.B exc_type
+The
+.I type
+of the exception caught.  This is value of type
+.B exc_extype
+(described below).
+.TP
+.B exc_val
+The
+.I value
+of the exception.  This has a union type, with members
+.BR "int i",
+.B "void *p"
+and
+.BR "char *s" .
+Only one of the members is valid; you should be able to work out which
+from the exception type.  There are abbreviations
+.BR "exc_i",
+.B exc_p
+and
+.B exc_s
+which refer to members of
+.B exc_val
+directly.
+.SS "The EXIT_TRY statement"
+It is not safe to leave the dynamic scope of an exception handler early
+(e.g., by a
+.B goto
+statement).  You can force a safe exit from a dynamic scope using the
+.B EXIT_TRY
+statement from within the
+.I lexical
+scope of the
+.B TRY
+statement.
+.SS "The THROW and RETHROW statements"
+The
+.B THROW
+expression throws an exception.  The first argument is the type of
+exception; the second is some data to attach to the exception.  The type
+of data, integer, string or pointer, is determined from the exception
+type.
+.PP
+Control is immediately passed to the exception handler with the
+innermost enclosing dynamic scope.
+.PP
+The
+.B RETHROW
+expression is only valid within an exception handler.  It rethrows the
+last exception caught by the handler.
+.PP
+Neither
+.B THROW
+nor
+.B RETHROW
+yields any value.
+.SS "Exception type allocation"
+Exception types are 32-bit values.  The top 16 bits are an
+.IR "owner identifier" .
+The idea is that each library can have an owner identifier, and it can
+then allocate exceptions for its own use from the remaining space.  Two
+special owner codes are defined:
+.TP
+.B "EXC_GLOBAL (0x0000)"
+The global space defined for everyone's benefit.  Don't define your own
+exceptions in this space.
+.TP
+.B "EXC_SHARED (0xffff)"
+A shared space.  You can use this for any exceptions which won't be seen
+by anyone else.
+.PP
+Other owner codes may be allocated by choosing two characters (probably
+letters) which best suit your application and applying the
+.B EXC_PAIR
+macro to them.  For example, the owner code for
+.B mLib
+would probably be
+.BR "EXC_PAIR('m', 'L')" ,
+if
+.B mLib
+defined any exceptions other then the global ones.
+.PP
+The bottom 16 bits are the actual exception type, and the data type
+which gets passed around with the exception.  The data type is
+(bizarrely) in bits 6 and 7 of the type word.  The data type code is one
+of the following:
+.TP
+.B EXC_NOVAL
+There is no data associated with this exception.
+.TP
+.B EXC_INTVAL
+The data is an integer, with type
+.BR int .
+.TP
+.B EXC_PTRVAL
+The data is a pointer to some data structure, with type
+.BR "void *" .
+Note that you probably have to do an explicit cast to
+.B "void *"
+in the
+.B THROW
+expression.
+.TP
+.B EXC_STRVAL
+The data is a pointer to a string of characters, of type
+.BR "char *" .
+.PP
+If the data to be thrown is a pointer, make sure that the object pointed
+to has a long enough lifetime for it to actually get to its exception
+handler intact.  In particular, don't pass pointers to automatic
+variables unless you're
+.I sure
+they were allocated outside the handler's dynamic scope.
+.PP
+Individual exceptions are allocated by the macros
+.BI EXC_ALLOC t\fR,
+where
+.I t
+is one of:
+.TP
+.B N
+The exception has no data
+.TP
+.B I
+The exception data is an integer.
+.TP
+.B P
+The exception data is a pointer.
+.TP
+.B S
+The exception data is a character string.
+.PP
+The
+.BI EXC_ALLOC t
+macros take two arguments: the owner code (usually allocated with
+.B EXC_PAIR
+as described above), and the type code.  The data type is encoded into
+the exception type by the allocation macro.
+.SS "Predefined exceptions"
+The following exceptions are predefined:
+.TP
+.B EXC_NOMEM
+No data.  Signals an out-of-memory condition.
+.TP
+.B EXC_ERRNO
+Integer data.  Signals an operating system error.  The data is the value
+of
+.B errno
+associated with the error.
+.TP
+.B EXC_OSERROR
+Pointer data.  Signals a RISC\ OS error.  The data is a pointer to the
+RISC\ OS error block.  (Non RISC\ OS programmers don't need to worry
+about this.)
+.TP
+.B EXC_SIGNAL
+Integer data.  Signals a raised operating system signal.  The data is
+the signal number.
+.TP
+.B EXC_FAIL
+String data.  Signals a miscellaneous failure.  The data is a pointer to
+an explanatory string.
+.SH BUGS
+The call to an exception handler is acheived using
+.BR longjmp (3).
+Therefore all the caveats about
+.B longjmp
+and automatic data apply.  Also, note that status such as the signal
+mask is not reset, so you might have to do that manually in order to
+recover from a signal.
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/lock.3 b/man/lock.3
new file mode 100644 (file)
index 0000000..68aebea
--- /dev/null
@@ -0,0 +1,57 @@
+.\" -*-nroff-*-
+.TH lock 3mLib "23 May 1999" mLib
+.SH NAME
+lock \- oversimplified file locking interface
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/lock.h>
+
+.BI "int lock_file(int " fd ", unsigned " how );
+.fi
+.SH DESCRIPTION
+The
+.B lock_file
+function provides an extremely simplistic interface to POSIX
+.BR fcntl (2)
+locking.  It locks only entire files, not sections of files.  It doesn't
+have a nonblocking `is this file locked?' function.
+.PP
+On entry,
+.I fd
+should be a file descriptor on an open file, and
+.I how
+is a constant which describes how the file is to be locked.  The
+possible values of
+.I how
+are:
+.TP
+.B LOCK_EXCL
+Lock the file exclusively.  Attempts to lock the file exclusively or
+nonexclusively will fail until the file is unlocked.
+.TP
+.B LOCK_NONEXCL
+Lock the file nonexclusively.  Until the file is unlocked, attempts to
+lock it exclusively will fail, but other nonexclusive locks will
+succeed.
+.TP
+.B LOCK_UNLOCK
+Unlocks a locked file.  Any locks afterwards can succeed.
+.PP
+The
+.B lock_file
+function will block if it can't obtain a lock immediately.  It will time
+itself out after a short while (10 seconds in the current
+implementation) if the lock doesn't become available.
+.PP
+If the call succeeds,
+.B lock_file
+returns zero.  On failure, \-1 is returned, and
+.B errno
+is set to an appropriate value.  Most of the error returns are from
+.BR fcntl (2)
+(q.v.).  If the lock operation times out,
+.B errno
+is set to
+.BR EINTR .
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/quis.3 b/man/quis.3
new file mode 100644 (file)
index 0000000..3b2cce8
--- /dev/null
@@ -0,0 +1,40 @@
+.\" -*-nroff-*-
+.TH quis 3mLib "22 May 1999" mLib
+.SH NAME
+quis \- remember the program's name for use in messages
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/quis.h>"
+
+.BI "void ego(const char *" p );
+.B "const char *quis(void);"
+.B "const char *QUIS;"
+.fi
+.SH DESCRIPTION
+The
+.B ego
+function should be called early in your program's initialization
+sequence, with the value of
+.B argv[0]
+as its argument.  It will strip away leading path components, and a
+leading `\-' character (in case the program was called as a login
+shell), and keep the resulting short name for later.
+.PP
+The
+.B quis
+function returns the stored program name.  There is also a macro
+.B QUIS
+which expands to the name of a global variable whose value is the string
+returned by
+.BR quis() .
+.PP
+Don't ask why it's done this way.  There are raisins, but they're mostly
+hysterical.
+.PP
+The program name is used in the messages produced by the
+.BR die (3mLib)
+and
+.BR moan (3mLib)
+functions.
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/report.3 b/man/report.3
new file mode 100644 (file)
index 0000000..e9dc226
--- /dev/null
@@ -0,0 +1,41 @@
+.\" -*-nroff-*-
+.TH report 3mLib "20 June 1999" mLib
+.SH NAME
+report \- report errors
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/report.h>"
+
+.BI "void moan(const char *" f ", ...);"
+.BI "void die(int " status ", const char *" f ", ...);"
+.fi
+.SH DESCRIPTION
+The
+.B moan
+function emits a message to the standard error stream consisting of the
+program's name (as read by the
+.B quis
+function; see
+.BR quis (3mLib) for details),
+a colon, a space, and the
+.BR printf -style
+formatted string
+.I f
+followed by a newline.  This is a handy way to report nonfatal errors in
+a program.
+.PP
+The
+.B die
+function emits a message to the standard error stream, just as for
+.B moan
+above, and then calls the
+.B exit
+function with argument
+.I status
+to halt the program.  This is a handy way to report fatal errors in a
+program.
+.SH SEE ALSO
+.BR exit (3),
+.BR quis (3mLib).
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/sel.3 b/man/sel.3
new file mode 100644 (file)
index 0000000..c3e81ae
--- /dev/null
+++ b/man/sel.3
@@ -0,0 +1,258 @@
+.\" -*-nroff-*-
+.TH sel 3mLib "22 May 1999" mLib
+.SH NAME
+sel \- low level interface for waiting for I/O
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/sel.h>"
+
+.BI "void sel_init(sel_state *" s );
+
+.BI "void sel_initfile(sel_state *" s ", sel_file *" f ,
+.BI "                  int " fd ", unsigned " mode ,
+.BI "                  void (*" func ")(int " fd ", unsigned " mode ", void *" p ),
+.BI "                  void *" p );
+.BI "void sel_addfile(sel_file *" f );
+.BI "void sel_rmfile(sel_file *" f );
+
+.BI "void sel_addtimer(sel_state *" s ", sel_timer *" t ,
+.BI "                  struct timeval *" tv ,
+.BI "                  void (*" func ")(struct timeval *" tv ", void *" p ),
+.BI "void sel_rmtimer(sel_timer *" t );
+
+.BI "int sel_select(sel_state *" s );
+.fi
+.SH "OVERVIEW"
+The
+.B sel
+subsystem provides a structured way of handling I/O in a non-blocking
+event-driven sort of a way, for single-threaded programs.  (Although
+there's no reason at all why multithreaded programs shouldn't use 
+.BR sel ,
+it's much less useful.)
+.PP
+The
+.B sel
+subsystem does no memory allocation, and has no static state.  All
+of its data is stored in structures allocated by the caller.  I'll
+explain how this fits in nicely with typical calling sequences below.
+.PP
+Although all the data structures are exposed in the header file, you
+should consider
+.BR sel 's
+data structures to be opaque except where described here, and not fiddle
+around inside them.  Some things may become more sophisticated later.
+.SH "IMPORTANT CONCEPTS"
+The system is based around two concepts:
+.I multiplexors
+and
+.IR selectors .
+.PP
+A
+.I selector
+is interested in some sort of I/O event, which might be something like
+`my socket has become readable', or `the time is now half past three on
+the third of June 2013'.  It has a handler function attached to it,
+which is called when the appropriate event occurs.  Some events happen
+once only ever; some events happen over and over again.  For example, a
+socket might become readable many times, but it's only half-past three
+on the third of June 2013 once.
+.PP
+When a selector is initialized, the caller describes the event the
+selector is interested in, and specifies which function should handle
+the event.  Also, it must specify an arbitrary pointer which is passed
+to the handler function when the event occurs.  This is typically some
+sort of pointer to instance data of some kind, providing more
+information about the event (`it's
+.I this
+socket that's become readable'), or what to do about it.
+.PP
+A multiplexor gathers information about who's interested in what.  It
+maintains lists of selectors.  Selectors must be added to a
+mulitplexor before the events they're interested in are actually watched
+for.  Selectors can be removed again when their events aren't
+interesting any more.  Apart from adding and removing selectors, you can
+.I select
+on a multiplexor.  This waits for something interesting to happen and
+then fires off all the selectors which have events waiting for them.
+.PP
+You can have lots of multiplexors in your program if you like.  You can
+only ask for events from one of them at a time, though.
+.PP
+There are currently two types of selector understood by the low-level
+.B sel
+system: file selectors and timer selectors.  These two types of
+selectors react to corresponding different types of events.  A file
+event indicates that a file is now ready for reading or writing.  A
+timer event indicates that a particular time has now passed (useful for
+implementing timeouts).  More sophisticated selectors can be constructed
+using
+.BR sel 's
+interface.  For examples, see
+.BR selbuf (3mLib)
+and
+.BR conn (3mLib).
+.SH "PROGRAMMING INTERFACE"
+A multiplexor is represented using the type
+.B sel_state
+defined in the
+.B <mLib/sel.h>
+header file.  Before use, a
+.B sel_state
+must be initialized, by passing it to the
+.B sel_init
+function.  The header file talks about `state blocks' a lot \- that's
+because it was written before I thought the word `multiplexor' was
+nicer.
+.PP
+File selectors are represented by the type
+.BR sel_file .
+The interface provides three operations on file selectors:
+initialization, addition to multiplexor, and removal from a
+multiplexor.  It's convenient to separate addition and removal from
+initialization because file selectors often get added and removed many
+times over during their lifetimes.
+.PP
+A file selector is initialized by the
+.B sel_initfile
+function.  This requires a large number of arguments:
+.TP
+.I s
+A pointer to the multiplexor with which the file selector will be
+associated.  This is stored in the selector so that the multiplexor
+argument can be omitted from later calls.
+.TP
+.I f
+Pointer to the file selector object to be initialized.
+.TP
+.I fd
+The file descriptor which the selector is meant to watch.
+.TP
+.I mode
+A constant describing which condition the selector is interested in.
+This must be one of the
+.B SEL_
+constants described below.
+.TP
+.I func
+The handler function which is called when the appropriate condition
+occurs on the file.  This function's interface is described in more
+detail below.
+.TP
+.I p
+An arbitrary pointer argument passed to
+.I func
+when it's called.  Beyond this, no meaning is attached to the value of
+the pointer.  If you don't care about it, just leave it as null.
+.PP
+The mode argument is one of the following constants:
+.TP
+.B SEL_READ
+Raise an event when the file is ready to be read from.
+.TP
+.B SEL_WRITE
+Raise an event when the file is ready to be written to.
+.TP
+.B SEL_EXC
+Raise an event when the file has an `exceptional condition'.
+.PP
+The constant
+.B SEL_MODES
+contains the number of possible file modes.  This is useful internally
+for allocating arrays of the right size.
+.PP
+The functions
+.B sel_addfile
+and
+.B sel_rmfile
+perform the addition and removal operations on file selectors.  They are
+passed only the actual selector object, since the selector already knows
+which multiplexor it's associated with.  A newly initialized file
+selector is not added to its multiplexor: this must be done explicitly.
+.PP
+The handler function for a file multiplexor is passed three arguments:
+the file descriptor for the file, a mode argument which descibes the
+file's new condition, and the pointer argument set up at initialization
+time.
+.PP
+The member
+.B fd
+of the
+.B sel_file
+structure is exported.  It contains the file descriptor in which the
+selector is interested.  You may not modify this value, but it's useful
+to be able to read it out \- it saves having to keep a copy.
+.PP
+Timer selectors are simpler.  There are only two operations provided on
+timer selectors: addition and removal.  Initialization is performed as
+part of the addition operation.
+.PP
+A timer selector is represented by an object of time
+.BR sel_timer .
+.PP
+The function
+.B sel_addtimer
+requires lots of arguments:
+.TP
+.I s
+Pointer to the multiplexor to which the selector is to be added.
+.TP
+.I t
+Pointer to the timer selector object being initialized and added.
+.TP
+.I tv
+A
+.B "struct timeval"
+object describing when the selector should raise its event.  This is an
+.I absolute
+time, not a relative time as required by the traditional
+.BR select (2)
+and
+.BR poll (2)
+system calls.
+.TP
+.I func
+A handler function to be called when the event occurs.  The function is
+passed the
+.I current
+time, and the arbitrary pointer passed to
+.B sel_addtimer
+as the
+.I p
+argument.
+.TP
+.I p
+A pointer passed to
+.I func
+when the timer event occurs.  Beyond this, the value of the pointer is
+not inspected.
+.PP
+The function
+.B sel_rmtimer
+removes a timer selector.  It is passed only the selector object.
+.PP
+Note that timer events are a one-shot thing.  Once they've happened, the
+timer selector is removed and the event can't happen again.  This is
+normally what you want.  Removing a timer is only useful (or safe!)
+before the timer event has been sent.
+.PP
+Finally, the function
+.B sel_select
+is passed a multiplexor object.  It waits for something interesting to
+happen, informs the appropriate selector handlers, and returns.  If
+everything went according to plan,
+.B sel_select
+returns zero.  Otherwise it returns -1, and the global variable
+.B errno
+is set appropriately.
+.SH "OTHER NOTES"
+Although the naming seems to suggest that this is all
+based around the BSD-ish
+.BR select (2)
+system call (and indeed it is), the interface is actually a good deal
+more general than that.  An implementation which worked off System V-ish
+.BR poll (2)
+instead would be fairly trivial to make, and would look just the same
+from the outside.
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/selbuf.3 b/man/selbuf.3
new file mode 100644 (file)
index 0000000..386a718
--- /dev/null
@@ -0,0 +1,89 @@
+.\" -*-nroff-*-
+.TH selbuf 3mLib "23 May 1999" mLib
+.SH NAME
+selbuf \- line-buffering input selector
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/selbuf.h>"
+
+.BI "void selbuf_enable(selbuf *" b );
+.BI "void selbuf_disable(selbuf *" b );
+.BI "void selbuf_init(selbuf *" b ,
+.BI "                 sel_state *" s ,
+.BI "                 int " fd ,
+.BI "                 void (*" func ")(char *" s ", void *" p ),
+.BI "                 void *" p );
+.fi
+.SH DESCRIPTION
+The
+.B selbuf
+subsystem is a selector which integrates with the
+.BR sel (3mLib)
+system for I/O multiplexing.  It reads entire text lines from a file
+descriptor and passes them to a caller-defined function.  It uses the
+line buffer described in
+.BR lbuf (3mLib)
+to do its work: you should read about it in order to understand exactly
+what gets considered to be a line of text and what doesn't, and the
+exact rules about what your line handling function should and shouldn't
+do.
+.PP
+All the data for a
+.B selbuf
+selector is stored in an object of type
+.BR selbuf .
+This object must be allocated by the caller, and initialized using the
+.B selbuf_init
+function.  This requires a fair few arguments:
+.TP
+.I b
+Pointer to the
+.B selbuf
+object to initialize.
+.TP
+.I s
+Pointer to a multiplexor object (type
+.BR sel_state )
+to which this selector should be attached.  See
+.BR sel (3mLib)
+for more details about multiplexors, and how this whole system works.
+.TP
+.I fd
+The file descriptor of the stream the selector should read from.
+.TP
+.I func
+The
+.I "line handler"
+function.  It is passed a pointer to each line read from the file (or
+null to indicate end-of-file) and an arbitrary pointer (the
+.I p
+argument to
+.B selbuf_init
+described below).
+.TP
+.I p
+A pointer argument passed to
+.I func
+for each line read from the file.  Apart from this, the pointer is not
+used at all.
+.PP
+The
+.B selbuf
+selector is immediately active.  Subsequent calls to
+.B sel_select
+on the same multiplexor will cause any complete lines read from the file
+to be passed to your handling function.  This function can at any time
+call
+.B selbuf_disable
+to stop itself from being called any more.  The selector is then
+disengaged from the I/O multiplexor and won't do anything until
+.B selbuf_enable
+is called.  Note that
+.B selbuf_enable
+may well immediately start emitting complete lines of text which were
+queued up from the last I/O operation: it doesn't necessarily wait for
+the next
+.B sel_select
+call.
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/str.3 b/man/str.3
new file mode 100644 (file)
index 0000000..16e859d
--- /dev/null
+++ b/man/str.3
@@ -0,0 +1,136 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.in +5n
+.ft B
+.nf
+..
+.de VE
+.ft R
+.in -5n
+.sp 1
+.fi
+..
+.TH str 3mLib "20 June 1999" mLib
+.SH NAME
+str \- small string utilities
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/str.h>"
+
+.BI "char *str_getword(char **" pp );
+.BI "size_t str_split(char *" p ", char *" v "[], size_t " c ", char **" rest );
+.BI "void str_sanitize(char *" d ", const char *" p ", size_t " sz );
+.fi
+.SH DESCRIPTION
+The header file
+.B <mLib/str.h>
+contains a few small utility functions for manipulating null-terminated
+strings.  
+.PP
+The function
+.B str_getword
+extracts the next whitespace-delimited word from a string.  The
+function's argument,
+.IR pp ,
+is the address of a pointer into the string: this pointer is updated by
+.B str_getword
+so that it can extract the following word on the next call and so on.
+The return value is the address of the next word, appropriately null
+terminated.  A null pointer is returned if the entire remainder of the
+string is whitespace.  Note that
+.B str_getword
+modifies the string as it goes, to null-terminate the individual words.
+.PP
+The function
+.B str_split
+divides a string into whitespace-separated words.  The arguments are as
+follows:
+.TP
+.I p
+The address of the string to split.  The string is modified by having
+null terminators written after each word extracted.
+.TP
+.I v
+The address of an array of pointers to characters.  This array will be
+filled in by
+.BR str_split :
+the first entry will point to the first word extracted from the string,
+and so on.  If there aren't enough words in the string, the remaining
+array elements are filled with null pointers.
+.TP
+.I c
+The maxmimum number of words to extract; also, the number of elements in
+the array
+.IR v .
+.TP
+.I rest
+The address of a pointer in which to store the address of the remainder
+of the string.  Leading whitespace is removed from the remainder before
+storing.  If the remainder string is empty, a null pointer is stored
+instead.  If
+.I rest
+is null, the remainder pointer is discarded.
+.PP
+The return value of
+.B str_split
+is the number of words extracted from the input string.
+.PP
+The function
+.B str_sanitize
+copies at most
+.I sz \- 1
+characters from the string
+.I p
+to
+.IR d .
+The result string is null terminated.  Any nonprinting characters in
+.I p
+are replaced by an underscore
+.RB ` _ '
+when written to
+.IR d .
+.SH EXAMPLES
+Given the code
+.VS
+char p[] = " alpha  beta gamma   delta ";
+char *v[3];
+size_t n;
+char *q;
+
+n = str_split(p, v, 3, &q);
+.VE
+following the call to
+.BR str_split ,
+.B n
+will have the value 3,
+.B v[0]
+will point to
+.RB ` alpha ',
+.B v[1]
+will point to
+.RB ` beta ',
+.B v[2]
+will point to
+.RB ` gamma '
+and
+.B rest
+will point to
+.RB ` delta\  '
+(note the trailing space).
+.PP
+Similarly, given the string
+.B """\ alpha\ \ beta\ """
+instead,
+.B n
+will be assigned the value 2,
+.B v[0]
+and
+.B v[1]
+will have the same values as last time, and
+.B v[2]
+and
+.B rest
+will be null.
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/sub.3 b/man/sub.3
new file mode 100644 (file)
index 0000000..b460506
--- /dev/null
+++ b/man/sub.3
@@ -0,0 +1,100 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.RS 5
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.RE
+.sp 1
+..
+.TH sub 3mLib "8 May 1999" mLib
+.SH NAME
+sub \- efficient allocation and freeing of small blocks
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/sub.h>"
+
+.B "void sub_init(void);"
+.BI "void *sub_alloc(size_t " sz );
+.BI "void sub_free(void *" p ", size_t " sz );
+
+.BI "void *CREATE(" type );
+.BI "void DESTROY(" type " *" p );
+.fi
+.SH DESCRIPTION
+The
+.B sub
+collection of functions and macros implement an efficient allocator for
+small blocks of known sizes.  Free blocks of the same size are linked
+together in list, making freeing and allocation fast.  The `free'
+operation requires the block size as an argument, so there's no data
+overhead for an allocated block.  The system takes advantage of this by
+allocating big chunks from the underlying system (actually via
+.BR xmalloc (3mLib),
+q.v.) and splitting the chunks into smaller blocks of the right size, so
+the space and time overhead from the underlying allocator is divided
+over many blocks.
+.PP
+Calling
+.B sub_alloc
+allocates a block of
+.I sz
+bytes.  If there isn't enough memory to allocate the block, the
+exception
+.B EXC_NOMEM
+is raised.
+.PP
+The
+.B sub_free
+function frees a block allocated by
+.BR sub_alloc .
+You must know the size of the block in advance.  Note that
+.B sub_free
+never gives memory back to the underlying allocator.  Free sub-blocks
+are just made available to later calls of
+.BR sub_alloc .
+.PP
+Don't try to pass blocks allocated by
+.B sub_alloc
+to
+.BR free (3);
+similarly, don't try to pass blocks allocated by
+.BR xmalloc (3mLib)
+or
+.BR malloc (3)
+to
+.BR sub_free .
+If you do, you'll get what you deserve.
+.PP
+The pair of macros
+.B CREATE
+and
+.B DESTROY
+are intended to provide a slightly more natural interface to
+allocation.  The call
+.VS
+mystruct *p = sub_alloc(sizeof(mystruct));
+.VE
+can be replaced by
+.VS
+mystruct p = CREATE(mystruct);
+.VE
+Similarly, the block can be freed by saying
+.VS
+DESTROY(p)
+.VE
+rather than the more cubersome
+.VS
+sub_free(p, sizeof(*p));
+.VE
+The function
+.B sub_init
+must be called before any of the other
+.B sub
+functions or macros.
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/sym.3 b/man/sym.3
new file mode 100644 (file)
index 0000000..10b8084
--- /dev/null
+++ b/man/sym.3
@@ -0,0 +1,214 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.RS 5
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.RE
+.sp 1
+..
+.TH sym 3mLib "8 May 1999" mLib
+.SH NAME
+sym \- symbol table manager
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/sym.h>"
+
+.BI "void sym_create(sym_table *" t );
+.BI "void sym_destroy(sym_table *" t );
+
+.BI "char *SYM_NAME(void *" p );
+.BI "void *sym_find(sym_table *" t ,
+.BI "               const char *" n ", long " l ,
+.BI "               size_t " sz ", unsigned *" f );
+.BI "void sym_remove(sym_table *" t ", void *" b );
+
+.BI "void sym_mkiter(sym_iter *" i ", sym_table *" t );
+.BI "void *sym_next(sym_iter *" i );
+.fi
+.SH "HOW IT WORKS"
+The
+.B sym
+functions implement a data structure often described as a dictionary, a
+finite map, an associative array, or a symbol table.  It associates
+.I values
+with
+.I keys
+such that the value corresponding to a given key can be found quickly.
+Additionally, all stored associations can be enumerated.
+.PP
+The interface provides an
+.I intrusive
+symbol table.  The data objects stored in the table must include a small
+header used by the symbol table manager.  This reduces the amount of
+pointer fiddling that needs to be done, and in practice doesn't seem to
+be much of a problem.  It's also fairly easy to construct a
+non-intrusive interface if you really want one.
+.PP
+There are three main data structures involved in the interface:
+.TP
+.B sym_table
+Keeps track of the information associated with a particular table.
+.TP
+.B sym_base
+The header which must be attached to the front of all the value
+objects.
+.TP
+.B sym_iter
+An iterator object, used for enumerating all of the associations stored
+in a symbol table.
+.PP
+All of the above data structures should be considered
+.IR opaque :
+don't try looking inside.  Representations have changed in the past, and
+they may change again in the future.
+.SH "CREATION AND DESTRUCTION"
+The
+.B sym_table
+object itself needs to be allocated by the caller.  It is initialized by
+passing it to the function
+.BR sym_create .
+After initialization, the table contains no entries.
+.PP
+Initializing a symbol table involves allocating some memory.  If this
+allocation failes, an
+.B EXC_NOMEM
+exception is raised.
+.PP
+When a symbol table is no longer needed, the memory occupied by the
+values and other maintenance structures can be reclaimed by calling
+.BR sym_destroy .
+Any bits of user data attached to the symbol table values should have
+previously been destroyed.
+.SH "ADDING, SEARCHING AND REMOVING"
+Most of the actual work is done by the function
+.BR sym_find .
+It does both lookup and creation, depending on its arguments.  To do its
+job, it needs to know the following bits of information:
+.TP
+.I t
+A pointer to a symbol table to manipulate.
+.TP
+.I n
+The address of the
+.I key
+to look up or create.  Usually this will be a simple text string,
+although it can actually be any arbitrary binary data.
+.TP
+.I l
+The length of the key.  If this is \-1,
+.B sym_find
+assumes that the key is a null-terminated string, and calculates its
+length itself.
+.TP
+.I sz
+The size of the value block to allocate if the key could not be found.
+If this is zero, no value is allocated, and a null pointer is returned
+to indicate an unsuccessful lookup.
+.TP
+.I f
+The address of a `found' flag to set.  This is an output parameter.  On
+exit,
+.B sym_find
+will set the value of
+.BI * f
+to zero if the key could not be found, or nonzero if it was found.  This
+can be used to tell whether the value returned has been newly allocated,
+or whether it was already in the table.
+.PP
+The macro
+.B SYM_NAME
+will return the key associated with a given value block.  You must use
+this macro rather than fiddling inside the
+.B sym_base
+structure.
+.PP
+A symbol can be removed from the table by calling
+.BR sym_remove ,
+passing the symbol table itself, and the value block that needs
+removing.
+.SH ENUMERATION
+Enumerating the values in a symbol table is fairly simple.  Allocate a
+.B sym_iter
+object from somewhere.  Attach it to a symbol table by calling
+.BR sym_mkiter ,
+and passing in the addresses of the iterator and the symbol table.
+Then, each call to
+.B sym_next
+will return a different value from the symbol table, until all of them
+have been enumerated, at which point,
+.B sym_next
+returns a null pointer.
+.PP
+It's safe to remove the symbol you've just been returned by
+.BR sym_next .
+However, it's not safe to remove any other symbol.  So don't do that.
+.PP
+When you've finished with an iterator, it's safe to just throw it away.
+You don't need to call any functions beforehand.
+.SH "USE IN PRACTICE"
+In normal use, the keys are simple strings (usually identifiers from
+some language), and the values are nontrivial structures providing
+information about types and values.
+.PP
+In this case, you'd define something like the following structure for
+your values:
+.VS
+typedef struct val {
+  sym_base _base;      /* Symbol header */
+  unsigned type;       /* Type of this symbol */
+  int dispoff;         /* Which display variable is in */
+  size_t frameoff;     /* Offset of variable in frame */
+} val;
+.VE
+Given a pointer
+.I v
+to a
+.BR val ,
+you can find the variable's name by calling
+.BI SYM_NAME( v )\fR.
+.PP
+You can look up a name in the table by saying something like:
+.VS
+val *v = sym_find(t, name, -1, 0, 0);
+if (!v)
+  error("unknown variable `%s'", name);
+.VE
+You can add in a new variable by saying something like
+.VS
+unsigned f;
+val *v = sym_find(t, name, -1, sizeof(val), &f);
+if (f)
+  error("variable `%s' already exists", name);
+/* fill in v */
+.VE
+You can examine all the variables in your symbol table by saying
+something like:
+.VS
+sym_iter i;
+val *v;
+
+for (sym_mkiter(&i, t); (v = sym_next(&i)) != 0; ) {
+  /* ... */
+}
+.VE
+That ought to be enough examples to be getting on with.
+.SH CAVEATS
+The symbol table manager requires the suballocator (see
+.BR sub (3mLib)
+for details).  You must ensure that
+.B sub_init
+has been called before using any symbol tables in your program.
+.SH IMPLEMENTATION
+The symbol table is an extensible hashtable, using a 32-bit CRC as the
+hash function.  The hash chains are kept very short (probably too short,
+actually).  Every time a symbol is found, its block is promoted to the
+front of its bin chain so it gets found faster next time.
+.SH SEE ALSO
+.BR sub (3mLib).
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/tv.3 b/man/tv.3
new file mode 100644 (file)
index 0000000..71f33f4
--- /dev/null
+++ b/man/tv.3
@@ -0,0 +1,160 @@
+.\" -*-nroff-*-
+.TH tv 3mLib "22 May 1999" mLib
+.SH NAME
+tv \- arithmetic on \fBstruct timeval\fR objects
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/tv.h>"
+
+.BI "void tv_add(struct timeval *" dst ,
+.BI "            const struct timeval *" a ,
+.BI "            const struct timeval *" b );
+.BI "void tv_addl(struct timeval *" dst ,
+.BI "             const struct timeval *" a ,
+.BI "             time_t " sec ", unsigned long " usec );
+.BI "void tv_sub(struct timeval *" dst ,
+.BI "            const struct timeval *" a ,
+.BI "            const struct timeval *" b );
+.BI "void tv_subl(struct timeval *" dst ,
+.BI "             const struct timeval *" a ,
+.BI "             time_t " sec ", unsigned long " usec );
+.BI "int tv_cmp(const struct timeval *" a ,
+.BI "           const struct timeval *" b );
+
+.B "int MILLION;"
+.BI "void TV_ADD(struct timeval *" dst ,
+.BI "            const struct timeval *" a ,
+.BI "            const struct timeval *" b );
+.BI "void TV_ADDL(struct timeval *" dst ,
+.BI "             const struct timeval *" a ,
+.BI "             time_t " sec ", unsigned long " usec );
+.BI "void TV_SUB(struct timeval *" dst ,
+.BI "            const struct timeval *" a ,
+.BI "            const struct timeval *" b );
+.BI "void TV_SUBL(struct timeval *" dst ,
+.BI "             const struct timeval *" a ,
+.BI "             time_t " sec ", unsigned long " usec );
+.BI "int TV_CMP(const struct timeval *" a ", " op ,
+.BI "           const struct timeval *" b );
+.fi
+.SH DESCRIPTION
+The
+.B <mLib/tv.h>
+header file provides functions and macros which perform simple
+arithmetic on objects of type
+.BR "struct timeval" ,
+which is capable of representing times to microsecond precision.
+See your
+.BR gettimeofday (2)
+or
+.BR select (2)
+manpages for details of this structure.
+.PP
+The macros are the recommended interface to
+.BR tv 's
+facilities.  The function interface is provided for compatibility
+reasons, and for bizarre cases when macros won't do the job.
+.PP
+The main arithmetic functions are in three-address form: they accept two
+source arguments and a separate destination argument (which may be the
+same as one or even both of the source arguments).  The destination is
+written before the sources.  All the arguments are pointers to the
+actual structures.
+.PP
+.BI TV_ADD( d ", " x ", " y )
+adds
+.BR timeval s
+.I x
+and
+.I y
+storing the result in
+.IR d .
+Similarly,
+.BI TV_SUB( d ", " x ", " y )
+subtracts
+.I y
+from
+.I x
+storing the result in
+.IR d .
+.PP
+The macros
+.B TV_ADDL
+and
+.B TV_SUBL
+work the same way as
+.B TV_ADD
+and
+.B TV_SUB
+respectively, except their second source operand is expressed
+immediately as two integers arguments expressing a time in seconds and
+microseconds respectively.  Hence,
+.BI TV_ADDL( d ", " s ", 3, 250000)"
+adds 3.25 seconds to
+.I s
+and puts the result in
+.IR d .
+Similarly,
+.BI TV_SUBL( d ", " s ", 3, 250000)"
+subtracts 3.25 seconds from
+.I s
+and puts the answer in
+.IR d .
+.PP
+The function equivalents for the above arithmetic macros work in exactly
+the same way (and indeed have trivial implementations in terms of the
+macros).  The name of the function corresponding to a macro is simply
+the macro name in lower-case.
+.PP
+Two
+.B timeval
+objects can be compared using the
+.B TV_CMP
+macro.  If
+.I op
+is a relational operator (e.g.,
+.RB ` == ',
+.RB ` < ',
+or
+.RB ` >= ')
+then
+.BI TV_CMP( x ", " op ", " y )
+is one when
+.I "x op y"
+is true and zero otherwise.
+.PP
+The function
+.B tv_cmp
+works differently.  Given two arguments
+.I x
+and
+.IR y ,
+it returns -1 if
+.IR x " < " y ,
+zero if
+.IR x " == " y ,
+or 1 if
+.IR x " > " y .
+Hence, the result can be compared against zero in a relatively intuitive
+way (as for
+.BR strcmp (3),
+except that because the results are defined more tightly, it's possible
+to use a
+.B switch
+on the result).
+.SH ACKNOWLEDGEMENT
+The idea of passing a relational operator to
+.B TV_CMP
+is stolen from the
+.B timercmp
+macro in the GNU C library.  I don't know whether this macro is a GNU
+original, but it certainly doesn't seem to be portable.  The
+.B timercmp
+macro had a warning attached to it that it wouldn't work for operators
+like
+.RB ` <= ',
+although I can't see why there'd be a problem.  (If there is one, then
+my implementation has it too, because they're the same.  I don't
+document the restriction because I don't think it exists.)
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
diff --git a/man/url.3 b/man/url.3
new file mode 100644 (file)
index 0000000..f343962
--- /dev/null
+++ b/man/url.3
@@ -0,0 +1,121 @@
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.in +5n
+.ft B
+.nf
+..
+.de VE
+.ft R
+.in -5n
+.sp 1
+.fi
+..
+.TH url 3mLib "20 June 1999" mLib
+.SH NAME
+url \- manipulation of form-urlencoded strings
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/url.h>
+
+.BI "void url_initenc(url_ectx *" ctx );
+.BI "void url_enc(url_ectx *" ctx ", dstr *" d ,
+.BI "             const char *" name ", const char *" value );
+
+.BI "void url_initdec(url_dctx *" ctx ", const char *" p );
+.BI "int url_dec(url_dctx *" ctx ", dstr *" n ", dstr *" v );
+.fi
+.SH DESCRIPTION
+The functions in
+.B <mLib/url.h>
+read and write `form-urlencoded' data, as specified in RFC1866.  The
+encoding represents a sequence of name/value pairs where both the name
+and value are arbitrary binary strings (although the format is optimized
+for textual data).  An encoded string contains no nonprintable
+characters or whitespace.  This interface is capable of decoding any
+urlencoded string; however, it can currently only
+.I encode
+names and values which do not contain null bytes, because the encoding
+interface uses standard C strings.
+.PP
+Encoding a sequence of name/value pairs is achieved using the
+.B url_enc
+function.  It requires as input an
+.IR "encoding context" ,
+represented as an object of type
+.BR url_ectx .
+This must be initialized before use by passing it to the function
+.BR url_initenc .
+Each call to
+.B url_enc
+encodes one name/value pair, appending the encoded output to a dynamic
+string (see
+.BR dstr (3mLib)
+for details).
+.PP
+Decoding a sequence of name/value pairs is performed using the
+.B url_dec
+function.  It requires as input a
+.IR "decoding context" ,
+represented as an object of type
+.BR url_dctx .
+This must be initialized before use by passing it to the function
+.BR url_initdec ,
+along with the address of the urlencoded string to decode.  The string
+is not modified during decoding.  Each call to
+.B url_dec
+extracts a name/value pair.  The name and value are written to the
+dynamic strings
+.I n
+and
+.IR v ,
+so you probably want to reset them before each call.  If there are no
+more name/value pairs to read,
+.B url_dec
+returns zero; otherwise it returns a nonzero value.
+.SH EXAMPLE
+The example code below demonstrates converting between a symbol table
+and a urlencoded representation.  The code is untested.
+.VS
+#include <stdlib.h>
+#include <mLib/alloc.h>
+#include <mLib/dstr.h>
+#include <mLib/sym.h>
+#include <mLib/url.h>
+
+typedef struct {
+  sym_base _b;
+  char *v;
+} val;
+
+void decode(sym_table *t, const char *p)
+{
+  url_dctx c;
+  dstr n = DSTR_INIT, v = DSTR_INIT;
+
+  for (url_initdec(&c, p); url_dec(&c, &n, &v); ) {
+    unsigned f;
+    val *vv = sym_find(t, n.buf, -1, sizeof(*vv), &f);
+    if (f)
+      free(vv->v);
+    vv->v = xstrdup(v.buf);
+    DRESET(&n);
+    DRESET(&v);
+  }
+  dstr_destroy(&n);
+  dstr_destroy(&v);
+}
+
+void encode(sym_table *t, dstr *d)
+{
+  sym_iter i;
+  url_ectx c;
+  val *v;
+
+  url_initenc(&c);
+  for (sym_mkiter(&i, t); (v = sym_next(&i)) != 0; )
+    url_enc(&c, d, SYM_NAME(v), v->v);
+}
+.VE
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>.