summaryrefslogtreecommitdiff
path: root/src/libstddjb
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstddjb')
-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
497 files changed, 10425 insertions, 0 deletions
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 ;
+}