summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--AUTHORS21
-rw-r--r--CHANGES260
-rw-r--r--COPYING13
-rw-r--r--INSTALL139
-rw-r--r--Makefile236
-rw-r--r--README26
-rw-r--r--README.macosx4
-rw-r--r--README.solaris12
-rwxr-xr-xconfigure590
-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
-rw-r--r--package/deps.mak756
-rw-r--r--package/info4
-rwxr-xr-xpatch-for-solaris17
-rw-r--r--src/etc/leapsecs.datbin0 -> 200 bytes
-rw-r--r--src/headers/error-addrinuse3
-rw-r--r--src/headers/error-already1
-rw-r--r--src/headers/error-footer2
-rw-r--r--src/headers/error-header12
-rw-r--r--src/headers/error-proto3
-rw-r--r--src/headers/gidstuff-167
-rw-r--r--src/headers/gidstuff-327
-rw-r--r--src/headers/gidstuff-647
-rw-r--r--src/headers/gidstuff-footer2
-rw-r--r--src/headers/gidstuff-header5
-rw-r--r--src/headers/ip46-footer10
-rw-r--r--src/headers/ip46-header34
-rw-r--r--src/headers/ip46-with24
-rw-r--r--src/headers/ip46-without28
-rw-r--r--src/headers/setgroups-footer2
-rw-r--r--src/headers/setgroups-header5
-rw-r--r--src/headers/setgroups-stub2
-rw-r--r--src/headers/uint-1634
-rw-r--r--src/headers/uint-3234
-rw-r--r--src/headers/uint-6434
-rw-r--r--src/headers/uint-footer10
-rw-r--r--src/headers/uint-header5
-rw-r--r--src/headers/uint16-bendian3
-rw-r--r--src/headers/uint16-footer40
-rw-r--r--src/headers/uint16-header9
-rw-r--r--src/headers/uint16-lendian3
-rw-r--r--src/headers/uint32-bendian3
-rw-r--r--src/headers/uint32-footer39
-rw-r--r--src/headers/uint32-header9
-rw-r--r--src/headers/uint32-inttypesh3
-rw-r--r--src/headers/uint32-lendian3
-rw-r--r--src/headers/uint32-noulong322
-rw-r--r--src/headers/uint32-stdinth3
-rw-r--r--src/headers/uint32-ulong322
-rw-r--r--src/headers/uint64-bendian3
-rw-r--r--src/headers/uint64-footer39
-rw-r--r--src/headers/uint64-header5
-rw-r--r--src/headers/uint64-lendian3
-rw-r--r--src/headers/uint64-noulong642
-rw-r--r--src/headers/uint64-stdinth3
-rw-r--r--src/headers/uint64-ulong641
-rw-r--r--src/headers/ulong-3232
-rw-r--r--src/headers/ulong-6432
-rw-r--r--src/headers/ulong-footer10
-rw-r--r--src/headers/ulong-header5
-rw-r--r--src/headers/ushort-1634
-rw-r--r--src/headers/ushort-3234
-rw-r--r--src/headers/ushort-footer10
-rw-r--r--src/headers/ushort-header5
-rw-r--r--src/include/skalibs/alloc.h16
-rw-r--r--src/include/skalibs/allreadwrite.h27
-rw-r--r--src/include/skalibs/avlnode.h44
-rw-r--r--src/include/skalibs/avltree.h55
-rw-r--r--src/include/skalibs/avltreen.h87
-rw-r--r--src/include/skalibs/biguint.h46
-rw-r--r--src/include/skalibs/bitarray.h33
-rw-r--r--src/include/skalibs/bufalloc.h36
-rw-r--r--src/include/skalibs/buffer.h134
-rw-r--r--src/include/skalibs/bytestr.h65
-rw-r--r--src/include/skalibs/cbuffer.h62
-rw-r--r--src/include/skalibs/cdb.h51
-rw-r--r--src/include/skalibs/cdb_make.h27
-rw-r--r--src/include/skalibs/datastruct.h12
-rw-r--r--src/include/skalibs/direntry.h13
-rw-r--r--src/include/skalibs/diuint.h15
-rw-r--r--src/include/skalibs/diuint32.h17
-rw-r--r--src/include/skalibs/djbtime.h70
-rw-r--r--src/include/skalibs/djbunix.h149
-rw-r--r--src/include/skalibs/env.h26
-rw-r--r--src/include/skalibs/envalloc.h15
-rw-r--r--src/include/skalibs/environ.h8
-rw-r--r--src/include/skalibs/fmtscan.h53
-rw-r--r--src/include/skalibs/functypes.h33
-rw-r--r--src/include/skalibs/gccattributes.h61
-rw-r--r--src/include/skalibs/genalloc.h35
-rw-r--r--src/include/skalibs/genset.h37
-rw-r--r--src/include/skalibs/gensetdyn.h40
-rw-r--r--src/include/skalibs/genwrite.h35
-rw-r--r--src/include/skalibs/getpeereid.h10
-rw-r--r--src/include/skalibs/iobuffer.h117
-rw-r--r--src/include/skalibs/iopause.h32
-rw-r--r--src/include/skalibs/kolbak.h32
-rw-r--r--src/include/skalibs/lolstdio.h30
-rw-r--r--src/include/skalibs/md5.h21
-rw-r--r--src/include/skalibs/mininetstring.h13
-rw-r--r--src/include/skalibs/netstring.h24
-rw-r--r--src/include/skalibs/nonposix.h58
-rw-r--r--src/include/skalibs/nsig.h13
-rw-r--r--src/include/skalibs/random.h33
-rw-r--r--src/include/skalibs/randomegd.h10
-rw-r--r--src/include/skalibs/rc4.h19
-rw-r--r--src/include/skalibs/rrandom.h36
-rw-r--r--src/include/skalibs/segfault.h11
-rw-r--r--src/include/skalibs/selfpipe.h17
-rw-r--r--src/include/skalibs/sgetopt.h46
-rw-r--r--src/include/skalibs/sha1.h22
-rw-r--r--src/include/skalibs/sha256.h29
-rw-r--r--src/include/skalibs/sig.h61
-rw-r--r--src/include/skalibs/siovec.h29
-rw-r--r--src/include/skalibs/skaclient.h115
-rw-r--r--src/include/skalibs/skalibs.h19
-rw-r--r--src/include/skalibs/skamisc.h29
-rw-r--r--src/include/skalibs/socket.h122
-rw-r--r--src/include/skalibs/stdcrypto.h11
-rw-r--r--src/include/skalibs/stddjb.h60
-rw-r--r--src/include/skalibs/stralloc.h40
-rw-r--r--src/include/skalibs/strerr.h139
-rw-r--r--src/include/skalibs/strerr2.h267
-rw-r--r--src/include/skalibs/surf.h29
-rw-r--r--src/include/skalibs/tai.h140
-rw-r--r--src/include/skalibs/unirandom.h57
-rw-r--r--src/include/skalibs/unirandomdev.h19
-rw-r--r--src/include/skalibs/unirandomegd.h17
-rw-r--r--src/include/skalibs/unisurf.h16
-rw-r--r--src/include/skalibs/unix-timed.h36
-rw-r--r--src/include/skalibs/unix-transactional.h59
-rw-r--r--src/include/skalibs/unixmessage.h103
-rw-r--r--src/include/skalibs/unixonacid.h12
-rw-r--r--src/include/skalibs/webipc.h60
-rw-r--r--src/libbiguint/bu_addc.c22
-rw-r--r--src/libbiguint/bu_addmod.c11
-rw-r--r--src/libbiguint/bu_cmp.c18
-rw-r--r--src/libbiguint/bu_copy.c21
-rw-r--r--src/libbiguint/bu_copy_internal.c9
-rw-r--r--src/libbiguint/bu_div.c23
-rw-r--r--src/libbiguint/bu_div_internal.c46
-rw-r--r--src/libbiguint/bu_divmod.c32
-rw-r--r--src/libbiguint/bu_divmod_internal.c37
-rw-r--r--src/libbiguint/bu_fmt.c19
-rw-r--r--src/libbiguint/bu_gcd.c33
-rw-r--r--src/libbiguint/bu_invmod.c12
-rw-r--r--src/libbiguint/bu_len.c10
-rw-r--r--src/libbiguint/bu_mod.c10
-rw-r--r--src/libbiguint/bu_mul.c32
-rw-r--r--src/libbiguint/bu_mulmod.c16
-rw-r--r--src/libbiguint/bu_pack.c9
-rw-r--r--src/libbiguint/bu_pack_big.c10
-rw-r--r--src/libbiguint/bu_scan.c18
-rw-r--r--src/libbiguint/bu_scan_internal.c21
-rw-r--r--src/libbiguint/bu_scanlen.c12
-rw-r--r--src/libbiguint/bu_slbc.c17
-rw-r--r--src/libbiguint/bu_srbc.c15
-rw-r--r--src/libbiguint/bu_subc.c22
-rw-r--r--src/libbiguint/bu_submod.c12
-rw-r--r--src/libbiguint/bu_unpack.c9
-rw-r--r--src/libbiguint/bu_unpack_big.c10
-rw-r--r--src/libbiguint/bu_zero.c9
-rw-r--r--src/libdatastruct/avlnode-internal.h15
-rw-r--r--src/libdatastruct/avlnode_delete.c72
-rw-r--r--src/libdatastruct/avlnode_doublerotate.c19
-rw-r--r--src/libdatastruct/avlnode_extreme.c12
-rw-r--r--src/libdatastruct/avlnode_extremenode.c10
-rw-r--r--src/libdatastruct/avlnode_height.c15
-rw-r--r--src/libdatastruct/avlnode_insertnode.c42
-rw-r--r--src/libdatastruct/avlnode_iter.c26
-rw-r--r--src/libdatastruct/avlnode_rotate.c15
-rw-r--r--src/libdatastruct/avlnode_search.c12
-rw-r--r--src/libdatastruct/avlnode_searchnode.c16
-rw-r--r--src/libdatastruct/avlnode_zero.c5
-rw-r--r--src/libdatastruct/avltree_delete.c16
-rw-r--r--src/libdatastruct/avltree_free.c10
-rw-r--r--src/libdatastruct/avltree_init.c16
-rw-r--r--src/libdatastruct/avltree_insert.c11
-rw-r--r--src/libdatastruct/avltree_newnode.c18
-rw-r--r--src/libdatastruct/avltree_zero.c5
-rw-r--r--src/libdatastruct/avltreen_delete.c16
-rw-r--r--src/libdatastruct/avltreen_init.c15
-rw-r--r--src/libdatastruct/avltreen_insert.c11
-rw-r--r--src/libdatastruct/avltreen_newnode.c18
-rw-r--r--src/libdatastruct/genset.c27
-rw-r--r--src/libdatastruct/genset_iter.c19
-rw-r--r--src/libdatastruct/gensetdyn_delete.c11
-rw-r--r--src/libdatastruct/gensetdyn_free.c12
-rw-r--r--src/libdatastruct/gensetdyn_init.c15
-rw-r--r--src/libdatastruct/gensetdyn_iter.c26
-rw-r--r--src/libdatastruct/gensetdyn_new.c14
-rw-r--r--src/libdatastruct/gensetdyn_ready.c26
-rw-r--r--src/libdatastruct/gensetdyn_zero.c5
-rw-r--r--src/librandom/badrandom_char.c13
-rw-r--r--src/librandom/badrandom_finish.c12
-rw-r--r--src/librandom/badrandom_here.c40
-rw-r--r--src/librandom/badrandom_init.c10
-rw-r--r--src/librandom/badrandom_int.c12
-rw-r--r--src/librandom/badrandom_string.c12
-rw-r--r--src/librandom/goodrandom_char.c13
-rw-r--r--src/librandom/goodrandom_finish.c12
-rw-r--r--src/librandom/goodrandom_here.c40
-rw-r--r--src/librandom/goodrandom_init.c10
-rw-r--r--src/librandom/goodrandom_int.c12
-rw-r--r--src/librandom/goodrandom_string.c12
-rw-r--r--src/librandom/random-internal.h20
-rw-r--r--src/librandom/random_mask2.c35
-rw-r--r--src/librandom/random_name.c13
-rw-r--r--src/librandom/random_sauniquename.c25
-rw-r--r--src/librandom/random_unsort.c17
-rw-r--r--src/librandom/randomegd_open.c20
-rw-r--r--src/librandom/randomegd_readb.c27
-rw-r--r--src/librandom/randomegd_readnb.c28
-rw-r--r--src/librandom/rrandom_add.c13
-rw-r--r--src/librandom/rrandom_finish.c14
-rw-r--r--src/librandom/rrandom_name.c13
-rw-r--r--src/librandom/rrandom_read.c21
-rw-r--r--src/librandom/rrandom_readint.c24
-rw-r--r--src/librandom/surf.c54
-rw-r--r--src/librandom/surf_autoinit.c10
-rw-r--r--src/librandom/surf_here.c8
-rw-r--r--src/librandom/surf_init.c10
-rw-r--r--src/librandom/surf_makeseed.c35
-rw-r--r--src/librandom/surf_sinit.c13
-rw-r--r--src/librandom/unidevrandom.c38
-rw-r--r--src/librandom/unidevurandom.c38
-rw-r--r--src/librandom/unihasegd.c38
-rw-r--r--src/librandom/unirandom_finish.c12
-rw-r--r--src/librandom/unirandom_init.c12
-rw-r--r--src/librandom/unirandom_readb.c10
-rw-r--r--src/librandom/unirandom_readnb.c10
-rw-r--r--src/librandom/unirandom_register.c16
-rw-r--r--src/librandom/unirandomdev.c50
-rw-r--r--src/librandom/unirandomegd.c37
-rw-r--r--src/librandom/unisurf.c23
-rw-r--r--src/librandom/unisurf_init.c18
-rw-r--r--src/libstdcrypto/INCLUDE5
-rw-r--r--src/libstdcrypto/Makefile7
-rw-r--r--src/libstdcrypto/md5-internal.h11
-rw-r--r--src/libstdcrypto/md5_final.c30
-rw-r--r--src/libstdcrypto/md5_init.c13
-rw-r--r--src/libstdcrypto/md5_transform.c91
-rw-r--r--src/libstdcrypto/md5_update.c37
-rw-r--r--src/libstdcrypto/rc4.c20
-rw-r--r--src/libstdcrypto/rc4_init.c26
-rw-r--r--src/libstdcrypto/sha1-internal.h12
-rw-r--r--src/libstdcrypto/sha1_feed.c24
-rw-r--r--src/libstdcrypto/sha1_final.c18
-rw-r--r--src/libstdcrypto/sha1_init.c16
-rw-r--r--src/libstdcrypto/sha1_transform.c42
-rw-r--r--src/libstdcrypto/sha1_update.c10
-rw-r--r--src/libstdcrypto/sha256-internal.h12
-rw-r--r--src/libstdcrypto/sha256_feed.c23
-rw-r--r--src/libstdcrypto/sha256_final.c31
-rw-r--r--src/libstdcrypto/sha256_init.c9
-rw-r--r--src/libstdcrypto/sha256_transform.c53
-rw-r--r--src/libstdcrypto/sha256_update.c10
-rw-r--r--src/libstddjb/absolutepath.c12
-rw-r--r--src/libstddjb/absolutepath_tmp.c62
-rw-r--r--src/libstddjb/alloc-internal.h21
-rw-r--r--src/libstddjb/alloc.c49
-rw-r--r--src/libstddjb/alloc_0.c13
-rw-r--r--src/libstddjb/allread.c8
-rw-r--r--src/libstddjb/allreadwrite.c19
-rw-r--r--src/libstddjb/allwrite.c8
-rw-r--r--src/libstddjb/baprintf.c15
-rw-r--r--src/libstddjb/basename.c19
-rw-r--r--src/libstddjb/bitarray_and.c10
-rw-r--r--src/libstddjb/bitarray_clearsetn.c24
-rw-r--r--src/libstddjb/bitarray_firstclear.c14
-rw-r--r--src/libstddjb/bitarray_firstset.c14
-rw-r--r--src/libstddjb/bitarray_not.c18
-rw-r--r--src/libstddjb/bitarray_or.c10
-rw-r--r--src/libstddjb/bitarray_testandpoke.c11
-rw-r--r--src/libstddjb/bitarray_xor.c10
-rw-r--r--src/libstddjb/bprintf.c15
-rw-r--r--src/libstddjb/bufalloc_1.c9
-rw-r--r--src/libstddjb/bufalloc_2.c9
-rw-r--r--src/libstddjb/bufalloc_clean.c14
-rw-r--r--src/libstddjb/bufalloc_flush.c11
-rw-r--r--src/libstddjb/bufalloc_getfd.c8
-rw-r--r--src/libstddjb/bufalloc_getlen.c8
-rw-r--r--src/libstddjb/bufalloc_init.c12
-rw-r--r--src/libstddjb/buffer_0.c8
-rw-r--r--src/libstddjb/buffer_0f1.c8
-rw-r--r--src/libstddjb/buffer_0small.c8
-rw-r--r--src/libstddjb/buffer_1.c8
-rw-r--r--src/libstddjb/buffer_1small.c8
-rw-r--r--src/libstddjb/buffer_2.c8
-rw-r--r--src/libstddjb/buffer_fill.c17
-rw-r--r--src/libstddjb/buffer_flush.c20
-rw-r--r--src/libstddjb/buffer_flush1read.c10
-rw-r--r--src/libstddjb/buffer_get.c12
-rw-r--r--src/libstddjb/buffer_getall.c18
-rw-r--r--src/libstddjb/buffer_getallnf.c15
-rw-r--r--src/libstddjb/buffer_getfd.c8
-rw-r--r--src/libstddjb/buffer_getlen.c8
-rw-r--r--src/libstddjb/buffer_getv.c15
-rw-r--r--src/libstddjb/buffer_getvall.c18
-rw-r--r--src/libstddjb/buffer_getvallnf.c16
-rw-r--r--src/libstddjb/buffer_init.c13
-rw-r--r--src/libstddjb/buffer_put.c10
-rw-r--r--src/libstddjb/buffer_putall.c16
-rw-r--r--src/libstddjb/buffer_putallnf.c15
-rw-r--r--src/libstddjb/buffer_putflush.c11
-rw-r--r--src/libstddjb/buffer_putv.c12
-rw-r--r--src/libstddjb/buffer_putvall.c15
-rw-r--r--src/libstddjb/buffer_putvallnf.c15
-rw-r--r--src/libstddjb/buffer_putvflush.c12
-rw-r--r--src/libstddjb/buffer_read.c15
-rw-r--r--src/libstddjb/buffer_write.c15
-rw-r--r--src/libstddjb/byte_chr.c33
-rw-r--r--src/libstddjb/byte_copy.c14
-rw-r--r--src/libstddjb/byte_count.c10
-rw-r--r--src/libstddjb/byte_cr.c22
-rw-r--r--src/libstddjb/byte_diff.c22
-rw-r--r--src/libstddjb/byte_in.c14
-rw-r--r--src/libstddjb/byte_rchr.c12
-rw-r--r--src/libstddjb/byte_zero.c15
-rw-r--r--src/libstddjb/case_diffb.c18
-rw-r--r--src/libstddjb/case_diffs.c18
-rw-r--r--src/libstddjb/case_lowerb.c13
-rw-r--r--src/libstddjb/case_lowers.c13
-rw-r--r--src/libstddjb/case_startb.c9
-rw-r--r--src/libstddjb/case_str.c32
-rw-r--r--src/libstddjb/case_upperb.c13
-rw-r--r--src/libstddjb/case_uppers.c13
-rw-r--r--src/libstddjb/cbuffer_get.c11
-rw-r--r--src/libstddjb/cbuffer_getv.c11
-rw-r--r--src/libstddjb/cbuffer_init.c13
-rw-r--r--src/libstddjb/cbuffer_put.c11
-rw-r--r--src/libstddjb/cbuffer_putv.c11
-rw-r--r--src/libstddjb/cbuffer_rpeek.c21
-rw-r--r--src/libstddjb/cbuffer_rseek.c10
-rw-r--r--src/libstddjb/cbuffer_unget.c10
-rw-r--r--src/libstddjb/cbuffer_unput.c10
-rw-r--r--src/libstddjb/cbuffer_wpeek.c22
-rw-r--r--src/libstddjb/cbuffer_wseek.c10
-rw-r--r--src/libstddjb/cdb_findnext.c67
-rw-r--r--src/libstddjb/cdb_free.c11
-rw-r--r--src/libstddjb/cdb_hash.c17
-rw-r--r--src/libstddjb/cdb_init_map.c23
-rw-r--r--src/libstddjb/cdb_make.c145
-rw-r--r--src/libstddjb/cdb_mapfile.c20
-rw-r--r--src/libstddjb/cdb_nextkey.c23
-rw-r--r--src/libstddjb/cdb_read.c24
-rw-r--r--src/libstddjb/cdb_successor.c17
-rw-r--r--src/libstddjb/cdb_zero.c5
-rw-r--r--src/libstddjb/child_spawn.c228
-rw-r--r--src/libstddjb/child_spawn0.c73
-rw-r--r--src/libstddjb/child_spawn1.c115
-rw-r--r--src/libstddjb/coe.c11
-rw-r--r--src/libstddjb/deepsleepuntil.c10
-rw-r--r--src/libstddjb/dir_close.c14
-rw-r--r--src/libstddjb/dirname.c19
-rw-r--r--src/libstddjb/djbtime-internal.h23
-rw-r--r--src/libstddjb/doublefork.c53
-rw-r--r--src/libstddjb/env_addmodif.c18
-rw-r--r--src/libstddjb/env_get.c9
-rw-r--r--src/libstddjb/env_get2.c18
-rw-r--r--src/libstddjb/env_len.c10
-rw-r--r--src/libstddjb/env_make.c16
-rw-r--r--src/libstddjb/env_merge.c25
-rw-r--r--src/libstddjb/env_string.c19
-rw-r--r--src/libstddjb/envalloc_0.c10
-rw-r--r--src/libstddjb/envalloc_make.c18
-rw-r--r--src/libstddjb/envalloc_merge.c15
-rw-r--r--src/libstddjb/envalloc_uniq.c31
-rw-r--r--src/libstddjb/envdir.c84
-rw-r--r--src/libstddjb/error_str.c277
-rw-r--r--src/libstddjb/error_temp.c78
-rw-r--r--src/libstddjb/execvep.c38
-rw-r--r--src/libstddjb/fd_cat.c25
-rw-r--r--src/libstddjb/fd_catn.c42
-rw-r--r--src/libstddjb/fd_chdir.c14
-rw-r--r--src/libstddjb/fd_chmod.c17
-rw-r--r--src/libstddjb/fd_chown.c15
-rw-r--r--src/libstddjb/fd_close.c15
-rw-r--r--src/libstddjb/fd_copy.c15
-rw-r--r--src/libstddjb/fd_copy2.c17
-rw-r--r--src/libstddjb/fd_ensure_open.c25
-rw-r--r--src/libstddjb/fd_move.c15
-rw-r--r--src/libstddjb/fd_move2.c37
-rw-r--r--src/libstddjb/fd_read.c13
-rw-r--r--src/libstddjb/fd_readv.c14
-rw-r--r--src/libstddjb/fd_recv.c14
-rw-r--r--src/libstddjb/fd_select.c14
-rw-r--r--src/libstddjb/fd_send.c14
-rw-r--r--src/libstddjb/fd_sync.c14
-rw-r--r--src/libstddjb/fd_write.c13
-rw-r--r--src/libstddjb/fd_writev.c14
-rw-r--r--src/libstddjb/fmtscan-internal.h105
-rw-r--r--src/libstddjb/fmtscan_asc.c9
-rw-r--r--src/libstddjb/fmtscan_num.c16
-rw-r--r--src/libstddjb/genalloc_deepfree.c12
-rw-r--r--src/libstddjb/genwrite_flush_bufalloc.c10
-rw-r--r--src/libstddjb/genwrite_flush_buffer.c10
-rw-r--r--src/libstddjb/genwrite_flush_stralloc.c9
-rw-r--r--src/libstddjb/genwrite_put_bufalloc.c10
-rw-r--r--src/libstddjb/genwrite_put_buffer.c10
-rw-r--r--src/libstddjb/genwrite_put_stralloc.c10
-rw-r--r--src/libstddjb/genwrite_stderr.c6
-rw-r--r--src/libstddjb/genwrite_stdout.c6
-rw-r--r--src/libstddjb/getlnmax.c28
-rw-r--r--src/libstddjb/getlnmaxsep.c28
-rw-r--r--src/libstddjb/getpeereid.c68
-rw-r--r--src/libstddjb/int_scan.c6
-rw-r--r--src/libstddjb/iobuffer_fill.c14
-rw-r--r--src/libstddjb/iobuffer_flush.c14
-rw-r--r--src/libstddjb/iobuffer_init.c17
-rw-r--r--src/libstddjb/iobuffer_kfromu.c41
-rw-r--r--src/libstddjb/iobuffer_salvage.c19
-rw-r--r--src/libstddjb/iobuffer_ufromk.c39
-rw-r--r--src/libstddjb/iobufferk_fill.c49
-rw-r--r--src/libstddjb/iobufferk_finish.c50
-rw-r--r--src/libstddjb/iobufferk_flush.c61
-rw-r--r--src/libstddjb/iobufferk_init.c78
-rw-r--r--src/libstddjb/iobufferk_isworking.c48
-rw-r--r--src/libstddjb/iobufferk_nosys.c10
-rw-r--r--src/libstddjb/iobufferu_fill.c11
-rw-r--r--src/libstddjb/iobufferu_finish.c9
-rw-r--r--src/libstddjb/iobufferu_flush.c11
-rw-r--r--src/libstddjb/iobufferu_init.c15
-rw-r--r--src/libstddjb/iopause.c24
-rw-r--r--src/libstddjb/iopause_poll.c19
-rw-r--r--src/libstddjb/iopause_ppoll.c44
-rw-r--r--src/libstddjb/iopause_select.c63
-rw-r--r--src/libstddjb/iopause_stamp.c22
-rw-r--r--src/libstddjb/iovec_from_siovec.c14
-rw-r--r--src/libstddjb/ip46_scan.c18
-rw-r--r--src/libstddjb/ip46_scanlist.c28
-rw-r--r--src/libstddjb/ip4_fmt.c20
-rw-r--r--src/libstddjb/ip4_fmtu32.c11
-rw-r--r--src/libstddjb/ip4_scan.c23
-rw-r--r--src/libstddjb/ip4_scanlist.c18
-rw-r--r--src/libstddjb/ip4_scanlist_u32.c19
-rw-r--r--src/libstddjb/ip4_scanu32.c12
-rw-r--r--src/libstddjb/ip6_fmt.c79
-rw-r--r--src/libstddjb/ip6_scan.c35
-rw-r--r--src/libstddjb/ip6_scanlist.c20
-rw-r--r--src/libstddjb/ipc_accept.c48
-rw-r--r--src/libstddjb/ipc_bind.c20
-rw-r--r--src/libstddjb/ipc_bind_reuse.c14
-rw-r--r--src/libstddjb/ipc_connect.c25
-rw-r--r--src/libstddjb/ipc_connected.c20
-rw-r--r--src/libstddjb/ipc_dgram.c11
-rw-r--r--src/libstddjb/ipc_eid.c15
-rw-r--r--src/libstddjb/ipc_listen.c10
-rw-r--r--src/libstddjb/ipc_local.c23
-rw-r--r--src/libstddjb/ipc_pair.c11
-rw-r--r--src/libstddjb/ipc_recv.c33
-rw-r--r--src/libstddjb/ipc_send.c20
-rw-r--r--src/libstddjb/ipc_stream.c11
-rw-r--r--src/libstddjb/ipc_timed_connect.c26
-rw-r--r--src/libstddjb/leapsecs_add.c19
-rw-r--r--src/libstddjb/leapsecs_here.c9
-rw-r--r--src/libstddjb/leapsecs_init.c34
-rw-r--r--src/libstddjb/leapsecs_sub.c22
-rw-r--r--src/libstddjb/localtm_fmt.c17
-rw-r--r--src/libstddjb/localtm_from_ltm64.c23
-rw-r--r--src/libstddjb/localtm_from_sysclock.c12
-rw-r--r--src/libstddjb/localtm_from_tai.c14
-rw-r--r--src/libstddjb/localtm_from_utc.c12
-rw-r--r--src/libstddjb/localtm_scan.c40
-rw-r--r--src/libstddjb/localtmn_fmt.c12
-rw-r--r--src/libstddjb/localtmn_from_sysclock.c13
-rw-r--r--src/libstddjb/localtmn_from_tain.c13
-rw-r--r--src/libstddjb/localtmn_scan.c21
-rw-r--r--src/libstddjb/lock_ex.c37
-rw-r--r--src/libstddjb/lock_exnb.c38
-rw-r--r--src/libstddjb/lock_sh.c37
-rw-r--r--src/libstddjb/lock_shnb.c38
-rw-r--r--src/libstddjb/lock_un.c37
-rw-r--r--src/libstddjb/lolprintf.c15
-rw-r--r--src/libstddjb/long_fmt.c10
-rw-r--r--src/libstddjb/long_scan.c6
-rw-r--r--src/libstddjb/ltm64_from_localtm.c17
-rw-r--r--src/libstddjb/ltm64_from_sysclock.c24
-rw-r--r--src/libstddjb/ltm64_from_tai.c23
-rw-r--r--src/libstddjb/ltm64_from_utc.c23
-rw-r--r--src/libstddjb/mininetstring_read.c44
-rw-r--r--src/libstddjb/mininetstring_write.c37
-rw-r--r--src/libstddjb/ndelay_off.c11
-rw-r--r--src/libstddjb/ndelay_on.c11
-rw-r--r--src/libstddjb/netstring_append.c19
-rw-r--r--src/libstddjb/netstring_appendv.c27
-rw-r--r--src/libstddjb/netstring_decode.c22
-rw-r--r--src/libstddjb/netstring_encode.c17
-rw-r--r--src/libstddjb/netstring_get.c54
-rw-r--r--src/libstddjb/netstring_put.c36
-rw-r--r--src/libstddjb/ntp_from_tain.c23
-rw-r--r--src/libstddjb/open2.c15
-rw-r--r--src/libstddjb/open3.c15
-rw-r--r--src/libstddjb/open_append.c10
-rw-r--r--src/libstddjb/open_create.c10
-rw-r--r--src/libstddjb/open_excl.c10
-rw-r--r--src/libstddjb/open_read.c10
-rw-r--r--src/libstddjb/open_readb.c15
-rw-r--r--src/libstddjb/open_trunc.c10
-rw-r--r--src/libstddjb/open_write.c10
-rw-r--r--src/libstddjb/openreadclose.c21
-rw-r--r--src/libstddjb/openreadfileclose.c37
-rw-r--r--src/libstddjb/openreadnclose.c21
-rw-r--r--src/libstddjb/openslurpclose.c18
-rw-r--r--src/libstddjb/openwritenclose_suffix.c29
-rw-r--r--src/libstddjb/openwritenclose_unsafe.c32
-rw-r--r--src/libstddjb/pathexec.c12
-rw-r--r--src/libstddjb/pathexec0.c12
-rw-r--r--src/libstddjb/pathexec0_run.c10
-rw-r--r--src/libstddjb/pathexec_fromenv.c17
-rw-r--r--src/libstddjb/pathexec_r.c8
-rw-r--r--src/libstddjb/pathexec_r_name.c13
-rw-r--r--src/libstddjb/pathexec_run.c12
-rw-r--r--src/libstddjb/pipe_internal.c45
-rw-r--r--src/libstddjb/prog.c7
-rw-r--r--src/libstddjb/prot.c19
-rw-r--r--src/libstddjb/prot_grps.c17
-rw-r--r--src/libstddjb/prot_readgroups.c28
-rw-r--r--src/libstddjb/realpath.c11
-rw-r--r--src/libstddjb/realpath_tmp.c26
-rw-r--r--src/libstddjb/rm_rf.c11
-rw-r--r--src/libstddjb/rm_rf_in_tmp.c93
-rw-r--r--src/libstddjb/rm_rf_tmp.c18
-rw-r--r--src/libstddjb/rmstar.c11
-rw-r--r--src/libstddjb/sabasename.c17
-rw-r--r--src/libstddjb/sadirname.c18
-rw-r--r--src/libstddjb/sagetcwd.c27
-rw-r--r--src/libstddjb/sagethostname.c27
-rw-r--r--src/libstddjb/sanitize_read.c11
-rw-r--r--src/libstddjb/sareadlink.c27
-rw-r--r--src/libstddjb/satmp.c6
-rw-r--r--src/libstddjb/sauniquename.c28
-rw-r--r--src/libstddjb/seek_cur.c10
-rw-r--r--src/libstddjb/seek_set.c13
-rw-r--r--src/libstddjb/selfpipe-internal.h28
-rw-r--r--src/libstddjb/selfpipe_finish.c35
-rw-r--r--src/libstddjb/selfpipe_init.c27
-rw-r--r--src/libstddjb/selfpipe_internal.c31
-rw-r--r--src/libstddjb/selfpipe_read.c31
-rw-r--r--src/libstddjb/selfpipe_trap.c51
-rw-r--r--src/libstddjb/selfpipe_trapset.c64
-rw-r--r--src/libstddjb/selfpipe_untrap.c54
-rw-r--r--src/libstddjb/sgetopt.c24
-rw-r--r--src/libstddjb/short_scan.c6
-rw-r--r--src/libstddjb/sig.c18
-rw-r--r--src/libstddjb/sig_block.c12
-rw-r--r--src/libstddjb/sig_blocknone.c11
-rw-r--r--src/libstddjb/sig_blockset.c9
-rw-r--r--src/libstddjb/sig_catch.c11
-rw-r--r--src/libstddjb/sig_pause.c11
-rw-r--r--src/libstddjb/sig_push.c11
-rw-r--r--src/libstddjb/sig_restoreto.c17
-rw-r--r--src/libstddjb/sig_shield.c17
-rw-r--r--src/libstddjb/sig_stack.c29
-rw-r--r--src/libstddjb/sig_unblock.c12
-rw-r--r--src/libstddjb/sig_unshield.c17
-rw-r--r--src/libstddjb/sigfpe.c9
-rw-r--r--src/libstddjb/sigsegv.c9
-rw-r--r--src/libstddjb/siovec_bytechr.c17
-rw-r--r--src/libstddjb/siovec_bytein.c17
-rw-r--r--src/libstddjb/siovec_deal.c24
-rw-r--r--src/libstddjb/siovec_from_iovec.c14
-rw-r--r--src/libstddjb/siovec_gather.c18
-rw-r--r--src/libstddjb/siovec_len.c10
-rw-r--r--src/libstddjb/siovec_scatter.c18
-rw-r--r--src/libstddjb/siovec_seek.c25
-rw-r--r--src/libstddjb/skagetln.c27
-rw-r--r--src/libstddjb/skagetlnsep.c27
-rw-r--r--src/libstddjb/skasig_dfl.c7
-rw-r--r--src/libstddjb/skasigaction.c24
-rw-r--r--src/libstddjb/slurp.c31
-rw-r--r--src/libstddjb/socket_accept4.c39
-rw-r--r--src/libstddjb/socket_accept4_u32.c13
-rw-r--r--src/libstddjb/socket_accept6.c55
-rw-r--r--src/libstddjb/socket_bind4.c19
-rw-r--r--src/libstddjb/socket_bind4r.c13
-rw-r--r--src/libstddjb/socket_bind6.c34
-rw-r--r--src/libstddjb/socket_bind6r.c13
-rw-r--r--src/libstddjb/socket_conn4.c24
-rw-r--r--src/libstddjb/socket_conn4_u32.c12
-rw-r--r--src/libstddjb/socket_conn6.c38
-rw-r--r--src/libstddjb/socket_connected.c20
-rw-r--r--src/libstddjb/socket_deadlineconnstamp4.c14
-rw-r--r--src/libstddjb/socket_deadlineconnstamp46.c15
-rw-r--r--src/libstddjb/socket_deadlineconnstamp4_u32.c13
-rw-r--r--src/libstddjb/socket_deadlineconnstamp6.c14
-rw-r--r--src/libstddjb/socket_delay.c13
-rw-r--r--src/libstddjb/socket_internal.c33
-rw-r--r--src/libstddjb/socket_ioloop.c30
-rw-r--r--src/libstddjb/socket_ioloop_send4.c8
-rw-r--r--src/libstddjb/socket_ioloop_send6.c8
-rw-r--r--src/libstddjb/socket_local4.c20
-rw-r--r--src/libstddjb/socket_local46.c36
-rw-r--r--src/libstddjb/socket_local6.c37
-rw-r--r--src/libstddjb/socket_recv4.c22
-rw-r--r--src/libstddjb/socket_recv6.c39
-rw-r--r--src/libstddjb/socket_remote4.c20
-rw-r--r--src/libstddjb/socket_remote46.c36
-rw-r--r--src/libstddjb/socket_remote6.c36
-rw-r--r--src/libstddjb/socket_send4.c22
-rw-r--r--src/libstddjb/socket_send6.c39
-rw-r--r--src/libstddjb/socket_tcp4.c11
-rw-r--r--src/libstddjb/socket_tcp6.c38
-rw-r--r--src/libstddjb/socket_timeoutconn.c13
-rw-r--r--src/libstddjb/socket_tryr.c14
-rw-r--r--src/libstddjb/socket_udp4.c11
-rw-r--r--src/libstddjb/socket_udp6.c38
-rw-r--r--src/libstddjb/socket_waitconn.c25
-rw-r--r--src/libstddjb/socketpair_internal.c56
-rw-r--r--src/libstddjb/stamp.c7
-rw-r--r--src/libstddjb/str_chr.c33
-rw-r--r--src/libstddjb/str_cpy.c16
-rw-r--r--src/libstddjb/str_diff.c24
-rw-r--r--src/libstddjb/str_diffn.c19
-rw-r--r--src/libstddjb/str_fmt.c9
-rw-r--r--src/libstddjb/str_len.c21
-rw-r--r--src/libstddjb/str_rchr.c28
-rw-r--r--src/libstddjb/str_start.c16
-rw-r--r--src/libstddjb/str_strn.c36
-rw-r--r--src/libstddjb/stralloc_append.c8
-rw-r--r--src/libstddjb/stralloc_catb.c12
-rw-r--r--src/libstddjb/stralloc_catv.c21
-rw-r--r--src/libstddjb/stralloc_copyb.c12
-rw-r--r--src/libstddjb/stralloc_free.c10
-rw-r--r--src/libstddjb/stralloc_insertb.c15
-rw-r--r--src/libstddjb/stralloc_ready_tuned.c25
-rw-r--r--src/libstddjb/stralloc_reverse.c15
-rw-r--r--src/libstddjb/stralloc_reverse_blocks.c17
-rw-r--r--src/libstddjb/stralloc_shrink.c14
-rw-r--r--src/libstddjb/stralloc_zero.c5
-rw-r--r--src/libstddjb/strerr.c35
-rw-r--r--src/libstddjb/strerr_sys.c22
-rw-r--r--src/libstddjb/string_format.c33
-rw-r--r--src/libstddjb/string_quote.c17
-rw-r--r--src/libstddjb/string_quote_nodelim.c9
-rw-r--r--src/libstddjb/string_quote_nodelim_mustquote.c62
-rw-r--r--src/libstddjb/string_unquote.c20
-rw-r--r--src/libstddjb/string_unquote_nodelim.c11
-rw-r--r--src/libstddjb/string_unquote_withdelim.c60
-rw-r--r--src/libstddjb/strn_fmt.c21
-rw-r--r--src/libstddjb/subgetopt.c63
-rw-r--r--src/libstddjb/subgetopt_here.c7
-rw-r--r--src/libstddjb/sysclock_from_localtm.c15
-rw-r--r--src/libstddjb/sysclock_from_localtmn.c13
-rw-r--r--src/libstddjb/sysclock_from_ltm64.c26
-rw-r--r--src/libstddjb/sysclock_from_tai.c23
-rw-r--r--src/libstddjb/sysclock_from_utc.c27
-rw-r--r--src/libstddjb/sysclock_get.c42
-rw-r--r--src/libstddjb/sysclock_set.c53
-rw-r--r--src/libstddjb/tai_add.c8
-rw-r--r--src/libstddjb/tai_from_localtm.c14
-rw-r--r--src/libstddjb/tai_from_ltm64.c23
-rw-r--r--src/libstddjb/tai_from_sysclock.c23
-rw-r--r--src/libstddjb/tai_from_timespec.c11
-rw-r--r--src/libstddjb/tai_from_timeval.c10
-rw-r--r--src/libstddjb/tai_from_utc.c14
-rw-r--r--src/libstddjb/tai_now.c13
-rw-r--r--src/libstddjb/tai_pack.c9
-rw-r--r--src/libstddjb/tai_pack_little.c9
-rw-r--r--src/libstddjb/tai_relative_from_timespec.c11
-rw-r--r--src/libstddjb/tai_relative_from_timeval.c10
-rw-r--r--src/libstddjb/tai_sub.c8
-rw-r--r--src/libstddjb/tai_unpack.c9
-rw-r--r--src/libstddjb/tai_unpack_little.c9
-rw-r--r--src/libstddjb/tain_add.c14
-rw-r--r--src/libstddjb/tain_addsec.c20
-rw-r--r--src/libstddjb/tain_approx.c8
-rw-r--r--src/libstddjb/tain_clockmon.c47
-rw-r--r--src/libstddjb/tain_fmt.c11
-rw-r--r--src/libstddjb/tain_frac.c8
-rw-r--r--src/libstddjb/tain_from_localtmn.c13
-rw-r--r--src/libstddjb/tain_from_millisecs.c12
-rw-r--r--src/libstddjb/tain_from_ntp.c17
-rw-r--r--src/libstddjb/tain_from_timespec.c13
-rw-r--r--src/libstddjb/tain_from_timeval.c12
-rw-r--r--src/libstddjb/tain_half.c10
-rw-r--r--src/libstddjb/tain_infinite_relative.c5
-rw-r--r--src/libstddjb/tain_less.c10
-rw-r--r--src/libstddjb/tain_nano500.c5
-rw-r--r--src/libstddjb/tain_now.c49
-rw-r--r--src/libstddjb/tain_pack.c10
-rw-r--r--src/libstddjb/tain_pack_little.c10
-rw-r--r--src/libstddjb/tain_relative_from_timespec.c13
-rw-r--r--src/libstddjb/tain_relative_from_timeval.c12
-rw-r--r--src/libstddjb/tain_scan.c12
-rw-r--r--src/libstddjb/tain_setnow.c13
-rw-r--r--src/libstddjb/tain_sub.c15
-rw-r--r--src/libstddjb/tain_sysclock.c12
-rw-r--r--src/libstddjb/tain_to_millisecs.c11
-rw-r--r--src/libstddjb/tain_ulong.c9
-rw-r--r--src/libstddjb/tain_unpack.c10
-rw-r--r--src/libstddjb/tain_unpack_little.c10
-rw-r--r--src/libstddjb/timespec_from_tai.c12
-rw-r--r--src/libstddjb/timespec_from_tai_relative.c19
-rw-r--r--src/libstddjb/timespec_from_tain.c14
-rw-r--r--src/libstddjb/timespec_from_tain_relative.c14
-rw-r--r--src/libstddjb/timestamp.c9
-rw-r--r--src/libstddjb/timestamp_fmt.c9
-rw-r--r--src/libstddjb/timestamp_r.c10
-rw-r--r--src/libstddjb/timestamp_scan.c11
-rw-r--r--src/libstddjb/timeval_from_tai.c11
-rw-r--r--src/libstddjb/timeval_from_tai_relative.c18
-rw-r--r--src/libstddjb/timeval_from_tain.c13
-rw-r--r--src/libstddjb/timeval_from_tain_relative.c13
-rw-r--r--src/libstddjb/ucharn_findlen.c10
-rw-r--r--src/libstddjb/ucharn_fmt.c14
-rw-r--r--src/libstddjb/ucharn_fmt_little.c14
-rw-r--r--src/libstddjb/ucharn_scan.c18
-rw-r--r--src/libstddjb/ucharn_scan_little.c18
-rw-r--r--src/libstddjb/ucspi_get.c22
-rw-r--r--src/libstddjb/uint160_scan.c6
-rw-r--r--src/libstddjb/uint16_fmtlist.c6
-rw-r--r--src/libstddjb/uint16_pack.c10
-rw-r--r--src/libstddjb/uint16_pack_big.c10
-rw-r--r--src/libstddjb/uint16_reverse.c14
-rw-r--r--src/libstddjb/uint16_scan.c6
-rw-r--r--src/libstddjb/uint16_scanlist.c6
-rw-r--r--src/libstddjb/uint16_unpack.c11
-rw-r--r--src/libstddjb/uint16_unpack_big.c11
-rw-r--r--src/libstddjb/uint320_scan.c6
-rw-r--r--src/libstddjb/uint32_fmtlist.c6
-rw-r--r--src/libstddjb/uint32_pack.c12
-rw-r--r--src/libstddjb/uint32_pack_big.c12
-rw-r--r--src/libstddjb/uint32_reverse.c17
-rw-r--r--src/libstddjb/uint32_scan.c6
-rw-r--r--src/libstddjb/uint32_scanlist.c6
-rw-r--r--src/libstddjb/uint32_unpack.c13
-rw-r--r--src/libstddjb/uint32_unpack_big.c13
-rw-r--r--src/libstddjb/uint640_fmt.c10
-rw-r--r--src/libstddjb/uint640_scan.c6
-rw-r--r--src/libstddjb/uint64_fmt.c19
-rw-r--r--src/libstddjb/uint64_fmtlist.c6
-rw-r--r--src/libstddjb/uint64_pack.c16
-rw-r--r--src/libstddjb/uint64_pack_big.c16
-rw-r--r--src/libstddjb/uint64_reverse.c15
-rw-r--r--src/libstddjb/uint64_scan.c6
-rw-r--r--src/libstddjb/uint64_scanlist.c6
-rw-r--r--src/libstddjb/uint64_unpack.c17
-rw-r--r--src/libstddjb/uint64_unpack_big.c17
-rw-r--r--src/libstddjb/uncoe.c11
-rw-r--r--src/libstddjb/unsanitize_read.c11
-rw-r--r--src/libstddjb/utc_from_localtm.c15
-rw-r--r--src/libstddjb/utc_from_ltm64.c23
-rw-r--r--src/libstddjb/utc_from_sysclock.c25
-rw-r--r--src/libstddjb/utc_from_tai.c14
-rw-r--r--src/libstddjb/vbaprintf.c23
-rw-r--r--src/libstddjb/vbprintf.c25
-rw-r--r--src/libstddjb/wait_nointr.c15
-rw-r--r--src/libstddjb/wait_pid_nohang.c17
-rw-r--r--src/libstddjb/wait_pids_nohang.c23
-rw-r--r--src/libstddjb/wait_reap.c11
-rw-r--r--src/libstddjb/waitn.c18
-rw-r--r--src/libstddjb/waitn_reap.c19
-rw-r--r--src/libstddjb/waitpid_nointr.c15
-rw-r--r--src/libunixonacid/bufalloc_timed_flush.c16
-rw-r--r--src/libunixonacid/buffer_timed_fill.c17
-rw-r--r--src/libunixonacid/buffer_timed_flush.c16
-rw-r--r--src/libunixonacid/buffer_timed_get.c30
-rw-r--r--src/libunixonacid/dd_cancel.c17
-rw-r--r--src/libunixonacid/dd_close.c9
-rw-r--r--src/libunixonacid/dd_commit.c68
-rw-r--r--src/libunixonacid/dd_commit_devino.c16
-rw-r--r--src/libunixonacid/dd_open_read.c14
-rw-r--r--src/libunixonacid/dd_open_write.c34
-rw-r--r--src/libunixonacid/kolbak_call.c13
-rw-r--r--src/libunixonacid/kolbak_enqueue.c15
-rw-r--r--src/libunixonacid/kolbak_queue_init.c14
-rw-r--r--src/libunixonacid/kolbak_unenqueue.c11
-rw-r--r--src/libunixonacid/mkdir_unique.c24
-rw-r--r--src/libunixonacid/netstring_timed_get.c24
-rw-r--r--src/libunixonacid/open2_at.c60
-rw-r--r--src/libunixonacid/open3_at.c60
-rw-r--r--src/libunixonacid/open_appendat.c11
-rw-r--r--src/libunixonacid/open_appendatb.c12
-rw-r--r--src/libunixonacid/open_readat.c10
-rw-r--r--src/libunixonacid/open_readatb.c12
-rw-r--r--src/libunixonacid/open_truncat.c10
-rw-r--r--src/libunixonacid/open_truncatb.c12
-rw-r--r--src/libunixonacid/open_writeat.c10
-rw-r--r--src/libunixonacid/open_writeatb.c12
-rw-r--r--src/libunixonacid/opengetlnclose.c24
-rw-r--r--src/libunixonacid/opengetlnclose_at.c24
-rw-r--r--src/libunixonacid/openreadnclose_at.c19
-rw-r--r--src/libunixonacid/openslurpclose_at.c21
-rw-r--r--src/libunixonacid/openwritenclose.c11
-rw-r--r--src/libunixonacid/openwritenclose_at.c24
-rw-r--r--src/libunixonacid/openwritenclose_devino.c12
-rw-r--r--src/libunixonacid/openwritenclose_devino_tmp.c35
-rw-r--r--src/libunixonacid/openwritenclose_tmp.c11
-rw-r--r--src/libunixonacid/skaclient-internal.h15
-rw-r--r--src/libunixonacid/skaclient_default_cb.c14
-rw-r--r--src/libunixonacid/skaclient_end.c21
-rw-r--r--src/libunixonacid/skaclient_init.c32
-rw-r--r--src/libunixonacid/skaclient_put.c10
-rw-r--r--src/libunixonacid/skaclient_putmsg.c16
-rw-r--r--src/libunixonacid/skaclient_putmsgv.c16
-rw-r--r--src/libunixonacid/skaclient_putv.c11
-rw-r--r--src/libunixonacid/skaclient_send.c11
-rw-r--r--src/libunixonacid/skaclient_sendmsg.c15
-rw-r--r--src/libunixonacid/skaclient_sendmsgv.c15
-rw-r--r--src/libunixonacid/skaclient_sendv.c12
-rw-r--r--src/libunixonacid/skaclient_server_ack.c30
-rw-r--r--src/libunixonacid/skaclient_server_bidi_ack.c12
-rw-r--r--src/libunixonacid/skaclient_server_init.c15
-rw-r--r--src/libunixonacid/skaclient_start.c43
-rw-r--r--src/libunixonacid/skaclient_start_async.c52
-rw-r--r--src/libunixonacid/skaclient_start_cb.c18
-rw-r--r--src/libunixonacid/skaclient_startf.c46
-rw-r--r--src/libunixonacid/skaclient_startf_async.c61
-rw-r--r--src/libunixonacid/skaclient_zero.c5
-rw-r--r--src/libunixonacid/timed_flush.c26
-rw-r--r--src/libunixonacid/timed_get.c22
-rw-r--r--src/libunixonacid/timed_getln.c32
-rw-r--r--src/libunixonacid/timed_getlnmax.c33
-rw-r--r--src/libunixonacid/unixmessage_bits_closeall.c7
-rw-r--r--src/libunixonacid/unixmessage_bits_closenone.c7
-rw-r--r--src/libunixonacid/unixmessage_handle.c19
-rw-r--r--src/libunixonacid/unixmessage_put.c83
-rw-r--r--src/libunixonacid/unixmessage_read.c60
-rw-r--r--src/libunixonacid/unixmessage_receive.c44
-rw-r--r--src/libunixonacid/unixmessage_receiver_free.c11
-rw-r--r--src/libunixonacid/unixmessage_receiver_init.c17
-rw-r--r--src/libunixonacid/unixmessage_sender_flush.c82
-rw-r--r--src/libunixonacid/unixmessage_sender_free.c29
-rw-r--r--src/libunixonacid/unixmessage_sender_getfd.c8
-rw-r--r--src/libunixonacid/unixmessage_sender_init.c14
-rw-r--r--src/libunixonacid/unixmessage_sender_timed_flush.c17
-rw-r--r--src/libunixonacid/unixmessage_sender_zero.c5
-rw-r--r--src/libunixonacid/unixmessage_timed_handle.c30
-rw-r--r--src/libunixonacid/unixmessage_timed_receive.c29
-rw-r--r--src/libunixonacid/unixmessage_v_zero.c5
-rw-r--r--src/libunixonacid/unixmessage_zero.c5
-rw-r--r--src/sysdeps/tryaccept4.c33
-rw-r--r--src/sysdeps/tryancilautoclose.c116
-rw-r--r--src/sysdeps/tryclockmon.c11
-rw-r--r--src/sysdeps/tryclockrt.c11
-rw-r--r--src/sysdeps/trycmsgcloexec.c25
-rw-r--r--src/sysdeps/trydevrandom.c54
-rw-r--r--src/sysdeps/trydevurandom.c31
-rw-r--r--src/sysdeps/tryendianness.c43
-rw-r--r--src/sysdeps/tryeproto.c7
-rw-r--r--src/sysdeps/tryeventfd.c10
-rw-r--r--src/sysdeps/tryflock.c13
-rw-r--r--src/sysdeps/trygetpeereid.c15
-rw-r--r--src/sysdeps/trygetpeerucred.c20
-rw-r--r--src/sysdeps/tryipv6.c35
-rw-r--r--src/sysdeps/trylinkat.c29
-rw-r--r--src/sysdeps/trylsock.c26
-rw-r--r--src/sysdeps/trymalloc0.c4
-rw-r--r--src/sysdeps/tryopenat.c29
-rw-r--r--src/sysdeps/trypipe2.c17
-rw-r--r--src/sysdeps/tryposixspawn.c16
-rw-r--r--src/sysdeps/tryppoll.c18
-rw-r--r--src/sysdeps/tryrevoke.c7
-rw-r--r--src/sysdeps/trysendfile.c10
-rw-r--r--src/sysdeps/trysetgroups.c27
-rw-r--r--src/sysdeps/trysettimeofday.c27
-rw-r--r--src/sysdeps/trysignalfd.c13
-rw-r--r--src/sysdeps/trysizeofgid.c8
-rw-r--r--src/sysdeps/trysizeoftime.c8
-rw-r--r--src/sysdeps/trysizeofuint.c7
-rw-r--r--src/sysdeps/trysizeofulong.c7
-rw-r--r--src/sysdeps/trysizeofushort.c7
-rw-r--r--src/sysdeps/trysopeercred.c29
-rw-r--r--src/sysdeps/trysplice.c28
-rw-r--r--src/sysdeps/trystrcasestr.c21
-rw-r--r--src/sysdeps/tryuint64t.c5
-rwxr-xr-xtools/gen-deps.sh50
-rwxr-xr-xtools/install.sh64
901 files changed, 26382 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5c6415e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+*.o
+*.a
+*.lo
+*.so
+*.so.*
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..3f51fd7
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,21 @@
+Main author:
+ Laurent Bercot <ska-skaware@skarnet.org>
+
+Contributors:
+ Dan J. Bernstein <djb@cr.yp.to>
+ William E. Baxter <web@superscript.com>
+
+Thanks to:
+ Jean Marot <marot@quatramaran.ens.fr>
+ Paul Jarc <prj@dogmap.org>
+ Nicolas George <cigaes@salle-s.org>
+ David Madore <david@madore.org>
+ Taj Khattra <taj.khattra@pobox.com>
+ Dan Kegel <dank@kegel.com>
+ Stefan Karrmann <sk@mathematik.uni-ulm.de>
+ Matthew R. Dempsky <mrd@alkemio.org>
+ Lasse Kliemann <lasse@plastictree.net>
+ Robert Ransom <rransom.8774@gmail.com>
+ Frans Haarman <franshaarman@gmail.com>
+ Vincent De Ribou <vins_bozo@yahoo.fr>
+ Jorge Almeida <jalmeida@math.ist.utl.pt>
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 0000000..e99420b
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,260 @@
+20110628
+ version: 1.0.0
+20110630
+ doc: in libstddjb/index.html, corrected strerr.h -> webipc.h
+ bug: when not HASSIGNALFD, selfpipe_trap.c and selfpipe_untrap.c did not compile
+ fix: change "i" to "sig". Silly me.
+ version: 1.0.1
+20110705
+ bug: wrong test for "after" banner in skaclient2_startf.c
+ fix: test readbanner() < afterlen
+ version: 1.0.2
+20110711
+ bug: sig_restoreto.o wasn't in deps-lib/stddjb
+ fix: add it
+ portability: some OSes have an off-by-one NSIG (65).
+ fix: don't rely on NSIG, always test whether sigismember() < 0
+ in the future: consider making SKALIBS_NSIG a sysdep
+ internal: removed sig_nostack, made sig_catcha and sig_restore macros.
+ version: 1.0.3
+20110712
+ bug: localtmn_scan didn't scan the nano part properly
+ fix: change *s to *s++
+ version: 1.0.4
+20110718
+ code: changed short_scan, int_scan and long_scan behaviour according
+ to prj's advice
+ build: changed internal targets to mode 755 instead of 555
+ ui: gensetdyn_p sets errno when returning NULL
+ bug: genset_new() didn't set the newly allocated bit
+ fix: trivial
+ bug: static initialization of gensetb and avltreeb didn't work
+ fix: impossible to make them work in all cases -> scrap the API
+ workaround: declare them statically, but init them dynamically
+ ui: changed uintcmpfunc_t to accept a callback argument
+ modified avlnode/avltree(n) in consequence
+ ui: changed gensetdyn_new() and avltree_newnode() interfaces
+ bug: avlnode_insert and avlnode_delete() didn't work in all cases
+ fix: went over the logic again, added missing logic (subspin...)
+ version: 1.1.0
+20110726
+ bug: avltree_newnode() segfaulted in some cases
+ fix: don't deref before the gensetdyn_new, duh.
+ version: 1.1.1
+20110815
+ ui: clarified avlnode, avltree and avltreen interfaces
+ version: 1.2.0
+20110820
+ ui: added lolstdio.h
+ doc: documented lolstdio.h
+20110822
+ version: 1.2.1
+20110906
+ bug: absolutepath sometimes added a stray '\0'
+ fix: adjust tmp length when exiting the loop
+ internal: exposed buffer_0/1/2 objects; buffer_0/1/2 now is a macro
+ code: added genwrite
+ doc: documented genwrite
+20110915
+ internal: separated genwrite write into put and flush, added bufalloc handles
+ doc: reflected changes
+ internal: changed EINVAL to EOVERFLOW when localtm_from_ltm64() finds a date > 32 bits
+ todo: 2038 is fast approaching, we need to push for tai64 adoption
+20110919
+ version: 1.2.2
+20110929
+ ui: changed openwritenclose_unsafe* and openwritenclose_suffix* to macros
+ ui: changed socket_accept4* to macros, same thing
+ ui: changed ipc_accept* to macros, same thing
+ ui: added more macros in tai.h to help with static init
+ version: 1.2.3
+20111108
+ bug: TAI_INFINITE was incorrectly defined
+ fix: trivial
+ bug: potential security hole in stralloc_ready_tuned
+ fix: check for uint overflows
+20111207
+ internal: reworked nbcoe to accommodate new Linux socket() options
+ ui: socket_* and ipc_* are now often macros
+20111208
+ version: 1.2.4
+20120206
+ bug: missing const in taia_clockmon() stub definition when !HASCLOCKMON
+ fix: trivial
+20120213
+ internal: changed all bools from unsigned char to int
+ ui: some APIs are affected by the unsigned char to int change
+20120220
+ version: 1.2.5
+20120310
+ code: added options to envdir(), renamed it envdir_internal()
+ ui: envdir() is now a macro, for compatibility
+ version: 1.2.6
+20120311
+ data: updated leapsecs.dat to include the 2012-06-30 leap second
+20120312
+ bug: some sysdeps tested libc behaviour instead of kernel behaviour
+ impact: some kernel/libc combinations would get the wrong sysdeps
+ fix: added more run tests instead of relying on load tests
+ version: 1.2.7
+20120518
+ ui: changed skagetlnsep to handle non-empty target strallocs
+ (used in execline-1.1.5's forbacktickx)
+20120527
+ bug: off-by-10 TAI values with some libcs
+ fix: tai_unix() is now sysclock-agnostic
+20120606
+ bug: splice() (in iobufferk) sometimes blocks
+ fix: add non-blocking handling in iobufferk and SPLICE_F_NONBLOCK
+ also fixed include files order for proper _GNU_SOURCE scope
+ portability: no HASOPENAT detection with newer glibcs
+ fix: change _ATFILE_SOURCE to _GNU_SOURCE, modify tryopenat.c
+20120612
+ version: 1.2.8
+20120712
+ code: added ipv6 sysdep
+20120818
+ code: added ipv6 fmt, scan and socket functions
+20120824
+ code: added ip6_scanlist, changed ip4_scanlist API
+20120827
+ code: added support for flag-noipv6 and flag-forcedevr
+20120905
+ ui: simplified libancillary UI by autoallocating buffers
+20121015
+ portability: some libcs still mess up basename and dirname prototypes
+ fix: forget trying to write "standard" (oh the irony) stuff,
+ just get rid of basename.o, dirname.o and realpath.o in libstddjb.
+ code: added ip46 lesser evil
+20121215
+ bug: strerr_warn functions didn't preserve errno
+ fix: obvious
+20121218
+ internal: renamed strerr_die.c to strerr.c
+20121231
+ ui: added STAMP global and _g macros to timed functions
+ ui: marked non-STAMP-compatible functions as deprecated
+ ui: marked dns_random* as deprecated
+20130103
+ portability: added support for uint64_t
+ ui: rewrote libbiguint UI for arbitrary size handling.
+ (Still no heap. Heap is for noobs.)
+20130111
+ bug: stralloc_cat and stralloc_copy were incorrectly defined
+ fix: obvious
+20130124
+ build: added non-slashpackage support
+ doc: added rants about the change
+20130206
+ ui: defined PROG global in libstddjb
+20130212
+ version: 1.3.0
+20130320
+ code: added freelist
+ code: changed genset(dyn) bits from bitarray to freelist
+ impact: more space taken, but adding a new cell is now
+ amortized O(1) instead of O(n).
+20130403
+ code: added ip46_scanlist and a bit more ip46 stuff
+ bug: ip6_fmt didn't collapse trailing 0s
+ fix: add final iszero test in find_colcol
+20130413
+ bug: alloc() was incorrectly defined as gccattr_malloc
+ impact: could leak 0-sized cells (yeah...)
+ fix: remove the attribute
+ ui: made alloc_re a macro
+20130415
+ ui: removed unused SKACLIENT_BANNER_MAXLEN macro
+ internal: increased SKACLIENTIN_BUFSIZE to 4096
+20130422
+ internal: used sin_addr.s_addr instead of s_addr in socket_*
+ ui: removed deprecated socket_deadlineconn()
+20130709
+ ui: removed socket_ipoptionskill()
+ rationale: IP_OPTIONS is not POSIX and the value isn't
+ even proto-standardized - it's not 1 anymore on Linux
+ code: more stuff in ip46.h
+20130710
+ ui: removed pflocal.h
+ ui: added nonposix.h
+ internal: cleaned up ipc_* and socket_*
+ licensing: cleaned up a lot of legacy "public domain" in sysdeps
+20130711
+ internal: gathered most portability problems into nonposix.h
+20130912
+ internal: reworked scan architecture to avoid uint64 pointers
+ ui: added ushort.h, uint.h, ulong.h
+ ui: removed deprecated stuff in fmtscan.h and librandom
+ internal: cleaned up legacy code relying on it
+ internal: /dev/(u)random is now bufferized
+ internal: rrandom_readint now only reads the necessary amount
+20130913
+ ui: removed deprecated deepsleep and deepmillisleep
+ ui: changed taia's nano and atto to uint32
+20130918
+ doc: pretended to add stralloc and genalloc pages
+20130926
+ version: 1.4.0
+20130927
+ bug: ulong-64 defined UINT_* instead of ULONG_*
+ fix: trivial
+ version: 1.4.1
+20131003
+ code: added siovec and its uses in stralloc/netstring/skaclient
+20131012
+ bug: ip46_t instead of ip46full_t in ip46_scanlist.c
+ fix: trivial
+20131019
+ version: 1.4.2
+20140214
+ doc: minor fixes
+ code: added kolbak and skaclient4
+20140301
+ code: added skaclient3 and needed infrastructure
+ internal: ancil sandwich protocol changed to pass # of fds in before
+20140322
+ bug: typos in bitarray_clearsetn
+ impact: freelist-based iterators failed
+ fix: trivial
+ internal: scrapped complex byte optimizations in freelist. unsigned ints ftw.
+ ui: removed freelist.h
+ version: 1.5.0
+20140327
+ bug: sysdeps.h missing in sysdeps/ - important for crosscompilation
+ fix: meh. It belongs in include/. Quick and dirty fix: added a copy
+ to sysdeps/ with a line in package/sysdeps.
+ version: 1.5.1
+20140409
+ portability: MacOSX echo doesn't support -n.
+ fix: replace echo -n with echo | tr -d '\n'.
+ build: moved to 4-number versioning
+20140413
+ ui: better avltree API
+20140429
+ code: added correct supplementary group management in prot
+ ui: prot_gid() and prot_uid() are now macros
+20140430
+ doc: updated
+20140503
+ internal: cleaned up sysdeps usage in exported headers
+ ui: added setgroups.h, gidstuff.h, and *_fmtlist/scanlist
+ ui: sysdeps.h removed from stddjb.h
+20140504
+ ui: timed_ancil_* now reports actual # of fds sent/received
+20140506
+ internal: netstring_get cleanup
+ ui: made buffer_getall and netstring_get interfaces more consistent
+ internal: this impacts skaclient2+
+ ui: added timed_netstring_get
+20140508
+ internal: better timeout rounding for poll()
+ ui: added ppoll sysdep
+ internal: added ppoll() iopause backend
+20140514
+ internal: made time*_from_tai_relative work with IA-32
+ version: 1.6.0.0
+20140515
+ portability: getpeereid uses unsigned types on MacOS X
+ fix: change getpeereid signature to use uid_t and gid_t
+20140612
+ build: fixed libexec installation
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..63309ba
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,13 @@
+Copyright (c) 2011-2014 Laurent Bercot <ska-skaware@skarnet.org>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..efa5596
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,139 @@
+Build Instructions
+------------------
+
+* Requirements
+ ------------
+
+ - A POSIX-compliant C development environment
+ - GNU make version 3.81 or later
+ - If cross-compiling: the sysdeps for your target architecture
+ (see the "Cross-compilation" section below)
+
+ This software will install on any operating system that implements
+POSIX.1-2008, available at:
+ http://pubs.opengroup.org/onlinepubs/9699919799/
+
+
+* Standard usage
+ --------------
+
+ ./configure && make && sudo make install
+
+ will work for most users.
+ It will install the static libraries in /usr/lib/skalibs, the shared
+libraries in /lib, and the sysdeps in /usr/lib/skalibs/sysdeps.
+
+ You can strip the libraries of their extra symbols via "make strip"
+before the "make install" phase. It will shave a few bytes off them.
+
+
+* Customization
+ -------------
+
+ You can customize paths via flags given to configure.
+ See ./configure --help for a list of all available configure options.
+
+
+
+* Environment variables
+ ---------------------
+
+ Controlling a build process via environment variables is a big and
+dangerous hammer. You should try and pass flags to configure instead;
+nevertheless, the standard environment variables are recognized.
+
+ The value of the CROSS_COMPILE environment variable will prefix the
+building tools' names. The --enable-cross option is preferred, see
+"Cross-compilation" below.
+
+ If the CC environment variable is set, its value will override compiler
+detection by configure.
+
+ The values of CFLAGS, CPPFLAGS and LDFLAGS will be appended to flags
+auto-detected by configure. To entirely override the flags set by
+configure, use make -e.
+
+ The Makefile supports the DESTDIR convention for staging.
+
+
+* Shared libraries
+ ----------------
+
+ Software from skarnet.org is small enough that shared libraries are
+generally not worth using. Static linking is simpler and incurs less
+runtime overhead and less points of failure: but since skalibs only
+provides libraries, both versions are built by default.
+ Nevertheless, you can:
+ * avoid building shared libraries: --disable-shared
+ * avoid building static libraries: --disable-static
+
+ If you are using a GNU/Linux system, be aware that the GNU libc
+behaves badly with static linking and produces huge executables,
+so if you plan on making static executables, you should consider
+using another libc, which you also need to use when compiling
+skalibs. musl is recommended: http://musl-libc.org/
+
+
+* Cross-compilation
+ -----------------
+
+ skarnet.org centralizes all the difficulty of cross-compilation
+in skalibs.
+ The native skalibs build process runs some tests to gather "sysdeps",
+i.e. system-dependent properties of the target, and stores those
+into a sysdeps directory; software depending on skalibs is provided
+the name of the sysdeps directory at build time, and can depend on
+its contents - that's how skarnet.org packages are easily made
+portable.
+ However, when the host differs from the target - the cross-compilation
+case - those build-time tests are invalid. So you must provide
+configure with a precomputed sysdeps directory, containing valid
+sysdeps values for your target.
+
+ Use the --with-sysdeps=DIR option to specify DIR as a sysdeps
+directory for your target. Also use the --enable-cross=PREFIX option
+to specify a cross-compiling PREFIX for your toolchain's binaries,
+or simply --enable-cross if your default toolchain is a cross-compiler.
+
+ If you know the peculiarities of your target system, you can build
+a sysdeps directory by hand. However, a much easier, and recommended,
+method of obtaining sysdeps, is to natively determine them (via
+./configure) in a virtual machine, for instance provided by qemu. If you
+are using Linux, simple root filesystems bootable with qemu for testing
+purposes are available at Aboriginal Linux: http://landley.net/aboriginal/
+ Precomputed sysdeps for various targets may also be available on
+skarnet.org or on third-party sites.
+
+
+* The slashpackage convention
+ ---------------------------
+
+ The slashpackage convention (http://cr.yp.to/slashpackage.html)
+is a package installation scheme that provides a few guarantees
+over other conventions such as the FHS, for instance fixed
+absolute pathnames. skarnet.org packages support it: use the
+--enable-slashpackage option to configure, or
+--enable-slashpackage=DIR for a prefixed DIR/package tree.
+This option will activate slashpackage support during the build
+and set slashpackage-compatible installation directories.
+Other options setting individual installation directories will be
+ignored.
+
+ When using slashpackage, two additional Makefile targets are
+available after "make install":
+ - "make -L update" changes the default version of the software to the
+freshly installed one. (This is useful when you have several installed
+versions of the same software, which slashpackage supports.)
+ - "make -L global-links" adds links from /command and /library.so to the
+default version of the binaries and shared libraries.
+ The "-L" option to make is necessary because targets are symbolic links,
+and the default make behaviour is to check the pointed file's timestamp
+and not the symlink's timestamp.
+
+
+* Out-of-tree builds
+ ------------------
+
+ skarnet.org packages do not support out-of-tree builds. They
+are small, so it does not cost much to duplicate the entire
+source tree if parallel builds are needed.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..0f56c1c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,236 @@
+#
+# This Makefile requires GNU make.
+#
+# Do not make changes here.
+# Use the included .mak files.
+#
+
+it: all
+
+CC = $(error Please use ./configure first)
+
+SHARED_LIBS := libskarnet.so
+STATIC_LIBS := libskarnet.a
+
+include package/deps.mak
+-include config.mak
+
+version_m := $(basename $(version))
+version_M := $(basename $(version_m))
+version_l := $(basename $(version_M))
+CPPFLAGS_ALL := -Isrc/include $(CPPFLAGS)
+CFLAGS_ALL := $(CFLAGS) -pipe -Wall
+CFLAGS_SHARED := -fPIC
+LDFLAGS_ALL := $(LDFLAGS)
+LDFLAGS_SHARED := -shared
+LDLIBS_ALL := $(LDLIBS)
+REALCC = $(CROSS_COMPILE)$(CC)
+AR := $(CROSS_COMPILE)ar
+RANLIB := $(CROSS_COMPILE)ranlib
+STRIP := $(CROSS_COMPILE)strip
+INSTALL := ./tools/install.sh
+
+ALL_SRCS := $(wildcard src/lib*/*.c)
+ALL_SOBJS := $(ALL_SRCS:%.c=%.o)
+ALL_DOBJS := $(ALL_SRCS:%.c=%.lo)
+ALL_LIBS := $(SHARED_LIBS) $(STATIC_LIBS)
+ALL_INCLUDES := $(wildcard src/include/$(package)/*.h)
+BUILT_INCLUDES := \
+src/include/$(package)/sysdeps.h \
+src/include/$(package)/uint16.h \
+src/include/$(package)/uint32.h \
+src/include/$(package)/uint64.h \
+src/include/$(package)/ushort.h \
+src/include/$(package)/uint.h \
+src/include/$(package)/ulong.h \
+src/include/$(package)/error.h \
+src/include/$(package)/gidstuff.h \
+src/include/$(package)/ip46.h \
+src/include/$(package)/setgroups.h
+ALL_SYSDEPS := $(wildcard $(sysdeps)/*)
+ALL_DATA := $(wildcard src/etc/*)
+
+all: $(ALL_LIBS) $(ALL_INCLUDES) $(ALL_SYSDEPS) $(ALL_DATA)
+
+clean:
+ @exec rm -f $(ALL_LIBS) $(ALL_BINS) $(ALL_SOBJS) $(ALL_DOBJS) $(BUILT_INCLUDES)
+
+distclean: clean
+ @exec rm -rf config.mak src/include/${package}/config.h sysdeps.cfg
+
+tgz: distclean
+ @. package/info && \
+ rm -rf /tmp/$$package-$$version && \
+ cp -a . /tmp/$$package-$$version && \
+ cd /tmp && \
+ tar -zpcv --owner=0 --group=0 --numeric-owner -f /tmp/$$package-$$version.tar.gz $$package-$$version && \
+ exec rm -rf /tmp/$$package-$$version
+
+strip: $(ALL_LIBS)
+ exec ${STRIP} -x -R .note -R .comment -R .note.GNU-stack $(ALL_LIBS)
+
+install: install-data install-sysdeps install-dynlib install-lib install-include
+install-data: $(ALL_DATA:src/etc/%=$(DESTDIR)$(datadir)/%)
+install-sysdeps: $(ALL_SYSDEPS:$(sysdeps)/%=$(DESTDIR)$(sysdepdir)/%)
+install-dynlib: $(SHARED_LIBS:lib%.so=$(DESTDIR)$(dynlibdir)/lib%.so)
+install-lib: $(STATIC_LIBS:lib%.a=$(DESTDIR)$(libdir)/lib%.a)
+install-include: $(ALL_INCLUDES:src/include/$(package)/%.h=$(DESTDIR)$(includedir)/$(package)/%.h)
+
+ifneq ($(exthome),)
+
+update:
+ exec $(INSTALL) -l $(notdir $(home)) $(DESTDIR)$(exthome)
+
+global-links: $(DESTDIR)$(exthome) $(SHARED_LIBS:lib%.so=$(DESTDIR)$(sproot)/library.so/lib%.so)
+
+$(DESTDIR)$(sproot)/library.so/lib%.so: $(DESTDIR)$(home)/library.so/lib%.so
+ exec $(INSTALL) -D -l ..$(exthome)/library.so/$(<F) $@
+
+.PHONY: update global-links
+
+endif
+
+$(DESTDIR)$(datadir)/%: src/etc/%
+ exec $(INSTALL) -D -m 644 $< $@
+
+$(DESTDIR)$(sysdepdir)/%: $(sysdeps)/%
+ exec $(INSTALL) -D -m 644 $< $@
+
+$(DESTDIR)$(dynlibdir)/%.so: %.so
+ $(INSTALL) -D -m 755 $< $@.$(version) && \
+ $(INSTALL) -l $<.$(version) $@.$(version_m) && \
+ $(INSTALL) -l $<.$(version_m) $@.$(version_M) && \
+ $(INSTALL) -l $<.$(version_M) $@.$(version_l) && \
+ exec $(INSTALL) -l $<.$(version_l) $@
+
+$(DESTDIR)$(libdir)/lib%.a: lib%.a
+ exec $(INSTALL) -D -m 644 $< $@
+
+$(DESTDIR)$(includedir)/$(package)/%.h: src/include/$(package)/%.h
+ exec $(INSTALL) -D -m 644 $< $@
+
+%.o: %.c
+ exec $(REALCC) $(CPPFLAGS_ALL) $(CFLAGS_ALL) -c -o $@ $<
+
+%.lo: %.c
+ exec $(REALCC) $(CPPFLAGS_ALL) $(CFLAGS_ALL) $(CFLAGS_SHARED) -c -o $@ $<
+
+libskarnet.a: $(ALL_SOBJS)
+ exec $(AR) rc $@ $^
+ exec $(RANLIB) $@
+
+libskarnet.so: $(ALL_DOBJS)
+ exec $(REALCC) -o $@ $(CFLAGS_ALL) $(CFLAGS_SHARED) $(LDFLAGS_ALL) $(LDFLAGS_SHARED) -Wl,-soname,$@.$(version_l) $^
+
+.PHONY: it all clean distclean tgz strip install install-data install-sysdeps install-dynlib install-lib install-include
+
+.DELETE_ON_ERROR:
+
+src/include/${package}/sysdeps.h: $(sysdeps)/sysdeps.h
+ exec cat < $< > $@
+
+src/include/${package}/uint16.h: src/include/${package}/uint64.h $(sysdeps)/sysdeps src/headers/uint16-header src/headers/uint16-footer src/headers/uint16-lendian src/headers/uint16-bendian
+ @{ \
+ cat src/headers/uint16-header ; \
+ if grep -qF 'endianness: little' $(sysdeps)/sysdeps ; then cat src/headers/uint16-lendian ; \
+ elif grep -qF 'endianness: big' $(sysdeps)/sysdeps ; then cat src/headers/uint16-bendian ; \
+ else echo 'Error ! Unsupported endianness' 1>&2 ; ./crash ; \
+ fi ; \
+ exec cat src/headers/uint16-footer ; \
+ } > $@
+
+src/include/${package}/uint32.h: src/include/${package}/uint64.h $(sysdeps)/sysdeps src/headers/uint32-header src/headers/uint32-footer src/headers/uint32-lendian src/headers/uint32-bendian
+ @{ \
+ cat src/headers/uint32-header ; \
+ if grep -qF 'endianness: little' $(sysdeps)/sysdeps ; then cat src/headers/uint32-lendian ; \
+ elif grep -qF 'endianness: big' $(sysdeps)/sysdeps ; then cat src/headers/uint32-bendian ; \
+ else echo 'Error ! Unsupported endianness' 1>&2 ; ./crash ; \
+ fi ; \
+ exec cat src/headers/uint32-footer ; \
+ } > $@
+
+src/include/${package}/uint64.h: $(sysdeps)/sysdeps src/headers/uint64-header src/headers/uint64-footer src/headers/uint64-ulong64 src/headers/uint64-noulong64 src/headers/uint64-lendian src/headers/uint64-bendian
+ @{ \
+ cat src/headers/uint64-header ; \
+ if grep -qF 'uint64t: yes' $(sysdeps)/sysdeps ; then cat src/headers/uint64-stdinth ; \
+ elif grep -qF 'sizeofulong: 8' $(sysdeps)/sysdeps ; then cat src/headers/uint64-ulong64 ; \
+ else cat uint64-noulong64 ; \
+ fi ; \
+ if grep -qF 'endianness: little' $(sysdeps)/sysdeps ; then cat src/headers/uint64-lendian ; \
+ elif grep -qF 'endianness: big' $(sysdeps)/sysdeps ; then cat src/headers/uint64-bendian ; \
+ else echo 'Error ! Unsupported endianness' 1>&2 ; ./crash ; \
+ fi ; \
+ exec cat src/headers/uint64-footer ; \
+ } > $@
+
+src/include/${package}/ushort.h: src/include/${package}/uint16.h src/include/${package}/uint32.h $(sysdeps)/sysdeps src/headers/ushort-header src/headers/ushort-footer src/headers/ushort-16 src/headers/ushort-32
+ @{ \
+ cat src/headers/ushort-header ; \
+ if grep -qF 'sizeofushort: 2' $(sysdeps)/sysdeps ; then cat src/headers/ushort-16 ; \
+ elif grep -qF 'sizeofushort: 4' $(sysdeps)/sysdeps ; then cat src/headers/ushort-32 ; \
+ else echo 'Error ! Unsupported unsigned short size' 1>&2 ; ./crash ; \
+ fi ; \
+ exec cat src/headers/ushort-footer ; \
+ } > $@
+
+src/include/${package}/uint.h: src/include/${package}/uint16.h src/include/${package}/uint32.h src/include/${package}/uint64.h $(sysdeps)/sysdeps src/headers/uint-header src/headers/uint-footer src/headers/uint-16 src/headers/uint-32 src/headers/uint-64
+ @{ \
+ cat src/headers/uint-header ; \
+ if grep -qF 'sizeofuint: 2' $(sysdeps)/sysdeps ; then cat src/headers/uint-16 ; \
+ elif grep -qF 'sizeofuint: 4' $(sysdeps)/sysdeps ; then cat src/headers/uint-32 ; \
+ elif grep -qF 'sizeofuint: 8' $(sysdeps)/sysdeps ; then cat src/headers/uint-64 ; \
+ else echo 'Error ! Unsupported unsigned int size' 1>&2 ; ./crash ; \
+ fi ; \
+ exec cat src/headers/uint-footer ; \
+ } > $@
+
+src/include/${package}/ulong.h: src/include/${package}/uint32.h src/include/${package}/uint64.h $(sysdeps)/sysdeps src/headers/ulong-header src/headers/ulong-footer src/headers/ulong-32 src/headers/ulong-64
+ @{ \
+ cat src/headers/ulong-header ; \
+ if grep -qF 'sizeofulong: 4' $(sysdeps)/sysdeps ; then cat src/headers/ulong-32 ; \
+ elif grep -qF 'sizeofulong: 8' $(sysdeps)/sysdeps ; then cat src/headers/ulong-64 ; \
+ else echo 'Error ! Unsupported unsigned long size' 1>&2 ; ./crash ; \
+ fi ; \
+ exec cat src/headers/ulong-footer ; \
+ } > $@
+
+src/include/${package}/error.h: src/include/${package}/gccattributes.h $(sysdeps)/sysdeps src/headers/error-addrinuse src/headers/error-already src/headers/error-proto src/headers/error-header src/headers/error-footer
+ @{ \
+ cat src/headers/error-header ; \
+ if grep -F target: $(sysdeps)/sysdeps | grep -qiF bsd ; then cat src/headers/error-addrinuse ; \
+ else cat src/headers/error-already ; \
+ fi ; \
+ if grep -qF 'eproto: yes' $(sysdeps)/sysdeps ; then : ; \
+ else cat src/headers/error-proto ; \
+ fi ; \
+ exec cat src/headers/error-footer ; \
+ } > $@
+
+src/include/${package}/gidstuff.h: src/include/${package}/uint16.h src/include/${package}/uint32.h src/include/${package}/uint64.h $(sysdeps)/sysdeps src/headers/gidstuff-header src/headers/gidstuff-footer src/headers/gidstuff-16 src/headers/gidstuff-32 src/headers/gidstuff-64
+ @{ \
+ cat src/headers/gidstuff-header ; \
+ if grep -qF 'sizeofgid: 2' $(sysdeps)/sysdeps ; then cat src/headers/gidstuff-16 ; \
+ elif grep -qF 'sizeofgid: 4' $(sysdeps)/sysdeps ; then cat src/headers/gidstuff-32 ; \
+ elif grep -qF 'sizeofgid: 8' $(sysdeps)/sysdeps ; then cat src/headers/gidstuff-64 ; \
+ else echo 'Error ! Unsupported gid_t size' 1>&2 ; ./crash ; \
+ fi ; \
+ exec cat src/headers/gidstuff-footer ; \
+ } > $@
+
+src/include/${package}/ip46.h: src/include/${package}/uint16.h src/include/${package}/bytestr.h src/include/${package}/fmtscan.h src/include/${package}/tai.h src/include/${package}/socket.h $(sysdeps)/sysdeps src/headers/ip46-header src/headers/ip46-footer src/headers/ip46-with src/headers/ip46-without
+ @{ \
+ cat src/headers/ip46-header ; \
+ if $(ipv6) && grep -qF 'ipv6: yes' $(sysdeps)/sysdeps ; then cat src/headers/ip46-with ; \
+ else cat src/headers/ip46-without ; \
+ fi ; \
+ exec cat src/headers/ip46-footer ; \
+ } > $@
+
+src/include/${package}/setgroups.h: $(sysdeps)/sysdeps src/headers/setgroups-header src/headers/setgroups-footer src/headers/setgroups-stub
+ @{ \
+ cat src/headers/setgroups-header ; \
+ if grep -qF 'setgroups: yes' $(sysdeps)/sysdeps ; then : ; \
+ else cat src/headers/setgroups-stub ; \
+ fi ; \
+ exec cat src/headers/setgroups-footer ; \
+ } > $@
diff --git a/README b/README
new file mode 100644
index 0000000..dd98719
--- /dev/null
+++ b/README
@@ -0,0 +1,26 @@
+skalibs - a general-purpose low-level C library
+-----------------------------------------------
+
+ skalibs is a C library used by all the skarnet.org packages.
+It provides APIs more suited to secure and efficient system
+programming than the libc, especially where network programming
+and IPCs are concerned.
+
+ See the enclosed doc/ subdirectory for the documentation, or
+ http://skarnet.org/software/skalibs/
+
+
+* Installation
+ ------------
+
+ See the INSTALL file.
+
+
+* Contact information
+ -------------------
+
+ Laurent Bercot <ska-skaware at skarnet.org>
+
+ Please use the <skaware at list.skarnet.org> mailing-list for
+questions about skalibs.
+
diff --git a/README.macosx b/README.macosx
new file mode 100644
index 0000000..f7ee000
--- /dev/null
+++ b/README.macosx
@@ -0,0 +1,4 @@
+
+ This package will compile on Darwin (MacOS X), but the building of
+shared libraries is not supported.
+ Make sure you use the --disable-shared option to configure.
diff --git a/README.solaris b/README.solaris
new file mode 100644
index 0000000..91a5b26
--- /dev/null
+++ b/README.solaris
@@ -0,0 +1,12 @@
+
+ This package assumes the existence of a POSIX shell in /bin/sh.
+ On Solaris, /bin/sh is not POSIX. Most versions of Solaris provide
+a POSIX shell in /usr/xpg4/bin/sh.
+
+ To compile this package on Solaris, you will need to run
+
+ ./patch-for-solaris
+
+ before you run ./configure. This script will change the #! invocation
+of the configure script and various tools so that a POSIX shell is used
+for the compilation process.
diff --git a/configure b/configure
new file mode 100755
index 0000000..7b86bb4
--- /dev/null
+++ b/configure
@@ -0,0 +1,590 @@
+#!/bin/sh
+
+usage () {
+ cat <<EOF
+Usage: $0 [OPTION]... [VAR=VALUE]... [TARGET]
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+System types:
+ --target=TARGET configure to run on target TARGET [detected]
+ --host=TARGET same as --target
+
+Installation directories:
+ --prefix=PREFIX main installation prefix [/]
+
+Fine tuning of the installation directories:
+ --dynlibdir=DIR shared library files [PREFIX/lib]
+ --libdir=DIR static library files [PREFIX/usr/lib/skalibs]
+ --includedir=DIR include files for the C compiler [PREFIX/usr/include]
+ --datadir=DIR global configuration files [PREFIX/etc]
+ --sysdepdir=DIR sysdeps directory [PREFIX/usr/lib/skalibs/sysdeps]
+
+Dependencies:
+ --with-sysdeps=DIR use provided sysdeps in DIR [autodetected]
+ --with-include=DIR add DIR to the list of searched directories for headers
+ --with-lib=DIR add DIR to the list of searched directories for static libraries
+ --with-dynlib=DIR add DIR to the list of searched directories for shared libraries
+
+Optional features:
+ --disable-shared do not build shared libraries [enabled]
+ --disable-static do not build static libraries [enabled]
+ --enable-slashpackage[=ROOT] assume /package installation at ROOT [disabled]
+ --enable-cross=PREFIX prefix toolchain executable names with PREFIX [none]
+
+skalibs options:
+ --enable-libc-replacements use independent low-level primitives [disabled]
+ --enable-egd=PATH support an EGD daemon listening on PATH as RNG [disabled]
+ --disable-ipv6 do not build IPv6 support [enabled]
+ --enable-iopause-select prefer select() over poll() for iopause implementation [disabled]
+ --enable-tai-clock assume the system clock is TAI-10 instead of UTC [disabled]
+ --enable-right-tz assume the timezone is Olson's right/ instead of posix/ [disabled]
+ --enable-clock use clock_gettime() instead of gettimeofday() [disabled]
+ --enable-monotonic count time with CLOCK_MONOTONIC instead of CLOCK_REALTIME
+ --enable-force-devr assume /dev/random exists and is valid [autodetection takes time]
+ --with-default-path=PATH default executable search path [/usr/bin:/bin]
+
+EOF
+ exit 0
+}
+
+
+# Helper functions
+
+# If your system does not have printf, you can comment this, but it is
+# generally not a good idea to use echo.
+# See http://www.etalabs.net/sh_tricks.html
+echo () {
+ IFS=" "
+ printf %s\\n "$*"
+}
+
+quote () {
+ tr '\n' ' ' <<EOF | grep '^[-[:alnum:]_=,./:]* $' >/dev/null 2>&1 && { echo "$1" ; return 0 ; }
+$1
+EOF
+ echo "$1" | sed -e "s/'/'\\\\''/g" -e "1s/^/'/" -e "\$s/\$/'/" -e "s#^'\([-[:alnum:]_,./:]*\)=\(.*\)\$#\1='\2#" -e "s|\*/|* /|g"
+}
+
+fail () {
+ echo "$*"
+ exit 1
+}
+
+fnmatch () {
+ eval "case \"\$2\" in $1) return 0 ;; *) return 1 ;; esac"
+}
+
+cmdexists () {
+ type "$1" >/dev/null 2>&1
+}
+
+trycc () {
+ test -z "$CC_AUTO" && cmdexists "$1" && CC_AUTO=$1
+}
+
+stripdir () {
+ while eval "fnmatch '*/' \"\${$1}\"" ; do
+ eval "$1=\${$1%/}"
+ done
+}
+
+tryflag () {
+ echo "Checking whether compiler accepts $2 ..."
+ echo "typedef int x;" > "$tmpc"
+ if $CC_AUTO "$2" -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then
+ echo " ... yes"
+ eval "$1=\"\${$1} \$2\""
+ eval "$1=\${$1# }"
+ return 0
+ else
+ echo " ... no"
+ return 1
+ fi
+}
+
+tryldflag () {
+ echo "Checking whether linker accepts $2 ..."
+ echo "typedef int x;" > "$tmpc"
+ if $CC_AUTO -nostdlib "$2" -o /dev/null "$tmpc" >/dev/null 2>&1 ; then
+ echo " ... yes"
+ eval "$1=\"\${$1} \$2\""
+ eval "$1=\${$1# }"
+ return 0
+ else
+ echo " ... no"
+ return 1
+ fi
+}
+
+choose () {
+ echo "Checking whether system has $4..."
+ r=true
+ case "$1" in
+ *c*) $CC_AUTO $CPPFLAGS_AUTO $CFLAGS_AUTO -o try$2.o -c src/sysdeps/try$2.c 2>/dev/null || r=false ;;
+ esac
+ if $r ; then
+ case "$1" in
+ *l*) $CC_AUTO $CFLAGS_AUTO $LDFLAGS_AUTO -o try$2 try$2.o $5 2>/dev/null || r=false ;;
+ esac
+ fi
+ if $r ; then
+ case "$1" in
+ *r*) ./try$2 >/dev/null 2>&1 || r=false ;;
+ esac
+ fi
+ rm -f try$2.o try$2
+ if $r ; then
+ echo "$2: yes" >> $sysdeps/sysdeps
+ echo "#define ${package_macro_name}_HAS$3" >> $sysdeps/sysdeps.h
+ echo " ... yes"
+ else
+ echo "$2: no" >> $sysdeps/sysdeps
+ echo "#undef ${package_macro_name}_HAS$3" >> $sysdeps/sysdeps.h
+ echo " ... no"
+ fi
+}
+
+trytypesize() {
+ echo "Checking size of $3..."
+ $CC_AUTO $CPPFLAGS_AUTO $CFLAGS_AUTO $LDFLAGS_AUTO -o trysizeof$1 src/sysdeps/trysizeof$1.c
+ type_size=$(./trysizeof$1) || fail "$0: unable to determine size of $3"
+ type_bits=$(expr 8 \* $type_size)
+ rm -f trysizeof$1
+ echo "sizeof$1: $type_size" >> $sysdeps/sysdeps
+ echo "#define ${package_macro_name}_SIZEOF$2 $type_size" >> $sysdeps/sysdeps.h
+ echo "#define ${package_macro_name}_$2_BITS $type_bits" >> $sysdeps/sysdeps.h
+ echo " ... $type_size"
+}
+
+# Actual script
+
+CC_AUTO="$CC"
+CFLAGS_AUTO="$CFLAGS"
+CPPFLAGS_AUTO="-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=600 $CPPFLAGS"
+LDFLAGS_AUTO="$LDFLAGS"
+LDFLAGS_NOSHARED=
+prefix=
+dynlibdir='$prefix/lib'
+libdir='$prefix/usr/lib/skalibs'
+includedir='$prefix/usr/include'
+datadir='$prefix/etc'
+sysdepdir='$prefix/usr/lib/$package/sysdeps'
+sysdeps=
+shared=true
+static=true
+slashpackage=false
+replacements=false
+egd=
+ipv6=true
+select=false
+taiclock=false
+righttz=false
+clockrt=false
+clockmon=false
+forcedevr=false
+defaultpath=/usr/bin:/bin
+sproot=
+home=
+exthome=
+addincpath=''
+addlibspath=''
+addlibdpath=''
+vpaths=''
+vpathd=''
+cross="$CROSS_COMPILE"
+
+. package/info
+
+for arg ; do
+ case "$arg" in
+ --help) usage ;;
+ --prefix=*) prefix=${arg#*=} ;;
+ --dynlibdir=*) dynlibdir=${arg#*=} ;;
+ --libdir=*) libdir=${arg#*=} ;;
+ --includedir=*) includedir=${arg#*=} ;;
+ --datadir=*) datadir=${arg#*=} ;;
+ --sysdepdir=*) sysdepdir=${arg#*=} ;;
+ --with-sysdeps=*) sysdeps=${arg#*=} ;;
+ --with-include=*) var=${arg#*=} ; stripdir var ; addincpath="$addincpath -I$var" ;;
+ --with-lib=*) var=${arg#*=} ; stripdir var ; addlibspath="$addlibspath -L$var" ; vpaths="$vpaths $var" ;;
+ --with-dynlib=*) var=${arg#*=} ; stripdir var ; addlibdpath="$addlibdpath -L$var" ; vpathd="$vpathd $var" ;;
+ --enable-shared|--enable-shared=yes) shared=true ;;
+ --disable-shared|--enable-shared=no) shared=false ;;
+ --enable-static|--enable-static=yes) static=true ;;
+ --disable-static|--enable-static=no) static=false ;;
+ --enable-slashpackage=*) sproot=${arg#*=} ; slashpackage=true ; ;;
+ --enable-slashpackage) sproot= ; slashpackage=true ;;
+ --disable-slashpackage) sproot= ; slashpackage=false ;;
+ --enable-cross=*) cross=${arg#*=} ;;
+ --enable-cross) cross= ;;
+ --disable-cross) cross= ;;
+ --enable-libc-replacements|--enable-libc-replacements=yes) replacements=true ;;
+ --disable-libc-replacements|--enable-libc-replacements=no) replacements=false ;;
+ --enable-egd=*) egd=${arg#*=} ;;
+ --disable-egd) egd= ;;
+ --enable-ipv6|--enable-ipv6=yes) ipv6=true ;;
+ --disable-ipv6|--enable-ipv6=no) ipv6=false ;;
+ --enable-iopause-select|--enable-iopause-select=yes) select=true ;;
+ --disable-iopause-select|--enable-iopause-select=no) select=false ;;
+ --enable-tai-clock|--enable-tai-clock=yes) taiclock=true ;;
+ --disable-tai-clock|--enable-tai-clock=no) taiclock=false ;;
+ --enable-right-tz|--enable-right-tz=yes) righttz=true ;;
+ --disable-right-tz|--enable-right-tz=no) righttz=false ;;
+ --enable-clock|--enable-clock=yes) clockrt=true ;;
+ --disable-clock|--enable-clock=no) clockrt=false ;;
+ --enable-monotonic|--enable-monotonic=yes) clockmon=true ;;
+ --disable-monotonic|--enable-monotonic=no) clockmon=false ;;
+ --enable-force-devr|--enable-force-devr=yes) forcedevr=true ;;
+ --disable-force-devr|--enable-force-devr=no) forcedevr=false ;;
+ --with-default-path=*) defaultpath=${arg#*=} ;;
+ --without-default-path) defaultpath=/usr/bin:/bin ;;
+ --enable-*|--disable-*|--with-*|--without-*|--*dir=*|--build=*) ;;
+ --host=*|--target=*) target=${arg#*=} ;;
+ -* ) echo "$0: unknown option $arg" ;;
+ *=*) ;;
+ *) target=$arg ;;
+ esac
+done
+
+for i in prefix exec_prefix dynlibdir libdir includedir datadir sysdepdir sysdeps sproot ; do
+ eval tmp=\${$i}
+ eval $i=$tmp
+ stripdir $i
+done
+
+# Get usable temp filenames
+i=0
+set -C
+while : ; do
+ i=$(($i+1))
+ tmpc="./tmp-configure-$$-$PPID-$i.c"
+ tmpe="./tmp-configure-$$-$PPID-$i.tmp"
+ 2>|/dev/null > "$tmpc" && break
+ 2>|/dev/null > "$tmpe" && break
+ test "$i" -gt 50 && fail "$0: cannot create temporary files"
+done
+set +C
+trap 'rm -f "$tmpc" "$tmpe"' EXIT ABRT INT QUIT TERM HUP
+
+# Set slashpackage values
+if $slashpackage ; then
+ home=${sproot}/package/${category}/${package}-${version}
+ exthome=${sproot}/package/${category}/${package}
+ sysdepdir=${home}/sysdeps
+ binprefix=${home}/command
+ extbinprefix=${exthome}/command
+ dynlibdir=${home}/library.so
+ libdir=${home}/library
+ includedir=${home}/include
+fi
+
+# Find a C compiler to use
+echo "Checking for C compiler..."
+trycc ${cross}gcc
+trycc ${cross}c99
+trycc ${cross}cc
+test -n "$CC_AUTO" || { echo "$0: cannot find a C compiler" ; exit 1 ; }
+echo " ... $CC_AUTO"
+echo "Checking whether C compiler works... "
+echo "typedef int x;" > "$tmpc"
+if $CC_AUTO $CPPFLAGS_AUTO $CFLAGS_AUTO -c -o /dev/null "$tmpc" 2>"$tmpe" ; then
+ echo " ... yes"
+else
+ echo " ... no. Compiler output follows:"
+ cat < "$tmpe"
+ exit 1
+fi
+
+echo "Checking target system type..."
+test -n "$target" || target=$($CC_AUTO -dumpmachine 2>/dev/null) || target=unknown
+echo " ... $target"
+
+tryflag CFLAGS_AUTO -std=c99
+tryflag CFLAGS_AUTO -fomit-frame-pointer
+tryflag CFLAGS_AUTO -fno-exceptions
+tryflag CFLAGS_AUTO -fno-unwind-tables
+tryflag CFLAGS_AUTO -fno-asynchronous-unwind-tables
+tryflag CFLAGS_AUTO -Wa,--noexecstack
+tryflag CFLAGS_AUTO -fno-stack-protector
+tryflag CPPFLAGS_AUTO -Werror=implicit-function-declaration
+tryflag CPPFLAGS_AUTO -Werror=implicit-int
+tryflag CPPFLAGS_AUTO -Werror=pointer-sign
+tryflag CPPFLAGS_AUTO -Werror=pointer-arith
+tryflag CPPFLAGS_AUTO -Wno-parentheses
+tryflag CPPFLAGS_AUTO -Wno-uninitialized
+tryflag CPPFLAGS_AUTO -Wno-missing-braces
+tryflag CPPFLAGS_AUTO -Wno-unused-value
+tryflag CPPFLAGS_AUTO -Wno-unused-but-set-variable
+tryflag CPPFLAGS_AUTO -Wno-unknown-pragmas
+tryflag CPPFLAGS_AUTO -Wno-pointer-to-int-cast
+
+if $shared ; then
+ tryldflag LDFLAGS_AUTO -Wl,--hash-style=both
+fi
+
+if test -n "$sysdeps" ; then
+ if test ! -d $sysdeps || test ! -f $sysdeps/target ; then
+ echo "$0: error: $sysdeps is not a valid sysdeps directory"
+ exit 1
+ fi
+ if [ "x$target" != "x$(cat $sysdeps/target)" ] ; then
+ echo "$0: error: target $target does not match the contents of $sysdepdir/target"
+ exit 1
+ fi
+ echo "Using pre-computed sysdeps in $sysdeps."
+ rt_lib=$(cat $sysdeps/rt.lib)
+ socket_lib=$(cat $sysdeps/socket.lib)
+ sysclock_lib=$(cat $sysdeps/sysclock.lib)
+ tainnow_lib=$(cat $sysdeps/tainnow.lib)
+ util_lib=$(cat $sysdeps/util.lib)
+ if test -n "$egd" ; then
+ egd=$(grep -F egd: $sysdeps/sysdeps | cut -d' ' -f2-)
+ echo "warning: --enable-egd option ignored, using sysdeps-provided value instead: $egd"
+ fi
+else
+ sysdeps=sysdeps.cfg
+ mkdir -p $sysdeps
+ echo "$target" > $sysdeps/target
+ echo "target: $target" > $sysdeps/sysdeps
+ cat <<EOF > $sysdeps/sysdeps.h
+/* ISC license. */
+
+#ifndef SYSDEPS_H
+#define SYSDEPS_H
+
+#define SKALIBS_TARGET "$target"
+EOF
+
+ util_lib=
+ echo > $sysdeps/util.lib
+
+ echo "Checking whether socket functions need an additional library..."
+ $CC_AUTO $CPPFLAGS_AUTO $CFLAGS_AUTO -c -o trylsock.o src/sysdeps/trylsock.c || fail "$0: compiler cannot compile src/sysdeps/trylsock.c"
+ if $CC_AUTO $CFLAGS_AUTO $LDFLAGS_AUTO -o /dev/null trylsock.o 2>/dev/null ; then
+ socket_lib=
+ echo " ... no"
+ elif $CC_AUTO $CFLAGS_AUTO $LDFLAGS_AUTO -o /dev/null trylsock.o -lsocket 2>/dev/null ; then
+ socket_lib=-lsocket
+ echo " ... -lsocket"
+ elif $CC_AUTO $CFLAGS_AUTO $LDFLAGS_AUTO -o /dev/null trylsock.o -lsocket -lnsl 2>/dev/null ; then
+ socket_lib="-lsocket -lnsl"
+ echo " ... -lsocket -lnsl"
+ else
+ fail "$0: unable to determine socket.lib sysdep"
+ fi
+ rm -f trylsock.o
+ echo "$socket_lib" > $sysdeps/socket.lib
+
+ echo "Checking whether clock functions are available..."
+ rt_lib=
+ if $CC_AUTO $CPPFLAGS_AUTO $CFLAGS_AUTO -c -o tryclockrt.o src/sysdeps/tryclockrt.c 2>/dev/null ; then
+ if $CC_AUTO $CFLAGS_AUTO $LDFLAGS_AUTO -o /dev/null tryclockrt.o 2>/dev/null ; then
+ hasclock=true
+ echo " ... yes"
+ elif $CC_AUTO $CFLAGS_AUTO $LDFLAGS_AUTO -o /dev/null tryclockrt.o -lrt 2>/dev/null ; then
+ hasclock=true
+ echo " ... yes, with -lrt"
+ rt_lib=-lrt
+ else
+ hasclock=false
+ fi
+ rm -f tryclockrt.o
+ else
+ hasclock=false
+ fi
+ echo "$rt_lib" > $sysdeps/rt.lib
+ if $clockrt ; then
+ echo "$rt_lib" > $sysdeps/sysclock.lib
+ echo "$rt_lib" > $sysdeps/tainnow.lib
+ else
+ echo > $sysdeps/sysclock.lib
+ if $clockmon ; then
+ echo "$rt_lib" > $sysdeps/tainnow.lib
+ else
+ echo > $sysdeps/tainnow.lib
+ fi
+ fi
+ if $hasclock ; then
+ rm -f tryclockrt
+ echo 'clockrt: yes' >> $sysdeps/sysdeps
+ echo "#define ${package_macro_name}_HASCLOCKRT" >> $sysdeps/sysdeps.h
+ choose cl clockmon CLOCKMON CLOCK_MONOTONIC $rt_lib
+ else
+ echo 'clockrt: no' >> $sysdeps/sysdeps
+ echo "#undef ${package_macro_name}_HASCLOCKRT" >> $sysdeps/sysdeps.h
+ echo ' ... no'
+ fi
+
+ echo "Checking system endianness..."
+ $CC_AUTO $CPPFLAGS_AUTO $CFLAGS_AUTO -o tryendianness src/sysdeps/tryendianness.c
+ endianness=$(./tryendianness) || fail "$0: unable to determine endianness"
+ echo "endianness: $endianness" >> $sysdeps/sysdeps
+ echo "#define ${package_macro_name}_ENDIANNESS \"$endianness\"" >> $sysdeps/sysdeps.h
+ echo " ... $endianness"
+ rm -f tryendianness
+
+ trytypesize ushort USHORT "unsigned short"
+ trytypesize uint UINT "unsigned int"
+ trytypesize ulong ULONG "unsigned long"
+ trytypesize gid GID "gid_t"
+ trytypesize time TIME "time_t"
+ choose clr accept4 ACCEPT4 'accept4()'
+ choose clr ancilautoclose ANCILAUTOCLOSE 'auto-close after fd-passing'
+ choose c cmsgcloexec CMSGCLOEXEC 'MSG_CMSG_CLOEXEC'
+ choose clr devurandom DEVURANDOM '/dev/urandom'
+ choose c eproto EPROTO EPROTO
+ choose cl eventfd EVENTFD 'eventfd()'
+ choose cl flock FLOCK 'flock()'
+ choose cl getpeereid GETPEEREID 'getpeereid()'
+ choose cl sopeercred SOPEERCRED 'SO_PEERCRED'
+ choose cl getpeerucred GETPEERUCRED 'getpeerucred()'
+ choose cl ipv6 IPV6 'IPv6 support' $socket_lib
+ choose clr malloc0 MALLOC0 'non-NULL malloc(0)'
+ choose cl openat OPENAT 'openat()'
+ choose cl linkat LINKAT 'linkat()'
+ choose clr pipe2 PIPE2 'pipe2()'
+ choose cl posixspawn POSIXSPAWN 'posix_spawn()'
+ choose clr ppoll PPOLL 'ppoll()'
+ choose cl revoke REVOKE 'revoke()'
+ choose cl sendfile SENDFILE 'sendfile()'
+ choose cl setgroups SETGROUPS 'setgroups()'
+ choose cl settimeofday SETTIMEOFDAY 'settimeofday()'
+ choose clr signalfd SIGNALFD 'signalfd()'
+ choose clr splice SPLICE 'splice()'
+ choose cl strcasestr STRCASESTR 'strcasestr()'
+ choose c uint64t UINT64T 'uint64_t'
+
+ if $forcedevr ; then
+ echo "/dev/random detection override required, assuming it exists and is working."
+ echo "devrandom: yes" >> $sysdeps/sysdeps
+ echo "#define ${package_macro_name}_HASDEVRANDOM" >> $sysdeps/sysdeps.h
+ else
+ choose clr devrandom DEVRANDOM /dev/random
+ fi
+ if test -n "$egd" ; then
+ if echo "$egd" | grep -q '[^[:alnum:]/_-]' ; then
+ fail "$0: invalid EGD path: $egd"
+ fi
+ echo "egd: $egd" >> $sysdeps/sysdeps
+ echo "#define ${package_macro_name}_HASEGD \"$egd\"" >> $sysdeps/sysdeps.h
+ fi
+ echo '#endif' >> $sysdeps/sysdeps.h
+fi
+
+echo "Copying $sysdeps/sysdeps.h to src/include/${package}/sysdeps.h ..."
+cat < $sysdeps/sysdeps.h > src/include/${package}/sysdeps.h
+echo " ... done"
+
+echo "Creating config.mak..."
+cmdline=$(quote "$0")
+for i ; do cmdline="$cmdline $(quote "$i")" ; done
+exec 3>&1 1>config.mak
+cat << EOF
+# This file was generated by:
+# $cmdline
+# Any changes made here will be lost if configure is re-run.
+
+target := $target
+package := $package
+prefix := $prefix
+datadir := $datadir
+sysdepdir := $sysdepdir
+dynlibdir := $dynlibdir
+libdir := $libdir
+includedir := $includedir
+sysdeps := $sysdeps
+version := $version
+sproot := $sproot
+home := $home
+exthome := $exthome
+ipv6 := $ipv6
+RT_LIB := ${rt_lib}
+SOCKET_LIB := ${socket_lib}
+SYSCLOCK_LIB := ${sysclock_lib}
+TAINNOW_LIB := ${tainnow_lib}
+UTIL_LIB := ${util_lib}
+CC := $CC_AUTO
+CFLAGS := $CFLAGS_AUTO
+CPPFLAGS := $CPPFLAGS_AUTO
+LDFLAGS := $LDFLAGS_AUTO
+LDFLAGS_NOSHARED := $LDFLAGS_NOSHARED
+CROSS_COMPILE := $cross
+EOF
+if test -n "$vpaths" ; then
+ echo "vpath lib%a$vpaths"
+fi
+if test -n "$vpathd" ; then
+ echo "vpath lib%.so$vpathd"
+fi
+
+$static || echo "STATIC_LIBS :="
+$shared || echo "SHARED_LIBS :="
+exec 1>&3 3>&-
+echo " ... done."
+
+echo "Creating src/include/${package}/config.h..."
+mkdir -p -m 0755 src/include/${package}
+exec 3>&1 1> src/include/${package}/config.h
+cat <<EOF
+/* ISC license. */
+
+/* Generated by: $cmdline */
+
+#ifndef ${package_macro_name}_CONFIG_H
+#define ${package_macro_name}_CONFIG_H
+
+#define ${package_macro_name}_VERSION "$version"
+#define ${package_macro_name}_DEFAULTPATH "$defaultpath"
+#define ${package_macro_name}_ETC "$datadir"
+#define ${package_macro_name}_SPROOT "$sproot"
+#define ${package_macro_name}_HOME "$home"
+EOF
+if $replacements ; then
+ echo "#define ${package_macro_name}_FLAG_REPLACE_LIBC"
+else
+ echo "#undef ${package_macro_name}_FLAG_REPLACE_LIBC"
+fi
+if $taiclock ; then
+ echo "#define ${package_macro_name}_FLAG_CLOCKISTAI"
+else
+ echo "#undef ${package_macro_name}_FLAG_CLOCKISTAI"
+fi
+if $righttz ; then
+ echo "#define ${package_macro_name}_FLAG_TZISRIGHT"
+else
+ echo "#undef ${package_macro_name}_FLAG_TZISRIGHT"
+fi
+if $clockrt ; then
+ echo "#define ${package_macro_name}_FLAG_USERT"
+else
+ echo "#undef ${package_macro_name}_FLAG_USERT"
+fi
+if $clockmon ; then
+ echo "#define ${package_macro_name}_FLAG_USEMON"
+else
+ echo "#undef ${package_macro_name}_FLAG_USEMON"
+fi
+if $ipv6 ; then
+ echo "#define ${package_macro_name}_FLAG_WANTIPV6"
+else
+ echo "#undef ${package_macro_name}_FLAG_WANTIPV6"
+fi
+if $select ; then
+ echo "#define ${package_macro_name}_FLAG_PREFERSELECT"
+else
+ echo "#undef ${package_macro_name}_FLAG_PREFERSELECT"
+fi
+if test -n "$egd" ; then
+ echo "#define ${package_macro_name}_EGD $egd"
+else
+ echo "#undef ${package_macro_name}_EGD"
+fi
+
+echo
+echo "#endif"
+exec 1>&3 3>&-
+echo " ... done."
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>
diff --git a/package/deps.mak b/package/deps.mak
new file mode 100644
index 0000000..7e177b5
--- /dev/null
+++ b/package/deps.mak
@@ -0,0 +1,756 @@
+#
+# This file has been generated by tools/gen-deps.sh
+#
+
+src/include/skalibs/alloc.h: src/include/skalibs/gccattributes.h
+src/include/skalibs/allreadwrite.h: src/include/skalibs/functypes.h
+src/include/skalibs/avlnode.h: src/include/skalibs/functypes.h src/include/skalibs/gccattributes.h
+src/include/skalibs/avltree.h: src/include/skalibs/avlnode.h src/include/skalibs/functypes.h src/include/skalibs/gensetdyn.h
+src/include/skalibs/avltreen.h: src/include/skalibs/avlnode.h src/include/skalibs/functypes.h src/include/skalibs/genset.h
+src/include/skalibs/biguint.h: src/include/skalibs/gccattributes.h src/include/skalibs/uint32.h
+src/include/skalibs/bitarray.h: src/include/skalibs/gccattributes.h
+src/include/skalibs/bufalloc.h: src/include/skalibs/gccattributes.h src/include/skalibs/stralloc.h
+src/include/skalibs/buffer.h: src/include/skalibs/bytestr.h src/include/skalibs/cbuffer.h src/include/skalibs/diuint.h src/include/skalibs/gccattributes.h src/include/skalibs/siovec.h
+src/include/skalibs/bytestr.h: src/include/skalibs/config.h src/include/skalibs/gccattributes.h
+src/include/skalibs/cbuffer.h: src/include/skalibs/bytestr.h src/include/skalibs/diuint.h src/include/skalibs/gccattributes.h src/include/skalibs/siovec.h
+src/include/skalibs/cdb.h: src/include/skalibs/gccattributes.h src/include/skalibs/uint32.h
+src/include/skalibs/cdb_make.h: src/include/skalibs/buffer.h src/include/skalibs/diuint32.h src/include/skalibs/genalloc.h src/include/skalibs/uint32.h
+src/include/skalibs/datastruct.h: src/include/skalibs/avlnode.h src/include/skalibs/avltree.h src/include/skalibs/avltreen.h src/include/skalibs/genset.h src/include/skalibs/gensetdyn.h
+src/include/skalibs/diuint32.h: src/include/skalibs/uint32.h
+src/include/skalibs/djbtime.h: src/include/skalibs/config.h src/include/skalibs/tai.h src/include/skalibs/uint32.h src/include/skalibs/uint64.h
+src/include/skalibs/djbunix.h: src/include/skalibs/env.h src/include/skalibs/envalloc.h src/include/skalibs/gccattributes.h src/include/skalibs/stralloc.h src/include/skalibs/uint64.h
+src/include/skalibs/env.h: src/include/skalibs/gccattributes.h src/include/skalibs/stralloc.h
+src/include/skalibs/envalloc.h: src/include/skalibs/genalloc.h
+src/include/skalibs/fmtscan.h: src/include/skalibs/gccattributes.h src/include/skalibs/uint32.h
+src/include/skalibs/genalloc.h: src/include/skalibs/functypes.h src/include/skalibs/stralloc.h
+src/include/skalibs/genset.h: src/include/skalibs/functypes.h
+src/include/skalibs/gensetdyn.h: src/include/skalibs/functypes.h src/include/skalibs/genalloc.h src/include/skalibs/stralloc.h
+src/include/skalibs/iobuffer.h: src/include/skalibs/buffer.h src/include/skalibs/djbunix.h
+src/include/skalibs/iopause.h: src/include/skalibs/tai.h
+src/include/skalibs/kolbak.h: src/include/skalibs/unixmessage.h
+src/include/skalibs/lolstdio.h: src/include/skalibs/bufalloc.h src/include/skalibs/buffer.h src/include/skalibs/strerr2.h
+src/include/skalibs/md5.h: src/include/skalibs/uint32.h
+src/include/skalibs/mininetstring.h: src/include/skalibs/stralloc.h src/include/skalibs/uint16.h src/include/skalibs/uint32.h
+src/include/skalibs/netstring.h: src/include/skalibs/buffer.h src/include/skalibs/siovec.h src/include/skalibs/stralloc.h
+src/include/skalibs/random.h: src/include/skalibs/gccattributes.h src/include/skalibs/stralloc.h
+src/include/skalibs/rrandom.h: src/include/skalibs/unirandom.h
+src/include/skalibs/sha1.h: src/include/skalibs/uint32.h
+src/include/skalibs/sha256.h: src/include/skalibs/uint32.h
+src/include/skalibs/sig.h: src/include/skalibs/gccattributes.h
+src/include/skalibs/siovec.h: src/include/skalibs/gccattributes.h
+src/include/skalibs/skaclient.h: src/include/skalibs/kolbak.h src/include/skalibs/siovec.h src/include/skalibs/tai.h src/include/skalibs/uint32.h src/include/skalibs/unixmessage.h
+src/include/skalibs/skalibs.h: src/include/skalibs/biguint.h src/include/skalibs/datastruct.h src/include/skalibs/random.h src/include/skalibs/stdcrypto.h src/include/skalibs/stddjb.h src/include/skalibs/unixonacid.h
+src/include/skalibs/skamisc.h: src/include/skalibs/buffer.h src/include/skalibs/stralloc.h
+src/include/skalibs/socket.h: src/include/skalibs/djbunix.h src/include/skalibs/gccattributes.h src/include/skalibs/tai.h src/include/skalibs/uint16.h src/include/skalibs/uint32.h src/include/skalibs/webipc.h
+src/include/skalibs/stdcrypto.h: src/include/skalibs/md5.h src/include/skalibs/rc4.h src/include/skalibs/sha1.h src/include/skalibs/sha256.h
+src/include/skalibs/stddjb.h: src/include/skalibs/alloc.h src/include/skalibs/allreadwrite.h src/include/skalibs/bitarray.h src/include/skalibs/bufalloc.h src/include/skalibs/buffer.h src/include/skalibs/bytestr.h src/include/skalibs/cbuffer.h src/include/skalibs/cdb.h src/include/skalibs/cdb_make.h src/include/skalibs/config.h src/include/skalibs/direntry.h src/include/skalibs/diuint.h src/include/skalibs/diuint32.h src/include/skalibs/djbtime.h src/include/skalibs/djbunix.h src/include/skalibs/env.h src/include/skalibs/envalloc.h src/include/skalibs/environ.h src/include/skalibs/error.h src/include/skalibs/fmtscan.h src/include/skalibs/functypes.h src/include/skalibs/gccattributes.h src/include/skalibs/genalloc.h src/include/skalibs/genwrite.h src/include/skalibs/getpeereid.h src/include/skalibs/gidstuff.h src/include/skalibs/iobuffer.h src/include/skalibs/iopause.h src/include/skalibs/ip46.h src/include/skalibs/lolstdio.h src/include/skalibs/mininetstring.h src/include/skalibs/netstring.h src/include/skalibs/nsig.h src/include/skalibs/segfault.h src/include/skalibs/selfpipe.h src/include/skalibs/setgroups.h src/include/skalibs/sgetopt.h src/include/skalibs/sig.h src/include/skalibs/siovec.h src/include/skalibs/skamisc.h src/include/skalibs/socket.h src/include/skalibs/stralloc.h src/include/skalibs/strerr.h src/include/skalibs/strerr2.h src/include/skalibs/tai.h src/include/skalibs/uint.h src/include/skalibs/uint16.h src/include/skalibs/uint32.h src/include/skalibs/uint64.h src/include/skalibs/ulong.h src/include/skalibs/ushort.h src/include/skalibs/webipc.h
+src/include/skalibs/stralloc.h: src/include/skalibs/bytestr.h src/include/skalibs/siovec.h
+src/include/skalibs/strerr.h: src/include/skalibs/gccattributes.h
+src/include/skalibs/strerr2.h: src/include/skalibs/strerr.h
+src/include/skalibs/surf.h: src/include/skalibs/uint32.h
+src/include/skalibs/tai.h: src/include/skalibs/gccattributes.h src/include/skalibs/uint32.h src/include/skalibs/uint64.h
+src/include/skalibs/unirandom.h: src/include/skalibs/buffer.h src/include/skalibs/surf.h
+src/include/skalibs/unirandomdev.h: src/include/skalibs/unirandom.h
+src/include/skalibs/unirandomegd.h: src/include/skalibs/unirandom.h
+src/include/skalibs/unisurf.h: src/include/skalibs/unirandom.h
+src/include/skalibs/unix-timed.h: src/include/skalibs/bufalloc.h src/include/skalibs/buffer.h src/include/skalibs/functypes.h src/include/skalibs/stralloc.h src/include/skalibs/tai.h
+src/include/skalibs/unix-transactional.h: src/include/skalibs/stralloc.h src/include/skalibs/uint64.h
+src/include/skalibs/unixmessage.h: src/include/skalibs/buffer.h src/include/skalibs/cbuffer.h src/include/skalibs/gccattributes.h src/include/skalibs/genalloc.h src/include/skalibs/siovec.h src/include/skalibs/stralloc.h src/include/skalibs/tai.h
+src/include/skalibs/unixonacid.h: src/include/skalibs/kolbak.h src/include/skalibs/skaclient.h src/include/skalibs/unix-timed.h src/include/skalibs/unix-transactional.h src/include/skalibs/unixmessage.h
+src/include/skalibs/webipc.h: src/include/skalibs/djbunix.h src/include/skalibs/tai.h
+src/libdatastruct/avlnode-internal.h: src/include/skalibs/avlnode.h
+src/librandom/random-internal.h: src/include/skalibs/gccattributes.h src/include/skalibs/rrandom.h src/include/skalibs/surf.h src/include/skalibs/unirandom.h
+src/libstdcrypto/md5-internal.h: src/include/skalibs/md5.h src/include/skalibs/uint32.h
+src/libstdcrypto/sha1-internal.h: src/include/skalibs/sha1.h src/include/skalibs/uint32.h
+src/libstdcrypto/sha256-internal.h: src/include/skalibs/sha256.h src/include/skalibs/uint32.h
+src/libstddjb/alloc-internal.h: src/include/skalibs/alloc.h src/include/skalibs/sysdeps.h
+src/libstddjb/djbtime-internal.h: src/include/skalibs/uint64.h
+src/libstddjb/fmtscan-internal.h: src/include/skalibs/bytestr.h src/include/skalibs/fmtscan.h
+src/libstddjb/selfpipe-internal.h: src/include/skalibs/sig.h src/include/skalibs/sysdeps.h
+src/libunixonacid/skaclient-internal.h: src/include/skalibs/kolbak.h src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h
+src/libbiguint/bu_addc.o src/libbiguint/bu_addc.lo: src/libbiguint/bu_addc.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_addmod.o src/libbiguint/bu_addmod.lo: src/libbiguint/bu_addmod.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_cmp.o src/libbiguint/bu_cmp.lo: src/libbiguint/bu_cmp.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_copy.o src/libbiguint/bu_copy.lo: src/libbiguint/bu_copy.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_copy_internal.o src/libbiguint/bu_copy_internal.lo: src/libbiguint/bu_copy_internal.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_div.o src/libbiguint/bu_div.lo: src/libbiguint/bu_div.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_div_internal.o src/libbiguint/bu_div_internal.lo: src/libbiguint/bu_div_internal.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_divmod.o src/libbiguint/bu_divmod.lo: src/libbiguint/bu_divmod.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_divmod_internal.o src/libbiguint/bu_divmod_internal.lo: src/libbiguint/bu_divmod_internal.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_fmt.o src/libbiguint/bu_fmt.lo: src/libbiguint/bu_fmt.c src/include/skalibs/biguint.h src/include/skalibs/bytestr.h src/include/skalibs/uint32.h
+src/libbiguint/bu_gcd.o src/libbiguint/bu_gcd.lo: src/libbiguint/bu_gcd.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_invmod.o src/libbiguint/bu_invmod.lo: src/libbiguint/bu_invmod.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_len.o src/libbiguint/bu_len.lo: src/libbiguint/bu_len.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_mod.o src/libbiguint/bu_mod.lo: src/libbiguint/bu_mod.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_mul.o src/libbiguint/bu_mul.lo: src/libbiguint/bu_mul.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h src/include/skalibs/uint64.h
+src/libbiguint/bu_mulmod.o src/libbiguint/bu_mulmod.lo: src/libbiguint/bu_mulmod.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_pack.o src/libbiguint/bu_pack.lo: src/libbiguint/bu_pack.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_pack_big.o src/libbiguint/bu_pack_big.lo: src/libbiguint/bu_pack_big.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_scan.o src/libbiguint/bu_scan.lo: src/libbiguint/bu_scan.c src/include/skalibs/biguint.h src/include/skalibs/bitarray.h src/include/skalibs/uint32.h
+src/libbiguint/bu_scan_internal.o src/libbiguint/bu_scan_internal.lo: src/libbiguint/bu_scan_internal.c src/include/skalibs/biguint.h src/include/skalibs/bytestr.h src/include/skalibs/uint32.h
+src/libbiguint/bu_scanlen.o src/libbiguint/bu_scanlen.lo: src/libbiguint/bu_scanlen.c src/include/skalibs/biguint.h src/include/skalibs/fmtscan.h
+src/libbiguint/bu_slbc.o src/libbiguint/bu_slbc.lo: src/libbiguint/bu_slbc.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_srbc.o src/libbiguint/bu_srbc.lo: src/libbiguint/bu_srbc.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_subc.o src/libbiguint/bu_subc.lo: src/libbiguint/bu_subc.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_submod.o src/libbiguint/bu_submod.lo: src/libbiguint/bu_submod.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_unpack.o src/libbiguint/bu_unpack.lo: src/libbiguint/bu_unpack.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_unpack_big.o src/libbiguint/bu_unpack_big.lo: src/libbiguint/bu_unpack_big.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libbiguint/bu_zero.o src/libbiguint/bu_zero.lo: src/libbiguint/bu_zero.c src/include/skalibs/biguint.h src/include/skalibs/uint32.h
+src/libdatastruct/avlnode_delete.o src/libdatastruct/avlnode_delete.lo: src/libdatastruct/avlnode_delete.c src/libdatastruct/avlnode-internal.h src/include/skalibs/avlnode.h src/include/skalibs/functypes.h
+src/libdatastruct/avlnode_doublerotate.o src/libdatastruct/avlnode_doublerotate.lo: src/libdatastruct/avlnode_doublerotate.c src/libdatastruct/avlnode-internal.h src/include/skalibs/avlnode.h
+src/libdatastruct/avlnode_extreme.o src/libdatastruct/avlnode_extreme.lo: src/libdatastruct/avlnode_extreme.c src/include/skalibs/avlnode.h
+src/libdatastruct/avlnode_extremenode.o src/libdatastruct/avlnode_extremenode.lo: src/libdatastruct/avlnode_extremenode.c src/include/skalibs/avlnode.h
+src/libdatastruct/avlnode_height.o src/libdatastruct/avlnode_height.lo: src/libdatastruct/avlnode_height.c src/include/skalibs/avlnode.h
+src/libdatastruct/avlnode_insertnode.o src/libdatastruct/avlnode_insertnode.lo: src/libdatastruct/avlnode_insertnode.c src/libdatastruct/avlnode-internal.h src/include/skalibs/avlnode.h src/include/skalibs/functypes.h
+src/libdatastruct/avlnode_iter.o src/libdatastruct/avlnode_iter.lo: src/libdatastruct/avlnode_iter.c src/include/skalibs/avlnode.h
+src/libdatastruct/avlnode_rotate.o src/libdatastruct/avlnode_rotate.lo: src/libdatastruct/avlnode_rotate.c src/libdatastruct/avlnode-internal.h src/include/skalibs/avlnode.h
+src/libdatastruct/avlnode_search.o src/libdatastruct/avlnode_search.lo: src/libdatastruct/avlnode_search.c src/include/skalibs/avlnode.h
+src/libdatastruct/avlnode_searchnode.o src/libdatastruct/avlnode_searchnode.lo: src/libdatastruct/avlnode_searchnode.c src/libdatastruct/avlnode-internal.h src/include/skalibs/avlnode.h src/include/skalibs/functypes.h
+src/libdatastruct/avlnode_zero.o src/libdatastruct/avlnode_zero.lo: src/libdatastruct/avlnode_zero.c src/include/skalibs/avlnode.h
+src/libdatastruct/avltree_delete.o src/libdatastruct/avltree_delete.lo: src/libdatastruct/avltree_delete.c src/include/skalibs/avlnode.h src/include/skalibs/avltree.h src/include/skalibs/gensetdyn.h
+src/libdatastruct/avltree_free.o src/libdatastruct/avltree_free.lo: src/libdatastruct/avltree_free.c src/include/skalibs/avltree.h src/include/skalibs/gensetdyn.h
+src/libdatastruct/avltree_init.o src/libdatastruct/avltree_init.lo: src/libdatastruct/avltree_init.c src/include/skalibs/avlnode.h src/include/skalibs/avltree.h src/include/skalibs/functypes.h src/include/skalibs/gensetdyn.h
+src/libdatastruct/avltree_insert.o src/libdatastruct/avltree_insert.lo: src/libdatastruct/avltree_insert.c src/include/skalibs/avltree.h
+src/libdatastruct/avltree_newnode.o src/libdatastruct/avltree_newnode.lo: src/libdatastruct/avltree_newnode.c src/include/skalibs/avlnode.h src/include/skalibs/avltree.h src/include/skalibs/gensetdyn.h
+src/libdatastruct/avltree_zero.o src/libdatastruct/avltree_zero.lo: src/libdatastruct/avltree_zero.c src/include/skalibs/avltree.h
+src/libdatastruct/avltreen_delete.o src/libdatastruct/avltreen_delete.lo: src/libdatastruct/avltreen_delete.c src/include/skalibs/avlnode.h src/include/skalibs/avltreen.h src/include/skalibs/genset.h
+src/libdatastruct/avltreen_init.o src/libdatastruct/avltreen_init.lo: src/libdatastruct/avltreen_init.c src/include/skalibs/avlnode.h src/include/skalibs/avltreen.h src/include/skalibs/functypes.h src/include/skalibs/genset.h
+src/libdatastruct/avltreen_insert.o src/libdatastruct/avltreen_insert.lo: src/libdatastruct/avltreen_insert.c src/include/skalibs/avltreen.h
+src/libdatastruct/avltreen_newnode.o src/libdatastruct/avltreen_newnode.lo: src/libdatastruct/avltreen_newnode.c src/include/skalibs/avlnode.h src/include/skalibs/avltreen.h src/include/skalibs/genset.h
+src/libdatastruct/genset.o src/libdatastruct/genset.lo: src/libdatastruct/genset.c src/include/skalibs/genset.h
+src/libdatastruct/genset_iter.o src/libdatastruct/genset_iter.lo: src/libdatastruct/genset_iter.c src/include/skalibs/bitarray.h src/include/skalibs/functypes.h src/include/skalibs/genset.h
+src/libdatastruct/gensetdyn_delete.o src/libdatastruct/gensetdyn_delete.lo: src/libdatastruct/gensetdyn_delete.c src/include/skalibs/genalloc.h src/include/skalibs/gensetdyn.h
+src/libdatastruct/gensetdyn_free.o src/libdatastruct/gensetdyn_free.lo: src/libdatastruct/gensetdyn_free.c src/include/skalibs/genalloc.h src/include/skalibs/gensetdyn.h src/include/skalibs/stralloc.h
+src/libdatastruct/gensetdyn_init.o src/libdatastruct/gensetdyn_init.lo: src/libdatastruct/gensetdyn_init.c src/include/skalibs/genalloc.h src/include/skalibs/gensetdyn.h src/include/skalibs/stralloc.h
+src/libdatastruct/gensetdyn_iter.o src/libdatastruct/gensetdyn_iter.lo: src/libdatastruct/gensetdyn_iter.c src/include/skalibs/bitarray.h src/include/skalibs/functypes.h src/include/skalibs/gensetdyn.h
+src/libdatastruct/gensetdyn_new.o src/libdatastruct/gensetdyn_new.lo: src/libdatastruct/gensetdyn_new.c src/include/skalibs/genalloc.h src/include/skalibs/gensetdyn.h
+src/libdatastruct/gensetdyn_ready.o src/libdatastruct/gensetdyn_ready.lo: src/libdatastruct/gensetdyn_ready.c src/include/skalibs/genalloc.h src/include/skalibs/gensetdyn.h src/include/skalibs/stralloc.h
+src/libdatastruct/gensetdyn_zero.o src/libdatastruct/gensetdyn_zero.lo: src/libdatastruct/gensetdyn_zero.c src/include/skalibs/gensetdyn.h
+src/librandom/badrandom_char.o src/librandom/badrandom_char.lo: src/librandom/badrandom_char.c src/librandom/random-internal.h src/include/skalibs/random.h
+src/librandom/badrandom_finish.o src/librandom/badrandom_finish.lo: src/librandom/badrandom_finish.c src/librandom/random-internal.h src/include/skalibs/random.h src/include/skalibs/rrandom.h
+src/librandom/badrandom_here.o src/librandom/badrandom_here.lo: src/librandom/badrandom_here.c src/include/skalibs/config.h src/librandom/random-internal.h src/include/skalibs/sysdeps.h src/include/skalibs/unisurf.h
+src/librandom/badrandom_init.o src/librandom/badrandom_init.lo: src/librandom/badrandom_init.c src/include/skalibs/random.h
+src/librandom/badrandom_int.o src/librandom/badrandom_int.lo: src/librandom/badrandom_int.c src/librandom/random-internal.h src/include/skalibs/random.h src/include/skalibs/rrandom.h
+src/librandom/badrandom_string.o src/librandom/badrandom_string.lo: src/librandom/badrandom_string.c src/librandom/random-internal.h src/include/skalibs/random.h src/include/skalibs/rrandom.h
+src/librandom/goodrandom_char.o src/librandom/goodrandom_char.lo: src/librandom/goodrandom_char.c src/librandom/random-internal.h src/include/skalibs/random.h
+src/librandom/goodrandom_finish.o src/librandom/goodrandom_finish.lo: src/librandom/goodrandom_finish.c src/librandom/random-internal.h src/include/skalibs/random.h src/include/skalibs/rrandom.h
+src/librandom/goodrandom_here.o src/librandom/goodrandom_here.lo: src/librandom/goodrandom_here.c src/include/skalibs/config.h src/librandom/random-internal.h src/include/skalibs/sysdeps.h src/include/skalibs/unisurf.h
+src/librandom/goodrandom_init.o src/librandom/goodrandom_init.lo: src/librandom/goodrandom_init.c src/include/skalibs/random.h
+src/librandom/goodrandom_int.o src/librandom/goodrandom_int.lo: src/librandom/goodrandom_int.c src/librandom/random-internal.h src/include/skalibs/random.h src/include/skalibs/rrandom.h
+src/librandom/goodrandom_string.o src/librandom/goodrandom_string.lo: src/librandom/goodrandom_string.c src/librandom/random-internal.h src/include/skalibs/random.h src/include/skalibs/rrandom.h
+src/librandom/random_mask2.o src/librandom/random_mask2.lo: src/librandom/random_mask2.c src/librandom/random-internal.h src/include/skalibs/sysdeps.h
+src/librandom/random_name.o src/librandom/random_name.lo: src/librandom/random_name.c src/librandom/random-internal.h src/include/skalibs/random.h
+src/librandom/random_sauniquename.o src/librandom/random_sauniquename.lo: src/librandom/random_sauniquename.c src/include/skalibs/random.h src/include/skalibs/skamisc.h src/include/skalibs/stralloc.h
+src/librandom/random_unsort.o src/librandom/random_unsort.lo: src/librandom/random_unsort.c src/include/skalibs/bytestr.h src/include/skalibs/random.h
+src/librandom/randomegd_open.o src/librandom/randomegd_open.lo: src/librandom/randomegd_open.c src/include/skalibs/djbunix.h src/include/skalibs/randomegd.h src/include/skalibs/webipc.h
+src/librandom/randomegd_readb.o src/librandom/randomegd_readb.lo: src/librandom/randomegd_readb.c src/include/skalibs/allreadwrite.h src/include/skalibs/randomegd.h
+src/librandom/randomegd_readnb.o src/librandom/randomegd_readnb.lo: src/librandom/randomegd_readnb.c src/include/skalibs/allreadwrite.h src/include/skalibs/randomegd.h
+src/librandom/rrandom_add.o src/librandom/rrandom_add.lo: src/librandom/rrandom_add.c src/include/skalibs/rrandom.h src/include/skalibs/unirandom.h
+src/librandom/rrandom_finish.o src/librandom/rrandom_finish.lo: src/librandom/rrandom_finish.c src/include/skalibs/rrandom.h src/include/skalibs/unirandom.h
+src/librandom/rrandom_name.o src/librandom/rrandom_name.lo: src/librandom/rrandom_name.c src/include/skalibs/rrandom.h src/include/skalibs/unirandom.h
+src/librandom/rrandom_read.o src/librandom/rrandom_read.lo: src/librandom/rrandom_read.c src/include/skalibs/allreadwrite.h src/include/skalibs/error.h src/include/skalibs/rrandom.h src/include/skalibs/unirandom.h
+src/librandom/rrandom_readint.o src/librandom/rrandom_readint.lo: src/librandom/rrandom_readint.c src/librandom/random-internal.h src/include/skalibs/rrandom.h src/include/skalibs/uint.h src/include/skalibs/unirandom.h
+src/librandom/surf.o src/librandom/surf.lo: src/librandom/surf.c src/include/skalibs/bytestr.h src/include/skalibs/surf.h src/include/skalibs/uint32.h
+src/librandom/surf_autoinit.o src/librandom/surf_autoinit.lo: src/librandom/surf_autoinit.c src/include/skalibs/surf.h
+src/librandom/surf_here.o src/librandom/surf_here.lo: src/librandom/surf_here.c src/librandom/random-internal.h src/include/skalibs/surf.h
+src/librandom/surf_init.o src/librandom/surf_init.lo: src/librandom/surf_init.c src/include/skalibs/surf.h
+src/librandom/surf_makeseed.o src/librandom/surf_makeseed.lo: src/librandom/surf_makeseed.c src/include/skalibs/sha1.h src/include/skalibs/surf.h src/include/skalibs/tai.h src/include/skalibs/uint32.h
+src/librandom/surf_sinit.o src/librandom/surf_sinit.lo: src/librandom/surf_sinit.c src/include/skalibs/surf.h src/include/skalibs/uint32.h
+src/librandom/unidevrandom.o src/librandom/unidevrandom.lo: src/librandom/unidevrandom.c src/librandom/random-internal.h src/include/skalibs/sysdeps.h src/include/skalibs/unirandom.h src/include/skalibs/unirandomdev.h
+src/librandom/unidevurandom.o src/librandom/unidevurandom.lo: src/librandom/unidevurandom.c src/librandom/random-internal.h src/include/skalibs/sysdeps.h src/include/skalibs/unirandom.h src/include/skalibs/unirandomdev.h
+src/librandom/unihasegd.o src/librandom/unihasegd.lo: src/librandom/unihasegd.c src/include/skalibs/config.h src/librandom/random-internal.h src/include/skalibs/unirandom.h src/include/skalibs/unirandomegd.h
+src/librandom/unirandom_finish.o src/librandom/unirandom_finish.lo: src/librandom/unirandom_finish.c src/include/skalibs/unirandom.h
+src/librandom/unirandom_init.o src/librandom/unirandom_init.lo: src/librandom/unirandom_init.c src/include/skalibs/unirandom.h
+src/librandom/unirandom_readb.o src/librandom/unirandom_readb.lo: src/librandom/unirandom_readb.c src/include/skalibs/unirandom.h
+src/librandom/unirandom_readnb.o src/librandom/unirandom_readnb.lo: src/librandom/unirandom_readnb.c src/include/skalibs/unirandom.h
+src/librandom/unirandom_register.o src/librandom/unirandom_register.lo: src/librandom/unirandom_register.c src/librandom/random-internal.h src/include/skalibs/unirandom.h
+src/librandom/unirandomdev.o src/librandom/unirandomdev.lo: src/librandom/unirandomdev.c src/include/skalibs/buffer.h src/include/skalibs/djbunix.h src/include/skalibs/unirandom.h src/include/skalibs/unirandomdev.h
+src/librandom/unirandomegd.o src/librandom/unirandomegd.lo: src/librandom/unirandomegd.c src/include/skalibs/djbunix.h src/include/skalibs/randomegd.h src/include/skalibs/unirandom.h src/include/skalibs/unirandomegd.h
+src/librandom/unisurf.o src/librandom/unisurf.lo: src/librandom/unisurf.c src/include/skalibs/surf.h src/include/skalibs/unirandom.h src/include/skalibs/unisurf.h
+src/librandom/unisurf_init.o src/librandom/unisurf_init.lo: src/librandom/unisurf_init.c src/librandom/random-internal.h src/include/skalibs/surf.h src/include/skalibs/unirandom.h src/include/skalibs/unisurf.h
+src/libstdcrypto/md5_final.o src/libstdcrypto/md5_final.lo: src/libstdcrypto/md5_final.c src/include/skalibs/bytestr.h src/libstdcrypto/md5-internal.h src/include/skalibs/md5.h src/include/skalibs/uint32.h
+src/libstdcrypto/md5_init.o src/libstdcrypto/md5_init.lo: src/libstdcrypto/md5_init.c src/include/skalibs/md5.h
+src/libstdcrypto/md5_transform.o src/libstdcrypto/md5_transform.lo: src/libstdcrypto/md5_transform.c src/libstdcrypto/md5-internal.h src/include/skalibs/uint32.h
+src/libstdcrypto/md5_update.o src/libstdcrypto/md5_update.lo: src/libstdcrypto/md5_update.c src/include/skalibs/bytestr.h src/libstdcrypto/md5-internal.h src/include/skalibs/md5.h src/include/skalibs/uint32.h
+src/libstdcrypto/rc4.o src/libstdcrypto/rc4.lo: src/libstdcrypto/rc4.c src/include/skalibs/bytestr.h src/include/skalibs/rc4.h
+src/libstdcrypto/rc4_init.o src/libstdcrypto/rc4_init.lo: src/libstdcrypto/rc4_init.c src/include/skalibs/bytestr.h src/include/skalibs/rc4.h
+src/libstdcrypto/sha1_feed.o src/libstdcrypto/sha1_feed.lo: src/libstdcrypto/sha1_feed.c src/include/skalibs/bytestr.h src/libstdcrypto/sha1-internal.h src/include/skalibs/sha1.h src/include/skalibs/uint32.h
+src/libstdcrypto/sha1_final.o src/libstdcrypto/sha1_final.lo: src/libstdcrypto/sha1_final.c src/libstdcrypto/sha1-internal.h src/include/skalibs/sha1.h src/include/skalibs/uint32.h
+src/libstdcrypto/sha1_init.o src/libstdcrypto/sha1_init.lo: src/libstdcrypto/sha1_init.c src/include/skalibs/sha1.h
+src/libstdcrypto/sha1_transform.o src/libstdcrypto/sha1_transform.lo: src/libstdcrypto/sha1_transform.c src/libstdcrypto/sha1-internal.h src/include/skalibs/uint32.h
+src/libstdcrypto/sha1_update.o src/libstdcrypto/sha1_update.lo: src/libstdcrypto/sha1_update.c src/libstdcrypto/sha1-internal.h src/include/skalibs/sha1.h
+src/libstdcrypto/sha256_feed.o src/libstdcrypto/sha256_feed.lo: src/libstdcrypto/sha256_feed.c src/include/skalibs/bytestr.h src/libstdcrypto/sha256-internal.h src/include/skalibs/sha256.h src/include/skalibs/uint32.h
+src/libstdcrypto/sha256_final.o src/libstdcrypto/sha256_final.lo: src/libstdcrypto/sha256_final.c src/include/skalibs/bytestr.h src/libstdcrypto/sha256-internal.h src/include/skalibs/sha256.h src/include/skalibs/uint32.h
+src/libstdcrypto/sha256_init.o src/libstdcrypto/sha256_init.lo: src/libstdcrypto/sha256_init.c src/include/skalibs/sha256.h
+src/libstdcrypto/sha256_transform.o src/libstdcrypto/sha256_transform.lo: src/libstdcrypto/sha256_transform.c src/libstdcrypto/sha256-internal.h src/include/skalibs/uint32.h
+src/libstdcrypto/sha256_update.o src/libstdcrypto/sha256_update.lo: src/libstdcrypto/sha256_update.c src/libstdcrypto/sha256-internal.h src/include/skalibs/sha256.h
+src/libstddjb/absolutepath.o src/libstddjb/absolutepath.lo: src/libstddjb/absolutepath.c src/include/skalibs/djbunix.h src/include/skalibs/skamisc.h src/include/skalibs/stralloc.h
+src/libstddjb/absolutepath_tmp.o src/libstddjb/absolutepath_tmp.lo: src/libstddjb/absolutepath_tmp.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h
+src/libstddjb/alloc.o src/libstddjb/alloc.lo: src/libstddjb/alloc.c src/libstddjb/alloc-internal.h src/include/skalibs/alloc.h src/include/skalibs/sysdeps.h
+src/libstddjb/alloc_0.o src/libstddjb/alloc_0.lo: src/libstddjb/alloc_0.c src/libstddjb/alloc-internal.h src/include/skalibs/alloc.h src/include/skalibs/sysdeps.h
+src/libstddjb/allread.o src/libstddjb/allread.lo: src/libstddjb/allread.c src/include/skalibs/allreadwrite.h
+src/libstddjb/allreadwrite.o src/libstddjb/allreadwrite.lo: src/libstddjb/allreadwrite.c src/include/skalibs/allreadwrite.h
+src/libstddjb/allwrite.o src/libstddjb/allwrite.lo: src/libstddjb/allwrite.c src/include/skalibs/allreadwrite.h
+src/libstddjb/baprintf.o src/libstddjb/baprintf.lo: src/libstddjb/baprintf.c src/include/skalibs/bufalloc.h src/include/skalibs/lolstdio.h
+src/libstddjb/basename.o src/libstddjb/basename.lo: src/libstddjb/basename.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h
+src/libstddjb/bitarray_and.o src/libstddjb/bitarray_and.lo: src/libstddjb/bitarray_and.c src/include/skalibs/bitarray.h
+src/libstddjb/bitarray_clearsetn.o src/libstddjb/bitarray_clearsetn.lo: src/libstddjb/bitarray_clearsetn.c src/include/skalibs/bitarray.h
+src/libstddjb/bitarray_firstclear.o src/libstddjb/bitarray_firstclear.lo: src/libstddjb/bitarray_firstclear.c src/include/skalibs/bitarray.h
+src/libstddjb/bitarray_firstset.o src/libstddjb/bitarray_firstset.lo: src/libstddjb/bitarray_firstset.c src/include/skalibs/bitarray.h
+src/libstddjb/bitarray_not.o src/libstddjb/bitarray_not.lo: src/libstddjb/bitarray_not.c src/include/skalibs/bitarray.h
+src/libstddjb/bitarray_or.o src/libstddjb/bitarray_or.lo: src/libstddjb/bitarray_or.c src/include/skalibs/bitarray.h
+src/libstddjb/bitarray_testandpoke.o src/libstddjb/bitarray_testandpoke.lo: src/libstddjb/bitarray_testandpoke.c src/include/skalibs/bitarray.h
+src/libstddjb/bitarray_xor.o src/libstddjb/bitarray_xor.lo: src/libstddjb/bitarray_xor.c src/include/skalibs/bitarray.h
+src/libstddjb/bprintf.o src/libstddjb/bprintf.lo: src/libstddjb/bprintf.c src/include/skalibs/buffer.h src/include/skalibs/lolstdio.h
+src/libstddjb/bufalloc_1.o src/libstddjb/bufalloc_1.lo: src/libstddjb/bufalloc_1.c src/include/skalibs/allreadwrite.h src/include/skalibs/bufalloc.h
+src/libstddjb/bufalloc_2.o src/libstddjb/bufalloc_2.lo: src/libstddjb/bufalloc_2.c src/include/skalibs/allreadwrite.h src/include/skalibs/bufalloc.h
+src/libstddjb/bufalloc_clean.o src/libstddjb/bufalloc_clean.lo: src/libstddjb/bufalloc_clean.c src/include/skalibs/bufalloc.h src/include/skalibs/bytestr.h
+src/libstddjb/bufalloc_flush.o src/libstddjb/bufalloc_flush.lo: src/libstddjb/bufalloc_flush.c src/include/skalibs/allreadwrite.h src/include/skalibs/bufalloc.h
+src/libstddjb/bufalloc_getfd.o src/libstddjb/bufalloc_getfd.lo: src/libstddjb/bufalloc_getfd.c src/include/skalibs/bufalloc.h
+src/libstddjb/bufalloc_getlen.o src/libstddjb/bufalloc_getlen.lo: src/libstddjb/bufalloc_getlen.c src/include/skalibs/bufalloc.h
+src/libstddjb/bufalloc_init.o src/libstddjb/bufalloc_init.lo: src/libstddjb/bufalloc_init.c src/include/skalibs/bufalloc.h src/include/skalibs/stralloc.h
+src/libstddjb/buffer_0.o src/libstddjb/buffer_0.lo: src/libstddjb/buffer_0.c src/include/skalibs/buffer.h
+src/libstddjb/buffer_0f1.o src/libstddjb/buffer_0f1.lo: src/libstddjb/buffer_0f1.c src/include/skalibs/buffer.h
+src/libstddjb/buffer_0small.o src/libstddjb/buffer_0small.lo: src/libstddjb/buffer_0small.c src/include/skalibs/buffer.h
+src/libstddjb/buffer_1.o src/libstddjb/buffer_1.lo: src/libstddjb/buffer_1.c src/include/skalibs/buffer.h
+src/libstddjb/buffer_1small.o src/libstddjb/buffer_1small.lo: src/libstddjb/buffer_1small.c src/include/skalibs/buffer.h
+src/libstddjb/buffer_2.o src/libstddjb/buffer_2.lo: src/libstddjb/buffer_2.c src/include/skalibs/buffer.h
+src/libstddjb/buffer_fill.o src/libstddjb/buffer_fill.lo: src/libstddjb/buffer_fill.c src/include/skalibs/buffer.h src/include/skalibs/cbuffer.h
+src/libstddjb/buffer_flush.o src/libstddjb/buffer_flush.lo: src/libstddjb/buffer_flush.c src/include/skalibs/buffer.h src/include/skalibs/cbuffer.h src/include/skalibs/siovec.h
+src/libstddjb/buffer_flush1read.o src/libstddjb/buffer_flush1read.lo: src/libstddjb/buffer_flush1read.c src/include/skalibs/buffer.h src/include/skalibs/siovec.h
+src/libstddjb/buffer_get.o src/libstddjb/buffer_get.lo: src/libstddjb/buffer_get.c src/include/skalibs/buffer.h
+src/libstddjb/buffer_getall.o src/libstddjb/buffer_getall.lo: src/libstddjb/buffer_getall.c src/include/skalibs/allreadwrite.h src/include/skalibs/buffer.h
+src/libstddjb/buffer_getallnf.o src/libstddjb/buffer_getallnf.lo: src/libstddjb/buffer_getallnf.c src/include/skalibs/buffer.h
+src/libstddjb/buffer_getfd.o src/libstddjb/buffer_getfd.lo: src/libstddjb/buffer_getfd.c src/include/skalibs/buffer.h
+src/libstddjb/buffer_getlen.o src/libstddjb/buffer_getlen.lo: src/libstddjb/buffer_getlen.c src/include/skalibs/buffer.h
+src/libstddjb/buffer_getv.o src/libstddjb/buffer_getv.lo: src/libstddjb/buffer_getv.c src/include/skalibs/buffer.h src/include/skalibs/diuint.h src/include/skalibs/siovec.h
+src/libstddjb/buffer_getvall.o src/libstddjb/buffer_getvall.lo: src/libstddjb/buffer_getvall.c src/include/skalibs/buffer.h src/include/skalibs/diuint.h src/include/skalibs/siovec.h
+src/libstddjb/buffer_getvallnf.o src/libstddjb/buffer_getvallnf.lo: src/libstddjb/buffer_getvallnf.c src/include/skalibs/buffer.h src/include/skalibs/siovec.h
+src/libstddjb/buffer_init.o src/libstddjb/buffer_init.lo: src/libstddjb/buffer_init.c src/include/skalibs/buffer.h
+src/libstddjb/buffer_put.o src/libstddjb/buffer_put.lo: src/libstddjb/buffer_put.c src/include/skalibs/buffer.h
+src/libstddjb/buffer_putall.o src/libstddjb/buffer_putall.lo: src/libstddjb/buffer_putall.c src/include/skalibs/buffer.h
+src/libstddjb/buffer_putallnf.o src/libstddjb/buffer_putallnf.lo: src/libstddjb/buffer_putallnf.c src/include/skalibs/buffer.h
+src/libstddjb/buffer_putflush.o src/libstddjb/buffer_putflush.lo: src/libstddjb/buffer_putflush.c src/include/skalibs/buffer.h
+src/libstddjb/buffer_putv.o src/libstddjb/buffer_putv.lo: src/libstddjb/buffer_putv.c src/include/skalibs/buffer.h src/include/skalibs/diuint.h src/include/skalibs/siovec.h
+src/libstddjb/buffer_putvall.o src/libstddjb/buffer_putvall.lo: src/libstddjb/buffer_putvall.c src/include/skalibs/buffer.h src/include/skalibs/diuint.h src/include/skalibs/siovec.h
+src/libstddjb/buffer_putvallnf.o src/libstddjb/buffer_putvallnf.lo: src/libstddjb/buffer_putvallnf.c src/include/skalibs/buffer.h
+src/libstddjb/buffer_putvflush.o src/libstddjb/buffer_putvflush.lo: src/libstddjb/buffer_putvflush.c src/include/skalibs/buffer.h src/include/skalibs/siovec.h
+src/libstddjb/buffer_read.o src/libstddjb/buffer_read.lo: src/libstddjb/buffer_read.c src/include/skalibs/allreadwrite.h src/include/skalibs/buffer.h src/include/skalibs/siovec.h
+src/libstddjb/buffer_write.o src/libstddjb/buffer_write.lo: src/libstddjb/buffer_write.c src/include/skalibs/allreadwrite.h src/include/skalibs/buffer.h src/include/skalibs/siovec.h
+src/libstddjb/byte_chr.o src/libstddjb/byte_chr.lo: src/libstddjb/byte_chr.c src/include/skalibs/bytestr.h src/include/skalibs/config.h
+src/libstddjb/byte_copy.o src/libstddjb/byte_copy.lo: src/libstddjb/byte_copy.c src/include/skalibs/bytestr.h src/include/skalibs/config.h
+src/libstddjb/byte_count.o src/libstddjb/byte_count.lo: src/libstddjb/byte_count.c src/include/skalibs/bytestr.h
+src/libstddjb/byte_cr.o src/libstddjb/byte_cr.lo: src/libstddjb/byte_cr.c src/include/skalibs/bytestr.h src/include/skalibs/config.h
+src/libstddjb/byte_diff.o src/libstddjb/byte_diff.lo: src/libstddjb/byte_diff.c src/include/skalibs/bytestr.h src/include/skalibs/config.h
+src/libstddjb/byte_in.o src/libstddjb/byte_in.lo: src/libstddjb/byte_in.c src/include/skalibs/bytestr.h
+src/libstddjb/byte_rchr.o src/libstddjb/byte_rchr.lo: src/libstddjb/byte_rchr.c src/include/skalibs/bytestr.h
+src/libstddjb/byte_zero.o src/libstddjb/byte_zero.lo: src/libstddjb/byte_zero.c src/include/skalibs/bytestr.h src/include/skalibs/config.h
+src/libstddjb/case_diffb.o src/libstddjb/case_diffb.lo: src/libstddjb/case_diffb.c src/include/skalibs/bytestr.h
+src/libstddjb/case_diffs.o src/libstddjb/case_diffs.lo: src/libstddjb/case_diffs.c src/include/skalibs/bytestr.h
+src/libstddjb/case_lowerb.o src/libstddjb/case_lowerb.lo: src/libstddjb/case_lowerb.c src/include/skalibs/bytestr.h
+src/libstddjb/case_lowers.o src/libstddjb/case_lowers.lo: src/libstddjb/case_lowers.c src/include/skalibs/bytestr.h
+src/libstddjb/case_startb.o src/libstddjb/case_startb.lo: src/libstddjb/case_startb.c src/include/skalibs/bytestr.h
+src/libstddjb/case_str.o src/libstddjb/case_str.lo: src/libstddjb/case_str.c src/include/skalibs/bytestr.h src/include/skalibs/config.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
+src/libstddjb/case_upperb.o src/libstddjb/case_upperb.lo: src/libstddjb/case_upperb.c src/include/skalibs/bytestr.h
+src/libstddjb/case_uppers.o src/libstddjb/case_uppers.lo: src/libstddjb/case_uppers.c src/include/skalibs/bytestr.h
+src/libstddjb/cbuffer_get.o src/libstddjb/cbuffer_get.lo: src/libstddjb/cbuffer_get.c src/include/skalibs/cbuffer.h src/include/skalibs/siovec.h
+src/libstddjb/cbuffer_getv.o src/libstddjb/cbuffer_getv.lo: src/libstddjb/cbuffer_getv.c src/include/skalibs/cbuffer.h src/include/skalibs/siovec.h
+src/libstddjb/cbuffer_init.o src/libstddjb/cbuffer_init.lo: src/libstddjb/cbuffer_init.c src/include/skalibs/cbuffer.h
+src/libstddjb/cbuffer_put.o src/libstddjb/cbuffer_put.lo: src/libstddjb/cbuffer_put.c src/include/skalibs/cbuffer.h src/include/skalibs/siovec.h
+src/libstddjb/cbuffer_putv.o src/libstddjb/cbuffer_putv.lo: src/libstddjb/cbuffer_putv.c src/include/skalibs/cbuffer.h src/include/skalibs/siovec.h
+src/libstddjb/cbuffer_rpeek.o src/libstddjb/cbuffer_rpeek.lo: src/libstddjb/cbuffer_rpeek.c src/include/skalibs/cbuffer.h src/include/skalibs/siovec.h
+src/libstddjb/cbuffer_rseek.o src/libstddjb/cbuffer_rseek.lo: src/libstddjb/cbuffer_rseek.c src/include/skalibs/cbuffer.h
+src/libstddjb/cbuffer_unget.o src/libstddjb/cbuffer_unget.lo: src/libstddjb/cbuffer_unget.c src/include/skalibs/cbuffer.h
+src/libstddjb/cbuffer_unput.o src/libstddjb/cbuffer_unput.lo: src/libstddjb/cbuffer_unput.c src/include/skalibs/cbuffer.h
+src/libstddjb/cbuffer_wpeek.o src/libstddjb/cbuffer_wpeek.lo: src/libstddjb/cbuffer_wpeek.c src/include/skalibs/cbuffer.h src/include/skalibs/siovec.h
+src/libstddjb/cbuffer_wseek.o src/libstddjb/cbuffer_wseek.lo: src/libstddjb/cbuffer_wseek.c src/include/skalibs/cbuffer.h
+src/libstddjb/cdb_findnext.o src/libstddjb/cdb_findnext.lo: src/libstddjb/cdb_findnext.c src/include/skalibs/bytestr.h src/include/skalibs/cdb.h src/include/skalibs/uint32.h
+src/libstddjb/cdb_free.o src/libstddjb/cdb_free.lo: src/libstddjb/cdb_free.c src/include/skalibs/cdb.h
+src/libstddjb/cdb_hash.o src/libstddjb/cdb_hash.lo: src/libstddjb/cdb_hash.c src/include/skalibs/cdb.h src/include/skalibs/uint32.h
+src/libstddjb/cdb_init_map.o src/libstddjb/cdb_init_map.lo: src/libstddjb/cdb_init_map.c src/include/skalibs/cdb.h
+src/libstddjb/cdb_make.o src/libstddjb/cdb_make.lo: src/libstddjb/cdb_make.c src/include/skalibs/buffer.h src/include/skalibs/cdb.h src/include/skalibs/cdb_make.h src/include/skalibs/diuint32.h src/include/skalibs/djbunix.h src/include/skalibs/genalloc.h src/include/skalibs/uint32.h
+src/libstddjb/cdb_mapfile.o src/libstddjb/cdb_mapfile.lo: src/libstddjb/cdb_mapfile.c src/include/skalibs/cdb.h src/include/skalibs/djbunix.h
+src/libstddjb/cdb_nextkey.o src/libstddjb/cdb_nextkey.lo: src/libstddjb/cdb_nextkey.c src/include/skalibs/cdb.h src/include/skalibs/uint32.h
+src/libstddjb/cdb_read.o src/libstddjb/cdb_read.lo: src/libstddjb/cdb_read.c src/include/skalibs/allreadwrite.h src/include/skalibs/bytestr.h src/include/skalibs/cdb.h src/include/skalibs/djbunix.h src/include/skalibs/error.h src/include/skalibs/uint32.h
+src/libstddjb/cdb_successor.o src/libstddjb/cdb_successor.lo: src/libstddjb/cdb_successor.c src/include/skalibs/cdb.h src/include/skalibs/uint32.h
+src/libstddjb/cdb_zero.o src/libstddjb/cdb_zero.lo: src/libstddjb/cdb_zero.c src/include/skalibs/cdb.h
+src/libstddjb/child_spawn.o src/libstddjb/child_spawn.lo: src/libstddjb/child_spawn.c src/include/skalibs/allreadwrite.h src/include/skalibs/bytestr.h src/include/skalibs/config.h src/include/skalibs/djbunix.h src/include/skalibs/env.h src/include/skalibs/sig.h src/include/skalibs/strerr2.h src/include/skalibs/sysdeps.h src/include/skalibs/uint.h src/include/skalibs/webipc.h
+src/libstddjb/child_spawn0.o src/libstddjb/child_spawn0.lo: src/libstddjb/child_spawn0.c src/include/skalibs/allreadwrite.h src/include/skalibs/config.h src/include/skalibs/djbunix.h src/include/skalibs/env.h src/include/skalibs/sysdeps.h
+src/libstddjb/child_spawn1.o src/libstddjb/child_spawn1.lo: src/libstddjb/child_spawn1.c src/include/skalibs/allreadwrite.h src/include/skalibs/config.h src/include/skalibs/djbunix.h src/include/skalibs/env.h src/include/skalibs/sysdeps.h
+src/libstddjb/coe.o src/libstddjb/coe.lo: src/libstddjb/coe.c src/include/skalibs/djbunix.h
+src/libstddjb/deepsleepuntil.o src/libstddjb/deepsleepuntil.lo: src/libstddjb/deepsleepuntil.c src/include/skalibs/iopause.h src/include/skalibs/tai.h
+src/libstddjb/dir_close.o src/libstddjb/dir_close.lo: src/libstddjb/dir_close.c src/include/skalibs/direntry.h
+src/libstddjb/dirname.o src/libstddjb/dirname.lo: src/libstddjb/dirname.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h
+src/libstddjb/doublefork.o src/libstddjb/doublefork.lo: src/libstddjb/doublefork.c src/include/skalibs/allreadwrite.h src/include/skalibs/djbunix.h src/include/skalibs/uint64.h
+src/libstddjb/env_addmodif.o src/libstddjb/env_addmodif.lo: src/libstddjb/env_addmodif.c src/include/skalibs/env.h src/include/skalibs/stralloc.h
+src/libstddjb/env_get.o src/libstddjb/env_get.lo: src/libstddjb/env_get.c src/include/skalibs/env.h src/include/skalibs/environ.h
+src/libstddjb/env_get2.o src/libstddjb/env_get2.lo: src/libstddjb/env_get2.c src/include/skalibs/bytestr.h src/include/skalibs/env.h
+src/libstddjb/env_len.o src/libstddjb/env_len.lo: src/libstddjb/env_len.c src/include/skalibs/env.h
+src/libstddjb/env_make.o src/libstddjb/env_make.lo: src/libstddjb/env_make.c src/include/skalibs/bytestr.h src/include/skalibs/env.h
+src/libstddjb/env_merge.o src/libstddjb/env_merge.lo: src/libstddjb/env_merge.c src/include/skalibs/bytestr.h src/include/skalibs/env.h
+src/libstddjb/env_string.o src/libstddjb/env_string.lo: src/libstddjb/env_string.c src/include/skalibs/env.h src/include/skalibs/stralloc.h
+src/libstddjb/envalloc_0.o src/libstddjb/envalloc_0.lo: src/libstddjb/envalloc_0.c src/include/skalibs/envalloc.h src/include/skalibs/genalloc.h
+src/libstddjb/envalloc_make.o src/libstddjb/envalloc_make.lo: src/libstddjb/envalloc_make.c src/include/skalibs/env.h src/include/skalibs/envalloc.h src/include/skalibs/genalloc.h
+src/libstddjb/envalloc_merge.o src/libstddjb/envalloc_merge.lo: src/libstddjb/envalloc_merge.c src/include/skalibs/bytestr.h src/include/skalibs/env.h src/include/skalibs/envalloc.h src/include/skalibs/genalloc.h
+src/libstddjb/envalloc_uniq.o src/libstddjb/envalloc_uniq.lo: src/libstddjb/envalloc_uniq.c src/include/skalibs/bytestr.h src/include/skalibs/envalloc.h src/include/skalibs/genalloc.h
+src/libstddjb/envdir.o src/libstddjb/envdir.lo: src/libstddjb/envdir.c src/include/skalibs/bytestr.h src/include/skalibs/direntry.h src/include/skalibs/djbunix.h src/include/skalibs/env.h src/include/skalibs/stralloc.h
+src/libstddjb/error_str.o src/libstddjb/error_str.lo: src/libstddjb/error_str.c src/include/skalibs/config.h src/include/skalibs/error.h
+src/libstddjb/error_temp.o src/libstddjb/error_temp.lo: src/libstddjb/error_temp.c src/include/skalibs/error.h
+src/libstddjb/execvep.o src/libstddjb/execvep.lo: src/libstddjb/execvep.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h
+src/libstddjb/fd_cat.o src/libstddjb/fd_cat.lo: src/libstddjb/fd_cat.c src/include/skalibs/djbunix.h src/include/skalibs/iobuffer.h
+src/libstddjb/fd_catn.o src/libstddjb/fd_catn.lo: src/libstddjb/fd_catn.c src/include/skalibs/allreadwrite.h src/include/skalibs/djbunix.h src/include/skalibs/iobuffer.h
+src/libstddjb/fd_chdir.o src/libstddjb/fd_chdir.lo: src/libstddjb/fd_chdir.c src/include/skalibs/djbunix.h
+src/libstddjb/fd_chmod.o src/libstddjb/fd_chmod.lo: src/libstddjb/fd_chmod.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h
+src/libstddjb/fd_chown.o src/libstddjb/fd_chown.lo: src/libstddjb/fd_chown.c src/include/skalibs/djbunix.h
+src/libstddjb/fd_close.o src/libstddjb/fd_close.lo: src/libstddjb/fd_close.c src/include/skalibs/djbunix.h
+src/libstddjb/fd_copy.o src/libstddjb/fd_copy.lo: src/libstddjb/fd_copy.c src/include/skalibs/djbunix.h
+src/libstddjb/fd_copy2.o src/libstddjb/fd_copy2.lo: src/libstddjb/fd_copy2.c src/include/skalibs/djbunix.h
+src/libstddjb/fd_ensure_open.o src/libstddjb/fd_ensure_open.lo: src/libstddjb/fd_ensure_open.c src/include/skalibs/djbunix.h
+src/libstddjb/fd_move.o src/libstddjb/fd_move.lo: src/libstddjb/fd_move.c src/include/skalibs/djbunix.h
+src/libstddjb/fd_move2.o src/libstddjb/fd_move2.lo: src/libstddjb/fd_move2.c src/include/skalibs/djbunix.h
+src/libstddjb/fd_read.o src/libstddjb/fd_read.lo: src/libstddjb/fd_read.c src/include/skalibs/allreadwrite.h
+src/libstddjb/fd_readv.o src/libstddjb/fd_readv.lo: src/libstddjb/fd_readv.c src/include/skalibs/allreadwrite.h
+src/libstddjb/fd_recv.o src/libstddjb/fd_recv.lo: src/libstddjb/fd_recv.c src/include/skalibs/allreadwrite.h
+src/libstddjb/fd_select.o src/libstddjb/fd_select.lo: src/libstddjb/fd_select.c
+src/libstddjb/fd_send.o src/libstddjb/fd_send.lo: src/libstddjb/fd_send.c src/include/skalibs/allreadwrite.h
+src/libstddjb/fd_sync.o src/libstddjb/fd_sync.lo: src/libstddjb/fd_sync.c src/include/skalibs/djbunix.h
+src/libstddjb/fd_write.o src/libstddjb/fd_write.lo: src/libstddjb/fd_write.c src/include/skalibs/allreadwrite.h
+src/libstddjb/fd_writev.o src/libstddjb/fd_writev.lo: src/libstddjb/fd_writev.c src/include/skalibs/allreadwrite.h
+src/libstddjb/fmtscan_asc.o src/libstddjb/fmtscan_asc.lo: src/libstddjb/fmtscan_asc.c src/include/skalibs/fmtscan.h
+src/libstddjb/fmtscan_num.o src/libstddjb/fmtscan_num.lo: src/libstddjb/fmtscan_num.c src/include/skalibs/fmtscan.h
+src/libstddjb/genalloc_deepfree.o src/libstddjb/genalloc_deepfree.lo: src/libstddjb/genalloc_deepfree.c src/include/skalibs/genalloc.h src/include/skalibs/stralloc.h
+src/libstddjb/genwrite_flush_bufalloc.o src/libstddjb/genwrite_flush_bufalloc.lo: src/libstddjb/genwrite_flush_bufalloc.c src/include/skalibs/bufalloc.h src/include/skalibs/genwrite.h
+src/libstddjb/genwrite_flush_buffer.o src/libstddjb/genwrite_flush_buffer.lo: src/libstddjb/genwrite_flush_buffer.c src/include/skalibs/buffer.h src/include/skalibs/genwrite.h
+src/libstddjb/genwrite_flush_stralloc.o src/libstddjb/genwrite_flush_stralloc.lo: src/libstddjb/genwrite_flush_stralloc.c src/include/skalibs/genwrite.h
+src/libstddjb/genwrite_put_bufalloc.o src/libstddjb/genwrite_put_bufalloc.lo: src/libstddjb/genwrite_put_bufalloc.c src/include/skalibs/bufalloc.h src/include/skalibs/genwrite.h
+src/libstddjb/genwrite_put_buffer.o src/libstddjb/genwrite_put_buffer.lo: src/libstddjb/genwrite_put_buffer.c src/include/skalibs/buffer.h src/include/skalibs/genwrite.h
+src/libstddjb/genwrite_put_stralloc.o src/libstddjb/genwrite_put_stralloc.lo: src/libstddjb/genwrite_put_stralloc.c src/include/skalibs/genwrite.h src/include/skalibs/stralloc.h
+src/libstddjb/genwrite_stderr.o src/libstddjb/genwrite_stderr.lo: src/libstddjb/genwrite_stderr.c src/include/skalibs/buffer.h src/include/skalibs/genwrite.h
+src/libstddjb/genwrite_stdout.o src/libstddjb/genwrite_stdout.lo: src/libstddjb/genwrite_stdout.c src/include/skalibs/buffer.h src/include/skalibs/genwrite.h
+src/libstddjb/getlnmax.o src/libstddjb/getlnmax.lo: src/libstddjb/getlnmax.c src/include/skalibs/buffer.h src/include/skalibs/bytestr.h src/include/skalibs/skamisc.h
+src/libstddjb/getlnmaxsep.o src/libstddjb/getlnmaxsep.lo: src/libstddjb/getlnmaxsep.c src/include/skalibs/buffer.h src/include/skalibs/bytestr.h src/include/skalibs/skamisc.h
+src/libstddjb/getpeereid.o src/libstddjb/getpeereid.lo: src/libstddjb/getpeereid.c src/include/skalibs/getpeereid.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
+src/libstddjb/int_scan.o src/libstddjb/int_scan.lo: src/libstddjb/int_scan.c src/libstddjb/fmtscan-internal.h src/include/skalibs/uint.h
+src/libstddjb/iobuffer_fill.o src/libstddjb/iobuffer_fill.lo: src/libstddjb/iobuffer_fill.c src/include/skalibs/iobuffer.h
+src/libstddjb/iobuffer_flush.o src/libstddjb/iobuffer_flush.lo: src/libstddjb/iobuffer_flush.c src/include/skalibs/iobuffer.h
+src/libstddjb/iobuffer_init.o src/libstddjb/iobuffer_init.lo: src/libstddjb/iobuffer_init.c src/include/skalibs/iobuffer.h
+src/libstddjb/iobuffer_kfromu.o src/libstddjb/iobuffer_kfromu.lo: src/libstddjb/iobuffer_kfromu.c src/include/skalibs/buffer.h src/include/skalibs/iobuffer.h src/include/skalibs/nonposix.h src/include/skalibs/siovec.h src/include/skalibs/sysdeps.h
+src/libstddjb/iobuffer_salvage.o src/libstddjb/iobuffer_salvage.lo: src/libstddjb/iobuffer_salvage.c src/include/skalibs/iobuffer.h
+src/libstddjb/iobuffer_ufromk.o src/libstddjb/iobuffer_ufromk.lo: src/libstddjb/iobuffer_ufromk.c src/include/skalibs/iobuffer.h src/include/skalibs/sysdeps.h
+src/libstddjb/iobufferk_fill.o src/libstddjb/iobufferk_fill.lo: src/libstddjb/iobufferk_fill.c src/include/skalibs/iobuffer.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
+src/libstddjb/iobufferk_finish.o src/libstddjb/iobufferk_finish.lo: src/libstddjb/iobufferk_finish.c src/include/skalibs/djbunix.h src/include/skalibs/iobuffer.h src/include/skalibs/sysdeps.h
+src/libstddjb/iobufferk_flush.o src/libstddjb/iobufferk_flush.lo: src/libstddjb/iobufferk_flush.c src/include/skalibs/iobuffer.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
+src/libstddjb/iobufferk_init.o src/libstddjb/iobufferk_init.lo: src/libstddjb/iobufferk_init.c src/include/skalibs/djbunix.h src/include/skalibs/iobuffer.h src/include/skalibs/sysdeps.h
+src/libstddjb/iobufferk_isworking.o src/libstddjb/iobufferk_isworking.lo: src/libstddjb/iobufferk_isworking.c src/include/skalibs/iobuffer.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
+src/libstddjb/iobufferk_nosys.o src/libstddjb/iobufferk_nosys.lo: src/libstddjb/iobufferk_nosys.c src/include/skalibs/iobuffer.h
+src/libstddjb/iobufferu_fill.o src/libstddjb/iobufferu_fill.lo: src/libstddjb/iobufferu_fill.c src/include/skalibs/buffer.h src/include/skalibs/iobuffer.h
+src/libstddjb/iobufferu_finish.o src/libstddjb/iobufferu_finish.lo: src/libstddjb/iobufferu_finish.c src/include/skalibs/alloc.h src/include/skalibs/iobuffer.h
+src/libstddjb/iobufferu_flush.o src/libstddjb/iobufferu_flush.lo: src/libstddjb/iobufferu_flush.c src/include/skalibs/buffer.h src/include/skalibs/iobuffer.h
+src/libstddjb/iobufferu_init.o src/libstddjb/iobufferu_init.lo: src/libstddjb/iobufferu_init.c src/include/skalibs/alloc.h src/include/skalibs/buffer.h src/include/skalibs/iobuffer.h
+src/libstddjb/iopause.o src/libstddjb/iopause.lo: src/libstddjb/iopause.c src/include/skalibs/config.h src/include/skalibs/iopause.h src/include/skalibs/sysdeps.h
+src/libstddjb/iopause_poll.o src/libstddjb/iopause_poll.lo: src/libstddjb/iopause_poll.c src/include/skalibs/iopause.h src/include/skalibs/tai.h
+src/libstddjb/iopause_ppoll.o src/libstddjb/iopause_ppoll.lo: src/libstddjb/iopause_ppoll.c src/include/skalibs/iopause.h src/include/skalibs/sysdeps.h src/include/skalibs/tai.h
+src/libstddjb/iopause_select.o src/libstddjb/iopause_select.lo: src/libstddjb/iopause_select.c src/include/skalibs/iopause.h src/include/skalibs/tai.h
+src/libstddjb/iopause_stamp.o src/libstddjb/iopause_stamp.lo: src/libstddjb/iopause_stamp.c src/include/skalibs/iopause.h src/include/skalibs/tai.h
+src/libstddjb/iovec_from_siovec.o src/libstddjb/iovec_from_siovec.lo: src/libstddjb/iovec_from_siovec.c src/include/skalibs/siovec.h
+src/libstddjb/ip46_scan.o src/libstddjb/ip46_scan.lo: src/libstddjb/ip46_scan.c src/include/skalibs/fmtscan.h src/include/skalibs/ip46.h
+src/libstddjb/ip46_scanlist.o src/libstddjb/ip46_scanlist.lo: src/libstddjb/ip46_scanlist.c src/include/skalibs/bytestr.h src/include/skalibs/fmtscan.h src/include/skalibs/ip46.h
+src/libstddjb/ip4_fmt.o src/libstddjb/ip4_fmt.lo: src/libstddjb/ip4_fmt.c src/include/skalibs/fmtscan.h src/include/skalibs/uint32.h
+src/libstddjb/ip4_fmtu32.o src/libstddjb/ip4_fmtu32.lo: src/libstddjb/ip4_fmtu32.c src/include/skalibs/fmtscan.h src/include/skalibs/uint32.h
+src/libstddjb/ip4_scan.o src/libstddjb/ip4_scan.lo: src/libstddjb/ip4_scan.c src/include/skalibs/uint.h
+src/libstddjb/ip4_scanlist.o src/libstddjb/ip4_scanlist.lo: src/libstddjb/ip4_scanlist.c src/include/skalibs/bytestr.h src/include/skalibs/fmtscan.h
+src/libstddjb/ip4_scanlist_u32.o src/libstddjb/ip4_scanlist_u32.lo: src/libstddjb/ip4_scanlist_u32.c src/include/skalibs/bytestr.h src/include/skalibs/fmtscan.h src/include/skalibs/uint32.h
+src/libstddjb/ip4_scanu32.o src/libstddjb/ip4_scanu32.lo: src/libstddjb/ip4_scanu32.c src/include/skalibs/fmtscan.h src/include/skalibs/uint32.h
+src/libstddjb/ip6_fmt.o src/libstddjb/ip6_fmt.lo: src/libstddjb/ip6_fmt.c src/include/skalibs/diuint.h src/include/skalibs/fmtscan.h
+src/libstddjb/ip6_scan.o src/libstddjb/ip6_scan.lo: src/libstddjb/ip6_scan.c src/include/skalibs/fmtscan.h src/include/skalibs/uint16.h
+src/libstddjb/ip6_scanlist.o src/libstddjb/ip6_scanlist.lo: src/libstddjb/ip6_scanlist.c src/include/skalibs/bytestr.h src/include/skalibs/fmtscan.h
+src/libstddjb/ipc_accept.o src/libstddjb/ipc_accept.lo: src/libstddjb/ipc_accept.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h src/include/skalibs/webipc.h
+src/libstddjb/ipc_bind.o src/libstddjb/ipc_bind.lo: src/libstddjb/ipc_bind.c src/include/skalibs/bytestr.h src/include/skalibs/error.h src/include/skalibs/nonposix.h src/include/skalibs/webipc.h
+src/libstddjb/ipc_bind_reuse.o src/libstddjb/ipc_bind_reuse.lo: src/libstddjb/ipc_bind_reuse.c src/include/skalibs/nonposix.h src/include/skalibs/webipc.h
+src/libstddjb/ipc_connect.o src/libstddjb/ipc_connect.lo: src/libstddjb/ipc_connect.c src/include/skalibs/bytestr.h src/include/skalibs/error.h src/include/skalibs/nonposix.h src/include/skalibs/webipc.h
+src/libstddjb/ipc_connected.o src/libstddjb/ipc_connected.lo: src/libstddjb/ipc_connected.c src/include/skalibs/allreadwrite.h src/include/skalibs/nonposix.h src/include/skalibs/webipc.h
+src/libstddjb/ipc_dgram.o src/libstddjb/ipc_dgram.lo: src/libstddjb/ipc_dgram.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/webipc.h
+src/libstddjb/ipc_eid.o src/libstddjb/ipc_eid.lo: src/libstddjb/ipc_eid.c src/include/skalibs/getpeereid.h src/include/skalibs/webipc.h
+src/libstddjb/ipc_listen.o src/libstddjb/ipc_listen.lo: src/libstddjb/ipc_listen.c src/include/skalibs/nonposix.h src/include/skalibs/webipc.h
+src/libstddjb/ipc_local.o src/libstddjb/ipc_local.lo: src/libstddjb/ipc_local.c src/include/skalibs/bytestr.h src/include/skalibs/nonposix.h src/include/skalibs/webipc.h
+src/libstddjb/ipc_pair.o src/libstddjb/ipc_pair.lo: src/libstddjb/ipc_pair.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/webipc.h
+src/libstddjb/ipc_recv.o src/libstddjb/ipc_recv.lo: src/libstddjb/ipc_recv.c src/include/skalibs/bytestr.h src/include/skalibs/error.h src/include/skalibs/nonposix.h src/include/skalibs/webipc.h
+src/libstddjb/ipc_send.o src/libstddjb/ipc_send.lo: src/libstddjb/ipc_send.c src/include/skalibs/bytestr.h src/include/skalibs/error.h src/include/skalibs/nonposix.h src/include/skalibs/webipc.h
+src/libstddjb/ipc_stream.o src/libstddjb/ipc_stream.lo: src/libstddjb/ipc_stream.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/webipc.h
+src/libstddjb/ipc_timed_connect.o src/libstddjb/ipc_timed_connect.lo: src/libstddjb/ipc_timed_connect.c src/include/skalibs/error.h src/include/skalibs/iopause.h src/include/skalibs/tai.h src/include/skalibs/webipc.h
+src/libstddjb/leapsecs_add.o src/libstddjb/leapsecs_add.lo: src/libstddjb/leapsecs_add.c src/libstddjb/djbtime-internal.h src/include/skalibs/uint64.h
+src/libstddjb/leapsecs_here.o src/libstddjb/leapsecs_here.lo: src/libstddjb/leapsecs_here.c src/libstddjb/djbtime-internal.h src/include/skalibs/uint64.h
+src/libstddjb/leapsecs_init.o src/libstddjb/leapsecs_init.lo: src/libstddjb/leapsecs_init.c src/libstddjb/djbtime-internal.h src/include/skalibs/djbunix.h src/include/skalibs/uint64.h
+src/libstddjb/leapsecs_sub.o src/libstddjb/leapsecs_sub.lo: src/libstddjb/leapsecs_sub.c src/libstddjb/djbtime-internal.h src/include/skalibs/uint64.h
+src/libstddjb/localtm_fmt.o src/libstddjb/localtm_fmt.lo: src/libstddjb/localtm_fmt.c src/include/skalibs/djbtime.h src/include/skalibs/uint.h
+src/libstddjb/localtm_from_ltm64.o src/libstddjb/localtm_from_ltm64.lo: src/libstddjb/localtm_from_ltm64.c src/include/skalibs/djbtime.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/localtm_from_sysclock.o src/libstddjb/localtm_from_sysclock.lo: src/libstddjb/localtm_from_sysclock.c src/include/skalibs/djbtime.h src/include/skalibs/uint64.h
+src/libstddjb/localtm_from_tai.o src/libstddjb/localtm_from_tai.lo: src/libstddjb/localtm_from_tai.c src/include/skalibs/djbtime.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/localtm_from_utc.o src/libstddjb/localtm_from_utc.lo: src/libstddjb/localtm_from_utc.c src/include/skalibs/djbtime.h src/include/skalibs/uint64.h
+src/libstddjb/localtm_scan.o src/libstddjb/localtm_scan.lo: src/libstddjb/localtm_scan.c src/include/skalibs/djbtime.h src/include/skalibs/uint.h
+src/libstddjb/localtmn_fmt.o src/libstddjb/localtmn_fmt.lo: src/libstddjb/localtmn_fmt.c src/include/skalibs/djbtime.h src/include/skalibs/uint32.h
+src/libstddjb/localtmn_from_sysclock.o src/libstddjb/localtmn_from_sysclock.lo: src/libstddjb/localtmn_from_sysclock.c src/include/skalibs/djbtime.h src/include/skalibs/tai.h
+src/libstddjb/localtmn_from_tain.o src/libstddjb/localtmn_from_tain.lo: src/libstddjb/localtmn_from_tain.c src/include/skalibs/djbtime.h src/include/skalibs/tai.h
+src/libstddjb/localtmn_scan.o src/libstddjb/localtmn_scan.lo: src/libstddjb/localtmn_scan.c src/include/skalibs/djbtime.h src/include/skalibs/uint32.h
+src/libstddjb/lock_ex.o src/libstddjb/lock_ex.lo: src/libstddjb/lock_ex.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
+src/libstddjb/lock_exnb.o src/libstddjb/lock_exnb.lo: src/libstddjb/lock_exnb.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
+src/libstddjb/lock_sh.o src/libstddjb/lock_sh.lo: src/libstddjb/lock_sh.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
+src/libstddjb/lock_shnb.o src/libstddjb/lock_shnb.lo: src/libstddjb/lock_shnb.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
+src/libstddjb/lock_un.o src/libstddjb/lock_un.lo: src/libstddjb/lock_un.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
+src/libstddjb/lolprintf.o src/libstddjb/lolprintf.lo: src/libstddjb/lolprintf.c src/include/skalibs/buffer.h src/include/skalibs/lolstdio.h
+src/libstddjb/long_fmt.o src/libstddjb/long_fmt.lo: src/libstddjb/long_fmt.c src/include/skalibs/ulong.h
+src/libstddjb/long_scan.o src/libstddjb/long_scan.lo: src/libstddjb/long_scan.c src/libstddjb/fmtscan-internal.h src/include/skalibs/ulong.h
+src/libstddjb/ltm64_from_localtm.o src/libstddjb/ltm64_from_localtm.lo: src/libstddjb/ltm64_from_localtm.c src/include/skalibs/djbtime.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/ltm64_from_sysclock.o src/libstddjb/ltm64_from_sysclock.lo: src/libstddjb/ltm64_from_sysclock.c src/include/skalibs/config.h src/include/skalibs/djbtime.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/ltm64_from_tai.o src/libstddjb/ltm64_from_tai.lo: src/libstddjb/ltm64_from_tai.c src/include/skalibs/config.h src/include/skalibs/djbtime.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/ltm64_from_utc.o src/libstddjb/ltm64_from_utc.lo: src/libstddjb/ltm64_from_utc.c src/include/skalibs/config.h src/libstddjb/djbtime-internal.h src/include/skalibs/djbtime.h src/include/skalibs/uint64.h
+src/libstddjb/mininetstring_read.o src/libstddjb/mininetstring_read.lo: src/libstddjb/mininetstring_read.c src/include/skalibs/allreadwrite.h src/include/skalibs/mininetstring.h src/include/skalibs/stralloc.h src/include/skalibs/uint32.h
+src/libstddjb/mininetstring_write.o src/libstddjb/mininetstring_write.lo: src/libstddjb/mininetstring_write.c src/include/skalibs/allreadwrite.h src/include/skalibs/mininetstring.h src/include/skalibs/uint16.h src/include/skalibs/uint32.h
+src/libstddjb/ndelay_off.o src/libstddjb/ndelay_off.lo: src/libstddjb/ndelay_off.c src/include/skalibs/djbunix.h
+src/libstddjb/ndelay_on.o src/libstddjb/ndelay_on.lo: src/libstddjb/ndelay_on.c src/include/skalibs/djbunix.h
+src/libstddjb/netstring_append.o src/libstddjb/netstring_append.lo: src/libstddjb/netstring_append.c src/include/skalibs/bytestr.h src/include/skalibs/netstring.h src/include/skalibs/stralloc.h src/include/skalibs/uint.h
+src/libstddjb/netstring_appendv.o src/libstddjb/netstring_appendv.lo: src/libstddjb/netstring_appendv.c src/include/skalibs/bytestr.h src/include/skalibs/netstring.h src/include/skalibs/siovec.h src/include/skalibs/stralloc.h src/include/skalibs/uint.h
+src/libstddjb/netstring_decode.o src/libstddjb/netstring_decode.lo: src/libstddjb/netstring_decode.c src/include/skalibs/fmtscan.h src/include/skalibs/netstring.h src/include/skalibs/stralloc.h src/include/skalibs/uint.h
+src/libstddjb/netstring_encode.o src/libstddjb/netstring_encode.lo: src/libstddjb/netstring_encode.c src/include/skalibs/netstring.h src/include/skalibs/stralloc.h src/include/skalibs/uint.h
+src/libstddjb/netstring_get.o src/libstddjb/netstring_get.lo: src/libstddjb/netstring_get.c src/include/skalibs/allreadwrite.h src/include/skalibs/buffer.h src/include/skalibs/bytestr.h src/include/skalibs/cbuffer.h src/include/skalibs/error.h src/include/skalibs/netstring.h src/include/skalibs/stralloc.h src/include/skalibs/uint.h
+src/libstddjb/netstring_put.o src/libstddjb/netstring_put.lo: src/libstddjb/netstring_put.c src/include/skalibs/buffer.h src/include/skalibs/netstring.h src/include/skalibs/uint.h
+src/libstddjb/ntp_from_tain.o src/libstddjb/ntp_from_tain.lo: src/libstddjb/ntp_from_tain.c src/include/skalibs/djbtime.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/open2.o src/libstddjb/open2.lo: src/libstddjb/open2.c src/include/skalibs/nonposix.h
+src/libstddjb/open3.o src/libstddjb/open3.lo: src/libstddjb/open3.c src/include/skalibs/nonposix.h
+src/libstddjb/open_append.o src/libstddjb/open_append.lo: src/libstddjb/open_append.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h
+src/libstddjb/open_create.o src/libstddjb/open_create.lo: src/libstddjb/open_create.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h
+src/libstddjb/open_excl.o src/libstddjb/open_excl.lo: src/libstddjb/open_excl.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h
+src/libstddjb/open_read.o src/libstddjb/open_read.lo: src/libstddjb/open_read.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h
+src/libstddjb/open_readb.o src/libstddjb/open_readb.lo: src/libstddjb/open_readb.c src/include/skalibs/djbunix.h
+src/libstddjb/open_trunc.o src/libstddjb/open_trunc.lo: src/libstddjb/open_trunc.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h
+src/libstddjb/open_write.o src/libstddjb/open_write.lo: src/libstddjb/open_write.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h
+src/libstddjb/openreadclose.o src/libstddjb/openreadclose.lo: src/libstddjb/openreadclose.c src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h
+src/libstddjb/openreadfileclose.o src/libstddjb/openreadfileclose.lo: src/libstddjb/openreadfileclose.c src/include/skalibs/allreadwrite.h src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h
+src/libstddjb/openreadnclose.o src/libstddjb/openreadnclose.lo: src/libstddjb/openreadnclose.c src/include/skalibs/allreadwrite.h src/include/skalibs/djbunix.h
+src/libstddjb/openslurpclose.o src/libstddjb/openslurpclose.lo: src/libstddjb/openslurpclose.c src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h
+src/libstddjb/openwritenclose_suffix.o src/libstddjb/openwritenclose_suffix.lo: src/libstddjb/openwritenclose_suffix.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h src/include/skalibs/uint64.h
+src/libstddjb/openwritenclose_unsafe.o src/libstddjb/openwritenclose_unsafe.lo: src/libstddjb/openwritenclose_unsafe.c src/include/skalibs/allreadwrite.h src/include/skalibs/djbunix.h src/include/skalibs/uint64.h
+src/libstddjb/pathexec.o src/libstddjb/pathexec.lo: src/libstddjb/pathexec.c src/include/skalibs/djbunix.h src/include/skalibs/env.h src/include/skalibs/environ.h
+src/libstddjb/pathexec0.o src/libstddjb/pathexec0.lo: src/libstddjb/pathexec0.c src/include/skalibs/djbunix.h
+src/libstddjb/pathexec0_run.o src/libstddjb/pathexec0_run.lo: src/libstddjb/pathexec0_run.c src/include/skalibs/djbunix.h
+src/libstddjb/pathexec_fromenv.o src/libstddjb/pathexec_fromenv.lo: src/libstddjb/pathexec_fromenv.c src/include/skalibs/djbunix.h src/include/skalibs/env.h src/include/skalibs/stralloc.h
+src/libstddjb/pathexec_r.o src/libstddjb/pathexec_r.lo: src/libstddjb/pathexec_r.c src/include/skalibs/djbunix.h
+src/libstddjb/pathexec_r_name.o src/libstddjb/pathexec_r_name.lo: src/libstddjb/pathexec_r_name.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h src/include/skalibs/env.h
+src/libstddjb/pathexec_run.o src/libstddjb/pathexec_run.lo: src/libstddjb/pathexec_run.c src/include/skalibs/config.h src/include/skalibs/djbunix.h src/include/skalibs/env.h
+src/libstddjb/pipe_internal.o src/libstddjb/pipe_internal.lo: src/libstddjb/pipe_internal.c src/include/skalibs/djbunix.h src/include/skalibs/sysdeps.h
+src/libstddjb/prog.o src/libstddjb/prog.lo: src/libstddjb/prog.c src/include/skalibs/strerr2.h
+src/libstddjb/prot.o src/libstddjb/prot.lo: src/libstddjb/prot.c src/include/skalibs/djbunix.h
+src/libstddjb/prot_grps.o src/libstddjb/prot_grps.lo: src/libstddjb/prot_grps.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/setgroups.h
+src/libstddjb/prot_readgroups.o src/libstddjb/prot_readgroups.lo: src/libstddjb/prot_readgroups.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h
+src/libstddjb/realpath.o src/libstddjb/realpath.lo: src/libstddjb/realpath.c src/include/skalibs/djbunix.h src/include/skalibs/skamisc.h
+src/libstddjb/realpath_tmp.o src/libstddjb/realpath_tmp.lo: src/libstddjb/realpath_tmp.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h
+src/libstddjb/rm_rf.o src/libstddjb/rm_rf.lo: src/libstddjb/rm_rf.c src/include/skalibs/djbunix.h src/include/skalibs/skamisc.h
+src/libstddjb/rm_rf_in_tmp.o src/libstddjb/rm_rf_in_tmp.lo: src/libstddjb/rm_rf_in_tmp.c src/include/skalibs/bytestr.h src/include/skalibs/direntry.h src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h
+src/libstddjb/rm_rf_tmp.o src/libstddjb/rm_rf_tmp.lo: src/libstddjb/rm_rf_tmp.c src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h
+src/libstddjb/rmstar.o src/libstddjb/rmstar.lo: src/libstddjb/rmstar.c src/include/skalibs/djbunix.h src/include/skalibs/skamisc.h
+src/libstddjb/sabasename.o src/libstddjb/sabasename.lo: src/libstddjb/sabasename.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h
+src/libstddjb/sadirname.o src/libstddjb/sadirname.lo: src/libstddjb/sadirname.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h
+src/libstddjb/sagetcwd.o src/libstddjb/sagetcwd.lo: src/libstddjb/sagetcwd.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h
+src/libstddjb/sagethostname.o src/libstddjb/sagethostname.lo: src/libstddjb/sagethostname.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h
+src/libstddjb/sanitize_read.o src/libstddjb/sanitize_read.lo: src/libstddjb/sanitize_read.c src/include/skalibs/allreadwrite.h src/include/skalibs/error.h
+src/libstddjb/sareadlink.o src/libstddjb/sareadlink.lo: src/libstddjb/sareadlink.c src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h
+src/libstddjb/satmp.o src/libstddjb/satmp.lo: src/libstddjb/satmp.c src/include/skalibs/skamisc.h src/include/skalibs/stralloc.h
+src/libstddjb/sauniquename.o src/libstddjb/sauniquename.lo: src/libstddjb/sauniquename.c src/include/skalibs/djbunix.h src/include/skalibs/skamisc.h src/include/skalibs/stralloc.h src/include/skalibs/tai.h src/include/skalibs/uint.h
+src/libstddjb/seek_cur.o src/libstddjb/seek_cur.lo: src/libstddjb/seek_cur.c src/include/skalibs/djbunix.h
+src/libstddjb/seek_set.o src/libstddjb/seek_set.lo: src/libstddjb/seek_set.c src/include/skalibs/djbunix.h
+src/libstddjb/selfpipe_finish.o src/libstddjb/selfpipe_finish.lo: src/libstddjb/selfpipe_finish.c src/include/skalibs/djbunix.h src/include/skalibs/nsig.h src/libstddjb/selfpipe-internal.h src/include/skalibs/selfpipe.h src/include/skalibs/sig.h src/include/skalibs/sysdeps.h
+src/libstddjb/selfpipe_init.o src/libstddjb/selfpipe_init.lo: src/libstddjb/selfpipe_init.c src/include/skalibs/djbunix.h src/libstddjb/selfpipe-internal.h src/include/skalibs/selfpipe.h src/include/skalibs/sysdeps.h
+src/libstddjb/selfpipe_internal.o src/libstddjb/selfpipe_internal.lo: src/libstddjb/selfpipe_internal.c src/include/skalibs/allreadwrite.h src/include/skalibs/djbunix.h src/libstddjb/selfpipe-internal.h src/include/skalibs/sysdeps.h
+src/libstddjb/selfpipe_read.o src/libstddjb/selfpipe_read.lo: src/libstddjb/selfpipe_read.c src/include/skalibs/allreadwrite.h src/libstddjb/selfpipe-internal.h src/include/skalibs/selfpipe.h src/include/skalibs/sysdeps.h
+src/libstddjb/selfpipe_trap.o src/libstddjb/selfpipe_trap.lo: src/libstddjb/selfpipe_trap.c src/libstddjb/selfpipe-internal.h src/include/skalibs/selfpipe.h src/include/skalibs/sig.h src/include/skalibs/sysdeps.h
+src/libstddjb/selfpipe_trapset.o src/libstddjb/selfpipe_trapset.lo: src/libstddjb/selfpipe_trapset.c src/include/skalibs/nsig.h src/libstddjb/selfpipe-internal.h src/include/skalibs/selfpipe.h src/include/skalibs/sig.h src/include/skalibs/sysdeps.h
+src/libstddjb/selfpipe_untrap.o src/libstddjb/selfpipe_untrap.lo: src/libstddjb/selfpipe_untrap.c src/libstddjb/selfpipe-internal.h src/include/skalibs/selfpipe.h src/include/skalibs/sig.h src/include/skalibs/sysdeps.h
+src/libstddjb/sgetopt.o src/libstddjb/sgetopt.lo: src/libstddjb/sgetopt.c src/include/skalibs/buffer.h src/include/skalibs/sgetopt.h
+src/libstddjb/short_scan.o src/libstddjb/short_scan.lo: src/libstddjb/short_scan.c src/libstddjb/fmtscan-internal.h src/include/skalibs/ushort.h
+src/libstddjb/sig.o src/libstddjb/sig.lo: src/libstddjb/sig.c src/include/skalibs/sig.h
+src/libstddjb/sig_block.o src/libstddjb/sig_block.lo: src/libstddjb/sig_block.c src/include/skalibs/sig.h
+src/libstddjb/sig_blocknone.o src/libstddjb/sig_blocknone.lo: src/libstddjb/sig_blocknone.c src/include/skalibs/sig.h
+src/libstddjb/sig_blockset.o src/libstddjb/sig_blockset.lo: src/libstddjb/sig_blockset.c src/include/skalibs/sig.h
+src/libstddjb/sig_catch.o src/libstddjb/sig_catch.lo: src/libstddjb/sig_catch.c src/include/skalibs/sig.h
+src/libstddjb/sig_pause.o src/libstddjb/sig_pause.lo: src/libstddjb/sig_pause.c src/include/skalibs/sig.h
+src/libstddjb/sig_push.o src/libstddjb/sig_push.lo: src/libstddjb/sig_push.c src/include/skalibs/sig.h
+src/libstddjb/sig_restoreto.o src/libstddjb/sig_restoreto.lo: src/libstddjb/sig_restoreto.c src/include/skalibs/sig.h
+src/libstddjb/sig_shield.o src/libstddjb/sig_shield.lo: src/libstddjb/sig_shield.c src/include/skalibs/sig.h
+src/libstddjb/sig_stack.o src/libstddjb/sig_stack.lo: src/libstddjb/sig_stack.c src/include/skalibs/nsig.h src/include/skalibs/sig.h
+src/libstddjb/sig_unblock.o src/libstddjb/sig_unblock.lo: src/libstddjb/sig_unblock.c src/include/skalibs/sig.h
+src/libstddjb/sig_unshield.o src/libstddjb/sig_unshield.lo: src/libstddjb/sig_unshield.c src/include/skalibs/sig.h
+src/libstddjb/sigfpe.o src/libstddjb/sigfpe.lo: src/libstddjb/sigfpe.c src/include/skalibs/segfault.h
+src/libstddjb/sigsegv.o src/libstddjb/sigsegv.lo: src/libstddjb/sigsegv.c src/include/skalibs/segfault.h
+src/libstddjb/siovec_bytechr.o src/libstddjb/siovec_bytechr.lo: src/libstddjb/siovec_bytechr.c src/include/skalibs/bytestr.h src/include/skalibs/siovec.h
+src/libstddjb/siovec_bytein.o src/libstddjb/siovec_bytein.lo: src/libstddjb/siovec_bytein.c src/include/skalibs/bytestr.h src/include/skalibs/siovec.h
+src/libstddjb/siovec_deal.o src/libstddjb/siovec_deal.lo: src/libstddjb/siovec_deal.c src/include/skalibs/bytestr.h src/include/skalibs/siovec.h
+src/libstddjb/siovec_from_iovec.o src/libstddjb/siovec_from_iovec.lo: src/libstddjb/siovec_from_iovec.c src/include/skalibs/siovec.h
+src/libstddjb/siovec_gather.o src/libstddjb/siovec_gather.lo: src/libstddjb/siovec_gather.c src/include/skalibs/bytestr.h src/include/skalibs/siovec.h
+src/libstddjb/siovec_len.o src/libstddjb/siovec_len.lo: src/libstddjb/siovec_len.c src/include/skalibs/siovec.h
+src/libstddjb/siovec_scatter.o src/libstddjb/siovec_scatter.lo: src/libstddjb/siovec_scatter.c src/include/skalibs/bytestr.h src/include/skalibs/siovec.h
+src/libstddjb/siovec_seek.o src/libstddjb/siovec_seek.lo: src/libstddjb/siovec_seek.c src/include/skalibs/bytestr.h src/include/skalibs/siovec.h
+src/libstddjb/skagetln.o src/libstddjb/skagetln.lo: src/libstddjb/skagetln.c src/include/skalibs/buffer.h src/include/skalibs/siovec.h src/include/skalibs/skamisc.h src/include/skalibs/stralloc.h
+src/libstddjb/skagetlnsep.o src/libstddjb/skagetlnsep.lo: src/libstddjb/skagetlnsep.c src/include/skalibs/buffer.h src/include/skalibs/siovec.h src/include/skalibs/skamisc.h src/include/skalibs/stralloc.h
+src/libstddjb/skasig_dfl.o src/libstddjb/skasig_dfl.lo: src/libstddjb/skasig_dfl.c src/include/skalibs/sig.h
+src/libstddjb/skasigaction.o src/libstddjb/skasigaction.lo: src/libstddjb/skasigaction.c src/include/skalibs/sig.h src/include/skalibs/sysdeps.h
+src/libstddjb/slurp.o src/libstddjb/slurp.lo: src/libstddjb/slurp.c src/include/skalibs/allreadwrite.h src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h
+src/libstddjb/socket_accept4.o src/libstddjb/socket_accept4.lo: src/libstddjb/socket_accept4.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h src/include/skalibs/sysdeps.h src/include/skalibs/uint16.h
+src/libstddjb/socket_accept4_u32.o src/libstddjb/socket_accept4_u32.lo: src/libstddjb/socket_accept4_u32.c src/include/skalibs/socket.h src/include/skalibs/uint16.h src/include/skalibs/uint32.h
+src/libstddjb/socket_accept6.o src/libstddjb/socket_accept6.lo: src/libstddjb/socket_accept6.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h src/include/skalibs/ip46.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h src/include/skalibs/sysdeps.h src/include/skalibs/uint16.h
+src/libstddjb/socket_bind4.o src/libstddjb/socket_bind4.lo: src/libstddjb/socket_bind4.c src/include/skalibs/bytestr.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h src/include/skalibs/uint16.h
+src/libstddjb/socket_bind4r.o src/libstddjb/socket_bind4r.lo: src/libstddjb/socket_bind4r.c src/include/skalibs/nonposix.h src/include/skalibs/socket.h src/include/skalibs/uint16.h
+src/libstddjb/socket_bind6.o src/libstddjb/socket_bind6.lo: src/libstddjb/socket_bind6.c src/include/skalibs/bytestr.h src/include/skalibs/ip46.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h src/include/skalibs/uint16.h
+src/libstddjb/socket_bind6r.o src/libstddjb/socket_bind6r.lo: src/libstddjb/socket_bind6r.c src/include/skalibs/nonposix.h src/include/skalibs/socket.h src/include/skalibs/uint16.h
+src/libstddjb/socket_conn4.o src/libstddjb/socket_conn4.lo: src/libstddjb/socket_conn4.c src/include/skalibs/bytestr.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h src/include/skalibs/uint16.h
+src/libstddjb/socket_conn4_u32.o src/libstddjb/socket_conn4_u32.lo: src/libstddjb/socket_conn4_u32.c src/include/skalibs/socket.h src/include/skalibs/uint16.h src/include/skalibs/uint32.h
+src/libstddjb/socket_conn6.o src/libstddjb/socket_conn6.lo: src/libstddjb/socket_conn6.c src/include/skalibs/bytestr.h src/include/skalibs/ip46.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h src/include/skalibs/uint16.h
+src/libstddjb/socket_connected.o src/libstddjb/socket_connected.lo: src/libstddjb/socket_connected.c src/include/skalibs/allreadwrite.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h
+src/libstddjb/socket_deadlineconnstamp4.o src/libstddjb/socket_deadlineconnstamp4.lo: src/libstddjb/socket_deadlineconnstamp4.c src/include/skalibs/error.h src/include/skalibs/socket.h src/include/skalibs/tai.h src/include/skalibs/uint16.h
+src/libstddjb/socket_deadlineconnstamp46.o src/libstddjb/socket_deadlineconnstamp46.lo: src/libstddjb/socket_deadlineconnstamp46.c src/include/skalibs/error.h src/include/skalibs/ip46.h src/include/skalibs/socket.h src/include/skalibs/tai.h src/include/skalibs/uint16.h
+src/libstddjb/socket_deadlineconnstamp4_u32.o src/libstddjb/socket_deadlineconnstamp4_u32.lo: src/libstddjb/socket_deadlineconnstamp4_u32.c src/include/skalibs/socket.h src/include/skalibs/tai.h src/include/skalibs/uint16.h src/include/skalibs/uint32.h
+src/libstddjb/socket_deadlineconnstamp6.o src/libstddjb/socket_deadlineconnstamp6.lo: src/libstddjb/socket_deadlineconnstamp6.c src/include/skalibs/error.h src/include/skalibs/socket.h src/include/skalibs/tai.h src/include/skalibs/uint16.h
+src/libstddjb/socket_delay.o src/libstddjb/socket_delay.lo: src/libstddjb/socket_delay.c src/include/skalibs/nonposix.h src/include/skalibs/socket.h
+src/libstddjb/socket_internal.o src/libstddjb/socket_internal.lo: src/libstddjb/socket_internal.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
+src/libstddjb/socket_ioloop.o src/libstddjb/socket_ioloop.lo: src/libstddjb/socket_ioloop.c src/include/skalibs/error.h src/include/skalibs/iopause.h src/include/skalibs/socket.h src/include/skalibs/tai.h src/include/skalibs/uint16.h
+src/libstddjb/socket_ioloop_send4.o src/libstddjb/socket_ioloop_send4.lo: src/libstddjb/socket_ioloop_send4.c src/include/skalibs/socket.h
+src/libstddjb/socket_ioloop_send6.o src/libstddjb/socket_ioloop_send6.lo: src/libstddjb/socket_ioloop_send6.c src/include/skalibs/socket.h
+src/libstddjb/socket_local4.o src/libstddjb/socket_local4.lo: src/libstddjb/socket_local4.c src/include/skalibs/bytestr.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h src/include/skalibs/uint16.h
+src/libstddjb/socket_local46.o src/libstddjb/socket_local46.lo: src/libstddjb/socket_local46.c src/include/skalibs/bytestr.h src/include/skalibs/ip46.h src/include/skalibs/nonposix.h src/include/skalibs/uint16.h
+src/libstddjb/socket_local6.o src/libstddjb/socket_local6.lo: src/libstddjb/socket_local6.c src/include/skalibs/bytestr.h src/include/skalibs/ip46.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h src/include/skalibs/uint16.h
+src/libstddjb/socket_recv4.o src/libstddjb/socket_recv4.lo: src/libstddjb/socket_recv4.c src/include/skalibs/bytestr.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h src/include/skalibs/uint16.h
+src/libstddjb/socket_recv6.o src/libstddjb/socket_recv6.lo: src/libstddjb/socket_recv6.c src/include/skalibs/bytestr.h src/include/skalibs/ip46.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h src/include/skalibs/uint16.h
+src/libstddjb/socket_remote4.o src/libstddjb/socket_remote4.lo: src/libstddjb/socket_remote4.c src/include/skalibs/bytestr.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h src/include/skalibs/uint16.h
+src/libstddjb/socket_remote46.o src/libstddjb/socket_remote46.lo: src/libstddjb/socket_remote46.c src/include/skalibs/bytestr.h src/include/skalibs/ip46.h src/include/skalibs/nonposix.h src/include/skalibs/uint16.h
+src/libstddjb/socket_remote6.o src/libstddjb/socket_remote6.lo: src/libstddjb/socket_remote6.c src/include/skalibs/bytestr.h src/include/skalibs/ip46.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h src/include/skalibs/uint16.h
+src/libstddjb/socket_send4.o src/libstddjb/socket_send4.lo: src/libstddjb/socket_send4.c src/include/skalibs/bytestr.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h src/include/skalibs/uint16.h
+src/libstddjb/socket_send6.o src/libstddjb/socket_send6.lo: src/libstddjb/socket_send6.c src/include/skalibs/bytestr.h src/include/skalibs/ip46.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h src/include/skalibs/uint16.h
+src/libstddjb/socket_tcp4.o src/libstddjb/socket_tcp4.lo: src/libstddjb/socket_tcp4.c src/include/skalibs/nonposix.h src/include/skalibs/socket.h
+src/libstddjb/socket_tcp6.o src/libstddjb/socket_tcp6.lo: src/libstddjb/socket_tcp6.c src/include/skalibs/djbunix.h src/include/skalibs/ip46.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h
+src/libstddjb/socket_timeoutconn.o src/libstddjb/socket_timeoutconn.lo: src/libstddjb/socket_timeoutconn.c src/include/skalibs/socket.h src/include/skalibs/tai.h src/include/skalibs/uint16.h
+src/libstddjb/socket_tryr.o src/libstddjb/socket_tryr.lo: src/libstddjb/socket_tryr.c src/include/skalibs/nonposix.h src/include/skalibs/socket.h
+src/libstddjb/socket_udp4.o src/libstddjb/socket_udp4.lo: src/libstddjb/socket_udp4.c src/include/skalibs/nonposix.h src/include/skalibs/socket.h
+src/libstddjb/socket_udp6.o src/libstddjb/socket_udp6.lo: src/libstddjb/socket_udp6.c src/include/skalibs/djbunix.h src/include/skalibs/ip46.h src/include/skalibs/nonposix.h src/include/skalibs/socket.h
+src/libstddjb/socket_waitconn.o src/libstddjb/socket_waitconn.lo: src/libstddjb/socket_waitconn.c src/include/skalibs/allreadwrite.h src/include/skalibs/iopause.h src/include/skalibs/socket.h src/include/skalibs/tai.h
+src/libstddjb/socketpair_internal.o src/libstddjb/socketpair_internal.lo: src/libstddjb/socketpair_internal.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
+src/libstddjb/stamp.o src/libstddjb/stamp.lo: src/libstddjb/stamp.c src/include/skalibs/tai.h
+src/libstddjb/str_chr.o src/libstddjb/str_chr.lo: src/libstddjb/str_chr.c src/include/skalibs/bytestr.h src/include/skalibs/config.h
+src/libstddjb/str_cpy.o src/libstddjb/str_cpy.lo: src/libstddjb/str_cpy.c src/include/skalibs/bytestr.h src/include/skalibs/config.h
+src/libstddjb/str_diff.o src/libstddjb/str_diff.lo: src/libstddjb/str_diff.c src/include/skalibs/bytestr.h src/include/skalibs/config.h
+src/libstddjb/str_diffn.o src/libstddjb/str_diffn.lo: src/libstddjb/str_diffn.c src/include/skalibs/bytestr.h src/include/skalibs/config.h
+src/libstddjb/str_fmt.o src/libstddjb/str_fmt.lo: src/libstddjb/str_fmt.c src/include/skalibs/bytestr.h src/include/skalibs/fmtscan.h
+src/libstddjb/str_len.o src/libstddjb/str_len.lo: src/libstddjb/str_len.c src/include/skalibs/bytestr.h src/include/skalibs/config.h
+src/libstddjb/str_rchr.o src/libstddjb/str_rchr.lo: src/libstddjb/str_rchr.c src/include/skalibs/bytestr.h src/include/skalibs/config.h
+src/libstddjb/str_start.o src/libstddjb/str_start.lo: src/libstddjb/str_start.c src/include/skalibs/bytestr.h
+src/libstddjb/str_strn.o src/libstddjb/str_strn.lo: src/libstddjb/str_strn.c src/include/skalibs/bytestr.h src/include/skalibs/config.h
+src/libstddjb/stralloc_append.o src/libstddjb/stralloc_append.lo: src/libstddjb/stralloc_append.c src/include/skalibs/stralloc.h
+src/libstddjb/stralloc_catb.o src/libstddjb/stralloc_catb.lo: src/libstddjb/stralloc_catb.c src/include/skalibs/bytestr.h src/include/skalibs/stralloc.h
+src/libstddjb/stralloc_catv.o src/libstddjb/stralloc_catv.lo: src/libstddjb/stralloc_catv.c src/include/skalibs/bytestr.h src/include/skalibs/siovec.h src/include/skalibs/stralloc.h
+src/libstddjb/stralloc_copyb.o src/libstddjb/stralloc_copyb.lo: src/libstddjb/stralloc_copyb.c src/include/skalibs/bytestr.h src/include/skalibs/stralloc.h
+src/libstddjb/stralloc_free.o src/libstddjb/stralloc_free.lo: src/libstddjb/stralloc_free.c src/include/skalibs/alloc.h src/include/skalibs/stralloc.h
+src/libstddjb/stralloc_insertb.o src/libstddjb/stralloc_insertb.lo: src/libstddjb/stralloc_insertb.c src/include/skalibs/bytestr.h src/include/skalibs/stralloc.h
+src/libstddjb/stralloc_ready_tuned.o src/libstddjb/stralloc_ready_tuned.lo: src/libstddjb/stralloc_ready_tuned.c src/include/skalibs/alloc.h src/include/skalibs/stralloc.h
+src/libstddjb/stralloc_reverse.o src/libstddjb/stralloc_reverse.lo: src/libstddjb/stralloc_reverse.c src/include/skalibs/bytestr.h src/include/skalibs/stralloc.h
+src/libstddjb/stralloc_reverse_blocks.o src/libstddjb/stralloc_reverse_blocks.lo: src/libstddjb/stralloc_reverse_blocks.c src/include/skalibs/bytestr.h src/include/skalibs/stralloc.h
+src/libstddjb/stralloc_shrink.o src/libstddjb/stralloc_shrink.lo: src/libstddjb/stralloc_shrink.c src/include/skalibs/alloc.h src/include/skalibs/stralloc.h
+src/libstddjb/stralloc_zero.o src/libstddjb/stralloc_zero.lo: src/libstddjb/stralloc_zero.c src/include/skalibs/stralloc.h
+src/libstddjb/strerr.o src/libstddjb/strerr.lo: src/libstddjb/strerr.c src/include/skalibs/buffer.h src/include/skalibs/strerr.h
+src/libstddjb/strerr_sys.o src/libstddjb/strerr_sys.lo: src/libstddjb/strerr_sys.c src/include/skalibs/error.h src/include/skalibs/strerr.h
+src/libstddjb/string_format.o src/libstddjb/string_format.lo: src/libstddjb/string_format.c src/include/skalibs/bytestr.h src/include/skalibs/stralloc.h
+src/libstddjb/string_quote.o src/libstddjb/string_quote.lo: src/libstddjb/string_quote.c src/include/skalibs/skamisc.h src/include/skalibs/stralloc.h
+src/libstddjb/string_quote_nodelim.o src/libstddjb/string_quote_nodelim.lo: src/libstddjb/string_quote_nodelim.c src/include/skalibs/skamisc.h src/include/skalibs/stralloc.h
+src/libstddjb/string_quote_nodelim_mustquote.o src/libstddjb/string_quote_nodelim_mustquote.lo: src/libstddjb/string_quote_nodelim_mustquote.c src/include/skalibs/bytestr.h src/include/skalibs/fmtscan.h src/include/skalibs/skamisc.h src/include/skalibs/stralloc.h
+src/libstddjb/string_unquote.o src/libstddjb/string_unquote.lo: src/libstddjb/string_unquote.c src/include/skalibs/bytestr.h src/include/skalibs/skamisc.h
+src/libstddjb/string_unquote_nodelim.o src/libstddjb/string_unquote_nodelim.lo: src/libstddjb/string_unquote_nodelim.c src/include/skalibs/skamisc.h
+src/libstddjb/string_unquote_withdelim.o src/libstddjb/string_unquote_withdelim.lo: src/libstddjb/string_unquote_withdelim.c src/include/skalibs/bytestr.h src/include/skalibs/error.h src/include/skalibs/fmtscan.h src/include/skalibs/skamisc.h
+src/libstddjb/strn_fmt.o src/libstddjb/strn_fmt.lo: src/libstddjb/strn_fmt.c src/include/skalibs/fmtscan.h src/include/skalibs/uint.h
+src/libstddjb/subgetopt.o src/libstddjb/subgetopt.lo: src/libstddjb/subgetopt.c src/include/skalibs/sgetopt.h
+src/libstddjb/subgetopt_here.o src/libstddjb/subgetopt_here.lo: src/libstddjb/subgetopt_here.c src/include/skalibs/sgetopt.h
+src/libstddjb/sysclock_from_localtm.o src/libstddjb/sysclock_from_localtm.lo: src/libstddjb/sysclock_from_localtm.c src/include/skalibs/djbtime.h src/include/skalibs/uint64.h
+src/libstddjb/sysclock_from_localtmn.o src/libstddjb/sysclock_from_localtmn.lo: src/libstddjb/sysclock_from_localtmn.c src/include/skalibs/djbtime.h src/include/skalibs/tai.h
+src/libstddjb/sysclock_from_ltm64.o src/libstddjb/sysclock_from_ltm64.lo: src/libstddjb/sysclock_from_ltm64.c src/include/skalibs/config.h src/include/skalibs/djbtime.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/sysclock_from_tai.o src/libstddjb/sysclock_from_tai.lo: src/libstddjb/sysclock_from_tai.c src/include/skalibs/config.h src/include/skalibs/djbtime.h src/include/skalibs/tai.h
+src/libstddjb/sysclock_from_utc.o src/libstddjb/sysclock_from_utc.lo: src/libstddjb/sysclock_from_utc.c src/include/skalibs/config.h src/include/skalibs/djbtime.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/sysclock_get.o src/libstddjb/sysclock_get.lo: src/libstddjb/sysclock_get.c src/include/skalibs/config.h src/include/skalibs/sysdeps.h src/include/skalibs/tai.h
+src/libstddjb/sysclock_set.o src/libstddjb/sysclock_set.lo: src/libstddjb/sysclock_set.c src/include/skalibs/config.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h src/include/skalibs/tai.h
+src/libstddjb/tai_add.o src/libstddjb/tai_add.lo: src/libstddjb/tai_add.c src/include/skalibs/tai.h
+src/libstddjb/tai_from_localtm.o src/libstddjb/tai_from_localtm.lo: src/libstddjb/tai_from_localtm.c src/include/skalibs/djbtime.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/tai_from_ltm64.o src/libstddjb/tai_from_ltm64.lo: src/libstddjb/tai_from_ltm64.c src/include/skalibs/config.h src/include/skalibs/djbtime.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/tai_from_sysclock.o src/libstddjb/tai_from_sysclock.lo: src/libstddjb/tai_from_sysclock.c src/include/skalibs/config.h src/include/skalibs/djbtime.h src/include/skalibs/tai.h
+src/libstddjb/tai_from_timespec.o src/libstddjb/tai_from_timespec.lo: src/libstddjb/tai_from_timespec.c src/include/skalibs/tai.h
+src/libstddjb/tai_from_timeval.o src/libstddjb/tai_from_timeval.lo: src/libstddjb/tai_from_timeval.c src/include/skalibs/tai.h
+src/libstddjb/tai_from_utc.o src/libstddjb/tai_from_utc.lo: src/libstddjb/tai_from_utc.c src/libstddjb/djbtime-internal.h src/include/skalibs/djbtime.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/tai_now.o src/libstddjb/tai_now.lo: src/libstddjb/tai_now.c src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/tai_pack.o src/libstddjb/tai_pack.lo: src/libstddjb/tai_pack.c src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/tai_pack_little.o src/libstddjb/tai_pack_little.lo: src/libstddjb/tai_pack_little.c src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/tai_relative_from_timespec.o src/libstddjb/tai_relative_from_timespec.lo: src/libstddjb/tai_relative_from_timespec.c src/include/skalibs/tai.h
+src/libstddjb/tai_relative_from_timeval.o src/libstddjb/tai_relative_from_timeval.lo: src/libstddjb/tai_relative_from_timeval.c src/include/skalibs/tai.h
+src/libstddjb/tai_sub.o src/libstddjb/tai_sub.lo: src/libstddjb/tai_sub.c src/include/skalibs/tai.h
+src/libstddjb/tai_unpack.o src/libstddjb/tai_unpack.lo: src/libstddjb/tai_unpack.c src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/tai_unpack_little.o src/libstddjb/tai_unpack_little.lo: src/libstddjb/tai_unpack_little.c src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/tain_add.o src/libstddjb/tain_add.lo: src/libstddjb/tain_add.c src/include/skalibs/tai.h
+src/libstddjb/tain_addsec.o src/libstddjb/tain_addsec.lo: src/libstddjb/tain_addsec.c src/include/skalibs/tai.h
+src/libstddjb/tain_approx.o src/libstddjb/tain_approx.lo: src/libstddjb/tain_approx.c src/include/skalibs/tai.h
+src/libstddjb/tain_clockmon.o src/libstddjb/tain_clockmon.lo: src/libstddjb/tain_clockmon.c src/include/skalibs/sysdeps.h src/include/skalibs/tai.h
+src/libstddjb/tain_fmt.o src/libstddjb/tain_fmt.lo: src/libstddjb/tain_fmt.c src/include/skalibs/fmtscan.h src/include/skalibs/tai.h
+src/libstddjb/tain_frac.o src/libstddjb/tain_frac.lo: src/libstddjb/tain_frac.c src/include/skalibs/tai.h
+src/libstddjb/tain_from_localtmn.o src/libstddjb/tain_from_localtmn.lo: src/libstddjb/tain_from_localtmn.c src/include/skalibs/djbtime.h src/include/skalibs/tai.h
+src/libstddjb/tain_from_millisecs.o src/libstddjb/tain_from_millisecs.lo: src/libstddjb/tain_from_millisecs.c src/include/skalibs/tai.h
+src/libstddjb/tain_from_ntp.o src/libstddjb/tain_from_ntp.lo: src/libstddjb/tain_from_ntp.c src/include/skalibs/djbtime.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/tain_from_timespec.o src/libstddjb/tain_from_timespec.lo: src/libstddjb/tain_from_timespec.c src/include/skalibs/tai.h
+src/libstddjb/tain_from_timeval.o src/libstddjb/tain_from_timeval.lo: src/libstddjb/tain_from_timeval.c src/include/skalibs/tai.h
+src/libstddjb/tain_half.o src/libstddjb/tain_half.lo: src/libstddjb/tain_half.c src/include/skalibs/tai.h
+src/libstddjb/tain_infinite_relative.o src/libstddjb/tain_infinite_relative.lo: src/libstddjb/tain_infinite_relative.c src/include/skalibs/tai.h
+src/libstddjb/tain_less.o src/libstddjb/tain_less.lo: src/libstddjb/tain_less.c src/include/skalibs/tai.h
+src/libstddjb/tain_nano500.o src/libstddjb/tain_nano500.lo: src/libstddjb/tain_nano500.c src/include/skalibs/tai.h
+src/libstddjb/tain_now.o src/libstddjb/tain_now.lo: src/libstddjb/tain_now.c src/include/skalibs/config.h src/include/skalibs/sysdeps.h src/include/skalibs/tai.h
+src/libstddjb/tain_pack.o src/libstddjb/tain_pack.lo: src/libstddjb/tain_pack.c src/include/skalibs/tai.h src/include/skalibs/uint32.h
+src/libstddjb/tain_pack_little.o src/libstddjb/tain_pack_little.lo: src/libstddjb/tain_pack_little.c src/include/skalibs/tai.h src/include/skalibs/uint32.h
+src/libstddjb/tain_relative_from_timespec.o src/libstddjb/tain_relative_from_timespec.lo: src/libstddjb/tain_relative_from_timespec.c src/include/skalibs/tai.h
+src/libstddjb/tain_relative_from_timeval.o src/libstddjb/tain_relative_from_timeval.lo: src/libstddjb/tain_relative_from_timeval.c src/include/skalibs/tai.h
+src/libstddjb/tain_scan.o src/libstddjb/tain_scan.lo: src/libstddjb/tain_scan.c src/include/skalibs/fmtscan.h src/include/skalibs/tai.h
+src/libstddjb/tain_setnow.o src/libstddjb/tain_setnow.lo: src/libstddjb/tain_setnow.c src/include/skalibs/tai.h
+src/libstddjb/tain_sub.o src/libstddjb/tain_sub.lo: src/libstddjb/tain_sub.c src/include/skalibs/tai.h
+src/libstddjb/tain_sysclock.o src/libstddjb/tain_sysclock.lo: src/libstddjb/tain_sysclock.c src/include/skalibs/tai.h
+src/libstddjb/tain_to_millisecs.o src/libstddjb/tain_to_millisecs.lo: src/libstddjb/tain_to_millisecs.c src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/tain_ulong.o src/libstddjb/tain_ulong.lo: src/libstddjb/tain_ulong.c src/include/skalibs/tai.h
+src/libstddjb/tain_unpack.o src/libstddjb/tain_unpack.lo: src/libstddjb/tain_unpack.c src/include/skalibs/tai.h src/include/skalibs/uint32.h
+src/libstddjb/tain_unpack_little.o src/libstddjb/tain_unpack_little.lo: src/libstddjb/tain_unpack_little.c src/include/skalibs/tai.h src/include/skalibs/uint32.h
+src/libstddjb/timespec_from_tai.o src/libstddjb/timespec_from_tai.lo: src/libstddjb/timespec_from_tai.c src/include/skalibs/tai.h
+src/libstddjb/timespec_from_tai_relative.o src/libstddjb/timespec_from_tai_relative.lo: src/libstddjb/timespec_from_tai_relative.c src/include/skalibs/sysdeps.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/timespec_from_tain.o src/libstddjb/timespec_from_tain.lo: src/libstddjb/timespec_from_tain.c src/include/skalibs/tai.h
+src/libstddjb/timespec_from_tain_relative.o src/libstddjb/timespec_from_tain_relative.lo: src/libstddjb/timespec_from_tain_relative.c src/include/skalibs/tai.h
+src/libstddjb/timestamp.o src/libstddjb/timestamp.lo: src/libstddjb/timestamp.c src/include/skalibs/tai.h
+src/libstddjb/timestamp_fmt.o src/libstddjb/timestamp_fmt.lo: src/libstddjb/timestamp_fmt.c src/include/skalibs/tai.h
+src/libstddjb/timestamp_r.o src/libstddjb/timestamp_r.lo: src/libstddjb/timestamp_r.c src/include/skalibs/tai.h
+src/libstddjb/timestamp_scan.o src/libstddjb/timestamp_scan.lo: src/libstddjb/timestamp_scan.c src/include/skalibs/tai.h
+src/libstddjb/timeval_from_tai.o src/libstddjb/timeval_from_tai.lo: src/libstddjb/timeval_from_tai.c src/include/skalibs/tai.h
+src/libstddjb/timeval_from_tai_relative.o src/libstddjb/timeval_from_tai_relative.lo: src/libstddjb/timeval_from_tai_relative.c src/include/skalibs/sysdeps.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/timeval_from_tain.o src/libstddjb/timeval_from_tain.lo: src/libstddjb/timeval_from_tain.c src/include/skalibs/tai.h
+src/libstddjb/timeval_from_tain_relative.o src/libstddjb/timeval_from_tain_relative.lo: src/libstddjb/timeval_from_tain_relative.c src/include/skalibs/tai.h
+src/libstddjb/ucharn_findlen.o src/libstddjb/ucharn_findlen.lo: src/libstddjb/ucharn_findlen.c src/include/skalibs/fmtscan.h
+src/libstddjb/ucharn_fmt.o src/libstddjb/ucharn_fmt.lo: src/libstddjb/ucharn_fmt.c src/include/skalibs/fmtscan.h
+src/libstddjb/ucharn_fmt_little.o src/libstddjb/ucharn_fmt_little.lo: src/libstddjb/ucharn_fmt_little.c src/include/skalibs/fmtscan.h
+src/libstddjb/ucharn_scan.o src/libstddjb/ucharn_scan.lo: src/libstddjb/ucharn_scan.c src/include/skalibs/fmtscan.h
+src/libstddjb/ucharn_scan_little.o src/libstddjb/ucharn_scan_little.lo: src/libstddjb/ucharn_scan_little.c src/include/skalibs/fmtscan.h
+src/libstddjb/ucspi_get.o src/libstddjb/ucspi_get.lo: src/libstddjb/ucspi_get.c src/include/skalibs/bytestr.h src/include/skalibs/env.h
+src/libstddjb/uint160_scan.o src/libstddjb/uint160_scan.lo: src/libstddjb/uint160_scan.c src/libstddjb/fmtscan-internal.h src/include/skalibs/uint16.h
+src/libstddjb/uint16_fmtlist.o src/libstddjb/uint16_fmtlist.lo: src/libstddjb/uint16_fmtlist.c src/libstddjb/fmtscan-internal.h src/include/skalibs/uint16.h
+src/libstddjb/uint16_pack.o src/libstddjb/uint16_pack.lo: src/libstddjb/uint16_pack.c src/include/skalibs/bytestr.h src/include/skalibs/uint16.h
+src/libstddjb/uint16_pack_big.o src/libstddjb/uint16_pack_big.lo: src/libstddjb/uint16_pack_big.c src/include/skalibs/bytestr.h src/include/skalibs/uint16.h
+src/libstddjb/uint16_reverse.o src/libstddjb/uint16_reverse.lo: src/libstddjb/uint16_reverse.c src/include/skalibs/uint16.h
+src/libstddjb/uint16_scan.o src/libstddjb/uint16_scan.lo: src/libstddjb/uint16_scan.c src/libstddjb/fmtscan-internal.h src/include/skalibs/uint16.h
+src/libstddjb/uint16_scanlist.o src/libstddjb/uint16_scanlist.lo: src/libstddjb/uint16_scanlist.c src/libstddjb/fmtscan-internal.h src/include/skalibs/uint16.h
+src/libstddjb/uint16_unpack.o src/libstddjb/uint16_unpack.lo: src/libstddjb/uint16_unpack.c src/include/skalibs/bytestr.h src/include/skalibs/uint16.h
+src/libstddjb/uint16_unpack_big.o src/libstddjb/uint16_unpack_big.lo: src/libstddjb/uint16_unpack_big.c src/include/skalibs/bytestr.h src/include/skalibs/uint16.h
+src/libstddjb/uint320_scan.o src/libstddjb/uint320_scan.lo: src/libstddjb/uint320_scan.c src/libstddjb/fmtscan-internal.h src/include/skalibs/uint32.h
+src/libstddjb/uint32_fmtlist.o src/libstddjb/uint32_fmtlist.lo: src/libstddjb/uint32_fmtlist.c src/libstddjb/fmtscan-internal.h src/include/skalibs/uint16.h
+src/libstddjb/uint32_pack.o src/libstddjb/uint32_pack.lo: src/libstddjb/uint32_pack.c src/include/skalibs/bytestr.h src/include/skalibs/uint32.h
+src/libstddjb/uint32_pack_big.o src/libstddjb/uint32_pack_big.lo: src/libstddjb/uint32_pack_big.c src/include/skalibs/bytestr.h src/include/skalibs/uint32.h
+src/libstddjb/uint32_reverse.o src/libstddjb/uint32_reverse.lo: src/libstddjb/uint32_reverse.c src/include/skalibs/uint32.h
+src/libstddjb/uint32_scan.o src/libstddjb/uint32_scan.lo: src/libstddjb/uint32_scan.c src/libstddjb/fmtscan-internal.h src/include/skalibs/uint32.h
+src/libstddjb/uint32_scanlist.o src/libstddjb/uint32_scanlist.lo: src/libstddjb/uint32_scanlist.c src/libstddjb/fmtscan-internal.h src/include/skalibs/uint16.h
+src/libstddjb/uint32_unpack.o src/libstddjb/uint32_unpack.lo: src/libstddjb/uint32_unpack.c src/include/skalibs/bytestr.h src/include/skalibs/uint32.h
+src/libstddjb/uint32_unpack_big.o src/libstddjb/uint32_unpack_big.lo: src/libstddjb/uint32_unpack_big.c src/include/skalibs/bytestr.h src/include/skalibs/uint32.h
+src/libstddjb/uint640_fmt.o src/libstddjb/uint640_fmt.lo: src/libstddjb/uint640_fmt.c src/include/skalibs/uint64.h
+src/libstddjb/uint640_scan.o src/libstddjb/uint640_scan.lo: src/libstddjb/uint640_scan.c src/libstddjb/fmtscan-internal.h src/include/skalibs/uint64.h
+src/libstddjb/uint64_fmt.o src/libstddjb/uint64_fmt.lo: src/libstddjb/uint64_fmt.c src/include/skalibs/fmtscan.h src/include/skalibs/uint64.h
+src/libstddjb/uint64_fmtlist.o src/libstddjb/uint64_fmtlist.lo: src/libstddjb/uint64_fmtlist.c src/libstddjb/fmtscan-internal.h src/include/skalibs/uint16.h
+src/libstddjb/uint64_pack.o src/libstddjb/uint64_pack.lo: src/libstddjb/uint64_pack.c src/include/skalibs/bytestr.h src/include/skalibs/uint64.h
+src/libstddjb/uint64_pack_big.o src/libstddjb/uint64_pack_big.lo: src/libstddjb/uint64_pack_big.c src/include/skalibs/bytestr.h src/include/skalibs/uint64.h
+src/libstddjb/uint64_reverse.o src/libstddjb/uint64_reverse.lo: src/libstddjb/uint64_reverse.c src/include/skalibs/uint64.h
+src/libstddjb/uint64_scan.o src/libstddjb/uint64_scan.lo: src/libstddjb/uint64_scan.c src/libstddjb/fmtscan-internal.h src/include/skalibs/uint64.h
+src/libstddjb/uint64_scanlist.o src/libstddjb/uint64_scanlist.lo: src/libstddjb/uint64_scanlist.c src/libstddjb/fmtscan-internal.h src/include/skalibs/uint16.h
+src/libstddjb/uint64_unpack.o src/libstddjb/uint64_unpack.lo: src/libstddjb/uint64_unpack.c src/include/skalibs/bytestr.h src/include/skalibs/uint64.h
+src/libstddjb/uint64_unpack_big.o src/libstddjb/uint64_unpack_big.lo: src/libstddjb/uint64_unpack_big.c src/include/skalibs/bytestr.h src/include/skalibs/uint64.h
+src/libstddjb/uncoe.o src/libstddjb/uncoe.lo: src/libstddjb/uncoe.c src/include/skalibs/djbunix.h
+src/libstddjb/unsanitize_read.o src/libstddjb/unsanitize_read.lo: src/libstddjb/unsanitize_read.c src/include/skalibs/allreadwrite.h src/include/skalibs/error.h
+src/libstddjb/utc_from_localtm.o src/libstddjb/utc_from_localtm.lo: src/libstddjb/utc_from_localtm.c src/include/skalibs/djbtime.h src/include/skalibs/uint64.h
+src/libstddjb/utc_from_ltm64.o src/libstddjb/utc_from_ltm64.lo: src/libstddjb/utc_from_ltm64.c src/include/skalibs/config.h src/libstddjb/djbtime-internal.h src/include/skalibs/djbtime.h src/include/skalibs/uint64.h
+src/libstddjb/utc_from_sysclock.o src/libstddjb/utc_from_sysclock.lo: src/libstddjb/utc_from_sysclock.c src/include/skalibs/config.h src/include/skalibs/djbtime.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/utc_from_tai.o src/libstddjb/utc_from_tai.lo: src/libstddjb/utc_from_tai.c src/libstddjb/djbtime-internal.h src/include/skalibs/djbtime.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
+src/libstddjb/vbaprintf.o src/libstddjb/vbaprintf.lo: src/libstddjb/vbaprintf.c src/include/skalibs/bufalloc.h src/include/skalibs/lolstdio.h src/include/skalibs/stralloc.h
+src/libstddjb/vbprintf.o src/libstddjb/vbprintf.lo: src/libstddjb/vbprintf.c src/include/skalibs/buffer.h src/include/skalibs/lolstdio.h
+src/libstddjb/wait_nointr.o src/libstddjb/wait_nointr.lo: src/libstddjb/wait_nointr.c src/include/skalibs/djbunix.h
+src/libstddjb/wait_pid_nohang.o src/libstddjb/wait_pid_nohang.lo: src/libstddjb/wait_pid_nohang.c src/include/skalibs/djbunix.h
+src/libstddjb/wait_pids_nohang.o src/libstddjb/wait_pids_nohang.lo: src/libstddjb/wait_pids_nohang.c src/include/skalibs/djbunix.h
+src/libstddjb/wait_reap.o src/libstddjb/wait_reap.lo: src/libstddjb/wait_reap.c src/include/skalibs/djbunix.h
+src/libstddjb/waitn.o src/libstddjb/waitn.lo: src/libstddjb/waitn.c src/include/skalibs/djbunix.h
+src/libstddjb/waitn_reap.o src/libstddjb/waitn_reap.lo: src/libstddjb/waitn_reap.c src/include/skalibs/djbunix.h
+src/libstddjb/waitpid_nointr.o src/libstddjb/waitpid_nointr.lo: src/libstddjb/waitpid_nointr.c src/include/skalibs/djbunix.h
+src/libunixonacid/bufalloc_timed_flush.o src/libunixonacid/bufalloc_timed_flush.lo: src/libunixonacid/bufalloc_timed_flush.c src/include/skalibs/bufalloc.h src/include/skalibs/functypes.h src/include/skalibs/tai.h src/include/skalibs/unix-timed.h
+src/libunixonacid/buffer_timed_fill.o src/libunixonacid/buffer_timed_fill.lo: src/libunixonacid/buffer_timed_fill.c src/include/skalibs/allreadwrite.h src/include/skalibs/buffer.h src/include/skalibs/functypes.h src/include/skalibs/tai.h src/include/skalibs/unix-timed.h
+src/libunixonacid/buffer_timed_flush.o src/libunixonacid/buffer_timed_flush.lo: src/libunixonacid/buffer_timed_flush.c src/include/skalibs/buffer.h src/include/skalibs/functypes.h src/include/skalibs/tai.h src/include/skalibs/unix-timed.h
+src/libunixonacid/buffer_timed_get.o src/libunixonacid/buffer_timed_get.lo: src/libunixonacid/buffer_timed_get.c src/include/skalibs/buffer.h src/include/skalibs/tai.h src/include/skalibs/unix-timed.h
+src/libunixonacid/dd_cancel.o src/libunixonacid/dd_cancel.lo: src/libunixonacid/dd_cancel.c src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/dd_close.o src/libunixonacid/dd_close.lo: src/libunixonacid/dd_close.c src/include/skalibs/djbunix.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/dd_commit.o src/libunixonacid/dd_commit.lo: src/libunixonacid/dd_commit.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h src/include/skalibs/random.h src/include/skalibs/stralloc.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/dd_commit_devino.o src/libunixonacid/dd_commit_devino.lo: src/libunixonacid/dd_commit_devino.c src/include/skalibs/uint64.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/dd_open_read.o src/libunixonacid/dd_open_read.lo: src/libunixonacid/dd_open_read.c src/include/skalibs/djbunix.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/dd_open_write.o src/libunixonacid/dd_open_write.lo: src/libunixonacid/dd_open_write.c src/include/skalibs/djbunix.h src/include/skalibs/random.h src/include/skalibs/stralloc.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/kolbak_call.o src/libunixonacid/kolbak_call.lo: src/libunixonacid/kolbak_call.c src/include/skalibs/kolbak.h src/include/skalibs/unixmessage.h
+src/libunixonacid/kolbak_enqueue.o src/libunixonacid/kolbak_enqueue.lo: src/libunixonacid/kolbak_enqueue.c src/include/skalibs/kolbak.h src/include/skalibs/unixmessage.h
+src/libunixonacid/kolbak_queue_init.o src/libunixonacid/kolbak_queue_init.lo: src/libunixonacid/kolbak_queue_init.c src/include/skalibs/kolbak.h
+src/libunixonacid/kolbak_unenqueue.o src/libunixonacid/kolbak_unenqueue.lo: src/libunixonacid/kolbak_unenqueue.c src/include/skalibs/kolbak.h
+src/libunixonacid/mkdir_unique.o src/libunixonacid/mkdir_unique.lo: src/libunixonacid/mkdir_unique.c src/include/skalibs/random.h src/include/skalibs/stralloc.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/netstring_timed_get.o src/libunixonacid/netstring_timed_get.lo: src/libunixonacid/netstring_timed_get.c src/include/skalibs/buffer.h src/include/skalibs/iopause.h src/include/skalibs/netstring.h src/include/skalibs/stralloc.h src/include/skalibs/tai.h src/include/skalibs/unix-timed.h
+src/libunixonacid/open2_at.o src/libunixonacid/open2_at.lo: src/libunixonacid/open2_at.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/open3_at.o src/libunixonacid/open3_at.lo: src/libunixonacid/open3_at.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/open_appendat.o src/libunixonacid/open_appendat.lo: src/libunixonacid/open_appendat.c src/include/skalibs/unix-transactional.h
+src/libunixonacid/open_appendatb.o src/libunixonacid/open_appendatb.lo: src/libunixonacid/open_appendatb.c src/include/skalibs/djbunix.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/open_readat.o src/libunixonacid/open_readat.lo: src/libunixonacid/open_readat.c src/include/skalibs/unix-transactional.h
+src/libunixonacid/open_readatb.o src/libunixonacid/open_readatb.lo: src/libunixonacid/open_readatb.c src/include/skalibs/djbunix.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/open_truncat.o src/libunixonacid/open_truncat.lo: src/libunixonacid/open_truncat.c src/include/skalibs/unix-transactional.h
+src/libunixonacid/open_truncatb.o src/libunixonacid/open_truncatb.lo: src/libunixonacid/open_truncatb.c src/include/skalibs/djbunix.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/open_writeat.o src/libunixonacid/open_writeat.lo: src/libunixonacid/open_writeat.c src/include/skalibs/unix-transactional.h
+src/libunixonacid/open_writeatb.o src/libunixonacid/open_writeatb.lo: src/libunixonacid/open_writeatb.c src/include/skalibs/djbunix.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/opengetlnclose.o src/libunixonacid/opengetlnclose.lo: src/libunixonacid/opengetlnclose.c src/include/skalibs/buffer.h src/include/skalibs/djbunix.h src/include/skalibs/skamisc.h src/include/skalibs/stralloc.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/opengetlnclose_at.o src/libunixonacid/opengetlnclose_at.lo: src/libunixonacid/opengetlnclose_at.c src/include/skalibs/buffer.h src/include/skalibs/djbunix.h src/include/skalibs/skamisc.h src/include/skalibs/stralloc.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/openreadnclose_at.o src/libunixonacid/openreadnclose_at.lo: src/libunixonacid/openreadnclose_at.c src/include/skalibs/allreadwrite.h src/include/skalibs/djbunix.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/openslurpclose_at.o src/libunixonacid/openslurpclose_at.lo: src/libunixonacid/openslurpclose_at.c src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/openwritenclose.o src/libunixonacid/openwritenclose.lo: src/libunixonacid/openwritenclose.c src/include/skalibs/skamisc.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/openwritenclose_at.o src/libunixonacid/openwritenclose_at.lo: src/libunixonacid/openwritenclose_at.c src/include/skalibs/allreadwrite.h src/include/skalibs/djbunix.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/openwritenclose_devino.o src/libunixonacid/openwritenclose_devino.lo: src/libunixonacid/openwritenclose_devino.c src/include/skalibs/skamisc.h src/include/skalibs/uint64.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/openwritenclose_devino_tmp.o src/libunixonacid/openwritenclose_devino_tmp.lo: src/libunixonacid/openwritenclose_devino_tmp.c src/include/skalibs/djbunix.h src/include/skalibs/random.h src/include/skalibs/stralloc.h src/include/skalibs/uint64.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/openwritenclose_tmp.o src/libunixonacid/openwritenclose_tmp.lo: src/libunixonacid/openwritenclose_tmp.c src/include/skalibs/stralloc.h src/include/skalibs/uint64.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/skaclient_default_cb.o src/libunixonacid/skaclient_default_cb.lo: src/libunixonacid/skaclient_default_cb.c src/include/skalibs/error.h src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h
+src/libunixonacid/skaclient_end.o src/libunixonacid/skaclient_end.lo: src/libunixonacid/skaclient_end.c src/include/skalibs/djbunix.h src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h
+src/libunixonacid/skaclient_init.o src/libunixonacid/skaclient_init.lo: src/libunixonacid/skaclient_init.c src/include/skalibs/kolbak.h src/libunixonacid/skaclient-internal.h src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h
+src/libunixonacid/skaclient_put.o src/libunixonacid/skaclient_put.lo: src/libunixonacid/skaclient_put.c src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h
+src/libunixonacid/skaclient_putmsg.o src/libunixonacid/skaclient_putmsg.lo: src/libunixonacid/skaclient_putmsg.c src/include/skalibs/kolbak.h src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h
+src/libunixonacid/skaclient_putmsgv.o src/libunixonacid/skaclient_putmsgv.lo: src/libunixonacid/skaclient_putmsgv.c src/include/skalibs/kolbak.h src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h
+src/libunixonacid/skaclient_putv.o src/libunixonacid/skaclient_putv.lo: src/libunixonacid/skaclient_putv.c src/include/skalibs/siovec.h src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h
+src/libunixonacid/skaclient_send.o src/libunixonacid/skaclient_send.lo: src/libunixonacid/skaclient_send.c src/include/skalibs/skaclient.h src/include/skalibs/tai.h src/include/skalibs/unixmessage.h
+src/libunixonacid/skaclient_sendmsg.o src/libunixonacid/skaclient_sendmsg.lo: src/libunixonacid/skaclient_sendmsg.c src/include/skalibs/skaclient.h src/include/skalibs/tai.h src/include/skalibs/unixmessage.h
+src/libunixonacid/skaclient_sendmsgv.o src/libunixonacid/skaclient_sendmsgv.lo: src/libunixonacid/skaclient_sendmsgv.c src/include/skalibs/skaclient.h src/include/skalibs/tai.h src/include/skalibs/unixmessage.h
+src/libunixonacid/skaclient_sendv.o src/libunixonacid/skaclient_sendv.lo: src/libunixonacid/skaclient_sendv.c src/include/skalibs/siovec.h src/include/skalibs/skaclient.h src/include/skalibs/tai.h src/include/skalibs/unixmessage.h
+src/libunixonacid/skaclient_server_ack.o src/libunixonacid/skaclient_server_ack.lo: src/libunixonacid/skaclient_server_ack.c src/include/skalibs/bytestr.h src/include/skalibs/djbunix.h src/include/skalibs/error.h src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h src/include/skalibs/webipc.h
+src/libunixonacid/skaclient_server_bidi_ack.o src/libunixonacid/skaclient_server_bidi_ack.lo: src/libunixonacid/skaclient_server_bidi_ack.c src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h
+src/libunixonacid/skaclient_server_init.o src/libunixonacid/skaclient_server_init.lo: src/libunixonacid/skaclient_server_init.c src/include/skalibs/skaclient.h src/include/skalibs/tai.h src/include/skalibs/unixmessage.h
+src/libunixonacid/skaclient_start.o src/libunixonacid/skaclient_start.lo: src/libunixonacid/skaclient_start.c src/include/skalibs/kolbak.h src/libunixonacid/skaclient-internal.h src/include/skalibs/skaclient.h src/include/skalibs/tai.h
+src/libunixonacid/skaclient_start_async.o src/libunixonacid/skaclient_start_async.lo: src/libunixonacid/skaclient_start_async.c src/include/skalibs/error.h src/include/skalibs/kolbak.h src/libunixonacid/skaclient-internal.h src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h src/include/skalibs/webipc.h
+src/libunixonacid/skaclient_start_cb.o src/libunixonacid/skaclient_start_cb.lo: src/libunixonacid/skaclient_start_cb.c src/include/skalibs/bytestr.h src/include/skalibs/error.h src/libunixonacid/skaclient-internal.h src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h
+src/libunixonacid/skaclient_startf.o src/libunixonacid/skaclient_startf.lo: src/libunixonacid/skaclient_startf.c src/include/skalibs/kolbak.h src/libunixonacid/skaclient-internal.h src/include/skalibs/skaclient.h src/include/skalibs/tai.h
+src/libunixonacid/skaclient_startf_async.o src/libunixonacid/skaclient_startf_async.lo: src/libunixonacid/skaclient_startf_async.c src/include/skalibs/djbunix.h src/include/skalibs/kolbak.h src/libunixonacid/skaclient-internal.h src/include/skalibs/skaclient.h src/include/skalibs/uint32.h
+src/libunixonacid/skaclient_zero.o src/libunixonacid/skaclient_zero.lo: src/libunixonacid/skaclient_zero.c src/include/skalibs/skaclient.h
+src/libunixonacid/timed_flush.o src/libunixonacid/timed_flush.lo: src/libunixonacid/timed_flush.c src/include/skalibs/bufalloc.h src/include/skalibs/error.h src/include/skalibs/functypes.h src/include/skalibs/iopause.h src/include/skalibs/tai.h src/include/skalibs/unix-timed.h
+src/libunixonacid/timed_get.o src/libunixonacid/timed_get.lo: src/libunixonacid/timed_get.c src/include/skalibs/allreadwrite.h src/include/skalibs/functypes.h src/include/skalibs/iopause.h src/include/skalibs/tai.h src/include/skalibs/unix-timed.h
+src/libunixonacid/timed_getln.o src/libunixonacid/timed_getln.lo: src/libunixonacid/timed_getln.c src/include/skalibs/allreadwrite.h src/include/skalibs/buffer.h src/include/skalibs/functypes.h src/include/skalibs/skamisc.h src/include/skalibs/stralloc.h src/include/skalibs/tai.h src/include/skalibs/unix-timed.h
+src/libunixonacid/timed_getlnmax.o src/libunixonacid/timed_getlnmax.lo: src/libunixonacid/timed_getlnmax.c src/include/skalibs/allreadwrite.h src/include/skalibs/buffer.h src/include/skalibs/functypes.h src/include/skalibs/skamisc.h src/include/skalibs/tai.h src/include/skalibs/unix-timed.h
+src/libunixonacid/unixmessage_bits_closeall.o src/libunixonacid/unixmessage_bits_closeall.lo: src/libunixonacid/unixmessage_bits_closeall.c src/include/skalibs/bitarray.h src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_bits_closenone.o src/libunixonacid/unixmessage_bits_closenone.lo: src/libunixonacid/unixmessage_bits_closenone.c src/include/skalibs/bitarray.h src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_handle.o src/libunixonacid/unixmessage_handle.lo: src/libunixonacid/unixmessage_handle.c src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_put.o src/libunixonacid/unixmessage_put.lo: src/libunixonacid/unixmessage_put.c src/include/skalibs/bitarray.h src/include/skalibs/bytestr.h src/include/skalibs/diuint.h src/include/skalibs/genalloc.h src/include/skalibs/siovec.h src/include/skalibs/stralloc.h src/include/skalibs/sysdeps.h src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_read.o src/libunixonacid/unixmessage_read.lo: src/libunixonacid/unixmessage_read.c src/include/skalibs/buffer.h src/include/skalibs/cbuffer.h src/include/skalibs/djbunix.h src/include/skalibs/error.h src/include/skalibs/nonposix.h src/include/skalibs/siovec.h src/include/skalibs/sysdeps.h src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_receive.o src/libunixonacid/unixmessage_receive.lo: src/libunixonacid/unixmessage_receive.c src/include/skalibs/allreadwrite.h src/include/skalibs/buffer.h src/include/skalibs/cbuffer.h src/include/skalibs/error.h src/include/skalibs/stralloc.h src/include/skalibs/uint.h src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_receiver_free.o src/libunixonacid/unixmessage_receiver_free.lo: src/libunixonacid/unixmessage_receiver_free.c src/include/skalibs/stralloc.h src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_receiver_init.o src/libunixonacid/unixmessage_receiver_init.lo: src/libunixonacid/unixmessage_receiver_init.c src/include/skalibs/buffer.h src/include/skalibs/cbuffer.h src/include/skalibs/stralloc.h src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_sender_flush.o src/libunixonacid/unixmessage_sender_flush.lo: src/libunixonacid/unixmessage_sender_flush.c src/include/skalibs/diuint.h src/include/skalibs/djbunix.h src/include/skalibs/genalloc.h src/include/skalibs/nonposix.h src/include/skalibs/stralloc.h src/include/skalibs/sysdeps.h src/include/skalibs/uint.h src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_sender_free.o src/libunixonacid/unixmessage_sender_free.lo: src/libunixonacid/unixmessage_sender_free.c src/include/skalibs/diuint.h src/include/skalibs/genalloc.h src/include/skalibs/stralloc.h src/include/skalibs/sysdeps.h src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_sender_getfd.o src/libunixonacid/unixmessage_sender_getfd.lo: src/libunixonacid/unixmessage_sender_getfd.c src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_sender_init.o src/libunixonacid/unixmessage_sender_init.lo: src/libunixonacid/unixmessage_sender_init.c src/include/skalibs/genalloc.h src/include/skalibs/stralloc.h src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_sender_timed_flush.o src/libunixonacid/unixmessage_sender_timed_flush.lo: src/libunixonacid/unixmessage_sender_timed_flush.c src/include/skalibs/functypes.h src/include/skalibs/genalloc.h src/include/skalibs/tai.h src/include/skalibs/unix-timed.h src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_sender_zero.o src/libunixonacid/unixmessage_sender_zero.lo: src/libunixonacid/unixmessage_sender_zero.c src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_timed_handle.o src/libunixonacid/unixmessage_timed_handle.lo: src/libunixonacid/unixmessage_timed_handle.c src/include/skalibs/functypes.h src/include/skalibs/tai.h src/include/skalibs/unix-timed.h src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_timed_receive.o src/libunixonacid/unixmessage_timed_receive.lo: src/libunixonacid/unixmessage_timed_receive.c src/include/skalibs/functypes.h src/include/skalibs/tai.h src/include/skalibs/unix-timed.h src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_v_zero.o src/libunixonacid/unixmessage_v_zero.lo: src/libunixonacid/unixmessage_v_zero.c src/include/skalibs/unixmessage.h
+src/libunixonacid/unixmessage_zero.o src/libunixonacid/unixmessage_zero.lo: src/libunixonacid/unixmessage_zero.c src/include/skalibs/unixmessage.h
diff --git a/package/info b/package/info
new file mode 100644
index 0000000..5da5a0c
--- /dev/null
+++ b/package/info
@@ -0,0 +1,4 @@
+package=skalibs
+version=2.0.0.0
+category=prog
+package_macro_name=SKALIBS
diff --git a/patch-for-solaris b/patch-for-solaris
new file mode 100755
index 0000000..02f2e3c
--- /dev/null
+++ b/patch-for-solaris
@@ -0,0 +1,17 @@
+#!/usr/xpg4/bin/sh
+
+patchit () {
+ echo '#!/usr/xpg4/bin/sh' > $1.tmp
+ tail -n +2 $1 >> $1.tmp
+ mv -f $1.tmp $1
+ chmod 755 $1
+}
+
+patchit ./configure
+patchit ./tools/install.sh
+patchit ./tools/gen-deps.sh
+
+echo 'SHELL := /usr/xpg4/bin/sh' > Makefile.tmp
+echo >> Makefile.tmp
+cat Makefile >> Makefile.tmp
+mv -f Makefile.tmp Makefile
diff --git a/src/etc/leapsecs.dat b/src/etc/leapsecs.dat
new file mode 100644
index 0000000..86a9a90
--- /dev/null
+++ b/src/etc/leapsecs.dat
Binary files differ
diff --git a/src/headers/error-addrinuse b/src/headers/error-addrinuse
new file mode 100644
index 0000000..6f1e4fe
--- /dev/null
+++ b/src/headers/error-addrinuse
@@ -0,0 +1,3 @@
+
+/* BSD sucks */
+#define error_isalready(e) (((e) == EALREADY) || ((e) == EINPROGRESS) || ((e) == EADDRINUSE))
diff --git a/src/headers/error-already b/src/headers/error-already
new file mode 100644
index 0000000..ac6b8a7
--- /dev/null
+++ b/src/headers/error-already
@@ -0,0 +1 @@
+#define error_isalready(e) (((e) == EALREADY) || ((e) == EINPROGRESS))
diff --git a/src/headers/error-footer b/src/headers/error-footer
new file mode 100644
index 0000000..ddd5dae
--- /dev/null
+++ b/src/headers/error-footer
@@ -0,0 +1,2 @@
+
+#endif
diff --git a/src/headers/error-header b/src/headers/error-header
new file mode 100644
index 0000000..b891b6b
--- /dev/null
+++ b/src/headers/error-header
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#ifndef ERROR_H
+#define ERROR_H
+
+#include <errno.h>
+#include <skalibs/gccattributes.h>
+
+extern char const *error_str (int) gccattr_const ;
+extern int error_temp (int) gccattr_const ;
+
+#define error_isagain(e) (((e) == EAGAIN) || ((e) == EWOULDBLOCK))
diff --git a/src/headers/error-proto b/src/headers/error-proto
new file mode 100644
index 0000000..fd0c01d
--- /dev/null
+++ b/src/headers/error-proto
@@ -0,0 +1,3 @@
+
+/* Did I ever mention that BSD sucks ? */
+#define EPROTO EPROTOTYPE
diff --git a/src/headers/gidstuff-16 b/src/headers/gidstuff-16
new file mode 100644
index 0000000..491de89
--- /dev/null
+++ b/src/headers/gidstuff-16
@@ -0,0 +1,7 @@
+#include <skalibs/uint16.h>
+
+#define GID_FMT UINT16_FMT
+#define gid_fmt(s, u) uint16_fmt(s, u)
+#define gid_scan(s, u) uint16_scan(s, u)
+#define gid_fmtlist(s, tab, n) uint16_fmtlist(s, tab, n)
+#define gid_scanlist(tab, max, s, num) uint16_scanlist(tab, max, s, num)
diff --git a/src/headers/gidstuff-32 b/src/headers/gidstuff-32
new file mode 100644
index 0000000..a8ed0e8
--- /dev/null
+++ b/src/headers/gidstuff-32
@@ -0,0 +1,7 @@
+#include <skalibs/uint32.h>
+
+#define GID_FMT UINT32_FMT
+#define gid_fmt(s, u) uint32_fmt(s, u)
+#define gid_scan(s, u) uint32_scan(s, u)
+#define gid_fmtlist(s, tab, n) uint32_fmtlist(s, tab, n)
+#define gid_scanlist(tab, max, s, num) uint32_scanlist(tab, max, s, num)
diff --git a/src/headers/gidstuff-64 b/src/headers/gidstuff-64
new file mode 100644
index 0000000..3d441e6
--- /dev/null
+++ b/src/headers/gidstuff-64
@@ -0,0 +1,7 @@
+#include <skalibs/uint64.h>
+
+#define GID_FMT UINT64_FMT
+#define gid_fmt(s, u) uint64_fmt(s, u)
+#define gid_scan(s, u) uint64_scan(s, u)
+#define gid_fmtlist(s, tab, n) uint64_fmtlist(s, tab, n)
+#define gid_scanlist(tab, max, s, num) uint64_scanlist(tab, max, s, num)
diff --git a/src/headers/gidstuff-footer b/src/headers/gidstuff-footer
new file mode 100644
index 0000000..ddd5dae
--- /dev/null
+++ b/src/headers/gidstuff-footer
@@ -0,0 +1,2 @@
+
+#endif
diff --git a/src/headers/gidstuff-header b/src/headers/gidstuff-header
new file mode 100644
index 0000000..73bf86b
--- /dev/null
+++ b/src/headers/gidstuff-header
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#ifndef GIDSTUFF_H
+#define GIDSTUFF_H
+
diff --git a/src/headers/ip46-footer b/src/headers/ip46-footer
new file mode 100644
index 0000000..4340daf
--- /dev/null
+++ b/src/headers/ip46-footer
@@ -0,0 +1,10 @@
+
+#define ip46_from_ip(i, s, h) ((h) ? ip46_from_ip6(i, s) : ip46_from_ip4(i, s))
+
+#define socket_recvnb46_g(fd, buf, len, i, port, deadline) socket_recvnb46(fd, buf, len, i, port, (deadline), &STAMP)
+#define socket_sendnb46_g(fd, buf, len, i, port, deadline) socket_sendnb46(fd, buf, len, i, port, (deadline), &STAMP)
+
+extern int socket_deadlineconnstamp46 (int, ip46_t const *, uint16, tain_t const *, tain_t *) ;
+#define socket_deadlineconnstamp46_g(fd, ip, port, deadline) socket_deadlineconnstamp46(fd, ip, port, (deadline), &STAMP)
+
+#endif
diff --git a/src/headers/ip46-header b/src/headers/ip46-header
new file mode 100644
index 0000000..4f0cf8c
--- /dev/null
+++ b/src/headers/ip46-header
@@ -0,0 +1,34 @@
+/* ISC license. */
+
+#ifndef IP46_H
+#define IP46_H
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/fmtscan.h>
+#include <skalibs/tai.h>
+#include <skalibs/socket.h>
+
+#define IP46_FMT IP6_FMT
+#define IP4_ANY "\0\0\0"
+#define IP6_ANY "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+#define IP4_LOCAL "\177\0\0\1"
+#define IP6_LOCAL "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1"
+
+typedef struct ip46full_s ip46full_t, *ip46full_t_ref ;
+
+struct ip46full_s
+{
+ char ip[16] ;
+ unsigned int is6: 1 ;
+} ;
+#define IP46FULL_ZERO { .ip = IP6_ANY, .is6 = 0 }
+
+#define ip46full_is6(i) ((i)->is6)
+#define ip46full_fmt(s, i) ((i)->is6 ? ip6_fmt(s, (i)->ip) : ip4_fmt(s, (i)->ip))
+extern unsigned int ip46full_scan (char const *, ip46full_t_ref) ;
+extern unsigned int ip46full_scanlist (ip46full_t_ref, unsigned int, char const *, unsigned int *) ;
+#define ip46full_from_ip4(i, ip4) (byte_copy((i)->ip, 4, ip4), byte_zero((i)->ip + 4, 12), (i)->is6 = 0)
+#define ip46full_from_ip6(i, ip6) (byte_copy((i)->ip, 16, ip6), (i)->is6 = 1)
+
diff --git a/src/headers/ip46-with b/src/headers/ip46-with
new file mode 100644
index 0000000..0cd3d19
--- /dev/null
+++ b/src/headers/ip46-with
@@ -0,0 +1,24 @@
+typedef ip46full_t ip46_t, *ip46_t_ref ;
+#define IP46_ZERO IP46FULL_ZERO
+
+#define SKALIBS_IPV6_ENABLED
+#define SKALIBS_IP_SIZE 16
+#define ip46_is6(i) ip46full_is6(i)
+#define ip46_fmt(s, i) ip46full_fmt(s, i)
+#define ip46_scan(s, i) ip46full_scan(s, i)
+#define ip46_scanlist(out, max, s, num) ip46full_scanlist(out, max, s, num)
+#define ip46_from_ip4(i, ip4) (ip46full_from_ip4(i, ip4), 1)
+#define ip46_from_ip6(i, ip6) (ip46full_from_ip6(i, ip6), 1)
+
+#define socket_connect46(s, i, port) ((i)->is6 ? socket_connect6(s, (i)->ip, port) : socket_connect4(s, (i)->ip, port))
+#define socket_bind46(s, i, port) ((i)->is6 ? socket_bind6(s, (i)->ip, port) : socket_bind4(s, (i)->ip, port))
+#define socket_bind46_reuse(s, i, port) ((i)->is6 ? socket_bind6_reuse(s, (i)->ip, port) : socket_bind4_reuse(s, (i)->ip, port))
+#define socket_tcp46(h) ((h) ? socket_tcp6() : socket_tcp4())
+#define socket_udp46(h) ((h) ? socket_udp6() : socket_udp4())
+#define socket_recv46(fd, s, len, i, port) ((i)->is6 ? socket_recv6(fd, s, len, (i)->ip, port) : socket_recv4(fd, s, len, (i)->ip, port))
+#define socket_send46(fd, s, len, i, port) ((i)->is6 ? socket_send6(fd, s, len, (i)->ip, port) : socket_send4(fd, s, len, (i)->ip, port))
+extern int socket_local46 (int, ip46_t_ref, uint16 *) ;
+extern int socket_remote46 (int, ip46_t_ref, uint16 *) ;
+
+#define socket_recvnb46(fd, buf, len, i, port, deadline, stamp) ((i)->is6 ? socket_recvnb6(fd, buf, len, (i)->ip, port, deadline, stamp) : socket_recvnb4(fd, buf, len, (i)->ip, port, deadline, stamp))
+#define socket_sendnb46(fd, buf, len, i, port, deadline, stamp) ((i)->is6 ? socket_sendnb6(fd, buf, len, (i)->ip, port, deadline, stamp) : socket_sendnb4(fd, buf, len, (i)->ip, port, deadline, stamp))
diff --git a/src/headers/ip46-without b/src/headers/ip46-without
new file mode 100644
index 0000000..7887482
--- /dev/null
+++ b/src/headers/ip46-without
@@ -0,0 +1,28 @@
+typedef struct ip46_s ip46_t, *ip46_t_ref ;
+struct ip46_s
+{
+ char ip[4] ;
+} ;
+#define IP46_ZERO { .ip = "\0\0\0" }
+
+#undef SKALIBS_IPV6_ENABLED
+#define SKALIBS_IP_SIZE 4
+#define ip46_is6(ip) 0
+#define ip46_fmt(s, i) ip4_fmt(s, (i)->ip)
+#define ip46_scan(s, i) ip4_scan(s, (i)->ip)
+#define ip46_scanlist(out, max, s, num) ip4_scanlist((out)->ip, max, s, num)
+#define ip46_from_ip4(i, ip4) (byte_copy((i)->ip, 4, ip4), 1)
+#define ip46_from_ip6(i, ip6) (errno = ENOSYS, 0)
+
+#define socket_connect46(s, i, port) socket_connect4(s, (i)->ip, port)
+#define socket_bind46(s, i, port) socket_bind4(s, (i)->ip, port)
+#define socket_bind46_reuse(s, i, port) socket_bind4_reuse(s, (i)->ip, port)
+#define socket_tcp46(h) socket_tcp4()
+#define socket_udp46(h) socket_udp4()
+#define socket_recv46(fd, s, len, i, port) socket_recv4(fd, s, len, (i)->ip, port)
+#define socket_send46(fd, s, len, i, port) socket_send4(fd, s, len, (i)->ip, port)
+#define socket_local46(fd, i, port) socket_local4(fd, (i)->ip, port)
+#define socket_remote46(fd, i, port) socket_remote4(fd, (i)->ip, port)
+
+#define socket_recvnb46(fd, buf, len, i, port, deadline, stamp) socket_recvnb4(fd, buf, len, (i)->ip, port, deadline, stamp)
+#define socket_sendnb46(fd, buf, len, i, port, deadline, stamp) socket_sendnb4(fd, buf, len, (i)->ip, port, deadline, stamp)
diff --git a/src/headers/setgroups-footer b/src/headers/setgroups-footer
new file mode 100644
index 0000000..ddd5dae
--- /dev/null
+++ b/src/headers/setgroups-footer
@@ -0,0 +1,2 @@
+
+#endif
diff --git a/src/headers/setgroups-header b/src/headers/setgroups-header
new file mode 100644
index 0000000..0b8697a
--- /dev/null
+++ b/src/headers/setgroups-header
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#ifndef SETGROUPS_H
+#define SETGROUPS_H
+
diff --git a/src/headers/setgroups-stub b/src/headers/setgroups-stub
new file mode 100644
index 0000000..3c54861
--- /dev/null
+++ b/src/headers/setgroups-stub
@@ -0,0 +1,2 @@
+#include <errno.h>
+#define setgroups(n, s) (errno = ENOSYS, -1)
diff --git a/src/headers/uint-16 b/src/headers/uint-16
new file mode 100644
index 0000000..85434db
--- /dev/null
+++ b/src/headers/uint-16
@@ -0,0 +1,34 @@
+#include <skalibs/uint16.h>
+
+#define UINT_PACK 2
+#define uint_pack uint16_pack
+#define uint_pack_big uint16_pack_big
+#define uint_unpack(s, u) uint16_unpack(s, (uint16 *)(char *)(u))
+#define uint_unpack_big(s, u) uint16_unpack_big(s, (uint16 *)(char *)(u))
+
+#define uint_reverse uint16_reverse
+#define uint_big_endian uint16_big_endian
+#define uint_little_endian uint16_little_endian
+
+#define UINT_FMT UINT16_FMT
+#define UINT_OFMT UINT16_OFMT
+#define UINT_XFMT UINT16_XFMT
+#define UINT_BFMT UINT16_BFMT
+
+#define uint_fmt_base uint16_fmt_base
+#define uint0_fmt_base uint160_fmt_base
+#define uint_fmt uint16_fmt
+#define uint0_fmt uint160_fmt
+#define uint_ofmt uint16_ofmt
+#define uint0_ofmt uint160_ofmt
+#define uint_xfmt uint16_xfmt
+#define uint0_xfmt uint160_xfmt
+#define uint_bfmt uint16_bfmt
+#define uint0_bfmt uint160_bfmt
+
+#define uint_fmtlist(s, tab, n) uint16_fmtlist(s, tab, n)
+
+#define uint_scan_base(s, u, b) uint16_scan_base(s, (uint16 *)(char *)(u), b)
+#define uint0_scan_base(s, u, b) uint160_scan_base(s, (uint16 *)(char *)(u), b)
+
+#define uint_scanlist(tab, max, s, num) uint16_scanlist(tab, max, s, num)
diff --git a/src/headers/uint-32 b/src/headers/uint-32
new file mode 100644
index 0000000..32c6600
--- /dev/null
+++ b/src/headers/uint-32
@@ -0,0 +1,34 @@
+#include <skalibs/uint32.h>
+
+#define UINT_PACK 4
+#define uint_pack uint32_pack
+#define uint_pack_big uint32_pack_big
+#define uint_unpack(s, u) uint32_unpack(s, (uint32 *)(char *)(u))
+#define uint_unpack_big(s, u) uint32_unpack_big(s, (uint32 *)(char *)(u))
+
+#define uint_reverse uint32_reverse
+#define uint_big_endian uint32_big_endian
+#define uint_little_endian uint32_little_endian
+
+#define UINT_FMT UINT32_FMT
+#define UINT_OFMT UINT32_OFMT
+#define UINT_XFMT UINT32_XFMT
+#define UINT_BFMT UINT32_BFMT
+
+#define uint_fmt_base uint32_fmt_base
+#define uint0_fmt_base uint320_fmt_base
+#define uint_fmt uint32_fmt
+#define uint0_fmt uint320_fmt
+#define uint_ofmt uint32_ofmt
+#define uint0_ofmt uint320_ofmt
+#define uint_xfmt uint32_xfmt
+#define uint0_xfmt uint320_xfmt
+#define uint_bfmt uint32_bfmt
+#define uint0_bfmt uint320_bfmt
+
+#define uint_fmtlist(s, tab, n) uint32_fmtlist(s, tab, n)
+
+#define uint_scan_base(s, u, b) uint32_scan_base(s, (uint32 *)(char *)(u), b)
+#define uint0_scan_base(s, u, b) uint320_scan_base(s, (uint32 *)(char *)(u), b)
+
+#define uint_scanlist(tab, max, s, num) uint32_scanlist(tab, max, s, num)
diff --git a/src/headers/uint-64 b/src/headers/uint-64
new file mode 100644
index 0000000..31926d9
--- /dev/null
+++ b/src/headers/uint-64
@@ -0,0 +1,34 @@
+#include <skalibs/uint64.h>
+
+#define UINT_PACK 8
+#define uint_pack uint64_pack
+#define uint_pack_big uint64_pack_big
+#define uint_unpack(s, u) uint64_unpack(s, (uint64 *)(char *)(u))
+#define uint_unpack_big(s, u) uint64_unpack_big(s, (uint64 *)(char *)(u))
+
+#define uint_reverse uint64_reverse
+#define uint_big_endian uint64_big_endian
+#define uint_little_endian uint64_little_endian
+
+#define UINT_FMT UINT64_FMT
+#define UINT_OFMT UINT64_OFMT
+#define UINT_XFMT UINT64_XFMT
+#define UINT_BFMT UINT64_BFMT
+
+#define uint_fmt_base uint64_fmt_base
+#define uint0_fmt_base uint640_fmt_base
+#define uint_fmt uint64_fmt
+#define uint0_fmt uint640_fmt
+#define uint_ofmt uint64_ofmt
+#define uint0_ofmt uint640_ofmt
+#define uint_xfmt uint64_xfmt
+#define uint0_xfmt uint640_xfmt
+#define uint_bfmt uint64_bfmt
+#define uint0_bfmt uint640_bfmt
+
+#define uint_fmtlist(s, tab, n) uint64_fmtlist(s, tab, n)
+
+#define uint_scan_base(s, u, b) uint64_scan_base(s, (uint64 *)(char *)(u), b)
+#define uint0_scan_base(s, u, b) uint640_scan_base(s, (uint64 *)(char *)(u), b)
+
+#define uint_scanlist(tab, max, s, num) uint64_scanlist(tab, max, s, num)
diff --git a/src/headers/uint-footer b/src/headers/uint-footer
new file mode 100644
index 0000000..68bbaf7
--- /dev/null
+++ b/src/headers/uint-footer
@@ -0,0 +1,10 @@
+#define uint_scan(s, u) uint_scan_base(s, (u), 10)
+#define uint0_scan(s, u) uint0_scan_base(s, (u), 10)
+#define uint_oscan(s, u) uint_scan_base(s, (u), 8)
+#define uint0_oscan(s, u) uint0_scan_base(s, (u), 8)
+#define uint_xscan(s, u) uint_scan_base(s, (u), 16)
+#define uint0_xscan(s, u) uint0_scan_base(s, (u), 16)
+#define uint_bscan(s, u) uint_scan_base(s, (u), 2)
+#define uint0_bscan(s, u) uint0_scan_base(s, (u), 2)
+
+#endif
diff --git a/src/headers/uint-header b/src/headers/uint-header
new file mode 100644
index 0000000..8136b0c
--- /dev/null
+++ b/src/headers/uint-header
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#ifndef UINT_H
+#define UINT_H
+
diff --git a/src/headers/uint16-bendian b/src/headers/uint16-bendian
new file mode 100644
index 0000000..e1d0427
--- /dev/null
+++ b/src/headers/uint16-bendian
@@ -0,0 +1,3 @@
+#define uint16_little_endian(s, n) uint16_reverse((s), (n))
+#define uint16_big_endian(s, n)
+
diff --git a/src/headers/uint16-footer b/src/headers/uint16-footer
new file mode 100644
index 0000000..5602571
--- /dev/null
+++ b/src/headers/uint16-footer
@@ -0,0 +1,40 @@
+
+extern void uint16_pack (char *, uint16) ;
+extern void uint16_pack_big (char *, uint16) ;
+extern void uint16_unpack (char const *, uint16 *) ;
+extern void uint16_unpack_big (char const *, uint16 *) ;
+extern void uint16_reverse (char *, unsigned int) ;
+
+#define UINT16_FMT 6
+#define UINT16_OFMT 7
+#define UINT16_XFMT 5
+#define UINT16_BFMT 17
+
+#define uint16_fmt_base(s, u, b) uint64_fmt_base(s, (uint64)(uint16)(u), b)
+#define uint160_fmt_base(s, u, n, b) uint640_fmt_base(s, (uint64)(uint16)(u), n, b)
+
+#define uint16_fmt(s, u) uint64_fmt(s, (uint64)(uint16)(u))
+#define uint160_fmt(s, u, n) uint64_fmt(s, (uint64)(uint16)(u), n)
+#define uint16_ofmt(s, o) uint64_ofmt(s, (uint64)(uint16)(o))
+#define uint160_ofmt(s, o, n) uint64_ofmt(s, (uint64)(uint16)(o), n)
+#define uint16_xfmt(s, x) uint64_xfmt(s, (uint64)(uint16)(x))
+#define uint160_xfmt(s, x, n) uint64_xfmt(s, (uint64)(uint16)(x), n)
+#define uint16_bfmt(s, b) uint64_bfmt(s, (uint64)(uint16)(b))
+#define uint160_bfmt(s, b, n) uint64_bfmt(s, (uint64)(uint16)(b), n)
+
+extern unsigned int uint16_fmtlist (char *, uint16 const *, unsigned int) ;
+
+extern unsigned int uint16_scan_base (char const *, uint16 *, unsigned char) ;
+extern unsigned int uint160_scan_base (char const *, uint16 *, unsigned char) ;
+#define uint16_scan(s, u) uint16_scan_base(s, (u), 10)
+#define uint160_scan(s, u) uint160_scan_base(s, (u), 10)
+#define uint16_oscan(s, u) uint16_scan_base(s, (u), 8)
+#define uint160_oscan(s, u) uint160_scan_base(s, (u), 8)
+#define uint16_xscan(s, u) uint16_scan_base(s, (u), 16)
+#define uint160_xscan(s, u) uint160_scan_base(s, (u), 16)
+#define uint16_bscan(s, u) uint16_scan_base(s, (u), 2)
+#define uint160_bscan(s, u) uint160_scan_base(s, (u), 2)
+
+extern unsigned int uint16_scanlist (uint16 *, unsigned int, char const *, unsigned int *) ;
+
+#endif
diff --git a/src/headers/uint16-header b/src/headers/uint16-header
new file mode 100644
index 0000000..a8058c6
--- /dev/null
+++ b/src/headers/uint16-header
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#ifndef UINT16_H
+#define UINT16_H
+
+#include <stdint.h>
+#include <skalibs/uint64.h>
+
+typedef uint16_t uint16 ;
diff --git a/src/headers/uint16-lendian b/src/headers/uint16-lendian
new file mode 100644
index 0000000..a9f9945
--- /dev/null
+++ b/src/headers/uint16-lendian
@@ -0,0 +1,3 @@
+#define uint16_little_endian(s, n)
+#define uint16_big_endian(s, n) uint16_reverse((s), (n))
+
diff --git a/src/headers/uint32-bendian b/src/headers/uint32-bendian
new file mode 100644
index 0000000..27903c7
--- /dev/null
+++ b/src/headers/uint32-bendian
@@ -0,0 +1,3 @@
+#define uint32_little_endian(s, n) uint32_reverse((s), (n))
+#define uint32_big_endian(s, n)
+
diff --git a/src/headers/uint32-footer b/src/headers/uint32-footer
new file mode 100644
index 0000000..7cfe7ba
--- /dev/null
+++ b/src/headers/uint32-footer
@@ -0,0 +1,39 @@
+extern void uint32_pack (char *, uint32) ;
+extern void uint32_pack_big (char *, uint32) ;
+extern void uint32_unpack (char const *, uint32 *) ;
+extern void uint32_unpack_big (char const *, uint32 *) ;
+extern void uint32_reverse (char *, unsigned int) ;
+
+#define UINT32_FMT 11
+#define UINT32_OFMT 13
+#define UINT32_XFMT 9
+#define UINT32_BFMT 33
+
+#define uint32_fmt_base(s, u, b) uint64_fmt_base(s, (uint64)(uint32)(u), b)
+#define uint320_fmt_base(s, u, n, b) uint640_fmt_base(s, (uint64)(uint32)(u), n, b)
+
+#define uint32_fmt(s, u) uint64_fmt(s, (uint64)(uint32)(u))
+#define uint320_fmt(s, u, n) uint640_fmt(s, (uint64)(uint32)(u), n)
+#define uint32_ofmt(s, o) uint64_ofmt(s, (uint64)(uint32)(o))
+#define uint320_ofmt(s, o, n) uint640_ofmt(s, (uint64)(uint32)(o), n)
+#define uint32_xfmt(s, x) uint64_xfmt(s, (uint64)(uint32)(x))
+#define uint320_xfmt(s, x, n) uint640_xfmt(s, (uint64)(uint32)(x), n)
+#define uint32_bfmt(s, b) uint64_bfmt(s, (uint64)(uint32)(b))
+#define uint320_bfmt(s, b, n) uint640_bfmt(s, (uint64)(uint32)(b), n)
+
+extern unsigned int uint32_fmtlist (char *, uint32 const *, unsigned int) ;
+
+extern unsigned int uint32_scan_base (char const *, uint32 *, unsigned char) ;
+extern unsigned int uint320_scan_base (char const *, uint32 *, unsigned char) ;
+#define uint32_scan(s, u) uint32_scan_base(s, (u), 10)
+#define uint320_scan(s, u) uint320_scan_base(s, (u), 10)
+#define uint32_oscan(s, u) uint32_scan_base(s, (u), 8)
+#define uint320_oscan(s, u) uint320_scan_base(s, (u), 8)
+#define uint32_xscan(s, u) uint32_scan_base(s, (u), 16)
+#define uint320_xscan(s, u) uint320_scan_base(s, (u), 16)
+#define uint32_bscan(s, u) uint32_scan_base(s, (u), 2)
+#define uint320_bscan(s, u) uint320_scan_base(s, (u), 2)
+
+extern unsigned int uint32_scanlist (uint32 *, unsigned int, char const *, unsigned int *) ;
+
+#endif
diff --git a/src/headers/uint32-header b/src/headers/uint32-header
new file mode 100644
index 0000000..f71267f
--- /dev/null
+++ b/src/headers/uint32-header
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#ifndef UINT32_H
+#define UINT32_H
+
+#include <stdint.h>
+#include <skalibs/uint64.h>
+
+typedef uint32_t uint32 ;
diff --git a/src/headers/uint32-inttypesh b/src/headers/uint32-inttypesh
new file mode 100644
index 0000000..47a8910
--- /dev/null
+++ b/src/headers/uint32-inttypesh
@@ -0,0 +1,3 @@
+#include <inttypes.h>
+typedef uint32_t uint32 ;
+
diff --git a/src/headers/uint32-lendian b/src/headers/uint32-lendian
new file mode 100644
index 0000000..f88c111
--- /dev/null
+++ b/src/headers/uint32-lendian
@@ -0,0 +1,3 @@
+#define uint32_little_endian(s, n)
+#define uint32_big_endian(s, n) uint32_reverse((s), (n))
+
diff --git a/src/headers/uint32-noulong32 b/src/headers/uint32-noulong32
new file mode 100644
index 0000000..4705047
--- /dev/null
+++ b/src/headers/uint32-noulong32
@@ -0,0 +1,2 @@
+typedef unsigned int uint32 ;
+
diff --git a/src/headers/uint32-stdinth b/src/headers/uint32-stdinth
new file mode 100644
index 0000000..dc9eb42
--- /dev/null
+++ b/src/headers/uint32-stdinth
@@ -0,0 +1,3 @@
+#include <stdint.h>
+typedef uint32_t uint32 ;
+
diff --git a/src/headers/uint32-ulong32 b/src/headers/uint32-ulong32
new file mode 100644
index 0000000..87119a5
--- /dev/null
+++ b/src/headers/uint32-ulong32
@@ -0,0 +1,2 @@
+typedef unsigned long uint32 ;
+
diff --git a/src/headers/uint64-bendian b/src/headers/uint64-bendian
new file mode 100644
index 0000000..2485bec
--- /dev/null
+++ b/src/headers/uint64-bendian
@@ -0,0 +1,3 @@
+#define uint64_little_endian(s, n) uint64_reverse((s), (n))
+#define uint64_big_endian(s, n)
+
diff --git a/src/headers/uint64-footer b/src/headers/uint64-footer
new file mode 100644
index 0000000..df620a5
--- /dev/null
+++ b/src/headers/uint64-footer
@@ -0,0 +1,39 @@
+extern void uint64_pack (char *, uint64) ;
+extern void uint64_pack_big (char *, uint64) ;
+extern void uint64_unpack (char const *, uint64 *) ;
+extern void uint64_unpack_big (char const *, uint64 *) ;
+extern void uint64_reverse (char *, unsigned int) ;
+
+#define UINT64_FMT 21
+#define UINT64_OFMT 25
+#define UINT64_XFMT 17
+#define UINT64_BFMT 65
+
+extern unsigned int uint64_fmt_base (char *, uint64, unsigned char) ;
+extern unsigned int uint640_fmt_base (char *, uint64, unsigned int, unsigned char) ;
+
+#define uint64_fmt(s, u) uint64_fmt_base(s, (u), 10)
+#define uint640_fmt(s, u, n) uint640_fmt_base(s, u, (n), 10)
+#define uint64_ofmt(s, u) uint64_fmt_base(s, (u), 8)
+#define uint640_ofmt(s, u, n) uint640_fmt_base(s, u, (n), 8)
+#define uint64_xfmt(s, u) uint64_fmt_base(s, (u), 16)
+#define uint640_xfmt(s, u, n) uint640_fmt_base(s, u, (n), 16)
+#define uint64_bfmt(s, u) uint64_fmt_base(s, (u), 2)
+#define uint640_bfmt(s, u, n) uint640_fmt_base(s, u, (n), 2)
+
+extern unsigned int uint64_fmtlist (char *, uint64 const *, unsigned int) ;
+
+extern unsigned int uint64_scan_base (char const *, uint64 *, unsigned char) ;
+extern unsigned int uint640_scan_base (char const *, uint64 *, unsigned char) ;
+#define uint64_scan(s, u) uint64_scan_base(s, (u), 10)
+#define uint640_scan(s, u) uint640_scan_base(s, (u), 10)
+#define uint64_oscan(s, u) uint64_scan_base(s, (u), 8)
+#define uint640_oscan(s, u) uint640_scan_base(s, (u), 8)
+#define uint64_xscan(s, u) uint64_scan_base(s, (u), 16)
+#define uint640_xscan(s, u) uint640_scan_base(s, (u), 16)
+#define uint64_bscan(s, u) uint64_scan_base(s, (u), 2)
+#define uint640_bscan(s, u) uint640_scan_base(s, (u), 2)
+
+extern unsigned int uint64_scanlist (uint64 *, unsigned int, char const *, unsigned int *) ;
+
+#endif
diff --git a/src/headers/uint64-header b/src/headers/uint64-header
new file mode 100644
index 0000000..f0f10e6
--- /dev/null
+++ b/src/headers/uint64-header
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#ifndef UINT64_H
+#define UINT64_H
+
diff --git a/src/headers/uint64-lendian b/src/headers/uint64-lendian
new file mode 100644
index 0000000..ffdb4de
--- /dev/null
+++ b/src/headers/uint64-lendian
@@ -0,0 +1,3 @@
+#define uint64_little_endian(s, n)
+#define uint64_big_endian(s, n) uint64_reverse((s), (n))
+
diff --git a/src/headers/uint64-noulong64 b/src/headers/uint64-noulong64
new file mode 100644
index 0000000..c72ebef
--- /dev/null
+++ b/src/headers/uint64-noulong64
@@ -0,0 +1,2 @@
+typedef unsigned long long uint64 ;
+
diff --git a/src/headers/uint64-stdinth b/src/headers/uint64-stdinth
new file mode 100644
index 0000000..9c43f44
--- /dev/null
+++ b/src/headers/uint64-stdinth
@@ -0,0 +1,3 @@
+#include <stdint.h>
+
+typedef uint64_t uint64 ;
diff --git a/src/headers/uint64-ulong64 b/src/headers/uint64-ulong64
new file mode 100644
index 0000000..d9313d4
--- /dev/null
+++ b/src/headers/uint64-ulong64
@@ -0,0 +1 @@
+typedef unsigned long uint64 ;
diff --git a/src/headers/ulong-32 b/src/headers/ulong-32
new file mode 100644
index 0000000..b1b3326
--- /dev/null
+++ b/src/headers/ulong-32
@@ -0,0 +1,32 @@
+#include <skalibs/uint32.h>
+
+#define ULONG_PACK 4
+#define ulong_pack uint32_pack
+#define ulong_pack_big uint32_pack_big
+#define ulong_unpack(s, u) uint32_unpack(s, (uint32 *)(char *)(u))
+#define ulong_unpack_big(s, u) uint32_unpack_big(s, (uint32 *)(char *)(u))
+
+#define ulong_reverse uint32_reverse
+#define ulong_big_endian uint32_big_endian
+#define ulong_little_endian uint32_little_endian
+
+#define ULONG_FMT UINT32_FMT
+#define ULONG_OFMT UINT32_OFMT
+#define ULONG_XFMT UINT32_XFMT
+#define ULONG_BFMT UINT32_BFMT
+
+#define ulong_fmt uint32_fmt
+#define ulong0_fmt uint320_fmt
+#define ulong_ofmt uint32_ofmt
+#define ulong0_ofmt uint320_ofmt
+#define ulong_xfmt uint32_xfmt
+#define ulong0_xfmt uint320_xfmt
+#define ulong_bfmt uint32_bfmt
+#define ulong0_bfmt uint320_bfmt
+
+#define ulong_fmtlist(s, tab, n) uint32_fmtlist(s, tab, n)
+
+#define ulong_scan_base(s, u, b) uint32_scan_base(s, (uint32 *)(char *)(u), b)
+#define ulong0_scan_base(s, u, b) uint320_scan_base(s, (uint32 *)(char *)(u), b)
+
+#define ulong_scanlist(tab, max, s, num) uint32_scanlist(tab, max, s, num)
diff --git a/src/headers/ulong-64 b/src/headers/ulong-64
new file mode 100644
index 0000000..016fd1f
--- /dev/null
+++ b/src/headers/ulong-64
@@ -0,0 +1,32 @@
+#include <skalibs/uint64.h>
+
+#define ULONG_PACK 8
+#define ulong_pack uint64_pack
+#define ulong_pack_big uint64_pack_big
+#define ulong_unpack(s, u) uint64_unpack(s, (uint64 *)(char *)(u))
+#define ulong_unpack_big(s, u) uint64_unpack_big(s, (uint64 *)(char *)(u))
+
+#define ulong_reverse uint64_reverse
+#define ulong_big_endian uint64_big_endian
+#define ulong_little_endian uint64_little_endian
+
+#define ULONG_FMT UINT64_FMT
+#define ULONG_OFMT UINT64_OFMT
+#define ULONG_XFMT UINT64_XFMT
+#define ULONG_BFMT UINT64_BFMT
+
+#define ulong_fmt uint64_fmt
+#define ulong0_fmt uint640_fmt
+#define ulong_ofmt uint64_ofmt
+#define ulong0_ofmt uint640_ofmt
+#define ulong_xfmt uint64_xfmt
+#define ulong0_xfmt uint640_xfmt
+#define ulong_bfmt uint64_bfmt
+#define ulong0_bfmt uint640_bfmt
+
+#define ulong_fmtlist(s, tab, n) uint64_fmtlist(s, tab, n)
+
+#define ulong_scan_base(s, u, b) uint64_scan_base(s, (uint64 *)(char *)(u), b)
+#define ulong0_scan_base(s, u, b) uint640_scan_base(s, (uint64 *)(char *)(u), b)
+
+#define ulong_scanlist(tab, max, s, num) uint64_scanlist(tab, max, s, num)
diff --git a/src/headers/ulong-footer b/src/headers/ulong-footer
new file mode 100644
index 0000000..0607872
--- /dev/null
+++ b/src/headers/ulong-footer
@@ -0,0 +1,10 @@
+#define ulong_scan(s, u) ulong_scan_base(s, (u), 10)
+#define ulong0_scan(s, u) ulong0_scan_base(s, (u), 10)
+#define ulong_oscan(s, u) ulong_scan_base(s, (u), 8)
+#define ulong0_oscan(s, u) ulong0_scan_base(s, (u), 8)
+#define ulong_xscan(s, u) ulong_scan_base(s, (u), 16)
+#define ulong0_xscan(s, u) ulong0_scan_base(s, (u), 16)
+#define ulong_bscan(s, u) ulong_scan_base(s, (u), 2)
+#define ulong0_bscan(s, u) ulong0_scan_base(s, (u), 2)
+
+#endif
diff --git a/src/headers/ulong-header b/src/headers/ulong-header
new file mode 100644
index 0000000..98e6f37
--- /dev/null
+++ b/src/headers/ulong-header
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#ifndef ULONG_H
+#define ULONG_H
+
diff --git a/src/headers/ushort-16 b/src/headers/ushort-16
new file mode 100644
index 0000000..0e210c6
--- /dev/null
+++ b/src/headers/ushort-16
@@ -0,0 +1,34 @@
+#include <skalibs/uint16.h>
+
+#define USHORT_PACK 2
+#define ushort_pack uint16_pack
+#define ushort_pack_big uint16_pack_big
+#define ushort_unpack(s, u) uint16_unpack(s, (uint16 *)(char *)(u))
+#define ushort_unpack_big(s, u) uint16_unpack_big(s, (uint16 *)(char *)(u))
+
+#define ushort_reverse uint16_reverse
+#define ushort_big_endian uint16_big_endian
+#define ushort_little_endian uint16_little_endian
+
+#define USHORT_FMT UINT16_FMT
+#define USHORT_OFMT UINT16_OFMT
+#define USHORT_XFMT UINT16_XFMT
+#define USHORT_BFMT UINT16_BFMT
+
+#define ushort_fmt_base uint16_fmt_base
+#define ushort0_fmt_base uint160_fmt_base
+#define ushort_fmt uint16_fmt
+#define ushort0_fmt uint160_fmt
+#define ushort_ofmt uint16_ofmt
+#define ushort0_ofmt uint160_ofmt
+#define ushort_xfmt uint16_xfmt
+#define ushort0_xfmt uint160_xfmt
+#define ushort_bfmt uint16_bfmt
+#define ushort0_bfmt uint160_bfmt
+
+#define ushort_fmtlist(s, tab, n) uint16_fmtlist(s, tab, n)
+
+#define ushort_scan_base(s, u, b) uint16_scan_base(s, (uint16 *)(char *)(u), b)
+#define ushort0_scan_base(s, u, b) uint160_scan_base(s, (uint16 *)(char *)(u), b)
+
+#define ushort_scanlist(tab, max, s, num) uint16_scanlist(tab, max, s, num)
diff --git a/src/headers/ushort-32 b/src/headers/ushort-32
new file mode 100644
index 0000000..b41aef4
--- /dev/null
+++ b/src/headers/ushort-32
@@ -0,0 +1,34 @@
+#include <skalibs/uint32.h>
+
+#define USHORT_PACK 4
+#define ushort_pack uint32_pack
+#define ushort_pack_big uint32_pack_big
+#define ushort_unpack(s, u) uint32_unpack(s, (uint32 *)(char *)(u))
+#define ushort_unpack_big(s, u) uint32_unpack_big(s, (uint32 *)(char *)(u))
+
+#define ushort_reverse uint32_reverse
+#define ushort_big_endian uint32_big_endian
+#define ushort_little_endian uint32_little_endian
+
+#define USHORT_FMT UINT32_FMT
+#define USHORT_OFMT UINT32_OFMT
+#define USHORT_XFMT UINT32_XFMT
+#define USHORT_BFMT UINT32_BFMT
+
+#define ushort_fmt_base uint32_fmt_base
+#define ushort0_fmt_base uint320_fmt_base
+#define ushort_fmt uint32_fmt
+#define ushort0_fmt uint320_fmt
+#define ushort_ofmt uint32_ofmt
+#define ushort0_ofmt uint320_ofmt
+#define ushort_xfmt uint32_xfmt
+#define ushort0_xfmt uint320_xfmt
+#define ushort_bfmt uint32_bfmt
+#define ushort0_bfmt uint320_bfmt
+
+#define ushort_fmtlist(s, tab, n) uint32_fmtlist(s, tab, n)
+
+#define ushort_scan_base(s, u, b) uint32_scan_base(s, (uint32 *)(char *)(u), b)
+#define ushort0_scan_base(s, u, b) uint320_scan_base(s, (uint32 *)(char *)(u), b)
+
+#define ushort_scanlist(tab, max, s, num) uint32_scanlist(tab, max, s, num)
diff --git a/src/headers/ushort-footer b/src/headers/ushort-footer
new file mode 100644
index 0000000..db56f73
--- /dev/null
+++ b/src/headers/ushort-footer
@@ -0,0 +1,10 @@
+#define ushort_scan(s, u) ushort_scan_base(s, (u), 10)
+#define ushort0_scan(s, u) ushort0_scan_base(s, (u), 10)
+#define ushort_oscan(s, u) ushort_scan_base(s, (u), 8)
+#define ushort0_oscan(s, u) ushort0_scan_base(s, (u), 8)
+#define ushort_xscan(s, u) ushort_scan_base(s, (u), 16)
+#define ushort0_xscan(s, u) ushort0_scan_base(s, (u), 16)
+#define ushort_bscan(s, u) ushort_scan_base(s, (u), 2)
+#define ushort0_bscan(s, u) ushort0_scan_base(s, (u), 2)
+
+#endif
diff --git a/src/headers/ushort-header b/src/headers/ushort-header
new file mode 100644
index 0000000..66b7f9a
--- /dev/null
+++ b/src/headers/ushort-header
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#ifndef USHORT_H
+#define USHORT_H
+
diff --git a/src/include/skalibs/alloc.h b/src/include/skalibs/alloc.h
new file mode 100644
index 0000000..707d5c1
--- /dev/null
+++ b/src/include/skalibs/alloc.h
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#ifndef ALLOC_H
+#define ALLOC_H
+
+#include <skalibs/gccattributes.h>
+
+typedef char aligned_char gccattr_aligned ;
+typedef aligned_char *aligned_char_ref, **aligned_char_ref_ref ;
+
+extern aligned_char_ref alloc (unsigned int) ;
+extern void alloc_free (void *) ;
+#define alloc_re(p, old, new) alloc_realloc(p, new)
+extern int alloc_realloc (aligned_char_ref_ref, unsigned int) ;
+
+#endif
diff --git a/src/include/skalibs/allreadwrite.h b/src/include/skalibs/allreadwrite.h
new file mode 100644
index 0000000..6b2a0cf
--- /dev/null
+++ b/src/include/skalibs/allreadwrite.h
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#ifndef ALLREADWRITE_H
+#define ALLREADWRITE_H
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <skalibs/functypes.h>
+
+extern int sanitize_read (int) ;
+extern int unsanitize_read (int) ;
+
+extern unsigned int allreadwrite (iofunc_t_ref, int, char *, unsigned int) ;
+
+extern int fd_read (int, char *, unsigned int) ;
+extern int fd_write (int, char const *, unsigned int) ;
+
+extern int fd_recv (int, char *, unsigned int, unsigned int) ;
+extern int fd_send (int, char const *, unsigned int, unsigned int) ;
+
+extern unsigned int allread (int, char *, unsigned int) ;
+extern unsigned int allwrite (int, char const *, unsigned int) ;
+
+extern int fd_readv (int, struct iovec const *, unsigned int) ;
+extern int fd_writev (int, struct iovec const *, unsigned int) ;
+
+#endif
diff --git a/src/include/skalibs/avlnode.h b/src/include/skalibs/avlnode.h
new file mode 100644
index 0000000..4d13d15
--- /dev/null
+++ b/src/include/skalibs/avlnode.h
@@ -0,0 +1,44 @@
+/* ISC license. */
+
+#ifndef AVLNODE_H
+#define AVLNODE_H
+
+#include <skalibs/gccattributes.h>
+#include <skalibs/functypes.h>
+
+
+#define AVLNODE_MAXDEPTH 49 /* enough for 2^32 nodes in the worst case */
+
+typedef int avliterfunc_t (unsigned int, unsigned int, void *) ;
+typedef avliterfunc_t *avliterfunc_t_ref ;
+
+typedef struct avlnode_s avlnode, *avlnode_ref ;
+struct avlnode_s
+{
+ unsigned int data ;
+ unsigned int child[2] ;
+ signed char balance : 2 ;
+} ;
+
+#define AVLNODE_ZERO { .data = 0, .child = { (unsigned int)-1, (unsigned int)-1 }, .balance = 0 }
+extern avlnode const avlnode_zero ;
+
+extern unsigned int avlnode_searchnode (avlnode const *, unsigned int, unsigned int, void const *, dtokfunc_t_ref, cmpfunc_t_ref, void *) ;
+extern int avlnode_search (avlnode const *, unsigned int, unsigned int, void const *, unsigned int *, dtokfunc_t_ref, cmpfunc_t_ref, void *) ;
+extern unsigned int avlnode_height (avlnode const *, unsigned int, unsigned int) gccattr_pure ;
+
+extern unsigned int avlnode_extremenode (avlnode const *, unsigned int, unsigned int, int) gccattr_pure ;
+#define avlnode_minnode(s, max, r) avlnode_extremenode(s, max, (r), 0)
+#define avlnode_maxnode(s, max, r) avlnode_extremenode(s, max, (r), 1)
+
+extern int avlnode_extreme (avlnode const *, unsigned int, unsigned int, int, unsigned int *) ;
+#define avlnode_min(s, max, r, data) avlnode_extreme(s, max, (r), 0, data)
+#define avlnode_max(s, max, r, data) avlnode_extreme(s, max, (r), 1, data)
+
+extern unsigned int avlnode_insertnode (avlnode_ref, unsigned int, unsigned int, unsigned int, dtokfunc_t_ref, cmpfunc_t_ref, void *) ;
+extern unsigned int avlnode_delete (avlnode_ref, unsigned int, unsigned int *, void const *, dtokfunc_t_ref, cmpfunc_t_ref, void *) ;
+#define avlnode_deletenode(s, max, r, i, dtok, f, p) avlnode_delete(s, max, r, (*(dtok))((s)[i].data), dtok, f, p)
+
+extern int avlnode_iter (avlnode_ref, unsigned int, unsigned int, avliterfunc_t_ref, void *) ;
+
+#endif
diff --git a/src/include/skalibs/avltree.h b/src/include/skalibs/avltree.h
new file mode 100644
index 0000000..cefd116
--- /dev/null
+++ b/src/include/skalibs/avltree.h
@@ -0,0 +1,55 @@
+/* ISC license. */
+
+#ifndef AVLTREE_H
+#define AVLTREE_H
+
+#include <skalibs/functypes.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/avlnode.h>
+
+typedef struct avltree_s avltree, *avltree_ref ;
+struct avltree_s
+{
+ gensetdyn x ;
+ unsigned int root ;
+ dtokfunc_t_ref dtok ;
+ cmpfunc_t_ref kcmp ;
+ void *external ;
+} ;
+
+#define AVLTREE_ZERO { .x = GENSETDYN_ZERO, .root = (unsigned int)-1, .dtok = 0, .kcmp = 0, .external = 0 }
+extern avltree const avltree_zero ;
+#define avltree_len(t) gensetdyn_n(&(t)->x)
+#define avltree_totalsize(t) ((t)->x.storage.len)
+#define avltree_nodes(t) ((avlnode_ref)(t)->x.storage.s)
+#define avltree_data(t, i) (avltree_nodes(t)[i].data)
+#define avltree_root(t) ((t)->root)
+#define avltree_setroot(t, r) ((t)->root = (r))
+
+extern void avltree_free (avltree_ref) ;
+extern void avltree_init (avltree_ref, unsigned int, unsigned int, unsigned int, dtokfunc_t_ref, cmpfunc_t_ref, void *) ;
+#define AVLTREE_INIT(b, num, den, dtk, f, p) { .x = GENSETDYN_INIT(avlnode, (b), num, den), .root = (unsigned int)-1, .dtok = (dtk), .kcmp = (f), .external = (p) }
+
+#define avltree_searchnode(t, k) avlnode_searchnode(avltree_nodes(t), avltree_totalsize(t), avltree_root(t), k, (t)->dtok, (t)->kcmp, (t)->external)
+#define avltree_search(t, k, data) avlnode_search(avltree_nodes(t), avltree_totalsize(t), avltree_root(t), k, (data), (t)->dtok, (t)->kcmp, (t)->external)
+
+#define avltree_height(t) avlnode_height(avltree_nodes(t), avltree_totalsize(t), avltree_root(t))
+
+#define avltree_extremenode(t, h) avlnode_extremenode(avltree_nodes(t), avltree_totalsize(t), avltree_root(t), h)
+#define avltree_minnode(t) avltree_extremenode((t), 0)
+#define avltree_maxnode(t) avltree_extremenode((t), 1)
+
+#define avltree_extreme(t, h, data) avlnode_extreme(avltree_nodes(t), avltree_totalsize(t), avltree_root(t), (h), data)
+#define avltree_min(t, data) avltree_extreme((t), 0, data)
+#define avltree_max(t, data) avltree_extreme((t), 1, data)
+
+extern int avltree_newnode (avltree_ref, unsigned int, unsigned int *) ;
+#define avltree_insertnode(t, i) avltree_setroot(t, avlnode_insertnode(avltree_nodes(t), avltree_totalsize(t), avltree_root(t), i, (t)->dtok, (t)->kcmp, (t)->external))
+extern int avltree_insert (avltree_ref, unsigned int) ;
+
+#define avltree_deletenode(t, i) avltree_delete(t, (*(t)->dtok)(avltree_data(t, i)))
+extern int avltree_delete (avltree_ref, void const *) ;
+
+#define avltree_iter(t, f, p) avlnode_iter(avltree_nodes(t), avltree_totalsize(t), avltree_root(t), f, p)
+
+#endif
diff --git a/src/include/skalibs/avltreen.h b/src/include/skalibs/avltreen.h
new file mode 100644
index 0000000..8151e9d
--- /dev/null
+++ b/src/include/skalibs/avltreen.h
@@ -0,0 +1,87 @@
+/* ISC license. */
+
+#ifndef AVLTREEN_H
+#define AVLTREEN_H
+
+#include <skalibs/functypes.h>
+#include <skalibs/genset.h>
+#include <skalibs/avlnode.h>
+
+
+ /* avltreen: just the structure. Storage and freelist are outside. */
+
+typedef struct avltreen_s avltreen, *avltreen_ref ;
+struct avltreen_s
+{
+ genset x ;
+ unsigned int root ;
+ dtokfunc_t_ref dtok ;
+ cmpfunc_t_ref kcmp ;
+ void *external ;
+} ;
+
+#define AVLTREEN_ZERO { .x = GENSET_ZERO, .root = (unsigned int)-1, .dtok = 0, .kcmp = 0, .external = 0 }
+#define avltreen_totalsize(t) ((t)->x.max)
+#define avltreen_len(t) genset_n(&(t)->x)
+#define avltreen_nodes(t) ((avlnode_ref)(t)->x.storage)
+#define avltreen_data(t, i) (avltreen_nodes(t)[i].data)
+#define avltreen_root(t) ((t)->root)
+#define avltreen_setroot(t, r) ((t)->root = (r))
+extern void avltreen_init (avltreen_ref, avlnode_ref, unsigned int *, unsigned int, dtokfunc_t_ref, cmpfunc_t_ref, void *) ;
+
+#define avltreen_searchnode(t, k) avlnode_searchnode(avltreen_nodes(t), avltreen_totalsize(t), avltreen_root(t), (k), (t)->dtok, (t)->kcmp, (t)->external)
+#define avltreen_search(t, k, data) avlnode_search(avltreen_nodes(t), avltreen_totalsize(t), avltreen_root(t), k, (data), (t)->dtok, (t)->kcmp, (t)->external)
+
+#define avltreen_height(t) avlnode_height(avltreen_nodes(t), avltreen_totalsize(t), avltreen_root(t))
+
+#define avltreen_extremenode(t, h) avlnode_extremenode(avltreen_nodes(t), avltreen_totalsize(t), avltreen_root(t), h)
+#define avltreen_minnode(t) avltreen_extremenode((t), 0)
+#define avltreen_maxnode(t) avltreen_extremenode((t), 1)
+
+#define avltreen_extreme(t, h, data) avlnode_extreme(avltreen_nodes(t), avltreen_totalsize(t), avltreen_root(t), (h), data)
+#define avltreen_min(t, data) avltreen_extreme((t), 0, data)
+#define avltreen_max(t, data) avltreen_extreme((t), 1, data)
+
+extern unsigned int avltreen_newnode (avltreen_ref, unsigned int) ;
+#define avltreen_insertnode(t, i) avltreen_setroot(t, avlnode_insertnode(avltreen_nodes(t), avltreen_totalsize(t), avltreen_root(t), i, (t)->dtok, (t)->kcmp, (t)->external))
+extern int avltreen_insert (avltreen_ref, unsigned int) ;
+
+#define avltreen_deletenode(t, i) avltreen_delete(t, avltreen_data(t, i))
+extern int avltreen_delete (avltreen_ref, void const *) ;
+
+#define avltreen_iter(t, f, p) avlnode_iter(avltreen_nodes(t), avltreen_totalsize(t), avltreen_root(t), f, p)
+
+
+ /* avltreeb: everything in one place. Stack or BSS, or heap if you insist */
+
+#define AVLTREEB_TYPE(size) struct { avlnode storage[size] ; unsigned int freelist[size] ; avltreen info ; }
+#define avltreeb_init(t, size, dtk, f, p) avltreen_init(&(t)->info, (t)->storage, (t)->freelist, size, dtk, f, p)
+#define avltreeb_totalsize(t) avltreen_totalsize(&(t)->info)
+#define avltreeb_len(t) avltreen_len(&(t)->info)
+#define avltreeb_nodes(t) ((avlnode_ref)(t)->storage)
+#define avltreeb_data(t, i) (avltreeb_nodes(t)[i].data)
+#define avltreeb_root(t) ((t)->info.root)
+#define avltreeb_setroot(t, r) ((t)->info.root = (r))
+
+#define avltreeb_searchnode(t, k) avlnode_searchnode(avltreeb_nodes(t), avltreeb_totalsize(t), avltreeb_root(t), (k), (t)->info.dtok, (t)->info.kcmp, (t)->info.external)
+#define avltreeb_search(t, k, data) avlnode_search(avltreeb_nodes(t), avltreeb_totalsize(t), avltreeb_root(t), k, (data), (t)->info.dtok, (t)->info.kcmp, (t)->info.external)
+#define avltreeb_height(t) avlnode_height(avltreeb_nodes(t), avltreeb_totalsize(t), avltreeb_root(t))
+
+#define avltreeb_extremenode(t, h) avlnode_extremenode(avltreeb_nodes(t), avltreeb_totalsize(t), avltreeb_root(t), h)
+#define avltreeb_minnode(t) avltreeb_extremenode((t), 0)
+#define avltreeb_maxnode(t) avltreeb_extremenode((t), 1)
+
+#define avltreeb_extreme(t, h, data) avlnode_extremenode(avltreeb_nodes(t), avltreeb_totalsize(t), avltreeb_root(t), h, data)
+#define avltreeb_min(t, data) avltreeb_extreme((t), 0, data)
+#define avltreeb_max(t, data) avltreeb_extreme((t), 1, data)
+
+#define avltreeb_newnode(t, d) avltreen_newnode(&(t)->info, d)
+#define avltreeb_insertnode(t, i) avltreeb_setroot(t, avlnode_insertnode(avltreeb_nodes(t), avltreeb_totalsize(t), avltreeb_root(t), (i), (t)->info.dtok, (t)->info.kcmp, (t)->info.external))
+#define avltreeb_insert(t, d) avltreen_insert(&(t)->info, d)
+
+#define avltreeb_deletenode(t, i) avltreeb_delete(t, avltreeb_data(t, i))
+#define avltreeb_delete(t, k) avltreen_delete(&(t)->info, k)
+
+#define avltreeb_iter(t, f, p) avlnode_iter(avltreeb_nodes(t), avltreeb_totalsize(t), avltreeb_root(t), f, p)
+
+#endif
diff --git a/src/include/skalibs/biguint.h b/src/include/skalibs/biguint.h
new file mode 100644
index 0000000..94e99a9
--- /dev/null
+++ b/src/include/skalibs/biguint.h
@@ -0,0 +1,46 @@
+/* ISC license. */
+
+#ifndef BIGUINT_H
+#define BIGUINT_H
+
+#include <skalibs/gccattributes.h>
+#include <skalibs/uint32.h>
+
+extern void bu_pack (char *, uint32 const *, unsigned int) ;
+extern void bu_unpack (char const *, uint32 *, unsigned int) ;
+extern void bu_pack_big (char *, uint32 const *, unsigned int) ;
+extern void bu_unpack_big (char const *, uint32 *, unsigned int) ;
+extern unsigned int bu_fmt (char *, uint32 const *, unsigned int) ;
+extern unsigned int bu_scanlen (char const *, unsigned int *) ;
+extern int bu_scan (char const *, unsigned int, uint32 *, unsigned int, unsigned int) ;
+
+extern unsigned int bu_len (uint32 const *, unsigned int) gccattr_pure ;
+extern void bu_zero (uint32 *, unsigned int) ;
+extern int bu_copy (uint32 *, unsigned int, uint32 const *, unsigned int) ;
+extern int bu_cmp (uint32 const *, unsigned int, uint32 const *, unsigned int) gccattr_pure ;
+
+#define bu_add(c, cn, a, an, b, bn) bu_addc(c, cn, a, an, b, (bn), 0)
+extern int bu_addc (uint32 *, unsigned int, uint32 const *, unsigned int, uint32 const *, unsigned int, int) ;
+#define bu_sub(c, cn, a, an, b, bn) bu_subc(c, cn, a, an, b, (bn), 0)
+extern int bu_subc (uint32 *, unsigned int, uint32 const *, unsigned int, uint32 const *, unsigned int, int) ;
+extern int bu_mul (uint32 *, unsigned int, uint32 const *, unsigned int, uint32 const *, unsigned int) ;
+extern int bu_div (uint32 const *, unsigned int, uint32 const *, unsigned int, uint32 *, unsigned int, uint32 *, unsigned int) ;
+extern int bu_mod (uint32 *, unsigned int, uint32 const *, unsigned int) ;
+extern int bu_gcd (uint32 *, unsigned int, uint32 const *, unsigned int, uint32 const *, unsigned int) ;
+
+#define bu_slb(a, n) bu_slbc(a, n, 0)
+extern int bu_slbc (uint32 *, unsigned int, int) ;
+#define bu_srb(a, n) bu_srbc(a, n, 0)
+extern int bu_srbc (uint32 *, unsigned int, int) ;
+
+extern int bu_addmod (uint32 *, unsigned int, uint32 const *, unsigned int, uint32 const *, unsigned int, uint32 const *, unsigned int) ;
+extern int bu_submod (uint32 *, unsigned int, uint32 const *, unsigned int, uint32 const *, unsigned int, uint32 const *, unsigned int) ;
+extern int bu_invmod (uint32 *, unsigned int, uint32 const *, unsigned int) ;
+extern int bu_divmod (uint32 *, unsigned int, uint32 const *, unsigned int, uint32 const *, unsigned int, uint32 const *, unsigned int) ;
+
+extern void bu_scan_internal (char const *, unsigned int, uint32 *) ;
+extern void bu_copy_internal (uint32 *, uint32 const *, unsigned int) ;
+extern void bu_div_internal (uint32 *, unsigned int, uint32 const *, unsigned int, uint32 *, unsigned int) ;
+extern void bu_divmod_internal (uint32 *, uint32 *, uint32 const *, unsigned int) ;
+
+#endif
diff --git a/src/include/skalibs/bitarray.h b/src/include/skalibs/bitarray.h
new file mode 100644
index 0000000..7cf79b3
--- /dev/null
+++ b/src/include/skalibs/bitarray.h
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#ifndef BITARRAY_H
+#define BITARRAY_H
+
+#include <skalibs/gccattributes.h>
+
+#define bitarray_div8(n) ((n) ? 1U + (((n) - 1) >> 3) : 0U)
+
+extern void bitarray_clearsetn (unsigned char *, unsigned int, unsigned int, int) ;
+#define bitarray_clearn(s, start, len) bitarray_clearsetn(s, start, (len), 0)
+#define bitarray_setn(s, start, len) bitarray_clearsetn(s, start, (len), 1)
+
+#define bitarray_peek(s, n) (((s)[(n)>>3] & (1U<<((n)&7))) ? 1 : 0)
+#define bitarray_isset(b, n) bitarray_peek(b, n)
+#define bitarray_clear(s, n) ((s)[(n)>>3] &= ~(1U << ((n) & 7)))
+#define bitarray_set(s, n) ((s)[(n)>>3] |= 1U << ((n) & 7))
+#define bitarray_poke(s, n, h) ((h) ? bitarray_set(s, n) : bitarray_clear(s, n))
+
+extern int bitarray_testandpoke (unsigned char *, unsigned int, int) ;
+#define bitarray_testandclear(b, n) bitarray_testandpoke(b, n, 0)
+#define bitarray_testandset(b, n) bitarray_testandpoke(b, n, 1)
+
+extern unsigned int bitarray_firstclear (unsigned char const *, unsigned int) gccattr_pure ;
+extern unsigned int bitarray_firstset (unsigned char const *, unsigned int) gccattr_pure ;
+#define bitarray_first(s, n, h) ((h) ? bitarray_firstset(s, n) : bitarray_firstclear(s, n))
+
+extern void bitarray_not (unsigned char *, unsigned int, unsigned int) ;
+extern void bitarray_and (unsigned char *, unsigned char const *, unsigned char const *, unsigned int) ;
+extern void bitarray_or (unsigned char *, unsigned char const *, unsigned char const *, unsigned int) ;
+extern void bitarray_xor (unsigned char *, unsigned char const *, unsigned char const *, unsigned int) ;
+
+#endif
diff --git a/src/include/skalibs/bufalloc.h b/src/include/skalibs/bufalloc.h
new file mode 100644
index 0000000..c2779b6
--- /dev/null
+++ b/src/include/skalibs/bufalloc.h
@@ -0,0 +1,36 @@
+/* ISC license. */
+
+#ifndef BUFALLOC_H
+#define BUFALLOC_H
+
+#include <skalibs/gccattributes.h>
+#include <skalibs/stralloc.h>
+
+typedef struct bufalloc bufalloc, *bufalloc_ref ;
+struct bufalloc
+{
+ stralloc x ;
+ unsigned int p ;
+ int fd ;
+ int (*op) (int, char const *, unsigned int) ;
+} ;
+
+#define BUFALLOC_ZERO { .x = STRALLOC_ZERO, .p = 0, .fd = -1, .op = 0 }
+#define BUFALLOC_INIT(f, d) { .x = STRALLOC_ZERO, .p = 0, .fd = (d), .op = (f) }
+extern void bufalloc_init (bufalloc_ref, int (*)(int, char const *, unsigned int), int) ;
+#define bufalloc_shrink(ba) stralloc_shrink(&(ba)->x)
+#define bufalloc_free(ba) stralloc_free(&(ba)->x)
+#define bufalloc_put(ba, s, n) stralloc_catb(&(ba)->x, s, n)
+#define bufalloc_puts(ba, s) stralloc_cats(&(ba)->x, s)
+#define bufalloc_putv(ba, v, n) stralloc_catv(&(ba)->x, v, n)
+#define bufalloc_fd(ba) ((ba)->fd)
+extern int bufalloc_getfd (bufalloc const *) gccattr_pure ;
+extern int bufalloc_flush (bufalloc_ref) ;
+extern void bufalloc_clean (bufalloc_ref) ;
+#define bufalloc_len(ba) ((ba)->x.len - (ba)->p)
+extern unsigned int bufalloc_getlen (bufalloc const *) gccattr_pure ;
+#define bufalloc_isempty(ba) ((ba)->x.len == (ba)->p)
+
+extern bufalloc_ref bufalloc_1, bufalloc_2 ;
+
+#endif
diff --git a/src/include/skalibs/buffer.h b/src/include/skalibs/buffer.h
new file mode 100644
index 0000000..3064c51
--- /dev/null
+++ b/src/include/skalibs/buffer.h
@@ -0,0 +1,134 @@
+/* ISC license. */
+
+#ifndef BUFFER_H
+#define BUFFER_H
+
+#include <skalibs/gccattributes.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/cbuffer.h>
+#include <skalibs/diuint.h>
+#include <skalibs/siovec.h>
+
+typedef int buffer_io_func_t (int, siovec_t const *, unsigned int, void *) ;
+typedef buffer_io_func_t *buffer_io_func_t_ref ;
+
+typedef struct buffer_s buffer, buffer_t, *buffer_ref, *buffer_t_ref ;
+struct buffer_s
+{
+ buffer_io_func_t *op ;
+ int fd ;
+ cbuffer_t c ;
+ void *aux ;
+} ;
+#define BUFFER_ZERO { .op = 0, .fd = -1, .c = CBUFFER_ZERO, .aux = 0 }
+
+
+ /*
+ Circular buffers need to be 1 char bigger than the storage space,
+ so that the head == tail case is nonambiguous (empty).
+ */
+
+#define BUFFER_INSIZE 8193
+#define BUFFER_OUTSIZE 8193
+#define BUFFER_ERRSIZE 1025
+#define BUFFER_INSIZE_SMALL 513
+#define BUFFER_OUTSIZE_SMALL 513
+
+#define BUFFER_INIT_AUX(f, d, buf, len, data) { .op = (f), .fd = (d), .c = CBUFFER_INIT(buf, len), .aux = (data) }
+#define BUFFER_INIT(f, d, buf, len) BUFFER_INIT_AUX(f, d, buf, (len), 0)
+extern int buffer_init_aux (buffer *, buffer_io_func_t *, int, char *, unsigned int, void *) ;
+#define buffer_init(b, f, d, buf, len) buffer_init_aux(b, f, d, buf, len, 0)
+
+
+ /* Writing */
+
+extern int buffer_flush (buffer *) ;
+
+#define buffer_putnoflush(b, s, len) cbuffer_put(&(b)->c, s, len)
+#define buffer_putvnoflush(b, v, n) cbuffer_putv(&(b)->c, v, n)
+#define buffer_putsnoflush(b, s) buffer_putnoflush(b, (s), str_len(s))
+
+extern int buffer_putallnoflush (buffer *, char const *, unsigned int) ;
+extern int buffer_putvallnoflush (buffer *, siovec_t const *, unsigned int) ;
+#define buffer_putsallnoflush(b, s) buffer_putallnoflush(b, (s), str_len(s))
+
+extern int buffer_putall (buffer *, char const *, unsigned int, unsigned int *) ;
+extern int buffer_putvall (buffer *, siovec_t const *, unsigned int, diuint *) ;
+#define buffer_putsall(b, s, w) buffer_putall(b, s, str_len(s), w)
+
+#define buffer_putallflush(b, s, len, w) (buffer_putall(b, s, len, w) && buffer_flush(b))
+#define buffer_putvallflush(b, v, n, w) (buffer_putvall(b, v, n, w) && buffer_flush(b))
+#define buffer_putsallflush(b, s, w) buffer_putallflush(b, s, str_len(s), w)
+
+extern int buffer_put (buffer *, char const *, unsigned int) ;
+extern int buffer_putv (buffer *, siovec_t const *, unsigned int) ;
+#define buffer_puts(b, s) buffer_put(b, (s), str_len(s))
+
+extern int buffer_putflush (buffer *, char const *, unsigned int) ;
+extern int buffer_putvflush (buffer *, siovec_t const *, unsigned int) ;
+#define buffer_putsflush(b, s) buffer_putflush(b, (s), str_len(s))
+
+#define buffer_unput(b, n) cbuffer_unput(&(b)->c, n)
+#define buffer_wpeek(b, v) cbuffer_wpeek(&(b)->c, v)
+#define buffer_wseek(b, n) cbuffer_wseek(&(b)->c, n)
+extern buffer_io_func_t buffer_write ;
+
+
+ /* Reading */
+
+extern int buffer_fill (buffer *) ;
+
+#define buffer_getnofill(b, s, len) cbuffer_get(&(b)->c, s, len)
+#define buffer_getvnofill(b, v, n) cbuffer_getv(&(b)->c, v, n)
+
+extern int buffer_getallnofill (buffer *, char *, unsigned int) ;
+extern int buffer_getvallnofill (buffer *, siovec_t const *, unsigned int) ;
+
+extern int buffer_getall (buffer *, char *, unsigned int, unsigned int *) ;
+extern int buffer_getvall (buffer *, siovec_t const *, unsigned int, diuint *) ;
+
+extern int buffer_get (buffer *, char *, unsigned int) ;
+extern int buffer_getv (buffer *, siovec_t const *, unsigned int) ;
+
+#define buffer_unget(b, n) cbuffer_unget(&(b)->c, n)
+#define buffer_rpeek(b, n) cbuffer_rpeek(&(b)->c, n)
+#define buffer_rseek(b, n) cbuffer_rseek(&(b)->c, n)
+extern buffer_io_func_t buffer_read ;
+
+
+ /* Utility */
+
+#define buffer_len(b) cbuffer_len(&(b)->c)
+extern unsigned int buffer_getlen (buffer const *) gccattr_pure ;
+#define buffer_available(b) cbuffer_available(&(b)->c)
+#define buffer_isempty(b) cbuffer_isempty(&(b)->c)
+#define buffer_isfull(b) cbuffer_isfull(&(b)->c)
+#define buffer_fd(b) ((b)->fd)
+extern int buffer_getfd (buffer const *) gccattr_pure ;
+#define buffer_isreadable(b) (!buffer_isfull(b))
+#define buffer_iswritable(b) (!buffer_isempty(b))
+
+
+ /* Globals */
+
+extern buffer_io_func_t buffer_flush1read ;
+
+extern buffer buffer_0_ ;
+#define buffer_0 (&buffer_0_)
+
+extern buffer buffer_0small_ ;
+#define buffer_0small (&buffer_0small_)
+
+extern buffer buffer_0f1_ ;
+#define buffer_0f1 (&buffer_0f1_)
+
+extern buffer buffer_1_ ;
+#define buffer_1 (&buffer_1_)
+
+extern buffer buffer_1small_ ;
+#define buffer_1small (&buffer_1small_)
+
+extern buffer buffer_2_ ;
+#define buffer_2 (&buffer_2_)
+
+#endif
diff --git a/src/include/skalibs/bytestr.h b/src/include/skalibs/bytestr.h
new file mode 100644
index 0000000..52e9bd6
--- /dev/null
+++ b/src/include/skalibs/bytestr.h
@@ -0,0 +1,65 @@
+/* ISC license. */
+
+#ifndef BYTESTR_H
+#define BYTESTR_H
+
+#include <skalibs/config.h>
+#include <skalibs/gccattributes.h>
+
+/* for Alphas and other archs where char != 8bit */
+#define T8(x) ((x) & 0xffU)
+
+#ifndef SKALIBS_FLAG_REPLACE_LIBC
+
+#include <sys/types.h>
+#include <string.h>
+
+#define byte_copy(to, n, from) memmove(to, (from), n)
+#define byte_copyr(to, n, from) memmove(to, (from), n)
+#define byte_diff(a, n, b) memcmp(a, (b), n)
+#define byte_zero(p, n) memset(p, 0, n)
+#define str_len(s) strlen(s)
+#define str_diff(a, b) strcmp(a, b)
+#define str_diffn(a, b, n) strncmp(a, b, n)
+#define str_copy(to, from) strlen(strcpy(to, from))
+
+#else
+
+extern void byte_copy (char *, unsigned int, char const *) ;
+extern void byte_copyr (char *, unsigned int, char const *) ;
+extern int byte_diff (char const *, unsigned int, char const *) gccattr_pure ;
+extern void byte_zero (void *, unsigned int) ;
+extern unsigned int str_len (char const *) gccattr_pure ;
+extern int str_diff (char const *, char const *) gccattr_pure ;
+extern int str_diffn (char const *, char const *, unsigned int) gccattr_pure ;
+extern unsigned int str_copy (char *, char const *) ;
+
+#endif
+
+
+extern unsigned int byte_chr (char const *, unsigned int, int) gccattr_pure ;
+extern unsigned int byte_rchr (char const *, unsigned int, int) gccattr_pure ;
+extern unsigned int byte_in (char const *, unsigned int, char const *, unsigned int) gccattr_pure ;
+#define byte_equal(s, n, t) (!byte_diff((s), (n), (t)))
+extern unsigned int byte_count (char const *, unsigned int, char) gccattr_pure ;
+
+#define str_diffb(a, n, b) str_diffn(a, (b), n)
+extern unsigned int str_chr (char const *, int) gccattr_pure ;
+extern unsigned int str_rchr (char const *, int) gccattr_pure ;
+extern int str_start (char const *, char const *) gccattr_pure ;
+#define str_equal(s, t) (!str_diff(s, t))
+extern unsigned int str_strn (char const *, unsigned int, char const *, unsigned int) gccattr_pure ;
+
+extern void case_lowers (char *) ;
+extern void case_lowerb (char *, unsigned int) ;
+extern void case_uppers (char *) ;
+extern void case_upperb (char *, unsigned int) ;
+#define case_equals(a, b) (!case_diffs(a, b))
+#define case_equalb(a, n, b) (!case_diffb(a, n, b))
+extern int case_diffs (char const *, char const *) gccattr_pure ;
+extern int case_diffb (char const *, unsigned int, char const *) gccattr_pure ;
+#define case_starts(s, t) case_startb(s, str_len(s), t)
+extern int case_startb (char const *, unsigned int, char const *) gccattr_pure ;
+extern unsigned int case_str (char const *, char const *) gccattr_pure ;
+
+#endif
diff --git a/src/include/skalibs/cbuffer.h b/src/include/skalibs/cbuffer.h
new file mode 100644
index 0000000..a80e3af
--- /dev/null
+++ b/src/include/skalibs/cbuffer.h
@@ -0,0 +1,62 @@
+/* ISC license. */
+
+#ifndef CBUFFER_H
+#define CBUFFER_H
+
+#include <skalibs/gccattributes.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/diuint.h>
+#include <skalibs/siovec.h>
+
+typedef struct cbuffer_s cbuffer_t, *cbuffer_t_ref ;
+struct cbuffer_s
+{
+ char *x ;
+ unsigned int a ; /* total length */
+ unsigned int p ; /* head */
+ unsigned int n ; /* tail */
+} ;
+#define CBUFFER_ZERO { .x = 0, .a = 0, .p = 0, .n = 0 }
+
+ /*
+ Circular buffers need to be 1 char bigger than the storage space,
+ so that the head == tail case is nonambiguous (empty).
+ */
+
+#define CBUFFER_INIT(buf, len) { .x = (buf), .a = (len), .p = 0, .n = 0 }
+extern int cbuffer_init (cbuffer_t *, char *, unsigned int) ;
+
+
+ /* Writing */
+
+extern unsigned int cbuffer_put (cbuffer_t *, char const *, unsigned int) ;
+extern unsigned int cbuffer_putv (cbuffer_t *, siovec_t const *, unsigned int) ;
+#define cbuffer_puts(b, s) cbuffer_put(b, (s), str_len(s))
+
+#define cbuffer_UNPUT(b, w) ((b)->n = ((b)->a + (b)->n - w) % (b)->a, w) ;
+extern unsigned int cbuffer_unput (cbuffer_t *, unsigned int) ;
+extern void cbuffer_wpeek (cbuffer_t *, siovec_t *) ;
+#define cbuffer_WSEEK(b, w) ((b)->n = ((b)->n + (w)) % (b)->a, w)
+extern unsigned int cbuffer_wseek (cbuffer_t *, unsigned int) ;
+
+
+ /* Reading */
+
+extern unsigned int cbuffer_get (cbuffer_t *, char *, unsigned int) ;
+extern unsigned int cbuffer_getv (cbuffer_t *, siovec_t const *, unsigned int) ;
+
+#define cbuffer_UNGET(b, n) ((b)->p = ((b)->a + (b)->p - n) % (b)->a, n) ;
+extern unsigned int cbuffer_unget (cbuffer_t *, unsigned int) ;
+extern void cbuffer_rpeek (cbuffer_t *, siovec_t *) ;
+#define cbuffer_RSEEK(b, n) ((b)->p = ((b)->p + (n)) % (b)->a, n)
+extern unsigned int cbuffer_rseek (cbuffer_t *, unsigned int) ;
+
+
+ /* Utility */
+
+#define cbuffer_len(b) ((unsigned int)(((b)->a - (b)->p + (b)->n) % (b)->a))
+#define cbuffer_available(b) ((unsigned int)(((b)->a - (b)->n + (b)->p - 1) % (b)->a))
+#define cbuffer_isempty(b) (!cbuffer_len(b))
+#define cbuffer_isfull(b) (!cbuffer_available(b))
+
+#endif
diff --git a/src/include/skalibs/cdb.h b/src/include/skalibs/cdb.h
new file mode 100644
index 0000000..9e9aae0
--- /dev/null
+++ b/src/include/skalibs/cdb.h
@@ -0,0 +1,51 @@
+/* ISC license. */
+
+#ifndef CDB_H
+#define CDB_H
+
+#include <skalibs/gccattributes.h>
+#include <skalibs/uint32.h>
+
+#define CDB_HASHSTART 5381
+extern uint32 cdb_hashadd (uint32, unsigned char) gccattr_const ;
+extern uint32 cdb_hash (char const *, unsigned int) gccattr_pure ;
+
+typedef struct cdb cdb_t, *cdb_t_ref ;
+struct cdb
+{
+ char *map ; /* 0 if no map */
+ int fd ; /* -1 if uninitted, negative if mapped, nonnegative if nomapped */
+ uint32 size ; /* initialized if map is nonzero */
+ uint32 loop ; /* number of hash slots searched under this key */
+ uint32 khash ; /* initialized if loop is nonzero */
+ uint32 kpos ; /* initialized if loop is nonzero */
+ uint32 hpos ; /* initialized if loop is nonzero */
+ uint32 hslots ; /* initialized if loop is nonzero */
+ uint32 dpos ; /* initialized if cdb_findnext() returns 1 */
+ uint32 dlen ; /* initialized if cdb_findnext() returns 1 */
+} ;
+
+#define CDB_ZERO { .map = 0, .fd = -1, .size = 0, .loop = 0, .khash = 0, .kpos = 0, .hpos = 0, .hslots = 0, .dpos = 0, .dlen = 0 }
+extern struct cdb const cdb_zero ;
+
+extern void cdb_free (struct cdb *) ;
+
+#define cdb_init(c, fd) (cdb_init_map(c, (fd), 1) ? 0 : -1)
+extern int cdb_init_map (struct cdb *, int fd, int) ;
+extern int cdb_mapfile (struct cdb *, char const *) ;
+extern int cdb_read (struct cdb *, char *, unsigned int, uint32) ;
+#define cdb_findstart(c) ((c)->loop = 0)
+extern int cdb_findnext (struct cdb *, char const *, unsigned int) ;
+#define cdb_find(c, s, len) (cdb_findstart(c), cdb_findnext(c, s, len))
+
+#define cdb_datapos(c) ((c)->dpos)
+#define cdb_datalen(c) ((c)->dlen)
+#define cdb_keypos(c) ((c)->kpos)
+#define cdb_keylen(c) ((c)->dpos - (c)->kpos)
+
+#define cdb_traverse_init(c, kpos) (*(kpos) = 2048)
+#define cdb_firstkey(c, kpos) (cdb_traverse_init(c, kpos), cdb_nextkey(c, kpos))
+extern int cdb_nextkey (struct cdb *, uint32 *) ;
+extern int cdb_successor (struct cdb *, char const *, unsigned int) ;
+
+#endif
diff --git a/src/include/skalibs/cdb_make.h b/src/include/skalibs/cdb_make.h
new file mode 100644
index 0000000..d0a949b
--- /dev/null
+++ b/src/include/skalibs/cdb_make.h
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#ifndef CDB_MAKE_H
+#define CDB_MAKE_H
+
+#include <skalibs/uint32.h>
+#include <skalibs/diuint32.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/buffer.h>
+
+typedef struct cdb_make cdb_make, *cdb_make_ref ;
+struct cdb_make
+{
+ char buf[BUFFER_OUTSIZE] ;
+ genalloc hplist ; /* diuint32 */
+ buffer b ;
+ uint32 pos ;
+ int fd ;
+} ;
+
+#define CDB_MAKE_ZERO { .buf = "", .hplist = GENALLOC_ZERO, .b = BUFFER_INIT(&buffer_write, -1, 0, 0), .pos = 2048, .fd = -1 }
+
+extern int cdb_make_start (struct cdb_make *, int) ;
+extern int cdb_make_add (struct cdb_make *, char const *, unsigned int, char const *, unsigned int) ;
+extern int cdb_make_finish (struct cdb_make *) ;
+
+#endif
diff --git a/src/include/skalibs/datastruct.h b/src/include/skalibs/datastruct.h
new file mode 100644
index 0000000..1c7d816
--- /dev/null
+++ b/src/include/skalibs/datastruct.h
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#ifndef DATASTRUCT_H
+#define DATASTRUCT_H
+
+#include <skalibs/genset.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/avlnode.h>
+#include <skalibs/avltree.h>
+#include <skalibs/avltreen.h>
+
+#endif
diff --git a/src/include/skalibs/direntry.h b/src/include/skalibs/direntry.h
new file mode 100644
index 0000000..3150e51
--- /dev/null
+++ b/src/include/skalibs/direntry.h
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#ifndef DIRENTRY_H
+#define DIRENTRY_H
+
+#include <sys/types.h>
+#include <dirent.h>
+
+typedef struct dirent direntry, direntry_t, *direntry_ref, *direntry_t_ref ;
+
+extern int dir_close (DIR *) ;
+
+#endif
diff --git a/src/include/skalibs/diuint.h b/src/include/skalibs/diuint.h
new file mode 100644
index 0000000..1c13bd8
--- /dev/null
+++ b/src/include/skalibs/diuint.h
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#ifndef DIUINT_H
+#define DIUINT_H
+
+typedef struct diuint diuint, *diuint_ref ;
+struct diuint
+{
+ unsigned int left ;
+ unsigned int right ;
+} ;
+
+#define DIUINT_ZERO { .left = 0, .right = 0 }
+
+#endif
diff --git a/src/include/skalibs/diuint32.h b/src/include/skalibs/diuint32.h
new file mode 100644
index 0000000..cd8ae75
--- /dev/null
+++ b/src/include/skalibs/diuint32.h
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#ifndef DIUINT32_H
+#define DIUINT32_H
+
+#include <skalibs/uint32.h>
+
+typedef struct diuint32 diuint32, *diuint32_ref ;
+struct diuint32
+{
+ uint32 left ;
+ uint32 right ;
+} ;
+
+#define DIUINT32_ZERO { .left = 0, .right = 0 }
+
+#endif
diff --git a/src/include/skalibs/djbtime.h b/src/include/skalibs/djbtime.h
new file mode 100644
index 0000000..60a1d0b
--- /dev/null
+++ b/src/include/skalibs/djbtime.h
@@ -0,0 +1,70 @@
+/* ISC license. */
+
+#ifndef DJBTIME_H
+#define DJBTIME_H
+
+#include <time.h>
+#include <skalibs/config.h>
+#include <skalibs/uint32.h>
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+
+
+/* UTC <--> TAI conversions */
+/* sysclock can be either TAI-10 or UTC */
+
+extern int utc_from_tai (uint64 *, tai_t const *) ;
+extern int tai_from_utc (tai_t *, uint64) ;
+extern int utc_from_sysclock (uint64 *) ;
+extern int sysclock_from_utc (uint64 *) ;
+
+
+/* NTP internal format */
+
+#define NTP_OFFSET 2208988800UL
+extern int ntp_from_tain (uint64 *, tain_t const *) ;
+extern int tain_from_ntp (tain_t *, uint64) ;
+
+
+/* localtime handling - replaces caltimedate functions */
+/* ltm64 can be either TAI-10 or UTC depending on --enable-right-tz */
+/* normally ltm64 is the same as sysclock, but we allow it to be different */
+/* for instance for musl TAI-10 systems */
+
+typedef struct localtmn_s localtmn_t, *localtmn_t_ref ;
+struct localtmn_s
+{
+ struct tm tm ;
+ uint32 nano ;
+} ;
+
+extern int ltm64_from_tai (uint64 *, tai_t const *) ;
+extern int tai_from_ltm64 (tai_t *, uint64) ;
+extern int ltm64_from_utc (uint64 *) ;
+extern int utc_from_ltm64 (uint64 *) ;
+extern int ltm64_from_sysclock (uint64 *) ;
+extern int sysclock_from_ltm64 (uint64 *) ;
+
+extern int localtm_from_ltm64 (struct tm *, uint64, int) ;
+extern int ltm64_from_localtm (uint64 *, struct tm const *) ;
+extern int localtm_from_sysclock (struct tm *, uint64, int) ;
+extern int sysclock_from_localtm (uint64 *, struct tm const *) ;
+extern int localtm_from_utc (struct tm *, uint64, int) ;
+extern int utc_from_localtm (uint64 *, struct tm const *) ;
+extern int localtm_from_tai (struct tm *, tai_t const *, int) ;
+extern int tai_from_localtm (tai_t *, struct tm const *) ;
+
+extern int localtmn_from_tain (localtmn_t_ref, tain_t const *, int) ;
+extern int tain_from_localtmn (tain_t *, localtmn_t const *) ;
+extern int localtmn_from_sysclock (localtmn_t_ref, tain_t const *, int) ;
+extern int sysclock_from_localtmn (tain_t *, localtmn_t const *) ;
+
+#define LOCALTM_FMT 21
+extern unsigned int localtm_fmt (char *, struct tm const *) ;
+extern unsigned int localtm_scan (char const *, struct tm *) ;
+
+#define LOCALTMN_FMT 31
+extern unsigned int localtmn_fmt (char *, localtmn_t const *) ;
+extern unsigned int localtmn_scan (char const *, localtmn_t_ref) ;
+
+#endif
diff --git a/src/include/skalibs/djbunix.h b/src/include/skalibs/djbunix.h
new file mode 100644
index 0000000..b5f5db4
--- /dev/null
+++ b/src/include/skalibs/djbunix.h
@@ -0,0 +1,149 @@
+/* ISC license. */
+
+#ifndef DJBUNIX_H
+#define DJBUNIX_H
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <skalibs/gccattributes.h>
+#include <skalibs/uint64.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/envalloc.h>
+#include <skalibs/env.h> /* compatibility */
+
+#define DJBUNIX_FLAG_NB 0x01U
+#define DJBUNIX_FLAG_COE 0x02U
+
+extern int coe (int) ;
+extern int uncoe (int) ;
+extern int ndelay_on (int) ;
+extern int ndelay_off (int) ;
+extern int pipe_internal (int *, unsigned int) ;
+#define pipenb(p) pipe_internal(p, DJBUNIX_FLAG_NB)
+#define pipecoe(p) pipe_internal(p, DJBUNIX_FLAG_COE)
+#define pipenbcoe(p) pipe_internal(p, DJBUNIX_FLAG_NB|DJBUNIX_FLAG_COE)
+extern int fd_copy (int, int) ;
+extern int fd_copy2 (int, int, int, int) ;
+extern int fd_move (int, int) ;
+extern int fd_move2 (int, int, int, int) ;
+extern int fd_close (int) ;
+extern int fd_chmod (int, unsigned int) ;
+extern int fd_chown (int, unsigned int, unsigned int) ;
+extern int fd_sync (int) ;
+extern int fd_cat (int, int) ;
+extern unsigned int fd_catn (int, int, unsigned int) ;
+extern int fd_ensure_open (int, int) ;
+#define fd_sanitize() (fd_ensure_open(0, 0) && fd_ensure_open(1, 1))
+extern int lock_ex (int) ;
+extern int lock_exnb (int) ;
+extern int lock_sh (int) ;
+extern int lock_shnb (int) ;
+extern int lock_un (int) ;
+extern int open2 (char const *, unsigned int) ;
+extern int open3 (char const *, unsigned int, unsigned int) ;
+extern int open_read (char const *) ;
+extern int open_readb (char const *) ;
+extern int open_excl (char const *) ;
+extern int open_append (char const *) ;
+extern int open_create (char const *) ;
+extern int open_trunc (char const *) ;
+extern int open_write (char const *) ;
+extern int socket_internal (int, int, int, unsigned int) ;
+extern int socketpair_internal (int, int, int, unsigned int, int *) ;
+
+extern int pathexec_env (char const *, char const *) ;
+extern void pathexec_r (char const *const *, char const *const *, unsigned int, char const *, unsigned int) ;
+extern void pathexec_r_name (char const *, char const *const *, char const *const *, unsigned int, char const *, unsigned int) ;
+extern void pathexec_fromenv (char const *const *, char const *const *, unsigned int) ;
+extern void execvep (char const *, char const *const *, char const *const *, char const *) ;
+extern void pathexec_run (char const *, char const *const *, char const *const *) ;
+extern void pathexec0_run (char const *const *, char const *const *) ;
+extern void pathexec (char const *const *) ;
+extern void pathexec0 (char const *const *) ;
+
+#define prot_gid(gid) setgid(gid)
+#define prot_uid(uid) setuid(uid)
+extern int prot_readgroups (char const *, gid_t *, unsigned int) ;
+extern int prot_grps (char const *) ;
+extern int prot_setuidgid (char const *) ;
+
+extern long seek_cur (int) ;
+extern int seek_set (int, long) ;
+extern int seek_end (int) ;
+extern int seek_trunc (int, long) ;
+#define seek_begin(fd) (seek_set((fd), 0))
+
+extern pid_t wait_nointr (int *) ;
+extern pid_t waitpid_nointr (pid_t, int *, int) ;
+#define wait_pid(pid, wstat) waitpid_nointr(pid, (wstat), 0)
+#define wait_nohang(wstat) waitpid_nointr(-1, (wstat), WNOHANG)
+extern pid_t wait_pid_nohang (pid_t, int *) ;
+extern int wait_pids_nohang (pid_t const *, unsigned int, int *) ;
+#define wait_status(w) (WIFSIGNALED(w) ? 126 : WEXITSTATUS(w))
+extern unsigned int wait_reap (void) ;
+extern int waitn (pid_t *, unsigned int) ;
+extern int waitn_reap (pid_t *, unsigned int) ;
+
+extern pid_t doublefork (void) ;
+
+extern int fd_chdir (int) ;
+
+#define absolutepath(sa, s) sarealpath(sa, s)
+/* extern char *realpath (char const *, char *) ; */
+extern char *realpath_tmp (char const *, char *, stralloc *) ;
+extern int sarealpath (stralloc *, char const *) ;
+extern int sarealpath_tmp (stralloc *, char const *, stralloc *) ;
+/* extern char *basename (char *) ; */
+extern int sabasename (stralloc *, char const *, unsigned int) ;
+/* extern char *dirname (char *) ; */
+extern int sadirname (stralloc *, char const *, unsigned int) ;
+extern int sagetcwd (stralloc *) ;
+extern int sareadlink (stralloc *, char const *) ;
+extern int sagethostname (stralloc *) ;
+
+extern int slurp (stralloc *, int) ;
+extern int openslurpclose (stralloc *, char const *) ;
+extern int openreadclose (char const *, stralloc *, unsigned int) ;
+extern int openreadnclose (char const *, char *, unsigned int) ;
+extern int openreadfileclose (char const *, stralloc *, unsigned int) ;
+
+#define openwritenclose_unsafe(f, s, n) openwritenclose_unsafe_internal(f, s, (n), 0, 0, 0)
+#define openwritenclose_unsafe_sync(f, s, n) openwritenclose_unsafe_internal(f, s, (n), 0, 0, 1)
+#define openwritenclose_unsafe_devino(f, s, n, dev, ino) openwritenclose_unsafe_internal(f, s, n, dev, (ino), 0)
+#define openwritenclose_unsafe_devino_sync(f, s, n, dev, ino) openwritenclose_unsafe_internal(f, s, n, dev, (ino), 1)
+extern int openwritenclose_unsafe_internal (char const *, char const *, unsigned int, uint64 *, uint64 *, int) ;
+
+#define openwritenclose_suffix(f, s, n, t) openwritenclose_suffix_internal(f, s, n, 0, 0, 0, t)
+#define openwritenclose_suffix_sync(f, s, n, t) openwritenclose_suffix_internal(f, s, n, 0, 0, 1, t)
+#define openwritenclose_suffix_devino(f, s, n, t, dev, ino) openwritenclose_suffix_internal(f, s, n, dev, (ino), 0, t)
+#define openwritenclose_suffix_devino_sync(f, s, n, t, dev, ino) openwritenclose_suffix_internal(f, s, n, dev, (ino), 1, t)
+extern int openwritenclose_suffix_internal (char const *, char const *, unsigned int, uint64 *, uint64 *, int, char const *) ;
+
+extern int rm_rf (char const *) ;
+extern int rm_rf_tmp (char const *, stralloc *) ;
+extern int rm_rf_in_tmp (stralloc *, unsigned int) ; /* caution ! */
+extern int rmstar (char const *) ;
+extern int rmstar_tmp (char const *, stralloc *) ;
+
+
+ /* Simple spawn functions. 0 for no communication, 1 for a child/parent pipe. */
+
+extern pid_t child_spawn0 (char const *, char const *const *, char const *const *) ;
+extern pid_t child_spawn1 (char const *, char const *const *, char const *const *, int *, int) ;
+
+
+ /*
+ Unified function to fork a child with communication canals.
+ * uses posix_spawn() if available, else uses fork+exec
+ * requests n (the last arg) communication fds between parent and child
+ * if n=1, the fd is a Unix socket. If more canals are needed, you can
+ pass them through that socket.
+ * if n>=2, the fds are pipes, parent reads on even and writes on odd.
+ */
+
+extern pid_t child_spawn (char const *, char const *const *, char const *const *, int *, unsigned int) ;
+
+#endif
diff --git a/src/include/skalibs/env.h b/src/include/skalibs/env.h
new file mode 100644
index 0000000..ccb3aac
--- /dev/null
+++ b/src/include/skalibs/env.h
@@ -0,0 +1,26 @@
+/* ISC license. */
+
+#ifndef ENV_H
+#define ENV_H
+
+#include <skalibs/gccattributes.h>
+#include <skalibs/stralloc.h>
+
+extern unsigned int env_len (char const *const *) gccattr_pure ;
+extern char const *env_get (char const *) gccattr_pure ;
+extern char const *env_get2 (char const *const *, char const *) gccattr_pure ;
+extern char const *ucspi_get (char const *) gccattr_pure ;
+extern int env_addmodif (stralloc *, char const *, char const *) ;
+extern int env_make (char const **, unsigned int, char const *, unsigned int) ;
+extern unsigned int env_merge (char const **, unsigned int, char const *const *, unsigned int, char const *, unsigned int) ;
+extern int env_string (stralloc *, char const *const *, unsigned int) ;
+
+#define SKALIBS_ENVDIR_VERBATIM 0x01
+#define SKALIBS_ENVDIR_NOCHOMP 0x02
+extern int envdir_internal (char const *, stralloc *, unsigned int, char) ;
+#define envdir(path, sa) envdir_internal(path, (sa), 0, '\n')
+#define envdir_leaveblanks(path, sa) envdir_internal(path, (sa), SKALIBS_ENVDIR_NOCHOMP, '\n')
+#define envdir_verbatim_chomp(path, sa) envdir_internal(path, (sa), SKALIBS_ENVDIR_VERBATIM, '\n')
+#define envdir_verbatim(path, sa) envdir_internal(path, (sa), SKALIBS_ENVDIR_VERBATIM|SKALIBS_ENVDIR_NOCHOMP, '\n')
+
+#endif
diff --git a/src/include/skalibs/envalloc.h b/src/include/skalibs/envalloc.h
new file mode 100644
index 0000000..1ebcd6b
--- /dev/null
+++ b/src/include/skalibs/envalloc.h
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#ifndef ENVALLOC_H
+#define ENVALLOC_H
+
+#include <skalibs/genalloc.h>
+
+#define ENVALLOC_ZERO GENALLOC_ZERO
+
+extern int envalloc_make (genalloc *, unsigned int, char const *, unsigned int) ;
+extern int envalloc_uniq (genalloc *, char) ;
+extern int envalloc_merge (genalloc *, char const *const *, unsigned int, char const *, unsigned int) ;
+extern int envalloc_0 (genalloc *) ;
+
+#endif
diff --git a/src/include/skalibs/environ.h b/src/include/skalibs/environ.h
new file mode 100644
index 0000000..6bf3041
--- /dev/null
+++ b/src/include/skalibs/environ.h
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#ifndef ENVIRON_H
+#define ENVIRON_H
+
+extern char **environ ;
+
+#endif
diff --git a/src/include/skalibs/fmtscan.h b/src/include/skalibs/fmtscan.h
new file mode 100644
index 0000000..ccfd160
--- /dev/null
+++ b/src/include/skalibs/fmtscan.h
@@ -0,0 +1,53 @@
+/* ISC license. */
+
+#ifndef FMTSCAN_H
+#define FMTSCAN_H
+
+#include <skalibs/gccattributes.h>
+#include <skalibs/uint32.h>
+
+
+ /* fmt */
+
+
+extern unsigned char fmtscan_asc (unsigned char) gccattr_const ;
+
+extern unsigned int str_fmt (char *, char const *) ;
+extern unsigned int strn_fmt (char *, char const *, unsigned int) ;
+
+#define IP4_FMT 20
+extern unsigned int ip4_fmt (char *, char const *) ;
+extern unsigned int ip4_fmtu32 (char *, uint32) ;
+
+extern unsigned int ucharn_fmt (char *, char const *, unsigned int) ;
+extern unsigned int ucharn_fmt_little (char *, char const *, unsigned int) ;
+
+#define IP6_FMT 40
+extern unsigned int ip6_fmt (char *, char const *) ;
+
+#define short_fmt(s, u) long_fmt((s), (long)(u))
+#define int_fmt(s, u) long_fmt((s), (long)(u))
+extern unsigned int long_fmt (char *, long) ;
+
+
+ /* scan */
+
+
+extern unsigned char fmtscan_num (unsigned char, unsigned char) gccattr_const ;
+
+extern unsigned int ip4_scan (char const *, char *) ;
+extern unsigned int ip4_scanu32 (char const *, uint32 *) ;
+extern unsigned int ip4_scanlist_u32 (uint32 *, unsigned int, char const *, unsigned int *) ;
+extern unsigned int ip4_scanlist (char *, unsigned int, char const *, unsigned int *) ;
+extern unsigned int ip6_scan (char const *, char *) ;
+extern unsigned int ip6_scanlist (char *, unsigned int, char const *, unsigned int *) ;
+
+extern unsigned int ucharn_scan (char const *, char *, unsigned int) ;
+extern unsigned int ucharn_scan_little (char const *, char *, unsigned int) ;
+extern unsigned int ucharn_findlen (char const *) gccattr_pure ;
+
+extern unsigned int short_scan (char const *, short *) ;
+extern unsigned int int_scan (char const *, int *) ;
+extern unsigned int long_scan (char const *, long *) ;
+
+#endif
diff --git a/src/include/skalibs/functypes.h b/src/include/skalibs/functypes.h
new file mode 100644
index 0000000..15cdbcc
--- /dev/null
+++ b/src/include/skalibs/functypes.h
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#ifndef FUNCTYPES_H
+#define FUNCTYPES_H
+
+typedef int uintcmpfunc_t (unsigned int, unsigned int, void *) ;
+typedef uintcmpfunc_t *uintcmpfunc_t_ref ;
+
+typedef int cmpfunc_t (void const *, void const *, void *) ;
+typedef cmpfunc_t *cmpfunc_t_ref ;
+
+typedef void *dtokfunc_t (unsigned int, void *) ;
+typedef dtokfunc_t *dtokfunc_t_ref ;
+
+typedef int iterfunc_t (char *, void *) ;
+typedef iterfunc_t *iterfunc_t_ref ;
+
+typedef void freefunc_t (void *) ;
+typedef freefunc_t *freefunc_t_ref ;
+
+typedef int initfunc_t (void *) ;
+typedef initfunc_t *initfunc_t_ref ;
+
+typedef unsigned int uinitfunc_t (void *) ;
+typedef uinitfunc_t *uinitfunc_t_ref ;
+
+typedef int iofunc_t (int, char *, unsigned int) ;
+typedef iofunc_t *iofunc_t_ref ;
+
+typedef unsigned int alliofunc_t (int, char *, unsigned int) ;
+typedef alliofunc_t *alliofunc_t_ref ;
+
+#endif
diff --git a/src/include/skalibs/gccattributes.h b/src/include/skalibs/gccattributes.h
new file mode 100644
index 0000000..0584480
--- /dev/null
+++ b/src/include/skalibs/gccattributes.h
@@ -0,0 +1,61 @@
+/* ISC license. */
+
+#ifndef GCCATTRIBUTES_H
+#define GCCATTRIBUTES_H
+
+#ifdef __GNUC__
+
+#define gccattr_noreturn __attribute__((__noreturn__))
+#define gccattr_noinline __attribute__((__noinline__))
+#define gccattr_inline __attribute__((__always_inline__))
+#define gccattr_const __attribute__((__const__))
+#define gccattr_unused __attribute__((__unused__))
+#define gccattr_used __attribute__((__used__))
+#define gccattr_weak __attribute__((__weak__))
+#define gccattr_aligned __attribute__((__aligned__))
+
+# if (__GNUC__ >= 3) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 96))
+#define gccattr_malloc __attribute__((__malloc__))
+#define gccattr_pure __attribute__((__pure__))
+# else
+#define gccattr_malloc
+#define gccattr_pure
+# endif
+
+# if (__GNUC__ >= 3)
+#define gccattr_deprecated __attribute__((__deprecated__))
+# else
+#define gccattr_deprecated
+# endif
+
+#else
+
+#define gccattr_noreturn
+#define gccattr_noinline
+#define gccattr_inline
+#define gccattr_const
+#define gccattr_unused
+#define gccattr_used
+#define gccattr_weak
+#define gccattr_aligned
+#define gccattr_malloc
+#define gccattr_pure
+#define gccattr_deprecated
+
+#endif
+
+#ifdef GCCATTR_COMPAT_0_22
+#define _a_noreturn gccattr_noreturn
+#define _a_noinline gccattr_noinline
+#define _a_inline gccattr_inline
+#define _a_const gccattr_const
+#define _a_unused gccattr_unused
+#define _a_used gccattr_used
+#define _a_weak gccattr_weak
+#define _a_aligned gccattr_aligned
+#define _a_malloc gccattr_malloc
+#define _a_pure gccattr_pure
+#define _a_deprecated gccattr_deprecated
+#endif
+
+#endif
diff --git a/src/include/skalibs/genalloc.h b/src/include/skalibs/genalloc.h
new file mode 100644
index 0000000..1aa0613
--- /dev/null
+++ b/src/include/skalibs/genalloc.h
@@ -0,0 +1,35 @@
+/* ISC license. */
+
+#ifndef GENALLOC_H
+#define GENALLOC_H
+
+#include <skalibs/stralloc.h>
+#include <skalibs/functypes.h>
+
+typedef stralloc genalloc, *genalloc_ref ;
+
+#define GENALLOC_ZERO STRALLOC_ZERO
+#define genalloc_zero stralloc_zero
+
+#define genalloc_s(type, g) ((type *)((g)->s))
+#define genalloc_len(type, g) ((g)->len/sizeof(type))
+#define genalloc_setlen(type, g, n) ((g)->len = (n)*sizeof(type))
+
+#define genalloc_ready(type, g, n) stralloc_ready((g), (n)*sizeof(type))
+#define genalloc_ready_tuned(type, g, n, base, fracnum, fracden) stralloc_ready_tuned((g), (n)*sizeof(type), base, fracnum, fracden)
+#define genalloc_readyplus(type, g, n) stralloc_readyplus((g), (n)*sizeof(type))
+#define genalloc_free(type, g) stralloc_free(g)
+#define genalloc_shrink(type, g) stralloc_shrink(g)
+#define genalloc_catb(type, g, s, n) stralloc_catb((g), (char const *)(s), (n)*sizeof(type))
+#define genalloc_copyb(type, g, s, n) stralloc_copyb((g), (char const *)(s), (n)*sizeof(type))
+#define genalloc_copy(type, g1, g2) stralloc_copy((g1), g2)
+#define genalloc_cat(type, g1, g2) stralloc_cat((g1), g2)
+#define genalloc_append(type, g, p) stralloc_catb((g), (char const *)(p), sizeof(type))
+#define genalloc_reverse(type, g) stralloc_reverse_blocks((g), sizeof(type))
+#define genalloc_insertb(type, g, offset, s, n) stralloc_insertb((g), (offset)*sizeof(type), (char const *)(s), (n)*sizeof(type))
+#define genalloc_insert(type, g1, offset, g2) stralloc_insert((g1), (offset)*sizeof(type), (g2))
+
+#define genalloc_deepfree(type, g, f) genalloc_deepfree_size(g, (freefunc_t_ref)(f), sizeof(type))
+extern void genalloc_deepfree_size (genalloc *, freefunc_t_ref, unsigned int) ;
+
+#endif
diff --git a/src/include/skalibs/genset.h b/src/include/skalibs/genset.h
new file mode 100644
index 0000000..5eb47d7
--- /dev/null
+++ b/src/include/skalibs/genset.h
@@ -0,0 +1,37 @@
+/* ISC license. */
+
+#ifndef GENSET_H
+#define GENSET_H
+
+#include <skalibs/functypes.h>
+
+typedef struct genset_s genset, *genset_ref ;
+struct genset_s
+{
+ char *storage ;
+ unsigned int *freelist ;
+ unsigned int esize ;
+ unsigned int max ;
+ unsigned int sp ;
+} ;
+
+#define GENSET_ZERO { .storage = 0, .freelist = 0, .esize = 1, .max = 0, .sp = 0 }
+extern void genset_init (genset_ref, void *, unsigned int *, unsigned int, unsigned int) ;
+#define GENSET_init(g, type, storage, fl, size) genset_init(g, storage, fl, sizeof(type), size)
+
+#define genset_p(type, g, i) ((type *)((g)->storage + (i) * (g)->esize))
+extern unsigned int genset_new (genset_ref) ;
+extern int genset_delete (genset_ref, unsigned int) ;
+#define genset_n(g) ((g)->max - (g)->sp)
+extern unsigned int genset_iter (genset_ref, iterfunc_t_ref, void *) ;
+
+
+#define GENSETB_TYPE(type, size) struct { type storage[size] ; unsigned int freelist[size] ; genset info ; }
+#define GENSETB_init(type, g, size) GENSET_init(&(g)->info, type, (g)->storage, (g)->freelist, size)
+#define gensetb_p(type, g, i) genset_p(type, &(g)->info, i)
+#define gensetb_new(g) genset_new(&(g)->info)
+#define gensetb_delete(g, i) genset_delete(&(g)->info, i)
+#define gensetb_n(g) genset_n(&(g)->info)
+#define gensetb_iter(g, f, p) genset_iter(&(g)->info, f, p)
+
+#endif
diff --git a/src/include/skalibs/gensetdyn.h b/src/include/skalibs/gensetdyn.h
new file mode 100644
index 0000000..4fe396b
--- /dev/null
+++ b/src/include/skalibs/gensetdyn.h
@@ -0,0 +1,40 @@
+/* ISC license. */
+
+#ifndef GENSETDYN_H
+#define GENSETDYN_H
+
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/functypes.h>
+
+typedef struct gensetdyn_s gensetdyn, *gensetdyn_ref ;
+struct gensetdyn_s
+{
+ stralloc storage ;
+ genalloc freelist ; /* array of unsigned int */
+ unsigned int esize ;
+ unsigned int base ;
+ unsigned int fracnum ;
+ unsigned int fracden ;
+} ;
+
+#define GENSETDYN_ZERO { .storage = STRALLOC_ZERO, .freelist = GENALLOC_ZERO, .esize = 1, .base = 0, .fracnum = 0, .fracden = 1 }
+extern gensetdyn const gensetdyn_zero ;
+
+#define GENSETDYN_INIT(type, b, num, den) { .storage = STRALLOC_ZERO, .freelist = GENALLOC_ZERO, .esize = sizeof(type), .base = (b), .fracnum = (num), .fracden = (den) }
+extern void gensetdyn_init (gensetdyn_ref, unsigned int, unsigned int, unsigned int, unsigned int) ;
+
+#define gensetdyn_n(g) ((g)->storage.len - genalloc_len(unsigned int, &(g)->freelist))
+extern int gensetdyn_ready (gensetdyn_ref, unsigned int) ;
+#define gensetdyn_readyplus(x, n) gensetdyn_ready(x, gensetdyn_n(x) + (n))
+extern void gensetdyn_free (gensetdyn_ref) ;
+
+extern int gensetdyn_new (gensetdyn_ref, unsigned int *) ;
+extern int gensetdyn_delete (gensetdyn_ref, unsigned int) ;
+
+#define gensetdyn_p(g, i) ((g)->storage.s + (i) * (g)->esize)
+#define GENSETDYN_P(type, g, i) ((type *)gensetdyn_p(g, i))
+
+extern unsigned int gensetdyn_iter (gensetdyn_ref, iterfunc_t_ref, void *) ;
+
+#endif
diff --git a/src/include/skalibs/genwrite.h b/src/include/skalibs/genwrite.h
new file mode 100644
index 0000000..9ae0fb9
--- /dev/null
+++ b/src/include/skalibs/genwrite.h
@@ -0,0 +1,35 @@
+/* ISC license. */
+
+#ifndef GENWRITE_H
+#define GENWRITE_H
+
+typedef int genwrite_put_func_t (void *, char const *, unsigned int) ;
+typedef genwrite_put_func_t *genwrite_put_func_t_ref ;
+
+typedef int genwrite_flush_func_t (void *) ;
+typedef genwrite_flush_func_t *genwrite_flush_func_t_ref ;
+
+typedef struct genwrite_s genwrite_t, *genwrite_t_ref ;
+struct genwrite_s
+{
+ genwrite_put_func_t_ref put ;
+ genwrite_flush_func_t_ref flush ;
+ void *target ;
+} ;
+#define GENWRITE_ZERO { .put = 0, .flush = 0, .target = 0 }
+
+extern genwrite_put_func_t genwrite_put_stralloc ;
+extern genwrite_flush_func_t genwrite_flush_stralloc ;
+extern genwrite_put_func_t genwrite_put_buffer ;
+extern genwrite_flush_func_t genwrite_flush_buffer ;
+extern genwrite_put_func_t genwrite_put_bufalloc ;
+extern genwrite_flush_func_t genwrite_flush_bufalloc ;
+
+#define GENWRITE_STRALLOC_INIT(sa) { .put = &genwrite_put_stralloc, .flush = &genwrite_flush_stralloc, .target = (sa) }
+#define GENWRITE_BUFFER_INIT(b) { .put = &genwrite_put_buffer, .flush = &genwrite_flush_buffer, .target = (b) }
+#define GENWRITE_BUFALLOC_INIT(ba) { .put = &genwrite_put_bufalloc, .flush = &genwrite_flush_bufalloc, .target = (ba) }
+
+extern genwrite_t genwrite_stdout ;
+extern genwrite_t genwrite_stderr ;
+
+#endif
diff --git a/src/include/skalibs/getpeereid.h b/src/include/skalibs/getpeereid.h
new file mode 100644
index 0000000..4aa2898
--- /dev/null
+++ b/src/include/skalibs/getpeereid.h
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#ifndef GETPEEREID_H
+#define GETPEEREID_H
+
+#include <sys/types.h>
+
+extern int getpeereid (int, uid_t *, gid_t *) ;
+
+#endif
diff --git a/src/include/skalibs/iobuffer.h b/src/include/skalibs/iobuffer.h
new file mode 100644
index 0000000..c1864cf
--- /dev/null
+++ b/src/include/skalibs/iobuffer.h
@@ -0,0 +1,117 @@
+/* ISC license. */
+
+#ifndef IOBUFFER_H
+#define IOBUFFER_H
+
+#define IOBUFFER_SIZE 65536U
+
+ /* iobufferu */
+
+#include <skalibs/buffer.h>
+#include <skalibs/djbunix.h>
+
+#define IOBUFFERU_SIZE (IOBUFFER_SIZE+1)
+
+typedef struct iobufferu_s iobufferu, *iobufferu_ref ;
+struct iobufferu_s
+{
+ buffer b[2] ;
+ char *buf ;
+} ;
+
+extern int iobufferu_init (iobufferu_ref, int, int) ;
+extern int iobufferu_fill (iobufferu_ref) ;
+extern int iobufferu_flush (iobufferu_ref) ;
+extern void iobufferu_finish (iobufferu_ref) ;
+
+#define iobufferu_len(u) buffer_len(&(u)->b[0])
+#define iobufferu_available(u) buffer_available(&(u)->b[1])
+#define iobufferu_isempty(u) buffer_isempty(&(u)->b[0])
+#define iobufferu_isfull(u) buffer_isfull(&(u)->b[1])
+#define iobufferu_fd(u, h) buffer_fd((u)->b[h])
+#define iobufferu_isreadable(u) iobufferu_available(u)
+#define iobufferu_iswritable(u) iobufferu_len(u)
+#define iobufferu_nonblock(u, h) ndelay_on(iobufferu_fd(u, h))
+#define iobufferu_block(u, h) ndelay_off(iobufferu_fd(u, h))
+#define iobufferu_nbstate(u, h, j) (j ? iobufferu_nonblock(u, h) : iobufferu_block(u, h))
+
+
+ /* iobufferk */
+
+#define IOBUFFERK_SIZE IOBUFFER_SIZE
+
+typedef struct iobufferk_s iobufferk, *iobufferk_ref ;
+struct iobufferk_s
+{
+ int fd[2] ;
+ int p[2] ;
+ unsigned int n ;
+ unsigned int type : 2 ;
+ unsigned int nb : 2 ;
+} ;
+
+typedef int iobufferk_io_func_t (iobufferk_ref) ;
+typedef iobufferk_io_func_t *iobufferk_io_func_t_ref ;
+typedef void iobufferk_finish_func_t (iobufferk_ref) ;
+typedef iobufferk_finish_func_t *iobufferk_finish_func_t_ref ;
+
+extern iobufferk_io_func_t iobufferk_nosys ;
+extern iobufferk_io_func_t iobufferk_isworking ;
+
+extern int iobufferk_init (iobufferk_ref, int, int) ;
+extern iobufferk_io_func_t_ref const iobufferk_fill_f[4] ;
+extern iobufferk_io_func_t_ref const iobufferk_flush_f[4] ;
+extern iobufferk_finish_func_t_ref const iobufferk_finish_f[4] ;
+
+#define iobufferk_fill(k) (*iobufferk_fill_f[(k)->type])(k)
+#define iobufferk_flush(k) (*iobufferk_flush_f[(k)->type])(k)
+#define iobufferk_finish(k) (*iobufferk_finish_f[(k)->type])(k)
+#define iobufferk_len(k) ((k)->n)
+#define iobufferk_available(k) (IOBUFFERK_SIZE - (k)->n)
+#define iobufferk_isempty(k) (!iobufferk_len(k))
+#define iobufferk_isfull(k) (!iobufferk_available(k))
+#define iobufferk_fd(k, h) ((k)->fd[h])
+#define iobufferk_isreadable(k) iobufferk_available(k)
+#define iobufferk_iswritable(k) iobufferk_len(k)
+#define iobufferk_nonblock(k, h) ((k)->nb |= (1 << (h)), 0)
+#define iobufferk_block(k, h) ((k)->nb &= (3 - (1 << (h))), 0)
+#define iobufferk_nbstate(k, h, j) (j ? iobufferk_nonblock(k, h) : iobufferk_block(k, h))
+
+
+ /* iobuffer */
+
+typedef union iobufferku_u iobufferku, *iobufferku_ref ;
+union iobufferku_u
+{
+ iobufferk k ;
+ iobufferu u ;
+} ;
+
+typedef struct iobuffer_s iobuffer, *iobuffer_ref ;
+struct iobuffer_s
+{
+ iobufferku x ;
+ unsigned int isk : 1 ;
+} ;
+
+extern int iobuffer_ufromk (iobufferu_ref, iobufferk_ref) ;
+extern int iobuffer_kfromu (iobufferk_ref, iobufferu_ref) ;
+extern int iobuffer_salvage (iobuffer_ref) ;
+
+extern int iobuffer_init (iobuffer_ref, int, int) ;
+extern int iobuffer_fill (iobuffer_ref) ;
+extern int iobuffer_flush (iobuffer_ref) ;
+
+#define iobuffer_finish(b) ((b)->isk ? iobufferk_finish(&(b)->x.k) : iobufferu_finish(&(b)->x.u))
+#define iobuffer_len(b) ((b)->isk ? iobufferk_len(&(b)->x.k) : iobufferu_len(&(b)->x.u))
+#define iobuffer_available(b) ((b)->isk ? iobufferk_available(&(b)->x.k) : iobufferu_available(&(b)->x.u))
+#define iobuffer_isempty(b) ((b)->isk ? iobufferk_isempty(&(b)->x.k) : iobufferu_isempty(&(b)->x.u))
+#define iobuffer_isfull(b) ((b)->isk ? iobufferk_isfull(&(b)->x.k) : iobufferu_isfull(&(b)->x.u))
+#define iobuffer_fd(b, h) ((b)->isk ? iobufferk_fd(&(b)->x.k, h) : iobufferu_fd(&(b)->x.u, h))
+#define iobuffer_isreadable(b) ((b)->isk ? iobufferk_isreadable(&(b)->x.k) : iobufferu_isreadable(&(b)->x.u))
+#define iobuffer_iswritable(b) ((b)->isk ? iobufferk_iswritable(&(b)->x.k) : iobufferu_iswritable(&(b)->x.u))
+#define iobuffer_nonblock(b, h) ((b)->isk ? iobufferk_nonblock(&(b)->x.k, h) : iobufferu_nonblock(&(b)->x.u, h))
+#define iobuffer_block(b, h) ((b)->isk ? iobufferk_block(&(b)->x.k, h) : iobufferu_block(&(b)->x.u, h))
+#define iobuffer_nbstate(b, h, j) ((b)->isk ? iobufferk_nbstate(&(b)->x.k, h, j) : iobufferu_nbstate(&(b)->x.u, h, j))
+
+#endif
diff --git a/src/include/skalibs/iopause.h b/src/include/skalibs/iopause.h
new file mode 100644
index 0000000..d8f5e1c
--- /dev/null
+++ b/src/include/skalibs/iopause.h
@@ -0,0 +1,32 @@
+/* ISC license. */
+
+#ifndef IOPAUSE_H
+#define IOPAUSE_H
+
+#include <sys/types.h>
+#include <poll.h>
+#include <skalibs/tai.h>
+
+typedef struct pollfd iopause_fd, *iopause_fd_ref ;
+
+#define IOPAUSE_READ (POLLIN|POLLHUP)
+#define IOPAUSE_WRITE POLLOUT
+#define IOPAUSE_EXCEPT (POLLERR|POLLHUP|POLLNVAL)
+
+typedef int iopause_func_t (iopause_fd *, unsigned int, tain_t const *, tain_t const *) ;
+typedef iopause_func_t *iopause_func_t_ref ;
+
+extern iopause_func_t iopause_select ;
+extern iopause_func_t iopause_poll ;
+extern iopause_func_t iopause_ppoll ;
+
+extern iopause_func_t_ref const iopause_ ;
+#define iopause (*iopause_)
+
+extern int iopause_stamp (iopause_fd *, unsigned int, tain_t const *, tain_t *) ;
+#define iopause_g(x, n, deadline) iopause_stamp(x, n, (deadline), &STAMP)
+
+extern void deepsleepuntil (tain_t const *, tain_t *) ;
+#define deepsleepuntil_g(deadline) deepsleepuntil((deadline), &STAMP)
+
+#endif
diff --git a/src/include/skalibs/kolbak.h b/src/include/skalibs/kolbak.h
new file mode 100644
index 0000000..86a2170
--- /dev/null
+++ b/src/include/skalibs/kolbak.h
@@ -0,0 +1,32 @@
+/* ISC license. */
+
+#ifndef KOLBAK_H
+#define KOLBAK_H
+
+#include <skalibs/unixmessage.h>
+
+typedef struct kolbak_closure_s kolbak_closure_t, *kolbak_closure_t_ref ;
+struct kolbak_closure_s
+{
+ unixmessage_handler_func_t_ref f ;
+ void *data ;
+} ;
+#define KOLBAK_CLOSURE_ZERO { .f = 0, .data = 0 }
+
+typedef struct kolbak_queue_s kolbak_queue_t, *kolbak_queue_t_ref ;
+struct kolbak_queue_s
+{
+ kolbak_closure_t *x ;
+ unsigned int n ;
+ unsigned int head ;
+ unsigned int tail ;
+} ;
+#define KOLBAK_QUEUE_ZERO { .x = 0, .n = 0, .head = 0, .tail = 0 }
+#define KOLBAK_QUEUE_INIT(s, len) { .x = (s), .n = (len), .head = 0, .tail = 0 }
+
+extern int kolbak_queue_init (kolbak_queue_t *, kolbak_closure_t *, unsigned int) ;
+extern int kolbak_enqueue (kolbak_queue_t *, unixmessage_handler_func_t_ref, void *) ;
+extern int kolbak_unenqueue (kolbak_queue_t *) ;
+extern int kolbak_call (unixmessage_t const *, kolbak_queue_t *) ;
+
+#endif
diff --git a/src/include/skalibs/lolstdio.h b/src/include/skalibs/lolstdio.h
new file mode 100644
index 0000000..ec66da2
--- /dev/null
+++ b/src/include/skalibs/lolstdio.h
@@ -0,0 +1,30 @@
+/* ISC license. */
+
+#ifndef LOLSTDIO_H
+#define LOLSTDIO_H
+
+#include <stdarg.h>
+#include <skalibs/buffer.h>
+#include <skalibs/bufalloc.h>
+#include <skalibs/strerr2.h>
+
+#ifdef DEBUG
+# define LOLDEBUG(...) do \
+ { \
+ buffer_puts(buffer_2, PROG) ; \
+ buffer_puts(buffer_2, ": debug: ") ; \
+ bprintf(buffer_2, __VA_ARGS__) ; \
+ buffer_putflush(buffer_2, "\n", 1) ; \
+ } while (0)
+#else
+# define LOLDEBUG(...)
+#endif
+
+extern int vbprintf (buffer *, char const *, va_list) ;
+extern int bprintf (buffer *, char const *, ...) ;
+extern int lolprintf (char const *, ...) ;
+
+extern int vbaprintf (bufalloc *, char const *, va_list) ;
+extern int baprintf (bufalloc *, char const *, ...) ;
+
+#endif
diff --git a/src/include/skalibs/md5.h b/src/include/skalibs/md5.h
new file mode 100644
index 0000000..00e43cc
--- /dev/null
+++ b/src/include/skalibs/md5.h
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#ifndef MD5_H
+#define MD5_H
+
+#include <skalibs/uint32.h>
+
+typedef struct MD5Schedule MD5Schedule, *MD5Schedule_ref ;
+struct MD5Schedule
+{
+ uint32 buf[4] ;
+ uint32 bits[2] ;
+ unsigned char in[64] ;
+} ;
+
+#define MD5_INIT() { .buf = { 0x67452301UL, 0xefcdab89UL, 0x98badcfeUL, 0x10325476UL }, .bits = { 0, 0 }, .in = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" }
+extern void md5_init (MD5Schedule_ref) ;
+extern void md5_update (MD5Schedule_ref, char const *, unsigned int) ;
+extern void md5_final (MD5Schedule_ref, char * /* 16 chars */) ;
+
+#endif
diff --git a/src/include/skalibs/mininetstring.h b/src/include/skalibs/mininetstring.h
new file mode 100644
index 0000000..c275fb2
--- /dev/null
+++ b/src/include/skalibs/mininetstring.h
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#ifndef MININETSTRING_H
+#define MININETSTRING_H
+
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/stralloc.h>
+
+extern int mininetstring_read (int, stralloc *, uint32 *) ;
+extern int mininetstring_write (int, char const *, uint16, uint32 *) ;
+
+#endif
diff --git a/src/include/skalibs/netstring.h b/src/include/skalibs/netstring.h
new file mode 100644
index 0000000..ee5cd85
--- /dev/null
+++ b/src/include/skalibs/netstring.h
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#ifndef NETSTRING_H
+#define NETSTRING_H
+
+#include <skalibs/buffer.h>
+#include <skalibs/siovec.h>
+#include <skalibs/stralloc.h>
+
+extern int netstring_appendb (stralloc *, char const *, unsigned int) ;
+#define netstring_appends(sa, s) netstring_appendb((sa), (s), str_len(s))
+#define netstring_append(to, from) netstring_appendb((to), (from)->s, (from)->len)
+extern int netstring_appendv (stralloc *, siovec_t const *, unsigned int) ;
+
+extern int netstring_encode (stralloc *, char const *, unsigned int) ;
+extern int netstring_decode (stralloc *, char const *, unsigned int) ;
+
+extern int netstring_okeof (buffer *, unsigned int) ;
+extern int netstring_get (buffer *, stralloc *, unsigned int *) ;
+extern int netstring_put (buffer *, char const *, unsigned int, unsigned int *) ;
+#define netstring_putba(ba, s, n) netstring_appendb(&(ba)->x, s, n)
+#define netstring_putbav(ba, v, n) netstring_appendv(&(ba)->x, v, n)
+
+#endif
diff --git a/src/include/skalibs/nonposix.h b/src/include/skalibs/nonposix.h
new file mode 100644
index 0000000..26af211
--- /dev/null
+++ b/src/include/skalibs/nonposix.h
@@ -0,0 +1,58 @@
+/* ISC license. */
+
+#ifndef NONPOSIX_H
+#define NONPOSIX_H
+
+
+ /* Drop all pretense of standardness: some libc headers are *more*
+ broken when you define standard feature test macros than when
+ you don't (I'm looking at you, FreeBSD). */
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+
+ /* Solaris: the socket API is not POSIX unless you enable this */
+
+#ifndef _XPG4_2
+#define _XPG4_2
+#endif
+#ifndef _XPG6
+#define _XPG6
+#endif
+
+
+ /* Solaris: for settimeofday() and similar. Notice how you
+ have to define by hand a macro with double underscores. */
+
+#ifndef __EXTENSIONS__
+#define __EXTENSIONS__
+#endif
+
+
+ /* GNU: most extensions are unavailable unless you enable this */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE
+#endif
+
+
+ /* NetBSD: of course they had to have their own macros. */
+
+#ifndef _NETBSD_SOURCE
+#define _NETBSD_SOURCE
+#endif
+#ifndef _INCOMPLETE_XOPEN_C063
+#define _INCOMPLETE_XOPEN_C063
+#endif
+
+
+ /* old versions of BSD: system headers are not self-contained,
+ starting with sys/types.h is the usual workaround */
+
+#include <sys/types.h>
+
+#endif
diff --git a/src/include/skalibs/nsig.h b/src/include/skalibs/nsig.h
new file mode 100644
index 0000000..f6bd240
--- /dev/null
+++ b/src/include/skalibs/nsig.h
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#ifndef NSIG_H
+
+#include <signal.h>
+
+#define SKALIBS_NSIG 64
+
+#ifndef NSIG
+# define NSIG SKALIBS_NSIG
+#endif
+
+#endif
diff --git a/src/include/skalibs/random.h b/src/include/skalibs/random.h
new file mode 100644
index 0000000..90aa0c0
--- /dev/null
+++ b/src/include/skalibs/random.h
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+/* MT-unsafe functions only. Use rrandom for MT-safety. */
+
+#ifndef RANDOM_H
+#define RANDOM_H
+
+#include <skalibs/gccattributes.h>
+#include <skalibs/stralloc.h>
+
+extern int badrandom_init (void) ;
+extern unsigned char badrandom_char (void) ;
+extern unsigned int badrandom_int (unsigned int) ;
+extern unsigned int badrandom_string (char *, unsigned int) ;
+extern void badrandom_finish (void) ;
+
+extern int goodrandom_init (void) ;
+extern unsigned char goodrandom_char (void) ;
+extern unsigned int goodrandom_int (unsigned int) ;
+extern unsigned int goodrandom_string (char *, unsigned int) ;
+extern void goodrandom_finish (void) ;
+
+#define random_init badrandom_init
+#define random_char badrandom_char
+#define random_int badrandom_int
+#define random_string badrandom_string
+#define random_finish badrandom_finish
+
+extern int random_name (char *, unsigned int) ;
+extern int random_sauniquename (stralloc *, unsigned int) ;
+extern void random_unsort (char *, unsigned int, unsigned int) ;
+
+#endif
diff --git a/src/include/skalibs/randomegd.h b/src/include/skalibs/randomegd.h
new file mode 100644
index 0000000..28d4faa
--- /dev/null
+++ b/src/include/skalibs/randomegd.h
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#ifndef RANDOMEGD_H
+#define RANDOMEGD_H
+
+extern int randomegd_open (char const *) ;
+extern unsigned int randomegd_readb (int, char *, unsigned int) ;
+extern unsigned int randomegd_readnb (int, char *, unsigned int) ;
+
+#endif
diff --git a/src/include/skalibs/rc4.h b/src/include/skalibs/rc4.h
new file mode 100644
index 0000000..16683ce
--- /dev/null
+++ b/src/include/skalibs/rc4.h
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#ifndef RC4_H
+#define RC4_H
+
+#define RC4_THROWAWAY 128
+
+typedef struct RC4Schedule RC4Schedule, *RC4Schedule_ref ;
+
+struct RC4Schedule
+{
+ unsigned char tab[256] ;
+ unsigned char x, y ;
+} ;
+
+extern void rc4_init (RC4Schedule_ref, char const *, unsigned int) ;
+extern void rc4 (RC4Schedule_ref, char const *, char *, unsigned int) ;
+
+#endif
diff --git a/src/include/skalibs/rrandom.h b/src/include/skalibs/rrandom.h
new file mode 100644
index 0000000..7f6a2aa
--- /dev/null
+++ b/src/include/skalibs/rrandom.h
@@ -0,0 +1,36 @@
+/* ISC license. */
+
+#ifndef RRANDOM_H
+#define RRANDOM_H
+
+#include <skalibs/unirandom.h>
+
+typedef struct rrandominfo rrandominfo, *rrandominfo_ref, **rrandominfo_ref_ref ;
+struct rrandominfo
+{
+ unirandom it ;
+ unsigned int ok ;
+} ;
+
+#define RRANDOMINFO_ZERO { .it = UNIRANDOM_ZERO, .ok = 3 }
+
+typedef struct rrandom rrandom, *rrandom_ref, **rrandom_ref_ref ;
+struct rrandom
+{
+ rrandominfo tries[3] ;
+ unsigned int n ;
+} ;
+
+#define RRANDOM_ZERO { .tries = { RRANDOMINFO_ZERO, RRANDOMINFO_ZERO, RRANDOMINFO_ZERO }, .n = 0 }
+
+extern int rrandom_add (rrandom_ref, int (*) (unirandom_ref)) ;
+extern int rrandom_finish (rrandom_ref) ;
+
+extern unsigned int rrandom_read (rrandom_ref, char *, unsigned int, unsigned int (*) (unirandom_ref, char *, unsigned int)) ;
+extern unsigned int rrandom_readint (rrandom_ref, unsigned int, unsigned int (*) (unirandom_ref, char *, unsigned int)) ;
+#define rrandom_readb(z, s, n) rrandom_read((z), (s), (n), &unirandom_readb)
+#define rrandom_readnb(z, s, n) rrandom_read((z), (s), (n), &unirandom_readnb)
+
+extern unsigned int rrandom_name (rrandom_ref, char *, unsigned int, int) ;
+
+#endif
diff --git a/src/include/skalibs/segfault.h b/src/include/skalibs/segfault.h
new file mode 100644
index 0000000..732ad4f
--- /dev/null
+++ b/src/include/skalibs/segfault.h
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#ifndef SEGFAULT_H
+#define SEGFAULT_H
+
+extern int sigsegv (void) ;
+extern int sigfpe (void) ;
+
+#define segfault() sigsegv()
+
+#endif
diff --git a/src/include/skalibs/selfpipe.h b/src/include/skalibs/selfpipe.h
new file mode 100644
index 0000000..c587f93
--- /dev/null
+++ b/src/include/skalibs/selfpipe.h
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#ifndef SELFPIPE_H
+#define SELFPIPE_H
+
+#include <signal.h>
+
+extern int selfpipe_init (void) ;
+extern int selfpipe_trap (int) ;
+extern int selfpipe_untrap (int) ;
+extern int selfpipe_trapset (sigset_t const *) ;
+extern int selfpipe_read (void) ;
+extern void selfpipe_finish (void) ;
+
+#endif
diff --git a/src/include/skalibs/sgetopt.h b/src/include/skalibs/sgetopt.h
new file mode 100644
index 0000000..367edf3
--- /dev/null
+++ b/src/include/skalibs/sgetopt.h
@@ -0,0 +1,46 @@
+/* ISC license. */
+
+#ifndef SGETOPT_H
+#define SGETOPT_H
+
+
+ /* reentrant */
+
+typedef struct subgetopt_s subgetopt_t, *subgetopt_t_ref ;
+struct subgetopt_s
+{
+ int ind ;
+ int err ;
+ int problem ;
+ char const *arg ;
+ unsigned int pos ;
+ char const *prog ;
+} ;
+
+#define SUBGETOPT_ZERO { .ind = 1, .err = 1, .problem = 0, .arg = 0, .pos = 0, .prog = 0 }
+
+extern int subgetopt_r (int, char const *const *, char const *, subgetopt_t_ref) ;
+
+
+ /* non-reentrant */
+
+extern int sgetopt_r (int, char const *const *, char const *, subgetopt_t_ref) ;
+
+extern subgetopt_t subgetopt_here ;
+
+#define subgetopt(argc, argv, opts) subgetopt_r((argc), (argv), (opts), &subgetopt_here)
+#define sgetopt(argc, argv, opts) sgetopt_r((argc), (argv), (opts), &subgetopt_here)
+#define sgetopt_prog() (subgetopt_here.prog = PROG)
+
+/* define SUBGETOPT_SHORT if you don't mind potential name conflicts */
+
+#ifdef SUBGETOPT_SHORT
+# define getopt sgetopt
+# define optarg subgetopt_here.arg
+# define optind subgetopt_here.ind
+# define opterr subgetopt_here.err
+# define optopt subgetopt_here.problem
+# define opteof (-1)
+#endif
+
+#endif
diff --git a/src/include/skalibs/sha1.h b/src/include/skalibs/sha1.h
new file mode 100644
index 0000000..03cdaf0
--- /dev/null
+++ b/src/include/skalibs/sha1.h
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#ifndef SHA1_H
+#define SHA1_H
+
+#include <skalibs/uint32.h>
+
+typedef struct SHA1Schedule SHA1Schedule, *SHA1Schedule_ref ;
+struct SHA1Schedule
+{
+ uint32 buf[5] ;
+ uint32 bits[2] ;
+ uint32 in[16] ;
+ unsigned int b ;
+} ;
+
+#define SHA1_INIT() { .buf = { 0x67452301UL, 0xefcdab89UL, 0x98badcfeUL, 0x10325476UL, 0xc3d2e1f0UL }, .bits = { 0, 0 }, .in = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .b = 0 }
+extern void sha1_init (SHA1Schedule_ref) ;
+extern void sha1_update (SHA1Schedule_ref, char const *, unsigned int) ;
+extern void sha1_final (SHA1Schedule_ref, char * /* 20 chars */) ;
+
+#endif
diff --git a/src/include/skalibs/sha256.h b/src/include/skalibs/sha256.h
new file mode 100644
index 0000000..8f28c38
--- /dev/null
+++ b/src/include/skalibs/sha256.h
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+/* SHA256 routines */
+/* Written by David Madore (<URL: http://www.madore.org/~david/ >) */
+/* Adapted by Laurent Bercot. */
+/* This version last modified 2010-01-08 */
+
+/* Note: these routines do not depend on endianness. */
+
+#ifndef SHA256_H
+#define SHA256_H
+
+#include <skalibs/uint32.h>
+
+typedef struct SHA256Schedule_s SHA256Schedule, *SHA256Schedule_ref ;
+struct SHA256Schedule_s
+{
+ uint32 buf[8] ; /* The eight chaining variables */
+ uint32 bits[2] ; /* Count number of message bits */
+ uint32 in[16] ; /* Data being fed in */
+ unsigned int b ; /* Our position within the 512 bits (always between 0 and 63) */
+} ;
+
+#define SHA256_INIT() { .buf = { 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL }, .bits = { 0, 0 }, .in = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .b = 0 }
+extern void sha256_init (SHA256Schedule_ref) ;
+extern void sha256_update (SHA256Schedule_ref, char const *, unsigned int) ;
+extern void sha256_final (SHA256Schedule_ref, char *digest) ;
+
+#endif
diff --git a/src/include/skalibs/sig.h b/src/include/skalibs/sig.h
new file mode 100644
index 0000000..a463b63
--- /dev/null
+++ b/src/include/skalibs/sig.h
@@ -0,0 +1,61 @@
+/* ISC license. */
+
+#ifndef SIG_H
+#define SIG_H
+
+#include <signal.h>
+#include <skalibs/gccattributes.h>
+
+extern int sig_alarm gccattr_deprecated ;
+extern int sig_child gccattr_deprecated ;
+extern int sig_stop gccattr_deprecated ;
+extern int sig_cont gccattr_deprecated ;
+extern int sig_hangup gccattr_deprecated ;
+extern int sig_int gccattr_deprecated ;
+extern int sig_kill gccattr_deprecated ;
+extern int sig_pipe gccattr_deprecated ;
+extern int sig_term gccattr_deprecated ;
+extern int sig_usr1 gccattr_deprecated ;
+extern int sig_usr2 gccattr_deprecated ;
+extern int sig_quit gccattr_deprecated ;
+extern int sig_abort gccattr_deprecated ;
+
+
+typedef void skasighandler_t (int) ;
+typedef skasighandler_t *skasighandler_t_ref ;
+
+struct skasigaction
+{
+ skasighandler_t_ref handler ;
+ unsigned int flags : 2 ;
+} ;
+
+#define SKASA_MASKALL 0x01
+#define SKASA_NOCLDSTOP 0x02
+
+extern struct skasigaction const SKASIG_DFL ;
+extern struct skasigaction const SKASIG_IGN ;
+extern int skasigaction (int, struct skasigaction const *, struct skasigaction *) ;
+
+#define sig_catcha(sig, ac) skasigaction(sig, (ac), 0)
+#define sig_restore(sig) skasigaction((sig), &SKASIG_DFL, 0)
+
+extern void sig_restoreto (sigset_t const *, unsigned int) ;
+extern int sig_catch (int, skasighandler_t_ref) ;
+#define sig_ignore(sig) sig_catcha((sig), &SKASIG_IGN)
+#define sig_uncatch(sig) sig_restore(sig)
+
+#define SIGSTACKSIZE 16
+extern int sig_pusha (int, struct skasigaction const *) ;
+extern int sig_pop (int) ;
+extern int sig_push (int, skasighandler_t_ref) ;
+
+extern void sig_block (int) ;
+extern void sig_blockset (sigset_t const *) ;
+extern void sig_unblock (int) ;
+extern void sig_blocknone (void) ;
+extern void sig_pause (void) ;
+extern void sig_shield (void) ;
+extern void sig_unshield (void) ;
+
+#endif
diff --git a/src/include/skalibs/siovec.h b/src/include/skalibs/siovec.h
new file mode 100644
index 0000000..8c8161f
--- /dev/null
+++ b/src/include/skalibs/siovec.h
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#ifndef SIOVEC_H
+#define SIOVEC_H
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <skalibs/gccattributes.h>
+
+typedef struct siovec_s siovec_t, *siovec_t_ref ;
+struct siovec_s
+{
+ char *s ;
+ unsigned int len ;
+} ;
+
+extern unsigned int siovec_len (siovec_t const *, unsigned int) gccattr_pure ;
+extern unsigned int siovec_gather (siovec_t const *, unsigned int, char *, unsigned int) ;
+extern unsigned int siovec_scatter (siovec_t const *, unsigned int, char const *, unsigned int) ;
+extern unsigned int siovec_deal (siovec_t const *, unsigned int, siovec_t const *, unsigned int) ;
+extern unsigned int siovec_seek (siovec_t *, unsigned int, unsigned int) ;
+
+extern void siovec_from_iovec (siovec_t *, struct iovec const *, unsigned int) ;
+extern void iovec_from_siovec (struct iovec *, siovec_t const *, unsigned int) ;
+
+extern unsigned int siovec_bytechr (siovec_t const *, unsigned int, char) ;
+extern unsigned int siovec_bytein (siovec_t const *, unsigned int, char const *, unsigned int) ;
+
+#endif
diff --git a/src/include/skalibs/skaclient.h b/src/include/skalibs/skaclient.h
new file mode 100644
index 0000000..a057d50
--- /dev/null
+++ b/src/include/skalibs/skaclient.h
@@ -0,0 +1,115 @@
+/* ISC license. */
+
+#ifndef SKACLIENT_H
+#define SKACLIENT_H
+
+#include <sys/types.h>
+#include <skalibs/kolbak.h>
+#include <skalibs/siovec.h>
+#include <skalibs/tai.h>
+#include <skalibs/uint32.h>
+#include <skalibs/unixmessage.h>
+
+
+ /* Server part */
+
+extern int skaclient_server_ack (unixmessage_t const *, unixmessage_sender_t *, unixmessage_sender_t *, char const *, unsigned int, char const *, unsigned int) ;
+extern int skaclient_server_bidi_ack (unixmessage_t const *, unixmessage_sender_t *, unixmessage_sender_t *, unixmessage_receiver_t *, char *, unsigned int, char *, unsigned int, char const *, unsigned int, char const *, unsigned int) ;
+extern int skaclient_server_init (unixmessage_receiver_t *, char *, unsigned int, char *, unsigned int, unixmessage_sender_t *, unixmessage_sender_t *, char const *, unsigned int, char const *, unsigned int, tain_t const *, tain_t *) ;
+#define skaclient_server_init_g(in, mainbuf, mainlen, auxbuf, auxlen, out, asyncout, before, beforelen, after, afterlen, deadline) skaclient_server_init(in, mainbuf, mainlen, auxbuf, auxlen, out, asyncout, before, beforelen, after, afterlen, (deadline), &STAMP)
+
+
+ /* Client part: the rest of this file */
+
+#define SKACLIENT_KOLBAK_SIZE 64
+#define SKACLIENT_OPTION_WAITPID 0x00000001U
+
+#define skaclient_buffer_type(bufsn, auxbufsn, bufan, auxbufan, qlen) struct { char bufs[bufsn] ; char auxbufs[auxbufsn] ; char bufa[bufan] ; char auxbufa[auxbufan] ; kolbak_closure_t q[qlen] ; }
+typedef skaclient_buffer_type(UNIXMESSAGE_BUFSIZE, UNIXMESSAGE_AUXBUFSIZE, UNIXMESSAGE_BUFSIZE, UNIXMESSAGE_AUXBUFSIZE, SKACLIENT_KOLBAK_SIZE) skaclient_buffer_t, *skaclient_buffer_t_ref ;
+
+
+ /* Callback data for init */
+
+typedef struct skaclient_cbdata_s skaclient_cbdata_t, *skaclient_cbdata_t_ref ;
+struct skaclient_cbdata_s
+{
+ unixmessage_receiver_t *asyncin ;
+ unixmessage_sender_t *asyncout ;
+ char const *after ;
+ unsigned int afterlen ;
+} ;
+
+
+ /* User structure */
+
+typedef struct skaclient_s skaclient_t, *skaclient_t_ref ;
+struct skaclient_s
+{
+ unixmessage_receiver_t syncin ;
+ unixmessage_sender_t syncout ;
+ kolbak_queue_t kq ;
+ unixmessage_receiver_t asyncin ;
+ unixmessage_sender_t asyncout ;
+ pid_t pid ;
+ uint32 options ;
+} ;
+#define SKACLIENT_ZERO { .syncin = UNIXMESSAGE_RECEIVER_ZERO, .syncout = UNIXMESSAGE_SENDER_ZERO, .kq = KOLBAK_QUEUE_ZERO, .asyncin = UNIXMESSAGE_RECEIVER_ZERO, .asyncout = UNIXMESSAGE_SENDER_ZERO, .pid = 0, .options = 0 }
+extern skaclient_t const skaclient_zero ;
+
+extern void skaclient_end (skaclient_t *) ;
+
+extern int skaclient_start_async (skaclient_t *, char *, unsigned int, char *, unsigned int, char *, unsigned int, char *, unsigned int, kolbak_closure_t *, unsigned int, char const *, char const *, unsigned int, char const *, unsigned int, skaclient_cbdata_t *) ;
+#define skaclient_start_async_b(a, sb, path, before, beforelen, after, afterlen, blah) skaclient_start_async(a, (sb)->bufs, sizeof((sb)->bufs), (sb)->auxbufs, sizeof((sb)->auxbufs), (sb)->bufa, sizeof((sb)->bufa), (sb)->auxbufa, sizeof((sb)->auxbufa), (sb)->q, sizeof((sb)->q), path, before, beforelen, after, afterlen, blah)
+extern int skaclient_startf_async (skaclient_t *, char *, unsigned int, char *, unsigned int, char *, unsigned int, char *, unsigned int, kolbak_closure_t *, unsigned int, char const *, char const *const *, char const *const *, uint32, char const *, unsigned int, char const *, unsigned int, skaclient_cbdata_t *) ;
+#define skaclient_startf_async_b(a, sb, prog, argv, envp, options, before, beforelen, after, afterlen, blah) skaclient_startf_async(a, (sb)->bufs, sizeof((sb)->bufs), (sb)->auxbufs, sizeof((sb)->auxbufs), (sb)->bufa, sizeof((sb)->bufa), (sb)->auxbufa, sizeof((sb)->auxbufa), (sb)->q, sizeof((sb)->q), prog, argv, envp, options, before, beforelen, after, afterlen, blah)
+
+extern int skaclient_start (skaclient_t *, char *, unsigned int, char *, unsigned int, char *, unsigned int, char *, unsigned int, kolbak_closure_t *, unsigned int, char const *, char const *, unsigned int, char const *, unsigned int, tain_t const *, tain_t *) ;
+#define skaclient_start_b(a, sb, path, before, beforelen, after, afterlen, deadline, stamp) skaclient_start((a, (sb)->bufs, sizeof((sb)->bufs), (sb)->auxbufs, sizeof((sb)->auxbufs), (sb)->bufa, sizeof((sb)->bufa), (sb)->auxbufa, sizeof((sb)->auxbufa), (sb)->q, sizeof((sb)->q), path, before, beforelen, after, afterlen, deadline, stamp)
+#define skaclient_start_g(a, bufs, bufsn, auxbufs, auxbufsn, bufa, bufan, auxbufa, auxbufan, q, qlen, path, before, beforelen, after, afterlen, deadline) skaclient_start(a, bufs, bufsn, auxbufs, auxbufsn, bufa, bufan, auxbufa, auxbufan, q, qlen, path, before, beforelen, after, afterlen, (deadline), &STAMP)
+#define skaclient_start_b_g(a, sb, path, before, beforelen, after, afterlen, deadline) skaclient_start_b(a, sb, path, before, beforelen, after, afterlen, (deadline), &STAMP)
+
+extern int skaclient_startf (skaclient_t *, char *, unsigned int, char *, unsigned int, char *, unsigned int, char *, unsigned int, kolbak_closure_t *, unsigned int, char const *, char const *const *, char const *const *, uint32, char const *, unsigned int, char const *, unsigned int, tain_t const *, tain_t *) ;
+#define skaclient_startf_b(a, sb, prog, argv, envp, before, beforelen, after, afterlen, deadline, stamp) skaclient_start((a, (sb)->bufs, sizeof((sb)->bufs), (sb)->auxbufs, sizeof((sb)->auxbufs), (sb)->bufa, sizeof((sb)->bufa), (sb)->auxbufa, sizeof((sb)->auxbufa), (sb)->q, sizeof((sb)->q), prog, argv, envp, before, beforelen, after, afterlen, deadline, stamp)
+#define skaclient_startf_g(a, bufs, bufsn, auxbufs, auxbufsn, bufa, bufan, auxbufa, auxbufan, q, qlen, prog, argv, envp, options, before, beforelen, after, afterlen, deadline) skaclient_startf(a, bufs, bufsn, auxbufs, auxbufsn, bufa, bufan, auxbufa, auxbufan, q, qlen, prog, argv, envp, options, before, beforelen, after, afterlen, (deadline), &STAMP)
+#define skaclient_startf_b_g(a, sb, prog, argv, envp, options, before, beforelen, after, afterlen, deadline) skaclient_startf_b(a, sb, prog, argv, envp, options, before, beforelen, after, afterlen, (deadline), &STAMP)
+
+extern int skaclient_putmsg_and_close (skaclient_t *, unixmessage_t const *, unsigned char const *, unixmessage_handler_func_t *, void *) ;
+#define skaclient_putmsg(a, m, cb, result) skaclient_putmsg_and_close(a, m, unixmessage_bits_closenone, cb, result)
+extern int skaclient_putmsgv_and_close (skaclient_t *, unixmessage_v_t const *, unsigned char const *, unixmessage_handler_func_t *, void *) ;
+#define skaclient_putmsgv(a, m, cb, result) skaclient_putmsgv_and_close(a, m, unixmessage_bits_closenone, cb, result)
+
+extern int skaclient_put (skaclient_t *, char const *, unsigned int, unixmessage_handler_func_t *, void *) ;
+extern int skaclient_putv (skaclient_t *, siovec_t const *, unsigned int, unixmessage_handler_func_t *, void *) ;
+
+extern int skaclient_sendmsg_and_close (skaclient_t *, unixmessage_t const *, unsigned char const *, unixmessage_handler_func_t *, void *, tain_t const *, tain_t *) ;
+#define skaclient_sendmsg_and_close_g(a, m, bits, cb, result, deadline) skaclient_sendmsg_and_close(a, m, bits, cb, result, (deadline), &STAMP)
+#define skaclient_sendmsg(a, m, cb, result, deadline, stamp) skaclient_sendmsg_and_close(a, m, unixmessage_bits_closenone, cb, result, deadline, stamp)
+#define skaclient_sendmsg_g(a, m, cb, result, deadline) skaclient_sendmsg(a, m, cb, result, (deadline), &STAMP)
+
+extern int skaclient_sendmsgv_and_close (skaclient_t *, unixmessage_v_t const *, unsigned char const *, unixmessage_handler_func_t *, void *, tain_t const *, tain_t *) ;
+#define skaclient_sendmsgv_and_close_g(a, m, bits, cb, result, deadline) skaclient_sendmsgv_and_close(a, m, bits, cb, result, (deadline), &STAMP)
+#define skaclient_sendmsgv(a, m, cb, result, deadline, stamp) skaclient_sendmsgv_and_close(a, m, unixmessage_bits_closenone, cb, result, deadline, stamp)
+#define skaclient_sendmsgv_g(a, m, cb, result, deadline) skaclient_sendmsgv(a, m, cb, result, (deadline), &STAMP)
+
+extern int skaclient_send (skaclient_t *, char const *, unsigned int, unixmessage_handler_func_t *, void *, tain_t const *, tain_t *) ;
+#define skaclient_send_g(a, s, len, cb, result, deadline) skaclient_send(a, s, len, cb, result, (deadline), &STAMP)
+extern int skaclient_sendv (skaclient_t *, siovec_t const *, unsigned int, unixmessage_handler_func_t *, void *, tain_t const *, tain_t *) ;
+#define skaclient_sendv_g(a, v, vlen, cb, result, deadline) skaclient_sendv(a, v, vlen, cb, result, (deadline), &STAMP)
+
+#define skaclient_sfd(a) unixmessage_receiver_fd(&(a)->syncin)
+#define skaclient_flush(a) unixmessage_sender_flush(&(a)->syncout)
+#define skaclient_timed_flush(a, deadline, stamp) unixmessage_sender_timed_flush(&(a)->syncout, deadline, stamp)
+#define skaclient_timed_flush_g(a, deadline) skaclient_timed_flush(a, (deadline), &STAMP)
+
+#define skaclient_supdate(a) unixmessage_handle(&(a)->syncin, (unixmessage_handler_func_t *)&kolbak_call, &(a)->kq)
+#define skaclient_timed_supdate(a, deadline, stamp) unixmessage_timed_handle(&(a)->syncin, (unixmessage_handler_func_t *)&kolbak_call, &(a)->kq, deadline, stamp)
+#define skaclient_timed_supdate_g(a, deadline) skaclient_timed_supdate(a, (deadline), &STAMP)
+
+#define skaclient_fd(a) skaclient_afd(a)
+#define skaclient_afd(a) unixmessage_receiver_fd(&(a)->asyncin)
+#define skaclient_update(a, f, p) skaclient_aupdate(a, f, p)
+#define skaclient_aupdate(a, f, p) unixmessage_handle(&(a)->asyncin, f, p)
+
+extern unixmessage_handler_func_t skaclient_default_cb ;
+
+#endif
diff --git a/src/include/skalibs/skalibs.h b/src/include/skalibs/skalibs.h
new file mode 100644
index 0000000..e889461
--- /dev/null
+++ b/src/include/skalibs/skalibs.h
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#ifndef SKALIBS_H
+#define SKALIBS_H
+
+/*
+ This header includes everything in skalibs,
+ except skalibs/config.h and skalibs/sysdeps.h
+ It's heavy!
+*/
+
+#include <skalibs/stddjb.h>
+#include <skalibs/stdcrypto.h>
+#include <skalibs/random.h>
+#include <skalibs/datastruct.h>
+#include <skalibs/biguint.h>
+#include <skalibs/unixonacid.h>
+
+#endif
diff --git a/src/include/skalibs/skamisc.h b/src/include/skalibs/skamisc.h
new file mode 100644
index 0000000..bdc4869
--- /dev/null
+++ b/src/include/skalibs/skamisc.h
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#ifndef SKAMISC_H
+#define SKAMISC_H
+
+#include <skalibs/buffer.h>
+#include <skalibs/stralloc.h>
+
+extern stralloc satmp ;
+
+extern int skagetln (buffer *, stralloc *, char) ;
+extern int skagetlnsep (buffer *, stralloc *, char const *, unsigned int) ;
+extern int getlnmax (buffer *, char *, unsigned int, unsigned int *, char) ;
+extern int getlnmaxsep (buffer *, char *, unsigned int, unsigned int *, char const *, unsigned int) ;
+
+extern int sauniquename (stralloc *) ;
+
+extern int string_quote (stralloc *, char const *, unsigned int) ;
+extern int string_quote_nodelim (stralloc *, char const *, unsigned int) ;
+extern int string_quote_nodelim_mustquote (stralloc *, char const *, unsigned int, char const *, unsigned int) ;
+extern int string_unquote (char *, unsigned int *, char const *, unsigned int, unsigned int *) ;
+extern int string_unquote_nodelim (char *, char const *, unsigned int) ;
+extern int string_unquote_withdelim (char *, unsigned int *, char const *, unsigned int, unsigned int *, char const *, unsigned int) ;
+
+extern int string_format (stralloc *, char const *, char const *, char const *const *) ;
+
+#define skaoffsetof(n, s, field) do { s sofoftmp ; *(n) = (unsigned char *)&sofoftmp->field - (unsigned char *)&sofoftmp ; } while (0)
+
+#endif
diff --git a/src/include/skalibs/socket.h b/src/include/skalibs/socket.h
new file mode 100644
index 0000000..91be2f5
--- /dev/null
+++ b/src/include/skalibs/socket.h
@@ -0,0 +1,122 @@
+/* ISC license. */
+
+#ifndef SOCKET_H
+#define SOCKET_H
+
+#include <skalibs/gccattributes.h>
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/webipc.h>
+
+typedef int socket_io_func_t (int, char *, unsigned int, char *, uint16 *) ;
+typedef socket_io_func_t *socket_io_func_t_ref ;
+
+
+ /* INET and INET6 domain socket operations */
+
+#define socket_tcp() socket_tcp4()
+#define socket_tcp_b() socket_tcp4_b()
+#define socket_tcp_nb() socket_tcp4_nb()
+#define socket_tcp_coe() socket_tcp4_coe()
+#define socket_tcp_nbcoe() socket_tcp4_nbcoe()
+
+#define socket_tcp4() socket_tcp4_nb()
+#define socket_tcp4_b() socket_tcp4_internal(0)
+#define socket_tcp4_nb() socket_tcp4_internal(DJBUNIX_FLAG_NB)
+#define socket_tcp4_coe() socket_tcp4_internal(DJBUNIX_FLAG_COE)
+#define socket_tcp4_nbcoe() socket_tcp4_internal(DJBUNIX_FLAG_NB|DJBUNIX_FLAG_COE)
+extern int socket_tcp4_internal (unsigned int) ;
+
+#define socket_tcp6() socket_tcp6_nb()
+#define socket_tcp6_b() socket_tcp6_internal(0)
+#define socket_tcp6_nb() socket_tcp6_internal(DJBUNIX_FLAG_NB)
+#define socket_tcp6_coe() socket_tcp6_internal(DJBUNIX_FLAG_COE)
+#define socket_tcp6_nbcoe() socket_tcp6_internal(DJBUNIX_FLAG_NB|DJBUNIX_FLAG_COE)
+extern int socket_tcp6_internal (unsigned int) ;
+
+#define socket_udp() socket_udp4()
+#define socket_udp_b() socket_udp4_b()
+#define socket_udp_nb() socket_udp4_nb()
+#define socket_udp_coe() socket_udp4_coe()
+#define socket_udp_nbcoe() socket_udp4_nbcoe()
+
+#define socket_udp4() socket_udp4_nb()
+#define socket_udp4_b() socket_udp4_internal(0)
+#define socket_udp4_nb() socket_udp4_internal(DJBUNIX_FLAG_NB)
+#define socket_udp4_coe() socket_udp4_internal(DJBUNIX_FLAG_COE)
+#define socket_udp4_nbcoe() socket_udp4_internal(DJBUNIX_FLAG_NB|DJBUNIX_FLAG_COE)
+extern int socket_udp4_internal (unsigned int) ;
+
+#define socket_udp6() socket_udp6_nb()
+#define socket_udp6_b() socket_udp6_internal(0)
+#define socket_udp6_nb() socket_udp6_internal(DJBUNIX_FLAG_NB)
+#define socket_udp6_coe() socket_udp6_internal(DJBUNIX_FLAG_COE)
+#define socket_udp6_nbcoe() socket_udp6_internal(DJBUNIX_FLAG_NB|DJBUNIX_FLAG_COE)
+extern int socket_udp6_internal (unsigned int) ;
+
+extern int socket_waitconn (int, tain_t const *, tain_t *) ;
+#define socket_waitconn_g(fd, deadline) socket_waitconn(fd, (deadline), &STAMP)
+extern int socket_deadlineconnstamp4 (int, char const *, uint16, tain_t const *, tain_t *) ;
+#define socket_deadlineconnstamp(s, ip, port, deadline, stamp) socket_deadlineconnstamp4(s, ip, port, deadline, stamp)
+#define socket_deadlineconnstamp4_g(fd, ip, port, deadline) socket_deadlineconnstamp4(fd, ip, port, (deadline), &STAMP)
+extern int socket_deadlineconnstamp4_u32 (int, uint32, uint16, tain_t const *, tain_t *) ;
+#define socket_deadlineconnstamp4_u32_g(fd, ip, port, deadline) socket_deadlineconnstamp4_u32(fd, ip, port, (deadline), &STAMP)
+
+extern int socket_timeoutconn (int, char const *, uint16, unsigned int) ;
+extern int socket_connect4 (int, char const *, uint16) ;
+extern int socket_connect4_u32 (int, uint32, uint16) ;
+extern int socket_connected (int) gccattr_const ;
+extern int socket_bind4 (int, char const *, uint16) ;
+extern int socket_bind4_reuse (int, char const *, uint16) ;
+#define socket_listen(fd, b) ipc_listen(fd, b)
+
+extern int socket_connect6 (int, char const *, uint16) ;
+extern int socket_deadlineconnstamp6 (int, char const *, uint16, tain_t const *, tain_t *) ;
+#define socket_deadlineconnstamp6_g(fd, ip6, port, deadline) socket_deadlineconnstamp6(fd, ip6, port, (deadline), &STAMP)
+extern int socket_bind6 (int, char const *, uint16) ;
+extern int socket_bind6_reuse (int, char const *, uint16) ;
+
+#define socket_accept4(s, ip, port) socket_accept4_internal(s, ip, (port), 0)
+#define socket_accept4_nb(s, ip, port) socket_accept4_internal(s, ip, (port), DJBUNIX_FLAG_NB)
+#define socket_accept4_coe(s, ip, port) socket_accept4_internal(s, ip, (port), DJBUNIX_FLAG_COE)
+#define socket_accept4_nbcoe(s, ip, port) socket_accept4_internal(s, ip, (port), DJBUNIX_FLAG_NB|DJBUNIX_FLAG_COE)
+extern int socket_accept4_internal (int, char *, uint16 *, unsigned int) ;
+extern socket_io_func_t socket_recv4 ;
+extern int socket_send4 (int, char const *, unsigned int, char const *, uint16) ;
+extern socket_io_func_t socket_ioloop_send4 ;
+extern int socket_local4 (int, char *, uint16 *) ;
+extern int socket_remote4 (int, char *, uint16 *) ;
+
+#define socket_accept6(s, ip6, port) socket_accept6_internal(s, ip6, (port), 0)
+#define socket_accept6_nb(s, ip6, port) socket_accept6_internal(s, ip6, (port), DJBUNIX_FLAG_NB)
+#define socket_accept6_coe(s, ip6, port) socket_accept6_internal(s, ip6, (port), DJBUNIX_FLAG_COE)
+#define socket_accept6_nbcoe(s, ip6, port) socket_accept6_internal(s, ip6, (port), DJBUNIX_FLAG_NB|DJBUNIX_FLAG_COE)
+extern int socket_accept6_internal (int, char *, uint16 *, unsigned int) ;
+extern socket_io_func_t socket_recv6 ;
+extern int socket_send6 (int, char const *, unsigned int, char const *, uint16) ;
+extern socket_io_func_t socket_ioloop_send6 ;
+extern int socket_local6 (int, char *, uint16 *) ;
+extern int socket_remote6 (int, char *, uint16 *) ;
+
+extern int socket_ipoptionskill (int) ;
+extern int socket_tcpnodelay (int) ;
+extern void socket_tryreservein (int, unsigned int) ;
+
+
+ /* Timed send and recv operations (for dgram sockets) */
+
+extern int socket_ioloop (int, char *, unsigned int, char *, uint16 *, socket_io_func_t_ref, int, tain_t const *, tain_t *) ;
+
+#define socket_sendnb4(fd, buf, len, ip4, port, deadline, stamp) socket_ioloop(fd, buf, len, (char *)ip4, &(port), &socket_ioloop_send4, 1, deadline, stamp)
+#define socket_sendnb4_g(fd, buf, len, ip4, port, deadline) socket_sendnb4(fd, buf, len, ip4, port, (deadline), &STAMP)
+#define socket_recvnb4(fd, buf, len, ip4, port, deadline, stamp) socket_ioloop(fd, buf, len, ip4, port, &socket_recv4, 0, deadline, stamp)
+#define socket_recvnb4_g(fd, buf, len, ip4, port, deadline) socket_recvnb4(fd, buf, len, ip4, port, (deadline), &STAMP)
+
+#define socket_sendnb6(fd, buf, len, ip6, port, deadline, stamp) socket_ioloop(fd, buf, len, (char *)ip6, &(port), &socket_ioloop_send6, 1, deadline, stamp)
+#define socket_sendnb6_g(fd, buf, len, ip6, port, deadline) socket_sendnb6(fd, buf, len, ip6, port, (deadline), &STAMP)
+#define socket_recvnb6(fd, buf, len, ip6, port, deadline, stamp) socket_ioloop(fd, buf, len, ip6, port, &socket_recv6, 0, deadline, stamp)
+#define socket_recvnb6_g(fd, buf, len, ip6, port, deadline) socket_recvnb6(fd, buf, len, ip6, port, (deadline), &STAMP)
+
+#endif
diff --git a/src/include/skalibs/stdcrypto.h b/src/include/skalibs/stdcrypto.h
new file mode 100644
index 0000000..bd6751b
--- /dev/null
+++ b/src/include/skalibs/stdcrypto.h
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#ifndef STDCRYPTO_H
+#define STDCRYPTO_H
+
+#include <skalibs/rc4.h>
+#include <skalibs/md5.h>
+#include <skalibs/sha1.h>
+#include <skalibs/sha256.h>
+
+#endif
diff --git a/src/include/skalibs/stddjb.h b/src/include/skalibs/stddjb.h
new file mode 100644
index 0000000..e265003
--- /dev/null
+++ b/src/include/skalibs/stddjb.h
@@ -0,0 +1,60 @@
+/* ISC license. */
+
+#ifndef STDDJB_H
+#define STDDJB_H
+
+#include <skalibs/config.h>
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/uint64.h>
+#include <skalibs/ushort.h>
+#include <skalibs/uint.h>
+#include <skalibs/ulong.h>
+#include <skalibs/error.h>
+#include <skalibs/gidstuff.h>
+#include <skalibs/ip46.h>
+#include <skalibs/setgroups.h>
+
+#include <skalibs/alloc.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/bitarray.h>
+#include <skalibs/bufalloc.h>
+#include <skalibs/buffer.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/cbuffer.h>
+#include <skalibs/cdb.h>
+#include <skalibs/cdb_make.h>
+#include <skalibs/direntry.h>
+#include <skalibs/diuint32.h>
+#include <skalibs/diuint.h>
+#include <skalibs/djbtime.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/envalloc.h>
+#include <skalibs/env.h>
+#include <skalibs/environ.h>
+#include <skalibs/fmtscan.h>
+#include <skalibs/functypes.h>
+#include <skalibs/gccattributes.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/genwrite.h>
+#include <skalibs/getpeereid.h>
+#include <skalibs/iobuffer.h>
+#include <skalibs/iopause.h>
+#include <skalibs/lolstdio.h>
+#include <skalibs/mininetstring.h>
+#include <skalibs/netstring.h>
+#include <skalibs/nsig.h>
+#include <skalibs/segfault.h>
+#include <skalibs/selfpipe.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/sig.h>
+#include <skalibs/siovec.h>
+#include <skalibs/skamisc.h>
+#include <skalibs/socket.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/strerr.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/tai.h>
+#include <skalibs/webipc.h>
+
+#endif
diff --git a/src/include/skalibs/stralloc.h b/src/include/skalibs/stralloc.h
new file mode 100644
index 0000000..2d762d4
--- /dev/null
+++ b/src/include/skalibs/stralloc.h
@@ -0,0 +1,40 @@
+/* ISC license. */
+
+#ifndef STRALLOC_H
+#define STRALLOC_H
+
+#include <skalibs/bytestr.h>
+#include <skalibs/siovec.h>
+
+typedef struct stralloc_s stralloc, *stralloc_ref ;
+struct stralloc_s
+{
+ char *s ;
+ unsigned int len ;
+ unsigned int a ;
+} ;
+
+#define STRALLOC_ZERO { .s = 0, .len = 0, .a = 0 }
+extern stralloc const stralloc_zero ;
+
+extern int stralloc_ready_tuned (stralloc *, unsigned int, unsigned int, unsigned int, unsigned int) ;
+#define stralloc_ready(sa, n) stralloc_ready_tuned(sa, (n), 8, 1, 8)
+#define stralloc_readyplus(sa, n) stralloc_ready(sa, (sa)->len + (n))
+extern void stralloc_free (stralloc *) ;
+extern int stralloc_shrink (stralloc *) ;
+extern int stralloc_copyb (stralloc *, char const *, unsigned int) ;
+extern int stralloc_catb (stralloc *, char const *, unsigned int) ;
+extern int stralloc_catv (stralloc *, siovec_t const *, unsigned int) ;
+#define stralloc_copys(sa, s) stralloc_copyb(sa, (s), str_len(s))
+#define stralloc_cats(sa, s) stralloc_catb(sa, (s), str_len(s))
+#define stralloc_copy(sa1, sa2) stralloc_copyb(sa1, (sa2)->s, (sa2)->len)
+#define stralloc_cat(sa1, sa2) stralloc_catb(sa1, (sa2)->s, (sa2)->len)
+extern int stralloc_append (stralloc *, char) ;
+extern void stralloc_reverse (stralloc *) ;
+extern void stralloc_reverse_blocks (stralloc *, unsigned int) ;
+#define stralloc_0(sa) stralloc_catb(sa, "", 1)
+extern int stralloc_insertb (stralloc *, unsigned int, char const *, unsigned int) ;
+#define stralloc_inserts(sa, offset, s) stralloc_insertb(sa, offset, (s), str_len(s))
+#define stralloc_insert(sa1, offset, sa2) stralloc_insertb(sa1, offset, (sa2)->s, (sa2)->len)
+
+#endif
diff --git a/src/include/skalibs/strerr.h b/src/include/skalibs/strerr.h
new file mode 100644
index 0000000..64665b5
--- /dev/null
+++ b/src/include/skalibs/strerr.h
@@ -0,0 +1,139 @@
+/* ISC license. */
+
+#ifndef STRERR_H
+#define STRERR_H
+
+#include <skalibs/gccattributes.h>
+
+extern void strerr_warn (char const *, char const *, char const *, char const *, char const *, char const *, char const *, char const *, char const *, char const *, char const *) ;
+extern void strerr_die (int, char const *, char const *, char const *, char const *, char const *, char const *, char const *, char const *, char const *, char const *, char const *) gccattr_noreturn ;
+extern void strerr_warnsys (char const *, char const *, char const *, char const *, char const *, char const *, char const *, char const *, char const *, char const *) ;
+extern void strerr_diesys (int, char const *, char const *, char const *, char const *, char const *, char const *, char const *, char const *, char const *, char const *) gccattr_noreturn ;
+
+#define strerr_warn10(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, se) \
+strerr_warn(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, se)
+#define strerr_warn9(x1, x2, x3, x4, x5, x6, x7, x8, x9, se) \
+strerr_warn(x1, x2, x3, x4, x5, x6, x7, x8, x9, 0, se)
+#define strerr_warn8(x1, x2, x3, x4, x5, x6, x7, x8, se) \
+strerr_warn(x1, x2, x3, x4, x5, x6, x7, x8, 0, 0, se)
+#define strerr_warn7(x1, x2, x3, x4, x5, x6, x7, se) \
+strerr_warn(x1, x2, x3, x4, x5, x6, x7, 0, 0, 0, se)
+#define strerr_warn6(x1, x2, x3, x4, x5, x6, se) \
+strerr_warn(x1, x2, x3, x4, x5, x6, 0, 0, 0, 0, se)
+#define strerr_warn5(x1, x2, x3, x4, x5, se) \
+strerr_warn(x1, x2, x3, x4, x5, 0, 0, 0, 0, 0, se)
+#define strerr_warn4(x1, x2, x3, x4, se) \
+strerr_warn(x1, x2, x3, x4, 0, 0, 0, 0, 0, 0, se)
+#define strerr_warn3(x1, x2, x3, se) \
+strerr_warn(x1, x2, x3, 0, 0, 0, 0, 0, 0, 0, se)
+#define strerr_warn2(x1, x2, se) \
+strerr_warn(x1, x2, 0, 0, 0, 0, 0, 0, 0, 0, se)
+#define strerr_warn1(x1, se) \
+strerr_warn(x1, 0, 0, 0, 0, 0, 0, 0, 0, 0, se)
+
+#define strerr_warn10sys(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) \
+strerr_warnsys(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)
+#define strerr_warn9sys(x1, x2, x3, x4, x5, x6, x7, x8, x9) \
+strerr_warnsys(x1, x2, x3, x4, x5, x6, x7, x8, (x9), 0)
+#define strerr_warn8sys(x1, x2, x3, x4, x5, x6, x7, x8) \
+strerr_warnsys(x1, x2, x3, x4, x5, x6, x7, (x8), 0, 0)
+#define strerr_warn7sys(x1, x2, x3, x4, x5, x6, x7) \
+strerr_warnsys(x1, x2, x3, x4, x5, x6, (x7), 0, 0, 0)
+#define strerr_warn6sys(x1, x2, x3, x4, x5, x6) \
+strerr_warnsys(x1, x2, x3, x4, x5, (x6), 0, 0, 0, 0)
+#define strerr_warn5sys(x1, x2, x3, x4, x5) \
+strerr_warnsys(x1, x2, x3, x4, (x5), 0, 0, 0, 0, 0)
+#define strerr_warn4sys(x1, x2, x3, x4) \
+strerr_warnsys(x1, x2, x3, (x4), 0, 0, 0, 0, 0, 0)
+#define strerr_warn3sys(x1, x2, x3) \
+strerr_warnsys(x1, x2, (x3), 0, 0, 0, 0, 0, 0, 0)
+#define strerr_warn2sys(x1, x2) \
+strerr_warnsys(x1, (x2), 0, 0, 0, 0, 0, 0, 0, 0)
+#define strerr_warn1sys(x1) \
+strerr_warnsys((x1), 0, 0, 0, 0, 0, 0, 0, 0, 0)
+
+#define strerr_warn10x(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) \
+strerr_warn(x1, x2, x3, x4, x5, x6, x7, x8, x9, (x10), 0)
+#define strerr_warn9x(x1, x2, x3, x4, x5, x6, x7, x8, x9) \
+strerr_warn(x1, x2, x3, x4, x5, x6, x7, x8, (x9), 0, 0)
+#define strerr_warn8x(x1, x2, x3, x4, x5, x6, x7, x8) \
+strerr_warn(x1, x2, x3, x4, x5, x6, x7, (x8), 0, 0, 0)
+#define strerr_warn7x(x1, x2, x3, x4, x5, x6, x7) \
+strerr_warn(x1, x2, x3, x4, x5, x6, (x7), 0, 0, 0, 0)
+#define strerr_warn6x(x1, x2, x3, x4, x5, x6) \
+strerr_warn(x1, x2, x3, x4, x5, (x6), 0, 0, 0, 0, 0)
+#define strerr_warn5x(x1, x2, x3, x4, x5) \
+strerr_warn(x1, x2, x3, x4, (x5), 0, 0, 0, 0, 0, 0)
+#define strerr_warn4x(x1, x2, x3, x4) \
+strerr_warn(x1, x2, x3, (x4), 0, 0, 0, 0, 0, 0, 0)
+#define strerr_warn3x(x1, x2, x3) \
+strerr_warn(x1, x2, (x3), 0, 0, 0, 0, 0, 0, 0, 0)
+#define strerr_warn2x(x1, x2) \
+strerr_warn(x1, (x2), 0, 0, 0, 0, 0, 0, 0, 0, 0)
+#define strerr_warn1x(x1) \
+strerr_warn((x1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+
+#define strerr_die10(e, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, se) \
+strerr_die(e, x1, x2, x3, x4, x5 , x6, x7, x8, x9, x10, se)
+#define strerr_die9(e, x1, x2, x3, x4, x5, x6, x7, x8, x9, se) \
+strerr_die(e, x1, x2, x3, x4, x5, x6, x7, x8, x9, 0, se)
+#define strerr_die8(e, x1, x2, x3, x4, x5, x6, x7, x8, se) \
+strerr_die(e, x1, x2, x3, x4, x5, x6, x7, x8, 0, 0, se)
+#define strerr_die7(e, x1, x2, x3, x4, x5, x6, x7, se) \
+strerr_die(e, x1, x2, x3, x4, x5, x6, x7, 0, 0, 0, se)
+#define strerr_die6(e, x1, x2, x3, x4, x5, x6, se) \
+strerr_die(e, x1, x2, x3, x4, x5, x6, 0, 0, 0, 0, se)
+#define strerr_die5(e, x1, x2, x3, x4, x5, se) \
+strerr_die(e, x1, x2, x3, x4, x5, 0, 0, 0, 0, 0, se)
+#define strerr_die4(e, x1, x2, x3, x4, se) \
+strerr_die(e, x1, x2, x3, x4, 0, 0, 0, 0, 0, 0, se)
+#define strerr_die3(e, x1, x2, x3, se) \
+strerr_die(e, x1, x2, x3, 0, 0, 0, 0, 0, 0, 0, se)
+#define strerr_die2(e, x1, x2, se) \
+strerr_die(e, x1, x2, 0, 0, 0, 0, 0, 0, 0, 0, se)
+#define strerr_die1(e, x1, se) \
+strerr_die(e, x1, 0, 0, 0, 0, 0, 0, 0, 0, 0, se)
+
+#define strerr_die10sys(e, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) \
+strerr_diesys(e, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)
+#define strerr_die9sys(e, x1, x2, x3, x4, x5, x6, x7, x8, x9) \
+strerr_diesys(e, x1, x2, x3, x4, x5, x6, x7, x8, (x9), 0)
+#define strerr_die8sys(e, x1, x2, x3, x4, x5, x6, x7, x8) \
+strerr_diesys(e, x1, x2, x3, x4, x5, x6, x7, (x8), 0, 0)
+#define strerr_die7sys(e, x1, x2, x3, x4, x5, x6, x7) \
+strerr_diesys(e, x1, x2, x3, x4, x5, x6, (x7), 0, 0, 0)
+#define strerr_die6sys(e, x1, x2, x3, x4, x5, x6) \
+strerr_diesys(e, x1, x2, x3, x4, x5, (x6), 0, 0, 0, 0)
+#define strerr_die5sys(e, x1, x2, x3, x4, x5) \
+strerr_diesys(e, x1, x2, x3, x4, (x5), 0, 0, 0, 0, 0)
+#define strerr_die4sys(e, x1, x2, x3, x4) \
+strerr_diesys(e, x1, x2, x3, (x4), 0, 0, 0, 0, 0, 0)
+#define strerr_die3sys(e, x1, x2, x3) \
+strerr_diesys(e, x1, x2, (x3), 0, 0, 0, 0, 0, 0, 0)
+#define strerr_die2sys(e, x1, x2) \
+strerr_diesys(e, x1, (x2), 0, 0, 0, 0, 0, 0, 0, 0)
+#define strerr_die1sys(e, x1) \
+strerr_diesys(e, (x1), 0, 0, 0, 0, 0, 0, 0, 0, 0)
+
+#define strerr_die10x(e, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) \
+strerr_die(e, x1, x2, x3, x4, x5, x6, x7, x8, x9, (x10), 0)
+#define strerr_die9x(e, x1, x2, x3, x4, x5, x6, x7, x8, x9) \
+strerr_die(e, x1, x2, x3, x4, x5, x6, x7, x8, (x9), 0, 0)
+#define strerr_die8x(e, x1, x2, x3, x4, x5, x6, x7, x8) \
+strerr_die(e, x1, x2, x3, x4, x5, x6, x7, (x8), 0, 0, 0)
+#define strerr_die7x(e, x1, x2, x3, x4, x5, x6, x7) \
+strerr_die(e, x1, x2, x3, x4, x5, x6, (x7), 0, 0, 0, 0)
+#define strerr_die6x(e, x1, x2, x3, x4, x5, x6) \
+strerr_die(e, x1, x2, x3, x4, x5, (x6), 0, 0, 0, 0, 0)
+#define strerr_die5x(e, x1, x2, x3, x4, x5) \
+strerr_die(e, x1, x2, x3, x4, (x5), 0, 0, 0, 0, 0, 0)
+#define strerr_die4x(e, x1, x2, x3, x4) \
+strerr_die(e, x1, x2, x3, (x4), 0, 0, 0, 0, 0, 0, 0)
+#define strerr_die3x(e, x1, x2, x3) \
+strerr_die(e, x1, x2, (x3), 0, 0, 0, 0, 0, 0, 0, 0)
+#define strerr_die2x(e, x1, x2) \
+strerr_die(e, x1, (x2), 0, 0, 0, 0, 0, 0, 0, 0, 0)
+#define strerr_die1x(e, x1) \
+strerr_die(e, (x1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+
+#endif
diff --git a/src/include/skalibs/strerr2.h b/src/include/skalibs/strerr2.h
new file mode 100644
index 0000000..fa7cc02
--- /dev/null
+++ b/src/include/skalibs/strerr2.h
@@ -0,0 +1,267 @@
+/* ISC license. */
+
+#ifndef STRERR2_H
+#define STRERR2_H
+
+#include <skalibs/strerr.h>
+
+extern char const *PROG ;
+
+
+#define strerr_warnw1x(x1) \
+strerr_warn3x(PROG, ": warning: ", (x1))
+#define strerr_warnw2x(x1, x2) \
+strerr_warn4x(PROG, ": warning: ", (x1), x2)
+#define strerr_warnw3x(x1, x2, x3) \
+strerr_warn5x(PROG, ": warning: ", (x1), x2, x3)
+#define strerr_warnw4x(x1, x2, x3, x4) \
+strerr_warn6x(PROG, ": warning: ", (x1), x2, x3, x4)
+#define strerr_warnw5x(x1, x2, x3, x4, x5) \
+strerr_warn7x(PROG, ": warning: ", (x1), x2, x3, x4, x5)
+#define strerr_warnw6x(x1, x2, x3, x4, x5, x6) \
+strerr_warn8x(PROG, ": warning: ", (x1), x2, x3, x4, x5, x6)
+#define strerr_warnw7x(x1, x2, x3, x4, x5, x6, x7) \
+strerr_warn9x(PROG, ": warning: ", (x1), x2, x3, x4, x5, x6, x7)
+#define strerr_warnw8x(x1, x2, x3, x4, x5, x6, x7, x8) \
+strerr_warn10x(PROG, ": warning: ", (x1), x2, x3, x4, x5, x6, x7, x8)
+
+#define strerr_warnw1sys(x1) \
+strerr_warn4sys(PROG, ": warning: ", (x1), ": ")
+#define strerr_warnw2sys(x1, x2) \
+strerr_warn5sys(PROG, ": warning: ", (x1), (x2), ": ")
+#define strerr_warnw3sys(x1, x2, x3) \
+strerr_warn6sys(PROG, ": warning: ", (x1), x2, (x3), ": ")
+#define strerr_warnw4sys(x1, x2, x3, x4) \
+strerr_warn7sys(PROG, ": warning: ", (x1), x2, x3, (x4), ": ")
+#define strerr_warnw5sys(x1, x2, x3, x4, x5) \
+strerr_warn8sys(PROG, ": warning: ", (x1), x2, x3, x4, (x5), ": ")
+#define strerr_warnw6sys(x1, x2, x3, x4, x5, x6) \
+strerr_warn9sys(PROG, ": warning: ", (x1), x2, x3, x4, x5, (x6), ": ")
+#define strerr_warnw7sys(x1, x2, x3, x4, x5, x6, x7) \
+strerr_warn10sys(PROG, ": warning: ", (x1), x2, x3, x4, x5, x6, (x7), ": ")
+
+#define strerr_diew1x(e, x1) \
+strerr_die3x(e, PROG, ": warning: ", x1)
+#define strerr_diew2x(e, x1, x2) \
+strerr_die4x(e, PROG, ": warning: ", x1, x2)
+#define strerr_diew3x(e, x1, x2, x3) \
+strerr_die5x(e, PROG, ": warning: ", x1, x2, x3)
+#define strerr_diew4x(e, x1, x2, x3, x4) \
+strerr_die6x(e, PROG, ": warning: ", x1, x2, x3, x4)
+#define strerr_diew5x(e, x1, x2, x3, x4, x5) \
+strerr_die7x(e, PROG, ": warning: ", x1, x2, x3, x4, x5)
+#define strerr_diew6x(e, x1, x2, x3, x4, x5, x6) \
+strerr_die8x(e, PROG, ": warning: ", x1, x2, x3, x4, x5, x6)
+#define strerr_diew7x(e, x1, x2, x3, x4, x5, x6, x7) \
+strerr_die9x(e, PROG, ": warning: ", x1, x2, x3, x4, x5, x6, x7)
+#define strerr_diew8x(e, x1, x2, x3, x4, x5, x6, x7, x8) \
+strerr_die10x(e, PROG, ": warning: ", x1, x2, x3, x4, x5, x6, x7, x8)
+
+#define strerr_diew1sys(e, x1) \
+strerr_die4sys(e, PROG, ": warning: ", (x1), ": ")
+#define strerr_diew2sys(e, x1, x2) \
+strerr_die5sys(e, PROG, ": warning: ", x1, (x2), ": ")
+#define strerr_diew3sys(e, x1, x2, x3) \
+strerr_die6sys(e, PROG, ": warning: ", x1, x2, (x3), ": ")
+#define strerr_diew4sys(e, x1, x2, x3, x4) \
+strerr_die7sys(e, PROG, ": warning: ", x1, x2, x3, (x4), ": ")
+#define strerr_diew5sys(e, x1, x2, x3, x4, x5) \
+strerr_die8sys(e, PROG, ": warning: ", x1, x2, x3, x4, (x5), ": ")
+#define strerr_diew6sys(e, x1, x2, x3, x4, x5, x6) \
+strerr_die9sys(e, PROG, ": warning: ", x1, x2, x3, x4, x5, (x6), ": ")
+#define strerr_diew7sys(e, x1, x2, x3, x4, x5, x6, x7) \
+strerr_die10sys(e, PROG, ": warning: ", x1, x2, x3, x4, x5, x6, (x7), ": ")
+
+#define strerr_dief1x(e, x1) \
+strerr_die3x(e, PROG, ": fatal: ", x1)
+#define strerr_dief2x(e, x1, x2) \
+strerr_die4x(e, PROG, ": fatal: ", x1, x2)
+#define strerr_dief3x(e, x1, x2, x3) \
+strerr_die5x(e, PROG, ": fatal: ", x1, x2, x3)
+#define strerr_dief4x(e, x1, x2, x3, x4) \
+strerr_die6x(e, PROG, ": fatal: ", x1, x2, x3, x4)
+#define strerr_dief5x(e, x1, x2, x3, x4, x5) \
+strerr_die7x(e, PROG, ": fatal: ", x1, x2, x3, x4, x5)
+#define strerr_dief6x(e, x1, x2, x3, x4, x5, x6) \
+strerr_die8x(e, PROG, ": fatal: ", x1, x2, x3, x4, x5, x6)
+#define strerr_dief7x(e, x1, x2, x3, x4, x5, x6, x7) \
+strerr_die9x(e, PROG, ": fatal: ", x1, x2, x3, x4, x5, x6, x7)
+#define strerr_dief8x(e, x1, x2, x3, x4, x5, x6, x7, x8) \
+strerr_die10x(e, PROG, ": fatal: ", x1, x2, x3, x4, x5, x6, x7, x8)
+
+#define strerr_dief1sys(e, x1) \
+strerr_die4sys(e, PROG, ": fatal: ", (x1), ": ")
+#define strerr_dief2sys(e, x1, x2) \
+strerr_die5sys(e, PROG, ": fatal: ", x1, (x2), ": ")
+#define strerr_dief3sys(e, x1, x2, x3) \
+strerr_die6sys(e, PROG, ": fatal: ", x1, x2, (x3), ": ")
+#define strerr_dief4sys(e, x1, x2, x3, x4) \
+strerr_die7sys(e, PROG, ": fatal: ", x1, x2, x3, (x4), ": ")
+#define strerr_dief5sys(e, x1, x2, x3, x4, x5) \
+strerr_die8sys(e, PROG, ": fatal: ", x1, x2, x3, x4, (x5), ": ")
+#define strerr_dief6sys(e, x1, x2, x3, x4, x5, x6) \
+strerr_die9sys(e, PROG, ": fatal: ", x1, x2, x3, x4, x5, (x6), ": ")
+#define strerr_dief7sys(e, x1, x2, x3, x4, x5, x6, x7) \
+strerr_die10sys(e, PROG, ": fatal: ", x1, x2, x3, x4, x5, x6, (x7), ": ")
+
+#define strerr_diefu1x(e, x1) \
+strerr_die4x(e, PROG, ": fatal: ", "unable to ", x1)
+#define strerr_diefu2x(e, x1, x2) \
+strerr_die5x(e, PROG, ": fatal: ", "unable to ", x1, x2)
+#define strerr_diefu3x(e, x1, x2, x3) \
+strerr_die6x(e, PROG, ": fatal: ", "unable to ", x1, x2, x3)
+#define strerr_diefu4x(e, x1, x2, x3, x4) \
+strerr_die7x(e, PROG, ": fatal: ", "unable to ", x1, x2, x3, x4)
+#define strerr_diefu5x(e, x1, x2, x3, x4, x5) \
+strerr_die8x(e, PROG, ": fatal: ", "unable to ", x1, x2, x3, x4, x5)
+#define strerr_diefu6x(e, x1, x2, x3, x4, x5, x6) \
+strerr_die9x(e, PROG, ": fatal: ", "unable to ", x1, x2, x3, x4, x5, x6)
+#define strerr_diefu7x(e, x1, x2, x3, x4, x5, x6, x7) \
+strerr_die10x(e, PROG, ": fatal: ", "unable to ", x1, x2, x3, x4, x5, x6, x7)
+
+#define strerr_diefu1sys(e, x1) \
+strerr_die5sys(e, PROG, ": fatal: ", "unable to ", (x1), ": ")
+#define strerr_diefu2sys(e, x1, x2) \
+strerr_die6sys(e, PROG, ": fatal: ", "unable to ", x1, (x2), ": ")
+#define strerr_diefu3sys(e, x1, x2, x3) \
+strerr_die7sys(e, PROG, ": fatal: ", "unable to ", x1, x2, (x3), ": ")
+#define strerr_diefu4sys(e, x1, x2, x3, x4) \
+strerr_die8sys(e, PROG, ": fatal: ", "unable to ", x1, x2, x3, (x4), ": ")
+#define strerr_diefu5sys(e, x1, x2, x3, x4, x5) \
+strerr_die9sys(e, PROG, ": fatal: ", "unable to ", x1, x2, x3, x4, (x5), ": ")
+#define strerr_diefu6sys(e, x1, x2, x3, x4, x5, x6) \
+strerr_die10sys(e, PROG, ": fatal: ", "unable to ", x1, x2, x3, x4, x5, (x6), ": ")
+
+#define strerr_warnwu1x(x1) \
+strerr_warn4x(PROG, ": warning: ", "unable to ", (x1))
+#define strerr_warnwu2x(x1, x2) \
+strerr_warn5x(PROG, ": warning: ", "unable to ", (x1), x2)
+#define strerr_warnwu3x(x1, x2, x3) \
+strerr_warn6x(PROG, ": warning: ", "unable to ", (x1), x2, x3)
+#define strerr_warnwu4x(x1, x2, x3, x4) \
+strerr_warn7x(PROG, ": warning: ", "unable to ", (x1), x2, x3, x4)
+#define strerr_warnwu5x(x1, x2, x3, x4, x5) \
+strerr_warn8x(PROG, ": warning: ", "unable to ", (x1), x2, x3, x4, x5)
+#define strerr_warnwu6x(x1, x2, x3, x4, x5, x6) \
+strerr_warn9x(PROG, ": warning: ", "unable to ", (x1), x2, x3, x4, x5, x6)
+#define strerr_warnwu7x(x1, x2, x3, x4, x5, x6, x7) \
+strerr_warn10x(PROG, ": warning: ", "unable to ", (x1), x2, x3, x4, x5, x6, x7)
+
+#define strerr_warnwu1sys(x1) \
+strerr_warn5sys(PROG, ": warning: ", "unable to ", (x1), ": ")
+#define strerr_warnwu2sys(x1, x2) \
+strerr_warn6sys(PROG, ": warning: ", "unable to ", (x1), (x2), ": ")
+#define strerr_warnwu3sys(x1, x2, x3) \
+strerr_warn7sys(PROG, ": warning: ", "unable to ", (x1), x2, (x3), ": ")
+#define strerr_warnwu4sys(x1, x2, x3, x4) \
+strerr_warn8sys(PROG, ": warning: ", "unable to ", (x1), x2, x3, (x4), ": ")
+#define strerr_warnwu5sys(x1, x2, x3, x4, x5) \
+strerr_warn9sys(PROG, ": warning: ", "unable to ", (x1), x2, x3, x4, (x5), ": ")
+#define strerr_warnwu6sys(x1, x2, x3, x4, x5, x6) \
+strerr_warn10sys(PROG, ": warning: ", "unable to ", (x1), x2, x3, x4, x5, (x6), ": ")
+
+#define strerr_diewu1x(e, x1) \
+strerr_die4x(e, PROG, ": warning: ", "unable to ", x1)
+#define strerr_diewu2x(e, x1, x2) \
+strerr_die5x(e, PROG, ": warning: ", "unable to ", x1, x2)
+#define strerr_diewu3x(e, x1, x2, x3) \
+strerr_die6x(e, PROG, ": warning: ", "unable to ", x1, x2, x3)
+#define strerr_diewu4x(e, x1, x2, x3, x4) \
+strerr_die7x(e, PROG, ": warning: ", "unable to ", x1, x2, x3, x4)
+#define strerr_diewu5x(e, x1, x2, x3, x4, x5) \
+strerr_die8x(e, PROG, ": warning: ", "unable to ", x1, x2, x3, x4, x5)
+#define strerr_diewu6x(e, x1, x2, x3, x4, x5, x6) \
+strerr_die9x(e, PROG, ": warning: ", "unable to ", x1, x2, x3, x4, x5, x6)
+#define strerr_diewu7x(e, x1, x2, x3, x4, x5, x6, x7) \
+strerr_die10x(e, PROG, ": warning: ", "unable to ", x1, x2, x3, x4, x5, x6, x7)
+
+#define strerr_diewu1sys(e, x1) \
+strerr_die5sys(e, PROG, ": warning: ", "unable to ", (x1), ": ")
+#define strerr_diewu2sys(e, x1, x2) \
+strerr_die6sys(e, PROG, ": warning: ", "unable to ", x1, (x2), ": ")
+#define strerr_diewu3sys(e, x1, x2, x3) \
+strerr_die7sys(e, PROG, ": warning: ", "unable to ", x1, x2, (x3), ": ")
+#define strerr_diewu4sys(e, x1, x2, x3, x4) \
+strerr_die8sys(e, PROG, ": warning: ", "unable to ", x1, x2, x3, (x4), ": ")
+#define strerr_diewu5sys(e, x1, x2, x3, x4, x5) \
+strerr_die9sys(e, PROG, ": warning: ", "unable to ", x1, x2, x3, x4, (x5), ": ")
+#define strerr_diewu6sys(e, x1, x2, x3, x4, x5, x6) \
+strerr_die10sys(e, PROG, ": warning: ", "unable to ", x1, x2, x3, x4, x5, (x6), ": ")
+
+#define strerr_dieusage(e, u) \
+strerr_die3x(e, PROG, ": usage: ", u)
+
+#define strerr_dienotset(e, x) \
+strerr_dief2x(e, (x), " not set")
+
+#define strerr_dieinvalid(e, x) \
+strerr_dief2x(e, "invalid $", x)
+
+#define strerr_dieexec(e, x) \
+strerr_diefu2sys(e, "exec ", x)
+
+#define strerr_warni1x(x1) \
+strerr_warn3x(PROG, ": info: ", (x1))
+#define strerr_warni2x(x1, x2) \
+strerr_warn4x(PROG, ": info: ", (x1), x2)
+#define strerr_warni3x(x1, x2, x3) \
+strerr_warn5x(PROG, ": info: ", (x1), x2, x3)
+#define strerr_warni4x(x1, x2, x3, x4) \
+strerr_warn6x(PROG, ": info: ", (x1), x2, x3, x4)
+#define strerr_warni5x(x1, x2, x3, x4, x5) \
+strerr_warn7x(PROG, ": info: ", (x1), x2, x3, x4, x5)
+#define strerr_warni6x(x1, x2, x3, x4, x5, x6) \
+strerr_warn8x(PROG, ": info: ", (x1), x2, x3, x4, x5, x6)
+#define strerr_warni7x(x1, x2, x3, x4, x5, x6, x7) \
+strerr_warn9x(PROG, ": info: ", (x1), x2, x3, x4, x5, x6, x7)
+#define strerr_warni8x(x1, x2, x3, x4, x5, x6, x7, x8) \
+strerr_warn10x(PROG, ": info: ", (x1), x2, x3, x4, x5, x6, x7, x8)
+
+#define strerr_warni1sys(x1) \
+strerr_warn4sys(PROG, ": info: ", (x1), ": ")
+#define strerr_warni2sys(x1, x2) \
+strerr_warn5sys(PROG, ": info: ", (x1), (x2), ": ")
+#define strerr_warni3sys(x1, x2, x3) \
+strerr_warn6sys(PROG, ": info: ", (x1), x2, (x3), ": ")
+#define strerr_warni4sys(x1, x2, x3, x4) \
+strerr_warn7sys(PROG, ": info: ", (x1), x2, x3, (x4), ": ")
+#define strerr_warni5sys(x1, x2, x3, x4, x5) \
+strerr_warn8sys(PROG, ": info: ", (x1), x2, x3, x4, (x5), ": ")
+#define strerr_warni6sys(x1, x2, x3, x4, x5, x6) \
+strerr_warn9sys(PROG, ": info: ", (x1), x2, x3, x4, x5, (x6), ": ")
+#define strerr_warni7sys(x1, x2, x3, x4, x5, x6, x7) \
+strerr_warn10sys(PROG, ": info: ", (x1), x2, x3, x4, x5, x6, (x7), ": ")
+
+#define strerr_warnt1x(x1) \
+strerr_warn3x(PROG, ": tracing: ", (x1))
+#define strerr_warnt2x(x1, x2) \
+strerr_warn4x(PROG, ": tracing: ", (x1), x2)
+#define strerr_warnt3x(x1, x2, x3) \
+strerr_warn5x(PROG, ": tracing: ", (x1), x2, x3)
+#define strerr_warnt4x(x1, x2, x3, x4) \
+strerr_warn6x(PROG, ": tracing: ", (x1), x2, x3, x4)
+#define strerr_warnt5x(x1, x2, x3, x4, x5) \
+strerr_warn7x(PROG, ": tracing: ", (x1), x2, x3, x4, x5)
+#define strerr_warnt6x(x1, x2, x3, x4, x5, x6) \
+strerr_warn8x(PROG, ": tracing: ", (x1), x2, x3, x4, x5, x6)
+#define strerr_warnt7x(x1, x2, x3, x4, x5, x6, x7) \
+strerr_warn9x(PROG, ": tracing: ", (x1), x2, x3, x4, x5, x6, x7)
+#define strerr_warnt8x(x1, x2, x3, x4, x5, x6, x7, x8) \
+strerr_warn10x(PROG, ": tracing: ", (x1), x2, x3, x4, x5, x6, x7, x8)
+
+#define strerr_warnt1sys(x1) \
+strerr_warn4sys(PROG, ": tracing: ", (x1), ": ")
+#define strerr_warnt2sys(x1, x2) \
+strerr_warn5sys(PROG, ": tracing: ", (x1), (x2), ": ")
+#define strerr_warnt3sys(x1, x2, x3) \
+strerr_warn6sys(PROG, ": tracing: ", (x1), x2, (x3), ": ")
+#define strerr_warnt4sys(x1, x2, x3, x4) \
+strerr_warn7sys(PROG, ": tracing: ", (x1), x2, x3, (x4), ": ")
+#define strerr_warnt5sys(x1, x2, x3, x4, x5) \
+strerr_warn8sys(PROG, ": tracing: ", (x1), x2, x3, x4, (x5), ": ")
+#define strerr_warnt6sys(x1, x2, x3, x4, x5, x6) \
+strerr_warn9sys(PROG, ": tracing: ", (x1), x2, x3, x4, x5, (x6), ": ")
+#define strerr_warnt7sys(x1, x2, x3, x4, x5, x6, x7) \
+strerr_warn10sys(PROG, ": tracing: ", (x1), x2, x3, x4, x5, x6, (x7), ": ")
+
+#endif
diff --git a/src/include/skalibs/surf.h b/src/include/skalibs/surf.h
new file mode 100644
index 0000000..6422903
--- /dev/null
+++ b/src/include/skalibs/surf.h
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#ifndef SKALIBS_SURF_H
+#define SKALIBS_SURF_H
+
+#include <skalibs/uint32.h>
+
+typedef struct SURFSchedule SURFSchedule, *SURFSchedule_ref, **SURFSchedule_ref_ref ;
+struct SURFSchedule
+{
+ uint32 seed[32] ;
+ uint32 in[12] ;
+ char out[32] ;
+ unsigned int pos ;
+} ;
+
+#define SURFSCHEDULE_ZERO { .seed = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .in = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .out = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", .pos = 32 }
+
+extern void surf_sinit (SURFSchedule_ref, char const *) ; /* 160 chars */
+extern void surf (SURFSchedule_ref, char *, unsigned int) ;
+
+
+ /* The following functions need libstdcrypto.a */
+
+extern void surf_makeseed (char *) ; /* fills 160 chars */
+extern void surf_init (SURFSchedule_ref) ;
+extern void surf_autoinit (SURFSchedule_ref, char *, unsigned int) ;
+
+#endif
diff --git a/src/include/skalibs/tai.h b/src/include/skalibs/tai.h
new file mode 100644
index 0000000..cce5670
--- /dev/null
+++ b/src/include/skalibs/tai.h
@@ -0,0 +1,140 @@
+/* ISC license. */
+
+#ifndef TAI_H
+#define TAI_H
+
+#include <sys/types.h>
+#include <time.h>
+#include <sys/time.h>
+#include <skalibs/gccattributes.h>
+#include <skalibs/uint32.h>
+#include <skalibs/uint64.h>
+
+typedef struct tai_s tai_t, *tai_t_ref ;
+struct tai_s
+{
+ uint64 x ;
+} ;
+
+
+#define TAI_ZERO { .x = 0 }
+#define TAI_MAGIC ((uint64)4611686018427387904ULL)
+#define TAI_EPOCH { .x = TAI_MAGIC + 10UL }
+#define TAI_INFINITE_RELATIVE { .x = ((uint64)1 << 60) }
+#define TAI_INFINITE { .x = TAI_MAGIC + ((uint64)1 << 61) }
+
+#define tai_sec(t) ((t)->x)
+#define tai_u64(t, u) ((void)((t)->x = (u)))
+#define tai_unix(t, u) tai_u64(t, (TAI_MAGIC + (u)))
+#define tai_uint(t, u) tai_u64(t, (uint64)(u))
+
+extern int tai_relative_from_timeval (tai_t *, struct timeval const *) ;
+extern int tai_from_timeval (tai_t *, struct timeval const *) ;
+extern int timeval_from_tai_relative (struct timeval *, tai_t const *) ;
+extern int timeval_from_tai (struct timeval *, tai_t const *) ;
+
+extern int tai_relative_from_timespec (tai_t *, struct timespec const *) ;
+extern int tai_from_timespec (tai_t *, struct timespec const *) ;
+extern int timespec_from_tai_relative (struct timespec *, tai_t const *) ;
+extern int timespec_from_tai (struct timespec *, tai_t const *) ;
+
+extern int tai_now (tai_t *) ;
+extern int tai_from_sysclock (tai_t *, uint64) ;
+extern int sysclock_from_tai (uint64 *, tai_t const *) ;
+
+#define tai_approx(t) ((double)(tai_sec(t)))
+
+extern void tai_add (tai_t *, tai_t const *, tai_t const *) ;
+extern void tai_sub (tai_t *, tai_t const *, tai_t const *) ;
+#define tai_less(t,u) (tai_sec(t) < tai_sec(u))
+
+#define TAI_PACK 8
+extern void tai_pack (char *, tai_t const *) ;
+extern void tai_unpack (char const *, tai_t *) ;
+extern void tai_pack_little (char *, tai_t const *) ;
+extern void tai_unpack_little (char const *, tai_t *) ;
+
+typedef struct tain_s tain_t, *tain_t_ref ;
+struct tain_s
+{
+ tai_t sec ;
+ uint32 nano ; /* 0..999999999U */
+} ;
+
+#define TAIN_ZERO { .sec = TAI_ZERO, .nano = 0 }
+#define TAIN_EPOCH { .sec = TAI_EPOCH, .nano = 0 }
+#define TAIN_INFINITE { .sec = TAI_INFINITE, .nano = 0 }
+#define TAIN_INFINITE_RELATIVE { .sec = TAI_INFINITE_RELATIVE, .nano = 0 }
+#define TAIN_NANO500 { .sec = TAI_ZERO, .nano = 500 }
+
+extern tain_t STAMP ; /* the global process wallclock */
+extern tain_t const tain_infinite_relative ;
+extern tain_t const tain_nano500 ;
+
+#define tain_sec(a) ((a)->sec)
+#define tain_secp(a) (&(a)->sec)
+#define tain_nano(a) ((a)->nano)
+
+extern int tain_relative_from_timeval (tain_t *, struct timeval const *) ;
+extern int tain_from_timeval (tain_t *, struct timeval const *) ;
+extern int timeval_from_tain_relative (struct timeval *, tain_t const *) ;
+extern int timeval_from_tain (struct timeval *, tain_t const *) ;
+
+extern int tain_relative_from_timespec (tain_t *, struct timespec const *) ;
+extern int tain_from_timespec (tain_t *, struct timespec const *) ;
+extern int timespec_from_tain_relative (struct timespec *, tain_t const *) ;
+extern int timespec_from_tain (struct timespec *, tain_t const *) ;
+
+extern int sysclock_get (tain_t *) ;
+extern int tain_sysclock (tain_t *) ;
+#define tain_sysclock_g() tain_sysclock(&STAMP)
+extern int tain_clockmon_init (tain_t *) ;
+extern int tain_clockmon (tain_t *, tain_t const *) ;
+#define tain_clockmon_g(offset) tain_clockmon(&STAMP, (offset))
+extern int tain_init (void) ;
+extern int tain_now (tain_t *) ;
+#define tain_now_g() tain_now(&STAMP)
+#define tain_copynow(t) (*(t) = STAMP)
+
+extern int sysclock_set (tain_t const *) ;
+extern int tain_setnow (tain_t const *) ;
+
+extern double tain_approx (tain_t const *) gccattr_pure ;
+extern double tain_frac (tain_t const *) gccattr_pure ;
+
+extern int tain_from_millisecs (tain_t *, int) ;
+extern int tain_to_millisecs (tain_t const *) gccattr_pure ;
+
+extern void tain_add (tain_t *, tain_t const *, tain_t const *) ;
+#define tain_add_g(deadline, tto) tain_add(deadline, &STAMP, tto)
+extern void tain_addsec (tain_t *, tain_t const *, int) ;
+#define tain_addsec_g(deadline, n) tain_addsec(deadline, &STAMP, n)
+extern void tain_sub (tain_t *, tain_t const *, tain_t const *) ;
+extern void tain_half (tain_t *, tain_t const *) ;
+extern int tain_less (tain_t const *, tain_t const *) gccattr_pure ;
+#define tain_future(deadline) tain_less(&STAMP, (deadline))
+
+#define TAIN_PACK 12
+extern void tain_pack (char *, tain_t const *) ;
+extern void tain_unpack (char const *, tain_t *) ;
+extern void tain_pack_little (char *, tain_t const *) ;
+extern void tain_unpack_little (char const *, tain_t *) ;
+
+#define TAIN_FMT 25
+extern unsigned int tain_fmt (char *, tain_t const *) ;
+extern unsigned int tain_scan (char const *, tain_t *) ;
+
+#define TAIN_FMTFRAC 19
+extern unsigned int tain_fmtfrac (char *, tain_t const *) ;
+
+#define tain_uint(a, u) tain_ulong(a, u)
+extern void tain_ulong (tain_t *, unsigned long) ;
+
+#define TIMESTAMP (1 + (TAIN_PACK << 1))
+extern unsigned int timestamp_fmt (char *, tain_t const *) ;
+extern unsigned int timestamp_scan (char const *, tain_t *) ;
+extern int timestamp_r (char *, tain_t *) ;
+extern int timestamp (char *) ;
+#define timestamp_g(s) timestamp_fmt((s), &STAMP)
+
+#endif
diff --git a/src/include/skalibs/unirandom.h b/src/include/skalibs/unirandom.h
new file mode 100644
index 0000000..fc87886
--- /dev/null
+++ b/src/include/skalibs/unirandom.h
@@ -0,0 +1,57 @@
+/* ISC license. */
+
+#ifndef UNIRANDOM_H
+#define UNIRANDOM_H
+
+#include <skalibs/buffer.h>
+#include <skalibs/surf.h>
+
+#define RANDOMBUF_BUFSIZE 257
+
+struct randombuf_s
+{
+ char buf[RANDOMBUF_BUFSIZE] ;
+ buffer b ;
+ unsigned int nb : 1 ;
+} ;
+#define RANDOMBUF_ZERO { .buf = "", .b = BUFFER_INIT(0, -1, 0, 0), .nb = 0 }
+
+struct randomegd_s
+{
+ int fd ;
+} ;
+
+union unirandominfo
+{
+ SURFSchedule surf_ctx ;
+ struct randombuf_s device ;
+ struct randomegd_s egd ;
+} ;
+
+#define UNIRANDOMINFO_ZERO { .surf_ctx = SURFSCHEDULE_ZERO }
+
+typedef struct unirandom unirandom, *unirandom_ref, **unirandom_ref_ref ;
+struct unirandom
+{
+ unsigned int (*readb) (union unirandominfo *, char *, unsigned int) ;
+ unsigned int (*readnb) (union unirandominfo *, char *, unsigned int) ;
+ int (*init) (union unirandominfo *) ;
+ int (*finish) (union unirandominfo *) ;
+ union unirandominfo data ;
+ unsigned int initted : 1 ;
+} ;
+
+#define UNIRANDOM_ZERO { .readb = 0, .readnb = 0, .init = 0, .finish = 0, .data = UNIRANDOMINFO_ZERO, .initted = 0 }
+
+extern int unirandom_register_devrandom (unirandom_ref) ;
+extern int unirandom_register_devurandom (unirandom_ref) ;
+extern int unirandom_register_hasegd (unirandom_ref) ;
+extern int unirandom_register_surf (unirandom_ref) ;
+
+extern int unirandom_init (unirandom_ref) ;
+extern unsigned int unirandom_readb (unirandom_ref, char *, unsigned int) ;
+extern unsigned int unirandom_readnb (unirandom_ref, char *, unsigned int) ;
+extern int unirandom_finish (unirandom_ref) ;
+
+
+#endif
diff --git a/src/include/skalibs/unirandomdev.h b/src/include/skalibs/unirandomdev.h
new file mode 100644
index 0000000..589a1c1
--- /dev/null
+++ b/src/include/skalibs/unirandomdev.h
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#ifndef UNIRANDOMDEV_H
+#define UNIRANDOMDEV_H
+
+#include <skalibs/unirandom.h>
+
+extern int unirandomdev_sinit (union unirandominfo *, char const *) ;
+extern unsigned int unirandomdev_readb (union unirandominfo *, char *, unsigned int) ;
+extern unsigned int unirandomdev_readnb (union unirandominfo *, char *, unsigned int) ;
+extern int unirandomdev_finish (union unirandominfo *) ;
+
+extern int unidevrandom_init (union unirandominfo *) ;
+extern int unidevurandom_init (union unirandominfo *) ;
+
+#define UNIRANDOM_REGISTER_DEVRANDOM() { .readb = &unirandomdev_readb, .readnb = &unirandomdev_readnb, .init = &unidevrandom_init, .finish = &unirandomdev_finish, .data = UNIRANDOMINFO_ZERO, .initted = 0 }
+#define UNIRANDOM_REGISTER_DEVURANDOM() { .readb = &unirandomdev_readb, .readnb = &unirandomdev_readnb, .init = &unidevurandom_init, .finish = &unirandomdev_finish, .data = UNIRANDOMINFO_ZERO, .initted = 0 }
+
+#endif
diff --git a/src/include/skalibs/unirandomegd.h b/src/include/skalibs/unirandomegd.h
new file mode 100644
index 0000000..11bb464
--- /dev/null
+++ b/src/include/skalibs/unirandomegd.h
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#ifndef UNIRANDOMEGD_H
+#define UNIRANDOMEGD_H
+
+#include <skalibs/unirandom.h>
+
+extern int unirandomegd_sinit (union unirandominfo *, char const *) ;
+extern unsigned int unirandomegd_readb (union unirandominfo *, char *, unsigned int) ;
+extern unsigned int unirandomegd_readnb (union unirandominfo *, char *, unsigned int) ;
+extern int unirandomegd_finish (union unirandominfo *) ;
+
+extern int unihasegd_init (union unirandominfo *) ;
+
+#define UNIRANDOM_REGISTER_HASEGD() { .readb = &unirandomegd_readb, .readnb = &unirandomegd_readnb, .init = &unihasegd_init, .finish = &unirandomegd_finish, .data = UNIRANDOMINFO_ZERO, .initted = 0 }
+
+#endif
diff --git a/src/include/skalibs/unisurf.h b/src/include/skalibs/unisurf.h
new file mode 100644
index 0000000..5c95c82
--- /dev/null
+++ b/src/include/skalibs/unisurf.h
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#ifndef UNISURF_H
+#define UNISURF_H
+
+#include <skalibs/unirandom.h>
+
+extern int unisurf_sinit (union unirandominfo *, char const *) ;
+extern unsigned int unisurf_read (union unirandominfo *, char *, unsigned int) ;
+extern int unisurf_finish (union unirandominfo *) ;
+
+extern int unisurf_init (union unirandominfo *) ;
+
+#define UNIRANDOM_REGISTER_SURF() { .readb = &unisurf_read, .readnb = &unisurf_read, .init = &unisurf_init, .finish = &unisurf_finish, .data = UNIRANDOMINFO_ZERO, .initted = 0 }
+
+#endif
diff --git a/src/include/skalibs/unix-timed.h b/src/include/skalibs/unix-timed.h
new file mode 100644
index 0000000..f5a25b6
--- /dev/null
+++ b/src/include/skalibs/unix-timed.h
@@ -0,0 +1,36 @@
+/* ISC license. */
+
+#ifndef UNIX_TIMED_H
+#define UNIX_TIMED_H
+
+#include <skalibs/bufalloc.h>
+#include <skalibs/buffer.h>
+#include <skalibs/functypes.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/tai.h>
+
+ /* Timed "blocking" operations (the fd must still be non-blocking) */
+
+
+extern int timed_flush (void *, initfunc_t_ref, initfunc_t_ref, initfunc_t_ref, tain_t const *, tain_t *) ;
+#define timed_flush_g(b, getfd, isnonempty, flush, deadline) timed_flush(b, getfd, isnonempty, flush, (deadline_), &STAMP)
+extern int timed_get (void *, initfunc_t_ref, initfunc_t_ref, tain_t const *, tain_t *) ;
+#define timed_get_g (b, getfd, get, deadline) timed_get(b, getfd, get, (deadline), &STAMP)
+
+extern int buffer_timed_fill (buffer *, tain_t const *, tain_t *) ;
+#define buffer_timed_fill_g(b, deadline) buffer_timed_fill(b, (deadline), &STAMP)
+extern int bufalloc_timed_flush (bufalloc *, tain_t const *, tain_t *) ;
+#define bufalloc_timed_flush_g(ba, deadline) bufalloc_timed_flush(ba, (deadline), &STAMP)
+extern int buffer_timed_flush (buffer *, tain_t const *, tain_t *) ;
+#define buffer_timed_flush_g(b, deadline) buffer_timed_flush(b, (deadline), &STAMP)
+extern unsigned int buffer_timed_get (buffer *, char *, unsigned int, tain_t const *, tain_t *) ;
+#define buffer_timed_get_g(b, buf, buflen, deadline) buffer_timed_get(b, buf, buflen, (deadline), &STAMP)
+
+extern int timed_getln (buffer_ref, stralloc *, char, tain_t const *, tain_t *) ;
+#define timed_getln_g(b, sa, sep, deadline) timed_getln(b, sa, sep, (deadline), &STAMP)
+extern int timed_getlnmax (buffer_ref, char *, unsigned int, unsigned int *, char, tain_t const *, tain_t *) ;
+#define timed_getlnmax_g(b, max, maxlen, len, sep, deadline) timed_getlnmax(b, max, maxlen, len, sep, (deadline), &STAMP)
+extern int netstring_timed_get (buffer *, stralloc *, tain_t const *, tain_t *) ;
+#define netstring_timed_get_g(b, sa, deadline) netstring_timed_get(b, sa, (deadline), &STAMP)
+
+#endif
diff --git a/src/include/skalibs/unix-transactional.h b/src/include/skalibs/unix-transactional.h
new file mode 100644
index 0000000..e1545e0
--- /dev/null
+++ b/src/include/skalibs/unix-transactional.h
@@ -0,0 +1,59 @@
+/* ISC license. */
+
+#ifndef UNIX_TRANSACTIONAL_H
+#define UNIX_TRANSACTIONAL_H
+
+#include <skalibs/uint64.h>
+#include <skalibs/stralloc.h>
+
+ /* Transactional/reliable filesystem operations */
+
+extern int open2_at (int, char const *, int) ;
+extern int open3_at (int, char const *, int, unsigned int) ;
+
+extern int opengetlnclose (char const *, stralloc *, int) ;
+
+extern int open_readat (int, char const *) ;
+extern int open_readatb (int, char const *) ;
+extern int open_writeat (int, char const *) ;
+extern int open_writeatb (int, char const *) ;
+extern int open_truncat (int, char const *) ;
+extern int open_truncatb (int, char const *) ;
+extern int open_appendat (int, char const *) ;
+extern int open_appendatb (int, char const *) ;
+
+extern unsigned int openreadnclose_at (int, char const *, char *, unsigned int) ;
+extern int openslurpclose_at (int, char const *, stralloc *) ;
+extern int opengetlnclose_at (int, char const *, stralloc *, int) ;
+
+extern int openwritenclose (char const *, char const *, unsigned int) ;
+extern int openwritenclose_devino (char const *, char const *, unsigned int, uint64 *, uint64 *) ;
+extern int openwritenclose_tmp (char const *, char const *, unsigned int, stralloc *) ;
+extern int openwritenclose_devino_tmp (char const *, char const *, unsigned int, uint64 *, uint64 *, stralloc *) ;
+extern unsigned int openwritenclose_at (int, char const *, char const *, unsigned int) ;
+
+extern int mkdir_unique (stralloc *, char const *, unsigned int) ;
+
+typedef struct dirdescriptor_s dirdescriptor_t, *dirdescriptor_t_ref ;
+struct dirdescriptor_s
+{
+ int fd ;
+ char const *lnkfn ;
+ stralloc new ;
+} ;
+
+#define DIRDESCRIPTOR_ZERO { .fd = 0, .lnkfn = 0, .new = STRALLOC_ZERO }
+
+extern int dd_open_read (dirdescriptor_t_ref, char const *) ;
+extern int dd_open_write (dirdescriptor_t_ref, char const *, unsigned int) ;
+extern int dd_close (dirdescriptor_t_ref) ; /* after dd_open_read */
+extern void dd_cancel (dirdescriptor_t_ref) ; /* after dd_open_write */
+extern int dd_commit (dirdescriptor_t_ref) ; /* after dd_open_write */
+extern int dd_commit_devino (dirdescriptor_t_ref, uint64 *, uint64 *) ; /* after dd_open_write */
+
+#define dd_openreadnclose(blah, file, s, len) openreadnclose_at((blah)->fd, file, s, len)
+#define dd_openslurpclose(blah, file, sa) openslurpclose_at((blah)->fd, file, sa)
+#define dd_opengetlnclose(blah, file, sa, sep) opengetlnclose_at((blah)->fd, file, sa, sep)
+#define dd_openwritenclose(blah, file, s, len) openwritenclose_at((blah)->fd, file, s, len)
+
+#endif
diff --git a/src/include/skalibs/unixmessage.h b/src/include/skalibs/unixmessage.h
new file mode 100644
index 0000000..69d6717
--- /dev/null
+++ b/src/include/skalibs/unixmessage.h
@@ -0,0 +1,103 @@
+/* ISC license. */
+
+#ifndef UNIXMESSAGE_H
+#define UNIXMESSAGE_H
+
+#include <skalibs/buffer.h>
+#include <skalibs/cbuffer.h>
+#include <skalibs/gccattributes.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/siovec.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/tai.h>
+
+typedef struct unixmessage_s unixmessage_t, *unixmessage_t_ref ;
+struct unixmessage_s
+{
+ char *s ;
+ unsigned int len ;
+ int *fds ;
+ unsigned int nfds ;
+} ;
+#define UNIXMESSAGE_ZERO { .s = 0, .len = 0, .fds = 0, .nfds = 0 }
+extern unixmessage_t const unixmessage_zero ;
+
+typedef struct unixmessage_v_s unixmessage_v_t, *unixmessage_v_t_ref ;
+struct unixmessage_v_s
+{
+ siovec_t *v ;
+ unsigned int vlen ;
+ int *fds ;
+ unsigned int nfds ;
+} ;
+#define UNIXMESSAGE_V_ZERO { .v = 0, .vlen = 0, .fds = 0, .nfds = 0 }
+extern unixmessage_v_t const unixmessage_v_zero ;
+
+
+#define UNIXMESSAGE_BUFSIZE 2049
+#define UNIXMESSAGE_AUXBUFSIZE 2049
+#define UNIXMESSAGE_MAXFDS 256
+#define UNIXMESSAGE_MAXREADS 32
+
+typedef struct unixmessage_sender_s unixmessage_sender_t, *unixmessage_sender_t_ref ;
+struct unixmessage_sender_s
+{
+ int fd ;
+ stralloc data ;
+ genalloc fds ; /* int */
+ genalloc offsets ; /* diuint */
+ unsigned int head ;
+} ;
+#define UNIXMESSAGE_SENDER_ZERO UNIXMESSAGE_SENDER_INIT(-1)
+#define UNIXMESSAGE_SENDER_INIT(s) { .fd = (s), .data = STRALLOC_ZERO, .fds = GENALLOC_ZERO, .offsets = GENALLOC_ZERO, .head = 0 }
+
+extern unixmessage_sender_t const unixmessage_sender_zero ;
+extern void unixmessage_sender_init (unixmessage_sender_t *, int) ;
+extern void unixmessage_sender_free (unixmessage_sender_t *) ;
+#define unixmessage_sender_fd(b) ((b)->fd)
+extern int unixmessage_sender_getfd (unixmessage_sender_t const *) gccattr_pure ;
+
+extern int unixmessage_put_and_close (unixmessage_sender_t *, unixmessage_t const *, unsigned char const *) ;
+#define unixmessage_put(b, m) unixmessage_put_and_close(b, m, unixmessage_bits_closenone)
+extern int unixmessage_putv_and_close (unixmessage_sender_t *, unixmessage_v_t const *, unsigned char const *) ;
+#define unixmessage_putv(b, m) unixmessage_putv_and_close(b, m, unixmessage_bits_closenone)
+
+extern unsigned char const *const unixmessage_bits_closenone ;
+extern unsigned char const *const unixmessage_bits_closeall ;
+
+extern int unixmessage_sender_flush (unixmessage_sender_t *) ;
+extern int unixmessage_sender_timed_flush (unixmessage_sender_t *, tain_t const *, tain_t *) ;
+#define unixmessage_sender_timed_flush_g(sender, deadline) unixmessage_sender_timed_flush(sender, (deadline), &STAMP)
+
+
+typedef struct unixmessage_receiver_s unixmessage_receiver_t, *unixmessage_receiver_t_ref ;
+struct unixmessage_receiver_s
+{
+ buffer mainb ;
+ cbuffer_t auxb ;
+ unsigned int mainlen ;
+ unsigned int auxlen ;
+ stralloc data ;
+ int fds[UNIXMESSAGE_MAXFDS] ;
+ unsigned int auxw ;
+} ;
+#define UNIXMESSAGE_RECEIVER_ZERO { .mainb = BUFFER_ZERO, .auxb = CBUFFER_ZERO, .mainlen = 0, .auxlen = 0, .data = STRALLOC_ZERO, .fds = { -1 }, .auxw = 0 }
+
+extern int unixmessage_receiver_init (unixmessage_receiver_t *, int, char *, unsigned int, char *, unsigned int) ;
+extern void unixmessage_receiver_free (unixmessage_receiver_t *) ;
+#define unixmessage_receiver_fd(b) buffer_fd(&(b)->mainb)
+
+extern int unixmessage_receive (unixmessage_receiver_t *, unixmessage_t *) ;
+extern int unixmessage_timed_receive (unixmessage_receiver_t *, unixmessage_t *, tain_t const *, tain_t *) ;
+#define unixmessage_timed_receive_g(receiver, msg, deadline) unixmessage_timed_receive(receiver, msg, (deadline), &STAMP)
+
+extern buffer_io_func_t unixmessage_read ;
+
+typedef int unixmessage_handler_func_t (unixmessage_t const *, void *) ;
+typedef unixmessage_handler_func_t *unixmessage_handler_func_t_ref ;
+
+extern int unixmessage_handle (unixmessage_receiver_t *, unixmessage_handler_func_t *, void *) ;
+extern int unixmessage_timed_handle (unixmessage_receiver_t *, unixmessage_handler_func_t *, void *, tain_t const *, tain_t *) ;
+#define unixmessage_timed_handle_g(b, f, p, deadline) unixmessage_timed_handle(b, f, p, (deadline), &STAMP)
+
+#endif
diff --git a/src/include/skalibs/unixonacid.h b/src/include/skalibs/unixonacid.h
new file mode 100644
index 0000000..a150e39
--- /dev/null
+++ b/src/include/skalibs/unixonacid.h
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#ifndef UNIXONACID_H
+#define UNIXONACID_H
+
+#include <skalibs/unix-transactional.h>
+#include <skalibs/unix-timed.h>
+#include <skalibs/unixmessage.h>
+#include <skalibs/kolbak.h>
+#include <skalibs/skaclient.h>
+
+#endif
diff --git a/src/include/skalibs/webipc.h b/src/include/skalibs/webipc.h
new file mode 100644
index 0000000..6b2c1fe
--- /dev/null
+++ b/src/include/skalibs/webipc.h
@@ -0,0 +1,60 @@
+/* ISC license. */
+
+#ifndef WEBIPC_H
+#define WEBIPC_H
+
+ /*
+ UNIX domain socket functions.
+ "web" stands for William E. Baxter, the original author, who kindly
+ permitted me to modify and release his code as a part of skalibs.
+ It has nothing to do with the World Wide Web.
+ */
+
+#define IPCPATH_MAX 107
+
+#include <skalibs/tai.h>
+#include <skalibs/djbunix.h>
+
+#define ipc_stream() ipc_stream_nb()
+#define ipc_stream_b() ipc_stream_internal(0)
+#define ipc_stream_nb() ipc_stream_internal(DJBUNIX_FLAG_NB)
+#define ipc_stream_coe() ipc_stream_internal(DJBUNIX_FLAG_COE)
+#define ipc_stream_nbcoe() ipc_stream_internal(DJBUNIX_FLAG_NB|DJBUNIX_FLAG_COE)
+extern int ipc_stream_internal (unsigned int) ;
+
+#define ipc_datagram() ipc_datagram_nb()
+#define ipc_datagram_b() ipc_datagram_internal(0)
+#define ipc_datagram_nb() ipc_datagram_internal(DJBUNIX_FLAG_NB)
+#define ipc_datagram_coe() ipc_datagram_internal(DJBUNIX_FLAG_COE)
+#define ipc_datagram_nbcoe() ipc_datagram_internal(DJBUNIX_FLAG_NB|DJBUNIX_FLAG_COE)
+extern int ipc_datagram_internal (unsigned int) ;
+
+#define ipc_pair(sv) ipc_pair_nb(sv)
+#define ipc_pair_b(sv) ipc_pair_internal((sv), 0)
+#define ipc_pair_nb(sv) ipc_pair_internal((sv), DJBUNIX_FLAG_NB)
+#define ipc_pair_coe(sv) ipc_pair_internal((sv), DJBUNIX_FLAG_COE)
+#define ipc_pair_nbcoe(sv) ipc_pair_internal((sv), DJBUNIX_FLAG_NB|DJBUNIX_FLAG_COE)
+extern int ipc_pair_internal (int *, unsigned int) ;
+
+extern int ipc_bind (int, char const *) ;
+extern int ipc_bind_reuse (int, char const *) ;
+extern int ipc_listen (int, int) ;
+
+#define ipc_accept(s, path, len, trunc) ipc_accept_internal(s, path, len, (trunc), 0)
+#define ipc_accept_nb(s, path, len, trunc) ipc_accept_internal(s, path, len, (trunc), DJBUNIX_FLAG_NB)
+#define ipc_accept_coe(s, path, len, trunc) ipc_accept_internal(s, path, len, (trunc), DJBUNIX_FLAG_COE)
+#define ipc_accept_nbcoe(s, path, len, trunc) ipc_accept_internal(s, path, len, (trunc), DJBUNIX_FLAG_NB|DJBUNIX_FLAG_COE)
+extern int ipc_accept_internal (int, char *, unsigned int, int *, unsigned int) ;
+
+extern int ipc_eid (int, unsigned int *, unsigned int *) ;
+extern int ipc_local (int, char *, unsigned int, int *) ;
+
+extern int ipc_connect (int, char const *) ;
+extern int ipc_connected (int) ;
+extern int ipc_timed_connect (int, char const *, tain_t const *, tain_t *) ;
+#define ipc_timed_connect_g(fd, path, deadline) ipc_timed_connect(fd, path, (deadline), &STAMP)
+
+extern int ipc_send (int, char const *, unsigned int, char const *) ;
+extern int ipc_recv (int, char *, unsigned int, char *) ;
+
+#endif
diff --git a/src/libbiguint/bu_addc.c b/src/libbiguint/bu_addc.c
new file mode 100644
index 0000000..0a57531
--- /dev/null
+++ b/src/libbiguint/bu_addc.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+/* OpenBSD needs that for EOVERFLOW. wtfbsdseriously */
+#define _BSD_SOURCE
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_addc (uint32 *c, unsigned int cn, uint32 const *a, unsigned int an, uint32 const *b, unsigned int bn, register int carry)
+{
+ register unsigned int i = 0 ;
+ for (; i < cn ; i++)
+ {
+ register uint32 ai = (i < an) ? a[i] : 0 ;
+ register uint32 bi = (i < bn) ? b[i] : 0 ;
+ register uint32 ci = ai + bi + carry ;
+ carry = (carry || bi) && (ci < ai) ;
+ c[i] = ci ;
+ }
+ return carry ? (errno = EOVERFLOW, 0) : 1 ;
+}
diff --git a/src/libbiguint/bu_addmod.c b/src/libbiguint/bu_addmod.c
new file mode 100644
index 0000000..c997897
--- /dev/null
+++ b/src/libbiguint/bu_addmod.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_addmod (uint32 *c, unsigned int cn, uint32 const *a, unsigned int an, uint32 const *b, unsigned int bn, uint32 const *m, unsigned int mn)
+{
+ if (!bu_add(c, cn, a, an, b, bn)) return 0 ;
+ if (bu_cmp(c, cn, m, mn) >= 0) bu_sub(c, cn, c, cn, m, mn) ;
+ return 1 ;
+}
diff --git a/src/libbiguint/bu_cmp.c b/src/libbiguint/bu_cmp.c
new file mode 100644
index 0000000..a6bfaeb
--- /dev/null
+++ b/src/libbiguint/bu_cmp.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_cmp (register uint32 const *a, register unsigned int an, register uint32 const *b, register unsigned int bn)
+{
+ an = bu_len(a, an) ;
+ bn = bu_len(b, bn) ;
+ if (an < bn) return -1 ;
+ if (an > bn) return 1 ;
+ while (bn--)
+ {
+ if (a[bn] < b[bn]) return -1 ;
+ if (a[bn] > b[bn]) return 1 ;
+ }
+ return 0 ;
+}
diff --git a/src/libbiguint/bu_copy.c b/src/libbiguint/bu_copy.c
new file mode 100644
index 0000000..1358aca
--- /dev/null
+++ b/src/libbiguint/bu_copy.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+/* OpenBSD needs that for EOVERFLOW. wtfbsdseriously */
+#define _BSD_SOURCE
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_copy (uint32 *b, unsigned int bn, uint32 const *a, unsigned int an)
+{
+ register unsigned int alen = bu_len(a, an) ;
+ if (bn < alen)
+ {
+ bu_copy_internal(b, a, bn) ;
+ return (errno = EOVERFLOW, 0) ;
+ }
+ bu_copy_internal(b, a, alen) ;
+ bu_zero(b + alen, bn - alen) ;
+ return 1 ;
+}
diff --git a/src/libbiguint/bu_copy_internal.c b/src/libbiguint/bu_copy_internal.c
new file mode 100644
index 0000000..919929b
--- /dev/null
+++ b/src/libbiguint/bu_copy_internal.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+void bu_copy_internal (register uint32 *b, register uint32 const *a, register unsigned int n)
+{
+ while (n--) b[n] = a[n] ;
+}
diff --git a/src/libbiguint/bu_div.c b/src/libbiguint/bu_div.c
new file mode 100644
index 0000000..c7718e2
--- /dev/null
+++ b/src/libbiguint/bu_div.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_div (uint32 const *a, unsigned int an, uint32 const *b, unsigned int bn, uint32 *q, unsigned int qn, uint32 *r, unsigned int rn)
+{
+ unsigned int alen = bu_len(a, an) ;
+ unsigned int blen = bu_len(b, bn) ;
+ if (!blen) return (errno = EDOM, 0) ;
+ else
+ {
+ uint32 qq[alen] ;
+ uint32 rr[alen] ;
+ register int qh, rh ;
+ bu_copy_internal(rr, a, alen) ;
+ bu_div_internal(rr, alen, b, blen, qq, alen) ;
+ qh = bu_copy(q, qn, qq, alen) ;
+ rh = bu_copy(r, rn, rr, alen) ;
+ return qh && rh ;
+ }
+}
diff --git a/src/libbiguint/bu_div_internal.c b/src/libbiguint/bu_div_internal.c
new file mode 100644
index 0000000..d1be789
--- /dev/null
+++ b/src/libbiguint/bu_div_internal.c
@@ -0,0 +1,46 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+/*
+ q = a/b, a = a mod b. Assumes b != 0 and qn >= alen - blen + 1.
+*/
+
+void bu_div_internal (uint32 *a, unsigned int an, uint32 const *b, unsigned int bn, uint32 *q, unsigned int qn)
+{
+ unsigned int alen = bu_len(a, an) ;
+ unsigned int blen = bu_len(b, bn) ;
+ bu_zero(q, qn) ;
+ if (alen < blen) return ;
+ {
+ uint32 bb[alen + 1] ;
+ unsigned int i = 1 + ((alen - blen) << 5) ;
+ bu_zero(bb, alen - blen) ;
+ bu_copy_internal(bb + alen - blen, b, blen) ;
+ bb[alen] = 0 ;
+
+ while (bu_cmp(a, alen, bb, alen+1) >= 0)
+ {
+ bu_slb(bb + alen - blen, blen + 1) ;
+ i++ ;
+ }
+ while (i && (bu_cmp(a, alen, bb, alen+1) < 0))
+ {
+ bu_srb(bb, alen + 1) ;
+ i-- ;
+ }
+
+ while (i--)
+ {
+ bu_slb(q, alen - blen + 1) ;
+ if (bu_cmp(a, alen, bb, alen) >= 0)
+ {
+ bu_sub(a, alen, a, alen, bb, alen) ;
+ q[0] |= 1 ;
+ }
+ bu_srb(bb, alen) ;
+ }
+ }
+}
diff --git a/src/libbiguint/bu_divmod.c b/src/libbiguint/bu_divmod.c
new file mode 100644
index 0000000..5d5802f
--- /dev/null
+++ b/src/libbiguint/bu_divmod.c
@@ -0,0 +1,32 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+/*
+ q = y/x mod m.
+*/
+
+int bu_divmod (uint32 *q, unsigned int qn, uint32 const *y, unsigned int yn, uint32 const *x, unsigned int xn, uint32 const *m, unsigned int mn)
+{
+ unsigned int ylen = bu_len(y, yn) ;
+ unsigned int xlen = bu_len(x, xn) ;
+ unsigned int mlen = bu_len(m, mn) ;
+ unsigned int n = ylen ;
+ if (n < xlen) n = xlen ;
+ if (n < mlen) n = mlen ;
+ if (!n) return (errno = EDOM, 0) ;
+ {
+ uint32 yy[n] ;
+ uint32 xx[n] ;
+ uint32 mm[n] ;
+ bu_gcd(xx, n, x, xlen, m, mlen) ;
+ if ((xx[0] != 1) || (bu_len(xx, n) != 1)) return (errno = EDOM, 0) ;
+ bu_copy_internal(yy, y, ylen) ; bu_zero(yy+ylen, n-ylen) ;
+ bu_copy_internal(xx, x, xlen) ; bu_zero(xx+xlen, n-xlen) ;
+ bu_copy_internal(mm, m, mlen) ; bu_zero(mm+mlen, n-mlen) ;
+ bu_divmod_internal(yy, xx, mm, n) ;
+ return bu_copy(q, qn, yy, n) ;
+ }
+}
diff --git a/src/libbiguint/bu_divmod_internal.c b/src/libbiguint/bu_divmod_internal.c
new file mode 100644
index 0000000..46d3335
--- /dev/null
+++ b/src/libbiguint/bu_divmod_internal.c
@@ -0,0 +1,37 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+/*
+ u = u/a mod m. a and m must be relatively prime - otherwise, infinite loop.
+ a is not immutable.
+ Original idea: see http://research.sun.com/techrep/2001/abstract-95.html
+*/
+
+void bu_divmod_internal (register uint32 *u, register uint32 *a, register uint32 const *m, unsigned int n)
+{
+ uint32 bb[n] ; register uint32 *b = bb ;
+ uint32 vv[n] ; register uint32 *v = vv ;
+ bu_copy_internal(b, m, n) ;
+ bu_zero(v, n) ;
+
+ /*** XXX: this iterates like mad, should probably be optimized more */
+ for (;;)
+ {
+ while (!(a[0] & 1))
+ {
+ bu_srb(a, n) ;
+ if (u[0] & 1) bu_add(u, n, u, n, m, n) ;
+ bu_srb(u, n) ;
+ }
+ if ((a[0] == 1) && (bu_len(a, n) == 1)) break ;
+ if (bu_cmp(a, n, b, n) < 0)
+ {
+ register uint32 *t = a ; a = b ; b = t ;
+ t = u ; u = v ; v = t ;
+ }
+ bu_add(a, n, a, n, b, n) ;
+ bu_add(u, n, u, n, v, n) ;
+ }
+}
diff --git a/src/libbiguint/bu_fmt.c b/src/libbiguint/bu_fmt.c
new file mode 100644
index 0000000..31fa706
--- /dev/null
+++ b/src/libbiguint/bu_fmt.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/biguint.h>
+
+unsigned int bu_fmt (char *s, uint32 const *x, unsigned int n)
+{
+ unsigned int len = 0 ;
+ while (n--)
+ {
+ char fmt[8] ;
+ unsigned int i = uint32_xfmt(fmt, x[n]) ;
+ byte_copy(s+len, 8-i, "00000000") ;
+ byte_copy(s+len+8-i, i, fmt) ;
+ len += 8 ;
+ }
+ return len ;
+}
diff --git a/src/libbiguint/bu_gcd.c b/src/libbiguint/bu_gcd.c
new file mode 100644
index 0000000..d6c5791
--- /dev/null
+++ b/src/libbiguint/bu_gcd.c
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_gcd (uint32 *r, unsigned int rn, uint32 const *a, unsigned int an, uint32 const *b, unsigned int bn)
+{
+ if (bu_cmp(a, an, b, bn) < 0)
+ {
+ register uint32 const *t = a ;
+ register unsigned int tn = an ;
+ a = b ; an = bn ;
+ b = t ; bn = tn ;
+ }
+ {
+ uint32 trash[an] ;
+ uint32 aa[an] ;
+ uint32 bb[an] ;
+ uint32 *aaa = aa, *bbb = bb ;
+ bu_copy_internal(aa, a, an) ;
+ bu_copy_internal(bb, b, bn) ;
+ bu_zero(bb+bn, an-bn) ;
+
+ while (bu_len(bbb, an))
+ {
+ register uint32 *ttt = aaa ;
+ bu_div_internal(aaa, an, bbb, an, trash, an) ;
+ aaa = bbb ;
+ bbb = ttt ;
+ }
+ return bu_copy(r, rn, aaa, an) ;
+ }
+}
diff --git a/src/libbiguint/bu_invmod.c b/src/libbiguint/bu_invmod.c
new file mode 100644
index 0000000..ff209e7
--- /dev/null
+++ b/src/libbiguint/bu_invmod.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+/* x^-1 mod m. */
+
+int bu_invmod (uint32 *x, unsigned int xn, uint32 const *m, unsigned int mn)
+{
+ uint32 const one = 1 ;
+ return bu_divmod(x, xn, &one, 1, x, xn, m, mn) ;
+}
diff --git a/src/libbiguint/bu_len.c b/src/libbiguint/bu_len.c
new file mode 100644
index 0000000..0f6ec10
--- /dev/null
+++ b/src/libbiguint/bu_len.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+unsigned int bu_len (register uint32 const *a, register unsigned int n)
+{
+ while (n--) if (a[n]) return n+1 ;
+ return 0 ;
+}
diff --git a/src/libbiguint/bu_mod.c b/src/libbiguint/bu_mod.c
new file mode 100644
index 0000000..2050320
--- /dev/null
+++ b/src/libbiguint/bu_mod.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_mod (uint32 *a, unsigned int an, uint32 const *b, unsigned int bn)
+{
+ uint32 q[an] ;
+ return bu_div(a, an, b, bn, q, an, a, an) ;
+}
diff --git a/src/libbiguint/bu_mul.c b/src/libbiguint/bu_mul.c
new file mode 100644
index 0000000..184d652
--- /dev/null
+++ b/src/libbiguint/bu_mul.c
@@ -0,0 +1,32 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/uint64.h>
+#include <skalibs/biguint.h>
+
+ /* No Karatsuba. Keep it simple, stupid. */
+
+int bu_mul (uint32 *x, unsigned int xn, uint32 const *a, unsigned int an, uint32 const *b, unsigned int bn)
+{
+ unsigned int alen = bu_len(a, an) ;
+ unsigned int blen = bu_len(b, bn) ;
+ uint32 c[alen + blen] ;
+ register unsigned int i = 0 ;
+ bu_zero(c, alen + blen) ;
+ for (; i < alen ; i++)
+ {
+ register uint32 carry = 0 ;
+ register unsigned int j = 0 ;
+ for (; j < blen ; j++)
+ {
+ register uint64 t = a[i] ;
+ t *= b[j] ;
+ t += c[i+j] ;
+ t += carry ;
+ c[i+j] = (uint32)t ;
+ carry = (uint32)(t >> 32) ;
+ }
+ c[i+j] += carry ;
+ }
+ return bu_copy(x, xn, c, alen+blen) ;
+}
diff --git a/src/libbiguint/bu_mulmod.c b/src/libbiguint/bu_mulmod.c
new file mode 100644
index 0000000..18e5a1c
--- /dev/null
+++ b/src/libbiguint/bu_mulmod.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+ /* Nope, no Montgomery either. */
+
+int bu_mulmod (uint32 *c, unsigned int cn, uint32 const *a, unsigned int an, uint32 const *b, unsigned int bn, uint32 const *m, unsigned int mn)
+{
+ unsigned int alen = bu_len(a, an) ;
+ unsigned int blen = bu_len(b, bn) ;
+ uint32 x[alen+blen] ;
+ if (!bu_mul(x, alen+blen, a, alen, b, blen)) return 0 ;
+ if (!bu_mod(x, alen+blen, m, mn)) return 0 ;
+ return bu_copy(c, cn, x, mn) ;
+}
diff --git a/src/libbiguint/bu_pack.c b/src/libbiguint/bu_pack.c
new file mode 100644
index 0000000..0145b9f
--- /dev/null
+++ b/src/libbiguint/bu_pack.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+void bu_pack (char *s, uint32 const *a, register unsigned int n)
+{
+ while (n--) uint32_pack(s + (n<<2), a[n]) ;
+}
diff --git a/src/libbiguint/bu_pack_big.c b/src/libbiguint/bu_pack_big.c
new file mode 100644
index 0000000..8340fd7
--- /dev/null
+++ b/src/libbiguint/bu_pack_big.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+void bu_pack_big (char *s, uint32 const *a, unsigned int n)
+{
+ register unsigned int i = 0 ;
+ for (; i < n ; i++) uint32_pack_big(s + (i<<2), a[n-1-i]) ;
+}
diff --git a/src/libbiguint/bu_scan.c b/src/libbiguint/bu_scan.c
new file mode 100644
index 0000000..a34ed99
--- /dev/null
+++ b/src/libbiguint/bu_scan.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+/* OpenBSD needs that for EOVERFLOW. wtfbsdseriously */
+#define _BSD_SOURCE
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/bitarray.h>
+#include <skalibs/biguint.h>
+
+int bu_scan (char const *s, unsigned int len, uint32 *x, unsigned int xn, unsigned int zeron)
+{
+ register unsigned int n = bitarray_div8(zeron) ;
+ if (xn < n) return (errno = EOVERFLOW, 0) ;
+ bu_scan_internal(s, len, x) ;
+ bu_zero(x + n, xn - n) ;
+ return 1 ;
+}
diff --git a/src/libbiguint/bu_scan_internal.c b/src/libbiguint/bu_scan_internal.c
new file mode 100644
index 0000000..696880a
--- /dev/null
+++ b/src/libbiguint/bu_scan_internal.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/biguint.h>
+
+void bu_scan_internal (char const *s, unsigned int len, uint32 *x)
+{
+ char fmt[9] = "\0\0\0\0\0\0\0\0" ;
+ unsigned int i = 0 ;
+ if (len & 7)
+ {
+ byte_copy(fmt, len & 7, s) ;
+ uint32_xscan(fmt, x + (len >> 3)) ;
+ }
+ for (; i < (len >> 3) ; i++)
+ {
+ byte_copy(fmt, 8, s + len - 8 - (i << 3)) ;
+ uint32_xscan(fmt, x + i) ;
+ }
+}
diff --git a/src/libbiguint/bu_scanlen.c b/src/libbiguint/bu_scanlen.c
new file mode 100644
index 0000000..88c6aee
--- /dev/null
+++ b/src/libbiguint/bu_scanlen.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/fmtscan.h>
+#include <skalibs/biguint.h>
+
+unsigned int bu_scanlen (char const *s, unsigned int *zeron)
+{
+ unsigned int n = ucharn_findlen(s) ;
+ *zeron = n ;
+ while (*s == '0') { s++ ; (*zeron)-- ; }
+ return n ;
+}
diff --git a/src/libbiguint/bu_slbc.c b/src/libbiguint/bu_slbc.c
new file mode 100644
index 0000000..081c599
--- /dev/null
+++ b/src/libbiguint/bu_slbc.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_slbc (register uint32 *a, register unsigned int n, register int carry)
+{
+ register unsigned int i = 0 ;
+ carry = !!carry ;
+ for (; i < n ; i++)
+ {
+ register int c = a[i] >> 31 ;
+ a[i] = (a[i] << 1) | carry ;
+ carry = c ;
+ }
+ return carry ;
+}
diff --git a/src/libbiguint/bu_srbc.c b/src/libbiguint/bu_srbc.c
new file mode 100644
index 0000000..87196b1
--- /dev/null
+++ b/src/libbiguint/bu_srbc.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_srbc (register uint32 *a, register unsigned int n, register int carry)
+{
+ while (n--)
+ {
+ register int c = a[n] & 1 ;
+ a[n] = (a[n] >> 1) | (carry ? 0x80000000UL : 0) ;
+ carry = c ;
+ }
+ return carry ;
+}
diff --git a/src/libbiguint/bu_subc.c b/src/libbiguint/bu_subc.c
new file mode 100644
index 0000000..c26adca
--- /dev/null
+++ b/src/libbiguint/bu_subc.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+/* OpenBSD needs that for EOVERFLOW. wtfbsdseriously */
+#define _BSD_SOURCE
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_subc (uint32 *c, unsigned int cn, uint32 const *a, unsigned int an, uint32 const *b, unsigned int bn, register int carry)
+{
+ register unsigned int i = 0 ;
+ for (; i < cn ; i++)
+ {
+ register uint32 ai = (i < an) ? a[i] : 0 ;
+ register uint32 bi = (i < bn) ? b[i] : 0 ;
+ register uint32 ci = ai - bi - carry ;
+ carry = (carry || bi) && (ci > ai) ;
+ c[i] = ci ;
+ }
+ return carry ? (errno = EOVERFLOW, 0) : 1 ;
+}
diff --git a/src/libbiguint/bu_submod.c b/src/libbiguint/bu_submod.c
new file mode 100644
index 0000000..f988a50
--- /dev/null
+++ b/src/libbiguint/bu_submod.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_submod (uint32 *c, unsigned int cn, uint32 const *a, unsigned int an, uint32 const *b, unsigned int bn, uint32 const *m, unsigned int mn)
+{
+ if (!bu_sub(c, cn, a, an, b, bn) && bu_add(c, cn, c, cn, m, mn))
+ return (errno = EDOM, 0) ;
+ return (errno = 0, 1) ;
+}
diff --git a/src/libbiguint/bu_unpack.c b/src/libbiguint/bu_unpack.c
new file mode 100644
index 0000000..d4f4130
--- /dev/null
+++ b/src/libbiguint/bu_unpack.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+void bu_unpack (char const *s, uint32 *a, register unsigned int n)
+{
+ while (n--) uint32_unpack(s + (n<<2), a + n) ;
+}
diff --git a/src/libbiguint/bu_unpack_big.c b/src/libbiguint/bu_unpack_big.c
new file mode 100644
index 0000000..ef79029
--- /dev/null
+++ b/src/libbiguint/bu_unpack_big.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+void bu_unpack_big (char const *s, uint32 *a, unsigned int n)
+{
+ register unsigned int i = 0 ;
+ for (; i < n ; i++) uint32_unpack_big(s + (i<<2), a + n - 1 - i) ;
+}
diff --git a/src/libbiguint/bu_zero.c b/src/libbiguint/bu_zero.c
new file mode 100644
index 0000000..07efd69
--- /dev/null
+++ b/src/libbiguint/bu_zero.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+void bu_zero (register uint32 *z, register unsigned int n)
+{
+ while (n--) z[n] = 0 ;
+}
diff --git a/src/libdatastruct/avlnode-internal.h b/src/libdatastruct/avlnode-internal.h
new file mode 100644
index 0000000..0342695
--- /dev/null
+++ b/src/libdatastruct/avlnode-internal.h
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#ifndef AVLNODE_INTERNAL_H
+#define AVLNODE_INTERNAL_H
+
+#include <skalibs/avlnode.h>
+
+#define avlnode_ufroms(c) ((c) > 0)
+#define avlnode_sfromu(h) ((h) ? 1 : -1)
+
+extern unsigned int avlnode_rotate (avlnode_ref, unsigned int, unsigned int, int) ;
+extern unsigned int avlnode_doublerotate (avlnode_ref, unsigned int, unsigned int, int) ;
+#define avlnode_rotate_maydouble(s, max, r, h, isdouble) ((isdouble) ? avlnode_doublerotate(s, max, r, h) : avlnode_rotate(s, max, r, h))
+
+#endif
diff --git a/src/libdatastruct/avlnode_delete.c b/src/libdatastruct/avlnode_delete.c
new file mode 100644
index 0000000..b0f9dd0
--- /dev/null
+++ b/src/libdatastruct/avlnode_delete.c
@@ -0,0 +1,72 @@
+/* ISC license. */
+
+#include <skalibs/functypes.h>
+#include <skalibs/avlnode.h>
+#include "avlnode-internal.h"
+
+unsigned int avlnode_delete (avlnode_ref s, unsigned int max, unsigned int *root, void const *k, dtokfunc_t_ref dtok, cmpfunc_t_ref f, void *p)
+{
+ unsigned int stack[AVLNODE_MAXDEPTH] ;
+ int spin[AVLNODE_MAXDEPTH] ;
+ unsigned int sp = 0 ;
+ unsigned int r = *root ;
+ unsigned int itodel ;
+
+ for (; r < max ; sp++)
+ {
+ register int c = (*f)(k, (*dtok)(s[r].data, p), p) ;
+ if (!c) break ;
+ spin[sp] = avlnode_ufroms(c) ;
+ stack[sp] = r ;
+ r = s[r].child[spin[sp]] ;
+ }
+ if (r >= max) return max ;
+ itodel = r ;
+
+ if ((s[r].child[0] < max) || (s[r].child[1] < max))
+ {
+ int subspin = s[r].child[1] < max ;
+ stack[sp] = r ;
+ spin[sp++] = subspin ;
+ r = s[r].child[subspin] ;
+ for (; r < max ; sp++)
+ {
+ stack[sp] = r ;
+ spin[sp] = !subspin ;
+ r = s[r].child[!subspin] ;
+ }
+ r = stack[--sp] ;
+ s[itodel].data = s[r].data ;
+ itodel = s[r].child[subspin] ;
+ if (itodel < max)
+ {
+ s[r].data = s[itodel].data ;
+ stack[sp] = r ;
+ spin[sp++] = subspin ;
+ }
+ else itodel = r ;
+ }
+
+ r = max ;
+ while (sp--)
+ {
+ s[stack[sp]].child[spin[sp]] = r ;
+ r = stack[sp] ;
+ if (!s[r].balance) goto easyfix ;
+ else if (spin[sp] == avlnode_ufroms(s[r].balance)) s[r].balance = 0 ;
+ else if (!s[s[r].child[!spin[sp]]].balance) goto hardfix ;
+ else r = avlnode_rotate_maydouble(s, max, r, spin[sp], spin[sp] == avlnode_ufroms(s[s[r].child[!spin[sp]]].balance)) ;
+ }
+ *root = r ;
+ return itodel ;
+
+ easyfix:
+ s[r].balance = -avlnode_sfromu(spin[sp]) ;
+ return itodel ;
+
+ hardfix:
+ r = avlnode_rotate(s, max, r, spin[sp]) ;
+ if (!sp--) *root = r ;
+ else s[stack[sp]].child[spin[sp]] = r ;
+ return itodel ;
+}
diff --git a/src/libdatastruct/avlnode_doublerotate.c b/src/libdatastruct/avlnode_doublerotate.c
new file mode 100644
index 0000000..da1f31b
--- /dev/null
+++ b/src/libdatastruct/avlnode_doublerotate.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <skalibs/avlnode.h>
+#include "avlnode-internal.h"
+
+unsigned int avlnode_doublerotate (avlnode_ref s, unsigned int max, unsigned int i, int h)
+{
+ register unsigned int j = s[i].child[!h] ;
+ register unsigned int k = s[j].child[h] ;
+ s[i].child[!h] = s[k].child[h] ;
+ s[j].child[h] = s[k].child[!h] ;
+ s[k].child[!h] = j ;
+ s[k].child[h] = i ;
+ s[h ? i : j].balance = (s[k].balance < 0) ;
+ s[h ? j : i].balance = -(s[k].balance > 0) ;
+ s[k].balance = 0 ;
+ (void)max ;
+ return k ;
+}
diff --git a/src/libdatastruct/avlnode_extreme.c b/src/libdatastruct/avlnode_extreme.c
new file mode 100644
index 0000000..42d991d
--- /dev/null
+++ b/src/libdatastruct/avlnode_extreme.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/avlnode.h>
+
+int avlnode_extreme (avlnode const *s, unsigned int max, unsigned int r, int h, unsigned int *k)
+{
+ register unsigned int i = avlnode_extremenode(s, max, r, h) ;
+ if (i >= max) return (errno = ESRCH, 0) ;
+ *k = s[i].data ;
+ return 1 ;
+}
diff --git a/src/libdatastruct/avlnode_extremenode.c b/src/libdatastruct/avlnode_extremenode.c
new file mode 100644
index 0000000..57a8e59
--- /dev/null
+++ b/src/libdatastruct/avlnode_extremenode.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/avlnode.h>
+
+unsigned int avlnode_extremenode (avlnode const *s, unsigned int max, unsigned int r, int h)
+{
+ register unsigned int oldr = r ;
+ for (; r < max ; oldr = r, r = s[r].child[h]) ;
+ return oldr ;
+}
diff --git a/src/libdatastruct/avlnode_height.c b/src/libdatastruct/avlnode_height.c
new file mode 100644
index 0000000..e78448e
--- /dev/null
+++ b/src/libdatastruct/avlnode_height.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/avlnode.h>
+
+unsigned int avlnode_height (avlnode const *s, unsigned int max, unsigned int r)
+{
+ if (r >= max) return 0 ;
+ else if (s[r].balance) return 1 + avlnode_height(s, max, s[r].child[s[r].balance > 0]) ;
+ else
+ {
+ unsigned int h1 = avlnode_height(s, max, s[r].child[0]) ;
+ unsigned int h2 = avlnode_height(s, max, s[r].child[1]) ;
+ return 1 + ((h1 > h2) ? h1 : h2) ;
+ }
+}
diff --git a/src/libdatastruct/avlnode_insertnode.c b/src/libdatastruct/avlnode_insertnode.c
new file mode 100644
index 0000000..c69b34e
--- /dev/null
+++ b/src/libdatastruct/avlnode_insertnode.c
@@ -0,0 +1,42 @@
+/* ISC license. */
+
+#include <skalibs/functypes.h>
+#include <skalibs/avlnode.h>
+#include "avlnode-internal.h"
+
+unsigned int avlnode_insertnode (avlnode_ref s, unsigned int max, unsigned int r, unsigned int i, dtokfunc_t_ref dtok, cmpfunc_t_ref f, void *p)
+{
+ unsigned int stack[AVLNODE_MAXDEPTH] ;
+ int spin[AVLNODE_MAXDEPTH] ;
+ unsigned int sp = 0 ;
+
+ {
+ register void const *k = (*dtok)(s[i].data, p) ;
+ for (; r < max ; sp++)
+ {
+ spin[sp] = avlnode_ufroms((*f)(k, (*dtok)(s[r].data, p), p)) ;
+ stack[sp] = r ;
+ r = s[r].child[spin[sp]] ;
+ }
+ }
+ r = i ;
+ while (sp--)
+ {
+ s[stack[sp]].child[spin[sp]] = r ;
+ r = stack[sp] ;
+ if (s[r].balance) goto lastfix ;
+ s[r].balance = avlnode_sfromu(spin[sp]) ;
+ }
+ return r ;
+
+ lastfix:
+ if (avlnode_ufroms(s[r].balance) != spin[sp])
+ {
+ s[r].balance = 0 ;
+ return stack[0] ;
+ }
+ r = avlnode_rotate_maydouble(s, max, r, !spin[sp], spin[sp] != spin[sp+1]) ;
+ if (!sp--) return r ;
+ s[stack[sp]].child[spin[sp]] = r ;
+ return stack[0] ;
+}
diff --git a/src/libdatastruct/avlnode_iter.c b/src/libdatastruct/avlnode_iter.c
new file mode 100644
index 0000000..9e1d698
--- /dev/null
+++ b/src/libdatastruct/avlnode_iter.c
@@ -0,0 +1,26 @@
+/* ISC license. */
+
+#include <skalibs/avlnode.h>
+
+struct avlnode_iter_s
+{
+ avlnode_ref s ;
+ unsigned int max ;
+ avliterfunc_t_ref f ;
+ void *p ;
+} ;
+
+static int avlnode_iter_rec (struct avlnode_iter_s const *blah, unsigned int r, unsigned int h)
+{
+ return (r < blah->max) ?
+ avlnode_iter_rec(blah, blah->s[r].child[0], h+1)
+ && (*blah->f)(blah->s[r].data, h, blah->p)
+ && avlnode_iter_rec(blah, blah->s[r].child[1], h+1)
+ : 1 ;
+}
+
+int avlnode_iter (avlnode_ref s, unsigned int max, unsigned int r, avliterfunc_t_ref f, void *p)
+{
+ struct avlnode_iter_s blah = { s, max, f, p } ;
+ return avlnode_iter_rec(&blah, r, 0) ;
+}
diff --git a/src/libdatastruct/avlnode_rotate.c b/src/libdatastruct/avlnode_rotate.c
new file mode 100644
index 0000000..fe06994
--- /dev/null
+++ b/src/libdatastruct/avlnode_rotate.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/avlnode.h>
+#include "avlnode-internal.h"
+
+unsigned int avlnode_rotate (avlnode_ref s, unsigned int max, unsigned int i, int h)
+{
+ register unsigned int j = s[i].child[!h] ;
+ s[i].child[!h] = s[j].child[h] ;
+ s[j].child[h] = i ;
+ if (s[j].balance * avlnode_sfromu(h) < 0) s[i].balance = s[j].balance = 0 ;
+ else s[j].balance = avlnode_sfromu(h) ;
+ (void)max ;
+ return j ;
+}
diff --git a/src/libdatastruct/avlnode_search.c b/src/libdatastruct/avlnode_search.c
new file mode 100644
index 0000000..e12b0a4
--- /dev/null
+++ b/src/libdatastruct/avlnode_search.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/avlnode.h>
+
+int avlnode_search (avlnode const *s, unsigned int max, unsigned int r, void const *k, unsigned int *data, dtokfunc_t_ref dtok, cmpfunc_t_ref f, void *p)
+{
+ register unsigned int i = avlnode_searchnode(s, max, r, k, dtok, f, p) ;
+ if (i >= max) return (errno = ESRCH, 0) ;
+ *data = s[i].data ;
+ return 1 ;
+}
diff --git a/src/libdatastruct/avlnode_searchnode.c b/src/libdatastruct/avlnode_searchnode.c
new file mode 100644
index 0000000..4ab015c
--- /dev/null
+++ b/src/libdatastruct/avlnode_searchnode.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <skalibs/functypes.h>
+#include <skalibs/avlnode.h>
+#include "avlnode-internal.h"
+
+unsigned int avlnode_searchnode (avlnode const *s, unsigned int max, unsigned int r, void const *k, dtokfunc_t_ref dtok, cmpfunc_t_ref f, void *p)
+{
+ while (r < max)
+ {
+ register int h = (*f)(k, (*dtok)(s[r].data, p), p) ;
+ if (!h) break ;
+ r = s[r].child[avlnode_ufroms(h)] ;
+ }
+ return r ;
+}
diff --git a/src/libdatastruct/avlnode_zero.c b/src/libdatastruct/avlnode_zero.c
new file mode 100644
index 0000000..caf4adb
--- /dev/null
+++ b/src/libdatastruct/avlnode_zero.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include <skalibs/avlnode.h>
+
+avlnode const avlnode_zero = AVLNODE_ZERO ;
diff --git a/src/libdatastruct/avltree_delete.c b/src/libdatastruct/avltree_delete.c
new file mode 100644
index 0000000..5127f01
--- /dev/null
+++ b/src/libdatastruct/avltree_delete.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/avlnode.h>
+#include <skalibs/avltree.h>
+
+int avltree_delete (avltree_ref t, void const *k)
+{
+ unsigned int r = avltree_root(t) ;
+ unsigned int i = avlnode_delete(avltree_nodes(t), avltree_totalsize(t), &r, k, t->dtok, t->kcmp, t->external) ;
+ if (i >= avltree_totalsize(t)) return (errno = ESRCH, 0) ;
+ avltree_setroot(t, r) ;
+ if (!gensetdyn_delete(&t->x, i)) return 0 ;
+ return 1 ;
+}
diff --git a/src/libdatastruct/avltree_free.c b/src/libdatastruct/avltree_free.c
new file mode 100644
index 0000000..14198fe
--- /dev/null
+++ b/src/libdatastruct/avltree_free.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/gensetdyn.h>
+#include <skalibs/avltree.h>
+
+void avltree_free (avltree_ref t)
+{
+ gensetdyn_free(&t->x) ;
+ *t = avltree_zero ;
+}
diff --git a/src/libdatastruct/avltree_init.c b/src/libdatastruct/avltree_init.c
new file mode 100644
index 0000000..290ff64
--- /dev/null
+++ b/src/libdatastruct/avltree_init.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/functypes.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/avlnode.h>
+#include <skalibs/avltree.h>
+
+void avltree_init (avltree_ref t, unsigned int base, unsigned int fracnum, unsigned int fracden, dtokfunc_t_ref dtok, cmpfunc_t_ref f, void *p)
+{
+ gensetdyn_init(&t->x, sizeof(avlnode), base, fracnum, fracden) ;
+ t->root = (unsigned int)-1 ;
+ t->dtok = dtok ;
+ t->kcmp = f ;
+ t->external = p ;
+}
diff --git a/src/libdatastruct/avltree_insert.c b/src/libdatastruct/avltree_insert.c
new file mode 100644
index 0000000..308990a
--- /dev/null
+++ b/src/libdatastruct/avltree_insert.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/avltree.h>
+
+int avltree_insert (avltree_ref t, unsigned int d)
+{
+ unsigned int i ;
+ if (!avltree_newnode(t, d, &i)) return 0 ;
+ avltree_insertnode(t, i) ;
+ return 1 ;
+}
diff --git a/src/libdatastruct/avltree_newnode.c b/src/libdatastruct/avltree_newnode.c
new file mode 100644
index 0000000..dc972a0
--- /dev/null
+++ b/src/libdatastruct/avltree_newnode.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/avlnode.h>
+#include <skalibs/avltree.h>
+
+int avltree_newnode (avltree_ref t, unsigned int data, unsigned int *i)
+{
+ if (!gensetdyn_new(&t->x, i)) return 0 ;
+ {
+ register avlnode_ref s = avltree_nodes(t) ;
+ s[*i].data = data ;
+ s[*i].child[0] = s[*i].child[1] = (unsigned int)-1 ;
+ s[*i].balance = 0 ;
+ }
+ return 1 ;
+}
diff --git a/src/libdatastruct/avltree_zero.c b/src/libdatastruct/avltree_zero.c
new file mode 100644
index 0000000..400828a
--- /dev/null
+++ b/src/libdatastruct/avltree_zero.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include <skalibs/avltree.h>
+
+avltree const avltree_zero = AVLTREE_ZERO ;
diff --git a/src/libdatastruct/avltreen_delete.c b/src/libdatastruct/avltreen_delete.c
new file mode 100644
index 0000000..bfe85c5
--- /dev/null
+++ b/src/libdatastruct/avltreen_delete.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/genset.h>
+#include <skalibs/avlnode.h>
+#include <skalibs/avltreen.h>
+
+int avltreen_delete (avltreen_ref t, void const *k)
+{
+ unsigned int r = avltreen_root(t) ;
+ unsigned int i = avlnode_delete(avltreen_nodes(t), avltreen_totalsize(t), &r, k, t->dtok, t->kcmp, t->external) ;
+ if (i >= avltreen_totalsize(t)) return (errno = ESRCH, 0) ;
+ avltreen_setroot(t, r) ;
+ if (!genset_delete(&t->x, i)) return 0 ;
+ return 1 ;
+}
diff --git a/src/libdatastruct/avltreen_init.c b/src/libdatastruct/avltreen_init.c
new file mode 100644
index 0000000..5e141b1
--- /dev/null
+++ b/src/libdatastruct/avltreen_init.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/functypes.h>
+#include <skalibs/genset.h>
+#include <skalibs/avlnode.h>
+#include <skalibs/avltreen.h>
+
+void avltreen_init (avltreen_ref t, avlnode_ref storage, unsigned int *freelist, unsigned int size, dtokfunc_t_ref dtok, cmpfunc_t_ref f, void *p)
+{
+ GENSET_init(&t->x, avlnode, storage, freelist, size) ;
+ t->root = size ;
+ t->dtok = dtok ;
+ t->kcmp = f ;
+ t->external = p ;
+}
diff --git a/src/libdatastruct/avltreen_insert.c b/src/libdatastruct/avltreen_insert.c
new file mode 100644
index 0000000..795216d
--- /dev/null
+++ b/src/libdatastruct/avltreen_insert.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/avltreen.h>
+
+int avltreen_insert (avltreen_ref t, unsigned int d)
+{
+ unsigned int i = avltreen_newnode(t, d) ;
+ if (i >= avltreen_totalsize(t)) return 0 ;
+ avltreen_insertnode(t, i) ;
+ return 1 ;
+}
diff --git a/src/libdatastruct/avltreen_newnode.c b/src/libdatastruct/avltreen_newnode.c
new file mode 100644
index 0000000..335025c
--- /dev/null
+++ b/src/libdatastruct/avltreen_newnode.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/genset.h>
+#include <skalibs/avlnode.h>
+#include <skalibs/avltreen.h>
+
+unsigned int avltreen_newnode (avltreen_ref t, unsigned int d)
+{
+ register unsigned int i = genset_new(&t->x) ;
+ if (i < avltreen_totalsize(t))
+ {
+ register avlnode_ref s = avltreen_nodes(t) ;
+ s[i].data = d ;
+ s[i].child[0] = s[i].child[1] = avltreen_totalsize(t) ;
+ s[i].balance = 0 ;
+ }
+ return i ;
+}
diff --git a/src/libdatastruct/genset.c b/src/libdatastruct/genset.c
new file mode 100644
index 0000000..8d750b7
--- /dev/null
+++ b/src/libdatastruct/genset.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/genset.h>
+
+void genset_init (genset_ref x, void *storage, unsigned int *freelist, unsigned int esize, unsigned int max)
+{
+ register unsigned int i = 0 ;
+ x->storage = (char *)storage ;
+ x->freelist = freelist ;
+ x->esize = esize ;
+ x->max = max ;
+ x->sp = max ;
+ for (; i < max ; i++) freelist[i] = max - 1 - i ;
+}
+
+unsigned int genset_new (genset_ref x)
+{
+ return x->sp ? x->freelist[--x->sp] : (errno = ENOSPC, x->max) ;
+}
+
+int genset_delete (genset_ref x, unsigned int i)
+{
+ if ((i >= x->max) || (x->sp >= x->max)) return (errno = EINVAL, 0) ;
+ x->freelist[x->sp++] = i ;
+ return 1 ;
+}
diff --git a/src/libdatastruct/genset_iter.c b/src/libdatastruct/genset_iter.c
new file mode 100644
index 0000000..cc6e863
--- /dev/null
+++ b/src/libdatastruct/genset_iter.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <skalibs/bitarray.h>
+#include <skalibs/functypes.h>
+#include <skalibs/genset.h>
+
+unsigned int genset_iter (genset_ref g, iterfunc_t_ref f, void *stuff)
+{
+ unsigned char bits[bitarray_div8(g->max)] ;
+ unsigned int i = 0, j = 0, n = 0, m = genset_n(g) ;
+ bitarray_setn(bits, 0, g->max) ;
+ for (; i < g->sp ; i++) bitarray_clear(bits, g->freelist[i]) ;
+ for (i = 0 ; (i < g->max) && (j < m) ; i++) if (bitarray_peek(bits, i))
+ {
+ j++ ;
+ if ((*f)(g->storage + i * g->esize, stuff)) n++ ;
+ }
+ return n ;
+}
diff --git a/src/libdatastruct/gensetdyn_delete.c b/src/libdatastruct/gensetdyn_delete.c
new file mode 100644
index 0000000..58aec05
--- /dev/null
+++ b/src/libdatastruct/gensetdyn_delete.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/gensetdyn.h>
+
+int gensetdyn_delete (gensetdyn_ref g, unsigned int i)
+{
+ return (i >= g->storage.len) ? (errno = EINVAL, 0) :
+ genalloc_catb(unsigned int, &g->freelist, &i, 1) ;
+}
diff --git a/src/libdatastruct/gensetdyn_free.c b/src/libdatastruct/gensetdyn_free.c
new file mode 100644
index 0000000..c0a4366
--- /dev/null
+++ b/src/libdatastruct/gensetdyn_free.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/gensetdyn.h>
+
+void gensetdyn_free (gensetdyn_ref g)
+{
+ stralloc_free(&g->storage) ;
+ genalloc_free(unsigned int, &g->freelist) ;
+ *g = gensetdyn_zero ;
+}
diff --git a/src/libdatastruct/gensetdyn_init.c b/src/libdatastruct/gensetdyn_init.c
new file mode 100644
index 0000000..cff6ff5
--- /dev/null
+++ b/src/libdatastruct/gensetdyn_init.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/gensetdyn.h>
+
+void gensetdyn_init (gensetdyn_ref g, unsigned int esize, unsigned int base, unsigned int fracnum, unsigned int fracden)
+{
+ g->storage = stralloc_zero ;
+ g->freelist = genalloc_zero ;
+ g->esize = esize ;
+ g->base = base ;
+ g->fracnum = fracnum ;
+ g->fracden = fracden ;
+}
diff --git a/src/libdatastruct/gensetdyn_iter.c b/src/libdatastruct/gensetdyn_iter.c
new file mode 100644
index 0000000..216d42b
--- /dev/null
+++ b/src/libdatastruct/gensetdyn_iter.c
@@ -0,0 +1,26 @@
+/* ISC license. */
+
+#include <skalibs/bitarray.h>
+#include <skalibs/functypes.h>
+#include <skalibs/gensetdyn.h>
+
+unsigned int gensetdyn_iter (gensetdyn_ref g, iterfunc_t_ref f, void *stuff)
+{
+ /*
+ XXX: we may be called by a freeing function, so we cannot alloc -
+ XXX: so pray that the bitarray fits in the stack.
+ */
+ unsigned char bits[bitarray_div8(g->storage.len)] ;
+ unsigned int i = 0, j = 0, n = 0, m = gensetdyn_n(g) ;
+ register unsigned int *fl = genalloc_s(unsigned int, &g->freelist) ;
+ register unsigned int sp = genalloc_len(unsigned int, &g->freelist) ;
+ bitarray_setn(bits, 0, g->storage.len) ;
+
+ for (; i < sp ; i++) bitarray_clear(bits, fl[i]) ;
+ for (i = 0 ; (i < g->storage.len) && (j < m) ; i++) if (bitarray_peek(bits, i))
+ {
+ j++ ;
+ if ((*f)(gensetdyn_p(g, i), stuff)) n++ ;
+ }
+ return n ;
+}
diff --git a/src/libdatastruct/gensetdyn_new.c b/src/libdatastruct/gensetdyn_new.c
new file mode 100644
index 0000000..6a49189
--- /dev/null
+++ b/src/libdatastruct/gensetdyn_new.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/genalloc.h>
+#include <skalibs/gensetdyn.h>
+
+int gensetdyn_new (gensetdyn_ref g, unsigned int *i)
+{
+ register unsigned int n ;
+ if (!genalloc_len(unsigned int, &g->freelist) && !gensetdyn_readyplus(g, 1)) return 0 ;
+ n = genalloc_len(unsigned int, &g->freelist) ;
+ *i = genalloc_s(unsigned int, &g->freelist)[n-1] ;
+ genalloc_setlen(unsigned int, &g->freelist, n-1) ;
+ return 1 ;
+}
diff --git a/src/libdatastruct/gensetdyn_ready.c b/src/libdatastruct/gensetdyn_ready.c
new file mode 100644
index 0000000..d1cfd9f
--- /dev/null
+++ b/src/libdatastruct/gensetdyn_ready.c
@@ -0,0 +1,26 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/gensetdyn.h>
+
+int gensetdyn_ready (gensetdyn_ref g, unsigned int n)
+{
+ int wasnull = !g->storage.s ;
+ unsigned int i = g->storage.len ;
+ if (n < i) return 1 ;
+ n += g->base + (n * g->fracnum) / g->fracden ;
+ if (!stralloc_ready_tuned(&g->storage, n * g->esize, 0, 0, 1)) return 0 ;
+ if (!genalloc_ready(unsigned int, &g->freelist, n))
+ {
+ if (wasnull) stralloc_free(&g->storage) ;
+ return 0 ;
+ }
+ for (; i < n ; i++)
+ {
+ unsigned int j = n - 1 - i + g->storage.len ;
+ genalloc_catb(unsigned int, &g->freelist, &j, 1) ;
+ }
+ g->storage.len = n ;
+ return 1 ;
+}
diff --git a/src/libdatastruct/gensetdyn_zero.c b/src/libdatastruct/gensetdyn_zero.c
new file mode 100644
index 0000000..e3ab04a
--- /dev/null
+++ b/src/libdatastruct/gensetdyn_zero.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include <skalibs/gensetdyn.h>
+
+gensetdyn const gensetdyn_zero = GENSETDYN_ZERO ;
diff --git a/src/librandom/badrandom_char.c b/src/librandom/badrandom_char.c
new file mode 100644
index 0000000..c0ca1de
--- /dev/null
+++ b/src/librandom/badrandom_char.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include "random-internal.h"
+#include <skalibs/random.h>
+
+unsigned char badrandom_char (void)
+{
+ unsigned char x ;
+ badrandom_string((char *)&x, 1) ;
+ return x ;
+}
diff --git a/src/librandom/badrandom_finish.c b/src/librandom/badrandom_finish.c
new file mode 100644
index 0000000..e0791ee
--- /dev/null
+++ b/src/librandom/badrandom_finish.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/rrandom.h>
+#include "random-internal.h"
+#include <skalibs/random.h>
+
+void badrandom_finish (void)
+{
+ rrandom_finish(&badrandom_here) ;
+}
diff --git a/src/librandom/badrandom_here.c b/src/librandom/badrandom_here.c
new file mode 100644
index 0000000..c7d2992
--- /dev/null
+++ b/src/librandom/badrandom_here.c
@@ -0,0 +1,40 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/config.h>
+#include <skalibs/unisurf.h>
+#include "random-internal.h"
+
+#ifdef SKALIBS_EGD
+
+# include <skalibs/unirandomegd.h>
+
+# ifdef SKALIBS_HASDEVURANDOM
+
+# include <skalibs/unirandomdev.h>
+
+rrandom badrandom_here = { { { UNIRANDOM_REGISTER_DEVURANDOM(), 3 }, { UNIRANDOM_REGISTER_HASEGD(), 3 }, { UNIRANDOM_REGISTER_SURF(), 3 } }, 3 } ;
+
+# else
+
+rrandom badrandom_here = { { { UNIRANDOM_REGISTER_HASEGD(), 3 }, { UNIRANDOM_REGISTER_SURF(), 3 }, { UNIRANDOM_ZERO, 3 } }, 2 } ;
+
+# endif
+
+#else
+
+# ifdef SKALIBS_HASDEVURANDOM
+
+# include <skalibs/unirandomdev.h>
+
+rrandom badrandom_here = { { { UNIRANDOM_REGISTER_DEVURANDOM(), 3 }, { UNIRANDOM_REGISTER_SURF(), 3 }, { UNIRANDOM_ZERO, 3 } }, 2 } ;
+
+# else
+
+rrandom badrandom_here = { { { UNIRANDOM_REGISTER_SURF(), 3 }, { UNIRANDOM_ZERO, 3 }, { UNIRANDOM_ZERO, 3 } }, 1 } ;
+
+# endif
+
+#endif
diff --git a/src/librandom/badrandom_init.c b/src/librandom/badrandom_init.c
new file mode 100644
index 0000000..a6eb7e3
--- /dev/null
+++ b/src/librandom/badrandom_init.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/random.h>
+
+int badrandom_init (void)
+{
+ return 1 ;
+}
diff --git a/src/librandom/badrandom_int.c b/src/librandom/badrandom_int.c
new file mode 100644
index 0000000..ae12db5
--- /dev/null
+++ b/src/librandom/badrandom_int.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/rrandom.h>
+#include "random-internal.h"
+#include <skalibs/random.h>
+
+unsigned int badrandom_int (unsigned int n)
+{
+ return rrandom_readint(&badrandom_here, n, &unirandom_readnb) ;
+}
diff --git a/src/librandom/badrandom_string.c b/src/librandom/badrandom_string.c
new file mode 100644
index 0000000..ec20f5b
--- /dev/null
+++ b/src/librandom/badrandom_string.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/rrandom.h>
+#include "random-internal.h"
+#include <skalibs/random.h>
+
+unsigned int badrandom_string (char *s, unsigned int n)
+{
+ return rrandom_readnb(&badrandom_here, s, n) ;
+}
diff --git a/src/librandom/goodrandom_char.c b/src/librandom/goodrandom_char.c
new file mode 100644
index 0000000..8fbf5e8
--- /dev/null
+++ b/src/librandom/goodrandom_char.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include "random-internal.h"
+#include <skalibs/random.h>
+
+unsigned char goodrandom_char (void)
+{
+ unsigned char x ;
+ goodrandom_string((char *)&x, 1) ;
+ return x ;
+}
diff --git a/src/librandom/goodrandom_finish.c b/src/librandom/goodrandom_finish.c
new file mode 100644
index 0000000..a764030
--- /dev/null
+++ b/src/librandom/goodrandom_finish.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include "random-internal.h"
+#include <skalibs/rrandom.h>
+#include <skalibs/random.h>
+
+void goodrandom_finish (void)
+{
+ rrandom_finish(&goodrandom_here) ;
+}
diff --git a/src/librandom/goodrandom_here.c b/src/librandom/goodrandom_here.c
new file mode 100644
index 0000000..8275ab2
--- /dev/null
+++ b/src/librandom/goodrandom_here.c
@@ -0,0 +1,40 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/config.h>
+#include <skalibs/unisurf.h>
+#include "random-internal.h"
+
+#ifdef SKALIBS_EGD
+
+# include <skalibs/unirandomegd.h>
+
+# ifdef SKALIBS_HASDEVRANDOM
+
+# include <skalibs/unirandomdev.h>
+
+rrandom goodrandom_here = { { { UNIRANDOM_REGISTER_DEVRANDOM(), 3 }, { UNIRANDOM_REGISTER_HASEGD(), 3 }, { UNIRANDOM_REGISTER_SURF(), 3 } }, 3 } ;
+
+# else
+
+rrandom goodrandom_here = { { { UNIRANDOM_REGISTER_HASEGD(), 3 }, { UNIRANDOM_REGISTER_SURF(), 3 }, { UNIRANDOM_ZERO, 3 } }, 2 } ;
+
+# endif
+
+#else
+
+# ifdef SKALIBS_HASDEVRANDOM
+
+# include <skalibs/unirandomdev.h>
+
+rrandom goodrandom_here = { { { UNIRANDOM_REGISTER_DEVRANDOM(), 3 }, { UNIRANDOM_REGISTER_SURF(), 3 }, { UNIRANDOM_ZERO, 3 } }, 2 } ;
+
+# else
+
+rrandom goodrandom_here = { { { UNIRANDOM_REGISTER_SURF(), 3 }, { UNIRANDOM_ZERO, 3 }, { UNIRANDOM_ZERO, 3 } }, 1 } ;
+
+# endif
+
+#endif
diff --git a/src/librandom/goodrandom_init.c b/src/librandom/goodrandom_init.c
new file mode 100644
index 0000000..dea6225
--- /dev/null
+++ b/src/librandom/goodrandom_init.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/random.h>
+
+int goodrandom_init (void)
+{
+ return 1 ;
+}
diff --git a/src/librandom/goodrandom_int.c b/src/librandom/goodrandom_int.c
new file mode 100644
index 0000000..11ef2e1
--- /dev/null
+++ b/src/librandom/goodrandom_int.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/rrandom.h>
+#include "random-internal.h"
+#include <skalibs/random.h>
+
+unsigned int goodrandom_int (unsigned int n)
+{
+ return rrandom_readint(&goodrandom_here, n, &unirandom_readb) ;
+}
diff --git a/src/librandom/goodrandom_string.c b/src/librandom/goodrandom_string.c
new file mode 100644
index 0000000..556c41c
--- /dev/null
+++ b/src/librandom/goodrandom_string.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/rrandom.h>
+#include "random-internal.h"
+#include <skalibs/random.h>
+
+unsigned int goodrandom_string (char *s, unsigned int n)
+{
+ return rrandom_readb(&goodrandom_here, s, n) ;
+}
diff --git a/src/librandom/random-internal.h b/src/librandom/random-internal.h
new file mode 100644
index 0000000..37b534e
--- /dev/null
+++ b/src/librandom/random-internal.h
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#ifndef RANDOM_INTERNAL_H
+#define RANDOM_INTERNAL_H
+
+#include <skalibs/gccattributes.h>
+#include <skalibs/surf.h>
+#include <skalibs/unirandom.h>
+#include <skalibs/rrandom.h>
+
+extern void unirandom_register (unirandom_ref, int (*) (union unirandominfo *), int (*) (union unirandominfo *), unsigned int (*) (union unirandominfo *, char *, unsigned int), unsigned int (*) (union unirandominfo *, char *, unsigned int)) ;
+
+extern unsigned int random_mask2 (unsigned int) gccattr_const ;
+extern unsigned int random_nchars (unsigned int) gccattr_const ;
+
+extern SURFSchedule surf_here ;
+extern rrandom goodrandom_here ;
+extern rrandom badrandom_here ;
+
+#endif
diff --git a/src/librandom/random_mask2.c b/src/librandom/random_mask2.c
new file mode 100644
index 0000000..ab8c8e7
--- /dev/null
+++ b/src/librandom/random_mask2.c
@@ -0,0 +1,35 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include "random-internal.h"
+
+unsigned int random_mask2 (register unsigned int n)
+{
+ for (;;)
+ {
+ register unsigned int m = n | (n >> 1) ;
+ if (m == n) return n ;
+ n = m ;
+ }
+}
+
+unsigned int random_nchars (register unsigned int n)
+{
+ return n <= 0xff ? 1 :
+#if SKALIBS_SIZEOFUINT == 2
+ 2
+#else
+ n <= 0xffff ? 2 :
+ n <= 0xffffffUL ? 3 :
+# if SKALIBS_SIZEOFUINT == 4
+ 4
+# else
+ n <= 0xffffffffUL ? 4 :
+ n <= 0xffffffffffULL ? 5 :
+ n <= 0xffffffffffffULL ? 6 :
+ n <= 0xffffffffffffffULL ? 7 :
+ 8
+# endif
+#endif
+ ;
+}
diff --git a/src/librandom/random_name.c b/src/librandom/random_name.c
new file mode 100644
index 0000000..8736699
--- /dev/null
+++ b/src/librandom/random_name.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include "random-internal.h"
+#include <skalibs/random.h>
+
+int random_name (char *s, unsigned int n)
+{
+ register unsigned int r = rrandom_name(&badrandom_here, s, n, 1) ;
+ if (r < n) return -1 ;
+ return n ;
+}
diff --git a/src/librandom/random_sauniquename.c b/src/librandom/random_sauniquename.c
new file mode 100644
index 0000000..7c902ef
--- /dev/null
+++ b/src/librandom/random_sauniquename.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/skamisc.h>
+#include <skalibs/random.h>
+
+int random_sauniquename (stralloc *sa, unsigned int n)
+{
+ unsigned int base = sa->len ;
+ int wasnull = !sa->s ;
+ register int r ;
+ if (sauniquename(sa) == -1) return -1 ;
+ if (!stralloc_readyplus(sa, n+1)) goto err ;
+ stralloc_catb(sa, ":", 1) ;
+ r = random_name(sa->s + sa->len, n) ;
+ if (r == -1) goto err ;
+ sa->len += r ;
+ return r ;
+
+err:
+ if (wasnull) stralloc_free(sa) ; else sa->len = base ;
+ return -1 ;
+}
diff --git a/src/librandom/random_unsort.c b/src/librandom/random_unsort.c
new file mode 100644
index 0000000..289ef96
--- /dev/null
+++ b/src/librandom/random_unsort.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/random.h>
+
+void random_unsort (char *s, unsigned int n, unsigned int chunksize)
+{
+ char tmp[chunksize] ;
+ while (n--)
+ {
+ register unsigned int i = badrandom_int(n+1) ;
+ byte_copy(tmp, chunksize, s + i * chunksize) ;
+ byte_copy(s + i * chunksize, chunksize, s + n * chunksize) ;
+ byte_copy(s + n * chunksize, chunksize, tmp) ;
+ }
+}
diff --git a/src/librandom/randomegd_open.c b/src/librandom/randomegd_open.c
new file mode 100644
index 0000000..7c43f0d
--- /dev/null
+++ b/src/librandom/randomegd_open.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/webipc.h>
+#include <skalibs/randomegd.h>
+
+int randomegd_open (char const *path)
+{
+ int s = ipc_stream() ;
+ if (s < 0) return -1 ;
+ if (ipc_connect(s, path) == -1)
+ {
+ register int e = errno ;
+ fd_close(s) ;
+ errno = e ;
+ return -1 ;
+ }
+ return s ;
+}
diff --git a/src/librandom/randomegd_readb.c b/src/librandom/randomegd_readb.c
new file mode 100644
index 0000000..614f7a8
--- /dev/null
+++ b/src/librandom/randomegd_readb.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <skalibs/allreadwrite.h>
+#include <skalibs/randomegd.h>
+
+unsigned int randomegd_readb (int s, char *x, unsigned int n)
+{
+ unsigned int w = 0 ;
+ unsigned int i = 0 ;
+ for (; i < (n / 255) ; i++)
+ {
+ char const c[2] = { 0x02, 0xFF } ;
+ register unsigned int wtmp ;
+ if (allwrite(s, c, 2) < 2) return w ;
+ wtmp = allread(s, x + w, 255) ;
+ w += wtmp ;
+ if (wtmp < 255) return w ;
+ }
+ if (w < n)
+ {
+ char c[2] = "\002" ;
+ c[1] = n - w ;
+ if (allwrite(s, c, 2) < 2) return w ;
+ w += allread(s, x + w, c[1]) ;
+ }
+ return w ;
+}
diff --git a/src/librandom/randomegd_readnb.c b/src/librandom/randomegd_readnb.c
new file mode 100644
index 0000000..29165c4
--- /dev/null
+++ b/src/librandom/randomegd_readnb.c
@@ -0,0 +1,28 @@
+/* ISC license. */
+
+#include <skalibs/allreadwrite.h>
+#include <skalibs/randomegd.h>
+
+unsigned int randomegd_readnb (int s, char *x, unsigned int n)
+{
+ unsigned int w = 0 ;
+ while ((n - w) >= 255)
+ {
+ char c[2] = { 0x01, 0xFF } ;
+ register unsigned char wtmp ;
+ if (allwrite(s, c, 2) < 2) return w ;
+ if (sanitize_read(fd_read(s, c+1, 1)) < 1) return w ;
+ wtmp = allread(s, x + w, c[1]) ;
+ w += wtmp ;
+ if ((wtmp < (unsigned char)c[1]) || ((unsigned char)c[1] < 0xFF)) return w ;
+ }
+ if (w < n)
+ {
+ char c[2] = "\001" ;
+ c[1] = n - w ;
+ if (allwrite(s, c, 2) < 2) return w ;
+ if (sanitize_read(fd_read(s, c+1, 1)) < 1) return w ;
+ w += allread(s, x + w, c[1]) ;
+ }
+ return w ;
+}
diff --git a/src/librandom/rrandom_add.c b/src/librandom/rrandom_add.c
new file mode 100644
index 0000000..c22a43c
--- /dev/null
+++ b/src/librandom/rrandom_add.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/unirandom.h>
+#include <skalibs/rrandom.h>
+
+int rrandom_add (rrandom_ref z, int (*f) (unirandom_ref))
+{
+ if (z->n >= 3) return (errno = EBUSY, 0) ;
+ if (!(*f)(&z->tries[z->n].it)) return 0 ;
+ z->tries[z->n++].ok = 3 ;
+ return 1 ;
+}
diff --git a/src/librandom/rrandom_finish.c b/src/librandom/rrandom_finish.c
new file mode 100644
index 0000000..a3cb24b
--- /dev/null
+++ b/src/librandom/rrandom_finish.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/unirandom.h>
+#include <skalibs/rrandom.h>
+
+int rrandom_finish (rrandom_ref z)
+{
+ rrandom zero = RRANDOM_ZERO ;
+ unsigned int i = z->n ;
+ int e = 1 ;
+ while (i--) e &= unirandom_finish(&z->tries[i].it) ;
+ if (e) *z = zero ;
+ return e ;
+}
diff --git a/src/librandom/rrandom_name.c b/src/librandom/rrandom_name.c
new file mode 100644
index 0000000..5e77e83
--- /dev/null
+++ b/src/librandom/rrandom_name.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/unirandom.h>
+#include <skalibs/rrandom.h>
+
+unsigned int rrandom_name (rrandom_ref z, char *s, unsigned int n, int nb)
+{
+ static char const *oklist = "ABCDEFGHIJKLMNOPQRSTUVWXYZghijklmnopqrstuvwxyz-_0123456789abcdef" ;
+ register unsigned int r = rrandom_read(z, s, n, nb ? &unirandom_readnb : &unirandom_readb) ;
+ register unsigned int i = 0 ;
+ for (; i < r ; i++) s[i] = oklist[s[i] & 63] ;
+ return r ;
+}
diff --git a/src/librandom/rrandom_read.c b/src/librandom/rrandom_read.c
new file mode 100644
index 0000000..57ff920
--- /dev/null
+++ b/src/librandom/rrandom_read.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/error.h>
+#include <skalibs/unirandom.h>
+#include <skalibs/rrandom.h>
+
+unsigned int rrandom_read (rrandom_ref z, char *s, unsigned int n, unsigned int (*f) (unirandom_ref, char *, unsigned int))
+{
+ unsigned int i = 0 ;
+ for (; i < 3 ; i++)
+ {
+ int r ;
+ if (!z->tries[i].ok) continue ;
+ r = sanitize_read((*f)(&z->tries[i].it, s, n)) ;
+ if (r > 0) return r ;
+ z->tries[i].ok = error_temp(errno) ? z->tries[i].ok - 1 : 0 ;
+ }
+ return (errno = ENOENT, 0) ;
+}
diff --git a/src/librandom/rrandom_readint.c b/src/librandom/rrandom_readint.c
new file mode 100644
index 0000000..e4f677c
--- /dev/null
+++ b/src/librandom/rrandom_readint.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/unirandom.h>
+#include "random-internal.h"
+#include <skalibs/rrandom.h>
+
+unsigned int rrandom_readint (rrandom_ref z, unsigned int n, unsigned int (*f) (unirandom_ref, char *, unsigned int))
+{
+ if (!n) return 0 ;
+ else
+ {
+ unsigned int i = n, nchars = random_nchars(n), m = random_mask2(n-1) ;
+ char tmp[UINT_PACK] ;
+ while (i >= n)
+ {
+ if (rrandom_read(z, tmp, nchars, f) < nchars) return 0 ;
+ byte_zero(tmp + nchars, UINT_PACK - nchars) ;
+ uint_unpack(tmp, &i) ;
+ i &= m ;
+ }
+ return i ;
+ }
+}
diff --git a/src/librandom/surf.c b/src/librandom/surf.c
new file mode 100644
index 0000000..1687df9
--- /dev/null
+++ b/src/librandom/surf.c
@@ -0,0 +1,54 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/surf.h>
+
+#define ROTATE(x, b) (((x) << (b)) | ((x) >> (32 - (b))))
+#define MUSH(i, b) x = t[i] += (((x ^ ctx->seed[i]) + sum) ^ ROTATE(x, b))
+
+static void surfit (SURFSchedule_ref ctx)
+{
+ uint32 t[12] ;
+ uint32 z[8] ;
+ uint32 x ;
+ uint32 sum = 0 ;
+ unsigned int i = 0, loop = 0 ; ;
+
+ if (!++ctx->in[0] && !++ctx->in[1] && !++ctx->in[2]) ++ctx->in[3] ;
+ for (; i < 12 ; i++) t[i] = ctx->in[i] ^ ctx->seed[12+i] ;
+ for (i = 0 ; i < 8 ; i++) z[i] = ctx->seed[24+i] ;
+ x = t[11] ;
+ for (; loop < 2 ; loop++)
+ {
+ for (i = 0 ; i < 16 ; i++)
+ {
+ sum += 0x9e3779b9 ;
+ MUSH(0, 5) ; MUSH(1, 7) ; MUSH(2, 9) ; MUSH(3, 13) ;
+ MUSH(4, 5) ; MUSH(5, 7) ; MUSH(6, 9) ; MUSH(7, 13) ;
+ MUSH(8, 5) ; MUSH(9, 7) ; MUSH(10, 9) ; MUSH(11, 13) ;
+ }
+ for (i = 0 ; i < 8 ; i++) z[i] ^= t[i+4] ;
+ }
+ for (i = 0 ; i < 8 ; i++) uint32_pack(ctx->out + (i<<2), z[i]) ;
+}
+
+void surf (SURFSchedule_ref ctx, char *s, unsigned int n)
+{
+ {
+ register unsigned int i = 32 - ctx->pos ;
+ if (n < i) i = n ;
+ byte_copy(s, i, ctx->out + ctx->pos) ;
+ s += i ; n -= i ; ctx->pos += i ;
+ }
+ while (n > 32)
+ {
+ surfit(ctx) ;
+ byte_copy(s, 32, ctx->out) ;
+ s += 32 ; n -= 32 ;
+ }
+ if (!n) return ;
+ surfit(ctx) ;
+ byte_copy(s, n, ctx->out) ;
+ ctx->pos = n ;
+}
diff --git a/src/librandom/surf_autoinit.c b/src/librandom/surf_autoinit.c
new file mode 100644
index 0000000..920612b
--- /dev/null
+++ b/src/librandom/surf_autoinit.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/surf.h>
+
+void surf_autoinit (SURFSchedule_ref ctx, char *s, unsigned int n)
+{
+ if (!ctx->in[0] && !ctx->in[1] && !ctx->in[2] && !ctx->in[3])
+ surf_init(ctx) ;
+ surf(ctx, s, n) ;
+}
diff --git a/src/librandom/surf_here.c b/src/librandom/surf_here.c
new file mode 100644
index 0000000..ebbdffb
--- /dev/null
+++ b/src/librandom/surf_here.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/surf.h>
+#include "random-internal.h"
+
+SURFSchedule surf_here = SURFSCHEDULE_ZERO ;
diff --git a/src/librandom/surf_init.c b/src/librandom/surf_init.c
new file mode 100644
index 0000000..3662fa8
--- /dev/null
+++ b/src/librandom/surf_init.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/surf.h>
+
+void surf_init (SURFSchedule_ref ctx)
+{
+ char s[160] ;
+ surf_makeseed(s) ;
+ surf_sinit(ctx, s) ;
+}
diff --git a/src/librandom/surf_makeseed.c b/src/librandom/surf_makeseed.c
new file mode 100644
index 0000000..adae9a4
--- /dev/null
+++ b/src/librandom/surf_makeseed.c
@@ -0,0 +1,35 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <skalibs/uint32.h>
+#include <skalibs/tai.h>
+#include <skalibs/sha1.h>
+#include <skalibs/surf.h>
+
+void surf_makeseed (char *s)
+{
+ SHA1Schedule bak = SHA1_INIT() ;
+ {
+ tain_t now ;
+ char tmp[20 + TAIN_PACK] ;
+ uint32 x = getpid() ;
+ uint32_pack(tmp, x) ;
+ x = getppid() ;
+ uint32_pack(tmp + 4, x) ;
+ tain_now(&now) ;
+ tain_pack(tmp + 8, &now) ;
+ sha1_update(&bak, tmp, 8 + TAIN_PACK) ;
+ sha1_final(&bak, tmp) ;
+ sha1_init(&bak) ;
+ sha1_update(&bak, tmp, 20) ;
+ }
+ {
+ char i = 0 ;
+ for (; i < 8 ; i++)
+ {
+ SHA1Schedule ctx = bak ;
+ sha1_update(&ctx, &i, 1) ;
+ sha1_final(&ctx, s + 20*i) ;
+ }
+ }
+}
diff --git a/src/librandom/surf_sinit.c b/src/librandom/surf_sinit.c
new file mode 100644
index 0000000..ae7f480
--- /dev/null
+++ b/src/librandom/surf_sinit.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/surf.h>
+
+void surf_sinit (SURFSchedule_ref ctx, char const *s)
+{
+ SURFSchedule zero = SURFSCHEDULE_ZERO ;
+ register unsigned int i = 4 ;
+ *ctx = zero ;
+ for (; i < 12 ; i++) uint32_unpack(s + (i<<2) - 16, ctx->in + i) ;
+ for (i = 0 ; i < 32 ; i++) uint32_unpack(s + 32 + (i<<2), ctx->seed + i) ;
+}
diff --git a/src/librandom/unidevrandom.c b/src/librandom/unidevrandom.c
new file mode 100644
index 0000000..fb7b6b8
--- /dev/null
+++ b/src/librandom/unidevrandom.c
@@ -0,0 +1,38 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/unirandomdev.h>
+#include <skalibs/unirandom.h>
+
+#ifdef SKALIBS_HASDEVRANDOM
+
+#include "random-internal.h"
+
+int unidevrandom_init (union unirandominfo *u)
+{
+ return unirandomdev_sinit(u, "/dev/random") ;
+}
+
+int unirandom_register_devrandom (unirandom *u)
+{
+ unirandom_register(u, &unidevrandom_init, &unirandomdev_finish, &unirandomdev_readb, &unirandomdev_readnb) ;
+ return 1 ;
+}
+
+#else
+
+#include <errno.h>
+
+int unidevrandom_init (union unirandominfo *u)
+{
+ (void)u ;
+ return (errno = ENOSYS, 0) ;
+}
+
+int unirandom_register_devrandom (unirandom *u)
+{
+ (void)u ;
+ return (errno = ENOSYS, 0) ;
+}
+
+#endif
diff --git a/src/librandom/unidevurandom.c b/src/librandom/unidevurandom.c
new file mode 100644
index 0000000..d601ea0
--- /dev/null
+++ b/src/librandom/unidevurandom.c
@@ -0,0 +1,38 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/unirandomdev.h>
+#include <skalibs/unirandom.h>
+
+#ifdef SKALIBS_HASDEVURANDOM
+
+#include "random-internal.h"
+
+int unidevurandom_init (union unirandominfo *u)
+{
+ return unirandomdev_sinit(u, "/dev/urandom") ;
+}
+
+int unirandom_register_devurandom (unirandom *u)
+{
+ unirandom_register(u, &unidevurandom_init, &unirandomdev_finish, &unirandomdev_readb, &unirandomdev_readnb) ;
+ return 1 ;
+}
+
+#else
+
+#include <errno.h>
+
+int unidevurandom_init (union unirandominfo *u)
+{
+ (void)u ;
+ return (errno = ENOSYS, 0) ;
+}
+
+int unirandom_register_devurandom (unirandom *u)
+{
+ (void)u ;
+ return (errno = ENOSYS, 0) ;
+}
+
+#endif
diff --git a/src/librandom/unihasegd.c b/src/librandom/unihasegd.c
new file mode 100644
index 0000000..ab263c7
--- /dev/null
+++ b/src/librandom/unihasegd.c
@@ -0,0 +1,38 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/unirandomegd.h>
+#include <skalibs/unirandom.h>
+
+#ifdef SKALIBS_EGD
+
+#include "random-internal.h"
+
+int unihasegd_init (union unirandominfo *u)
+{
+ return unirandomegd_sinit(u, SKALIBS_EGD) ;
+}
+
+int unirandom_register_hasegd (unirandom *u)
+{
+ unirandom_register(u, &unihasegd_init, &unirandomegd_finish, &unirandomegd_readb, &unirandomegd_readnb) ;
+ return 1 ;
+}
+
+#else
+
+#include <errno.h>
+
+int unihasegd_init (union unirandominfo *u)
+{
+ (void)u ;
+ return (errno = ENOSYS, 0) ;
+}
+
+int unirandom_register_hasegd (unirandom *u)
+{
+ (void)u ;
+ return (errno = ENOSYS, 0) ;
+}
+
+#endif
diff --git a/src/librandom/unirandom_finish.c b/src/librandom/unirandom_finish.c
new file mode 100644
index 0000000..14c4411
--- /dev/null
+++ b/src/librandom/unirandom_finish.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/unirandom.h>
+
+int unirandom_finish (unirandom_ref u)
+{
+ if (!u->initted) return 1 ;
+ if (!(*u->finish)(&u->data)) return 0 ;
+ u->initted = 0 ;
+ return 1 ;
+}
diff --git a/src/librandom/unirandom_init.c b/src/librandom/unirandom_init.c
new file mode 100644
index 0000000..711a4ac
--- /dev/null
+++ b/src/librandom/unirandom_init.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/unirandom.h>
+
+int unirandom_init (unirandom_ref u)
+{
+ if (u->initted) return 1 ;
+ if (!(*u->init)(&u->data)) return 0 ;
+ u->initted = 1 ;
+ return 1 ;
+}
diff --git a/src/librandom/unirandom_readb.c b/src/librandom/unirandom_readb.c
new file mode 100644
index 0000000..cbe45a6
--- /dev/null
+++ b/src/librandom/unirandom_readb.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/unirandom.h>
+
+unsigned int unirandom_readb (unirandom_ref u, char *s, unsigned int n)
+{
+ if (!u->initted && !unirandom_init(u)) return 0 ;
+ return (*u->readb)(&u->data, s, n) ;
+}
diff --git a/src/librandom/unirandom_readnb.c b/src/librandom/unirandom_readnb.c
new file mode 100644
index 0000000..f0cc38e
--- /dev/null
+++ b/src/librandom/unirandom_readnb.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/unirandom.h>
+
+unsigned int unirandom_readnb (unirandom_ref u, char *s, unsigned int n)
+{
+ if (!u->initted && !unirandom_init(u)) return 0 ;
+ return (*u->readnb)(&u->data, s, n) ;
+}
diff --git a/src/librandom/unirandom_register.c b/src/librandom/unirandom_register.c
new file mode 100644
index 0000000..35f7411
--- /dev/null
+++ b/src/librandom/unirandom_register.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/unirandom.h>
+#include "random-internal.h"
+
+void unirandom_register (unirandom_ref u, int (*init) (union unirandominfo *), int (*finish) (union unirandominfo *), unsigned int (*readb) (union unirandominfo *, char *, unsigned int), unsigned int (*readnb) (union unirandominfo *, char *, unsigned int))
+{
+ unirandom zero = UNIRANDOM_ZERO ;
+ *u = zero ;
+ u->init = init ;
+ u->finish = finish ;
+ u->readb = readb ;
+ u->readnb = readnb ;
+ u->initted = 0 ;
+}
diff --git a/src/librandom/unirandomdev.c b/src/librandom/unirandomdev.c
new file mode 100644
index 0000000..4a22514
--- /dev/null
+++ b/src/librandom/unirandomdev.c
@@ -0,0 +1,50 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/unirandom.h>
+#include <skalibs/unirandomdev.h>
+
+int unirandomdev_sinit (union unirandominfo *u, char const *file)
+{
+ register int fd = open_read(file) ;
+ if (fd < 0) return 0 ;
+ if (coe(fd) < 0)
+ {
+ register int e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ return 0 ;
+ }
+ buffer_init(&u->device.b, &buffer_read, fd, u->device.buf, RANDOMBUF_BUFSIZE) ;
+ u->device.nb = 1 ;
+ return 1 ;
+}
+
+int unirandomdev_finish (union unirandominfo *u)
+{
+ return fd_close(buffer_fd(&u->device.b)) < 0 ;
+}
+
+static unsigned int unirandomdev_read (union unirandominfo *u, char *s, unsigned int n, unsigned int h)
+{
+ unsigned int w = 0 ;
+ if (u->device.nb != h)
+ {
+ if ((h ? ndelay_on(buffer_fd(&u->device.b)) : ndelay_off(buffer_fd(&u->device.b))) < 0) return 0 ;
+ u->device.nb = h ;
+ }
+ buffer_getall(&u->device.b, s, n, &w) ;
+ return w ;
+}
+
+unsigned int unirandomdev_readb (union unirandominfo *u, char *s, unsigned int n)
+{
+ return unirandomdev_read(u, s, n, 0) ;
+}
+
+unsigned int unirandomdev_readnb (union unirandominfo *u, char *s, unsigned int n)
+{
+ return unirandomdev_read(u, s, n, 1) ;
+}
diff --git a/src/librandom/unirandomegd.c b/src/librandom/unirandomegd.c
new file mode 100644
index 0000000..a340f06
--- /dev/null
+++ b/src/librandom/unirandomegd.c
@@ -0,0 +1,37 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/randomegd.h>
+#include <skalibs/unirandom.h>
+#include <skalibs/unirandomegd.h>
+
+int unirandomegd_sinit (union unirandominfo *u, char const *path)
+{
+ register int s = randomegd_open(path) ;
+ if (s == -1) return 0 ;
+ if (coe(s) == -1)
+ {
+ register int e = errno ;
+ fd_close(s) ;
+ errno = e ;
+ return 0 ;
+ }
+ u->egd.fd = s ;
+ return 1 ;
+}
+
+int unirandomegd_finish (union unirandominfo *u)
+{
+ return !fd_close(u->egd.fd) ;
+}
+
+unsigned int unirandomegd_readb (union unirandominfo *u, char *s, unsigned int n)
+{
+ return randomegd_readb(u->egd.fd, s, n) ;
+}
+
+unsigned int unirandomegd_readnb (union unirandominfo *u, char *s, unsigned int n)
+{
+ return randomegd_readnb(u->egd.fd, s, n) ;
+}
diff --git a/src/librandom/unisurf.c b/src/librandom/unisurf.c
new file mode 100644
index 0000000..334d044
--- /dev/null
+++ b/src/librandom/unisurf.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <skalibs/surf.h>
+#include <skalibs/unirandom.h>
+#include <skalibs/unisurf.h>
+
+int unisurf_sinit (union unirandominfo *u, char const *s)
+{
+ surf_sinit(&u->surf_ctx, s) ;
+ return 1 ;
+}
+
+int unisurf_finish (union unirandominfo *u)
+{
+ (void)u ;
+ return 1 ;
+}
+
+unsigned int unisurf_read (union unirandominfo *u, char *s, unsigned int n)
+{
+ surf(&u->surf_ctx, s, n) ;
+ return n ;
+}
diff --git a/src/librandom/unisurf_init.c b/src/librandom/unisurf_init.c
new file mode 100644
index 0000000..d5a1f73
--- /dev/null
+++ b/src/librandom/unisurf_init.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/surf.h>
+#include "random-internal.h"
+#include <skalibs/unirandom.h>
+#include <skalibs/unisurf.h>
+
+int unisurf_init (union unirandominfo *u)
+{
+ surf_init(&u->surf_ctx) ;
+ return 1 ;
+}
+
+int unirandom_register_surf (unirandom *u)
+{
+ unirandom_register(u, &unisurf_init, &unisurf_finish, &unisurf_read, &unisurf_read) ;
+ return 1 ;
+}
diff --git a/src/libstdcrypto/INCLUDE b/src/libstdcrypto/INCLUDE
new file mode 100644
index 0000000..563254f
--- /dev/null
+++ b/src/libstdcrypto/INCLUDE
@@ -0,0 +1,5 @@
+rc4.h
+md5.h
+sha1.h
+sha256.h
+stdcrypto.h
diff --git a/src/libstdcrypto/Makefile b/src/libstdcrypto/Makefile
new file mode 100644
index 0000000..8c0d22f
--- /dev/null
+++ b/src/libstdcrypto/Makefile
@@ -0,0 +1,7 @@
+it: EXPORT- .done
+
+EXPORT-: gen-EXPORT
+ exec ./gen-EXPORT > EXPORT-
+
+.done: gen-Makefile
+ ./gen-Makefile > Makefile.real && make -f Makefile.real && : > .done
diff --git a/src/libstdcrypto/md5-internal.h b/src/libstdcrypto/md5-internal.h
new file mode 100644
index 0000000..374528a
--- /dev/null
+++ b/src/libstdcrypto/md5-internal.h
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#ifndef MD5_INTERNAL_H
+#define MD5_INTERNAL_H
+
+#include <skalibs/uint32.h>
+#include <skalibs/md5.h>
+
+extern void md5_transform (uint32 * /* 4 uint32s */, uint32 const * /* 16 uint32s */) ;
+
+#endif
diff --git a/src/libstdcrypto/md5_final.c b/src/libstdcrypto/md5_final.c
new file mode 100644
index 0000000..834d57c
--- /dev/null
+++ b/src/libstdcrypto/md5_final.c
@@ -0,0 +1,30 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/md5.h>
+#include "md5-internal.h"
+
+void md5_final (MD5Schedule_ref ctx, char *digest /* 16 chars */)
+{
+ register unsigned int count = (ctx->bits[0] >> 3) & 0x3F ;
+ register unsigned char *p = ctx->in + count ;
+ *p++ = 0x80;
+ count = 63 - count ;
+ if (count < 8)
+ {
+ byte_zero(p, count) ;
+ uint32_little_endian((char *)ctx->in, 16) ;
+ md5_transform(ctx->buf, (uint32 *)ctx->in) ;
+ byte_zero(ctx->in, 56) ;
+ }
+ else byte_zero(p, count - 8) ;
+ uint32_little_endian((char *)ctx->in, 14) ;
+
+ byte_copy(ctx->in + 56, 4, (char *)&ctx->bits[0]) ;
+ byte_copy(ctx->in + 60, 4, (char *)&ctx->bits[1]) ;
+
+ md5_transform(ctx->buf, (uint32 *)ctx->in) ;
+ uint32_little_endian((char *)ctx->buf, 4) ;
+ byte_copy(digest, 16, (char *)ctx->buf) ;
+}
diff --git a/src/libstdcrypto/md5_init.c b/src/libstdcrypto/md5_init.c
new file mode 100644
index 0000000..cb2f611
--- /dev/null
+++ b/src/libstdcrypto/md5_init.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/md5.h>
+
+void md5_init (MD5Schedule_ref ctx)
+{
+ ctx->buf[0] = 0x67452301UL ;
+ ctx->buf[1] = 0xefcdab89UL ;
+ ctx->buf[2] = 0x98badcfeUL ;
+ ctx->buf[3] = 0x10325476UL ;
+ ctx->bits[0] = 0 ;
+ ctx->bits[1] = 0 ;
+}
diff --git a/src/libstdcrypto/md5_transform.c b/src/libstdcrypto/md5_transform.c
new file mode 100644
index 0000000..2449b58
--- /dev/null
+++ b/src/libstdcrypto/md5_transform.c
@@ -0,0 +1,91 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include "md5-internal.h"
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+void md5_transform (uint32 *buf /* 4 uint32s */, uint32 const *in /* 16 uint32s */)
+{
+ register uint32 a = buf[0], b = buf[1], c = buf[2], d = buf[3] ;
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7) ;
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12) ;
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17) ;
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22) ;
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7) ;
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12) ;
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17) ;
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22) ;
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7) ;
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12) ;
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17) ;
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22) ;
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7) ;
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12) ;
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17) ;
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22) ;
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5) ;
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9) ;
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14) ;
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20) ;
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5) ;
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9) ;
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14) ;
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20) ;
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5) ;
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9) ;
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14) ;
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20) ;
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5) ;
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9) ;
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14) ;
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20) ;
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4) ;
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11) ;
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16) ;
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23) ;
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4) ;
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11) ;
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16) ;
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23) ;
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4) ;
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11) ;
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16) ;
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23) ;
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4) ;
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11) ;
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16) ;
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23) ;
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6) ;
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10) ;
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15) ;
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21) ;
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6) ;
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10) ;
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15) ;
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21) ;
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6) ;
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10) ;
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15) ;
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21) ;
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6) ;
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10) ;
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15) ;
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21) ;
+
+ buf[0] += a ;
+ buf[1] += b ;
+ buf[2] += c ;
+ buf[3] += d ;
+}
diff --git a/src/libstdcrypto/md5_update.c b/src/libstdcrypto/md5_update.c
new file mode 100644
index 0000000..63fdea3
--- /dev/null
+++ b/src/libstdcrypto/md5_update.c
@@ -0,0 +1,37 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/md5.h>
+#include "md5-internal.h"
+
+void md5_update (MD5Schedule_ref ctx, char const *s, unsigned int len)
+{
+ register uint32 t = ctx->bits[0] ;
+ if ((ctx->bits[0] = t + (len << 3)) < t)
+ ctx->bits[1]++ ;
+ ctx->bits[1] += len >> 29 ;
+ t = (t >> 3) & 0x3f ;
+ if (t)
+ {
+ unsigned char *p = ctx->in + t ;
+ t = 64 - t ;
+ if (len < t)
+ {
+ byte_copy((char *)p, len, s) ;
+ return ;
+ }
+ byte_copy((char *)p, t, s) ;
+ uint32_little_endian((char *)ctx->in, 16) ;
+ md5_transform(ctx->buf, (uint32 *)ctx->in) ;
+ s += t ; len -= t ;
+ }
+ while (len >= 64)
+ {
+ byte_copy((char *)ctx->in, 64, s) ;
+ uint32_little_endian((char *)ctx->in, 16) ;
+ md5_transform(ctx->buf, (uint32 *)ctx->in) ;
+ s += 64 ; len -= 64 ;
+ }
+ byte_copy((char *)ctx->in, len, s) ;
+}
diff --git a/src/libstdcrypto/rc4.c b/src/libstdcrypto/rc4.c
new file mode 100644
index 0000000..7ead2c6
--- /dev/null
+++ b/src/libstdcrypto/rc4.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+/* Thanks to Thomas Pornin <pornin@bolet.org> */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/rc4.h>
+
+void rc4 (RC4Schedule_ref r, char const *in, char *out, unsigned int n)
+{
+ register unsigned int i = 0 ;
+ for (; i < n ; i++)
+ {
+ register unsigned char t ;
+ r->x = T8(r->x + 1) ;
+ t = r->tab[r->x] ;
+ r->y = T8(r->y + t) ;
+ r->tab[r->x] = r->tab[r->y] ;
+ r->tab[r->y] = t ;
+ out[i] = (unsigned char)in[i] ^ T8(r->tab[r->x] + r->tab[r->y]) ;
+ }
+}
diff --git a/src/libstdcrypto/rc4_init.c b/src/libstdcrypto/rc4_init.c
new file mode 100644
index 0000000..d6f8c20
--- /dev/null
+++ b/src/libstdcrypto/rc4_init.c
@@ -0,0 +1,26 @@
+/* ISC license. */
+/* Thanks to Thomas Pornin <pornin@bolet.org> */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/rc4.h>
+
+void rc4_init (RC4Schedule_ref r, char const *key, unsigned int ksize)
+{
+ register unsigned int i = 0, j = 0 ;
+ register unsigned char c = 0;
+
+ r->x = r->y = 0 ;
+ for (; i < 256 ; i++) r->tab[i] = i ;
+ for (i = 0 ; i < 256 ; i++)
+ {
+ unsigned char t = r->tab[i] ;
+ c = T8(c + (unsigned char)key[j] + t) ;
+ r->tab[i] = r->tab[c] ;
+ r->tab[c] = t ;
+ if (++j == ksize) j = 0 ;
+ }
+ {
+ char tmp[RC4_THROWAWAY] ;
+ rc4(r, tmp, tmp, RC4_THROWAWAY) ;
+ }
+}
diff --git a/src/libstdcrypto/sha1-internal.h b/src/libstdcrypto/sha1-internal.h
new file mode 100644
index 0000000..eae3947
--- /dev/null
+++ b/src/libstdcrypto/sha1-internal.h
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#ifndef SHA1_INTERNAL_H
+#define SHA1_INTERNAL_H
+
+#include <skalibs/uint32.h>
+#include <skalibs/sha1.h>
+
+extern void sha1_feed (SHA1Schedule_ref, unsigned char) ;
+extern void sha1_transform (uint32 * /* 5 uint32s */, uint32 const * /* 16 uint32s */) ;
+
+#endif
diff --git a/src/libstdcrypto/sha1_feed.c b/src/libstdcrypto/sha1_feed.c
new file mode 100644
index 0000000..208cebd
--- /dev/null
+++ b/src/libstdcrypto/sha1_feed.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/sha1.h>
+#include "sha1-internal.h"
+
+void sha1_feed (SHA1Schedule_ref ctx, unsigned char inb)
+{
+ register uint32 tmp ;
+
+ ctx->in[ctx->b>>2] <<= 8 ;
+ ctx->in[ctx->b>>2] |= T8(inb) ;
+ if (++ctx->b >= 64)
+ {
+ register unsigned int i = 0 ;
+ sha1_transform(ctx->buf, ctx->in) ;
+ ctx->b = 0 ;
+ for (i = 0 ; i < 16 ; i++) ctx->in[i] = 0 ;
+ }
+ tmp = ctx->bits[0] ;
+ ctx->bits[0] += 8 ;
+ if (tmp > ctx->bits[0]) ctx->bits[1]++ ;
+}
diff --git a/src/libstdcrypto/sha1_final.c b/src/libstdcrypto/sha1_final.c
new file mode 100644
index 0000000..4af2efb
--- /dev/null
+++ b/src/libstdcrypto/sha1_final.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/sha1.h>
+#include "sha1-internal.h"
+
+void sha1_final (SHA1Schedule_ref ctx, char *digest)
+{
+ char pack[8] ;
+ register unsigned int i = 0 ;
+ uint32_pack_big(pack, ctx->bits[1]) ;
+ uint32_pack_big(pack+4, ctx->bits[0]) ;
+ sha1_feed(ctx, 0x80) ;
+ while (ctx->b != 56) sha1_feed(ctx, 0) ;
+ sha1_update(ctx, pack, 8) ;
+ for (; i < 5 ; i++)
+ uint32_pack_big(digest + (i<<2), ctx->buf[i]) ;
+}
diff --git a/src/libstdcrypto/sha1_init.c b/src/libstdcrypto/sha1_init.c
new file mode 100644
index 0000000..bdcb5fd
--- /dev/null
+++ b/src/libstdcrypto/sha1_init.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <skalibs/sha1.h>
+
+void sha1_init (SHA1Schedule_ref ctx)
+{
+ register unsigned int i = 0 ;
+ ctx->buf[0] = 0x67452301UL ;
+ ctx->buf[1] = 0xefcdab89UL ;
+ ctx->buf[2] = 0x98badcfeUL ;
+ ctx->buf[3] = 0x10325476UL ;
+ ctx->buf[4] = 0xc3d2e1f0UL ;
+ ctx->bits[0] = ctx->bits[1] = 0 ;
+ for (; i < 16 ; i++) ctx->in[i] = 0 ;
+ ctx->b = 0 ;
+}
diff --git a/src/libstdcrypto/sha1_transform.c b/src/libstdcrypto/sha1_transform.c
new file mode 100644
index 0000000..bd6e624
--- /dev/null
+++ b/src/libstdcrypto/sha1_transform.c
@@ -0,0 +1,42 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include "sha1-internal.h"
+
+#define F1(x, y, z) ((x & y) | ((~x) & z))
+#define F2(x, y, z) (x ^ y ^ z)
+#define F3(x, y, z) ((x & y) | (x & z) | (y & z))
+#define F4(x, y, z) (x ^ y ^ z)
+
+#define SHA1STEP(f, data) \
+{ \
+ register uint32 tmp = e + f(b, c, d) + data + ((a<<5) | (a>>27)); \
+ e = d ; \
+ d = c ; \
+ c = (b<<30) | (b>>2) ; \
+ b = a ; \
+ a = tmp ; \
+}
+
+void sha1_transform (uint32 *buf, uint32 const *in)
+{
+ register uint32 a = buf[0], b = buf[1], c = buf[2], d = buf[3], e = buf[4] ;
+ uint32 w[80] ;
+ register unsigned int i = 0 ;
+
+ for (; i < 16 ; i++) w[i] = in[i] ;
+ for (; i < 80 ; i++)
+ {
+ w[i] = w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16] ;
+ w[i] = (w[i]<<1) | (w[i]>>31) ;
+ }
+ for (i = 0 ; i < 20 ; i++)
+ SHA1STEP(F1, w[i] + 0x5a827999UL) ;
+ for (; i < 40 ; i++)
+ SHA1STEP(F2, w[i] + 0x6ed9eba1UL) ;
+ for (; i < 60 ; i++)
+ SHA1STEP(F3, w[i] + 0x8f1bbcdcUL) ;
+ for (; i < 80 ; i++)
+ SHA1STEP(F4, w[i] + 0xca62c1d6UL) ;
+ buf[0] += a ; buf[1] += b ; buf[2] += c ; buf[3] += d ; buf[4] += e ;
+}
diff --git a/src/libstdcrypto/sha1_update.c b/src/libstdcrypto/sha1_update.c
new file mode 100644
index 0000000..1b3c4de
--- /dev/null
+++ b/src/libstdcrypto/sha1_update.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/sha1.h>
+#include "sha1-internal.h"
+
+void sha1_update (SHA1Schedule_ref ctx, char const *buf, unsigned int len)
+{
+ register unsigned int i = 0 ;
+ for (; i < len ; i++) sha1_feed(ctx, (unsigned char)buf[i]) ;
+}
diff --git a/src/libstdcrypto/sha256-internal.h b/src/libstdcrypto/sha256-internal.h
new file mode 100644
index 0000000..377e6ef
--- /dev/null
+++ b/src/libstdcrypto/sha256-internal.h
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#ifndef SHA256_INTERNAL_H
+#define SHA256_INTERNAL_H
+
+#include <skalibs/uint32.h>
+#include <skalibs/sha256.h>
+
+extern void sha256_feed (SHA256Schedule_ref, unsigned char) ;
+extern void sha256_transform (uint32 *, uint32 const *) ;
+
+#endif
diff --git a/src/libstdcrypto/sha256_feed.c b/src/libstdcrypto/sha256_feed.c
new file mode 100644
index 0000000..5533d75
--- /dev/null
+++ b/src/libstdcrypto/sha256_feed.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/sha256.h>
+#include "sha256-internal.h"
+
+void sha256_feed (SHA256Schedule_ref ctx, unsigned char inb)
+{
+ register uint32 tmp ;
+ ctx->in[ctx->b>>2] <<= 8 ;
+ ctx->in[ctx->b>>2] |= T8(inb) ;
+ if (++ctx->b >= 64)
+ {
+ register unsigned int i = 0 ;
+ sha256_transform(ctx->buf, ctx->in) ;
+ ctx->b = 0 ;
+ for (; i < 16 ; i++) ctx->in[i] = 0 ;
+ }
+ tmp = ctx->bits[0] ;
+ ctx->bits[0] += 8 ;
+ if (tmp > ctx->bits[0]) ctx->bits[1]++ ;
+}
diff --git a/src/libstdcrypto/sha256_final.c b/src/libstdcrypto/sha256_final.c
new file mode 100644
index 0000000..58b938a
--- /dev/null
+++ b/src/libstdcrypto/sha256_final.c
@@ -0,0 +1,31 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/uint32.h>
+#include <skalibs/sha256.h>
+#include "sha256-internal.h"
+
+void sha256_final (SHA256Schedule_ref ctx, char *digest)
+{
+ register unsigned int i = 0 ;
+ register unsigned char *p = (unsigned char *)digest ;
+ uint32 bits[2] = { ctx->bits[0], ctx->bits[1] } ;
+
+ sha256_feed(ctx, 0x80) ;
+ while (ctx->b != 56) sha256_feed(ctx, 0) ;
+ sha256_feed(ctx, T8(bits[1]>>24)) ;
+ sha256_feed(ctx, T8(bits[1]>>16)) ;
+ sha256_feed(ctx, T8(bits[1]>>8)) ;
+ sha256_feed(ctx, T8(bits[1])) ;
+ sha256_feed(ctx, T8(bits[0]>>24)) ;
+ sha256_feed(ctx, T8(bits[0]>>16)) ;
+ sha256_feed(ctx, T8(bits[0]>>8)) ;
+ sha256_feed(ctx, T8(bits[0])) ;
+ for (; i < 8 ; i++)
+ {
+ *p++ = T8(ctx->buf[i]>>24) ;
+ *p++ = T8(ctx->buf[i]>>16) ;
+ *p++ = T8(ctx->buf[i]>>8) ;
+ *p++ = T8(ctx->buf[i]) ;
+ }
+}
diff --git a/src/libstdcrypto/sha256_init.c b/src/libstdcrypto/sha256_init.c
new file mode 100644
index 0000000..e8a9ae1
--- /dev/null
+++ b/src/libstdcrypto/sha256_init.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/sha256.h>
+
+void sha256_init (SHA256Schedule_ref ctx)
+{
+ SHA256Schedule empty = SHA256_INIT() ;
+ *ctx = empty ;
+}
diff --git a/src/libstdcrypto/sha256_transform.c b/src/libstdcrypto/sha256_transform.c
new file mode 100644
index 0000000..e61775c
--- /dev/null
+++ b/src/libstdcrypto/sha256_transform.c
@@ -0,0 +1,53 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include "sha256-internal.h"
+
+#define F1(x, y, z) ((x & y) | ((~x) & z))
+#define F2(x, y, z) ((x & y) | (x & z) | (y & z))
+
+#define ROTR(x,n) (((x)>>(n)) | ((x)<<(32-(n))))
+#define CAPITALSIGMA0(x) (ROTR(x,2)^ROTR(x,13)^ROTR(x,22))
+#define CAPITALSIGMA1(x) (ROTR(x,6)^ROTR(x,11)^ROTR(x,25))
+#define SMALLSIGMA0(x) (ROTR(x,7)^ROTR(x,18)^((x)>>3))
+#define SMALLSIGMA1(x) (ROTR(x,17)^ROTR(x,19)^((x)>>10))
+
+static uint32 const sha256_constants[64] =
+{
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
+ 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
+ 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
+ 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
+ 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
+ 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
+ 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
+ 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
+ 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
+ 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
+ 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
+ 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
+ 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+} ;
+
+void sha256_transform (uint32 *buf, uint32 const *in)
+{
+ uint32 w[64] ;
+ unsigned int i = 0 ;
+ register uint32 a = buf[0], b = buf[1], c = buf[2], d = buf[3], e = buf[4], f = buf[5], g = buf[6], h = buf[7] ;
+
+ for (; i < 16 ; i++) w[i] = in[i] ;
+ for (; i < 64 ; i++)
+ w[i] = SMALLSIGMA1(w[i-2]) + w[i-7] + SMALLSIGMA0(w[i-15]) + w[i-16] ;
+ for (i = 0 ; i < 64 ; i++)
+ {
+ uint32 temp1 = h + CAPITALSIGMA1(e) + F1(e, f, g) + sha256_constants[i] + w[i] ;
+ uint32 temp2 = CAPITALSIGMA0(a) + F2(a, b, c) ;
+ h = g ; g = f ; f = e ; e = d + temp1 ;
+ d = c ; c = b ; b = a ; a = temp1 + temp2 ;
+ }
+ buf[0] += a ; buf[1] += b ; buf[2] += c ; buf[3] += d ;
+ buf[4] += e ; buf[5] += f ; buf[6] += g ; buf[7] += h ;
+}
diff --git a/src/libstdcrypto/sha256_update.c b/src/libstdcrypto/sha256_update.c
new file mode 100644
index 0000000..c87644e
--- /dev/null
+++ b/src/libstdcrypto/sha256_update.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/sha256.h>
+#include "sha256-internal.h"
+
+void sha256_update (SHA256Schedule_ref ctx, char const *buf, unsigned int len)
+{
+ register unsigned int i = 0 ;
+ for (; i < len ; i++) sha256_feed(ctx, (unsigned char)buf[i]) ;
+}
diff --git a/src/libstddjb/absolutepath.c b/src/libstddjb/absolutepath.c
new file mode 100644
index 0000000..9a7a19f
--- /dev/null
+++ b/src/libstddjb/absolutepath.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/skamisc.h>
+#include <skalibs/djbunix.h>
+
+int sarealpath (stralloc *sa, char const *path)
+{
+ return sarealpath_tmp(sa, path, &satmp) ;
+}
diff --git a/src/libstddjb/absolutepath_tmp.c b/src/libstddjb/absolutepath_tmp.c
new file mode 100644
index 0000000..79a613a
--- /dev/null
+++ b/src/libstddjb/absolutepath_tmp.c
@@ -0,0 +1,62 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+
+int sarealpath_tmp (stralloc *sa, char const *path, stralloc *tmp)
+{
+ unsigned int tmpbase = tmp->len ;
+ unsigned int base = sa->len ;
+ unsigned int loop = 48 ;
+ int fdhere ;
+ int wasnull = !sa->s ;
+
+ if (!path) return (errno = EINVAL, -1) ;
+ if (!stralloc_cats(sa, path)) return -1 ;
+ fdhere = open_read(".") ;
+ if (fdhere == -1)
+ {
+ if (wasnull) stralloc_free(sa) ; else sa->len = base ;
+ return -1 ;
+ }
+
+ do
+ {
+ tmp->len = tmpbase ;
+ if (!loop--) { errno = ELOOP ; goto err ; }
+ if (!sadirname(tmp, sa->s + base, sa->len - base)
+ || !stralloc_0(tmp)
+ || (chdir(tmp->s + tmpbase) == -1))
+ goto err ;
+ tmp->len = tmpbase ;
+ if (!sabasename(tmp, sa->s + base, sa->len - base)
+ || !stralloc_0(tmp)) goto err ;
+ sa->len = base ;
+ }
+ while (sareadlink(sa, tmp->s + tmpbase) >= 0) ;
+
+ if ((errno != EINVAL)
+ || (sagetcwd(sa) == -1)
+ || ((sa->len > base + 1) && !stralloc_catb(sa, "/", 1))
+ || ((--tmp->len > tmpbase) && (tmp->s[tmpbase] != '/') && !stralloc_catb(sa, tmp->s + tmpbase, tmp->len - tmpbase)))
+ goto err ;
+
+ tmp->len = tmpbase ;
+ fd_chdir(fdhere) ;
+ fd_close(fdhere) ;
+ return 0 ;
+
+err:
+ {
+ register int e = errno ;
+ tmp->len = tmpbase ;
+ fd_chdir(fdhere) ;
+ fd_close(fdhere) ;
+ if (wasnull) stralloc_free(sa) ; else sa->len = base ;
+ errno = e ;
+ }
+ return -1 ;
+}
diff --git a/src/libstddjb/alloc-internal.h b/src/libstddjb/alloc-internal.h
new file mode 100644
index 0000000..918b5df
--- /dev/null
+++ b/src/libstddjb/alloc-internal.h
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#ifndef ALLOC_0_H
+#define ALLOC_0_H
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/alloc.h>
+
+#ifdef SKALIBS_HASMALLOC0
+
+#include <stdlib.h>
+
+#define alloc_0 (aligned_char_ref)malloc(0)
+
+#else
+
+extern aligned_char_ref alloc_0 ;
+
+#endif
+
+#endif
diff --git a/src/libstddjb/alloc.c b/src/libstddjb/alloc.c
new file mode 100644
index 0000000..e3f89dd
--- /dev/null
+++ b/src/libstddjb/alloc.c
@@ -0,0 +1,49 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <skalibs/sysdeps.h>
+#include <skalibs/alloc.h>
+#include "alloc-internal.h"
+
+#ifdef DEBUG_ALLOC
+# include "buffer.h"
+# include "strerr2.h"
+# include "lolstdio.h"
+# define PLM(...) (bprintf(buffer_2, "%s: debug_alloc: ", PROG), bprintf(buffer_2, __VA_ARGS__), buffer_putflush(buffer_2, "\n", 1))
+#endif
+
+aligned_char_ref alloc (unsigned int n)
+{
+ register aligned_char_ref p = n ? (aligned_char_ref)malloc(n) : (aligned_char_ref)alloc_0 ;
+#ifdef DEBUG_ALLOC
+ static unsigned int counter = 0 ;
+ PLM("alloc(%u): %p. Allocated: %u", n, p, ++counter) ;
+#endif
+ return p ;
+}
+
+void alloc_free (void *p)
+{
+ register int e = errno ;
+#ifdef DEBUG_ALLOC
+ static unsigned int counter = 0 ;
+ PLM("alloc_free(%p). Freed: %u", p, ++counter) ;
+#endif
+#ifndef SKALIBS_HASMALLOC0
+ if (p != alloc_0)
+#endif
+ free(p) ;
+ errno = e ;
+}
+
+int alloc_realloc (aligned_char_ref *x, unsigned int n)
+{
+ aligned_char_ref y = n ? (aligned_char_ref)realloc(*x, n) : (free(*x), alloc_0) ;
+#ifdef DEBUG_ALLOC
+ PLM("alloc_realloc(&%p) -> new address = %p", *x, y) ;
+#endif
+ if (!y) return 0 ;
+ *x = y ;
+ return 1 ;
+}
diff --git a/src/libstddjb/alloc_0.c b/src/libstddjb/alloc_0.c
new file mode 100644
index 0000000..2175262
--- /dev/null
+++ b/src/libstddjb/alloc_0.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/alloc.h>
+#include "alloc-internal.h"
+
+#ifndef SKALIBS_HASMALLOC0
+
+#define ALIGNMENT 16
+static union { unsigned char blah[ALIGNMENT] ; long double ld ; } const zeroblock ;
+aligned_char_ref alloc_0 = (aligned_char_ref)(&zeroblock) ;
+
+#endif
diff --git a/src/libstddjb/allread.c b/src/libstddjb/allread.c
new file mode 100644
index 0000000..9f3d3bc
--- /dev/null
+++ b/src/libstddjb/allread.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/allreadwrite.h>
+
+unsigned int allread (int fd, char *buf, unsigned int len)
+{
+ return allreadwrite(&fd_read, fd, buf, len) ;
+}
diff --git a/src/libstddjb/allreadwrite.c b/src/libstddjb/allreadwrite.c
new file mode 100644
index 0000000..7e7867b
--- /dev/null
+++ b/src/libstddjb/allreadwrite.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+
+unsigned int allreadwrite (iofunc_t_ref op, int fd, register char *buf, register unsigned int len)
+{
+ register unsigned int written = 0 ;
+ while (len)
+ {
+ register int w = (*op)(fd, buf, len) ;
+ if (!w) errno = EPIPE ;
+ if (w <= 0) break ;
+ written += w ;
+ buf += w ;
+ len -= w ;
+ }
+ return written ;
+}
diff --git a/src/libstddjb/allwrite.c b/src/libstddjb/allwrite.c
new file mode 100644
index 0000000..61c8ad7
--- /dev/null
+++ b/src/libstddjb/allwrite.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/allreadwrite.h>
+
+unsigned int allwrite (int fd, char const *buf, unsigned int len)
+{
+ return allreadwrite((iofunc_t_ref)&fd_write, fd, (char *)buf, len) ;
+}
diff --git a/src/libstddjb/baprintf.c b/src/libstddjb/baprintf.c
new file mode 100644
index 0000000..63ea5a7
--- /dev/null
+++ b/src/libstddjb/baprintf.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <stdarg.h>
+#include <skalibs/bufalloc.h>
+#include <skalibs/lolstdio.h>
+
+int baprintf (bufalloc *ba, char const *format, ...)
+{
+ va_list args ;
+ int r ;
+ va_start(args, format) ;
+ r = vbaprintf(ba, format, args) ;
+ va_end(args) ;
+ return r ;
+}
diff --git a/src/libstddjb/basename.c b/src/libstddjb/basename.c
new file mode 100644
index 0000000..4eb4080
--- /dev/null
+++ b/src/libstddjb/basename.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+
+char *basename (char *s)
+{
+ static stralloc basename_sa = STRALLOC_ZERO ;
+ static char dot0[2] = "." ;
+ char *dot = dot0 ;
+ if (!s) return dot ;
+ basename_sa.len = 0 ;
+ if (!sabasename(&basename_sa, s, str_len(s))) return 0 ;
+ if (!stralloc_0(&basename_sa)) return 0 ;
+ return basename_sa.s ;
+}
diff --git a/src/libstddjb/bitarray_and.c b/src/libstddjb/bitarray_and.c
new file mode 100644
index 0000000..d2f491e
--- /dev/null
+++ b/src/libstddjb/bitarray_and.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/bitarray.h>
+
+void bitarray_and (unsigned char *c, unsigned char const *a, unsigned char const *b, unsigned int n)
+{
+ unsigned int len = bitarray_div8(n) ;
+ register unsigned int i = 0 ;
+ for (; i < len ; i++) c[i] = a[i] & b[i] ;
+}
diff --git a/src/libstddjb/bitarray_clearsetn.c b/src/libstddjb/bitarray_clearsetn.c
new file mode 100644
index 0000000..b3f46f1
--- /dev/null
+++ b/src/libstddjb/bitarray_clearsetn.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <skalibs/bitarray.h>
+
+void bitarray_clearsetn (register unsigned char *s, register unsigned int a, register unsigned int b, register int h)
+{
+ if (!b) return ;
+ b += a ;
+ if ((a >> 3) == ((b-1) >> 3))
+ {
+ register unsigned char mask = ((1 << (a & 7)) - 1) ^ ((1 << (b & 7)) - 1) ;
+ if (h) s[a>>3] |= mask ; else s[a>>3] &= ~mask ;
+ }
+ else
+ {
+ register unsigned char mask = ~((1 << (a & 7)) - 1) ;
+ register unsigned int i = (a>>3) + 1 ;
+ if (h) s[a>>3] |= mask ; else s[a>>3] &= ~mask ;
+ mask = h ? 0xff : 0x00 ;
+ for (; i < b>>3 ; i++) s[i] = mask ;
+ mask = (1 << (b & 7)) - 1 ;
+ if (h) s[b>>3] |= mask ; else s[b>>3] &= ~mask ;
+ }
+}
diff --git a/src/libstddjb/bitarray_firstclear.c b/src/libstddjb/bitarray_firstclear.c
new file mode 100644
index 0000000..80b6fbb
--- /dev/null
+++ b/src/libstddjb/bitarray_firstclear.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/bitarray.h>
+
+unsigned int bitarray_firstclear (register unsigned char const *s, unsigned int max)
+{
+ unsigned int n = bitarray_div8(max) ;
+ register unsigned int i = 0 ;
+ for (; i < n ; i++) if (s[i] != 0xffU) break ;
+ if (i == n) return max ;
+ i <<= 3 ;
+ while ((i < max) && bitarray_peek(s, i)) i++ ;
+ return i ;
+}
diff --git a/src/libstddjb/bitarray_firstset.c b/src/libstddjb/bitarray_firstset.c
new file mode 100644
index 0000000..de3d27e
--- /dev/null
+++ b/src/libstddjb/bitarray_firstset.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/bitarray.h>
+
+unsigned int bitarray_firstset (register unsigned char const *s, unsigned int max)
+{
+ unsigned int n = bitarray_div8(max) ;
+ register unsigned int i = 0 ;
+ for (; i < n ; i++) if (s[i]) break ;
+ if (i == n) return max ;
+ i <<= 3 ;
+ while ((i < max) && !bitarray_peek(s, i)) i++ ;
+ return i ;
+}
diff --git a/src/libstddjb/bitarray_not.c b/src/libstddjb/bitarray_not.c
new file mode 100644
index 0000000..4bd95ad
--- /dev/null
+++ b/src/libstddjb/bitarray_not.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/bitarray.h>
+
+void bitarray_not (register unsigned char *s, register unsigned int a, register unsigned int b)
+{
+ if (!b) return ;
+ b += a ;
+ if ((a >> 3) == ((b-1) >> 3))
+ s[a>>3] ^= ((1 << (a & 7)) - 1) ^ ((a << (b & 7)) - 1) ;
+ else
+ {
+ register unsigned int i = (a>>3) + 1 ;
+ s[a>>3] ^= ~((1 << (a & 7)) - 1) ;
+ for (; i < (b>>3) - 1 ; i++) s[i] = ~s[i] ;
+ s[b>>3] ^= (1 << (b & 7)) - 1 ;
+ }
+}
diff --git a/src/libstddjb/bitarray_or.c b/src/libstddjb/bitarray_or.c
new file mode 100644
index 0000000..9e9e6b3
--- /dev/null
+++ b/src/libstddjb/bitarray_or.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/bitarray.h>
+
+void bitarray_or (unsigned char *c, unsigned char const *a, unsigned char const *b, unsigned int n)
+{
+ unsigned int len = bitarray_div8(n) ;
+ register unsigned int i = 0 ;
+ for (; i < len ; i++) c[i] = a[i] | b[i] ;
+}
diff --git a/src/libstddjb/bitarray_testandpoke.c b/src/libstddjb/bitarray_testandpoke.c
new file mode 100644
index 0000000..5075f1d
--- /dev/null
+++ b/src/libstddjb/bitarray_testandpoke.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/bitarray.h>
+
+int bitarray_testandpoke (register unsigned char *s, register unsigned int n, register int h)
+{
+ register unsigned char mask = 1 << (n & 7) ;
+ register unsigned char c = s[n>>3] ;
+ s[n>>3] = h ? c | mask : c & ~mask ;
+ return (c & mask) ? 1 : 0 ;
+}
diff --git a/src/libstddjb/bitarray_xor.c b/src/libstddjb/bitarray_xor.c
new file mode 100644
index 0000000..8b16f25
--- /dev/null
+++ b/src/libstddjb/bitarray_xor.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/bitarray.h>
+
+void bitarray_xor (unsigned char *c, unsigned char const *a, unsigned char const *b, unsigned int n)
+{
+ unsigned int len = bitarray_div8(n) ;
+ register unsigned int i = 0 ;
+ for (; i < len ; i++) c[i] = a[i] ^ b[i] ;
+}
diff --git a/src/libstddjb/bprintf.c b/src/libstddjb/bprintf.c
new file mode 100644
index 0000000..56617ad
--- /dev/null
+++ b/src/libstddjb/bprintf.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <stdarg.h>
+#include <skalibs/buffer.h>
+#include <skalibs/lolstdio.h>
+
+int bprintf (buffer *b, char const *format, ...)
+{
+ va_list args ;
+ int r ;
+ va_start(args, format) ;
+ r = vbprintf(b, format, args) ;
+ va_end(args) ;
+ return r ;
+}
diff --git a/src/libstddjb/bufalloc_1.c b/src/libstddjb/bufalloc_1.c
new file mode 100644
index 0000000..6e636ca
--- /dev/null
+++ b/src/libstddjb/bufalloc_1.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/allreadwrite.h>
+#include <skalibs/bufalloc.h>
+
+static bufalloc b = BUFALLOC_INIT(&fd_write, 1) ;
+bufalloc_ref bufalloc_1 = &b ;
diff --git a/src/libstddjb/bufalloc_2.c b/src/libstddjb/bufalloc_2.c
new file mode 100644
index 0000000..bcf97da
--- /dev/null
+++ b/src/libstddjb/bufalloc_2.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/allreadwrite.h>
+#include <skalibs/bufalloc.h>
+
+static bufalloc b = BUFALLOC_INIT(&fd_write, 2) ;
+bufalloc_ref bufalloc_2 = &b ;
diff --git a/src/libstddjb/bufalloc_clean.c b/src/libstddjb/bufalloc_clean.c
new file mode 100644
index 0000000..28bd35e
--- /dev/null
+++ b/src/libstddjb/bufalloc_clean.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/bufalloc.h>
+
+void bufalloc_clean (register bufalloc_ref ba)
+{
+ if (ba->p)
+ {
+ byte_copy(ba->x.s, ba->x.len - ba->p, ba->x.s + ba->p) ;
+ ba->x.len -= ba->p ;
+ ba->p = 0 ;
+ }
+}
diff --git a/src/libstddjb/bufalloc_flush.c b/src/libstddjb/bufalloc_flush.c
new file mode 100644
index 0000000..49b2eb1
--- /dev/null
+++ b/src/libstddjb/bufalloc_flush.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/allreadwrite.h>
+#include <skalibs/bufalloc.h>
+
+int bufalloc_flush (bufalloc_ref ba)
+{
+ ba->p += allreadwrite((iofunc_t_ref)ba->op, ba->fd, ba->x.s + ba->p, ba->x.len - ba->p) ;
+ bufalloc_clean(ba) ;
+ return !ba->x.len ;
+}
diff --git a/src/libstddjb/bufalloc_getfd.c b/src/libstddjb/bufalloc_getfd.c
new file mode 100644
index 0000000..d24ab88
--- /dev/null
+++ b/src/libstddjb/bufalloc_getfd.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/bufalloc.h>
+
+int bufalloc_getfd (bufalloc const *ba)
+{
+ return bufalloc_fd(ba) ;
+}
diff --git a/src/libstddjb/bufalloc_getlen.c b/src/libstddjb/bufalloc_getlen.c
new file mode 100644
index 0000000..696e41d
--- /dev/null
+++ b/src/libstddjb/bufalloc_getlen.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/bufalloc.h>
+
+unsigned int bufalloc_getlen (bufalloc const *ba)
+{
+ return bufalloc_len(ba) ;
+}
diff --git a/src/libstddjb/bufalloc_init.c b/src/libstddjb/bufalloc_init.c
new file mode 100644
index 0000000..ddb6b6b
--- /dev/null
+++ b/src/libstddjb/bufalloc_init.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/bufalloc.h>
+
+void bufalloc_init (bufalloc_ref ba, int (*op)(int, char const *, unsigned int), int fd)
+{
+ ba->x.len = 0 ;
+ ba->op = op ;
+ ba->fd = fd ;
+ ba->p = 0 ;
+}
diff --git a/src/libstddjb/buffer_0.c b/src/libstddjb/buffer_0.c
new file mode 100644
index 0000000..50dc6dc
--- /dev/null
+++ b/src/libstddjb/buffer_0.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/buffer.h>
+
+static char buf[BUFFER_INSIZE] ;
+buffer buffer_0_ = BUFFER_INIT(&buffer_read, 0, buf, BUFFER_INSIZE) ;
diff --git a/src/libstddjb/buffer_0f1.c b/src/libstddjb/buffer_0f1.c
new file mode 100644
index 0000000..685577c
--- /dev/null
+++ b/src/libstddjb/buffer_0f1.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/buffer.h>
+
+static char buf[BUFFER_INSIZE] ;
+buffer buffer_0f1_ = BUFFER_INIT(&buffer_flush1read, 0, buf, BUFFER_INSIZE) ;
diff --git a/src/libstddjb/buffer_0small.c b/src/libstddjb/buffer_0small.c
new file mode 100644
index 0000000..849edec
--- /dev/null
+++ b/src/libstddjb/buffer_0small.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/buffer.h>
+
+static char buf[BUFFER_INSIZE_SMALL] ;
+buffer buffer_0small_ = BUFFER_INIT(&buffer_read, 0, buf, BUFFER_INSIZE_SMALL) ;
diff --git a/src/libstddjb/buffer_1.c b/src/libstddjb/buffer_1.c
new file mode 100644
index 0000000..088d421
--- /dev/null
+++ b/src/libstddjb/buffer_1.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/buffer.h>
+
+static char buf[BUFFER_OUTSIZE] ;
+buffer buffer_1_ = BUFFER_INIT(&buffer_write, 1, buf, BUFFER_OUTSIZE) ;
diff --git a/src/libstddjb/buffer_1small.c b/src/libstddjb/buffer_1small.c
new file mode 100644
index 0000000..6e9cfa2
--- /dev/null
+++ b/src/libstddjb/buffer_1small.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/buffer.h>
+
+static char buf[BUFFER_OUTSIZE_SMALL] ;
+buffer buffer_1small_ = BUFFER_INIT(&buffer_write, 1, buf, BUFFER_OUTSIZE_SMALL) ;
diff --git a/src/libstddjb/buffer_2.c b/src/libstddjb/buffer_2.c
new file mode 100644
index 0000000..9bc4e3f
--- /dev/null
+++ b/src/libstddjb/buffer_2.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/buffer.h>
+
+static char buf[BUFFER_ERRSIZE] ;
+buffer buffer_2_ = BUFFER_INIT(&buffer_write, 2, buf, BUFFER_ERRSIZE) ;
diff --git a/src/libstddjb/buffer_fill.c b/src/libstddjb/buffer_fill.c
new file mode 100644
index 0000000..c158abe
--- /dev/null
+++ b/src/libstddjb/buffer_fill.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/cbuffer.h>
+
+int buffer_fill (buffer *b)
+{
+ siovec_t v[2] ;
+ register int r ;
+ if (buffer_isfull(b)) return (errno = ENOBUFS, -1) ;
+ buffer_wpeek(b, v) ;
+ r = (*b->op)(b->fd, v, 2, b->aux) ;
+ if (r <= 0) return r ;
+ cbuffer_WSEEK(&b->c, r) ;
+ return r ;
+}
diff --git a/src/libstddjb/buffer_flush.c b/src/libstddjb/buffer_flush.c
new file mode 100644
index 0000000..ca6ca6b
--- /dev/null
+++ b/src/libstddjb/buffer_flush.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/cbuffer.h>
+#include <skalibs/siovec.h>
+
+int buffer_flush (buffer *b)
+{
+ for (;;)
+ {
+ siovec_t v[2] ;
+ register int r ;
+ buffer_rpeek(b, v) ;
+ if (!v[0].len && !v[1].len) break ;
+ r = (*b->op)(b->fd, v, 2, b->aux) ;
+ if (r <= 0) return 0 ;
+ cbuffer_RSEEK(&b->c, r) ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/buffer_flush1read.c b/src/libstddjb/buffer_flush1read.c
new file mode 100644
index 0000000..9dcdf81
--- /dev/null
+++ b/src/libstddjb/buffer_flush1read.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/siovec.h>
+
+int buffer_flush1read (int fd, siovec_t const *v, unsigned int n, void *aux)
+{
+ if (!buffer_flush(buffer_1)) return -1 ;
+ return buffer_read(fd, v, n, aux) ;
+}
diff --git a/src/libstddjb/buffer_get.c b/src/libstddjb/buffer_get.c
new file mode 100644
index 0000000..dcfa8e7
--- /dev/null
+++ b/src/libstddjb/buffer_get.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+
+int buffer_get (buffer *b, char *s, unsigned int len)
+{
+ unsigned int w = 0 ;
+ register int r = buffer_getall(b, s, len, &w) ;
+ return r == -1 ? errno == EPIPE ? (errno = 0, 0) : -1 :
+ !r ? (errno = EWOULDBLOCK, -1) : (int)w ;
+}
diff --git a/src/libstddjb/buffer_getall.c b/src/libstddjb/buffer_getall.c
new file mode 100644
index 0000000..34db9df
--- /dev/null
+++ b/src/libstddjb/buffer_getall.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/buffer.h>
+
+int buffer_getall (buffer_ref b, char *buf, unsigned int len, unsigned int *w)
+{
+ if (*w > len) return (errno = EINVAL, -1) ;
+ *w += buffer_getnofill(b, buf + *w, len - *w) ;
+ while (*w < len)
+ {
+ register int r = sanitize_read(buffer_fill(b)) ;
+ if (r <= 0) return r ;
+ *w += buffer_getnofill(b, buf + *w, len - *w) ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/buffer_getallnf.c b/src/libstddjb/buffer_getallnf.c
new file mode 100644
index 0000000..8a97a31
--- /dev/null
+++ b/src/libstddjb/buffer_getallnf.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+
+int buffer_getallnofill (buffer_ref b, char *s, unsigned int len)
+{
+ register unsigned int r = buffer_getnofill(b, s, len) ;
+ if (r < len)
+ {
+ buffer_unget(b, r) ;
+ return (errno = ENOBUFS, 0) ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/buffer_getfd.c b/src/libstddjb/buffer_getfd.c
new file mode 100644
index 0000000..224beec
--- /dev/null
+++ b/src/libstddjb/buffer_getfd.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+
+int buffer_getfd (buffer const *b)
+{
+ return buffer_fd(b) ;
+}
diff --git a/src/libstddjb/buffer_getlen.c b/src/libstddjb/buffer_getlen.c
new file mode 100644
index 0000000..73289a7
--- /dev/null
+++ b/src/libstddjb/buffer_getlen.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+
+unsigned int buffer_getlen (buffer const *b)
+{
+ return buffer_len(b) ;
+}
diff --git a/src/libstddjb/buffer_getv.c b/src/libstddjb/buffer_getv.c
new file mode 100644
index 0000000..0f8f848
--- /dev/null
+++ b/src/libstddjb/buffer_getv.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/diuint.h>
+#include <skalibs/siovec.h>
+
+int buffer_getv (buffer *b, siovec_t const *v, unsigned int n)
+{
+ diuint w = DIUINT_ZERO ;
+ register int r = buffer_getvall(b, v, n, &w) ;
+ return r == -1 ? errno == EPIPE ? (errno = 0, 0) : -1 :
+ !r ? (errno = EWOULDBLOCK, -1) :
+ (int)(siovec_len(v, w.left) + w.right) ;
+}
diff --git a/src/libstddjb/buffer_getvall.c b/src/libstddjb/buffer_getvall.c
new file mode 100644
index 0000000..b6eeb46
--- /dev/null
+++ b/src/libstddjb/buffer_getvall.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/diuint.h>
+#include <skalibs/siovec.h>
+
+int buffer_getvall (buffer *b, siovec_t const *v, unsigned int n, diuint *w)
+{
+ if (w->left > n || (w->left == n && w->right) || w->right >= v[w->left].len)
+ return (errno = EINVAL, -1) ;
+ for (; w->left < n ; w->left++, w->right = 0)
+ {
+ register int r = buffer_getall(b, v[w->left].s, v[w->left].len, &w->right) ;
+ if (r <= 0) return r ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/buffer_getvallnf.c b/src/libstddjb/buffer_getvallnf.c
new file mode 100644
index 0000000..2f4b82d
--- /dev/null
+++ b/src/libstddjb/buffer_getvallnf.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/siovec.h>
+
+int buffer_getvallnofill (buffer_ref b, siovec_t const *v, unsigned int n)
+{
+ register unsigned int r = buffer_getvnofill(b, v, n) ;
+ if (r < siovec_len(v, n))
+ {
+ buffer_unget(b, r) ;
+ return (errno = ENOBUFS, 0) ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/buffer_init.c b/src/libstddjb/buffer_init.c
new file mode 100644
index 0000000..09d4910
--- /dev/null
+++ b/src/libstddjb/buffer_init.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+
+int buffer_init_aux (buffer *b, buffer_io_func_t *op, int fd, char *s, unsigned int len, void *aux)
+{
+ if (!cbuffer_init(&b->c, s, len)) return 0 ;
+ b->fd = fd ;
+ b->op = op ;
+ b->aux = aux ;
+ return 1 ;
+}
diff --git a/src/libstddjb/buffer_put.c b/src/libstddjb/buffer_put.c
new file mode 100644
index 0000000..56baaa7
--- /dev/null
+++ b/src/libstddjb/buffer_put.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+
+int buffer_put (buffer *b, char const *s, unsigned int len)
+{
+ unsigned int w = 0 ;
+ if (!buffer_putall(b, s, len, &w)) return -1 ;
+ return (int)w ;
+}
diff --git a/src/libstddjb/buffer_putall.c b/src/libstddjb/buffer_putall.c
new file mode 100644
index 0000000..16facc2
--- /dev/null
+++ b/src/libstddjb/buffer_putall.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+
+int buffer_putall (buffer *b, char const *s, unsigned int len, unsigned int *written)
+{
+ if (*written > len) return (errno = EINVAL, 0) ;
+ for (;;)
+ {
+ *written += buffer_putnoflush(b, s + *written, len - *written) ;
+ if (*written >= len) return 1 ;
+ buffer_flush(b) ;
+ if (buffer_isfull(b)) return 0 ;
+ }
+}
diff --git a/src/libstddjb/buffer_putallnf.c b/src/libstddjb/buffer_putallnf.c
new file mode 100644
index 0000000..1cf3c5e
--- /dev/null
+++ b/src/libstddjb/buffer_putallnf.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+
+int buffer_putallnoflush (buffer *b, char const *s, unsigned int len)
+{
+ register unsigned int r = buffer_putnoflush(b, s, len) ;
+ if (r < len)
+ {
+ buffer_unput(b, r) ;
+ return (errno = ENOBUFS, 0) ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/buffer_putflush.c b/src/libstddjb/buffer_putflush.c
new file mode 100644
index 0000000..609d88b
--- /dev/null
+++ b/src/libstddjb/buffer_putflush.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+
+int buffer_putflush (buffer *b, char const *s, unsigned int len)
+{
+ int r = buffer_put(b, s, len) ;
+ if (r < 0) return -1 ;
+ if (!buffer_flush(b)) return -1 ;
+ return r ;
+}
diff --git a/src/libstddjb/buffer_putv.c b/src/libstddjb/buffer_putv.c
new file mode 100644
index 0000000..a1530d2
--- /dev/null
+++ b/src/libstddjb/buffer_putv.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/diuint.h>
+#include <skalibs/siovec.h>
+
+int buffer_putv (buffer *b, siovec_t const *v, unsigned int n)
+{
+ diuint w = DIUINT_ZERO ;
+ if (!buffer_putvall(b, v, n, &w)) return -1 ;
+ return (int)(siovec_len(v, w.left) + w.right) ;
+}
diff --git a/src/libstddjb/buffer_putvall.c b/src/libstddjb/buffer_putvall.c
new file mode 100644
index 0000000..d6297c1
--- /dev/null
+++ b/src/libstddjb/buffer_putvall.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/diuint.h>
+#include <skalibs/siovec.h>
+
+int buffer_putvall (buffer *b, siovec_t const *v, unsigned int n, diuint *w)
+{
+ if (w->left > n || (w->left == n && w->right) || w->right >= v[w->left].len)
+ return (errno = EINVAL, 0) ;
+ for (; w->left < n ; w->left++, w->right = 0)
+ if (!buffer_putall(b, v[w->left].s, v[w->left].len, &w->right)) return 0 ;
+ return 1 ;
+}
diff --git a/src/libstddjb/buffer_putvallnf.c b/src/libstddjb/buffer_putvallnf.c
new file mode 100644
index 0000000..cada660
--- /dev/null
+++ b/src/libstddjb/buffer_putvallnf.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+
+int buffer_putvallnoflush (buffer *b, siovec_t const *v, unsigned int n)
+{
+ register unsigned int r = buffer_putvnoflush(b, v, n) ;
+ if (r < siovec_len(v, n))
+ {
+ buffer_unput(b, r) ;
+ return (errno = ENOBUFS, 0) ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/buffer_putvflush.c b/src/libstddjb/buffer_putvflush.c
new file mode 100644
index 0000000..46f9e03
--- /dev/null
+++ b/src/libstddjb/buffer_putvflush.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/siovec.h>
+
+int buffer_putvflush (buffer *b, siovec_t const *v, unsigned int n)
+{
+ int r = buffer_putv(b, v, n) ;
+ if (r < 0) return -1 ;
+ if (!buffer_flush(b)) return -1 ;
+ return r ;
+}
diff --git a/src/libstddjb/buffer_read.c b/src/libstddjb/buffer_read.c
new file mode 100644
index 0000000..150bc15
--- /dev/null
+++ b/src/libstddjb/buffer_read.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/buffer.h>
+#include <skalibs/siovec.h>
+
+int buffer_read (int fd, siovec_t const *v, unsigned int n, void *aux)
+{
+ struct iovec iov[n] ;
+ iovec_from_siovec(iov, v, n) ;
+ (void)aux ;
+ return fd_readv(fd, iov, n) ;
+}
diff --git a/src/libstddjb/buffer_write.c b/src/libstddjb/buffer_write.c
new file mode 100644
index 0000000..40ffd46
--- /dev/null
+++ b/src/libstddjb/buffer_write.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/buffer.h>
+#include <skalibs/siovec.h>
+
+int buffer_write (int fd, siovec_t const *v, unsigned int n, void *aux)
+{
+ struct iovec iov[n] ;
+ iovec_from_siovec(iov, v, n) ;
+ (void)aux ;
+ return fd_writev(fd, iov, n) ;
+}
diff --git a/src/libstddjb/byte_chr.c b/src/libstddjb/byte_chr.c
new file mode 100644
index 0000000..e9caef5
--- /dev/null
+++ b/src/libstddjb/byte_chr.c
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/bytestr.h>
+
+#ifndef SKALIBS_FLAG_REPLACE_LIBC
+
+#include <string.h>
+
+unsigned int byte_chr (char const *s, unsigned int n, int c)
+{
+ register void *p = memchr(s, c, n) ;
+ return p ? (unsigned int)((char *)p - s) : n ;
+}
+
+#else
+
+unsigned int byte_chr (char const *s, unsigned int n, int c)
+{
+ register char ch = c ;
+ register char const *t = s ;
+
+ for (;;)
+ {
+ if (!n) break; if (*t == ch) break; ++t; --n;
+ if (!n) break; if (*t == ch) break; ++t; --n;
+ if (!n) break; if (*t == ch) break; ++t; --n;
+ if (!n) break; if (*t == ch) break; ++t; --n;
+ }
+ return t - s ;
+}
+
+#endif
diff --git a/src/libstddjb/byte_copy.c b/src/libstddjb/byte_copy.c
new file mode 100644
index 0000000..410fb95
--- /dev/null
+++ b/src/libstddjb/byte_copy.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+
+#ifdef SKALIBS_FLAG_REPLACE_LIBC
+
+#include <skalibs/bytestr.h>
+
+void byte_copy (register char *to, register unsigned int n, register char const *from)
+{
+ while (n--) *to++ = *from++ ;
+}
+
+#endif
diff --git a/src/libstddjb/byte_count.c b/src/libstddjb/byte_count.c
new file mode 100644
index 0000000..5e3f8af
--- /dev/null
+++ b/src/libstddjb/byte_count.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+
+unsigned int byte_count (register char const *s, register unsigned int len, register char b)
+{
+ register unsigned int n = 0 ;
+ while (len--) if (*s++ == b) n++ ;
+ return n ;
+}
diff --git a/src/libstddjb/byte_cr.c b/src/libstddjb/byte_cr.c
new file mode 100644
index 0000000..d81e7cf
--- /dev/null
+++ b/src/libstddjb/byte_cr.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+
+#ifdef SKALIBS_FLAG_REPLACE_LIBC
+
+#include <skalibs/bytestr.h>
+
+void byte_copyr (register char *to, register unsigned int n, register char const *from)
+{
+ to += n ;
+ from += n ;
+ for (;;)
+ {
+ if (!n) return; *--to = *--from; --n;
+ if (!n) return; *--to = *--from; --n;
+ if (!n) return; *--to = *--from; --n;
+ if (!n) return; *--to = *--from; --n;
+ }
+}
+
+#endif
diff --git a/src/libstddjb/byte_diff.c b/src/libstddjb/byte_diff.c
new file mode 100644
index 0000000..9e7f107
--- /dev/null
+++ b/src/libstddjb/byte_diff.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+
+#ifdef SKALIBS_FLAG_REPLACE_LIBC
+
+#include <skalibs/bytestr.h>
+
+int byte_diff (register char const *s, register unsigned int n, register char const *t)
+{
+ for (;;)
+ {
+ if (!n) return 0; if (*s != *t) break; ++s; ++t; --n;
+ if (!n) return 0; if (*s != *t) break; ++s; ++t; --n;
+ if (!n) return 0; if (*s != *t) break; ++s; ++t; --n;
+ if (!n) return 0; if (*s != *t) break; ++s; ++t; --n;
+ }
+ return ((int)(unsigned int)(unsigned char) *s)
+ - ((int)(unsigned int)(unsigned char) *t) ;
+}
+
+#endif
diff --git a/src/libstddjb/byte_in.c b/src/libstddjb/byte_in.c
new file mode 100644
index 0000000..60625c5
--- /dev/null
+++ b/src/libstddjb/byte_in.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+
+unsigned int byte_in (char const *s, register unsigned int n, register char const *sep, register unsigned int len)
+{
+ register char const *t = s ;
+ while (n--)
+ {
+ if (byte_chr(sep, len, *t) < len) break ;
+ ++t ;
+ }
+ return t - s ;
+}
diff --git a/src/libstddjb/byte_rchr.c b/src/libstddjb/byte_rchr.c
new file mode 100644
index 0000000..3564c36
--- /dev/null
+++ b/src/libstddjb/byte_rchr.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+
+unsigned int byte_rchr (register char const *s, unsigned int n, int c)
+{
+ register unsigned int i = n ;
+ register char ch = c ;
+ s += n ;
+ while (i--) if (*--s == ch) return i ;
+ return n ;
+}
diff --git a/src/libstddjb/byte_zero.c b/src/libstddjb/byte_zero.c
new file mode 100644
index 0000000..6751210
--- /dev/null
+++ b/src/libstddjb/byte_zero.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+
+#ifdef SKALIBS_FLAG_REPLACE_LIBC
+
+#include <skalibs/bytestr.h>
+
+void byte_zero (void *p, register unsigned int n)
+{
+ register char *s = (char *)p ;
+ while (n--) *s++ = 0 ;
+}
+
+#endif
diff --git a/src/libstddjb/case_diffb.c b/src/libstddjb/case_diffb.c
new file mode 100644
index 0000000..1931c0f
--- /dev/null
+++ b/src/libstddjb/case_diffb.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+
+int case_diffb (char const *s, unsigned int len, char const *t)
+{
+ register unsigned char x = 0, y = 0 ;
+ unsigned char const d = 'a' - 'A' ;
+
+ while (len-- && (x == y))
+ {
+ x = *s++ ;
+ if (('a' <= x) && (x <= 'z')) x -= d ;
+ y = *t++ ;
+ if (('a' <= y) && (y <= 'z')) y -= d ;
+ }
+ return (int)(x - y) ;
+}
diff --git a/src/libstddjb/case_diffs.c b/src/libstddjb/case_diffs.c
new file mode 100644
index 0000000..2731408
--- /dev/null
+++ b/src/libstddjb/case_diffs.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+
+int case_diffs (char const *s, char const *t)
+{
+ register unsigned char x = 1, y = 1 ;
+ unsigned char const d = 'a' - 'A' ;
+
+ while (x && (x == y))
+ {
+ x = *s++ ;
+ if (('a' <= x) && (x <= 'z')) x -= d ;
+ y = *t++ ;
+ if (('a' <= y) && (y <= 'z')) y -= d ;
+ }
+ return (int)(x - y) ;
+}
diff --git a/src/libstddjb/case_lowerb.c b/src/libstddjb/case_lowerb.c
new file mode 100644
index 0000000..9f51ed5
--- /dev/null
+++ b/src/libstddjb/case_lowerb.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+
+void case_lowerb (register char *s, unsigned int len)
+{
+ register unsigned char const d = 'a' - 'A' ;
+ while (len--)
+ {
+ if (('A' <= *s) && (*s <= 'Z')) *s += d ;
+ ++s ;
+ }
+}
diff --git a/src/libstddjb/case_lowers.c b/src/libstddjb/case_lowers.c
new file mode 100644
index 0000000..5999786
--- /dev/null
+++ b/src/libstddjb/case_lowers.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+
+void case_lowers (register char *s)
+{
+ register unsigned char const d = 'a' - 'A' ;
+ while (*s)
+ {
+ if (('A' <= *s) && (*s <= 'Z')) *s += d ;
+ ++s ;
+ }
+}
diff --git a/src/libstddjb/case_startb.c b/src/libstddjb/case_startb.c
new file mode 100644
index 0000000..cae0fb4
--- /dev/null
+++ b/src/libstddjb/case_startb.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+
+int case_startb (register char const *s, unsigned int slen, register char const *t)
+{
+ register unsigned int tlen = str_len(t) ;
+ return slen < tlen ? 0 : !case_diffb(s, tlen, t) ;
+}
diff --git a/src/libstddjb/case_str.c b/src/libstddjb/case_str.c
new file mode 100644
index 0000000..14409c3
--- /dev/null
+++ b/src/libstddjb/case_str.c
@@ -0,0 +1,32 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/sysdeps.h>
+
+#if defined(SKALIBS_HASSTRCASESTR) && !defined(SKALIBS_FLAG_REPLACE_LIBC)
+
+#include <skalibs/nonposix.h>
+#include <string.h>
+#include <skalibs/bytestr.h>
+
+unsigned int case_str (char const *haystack, char const *needle)
+{
+ register char *p = strcasestr(haystack, needle) ;
+ return p ? p - haystack : str_len(haystack) ;
+}
+
+#else
+
+#include <skalibs/bytestr.h>
+
+unsigned int case_str (char const *haystack, char const *needle)
+{
+ unsigned int nlen = str_len(needle) ;
+ register char const *p = haystack ;
+ if (!nlen) return 0 ;
+ for (; *p ; p++)
+ if (!case_diffb(p, nlen, needle)) return p - haystack ;
+ return str_len(haystack) ;
+}
+
+#endif
diff --git a/src/libstddjb/case_upperb.c b/src/libstddjb/case_upperb.c
new file mode 100644
index 0000000..54ceab4
--- /dev/null
+++ b/src/libstddjb/case_upperb.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+
+void case_upperb (register char *s, unsigned int len)
+{
+ register unsigned char const d = 'a' - 'A' ;
+ while (len--)
+ {
+ if (('a' <= *s) && (*s <= 'z')) *s -= d ;
+ ++s ;
+ }
+}
diff --git a/src/libstddjb/case_uppers.c b/src/libstddjb/case_uppers.c
new file mode 100644
index 0000000..cf2875a
--- /dev/null
+++ b/src/libstddjb/case_uppers.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+
+void case_uppers (register char *s)
+{
+ register unsigned char const d = 'a' - 'A' ;
+ while (*s)
+ {
+ if (('a' <= *s) && (*s <= 'z')) *s -= d ;
+ ++s ;
+ }
+}
diff --git a/src/libstddjb/cbuffer_get.c b/src/libstddjb/cbuffer_get.c
new file mode 100644
index 0000000..544cbb2
--- /dev/null
+++ b/src/libstddjb/cbuffer_get.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/cbuffer.h>
+#include <skalibs/siovec.h>
+
+unsigned int cbuffer_get (cbuffer_t *b, char *s, unsigned int len)
+{
+ siovec_t v[2] ;
+ cbuffer_rpeek(b, v) ;
+ return cbuffer_RSEEK(b, siovec_gather(v, 2, s, len)) ;
+}
diff --git a/src/libstddjb/cbuffer_getv.c b/src/libstddjb/cbuffer_getv.c
new file mode 100644
index 0000000..3db638f
--- /dev/null
+++ b/src/libstddjb/cbuffer_getv.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/cbuffer.h>
+#include <skalibs/siovec.h>
+
+unsigned int cbuffer_getv (cbuffer_t *b, siovec_t const *v, unsigned int n)
+{
+ siovec_t vsrc[2] ;
+ cbuffer_rpeek(b, vsrc) ;
+ return cbuffer_RSEEK(b, siovec_deal(v, n, vsrc, 2)) ;
+}
diff --git a/src/libstddjb/cbuffer_init.c b/src/libstddjb/cbuffer_init.c
new file mode 100644
index 0000000..eba4765
--- /dev/null
+++ b/src/libstddjb/cbuffer_init.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/cbuffer.h>
+
+int cbuffer_init (cbuffer_t *b, char *s, unsigned int len)
+{
+ if (len < 2) return (errno = EINVAL, 0) ;
+ b->x = s ;
+ b->a = len ;
+ b->p = b->n = 0 ;
+ return 1 ;
+}
diff --git a/src/libstddjb/cbuffer_put.c b/src/libstddjb/cbuffer_put.c
new file mode 100644
index 0000000..12f513e
--- /dev/null
+++ b/src/libstddjb/cbuffer_put.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/cbuffer.h>
+#include <skalibs/siovec.h>
+
+unsigned int cbuffer_put (cbuffer_t *b, char const *s, unsigned int len)
+{
+ siovec_t v[2] ;
+ cbuffer_wpeek(b, v) ;
+ return cbuffer_WSEEK(b, siovec_scatter(v, 2, s, len)) ;
+}
diff --git a/src/libstddjb/cbuffer_putv.c b/src/libstddjb/cbuffer_putv.c
new file mode 100644
index 0000000..66bed05
--- /dev/null
+++ b/src/libstddjb/cbuffer_putv.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/cbuffer.h>
+#include <skalibs/siovec.h>
+
+unsigned int cbuffer_putv (cbuffer_t *b, siovec_t const *v, unsigned int n)
+{
+ siovec_t vdest[2] ;
+ cbuffer_wpeek(b, vdest) ;
+ return cbuffer_WSEEK(b, siovec_deal(vdest, 2, v, n)) ;
+}
diff --git a/src/libstddjb/cbuffer_rpeek.c b/src/libstddjb/cbuffer_rpeek.c
new file mode 100644
index 0000000..22a1ef5
--- /dev/null
+++ b/src/libstddjb/cbuffer_rpeek.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <skalibs/cbuffer.h>
+#include <skalibs/siovec.h>
+
+void cbuffer_rpeek (cbuffer_t *b, siovec_t *v)
+{
+ v[0].s = b->x + b->p ;
+ if (b->n >= b->p)
+ {
+ v[0].len = b->n - b->p ;
+ v[1].s = 0 ;
+ v[1].len = 0 ;
+ }
+ else
+ {
+ v[0].len = b->a - b->p ;
+ v[1].s = b->x ;
+ v[1].len = b->n ;
+ }
+}
diff --git a/src/libstddjb/cbuffer_rseek.c b/src/libstddjb/cbuffer_rseek.c
new file mode 100644
index 0000000..4a98511
--- /dev/null
+++ b/src/libstddjb/cbuffer_rseek.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/cbuffer.h>
+
+unsigned int cbuffer_rseek (cbuffer_t *b, unsigned int len)
+{
+ register unsigned int max = cbuffer_len(b) ;
+ if (len > max) len = max ;
+ return cbuffer_RSEEK(b, len) ;
+}
diff --git a/src/libstddjb/cbuffer_unget.c b/src/libstddjb/cbuffer_unget.c
new file mode 100644
index 0000000..d1591e6
--- /dev/null
+++ b/src/libstddjb/cbuffer_unget.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/cbuffer.h>
+
+unsigned int cbuffer_unget (cbuffer_t *b, unsigned int len)
+{
+ register unsigned int max = cbuffer_available(b) ;
+ if (len > max) len = max ;
+ return cbuffer_UNGET(b, len) ;
+}
diff --git a/src/libstddjb/cbuffer_unput.c b/src/libstddjb/cbuffer_unput.c
new file mode 100644
index 0000000..8221ca0
--- /dev/null
+++ b/src/libstddjb/cbuffer_unput.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/cbuffer.h>
+
+unsigned int cbuffer_unput (cbuffer_t *b, unsigned int len)
+{
+ register unsigned int max = cbuffer_len(b) ;
+ if (len > max) len = max ;
+ return cbuffer_UNPUT(b, len) ;
+}
diff --git a/src/libstddjb/cbuffer_wpeek.c b/src/libstddjb/cbuffer_wpeek.c
new file mode 100644
index 0000000..a2c6a63
--- /dev/null
+++ b/src/libstddjb/cbuffer_wpeek.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <skalibs/cbuffer.h>
+#include <skalibs/siovec.h>
+
+void cbuffer_wpeek (cbuffer_t *b, siovec_t *v)
+{
+ unsigned int last = (b->a - 1 + b->p) % b->a ;
+ v[0].s = b->x + b->n ;
+ if (last >= b->n)
+ {
+ v[0].len = last - b->n ;
+ v[1].s = 0 ;
+ v[1].len = 0 ;
+ }
+ else
+ {
+ v[0].len = b->a - b->n ;
+ v[1].s = b->x ;
+ v[1].len = last ;
+ }
+}
diff --git a/src/libstddjb/cbuffer_wseek.c b/src/libstddjb/cbuffer_wseek.c
new file mode 100644
index 0000000..6b90ab6
--- /dev/null
+++ b/src/libstddjb/cbuffer_wseek.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/cbuffer.h>
+
+unsigned int cbuffer_wseek (cbuffer_t *b, unsigned int len)
+{
+ register unsigned int max = cbuffer_available(b) ;
+ if (len > max) len = max ;
+ return cbuffer_WSEEK(b, len) ;
+}
diff --git a/src/libstddjb/cdb_findnext.c b/src/libstddjb/cdb_findnext.c
new file mode 100644
index 0000000..2559bc2
--- /dev/null
+++ b/src/libstddjb/cdb_findnext.c
@@ -0,0 +1,67 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/uint32.h>
+#include <skalibs/cdb.h>
+
+static int match (struct cdb *c, char const *key, unsigned int len, uint32 pos)
+{
+ char buf[1024] ;
+ while (len > 0)
+ {
+ register unsigned int n = 1024 ;
+ if (n > len) n = len ;
+ if (cdb_read(c, buf, n, pos) < 0) return -1 ;
+ if (byte_diff(buf, n, key)) return 0 ;
+ pos += n ; key += n ; len -= n ;
+ }
+ return 1 ;
+}
+
+int cdb_findnext (struct cdb *c, char const *key, unsigned int len)
+{
+ char buf[8] ;
+ uint32 pos ;
+ uint32 u ;
+
+ if (!c->loop)
+ {
+ u = cdb_hash(key, len) ;
+ if (cdb_read(c, buf, 8, (u << 3) & 2047) < 0) return -1 ;
+ uint32_unpack(buf + 4, &c->hslots) ;
+ if (!c->hslots) return 0 ;
+ uint32_unpack(buf, &c->hpos) ;
+ c->khash = u ;
+ u >>= 8 ;
+ u %= c->hslots ;
+ u <<= 3 ;
+ c->kpos = c->hpos + u ;
+ }
+
+ while (c->loop < c->hslots)
+ {
+ if (cdb_read(c, buf, 8, c->kpos) < 0) return -1 ;
+ uint32_unpack(buf + 4, &pos) ;
+ if (!pos) return 0 ;
+ c->loop++ ;
+ c->kpos += 8 ;
+ if (c->kpos == c->hpos + (c->hslots << 3)) c->kpos = c->hpos ;
+ uint32_unpack(buf, &u) ;
+ if (u == c->khash)
+ {
+ if (cdb_read(c, buf, 8, pos) < 0) return -1 ;
+ uint32_unpack(buf, &u) ;
+ if (u == len)
+ switch (match(c, key, len, pos + 8))
+ {
+ case -1:
+ return -1 ;
+ case 1:
+ uint32_unpack(buf + 4, &c->dlen) ;
+ c->dpos = pos + 8 + len ;
+ return 1 ;
+ }
+ }
+ }
+ return 0 ;
+}
diff --git a/src/libstddjb/cdb_free.c b/src/libstddjb/cdb_free.c
new file mode 100644
index 0000000..dcf9675
--- /dev/null
+++ b/src/libstddjb/cdb_free.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <skalibs/cdb.h>
+
+extern void cdb_free (struct cdb *c)
+{
+ if (c->map) munmap(c->map, c->size) ;
+ *c = cdb_zero ;
+}
diff --git a/src/libstddjb/cdb_hash.c b/src/libstddjb/cdb_hash.c
new file mode 100644
index 0000000..9eedf54
--- /dev/null
+++ b/src/libstddjb/cdb_hash.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/cdb.h>
+
+uint32 cdb_hashadd (uint32 h, unsigned char c)
+{
+ h += (h << 5) ;
+ return h ^ c ;
+}
+
+uint32 cdb_hash (char const *buf, unsigned int len)
+{
+ uint32 h = CDB_HASHSTART ;
+ while (len--) h = cdb_hashadd(h, *buf++) ;
+ return h ;
+}
diff --git a/src/libstddjb/cdb_init_map.c b/src/libstddjb/cdb_init_map.c
new file mode 100644
index 0000000..bf8eb9d
--- /dev/null
+++ b/src/libstddjb/cdb_init_map.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <skalibs/cdb.h>
+
+int cdb_init_map (struct cdb *c, int fd, int domap)
+{
+ if (domap)
+ {
+ struct stat st ;
+ char *map ;
+ if (fstat(fd, &st) < 0) return 0 ;
+ map = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0) ;
+ if (map == MAP_FAILED) return 0 ;
+ c->fd = -fd-2 ;
+ c->map = map ;
+ c->size = st.st_size ;
+ }
+ else c->fd = fd ;
+ return 1 ;
+}
diff --git a/src/libstddjb/cdb_make.c b/src/libstddjb/cdb_make.c
new file mode 100644
index 0000000..0ec3423
--- /dev/null
+++ b/src/libstddjb/cdb_make.c
@@ -0,0 +1,145 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/diuint32.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/buffer.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/cdb.h>
+#include <skalibs/cdb_make.h>
+
+static void cdb_make_free (struct cdb_make *c)
+{
+ struct cdb_make zero = CDB_MAKE_ZERO ;
+ genalloc_free(diuint32, &c->hplist) ;
+ *c = zero ;
+}
+
+int cdb_make_start (struct cdb_make *c, int fd)
+{
+ c->hplist = genalloc_zero ;
+ c->fd = fd ;
+ c->pos = 2048 ;
+ buffer_init(&c->b, &buffer_write, fd, c->buf, BUFFER_OUTSIZE) ;
+ return seek_set(fd, c->pos) ;
+}
+
+static int posplus (struct cdb_make *c, uint32 len)
+{
+ register uint32 newpos = c->pos + len ;
+ if (newpos < len) return (errno = ENOMEM, 0) ;
+ c->pos = newpos ;
+ return 1 ;
+}
+
+static int cdb_make_addend (struct cdb_make *c, unsigned int keylen, unsigned int datalen, uint32 h)
+{
+ diuint32 blah = { h, c->pos } ;
+ if (!genalloc_append(diuint32, &c->hplist, &blah) || !posplus(c, 8) || !posplus(c, keylen) || !posplus(c, datalen))
+ {
+ cdb_make_free(c) ;
+ return -1 ;
+ }
+ return 0 ;
+}
+
+static int cdb_make_addbegin (struct cdb_make *c, unsigned int keylen, unsigned int datalen)
+{
+ char buf[8] ;
+ if ((keylen > 0xffffffff) || (datalen > 0xffffffff))
+ {
+ errno = ENOMEM ;
+ goto err ;
+ }
+ uint32_pack(buf, keylen) ;
+ uint32_pack(buf + 4, datalen) ;
+ if (buffer_put(&c->b, buf, 8) < 0) goto err ;
+ return 0 ;
+err:
+ cdb_make_free(c) ;
+ return -1 ;
+}
+
+int cdb_make_add (struct cdb_make *c, char const *key, unsigned int keylen, char const *data, unsigned int datalen)
+{
+ if ((cdb_make_addbegin(c, keylen, datalen) < 0)
+ || (buffer_put(&c->b, key, keylen) < 0)
+ || (buffer_put(&c->b, data, datalen) < 0)
+ || (cdb_make_addend(c, keylen, datalen, cdb_hash(key, keylen)) < 0))
+ return -1 ;
+ return 0 ;
+}
+
+int cdb_make_finish (struct cdb_make *c)
+{
+ uint32 count[256] ;
+ uint32 start[256] ;
+ char final[2048] ;
+ unsigned int size = 1 ;
+ unsigned int n = genalloc_len(diuint32, &c->hplist) ;
+ register unsigned int i = 0 ;
+ register diuint32 *hp = genalloc_s(diuint32, &c->hplist) ;
+
+ for ( ; i < 256 ; i++) count[i] = 0 ;
+ for (i = 0 ; i < n ; i++) ++count[hp[i].left & 255] ;
+
+ {
+ register uint32 u = 0 ;
+ for (i = 0 ; i < 256 ; i++) start[i] = u += count[i] ; /* bounded by n */
+ for (i = 0 ; i < 256 ; i++)
+ {
+ u = count[i] << 1 ;
+ if (u > size) size = u ;
+ }
+ size += n ; /* no overflow possible up to now */
+ u = 0xffffffffUL ; u /= sizeof(diuint32) ;
+ if (size > u) return (errno = ENOMEM, -1) ;
+ }
+ i = n ;
+ {
+ diuint32 split[size] ;
+ while (i--) split[--start[hp[i].left & 255]] = hp[i] ;
+ genalloc_free(diuint32, &c->hplist) ;
+ hp = split + n ;
+
+ for (i = 0 ; i < 256 ; ++i)
+ {
+ char buf[8] ;
+ register uint32 k = count[i] ;
+ register uint32 len = k << 1 ; /* no overflow possible */
+ register diuint32 *p = split + start[i] ;
+ register unsigned int j = 0 ;
+
+ uint32_pack(final + (i << 3), c->pos) ;
+ uint32_pack(final + (i << 3) + 4, len) ;
+
+ for ( ; j < len ; j++) hp[j].left = hp[j].right = 0 ;
+ for (j = 0 ; j < k ; j++)
+ {
+ register uint32 where = (p->left >> 8) % len ;
+ while (hp[where].right) if (++where == len) where = 0 ;
+ hp[where] = *p++ ;
+ }
+
+ for (j = 0 ; j < len ; j++)
+ {
+ uint32_pack(buf, hp[j].left) ;
+ uint32_pack(buf + 4, hp[j].right) ;
+ if (buffer_put(&c->b, buf, 8) < 0) goto err0 ;
+ if (!posplus(c, 8)) goto err0 ;
+ }
+ }
+ }
+
+ if (!buffer_flush(&c->b)) goto err0 ;
+ if (seek_begin(c->fd) == -1) goto err0 ;
+ if (buffer_putflush(&c->b, final, 2048) < 0) goto err0 ;
+ cdb_make_free(c) ;
+ return 0 ;
+
+err0:
+ cdb_make_free(c) ;
+ return -1 ;
+}
diff --git a/src/libstddjb/cdb_mapfile.c b/src/libstddjb/cdb_mapfile.c
new file mode 100644
index 0000000..f26ad3c
--- /dev/null
+++ b/src/libstddjb/cdb_mapfile.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/cdb.h>
+
+int cdb_mapfile (struct cdb *c, char const *file)
+{
+ int fd = open_readb(file) ;
+ if (fd < 0) return 0 ;
+ if (!cdb_init_map(c, fd, 1))
+ {
+ register int e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ return 0 ;
+ }
+ fd_close(fd) ;
+ return 1 ;
+}
diff --git a/src/libstddjb/cdb_nextkey.c b/src/libstddjb/cdb_nextkey.c
new file mode 100644
index 0000000..28925fe
--- /dev/null
+++ b/src/libstddjb/cdb_nextkey.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/cdb.h>
+
+int cdb_nextkey (struct cdb *c, uint32 *kpos)
+{
+ char buf[8] ;
+ uint32 eod, klen ;
+ if (cdb_read(c, buf, 4, 0) < 0) return -1 ;
+ uint32_unpack(buf, &eod) ;
+ if (eod < 8 || eod - 8 < *kpos) return 0 ;
+ c->kpos = *kpos + 8 ;
+ if (c->kpos < *kpos) return -1 ; /* wraparound */
+ cdb_findstart(c) ;
+ c->hslots = 1 ;
+ if (cdb_read(c, buf, 8, *kpos) < 0) return -1 ;
+ uint32_unpack(buf, &klen) ;
+ uint32_unpack(buf + 4, &c->dlen) ;
+ c->dpos = c->kpos + klen ;
+ *kpos += 8 + klen + c->dlen ;
+ return 1 ;
+}
diff --git a/src/libstddjb/cdb_read.c b/src/libstddjb/cdb_read.c
new file mode 100644
index 0000000..76fbd63
--- /dev/null
+++ b/src/libstddjb/cdb_read.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/error.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/uint32.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/cdb.h>
+
+int cdb_read (struct cdb *c, char *buf, unsigned int len, uint32 pos)
+{
+ if (c->map)
+ {
+ if ((pos > c->size) || (c->size - pos < len)) return (errno = EPROTO, -1) ;
+ byte_copy(buf, len, c->map + pos) ;
+ }
+ else
+ {
+ if (seek_set(c->fd, pos) < 0) return -1 ;
+ if (allread(c->fd, buf, len) < len) return -1 ;
+ }
+ return 0 ;
+}
diff --git a/src/libstddjb/cdb_successor.c b/src/libstddjb/cdb_successor.c
new file mode 100644
index 0000000..5660692
--- /dev/null
+++ b/src/libstddjb/cdb_successor.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/cdb.h>
+
+int cdb_successor (struct cdb *c, char const *key, unsigned int klen)
+{
+ uint32 kpos ;
+ if (key)
+ {
+ register int r = cdb_find(c, key, klen) ;
+ if (r < 1) return r ;
+ kpos = c->dpos + c->dlen ;
+ }
+ else cdb_traverse_init(c, &kpos) ;
+ return cdb_nextkey(c, &kpos) ;
+}
diff --git a/src/libstddjb/cdb_zero.c b/src/libstddjb/cdb_zero.c
new file mode 100644
index 0000000..ce70444
--- /dev/null
+++ b/src/libstddjb/cdb_zero.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include <skalibs/cdb.h>
+
+struct cdb const cdb_zero = CDB_ZERO ;
diff --git a/src/libstddjb/child_spawn.c b/src/libstddjb/child_spawn.c
new file mode 100644
index 0000000..aa937fd
--- /dev/null
+++ b/src/libstddjb/child_spawn.c
@@ -0,0 +1,228 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/sysdeps.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/env.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/uint.h>
+#include <skalibs/webipc.h>
+
+#ifdef SKALIBS_HASPOSIXSPAWN
+
+#include <stdlib.h>
+#include <spawn.h>
+#include <skalibs/config.h>
+
+#else
+
+#include <skalibs/sig.h>
+#include <skalibs/strerr2.h>
+
+#endif
+
+#define NOFDVAR "SKALIBS_CHILD_SPAWN_FDS"
+
+
+ /*
+ If n = 0 : child's stdin and stdout are the same as the parent's
+ If n = 1 : Unix socket between parent and child.
+ Additional canals, if needed, may be fd-passed through it.
+ If n >= 2 : pipes between parent and child.
+ Parent reads on even ones, writes on odd ones.
+ */
+
+pid_t child_spawn (char const *prog, char const *const *argv, char const *const *envp, int *fds, unsigned int n)
+{
+#ifdef SKALIBS_HASPOSIXSPAWN
+ posix_spawn_file_actions_t actions ;
+ posix_spawnattr_t attr ;
+#endif
+ int p[n ? n : 1][2] ;
+ int syncpipe[2] ;
+ pid_t pid ;
+ int e ;
+ unsigned int m = sizeof(NOFDVAR) ;
+ unsigned int i ;
+ char modifs[m + 1 + n * UINT_FMT] ;
+ byte_copy(modifs, sizeof(NOFDVAR), NOFDVAR "=") ;
+ if (n == 1)
+ {
+ if (ipc_pair_b(p[0]) < 0) return 0 ;
+ }
+ else if (n >= 2)
+ {
+ for (i = 0 ; i < n ; i++) if (pipe(p[i]) < 0) { e = errno ; goto errp ; }
+ }
+ if (pipe(syncpipe) < 0) { e = errno ; goto errp ; }
+ if (coe(syncpipe[1]) < 0) { e = errno ; goto errsp ; }
+ for (i = 0 ; i < n ; i++)
+ if ((ndelay_on(p[i][i & 1]) < 0) || (coe(p[i][i & 1]) < 0))
+ {
+ e = errno ; goto errsp ;
+ }
+ for (i = 2 ; i < n ; i++)
+ {
+ m += uint_fmt(modifs + m, p[i][!(i & 1)]) ;
+ if (i+1 < n) modifs[m++] = ',' ;
+ }
+ modifs[m++] = 0 ;
+
+#ifdef SKALIBS_HASPOSIXSPAWN
+
+ e = posix_spawnattr_init(&attr) ;
+ if (e) goto errsp ;
+ {
+ sigset_t set ;
+ sigemptyset(&set) ;
+ e = posix_spawnattr_setsigmask(&attr, &set) ;
+ }
+ if (e) goto errattr ;
+ e = posix_spawn_file_actions_init(&actions) ;
+ if (e) goto errattr ;
+ e = posix_spawn_file_actions_addclose(&actions, syncpipe[0]) ;
+ if (e) goto erractions ;
+ switch (n)
+ {
+ case 0 :
+ break ;
+ case 1 :
+ e = posix_spawn_file_actions_adddup2(&actions, p[0][1], 1) ;
+ if (e) goto erractions ;
+ e = posix_spawn_file_actions_addclose(&actions, p[0][1]) ;
+ if (e) goto erractions ;
+ e = posix_spawn_file_actions_adddup2(&actions, 1, 0) ;
+ if (e) goto erractions ;
+ break ;
+ default :
+ e = posix_spawn_file_actions_adddup2(&actions, p[1][0], 0) ;
+ if (e) goto erractions ;
+ e = posix_spawn_file_actions_addclose(&actions, p[1][0]) ;
+ if (e) goto erractions ;
+ e = posix_spawn_file_actions_adddup2(&actions, p[0][1], 1) ;
+ if (e) goto erractions ;
+ e = posix_spawn_file_actions_addclose(&actions, p[0][1]) ;
+ if (e) goto erractions ;
+ break ;
+ }
+ {
+ int haspath = !!env_get("PATH") ;
+ unsigned int envlen = env_len(envp) ;
+ char const *newenv[envlen + 2] ;
+ if (!env_merge(newenv, envlen+2, envp, envlen, modifs, m)) goto errsp ;
+ if (!haspath && (setenv("PATH", SKALIBS_DEFAULTPATH, 0) < 0))
+ {
+ e = errno ; goto erractions ;
+ }
+ e = posix_spawnp(&pid, prog, &actions, &attr, (char *const *)argv, (char *const *)newenv) ;
+ if (!haspath) unsetenv("PATH") ;
+ if (e) goto erractions ;
+ }
+
+ posix_spawn_file_actions_destroy(&actions) ;
+ posix_spawnattr_destroy(&attr) ;
+
+#else
+
+ pid = fork() ;
+ if (pid < 0) { e = errno ; goto errsp ; }
+ else if (!pid)
+ {
+ unsigned int len = str_len(PROG) ;
+ char name[len + 9] ;
+ byte_copy(name, len, PROG) ;
+ byte_copy(name + len, 9, " (child)") ;
+ PROG = name ;
+ fd_close(syncpipe[0]) ;
+ switch (n)
+ {
+ case 0 :
+ {
+ int fd = open2("/dev/null", O_RDONLY) ;
+ if (fd < 0) goto syncdie ;
+ if (fd_move(0, fd) < 0) goto syncdie ;
+ fd = open2("/dev/null", O_WRONLY) ;
+ if (fd < 0) goto syncdie ;
+ if (fd_move(1, fd) < 0) goto syncdie ;
+ break ;
+ }
+ case 1 :
+ if (fd_move(1, p[0][1]) < 0) goto syncdie ;
+ if (fd_copy(0, 1) < 0) goto syncdie ;
+ break ;
+ default :
+ if (fd_move2(0, p[1][0], 1, p[0][1]) < 0) goto syncdie ;
+ break ;
+ }
+ sig_blocknone() ;
+ pathexec_r_name(prog, argv, envp, env_len(envp), modifs, m) ;
+
+ syncdie:
+ {
+ char c = errno ;
+ fd_write(syncpipe[1], &c, 1) ;
+ }
+ _exit(127) ;
+ }
+
+#endif
+
+ fd_close(syncpipe[1]) ;
+ {
+ char c ;
+ syncpipe[1] = fd_read(syncpipe[0], &c, 1) ;
+ if (syncpipe[1])
+ {
+ if (syncpipe[1] < 0) e = errno ;
+ else
+ {
+ kill(pid, SIGKILL) ;
+ e = c ;
+ }
+ wait_pid(pid, &syncpipe[1]) ;
+ goto errsp0 ;
+ }
+ }
+ if (waitpid_nointr(pid, &e, WNOHANG))
+ {
+ e = WEXITSTATUS(e) == 127 ? EIO : 0 ;
+ goto errsp0 ;
+ }
+
+ fd_close(syncpipe[0]) ;
+ for (i = n ; i ; i--)
+ {
+ fd_close(p[i-1][i & 1]) ;
+ fds[i-1] = p[i-1][!(i & 1)] ;
+ }
+ return pid ;
+
+#ifdef SKALIBS_HASPOSIXSPAWN
+ erractions:
+ posix_spawn_file_actions_destroy(&actions) ;
+ errattr:
+ posix_spawnattr_destroy(&attr) ;
+#endif
+ errsp:
+ fd_close(syncpipe[1]) ;
+ errsp0:
+ fd_close(syncpipe[0]) ;
+ i = n ;
+ errp:
+ while (i--)
+ {
+ fd_close(p[i][1]) ;
+ fd_close(p[i][0]) ;
+ }
+ errno = e ;
+ return 0 ;
+}
diff --git a/src/libstddjb/child_spawn0.c b/src/libstddjb/child_spawn0.c
new file mode 100644
index 0000000..b96b2ef
--- /dev/null
+++ b/src/libstddjb/child_spawn0.c
@@ -0,0 +1,73 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#ifdef SKALIBS_HASPOSIXSPAWN
+
+#include <spawn.h>
+#include <stdlib.h>
+#include <skalibs/config.h>
+#include <skalibs/env.h>
+
+pid_t child_spawn0 (char const *prog, char const *const *argv, char const *const *envp)
+{
+ pid_t pid ;
+ int e ;
+ int haspath = !!env_get("PATH") ;
+ if (!haspath && (setenv("PATH", SKALIBS_DEFAULTPATH, 0) < 0)) return 0 ;
+ e = posix_spawnp(&pid, prog, 0, 0, (char *const *)argv, (char *const *)envp) ;
+ if (!haspath) unsetenv("PATH") ;
+ return e ? (errno = e, 0) : pid ;
+}
+
+#else
+
+#include <unistd.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/djbunix.h>
+
+pid_t child_spawn0 (char const *prog, char const *const *argv, char const *const *envp)
+{
+ int e ;
+ int p[2] ;
+ pid_t pid ;
+ if (pipecoe(p) < 0) return 0 ;
+ pid = fork() ;
+ if (pid < 0)
+ {
+ e = errno ;
+ fd_close(p[1]) ;
+ fd_close(p[0]) ;
+ errno = e ;
+ return 0 ;
+ }
+ if (pid)
+ {
+ fd_close(p[0]) ;
+ pathexec_run(prog, argv, envp) ;
+ e = errno ;
+ fd_write(p[1], (char *)&e, sizeof(e)) ;
+ _exit(127) ;
+ }
+ fd_close(p[1]) ;
+ p[1] = fd_read(p[0], (char *)&e, sizeof(e)) ;
+ if (p[1] < 0)
+ {
+ e = errno ;
+ fd_close(p[0]) ;
+ errno = e ;
+ return 0 ;
+ }
+ fd_close(p[0]) ;
+ if (p[1] == sizeof(e))
+ {
+ wait_pid(pid, &p[0]) ;
+ errno = e ;
+ return 0 ;
+ }
+ return pid ;
+}
+
+#endif
diff --git a/src/libstddjb/child_spawn1.c b/src/libstddjb/child_spawn1.c
new file mode 100644
index 0000000..bb51ab9
--- /dev/null
+++ b/src/libstddjb/child_spawn1.c
@@ -0,0 +1,115 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+#ifdef SKALIBS_HASPOSIXSPAWN
+
+#include <spawn.h>
+#include <stdlib.h>
+#include <skalibs/config.h>
+#include <skalibs/env.h>
+
+pid_t child_spawn1 (char const *prog, char const *const *argv, char const *const *envp, int *fd, int to)
+{
+ posix_spawn_file_actions_t actions ;
+ int e ;
+ int p[2] ;
+ pid_t pid ;
+ int haspath = !!env_get("PATH") ;
+ if (pipe(p) < 0) return 0 ;
+ to = !!to ;
+ e = posix_spawn_file_actions_init(&actions) ;
+ if (e) goto err ;
+ e = posix_spawn_file_actions_addclose(&actions, p[!to]) ;
+ if (e) goto erractions ;
+ e = posix_spawn_file_actions_adddup2(&actions, p[to], to) ;
+ if (e) goto erractions ;
+ if (!haspath && (setenv("PATH", SKALIBS_DEFAULTPATH, 0) < 0)) { e = errno ; goto erractions ; }
+ e = posix_spawnp(&pid, prog, &actions, 0, (char *const *)argv, (char *const *)envp) ;
+ if (!haspath) unsetenv("PATH") ;
+ posix_spawn_file_actions_destroy(&actions) ;
+ fd_close(p[to]) ;
+ if (e) goto errp ;
+ *fd = p[!to] ;
+ return pid ;
+
+ erractions:
+ posix_spawn_file_actions_destroy(&actions) ;
+ err:
+ fd_close(p[to]) ;
+ errp:
+ fd_close(p[!to]) ;
+ errno = e ;
+ return 0 ;
+}
+
+#else
+
+#include <skalibs/allreadwrite.h>
+
+pid_t child_spawn1 (char const *prog, char const *const *argv, char const *const *envp, int *fd, int to)
+{
+ int e ;
+ int syncp[2] ;
+ int p[2] ;
+ pid_t pid ;
+ if (pipe(p) < 0) return 0 ;
+ if (pipecoe(syncp) < 0)
+ {
+ e = errno ;
+ fd_close(p[1]) ;
+ fd_close(p[0]) ;
+ errno = e ;
+ return 0 ;
+ }
+ to = !!to ;
+ pid = fork() ;
+ if (pid < 0)
+ {
+ e = errno ;
+ fd_close(syncp[1]) ;
+ fd_close(syncp[0]) ;
+ fd_close(p[1]) ;
+ fd_close(p[0]) ;
+ errno = e ;
+ return 0 ;
+ }
+ if (pid)
+ {
+ fd_close(syncp[0]) ;
+ fd_close(p[!to]) ;
+ if (fd_move(to, p[to]) < 0) goto err ;
+ pathexec_run(prog, argv, envp) ;
+err:
+ e = errno ;
+ fd_write(syncp[1], (char *)&e, sizeof(e)) ;
+ _exit(127) ;
+ }
+ fd_close(syncp[1]) ;
+ fd_close(p[to]) ;
+ syncp[1] = fd_read(syncp[0], (char *)&e, sizeof(e)) ;
+ if (syncp[1] < 0)
+ {
+ e = errno ;
+ fd_close(syncp[0]) ;
+ fd_close(p[!to]) ;
+ errno = e ;
+ return 0 ;
+ }
+ fd_close(syncp[0]) ;
+ if (syncp[1] == sizeof(e))
+ {
+ fd_close(p[!to]) ;
+ wait_pid(pid, &syncp[1]) ;
+ errno = e ;
+ return 0 ;
+ }
+ *fd = p[!to] ;
+ return pid ;
+}
+
+#endif
diff --git a/src/libstddjb/coe.c b/src/libstddjb/coe.c
new file mode 100644
index 0000000..a12f9cb
--- /dev/null
+++ b/src/libstddjb/coe.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <fcntl.h>
+#include <skalibs/djbunix.h>
+
+int coe (int fd)
+{
+ register int flags = fcntl(fd, F_GETFD, 0) ;
+ if (flags < 0) return -1 ;
+ return fcntl(fd, F_SETFD, flags | FD_CLOEXEC) ;
+}
diff --git a/src/libstddjb/deepsleepuntil.c b/src/libstddjb/deepsleepuntil.c
new file mode 100644
index 0000000..77ac080
--- /dev/null
+++ b/src/libstddjb/deepsleepuntil.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+
+void deepsleepuntil (tain_t const *deadline, tain_t *stamp)
+{
+ iopause_fd x ;
+ while (tain_less(stamp, deadline)) iopause_stamp(&x, 0, deadline, stamp) ;
+}
diff --git a/src/libstddjb/dir_close.c b/src/libstddjb/dir_close.c
new file mode 100644
index 0000000..0af6f0e
--- /dev/null
+++ b/src/libstddjb/dir_close.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/direntry.h>
+
+int dir_close (DIR *dir)
+{
+ register unsigned int done = 0 ;
+doit:
+ done++ ;
+ if (!closedir(dir)) return 0 ;
+ if (errno == EINTR) goto doit ;
+ return ((errno == EBADF) && (done > 1)) ? 0 : -1 ;
+}
diff --git a/src/libstddjb/dirname.c b/src/libstddjb/dirname.c
new file mode 100644
index 0000000..1def443
--- /dev/null
+++ b/src/libstddjb/dirname.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+
+char *dirname (char *s)
+{
+ static stralloc dirname_sa = STRALLOC_ZERO ;
+ static char dot0[2] = "." ;
+ char *dot = dot0 ;
+ if (!s) return dot ;
+ dirname_sa.len = 0 ;
+ if (!sadirname(&dirname_sa, s, str_len(s))) return 0 ;
+ if (!stralloc_0(&dirname_sa)) return 0 ;
+ return dirname_sa.s ;
+}
diff --git a/src/libstddjb/djbtime-internal.h b/src/libstddjb/djbtime-internal.h
new file mode 100644
index 0000000..26ffc81
--- /dev/null
+++ b/src/libstddjb/djbtime-internal.h
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#ifndef DJBTIME_INTERNAL_H
+#define DJBTIME_INTERNAL_H
+
+#include <skalibs/uint64.h>
+
+
+/* Leap second handling, for UTC <--> TAI conversions */
+
+#define LEAPSECS_MAX 39
+#define LEAPSECS_FILE SKALIBS_ETC "/leapsecs.dat"
+extern uint64 *leapsecs_here ;
+
+extern int leapsecs_init_r (char const *, uint64 *) ;
+#define leapsecs_init() leapsecs_init_r(LEAPSECS_FILE, leapsecs_here)
+extern int leapsecs_add_r (uint64 *, char const *, uint64 *, int) ;
+#define leapsecs_add(t, h) leapsecs_add_r(t, LEAPSECS_FILE, leapsecs_here, h)
+extern int leapsecs_sub_r (uint64 *, char const *, uint64 *) ;
+#define leapsecs_sub(t) leapsecs_sub_r((t), LEAPSECS_FILE, leapsecs_here)
+
+
+#endif
diff --git a/src/libstddjb/doublefork.c b/src/libstddjb/doublefork.c
new file mode 100644
index 0000000..5a1f7b1
--- /dev/null
+++ b/src/libstddjb/doublefork.c
@@ -0,0 +1,53 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/uint64.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/djbunix.h>
+
+pid_t doublefork ()
+{
+ char pack[8] ;
+ int fd[2] ;
+ pid_t child ;
+ if (pipe(fd) == -1) return -1 ;
+ child = fork() ;
+ switch (child)
+ {
+ case -1:
+ {
+ register int e = errno ;
+ fd_close(fd[1]) ;
+ fd_close(fd[0]) ;
+ errno = e ;
+ return -1 ;
+ }
+ case 0:
+ {
+ pid_t pid ;
+ fd_close(fd[0]) ;
+ pid = fork() ;
+ switch (pid)
+ {
+ case -1: _exit(errno) ;
+ case 0: fd_close(fd[1]) ; return 0 ;
+ }
+ uint64_pack_big(pack, (uint64)pid) ;
+ _exit((allwrite(fd[1], pack, 8) < 8) ? errno : 0) ;
+ }
+ }
+ fd_close(fd[1]) ;
+ {
+ uint64 grandchild = 0 ;
+ int wstat ;
+ if (allread(fd[0], pack, 8) < 8) grandchild = 1 ;
+ fd_close(fd[0]) ;
+ wait_pid(child, &wstat) ;
+ if (grandchild) return (errno = WIFSIGNALED(wstat) ? EINTR : WEXITSTATUS(wstat), -1) ;
+ uint64_unpack_big(pack, &grandchild) ;
+ return (pid_t)grandchild ;
+ }
+}
diff --git a/src/libstddjb/env_addmodif.c b/src/libstddjb/env_addmodif.c
new file mode 100644
index 0000000..4c34479
--- /dev/null
+++ b/src/libstddjb/env_addmodif.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/env.h>
+
+int env_addmodif (stralloc *sa, char const *s, char const *t)
+{
+ unsigned int oldlen = sa->len ;
+ if (!s) return 1 ;
+ if (!stralloc_cats(sa, s)) return 0 ;
+ if ((t && (!stralloc_catb(sa, "=", 1) || !stralloc_cats(sa, t)))
+ || !stralloc_0(sa))
+ {
+ sa->len = oldlen ;
+ return 0 ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/env_get.c b/src/libstddjb/env_get.c
new file mode 100644
index 0000000..927955f
--- /dev/null
+++ b/src/libstddjb/env_get.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/env.h>
+#include <skalibs/environ.h>
+
+char const *env_get (char const *s)
+{
+ return env_get2((char const **)environ, s) ;
+}
diff --git a/src/libstddjb/env_get2.c b/src/libstddjb/env_get2.c
new file mode 100644
index 0000000..612cf6a
--- /dev/null
+++ b/src/libstddjb/env_get2.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/env.h>
+
+char const *env_get2 (char const *const *envp, char const *s)
+{
+ unsigned int i ;
+ unsigned int len ;
+
+ if (!s) return 0 ;
+ len = str_len(s) ;
+ for (i = 0 ; envp[i] ; ++i)
+ if (str_start(envp[i], s)
+ && (envp[i][len] == '='))
+ return envp[i] + len + 1 ;
+ return 0 ;
+}
diff --git a/src/libstddjb/env_len.c b/src/libstddjb/env_len.c
new file mode 100644
index 0000000..7e0bea8
--- /dev/null
+++ b/src/libstddjb/env_len.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/env.h>
+
+unsigned int env_len (register char const *const *e)
+{
+ register unsigned int i = 0 ;
+ while (*e++) i++ ;
+ return i ;
+}
diff --git a/src/libstddjb/env_make.c b/src/libstddjb/env_make.c
new file mode 100644
index 0000000..dd5139f
--- /dev/null
+++ b/src/libstddjb/env_make.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/env.h>
+
+int env_make (char const **v, unsigned int argc, char const *s, unsigned int len)
+{
+ while (argc--)
+ {
+ register unsigned int n = str_len(s) + 1 ;
+ if (n > len) return (errno = EINVAL, 0) ;
+ *v++ = s ; s += n ; len -= n ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/env_merge.c b/src/libstddjb/env_merge.c
new file mode 100644
index 0000000..2a0e5bd
--- /dev/null
+++ b/src/libstddjb/env_merge.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/env.h>
+
+unsigned int env_merge (char const **v, unsigned int vmax, char const *const *envp, unsigned int envlen, char const *modifs, unsigned int modiflen)
+{
+ unsigned int n = byte_count(modifs, modiflen, '\0') ;
+ unsigned int vlen = envlen ;
+ register unsigned int i = 0 ;
+ if (envlen + n + 1 > vmax) return (errno = ENAMETOOLONG, 0) ;
+ for (; i < envlen ; i++) v[i] = envp[i] ;
+ for (i = 0 ; i < modiflen ; i += str_len(modifs + i) + 1)
+ {
+ unsigned int split = str_chr(modifs + i, '=') ;
+ register unsigned int j = 0 ;
+ for (; j < vlen ; j++)
+ if (!byte_diff(modifs + i, split, v[j]) && (v[j][split] == '=')) break ;
+ if (j < vlen) v[j] = v[--vlen] ;
+ if (modifs[i + split]) v[vlen++] = modifs + i ;
+ }
+ v[vlen++] = 0 ;
+ return vlen ;
+}
diff --git a/src/libstddjb/env_string.c b/src/libstddjb/env_string.c
new file mode 100644
index 0000000..7f97859
--- /dev/null
+++ b/src/libstddjb/env_string.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/env.h>
+
+int env_string (stralloc *sa, char const *const *envp, unsigned int envlen)
+{
+ unsigned int salen = sa->len ;
+ register unsigned int i = 0 ;
+ for (; i < envlen ; i++)
+ {
+ if (!stralloc_cats(sa, envp[i]) || !stralloc_0(sa))
+ {
+ sa->len = salen ;
+ return 0 ;
+ }
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/envalloc_0.c b/src/libstddjb/envalloc_0.c
new file mode 100644
index 0000000..114f69e
--- /dev/null
+++ b/src/libstddjb/envalloc_0.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/genalloc.h>
+#include <skalibs/envalloc.h>
+
+int envalloc_0 (genalloc *v)
+{
+ char const *z = 0 ;
+ return genalloc_append(char const *, v, &z) ;
+}
diff --git a/src/libstddjb/envalloc_make.c b/src/libstddjb/envalloc_make.c
new file mode 100644
index 0000000..1cc44b9
--- /dev/null
+++ b/src/libstddjb/envalloc_make.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/env.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/envalloc.h>
+
+int envalloc_make (genalloc *v, unsigned int argc, char const *s, unsigned int len)
+{
+ int wasnull = !v->s ;
+ if (!genalloc_readyplus(char const *, v, argc+1)) return 0 ;
+ if (!env_make(genalloc_s(char const *, v) + genalloc_len(char const *, v), argc, s, len))
+ {
+ if (wasnull) genalloc_free(char const *, v) ;
+ return 0 ;
+ }
+ genalloc_setlen(char const *, v, genalloc_len(char const *, v) + argc) ;
+ return 1 ;
+}
diff --git a/src/libstddjb/envalloc_merge.c b/src/libstddjb/envalloc_merge.c
new file mode 100644
index 0000000..9134b84
--- /dev/null
+++ b/src/libstddjb/envalloc_merge.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/env.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/envalloc.h>
+
+int envalloc_merge (genalloc *v, char const *const *envp, unsigned int envlen, char const *modifs, unsigned int modiflen)
+{
+ unsigned int n = envlen + 1 + byte_count(modifs, modiflen, '\0') ;
+ if (!genalloc_readyplus(char const *, v, n)) return 0 ;
+ n = env_merge(genalloc_s(char const *, v) + genalloc_len(char const *, v), n, envp, envlen, modifs, modiflen) ;
+ genalloc_setlen(char const *, v, genalloc_len(char const *, v) + n) ;
+ return 1 ;
+}
diff --git a/src/libstddjb/envalloc_uniq.c b/src/libstddjb/envalloc_uniq.c
new file mode 100644
index 0000000..181128a
--- /dev/null
+++ b/src/libstddjb/envalloc_uniq.c
@@ -0,0 +1,31 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/envalloc.h>
+
+int envalloc_uniq (genalloc *v, char delim)
+{
+ unsigned int m = 0 ;
+ register unsigned int i = 0 ;
+ for (; i < genalloc_len(char const *, v) ; i++)
+ {
+ register unsigned int j = i+1 ;
+ char const *s = genalloc_s(char const *, v)[i] ;
+ unsigned int n = str_chr(s, delim) ;
+ if (delim && !s[n]) return (errno = EINVAL, -1) ;
+ for (; j < genalloc_len(char const *, v) ; j++)
+ {
+ register char const **p = genalloc_s(char const *, v) ;
+ if (!str_diffn(s, p[j], n))
+ {
+ register unsigned int len = genalloc_len(char const *, v) - 1 ;
+ genalloc_setlen(char const *, v, len) ;
+ p[j] = p[len] ;
+ m++ ;
+ }
+ }
+ }
+ return (int)m ;
+}
diff --git a/src/libstddjb/envdir.c b/src/libstddjb/envdir.c
new file mode 100644
index 0000000..7866c7a
--- /dev/null
+++ b/src/libstddjb/envdir.c
@@ -0,0 +1,84 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/env.h>
+#include <skalibs/direntry.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+
+#define MAXVARSIZE 4095
+
+int envdir_internal (char const *path, stralloc *modifs, unsigned int options, char nullis)
+{
+ char buf[MAXVARSIZE + 1] ;
+ unsigned int n = 0 ;
+ unsigned int pathlen = str_len(path) ;
+ unsigned int modifbase = modifs->len ;
+ int wasnull = !modifs->s ;
+ DIR *dir ;
+ if (!nullis) return (errno = EINVAL, -1) ;
+ dir = opendir(path) ;
+ if (!dir) return -1 ;
+ for (;;)
+ {
+ direntry *d ;
+ unsigned int len ;
+ register int r ;
+ errno = 0 ;
+ d = readdir(dir) ;
+ if (!d) break ;
+ if (d->d_name[0] == '.') continue ;
+ len = str_len(d->d_name) ;
+ if (str_chr(d->d_name, '=') < len) continue ;
+ {
+ char tmp[pathlen + len + 2] ;
+ byte_copy(tmp, pathlen, path) ;
+ tmp[pathlen] = '/' ;
+ byte_copy(tmp + pathlen + 1, len + 1, d->d_name) ;
+ r = openreadnclose(tmp, buf, MAXVARSIZE) ;
+ }
+ if (r < 0)
+ {
+ if (errno == ENOENT) errno = EIDRM ;
+ goto err ;
+ }
+ else if (r > 0)
+ {
+ if (options & SKALIBS_ENVDIR_VERBATIM)
+ {
+ if (!(options & SKALIBS_ENVDIR_NOCHOMP) && (buf[r-1] == '\n')) r-- ;
+ }
+ else
+ {
+ r = byte_chr(buf, r, '\n') ;
+ if (!(options & SKALIBS_ENVDIR_NOCHOMP))
+ {
+ while (r--) if ((buf[r] != ' ') && (buf[r] != '\t') && (buf[r] != '\r')) break ;
+ r++ ;
+ }
+ }
+ {
+ register unsigned int i = 0 ;
+ for (; i < (unsigned int)r ; i++) if (!buf[i]) buf[i] = nullis ;
+ }
+ buf[r++] = 0 ;
+ if (!env_addmodif(modifs, d->d_name, buf)) goto err ;
+ }
+ else if (!env_addmodif(modifs, d->d_name, 0)) goto err ;
+ n++ ;
+ }
+ if (errno) goto err ;
+ dir_close(dir) ;
+ return n ;
+
+ err:
+ {
+ register int e = errno ;
+ dir_close(dir) ;
+ if (wasnull) stralloc_free(modifs) ; else modifs->len = modifbase ;
+ errno = e ;
+ return -1 ;
+ }
+}
diff --git a/src/libstddjb/error_str.c b/src/libstddjb/error_str.c
new file mode 100644
index 0000000..6aca43f
--- /dev/null
+++ b/src/libstddjb/error_str.c
@@ -0,0 +1,277 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/error.h>
+
+#ifndef SKALIBS_FLAG_REPLACE_LIBC
+
+#include <string.h>
+
+char const *error_str (register int i)
+{
+ return (char const *)strerror(i) ;
+}
+
+#else
+
+#include <errno.h>
+
+#define X(e, s) case e : return s ;
+#define Y(e, s) if (i == e) return s ;
+
+char const *error_str (register int i)
+{
+ Y(EWOULDBLOCK, "input/output would block")
+ Y(EAGAIN, "temporary failure")
+ Y(EINVAL, "invalid argument")
+
+ switch (i)
+ {
+ X(0, "no error")
+ X(EINTR, "interrupted system call")
+ X(ENOMEM, "out of memory")
+ X(ENOENT, "file does not exist")
+ X(ETXTBSY, "text busy")
+ X(EIO, "input/output error")
+ X(EEXIST, "file already exists")
+ X(ETIMEDOUT, "timed out")
+ X(EINPROGRESS, "operation in progress")
+ X(EPIPE, "broken pipe")
+ X(EPERM, "permission denied")
+ X(EACCES, "access denied")
+ X(ENODEV, "device not configured")
+ X(EPROTO, "protocol error")
+ X(EISDIR, "is a directory")
+ X(ECONNREFUSED, "connection refused")
+ X(ENOTDIR, "not a directory")
+ X(ENOTSOCK, "not a socket")
+ X(EDOM, "input out of range")
+ X(ENOBUFS, "out of buffer space")
+
+#ifdef ESRCH
+ X(ESRCH, "no such process")
+#endif
+#ifdef E2BIG
+ X(E2BIG, "argument list too long")
+#endif
+#ifdef ENOEXEC
+ X(ENOEXEC, "exec format error")
+#endif
+#ifdef EBADF
+ X(EBADF, "file descriptor not open")
+#endif
+#ifdef ECHILD
+ X(ECHILD, "no child processes")
+#endif
+#ifdef EDEADLK
+ X(EDEADLK, "operation would cause deadlock")
+#endif
+#ifdef EFAULT
+ X(EFAULT, "bad address")
+#endif
+#ifdef ENOTBLK
+ X(ENOTBLK, "not a block device")
+#endif
+#ifdef EBUSY
+ X(EBUSY, "device busy")
+#endif
+#ifdef EXDEV
+ X(EXDEV, "cross-device link")
+#endif
+#ifdef ENFILE
+ X(ENFILE, "system cannot open more files")
+#endif
+#ifdef EMFILE
+ X(EMFILE, "process cannot open more files")
+#endif
+#ifdef ENOTTY
+ X(ENOTTY, "not a tty")
+#endif
+#ifdef EFBIG
+ X(EFBIG, "file too big")
+#endif
+#ifdef ENOSPC
+ X(ENOSPC, "out of disk space")
+#endif
+#ifdef ESPIPE
+ X(ESPIPE, "unseekable descriptor")
+#endif
+#ifdef EROFS
+ X(EROFS, "read-only file system")
+#endif
+#ifdef EMLINK
+ X(EMLINK, "too many links")
+#endif
+#ifdef ERANGE
+ X(ERANGE, "output out of range")
+#endif
+#ifdef EALREADY
+ X(EALREADY, "operation already in progress")
+#endif
+#ifdef EDESTADDRREQ
+ X(EDESTADDRREQ, "destination address required")
+#endif
+#ifdef EMSGSIZE
+ X(EMSGSIZE, "message too long")
+#endif
+#ifdef EPROTOTYPE
+ X(EPROTOTYPE, "incorrect protocol type")
+#endif
+#ifdef ENOPROTOOPT
+ X(ENOPROTOOPT, "protocol not available")
+#endif
+#ifdef EPROTONOSUPPORT
+ X(EPROTONOSUPPORT, "protocol not supported")
+#endif
+#ifdef ESOCKTNOSUPPORT
+ X(ESOCKTNOSUPPORT, "socket type not supported")
+#endif
+#ifdef EOPNOTSUPP
+ X(EOPNOTSUPP, "operation not supported")
+#endif
+#ifdef EPFNOSUPPORT
+ X(EPFNOSUPPORT, "protocol family not supported")
+#endif
+#ifdef EAFNOSUPPORT
+ X(EAFNOSUPPORT, "address family not supported")
+#endif
+#ifdef EADDRINUSE
+ X(EADDRINUSE, "address already used")
+#endif
+#ifdef EADDRNOTAVAIL
+ X(EADDRNOTAVAIL, "address not available")
+#endif
+#ifdef ENETDOWN
+ X(ENETDOWN, "network down")
+#endif
+#ifdef ENETUNREACH
+ X(ENETUNREACH, "network unreachable")
+#endif
+#ifdef ENETRESET
+ X(ENETRESET, "network reset")
+#endif
+#ifdef ECONNABORTED
+ X(ECONNABORTED, "connection aborted")
+#endif
+#ifdef ECONNRESET
+ X(ECONNRESET, "connection reset")
+#endif
+#ifdef EISCONN
+ X(EISCONN, "already connected")
+#endif
+#ifdef ENOTCONN
+ X(ENOTCONN, "not connected")
+#endif
+#ifdef ESHUTDOWN
+ X(ESHUTDOWN, "socket shut down")
+#endif
+#ifdef ETOOMANYREFS
+ X(ETOOMANYREFS, "too many references")
+#endif
+#ifdef ELOOP
+ X(ELOOP, "symbolic link loop")
+#endif
+#ifdef ENAMETOOLONG
+ X(ENAMETOOLONG, "file name too long")
+#endif
+#ifdef EHOSTDOWN
+ X(EHOSTDOWN, "host down")
+#endif
+#ifdef EHOSTUNREACH
+ X(EHOSTUNREACH, "host unreachable")
+#endif
+#ifdef ENOTEMPTY
+ X(ENOTEMPTY, "directory not empty")
+#endif
+#ifdef EPROCLIM
+ X(EPROCLIM, "too many processes")
+#endif
+#ifdef EUSERS
+ X(EUSERS, "too many users")
+#endif
+#ifdef EDQUOT
+ X(EDQUOT, "disk quota exceeded")
+#endif
+#ifdef ESTALE
+ X(ESTALE, "stale NFS file handle")
+#endif
+#ifdef EREMOTE
+ X(EREMOTE, "too many levels of remote in path")
+#endif
+#ifdef EBADRPC
+ X(EBADRPC, "RPC structure is bad")
+#endif
+#ifdef ERPCMISMATCH
+ X(ERPCMISMATCH, "RPC version mismatch")
+#endif
+#ifdef EPROGUNAVAIL
+ X(EPROGUNAVAIL, "RPC program unavailable")
+#endif
+#ifdef EPROGMISMATCH
+ X(EPROGMISMATCH, "program version mismatch")
+#endif
+#ifdef EPROCUNAVAIL
+ X(EPROCUNAVAIL, "bad procedure for program")
+#endif
+#ifdef ENOLCK
+ X(ENOLCK, "no locks available")
+#endif
+#ifdef ENOSYS
+ X(ENOSYS, "system call not available")
+#endif
+#ifdef EFTYPE
+ X(EFTYPE, "bad file type")
+#endif
+#ifdef EAUTH
+ X(EAUTH, "authentication error")
+#endif
+#ifdef ENEEDAUTH
+ X(ENEEDAUTH, "not authenticated")
+#endif
+#ifdef ENOSTR
+ X(ENOSTR, "not a stream device")
+#endif
+#ifdef ETIME
+ X(ETIME, "timer expired")
+#endif
+#ifdef ENOSR
+ X(ENOSR, "out of stream resources")
+#endif
+#ifdef ENOMSG
+ X(ENOMSG, "no message of desired type")
+#endif
+#ifdef EBADMSG
+ X(EBADMSG, "bad message type")
+#endif
+#ifdef EIDRM
+ X(EIDRM, "identifier removed")
+#endif
+#ifdef ENONET
+ X(ENONET, "machine not on network")
+#endif
+#ifdef ERREMOTE
+ X(ERREMOTE, "object not local")
+#endif
+#ifdef ENOLINK
+ X(ENOLINK, "link severed")
+#endif
+#ifdef EADV
+ X(EADV, "advertise error")
+#endif
+#ifdef ESRMNT
+ X(ESRMNT, "srmount error")
+#endif
+#ifdef ECOMM
+ X(ECOMM, "communication error")
+#endif
+#ifdef EMULTIHOP
+ X(EMULTIHOP, "multihop attempted")
+#endif
+#ifdef EREMCHG
+ X(EREMCHG, "remote address changed")
+#endif
+ default : return "unknown error" ;
+ }
+}
+
+#endif
diff --git a/src/libstddjb/error_temp.c b/src/libstddjb/error_temp.c
new file mode 100644
index 0000000..48a54f5
--- /dev/null
+++ b/src/libstddjb/error_temp.c
@@ -0,0 +1,78 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/error.h>
+
+int error_temp (register int e)
+{
+ if (error_isagain(e)) return 1 ;
+ switch (e)
+ {
+ case 0 :
+ case EINTR :
+ case ENOMEM :
+ case ETXTBSY :
+ case EIO :
+ case ETIMEDOUT :
+ case ENOBUFS :
+#ifdef EDEADLK
+ case EDEADLK :
+#endif
+#ifdef EBUSY
+ case EBUSY :
+#endif
+#ifdef ENFILE
+ case ENFILE :
+#endif
+#ifdef EFBIG
+ case EFBIG :
+#endif
+#ifdef ENOSPC
+ case ENOSPC :
+#endif
+#ifdef ENETDOWN
+ case ENETDOWN :
+#endif
+#ifdef ENETUNREACH
+ case ENETUNREACH :
+#endif
+#ifdef ENETRESET
+ case ENETRESET :
+#endif
+#ifdef ECONNABORTED
+ case ECONNABORTED :
+#endif
+#ifdef ECONNRESET
+ case ECONNRESET :
+#endif
+#ifdef ETOOMANYREFS
+ case ETOOMANYREFS :
+#endif
+#ifdef ECONNREFUSED
+ case ECONNREFUSED :
+#endif
+#ifdef EHOSTDOWN
+ case EHOSTDOWN :
+#endif
+#ifdef EHOSTUNREACH
+ case EHOSTUNREACH :
+#endif
+#ifdef EPROCLIM
+ case EPROCLIM :
+#endif
+#ifdef EUSERS
+ case EUSERS :
+#endif
+#ifdef EDQUOT
+ case EDQUOT :
+#endif
+#ifdef ESTALE
+ case ESTALE :
+#endif
+#ifdef ENOLCK
+ case ENOLCK :
+#endif
+ return 1 ;
+ default : return 0 ;
+ }
+}
diff --git a/src/libstddjb/execvep.c b/src/libstddjb/execvep.c
new file mode 100644
index 0000000..1639236
--- /dev/null
+++ b/src/libstddjb/execvep.c
@@ -0,0 +1,38 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/djbunix.h>
+
+void execvep (char const *file, char const *const *argv, char const *const *envp, char const *path)
+{
+ if (!path) errno = EINVAL ;
+ else if (file[str_chr(file, '/')])
+ execve(file, (char *const *)argv, (char *const *)envp) ; /* execve prototype sucks */
+ else
+ {
+ unsigned int pathlen = str_len(path) + 1 ;
+ unsigned int filelen = str_len(file) ;
+ int savederrno = 0 ;
+ while (pathlen)
+ {
+ unsigned int split = byte_chr(path, pathlen - 1, ':') ;
+ if (split)
+ {
+ char tmp[split + 2 + filelen] ;
+ byte_copy(tmp, split, path) ;
+ tmp[split] = '/' ;
+ byte_copy(tmp + split + 1, filelen + 1, file) ;
+ execve(tmp, (char *const *)argv, (char *const *)envp) ;
+ if (errno != ENOENT)
+ {
+ savederrno = errno ;
+ if ((errno != EACCES) && (errno != EPERM) && (errno != EISDIR)) break ;
+ }
+ }
+ path += split+1 ; pathlen -= split+1 ;
+ }
+ if (savederrno) errno = savederrno ;
+ }
+}
diff --git a/src/libstddjb/fd_cat.c b/src/libstddjb/fd_cat.c
new file mode 100644
index 0000000..5682f02
--- /dev/null
+++ b/src/libstddjb/fd_cat.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+#include <skalibs/iobuffer.h>
+#include <skalibs/djbunix.h>
+
+int fd_cat (int from, int to)
+{
+ iobuffer b ;
+ unsigned int n = 0 ;
+ if (!iobuffer_init(&b, from, to)) return -1 ;
+ for (;;)
+ {
+ register int r = iobuffer_fill(&b) ;
+ if (r < 0) goto err ;
+ else if (!r) break ;
+ if (!iobuffer_flush(&b)) goto err ;
+ n += r ;
+ }
+ iobuffer_finish(&b) ;
+ return n ;
+
+ err:
+ iobuffer_finish(&b) ;
+ return -1 ;
+}
diff --git a/src/libstddjb/fd_catn.c b/src/libstddjb/fd_catn.c
new file mode 100644
index 0000000..ca78546
--- /dev/null
+++ b/src/libstddjb/fd_catn.c
@@ -0,0 +1,42 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/iobuffer.h>
+#include <skalibs/djbunix.h>
+
+unsigned int fd_catn (int from, int to, unsigned int n)
+{
+ unsigned int w = 0 ;
+ if (n >= IOBUFFER_SIZE)
+ {
+ iobuffer b ;
+ if (!iobuffer_init(&b, from, to)) return 0 ;
+ while (n >= IOBUFFER_SIZE)
+ {
+ register int r = iobuffer_fill(&b) ;
+ if (r <= 0)
+ {
+ iobuffer_finish(&b) ;
+ if (!r) errno = EPIPE ;
+ return w ;
+ }
+ if (!iobuffer_flush(&b))
+ {
+ iobuffer_finish(&b) ;
+ return w ;
+ }
+ n -= r ; w += r ;
+ }
+ iobuffer_finish(&b) ;
+ }
+
+ {
+ char buf[n] ;
+ unsigned int r = allread(from, buf, n) ;
+ unsigned int v = 0 ;
+ if (r) v = allwrite(to, buf, r) ;
+ w += v ;
+ }
+ return w ;
+}
diff --git a/src/libstddjb/fd_chdir.c b/src/libstddjb/fd_chdir.c
new file mode 100644
index 0000000..e09656e
--- /dev/null
+++ b/src/libstddjb/fd_chdir.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+int fd_chdir (int d)
+{
+ register int r ;
+ do
+ r = fchdir(d) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/fd_chmod.c b/src/libstddjb/fd_chmod.c
new file mode 100644
index 0000000..a70c537
--- /dev/null
+++ b/src/libstddjb/fd_chmod.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+ /* OpenBSD manages to bork the fchmod declaration */
+#include <skalibs/nonposix.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+int fd_chmod (int fd, unsigned int mode)
+{
+ register int r ;
+ do
+ r = fchmod(fd, (mode_t)mode) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/fd_chown.c b/src/libstddjb/fd_chown.c
new file mode 100644
index 0000000..8aa36c8
--- /dev/null
+++ b/src/libstddjb/fd_chown.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+int fd_chown (int fd, unsigned int uid, unsigned int gid)
+{
+ register int r ;
+ do
+ r = fchown(fd, (uid_t)uid, (gid_t)gid) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/fd_close.c b/src/libstddjb/fd_close.c
new file mode 100644
index 0000000..8b107f6
--- /dev/null
+++ b/src/libstddjb/fd_close.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+int fd_close (int fd)
+{
+ register unsigned int i = 0 ;
+doit:
+ if (!close(fd)) return 0 ;
+ i++ ;
+ if (errno == EINTR) goto doit ;
+ return ((errno == EBADF) && (i > 1)) ? 0 : -1 ;
+}
diff --git a/src/libstddjb/fd_copy.c b/src/libstddjb/fd_copy.c
new file mode 100644
index 0000000..b051eaf
--- /dev/null
+++ b/src/libstddjb/fd_copy.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+int fd_copy (int to, int from)
+{
+ register int r ;
+ if (to == from) return (errno = EINVAL, -1) ;
+ do
+ r = dup2(from, to) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/fd_copy2.c b/src/libstddjb/fd_copy2.c
new file mode 100644
index 0000000..5537329
--- /dev/null
+++ b/src/libstddjb/fd_copy2.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+int fd_copy2 (int to1, int from1, int to2, int from2)
+{
+ if ((to1 == from2) || (to2 == from1)) return (errno = EINVAL, -1) ;
+ if (fd_copy(to1, from1) == -1) return -1 ;
+ if (fd_copy(to2, from2) == -1)
+ {
+ if (to1 != from1) fd_close(to1) ;
+ return -1 ;
+ }
+ return 0 ;
+}
diff --git a/src/libstddjb/fd_ensure_open.c b/src/libstddjb/fd_ensure_open.c
new file mode 100644
index 0000000..b399af2
--- /dev/null
+++ b/src/libstddjb/fd_ensure_open.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <skalibs/djbunix.h>
+
+int fd_ensure_open (int fd, int w)
+{
+ int dummy ;
+ if (fcntl(fd, F_GETFD, &dummy) < 0)
+ {
+ int newfd ;
+ if (errno != EBADF) return 0 ;
+ newfd = open2("/dev/null", w ? O_WRONLY : O_RDONLY) ;
+ if (newfd < 0) return 0 ;
+ if (fd_move(fd, newfd) < 0)
+ {
+ register int e = errno ;
+ fd_close(newfd) ;
+ errno = e ;
+ return 0 ;
+ }
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/fd_move.c b/src/libstddjb/fd_move.c
new file mode 100644
index 0000000..d79f8ac
--- /dev/null
+++ b/src/libstddjb/fd_move.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+int fd_move (int to, int from)
+{
+ register int r ;
+ if (to == from) return 0 ;
+ do
+ r = dup2(from, to) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return (r == -1) ? -1 : fd_close(from) ;
+}
diff --git a/src/libstddjb/fd_move2.c b/src/libstddjb/fd_move2.c
new file mode 100644
index 0000000..7894e2f
--- /dev/null
+++ b/src/libstddjb/fd_move2.c
@@ -0,0 +1,37 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+int fd_move2 (int to1, int from1, int to2, int from2)
+{
+ register int tmp = from2 ;
+ if (to1 == from1) return fd_move(to2, from2) ;
+ if (to2 == from2) return fd_move(to1, from1) ;
+ if (from1 == from2) return (to1 == to2) ? fd_move(to1, from1) : (errno = EINVAL, -1) ;
+ if (to1 == to2) return (errno = EINVAL, -1) ;
+ if (from2 == to1)
+ {
+ tmp = dup(from2) ;
+ if (tmp == -1) return -1 ;
+ }
+ if (fd_copy(to1, from1) == -1)
+ {
+ register int e = errno ;
+ if (from2 != tmp) fd_close(tmp) ;
+ errno = e ;
+ return -1 ;
+ }
+ if (fd_copy(to2, tmp) == -1)
+ {
+ register int e = errno ;
+ fd_close(to1) ;
+ if (from2 != tmp) fd_move(from2, tmp) ;
+ errno = e ;
+ return -1 ;
+ }
+ if (from1 != to2) fd_close(from1) ;
+ fd_close(tmp) ;
+ return 0 ;
+}
diff --git a/src/libstddjb/fd_read.c b/src/libstddjb/fd_read.c
new file mode 100644
index 0000000..22a296b
--- /dev/null
+++ b/src/libstddjb/fd_read.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+
+int fd_read (int fd, char *buf, unsigned int len)
+{
+ register int r ;
+ do r = read(fd, buf, len) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/fd_readv.c b/src/libstddjb/fd_readv.c
new file mode 100644
index 0000000..c97d7ab
--- /dev/null
+++ b/src/libstddjb/fd_readv.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+
+int fd_readv (int fd, struct iovec const *v, unsigned int vlen)
+{
+ register int r ;
+ do r = readv(fd, v, vlen) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/fd_recv.c b/src/libstddjb/fd_recv.c
new file mode 100644
index 0000000..592dc8e
--- /dev/null
+++ b/src/libstddjb/fd_recv.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+
+int fd_recv (int fd, char *buf, unsigned int len, unsigned int flags)
+{
+ register int r ;
+ do r = recv(fd, buf, len, (int)flags) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/fd_select.c b/src/libstddjb/fd_select.c
new file mode 100644
index 0000000..846485d
--- /dev/null
+++ b/src/libstddjb/fd_select.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <sys/select.h>
+
+int fd_select (int n, fd_set *rfds, fd_set *wfds, fd_set *xfds, struct timeval *tv)
+{
+ register int r ;
+ do
+ r = select(n, rfds, wfds, xfds, tv) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/fd_send.c b/src/libstddjb/fd_send.c
new file mode 100644
index 0000000..cdc3dd2
--- /dev/null
+++ b/src/libstddjb/fd_send.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+
+int fd_send (int fd, char const *buf, unsigned int len, unsigned int flags)
+{
+ register int r ;
+ do r = send(fd, buf, len, (int)flags) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/fd_sync.c b/src/libstddjb/fd_sync.c
new file mode 100644
index 0000000..db54136
--- /dev/null
+++ b/src/libstddjb/fd_sync.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+int fd_sync (int fd)
+{
+ register int r ;
+ do
+ r = fsync(fd) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/fd_write.c b/src/libstddjb/fd_write.c
new file mode 100644
index 0000000..636bce9
--- /dev/null
+++ b/src/libstddjb/fd_write.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+
+int fd_write (int fd, char const *buf, unsigned int len)
+{
+ register int r ;
+ do r = write(fd, buf, len) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/fd_writev.c b/src/libstddjb/fd_writev.c
new file mode 100644
index 0000000..d48d7f1
--- /dev/null
+++ b/src/libstddjb/fd_writev.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+
+int fd_writev (int fd, struct iovec const *v, unsigned int vlen)
+{
+ register int r ;
+ do r = writev(fd, v, vlen) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/fmtscan-internal.h b/src/libstddjb/fmtscan-internal.h
new file mode 100644
index 0000000..b1cac3e
--- /dev/null
+++ b/src/libstddjb/fmtscan-internal.h
@@ -0,0 +1,105 @@
+/* ISC license. */
+
+#ifndef FMTSCAN_INTERNAL_H
+#define FMTSCAN_INTERNAL_H
+
+#include <errno.h>
+#include <limits.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/fmtscan.h>
+
+#define SCANB(bits) \
+unsigned int uint##bits##_scan_base (char const *s, uint##bits *u, unsigned char base) \
+{ \
+ static uint##bits const max = (uint##bits)(-1) ; \
+ uint##bits result = 0 ; \
+ unsigned int pos = 0 ; \
+ for (;; pos++) \
+ { \
+ register unsigned char c = fmtscan_num(s[pos], base) ; \
+ if ((c >= base) || (result > ((max - c) / base))) break ; \
+ result = result * base + c ; \
+ } \
+ if (pos) *u = result ; \
+ return pos ; \
+} \
+
+#define SCANB0(bits) \
+unsigned int uint##bits##0_scan_base (char const *s, uint##bits *u, unsigned char base) \
+{ \
+ register unsigned int pos = uint##bits##_scan_base(s, u, base) ; \
+ if (!pos) return (errno = EINVAL, 0) ; \
+ if (!s[pos]) return pos ; \
+ errno = (fmtscan_num(s[pos], base) < base) ? EDOM : EINVAL ; \
+ return 0 ; \
+} \
+
+#define SCANS(type, cstname) \
+unsigned int type##_scan (char const *s, type *n) \
+{ \
+ unsigned type tmp ; \
+ register unsigned int r = 0 ; \
+ register unsigned int sign = 0 ; \
+ if (*s == '-') \
+ { \
+ r = 1 + u##type##_scan(s+1, &tmp) ; \
+ if (r == 1) return 0 ; \
+ if (tmp == 0) *n = 0 ; \
+ else \
+ { \
+ if (tmp-1 > -(cstname##_MIN+1)) \
+ { \
+ tmp /= 10 ; \
+ r-- ; \
+ } \
+ *n = cstname##_MIN + (-(cstname##_MIN+1) - (tmp-1)) ; \
+ } \
+ return r ; \
+ } \
+ if (*s == '+') (s++, sign++) ; \
+ r = u##type##_scan(s, &tmp) ; \
+ if (!r) return 0 ; \
+ r += sign ; \
+ if (tmp > cstname##_MAX) \
+ { \
+ tmp /= 10 ; \
+ r-- ; \
+ } \
+ *n = tmp ; \
+ return r ; \
+} \
+
+#define SCANL(bits) \
+unsigned int uint##bits##_scanlist (uint##bits *tab, unsigned int max, char const *s, unsigned int *num) \
+{ \
+ unsigned int i = 0, len = 0 ; \
+ for (; s[len] && (i < max) ; i++) \
+ { \
+ register unsigned int w = uint##bits##_scan(s + len, tab + i) ; \
+ if (!w) break ; \
+ len += w ; \
+ while (byte_chr(",:; \t\r\n", 7, s[len]) < 7) len++ ; \
+ } \
+ *num = i ; \
+ return len ; \
+} \
+
+#define FMTL(bits) \
+unsigned int uint##bits##_fmtlist (char *s, uint##bits const *tab, unsigned int n) \
+{ \
+ unsigned int i = 0, len = 0 ; \
+ for (; i < n ; i++) \
+ { \
+ register unsigned int w = uint##bits##_fmt(s, tab[i]) ; \
+ len += w ; \
+ if (s) \
+ { \
+ s += w ; \
+ if (i < n-1) { *s++ = ',' ; len++ ; } \
+ } \
+ } \
+ return len ; \
+} \
+
+
+#endif
diff --git a/src/libstddjb/fmtscan_asc.c b/src/libstddjb/fmtscan_asc.c
new file mode 100644
index 0000000..c33c0ec
--- /dev/null
+++ b/src/libstddjb/fmtscan_asc.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/fmtscan.h>
+
+unsigned char fmtscan_asc (unsigned char c)
+{
+ static char const *tab = "0123456789abcdefghijklmnopqrstuvwxyz" ;
+ return (c >= 36) ? 0 : tab[c] ;
+}
diff --git a/src/libstddjb/fmtscan_num.c b/src/libstddjb/fmtscan_num.c
new file mode 100644
index 0000000..094eb2a
--- /dev/null
+++ b/src/libstddjb/fmtscan_num.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <skalibs/fmtscan.h>
+
+unsigned char fmtscan_num (register unsigned char c, unsigned char n)
+{
+ return
+ ((c < '0') || (n > 36)) ? n :
+ (n <= 10) ? (c - '0' <= n) ? c - '0' : n :
+ (c - '0' <= 9) ? c - '0' :
+ (c < 'A') ? n :
+ (c - 'A' < n - 10) ? c - 'A' + 10 :
+ (c < 'a') ? n :
+ (c - 'a' < n - 10) ? c - 'a' + 10 :
+ n ;
+}
diff --git a/src/libstddjb/genalloc_deepfree.c b/src/libstddjb/genalloc_deepfree.c
new file mode 100644
index 0000000..cda800a
--- /dev/null
+++ b/src/libstddjb/genalloc_deepfree.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+
+void genalloc_deepfree_size (genalloc *g, freefunc_t_ref f, unsigned int size)
+{
+ unsigned int len = g->len / size ;
+ register unsigned int i = 0 ;
+ for (; i < len ; i++) (*f)(g->s + i * size) ;
+ stralloc_free(g) ;
+}
diff --git a/src/libstddjb/genwrite_flush_bufalloc.c b/src/libstddjb/genwrite_flush_bufalloc.c
new file mode 100644
index 0000000..6383246
--- /dev/null
+++ b/src/libstddjb/genwrite_flush_bufalloc.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/bufalloc.h>
+#include <skalibs/genwrite.h>
+
+int genwrite_flush_bufalloc (void *target)
+{
+ register bufalloc *ba = target ;
+ return bufalloc_flush(ba) ;
+}
diff --git a/src/libstddjb/genwrite_flush_buffer.c b/src/libstddjb/genwrite_flush_buffer.c
new file mode 100644
index 0000000..d30f3e6
--- /dev/null
+++ b/src/libstddjb/genwrite_flush_buffer.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/genwrite.h>
+
+int genwrite_flush_buffer (void *target)
+{
+ register buffer *b = target ;
+ return buffer_flush(b) ;
+}
diff --git a/src/libstddjb/genwrite_flush_stralloc.c b/src/libstddjb/genwrite_flush_stralloc.c
new file mode 100644
index 0000000..f623941
--- /dev/null
+++ b/src/libstddjb/genwrite_flush_stralloc.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/genwrite.h>
+
+int genwrite_flush_stralloc (void *target)
+{
+ (void)target ;
+ return 1 ;
+}
diff --git a/src/libstddjb/genwrite_put_bufalloc.c b/src/libstddjb/genwrite_put_bufalloc.c
new file mode 100644
index 0000000..6aabe1c
--- /dev/null
+++ b/src/libstddjb/genwrite_put_bufalloc.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/bufalloc.h>
+#include <skalibs/genwrite.h>
+
+int genwrite_put_bufalloc (void *target, char const *s, unsigned int len)
+{
+ register bufalloc *ba = target ;
+ return bufalloc_put(ba, s, len) ? (int)len : -1 ;
+}
diff --git a/src/libstddjb/genwrite_put_buffer.c b/src/libstddjb/genwrite_put_buffer.c
new file mode 100644
index 0000000..1c85725
--- /dev/null
+++ b/src/libstddjb/genwrite_put_buffer.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/genwrite.h>
+
+int genwrite_put_buffer (void *target, char const *s, unsigned int len)
+{
+ register buffer *b = target ;
+ return buffer_put(b, s, len) ;
+}
diff --git a/src/libstddjb/genwrite_put_stralloc.c b/src/libstddjb/genwrite_put_stralloc.c
new file mode 100644
index 0000000..2a8a8e8
--- /dev/null
+++ b/src/libstddjb/genwrite_put_stralloc.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/genwrite.h>
+
+int genwrite_put_stralloc (void *target, char const *s, unsigned int len)
+{
+ register stralloc *sa = target ;
+ return stralloc_catb(sa, s, len) ? (int)len : -1 ;
+}
diff --git a/src/libstddjb/genwrite_stderr.c b/src/libstddjb/genwrite_stderr.c
new file mode 100644
index 0000000..1d6bae3
--- /dev/null
+++ b/src/libstddjb/genwrite_stderr.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/genwrite.h>
+
+genwrite_t genwrite_stderr = GENWRITE_BUFFER_INIT(buffer_2) ;
diff --git a/src/libstddjb/genwrite_stdout.c b/src/libstddjb/genwrite_stdout.c
new file mode 100644
index 0000000..4fec080
--- /dev/null
+++ b/src/libstddjb/genwrite_stdout.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/genwrite.h>
+
+genwrite_t genwrite_stdout = GENWRITE_BUFFER_INIT(buffer_1) ;
diff --git a/src/libstddjb/getlnmax.c b/src/libstddjb/getlnmax.c
new file mode 100644
index 0000000..e3fde8f
--- /dev/null
+++ b/src/libstddjb/getlnmax.c
@@ -0,0 +1,28 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/buffer.h>
+#include <skalibs/skamisc.h>
+
+int getlnmax (buffer *b, char *d, unsigned int max, unsigned int *w, char sep)
+{
+ if (max < *w) return (errno = EINVAL, -1) ;
+ for (;;)
+ {
+ siovec_t v[2] ;
+ unsigned int len = buffer_len(b) ;
+ unsigned int pos ;
+ int r ;
+ buffer_rpeek(b, v) ;
+ if (len > max - *w) len = max - *w ;
+ pos = siovec_bytechr(v, 2, sep) ;
+ if (pos > len) pos = len ;
+ r = pos < len ;
+ buffer_getnofill(b, d + *w, pos + r) ; *w += pos ;
+ if (*w >= max) return (errno = ERANGE, -1) ;
+ if (r) return 1 ;
+ r = buffer_fill(b) ;
+ if (r <= 0) return r ;
+ }
+}
diff --git a/src/libstddjb/getlnmaxsep.c b/src/libstddjb/getlnmaxsep.c
new file mode 100644
index 0000000..2bde443
--- /dev/null
+++ b/src/libstddjb/getlnmaxsep.c
@@ -0,0 +1,28 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/buffer.h>
+#include <skalibs/skamisc.h>
+
+int getlnmaxsep (buffer *b, char *d, unsigned int max, unsigned int *w, char const *sep, unsigned int seplen)
+{
+ if (max < *w) return (errno = EINVAL, -1) ;
+ for (;;)
+ {
+ siovec_t v[2] ;
+ unsigned int len = buffer_len(b) ;
+ unsigned int pos ;
+ int r ;
+ buffer_rpeek(b, v) ;
+ if (len > max - *w) len = max - *w ;
+ pos = siovec_bytein(v, 2, sep, seplen) ;
+ if (pos > len) pos = len ;
+ r = pos < len ;
+ buffer_getnofill(b, d + *w, pos + r) ; *w += pos ;
+ if (*w >= max) return (errno = ERANGE, -1) ;
+ if (r) return 1 ;
+ r = buffer_fill(b) ;
+ if (r <= 0) return r ;
+ }
+}
diff --git a/src/libstddjb/getpeereid.c b/src/libstddjb/getpeereid.c
new file mode 100644
index 0000000..bf70aca
--- /dev/null
+++ b/src/libstddjb/getpeereid.c
@@ -0,0 +1,68 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASGETPEEREID
+/* syscall exists - do nothing */
+
+#else
+
+#ifdef SKALIBS_HASSOPEERCRED
+/* implementation with SO_PEERCRED */
+
+#include <skalibs/nonposix.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <skalibs/getpeereid.h>
+
+int getpeereid (int s, uid_t *u, gid_t *g)
+{
+ struct ucred blah ;
+ unsigned int len = sizeof(blah) ;
+
+ if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &blah, &len) == -1)
+ return -1 ;
+ *u = blah.uid ;
+ *g = blah.gid ;
+ return 0 ;
+}
+
+#else
+
+#ifdef SKALIBS_HASGETPEERUCRED
+/* implementation with getpeerucred() */
+
+#include <skalibs/nonposix.h>
+#include <sys/types.h>
+#include <ucred.h>
+
+int getpeereid (int s, uid_t *u, gid_t *g)
+{
+ ucred_t *cred ;
+ if (getpeerucred(s, &cred) == -1) return -1 ;
+ *u = ucred_geteuid(cred) ;
+ *g = ucred_getegid(cred) ;
+ ucred_free(cred) ;
+ return 0 ;
+}
+
+#else
+
+/* can't find a real implementation, make a stub */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <skalibs/getpeereid.h>
+
+int getpeereid (int s, uid_t *uid, gid_t *gid)
+{
+ (void)s ;
+ *uid = *gid = -1 ;
+ errno = ENOSYS ;
+ return -1 ;
+}
+
+#endif
+#endif
+#endif
diff --git a/src/libstddjb/int_scan.c b/src/libstddjb/int_scan.c
new file mode 100644
index 0000000..2547a04
--- /dev/null
+++ b/src/libstddjb/int_scan.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include "fmtscan-internal.h"
+
+SCANS(int, INT)
diff --git a/src/libstddjb/iobuffer_fill.c b/src/libstddjb/iobuffer_fill.c
new file mode 100644
index 0000000..991dffc
--- /dev/null
+++ b/src/libstddjb/iobuffer_fill.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/iobuffer.h>
+
+int iobuffer_fill (iobuffer_ref b)
+{
+ if (b->isk)
+ {
+ register int r = iobufferk_fill(&b->x.k) ;
+ if (r >= 0 || errno != ENOSYS || !iobuffer_salvage(b)) return r ;
+ }
+ return iobufferu_fill(&b->x.u) ;
+}
diff --git a/src/libstddjb/iobuffer_flush.c b/src/libstddjb/iobuffer_flush.c
new file mode 100644
index 0000000..543744b
--- /dev/null
+++ b/src/libstddjb/iobuffer_flush.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/iobuffer.h>
+
+int iobuffer_flush (iobuffer_ref b)
+{
+ if (b->isk)
+ {
+ if (iobufferk_flush(&b->x.k)) return 1 ;
+ if (errno != ENOSYS || !iobuffer_salvage(b)) return 0 ;
+ }
+ return iobufferu_flush(&b->x.u) ;
+}
diff --git a/src/libstddjb/iobuffer_init.c b/src/libstddjb/iobuffer_init.c
new file mode 100644
index 0000000..561379a
--- /dev/null
+++ b/src/libstddjb/iobuffer_init.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/iobuffer.h>
+
+int iobuffer_init (iobuffer_ref b, int fdin, int fdout)
+{
+ if (!iobufferk_init(&b->x.k, fdin, fdout)) goto user ;
+ if (!iobufferk_isworking(&b->x.k)) goto fk ;
+ b->isk = 1 ;
+ return 1 ;
+ fk:
+ iobufferk_finish(&b->x.k) ;
+ user:
+ if (!iobufferu_init(&b->x.u, fdin, fdout)) return 0 ;
+ b->isk = 0 ;
+ return 1 ;
+}
diff --git a/src/libstddjb/iobuffer_kfromu.c b/src/libstddjb/iobuffer_kfromu.c
new file mode 100644
index 0000000..28785e6
--- /dev/null
+++ b/src/libstddjb/iobuffer_kfromu.c
@@ -0,0 +1,41 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASSPLICE
+
+#include <skalibs/nonposix.h>
+#include <fcntl.h>
+#include <sys/uio.h>
+#include <skalibs/buffer.h>
+#include <skalibs/iobuffer.h>
+#include <skalibs/siovec.h>
+
+int iobuffer_kfromu (iobufferk_ref k, iobufferu_ref u)
+{
+ struct iovec iov[2] ;
+ siovec_t v[2] ;
+ int r ;
+ buffer_rpeek(&u->b[0], v) ;
+ iovec_from_siovec(iov, v, 2) ;
+ r = vmsplice(k->p[1], iov, 2, 0) ;
+ if (r < 0) return 0 ;
+ k->n += r ;
+ buffer_rseek(&u->b[0], (unsigned int)r) ;
+ u->b[1].c.p = u->b[0].c.p ;
+ return iobufferu_isempty(u) ;
+}
+
+#else
+
+#include <errno.h>
+#include <skalibs/iobuffer.h>
+
+int iobuffer_kfromu (iobufferk_ref k, iobufferu_ref u)
+{
+ (void)k ;
+ (void)u ;
+ return (errno = ENOSYS, 0) ;
+}
+
+#endif
diff --git a/src/libstddjb/iobuffer_salvage.c b/src/libstddjb/iobuffer_salvage.c
new file mode 100644
index 0000000..b434568
--- /dev/null
+++ b/src/libstddjb/iobuffer_salvage.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <skalibs/iobuffer.h>
+
+int iobuffer_salvage (iobuffer_ref b)
+{
+ iobufferu u ;
+ if (!b->isk) return 1 ;
+ if (!iobufferu_init(&u, b->x.k.fd[0], b->x.k.fd[1])) return 0 ;
+ if (!iobuffer_ufromk(&u, &b->x.k)) goto err ;
+ iobufferk_finish(&b->x.k) ;
+ b->x.u = u ;
+ b->isk = 0 ;
+ return 1 ;
+
+err:
+ iobufferu_finish(&u) ;
+ return 0 ;
+}
diff --git a/src/libstddjb/iobuffer_ufromk.c b/src/libstddjb/iobuffer_ufromk.c
new file mode 100644
index 0000000..efb0368
--- /dev/null
+++ b/src/libstddjb/iobuffer_ufromk.c
@@ -0,0 +1,39 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASSPLICE
+
+#include <skalibs/iobuffer.h>
+
+int iobuffer_ufromk (iobufferu_ref u, iobufferk_ref k)
+{
+ int in = u->b[0].fd ;
+ u->b[0].fd = k->p[0] ;
+ while (k->n)
+ {
+ register int r = iobufferu_fill(u) ;
+ if (r <= 0) goto err ;
+ k->n -= r ;
+ }
+ u->b[0].fd = in ;
+ return 1 ;
+
+ err:
+ u->b[0].fd = in ;
+ return 0 ;
+}
+
+#else
+
+#include <errno.h>
+#include <skalibs/iobuffer.h>
+
+int iobuffer_ufromk (iobufferu_ref u, iobufferk_ref k)
+{
+ (void)u ;
+ (void)k ;
+ return (errno = ENOSYS, 0) ;
+}
+
+#endif
diff --git a/src/libstddjb/iobufferk_fill.c b/src/libstddjb/iobufferk_fill.c
new file mode 100644
index 0000000..50ac403
--- /dev/null
+++ b/src/libstddjb/iobufferk_fill.c
@@ -0,0 +1,49 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASSPLICE
+
+#include <skalibs/nonposix.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <skalibs/iobuffer.h>
+
+static int iobufferk_tee (iobufferk_ref k)
+{
+ register int r = tee(k->fd[0], k->fd[1], IOBUFFERK_SIZE - k->n, k->nb & 1 ? SPLICE_F_NONBLOCK : 0) ;
+ if (r > 0) k->n += r ;
+ return r ;
+}
+
+static int iobufferk_splice (iobufferk_ref k)
+{
+ register int r = splice(k->fd[0], 0, k->fd[1], 0, IOBUFFERK_SIZE, k->nb ? SPLICE_F_NONBLOCK : 0) ;
+ if (r > 0) k->n += r ;
+ if ((r < 0) && (errno == EINVAL)) errno = ENOSYS ;
+ return r ;
+}
+
+static int iobufferk_fill_3 (iobufferk_ref k)
+{
+ register int r = splice(k->fd[0], 0, k->p[1], 0, IOBUFFERK_SIZE - k->n, k->nb & 1 ? SPLICE_F_NONBLOCK : 0) ;
+ if (r > 0) k->n += r ;
+ if ((r < 0) && (errno == EINVAL)) errno = ENOSYS ;
+ return r ;
+}
+
+iobufferk_io_func_t_ref const iobufferk_fill_f[4] =
+{
+ &iobufferk_tee, &iobufferk_splice, &iobufferk_splice, &iobufferk_fill_3
+} ;
+
+#else
+
+#include <skalibs/iobuffer.h>
+
+iobufferk_io_func_t_ref const iobufferk_fill_f[4] =
+{
+ &iobufferk_nosys, &iobufferk_nosys, &iobufferk_nosys, &iobufferk_nosys
+} ;
+
+#endif
diff --git a/src/libstddjb/iobufferk_finish.c b/src/libstddjb/iobufferk_finish.c
new file mode 100644
index 0000000..ef20d57
--- /dev/null
+++ b/src/libstddjb/iobufferk_finish.c
@@ -0,0 +1,50 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASSPLICE
+
+#include <errno.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/iobuffer.h>
+
+static void iobufferk_nop (iobufferk_ref k)
+{
+ (void)k ;
+}
+
+static void iobufferk_finish_0 (iobufferk_ref k)
+{
+ register int e = errno ;
+ fd_close(k->p[1]) ;
+ errno = e ;
+}
+
+static void iobufferk_finish_3 (iobufferk_ref k)
+{
+ register int e = errno ;
+ fd_close(k->p[1]) ;
+ fd_close(k->p[0]) ;
+ errno = e ;
+}
+
+iobufferk_finish_func_t_ref const iobufferk_finish_f[4] =
+{
+ &iobufferk_finish_0, &iobufferk_nop, &iobufferk_nop, &iobufferk_finish_3
+} ;
+
+#else
+
+#include <skalibs/iobuffer.h>
+
+static void iobufferk_nop (iobufferk_ref k)
+{
+ (void)k ;
+}
+
+iobufferk_finish_func_t_ref const iobufferk_finish_f[4] =
+{
+ &iobufferk_nop, &iobufferk_nop, &iobufferk_nop, &iobufferk_nop
+} ;
+
+#endif
diff --git a/src/libstddjb/iobufferk_flush.c b/src/libstddjb/iobufferk_flush.c
new file mode 100644
index 0000000..fb51e32
--- /dev/null
+++ b/src/libstddjb/iobufferk_flush.c
@@ -0,0 +1,61 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASSPLICE
+
+#include <skalibs/nonposix.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <skalibs/iobuffer.h>
+
+static int iobufferk_flush_0 (iobufferk_ref k)
+{
+ while (k->n)
+ {
+ register int r = splice(k->fd[0], 0, k->p[1], 0, k->n, 0) ;
+ if (r < 0) return 0 ;
+ else if (!r) break ;
+ k->n -= r ;
+ }
+ return 1 ;
+}
+
+static int fakeflush (iobufferk_ref k)
+{
+ k->n = 0 ;
+ return 1 ;
+}
+
+static int iobufferk_flush_3 (iobufferk_ref k)
+{
+ while (k->n)
+ {
+ register int r = splice(k->p[0], 0, k->fd[1], 0, k->n, SPLICE_F_MORE | (k->nb & 2 ? SPLICE_F_NONBLOCK : 0)) ;
+ if (r < 0)
+ {
+ if (errno == EINVAL) errno = ENOSYS ;
+ return 0 ;
+ }
+ else if (!r) return (errno = EPIPE, 0) ;
+ k->n -= r ;
+ }
+ return 1 ;
+}
+
+iobufferk_io_func_t_ref const iobufferk_flush_f[4] =
+{
+ &iobufferk_flush_0, &fakeflush, &fakeflush, &iobufferk_flush_3
+} ;
+
+#else
+
+#include <errno.h>
+#include <skalibs/iobuffer.h>
+
+iobufferk_io_func_t_ref const iobufferk_flush_f[4] =
+{
+ &iobufferk_nosys, &iobufferk_nosys, &iobufferk_nosys, &iobufferk_nosys
+} ;
+
+#endif
diff --git a/src/libstddjb/iobufferk_init.c b/src/libstddjb/iobufferk_init.c
new file mode 100644
index 0000000..03f7fae
--- /dev/null
+++ b/src/libstddjb/iobufferk_init.c
@@ -0,0 +1,78 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASSPLICE
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/iobuffer.h>
+
+static int iobufferk_init_0 (iobufferk_ref k)
+{
+ register int fd = open_write("/dev/null") ;
+ if (fd < 0) return 0 ;
+ if (coe(fd) < 0)
+ {
+ fd_close(fd) ;
+ return 0 ;
+ }
+ k->p[0] = -1 ;
+ k->p[1] = fd ;
+ return 1 ;
+}
+
+static int iobufferk_nofd (iobufferk_ref k)
+{
+ k->p[0] = k->p[1] = -1 ;
+ return 1 ;
+}
+
+static int iobufferk_init_3 (iobufferk_ref k)
+{
+ return (pipenbcoe(k->p) >= 0) ;
+}
+
+static iobufferk_io_func_t_ref iobufferk_init_f[4] =
+{
+ &iobufferk_init_0, &iobufferk_nofd, &iobufferk_nofd, &iobufferk_init_3
+} ;
+
+int iobufferk_init (iobufferk_ref k, int fdin, int fdout)
+{
+ iobufferk tmp ;
+ struct stat st ;
+ register int r ;
+ if (fstat(fdin, &st) < 0) return 0 ;
+ r = fcntl(fdin, F_GETFL) ;
+ if (r < 0) return 0 ;
+ tmp.type = !S_ISFIFO(st.st_mode) ;
+ tmp.nb = !!(r & O_NONBLOCK) ;
+ if (fstat(fdout, &st) < 0) return 0 ;
+ r = fcntl(fdout, F_GETFL) ;
+ if (r < 0) return 0 ;
+ tmp.type |= (!S_ISFIFO(st.st_mode) << 1) ;
+ tmp.nb |= (r & O_NONBLOCK) ? 2 : 0 ;
+ tmp.fd[0] = fdin ;
+ tmp.fd[1] = fdout ;
+ tmp.n = 0 ;
+ if (!(*iobufferk_init_f[tmp.type])(&tmp)) return 0 ;
+ *k = tmp ;
+ return 1 ;
+}
+
+#else
+
+#include <errno.h>
+#include <skalibs/iobuffer.h>
+
+int iobufferk_init (iobufferk_ref k, int fdin, int fdout)
+{
+ (void)k ;
+ (void)fdin ;
+ (void)fdout ;
+ return (errno = ENOSYS, 0) ;
+}
+
+#endif
diff --git a/src/libstddjb/iobufferk_isworking.c b/src/libstddjb/iobufferk_isworking.c
new file mode 100644
index 0000000..f02b7e0
--- /dev/null
+++ b/src/libstddjb/iobufferk_isworking.c
@@ -0,0 +1,48 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASSPLICE
+
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <skalibs/iobuffer.h>
+
+int iobufferk_isworking (iobufferk_ref k)
+{
+ /* for now splice() with a length of 0 returns 0 no matter what, so this */
+ /* test is useless. splice() should test the underlying filesystems even */
+ /* if the length is 0. */
+
+# if 0
+
+ register int e = errno ;
+ if (splice(k->fd[0], 0, k->p[1], 0, 0, 0) < 0) goto no ;
+ if (splice(k->p[0], 0, k->fd[1], 0, 0, 0) < 0) goto no ;
+ errno = e ;
+ return 1 ;
+ no:
+ errno = e ;
+ return 0 ;
+
+# else
+
+ (void)k ;
+ return 1 ;
+
+# endif
+}
+
+#else
+
+#include <skalibs/iobuffer.h>
+
+int iobufferk_isworking (iobufferk_ref k)
+{
+ (void)k ;
+ return 0 ;
+}
+
+#endif
+
diff --git a/src/libstddjb/iobufferk_nosys.c b/src/libstddjb/iobufferk_nosys.c
new file mode 100644
index 0000000..46f8be4
--- /dev/null
+++ b/src/libstddjb/iobufferk_nosys.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/iobuffer.h>
+
+int iobufferk_nosys (iobufferk_ref k)
+{
+ (void)k ;
+ return (errno = ENOSYS, -1) ;
+}
diff --git a/src/libstddjb/iobufferu_fill.c b/src/libstddjb/iobufferu_fill.c
new file mode 100644
index 0000000..7ebb67c
--- /dev/null
+++ b/src/libstddjb/iobufferu_fill.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/iobuffer.h>
+
+int iobufferu_fill (iobufferu_ref b)
+{
+ register int r = buffer_fill(&b->b[0]) ;
+ b->b[1].c.n = b->b[0].c.n ;
+ return r ;
+}
diff --git a/src/libstddjb/iobufferu_finish.c b/src/libstddjb/iobufferu_finish.c
new file mode 100644
index 0000000..eb3749e
--- /dev/null
+++ b/src/libstddjb/iobufferu_finish.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/alloc.h>
+#include <skalibs/iobuffer.h>
+
+void iobufferu_finish (iobufferu_ref b)
+{
+ alloc_free(b->buf) ;
+}
diff --git a/src/libstddjb/iobufferu_flush.c b/src/libstddjb/iobufferu_flush.c
new file mode 100644
index 0000000..734fab1
--- /dev/null
+++ b/src/libstddjb/iobufferu_flush.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/iobuffer.h>
+
+int iobufferu_flush (iobufferu_ref b)
+{
+ register int r = buffer_flush(&b->b[1]) ;
+ b->b[0].c.p = b->b[1].c.p ;
+ return r ;
+}
diff --git a/src/libstddjb/iobufferu_init.c b/src/libstddjb/iobufferu_init.c
new file mode 100644
index 0000000..e9ea5c8
--- /dev/null
+++ b/src/libstddjb/iobufferu_init.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/alloc.h>
+#include <skalibs/buffer.h>
+#include <skalibs/iobuffer.h>
+
+int iobufferu_init (iobufferu_ref b, int fdin, int fdout)
+{
+ register char *x = alloc(IOBUFFERU_SIZE) ;
+ if (!x) return 0 ;
+ b->buf = x ;
+ buffer_init(&b->b[0], &buffer_read, fdin, x, IOBUFFERU_SIZE) ;
+ buffer_init(&b->b[1], &buffer_write, fdout, x, IOBUFFERU_SIZE) ;
+ return 1 ;
+}
diff --git a/src/libstddjb/iopause.c b/src/libstddjb/iopause.c
new file mode 100644
index 0000000..38e3b54
--- /dev/null
+++ b/src/libstddjb/iopause.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/iopause.h>
+
+#ifdef SKALIBS_HASPPOLL
+
+iopause_func_t_ref const iopause_ = &iopause_ppoll ;
+
+#else
+
+#include <skalibs/config.h>
+
+#ifdef SKALIBS_FLAG_PREFERSELECT
+
+iopause_func_t_ref const iopause_ = &iopause_select ;
+
+#else
+
+iopause_func_t_ref const iopause_ = &iopause_poll ;
+
+#endif
+
+#endif
diff --git a/src/libstddjb/iopause_poll.c b/src/libstddjb/iopause_poll.c
new file mode 100644
index 0000000..e4e4da1
--- /dev/null
+++ b/src/libstddjb/iopause_poll.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <poll.h>
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+
+int iopause_poll (iopause_fd *x, unsigned int len, tain_t const *deadline, tain_t const *stamp)
+{
+ register int millisecs = 0 ;
+ if (!deadline) millisecs = -1 ;
+ else if (tain_less(stamp, deadline))
+ {
+ tain_t t ;
+ tain_sub(&t, deadline, stamp) ;
+ millisecs = tain_to_millisecs(&t) ;
+ }
+ return poll(x, len, millisecs) ;
+}
diff --git a/src/libstddjb/iopause_ppoll.c b/src/libstddjb/iopause_ppoll.c
new file mode 100644
index 0000000..b181d0a
--- /dev/null
+++ b/src/libstddjb/iopause_ppoll.c
@@ -0,0 +1,44 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASPPOLL
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <time.h>
+#include <poll.h>
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+
+int iopause_ppoll (iopause_fd *x, unsigned int len, tain_t const *deadline, tain_t const *stamp)
+{
+ struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 } ;
+ if (deadline && tain_less(stamp, deadline))
+ {
+ tain_t delta ;
+ tain_sub(&delta, deadline, stamp) ;
+ if (!timespec_from_tain_relative(&ts, &delta))
+ {
+ if (errno != ERANGE) return -1 ;
+ else deadline = 0 ;
+ }
+ }
+ return ppoll(x, len, deadline ? &ts : 0, 0) ;
+}
+
+#else
+
+#include <errno.h>
+#include <skalibs/iopause.h>
+
+int iopause_ppoll (iopause_fd *x, unsigned int len, tain_t const *deadline, tain_t const *stamp)
+{
+ (void)x ;
+ (void)len ;
+ (void)deadline ;
+ (void)stamp ;
+ return (errno = ENOSYS, -1) ;
+}
+
+#endif
diff --git a/src/libstddjb/iopause_select.c b/src/libstddjb/iopause_select.c
new file mode 100644
index 0000000..a9c6529
--- /dev/null
+++ b/src/libstddjb/iopause_select.c
@@ -0,0 +1,63 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <string.h> /* Solaris... */
+#include <errno.h>
+#include <sys/select.h>
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+
+int iopause_select (iopause_fd *x, unsigned int len, tain_t const *deadline, tain_t const *stamp)
+{
+ struct timeval tv = { .tv_sec = 0, .tv_usec = 0 } ;
+ int nfds = 0 ;
+ fd_set rfds, wfds, xfds ;
+ int r ;
+
+ FD_ZERO(&rfds) ;
+ FD_ZERO(&wfds) ;
+ FD_ZERO(&xfds) ;
+ if (deadline && tain_less(stamp, deadline))
+ {
+ tain_t delta ;
+ tain_sub(&delta, deadline, stamp) ;
+ if (!timeval_from_tain_relative(&tv, &delta))
+ {
+ if (errno != ERANGE) return -1 ;
+ else deadline = 0 ;
+ }
+ }
+
+ {
+ register unsigned int i = 0 ;
+ for (; i < len ; i++)
+ {
+ x[i].revents = 0 ;
+ if (x[i].fd >= 0)
+ {
+ if (x[i].fd >= nfds) nfds = x[i].fd + 1 ;
+ if (x[i].events & IOPAUSE_READ) FD_SET(x[i].fd, &rfds) ;
+ if (x[i].events & IOPAUSE_WRITE) FD_SET(x[i].fd, &wfds) ;
+ if (x[i].events & IOPAUSE_EXCEPT) FD_SET(x[i].fd, &xfds) ;
+ }
+ }
+ }
+
+ r = select(nfds, &rfds, &wfds, &xfds, deadline ? &tv : 0) ;
+
+ if (r > 0)
+ {
+ register unsigned int i = 0 ;
+ for (; i < len ; i++) if (x[i].fd >= 0)
+ {
+ if ((x[i].events & IOPAUSE_READ) && FD_ISSET(x[i].fd, &rfds))
+ x[i].revents |= IOPAUSE_READ ;
+ if ((x[i].events & IOPAUSE_WRITE) && FD_ISSET(x[i].fd, &wfds))
+ x[i].revents |= IOPAUSE_WRITE ;
+ if ((x[i].events & IOPAUSE_EXCEPT) && FD_ISSET(x[i].fd, &xfds))
+ x[i].revents |= IOPAUSE_EXCEPT ;
+ }
+ }
+
+ return r ;
+}
diff --git a/src/libstddjb/iopause_stamp.c b/src/libstddjb/iopause_stamp.c
new file mode 100644
index 0000000..d9a7e31
--- /dev/null
+++ b/src/libstddjb/iopause_stamp.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+
+extern int iopause_stamp (iopause_fd *x, unsigned int n, tain_t const *deadline, tain_t *stamp)
+{
+ register int r ;
+ do
+ {
+ r = iopause(x, n, deadline, stamp) ;
+ if (stamp)
+ {
+ int e = errno ;
+ tain_now(stamp) ;
+ errno = e ;
+ }
+ }
+ while ((r < 0) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/iovec_from_siovec.c b/src/libstddjb/iovec_from_siovec.c
new file mode 100644
index 0000000..154cca5
--- /dev/null
+++ b/src/libstddjb/iovec_from_siovec.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <skalibs/siovec.h>
+
+void iovec_from_siovec (struct iovec *iov, siovec_t const *v, unsigned int n)
+{
+ while (n--)
+ {
+ iov[n].iov_base = v[n].s ;
+ iov[n].iov_len = v[n].len ;
+ }
+}
diff --git a/src/libstddjb/ip46_scan.c b/src/libstddjb/ip46_scan.c
new file mode 100644
index 0000000..97ebe4d
--- /dev/null
+++ b/src/libstddjb/ip46_scan.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/ip46.h>
+
+#include <skalibs/fmtscan.h>
+#include <skalibs/ip46.h>
+
+unsigned int ip46full_scan (char const *s, ip46full_t_ref ip)
+{
+ unsigned int len = ip6_scan(s, ip->ip) ;
+ if (len) ip->is6 = 1 ;
+ else
+ {
+ len = ip4_scan(s, ip->ip) ;
+ if (len) ip->is6 = 0 ;
+ }
+ return len ;
+}
diff --git a/src/libstddjb/ip46_scanlist.c b/src/libstddjb/ip46_scanlist.c
new file mode 100644
index 0000000..37f2e18
--- /dev/null
+++ b/src/libstddjb/ip46_scanlist.c
@@ -0,0 +1,28 @@
+/* ISC license. */
+
+#include <skalibs/ip46.h>
+
+#include <skalibs/bytestr.h>
+#include <skalibs/fmtscan.h>
+
+unsigned int ip46full_scanlist (ip46full_t_ref out, unsigned int max, char const *s, unsigned int *num)
+{
+ unsigned int n = 0, w = 0 ;
+ for (; s[w] && (n < max) ; n++)
+ {
+ ip46full_t z ;
+ register unsigned int i = ip6_scan(s + w, z.ip) ;
+ if (i) z.is6 = 1 ;
+ else
+ {
+ i = ip4_scan(s + w, z.ip) ;
+ if (!i) break ;
+ z.is6 = 0 ;
+ }
+ out[n] = z ;
+ w += i ;
+ while (byte_chr(",; \t\r\n", 6, s[w]) < 6) w++ ;
+ }
+ *num = n ;
+ return w ;
+}
diff --git a/src/libstddjb/ip4_fmt.c b/src/libstddjb/ip4_fmt.c
new file mode 100644
index 0000000..4c2f6a3
--- /dev/null
+++ b/src/libstddjb/ip4_fmt.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/fmtscan.h>
+
+unsigned int ip4_fmt (char *s, char const *ip)
+{
+ unsigned int len = 0 ;
+ unsigned int i, j ;
+ for (j = 0 ; j < 4 ; j++)
+ {
+ i = uint32_fmt(s, (uint32)(unsigned char) ip[j]) ;
+ len += i ;
+ if (s) s += i ;
+ if (j == 3) break ;
+ if (s) *s++ = '.' ;
+ ++len ;
+ }
+ return len ;
+}
diff --git a/src/libstddjb/ip4_fmtu32.c b/src/libstddjb/ip4_fmtu32.c
new file mode 100644
index 0000000..d4833e8
--- /dev/null
+++ b/src/libstddjb/ip4_fmtu32.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/fmtscan.h>
+
+unsigned int ip4_fmtu32 (char *s, uint32 ip)
+{
+ char pack[4] ;
+ uint32_pack_big(pack, ip) ;
+ return ip4_fmt(s, pack) ;
+}
diff --git a/src/libstddjb/ip4_scan.c b/src/libstddjb/ip4_scan.c
new file mode 100644
index 0000000..2873cd4
--- /dev/null
+++ b/src/libstddjb/ip4_scan.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+
+unsigned int ip4_scan (char const *s, char *ip)
+{
+ register unsigned int j = 0 ;
+ unsigned int len = 0 ;
+ for (; j < 4 ; j++)
+ {
+ unsigned int u ;
+ register unsigned int i = uint_scan(s, &u) ;
+ if (!i) return 0 ;
+ ip[j] = (char)u ;
+ s += i ;
+ len += i ;
+ if (j == 3) break ;
+ if (*s != '.') return 0 ;
+ ++s ;
+ ++len ;
+ }
+ return len ;
+}
diff --git a/src/libstddjb/ip4_scanlist.c b/src/libstddjb/ip4_scanlist.c
new file mode 100644
index 0000000..f1e3ccc
--- /dev/null
+++ b/src/libstddjb/ip4_scanlist.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/fmtscan.h>
+
+unsigned int ip4_scanlist (char *out, unsigned int max, char const *s, unsigned int *num)
+{
+ unsigned int n = 0, w = 0 ;
+ for (; s[w] && (n < max) ; n++)
+ {
+ register unsigned int i = ip4_scan(s + w, out + (n << 2)) ;
+ if (!i) break ;
+ w += i ;
+ while (byte_chr(",:; \t\r\n", 7, s[w]) < 7) w++ ;
+ }
+ *num = n ;
+ return w ;
+}
diff --git a/src/libstddjb/ip4_scanlist_u32.c b/src/libstddjb/ip4_scanlist_u32.c
new file mode 100644
index 0000000..26a4e38
--- /dev/null
+++ b/src/libstddjb/ip4_scanlist_u32.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/fmtscan.h>
+
+unsigned int ip4_scanlist_u32 (uint32 *out, unsigned int max, char const *s, unsigned int *num)
+{
+ unsigned int n = 0, w = 0 ;
+ for (; s[w] && (n < max) ; n++)
+ {
+ register unsigned int i = ip4_scanu32(s + w, out + n) ;
+ if (!i) break ;
+ w += i ;
+ while (byte_chr(",:; \t\r\n", 7, s[w]) < 7) w++ ;
+ }
+ *num = n ;
+ return w ;
+}
diff --git a/src/libstddjb/ip4_scanu32.c b/src/libstddjb/ip4_scanu32.c
new file mode 100644
index 0000000..a305926
--- /dev/null
+++ b/src/libstddjb/ip4_scanu32.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/fmtscan.h>
+
+unsigned int ip4_scanu32 (char const *s, uint32 *ip)
+{
+ char pack[4] ;
+ register unsigned int r = ip4_scan(s, pack) ;
+ if (r) uint32_unpack_big(pack, ip) ;
+ return r ;
+}
diff --git a/src/libstddjb/ip6_fmt.c b/src/libstddjb/ip6_fmt.c
new file mode 100644
index 0000000..afd8a21
--- /dev/null
+++ b/src/libstddjb/ip6_fmt.c
@@ -0,0 +1,79 @@
+/* ISC license. */
+
+#include <skalibs/diuint.h>
+#include <skalibs/fmtscan.h>
+
+#define px(c) ((j || (c)) ? (*s++ = fmtscan_asc(c), 1) : 0)
+
+static inline unsigned int xfmt16 (char *s, char const *key)
+{
+ register unsigned int j = 0 ;
+ j += px((unsigned char)key[0] >> 4) ;
+ j += px((unsigned char)key[0] & 15) ;
+ j += px((unsigned char)key[1] >> 4) ;
+ j += px((unsigned char)key[1] & 15) ;
+ return j ? j : (*s = '0', 1) ;
+}
+
+static inline unsigned int find_colcol (char const *key, unsigned int *pos)
+{
+ diuint z[4] = { DIUINT_ZERO, DIUINT_ZERO, DIUINT_ZERO, DIUINT_ZERO } ;
+ unsigned int j = 0 ;
+ unsigned int max = 0 ;
+ register int iszero = 0 ;
+ register unsigned int i = 0 ;
+ for ( ; i < 8 ; i++)
+ {
+ if (key[i<<1] || key[(i<<1)+1])
+ {
+ if (iszero)
+ {
+ iszero = 0 ;
+ z[j].right = i - z[j].left ;
+ if (z[j].right > max) max = z[j].right ;
+ j++ ;
+ }
+ }
+ else
+ {
+ if (!iszero)
+ {
+ iszero = 1 ;
+ z[j].left = i ;
+ }
+ }
+ }
+ if (iszero)
+ {
+ z[j].right = 8 - z[j].left ;
+ if (z[j].right > max) max = z[j].right ;
+ j++ ;
+ }
+
+ if (max >= 2)
+ for (i = 0 ; i < j ; i++) if (z[i].right == max) return (*pos = z[i].left, max) ;
+ return 0 ;
+}
+
+unsigned int ip6_fmt (char *s, char const *ip6)
+{
+ unsigned int w = 0 ;
+ register unsigned int i = 0 ;
+ unsigned int pos = 8 ;
+ unsigned int len = find_colcol(ip6, &pos) ;
+ for (; i < 8 ; i++)
+ {
+ if (i == pos)
+ {
+ if (!i) s[w++] = ':' ;
+ s[w++] = ':' ;
+ i += len-1 ;
+ }
+ else
+ {
+ w += xfmt16(s + w, ip6 + (i<<1)) ;
+ if (i < 7) s[w++] = ':' ;
+ }
+ }
+ return w ;
+}
diff --git a/src/libstddjb/ip6_scan.c b/src/libstddjb/ip6_scan.c
new file mode 100644
index 0000000..cb2dc49
--- /dev/null
+++ b/src/libstddjb/ip6_scan.c
@@ -0,0 +1,35 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/fmtscan.h>
+
+unsigned int ip6_scan (char const *s, char *ip6)
+{
+ static const unsigned char class[256] = "2222222222222222222222222222222222222222222222220000000000122222200000022222222222222222222222222000000222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222" ;
+ static const unsigned char table[5][3] = { "\024#\005", "\024\"\005", "\024\005\006", "\005\002\005", "\024\t\016" } ;
+ uint16 tmp[8] = { 0, 0, 0, 0, 0, 0, 0, 0 } ;
+ unsigned int pos = 8, j = 0, state = 0, i = 0 ;
+
+ while (state < 5)
+ {
+ register unsigned char c = table[state][class[(unsigned char)s[i]] - '0'] ;
+ state = c & 7 ;
+ if (c & 0x20) { if (pos < 8) state = 5 ; else pos = j ; }
+ if (c & 0x10)
+ {
+ if (tmp[j] & 0xf000) state = 5 ;
+ else tmp[j] = (tmp[j] << 4) + fmtscan_num(s[i], 16) ;
+ }
+ if (c & 0x08) if ((++j > 7) && (state < 5)) state = 5 ;
+ i++ ;
+ }
+
+ if (((pos < 8) && (j > 6)) || ((pos == 8) && (j < 8))) state = 5 ;
+ if (state == 5) return (errno = EINVAL, 0) ;
+ for (state = j ; state > pos ; state--) tmp[state - j + 7] = tmp[state - 1] ;
+ for (; state < pos + 8 - j ; state++) tmp[state] = 0 ;
+
+ for (j = 0 ; j < 8 ; j++) uint16_pack_big(ip6 + (j<<1), tmp[j]) ;
+ return i - 1 ;
+}
diff --git a/src/libstddjb/ip6_scanlist.c b/src/libstddjb/ip6_scanlist.c
new file mode 100644
index 0000000..8d751a6
--- /dev/null
+++ b/src/libstddjb/ip6_scanlist.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/fmtscan.h>
+
+unsigned int ip6_scanlist (char *out, unsigned int max, char const *s, unsigned int *num)
+{
+ unsigned int n = 0, w = 0 ;
+ for (; s[w] && (n < max) ; n++)
+ {
+ char ip[16] ;
+ register unsigned int i = ip6_scan(s + w, ip) ;
+ if (!i) break ;
+ byte_copy(out + (n << 4), 16, ip) ;
+ w += i ;
+ while (byte_chr(",; \t\r\n", 6, s[w]) < 6) w++ ;
+ }
+ *num = n ;
+ return w ;
+}
diff --git a/src/libstddjb/ipc_accept.c b/src/libstddjb/ipc_accept.c
new file mode 100644
index 0000000..dc3eae7
--- /dev/null
+++ b/src/libstddjb/ipc_accept.c
@@ -0,0 +1,48 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/webipc.h>
+
+int ipc_accept_internal (int s, char *p, unsigned int l, int *trunc, unsigned int options)
+{
+ struct sockaddr_un sa ;
+ socklen_t dummy = sizeof sa ;
+ register int fd ;
+ byte_zero((char*)&sa, (unsigned int)dummy) ;
+ do
+#ifdef SKALIBS_HASACCEPT4
+ fd = accept4(s, (struct sockaddr *)&sa, &dummy, ((options & DJBUNIX_FLAG_NB) ? SOCK_NONBLOCK : 0) | ((options & DJBUNIX_FLAG_COE) ? SOCK_CLOEXEC : 0)) ;
+#else
+ fd = accept(s, (struct sockaddr *)&sa, &dummy) ;
+#endif
+ while ((fd == -1) && (errno == EINTR)) ;
+ if (fd == -1) return -1 ;
+#ifndef SKALIBS_HASACCEPT4
+ if ((((options & DJBUNIX_FLAG_NB) ? ndelay_on(fd) : ndelay_off(fd)) < 0)
+ || (((options & DJBUNIX_FLAG_COE) ? coe(fd) : uncoe(fd)) < 0))
+ {
+ register int e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ return -1 ;
+ }
+#endif
+
+ if (p)
+ {
+ dummy = byte_chr(sa.sun_path, dummy, 0) ;
+ *trunc = 1 ;
+ if (!l) return fd ;
+ if (l < (dummy + 1)) dummy = l - 1 ;
+ else *trunc = 0 ;
+ byte_copy(p, dummy, sa.sun_path) ;
+ p[dummy] = 0 ;
+ }
+ return fd ;
+}
diff --git a/src/libstddjb/ipc_bind.c b/src/libstddjb/ipc_bind.c
new file mode 100644
index 0000000..2bb8678
--- /dev/null
+++ b/src/libstddjb/ipc_bind.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/error.h>
+#include <skalibs/webipc.h>
+
+int ipc_bind (int s, char const *p)
+{
+ struct sockaddr_un sa ;
+ register unsigned int l = str_len(p) ;
+ if (l > IPCPATH_MAX) return (errno = EPROTO, -1) ;
+ byte_zero((char *)&sa, sizeof sa) ;
+ sa.sun_family = AF_UNIX ;
+ byte_copy(sa.sun_path, l+1, p) ;
+ return bind(s, (struct sockaddr *)&sa, sizeof sa) ;
+}
diff --git a/src/libstddjb/ipc_bind_reuse.c b/src/libstddjb/ipc_bind_reuse.c
new file mode 100644
index 0000000..31db745
--- /dev/null
+++ b/src/libstddjb/ipc_bind_reuse.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <skalibs/webipc.h>
+
+int ipc_bind_reuse (int s, char const *p)
+{
+ unsigned int opt = 1 ;
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt) ;
+ unlink(p) ;
+ return ipc_bind(s, p) ;
+}
diff --git a/src/libstddjb/ipc_connect.c b/src/libstddjb/ipc_connect.c
new file mode 100644
index 0000000..6c5eac2
--- /dev/null
+++ b/src/libstddjb/ipc_connect.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/error.h>
+#include <skalibs/webipc.h>
+
+int ipc_connect (int s, char const *p)
+{
+ struct sockaddr_un sa ;
+ unsigned int l = str_len(p) ;
+ if (l > IPCPATH_MAX) return (errno = EPROTO, 0) ;
+ byte_zero((char *) &sa, sizeof sa) ;
+ sa.sun_family = AF_UNIX ;
+ byte_copy(sa.sun_path, l+1, p) ;
+ if (connect(s, (struct sockaddr *)&sa, sizeof sa) == -1)
+ {
+ if (errno == EINTR) errno = EINPROGRESS ;
+ return 0 ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/ipc_connected.c b/src/libstddjb/ipc_connected.c
new file mode 100644
index 0000000..4965c9f
--- /dev/null
+++ b/src/libstddjb/ipc_connected.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/webipc.h>
+
+int ipc_connected (int s)
+{
+ struct sockaddr_un sa ;
+ socklen_t dummy = sizeof sa ;
+ if (getpeername(s, (struct sockaddr *)&sa, &dummy) == -1)
+ {
+ char ch ;
+ fd_read(s, &ch, 1) ; /* sets errno */
+ return 0 ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/ipc_dgram.c b/src/libstddjb/ipc_dgram.c
new file mode 100644
index 0000000..ac61ee7
--- /dev/null
+++ b/src/libstddjb/ipc_dgram.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/webipc.h>
+
+int ipc_datagram_internal (unsigned int flags)
+{
+ return socket_internal(AF_UNIX, SOCK_DGRAM, 0, flags) ;
+}
diff --git a/src/libstddjb/ipc_eid.c b/src/libstddjb/ipc_eid.c
new file mode 100644
index 0000000..81f608a
--- /dev/null
+++ b/src/libstddjb/ipc_eid.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <skalibs/getpeereid.h>
+#include <skalibs/webipc.h>
+
+int ipc_eid (int s, unsigned int *u, unsigned int *g)
+{
+ uid_t dummyu ;
+ gid_t dummyg ;
+ if (getpeereid(s, &dummyu, &dummyg) < 0) return -1 ;
+ *u = (unsigned int)dummyu ;
+ *g = (unsigned int)dummyg ;
+ return 0 ;
+}
diff --git a/src/libstddjb/ipc_listen.c b/src/libstddjb/ipc_listen.c
new file mode 100644
index 0000000..a96be58
--- /dev/null
+++ b/src/libstddjb/ipc_listen.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <skalibs/webipc.h>
+
+int ipc_listen (int s, int backlog)
+{
+ return listen(s, backlog) ;
+}
diff --git a/src/libstddjb/ipc_local.c b/src/libstddjb/ipc_local.c
new file mode 100644
index 0000000..57ffb37
--- /dev/null
+++ b/src/libstddjb/ipc_local.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/webipc.h>
+
+int ipc_local (int s, char *p, unsigned int l, int *trunc)
+{
+ struct sockaddr_un sa ;
+ socklen_t dummy = sizeof sa ;
+ byte_zero((char *)&sa, sizeof sa) ;
+ if (getsockname(s, (struct sockaddr *)&sa, &dummy) == -1) return -1 ;
+ dummy = byte_chr(sa.sun_path, dummy, 0) ;
+ *trunc = 1 ;
+ if (!l) return 0 ;
+ if (l < (dummy + 1)) dummy = l - 1 ;
+ else *trunc = 0 ;
+ byte_copy(p, dummy, sa.sun_path) ;
+ p[dummy] = 0 ;
+ return 0 ;
+}
diff --git a/src/libstddjb/ipc_pair.c b/src/libstddjb/ipc_pair.c
new file mode 100644
index 0000000..6038d17
--- /dev/null
+++ b/src/libstddjb/ipc_pair.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/webipc.h>
+
+int ipc_pair_internal (int *sv, unsigned int flags)
+{
+ return socketpair_internal(AF_UNIX, SOCK_STREAM, 0, flags, sv) ;
+}
diff --git a/src/libstddjb/ipc_recv.c b/src/libstddjb/ipc_recv.c
new file mode 100644
index 0000000..80806e7
--- /dev/null
+++ b/src/libstddjb/ipc_recv.c
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/error.h>
+#include <skalibs/webipc.h>
+
+int ipc_recv (int fd, char *s, unsigned int len, char *path)
+{
+ struct sockaddr_un sa ;
+ socklen_t total = sizeof sa ;
+ char tmp[len] ;
+ register int r ;
+ do r = recvfrom(fd, tmp, len, 0, (struct sockaddr *)&sa, &total) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ if (r < 0) return r ;
+ if (sa.sun_family != AF_UNIX) return (errno = EPROTO, -1) ;
+ if (path)
+ {
+ if (total == sizeof(sa_family_t)) path[0] = 0 ;
+ else
+ {
+ unsigned int l = str_len(sa.sun_path) ;
+ if (l > IPCPATH_MAX) return (errno = EPROTO, -1) ;
+ byte_copy(path, l+1, sa.sun_path) ;
+ }
+ }
+ byte_copy(s, r, tmp) ;
+ return r ;
+}
diff --git a/src/libstddjb/ipc_send.c b/src/libstddjb/ipc_send.c
new file mode 100644
index 0000000..0e71d98
--- /dev/null
+++ b/src/libstddjb/ipc_send.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/error.h>
+#include <skalibs/webipc.h>
+
+int ipc_send (int fd, char const *s, unsigned int len, char const *path)
+{
+ struct sockaddr_un sa ;
+ register unsigned int l = str_len(path) ;
+ if (l > IPCPATH_MAX) return (errno = EPROTO, -1) ;
+ byte_zero(&sa, sizeof sa) ;
+ sa.sun_family = AF_UNIX ;
+ byte_copy(sa.sun_path, l+1, path) ;
+ return sendto(fd, s, len, 0, (struct sockaddr *)&sa, sizeof sa) ;
+}
diff --git a/src/libstddjb/ipc_stream.c b/src/libstddjb/ipc_stream.c
new file mode 100644
index 0000000..c2c6c1b
--- /dev/null
+++ b/src/libstddjb/ipc_stream.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/webipc.h>
+
+int ipc_stream_internal (unsigned int flags)
+{
+ return socket_internal(AF_UNIX, SOCK_STREAM, 0, flags) ;
+}
diff --git a/src/libstddjb/ipc_timed_connect.c b/src/libstddjb/ipc_timed_connect.c
new file mode 100644
index 0000000..4f8e73d
--- /dev/null
+++ b/src/libstddjb/ipc_timed_connect.c
@@ -0,0 +1,26 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/error.h>
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+#include <skalibs/webipc.h>
+
+int ipc_timed_connect (int s, char const *path, tain_t const *deadline, tain_t *stamp)
+{
+ if (!ipc_connect(s, path))
+ {
+ iopause_fd x = { s, IOPAUSE_WRITE, 0 } ;
+ if (!error_isagain(errno) && !error_isalready(errno)) return 0 ;
+ for (;;)
+ {
+ register int r = iopause_stamp(&x, 1, deadline, stamp) ;
+ if (r < 0) return 0 ;
+ else if (!r) return (errno = ETIMEDOUT, 0) ;
+ else if (x.revents & IOPAUSE_EXCEPT) return 0 ;
+ else if (x.revents & IOPAUSE_WRITE) break ;
+ }
+ if (!ipc_connected(s)) return 0 ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/leapsecs_add.c b/src/libstddjb/leapsecs_add.c
new file mode 100644
index 0000000..c24486b
--- /dev/null
+++ b/src/libstddjb/leapsecs_add.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include "djbtime-internal.h"
+
+int leapsecs_add_r (uint64 *t, char const *file, uint64 *leapsecs, int hit)
+{
+ uint64 u = *t ;
+ int n = leapsecs_init_r(file, leapsecs) ;
+ register unsigned int i = 0 ;
+ if (n < 0) return -1 ;
+ for (; i < (unsigned int)n ; i++)
+ {
+ if (u < leapsecs[i]) break ;
+ if (!hit || (leapsecs[i] < u)) ++u ;
+ }
+ *t = u ;
+ return n ;
+}
diff --git a/src/libstddjb/leapsecs_here.c b/src/libstddjb/leapsecs_here.c
new file mode 100644
index 0000000..3ecdfd1
--- /dev/null
+++ b/src/libstddjb/leapsecs_here.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/uint64.h>
+#include "djbtime-internal.h"
+
+static uint64 leapsecs_here_tab[LEAPSECS_MAX+1] ;
+uint64 *leapsecs_here = leapsecs_here_tab ;
diff --git a/src/libstddjb/leapsecs_init.c b/src/libstddjb/leapsecs_init.c
new file mode 100644
index 0000000..41f9b89
--- /dev/null
+++ b/src/libstddjb/leapsecs_init.c
@@ -0,0 +1,34 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint64.h>
+#include <skalibs/djbunix.h>
+#include "djbtime-internal.h"
+
+static unsigned int leapsecs_len (uint64 const *data)
+{
+ register unsigned int i = 1 ;
+ while (data[i]) i++ ;
+ return i ;
+}
+
+static int leapsecs_read (char const *file, uint64 *data)
+{
+ char s[LEAPSECS_MAX * sizeof(uint64)] ;
+ register int n = openreadnclose(file, s, LEAPSECS_MAX * sizeof(uint64)) ;
+ if (n < 0) return -1 ;
+ if (n % sizeof(uint64)) return (errno = EINVAL, -1) ;
+ n /= sizeof(uint64) ;
+ {
+ register unsigned int i = 0 ;
+ for (; i < (unsigned int)n ; i++)
+ uint64_unpack_big(s + i * sizeof(uint64), data + i) ;
+ }
+ data[n] = 0 ;
+ return n ;
+}
+
+int leapsecs_init_r (char const *file, uint64 *data)
+{
+ return data[0] ? (int)leapsecs_len(data) : leapsecs_read(file, data) ;
+}
diff --git a/src/libstddjb/leapsecs_sub.c b/src/libstddjb/leapsecs_sub.c
new file mode 100644
index 0000000..271f592
--- /dev/null
+++ b/src/libstddjb/leapsecs_sub.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include "djbtime-internal.h"
+
+int leapsecs_sub_r (uint64 *t, char const *file, uint64 *leapsecs)
+{
+ uint64 u = *t ;
+ uint64 d = 0 ;
+ int n = leapsecs_init_r(file, leapsecs) ;
+ register unsigned int i = 0 ;
+ register int hit = 0 ;
+ if (n < 0) return -1 ;
+ for (; i < (unsigned int)n ; i++)
+ {
+ if (u < leapsecs[i]) break ;
+ ++d ;
+ if (u == leapsecs[i]) hit = 1 ;
+ }
+ *t = u - d ;
+ return hit ;
+}
diff --git a/src/libstddjb/localtm_fmt.c b/src/libstddjb/localtm_fmt.c
new file mode 100644
index 0000000..ee083ef
--- /dev/null
+++ b/src/libstddjb/localtm_fmt.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <time.h>
+#include <skalibs/uint.h>
+#include <skalibs/djbtime.h>
+
+unsigned int localtm_fmt (char *s, struct tm const *l)
+{
+ char *p = s ;
+ p += uint_fmt(p, 1900 + l->tm_year) ; *p++ = '-' ;
+ uint0_fmt(p, 1 + l->tm_mon, 2) ; p += 2 ; *p++ = '-' ;
+ uint0_fmt(p, l->tm_mday, 2) ; p += 2 ; *p++ = ' ' ;
+ uint0_fmt(p, l->tm_hour, 2) ; p += 2 ; *p++ = ':' ;
+ uint0_fmt(p, l->tm_min, 2) ; p += 2 ; *p++ = ':' ;
+ uint0_fmt(p, l->tm_sec, 2) ; p += 2 ;
+ return p - s ;
+}
diff --git a/src/libstddjb/localtm_from_ltm64.c b/src/libstddjb/localtm_from_ltm64.c
new file mode 100644
index 0000000..63c5aac
--- /dev/null
+++ b/src/libstddjb/localtm_from_ltm64.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+/* OpenBSD needs that for EOVERFLOW. wtfbsdseriously */
+#define _BSD_SOURCE
+
+#include <sys/types.h>
+#include <errno.h>
+#include <time.h>
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbtime.h>
+
+int localtm_from_ltm64 (struct tm *l, uint64 uu, int tz)
+{
+ if (uu < TAI_MAGIC) return (errno = EINVAL, 0) ;
+ uu -= TAI_MAGIC ;
+ if (uu > 0xFFFFFFFFUL) return (errno = EOVERFLOW, 0) ;
+ {
+ time_t u = (time_t)uu ;
+ if (tz ? !localtime_r(&u, l) : !gmtime_r(&u, l)) return 0 ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/localtm_from_sysclock.c b/src/libstddjb/localtm_from_sysclock.c
new file mode 100644
index 0000000..939bb21
--- /dev/null
+++ b/src/libstddjb/localtm_from_sysclock.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <time.h>
+#include <skalibs/uint64.h>
+#include <skalibs/djbtime.h>
+
+int localtm_from_sysclock (struct tm *l, uint64 u, int tz)
+{
+ if (!ltm64_from_sysclock(&u)) return 0 ;
+ return localtm_from_ltm64(l, u, tz) ;
+}
diff --git a/src/libstddjb/localtm_from_tai.c b/src/libstddjb/localtm_from_tai.c
new file mode 100644
index 0000000..ad12cf2
--- /dev/null
+++ b/src/libstddjb/localtm_from_tai.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <time.h>
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbtime.h>
+
+int localtm_from_tai (struct tm *l, tai_t const *t, int tz)
+{
+ uint64 u ;
+ if (!ltm64_from_tai(&u, t)) return 0 ;
+ return localtm_from_ltm64(l, u, tz) ;
+}
diff --git a/src/libstddjb/localtm_from_utc.c b/src/libstddjb/localtm_from_utc.c
new file mode 100644
index 0000000..697621c
--- /dev/null
+++ b/src/libstddjb/localtm_from_utc.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <time.h>
+#include <skalibs/uint64.h>
+#include <skalibs/djbtime.h>
+
+int localtm_from_utc (struct tm *l, uint64 u, int tz)
+{
+ if (!ltm64_from_utc(&u)) return 0 ;
+ return localtm_from_ltm64(l, u, tz) ;
+}
diff --git a/src/libstddjb/localtm_scan.c b/src/libstddjb/localtm_scan.c
new file mode 100644
index 0000000..b028883
--- /dev/null
+++ b/src/libstddjb/localtm_scan.c
@@ -0,0 +1,40 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <time.h>
+#include <skalibs/djbtime.h>
+#include <skalibs/uint.h>
+
+unsigned int localtm_scan (char const *s, struct tm *l)
+{
+ struct tm ll = { .tm_isdst = -1 } ;
+ unsigned int n = 0 ; unsigned int u ;
+ register unsigned int i = uint_scan(s+n, &u) ;
+ if (!i) goto fail ; n += i ;
+ if (u < 1900) goto fail ; u -= 1900 ; ll.tm_year = u ;
+ if (s[n++] != '-') goto fail ;
+ i = uint_scan(s+n, &u) ;
+ if (!i) goto fail ; n += i ;
+ if (!u || (u > 12)) goto fail ; u-- ; ll.tm_mon = u ;
+ if (s[n++] != '-') goto fail ;
+ i = uint_scan(s+n, &u) ;
+ if (!i) goto fail ; n += i ;
+ if (!u || (u > 31)) goto fail ; ll.tm_mday = u ;
+ if ((s[n] != ' ') && (s[n] != 'T')) goto fail ; n++ ;
+ i = uint_scan(s+n, &u) ;
+ if (!i) goto fail ; n += i ;
+ if (u > 23) goto fail ; ll.tm_hour = u ;
+ if (s[n++] != ':') goto fail ;
+ i = uint_scan(s+n, &u) ;
+ if (!i) goto fail ; n += i ;
+ if (u > 59) goto fail ; ll.tm_min = u ;
+ if (s[n++] != ':') goto fail ;
+ i = uint_scan(s+n, &u) ;
+ if (!i) goto fail ; n += i ;
+ if (u > 60) goto fail ; ll.tm_sec = u ;
+ if (mktime(&ll) == (time_t)-1) goto fail ;
+ *l = ll ;
+ return n ;
+ fail:
+ return (errno = EINVAL, 0) ;
+}
diff --git a/src/libstddjb/localtmn_fmt.c b/src/libstddjb/localtmn_fmt.c
new file mode 100644
index 0000000..79a869d
--- /dev/null
+++ b/src/libstddjb/localtmn_fmt.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/djbtime.h>
+
+unsigned int localtmn_fmt (char *s, localtmn_t const *l)
+{
+ char *p = s ;
+ p += localtm_fmt(p, &l->tm) ; *p++ = '.' ;
+ uint320_fmt(p, l->nano, 9) ; p += 9 ;
+ return p - s ;
+}
diff --git a/src/libstddjb/localtmn_from_sysclock.c b/src/libstddjb/localtmn_from_sysclock.c
new file mode 100644
index 0000000..2d4e4fd
--- /dev/null
+++ b/src/libstddjb/localtmn_from_sysclock.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+#include <skalibs/djbtime.h>
+
+int localtmn_from_sysclock (localtmn_t_ref l, tain_t const *a, int tz)
+{
+ struct tm t ;
+ if (!localtm_from_sysclock(&t, a->sec.x, tz)) return 0 ;
+ l->tm = t ;
+ l->nano = a->nano ;
+ return 1 ;
+}
diff --git a/src/libstddjb/localtmn_from_tain.c b/src/libstddjb/localtmn_from_tain.c
new file mode 100644
index 0000000..a3d3f6e
--- /dev/null
+++ b/src/libstddjb/localtmn_from_tain.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+#include <skalibs/djbtime.h>
+
+int localtmn_from_tain (localtmn_t_ref l, tain_t const *a, int tz)
+{
+ struct tm t ;
+ if (!localtm_from_tai(&t, tain_secp(a), tz)) return 0 ;
+ l->tm = t ;
+ l->nano = a->nano ;
+ return 1 ;
+}
diff --git a/src/libstddjb/localtmn_scan.c b/src/libstddjb/localtmn_scan.c
new file mode 100644
index 0000000..f33ab51
--- /dev/null
+++ b/src/libstddjb/localtmn_scan.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/djbtime.h>
+
+unsigned int localtmn_scan (char const *s, localtmn_t_ref l)
+{
+ localtmn_t m ;
+ unsigned int n = localtm_scan(s, &m.tm) ;
+ if (!n) return 0 ;
+ s += n ;
+ if (*s++ != '.') m.nano = 0 ;
+ else
+ {
+ register unsigned int b = uint32_scan(s, &m.nano) ;
+ if (!b) return 0 ;
+ s += b ; n += b ;
+ }
+ *l = m ;
+ return n ;
+}
diff --git a/src/libstddjb/lock_ex.c b/src/libstddjb/lock_ex.c
new file mode 100644
index 0000000..fde901b
--- /dev/null
+++ b/src/libstddjb/lock_ex.c
@@ -0,0 +1,37 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASFLOCK
+
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/file.h>
+#include <skalibs/djbunix.h>
+
+int lock_ex (int fd)
+{
+ register int r ;
+ do
+ r = flock(fd, LOCK_EX) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
+
+#else
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+int lock_ex (int fd)
+{
+ register int r ;
+ do
+ r = lockf(fd, F_LOCK, 0) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
+
+#endif
diff --git a/src/libstddjb/lock_exnb.c b/src/libstddjb/lock_exnb.c
new file mode 100644
index 0000000..7fed9f0
--- /dev/null
+++ b/src/libstddjb/lock_exnb.c
@@ -0,0 +1,38 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASFLOCK
+
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/file.h>
+#include <skalibs/djbunix.h>
+
+int lock_exnb (int fd)
+{
+ register int r ;
+ do
+ r = flock(fd, LOCK_EX | LOCK_NB) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
+
+#else
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+int lock_exnb (int fd)
+{
+ register int r ;
+ do
+ r = lockf(fd, F_TLOCK, 0) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ if ((r == -1) && (errno == EACCES)) errno = EAGAIN ;
+ return r ;
+}
+
+#endif
diff --git a/src/libstddjb/lock_sh.c b/src/libstddjb/lock_sh.c
new file mode 100644
index 0000000..4a42dc1
--- /dev/null
+++ b/src/libstddjb/lock_sh.c
@@ -0,0 +1,37 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASFLOCK
+
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/file.h>
+#include <skalibs/djbunix.h>
+
+int lock_sh (int fd)
+{
+ register int r ;
+ do
+ r = flock(fd, LOCK_SH) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
+
+#else
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+int lock_sh (int fd)
+{
+ register int r ;
+ do
+ r = lockf(fd, F_LOCK, 0) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
+
+#endif
diff --git a/src/libstddjb/lock_shnb.c b/src/libstddjb/lock_shnb.c
new file mode 100644
index 0000000..6a8fd42
--- /dev/null
+++ b/src/libstddjb/lock_shnb.c
@@ -0,0 +1,38 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASFLOCK
+
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/file.h>
+#include <skalibs/djbunix.h>
+
+int lock_shnb (int fd)
+{
+ register int r ;
+ do
+ r = flock(fd, LOCK_SH | LOCK_NB) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
+
+#else
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+int lock_shnb (int fd)
+{
+ register int r ;
+ do
+ r = lockf(fd, F_TLOCK, 0) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ if ((r == -1) && (errno == EACCES)) errno = EAGAIN ;
+ return r ;
+}
+
+#endif
diff --git a/src/libstddjb/lock_un.c b/src/libstddjb/lock_un.c
new file mode 100644
index 0000000..099716a
--- /dev/null
+++ b/src/libstddjb/lock_un.c
@@ -0,0 +1,37 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASFLOCK
+
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/file.h>
+#include <skalibs/djbunix.h>
+
+int lock_un (int fd)
+{
+ register int r ;
+ do
+ r = flock(fd, LOCK_UN) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
+
+#else
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+int lock_un (int fd)
+{
+ register int r ;
+ do
+ r = lockf(fd, F_ULOCK, 0) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
+
+#endif
diff --git a/src/libstddjb/lolprintf.c b/src/libstddjb/lolprintf.c
new file mode 100644
index 0000000..90cc5fc
--- /dev/null
+++ b/src/libstddjb/lolprintf.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <stdarg.h>
+#include <skalibs/buffer.h>
+#include <skalibs/lolstdio.h>
+
+int lolprintf (char const *format, ...)
+{
+ va_list args ;
+ int r ;
+ va_start(args, format) ;
+ r = vbprintf(buffer_1, format, args) ;
+ va_end(args) ;
+ return r ;
+}
diff --git a/src/libstddjb/long_fmt.c b/src/libstddjb/long_fmt.c
new file mode 100644
index 0000000..552fe47
--- /dev/null
+++ b/src/libstddjb/long_fmt.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/ulong.h>
+
+unsigned int long_fmt (char *fmt, long n)
+{
+ if (n >= 0) return ulong_fmt(fmt, n) ;
+ if (fmt) *fmt++ = '-' ;
+ return 1 + ulong_fmt(fmt, -n) ;
+}
diff --git a/src/libstddjb/long_scan.c b/src/libstddjb/long_scan.c
new file mode 100644
index 0000000..34a5e1a
--- /dev/null
+++ b/src/libstddjb/long_scan.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/ulong.h>
+#include "fmtscan-internal.h"
+
+SCANS(long, LONG)
diff --git a/src/libstddjb/ltm64_from_localtm.c b/src/libstddjb/ltm64_from_localtm.c
new file mode 100644
index 0000000..6169f04
--- /dev/null
+++ b/src/libstddjb/ltm64_from_localtm.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <time.h>
+#include <skalibs/tai.h>
+#include <skalibs/uint64.h>
+#include <skalibs/djbtime.h>
+
+int ltm64_from_localtm (uint64 *uu, struct tm const *l)
+{
+ struct tm ll = *l ;
+ time_t u = mktime(&ll) ;
+ if (u == (time_t)-1) return (errno = EINVAL, 0) ;
+ *uu = TAI_MAGIC + u ;
+ return 1 ;
+}
diff --git a/src/libstddjb/ltm64_from_sysclock.c b/src/libstddjb/ltm64_from_sysclock.c
new file mode 100644
index 0000000..54aca39
--- /dev/null
+++ b/src/libstddjb/ltm64_from_sysclock.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/uint64.h>
+#include <skalibs/djbtime.h>
+
+#ifdef SKALIBS_FLAG_CLOCKISTAI
+
+#include <skalibs/tai.h>
+
+int ltm64_from_sysclock (uint64 *u)
+{
+ tai_t t = { *u + 10U } ;
+ return ltm64_from_tai(u, &t) ;
+}
+
+#else
+
+int ltm64_from_sysclock (uint64 *u)
+{
+ return ltm64_from_utc(u) ;
+}
+
+#endif
diff --git a/src/libstddjb/ltm64_from_tai.c b/src/libstddjb/ltm64_from_tai.c
new file mode 100644
index 0000000..c0650c5
--- /dev/null
+++ b/src/libstddjb/ltm64_from_tai.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbtime.h>
+
+#ifdef SKALIBS_FLAG_TZISRIGHT
+
+int ltm64_from_tai (uint64 *u, tai_t const *t)
+{
+ *u = t->x - 10U ;
+ return 1 ;
+}
+
+#else
+
+int ltm64_from_tai (uint64 *u, tai_t const *t)
+{
+ return utc_from_tai(u, t) ;
+}
+
+#endif
diff --git a/src/libstddjb/ltm64_from_utc.c b/src/libstddjb/ltm64_from_utc.c
new file mode 100644
index 0000000..8d66813
--- /dev/null
+++ b/src/libstddjb/ltm64_from_utc.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/uint64.h>
+#include <skalibs/djbtime.h>
+#include "djbtime-internal.h"
+
+#ifdef SKALIBS_FLAG_TZISRIGHT
+
+int ltm64_from_utc (uint64 *u)
+{
+ return (leapsecs_add(u, 0) >= 0) ;
+}
+
+#else
+
+int ltm64_from_utc (uint64 *u)
+{
+ (void)u ;
+ return 1 ;
+}
+
+#endif
diff --git a/src/libstddjb/mininetstring_read.c b/src/libstddjb/mininetstring_read.c
new file mode 100644
index 0000000..6a38523
--- /dev/null
+++ b/src/libstddjb/mininetstring_read.c
@@ -0,0 +1,44 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/uint32.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/mininetstring.h>
+
+int mininetstring_read (int fd, stralloc *sa, uint32 *w)
+{
+ if (!*w)
+ {
+ char pack[2] ;
+ switch (fd_read(fd, pack, 2))
+ {
+ case -1 : return -1 ;
+ case 0 : return 0 ;
+ case 1 : *w = ((uint32)pack[0] << 8) | (1U << 31) ; break ;
+ case 2 : *w = ((uint32)pack[0] << 8) | (uint32)pack[1] | (1U << 30) ; break ;
+ default : return (errno = EDOM, -1) ;
+ }
+ }
+ if (*w & (1U << 31))
+ {
+ char c ;
+ switch (fd_read(fd, &c, 1))
+ {
+ case -1 : return -1 ;
+ case 0 : return (errno = EPIPE, -1) ;
+ case 1 : *w |= (uint32)c | (1U << 30) ; *w &= ~(1U << 31) ; break ;
+ default : return (errno = EDOM, -1) ;
+ }
+ }
+ if (*w & (1U << 30))
+ {
+ if (!stralloc_readyplus(sa, *w & ~(1U << 30))) return -1 ;
+ *w &= ~(1U << 30) ;
+ }
+ {
+ register unsigned int r = allread(fd, sa->s + sa->len, *w) ;
+ sa->len += r ; *w -= r ;
+ }
+ return *w ? -1 : 1 ;
+}
diff --git a/src/libstddjb/mininetstring_write.c b/src/libstddjb/mininetstring_write.c
new file mode 100644
index 0000000..6b31f17
--- /dev/null
+++ b/src/libstddjb/mininetstring_write.c
@@ -0,0 +1,37 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/mininetstring.h>
+
+int mininetstring_write (int fd, char const *s, uint16 len, uint32 *w)
+{
+ if (!w)
+ {
+ char pack[2] ;
+ uint16_pack_big(pack, len) ;
+ switch (fd_write(fd, pack, 2))
+ {
+ case -1 : return -1 ;
+ case 0 : return (errno = EAGAIN, -1) ;
+ case 1 : *w = (1U << 31) ; break ;
+ case 2 : *w = len ; break ;
+ default : return (errno = EDOM, -1) ;
+ }
+ }
+ if (*w & (1U << 31))
+ {
+ char c = len & 0xFFU ;
+ switch (fd_write(fd, &c, 1))
+ {
+ case -1 : return -1 ;
+ case 0 : return (errno = EAGAIN, -1) ;
+ case 1 : *w = len ; break ;
+ default : return (errno = EDOM, -1) ;
+ }
+ }
+ *w -= allwrite(fd, s + len - *w, *w) ;
+ return *w ? -1 : 1 ;
+}
diff --git a/src/libstddjb/ndelay_off.c b/src/libstddjb/ndelay_off.c
new file mode 100644
index 0000000..828acfa
--- /dev/null
+++ b/src/libstddjb/ndelay_off.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <skalibs/djbunix.h>
+
+int ndelay_off (int fd)
+{
+ register int got = fcntl(fd, F_GETFL) ;
+ return (got == -1) ? -1 : fcntl(fd, F_SETFL, got & ~O_NONBLOCK) ;
+}
diff --git a/src/libstddjb/ndelay_on.c b/src/libstddjb/ndelay_on.c
new file mode 100644
index 0000000..186590b
--- /dev/null
+++ b/src/libstddjb/ndelay_on.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <skalibs/djbunix.h>
+
+int ndelay_on (int fd)
+{
+ register int got = fcntl(fd, F_GETFL) ;
+ return (got == -1) ? -1 : fcntl(fd, F_SETFL, got | O_NONBLOCK) ;
+}
diff --git a/src/libstddjb/netstring_append.c b/src/libstddjb/netstring_append.c
new file mode 100644
index 0000000..9c14f49
--- /dev/null
+++ b/src/libstddjb/netstring_append.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/netstring.h>
+
+int netstring_appendb (stralloc *sa, char const *s, unsigned int len)
+{
+ char fmt[UINT_FMT] ;
+ unsigned int n = uint_fmt(fmt, len) ;
+ if (!stralloc_readyplus(sa, len + n + 2)) return 0 ;
+ fmt[n] = ':' ;
+ byte_copy(sa->s + sa->len, n+1, fmt) ;
+ byte_copy(sa->s + sa->len + n+1, len, s) ;
+ sa->s[sa->len + n+1 + len] = ',' ;
+ sa->len += n + 2 + len ;
+ return 1 ;
+}
diff --git a/src/libstddjb/netstring_appendv.c b/src/libstddjb/netstring_appendv.c
new file mode 100644
index 0000000..1fc1406
--- /dev/null
+++ b/src/libstddjb/netstring_appendv.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <skalibs/uint.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/siovec.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/netstring.h>
+
+int netstring_appendv (stralloc *sa, siovec_t const *v, unsigned int n)
+{
+ char fmt[UINT_FMT] ;
+ unsigned int len = 0, pos ;
+ register unsigned int i = 0 ;
+ for (; i < n ; i++) len += v[i].len ;
+ pos = uint_fmt(fmt, len) ;
+ if (!stralloc_readyplus(sa, len + pos + 2)) return 0 ;
+ fmt[pos] = ':' ;
+ byte_copy(sa->s + sa->len, pos+1, fmt) ;
+ sa->len += pos+1 ;
+ for (i = 0 ; i < n ; i++)
+ {
+ byte_copy(sa->s + sa->len, v[i].len, v[i].s) ;
+ sa->len += v[i].len ;
+ }
+ sa->s[sa->len++] = ',' ;
+ return 1 ;
+}
diff --git a/src/libstddjb/netstring_decode.c b/src/libstddjb/netstring_decode.c
new file mode 100644
index 0000000..a81756b
--- /dev/null
+++ b/src/libstddjb/netstring_decode.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/fmtscan.h>
+#include <skalibs/netstring.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/uint.h>
+
+int netstring_decode (stralloc *sa, char const *s, unsigned int len)
+{
+ unsigned int nlen ;
+ register unsigned int pos ;
+ if (!len) return 0 ;
+ pos = uint_scan(s, &nlen) ;
+ if (pos >= len) return (errno = EINVAL, -1) ;
+ if (s[pos] != ':') return (errno = EINVAL, -1) ;
+ s += pos+1 ; len -= pos+1 ;
+ if (len <= nlen) return (errno = EINVAL, -1) ;
+ if (s[nlen] != ',') return (errno = EINVAL, -1) ;
+ if (!stralloc_catb(sa, s, nlen)) return -1 ;
+ return pos + nlen + 2 ;
+}
diff --git a/src/libstddjb/netstring_encode.c b/src/libstddjb/netstring_encode.c
new file mode 100644
index 0000000..c13abd6
--- /dev/null
+++ b/src/libstddjb/netstring_encode.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/netstring.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/uint.h>
+
+int netstring_encode (stralloc *sa, char const *s, unsigned int len)
+{
+ char fmt[UINT_FMT] ;
+ unsigned int pos = uint_fmt(fmt, len) ;
+ if (!stralloc_readyplus(sa, pos + len + 2)) return 0 ;
+ stralloc_catb(sa, fmt, pos) ;
+ stralloc_catb(sa, ":", 1) ;
+ stralloc_catb(sa, s, len) ;
+ stralloc_catb(sa, ",", 1) ;
+ return 1 ;
+}
diff --git a/src/libstddjb/netstring_get.c b/src/libstddjb/netstring_get.c
new file mode 100644
index 0000000..6f6c602
--- /dev/null
+++ b/src/libstddjb/netstring_get.c
@@ -0,0 +1,54 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/uint.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/buffer.h>
+#include <skalibs/cbuffer.h>
+#include <skalibs/error.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/netstring.h>
+
+int netstring_okeof (buffer *b, unsigned int w)
+{
+ return (errno == EPIPE) && !w && buffer_isempty(b) ? (errno = 0, 1) : 0 ;
+}
+
+int netstring_get (buffer *b, stralloc *sa, unsigned int *state)
+{
+ if (!*state)
+ {
+ unsigned int n ;
+ unsigned int len ;
+ char buf[UINT_FMT] ;
+ if (b->c.a < UINT_FMT+1) return (errno = EINVAL, -1) ;
+ for (;;)
+ {
+ register int r ;
+ len = buffer_getnofill(b, buf, UINT_FMT) ;
+ n = byte_chr(buf, len, ':') ; /* XXX: accepts :, as a valid netstring */
+ if (n >= UINT_FMT)
+ {
+ buffer_unget(b, len) ;
+ return (errno = EPROTO, -1) ;
+ }
+ if (n < len) break ;
+ buffer_unget(b, len) ;
+ r = sanitize_read(buffer_fill(b)) ;
+ if (r <= 0) return r ;
+ }
+ buffer_unget(b, len - n - 1) ;
+ if (!n || n != uint_scan(buf, &len)) return (errno = EPROTO, -1) ;
+ if (!stralloc_readyplus(sa, len + 1)) return -1 ;
+ *state = len + 1 ;
+ }
+ {
+ unsigned int w = 0 ;
+ register int r = buffer_getall(b, sa->s + sa->len, *state, &w) ;
+ sa->len += w ;
+ *state -= w ;
+ if (r <= 0) return r ;
+ }
+ return (sa->s[--sa->len] == ',') ? 1 : (errno = EPROTO, -1) ;
+}
diff --git a/src/libstddjb/netstring_put.c b/src/libstddjb/netstring_put.c
new file mode 100644
index 0000000..5a27b25
--- /dev/null
+++ b/src/libstddjb/netstring_put.c
@@ -0,0 +1,36 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/netstring.h>
+#include <skalibs/uint.h>
+
+int netstring_put (buffer *b, char const *s, unsigned int len, unsigned int *written)
+{
+ char fmt[UINT_FMT] ;
+ unsigned int n = uint_fmt(fmt, len) ;
+ if (*written > len + n + 2) return (errno = EINVAL, 0) ;
+ fmt[n] = ':' ;
+ if (*written < n + 1)
+ {
+ unsigned int w = *written ;
+ int r = buffer_putall(b, fmt, n+1, &w) ;
+ if (r < 0) return (*written = w, 0) ;
+ *written = n+1 ;
+ }
+ if (*written < n+1 + len)
+ {
+ unsigned int w = *written - (n+1) ;
+ int r = buffer_putall(b, s, len, &w) ;
+ *written = w + (n+1) ;
+ if (r < 0) return (*written = n+1 + w, 0) ;
+ *written = n+1 + len ;
+ }
+ {
+ unsigned int w = 0 ;
+ int r = buffer_putall(b, ",", 1, &w) ;
+ if (r < 0) return 0 ;
+ }
+ *written = 0 ;
+ return 1 ;
+}
diff --git a/src/libstddjb/ntp_from_tain.c b/src/libstddjb/ntp_from_tain.c
new file mode 100644
index 0000000..43d5a42
--- /dev/null
+++ b/src/libstddjb/ntp_from_tain.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbtime.h>
+
+int ntp_from_tain (uint64 *u, tain_t const *a)
+{
+ uint64 secs, frac ;
+ if (!utc_from_tai(&secs, tain_secp(a))) return 0 ;
+ secs += NTP_OFFSET ;
+ if (secs < TAI_MAGIC + 2147483648UL) goto ifail ;
+ secs -= TAI_MAGIC ;
+ if (secs >= ((uint64)3 << 31)) goto ifail ;
+ secs &= (secs < ((uint64)1 << 32)) ? 0xFFFFFFFFUL : 0x7FFFFFFFUL ;
+ frac = ((uint64)a->nano << 32) / 1000000000UL ;
+ *u = (secs << 32) + frac ;
+ return 1 ;
+ ifail:
+ errno = EINVAL ;
+ return 0 ;
+}
diff --git a/src/libstddjb/open2.c b/src/libstddjb/open2.c
new file mode 100644
index 0000000..780f345
--- /dev/null
+++ b/src/libstddjb/open2.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+int open2 (char const *s, unsigned int flags)
+{
+ register int r ;
+ do
+ r = open(s, (int)flags) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/open3.c b/src/libstddjb/open3.c
new file mode 100644
index 0000000..f990d63
--- /dev/null
+++ b/src/libstddjb/open3.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+int open3 (char const *s, unsigned int flags, unsigned int mode)
+{
+ register int r ;
+ do
+ r = open(s, (int)flags, (mode_t)mode) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/open_append.c b/src/libstddjb/open_append.c
new file mode 100644
index 0000000..7486312
--- /dev/null
+++ b/src/libstddjb/open_append.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <fcntl.h>
+#include <skalibs/djbunix.h>
+
+int open_append (char const *fn)
+{
+ return open3(fn, O_WRONLY | O_NONBLOCK | O_APPEND | O_CREAT, 0666) ;
+}
diff --git a/src/libstddjb/open_create.c b/src/libstddjb/open_create.c
new file mode 100644
index 0000000..db072d1
--- /dev/null
+++ b/src/libstddjb/open_create.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <fcntl.h>
+#include <skalibs/djbunix.h>
+
+int open_create (char const *fn)
+{
+ return open3(fn, O_WRONLY | O_NONBLOCK | O_CREAT, 0666) ;
+}
diff --git a/src/libstddjb/open_excl.c b/src/libstddjb/open_excl.c
new file mode 100644
index 0000000..83c7770
--- /dev/null
+++ b/src/libstddjb/open_excl.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <fcntl.h>
+#include <skalibs/djbunix.h>
+
+int open_excl (char const *fn)
+{
+ return open3(fn, O_WRONLY | O_CREAT | O_EXCL | O_NONBLOCK, 0666) ;
+}
diff --git a/src/libstddjb/open_read.c b/src/libstddjb/open_read.c
new file mode 100644
index 0000000..cc1b191
--- /dev/null
+++ b/src/libstddjb/open_read.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <fcntl.h>
+#include <skalibs/djbunix.h>
+
+int open_read (char const *fn)
+{
+ return open2(fn, O_RDONLY | O_NONBLOCK) ;
+}
diff --git a/src/libstddjb/open_readb.c b/src/libstddjb/open_readb.c
new file mode 100644
index 0000000..a8b0518
--- /dev/null
+++ b/src/libstddjb/open_readb.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/djbunix.h>
+
+int open_readb (char const *fn)
+{
+ register int fd = open_read(fn) ;
+ if (fd == -1) return -1 ;
+ if (ndelay_off(fd) == -1)
+ {
+ fd_close(fd) ;
+ return -1 ;
+ }
+ return fd ;
+}
diff --git a/src/libstddjb/open_trunc.c b/src/libstddjb/open_trunc.c
new file mode 100644
index 0000000..b34e3c2
--- /dev/null
+++ b/src/libstddjb/open_trunc.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <fcntl.h>
+#include <skalibs/djbunix.h>
+
+int open_trunc (char const *fn)
+{
+ return open3(fn, O_WRONLY | O_NONBLOCK | O_TRUNC | O_CREAT, 0666) ;
+}
diff --git a/src/libstddjb/open_write.c b/src/libstddjb/open_write.c
new file mode 100644
index 0000000..42a92c3
--- /dev/null
+++ b/src/libstddjb/open_write.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <fcntl.h>
+#include <skalibs/djbunix.h>
+
+int open_write (char const *fn)
+{
+ return open2(fn, O_WRONLY | O_NONBLOCK) ;
+}
diff --git a/src/libstddjb/openreadclose.c b/src/libstddjb/openreadclose.c
new file mode 100644
index 0000000..cf9a736
--- /dev/null
+++ b/src/libstddjb/openreadclose.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+
+int openreadclose (char const *fn, stralloc *sa, unsigned int bufsize)
+{
+ int fd = open_readb(fn) ;
+ if (fd == -1) return (errno == ENOENT) ? 0 : -1 ;
+ if (!slurp(sa, fd))
+ {
+ register int e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ return -1 ;
+ }
+ fd_close(fd) ;
+ (void)bufsize ;
+ return 0 ;
+}
diff --git a/src/libstddjb/openreadfileclose.c b/src/libstddjb/openreadfileclose.c
new file mode 100644
index 0000000..90e6b47
--- /dev/null
+++ b/src/libstddjb/openreadfileclose.c
@@ -0,0 +1,37 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+
+int openreadfileclose (char const *file, stralloc *sa, unsigned int limit)
+{
+ unsigned int n ;
+ int fd = open_readb(file) ;
+ if (fd < 0) return 0 ;
+ {
+ struct stat st ;
+ if (fstat(fd, &st) < 0) goto err ;
+ n = st.st_size ;
+ }
+ if (limit && (limit < n)) n = limit ;
+ if (!stralloc_ready_tuned(sa, sa->len + n, 0, 0, 1)) goto err ;
+ {
+ register unsigned int r = allread(fd, sa->s + sa->len, n) ;
+ sa->len += r ;
+ if (r < n) goto err ;
+ }
+ fd_close(fd) ;
+ return 1 ;
+
+err:
+ {
+ register int e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ }
+ return 0 ;
+}
diff --git a/src/libstddjb/openreadnclose.c b/src/libstddjb/openreadnclose.c
new file mode 100644
index 0000000..b0cf5d0
--- /dev/null
+++ b/src/libstddjb/openreadnclose.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/djbunix.h>
+
+int openreadnclose (char const *file, char *s, unsigned int n)
+{
+ register int r ;
+ int fd = open_readb(file) ;
+ if (fd == -1) return -1 ;
+ r = allread(fd, s, n) ;
+ if (r == -1)
+ {
+ fd_close(fd) ;
+ return -1 ;
+ }
+ fd_close(fd) ;
+ if ((r > 0) && (r < (int)n)) errno = EPIPE ;
+ return r ;
+}
diff --git a/src/libstddjb/openslurpclose.c b/src/libstddjb/openslurpclose.c
new file mode 100644
index 0000000..5f67d76
--- /dev/null
+++ b/src/libstddjb/openslurpclose.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+
+int openslurpclose (stralloc *sa, char const *fn)
+{
+ int r ;
+ int e ;
+ int fd = open_readb(fn) ;
+ if (fd == -1) return 0 ;
+ r = slurp(sa, fd) ;
+ e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ return r ;
+}
diff --git a/src/libstddjb/openwritenclose_suffix.c b/src/libstddjb/openwritenclose_suffix.c
new file mode 100644
index 0000000..1c538ed
--- /dev/null
+++ b/src/libstddjb/openwritenclose_suffix.c
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h> /* for rename() */
+#include <skalibs/uint64.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/djbunix.h>
+
+int openwritenclose_suffix_internal (char const *fn, char const *s, unsigned int n, uint64 *dev, uint64 *ino, int dosync, char const *suffix)
+{
+ uint64 tmpdev, tmpino ;
+ unsigned int len = str_len(fn) ;
+ unsigned int suffixlen = str_len(suffix) ;
+ char tmp[len + suffixlen + 1] ;
+ byte_copy(tmp, len, fn) ;
+ byte_copy(tmp + len, suffixlen + 1, suffix) ;
+ if (!openwritenclose_unsafe_internal(tmp, s, n, dev ? &tmpdev : 0, ino ? &tmpino : 0, dosync)) return 0 ;
+ if (rename(tmp, fn) < 0)
+ {
+ register int e = errno ;
+ unlink(tmp) ;
+ errno = e ;
+ return 0 ;
+ }
+ if (dev) *dev = tmpdev ;
+ if (ino) *ino = tmpino ;
+ return 1 ;
+}
diff --git a/src/libstddjb/openwritenclose_unsafe.c b/src/libstddjb/openwritenclose_unsafe.c
new file mode 100644
index 0000000..427f6a6
--- /dev/null
+++ b/src/libstddjb/openwritenclose_unsafe.c
@@ -0,0 +1,32 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <skalibs/uint64.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/djbunix.h>
+
+int openwritenclose_unsafe_internal (char const *fn, char const *s, unsigned int len, uint64 *dev, uint64 *ino, int dosync)
+{
+ struct stat st ;
+ int fd = open_trunc(fn) ;
+ if (fd < 0) return 0 ;
+ if (allwrite(fd, s, len) < len) goto fail ;
+ if ((dev || ino) && (fstat(fd, &st) < 0)) goto fail ;
+ if (dosync && (fd_sync(fd) < 0) && (errno != EINVAL)) goto fail ;
+ fd_close(fd) ;
+ if (dev) *dev = (uint64)st.st_dev ;
+ if (ino) *ino = (uint64)st.st_ino ;
+ return 1 ;
+
+ fail:
+ {
+ register int e = errno ;
+ fd_close(fd) ;
+ unlink(fn) ;
+ errno = e ;
+ }
+ return 0 ;
+}
diff --git a/src/libstddjb/pathexec.c b/src/libstddjb/pathexec.c
new file mode 100644
index 0000000..b7b088e
--- /dev/null
+++ b/src/libstddjb/pathexec.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/env.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/environ.h>
+
+void pathexec (char const *const *argv)
+{
+ pathexec_fromenv(argv, (char const **)environ, env_len((char const **)environ)) ;
+}
diff --git a/src/libstddjb/pathexec0.c b/src/libstddjb/pathexec0.c
new file mode 100644
index 0000000..5241452
--- /dev/null
+++ b/src/libstddjb/pathexec0.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <unistd.h>
+#include <skalibs/djbunix.h>
+
+void pathexec0 (char const *const *argv)
+{
+ if (!argv[0]) _exit(0) ;
+ pathexec(argv) ;
+}
diff --git a/src/libstddjb/pathexec0_run.c b/src/libstddjb/pathexec0_run.c
new file mode 100644
index 0000000..818877e
--- /dev/null
+++ b/src/libstddjb/pathexec0_run.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <skalibs/djbunix.h>
+
+void pathexec0_run (char const *const *argv, char const *const *envp)
+{
+ if (!argv[0]) _exit(0) ;
+ pathexec_run(argv[0], argv, envp) ;
+}
diff --git a/src/libstddjb/pathexec_fromenv.c b/src/libstddjb/pathexec_fromenv.c
new file mode 100644
index 0000000..df8b0e6
--- /dev/null
+++ b/src/libstddjb/pathexec_fromenv.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/env.h>
+#include <skalibs/djbunix.h>
+
+static stralloc plus = STRALLOC_ZERO ;
+
+int pathexec_env (char const *s, char const *t) /* historic, bad name */
+{
+ return env_addmodif(&plus, s, t) ;
+}
+
+void pathexec_fromenv (char const *const *argv, char const *const *envp, unsigned int envlen)
+{
+ pathexec_r(argv, envp, envlen, plus.s, plus.len) ;
+}
diff --git a/src/libstddjb/pathexec_r.c b/src/libstddjb/pathexec_r.c
new file mode 100644
index 0000000..eb4a894
--- /dev/null
+++ b/src/libstddjb/pathexec_r.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/djbunix.h>
+
+void pathexec_r (char const *const *argv, char const *const *envp, unsigned int envlen, char const *modifs, unsigned int modiflen)
+{
+ pathexec_r_name(argv[0], argv, envp, envlen, modifs, modiflen) ;
+}
diff --git a/src/libstddjb/pathexec_r_name.c b/src/libstddjb/pathexec_r_name.c
new file mode 100644
index 0000000..c5caf4e
--- /dev/null
+++ b/src/libstddjb/pathexec_r_name.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/env.h>
+#include <skalibs/djbunix.h>
+
+void pathexec_r_name (char const *file, char const *const *argv, char const *const *envp, unsigned int envlen, char const *modifs, unsigned int modiflen)
+{
+ unsigned int n = envlen + 1 + byte_count(modifs, modiflen, '\0') ;
+ char const *v[n] ;
+ if (env_merge(v, n, envp, envlen, modifs, modiflen))
+ pathexec_run(file, argv, v) ;
+}
diff --git a/src/libstddjb/pathexec_run.c b/src/libstddjb/pathexec_run.c
new file mode 100644
index 0000000..ced2ae6
--- /dev/null
+++ b/src/libstddjb/pathexec_run.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/env.h>
+#include <skalibs/djbunix.h>
+
+void pathexec_run (char const *file, char const *const *argv, char const *const *envp)
+{
+ register char const *path = env_get("PATH") ;
+ if (!path) path = SKALIBS_DEFAULTPATH ;
+ execvep(file, argv, envp, path) ;
+}
diff --git a/src/libstddjb/pipe_internal.c b/src/libstddjb/pipe_internal.c
new file mode 100644
index 0000000..d5354de
--- /dev/null
+++ b/src/libstddjb/pipe_internal.c
@@ -0,0 +1,45 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASPIPE2
+
+#define _NETBSD_SOURCE
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <skalibs/djbunix.h>
+
+int pipe_internal (int *p, unsigned int flags)
+{
+ return pipe2(p, ((flags & DJBUNIX_FLAG_COE) ? O_CLOEXEC : 0) | ((flags & DJBUNIX_FLAG_NB) ? O_NONBLOCK : 0)) ;
+}
+
+#else
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+int pipe_internal (int *p, unsigned int flags)
+{
+ int pi[2] ;
+ if (pipe(pi) < 0) return -1 ;
+ if (flags & DJBUNIX_FLAG_COE)
+ if ((coe(pi[0]) < 0) || (coe(pi[1]) < 0)) goto err ;
+ if (flags & DJBUNIX_FLAG_NB)
+ if ((ndelay_on(pi[0]) < 0) || (ndelay_on(pi[1]) < 0)) goto err ;
+ p[0] = pi[0] ; p[1] = pi[1] ;
+ return 0 ;
+ err:
+ {
+ register int e = errno ;
+ fd_close(pi[1]) ;
+ fd_close(pi[0]) ;
+ errno = e ;
+ }
+ return -1 ;
+}
+
+#endif
diff --git a/src/libstddjb/prog.c b/src/libstddjb/prog.c
new file mode 100644
index 0000000..f6c683c
--- /dev/null
+++ b/src/libstddjb/prog.c
@@ -0,0 +1,7 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/strerr2.h>
+
+char const *PROG = "(none)" ;
diff --git a/src/libstddjb/prot.c b/src/libstddjb/prot.c
new file mode 100644
index 0000000..6714cfb
--- /dev/null
+++ b/src/libstddjb/prot.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <unistd.h>
+#include <pwd.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+int prot_setuidgid (char const *name)
+{
+ struct passwd *pw = getpwnam(name) ;
+ if (!pw)
+ {
+ if (!errno) errno = ESRCH ;
+ return 0 ;
+ }
+ return !prot_grps(name) && !setgid(pw->pw_gid) && !setuid(pw->pw_uid) ;
+}
diff --git a/src/libstddjb/prot_grps.c b/src/libstddjb/prot_grps.c
new file mode 100644
index 0000000..cc4ba0d
--- /dev/null
+++ b/src/libstddjb/prot_grps.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/nonposix.h>
+#include <unistd.h>
+#include <grp.h>
+#include <limits.h>
+#include <skalibs/setgroups.h>
+#include <skalibs/djbunix.h>
+
+int prot_grps (char const *name)
+{
+ gid_t tab[NGROUPS_MAX] ;
+ int n = prot_readgroups(name, tab, NGROUPS_MAX) ;
+ return n < 0 ? -1 : setgroups(n, tab) ;
+}
diff --git a/src/libstddjb/prot_readgroups.c b/src/libstddjb/prot_readgroups.c
new file mode 100644
index 0000000..5559882
--- /dev/null
+++ b/src/libstddjb/prot_readgroups.c
@@ -0,0 +1,28 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <sys/types.h>
+#include <grp.h>
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/djbunix.h>
+
+int prot_readgroups (char const *name, gid_t *tab, unsigned int max)
+{
+ unsigned int n = 0 ;
+ for (;;)
+ {
+ struct group *gr ;
+ register char **member ;
+ errno = 0 ;
+ if (n >= max) break ;
+ gr = getgrent() ;
+ if (!gr) break ;
+ for (member = gr->gr_mem ; *member ; member++)
+ if (!str_diff(name, *member)) break ;
+ if (*member) tab[n++] = gr->gr_gid ;
+ }
+ endgrent() ;
+ return errno ? -1 : (int)n ;
+}
diff --git a/src/libstddjb/realpath.c b/src/libstddjb/realpath.c
new file mode 100644
index 0000000..f286137
--- /dev/null
+++ b/src/libstddjb/realpath.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/skamisc.h>
+#include <skalibs/djbunix.h>
+
+char *realpath (char const *name, char *buf)
+{
+ return realpath_tmp(name, buf, &satmp) ;
+}
diff --git a/src/libstddjb/realpath_tmp.c b/src/libstddjb/realpath_tmp.c
new file mode 100644
index 0000000..8f877dd
--- /dev/null
+++ b/src/libstddjb/realpath_tmp.c
@@ -0,0 +1,26 @@
+/* ISC license. */
+
+#include <limits.h>
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+
+#ifndef PATH_MAX
+# define PATH_MAX 4095
+#endif
+
+char *realpath_tmp (char const *name, char *buf, stralloc *tmp)
+{
+ unsigned int tmpbase = tmp->len ;
+ if (sarealpath(tmp, name) == -1) return (char *)0 ;
+ if (tmp->len - tmpbase > PATH_MAX)
+ {
+ tmp->len = tmpbase ;
+ return (errno = ENAMETOOLONG, (char *)0) ;
+ }
+ byte_copy(buf, tmp->len - tmpbase, tmp->s + tmpbase) ;
+ buf[tmp->len - tmpbase] = 0 ;
+ tmp->len = tmpbase ;
+ return buf ;
+}
diff --git a/src/libstddjb/rm_rf.c b/src/libstddjb/rm_rf.c
new file mode 100644
index 0000000..3f8c00d
--- /dev/null
+++ b/src/libstddjb/rm_rf.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/skamisc.h>
+#include <skalibs/djbunix.h>
+
+int rm_rf (char const *filename)
+{
+ return rm_rf_tmp(filename, &satmp) ;
+}
diff --git a/src/libstddjb/rm_rf_in_tmp.c b/src/libstddjb/rm_rf_in_tmp.c
new file mode 100644
index 0000000..8a0a9ec
--- /dev/null
+++ b/src/libstddjb/rm_rf_in_tmp.c
@@ -0,0 +1,93 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/direntry.h>
+#include <skalibs/djbunix.h>
+
+static int rmstarindir (DIR *dir, stralloc *tmp, unsigned int ipos) /* WARNING: closes dir */
+{
+ unsigned int tmpbase = tmp->len ;
+ for (;;)
+ {
+ register direntry *d ;
+ errno = 0 ;
+ d = readdir(dir) ;
+ if (!d) break ;
+ if (d->d_name[0] == '.')
+ if (((d->d_name[1] == '.') && (d->d_name[2] == 0)) || (d->d_name[1] == 0))
+ continue ;
+ if (!stralloc_cats(tmp, d->d_name) || !stralloc_0(tmp)) goto closeanderr ;
+ }
+ if (errno) goto closeanderr ;
+ dir_close(dir) ;
+
+ {
+ unsigned int tmpstop = tmp->len ;
+ unsigned int fnbase = str_len(tmp->s + ipos) ;
+ unsigned int i = tmpbase ;
+ if (!stralloc_readyplus(tmp, fnbase+1)) goto err ;
+ stralloc_catb(tmp, tmp->s + ipos, fnbase) ;
+ stralloc_catb(tmp, "/", 1) ;
+ fnbase = tmp->len ;
+ for (; i < tmpstop ; i += tmp->len - fnbase)
+ {
+ register unsigned int n = str_len(tmp->s + i) ;
+ tmp->len = fnbase ;
+ if (!stralloc_readyplus(tmp, n+1)) goto err ;
+ stralloc_catb(tmp, tmp->s + i, n+1) ;
+ if (rm_rf_in_tmp(tmp, tmpstop) == -1) goto err ;
+ }
+ }
+ tmp->len = tmpbase ;
+ return 0 ;
+
+closeanderr:
+ {
+ register int e = errno ;
+ dir_close(dir) ;
+ errno = e ;
+ }
+err:
+ tmp->len = tmpbase ;
+ return -1 ;
+}
+
+int rm_rf_in_tmp (stralloc *tmp, unsigned int ipos)
+{
+ if (unlink(tmp->s + ipos) == 0) return 0 ;
+ if (errno == ENOENT) return 0 ;
+ if ((errno != EISDIR) && (errno != EPERM)) return -1 ;
+ {
+ register int h = (errno == EPERM) ;
+ register DIR *dir = opendir(tmp->s + ipos) ;
+ if (!dir)
+ {
+ if (h && (errno == ENOTDIR)) errno = EPERM ;
+ return -1 ;
+ }
+ if (rmstarindir(dir, tmp, ipos) == -1) return -1 ;
+ }
+ return rmdir(tmp->s + ipos) ;
+}
+
+int rmstar_tmp (char const *dirname, stralloc *tmp)
+{
+ unsigned int tmpbase = tmp->len ;
+ if (!stralloc_cats(tmp, dirname)) return -1 ;
+ if (!stralloc_0(tmp)) goto err ;
+ {
+ register DIR *dir = opendir(dirname) ;
+ if (!dir) goto err ;
+ if (rmstarindir(dir, tmp, tmpbase) == -1) goto err ;
+ }
+ tmp->len = tmpbase ;
+ return 0 ;
+
+err:
+ tmp->len = tmpbase ;
+ return -1 ;
+}
diff --git a/src/libstddjb/rm_rf_tmp.c b/src/libstddjb/rm_rf_tmp.c
new file mode 100644
index 0000000..6e434d7
--- /dev/null
+++ b/src/libstddjb/rm_rf_tmp.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+
+int rm_rf_tmp (char const *filename, stralloc *tmp)
+{
+ unsigned int tmpbase = tmp->len ;
+ if (!stralloc_cats(tmp, filename)) return -1 ;
+ if (!stralloc_0(tmp)) goto err ;
+ if (rm_rf_in_tmp(tmp, tmpbase) == -1) goto err ;
+ tmp->len = tmpbase ;
+ return 0 ;
+
+err:
+ tmp->len = tmpbase ;
+ return -1 ;
+}
diff --git a/src/libstddjb/rmstar.c b/src/libstddjb/rmstar.c
new file mode 100644
index 0000000..1870274
--- /dev/null
+++ b/src/libstddjb/rmstar.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/skamisc.h>
+#include <skalibs/djbunix.h>
+
+int rmstar (char const *dirname)
+{
+ return rmstar_tmp(dirname, &satmp) ;
+}
diff --git a/src/libstddjb/sabasename.c b/src/libstddjb/sabasename.c
new file mode 100644
index 0000000..829b2a7
--- /dev/null
+++ b/src/libstddjb/sabasename.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+
+int sabasename (stralloc *sa, char const *s, unsigned int len)
+{
+ if (!len) return stralloc_catb(sa, ".", 1) ;
+ while (len && (s[len-1] == '/')) len-- ;
+ if (!len) return stralloc_catb(sa, "/", 1) ;
+ {
+ register unsigned int i = byte_rchr(s, len, '/') ;
+ i = (i == len) ? 0 : i+1 ;
+ return stralloc_catb(sa, s + i, len - i) ;
+ }
+}
diff --git a/src/libstddjb/sadirname.c b/src/libstddjb/sadirname.c
new file mode 100644
index 0000000..9fc4802
--- /dev/null
+++ b/src/libstddjb/sadirname.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+
+int sadirname (stralloc *sa, char const *s, unsigned int len)
+{
+ if (!len) return stralloc_catb(sa, ".", 1) ;
+ while (len && (s[len-1] == '/')) len-- ;
+ if (!len) return stralloc_catb(sa, "/", 1) ;
+ {
+ register unsigned int i = byte_rchr(s, len, '/') ;
+ return (i == len) ? stralloc_catb(sa, ".", 1) :
+ (i == 0) ? stralloc_catb(sa, "/", 1) :
+ stralloc_catb(sa, s, i) ;
+ }
+}
diff --git a/src/libstddjb/sagetcwd.c b/src/libstddjb/sagetcwd.c
new file mode 100644
index 0000000..d8c5dea
--- /dev/null
+++ b/src/libstddjb/sagetcwd.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+
+int sagetcwd (stralloc *sa)
+{
+ unsigned int n = 128 ;
+ int wasnull = !sa->s ;
+
+ for (;;)
+ {
+ if (!stralloc_readyplus(sa, n)) goto err ;
+ if (getcwd(sa->s + sa->len, n)) break ;
+ if (errno != ERANGE) goto err ;
+ n += 128 ;
+ }
+ sa->len += str_len(sa->s + sa->len) ;
+ return 0 ;
+
+err:
+ if (wasnull) stralloc_free(sa) ;
+ return -1 ;
+}
diff --git a/src/libstddjb/sagethostname.c b/src/libstddjb/sagethostname.c
new file mode 100644
index 0000000..500a95c
--- /dev/null
+++ b/src/libstddjb/sagethostname.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+
+int sagethostname (stralloc *sa)
+{
+ unsigned int n = 128 ;
+ int wasnull = !sa->s ;
+
+ for (;;)
+ {
+ if (!stralloc_readyplus(sa, n)) goto err ;
+ sa->s[sa->len + n - 2] = 0 ;
+ if (gethostname(sa->s + sa->len, n) == -1) goto err ;
+ if (!sa->s[sa->len + n - 2]) break ;
+ n += 128 ;
+ }
+ sa->len += str_len(sa->s + sa->len) ;
+ return 0 ;
+
+err:
+ if (wasnull) stralloc_free(sa) ;
+ return -1 ;
+}
diff --git a/src/libstddjb/sanitize_read.c b/src/libstddjb/sanitize_read.c
new file mode 100644
index 0000000..bd8eee3
--- /dev/null
+++ b/src/libstddjb/sanitize_read.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/error.h>
+
+int sanitize_read (int r)
+{
+ return r == -1 ? error_isagain(errno) ? (errno = 0, 0) : -1 :
+ !r ? (errno = EPIPE, -1) : r ;
+}
diff --git a/src/libstddjb/sareadlink.c b/src/libstddjb/sareadlink.c
new file mode 100644
index 0000000..d6c2a4e
--- /dev/null
+++ b/src/libstddjb/sareadlink.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+
+int sareadlink (stralloc *sa, char const *path)
+{
+ unsigned int n = 128 ;
+ int wasnull = !sa->s ;
+ register int r ;
+
+ for (;;)
+ {
+ if (!stralloc_readyplus(sa, n)) goto err ;
+ r = readlink(path, sa->s + sa->len, n) ;
+ if (r < 0) goto err ;
+ if ((unsigned int)r < n) break ;
+ n += 128 ;
+ }
+ sa->len += r ;
+ return 0 ;
+
+err:
+ if (wasnull) stralloc_free(sa) ;
+ return -1 ;
+}
diff --git a/src/libstddjb/satmp.c b/src/libstddjb/satmp.c
new file mode 100644
index 0000000..833c74f
--- /dev/null
+++ b/src/libstddjb/satmp.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/skamisc.h>
+
+stralloc satmp = STRALLOC_ZERO ;
diff --git a/src/libstddjb/sauniquename.c b/src/libstddjb/sauniquename.c
new file mode 100644
index 0000000..5a6ad83
--- /dev/null
+++ b/src/libstddjb/sauniquename.c
@@ -0,0 +1,28 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/skamisc.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/tai.h>
+#include <skalibs/uint.h>
+
+int sauniquename (stralloc *sa)
+{
+ unsigned int base = sa->len ;
+ int wasnull = !sa->s ;
+
+ if (!stralloc_readyplus(sa, TIMESTAMP + UINT_FMT + 131)) return -1 ;
+ sa->s[base] = ':' ;
+ timestamp(sa->s + base + 1) ;
+ sa->s[base + 1 + TIMESTAMP] = ':' ;
+ sa->len = base + 2 + TIMESTAMP ;
+ sa->len += uint_fmt(sa->s + sa->len, getpid()) ;
+ sa->s[sa->len++] = ':' ;
+ if (sagethostname(sa) == -1) goto err ;
+ return 0 ;
+
+err:
+ if (wasnull) stralloc_free(sa) ; else sa->len = base ;
+ return -1 ;
+}
diff --git a/src/libstddjb/seek_cur.c b/src/libstddjb/seek_cur.c
new file mode 100644
index 0000000..cdfdac7
--- /dev/null
+++ b/src/libstddjb/seek_cur.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <skalibs/djbunix.h>
+
+long seek_cur (int fd)
+{
+ return (long)lseek(fd, 0, SEEK_CUR) ;
+}
diff --git a/src/libstddjb/seek_set.c b/src/libstddjb/seek_set.c
new file mode 100644
index 0000000..b5883ac
--- /dev/null
+++ b/src/libstddjb/seek_set.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <skalibs/djbunix.h>
+
+#define SET 0 /* sigh */
+
+int seek_set (int fd, long pos)
+{
+ if (lseek(fd, (off_t) pos, SET) == -1) return -1 ;
+ return 0 ;
+}
diff --git a/src/libstddjb/selfpipe-internal.h b/src/libstddjb/selfpipe-internal.h
new file mode 100644
index 0000000..994c179
--- /dev/null
+++ b/src/libstddjb/selfpipe-internal.h
@@ -0,0 +1,28 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#ifndef SELFPIPE_INTERNAL_H
+#define SELFPIPE_INTERNAL_H
+
+#include <signal.h>
+#include <skalibs/sysdeps.h>
+
+extern sigset_t selfpipe_caught ;
+
+#ifdef SKALIBS_HASSIGNALFD
+
+extern int selfpipe_fd ;
+
+#else
+
+#include <skalibs/sig.h>
+
+extern int selfpipe[2] ;
+#define selfpipe_fd selfpipe[0]
+
+extern struct skasigaction const selfpipe_ssa ;
+
+#endif
+
+#endif
diff --git a/src/libstddjb/selfpipe_finish.c b/src/libstddjb/selfpipe_finish.c
new file mode 100644
index 0000000..47a889f
--- /dev/null
+++ b/src/libstddjb/selfpipe_finish.c
@@ -0,0 +1,35 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <signal.h>
+#include <skalibs/sysdeps.h>
+#include <skalibs/djbunix.h>
+#include "selfpipe-internal.h"
+#include <skalibs/selfpipe.h>
+
+#ifdef SKALIBS_HASSIGNALFD
+
+void selfpipe_finish (void)
+{
+ sigprocmask(SIG_UNBLOCK, &selfpipe_caught, 0) ;
+ sigemptyset(&selfpipe_caught) ;
+ fd_close(selfpipe_fd) ;
+ selfpipe_fd = -1 ;
+}
+
+#else
+
+#include <skalibs/sig.h>
+#include <skalibs/nsig.h>
+
+void selfpipe_finish (void)
+{
+ sig_restoreto(&selfpipe_caught, NSIG) ;
+ sigemptyset(&selfpipe_caught) ;
+ fd_close(selfpipe[1]) ;
+ fd_close(selfpipe[0]) ;
+ selfpipe[0] = selfpipe[1] = -1 ;
+}
+
+#endif
diff --git a/src/libstddjb/selfpipe_init.c b/src/libstddjb/selfpipe_init.c
new file mode 100644
index 0000000..bd26d2f
--- /dev/null
+++ b/src/libstddjb/selfpipe_init.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <errno.h>
+#include <signal.h>
+#include <skalibs/sysdeps.h>
+#include "selfpipe-internal.h"
+#include <skalibs/selfpipe.h>
+
+#ifdef SKALIBS_HASSIGNALFD
+#include <sys/signalfd.h>
+#else
+#include <skalibs/djbunix.h>
+#endif
+
+int selfpipe_init (void)
+{
+ if (selfpipe_fd >= 0) return (errno = EBUSY, -1) ;
+ sigemptyset(&selfpipe_caught) ;
+#ifdef SKALIBS_HASSIGNALFD
+ selfpipe_fd = signalfd(-1, &selfpipe_caught, SFD_NONBLOCK | SFD_CLOEXEC) ;
+#else
+ if (pipenbcoe(selfpipe) < 0) return -1 ;
+#endif
+ return selfpipe_fd ;
+}
diff --git a/src/libstddjb/selfpipe_internal.c b/src/libstddjb/selfpipe_internal.c
new file mode 100644
index 0000000..e5d5d95
--- /dev/null
+++ b/src/libstddjb/selfpipe_internal.c
@@ -0,0 +1,31 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <signal.h>
+#include <skalibs/sysdeps.h>
+#include "selfpipe-internal.h"
+
+sigset_t selfpipe_caught ;
+
+#ifdef SKALIBS_HASSIGNALFD
+
+int selfpipe_fd = -1 ;
+
+#else
+
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/djbunix.h>
+
+int selfpipe[2] = { -1, -1 } ;
+
+static void selfpipe_trigger (int s)
+{
+ char c = (char)s ;
+ fd_write(selfpipe[1], &c, 1) ;
+}
+
+struct skasigaction const selfpipe_ssa = { &selfpipe_trigger, SKASA_NOCLDSTOP | SKASA_MASKALL } ;
+
+#endif
diff --git a/src/libstddjb/selfpipe_read.c b/src/libstddjb/selfpipe_read.c
new file mode 100644
index 0000000..b68e67d
--- /dev/null
+++ b/src/libstddjb/selfpipe_read.c
@@ -0,0 +1,31 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/allreadwrite.h>
+#include "selfpipe-internal.h"
+#include <skalibs/selfpipe.h>
+
+#ifdef SKALIBS_HASSIGNALFD
+
+#include <sys/signalfd.h>
+
+int selfpipe_read (void)
+{
+ struct signalfd_siginfo buf ;
+ register int r = sanitize_read(fd_read(selfpipe_fd, (char *)&buf, sizeof(struct signalfd_siginfo))) ;
+ return (r <= 0) ? r : (int)buf.ssi_signo ;
+}
+
+#else
+
+int selfpipe_read (void)
+{
+ char c ;
+ register int r = sanitize_read((fd_read(selfpipe_fd, &c, 1))) ;
+ return (r <= 0) ? r : (int)c ;
+}
+
+#endif
+
diff --git a/src/libstddjb/selfpipe_trap.c b/src/libstddjb/selfpipe_trap.c
new file mode 100644
index 0000000..f07db64
--- /dev/null
+++ b/src/libstddjb/selfpipe_trap.c
@@ -0,0 +1,51 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <errno.h>
+#include <signal.h>
+#include <skalibs/sysdeps.h>
+#include "selfpipe-internal.h"
+#include <skalibs/selfpipe.h>
+
+#ifdef SKALIBS_HASSIGNALFD
+
+#include <sys/signalfd.h>
+
+int selfpipe_trap (int sig)
+{
+ sigset_t ss = selfpipe_caught ;
+ sigset_t old ;
+ if (selfpipe_fd < 0) return (errno = EBADF, -1) ;
+ if ((sigaddset(&ss, sig) < 0) || (sigprocmask(SIG_BLOCK, &ss, &old) < 0))
+ return -1 ;
+ if (signalfd(selfpipe_fd, &ss, SFD_NONBLOCK | SFD_CLOEXEC) < 0)
+ {
+ int e = errno ;
+ sigprocmask(SIG_SETMASK, &old, 0) ;
+ errno = e ;
+ return -1 ;
+ }
+ selfpipe_caught = ss ;
+ return 0 ;
+}
+
+#else
+
+#include <skalibs/sig.h>
+
+int selfpipe_trap (int sig)
+{
+ if (selfpipe_fd < 0) return (errno = EBADF, -1) ;
+ if (sig_catcha(sig, &selfpipe_ssa) < 0) return -1 ;
+ if (sigaddset(&selfpipe_caught, sig) < 0)
+ {
+ int e = errno ;
+ sig_restore(sig) ;
+ errno = e ;
+ return -1 ;
+ }
+ return 0 ;
+}
+
+#endif
diff --git a/src/libstddjb/selfpipe_trapset.c b/src/libstddjb/selfpipe_trapset.c
new file mode 100644
index 0000000..f8c35ee
--- /dev/null
+++ b/src/libstddjb/selfpipe_trapset.c
@@ -0,0 +1,64 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <errno.h>
+#include <signal.h>
+#include <skalibs/sysdeps.h>
+#include "selfpipe-internal.h"
+#include <skalibs/selfpipe.h>
+
+#ifdef SKALIBS_HASSIGNALFD
+
+#include <sys/signalfd.h>
+
+int selfpipe_trapset (sigset_t const *set)
+{
+ sigset_t old ;
+ if (selfpipe_fd < 0) return (errno = EBADF, -1) ;
+ if (sigprocmask(SIG_SETMASK, set, &old) < 0) return -1 ;
+ if (signalfd(selfpipe_fd, set, SFD_NONBLOCK | SFD_CLOEXEC) < 0)
+ {
+ int e = errno ;
+ sigprocmask(SIG_SETMASK, &old, 0) ;
+ errno = e ;
+ return -1 ;
+ }
+ selfpipe_caught = *set ;
+ return 0 ;
+}
+
+#else
+
+#include <skalibs/sig.h>
+#include <skalibs/nsig.h>
+
+int selfpipe_trapset (sigset_t const *set)
+{
+ unsigned int i = 1 ;
+ if (selfpipe_fd < 0) return (errno = EBADF, -1) ;
+ for (; i <= NSIG ; i++)
+ {
+ register int h = sigismember(set, i) ;
+ if (h < 0) continue ;
+ if (h)
+ {
+ if (sig_catcha(i, &selfpipe_ssa) < 0) break ;
+ }
+ else if (sigismember(&selfpipe_caught, i))
+ {
+ if (sig_restore(i) < 0) break ;
+ }
+ }
+ if (i <= NSIG)
+ {
+ int e = errno ;
+ sig_restoreto(set, i) ;
+ errno = e ;
+ return -1 ;
+ }
+ selfpipe_caught = *set ;
+ return 0 ;
+}
+
+#endif
diff --git a/src/libstddjb/selfpipe_untrap.c b/src/libstddjb/selfpipe_untrap.c
new file mode 100644
index 0000000..776f2d7
--- /dev/null
+++ b/src/libstddjb/selfpipe_untrap.c
@@ -0,0 +1,54 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <errno.h>
+#include <signal.h>
+#include <skalibs/sysdeps.h>
+#include "selfpipe-internal.h"
+#include <skalibs/selfpipe.h>
+
+#ifdef SKALIBS_HASSIGNALFD
+
+#include <sys/signalfd.h>
+
+int selfpipe_untrap (int sig)
+{
+ sigset_t ss = selfpipe_caught ;
+ sigset_t blah ;
+ register int r = sigismember(&selfpipe_caught, sig) ;
+ if (selfpipe_fd < 0) return (errno = EBADF, -1) ;
+ if (r < 0) return -1 ;
+ if (!r) return (errno = EINVAL, -1) ;
+ if ((sigdelset(&ss, sig) < 0)
+ || (signalfd(selfpipe_fd, &ss, SFD_NONBLOCK | SFD_CLOEXEC) < 0))
+ return -1 ;
+ sigemptyset(&blah) ;
+ sigaddset(&blah, sig) ;
+ if (sigprocmask(SIG_UNBLOCK, &blah, 0) < 0)
+ {
+ int e = errno ;
+ signalfd(selfpipe_fd, &selfpipe_caught, SFD_NONBLOCK | SFD_CLOEXEC) ;
+ errno = e ;
+ return -1 ;
+ }
+ selfpipe_caught = ss ;
+ return 0 ;
+}
+
+#else
+
+#include <skalibs/sig.h>
+
+int selfpipe_untrap (int sig)
+{
+ register int r = sigismember(&selfpipe_caught, sig) ;
+ if (selfpipe_fd < 0) return (errno = EBADF, -1) ;
+ if (r < 0) return -1 ;
+ if (!r) return (errno = EINVAL, -1) ;
+ if (sig_restore(sig) < 0) return -1 ;
+ sigdelset(&selfpipe_caught, sig) ;
+ return 0 ;
+}
+
+#endif
diff --git a/src/libstddjb/sgetopt.c b/src/libstddjb/sgetopt.c
new file mode 100644
index 0000000..7e6bdf6
--- /dev/null
+++ b/src/libstddjb/sgetopt.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#undef SUBGETOPT_SHORT
+
+#include <skalibs/buffer.h>
+#include <skalibs/sgetopt.h>
+
+int sgetopt_r (int argc, char const *const *argv, char const *opts, subgetopt_t *o)
+{
+ char c = (char)subgetopt_r(argc, argv, opts, o) ;
+ if (o->err && ((c == '?') || (c == ':')))
+ {
+ buffer_puts(buffer_2, o->prog ? o->prog : argv[0]) ;
+ buffer_put(buffer_2, ": ", 2) ;
+ buffer_puts(buffer_2, ((c == '?') && argv[o->ind] && (o->ind < argc)) ?
+ "illegal option" : "option requires an argument") ;
+ buffer_put(buffer_2, " -- ", 4) ;
+ buffer_put(buffer_2, &c, 1) ;
+ buffer_putflush(buffer_2, "\n", 1) ;
+ }
+ return (int)c ;
+}
diff --git a/src/libstddjb/short_scan.c b/src/libstddjb/short_scan.c
new file mode 100644
index 0000000..898ba9f
--- /dev/null
+++ b/src/libstddjb/short_scan.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/ushort.h>
+#include "fmtscan-internal.h"
+
+SCANS(short, SHRT)
diff --git a/src/libstddjb/sig.c b/src/libstddjb/sig.c
new file mode 100644
index 0000000..334b79a
--- /dev/null
+++ b/src/libstddjb/sig.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <signal.h>
+#include <skalibs/sig.h>
+
+int sig_alarm = SIGALRM ;
+int sig_child = SIGCHLD ;
+int sig_stop = SIGSTOP ;
+int sig_cont = SIGCONT ;
+int sig_hangup = SIGHUP ;
+int sig_int = SIGINT ;
+int sig_kill = SIGKILL ;
+int sig_pipe = SIGPIPE ;
+int sig_term = SIGTERM ;
+int sig_usr1 = SIGUSR1 ;
+int sig_usr2 = SIGUSR2 ;
+int sig_quit = SIGQUIT ;
+int sig_abort = SIGABRT ;
diff --git a/src/libstddjb/sig_block.c b/src/libstddjb/sig_block.c
new file mode 100644
index 0000000..89ae51f
--- /dev/null
+++ b/src/libstddjb/sig_block.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <signal.h>
+#include <skalibs/sig.h>
+
+void sig_block (int sig)
+{
+ sigset_t ss ;
+ sigemptyset(&ss) ;
+ sigaddset(&ss, sig) ;
+ sigprocmask(SIG_BLOCK, &ss, 0) ;
+}
diff --git a/src/libstddjb/sig_blocknone.c b/src/libstddjb/sig_blocknone.c
new file mode 100644
index 0000000..8498f0f
--- /dev/null
+++ b/src/libstddjb/sig_blocknone.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <signal.h>
+#include <skalibs/sig.h>
+
+void sig_blocknone (void)
+{
+ sigset_t ss ;
+ sigemptyset(&ss) ;
+ sigprocmask(SIG_SETMASK, &ss, 0) ;
+}
diff --git a/src/libstddjb/sig_blockset.c b/src/libstddjb/sig_blockset.c
new file mode 100644
index 0000000..206c157
--- /dev/null
+++ b/src/libstddjb/sig_blockset.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <signal.h>
+#include <skalibs/sig.h>
+
+void sig_blockset (sigset_t const *set)
+{
+ sigprocmask(SIG_SETMASK, set, 0) ;
+}
diff --git a/src/libstddjb/sig_catch.c b/src/libstddjb/sig_catch.c
new file mode 100644
index 0000000..d0a72df
--- /dev/null
+++ b/src/libstddjb/sig_catch.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/sig.h>
+
+int sig_catch (int sig, skasighandler_t_ref f)
+{
+ struct skasigaction ssa = { f, SKASA_MASKALL | SKASA_NOCLDSTOP } ;
+ return sig_catcha(sig, &ssa) ;
+}
diff --git a/src/libstddjb/sig_pause.c b/src/libstddjb/sig_pause.c
new file mode 100644
index 0000000..7de8ff5
--- /dev/null
+++ b/src/libstddjb/sig_pause.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <signal.h>
+#include <skalibs/sig.h>
+
+void sig_pause (void)
+{
+ sigset_t ss ;
+ sigemptyset(&ss) ;
+ sigsuspend(&ss) ;
+}
diff --git a/src/libstddjb/sig_push.c b/src/libstddjb/sig_push.c
new file mode 100644
index 0000000..96e5fb2
--- /dev/null
+++ b/src/libstddjb/sig_push.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/sig.h>
+
+int sig_push (int sig, skasighandler_t_ref f)
+{
+ struct skasigaction ssa = { f, SKASA_MASKALL | SKASA_NOCLDSTOP } ;
+ return sig_pusha(sig, &ssa) ;
+}
diff --git a/src/libstddjb/sig_restoreto.c b/src/libstddjb/sig_restoreto.c
new file mode 100644
index 0000000..523b14a
--- /dev/null
+++ b/src/libstddjb/sig_restoreto.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <signal.h>
+#include <skalibs/sig.h>
+
+void sig_restoreto (sigset_t const *set, unsigned int n)
+{
+ register unsigned int i = 1 ;
+ for (; i <= n ; i++)
+ {
+ register int h = sigismember(set, i) ;
+ if (h < 0) continue ;
+ if (h) sig_restore(i) ;
+ }
+}
diff --git a/src/libstddjb/sig_shield.c b/src/libstddjb/sig_shield.c
new file mode 100644
index 0000000..ee5d9a9
--- /dev/null
+++ b/src/libstddjb/sig_shield.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <signal.h>
+#include <skalibs/sig.h>
+
+void sig_shield (void)
+{
+ sigset_t ss ;
+ sigemptyset(&ss) ;
+ sigaddset(&ss, SIGTERM) ;
+ sigaddset(&ss, SIGQUIT) ;
+ sigaddset(&ss, SIGABRT) ;
+ sigaddset(&ss, SIGINT) ;
+ sigaddset(&ss, SIGPIPE) ;
+ sigaddset(&ss, SIGHUP) ;
+ sigprocmask(SIG_BLOCK, &ss, 0) ;
+}
diff --git a/src/libstddjb/sig_stack.c b/src/libstddjb/sig_stack.c
new file mode 100644
index 0000000..c414a88
--- /dev/null
+++ b/src/libstddjb/sig_stack.c
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <errno.h>
+#include <signal.h>
+#include <skalibs/sig.h>
+#include <skalibs/nsig.h>
+
+static struct skasigaction skasigstack[NSIG][SIGSTACKSIZE] ;
+static unsigned int sigsp[NSIG] ;
+
+int sig_pusha (int sig, struct skasigaction const *ssa)
+{
+ if ((sig <= 0) || (sig > NSIG)) return (errno = EINVAL, -1) ;
+ if (sigsp[sig-1] >= SIGSTACKSIZE) return (errno = ENOBUFS, -1) ;
+ if (skasigaction(sig, ssa, &skasigstack[sig-1][sigsp[sig-1]]) == -1)
+ return -1 ;
+ return ++sigsp[sig-1] ;
+}
+
+int sig_pop (int sig)
+{
+ if ((sig <= 0) || (sig > NSIG)) return (errno = EINVAL, -1) ;
+ if (!sigsp[sig-1]) return (errno = EFAULT, -1);
+ if (skasigaction(sig, &skasigstack[sig-1][sigsp[sig-1]-1], 0) == -1)
+ return -1 ;
+ return --sigsp[sig-1] ;
+}
diff --git a/src/libstddjb/sig_unblock.c b/src/libstddjb/sig_unblock.c
new file mode 100644
index 0000000..26d5c1b
--- /dev/null
+++ b/src/libstddjb/sig_unblock.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <signal.h>
+#include <skalibs/sig.h>
+
+void sig_unblock (int sig)
+{
+ sigset_t ss ;
+ sigemptyset(&ss) ;
+ sigaddset(&ss, sig) ;
+ sigprocmask(SIG_UNBLOCK, &ss, 0) ;
+}
diff --git a/src/libstddjb/sig_unshield.c b/src/libstddjb/sig_unshield.c
new file mode 100644
index 0000000..24918b4
--- /dev/null
+++ b/src/libstddjb/sig_unshield.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <signal.h>
+#include <skalibs/sig.h>
+
+void sig_unshield (void)
+{
+ sigset_t ss ;
+ sigemptyset(&ss) ;
+ sigaddset(&ss, SIGTERM) ;
+ sigaddset(&ss, SIGQUIT) ;
+ sigaddset(&ss, SIGABRT) ;
+ sigaddset(&ss, SIGINT) ;
+ sigaddset(&ss, SIGPIPE) ;
+ sigaddset(&ss, SIGHUP) ;
+ sigprocmask(SIG_UNBLOCK, &ss, 0) ;
+}
diff --git a/src/libstddjb/sigfpe.c b/src/libstddjb/sigfpe.c
new file mode 100644
index 0000000..2ff92a7
--- /dev/null
+++ b/src/libstddjb/sigfpe.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <signal.h>
+#include <skalibs/segfault.h>
+
+int sigfpe (void)
+{
+ return raise(SIGFPE) == 0 ;
+}
diff --git a/src/libstddjb/sigsegv.c b/src/libstddjb/sigsegv.c
new file mode 100644
index 0000000..80c963c
--- /dev/null
+++ b/src/libstddjb/sigsegv.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <signal.h>
+#include <skalibs/segfault.h>
+
+int sigsegv (void)
+{
+ return raise(SIGSEGV) == 0 ;
+}
diff --git a/src/libstddjb/siovec_bytechr.c b/src/libstddjb/siovec_bytechr.c
new file mode 100644
index 0000000..a825488
--- /dev/null
+++ b/src/libstddjb/siovec_bytechr.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/siovec.h>
+
+unsigned int siovec_bytechr (siovec_t const *v, unsigned int n, char c)
+{
+ unsigned int w = 0 ;
+ unsigned int i = 0 ;
+ for (; i < n ; i++)
+ {
+ register unsigned int pos = byte_chr(v[i].s, v[i].len, c) ;
+ w += pos ;
+ if (pos < v[i].len) break ;
+ }
+ return w ;
+}
diff --git a/src/libstddjb/siovec_bytein.c b/src/libstddjb/siovec_bytein.c
new file mode 100644
index 0000000..e9db87d
--- /dev/null
+++ b/src/libstddjb/siovec_bytein.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/siovec.h>
+
+unsigned int siovec_bytein (siovec_t const *v, unsigned int n, char const *sep, unsigned int seplen)
+{
+ unsigned int w = 0 ;
+ unsigned int i = 0 ;
+ for (; i < n ; i++)
+ {
+ register unsigned int pos = byte_in(v[i].s, v[i].len, sep, seplen) ;
+ w += pos ;
+ if (pos < v[i].len) break ;
+ }
+ return w ;
+}
diff --git a/src/libstddjb/siovec_deal.c b/src/libstddjb/siovec_deal.c
new file mode 100644
index 0000000..fffea92
--- /dev/null
+++ b/src/libstddjb/siovec_deal.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/siovec.h>
+
+unsigned int siovec_deal (siovec_t const *vj, unsigned int nj, siovec_t const *vi, unsigned int ni)
+{
+ unsigned int w = 0 ;
+ unsigned int i = 0 ;
+ unsigned int j = 0 ;
+ unsigned int wi = 0 ;
+ unsigned int wj = 0 ;
+ while (i < ni && j < nj)
+ {
+ register unsigned int tor = vi[i].len - wi ;
+ register unsigned int tow = vj[j].len - wj ;
+ register unsigned int len = tor < tow ? tor : tow ;
+ byte_copy(vj[j].s + wj, len, vi[i].s + wi) ;
+ wi += len ; wj += len ; w += len ;
+ if (wi >= vi[i].len) { wi = 0 ; i++ ; }
+ if (wj >= vj[j].len) { wj = 0 ; j++ ; }
+ }
+ return w ;
+}
diff --git a/src/libstddjb/siovec_from_iovec.c b/src/libstddjb/siovec_from_iovec.c
new file mode 100644
index 0000000..ffc0508
--- /dev/null
+++ b/src/libstddjb/siovec_from_iovec.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <skalibs/siovec.h>
+
+void siovec_from_iovec (siovec_t *v, struct iovec const *iov, unsigned int n)
+{
+ while (n--)
+ {
+ v[n].s = iov[n].iov_base ;
+ v[n].len = iov[n].iov_len ;
+ }
+}
diff --git a/src/libstddjb/siovec_gather.c b/src/libstddjb/siovec_gather.c
new file mode 100644
index 0000000..23ae28a
--- /dev/null
+++ b/src/libstddjb/siovec_gather.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/siovec.h>
+
+unsigned int siovec_gather (siovec_t const *v, unsigned int n, char *s, unsigned int max)
+{
+ unsigned int w = 0 ;
+ register unsigned int i = 0 ;
+ for (; i < n && w < max ; i++)
+ {
+ register unsigned int len = v[i].len ;
+ if ((w + len) > max) len = max - w ;
+ byte_copy(s + w, len, v[i].s) ;
+ w += len ;
+ }
+ return w ;
+}
diff --git a/src/libstddjb/siovec_len.c b/src/libstddjb/siovec_len.c
new file mode 100644
index 0000000..5d53e53
--- /dev/null
+++ b/src/libstddjb/siovec_len.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/siovec.h>
+
+unsigned int siovec_len (siovec_t const *v, register unsigned int n)
+{
+ register unsigned int w = 0 ;
+ while (n--) w += v[n].len ;
+ return w ;
+}
diff --git a/src/libstddjb/siovec_scatter.c b/src/libstddjb/siovec_scatter.c
new file mode 100644
index 0000000..256bef5
--- /dev/null
+++ b/src/libstddjb/siovec_scatter.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/siovec.h>
+
+unsigned int siovec_scatter (siovec_t const *v, unsigned int n, char const *s, unsigned int len)
+{
+ unsigned int w = 0 ;
+ register unsigned int i = 0 ;
+ for (; i < n && w < len ; i++)
+ {
+ register unsigned int chunklen = v[i].len ;
+ if (w + chunklen > len) chunklen = len - w ;
+ byte_copy(v[i].s, chunklen, s + w) ;
+ w += chunklen ;
+ }
+ return w ;
+}
diff --git a/src/libstddjb/siovec_seek.c b/src/libstddjb/siovec_seek.c
new file mode 100644
index 0000000..34a8918
--- /dev/null
+++ b/src/libstddjb/siovec_seek.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/siovec.h>
+
+unsigned int siovec_seek (siovec_t *v, unsigned int n, unsigned int len)
+{
+ unsigned int w = 0 ;
+ register unsigned int i = 0 ;
+ for (; i < n ; i++)
+ {
+ if (len < v[i].len) break ;
+ w += v[i].len ;
+ len -= v[i].len ;
+ v[i].s = 0 ;
+ v[i].len = 0 ;
+ }
+ if (i < n)
+ {
+ v[i].s += len ;
+ v[i].len -= len ;
+ w += len ;
+ }
+ return w ;
+}
diff --git a/src/libstddjb/skagetln.c b/src/libstddjb/skagetln.c
new file mode 100644
index 0000000..056cc38
--- /dev/null
+++ b/src/libstddjb/skagetln.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/siovec.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/skamisc.h>
+
+int skagetln (buffer *b, stralloc *sa, char sep)
+{
+ unsigned int start = sa->len ;
+ for (;;)
+ {
+ siovec_t v[2] ;
+ unsigned int pos ;
+ int r ;
+ buffer_rpeek(b, v) ;
+ pos = siovec_bytechr(v, 2, sep) ;
+ r = pos < buffer_len(b) ; pos += r ;
+ if (!stralloc_readyplus(sa, pos)) return -1 ;
+ buffer_getnofill(b, sa->s + sa->len, pos) ; sa->len += pos ;
+ if (r) return 1 ;
+ r = buffer_fill(b) ;
+ if (r < 0) return r ;
+ if (!r) return (sa->s && (sa->len > start)) ? (errno = EPIPE, -1) : 0 ;
+ }
+}
diff --git a/src/libstddjb/skagetlnsep.c b/src/libstddjb/skagetlnsep.c
new file mode 100644
index 0000000..1d3b4ef
--- /dev/null
+++ b/src/libstddjb/skagetlnsep.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/siovec.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/skamisc.h>
+
+int skagetlnsep (buffer *b, stralloc *sa, char const *sep, unsigned int seplen)
+{
+ unsigned int start = sa->len ;
+ for (;;)
+ {
+ siovec_t v[2] ;
+ unsigned int pos ;
+ int r ;
+ buffer_rpeek(b, v) ;
+ pos = siovec_bytein(v, 2, sep, seplen) ;
+ r = pos < buffer_len(b) ; pos += r ;
+ if (!stralloc_readyplus(sa, pos)) return -1 ;
+ buffer_getnofill(b, sa->s + sa->len, pos) ; sa->len += pos ;
+ if (r) return 1 ;
+ r = buffer_fill(b) ;
+ if (r < 0) return r ;
+ if (!r) return (sa->s && (sa->len > start)) ? (errno = EPIPE, -1) : 0 ;
+ }
+}
diff --git a/src/libstddjb/skasig_dfl.c b/src/libstddjb/skasig_dfl.c
new file mode 100644
index 0000000..ca97b4f
--- /dev/null
+++ b/src/libstddjb/skasig_dfl.c
@@ -0,0 +1,7 @@
+/* ISC license. */
+
+#include <signal.h>
+#include <skalibs/sig.h>
+
+struct skasigaction const SKASIG_DFL = { SIG_DFL, 0 } ;
+struct skasigaction const SKASIG_IGN = { SIG_IGN, 0 } ;
diff --git a/src/libstddjb/skasigaction.c b/src/libstddjb/skasigaction.c
new file mode 100644
index 0000000..a673fcb
--- /dev/null
+++ b/src/libstddjb/skasigaction.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <signal.h>
+#include <skalibs/sysdeps.h>
+#include <skalibs/sig.h>
+
+int skasigaction (int sig, struct skasigaction const *new, struct skasigaction *old)
+{
+ struct sigaction sanew, saold ;
+ if (((new->flags & SKASA_MASKALL) ? sigfillset(&sanew.sa_mask) : sigemptyset(&sanew.sa_mask)) == -1) return -1 ;
+ sanew.sa_handler = new->handler ;
+ sanew.sa_flags = (new->flags & SKASA_NOCLDSTOP) ? SA_NOCLDSTOP : 0 ;
+ if (sigaction(sig, &sanew, &saold) == -1) return -1 ;
+ if (old)
+ {
+ register int r = sigismember(&saold.sa_mask, (sig == SIGTERM) ? SIGPIPE : SIGTERM) ;
+ if (r == -1) return -1 ;
+ old->flags = 0 ;
+ if (r) old->flags |= SKASA_MASKALL ;
+ if (saold.sa_flags & SA_NOCLDSTOP) old->flags |= SKASA_NOCLDSTOP ;
+ old->handler = saold.sa_handler ;
+ }
+ return 0 ;
+}
diff --git a/src/libstddjb/slurp.c b/src/libstddjb/slurp.c
new file mode 100644
index 0000000..553b29e
--- /dev/null
+++ b/src/libstddjb/slurp.c
@@ -0,0 +1,31 @@
+/* ISC license. */
+
+#include <skalibs/allreadwrite.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+
+#define N 4096
+
+int slurp (stralloc *sa, int fd)
+{
+ register unsigned int salen = sa->len ;
+ for (;;)
+ {
+ int r ;
+ if (!stralloc_readyplus(sa, N)) break ;
+ r = fd_read(fd, sa->s + sa->len, N) ;
+ switch (r)
+ {
+ case -1: goto err ;
+ case 0:
+ stralloc_shrink(sa) ;
+ return 1 ;
+ default:
+ sa->len += r ;
+ }
+ }
+err:
+ sa->len = salen ;
+ stralloc_shrink(sa) ;
+ return 0 ;
+}
diff --git a/src/libstddjb/socket_accept4.c b/src/libstddjb/socket_accept4.c
new file mode 100644
index 0000000..e504375
--- /dev/null
+++ b/src/libstddjb/socket_accept4.c
@@ -0,0 +1,39 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/socket.h>
+
+int socket_accept4_internal (int s, char *ip, uint16 *port, unsigned int options)
+{
+ struct sockaddr_in sa ;
+ socklen_t dummy = sizeof sa ;
+ register int fd ;
+ do
+#ifdef SKALIBS_HASACCEPT4
+ fd = accept4(s, (struct sockaddr *)&sa, &dummy, ((options & DJBUNIX_FLAG_NB) ? SOCK_NONBLOCK : 0) | ((options & DJBUNIX_FLAG_COE) ? SOCK_CLOEXEC : 0)) ;
+#else
+ fd = accept(s, (struct sockaddr *)&sa, &dummy) ;
+#endif
+ while ((fd < 0) && (errno == EINTR)) ;
+ if (fd < 0) return -1 ;
+#ifndef SKALIBS_HASACCEPT4
+ if ((((options & DJBUNIX_FLAG_NB) ? ndelay_on(fd) : ndelay_off(fd)) < 0)
+ || (((options & DJBUNIX_FLAG_COE) ? coe(fd) : uncoe(fd)) < 0))
+ {
+ register int e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ return -1 ;
+ }
+#endif
+ byte_copy(ip, 4, (char *)&sa.sin_addr.s_addr) ;
+ uint16_unpack_big((char *)&sa.sin_port, port) ;
+ return fd ;
+}
diff --git a/src/libstddjb/socket_accept4_u32.c b/src/libstddjb/socket_accept4_u32.c
new file mode 100644
index 0000000..18455fc
--- /dev/null
+++ b/src/libstddjb/socket_accept4_u32.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/socket.h>
+
+int socket_accept4_internal_u32 (int s, uint32 *ip, uint16 *port, unsigned int options)
+{
+ char pack[4] ;
+ register int r = socket_accept4_internal(s, pack, port, options) ;
+ if (r >= 0) uint32_unpack_big(pack, ip) ;
+ return r ;
+}
diff --git a/src/libstddjb/socket_accept6.c b/src/libstddjb/socket_accept6.c
new file mode 100644
index 0000000..8e87e46
--- /dev/null
+++ b/src/libstddjb/socket_accept6.c
@@ -0,0 +1,55 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/ip46.h>
+#include <skalibs/socket.h>
+
+#ifdef SKALIBS_IPV6_ENABLED
+
+int socket_accept6_internal (int s, char *ip6, uint16 *port, unsigned int options)
+{
+ struct sockaddr_in6 sa ;
+ socklen_t dummy = sizeof sa ;
+ register int fd ;
+ do
+#ifdef SKALIBS_HASACCEPT4
+ fd = accept4(s, (struct sockaddr *)&sa, &dummy, ((options & DJBUNIX_FLAG_NB) ? SOCK_NONBLOCK : 0) | ((options & DJBUNIX_FLAG_COE) ? SOCK_CLOEXEC : 0)) ;
+#else
+ fd = accept(s, (struct sockaddr *)&sa, &dummy) ;
+#endif
+ while ((fd < 0) && (errno == EINTR)) ;
+ if (fd < 0) return -1 ;
+#ifndef SKALIBS_HASACCEPT4
+ if ((((options & DJBUNIX_FLAG_NB) ? ndelay_on(fd) : ndelay_off(fd)) < 0)
+ || (((options & DJBUNIX_FLAG_COE) ? coe(fd) : uncoe(fd)) < 0))
+ {
+ register int e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ return -1 ;
+ }
+#endif
+ byte_copy(ip6, 16, sa.sin6_addr.s6_addr) ;
+ uint16_unpack_big((char *)&sa.sin6_port, port) ;
+ return fd ;
+}
+
+#else
+
+int socket_accept6_internal (int s, char *ip6, uint16 *port, unsigned int options)
+{
+ (void)s ;
+ (void)ip6 ;
+ (void)port ;
+ (void)options ;
+ return (errno = ENOSYS, -1) ;
+}
+
+#endif
diff --git a/src/libstddjb/socket_bind4.c b/src/libstddjb/socket_bind4.c
new file mode 100644
index 0000000..e9c9593
--- /dev/null
+++ b/src/libstddjb/socket_bind4.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/socket.h>
+
+int socket_bind4 (int s, char const *ip, uint16 port)
+{
+ struct sockaddr_in sa ;
+ byte_zero(&sa, sizeof sa) ;
+ sa.sin_family = AF_INET ;
+ uint16_big_endian((char *)&port, 1) ;
+ sa.sin_port = port ;
+ byte_copy(&sa.sin_addr.s_addr, 4, ip) ;
+ return bind(s, (struct sockaddr *)&sa, sizeof sa) ;
+}
diff --git a/src/libstddjb/socket_bind4r.c b/src/libstddjb/socket_bind4r.c
new file mode 100644
index 0000000..55f0903
--- /dev/null
+++ b/src/libstddjb/socket_bind4r.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <skalibs/uint16.h>
+#include <skalibs/socket.h>
+
+int socket_bind4_reuse (int s, char const *ip, uint16 port)
+{
+ unsigned int opt = 1 ;
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt) ;
+ return socket_bind4(s, ip, port) ;
+}
diff --git a/src/libstddjb/socket_bind6.c b/src/libstddjb/socket_bind6.c
new file mode 100644
index 0000000..fa4cae1
--- /dev/null
+++ b/src/libstddjb/socket_bind6.c
@@ -0,0 +1,34 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/socket.h>
+#include <skalibs/ip46.h>
+
+#ifdef SKALIBS_IPV6_ENABLED
+
+int socket_bind6 (int s, char const *ip6, uint16 port)
+{
+ struct sockaddr_in6 sa ;
+ byte_zero(&sa, sizeof sa) ;
+ sa.sin6_family = AF_INET6 ;
+ uint16_pack_big((char *)&sa.sin6_port, port) ;
+ byte_copy(sa.sin6_addr.s6_addr, 16, ip6) ;
+ return bind(s, (struct sockaddr *)&sa, sizeof sa) ;
+}
+
+#else
+
+int socket_bind6 (int s, char const *ip6, uint16 port)
+{
+ (void)s ;
+ (void)ip6 ;
+ (void)port ;
+ return (errno = ENOSYS, -1) ;
+}
+
+#endif
diff --git a/src/libstddjb/socket_bind6r.c b/src/libstddjb/socket_bind6r.c
new file mode 100644
index 0000000..6bf5e0d
--- /dev/null
+++ b/src/libstddjb/socket_bind6r.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <skalibs/uint16.h>
+#include <skalibs/socket.h>
+
+int socket_bind6_reuse (int s, char const *ip6, uint16 port)
+{
+ unsigned int opt = 1 ;
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt) ;
+ return socket_bind6(s, ip6, port) ;
+}
diff --git a/src/libstddjb/socket_conn4.c b/src/libstddjb/socket_conn4.c
new file mode 100644
index 0000000..0180378
--- /dev/null
+++ b/src/libstddjb/socket_conn4.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/socket.h>
+
+int socket_connect4 (int s, char const *ip, uint16 port)
+{
+ struct sockaddr_in sa ;
+ register int r ;
+ byte_zero(&sa, sizeof sa) ;
+ sa.sin_family = AF_INET ;
+ uint16_big_endian((char *)&port, 1) ;
+ sa.sin_port = port ;
+ byte_copy(&sa.sin_addr.s_addr, 4, ip) ;
+ do r = connect(s, (struct sockaddr *)&sa, sizeof sa) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ if ((r == -1) && (errno == EALREADY)) errno = EINPROGRESS ;
+ return r ;
+}
diff --git a/src/libstddjb/socket_conn4_u32.c b/src/libstddjb/socket_conn4_u32.c
new file mode 100644
index 0000000..20887ce
--- /dev/null
+++ b/src/libstddjb/socket_conn4_u32.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/socket.h>
+
+int socket_connect4_u32 (int s, uint32 ip, uint16 port)
+{
+ char pack[4] ;
+ uint32_pack_big(pack, ip) ;
+ return socket_connect4(s, pack, port) ;
+}
diff --git a/src/libstddjb/socket_conn6.c b/src/libstddjb/socket_conn6.c
new file mode 100644
index 0000000..49a64d1
--- /dev/null
+++ b/src/libstddjb/socket_conn6.c
@@ -0,0 +1,38 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/socket.h>
+#include <skalibs/ip46.h>
+
+#ifdef SKALIBS_IPV6_ENABLED
+
+int socket_connect6 (int s, char const *ip6, uint16 port)
+{
+ struct sockaddr_in6 sa ;
+ register int r ;
+ byte_zero(&sa, sizeof sa) ;
+ sa.sin6_family = AF_INET6 ;
+ uint16_pack_big((char *)&sa.sin6_port,port) ;
+ byte_copy(sa.sin6_addr.s6_addr, 16, ip6) ;
+ do r = connect(s, (struct sockaddr *)&sa, sizeof sa) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ if ((r == -1) && (errno == EALREADY)) errno = EINPROGRESS ;
+ return r ;
+}
+
+#else
+
+int socket_connect6 (int s, char const *ip6, uint16 port)
+{
+ (void)s ;
+ (void)ip6 ;
+ (void)port ;
+ return (errno = ENOSYS, -1) ;
+}
+
+#endif
diff --git a/src/libstddjb/socket_connected.c b/src/libstddjb/socket_connected.c
new file mode 100644
index 0000000..895eaf3
--- /dev/null
+++ b/src/libstddjb/socket_connected.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/socket.h>
+
+int socket_connected (int s)
+{
+ struct sockaddr_in sa ;
+ socklen_t dummy = sizeof sa ;
+ if (getpeername(s, (struct sockaddr *)&sa, &dummy) == -1)
+ {
+ char ch ;
+ fd_read(s, &ch, 1) ; /* sets errno */
+ return 0 ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/socket_deadlineconnstamp4.c b/src/libstddjb/socket_deadlineconnstamp4.c
new file mode 100644
index 0000000..618852f
--- /dev/null
+++ b/src/libstddjb/socket_deadlineconnstamp4.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/error.h>
+#include <skalibs/tai.h>
+#include <skalibs/socket.h>
+
+int socket_deadlineconnstamp (int s, char const *ip, uint16 port, tain_t const *deadline, tain_t *stamp)
+{
+ if (socket_connect4(s, ip, port) >= 0) return 1 ;
+ if (!error_isagain(errno) && !error_isalready(errno)) return 0 ;
+ return socket_waitconn(s, deadline, stamp) ;
+}
diff --git a/src/libstddjb/socket_deadlineconnstamp46.c b/src/libstddjb/socket_deadlineconnstamp46.c
new file mode 100644
index 0000000..4ab2c9a
--- /dev/null
+++ b/src/libstddjb/socket_deadlineconnstamp46.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/error.h>
+#include <skalibs/tai.h>
+#include <skalibs/socket.h>
+#include <skalibs/ip46.h>
+
+int socket_deadlineconnstamp46 (int s, ip46_t const *i, uint16 port, tain_t const *deadline, tain_t *stamp)
+{
+ if (socket_connect46(s, i, port) >= 0) return 1 ;
+ if (!error_isagain(errno) && !error_isalready(errno)) return 0 ;
+ return socket_waitconn(s, deadline, stamp) ;
+}
diff --git a/src/libstddjb/socket_deadlineconnstamp4_u32.c b/src/libstddjb/socket_deadlineconnstamp4_u32.c
new file mode 100644
index 0000000..4a82e50
--- /dev/null
+++ b/src/libstddjb/socket_deadlineconnstamp4_u32.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/tai.h>
+#include <skalibs/socket.h>
+
+int socket_deadlineconnstamp4_u32 (int s, uint32 ip, uint16 port, tain_t const *deadline, tain_t *stamp)
+{
+ char pack[4] ;
+ uint32_pack_big(pack, ip) ;
+ return socket_deadlineconnstamp4(s, pack, port, deadline, stamp) ;
+}
diff --git a/src/libstddjb/socket_deadlineconnstamp6.c b/src/libstddjb/socket_deadlineconnstamp6.c
new file mode 100644
index 0000000..a797d1e
--- /dev/null
+++ b/src/libstddjb/socket_deadlineconnstamp6.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/error.h>
+#include <skalibs/tai.h>
+#include <skalibs/socket.h>
+
+int socket_deadlineconnstamp6 (int s, char const *ip, uint16 port, tain_t const *deadline, tain_t *stamp)
+{
+ if (socket_connect6(s, ip, port) >= 0) return 1 ;
+ if (!error_isagain(errno) && !error_isalready(errno)) return 0 ;
+ return socket_waitconn(s, deadline, stamp) ;
+}
diff --git a/src/libstddjb/socket_delay.c b/src/libstddjb/socket_delay.c
new file mode 100644
index 0000000..7d1a8db
--- /dev/null
+++ b/src/libstddjb/socket_delay.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <skalibs/socket.h>
+
+int socket_tcpnodelay (int s)
+{
+ static int const opt = TCP_NODELAY ;
+ return setsockopt(s, IPPROTO_TCP, 1, &opt, sizeof(int)) ;
+}
diff --git a/src/libstddjb/socket_internal.c b/src/libstddjb/socket_internal.c
new file mode 100644
index 0000000..ae57e06
--- /dev/null
+++ b/src/libstddjb/socket_internal.c
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+#ifdef SKALIBS_HASACCEPT4
+
+int socket_internal (int domain, int type, int protocol, unsigned int flags)
+{
+ return socket(domain, type | ((flags & DJBUNIX_FLAG_NB) ? SOCK_NONBLOCK : 0) | ((flags & DJBUNIX_FLAG_COE) ? SOCK_CLOEXEC : 0), protocol) ;
+}
+
+#else
+
+int socket_internal (int domain, int type, int protocol, unsigned int flags)
+{
+ int s = socket(domain, type, protocol) ;
+ if (s == -1) return -1 ;
+ if ((((flags & DJBUNIX_FLAG_NB) ? ndelay_on(s) : ndelay_off(s)) < 0)
+ || (((flags & DJBUNIX_FLAG_COE) ? coe(s) : uncoe(s)) < 0))
+ {
+ register int e = errno ;
+ fd_close(s) ;
+ errno = e ;
+ return -1 ;
+ }
+ return s ;
+}
+
+#endif
diff --git a/src/libstddjb/socket_ioloop.c b/src/libstddjb/socket_ioloop.c
new file mode 100644
index 0000000..a158f01
--- /dev/null
+++ b/src/libstddjb/socket_ioloop.c
@@ -0,0 +1,30 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/error.h>
+#include <skalibs/uint16.h>
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+#include <skalibs/socket.h>
+
+int socket_ioloop (int s, char *buf, unsigned int len, char *ip, uint16 *port, socket_io_func_t_ref f, int w, tain_t const *deadline, tain_t *stamp)
+{
+ iopause_fd x = { .fd = s, .events = w ? IOPAUSE_WRITE : IOPAUSE_READ, .revents = 0 } ;
+ for (;;)
+ {
+ register int r = iopause_stamp(&x, 1, deadline, stamp) ;
+ if (r < 0) return -1 ;
+ if (!r) return (errno = ETIMEDOUT, -1) ;
+ if (x.revents & IOPAUSE_EXCEPT) return (errno = EIO, -1) ;
+ if (x.revents & x.events)
+ {
+ r = (*f)(s, buf, len, ip, port) ;
+ if (r < 0)
+ {
+ if (!error_isagain(errno)) return -1 ;
+ }
+ else return r ;
+ }
+ }
+}
+
diff --git a/src/libstddjb/socket_ioloop_send4.c b/src/libstddjb/socket_ioloop_send4.c
new file mode 100644
index 0000000..aff251d
--- /dev/null
+++ b/src/libstddjb/socket_ioloop_send4.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/socket.h>
+
+int socket_ioloop_send4 (int fd, char *s, unsigned int len, char *ip, uint16 *port)
+{
+ return socket_send4(fd, s, len, ip, *port) ;
+}
diff --git a/src/libstddjb/socket_ioloop_send6.c b/src/libstddjb/socket_ioloop_send6.c
new file mode 100644
index 0000000..151a58c
--- /dev/null
+++ b/src/libstddjb/socket_ioloop_send6.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/socket.h>
+
+int socket_ioloop_send6 (int fd, char *s, unsigned int len, char *ip, uint16 *port)
+{
+ return socket_send6(fd, s, len, ip, *port) ;
+}
diff --git a/src/libstddjb/socket_local4.c b/src/libstddjb/socket_local4.c
new file mode 100644
index 0000000..90ae93a
--- /dev/null
+++ b/src/libstddjb/socket_local4.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/socket.h>
+
+int socket_local4 (int s, char *ip, uint16 *port)
+{
+ struct sockaddr_in sa ;
+ socklen_t dummy = sizeof sa ;
+
+ if (getsockname(s, (struct sockaddr *)&sa, &dummy) == -1)
+ return -1 ;
+ byte_copy(ip, 4, (char *)&sa.sin_addr.s_addr) ;
+ uint16_unpack_big((char *)&sa.sin_port, port) ;
+ return 0 ;
+}
diff --git a/src/libstddjb/socket_local46.c b/src/libstddjb/socket_local46.c
new file mode 100644
index 0000000..a53bcac
--- /dev/null
+++ b/src/libstddjb/socket_local46.c
@@ -0,0 +1,36 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/ip46.h>
+
+#ifdef SKALIBS_IPV6_ENABLED
+
+int socket_local46 (int s, ip46_t_ref ip, uint16 *port)
+{
+ struct sockaddr sa ;
+ socklen_t dummy = sizeof sa ;
+ if (getsockname(s, &sa, &dummy) < 0) return -1 ;
+ if (sa.sa_family == AF_INET6)
+ {
+ register struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&sa ;
+ byte_copy(ip->ip, 16, sa6->sin6_addr.s6_addr) ;
+ uint16_unpack_big((char *)&sa6->sin6_port, port) ;
+ ip->is6 = 1 ;
+ }
+ else if (sa.sa_family == AF_INET)
+ {
+ register struct sockaddr_in *sa4 = (struct sockaddr_in *)&sa ;
+ byte_copy(ip->ip, 4, &sa4->sin_addr.s_addr) ;
+ uint16_unpack_big((char *)&sa4->sin_port, port) ;
+ ip->is6 = 0 ;
+ }
+ else return (errno = EAFNOSUPPORT, -1) ;
+ return 0 ;
+}
+
+#endif
diff --git a/src/libstddjb/socket_local6.c b/src/libstddjb/socket_local6.c
new file mode 100644
index 0000000..31ee1f0
--- /dev/null
+++ b/src/libstddjb/socket_local6.c
@@ -0,0 +1,37 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/socket.h>
+#include <skalibs/ip46.h>
+
+#ifdef SKALIBS_IPV6_ENABLED
+
+int socket_local6 (int s, char *ip, uint16 *port)
+{
+ struct sockaddr_in6 sa ;
+ socklen_t dummy = sizeof sa ;
+
+ if (getsockname(s, (struct sockaddr *)&sa, &dummy) == -1)
+ return -1 ;
+ byte_copy(ip, 16, sa.sin6_addr.s6_addr) ;
+ uint16_unpack_big((char *)&sa.sin6_port, port) ;
+ return 0 ;
+}
+
+#else
+
+#include <errno.h>
+
+int socket_local6 (int s, char *ip, uint16 *port)
+{
+ (void)s ;
+ (void)ip ;
+ (void)port ;
+ return (errno = ENOSYS, -1) ;
+}
+
+#endif
diff --git a/src/libstddjb/socket_recv4.c b/src/libstddjb/socket_recv4.c
new file mode 100644
index 0000000..02354e9
--- /dev/null
+++ b/src/libstddjb/socket_recv4.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/socket.h>
+
+int socket_recv4 (int s, char *buf, unsigned int len, char *ip, uint16 *port)
+{
+ struct sockaddr_in sa ;
+ socklen_t dummy = sizeof sa ;
+ register int r ;
+ do r = recvfrom(s, buf, len, 0, (struct sockaddr *)&sa, &dummy) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ if (r == -1) return -1 ;
+ byte_copy(ip, 4, (char *)&sa.sin_addr) ;
+ uint16_unpack_big((char *)&sa.sin_port, port) ;
+ return r ;
+}
diff --git a/src/libstddjb/socket_recv6.c b/src/libstddjb/socket_recv6.c
new file mode 100644
index 0000000..d745604
--- /dev/null
+++ b/src/libstddjb/socket_recv6.c
@@ -0,0 +1,39 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/ip46.h>
+#include <skalibs/socket.h>
+
+#ifdef SKALIBS_IPV6_ENABLED
+
+int socket_recv6 (int s, char *buf, unsigned int len, char *ip6, uint16 *port)
+{
+ struct sockaddr_in6 sa ;
+ socklen_t dummy = sizeof sa ;
+ register int r ;
+ do r = recvfrom(s, buf, len, 0, (struct sockaddr *)&sa, &dummy) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ if (r == -1) return -1 ;
+ byte_copy(ip6, 16, sa.sin6_addr.s6_addr) ;
+ uint16_unpack_big((char *)&sa.sin6_port, port) ;
+ return r ;
+}
+
+#else
+
+int socket_recv6 (int s, char *buf, unsigned int len, char *ip6, uint16 *port)
+{
+ (void)s ;
+ (void)buf ;
+ (void)len ;
+ (void)ip6 ;
+ (void)port ;
+ return (errno = ENOSYS, -1) ;
+}
+
+#endif
diff --git a/src/libstddjb/socket_remote4.c b/src/libstddjb/socket_remote4.c
new file mode 100644
index 0000000..767a694
--- /dev/null
+++ b/src/libstddjb/socket_remote4.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/socket.h>
+
+int socket_remote4 (int s, char *ip, uint16 *port)
+{
+ struct sockaddr_in sa ;
+ socklen_t dummy = sizeof sa ;
+
+ if (getpeername(s, (struct sockaddr *)&sa, &dummy) == -1)
+ return -1 ;
+ byte_copy(ip, 4, (char *)&sa.sin_addr.s_addr) ;
+ uint16_unpack_big((char *)&sa.sin_port, port) ;
+ return 0 ;
+}
diff --git a/src/libstddjb/socket_remote46.c b/src/libstddjb/socket_remote46.c
new file mode 100644
index 0000000..835b7c9
--- /dev/null
+++ b/src/libstddjb/socket_remote46.c
@@ -0,0 +1,36 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/ip46.h>
+
+#ifdef SKALIBS_IPV6_ENABLED
+
+int socket_remote46 (int s, ip46_t_ref ip, uint16 *port)
+{
+ struct sockaddr sa ;
+ socklen_t dummy = sizeof sa ;
+ if (getpeername(s, &sa, &dummy) < 0) return -1 ;
+ if (sa.sa_family == AF_INET6)
+ {
+ register struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&sa ;
+ byte_copy(ip->ip, 16, sa6->sin6_addr.s6_addr) ;
+ uint16_unpack_big((char *)&sa6->sin6_port, port) ;
+ ip->is6 = 1 ;
+ }
+ else if (sa.sa_family == AF_INET)
+ {
+ register struct sockaddr_in *sa4 = (struct sockaddr_in *)&sa ;
+ byte_copy(ip->ip, 4, &sa4->sin_addr.s_addr) ;
+ uint16_unpack_big((char *)&sa4->sin_port, port) ;
+ ip->is6 = 0 ;
+ }
+ else return (errno = EAFNOSUPPORT, -1) ;
+ return 0 ;
+}
+
+#endif
diff --git a/src/libstddjb/socket_remote6.c b/src/libstddjb/socket_remote6.c
new file mode 100644
index 0000000..9d40d70
--- /dev/null
+++ b/src/libstddjb/socket_remote6.c
@@ -0,0 +1,36 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/ip46.h>
+#include <skalibs/socket.h>
+
+#ifdef SKALIBS_IPV6_ENABLED
+
+int socket_remote6 (int s, char *ip, uint16 *port)
+{
+ struct sockaddr_in6 sa ;
+ socklen_t dummy = sizeof sa ;
+
+ if (getpeername(s, (struct sockaddr *)&sa, &dummy) == -1)
+ return -1 ;
+ byte_copy(ip, 16, sa.sin6_addr.s6_addr) ;
+ uint16_unpack_big((char *)&sa.sin6_port, port) ;
+ return 0 ;
+}
+
+#else
+
+int socket_remote6 (int s, char *ip, uint16 *port)
+{
+ (void)s ;
+ (void)ip ;
+ (void)port ;
+ return (errno = ENOSYS, -1) ;
+}
+
+#endif
diff --git a/src/libstddjb/socket_send4.c b/src/libstddjb/socket_send4.c
new file mode 100644
index 0000000..6078dff
--- /dev/null
+++ b/src/libstddjb/socket_send4.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/socket.h>
+
+int socket_send4 (int s, char const *buf, unsigned int len, char const *ip, uint16 port)
+{
+ struct sockaddr_in sa ;
+ register int r ;
+ byte_zero((char *)&sa, sizeof sa) ;
+ sa.sin_family = AF_INET ;
+ uint16_pack_big((char *)&sa.sin_port, port) ;
+ byte_copy((char *)&sa.sin_addr, 4, ip) ;
+ do r = sendto(s, buf, len, 0, (struct sockaddr *)&sa, sizeof sa) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/socket_send6.c b/src/libstddjb/socket_send6.c
new file mode 100644
index 0000000..01319a1
--- /dev/null
+++ b/src/libstddjb/socket_send6.c
@@ -0,0 +1,39 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/ip46.h>
+#include <skalibs/socket.h>
+
+#ifdef SKALIBS_IPV6_ENABLED
+
+int socket_send6 (int s, char const *buf, unsigned int len, char const *ip6, uint16 port)
+{
+ struct sockaddr_in6 sa ;
+ register int r ;
+ byte_zero((char *)&sa, sizeof sa) ;
+ sa.sin6_family = AF_INET6 ;
+ uint16_pack_big((char *)&sa.sin6_port, port) ;
+ byte_copy(sa.sin6_addr.s6_addr, 16, ip6) ;
+ do r = sendto(s, buf, len, 0, (struct sockaddr *)&sa, sizeof sa) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
+
+#else
+
+int socket_send6 (int s, char const *buf, unsigned int len, char const *ip6, uint16 port)
+{
+ (void)s ;
+ (void)buf ;
+ (void)len ;
+ (void)ip6 ;
+ (void)port ;
+ return (errno = ENOSYS, -1) ;
+}
+
+#endif
diff --git a/src/libstddjb/socket_tcp4.c b/src/libstddjb/socket_tcp4.c
new file mode 100644
index 0000000..8eecb67
--- /dev/null
+++ b/src/libstddjb/socket_tcp4.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <skalibs/socket.h>
+
+int socket_tcp4_internal (unsigned int flags)
+{
+ return socket_internal(AF_INET, SOCK_STREAM, 0, flags) ;
+}
diff --git a/src/libstddjb/socket_tcp6.c b/src/libstddjb/socket_tcp6.c
new file mode 100644
index 0000000..fd282fc
--- /dev/null
+++ b/src/libstddjb/socket_tcp6.c
@@ -0,0 +1,38 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/ip46.h>
+#include <skalibs/socket.h>
+
+#ifdef SKALIBS_IPV6_ENABLED
+
+int socket_tcp6_internal (unsigned int flags)
+{
+ int fd = socket_internal(AF_INET6, SOCK_STREAM, 0, flags) ;
+ if (fd < 0) return fd ;
+ {
+ int option = 1 ;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &option, sizeof(option)) < 0)
+ {
+ register int e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ return -1 ;
+ }
+ }
+ return fd ;
+}
+
+#else
+
+int socket_tcp6_internal (unsigned int flags)
+{
+ (void)flags ;
+ return (errno = ENOSYS, -1) ;
+}
+
+#endif
diff --git a/src/libstddjb/socket_timeoutconn.c b/src/libstddjb/socket_timeoutconn.c
new file mode 100644
index 0000000..ec7e251
--- /dev/null
+++ b/src/libstddjb/socket_timeoutconn.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include <skalibs/tai.h>
+#include <skalibs/socket.h>
+
+int socket_timeoutconn (int s, char const *ip, uint16 port, unsigned int timeout)
+{
+ tain_t stamp, deadline ;
+ tain_now(&stamp) ;
+ tain_addsec(&deadline, &stamp, timeout) ;
+ return socket_deadlineconnstamp4(s, ip, port, &deadline, &stamp) ;
+}
diff --git a/src/libstddjb/socket_tryr.c b/src/libstddjb/socket_tryr.c
new file mode 100644
index 0000000..6544c9d
--- /dev/null
+++ b/src/libstddjb/socket_tryr.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <skalibs/socket.h>
+
+void socket_tryreservein (int s, unsigned int size)
+{
+ while (size >= 1024)
+ {
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &size, sizeof size) == 0) return ;
+ size -= (size >> 5) ;
+ }
+}
diff --git a/src/libstddjb/socket_udp4.c b/src/libstddjb/socket_udp4.c
new file mode 100644
index 0000000..d6e8ead
--- /dev/null
+++ b/src/libstddjb/socket_udp4.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <skalibs/socket.h>
+
+int socket_udp4_internal (unsigned int flags)
+{
+ return socket_internal(AF_INET, SOCK_DGRAM, 0, flags) ;
+}
diff --git a/src/libstddjb/socket_udp6.c b/src/libstddjb/socket_udp6.c
new file mode 100644
index 0000000..41d395a
--- /dev/null
+++ b/src/libstddjb/socket_udp6.c
@@ -0,0 +1,38 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/ip46.h>
+#include <skalibs/socket.h>
+
+#ifdef SKALIBS_IPV6_ENABLED
+
+int socket_udp6_internal (unsigned int flags)
+{
+ int fd = socket_internal(AF_INET6, SOCK_DGRAM, 0, flags) ;
+ if (fd < 0) return fd ;
+ {
+ int option = 1 ;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &option, sizeof(option)) < 0)
+ {
+ register int e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ return -1 ;
+ }
+ }
+ return fd ;
+}
+
+#else
+
+int socket_udp6_internal (unsigned int flags)
+{
+ (void)flags ;
+ return (errno = ENOSYS, -1) ;
+}
+
+#endif
diff --git a/src/libstddjb/socket_waitconn.c b/src/libstddjb/socket_waitconn.c
new file mode 100644
index 0000000..6e5c352
--- /dev/null
+++ b/src/libstddjb/socket_waitconn.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+#include <skalibs/socket.h>
+
+int socket_waitconn (int s, tain_t const *deadline, tain_t *stamp)
+{
+ iopause_fd x = { s, IOPAUSE_WRITE, 0 } ;
+ for (;;)
+ {
+ register int r = iopause_stamp(&x, 1, deadline, stamp) ;
+ if (r < 0) return 0 ;
+ if (!r) return (errno = ETIMEDOUT, 0) ;
+ if (x.revents & IOPAUSE_WRITE) break ;
+ if (x.revents & IOPAUSE_EXCEPT)
+ {
+ fd_write(s, "", 1) ; /* sets errno */
+ return 0 ;
+ }
+ }
+ return socket_connected(s) ;
+}
diff --git a/src/libstddjb/socketpair_internal.c b/src/libstddjb/socketpair_internal.c
new file mode 100644
index 0000000..8e62bdf
--- /dev/null
+++ b/src/libstddjb/socketpair_internal.c
@@ -0,0 +1,56 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+#ifdef SKALIBS_HASACCEPT4
+
+int socketpair_internal (int domain, int type, int protocol, unsigned int flags, int *sv)
+{
+ return socketpair(domain, type | ((flags & DJBUNIX_FLAG_NB) ? SOCK_NONBLOCK : 0) | ((flags & DJBUNIX_FLAG_COE) ? SOCK_CLOEXEC : 0), protocol, sv) ;
+}
+
+#else
+
+int socketpair_internal (int domain, int type, int protocol, unsigned int flags, int *sv)
+{
+ int fd[2] ;
+ if (socketpair(domain, type, protocol, fd) < 0) return -1 ;
+ if (flags & DJBUNIX_FLAG_NB)
+ {
+ if (ndelay_on(fd[0]) < 0) goto err ;
+ if (ndelay_on(fd[1]) < 0) goto err ;
+ }
+ else
+ {
+ if (ndelay_off(fd[0]) < 0) goto err ;
+ if (ndelay_off(fd[1]) < 0) goto err ;
+ }
+ if (flags & DJBUNIX_FLAG_COE)
+ {
+ if (coe(fd[0]) < 0) goto err ;
+ if (coe(fd[1]) < 0) goto err ;
+ }
+ else
+ {
+ if (uncoe(fd[0]) < 0) goto err ;
+ if (uncoe(fd[1]) < 0) goto err ;
+ }
+ sv[0] = fd[0] ;
+ sv[1] = fd[1] ;
+ return 0 ;
+
+ err:
+ {
+ register int e = errno ;
+ fd_close(fd[1]) ;
+ fd_close(fd[0]) ;
+ errno = e ;
+ }
+ return -1 ;
+}
+
+#endif
diff --git a/src/libstddjb/stamp.c b/src/libstddjb/stamp.c
new file mode 100644
index 0000000..65becc6
--- /dev/null
+++ b/src/libstddjb/stamp.c
@@ -0,0 +1,7 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/tai.h>
+
+tain_t STAMP = TAIN_EPOCH ;
diff --git a/src/libstddjb/str_chr.c b/src/libstddjb/str_chr.c
new file mode 100644
index 0000000..ed55e50
--- /dev/null
+++ b/src/libstddjb/str_chr.c
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/bytestr.h>
+
+#ifndef SKALIBS_FLAG_REPLACE_LIBC
+
+#include <string.h>
+
+unsigned int str_chr (register char const *s, int c)
+{
+ register char *p = strchr(s, c) ;
+ return p ? (unsigned int)(p - s) : strlen(s) ;
+}
+
+#else
+
+unsigned int str_chr (register char const *s, int c)
+{
+ register char ch = c ;
+ register char const *t = s ;
+
+ for (;;)
+ {
+ if (!*t) break; if (*t == ch) break; ++t;
+ if (!*t) break; if (*t == ch) break; ++t;
+ if (!*t) break; if (*t == ch) break; ++t;
+ if (!*t) break; if (*t == ch) break; ++t;
+ }
+ return t - s ;
+}
+
+#endif
diff --git a/src/libstddjb/str_cpy.c b/src/libstddjb/str_cpy.c
new file mode 100644
index 0000000..179688c
--- /dev/null
+++ b/src/libstddjb/str_cpy.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+
+#ifdef SKALIBS_FLAG_REPLACE_LIBC
+
+#include <skalibs/bytestr.h>
+
+unsigned int str_copy (char *s, char const *t)
+{
+ register unsigned int len = 0 ;
+ while ((*s = *t)) (s++, t++, len++) ;
+ return len ;
+}
+
+#endif
diff --git a/src/libstddjb/str_diff.c b/src/libstddjb/str_diff.c
new file mode 100644
index 0000000..b85288a
--- /dev/null
+++ b/src/libstddjb/str_diff.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+
+#ifdef SKALIBS_FLAG_REPLACE_LIBC
+
+#include <skalibs/bytestr.h>
+
+int str_diff (register char const *s, register char const *t)
+{
+ register char x ;
+
+ for (;;)
+ {
+ x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+ x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+ x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+ x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+ }
+ return ((int)(unsigned int)(unsigned char) x)
+ - ((int)(unsigned int)(unsigned char) *t) ;
+}
+
+#endif
diff --git a/src/libstddjb/str_diffn.c b/src/libstddjb/str_diffn.c
new file mode 100644
index 0000000..28f37f6
--- /dev/null
+++ b/src/libstddjb/str_diffn.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/bytestr.h>
+
+#ifdef SKALIBS_FLAG_REPLACE_LIBC
+
+int str_diffn (register char const *s, register char const *t, register unsigned int len)
+{
+ while (len--)
+ {
+ if (*s != *t) return *s - *t ;
+ if (!*s) break ;
+ s++ ; t++ ;
+ }
+ return 0 ;
+}
+
+#endif
diff --git a/src/libstddjb/str_fmt.c b/src/libstddjb/str_fmt.c
new file mode 100644
index 0000000..1c14c70
--- /dev/null
+++ b/src/libstddjb/str_fmt.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/fmtscan.h>
+
+unsigned int str_fmt (register char *d, char const *s)
+{
+ return strn_fmt(d, s, str_len(s)) ;
+}
diff --git a/src/libstddjb/str_len.c b/src/libstddjb/str_len.c
new file mode 100644
index 0000000..4db2f4c
--- /dev/null
+++ b/src/libstddjb/str_len.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+
+#ifdef SKALIBS_FLAG_REPLACE_LIBC
+
+#include <skalibs/bytestr.h>
+
+unsigned int str_len (char const *s)
+{
+ register char const *t = s ;
+ for (;;)
+ {
+ if (!*t) return t - s; ++t;
+ if (!*t) return t - s; ++t;
+ if (!*t) return t - s; ++t;
+ if (!*t) return t - s; ++t;
+ }
+}
+
+#endif
diff --git a/src/libstddjb/str_rchr.c b/src/libstddjb/str_rchr.c
new file mode 100644
index 0000000..39a4822
--- /dev/null
+++ b/src/libstddjb/str_rchr.c
@@ -0,0 +1,28 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/bytestr.h>
+
+#ifndef SKALIBS_FLAG_REPLACE_LIBC
+
+#include <string.h>
+
+unsigned int str_rchr (register char const *s, int c)
+{
+ register char *p = strrchr(s, c) ;
+ return p ? (unsigned int)(p - s) : (unsigned int)strlen(s) ;
+}
+
+#else
+
+unsigned int str_rchr (register char const *s, int c)
+{
+ register char ch = c ;
+ register char const *t = s ;
+ register char const *u = 0 ;
+ for ( ; *t ; t++) if (*t == ch) u = t ;
+ if (!u) u = t ;
+ return u - s ;
+}
+
+#endif
diff --git a/src/libstddjb/str_start.c b/src/libstddjb/str_start.c
new file mode 100644
index 0000000..30396bd
--- /dev/null
+++ b/src/libstddjb/str_start.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+
+int str_start (register char const *s, register char const *t)
+{
+ register char x ;
+
+ for (;;)
+ {
+ x = *t++; if (!x) return 1; if (x != *s++) return 0;
+ x = *t++; if (!x) return 1; if (x != *s++) return 0;
+ x = *t++; if (!x) return 1; if (x != *s++) return 0;
+ x = *t++; if (!x) return 1; if (x != *s++) return 0;
+ }
+}
diff --git a/src/libstddjb/str_strn.c b/src/libstddjb/str_strn.c
new file mode 100644
index 0000000..7c2e425
--- /dev/null
+++ b/src/libstddjb/str_strn.c
@@ -0,0 +1,36 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/bytestr.h>
+
+#ifdef SKALIBS_FLAG_REPLACE_LIBC
+
+/* Very naive implementation, but it's small. */
+
+unsigned int str_strn (char const *haystack, unsigned int hlen, char const *needle, unsigned int nlen)
+{
+ register unsigned int i = 0 ;
+ if (!nlen) return 0 ;
+ if (hlen < nlen) return hlen ;
+ hlen -= nlen ;
+ for (; i <= hlen ; i++)
+ if (!byte_diff(haystack+i, nlen, needle)) return i ;
+ return hlen+nlen ;
+}
+
+#else
+
+#include <string.h>
+
+unsigned int str_strn (char const *haystack, unsigned int hlen, char const *needle, unsigned int nlen)
+{
+ char haystack2[hlen+1] ;
+ char needle2[nlen+1] ;
+ register char *p ;
+ byte_copy(haystack2, hlen, haystack) ; haystack2[hlen] = 0 ;
+ byte_copy(needle2, nlen, needle) ; needle2[nlen] = 0 ;
+ p = strstr(haystack2, needle2) ;
+ return p ? p - haystack2 : hlen ;
+}
+
+#endif
diff --git a/src/libstddjb/stralloc_append.c b/src/libstddjb/stralloc_append.c
new file mode 100644
index 0000000..a51db36
--- /dev/null
+++ b/src/libstddjb/stralloc_append.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+
+int stralloc_append (stralloc *sa, char c)
+{
+ return stralloc_catb(sa, &c, 1) ;
+}
diff --git a/src/libstddjb/stralloc_catb.c b/src/libstddjb/stralloc_catb.c
new file mode 100644
index 0000000..bb03405
--- /dev/null
+++ b/src/libstddjb/stralloc_catb.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+
+int stralloc_catb (stralloc *sa, char const *s, unsigned int n)
+{
+ if (!stralloc_readyplus(sa, n)) return 0 ;
+ byte_copy(sa->s + sa->len, n, s) ;
+ sa->len += n ;
+ return 1 ;
+}
diff --git a/src/libstddjb/stralloc_catv.c b/src/libstddjb/stralloc_catv.c
new file mode 100644
index 0000000..1649f4c
--- /dev/null
+++ b/src/libstddjb/stralloc_catv.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/siovec.h>
+#include <skalibs/stralloc.h>
+
+int stralloc_catv (stralloc *sa, siovec_t const *v, unsigned int n)
+{
+ register unsigned int i = 0 ;
+ {
+ unsigned int total = 0 ;
+ for (; i < n ; i++) total += v[i].len ;
+ if (!stralloc_readyplus(sa, total)) return 0 ;
+ }
+ for (i = 0 ; i < n ; i++)
+ {
+ byte_copy(sa->s + sa->len, v[i].len, v[i].s) ;
+ sa->len += v[i].len ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/stralloc_copyb.c b/src/libstddjb/stralloc_copyb.c
new file mode 100644
index 0000000..be2b397
--- /dev/null
+++ b/src/libstddjb/stralloc_copyb.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+
+int stralloc_copyb (stralloc *sa, char const *s, unsigned int n)
+{
+ if (!stralloc_ready(sa, n)) return 0 ;
+ byte_copy(sa->s, n, s) ;
+ sa->len = n ;
+ return 1 ;
+}
diff --git a/src/libstddjb/stralloc_free.c b/src/libstddjb/stralloc_free.c
new file mode 100644
index 0000000..889b2ca
--- /dev/null
+++ b/src/libstddjb/stralloc_free.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/alloc.h>
+#include <skalibs/stralloc.h>
+
+void stralloc_free (stralloc *sa)
+{
+ alloc_free(sa->s) ;
+ *sa = stralloc_zero ;
+}
diff --git a/src/libstddjb/stralloc_insertb.c b/src/libstddjb/stralloc_insertb.c
new file mode 100644
index 0000000..339ffff
--- /dev/null
+++ b/src/libstddjb/stralloc_insertb.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+
+int stralloc_insertb (stralloc *sa, unsigned int offset, char const *s, unsigned int n)
+{
+ if (offset > sa->len) return (errno = EINVAL, 0) ;
+ if (!stralloc_readyplus(sa, n)) return 0 ;
+ byte_copyr(sa->s + offset + n, sa->len - offset, sa->s + offset) ;
+ sa->len += n ;
+ byte_copyr(sa->s + offset, n, s) ;
+ return 1 ;
+}
diff --git a/src/libstddjb/stralloc_ready_tuned.c b/src/libstddjb/stralloc_ready_tuned.c
new file mode 100644
index 0000000..04e1a41
--- /dev/null
+++ b/src/libstddjb/stralloc_ready_tuned.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/alloc.h>
+#include <skalibs/stralloc.h>
+
+int stralloc_ready_tuned (stralloc *sa, unsigned int n, unsigned int base, unsigned int a, unsigned int b)
+{
+ register unsigned int t ;
+ if (!b) return (errno = EINVAL, 0) ;
+ t = n + base + a * n / b ;
+ if (t < n) return (errno = ERANGE, 0) ;
+ if (!sa->s)
+ {
+ sa->s = alloc(t) ;
+ if (!sa->s) return 0 ;
+ sa->a = t ;
+ }
+ else if (n > sa->a)
+ {
+ if (!alloc_re(&sa->s, sa->a, t)) return 0 ;
+ sa->a = t ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/stralloc_reverse.c b/src/libstddjb/stralloc_reverse.c
new file mode 100644
index 0000000..9ad29e7
--- /dev/null
+++ b/src/libstddjb/stralloc_reverse.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+
+void stralloc_reverse (stralloc *sa)
+{
+ register unsigned int i = 0 ;
+ for (; i < sa->len >> 1 ; i++)
+ {
+ char tmp = sa->s[i] ;
+ sa->s[i] = sa->s[sa->len - 1 - i] ;
+ sa->s[sa->len - 1 - i] = tmp ;
+ }
+}
diff --git a/src/libstddjb/stralloc_reverse_blocks.c b/src/libstddjb/stralloc_reverse_blocks.c
new file mode 100644
index 0000000..6a2e4b8
--- /dev/null
+++ b/src/libstddjb/stralloc_reverse_blocks.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+
+void stralloc_reverse_blocks (stralloc *sa, unsigned int size)
+{
+ register unsigned int n = sa->len / (size << 1) ;
+ register unsigned int i = 0 ;
+ char tmp[size] ;
+ for (; i < n ; i++)
+ {
+ byte_copy(tmp, size, sa->s + i * size) ;
+ byte_copy(sa->s + i * size, size, sa->s + (2*n - 1 - i) * size) ;
+ byte_copy(sa->s + (2*n - 1 - i) * size, size, tmp) ;
+ }
+}
diff --git a/src/libstddjb/stralloc_shrink.c b/src/libstddjb/stralloc_shrink.c
new file mode 100644
index 0000000..0dceca2
--- /dev/null
+++ b/src/libstddjb/stralloc_shrink.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/alloc.h>
+#include <skalibs/stralloc.h>
+
+int stralloc_shrink (stralloc *sa)
+{
+ if (sa->a > sa->len)
+ {
+ if (!alloc_re(&sa->s, sa->a, sa->len)) return 0 ;
+ sa->a = sa->len ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/stralloc_zero.c b/src/libstddjb/stralloc_zero.c
new file mode 100644
index 0000000..5c2185b
--- /dev/null
+++ b/src/libstddjb/stralloc_zero.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+
+stralloc const stralloc_zero = STRALLOC_ZERO ;
diff --git a/src/libstddjb/strerr.c b/src/libstddjb/strerr.c
new file mode 100644
index 0000000..ae70477
--- /dev/null
+++ b/src/libstddjb/strerr.c
@@ -0,0 +1,35 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/strerr.h>
+
+void strerr_warn (char const *x1, char const *x2, char const *x3, char const *x4, char const *x5, char const *x6, char const *x7, char const *x8, char const *x9, char const *x10, char const *se)
+{
+ int e = errno ;
+ if (x1) buffer_puts(buffer_2, x1) ;
+ if (x2) buffer_puts(buffer_2, x2) ;
+ if (x3) buffer_puts(buffer_2, x3) ;
+ if (x4) buffer_puts(buffer_2, x4) ;
+ if (x5) buffer_puts(buffer_2, x5) ;
+ if (x6) buffer_puts(buffer_2, x6) ;
+ if (x7) buffer_puts(buffer_2, x7) ;
+ if (x8) buffer_puts(buffer_2, x8) ;
+ if (x9) buffer_puts(buffer_2, x9) ;
+ if (x10) buffer_puts(buffer_2, x10) ;
+ if (se) buffer_puts(buffer_2, se) ;
+ buffer_putflush(buffer_2, "\n", 1) ;
+ errno = e ;
+}
+
+void strerr_die (int e, char const *x1, char const *x2, char const *x3, char const *x4, char const *x5, char const *x6, char const *x7, char const *x8, char const *x9, char const *x10, char const *se)
+{
+ strerr_warn(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, se) ;
+ _exit(e) ;
+
+ /* No, OpenBSD, this noreturn function does NOT return.
+ Please learn what _exit() does. */
+}
diff --git a/src/libstddjb/strerr_sys.c b/src/libstddjb/strerr_sys.c
new file mode 100644
index 0000000..46789d8
--- /dev/null
+++ b/src/libstddjb/strerr_sys.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/error.h>
+#include <skalibs/strerr.h>
+
+void strerr_warnsys (char const *x1, char const *x2, char const *x3, char const *x4, char const *x5, char const *x6, char const *x7, char const *x8, char const *x9, char const *x10)
+{
+ strerr_warn(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, error_str(errno)) ;
+}
+
+void strerr_diesys (int e, char const *x1, char const *x2, char const *x3, char const *x4, char const *x5, char const *x6, char const *x7, char const *x8, char const *x9, char const *x10)
+{
+ strerr_warnsys(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) ;
+ _exit(e) ;
+
+ /* No, OpenBSD, this noreturn function does NOT return.
+ Please learn what _exit() does. */
+}
diff --git a/src/libstddjb/string_format.c b/src/libstddjb/string_format.c
new file mode 100644
index 0000000..f81b03d
--- /dev/null
+++ b/src/libstddjb/string_format.c
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+
+int string_format (stralloc *sa, char const *vars, char const *format, char const *const *args)
+{
+ static unsigned char const tab[2][4] = { "1442", "4833" } ;
+ char class[256] = "3222222222222222222222222222222222222022222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222" ;
+ unsigned int varlen = str_len(vars) ;
+ unsigned int base = sa->len ;
+ int wasnull = !sa->s ;
+ unsigned int state = 0 ;
+
+ for (; state < varlen ; state++)
+ if (class[(unsigned char)vars[state]] == '2')
+ class[(unsigned char)vars[state]] = '1' ;
+ else return (errno = EINVAL, 0) ;
+
+ for (state = 0 ; state < 2 ; format++)
+ {
+ unsigned char c = tab[state][class[(unsigned char)(*format)] - '0'] ;
+ state = c & 3 ;
+ if (c & 4) if (!stralloc_catb(sa, format, 1)) goto err ;
+ if (c & 8) if (!stralloc_cats(sa, args[byte_chr(vars, varlen, *format)])) goto err ;
+ }
+ if (state == 2) return 1 ;
+ errno = EINVAL ;
+ err:
+ if (wasnull) stralloc_free(sa) ; else sa->len = base ;
+ return 0 ;
+}
diff --git a/src/libstddjb/string_quote.c b/src/libstddjb/string_quote.c
new file mode 100644
index 0000000..ed00402
--- /dev/null
+++ b/src/libstddjb/string_quote.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/skamisc.h>
+
+int string_quote (stralloc *sa, char const *s, unsigned int len)
+{
+ unsigned int base = sa->len ;
+ int wasnull = !sa->s ;
+ if (!stralloc_catb(sa, "\"", 1)) return 0 ;
+ if (!string_quote_nodelim(sa, s, len) || !stralloc_catb(sa, "\"", 1))
+ {
+ if (wasnull) stralloc_free(sa) ; else sa->len = base ;
+ return 0 ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/string_quote_nodelim.c b/src/libstddjb/string_quote_nodelim.c
new file mode 100644
index 0000000..dfe41ce
--- /dev/null
+++ b/src/libstddjb/string_quote_nodelim.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/skamisc.h>
+
+int string_quote_nodelim (stralloc *sa, char const *s, unsigned int len)
+{
+ return string_quote_nodelim_mustquote(sa, s, len, "\"", 1) ;
+}
diff --git a/src/libstddjb/string_quote_nodelim_mustquote.c b/src/libstddjb/string_quote_nodelim_mustquote.c
new file mode 100644
index 0000000..e52bce3
--- /dev/null
+++ b/src/libstddjb/string_quote_nodelim_mustquote.c
@@ -0,0 +1,62 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/fmtscan.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/skamisc.h>
+
+int string_quote_nodelim_mustquote (stralloc *sa, char const *s, unsigned int len, char const *delim, unsigned int delimlen)
+{
+ char class[256] = "dddddddaaaaaaaddddddddddddddddddcccccccccccccccceeeeeeeeeeccccccccccccccccccccccccccccccccccbcccceeeeeecccccccecccececececcccccddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" ;
+
+ unsigned int base = sa->len ;
+ unsigned int i = 0 ;
+ int wasnull = !sa->s ;
+
+ for (; i < delimlen ; i++)
+ if (class[(unsigned char)delim[i]] == 'c')
+ class[(unsigned char)delim[i]] = 'b' ;
+ else return (errno = EINVAL, 0) ;
+
+ for (i = 0 ; i < len ; i++)
+ {
+ switch (class[(unsigned char)s[i]])
+ {
+ case 'a' :
+ {
+ static char const tab[7] = "abtnvfr" ;
+ char fmt[2] = "\\" ;
+ fmt[1] = tab[s[i] - 7] ;
+ if (!stralloc_catb(sa, fmt, 2)) goto err ;
+ break ;
+ }
+ case 'b' :
+ {
+ char fmt[2] = "\\" ;
+ fmt[1] = s[i] ;
+ if (!stralloc_catb(sa, fmt, 2)) goto err ;
+ break ;
+ }
+ case 'c' :
+ case 'e' :
+ {
+ if (!stralloc_catb(sa, s+i, 1)) goto err ;
+ break ;
+ }
+ case 'd' :
+ {
+ char fmt[5] = "\\0x" ;
+ ucharn_fmt(fmt+3, s+i, 1) ;
+ if (!stralloc_catb(sa, fmt, 5)) goto err ;
+ break ;
+ }
+ default : errno = EFAULT ; goto err ; /* can't happen */
+ }
+ }
+ return 1 ;
+
+ err:
+ if (wasnull) stralloc_free(sa) ; else sa->len = base ;
+ return 0 ;
+}
diff --git a/src/libstddjb/string_unquote.c b/src/libstddjb/string_unquote.c
new file mode 100644
index 0000000..f4482ff
--- /dev/null
+++ b/src/libstddjb/string_unquote.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/skamisc.h>
+
+int string_unquote (char *d, unsigned int *w, char const *s, unsigned int len, unsigned int *r)
+{
+ if (!len-- || (*s++ != '"')) return (errno = EINVAL, 0) ;
+ {
+ unsigned int rr, ww ;
+ char tmp[len] ;
+ if (!string_unquote_withdelim(tmp, &ww, s, len, &rr, "\"", 1)) return 0 ;
+ if (rr == len) return (errno = EPIPE, 0) ;
+ byte_copy(d, ww, tmp) ;
+ *w = ww ;
+ *r = rr + 2 ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/string_unquote_nodelim.c b/src/libstddjb/string_unquote_nodelim.c
new file mode 100644
index 0000000..1dc90f1
--- /dev/null
+++ b/src/libstddjb/string_unquote_nodelim.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/skamisc.h>
+
+int string_unquote_nodelim (char *d, char const *s, unsigned int len)
+{
+ unsigned int rr, ww ;
+ if (!string_unquote_withdelim(d, &ww, s, len, &rr, 0, 0)) return -1 ;
+ return (int)ww ;
+}
diff --git a/src/libstddjb/string_unquote_withdelim.c b/src/libstddjb/string_unquote_withdelim.c
new file mode 100644
index 0000000..dd52dbd
--- /dev/null
+++ b/src/libstddjb/string_unquote_withdelim.c
@@ -0,0 +1,60 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/error.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/fmtscan.h>
+#include <skalibs/skamisc.h>
+
+#define PUSH0 0x40
+#define PUSH 0x20
+#define PUSHSPEC 0x10
+#define STORE 0x08
+#define CALC 0x04
+#define SYNTAXERROR 0x02
+#define BROKENPIPE 0x01
+
+int string_unquote_withdelim (char *d, unsigned int *w, char const *s, unsigned int len, unsigned int *r, char const *delim, unsigned int delimlen)
+{
+ register unsigned int i = 0 ;
+ static unsigned char const actions[5][9] =
+ {
+ { 0, 0, PUSH, PUSH, PUSH, PUSH, PUSH, PUSH, 0 },
+ { PUSH, PUSH, 0, PUSH, PUSHSPEC, PUSH, PUSHSPEC, PUSH, BROKENPIPE },
+ { PUSH0, PUSH0, PUSH0|PUSH, 0, PUSH0|PUSH, PUSH0|PUSH, PUSH0|PUSH, PUSH0|PUSH, PUSH0 },
+ { SYNTAXERROR, SYNTAXERROR, STORE, SYNTAXERROR, STORE, STORE, SYNTAXERROR, SYNTAXERROR, BROKENPIPE },
+ { SYNTAXERROR, SYNTAXERROR, CALC, SYNTAXERROR, CALC, CALC, SYNTAXERROR, SYNTAXERROR, BROKENPIPE }
+ } ;
+ static unsigned char const states[5][9] =
+ {
+ { 1, 5, 0, 0, 0, 0, 0, 0, 5 },
+ { 0, 0, 2, 0, 0, 0, 0, 0, 6 },
+ { 1, 5, 0, 3, 0, 0, 0, 0, 5 },
+ { 6, 6, 4, 6, 4, 4, 6, 6, 6 },
+ { 6, 6, 0, 6, 0, 0, 6, 6, 6 }
+ } ;
+ unsigned char class[256] = "7777777777777777777777777777777777777777777777772555555555777777777777777777777777777777777707777445554777777767776767673777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777" ;
+ unsigned char store = 0 ;
+ unsigned char state = 0 ;
+ for (; i < delimlen ; i++)
+ if (class[(unsigned char)delim[i]] == '7')
+ class[(unsigned char)delim[i]] = '1' ;
+ else return (errno = EINVAL, 0) ;
+ *w = 0 ;
+
+ for (i = 0 ; state < 5 ; i++)
+ {
+ unsigned char c = i < len ? class[(unsigned char)s[i]] - '0' : 8 ;
+ unsigned char action = actions[state][c] ;
+ state = states[state][c] ;
+ if (action & PUSH0) d[(*w)++] = 0 ;
+ if (action & PUSH) d[(*w)++] = s[i] ;
+ if (action & PUSHSPEC) d[(*w)++] = 7 + byte_chr("abtnvfr", 7, s[i]) ;
+ if (action & STORE) store = fmtscan_num(s[i], 16) << 4 ;
+ if (action & CALC) d[(*w)++] = store | fmtscan_num(s[i], 16) ;
+ if (action & SYNTAXERROR) errno = EPROTO ;
+ if (action & BROKENPIPE) errno = EPIPE ;
+ }
+ *r = i - 1 ;
+ return (state == 5) ;
+}
diff --git a/src/libstddjb/strn_fmt.c b/src/libstddjb/strn_fmt.c
new file mode 100644
index 0000000..bbb9651
--- /dev/null
+++ b/src/libstddjb/strn_fmt.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <skalibs/fmtscan.h>
+#include <skalibs/uint.h>
+
+unsigned int strn_fmt (char *blah, register char const *s, unsigned int len)
+{
+ register char *d = blah ;
+ unsigned int i ;
+ for (i = 0 ; i < len ; i++)
+ if ((s[i] >= 32) && ((unsigned char)s[i] < 127)) *d++ = s[i] ;
+ else
+ {
+ *d++ = '\\' ;
+ *d++ = '0' ;
+ *d++ = 'x' ;
+ if ((unsigned char)s[i] < 16) *d++ = '0' ;
+ d += uint_xfmt(d, (unsigned char)s[i]) ;
+ }
+ return d - blah ;
+}
diff --git a/src/libstddjb/subgetopt.c b/src/libstddjb/subgetopt.c
new file mode 100644
index 0000000..69201c6
--- /dev/null
+++ b/src/libstddjb/subgetopt.c
@@ -0,0 +1,63 @@
+/* ISC license. */
+
+#undef SUBGETOPT_SHORT
+#include <skalibs/sgetopt.h>
+
+int subgetopt_r (int argc, char const *const *argv, char const *opts, subgetopt_t_ref o)
+{
+ o->arg = 0 ;
+ if ((o->ind >= argc) || !argv[o->ind]) return -1 ;
+ if (o->pos && !argv[o->ind][o->pos])
+ {
+ o->ind++ ;
+ o->pos = 0 ;
+ if ((o->ind >= argc) || !argv[o->ind]) return -1 ;
+ }
+
+ if (!o->pos)
+ {
+ if (argv[o->ind][0] != '-') return -1 ;
+ else
+ {
+ char c ;
+ o->pos++ ;
+ c = argv[o->ind][1] ;
+ if (c == '-') o->ind++ ;
+ if (!c || (c == '-'))
+ {
+ o->pos = 0 ;
+ return -1 ;
+ }
+ }
+ }
+ {
+ char c = argv[o->ind][o->pos++] ;
+ char const *s = opts ;
+ char retnoarg = (*s == ':') ? (s++, ':') : '?' ;
+ while (*s)
+ {
+ if (c == *s)
+ {
+ if (s[1] == ':')
+ {
+ o->arg = argv[o->ind++] + o->pos ;
+ o->pos = 0 ;
+ if (!*o->arg)
+ {
+ o->arg = argv[o->ind] ;
+ if ((o->ind >= argc) || !o->arg)
+ {
+ o->problem = c ;
+ return retnoarg ;
+ }
+ o->ind++ ;
+ }
+ }
+ return c ;
+ }
+ if (*++s == ':') s++ ;
+ }
+ o->problem = c ;
+ }
+ return '?' ;
+}
diff --git a/src/libstddjb/subgetopt_here.c b/src/libstddjb/subgetopt_here.c
new file mode 100644
index 0000000..e0be29a
--- /dev/null
+++ b/src/libstddjb/subgetopt_here.c
@@ -0,0 +1,7 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/sgetopt.h>
+
+subgetopt_t subgetopt_here = SUBGETOPT_ZERO ;
diff --git a/src/libstddjb/sysclock_from_localtm.c b/src/libstddjb/sysclock_from_localtm.c
new file mode 100644
index 0000000..6408fc8
--- /dev/null
+++ b/src/libstddjb/sysclock_from_localtm.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <time.h>
+#include <skalibs/uint64.h>
+#include <skalibs/djbtime.h>
+
+int sysclock_from_localtm (uint64 *uu, struct tm const *l)
+{
+ uint64 u ;
+ if (!ltm64_from_localtm(&u, l)) return 0 ;
+ if (!sysclock_from_ltm64(&u)) return 0 ;
+ *uu = u ;
+ return 1 ;
+}
diff --git a/src/libstddjb/sysclock_from_localtmn.c b/src/libstddjb/sysclock_from_localtmn.c
new file mode 100644
index 0000000..7b227d2
--- /dev/null
+++ b/src/libstddjb/sysclock_from_localtmn.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+#include <skalibs/djbtime.h>
+
+int sysclock_from_localtmn (tain_t *a, localtmn_t const *l)
+{
+ uint64 u ;
+ if (!sysclock_from_localtm(&u, &l->tm)) return 0 ;
+ tai_u64(&a->sec, u) ;
+ a->nano = l->nano ;
+ return 1 ;
+}
diff --git a/src/libstddjb/sysclock_from_ltm64.c b/src/libstddjb/sysclock_from_ltm64.c
new file mode 100644
index 0000000..a7e7a36
--- /dev/null
+++ b/src/libstddjb/sysclock_from_ltm64.c
@@ -0,0 +1,26 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/uint64.h>
+#include <skalibs/djbtime.h>
+
+#ifdef SKALIBS_FLAG_CLOCKISTAI
+
+#include <skalibs/tai.h>
+
+int sysclock_from_ltm64 (uint64 *u)
+{
+ tai_t t ;
+ if (!tai_from_ltm64(&t, *u)) return 0 ;
+ *u = t.x - 10U ;
+ return 1 ;
+}
+
+#else
+
+int sysclock_from_ltm64 (uint64 *u)
+{
+ return utc_from_sysclock(u) ;
+}
+
+#endif
diff --git a/src/libstddjb/sysclock_from_tai.c b/src/libstddjb/sysclock_from_tai.c
new file mode 100644
index 0000000..3db2640
--- /dev/null
+++ b/src/libstddjb/sysclock_from_tai.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/tai.h>
+
+#ifdef SKALIBS_FLAG_CLOCKISTAI
+
+int sysclock_from_tai (uint64 *u, tai_t const *t)
+{
+ *u = t->x - 10U ;
+ return 1 ;
+}
+
+#else
+
+#include <skalibs/djbtime.h>
+
+int sysclock_from_tai (uint64 *u, tai_t const *t)
+{
+ return utc_from_tai(u, t) ;
+}
+
+#endif
diff --git a/src/libstddjb/sysclock_from_utc.c b/src/libstddjb/sysclock_from_utc.c
new file mode 100644
index 0000000..25f9205
--- /dev/null
+++ b/src/libstddjb/sysclock_from_utc.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/uint64.h>
+#include <skalibs/djbtime.h>
+
+#ifdef SKALIBS_FLAG_CLOCKISTAI
+
+#include <skalibs/tai.h>
+
+int sysclock_from_utc (uint64 *u)
+{
+ tai_t t ;
+ if (!tai_from_utc(&t, *u)) return 0 ;
+ *u = t.x - 10 ;
+ return 1 ;
+}
+
+#else
+
+int sysclock_from_utc (uint64 *u)
+{
+ (void)u ;
+ return 1 ;
+}
+
+#endif
diff --git a/src/libstddjb/sysclock_get.c b/src/libstddjb/sysclock_get.c
new file mode 100644
index 0000000..3d14f96
--- /dev/null
+++ b/src/libstddjb/sysclock_get.c
@@ -0,0 +1,42 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/sysdeps.h>
+#include <skalibs/tai.h>
+
+#ifdef SKALIBS_FLAG_USERT
+# ifndef SKALIBS_HASCLOCKRT
+# undef SKALIBS_FLAG_USERT
+# warning "SKALIBS_FLAG_USERT set but SKALIBS_HASCLOCKRT not found. Clearing SKALIBS_FLAG_USERT."
+# endif
+#endif
+
+#ifdef SKALIBS_FLAG_USERT
+
+#include <time.h>
+
+int sysclock_get (tain_t *a)
+{
+ tain_t aa ;
+ struct timespec now ;
+ if (clock_gettime(CLOCK_REALTIME, &now) < 0) return 0 ;
+ if (!tain_from_timespec(&aa, &now)) return 0 ;
+ tain_add(a, &aa, &tain_nano500) ;
+ return 1 ;
+}
+
+#else
+
+#include <sys/time.h>
+
+int sysclock_get (tain_t *a)
+{
+ tain_t aa ;
+ struct timeval now ;
+ if (gettimeofday(&now, 0) < 0) return 0 ;
+ if (!tain_from_timeval(&aa, &now)) return 0 ;
+ tain_add(a, &aa, &tain_nano500) ;
+ return 1 ;
+}
+
+#endif
diff --git a/src/libstddjb/sysclock_set.c b/src/libstddjb/sysclock_set.c
new file mode 100644
index 0000000..0ec51c6
--- /dev/null
+++ b/src/libstddjb/sysclock_set.c
@@ -0,0 +1,53 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/config.h>
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_FLAG_USERT
+# ifndef SKALIBS_HASCLOCKRT
+# undef SKALIBS_FLAG_USERT
+# warning "SKALIBS_FLAG_USERT set but SKALIBS_HASCLOCKRT not found. Clearing SKALIBS_FLAG_USERT."
+# endif
+#endif
+
+#ifndef SKALIBS_FLAG_USERT
+# ifndef SKALIBS_HASSETTIMEOFDAY
+# error "SKALIBS_FLAG_USERT clear but SKALIBS_HASSETTIMEOFDAY not found. How do your set your system clock?"
+# endif
+#endif
+
+
+#ifdef SKALIBS_FLAG_USERT
+
+#include <time.h>
+#include <skalibs/tai.h>
+
+int sysclock_set (tain_t const *a)
+{
+ struct timespec now ;
+ tain_t aa ;
+ tain_add(&aa, a, &tain_nano500) ;
+ if (!timespec_from_tain(&now, &aa)) return 0 ;
+ if (clock_settime(CLOCK_REALTIME, &now) < 0) return 0 ;
+ return 1 ;
+}
+
+#else
+
+#include <skalibs/nonposix.h>
+#include <sys/time.h>
+#include <skalibs/tai.h>
+
+int sysclock_set (tain_t const *a)
+{
+ struct timeval now ;
+ tain_t aa ;
+ tain_add(&aa, a, &tain_nano500) ;
+ if (!timeval_from_tain(&now, &aa)) return 0 ;
+ if (settimeofday(&now, 0) < 0) return 0 ;
+ return 1 ;
+}
+
+#endif
diff --git a/src/libstddjb/tai_add.c b/src/libstddjb/tai_add.c
new file mode 100644
index 0000000..91af283
--- /dev/null
+++ b/src/libstddjb/tai_add.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+void tai_add (tai_t *t, tai_t const *u, tai_t const *v)
+{
+ tai_u64(t, tai_sec(u) + tai_sec(v)) ;
+}
diff --git a/src/libstddjb/tai_from_localtm.c b/src/libstddjb/tai_from_localtm.c
new file mode 100644
index 0000000..1f43070
--- /dev/null
+++ b/src/libstddjb/tai_from_localtm.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <time.h>
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbtime.h>
+
+int tai_from_localtm (tai_t *t, struct tm const *l)
+{
+ uint64 u ;
+ if (!ltm64_from_localtm(&u, l)) return 0 ;
+ return tai_from_ltm64(t, u) ;
+}
diff --git a/src/libstddjb/tai_from_ltm64.c b/src/libstddjb/tai_from_ltm64.c
new file mode 100644
index 0000000..2538c00
--- /dev/null
+++ b/src/libstddjb/tai_from_ltm64.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbtime.h>
+
+#ifdef SKALIBS_FLAG_TZISRIGHT
+
+int tai_from_ltm64 (tai_t *t, uint64 u)
+{
+ tai_u64(t, u + 10U) ;
+ return 1 ;
+}
+
+#else
+
+int tai_from_ltm64 (tai_t *t, uint64 u)
+{
+ return tai_from_utc(t, u) ;
+}
+
+#endif
diff --git a/src/libstddjb/tai_from_sysclock.c b/src/libstddjb/tai_from_sysclock.c
new file mode 100644
index 0000000..c2bb546
--- /dev/null
+++ b/src/libstddjb/tai_from_sysclock.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/tai.h>
+
+#ifdef SKALIBS_FLAG_CLOCKISTAI
+
+int tai_from_sysclock (tai_t *t, uint64 u)
+{
+ tai_u64(t, u + 10U) ;
+ return 1 ;
+}
+
+#else
+
+#include <skalibs/djbtime.h>
+
+int tai_from_sysclock (tai_t *t, uint64 u)
+{
+ return tai_from_utc(t, u) ;
+}
+
+#endif
diff --git a/src/libstddjb/tai_from_timespec.c b/src/libstddjb/tai_from_timespec.c
new file mode 100644
index 0000000..e9fbe3e
--- /dev/null
+++ b/src/libstddjb/tai_from_timespec.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <time.h>
+#include <skalibs/tai.h>
+
+int tai_from_timespec (tai_t *t, struct timespec const *ts)
+{
+ tai_unix(t, ts->tv_sec) ;
+ return 1 ;
+}
diff --git a/src/libstddjb/tai_from_timeval.c b/src/libstddjb/tai_from_timeval.c
new file mode 100644
index 0000000..41cf5a1
--- /dev/null
+++ b/src/libstddjb/tai_from_timeval.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <sys/time.h>
+#include <skalibs/tai.h>
+
+int tai_from_timeval (tai_t *t, struct timeval const *tv)
+{
+ tai_unix(t, tv->tv_sec) ;
+ return 1 ;
+}
diff --git a/src/libstddjb/tai_from_utc.c b/src/libstddjb/tai_from_utc.c
new file mode 100644
index 0000000..ba9cea9
--- /dev/null
+++ b/src/libstddjb/tai_from_utc.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbtime.h>
+#include "djbtime-internal.h"
+
+int tai_from_utc (tai_t *t, uint64 u)
+{
+ if (leapsecs_add(&u, 0) < 0) return 0 ;
+ u += 10 ;
+ t->x = u ;
+ return 1 ;
+}
diff --git a/src/libstddjb/tai_now.c b/src/libstddjb/tai_now.c
new file mode 100644
index 0000000..a1847ab
--- /dev/null
+++ b/src/libstddjb/tai_now.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <time.h>
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+
+int tai_now (tai_t *t)
+{
+ register uint64 u = TAI_MAGIC + time(0) ;
+ return tai_from_sysclock(t, u) ;
+}
diff --git a/src/libstddjb/tai_pack.c b/src/libstddjb/tai_pack.c
new file mode 100644
index 0000000..f81afe2
--- /dev/null
+++ b/src/libstddjb/tai_pack.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+
+void tai_pack (char *s, tai_t const *t)
+{
+ uint64_pack_big(s, tai_sec(t)) ;
+}
diff --git a/src/libstddjb/tai_pack_little.c b/src/libstddjb/tai_pack_little.c
new file mode 100644
index 0000000..41e552a
--- /dev/null
+++ b/src/libstddjb/tai_pack_little.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+
+void tai_pack_little (char *s, tai_t const *t)
+{
+ uint64_pack(s, tai_sec(t)) ;
+}
diff --git a/src/libstddjb/tai_relative_from_timespec.c b/src/libstddjb/tai_relative_from_timespec.c
new file mode 100644
index 0000000..34bb555
--- /dev/null
+++ b/src/libstddjb/tai_relative_from_timespec.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <time.h>
+#include <skalibs/tai.h>
+
+int tai_relative_from_timespec (tai_t *t, struct timespec const *ts)
+{
+ tai_u64(t, ts->tv_sec) ;
+ return 1 ;
+}
diff --git a/src/libstddjb/tai_relative_from_timeval.c b/src/libstddjb/tai_relative_from_timeval.c
new file mode 100644
index 0000000..f685da7
--- /dev/null
+++ b/src/libstddjb/tai_relative_from_timeval.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <sys/time.h>
+#include <skalibs/tai.h>
+
+int tai_relative_from_timeval (tai_t *t, struct timeval const *tv)
+{
+ tai_u64(t, tv->tv_sec) ;
+ return 1 ;
+}
diff --git a/src/libstddjb/tai_sub.c b/src/libstddjb/tai_sub.c
new file mode 100644
index 0000000..d0c879e
--- /dev/null
+++ b/src/libstddjb/tai_sub.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+void tai_sub (tai_t *t, tai_t const *u, tai_t const *v)
+{
+ tai_u64(t, tai_sec(u) - tai_sec(v)) ;
+}
diff --git a/src/libstddjb/tai_unpack.c b/src/libstddjb/tai_unpack.c
new file mode 100644
index 0000000..a733c4a
--- /dev/null
+++ b/src/libstddjb/tai_unpack.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+
+void tai_unpack (char const *s, tai_t *t)
+{
+ uint64_unpack_big(s, &t->x) ;
+}
diff --git a/src/libstddjb/tai_unpack_little.c b/src/libstddjb/tai_unpack_little.c
new file mode 100644
index 0000000..71804a5
--- /dev/null
+++ b/src/libstddjb/tai_unpack_little.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+
+void tai_unpack_little (char const *s, tai_t *t)
+{
+ uint64_unpack(s, &t->x) ;
+}
diff --git a/src/libstddjb/tain_add.c b/src/libstddjb/tain_add.c
new file mode 100644
index 0000000..6c6a237
--- /dev/null
+++ b/src/libstddjb/tain_add.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+void tain_add (tain_t *t, tain_t const *u, tain_t const *v)
+{
+ tai_add(&t->sec, &u->sec, &v->sec) ;
+ t->nano = u->nano + v->nano ;
+ if (t->nano > 999999999U)
+ {
+ t->nano -= 1000000000U ;
+ tai_u64(&t->sec, tai_sec(&t->sec)+1) ;
+ }
+}
diff --git a/src/libstddjb/tain_addsec.c b/src/libstddjb/tain_addsec.c
new file mode 100644
index 0000000..f4252a7
--- /dev/null
+++ b/src/libstddjb/tain_addsec.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+void tain_addsec (tain_t *b, tain_t const *a, int c)
+{
+ b->nano = a->nano ;
+ if (c >= 0)
+ {
+ tai_t t ;
+ tai_u64(&t, c) ;
+ tai_add(&b->sec, &a->sec, &t) ;
+ }
+ else
+ {
+ tai_t t ;
+ tai_u64(&t, -c) ;
+ tai_sub(&b->sec, &a->sec, &t) ;
+ }
+}
diff --git a/src/libstddjb/tain_approx.c b/src/libstddjb/tain_approx.c
new file mode 100644
index 0000000..d749cdf
--- /dev/null
+++ b/src/libstddjb/tain_approx.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+double tain_approx (tain_t const *t)
+{
+ return tai_approx(&t->sec) + tain_frac(t) ;
+}
diff --git a/src/libstddjb/tain_clockmon.c b/src/libstddjb/tain_clockmon.c
new file mode 100644
index 0000000..f14cd31
--- /dev/null
+++ b/src/libstddjb/tain_clockmon.c
@@ -0,0 +1,47 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/tai.h>
+
+#ifdef SKALIBS_HASCLOCKMON
+
+#include <time.h>
+
+int tain_clockmon_init (tain_t *offset)
+{
+ tain_t a, b ;
+ struct timespec ts ;
+ if (!tain_sysclock(&a)) return 0 ;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) return 0 ;
+ if (!tain_from_timespec(&b, &ts)) return 0 ;
+ tain_add(&a, &a, &tain_nano500) ;
+ tain_sub(offset, &a, &b) ;
+ return 1 ;
+}
+
+int tain_clockmon (tain_t *a, tain_t const *offset)
+{
+ struct timespec ts ;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) return 0 ;
+ if (!tain_from_timespec(a, &ts)) return 0 ;
+ tain_add(a, a, offset) ;
+ return 1 ;
+}
+
+#else
+
+#include <errno.h>
+
+int tain_clockmon_init (tain_t *offset)
+{
+ (void)offset ;
+ return (errno = ENOSYS, 0) ;
+}
+
+int tain_clockmon (tain_t *a, tain_t const *offset)
+{
+ (void)a ; (void)offset ;
+ return (errno = ENOSYS, 0) ;
+}
+
+#endif
diff --git a/src/libstddjb/tain_fmt.c b/src/libstddjb/tain_fmt.c
new file mode 100644
index 0000000..1fa04e3
--- /dev/null
+++ b/src/libstddjb/tain_fmt.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/fmtscan.h>
+#include <skalibs/tai.h>
+
+unsigned int tain_fmt (char *s, tain_t const *a)
+{
+ char pack[TAIN_PACK] ;
+ tain_pack(pack, a) ;
+ return ucharn_fmt(s, pack, TAIN_PACK) ;
+}
diff --git a/src/libstddjb/tain_frac.c b/src/libstddjb/tain_frac.c
new file mode 100644
index 0000000..45ee3b4
--- /dev/null
+++ b/src/libstddjb/tain_frac.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+double tain_frac (tain_t const *t)
+{
+ return t->nano * 0.000000001 ;
+}
diff --git a/src/libstddjb/tain_from_localtmn.c b/src/libstddjb/tain_from_localtmn.c
new file mode 100644
index 0000000..cc9bd19
--- /dev/null
+++ b/src/libstddjb/tain_from_localtmn.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+#include <skalibs/djbtime.h>
+
+int tain_from_localtmn (tain_t *a, localtmn_t const *l)
+{
+ tai_t t ;
+ if (!tai_from_localtm(&t, &l->tm)) return 0 ;
+ a->sec = t ;
+ a->nano = l->nano ;
+ return 1 ;
+}
diff --git a/src/libstddjb/tain_from_millisecs.c b/src/libstddjb/tain_from_millisecs.c
new file mode 100644
index 0000000..e6bfca4
--- /dev/null
+++ b/src/libstddjb/tain_from_millisecs.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/tai.h>
+
+int tain_from_millisecs (tain_t *a, int millisecs)
+{
+ if (millisecs < 0) return (errno = EINVAL, 0) ;
+ a->sec.x = millisecs / 1000 ;
+ a->nano = (millisecs % 1000) * 1000000U ;
+ return 1 ;
+}
diff --git a/src/libstddjb/tain_from_ntp.c b/src/libstddjb/tain_from_ntp.c
new file mode 100644
index 0000000..6bf7697
--- /dev/null
+++ b/src/libstddjb/tain_from_ntp.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbtime.h>
+
+int tain_from_ntp (tain_t *a, uint64 u)
+{
+ tai_t secs = { u >> 32 } ;
+ if (secs.x <= 0x7FFFFFFFUL) secs.x |= ((uint64)1 << 32) ;
+ secs.x += TAI_MAGIC ;
+ secs.x -= NTP_OFFSET ;
+ if (!tai_from_utc(&secs, secs.x)) return 0 ;
+ a->sec = secs ;
+ a->nano = ((u & 0xFFFFFFFFUL) * 1000000000) >> 32 ;
+ return 1 ;
+}
diff --git a/src/libstddjb/tain_from_timespec.c b/src/libstddjb/tain_from_timespec.c
new file mode 100644
index 0000000..e862f46
--- /dev/null
+++ b/src/libstddjb/tain_from_timespec.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <time.h>
+#include <errno.h>
+#include <skalibs/tai.h>
+
+int tain_from_timespec (tain_t *a, struct timespec const *ts)
+{
+ if (!tai_from_timespec(tain_secp(a), ts)) return 0 ;
+ a->nano = ts->tv_nsec ;
+ return 1 ;
+}
diff --git a/src/libstddjb/tain_from_timeval.c b/src/libstddjb/tain_from_timeval.c
new file mode 100644
index 0000000..9c74d13
--- /dev/null
+++ b/src/libstddjb/tain_from_timeval.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <sys/time.h>
+#include <errno.h>
+#include <skalibs/tai.h>
+
+int tain_from_timeval (tain_t *a, struct timeval const *tv)
+{
+ if (!tai_from_timeval(tain_secp(a), tv)) return 0 ;
+ a->nano = 1000 * tv->tv_usec ;
+ return 1 ;
+}
diff --git a/src/libstddjb/tain_half.c b/src/libstddjb/tain_half.c
new file mode 100644
index 0000000..a95072e
--- /dev/null
+++ b/src/libstddjb/tain_half.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+void tain_half (tain_t *t, tain_t const *u)
+{
+ t->nano = u->nano>>1 ;
+ if (tai_sec(&u->sec) & 1) t->nano += 500000000U ;
+ tai_u64(&t->sec, tai_sec(&u->sec)>>1) ;
+}
diff --git a/src/libstddjb/tain_infinite_relative.c b/src/libstddjb/tain_infinite_relative.c
new file mode 100644
index 0000000..89d750c
--- /dev/null
+++ b/src/libstddjb/tain_infinite_relative.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+tain_t const tain_infinite_relative = TAIN_INFINITE_RELATIVE ;
diff --git a/src/libstddjb/tain_less.c b/src/libstddjb/tain_less.c
new file mode 100644
index 0000000..e52c058
--- /dev/null
+++ b/src/libstddjb/tain_less.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+int tain_less (tain_t const *t, tain_t const *u)
+{
+ if (tai_sec(&t->sec) < tai_sec(&u->sec)) return 1 ;
+ if (tai_sec(&t->sec) > tai_sec(&u->sec)) return 0 ;
+ return t->nano < u->nano ;
+}
diff --git a/src/libstddjb/tain_nano500.c b/src/libstddjb/tain_nano500.c
new file mode 100644
index 0000000..70d86c5
--- /dev/null
+++ b/src/libstddjb/tain_nano500.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+tain_t const tain_nano500 = TAIN_NANO500 ;
diff --git a/src/libstddjb/tain_now.c b/src/libstddjb/tain_now.c
new file mode 100644
index 0000000..157087a
--- /dev/null
+++ b/src/libstddjb/tain_now.c
@@ -0,0 +1,49 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/config.h>
+#include <skalibs/sysdeps.h>
+#include <skalibs/tai.h>
+
+#ifdef SKALIBS_FLAG_USEMON
+# ifndef SKALIBS_HASCLOCKMON
+# undef SKALIBS_FLAG_USEMON
+# warning "SKALIBS_FLAG_USEMON set but SKALIBS_HASCLOCKMON not found. Clearing SKALIBS_FLAG_USEMON."
+# endif
+#endif
+
+
+#ifdef SKALIBS_FLAG_USEMON
+
+static tain_t offset ;
+
+int tain_init ()
+{
+ return tain_clockmon_init(&offset) ;
+}
+
+int tain_now (tain_t *a)
+{
+ static int initted = 0 ;
+ if (!initted)
+ {
+ if (!tain_clockmon_init(&offset)) return 0 ;
+ initted = 1 ;
+ }
+ return tain_clockmon(a, &offset) ;
+}
+
+#else
+
+int tain_init ()
+{
+ return 1 ;
+}
+
+int tain_now (tain_t *a)
+{
+ return tain_sysclock(a) ;
+}
+
+#endif
diff --git a/src/libstddjb/tain_pack.c b/src/libstddjb/tain_pack.c
new file mode 100644
index 0000000..cb1918a
--- /dev/null
+++ b/src/libstddjb/tain_pack.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/tai.h>
+
+void tain_pack (char *s, tain_t const *t)
+{
+ tai_pack(s, &t->sec) ;
+ uint32_pack_big(s+8, t->nano) ;
+}
diff --git a/src/libstddjb/tain_pack_little.c b/src/libstddjb/tain_pack_little.c
new file mode 100644
index 0000000..170da28
--- /dev/null
+++ b/src/libstddjb/tain_pack_little.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/tai.h>
+
+void tain_pack_little (char *s, tain_t const *t)
+{
+ uint32_pack(s, t->nano) ;
+ tai_pack_little(s+4, &t->sec) ;
+}
diff --git a/src/libstddjb/tain_relative_from_timespec.c b/src/libstddjb/tain_relative_from_timespec.c
new file mode 100644
index 0000000..e25793e
--- /dev/null
+++ b/src/libstddjb/tain_relative_from_timespec.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <time.h>
+#include <errno.h>
+#include <skalibs/tai.h>
+
+int tain_relative_from_timespec (tain_t *a, struct timespec const *ts)
+{
+ if (!tai_relative_from_timespec(tain_secp(a), ts)) return 0 ;
+ a->nano = ts->tv_nsec ;
+ return 1 ;
+}
diff --git a/src/libstddjb/tain_relative_from_timeval.c b/src/libstddjb/tain_relative_from_timeval.c
new file mode 100644
index 0000000..83aa1c3
--- /dev/null
+++ b/src/libstddjb/tain_relative_from_timeval.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <sys/time.h>
+#include <errno.h>
+#include <skalibs/tai.h>
+
+int tain_relative_from_timeval (tain_t *a, struct timeval const *tv)
+{
+ if (!tai_relative_from_timeval(tain_secp(a), tv)) return 0 ;
+ a->nano = 1000 * tv->tv_usec ;
+ return 1 ;
+}
diff --git a/src/libstddjb/tain_scan.c b/src/libstddjb/tain_scan.c
new file mode 100644
index 0000000..84a0cab
--- /dev/null
+++ b/src/libstddjb/tain_scan.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/fmtscan.h>
+#include <skalibs/tai.h>
+
+unsigned int tain_scan (char const *s, tain_t *a)
+{
+ char pack[TAIN_PACK] ;
+ register unsigned int r = ucharn_scan(s, pack, TAIN_PACK) ;
+ if (r) tain_unpack(pack, a) ;
+ return r ;
+}
diff --git a/src/libstddjb/tain_setnow.c b/src/libstddjb/tain_setnow.c
new file mode 100644
index 0000000..a8b372f
--- /dev/null
+++ b/src/libstddjb/tain_setnow.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/tai.h>
+
+int tain_setnow (tain_t const *a)
+{
+ tain_t aa ;
+ if (!sysclock_from_tai(&aa.sec.x, &a->sec)) return 0 ;
+ aa.nano = a->nano ;
+ return sysclock_set(&aa) ;
+}
diff --git a/src/libstddjb/tain_sub.c b/src/libstddjb/tain_sub.c
new file mode 100644
index 0000000..f7dd4eb
--- /dev/null
+++ b/src/libstddjb/tain_sub.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+void tain_sub (tain_t *t, tain_t const *u, tain_t const *v)
+{
+ tain_t uu = *u ;
+ tai_sub(&t->sec, &uu.sec, &v->sec) ;
+ t->nano = uu.nano - v->nano ;
+ if (t->nano > uu.nano)
+ {
+ t->nano += 1000000000U ;
+ tai_u64(&t->sec, tai_sec(&t->sec)-1) ;
+ }
+}
diff --git a/src/libstddjb/tain_sysclock.c b/src/libstddjb/tain_sysclock.c
new file mode 100644
index 0000000..7f54db6
--- /dev/null
+++ b/src/libstddjb/tain_sysclock.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+int tain_sysclock (tain_t *a)
+{
+ tain_t aa ;
+ if (!sysclock_get(&aa)) return 0 ;
+ if (!tai_from_sysclock(&a->sec, aa.sec.x)) return 0 ;
+ a->nano = aa.nano ;
+ return 1 ;
+}
diff --git a/src/libstddjb/tain_to_millisecs.c b/src/libstddjb/tain_to_millisecs.c
new file mode 100644
index 0000000..0fa9395
--- /dev/null
+++ b/src/libstddjb/tain_to_millisecs.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+
+int tain_to_millisecs (tain_t const *a)
+{
+ if (a->sec.x > (uint64)2147483) return -1 ;
+ if ((a->sec.x == (uint64)2147483) && (a->nano > 646000000U)) return -1 ;
+ return a->sec.x * 1000 + (a->nano + 999999) / 1000000U ;
+}
diff --git a/src/libstddjb/tain_ulong.c b/src/libstddjb/tain_ulong.c
new file mode 100644
index 0000000..2ba730a
--- /dev/null
+++ b/src/libstddjb/tain_ulong.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+void tain_ulong (tain_t *t, unsigned long s)
+{
+ tai_u64(&t->sec, s) ;
+ t->nano = 0 ;
+}
diff --git a/src/libstddjb/tain_unpack.c b/src/libstddjb/tain_unpack.c
new file mode 100644
index 0000000..a62dc29
--- /dev/null
+++ b/src/libstddjb/tain_unpack.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/tai.h>
+
+void tain_unpack (char const *s, tain_t *t)
+{
+ tai_unpack(s, &t->sec) ;
+ uint32_unpack_big(s+8, &t->nano) ;
+}
diff --git a/src/libstddjb/tain_unpack_little.c b/src/libstddjb/tain_unpack_little.c
new file mode 100644
index 0000000..278d494
--- /dev/null
+++ b/src/libstddjb/tain_unpack_little.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/tai.h>
+
+void tain_unpack_little (char const *s, tain_t *t)
+{
+ uint32_unpack(s, &t->nano) ;
+ tai_unpack_little(s+4, &t->sec) ;
+}
diff --git a/src/libstddjb/timespec_from_tai.c b/src/libstddjb/timespec_from_tai.c
new file mode 100644
index 0000000..7bb84d4
--- /dev/null
+++ b/src/libstddjb/timespec_from_tai.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <time.h>
+#include <skalibs/tai.h>
+
+int timespec_from_tai (struct timespec *ts, tai_t const *t)
+{
+ tai_t trel ;
+ tai_u64(&trel, tai_sec(t) - TAI_MAGIC) ;
+ return timespec_from_tai_relative(ts, &trel) ;
+}
diff --git a/src/libstddjb/timespec_from_tai_relative.c b/src/libstddjb/timespec_from_tai_relative.c
new file mode 100644
index 0000000..42f2e95
--- /dev/null
+++ b/src/libstddjb/timespec_from_tai_relative.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <time.h>
+#include <errno.h>
+#include <skalibs/sysdeps.h>
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+
+int timespec_from_tai_relative (struct timespec *ts, tai_t const *t)
+{
+ if (tai_sec(t) >= (uint64)1 << 63) return (errno = EINVAL, 0) ;
+#if SKALIBS_SIZEOFTIME < 8
+ if (tai_sec(t) > 0xffffffffU) return (errno = ERANGE, 0) ;
+#endif
+ ts->tv_sec = (time_t)tai_sec(t) ;
+ ts->tv_nsec = 0 ;
+ return 1 ;
+}
diff --git a/src/libstddjb/timespec_from_tain.c b/src/libstddjb/timespec_from_tain.c
new file mode 100644
index 0000000..5eb6e30
--- /dev/null
+++ b/src/libstddjb/timespec_from_tain.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <time.h>
+#include <skalibs/tai.h>
+
+int timespec_from_tain (struct timespec *ts, tain_t const *a)
+{
+ struct timespec tmp ;
+ if (!timespec_from_tai(&tmp, tain_secp(a))) return 0 ;
+ ts->tv_sec = tmp.tv_sec ;
+ ts->tv_nsec = a->nano ;
+ return 1 ;
+}
diff --git a/src/libstddjb/timespec_from_tain_relative.c b/src/libstddjb/timespec_from_tain_relative.c
new file mode 100644
index 0000000..32e7993
--- /dev/null
+++ b/src/libstddjb/timespec_from_tain_relative.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <time.h>
+#include <skalibs/tai.h>
+
+int timespec_from_tain_relative (struct timespec *ts, tain_t const *a)
+{
+ struct timespec tmp ;
+ if (!timespec_from_tai_relative(&tmp, tain_secp(a))) return 0 ;
+ ts->tv_sec = tmp.tv_sec ;
+ ts->tv_nsec = a->nano ;
+ return 1 ;
+}
diff --git a/src/libstddjb/timestamp.c b/src/libstddjb/timestamp.c
new file mode 100644
index 0000000..7feb7c2
--- /dev/null
+++ b/src/libstddjb/timestamp.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+int timestamp (char *s)
+{
+ tain_t now ;
+ return timestamp_r(s, &now) ;
+}
diff --git a/src/libstddjb/timestamp_fmt.c b/src/libstddjb/timestamp_fmt.c
new file mode 100644
index 0000000..1956723
--- /dev/null
+++ b/src/libstddjb/timestamp_fmt.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+unsigned int timestamp_fmt (char *s, tain_t const *a)
+{
+ *s = '@' ;
+ return 1 + tain_fmt(s+1, a) ;
+}
diff --git a/src/libstddjb/timestamp_r.c b/src/libstddjb/timestamp_r.c
new file mode 100644
index 0000000..6eb8ab7
--- /dev/null
+++ b/src/libstddjb/timestamp_r.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+int timestamp_r (char *s, tain_t *stamp)
+{
+ if (!tain_sysclock(stamp)) return 0 ;
+ timestamp_fmt(s, stamp) ;
+ return 1 ;
+}
diff --git a/src/libstddjb/timestamp_scan.c b/src/libstddjb/timestamp_scan.c
new file mode 100644
index 0000000..1d48612
--- /dev/null
+++ b/src/libstddjb/timestamp_scan.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+
+unsigned int timestamp_scan (char const *s, tain_t *a)
+{
+ register unsigned int r ;
+ if (*s != '@') return 0 ;
+ r = tain_scan(s+1, a) ;
+ return r ? r+1 : 0 ;
+}
diff --git a/src/libstddjb/timeval_from_tai.c b/src/libstddjb/timeval_from_tai.c
new file mode 100644
index 0000000..d0c4777
--- /dev/null
+++ b/src/libstddjb/timeval_from_tai.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <sys/time.h>
+#include <skalibs/tai.h>
+
+int timeval_from_tai (struct timeval *tv, tai_t const *t)
+{
+ tai_t trel ;
+ tai_u64(&trel, tai_sec(t) - TAI_MAGIC) ;
+ return timeval_from_tai_relative(tv, &trel) ;
+}
diff --git a/src/libstddjb/timeval_from_tai_relative.c b/src/libstddjb/timeval_from_tai_relative.c
new file mode 100644
index 0000000..94bd3f7
--- /dev/null
+++ b/src/libstddjb/timeval_from_tai_relative.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <sys/time.h>
+#include <errno.h>
+#include <skalibs/sysdeps.h>
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+
+int timeval_from_tai_relative (struct timeval *tv, tai_t const *t)
+{
+ if (tai_sec(t) >= (uint64)1 << 63) return (errno = EINVAL, 0) ;
+#if SKALIBS_SIZEOFTIME < 8
+ if (tai_sec(t) > 0xffffffffU) return (errno = ERANGE, 0) ;
+#endif
+ tv->tv_sec = (time_t)tai_sec(t) ;
+ tv->tv_usec = 0 ;
+ return 1 ;
+}
diff --git a/src/libstddjb/timeval_from_tain.c b/src/libstddjb/timeval_from_tain.c
new file mode 100644
index 0000000..c780af7
--- /dev/null
+++ b/src/libstddjb/timeval_from_tain.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <sys/time.h>
+#include <skalibs/tai.h>
+
+int timeval_from_tain (struct timeval *tv, tain_t const *a)
+{
+ struct timeval tmp ;
+ if (!timeval_from_tai(&tmp, tain_secp(a))) return 0 ;
+ tv->tv_sec = tmp.tv_sec ;
+ tv->tv_usec = a->nano / 1000 ;
+ return 1 ;
+}
diff --git a/src/libstddjb/timeval_from_tain_relative.c b/src/libstddjb/timeval_from_tain_relative.c
new file mode 100644
index 0000000..624293c
--- /dev/null
+++ b/src/libstddjb/timeval_from_tain_relative.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <sys/time.h>
+#include <skalibs/tai.h>
+
+int timeval_from_tain_relative (struct timeval *tv, tain_t const *a)
+{
+ struct timeval tmp ;
+ if (!timeval_from_tai_relative(&tmp, tain_secp(a))) return 0 ;
+ tv->tv_sec = tmp.tv_sec ;
+ tv->tv_usec = a->nano / 1000 ;
+ return 1 ;
+}
diff --git a/src/libstddjb/ucharn_findlen.c b/src/libstddjb/ucharn_findlen.c
new file mode 100644
index 0000000..1016647
--- /dev/null
+++ b/src/libstddjb/ucharn_findlen.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/fmtscan.h>
+
+unsigned int ucharn_findlen (char const *s)
+{
+ register unsigned int i = 0 ;
+ while (fmtscan_num(s[i], 16) <= 0xF) i++ ;
+ return i ;
+}
diff --git a/src/libstddjb/ucharn_fmt.c b/src/libstddjb/ucharn_fmt.c
new file mode 100644
index 0000000..2943fdf
--- /dev/null
+++ b/src/libstddjb/ucharn_fmt.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/fmtscan.h>
+
+unsigned int ucharn_fmt (char *s, char const *key, unsigned int n)
+{
+ register unsigned int i = 0 ;
+ for (; i < n ; i++)
+ {
+ s[i<<1] = fmtscan_asc((unsigned char)key[i] >> 4) ;
+ s[(i<<1)+1] = fmtscan_asc((unsigned char)key[i] & 0xF) ;
+ }
+ return n << 1 ;
+}
diff --git a/src/libstddjb/ucharn_fmt_little.c b/src/libstddjb/ucharn_fmt_little.c
new file mode 100644
index 0000000..8450c46
--- /dev/null
+++ b/src/libstddjb/ucharn_fmt_little.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/fmtscan.h>
+
+unsigned int ucharn_fmt_little (char *s, char const *key, unsigned int n)
+{
+ register unsigned int i = 0 ;
+ for (; i < n ; i++)
+ {
+ s[i<<1] = fmtscan_asc((unsigned char)key[i] & 0xF) ;
+ s[(i<<1)+1] = fmtscan_asc((unsigned char)key[i] >> 4) ;
+ }
+ return n << 1 ;
+}
diff --git a/src/libstddjb/ucharn_scan.c b/src/libstddjb/ucharn_scan.c
new file mode 100644
index 0000000..cdcc403
--- /dev/null
+++ b/src/libstddjb/ucharn_scan.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/fmtscan.h>
+
+unsigned int ucharn_scan (char const *s, char *key, unsigned int n)
+{
+ register unsigned int i = 0 ;
+ for (; i < n ; i++)
+ {
+ unsigned char c = fmtscan_num(s[2*i], 16) ;
+ if (c > 0xF) return 0 ;
+ key[i] = c << 4 ;
+ c = fmtscan_num(s[2*i+1], 16) ;
+ if (c > 0xF) return 0 ;
+ key[i] += c ;
+ }
+ return n << 1 ;
+}
diff --git a/src/libstddjb/ucharn_scan_little.c b/src/libstddjb/ucharn_scan_little.c
new file mode 100644
index 0000000..5b66af5
--- /dev/null
+++ b/src/libstddjb/ucharn_scan_little.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/fmtscan.h>
+
+unsigned int ucharn_scan_little (char const *s, char *key, unsigned int n)
+{
+ register unsigned int i = 0 ;
+ for (; i < n ; i++)
+ {
+ unsigned char c = fmtscan_num(s[(i<<1)+1], 16) ;
+ if (c > 0xF) return 0 ;
+ key[i] = c << 4 ;
+ c = fmtscan_num(s[i<<1], 16) ;
+ if (c > 0xF) return 0 ;
+ key[i] += c ;
+ }
+ return n << 1 ;
+}
diff --git a/src/libstddjb/ucspi_get.c b/src/libstddjb/ucspi_get.c
new file mode 100644
index 0000000..916ae2a
--- /dev/null
+++ b/src/libstddjb/ucspi_get.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/env.h>
+
+char const *ucspi_get (char const *s)
+{
+ char const *x = env_get("PROTO") ;
+ if (x)
+ {
+ unsigned int len = str_len(s) ;
+ unsigned int xlen = str_len(x) ;
+ char tmp[len + xlen + 1] ;
+ byte_copy(tmp, xlen, x) ;
+ byte_copy(tmp + xlen, len + 1, s) ;
+ x = env_get(tmp) ;
+ if (!x) errno = ENOENT ;
+ }
+ else errno = EINVAL ;
+ return x ;
+}
diff --git a/src/libstddjb/uint160_scan.c b/src/libstddjb/uint160_scan.c
new file mode 100644
index 0000000..9a48514
--- /dev/null
+++ b/src/libstddjb/uint160_scan.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include "fmtscan-internal.h"
+
+SCANB0(16)
diff --git a/src/libstddjb/uint16_fmtlist.c b/src/libstddjb/uint16_fmtlist.c
new file mode 100644
index 0000000..721b443
--- /dev/null
+++ b/src/libstddjb/uint16_fmtlist.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include "fmtscan-internal.h"
+
+FMTL(16)
diff --git a/src/libstddjb/uint16_pack.c b/src/libstddjb/uint16_pack.c
new file mode 100644
index 0000000..c84f504
--- /dev/null
+++ b/src/libstddjb/uint16_pack.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+
+void uint16_pack (char *s, uint16 u)
+{
+ ((unsigned char *)s)[0] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[1] = T8(u) ;
+}
diff --git a/src/libstddjb/uint16_pack_big.c b/src/libstddjb/uint16_pack_big.c
new file mode 100644
index 0000000..9fac1fa
--- /dev/null
+++ b/src/libstddjb/uint16_pack_big.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+
+void uint16_pack_big (char *s, uint16 u)
+{
+ ((unsigned char *)s)[1] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[0] = T8(u) ;
+}
diff --git a/src/libstddjb/uint16_reverse.c b/src/libstddjb/uint16_reverse.c
new file mode 100644
index 0000000..fedade1
--- /dev/null
+++ b/src/libstddjb/uint16_reverse.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+
+void uint16_reverse (char *s, unsigned int n)
+{
+ while (n--)
+ {
+ char c = s[0] ;
+ s[0] = s[1] ;
+ s[1] = c ;
+ s += 2 ;
+ }
+}
diff --git a/src/libstddjb/uint16_scan.c b/src/libstddjb/uint16_scan.c
new file mode 100644
index 0000000..5665807
--- /dev/null
+++ b/src/libstddjb/uint16_scan.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include "fmtscan-internal.h"
+
+SCANB(16)
diff --git a/src/libstddjb/uint16_scanlist.c b/src/libstddjb/uint16_scanlist.c
new file mode 100644
index 0000000..e98777f
--- /dev/null
+++ b/src/libstddjb/uint16_scanlist.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include "fmtscan-internal.h"
+
+SCANL(16)
diff --git a/src/libstddjb/uint16_unpack.c b/src/libstddjb/uint16_unpack.c
new file mode 100644
index 0000000..c3ade45
--- /dev/null
+++ b/src/libstddjb/uint16_unpack.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+
+void uint16_unpack (char const *s, uint16 *u)
+{
+ uint16 r = T8((unsigned char)s[1]) ; r <<= 8 ;
+ r += T8((unsigned char)s[0]) ;
+ *u = r ;
+}
diff --git a/src/libstddjb/uint16_unpack_big.c b/src/libstddjb/uint16_unpack_big.c
new file mode 100644
index 0000000..2f22555
--- /dev/null
+++ b/src/libstddjb/uint16_unpack_big.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+
+void uint16_unpack_big (char const *s, uint16 *u)
+{
+ uint16 r = T8((unsigned char)s[0]) ; r <<= 8 ;
+ r += T8((unsigned char)s[1]) ;
+ *u = r ;
+}
diff --git a/src/libstddjb/uint320_scan.c b/src/libstddjb/uint320_scan.c
new file mode 100644
index 0000000..103354c
--- /dev/null
+++ b/src/libstddjb/uint320_scan.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include "fmtscan-internal.h"
+
+SCANB0(32)
diff --git a/src/libstddjb/uint32_fmtlist.c b/src/libstddjb/uint32_fmtlist.c
new file mode 100644
index 0000000..978d72a
--- /dev/null
+++ b/src/libstddjb/uint32_fmtlist.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include "fmtscan-internal.h"
+
+FMTL(32)
diff --git a/src/libstddjb/uint32_pack.c b/src/libstddjb/uint32_pack.c
new file mode 100644
index 0000000..d467c3d
--- /dev/null
+++ b/src/libstddjb/uint32_pack.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+
+void uint32_pack (char *s, uint32 u)
+{
+ ((unsigned char *)s)[0] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[1] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[2] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[3] = T8(u) ;
+}
diff --git a/src/libstddjb/uint32_pack_big.c b/src/libstddjb/uint32_pack_big.c
new file mode 100644
index 0000000..487cf21
--- /dev/null
+++ b/src/libstddjb/uint32_pack_big.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+
+void uint32_pack_big (char *s, uint32 u)
+{
+ ((unsigned char *)s)[3] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[2] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[1] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[0] = T8(u) ;
+}
diff --git a/src/libstddjb/uint32_reverse.c b/src/libstddjb/uint32_reverse.c
new file mode 100644
index 0000000..18b3b43
--- /dev/null
+++ b/src/libstddjb/uint32_reverse.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+
+void uint32_reverse (char *s, unsigned int n)
+{
+ while (n--)
+ {
+ char c = s[0] ;
+ s[0] = s[3] ;
+ s[3] = c ;
+ c = s[1] ;
+ s[1] = s[2] ;
+ s[2] = c ;
+ s += 4 ;
+ }
+}
diff --git a/src/libstddjb/uint32_scan.c b/src/libstddjb/uint32_scan.c
new file mode 100644
index 0000000..06e2d77
--- /dev/null
+++ b/src/libstddjb/uint32_scan.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include "fmtscan-internal.h"
+
+SCANB(32)
diff --git a/src/libstddjb/uint32_scanlist.c b/src/libstddjb/uint32_scanlist.c
new file mode 100644
index 0000000..f2bf094
--- /dev/null
+++ b/src/libstddjb/uint32_scanlist.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include "fmtscan-internal.h"
+
+SCANL(32)
diff --git a/src/libstddjb/uint32_unpack.c b/src/libstddjb/uint32_unpack.c
new file mode 100644
index 0000000..d5dabcc
--- /dev/null
+++ b/src/libstddjb/uint32_unpack.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+
+void uint32_unpack (char const *s, uint32 *u)
+{
+ uint32 r = T8((unsigned char)s[3]) ; r <<= 8 ;
+ r += T8((unsigned char)s[2]) ; r <<= 8 ;
+ r += T8((unsigned char)s[1]) ; r <<= 8 ;
+ r += T8((unsigned char)s[0]) ;
+ *u = r ;
+}
diff --git a/src/libstddjb/uint32_unpack_big.c b/src/libstddjb/uint32_unpack_big.c
new file mode 100644
index 0000000..1a53292
--- /dev/null
+++ b/src/libstddjb/uint32_unpack_big.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+
+void uint32_unpack_big (char const *s, uint32 *u)
+{
+ uint32 r = T8((unsigned char)s[0]) ; r <<= 8 ;
+ r += T8((unsigned char)s[1]) ; r <<= 8 ;
+ r += T8((unsigned char)s[2]) ; r <<= 8 ;
+ r += T8((unsigned char)s[3]) ;
+ *u = r ;
+}
diff --git a/src/libstddjb/uint640_fmt.c b/src/libstddjb/uint640_fmt.c
new file mode 100644
index 0000000..7153055
--- /dev/null
+++ b/src/libstddjb/uint640_fmt.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+
+unsigned int uint640_fmt_base (char *s, uint64 x, register unsigned int n, unsigned char base)
+{
+ register unsigned int len = uint64_fmt_base(0, x, base) ;
+ while (n-- > len) *s++ = '0' ;
+ return uint64_fmt_base(s, x, base) ;
+}
diff --git a/src/libstddjb/uint640_scan.c b/src/libstddjb/uint640_scan.c
new file mode 100644
index 0000000..45c8e20
--- /dev/null
+++ b/src/libstddjb/uint640_scan.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include "fmtscan-internal.h"
+
+SCANB0(64)
diff --git a/src/libstddjb/uint64_fmt.c b/src/libstddjb/uint64_fmt.c
new file mode 100644
index 0000000..cbe3382
--- /dev/null
+++ b/src/libstddjb/uint64_fmt.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include <skalibs/fmtscan.h>
+
+unsigned int uint64_fmt_base (char *s, uint64 x, unsigned char base)
+{
+ register unsigned int len = 1 ;
+ {
+ register uint64 q = x ;
+ while (q >= base) { len++ ; q /= base ; }
+ }
+ if (s)
+ {
+ s += len ;
+ do { *--s = fmtscan_asc(x % base) ; x /= base ; } while (x) ;
+ }
+ return len ;
+}
diff --git a/src/libstddjb/uint64_fmtlist.c b/src/libstddjb/uint64_fmtlist.c
new file mode 100644
index 0000000..4d18a8b
--- /dev/null
+++ b/src/libstddjb/uint64_fmtlist.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include "fmtscan-internal.h"
+
+FMTL(64)
diff --git a/src/libstddjb/uint64_pack.c b/src/libstddjb/uint64_pack.c
new file mode 100644
index 0000000..23c8e19
--- /dev/null
+++ b/src/libstddjb/uint64_pack.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include <skalibs/bytestr.h>
+
+void uint64_pack (char *s, uint64 u)
+{
+ ((unsigned char *)s)[0] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[1] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[2] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[3] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[4] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[5] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[6] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[7] = T8(u) ;
+}
diff --git a/src/libstddjb/uint64_pack_big.c b/src/libstddjb/uint64_pack_big.c
new file mode 100644
index 0000000..17d0206
--- /dev/null
+++ b/src/libstddjb/uint64_pack_big.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include <skalibs/bytestr.h>
+
+void uint64_pack_big (char *s, uint64 u)
+{
+ ((unsigned char *)s)[7] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[6] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[5] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[4] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[3] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[2] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[1] = T8(u) ; u >>= 8 ;
+ ((unsigned char *)s)[0] = T8(u) ;
+}
diff --git a/src/libstddjb/uint64_reverse.c b/src/libstddjb/uint64_reverse.c
new file mode 100644
index 0000000..f8730fe
--- /dev/null
+++ b/src/libstddjb/uint64_reverse.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+
+void uint64_reverse (char *s, unsigned int n)
+{
+ while (n--)
+ {
+ char c = s[0] ; s[0] = s[7] ; s[7] = c ;
+ c = s[1] ; s[1] = s[6] ; s[6] = c ;
+ c = s[2] ; s[2] = s[5] ; s[5] = c ;
+ c = s[3] ; s[3] = s[4] ; s[4] = c ;
+ s += 8 ;
+ }
+}
diff --git a/src/libstddjb/uint64_scan.c b/src/libstddjb/uint64_scan.c
new file mode 100644
index 0000000..530e84c
--- /dev/null
+++ b/src/libstddjb/uint64_scan.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include "fmtscan-internal.h"
+
+SCANB(64)
diff --git a/src/libstddjb/uint64_scanlist.c b/src/libstddjb/uint64_scanlist.c
new file mode 100644
index 0000000..4a22478
--- /dev/null
+++ b/src/libstddjb/uint64_scanlist.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include "fmtscan-internal.h"
+
+SCANL(64)
diff --git a/src/libstddjb/uint64_unpack.c b/src/libstddjb/uint64_unpack.c
new file mode 100644
index 0000000..e0561d9
--- /dev/null
+++ b/src/libstddjb/uint64_unpack.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include <skalibs/bytestr.h>
+
+void uint64_unpack (char const *s, uint64 *u)
+{
+ uint64 r = T8((unsigned char)s[7]) ; r <<= 8 ;
+ r += T8((unsigned char)s[6]) ; r <<= 8 ;
+ r += T8((unsigned char)s[5]) ; r <<= 8 ;
+ r += T8((unsigned char)s[4]) ; r <<= 8 ;
+ r += T8((unsigned char)s[3]) ; r <<= 8 ;
+ r += T8((unsigned char)s[2]) ; r <<= 8 ;
+ r += T8((unsigned char)s[1]) ; r <<= 8 ;
+ r += T8((unsigned char)s[0]) ;
+ *u = r ;
+}
diff --git a/src/libstddjb/uint64_unpack_big.c b/src/libstddjb/uint64_unpack_big.c
new file mode 100644
index 0000000..ebb419b
--- /dev/null
+++ b/src/libstddjb/uint64_unpack_big.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include <skalibs/bytestr.h>
+
+void uint64_unpack_big (char const *s, uint64 *u)
+{
+ uint64 r = T8((unsigned char)s[0]) ; r <<= 8 ;
+ r += T8((unsigned char)s[1]) ; r <<= 8 ;
+ r += T8((unsigned char)s[2]) ; r <<= 8 ;
+ r += T8((unsigned char)s[3]) ; r <<= 8 ;
+ r += T8((unsigned char)s[4]) ; r <<= 8 ;
+ r += T8((unsigned char)s[5]) ; r <<= 8 ;
+ r += T8((unsigned char)s[6]) ; r <<= 8 ;
+ r += T8((unsigned char)s[7]) ;
+ *u = r ;
+}
diff --git a/src/libstddjb/uncoe.c b/src/libstddjb/uncoe.c
new file mode 100644
index 0000000..61593b9
--- /dev/null
+++ b/src/libstddjb/uncoe.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <fcntl.h>
+#include <skalibs/djbunix.h>
+
+int uncoe (int fd)
+{
+ register int flags = fcntl(fd, F_GETFD, 0) ;
+ if (flags < 0) return -1 ;
+ return fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC) ;
+}
diff --git a/src/libstddjb/unsanitize_read.c b/src/libstddjb/unsanitize_read.c
new file mode 100644
index 0000000..efea22a
--- /dev/null
+++ b/src/libstddjb/unsanitize_read.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/error.h>
+
+int unsanitize_read (int r)
+{
+ return r == -1 ? errno == EPIPE ? (errno = 0, 0) : -1 :
+ !r ? (errno = EWOULDBLOCK, -1) : r ;
+}
diff --git a/src/libstddjb/utc_from_localtm.c b/src/libstddjb/utc_from_localtm.c
new file mode 100644
index 0000000..cad1a06
--- /dev/null
+++ b/src/libstddjb/utc_from_localtm.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <time.h>
+#include <skalibs/uint64.h>
+#include <skalibs/djbtime.h>
+
+int utc_from_localtm (uint64 *uu, struct tm const *l)
+{
+ uint64 u ;
+ if (!ltm64_from_localtm(&u, l)) return 0 ;
+ if (!utc_from_ltm64(&u)) return 0 ;
+ *uu = u ;
+ return 1 ;
+}
diff --git a/src/libstddjb/utc_from_ltm64.c b/src/libstddjb/utc_from_ltm64.c
new file mode 100644
index 0000000..44aea15
--- /dev/null
+++ b/src/libstddjb/utc_from_ltm64.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/uint64.h>
+#include <skalibs/djbtime.h>
+#include "djbtime-internal.h"
+
+#ifdef SKALIBS_FLAG_CLOCKISTAI
+
+int utc_from_ltm64 (uint64 *u)
+{
+ return (leapsecs_sub(u) > 0) ;
+}
+
+#else
+
+int utc_from_ltm64 (uint64 *u)
+{
+ (void)u ;
+ return 1 ;
+}
+
+#endif
diff --git a/src/libstddjb/utc_from_sysclock.c b/src/libstddjb/utc_from_sysclock.c
new file mode 100644
index 0000000..979bb04
--- /dev/null
+++ b/src/libstddjb/utc_from_sysclock.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+#include <skalibs/config.h>
+#include <skalibs/uint64.h>
+#include <skalibs/djbtime.h>
+
+#ifdef SKALIBS_FLAG_CLOCKISTAI
+
+#include <skalibs/tai.h>
+
+int utc_from_sysclock (uint64 *u)
+{
+ tai_t t = { .x = *u + 10U } ;
+ return utc_from_tai(u, &t) ;
+}
+
+#else
+
+int utc_from_sysclock (uint64 *u)
+{
+ (void)u ;
+ return 1 ;
+}
+
+#endif
diff --git a/src/libstddjb/utc_from_tai.c b/src/libstddjb/utc_from_tai.c
new file mode 100644
index 0000000..f4d247e
--- /dev/null
+++ b/src/libstddjb/utc_from_tai.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbtime.h>
+#include "djbtime-internal.h"
+
+int utc_from_tai (uint64 *u, tai_t const *t)
+{
+ uint64 tt = t->x - 10 ;
+ if (leapsecs_sub(&tt) < 0) return 0 ;
+ *u = tt ;
+ return 1 ;
+}
diff --git a/src/libstddjb/vbaprintf.c b/src/libstddjb/vbaprintf.c
new file mode 100644
index 0000000..efc2bd1
--- /dev/null
+++ b/src/libstddjb/vbaprintf.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/bufalloc.h>
+#include <skalibs/lolstdio.h>
+
+int vbaprintf (bufalloc *ba, char const *format, va_list args)
+{
+ int r ;
+ {
+ va_list ugly ;
+ va_copy(ugly, args) ;
+ r = vsnprintf(0, 0, format, ugly) ;
+ va_end(ugly) ;
+ }
+ if (r < 0) return r ;
+ if (!stralloc_readyplus(&ba->x, (unsigned int)r + 1)) return -1 ;
+ r = vsnprintf(ba->x.s + ba->x.len, (unsigned int)r + 1, format, args) ;
+ if (r > 0) ba->x.len += r ;
+ return r ;
+}
diff --git a/src/libstddjb/vbprintf.c b/src/libstddjb/vbprintf.c
new file mode 100644
index 0000000..a6a75f3
--- /dev/null
+++ b/src/libstddjb/vbprintf.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <skalibs/buffer.h>
+#include <skalibs/lolstdio.h>
+
+int vbprintf (buffer *b, char const *format, va_list args)
+{
+ int r ;
+ {
+ va_list ugly ;
+ va_copy(ugly, args) ;
+ r = vsnprintf(0, 0, format, ugly) ;
+ va_end(ugly) ;
+ }
+ if (r < 0) return r ;
+ {
+ char buf[(unsigned int)r + 1] ;
+ r = vsnprintf(buf, (unsigned int)r + 1, format, args) ;
+ if (r < 0) return r ;
+ if (buffer_put(b, buf, r) < r) return -1 ;
+ }
+ return r ;
+}
diff --git a/src/libstddjb/wait_nointr.c b/src/libstddjb/wait_nointr.c
new file mode 100644
index 0000000..02dcd42
--- /dev/null
+++ b/src/libstddjb/wait_nointr.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+pid_t wait_nointr (int *wstat)
+{
+ register pid_t r ;
+ do
+ r = wait(wstat) ;
+ while ((r == (pid_t)-1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libstddjb/wait_pid_nohang.c b/src/libstddjb/wait_pid_nohang.c
new file mode 100644
index 0000000..11beed6
--- /dev/null
+++ b/src/libstddjb/wait_pid_nohang.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <skalibs/djbunix.h>
+
+pid_t wait_pid_nohang (pid_t pid, int *wstat)
+{
+ int w = 0 ;
+ register pid_t r = 0 ;
+ while (r != pid)
+ {
+ r = wait_nohang(&w) ;
+ if (!r || (r == (pid_t)-1)) return (int)r ;
+ }
+ *wstat = w ;
+ return r ;
+}
diff --git a/src/libstddjb/wait_pids_nohang.c b/src/libstddjb/wait_pids_nohang.c
new file mode 100644
index 0000000..3c52e6b
--- /dev/null
+++ b/src/libstddjb/wait_pids_nohang.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <skalibs/djbunix.h>
+
+int wait_pids_nohang (pid_t const *pids, unsigned int len, int *wstat)
+{
+ for (;;)
+ {
+ int w ;
+ register pid_t r = wait_nohang(&w) ;
+ if (!r || (r == (pid_t)-1)) return (int)r ;
+ {
+ register unsigned int i = 0 ;
+ for (; i < len ; i++) if (r == pids[i]) break ;
+ if (i < len)
+ {
+ *wstat = w ;
+ return 1+i ;
+ }
+ }
+ }
+}
diff --git a/src/libstddjb/wait_reap.c b/src/libstddjb/wait_reap.c
new file mode 100644
index 0000000..7049b27
--- /dev/null
+++ b/src/libstddjb/wait_reap.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/djbunix.h>
+
+unsigned int wait_reap ()
+{
+ register unsigned int n = 0 ;
+ int wstat ;
+ while (wait_nohang(&wstat) > 0) n++ ;
+ return n ;
+}
diff --git a/src/libstddjb/waitn.c b/src/libstddjb/waitn.c
new file mode 100644
index 0000000..0d01cd1
--- /dev/null
+++ b/src/libstddjb/waitn.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <skalibs/djbunix.h>
+
+int waitn (pid_t *pids, unsigned int n)
+{
+ while (n)
+ {
+ int wstat ;
+ register unsigned int i = 0 ;
+ register pid_t pid = wait_nointr(&wstat) ;
+ if (pid < 0) return 0 ;
+ for (; i < n ; i++) if (pid == pids[i]) break ;
+ if (i < n) pids[i] = pids[--n] ;
+ }
+ return 1 ;
+}
diff --git a/src/libstddjb/waitn_reap.c b/src/libstddjb/waitn_reap.c
new file mode 100644
index 0000000..96a0c61
--- /dev/null
+++ b/src/libstddjb/waitn_reap.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <skalibs/djbunix.h>
+
+int waitn_reap (pid_t *pids, unsigned int len)
+{
+ unsigned int n = 0 ;
+ while (len)
+ {
+ int w ;
+ register int r = wait_pids_nohang(pids, len, &w) ;
+ if (r < 0) return r ;
+ else if (!r) break ;
+ pids[r-1] = pids[--len] ;
+ n++ ;
+ }
+ return (int)n ;
+}
diff --git a/src/libstddjb/waitpid_nointr.c b/src/libstddjb/waitpid_nointr.c
new file mode 100644
index 0000000..8c6a65e
--- /dev/null
+++ b/src/libstddjb/waitpid_nointr.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+
+pid_t waitpid_nointr (pid_t pid, int *wstat, int flags)
+{
+ register pid_t r ;
+ do
+ r = waitpid(pid, wstat, flags) ;
+ while ((r == (pid_t)-1) && (errno == EINTR)) ;
+ return r ;
+}
diff --git a/src/libunixonacid/bufalloc_timed_flush.c b/src/libunixonacid/bufalloc_timed_flush.c
new file mode 100644
index 0000000..df0eb79
--- /dev/null
+++ b/src/libunixonacid/bufalloc_timed_flush.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <skalibs/bufalloc.h>
+#include <skalibs/functypes.h>
+#include <skalibs/tai.h>
+#include <skalibs/unix-timed.h>
+
+static int bufalloc_isnonempty (bufalloc *ba)
+{
+ return !!bufalloc_len(ba) ;
+}
+
+int bufalloc_timed_flush (bufalloc *ba, tain_t const *deadline, tain_t *stamp)
+{
+ return timed_flush(ba, (initfunc_t_ref)&bufalloc_getfd, (initfunc_t_ref)&bufalloc_isnonempty, (initfunc_t_ref)&bufalloc_flush, deadline, stamp) ;
+}
diff --git a/src/libunixonacid/buffer_timed_fill.c b/src/libunixonacid/buffer_timed_fill.c
new file mode 100644
index 0000000..c6f580f
--- /dev/null
+++ b/src/libunixonacid/buffer_timed_fill.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/allreadwrite.h>
+#include <skalibs/buffer.h>
+#include <skalibs/functypes.h>
+#include <skalibs/tai.h>
+#include <skalibs/unix-timed.h>
+
+static int get (buffer *b)
+{
+ return sanitize_read(buffer_fill(b)) ;
+}
+
+int buffer_timed_fill (buffer *b, tain_t const *deadline, tain_t *stamp)
+{
+ return timed_get(b, (initfunc_t_ref)&buffer_getfd, (initfunc_t_ref)&get, deadline, stamp) ;
+}
diff --git a/src/libunixonacid/buffer_timed_flush.c b/src/libunixonacid/buffer_timed_flush.c
new file mode 100644
index 0000000..63a2587
--- /dev/null
+++ b/src/libunixonacid/buffer_timed_flush.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/functypes.h>
+#include <skalibs/tai.h>
+#include <skalibs/unix-timed.h>
+
+static int buffer_isnonempty (buffer *b)
+{
+ return !buffer_isempty(b) ;
+}
+
+int timed_buffer_flush (buffer *b, tain_t const *deadline, tain_t *stamp)
+{
+ return timed_flush(b, (initfunc_t_ref)&buffer_getfd, (initfunc_t_ref)&buffer_isnonempty, (initfunc_t_ref)&buffer_flush, deadline, stamp) ;
+}
diff --git a/src/libunixonacid/buffer_timed_get.c b/src/libunixonacid/buffer_timed_get.c
new file mode 100644
index 0000000..2f3b751
--- /dev/null
+++ b/src/libunixonacid/buffer_timed_get.c
@@ -0,0 +1,30 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/tai.h>
+#include <skalibs/unix-timed.h>
+
+struct blah_s
+{
+ buffer *b ;
+ char *s ;
+ unsigned int len ;
+ unsigned int w ;
+} ;
+
+static int getfd (struct blah_s *blah)
+{
+ return buffer_fd(blah->b) ;
+}
+
+static int get (struct blah_s *blah)
+{
+ return buffer_getall(blah->b, blah->s, blah->len, &blah->w) ;
+}
+
+unsigned int buffer_timed_get (buffer *b, char *s, unsigned int len, tain_t const *deadline, tain_t *stamp)
+{
+ struct blah_s blah = { .b = b, .s = s, .len = len, .w = 0 } ;
+ timed_get(&blah, (initfunc_t_ref)&getfd, (initfunc_t_ref)&get, deadline, stamp) ;
+ return blah.w ;
+}
diff --git a/src/libunixonacid/dd_cancel.c b/src/libunixonacid/dd_cancel.c
new file mode 100644
index 0000000..22adf4e
--- /dev/null
+++ b/src/libunixonacid/dd_cancel.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/unix-transactional.h>
+
+void dd_cancel (dirdescriptor_t_ref dd)
+{
+ dirdescriptor_t zero = DIRDESCRIPTOR_ZERO ;
+ register int e = errno ;
+ fd_close(dd->fd) ;
+ rm_rf_in_tmp(&dd->new, 0) ;
+ stralloc_free(&dd->new) ;
+ *dd = zero ;
+ errno = e ;
+}
diff --git a/src/libunixonacid/dd_close.c b/src/libunixonacid/dd_close.c
new file mode 100644
index 0000000..74961a1
--- /dev/null
+++ b/src/libunixonacid/dd_close.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/djbunix.h>
+#include <skalibs/unix-transactional.h>
+
+int dd_close (dirdescriptor_t_ref dd)
+{
+ return (fd_close(dd->fd) >= 0) ;
+}
diff --git a/src/libunixonacid/dd_commit.c b/src/libunixonacid/dd_commit.c
new file mode 100644
index 0000000..b55addb
--- /dev/null
+++ b/src/libunixonacid/dd_commit.c
@@ -0,0 +1,68 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h> /* for rename() */
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/random.h>
+#include <skalibs/unix-transactional.h>
+
+static char const *mybasename (char const *s, unsigned int len)
+{
+ register unsigned int i = len ;
+ while (i--) if (s[i] == '/') return s + i + 1 ;
+ return s ;
+}
+
+int dd_commit (dirdescriptor_t_ref dd)
+{
+ dirdescriptor_t zero = DIRDESCRIPTOR_ZERO ;
+ unsigned int len = str_len(dd->lnkfn) ;
+ unsigned int oldbase = dd->new.len ;
+ unsigned int newlnkbase ;
+ char const *lnkbn = mybasename(dd->lnkfn, len) ;
+ if (!sadirname(&dd->new, dd->lnkfn, len)) return 0 ;
+ if (!stralloc_catb(&dd->new, "/", 1)) goto fail ;
+ if (sareadlink(&dd->new, dd->lnkfn) < 0)
+ {
+ unsigned int lnkbnbase = dd->new.len ;
+ if (errno != EINVAL) goto fail ;
+ if (!stralloc_cats(&dd->new, lnkbn)) goto fail ;
+ if (random_sauniquename(&dd->new, 8) < 0) goto fail ;
+ if (!stralloc_0(&dd->new)) goto fail ;
+ if (rename(dd->lnkfn, dd->new.s + oldbase) < 0) goto fail ;
+ /* /!\ race condition right here: there's no lnkfn in the fs */
+ if (symlink(dd->new.s + lnkbnbase, dd->lnkfn) < 0) /* now that's VERY BAD if it fails */
+ {
+ register int e = errno ;
+ rename(dd->new.s + oldbase, dd->lnkfn) ; /* attempt to revert to initial situation */
+ errno = e ;
+ goto fail ; /* and hope for the best */
+ }
+ }
+ if (!stralloc_0(&dd->new)) goto fail ;
+ newlnkbase = dd->new.len ;
+ if (!stralloc_catb(&dd->new, dd->lnkfn, len)) goto fail ;
+ if (random_sauniquename(&dd->new, 8) < 0) goto fail ;
+ if (!stralloc_0(&dd->new)) goto fail ;
+ if (symlink(dd->new.s, dd->new.s + newlnkbase) < 0) goto fail ;
+ if (rename(dd->new.s + newlnkbase, dd->lnkfn) < 0)
+ {
+ register int e = errno ;
+ unlink(dd->new.s + newlnkbase) ;
+ errno = e ;
+ goto fail ;
+ }
+ fd_close(dd->fd) ;
+ dd->new.len = newlnkbase ;
+ rm_rf_in_tmp(&dd->new, oldbase) ;
+ stralloc_free(&dd->new) ;
+ *dd = zero ;
+ return 1 ;
+
+ fail:
+ dd->new.len = oldbase ;
+ return 0 ;
+}
diff --git a/src/libunixonacid/dd_commit_devino.c b/src/libunixonacid/dd_commit_devino.c
new file mode 100644
index 0000000..481db19
--- /dev/null
+++ b/src/libunixonacid/dd_commit_devino.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <skalibs/uint64.h>
+#include <skalibs/unix-transactional.h>
+
+int dd_commit_devino (dirdescriptor_t_ref dd, uint64 *dev, uint64 *ino)
+{
+ struct stat st ;
+ if (fstat(dd->fd, &st) < 0) return 0 ;
+ if (!dd_commit(dd)) return 0 ;
+ *dev = (uint64)st.st_dev ;
+ *ino = (uint64)st.st_ino ;
+ return 1 ;
+}
diff --git a/src/libunixonacid/dd_open_read.c b/src/libunixonacid/dd_open_read.c
new file mode 100644
index 0000000..1996297
--- /dev/null
+++ b/src/libunixonacid/dd_open_read.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/djbunix.h>
+#include <skalibs/unix-transactional.h>
+
+int dd_open_read (dirdescriptor_t_ref dd, char const *path)
+{
+ dirdescriptor_t d = DIRDESCRIPTOR_ZERO ;
+ d.fd = open_read(path) ;
+ if (d.fd < 0) return 0 ;
+ d.lnkfn = path ;
+ *dd = d ;
+ return 1 ;
+}
diff --git a/src/libunixonacid/dd_open_write.c b/src/libunixonacid/dd_open_write.c
new file mode 100644
index 0000000..efee60f
--- /dev/null
+++ b/src/libunixonacid/dd_open_write.c
@@ -0,0 +1,34 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/random.h>
+#include <skalibs/unix-transactional.h>
+
+int dd_open_write (dirdescriptor_t_ref dd, char const *lnkfn, unsigned int mode)
+{
+ dirdescriptor_t d = DIRDESCRIPTOR_ZERO ;
+ d.lnkfn = lnkfn ;
+ if (!stralloc_cats(&d.new, lnkfn)) return 0 ;
+ if (random_sauniquename(&d.new, 8) < 0) goto fail ;
+ if (!stralloc_0(&d.new)) goto fail ;
+ if (mkdir(d.new.s, mode) < 0) goto fail ;
+ d.fd = open_read(d.new.s) ;
+ if (d.fd < 0)
+ {
+ register int e = errno ;
+ rmdir(d.new.s) ;
+ errno = e ;
+ goto fail ;
+ }
+ *dd = d ;
+ return 1 ;
+
+ fail:
+ stralloc_free(&d.new) ;
+ return 0 ;
+}
diff --git a/src/libunixonacid/kolbak_call.c b/src/libunixonacid/kolbak_call.c
new file mode 100644
index 0000000..b7b97c0
--- /dev/null
+++ b/src/libunixonacid/kolbak_call.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/unixmessage.h>
+#include <skalibs/kolbak.h>
+
+int kolbak_call (unixmessage_t const *m, kolbak_queue_t *q)
+{
+ if (q->head == q->tail) return (errno = EILSEQ, 0) ;
+ if (!(*q->x[q->head].f)(m, q->x[q->head].data)) return 0 ;
+ q->head = (q->head + 1) % q->n ;
+ return 1 ;
+}
diff --git a/src/libunixonacid/kolbak_enqueue.c b/src/libunixonacid/kolbak_enqueue.c
new file mode 100644
index 0000000..80fce01
--- /dev/null
+++ b/src/libunixonacid/kolbak_enqueue.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/kolbak.h>
+#include <skalibs/unixmessage.h>
+
+int kolbak_enqueue (kolbak_queue_t *q, unixmessage_handler_func_t *f, void *data)
+{
+ register unsigned int newtail = (q->tail + 1) % q->n ;
+ if (newtail == q->head) return (errno = ENOBUFS, 0) ;
+ q->x[q->tail].f = f ;
+ q->x[q->tail].data = data ;
+ q->tail = newtail ;
+ return 1 ;
+}
diff --git a/src/libunixonacid/kolbak_queue_init.c b/src/libunixonacid/kolbak_queue_init.c
new file mode 100644
index 0000000..6d91232
--- /dev/null
+++ b/src/libunixonacid/kolbak_queue_init.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/kolbak.h>
+
+int kolbak_queue_init (kolbak_queue_t *q, kolbak_closure_t *s, unsigned int len)
+{
+ if (len < 2) return (errno = EINVAL, 0) ;
+ q->x = s ;
+ q->n = len ;
+ q->head = 0 ;
+ q->tail = 0 ;
+ return 1 ;
+}
diff --git a/src/libunixonacid/kolbak_unenqueue.c b/src/libunixonacid/kolbak_unenqueue.c
new file mode 100644
index 0000000..894beea
--- /dev/null
+++ b/src/libunixonacid/kolbak_unenqueue.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/kolbak.h>
+
+int kolbak_unenqueue (kolbak_queue_t *q)
+{
+ if (q->head == q->tail) return (errno = EINVAL, 0) ;
+ q->tail = (q->tail + q->n - 1) % q->n ;
+ return 1 ;
+}
diff --git a/src/libunixonacid/mkdir_unique.c b/src/libunixonacid/mkdir_unique.c
new file mode 100644
index 0000000..523ecef
--- /dev/null
+++ b/src/libunixonacid/mkdir_unique.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <sys/stat.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/random.h>
+#include <skalibs/unix-transactional.h>
+
+int mkdir_unique (stralloc *sa, char const *fn, unsigned int mode)
+{
+ unsigned int base = sa->len ;
+ int wasnull = !sa->s ;
+ if (!stralloc_cats(sa, fn)) return 0 ;
+ if (!stralloc_cats(sa, "/mkdir_unique")) goto fail ;
+ if (random_sauniquename(sa, 8) < 0) goto fail ;
+ if (!stralloc_0(sa)) goto fail ;
+ if (mkdir(sa->s + base, mode) < 0) goto fail ;
+ sa->len-- ;
+ return 1 ;
+
+ fail:
+ if (wasnull) stralloc_free(sa) ;
+ else sa->len = base ;
+ return 0 ;
+}
diff --git a/src/libunixonacid/netstring_timed_get.c b/src/libunixonacid/netstring_timed_get.c
new file mode 100644
index 0000000..04ace6c
--- /dev/null
+++ b/src/libunixonacid/netstring_timed_get.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/netstring.h>
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+#include <skalibs/unix-timed.h>
+
+int netstring_timed_get (buffer *b, stralloc *sa, tain_t const *deadline, tain_t *stamp)
+{
+ iopause_fd x = { .fd = buffer_fd(b), .events = IOPAUSE_READ } ;
+ unsigned int w = 0 ;
+ for (;;)
+ {
+ register int r = netstring_get(b, sa, &w) ;
+ if (r > 0) return r ;
+ if (r < 0) return 0 ;
+ r = iopause_stamp(&x, 1, deadline, stamp) ;
+ if (r < 0) return 0 ;
+ else if (!r) return (errno = ETIMEDOUT, 0) ;
+ }
+}
diff --git a/src/libunixonacid/open2_at.c b/src/libunixonacid/open2_at.c
new file mode 100644
index 0000000..4deb837
--- /dev/null
+++ b/src/libunixonacid/open2_at.c
@@ -0,0 +1,60 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASOPENAT
+
+#ifndef _ATFILE_SOURCE
+#define _ATFILE_SOURCE
+#endif
+
+#include <skalibs/nonposix.h>
+#include <fcntl.h>
+#include <skalibs/unix-transactional.h>
+
+int open2_at (int dirfd, char const *file, int flags)
+{
+ return openat(dirfd, file, flags) ;
+}
+
+#else
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/unix-transactional.h>
+
+int open2_at (int dirfd, char const *file, int flags)
+{
+ int fd ;
+ int fdhere = open_read(".") ;
+ if (fdhere < 0) return -1 ;
+ if (fd_chdir(dirfd) < 0)
+ {
+ register int e = errno ;
+ fd_close(fdhere) ;
+ errno = e ;
+ return -1 ;
+ }
+ fd = open2(file, flags) ;
+ if (fd < 0)
+ {
+ register int e = errno ;
+ fd_chdir(fdhere) ;
+ fd_close(fdhere) ;
+ errno = e ;
+ return -1 ;
+ }
+ if (fd_chdir(fdhere) < 0)
+ {
+ register int e = errno ;
+ fd_close(fdhere) ;
+ errno = e ;
+ return -1 ;
+ }
+ return fd ;
+}
+
+#endif
diff --git a/src/libunixonacid/open3_at.c b/src/libunixonacid/open3_at.c
new file mode 100644
index 0000000..d9c7222
--- /dev/null
+++ b/src/libunixonacid/open3_at.c
@@ -0,0 +1,60 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#ifdef SKALIBS_HASOPENAT
+
+#ifndef _ATFILE_SOURCE
+#define _ATFILE_SOURCE
+#endif
+
+#include <skalibs/nonposix.h>
+#include <fcntl.h>
+#include <skalibs/unix-transactional.h>
+
+int open3_at (int dirfd, char const *file, int flags, unsigned int mode)
+{
+ return openat(dirfd, file, flags, mode) ;
+}
+
+#else
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/unix-transactional.h>
+
+int open3_at (int dirfd, char const *file, int flags, unsigned int mode)
+{
+ int fd ;
+ int fdhere = open_read(".") ;
+ if (fdhere < 0) return -1 ;
+ if (fd_chdir(dirfd) < 0)
+ {
+ register int e = errno ;
+ fd_close(fdhere) ;
+ errno = e ;
+ return -1 ;
+ }
+ fd = open3(file, flags, mode) ;
+ if (fd < 0)
+ {
+ register int e = errno ;
+ fd_chdir(fdhere) ;
+ fd_close(fdhere) ;
+ errno = e ;
+ return -1 ;
+ }
+ if (fd_chdir(fdhere) < 0)
+ {
+ register int e = errno ;
+ fd_close(fdhere) ;
+ errno = e ;
+ return -1 ;
+ }
+ return fd ;
+}
+
+#endif
diff --git a/src/libunixonacid/open_appendat.c b/src/libunixonacid/open_appendat.c
new file mode 100644
index 0000000..debfe8a
--- /dev/null
+++ b/src/libunixonacid/open_appendat.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <skalibs/unix-transactional.h>
+
+int open_appendat (int fd, char const *name)
+{
+ return open3_at(fd, name, O_WRONLY | O_NONBLOCK | O_APPEND | O_CREAT, 0666) ;
+}
diff --git a/src/libunixonacid/open_appendatb.c b/src/libunixonacid/open_appendatb.c
new file mode 100644
index 0000000..5a75120
--- /dev/null
+++ b/src/libunixonacid/open_appendatb.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/djbunix.h>
+#include <skalibs/unix-transactional.h>
+
+int open_appendatb (int dirfd, char const *name)
+{
+ int fd = open_appendat(dirfd, name) ;
+ if (fd < 0) return -1 ;
+ if (ndelay_off(fd) < 0) return -1 ;
+ return fd ;
+}
diff --git a/src/libunixonacid/open_readat.c b/src/libunixonacid/open_readat.c
new file mode 100644
index 0000000..7764ffc
--- /dev/null
+++ b/src/libunixonacid/open_readat.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <skalibs/unix-transactional.h>
+
+int open_readat (int fd, char const *name)
+{
+ return open2_at(fd, name, O_RDONLY | O_NONBLOCK) ;
+}
diff --git a/src/libunixonacid/open_readatb.c b/src/libunixonacid/open_readatb.c
new file mode 100644
index 0000000..6e4cd0f
--- /dev/null
+++ b/src/libunixonacid/open_readatb.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/djbunix.h>
+#include <skalibs/unix-transactional.h>
+
+int open_readatb (int dirfd, char const *name)
+{
+ int fd = open_readat(dirfd, name) ;
+ if (fd < 0) return -1 ;
+ if (ndelay_off(fd) < 0) return -1 ;
+ return fd ;
+}
diff --git a/src/libunixonacid/open_truncat.c b/src/libunixonacid/open_truncat.c
new file mode 100644
index 0000000..2a868d2
--- /dev/null
+++ b/src/libunixonacid/open_truncat.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <skalibs/unix-transactional.h>
+
+int open_truncat (int fd, char const *name)
+{
+ return open3_at(fd, name, O_WRONLY | O_NONBLOCK | O_TRUNC | O_CREAT, 0666) ;
+}
diff --git a/src/libunixonacid/open_truncatb.c b/src/libunixonacid/open_truncatb.c
new file mode 100644
index 0000000..fc4d685
--- /dev/null
+++ b/src/libunixonacid/open_truncatb.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/djbunix.h>
+#include <skalibs/unix-transactional.h>
+
+int open_truncatb (int dirfd, char const *name)
+{
+ int fd = open_truncat(dirfd, name) ;
+ if (fd < 0) return -1 ;
+ if (ndelay_off(fd) < 0) return -1 ;
+ return fd ;
+}
diff --git a/src/libunixonacid/open_writeat.c b/src/libunixonacid/open_writeat.c
new file mode 100644
index 0000000..6b1a173
--- /dev/null
+++ b/src/libunixonacid/open_writeat.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <skalibs/unix-transactional.h>
+
+int open_writeat (int fd, char const *name)
+{
+ return open2_at(fd, name, O_WRONLY | O_NONBLOCK) ;
+}
diff --git a/src/libunixonacid/open_writeatb.c b/src/libunixonacid/open_writeatb.c
new file mode 100644
index 0000000..fd75365
--- /dev/null
+++ b/src/libunixonacid/open_writeatb.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/djbunix.h>
+#include <skalibs/unix-transactional.h>
+
+int open_writeatb (int dirfd, char const *name)
+{
+ int fd = open_writeat(dirfd, name) ;
+ if (fd < 0) return -1 ;
+ if (ndelay_off(fd) < 0) return -1 ;
+ return fd ;
+}
diff --git a/src/libunixonacid/opengetlnclose.c b/src/libunixonacid/opengetlnclose.c
new file mode 100644
index 0000000..ca1959e
--- /dev/null
+++ b/src/libunixonacid/opengetlnclose.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/skamisc.h>
+#include <skalibs/unix-transactional.h>
+
+int opengetlnclose (char const *fn, stralloc *sa, int sep)
+{
+ char buf[BUFFER_INSIZE] ;
+ buffer b ;
+ register int r ;
+ register int e ;
+ int fd = open_readb(fn) ;
+ if (fd < 0) return -1 ;
+ buffer_init(&b, &buffer_read, fd, buf, BUFFER_INSIZE) ;
+ r = skagetln(&b, sa, sep) ;
+ e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ return r ;
+}
diff --git a/src/libunixonacid/opengetlnclose_at.c b/src/libunixonacid/opengetlnclose_at.c
new file mode 100644
index 0000000..be2ffaf
--- /dev/null
+++ b/src/libunixonacid/opengetlnclose_at.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/skamisc.h>
+#include <skalibs/unix-transactional.h>
+
+int opengetlnclose_at (int dirfd, char const *fn, stralloc *sa, int sep)
+{
+ char buf[BUFFER_INSIZE] ;
+ buffer b ;
+ register int r ;
+ register int e ;
+ int fd = open_readatb(dirfd, fn) ;
+ if (fd < 0) return -1 ;
+ buffer_init(&b, &buffer_read, fd, buf, BUFFER_INSIZE) ;
+ r = skagetln(&b, sa, sep) ;
+ e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ return r ;
+}
diff --git a/src/libunixonacid/openreadnclose_at.c b/src/libunixonacid/openreadnclose_at.c
new file mode 100644
index 0000000..4e8209d
--- /dev/null
+++ b/src/libunixonacid/openreadnclose_at.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/unix-transactional.h>
+
+unsigned int openreadnclose_at (int dirfd, char const *file, char *s, unsigned int n)
+{
+ register unsigned int r ;
+ register int e ;
+ int fd = open_readatb(dirfd, file) ;
+ if (fd < 0) return 0 ;
+ r = allread(fd, s, n) ;
+ e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ return r ;
+}
diff --git a/src/libunixonacid/openslurpclose_at.c b/src/libunixonacid/openslurpclose_at.c
new file mode 100644
index 0000000..cf2f8ee
--- /dev/null
+++ b/src/libunixonacid/openslurpclose_at.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/unix-transactional.h>
+
+int openslurpclose_at (int dirfd, char const *fn, stralloc *sa)
+{
+ int fd = open_readatb(dirfd, fn) ;
+ if (fd < 0) return 0 ;
+ if (!slurp(sa, fd))
+ {
+ register int e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ return 0 ;
+ }
+ fd_close(fd) ;
+ return 1 ;
+}
diff --git a/src/libunixonacid/openwritenclose.c b/src/libunixonacid/openwritenclose.c
new file mode 100644
index 0000000..09149e2
--- /dev/null
+++ b/src/libunixonacid/openwritenclose.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/skamisc.h>
+#include <skalibs/unix-transactional.h>
+
+int openwritenclose (char const *fn, char const *s, unsigned int len)
+{
+ return openwritenclose_tmp(fn, s, len, &satmp) ;
+}
diff --git a/src/libunixonacid/openwritenclose_at.c b/src/libunixonacid/openwritenclose_at.c
new file mode 100644
index 0000000..fe92a5e
--- /dev/null
+++ b/src/libunixonacid/openwritenclose_at.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/unix-transactional.h>
+
+unsigned int openwritenclose_at (int dirfd, char const *file, char const *s, unsigned int n)
+{
+ register unsigned int r ;
+ int fd = open_truncatb(dirfd, file) ;
+ if (fd < 0) return 0 ;
+ r = allwrite(fd, s, n) ;
+ if ((r < n) || (fsync(fd) < 0))
+ {
+ register int e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ return r ;
+ }
+ fd_close(fd) ;
+ return r ;
+}
diff --git a/src/libunixonacid/openwritenclose_devino.c b/src/libunixonacid/openwritenclose_devino.c
new file mode 100644
index 0000000..5edc646
--- /dev/null
+++ b/src/libunixonacid/openwritenclose_devino.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/uint64.h>
+#include <skalibs/skamisc.h>
+#include <skalibs/unix-transactional.h>
+
+int openwritenclose_devino (char const *fn, char const *s, unsigned int len, uint64 *dev, uint64 *ino)
+{
+ return openwritenclose_devino_tmp(fn, s, len, dev, ino, &satmp) ;
+}
diff --git a/src/libunixonacid/openwritenclose_devino_tmp.c b/src/libunixonacid/openwritenclose_devino_tmp.c
new file mode 100644
index 0000000..343da65
--- /dev/null
+++ b/src/libunixonacid/openwritenclose_devino_tmp.c
@@ -0,0 +1,35 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h> /* for rename() */
+#include <skalibs/uint64.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/random.h>
+#include <skalibs/unix-transactional.h>
+
+int openwritenclose_devino_tmp (char const *fn, char const *s, unsigned int len, uint64 *dev, uint64 *ino, stralloc *tmp)
+{
+ uint64 tmpdev, tmpino ;
+ unsigned int base = tmp->len ;
+ if (!stralloc_cats(tmp, fn)) return 0 ;
+ if (random_sauniquename(tmp, 8) < 0) goto fail ;
+ if (!stralloc_0(tmp)) goto fail ;
+ if (!openwritenclose_unsafe_devino_sync(tmp->s + base, s, len, &tmpdev, &tmpino)) goto fail ;
+ if (rename(tmp->s + base, fn) < 0)
+ {
+ register int e = errno ;
+ unlink(tmp->s + base) ;
+ errno = e ;
+ goto fail ;
+ }
+ tmp->len = base ;
+ *dev = tmpdev ;
+ *ino = tmpino ;
+ return 1 ;
+
+ fail:
+ tmp->len = base ;
+ return 0 ;
+}
diff --git a/src/libunixonacid/openwritenclose_tmp.c b/src/libunixonacid/openwritenclose_tmp.c
new file mode 100644
index 0000000..1ada80b
--- /dev/null
+++ b/src/libunixonacid/openwritenclose_tmp.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/uint64.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/unix-transactional.h>
+
+int openwritenclose_tmp (char const *fn, char const *s, unsigned int len, stralloc *tmp)
+{
+ uint64 dev, ino ;
+ return openwritenclose_devino_tmp(fn, s, len, &dev, &ino, tmp) ;
+}
diff --git a/src/libunixonacid/skaclient-internal.h b/src/libunixonacid/skaclient-internal.h
new file mode 100644
index 0000000..f0a9bfe
--- /dev/null
+++ b/src/libunixonacid/skaclient-internal.h
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#ifndef SKACLIENT_INTERNAL_H
+#define SKACLIENT_INTERNAL_H
+
+#include <skalibs/kolbak.h>
+#include <skalibs/skaclient.h>
+#include <skalibs/unixmessage.h>
+
+extern int skaclient_init (skaclient_t *, int, char *, unsigned int, char *, unsigned int, char *, unsigned int, char *, unsigned int, kolbak_closure_t *, unsigned int, char const *, unsigned int) ;
+extern int skaclient_start_async_th (skaclient_t *, char *, unsigned int, char *, unsigned int, char *, unsigned int, char *, unsigned int, kolbak_closure_t *, unsigned int, char const *, char const *, unsigned int) ;
+extern int skaclient_startf_async_th (skaclient_t *, char *, unsigned int, char *, unsigned int, char *, unsigned int, char *, unsigned int, kolbak_closure_t *, unsigned int, char const *, char const *const *, char const *const *, uint32, char const *, unsigned int) ;
+extern int skaclient_start_cb (unixmessage_t const *, skaclient_cbdata_t *) ;
+
+#endif
diff --git a/src/libunixonacid/skaclient_default_cb.c b/src/libunixonacid/skaclient_default_cb.c
new file mode 100644
index 0000000..10934e5
--- /dev/null
+++ b/src/libunixonacid/skaclient_default_cb.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/error.h>
+#include <skalibs/skaclient.h>
+#include <skalibs/unixmessage.h>
+
+int skaclient_default_cb (unixmessage_t const *m, void *p)
+{
+ unsigned char *err = p ;
+ if (m->len != 1 || m->nfds) return (errno = EPROTO, 0) ;
+ *err = m->s[0] ;
+ return 1 ;
+}
diff --git a/src/libunixonacid/skaclient_end.c b/src/libunixonacid/skaclient_end.c
new file mode 100644
index 0000000..23dafab
--- /dev/null
+++ b/src/libunixonacid/skaclient_end.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <skalibs/djbunix.h>
+#include <skalibs/skaclient.h>
+#include <skalibs/unixmessage.h>
+
+void skaclient_end (skaclient_t *a)
+{
+ fd_close(a->syncout.fd) ;
+ fd_close(a->asyncout.fd) ;
+ unixmessage_sender_free(&a->syncout) ;
+ unixmessage_sender_free(&a->asyncout) ;
+ unixmessage_receiver_free(&a->syncin) ;
+ unixmessage_receiver_free(&a->asyncin) ;
+ if (a->pid && a->options & SKACLIENT_OPTION_WAITPID)
+ {
+ int wstat ;
+ waitpid_nointr(a->pid, &wstat, 0) ;
+ }
+ *a = skaclient_zero ;
+}
diff --git a/src/libunixonacid/skaclient_init.c b/src/libunixonacid/skaclient_init.c
new file mode 100644
index 0000000..89ed59c
--- /dev/null
+++ b/src/libunixonacid/skaclient_init.c
@@ -0,0 +1,32 @@
+/* ISC license. */
+
+#include <skalibs/kolbak.h>
+#include <skalibs/skaclient.h>
+#include <skalibs/unixmessage.h>
+#include "skaclient-internal.h"
+
+int skaclient_init (
+ skaclient_t *a,
+ int fd,
+ char *bufss,
+ unsigned int bufsn,
+ char *auxbufss,
+ unsigned int auxbufsn,
+ char *bufas,
+ unsigned int bufan,
+ char *auxbufas,
+ unsigned int auxbufan,
+ kolbak_closure_t *q,
+ unsigned int qlen,
+ char const *before,
+ unsigned int beforelen)
+{
+ unixmessage_t msg = { .s = (char *)before, .len = beforelen, .fds = 0, .nfds = 0 } ;
+ if (!unixmessage_receiver_init(&a->syncin, fd, bufss, bufsn, auxbufss, auxbufsn)
+ || !unixmessage_receiver_init(&a->asyncin, -1, bufas, bufan, auxbufas, auxbufan)
+ || !kolbak_queue_init(&a->kq, q, qlen)) return 0 ;
+ unixmessage_sender_init(&a->syncout, fd) ;
+ unixmessage_sender_init(&a->asyncout, -1) ;
+ if (!unixmessage_put(&a->syncout, &msg)) return 0 ;
+ return 1 ;
+}
diff --git a/src/libunixonacid/skaclient_put.c b/src/libunixonacid/skaclient_put.c
new file mode 100644
index 0000000..5e3dc92
--- /dev/null
+++ b/src/libunixonacid/skaclient_put.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/skaclient.h>
+#include <skalibs/unixmessage.h>
+
+int skaclient_put (skaclient_t *a, char const *s, unsigned int len, unixmessage_handler_func_t *cb, void *result)
+{
+ unixmessage_t m = { .s = (char *)s, .len = len, .fds = 0, .nfds = 0 } ;
+ return skaclient_putmsg(a, &m, cb, result) ;
+}
diff --git a/src/libunixonacid/skaclient_putmsg.c b/src/libunixonacid/skaclient_putmsg.c
new file mode 100644
index 0000000..9dcb37d
--- /dev/null
+++ b/src/libunixonacid/skaclient_putmsg.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <skalibs/kolbak.h>
+#include <skalibs/skaclient.h>
+#include <skalibs/unixmessage.h>
+
+int skaclient_putmsg_and_close (skaclient_t *a, unixmessage_t const *m, unsigned char const *bits, unixmessage_handler_func_t *cb, void *result)
+{
+ if (!kolbak_enqueue(&a->kq, cb, result)) return 0 ;
+ if (!unixmessage_put_and_close(&a->syncout, m, bits))
+ {
+ kolbak_unenqueue(&a->kq) ;
+ return 0 ;
+ }
+ return 1 ;
+}
diff --git a/src/libunixonacid/skaclient_putmsgv.c b/src/libunixonacid/skaclient_putmsgv.c
new file mode 100644
index 0000000..e53935a
--- /dev/null
+++ b/src/libunixonacid/skaclient_putmsgv.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <skalibs/kolbak.h>
+#include <skalibs/skaclient.h>
+#include <skalibs/unixmessage.h>
+
+int skaclient_putmsgv_and_close (skaclient_t *a, unixmessage_v_t const *m, unsigned char const *bits, unixmessage_handler_func_t *cb, void *result)
+{
+ if (!kolbak_enqueue(&a->kq, cb, result)) return 0 ;
+ if (!unixmessage_putv_and_close(&a->syncout, m, bits))
+ {
+ kolbak_unenqueue(&a->kq) ;
+ return 0 ;
+ }
+ return 1 ;
+}
diff --git a/src/libunixonacid/skaclient_putv.c b/src/libunixonacid/skaclient_putv.c
new file mode 100644
index 0000000..c41b092
--- /dev/null
+++ b/src/libunixonacid/skaclient_putv.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/siovec.h>
+#include <skalibs/skaclient.h>
+#include <skalibs/unixmessage.h>
+
+int skaclient_putv (skaclient_t *a, siovec_t const *v, unsigned int vlen, unixmessage_handler_func_t *cb, void *result)
+{
+ unixmessage_v_t m = { .v = (siovec_t *)v, .vlen = vlen, .fds = 0, .nfds = 0 } ;
+ return skaclient_putmsgv(a, &m, cb, result) ;
+}
diff --git a/src/libunixonacid/skaclient_send.c b/src/libunixonacid/skaclient_send.c
new file mode 100644
index 0000000..8bd31ab
--- /dev/null
+++ b/src/libunixonacid/skaclient_send.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/skaclient.h>
+#include <skalibs/tai.h>
+#include <skalibs/unixmessage.h>
+
+int skaclient_send (skaclient_t *a, char const *s, unsigned int len, unixmessage_handler_func_t *cb, void *result, tain_t const *deadline, tain_t *stamp)
+{
+ unixmessage_t m = { .s = (char *)s, .len = len, .fds = 0, .nfds = 0 } ;
+ return skaclient_sendmsg(a, &m, cb, result, deadline, stamp) ;
+}
diff --git a/src/libunixonacid/skaclient_sendmsg.c b/src/libunixonacid/skaclient_sendmsg.c
new file mode 100644
index 0000000..3f88ec7
--- /dev/null
+++ b/src/libunixonacid/skaclient_sendmsg.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/skaclient.h>
+#include <skalibs/tai.h>
+#include <skalibs/unixmessage.h>
+
+int skaclient_sendmsg_and_close (skaclient_t *a, unixmessage_t const *m, unsigned char const *bits, unixmessage_handler_func_t *cb, void *result, tain_t const *deadline, tain_t *stamp)
+{
+ register int r ;
+ if (!skaclient_putmsg_and_close(a, m, bits, cb, result)) return 0 ;
+ if (!skaclient_timed_flush(a, deadline, stamp)) return 0 ;
+ r = skaclient_timed_supdate(a, deadline, stamp) ;
+ return r < 0 ? 0 : !r ? (errno = EPIPE, 0) : 1 ;
+}
diff --git a/src/libunixonacid/skaclient_sendmsgv.c b/src/libunixonacid/skaclient_sendmsgv.c
new file mode 100644
index 0000000..ac4bcdb
--- /dev/null
+++ b/src/libunixonacid/skaclient_sendmsgv.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/skaclient.h>
+#include <skalibs/tai.h>
+#include <skalibs/unixmessage.h>
+
+int skaclient_sendmsgv_and_close (skaclient_t *a, unixmessage_v_t const *m, unsigned char const *bits, unixmessage_handler_func_t *cb, void *result, tain_t const *deadline, tain_t *stamp)
+{
+ register int r ;
+ if (!skaclient_putmsgv_and_close(a, m, bits, cb, result)) return 0 ;
+ if (!skaclient_timed_flush(a, deadline, stamp)) return 0 ;
+ r = skaclient_timed_supdate(a, deadline, stamp) ;
+ return r < 0 ? 0 : !r ? (errno = EPIPE, 0) : 1 ;
+}
diff --git a/src/libunixonacid/skaclient_sendv.c b/src/libunixonacid/skaclient_sendv.c
new file mode 100644
index 0000000..a140768
--- /dev/null
+++ b/src/libunixonacid/skaclient_sendv.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/siovec.h>
+#include <skalibs/skaclient.h>
+#include <skalibs/tai.h>
+#include <skalibs/unixmessage.h>
+
+int skaclient_sendv (skaclient_t *a, siovec_t const *v, unsigned int vlen, unixmessage_handler_func_t *cb, void *result, tain_t const *deadline, tain_t *stamp)
+{
+ unixmessage_v_t m = { .v = (siovec_t *)v, .vlen = vlen, .fds = 0, .nfds = 0 } ;
+ return skaclient_sendmsgv(a, &m, cb, result, deadline, stamp) ;
+}
diff --git a/src/libunixonacid/skaclient_server_ack.c b/src/libunixonacid/skaclient_server_ack.c
new file mode 100644
index 0000000..31ee9fe
--- /dev/null
+++ b/src/libunixonacid/skaclient_server_ack.c
@@ -0,0 +1,30 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/error.h>
+#include <skalibs/skaclient.h>
+#include <skalibs/unixmessage.h>
+#include <skalibs/webipc.h>
+
+int skaclient_server_ack (unixmessage_t const *clientmsg, unixmessage_sender_t *out, unixmessage_sender_t *asyncout, char const *before, unsigned int beforelen, char const *after, unsigned int afterlen)
+{
+ int fd[2] ;
+ unixmessage_t m = { .s = (char *)after, .len = afterlen, .fds = fd, .nfds = 1 } ;
+ static unsigned char const bits = 0xff ;
+ if (clientmsg->nfds
+ || clientmsg->len != beforelen
+ || byte_diff(clientmsg->s, beforelen, before)) return (errno = EPROTO, 0) ;
+ if (ipc_pair_nbcoe(fd) < 0) return 0 ;
+ unixmessage_sender_init(asyncout, fd[1]) ;
+ if (!unixmessage_put_and_close(out, &m, &bits))
+ {
+ int e = errno ;
+ fd_close(fd[1]) ;
+ fd_close(fd[0]) ;
+ errno = e ;
+ return 0 ;
+ }
+ return 1 ;
+}
diff --git a/src/libunixonacid/skaclient_server_bidi_ack.c b/src/libunixonacid/skaclient_server_bidi_ack.c
new file mode 100644
index 0000000..eede82c
--- /dev/null
+++ b/src/libunixonacid/skaclient_server_bidi_ack.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/skaclient.h>
+#include <skalibs/unixmessage.h>
+
+int skaclient_server_bidi_ack (unixmessage_t const *clientmsg, unixmessage_sender_t *out, unixmessage_sender_t *asyncout, unixmessage_receiver_t *asyncin, char *mainbuf, unsigned int mainlen, char *auxbuf, unsigned int auxlen, char const *before, unsigned int beforelen, char const *after, unsigned int afterlen)
+{
+ if (!unixmessage_receiver_init(asyncin, -1, mainbuf, mainlen, auxbuf, auxlen)) return 0 ;
+ if (!skaclient_server_ack(clientmsg, out, asyncout, before, beforelen, after, afterlen)) return 0 ;
+ asyncin->mainb.fd = unixmessage_sender_fd(asyncout) ;
+ return 1 ;
+}
diff --git a/src/libunixonacid/skaclient_server_init.c b/src/libunixonacid/skaclient_server_init.c
new file mode 100644
index 0000000..bd7c143
--- /dev/null
+++ b/src/libunixonacid/skaclient_server_init.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/skaclient.h>
+#include <skalibs/tai.h>
+#include <skalibs/unixmessage.h>
+
+int skaclient_server_init (unixmessage_receiver_t *in, char *mainbuf, unsigned int mainlen, char *auxbuf, unsigned int auxlen, unixmessage_sender_t *out, unixmessage_sender_t *asyncout, char const *before, unsigned int beforelen, char const *after, unsigned int afterlen, tain_t const *deadline, tain_t *stamp)
+{
+ unixmessage_t m ;
+ if (!unixmessage_receiver_init(in, 0, mainbuf, mainlen, auxbuf, auxlen)) return 0 ;
+ unixmessage_sender_init(out, 1) ;
+ if (unixmessage_timed_receive(in, &m, deadline, stamp) < 0) return 0 ;
+ if (!skaclient_server_ack(&m, out, asyncout, before, beforelen, after, afterlen)) return 0 ;
+ return unixmessage_sender_timed_flush(out, deadline, stamp) ;
+}
diff --git a/src/libunixonacid/skaclient_start.c b/src/libunixonacid/skaclient_start.c
new file mode 100644
index 0000000..b17750b
--- /dev/null
+++ b/src/libunixonacid/skaclient_start.c
@@ -0,0 +1,43 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/kolbak.h>
+#include <skalibs/skaclient.h>
+#include <skalibs/tai.h>
+#include "skaclient-internal.h"
+
+int skaclient_start (
+ skaclient_t *a,
+ char *bufss,
+ unsigned int bufsn,
+ char *auxbufss,
+ unsigned int auxbufsn,
+ char *bufas,
+ unsigned int bufan,
+ char *auxbufas,
+ unsigned int auxbufan,
+ kolbak_closure_t *q,
+ unsigned int qlen,
+ char const *path,
+ char const *before,
+ unsigned int beforelen,
+ char const *after,
+ unsigned int afterlen,
+ tain_t const *deadline,
+ tain_t *stamp)
+{
+ skaclient_cbdata_t blah ;
+ unixmessage_t m ;
+ register int r ;
+ if (!skaclient_start_async(a, bufss, bufsn, auxbufss, auxbufsn, bufas, bufan, auxbufas, auxbufan, q, qlen, path, before, beforelen, after, afterlen, &blah)) return 0 ;
+ r = unixmessage_timed_receive(&a->syncin, &m, deadline, stamp) ;
+ if (r < 1)
+ {
+ int e = errno ;
+ if (!r) e = EPIPE ;
+ skaclient_end(a) ;
+ errno = e ;
+ return 0 ;
+ }
+ return kolbak_call(&m, &a->kq) ;
+}
diff --git a/src/libunixonacid/skaclient_start_async.c b/src/libunixonacid/skaclient_start_async.c
new file mode 100644
index 0000000..4dbbf1c
--- /dev/null
+++ b/src/libunixonacid/skaclient_start_async.c
@@ -0,0 +1,52 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/error.h>
+#include <skalibs/kolbak.h>
+#include <skalibs/skaclient.h>
+#include <skalibs/unixmessage.h>
+#include <skalibs/webipc.h>
+#include "skaclient-internal.h"
+
+int skaclient_start_async (
+ skaclient_t *a,
+ char *bufss,
+ unsigned int bufsn,
+ char *auxbufss,
+ unsigned int auxbufsn,
+ char *bufas,
+ unsigned int bufan,
+ char *auxbufas,
+ unsigned int auxbufan,
+ kolbak_closure_t *q,
+ unsigned int qlen,
+ char const *path,
+ char const *before,
+ unsigned int beforelen,
+ char const *after,
+ unsigned int afterlen,
+ skaclient_cbdata_t *blah)
+{
+ int fd = ipc_stream_nbcoe() ;
+ if (fd < 0) return 0 ;
+ if ((!ipc_connect(fd, path) && !error_isalready(errno))
+ || !skaclient_init(a, fd, bufss, bufsn, auxbufss, auxbufsn, bufas, bufan, auxbufas, auxbufan, q, qlen, before, beforelen))
+ {
+ register int e = errno ;
+ fd_close(fd) ;
+ errno = e ;
+ return 0 ;
+ }
+ a->pid = 0 ;
+ a->options = 0 ;
+ if (!kolbak_enqueue(&a->kq, (unixmessage_handler_func_t_ref)&skaclient_start_cb, blah))
+ {
+ skaclient_end(a) ;
+ return 0 ;
+ }
+ blah->asyncin = &a->asyncin ;
+ blah->asyncout = &a->asyncout ;
+ blah->after = after ;
+ blah->afterlen = afterlen ;
+ return 1 ;
+}
diff --git a/src/libunixonacid/skaclient_start_cb.c b/src/libunixonacid/skaclient_start_cb.c
new file mode 100644
index 0000000..6e641e2
--- /dev/null
+++ b/src/libunixonacid/skaclient_start_cb.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/error.h>
+#include <skalibs/skaclient.h>
+#include <skalibs/unixmessage.h>
+#include "skaclient-internal.h"
+
+int skaclient_start_cb (unixmessage_t const *m, skaclient_cbdata_t *blah)
+{
+ if (m->len != blah->afterlen
+ || byte_diff(m->s, m->len, blah->after)
+ || m->nfds != 1) return (errno = EPROTO, 0) ;
+ blah->asyncin->mainb.fd = m->fds[0] ;
+ blah->asyncout->fd = m->fds[0] ;
+ return 1 ;
+}
diff --git a/src/libunixonacid/skaclient_startf.c b/src/libunixonacid/skaclient_startf.c
new file mode 100644
index 0000000..aa36323
--- /dev/null
+++ b/src/libunixonacid/skaclient_startf.c
@@ -0,0 +1,46 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/kolbak.h>
+#include <skalibs/skaclient.h>
+#include <skalibs/tai.h>
+#include "skaclient-internal.h"
+
+int skaclient_startf (
+ skaclient_t *a,
+ char *bufss,
+ unsigned int bufsn,
+ char *auxbufss,
+ unsigned int auxbufsn,
+ char *bufas,
+ unsigned int bufan,
+ char *auxbufas,
+ unsigned int auxbufan,
+ kolbak_closure_t *q,
+ unsigned int qlen,
+ char const *prog,
+ char const *const *argv,
+ char const *const *envp,
+ uint32 options,
+ char const *before,
+ unsigned int beforelen,
+ char const *after,
+ unsigned int afterlen,
+ tain_t const *deadline,
+ tain_t *stamp)
+{
+ skaclient_cbdata_t blah ;
+ unixmessage_t m ;
+ register int r ;
+ if (!skaclient_startf_async(a, bufss, bufsn, auxbufss, auxbufsn, bufas, bufan, auxbufas, auxbufan, q, qlen, prog, argv, envp, options, before, beforelen, after, afterlen, &blah)) return 0 ;
+ r = unixmessage_timed_receive(&a->syncin, &m, deadline, stamp) ;
+ if (r < 1)
+ {
+ int e = errno ;
+ if (!r) e = EPIPE ;
+ skaclient_end(a) ;
+ errno = e ;
+ return 0 ;
+ }
+ return kolbak_call(&m, &a->kq) ;
+}
diff --git a/src/libunixonacid/skaclient_startf_async.c b/src/libunixonacid/skaclient_startf_async.c
new file mode 100644
index 0000000..4077c1e
--- /dev/null
+++ b/src/libunixonacid/skaclient_startf_async.c
@@ -0,0 +1,61 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <signal.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/kolbak.h>
+#include <skalibs/skaclient.h>
+#include <skalibs/uint32.h>
+#include "skaclient-internal.h"
+
+int skaclient_startf_async (
+ skaclient_t *a,
+ char *bufss,
+ unsigned int bufsn,
+ char *auxbufss,
+ unsigned int auxbufsn,
+ char *bufas,
+ unsigned int bufan,
+ char *auxbufas,
+ unsigned int auxbufan,
+ kolbak_closure_t *q,
+ unsigned int qlen,
+ char const *prog,
+ char const *const *argv,
+ char const *const *envp,
+ uint32 options,
+ char const *before,
+ unsigned int beforelen,
+ char const *after,
+ unsigned int afterlen,
+ skaclient_cbdata_t *blah)
+{
+ int fd ;
+ pid_t pid = child_spawn(prog, argv, envp, &fd, 1) ;
+ if (!pid) return 0 ;
+ if (!skaclient_init(a, fd, bufss, bufsn, auxbufss, auxbufsn, bufas, bufan, auxbufas, auxbufan, q, qlen, before, beforelen))
+ {
+ register int e = errno ;
+ fd_close(fd) ;
+ if (options & SKACLIENT_OPTION_WAITPID)
+ {
+ int wstat ;
+ waitpid_nointr(a->pid, &wstat, 0) ;
+ }
+ errno = e ;
+ return 0 ;
+ }
+ a->pid = pid ;
+ a->options = options ;
+ if (!kolbak_enqueue(&a->kq, (unixmessage_handler_func_t_ref)&skaclient_start_cb, blah))
+ {
+ skaclient_end(a) ;
+ return 0 ;
+ }
+ blah->asyncin = &a->asyncin ;
+ blah->asyncout = &a->asyncout ;
+ blah->after = after ;
+ blah->afterlen = afterlen ;
+ return 1 ;
+}
diff --git a/src/libunixonacid/skaclient_zero.c b/src/libunixonacid/skaclient_zero.c
new file mode 100644
index 0000000..4bb85b5
--- /dev/null
+++ b/src/libunixonacid/skaclient_zero.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include <skalibs/skaclient.h>
+
+skaclient_t const skaclient_zero = SKACLIENT_ZERO ;
diff --git a/src/libunixonacid/timed_flush.c b/src/libunixonacid/timed_flush.c
new file mode 100644
index 0000000..2d60256
--- /dev/null
+++ b/src/libunixonacid/timed_flush.c
@@ -0,0 +1,26 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/error.h>
+#include <skalibs/bufalloc.h>
+#include <skalibs/functypes.h>
+#include <skalibs/iopause.h>
+#include <skalibs/tai.h>
+#include <skalibs/unix-timed.h>
+
+int timed_flush (void *b, initfunc_t_ref getfd, initfunc_t_ref isnonempty, initfunc_t_ref flush, tain_t const *deadline, tain_t *stamp)
+{
+ iopause_fd x = { .fd = (*getfd)(b), .events = IOPAUSE_WRITE, .revents = 0 } ;
+ while ((*isnonempty)(b))
+ {
+ register int r = iopause_stamp(&x, 1, deadline, stamp) ;
+ if (r < 0) return 0 ;
+ else if (!r) return (errno = ETIMEDOUT, 0) ;
+ else if (x.revents & IOPAUSE_WRITE)
+ {
+ if (!((*flush)(b)) && !error_isagain(errno)) return 0 ;
+ }
+ else if (x.revents & IOPAUSE_EXCEPT) return (*flush)(b) ;
+ }
+ return 1 ;
+}
diff --git a/src/libunixonacid/timed_get.c b/src/libunixonacid/timed_get.c
new file mode 100644
index 0000000..0a02382
--- /dev/null
+++ b/src/libunixonacid/timed_get.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/functypes.h>
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+#include <skalibs/unix-timed.h>
+
+int timed_get (void *b, initfunc_t *getfd, initfunc_t *get, tain_t const *deadline, tain_t *stamp)
+{
+ iopause_fd x = { .fd = (*getfd)(b), .events = IOPAUSE_READ, .revents = 0 } ;
+ register int r = (*get)(b) ;
+ while (!r)
+ {
+ r = iopause_stamp(&x, 1, deadline, stamp) ;
+ if (!r) return (errno = ETIMEDOUT, -1) ;
+ else if (r > 0 && x.revents & (IOPAUSE_READ | IOPAUSE_EXCEPT))
+ r = (*get)(b) ;
+ }
+ return unsanitize_read(r) ;
+}
diff --git a/src/libunixonacid/timed_getln.c b/src/libunixonacid/timed_getln.c
new file mode 100644
index 0000000..0c442de
--- /dev/null
+++ b/src/libunixonacid/timed_getln.c
@@ -0,0 +1,32 @@
+/* ISC license. */
+
+#include <skalibs/allreadwrite.h>
+#include <skalibs/buffer.h>
+#include <skalibs/functypes.h>
+#include <skalibs/skamisc.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/tai.h>
+#include <skalibs/unix-timed.h>
+
+struct blah_s
+{
+ buffer *b ;
+ stralloc *sa ;
+ char sep ;
+} ;
+
+static int getfd (struct blah_s *blah)
+{
+ return buffer_fd(blah->b) ;
+}
+
+static int get (struct blah_s *blah)
+{
+ return sanitize_read(skagetln(blah->b, blah->sa, blah->sep)) ;
+}
+
+int timed_getln (buffer *b, stralloc *sa, char sep, tain_t const *deadline, tain_t *stamp)
+{
+ struct blah_s blah = { .b = b, .sa = sa, .sep = sep } ;
+ return timed_get(&blah, (initfunc_t_ref)&getfd, (initfunc_t_ref)&get, deadline, stamp) ;
+}
diff --git a/src/libunixonacid/timed_getlnmax.c b/src/libunixonacid/timed_getlnmax.c
new file mode 100644
index 0000000..8953606
--- /dev/null
+++ b/src/libunixonacid/timed_getlnmax.c
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#include <skalibs/allreadwrite.h>
+#include <skalibs/buffer.h>
+#include <skalibs/functypes.h>
+#include <skalibs/skamisc.h>
+#include <skalibs/tai.h>
+#include <skalibs/unix-timed.h>
+
+struct blah_s
+{
+ buffer *b ;
+ char *d ;
+ unsigned int max ;
+ unsigned int w ;
+ char sep ;
+} ;
+
+static int getfd (struct blah_s *blah)
+{
+ return buffer_fd(blah->b) ;
+}
+
+static int get (struct blah_s *blah)
+{
+ return sanitize_read(getlnmax(blah->b, blah->d, blah->max, &blah->w, blah->sep)) ;
+}
+
+int timed_getlnmax (buffer *b, char *d, unsigned int max, unsigned int *w, char sep, tain_t const *deadline, tain_t *stamp)
+{
+ struct blah_s blah = { .b = b, .d = d, .max = max, .w = 0, .sep = sep } ;
+ return timed_get(&blah, (initfunc_t_ref)&getfd, (initfunc_t_ref)&get, deadline, stamp) ;
+}
diff --git a/src/libunixonacid/unixmessage_bits_closeall.c b/src/libunixonacid/unixmessage_bits_closeall.c
new file mode 100644
index 0000000..a963809
--- /dev/null
+++ b/src/libunixonacid/unixmessage_bits_closeall.c
@@ -0,0 +1,7 @@
+/* ISC license. */
+
+#include <skalibs/bitarray.h>
+#include <skalibs/unixmessage.h>
+
+static unsigned char _unixmessage_bits_closeall[bitarray_div8(UNIXMESSAGE_MAXFDS)] = "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" ;
+unsigned char const *const unixmessage_bits_closeall = _unixmessage_bits_closeall ;
diff --git a/src/libunixonacid/unixmessage_bits_closenone.c b/src/libunixonacid/unixmessage_bits_closenone.c
new file mode 100644
index 0000000..79412a5
--- /dev/null
+++ b/src/libunixonacid/unixmessage_bits_closenone.c
@@ -0,0 +1,7 @@
+/* ISC license. */
+
+#include <skalibs/bitarray.h>
+#include <skalibs/unixmessage.h>
+
+static unsigned char _unixmessage_bits_closenone[bitarray_div8(UNIXMESSAGE_MAXFDS)] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ;
+unsigned char const *const unixmessage_bits_closenone = _unixmessage_bits_closenone ;
diff --git a/src/libunixonacid/unixmessage_handle.c b/src/libunixonacid/unixmessage_handle.c
new file mode 100644
index 0000000..ad5789c
--- /dev/null
+++ b/src/libunixonacid/unixmessage_handle.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <skalibs/unixmessage.h>
+
+int unixmessage_handle (unixmessage_receiver_t *b, unixmessage_handler_func_t *f, void *p)
+{
+ unsigned int n = UNIXMESSAGE_MAXREADS ;
+ int count = 0 ;
+ while (n--)
+ {
+ unixmessage_t m ;
+ register int r = unixmessage_receive(b, &m) ;
+ if (r < 0) return -1 ;
+ if (!r) break ;
+ if (!(*f)(&m, p)) return -2 ;
+ count++ ;
+ }
+ return count ;
+}
diff --git a/src/libunixonacid/unixmessage_put.c b/src/libunixonacid/unixmessage_put.c
new file mode 100644
index 0000000..f6db23b
--- /dev/null
+++ b/src/libunixonacid/unixmessage_put.c
@@ -0,0 +1,83 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#ifdef SKALIBS_HASANCILAUTOCLOSE
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <skalibs/bitarray.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/diuint.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/siovec.h>
+#include <skalibs/unixmessage.h>
+
+static inline int copyfds (char *s, int const *fds, unsigned int n, unsigned char const *bits)
+{
+ register unsigned int i = 0 ;
+ for (; i < n ; i++)
+ {
+ int fd = fds[i] ;
+ if (fd < 0) return (errno = EINVAL, -1) ;
+ if (bitarray_peek(bits, i)) fd = - fd - 1 ;
+#ifdef SKALIBS_HASANCILAUTOCLOSE
+ else
+ {
+ fd = dup(fd) ;
+ if (fd < 0)
+ {
+ int e = errno ;
+ while (i--)
+ {
+ s -= sizeof(int) ;
+ byte_copy((char *)fd, sizeof(int), s) ;
+ if (fd >= 0) fd_close(fd) ;
+ }
+ errno = e ;
+ return 0 ;
+ }
+ }
+#else
+#endif
+ byte_copy(s, sizeof(int), (char const *)&fd) ;
+ s += sizeof(int) ;
+ }
+ return 1 ;
+}
+
+static int reserve_and_copy (unixmessage_sender_t *b, unsigned int len, int const *fds, unsigned int nfds, unsigned char const *bits)
+{
+ diuint cur = { .left = b->data.len, .right = b->fds.len } ;
+ if (!genalloc_readyplus(diuint, &b->offsets, 1)
+ || !genalloc_readyplus(int, &b->fds, nfds)
+ || !stralloc_readyplus(&b->data, len))
+ return 0 ;
+ if (!copyfds(b->fds.s + b->fds.len, fds, nfds, bits)) return 0 ;
+ b->fds.len += nfds * sizeof(int) ;
+ byte_copy(b->offsets.s + b->offsets.len, sizeof(diuint), (char const *)&cur) ;
+ b->offsets.len += sizeof(diuint) ;
+ return 1 ;
+}
+
+int unixmessage_put_and_close (unixmessage_sender_t *b, unixmessage_t const *m, unsigned char const *bits)
+{
+ if (!reserve_and_copy(b, m->len, m->fds, m->nfds, bits)) return 0 ;
+ byte_copy(b->data.s + b->data.len, m->len, m->s) ;
+ b->data.len += m->len ;
+ return 1 ;
+}
+
+int unixmessage_putv_and_close (unixmessage_sender_t *b, unixmessage_v_t const *m, unsigned char const *bits)
+{
+ unsigned int len = 0 ;
+ register unsigned int i = 0 ;
+ for (; i < m->vlen ; i++) len += m->v[i].len ;
+ if (!reserve_and_copy(b, len, m->fds, m->nfds, bits)) return 0 ;
+ for (i = 0 ; i < m->vlen ; i++)
+ {
+ byte_copy(b->data.s + b->data.len, m->v[i].len, m->v[i].s) ;
+ b->data.len += m->v[i].len ;
+ }
+ return 1 ;
+}
diff --git a/src/libunixonacid/unixmessage_read.c b/src/libunixonacid/unixmessage_read.c
new file mode 100644
index 0000000..5a23b84
--- /dev/null
+++ b/src/libunixonacid/unixmessage_read.c
@@ -0,0 +1,60 @@
+/* ISC license. */
+
+#define _XPG4_2
+#include <skalibs/sysdeps.h>
+#include <skalibs/nonposix.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <skalibs/buffer.h>
+#include <skalibs/cbuffer.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/error.h>
+#include <skalibs/siovec.h>
+#include <skalibs/unixmessage.h>
+
+int unixmessage_read (int fd, siovec_t const *v, unsigned int n, void *aux)
+{
+ int r ;
+ char ancilbuf[CMSG_SPACE(UNIXMESSAGE_MAXFDS * sizeof(int))] ;
+ struct iovec iov[n] ;
+ struct msghdr msghdr =
+ {
+ .msg_name = 0,
+ .msg_namelen = 0,
+ .msg_iov = iov,
+ .msg_iovlen = n,
+ .msg_flags = 0,
+ .msg_control = ancilbuf,
+ .msg_controllen = sizeof(ancilbuf)
+ } ;
+ iovec_from_siovec(iov, v, n) ;
+#ifdef SKALIBS_HASCMSGCLOEXEC
+ r = recvmsg(fd, &msghdr, MSG_WAITALL | MSG_CMSG_CLOEXEC) ;
+#else
+ r = recvmsg(fd, &msghdr, MSG_WAITALL) ;
+#endif
+ if (r > 0)
+ {
+ struct cmsghdr *c = CMSG_FIRSTHDR(&msghdr) ;
+ if (c)
+ {
+ cbuffer_t *auxb = aux ;
+ unsigned int len ;
+ if (c->cmsg_level != SOL_SOCKET
+ || c->cmsg_type != SCM_RIGHTS) return (errno = EPROTO, -1-r) ;
+ len = (unsigned int)(c->cmsg_len - (CMSG_DATA(c) - (unsigned char *)c)) ;
+#ifndef SKALIBS_HASCMSGCLOEXEC
+ {
+ register unsigned int i = 0 ;
+ for (; i < len/sizeof(int) ; i++)
+ if (coe(((int *)CMSG_DATA(c))[i]) < 0) return -1-r ;
+ }
+#endif
+ if (msghdr.msg_flags | MSG_CTRUNC) return (errno = EPROTO, -1-r) ;
+ if (cbuffer_put(auxb, (char *)CMSG_DATA(c), len) < len)
+ return (errno = ENOBUFS, -1-r) ;
+ }
+ }
+ return r ;
+}
diff --git a/src/libunixonacid/unixmessage_receive.c b/src/libunixonacid/unixmessage_receive.c
new file mode 100644
index 0000000..dc75263
--- /dev/null
+++ b/src/libunixonacid/unixmessage_receive.c
@@ -0,0 +1,44 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/buffer.h>
+#include <skalibs/cbuffer.h>
+#include <skalibs/error.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/uint.h>
+#include <skalibs/unixmessage.h>
+
+int unixmessage_receive (unixmessage_receiver_t *b, unixmessage_t *m)
+{
+ if (b->data.len == b->mainlen)
+ {
+ char pack[sizeof(unsigned int) << 1] ;
+ if (buffer_len(&b->mainb) < sizeof(unsigned int) << 1)
+ {
+ register int r = sanitize_read(buffer_fill(&b->mainb)) ;
+ if (r <= 0) return r ;
+ if (r < sizeof(unsigned int) << 1) return (errno = EWOULDBLOCK, 0) ;
+ }
+ buffer_getnofill(&b->mainb, pack, sizeof(unsigned int) << 1) ;
+ uint_unpack_big(pack, &b->mainlen) ;
+ uint_unpack_big(pack + sizeof(unsigned int), &b->auxlen) ;
+ if (b->auxlen > UNIXMESSAGE_MAXFDS) return (errno = EPROTO, -1) ;
+ b->auxlen *= sizeof(int) ;
+ if (!stralloc_ready(&b->data, b->mainlen)) return -1 ;
+ b->data.len = 0 ;
+ b->auxw = cbuffer_get(&b->auxb, (char *)b->fds, b->auxlen) ;
+ }
+ {
+ register int r = buffer_getall(&b->mainb, b->data.s, b->mainlen, &b->data.len) ;
+ if (r <= 0) return r ;
+ }
+ if (b->auxw < b->auxlen)
+ b->auxw += cbuffer_get(&b->auxb, (char *)b->fds, b->auxlen - b->auxw) ;
+ if (b->auxw < b->auxlen) return (errno = EPROTO, -1) ;
+ m->s = b->data.s ;
+ m->len = b->data.len ;
+ m->fds = b->fds ;
+ m->nfds = b->auxlen / sizeof(int) ;
+ return 1 ;
+}
diff --git a/src/libunixonacid/unixmessage_receiver_free.c b/src/libunixonacid/unixmessage_receiver_free.c
new file mode 100644
index 0000000..c23cc77
--- /dev/null
+++ b/src/libunixonacid/unixmessage_receiver_free.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/unixmessage.h>
+
+void unixmessage_receiver_free (unixmessage_receiver_t *b)
+{
+ stralloc_free(&b->data) ;
+ b->mainb.fd = -1 ;
+ b->mainlen = b->auxlen = b->auxw = 0 ;
+}
diff --git a/src/libunixonacid/unixmessage_receiver_init.c b/src/libunixonacid/unixmessage_receiver_init.c
new file mode 100644
index 0000000..982547c
--- /dev/null
+++ b/src/libunixonacid/unixmessage_receiver_init.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/cbuffer.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/unixmessage.h>
+
+int unixmessage_receiver_init (unixmessage_receiver_t *b, int fd, char *mainbuf, unsigned int mainlen, char *auxbuf, unsigned int auxlen)
+{
+ if (mainlen < 9 || auxlen < UNIXMESSAGE_MAXFDS * sizeof(int) + 1) return (errno = EINVAL, 0) ;
+ if (!cbuffer_init(&b->auxb, auxbuf, auxlen)) return 0 ;
+ if (!buffer_init_aux(&b->mainb, &unixmessage_read, fd, mainbuf, mainlen, &b->auxb)) return 0 ;
+ b->mainlen = b->auxlen = b->auxw = 0 ;
+ b->data = stralloc_zero ;
+ return 1 ;
+}
diff --git a/src/libunixonacid/unixmessage_sender_flush.c b/src/libunixonacid/unixmessage_sender_flush.c
new file mode 100644
index 0000000..ab8d460
--- /dev/null
+++ b/src/libunixonacid/unixmessage_sender_flush.c
@@ -0,0 +1,82 @@
+/* ISC license. */
+
+#define _XPG4_2
+#include <skalibs/sysdeps.h>
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <skalibs/uint.h>
+#include <skalibs/diuint.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/unixmessage.h>
+
+ /* MacOS X tries hard to be POSIX-compliant... and fails. */
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL 0
+#endif
+
+int unixmessage_sender_flush (unixmessage_sender_t *b)
+{
+ diuint last = { .left = b->data.len, .right = genalloc_len(int, &b->fds) } ;
+ diuint *offsets = genalloc_s(diuint, &b->offsets) ;
+ unsigned int n = genalloc_len(diuint, &b->offsets) ;
+ unsigned int oldhead = b->head ;
+ for (; b->head < n ; b->head++)
+ {
+ diuint *next = b->head+1 < n ? offsets + b->head+1 : &last ;
+ unsigned int len = next->left - offsets[b->head].left ;
+ unsigned int nfds = next->right - offsets[b->head].right ;
+ char pack[sizeof(unsigned int) << 1] ;
+ struct iovec v[2] =
+ {
+ { .iov_base = pack, .iov_len = sizeof(unsigned int) << 1 },
+ { .iov_base = b->data.s + offsets[b->head].left, .iov_len = len }
+ } ;
+ char ancilbuf[CMSG_SPACE(nfds * sizeof(int))] ;
+ struct msghdr hdr =
+ {
+ .msg_name = 0,
+ .msg_namelen = 0,
+ .msg_iov = v,
+ .msg_iovlen = 2,
+ .msg_control = nfds ? ancilbuf : 0,
+ .msg_controllen = nfds ? sizeof(ancilbuf) : 0
+ } ;
+ uint_pack_big(pack, len) ;
+ uint_pack_big(pack + sizeof(unsigned int), nfds) ;
+ if (nfds)
+ {
+ struct cmsghdr *cp = CMSG_FIRSTHDR(&hdr) ;
+ register unsigned int i = 0 ;
+ cp->cmsg_level = SOL_SOCKET ;
+ cp->cmsg_type = SCM_RIGHTS ;
+ cp->cmsg_len = CMSG_LEN(nfds * sizeof(int)) ;
+ for (; i < nfds ; i++)
+ {
+ register int fd = genalloc_s(int, &b->fds)[offsets[b->head].right + i] ;
+ ((int *)CMSG_DATA(cp))[i] = fd < 0 ? -(fd+1) : fd ;
+ }
+ }
+ if (sendmsg(b->fd, &hdr, MSG_NOSIGNAL) < len + (sizeof(unsigned int) << 1))
+ return -(int)(b->head-oldhead)-1 ;
+#ifndef SKALIBS_HASANCILAUTOCLOSE
+ if (nfds)
+ {
+ register unsigned int i = 0 ;
+ for (; i < nfds ; i++)
+ {
+ register int fd = genalloc_s(int, &b->fds)[offsets[b->head].right + i] ;
+ if (fd < 0) fd_close(-(fd+1)) ;
+ }
+ }
+#endif
+ }
+ b->data.len = 0 ;
+ genalloc_setlen(int, &b->fds, 0) ;
+ genalloc_setlen(diuint, &b->offsets, 0) ;
+ b->head = 0 ;
+ return (int)(n - oldhead) ;
+}
diff --git a/src/libunixonacid/unixmessage_sender_free.c b/src/libunixonacid/unixmessage_sender_free.c
new file mode 100644
index 0000000..797220c
--- /dev/null
+++ b/src/libunixonacid/unixmessage_sender_free.c
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/diuint.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/unixmessage.h>
+
+void unixmessage_sender_free (unixmessage_sender_t *b)
+{
+#ifdef SKALIBS_HASANCILAUTOCLOSE
+ {
+ diuint *offsets = genalloc_s(unsigned int, &b->offsets) ;
+ unsigned int n = genalloc_len(unsigned int, &b->offsets) ;
+ int *fds = genalloc_s(int, &b->fds) ;
+ unsigned int nfds = genalloc_len(int, &b->fds) ;
+ for (; b->head < n ; b->head++)
+ {
+ register unsigned int last = b->head+1 < n ? offsets[b->head+1].right : nfds ;
+ register unsigned int i = offsets[b->head].right ;
+ for (; i < last ; i++) if (fds[i] >= 0) fd_close(fds[i]) ;
+ }
+ }
+#endif
+ genalloc_free(diuint, &b->offsets) ;
+ genalloc_free(int, &b->fds) ;
+ stralloc_free(&b->data) ;
+ *b = unixmessage_sender_zero ;
+}
diff --git a/src/libunixonacid/unixmessage_sender_getfd.c b/src/libunixonacid/unixmessage_sender_getfd.c
new file mode 100644
index 0000000..1f130eb
--- /dev/null
+++ b/src/libunixonacid/unixmessage_sender_getfd.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/unixmessage.h>
+
+int unixmessage_sender_getfd (unixmessage_sender_t const *b)
+{
+ return b->fd ;
+}
diff --git a/src/libunixonacid/unixmessage_sender_init.c b/src/libunixonacid/unixmessage_sender_init.c
new file mode 100644
index 0000000..07c0bc2
--- /dev/null
+++ b/src/libunixonacid/unixmessage_sender_init.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/unixmessage.h>
+
+void unixmessage_sender_init (unixmessage_sender_t *b, int fd)
+{
+ b->fd = fd ;
+ b->data = stralloc_zero ;
+ b->fds = genalloc_zero ;
+ b->offsets = genalloc_zero ;
+ b->head = 0 ;
+}
diff --git a/src/libunixonacid/unixmessage_sender_timed_flush.c b/src/libunixonacid/unixmessage_sender_timed_flush.c
new file mode 100644
index 0000000..74e4937
--- /dev/null
+++ b/src/libunixonacid/unixmessage_sender_timed_flush.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/functypes.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/tai.h>
+#include <skalibs/unix-timed.h>
+#include <skalibs/unixmessage.h>
+
+static int unixmessage_sender_isnonempty (unixmessage_sender_t *b)
+{
+ return !!genalloc_len(unsigned int, &b->offsets) ;
+}
+
+int unixmessage_sender_timed_flush (unixmessage_sender_t *b, tain_t const *deadline, tain_t *stamp)
+{
+ return timed_flush(b, (initfunc_t_ref)&unixmessage_sender_getfd, (initfunc_t_ref)&unixmessage_sender_isnonempty, (initfunc_t_ref)&unixmessage_sender_flush, deadline, stamp) ;
+}
diff --git a/src/libunixonacid/unixmessage_sender_zero.c b/src/libunixonacid/unixmessage_sender_zero.c
new file mode 100644
index 0000000..bda0a9b
--- /dev/null
+++ b/src/libunixonacid/unixmessage_sender_zero.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include <skalibs/unixmessage.h>
+
+unixmessage_sender_t const unixmessage_sender_zero = UNIXMESSAGE_SENDER_ZERO ;
diff --git a/src/libunixonacid/unixmessage_timed_handle.c b/src/libunixonacid/unixmessage_timed_handle.c
new file mode 100644
index 0000000..5ac7ccd
--- /dev/null
+++ b/src/libunixonacid/unixmessage_timed_handle.c
@@ -0,0 +1,30 @@
+/* ISC license. */
+
+#include <skalibs/functypes.h>
+#include <skalibs/tai.h>
+#include <skalibs/unix-timed.h>
+#include <skalibs/unixmessage.h>
+
+typedef struct unixmessage_handler_blah_s unixmessage_handler_blah_t, *unixmessage_handler_blah_t_ref ;
+struct unixmessage_handler_blah_s
+{
+ unixmessage_receiver_t *b ;
+ unixmessage_handler_func_t *f ;
+ void *p ;
+} ;
+
+static int getfd (unixmessage_handler_blah_t *blah)
+{
+ return unixmessage_receiver_fd(blah->b) ;
+}
+
+static int get (unixmessage_handler_blah_t *blah)
+{
+ return unixmessage_handle(blah->b, blah->f, blah->p) ;
+}
+
+int unixmessage_timed_handle (unixmessage_receiver_t *b, unixmessage_handler_func_t *f, void *p, tain_t const *deadline, tain_t *stamp)
+{
+ unixmessage_handler_blah_t blah = { .b = b, .f = f, .p = p } ;
+ return timed_get(&blah, (initfunc_t_ref)&getfd, (initfunc_t_ref)&get, deadline, stamp) ;
+}
diff --git a/src/libunixonacid/unixmessage_timed_receive.c b/src/libunixonacid/unixmessage_timed_receive.c
new file mode 100644
index 0000000..3761d26
--- /dev/null
+++ b/src/libunixonacid/unixmessage_timed_receive.c
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#include <skalibs/functypes.h>
+#include <skalibs/tai.h>
+#include <skalibs/unix-timed.h>
+#include <skalibs/unixmessage.h>
+
+typedef struct unixmessage_get_s unixmessage_get_t, *unixmessage_get_t_ref ;
+struct unixmessage_get_s
+{
+ unixmessage_receiver_t *b ;
+ unixmessage_t *m ;
+} ;
+
+static int getfd (unixmessage_get_t *g)
+{
+ return unixmessage_receiver_fd(g->b) ;
+}
+
+static int get (unixmessage_get_t *g)
+{
+ return unixmessage_receive(g->b, g->m) ;
+}
+
+int unixmessage_timed_receive (unixmessage_receiver_t *b, unixmessage_t *m, tain_t const *deadline, tain_t *stamp)
+{
+ unixmessage_get_t g = { .b = b, .m = m } ;
+ return timed_get(&g, (initfunc_t *)&getfd, (initfunc_t *)&get, deadline, stamp) ;
+}
diff --git a/src/libunixonacid/unixmessage_v_zero.c b/src/libunixonacid/unixmessage_v_zero.c
new file mode 100644
index 0000000..b4ab13a
--- /dev/null
+++ b/src/libunixonacid/unixmessage_v_zero.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include <skalibs/unixmessage.h>
+
+unixmessage_v_t const unixmessage_v_zero = UNIXMESSAGE_V_ZERO ;
diff --git a/src/libunixonacid/unixmessage_zero.c b/src/libunixonacid/unixmessage_zero.c
new file mode 100644
index 0000000..4cfb242
--- /dev/null
+++ b/src/libunixonacid/unixmessage_zero.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include <skalibs/unixmessage.h>
+
+unixmessage_t const unixmessage_zero = UNIXMESSAGE_ZERO ;
diff --git a/src/sysdeps/tryaccept4.c b/src/sysdeps/tryaccept4.c
new file mode 100644
index 0000000..e27eb1a
--- /dev/null
+++ b/src/sysdeps/tryaccept4.c
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+#ifndef _XPG4_2
+# define _XPG4_2
+#endif
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+#include <sys/types.h>
+
+#if defined(__FreeBSD__)
+# include <sys/param.h>
+#endif
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+int main (void)
+{
+ struct sockaddr blah ;
+ socklen_t blahlen = sizeof(blah) ;
+ int fd = open("/dev/null", O_RDONLY | O_NONBLOCK) ;
+ if (fd < 0) return 111 ;
+ if ((accept4(fd, &blah, &blahlen, SOCK_NONBLOCK) < 0) && (errno != ENOTSOCK)) return 1 ;
+ return 0 ;
+}
diff --git a/src/sysdeps/tryancilautoclose.c b/src/sysdeps/tryancilautoclose.c
new file mode 100644
index 0000000..7b4a563
--- /dev/null
+++ b/src/sysdeps/tryancilautoclose.c
@@ -0,0 +1,116 @@
+/* ISC license. */
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+#ifndef _XPG4_2
+# define _XPG4_2
+#endif
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#if defined(__FreeBSD__)
+# include <sys/param.h>
+#endif
+
+typedef struct ancilbuf_s ancilbuf_t, *ancilbuf_t_ref ;
+struct ancilbuf_s
+{
+ struct cmsghdr h ;
+ int fd ;
+} ;
+
+static int ancil_send_fd (int sock, int fd)
+{
+ struct msghdr msghdr ;
+ struct iovec nothing_ptr ;
+ ancilbuf_t buf ;
+ struct cmsghdr *cmsg ;
+ char nothing = '!' ;
+
+ nothing_ptr.iov_base = &nothing ;
+ nothing_ptr.iov_len = 1 ;
+ msghdr.msg_name = 0 ;
+ msghdr.msg_namelen = 0 ;
+ msghdr.msg_iov = &nothing_ptr ;
+ msghdr.msg_iovlen = 1 ;
+ msghdr.msg_flags = 0 ;
+ msghdr.msg_control = &buf ;
+ msghdr.msg_controllen = sizeof(ancilbuf_t) ;
+ cmsg = CMSG_FIRSTHDR(&msghdr) ;
+ cmsg->cmsg_len = msghdr.msg_controllen ;
+ cmsg->cmsg_level = SOL_SOCKET ;
+ cmsg->cmsg_type = SCM_RIGHTS ;
+ *((int *)CMSG_DATA(cmsg)) = fd ;
+ return (sendmsg(sock, &msghdr, 0) >= 0) ;
+}
+
+static int ancil_recv_fd (int sock)
+{
+ struct msghdr msghdr ;
+ struct iovec nothing_ptr ;
+ ancilbuf_t buf ;
+ struct cmsghdr *cmsg ;
+ char nothing ;
+
+ nothing_ptr.iov_base = &nothing ;
+ nothing_ptr.iov_len = 1 ;
+ msghdr.msg_name = 0 ;
+ msghdr.msg_namelen = 0 ;
+ msghdr.msg_iov = &nothing_ptr ;
+ msghdr.msg_iovlen = 1 ;
+ msghdr.msg_flags = 0 ;
+ msghdr.msg_control = &buf ;
+ msghdr.msg_controllen = sizeof(ancilbuf_t) ;
+ cmsg = CMSG_FIRSTHDR(&msghdr) ;
+ cmsg->cmsg_len = msghdr.msg_controllen ;
+ cmsg->cmsg_level = SOL_SOCKET ;
+ cmsg->cmsg_type = SCM_RIGHTS ;
+ *((int *)CMSG_DATA(cmsg)) = -1 ;
+ if (recvmsg(sock, &msghdr, 0) < 0) return -1 ;
+ return *((int *)CMSG_DATA(cmsg)) ;
+}
+
+static int client (int sock)
+{
+ int p ;
+ char c ;
+ if (read(sock, &c, 1) < 1) return 111 ;
+ if (c != 'b') return 111 ;
+ p = ancil_recv_fd(sock) ;
+ if (p < 0) return 111 ;
+ if (read(sock, &c, 1) < 1) return 111 ;
+ if (c != 'a') return 111 ;
+ if (read(p, &c, 1) < 1) return 111 ;
+ if (c != 'K') return 111 ;
+ if (read(p, &c, 1) < 1) return 111 ;
+ return c ;
+}
+
+static void server (int sock)
+{
+ int p[2] ;
+ char c = 1 ;
+ if (pipe(p) < 0) return ;
+ if (write(sock, "b", 1) < 1) return ;
+ if (!ancil_send_fd(sock, p[0])) return ;
+ if (write(sock, "a", 1) < 1) return ;
+ if (write(p[1], "K", 1) < 1) return ;
+ if ((close(p[0]) < 0) && (errno == EBADF)) c = 0 ;
+ write(p[1], &c, 1) ;
+}
+
+int main (void)
+{
+ int fd[2] ;
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) return 111 ;
+ switch (fork())
+ {
+ case -1 : return 111 ;
+ case 0 : close(fd[0]) ; server(fd[1]) ; return 0 ;
+ default : close(fd[1]) ; return client(fd[0]) ;
+ }
+}
diff --git a/src/sysdeps/tryclockmon.c b/src/sysdeps/tryclockmon.c
new file mode 100644
index 0000000..2564ed3
--- /dev/null
+++ b/src/sysdeps/tryclockmon.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <time.h>
+
+int main (void)
+{
+ struct timespec ts ;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) return 111 ;
+ return 0 ;
+}
diff --git a/src/sysdeps/tryclockrt.c b/src/sysdeps/tryclockrt.c
new file mode 100644
index 0000000..01bae7c
--- /dev/null
+++ b/src/sysdeps/tryclockrt.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <time.h>
+
+int main (void)
+{
+ struct timespec ts ;
+ if (clock_gettime(CLOCK_REALTIME, &ts) < 0) return 111 ;
+ return 0 ;
+}
diff --git a/src/sysdeps/trycmsgcloexec.c b/src/sysdeps/trycmsgcloexec.c
new file mode 100644
index 0000000..7923340
--- /dev/null
+++ b/src/sysdeps/trycmsgcloexec.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+#ifndef _XPG4_2
+# define _XPG4_2
+#endif
+
+#ifndef _XPG_6
+# define _XPG6
+#endif
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int main (void)
+{
+ int flag = MSG_CMSG_CLOEXEC ;
+ return 0 ;
+}
diff --git a/src/sysdeps/trydevrandom.c b/src/sysdeps/trydevrandom.c
new file mode 100644
index 0000000..395d008
--- /dev/null
+++ b/src/sysdeps/trydevrandom.c
@@ -0,0 +1,54 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+
+static int fd_read (int fd, char *buf, unsigned int len)
+{
+ register int r ;
+ do r = read(fd, buf, len) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ return r ;
+}
+
+static unsigned int allread (int fd, register char *buf, register unsigned int len)
+{
+ register unsigned int written = 0 ;
+ while (len)
+ {
+ register int w = fd_read(fd, buf, len) ;
+ if (!w) errno = EPIPE ;
+ if (w <= 0) break ;
+ written += w ;
+ buf += w ;
+ len -= w ;
+ }
+ return written ;
+}
+
+static int byte_diff (char *s, unsigned int n, char *t)
+{
+ for (;;)
+ {
+ if (!n) return 0 ;
+ if (*s != *t) break ;
+ ++s ; ++t ; --n ;
+ }
+ return ((int)(unsigned int)(unsigned char) *s)
+ - ((int)(unsigned int)(unsigned char) *t);
+}
+
+int main ()
+{
+ char a[64] ;
+ char b[64] ;
+ int fd = open("/dev/random", O_RDONLY) ;
+ if ((fd == -1) || (allread(fd, a, 64) < 64) ) return 111 ;
+ close(fd) ;
+ fd = open("/dev/random", O_RDONLY) ;
+ if ((fd == -1) || (allread(fd, b, 64) < 64) ) return 111 ;
+ close(fd) ;
+ return !byte_diff(a, 64, b) ;
+}
diff --git a/src/sysdeps/trydevurandom.c b/src/sysdeps/trydevurandom.c
new file mode 100644
index 0000000..3d0f912
--- /dev/null
+++ b/src/sysdeps/trydevurandom.c
@@ -0,0 +1,31 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+static int byte_diff (char *s, unsigned int n, char *t)
+{
+ for (;;)
+ {
+ if (!n) return 0 ;
+ if (*s != *t) break ;
+ ++s ; ++t ; --n ;
+ }
+ return ((int)(unsigned int)(unsigned char) *s)
+ - ((int)(unsigned int)(unsigned char) *t);
+}
+
+int main ()
+{
+ char a[64] ;
+ char b[64] ;
+ int fd ;
+ fd = open("/dev/urandom", O_RDONLY) ;
+ if ((fd == -1) || (read(fd, a, 64) < 64) ) return 111 ;
+ close(fd) ;
+ fd = open("/dev/urandom", O_RDONLY) ;
+ if ((fd == -1) || (read(fd, b, 64) < 64) ) return 111 ;
+ close(fd) ;
+ return (!byte_diff(a, 64, b)) ;
+}
diff --git a/src/sysdeps/tryendianness.c b/src/sysdeps/tryendianness.c
new file mode 100644
index 0000000..3fa1938
--- /dev/null
+++ b/src/sysdeps/tryendianness.c
@@ -0,0 +1,43 @@
+/* ISC license. */
+
+#include <stdio.h>
+
+int main (void)
+{
+ unsigned long i = 0xdeadbeefUL ;
+ if (sizeof(unsigned long) == 4)
+ if ((((unsigned char *)(&i))[0] == 0xef)
+ && (((unsigned char *)(&i))[1] == 0xbe)
+ && (((unsigned char *)(&i))[2] == 0xad)
+ && (((unsigned char *)(&i))[3] == 0xde))
+ return (puts("little"), 0) ;
+ else if ((((unsigned char *)(&i))[0] == 0xde)
+ && (((unsigned char *)(&i))[1] == 0xad)
+ && (((unsigned char *)(&i))[2] == 0xbe)
+ && (((unsigned char *)(&i))[3] == 0xef))
+ return (puts("big"), 0) ;
+ else return (puts("unknown"), 1) ;
+ else if (sizeof(unsigned long) == 8)
+ if ((((unsigned char *)(&i))[0] == 0xef)
+ && (((unsigned char *)(&i))[1] == 0xbe)
+ && (((unsigned char *)(&i))[2] == 0xad)
+ && (((unsigned char *)(&i))[3] == 0xde)
+ && (((unsigned char *)(&i))[4] == 0x00)
+ && (((unsigned char *)(&i))[5] == 0x00)
+ && (((unsigned char *)(&i))[6] == 0x00)
+ && (((unsigned char *)(&i))[7] == 0x00))
+ return (puts("little"), 0) ;
+ else if (sizeof(unsigned long) == 8)
+ if ((((unsigned char *)(&i))[0] == 0x00)
+ && (((unsigned char *)(&i))[1] == 0x00)
+ && (((unsigned char *)(&i))[2] == 0x00)
+ && (((unsigned char *)(&i))[3] == 0x00)
+ && (((unsigned char *)(&i))[4] == 0xde)
+ && (((unsigned char *)(&i))[5] == 0xad)
+ && (((unsigned char *)(&i))[6] == 0xbe)
+ && (((unsigned char *)(&i))[7] == 0xef))
+ return (puts("big"), 0) ;
+ else return (puts("unknown"), 1) ;
+ else return 1 ;
+ else return (puts("unknown unsigned long size"), 1) ;
+}
diff --git a/src/sysdeps/tryeproto.c b/src/sysdeps/tryeproto.c
new file mode 100644
index 0000000..b5cc66c
--- /dev/null
+++ b/src/sysdeps/tryeproto.c
@@ -0,0 +1,7 @@
+/* ISC license. */
+
+#include <errno.h>
+static int dummy ;
+#ifndef EPROTO
+ syntax error !
+#endif
diff --git a/src/sysdeps/tryeventfd.c b/src/sysdeps/tryeventfd.c
new file mode 100644
index 0000000..3c3122c
--- /dev/null
+++ b/src/sysdeps/tryeventfd.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <sys/eventfd.h>
+
+int main (void)
+{
+ int fd = eventfd(0, EFD_NONBLOCK) ;
+ if (fd < 0) return 1 ;
+ return 0 ;
+}
diff --git a/src/sysdeps/tryflock.c b/src/sysdeps/tryflock.c
new file mode 100644
index 0000000..47fadf8
--- /dev/null
+++ b/src/sysdeps/tryflock.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <fcntl.h>
+
+int main (void)
+{
+ return flock(0, LOCK_EX | LOCK_UN | LOCK_NB) ;
+}
diff --git a/src/sysdeps/trygetpeereid.c b/src/sysdeps/trygetpeereid.c
new file mode 100644
index 0000000..10a411a
--- /dev/null
+++ b/src/sysdeps/trygetpeereid.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+#include <sys/types.h>
+#include <unistd.h>
+
+int main (void)
+{
+ uid_t uid ;
+ gid_t gid ;
+ int s = 0 ;
+ return getpeereid(s, &uid, &gid) ;
+}
diff --git a/src/sysdeps/trygetpeerucred.c b/src/sysdeps/trygetpeerucred.c
new file mode 100644
index 0000000..22dac68
--- /dev/null
+++ b/src/sysdeps/trygetpeerucred.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+#include <sys/types.h>
+#include <ucred.h>
+
+int main (void)
+{
+ ucred_t *cred ;
+ uid_t uid ;
+ gid_t gid ;
+ int s = 0 ;
+ getpeerucred(s, &cred) ;
+ uid = ucred_geteuid(cred) ;
+ gid = ucred_getegid(cred) ;
+ ucred_free(cred) ;
+ return 0 ;
+}
diff --git a/src/sysdeps/tryipv6.c b/src/sysdeps/tryipv6.c
new file mode 100644
index 0000000..0c7f306
--- /dev/null
+++ b/src/sysdeps/tryipv6.c
@@ -0,0 +1,35 @@
+/* ISC license. */
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+#define _XPG4_2
+#define _XPG6
+
+#include <sys/types.h>
+
+#if defined(__FreeBSD__)
+# include <sys/param.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+int main (void)
+{
+ int s ;
+ register int r ;
+ struct in6_addr foo ;
+ struct sockaddr_in6 bar ;
+ memset(&foo, 0, sizeof(struct sockaddr_in6)) ;
+ bar.sin6_addr = foo ;
+ bar.sin6_port = 1026 ;
+ s = socket(AF_INET6, SOCK_STREAM, 0) ;
+ if (s < 0) return 111 ;
+ do r = connect(s, (struct sockaddr *)&bar, sizeof bar) ;
+ while ((r == -1) && (errno == EINTR)) ;
+ if ((r == -1) && (errno == EALREADY)) errno = EINPROGRESS ;
+ return 0 ;
+}
diff --git a/src/sysdeps/trylinkat.c b/src/sysdeps/trylinkat.c
new file mode 100644
index 0000000..3db0845
--- /dev/null
+++ b/src/sysdeps/trylinkat.c
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#ifndef _ATFILE_SOURCE
+#define _ATFILE_SOURCE
+#endif
+
+#ifndef _INCOMPLETE_XOPEN_C063
+#define _INCOMPLETE_XOPEN_C063
+#endif
+
+#ifndef __EXTENSIONS__
+#define __EXTENSIONS__
+#endif
+
+#include <unistd.h>
+#include <fcntl.h>
+
+int main (void)
+{
+ int r = linkat(AT_FDCWD, "/foo", AT_FDCWD, "foo", AT_SYMLINK_FOLLOW) ;
+ return (r < 0) ;
+}
diff --git a/src/sysdeps/trylsock.c b/src/sysdeps/trylsock.c
new file mode 100644
index 0000000..b5b4413
--- /dev/null
+++ b/src/sysdeps/trylsock.c
@@ -0,0 +1,26 @@
+/* ISC license. */
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+#ifndef _XPG4_2
+# define _XPG4_2
+#endif
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+#include <sys/types.h>
+
+#if defined(__FreeBSD__)
+# include <sys/param.h>
+#endif
+
+#include <sys/socket.h>
+
+int main (void)
+{
+ shutdown(0, 0) ;
+ return 0 ;
+}
diff --git a/src/sysdeps/trymalloc0.c b/src/sysdeps/trymalloc0.c
new file mode 100644
index 0000000..0f68329
--- /dev/null
+++ b/src/sysdeps/trymalloc0.c
@@ -0,0 +1,4 @@
+/* ISC license */
+
+#include <stdlib.h>
+int main() { return !malloc(0) ; }
diff --git a/src/sysdeps/tryopenat.c b/src/sysdeps/tryopenat.c
new file mode 100644
index 0000000..d24a9cb
--- /dev/null
+++ b/src/sysdeps/tryopenat.c
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#ifndef _ATFILE_SOURCE
+#define _ATFILE_SOURCE
+#endif
+
+#ifndef _INCOMPLETE_XOPEN_C063
+#define _INCOMPLETE_XOPEN_C063
+#endif
+
+#ifndef __EXTENSIONS__
+#define __EXTENSIONS__
+#endif
+
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int main (void)
+{
+ int fd = openat(0, "/", O_RDONLY) ;
+ return (fd < 0) ;
+}
diff --git a/src/sysdeps/trypipe2.c b/src/sysdeps/trypipe2.c
new file mode 100644
index 0000000..4e63182
--- /dev/null
+++ b/src/sysdeps/trypipe2.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#ifndef _NETBSD_SOURCE
+#define _NETBSD_SOURCE
+#endif
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <unistd.h>
+
+int main (void)
+{
+ int p[2] ;
+ if (pipe2(p, 0) < 0) return 111 ;
+ return 0 ;
+}
diff --git a/src/sysdeps/tryposixspawn.c b/src/sysdeps/tryposixspawn.c
new file mode 100644
index 0000000..dccdba4
--- /dev/null
+++ b/src/sysdeps/tryposixspawn.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <spawn.h>
+
+int main (void)
+{
+ pid_t pid ;
+ posix_spawn_file_actions_t actions ;
+ posix_spawnattr_t attr ;
+ char *const argv[2] = { "/bin/true", 0 } ;
+ char *const envp[1] = { 0 } ;
+ posix_spawnattr_setflags(&attr, 0) ;
+ posix_spawn_file_actions_init(&actions) ;
+ return posix_spawn(&pid, argv[0], 0, 0, argv, envp) ;
+}
diff --git a/src/sysdeps/tryppoll.c b/src/sysdeps/tryppoll.c
new file mode 100644
index 0000000..33380b8
--- /dev/null
+++ b/src/sysdeps/tryppoll.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#define _GNU_SOURCE
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <poll.h>
+
+int main (void)
+{
+ struct pollfd x = { .events = POLLIN } ;
+ struct timespec ts = { .tv_sec = 0, .tv_nsec = 10 } ;
+ x.fd = open("src/sysdeps/tryppoll.c", O_RDONLY);
+ if (x.fd < 0) return 111 ;
+ if (ppoll(&x, 1, &ts, 0) < 0) return 1 ;
+ if (x.revents != POLLIN) return 1 ;
+ return 0 ;
+}
diff --git a/src/sysdeps/tryrevoke.c b/src/sysdeps/tryrevoke.c
new file mode 100644
index 0000000..9cbc615
--- /dev/null
+++ b/src/sysdeps/tryrevoke.c
@@ -0,0 +1,7 @@
+/* ISC license. */
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+#include <unistd.h>
+int main () { return revoke("/") ; }
diff --git a/src/sysdeps/trysendfile.c b/src/sysdeps/trysendfile.c
new file mode 100644
index 0000000..6c99ad0
--- /dev/null
+++ b/src/sysdeps/trysendfile.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/sendfile.h>
+
+int main (void)
+{
+ sendfile(1, 0, 0, 4096) ;
+ return 0 ;
+}
diff --git a/src/sysdeps/trysetgroups.c b/src/sysdeps/trysetgroups.c
new file mode 100644
index 0000000..af2d8c6
--- /dev/null
+++ b/src/sysdeps/trysetgroups.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE
+#endif
+
+#ifndef _NETBSD_SOURCE
+#define _NETBSD_SOURCE
+#endif
+
+#ifndef __EXTENSIONS__
+#define __EXTENSIONS__
+#endif
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <grp.h>
+
+int main (void)
+{
+ gid_t g = 0 ;
+ setgroups(1, &g) ;
+ return 0 ;
+}
diff --git a/src/sysdeps/trysettimeofday.c b/src/sysdeps/trysettimeofday.c
new file mode 100644
index 0000000..05ae3c4
--- /dev/null
+++ b/src/sysdeps/trysettimeofday.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE
+#endif
+
+#ifndef _NETBSD_SOURCE
+#define _NETBSD_SOURCE
+#endif
+
+#ifndef __EXTENSIONS__
+#define __EXTENSIONS__
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+int main (void)
+{
+ struct timeval tv ;
+ gettimeofday(&tv, 0) ;
+ settimeofday(&tv, 0) ;
+ return 0 ;
+}
diff --git a/src/sysdeps/trysignalfd.c b/src/sysdeps/trysignalfd.c
new file mode 100644
index 0000000..1f06933
--- /dev/null
+++ b/src/sysdeps/trysignalfd.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/signalfd.h>
+
+int main (void)
+{
+ sigset_t foo ;
+ sigemptyset(&foo) ;
+ if (signalfd(-1, &foo, SFD_NONBLOCK) < 0) return 1 ;
+ return 0 ;
+}
diff --git a/src/sysdeps/trysizeofgid.c b/src/sysdeps/trysizeofgid.c
new file mode 100644
index 0000000..75eeb2c
--- /dev/null
+++ b/src/sysdeps/trysizeofgid.c
@@ -0,0 +1,8 @@
+#include <sys/types.h>
+#include <stdio.h>
+
+int main (void)
+{
+ printf("%u\n", (unsigned int)sizeof(gid_t)) ;
+ return 0 ;
+}
diff --git a/src/sysdeps/trysizeoftime.c b/src/sysdeps/trysizeoftime.c
new file mode 100644
index 0000000..13674de
--- /dev/null
+++ b/src/sysdeps/trysizeoftime.c
@@ -0,0 +1,8 @@
+#include <sys/types.h>
+#include <stdio.h>
+
+int main (void)
+{
+ printf("%u\n", (unsigned int)sizeof(time_t)) ;
+ return 0 ;
+}
diff --git a/src/sysdeps/trysizeofuint.c b/src/sysdeps/trysizeofuint.c
new file mode 100644
index 0000000..ca4af39
--- /dev/null
+++ b/src/sysdeps/trysizeofuint.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+ printf("%u\n", (unsigned int)sizeof(unsigned int)) ;
+ return 0 ;
+}
diff --git a/src/sysdeps/trysizeofulong.c b/src/sysdeps/trysizeofulong.c
new file mode 100644
index 0000000..f2f21b1
--- /dev/null
+++ b/src/sysdeps/trysizeofulong.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+ printf("%u\n", (unsigned int)sizeof(unsigned long)) ;
+ return 0 ;
+}
diff --git a/src/sysdeps/trysizeofushort.c b/src/sysdeps/trysizeofushort.c
new file mode 100644
index 0000000..fd410bb
--- /dev/null
+++ b/src/sysdeps/trysizeofushort.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+ printf("%u\n", (unsigned int)sizeof(unsigned short)) ;
+ return 0 ;
+}
diff --git a/src/sysdeps/trysopeercred.c b/src/sysdeps/trysopeercred.c
new file mode 100644
index 0000000..0356fcf
--- /dev/null
+++ b/src/sysdeps/trysopeercred.c
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+#ifndef _XPG4_2
+# define _XPG4_2
+#endif
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+#include <sys/types.h>
+
+#if defined(__FreeBSD__)
+# include <sys/param.h>
+#endif
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+int main (void)
+{
+ int s ;
+ struct ucred dummy ;
+ socklen_t len = sizeof(struct ucred) ;
+ return getsockopt(s, SOL_SOCKET, SO_PEERCRED, &dummy, &len) ;
+}
diff --git a/src/sysdeps/trysplice.c b/src/sysdeps/trysplice.c
new file mode 100644
index 0000000..6b566b8
--- /dev/null
+++ b/src/sysdeps/trysplice.c
@@ -0,0 +1,28 @@
+/* ISC license. */
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#define N 4096
+
+int main (void)
+{
+ char buf[N] ;
+ int p[2] ;
+ int fd ;
+ if (pipe(p) < 0) return 111 ;
+ fd = open("./src/sysdeps/trysplice.c", O_RDONLY) ;
+ if (fd < 0) return 111 ;
+
+ for (;;)
+ {
+ register int r = splice(fd, 0, p[1], 0, N, 0) ;
+ if (r < 0) return 1 ;
+ if (!r) break ;
+ if (splice(p[0], 0, 1, 0, r, 0) < r) return 2 ;
+ }
+ return 0 ;
+}
diff --git a/src/sysdeps/trystrcasestr.c b/src/sysdeps/trystrcasestr.c
new file mode 100644
index 0000000..f362202
--- /dev/null
+++ b/src/sysdeps/trystrcasestr.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE
+#endif
+#ifndef _NETBSD_SOURCE
+#define _NETBSD_SOURCE
+#endif
+
+#include <string.h>
+
+int main (void)
+{
+ return !strcasestr("foobar", "bar") ;
+}
diff --git a/src/sysdeps/tryuint64t.c b/src/sysdeps/tryuint64t.c
new file mode 100644
index 0000000..23aafad
--- /dev/null
+++ b/src/sysdeps/tryuint64t.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include <stdint.h>
+
+uint64_t dummy = 0 ;
diff --git a/tools/gen-deps.sh b/tools/gen-deps.sh
new file mode 100755
index 0000000..ce18091
--- /dev/null
+++ b/tools/gen-deps.sh
@@ -0,0 +1,50 @@
+#!/bin/sh -e
+
+. package/info
+
+echo '#'
+echo '# This file has been generated by tools/gen-deps.sh'
+echo '#'
+echo
+
+for dir in src/include/${package} src/lib* ; do
+ for file in $(ls -1 $dir | grep -- \\.h$) ; do
+ {
+ grep -F "#include <${package}/" < ${dir}/$file | cut -d/ -f2- | cut -d'>' -f1 ;
+ grep -- '#include ".*-internal\.h"' < ${dir}/$file | cut -d'"' -f2
+ } | sort -u | {
+ deps=
+ while read dep ; do
+ if echo $dep | grep -q -- -internal\\.h$ ; then
+ deps="$deps ${dir}/$dep"
+ else
+ deps="$deps src/include/${package}/$dep"
+ fi
+ done
+ if test -n "$deps" ; then
+ echo "${dir}/${file}:${deps}"
+ fi
+ }
+ done
+done
+
+for dir in src/lib* ; do
+ for file in $(ls -1 $dir | grep -- \\.c$) ; do
+ {
+ grep -F "#include <${package}/" < ${dir}/$file | cut -d/ -f2- | cut -d'>' -f1 ;
+ grep -- '#include ".*-internal\.h"' < ${dir}/$file | cut -d'"' -f2
+ } | sort -u | {
+ deps=" ${dir}/$file"
+ while read dep ; do
+ if echo $dep | grep -q -- -internal\\.h$ ; then
+ deps="$deps ${dir}/$dep"
+ else
+ deps="$deps src/include/${package}/$dep"
+ fi
+ done
+ o=$(echo $file | sed s/\\.c$/.o/)
+ lo=$(echo $file | sed s/\\.c$/.lo/)
+ echo "${dir}/${o} ${dir}/${lo}:${deps}"
+ }
+ done
+done
diff --git a/tools/install.sh b/tools/install.sh
new file mode 100755
index 0000000..89f9428
--- /dev/null
+++ b/tools/install.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+usage() {
+ echo "usage: $0 [-D] [-l] [-m mode] src dst" 1>&2
+ exit 1
+}
+
+mkdirp=false
+symlink=false
+mode=0755
+
+while getopts Dlm: name ; do
+ case "$name" in
+ D) mkdirp=true ;;
+ l) symlink=true ;;
+ m) mode=$OPTARG ;;
+ ?) usage ;;
+ esac
+done
+shift $(($OPTIND - 1))
+
+test "$#" -eq 2 || usage
+src=$1
+dst=$2
+tmp="$dst.tmp.$$"
+
+case "$dst" in
+ */) echo "$0: $dst ends in /" 1>&2 ; exit 1 ;;
+esac
+
+set -C
+set -e
+
+if $mkdirp ; then
+ umask 022
+ case "$2" in
+ */*) mkdir -p "${dst%/*}" ;;
+ esac
+fi
+
+trap 'rm -f "$tmp"' EXIT INT QUIT TERM HUP
+
+umask 077
+
+if $symlink ; then
+ ln -s "$src" "$tmp"
+else
+ cat < "$1" > "$tmp"
+ chmod "$mode" "$tmp"
+fi
+
+mv -f "$tmp" "$dst"
+if test -d "$dst" ; then
+ rm -f "$dst/$(basename $tmp)"
+ if $symlink ; then
+ mkdir "$tmp"
+ ln -s "$src" "$tmp/$(basename $dst)"
+ mv -f "$tmp/$(basename $dst)" "${dst%/*}"
+ rmdir "$tmp"
+ else
+ echo "$0: $dst is a directory" 1>&2
+ exit 1
+ fi
+fi