summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2014-09-18 18:55:44 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2014-09-18 18:55:44 +0000
commit3534b428629be185e096be99e3bd5fdfe32d5544 (patch)
tree210ef3198ed66bc7f7b7bf6a85e4579f455e5a36 /doc
downloadskalibs-3534b428629be185e096be99e3bd5fdfe32d5544.tar.xz
initial commit with rc for skalibs-2.0.0.0
Diffstat (limited to 'doc')
-rw-r--r--doc/crosscompile.html93
-rw-r--r--doc/djblegacy.html151
-rw-r--r--doc/flags.html313
-rw-r--r--doc/index.html131
-rw-r--r--doc/libbiguint/index.html391
-rw-r--r--doc/libdatastruct/index.html40
-rw-r--r--doc/librandom/index.html113
-rw-r--r--doc/libskarnet.html100
-rw-r--r--doc/libstdcrypto/index.html110
-rw-r--r--doc/libstddjb/alloc.html98
-rw-r--r--doc/libstddjb/allreadwrite.html145
-rw-r--r--doc/libstddjb/bitarray.html131
-rw-r--r--doc/libstddjb/djbtime.html201
-rw-r--r--doc/libstddjb/djbunix.html760
-rw-r--r--doc/libstddjb/gccattributes.html48
-rw-r--r--doc/libstddjb/genalloc.html46
-rw-r--r--doc/libstddjb/genwrite.html98
-rw-r--r--doc/libstddjb/index.html125
-rw-r--r--doc/libstddjb/iopause.html196
-rw-r--r--doc/libstddjb/ip46.html172
-rw-r--r--doc/libstddjb/lolstdio.html91
-rw-r--r--doc/libstddjb/safewrappers.html91
-rw-r--r--doc/libstddjb/selfpipe.html242
-rw-r--r--doc/libstddjb/stralloc.html118
-rw-r--r--doc/libstddjb/tai.html462
-rw-r--r--doc/libunixonacid/index.html58
-rw-r--r--doc/libunixonacid/kolbak.html40
-rw-r--r--doc/libunixonacid/skaclient.html34
-rw-r--r--doc/libunixonacid/unix-timed.html34
-rw-r--r--doc/libunixonacid/unix-transactional.html34
-rw-r--r--doc/libunixonacid/unixmessage.html40
-rw-r--r--doc/license.html82
-rw-r--r--doc/upgrade.html34
33 files changed, 4822 insertions, 0 deletions
diff --git a/doc/crosscompile.html b/doc/crosscompile.html
new file mode 100644
index 0000000..ba22b31
--- /dev/null
+++ b/doc/crosscompile.html
@@ -0,0 +1,93 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>How to cross-compile skalibs</title>
+ <meta name="Description" content="How to cross-compile skalibs" />
+ <meta name="Keywords" content="skalibs build cross-compilation" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> How to cross-compile skalibs </h1>
+
+<p>
+ There are three issues in the world of cross-compilation:
+</p>
+
+<ul>
+ <li> support for parallel builds: the source directory must be read-only
+and each build process must have its own build tree. </li>
+ <li> support for compiler options: to specify the target architecture,
+the header and library files that should be used, etc.
+ <li> build-time tests performed on the build architecture are invalid
+if the target architecture is different. </li>
+</ul>
+
+<h2> Support for parallel builds </h2>
+
+<p>
+ skalibs does not support out-of-tree builds at the moment,
+but since the source code tree is small, it's not costly to duplicate it
+to perform parallel builds. If the source code trees grows significantly
+larger, out-of-tree build support will be considered.
+</p>
+
+<h2> Support for build-time options </h2>
+
+<p>
+ skalibs now uses a standard <tt>./configure &amp;&amp; make &amp;&amp; make install</tt>
+process, and cross-compiling build-time options can be given on the
+<tt>./configure</tt> command line.
+</p>
+
+<h2> Bypassing the build-time tests </h2>
+
+<p>
+ This is the hardest part of cross-compilation, and very few build systems
+get it right. (GNU autotools does not, which is one of the reasons why
+skarnet.org packages do not use autotools.)
+</p>
+
+<p>
+ Native build procedures usually perform build-time tests: they compile
+executables and run them (on the build platform, which is the same as
+the target platform) to check for features and system quirks. skalibs
+does exactly that: the <tt>./configure</tt> step performs tests on the
+build platform and stores the system-dependent results in a directory
+that it calls the <em>sysdeps</em> for this platform.
+</p>
+
+<p>
+But in a
+cross-compilation environment, build-time tests are invalid, since the build
+platform and the target platform differ.
+ There is only one way to cross-compile portable code without resorting
+to build-time autodetection:
+<strong>you must provide by hand the sysdeps for your target
+architecture</strong>, via the --with-sysdeps option to configure.
+</p>
+
+<p>
+ The easiest way to get the correct sysdeps for a target achitecture is
+to natively compile skalibs on that target, and steal the produced sysdeps
+files. It can be easily done with a virtual machine, qemu for instance.
+You could also (politely) ask for precompiled sysdeps on the
+skaware mailing-list, if you cannot find them anywhere on the Internet.
+</p>
+
+<h2> Credits </h2>
+
+<p>
+<a href="http://www.kegel.com/">Dan Kegel</a> brought up the need for a
+clean cross-compilation system.
+</p>
+
+</body>
+</html>
diff --git a/doc/djblegacy.html b/doc/djblegacy.html
new file mode 100644
index 0000000..0cdd891
--- /dev/null
+++ b/doc/djblegacy.html
@@ -0,0 +1,151 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the djb legacy</title>
+ <meta name="Description" content="skalibs: the djb legacy" />
+ <meta name="Keywords" content="skalibs c unix djb legacy library libstddjb" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The DJB legacy </h1>
+
+<h2> Who is this DJB guy, and why is he so special anyway&nbsp;? </h2>
+
+<p>
+<a href="http://cr.yp.to/">Dan J. Bernstein</a> is a cryptologist and
+a mathematician; he's also the author of a widely known and used MTA,
+<a href="http://cr.yp.to/qmail.html">qmail</a>, as well as a few
+lesser known pieces of software.
+</p>
+
+<p>
+ For some time he was quite active in some Unix software-related
+Internet newsgroups and mailing-lists; he quickly became a
+controversial figure of the Unix programming community, mostly
+by being extremely vocal against well-known authors of
+"mainstream" Unix software and by suggesting designs so removed
+from traditional software design that a normal human reaction is
+to first view him as a complete nut.
+</p>
+
+<p>
+ I do not care for controversy. I am interested in the code. I was
+a sysadmin at the time, and still learning to program in C beyond
+what they teach you in school (i.e. not much). I had heard enough
+horror stories with sendmail; so I gave a shot at qmail, trying to
+understand its design principles and the way it was made. And then
+I fell down the rabbit hole.
+</p>
+
+<p>
+ Look, I don't care what you think of the guy, I don't know him
+anyway, and this is totally beside the point. The only thing that
+matters is that DJB's software is <strong>right</strong> in so
+many ways. This software <strong>works</strong>. DJB's design
+principles are <strong>sound</strong> and elegant; they are
+sound foundations to build <strong>reliable, secure, and
+low resource-consuming</strong> software. And the design,
+when you get used to it, feels so unix-ish: it's Unix the way it
+should have been from the start.
+</p>
+
+<p>
+ Studying DJB's software was the best course in C/Unix programming
+I ever had. Now I <em>teach</em> C/Unix; and I am really glad I
+learned from the best.
+</p>
+
+<h2> Building beyond DJB's works. </h2>
+
+<p>
+ There's already
+<a href="http://thedjbway.b0llix.net/">a lot you can do</a> with
+pristine DJB software and some brains.
+</p>
+
+<p>
+ However, I mostly see DJB as a pioneer. He showed it was possible
+to think Unix differently and build secure, reliable and efficient
+software without investing millions of dollars into it; now it is
+up to software architects and programmers to use the breakthrough
+and build upon it. There's a real demand for quality Unix software
+out there; it's time to supply. And
+<a href="http://thedjbway.b0llix.net/friends.html">I am not the only
+one</a> thinking this way.
+</p>
+
+<p>
+ So, skalibs.
+</p>
+
+<p>
+ One of the "DJB philosophy" key points is to <em>question the
+interfaces</em>. You have a task to do; you have existing interfaces.
+What do you do?
+</p>
+
+<ul>
+ <li> Most people don't even think about it and use the existing
+interfaces, even if it amounts to cramming a square peg into a
+round hole. This is why buffer overflows exist. This is why
+people use abominations such as
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/gets.html">gets()</a>,
+<em>which is still in the Single Unix Specification as of version 4,
+in freaking June 2011</em>. This is why the System V
+initialization scheme is still prevalent in Linux distributions,
+despite being one of the slowest and most unreliable of all
+initialization schemes. This is why people still use the
+atrocious "libresolv" DNS client library. </li>
+ <li> An alternative way of thinking is to ask yourself:
+"Is the interface I have adequate for the task at hand?"
+ <ul>
+ <li> If yes: perfect, use that interface. </li>
+ <li> If no: then <em>do not use</em> that interface, duh. Design a
+better one and use it: so the complexity will be split and the code
+will be easier to maintain. </li>
+ </ul> </li>
+</ul>
+
+<p>
+ Interfaces should be questioned <em>right down to the libc</em>. You
+cannot build strong software on flakey foundations. And from a system
+and network programmer's point of view, one thing is clear: <em>most
+standard libc interfaces suck.</em> There is no buffered asynchronous
+I/O. There is no timed I/O. There is no heap management helper. Even
+<a href="libstddjb/safewrappers.html">simple system calls are not
+guaranteed to succeed!</a>
+</p>
+
+<p>
+ That is where skalibs comes from. skalibs results from questioning
+the libc interfaces, and providing replacements or additions where
+the existing interfaces do not make it easy to write reliable, secure
+and efficient software. It is <em>inspired by</em> DJB's work. It is
+not a shrine or anything of the kind.
+</p>
+
+<h2> Conclusion </h2>
+
+<p>
+ So, in short, DJB is not a guru, I'm not a mindless brainwashed fan,
+and the "DJB advocates" are not a cult. We just think DJB brought
+something to Unix and more generally to the software programming world;
+we learned from him, we write software following
+sound principles that he was one of the first to really apply, and we give
+credit where credit is due.
+</p>
+
+<p>
+ Use our software. You will never want to go back.
+</p>
+
+</body>
+</html>
diff --git a/doc/flags.html b/doc/flags.html
new file mode 100644
index 0000000..2579d5a
--- /dev/null
+++ b/doc/flags.html
@@ -0,0 +1,313 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: configuration flags</title>
+ <meta name="Description" content="skalibs: configuration flags" />
+ <meta name="Keywords" content="skalibs build compilation configuration flags options" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> skalibs configuration flags </h1>
+
+<p>
+ The skalibs <tt>./configure</tt> script comes with a few
+uncommon options; this page explains what they are for.
+</p>
+
+<a name="slashpackage"><h3> --enable-slashpackage[=<em>sproot</em>] </h3></a>
+
+<p>
+ This flag tells configure that you want to install skalibs according to
+the <a href="http://cr.yp.to/slashpackage.html">slashpackage convention</a>.
+If you enable it, and $v is the version of skalibs you're compiling,
+<tt>make install</tt> will install the skalibs header files in
+<tt>/package/prog/skalibs-$v/include</tt>, the static libraries in
+<tt>/package/prog/skalibs-$v/library</tt>, the dynamic libraries in
+<tt>/package/prog/skalibs-$v/library.so</tt> and the data files in
+<tt>/package/prog/skalibs-$v/etc</tt>, all prefixed by <em>sproot</em>
+it present. It will also add two more "make" targets:
+</p>
+
+<ul>
+ <li> <tt>make update</tt> will update the <tt>/package/prog/skalibs</tt>
+symbolic link to point to <tt>skalibs-$v</tt> </li>
+ <li> <tt>make -L global-links </tt> will make links from <tt>/library.so</tt>
+to the installed skalibs shared libraries. </li>
+</ul>
+
+<a name="replace-libc"><h3> --enable-libc-replacements </h3></a>
+
+<p>
+ If this option is given, then the low-level components
+of <a href="libstddjb/">libstddjb</a>, such as <tt>byte_copy()</tt>,
+will be built using independent, failsafe implementations; skalibs will
+avoid relying on the libc when possible.
+</p>
+
+<p>
+ If this option is not given, then native libc primitives such as
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/memmove.html">memmove()</a>
+will be used for the low-levels components of libstddjb. This is the default.
+</p>
+
+<p>
+ This flag should be set if your libc has known bugs or you are uncertain
+of it for some reason. Standard libcs on modern systems have been thoroughly
+tested, so it's usually safe, and faster, to stick to the default.
+</p>
+
+<a name="clockistai"><h3> --enable-tai-clock </h3></a>
+
+<p>
+ To understand what this flag is about - and the next three flags too - you
+should start by reading
+<a href="http://www.madore.org/~david/computers/unix-leap-seconds.html">this
+page about Unix time</a>,
+which <a href="http://www.madore.org/~david/">David Madore</a> wrote after
+a long and fairly complete discussion we had on the subject. You can also
+read <a href="http://cr.yp.to/proto/utctai.html">what DJB says about Unix time</a>.
+Unfortunately, when he says "the POSIX rules are so outrageously dumb (...)
+that no self-respecting engineer would obey them", DJB is wrong: a lot of
+people follow the POSIX rules. Or maybe he's right... and there are very,
+very few self-respecting engineers.
+</p>
+
+<p>
+ Basically, when you configure a Unix system, there are essentially two
+ways to deal with your system clock.
+</p>
+
+<ol>
+ <li> You can set your system clock to TAI-10, which is the "right", but
+uncommon, thing to do:
+ <ul>
+ <li> &uarr; The main advantage of this setup is that it makes your system clock
+<em>linear</em>. In other words,
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/gettimeofday.html">gettimeofday()</a>
+becomes suitable for both timestamping (which needs absolute time) and timeout
+computations (which need reliable interval measurements); if your clock is
+accurate enough, it can function as both a wall clock and a stopwatch.
+This simplifies keeping track of the current time <strong>considerably</strong>,
+and makes event loop handling (with functions such as
+<a href="libstddjb/iopause.html">iopause()</a>) trivial. </li>
+ <li> &uarr; skalibs uses TAI internally; setting your system clock to TAI-10
+saves a lot of conversions and makes time computations with skalibs more
+efficient. </li>
+ <li> &rarr; In order to display GMT or local time properly, you have to
+use the <tt>right/</tt> timezones from Arthur David Olson's timezone
+library. If your libc does not support them, see the
+<a href="#tzisright">next flag</a>. </li>
+ <li> &darr; This setup is arguably not SUSv4 conformant (a strict
+interpretation of Single Unix requires the system clock to be set to UTC). </li>
+ <li> &darr; This setup is <em>not</em> compatible with
+<a href="http://en.wikipedia.org/wiki/Ntpd">ntpd</a>. <tt>ntpd</tt>'s design
+is flawed: it makes the mistake of setting the system clock itself - instead
+of simply making the computed time available to other programs, one of which
+could set the system clock - and it always sets it to UTC. (The
+<a href="http://www.skarnet.org/software/s6-networking/">s6-networking</a>
+package provides alternate ways to synchronize your clock, though.) </li>
+ </ul>
+ </li>
+ <li> You can set your system clock to UTC, which is the common, strictly
+POSIX setup:
+ <ul>
+ <li> &uarr; This is strictly SUSv4-compliant. Most Unix machines all over
+the world are set up like this. </li>
+ <li> &uarr; This is compatible with ntpd. </li>
+ <li> &rarr; You should not use Olson's time library in that case. </li>
+ <li> &darr; skalibs time computations will take a bit more processing power. </li>
+ <li> &darr; Most importantly, you forsake all linearity - and even monotonicity
+- on your system clock, which can now only be used as a wall clock,
+<em>not</em> as a stopwatch. skalibs will try its best to do accurate time
+computations, but there's no way <tt>gettimeofday()</tt> can be relied on
+when a leap second is nearby; you have to use CLOCK_MONOTONIC as a stopwatch
+for accurate interval measurement. </li>
+ </ul>
+ </li>
+</ol>
+
+<p>
+ USe <tt>--enable-tai-clock</tt> if your system clock is set to TAI-10.
+I generally recommend this setup
+for computers you have full control on, on which you install and tweak
+the software your way, like manually administered servers or embedded
+boxes. If you do not run ntpd and do not mind breaking POSIX, it is the
+sensible choice.
+</p>
+
+<p>
+ Do not use this option if your system clock is set to UTC, i.e. if
+you're in none of the above cases: you are a
+POSIX freak, or your Unix distribution is running ntpd for you, or
+other software is assuming you're on UTC. This is the default.
+</p>
+
+
+<a name="tzisright"><h3> --enable-right-tz </h3>
+
+<p>
+ This option instructs skalibs that you're using Olson's time
+library, i.e. "right/" timezones.
+</p>
+
+<p>
+ Normally, if you set <a href="#clockistai">--enable-tai-clock</a>, you
+<em>should</em> also set up your timezone to a "right/" one, and
+set <tt>flag-tzisright</tt>. And if you don't use
+<a href="#clockistai">--enable-tai-clock</a>, you should also use a POSIX
+timezone, and NOT use <tt>--enable-right-tz</tt>. Those two options
+should always be used together.
+</p>
+
+<p>
+ <em>But</em> some C libraries do not support the Olson time library's
+timezone format, and just do not provide the "right/" timezones! For
+instance, <a href="http://musl-libc.org/">musl</a>,
+an alternative libc for Linux, only supports POSIX timezones. And you
+might want to use such a libc, and <em>still</em> set up your clock to
+TAI-10, for instance in embedded environments where accurate timekeeping
+is important. In such cases, you'll set up a POSIX timezone, and use the
+<tt>--enable-tai-clock</tt> option without the <tt>--enable-right-tz</tt> one.
+</p>
+
+<p>
+ Be aware that setting your system clock to TAI-10 without having a
+"right/" timezone will cause non-skalibs-using software to display
+local time incorrectly; in such a setup, only skalibs-using software
+will understand what is going on and do the proper computations to
+display the correct local time. Keep your settings as consistent as
+possible.
+</p>
+
+<p>
+ By default, skalibs will consider you are using POSIX timezones (as well
+as a UTC system clock).
+</p>
+
+<a name="usert"><h3> --enable-clock </h3></a>
+
+<p>
+ The Open Group Base Specifications, issue 7, describes <tt>gettimeofday()</tt>
+as obsolescent, and recommends the use of
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_gettime.html">clock_gettime()</a>
+with the CLOCK_REALTIME option instead. However:
+</p>
+
+<ul>
+ <li> <tt>clock_gettime()</tt> is not as portable; for instance, Darwin does not have it. </li>
+ <li> On most systems, using the <tt>clock_</tt> functions requires linking with <tt>librt</tt>,
+which is slightly inconvenient - and silly if all you want is timestamping.
+</ul>
+
+<p>
+ If <tt>--enable-clock</tt> is set, the <a href="libstddjb/tai.html">tain_now()
+and tain_setnow()</a> functions for getting and setting time will be based on
+the <tt>clock_gettime()</tt> and <tt>clock_settime()</tt> functions.
+</p>
+
+<p>
+ Otherwise, the old-school <tt>gettimeofday()</tt>
+and <tt>settimeofday()</tt> interfaces will be used. This is the default,
+and it's usually safe.
+</p>
+
+<a name="usemon"><h3> --enable-monotonic </h3></a>
+
+<p>
+ Unless you have an accurate hardware system clock <em>and</em> you set it
+on a linear time scale such as TAI-10 instead of UTC (see above), it is
+generally a bad idea to trust the system clock for precise time interval
+measurements. Single Unix recommends the use of <tt>clock_gettime()</tt>
+with the CLOCK_MONOTONIC option to do such measurements: a stopwatch, not
+a wall clock. However:
+</p>
+
+<ul>
+ <li> CLOCK_MONOTONIC is even less portable than CLOCK_REALTIME. </li>
+ <li> It's a bit tricky to emulate absolute time calculations based on
+CLOCK_MONOTONIC. </li>
+</ul>
+
+<p>
+ If <tt>--enable-monotonic</tt> is set, then the absolute time given by the
+<tt>tain_now()</tt> call will be computed with CLOCK_MONOTONIC. This
+will ensure precise time arithmetic but may drift away from the system
+clock.
+</p>
+
+<p>
+ Otherwise, <tt>tain_now()</tt> will
+return a time based on the system clock, and not use CLOCK_MONOTONIC.
+This is the default.
+</p>
+
+<a name="noipv6"><h3> --disable-ipv6 </h3></a>
+
+<p>
+ If you set this option, then skalibs will be compiled without IPv6 support,
+even if your target architecture supports it. This can significantly
+reduce the size of your networking applications if they don't need IPv6
+support.
+</p>
+
+<p>
+ If you don't set this option, then skalibs will include IPv6 support in the
+relevant networking functions, if the target architecture supports it.
+The safe option is to let this flag clear.
+</p>
+
+<a name="forcedevr"><h3> --enable-force-devr </h3></a>
+
+<p>
+ If this option is set, then the automatic sysdeps tests will assume the
+target architecture has a working <tt>/dev/random</tt> and will skip
+its autodetection.
+</p>
+
+<p>
+ Otherwise, <tt>/dev/random</tt> will be autodetected
+and tested; if entropy generation is low on the host, the compilation
+process might hang for several minutes. It is safe to let this flag
+clear; it should only be set to speed up the compilation process in a
+known environment and for testing purposes.
+</p>
+
+<p>
+ If skalibs is being cross-compiled, this flag obviously has no effect:
+the presence of a working <tt>/dev/random</tt> is read from the user-provided
+sysdeps.
+</p>
+
+<a name="forcedevr"><h3> --enable-egd=<em>path</em> </h3></a>
+
+<p>
+ If you set this option, then the <a href="librandom/">librandom</a> functions
+will assume the presence of an EGD daemon listening on <em>path</em>,
+and use it to get random data.
+</p>
+
+<p>
+ By default, skalibs will not include EGD support.
+</p>
+
+<a name="defaultpath"><h3> --with-default-path=<em>path</em> </h3></a>
+
+<p>
+ The <a href="libstddjb/djbunix.html">execvep()</a> function uses
+the value of the PATH environment variable as its executable search path.
+Specifying this option to configure tells execvep() what executable
+search path to use when PATH is undefined (which should not happen
+often anyway).
+ The default is <tt>/usr/bin:/bin</tt>, which is usually safe.
+</p>
+
+</body>
+</html>
diff --git a/doc/index.html b/doc/index.html
new file mode 100644
index 0000000..344ffff
--- /dev/null
+++ b/doc/index.html
@@ -0,0 +1,131 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: a C library for system programming</title>
+ <meta name="Description" content="skalibs: a C library for system programming" />
+ <meta name="Keywords" content="skalibs package skarnet.org libraries public domain" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> skalibs </h1>
+
+<h2> What is it&nbsp;? </h2>
+
+<p>
+ skalibs is a package centralizing the free software / open source C development
+files used for building all software at skarnet.org: it contains essentially
+general-purpose libraries.
+You will need to install skalibs if you plan to build skarnet.org software.
+ The point is that you won't have to download and compile big libraries, and care
+about portability issues,
+everytime you need to build a package: do it only once.
+</p>
+
+<p>
+ skalibs can also be used as a sound basic start for C development. There
+are a lot of general-purpose libraries out there; but if your main goal is
+to produce <em>small</em> and <em>secure</em> C code with a focus on system
+programming, skalibs might be for you.
+</p>
+
+<hr />
+
+<h2> Installation </h2>
+
+<h3> Requirements </h3>
+
+<ul>
+ <li> A Unix-like system, compliant with
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/">The
+Open Group Base Specifications Issue 7</a>,
+with a standard C development environment </li>
+ <li> GNU make, version 3.81 or later </li>
+</ul>
+
+<h3> Licensing </h3>
+
+<p>
+ skalibs is free software. It is available under the
+<a href="http://opensource.org/licenses/ISC">ISC license</a>.
+</p>
+
+<h3> Download </h3>
+
+<ul>
+ <li> The current skalibs version is <a href="skalibs-2.0.0.0.tar.gz">2.0.0.0</a>. </li>
+</ul>
+
+<h3> Compilation </h3>
+
+<ul>
+ <li> See the enclosed INSTALL file for installation details. </li>
+ <li> skalibs sports a few uncommon options to its <tt>./configure</tt> script.
+<a href="flags.html">This page</a> documents them in detail. </li>
+</ul>
+
+<h3> Upgrade notes </h3>
+
+<ul>
+ <li> <a href="upgrade.html">This page</a> lists the differences to be aware of between
+the previous versions of skalibs and the current one. </li>
+</ul>
+
+<h3> Cross-compilation </h3>
+
+<p>
+ Cross-compilation is tricky. skalibs provides system-agnostic interfaces, so all the
+other skarnet.org packages cross-compile easily; but some effort needs to be made to
+cross-compile skalibs, see <a href="crosscompile.html">this page</a>.
+
+<hr />
+
+<h2> Reference </h2>
+
+<h3> Libraries </h3>
+
+<ul>
+<li> <a href="libskarnet.html">The <tt>skarnet</tt> library interface</a> </li>
+</ul>
+
+<hr />
+
+<h2> Similar work </h2>
+
+<p>
+ Here are a few other libraries originating from the same place as
+skalibs, i.e. people start to reuse and package, or rewrite,
+<a href="djblegacy.html">code from Dan J. Bernstein</a>, and then patch
+after patch, addition after addition, the code evolves into a project
+of its own:
+</p>
+
+<ul>
+ <li> <a href="http://b0llix.net/">Wayne Marshall</a>'s <em>libasagna</em>,
+available for instance in the
+<a href="http://b0llix.net/perp/site.cgi">perp</a> package </li>
+ <li> <a href="http://www.fefe.de/">Felix von Leitner</a>'s
+<a href="http://www.fefe.de/libowfat/">libowfat</a> </li>
+ <li> <a href="http://untroubled.org/">Bruce Guenter</a>'s
+<a href="http://untroubled.org/bglibs/">bglibs</a> </li>
+ <li> <a href="http://dogmap.org/">Paul Jarc</a>'s
+<a href="http://code.dogmap.org./prjlibs/">prjlibs</a>, which also
+includes libraries for Scheme programming </li>
+</ul>
+
+<h2> Related resources </h2>
+
+<ul>
+ <li> <tt>skalibs</tt> is discussed on the
+<a href="http://www.skarnet.org/lists.html#skaware">skaware</a> mailing-list. </li>
+ </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/libbiguint/index.html b/doc/libbiguint/index.html
new file mode 100644
index 0000000..30de27e
--- /dev/null
+++ b/doc/libbiguint/index.html
@@ -0,0 +1,391 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the biguint library interface</title>
+ <meta name="Description" content="skalibs: the biguint library interface" />
+ <meta name="Keywords" content="skalibs biguint libbiguint library interface" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://www.skarnet.org/software/">Software</a><br />
+<a href="http://www.skarnet.org/">www.skarnet.org</a>
+</p>
+
+<h1> The <tt>biguint</tt> library interface </h1>
+
+<p>
+<tt>biguint</tt> is set of simple primitives performing arithmetical
+operations on (unsigned) integers of arbitrary length. It is nowhere
+near as powerful or efficient as specialized,
+assembly language-optimized libraries such as
+<a href="http://gmplib.org/">GMP</a>, but it has the advantages
+of smallness and simplicity.
+</p>
+
+<h2> Compiling </h2>
+
+<ul>
+ <li> Use <tt>#include &lt;skalibs/biguint.h&gt;</tt> </li>
+</ul>
+
+<h2> Programming </h2>
+
+<p>
+ You should refer to the <tt>skalibs/biguint.h</tt> header for the exact function
+prototypes.
+</p>
+
+<h3> <a name="defs" />
+Definitions </h3>
+
+<ul>
+ <li> A <em>biguint</em> <tt>x</tt> is a pointer to an array <tt>u</tt>
+of uint32, together with an unsigned integer <tt>n</tt> called its <em>length</em>.
+<br><tt>x = (2^32)^0 * u[0] + (2^32)^1 * u[1] + ... + (2^32)^(n-1) * u[n-1]</tt>. </li>
+ <li> Every <tt>u[i]</tt> is called a <em>limb</em>. </li>
+ <li> The greatest integer <tt>i</tt> lesser than <tt>n</tt> for which
+<tt>u[i]</tt> is non-zero is called the <em>order</em> of <tt>x</tt>. The
+order of zero is 0. </li>
+</ul>
+
+<h3> <a name="basic" />
+Basic operations </h3>
+
+<h4> Creating a biguint </h4>
+
+<p>
+ Just declare <tt>uint32 x[n] ;</tt> - <em>n</em> being the length of the
+biguint. You could also allocate <em>x</em> in the heap, possibly using a
+uint32 <a href="../libstddjb/genalloc.html">genalloc</a>. In the following,
+a biguint is always referred to as a <tt>uint32 *</tt> with its
+<tt>unsigned int</tt> length ; it must always be pre-allocated.
+</p>
+
+<p>
+ If an operation fails because a biguint's length <tt>n</tt> is too small to
+accommodate the result, the function will write the first (i.e. least significant)
+<tt>n</tt> limbs of the result, truncating it, then return 0 with errno set to
+EOVERFLOW.
+</p>
+
+<h4> Setting it to zero </h4>
+
+<pre>
+uint32 *x ;
+unsigned int n ;
+
+ bu_zero(x, n) ;
+</pre>
+
+<p>
+<tt>bu_zero()</tt> sets the first <tt>n</tt> limbs of <tt>x</tt> to zero.
+</p>
+
+<h4> Copying a biguint </h4>
+
+<pre>
+uint32 const *x ;
+unsigned int xn ;
+uint32 *y ;
+unsigned int yn ;
+
+ bu_copy(y, yn, x, xn) ;
+</pre>
+
+<p>
+<tt>bu_copy()</tt> copies <tt>x</tt> to <tt>y</tt>, setting higher limbs of <tt>y</tt>
+to zero if needed. It then returns 1. If <tt>y</tt> is too small to contain <tt>x</tt>,
+the function returns 0 EOVERFLOW.
+</p>
+
+<h4> Calculating the order </h4>
+
+<pre>
+uint32 const *x ;
+unsigned int n ;
+unsigned int r ;
+
+ r = bu_len(x, n) ;
+</pre>
+
+<p>
+<tt>bu_len()</tt> outputs the order of <tt>x</tt> of length <tt>n</tt>.
+<tt>0&nbsp;&lt;=&nbsp;r&nbsp;&lt;=&nbsp;n</tt>.
+</p>
+
+<h4> Comparing two biguints </h4>
+
+<pre>
+uint32 const *a ;
+unsigned int an ;
+uint32 const *b ;
+unsigned int bn ;
+int r ;
+
+ r = bu_cmp(a, an, b, bn) ;
+</pre>
+
+<p>
+<tt>bu_cmp()</tt> returns -1 if <tt>a&nbsp;&lt;&nbsp;b</tt>, 1 if
+<tt>a&nbsp;&gt;&nbsp;b</tt>, and 0 if <tt>a&nbsp;=&nbsp;b</tt>.
+</p>
+
+<h3> <a name="io" />
+I/O operations </h3>
+
+<h4> Writing a biguint as an array of bytes </h4>
+
+<pre>
+char *s ;
+uint32 const *x ;
+unsigned int n ;
+
+ bu_pack(s, x, n) ;
+ bu_pack_big(s, x, n) ;
+</pre>
+
+<p>
+<tt>bu_pack()</tt> writes <tt>4*n</tt> bytes to <tt>s</tt>. The bytes
+are a little-endian representation of <tt>x</tt>.<br />
+<tt>bu_pack_big()</tt> is the same, with a big-endian representation.
+</p>
+
+<h4> Reading a biguint from an array of bytes </h4>
+
+<pre>
+char const *s ;
+uint32 *x ;
+unsigned int n ;
+
+ bu_unpack(s, x, n) ;
+ bu_unpack_big(s, x, n) ;
+</pre>
+
+<p>
+<tt>bu_unpack()</tt> reads <tt>4*n</tt> little-endian bytes from <tt>s</tt>
+and writes them into the corresponding biguint <tt>x</tt>. <br />
+<tt>bu_unpack_big()</tt> is the same, but the bytes are interpreted as
+big-endian.
+</p>
+
+<h4> Formatting a biguint for readable output </h4>
+
+<pre>
+char *s ;
+uint32 const *x ;
+unsigned int n ;
+
+ bu_fmt(s, x, n) ;
+</pre>
+
+<p>
+<tt>bu_fmt()</tt> writes <tt>x</tt> in <tt>s</tt> as a standard big-endian
+hexadecimal number. <tt>x</tt> is considered of length <tt>n</tt>, so
+<tt>8*n</tt> bytes will be written to <tt>s</tt>, even if it <tt>x</tt>
+starts with zeros. <tt>bu_fmt</tt> returns the number of bytes written.
+</p>
+
+<h4> Reading a biguint from readable format </h4>
+
+<pre>
+char const *s ;
+uint32 *x ;
+unsigned int xn ;
+unsigned int z ;
+unsigned int len ;
+
+ len = bu_scanlen(s, &amp;z) ;
+ bu_scan(s, len, x, xn, z) ;
+</pre>
+
+<p>
+ bu_scanlen() scans <tt>s</tt> for a biguint written as a hexadecimal
+number and returns the number of
+bytes read. The reading stops at the first byte encountered that is not
+in the 0-9, A-F or a-f range. The <tt>z</tt> integer then contains the
+number of bytes excluding leading zeros.
+</p>
+
+<p>
+ If x has not been allocated yet, you can use <tt>xn = bitarray_div8(z)</tt>
+(if you have included the <tt>bitarray.h</tt> header)
+and allocate <tt>x</tt> with length <tt>xn</tt>.
+</p>
+
+<p>
+<tt>bu_scan()</tt> then reads <tt>len</tt> bytes from <tt>s</tt>, assuming
+there are <tt>z</tt> significant bytes (i.e. not leading zeros); it writes
+the resulting biguint into <tt>x</tt> of length <tt>xn</tt>. It returns 1,
+except if <tt>xn</tt> is too small, in which case it returns 0 EOVERFLOW.
+</p>
+
+<h3> <a name="arith" />
+Arithmetic operations </h3>
+
+<h4> Addition </h4>
+
+<pre>
+uint32 const *a ;
+unsigned int an ;
+uint32 const *b ;
+unsigned int bn ;
+uint32 *c ;
+unsigned int cn ;
+unsigned char carrybefore ;
+unsigned char carryafter ;
+
+ bu_add(c, cn, a, an, b, bn) ;
+ bu_sub(c, cn, a, an, b, bn) ;
+</pre>
+
+<p>
+<tt>bu_add()</tt> adds <tt>a</tt> and <tt>b</tt>, and puts the result
+into <tt>c</tt>. It returns 1 unless it has to truncate it.
+</p>
+
+<p>
+<tt>bu_sub()</tt> substracts <tt>b</tt> from <tt>a</tt>, and puts the
+result into <tt>c</tt>. If the result should be negative, then it is
+written as <tt>(2^32)^cn - c</tt> and the function returns 0 EOVERFLOW.
+</p>
+
+<h4> Multiplication </h4>
+
+<pre>
+uint32 const *a ;
+unsigned int an ;
+uint32 const *b ;
+unsigned int bn ;
+uint32 *c ;
+unsigned int cn ;
+
+ bu_mul(c, cn, a, an, b, bn) ;
+</pre>
+
+<p>
+<tt>bu_mul()</tt> computes <tt>c=a*b</tt>.
+Make sure that <tt>cn</tt> &ge; <tt>bu_len(a, an) + bu_len(b, bn)</tt>.
+If it is not the case, the result will be truncated and bu_mul will return
+0 EOVERFLOW.
+</p>
+
+<h4> Division </h4>
+
+<pre>
+uint32 const *a ;
+unsigned int an ;
+uint32 const *b ;
+unsigned int bn ;
+uint32 *q ;
+unsigned int qn ;
+uint32 *r ;
+unsigned int rn ;
+
+ bu_div(a, an, b, bn, q, qn, r, rn) ;
+ bu_mod(r, rn, b, bn) ;
+</pre>
+
+<p>
+<tt>bu_div()</tt> computes <tt>q</tt>, the quotient, and <tt>r</tt>, the
+remainder, of <tt>a</tt> divided by <tt>b</tt>. If <tt>b</tt> is zero, it
+returns 0 EDOM. If <tt>qn</tt> or <tt>rn</tt> is to small to store the
+quotient or the remainder, it returns 0 EOVERFLOW.
+<tt>bu_mod()</tt> computes only the remainder, and stores it in-place.
+</p>
+
+<h4> GCD </h4>
+
+<pre>
+uint32 *r ;
+unsigned int rn ;
+uint32 const *a ;
+unsigned int an ;
+uint32 const *b ;
+unsigned int bn ;
+
+ bu_gcd(r, rn, a, an, b, bn) ;
+</pre>
+
+<p>
+</p>
+<tt>bu_gcd()</tt> computes the greatest common divisor between <tt>a</tt>
+and <tt>b</tt>, and stores it into <tt>r</tt>. It returns 1 if all went well.
+</p>
+
+<p>
+ Note that this function iterates on divisions, so it might use a non totally
+negligible amount of CPU time.
+</p>
+
+
+<h4> Left-shifts and right-shifts </h4>
+
+<pre>
+uint32 *x ;
+unsigned int xn ;
+unsigned char carryafter ;
+unsigned char carrybefore ;
+
+ carryafter = bu_slbc(x, xn, carrybefore) ;
+ carryafter = bu_srbc(x, xn, carrybefore) ;
+</pre>
+
+<p>
+<tt>bu_slbc()</tt> computes <tt>x&nbsp;&lt;&lt;=&nbsp;1</tt>.
+The least significant bit of <tt>x</tt> is then set to
+<tt>carrybefore</tt>. <tt>bu_slbc()</tt> returns the
+previous value of <tt>x</tt>'s most significant bit. <br />
+<tt>bu_srbc()</tt> computes <tt>x&nbsp;&gt;&gt;=&nbsp;1</tt>.
+The most significant bit of <tt>x</tt> is then set to
+<tt>carrybefore</tt>. <tt>bu_slbc()</tt> returns the
+previous value of <tt>x</tt>'s least significant bit.<br />
+<tt>bu_slb(x, n)</tt> and <tt>bu_srb(x, n)</tt> are macros for
+respectively <tt>bu_slbc(x, n, 0)</tt> and <tt>bu_srbc(x, n, 0)</tt>.
+</p>
+
+<h4> Modular operations </h4>
+
+<pre>
+uint32 const *a ;
+unsigned int an ;
+uint32 const *b ;
+unsigned int bn ;
+uint32 *c ;
+unsigned int cn ;
+uint32 const *m ;
+unsigned int mn ;
+
+ bu_addmod(c, cn, a, an, b, bn, m, mn) ;
+ bu_submod(c, cn, a, an, b, bn, m, mn) ;
+ bu_mulmod(c, cn, a, an, b, bn, m, mn) ;
+ bu_divmod(c, cn, a, an, b, bn, m, mn) ;
+ bu_invmod(c, cn, m, mn) ;
+</pre>
+
+<p>
+<tt>bu_addmod()</tt> computes <tt>c&nbsp;=&nbsp;(a+b)&nbsp;mod&nbsp;m</tt>.<br />
+<tt>bu_submod()</tt> computes <tt>c&nbsp;=&nbsp;(a-b)&nbsp;mod&nbsp;m</tt>.<br />
+<tt>bu_mulmod()</tt> computes <tt>c&nbsp;=&nbsp;(a*b)&nbsp;mod&nbsp;m</tt>.<br />
+<tt>a</tt> and <tt>b</tt> must already be numbers modulo <tt>m</tt>.<br />
+The functions return 1 if all went well.
+</p>
+
+<p>
+<tt>bu_divmod()</tt> computes <tt>a</tt> divided by <tt>b</tt> modulo
+<tt>m</tt> and stores it into <tt>c</tt>. <br />
+<tt>bu_invmod()</tt> computes the inverse of <tt>c</tt> modulo <tt>m</tt>
+and stores it into <tt>c</tt>. <br />
+The divisor and <tt>m</tt> must be relatively prime, else
+those functions return 0 EDOM. <br />
+ The algorithm for modular division and inversion is due to
+<a href="http://research.sun.com/techrep/2001/abstract-95.html">Sheueling
+Chang Shantz</a>.
+</p>
+
+</body>
+</html>
diff --git a/doc/libdatastruct/index.html b/doc/libdatastruct/index.html
new file mode 100644
index 0000000..b32c7ce
--- /dev/null
+++ b/doc/libdatastruct/index.html
@@ -0,0 +1,40 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the datastruct library interface</title>
+ <meta name="Description" content="skalibs: the datastruct library interface" />
+ <meta name="Keywords" content="skalibs datastruct libdatastruct library interface" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>datastruct</tt> library interface </h1>
+
+<p>
+<tt>libdatastruct</tt> implements generic data structures like chained
+lists and AVL trees, in a memory-efficient and CPU-efficient way.
+</p>
+
+<h2> Compiling </h2>
+
+<ul>
+ <li> Use <tt>#include &lt;skalibs/datastruct.h&gt;</tt> </li>
+ <li> You can also use the lower-level headers included by <tt>skalibs/datastruct.h</tt> instead. </li>
+</ul>
+
+<h2> Programming </h2>
+
+<p>
+FIXME: to be completed.
+</p>
+
+</body>
+</html>
diff --git a/doc/librandom/index.html b/doc/librandom/index.html
new file mode 100644
index 0000000..b721594
--- /dev/null
+++ b/doc/librandom/index.html
@@ -0,0 +1,113 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the random library interface</title
+ <meta name="Description" content="skalibs: the random library interface" />
+ <meta name="Keywords" content="skalibs library random librandom random.h" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>random</tt> library interface </h1>
+
+<p>
+<tt>librandom</tt> is a small library designed to provide an
+interface to some reasonable-quality pseudorandom number
+generation. Some libcs have a bad
+<tt>random()</tt> implementation; <tt>librandom</tt> is designed
+to use system pseudorandom number generation when it's provided
+via <tt>/dev/random</tt> and <tt>/dev/urandom</tt>, and to use
+a good default PRNG otherwise.
+</p>
+
+<p>
+ <tt>librandom</tt> also supports
+<a href="http://egd.sourceforge.net/">EGD</a>. If you have built
+skalibs with <tt>--enable-egd</tt>, then the librandom
+primitives will try and connect to an EGD service to get random bytes
+if there is no kernel-based entropy generator such as <tt>/dev/random</tt>.
+If the EGD connection fails, a SURF PRNG is used.
+</p>
+
+<h2> Compiling </h2>
+
+<ul>
+ <li> Use <tt>#include &lt;skalibs/random.h&gt;</tt> </li>
+</ul>
+
+<h2> Programming </h2>
+
+<p>
+ You should refer to the <tt>skalibs/random.h</tt> header for the exact
+function prototypes.
+</p>
+
+ <h3> High quality, cryptographically strong random data </h3>
+
+<pre>
+ unsigned char c ;
+ unsigned int max ;
+ unsigned int n ;
+ unsigned int b ;
+ char data[at least b] ;
+ int r ;
+
+ goodrandom_init() ;
+ c = goodrandom_char() ;
+ n = goodrandom_int(max) ;
+ r = goodrandom_string(data, b) ;
+ goodrandom_finish() ;
+</pre>
+
+<p>
+ <tt>goodrandom_init()</tt> becomes optional with skalibs-0.43.
+ It is recommended that you let the library perform cleanups after you
+have used it, by calling <tt>goodrandom_finish()</tt>.
+</p>
+
+<ul>
+ <li> <tt>goodrandom_char()</tt> returns a random character </li>
+ <li> <tt>goodrandom_int(<em>max</em>)</tt> returns a random integer
+between 0 and <em>max</em>-1 </li>
+ <li> <tt>goodrandom_string(<em>data</em>, <em>b</em>)</tt> puts
+<em>b</em> random bytes in <em>data</em>, which must be preallocated.
+It returns <em>b</em> if it succeeds, or a non-negative integer lesser
+than <em>b</em> if it fails for any reason. </li>
+</ul>
+
+<p>
+ If you have neither <tt>/dev/random</tt> nor EGD, a software PRNG is
+used. This PRNG is based on the
+<a href="http://cr.yp.to/antiforgery.html#surf">SURF</a> function, which
+is unpredictable enough for most uses.
+</p>
+
+ <h3> Lower quality random data </h3>
+
+<p>
+ It works basically the same, by replacing <tt>goodrandom_*</tt> with
+<tt>badrandom_*</tt>. It uses <tt>/dev/urandom</tt> on systems that
+support it; on systems that do not, but support EGD, non-blocking calls
+to EGD are made ; if that is not enough, or EGD is not supported,
+the SURF generator is used.
+</p>
+
+<p>
+ The point of <tt>badrandom</tt> is to get random bytes <em>instantly</em>,
+even at the expense of quality; whereas <tt>goodrandom</tt> always returns
+high-quality random bytes, but may block if entropy is insufficient. In
+practice, in spite of its name, <tt>badrandom</tt> will return quite
+unpredictable pseudo-random data, so <tt>goodrandom</tt> should be used
+only when paranoia is the rule and blocking is an option.
+</p>
+
+</body>
+</html>
diff --git a/doc/libskarnet.html b/doc/libskarnet.html
new file mode 100644
index 0000000..9c29514
--- /dev/null
+++ b/doc/libskarnet.html
@@ -0,0 +1,100 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the skarnet library interface</title>
+ <meta name="Description" content="skalibs: the skarnet library interface" />
+ <meta name="Keywords" content="skalibs skarnet libskarnet library interface" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>skarnet</tt> library interface </h1>
+
+<p>
+ <em>libskarnet</em> is the library exported by skalibs; both a static
+library and a shared library (if they are supported on your system) are
+available. Every skarnet.org binary needs this library.
+</p>
+
+<h2> Compiling </h2>
+
+<ul>
+ <li> Make sure the place you installed the skalibs header files in is in
+your header directory list; the default is <tt>/usr/include</tt>,
+which is normally browsed by default by your C preprocessor. </li>
+ <li> Use <tt>#include &lt;skalibs/<em>foobar.h</em>&gt;</tt> where
+<em>foobar.h</em> is the header you need.
+ <ul>
+ <li> The <tt>skalibs/skalibs.h</tt> header is the general entry
+point that will declare the near-entirety of the functions, variables
+and constants in skalibs. Including this header
+in your source files whenever you need a skalibs function will work;
+however, it is rather heavy, and you might want to include lower-level
+headers instead to reduce compilation time. </li>
+ </ul>
+ </li>
+</ul>
+
+<h2> Linking </h2>
+
+<ul>
+ <li> For static linking:
+ add <tt>/usr/lib/skalibs</tt>, or wherever you installed
+your .a files, to your library directory list. </li>
+ <li> For dynamic linking:
+ make sure the place you installed the libskarnet.so shared library in
+is in your shared library directory list; the default is <tt>/lib</tt>,
+which is normally browsed by default by your build-time and run-time linker.
+If you are using another place than the default (for instance, if you are
+using the slashpackage convention), make sure to
+edit your <tt>ld.so.conf</tt> file so your linker can find this place, and
+to run <tt>ldconfig</tt> if needed. </li>
+ <li> Take note of the place where your sysdeps directory has been
+installed: by default, it's <tt>/usr/lib/skalibs/sysdeps</tt>. Let's call
+it <tt>$sysdeps</tt>. </li>
+ <li> Link with <tt>-lskarnet</tt>. If you are using socket functions, you
+will also need to link with <tt>-l$sysdeps/socket.lib</tt>. If you are using
+time functions such as <tt>tain_now()</tt>, you will also need to link with
+<tt>-l$sysdeps/tainnow.lib</tt>. </li>
+</ul>
+
+<p>
+ The <em>skarnet</em> library as a whole is big (833k for libskarnet.a and
+257k for libskarnet.so.2.0.0.0 on x86_64), but the utmost care has been
+given to separate functions so that linkers never pull in any more than they
+need. Linking against the static version of libskarnet actually produces
+very small executables, and if your libc is suited for that, since skalibs
+only uses very basic libc interfaces, it is very possible to produce small
+static binaries - in many cases, a static program written with skalibs APIs
+will be an order of magnitude smaller than the equivalent program written
+using libc's or other utility libraries' APIs.
+</p>
+
+<h2> Programming </h2>
+
+<p>
+ The skalibs source code is divided into several subdirectories, each
+containing a logical unit of code implementing independent functions.
+</p>
+
+<ul>
+<li><a href="libstddjb/">libstddjb</a>: basic C API for system programming </li>
+<li><a href="libdatastruct/">libdatastruct</a>: efficient C implementation of
+basic data structures like sets or trees</li>
+<li><a href="libstdcrypto/">libstdcrypto</a>: a few crypto primitives </li>
+<li><a href="librandom/">librandom</a>: cryptographically secure random or
+pseudorandom number generation </li>
+<li><a href="libunixonacid/">libunixonacid</a>: more advanced C/Unix APIs,
+mainly for safe asynchronous interprocess communication </li>
+<li><a href="libbiguint/">libbiguint</a>: large integer arithmetic</li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/libstdcrypto/index.html b/doc/libstdcrypto/index.html
new file mode 100644
index 0000000..bbc5f08
--- /dev/null
+++ b/doc/libstdcrypto/index.html
@@ -0,0 +1,110 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the stdcrypto library interface</title>
+ <meta name="Description" content="skalibs: the stdcrypto library interface" />
+ <meta name="Keywords" content="skalibs stdcrypto libstdcrypto library interface" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>stdcrypto</tt> library interface </h1>
+
+<p>
+<tt>stdcrypto</tt> is a small collection of standard,
+public-domain cryptographic primitives. Currently, the following
+operations are provided:
+</p>
+
+<ul>
+ <li> rc4 </li>
+ <li> md5 </li>
+ <li> sha1 </li>
+</ul>
+
+<h2> Compiling </h2>
+
+<ul>
+ <li> Use <tt>#include &lt;skalibs/stdcrypto.h&gt;</tt> </li>
+</ul>
+
+<h2> Programming </h2>
+
+<p>
+ You should refer to the <tt>skalibs/stdcrypto.h</tt> header and included headers
+for the exact function prototypes.
+</p>
+
+<h3> <a name="rc4" />
+RC4 </h3>
+
+<pre>
+ RC4Schedule ctx ;
+ unsigned char const *key ;
+ unsigned int keylen ;
+ unsigned char const *in ;
+ unsigned char *out ;
+ unsigned int len ;
+
+ rc4_init(&amp;ctx, key, keylen) ;
+ rc4(&amp;ctx, in, out, len) ;
+</pre>
+
+<ul>
+ <li> <tt>rc4_init()</tt> initializes a RC4Schedule structure with a key <em>key</em>,
+of length <em>keylen</em>. It then computes and throws away the first <tt>RC4_THROWAWAY</tt>
+bytes, usually 100 </li>
+ <li> <tt>rc4()</tt> encrypts <em>len</em> bytes of <em>in</em> with the RC4 flow, and
+stores the results into <em>out</em> </li>
+</ul>
+
+<h3> <a name="md5" />
+MD5 </h3>
+
+<pre>
+ MD5Schedule ctx ;
+ char const *message ;
+ unsigned int messagelen ;
+ char digest[16] ;
+
+ md5_init(&amp;ctx) ;
+ md5_update(&amp;ctx, message, messagelen) ;
+ md5_final(&amp;ctx, digest) ;
+</pre>
+
+<ul>
+ <li> <tt>md5_init()</tt> prepares a MD5Schedule structure for computation </li>
+ <li> <tt>md5_update()</tt> adds <em>message</em> to the message to be digested </li>
+ <li> <tt>md5_final()</tt> computes the digest </li>
+</ul>
+
+<h3> <a name="sha1"></a>
+SHA1 </h3>
+
+<pre>
+ SHA1Schedule ctx ;
+ char const *message ;
+ unsigned int messagelen ;
+ unsigned char digest[20] ;
+
+ sha1_init(&amp;ctx) ;
+ sha1_update(&amp;ctx, message, messagelen) ;
+ sha1_final(&amp;ctx, digest) ;
+</pre>
+
+<ul>
+ <li> <tt>sha1_init()</tt> prepares a SHA1Schedule structure for computation </li>
+ <li> <tt>sha1_update()</tt> adds <em>message</em> to the message to be digested </li>
+ <li> <tt>sha1_final()</tt> computes the digest </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/libstddjb/alloc.html b/doc/libstddjb/alloc.html
new file mode 100644
index 0000000..e17fcc7
--- /dev/null
+++ b/doc/libstddjb/alloc.html
@@ -0,0 +1,98 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the alloc library interface</title>
+ <meta name="Description" content="skalibs: the alloc library interface" />
+ <meta name="Keywords" content="skalibs c unix alloc library libstddjb" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libstddjb</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>alloc</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/alloc.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>alloc</tt> is the skalibs heap memory manager. It's actually a
+wrapper for the
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/malloc.html">malloc()</a>
+series of functions; it unifies a few system-dependent <tt>malloc</tt>
+behaviours. It's also the API to implement and preload if for some
+reason you need to plug in your own allocator: replacing <tt>alloc()</tt>
+is much easier than replacing <tt>malloc()</tt> safely.
+</p>
+
+<p>
+<strong> As a general rule, you should not be using the <tt>alloc</tt>
+interface directly. </strong> Allocating and freeing individual cells
+in the heap is a recipe for heap fragmentation, as well as cell
+tracking nightmares leading to memory leaks. <strong> You should use
+the higher-level <a href="stralloc.html">stralloc</a> and
+<a href="genalloc.html">genalloc</a> interfaces </strong> to handle dynamic
+arrays of objects.
+</p>
+
+<p>
+ C's lack of automatic management of heap memory is not a drawback: it's
+a feature of the language. It allows for code that is one or two orders
+of magnitude faster than the equivalent in a higher-level language,
+and very low on resources consumption. However, it requires more attention
+from the programmer. Good APIs can significantly reduce the difficulty of
+keeping track of every heap-allocated cell, and every smart programmer
+should favor them over basic interfaces like <tt>malloc()</tt>.
+</p>
+
+<p>
+ <tt>alloc</tt> is used internally by skalibs to implement
+<a href="stralloc.html">stralloc</a>, and nowhere else.
+</p>
+
+<h2> Functions </h2>
+
+<p>
+<code> char *alloc (unsigned int len) </code> <br />
+Allocates a block of <em>len</em> bytes in the heap and returns a pointer
+to the start of the block (or NULL if it failed). Though the pointer type
+is <tt>char *</tt>, the block of memory is correctly aligned for any type
+of object. If <em>len</em> is 0, the function returns a pointer that
+cannot be written to, but that is <em>not null</em>. Note that this is
+different from the required C99 behaviour for <tt>malloc()</tt>.
+</p>
+
+<p>
+<code> void alloc_free (void *p) </code> <br />
+Frees the block of heap memory pointed to by <em>p</em>.
+</p>
+
+<p>
+<code> int alloc_realloc (char **p, unsigned int newlen) </code> <br />
+Redimension the block of heap memory pointed to by *<em>p</em> to
+<em>newlen</em> bytes. The block may have to be moved, in which case
+*<em>p</em> will be modified. Normally returns 1; if an error occurred,
+returns 0 and sets errno, and neither *<em>p</em> nor its contents are
+modified.
+</p>
+
+<p>
+<code> int alloc_re (char **p, unsigned int oldlen, unsigned int newlen) </code> <br />
+Legacy interface for reallocation. It works like <tt>alloc_realloc</tt>,
+except that the original block length must be provided as the <em>oldlen</em>
+argument.
+</p>
+
+</body>
+</html>
diff --git a/doc/libstddjb/allreadwrite.html b/doc/libstddjb/allreadwrite.html
new file mode 100644
index 0000000..847c4e3
--- /dev/null
+++ b/doc/libstddjb/allreadwrite.html
@@ -0,0 +1,145 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the allreadwrite library interface</title>
+ <meta name="Description" content="skalibs: the allreadwrite library interface" />
+ <meta name="Keywords" content="skalibs c unix allreadwrite library libstddjb" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libstddjb</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>allreadwrite</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/allreadwrite.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>allreadwrite</tt> is a set of IO function helpers. It's the
+basis for safe reading and writing, either in blocking or in
+non-blocking mode. The <a href="buffer.html">buffer</a> interface
+relies heavily on <tt>allreadwrite</tt>.
+</p>
+
+<p>
+ Unless the IO you need is very simple, you generally should not
+be using the <tt>allreadwrite</tt> functions directly; you should
+use higher-level APIs such as <a href="buffer.html>buffer</a> and
+<a href="bufalloc.html">bufalloc</a>.
+</p>
+
+<h2> Function types </h2>
+
+<p>
+<code> typedef int iofunc_t (int fd, char *buf, unsigned int len) </code> <br />
+This is the simplified type of IO functions such as
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/read.html">read()</a>
+and
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/write.html">write()</a>.
+Unless your system's <tt>int</tt> is 64-bit, skalibs - which has been
+optimized for small systems - does not support IO operations of more than
+2 GB of data, for the sake of simplicity. In any case, it's always
+possible to send data in several smaller chunks.
+</p>
+
+<p>
+<code> typedef unsigned int alliofunc_t (int fd, char *buf, unsigned int len) </code> <br />
+This is the type of an IO operation that expects <em>all</em> of its
+<em>len</em> bytes to be sent or received, and that will loop around a
+lower-level IO function until either <em>len</em> bytes have been
+transmitted or an error has occurred. The return value is the actual
+number of transmitted bytes; if this value is lesser than <em>len</em>,
+it means that an error has occurred and <tt>errno</tt> is set.
+</p>
+
+<h2> Functions </h2>
+
+<p>
+<code> int sanitize_read (int r) </code> <br />
+Reading functions such as <tt>read()</tt> and <tt>fd_read</tt> return
+a positive number when they succeed, -1 when they fail, and 0 when they
+read an EOF. No data available on the descriptor when reading in
+non-blocking mode is treated as a failure: -1 EWOULDBLOCK. But sometimes
+(namely, in asynchronous IO loops) it's preferrable to handle EOF as an
+exception condition and EWOULDBLOCK as a normal condition.
+<tt>sanitize_read()</tt>, when applied to the result of a basic reading
+function, returns 0 if <em>r</em> is -1 and errno is EWOULDBLOCK (or
+EAGAIN). If <em>r</em> is zero, it returns -1 EPIPE. Else it returns <em>r</em>.
+</p>
+
+<p>
+ (No system reading function can ever set errno to EPIPE, and the
+semantics are appropriate, so EPIPE is a good candidate to signal EOF
+on reading.)
+</p>
+
+<p>
+<code> unsigned int allreadwrite (iofunc_t *f, int fd, char *s, unsigned int len) </code> <br />
+*<em>f</em> must be a basic reading or writing function such as
+<tt>fd_read</tt> or <tt>fd_write</tt>. <tt>allreadwrite()</tt> performs
+*<em>f</em> on <em>fd</em>, <em>s</em> and <em>len</em> until <em>len</em>
+bytes have been read or written, or until an error occurs. It returns the
+total number of handled bytes, and sets errno if this number is not
+<em>len</em>. <tt>allreadwrite</tt> may block if <em>fd</em> is in
+blocking mode; if <em>fd</em> is in non-blocking mode, it might
+set errno to EWOULDBLOCK or EAGAIN.
+</p>
+
+<p>
+<code> int fd_read (int fd, char *s, unsigned int len) </code> <br />
+<a href="safewrappers.html">Safe wrapper</a> around the
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/read.html">read()</a>
+function.
+</p>
+
+<p>
+<code> int fd_write (int fd, char const *s, unsigned int len) </code> <br />
+<a href="safewrappers.html">Safe wrapper</a> around the
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/write.html">write()</a>
+function.
+</p>
+
+<p>
+<code> int fd_recv (int fd, char *s, unsigned int len, unsigned int flags) </code> <br />
+<a href="safewrappers.html">Safe wrapper</a> around the
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/recv.html">recv()</a>
+function.
+</p>
+
+<p>
+<code> int fd_send (int fd, char const *s, unsigned int len, unsigned int flags) </code> <br />
+<a href="safewrappers.html">Safe wrapper</a> around the
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/send.html">send()</a>
+function.
+</p>
+
+<p>
+<code> unsigned int allread (int fd, char *s, unsigned int len) </code> <br />
+Equivalent to <code> allreadwrite(&fd_read, fd, s, len) </code>: attempts
+to read <em>len</em> bytes from <em>fd</em> into <em>s</em>, looping around
+<tt>fd_read()</tt> if necessary, until either <em>len</em> bytes are read or
+an error occurs. EOF is reported as EPIPE.
+</p>
+
+<p>
+<code> unsigned int allwrite (int fd, char const *s, unsigned int len) </code> <br />
+Equivalent to <code> allreadwrite((iofunc_t *)&fd_write, fd, s, len) </code>:
+attempts to write <em>len</em> bytes from <em>s</em> to <em>fd</em>, looping
+around <tt>fd_write()</tt> if necessary, until either <em>len</em> bytes are
+written or an error occurs.
+</p>
+
+</body>
+</html>
diff --git a/doc/libstddjb/bitarray.html b/doc/libstddjb/bitarray.html
new file mode 100644
index 0000000..1f88c3d
--- /dev/null
+++ b/doc/libstddjb/bitarray.html
@@ -0,0 +1,131 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the bitarray library interface</title>
+ <meta name="Description" content="skalibs: the bitarray library interface" />
+ <meta name="Keywords" content="skalibs c unix bitarray library libstddjb" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libstddjb</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>bitarray</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/bitarray.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>bitarray</tt> is a set of primitives to operate efficiently on
+large bitfields.
+</p>
+
+<p>
+ A bitfield is represented by a pre-allocated block of
+<tt>unsigned char</tt>; <tt>bitarray</tt> does not care if that
+block has been BSS-, stack- or heap-allocated. Bitfields that
+can grow in size should be stored in a
+<a href="stralloc.html">stralloc</a>.
+</p>
+
+<p>
+ Bits in a bitfield of length <em>n</em> are numbered from 0 to <em>n</em>-1.
+</p>
+
+<h2> Functions </h2>
+
+<p>
+<code> unsigned int bitarray_div8 (unsigned int n) </code> <br />
+Returns the minimum number of bytes needed to store a field of <em>n</em> bits.
+
+</p>
+
+<p>
+<code> void bitarray_clearsetn (unsigned char *s, unsigned int start, unsigned int len, int h) </code> <br />
+Sets (if <em>h</em> is nonzero) or clears (if <em>h</em> is zero)
+<em>len</em> bits in field <em>s</em>, starting at bit <em>start</em>.
+</p>
+
+<p>
+<code> void bitarray_clearn (unsigned char *s, unsigned int start, unsigned int len) </code> <br />
+Clears <em>len</em> bits in field <em>s</em>, starting at bit <em>start</em>.
+</p>
+
+<p>
+<code> void bitarray_setn (unsigned char *s, unsigned int start, unsigned int len) </code> <br />
+Sets <em>len</em> bits in field <em>s</em>, starting at bit <em>start</em>.
+</p>
+
+<p>
+<code> int bitarray_peek (unsigned char const *s, unsigned int n) </code> <br />
+Returns the value of the <em>n</em>th bit in field <em>s</em>.
+</p>
+
+<p>
+<code> void bitarray_poke (unsigned char *s, unsigned int n, int h) </code> <br />
+Sets (if <em>h</em> is nonzero) or clears (if <em>h</em> is zero)
+the <em>n</em>th bit in field <em>s</em>.
+</p>
+
+<p>
+<code> void bitarray_clear (unsigned char *s, unsigned int n) </code> <br />
+Clears the <em>n</em>th bit in field <em>s</em>.
+</p>
+
+<p>
+<code> void bitarray_set (unsigned char *s, unsigned int n) </code> <br />
+Sets the <em>n</em>th bit in field <em>s</em>.
+</p>
+
+<p>
+<code> int bitarray_testandpoke (unsigned char *s, unsigned int n, int h) </code> <br />
+Sets (if <em>h</em> is nonzero) or clears (if <em>h</em> is zero)
+the <em>n</em>th bit in field <em>s</em>,
+and returns the previous value of that bit.
+</p>
+
+<p>
+<code> int bitarray_testandclear (unsigned char *s, unsigned int n) </code> <br />
+Clear the <em>n</em>th bit in field <em>s</em>,
+and returns the previous value of that bit.
+</p>
+
+<p>
+<code> int bitarray_testandset (unsigned char *s, unsigned int n) </code> <br />
+Sets the <em>n</em>th bit in field <em>s</em>,
+and returns the previous value of that bit.
+</p>
+
+<p>
+<code> unsigned int bitarray_first (unsigned char const *s, unsigned int len, int h) </code> <br />
+Returns the number of the first set (if <em>h</em> is nonzero) or clear
+(if <em>h</em> is zero) bit in <em>s</em>, <em>len</em> being
+the total number of bits. If all bits in <em>s</em> are the negation of
+<em>h</em>, then <em>len</em> is returned.
+</p>
+
+<p>
+<code> unsigned int bitarray_firstclear (unsigned char const *s, unsigned int len) </code> <br />
+Returns the number of the first clear bit in <em>s</em>, <em>len</em> being
+the total number of bits. If all bits in <em>s</em> are set, <em>len</em> is returned.
+</p>
+
+<p>
+<code> unsigned int bitarray_firstset (unsigned char const *s, unsigned int len) </code> <br />
+Returns the number of the first set bit in <em>s</em>, <em>len</em> being
+the total number of bits. If all bits in <em>s</em> are clear, <em>len</em> is returned.
+</p>
+
+</body>
+</html>
diff --git a/doc/libstddjb/djbtime.html b/doc/libstddjb/djbtime.html
new file mode 100644
index 0000000..45876c8
--- /dev/null
+++ b/doc/libstddjb/djbtime.html
@@ -0,0 +1,201 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the djbtime library interface</title>
+ <meta name="Description" content="skalibs: the djbtime library interface" />
+ <meta name="Keywords" content="skalibs c unix djbtime library libstddjb" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libstddjb</a><br />
+<a href="../libskarnet.html">skalibs</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>djbtime</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/djbtime.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>djbtime</tt> is a set of functions to convert
+<a href="tai.html">tai_t and tain_t</a> structures, and
+<a href="http://cr.yp.to/libtai/tai64.html">TAI time</a>, from and to
+other time formats and user-friendly representations.
+</p>
+
+<h2> The <tt>/etc/leapsecs.dat</tt> file </h2>
+
+<p>
+ User-friendly time is calculated from UTC. Internal time computations
+should be performed on TAI time - because TAI flows linearly whereas
+UTC does not. To convert between UTC and TAI time, you need a
+<em>leap second table</em>. skalibs provides such a file in its
+<tt>src/etc/leapsecs.dat</tt> subdirectory, which is copied
+to <tt>/etc/leapsecs.dat</tt> at installation time (unless you specify
+a --prefix or --datadir option to configure).
+<strong>The <tt>/etc/leapsecs.dat</tt> file must remain accessible
+on your system, else time conversions will not be computed
+properly.</strong>
+</p>
+
+<h2> Data structures </h2>
+
+<ul>
+ <li> TAI time with 1-second precision is represented as a <a href="tai.html">tai_t</a>. </li>
+ <li> TAI time with more precision is represented as a <a href="tai.html">tain_t</a>. </li>
+ <li> UTC time is represented as an <a href="headers.html#uint64">unsigned 64-bit integer</a>
+equal to 2^62 added to the number of seconds since the Epoch. It's a trivial extension of
+the standard 32-bit Unix time that will expire in 2038. </li>
+ <li> Broken-down GMT or local time with more than a 1-second precision is stored in a
+<tt>localtmn_t</tt> structure, containing a <tt>struct tm</tt> <em>tm</em>
+field and an unsigned long <em>nano</em> field. </li>
+</ul>
+
+<h2> Functions </h2>
+
+<h3> UTC </h3>
+
+<p>
+<code> int utc_from_tai (uint64 *u, tai_t const *t) </code> <br />
+Converts the absolute TAI64 time in *<em>t</em> to an UTC time, stored in
+*<em>u</em> as an unsigned 64-bit integer. *<em>u</em> is actually 2^62
+plus the number of seconds since the Epoch.
+The function returns 1 if it succeeds, or 0 (and sets errno) if an
+error occurs (for instance: the leap second table cannot be found).
+</p>
+
+<p>
+<code> int tai_from_utc (tai_t *t, uint64 u) </code> <br />
+Converts the UTC time in <em>u</em>, stored
+as an unsigned 64-bit integer (2^62 plus the number of seconds since
+the Epoch), to a TAI64 time in *<em>t</em>.
+The function returns 1 if it succeeds, or 0 (and sets errno) if an
+error occurs (for instance: the leap second table cannot be found).
+</p>
+
+<h3> NTP </h3>
+
+<p>
+<code> int ntp_from_tain (uint64 *ntp, tain_t const *a) </code> <br />
+Converts the absolute TAI64N time in *<em>a</em> to a 64-bit NTP timestamp,
+stored in *<em>ntp</em>. The higher 32 bits of *<em>ntp</em> represent a number
+of seconds ; the lower 32 bits are the fractional part of the timestamp.
+The function returns 1 if it succeeds, or 0 (and sets errno) if an
+error occurs (for instance: the leap second table cannot be found, or
+*<em>a</em> cannot be represented in the valid NTP range).
+</p>
+
+<p>
+<code> int tain_from_ntp (tain_t *a, uint64 ntp) </code> <br />
+Converts the NTP timestamp in <em>ntp</em> to a TAI64N time in
+*<em>a</em>.
+The function returns 1 if it succeeds, or 0 (and sets errno) if an
+error occurs (for instance: the leap second table cannot be found).
+</p>
+
+<h3> Local time </h3>
+
+<p>
+ The following functions convert time between an internal representation
+and a broken-down <tt>struct tm</tt>. The
+<a href="../flags.html#tzisright">--enable-right-tz</a> configure option is used in
+determining how the conversion should proceed. If the <tt>--enable-tai-clock</tt>
+and <tt>--enable-right-tz</tt> configure options have been both enabled
+or both disabled, everything is naturally
+converted as it should be. If only one of them has been enabled,
+unholy magic happens here
+to get the correct broken-down time despite the timezone definition being
+wrong.
+</p>
+
+<p>
+<code> int localtm_from_tai (struct tm *tm, tai_t const *t, int lo) </code> <br />
+Converts the TAI time in *<em>t</em> to broken-down GMT (if
+<em>lo</em> is zero) or local (if <em>lo</em> is nonzero) time in
+*<em>tm</em>.
+The function returns 1 if it succeeds, or 0 (and sets errno) if an
+error occurs (for instance: *<em>t</em> cannot be validly represented
+in a struct tm).
+</p>
+
+<p>
+<code> int localtm_from_utc (struct tm *tm, uint64 u, int lo) </code> <br />
+Converts the UTC time in <em>u</em> to broken-down GMT (if
+<em>lo</em> is zero) or local (if <em>lo</em> is nonzero) time in
+*<em>tm</em>.
+The function returns 1 if it succeeds, or 0 (and sets errno) if an
+error occurs (for instance: <em>u</em> cannot be validly represented
+in a struct tm).
+</p>
+
+<p>
+<code> int localtm_from_sysclock (struct tm *tm, uint64 u, int lo) </code> <br />
+Converts the time in <em>u</em> to broken-down GMT (if
+<em>lo</em> is zero) or local (if <em>lo</em> is nonzero) time in
+*<em>tm</em>. <em>u</em> will be interpreted as a TAI-10 value (with
+<tt>--enable-tai-clock</tt>) or as a UTC value (without <tt>--enable-tai-clock</tt>).
+The function returns 1 if it succeeds, or 0 (and sets errno) if an
+error occurs (for instance: <em>u</em> cannot be validly represented
+in a struct tm).
+</p>
+
+<p>
+<code> int utc_from_localtm (uint64 *u, struct tm const *tm) </code> <br />
+Converts the broken-down local time in *<em>tm</em> to an UTC value
+in *<em>u</em>.
+The function returns 1 if it succeeds, or 0 (and sets errno) if an
+error occurs.
+</p>
+
+<p>
+<code> int tai_from_localtm (tai_t *t, struct tm const *tm) </code> <br />
+Converts the broken-down local time in *<em>tm</em> to a TAI value
+in *<em>t</em>.
+The function returns 1 if it succeeds, or 0 (and sets errno) if an
+error occurs.
+</p>
+
+<p>
+<code> int sysclock_from_localtm (uint64 *u, struct tm const *tm) </code> <br />
+Converts the broken-down local time in *<em>tm</em> to a value
+in *<em>u</em> - either TAI-10 or UTC depending on your system clock.
+The function returns 1 if it succeeds, or 0 (and sets errno) if an
+error occurs.
+</p>
+
+<p>
+ The following functions use the <tt>localtmn_t</tt> type to hold both
+a broken-down time and a nanosecond count:
+</p>
+
+<pre>typedef struct localtmn_s localtmn_t, *localtmn_t_ref ;
+struct localtmn_s
+{
+ struct tm tm ;
+ uint32 nano ;
+} ;
+</pre>
+
+<p>
+ The prototypes are self-explaining:
+</p>
+
+<p>
+<code> int localtmn_from_tain (localtmn_t_ref tmn, tain_t const *a, int lo) ; <br />
+int tain_from_localtmn (tain_t *a, localtmn_t const *tmn) ; <br />
+int localtmn_from_sysclock (localtmn_t_ref tmn, tain_t const *a, int lo) ; <br />
+int sysclock_from_localtmn (tain_t *a, localtmn_t const *tmn) ; </code> <br />
+</p>
+
+</body>
+</html>
diff --git a/doc/libstddjb/djbunix.html b/doc/libstddjb/djbunix.html
new file mode 100644
index 0000000..0d6c89f
--- /dev/null
+++ b/doc/libstddjb/djbunix.html
@@ -0,0 +1,760 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the djbunix library interface</title>
+ <meta name="Description" content="skalibs: the djbunix library interface" />
+ <meta name="Keywords" content="skalibs c unix djbunix library libstddjb" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://www.skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libstddjb</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>djbunix</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/djbunix.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>djbunix</tt> is an alternative API to management of basic Unix
+concepts: file descriptors, files, environment, and so on. It is a
+rather chaotic mix of <a href="safewrappers.html">safe wrappers</a>
+around Unix system calls, better reimplementations of standard libc
+functionalities, and higher-level manipulations of Unix concepts.
+</p>
+
+<p>
+ Understanding <tt>djbunix</tt> is essential to understanding any piece
+of code depending on skalibs.
+</p>
+
+<h2> Functions </h2>
+
+<h3> Basic fd operations </h3>
+
+<p>
+<code> int coe (int fd) </code> <br />
+Sets the close-on-exec flag on <em>fd</em>.
+Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int uncoe (int fd) </code> <br />
+Clears the close-on-exec flag on <em>fd</em>.
+Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int ndelay_on (int fd) </code> <br />
+Sets the O_NONBLOCK flag on <em>fd</em>: sets it to non-blocking mode.
+Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int ndelay_off (int fd) </code> <br />
+Clears the O_NONBLOCK flag on <em>fd</em>: sets it to blocking mode.
+Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int pipenb (int *p) </code> <br />
+Like
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/pipe.html">pipe()</a>,
+but both ends of the created pipe are in non-blocking mode.
+</p>
+
+<p>
+<code> int pipecoe (int *p) </code> <br />
+Like
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/pipe.html">pipe()</a>,
+but both ends of the created pipe are close-on-exec.
+</p>
+
+<p>
+<code> int pipenbcoe (int *p) </code> <br />
+Like
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/pipe.html">pipe()</a>,
+but both ends of the created pipe are in non-blocking mode <em>and</em> close-on-exec.
+</p>
+
+<p>
+<code> int fd_copy (int to, int from) </code> <br />
+Copies the open fd <em>from</em> to number <em>to</em>. <em>to</em>
+must not refer to an already open fd.
+Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int fd_copy2 (int to1, int from1, int to2, int from2) </code> <br />
+Copies the open fd <em>from1</em> to number <em>to2</em>. Also copies
+<em>from2</em> to <em>to2</em> at the same time.
+Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int fd_move (int to, int from) </code> <br />
+Moves the open fd <em>from</em> to number <em>to</em>. <em>to</em>
+must not refer to an already open fd, unless it's equal to <em>from</em>.
+Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int fd_move2 (int to1, int from1, int to2, int from2) </code> <br />
+Moves the open fd <em>from</em> to number <em>to</em>. Also moves
+<em>from2</em> to <em>to2</em> at the same time. This is useful for instance
+when you want to swap two fds: <tt>fd_move2</tt> will handle the situation
+correctly.
+Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int fd_close (int fd) </code> <br />
+Closes <em>fd</em>.
+Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
+This is a <a href="safewrappers.html">safe wrapper</a> around
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/close.html">close()</a>,
+or rather as safe a wrapper as is possible to write: the <tt>close()</tt>
+specification does not allow a 100% safe behaviour. So, in rare cases
+it is possible for <tt>fd_close()</tt> to return 0 (instead of -1 EBADF)
+when it is provided an argument that is not an open fd. This should not
+be a problem, because giving wrong arguments to <tt>fd_close()</tt> is
+always a static programming error.
+</p>
+
+<p>
+<code> int fd_chmod (int fd, unsigned int mode) </code> <br />
+Safe wrapper around
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/fchmod.html">fchmod()</a>.
+</p>
+
+<p>
+<code> int fd_chown (int fd, unsigned int uid, unsigned int gid) </code> <br />
+Safe wrapper around
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/fchown.html">fchown()</a>.
+This function requires root privileges.
+</p>
+
+<p>
+<code> int fd_sync (int fd) </code> <br />
+Safe wrapper around
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/fsync.html">fsync()</a>.
+</p>
+
+<p>
+<code> int fd_chdir (int fd) </code> <br />
+Safe wrapper around
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/fchdir.html">fchdir()</a>.
+</p>
+
+<p>
+<code> int fd_cat (int from, int to) </code> <br />
+Synchronously copies data from fd <em>from</em> to fd <em>to</em>,
+until it encounters EOF or an error. Returns -1 (and sets errno) if
+it fails; returns the number of transmitted bytes if it gets an EOF.
+</p>
+
+<p>
+When the underlying OS allows it, zero-copy transmission is
+performed. Currently, the following zero-copy implementations are
+supported:
+</p>
+
+<ul>
+ <li> <a href="http://www.kernel.org/doc/man-pages/online/pages/man2/splice.2.html">splice()</a>,
+in Linux 2.6.17 and later </li>
+</ul>
+
+<p>
+<code> unsigned int fd_catn (int from, int to, unsigned int n) </code> <br />
+Synchronously copies at most <em>n</em> bytes from fd <em>from</em> to fd <em>to</em>.
+Returns the total number of transmitted bytes; sets errno if this number
+is lesser than <em>n</em>. EOF is reported as EPIPE. See above for zero-copy
+transmission; zero-copy transmission is not attempted for less than 64k of data.
+</p>
+
+<p>
+<code> int fd_ensure_open (int fd, int w) </code> <br />
+If <em>fd</em> is not open, opens it to <tt>/dev/null</tt>,
+for reading if <em>w</em> is zero, and for writing otherwise.
+Returns 1 if it succeeds and 0 if it fails.
+</p>
+
+<p>
+<code> int fd_sanitize (void) </code> <br />
+Ensures stdin and stdout are open. If one of those
+file descriptors was closed, it now points to <tt>/dev/null</tt>.
+Returns 1 if it succeeds and 0 if it fails.
+</p>
+
+<p>
+<code> int lock_ex (int fd) </code> <br />
+Gets an exclusive advisory lock on <em>fd</em>. <em>fd</em> must point to
+a regular file, open for writing. Blocks until the lock can be obtained.
+Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int lock_exnb (int fd) </code> <br />
+Gets an exclusive advisory lock on <em>fd</em>. <em>fd</em> must point to
+a regular file, open for writing.
+Returns 0 if it succeeds, or -1 (and sets errno) if it fails. If the lock
+is held and the function would block, it immediately returns with -1 EWOULDBLOCK.
+</p>
+
+<p>
+<code> int lock_sh (int fd) </code> <br />
+Gets a shared advisory lock on <em>fd</em>. <em>fd</em> must point to
+a regular file, open for reading. Blocks until the lock can be obtained.
+Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int lock_shnb (int fd) </code> <br />
+Gets a shared advisory lock on <em>fd</em>. <em>fd</em> must point to
+a regular file, open for reading.
+Returns 0 if it succeeds, or -1 (and sets errno) if it fails. If the lock
+is held and the function would block, it immediately returns with -1 EWOULDBLOCK.
+</p>
+
+<p>
+<code> int lock_un (int fd) </code> <br />
+Releases a previously held lock on <em>fd</em>.
+Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int open2 (char const *file, unsigned int flags) </code> <br />
+Safe wrapper around
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/open.html">open()</a>
+when it takes 2 arguments.
+</p>
+
+<p>
+<code> int open3 (char const *file, unsigned int flags) </code> <br />
+Safe wrapper around
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/open.html">open()</a>
+when it takes 3 arguments.
+</p>
+
+<p>
+<code> int open_read (char const *file) </code> <br />
+Opens <em>file</em> in read-only, non-blocking mode.
+Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int open_readb (char const *file) </code> <br />
+Opens <em>file</em> in read-only, blocking mode.
+Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
+<em>This call does not block.</em> The
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/open.html">open()</a>
+system call is actually performed with the O_NONBLOCK option, and blocking mode
+is set afterwards; this behaviour allows for more transparent interactions
+with FIFOs.
+</p>
+
+<p>
+<code> int open_excl (char const *file) </code> <br />
+Opens <em>file</em> in write-only, non-blocking mode, with the
+additional O_EXCL and O_CREAT flags.
+Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int open_append (char const *file) </code> <br />
+Opens <em>file</em> in write-only, non-blocking mode, with the
+additional O_APPEND and O_CREAT flags.
+Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int open_trunc (char const *file) </code> <br />
+Opens <em>file</em> in write-only, non-blocking mode, with the
+additional O_TRUNC and O_CREAT flags.
+Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int open_create (char const *file) </code> <br />
+Opens <em>file</em> in write-only, non-blocking mode, with the
+additional O_CREAT flag.
+Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int open_write (char const *file) </code> <br />
+Opens <em>file</em> in write-only, non-blocking mode.
+Returns a valid fd number if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<h3> Seek operations </h3>
+
+<p>
+<code> long seek_cur (int fd) </code> <br />
+Returns the current file offset for descriptor <em>fd</em>.
+</p>
+
+<p>
+<code> int seek_set (int fd, long pos) </code> <br />
+Sets the current file offset for <em>fd</em> to <em>pos</em>.
+Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
+</p>
+
+<h3> Privilege management </h3>
+
+<p>
+<code> int prot_readgroups (char const *name, gid_t *tab, unsigned int max) </code> <br />
+Reads the group database (normally <tt>/etc/group</tt>, but it can be
+altered via NSS) to get the list of supplementary groups for user <em>name</em>.
+Stores that list into the array pointed to by <em>tab</em>, which must be
+preallocated. Stores at most <em>max</em> elements into <em>tab</em>.
+Returns -1 and sets errno if it fails; else, returns the number of elements actually
+stored into <em>tab</em>.
+</p>
+
+<p>
+<code> int prot_grps (char const *name) </code> <br />
+Sets the kernel-maintained list of supplementary groups for the current process
+to the list of supplementary groups for user <em>name</em> according to the
+group database. This is a privileged operation.
+Returns -1 and sets errno if it fails; returns 0 if it succeeds.
+</p>
+
+<p>
+<code> int prot_gid (int gid) </code> <br />
+Alias to <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/setgid.html">setgid</a>.
+</p>
+
+<p>
+<code> int prot_uid (int uid) </code> <br />
+Alias to <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/setuid.html">setuid</a>.
+</p>
+
+<h3> Executable search and execution, and environment </h3>
+
+<p>
+<code> void execvep (char const *file, char const *const *argv, char const *const *envp, char const *path) </code> <br />
+Executes into the executable file at <em>file</em>, with the command line
+set to <em>argv</em> and the environment set to <em>envp</em>.
+If <em>file</em> is not an absolute path, it is searched in the
+<em>path</em> string, which must contain a colon-separated list of
+search directories such as the contents of the PATH environment variable.
+The function returns if it fails, and sets errno to the most relevant
+error that happened.
+</p>
+
+<p>
+<code> void pathexec_run (char const *file, char const *const *argv, char const *const *envp) </code> <br />
+Performs <tt>execvep(file, argv, envp, path)</tt>, <em>path</em> being the
+contents of the PATH environment variable. If PATH is not set, <em>path</em>
+is set to the contents of the <tt>conf-compile/conf-defaultpath</tt> file in
+the skalibs distribution.
+The function returns if it fails, and sets errno appropriately.
+</p>
+
+<p>
+ <tt>pathexec_run()</tt> is the standard skalibs API to perform an
+<tt>exec</tt> call with a path search. It is recommended that you use
+it instead of the Single Unix
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/execvp.html">execvp()</a> or
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/execlp.html">execlp()</a>
+functions, because <tt>execvp</tt> and <tt>execlp</tt> default to execution of
+the <tt>/bin/sh</tt> interpreter with <em>file</em> as an argument if they
+cannot find a suitable executable <em>file</em>, and this is:
+</p>
+
+<ol>
+ <li> a security risk, </li>
+ <li> probably not what you want. </li>
+</ol>
+
+<p>
+ <tt>execvep()</tt> and <tt>pathexec_run()</tt> just fail with ENOENT
+when they cannot find a <em>file</em> to exec into, which is the
+sensible behaviour.
+</p>
+
+<p>
+<code> void pathexec0_run (char const *const *argv, char const *const *envp) </code> <br />
+Performs <tt>pathexec_run(argv[0], argv, envp)</tt>. If <em>argv</em> is empty, i.e.
+<em>argv</em>[0] is null, the process exits 0 instead. Rationale: executing
+the empty command line should amount to executing <tt>true</tt>, i.e.
+simply exiting 0.
+</p>
+
+<p>
+<code> void pathexec_r_name (char const *file, char const *const *argv, char const *const *envp, unsigned int envlen, char const *modifs, unsigned int modiflen) </code> <br />
+Alters <em>envp</em> (which does not have to be NULL-terminated, but the
+number <em>envlen</em> of elements must be provided) with the modifier
+string <em>modifs</em> of length <em>modiflen</em>, then performs
+<tt>pathexec_run(file, argv, altered-envp)</tt>.
+</p>
+
+<p>
+<code> void pathexec_r (char const *const *argv, char const *const *envp, unsigned int envlen, char const *modifs, unsigned int modiflen) </code> <br />
+Same as <tt>pathexec_r_name</tt>, except that the <em>file</em> argument is read from <em>argv</em>[0].
+</p>
+
+<p>
+<code> int pathexec_env (char const *var, char const *value) </code> <br />
+Adds the "add variable <em>var</em> with value <em>value</em>" instruction
+(if <em>value</em> is not null) or the "unset <em>var</em>" instruction
+(if <em>value</em> is null) to a static hidden modifier string, used by the
+following three functions.
+Returns 1 if it succeeds and 0 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> void pathexec_fromenv (char const *const *argv, char const *const *envp, unsigned int envlen) </code> <br />
+Performs <tt>pathexec_r()</tt> with the given arguments and the hidden modifier
+string.
+</p>
+
+<p>
+<code> void pathexec (char const *const *argv) </code> <br />
+Executes into the <em>argv</em> command line, with the current environment
+modified by the hidden modifier string.
+</p>
+
+<p>
+<code> void pathexec0 (char const *const *argv) </code> <br />
+Executes into the <em>argv</em> command line, with the current environment
+modified by the hidden modifier string. If this command line is empty,
+exit 0 instead.
+</p>
+
+<p>
+ The <a href="env.html">env</a> library interface provides additional functions
+to manipulate modifier strings and environments.
+</p>
+
+<h3> Forking children </h3>
+
+<p>
+<code> int doublefork () </code> <br />
+Performs a double fork. Returns -1 if it fails (and
+sets errno, EINTR meaning that the intermediate process
+was killed by a signal), 0 if the current process is the grandchild,
+and the grandchild's PID if the current process is the parent.
+</p>
+
+<p>
+<code> pid_t child_spawn0 (char const *file, char const *const *argv, char const *const *envp) </code> <br />
+Forks and executes a child as with <tt>pathexec_run(file, argv, envp)</tt>.
+Returns 0 if it fails, and the pid of the child if it succeeds.
+Implemented via <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawn.html">posix_spawn()</a>
+on systems that support it.
+</p>
+
+<p>
+<code> pid_t child_spawn1 (char const *file, char const *const *argv, char const *const *envp, int *fd, int w) </code> <br />
+Like <tt>child_spawn0()</tt>, except that a pipe is created between the child's
+stdin (if <em>w</em> is 0) or stdout (if <em>w</em> is nonzero) and the parent.
+The parent's end of the pipe will be stored in *<em>fd</em>.
+</p>
+
+<p>
+<code> pid_t child_spawn (char const *file, char const *const *argv, char const *const *envp, int *fds, unsigned int nfds) </code> <br />
+More generic spawning function. <em>fds</em> must point to an array of at least <em>nfds</em> ints;
+file descriptors reading from or writing to the child will be stored there. The function returns
+0 on failure or the pid of the child on success.
+</p>
+<ul>
+ <li> If <em>nfds</em> is 0, then the function behaves like <tt>child_spawn0</tt>, except
+all signals will be reset to the default behaviour in the child </li>
+ <li> If <em>nfds</em> is 1, then <em>fds</em>[0] will contain a Unix domain socket
+connected to the child's stdin and stdout. </li>
+ <li> If <em>nfds</em> is 2 or more, then <em>fds</em> will contain pipes between the
+child and the parent. The parent will read on even-numbered ones (starting on <em>fds</em>[0])
+and write on odd-numbered ones. </li>
+</ul>
+
+<h3> Waiting for children </h3>
+
+<p>
+<code> unsigned int wait_reap () </code> <br />
+Instantly reaps all the pending zombies, without blocking, without a look at
+the exit codes.
+Returns the number of reaped zombies.
+</p>
+
+<p>
+<code> int waitn (pid_t *pids, unsigned int n) </code> <br />
+Waits until all processes whose PIDs are stored in the
+<em>pids</em> array, of size <em>n</em>, have died.
+Returns 1 if it succeeds, and 0 (and sets errno) if it fails. The
+<em>pid</em> array is not guaranteed to be unchanged.
+</p>
+
+<p>
+<code> int waitn_reap (pid_t *pids, unsigned int n) </code> <br />
+Instantly reaps all zombies whose PIDs are stored in the
+<em>pids</em> array, of size <em>n</em>.
+Returns -1 (and sets errno) if it fails, and the number of reaped
+zombies if it succeeds. The <em>pid</em> array is not guaranteed to
+be unchanged.
+</p>
+
+<p>
+<code> int wait_nohang (int *wstat) </code> <br />
+Instantly reaps one zombie, and stores the status information into
+*<em>wstat</em>.
+Returns the PID of the reaped zombie if it succeeds, 0 if there was
+nothing to reap (and the current process still has children), -1 ECHILD
+if there was nothing to reap (and the current process has no children),
+or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int waitpid_nointr (pid_t pid, int *wstat, int flags) </code> <br />
+Safe wrapper around
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/waitpid.html">waitpid()</a>.
+</p>
+
+<p>
+<code> int wait_pid_nohang (pid_t pid, int *wstat) </code> <br />
+Instantly reaps an undetermined number of zombies until it finds <em>pid</em>.
+Stores the status information for dead <em>pid</em> into *<em>wstat</em>.
+Returns <em>pid</em> if it succeeds, 0 if there was
+nothing to reap (and the current process still has children), -1 ECHILD
+if there was nothing to reap (and the current process has no children),
+or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int wait_pids_nohang (pid_t const *pids, unsigned int len, int *wstat) </code> <br />
+Instantly reaps an undetermined number of zombies until it finds one whose
+PID is in the <em>pids</em> array, of size <em>len</em>.
+Stores the status information for that dead process into *<em>wstat</em>.
+Returns the index of the found PID in <em>pids</em>, starting at 1.
+Returns 0 if there was
+nothing to reap (and the current process still has children), -1 ECHILD
+if there was nothing to reap (and the current process has no children),
+or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+ When asynchronously dealing with a child (resp. several children) and
+getting a SIGCHLD - which should be handled via a
+<a href="selfpipe.html">selfpipe</a> - it is generally a good idea to
+use the <tt>wait_pid_nohang()</tt> (resp. <tt>wait_pids_nohang()</tt>)
+function over the basic Unix APIs. This allows a program to:
+</p>
+
+<ul>
+ <li> Automatically and silently take care of children it does not know
+it has. This situation can happen when a process forks and the parent
+execs. When the child dies, the new parent process has to drag the
+"zombie bastard" along, which is ugly; <tt>wait_pids_nohang()</tt>
+prevents this. </li>
+ <li> Still take appropriate care of its legitimate children, in
+any order. </li>
+</ul>
+
+<h3> Reading and writing whole files </h3>
+
+<p>
+<code> int slurp (stralloc *sa, int fd) </code> <br />
+Slurps the contents of open descriptor <em>fd</em> into
+the *<em>sa</em> <a href="stralloc.html">stralloc</a>. If you are
+doing this, you should either have full control over the slurped
+file, or run your process with suitable
+<a href="http://www.skarnet.org/software/s6/s6-softlimit.html">limits</a>
+to the amount of heap memory it can get.
+The function returns 1 if it succeeds, or 0 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int openslurpclose (stralloc *sa, char const *file) </code> <br />
+Slurps the contents of file <em>file</em> into *<em>sa</em>.
+Returns 1 if it succeeds, and 0 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int openreadclose (char const *file, stralloc *sa, unsigned int dummy) </code> <br />
+Legacy interface for <code>openslurpclose(sa, file)</code>. The <em>dummy</em>
+argument is unused. Returns 0 if it succeeds, and -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int openreadnclose (char const *file, char *s, unsigned int n) </code> <br />
+Reads at most <em>n</em> bytes from file <em>file</em> into preallocated
+buffer <em>s</em>. Returns -1 (and sets errno) if it fails; else returns the
+number of read bytes. If that number is not <em>n</em>, errno is set to EPIPE.
+</p>
+
+<p>
+<code> int openreadfileclose (char const *file, stralloc *sa, unsigned int n) </code> <br />
+Reads at most <em>n</em> bytes from file <em>file</em> into the *<em>sa</em>
+stralloc, which is grown (if needed) to <em>just</em> accommodate the file
+size. Returns 1 if it succeeds and 0 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int openwritenclose_unsafe_internal (char const *file, char const *s, unsigned int len, uint64 *dev, uint64 *ino, unsigned char dosync) </code> <br />
+Writes the <em>n</em> bytes stored at <em>s</em> into file <em>file</em>.
+The previous contents of <em>file</em> are destroyed even if the function
+fails. If <em>dosync</em> is nonzero, the new contents of <em>file</em>
+are synced to disk before the function returns. If <em>dev</em> and <em>ino</em>
+are not null, they're used to store the device and inode number of <em>file</em>.
+The function returns 1 if it succeeds, or 0 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int openwritenclose_unsafe (char const *file, char const *s, unsigned int len) <br />
+int openwritenclose_unsafe_sync (char const *file, char const *s, unsigned int len) <br />
+int openwritenclose_unsafe_devino (char const *file, char const *s, unsigned int len, uint64 *dev, uint64 *ino) <br />
+int openwritenclose_unsafe_devino_sync (char const *file, char const *s, unsigned int len, uint64 *dev, uint64 *ino) </code> <br />
+Trivial shortcuts around <tt>openwritenclose_unsafe_internal()</tt>. The
+reader can easily figure out what they do.
+</p>
+
+<p>
+<code> int openwritenclose_suffix_internal (char const *file, char const *s, unsigned int len, uint64 *dev, uint64 *ino, unsigned char dosync, char const *suffix) </code> <br />
+Writes the <em>n</em> bytes stored at <em>s</em> into file <em>file</em>,
+by first writing into <em>filesuffix</em> and atomically renaming
+<em>filesuffix</em> to <em>file</em>. IOW, the old contents of <em>file</em>
+are preserved if the operation fails, and are atomically replaced with the
+new contents if the operation succeeds.
+If <em>dosync</em> is nonzero, the new contents of <em>filesuffix</em>
+are synced to disk before the atomic replace. If <em>dev</em> and <em>ino</em>
+are not null, they're used to store the device and inode number of <em>file</em>.
+The function returns 1 if it succeeds, or 0 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int openwritenclose_suffix (char const *file, char const *s, unsigned int len, char const *suffix) <br />
+int openwritenclose_suffix_sync (char const *file, char const *s, unsigned int len, char const *suffix) <br />
+int openwritenclose_suffix_devino (char const *file, char const *s, unsigned int len, uint64 *dev, uint64 *ino, char const *suffix) <br />
+int openwritenclose_suffix_devino_sync (char const *file, char const *s, unsigned int len, uint64 *dev, uint64 *ino, char const *suffix) </code> <br />
+Trivial shortcuts around <tt>openwritenclose_suffix_internal()</tt>. The
+reader can easily figure out what they do.
+</p>
+
+<h3> Filesystem deletion </h3>
+
+<p>
+The following operations are not atomic, so if they fail, the
+relevant subtree might end up partially deleted.
+</p>
+
+<p>
+<code> int rm_rf (char const *path) </code> <br />
+Deletes the filesystem subtree at <em>path</em>.
+Returns 0 if it succeeds or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int rm_rf_tmp (char const *path, stralloc *tmp) </code> <br />
+Deletes the filesystem subtree at <em>path</em>, using *<em>tmp</em>
+as heap-allocated temporary space.
+Returns 0 if it succeeds or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int rm_rf_in_tmp (stralloc *tmp, unsigned int n) </code> <br />
+Deletes a filesystem subtree, using *<em>tmp</em>
+as heap-allocated temporary space.
+Returns 0 if it succeeds or -1 (and sets errno) if it fails.
+When the function is called, *<em>tmp</em> must contain the
+null-terminated name of the subtree to delete at offset <em>n</em>.
+</p>
+
+<p>
+<code> int rmstar (char const *dir) </code> <br />
+Deletes all the filesystem subtrees in directory <em>dir</em>.
+Returns 0 if it succeeds or -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int rmstar_tmp (char const *dir, stralloc *tmp) </code> <br />
+Deletes all the filesystem subtrees in directory <em>dir</em>,
+using *<em>tmp</em> as heap-allocated temporary space.
+Returns 0 if it succeeds or -1 (and sets errno) if it fails.
+</p>
+
+<h3> Variable length wrappers around Single Unix calls </h3>
+
+<p>
+<code> int sarealpath (stralloc *sa, char const *path) </code> <br />
+Resolves <em>path</em> into a symlink-free absolute path, appending
+the result to the *<em>sa</em>
+<a href="stralloc.html">stralloc</a>.
+Returns 0 if it succeeds and -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int sarealpath_tmp (stralloc *sa, char const *path, stralloc *tmp) </code> <br />
+Resolves <em>path</em> into a symlink-free absolute path, appending
+the result to *<em>sa</em>. Uses *<em>tmp</em> as heap-allocated
+temporary space.
+Returns 0 if it succeeds and -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int sabasename (stralloc *sa, char const *s, unsigned int len) </code> <br />
+Appends the basename of filename <em>s</em> (of length <em>len</em>)
+to *<em>sa</em>.
+Returns 1 if it succeeds and 0 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int sadirname (stralloc *sa, char const *s, unsigned int len) </code> <br />
+Appends the dirname of filename <em>s</em> (of length <em>len</em>)
+to *<em>sa</em>.
+Returns 1 if it succeeds and 0 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int sagetcwd (stralloc *sa) </code> <br />
+Appends the current working directory to *<em>sa</em>.
+Returns 0 if it succeeds and -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int sareadlink (stralloc *sa, char const *link) </code> <br />
+Appends the contents of symbolic link <em>link</em> to *<em>sa</em>.
+Returns 0 if it succeeds and -1 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int sagethostname (stralloc *sa) </code> <br />
+Appends the machine's hostname to *<em>sa</em>.
+Returns 0 if it succeeds and -1 (and sets errno) if it fails.
+</p>
+
+<h3> Temporization </h3>
+
+<p>
+<code> void deepsleepuntil (tain_t const *deadline, tain_t *stamp) </code> <br />
+Sleeps until the absolute time represented by the
+<a href="tai.html">tain_t</a> *<em>deadline</em>. *<em>stamp</em>
+must contain the current time. When the function returns, *<em>stamp</em>
+has been updated to reflect the new current time.
+</p>
+
+<p>
+<code> void deepsleep (unsigned int n) </code> <br />
+Sleeps <em>n</em> seconds. Signals received during that time are handled,
+but <em>do not</em> interrupt the sleep.
+</p>
+
+<p>
+<code> void deepmillisleep (unsigned long n) </code> <br />
+Sleeps <em>n</em> milliseconds. Signals received during that time are handled,
+but <em>do not</em> interrupt the sleep.
+</p>
+
+</body>
+</html>
diff --git a/doc/libstddjb/gccattributes.html b/doc/libstddjb/gccattributes.html
new file mode 100644
index 0000000..6ee71ef
--- /dev/null
+++ b/doc/libstddjb/gccattributes.html
@@ -0,0 +1,48 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the gccattributes header</title>
+ <meta name="Description" content="skalibs: the gccattributes header" />
+ <meta name="Keywords" content="skalibs header gccattributes gcc attributes" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libstddjb</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>skalibs/gccattributes.h</tt> header </h1>
+
+<p>
+ <tt>skalibs/gccattributes.h</tt> is a set of wrappers around
+<a href="http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html">gcc
+attributes</a> (duh). It defines macros that are always valid, and
+that have no effect if the compiler is not gcc or the used version
+of gcc does not support the wanted attribute.
+</p>
+
+<p>
+ For instance:
+</p>
+
+<pre>
+ extern unsigned int str_len (char const *) gccattr_pure ;
+</pre>
+
+<p>
+ defines the <tt>str_len</tt> function as <em>pure</em> if it is
+supported.
+</p>
+
+<p>
+ The source code is self-explanatory.
+</p>
+
+</body>
+</html>
diff --git a/doc/libstddjb/genalloc.html b/doc/libstddjb/genalloc.html
new file mode 100644
index 0000000..b9ab934
--- /dev/null
+++ b/doc/libstddjb/genalloc.html
@@ -0,0 +1,46 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the genalloc library interface</title>
+ <meta name="Description" content="skalibs: the genalloc library interface" />
+ <meta name="Keywords" content="skalibs c unix genalloc library libstddjb" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libstddjb</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>genalloc</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/genalloc.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>genalloc</tt> is the skalibs way of handling dynamic arrays, i.e.
+dynamically growing arrays of fixed-size objects. Any array that needs
+to be stored in heap memory can be implemented via genalloc.
+</p>
+
+<p>
+ Most genalloc functions are just macro calls around
+<a href="stralloc.html">stralloc</a> functions.
+</p>
+
+<p>
+ The <tt>genalloc.h</tt> header is actually very simple and the
+prototypes there are self-explaining.
+</p>
+
+</body>
+</html>
diff --git a/doc/libstddjb/genwrite.html b/doc/libstddjb/genwrite.html
new file mode 100644
index 0000000..33ff4d3
--- /dev/null
+++ b/doc/libstddjb/genwrite.html
@@ -0,0 +1,98 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the genwrite library interface</title>
+ <meta name="Description" content="skalibs: the genwrite library interface" />
+ <meta name="Keywords" content="skalibs c unix genwrite buffer stralloc write library libstddjb" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libstddjb</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>genwrite</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/genwrite.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>genwrite</tt> is syntactic sugar to help write functions that might
+want to write either to memory or to a file descriptor.
+</p>
+
+<p>
+ Writing to memory is achieved via appending to a
+<a href="stralloc.html">stralloc</a>; writing to a file descriptor is achieved
+via appending to a <a href="buffer.html">buffer</a> or a
+<a href="bufalloc.html">bufalloc</a>.
+</p>
+
+<h2> Usage </h2>
+
+<p>
+ A <tt>genwrite_t</tt> structure contains a pointer to a function that writes
+stuff to the target without flushing it
+(which can be <tt>genwrite_put_stralloc</tt>, <tt>genwrite_put_buffer</tt>,
+<tt>genwrite_put_bufalloc</tt> or any
+compatible user-defined function) in <tt>.put</tt>, a pointer to a function
+that flushes the target (which can be <tt>genwrite_flush_stralloc</tt>,
+<tt>genwrite_flush_buffer</tt>, <tt>genwrite_flush_bufalloc</tt> or any
+compatible user-defined function) in <tt>.flush</tt>, and a pointer to
+the target writing structure in <tt>.target</tt>.
+</p>
+
+<p>
+ Users should define a <tt>genwrite_t</tt> first, using the provided functions,
+and give applications a pointer <tt>gp</tt> to this structure. To write <em>len</em>
+characters at position <em>s</em> to the target, the application should then call
+<code>(*gp-&gt;put)(gp-&gt;target, s, len)</code>. When it is done writing, the
+application should call <code>(*gp-&gt;flush)(gp-&gt;target)</code> to flush the
+output.
+</p>
+
+<p>
+ <tt>genwrite_stdout</tt> and <tt>genwrite_stderr</tt> are predefined; they
+write to <tt>buffer_1</tt> and <tt>buffer_2</tt> respectively.
+</p>
+
+<h2> Macros </h2>
+
+<p>
+<code> GENWRITE_STRALLOC_INIT(sa) </code> <br />
+Declares a <tt>genwrite_t</tt> writing to the stralloc *<em>sa</em>.
+</p>
+
+<p>
+<code> GENWRITE_BUFFER_INIT(b) </code> <br />
+Declares a <tt>genwrite_t</tt> writing to the buffer *<em>b</em>. Use
+of such a buffer might interact badly with nonblocking I/O.
+</p>
+
+<p>
+<code> GENWRITE_BUFALLOC_INIT(ba) </code> <br />
+Declares a <tt>genwrite_t</tt> writing to the bufalloc *<em>ba</em>.
+</p>
+
+<h2> Note </h2>
+
+<p>
+Object-oriented programming in C is inefficient and cumbersome. It is
+usually possible to avoid it in Unix system programming, because Unix
+primitives are often generic enough. Unfortunately, it is not the case
+here: Unix does not provide an abstraction representing either a file
+or a memory buffer. So an object-oriented approach is unavoidable.
+</p>
+
+</body>
+</html>
diff --git a/doc/libstddjb/index.html b/doc/libstddjb/index.html
new file mode 100644
index 0000000..e0853cc
--- /dev/null
+++ b/doc/libstddjb/index.html
@@ -0,0 +1,125 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the stddjb library interface</title>
+ <meta name="Description" content="skalibs: the stddjb library interface" />
+ <meta name="Keywords" content="skalibs stddjb libstddjb library interface" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">www.skarnet.org</a>
+</p>
+
+<h1> The <tt>stddjb</tt> library interface </h1>
+
+<p>
+ <tt>libstddjb</tt> is the base, and the most important part, of skalibs.
+It is a set of general-purpose C functions wrapping some
+system calls, hiding some Unix portability problems, providing some
+basic low-level buffering functions and string handling, and generally
+offering a nice API to Unix programming - in many ways nicer and safer
+than the "standard" Unix APIs like <tt>stdio.h</tt>.
+</p>
+
+<p>
+ It is mostly based on some excellent code written and placed into the
+public domain by <a href="../djblegacy.html">D. J. Bernstein</a>.
+</p>
+
+<h2> Compiling </h2>
+
+<ul>
+ <li> The libstddjb functions are available under the <tt>skalibs/stddjb.h</tt>
+header, which includes a lot of lower-level headers. If you know what
+lower-level headers to use, you might speed up your compilation process by
+including them directly. </li>
+</ul>
+
+<h2> Programming </h2>
+
+<ul>
+ <li> <a href="alloc.html">skalibs/alloc.h</a>: basic heap memory allocation primitives </li>
+ <li> <a href="allreadwrite.html">skalibs/allreadwrite.h</a>: <a href="safewrappers.html">safe
+wrappers</a> around I/O functions, extra I/O functions </li>
+ <li> <a href="bitarray.html">skalibs/bitarray.h</a>: how to handle large arrays of bits </li>
+ <li> <a href="bufalloc.html">skalibs/bufalloc.h</a>: bufferized output (with dynamically allocated buffers)</li>
+ <li> <a href="buffer.html">skalibs/buffer.h</a>: bufferized I/O (with statically allocated buffers) </li>
+ <li> <a href="bytestr.html">skalibs/bytestr.h</a>: basic operations on strings and byte arrays </li>
+ <li> <a href="cdb.html">skalibs/cdb.h</a>: how to read
+<a href="http://en.wikipedia.org/wiki/Cdb_%28software%29">cdb</a> files </li>
+ <li> <a href="cdb_make.html">skalibs/cdb_make.h</a>: how to write
+<a href="http://en.wikipedia.org/wiki/Cdb_%28software%29">cdb</a> files </li>
+ <li> <a href="direntry.html">skalibs/direntry.h</a>: portable directory operations </li>
+ <li> <a href="djbtime.html">skalibs/djbtime.h</a>: conversions between date and time formats </li>
+ <li> <a href="djbunix.html">skalibs/djbunix.h</a>: management of basic Unix concepts </li>
+ <li> <a href="envalloc.html">skalibs/envalloc.h</a>: management of dynamically allocated <em>argv</em> and <em>envp</em> </li>
+ <li> <a href="env.html">skalibs/env.h</a>: management of <em>argv</em> and <em>envp</em> </li>
+ <li> <a href="fmtscan.html">skalibs/fmtscan.h</a>: formatters (printers) and scanners (parsers) for basic C types </li>
+ <li> <a href="genalloc.html">skalibs/genalloc.h</a>: generic advanced management of dynamically allocated structures </li>
+ <li> <a href="genwrite.html">skalibs/genwrite.h</a>: interface to generic writes either to strallocs or to buffers </li>
+ <li> <a href="getpeereid.html">skalibs/getpeereid.h</a>: the <tt>getpeereid()</tt> system call </li>
+ <li> <a href="iopause.html">skalibs/iopause.h</a>: the skalibs event loop selection function </li>
+ <li> <a href="iobuffer.html">skalibs/iobuffer.h</a>: optimized data transfer from a fd to another </li>
+ <li> <a href="lolstdio.html">skalibs/lolstdio.h</a>:
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html">printf</a>-like
+functions writing into <a href="buffer.html">buffers</a> or <a href="bufalloc.html">bufallocs</a> </li>
+ <li> <a href="mininetstring.html">skalibs/mininetstring.h</a>: a protocol to transmit variable-length messages (limited to 64kB) </li>
+ <li> <a href="netstring.html">skalibs/netstring.h</a>: a protocol to transmit variable-length messages (limited to 2^32 bytes) </li>
+ <li> <a href="segfault.html">skalibs/segfault.h</a>: voluntary error generation </li>
+ <li> <a href="selfpipe.html">skalibs/selfpipe.h</a>: automated selfpipe trick (i.e.
+how to safely handle signals in event loops) </li>
+ <li> <a href="sgetopt.html">skalibs/sgetopt.h</a>: <tt>getopt()</tt>-style command-line options management </li>
+ <li> <a href="sig.html">skalibs/sig.h</a>: safe signal management </li>
+ <li> <a href="skamisc.html">skalibs/skamisc.h</a>: general string quoting and parsing; miscellaneous, unclassifiable functions </li>
+ <li> <a href="socket.html">skalibs/socket.h</a>: INET domain sockets </li>
+ <li> <a href="stralloc.html">skalibs/stralloc.h</a>: advanced management of dynamically allocated strings </li>
+ <li> <a href="strerr.html">skalibs/strerr.h</a>: basic error messages </li>
+ <li> <a href="strerr2.html">skalibs/strerr2.h</a>: advanced error messages </li>
+ <li> <a href="tai.html">skalibs/tai.h</a>: time, timers and system clock </li>
+ <li> <a href="webipc.html">skalibs/webipc.h</a>: UNIX domain sockets </li>
+</ul>
+
+<p>
+ The following headers are automatically generated at compile-time, when the
+<em>headers</em> subsystem is made. The <tt>skalibs/stddjb.h</tt> file also
+includes them.
+</p>
+
+<ul>
+ <li> skalibs/uint16.h: operations with 16-bit unsigned integers </li>
+ <li> skalibs/uint32.h: operations with 32-bit unsigned integers </li>
+ <li> skalibs/uint64.h: operations with 64-bit unsigned integers </li>
+ <li> skalibs/ushort.h: portable helpers for the "unsigned short" basic type </li>
+ <li> skalibs/uint.h: portable helpers for the "unsigned int" basic type </li>
+ <li> skalibs/ulong.h: portable helpers for the "unsigned long" basic type </li>
+ <li> skalibs/error.h: portable macros for errno management </li>
+ <li> skalibs/gidstuff.h: helpers for the "gid_t" type </li>
+ <li> skalibs/setgroups.h: stub for the setgroups() function, for systems that do not define it</li>
+ <li> <a href="ip46.html">skalibs/ip46.h</a>: IPv4/IPv6 abstraction layer </li>
+</ul>
+
+<p>
+ Additionally, <tt>stddjb.h</tt> also includes the following headers, which
+are not associated with any code and are mostly self-explanatory:
+</p>
+
+<ul>
+ <li> <a href="gccattributes.html">skalibs/gccattributes.h</a>: wrappers around a few GCC-specific optimizations </li>
+ <li> skalibs/diuint.h: for associative arrays of unsigned integers </li>
+ <li> skalibs/diuint32.h: for associative arrays of 32-bit unsigned integers </li>
+ <li> skalibs/environ.h: declaration of the <em>environ</em> variable </li>
+ <li> skalibs/nsig.h: the number of system signals, for systems that do not define it </li>
+ <li> skalibs/nonposix.h: feature test macros for non-POSIX-compliant systems </li>
+ <li> skalibs/siovec.h:
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_uio.h.html">iovec</a>-like
+structure for scatter/gather IO operations </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/libstddjb/iopause.html b/doc/libstddjb/iopause.html
new file mode 100644
index 0000000..72eedde
--- /dev/null
+++ b/doc/libstddjb/iopause.html
@@ -0,0 +1,196 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the iopause library interface</title>
+ <meta name="Description" content="skalibs: the iopause library interface" />
+ <meta name="Keywords" content="skalibs c unix iopause library libstddjb" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libstddjb</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>iopause</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/iopause.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>iopause</tt> is the skalibs API for event loop selection. It's a
+wrapper around the system's
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/poll.html">poll()</a>
+(if available) or
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/select.html">select()</a>
+(if <tt>poll()</tt> is unavailable) function. It
+works around some system-dependent quirks; also it works with
+<em>absolute dates</em> instead of timeouts. This is a good thing:
+see below.
+</p>
+
+<p>
+ <tt>iopause</tt> is a derived work from Dan J. Bernstein's
+<a href="http://cr.yp.to/lib/iopause.html">iopause</a> library, but the
+skalibs implementation is subtly different.
+</p>
+
+<h2> Data structures </h2>
+
+<p>
+ An <tt>iopause_fd</tt> structure is similar to a
+<a href="http://www.opengroup.org/onlinepubs/9699919799/basedefs/poll.h.html">struct pollfd</a>
+structure, and must be filled the same way. Usually, the user declares
+an array of <tt>iopause_fd</tt> and fills it, one element per descriptor
+to select on. If <em>x</em> is an <tt>iopause_fd</tt>:
+</p>
+
+<ul>
+ <li> <em>x</em>.fd must be set to the fd number to select on. </li>
+ <li> <em>x</em>.events must be a disjunction of the following flags:
+ <ul>
+ <li> IOPAUSE_READ if the fd is to be selected for reading. </li>
+ <li> IOPAUSE_WRITE if the fd is to be selected for writing. </li>
+ </ul> </li>
+ <li> When the selection function returns, <em>x</em>.revents contains
+a disjunction of the following flags:
+ <ul>
+ <li> IOPAUSE_READ if the fd is readable (this include reception of an EOF). </li>
+ <li> IOPAUSE_WRITE if the fd is writable. </li>
+ <li> IOPAUSE_EXCEPT if an exception (such as EOF or an error) occurred on the fd. </li>
+ </ul> </li>
+</ul>
+
+<p>
+ Unlike <tt>poll()</tt> or <tt>select()</tt>, which use a <em>timeout</em>
+argument, the <tt>iopause()</tt> function uses a <em>deadline</em> argument,
+i.e. an absolute time at which it must return 0 if no event has happened
+so far, as well as a <em>stamp</em> argument, i.e. an absolute time meaning
+<em>now</em>. Those arguments are stored in
+<a href="tai.html">tain_t</a>s. Here is why:
+</p>
+
+<p>
+ The event loop pattern is mostly used to multiplex several asynchronous
+events that can happen independently, at the same time or not. Let's
+say you have 3 events, <em>x</em>, <em>y</em> and <em>z</em>. Each of
+those has a separate timeout: if <em>x</em> happens before <em>x-timeout</em>
+milliseconds, you call the <em>x-event-handler</em> function, but
+if <em>x-timeout</em> milliseconds elapse without <em>x</em> happening,
+you call <em>x-timeout-handler</em> function. And similarly with <em>y</em>
+and <em>z</em>.
+</p>
+
+<p>
+ But the selection function returning does not mean <em>x</em> has happened
+or that <em>x</em> has timed out. It might also mean that <em>y</em> has
+happened, that <em>y</em> has timed out, that <em>z</em> has happened, that
+<em>z</em> has timed out, or something else entirely. In the post-selection
+part of the loop, the proper handler is called for the event or timeout
+that has happened; then the loop is executed again, and in the
+pre-selection part of the loop, the array describing the events is filled,
+and the selection timeout is computed.
+</p>
+
+<p>
+ How are you going to compute that global selection timeout? Easy: it's the
+shortest of the three. But we just spent some amount of time waiting, so the
+individual timeouts must be recomputed! This means:
+<ul>
+ <li> You need a way to know the time spent in a selection primitive, which
+basically means getting a timestamp before the selection and once again
+after the timestamp. </li>
+ <li> You need to recompute every individual timeout everytime you enter
+the loop. </li>
+</ul>
+
+<p>
+ That is really cumbersome. A much simpler way of doing things is:
+</p>
+
+<ul>
+ <li> Always keep a reasonably accurate estimation of the current
+time in a <em>stamp</em> variable. That means getting the current time
+at the start of the process, and updating it <em>right after</em> any
+action that takes a significant amount of time. When to update <em>stamp</em>
+can be difficult to estimate in CPU-bound processes; fortunately, most
+processes using an event loop are IO-bound, and the only actions that take
+a non-negligible amount of time in an IO-bound process are the blocking
+primitives. So, <em>stamp</em> must be updated <em>right after a selection
+function returns</em>, and if the program has been correctly written and
+cannot block anywhere else, it's the only place where it needs to be. </li>
+ <li> For every event, compute the <em>deadline</em> of that event:
+<em>x-deadline</em> is <em>x-timeout</em> added to the current <em>stamp</em>
+value when <em>x</em> enters the loop. This is done only once per event:
+you never have to recompute event deadlines - unlike timeouts, which diminish
+over time, deadlines do not change. </li>
+ <li> At every iteration, the selection deadline is the earliest of all the
+available event deadlines. </li>
+ <li> As an added bonus: after the selection function returns and
+ <em>stamp</em> has been updated, it is easy to check which events have
+timed out and which have not: <em>x</em> has timed out iff <em>x-deadline</em>
+is earlier than <em>stamp</em>. </li>
+</ul>
+
+<p>
+ Maintaining a global timestamp and using absolute times instead of relative
+times really is the right way to work with event loops, and the <tt>iopause</tt>
+interface reflects that. Of course, you need a reliable, bug-free time library
+and a monotonic, constant system clock to handle absolute times correctly;
+that is why <tt>iopause</tt> relies on the <a href="tai.html">tai</a> library.
+</p>
+
+<h2> Functions </h2>
+
+<p>
+<code> int iopause (iopause_fd *x, unsigned int len, tain_t const *deadline, tain_t const *stamp) </code> <br />
+Blocks until one of the events described in the <em>x</em> array, of length
+<em>len</em>, happens, or until the absolute date *<em>deadline</em> is
+reached. <em>deadline</em> may be null, in which case the function blocks
+indefinitely until an event happens. If <em>deadline</em> is not null, then
+<em>stamp</em> must not be null, and must contain an accurate estimation
+of the current time. The function returns the number of events that have
+happened, 0 for a timeout, or -1 (and sets errno) for an error.
+</p>
+
+<p>
+<code> int iopause_stamp (iopause_fd *x, unsigned int len, tain_t const *deadline, tain_t *stamp) </code> <br />
+Like <tt>iopause()</tt>, but if <em>stamp</em> is not null, it is updated
+right before the function returns. This helps the user always keep a
+reasonably accurate estimation of the current time in <em>stamp</em>;
+it is recommended to use this function instead of the lower-level
+<tt>iopause()</tt>.
+</p>
+
+<h3> Underlying implementations </h3>
+
+<p>
+ <tt>iopause</tt> is an alias to either <tt>iopause_poll</tt> or
+or <tt>iopause_select</tt>. By default, it is aliased to <tt>iopause_poll</tt>; to
+alias it to <tt>iopause_select</tt> instead, configure skalibs with the
+<tt>--enable-iopause-select</tt> option.
+</p>
+
+<p>
+Both <tt>iopause_poll</tt> and <tt>iopause_select</tt> are implemented on top of the
+<a href="http://man7.org/linux/man-pages/man2/ppoll.2.html">ppoll()</a> system call
+if it is available; but if it is not, then <tt>iopause_poll</tt> defaults to
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html">poll()</a>,
+which has a more comfortable API than
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html">select()</a>,
+but a maximum precision of 1 millisecond which might not be enough for some applications; whereas
+<tt>iopause_select<tt> defaults to select(), which incurs some CPU overhead for the
+API conversion, but has a 1 microsecond precision.
+</p>
+
+</body>
+</html>
diff --git a/doc/libstddjb/ip46.html b/doc/libstddjb/ip46.html
new file mode 100644
index 0000000..ee2f31c
--- /dev/null
+++ b/doc/libstddjb/ip46.html
@@ -0,0 +1,172 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the ip46 library interface</title>
+ <meta name="Description" content="skalibs: the ip46 library interface" />
+ <meta name="Keywords" content="skalibs c unix ip46 library libstddjb" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libstddjb</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>ip46</tt> library interface </h1>
+
+<p>
+ The following functions and structures are declared in the <tt>skalibs/ip46.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>ip46</tt> is a set of macros and functions to support both IPv4
+and IPv6 network operations in an abstracted way.
+</p>
+
+<p>
+ If skalibs has been built with the <a href="../flags.html#noipv6">--disable-ipv6</a>
+configure option, or it detects at build time than the target does not support IPv6, then
+<tt>ip46</tt> structures and functions will be directly aliased to their
+IPv4 implementations with no overhead at all.
+</p>
+
+<h2> Data structures </h2>
+
+<p>
+ An <tt>ip46full_t</tt> is a structure that contains either an IPv4 or an IPv6
+address.
+ If <em>a</em> is an <tt>ip46full_t</tt>, then:
+</p>
+
+<ul>
+ <li> ip46_is6(&amp;<em>a</em>) is 1 if <em>a</em> is
+IPv6 and 0 otherwise. </li>
+ <li> <em>a</em>.ip points to 16 (if IPv6) or 4 (if IPv4) bytes containing
+the address, in network byte order. </li>
+</ul>
+
+<p>
+ If skalibs has been build with IPv6 support, an <tt>ip46_t</tt> is
+the same type as an <tt>ip46full_t</tt>. Otherwise, an <tt>ip46_t</tt>
+is a structure that just contains an IPv4 address.
+</p>
+
+<h2> Functions </h2>
+
+<p>
+<code> int ip46_from_ip4 (ip46_t *a, char const *ip) </code> <br />
+Stores the IPv4 pointed to by <em>ip</em> into *<em>a</em>. Returns 1.
+</p>
+
+<p>
+<code> int ip46_from_ip6 (ip46_t *a, char const *ip) </code> <br />
+Stores the IPv6 pointed to by <em>ip</em> into *<em>a</em>. Returns 1,
+except if IPv6 is unavailable, in which case it returns 0 ENOSYS.
+</p>
+
+<p>
+<code> unsigned int ip46_fmt (char *s, ip46_t const *a) </code> <br />
+Formats the address in *<em>a</em> into the string <em>s</em>, which
+must be preallocated. Returns the number of bytes written. The address
+will be accordingly formatted as IPv4 or IPv6.
+</p>
+
+<p>
+<code> unsigned int ip46_scan (char const *s, ip46_t *a) </code> <br />
+Scans the string <em>s</em> for an IPv4 or IPv6 address. If it finds
+one, writes it into *<em>a</em> and returns the number of bytes read.
+If it cannot, returns 0.
+</p>
+
+<p>
+<code> unsigned int ip46_scanlist (ip46_t *list, unsigned int max, char const *s, unsigned int *n) </code> <br />
+Scans the string <em>s</em> for a list of comma-, semicolon-, space-, tab- or
+newline-separated IPv4 or IPv6 addresses, up to a maximum of <em>max</em>. It
+stores them into the (preallocated) ip46_t array pointed to by <em>list</em>.
+It returns the number of bytes read (0 if <em>s</em> does not contain a valid
+IP list at all), and stores the number of found and scanned addresses into *<em>n</em>.
+</p>
+
+<p>
+<code> int socket_connect46 (int fd, ip46_t *a, uint16 port) </code> <br />
+Connects the socket <em>fd</em> to address *<em>a</em> and port <em>port</em>.
+Returns 0 in case of success, and -1 (and sets errno) in case of failure.
+</p>
+
+<p>
+<code> int socket_bind46 (int fd, ip46_t *a, uint16 port) </code> <br />
+Binds the socket <em>fd</em> to address *<em>a</em> and port <em>port</em>.
+Returns 0 in case of success, and -1 (and sets errno) in case of failure.
+</p>
+
+<p>
+<code> int socket_bind46_reuse (int fd, ip46_t *a, uint16 port) </code> <br />
+Same as the previous function, with the SO_REUSEADDR option.
+</p>
+
+<p>
+<code> int socket_deadlineconnstamp46 (int fd, ip46_t const *a, uint16 port, tain_t const *deadline, tain_t *stamp) </code> <br />
+Attempts to synchronously connect the socket <em>fd</em> to address a<em>a</em>
+and port <em>port</em>. Returns 1 if it succeeds and 0 (and sets errno)
+if it fails. <em>stamp</em> must contain an accurate enough
+timestamp, and is updated when the function returns. If the connection is
+still pending by <em>deadline</em>, then the attempt stops and the function
+returns 0 ETIMEDOUT.
+</p>
+
+<p>
+<code> int socket_recv46 (int fd, char *s, unsigned int len, ip46_t *a, uint16 *port) </code> <br />
+Reads a datagram from socket <em>fd</em>. The message is stored into buffer <em>s</em>
+of max length <em>len</em>, and stores the sender information into address *<em>a</em>
+and port *<em>port</em>. Returns the length of the read datagram, or -1 if it fails.
+</p>
+
+<p>
+<code> int socket_send46 (int fd, char const *s, unsigned int len, ip46_t const *a, uint16 port) </code> <br />
+Writes a datagram to socket <em>fd</em>. The message is read from buffer <em>s</em>
+of length <em>len</em>, and the recipient information is address *<em>a</em>
+and port <em>port</em>. Returns the number of written bytes, or -1 if it fails.
+</p>
+
+<p>
+<code> int socket_local46 (int fd, ip46_t *a, uint16 *port) </code> <br />
+Gets the local information about bound socket <em>fd</em>: the local IP
+address is stored into *<em>a</em> and the local port into *<em>port</em>.
+Returns 0 in case of success, and -1 (and sets errno) in case of failure.
+</p>
+
+<p>
+<code> int socket_remote46 (int fd, ip46_t *a, uint16 *port) </code> <br />
+Gets the peer information about connected socket <em>fd</em>: the remote IP
+address is stored into *<em>a</em> and the remote port into *<em>port</em>.
+Returns 0 in case of success, and -1 (and sets errno) in case of failure.
+</p>
+
+<p>
+<code> int socket_recvnb46 (int fd, char *s, unsigned int len, ip46_t *a, uint16 *port,
+tain_t const *deadline, tain_t *stamp) </code> <br />
+Like <tt>socket_recv46</tt>, except that the function blocks until a datagram
+is received. *<em>stamp</em> must be an accurate enough approximation of the
+current time, and is updated when the function returns. If no datagram has
+arrived by absolute date *<em>deadline</em>, the function returns -1 ETIMEOUT.
+</p>
+
+<p>
+<code> int socket_sendnb46 (int fd, char const *s, unsigned int len, ip46_t const *a, uint16 port,
+tain_t const *deadline, tain_t *stamp) </code> <br />
+Like <tt>socket_send46</tt>, except that the function blocks until a datagram
+has been effectively sent. *<em>stamp</em> must be an accurate enough approximation of the
+current time, and is updated when the function returns. If the message still has
+not been sent by absolute date *<em>deadline</em>, the function returns -1 ETIMEOUT.
+</p>
+
+</body>
+</html>
diff --git a/doc/libstddjb/lolstdio.html b/doc/libstddjb/lolstdio.html
new file mode 100644
index 0000000..e059f24
--- /dev/null
+++ b/doc/libstddjb/lolstdio.html
@@ -0,0 +1,91 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the lolstdio library interface</title>
+ <meta name="Description" content="skalibs: the lolstdio library interface" />
+ <meta name="Keywords" content="skalibs c unix stdio lol printf fprintf library libstddjb" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libstddjb</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>lolstdio</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/lolstdio.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>lolstdio</tt> is a set of convenience functions providing
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html">printf</a>-style
+formatting but interacting with <a href="buffer.html">buffers</a> or
+<a href="bufalloc.html">bufallocs</a> instead of stdio FILEs.
+</p>
+
+<p>
+ Like any printf-style functions, the lolstdio functions are rather
+complex and inefficient, and not recommended for general use; they are
+provided as a quick and dirty way to debug or test things. Programmers
+are advised to use the <a href="fmtscan.html">type-specific formatting
+functions</a> instead in production-quality code.
+</p>
+
+<p>
+ Be aware that functions writing into buffers interact badly with
+non-blocking fds (and asynchronism in general) - just as you cannot
+use FILEs with non-blocking output. Functions writing into bufallocs,
+however, are fine, because bufallocs are much more suited to asynchronous
+writing than fixed-size buffers or FILEs are.
+</p>
+
+<p>
+ The current lolstdio implementation relies on the libc's
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/vsnprintf.html">vsnprintf</a>
+function.
+</p>
+
+<h2> Functions </h2>
+
+<p>
+<code> int vbprintf (buffer *b, char const *format, va_list args) </code> <br />
+Like <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/vfprintf.html">vfprintf</a>
+except that the result is written to the buffer <em>b</em>.
+</p>
+
+<p>
+<code> int bprintf (buffer *b, char const *format, ...) </code> <br />
+Like <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html">fprintf</a>
+except that the result is written to the buffer <em>b</em>.
+</p>
+
+<p>
+<code> int lolprintf (char const *format, ...) </code> <br />
+Like <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html">printf</a>
+except that the result is written to the buffer <tt>buffer_1</tt>.
+</p>
+
+<p>
+<code> int vbaprintf (bufalloc *ba, char const *format, va_list args) </code> <br />
+Like <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/vfprintf.html">vfprintf</a>
+except that the result is written to the bufalloc <em>ba</em>.
+</p>
+
+<p>
+<code> int baprintf (bufalloc *ba, char const *format, ...) </code> <br />
+Like <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html">fprintf</a>
+except that the result is written to the bufalloc <em>ba</em>.
+</p>
+
+</body>
+</html>
diff --git a/doc/libstddjb/safewrappers.html b/doc/libstddjb/safewrappers.html
new file mode 100644
index 0000000..6d889d6
--- /dev/null
+++ b/doc/libstddjb/safewrappers.html
@@ -0,0 +1,91 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: safe wrappers</title>
+ <meta name="Description" content="skalibs: safe wrappers" />
+ <meta name="Keywords" content="skalibs c unix safe wrappers safewrappers library libstddjb" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libstddjb</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> Safe wrappers </h1>
+
+<p>
+ Lots of functions in <tt>libstddjb</tt>, declared for instance in
+<a href="allreadwrite.html">allreadwrite.h</a> or
+<a href="djbunix.html">djbunix.h</a>, are just "safe wrappers"
+around corresponding system functions. For instance,
+<tt>fd_read()</tt> is a safe wrapper around the system <tt>read()</tt>
+function.
+</p>
+
+<h2> The problem </h2>
+
+<p>
+ Quite a lot of system calls are defined by
+<a href="http://www.opengroup.org/onlinepubs/9699919799/nfindex.html">The
+Open Group Base Specifications</a> as interruptible: when the process is in
+the middle of such a system call and receives a signal that it does not
+ignore, the system call immediately returns -1 EINTR (after the signal
+handler, if any, has been executed).
+</p>
+
+<p>
+ This means that the intended execution of the process is at the mercy
+of a stray signal. If a signal happens at the wrong time, a system call
+fails when it could have succeeded. This is not acceptable.
+</p>
+
+<h2> The solution </h2>
+
+<p>
+ So, in order to be perfectly reliable, when a program makes an interruptible
+system call, it <em>must</em> check whether the return value is -1 EINTR,
+and restart the system call if it is the case. This is annoying to write;
+so, <tt>libstddjb</tt> provides small wrappers around interruptible system
+calls, so that programmers can just call those <em>safe wrappers</em> and
+never bother with this again.
+</p>
+
+<p>
+ The performance loss from having a wrapper layer is totally negligible
+compared to the cost of using a system call in the first place.
+</p>
+
+<h2> But isn't it what the SA_RESTART flag is meant to address? </h2>
+
+<p>
+ Yes, it is. Unfortunately, SA_RESTART only protects interruptible
+system calls from signals you actually have control over, and set a
+handler for with
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/sigaction.html">sigaction()</a>.
+This is not enough. You cannot decide that <em>every</em> signal sent
+to your process should have SA_RESTART behaviour; and the Single Unix
+specification says nothing about signals you do not control. For instance,
+you cannot trap SIGSTOP; SIGSTOP does not kill your process, which
+should resume flawlessly at the next SIGCONT; and according to the
+specification, it is valid for SIGSTOP and SIGCONT to <em>not</em>
+have SA_RESTART behaviour. So if you get a SIGSTOP while performing
+an interruptible system call, that system call may return -1 EINTR,
+this is not an OS bug, and there's nothing you can do about it with
+<tt>sigaction()</tt>.
+</p>
+
+<p>
+ SA_RESTART is only a partial solution: in other words, it doesn't work.
+Until the Single Unix specification explicitly states that untrapped
+non-lethal signals MUST have SA_RESTART behaviour by default, you
+<em>need</em> safe wrappers to protect interruptible system calls.
+</p>
+
+</body>
+</html>
diff --git a/doc/libstddjb/selfpipe.html b/doc/libstddjb/selfpipe.html
new file mode 100644
index 0000000..7eff430
--- /dev/null
+++ b/doc/libstddjb/selfpipe.html
@@ -0,0 +1,242 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the selfpipe library interface</title>
+ <meta name="Description" content="skalibs: the selfpipe library interface" />
+ <meta name="Keywords" content="skalibs stddjb libstddjb selfpipe self-pipe library interface" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libstddjb</a><br />
+<a href="../libskarnet.html">skalibs</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>selfpipe</tt> library interface </h1>
+
+<p>
+ The selfpipe functions are declared in the
+<tt>skalibs/selfpipe.h</tt> header and implemented in the <tt>libskarnet.a</tt>
+or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> What does it do&nbsp;? </h2>
+
+<p>
+Signal handlers suck.
+</p>
+
+<p>
+They do. I don't care how experienced you are with C/Unix programming,
+they do. You can be Ken Thompson, if you use signal handlers as a
+regular part of your C programming model, you <em>are</em> going to
+screw up, and write buggy code.
+</p>
+
+<p>
+ Unix is tricky enough with interruptions. Most of libstddjb's wrappers
+are there to protect system calls from EINTR. (And no, the SA_RESTART
+option in sigaction() <a href="safewrappers.html">isn't protection
+enough</a>.) But signal handlers are
+more than just pesky interruptions: they can totally change the
+execution flow. They mess up the logic of linear and structured code,
+they introduce non-determinism; you always have to think "and what
+if I get interrupted here and the flow goes into a handler...". This
+is annoying.
+</p>
+
+<p>
+ Moreover, signal handler code is <em>very</em> limited in what it can
+do. It can't use any non-reentrant function! If you call a non-reentrant
+function, and by chance you were precisely in that non-reentrant function
+code when you got interrupted by a signal... you lose. That means, no
+malloc(). No bufferized IO. No globals. The list goes on and on. <br />
+ If you're going to catch signals, you'll want to handle them <em>outside</em>
+the signal handler. You actually want to spend <em>the least possible
+time</em> inside a signal handler - just enough to notify your main
+execution flow that there's a signal to take care of.
+</p>
+
+<p>
+ And, of course, signal handlers don't mix with event loops, which is
+a classic source of headaches for programmers and led to the birth of
+abominations such as
+<a href="http://www.opengroup.org/onlinepubs/009695399/functions/pselect.html">
+pselect</a>. So much for the "everything is a file" concept that Unix was
+built on.
+</p>
+
+<p>
+ A signal should be an event like any other.
+There should be a unified interface - receiving a signal should make some
+fd readable or something.
+</p>
+
+<p>
+ And that's exactly what the
+<a href="http://cr.yp.to/docs/selfpipe.html">self-pipe trick</a>, invented
+by <a href="../djblegacy.html">DJB</a>, does.
+</p>
+
+<p>
+ As long as you're in some kind of event loop, the self-pipe trick allows
+you to forget about signal handlers... <em>forever</em>. It works this way:
+</p>
+
+<ol>
+ <li> Create a pipe <tt>p</tt>. Make both ends close-on-exec and nonblocking. </li>
+ <li> Write a tiny signal handler ("top half") for all the signals you want to
+catch. This
+signal handler should just write one byte into <tt>p[1]</tt>, and do nothing
+more; ideally, the written byte identifies the signal. </li>
+ <li> In your event loop, add <tt>p[0]</tt> to the list of fds you're watching
+for readability. </li>
+</ol>
+
+<p>
+ When you get a signal, a byte will be written to the self-pipe, and your
+execution flow will resume. When you next go through the event loop,
+<tt>p[0]</tt> will be readable; you'll then be able to read a byte from
+it, identify the signal, and handle it - in your unrestricted main
+environment (the "bottom half" of the handler).
+</p>
+
+<p>
+ The selfpipe library does it all for you - you don't even have to write
+the top half yourself. You can forget their existence and recover
+some peace of mind. Of course, you <em>still</em> need to protect your
+system calls against EINTR: the self-pipe trick doesn't prevent signals
+from happening.
+</p>
+
+<h2> How do I use it&nbsp;? </h2>
+
+<h3> Starting </h3>
+
+<pre>
+int fd = selfpipe_init() ;
+</pre>
+
+<p>
+<tt>selfpipe_init()</tt> sets up a selfpipe. You must use that
+function first. <br />
+If <tt>fd</tt> is -1, then an error occurred. Else <tt>fd</tt> is a
+non-blocking descriptor that can be used in your event loop. It will
+be selected for readability when you've caught a signal.
+</p>
+
+<h3> Trapping/untrapping signals </h3>
+
+<pre>
+int r = selfpipe_trap(SIGTERM) ;
+</pre>
+
+<p>
+<tt>selfpipe_trap()</tt> catches a signal and sends it to the selfpipe.
+Uncaught signals won't trigger the selfpipe. <tt>r</tt> is 0 if
+the operation succeeded, and -1 if it failed. If it succeeded, you
+can forget about the trapped signal entirely. <br />
+In our example, if <tt>r</tt> is 0, then a SIGTERM will instantly
+trigger readability on <tt>fd</tt>.
+</p>
+
+<pre>
+int r = selfpipe_untrap(SIGTERM) ;
+</pre>
+
+<p>
+Conversely, <tt>selfpipe_untrap()</tt> uncatches a signal; the selfpipe
+will not manage it anymore. <tt>r</tt> is 0 if the operation succeeded
+and -1 if it failed.
+</p>
+
+<pre>
+int r ;
+sigset_t set ;
+sigemptyset(&set) ;
+sigaddset(&set, SIGTERM) ;
+sigaddset(&set, SIGHUP) ;
+r = selfpipe_trapset(&set) ;
+</pre>
+
+<p>
+<tt>selfpipe_trap()</tt> and <tt>selfpipe_untrap()</tt> handle signals one
+by one. Alternatively (and often preferrably), you can use
+<tt>selfpipe_trapset()</tt> to directly handle signal sets. When you call
+<tt>selfpipe_trapset()</tt>, signals that are present in <tt>set</tt> will
+be caught by the selfpipe, and signals that are absent from <tt>set</tt>
+will be uncaught. <tt>r</tt> is 0 if the operation succeeded and -1 if it
+failed.
+</p>
+
+<h3> Handling events </h3>
+
+<pre>
+int c = selfpipe_read() ;
+</pre>
+
+<p>
+ Call <tt>selfpipe_read()</tt> when your <tt>fd</tt> is readable.
+That's where you write your <em>real</em> signal handler: in the
+body of your event loop, in a "normal" context. <br />
+<tt>c</tt> is -1 if an error occurred - in which case chances are
+it's a serious one and your system has become very unstable.
+<tt>c</tt> is 0 if there are no more pending signals. If <tt>c</tt>
+is positive, it is the number of the signal that was caught.
+</p>
+
+<h3> Finishing </h3>
+
+<pre>
+selfpipe_finish() ;
+</pre>
+
+<p>
+ Call <tt>selfpipe_finish()</tt> when you're done using the selfpipe.
+Signal handlers will be restored to their previous value.
+</p>
+
+<h2> Any limitations&nbsp;? </h2>
+
+<p>
+ Some, as always.
+</p>
+
+<ul>
+ <li> The selfpipe library uses a global pipe;
+so, it's not safe for multithreading. I'm not sure how multithreaded
+programs handle signals; I personally don't like multithreading and
+never use it, so I'm not knowledgeable about it. Anyway, if your
+program is multithreaded, chances are you don't have an asynchronous
+event loop, so the self-pipe trick has less benefits for you. </li>
+ <li> In rare cases, the self-pipe can theoretically be filled, if some
+application sends more than PIPE_BUF signals before you have time to
+<tt>selfpipe_read()</tt>. On most Unix systems, PIPE_BUF is 4096,
+so it's a very acceptable margin. Unless your code is waiting where
+it should not be, only malicious applications will fill the self-pipe
+- and malicious applications could just send you a SIGKILL and be done
+with you, so this is not a concern. Protect yourself from malicious
+applications with clever use of uids. </li>
+</ul>
+
+<h2> Hey, Linux has <a href="http://www.kernel.org/doc/man-pages/online/pages/man2/signalfd.2.html">signalfd()</a> for this&nbsp;! </h2>
+
+<p>
+ Yes, the Linux team loves to gratuitously add new system calls to do
+things that could already be done before without much effort. This
+adds API complexity, which is not a sign of good engineering.
+</p>
+
+<p>
+ However, now that <tt>signalfd()</tt> exists, it is indeed marginally more
+efficient than a pipe, and it saves one fd: so the selfpipe library
+is implemented via <tt>signalfd()</tt> when this call is available.
+</p>
+
+</body>
+</html>
diff --git a/doc/libstddjb/stralloc.html b/doc/libstddjb/stralloc.html
new file mode 100644
index 0000000..a5a1c7e
--- /dev/null
+++ b/doc/libstddjb/stralloc.html
@@ -0,0 +1,118 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the stralloc library interface</title>
+ <meta name="Description" content="skalibs: the stralloc library interface" />
+ <meta name="Keywords" content="skalibs c unix stralloc library libstddjb" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libstddjb</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>stralloc</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/stralloc.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>stralloc</tt> is the preferred skalibs way of storing objects into
+heap memory. It focuses on strings of <em>char</em>, which is the generic
+way to handle any object. For easy structure manipulation, the
+<a href="genalloc.html">genalloc</a>
+series of functions can be used; those functions are mostly macros wrapping
+calls to their stralloc counterparts.
+</p>
+
+<p>
+ A stralloc is a structure containing the following fields:
+</p>
+
+<ul>
+ <li> <em>s</em>: a pointer to a zone of heap memory. The stralloc
+functions internally manipulate those via the
+<a href="alloc.html">alloc</a> series of functions. It is recommended
+to never modify that field manually. </li>
+ <li> <em>len</em>: the <strong>used</strong> length of the
+allocated zone. It is the only field that the user can modify
+directly. </li>
+ <li> <em>a</em>: the number of allocated bytes. The user should never
+have to access that field, because the memory allocation management
+should be entirely transparent. <em>len</em> cannot exceed <em>a</em>:
+if an operation needs a bigger <em>len</em>, it will automatically
+reallocate as needed. </li>
+</ul>
+
+<p>
+ The benefits of using stralloc are as follows:
+</p>
+
+<ul>
+ <li> Memory allocation is performed on-demand and automatically, with
+a suitable size. Heuristics are used to accommodate constantly growing
+strings while minimizing the amount of needed reallocations. </li>
+ <li> If every heap-allocated object is represented by a stralloc, then
+it is very easy to identify what pointer is in the heap. When you stop
+using a pointer <em>p</em>, should you free it&nbsp;? Sometimes it's not
+easy to find out. When you stop using a stralloc <em>sa</em>, you
+<em>know</em> you must call <tt>stralloc_free(&amp;sa)</tt>. Store
+your strong references as strallocs and weak references as simple
+pointers, and never free simple pointers. This policy allows me to
+boast that <em>no skarnet.org software has ever leaked memory</em>. </li>
+ <li> Repeated for emphasis:
+<strong> the golden rule for programming with strallocs is
+<em>every pointer to the heap must be owned by a stralloc</em>. </strong>
+Every pointer you handle yourself either does not point to the heap,
+or is weak. That sometimes implies unusual programming practices, such
+as having storage separated from structure, but it's hands down the
+easiest way to keep control of your heap in complex situations. </li>
+<li> The indirection layer makes weak references immune to
+reallocation troubles. The <em>s</em> field may change when a
+reallocation happens, but the stralloc structure's address never
+changes. </li>
+</ul>
+
+<p>
+ A stralloc can be declared anywhere: static/global data, stack or heap. (Of course,
+as a general rule, you should favor the stack whenever possible.)
+A stralloc should be initialized to STRALLOC_ZERO before its first use.
+</p>
+
+<h2> Functions </h2>
+
+<p>
+<code> int stralloc_catb (stralloc *sa, char const *s, unsigned int len) </code> <br />
+Appends the <em>len</em> bytes pointed to by <em>s</em> to the end of the
+memory zone handled by *<em>sa</em>, automatically allocating more memory
+if needed. Returns 1 if it succeeds, and 0 if it fails.
+</p>
+
+<p>
+<code> void stralloc_free (stralloc *sa) </code> <br />
+Frees <em>*sa</em>, i.e. calls <a href="alloc.html">alloc_free</a>
+on <em>sa</em>&rarr;s then zeroes the structure. *<em>sa</em> is
+then reusable. However, it is not good practice to call this function
+if you're going to reuse *<em>sa</em> soon: it takes time and causes
+memory fragmentation. Just setting <em>sa</em>&rarr;len to 0 allows
+you to instantly reuse the allocated block of memory.
+</p>
+
+<p>
+ The above are the most important and fundamental functions of
+<tt>skalibs/stralloc.h</tt>. Other functions can be found in this header and
+their prototypes are self-explaining.
+</p>
+
+</body>
+</html>
diff --git a/doc/libstddjb/tai.html b/doc/libstddjb/tai.html
new file mode 100644
index 0000000..3524c05
--- /dev/null
+++ b/doc/libstddjb/tai.html
@@ -0,0 +1,462 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the tai library interface</title>
+ <meta name="Description" content="skalibs: the tai library interface" />
+ <meta name="Keywords" content="skalibs c unix tai library libstddjb" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libstddjb</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>tai</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/tai.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>tai</tt> is a set of data structures and primitives to represent
+and perform operations on time.
+</p>
+
+<p>
+ The point of <tt>tai</tt> is to handle time without ever having to
+deal with annoyances such as Y2K, Y2038, NTP limits, non-linear
+clocks, and the like. By using the <tt>tai</tt> interface, you ensure
+your program will behave properly no matter what.
+</p>
+
+<h3> What is the problem&nbsp;? </h3>
+
+<p>
+ The standard APIs for time management under Unix are broken in more
+or less subtle ways. The most obvious thing is that they do not pass
+year 2038. A less obvious problem is that they do not handle leap
+seconds correctly. Here are a few references you should read to
+understand what is going on:
+</p>
+
+<ul>
+ <li> <a href="http://www.madore.org/~david/misc/time.html">David Madore's page
+on time</a>. It's outdated (there was a leap second in 2009), but complete. </li>
+ <li> From David Madore again, more to the point: a
+<a href="http://www.madore.org/~david/computers/unix-leap-seconds.html">page
+about leap seconds, UTC and TAI</a>. </li>
+ <li> The skalibs <a href="../flags.html#clockistai">--enable-tai-clock</a>
+and <a href="../flags.html#tzisright">--enable-right-tz</a> documentation. </li>
+ <li> <a href="http://cr.yp.to/proto/utctai.html">Dan J. Bernstein's page
+on UTC, TAI and Unix time</a>. </li>
+</ul>
+
+<p>
+ The meat and potatoes of all this is that programmers cannot simply rely on
+standard Unix APIs such as
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/gettimeofday.html">gettimeofday()</a>
+(which, by the way, is marked as obsolescent, but it's not going to disappear tomorrow)
+to measure time intervals or even to give precise absolute time, and in
+any case those APIs will become obsolete in 2038.
+</p>
+
+<h3> So what does <tt>tai</tt> do&nbsp;? </h3>
+
+<p>
+ <tt>tai</tt> implements - among other things - the
+<a href="http://cr.yp.to/libtai/tai64.html">TAI64 and TAI64N</a>
+formats, which are used in all of skalibs. This gives a programmer access
+to precise <em>linear absolute time</em>, which is suitable for both
+timestamping (<em>wallclock</em> usage) and time interval measurements
+(<em>stopwatch</em> usage). Additionally, TAI64 passes Y2038 (it can
+represent dates exceeding the estimated lifespan of the universe).
+</p>
+
+<p>
+ <tt>tai</tt> has been inspired by Dan J. Bernstein's
+<a href="http://cr.yp.to/libtai.html">libtai</a> library, but does not
+borrow any code from it.
+</p>
+
+<h2> Data structures </h2>
+
+<p>
+ A <tt>tai_t</tt> structure holds an absolute date with a one-second
+precision. A <tt>tain_t</tt> structure holds an absolute date with a
+maximum of one-nanosecond precision, as permitted by the underlying system
+call. If <a href="../flags.html#usert">flag-usert</a> is clear, the system
+clock will be read via
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/gettimeofday.html">gettimeofday()</a>
+system call, which has a one-microsecond precision; if it is set, the
+system clock will be read via the
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/clock_gettime.html">clock_gettime()</a>
+system call, which has a one-nanosecond precision. In either case, a current
+<tt>tain_t</tt> will be unable to be more precise than the underlying
+implementation.
+</p>
+
+<p>
+ A <tt>tai_t</tt>, as well as a <tt>tain_t</tt>, can also
+hold a (possibly negative) relative time, i.e. a difference of absolute
+dates. It is up to the programmer to make sure that a relative time is
+never interpreted as an absolute TAI64 date, and vice-versa.
+</p>
+
+<h3> The leap second table </h3>
+
+<p>
+ skalibs provides a <tt>src/etc/leapsecs.dat</tt> file,
+which is copied to <tt>/etc/leapsecs.dat</tt> at installation time
+(or wherever you specified with the <tt>--prefix</tt> or <tt>--datadir</tt>
+options to configure).
+<strong>Make sure this file is always present and readable.</strong>
+This file contains the <em>leap second table</em>, which is needed for
+conversions between TAI and UTC. If you call a function that needs such
+a conversion (for instance, you call <tt>tain_sysclock()</tt> and your
+system clock is set to UTC) and the file cannot be read, the function
+call will fail.
+</p>
+
+<p>
+ The leap second table is read once in every process that needs it
+(the first time a TAI &harr; UTC conversion is made) and then is
+stored in memory. If the <tt>leapsecs.dat</tt> file changes, long-lived
+processes will need to be restarted to take the change into account.
+</p>
+
+<h2> Functions </h2>
+
+<h3> Wallclock operations </h3>
+
+<p>
+<code> int tai_now (tai_t *t) </code> <br />
+Writes the current time as a TAI value to *<em>t</em>, with a
+1-second precision. The current time is based on the system clock.
+Make sure skalibs has been compiled with or without the
+<a href="../flags.html#clockistai">--enable-tai-clock</a> configure option according
+to your system clock synchronization method: skalibs supports a
+system clock set to TAI-10 or to UTC.
+The function returns 1 if it succeeds, or 0 (and sets errno) if
+it fails.
+</p>
+
+<p>
+<code> int sysclock_get (tain_t *a) </code> <br />
+Reads the current value of the system clock into *<em>a</em>, with
+a 1-nanosecond (resp. 1-microsecond ) precision if skalibs has been
+configured with (resp. without) the
+<a href="../flags.html#usert">--enable-clock</a> option.
+Returns 1 if it succeeds or 0 (and sets errno) if it
+fails. Note that despite being a <tt>tain_t</tt>, *<em>a</em>
+<strong>does not contain a TAI value</strong> - it only contains
+an internal, Y2038-safe representation of the value of the system
+clock, which should be either TAI-10 or UTC. You should not use
+this function directly unless you know exactly what you are doing.
+</p>
+
+<p>
+<code> int sysclock_set (tain_t const *a) </code> <br />
+Sets the system clock to *<em>a</em>, provided *<em>a</em> has
+the correct internal representation. You should not use this
+function directly unless you know exactly what you are doing.
+</p>
+
+<p>
+<code> int tain_sysclock (tain_t *a) </code> <br />
+Reads the current time into *<em>a</em>, as a TAI64N value,
+with a 1-nanosecond (resp. 1-microsecond) precision if skalibs
+has been configured with (resp. without) the
+<a href="../flags.html#usert">--enable-clock</a>
+option. Returns 1 if it succeeds or 0 (and sets errno) if it
+fails.
+ Here <em>a</em> contains a valid TAI stamp, no matter what the
+system clock is set to: arithmetic operations can be performed
+on it.
+</p>
+
+<p>
+<code> int tain_setnow (tain_t const *a) </code> <br />
+Sets the current time to *<em>a</em>, with a 1-nanosecond
+(resp. 1-microsecond) precision if skalibs has been configured
+with (resp. without) the
+<a href="../flags.html#usert">--enable-clock</a>
+option. Returns 1 if it succeeds or 0 (and sets errno) if it
+fails. <em>a</em> must contain a valid TAI stamp; proper
+operations will be automatically run to convert that stamp into
+the right format for the system clock.
+</p>
+
+<h3> Stopwatch operations </h3>
+
+<p>
+ The following 3 operations are only defined if your system
+provides the
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_gettime.html">clock_gettime()</a>
+primitive with the CLOCK_MONOTONIC option.
+</p>
+
+<p>
+<code> int tain_clockmon_init (tain_t *offset) </code> <br />
+Initializes a stopwatch in *<em>offset</em>. The actual value of
+*<em>offset</em> is meaningless to the user; <em>offset</em>'s only
+use is to be given as a second parameter to <tt>tain_clockmon()</tt>.
+The function returns 1 if it succeeds or 0 (and sets errno) if it fails.
+</p>
+
+<p>
+ What <tt>tain_clockmon_init()</tt> does is synchronize the "stopwatch
+clock" (CLOCK_MONOTONIC) to the system clock. Right after
+<tt>tain_clockmon_init()</tt> has been called, the absolute times given
+by <tt>tain_clockmon()</tt> and <tt>tain_sysclock()</tt> are similar. Then,
+depending on the accuracy of the system clock, a drift may appear; calling
+<tt>tain_clockmon_init()</tt> again resets that drift to zero.
+</p>
+
+<p>
+<code> int tain_clockmon (tain_t *a, tain_t const *offset) </code> <br />
+ Gives the absolute time, as a TAI64N value, in *<em>a</em>. This
+absolute time is computed as a linear increase (as measured with
+CLOCK_MONOTONIC) since the last time <tt>tain_clockmon_init()</tt>
+was called with parameter <em>offset</em>. <tt>tain_clockmon()</tt>
+guarantees precise time interval measurements; however, the time it
+gives can slightly differ from the result of <tt>tain_sysclock()</tt>.
+The function returns 1 if it succeeds or 0 (and sets errno) if it fails.
+</p>
+
+<h3> All-purpose time reading </h3>
+
+<p>
+<code> int tain_init (void) </code> <br />
+If skalibs has been configured with the
+<a href="../flags.html#usemon">--enable-monotonic</a> option: this
+function initializes a process-global stopwatch, that future
+<tt>tain_now</tt> invocations will depend on.
+Without the <a href="../flags.html#usemon">--enable-monotonic</a> option: this
+function does nothing.
+The function returns 1 if it succeeds or 0 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int tain_now (tain_t *a) </code> <br />
+Writes the current time, as a TAI value, to *<em>a</em>. This is the
+function you should use to read time by default. It returns 1 if it succeeds or
+0 (and sets errno) if it fails.
+</p>
+
+<p>
+ If skalibs has been configured with the
+<a href="../flags.html#usemon">--enable-monotonic</a> option:
+<tt>tain_now()</tt> is computed as a linear increase from the last time
+<tt>tain_init()</tt> was called. (If <tt>tain_init()</tt> has never
+been called before, the first invocation of <tt>tain_now()</tt>
+automatically calls <tt>tain_init()</tt>.)
+ Without the <a href="../flags.html#usemon">--enable-monotonic</a> option:
+<tt>tain_now()</tt> is the same as <tt>tain_sysclock()</tt>.
+</p>
+
+<p>
+ If the above is unclear to you: just use <tt>tain_now()</tt>
+everytime you need to read time, and you will always get a reasonable
+approximation of the current time, in a format suited for arithmetic
+computations.
+</p>
+
+<h3> Converting to/from libc representations </h3>
+
+<p>
+<code> int tai_from_timeval (tai_t *t, struct timeval const *tv) <br />
+int tai_from_timespec (tai_t *t, struct timespec const *ts) <br />
+int tai_relative_from_timeval (tai_t *t, struct timeval const *tv) <br />
+int tai_relative_from_timespec (tai_t *t, struct timespec const *ts) </code> <br />
+Those functions convert an absolute (resp. relative) time in a
+struct timeval (resp. struct timespec) to an absolute (resp. relative)
+time in a tai_t, with a 1-second precision. They return 1.
+</p>
+
+<p>
+<code> int timeval_from_tai (struct timeval *tv, tai_t const *t) <br />
+int timespec_from_tai (struct timespec *ts, tai_t const *t) <br />
+int timeval_from_tai_relative (struct timeval *tv, tai_t const *t) <br />
+int timespec_from_tai_relative (struct timespec *ts, tai_t const *t) </code> <br />
+Those functions do the opposite conversion. They normally return 1;
+however, <tt>struct timeval</tt> and <tt>struct timespec</tt> cannot
+represent an absolute date before the Epoch, or a negative relative time;
+if *<em>t</em> cannot be converted, 0 EINVAL is returned.
+</p>
+
+<p>
+<code> int tain_from_timeval (tain_t *a, struct timeval const *tv) <br />
+int tain_from_timespec (tain_t *a, struct timespec const *ts) <br />
+int tain_relative_from_timeval (tain_t *a, struct timeval const *tv) <br />
+int tain_relative_from_timespec (tain_t *a, struct timespec const *ts) <br />
+int timeval_from_tain (struct timeval *tv, tain_t const *a) <br />
+int timespec_from_tain (struct timespec *ts, tain_t const *a) <br />
+int timeval_from_tain_relative (struct timeval *tv, tain_t const *a) <br />
+int timespec_from_tain_relative (struct timespec *ts, tain_t const *a) </code> <br />
+Same conversion operations, but with a <tt>tain_t</tt>. The 1-microsecond
+(for <tt>struct timeval</tt>) or 1-nanosecond (for <tt>struct timespec</tt>)
+precision is preserved.
+</p>
+
+<p>
+<code> void tain_uint (tain_t *a, unsigned int c) </code> <br />
+Stores a relative time of <em>c</em> seconds into <em>a</em>.
+</p>
+
+<p>
+<code> int tain_from_millisecs (tain_t *a, int ms) </code> <br />
+This function makes a <tt>tain_t</tt> representing a relative
+time of <em>ms</em> milliseconds. <em>ms</em> must be non-negative.
+The function returns 1, unless <em>ms</em> is negative, in which case
+it returns 0 EINVAL.
+</p>
+
+<p>
+<code> int tain_to_millisecs (tain_t const *a) </code> <br />
+If *<em>a</em> contains a non-negative relative time that fits into
+a 31-bit integer number of milliseconds, the function returns that
+number. Else it returns -1 EINVAL.
+</p>
+
+<h3> Time computations </h3>
+
+<p>
+<code> void tai_add (tai_t *t, tai_t const *t1, tai_t const *t2) </code> <br />
+Stores *<em>t1</em> + *<em>t2</em> into <em>t</em>. Of course, *<em>t1</em>
+and *<em>t2</em> must not both represent absolute times.
+</p>
+
+<p>
+<code> void tai_sub (tai_t *t, tai_t const *t1, tai_t const *t2) </code> <br />
+Stores *<em>t1</em> - *<em>t2</em> into <em>t</em>. Of course, *<em>t1</em>
+and *<em>t2</em> must be of the same type (relative or absolute), and
+*<em>t</em> will always be relative.
+</p>
+
+<p>
+<code> void tain_add (tain_t *a, tain_t const *a1, tain_t const *a2) <br />
+void tain_sub (tain_t *a, tain_t const *a1, tain_t const *a2) </code> <br />
+Same thing with <tt>tain_t</tt>.
+</p>
+
+<p>
+<code> void tain_addsec (tain_t *a, tain_t const *a1, int c) </code> <br />
+Adds <em>c</em> seconds to *<em>a1</em> and stores the result into <em>a</em>.
+<em>c</em> may be negative.
+</p>
+
+<p>
+<code> void tain_half (tain_t *a, tain_t const *b) </code> <br />
+Stores *<em>b</em>/2 into <em>a</em>. *<em>b</em> must be relative.
+</p>
+
+<h3> Comparing dates or durations </h3>
+
+<p>
+<code> int tai_less (tai_t const *t1, tai_t const *t2) <br />
+int tain_less (tain_t const *t1, tain_t const *t2) </code> <br />
+Those functions return nonzero iff *<em>t1</em> is lesser than *<em>t2</em>.
+*<em>t1</em> and *<em>t2</em> must be both relative, or both absolute.
+</p>
+
+<h3> Packing and unpacking </h3>
+
+<p>
+<code> void tai_pack (char *s, tai_t const *t) </code> <br />
+Marshals *<em>t</em> into the buffer <em>s</em> points to, which
+must be preallocated with at least TAI_PACK (8) characters. Afterwards,
+the buffer contains the
+<a href="http://cr.yp.to/libtai/tai64.html#tai64">external TAI64 format</a>
+representation of *<em>t</em>.
+</p>
+
+<p>
+<code> void tai_unpack (char const *s, tai_t *t) </code> <br />
+Unmarshals the
+<a href="http://cr.yp.to/libtai/tai64.html#tai64">external TAI64 format</a>
+label pointed to by <em>s</em> (at least TAI_PACK characters) and stores
+the result into <em>t</em>.
+</p>
+
+<p>
+<code> void tain_pack (char *s, tain_t const *a) <br />
+void tain_unpack (char const *s, tain_t *a) <br />
+void tain_pack (char *s, tain_t const *a) <br />
+void tain_unpack (char const *s, tain_t *a) </code> <br />
+Same thing with
+<a href="http://cr.yp.to/libtai/tai64.html#tai64n">external TAI64N format</a>,
+using TAIN_PACK (12) characters.
+</p>
+
+<h3> Formatting and scanning </h3>
+
+<p>
+<code> unsigned int tain_fmt (char *s, tain_t const *a) </code> <br />
+Writes into <em>s</em> an ASCII representation of *<em>a</em> in external
+TAI64N format. <em>s</em> must point to a preallocated buffer of at least
+TAIN_PACK*2 (24) characters. The function returns the number of bytes that
+have been written to <em>s</em> (24).
+</p>
+
+<p>
+<code> unsigned int tain_scan (char const *s, tain_t *a) </code> <br />
+Reads 24 characters from <em>s</em>; if those characters are a valid ASCII
+representation of the external TAI64N format of some time value, this value
+is stored into <em>a</em>, and 24 is returned. Else 0 is returned.
+</p>
+
+<a name="timestamp"><h3> Timestamping </h3></a>
+
+<p>
+ A <em>TAI64N timestamp</em> is a string of 25 characters: a single '@'
+character followed by the ASCII representation of the TAI64N external
+format of an absolute date.
+</p>
+
+<p>
+<code> unsigned int timestamp_fmt (char *s, tain_t const *a) </code> <br />
+Writes a TAI64N timestamp representing the absolute date *<em>a</em>
+into the 25 characters pointed to by <em>s</em>. Returns 25.
+</p>
+
+<p>
+<code> unsigned int timestamp_scan (char const *s, tain_t *a) </code> <br />
+Reads 25 characters at <em>s</em>. If those characters are a valid TAI64N
+timestamp, stores the absolute date in <em>a</em> and returns 25. Else,
+returns 0.
+</p>
+
+<p>
+<code> int timestamp (char *s) </code> <br />
+Writes the current time (read from the system clock) as a TAI64N timestamp
+into <em>s</em>. Returns 1 if it succeeds or 0 (and sets errno) if it fails.
+</p>
+
+<p>
+ TAI64N timestamps are an efficient, robust, and easy-to-use way of
+timestampping log lines. They're easy to recognize in automatic data
+parsers. Log files where every line starts with a TAI64N timestamp can
+be merged and alphanumerically sorted: the resulting file will be
+chronologically sorted.
+</p>
+
+<p>
+ The <a href="http://skarnet.org/software/s6/">s6</a> package
+provides tools to convert TAI64N timestamps into human-readable
+dates. Please do not embed human-readable dates in your log files,
+thus making parsing tools unnecessarily hard to write;
+use TAI64N timestamps instead, design tools that can parse them,
+and translate them to human-readable form at human analysis time.
+</p>
+
+</body>
+</html>
diff --git a/doc/libunixonacid/index.html b/doc/libunixonacid/index.html
new file mode 100644
index 0000000..81b024f
--- /dev/null
+++ b/doc/libunixonacid/index.html
@@ -0,0 +1,58 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the unixonacid library interface</title
+ <meta name="Description" content="skalibs: the unixonacid library interface" />
+ <meta name="Keywords" content="skalibs library unixonacid libunixonacid unixonacid.h" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>unixonacid</tt> library interface </h1>
+
+<p>
+<tt>libunixonacid</tt> provides higher-level interfaces to Unix
+concepts such as the filesystem - for instance, it provides a way to
+access several files atomically, be it for reading or for writing - or
+interprocess communication.
+</p>
+
+
+<h2> Compiling </h2>
+
+<ul>
+ <li> Use <tt>#include &lt;skalibs/unixonacid.h&gt;</tt> </li>
+</ul>
+
+<h2> Programming </h2>
+
+<p>
+ The <tt>skalibs/unixonacid.h</tt> header is actually a concatenation of other
+headers, every one of each declaring related structures, macros and
+functions.
+</p>
+
+<ul>
+ <li> <a href="unix-transactional.html">skalibs/unix-transactional.h</a>:
+transactional filesystem operations </li>
+ <li> <a href="unix-timed.html">skalibs/unix-timed.h</a>: timed synchronous
+IPC or network operations </li>
+ <li> <a href="unixmessage.html">skalibs/unixmessage.h</a>: safe
+asynchronous and synchronous message
+transmission between processes via Unix sockets, including fd-passing </li>
+ <li> <a href="kolbak.html">skalibs/kolbak.h</a>: simple callback management
+for asynchronous message transmission </li>
+ <li> <a href="skaclient.html">skalibs/skaclient.h</a>: higher-level
+client-server interface using messages </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/libunixonacid/kolbak.html b/doc/libunixonacid/kolbak.html
new file mode 100644
index 0000000..a7480e8
--- /dev/null
+++ b/doc/libunixonacid/kolbak.html
@@ -0,0 +1,40 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the kolbak library interface</title>
+ <meta name="Description" content="skalibs: the kolbak library interface" />
+ <meta name="Keywords" content="skalibs c kolbak library libunixonacid" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libunixonacid</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>kolbak</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/kolbak.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>kolbak</tt> implements simple queuing of callback functions to use when
+sending a message to a peer and expecting an answer, which will be handled
+by the callback function. The queue is a circular buffer.
+</p>
+
+<p>
+ FIXME: To be completed.
+</p>
+
+</body>
+</html>
diff --git a/doc/libunixonacid/skaclient.html b/doc/libunixonacid/skaclient.html
new file mode 100644
index 0000000..7deb38b
--- /dev/null
+++ b/doc/libunixonacid/skaclient.html
@@ -0,0 +1,34 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the skaclient library interface</title>
+ <meta name="Description" content="skalibs: the skaclient library interface" />
+ <meta name="Keywords" content="skalibs c skaclient library libunixonacid" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libunixonacid</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>skaclient</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/skaclient.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+FIXME: to be completed.
+</p>
+
+</body>
+</html>
diff --git a/doc/libunixonacid/unix-timed.html b/doc/libunixonacid/unix-timed.html
new file mode 100644
index 0000000..5261475
--- /dev/null
+++ b/doc/libunixonacid/unix-timed.html
@@ -0,0 +1,34 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the unix-timed library interface</title>
+ <meta name="Description" content="skalibs: the unix-timed library interface" />
+ <meta name="Keywords" content="skalibs c unix-timed library libunixonacid" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libunixonacid</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>unix-timed</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/unix-timed.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+FIXME: to be completed.
+</p>
+
+</body>
+</html>
diff --git a/doc/libunixonacid/unix-transactional.html b/doc/libunixonacid/unix-transactional.html
new file mode 100644
index 0000000..036d8cd
--- /dev/null
+++ b/doc/libunixonacid/unix-transactional.html
@@ -0,0 +1,34 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the unix-transactional library interface</title>
+ <meta name="Description" content="skalibs: the unix-transactional library interface" />
+ <meta name="Keywords" content="skalibs c unix-transactional library libunixonacid" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libunixonacid</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://www.skarnet.org/software/">Software</a><br />
+<a href="http://www.skarnet.org/">www.skarnet.org</a>
+</p>
+
+<h1> The <tt>unix-transactional</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/unix-transactional.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+FIXME: to be completed.
+</p>
+
+</body>
+</html>
diff --git a/doc/libunixonacid/unixmessage.html b/doc/libunixonacid/unixmessage.html
new file mode 100644
index 0000000..2a6c46d
--- /dev/null
+++ b/doc/libunixonacid/unixmessage.html
@@ -0,0 +1,40 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the unixmessage library interface</title>
+ <meta name="Description" content="skalibs: the unixmessage library interface" />
+ <meta name="Keywords" content="skalibs c unixmessage library libunixonacid" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libunixonacid</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>unixmessage</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/unixmessage.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>unixmessage</tt> implements message transmission over Unix domain sockets.
+Messages are made of standard untyped data (strings), but can also include file
+descriptors using fd-passing.
+</p>
+
+<p>
+ FIXME: To be completed.
+</p>
+
+</body>
+</html>
diff --git a/doc/license.html b/doc/license.html
new file mode 100644
index 0000000..21865c0
--- /dev/null
+++ b/doc/license.html
@@ -0,0 +1,82 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: license</title>
+ <meta name="Description" content="skalibs: license" />
+ <meta name="Keywords" content="skalibs license isc free documentation" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> skalibs license </h1>
+
+<h2> Source code </h2>
+
+<p>
+The skalibs source code from skalibs is released under the
+<a href="http://en.wikipedia.org/wiki/ISC_license">ISC license</a>,
+the text of which can be found in the COPYING file enclosed in the
+package.
+</p>
+
+<p>
+ The license has been chosen for its simplicity - it's short
+and to the point - and above all its permissivity. There is nothing
+legitimate you should not be able to do with the skalibs code. If
+the license somehow stands in the way, please let me know.
+</p>
+
+<h2> Documentation </h2>
+
+<p>
+ However, the skalibs <em>documentation</em>, which you are currently
+reading, and which is available in the <tt>doc/</tt> subdirectory of
+the official skalibs tarball, is <strong>not</strong> provided under
+the same license.
+</p>
+
+<p>
+ The license for the skalibs documentation is more restrictive than
+the license for the source code. Namely:
+</p>
+
+<ul>
+ <li> The exact same disclaimer applies. </li>
+ <li> You have the right to download, use and modify the documentation. </li>
+ <li> You have the right to distribute <em>unmodified</em> copies of the documentation. </li>
+ <li> You have the right to distribute <em>modified</em> copies of the documentation,
+provided that:
+ <ul>
+ <li> The contents and links (not necessarily the appearance) of this file,
+<a href="license.html">license.html</a>, are <em>left unmodified</em>; </li>
+ <li> On your documentation's <a href="index.html">main page</a>,
+you explicitly state that the documentation has been modified, and you
+set up a
+<a href="http://skarnet.org/software/skalibs/">link to the original
+skalibs site</a>, explicitly stating that the original software and
+documentation can be found there; </li>
+ <li> The parts of the documentation that you have modified are
+<em>unarguably and undeniably distinguishable</em> from the unmodified parts.
+You can, for instance, use a different text color, different background
+color, or different text font. </li>
+ </ul>
+ </li>
+</ul>
+
+<p>
+ <em>I am aware that the previous restrictions sound completely
+ridiculous while the official skalibs documentation is incomplete.
+As of 2.0.0.0, I'm not going to enforce those restrictions, but if you're
+going to provide documentation for skalibs, don't keep it to yourself,
+please send it to me instead. :-) </em>
+</p>
+
+</body>
+</html>
diff --git a/doc/upgrade.html b/doc/upgrade.html
new file mode 100644
index 0000000..70c14b9
--- /dev/null
+++ b/doc/upgrade.html
@@ -0,0 +1,34 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: how to upgrade</title>
+ <meta name="Description" content="skalibs: How to upgrade" />
+ <meta name="Keywords" content="skalibs installation upgrade" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> Upgrade incompatibilities: notes for developers </h1>
+
+<h2> From previous versions to 2.0.0.0 </h2>
+
+<ul>
+ <li> No compatibility is ensured. Most APIs haven't changed, but no guarantee
+is offered. </li>
+ <li> The most important change is probably the disparition of <tt>struct tai</tt>
+and <tt>struct taia</tt>, replaced with the <tt>tai_t</tt> and <tt>tain_t</tt>
+types. Attosecond precision has been removed - processor speed is almost capped now,
+and it looks like nanosecond precision will be enough for the foreseeable future. </li>
+ <li> Programs should now link with <tt>-lskarnet</tt> followed by the appropriate
+sysdeps links. </li>
+</ul>
+
+</body>
+</html>