shithub: mc

Download patch

ref: c3f691a1ed4011c460bd24dfffa68f43c0a3eb23
parent: a23019f08b895626d073258d5d20fa3479d73731
author: Ori Bernstein <ori@eigenstate.org>
date: Wed Oct 26 08:35:49 EDT 2016

Clean up .gitignore.

diff: cannot open b/doc/api/libbio//null: file does not exist: 'b/doc/api/libbio//null' diff: cannot open b/doc/api/libdate//null: file does not exist: 'b/doc/api/libdate//null' diff: cannot open b/doc/api/libinifile//null: file does not exist: 'b/doc/api/libinifile//null' diff: cannot open b/doc/api/libregex//null: file does not exist: 'b/doc/api/libregex//null' diff: cannot open b/doc/api/libstd//null: file does not exist: 'b/doc/api/libstd//null' diff: cannot open b/doc/api/libtestr//null: file does not exist: 'b/doc/api/libtestr//null' diff: cannot open b/doc/api/libthread//null: file does not exist: 'b/doc/api/libthread//null' diff: cannot open b/doc/api//null: file does not exist: 'b/doc/api//null'
--- /dev/null
+++ b/doc/api/index.txt
@@ -1,0 +1,91 @@
+{
+        title:  API Reference
+        description:    Myrddin API Reference
+}
+
+This is the page where the Myrddin language is documented. You want to know
+all the boring, dull details? Well, they're here.
+
+APIs
+----
+
+### [Libstd](libstd)
+
+The standard library. You'll probably be using it in all your code, because
+it's the standard. It's intended to cover a good portion of the functionality
+that you'll need for any program. It's a bit of a grab bag, but can be roughly
+categorized into the following subsections:
+
+- [Memory Allocation](libstd/alloc): All of your memory allocation needs.
+- [Error Handling](libstd/err): Convenient utilities for aborting your program.
+- [OS Interfaces](libstd/os): Ask not what you can do for your OS, ask what
+  your OS can do for you.
+- [File Handling](libstd/files): Sometimes data just wants to persist.
+- [Networking](libstd/networking): Communicating with other sytems isn't just
+  a fad.
+- [Command Line Parsing](libstd/cli): Makes it easy to parse options from the
+  commad line.
+- [Formatted Output](libstd/fmt): I/O. Without monads.
+- [Variadic Arguments](libstd/varargs): If you want ugly APIs, we've got you
+  covered.
+- [Slice manipulation](libstd/slices): Some generic functions. Easy to write
+  yourself, but a bit tedious.
+- [String Manipulation](libstd/strings): Some unicode aware string poking.
+- [Unicode](libstd/unicode): Wait a second, all languages aren't english?
+- [Pervasive Data Structures](libstd/datastruct): At least, I use them a lot.
+  If you use them too, we've got you covered.
+- [Misc](libstd/misc): Random crap that doesn't really fit into a category.
+
+### [Libsys](libsys)
+
+Libsys is a direct interface to system calls provided by the platform. It is 
+
+- [Linux Syscalls](libsys/linux)
+- [OSX Syscalls](libsys/osx)
+- [FreeBSD Syscalls](libsys/freebsd)
+- [Plan 9 Syscalls](libsys/plan9)
+
+### [Libbio](/myrddin/doc/libbio)
+
+This is a buffered IO library. It allows for many small reads and writes to be
+done with better performance than writing a system call for each one. On top
+of that, it allows for more convenient interfaces to handle linewise or
+delimited input, where peeking at the input stream may be necessary.
+
+### [Libregex](/myrddin/doc/libregex)
+
+This is a regex library, as implied by the name. It implements a simple but
+powerful regex syntax, with full unicode support. It also exposes the regex
+syntax tree if needed, which is useful for code that wants custom regex
+handling, but wants to remain consistent with the regexes in hairless.
+
+### [Libcryptohash](/myrddin/doc/libcryptohash)
+
+This is a library that handles cryptographic hashes. It implements many of the
+most common cryptographic hashes, and provides a fairly consistent interface
+to it.
+
+### [Libdate](/myrddin/doc/libdate)
+
+Libdate provides a fairly complete interface for manipulating dates, times,
+and timezones. It handles adding durations and periods to dates, formatting
+and parsing dates.
+
+### [Libthread](/myrddin/doc/libthread)
+
+Libthread is currently half assed and broken, and it doesn't work very well
+with libstd, which is not yet thread aware. This needs work.
+
+Utilities
+---------
+
+### [Mbld](/myrddin/doc/mbld)
+
+Mbld is the Myrddin build tool. It knows how to handle source and library
+dependencies, as well as build generated sources.
+
+### [Hairless](/myrddin/doc/mbld)
+
+Hairless is the Myrddin parser generator. It's currently in a half-finished
+state, but is quit
+
--- /dev/null
+++ b/doc/api/libbio/index.txt
@@ -1,0 +1,416 @@
+{
+        title:  libbio
+        description:    BIO library description
+}
+
+Myrddin's BIO library is used for buffered input and output. It is a fairly
+simple library that handles reading and writing from file descriptors.
+
+The concepts in libbio should be familiar to anyone that has used a buffered
+IO library in most languages. The usual concepts are supported: Files,
+formatted output, binary and ascii reads, and so on. There are also some
+utility functions to deal with reading integers in a known endianness.
+
+One thing to keep in mind with libbio that it does not attempt to flush
+buffers on program exit, which means that any unwritten, unflushed data
+will be lost. Closing the bio files will prevent this issue.
+
+Summary
+-------
+
+    pkg bio =
+            type mode
+            const Rd	: mode
+            const Wr	: mode
+            const Rw	: mode
+
+            type file = struct
+            ;;
+
+	    type lineiter
+
+            type status(@a) = union
+                    `Eof
+                    `Ok @a
+                    `Err ioerr
+            ;;
+
+            type ioerr = union
+                    `Ebadfile
+                    `Ebadbuf
+                    `Ebadfd
+                    `Eioerr
+            ;;
+
+	    impl iterable lineiter
+
+            /* creation */
+            const mkfile	: (fd : std.fd, mode : mode	-> file#)
+            const open	: (path : byte[:], mode : mode	-> std.result(file#, byte[:]))
+            const dial	: (srv	: byte[:], mode : mode	-> std.result(file#, byte[:]))
+            const create	: (path : byte[:], mode : mode, perm : int	-> std.result(file#, byte[:]))
+            const close	: (f : file# -> bool)
+            const free	: (f : file# -> void)
+
+            /* basic i/o. Returns sub-buffer when applicable. */
+            const write	: (f : file#, src : byte[:]	-> status(std.size))
+            const read	: (f : file#, dst : byte[:]	-> status(byte[:]))
+            const flush	: (f : file# -> bool)
+
+            /* seeking */
+            const seek	: (f : file#, std.off -> std.result(std.off, ioerr))
+
+            /* single unit operations */
+            const putb	: (f : file#, b : byte	-> status(std.size))
+            const putc	: (f : file#, c : char	-> status(std.size))
+            const getb	: (f : file# -> status(byte))
+            const getc	: (f : file# -> status(char))
+
+            /* peeking */
+            const peekb	: (f : file# -> status(byte))
+            const peekc	: (f : file# -> status(char))
+
+            /* delimited read; returns freshly allocated buffer. */
+            const readln	: (f : file#	-> status(byte[:]))
+            const readto	: (f : file#, delim : byte[:]	-> status(byte[:]))
+            const skipto	: (f : file#, delim : byte[:]	-> bool)
+            const skipspace	: (f : file# -> bool)
+
+            /* iterators */
+            const lineiter	: (f : file# -> lineiter)
+
+            /* formatted i/o */
+            const put	: (f : file#, fmt : byte[:], args : ... -> status(std.size))
+
+            /* unsigned big endian reads */
+            generic getbe8	: (f : file# -> status(@a::(numeric,integral)))
+            generic getbe16	: (f : file# -> status(@a::(numeric,integral)))
+            generic getbe32	: (f : file# -> status(@a::(numeric,integral)))
+            generic getbe64	: (f : file# -> status(@a::(numeric,integral)))
+
+            /* signed big endian reads */
+            generic getle8	: (f : file# -> status(@a::(numeric,integral)))
+            generic getle16	: (f : file# -> status(@a::(numeric,integral)))
+            generic getle32	: (f : file# -> status(@a::(numeric,integral)))
+            generic getle64	: (f : file# -> status(@a::(numeric,integral)))
+
+            /* unsigned big endian */
+            generic putbe8	: (f : file#, v : @a::(numeric,integral) -> status(std.size))
+            generic putbe16	: (f : file#, v : @a::(numeric,integral) -> status(std.size))
+            generic putbe32	: (f : file#, v : @a::(numeric,integral) -> status(std.size))
+            generic putbe64	: (f : file#, v : @a::(numeric,integral) -> status(std.size))
+
+            /* unsigned little endian */
+            generic putle8	: (f : file#, v : @a::(numeric,integral) -> status(std.size))
+            generic putle16	: (f : file#, v : @a::(numeric,integral) -> status(std.size))
+            generic putle32	: (f : file#, v : @a::(numeric,integral) -> status(std.size))
+            generic putle64	: (f : file#, v : @a::(numeric,integral) -> status(std.size))
+    ;;
+
+The Data Structures
+-------------------
+
+    type file = struct
+            fd  : std.fd
+    ;;
+
+The `bio.file` type contains the state required to implement buffered files.
+All of the state is internal, except for the file descriptor, which is exposed
+for the purposes of poll() and friends. Reading from it directly may lead to
+inconsistent buffer state, and is strongly not recommended.
+
+    type ioerr = union
+            `Ebadfile
+            `Ebadbuf
+            `Ebadfd
+            `Eioerr
+    ;;
+
+    type status(@a) = union
+            `Eof
+            `Ok @a
+            `Err ioerr
+    ;;
+
+The `bio.status(@a)` union returns the result of the read operation, which
+is going to either be a result of type '@a', an error-free end of file, or
+an error of type `ioerr`. All of these conditions are transient, and are
+retried on subsequent calls to the IO operations. For example, if reading
+a file returns `Eof, but data is appended to a file, then a subsequent read
+will return data again.
+
+In general, errors will be queued up, so if there is a buffered read or
+write that partly succeeds but is interrupted halfway, the error will be
+reported on the next operation. This way, partial operations are not lost.
+
+File Creation and Opening
+-------------------------
+
+    const Rd	: mode
+    const Wr	: mode
+    const Rw	: mode
+
+When opening a file, one of the above flags must be passed to set the mode
+of the file. `Rd` indicates that the bio file should be read only, `Wr`
+indicates that it should be write only, and `Rw` indicates that it should be
+both readable and writable.
+
+Bio file creation
+-------------
+
+    const mkfile	: (fd : std.fd, mode : mode	-> file#)
+
+This function creates a bio file from a file descriptor and mode, returning a
+`bio.file#` which will buffer reads and/or writes from the fd. This function
+assumes that you are passing it a correctly initialized fd, and will always
+succeed. If the FD is incorrectly configured, uses of it will error out.
+
+Returns: A buffered file wrapping the file descriptor `fd`
+
+    const open	: (path : byte[:], mode : mode	-> std.result(file#, byte[:]))
+
+This function attempts to open the path passed in with the mode, returning
+a result which is either a file, or a string representing the error that
+prevented the file from being opened.
+
+Returns: A buffered file representing `path` opened with the requested
+permissions.
+
+    const dial	: (srv	: byte[:], mode : mode	-> std.result(file#, byte[:]))
+
+This function is similar to open, however, this function will open a
+connection via a dialstring (as in `std.dial`), and buffer the fd returned
+from that.
+
+Returns: A buffered file representing `dialstr` opened with the requested
+permissions.
+
+    const create	: (path : byte[:], mode : mode, perm : int	-> std.result(file#, byte[:]))
+
+This function is similar to open, however, this function will attempt to
+atomically create and open the file descriptor.
+
+Returns: A buffered file representing `path` opened with the requested
+permissions.
+
+    const close	: (f : file# -> bool)
+
+Closes the file descriptor that the bio file is wrapping, and frees any
+resources used for buffering it. Any data that has not yet been written is
+flushed.
+
+Returns: `true` if flushing the file succeeded, `false` if it failed.
+
+    const free	: (f : file# -> void)
+
+Frees any resources used for the file descriptor, but leaves it open. This is
+useful if the file descriptor has been 'stolen' using bio.mkfile, and is not
+owned by the bio file.
+
+    const flush	: (f : file# -> bool)
+
+Clears any data that has not been sent to the backing file descriptor.
+
+Returns: `true` if flushing the file succeeded, `false` if it failed.
+
+Binary I/O
+-----------
+
+    const write	: (f : file#, src : byte[:]	-> result(std.size, byte[:]))
+
+Writes bytes from the buffer `src` to a bio file, returning the number of
+bytes written in the case of success. This number may be smaller than the size
+of the buffer, but will never be larger.
+
+    const read	: (f : file#, dst : byte[:]	-> result(byte[:]))
+
+Reads from a bio file, into the buffer 'dst', returning the section of the
+buffer that was read in the result.
+
+	const seek	: (f : file#, std.off -> std.result(std.off, ioerr))
+
+Seeks the bio file to the given absolute offset.
+
+    const flush	: (f : file# -> bool)
+
+Flush attempts to clear the buffers within `f`, writing everything within
+the buffers and discarding them. If writing fails, `false` is returned.
+
+
+Single Unit Operations
+----------------------
+
+        /* single unit operations */
+    const putb	: (f : file#, b : byte	-> status(std.size))
+
+Writes a single byte out to the file 'f', returning a status. If
+it is successful, the return value represents the number of bytes written.
+For single byte writes, this value is unsurprisingly always 1.
+
+    const putc	: (f : file#, c : char	-> status(std.size))
+
+Writes a single unicode character out to the file 'f', returning a status.
+This character is encoded in utf-8. If it is successful, the return value
+represents the number of bytes written, varying between 1 and 4.
+
+    const getb	: (f : file# -> status(byte))
+
+Reads a single byte from the file `f`, returning a status. If this read
+succeeds, the next byte in the file is returned.
+
+    const getc	: (f : file# -> status(char))
+
+Reads a unicode character from the file `f`, returning a status. If this read
+was successful, the next character is returned from the file. The file is
+assumed to be encoded in utf-8.
+
+    /* peeking */
+    const peekb	: (f : file# -> status(byte))
+    const peekc	: (f : file# -> status(char))
+
+Both peekb and peekc are similar to getb and getc respectively, although
+they return the value without advancing the position within the buffer.
+
+
+Delimited Operations
+--------------------
+
+    /* delimited read; returns freshly allocated buffer. */
+    const readln	: (f : file#	-> status(byte[:]))
+
+Readln reads a single line of input from the file 'f', returning the line
+with the line ending characters removed. '\n', '\r', and '\r\n' are all
+accepted as valid line endings, and are treated interchangably when reading.
+
+The buffer is heap allocated, and must be freed with std.slfree
+
+    const readto	: (f : file#, delim : byte[:]	-> status(byte[:]))
+
+Readto is similar to readln, but instead of reading to a line ending, it will
+read up to the point where it finds the requested delimiter. The delimiter is
+an arbitrary sequence of bytes. If an end of file is reached, then the buffer
+up to the Eof is returned.
+
+The buffer is heap allocated, and must be freed with std.slfree
+
+    const skipto	: (f : file#, delim : byte[:]	-> bool)
+
+Skipto is identical to readto, but instead of allocating a buffer and reading
+into it, skipto will ignore the values and drop them. It returns true for
+any successful reads, and false if an error was encountered.
+
+    const skipspace	: (f : file# -> bool)
+
+Skipspace will consume any space tokens from the start of the input stream, It
+returns true for any successful reads, and false if an error was encountered.
+
+Iteration
+---------
+
+    const lineiter	: (f : file# -> lineiter)
+
+Lineiter will return an interable type that will iterate through each line
+in a file. These lines are allocated on the heap, and are automatically freed
+at the end of the iteration.
+
+The returned iterator object is a value type, and does not need to be freed.
+
+Formatted IO
+-------------
+
+    const put	: (f : file#, fmt : byte[:], args : ... -> status(std.size))
+
+This formats the output using the std.fmt api, and writes it to the file `f`.
+All custom formatters installed for `std.fmt` are used for this formatting.
+This call returns the number of bytes written on success.
+
+Endian Aware Reads
+------------------
+
+    generic getbe8	: (f : file# -> status(@a::(numeric,integral)))
+    generic getbe16	: (f : file# -> status(@a::(numeric,integral)))
+    generic getbe32	: (f : file# -> status(@a::(numeric,integral)))
+    generic getbe64	: (f : file# -> status(@a::(numeric,integral)))
+
+    generic getle8	: (f : file# -> status(@a::(numeric,integral)))
+    generic getle16	: (f : file# -> status(@a::(numeric,integral)))
+    generic getle32	: (f : file# -> status(@a::(numeric,integral)))
+    generic getle64	: (f : file# -> status(@a::(numeric,integral)))
+
+The functions above all read from a bio file, and return the value read on
+success. The 'be' variants read big endian values, and the `le' variants
+read little endian values. They final result is converted to whatever
+numeric, integral type is desired. If the value does not fit within the bounds
+of the type, it is truncated.
+
+The number of bytes read is determined by the number at the end of the
+function call. For eample, `getbe8()` will read 8 bits, or one byte from the
+stream. `getle64` will get a 64 bit, or 8 byte, value. The number of bytes
+consumed is independent of the size of the type being assigned to.
+
+    generic putbe8	: (f : file#, v : @a::(numeric,integral) -> status(std.size))
+    generic putbe16	: (f : file#, v : @a::(numeric,integral) -> status(std.size))
+    generic putbe32	: (f : file#, v : @a::(numeric,integral) -> status(std.size))
+    generic putbe64	: (f : file#, v : @a::(numeric,integral) -> status(std.size))
+
+    generic putle8	: (f : file#, v : @a::(numeric,integral) -> status(std.size))
+    generic putle16	: (f : file#, v : @a::(numeric,integral) -> status(std.size))
+    generic putle32	: (f : file#, v : @a::(numeric,integral) -> status(std.size))
+    generic putle64	: (f : file#, v : @a::(numeric,integral) -> status(std.size))
+
+The functions above all write to a bio file, and return the number of bytes
+written on success. The number of bytes written will always be the size of the
+type. The 'be' variants write the value in a big endian representation, and
+the 'le' variants write it in a little endian representation.
+
+The number of bytes written is determined by the number at the end of the
+function call. For eample, `putbe8()` will write 8 bits, or one byte.
+`putbe64` will write 64 bits, or 8 bytes. The number of
+bytes consumed is independent of the size of the type being assigned to.
+
+Examples
+---------
+
+The example below is the simplest program that creates and opens a file, and
+writes to it. It creates it with 0o644 permissions (ie, rw-r--r--), and then
+immediately closes it. The result of this program should be a file called
+`create-example` containing the words.
+
+    use std
+    use bio
+
+    const main = {
+            var f
+
+            match bio.create("create-example", bio.Wr, 0o644)
+            | `std.Some bio:    f = bio
+            | `std.None:        std.fatal(1, "Failed to open file\n")
+            ;;
+            bio.write(f, "Hello user\n")
+            bio.close(f)
+    }
+
+The next example shows reading from a file called "lines", line by line. It
+should echo the lines, numbering them as it prints them:
+
+    use std
+    use bio
+
+    const main = {
+            var f
+            var i
+
+            match bio.open("lines", bio.Rd)
+            | `std.Some bio:        f = bio
+            | `std.None:    std.fatal(1, "Unable to open data file\n")
+            ;;
+
+            while true
+                    match bio.readlin(f)
+                    | `std.Some ln:
+                            std.put("line %i: %s\n", i, ln)
+                    | `std.None:
+                            break;
+                    ;;
+            ;;
+    }
--- /dev/null
+++ b/doc/api/libdate/formatting.txt
@@ -1,0 +1,99 @@
+{
+	title: Formatting
+	description: Libdate API documentation.
+}
+
+Date and Time Formatting
+---------------------
+
+Formatting in libdate is done through the standard formatting
+functionality, and there are actually no functions exposed by libdate.
+Instead, you would write something like:
+
+```{runmyr stdfmt1}
+use date
+
+const main = {
+	std.put("{}\n", date.now())
+}
+```
+
+Custom formatting is done with a format option passed to std.format that
+looks like `f=dateformat`. The format strings used resemble the strings
+provided in strptime. Any characters preceded with a '%' are format
+characters, otherwise they are copied to the output stream directly.
+
+The format strings used to control formatting are also used to control parsing.
+
+An example would look like:
+
+```{runmyr stdfmt1}
+use date
+
+const main = {
+	std.put("{f=year is %Y, the day is %d}\n", date.now())
+}
+
+
+There are a number of short format options installed, specifically, `d`,
+`D`, and `t`, which respectively map to the default date format, the
+default date and time format, and the default time only format.
+
+```{runmyr stdfmt1}
+use date
+
+const main = {
+	std.put("{d}\n", date.now())
+	std.put("{D}\n", date.now())
+	std.put("{T}\n", date.now())
+}
+```
+
+Date and Time Formatting
+---------------------
+
+Both parsing and formatting use the same format strings. The
+modifiers that are supported by libdate are listed below.
+
+When possible, the default format verbs `D`, `d`, or `t`
+should be used for formatting, and the default constants
+`Datefmt`, `Datetimefmt`, or `Timefmt` should be used for
+parsing.
+
+
+Char  | Meaning
+------|----------------------------------------------
+_%a_  | Abbreviated day of week: Mon, Tues, etc
+_%A_  | Full day of week: Monday, Tuesday, Wednesday, etc
+_%b_  | Abbreviated month of year: Jan, Feb, Mar, etc.
+_%B_  | Full month of year: January, February, etc
+_%c_  | Short for %Y-%m-%d %H:%M:%S %z (ISO 8601)
+_%C_  | Century number of year, as two digit integer.
+_%d_  | Day of month as a decimal number, 00 to 31.
+_%D_  | Short for "%m/%d/%y (wtf america)"
+_%e_  | Same as d, but space padded instead of zero padded.
+_%F_  | Short for ISO 8601 date format %Y-%m-%d
+_%h_  | Same as '%b'.
+_%H_  | Hour number using the 24 hour clock, zero padded.
+_%I_  | Hour number using the 12 hour clock, zero padded.
+_%j_  | Day of year as a decimal number, 001 to 366.
+_%k_  | Hour number using the 24 hour clock, space padded.
+_%l_  | Hour number using the 12 hour clock, space padded.
+_%m_  | The month number, zero padded.
+_%M_  | The minute number, zero padded.
+_%p_  | AM or PM, according to the time provided.
+_%P_  | am or pm, according to the time provided.
+_%r_  | 12 hour time: %I:%M %p
+_%R_  | 24 hour time: %H:%M
+_%s_  | The number of seconds since the Epoch
+_%S_  | The second number, zero padded. 0 to 60.
+_%T_  | The time including seconds in 24 hour format.
+_%u_  | The day of the week in decimal, 0 to 7.
+_%x_  | The date without the time. Same as %F
+_%X_  | The date with the time. Same as %c
+_%y_  | The final two digits of year.
+_%Y_  | The full year, including century. BC dates are negative.
+_%z_  | Timezone offset.
+_%Z_  | Timezone name or abbreviation. Offset if this is not available.
+_%%_  | A literal '%'
+
--- /dev/null
+++ b/doc/api/libdate/index.txt
@@ -1,0 +1,95 @@
+{
+	title: libdate
+	description: Libdate API documentation.
+}
+
+Summary
+-------
+
+Libdate is a date API designed to cover most date related functinality in a
+sane, easy to use way. It will format, parse, and do basic manipulations on
+dates.  All operations are done on the proleptic Gregorian calendar, and the
+Julian to transition is not handled.
+
+Core Concepts
+-------------
+
+### Instants
+
+An instant is a point in time. Immovable, unchanging for eternity, it is
+anchored in one spot through the microseconds of unix time in the UTC time
+zone. It is broken up into a local representation, consisting of years,
+months, days, weekdays, hours, minutes, seconds, and microseconds, with a
+timezone attached.
+
+### Durations
+
+A duration is a difference between two instants. It has a fixed magnitude, and
+is independent of timezones and the oddities of human calendars. It may be
+added or subtracted from instants of other durations. Durations have a
+resolution of microseconds. It is signed, and negative durations move instants
+backwards in time.
+
+### Periods
+
+A period is another form of differece between two instants. However, a period
+is a flighty creature, which does not anchor itself to the world of men in any
+strong way. A year may be 365 or 366 days, according to the whims and vagaries
+of the local calendar. An hour added to a time may jump ahead by two hours, if
+it so desires to follow the savings of daylight. These creatures attempt to
+mold themselves to the irrationalities of man's mind, and eschew the divine
+ordering of absolute time handed down by the prophets.
+
+### Timezones
+
+A timezone is a named zone, as decreed by the mighty IANA timezone database.
+It may take the form of a location such as "America/New_York", a well-known
+abbreviation like "EST", or a special value such as "local" or "", which mean,
+respectively, the current zone or UTC.
+
+Conventions
+-----------
+
+Timezones are pervasive, and no time is manipulated in this API without
+the awareness of the timezone. As a result, it is useful to know that dates
+are represeted using IANA zoneinfo database names. These are documented
+fully here: http://www.iana.org/time-zones
+
+There are two extensions that libdate supports: The empty string represents
+the UTC timezone, and "local" represents the time zone of the system that
+the system libdate is running on has been configured to.
+
+In the case of ambiguous timezones -- for example, parsing a date with no
+time attached, while using API call that does not specify the timezone,
+libdate will assume UTC dates.
+
+Functionality
+-------------
+
+The functionality in libdate can be grouped into three main sections: Parsing,
+Manipulation, and Formatting.
+
+### [Types](types)
+
+This covers the set of all types provided by, and used throughout, the API
+of libdate, including all public fields and types.
+
+### [Parsing](parsing)
+
+This covers parse formatted dates in a manner similar to strptime. There are
+currently plans for an flexible parse() function, but this has not yet been
+implemented.
+
+### [Creation and Manipulation](manipulation)
+
+Manipulation covers date and time creation, and transition aware APIs that
+will work for timezone crossings, daylight savings time, and so on.
+
+#### Formatting
+
+This covers date formatting, which is done through strftime-like format
+strings. There are actually no functions exposed for formatting, as this is
+done through custom formatters for libstd, however, the format strings used
+to customize the date output are described here.
+
+
--- /dev/null
+++ b/doc/api/libdate/manipulation.txt
@@ -1,0 +1,130 @@
+
+{
+	title: Creation and Manipulation
+	description: Libdate API documentation.
+}
+
+Creation and Manipulation
+-------------------------
+    pkg date =
+            /* useful constructors */
+            const utcnow	: (-> instant)
+            const now	: (tz : byte[:] -> instant)
+            const tozone	: (d : instant, zone : byte[:]	-> instant)
+            const mkdate	: (y : int, m : int, day : int, zone : byte[:]	-> instant)
+            const mkdatetime	: (year : int, mon : int, day : int, \
+                    h : int, m : int, s : int, zone : byte[:]	-> instant)
+            const mkinstant	: (tm : std.time, zone : byte[:]	-> instant)
+
+            const localoff	: (tm : std.time -> duration)
+            const tzoff	: (tzname : byte[:], tm : std.time	-> duration)
+            const tzname	: (tzoff : int -> byte[:])
+            const isleap	: (d : instant	-> bool)
+
+            /* date differences */
+            const add	: (d : instant, dt : duration	-> instant)
+            const sub	: (d : instant, dt : duration	-> instant)
+            const addperiod	: (d : instant, dt : period	-> instant)
+            const subperiod	: (d : instant, dt : period	-> instant)
+
+            const duration	: (a : instant, b : instant	-> duration)
+
+            pkglocal const recalc	: (inst : instant# -> std.time)
+    ;;
+
+Creation
+-----------
+
+    const utcnow	: (-> instant)
+
+Creates an instant representing the current time. The timezone is UTC. As a
+general philosophical point, dates written out persisetntly should generally
+be in UTC, so this function should generally be used to get dates.
+
+Returns: An instant representing the current time in the UTC timezone.
+
+    const now	: (tz : byte[:] -> instant)
+
+Creates an instant representing the current time. The timezone is the local
+time. This is useful for displaying dates and times to the user.
+
+Returns: An instant representing the current time in the local timezone.
+
+    const tozone	: (d : instant, zone : byte[:]	-> instant)
+
+Takes an instant and converts it to a new timezone. This takes the instants by
+value, and therefore, does not mutate any of its arguments.
+
+Returns: An instant representing provided time in the requested timezone.
+
+    const mkdate	: (y : int, m : int, day : int, zone : byte[:]	-> instant)
+
+Creates a date with the given year, month, and day in the given timezone. The
+time is set to 0:00:00
+
+Returns: A date representing the given ymd
+
+    const mkdatetime	: (year : int, mon : int, day : int, \
+            h : int, m : int, s : int, zone : byte[:]	-> instant)
+
+Creates a date and time pair with the given year, month, day, at the time
+h, m, s, in the provided timezone. The microseconds are zeroed.
+
+Returns: A date representing the given ymd:hms
+
+    const mkinstant	: (tm : std.time, zone : byte[:]	-> instant)
+
+Creates an instant from a time type. This time can be derived from the
+standard library, or computed from any other source. The time is in
+microseconds since the Unix epoch (Jan 1 1970, 0:00, UTC).
+
+Returns: An instant representing a std.time in the requested timezone
+
+Timezones
+---------
+
+    const localoff	: (tm : std.time -> duration)
+
+Gets the local timezone offset for a time. Note that timezones can change due
+daylight savings, politics, and other similar factors, so a timezone offset
+needs to be associated with a specific instant.
+
+Returns: a duration representing the local timezone offset.
+
+    const tzoff	: (tzname : byte[:], tm : std.time	-> duration)
+
+Gets the timezone offset for a time and timezone pair. Note that timezones can
+change due daylight savings, politics, and other similar factors, so a
+timezone offset needs to be associated with a specific instant.
+
+Returns: a duration representing the requested timezone offset.
+
+    const isleap	: (d : instant	-> bool)
+
+Returns: whether a specific instant is within a leap year or not.
+
+Manipulation
+------------
+    
+    const add	: (d : instant, dt : duration	-> instant)
+    const sub	: (d : instant, dt : duration	-> instant)
+
+Adds or subtracts a duration from a date. A duration is an absolute length of
+time, and is not adjusted for calendar shifts around DST and similar events.
+
+Returns: an instant representing the adjusted time.
+
+    const addperiod	: (d : instant, dt : period	-> instant)
+    const subperiod	: (d : instant, dt : period	-> instant)
+
+Adds or subtracts a period from a date. A period is a humanized length of
+time, and is adjusted for calendar shifts around DST and similar events.
+
+Returns: an instant representing the adjusted time.
+
+    const duration	: (a : instant, b : instant	-> duration)
+
+Returns: the duration representing the difference between the two provided
+instants.
+
+
--- /dev/null
+++ b/doc/api/libdate/parsing.txt
@@ -1,0 +1,74 @@
+{
+	title: Date Parsing
+	description: Libdate API documentation.
+}
+
+Date and time parsing
+---------------------
+
+    type parsefail = union
+            `Doublefmt char
+            `Badsep (char, char)
+            `Badfmt char
+            `Badzone byte[:]
+            `Badname byte[:]
+            `Badchar
+            `Badampm
+            `Shortint
+            `Badint
+    ;;
+
+    const Datetimefmt
+    const Datefmt
+    const Timefmt
+
+    /* date i/o */
+    const parsefmt	: (fmt : byte[:], s: byte[:]	-> std.result(instant, parsefail))
+    const parsefmtl	: (fmt : byte[:], s: byte[:]	-> std.result(instant, parsefail))
+    const parsefmtz	: (fmt : byte[:], s: byte[:], tz : byte[:]	-> std.result(instant, parsefail))
+
+Descriptions
+------------
+
+    const Datetimefmt   = "%Y-%m-%d %H:%M:%S %z"
+    const Datefmt       = "%H:%M:%S %z"
+    const Timefmt       = "%Y-%m-%d %z"
+
+These are "sane defaults" for date and time formats, and can be passed in
+where a format is required.
+
+    type parsefail
+
+Parsefail is an error type, returning descriptions of the error that the
+parsing code saw. Strings returned within the error point into the format
+string, and will be invalid when the format string is freed.
+
+    const parsefmt	: (fmt : byte[:], s: byte[:]	-> std.result(instant, parsefail))
+
+Parses a format string with a format. If there is a timezone specified in the
+format string, that format string will be used. If there is no format, the
+timezone will be assumed to be UTC.
+
+The format string used is similar to strptime, and is documented fully in
+the [description of formatting](/libdate/formatting)
+
+Returns: Either an instant representing the time parsed, or an error
+describing the failure.
+
+    const parsefmtl	: (fmt : byte[:], s: byte[:]	-> std.result(instant, parsefail))
+
+Parses a format into the local time. If a timezone is specified, the
+conversion will be done from the instant of the timezone to the local time.
+The format strings are the same as 'parsefmt'.
+
+Returns: Either an instant representing the time parsed, or an error
+describing the failure.
+
+    const parsefmtz	: (fmt : byte[:], s: byte[:], tz : byte[:]	-> std.result(instant, parsefail))
+
+Parses a format into the specified timezone. If a timezone is specified in the
+parsed date, the conversion will be done from the timezone to the provided
+timezone. The format strings are the same as 'parsefmt'.
+
+Returns: Either an instant representing the time parsed, or an error
+describing the failure.
--- /dev/null
+++ b/doc/api/libdate/types.txt
@@ -1,0 +1,71 @@
+{
+	title: Types
+	description: Libdate API documentation.
+}
+
+Contents
+--------
+
+    pkg date = 
+            type instant = struct
+                    actual	: std.time	/* epoch time in microseconds */
+                    tzoff	: duration	/* timezone offset in microseconds */
+                    year	: int	/* year, != 0 */
+                    mon	: int	/* month, [1..12] */
+                    day	: int	/* day, [1..31] */
+                    wday	: int	/* weekday, [0..6] */
+                    h	: int	/* hour: [0..23] */
+                    m	: int	/* minute: [0..59] */
+                    s	: int	/* second: [0..59] */
+                    us	: int	/* microsecond: [0..999,999] */
+                    tzname	: byte[:]	/* current time zone name */
+            ;;
+
+            type duration = std.time
+
+            type period = union
+		`Year	int
+		`Month	int
+		`Day	int
+		`Hour	int
+		`Minute	int
+		`Second	int
+	;;
+    ;;
+
+Descriptions
+------------
+
+    type instant
+
+Instant represents a single instant of time, with a resolution
+of microseconds. It contains the actual instant in the member
+`actual`, which is a timestamp in microseconds since Jan 1, 1970
+at 00:00 in UTC, and breaks out the "humanized" time out into the
+various members that are exposed.
+
+The instant type always has a timezone attached, and the humanized
+time components are always in that timezone.
+
+    type duration
+
+A duration is an absolute number of microseconds that can be added
+or subtracted from an instant. This is not timezone adjusted.
+
+    type period
+
+A period is a time delta that is adjusted for crossing timezones,
+daylight savings, and other similar events. If you add a day to
+an instant, you would get the same wallclock time the next day,
+should that wallclock time exist.
+
+For example, if I were to add `\`Day 2` to the instant 
+`Oct 31 2015 3:00`, then the result would be the date
+`Nov 2 2015 3:00`, regardless of the daylight savings time adjustment.
+However, adding `\`Hour 48` would not have that effect.
+
+In cases where the adjustment does not exist -- for example, leap years,
+then the time will "wrap around" to the next available day. For example,
+Feb 29th on a leap year will become Mar 1st.
+
+
--- /dev/null
+++ b/doc/api/libinifile/index.txt
@@ -1,0 +1,135 @@
+{
+	title: libinifile
+	description: Libinifile API documentation.
+}
+
+Summary
+-------
+
+	pkg inifile =
+		type error = union
+			`Fileerr
+			`Parseerr int
+			`Dupkey int
+		;;
+
+		type inifile =
+		;;
+		
+		/* reading */
+		const load	: (path : byte[:]	-> std.result(inifile#, error))
+		const loadf	: (file : std.fd	-> std.result(inifile#, error))
+		const free	: (ini : inifile#	-> void)
+
+		/* writing */
+		const write	: (ini : inifile#, path : byte[:]	-> bool)
+
+		/* key getting/setting */
+		const get	: (ini : inifile#, sect : byte[:], key : byte[:]	-> std.option(byte[:]))
+		const getv	: (ini : inifile#, sect : byte[:], key : byte[:], val : byte[:]	-> byte[:])
+		const has	: (ini : inifile#, sect : byte[:], key : byte[:] -> bool)
+		const put	: (ini : inifile#, sect : byte[:], key : byte[:], val : byte[:]	-> void)
+	;;
+
+
+Overview
+--------
+
+Libinifile is a simple ini file parser. It does little interpretation of the
+data, and provides little in the way of convenience features. Loading will
+read the file into memory, and will not reflect changes of the on-disk data.
+
+Functions
+---------
+
+	const load	: (path : byte[:]	-> std.result(inifile#, error))
+
+Load will read a file from disk, parsing it, and returning either a pointer to
+an `inifile` data structure, or an error reporting the problem parsing it, and
+if applicable, the line that the error occurred on.
+
+This data structure must be freed with `inifile.free()`.
+
+	const loadf	: (file : std.fd	-> std.result(inifile#, error))
+
+This is identical to `inifile.load`, only it reads from a `std.fd` that has
+already been opened in read mode, instead of a path.
+
+	const free	: (ini : inifile#	-> void)
+
+Releases all storage associated with an inifile data structure.
+
+	const write	: (ini : inifile#, path : byte[:]	-> bool)
+
+Write will take the content of an infile, and serialize it to disk. Comments
+from the original ini file are not currently preserved.
+
+	const get	: (ini : inifile#, sect : byte[:], key : byte[:]	-> std.option(byte[:]))
+	const getv	: (ini : inifile#, sect : byte[:], key : byte[:], val : byte[:]	-> byte[:])
+
+Get and getv act like `std.hget` and `std.htgetv`. They will retrieve an entry
+from the ini file.
+
+Htget will return `\`std.Some val` if the key is present in the given section,
+or `\`std.None` if there is no value present in the ini file. Htgetv will
+return the default value `val` passed to it if the key is not found.
+
+For a key that is outside of a section, the empty string (`""`) should be
+passed for the section name.
+
+	const has	: (ini : inifile#, sect : byte[:], key : byte[:] -> bool)
+
+Queries whether a key is present in the ini file. Returns true if the key is
+present, or false if it is not.
+
+	const put	: (ini : inifile#, sect : byte[:], key : byte[:], val : byte[:]	-> void)
+
+Places a key value pair into the in-memory representation of the .ini file.
+This key value pair added if it is not present, and replaced if it is. The key
+and value are both copied, and ownership is not taken. The responsibility for
+freeing the previous value lies with the ini file implementation.
+
+Supported Syntax
+--------------
+
+The dialect that it supports allows for a list of zero or more key-value pairs
+before any sections are declared, followed by a list of sections containing
+more key value pairs.
+
+Keys are any sequence of characters, excluding an '=' sign. Values are any
+sequence of characters. For both of these, both leading and trailing white
+space is ignored.
+
+Sections are lists of characters started by `[` and end by `]`. The only
+character disallowed within a section name is `]`. Leading and trailing
+whitespace is stripped from a section.
+
+Keys within a file must be unique, otherwise this is an error.
+
+Section declarations may repeat throughout the file, but this will merely
+switch back into the old section.
+
+Example
+------
+
+Assuming that an file named `demo.ini` exists, and contains the following
+text:
+
+	toplev = hey, there's a value!
+	[section]
+		key = wait, there's another
+
+Then the following program will read it and show the values of the keys:
+
+	use std
+	use inifile
+
+	const main = {
+		var ini
+
+		ini = std.try(inifile.load("demo.ini"))
+		std.put("{}\n", inifile.getv(ini, "", "toplev", "not present")
+		std.put("{}\n", inifile.getv(ini, "section", "key", "not present")
+		inifile.free(ini)
+	}
+
--- /dev/null
+++ b/doc/api/libregex/index.txt
@@ -1,0 +1,279 @@
+{
+	title: libregex
+	description: Libregex API documentation.
+}
+
+Summary
+-------
+
+	pkg regex =
+                type ast = union
+                        /* basic string building */
+                        `Alt	(ast#, ast#)
+                        `Cat	(ast#, ast#)
+
+                        /* repetition */
+                        `Star	ast#
+                        `Rstar  ast#
+                        `Plus	ast#
+                        `Rplus	ast#
+                        `Quest	ast#	
+
+                        /* end matches */
+                        `Chr	char
+                        `Ranges	char[2][:]
+
+                        /* meta */
+                        `Cap	(std.size, ast#) /* id, ast */
+                        `Bol	/* beginning of line */
+                        `Eol	/* end of line */
+                        `Bow	/* beginning of word */
+                        `Eow	/* end of word */
+                ;;
+
+                type status = union
+                        `Noimpl
+                        `Incomplete
+                        `Unbalanced char
+                        `Emptyparen
+                        `Badrep char
+                        `Badrange byte[:]
+                        `Badescape char
+                ;;
+
+	/* regex compilation */
+        const parse	: (re : byte[:]	-> std.result(ast#, status))
+        const compile	: (re : byte[:] -> std.result(regex#, status))
+        const dbgcompile	: (re : byte[:] -> std.result(regex#, status))
+        const free	: (re : regex# -> void)
+
+        /* regex execution */
+        const exec	: (re : regex#, str : byte[:] -> std.option(byte[:][:]))
+        const search	: (re : regex#, str : byte[:] -> std.option(byte[:][:]))
+
+        const sub	: (re : regex#, str : byte[:], subst : byte[:][:] -> std.option(byte[:]))
+        const sbsub	: (sb : std.strbuf#, re : regex#, str : byte[:], subst : byte[:][:] -> bool)
+        const suball	: (re : regex#, str : byte[:], subst : byte[:][:] -> byte[:])
+        const sbsuball	: (sb : std.strbuf#, re : regex#, str : byte[:], subst : byte[:][:] -> void)
+
+        const matchfree	: (pat : byte[:][:] -> void)
+    ;;
+
+
+Overview
+--------
+
+Libregex is a simple regex API that uses a parallel NFA implementation. This
+means that while it is not blazingly fast, it does not exhibit pathological
+behavior on regexes like `(aa|aab?)\*` that many common regex APIs will see.
+
+Regex Syntax
+-------------
+
+The grammar for regexes that are accepted is sketched out below.
+
+           regex       : altexpr
+           altexpr     : catexpr ('|' altexpr)+
+           catexpr     : repexpr (catexpr)+
+           repexpr     : baseexpr[*+?][?]
+           baseexpr    : literal
+                       | charclass
+                       | charrange
+                       | '.'
+                       | '^'
+                       | '$'
+                       | '(' regex ')'
+           charclass   : see below
+           charrange   : '[' (literal('-' literal)?)+']'
+
+The following metacharacters have the meanings listed below:
+
+Matches a single unicode character
+
+<table>
+	<tr><tr><th>Metachar</th>        <th>Description</th></tr>
+	<tr><td><code>^</td></code>      <td>Matches the beginning of a line. Does not consume any characters.</td></tr>
+	<tr><td><code>$</td></code>      <td>Matches the end of a line. Does not consume any characters.</td></tr>
+	<tr><td><code>*</td></code>      <td>Matches any number of repetitions of the preceding regex fragment.</td></tr>
+	<tr><td><code>+</td></code>      <td>Matches one or more repetitions of the preceding regex fragment.</td></tr>
+	<tr><td><code>?</td></code>      <td>Matches zero or one of the preceding regex fragment.</td></tr>
+</table>
+
+In order to match a literal metacharacter, it needs to be preceded by a '\' character.
+
+The following character classes are supported:
+
+<table>
+	<tr><tr><th>Charclass</th>       <th>Description</th></tr>
+	<tr><td><code>\d </code></td>    <td>ASCII digits</td></tr>
+	<tr><td><code>\D </code></td>    <td>Negation of ASCII digits</td></tr>
+	<tr><td><code>\x </code></td>    <td>ASCII Hex digits</td></tr>
+	<tr><td><code>\X </code></td>    <td>Negation of ASCII Hex digits</td></tr>
+	<tr><td><code>\s </code></td>    <td>ASCII spaces</td></tr>
+	<tr><td><code>\S </code></td>    <td>Negation of ASCII spaces</td></tr>
+	<tr><td><code>\w </code></td>    <td>ASCII word characters</td></tr>
+	<tr><td><code>\W </code></td>    <td>Negation of ASCII word characters</td></tr>
+	<tr><td><code>\h </code></td>    <td>ASCII whitespace characters</td></tr>
+	<tr><td><code>\H </code></td>    <td>Negation of ASCII whitespace characters</td></tr>
+	<tr><td><code>\pX</code></td>    <td>Characters with unicode property 'X'</td></tr>
+	<tr><td><code>\PX</code></td>    <td>Negation of characters with property 'X'</td></tr>
+</table>
+
+The current list of supported Unicode character classes `X` are
+
+<table>
+	<tr><th>Abbrev</th> <th>Full name</th>      <th>Description</th></tr>
+	<tr>
+		<td><code>L</code></td>  <td><code>Letter</code></td>
+		<td>All letters, including lowercase, uppercase, titlecase,
+		and uncased.</td>
+	</tr>
+	<tr>
+		<td><code>Lu</code></td> <td><code>Uppercase_Letter</code></td>
+		<td>All uppercase letters.</td>
+	</tr>
+	<tr>
+		<td><code>Ll</code></td> <td><code>Lowercase_Letter</code></td>
+		<td>All lowercase letters.</td>
+	</tr>
+	<tr>
+		<td><code>Lt</code></td> <td><code>Titlecase_Letter</code></td>
+		<td>All titlecase letters.</td>
+	</tr>
+	<tr>
+		<td><code>N</code></td>  <td><code>Number</code></td>
+		<td>All numbers.</td>
+	</tr>
+	<tr>
+		<td><code>Z</code></td>  <td><code>Separator</code></td>
+		<td>All separators, including spaces and control characers.</td>
+	</tr>
+	<tr>
+		<td><code>Zs</code></td> <td><code>Space_Separator</code></td>
+		<td>All space separators, including tabs and ASCII spaces.</td>
+        </tr>
+</table>
+
+Functions
+---------
+
+    const parse	: (re : byte[:]	-> std.result(ast#, status))
+
+Parse takes a regex string, and converts it to a regex syntax tree, returning
+`\`std.Success ast#` if the regex was valid, or a `\`std.Failure r` if the
+regex could not be parsed. This AST can be used to further process the regex,
+possibly turning it into a multiregex as in Hairless, or using it for NFA and
+DFA tricks.
+
+    const compile	: (re : byte[:] -> std.result(regex#, status))
+    const dbgcompile	: (re : byte[:] -> std.result(regex#, status))
+
+`compile` takes a regex string, and converts it to a compiled regex, returning
+`\`std.Success regex` if the regex was valid, or a `\`std.Failure r` with the
+reason that the compilation failed. `dbgcompile` is similar, however, the
+regex is compiled so it will spit out a good deal of debugging output. Unless
+you are intent on debugging the internals of the regex engine, this is likely
+only of academic interest.
+
+    const free	: (re : regex# -> void)
+
+`free` must be called on a compiled regex to release it's resources after you
+are finished using it.
+
+    const exec	: (re : regex#, str : byte[:] -> std.option(byte[:][:])
+
+`exec` runs the regex over the specified text, returning an `\`std.Some matches`
+if the text matched, or `std.None` if the text did not match. matches[0] is
+always the full text that was matched, and will always be returned regardless
+of whether capture groups are specified.
+
+    const search	: (re : regex#, str : byte[:] -> std.option(byte[:][:]))
+
+`search` searches for a matching sub-segment of the regex over the specified
+text, returning an `\`std.Some matches` if the text matched, or `std.None` if
+the text did not match.  matches[0] is always the full text that was matched,
+and will always be returned regardless of whether capture groups are
+specified. `search` returns the the earliest match in the string provided.
+
+
+    const sub	: (re : regex#, str : byte[:], subst : byte[:][:] -> std.option(byte[:]))
+    const sbsub	: (sb : std.strbuf#, re : regex#, str : byte[:], subst : byte[:][:] -> bool)
+
+`sub` will take a pattern, an input string, and a set of substitutions, and
+attempt to match. If the match is successful, it will replace each group
+within `str` with `subst`, returning a freshly allocated string.  `sbsub`
+behaves identically, however it inserts the new string into the string
+buffer provided, instead of allocating a new string.
+
+If there is no match, then `\`std.None` will be returned.
+
+    const suball	: (re : regex#, str : byte[:], subst : byte[:][:] -> byte[:])
+    const sbsuball	: (sb : std.strbuf#, re : regex#, str : byte[:], subst : byte[:][:] -> void)
+
+`suball` replaces every match within the string using the given substitutions.
+Only captured groups will be substituted. The remaining text will be left in
+place.
+
+Example
+------
+
+#### Pattern matching
+
+```{runmyr regex}
+use std
+use regex
+
+const main = {
+	match regex.compile("ab(c+)")
+	| `std.Ok re:	runwith(re, "abccc")
+	| `std.Fail m:	std.fatal("Failed to compile regex\n")
+	;;
+}
+
+const runwith = {re, txt
+	match regex.exec(re, txt)
+	| `std.Some matches:
+		std.put("matched {}, got {} matches\n", txt, matches.len)
+		for m in matches
+			std.put("Match: {}\n", m)
+		;;
+		regex.matchfree(matches)
+	| `std.None:
+		std.put("%s did not match\n")
+	;;
+}
+```
+
+#### Substitution
+
+```{runmyr regex}
+use std
+use regex
+
+const main = {
+	var re
+
+	re = std.try(regex.compile("(a*)bc(d)e"))
+	match regex.sub(re, "aaabcdef", ["HEY", "X"][:])
+	| `std.Some sub:
+		std.put("{}\n", sub[0])
+		regex.matchfree(matches)
+	| `std.None:
+		std.fatal("should have matched")
+	;;
+}
+```
+
+```{runmyr regex}
+use std
+use regex
+
+const main = {
+	var re, sub
+
+	re = std.try(regex.compile("(b|e)"))
+        sub = regex.suball(re, "aaabbbcdef", ["SUB"][:])
+	std.put("subst: {}\n", sub)
+	std.slfree(sub)
+}
+```
--- /dev/null
+++ b/doc/api/libstd/algorithms.txt
@@ -1,0 +1,129 @@
+{
+        title:  Algorithms
+        description:    libstd: Algorithms
+}
+
+Algorithms
+----------
+
+    pkg std =
+            /* the result of a comparison */
+            type order = union
+                    `Before
+                    `Equal
+                    `After
+            ;;
+
+            /* sorting and searching */
+            generic sort	: (sl:@a[:], cmp:(a:@a, b:@a -> order) -> @a[:])
+            generic lsearch	: (sl : @t[:], val : @t, cmp : (a : @t, b : @t -> order) -> option(@idx::(integral,numeric)))
+            generic bsearch	: (sl : @t[:], val : @t, cmp : (a : @t, b : @t -> order) -> option(@idx::(integral,numeric)))
+            generic swap	: (a : @a#, b : @a# -> void)
+
+            /* prepackaged comparisons */
+            generic numcmp	: (a : @a, b : @a -> order)
+            const strcmp	: (a : byte[:], b : byte[:] -> order)
+            const strncmp	: (a : byte[:], b : byte[:], n : size -> order)
+
+            /* extrema and absolute values */
+            generic min	: (a : @a::numeric, b : @a::numeric  -> @a::numeric)
+            generic max	: (a : @a::numeric, b : @a::numeric  -> @a::numeric)
+            generic clamp	: (a : @a::numeric, min : @a::numeric, max : @a::numeric -> @a::numeric)
+            generic abs	: (a : @a::numeric -> @a::numeric)
+    ;;
+
+Overview
+--------
+
+There are a number of algorithms that are pervasive through many programs.
+These include sorting, searching, and similar
+
+We only cover sorting and searching here, although more would be a good
+addition. Maybe in a separate library.
+
+Types
+-----
+
+    type order = union
+            `Before
+            `Equal
+            `After
+    ;;
+
+When comparing, it's useful to have an ordering between values. The order type
+is the result of a comparison, `a CMP b` describing whether the first value
+`a` comes before, after, or is equivalent to `b`.
+
+Functions: Sorting and Searching
+--------------------------------
+
+    generic sort	: (sl:@a[:], cmp:(a:@a, b:@a -> order) -> @a[:])
+
+This function will sort a slice, modifying it in place. The comparison
+function `cmp` is used to decide how to order the slice. This comparison
+function must be transitive -- in otherwords, if A comes before B, and B comes
+before C, then A must come before C. This is true of most comparisons, but
+some care should be taken when attempting to provide "humanized" sorting.
+
+Returns: the same slice it was pased. The slice will not be reallocated or
+moved.
+
+    generic lsearch	: (sl : @t[:], val : @t, cmp : (a : @t, b : @t -> order) -> option(@idx::(integral,numeric)))
+
+Performs a linear search for a value using the comparison predicate `cmp`. The
+slice is walked in order until the first value where `cmp` returns `\`Equal`.
+
+Returns: `\`Some idx`, or `\`None` if the value is not present.
+
+    generic bsearch	: (sl : @t[:], val : @t, cmp : (a : @t, b : @t -> order) -> option(@idx::(integral,numeric)))
+
+Performs a binary search for a value using the comparison predicate `cmp`. The
+input slice `sl` must be sorted according to the comparsion function `cmp`
+such that for a value at index `idx`, the comparison `cmp(sl[idx - 1],
+sl[idx])` must return either `\`Before` or `\`Equal`.
+
+If there are multiple equal copies value within a list, the index retuned is
+not defined.
+
+Returns: `\`Some idx`, or `\`None` if the value is not present.
+
+    generic swap	: (a : @a#, b : @a# -> void)
+
+Takes two pointers to two values, and switches them. If the pointers are
+equal, this is a no-op.
+
+    generic numcmp	: (a : @a::numeric, b : @a::numeric -> order)
+    const strcmp	: (a : byte[:], b : byte[:] -> order)
+    const strncmp	: (a : byte[:], b : byte[:], n : size -> order)
+
+These functions are helpers for comparing values. They will compare any two
+numeric values, and will return the ordering between the two.
+
+Numcmp simply returns the result comparing whether `a` is less than `b`,
+relying on the behavior of the built in operators.
+
+Strcmp and strncmp will do a lexicographical comparison, comparing strings
+byte by byte. This is a useful and correct behavior for both strings of
+arbitrary data, and utf8 encoded strings, where it is equivalent to doing
+a comparison by codepoint.
+
+Functions: Extrema and Clamping
+-------------------------------
+
+    generic min	: (a : @a::numeric, b : @a::numeric  -> @a::numeric)
+    generic max	: (a : @a::numeric, b : @a::numeric  -> @a::numeric)
+
+Min and max return the larger or smaller of the two numeric values passed to
+them, respectively. They rely on the built in comparison functions.
+
+    generic clamp	: (a : @a::numeric, min : @a::numeric, max : @a::numeric -> @a::numeric)
+
+Clamp clamps the value `a` to the range [min, max], and returns it. This means
+that if `a` is lower than `min`, or greater than `max`, it is adjusted to
+those bounds and returned.
+
+    generic abs	: (a : @a::numeric -> @a::numeric)
+
+Abs returns the absolute value of a number. This means that if the number is
+less than 0, it is retuned with the sign inverted. If the type `@a` is
+unsigned, then this function is a no-op.
--- /dev/null
+++ b/doc/api/libstd/alloc.txt
@@ -1,0 +1,160 @@
+{
+        title:  Allocation
+        description:  libstd: Allocation
+}
+
+Memory Allocation
+-----------------
+
+    pkg std =
+            generic mk	: (val : @a -> @a#)
+            generic alloc	: (		-> @a#)
+            generic zalloc	: (		-> @a#)
+            generic free	: (v:@a#	-> void)
+            generic slalloc	: (len : size	-> @a[:])
+            generic slzalloc	: (len : size	-> @a[:])
+            generic slgrow	: (sl : @a[:]#, len : size	-> @a[:])
+            generic slzgrow	: (sl : @a[:]#, len : size	-> @a[:])
+            generic slfree	: (sl : @a[:]	-> void)
+            const bytealloc	: (sz:size	-> byte#)
+            const zbytealloc	: (sz:size	-> byte#)
+            const bytefree	: (m:byte#, sz:size	-> void)
+    ;;
+
+    generic mk	: (val : @a -> @a#)
+
+`mk` creates a shallow copy of variable passed to it on the heap, returning a
+pointer to the value that it allocated. It is conventionally used for creating
+new copies of larger complex data structures, although it can be used to
+heapify any value.
+
+Returns: Pointer to fully initialized value of type '@a', based on the value
+passed in.
+
+    generic alloc	: (		-> @a#)
+    generic zalloc	: (		-> @a#)
+
+`alloc` allocates or free a single element of type @a, respectively. `zalloc`
+does the same, but zeros the memory allocated before returning it. `free` is
+used to return the memory allocated by these functions to the system. In
+general, `mk` is preferred over these functions, as it does not leave any
+values uninitialized.,
+
+    generic slalloc	: (len : size	-> @a[:])
+    generic slzalloc	: (len : size	-> @a[:])
+
+`slalloc` allocates or frees a slice of `len` items of type @a. `slzalloc`
+does the same, but zeros the memory allocated before returning it. `slfree`
+is used to return the memory to the system.
+
+    generic slgrow	: (sl : @a[:]#, len : size	-> @a[:])
+    generic slzgrow	: (sl : @a[:]#, len : size	-> @a[:])
+
+`slgrow` resizes the slize `sl` to length `len`, allocating the appropriate
+amount of memory. `slzgrow` does the same, but any elements between the old
+and new length are zeroed, as in slzalloc.
+
+    generic free	: (v:@a#	-> void)
+    generic slfree	: (sl : @a[:]	-> void)
+
+`free` and `slfree` free the storage allocated allocated for the value or
+slice passed to them , allowing it to be reused again later in the program.
+This memory may be unmapped and returned to the operating system, or it may be
+cached within the program.
+
+Any uses of memory after a `free` call is invalid.
+
+    const bytealloc	: (sz:size	-> byte#)
+    const zbytealloc	: (sz:size	-> byte#)
+    const bytefree	: (m:byte#, sz:size	-> void)
+
+`bytealloc` `bytezalloc`, and `bytefree` are the low level raw-byte allocation
+interface, returning blobs of bytes. Since the only way to use more than one
+of these bytes is to cast to a different type, the generic versions are
+generally a better choice.
+
+Examples
+---------
+
+Overall, the examples here should not be unfamiliar to anyone who has used
+either C or C++.
+
+### Mk
+
+`std.mk` should be used to create new, fully constructed values wherever
+possible. The code for this looks like:
+
+```{runmyr mk-example}
+use std
+
+type mytype =
+	a : int
+	b : char
+	c : byte[:[
+;;
+
+const main = {
+        var v
+
+        v = std.mk([
+            .a = 123
+            .b = 'x'
+            .c = "my string" /* this isn't heapified */
+        ])
+
+        std.free(v)
+}
+```
+
+### Alloc and Zalloc
+
+`alloc` and `zalloc` know the type that they're being assigned to, and use
+this to calulate the size to allocate:
+
+
+```{runmyr mk-example}
+use std
+
+const main = {
+        var x : int#
+        var y : int#
+
+        x = std.alloc()
+        y = std.zalloc()
+        std.free(x)
+        std.free(y)
+}
+```
+
+### Slalloc and Slzalloc
+
+`slalloc` and `slzalloc` take a size to allocate, but infer the type similar
+to `alloc` and `zalloc`. They're freed with std.slfree() and slzfree().
+Thankfully, unlike C++ delete and delete[], it's impossible to pass a slice
+to the wrong free function.
+
+
+```{runmyr mk-example}
+use std
+
+const main = {
+        var x : int[:]
+
+        x = std.slalloc(10)     /* slice of 10 ints */
+        std.slfree(x)
+}
+```
+
+Growing slices can be done using slgrow() and slzgrow():
+
+```{runmyr mk-example}
+use std
+
+const main = {
+        var x : int[:]
+
+        x = std.slalloc(10)     /* slice of 10 ints */
+        x = std.slzgrow(x, 20)     /* x[10:20] are guaranteed to be zeroed.*/
+        std.slfree(x)
+}
+```
--- /dev/null
+++ b/doc/api/libstd/bigint.txt
@@ -1,0 +1,208 @@
+{
+        title:  Bigints
+        description:  libstd: Bigints
+}
+
+Bigints
+-------
+
+  pkg std =
+            type bigint = struct
+            ;;
+
+            generic mkbigint	: (v : @a::(numeric,integral) -> bigint#)
+            const bigfree	: (a : bigint# -> void)
+            const bigdup	: (a : bigint# -> bigint#)
+            const bigassign	: (d : bigint#, s : bigint# -> bigint#)
+            const bigmove	: (d : bigint#, s : bigint# -> bigint#)
+            const bigparse	: (s : byte[:] -> option(bigint#))
+            const bigclear	: (a : bigint# -> bigint#)
+            const bigbfmt	: (b : byte[:], a : bigint#, base : int -> size)
+            const bigtoint	: (a : bigint#	-> @a::(numeric,integral))
+            const bigiszero	: (a : bigint# -> bool)
+            const bigeq	: (a : bigint#, b : bigint# -> bool)
+            const bigcmp	: (a : bigint#, b : bigint# -> order)
+            const bigadd	: (a : bigint#, b : bigint# -> bigint#)
+            const bigsub	: (a : bigint#, b : bigint# -> bigint#)
+            const bigmul	: (a : bigint#, b : bigint# -> bigint#)
+            const bigdiv	: (a : bigint#, b : bigint# -> bigint#)
+            const bigmod	: (a : bigint#, b : bigint# -> bigint#)
+            const bigdivmod	: (a : bigint#, b : bigint# -> (bigint#, bigint#))
+            const bigshl	: (a : bigint#, b : bigint# -> bigint#)
+            const bigshr	: (a : bigint#, b : bigint# -> bigint#)
+            const bigmodpow	: (b : bigint#, e : bigint#, m : bigint# -> bigint#)
+            const bigpow	: (a : bigint#, b : bigint# -> bigint#)
+            generic bigeqi	: (a : bigint#, b : @a::(numeric,integral) -> bool)
+            generic bigaddi	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+            generic bigsubi	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+            generic bigmuli	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+            generic bigdivi	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+            generic bigshli	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+            generic bigshri	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+            const bigpowi	: (a : bigint#, b : uint64 -> bigint#)
+    ;;
+
+
+Overview
+--------
+
+While bigint usage in most programs is relatively rare, libstd needs them
+internally for handling floats, and several other widely used pieces of
+functionality also need them.
+
+This set of code covers the bulk of common big integer operations: Creation,
+input, output, and various arithmetic operations
+
+By convention, with a few exceptions, all operations on bigintegers will
+modify the bigint in place, and return a pointer to the first argument
+of the function. This allows for easy chaining of operations.
+
+A formatter for bigintegers is installed by default, so `std.put("{}\n",
+mybig)` will show  a reasonably formatted big integer. The standard `x`
+modifier is recognized to print the value in hex.
+
+Types
+-----
+
+    type bigint = struct
+    ;;
+
+This is a big integer. It stores big integers. Like it was an integer. But
+bigger.
+
+
+
+Functions: Bookkeeping and IO
+-----------------------
+
+    generic mkbigint	: (v : @a::(numeric,integral) -> bigint#)
+
+Mkbigint takes a regular small int, and creates a biginteger from that
+value. It allocates the value on the heap, returning a pointer to the bigint
+instance. This instance must be freed with `bigfree`.
+
+    const bigfree	: (a : bigint# -> void)
+
+Cleans up the storage associated with the bigint `a`.
+
+    const bigdup	: (a : bigint# -> bigint#)
+
+Bigdup creates a new biginteger, and copies the value from the original
+biginteger `a` into it. It returns a new biginteger.
+
+    const bigassign	: (d : bigint#, s : bigint# -> bigint#)
+
+Bigassign copies the value of the bigint `s` to `d`, and returns
+a pointer to `d`. No allocations or new values are created.
+
+    const bigmove	: (d : bigint#, s : bigint# -> bigint#)
+
+Bigmove clears the value of `d`, and moves the value from `s` into
+it efficiently, tearing down the value of `s` in the process. It
+returns a pointer to `d`.
+
+For example, if you had the `a=123` and `b=246`, then moving `a <= b`,
+the final values would be `a = 246` and `b = 0`.
+
+No new values are allocated.
+
+    const bigparse	: (s : byte[:] -> option(bigint#))
+
+Bigparse converts a string representation of an integer into a bigint,
+returning `\`Some val` if the string is a valid bigint, or `\`None` otherwise.
+
+Decimal, hex, octal, and binary biginteger strings are recognized. Decimal
+is the default, and is recognized unprefixed. Hex must be prefixed with `0x`,
+octal must be prefixed with `0o`, and binary must be prefixed with `0b`. As
+with all Myrddin integers, '_' is accepted and ignored within numerical
+constants.
+
+    const bigclear	: (a : bigint# -> bigint#)
+
+Bigclear zeroes out a biginteger, returning it.
+
+    const bigtoint	: (a : bigint#	-> @a::(numeric,integral))
+
+
+Bigtoint returns the low order digits of a bigint as an integer value. Care
+must be taken when using this function to ensure that values are not
+undesirably truncated.
+
+Functions: Arithmetic
+---------------------
+
+    const bigiszero	: (a : bigint# -> bool)
+
+Bigiszero checks if a bigint is zero, and returns true if it is, or false if
+it is not.
+
+    const bigeq	: (a : bigint#, b : bigint# -> bool)
+
+Bigeq compares whether two integers are equal.
+
+    const bigcmp	: (a : bigint#, b : bigint# -> order)
+
+Bigcmp compares two big integers, and returns the ordering between them.
+`\`Before` if a < b, `\`After` if a > b, and `\`Equal` if the two values
+are equal.
+
+    const bigadd	: (a : bigint#, b : bigint# -> bigint#)
+    const bigsub	: (a : bigint#, b : bigint# -> bigint#)
+    const bigmul	: (a : bigint#, b : bigint# -> bigint#)
+    const bigdiv	: (a : bigint#, b : bigint# -> bigint#)
+    const bigmod	: (a : bigint#, b : bigint# -> bigint#)
+    const bigshl	: (a : bigint#, b : bigint# -> bigint#)
+    const bigshr	: (a : bigint#, b : bigint# -> bigint#)
+    const bigmodpow	: (b : bigint#, e : bigint#, m : bigint# -> bigint#)
+    const bigpow	: (a : bigint#, b : bigint# -> bigint#)
+
+All of these functions follow the convention mentioned in the summary: They
+apply the operation `a = a OP b`, where `a` is the first argument, and `b`
+is the second argument. They return `a`, without allocating a new result.
+
+    const bigdivmod	: (a : bigint#, b : bigint# -> (bigint#, bigint#))
+
+Bigdivmod is an exception to the above convention. Because it needs to return
+two values, it returns a tuple of newly allocated bigints.
+
+    generic bigeqi	: (a : bigint#, b : @a::(numeric,integral) -> bool)
+    generic bigaddi	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+    generic bigsubi	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+    generic bigmuli	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+    generic bigdivi	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+    generic bigshli	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+    generic bigshri	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+    const bigpowi	: (a : bigint#, b : uint64 -> bigint#)
+
+All of these are identical ot the bigint operations above, however instead of
+taking a bigint for their second operand, they take an integer. This is useful
+for when operations like multiplication or division by a small constant is
+needed.
+
+Examples
+--------
+
+```{runmyr bigcmp}
+
+use std
+use bio
+
+const main = {args : byte[:][:]
+        var f
+
+        a = try(std.bigparse("1234_5678_1234_6789_6666_7777_8888"))
+        b = try(std.bigparse("0x75f3_fffc_1123_5ce4"))
+
+        match std.bigcmp(a, b)
+        | `std.Equal:   "{} is equal to {}\n", a, b)
+        | `std.Before:  "{} is less than {}\n", a, b)
+        | `std.After:  "{} is greater than {}\n", a, b)
+        ;;
+
+        std.bigmul(a, b)
+        std.bigdivi(a, 42)
+        std.put("a * b / 42 = {}\n", a)
+
+        std.bigfree(a, b)
+}
+```
--- /dev/null
+++ b/doc/api/libstd/cli.txt
@@ -1,0 +1,290 @@
+{
+        title:  CLI Parsing
+        description:  libstd: CLI Parsing
+}
+
+
+Command Line Parsing
+--------------------
+
+Command line parsing is something that nearly every program needs. This
+section of libstd provides simple command line parsing with autogenerated
+help.
+
+    pkg std =
+            type optdef = struct
+                    argdesc	: byte[:]	/* the description for the usage */
+                    minargs	: std.size	/* the minimum number of positional args */
+                    maxargs	: std.size	/* the maximum number of positional args (0 = unlimited) */
+                    noargs	: std.bool	/* whether we accept args at all */
+                    opts	: optdesc[:]	/* the description of the options */
+            ;;
+            type optdesc = struct
+                    opt	: char
+                    arg	: byte[:]
+                    desc	: byte[:]
+                    optional	: bool
+            ;;
+            type optparsed = struct
+                    opts	: (char, byte[:])[:]
+                    args	: byte[:][:]
+            ;;
+
+            const optparse	: (optargs : byte[:][:], def : optdef# -> optparsed)
+            const optusage	: (prog : byte[:], def : optdef# -> void)
+    ;;
+
+Syntax
+-------
+
+A command line is composed of a list of words, known as. These arguments may
+be options that the program can act on, known as "flags". These flags may take
+up to one argument. To avoid confusing with the top level arguments, this
+document will refer to them as "values". Anything that is not a flag is a
+"positional argument", or simply an "argument".
+
+In general, the POSIX syntax for arguments is followed, with a few minor
+enhancements. Myrddin program will use the following semantics for command
+line options:
+
+ - Arguments are groupls of flags if they follow a '-'. A flag is any
+   single unicode character, potentially followed by a single value. This
+   value may be optional.
+ - Flags that take values will consume the remainder of the argument as
+   the value. If the remainder of the argument is empty, then the next
+   argument is consumed as the value. For example, `-foo` and `-f oo`
+   are equivalent.
+ - Any flags that do not take arguments may be placed before other
+   flags within the same argument. For example, `-x -y -z` is equivalent
+   to `-xyz`, as long as `-x` and `-y` have no optional arguments.
+ - The first '--' stops flags from being recognized, and treats them
+   as arguments.
+ - Flags may be supplied in any order, intermingled with arguments,
+   and repeated as many times as desired. An unrecognized flag is an
+   error, and will trigger a usage message.
+
+Types
+------
+
+The API provided for command line parsing is relatively declarative, with the
+options specified in a struct passed to the parsing.
+
+    type optdef = struct
+            argdesc	: byte[:]
+            minargs	: std.size
+            maxargs	: std.size
+            noargs	: std.bool
+            opts	: optdesc[:]
+    ;;
+
+The optdef is the top level structure describing the command line arguments.
+It contains the following fields:
+
+<dl>
+    <dt><code>argdesc</code></dt>
+    <dd>
+    <p>Argdesc is a string describing the positional arguments passed to the
+    program. It doesn't change the way that the arguments are parsed, but is
+    used to document the arguments to the user.</p>
+
+    <p>In general, this should be a summary of any expected argument. If a
+    variable number of them are expected, the argument should be followed
+    with a <code>...</code>.</p>
+
+    <p>For example, a program that takes an output and a list of inputs may
+    provide the following for <code>argdesc</code>:</p>
+
+    <p><code>"output inputs..."</code></p>
+
+    <p>When the help string is generated, the output would look like:</p>
+    <p><code>myprog [-o option] output inputs...</code></p>
+    </dd>
+
+    <dt><code>minargs</code></dt>
+    <dd>
+    <p>This argument limits the minimum number of arguments that the
+    program will accept without error. If at minimum 3 inputs are needed, for
+    example, then this value should be set to 3. This does not count flags,
+    nor does it count the program name.</p>
+    <p> If set to 0, this value is ignored. This is the default value.</p>
+    </dd>
+
+    <dt><code>maxargs</code></dt>
+    <dd>
+    <p>This argument limits the maximum number of arguments that the program
+    will accept without error. If the program takes at most 1 argument, for
+    example, example, then this value should be set to 3. Just like
+    <code>maxargs</code>, this does not count flags or the program name.
+    </p>
+    <p> If set to 0, this value is ignored. This is the default value.</p>
+    </dd>
+
+    <dt><code>noargs</code></dt>
+    <dd>
+    <p>This argument causes the program to reject any arguments at all.</p>
+    </dd>
+    <dt><code>opts</code></dt>
+    <dd><p>This is a list of descriptions of the options that this program
+    takes. This list may be empty, at which point this api still provides a
+    good way of checking that no invalid arguments are passed.</p>
+    </dd>
+</dl>
+    
+    
+    type optdesc = struct
+            opt	: char
+            arg	: byte[:]
+            desc	: byte[:]
+            optional	: bool
+    ;;
+
+This is a description of a command line argument. It contains the following
+fields to be set by the user:
+
+<dl>
+    <dt><code>opt</code></dt>
+    <dd>
+    <p>This is a single unicode character that is used for the option
+    flag.</p>
+    </dd>
+    <dt><code>arg</code></dt>
+    <dd>
+    <p>This is a single word description of the argument. If it is not present
+    or has zero length, this indicates that the flag takes no value.
+    Otherwise, the value is mandatory, unless the <code>optional</code> flag
+    is set.</p>
+    </dd>
+    <dt><code>optional</code></dt>
+    <dd>
+    <p>This is a boolean that allows for the value <code>arg</code> to be
+    optionally omitted when using the flag. It is disabled by default.
+    </p>
+    </dd>
+    <dt><code>desc</code></dt>
+    <dd>
+    <p>This is a short sentence describing <code>arg</code>. It has no
+    semantic effect on the option parsing, and is only used in generating
+    help output for the arguments.
+    </p>
+    </dd>
+</dl>
+
+
+    type optparsed = struct
+            opts	: (char, byte[:])[:]
+            args	: byte[:][:]
+            prog        : byte[:]
+    ;;
+
+This is the final result of parsing the options. The `opts` member contains a
+list of options in the form of `(opt, val)` pairs. The option `opt` will be
+repeated once for every time that the flag `opt` is seen within the command
+line.
+
+If there is no value passed with the flag, then the string will be the empty
+string. Otherwise, it will contain the string passed.
+
+The `args` member contains the arguments, collected for easy iteration, and the
+`prog` member contains the binary name.
+
+Functions
+----------
+
+    const optparse	: (optargs : byte[:][:], def : optdef# -> optparsed)
+
+Optparse takes an array `optargs` containing the command line arguments passed
+to the program, as well as an `optdef` pointer describing the expected
+arguments, and spits out out an `optparsed`. The arguments `optargs` are
+expected to contain the program name.
+
+    const optusage	: (prog : byte[:], def : optdef# -> void)
+
+
+Optusage takes the string `prog` containing the program name, and an `def`
+containing an `optdef` which describes the arguments to provide help for. It
+prints these out on `stderr` (fd 1), and returns.
+
+
+Examples:
+--------
+
+This example is a trivial one, which parses no flags, and merely
+errors if given any.
+
+    const main = {args
+        var cmd
+        
+        cmd = std.optparse(args, &[
+                .argdesc = "vals",
+        ])
+        for arg in cmd.args
+                std.put("arg: {}\n", arg)
+        ;;
+    }
+
+This example shows some more advanced usage, and is extracted from
+mbld.
+
+    const main = {args
+	var dumponly
+	var targname
+	var bintarg
+	var cmd 
+	var libpath
+	
+	cmd = std.optparse(args, &[
+		.argdesc = "[inputs...]",
+		.opts = [
+			[.opt='t', .desc="list all available targets"],
+			[.opt='T', .arg="tag", .desc="build with specified systag"],
+			[.opt='S', .desc="generate assembly when building"],
+			[.opt='d', .desc="dump debugging information for mbld"],
+			[.opt='I', .arg="inc", .desc="add 'inc' to your include path"],
+			[.opt='R', .arg="root", .desc="install into 'root'"],
+			[.opt='b', .arg="bin", .desc="compile binary named 'bin' from inputs"],
+			[.opt='l', .arg="lib", .desc="compile lib named 'lib' from inputs"],
+			[.opt='r', .arg="rt", .desc="link against runtime 'rt' instead of default"],
+			[.opt='C', .arg="mc", .desc="compile with 'mc' instead of the default compiler"],
+			[.opt='M', .arg="mu", .desc="merge uses with 'mu' instead of the default muse"],
+		][:]
+	])
+	targname = ""
+	tags = [][:]
+	for opt in cmd.opts
+		match opt
+		| ('t', ""):	dumponly = true
+		| ('S', ""):	bld.opt_genasm = true
+		| ('I', arg):	bld.opt_incpaths = std.slpush(bld.opt_incpaths, arg)
+		| ('R', arg):	bld.opt_instroot = arg
+		| ('T', tag):	tags = std.slpush(tags, tag)
+		| ('b', arg):
+			targname = arg
+			bintarg = true
+		| ('l', arg):
+			targname = arg
+			bintarg = false
+		| ('r', arg):
+			if std.sleq(arg, "none")
+				bld.opt_runtime = ""
+			else
+				bld.opt_runtime = arg
+			;;
+		/*
+		internal undocumented args; used by compiler suite for
+		building with an uninstalled compiler.
+		*/
+		| ('d', arg): bld.opt_debug = true
+		| ('C', arg): bld.opt_mc = arg
+		| ('M', arg): bld.opt_muse = arg
+		| _:	std.die("unreachable\n")
+
+		;;
+	;;
+
+        for arg in cmd.args
+                /* build stuff */
+        ;;
+    }
+
+
+
--- /dev/null
+++ b/doc/api/libstd/datastruct.txt
@@ -1,0 +1,181 @@
+{
+        title:  Data Structures
+        description:  libstd: Data Structures
+}
+
+
+Data Structures
+----------------
+
+    pkg std =
+            type htab(@k, @v) = struct
+            ;;
+
+            type bitset = struct
+            ;;
+
+            /* hash tables */
+            generic mkht	: (h : (k : @k -> uint32), eq : (a : @k, b : @k -> bool) -> htab(@k, @v)#)
+            generic htfree	: (ht : htab(@k, @v)# -> void)
+            generic htput	: (ht : htab(@k, @v)#, k : @k, v : @v -> void)
+            generic htdel	: (ht : htab(@k, @v)#, k : @k -> void)
+            generic htget	: (ht : htab(@k, @v)#, k : @k -> option(@v))
+            generic htgetv	: (ht : htab(@k, @v)#, k : @k, fallback : @v-> @v)
+            generic hthas	: (ht : htab(@k, @v)#, k : @k -> bool)
+            generic htkeys	: (ht : htab(@k, @v)# -> @k[:])
+
+            /* bit sets */
+            const mkbs	: (-> bitset#)
+            const bsdup	: (bs : bitset# -> bitset#)
+            const bsfree	: (bs : bitset# -> void)
+            const bsmax	: (a : bitset# -> size)
+            generic bsput	: (bs : bitset#, v : @a::(integral,numeric) -> bool)
+            generic bsdel	: (bs : bitset#, v : @a::(integral,numeric) -> bool)
+            generic bshas	: (bs : bitset#, v : @a::(integral,numeric) -> bool)
+            const bsdiff	: (a : bitset#, b : bitset# -> void)
+            const bsintersect	: (a : bitset#, b : bitset# -> void)
+            const bsunion	: (a : bitset#, b : bitset# -> void)
+            const bseq	: (a : bitset#, b : bitset# -> bool)
+            const bsissubset	: (a : bitset#, b : bitset# -> bool)
+            const bsclear	: (bs : bitset# -> bitset#)
+
+            /* prepackaged hashing and equality tests */
+            const strhash	: (s : byte[:]	-> uint32)
+            const streq	: (a : byte[:], b : byte[:]	-> bool)
+            generic ptrhash	: (p : @a#	-> uint32)
+            generic ptreq	: (a : @a#, b : @a#	-> bool)
+            generic inthash	: (v : @a::(integral,numeric)	-> uint32)
+            generic inteq	: (a : @a::(integral,numeric), b : @a::(integral,numeric) -> bool)
+            generic slhash	: (sl : @a[:] -> uint32)
+    ;;
+
+Hash Tables
+-----------
+
+The need for key value lookup shows up everywhere, so libstd contains an
+implementation of hash tables.
+
+    type htab(@k, @v) = struct
+    ;;
+
+The hash table is a generic type which contains any key and any value. The
+key used is `@k`, and the value is `@v`.
+
+    generic mkht	: (h : (k : @k -> uint32), eq : (a : @k, b : @k -> bool) -> htab(@k, @v)#)
+
+Mkht creates a hash table on the heap. It accepts two functions, for hashing
+and equality comparison. The hash table should be freed with `htfree`.
+
+    generic htfree	: (ht : htab(@k, @v)# -> void)
+
+Htfree frees a hash table and associated storage. The keys and values remain
+untouched.
+
+    generic htput	: (ht : htab(@k, @v)#, k : @k, v : @v -> void)
+
+Inserts a key value pair into the hash table `ht`. If there is already a value
+with the key `k`, then the key value pair will be replaced.
+
+    generic htdel	: (ht : htab(@k, @v)#, k : @k -> void)
+
+Removes a key value pair from the hash table `ht`.
+
+    generic htget	: (ht : htab(@k, @v)#, k : @k -> option(@v))
+
+Looks up a value from a hash table, returning `\`Some v` if the key is
+present, or `\`None` if the value is not present.
+
+    generic htgetv	: (ht : htab(@k, @v)#, k : @k, fallback : @v-> @v)
+
+Looks up a value from a hash table, returning the value if the key is
+present, or `fallback` if it is not present.
+
+    generic hthas	: (ht : htab(@k, @v)#, k : @k -> bool)
+
+Looks up a value from a hash table, returning `true` if the key is
+present, or `falase` if the value is not present.
+
+    generic htkeys	: (ht : htab(@k, @v)# -> @k[:])
+
+Returns a list of all the keys present in the hash table. This list is
+heap allocated, and must be freed with `slfree`.
+
+
+Bit Sets
+--------
+
+The need for sets lookup shows up in many places, so libstd contains an
+implementation of bit sets. Any numeric value can be put into the set,
+and with the current API they may be freely intermixed [BUG?]
+
+    type bitset = struct
+    ;;
+
+The bitset holds a set of integers. It works well for relatively dense, small
+integers, as storage used is `O(max_value)`.
+
+    const mkbs	: (-> bitset#)
+
+Creates an empty bit set. The returned bit set should be freed with `bsfree`.
+
+    const bsdup	: (bs : bitset# -> bitset#)
+
+Duplicates an existing bit set. The returned bit set should be freed with
+`bsfree`.
+
+    const bsfree	: (bs : bitset# -> void)
+
+Frees all resources associated with the bitset `bs`.
+
+    const bsmax	: (a : bitset# -> size)
+
+Returns the maximum value that the bitset contains. This is an approximation
+of the capacity of the bitset, not a hard limit on the number of elements.
+
+    const bscount	: (a : bitset# -> size)
+
+Returns the total number of elements that the bitset contains. This is an
+O(n) operation that involves iterating all of the bits.
+
+    generic bsput	: (bs : bitset#, v : @a::(integral,numeric) -> bool)
+
+Inserts the integer value `v` into the bit set `bs`. Returns `true` if this
+operation changed the set, or `false` otherwise.
+
+    generic bsdel	: (bs : bitset#, v : @a::(integral,numeric) -> bool)
+
+Removes the integer value `v` from the bit set `bs`. Returns `true` if this
+operation changed the set, or `false` otherwise.
+
+    generic bshas	: (bs : bitset#, v : @a::(integral,numeric) -> bool)
+
+Returns whether the bit set `bs` contains the value `v`.
+
+    const bsdiff	: (a : bitset#, b : bitset# -> void)
+
+Takes the set difference between `a` and `b`, storing the result back into
+`a`.
+
+    const bsintersect	: (a : bitset#, b : bitset# -> void)
+
+Takes the set intersection between `a` and `b`, storing the result back into
+`a`.
+
+    const bsunion	: (a : bitset#, b : bitset# -> void)
+
+Takes the set union between `a` and `b`, storing the result back into `a`.
+
+    const bseq	: (a : bitset#, b : bitset# -> bool)
+
+Tests whether the bitsets `a` and `b` contain the same elements, returning
+`true` if they are equivalent and `false` otherwise.
+
+    const bsissubset	: (a : bitset#, b : bitset# -> bool)
+
+Tests whether every element of `b` is also within `a`, returning `true` if
+`true` if `b` is a subset of `a`, and `false` otherwise.
+
+    const bsclear	: (bs : bitset# -> bitset#)
+
+Zeros every value within the bitset `bs`. This is equivalent to iterating
+through it and deleting every element.
--- /dev/null
+++ b/doc/api/libstd/dns.txt
@@ -1,0 +1,102 @@
+{
+        title: DNS
+        description:    libstd: DNS
+}
+
+Networking
+----------
+
+     pkg std =
+            type rectype = union
+                    `DnsA	/* host address */
+                    `DnsNS	/* authoritative name server */
+                    `DnsCNAME	/* canonical name for an alias */
+                    `DnsSOA	/* marks the start of a zone of authority */
+                    `DnsWKS	/* well known service description */
+                    `DnsPTR	/* domain name pointer */
+                    `DnsHINFO	/* host information */
+                    `DnsMINFO	/* mailbox or mail list information */
+                    `DnsMX	/* mail exchange */
+                    `DnsTXT	/* text strings */
+                    `DnsAAAA	/* ipv6 host address */
+            ;;
+
+            type resolveerr = union
+                    `Badhost
+                    `Badsrv
+                    `Badquery
+                    `Badresp
+            ;;
+
+            type hostinfo = struct
+                    fam	: sys.sockfam
+                    stype	: sys.socktype
+                    ttl	: uint32
+                    addr	: netaddr
+            ;;
+
+            const resolve	: (host : byte[:]	-> result(hostinfo[:], resolveerr))
+            const resolvemx	: (host : byte[:]	-> result(hostinfo[:], resolveerr))
+            const resolverec	: (host : byte[:], t : rectype	-> result(hostinfo[:], resolveerr))
+    ;;
+
+
+Data Types
+----------
+
+    type rectype = union
+            `DnsA	/* host address */
+            `DnsNS	/* authoritative name server */
+            `DnsCNAME	/* canonical name for an alias */
+            `DnsSOA	/* marks the start of a zone of authority */
+            `DnsWKS	/* well known service description */
+            `DnsPTR	/* domain name pointer */
+            `DnsHINFO	/* host information */
+            `DnsMINFO	/* mailbox or mail list information */
+            `DnsMX	/* mail exchange */
+            `DnsTXT	/* text strings */
+            `DnsAAAA	/* ipv6 host address */
+    ;;
+
+This union contains all of the record types that we claim to know how to
+resolve. At the moment, few of them have been tested sufficiently (only A
+records can reasonably be said to be exercised).
+
+    type resolveerr = union
+            `Badhost
+            `Badsrv
+            `Badquery
+            `Badresp
+    ;;
+
+This union contains the errors that we can encounter when trying to resolve a
+host.
+
+    type hostinfo = struct
+            fam	: sys.sockfam
+            stype	: sys.socktype
+            ttl	: uint32
+            addr	: netaddr
+    ;;
+
+DNS Resolution
+--------------
+
+    const resolve	: (host : byte[:]	-> result(hostinfo[:], resolveerr))
+
+Resolves the A or AAAA record for the host `host` using DNS. This function
+does caching, expiring based on the TTL. Returns all of the host info entries sent
+back by DNS or found in the cache on success, or a resolve error on failure.
+
+    const resolvemx	: (host : byte[:]	-> result(hostinfo[:], resolveerr))
+
+Resolves the MX record for the host `host` using DNS. This function does
+caching, expiring based on the TTL. Returns all of the host info entries sent
+back by DNS or found in the cache on success, or a resolve error on failure.
+
+    const resolverec	: (host : byte[:], t : rectype	-> result(hostinfo[:], resolveerr))
+
+Resolves a record from DNS. This function's interface is slightly broken, as
+it will never work for TXT or CNAME records.
+
+
--- /dev/null
+++ b/doc/api/libstd/err.txt
@@ -1,0 +1,116 @@
+{
+        title:  Error Handling
+        description:  libstd: Error Handling
+}
+
+
+Error Handling
+--------------
+
+    pkg std =
+            type option(@a) = union
+                    `Some @a
+                    `None
+            ;;
+
+            type result(@a, @b) = union
+                    `Ok	@a
+                    `Fail	@b
+            ;;
+
+            $noret const fatalv	: (fmt : byte[:], ap : valist# -> void)
+            $noret const fatal	: (fmt : byte[:], args : ... -> void)
+            const assert	: (cond : bool, fmt : byte[:], args : ... -> void)
+            const die           : (msg : byte[:] -> void)
+            const suicide	: ( -> void)
+
+            generic try : (v : result(@a, @b) -> @a)
+            generic tryv : (v : result(@a, @b), d : @a -> @a)
+            generic get : (v : option(@a) -> @a)
+            generic getv : (v : option(@a), d : @a -> @a)
+    ;;
+
+Overview
+--------
+
+Myrddin does not have exceptions. By convention, code will abort on
+programmer errors, such as passing invalid values where valid ones
+were expected -- for example, calling `std.fmt("{}")` with the wrong
+number of arguments int the list.
+
+For recoverable error conditions that depend on the environment, and
+not the developer making a mistake, one of the branched return types
+are conventionally used.
+
+For conditions where something can be either present or not, the `option(@a)`
+type is used. For places where there can be either a result or an error, the
+`result(@a, @e)` type is used.
+
+Generally, by convention, the type returned for the result should have a
+custom that converts it to something directly displayable to the user.
+
+Types
+-----
+
+    type option(@a) = union
+            `Some @a
+            `None
+    ;;
+
+As mentioned in the overview, `option(@a)` is a type that wraps up a result
+and error type. It is typically used  in places where a missing value is the
+only exceptional condition.
+
+    type result(@a, @b) = union
+            `Ok	@a
+            `Fail	@b
+    ;;
+
+
+The type `result(@a, @e)` is used to signal either success or an error
+condition. The first type parameter, `@a` is what is returned on success,
+and the second, `@b` is returned on failure.
+
+
+Functions
+---------
+    $noret const fatalv	: (fmt : byte[:], ap : valist# -> void)
+    $noret const fatal	: (fmt : byte[:], args : ... -> void)
+
+Both fatal and fatalv exit the program with an error message, formatted as
+in `std.fmt`. They do not return.
+
+They exit with a failure status. On Unix, this status is `1`. On Plan 9,
+the status is the failure message that it prints out before exiting.
+
+    const assert	: (cond : bool, fmt : byte[:], args : ... -> void)
+
+Assert checks that condition is true. If it is not true, then the message
+is printed as in `std.fmt`, and the program is aborted with `suicide()`.
+
+    const suicide	: ( -> void)
+
+Suicide aborts a program. It does not print any message, it simply sends
+the program a SIGABRT or segfaults it. All threads are terminated, and the
+program goes away.
+
+    generic try : (v : result(@a, @b) -> @a)
+    generic get : (v : option(@a) -> @a)
+
+Try and get both return the value from the successful branch of their type:
+`try` returns the value contained in `\`std.Ok`, and `get` returns the value
+in `\`std.Some`.
+
+If this does not match the union, a diagnostic message is printed and the
+program is aborted.
+
+    generic tryv : (v : result(@a, @b), default : @a -> @a)
+    generic getv : (v : option(@a), default : @a -> @a)
+
+Try and get both return the value from the successful branch of their type:
+`try` returns the value contained in `\`std.Ok`, and `get` returns the value
+in `\`std.Some`.
+
+If this does not match the union, the default value is returned to the
+caller, as though the type had contained `\`Some default` or `\`Ok default` 
+
--- /dev/null
+++ b/doc/api/libstd/files.txt
@@ -1,0 +1,369 @@
+{
+        title:  File Handling
+        description:    libstd: File Handling
+}
+
+File Handling
+-------------
+
+
+    pkg std =
+            type dir = struct
+            ;;
+
+            /* seek options */
+            const Seekset	: whence 
+            const Seekcur	: whence 
+            const Seekend	: whence 
+
+            /* open options */
+            const Ordonly  	: fdopt 
+            const Owronly  	: fdopt 
+            const Ordwr    	: fdopt 
+            const Otrunc   	: fdopt 
+            const Ocreat   	: fdopt 
+            const Oappend  	: fdopt 
+            const Odir	: fdopt 
+
+            /* directory handling */
+            const diropen	: (p : byte[:] -> std.result(dir#, byte[:]))
+            const dirread	: (d : dir# -> std.option(byte[:]))
+            const dirclose	: (d : dir# -> void)
+            const dirname	: (p : byte[:] -> byte[:])
+            const mkdir	: (path : byte[:], mode : int64 -> int64)
+            const mkpath	: (p : byte[:] -> bool)
+            const chdir	: (path : byte[:] -> bool)
+
+            /* file handling */
+            const open	: (path : byte[:], opts : fdopt -> std.result(fd, errno))
+            const openmode	: (path : byte[:], opts : fdopt, mode : int64 -> std.result(fd, errno))
+            const mktemp	: (base : byte[:], opts : fdopt, mode : int64 -> std.result((fd, byte[:]), errno)
+            const close	: (fd : fd -> int64)
+            const creat	: (path : byte[:], mode : int64 -> fd)
+            const read	: (fd : fd, buf : byte[:] -> size)
+            const write	: (fd : fd, buf : byte[:] -> size)
+            const seek	: (fd : fd, delta : off, whence : whence -> off)
+            const pipe	: (fds : fd[2]# -> int64)
+            const dup2	: (ofd : fd, nfd : fd -> fd)
+            const remove	: (path : byte[:] -> bool)
+            const unlink	: (path : byte[:] -> int)
+
+            /* path manipulation */
+            const basename	: (p : byte[:] -> byte[:])
+            const pathcat	: (a : byte[:], b : byte[:] -> byte[:])
+            const pathjoin	: (p : byte[:][:] -> byte[:])
+            const pathnorm	: (p : byte[:] -> byte[:])
+            const getcwd : (-> byte[:])
+
+            /* file properties */
+            const fmtime	: (f : byte[:]	-> result(time, errno))
+            const fsize	: (f : byte[:]	-> result(off, errno))
+            const fexists	: (f : byte[:]	-> bool)
+            const fisdir	: (f : byte[:]	-> bool)
+
+            /* convenience functions */
+            const slurp : (path : byte[:] -> result(byte[:], byte[:]))
+            const fslurp : (path : fd -> result(byte[:], byte[:]))
+            const blat : (path : byte[:], buf : byte[:], perm : int64 -> bool)
+            const fblat : (f : fd, buf : byte[:] -> bool)
+    ;;
+
+
+Data Types and Constants
+------------------------
+
+Libstd's file APIs are generally relatively thin wrappers around the host OS
+functions. They are a portable subset of this functionality, designed for both
+ease of use and portability.
+
+    type dir = struct
+    ;;
+
+The directory struct represents the current state of a directory walk.
+
+    /* seek options */
+    const Seekset	: whence 
+    const Seekcur	: whence 
+    const Seekend	: whence 
+
+These are a set of values which describe from where to seek within the file.
+
+    /* open options */
+    const Oread  	: fdopt 
+    const Owrite  	: fdopt 
+    const Ordwr    	: fdopt 
+    const Otrunc   	: fdopt 
+    const Ocreat   	: fdopt 
+
+These are a set of options that are passed to the open variants describing
+what mode to open the file in. These are bit masks which be OR'ed together to
+combine them.
+
+`Oread` and `Owrite` request permission to read and write the file, respectively.
+`Ordwr` is a convenience flag which ors read and write together. `Otrunc`
+indicates that the file should be truncated to zero bytes in length before it
+is opened. `Ocreat` indicates that the file should be created if it does not
+exist instead of returning an error. `Odir` indicates that this file should
+be opened as a directory.
+
+`Ocreat` does not create the path leading to it, and will return an error if
+that path does not exist.
+
+
+Directories
+-----------
+
+    const diropen	: (p : byte[:] -> std.result(dir#, byte[:]))
+
+The `diropen` function opens a path as a directory, and returns a pointer
+to an object which tracks the state of the directory, allowing for reading
+file names one by one from this directory.
+
+Returns: Either a directory wrapped up in the `\`Ok` branch of the result,
+or a string describing the failure reason in the `\`Fail` branch.
+
+    const dirread	: (d : dir# -> result(option(byte[:]), errno)
+
+The `dirread` reads a single entry from the directory, opened with `diropen`,
+returning it as a string. 
+
+Returns `\`Some entry`, or `\`None` at the end of the directory.
+
+    const dirclose	: (d : dir# -> void)
+
+`dirclose` closes a directory for reading. This frees all associated
+resources, returning them to the system. The directory passed in must have
+been opened with `diropen`.
+
+Returns: Nothing.
+
+    const mkdir	: (path : byte[:], mode : int64 -> errno)
+
+`mkdir` creates the directory specified in `path`. with the mode `mode`. It
+requires the parent directory to exist and be writable. Absolute paths will
+be created relative to the root of the file system, and relative paths will
+be created relative to the current working directory, as usual.
+
+If the directory already exists, this is counted as a failure to create the
+directory.
+
+Returns: Enone on success, or the error that caused the failure if it fails.
+
+    const mkpath	: (path : byte[:] -> errno)
+
+`mkpath` creates a full path specified by `path`. It creates all of the
+path components required to create the full path specified. It requires
+the parent of the first directory entry that is not currently in existence
+to be writable.
+
+Absolute paths will be created relative to the root of the file system, and
+relative paths will be created relative to the current working directory, as
+usual.
+
+Returns: Enone on success, or the error that caused the directory creation
+to fail on failure.
+
+    const chdir	: (path : byte[:] -> bool)
+
+Chdir changes the current working directory to the path specified in `path`.
+
+Returns: True on success, false on failure.
+
+Files
+-----
+
+    const open	: (path : byte[:], opts : fdopt -> result(fd, errno))
+    const openmode	: (path : byte[:], opts : fdopt, mode : int64 -> result(fd, errno))
+
+Open opens the file `path` for I/O according to the flags reqeusted in `opts`,
+and returns a result containing the file descriptor or error. The mode is a
+combination of the modes specified above: `Oread`,   `Owrite`, `Ordwr`,
+`Otrunc`, or `Ocreat`.
+
+Openmode is similar to open, however, if Ocreate is passed, it the file
+requested will be created with the permissions passed in.
+
+Returns: either a valid file descriptor on success, or an error describing why
+the open failed on failure.
+
+    const mktemp : (base : byte[:], opts : fdopt, mode : int64 -> std.result((fd, byte[:]), errno)
+
+Mktemp is similar to openmode, however instead of taking a full path as
+its first argument, it generates a unique name for a file in temporary
+storage by appending a random string to the base name `base`. The mode
+provided is in addition to the implicit Ocreat | Oexcl.
+
+Returns: Either a successful result containing the tuple of file descriptor
+opened and path generated, or an error describing the failure. The path
+is allocated with `std.slalloc`, and must be freed by the caller using
+`std.slfree`. The file descriptor must be closed as ususal.
+
+
+    const close	: (fd : fd -> void)
+
+Closes closes the file descriptor. If the file descriptor is valid, close
+is guaranteed to close it. If it is not valid, this is a no-op.
+
+    const read	: (fd : fd, buf : byte[:] -> result(size, errno))
+
+Reads up to the length of `buf` from the file descriptor `fd`, at the current
+offset within the file, advancing the offset by the count of bytes read. The
+buffer may not be filled entirely when the read completes. For example, when
+reading from a console, often only one line will be returned at a time.
+
+Conventionally, `0` bytes are returned at the end of the file.
+
+Returns: Either the number of bytes read on success, or the error that caused
+a failure reading on failure.
+
+    const write	: (fd : fd, buf : byte[:] -> result(size, errno))
+
+Write writes up to the length of `buf` to the file descriptor, writing the
+bytes at the current offset. The offset is advanced by the number of bytes
+that were written, extending the file size if necessary. Write is not
+guaranteed to write the full buffer.
+
+Returns: The number of bytes written on success, or the error that caused
+the failure on error.
+
+    const seek	: (fd : fd, delta : off, whence : whence -> result(off, errno))
+
+Seek changes the current offset within the file descriptor `fd` by `delta`.
+This delta can be treated in three different ways, depending on the value of
+`whence.
+
+If `whence` is Seekset, then `delta` is treated as an absolute value to seek
+to, and the offset is set to `delta`. If `whence` is `Seekcur`, then `delta`
+is added to the current offset.  If `whence` is `Seekend`, then `delta` is
+added to the size of the file.
+
+Returns: Either the new offset within the file on success, or the error that
+occurred on failure.
+
+    const pipe	: (fds : fd[2]# -> errno)
+
+Pipe creates a unidirectional channel for communication between processes.
+Two file descriptors are returned in the array fd. Data written to fd[1] is
+available in fd[0]. The pipe may or may not be buffered.
+
+Returns: Enone on success, otherwise, returns the error that caused this
+call to fail.
+
+    const dup2	: (ofd : fd, nfd : fd -> result(fd, errno))
+
+Dup2 copies the old fd `ofd` to the new fd `nfd`. If the file descriptor
+`nfd` is already open, then it is implicitly closed by this call before
+the fd is copied. This is done atomically.
+
+Returns: Either the new fd used, on success, or an error describing the
+failure.
+
+    const remove	: (path : byte[:] -> errno)
+
+Remove removes the file specified from the directory in which it is contained.
+The user must have write permissions for the directory in order to remove
+files from it. If `path` is a directory, it must be empty.
+
+Returns: Enone on success, otherwise the error that caused the failure.
+
+Path Manipulation
+-----------------
+    const basename	: (p : byte[:] -> byte[:])
+    const dirname	: (p : byte[:] -> byte[:])
+
+Given a string of the form "foo/bar/baz", `dirname()` returns the directory
+component of it -- in other words, everything up to the final `/`. It ignores
+trailing slashes. It 
+
+The caller is responsible for freeing the path with `slfree`.
+
+For example, `dirname("foo/bar//")` will return `"foo/bar"`.
+
+    const pathcat	: (a : byte[:], b : byte[:] -> byte[:])
+
+Pathcat joins two paths together, using '/' as a directory
+separator. The paths are normalized before being returned. This
+call is shorthand for `std.pathjoin([a, b][:])`.
+
+The caller is responsible for freeing the path with `slfree`.
+
+Returns: A concatenated path.
+
+    const pathjoin	: (p : byte[:][:] -> byte[:])
+
+Pathcat joins a list of paths together, using '/' as a directory
+separator. The paths are normalized before being returned. This
+call is shorthand for `std.pathjoin([a, b][:])`.
+
+The caller is responsible for freeing the path with `slfree`.
+
+Returns: A concatenated path.
+
+    const pathnorm	: (p : byte[:] -> byte[:])
+
+Pathnorm does a purely lexical normalization of the path. It removes
+redundant components, doubled `/` characters, and similar. The returned
+path is equivalent to the original input path.
+
+The caller is responsible for freeing the path with `slfree`.
+
+Returns: A new normalized path.
+
+    const getcwd : (-> byte[:])
+
+Returns the current working directory of the program. The caller is
+responsible for freeing the path with `slfree`.
+
+Returns: A string representing the working directory.
+
+File Properties
+---------------
+
+    const fmtime	: (f : byte[:]	-> result(time, errno))
+
+Returns either the last modification time of the file `f`, or
+the error that was encountered extracting this information.
+
+    const fsize	: (f : byte[:]	-> result(off, errno))
+
+Returns either the size in bytes of the file `f`, or
+the error that was encountered extracting this information.
+
+    const fexists	: (f : byte[:]	-> bool)
+
+Returns `true` if the file is able to be `stat`ed, or `false`
+if this fails.
+
+    const fisdir	: (f : byte[:]	-> bool)
+
+Returns `true` if the file is a directory that is able to be `stat`ed, or
+`false` if this fails.
+
+Convenience Functions
+---------------------
+
+    const slurp : (path : byte[:] -> result(byte[:], errno))
+
+Reads all bytes from `path` until the end of file.
+
+Returns either the file data, or the failure encountered.
+
+    const fslurp : (fd : fd -> result(byte[:], errno))
+
+Reads all bytes from the file descriptor `fd` until the end of file.
+
+Returns either the file data, or the failure encountered.
+
+    const blat : (path : byte[:], buf : byte[:], perm : int64 -> bool)
+
+Creates the file `path` with permissions `perm`, and writes as much of
+`buf` as it can into it.
+
+Returns Enone if no errors were encountered. Otherwise, the error is returned.
+
+    const fblat : (f : fd, buf : byte[:] -> bool)
+
+Writes as much of `buf` as it can into the file descriptor `fd`.
+
+Returns Enone if no errors were encountered. Otherwise, the error is returned.
+
--- /dev/null
+++ b/doc/api/libstd/fmt.txt
@@ -1,0 +1,201 @@
+{
+        title:  Formatted I/O
+        description:  libstd: Formatted I/O
+}
+
+
+
+Formatted I/O
+-------
+
+    pkg std =
+            /* output to file descriptors */
+            const put	: (fmt : byte[:], args : ... -> size)
+            const fput	: (fd : fd, fmt : byte[:], args : ... -> size)
+            const putv	: (fmt : byte[:], ap : valist# -> size)
+            const fputv	: (fd : fd, fmt : byte[:], ap : valist# -> size)
+
+            /* formatting values */
+            const fmt	: (fmt : byte[:], args : ... -> byte[:])
+            const fmtv	: (fmt : byte[:], ap : valist# -> byte[:])
+            const bfmt	: (buf : byte[:], fmt : byte[:], args : ... -> byte[:])
+            const bfmtv	: (buf : byte[:], fmt : byte[:], ap : valist# -> byte[:])
+            const sbfmt	: (buf : strbuf#, fmt : byte[:], args : ... -> size)
+            const sbfmtv	: (buf : strbuf#, fmt : byte[:], ap : valist# -> size)
+            
+            /* custom formatting */
+            const fmtinstall	: (ty : byte[:], \
+                    fn : (sb : strbuf#, \
+                            ap : valist#, \
+                            opts : (byte[:],byte[:])[:] \
+                            -> void), \
+		optdesc : (byte[:], bool)[:] \
+		-> void)
+    ;;
+
+
+Overview
+--------
+
+Formatting in Myrddin is done with format strings. These are effectively
+dynamically typed at runtime, using introspection to decide the best way to
+format a type. Custom formatters are allowed and encouraged.
+
+Formatting is specified with a `{}` pair, with any specifiers describing the
+formatting passed in as a comma separated set of key value pairs. For example,
+an integer can be padded with zeros and formatted in hex with the following
+format specifier: `{p=0,x}`. If you want a literal '{' character, it can
+be escaped by doubling it.
+
+None of the format specifiers print a newline character by default.
+
+Format Specifiers
+--------------------------
+
+The set of specifiers for the default types is sparse, and is fully
+specified below.
+
+<dl>
+    <dt>w=WIDTH</dt>
+    <dd><p>Fill out to at least width WIDTH, filling with pad
+    characters.</p></dd>
+
+    <dt>p=PAD</dt>
+    <dd>
+    <p>Fill spare width with this character. Defaults to a space
+    character.</p> </dd>
+
+    <dt>x</dt>
+    <dd>
+    <p>Format in hex. This is only valid for integer types.</p>
+    </dd>
+
+    <dt>j=joiner</dt>
+    <dd>
+    <p>Join slices with the joiner string. This leaves off the square
+    brackets from the ends, and replaces the default joiner string ", ".
+    </p>
+    </dd>
+</dl>
+
+Specifiers can be installed by custom specifiers, and can be any
+arbitrary set of strings.
+
+Functions
+---------
+
+All the format functions come in two variants: A variadic one, and one
+that takes a variadic argument list. The latter is present for ease of
+chaining from within a variadic function.
+
+    const put	: (fmt : byte[:], args : ... -> size)
+    const fput	: (fd : fd, fmt : byte[:], args : ... -> size)
+    const putv	: (fmt : byte[:], ap : valist# -> size)
+    const fputv	: (fd : fd, fmt : byte[:], ap : valist# -> size)
+
+The `put` set of functions will format and output to a file descriptor. For
+`put` and `putv`, the file descriptor is stdout. For `fput` and `fputv`, the
+file descriptor is the one that is provided.
+
+These functions write immediately, and do not buffer, although they do attempt
+to do their writing in a single system call, and will only split the call if
+the kernel indicates short writes.
+
+The `v` variants will take a variadic argument list for printing.
+
+Returns: the number of bytes written to the file descriptor.
+
+    const sbfmt	: (buf : strbuf#, fmt : byte[:], args : ... -> size)
+    const sbfmtv	: (buf : strbuf#, fmt : byte[:], ap : valist# -> size)
+
+The sbfmt functions will append to a string buffer, instead of writing to an
+output stream, but are otherwise similar to the `fmt` functions. These
+functions will return the number of bytes formatted. If the string buffer is
+statically sized, and gets filled, the truncated size will be returned.
+
+    const fmt	: (fmt : byte[:], args : ... -> byte[:])
+    const fmtv	: (fmt : byte[:], ap : valist# -> byte[:])
+
+These functions will format according to the format string, and return a
+freshly allocated string containing the formatted string. This string should
+be freed with `slfree`.
+
+    const bfmt	: (buf : byte[:], fmt : byte[:], args : ... -> byte[:])
+    const bfmtv	: (buf : byte[:], fmt : byte[:], ap : valist# -> byte[:])
+
+These functions will format according to the format string, putting the result
+into `buf`. They return a slice into the buffer array.
+    
+    const fmtinstall	: (ty : byte[:], \
+            fn : (sb : strbuf#, 
+                    ap : valist#, \
+                    opts : (byte[:],byte[:])[:] \
+                    -> void), \
+        optdesc : (byte[:], bool)[:] \
+        -> void)
+
+Fmtinstall installs a custom formatter for a type. The type `ty` is a type
+description that you would want to format. It can be obtained
+using `std.typeof(var)`, `fn` is a function that handles custom formatting,
+and `optdesc` is a list of options that this custom formater takes. It is
+in the form a list of strings -- the argument names -- and booleans that
+define whether these arguments take values.
+
+
+The custom formatter takes a string buffer `sb` which you are expected to
+format the custom input into, as well as a valist that you are expected to
+pull the value from. Finally, it takes an option list.
+
+If a formatter is already installed for a type, it is replaced.
+
+Examples
+--------
+
+This example demonstrates a bunch of formatting using the std.format API. It
+covers all of the various format specifiers, escaping, as well as showing the
+formatting of complex types.
+
+```{runmyr fmtsimple}
+use std
+
+const main = {
+        /* default formats */
+	std.put("{} {}\n", "abcd", 123)
+	std.put("{}\n", [1,2,3][:])
+	std.put("{}\n", (1,"foo"))
+
+        /* mix in some format options */
+	std.put("{w=10}\n", "abcd")
+	std.put("{p=0,w=10}\n", "abcdefghijkl")
+	std.put("{w=10,x}\n", 10)
+	std.put("{p=0,w=10}\n", 10)
+
+        /* and now some escaping */
+	std.put("{}bar{}\n", "foo\n", "baz")
+	std.put("{{}}bar{}\n", "baz")
+	std.put("{{bar{}}}\n", "baz")
+}
+```
+
+This example shows how you would set up a 
+
+```{runmyr customfmt}
+use std
+
+const main = {
+        var x : int = 0 /* dummy: used for typeof */
+
+        std.fmtinstall(std.typeof(x), goaway, [][:])
+        std.put("custom format: {}\n", 0x41)
+}
+
+const goaway = {sb, ap, opts
+        var i : int64
+
+        i = std.vanext(ap)
+        std.sbfmt(sb, "go away! char val={}\n", i castto(char))
+}
+```
+
+
+
--- /dev/null
+++ b/doc/api/libstd/index.txt
@@ -1,0 +1,711 @@
+{
+        title:  libstd
+        description:  libstd: Summary
+}
+
+Libstd Summary
+---------------
+
+This is a summary page listing all of the functions and types available
+in libstd, sorted by category. The library is a bit of a grab bag of
+functionality, but a good chunk of what is needed will be built in to
+the library.
+
+
+#### [Memory Allocation](alloc)
+
+Memory allocation is a function that nearly every program needs
+to be able to do. Myrddin's generics allow for relatively easy
+to use and typesafe functions for this to be written.
+
+    pkg std =
+            generic mk	: (val : @a -> @a#)
+            generic alloc	: (		-> @a#)
+            generic zalloc	: (		-> @a#)
+            generic free	: (v:@a#	-> void)
+            generic slalloc	: (len : size	-> @a[:])
+            generic slzalloc	: (len : size	-> @a[:])
+            generic slgrow	: (sl : @a[:]#, len : size	-> @a[:])
+            generic slzgrow	: (sl : @a[:]#, len : size	-> @a[:])
+            generic slfree	: (sl : @a[:]	-> void)
+            const bytealloc	: (sz:size	-> byte#)
+            const zbytealloc	: (sz:size	-> byte#)
+            const bytefree	: (m:byte#, sz:size	-> void)
+    ;;
+
+#### [Error Handling](err)
+
+Myrddin provides a number of types and operations for propagating errors
+for later handling.
+
+It also provides operations for throwing up your hands, setting yourself on
+fire, and screaming, if that's more appropriate.
+
+    pkg std =
+            type option(@a) = union
+                    `Some @a
+                    `None
+            ;;
+            pkg std =
+                    type result(@a, @b) = union
+                            `Ok	@a
+                            `Fail	@b
+                    ;;
+            ;;
+
+            $noret const fatalv	: (fmt : byte[:], ap : valist# -> void)
+            $noret const fatal	: (fmt : byte[:], args : ... -> void)
+            const assert	: (cond : bool, fmt : byte[:], args : ... -> void)
+            const suicide	: ( -> void)
+
+            generic try : (v : result(@a, @b) -> @a)
+            generic tryv : (v : result(@a, @b), d : @a -> @a)
+            generic get : (v : option(@a) -> @a)
+            generic getv : (v : option(@a), d : @a -> @a)
+    ;;
+
+#### [OS Interfaces](os)
+
+The OS interfaces cover some portable primitives for handling processes
+and OS errors. It restricts itself to a set of portable wrappers for OS
+functionality.
+
+For complete interfaces, the `sys` library is your friend, providing
+all OS functionality that can be provided.
+
+    pkg std =
+            type sysinfo = struct
+                    system	: byte[:]
+                    version	: byte[:]
+                    release	: byte[:]
+                    arch	: byte[:]
+                    uname	: sys.utsname	/* storage */
+            ;;
+
+            type waitstatus = union
+                    `Wsuccess
+                    `Wfailure
+                    `Wsignalled
+                    `Waiterror
+            ;;
+
+            const Enone	: errno
+            const Erange	: errno
+            const Ebadf	: errno
+            const Eexist	: errno
+            const Einval	: errno
+            const Efault	: errno
+            const Eio	: errno
+            const Emisc : errno
+
+            const getsysinfo	: (si : sysinfo# -> void)
+            const execvp	: (cmd : byte[:], args : byte[:][:] -> int64)
+            const execvpe	: (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> int64)
+            const getenv	: (name : byte[:] -> option(byte[:]))
+            const getenvv	: (name : byte[:], default : byte[:] -> byte[:])
+            const getpid	: ( -> pid)
+            const fork		: (-> pid)
+            const exec		: (cmd : byte[:], args : byte[:][:] -> int64)
+            const execve	: (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> int64)
+            const waitpid	: (pid:pid, loc:int32#, opt : int64	-> int64)
+            const spork	: (cmd : byte[:][:]	-> result((pid, fd, fd), int))
+            const sporkfd	: (cmd : byte[:][:], infd : fd, outfd : fd	-> result(pid, int))
+            const exit	: (status:int -> void)
+            const wait	: (pid : pid -> waitstatus)
+    ;;
+
+#### [File Handling](files)
+
+Many programs do file i/o by default. This package provides a portable
+interface to the common subset that most programs need and most OSes provide.
+
+    pkg std =
+            type dir = struct
+            ;;
+
+            /* seek options */
+            const Seekset	: whence 
+            const Seekcur	: whence 
+            const Seekend	: whence 
+
+            /* open options */
+            const Ordonly  	: fdopt 
+            const Owronly  	: fdopt 
+            const Ordwr    	: fdopt 
+            const Otrunc   	: fdopt 
+            const Ocreat   	: fdopt 
+            const Oappend  	: fdopt 
+            const Odir	: fdopt 
+
+            /* directory handling */
+            const diropen	: (p : byte[:] -> std.result(dir#, byte[:]))
+            const dirread	: (d : dir# -> std.option(byte[:]))
+            const dirclose	: (d : dir# -> void)
+            const dirname	: (p : byte[:] -> byte[:])
+            const mkdir	: (path : byte[:], mode : int64 -> int64)
+            const mkpath	: (p : byte[:] -> bool)
+            const chdir	: (path : byte[:] -> bool)
+
+            /* file handling */
+            const open	: (path : byte[:], opts : fdopt -> fd)
+            const openmode	: (path : byte[:], opts : fdopt, mode : int64 -> fd)
+            const close	: (fd : fd -> int64)
+            const creat	: (path : byte[:], mode : int64 -> fd)
+            const read	: (fd : fd, buf : byte[:] -> size)
+            const write	: (fd : fd, buf : byte[:] -> size)
+            const seek	: (fd : fd, delta : off, whence : whence -> off)
+            const pipe	: (fds : fd[2]# -> int64)
+            const dup2	: (ofd : fd, nfd : fd -> fd)
+            const remove	: (path : byte[:] -> bool)
+            const unlink	: (path : byte[:] -> int)
+
+            /* path manipulation */
+            const basename	: (p : byte[:] -> byte[:])
+            const pathcat	: (a : byte[:], b : byte[:] -> byte[:])
+            const pathjoin	: (p : byte[:][:] -> byte[:])
+            const pathnorm	: (p : byte[:] -> byte[:])
+            const getcwd : (-> byte[:])
+
+            /* file properties */
+            const fmtime	: (f : byte[:]	-> option(time))
+            const fsize	: (f : byte[:]	-> option(off))
+            const fexists	: (f : byte[:]	-> bool)
+            const fisdir	: (f : byte[:]	-> bool)
+
+            /* convenience functions */
+            const slurp : (path : byte[:] -> result(byte[:], byte[:]))
+            const fslurp : (path : fd -> result(byte[:], byte[:]))
+            const blat : (path : byte[:], buf : byte[:], perm : int64 -> bool)
+            const fblat : (f : fd, buf : byte[:] -> bool)
+    ;;
+
+#### [Networking](networking)
+
+The networking related functionality in libstd provides the ability to
+quickly and easily open file descriptors to a server, as well as to 
+resolve servers and handle IP parsing.
+
+Currently, there is a large hole in functionality for announcing and
+serving, where raw system specific network APIs neeed to be used
+from the `sys` library.
+
+    pkg std =
+            type rectype = union
+                    `DnsA	/* host address */
+                    `DnsNS	/* authoritative name server */
+                    `DnsCNAME	/* canonical name for an alias */
+                    `DnsSOA	/* marks the start of a zone of authority */
+                    `DnsWKS	/* well known service description */
+                    `DnsPTR	/* domain name pointer */
+                    `DnsHINFO	/* host information */
+                    `DnsMINFO	/* mailbox or mail list information */
+                    `DnsMX	/* mail exchange */
+                    `DnsTXT	/* text strings */
+                    `DnsAAAA	/* ipv6 host address */
+            ;;
+
+            type resolveerr = union
+                    `Badhost
+                    `Badsrv
+                    `Badquery
+                    `Badresp
+            ;;
+
+            type hostinfo = struct
+                    fam	: sys.sockfam
+                    stype	: sys.socktype
+                    ttl	: uint32
+                    addr	: ipaddr
+            ;;
+
+            type ipaddr = union
+                    `Ipv4	byte[4]
+                    `Ipv6	byte[16]
+            ;;
+
+            /* network connections */
+            const dial	: (dialstr : byte[:] -> result(fd, byte[:]))
+            const resolve	: (host : byte[:]	-> result(hostinfo[:], resolveerr))
+            const resolvemx	: (host : byte[:]	-> result(hostinfo[:], resolveerr))
+            const resolverec	: (host : byte[:], t : rectype	-> result(hostinfo[:], resolveerr))
+
+            /* ip parsing */
+            const ipparse	: (ip : byte[:]	-> option(ipaddr))
+            const ip4parse	: (ip : byte[:] -> option(ipaddr))
+            const ip6parse	: (ip : byte[:] -> option(ipaddr))
+
+            generic hosttonet	: (v : @a -> @a)
+            generic nettohost	: (v : @a -> @a)
+    ;;
+
+#### [Command Line Parsing](cli)
+
+Simple command line parsing is offered, designed to meet the needs of most
+programs quickly and easily. There isn't much to say here.
+    
+    pkg std =
+            type optdef = struct
+                    argdesc	: byte[:]	/* the description for the usage */
+                    minargs	: std.size	/* the minimum number of positional args */
+                    maxargs	: std.size	/* the maximum number of positional args (0 = unlimited) */
+                    noargs	: std.bool	/* whether we accept args at all */
+                    opts	: optdesc[:]	/* the description of the options */
+            ;;
+            type optdesc = struct
+                    opt	: char
+                    arg	: byte[:]
+                    desc	: byte[:]
+                    optional	: bool
+            ;;
+            type optparsed = struct
+                    opts	: (char, byte[:])[:]
+                    args	: byte[:][:]
+            ;;
+
+            const optparse	: (optargs : byte[:][:], def : optdef# -> optparsed)
+            const optusage	: (prog : byte[:], def : optdef# -> void)
+    ;;
+
+#### [Formatted Output](fmt)
+
+libstd supports a number of simple, easy to use formatting functions,
+which can provide a sane format for any type out of the box, but also
+support custom formatters for specific types, so that they can be pretty
+printed. Many of the builtin types, such as bigints, install custom
+formatters by default.
+
+    pkg std =
+            /* output to file descriptors */
+            const put	: (fmt : byte[:], args : ... -> size)
+            const fput	: (fd : fd, fmt : byte[:], args : ... -> size)
+            const putv	: (fmt : byte[:], ap : valist# -> size)
+            const fputv	: (fd : fd, fmt : byte[:], ap : valist# -> size)
+
+            /* formatting values */
+            const fmt	: (fmt : byte[:], args : ... -> byte[:])
+            const fmtv	: (fmt : byte[:], ap : valist# -> byte[:])
+            const bfmt	: (buf : byte[:], fmt : byte[:], args : ... -> byte[:])
+            const bfmtv	: (buf : byte[:], fmt : byte[:], ap : valist# -> byte[:])
+            const sbfmt	: (buf : strbuf#, fmt : byte[:], args : ... -> size)
+            const sbfmtv	: (buf : strbuf#, fmt : byte[:], ap : valist# -> size)
+            
+            /* custom formatting */
+            const fmtinstall	: (ty : byte[:], \
+                    fn : (sb : strbuf#, \
+                            ap : valist#, \
+                            opts : (byte[:],byte[:])[:] \
+                            -> void), \
+		optdesc : (byte[:], bool)[:] \
+		-> void)
+    ;;
+
+#### [Iteration Utilities](iterutil)
+
+Support for some common iteration patterns is provided. There are many kinds
+of iteration that are done, and some of the most common ones are directly
+supported by libstd.
+
+There are a few syntactic(!) issues in the language preventing these from
+taking arbitrary iterators as parameters, but when this is resolved, that
+restriction will be lifted.
+
+	pkg std =
+		type zipiter(@a, @b)
+		type reverseiter(@a)
+		type enumiter(@a)
+
+		impl iterable zipiter(@a, @b) -> (@a, @b)
+		impl iterable enumiter(@a) -> (size, @a)
+		impl iterable reverseiter(@a) -> @a
+
+		generic byzip	: (a : @a[:], b : @b[:]	 -> zipiter(@a, @b))
+		generic byenum	: (a : @a[:] -> enumiter(@a))
+		generic byreverse 	: (sl : @a[:] -> reverseiter(@a))
+	;;
+
+
+#### [Variadic Arguments](varargs)
+
+Myrddin supports variadic arguments for functions, and allows you
+to walk over them, similar to the varargs functions in C, but safer.
+
+In addition, the Myrddin compiler generates type information for the types
+that are compiled into a program. This code provides a rather awkward API
+for iterating over them, and inspecting their values.
+
+    pkg std =
+            type typedesc = union
+                    `Tynone
+                    
+                    /* atomic types */
+                    `Tyvoid
+                    `Tybool
+                    `Tychar
+                    
+                    `Tyint8
+                    `Tyint16
+                    `Tyint
+                    `Tyint32
+                    `Tyint64
+                    
+                    `Tybyte
+                    `Tyuint8
+                    `Tyuint16
+                    `Tyuint
+                    `Tyuint32
+                    `Tyuint64
+                    `Tyflt32
+                    `Tyflt64
+                    `Tyvalist
+                    
+                    /* compound types */
+                    `Typtr byte[:]
+                    `Tyfunc	typecursor
+                    `Tyslice byte[:]
+                    `Tyarray (size, byte[:])
+                    
+                    /* aggregate types */
+                    `Tytuple	typecursor
+                    `Tystruct	typecursor
+                    `Tyunion	typecursor
+                    /* name info */
+                    `Tyname (byte[:], byte[:])
+            ;;
+            type typecursor = struct
+                    nelt	: size
+                    rem	: byte[:]
+                    isnamed	: bool
+                    isiter	: bool
+            ;;
+            type typeinfo = struct
+                    size	: size
+                    align	: size
+            ;;
+            generic typeof	: (v : @a -> byte[:])
+            const typeenc	: (p : ...# -> typecursor)
+            const typeenccursor	: (e : byte[:] -> typecursor)
+            const typedesc	: (e : byte[:] -> typedesc)
+            const typeinfo	: (e : byte[:] -> typeinfo)
+            const tcnext	: (t : typecursor# -> byte[:])
+            const tcpeek	: (t : typecursor# -> byte[:])
+            const ncpeek	: (t : typecursor# -> (byte[:], byte[:]))
+            const ncnext	: (t : typecursor# -> (byte[:], byte[:]))
+
+            const vastart	: (args : ...# -> valist)
+            const vatype	: (ap : valist# -> byte[:])
+            const vabytes	: (ap : valist# -> byte[:])
+            const vaenter	: (ap : valist# -> valist)
+            generic vanext	: (ap : valist# -> @a)
+    ;;
+
+#### [Slice manipulation](slices)
+
+Slices are used everywhere within Myrddin code, so clearly we have
+some functions to manipulate them. They're listed here. Boopity boopity
+boo.
+
+    pkg std =
+            generic sleq	: (a : @a[:], b : @a[:] -> bool)
+            generic slcp    : (a : @a[:], b : @a[:] -> void)
+            generic slput	: (sl : @a[:], idx : size, elt : @a	-> @a[:])
+            generic slpush	: (sl : @a[:]#, elt : @a	-> @a[:])
+            generic sldup   : (sl : @a[:] -> @a[:])
+            generic slfill	: (sl : @a[:], v : @a	-> @a[:])
+            generic sljoin	: (dst : @a[:]#, src : @a[:]	-> @a[:])
+    ;;
+
+#### [String Manipulation](strings)
+
+String manipulation also tends to show up in code sometimes. Here are some
+functions that do that. These are all unicode aware, and will not corrupt
+utf8 data.
+
+    pkg std =
+            /* string buffers */
+            type strbuf = struct
+            ;;
+
+            const mksb	: (-> strbuf#)
+            const mkbufsb	: (buf : byte[:] -> strbuf#)
+            const sbfin	: (sb : strbuf# -> byte[:])
+            const sbfree	: (sb : strbuf# -> void)
+            const sbpeek	: (sb : strbuf# -> byte[:])
+            const sbputc	: (sb : strbuf#, v : char -> bool)
+            const sbputs	: (sb : strbuf#, v : byte[:] -> bool)
+            const sbputb	: (sb : strbuf#, v : byte -> bool)
+            const sbtrim	: (sb : strbuf#, len : size -> void)
+
+            /* string searching */
+            const strfind	: (haystack : byte[:], needle : byte[:] -> option(size))
+            const strrfind	: (haystack : byte[:], needle : byte[:] -> option(size))
+            const strhas	: (haystack : byte[:], needle : byte[:]	-> bool)
+            const hasprefix	: (s : byte[:], pre : byte[:] -> bool)
+            const hassuffix	: (s : byte[:], suff : byte[:] -> bool)
+
+            /* C strings */
+            const cstrlen	: (buf : byte[:] -> size)
+            const cstrconv	: (buf : byte[:] -> byte[:])
+            const cstrconvp	: (p : byte# -> byte[:])
+
+            /* tokenizing and splitting */
+            const strsplit	: (s : byte[:], delim : byte[:] -> byte[:][:])
+            const strtok	: (s : byte[:] -> byte[:][:])
+
+            /* string joining and stripping */
+            const strcat	: (a : byte[:], b : byte[:] -> byte[:])
+            const strjoin	: (strings : byte[:][:], delim : byte[:] -> byte[:])
+            const strstrip	: (str : byte[:] -> byte[:])
+            const strfstrip	: (str : byte[:] -> byte[:])
+            const strrstrip	: (str : byte[:] -> byte[:])
+
+            /* parsing numbers out of strings */
+            generic intparsebase	: (s : byte[:], base : int -> option(@a::(integral,numeric)))
+            generic intparse	: (s : byte[:]	-> option(@a::(integral,numeric)))
+            generic charval : (c : char, base : int -> @a::(integral,numeric))
+    ;;
+
+#### [Unicode](unicode)
+
+A bunch of predicates and conversions to handle unicode. This only
+provides simple functionality. For canonicalization, collation, and
+all of the other UAX algorithms, go look in.. oh, who am I kidding.
+I haven't had a chance to write them yet.
+
+    pkg std =
+            const Badchar	: char 
+            const Maxcharlen : size 
+            const Maxcharval : char 
+
+            /* utf8 information */
+            const charlen	: (chr : char -> size)
+            const encode	: (buf : byte[:], chr : char -> size)
+            const decode	: (buf : byte[:] -> char)
+            const striter	: (str : byte[:] -> (char, byte[:]))
+
+            /* character class predicates */
+            const isalpha	: (c : char -> bool)
+            const isdigit	: (c : char -> bool)
+            const isxdigit	: (c : char -> bool)
+            const isnum	: (c : char -> bool)
+            const isalnum	: (c : char -> bool)
+            const isspace	: (c : char -> bool)
+            const isblank	: (c : char -> bool)
+            const islower	: (c : char -> bool)
+            const isupper	: (c : char -> bool)
+            const istitle	: (c : char -> bool)
+
+            /* character class conversions */
+            const tolower	: (c : char -> char)
+            const toupper	: (c : char -> char)
+            const totitle	: (c : char -> char)
+    ;;
+
+#### [Pervasive Data Structures](datastruct)
+
+There are some data structures that basically every program seems to use:
+Sets, and hash tables. Libstd includes them for that reason.
+
+    pkg std =
+            type bitset = struct
+            ;;
+
+            type htab(@k, @v) = struct
+            ;;
+
+	    type htkviter(@k, @v)
+	    impl iterable htkviter
+
+	    type bsiter = struct
+	    impl iterable bsiter
+
+            /* bit sets */
+            const mkbs	: (-> bitset#)
+            const bsdup	: (bs : bitset# -> bitset#)
+            const bsfree	: (bs : bitset# -> void)
+            const bsmax	: (a : bitset# -> size)
+            const bscount	: (a : bitset# -> size)
+            generic bsput	: (bs : bitset#, v : @a::(integral,numeric) -> bool)
+            generic bsdel	: (bs : bitset#, v : @a::(integral,numeric) -> bool)
+            generic bshas	: (bs : bitset#, v : @a::(integral,numeric) -> bool)
+            const bsdiff	: (a : bitset#, b : bitset# -> void)
+            const bsintersect	: (a : bitset#, b : bitset# -> void)
+            const bsunion	: (a : bitset#, b : bitset# -> void)
+            const bseq	: (a : bitset#, b : bitset# -> bool)
+            const bsissubset	: (a : bitset#, b : bitset# -> bool)
+            const bsclear	: (bs : bitset# -> bitset#)
+	    const bybsvalue	: (bs : bitset# -> bsiter)
+
+            /* hash tables */
+            generic mkht	: (h : (k : @k -> uint32), eq : (a : @k, b : @k -> bool) -> htab(@k, @v)#)
+            generic htfree	: (ht : htab(@k, @v)# -> void)
+            generic htput	: (ht : htab(@k, @v)#, k : @k, v : @v -> void)
+            generic htdel	: (ht : htab(@k, @v)#, k : @k -> void)
+            generic htget	: (ht : htab(@k, @v)#, k : @k -> option(@v))
+            generic htgetv	: (ht : htab(@k, @v)#, k : @k, fallback : @v-> @v)
+            generic hthas	: (ht : htab(@k, @v)#, k : @k -> bool)
+            generic htkeys	: (ht : htab(@k, @v)# -> @k[:])
+            generic byhtkeyvals	: (ht : htab(@k, @v)# -> htkviter(@k, @v))
+
+            /* prepackaged hashing and equality tests */
+            const strhash	: (s : byte[:]	-> uint32)
+            const streq	: (a : byte[:], b : byte[:]	-> bool)
+            generic ptrhash	: (p : @a#	-> uint32)
+            generic ptreq	: (a : @a#, b : @a#	-> bool)
+            generic inthash	: (v : @a::(integral,numeric)	-> uint32)
+            generic inteq	: (a : @a::(integral,numeric), b : @a::(integral,numeric) -> bool)
+            generic slhash	: (sl : @a[:] -> uint32)
+    ;;
+
+
+#### [Pervasive Algorithms](algorithms)
+
+Many programs also use sorting and searching, so this is also provided by
+libstd. In addition, we package some useful comparison and hashing functions
+
+    pkg std =
+            /* the result of a comparison */
+            type order = union
+                    `Before
+                    `Equal
+                    `After
+            ;;
+
+            /* sorting and searching */
+            generic sort	: (sl:@a[:], cmp:(a:@a, b:@a -> order) -> @a[:])
+            generic lsearch	: (sl : @t[:], val : @t, cmp : (a : @t, b : @t -> order) -> option(@idx::(integral,numeric)))
+            generic bsearch	: (sl : @t[:], val : @t, cmp : (a : @t, b : @t -> order) -> option(@idx::(integral,numeric)))
+            generic swap	: (a : @a#, b : @a# -> void)
+
+            /* prepackaged comparisons */
+            generic numcmp	: (a : @a, b : @a -> order)
+            const strcmp	: (a : byte[:], b : byte[:] -> order)
+            const strncmp	: (a : byte[:], b : byte[:], n : size -> order)
+
+            /* extrema and absolute values */
+            generic min	: (a : @a::numeric, b : @a::numeric  -> @a::numeric)
+            generic max	: (a : @a::numeric, b : @a::numeric  -> @a::numeric)
+            generic clamp	: (a : @a::numeric, min : @a::numeric, max : @a::numeric -> @a::numeric)
+            generic abs	: (a : @a::numeric -> @a::numeric)
+    ;;
+
+#### [Randomness](randomness)
+    
+And of course, you can't go without being a little random at times.
+
+    pkg std =
+            const mksrng	: (seed : uint32 -> rng#)
+            const freerng	: (rng : rng# -> void)
+            generic rand	: (lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral))
+            generic rngrand	: (rng : rng#, lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral))
+            generic rngrandnum	: (rng : rng# -> @a::(numeric,integral))
+            const rngrandbytes	: (rng : rng#, buf : byte[:]	-> size)
+    ;;
+
+#### [Bigint Operations](bigint)
+
+While bigint usage in most programs is relatively rare, libstd needs them
+internally for handling floats, and several other widely used pieces of
+functionality also need them.
+
+As they are a significant amount of code, I decided it made sense to
+expose them in the public API.
+
+    pkg std =
+            type bigint = struct
+            ;;
+
+            generic mkbigint	: (v : @a::(numeric,integral) -> bigint#)
+            const bigfree	: (a : bigint# -> void)
+            const bigdup	: (a : bigint# -> bigint#)
+            const bigassign	: (d : bigint#, s : bigint# -> bigint#)
+            const bigmove	: (d : bigint#, s : bigint# -> bigint#)
+            const bigparse	: (s : byte[:] -> option(bigint#))
+            const bigclear	: (a : bigint# -> bigint#)
+            const bigbfmt	: (b : byte[:], a : bigint#, base : int -> size)
+            const bigtoint	: (a : bigint#	-> @a::(numeric,integral))
+            const bigiszero	: (a : bigint# -> bool)
+            const bigeq	: (a : bigint#, b : bigint# -> bool)
+            const bigcmp	: (a : bigint#, b : bigint# -> order)
+            const bigadd	: (a : bigint#, b : bigint# -> bigint#)
+            const bigsub	: (a : bigint#, b : bigint# -> bigint#)
+            const bigmul	: (a : bigint#, b : bigint# -> bigint#)
+            const bigdiv	: (a : bigint#, b : bigint# -> bigint#)
+            const bigmod	: (a : bigint#, b : bigint# -> bigint#)
+            const bigdivmod	: (a : bigint#, b : bigint# -> (bigint#, bigint#))
+            const bigshl	: (a : bigint#, b : bigint# -> bigint#)
+            const bigshr	: (a : bigint#, b : bigint# -> bigint#)
+            const bigmodpow	: (b : bigint#, e : bigint#, m : bigint# -> bigint#)
+            const bigpow	: (a : bigint#, b : bigint# -> bigint#)
+            generic bigeqi	: (a : bigint#, b : @a::(numeric,integral) -> bool)
+            generic bigaddi	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+            generic bigsubi	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+            generic bigmuli	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+            generic bigdivi	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+            generic bigshli	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+            generic bigshri	: (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+            const bigpowi	: (a : bigint#, b : uint64 -> bigint#)
+    ;;
+
+
+#### [Closures](closures)
+
+There are functions for heapifying closures, too.
+
+    pkg std =
+            generic fndup	: (fn : @fn::function -> @fn::function)
+            generic fnfree	: (fn : @fn::function -> void)
+    ;;
+
+#### [Misc](misc)
+
+Well, I said it was a grab bag.  These don't really fit into any overarching
+category.
+
+    pkg std =
+            generic KiB	: @a::(integral,numeric)	
+            generic MiB	: @a::(integral,numeric)	
+            generic GiB	: @a::(integral,numeric)	
+            generic TiB	: @a::(integral,numeric)	
+            generic PiB	: @a::(integral,numeric)	
+            generic EiB	: @a::(integral,numeric)	
+            generic ZiB	: @a::(integral,numeric)	
+            generic YiB	: @a::(integral,numeric)	
+
+            generic Sec  : @a::(integral,numeric)
+            generic Msec  : @a::(integral,numeric)
+            generic Usec  : @a::(integral,numeric)
+
+            /* time */
+            const now	: (-> time)
+
+            /* packing integers */
+            generic putle64	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+            generic putbe64	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+            generic putle32	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+            generic putbe32	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+            generic putle16	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+            generic putbe16	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+            generic putle8	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+            generic putbe8	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+
+            /* unpacking integers */
+            generic getle64	: (buf : byte[:]	-> @a::(numeric,integral))
+            generic getbe64	: (buf : byte[:]	-> @a::(numeric,integral))
+            generic getle32	: (buf : byte[:]	-> @a::(numeric,integral))
+            generic getbe32	: (buf : byte[:]	-> @a::(numeric,integral))
+            generic getle16	: (buf : byte[:]	-> @a::(numeric,integral))
+            generic getbe16	: (buf : byte[:]	-> @a::(numeric,integral))
+            generic getle8	: (buf : byte[:]	-> @a::(numeric,integral))
+            generic getbe8	: (buf : byte[:]	-> @a::(numeric,integral))
+
+            /* exploding and stitching floats */
+            const flt64bits	: (flt : flt64 -> int64)
+            const flt32bits	: (flt : flt32 -> int32)
+            const flt64frombits	: (bits : uint64 -> flt64)
+            const flt32frombits	: (bits : uint32 -> flt32)
+            const flt64explode	: (flt : flt64 -> (bool, int64, int64))
+            const flt32explode	: (flt : flt32 -> (bool, int32, int32))
+            const flt64stitch	: (flt : flt64 -> (bool, int64, int64))
+            const flt32stitch	: (flt : flt32 -> (bool, int32, int32))
+
+    ;;
--- /dev/null
+++ b/doc/api/libstd/iterutil.txt
@@ -1,0 +1,100 @@
+{
+        title:  libstd
+        description:  libstd: Summary
+}
+
+
+Iteration Utilities
+----------------
+
+	pkg std =
+		type zipiter(@a, @b)
+		type reverseiter(@a)
+		type enumiter(@a)
+
+		impl iterable zipiter(@a, @b) -> (@a, @b)
+		impl iterable enumiter(@a) -> (size, @a)
+		impl iterable reverseiter(@a) -> @a
+
+		generic byzip	: (a : @a[:], b : @b[:]	 -> zipiter(@a, @b))
+		generic byenum	: (a : @a[:] -> enumiter(@a))
+		generic byreverse 	: (sl : @a[:] -> reverseiter(@a))
+	;;
+
+Summary
+--------
+
+Iteration over sequence is something that turns up regularly. The iteration
+utilities provided here simplify a number of common instances of iteration
+over collections. They allow for iterating over a zipped sequence,
+enumerating a collection of elements, or going over a collection of elements
+in reverse.
+
+All of these iterators hold a reference to the original data, and require that
+it not be freed until they are finished consuming it. They do not copy the
+slices that they iterate over, and all consume O(1) storage.
+
+Zip Iterators
+-------------
+
+	impl iterable zipiter(@a, @b) -> (@a, @b)
+	generic byzip	: (a : @a[:], b : @b[:]	 -> zipiter(@a, @b))
+
+The zipiter takes two slices, and returns an iterator that will walk over them
+pair by pair. So, for example, if you were to call `std.byzip([1,2,3][:],
+[4,5,6][:])`, you would iterate through the elements `(1,4), (2,5), (3, 6)`.
+
+Zip Iterators
+-------------
+	impl iterable enumiter(@a) -> (size, @a)
+	generic byenum	: (a : @a[:] -> enumiter(@a))
+
+The enumiter takes a single sequence, and returns the pair of (index, element)
+tuples. If you were to call `std.byenum(["hello", "there", "friend"][:])`, you
+iterate through the elements `(1, "hello"), (2, "there"), (3, "friend")`.
+
+Reverse Iterators
+-----------------
+
+	impl iterable reverseiter(@a) -> @a
+	generic byreverse 	: (sl : @a[:] -> reverseiter(@a))
+
+
+The reverse takes a single slice, and returns the same elements back, but in
+the reverse order. Calling `std.byenum(["hello", "there", "friend"][:])`
+would iterate in the sequence `"friend", "there", "hello".
+
+Examples
+--------
+
+This is a simple zip iterator:
+
+```{runmyr zipiter}
+use std
+const main = {
+	for x in std.byzip([1,2,3][:], [4,5,6][:])
+		std.put("{}\n", x)
+	;;
+}
+```
+
+This is a simple enum iterator:
+
+```{runmyr enumiter}
+use std
+const main = {
+	for x in std.byenum(["hello", "world"][:])
+		std.put("{}\n", x)
+	;;
+}
+```
+
+```{runmyr reverseiter}
+use std
+const main = {
+	for x in std.byreverse(["hello", "world"][:])
+		std.put("{}\n", x)
+	;;
+}
+```
+
--- /dev/null
+++ b/doc/api/libstd/misc.txt
@@ -1,0 +1,107 @@
+{
+        title:  Misc
+        description:  libstd: Misc
+}
+
+Misc
+-----
+
+The mongrels and mutts of libstd.
+
+    pkg std =
+            generic KiB	: @a::(integral,numeric)	
+            generic MiB	: @a::(integral,numeric)	
+            generic GiB	: @a::(integral,numeric)	
+            generic TiB	: @a::(integral,numeric)	
+            generic PiB	: @a::(integral,numeric)	
+            generic EiB	: @a::(integral,numeric)	
+            generic ZiB	: @a::(integral,numeric)	
+            generic YiB	: @a::(integral,numeric)	
+
+            /* time */
+            const now	: (-> time)
+
+            /* packing integers */
+            generic putle64	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+            generic putbe64	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+            generic putle32	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+            generic putbe32	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+            generic putle16	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+            generic putbe16	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+            generic putle8	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+            generic putbe8	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+
+            /* unpacking integers */
+            generic getle64	: (buf : byte[:]	-> @a::(numeric,integral))
+            generic getbe64	: (buf : byte[:]	-> @a::(numeric,integral))
+            generic getle32	: (buf : byte[:]	-> @a::(numeric,integral))
+            generic getbe32	: (buf : byte[:]	-> @a::(numeric,integral))
+            generic getle16	: (buf : byte[:]	-> @a::(numeric,integral))
+            generic getbe16	: (buf : byte[:]	-> @a::(numeric,integral))
+            generic getle8	: (buf : byte[:]	-> @a::(numeric,integral))
+            generic getbe8	: (buf : byte[:]	-> @a::(numeric,integral))
+
+            /* exploding and stitching floats */
+            const flt64bits	: (flt : flt64 -> int64)
+            const flt32bits	: (flt : flt32 -> int32)
+            const flt64frombits	: (bits : uint64 -> flt64)
+            const flt32frombits	: (bits : uint32 -> flt32)
+            const flt64explode	: (flt : flt64 -> (bool, int64, int64))
+            const flt32explode	: (flt : flt32 -> (bool, int32, int32))
+            const flt64stitch	: (flt : flt64 -> (bool, int64, int64))
+            const flt32stitch	: (flt : flt32 -> (bool, int32, int32))
+
+    ;;
+
+Constants
+----------
+
+    generic KiB	: @a::(integral,numeric)	
+    generic MiB	: @a::(integral,numeric)	
+    generic GiB	: @a::(integral,numeric)	
+    generic TiB	: @a::(integral,numeric)	
+    generic PiB	: @a::(integral,numeric)	
+    generic EiB	: @a::(integral,numeric)	
+    generic ZiB	: @a::(integral,numeric)	
+    generic YiB	: @a::(integral,numeric)	
+
+    generic Sec	: time
+    generic Msec : time
+    generic Usec : time
+
+These are just constants that you can multiply things by in order to scale
+units. If you want to get a 
+
+    const now	: (-> time)
+
+Returns the current time in signed microseconds since the Unix epoch. Can
+represent dates approximatelyl 70,000 years in either direction from the
+present.
+
+    generic putle64	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+    generic putbe64	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+    generic putle32	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+    generic putbe32	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+    generic putle16	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+    generic putbe16	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+    generic putle8	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+    generic putbe8	: (buf : byte[:], v :  @a::(numeric,integral) -> size)
+
+These functions pack integers into buffers. The suffix describes the number of
+bits that will be packed -- the values will be implicitly converted to an
+integer that is `nbits` long before packing into the buffer. Signed integers
+will be sign extended, and unsigned ones will be zero extended.
+
+    generic getle64	: (buf : byte[:]	-> @a::(numeric,integral))
+    generic getbe64	: (buf : byte[:]	-> @a::(numeric,integral))
+    generic getle32	: (buf : byte[:]	-> @a::(numeric,integral))
+    generic getbe32	: (buf : byte[:]	-> @a::(numeric,integral))
+    generic getle16	: (buf : byte[:]	-> @a::(numeric,integral))
+    generic getbe16	: (buf : byte[:]	-> @a::(numeric,integral))
+    generic getle8	: (buf : byte[:]	-> @a::(numeric,integral))
+    generic getbe8	: (buf : byte[:]	-> @a::(numeric,integral))
+
+These functions unpack integers from buffers. The numeric suffix describes how
+many bits will be extracted from the buffer. The value will implicitly be
+truncated or widened to the result returned by the specialization of this
+function.
--- /dev/null
+++ b/doc/api/libstd/networking.txt
@@ -1,0 +1,181 @@
+{
+        title: Networking
+        description:    libstd: Networking
+}
+Networking
+----------
+
+    pkg std =
+            type netaddr = union
+                    `Ipv4	byte[4]
+                    `Ipv6	byte[16]
+            ;;
+
+
+            /* network connections */
+            const dial	: (dialstr : byte[:] -> result(fd, byte[:]))
+            const announce	: (ds : byte[:] -> result(fd, byte[:]))
+            const listen	: (sock : fd -> result(fd, byte[:]))
+            const accept	: (lfd : fd -> result(fd, byte[:]))
+
+            /* ip parsing */
+            const ipparse	: (ip : byte[:]	-> option(netaddr))
+            const ip4parse	: (ip : byte[:] -> option(netaddr))
+            const ip6parse	: (ip : byte[:] -> option(netaddr))
+
+            generic hosttonet	: (v : @a -> @a)
+            generic nettohost	: (v : @a -> @a)
+    ;;
+
+Summary
+-------
+
+This group of functions contains the basic, portable networking functionality
+provided by libstd. There are other packages shipped which provide access
+to the underlying functionality used to implement this code, and which may
+provide more control.
+
+The bulk of the functionality is fairly low level. Most of the client side
+networking should be done using nothing more than `dial` and `announce`
+
+Dial describes the endpoint to connect to in the form `proto!host!service`.
+`proto` can be any supported protocol.  The host specified can be an IP
+address, hostname, or path to a local socket. The service ismay be either a
+named service, or a protocol specific port. If the port is not a component of
+the address (eg, Unix domain sockets) then it should be ommitted.
+
+On plan 9, the full dial(2) dial string syntax is suported.
+
+Data Types
+----------
+
+This contains the infomation that we extract by resolving a host.
+
+    type ipaddr = union
+            `Ipv4	byte[4]
+            `Ipv6	byte[16]
+    ;;
+
+This contains an IP address. Either V4 or V6 is supported.
+
+Connections
+----------
+
+    const dial	: (dialstr : byte[:] -> result(fd, byte[:]))
+
+Dial connects to a dial string as described in the summary, returning either a
+file descriptor on success, or an error description on failure. The FD
+returned is a connection to the server.
+
+    const announce	: (ds : byte[:] -> result(fd, byte[:]))
+
+Announce sets up a file descriptor which is ready to listen for connections,
+and binds it to an address. Wildcards can be specified with '*' within the
+dial string.
+
+    const listen	: (sock : fd -> result(fd, byte[:]))
+
+Listen specifies that the socket created with `announce` is willing to accept
+connections.
+
+    const accept	: (lfd : fd -> result(fd, byte[:]))
+
+Accept takes the returned file descriptor from listen, and returns a file
+descriptor that is prepared for reading and writing.
+
+IP Parsing
+----------
+
+    const ipparse	: (ip : byte[:]	-> option(netaddr))
+
+Ipparse will parse an IP address. This will recognize either V4 or V6
+addresses, and `\`Some \`Ipv4 bits or `\`Some \`Ipv6 bits` as appropriate, or
+`\`None` if the address can't be parsed.
+
+    const ip4parse	: (ip : byte[:] -> option(netaddr))
+
+Parses an Ipv4 address from the string `ip`. The syntax expected is dotted
+quad notation. Returns `\` Some \`Ipv4 bits` if the address parses successfully, or
+`\`None` if parsing fails.
+
+    const ip6parse	: (ip : byte[:] -> option(netaddr))
+
+Parses an Ipv6 address from the string `ip`. Returns `\` Some \`Ipv4 bits` if
+the address parses successfully, or `\`None` if parsing fails. Zones are
+currently not supported. This is a bug.
+
+
+Endian flipping
+--------------
+
+    generic hosttonet	: (v : @a -> @a)
+    generic nettohost	: (v : @a -> @a)
+
+
+Flips the bits in an integer to match the expected. These functions should be
+avoided in favor of explicit packing functions.
+
+Examples
+--------
+
+Some simple examples of how to use the Myrddin networking API
+
+#### Echo Server
+
+	use std
+
+	const Dialstr = "tcp!*!1234"
+	const main = {
+		var lfd, afd
+		var buf : byte[1024]
+
+		match std.announce(Dialstr)
+		| `std.Ok f:    lfd = f
+		| `std.Fail e:  std.fatal("unable to announce on {}: {}\n", Dialstr, e)
+		;;
+
+		match std.listen(lfd)
+		| `std.Ok f:    afd = f
+		| `std.Fail e:  std.fatal("unable to listen on {}: {}\n", Dialstr, e)
+		;;
+
+		while true
+			match std.accept(afd)
+			| `std.Ok fd:
+				match std.read(fd, buf[:])
+				| `std.Ok n:
+					std.writeall(fd, buf[:n])
+				| `std.Fail e:
+					std.put("lost conection while reading: {}\n", e)
+				;;
+				std.close(fd)
+			| `std.Fail e:
+				std.fatal("unable to accept connection on {}: {}\n", Dialstr, e)
+			;;
+		;;
+	}
+		
+
+#### Echo Client
+
+	use std
+
+	const Dialstr = "tcp!localhost!1234"
+	const main = {args : byte[:][:]
+		var req, resp
+
+		match std.dial(Dialstr)
+		| `std.Ok fd:
+			req = std.strjoin(args[1:], " ")
+			std.writeall(fd, req)
+			resp = std.try(std.fslurp(fd))
+			std.put("{}\n", resp)
+		| `std.Fail e:
+			std.fatal("unable to dial {}: {}\n", Dialstr, e)
+		;;
+	}
+
+Bugs
+----
+The errors returned are strings, when they should be unions with default
+formatting functions.
--- /dev/null
+++ b/doc/api/libstd/os.txt
@@ -1,0 +1,228 @@
+{
+        title:  OS Interfaces
+        description:  libstd: OS Interfaces
+}
+
+
+OS Interfaces
+-------------
+
+    pkg std =
+            type sysinfo = struct
+                    system	: byte[:]
+                    version	: byte[:]
+                    release	: byte[:]
+                    arch	: byte[:]
+            ;;
+
+            type waitstatus = union
+                    `Wsuccess
+                    `Wfailure
+                    `Wsignalled
+                    `Waiterror
+            ;;
+
+            const Enone	: errno 
+            const Eperm	: errno 
+            const Enoent	: errno 
+            const Esrch	: errno 
+            const Eintr	: errno 
+            const Eio	: errno 
+            const Enxio	: errno 
+            const E2big	: errno 
+            const Enoexec	: errno 
+            const Ebadf	: errno 
+            const Echild	: errno 
+            const Eagain	: errno 
+            const Enomem	: errno 
+            const Eacces	: errno 
+            const Efault	: errno 
+            const Enotblk	: errno 
+            const Ebusy	: errno 
+            const Eexist	: errno 
+            const Exdev	: errno 
+            const Enodev	: errno 
+            const Enotdir	: errno 
+            const Eisdir	: errno 
+            const Einval	: errno 
+            const Enfile	: errno 
+            const Emfile	: errno 
+            const Enotty	: errno 
+            const Etxtbsy	: errno 
+            const Efbig	: errno 
+            const Enospc	: errno 
+            const Espipe	: errno 
+            const Erofs	: errno 
+            const Emlink	: errno 
+            const Epipe	: errno 
+            const Edom	: errno 
+            const Erange	: errno 
+            const Emisc	: errno 
+
+            const Failmem	: byte#	
+
+            const getpid	: ( -> pid)
+            const getsysinfo	: (si : sysinfo# -> void)
+            const execvp	: (cmd : byte[:], args : byte[:][:] -> int64)
+            const execvpe	: (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> int64)
+            const getenv :	(name : byte[:] -> option(byte[:]))
+            const getenvv :	(name : byte[:], default : byte[:] -> byte[:])
+            const fork	: (-> pid)
+            const execv	: (cmd : byte[:], args : byte[:][:] -> int64)
+            const execve	: (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> int64)
+            const waitpid	: (pid:pid, loc:int32#, opt : int64	-> int64)
+            const spork	: (cmd : byte[:][:]	-> result((pid, fd, fd), int))
+            const sporkfd	: (cmd : byte[:][:], infd : fd, outfd : fd	-> result(pid, int))
+            const exit	: (status:int -> void)
+            const now	: (-> time)
+            const wait	: (pid : pid -> waitstatus)
+
+    ;;
+
+    type sysinfo = struct
+            system	: byte[:]
+            version	: byte[:]
+            release	: byte[:]
+            arch	: byte[:]
+    ;;
+
+The `sysinfo` struct is returned from the operating system, giving
+some information about the sytem that this program is running on. It
+is similar to the `uname` function in the standard C library, although
+it is guaranteed to be portable. All the storage for the members is
+within the private parts of the struct, and no freeing is needed to
+relase them.
+
+    type waitstatus = union
+            `Wsuccess
+            `Wfailure
+            `Wsignalled
+            `Waiterror
+    ;;
+
+This type indicates the exit status of a child process that was invoked
+with one of the exec family of functions. It only returns a broad category
+of values, and does not return the full details provided by the os -- this
+is not portable. If the exact exit status is needed, the `sys` package
+should cover this need.
+
+    const Enone	: errno 
+    const Erange	: errno 
+    const Ebadf	: errno 
+    const Eexist	: errno 
+    const Einval	: errno 
+    const Efault	: errno 
+    const Eio	: errno 
+    const Emisc	: errno 
+
+
+The errno results are used to signal OS errors. They are not going to remain
+stable, and will probably be replaced with system call specific unions for
+error handling in future API work. Use them, but parsimoniously. The code
+that uses them will break.
+
+Emisc is used for any non-portable error codes.
+
+    const getpid	: ( -> pid)
+
+Returns the process id of the current process.
+
+    const getsysinfo	: (si : sysinfo# -> void)
+
+Fills a `sysinfo` struct with information about the platform that the program
+is running on.
+
+    const execv	: (cmd : byte[:], args : byte[:][:] -> errno)
+    const execve	: (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> errno)
+
+    const execvp	: (cmd : byte[:], args : byte[:][:] -> errno)
+    const execvpe	: (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> errno)
+
+Executes a program. If the command `cmd` begins with a `/`, then it is
+resolved as an absolute path. Otherwise, command is resolved relative to the
+current directory.
+
+If the path in `cmd` is not an absolute path, the `execvp` variants of this
+function will search the path for this program in each directory relative to
+$PATH or $path, in addition to the current directory.
+
+The arguments in `args` are passed to the executed program as its argument
+vector. By convention, the first argument in the `args` array should be the
+filename of the program being executed.
+
+For the `execvp` exec variant, the current program's environment is inherited,
+and is not modified.
+
+The `execvpe` variant of this function takes an additional argument `env`,
+which is passed to the invoked binary, replacing alll the current environment
+variables. It is in the form of a list of `"ENV_VAR=value"` key value pairs.
+
+Returns: Errno on failure. On success, the function does not return.
+
+    const getenv :	(name : byte[:] -> option(byte[:]))
+
+The `getenv` function looks up a variable from the process environment.
+
+Returns: `\`Some env\_val` for an environment variable that is present in the
+environment, or `\`None` if it is not present.
+
+    const getenvv :	(name : byte[:], default : byte[:] -> byte[:])
+
+The `getenvv` is the same as `getenv, with the exception that will return the
+value of the environment variable if it is present, or `default` if there is
+no such environment variable.
+
+Returns: The value of "name" if present, or "default" if not.
+
+    const fork	: (-> pid)
+
+This forks a new process. This function returns twice, once in the parent
+and once in the child.
+
+On a successful fork, within the parent process `fork` returns a process ID
+greater than zero, which is the process id of the child process. Within the
+child process, `fork` returns zero.
+
+If the `fork` function returns a value less than zero, then creating a child
+process failed.
+
+Returns: The pid of the child.
+
+    const wait	: (pid : pid -> waitstatus)
+
+`wait` waits for a process with the PID `pid` to exit, returning its final
+status. This function blocks until the child process has exited. If the
+process has already exited before this function is called, but has not yet
+been called on the process id of the child process, then this function
+will return a status immediately.
+
+If the child process has already been waited on, calling this function is
+invalid, and it should return a `\`Waiterror`.
+
+Returns: A waitstatus, telling you if the process crashed, exited with
+failure, exited with success, or whether the wait call was invalid.
+
+    const spork	: (cmd : byte[:][:]	-> result((pid, fd, fd), errno))
+
+Spork stand for `Speak to Process Fork`. It returns a process id and an
+input and output file descriptor via which you can communicate to the process
+over stdin and stdout. Stderr is inherited from the current process.
+
+Returns: Either a tuple of (pid, stdin, stdout) on success, or the error
+that caused the failure.
+
+    const sporkfd	: (cmd : byte[:][:], infd : fd, outfd : fd	-> result(pid, errno))
+
+Sporkfd is identical to spork, however, instead of returning new file
+descriptors, it uses the file descriptors passed in.
+
+Returns: Either the pid spawned, or the error that caused the spawn failure.
+
+
+    const exit	: (status:int -> void)
+
+This exits a process with the status specified. On most Unixy systems,
+this will return the value to the shell. On Plan 9, this will call
+exits() with the number converted to a string.
+
+This function terminates the process.
--- /dev/null
+++ b/doc/api/libstd/randomness.txt
@@ -1,0 +1,88 @@
+{
+        title:  Randomness
+        description:    libstd: Randomness
+}
+
+
+Randomness
+----------
+
+    pkg std =
+            type rng = struct
+                ...
+            ;;
+
+            generic rand	: (lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral))
+            generic randnum	: (rng : rng# -> @a::(numeric,integral))
+            const randbytes	: (buf : byte[:] -> size)
+
+            const mksrng	: (seed : uint32 -> rng#)
+            const freerng	: (rng : rng# -> void)
+            generic rngrand	: (rng : rng#, lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral))
+            generic rngrandnum	: (rng : rng# -> @a::(numeric,integral))
+            const rngrandbytes	: (rng : rng#, buf : byte[:]	-> size)
+    ;;
+
+
+Overview
+--------
+
+Currently, the random number generation interface is quite poor. It is not
+cryptographically secure, although it should be. It exposes some functions
+that it should not.
+
+Overall, deterministic random numbers should be removed from APIs that do not
+define the specific generator.
+
+Types
+-----
+
+    type rng = struct
+        ...
+    ;;
+
+The `rng` type contains the state for the random number generator.
+
+Functions
+---------
+
+    generic rand	: (lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral))
+
+Generates a random integer in the range [lo, hi), returning the value. The
+range [lo, hi) must be positive, nonempty, and the difference between hi and
+lo must be less then 2^(type_bits - 1)
+
+    generic randnum	: (rng : rng# -> @a::(numeric,integral))
+
+Generates a random integer of any magnitude the type may hold. The returned
+value may be negative, if the type is signed.
+
+    const randbytes	: (buf : byte[:] -> size)
+
+Fills a buffer with random bytes.
+
+    const mksrng	: (seed : uint32 -> rng#)
+
+Allocates and initializes a random number generator. The seed `seed` is used
+to seed the generator. The returned random number generator must be freed
+using `freerng`.
+
+    const freerng	: (rng : rng# -> void)
+
+Frees all resources associated with the random number generator `rng`.
+
+    generic rngrand	: (rng : rng#, lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral))
+
+
+Generates a random integer from `rng` in the range [lo, hi), returning the
+value. The range [lo, hi) must be positive, nonempty, and the difference
+between hi and lo must be less then 2^(type_bits - 1)
+
+    generic rngrandnum	: (rng : rng# -> @a::(numeric,integral))
+
+Generates a random integer of any size from the random number generator `rng`.
+The returned value may be negative, if the type is signed.
+
+    const rngrandbytes	: (rng : rng#, buf : byte[:]	-> size)
+
+Fills a buffer with random bytes from the random number generator `rng`.
--- /dev/null
+++ b/doc/api/libstd/slices.txt
@@ -1,0 +1,71 @@
+{
+        title:  Slice Manipulation
+        description:  libstd: Slice Manipulation
+}
+
+
+Slice Manipulation
+------------------
+
+    pkg std =
+            generic sleq	: (a : @a[:], b : @a[:] -> bool)
+            generic slcp        : (dst : @a[:], src : @a[:] -> void)
+            generic slput	: (sl : @a[:], idx : size, elt : @a	-> @a[:])
+            generic slpush	: (sl : @a[:], elt : @a	-> @a[:])
+            generic slpop	: (sl : @a[:] -> (@a, @a[:]))
+            generic sldup       : (sl : @a[:] -> @a[:])
+            generic slfill	: (sl : @a[:], v : @a	-> @a[:])
+            generic sljoin	: (dst : @a[:]#, src : @a[:]	-> @a[:])
+    ;;
+
+
+Functions
+---------
+
+    generic sleq	: (a : @a[:], b : @a[:] -> bool)
+
+Compares if two slices are equal, elementwise. Uses the '==' operator for
+each value. Returns true if they are equal, false otherwise.
+
+    generic slcp    : (dst : @a[:], src : @a[:] -> void)
+
+Copies all the elements from `src` to `dst`. The copy made is shallow,
+and done using the `=` operator. The two slices must be equal size. If they
+are not equal, this will cause the program to abort.
+
+    generic slput	: (sl : @a[:], idx : size, elt : @a	-> @a[:])
+
+Inserts a value `elt` into the slice `sl` at index `idx`, moving all values
+from `sl[idx:len]` to `sl[idx+1:len+1]`. This assumes that the slice is either
+empty, or is allocated on the heap using `slalloc`.
+
+This may move the slice, invalidating the original input argument.
+
+    generic slpush	: (sl : @a[:], elt : @a	-> @a[:])
+
+Inserts a value `elt` into the slice `sl` at index the end of the slice.
+
+This may move the slice, invalidating the original input argument.
+
+
+    generic slpop	: (sl : @a[:] -> (@a, @a[:]))
+
+Removes an element from the end of the slice, returning the element and the
+new, truncated slice.
+
+This may move the slice, invalidating the original input argument.
+
+    generic sldup   : (sl : @a[:] -> @a[:])
+
+Duplicates a slice. This function is equivalent to calling slalloc() followed
+by slcp().
+
+    generic slfill	: (sl : @a[:], v : @a	-> @a[:])
+
+Fills a slice with a value.
+
+    generic sljoin	: (dst : @a[:]#, src : @a[:]	-> @a[:])
+
+Concatenates `src` onto the end of `dst#`. Equivalent to iterating through
+every element of `src` and `slpush()`ing it onto `dst`.
+
--- /dev/null
+++ b/doc/api/libstd/strings.txt
@@ -1,0 +1,205 @@
+{
+        title:  Strings
+        description:  libstd: Strings
+}
+
+Summary
+-------
+
+    pkg std =
+            /* string buffers */
+            type strbuf = struct
+            ;;
+
+            const mksb	: (-> strbuf#)
+            const mkbufsb	: (buf : byte[:] -> strbuf#)
+            const sbfin	: (sb : strbuf# -> byte[:])
+            const sbfree	: (sb : strbuf# -> void)
+            const sbpeek	: (sb : strbuf# -> byte[:])
+            const sbputc	: (sb : strbuf#, v : char -> bool)
+            const sbputs	: (sb : strbuf#, v : byte[:] -> bool)
+            const sbputb	: (sb : strbuf#, v : byte -> bool)
+            const sbtrim	: (sb : strbuf#, len : size -> void)
+
+            /* string searching */
+            const strfind	: (haystack : byte[:], needle : byte[:] -> option(size))
+            const strrfind	: (haystack : byte[:], needle : byte[:] -> option(size))
+            const strhas	: (haystack : byte[:], needle : byte[:]	-> bool)
+            const hasprefix	: (s : byte[:], pre : byte[:] -> bool)
+            const hassuffix	: (s : byte[:], suff : byte[:] -> bool)
+
+            /* C strings */
+            const cstrlen	: (buf : byte[:] -> size)
+            const cstrconv	: (buf : byte[:] -> byte[:])
+            const cstrconvp	: (p : byte# -> byte[:])
+
+            /* tokenizing and splitting */
+            const strsplit	: (s : byte[:], delim : byte[:] -> byte[:][:])
+            const bstrsplit	: (sp : byte[:][:], s : byte[:], delim : byte[:] -> byte[:][:])
+            const strtok	: (s : byte[:] -> byte[:][:])
+            const bstrtok	: (sp : byte[:][:], s : byte[:] -> byte[:][:])
+
+            /* string joining and stripping */
+            const strcat	: (a : byte[:], b : byte[:] -> byte[:])
+            const strjoin	: (strings : byte[:][:], delim : byte[:] -> byte[:])
+            const strstrip	: (str : byte[:] -> byte[:])
+            const strfstrip	: (str : byte[:] -> byte[:])
+            const strrstrip	: (str : byte[:] -> byte[:])
+
+            /* parsing numbers out of strings */
+            generic intparsebase	: (s : byte[:], base : int -> option(@a::(integral,numeric)))
+            generic intparse	: (s : byte[:]	-> option(@a::(integral,numeric)))
+            generic charval : (c : char, base : int -> @a::(integral,numeric))
+    ;;
+
+
+Types
+------
+
+    type strbuf = struct
+    ;;
+
+The `strbuf` type contains a string buffer under construction. It can operate
+in two modes: Allocated, and static. The allocated mode keeps track
+of buffer sizing, and grows it efficiently as the data is appended to it.
+
+The static mode, on the other hand, has a fixed size buffer that is provided
+to it, and truncates values to fit the buffer if needed. This can be used when
+allocations are undesirable.
+
+Functions: String buffers
+--------------------------
+
+    const mksb	: (-> strbuf#)
+
+Mksb creates an string buffer. The buffer returned is in allocated mode, and
+starts off with an empty string.
+
+    const mkbufsb	: (buf : byte[:] -> strbuf#)
+
+Mkbufsb creates a fixed size string buffer, initialized with `buf`. The
+initial length of the string is empty, regardless of the contents of the
+buffer. Anything in it will be overwritten as appends happen.
+
+    const sbfin	: (sb : strbuf# -> byte[:])
+
+Sbfin finishes the string buffer. Any auxiliary resources allocated by the
+string buffer are released, and the final string that was constructed is
+returned. In dynamic mode, the string is heap allocated, and must be freed
+with `slfree`. Otherwise, it is simply a slice into the buffer passed in
+the `mkbufsb` call.
+
+    const sbfree	: (sb : strbuf# -> void)
+
+Sbfree frees the string buffer `sb`, and all associated resources. The string
+under construction is discarded if the buffer is dynamically allocated.
+
+    const sbpeek	: (sb : strbuf# -> byte[:])
+
+Sbpeek returns the portion of the string that has already been constructed
+by the string buffer, without freeing it. The returned string is only valid
+as long as the buffer is not modified.
+
+    const sbputc	: (sb : strbuf#, v : char -> bool)
+
+Sbputc appends a single character to the string buffer, encoding it into
+utf8 before appending it to the buffer. If the buffer is fixed and the
+character will not fit, then it will be dropped in its entirety.
+
+Returns: True if there was sufficient space to append the character, false
+otherwise.
+
+    const sbputs	: (sb : strbuf#, v : byte[:] -> bool)
+
+Sbputs appends a string to the string buffer. If the buffer is a static
+buffer, and the string is too long to fit, as much of it as can possibly fit
+will be copied. This may truncate characters mid-way through.
+
+Returns: True if there was sufficient space to append the character, false
+otherwise.
+
+    const sbputb	: (sb : strbuf#, v : byte -> bool)
+
+Sbputs appends a single byte to the string buffer. If the buffer is a static
+buffer and the character does not fit, the buffer will remain unmodified
+
+Returns: True if there was sufficient space to append the byte, false
+otherwise.
+
+    const sbtrim	: (sb : strbuf#, len : size -> void)
+
+Truncates a string buffer to the length provided. If the length provided i
+longer than the size of the buffer, the length of the buffer remains
+unmodified.
+
+
+Functions: Searching
+--------------------
+
+    const strfind	: (haystack : byte[:], needle : byte[:] -> option(size))
+    const strrfind	: (haystack : byte[:], needle : byte[:] -> option(size))
+
+Strfind finds the first occurrence of the string `needle` within the string
+`haystack`.Strrfind is similar, but it finds the last occurrence of `needle`
+within `haystack`.
+
+Returns: `\`std.Some index` if needle is found within haystack, or `\`None`
+otherwise.
+
+    const strhas	: (haystack : byte[:], needle : byte[:]	-> bool)
+
+Strhas returns `true` if the string `needle` is found within haystack.
+
+    const hasprefix	: (s : byte[:], pre : byte[:] -> bool)
+
+hasprefix returns `true` if the string `pre` is found at the start of `s`.
+
+    const hassuffix	: (s : byte[:], suff : byte[:] -> bool)
+
+hassuffix returns `true` if the string `pre` is found at the end of `s`.
+
+
+Functions: Splitting and joining
+--------------------------------
+
+    const strsplit	: (s : byte[:], delim : byte[:] -> byte[:][:])
+    const strtok	: (s : byte[:] -> byte[:][:])
+
+Strsplit and strtok will split a string into its components. Strsplit uses a
+string passed in as a delimiter, while strtok will use a variable amount of
+whitespace to split the string. They dynamically allocate the split vector,
+but not the elements within it.
+
+If there are repeated delimiters, `strsplit` will include zero length strings
+between them. For example, `std.strsplit("a<><>b<>c", "<>")` will return
+`["a", "", "b", "c"]`.
+
+    const bstrsplit	: (sp : byte[:][:], s : byte[:], delim : byte[:] -> byte[:][:])
+    const strtok	: (sp : byte[:][:], s : byte[:] -> byte[:][:])
+
+The bstrsplit and bstrtok functions produce a split string similar to the
+strsplit versions above, but will fill the `sp` vector passed in, instead of
+allocating their own storage. If there are more splits to be made than the
+vector can hold, then the last element will contain the tail of the string.
+
+
+    const strcat	: (a : byte[:], b : byte[:] -> byte[:])
+
+Strcat will concatenate two strings, returning a new buffer containing the
+string that was created.
+
+    const strjoin	: (strings : byte[:][:], delim : byte[:] -> byte[:])
+
+
+Strcat will concatenate all strings in a list, returning a new buffer
+containing the string that was created. It will interpose the delimiter
+between them.
+
+    const strstrip	: (str : byte[:] -> byte[:])
+    const strfstrip	: (str : byte[:] -> byte[:])
+    const strrstrip	: (str : byte[:] -> byte[:])
+
+
+Strstrip will remove all whitespace characters from both ends of the string.
+Strfstrip and strrstrip will strip all whitespace characters from the start or
+end of the of the string, respectively.
--- /dev/null
+++ b/doc/api/libstd/unicode.txt
@@ -1,0 +1,133 @@
+{
+        title: Unicode
+        description:    libstd: Unicode
+}
+
+Unicode
+--------
+
+    pkg std =
+            const Badchar	: char 
+            const Maxcharlen : size 
+            const Maxcharval : char 
+
+	    /* iterators */
+	    impl iterable chariter -> char
+
+	    const chariter	: (byte[:] -> chariter)
+
+            /* utf8 information */
+            const charlen	: (chr : char -> size)
+            const encode	: (buf : byte[:], chr : char -> size)
+            const decode	: (buf : byte[:] -> char)
+            const strstep	: (str : byte[:] -> (char, byte[:]))
+
+            /* character class predicates */
+            const isalpha	: (c : char -> bool)
+            const isdigit	: (c : char -> bool)
+            const isxdigit	: (c : char -> bool)
+            const isnum	: (c : char -> bool)
+            const isalnum	: (c : char -> bool)
+            const isspace	: (c : char -> bool)
+            const isblank	: (c : char -> bool)
+            const islower	: (c : char -> bool)
+            const isupper	: (c : char -> bool)
+            const istitle	: (c : char -> bool)
+
+            /* character class conversions */
+            const tolower	: (c : char -> char)
+            const toupper	: (c : char -> char)
+            const totitle	: (c : char -> char)
+    ;;
+
+Summary
+-------
+
+As a reminder, Myrddin characters hold a single Unicode codepoint, and all
+strings are assumed to be encoded in UTF-8 by default. These functions are
+designed to facilitate manipuating unicode strings and codepoints.
+
+The APIs are generally designed that strings will be streamed through, and
+not encoded or decoded wholesale.
+
+Constants
+---------
+    const Badchar	: char 
+
+This is a character value that is not, and will never be, a valid unicode
+codepoint. This is generally returned when we encounter an error fr 
+
+    const Maxcharlen : size 
+
+This is a constant defining the maximum number of bytes that a character may
+be decoded into. It's guaranteed that a buffer that is at least Maxcharlen
+bytes long will be able to contain any character.
+
+    const Maxcharval : char 
+
+This is the maximum value that any valid future unicode codepoint may decode
+into. Any character that is greater than this is an invalid character.
+
+Functions: Iterating over strings
+--------------------------------
+
+	impl iterable chariter -> char
+
+	const chariter	: (byte[:] -> chariter)
+
+Chariter returns an iterator which steps through a string character by
+character.
+
+Functions: Encoding and Decoding
+--------------------------------
+
+    const charlen	: (chr : char -> size)
+
+Charlen returns the length in bytes that decoding the character provided into
+unicode would take. This can vary between 1 and Maxcharlen bytes.
+
+    const encode	: (buf : byte[:], chr : char -> size)
+
+Encode takes a single character, and encodes it to a utf8 string. The buffer
+must be at least long enough to hold the character.
+
+Returns: The number of bytes written, or -1 if the character could not be
+encoded.
+
+    const decode	: (buf : byte[:] -> char)
+
+Decode converts the head of the buffer `buf` to a single unicode codepoint,
+returning the codepoint itself, or `Badchar` if the codepoint is invalid.
+
+The tail of the buffer is not considered, allowing this function to be used
+to peek at the contents of a string.
+
+    const strstep	: (str : byte[:] -> (char, byte[:]))
+
+strstep is a function for stepping through unicode encoded strings. It
+returns the tuple (`Badchar`, str[1:]) if the value cannot be decoded,
+or `(charval, str[std.charlen(charval):])` therwise.
+
+
+```{runmyr striter}
+    s = "abcd"
+    while s.len != 0
+            (c, s) = std.striter(s)
+            std.put("next char is {}\n", s)
+    ;;
+```
+
+Character Classes
+-----------------
+
+    const isalpha	: (c : char -> bool)
+    const isdigit	: (c : char -> bool)
+    const isxdigit	: (c : char -> bool)
+    const isnum	: (c : char -> bool)
+    const isalnum	: (c : char -> bool)
+    const isspace	: (c : char -> bool)
+    const isblank	: (c : char -> bool)
+    const islower	: (c : char -> bool)
+    const isupper	: (c : char -> bool)
+    const istitle	: (c : char -> bool)
+
--- /dev/null
+++ b/doc/api/libstd/varargs.txt
@@ -1,0 +1,189 @@
+{
+        title:  Varargs
+        description:  libstd: Varargs
+}
+
+Varargs
+-------
+
+    pkg std =
+            type typedesc = union
+                    `Tynone
+                    
+                    /* atomic types */
+                    `Tyvoid
+                    `Tybool
+                    `Tychar
+                    
+                    `Tyint8
+                    `Tyint16
+                    `Tyint
+                    `Tyint32
+                    `Tyint64
+                    
+                    `Tybyte
+                    `Tyuint8
+                    `Tyuint16
+                    `Tyuint
+                    `Tyuint32
+                    `Tyuint64
+                    `Tyflt32
+                    `Tyflt64
+                    `Tyvalist
+                    
+                    /* compound types */
+                    `Typtr byte[:]
+                    `Tyfunc	typecursor
+                    `Tyslice byte[:]
+                    `Tyarray (size, byte[:])
+                    
+                    /* aggregate types */
+                    `Tytuple	typecursor
+                    `Tystruct	typecursor
+                    `Tyunion	typecursor
+                    /* name info */
+                    `Tyname (byte[:], byte[:])
+            ;;
+
+            type typecursor = struct
+                    nelt	: size
+            ;;
+
+            type typeinfo = struct
+                    size	: size
+                    align	: size
+            ;;
+
+            generic typeof	: (v : @a -> byte[:])
+            const typeenc	: (p : ...# -> typecursor)
+            const typeenccursor	: (e : byte[:] -> typecursor)
+            const typedesc	: (e : byte[:] -> typedesc)
+            const typeinfo	: (e : byte[:] -> typeinfo)
+            const tcnext	: (t : typecursor# -> byte[:])
+            const tcpeek	: (t : typecursor# -> byte[:])
+            const ncpeek	: (t : typecursor# -> (byte[:], byte[:]))
+            const ncnext	: (t : typecursor# -> (byte[:], byte[:]))
+
+            const vastart	: (args : ...# -> valist)
+            const vatype	: (ap : valist# -> byte[:])
+            const vabytes	: (ap : valist# -> byte[:])
+            const vaenter	: (ap : valist# -> valist)
+            generic vanext	: (ap : valist# -> @a)
+    ;;
+
+Overview
+--------
+
+Type descriptions are encoded byte strings. 
+
+Types
+-----
+
+
+    type typedesc = union
+            ...
+    ;;
+
+
+Typedesc provides a description of a type. It can be paired with a valist for
+walking over the contents of a value, but this is ugly.
+
+
+    type typecursor = struct
+            nelt	: size
+    ;;
+
+A type cursor allows for iterating over the subtypes of a type. It exposes the
+number of elements in the subtype.
+
+    type typeinfo = struct
+            size	: size
+            align	: size
+    ;;
+
+Typeinfo contains all of the attributes that we care about for the type. This
+may expand in the future.
+
+
+Type iteration
+---------
+
+    generic typeof	: (v : @a -> byte[:])
+
+Typeof takes any arbitrary value, and returns an encoded type description for
+the type of the value. It would be better to provide a first class interface
+for finding type encodings, but this needs thought.
+
+    const typeenc	: (p : ...# -> typecursor)
+
+Typeenc returns a type cursor for an argument list, allowing for iteration
+over the type of values within it.
+
+    const typeenccursor	: (e : byte[:] -> typecursor)
+
+Typeenccursor takes a type encoding, and converts it to a cursor with a single
+type. Iterating the cursor will return only the one type encoding that was
+passed to this function.
+
+    const typedesc	: (e : byte[:] -> typedesc)
+
+Typedesc extracts a typedesc from an encoded type. The type description
+may contain other type cursors for iterating over subtypes.
+
+    const typeinfo	: (e : byte[:] -> typeinfo)
+
+Typeinfo extracts a typeinfo from an encoded type. The type description
+contains attributes about the type, such as the size and alignment.
+
+    const tcnext	: (t : typecursor# -> byte[:])
+
+Tcnext pulls an encoded subtype from a type cursor and advances it.
+Calling this on a cursor that has a name is acceptable, and will
+discard the name.
+
+    const tcpeek	: (t : typecursor# -> byte[:])
+
+Tcnext pulls an encoded subtype from a type cursor and does not it.
+Calling this on a cursor that has a name is acceptable, and will
+discard the name.
+
+    const ncnext	: (t : typecursor# -> (byte[:], byte[:]))
+
+Ncnext pulls an encoded subtype from a type cursor for a type with named
+subtypes, and advances the type cursor. such as a struct or union, and returns
+the name and encoded type.
+
+    const ncpeek	: (t : typecursor# -> (byte[:], byte[:]))
+
+Ncpeek pulls an encoded subtype from a type cursor for a type with named
+subtypes, such as a struct or union, and returns the name and encoded
+type. This does not advance the cursor.
+
+Variadic Arguments
+-----------------
+
+    const vastart	: (args : ...# -> valist)
+
+Vastart takes a pointer to a variadic argument list, and returns a valist,
+which is basically an iterator for arguments.
+
+    const vatype	: (ap : valist# -> byte[:])
+
+Vatype returns a type encoding for the current variadic argument that the
+valist is pointing to.
+
+    generic vanext	: (ap : valist# -> @a)
+
+Vanext returns the next value for the variadic type, and advances the valist.
+
+    const vabytes	: (ap : valist# -> byte[:])
+
+Vanext returns a slice to the bytes of the variadic argument, and advances the
+valist.
+
+    const vaenter	: (ap : valist# -> valist)
+
+Vaenter does not advance the valist, but returns a new valist for the
+argument, allowing iteration over the fields within the argument. For example,
+if you had a struct passed as a variadic argument, calling 'vaenter' on it
+would allow iterating over the members of the struct.
--- /dev/null
+++ b/doc/api/libtestr/index.txt
@@ -1,0 +1,64 @@
+{
+        title:  libtestr
+        description:    Myrddin Test Library
+}
+
+Libtestr
+---------
+
+    pkg testr =
+            type ctx
+            
+            type spec = struct
+            	name	: byte[:]
+            	fn	: (ctx : ctx# -> void)
+            ;;
+            
+            const run	: (specs : spec[:] -> void)
+            const ok	: (ctx : ctx# -> void)
+            const fail	: (ctx : ctx#, msg : byte[:] -> void)
+    ;;
+
+Overview
+--------
+
+The testr library provides a simple library for running
+unit tests. It outputs subtest results in a format that mbld
+will be able to understand, log, and report on.
+
+Types
+-----
+
+    type ctx
+
+The context for the current test. Used to record the state
+of the set of tests currently running.
+
+    type spec = struct
+            name	: byte[:]
+            fn	: (ctx : ctx# -> void)
+    ;;	
+
+The specification for a single test. Contains the name
+of the test being run, and the code used to execute it.
+
+Mutex.
+
+Functions: Mutexes
+------------------
+            
+    const run	: (specs : spec[:] -> void)
+
+Runs a sequence of tests, recording the state of the test
+and outputting an appropriate log for mtest to consume.
+
+    const ok	: (ctx : ctx# -> void)
+
+Records a test success. It does not leave the current
+scope.
+
+    const fail	: (ctx : ctx#, msg : byte[:] -> void)
+
+Records a test failure. It does not leave the current
+scope.
+
--- /dev/null
+++ b/doc/api/libthread/index.txt
@@ -1,0 +1,115 @@
+{
+        title:  libthread
+        description:    Myrddin Thread Library
+}
+
+Libthread
+---------
+
+    pkg thread =
+            trait atomic @a::(integral,numeric) =
+                    xget	: (p : @a# -> @a)
+                    xset	: (p : @a#, v : @a -> void)
+                    xadd	: (p : @a#, v : @a -> @a)
+                    xsub	: (p : @a#, v : @a -> @a)
+                    xcas	: (p : @a#, old : @a, new : @a -> @a)
+                    xchg	: (p : @a#, new : @a -> @a)
+            ;;
+
+            type cond = struct
+                    ...
+            ;;
+
+            type mutex = struct
+                    ...
+            ;;	
+
+            impl atomic int32
+            impl atomic int64
+            impl atomic uint32
+            impl atomic uint64
+
+            /* mutexes */
+            const mkmtx	: (-> mutex)
+            const mtxlock	: (mtx : mutex# -> void)
+            const mtxtrylock	: (mtx : mutex# -> bool)
+            const mtxunlock	: (mtx : mutex# -> void)
+
+            /* condition variables */
+            const mkcond	: (mtx : mutex# -> cond)
+            const condwait	: (cond : cond# -> void)
+            const condsignal	: (cond : cond# -> void)
+            const condbroadcast	: (cond : cond# -> void)
+    ;;
+
+Types
+-----
+
+    type cond = struct
+            ...
+    ;;
+
+Condition variable.
+
+    type mutex = struct
+            ...
+    ;;	
+
+    trait atomic @a::(integral,numeric) =
+            xget	: (p : @a# -> @a)
+            xset	: (p : @a#, v : @a -> void)
+            xadd	: (p : @a#, v : @a -> @a)
+            xsub	: (p : @a#, v : @a -> @a)
+            xcas	: (p : @a#, old : @a, new : @a -> @a)
+            xchg	: (p : @a#, new : @a -> @a)
+    ;;
+
+
+Mutex.
+
+Functions: Mutexes
+------------------
+
+    const mkmtx	: (-> mutex)
+
+Crates a new mutex, in the unlocked state.
+
+    const mtxlock	: (mtx : mutex# -> void)
+
+Locks a mutex. Blocks if the mutex is already locked.
+
+    const mtxtrylock	: (mtx : mutex# -> bool)
+
+Attempts to lock a mutex. Returns true if the lock was
+taken successful. Returns false if the lock was not taken.
+
+This call does not block.
+
+    const mtxunlock	: (mtx : mutex# -> void)
+
+Unlocks a mutex that is taken. It is a bug to call this on a mutex that you
+have not successfully locked.
+
+Functions: Condition Variables.
+------------------------------
+
+    const mkcond	: (mtx : mutex# -> cond)
+
+Creates a condition variable. Associates the mutex with the condition
+variable.
+
+    const condwait	: (cond : cond# -> void)
+
+Waits on the condition to be notiifed on. Must be called with the associated
+mutex locked. Unlocks the mutex that is associated with the condition variable
+and sleeps until someone has notified on the condition variable.
+
+    const condsignal	: (cond : cond# -> void)
+
+Wakes at least one waiter on the condition variable, allowing them to take the
+mutex.
+
+    const condbroadcast	: (cond : cond# -> void)
+
+Wakes all waiters on the condition variable.
+